diff options
author | Perttu Ahola <celeron55@gmail.com> | 2010-12-18 17:46:00 +0200 |
---|---|---|
committer | Perttu Ahola <celeron55@gmail.com> | 2010-12-18 17:46:00 +0200 |
commit | 240499dc2c766c9d022e6df71e770a116a2c95de (patch) | |
tree | 3ae7c46b2ab20c226afb0d1ec5c6bddc80f33d48 /src | |
parent | 15a43c5ed02130f1b1e07a0385530da197b0c846 (diff) | |
download | minetest-240499dc2c766c9d022e6df71e770a116a2c95de.tar.gz minetest-240499dc2c766c9d022e6df71e770a116a2c95de.tar.bz2 minetest-240499dc2c766c9d022e6df71e770a116a2c95de.zip |
before daynight mesh cache
Diffstat (limited to 'src')
-rw-r--r-- | src/client.cpp | 32 | ||||
-rw-r--r-- | src/client.h | 8 | ||||
-rw-r--r-- | src/environment.cpp | 23 | ||||
-rw-r--r-- | src/environment.h | 8 | ||||
-rw-r--r-- | src/light.cpp | 2 | ||||
-rw-r--r-- | src/light.h | 4 | ||||
-rw-r--r-- | src/map.cpp | 362 | ||||
-rw-r--r-- | src/map.h | 22 | ||||
-rw-r--r-- | src/mapblock.cpp | 52 | ||||
-rw-r--r-- | src/mapblock.h | 21 | ||||
-rw-r--r-- | src/mapnode.h | 69 | ||||
-rw-r--r-- | src/test.cpp | 49 | ||||
-rw-r--r-- | src/voxel.cpp | 4 |
13 files changed, 441 insertions, 215 deletions
diff --git a/src/client.cpp b/src/client.cpp index f86445720..9fc9ebce6 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="<<m_time<<std::endl; + JMutexAutoLock envlock(m_env_mutex); + u32 dr = 500+500*sin((float)((m_time/10)%7)/7.*2.*PI); + if(dr != m_env.getDaylightRatio()) + { + dstream<<"dr="<<dr<<std::endl; + m_env.setDaylightRatio(dr); + m_env.expireMeshes(); + } + } + } + + //dstream<<"Client steps "<<dtime<<std::endl; { @@ -1755,4 +1780,9 @@ void Client::printDebugInfo(std::ostream &os) <<std::endl; } +float Client::getDaylightRatio() +{ + JMutexAutoLock envlock(m_env_mutex); + return m_env.getDaylightRatio(); +} diff --git a/src/client.h b/src/client.h index 70996cfef..413a936c6 100644 --- a/src/client.h +++ b/src/client.h @@ -133,7 +133,7 @@ public: i.atEnd() == false; i++) { v3s16 p = i.getNode()->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<v3s16, bool> 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 1f4223b23..d9d8b13ae 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 ebc80ad1a..6fdf6d33d 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<Player*> getPlayers(); void printPlayers(std::ostream &o); + + void updateMeshes(v3s16 blockpos); + void expireMeshes(); + void setDaylightRatio(u32 r); + u32 getDaylightRatio(); + private: Map *m_map; core::list<Player*> 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 03821a672..73ca297c7 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 1827ab53a..41d6f8bbe 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 7b057840d..80d41ce8f 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<v3s16, u8> & from_nodes, +void Map::unspreadLight(enum LightBank bank, + core::map<v3s16, u8> & from_nodes, core::map<v3s16, bool> & light_sources, core::map<v3s16, MapBlock*> & modified_blocks) { @@ -310,19 +311,19 @@ void Map::unspreadLight(core::map<v3s16, u8> & 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<v3s16, u8> & from_nodes, <<std::endl;*/ if(unlighted_nodes.size() > 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<v3s16, bool> & light_sources, core::map<v3s16, MapBlock*> & modified_blocks) { core::map<v3s16, u8> 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<v3s16, bool> & from_nodes, +void Map::spreadLight(enum LightBank bank, + core::map<v3s16, bool> & from_nodes, core::map<v3s16, MapBlock*> & modified_blocks) { const v3s16 dirs[6] = { @@ -452,7 +455,7 @@ void Map::spreadLight(core::map<v3s16, bool> & 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<v3s16, bool> & 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<v3s16, bool> & 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<v3s16, bool> & from_nodes, <<std::endl;*/ if(lighted_nodes.size() > 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<v3s16, MapBlock*> & modified_blocks) { core::map<v3s16, bool> 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<v3s16, MapBlock*> & a_blocks, +void Map::updateLighting(enum LightBank bank, + core::map<v3s16, MapBlock*> & a_blocks, core::map<v3s16, MapBlock*> & modified_blocks) { /*m_dout<<DTIME<<"Map::updateLighting(): " @@ -671,8 +676,8 @@ void Map::updateLighting(core::map<v3s16, MapBlock*> & 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<v3s16, MapBlock*> & 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 (" <<pos.X<<","<<pos.Y<<","<<pos.Z<<") not valid" @@ -725,7 +741,7 @@ void Map::updateLighting(core::map<v3s16, MapBlock*> & 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<v3s16, MapBlock*> & 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<v3s16, MapBlock*> & a_blocks, //m_dout<<"Done ("<<getTimestamp()<<")"<<std::endl; } +void Map::updateLighting(core::map<v3s16, MapBlock*> & a_blocks, + core::map<v3s16, MapBlock*> & 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<<DTIME<<"Map::nodeAddedUpdate(): p=(" <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/ - u8 lightwas = getNode(p).getLight(); - - //core::list<v3s16> light_sources; - core::map<v3s16, bool> 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<v3s16, bool> 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<<DTIME<<"doing"<<std::endl; - unLightNeighbors(n2pos, n2.getLight(), light_sources, modified_blocks); - n2.setLight(0); + unLightNeighbors(LIGHTBANK_DAY, + n2pos, n2.getLight(LIGHTBANK_DAY), + light_sources, modified_blocks); + n2.setLight(LIGHTBANK_DAY, 0); setNode(n2pos, n2); } else @@ -856,11 +891,16 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n, } } - /* - Spread light from all nodes that might be capable of doing so - TODO: Convert to spreadLight - */ - spreadLight(light_sources, modified_blocks); + for(s32 i=0; i<2; i++) + { + enum LightBank bank = banks[i]; + + /* + Spread light from all nodes that might be capable of doing so + TODO: Convert to spreadLight + */ + spreadLight(bank, light_sources, modified_blocks); + } } /* @@ -879,67 +919,6 @@ void Map::removeNodeAndUpdate(v3s16 p, // Node will be replaced with this u8 replace_material = CONTENT_AIR; - // NOTE: Water is now managed elsewhere -#if 0 - { - /* - Find out with what material the node will be replaced. - It will be replaced with the mostly seen buildable_to. - */ - - v3s16 dirs[6] = { - v3s16(0,0,1), // back - v3s16(0,1,0), // top - v3s16(1,0,0), // right - v3s16(0,0,-1), // front - v3s16(0,-1,0), // bottom - v3s16(-1,0,0), // left - }; - - core::map<u8, u16> neighbor_rankings; - - for(u32 i=0; i<sizeof(dirs)/sizeof(dirs[0]); i++) - { - try{ - MapNode n2 = getNode(p + dirs[i]); - - if(material_buildable_to(n2.d)) - { - if(neighbor_rankings.find(n2.d) == NULL) - neighbor_rankings[n2.d] = 1; - else - neighbor_rankings[n2.d] - = neighbor_rankings[n2.d] + 1; - } - } - catch(InvalidPositionException &e) - { - } - } - - u16 highest_ranking = 0; - - for(core::map<u8, u16>::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<v3s16> light_sources; core::map<v3s16, bool> 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<<DTIME<<"lighting neighbors of node (" <<p2.X<<","<<p2.Y<<","<<p2.Z<<")" <<std::endl;*/ - lightNeighbors(p2, modified_blocks); + lightNeighbors(LIGHTBANK_DAY, p2, modified_blocks); } } else { // Set the lighting of this node to 0 + // TODO: Is this needed? Lighting is cleared up there already. try{ MapNode n = getNode(p); - n.setLight(0); + n.setLight(LIGHTBANK_DAY, 0); setNode(p, n); } catch(InvalidPositionException &e) @@ -1016,43 +1013,78 @@ void Map::removeNodeAndUpdate(v3s16 p, } } - // Get the brightest neighbour node and propagate light from it - v3s16 n2p = getBrightestNeighbour(p); - try{ - MapNode n2 = getNode(n2p); - lightNeighbors(n2p, modified_blocks); + for(s32 i=0; i<2; i++) + { + enum LightBank bank = banks[i]; + + // Get the brightest neighbour node and propagate light from it + v3s16 n2p = getBrightestNeighbour(bank, p); + try{ + MapNode n2 = getNode(n2p); + lightNeighbors(bank, n2p, modified_blocks); + } + catch(InvalidPositionException &e) + { + } } - catch(InvalidPositionException &e) +} + +void Map::expireMeshes() +{ + TimeTaker timer("expireMeshes()", g_device); + + core::map<v2s16, MapSector*>::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<v2s16, MapSector*>::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<v2s16, MapSector*>::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; @@ -333,25 +333,33 @@ public: blockref->setNode(relpos, n); }*/ - void unspreadLight(core::map<v3s16, u8> & from_nodes, + void unspreadLight(enum LightBank bank, + core::map<v3s16, u8> & from_nodes, core::map<v3s16, bool> & light_sources, core::map<v3s16, MapBlock*> & modified_blocks); - void unLightNeighbors(v3s16 pos, u8 lightwas, + void unLightNeighbors(enum LightBank bank, + v3s16 pos, u8 lightwas, core::map<v3s16, bool> & light_sources, core::map<v3s16, MapBlock*> & modified_blocks); - void spreadLight(core::map<v3s16, bool> & from_nodes, + void spreadLight(enum LightBank bank, + core::map<v3s16, bool> & from_nodes, core::map<v3s16, MapBlock*> & modified_blocks); - void lightNeighbors(v3s16 pos, + void lightNeighbors(enum LightBank bank, + v3s16 pos, core::map<v3s16, MapBlock*> & modified_blocks); - v3s16 getBrightestNeighbour(v3s16 p); + v3s16 getBrightestNeighbour(enum LightBank bank, v3s16 p); s16 propagateSunlight(v3s16 start, core::map<v3s16, MapBlock*> & modified_blocks); + void updateLighting(enum LightBank bank, + core::map<v3s16, MapBlock*> & a_blocks, + core::map<v3s16, MapBlock*> & modified_blocks); + void updateLighting(core::map<v3s16, MapBlock*> & a_blocks, core::map<v3s16, MapBlock*> & 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<s16> getDisplayedBlockArea(); diff --git a/src/mapblock.cpp b/src/mapblock.cpp index 1afe00001..266587c12 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<PreMeshBuffer> m_prebuffers; }; -void MapBlock::updateMesh() +void MapBlock::updateMesh(u32 daylight_factor) { /*v3s16 p = getPosRelative(); std::cout<<"MapBlock("<<p.X<<","<<p.Y<<","<<p.Z<<")" <<"::updateMesh(): ";*/ //<<"::updateMesh()"<<std::endl; + TimeTaker timer1("updateMesh()", g_device); /* TODO: Change this to directly generate the mesh (and get rid @@ -492,6 +493,9 @@ void MapBlock::updateMesh() 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. + + NOTE: This is the slowest part of this method. The other parts + take around 0ms, this takes around 15-70ms. */ /* @@ -500,7 +504,8 @@ void MapBlock::updateMesh() for(s16 y=0; y<MAP_BLOCKSIZE; y++){ //for(s16 y=-1; y<MAP_BLOCKSIZE; y++){ for(s16 z=0; z<MAP_BLOCKSIZE; z++){ - updateFastFaceRow(v3s16(0,y,z), MAP_BLOCKSIZE, + updateFastFaceRow(daylight_factor, + v3s16(0,y,z), MAP_BLOCKSIZE, v3s16(1,0,0), v3s16(0,1,0), *fastfaces_new); @@ -512,7 +517,8 @@ void MapBlock::updateMesh() for(s16 x=0; x<MAP_BLOCKSIZE; x++){ //for(s16 x=-1; x<MAP_BLOCKSIZE; x++){ for(s16 y=0; y<MAP_BLOCKSIZE; y++){ - updateFastFaceRow(v3s16(x,y,0), MAP_BLOCKSIZE, + updateFastFaceRow(daylight_factor, + v3s16(x,y,0), MAP_BLOCKSIZE, v3s16(0,0,1), v3s16(1,0,0), *fastfaces_new); @@ -524,7 +530,8 @@ void MapBlock::updateMesh() for(s16 z=0; z<MAP_BLOCKSIZE; z++){ //for(s16 z=-1; z<MAP_BLOCKSIZE; z++){ for(s16 y=0; y<MAP_BLOCKSIZE; y++){ - updateFastFaceRow(v3s16(0,y,z), MAP_BLOCKSIZE, + updateFastFaceRow(daylight_factor, + v3s16(0,y,z), MAP_BLOCKSIZE, v3s16(1,0,0), v3s16(0,0,1), *fastfaces_new); @@ -568,7 +575,7 @@ void MapBlock::updateMesh() <<"and uses "<<mesh_new->getMeshBufferCount() <<" materials (meshbuffers)"<<std::endl;*/ } - + /* Clear temporary FastFaces */ @@ -667,7 +674,7 @@ void MapBlock::updateMesh() buf->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<v3s16, bool> & 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<v3s16, bool> & 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<v3s16, bool> & 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<v3s16, bool> & 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 ebc2b52ff..ff36e3a7d 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<FastFace*> &dest); - void updateMesh(); + void updateMesh(u32 daylight_factor); bool propagateSunlight(core::map<v3s16, bool> & 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 731442011..0e746af48 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 313fe50db..3ed642512 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<MAP_BLOCKSIZE; z++) - for(u16 y=0; y<MAP_BLOCKSIZE; y++) - for(u16 x=0; x<MAP_BLOCKSIZE; x++){ - assert(b.getNode(v3s16(x,y,z)).d == CONTENT_AIR); - assert(b.getNode(v3s16(x,y,z)).getLight() == 0); - } + for(u16 y=0; y<MAP_BLOCKSIZE; y++) + for(u16 x=0; x<MAP_BLOCKSIZE; x++) + { + assert(b.getNode(v3s16(x,y,z)).d == CONTENT_AIR); + assert(b.getNode(v3s16(x,y,z)).getLight(LIGHTBANK_DAY) == 0); + assert(b.getNode(v3s16(x,y,z)).getLight(LIGHTBANK_NIGHT) == 0); + } /* Parent fetch functions @@ -496,7 +499,8 @@ struct TestMapBlock for(u16 y=0; y<MAP_BLOCKSIZE; y++){ for(u16 x=0; x<MAP_BLOCKSIZE; x++){ MapNode n = b.getNode(v3s16(x,y,z)); - n.setLight(0); + n.setLight(LIGHTBANK_DAY, 0); + n.setLight(LIGHTBANK_NIGHT, 0); b.setNode(v3s16(x,y,z), n); } } @@ -508,22 +512,25 @@ struct TestMapBlock parent.position_valid = true; b.setIsUnderground(false); parent.node.d = CONTENT_AIR; - parent.node.setLight(LIGHT_SUN); + parent.node.setLight(LIGHTBANK_DAY, LIGHT_SUN); + parent.node.setLight(LIGHTBANK_NIGHT, 0); core::map<v3s16, bool> 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<v3s16, bool> 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<MAP_BLOCKSIZE; x++){ MapNode n; n.d = CONTENT_AIR; - n.setLight(0); + n.setLight(LIGHTBANK_DAY, 0); b.setNode(v3s16(x,y,z), n); } } @@ -574,7 +581,7 @@ struct TestMapBlock parent.validity_exceptions.push_back(v3s16(MAP_BLOCKSIZE+x, MAP_BLOCKSIZE-1, MAP_BLOCKSIZE+z)); } // Lighting value for the valid nodes - parent.node.setLight(LIGHT_MAX/2); + parent.node.setLight(LIGHTBANK_DAY, LIGHT_MAX/2); core::map<v3s16, bool> light_sources; // Bottom block is not valid assert(b.propagateSunlight(light_sources) == false); diff --git a/src/voxel.cpp b/src/voxel.cpp index 6412957b2..e94cba0f6 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. |