From 240499dc2c766c9d022e6df71e770a116a2c95de Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Sat, 18 Dec 2010 17:46:00 +0200 Subject: [PATCH] before daynight mesh cache --- src/client.cpp | 32 +++- src/client.h | 8 +- src/environment.cpp | 23 ++- src/environment.h | 8 + src/light.cpp | 2 +- src/light.h | 4 + src/map.cpp | 362 +++++++++++++++++++++++++------------------- src/map.h | 22 ++- src/mapblock.cpp | 52 ++++--- src/mapblock.h | 21 ++- src/mapnode.h | 69 ++++++++- src/test.cpp | 49 +++--- src/voxel.cpp | 4 +- 13 files changed, 441 insertions(+), 215 deletions(-) diff --git a/src/client.cpp b/src/client.cpp index f8644572..9fc9ebce 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -81,7 +81,9 @@ Client::Client(IrrlichtDevice *device, camera_direction(0,0,1), m_server_ser_ver(SER_FMT_VER_INVALID), m_step_dtime(0.0), - m_inventory_updated(false) + m_inventory_updated(false), + m_time(0), + m_time_counter(0.0) { //m_fetchblock_mutex.Init(); m_incoming_queue_mutex.Init(); @@ -142,6 +144,29 @@ void Client::step(float dtime) if(dtime > 2.0) dtime = 2.0; + /* + Day/night + */ + { + m_time_counter += dtime; + int seconds = (int)m_time_counter; + m_time_counter -= (float)seconds; + m_time += seconds; + if(seconds > 0) + { + dstream<<"m_time="<getKey(); - m_env->getMap().updateMeshes(p); + m_env->updateMeshes(p); } m_blocks.clear(); } @@ -236,6 +236,8 @@ public: // Prints a line or two of info void printDebugInfo(std::ostream &os); + + float getDaylightRatio(); private: @@ -284,6 +286,10 @@ private: core::map m_active_blocks; PacketCounter m_packetcounter; + + // Access these only in main thread. + u32 m_time; + float m_time_counter; }; #endif diff --git a/src/environment.cpp b/src/environment.cpp index 1f4223b2..d9d8b13a 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -24,6 +24,7 @@ Environment::Environment(Map *map, std::ostream &dout): m_dout(dout) { m_map = map; + m_daylight_ratio = 0.2; } Environment::~Environment() @@ -152,7 +153,7 @@ void Environment::step(float dtime) { v3s16 p_blocks = getNodeBlockPos(bottompos); MapBlock *b = m_map->getBlockNoCreate(p_blocks); - b->updateMesh(); + b->updateMesh(m_daylight_ratio); } } } @@ -240,3 +241,23 @@ void Environment::printPlayers(std::ostream &o) } } +void Environment::updateMeshes(v3s16 blockpos) +{ + m_map->updateMeshes(blockpos, m_daylight_ratio); +} + +void Environment::expireMeshes() +{ + m_map->expireMeshes(); +} + +void Environment::setDaylightRatio(u32 r) +{ + m_daylight_ratio = r; +} + +u32 Environment::getDaylightRatio() +{ + return m_daylight_ratio; +} + diff --git a/src/environment.h b/src/environment.h index ebc80ad1..6fdf6d33 100644 --- a/src/environment.h +++ b/src/environment.h @@ -49,6 +49,7 @@ public: void step(f32 dtime); Map & getMap(); + /* Environment deallocates players after use. */ @@ -58,11 +59,18 @@ public: Player * getPlayer(u16 peer_id); core::list getPlayers(); void printPlayers(std::ostream &o); + + void updateMeshes(v3s16 blockpos); + void expireMeshes(); + void setDaylightRatio(u32 r); + u32 getDaylightRatio(); + private: Map *m_map; core::list m_players; // Debug output goes here std::ostream &m_dout; + u32 m_daylight_ratio; }; #endif diff --git a/src/light.cpp b/src/light.cpp index 03821a67..73ca297c 100644 --- a/src/light.cpp +++ b/src/light.cpp @@ -19,7 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "light.h" -// LIGHT_MAX is 15, 0-15 is 16 values +// LIGHT_MAX is 14, 0-14 is 15 values /*u8 light_decode_table[LIGHT_MAX+1] = { 0, diff --git a/src/light.h b/src/light.h index 1827ab53..41d6f8bb 100644 --- a/src/light.h +++ b/src/light.h @@ -22,6 +22,10 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "common_irrlicht.h" +/* + Lower level lighting stuff +*/ + // This directly sets the range of light #define LIGHT_MAX 14 // Light is stored as 4 bits, thus 15 is the maximum. diff --git a/src/map.cpp b/src/map.cpp index 7b057840..80d41ce8 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -210,7 +210,8 @@ bool Map::isNodeUnderground(v3s16 p) values of from_nodes are lighting values. */ -void Map::unspreadLight(core::map & from_nodes, +void Map::unspreadLight(enum LightBank bank, + core::map & from_nodes, core::map & light_sources, core::map & modified_blocks) { @@ -310,19 +311,19 @@ void Map::unspreadLight(core::map & from_nodes, If the neighbor is dimmer than what was specified as oldlight (the light of the previous node) */ - if(n2.getLight() < oldlight) + if(n2.getLight(bank) < oldlight) { /* And the neighbor is transparent and it has some light */ - if(n2.light_propagates() && n2.getLight() != 0) + if(n2.light_propagates() && n2.getLight(bank) != 0) { /* Set light to 0 and add to queue */ - u8 current_light = n2.getLight(); - n2.setLight(0); + u8 current_light = n2.getLight(bank); + n2.setLight(bank, 0); block->setNode(relpos, n2); unlighted_nodes.insert(n2pos, current_light); @@ -371,27 +372,29 @@ void Map::unspreadLight(core::map & from_nodes, < 0) - unspreadLight(unlighted_nodes, light_sources, modified_blocks); + unspreadLight(bank, unlighted_nodes, light_sources, modified_blocks); } /* A single-node wrapper of the above */ -void Map::unLightNeighbors(v3s16 pos, u8 lightwas, +void Map::unLightNeighbors(enum LightBank bank, + v3s16 pos, u8 lightwas, core::map & light_sources, core::map & modified_blocks) { core::map from_nodes; from_nodes.insert(pos, lightwas); - unspreadLight(from_nodes, light_sources, modified_blocks); + unspreadLight(bank, from_nodes, light_sources, modified_blocks); } /* Lights neighbors of from_nodes, collects all them and then goes on recursively. */ -void Map::spreadLight(core::map & from_nodes, +void Map::spreadLight(enum LightBank bank, + core::map & from_nodes, core::map & modified_blocks) { const v3s16 dirs[6] = { @@ -452,7 +455,7 @@ void Map::spreadLight(core::map & from_nodes, // Get node straight from the block MapNode n = block->getNode(relpos); - u8 oldlight = n.getLight(); + u8 oldlight = n.getLight(bank); u8 newlight = diminish_light(oldlight); // Loop through 6 neighbors @@ -490,7 +493,7 @@ void Map::spreadLight(core::map & from_nodes, If the neighbor is brighter than the current node, add to list (it will light up this node on its turn) */ - if(n2.getLight() > undiminish_light(oldlight)) + if(n2.getLight(bank) > undiminish_light(oldlight)) { lighted_nodes.insert(n2pos, true); //lighted_nodes.push_back(n2pos); @@ -500,11 +503,11 @@ void Map::spreadLight(core::map & from_nodes, If the neighbor is dimmer than how much light this node would spread on it, add to list */ - if(n2.getLight() < newlight) + if(n2.getLight(bank) < newlight) { if(n2.light_propagates()) { - n2.setLight(newlight); + n2.setLight(bank, newlight); block->setNode(relpos, n2); lighted_nodes.insert(n2pos, true); //lighted_nodes.push_back(n2pos); @@ -536,21 +539,22 @@ void Map::spreadLight(core::map & from_nodes, < 0) - spreadLight(lighted_nodes, modified_blocks); + spreadLight(bank, lighted_nodes, modified_blocks); } /* A single-node source variation of the above. */ -void Map::lightNeighbors(v3s16 pos, +void Map::lightNeighbors(enum LightBank bank, + v3s16 pos, core::map & modified_blocks) { core::map from_nodes; from_nodes.insert(pos, true); - spreadLight(from_nodes, modified_blocks); + spreadLight(bank, from_nodes, modified_blocks); } -v3s16 Map::getBrightestNeighbour(v3s16 p) +v3s16 Map::getBrightestNeighbour(enum LightBank bank, v3s16 p) { v3s16 dirs[6] = { v3s16(0,0,1), // back @@ -577,8 +581,8 @@ v3s16 Map::getBrightestNeighbour(v3s16 p) { continue; } - if(n2.getLight() > brightest_light || found_something == false){ - brightest_light = n2.getLight(); + if(n2.getLight(bank) > brightest_light || found_something == false){ + brightest_light = n2.getLight(bank); brightest_pos = n2pos; found_something = true; } @@ -619,7 +623,7 @@ s16 Map::propagateSunlight(v3s16 start, if(n.sunlight_propagates()) { - n.setLight(LIGHT_SUN); + n.setLight(LIGHTBANK_DAY, LIGHT_SUN); block->setNode(relpos, n); modified_blocks.insert(blockpos, block); @@ -631,7 +635,8 @@ s16 Map::propagateSunlight(v3s16 start, return y + 1; } -void Map::updateLighting(core::map & a_blocks, +void Map::updateLighting(enum LightBank bank, + core::map & a_blocks, core::map & modified_blocks) { /*m_dout< & a_blocks, try{ v3s16 p(x,y,z); MapNode n = block->getNode(v3s16(x,y,z)); - u8 oldlight = n.getLight(); - n.setLight(0); + u8 oldlight = n.getLight(bank); + n.setLight(bank, 0); block->setNode(v3s16(x,y,z), n); // Collect borders for unlighting @@ -699,11 +704,22 @@ void Map::updateLighting(core::map & a_blocks, } } - bool bottom_valid = block->propagateSunlight(light_sources); + if(bank == LIGHTBANK_DAY) + { + bool bottom_valid = block->propagateSunlight(light_sources); - // If bottom is valid, we're done. - if(bottom_valid) + // If bottom is valid, we're done. + if(bottom_valid) + break; + } + else if(bank == LIGHTBANK_NIGHT) + { break; + } + else + { + assert(0); + } /*dstream<<"Bottom for sunlight-propagated block (" < & a_blocks, { //TimeTaker timer("unspreadLight", g_device); - unspreadLight(unlight_from, light_sources, modified_blocks); + unspreadLight(bank, unlight_from, light_sources, modified_blocks); } if(debug) @@ -744,7 +760,7 @@ void Map::updateLighting(core::map & a_blocks, { //TimeTaker timer("spreadLight", g_device); - spreadLight(light_sources, modified_blocks); + spreadLight(bank, light_sources, modified_blocks); } if(debug) @@ -757,6 +773,13 @@ void Map::updateLighting(core::map & a_blocks, //m_dout<<"Done ("< & a_blocks, + core::map & modified_blocks) +{ + updateLighting(LIGHTBANK_DAY, a_blocks, modified_blocks); + updateLighting(LIGHTBANK_NIGHT, a_blocks, modified_blocks); +} + /* This is called after changing a node from transparent to opaque. The lighting value of the node should be left as-is after changing @@ -771,12 +794,6 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n, m_dout< light_sources; - core::map light_sources; - //MapNode n = getNode(p); - /* From this node to nodes underneath: If lighting is sunlight (1.0), unlight neighbours and @@ -784,10 +801,11 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n, Else discontinue. */ - bool node_under_sunlight = true; - v3s16 toppos = p + v3s16(0,1,0); + bool node_under_sunlight = true; + core::map light_sources; + /* If there is a node at top and it doesn't have sunlight, there has not been any sunlight going down. @@ -797,36 +815,51 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n, try{ MapNode topnode = getNode(toppos); - if(topnode.getLight() != LIGHT_SUN) + if(topnode.getLight(LIGHTBANK_DAY) != LIGHT_SUN) node_under_sunlight = false; } catch(InvalidPositionException &e) { } - // Add the block of the added node to modified_blocks - v3s16 blockpos = getNodeBlockPos(p); - MapBlock * block = getBlockNoCreate(blockpos); - assert(block != NULL); - modified_blocks.insert(blockpos, block); - - if(isValidPosition(p) == false) - throw; + enum LightBank banks[] = + { + LIGHTBANK_DAY, + LIGHTBANK_NIGHT + }; + for(s32 i=0; i<2; i++) + { + enum LightBank bank = banks[i]; + + u8 lightwas = getNode(p).getLight(bank); + + // Add the block of the added node to modified_blocks + v3s16 blockpos = getNodeBlockPos(p); + MapBlock * block = getBlockNoCreate(blockpos); + assert(block != NULL); + modified_blocks.insert(blockpos, block); - // Unlight neighbours of node. - // This means setting light of all consequent dimmer nodes - // to 0. - // This also collects the nodes at the border which will spread - // light again into this. - unLightNeighbors(p, lightwas, light_sources, modified_blocks); - - n.setLight(0); + if(isValidPosition(p) == false) + throw; + + // Unlight neighbours of node. + // This means setting light of all consequent dimmer nodes + // to 0. + // This also collects the nodes at the border which will spread + // light again into this. + unLightNeighbors(bank, p, lightwas, light_sources, modified_blocks); + + n.setLight(bank, 0); + } + setNode(p, n); /* If node is under sunlight, take all sunlighted nodes under it and clear light from them and from where the light has been spread. + TODO: This could be optimized by mass-unlighting instead + of looping */ if(node_under_sunlight) { @@ -844,11 +877,13 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n, break; } - if(n2.getLight() == LIGHT_SUN) + if(n2.getLight(LIGHTBANK_DAY) == LIGHT_SUN) { //m_dout< neighbor_rankings; - - for(u32 i=0; i::Iterator - i = neighbor_rankings.getIterator(); - i.atEnd() == false; i++) - { - u8 m = i.getNode()->getKey(); - u8 c = i.getNode()->getValue(); - if( - c > highest_ranking || - // Prefer something else than air - (c >= highest_ranking && m != CONTENT_AIR) - - ) - { - replace_material = m; - highest_ranking = c; - } - } - } - -#endif - /* If there is a node at top and it doesn't have sunlight, there will be no sunlight going down. @@ -947,33 +926,50 @@ void Map::removeNodeAndUpdate(v3s16 p, try{ MapNode topnode = getNode(toppos); - if(topnode.getLight() != LIGHT_SUN) + if(topnode.getLight(LIGHTBANK_DAY) != LIGHT_SUN) node_under_sunlight = false; } catch(InvalidPositionException &e) { } - /* - Unlight neighbors (in case the node is a light source) - */ - //core::list light_sources; core::map light_sources; - unLightNeighbors(p, getNode(p).getLight(), - light_sources, modified_blocks); + + enum LightBank banks[] = + { + LIGHTBANK_DAY, + LIGHTBANK_NIGHT + }; + for(s32 i=0; i<2; i++) + { + enum LightBank bank = banks[i]; + + /* + Unlight neighbors (in case the node is a light source) + */ + unLightNeighbors(bank, p, + getNode(p).getLight(bank), + light_sources, modified_blocks); + } /* - Remove the node + Remove the node. + This also clears the lighting. */ + MapNode n; n.d = replace_material; - n.setLight(0); setNode(p, n); - /* - Recalculate lighting - */ - spreadLight(light_sources, modified_blocks); + for(s32 i=0; i<2; i++) + { + enum LightBank bank = banks[i]; + + /* + Recalculate lighting + */ + spreadLight(bank, light_sources, modified_blocks); + } // Add the block of the removed node to modified_blocks v3s16 blockpos = getNodeBlockPos(p); @@ -999,15 +995,16 @@ void Map::removeNodeAndUpdate(v3s16 p, /*m_dout<::Iterator si; + si = m_sectors.getIterator(); + for(; si.atEnd() == false; si++) { + MapSector *sector = si.getNode()->getValue(); + + core::list< MapBlock * > sectorblocks; + sector->getBlocks(sectorblocks); + + core::list< MapBlock * >::Iterator i; + for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++) + { + MapBlock *block = *i; + { + JMutexAutoLock lock(block->mesh_mutex); + if(block->mesh != NULL) + { + //block->mesh->drop(); + //block->mesh = NULL; + block->setMeshExpired(true); + } + } + } } } -void Map::updateMeshes(v3s16 blockpos) +void Map::updateMeshes(v3s16 blockpos, u32 daylight_factor) { assert(mapType() == MAPTYPE_CLIENT); try{ v3s16 p = blockpos + v3s16(0,0,0); MapBlock *b = getBlockNoCreate(p); - b->updateMesh(); + b->updateMesh(daylight_factor); } catch(InvalidPositionException &e){} try{ v3s16 p = blockpos + v3s16(-1,0,0); MapBlock *b = getBlockNoCreate(p); - b->updateMesh(); + b->updateMesh(daylight_factor); } catch(InvalidPositionException &e){} try{ v3s16 p = blockpos + v3s16(0,-1,0); MapBlock *b = getBlockNoCreate(p); - b->updateMesh(); + b->updateMesh(daylight_factor); } catch(InvalidPositionException &e){} try{ v3s16 p = blockpos + v3s16(0,0,-1); MapBlock *b = getBlockNoCreate(p); - b->updateMesh(); + b->updateMesh(daylight_factor); } catch(InvalidPositionException &e){} } @@ -1691,7 +1723,7 @@ MapBlock * ServerMap::emergeBlock( newly created block, they won't be taken into account. */ if(real_y > surface_y) - n.setLight(LIGHT_SUN); + n.setLight(LIGHTBANK_DAY, LIGHT_SUN); /* Calculate material @@ -1751,7 +1783,8 @@ MapBlock * ServerMap::emergeBlock( if(real_y < WATER_LEVEL) { n.d = water_material; - n.setLight(diminish_light(LIGHT_SUN, WATER_LEVEL-real_y+1)); + n.setLight(LIGHTBANK_DAY, + diminish_light(LIGHT_SUN, WATER_LEVEL-real_y+1)); } // else air else @@ -2732,11 +2765,13 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) u32 vertex_count = 0; - core::map::Iterator si; + // For limiting number of mesh updates per frame + u32 mesh_update_count = 0; //NOTE: The sectors map should be locked but we're not doing it // because it'd cause too much delays + core::map::Iterator si; si = m_sectors.getIterator(); for(; si.atEnd() == false; si++) { @@ -2837,11 +2872,34 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) /* Draw the faces of the block */ + + bool mesh_expired = false; + + { + JMutexAutoLock lock(block->mesh_mutex); + + mesh_expired = block->getMeshExpired(); + + // Mesh has not been expired and there is no mesh: + // block has no content + if(block->mesh == NULL && mesh_expired == false) + continue; + } + /* + This has to be done with the mesh_mutex unlocked + */ + if(mesh_expired && mesh_update_count < 1) + { + mesh_update_count++; + + // Mesh has been expired: generate new mesh + block->updateMesh(m_client->getDaylightRatio()); + } + { JMutexAutoLock lock(block->mesh_mutex); - // Cancel if block has no mesh if(block->mesh == NULL) continue; diff --git a/src/map.h b/src/map.h index 9ab77b25..41eadb08 100644 --- a/src/map.h +++ b/src/map.h @@ -333,25 +333,33 @@ public: blockref->setNode(relpos, n); }*/ - void unspreadLight(core::map & from_nodes, + void unspreadLight(enum LightBank bank, + core::map & from_nodes, core::map & light_sources, core::map & modified_blocks); - void unLightNeighbors(v3s16 pos, u8 lightwas, + void unLightNeighbors(enum LightBank bank, + v3s16 pos, u8 lightwas, core::map & light_sources, core::map & modified_blocks); - void spreadLight(core::map & from_nodes, + void spreadLight(enum LightBank bank, + core::map & from_nodes, core::map & modified_blocks); - void lightNeighbors(v3s16 pos, + void lightNeighbors(enum LightBank bank, + v3s16 pos, core::map & modified_blocks); - v3s16 getBrightestNeighbour(v3s16 p); + v3s16 getBrightestNeighbour(enum LightBank bank, v3s16 p); s16 propagateSunlight(v3s16 start, core::map & modified_blocks); + void updateLighting(enum LightBank bank, + core::map & a_blocks, + core::map & modified_blocks); + void updateLighting(core::map & a_blocks, core::map & modified_blocks); @@ -367,7 +375,9 @@ public: Updates the faces of the given block and blocks on the leading edge. */ - void updateMeshes(v3s16 blockpos); + void updateMeshes(v3s16 blockpos, u32 daylight_factor); + + void expireMeshes(); //core::aabbox3d getDisplayedBlockArea(); diff --git a/src/mapblock.cpp b/src/mapblock.cpp index 1afe0000..266587c1 100644 --- a/src/mapblock.cpp +++ b/src/mapblock.cpp @@ -147,20 +147,18 @@ FastFace * MapBlock::makeFastFace(TileSpec tile, u8 light, v3f p, If either of the nodes doesn't exist, light is 0. */ -u8 MapBlock::getFaceLight(v3s16 p, v3s16 face_dir) +u8 MapBlock::getFaceLight(u32 daylight_factor, v3s16 p, v3s16 face_dir) { try{ MapNode n = getNodeParent(p); MapNode n2 = getNodeParent(p + face_dir); u8 light; - /*if(n.solidness() < n2.solidness()) - light = n.getLight(); + u8 l1 = n.getLightBlend(daylight_factor); + u8 l2 = n2.getLightBlend(daylight_factor); + if(l1 > l2) + light = l1; else - light = n2.getLight();*/ - if(n.getLight() > n2.getLight()) - light = n.getLight(); - else - light = n2.getLight(); + light = l2; // Make some nice difference to different sides @@ -272,7 +270,9 @@ u8 MapBlock::getNodeContent(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 daylight_factor, + v3s16 startpos, u16 length, v3s16 translate_dir, v3s16 face_dir, @@ -292,7 +292,7 @@ void MapBlock::updateFastFaceRow(v3s16 startpos, /* Get face light at starting position */ - u8 light = getFaceLight(p, face_dir); + u8 light = getFaceLight(daylight_factor, p, face_dir); u16 continuous_tiles_count = 0; @@ -312,7 +312,7 @@ void MapBlock::updateFastFaceRow(v3s16 startpos, p_next = p + translate_dir; tile0_next = getNodeTile(p_next, face_dir); tile1_next = getNodeTile(p_next + face_dir, -face_dir); - light_next = getFaceLight(p_next, face_dir); + light_next = getFaceLight(daylight_factor, p_next, face_dir); if(tile0_next == tile0 && tile1_next == tile1 @@ -474,12 +474,13 @@ private: core::array m_prebuffers; }; -void MapBlock::updateMesh() +void MapBlock::updateMesh(u32 daylight_factor) { /*v3s16 p = getPosRelative(); std::cout<<"MapBlock("<getMeshBufferCount() <<" materials (meshbuffers)"<drop(); } } - + /* Do some stuff to the mesh */ @@ -693,6 +700,7 @@ void MapBlock::updateMesh() scene::SMesh *mesh_old = mesh; mesh = mesh_new; + setMeshExpired(false); if(mesh_old != NULL) { @@ -743,7 +751,7 @@ bool MapBlock::propagateSunlight(core::map & light_sources) // Check if node above block has sunlight try{ MapNode n = getNodeParent(v3s16(x, MAP_BLOCKSIZE, z)); - if(n.getLight() != LIGHT_SUN) + if(n.getLight(LIGHTBANK_DAY) != LIGHT_SUN) { /*if(is_underground) { @@ -789,7 +797,7 @@ bool MapBlock::propagateSunlight(core::map & light_sources) if(n.sunlight_propagates()) { - n.setLight(LIGHT_SUN); + n.setLight(LIGHTBANK_DAY, LIGHT_SUN); light_sources.insert(pos_relative + pos, true); } @@ -809,7 +817,7 @@ bool MapBlock::propagateSunlight(core::map & light_sources) if(n.light_propagates()) { - n.setLight(0); + n.setLight(LIGHTBANK_DAY, 0); } else{ break; @@ -831,10 +839,10 @@ bool MapBlock::propagateSunlight(core::map & light_sources) MapNode n = getNodeParent(v3s16(x, -1, z)); if(n.light_propagates()) { - if(n.getLight() == LIGHT_SUN + if(n.getLight(LIGHTBANK_DAY) == LIGHT_SUN && sunlight_should_go_down == false) block_below_is_valid = false; - else if(n.getLight() != LIGHT_SUN + else if(n.getLight(LIGHTBANK_DAY) != LIGHT_SUN && sunlight_should_go_down == true) block_below_is_valid = false; } diff --git a/src/mapblock.h b/src/mapblock.h index ebc2b52f..ff36e3a7 100644 --- a/src/mapblock.h +++ b/src/mapblock.h @@ -108,6 +108,7 @@ public: m_pos(pos), changed(true), is_underground(false), + m_mesh_expired(false), m_objects(this) //is_incomplete(false) { @@ -170,6 +171,16 @@ public: changed = true; } + void setMeshExpired(bool expired) + { + m_mesh_expired = expired; + } + + bool getMeshExpired() + { + return m_mesh_expired; + } + v3s16 getPos() { return m_pos; @@ -303,7 +314,7 @@ public: static FastFace * makeFastFace(TileSpec tile, u8 light, v3f p, v3s16 dir, v3f scale, v3f posRelative_f); - u8 getFaceLight(v3s16 p, v3s16 face_dir); + u8 getFaceLight(u32 daylight_factor, v3s16 p, v3s16 face_dir); TileSpec getNodeTile(v3s16 p, v3s16 face_dir); u8 getNodeContent(v3s16 p); @@ -313,13 +324,15 @@ public: 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(v3s16 startpos, + void updateFastFaceRow( + u32 daylight_factor, + v3s16 startpos, u16 length, v3s16 translate_dir, v3s16 face_dir, core::list &dest); - void updateMesh(); + void updateMesh(u32 daylight_factor); bool propagateSunlight(core::map & light_sources); @@ -464,6 +477,8 @@ private: At least /has been/ used. 8) */ bool is_underground; + + bool m_mesh_expired; MapBlockObjectList m_objects; diff --git a/src/mapnode.h b/src/mapnode.h index 73144201..0e746af4 100644 --- a/src/mapnode.h +++ b/src/mapnode.h @@ -280,6 +280,12 @@ inline u16 content_tile(u8 c, v3s16 dir) return g_content_tiles[c][dir_i]; } +enum LightBank +{ + LIGHTBANK_DAY, + LIGHTBANK_NIGHT +}; + struct MapNode { // Content @@ -352,24 +358,77 @@ struct MapNode return 0; } - u8 getLight() + u8 getLightBanksWithSource() + { + // Select the brightest of [light source, propagated light] + u8 lightday = 0; + u8 lightnight = 0; + if(light_propagates()) + { + lightday = param & 0x0f; + lightnight = (param>>4)&0x0f; + } + if(light_source() > lightday) + lightday = light_source(); + if(light_source() > lightnight) + lightnight = light_source(); + return (lightday&0x0f) | ((lightnight<<4)&0xf0); + } + + void setLightBanks(u8 a_light) + { + param = a_light; + } + + u8 getLight(enum LightBank bank) { // Select the brightest of [light source, propagated light] u8 light = 0; if(light_propagates()) - light = param & 0x0f; + { + if(bank == LIGHTBANK_DAY) + light = param & 0x0f; + else if(bank == LIGHTBANK_NIGHT) + light = (param>>4)&0x0f; + else + assert(0); + } if(light_source() > light) light = light_source(); return light; } + + // 0 <= daylight_factor <= 1000 + u8 getLightBlend(u32 daylight_factor) + { + u8 l = ((daylight_factor * getLight(LIGHTBANK_DAY) + + (1000-daylight_factor) * getLight(LIGHTBANK_NIGHT)) + )/1000; + u8 max = LIGHT_MAX; + if(getLight(LIGHTBANK_DAY) == LIGHT_SUN) + max = LIGHT_SUN; + if(l > max) + l = max; + return l; + } - void setLight(u8 a_light) + void setLight(enum LightBank bank, u8 a_light) { // If not transparent, can't set light if(light_propagates() == false) return; - param &= 0xf0; - param |= a_light; + if(bank == LIGHTBANK_DAY) + { + param &= 0xf0; + param |= a_light & 0x0f; + } + else if(bank == LIGHTBANK_NIGHT) + { + param &= 0x0f; + param |= (a_light & 0x0f)<<4; + } + else + assert(0); } u16 getTile(v3s16 dir) diff --git a/src/test.cpp b/src/test.cpp index 313fe50d..3ed64251 100644 --- a/src/test.cpp +++ b/src/test.cpp @@ -194,7 +194,8 @@ struct TestMapNode // Default values assert(n.d == CONTENT_AIR); - assert(n.getLight() == 0); + assert(n.getLight(LIGHTBANK_DAY) == 0); + assert(n.getLight(LIGHTBANK_NIGHT) == 0); // Transparency n.d = CONTENT_AIR; @@ -431,11 +432,13 @@ struct TestMapBlock // All nodes should have been set to // .d=CONTENT_AIR and .getLight() = 0 for(u16 z=0; z light_sources; // The bottom block is invalid, because we have a shadowing node assert(b.propagateSunlight(light_sources) == false); - assert(b.getNode(v3s16(1,4,0)).getLight() == LIGHT_SUN); - assert(b.getNode(v3s16(1,3,0)).getLight() == LIGHT_SUN); - assert(b.getNode(v3s16(1,2,0)).getLight() == 0); - assert(b.getNode(v3s16(1,1,0)).getLight() == 0); - assert(b.getNode(v3s16(1,0,0)).getLight() == 0); - assert(b.getNode(v3s16(1,2,3)).getLight() == LIGHT_SUN); - assert(b.getFaceLight(p, v3s16(0,1,0)) == LIGHT_SUN); - assert(b.getFaceLight(p, v3s16(0,-1,0)) == 0); + assert(b.getNode(v3s16(1,4,0)).getLight(LIGHTBANK_DAY) == LIGHT_SUN); + assert(b.getNode(v3s16(1,3,0)).getLight(LIGHTBANK_DAY) == LIGHT_SUN); + assert(b.getNode(v3s16(1,2,0)).getLight(LIGHTBANK_DAY) == 0); + assert(b.getNode(v3s16(1,1,0)).getLight(LIGHTBANK_DAY) == 0); + assert(b.getNode(v3s16(1,0,0)).getLight(LIGHTBANK_DAY) == 0); + assert(b.getNode(v3s16(1,2,3)).getLight(LIGHTBANK_DAY) == LIGHT_SUN); + assert(b.getFaceLight(1000, p, v3s16(0,1,0)) == LIGHT_SUN); + assert(b.getFaceLight(1000, p, v3s16(0,-1,0)) == 0); + assert(b.getFaceLight(0, p, v3s16(0,-1,0)) == 0); // According to MapBlock::getFaceLight, // The face on the z+ side should have double-diminished light //assert(b.getFaceLight(p, v3s16(0,0,1)) == diminish_light(diminish_light(LIGHT_MAX))); - assert(b.getFaceLight(p, v3s16(0,0,1)) == diminish_light(LIGHT_MAX)); + // The face on the z+ side should have diminished light + assert(b.getFaceLight(1000, p, v3s16(0,0,1)) == diminish_light(LIGHT_MAX)); } /* Check how the block handles being in between blocks with some non-sunlight @@ -533,7 +540,7 @@ struct TestMapBlock // Make neighbours to exist and set some non-sunlight to them parent.position_valid = true; b.setIsUnderground(true); - parent.node.setLight(LIGHT_MAX/2); + parent.node.setLight(LIGHTBANK_DAY, LIGHT_MAX/2); core::map light_sources; // The block below should be valid because there shouldn't be // sunlight in there either @@ -541,7 +548,7 @@ struct TestMapBlock // Should not touch nodes that are not affected (that is, all of them) //assert(b.getNode(v3s16(1,2,3)).getLight() == LIGHT_SUN); // Should set light of non-sunlighted blocks to 0. - assert(b.getNode(v3s16(1,2,3)).getLight() == 0); + assert(b.getNode(v3s16(1,2,3)).getLight(LIGHTBANK_DAY) == 0); } /* Set up a situation where: @@ -560,7 +567,7 @@ struct TestMapBlock for(u16 x=0; x light_sources; // Bottom block is not valid assert(b.propagateSunlight(light_sources) == false); diff --git a/src/voxel.cpp b/src/voxel.cpp index 6412957b..e94cba0f 100644 --- a/src/voxel.cpp +++ b/src/voxel.cpp @@ -734,12 +734,12 @@ bool VoxelManipulator::flowWater(v3s16 removed_pos, correctly. Otherwise unspreadLight will fuck up when water has replaced a light source. */ - u8 light = m_data[m_area.index(removed_pos)].getLight(); + u8 light = m_data[m_area.index(removed_pos)].getLightBanksWithSource(); m_data[m_area.index(removed_pos)].d = m; m_flags[m_area.index(removed_pos)] = f; - m_data[m_area.index(removed_pos)].setLight(light); + m_data[m_area.index(removed_pos)].setLightBanks(light); /*// NOTE: HACK: This has to be set to LIGHT_MAX so that // unspreadLight will clear all light that came from this node. -- 2.30.2