X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fmapblock.cpp;h=58b23bd146e6001d50055a18357c1e1ae308bde7;hb=26bbe66288c63fc55bc9185224c3078b7d6b946e;hp=7e23d295b07ec8933901bdbd2e519f63b75d0202;hpb=0ca9423b8b2cf7bd1435fb09eba7a9f50d444864;p=dragonfireclient.git diff --git a/src/mapblock.cpp b/src/mapblock.cpp index 7e23d295b..58b23bd14 100644 --- a/src/mapblock.cpp +++ b/src/mapblock.cpp @@ -19,124 +19,189 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "mapblock.h" #include "map.h" -// For g_materials +// For g_settings #include "main.h" #include "light.h" #include - -/* - MapBlock -*/ - -MapBlock::MapBlock(NodeContainer *parent, v3s16 pos, bool dummy): - m_parent(parent), - m_pos(pos), - changed(true), - is_underground(false), - m_mesh_expired(false), - m_day_night_differs(false), - m_objects(this) +#ifndef SERVER +void MeshMakeData::fill(u32 daynight_ratio, MapBlock *block) { - data = NULL; - if(dummy == false) - reallocate(); + m_daynight_ratio = daynight_ratio; + m_blockpos = block->getPos(); - mesh_mutex.Init(); + v3s16 blockpos_nodes = m_blockpos*MAP_BLOCKSIZE; + + /* + There is no harm not copying the TempMods of the neighbors + because they are already copied to this block + */ + m_temp_mods.clear(); + block->copyTempMods(m_temp_mods); + + /* + Copy data + */ + + // Allocate this block + neighbors + m_vmanip.clear(); + m_vmanip.addArea(VoxelArea(blockpos_nodes-v3s16(1,1,1)*MAP_BLOCKSIZE, + blockpos_nodes+v3s16(1,1,1)*MAP_BLOCKSIZE*2-v3s16(1,1,1))); - mesh = NULL; - /*for(s32 i=0; icopyTo(m_vmanip); + } { - JMutexAutoLock lock(mesh_mutex); + //TimeTaker timer("copy neighbor block data"); + // 0ms + + /* + Copy neighbors. This is lightning fast. + Copying only the borders would be *very* slow. + */ - if(mesh) + // Get map + NodeContainer *parentcontainer = block->getParent(); + // This will only work if the parent is the map + assert(parentcontainer->nodeContainerId() == NODECONTAINER_ID_MAP); + // OK, we have the map! + Map *map = (Map*)parentcontainer; + + for(u16 i=0; i<6; i++) { - mesh->drop(); - mesh = NULL; + const v3s16 &dir = g_6dirs[i]; + v3s16 bp = m_blockpos + dir; + MapBlock *b = map->getBlockNoCreateNoEx(bp); + if(b) + b->copyTo(m_vmanip); } - /*for(s32 i=0; idrop(); - mesh[i] = NULL; - } - }*/ } - - if(data) - delete[] data; } +#endif -bool MapBlock::isValidPositionParent(v3s16 p) +/* + Parameters must consist of air and !air. + Order doesn't matter. + + If either of the nodes doesn't exist, light is 0. + + parameters: + daynight_ratio: 0...1000 + n: getNodeParent(p) + n2: getNodeParent(p + face_dir) + face_dir: axis oriented unit vector from p to p2 + + returns encoded light value. +*/ +u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2, + v3s16 face_dir) { - if(isValidPosition(p)) - { - return true; + try{ + u8 light; + u8 l1 = n.getLightBlend(daynight_ratio); + u8 l2 = n2.getLightBlend(daynight_ratio); + if(l1 > l2) + light = l1; + else + light = l2; + + // Make some nice difference to different sides + + // This makes light come from a corner + /*if(face_dir.X == 1 || face_dir.Z == 1 || face_dir.Y == -1) + light = diminish_light(diminish_light(light)); + else if(face_dir.X == -1 || face_dir.Z == -1) + light = diminish_light(light);*/ + + // All neighboring faces have different shade (like in minecraft) + if(face_dir.X == 1 || face_dir.X == -1 || face_dir.Y == -1) + light = diminish_light(diminish_light(light)); + else if(face_dir.Z == 1 || face_dir.Z == -1) + light = diminish_light(light); + + return light; } - else{ - return m_parent->isValidPosition(getPosRelative() + p); + catch(InvalidPositionException &e) + { + return 0; } } -MapNode MapBlock::getNodeParent(v3s16 p) +#ifndef SERVER + +/* + vertex_dirs: v3s16[4] +*/ +void getNodeVertexDirs(v3s16 dir, v3s16 *vertex_dirs) { - if(isValidPosition(p) == false) + /* + 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)) { - return m_parent->getNode(getPosRelative() + p); + // 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 + else if(dir == v3s16(0,0,-1)) { - if(data == NULL) - throw InvalidPositionException(); - return data[p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X]; + // 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); } -} - -void MapBlock::setNodeParent(v3s16 p, MapNode & n) -{ - if(isValidPosition(p) == false) + else if(dir == v3s16(1,0,0)) { - m_parent->setNode(getPosRelative() + p, n); + // 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 + else if(dir == v3s16(-1,0,0)) { - if(data == NULL) - throw InvalidPositionException(); - data[p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X] = n; + // 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); } -} - -MapNode MapBlock::getNodeParentNoEx(v3s16 p) -{ - if(isValidPosition(p) == false) + else if(dir == v3s16(0,1,0)) { - try{ - return m_parent->getNode(getPosRelative() + p); - } - catch(InvalidPositionException &e) - { - return MapNode(CONTENT_IGNORE); - } + // 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 + else if(dir == v3s16(0,-1,0)) { - if(data == NULL) - { - return MapNode(CONTENT_IGNORE); - } - return data[p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X]; + // 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); } } -void MapBlock::makeFastFace(TileSpec tile, u8 light, v3f p, +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) { @@ -147,42 +212,15 @@ void MapBlock::makeFastFace(TileSpec tile, u8 light, v3f p, 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(dir == v3s16(0,0,1)) - { - for(u16 i=0; i<4; i++) - vertex_pos[i].rotateXZBy(0); - } - else if(dir == v3s16(0,0,-1)) - { - for(u16 i=0; i<4; i++) - vertex_pos[i].rotateXZBy(180); - } - else if(dir == v3s16(1,0,0)) - { - for(u16 i=0; i<4; i++) - vertex_pos[i].rotateXZBy(-90); - } - else if(dir == v3s16(-1,0,0)) - { - for(u16 i=0; i<4; i++) - vertex_pos[i].rotateXZBy(90); - } - else if(dir == v3s16(0,1,0)) - { - for(u16 i=0; i<4; i++) - vertex_pos[i].rotateYZBy(-90); - } - else if(dir == v3s16(0,-1,0)) + v3s16 vertex_dirs[4]; + getNodeVertexDirs(dir, vertex_dirs); + for(u16 i=0; i<4; i++) { - for(u16 i=0; i<4; i++) - vertex_pos[i].rotateYZBy(90); + 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++) @@ -200,131 +238,117 @@ void MapBlock::makeFastFace(TileSpec tile, u8 light, v3f p, v3f zerovector = v3f(0,0,0); - u8 li = decode_light(light); - //u8 li = 150; - - u8 alpha = 255; - + u8 alpha = tile.alpha; + /*u8 alpha = 255; if(tile.id == TILE_WATER) - { - alpha = 128; - } - - video::SColor c = video::SColor(alpha,li,li,li); - - face.vertices[0] = video::S3DVertex(vertex_pos[0], zerovector, c, - core::vector2d(0,1)); - face.vertices[1] = video::S3DVertex(vertex_pos[1], zerovector, c, - core::vector2d(abs_scale,1)); - face.vertices[2] = video::S3DVertex(vertex_pos[2], zerovector, c, - core::vector2d(abs_scale,0)); - face.vertices[3] = video::S3DVertex(vertex_pos[3], zerovector, c, - core::vector2d(0,0)); + alpha = WATER_ALPHA;*/ + + 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, + core::vector2d(x0, y0+h)); + 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; //DEBUG //f->tile = TILE_STONE; dest.push_back(face); - //return f; } -/* - Parameters must consist of air and !air. - Order doesn't matter. - - If either of the nodes doesn't exist, light is 0. - - parameters: - daynight_ratio: 0...1000 - n: getNodeParent(p) - n2: getNodeParent(p + face_dir) - face_dir: axis oriented unit vector from p to p2 -*/ -u8 MapBlock::getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2, - v3s16 face_dir) -{ - try{ - u8 light; - u8 l1 = n.getLightBlend(daynight_ratio); - u8 l2 = n2.getLightBlend(daynight_ratio); - if(l1 > l2) - light = l1; - else - light = l2; - - // Make some nice difference to different sides - - /*if(face_dir.X == 1 || face_dir.Z == 1 || face_dir.Y == -1) - light = diminish_light(diminish_light(light)); - else if(face_dir.X == -1 || face_dir.Z == -1) - light = diminish_light(light);*/ - - if(face_dir.X == 1 || face_dir.X == -1 || face_dir.Y == -1) - light = diminish_light(diminish_light(light)); - else if(face_dir.Z == 1 || face_dir.Z == -1) - light = diminish_light(light); - - return light; - } - catch(InvalidPositionException &e) - { - return 0; - } -} - /* Gets node tile from any place relative to block. Returns TILE_NODE if doesn't exist or should not be drawn. */ -TileSpec MapBlock::getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir) +TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir, + NodeModMap &temp_mods) { TileSpec spec; - - /*//DEBUG - { - spec.id = TILE_STONE; - return spec; - }*/ - - spec.feature = TILEFEAT_NONE; - //spec.id = TILE_STONE; - spec.id = mn.getTile(face_dir); - + spec = mn.getTile(face_dir); + /* Check temporary modifications on this node */ - core::map::Node *n; + /*core::map::Node *n; n = m_temp_mods.find(p); - // If modified if(n != NULL) { - struct NodeMod mod = n->getValue(); + struct NodeMod mod = n->getValue();*/ + NodeMod mod; + if(temp_mods.get(p, &mod)) + { if(mod.type == NODEMOD_CHANGECONTENT) { - spec.id = content_tile(mod.param, face_dir); + MapNode mn2(mod.param); + spec = mn2.getTile(face_dir); } if(mod.type == NODEMOD_CRACK) { + /* + Get texture id, translate it to name, append stuff to + name, get texture id + */ + + // Get original texture name + u32 orig_id = spec.texture.id; + std::string orig_name = g_texturesource->getTextureName(orig_id); + + // Create new texture name + std::ostringstream os; + os<getTextureId(os.str()); + + /*dstream<<"MapBlock::getNodeTile(): Switching from " + <getTexture(new_id); } } return spec; } -u8 MapBlock::getNodeContent(v3s16 p, MapNode mn) +u8 getNodeContent(v3s16 p, MapNode mn, NodeModMap &temp_mods) { /* Check temporary modifications on this node */ - core::map::Node *n; + /*core::map::Node *n; n = m_temp_mods.find(p); - // If modified if(n != NULL) { - struct NodeMod mod = n->getValue(); + struct NodeMod mod = n->getValue();*/ + NodeMod mod; + if(temp_mods.get(p, &mod)) + { if(mod.type == NODEMOD_CHANGECONTENT) { // Overrides content @@ -349,57 +373,199 @@ u8 MapBlock::getNodeContent(v3s16 p, MapNode mn) return mn.d; } -/* - startpos: - translate_dir: unit vector with only one of x, y or z - face_dir: unit vector with only one of x, y or z -*/ -void MapBlock::updateFastFaceRow( - u32 daynight_ratio, - v3f posRelative_f, - v3s16 startpos, - u16 length, - v3s16 translate_dir, - v3f translate_dir_f, - v3s16 face_dir, - v3f face_dir_f, - core::array &dest) +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) { - v3s16 p = startpos; - - u16 continuous_tiles_count = 0; - - MapNode n0 = getNodeParentNoEx(p); - MapNode n1 = getNodeParentNoEx(p + face_dir); + 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++; + } + } - u8 light = getFaceLight(daynight_ratio, n0, n1, face_dir); - - TileSpec tile0 = getNodeTile(n0, p, face_dir); - TileSpec tile1 = getNodeTile(n1, p + face_dir, -face_dir); + if(light_count == 0) + return 255; + + light /= light_count; - for(u16 j=0; j 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 + face_dir: unit vector with only one of x, y or z +*/ +void updateFastFaceRow( + u32 daynight_ratio, + v3f posRelative_f, + v3s16 startpos, + u16 length, + v3s16 translate_dir, + v3f translate_dir_f, + v3s16 face_dir, + v3f face_dir_f, + core::array &dest, + NodeModMap &temp_mods, + VoxelManipulator &vmanip, + v3s16 blockpos_nodes, + bool smooth_lighting) +{ + v3s16 p = startpos; + + u16 continuous_tiles_count = 0; + + 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; j m_prebuffers; }; -void MapBlock::updateMesh(u32 daynight_ratio) +scene::SMesh* makeMapBlockMesh(MeshMakeData *data) { -#if 0 - /* - DEBUG: If mesh has been generated, don't generate it again - */ - { - JMutexAutoLock meshlock(mesh_mutex); - if(mesh != NULL) - return; - } -#endif - - // 4-21ms - //TimeTaker timer1("updateMesh()", g_device); + // 4-21ms for MAP_BLOCKSIZE=16 + // 24-155ms for MAP_BLOCKSIZE=32 + //TimeTaker timer1("makeMapBlockMesh()"); core::array fastfaces_new; + + v3s16 blockpos_nodes = data->m_blockpos*MAP_BLOCKSIZE; + + // floating point conversion + v3f posRelative_f(blockpos_nodes.X, blockpos_nodes.Y, blockpos_nodes.Z); + + /* + 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"); - v3f posRelative_f(getPosRelative().X, getPosRelative().Y, - getPosRelative().Z); // floating point conversion + float node_water_level = 1.0; + if(new_style_water) + node_water_level = 0.85; /* We are including the faces of the trailing edges of the block. @@ -587,47 +760,64 @@ void MapBlock::updateMesh(u32 daynight_ratio) NOTE: This is the slowest part of this method. */ + + { + // 4-23ms for MAP_BLOCKSIZE=16 + //TimeTaker timer2("updateMesh() collect"); - /* - Go through every y,z and get top faces in rows of x+ - */ - for(s16 y=0; ym_daynight_ratio, posRelative_f, + v3s16(0,y,z), MAP_BLOCKSIZE, + v3s16(1,0,0), //dir + v3f (1,0,0), + v3s16(0,1,0), //face dir + v3f (0,1,0), + fastfaces_new, + data->m_temp_mods, + data->m_vmanip, + blockpos_nodes, + smooth_lighting); + } } - } - /* - Go through every y,z and get back faces in rows of x+ - */ - for(s16 z=0; zm_daynight_ratio, posRelative_f, + v3s16(x,y,0), MAP_BLOCKSIZE, + v3s16(0,0,1), + v3f (0,0,1), + v3s16(1,0,0), + v3f (1,0,0), + fastfaces_new, + data->m_temp_mods, + data->m_vmanip, + blockpos_nodes, + smooth_lighting); + } + } + /* + Go through every y,z and get back(z+) faces in rows of x+ + */ + for(s16 z=0; zm_daynight_ratio, posRelative_f, + v3s16(0,y,z), MAP_BLOCKSIZE, + v3s16(1,0,0), + v3f (1,0,0), + v3s16(0,0,1), + v3f (0,0,1), + fastfaces_new, + data->m_temp_mods, + data->m_vmanip, + blockpos_nodes, + smooth_lighting); + } } } @@ -637,161 +827,855 @@ void MapBlock::updateMesh(u32 daynight_ratio) Convert FastFaces to SMesh */ - scene::SMesh *mesh_new = NULL; - - mesh_new = new scene::SMesh(); - + MeshCollector collector; + if(fastfaces_new.size() > 0) { - MeshCollector collector; + // avg 0ms (100ms spikes when loading textures the first time) + //TimeTaker timer2("updateMesh() mesh building"); + + video::SMaterial material; + material.setFlag(video::EMF_LIGHTING, false); + material.setFlag(video::EMF_BILINEAR_FILTER, false); + material.setFlag(video::EMF_FOG_ENABLE, true); + //material.setFlag(video::EMF_ANTI_ALIASING, video::EAAM_OFF); + //material.setFlag(video::EMF_ANTI_ALIASING, video::EAAM_SIMPLE); for(u32 i=0; igetTexture( + 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); + + + for(s16 z=0; zm_vmanip.getNodeNoEx(blockpos_nodes+p); + + /* + Add torches to mesh + */ + if(n.d == CONTENT_TORCH) + { + video::SColor c(255,255,255,255); + + // Wall at X+ of node + video::S3DVertex vertices[4] = { - collector.append(g_tile_materials[f.tile.id], f.vertices, 4, - indices, 6); + video::S3DVertex(-BS/2,-BS/2,0, 0,0,0, c, 0,1), + video::S3DVertex(BS/2,-BS/2,0, 0,0,0, c, 1,1), + video::S3DVertex(BS/2,BS/2,0, 0,0,0, c, 1,0), + video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c, 0,0), + }; + + v3s16 dir = unpackDir(n.dir); + + 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 + blockpos_nodes, BS); } + + // 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.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; + material.MaterialType + = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; + + if(dir == v3s16(0,-1,0)) + material.setTexture(0, + g_texturesource->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")); + + u16 indices[] = {0,1,2,2,3,0}; + // Add to mesh collector + collector.append(material, vertices, 4, indices, 6); + } + /* + Signs on walls + */ + if(n.d == CONTENT_SIGN_WALL) + { + u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio)); + video::SColor c(255,l,l,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, 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), + }; + + v3s16 dir = unpackDir(n.dir); + + 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); + } + + // 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.d == CONTENT_WATER) + { + bool top_is_water = false; + 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 = 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) + // Includes current node + core::map neighbor_levels; + core::map neighbor_contents; + core::map neighbor_flags; + const u8 neighborflag_top_is_water = 0x01; + v3s16 neighbor_dirs[9] = { + v3s16(0,0,0), + v3s16(0,0,1), + v3s16(0,0,-1), + v3s16(1,0,0), + v3s16(-1,0,0), + v3s16(1,0,1), + v3s16(-1,0,-1), + v3s16(1,0,-1), + v3s16(-1,0,1), + }; + for(u32 i=0; i<9; i++) { - // Not implemented - assert(0); + u8 content = CONTENT_AIR; + float level = -0.5 * BS; + u8 flags = 0; + // Check neighbor + v3s16 p2 = p + neighbor_dirs[i]; + MapNode n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2); + if(n2.d != CONTENT_IGNORE) + { + content = n2.d; + + if(n2.d == CONTENT_WATERSOURCE) + level = (-0.5+node_water_level) * BS; + else if(n2.d == CONTENT_WATER) + level = (-0.5 + ((float)n2.param2 + 0.5) / 8.0 + * node_water_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.d == CONTENT_WATERSOURCE || n2.d == CONTENT_WATER) + flags |= neighborflag_top_is_water; + } + + neighbor_levels.insert(neighbor_dirs[i], level); + neighbor_contents.insert(neighbor_dirs[i], content); + 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) + f32 corner_levels[4]; + + v3s16 halfdirs[4] = { + v3s16(0,0,0), + v3s16(1,0,0), + v3s16(1,0,1), + v3s16(0,0,1), + }; + for(u32 i=0; i<4; i++) + { + v3s16 cornerdir = halfdirs[i]; + float cornerlevel = 0; + u32 valid_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) + { + cornerlevel = (-0.5+node_water_level)*BS; + valid_count = 1; + break; + } + else if(content == CONTENT_WATER) + { + cornerlevel += neighbor_levels[neighbordir]; + valid_count++; + } + else if(content == CONTENT_AIR) + { + cornerlevel += -0.5*BS; + valid_count++; + } + } + if(valid_count > 0) + cornerlevel /= valid_count; + corner_levels[i] = cornerlevel; + } + + /* + Generate sides + */ + + v3s16 side_dirs[4] = { + v3s16(1,0,0), + v3s16(-1,0,0), + v3s16(0,0,1), + v3s16(0,0,-1), + }; + s16 side_corners[4][2] = { + {1, 2}, + {3, 0}, + {2, 3}, + {0, 1}, + }; + for(u32 i=0; i<4; i++) + { + v3s16 dir = side_dirs[i]; + + /* + If our topside is water and neighbor's topside + is water, don't draw side face + */ + if(top_is_water && + neighbor_flags[dir] & neighborflag_top_is_water) + continue; + + u8 neighbor_content = neighbor_contents[dir]; + + // Don't draw face if neighbor is not air or water + if(neighbor_content != CONTENT_AIR + && neighbor_content != CONTENT_WATER) + continue; + + bool neighbor_is_water = (neighbor_content == CONTENT_WATER); + + // Don't draw any faces if neighbor is water and top is water + if(neighbor_is_water == true && top_is_water == false) + continue; + + 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()), + }; + + /* + If our topside is water, set upper border of face + at upper border of node + */ + if(top_is_water) + { + vertices[2].Pos.Y = 0.5*BS; + vertices[3].Pos.Y = 0.5*BS; + } + /* + Otherwise upper position of face is corner levels + */ + else + { + vertices[2].Pos.Y = corner_levels[side_corners[i][0]]; + vertices[3].Pos.Y = corner_levels[side_corners[i][1]]; + } + + /* + If neighbor is water, lower border of face is corner + water levels + */ + if(neighbor_is_water) + { + 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 + lower border of node + */ + else + { + vertices[0].Pos.Y = -0.5*BS; + vertices[1].Pos.Y = -0.5*BS; + } + + for(s32 j=0; j<4; j++) + { + if(dir == v3s16(0,0,1)) + vertices[j].Pos.rotateXZBy(0); + if(dir == v3s16(0,0,-1)) + vertices[j].Pos.rotateXZBy(180); + if(dir == v3s16(-1,0,0)) + vertices[j].Pos.rotateXZBy(90); + if(dir == v3s16(1,0,-0)) + vertices[j].Pos.rotateXZBy(-90); + + vertices[j].Pos += intToFloat(p + blockpos_nodes, BS); + } + + u16 indices[] = {0,1,2,2,3,0}; + // Add to mesh collector + collector.append(material_water1, vertices, 4, indices, 6); + } + + /* + Generate top side, if appropriate + */ + + if(top_is_water == 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()), + 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()), + }; + + // This fixes a strange bug + s32 corner_resolve[4] = {3,2,1,0}; + + for(s32 i=0; i<4; i++) + { + //vertices[i].Pos.Y += water_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); + } + + u16 indices[] = {0,1,2,2,3,0}; + // Add to mesh collector + collector.append(material_water1, vertices, 4, indices, 6); + } + } + /* + Add water sources to mesh if using new style + */ + else if(n.d == CONTENT_WATERSOURCE && new_style_water) + { + //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.d == CONTENT_WATER || n.d == CONTENT_WATERSOURCE) + top_is_water = true;*/ + if(n.d == 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(WATER_ALPHA,l,l,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); + } + + 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.d == 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))); + 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, 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()), + video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c, + pa_leaves1.x1(), pa_leaves1.y1()), + video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c, + pa_leaves1.x1(), pa_leaves1.y0()), + video::S3DVertex(-BS/2,BS/2,BS/2, 0,0,0, c, + pa_leaves1.x0(), pa_leaves1.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_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); } } - collector.fillMesh(mesh_new); + + + } + + /* + Add stuff from collector to mesh + */ + + scene::SMesh *mesh_new = NULL; + mesh_new = new scene::SMesh(); + + collector.fillMesh(mesh_new); + + /* + Do some stuff to the mesh + */ + + mesh_new->recalculateBoundingBox(); + + /* + Delete new mesh if it is empty + */ + + if(mesh_new->getMeshBufferCount() == 0) + { + mesh_new->drop(); + mesh_new = NULL; + } + + if(mesh_new) + { +#if 0 + // Usually 1-700 faces and 1-7 materials + std::cout<<"Updated MapBlock has "<getMeshBufferCount() + <<" materials (meshbuffers)"<setHardwareMappingHint(scene::EHM_STATIC); + + /* + NOTE: If that is enabled, some kind of a queue to the main + thread should be made which would call irrlicht to delete + the hardware buffer and then delete the mesh + */ + } + + return mesh_new; + + //std::cout<<"added "<getSize()<<" faces " - <<"and uses "<getMeshBufferCount() - <<" materials (meshbuffers)"<drop(); + mesh = NULL; + } } +#endif - /* - Clear temporary FastFaces - */ + if(data) + delete[] data; +} + +bool MapBlock::isValidPositionParent(v3s16 p) +{ + if(isValidPosition(p)) + { + return true; + } + else{ + return m_parent->isValidPosition(getPosRelative() + p); + } +} + +MapNode MapBlock::getNodeParent(v3s16 p) +{ + if(isValidPosition(p) == false) + { + return m_parent->getNode(getPosRelative() + p); + } + else + { + if(data == NULL) + throw InvalidPositionException(); + return data[p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X]; + } +} - /*core::list::Iterator i; - i = fastfaces_new->begin(); - for(; i != fastfaces_new->end(); i++) +void MapBlock::setNodeParent(v3s16 p, MapNode & n) +{ + if(isValidPosition(p) == false) { - delete *i; + m_parent->setNode(getPosRelative() + p, n); } - fastfaces_new->clear(); - delete fastfaces_new;*/ - - /* - Add special graphics: - - torches - - TODO: Optimize by using same meshbuffer for same textures - */ + else + { + if(data == NULL) + throw InvalidPositionException(); + data[p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X] = n; + } +} - /*scene::ISceneManager *smgr = NULL; - video::IVideoDriver* driver = NULL; - if(g_device) +MapNode MapBlock::getNodeParentNoEx(v3s16 p) +{ + if(isValidPosition(p) == false) { - smgr = g_device->getSceneManager(); - driver = smgr->getVideoDriver(); - }*/ - - for(s16 z=0; zgetNode(getPosRelative() + p); + } + catch(InvalidPositionException &e) + { + return MapNode(CONTENT_IGNORE); + } + } + else { - v3s16 p(x,y,z); - - MapNode &n = getNodeRef(x,y,z); - - if(n.d == CONTENT_TORCH) + if(data == NULL) { - //scene::IMeshBuffer *buf = new scene::SMeshBuffer(); - scene::SMeshBuffer *buf = new scene::SMeshBuffer(); - video::SColor c(255,255,255,255); - - video::S3DVertex vertices[4] = - { - video::S3DVertex(-BS/2,-BS/2,0, 0,0,0, c, 0,1), - video::S3DVertex(BS/2,-BS/2,0, 0,0,0, c, 1,1), - video::S3DVertex(BS/2,BS/2,0, 0,0,0, c, 1,0), - video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c, 0,0), - }; - - v3s16 dir = unpackDir(n.dir); - - 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 + getPosRelative()); - } - - u16 indices[] = {0,1,2,2,3,0}; - buf->append(vertices, 4, indices, 6); - - // Set material - buf->getMaterial().setFlag(video::EMF_LIGHTING, false); - buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false); - buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false); - //buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; - buf->getMaterial().MaterialType - = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; - if(dir == v3s16(0,-1,0)) - buf->getMaterial().setTexture(0, - g_texturecache.get("torch_on_floor")); - else if(dir == v3s16(0,1,0)) - buf->getMaterial().setTexture(0, - g_texturecache.get("torch_on_ceiling")); - // For backwards compatibility - else if(dir == v3s16(0,0,0)) - buf->getMaterial().setTexture(0, - g_texturecache.get("torch_on_floor")); - else - buf->getMaterial().setTexture(0, g_texturecache.get("torch")); - - // Add to mesh - mesh_new->addMeshBuffer(buf); - buf->drop(); + return MapNode(CONTENT_IGNORE); } + return data[p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X]; } - - /* - Do some stuff to the mesh - */ +} - mesh_new->recalculateBoundingBox(); +#ifndef SERVER +#if 1 +void MapBlock::updateMesh(u32 daynight_ratio) +{ +#if 0 /* - Delete new mesh if it is empty + DEBUG: If mesh has been generated, don't generate it again */ - - if(mesh_new->getMeshBufferCount() == 0) { - mesh_new->drop(); - mesh_new = NULL; + JMutexAutoLock meshlock(mesh_mutex); + if(mesh != NULL) + return; } +#endif + MeshMakeData data; + data.fill(daynight_ratio, this); + + scene::SMesh *mesh_new = makeMapBlockMesh(&data); + /* Replace the mesh */ + replaceMesh(mesh_new); + +} +#endif + +void MapBlock::replaceMesh(scene::SMesh *mesh_new) +{ mesh_mutex.Lock(); //scene::SMesh *mesh_old = mesh[daynight_i]; @@ -828,21 +1712,9 @@ void MapBlock::updateMesh(u32 daynight_ratio) } mesh_mutex.Unlock(); - - //std::cout<<"added "<= 0 && first_i <= DAYNIGHT_CACHE_COUNT); - updateMesh(first_i); - for(s32 i=0; i & light_sources) +bool MapBlock::propagateSunlight(core::map & light_sources, + bool remove_light, bool *black_air_left, + bool grow_grass) { // Whether the sunlight at the top of the bottom block is valid bool block_below_is_valid = true; @@ -869,6 +1750,7 @@ bool MapBlock::propagateSunlight(core::map & light_sources) { for(s16 z=0; z & light_sources) MapNode n = getNodeParent(v3s16(x, MAP_BLOCKSIZE, z)); if(n.getLight(LIGHTBANK_DAY) != LIGHT_SUN) { - /*if(is_underground) - { - no_sunlight = true; - }*/ no_sunlight = true; } } @@ -887,18 +1765,41 @@ bool MapBlock::propagateSunlight(core::map & light_sources) { no_top_block = true; - // TODO: This makes over-ground roofed places sunlighted + // NOTE: This makes over-ground roofed places sunlighted // Assume sunlight, unless is_underground==true if(is_underground) { no_sunlight = true; } - - // TODO: There has to be some way to allow this behaviour - // As of now, it just makes everything dark. + else + { + MapNode n = getNode(v3s16(x, MAP_BLOCKSIZE-1, z)); + if(n.d == CONTENT_WATER || n.d == CONTENT_WATERSOURCE) + { + no_sunlight = true; + } + } + // NOTE: As of now, this just would make everything dark. // No sunlight here //no_sunlight = true; } +#endif +#if 0 // Doesn't work; nothing gets light. + bool no_sunlight = true; + bool no_top_block = false; + // Check if node above block has sunlight + try{ + MapNode n = getNodeParent(v3s16(x, MAP_BLOCKSIZE, z)); + if(n.getLight(LIGHTBANK_DAY) == LIGHT_SUN) + { + no_sunlight = false; + } + } + catch(InvalidPositionException &e) + { + no_top_block = true; + } +#endif /*std::cout<<"("<= 10) { - // Uncompress and set pressure data + // Uncompress and set param2 data std::ostringstream os(std::ios_base::binary); decompress(is, os, version); std::string s = os.str(); @@ -1232,7 +2287,7 @@ void MapBlock::deSerialize(std::istream &is, u8 version) ("MapBlock::deSerialize: invalid format"); for(u32 i=0; i= 14) + { + // Ignore errors + try{ + if(version <= 15) + { + std::string data = deSerializeString(is); + std::istringstream iss(data, std::ios_base::binary); + m_node_metadata.deSerialize(iss); + } + else + { + //std::string data = deSerializeLongString(is); + std::ostringstream oss(std::ios_base::binary); + decompressZlib(is, oss); + std::istringstream iss(oss.str(), std::ios_base::binary); + m_node_metadata.deSerialize(iss); + } + } + catch(SerializationError &e) + { + dstream<<"WARNING: MapBlock::deSerialize(): Ignoring an error" + <<" while deserializing node metadata"<d<