Remove texture atlas / AtlasPointer, rename getTextureRaw to getTexture
[oweals/minetest.git] / src / mapblock_mesh.cpp
index f4d57922a52b0de37e8ce84c8e1276b6f5c96b36..a9ed7532516d1ecfaeb6b8f9df6a4c4cadd211ba 100644 (file)
@@ -445,16 +445,95 @@ struct FastFace
 };
 
 static void makeFastFace(TileSpec tile, u16 li0, u16 li1, u16 li2, u16 li3,
-               v3f p, v3s16 dir, v3f scale, u8 light_source, core::array<FastFace> &dest)
+               v3f p, v3s16 dir, v3f scale, u8 light_source, std::vector<FastFace> &dest)
 {
        FastFace face;
        
        // Position is at the center of the cube.
        v3f pos = p * BS;
 
+       float x0 = 0.0;
+       float y0 = 0.0;
+       float w = 1.0;
+       float h = 1.0;
+
        v3f vertex_pos[4];
        v3s16 vertex_dirs[4];
        getNodeVertexDirs(dir, vertex_dirs);
+       v3s16 t;
+       switch (tile.rotation)
+       {
+       case 0:
+               break;
+       case 1: //R90
+               t = vertex_dirs[0];
+               vertex_dirs[0] = vertex_dirs[3];
+               vertex_dirs[3] = vertex_dirs[2];
+               vertex_dirs[2] = vertex_dirs[1];
+               vertex_dirs[1] = t;
+               break;
+       case 2: //R180
+               t = vertex_dirs[0];
+               vertex_dirs[0] = vertex_dirs[2];
+               vertex_dirs[2] = t;
+               t = vertex_dirs[1];
+               vertex_dirs[1] = vertex_dirs[3];
+               vertex_dirs[3] = t;
+               break;
+       case 3: //R270
+               t = vertex_dirs[0];
+               vertex_dirs[0] = vertex_dirs[1];
+               vertex_dirs[1] = vertex_dirs[2];
+               vertex_dirs[2] = vertex_dirs[3];
+               vertex_dirs[3] = t;
+               break;
+       case 4: //FXR90
+               t = vertex_dirs[0];
+               vertex_dirs[0] = vertex_dirs[3];
+               vertex_dirs[3] = vertex_dirs[2];
+               vertex_dirs[2] = vertex_dirs[1];
+               vertex_dirs[1] = t;
+               y0 += h;
+               h *= -1;
+               break;
+       case 5: //FXR270
+               t = vertex_dirs[0];
+               vertex_dirs[0] = vertex_dirs[1];
+               vertex_dirs[1] = vertex_dirs[2];
+               vertex_dirs[2] = vertex_dirs[3];
+               vertex_dirs[3] = t;
+               y0 += h;
+               h *= -1;
+               break;
+       case 6: //FYR90
+               t = vertex_dirs[0];
+               vertex_dirs[0] = vertex_dirs[3];
+               vertex_dirs[3] = vertex_dirs[2];
+               vertex_dirs[2] = vertex_dirs[1];
+               vertex_dirs[1] = t;
+               x0 += w;
+               w *= -1;
+               break;
+       case 7: //FYR270
+               t = vertex_dirs[0];
+               vertex_dirs[0] = vertex_dirs[1];
+               vertex_dirs[1] = vertex_dirs[2];
+               vertex_dirs[2] = vertex_dirs[3];
+               vertex_dirs[3] = t;
+               x0 += w;
+               w *= -1;
+               break;
+       case 8: //FX
+               y0 += h;
+               h *= -1;
+               break;
+       case 9: //FY
+               x0 += w;
+               w *= -1;
+               break;
+       default:
+               break;
+       }
        for(u16 i=0; i<4; i++)
        {
                vertex_pos[i] = v3f(
@@ -481,11 +560,6 @@ static void makeFastFace(TileSpec tile, u16 li0, u16 li1, u16 li2, u16 li3,
 
        u8 alpha = tile.alpha;
 
-       float x0 = tile.texture.pos.X;
-       float y0 = tile.texture.pos.Y;
-       float w = tile.texture.size.X;
-       float h = tile.texture.size.Y;
-
        face.vertices[0] = video::S3DVertex(vertex_pos[0], normal,
                        MapBlock_LightColor(alpha, li0, light_source),
                        core::vector2d<f32>(x0+w*abs_scale, y0+h));
@@ -571,12 +645,6 @@ TileSpec getNodeTileN(MapNode mn, v3s16 p, u8 tileindex, MeshMakeData *data)
        if(p == data->m_crack_pos_relative)
        {
                spec.material_flags |= MATERIAL_FLAG_CRACK;
-               spec.texture = data->m_gamedef->tsrc()->getTextureRawAP(spec.texture);
-       }
-       // If animated, replace tile texture with one without texture atlas
-       if(spec.material_flags & MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES)
-       {
-               spec.texture = data->m_gamedef->tsrc()->getTextureRawAP(spec.texture);
        }
        return spec;
 }
@@ -601,60 +669,49 @@ TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 dir, MeshMakeData *data)
        //  5 = (0,0,-1)
        //  6 = (0,-1,0)
        //  7 = (-1,0,0)
-       u8 dir_i = (dir.X + 2 * dir.Y + 3 * dir.Z) & 7;
+       u8 dir_i = ((dir.X + 2 * dir.Y + 3 * dir.Z) & 7)*2;
 
        // Get rotation for things like chests
        u8 facedir = mn.getFaceDir(ndef);
-       assert(facedir <= 3);
-       
-       static const u8 dir_to_tile[4 * 8] =
+       assert(facedir <= 23);
+       static const u16 dir_to_tile[24 * 16] =
        {
-               // 0  +X  +Y  +Z   0  -Z  -Y  -X
-                  0,  2,  0,  4,  0,  5,  1,  3,  // facedir = 0
-                  0,  4,  0,  3,  0,  2,  1,  5,  // facedir = 1
-                  0,  3,  0,  5,  0,  4,  1,  2,  // facedir = 2
-                  0,  5,  0,  2,  0,  3,  1,  4,  // facedir = 3
+               // 0     +X    +Y    +Z           -Z    -Y    -X   ->   value=tile,rotation  
+                  0,0,  2,0 , 0,0 , 4,0 ,  0,0,  5,0 , 1,0 , 3,0 ,  // rotate around y+ 0 - 3
+                  0,0,  4,0 , 0,3 , 3,0 ,  0,0,  2,0 , 1,1 , 5,0 ,
+                  0,0,  3,0 , 0,2 , 5,0 ,  0,0,  4,0 , 1,2 , 2,0 ,
+                  0,0,  5,0 , 0,1 , 2,0 ,  0,0,  3,0 , 1,3 , 4,0 ,
+
+                  0,0,  2,3 , 5,0 , 0,2 ,  0,0,  1,0 , 4,2 , 3,1 ,  // rotate around z+ 4 - 7
+                  0,0,  4,3 , 2,0 , 0,3 ,  0,0,  1,1 , 3,2 , 5,1 ,
+                  0,0,  3,3 , 4,0 , 0,0 ,  0,0,  1,2 , 5,2 , 2,1 ,
+                  0,0,  5,3 , 3,0 , 0,1 ,  0,0,  1,3 , 2,2 , 4,1 ,
+
+                  0,0,  2,1 , 4,2 , 1,2 ,  0,0,  0,0 , 5,0 , 3,3 ,  // rotate around z- 8 - 11
+                  0,0,  4,1 , 3,2 , 1,3 ,  0,0,  0,3 , 2,0 , 5,3 ,
+                  0,0,  3,1 , 5,2 , 1,0 ,  0,0,  0,2 , 4,0 , 2,3 ,
+                  0,0,  5,1 , 2,2 , 1,1 ,  0,0,  0,1 , 3,0 , 4,3 ,
+
+                  0,0,  0,3 , 3,3 , 4,1 ,  0,0,  5,3 , 2,3 , 1,3 ,  // rotate around x+ 12 - 15
+                  0,0,  0,2 , 5,3 , 3,1 ,  0,0,  2,3 , 4,3 , 1,0 ,
+                  0,0,  0,1 , 2,3 , 5,1 ,  0,0,  4,3 , 3,3 , 1,1 ,
+                  0,0,  0,0 , 4,3 , 2,1 ,  0,0,  3,3 , 5,3 , 1,2 ,
+                  
+                  0,0,  1,1 , 2,1 , 4,3 ,  0,0,  5,1 , 3,1 , 0,1 ,  // rotate around x- 16 - 19  
+                  0,0,  1,2 , 4,1 , 3,3 ,  0,0,  2,1 , 5,1 , 0,0 ,
+                  0,0,  1,3 , 3,1 , 5,3 ,  0,0,  4,1 , 2,1 , 0,3 ,  
+                  0,0,  1,0 , 5,1 , 2,3 ,  0,0,  3,1 , 4,1 , 0,2 ,  
+               
+                  0,0,  3,2 , 1,2 , 4,2 ,  0,0,  5,2 , 0,2 , 2,2 ,  // rotate around y- 20 - 23
+                  0,0,  5,2 , 1,3 , 3,2 ,  0,0,  2,2 , 0,1 , 4,2 ,  
+                  0,0,  2,2 , 1,0 , 5,2 ,  0,0,  4,2 , 0,0 , 3,2 ,  
+                  0,0,  4,2 , 1,1 , 2,2 ,  0,0,  3,2 , 0,3 , 5,2   
+                  
        };
-       u8 tileindex = dir_to_tile[facedir*8 + dir_i];
-
-       // If not rotated or is side tile, we're done
-       if(facedir == 0 || (tileindex != 0 && tileindex != 1))
-               return getNodeTileN(mn, p, tileindex, data);
-
-       // This is the top or bottom tile, and it shall be rotated; thus rotate it
-       TileSpec spec = getNodeTileN(mn, p, tileindex, data);
-       if(tileindex == 0){
-               if(facedir == 1){ // -90
-                       std::string name = data->m_gamedef->tsrc()->getTextureName(spec.texture.id);
-                       name += "^[transformR270";
-                       spec.texture = data->m_gamedef->tsrc()->getTexture(name);
-               }
-               else if(facedir == 2){ // 180
-                       spec.texture.pos += spec.texture.size;
-                       spec.texture.size *= -1;
-               }
-               else if(facedir == 3){ // 90
-                       std::string name = data->m_gamedef->tsrc()->getTextureName(spec.texture.id);
-                       name += "^[transformR90";
-                       spec.texture = data->m_gamedef->tsrc()->getTexture(name);
-               }
-       }
-       else if(tileindex == 1){
-               if(facedir == 1){ // -90
-                       std::string name = data->m_gamedef->tsrc()->getTextureName(spec.texture.id);
-                       name += "^[transformR90";
-                       spec.texture = data->m_gamedef->tsrc()->getTexture(name);
-               }
-               else if(facedir == 2){ // 180
-                       spec.texture.pos += spec.texture.size;
-                       spec.texture.size *= -1;
-               }
-               else if(facedir == 3){ // 90
-                       std::string name = data->m_gamedef->tsrc()->getTextureName(spec.texture.id);
-                       name += "^[transformR270";
-                       spec.texture = data->m_gamedef->tsrc()->getTexture(name);
-               }
-       }
+       u16 tile_index=facedir*16 + dir_i;
+       TileSpec spec = getNodeTileN(mn, p, dir_to_tile[tile_index], data);
+       spec.rotation=dir_to_tile[tile_index + 1];
+       spec.texture = data->m_gamedef->tsrc()->getTexture(spec.texture_id);
        return spec;
 }
 
@@ -745,7 +802,7 @@ static void updateFastFaceRow(
                v3f translate_dir_f,
                v3s16 face_dir,
                v3f face_dir_f,
-               core::array<FastFace> &dest)
+               std::vector<FastFace> &dest)
 {
        v3s16 p = startpos;
        
@@ -794,6 +851,7 @@ static void updateFastFaceRow(
                                        && next_lights[2] == lights[2]
                                        && next_lights[3] == lights[3]
                                        && next_tile == tile
+                                       && tile.rotation == 0
                                        && next_light_source == light_source)
                        {
                                next_is_different = false;
@@ -825,23 +883,7 @@ static void updateFastFaceRow(
 
                continuous_tiles_count++;
                
-               // This is set to true if the texture doesn't allow more tiling
-               bool end_of_texture = false;
-               /*
-                       If there is no texture, it can be tiled infinitely.
-                       If tiled==0, it means the texture can be tiled infinitely.
-                       Otherwise check tiled agains continuous_tiles_count.
-               */
-               if(tile.texture.atlas != NULL && tile.texture.tiled != 0)
-               {
-                       if(tile.texture.tiled <= continuous_tiles_count)
-                               end_of_texture = true;
-               }
-               
-               // Do this to disable tiling textures
-               //end_of_texture = true; //DEBUG
-               
-               if(next_is_different || end_of_texture)
+               if(next_is_different)
                {
                        /*
                                Create a face if there should be one
@@ -897,7 +939,7 @@ static void updateFastFaceRow(
 }
 
 static void updateAllFastFaceRows(MeshMakeData *data,
-               core::array<FastFace> &dest)
+               std::vector<FastFace> &dest)
 {
        /*
                Go through every y,z and get top(y+) faces in rows of x+
@@ -962,7 +1004,7 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data):
        // 24-155ms for MAP_BLOCKSIZE=32  (NOTE: probably outdated)
        //TimeTaker timer1("MapBlockMesh()");
 
-       core::array<FastFace> fastfaces_new;
+       std::vector<FastFace> fastfaces_new;
 
        /*
                We are including the faces of the trailing edges of the block.
@@ -996,7 +1038,7 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data):
                        const u16 indices[] = {0,1,2,2,3,0};
                        const u16 indices_alternate[] = {0,1,3,2,3,1};
                        
-                       if(f.tile.texture.atlas == NULL)
+                       if(f.tile.texture == NULL)
                                continue;
 
                        const u16 *indices_p = indices;
@@ -1034,6 +1076,8 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data):
                        getShader("test_shader_1").material;
        video::E_MATERIAL_TYPE shadermat2 = m_gamedef->getShaderSource()->
                        getShader("test_shader_2").material;
+       video::E_MATERIAL_TYPE shadermat3 = m_gamedef->getShaderSource()->
+                       getShader("test_shader_3").material;
        for(u32 i = 0; i < collector.prebuffers.size(); i++)
        {
                PreMeshBuffer &p = collector.prebuffers[i];
@@ -1046,7 +1090,7 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data):
                if(p.tile.material_flags & MATERIAL_FLAG_CRACK)
                {
                        ITextureSource *tsrc = data->m_gamedef->tsrc();
-                       std::string crack_basename = tsrc->getTextureName(p.tile.texture.id);
+                       std::string crack_basename = tsrc->getTextureName(p.tile.texture_id);
                        if(p.tile.material_flags & MATERIAL_FLAG_CRACK_OVERLAY)
                                crack_basename += "^[cracko";
                        else
@@ -1071,9 +1115,11 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data):
                        }
                        // Replace tile texture with the first animation frame
                        std::ostringstream os(std::ios::binary);
-                       os<<tsrc->getTextureName(p.tile.texture.id);
+                       os<<tsrc->getTextureName(p.tile.texture_id);
                        os<<"^[verticalframe:"<<(int)p.tile.animation_frame_count<<":0";
-                       p.tile.texture = tsrc->getTexture(os.str());
+                       p.tile.texture = tsrc->getTexture(
+                                       os.str(),
+                                       &p.tile.texture_id);
                }
                // - Classic lighting (shaders handle this by themselves)
                if(!enable_shaders)
@@ -1107,9 +1153,9 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data):
                //material.setFlag(video::EMF_ANTI_ALIASING, video::EAAM_SIMPLE);
                material.MaterialType
                                = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
-               material.setTexture(0, p.tile.texture.atlas);
+               material.setTexture(0, p.tile.texture);
                if(enable_shaders)
-                       p.tile.applyMaterialOptionsWithShaders(material, shadermat1, shadermat2);
+                       p.tile.applyMaterialOptionsWithShaders(material, shadermat1, shadermat2, shadermat3);
                else
                        p.tile.applyMaterialOptions(material);
 
@@ -1124,8 +1170,8 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data):
                m_mesh->addMeshBuffer(buf);
                // Mesh grabbed it
                buf->drop();
-               buf->append(p.vertices.pointer(), p.vertices.size(),
-                               p.indices.pointer(), p.indices.size());
+               buf->append(&p.vertices[0], p.vertices.size(),
+                               &p.indices[0], p.indices.size());
        }
 
        /*
@@ -1133,7 +1179,6 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data):
        */
 
        translateMesh(m_mesh, intToFloat(data->m_blockpos * MAP_BLOCKSIZE, BS));
-       m_mesh->recalculateBoundingBox(); // translateMesh already does this
 
        if(m_mesh)
        {
@@ -1194,8 +1239,8 @@ bool MapBlockMesh::animate(bool faraway, float time, int crack, u32 daynight_rat
                        ITextureSource *tsrc = m_gamedef->getTextureSource();
                        std::ostringstream os;
                        os<<basename<<crack;
-                       AtlasPointer ap = tsrc->getTexture(os.str());
-                       buf->getMaterial().setTexture(0, ap.atlas);
+                       buf->getMaterial().setTexture(0,
+                                       tsrc->getTexture(os.str()));
                }
 
                m_last_crack = crack;
@@ -1222,11 +1267,10 @@ bool MapBlockMesh::animate(bool faraway, float time, int crack, u32 daynight_rat
 
                // Create new texture name from original
                std::ostringstream os(std::ios::binary);
-               os<<tsrc->getTextureName(tile.texture.id);
+               os<<tsrc->getTextureName(tile.texture_id);
                os<<"^[verticalframe:"<<(int)tile.animation_frame_count<<":"<<frame;
                // Set the texture
-               AtlasPointer ap = tsrc->getTexture(os.str());
-               buf->getMaterial().setTexture(0, ap.atlas);
+               buf->getMaterial().setTexture(0, tsrc->getTexture(os.str()));
        }
 
        // Day-night transition
@@ -1271,12 +1315,20 @@ void MeshCollector::append(const TileSpec &tile,
                const video::S3DVertex *vertices, u32 numVertices,
                const u16 *indices, u32 numIndices)
 {
+       if(numIndices > 65535)
+       {
+               dstream<<"FIXME: MeshCollector::append() called with numIndices="<<numIndices<<" (limit 65535)"<<std::endl;
+               return;
+       }
+
        PreMeshBuffer *p = NULL;
        for(u32 i=0; i<prebuffers.size(); i++)
        {
                PreMeshBuffer &pp = prebuffers[i];
                if(pp.tile != tile)
                        continue;
+               if(pp.indices.size() + numIndices > 65535)
+                       continue;
 
                p = &pp;
                break;
@@ -1294,11 +1346,6 @@ void MeshCollector::append(const TileSpec &tile,
        for(u32 i=0; i<numIndices; i++)
        {
                u32 j = indices[i] + vertex_count;
-               if(j > 65535)
-               {
-                       dstream<<"FIXME: Meshbuffer ran out of indices"<<std::endl;
-                       // NOTE: Fix is to just add an another MeshBuffer
-               }
                p->indices.push_back(j);
        }
        for(u32 i=0; i<numVertices; i++)