Optimize shaders code. Add settings at compile time.
[oweals/minetest.git] / src / mapblock_mesh.cpp
index be88b19732692e88d2979511dfaff5c7fe2856a9..afea3dcce2e9224d3d894b69c366834ae99d20ec 100644 (file)
@@ -448,14 +448,21 @@ static void makeFastFace(TileSpec tile, u16 li0, u16 li1, u16 li2, u16 li3,
                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;
+       u16 t1;
        switch (tile.rotation)
        {
        case 0:
@@ -466,6 +473,11 @@ static void makeFastFace(TileSpec tile, u16 li0, u16 li1, u16 li2, u16 li3,
                vertex_dirs[3] = vertex_dirs[2];
                vertex_dirs[2] = vertex_dirs[1];
                vertex_dirs[1] = t;
+               t1=li0;
+               li0=li3;
+               li3=li2;
+               li2=li1;
+               li1=t1;
                break;
        case 2: //R180
                t = vertex_dirs[0];
@@ -474,6 +486,12 @@ static void makeFastFace(TileSpec tile, u16 li0, u16 li1, u16 li2, u16 li3,
                t = vertex_dirs[1];
                vertex_dirs[1] = vertex_dirs[3];
                vertex_dirs[3] = t;
+               t1  = li0;
+               li0 = li2;
+               li2 = t1;
+               t1  = li1;
+               li1 = li3;
+               li3 = t1;
                break;
        case 3: //R270
                t = vertex_dirs[0];
@@ -481,6 +499,11 @@ static void makeFastFace(TileSpec tile, u16 li0, u16 li1, u16 li2, u16 li3,
                vertex_dirs[1] = vertex_dirs[2];
                vertex_dirs[2] = vertex_dirs[3];
                vertex_dirs[3] = t;
+               t1  = li0;
+               li0 = li1;
+               li1 = li2;
+               li2 = li3;
+               li3 = t1;
                break;
        case 4: //FXR90
                t = vertex_dirs[0];
@@ -488,8 +511,13 @@ static void makeFastFace(TileSpec tile, u16 li0, u16 li1, u16 li2, u16 li3,
                vertex_dirs[3] = vertex_dirs[2];
                vertex_dirs[2] = vertex_dirs[1];
                vertex_dirs[1] = t;
-               tile.texture.pos.Y += tile.texture.size.Y;
-               tile.texture.size.Y *= -1;
+               t1  = li0;
+               li0 = li3;
+               li3 = li2;
+               li2 = li1;
+               li1 = t1;
+               y0 += h;
+               h *= -1;
                break;
        case 5: //FXR270
                t = vertex_dirs[0];
@@ -497,8 +525,13 @@ static void makeFastFace(TileSpec tile, u16 li0, u16 li1, u16 li2, u16 li3,
                vertex_dirs[1] = vertex_dirs[2];
                vertex_dirs[2] = vertex_dirs[3];
                vertex_dirs[3] = t;
-               tile.texture.pos.Y += tile.texture.size.Y;
-               tile.texture.size.Y *= -1;
+               t1  = li0;
+               li0 = li1;
+               li1 = li2;
+               li2 = li3;
+               li3 = t1;
+               y0 += h;
+               h *= -1;
                break;
        case 6: //FYR90
                t = vertex_dirs[0];
@@ -506,8 +539,13 @@ static void makeFastFace(TileSpec tile, u16 li0, u16 li1, u16 li2, u16 li3,
                vertex_dirs[3] = vertex_dirs[2];
                vertex_dirs[2] = vertex_dirs[1];
                vertex_dirs[1] = t;
-               tile.texture.pos.X += tile.texture.size.X;
-               tile.texture.size.X *= -1;
+               t1  = li0;
+               li0 = li3;
+               li3 = li2;
+               li2 = li1;
+               li1 = t1;
+               x0 += w;
+               w *= -1;
                break;
        case 7: //FYR270
                t = vertex_dirs[0];
@@ -515,20 +553,26 @@ static void makeFastFace(TileSpec tile, u16 li0, u16 li1, u16 li2, u16 li3,
                vertex_dirs[1] = vertex_dirs[2];
                vertex_dirs[2] = vertex_dirs[3];
                vertex_dirs[3] = t;
-               tile.texture.pos.X += tile.texture.size.X;
-               tile.texture.size.X *= -1;
+               t1  = li0;
+               li0 = li1;
+               li1 = li2;
+               li2 = li3;
+               li3 = t1;
+               x0 += w;
+               w *= -1;
                break;
        case 8: //FX
-               tile.texture.pos.Y += tile.texture.size.Y;
-               tile.texture.size.Y *= -1;
+               y0 += h;
+               h *= -1;
                break;
        case 9: //FY
-               tile.texture.pos.X += tile.texture.size.X;
-               tile.texture.size.X *= -1;
+               x0 += w;
+               w *= -1;
                break;
        default:
                break;
        }
+
        for(u16 i=0; i<4; i++)
        {
                vertex_pos[i] = v3f(
@@ -546,7 +590,7 @@ static void makeFastFace(TileSpec tile, u16 li0, u16 li1, u16 li2, u16 li3,
                vertex_pos[i] += pos;
        }
 
-       f32 abs_scale = 1.;
+       f32 abs_scale = 1.0;
        if     (scale.X < 0.999 || scale.X > 1.001) abs_scale = scale.X;
        else if(scale.Y < 0.999 || scale.Y > 1.001) abs_scale = scale.Y;
        else if(scale.Z < 0.999 || scale.Z > 1.001) abs_scale = scale.Z;
@@ -555,11 +599,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));
@@ -574,7 +613,6 @@ static void makeFastFace(TileSpec tile, u16 li0, u16 li1, u16 li2, u16 li3,
                        core::vector2d<f32>(x0+w*abs_scale, y0));
 
        face.tile = tile;
-       
        dest.push_back(face);
 }
 
@@ -645,12 +683,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;
 }
@@ -679,7 +711,8 @@ TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 dir, MeshMakeData *data)
 
        // Get rotation for things like chests
        u8 facedir = mn.getFaceDir(ndef);
-       assert(facedir <= 23);
+       if (facedir > 23)
+               facedir = 0;
        static const u16 dir_to_tile[24 * 16] =
        {
                // 0     +X    +Y    +Z           -Z    -Y    -X   ->   value=tile,rotation  
@@ -702,22 +735,22 @@ TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 dir, MeshMakeData *data)
                   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   
-                  
+
        };
        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);
+       spec.texture = data->m_gamedef->tsrc()->getTexture(spec.texture_id);
        return spec;
 }
 
@@ -889,23 +922,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
@@ -1060,7 +1077,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;
@@ -1091,15 +1108,25 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data):
 
        /*
                Convert MeshCollector to SMesh
-               Also store animation info
        */
-       bool enable_shaders = (g_settings->getS32("enable_shaders") > 0);
-       video::E_MATERIAL_TYPE shadermat1 = m_gamedef->getShaderSource()->
-                       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;
+       bool enable_shaders     = g_settings->getBool("enable_shaders");
+       bool enable_bumpmapping = g_settings->getBool("enable_bumpmapping");
+       bool enable_parallax_occlusion = g_settings->getBool("enable_parallax_occlusion");
+
+       video::E_MATERIAL_TYPE  shadermat1, shadermat2, shadermat3,
+                                                       shadermat4, shadermat5;
+       shadermat1 = shadermat2 = shadermat3 = shadermat4 = shadermat5 = 
+               video::EMT_SOLID;
+
+       if (enable_shaders) {
+               IShaderSource *shdrsrc = m_gamedef->getShaderSource();
+               shadermat1 = shdrsrc->getShader("solids_shader").material;
+               shadermat2 = shdrsrc->getShader("liquids_shader").material;
+               shadermat3 = shdrsrc->getShader("alpha_shader").material;
+               shadermat4 = shdrsrc->getShader("leaves_shader").material;
+               shadermat5 = shdrsrc->getShader("plants_shader").material;
+       }
+
        for(u32 i = 0; i < collector.prebuffers.size(); i++)
        {
                PreMeshBuffer &p = collector.prebuffers[i];
@@ -1112,12 +1139,17 @@ 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);
+                       // Find the texture name plus ^[crack:N:
+                       std::ostringstream os(std::ios::binary);
+                       os<<tsrc->getTextureName(p.tile.texture_id)<<"^[crack";
                        if(p.tile.material_flags & MATERIAL_FLAG_CRACK_OVERLAY)
-                               crack_basename += "^[cracko";
-                       else
-                               crack_basename += "^[crack";
-                       m_crack_materials.insert(std::make_pair(i, crack_basename));
+                               os<<"o";  // use ^[cracko
+                       os<<":"<<(u32)p.tile.animation_frame_count<<":";
+                       m_crack_materials.insert(std::make_pair(i, os.str()));
+                       // Replace tile texture with the cracked one
+                       p.tile.texture = tsrc->getTexture(
+                                       os.str()+"0",
+                                       &p.tile.texture_id);
                }
                // - Texture animation
                if(p.tile.material_flags & MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES)
