X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Fmapblock.cpp;h=63f33ffc0d2d0cedb4a3264a728ced5a70946c3b;hb=607f548712ae5a41eceb668085c87d10089849b9;hp=a4da657d1ede796156797e2eb315a52bb42ffc8a;hpb=fc26dcdb19dd4e296d850714019ed7da1de0b021;p=oweals%2Fminetest.git diff --git a/src/mapblock.cpp b/src/mapblock.cpp index a4da657d1..63f33ffc0 100644 --- a/src/mapblock.cpp +++ b/src/mapblock.cpp @@ -19,7 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "mapblock.h" #include "map.h" -// For g_materials +// For g_settings and g_irrlicht #include "main.h" #include "light.h" #include @@ -29,6 +29,46 @@ with this program; if not, write to the Free Software Foundation, Inc., 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() +{ +#ifndef SERVER + { + JMutexAutoLock lock(mesh_mutex); + + if(mesh) + { + mesh->drop(); + mesh = NULL; + } + } +#endif + + if(data) + delete[] data; +} + bool MapBlock::isValidPositionParent(v3s16 p) { if(isValidPosition(p)) @@ -68,10 +108,83 @@ void MapBlock::setNodeParent(v3s16 p, MapNode & n) } } -FastFace * MapBlock::makeFastFace(u8 material, u8 light, v3f p, - v3f dir, v3f scale, v3f posRelative_f) +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]; + } +} + +/* + 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 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 + + // 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; + } + catch(InvalidPositionException &e) + { + return 0; + } +} + +#ifndef SERVER + +void MapBlock::makeFastFace(TileSpec tile, u8 light, v3f p, + v3s16 dir, v3f scale, v3f posRelative_f, + core::array &dest) { - FastFace *f = new FastFace; + FastFace face; // Position is at the center of the cube. v3f pos = p * BS; @@ -80,19 +193,44 @@ FastFace * MapBlock::makeFastFace(u8 material, u8 light, v3f p, 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); - - /* - TODO: Rotate it the right way (one side comes upside down) - */ - core::CMatrix4 m; - m.buildRotateFromTo(v3f(0,0,1), dir); + 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); - for(u16 i=0; i<4; i++){ - m.rotateVect(vertex_pos[i]); + 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)) + { + for(u16 i=0; i<4; i++) + vertex_pos[i].rotateYZBy(90); + } + + for(u16 i=0; i<4; i++) + { vertex_pos[i].X *= scale.X; vertex_pos[i].Y *= scale.Y; vertex_pos[i].Z *= scale.Z; @@ -106,85 +244,145 @@ FastFace * MapBlock::makeFastFace(u8 material, u8 light, v3f p, v3f zerovector = v3f(0,0,0); - u8 li = decode_light(light); - //u8 li = 150; - - u8 alpha = 255; + //u8 li = decode_light(light); + u8 li = light; + //u8 li = 255; //DEBUG - if(material == MATERIAL_WATER) - { - alpha = 128; - } + u8 alpha = tile.alpha; + /*u8 alpha = 255; + if(tile.id == TILE_WATER) + alpha = WATER_ALPHA;*/ video::SColor c = video::SColor(alpha,li,li,li); - /*f->vertices[0] = video::S3DVertex(vertex_pos[0], zerovector, c, - core::vector2d(0,1)); - f->vertices[1] = video::S3DVertex(vertex_pos[1], zerovector, c, + face.vertices[0] = video::S3DVertex(vertex_pos[0], zerovector, c, core::vector2d(abs_scale,1)); - f->vertices[2] = video::S3DVertex(vertex_pos[2], zerovector, c, - core::vector2d(abs_scale,0)); - f->vertices[3] = video::S3DVertex(vertex_pos[3], zerovector, c, - core::vector2d(0,0));*/ - f->vertices[0] = video::S3DVertex(vertex_pos[0], zerovector, c, + face.vertices[1] = video::S3DVertex(vertex_pos[1], zerovector, c, core::vector2d(0,1)); - f->vertices[1] = video::S3DVertex(vertex_pos[1], zerovector, c, - core::vector2d(abs_scale,1)); - f->vertices[2] = video::S3DVertex(vertex_pos[2], zerovector, c, - core::vector2d(abs_scale,0)); - f->vertices[3] = video::S3DVertex(vertex_pos[3], zerovector, c, + face.vertices[2] = video::S3DVertex(vertex_pos[2], zerovector, c, core::vector2d(0,0)); - - f->material = material; - - return f; + face.vertices[3] = video::S3DVertex(vertex_pos[3], zerovector, c, + core::vector2d(abs_scale,0)); + + /*float x0 = (float)tile.tx/256.0; + float y0 = (float)tile.ty/256.0; + float w = ((float)tile.tw + 1.0)/256.0; + float h = ((float)tile.th + 1.0)/256.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; + + face.vertices[0] = video::S3DVertex(vertex_pos[0], zerovector, c, + core::vector2d(x0+w*abs_scale, y0+h)); + face.vertices[1] = video::S3DVertex(vertex_pos[1], zerovector, c, + core::vector2d(x0, y0+h)); + face.vertices[2] = video::S3DVertex(vertex_pos[2], zerovector, c, + core::vector2d(x0, y0)); + face.vertices[3] = video::S3DVertex(vertex_pos[3], zerovector, c, + 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. + Gets node tile from any place relative to block. + Returns TILE_NODE if doesn't exist or should not be drawn. */ -u8 MapBlock::getFaceLight(v3s16 p, v3s16 face_dir) +TileSpec MapBlock::getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir, + NodeModMap &temp_mods) { - try{ - MapNode n = getNodeParent(p); - MapNode n2 = getNodeParent(p + face_dir); - u8 light; - if(n.solidness() < n2.solidness()) - light = n.getLight(); - else - light = n2.getLight(); + TileSpec spec; + spec = mn.getTile(face_dir); + + /* + Check temporary modifications on this node + */ + /*core::map::Node *n; + n = m_temp_mods.find(p); + // If modified + if(n != NULL) + { + struct NodeMod mod = n->getValue();*/ + NodeMod mod; + if(temp_mods.get(p, &mod)) + { + if(mod.type == NODEMOD_CHANGECONTENT) + { + 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 + */ - // 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); + // Get original texture name + u32 orig_id = spec.texture.id; + std::string orig_name = g_texturesource->getTextureName(orig_id); - return light; - } - catch(InvalidPositionException &e) - { - return 0; + // Create new texture name + std::ostringstream os; + os<getTextureId(os.str()); + + /*dstream<<"MapBlock::getNodeTile(): Switching from " + <getTexture(new_id); + } } + + return spec; } -/* - Gets node material from any place relative to block. - Returns MATERIAL_AIR if doesn't exist. -*/ -u8 MapBlock::getNodeMaterial(v3s16 p) +u8 MapBlock::getNodeContent(v3s16 p, MapNode mn, NodeModMap &temp_mods) { - try{ - MapNode n = getNodeParent(p); - return n.d; - } - catch(InvalidPositionException &e) + /* + Check temporary modifications on this node + */ + /*core::map::Node *n; + n = m_temp_mods.find(p); + // If modified + if(n != NULL) + { + struct NodeMod mod = n->getValue();*/ + NodeMod mod; + if(temp_mods.get(p, &mod)) { - return MATERIAL_IGNORE; + if(mod.type == NODEMOD_CHANGECONTENT) + { + // Overrides content + return mod.param; + } + if(mod.type == NODEMOD_CRACK) + { + /* + Content doesn't change. + + face_contents works just like it should, because + there should not be faces between differently cracked + nodes. + + If a semi-transparent node is cracked in front an + another one, it really doesn't matter whether there + is a cracked face drawn in between or not. + */ + } } + + return mn.d; } /* @@ -192,105 +390,138 @@ u8 MapBlock::getNodeMaterial(v3s16 p) 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(v3s16 startpos, +void MapBlock::updateFastFaceRow( + u32 daynight_ratio, + v3f posRelative_f, + v3s16 startpos, u16 length, v3s16 translate_dir, + v3f translate_dir_f, v3s16 face_dir, - core::list &dest) + v3f face_dir_f, + core::array &dest, + NodeModMap &temp_mods) { - /* - Precalculate some variables - */ - v3f translate_dir_f(translate_dir.X, translate_dir.Y, - translate_dir.Z); // floating point conversion - v3f face_dir_f(face_dir.X, face_dir.Y, - face_dir.Z); // floating point conversion - v3f posRelative_f(getPosRelative().X, getPosRelative().Y, - getPosRelative().Z); // floating point conversion - v3s16 p = startpos; - /* - The light in the air lights the surface is taken from - the node that is air. - */ - u8 light = getFaceLight(p, face_dir); - u16 continuous_materials_count = 0; + u16 continuous_tiles_count = 0; - u8 material0 = getNodeMaterial(p); - u8 material1 = getNodeMaterial(p + face_dir); + 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, temp_mods); + TileSpec tile1 = getNodeTile(n1, p + face_dir, -face_dir, temp_mods); + for(u16 j=0; j m_prebuffers; }; -void MapBlock::updateMesh() +void MapBlock::updateMesh(u32 daynight_ratio) { - /*v3s16 p = getPosRelative(); - std::cout<<"MapBlock("< *fastfaces_new = new core::list; + { + JMutexAutoLock meshlock(mesh_mutex); + if(mesh != NULL) + return; + } +#endif - /* - We are including the faces of the trailing edges of the block. - This means that when something changes, the caller must - also update the meshes of the blocks at the leading edges. - */ + // 4-21ms for MAP_BLOCKSIZE=16 + // 24-155ms for MAP_BLOCKSIZE=32 + //TimeTaker timer1("updateMesh()"); + core::array fastfaces_new; + + v3f posRelative_f(getPosRelative().X, getPosRelative().Y, + getPosRelative().Z); // floating point conversion + /* - Go through every y,z and get top faces in rows of x+ + Avoid interlocks by copying m_temp_mods */ - for(s16 y=0; ygetSize() > 0) - { - MeshCollector collector; + // End of slow part + + /* + Convert FastFaces to SMesh + */ - core::list::Iterator i = fastfaces_new->begin(); + MeshCollector collector; - for(; i != fastfaces_new->end(); i++) + if(fastfaces_new.size() > 0) + { + // avg 0ms (100ms spikes when loading textures the first time) + //TimeTaker timer2("updateMesh() mesh building"); + + 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_ANTI_ALIASING, video::EAAM_SIMPLE); + material.setFlag(video::EMF_FOG_ENABLE, true); + + for(u32 i=0; igetTexture(f.tile.spec); + video::ITexture *texture = f.tile.texture.atlas; + if(texture == NULL) + continue; - collector.append(g_materials[f->material], f->vertices, 4, - indices, 6); + material.setTexture(0, texture); + + f.tile.applyMaterialOptions(material); + + collector.append(material, f.vertices, 4, indices, 6); } + } - mesh_new = new scene::SMesh(); + /* + Add special graphics: + - torches + - 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; + //TODO + //material_water1.setTexture(0, g_irrlicht->getTexture("water.png")); + 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; + //TODO + //material_leaves1.setTexture(0, g_irrlicht->getTexture("leaves.png")); + AtlasPointer pa_leaves1 = g_texturesource->getTexture( + g_texturesource->getTextureId("leaves.png")); + material_leaves1.setTexture(0, pa_leaves1.atlas); + + for(s16 z=0; z::Iterator i = fastfaces_new->begin(); + v3s16 dir = unpackDir(n.dir); - // MATERIAL_AIR shouldn't be used by any face - u8 material_in_use = MATERIAL_AIR; + 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()); + } - for(; i != fastfaces_new->end(); i++) + // 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); + } + /* + Add flowing water to mesh + */ + else if(n.d == CONTENT_WATER) { - FastFace *f = *i; + 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){} - if(f->material != material_in_use || buf == NULL) + u8 l = decode_light(n.getLightBlend(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++) { - // Try to get a meshbuffer associated with the material - buf = mesh_new->getMeshBuffer(g_materials[f->material]); - // If not found, create one - if(buf == NULL) - { - // This is a "Standard MeshBuffer", - // it's a typedeffed CMeshBuffer - buf = new scene::SMeshBuffer(); - // Set material - ((scene::SMeshBuffer*)buf)->Material = g_materials[f->material]; - // Use VBO - //buf->setHardwareMappingHint(scene::EHM_STATIC); - // Add to mesh - mesh_new->addMeshBuffer(buf); - // Mesh grabbed it - buf->drop(); - } - material_in_use = f->material; + u8 content = CONTENT_AIR; + float level = -0.5 * BS; + u8 flags = 0; + try{ + // Check neighbor + v3s16 p2 = p + neighbor_dirs[i]; + MapNode n2 = getNodeParent(p2); + + 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 = getNodeParent(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); } - - u16 new_indices[] = {0,1,2,2,3,0}; - - //buf->append(f->vertices, 4, indices, 6); - } -#endif - - // Use VBO for mesh (this just would set this for ever buffer) - //mesh_new->setHardwareMappingHint(scene::EHM_STATIC); - - /*std::cout<<"MapBlock has "<getSize()<<" faces " - <<"and uses "<getMeshBufferCount() - <<" materials (meshbuffers)"<::Iterator i; - i = fastfaces_new->begin(); - for(; i != fastfaces_new->end(); i++) - { - delete *i; - } - fastfaces_new->clear(); - delete fastfaces_new; - - /* - Replace the mesh - */ - mesh_mutex.Lock(); + //float water_level = (-0.5 + ((float)n.param2 + 0.5) / 8.0) * BS; + //float water_level = neighbor_levels[v3s16(0,0,0)]; - scene::SMesh *mesh_old = mesh; + // 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 + getPosRelative()); + } + + 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 + getPosRelative()); + } + + 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; + try{ + MapNode n = getNodeParent(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; + }catch(InvalidPositionException &e){} + + /*if(top_is_water == true) + continue;*/ + if(top_is_air == false) + continue; + + u8 l = decode_light(n.getLightBlend(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 + getPosRelative()); + } + + 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(daynight_ratio));*/ + u8 l = decode_light(undiminish_light(n.getLightBlend(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 + getPosRelative()); + } + + u16 indices[] = {0,1,2,2,3,0}; + // Add to mesh collector + collector.append(material_leaves1, vertices, 4, indices, 6); + } + } + } + + /* + 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 + */ + } + + /* + Replace the mesh + */ + + mesh_mutex.Lock(); + //scene::SMesh *mesh_old = mesh[daynight_i]; + //mesh[daynight_i] = mesh_new; + + scene::SMesh *mesh_old = mesh; mesh = mesh_new; + setMeshExpired(false); if(mesh_old != NULL) { @@ -547,8 +1314,20 @@ void MapBlock::updateMesh() { IMeshBuffer *buf = mesh_old->getMeshBuffer(i); }*/ + + /*dstream<<"mesh_old->getReferenceCount()=" + <getReferenceCount()<getMeshBufferCount(); + for(u32 i=0; igetMeshBuffer(i); + dstream<<"buf->getReferenceCount()=" + <getReferenceCount()<drop(); + //delete mesh_old; } @@ -557,6 +1336,20 @@ void MapBlock::updateMesh() //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; @@ -582,17 +1384,14 @@ bool MapBlock::propagateSunlight(core::map & light_sources) { for(s16 z=0; z & 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<<"("<d<