X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fmapblock.cpp;h=58b23bd146e6001d50055a18357c1e1ae308bde7;hb=94c9686020798c8ec8113c242dc1dfe0c2accf71;hp=6f7e7533ee3d53d32d74b99d993ca3bcc80354ee;hpb=b36e5c05088aca7b500bf5fe355f4b3c205a59a3;p=minetest.git diff --git a/src/mapblock.cpp b/src/mapblock.cpp index 6f7e7533e..58b23bd14 100644 --- a/src/mapblock.cpp +++ b/src/mapblock.cpp @@ -133,53 +133,94 @@ u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2, #ifndef SERVER -void makeFastFace(TileSpec tile, u8 light, v3f p, - v3s16 dir, v3f scale, v3f posRelative_f, - core::array &dest) +/* + vertex_dirs: v3s16[4] +*/ +void getNodeVertexDirs(v3s16 dir, v3s16 *vertex_dirs) { - FastFace face; - - // Position is at the center of the cube. - v3f pos = p * BS; - posRelative_f *= BS; - - v3f vertex_pos[4]; - // If looking towards z+, this is the face that is behind - // the center point, facing towards z+. - vertex_pos[0] = v3f(-BS/2,-BS/2,BS/2); - vertex_pos[1] = v3f( BS/2,-BS/2,BS/2); - vertex_pos[2] = v3f( BS/2, BS/2,BS/2); - vertex_pos[3] = v3f(-BS/2, BS/2,BS/2); - + /* + If looked from outside the node towards the face, the corners are: + 0: bottom-right + 1: bottom-left + 2: top-left + 3: top-right + */ if(dir == v3s16(0,0,1)) { - for(u16 i=0; i<4; i++) - vertex_pos[i].rotateXZBy(0); + // If looking towards z+, this is the face that is behind + // the center point, facing towards z+. + vertex_dirs[0] = v3s16(-1,-1, 1); + vertex_dirs[1] = v3s16( 1,-1, 1); + vertex_dirs[2] = v3s16( 1, 1, 1); + vertex_dirs[3] = v3s16(-1, 1, 1); } else if(dir == v3s16(0,0,-1)) { - for(u16 i=0; i<4; i++) - vertex_pos[i].rotateXZBy(180); + // faces towards Z- + vertex_dirs[0] = v3s16( 1,-1,-1); + vertex_dirs[1] = v3s16(-1,-1,-1); + vertex_dirs[2] = v3s16(-1, 1,-1); + vertex_dirs[3] = v3s16( 1, 1,-1); } else if(dir == v3s16(1,0,0)) { - for(u16 i=0; i<4; i++) - vertex_pos[i].rotateXZBy(-90); + // faces towards X+ + vertex_dirs[0] = v3s16( 1,-1, 1); + vertex_dirs[1] = v3s16( 1,-1,-1); + vertex_dirs[2] = v3s16( 1, 1,-1); + vertex_dirs[3] = v3s16( 1, 1, 1); } else if(dir == v3s16(-1,0,0)) { - for(u16 i=0; i<4; i++) - vertex_pos[i].rotateXZBy(90); + // faces towards X- + vertex_dirs[0] = v3s16(-1,-1,-1); + vertex_dirs[1] = v3s16(-1,-1, 1); + vertex_dirs[2] = v3s16(-1, 1, 1); + vertex_dirs[3] = v3s16(-1, 1,-1); } else if(dir == v3s16(0,1,0)) { - for(u16 i=0; i<4; i++) - vertex_pos[i].rotateYZBy(-90); + // faces towards Y+ (assume Z- as "down" in texture) + vertex_dirs[0] = v3s16( 1, 1,-1); + vertex_dirs[1] = v3s16(-1, 1,-1); + vertex_dirs[2] = v3s16(-1, 1, 1); + vertex_dirs[3] = v3s16( 1, 1, 1); } else if(dir == v3s16(0,-1,0)) { - for(u16 i=0; i<4; i++) - vertex_pos[i].rotateYZBy(90); + // faces towards Y- (assume Z+ as "down" in texture) + vertex_dirs[0] = v3s16( 1,-1, 1); + vertex_dirs[1] = v3s16(-1,-1, 1); + vertex_dirs[2] = v3s16(-1,-1,-1); + vertex_dirs[3] = v3s16( 1,-1,-1); + } +} + +inline video::SColor lightColor(u8 alpha, u8 light) +{ + return video::SColor(alpha,light,light,light); +} + +void makeFastFace(TileSpec tile, u8 li0, u8 li1, u8 li2, u8 li3, v3f p, + v3s16 dir, v3f scale, v3f posRelative_f, + core::array &dest) +{ + FastFace face; + + // Position is at the center of the cube. + v3f pos = p * BS; + posRelative_f *= BS; + + v3f vertex_pos[4]; + v3s16 vertex_dirs[4]; + getNodeVertexDirs(dir, vertex_dirs); + for(u16 i=0; i<4; i++) + { + vertex_pos[i] = v3f( + BS/2*vertex_dirs[i].X, + BS/2*vertex_dirs[i].Y, + BS/2*vertex_dirs[i].Z + ); } for(u16 i=0; i<4; i++) @@ -197,22 +238,18 @@ void makeFastFace(TileSpec tile, u8 light, v3f p, v3f zerovector = v3f(0,0,0); - //u8 li = decode_light(light); - u8 li = light; - //u8 li = 255; //DEBUG - u8 alpha = tile.alpha; /*u8 alpha = 255; if(tile.id == TILE_WATER) alpha = WATER_ALPHA;*/ - video::SColor c = video::SColor(alpha,li,li,li); - float x0 = tile.texture.pos.X; float y0 = tile.texture.pos.Y; float w = tile.texture.size.X; float h = tile.texture.size.Y; + /*video::SColor c = lightColor(alpha, li); + face.vertices[0] = video::S3DVertex(vertex_pos[0], v3f(0,1,0), c, core::vector2d(x0+w*abs_scale, y0+h)); face.vertices[1] = video::S3DVertex(vertex_pos[1], v3f(0,1,0), c, @@ -220,6 +257,19 @@ void makeFastFace(TileSpec tile, u8 light, v3f p, face.vertices[2] = video::S3DVertex(vertex_pos[2], v3f(0,1,0), c, core::vector2d(x0, y0)); face.vertices[3] = video::S3DVertex(vertex_pos[3], v3f(0,1,0), c, + core::vector2d(x0+w*abs_scale, y0));*/ + + face.vertices[0] = video::S3DVertex(vertex_pos[0], v3f(0,1,0), + lightColor(alpha, li0), + core::vector2d(x0+w*abs_scale, y0+h)); + face.vertices[1] = video::S3DVertex(vertex_pos[1], v3f(0,1,0), + lightColor(alpha, li1), + core::vector2d(x0, y0+h)); + face.vertices[2] = video::S3DVertex(vertex_pos[2], v3f(0,1,0), + lightColor(alpha, li2), + core::vector2d(x0, y0)); + face.vertices[3] = video::S3DVertex(vertex_pos[3], v3f(0,1,0), + lightColor(alpha, li3), core::vector2d(x0+w*abs_scale, y0)); face.tile = tile; @@ -227,7 +277,6 @@ void makeFastFace(TileSpec tile, u8 light, v3f p, //f->tile = TILE_STONE; dest.push_back(face); - //return f; } /* @@ -324,6 +373,133 @@ u8 getNodeContent(v3s16 p, MapNode mn, NodeModMap &temp_mods) return mn.d; } +v3s16 dirs8[8] = { + v3s16(0,0,0), + v3s16(0,0,1), + v3s16(0,1,0), + v3s16(0,1,1), + v3s16(1,0,0), + v3s16(1,1,0), + v3s16(1,0,1), + v3s16(1,1,1), +}; + +// Calculate lighting at the XYZ- corner of p +u8 getSmoothLight(v3s16 p, VoxelManipulator &vmanip, u32 daynight_ratio) +{ + u16 ambient_occlusion = 0; + u16 light = 0; + u16 light_count = 0; + for(u32 i=0; i<8; i++) + { + MapNode n = vmanip.getNodeNoEx(p - dirs8[i]); + if(content_features(n.d).param_type == CPT_LIGHT) + { + light += decode_light(n.getLightBlend(daynight_ratio)); + light_count++; + } + else + { + if(n.d != CONTENT_IGNORE) + ambient_occlusion++; + } + } + + if(light_count == 0) + return 255; + + light /= light_count; + + if(ambient_occlusion > 4) + { + ambient_occlusion -= 4; + light = (float)light / ((float)ambient_occlusion * 0.5 + 1.0); + } + + return light; +} + +// Calculate lighting at the given corner of p +u8 getSmoothLight(v3s16 p, v3s16 corner, + VoxelManipulator &vmanip, u32 daynight_ratio) +{ + if(corner.X == 1) p.X += 1; + else assert(corner.X == -1); + if(corner.Y == 1) p.Y += 1; + else assert(corner.Y == -1); + if(corner.Z == 1) p.Z += 1; + else assert(corner.Z == -1); + + return getSmoothLight(p, vmanip, daynight_ratio); +} + +void getTileInfo( + // Input: + v3s16 blockpos_nodes, + v3s16 p, + v3s16 face_dir, + u32 daynight_ratio, + VoxelManipulator &vmanip, + NodeModMap &temp_mods, + bool smooth_lighting, + // Output: + bool &makes_face, + v3s16 &p_corrected, + v3s16 &face_dir_corrected, + u8 *lights, + TileSpec &tile + ) +{ + MapNode n0 = vmanip.getNodeNoEx(blockpos_nodes + p); + MapNode n1 = vmanip.getNodeNoEx(blockpos_nodes + p + face_dir); + TileSpec tile0 = getNodeTile(n0, p, face_dir, temp_mods); + TileSpec tile1 = getNodeTile(n1, p + face_dir, -face_dir, temp_mods); + + // This is hackish + u8 content0 = getNodeContent(p, n0, temp_mods); + u8 content1 = getNodeContent(p + face_dir, n1, temp_mods); + u8 mf = face_contents(content0, content1); + + if(mf == 0) + { + makes_face = false; + return; + } + + makes_face = true; + + if(mf == 1) + { + tile = tile0; + p_corrected = p; + face_dir_corrected = face_dir; + } + else + { + tile = tile1; + p_corrected = p + face_dir; + face_dir_corrected = -face_dir; + } + + if(smooth_lighting == false) + { + lights[0] = lights[1] = lights[2] = lights[3] = + decode_light(getFaceLight(daynight_ratio, n0, n1, face_dir)); + } + else + { + v3s16 vertex_dirs[4]; + getNodeVertexDirs(face_dir_corrected, vertex_dirs); + for(u16 i=0; i<4; i++) + { + lights[i] = getSmoothLight(blockpos_nodes + p_corrected, + vertex_dirs[i], vmanip, daynight_ratio); + } + } + + return; +} + /* startpos: translate_dir: unit vector with only one of x, y or z @@ -341,28 +517,34 @@ void updateFastFaceRow( core::array &dest, NodeModMap &temp_mods, VoxelManipulator &vmanip, - v3s16 blockpos_nodes) + v3s16 blockpos_nodes, + bool smooth_lighting) { v3s16 p = startpos; u16 continuous_tiles_count = 0; - MapNode n0 = vmanip.getNodeNoEx(blockpos_nodes + p); - MapNode n1 = vmanip.getNodeNoEx(blockpos_nodes + p + face_dir); - TileSpec tile0 = getNodeTile(n0, p, face_dir, temp_mods); - TileSpec tile1 = getNodeTile(n1, p + face_dir, -face_dir, temp_mods); - u8 light = getFaceLight(daynight_ratio, n0, n1, face_dir); + bool makes_face; + v3s16 p_corrected; + v3s16 face_dir_corrected; + u8 lights[4]; + TileSpec tile; + getTileInfo(blockpos_nodes, p, face_dir, daynight_ratio, + vmanip, temp_mods, smooth_lighting, + makes_face, p_corrected, face_dir_corrected, lights, tile); for(u16 j=0; jm_temp_mods, data->m_vmanip, - blockpos_nodes); + blockpos_nodes, + smooth_lighting); } } /* - Go through every x,y and get right faces in rows of z+ + Go through every x,y and get right(x+) faces in rows of z+ */ for(s16 x=0; xm_temp_mods, data->m_vmanip, - blockpos_nodes); + blockpos_nodes, + smooth_lighting); } } /* - Go through every y,z and get back faces in rows of x+ + Go through every y,z and get back(z+) faces in rows of x+ */ for(s16 z=0; zm_temp_mods, data->m_vmanip, - blockpos_nodes); + blockpos_nodes, + smooth_lighting); } } } @@ -675,6 +846,7 @@ scene::SMesh* makeMapBlockMesh(MeshMakeData *data) FastFace &f = fastfaces_new[i]; const u16 indices[] = {0,1,2,2,3,0}; + const u16 indices_alternate[] = {0,1,3,2,3,1}; video::ITexture *texture = f.tile.texture.atlas; if(texture == NULL) @@ -683,8 +855,18 @@ scene::SMesh* makeMapBlockMesh(MeshMakeData *data) material.setTexture(0, texture); f.tile.applyMaterialOptions(material); + + const u16 *indices_p = indices; - collector.append(material, f.vertices, 4, indices, 6); + /* + Revert triangles for nicer looking gradient if vertices + 1 and 3 have same color or 0 and 2 have different color. + */ + if(f.vertices[0].Color != f.vertices[2].Color + || f.vertices[1].Color == f.vertices[3].Color) + indices_p = indices_alternate; + + collector.append(material, f.vertices, 4, indices_p, 6); } } @@ -719,6 +901,17 @@ scene::SMesh* makeMapBlockMesh(MeshMakeData *data) g_texturesource->getTextureId("leaves.png")); material_leaves1.setTexture(0, pa_leaves1.atlas); + // Glass material + video::SMaterial material_glass; + material_glass.setFlag(video::EMF_LIGHTING, false); + material_glass.setFlag(video::EMF_BILINEAR_FILTER, false); + material_glass.setFlag(video::EMF_FOG_ENABLE, true); + material_glass.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; + AtlasPointer pa_glass = g_texturesource->getTexture( + g_texturesource->getTextureId("glass.png")); + material_glass.setTexture(0, pa_glass.atlas); + + for(s16 z=0; zm_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y+1,z)); - if(n.d == CONTENT_WATER || n.d == CONTENT_WATERSOURCE) + MapNode ntop = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y+1,z)); + if(ntop.d == CONTENT_WATER || ntop.d == CONTENT_WATERSOURCE) top_is_water = true; - u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio)); + u8 l = 0; + // Use the light of the node on top if possible + if(content_features(ntop.d).param_type == CPT_LIGHT) + l = decode_light(ntop.getLightBlend(data->m_daynight_ratio)); + // Otherwise use the light of this node (the water) + else + l = decode_light(n.getLightBlend(data->m_daynight_ratio)); video::SColor c(WATER_ALPHA,l,l,l); // Neighbor water levels (key = relative position) @@ -1218,6 +1417,72 @@ scene::SMesh* makeMapBlockMesh(MeshMakeData *data) collector.append(material_leaves1, vertices, 4, indices, 6); } } + /* + Add glass + */ + else if(n.d == CONTENT_GLASS) + { + u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio))); + video::SColor c(255,l,l,l); + + for(u32 j=0; j<6; j++) + { + video::S3DVertex vertices[4] = + { + video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c, + pa_glass.x0(), pa_glass.y1()), + video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c, + pa_glass.x1(), pa_glass.y1()), + video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c, + pa_glass.x1(), pa_glass.y0()), + video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c, + pa_glass.x0(), pa_glass.y0()), + }; + + if(j == 0) + { + for(u16 i=0; i<4; i++) + vertices[i].Pos.rotateXZBy(0); + } + else if(j == 1) + { + for(u16 i=0; i<4; i++) + vertices[i].Pos.rotateXZBy(180); + } + else if(j == 2) + { + for(u16 i=0; i<4; i++) + vertices[i].Pos.rotateXZBy(-90); + } + else if(j == 3) + { + for(u16 i=0; i<4; i++) + vertices[i].Pos.rotateXZBy(90); + } + else if(j == 4) + { + for(u16 i=0; i<4; i++) + vertices[i].Pos.rotateYZBy(-90); + } + else if(j == 5) + { + for(u16 i=0; i<4; i++) + vertices[i].Pos.rotateYZBy(90); + } + + for(u16 i=0; i<4; i++) + { + vertices[i].Pos += intToFloat(p + blockpos_nodes, BS); + } + + u16 indices[] = {0,1,2,2,3,0}; + // Add to mesh collector + collector.append(material_glass, vertices, 4, indices, 6); + } + } + + + } /* @@ -1921,9 +2186,17 @@ void MapBlock::serialize(std::ostream &os, u8 version) { if(version <= 15) { - std::ostringstream oss(std::ios_base::binary); - m_node_metadata.serialize(oss); - os<