@@ -1137,9 +1169,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)
@@ -1171,14 +1205,34 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data):
                material.setFlag(video::EMF_FOG_ENABLE, true);
                //material.setFlag(video::EMF_ANTI_ALIASING, video::EAAM_OFF);
                //material.setFlag(video::EMF_ANTI_ALIASING, video::EAAM_SIMPLE);
-               material.MaterialType
-                               = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
-               material.setTexture(0, p.tile.texture.atlas);
-               if(enable_shaders)
-                       p.tile.applyMaterialOptionsWithShaders(material, shadermat1, shadermat2, shadermat3);
-               else
-                       p.tile.applyMaterialOptions(material);
+               //material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
+               material.setTexture(0, p.tile.texture);
 
+               if (enable_shaders) {
+                       ITextureSource *tsrc = data->m_gamedef->tsrc();
+                       material.setTexture(2, tsrc->getTexture("disable_img.png"));
+                       if (enable_bumpmapping || enable_parallax_occlusion) {
+                               std::string fname_base = tsrc->getTextureName(p.tile.texture_id);
+                               std::string normal_ext = "_normal.png";
+                               size_t pos = fname_base.find(".");
+                               std::string fname_normal = fname_base.substr(0, pos) + normal_ext;
+
+                               if (tsrc->isKnownSourceImage(fname_normal)) {
+                                       // look for image extension and replace it 
+                                       size_t i = 0;
+                                       while ((i = fname_base.find(".", i)) != std::string::npos) {
+                                               fname_base.replace(i, 4, normal_ext);
+                                               i += normal_ext.length();
+                                       }
+                                       material.setTexture(1, tsrc->getTexture(fname_base));
+                                       material.setTexture(2, tsrc->getTexture("enable_img.png"));
+                               }
+                       }
+                       p.tile.applyMaterialOptionsWithShaders(material,
+                               shadermat1, shadermat2, shadermat3, shadermat4, shadermat5);
+               } else {
+                       p.tile.applyMaterialOptions(material);
+               }
                // Create meshbuffer
 
                // This is a "Standard MeshBuffer",
