X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fcontent_mapblock.cpp;h=d41aac81bf1250943ac4d91bdcccb641c0d3412e;hb=99d257ae8b8883f958381dc13d3017cdb2570eb0;hp=3044c8b359102c8c55293d48ecd62fb1b1509b4f;hpb=4ef9c7675ada82961d83601712a47ebad78b67b5;p=minetest.git diff --git a/src/content_mapblock.cpp b/src/content_mapblock.cpp index 3044c8b35..d41aac81b 100644 --- a/src/content_mapblock.cpp +++ b/src/content_mapblock.cpp @@ -18,198 +18,120 @@ with this program; if not, write to the Free Software Foundation, Inc., */ #include "content_mapblock.h" -#include "content_mapnode.h" -#include "main.h" // For g_settings and g_texturesource -#include "mineral.h" -#include "mapblock_mesh.h" // For MapBlock_LightColor() -#ifndef SERVER +#include "main.h" // For g_settings +#include "mapblock_mesh.h" // For MapBlock_LightColor() and MeshCollector +#include "settings.h" +#include "nodedef.h" +#include "tile.h" +#include "gamedef.h" + // Create a cuboid. -// material - the material to use (for all 6 faces) // collector - the MeshCollector for the resulting polygons -// pa - texture atlas pointer for the material +// box - the position and size of the box +// tiles - the tiles (materials) to use (for all 6 faces) +// tilecount - number of entries in tiles, 1<=tilecount<=6 // c - vertex colour - used for all -// pos - the position of the centre of the cuboid -// rz,ry,rz - the radius of the cuboid in each dimension // txc - texture coordinates - this is a list of texture coordinates // for the opposite corners of each face - therefore, there // should be (2+2)*6=24 values in the list. Alternatively, pass // NULL to use the entire texture for each face. The order of -// the faces in the list is top-backi-right-front-left-bottom -// If you specified 0,0,1,1 for each face, that would be the -// same as passing NULL. -void makeCuboid(video::SMaterial &material, MeshCollector *collector, - AtlasPointer* pa, video::SColor &c, - v3f &pos, f32 rx, f32 ry, f32 rz, f32* txc) +// the faces in the list is up-down-right-left-back-front +// (compatible with ContentFeatures). If you specified 0,0,1,1 +// for each face, that would be the same as passing NULL. +void makeCuboid(MeshCollector *collector, const aabb3f &box, + const TileSpec *tiles, int tilecount, + video::SColor &c, const f32* txc) { - f32 tu0=pa->x0(); - f32 tu1=pa->x1(); - f32 tv0=pa->y0(); - f32 tv1=pa->y1(); - f32 txus=tu1-tu0; - f32 txvs=tv1-tv0; - - video::S3DVertex v[4] = + assert(tilecount >= 1 && tilecount <= 6); + + v3f min = box.MinEdge; + v3f max = box.MaxEdge; + + if(txc == NULL) { - video::S3DVertex(0,0,0, 0,0,0, c, tu0, tv1), - video::S3DVertex(0,0,0, 0,0,0, c, tu1, tv1), - video::S3DVertex(0,0,0, 0,0,0, c, tu1, tv0), - video::S3DVertex(0,0,0, 0,0,0, c, tu0, tv0) - }; + static const f32 txc_default[24] = { + 0,0,1,1, + 0,0,1,1, + 0,0,1,1, + 0,0,1,1, + 0,0,1,1, + 0,0,1,1 + }; + txc = txc_default; + } - for(int i=0;i<6;i++) + video::S3DVertex vertices[24] = { - switch(i) - { - case 0: // top - v[0].Pos.X=-rx; v[0].Pos.Y= ry; v[0].Pos.Z=-rz; - v[1].Pos.X=-rx; v[1].Pos.Y= ry; v[1].Pos.Z= rz; - v[2].Pos.X= rx; v[2].Pos.Y= ry; v[2].Pos.Z= rz; - v[3].Pos.X= rx; v[3].Pos.Y= ry, v[3].Pos.Z=-rz; - break; - case 1: // back - v[0].Pos.X=-rx; v[0].Pos.Y= ry; v[0].Pos.Z=-rz; - v[1].Pos.X= rx; v[1].Pos.Y= ry; v[1].Pos.Z=-rz; - v[2].Pos.X= rx; v[2].Pos.Y=-ry; v[2].Pos.Z=-rz; - v[3].Pos.X=-rx; v[3].Pos.Y=-ry, v[3].Pos.Z=-rz; - break; - case 2: //right - v[0].Pos.X= rx; v[0].Pos.Y= ry; v[0].Pos.Z=-rz; - v[1].Pos.X= rx; v[1].Pos.Y= ry; v[1].Pos.Z= rz; - v[2].Pos.X= rx; v[2].Pos.Y=-ry; v[2].Pos.Z= rz; - v[3].Pos.X= rx; v[3].Pos.Y=-ry, v[3].Pos.Z=-rz; - break; - case 3: // front - v[0].Pos.X= rx; v[0].Pos.Y= ry; v[0].Pos.Z= rz; - v[1].Pos.X=-rx; v[1].Pos.Y= ry; v[1].Pos.Z= rz; - v[2].Pos.X=-rx; v[2].Pos.Y=-ry; v[2].Pos.Z= rz; - v[3].Pos.X= rx; v[3].Pos.Y=-ry, v[3].Pos.Z= rz; - break; - case 4: // left - v[0].Pos.X=-rx; v[0].Pos.Y= ry; v[0].Pos.Z= rz; - v[1].Pos.X=-rx; v[1].Pos.Y= ry; v[1].Pos.Z=-rz; - v[2].Pos.X=-rx; v[2].Pos.Y=-ry; v[2].Pos.Z=-rz; - v[3].Pos.X=-rx; v[3].Pos.Y=-ry, v[3].Pos.Z= rz; - break; - case 5: // bottom - v[0].Pos.X= rx; v[0].Pos.Y=-ry; v[0].Pos.Z= rz; - v[1].Pos.X=-rx; v[1].Pos.Y=-ry; v[1].Pos.Z= rz; - v[2].Pos.X=-rx; v[2].Pos.Y=-ry; v[2].Pos.Z=-rz; - v[3].Pos.X= rx; v[3].Pos.Y=-ry, v[3].Pos.Z=-rz; - break; - } + // up + video::S3DVertex(min.X,max.Y,max.Z, 0,1,0, c, txc[0],txc[1]), + video::S3DVertex(max.X,max.Y,max.Z, 0,1,0, c, txc[2],txc[1]), + video::S3DVertex(max.X,max.Y,min.Z, 0,1,0, c, txc[2],txc[3]), + video::S3DVertex(min.X,max.Y,min.Z, 0,1,0, c, txc[0],txc[3]), + // down + video::S3DVertex(min.X,min.Y,min.Z, 0,-1,0, c, txc[4],txc[5]), + video::S3DVertex(max.X,min.Y,min.Z, 0,-1,0, c, txc[6],txc[5]), + video::S3DVertex(max.X,min.Y,max.Z, 0,-1,0, c, txc[6],txc[7]), + video::S3DVertex(min.X,min.Y,max.Z, 0,-1,0, c, txc[4],txc[7]), + // right + video::S3DVertex(max.X,max.Y,min.Z, 1,0,0, c, txc[ 8],txc[9]), + video::S3DVertex(max.X,max.Y,max.Z, 1,0,0, c, txc[10],txc[9]), + video::S3DVertex(max.X,min.Y,max.Z, 1,0,0, c, txc[10],txc[11]), + video::S3DVertex(max.X,min.Y,min.Z, 1,0,0, c, txc[ 8],txc[11]), + // left + video::S3DVertex(min.X,max.Y,max.Z, -1,0,0, c, txc[12],txc[13]), + video::S3DVertex(min.X,max.Y,min.Z, -1,0,0, c, txc[14],txc[13]), + video::S3DVertex(min.X,min.Y,min.Z, -1,0,0, c, txc[14],txc[15]), + video::S3DVertex(min.X,min.Y,max.Z, -1,0,0, c, txc[12],txc[15]), + // back + video::S3DVertex(max.X,max.Y,max.Z, 0,0,1, c, txc[16],txc[17]), + video::S3DVertex(min.X,max.Y,max.Z, 0,0,1, c, txc[18],txc[17]), + video::S3DVertex(min.X,min.Y,max.Z, 0,0,1, c, txc[18],txc[19]), + video::S3DVertex(max.X,min.Y,max.Z, 0,0,1, c, txc[16],txc[19]), + // front + video::S3DVertex(min.X,max.Y,min.Z, 0,0,-1, c, txc[20],txc[21]), + video::S3DVertex(max.X,max.Y,min.Z, 0,0,-1, c, txc[22],txc[21]), + video::S3DVertex(max.X,min.Y,min.Z, 0,0,-1, c, txc[22],txc[23]), + video::S3DVertex(min.X,min.Y,min.Z, 0,0,-1, c, txc[20],txc[23]), + }; - if(txc!=NULL) - { - v[0].TCoords.X=tu0+txus*txc[0]; v[0].TCoords.Y=tv0+txvs*txc[3]; - v[1].TCoords.X=tu0+txus*txc[2]; v[1].TCoords.Y=tv0+txvs*txc[3]; - v[2].TCoords.X=tu0+txus*txc[2]; v[2].TCoords.Y=tv0+txvs*txc[1]; - v[3].TCoords.X=tu0+txus*txc[0]; v[3].TCoords.Y=tv0+txvs*txc[1]; - txc+=4; - } + for(s32 j=0; j<24; j++) + { + int tileindex = MYMIN(j/4, tilecount-1); + vertices[j].TCoords *= tiles[tileindex].texture.size; + vertices[j].TCoords += tiles[tileindex].texture.pos; + } - for(u16 i=0; i<4; i++) - v[i].Pos += pos; - u16 indices[] = {0,1,2,2,3,0}; - collector->append(material, v, 4, indices, 6); + u16 indices[] = {0,1,2,2,3,0}; + // Add to mesh collector + for(s32 j=0; j<24; j+=4) + { + int tileindex = MYMIN(j/4, tilecount-1); + collector->append(tiles[tileindex], + vertices+j, 4, indices, 6); } - } -#endif -#ifndef SERVER void mapblock_mesh_generate_special(MeshMakeData *data, MeshCollector &collector) { + INodeDefManager *nodedef = data->m_gamedef->ndef(); + // 0ms //TimeTaker timer("mapblock_mesh_generate_special()"); /* Some settings */ - bool new_style_water = g_settings.getBool("new_style_water"); - bool new_style_leaves = g_settings.getBool("new_style_leaves"); - //bool smooth_lighting = g_settings.getBool("smooth_lighting"); - bool invisible_stone = g_settings.getBool("invisible_stone"); + bool new_style_water = g_settings->getBool("new_style_water"); - float node_water_level = 1.0; + float node_liquid_level = 1.0; if(new_style_water) - node_water_level = 0.85; + node_liquid_level = 0.85; v3s16 blockpos_nodes = data->m_blockpos*MAP_BLOCKSIZE; - // Flowing water material - video::SMaterial material_water1; - material_water1.setFlag(video::EMF_LIGHTING, false); - material_water1.setFlag(video::EMF_BACK_FACE_CULLING, false); - material_water1.setFlag(video::EMF_BILINEAR_FILTER, false); - material_water1.setFlag(video::EMF_FOG_ENABLE, true); - material_water1.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA; - AtlasPointer pa_water1 = g_texturesource->getTexture( - g_texturesource->getTextureId("water.png")); - material_water1.setTexture(0, pa_water1.atlas); - - // New-style leaves material - video::SMaterial material_leaves1; - material_leaves1.setFlag(video::EMF_LIGHTING, false); - //material_leaves1.setFlag(video::EMF_BACK_FACE_CULLING, false); - material_leaves1.setFlag(video::EMF_BILINEAR_FILTER, false); - material_leaves1.setFlag(video::EMF_FOG_ENABLE, true); - material_leaves1.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; - AtlasPointer pa_leaves1 = g_texturesource->getTexture( - 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); - - // Wood material - video::SMaterial material_wood; - material_wood.setFlag(video::EMF_LIGHTING, false); - material_wood.setFlag(video::EMF_BILINEAR_FILTER, false); - material_wood.setFlag(video::EMF_FOG_ENABLE, true); - material_wood.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; - AtlasPointer pa_wood = g_texturesource->getTexture( - g_texturesource->getTextureId("wood.png")); - material_wood.setTexture(0, pa_wood.atlas); - - // General ground material for special output - // Texture is modified just before usage - video::SMaterial material_general; - material_general.setFlag(video::EMF_LIGHTING, false); - material_general.setFlag(video::EMF_BILINEAR_FILTER, false); - material_general.setFlag(video::EMF_FOG_ENABLE, true); - material_general.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; - - - // Papyrus material - video::SMaterial material_papyrus; - material_papyrus.setFlag(video::EMF_LIGHTING, false); - material_papyrus.setFlag(video::EMF_BILINEAR_FILTER, false); - material_papyrus.setFlag(video::EMF_FOG_ENABLE, true); - material_papyrus.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; - AtlasPointer pa_papyrus = g_texturesource->getTexture( - g_texturesource->getTextureId("papyrus.png")); - material_papyrus.setTexture(0, pa_papyrus.atlas); - - // junglegrass material - video::SMaterial material_junglegrass; - material_junglegrass.setFlag(video::EMF_LIGHTING, false); - material_junglegrass.setFlag(video::EMF_BILINEAR_FILTER, false); - material_junglegrass.setFlag(video::EMF_FOG_ENABLE, true); - material_junglegrass.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; - AtlasPointer pa_junglegrass = g_texturesource->getTexture( - g_texturesource->getTextureId("junglegrass.png")); - material_junglegrass.setTexture(0, pa_junglegrass.atlas); - for(s16 z=0; zm_vmanip.getNodeNoEx(blockpos_nodes+p); + const ContentFeatures &f = nodedef->get(n); + + // Only solidness=0 stuff is drawn here + if(f.solidness != 0) + continue; - /* - Add torches to mesh - */ - if(n.getContent() == CONTENT_TORCH) + switch(f.drawtype){ + default: + infostream<<"Got "<getTextureRaw("torch_on_floor.png")); - else if(dir == v3s16(0,1,0)) - material.setTexture(0, - g_texturesource->getTextureRaw("torch_on_ceiling.png")); - // For backwards compatibility - else if(dir == v3s16(0,0,0)) - material.setTexture(0, - g_texturesource->getTextureRaw("torch_on_floor.png")); - else - material.setTexture(0, - g_texturesource->getTextureRaw("torch.png")); + bool top_is_air = false; + MapNode n = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y+1,z)); + if(n.getContent() == CONTENT_AIR) + top_is_air = true; + + if(top_is_air == false) + continue; - u16 indices[] = {0,1,2,2,3,0}; - // Add to mesh collector - collector.append(material, vertices, 4, indices, 6); - } - /* - Signs on walls - */ - else if(n.getContent() == CONTENT_SIGN_WALL) - { - u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio)); - video::SColor c = MapBlock_LightColor(255, l); - - float d = (float)BS/16; - // Wall at X+ of node + u16 l = getInteriorLight(n, 0, data); + video::SColor c = MapBlock_LightColor(f.alpha, l); + video::S3DVertex vertices[4] = { - video::S3DVertex(BS/2-d,-BS/2,-BS/2, 0,0,0, c, 0,1), - video::S3DVertex(BS/2-d,-BS/2,BS/2, 0,0,0, c, 1,1), - video::S3DVertex(BS/2-d,BS/2,BS/2, 0,0,0, c, 1,0), - video::S3DVertex(BS/2-d,BS/2,-BS/2, 0,0,0, c, 0,0), + video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, + pa_liquid.x0(), pa_liquid.y1()), + video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, + pa_liquid.x1(), pa_liquid.y1()), + video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c, + pa_liquid.x1(), pa_liquid.y0()), + video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c, + pa_liquid.x0(), pa_liquid.y0()), }; - v3s16 dir = unpackDir(n.param2); - + v3f offset(p.X, p.Y + (-0.5+node_liquid_level)*BS, p.Z); for(s32 i=0; i<4; i++) { - if(dir == v3s16(1,0,0)) - vertices[i].Pos.rotateXZBy(0); - if(dir == v3s16(-1,0,0)) - vertices[i].Pos.rotateXZBy(180); - if(dir == v3s16(0,0,1)) - vertices[i].Pos.rotateXZBy(90); - if(dir == v3s16(0,0,-1)) - vertices[i].Pos.rotateXZBy(-90); - if(dir == v3s16(0,-1,0)) - vertices[i].Pos.rotateXYBy(-90); - if(dir == v3s16(0,1,0)) - vertices[i].Pos.rotateXYBy(90); - - vertices[i].Pos += intToFloat(p + blockpos_nodes, BS); + vertices[i].Pos += offset; } - // Set material - video::SMaterial material; - material.setFlag(video::EMF_LIGHTING, false); - material.setFlag(video::EMF_BACK_FACE_CULLING, false); - material.setFlag(video::EMF_BILINEAR_FILTER, false); - material.setFlag(video::EMF_FOG_ENABLE, true); - //material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; - material.MaterialType - = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; - - material.setTexture(0, - g_texturesource->getTextureRaw("sign_wall.png")); - u16 indices[] = {0,1,2,2,3,0}; // Add to mesh collector - collector.append(material, vertices, 4, indices, 6); - } - /* - Add flowing water to mesh - */ - else if(n.getContent() == CONTENT_WATER) + collector.append(tile_liquid, vertices, 4, indices, 6); + break;} + case NDT_FLOWINGLIQUID: { - bool top_is_water = false; + /* + Add flowing liquid to mesh + */ + TileSpec tile_liquid = f.special_tiles[0]; + TileSpec tile_liquid_bfculled = f.special_tiles[1]; + AtlasPointer &pa_liquid = tile_liquid.texture; + + bool top_is_same_liquid = false; MapNode ntop = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y+1,z)); - if(ntop.getContent() == CONTENT_WATER || ntop.getContent() == CONTENT_WATERSOURCE) - top_is_water = true; + content_t c_flowing = nodedef->getId(f.liquid_alternative_flowing); + content_t c_source = nodedef->getId(f.liquid_alternative_source); + if(ntop.getContent() == c_flowing || ntop.getContent() == c_source) + top_is_same_liquid = true; - u8 l = 0; + u16 l = 0; // Use the light of the node on top if possible - if(content_features(ntop).param_type == CPT_LIGHT) - l = decode_light(ntop.getLightBlend(data->m_daynight_ratio)); - // Otherwise use the light of this node (the water) + if(nodedef->get(ntop).param_type == CPT_LIGHT) + l = getInteriorLight(ntop, 0, data); + // Otherwise use the light of this node (the liquid) else - l = decode_light(n.getLightBlend(data->m_daynight_ratio)); - video::SColor c = MapBlock_LightColor(WATER_ALPHA, l); + l = getInteriorLight(n, 0, data); + video::SColor c = MapBlock_LightColor(f.alpha, l); - // Neighbor water levels (key = relative position) + // Neighbor liquid levels (key = relative position) // Includes current node core::map neighbor_levels; core::map neighbor_contents; core::map neighbor_flags; - const u8 neighborflag_top_is_water = 0x01; + const u8 neighborflag_top_is_same_liquid = 0x01; v3s16 neighbor_dirs[9] = { v3s16(0,0,0), v3s16(0,0,1), @@ -374,7 +237,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data, }; for(u32 i=0; i<9; i++) { - u8 content = CONTENT_AIR; + content_t content = CONTENT_AIR; float level = -0.5 * BS; u8 flags = 0; // Check neighbor @@ -384,19 +247,20 @@ void mapblock_mesh_generate_special(MeshMakeData *data, { content = n2.getContent(); - if(n2.getContent() == CONTENT_WATERSOURCE) - level = (-0.5+node_water_level) * BS; - else if(n2.getContent() == CONTENT_WATER) - level = (-0.5 + ((float)n2.param2 + 0.5) / 8.0 - * node_water_level) * BS; + if(n2.getContent() == c_source) + level = (-0.5+node_liquid_level) * BS; + else if(n2.getContent() == c_flowing) + level = (-0.5 + ((float)(n2.param2&LIQUID_LEVEL_MASK) + + 0.5) / 8.0 * node_liquid_level) * BS; // Check node above neighbor. // NOTE: This doesn't get executed if neighbor // doesn't exist p2.Y += 1; n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2); - if(n2.getContent() == CONTENT_WATERSOURCE || n2.getContent() == CONTENT_WATER) - flags |= neighborflag_top_is_water; + if(n2.getContent() == c_source || + n2.getContent() == c_flowing) + flags |= neighborflag_top_is_same_liquid; } neighbor_levels.insert(neighbor_dirs[i], level); @@ -404,10 +268,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data, neighbor_flags.insert(neighbor_dirs[i], flags); } - //float water_level = (-0.5 + ((float)n.param2 + 0.5) / 8.0) * BS; - //float water_level = neighbor_levels[v3s16(0,0,0)]; - - // Corner heights (average between four waters) + // Corner heights (average between four liquids) f32 corner_levels[4]; v3s16 halfdirs[4] = { @@ -421,29 +282,40 @@ void mapblock_mesh_generate_special(MeshMakeData *data, v3s16 cornerdir = halfdirs[i]; float cornerlevel = 0; u32 valid_count = 0; + u32 air_count = 0; for(u32 j=0; j<4; j++) { v3s16 neighbordir = cornerdir - halfdirs[j]; - u8 content = neighbor_contents[neighbordir]; - // Special case for source nodes - if(content == CONTENT_WATERSOURCE) + content_t content = neighbor_contents[neighbordir]; + // If top is liquid, draw starting from top of node + if(neighbor_flags[neighbordir] & + neighborflag_top_is_same_liquid) { - cornerlevel = (-0.5+node_water_level)*BS; + cornerlevel = 0.5*BS; valid_count = 1; break; } - else if(content == CONTENT_WATER) + // Source is always the same height + else if(content == c_source) + { + cornerlevel = (-0.5+node_liquid_level)*BS; + valid_count = 1; + break; + } + // Flowing liquid has level information + else if(content == c_flowing) { cornerlevel += neighbor_levels[neighbordir]; valid_count++; } else if(content == CONTENT_AIR) { - cornerlevel += -0.5*BS; - valid_count++; + air_count++; } } - if(valid_count > 0) + if(air_count >= 2) + cornerlevel = -0.5*BS; + else if(valid_count > 0) cornerlevel /= valid_count; corner_levels[i] = cornerlevel; } @@ -469,47 +341,52 @@ void mapblock_mesh_generate_special(MeshMakeData *data, v3s16 dir = side_dirs[i]; /* - If our topside is water and neighbor's topside - is water, don't draw side face + If our topside is liquid and neighbor's topside + is liquid, don't draw side face */ - if(top_is_water && - neighbor_flags[dir] & neighborflag_top_is_water) + if(top_is_same_liquid && + neighbor_flags[dir] & neighborflag_top_is_same_liquid) continue; - u8 neighbor_content = neighbor_contents[dir]; + content_t neighbor_content = neighbor_contents[dir]; + const ContentFeatures &n_feat = nodedef->get(neighbor_content); - // Don't draw face if neighbor is not air or water - if(neighbor_content != CONTENT_AIR - && neighbor_content != CONTENT_WATER) + // Don't draw face if neighbor is blocking the view + if(n_feat.solidness == 2) continue; - bool neighbor_is_water = (neighbor_content == CONTENT_WATER); + bool neighbor_is_same_liquid = (neighbor_content == c_source + || neighbor_content == c_flowing); - // Don't draw any faces if neighbor is water and top is water - if(neighbor_is_water == true && top_is_water == false) + // Don't draw any faces if neighbor same is liquid and top is + // same liquid + 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 + const TileSpec *current_tile = &tile_liquid; + if(n_feat.solidness != 0 || n_feat.visual_solidness != 0) + current_tile = &tile_liquid_bfculled; video::S3DVertex vertices[4] = { - /*video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,1), - video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,1), - video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,0), - video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,0),*/ video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, - pa_water1.x0(), pa_water1.y1()), + pa_liquid.x0(), pa_liquid.y1()), video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, - pa_water1.x1(), pa_water1.y1()), + pa_liquid.x1(), pa_liquid.y1()), video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, - pa_water1.x1(), pa_water1.y0()), + pa_liquid.x1(), pa_liquid.y0()), video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, - pa_water1.x0(), pa_water1.y0()), + pa_liquid.x0(), pa_liquid.y0()), }; /* - If our topside is water, set upper border of face + If our topside is liquid, set upper border of face at upper border of node */ - if(top_is_water) + if(top_is_same_liquid) { vertices[2].Pos.Y = 0.5*BS; vertices[3].Pos.Y = 0.5*BS; @@ -524,16 +401,16 @@ void mapblock_mesh_generate_special(MeshMakeData *data, } /* - If neighbor is water, lower border of face is corner - water levels + If neighbor is liquid, lower border of face is corner + liquid levels */ - if(neighbor_is_water) + if(neighbor_is_same_liquid) { vertices[0].Pos.Y = corner_levels[side_corners[i][1]]; vertices[1].Pos.Y = corner_levels[side_corners[i][0]]; } /* - If neighbor is not water, lower border of face is + If neighbor is not liquid, lower border of face is lower border of node */ else @@ -552,35 +429,38 @@ void mapblock_mesh_generate_special(MeshMakeData *data, vertices[j].Pos.rotateXZBy(90); if(dir == v3s16(1,0,-0)) vertices[j].Pos.rotateXZBy(-90); + + // Do this to not cause glitches when two liquids are + // side-by-side + /*if(neighbor_is_same_liquid == false){ + vertices[j].Pos.X *= 0.98; + vertices[j].Pos.Z *= 0.98; + }*/ - vertices[j].Pos += intToFloat(p + blockpos_nodes, BS); + vertices[j].Pos += intToFloat(p, BS); } u16 indices[] = {0,1,2,2,3,0}; // Add to mesh collector - collector.append(material_water1, vertices, 4, indices, 6); + collector.append(*current_tile, vertices, 4, indices, 6); } /* Generate top side, if appropriate */ - if(top_is_water == false) + if(top_is_same_liquid == false) { video::S3DVertex vertices[4] = { - /*video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c, 0,1), - video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c, 1,1), - video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,0), - video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,0),*/ video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, - pa_water1.x0(), pa_water1.y1()), + pa_liquid.x0(), pa_liquid.y1()), video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, - pa_water1.x1(), pa_water1.y1()), + pa_liquid.x1(), pa_liquid.y1()), video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c, - pa_water1.x1(), pa_water1.y0()), + pa_liquid.x1(), pa_liquid.y0()), video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c, - pa_water1.x0(), pa_water1.y0()), + pa_liquid.x0(), pa_liquid.y0()), }; // This fixes a strange bug @@ -588,230 +468,299 @@ void mapblock_mesh_generate_special(MeshMakeData *data, for(s32 i=0; i<4; i++) { - //vertices[i].Pos.Y += water_level; + //vertices[i].Pos.Y += liquid_level; //vertices[i].Pos.Y += neighbor_levels[v3s16(0,0,0)]; s32 j = corner_resolve[i]; vertices[i].Pos.Y += corner_levels[j]; - vertices[i].Pos += intToFloat(p + blockpos_nodes, BS); + vertices[i].Pos += intToFloat(p, BS); } u16 indices[] = {0,1,2,2,3,0}; // Add to mesh collector - collector.append(material_water1, vertices, 4, indices, 6); + collector.append(tile_liquid, vertices, 4, indices, 6); } - } - /* - Add water sources to mesh if using new style - */ - else if(n.getContent() == CONTENT_WATERSOURCE && new_style_water) + break;} + case NDT_GLASSLIKE: { - //bool top_is_water = false; - bool top_is_air = false; - MapNode n = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y+1,z)); - /*if(n.getContent() == CONTENT_WATER || n.getContent() == CONTENT_WATERSOURCE) - top_is_water = true;*/ - if(n.getContent() == CONTENT_AIR) - top_is_air = true; - - /*if(top_is_water == true) - continue;*/ - if(top_is_air == false) - continue; - - u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio)); - video::SColor c = MapBlock_LightColor(WATER_ALPHA, l); - - video::S3DVertex vertices[4] = - { - /*video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c, 0,1), - video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c, 1,1), - video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,0), - video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,0),*/ - video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, - pa_water1.x0(), pa_water1.y1()), - video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, - pa_water1.x1(), pa_water1.y1()), - video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c, - pa_water1.x1(), pa_water1.y0()), - video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c, - pa_water1.x0(), pa_water1.y0()), - }; - - for(s32 i=0; i<4; i++) - { - vertices[i].Pos.Y += (-0.5+node_water_level)*BS; - vertices[i].Pos += intToFloat(p + blockpos_nodes, BS); - } + TileSpec tile = getNodeTile(n, p, v3s16(0,0,0), data); + AtlasPointer ap = tile.texture; - u16 indices[] = {0,1,2,2,3,0}; - // Add to mesh collector - collector.append(material_water1, vertices, 4, indices, 6); - } - /* - Add leaves if using new style - */ - else if(n.getContent() == CONTENT_LEAVES && new_style_leaves) - { - /*u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio));*/ - u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio))); + u16 l = getInteriorLight(n, 1, data); video::SColor c = MapBlock_LightColor(255, l); for(u32 j=0; j<6; j++) { + // Check this neighbor + v3s16 n2p = blockpos_nodes + p + g_6dirs[j]; + MapNode n2 = data->m_vmanip.getNodeNoEx(n2p); + // Don't make face if neighbor is of same type + if(n2.getContent() == n.getContent()) + continue; + + // The face at Z+ video::S3DVertex vertices[4] = { - /*video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c, 0,1), - video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c, 1,1), - video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c, 1,0), - video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c, 0,0),*/ video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c, - pa_leaves1.x0(), pa_leaves1.y1()), + ap.x0(), ap.y1()), video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c, - pa_leaves1.x1(), pa_leaves1.y1()), + ap.x1(), ap.y1()), video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c, - pa_leaves1.x1(), pa_leaves1.y0()), + ap.x1(), ap.y0()), video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c, - pa_leaves1.x0(), pa_leaves1.y0()), + ap.x0(), ap.y0()), }; - - if(j == 0) - { + + // Rotations in the g_6dirs format + if(j == 0) // Z+ for(u16 i=0; i<4; i++) vertices[i].Pos.rotateXZBy(0); - } - else if(j == 1) - { + else if(j == 1) // Y+ for(u16 i=0; i<4; i++) - vertices[i].Pos.rotateXZBy(180); - } - else if(j == 2) - { + vertices[i].Pos.rotateYZBy(-90); + else if(j == 2) // X+ for(u16 i=0; i<4; i++) vertices[i].Pos.rotateXZBy(-90); - } - else if(j == 3) - { + else if(j == 3) // Z- 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) - { + vertices[i].Pos.rotateXZBy(180); + else if(j == 4) // Y- for(u16 i=0; i<4; i++) vertices[i].Pos.rotateYZBy(90); - } + else if(j == 5) // X- + for(u16 i=0; i<4; i++) + vertices[i].Pos.rotateXZBy(90); - for(u16 i=0; i<4; i++) - { - vertices[i].Pos += intToFloat(p + blockpos_nodes, BS); + for(u16 i=0; i<4; i++){ + vertices[i].Pos += intToFloat(p, BS); } u16 indices[] = {0,1,2,2,3,0}; // Add to mesh collector - collector.append(material_leaves1, vertices, 4, indices, 6); + collector.append(tile, vertices, 4, indices, 6); } - } - /* - Add glass - */ - else if(n.getContent() == CONTENT_GLASS) + break;} + case NDT_ALLFACES: { - u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio))); + TileSpec tile_leaves = getNodeTile(n, p, + v3s16(0,0,0), data); + AtlasPointer pa_leaves = tile_leaves.texture; + + u16 l = getInteriorLight(n, 1, data); video::SColor c = MapBlock_LightColor(255, l); - for(u32 j=0; j<6; j++) + v3f pos = intToFloat(p, BS); + aabb3f box(-BS/2,-BS/2,-BS/2,BS/2,BS/2,BS/2); + box.MinEdge += pos; + box.MaxEdge += pos; + makeCuboid(&collector, box, &tile_leaves, 1, c, NULL); + break;} + case NDT_ALLFACES_OPTIONAL: + // This is always pre-converted to something else + assert(0); + break; + case NDT_TORCHLIKE: + { + v3s16 dir = n.getWallMountedDir(nodedef); + + u8 tileindex = 0; + if(dir == v3s16(0,-1,0)){ + tileindex = 0; // floor + } else if(dir == v3s16(0,1,0)){ + tileindex = 1; // ceiling + // For backwards compatibility + } else if(dir == v3s16(0,0,0)){ + tileindex = 0; // floor + } else { + tileindex = 2; // side + } + + TileSpec tile = getNodeTileN(n, p, tileindex, data); + tile.material_flags &= ~MATERIAL_FLAG_BACKFACE_CULLING; + tile.material_flags |= MATERIAL_FLAG_CRACK_OVERLAY; + + AtlasPointer ap = tile.texture; + + video::SColor c(255,255,255,255); + + // Wall at X+ of node + video::S3DVertex vertices[4] = + { + video::S3DVertex(-BS/2,-BS/2,0, 0,0,0, c, + ap.x0(), ap.y1()), + video::S3DVertex(BS/2,-BS/2,0, 0,0,0, c, + ap.x1(), ap.y1()), + video::S3DVertex(BS/2,BS/2,0, 0,0,0, c, + ap.x1(), ap.y0()), + video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c, + ap.x0(), ap.y0()), + }; + + for(s32 i=0; i<4; i++) + { + if(dir == v3s16(1,0,0)) + vertices[i].Pos.rotateXZBy(0); + if(dir == v3s16(-1,0,0)) + vertices[i].Pos.rotateXZBy(180); + if(dir == v3s16(0,0,1)) + vertices[i].Pos.rotateXZBy(90); + if(dir == v3s16(0,0,-1)) + vertices[i].Pos.rotateXZBy(-90); + if(dir == v3s16(0,-1,0)) + vertices[i].Pos.rotateXZBy(45); + if(dir == v3s16(0,1,0)) + vertices[i].Pos.rotateXZBy(-45); + + vertices[i].Pos += intToFloat(p, BS); + } + + u16 indices[] = {0,1,2,2,3,0}; + // Add to mesh collector + collector.append(tile, vertices, 4, indices, 6); + break;} + case NDT_SIGNLIKE: + { + TileSpec tile = getNodeTileN(n, p, 0, data); + tile.material_flags &= ~MATERIAL_FLAG_BACKFACE_CULLING; + tile.material_flags |= MATERIAL_FLAG_CRACK_OVERLAY; + AtlasPointer ap = tile.texture; + + u16 l = getInteriorLight(n, 0, data); + video::SColor c = MapBlock_LightColor(255, l); + + float d = (float)BS/16; + // Wall at X+ of node + video::S3DVertex vertices[4] = + { + video::S3DVertex(BS/2-d,BS/2,BS/2, 0,0,0, c, + ap.x0(), ap.y0()), + video::S3DVertex(BS/2-d,BS/2,-BS/2, 0,0,0, c, + ap.x1(), ap.y0()), + video::S3DVertex(BS/2-d,-BS/2,-BS/2, 0,0,0, c, + ap.x1(), ap.y1()), + video::S3DVertex(BS/2-d,-BS/2,BS/2, 0,0,0, c, + ap.x0(), ap.y1()), + }; + + v3s16 dir = n.getWallMountedDir(nodedef); + + for(s32 i=0; i<4; i++) + { + if(dir == v3s16(1,0,0)) + vertices[i].Pos.rotateXZBy(0); + if(dir == v3s16(-1,0,0)) + vertices[i].Pos.rotateXZBy(180); + if(dir == v3s16(0,0,1)) + vertices[i].Pos.rotateXZBy(90); + if(dir == v3s16(0,0,-1)) + vertices[i].Pos.rotateXZBy(-90); + if(dir == v3s16(0,-1,0)) + vertices[i].Pos.rotateXYBy(-90); + if(dir == v3s16(0,1,0)) + vertices[i].Pos.rotateXYBy(90); + + vertices[i].Pos += intToFloat(p, BS); + } + + u16 indices[] = {0,1,2,2,3,0}; + // Add to mesh collector + collector.append(tile, vertices, 4, indices, 6); + break;} + case NDT_PLANTLIKE: + { + TileSpec tile = getNodeTileN(n, p, 0, data); + tile.material_flags |= MATERIAL_FLAG_CRACK_OVERLAY; + AtlasPointer ap = tile.texture; + + u16 l = getInteriorLight(n, 1, data); + video::SColor c = MapBlock_LightColor(255, l); + + for(u32 j=0; j<4; 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()), + video::S3DVertex(-BS/2*f.visual_scale,-BS/2,0, 0,0,0, c, + ap.x0(), ap.y1()), + video::S3DVertex( BS/2*f.visual_scale,-BS/2,0, 0,0,0, c, + ap.x1(), ap.y1()), + video::S3DVertex( BS/2*f.visual_scale, + -BS/2 + f.visual_scale*BS,0, 0,0,0, c, + ap.x1(), ap.y0()), + video::S3DVertex(-BS/2*f.visual_scale, + -BS/2 + f.visual_scale*BS,0, 0,0,0, c, + ap.x0(), ap.y0()), }; if(j == 0) { for(u16 i=0; i<4; i++) - vertices[i].Pos.rotateXZBy(0); + vertices[i].Pos.rotateXZBy(45); } else if(j == 1) { for(u16 i=0; i<4; i++) - vertices[i].Pos.rotateXZBy(180); + vertices[i].Pos.rotateXZBy(-45); } else if(j == 2) { for(u16 i=0; i<4; i++) - vertices[i].Pos.rotateXZBy(-90); + vertices[i].Pos.rotateXZBy(135); } 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); + vertices[i].Pos.rotateXZBy(-135); } for(u16 i=0; i<4; i++) { - vertices[i].Pos += intToFloat(p + blockpos_nodes, BS); + vertices[i].Pos *= f.visual_scale; + vertices[i].Pos += intToFloat(p, BS); } u16 indices[] = {0,1,2,2,3,0}; // Add to mesh collector - collector.append(material_glass, vertices, 4, indices, 6); + collector.append(tile, vertices, 4, indices, 6); } - } - /* - Add fence - */ - else if(n.getContent() == CONTENT_FENCE) + break;} + case NDT_FENCELIKE: { - u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio))); + TileSpec tile = getNodeTile(n, p, v3s16(0,0,0), data); + TileSpec tile_nocrack = tile; + tile_nocrack.material_flags &= ~MATERIAL_FLAG_CRACK; + + u16 l = getInteriorLight(n, 1, data); video::SColor c = MapBlock_LightColor(255, l); const f32 post_rad=(f32)BS/10; const f32 bar_rad=(f32)BS/20; const f32 bar_len=(f32)(BS/2)-post_rad; + v3f pos = intToFloat(p, BS); + // The post - always present - v3f pos = intToFloat(p+blockpos_nodes, BS); + aabb3f post(-post_rad,-BS/2,-post_rad,post_rad,BS/2,post_rad); + post.MinEdge += pos; + post.MaxEdge += pos; f32 postuv[24]={ + 0.4,0.4,0.6,0.6, 0.4,0.4,0.6,0.6, 0.35,0,0.65,1, 0.35,0,0.65,1, 0.35,0,0.65,1, - 0.35,0,0.65,1, - 0.4,0.4,0.6,0.6}; - makeCuboid(material_wood, &collector, - &pa_wood, c, pos, - post_rad,BS/2,post_rad, postuv); + 0.35,0,0.65,1}; + makeCuboid(&collector, post, &tile, 1, c, postuv); // Now a section of fence, +X, if there's a post there v3s16 p2 = p; p2.X++; MapNode n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2); - if(n2.getContent() == CONTENT_FENCE) + const ContentFeatures *f2 = &nodedef->get(n2); + if(f2->drawtype == NDT_FENCELIKE) { - pos = intToFloat(p+blockpos_nodes, BS); - pos.X += BS/2; - pos.Y += BS/4; + aabb3f bar(-bar_len+BS/2,-bar_rad+BS/4,-bar_rad, + bar_len+BS/2,bar_rad+BS/4,bar_rad); + bar.MinEdge += pos; + bar.MaxEdge += pos; f32 xrailuv[24]={ 0,0.4,1,0.6, 0,0.4,1,0.6, @@ -819,25 +768,26 @@ void mapblock_mesh_generate_special(MeshMakeData *data, 0,0.4,1,0.6, 0,0.4,1,0.6, 0,0.4,1,0.6}; - makeCuboid(material_wood, &collector, - &pa_wood, c, pos, - bar_len,bar_rad,bar_rad, xrailuv); - - pos.Y -= BS/2; - makeCuboid(material_wood, &collector, - &pa_wood, c, pos, - bar_len,bar_rad,bar_rad, xrailuv); + makeCuboid(&collector, bar, &tile_nocrack, 1, + c, xrailuv); + bar.MinEdge.Y -= BS/2; + bar.MaxEdge.Y -= BS/2; + // TODO: no crack + makeCuboid(&collector, bar, &tile_nocrack, 1, + c, xrailuv); } // Now a section of fence, +Z, if there's a post there p2 = p; p2.Z++; n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2); - if(n2.getContent() == CONTENT_FENCE) + f2 = &nodedef->get(n2); + if(f2->drawtype == NDT_FENCELIKE) { - pos = intToFloat(p+blockpos_nodes, BS); - pos.Z += BS/2; - pos.Y += BS/4; + aabb3f bar(-bar_rad,-bar_rad+BS/4,-bar_len+BS/2, + bar_rad,bar_rad+BS/4,bar_len+BS/2); + bar.MinEdge += pos; + bar.MaxEdge += pos; f32 zrailuv[24]={ 0,0.4,1,0.6, 0,0.4,1,0.6, @@ -845,281 +795,174 @@ void mapblock_mesh_generate_special(MeshMakeData *data, 0,0.4,1,0.6, 0,0.4,1,0.6, 0,0.4,1,0.6}; - makeCuboid(material_wood, &collector, - &pa_wood, c, pos, - bar_rad,bar_rad,bar_len, zrailuv); - pos.Y -= BS/2; - makeCuboid(material_wood, &collector, - &pa_wood, c, pos, - bar_rad,bar_rad,bar_len, zrailuv); - - } - - } -#if 1 - /* - Add stones with minerals if stone is invisible - */ - else if(n.getContent() == CONTENT_STONE && invisible_stone && n.getMineral() != MINERAL_NONE) - { - for(u32 j=0; j<6; j++) - { - // NOTE: Hopefully g_6dirs[j] is the right direction... - v3s16 dir = g_6dirs[j]; - /*u8 l = 0; - MapNode n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + dir); - if(content_features(n2).param_type == CPT_LIGHT) - l = decode_light(n2.getLightBlend(data->m_daynight_ratio)); - else - l = 255;*/ - u8 l = 255; - video::SColor c = MapBlock_LightColor(255, l); - - // Get the right texture - TileSpec ts = n.getTile(dir); - AtlasPointer ap = ts.texture; - material_general.setTexture(0, ap.atlas); - - video::S3DVertex vertices[4] = - { - /*video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c, 0,1), - video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c, 1,1), - video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c, 1,0), - video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c, 0,0),*/ - video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c, - ap.x0(), ap.y1()), - video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c, - ap.x1(), ap.y1()), - video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c, - ap.x1(), ap.y0()), - video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c, - ap.x0(), ap.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 += intToFloat(p + blockpos_nodes, BS); - } - - u16 indices[] = {0,1,2,2,3,0}; - // Add to mesh collector - collector.append(material_general, vertices, 4, indices, 6); - } - } -#endif - else if(n.getContent() == CONTENT_PAPYRUS) - { - u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio))); - video::SColor c = MapBlock_LightColor(255, l); - - for(u32 j=0; j<4; j++) - { - video::S3DVertex vertices[4] = - { - video::S3DVertex(-BS/2,-BS/2,0, 0,0,0, c, - pa_papyrus.x0(), pa_papyrus.y1()), - video::S3DVertex(BS/2,-BS/2,0, 0,0,0, c, - pa_papyrus.x1(), pa_papyrus.y1()), - video::S3DVertex(BS/2,BS/2,0, 0,0,0, c, - pa_papyrus.x1(), pa_papyrus.y0()), - video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c, - pa_papyrus.x0(), pa_papyrus.y0()), - }; - if(j == 0) - { - for(u16 i=0; i<4; i++) - vertices[i].Pos.rotateXZBy(45); - } - else if(j == 1) - { - for(u16 i=0; i<4; i++) - vertices[i].Pos.rotateXZBy(-45); - } - else if(j == 2) - { - for(u16 i=0; i<4; i++) - vertices[i].Pos.rotateXZBy(135); - } - else if(j == 3) - { - for(u16 i=0; i<4; i++) - vertices[i].Pos.rotateXZBy(-135); - } - - 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_papyrus, vertices, 4, indices, 6); + makeCuboid(&collector, bar, &tile_nocrack, 1, + c, zrailuv); + bar.MinEdge.Y -= BS/2; + bar.MaxEdge.Y -= BS/2; + makeCuboid(&collector, bar, &tile_nocrack, 1, + c, zrailuv); } - } - else if(n.getContent() == CONTENT_JUNGLEGRASS) + break;} + case NDT_RAILLIKE: { - u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio))); - video::SColor c = MapBlock_LightColor(255, l); - - for(u32 j=0; j<4; j++) - { - video::S3DVertex vertices[4] = - { - video::S3DVertex(-BS/2,-BS/2,0, 0,0,0, c, - pa_papyrus.x0(), pa_papyrus.y1()), - video::S3DVertex(BS/2,-BS/2,0, 0,0,0, c, - pa_papyrus.x1(), pa_papyrus.y1()), - video::S3DVertex(BS/2,BS/1,0, 0,0,0, c, - pa_papyrus.x1(), pa_papyrus.y0()), - video::S3DVertex(-BS/2,BS/1,0, 0,0,0, c, - pa_papyrus.x0(), pa_papyrus.y0()), - }; - - if(j == 0) - { - for(u16 i=0; i<4; i++) - vertices[i].Pos.rotateXZBy(45); - } - else if(j == 1) - { - for(u16 i=0; i<4; i++) - vertices[i].Pos.rotateXZBy(-45); - } - else if(j == 2) - { - for(u16 i=0; i<4; i++) - vertices[i].Pos.rotateXZBy(135); - } - else if(j == 3) - { - for(u16 i=0; i<4; i++) - vertices[i].Pos.rotateXZBy(-135); - } - - for(u16 i=0; i<4; i++) - { - vertices[i].Pos *= 1.3; - vertices[i].Pos += intToFloat(p + blockpos_nodes, BS); - } - - u16 indices[] = {0,1,2,2,3,0}; - // Add to mesh collector - collector.append(material_junglegrass, vertices, 4, indices, 6); - } - } - else if(n.getContent() == CONTENT_RAIL) - { - u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio)); - video::SColor c = MapBlock_LightColor(255, l); - bool is_rail_x [] = { false, false }; /* x-1, x+1 */ bool is_rail_z [] = { false, false }; /* z-1, z+1 */ + bool is_rail_z_minus_y [] = { false, false }; /* z-1, z+1; y-1 */ + bool is_rail_x_minus_y [] = { false, false }; /* x-1, z+1; y-1 */ + bool is_rail_z_plus_y [] = { false, false }; /* z-1, z+1; y+1 */ + bool is_rail_x_plus_y [] = { false, false }; /* x-1, x+1; y+1 */ + MapNode n_minus_x = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x-1,y,z)); MapNode n_plus_x = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x+1,y,z)); MapNode n_minus_z = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y,z-1)); MapNode n_plus_z = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y,z+1)); - - if(n_minus_x.getContent() == CONTENT_RAIL) + MapNode n_plus_x_plus_y = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x+1, y+1, z)); + MapNode n_plus_x_minus_y = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x+1, y-1, z)); + MapNode n_minus_x_plus_y = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x-1, y+1, z)); + MapNode n_minus_x_minus_y = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x-1, y-1, z)); + MapNode n_plus_z_plus_y = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x, y+1, z+1)); + MapNode n_minus_z_plus_y = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x, y+1, z-1)); + MapNode n_plus_z_minus_y = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x, y-1, z+1)); + MapNode n_minus_z_minus_y = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x, y-1, z-1)); + + content_t thiscontent = n.getContent(); + if(n_minus_x.getContent() == thiscontent) is_rail_x[0] = true; - if(n_plus_x.getContent() == CONTENT_RAIL) + if (n_minus_x_minus_y.getContent() == thiscontent) + is_rail_x_minus_y[0] = true; + if(n_minus_x_plus_y.getContent() == thiscontent) + is_rail_x_plus_y[0] = true; + + if(n_plus_x.getContent() == thiscontent) is_rail_x[1] = true; - if(n_minus_z.getContent() == CONTENT_RAIL) + if (n_plus_x_minus_y.getContent() == thiscontent) + is_rail_x_minus_y[1] = true; + if(n_plus_x_plus_y.getContent() == thiscontent) + is_rail_x_plus_y[1] = true; + + if(n_minus_z.getContent() == thiscontent) is_rail_z[0] = true; - if(n_plus_z.getContent() == CONTENT_RAIL) + if (n_minus_z_minus_y.getContent() == thiscontent) + is_rail_z_minus_y[0] = true; + if(n_minus_z_plus_y.getContent() == thiscontent) + is_rail_z_plus_y[0] = true; + + if(n_plus_z.getContent() == thiscontent) is_rail_z[1] = true; + if (n_plus_z_minus_y.getContent() == thiscontent) + is_rail_z_minus_y[1] = true; + if(n_plus_z_plus_y.getContent() == thiscontent) + is_rail_z_plus_y[1] = true; - float d = (float)BS/16; - video::S3DVertex vertices[4] = - { - video::S3DVertex(-BS/2,-BS/2+d,-BS/2, 0,0,0, c, - 0, 1), - video::S3DVertex(BS/2,-BS/2+d,-BS/2, 0,0,0, c, - 1, 1), - video::S3DVertex(BS/2,-BS/2+d,BS/2, 0,0,0, c, - 1, 0), - video::S3DVertex(-BS/2,-BS/2+d,BS/2, 0,0,0, c, - 0, 0), - }; - video::SMaterial material_rail; - material_rail.setFlag(video::EMF_LIGHTING, false); - material_rail.setFlag(video::EMF_BACK_FACE_CULLING, false); - material_rail.setFlag(video::EMF_BILINEAR_FILTER, false); - material_rail.setFlag(video::EMF_FOG_ENABLE, true); - material_rail.MaterialType - = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; + bool is_rail_x_all[] = {false, false}; + bool is_rail_z_all[] = {false, false}; + is_rail_x_all[0]=is_rail_x[0] || is_rail_x_minus_y[0] || is_rail_x_plus_y[0]; + is_rail_x_all[1]=is_rail_x[1] || is_rail_x_minus_y[1] || is_rail_x_plus_y[1]; + is_rail_z_all[0]=is_rail_z[0] || is_rail_z_minus_y[0] || is_rail_z_plus_y[0]; + is_rail_z_all[1]=is_rail_z[1] || is_rail_z_minus_y[1] || is_rail_z_plus_y[1]; - int adjacencies = is_rail_x[0] + is_rail_x[1] + is_rail_z[0] + is_rail_z[1]; + bool is_straight = (is_rail_x_all[0] && is_rail_x_all[1]) || (is_rail_z_all[0] && is_rail_z_all[1]);//is really straight, rails on both sides + int adjacencies = is_rail_x_all[0] + is_rail_x_all[1] + is_rail_z_all[0] + is_rail_z_all[1]; + + if (is_rail_x_plus_y[0] || is_rail_x_plus_y[1] || is_rail_z_plus_y[0] || is_rail_z_plus_y[1]) //is straight because sloped + { + adjacencies = 5; //5 means sloped + is_straight = true; + } // Assign textures + u8 tileindex = 0; // straight if(adjacencies < 2) - material_rail.setTexture(0, g_texturesource->getTextureRaw("rail.png")); + tileindex = 0; // straight else if(adjacencies == 2) { - if((is_rail_x[0] && is_rail_x[1]) || (is_rail_z[0] && is_rail_z[1])) - material_rail.setTexture(0, g_texturesource->getTextureRaw("rail.png")); + if(is_straight) + tileindex = 0; // straight else - material_rail.setTexture(0, g_texturesource->getTextureRaw("rail_curved.png")); + tileindex = 1; // curved } else if(adjacencies == 3) - material_rail.setTexture(0, g_texturesource->getTextureRaw("rail_t_junction.png")); + tileindex = 2; // t-junction else if(adjacencies == 4) - material_rail.setTexture(0, g_texturesource->getTextureRaw("rail_crossing.png")); + tileindex = 3; // crossing + + TileSpec tile = getNodeTileN(n, p, tileindex, data); + tile.material_flags &= ~MATERIAL_FLAG_BACKFACE_CULLING; + tile.material_flags |= MATERIAL_FLAG_CRACK_OVERLAY; + + AtlasPointer ap = tile.texture; + + u16 l = getInteriorLight(n, 0, data); + video::SColor c = MapBlock_LightColor(255, l); + + float d = (float)BS/64; + + char g=-1; + if (is_rail_x_plus_y[0] || is_rail_x_plus_y[1] || is_rail_z_plus_y[0] || is_rail_z_plus_y[1]) + g=1; //Object is at a slope + + video::S3DVertex vertices[4] = + { + video::S3DVertex(-BS/2,-BS/2+d,-BS/2, 0,0,0, c, + ap.x0(), ap.y1()), + video::S3DVertex(BS/2,-BS/2+d,-BS/2, 0,0,0, c, + ap.x1(), ap.y1()), + video::S3DVertex(BS/2,g*BS/2+d,BS/2, 0,0,0, c, + ap.x1(), ap.y0()), + video::S3DVertex(-BS/2,g*BS/2+d,BS/2, 0,0,0, c, + ap.x0(), ap.y0()), + }; + // Rotate textures int angle = 0; if(adjacencies == 1) { - if(is_rail_x[0] || is_rail_x[1]) + if(is_rail_x_all[0] || is_rail_x_all[1]) angle = 90; } - else if(adjacencies == 2) + if(adjacencies == 2) { - if(is_rail_x[0] && is_rail_x[1]) + if(is_rail_x_all[0] && is_rail_x_all[1]) + { angle = 90; - else if(is_rail_x[0] && is_rail_z[0]) + } + if(is_rail_z_all[0] && is_rail_z_all[1]) + { + if (n_minus_z_plus_y.getContent() == thiscontent) angle = 180; + } + else if(is_rail_x_all[0] && is_rail_z_all[0]) angle = 270; - else if(is_rail_x[0] && is_rail_z[1]) + else if(is_rail_x_all[0] && is_rail_z_all[1]) angle = 180; - else if(is_rail_x[1] && is_rail_z[1]) + else if(is_rail_x_all[1] && is_rail_z_all[1]) angle = 90; } - else if(adjacencies == 3) + if(adjacencies == 3) { - if(!is_rail_x[0]) + if(!is_rail_x_all[0]) angle=0; - if(!is_rail_x[1]) + if(!is_rail_x_all[1]) angle=180; - if(!is_rail_z[0]) + if(!is_rail_z_all[0]) angle=90; - if(!is_rail_z[1]) + if(!is_rail_z_all[1]) angle=270; } + //adjacencies 4: Crossing + if(adjacencies == 5) //sloped + { + if(is_rail_z_plus_y[0]) + angle = 180; + if(is_rail_x_plus_y[0]) + angle = 90; + if(is_rail_x_plus_y[1]) + angle = -90; + } if(angle != 0) { for(u16 i=0; i<4; i++) @@ -1128,13 +971,13 @@ void mapblock_mesh_generate_special(MeshMakeData *data, for(s32 i=0; i<4; i++) { - vertices[i].Pos += intToFloat(p + blockpos_nodes, BS); + vertices[i].Pos += intToFloat(p, BS); } u16 indices[] = {0,1,2,2,3,0}; - collector.append(material_rail, vertices, 4, indices, 6); + collector.append(tile, vertices, 4, indices, 6); + break;} } } } -#endif