X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fmapblock.cpp;h=58b23bd146e6001d50055a18357c1e1ae308bde7;hb=26bbe66288c63fc55bc9185224c3078b7d6b946e;hp=f06dbc81120ab98e99867c91e714d3b6cf4e009b;hpb=bd100c5483eb77a27eeac4e476c81a1bf6afc710;p=dragonfireclient.git diff --git a/src/mapblock.cpp b/src/mapblock.cpp index f06dbc811..58b23bd14 100644 --- a/src/mapblock.cpp +++ b/src/mapblock.cpp @@ -19,116 +19,69 @@ 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_day_night_differs(false), - m_objects(this) -{ - data = NULL; - if(dummy == false) - reallocate(); - - m_spawn_timer = -10000; - #ifndef SERVER - m_mesh_expired = false; - mesh_mutex.Init(); - mesh = NULL; - m_temp_mods_mutex.Init(); -#endif -} - -MapBlock::~MapBlock() +void MeshMakeData::fill(u32 daynight_ratio, MapBlock *block) { -#ifndef SERVER - { - JMutexAutoLock lock(mesh_mutex); - - if(mesh) - { - mesh->drop(); - mesh = NULL; - } - } -#endif + m_daynight_ratio = daynight_ratio; + m_blockpos = block->getPos(); - if(data) - delete[] data; -} + 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 + */ -bool MapBlock::isValidPositionParent(v3s16 p) -{ - if(isValidPosition(p)) - { - return true; - } - else{ - return m_parent->isValidPosition(getPosRelative() + p); - } -} + // 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))); -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]; - } -} + //TimeTaker timer("copy central block data"); + // 0ms -void MapBlock::setNodeParent(v3s16 p, MapNode & n) -{ - if(isValidPosition(p) == false) - { - m_parent->setNode(getPosRelative() + p, n); + // Copy our data + block->copyTo(m_vmanip); } - else { - if(data == NULL) - throw InvalidPositionException(); - data[p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X] = n; - } -} + //TimeTaker timer("copy neighbor block data"); + // 0ms -MapNode MapBlock::getNodeParentNoEx(v3s16 p) -{ - if(isValidPosition(p) == false) - { - try{ - return m_parent->getNode(getPosRelative() + p); - } - catch(InvalidPositionException &e) - { - return MapNode(CONTENT_IGNORE); - } - } - else - { - if(data == NULL) + /* + Copy neighbors. This is lightning fast. + Copying only the borders would be *very* slow. + */ + + // 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++) { - return MapNode(CONTENT_IGNORE); + const v3s16 &dir = g_6dirs[i]; + v3s16 bp = m_blockpos + dir; + MapBlock *b = map->getBlockNoCreateNoEx(bp); + if(b) + b->copyTo(m_vmanip); } - return data[p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X]; } } +#endif /* Parameters must consist of air and !air. @@ -144,29 +97,10 @@ MapNode MapBlock::getNodeParentNoEx(v3s16 p) returns encoded light value. */ -u8 MapBlock::getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2, +u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2, v3s16 face_dir) { try{ - // DEBUG - /*{ - if(n.d == CONTENT_WATER) - { - u8 l = n.param2*2; - if(l > LIGHT_MAX) - l = LIGHT_MAX; - return l; - } - if(n2.d == CONTENT_WATER) - { - u8 l = n2.param2*2; - if(l > LIGHT_MAX) - l = LIGHT_MAX; - return l; - } - }*/ - - u8 light; u8 l1 = n.getLightBlend(daynight_ratio); u8 l2 = n2.getLightBlend(daynight_ratio); @@ -177,11 +111,13 @@ u8 MapBlock::getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2, // 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) @@ -197,53 +133,94 @@ u8 MapBlock::getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2, #ifndef SERVER -void MapBlock::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++) @@ -261,38 +238,53 @@ void MapBlock::makeFastFace(TileSpec tile, u8 light, v3f p, v3f zerovector = v3f(0,0,0); - //u8 li = decode_light(light); - u8 li = light; - u8 alpha = tile.alpha; /*u8 alpha = 255; if(tile.id == TILE_WATER) alpha = WATER_ALPHA;*/ - 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)); + 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; } /* 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; spec = mn.getTile(face_dir); @@ -300,42 +292,63 @@ TileSpec MapBlock::getNodeTile(MapNode mn, v3s16 p, v3s16 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 = 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<<"[[mod:crack"<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 @@ -360,12 +373,139 @@ u8 MapBlock::getNodeContent(v3s16 p, MapNode mn) 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 face_dir: unit vector with only one of x, y or z */ -void MapBlock::updateFastFaceRow( +void updateFastFaceRow( u32 daynight_ratio, v3f posRelative_f, v3s16 startpos, @@ -374,43 +514,58 @@ void MapBlock::updateFastFaceRow( v3f translate_dir_f, v3s16 face_dir, v3f face_dir_f, - core::array &dest) + core::array &dest, + NodeModMap &temp_mods, + VoxelManipulator &vmanip, + v3s16 blockpos_nodes, + bool smooth_lighting) { v3s16 p = startpos; u16 continuous_tiles_count = 0; - MapNode n0 = getNodeParentNoEx(p); - MapNode n1 = getNodeParentNoEx(p + face_dir); - - 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); + 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 for MAP_BLOCKSIZE=16 // 24-155ms for MAP_BLOCKSIZE=32 - //TimeTaker timer1("updateMesh()"); + //TimeTaker timer1("makeMapBlockMesh()"); core::array fastfaces_new; + + v3s16 blockpos_nodes = data->m_blockpos*MAP_BLOCKSIZE; - v3f posRelative_f(getPosRelative().X, getPosRelative().Y, - getPosRelative().Z); // floating point conversion + // 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"); + + 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. @@ -601,51 +762,61 @@ void MapBlock::updateMesh(u32 daynight_ratio) */ { - TimeTaker timer2("updateMesh() collect"); - - // Lock this, as m_temp_mods will be used directly - JMutexAutoLock lock(m_temp_mods_mutex); + // 4-23ms for MAP_BLOCKSIZE=16 + //TimeTaker timer2("updateMesh() collect"); /* - Go through every y,z and get top faces in rows of x+ + Go through every y,z and get top(y+) 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); + fastfaces_new, + data->m_temp_mods, + data->m_vmanip, + 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_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); + 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+ + 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); + fastfaces_new, + data->m_temp_mods, + data->m_vmanip, + blockpos_nodes, + smooth_lighting); } } } @@ -656,10 +827,6 @@ 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) @@ -667,44 +834,91 @@ void MapBlock::updateMesh(u32 daynight_ratio) // 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(f.tile.name); - video::SMaterial material; - material.Lighting = false; - material.BackfaceCulling = false; - material.setFlag(video::EMF_BILINEAR_FILTER, false); - material.setFlag(video::EMF_ANTI_ALIASING, video::EAAM_OFF); - material.setFlag(video::EMF_FOG_ENABLE, true); material.setTexture(0, texture); - if(f.tile.alpha != 255) - material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA; - collector.append(material, f.vertices, 4, indices, 6); + f.tile.applyMaterialOptions(material); + + const u16 *indices_p = indices; + + /* + 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); } } /* Add special graphics: - torches - - TODO: Optimize by using same meshbuffer for same textures + - flowing water */ // 0ms //TimeTaker timer2("updateMesh() adding special stuff"); + // 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); + + for(s16 z=0; zm_vmanip.getNodeNoEx(blockpos_nodes+p); /* Add torches to mesh @@ -713,6 +927,7 @@ void MapBlock::updateMesh(u32 daynight_ratio) { 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, 0,1), @@ -738,7 +953,7 @@ void MapBlock::updateMesh(u32 daynight_ratio) if(dir == v3s16(0,1,0)) vertices[i].Pos.rotateXZBy(-45); - vertices[i].Pos += intToFloat(p + getPosRelative()); + vertices[i].Pos += intToFloat(p + blockpos_nodes, BS); } // Set material @@ -749,19 +964,75 @@ void MapBlock::updateMesh(u32 daynight_ratio) //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_irrlicht->getTexture(porting::getDataPath("torch_on_floor.png").c_str())); + g_texturesource->getTextureRaw("torch_on_floor.png")); else if(dir == v3s16(0,1,0)) material.setTexture(0, - g_irrlicht->getTexture(porting::getDataPath("torch_on_ceiling.png").c_str())); + g_texturesource->getTextureRaw("torch_on_ceiling.png")); // For backwards compatibility else if(dir == v3s16(0,0,0)) material.setTexture(0, - g_irrlicht->getTexture(porting::getDataPath("torch_on_floor.png").c_str())); + g_texturesource->getTextureRaw("torch_on_floor.png")); else material.setTexture(0, - g_irrlicht->getTexture(porting::getDataPath("torch.png").c_str())); + 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 @@ -773,19 +1044,25 @@ void MapBlock::updateMesh(u32 daynight_ratio) else if(n.d == CONTENT_WATER) { bool top_is_water = false; - try{ - MapNode n = getNodeParent(v3s16(x,y+1,z)); - if(n.d == CONTENT_WATER || n.d == CONTENT_WATERSOURCE) - top_is_water = true; - }catch(InvalidPositionException &e){} + 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(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) // 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), @@ -801,21 +1078,32 @@ void MapBlock::updateMesh(u32 daynight_ratio) { u8 content = CONTENT_AIR; float level = -0.5 * BS; - try{ - v3s16 p2 = p + neighbor_dirs[i]; - MapNode n2 = getNodeParent(p2); - + 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 * BS; + level = (-0.5+node_water_level) * BS; else if(n2.d == CONTENT_WATER) - level = (-0.5 + ((float)n2.param2 + 0.5) / 8.0) * BS; + 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; } - catch(InvalidPositionException &e){} 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; @@ -842,7 +1130,7 @@ void MapBlock::updateMesh(u32 daynight_ratio) // Special case for source nodes if(content == CONTENT_WATERSOURCE) { - cornerlevel = 0.5*BS; + cornerlevel = (-0.5+node_water_level)*BS; valid_count = 1; break; } @@ -882,129 +1170,328 @@ void MapBlock::updateMesh(u32 daynight_ratio) { v3s16 dir = side_dirs[i]; - //float neighbor_level = neighbor_levels[dir]; - /*if(neighbor_level > -0.5*BS + 0.001) - continue;*/ - /*if(neighbor_level > water_level - 0.1*BS) - continue;*/ + /* + 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,-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,0,BS/2, 0,0,0, c, 0,1), + /*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, 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) + + /* + 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) { - vertices[0].Pos.Y = corner_levels[side_corners[i][1]]; - vertices[1].Pos.Y = corner_levels[side_corners[i][0]]; + for(u16 i=0; i<4; i++) + vertices[i].Pos.rotateXZBy(90); } - else + else if(j == 4) { - vertices[0].Pos.Y = -0.5*BS; - vertices[1].Pos.Y = -0.5*BS; + for(u16 i=0; i<4; i++) + vertices[i].Pos.rotateYZBy(-90); } - - for(s32 j=0; j<4; j++) + else if(j == 5) { - 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 + getPosRelative()); + for(u16 i=0; i<4; i++) + vertices[i].Pos.rotateYZBy(90); } - // 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_VERTEX_ALPHA; - material.setTexture(0, - g_irrlicht->getTexture(porting::getDataPath("water.png").c_str())); + 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, vertices, 4, indices, 6); + collector.append(material_leaves1, vertices, 4, indices, 6); } - - /* - Generate top side, if appropriate - */ - - if(top_is_water == false) + } + /* + 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,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,-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()), }; - for(s32 i=0; i<4; i++) + if(j == 0) { - //vertices[i].Pos.Y += water_level; - //vertices[i].Pos.Y += neighbor_levels[v3s16(0,0,0)]; - vertices[i].Pos.Y += corner_levels[i]; - vertices[i].Pos += intToFloat(p + getPosRelative()); + 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); } - // 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_VERTEX_ALPHA; - material.setTexture(0, - g_irrlicht->getTexture(porting::getDataPath("water.png").c_str())); + 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, vertices, 4, indices, 6); + collector.append(material_glass, vertices, 4, indices, 6); } } + + + } /* Add stuff from collector to mesh */ + scene::SMesh *mesh_new = NULL; + mesh_new = new scene::SMesh(); + collector.fillMesh(mesh_new); /* @@ -1023,18 +1510,172 @@ void MapBlock::updateMesh(u32 daynight_ratio) mesh_new = NULL; } - // Use VBO for mesh (this just would set this for ever buffer) - // This will lead to infinite memory usage because or irrlicht. - //mesh_new->setHardwareMappingHint(scene::EHM_STATIC); + 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 "<drop(); + mesh = NULL; + } + } +#endif + + 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]; + } +} + +void MapBlock::setNodeParent(v3s16 p, MapNode & n) +{ + if(isValidPosition(p) == false) + { + m_parent->setNode(getPosRelative() + p, n); + } + else + { + if(data == NULL) + throw InvalidPositionException(); + data[p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X] = n; + } +} + +MapNode MapBlock::getNodeParentNoEx(v3s16 p) +{ + if(isValidPosition(p) == false) + { + try{ + return m_parent->getNode(getPosRelative() + p); + } + catch(InvalidPositionException &e) + { + return MapNode(CONTENT_IGNORE); + } + } + else + { + if(data == NULL) + { + return MapNode(CONTENT_IGNORE); + } + return data[p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X]; + } +} + +#ifndef SERVER + +#if 1 +void MapBlock::updateMesh(u32 daynight_ratio) +{ +#if 0 + /* + DEBUG: If mesh has been generated, don't generate it again + */ + { + JMutexAutoLock meshlock(mesh_mutex); + if(mesh != NULL) + return; + } +#endif + + MeshMakeData data; + data.fill(daynight_ratio, this); - /*std::cout<<"MapBlock has "<getMeshBufferCount() - <<" materials (meshbuffers)"<= 0 && first_i <= DAYNIGHT_CACHE_COUNT); - updateMesh(first_i); - for(s32 i=0; i & light_sources, return block_below_is_valid; } + void MapBlock::copyTo(VoxelManipulator &dst) { v3s16 data_size(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE); VoxelArea data_area(v3s16(0,0,0), data_size - v3s16(1,1,1)); + // Copy from data to VoxelManipulator dst.copyFrom(data, data_area, v3s16(0,0,0), getPosRelative(), data_size); } -/*void getPseudoObjects(v3f origin, f32 max_d, - core::array &dest) +void MapBlock::copyFrom(VoxelManipulator &dst) { -}*/ + v3s16 data_size(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE); + VoxelArea data_area(v3s16(0,0,0), data_size - v3s16(1,1,1)); + + // Copy from VoxelManipulator to data + dst.copyTo(data, data_area, v3s16(0,0,0), + getPosRelative(), data_size); +} + void MapBlock::stepObjects(float dtime, bool server, u32 daynight_ratio) { /* Step objects */ m_objects.step(dtime, server, daynight_ratio); - + +#if 0 /* Spawn some objects at random. @@ -1343,12 +1979,13 @@ void MapBlock::stepObjects(float dtime, bool server, u32 daynight_ratio) if(getNode(p).d == CONTENT_AIR && getNode(p).getLightBlend(daynight_ratio) <= 11) { - RatObject *obj = new RatObject(NULL, -1, intToFloat(p)); + RatObject *obj = new RatObject(NULL, -1, intToFloat(p, BS)); addObject(obj); } } } } +#endif setChangedFlag(); } @@ -1503,9 +2140,11 @@ void MapBlock::serialize(std::ostream &os, u8 version) // First byte u8 flags = 0; if(is_underground) - flags |= 1; + flags |= 0x01; if(m_day_night_differs) - flags |= 2; + flags |= 0x02; + if(m_lighting_expired) + flags |= 0x04; os.write((char*)&flags, 1); u32 nodecount = MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; @@ -1539,6 +2178,34 @@ void MapBlock::serialize(std::ostream &os, u8 version) */ compress(databuf, os, version); + + /* + NodeMetadata + */ + if(version >= 14) + { + if(version <= 15) + { + try{ + std::ostringstream oss(std::ios_base::binary); + m_node_metadata.serialize(oss); + os<= 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<