@@ -1237,6 +1291,10 @@ MapBlockMesh::~MapBlockMesh()
 
 bool MapBlockMesh::animate(bool faraway, float time, int crack, u32 daynight_ratio)
 {
+       bool enable_shaders = g_settings->getBool("enable_shaders");
+       bool enable_bumpmapping = g_settings->getBool("enable_bumpmapping");
+       bool enable_parallax_occlusion = g_settings->getBool("enable_parallax_occlusion");
+
        if(!m_has_animation)
        {
                m_animation_force_timer = 100000;
@@ -1259,8 +1317,22 @@ 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);
+                       u32 new_texture_id = 0;
+                       video::ITexture *new_texture =
+                               tsrc->getTexture(os.str(), &new_texture_id);
+                       buf->getMaterial().setTexture(0, new_texture);
+
+                       // If the current material is also animated,
+                       // update animation info
+                       std::map<u32, TileSpec>::iterator anim_iter =
+                               m_animation_tiles.find(i->first);
+                       if(anim_iter != m_animation_tiles.end()){
+                               TileSpec &tile = anim_iter->second;
+                               tile.texture = new_texture;
+                               tile.texture_id = new_texture_id;
+                               // force animation update
+                               m_animation_frames[i->first] = -1;
+                       }
                }
 
                m_last_crack = crack;
@@ -1287,11 +1359,26 @@ 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()));
+               buf->getMaterial().setTexture(2, tsrc->getTexture("disable_img.png"));
+               if (enable_shaders && (enable_bumpmapping || enable_parallax_occlusion))
+                       {
+                               std::string fname_base,fname_normal;
+                               fname_base = tsrc->getTextureName(tile.texture_id);
+                               unsigned pos;
+                               pos = fname_base.find(".");
+                               fname_normal = fname_base.substr (0, pos);
+                               fname_normal += "_normal.png";
+                               if (tsrc->isKnownSourceImage(fname_normal)){
+                                       os.str("");
+                                       os<<fname_normal<<"^[verticalframe:"<<(int)tile.animation_frame_count<<":"<<frame;
+                                       buf->getMaterial().setTexture(1, tsrc->getTexture(os.str()));
+                                       buf->getMaterial().setTexture(2, tsrc->getTexture("enable_img.png"));
+                               }
+                       }
        }
 
        // Day-night transition