From 045e32b6ecb99432beac3363685fb622e9ec3457 Mon Sep 17 00:00:00 2001
From: Perttu Ahola <celeron55@gmail.com>
Date: Tue, 8 Nov 2011 16:17:38 +0200
Subject: [PATCH] Fix water-glass and water-lava surfaces

---
 src/content_mapblock.cpp | 17 ++++++++++----
 src/content_mapnode.cpp  | 20 +++++++++++++---
 src/mapblock_mesh.cpp    |  7 +++++-
 src/mapnode.cpp          | 51 ++++++++++++++++++++++++++++++++++++++++
 src/mapnode.h            | 41 ++++----------------------------
 5 files changed, 91 insertions(+), 45 deletions(-)

diff --git a/src/content_mapblock.cpp b/src/content_mapblock.cpp
index 60e07781e..b033e484c 100644
--- a/src/content_mapblock.cpp
+++ b/src/content_mapblock.cpp
@@ -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);
 			}
 			
 			/*
diff --git a/src/content_mapnode.cpp b/src/content_mapnode.cpp
index bb6d7caa7..f10b941ba 100644
--- a/src/content_mapnode.cpp
+++ b/src/content_mapnode.cpp
@@ -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
diff --git a/src/mapblock_mesh.cpp b/src/mapblock_mesh.cpp
index 7ee49986f..5a29fbe94 100644
--- a/src/mapblock_mesh.cpp
+++ b/src/mapblock_mesh.cpp
@@ -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] =
diff --git a/src/mapnode.cpp b/src/mapnode.cpp
index 847608040..f81631999 100644
--- a/src/mapnode.cpp
+++ b/src/mapnode.cpp
@@ -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)
 {
 	/*
diff --git a/src/mapnode.h b/src/mapnode.h
index 81445b9ac..51bee0587 100644
--- a/src/mapnode.h
+++ b/src/mapnode.h
@@ -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)
-- 
GitLab