Fix water-glass and water-lava surfaces
authorPerttu Ahola <celeron55@gmail.com>
Tue, 8 Nov 2011 14:17:38 +0000 (16:17 +0200)
committerPerttu Ahola <celeron55@gmail.com>
Tue, 8 Nov 2011 14:17:38 +0000 (16:17 +0200)
src/content_mapblock.cpp
src/content_mapnode.cpp
src/mapblock_mesh.cpp
src/mapnode.cpp
src/mapnode.h

index 60e07781e3d1669b52a2b7389d4ea5e3f8b7becc..b033e484c35adf6fc1096319de0092889a26b4ba 100644 (file)
@@ -364,6 +364,9 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
                        assert(content_features(n).special_material);
                        video::SMaterial &liquid_material =
                                        *content_features(n).special_material;
+                       video::SMaterial &liquid_material_bfculled =
+                                       *content_features(n).special_material2;
+
                        assert(content_features(n).special_atlas);
                        AtlasPointer &pa_liquid1 =
                                        *content_features(n).special_atlas;
@@ -516,10 +519,10 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
                                        continue;
 
                                content_t neighbor_content = neighbor_contents[dir];
+                               ContentFeatures &n_feat = content_features(neighbor_content);
                                
-                               // Don't draw face if neighbor is not air or liquid
-                               if(neighbor_content != CONTENT_AIR
-                                               && content_liquid(neighbor_content) == false)
+                               // Don't draw face if neighbor is blocking the view
+                               if(n_feat.solidness == 2)
                                        continue;
                                
                                bool neighbor_is_same_liquid = (neighbor_content == c_source
@@ -530,6 +533,12 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
                                if(neighbor_is_same_liquid == true
                                                && top_is_same_liquid == false)
                                        continue;
+
+                               // Use backface culled material if neighbor doesn't have a
+                               // solidness of 0
+                               video::SMaterial *current_material = &liquid_material;
+                               if(n_feat.solidness != 0 || n_feat.visual_solidness != 0)
+                                       current_material = &liquid_material_bfculled;
                                
                                video::S3DVertex vertices[4] =
                                {
@@ -603,7 +612,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
 
                                u16 indices[] = {0,1,2,2,3,0};
                                // Add to mesh collector
-                               collector.append(liquid_material, vertices, 4, indices, 6);
+                               collector.append(*current_material, vertices, 4, indices, 6);
                        }
                        
                        /*
index bb6d7caa7284e82ecbb92c34636937b877d9ee38..f10b941ba57b6ea1b261bfef91a9342b06002a6b 100644 (file)
@@ -415,6 +415,12 @@ void content_mapnode_init()
                AtlasPointer *pa_water1 = new AtlasPointer(g_texturesource->getTexture(
                                g_texturesource->getTextureId("water.png")));
                f->special_material->setTexture(0, pa_water1->atlas);
+
+               // Flowing water material, backface culled
+               f->special_material2 = new video::SMaterial;
+               *f->special_material2 = *f->special_material;
+               f->special_material2->setFlag(video::EMF_BACK_FACE_CULLING, true);
+               
                f->special_atlas = pa_water1;
        }
 #endif
@@ -460,7 +466,7 @@ void content_mapnode_init()
        f->post_effect_color = video::SColor(64, 100, 100, 200);
        if(f->special_material == NULL && g_texturesource)
        {
-               // Flowing water material
+               // New-style water source material (mostly unused)
                f->special_material = new video::SMaterial;
                f->special_material->setFlag(video::EMF_LIGHTING, false);
                f->special_material->setFlag(video::EMF_BACK_FACE_CULLING, false);
@@ -482,7 +488,7 @@ void content_mapnode_init()
        f->light_propagates = false;
        f->light_source = LIGHT_MAX-1;
        f->solidness = 0; // Drawn separately, makes no faces
-       f->visual_solidness = 2;
+       f->visual_solidness = 1; // Does not completely cover block boundaries
        f->walkable = false;
        f->pointable = false;
        f->diggable = false;
@@ -503,10 +509,17 @@ void content_mapnode_init()
                f->special_material->setFlag(video::EMF_BILINEAR_FILTER, false);
                f->special_material->setFlag(video::EMF_FOG_ENABLE, true);
                f->special_material->MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
+
                AtlasPointer *pa_lava1 = new AtlasPointer(
                        g_texturesource->getTexture(
                                g_texturesource->getTextureId("lava.png")));
                f->special_material->setTexture(0, pa_lava1->atlas);
+
+               // Flowing lava material, backface culled
+               f->special_material2 = new video::SMaterial;
+               *f->special_material2 = *f->special_material;
+               f->special_material2->setFlag(video::EMF_BACK_FACE_CULLING, true);
+
                f->special_atlas = pa_lava1;
        }
 #endif
@@ -550,7 +563,7 @@ void content_mapnode_init()
        f->post_effect_color = video::SColor(192, 255, 64, 0);
        if(f->special_material == NULL && g_texturesource)
        {
-               // Flowing lava material
+               // New-style lava source material (mostly unused)
                f->special_material = new video::SMaterial;
                f->special_material->setFlag(video::EMF_LIGHTING, false);
                f->special_material->setFlag(video::EMF_BACK_FACE_CULLING, false);
@@ -561,6 +574,7 @@ void content_mapnode_init()
                        g_texturesource->getTexture(
                                g_texturesource->getTextureId("lava.png")));
                f->special_material->setTexture(0, pa_lava1->atlas);
+
                f->special_atlas = pa_lava1;
        }
 #endif
index 7ee49986f1465ef2d4b5e34d6a3c26df4c26b0a2..5a29fbe949c287b80d7e82a3541d41bb21346461 100644 (file)
@@ -427,7 +427,8 @@ void getTileInfo(
        // This is hackish
        content_t content0 = getNodeContent(p, n0, temp_mods);
        content_t content1 = getNodeContent(p + face_dir, n1, temp_mods);
-       u8 mf = face_contents(content0, content1);
+       bool equivalent = false;
+       u8 mf = face_contents(content0, content1, &equivalent);
 
        if(mf == 0)
        {
@@ -450,6 +451,10 @@ void getTileInfo(
                face_dir_corrected = -face_dir;
        }
        
+       // eg. water and glass
+       if(equivalent)
+               tile.material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
+       
        if(smooth_lighting == false)
        {
                lights[0] = lights[1] = lights[2] = lights[3] =
index 847608040b20bf27ccfc6f0c17ddb879dfaf5a6d..f816319999e1c30196c0b066f5aa83a45f55800a 100644 (file)
@@ -174,6 +174,57 @@ void init_mapnode()
        
 }
 
+/*
+       Nodes make a face if contents differ and solidness differs.
+       Return value:
+               0: No face
+               1: Face uses m1's content
+               2: Face uses m2's content
+       equivalent: Whether the blocks share the same face (eg. water and glass)
+*/
+u8 face_contents(content_t m1, content_t m2, bool *equivalent)
+{
+       *equivalent = false;
+
+       if(m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE)
+               return 0;
+       
+       bool contents_differ = (m1 != m2);
+       
+       // Contents don't differ for different forms of same liquid
+       if(content_liquid(m1) && content_liquid(m2)
+                       && make_liquid_flowing(m1) == make_liquid_flowing(m2))
+               contents_differ = false;
+       
+       u8 c1 = content_solidness(m1);
+       u8 c2 = content_solidness(m2);
+
+       bool solidness_differs = (c1 != c2);
+       bool makes_face = contents_differ && solidness_differs;
+
+       if(makes_face == false)
+               return 0;
+       
+       if(c1 == 0)
+               c1 = content_features(m1).visual_solidness;
+       if(c2 == 0)
+               c2 = content_features(m2).visual_solidness;
+       
+       if(c1 == c2){
+               *equivalent = true;
+               // If same solidness, liquid takes precense
+               if(content_features(m1).liquid_type != LIQUID_NONE)
+                       return 1;
+               if(content_features(m2).liquid_type != LIQUID_NONE)
+                       return 2;
+       }
+       
+       if(c1 > c2)
+               return 1;
+       else
+               return 2;
+}
+
 v3s16 facedir_rotate(u8 facedir, v3s16 dir)
 {
        /*
index 81445b9ac4e71434725d66a3d3822b49d5ca5808..51bee058704752c7bd29c776932ffac99b8d72f8 100644 (file)
@@ -121,6 +121,7 @@ struct ContentFeatures
        video::SColor post_effect_color;
        // Special irrlicht material, used sometimes
        video::SMaterial *special_material;
+       video::SMaterial *special_material2;
        AtlasPointer *special_atlas;
 #endif
 
@@ -199,6 +200,7 @@ struct ContentFeatures
                vertex_alpha = 255;
                post_effect_color = video::SColor(0, 0, 0, 0);
                special_material = NULL;
+               special_material2 = NULL;
                special_atlas = NULL;
 #endif
                param_type = CPT_NONE;
@@ -377,44 +379,9 @@ inline bool content_buildable_to(content_t m)
                0: No face
                1: Face uses m1's content
                2: Face uses m2's content
+       equivalent: Whether the blocks share the same face (eg. water and glass)
 */
-inline u8 face_contents(content_t m1, content_t m2)
-{
-       if(m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE)
-               return 0;
-       
-       bool contents_differ = (m1 != m2);
-       
-       // Contents don't differ for different forms of same liquid
-       if(content_liquid(m1) && content_liquid(m2)
-                       && make_liquid_flowing(m1) == make_liquid_flowing(m2))
-               contents_differ = false;
-       
-       bool solidness_differs = (content_solidness(m1) != content_solidness(m2));
-       bool makes_face = contents_differ && solidness_differs;
-
-       if(makes_face == false)
-               return 0;
-       
-       u8 c1 = content_solidness(m1);
-       u8 c2 = content_solidness(m2);
-       
-       /*
-               Special case for half-transparent content.
-
-               This makes eg. the water (solidness=1) surrounding an underwater
-               glass block (solidness=0, visual_solidness=1) not get drawn.
-       */
-       if(c1 == 1 && c2 == 0 && content_features(m2).visual_solidness != 0)
-               return 0;
-       if(c2 == 1 && c1 == 0 && content_features(m1).visual_solidness != 0)
-               return 0;
-
-       if(c1 > c2)
-               return 1;
-       else
-               return 2;
-}
+u8 face_contents(content_t m1, content_t m2, bool *equivalent);
 
 /*
        Packs directions like (1,0,0), (1,-1,0)