From 045e32b6ecb99432beac3363685fb622e9ec3457 Mon Sep 17 00:00:00 2001 From: Perttu Ahola 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)