diff options
author | Perttu Ahola <celeron55@gmail.com> | 2011-01-24 16:36:58 +0200 |
---|---|---|
committer | Perttu Ahola <celeron55@gmail.com> | 2011-01-24 16:36:58 +0200 |
commit | 3909e712a012c11793effc408fd348e438a9ac5b (patch) | |
tree | 237daebc0dd1e7053af50962d01d05a5630cff8e | |
parent | 87554408ca667bfb86a6472d4835a893e457c0ba (diff) | |
download | minetest-3909e712a012c11793effc408fd348e438a9ac5b.tar.gz minetest-3909e712a012c11793effc408fd348e438a9ac5b.tar.bz2 minetest-3909e712a012c11793effc408fd348e438a9ac5b.zip |
Faster lighting at map generation time
-rw-r--r-- | src/defaultsettings.cpp | 1 | ||||
-rw-r--r-- | src/main.cpp | 3 | ||||
-rw-r--r-- | src/map.cpp | 141 | ||||
-rw-r--r-- | src/map.h | 15 | ||||
-rw-r--r-- | src/player.cpp | 5 | ||||
-rw-r--r-- | src/server.cpp | 66 | ||||
-rw-r--r-- | src/voxel.cpp | 389 | ||||
-rw-r--r-- | src/voxel.h | 18 |
8 files changed, 605 insertions, 33 deletions
diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index 6cd242f01..4046b81b9 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -47,6 +47,7 @@ void set_default_settings() g_settings.setDefault("objectdata_interval", "0.2"); g_settings.setDefault("active_object_range", "2"); g_settings.setDefault("max_simultaneous_block_sends_per_client", "1"); + //g_settings.setDefault("max_simultaneous_block_sends_per_client", "2"); g_settings.setDefault("max_simultaneous_block_sends_server_total", "4"); g_settings.setDefault("max_block_send_distance", "6"); g_settings.setDefault("max_block_generate_distance", "6"); diff --git a/src/main.cpp b/src/main.cpp index 092d62988..d2f8a6b9d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -259,7 +259,8 @@ TODO: Remove HMParams TODO: Flowing water to actually contain flow direction information
-TODO: Faster lighting using VoxelManipulator
+TODO: Remove duplicate lighting implementation from Map (leave
+ VoxelManipulator)
Doing now:
----------
diff --git a/src/map.cpp b/src/map.cpp index 09fb154aa..bbcc0f36f 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -622,10 +622,13 @@ void Map::updateLighting(enum LightBank bank, core::map<v3s16, MapBlock*> & modified_blocks) { /*m_dout<<DTIME<<"Map::updateLighting(): " - <<a_blocks.getSize()<<" blocks... ";*/ + <<a_blocks.size()<<" blocks."<<std::endl;*/ + + //TimeTaker timer("updateLighting"); // For debugging - bool debug=false; + bool debug=true; + u32 count_was = modified_blocks.size(); core::map<v3s16, bool> light_sources; @@ -720,9 +723,10 @@ void Map::updateLighting(enum LightBank bank, } } - + +#if 0 { - //TimeTaker timer("unspreadLight"); + TimeTaker timer("unspreadLight"); unspreadLight(bank, unlight_from, light_sources, modified_blocks); } @@ -741,7 +745,7 @@ void Map::updateLighting(enum LightBank bank, // - Find out why it works { - //TimeTaker timer("spreadLight"); + TimeTaker timer("spreadLight"); spreadLight(bank, light_sources, modified_blocks); } @@ -751,6 +755,36 @@ void Map::updateLighting(enum LightBank bank, count_was = modified_blocks.size(); dstream<<"spreadLight modified "<<diff<<std::endl; } +#endif + + { + //MapVoxelManipulator vmanip(this); + + ManualMapVoxelManipulator vmanip(this); + + core::map<v3s16, MapBlock*>::Iterator i; + i = a_blocks.getIterator(); + for(; i.atEnd() == false; i++) + { + MapBlock *block = i.getNode()->getValue(); + v3s16 p = block->getPos(); + vmanip.initialEmerge(p - v3s16(1,1,1), p + v3s16(1,1,1)); + } + { + //TimeTaker timer("unSpreadLight"); + vmanip.unspreadLight(bank, unlight_from, light_sources); + } + { + //TimeTaker timer("spreadLight"); + vmanip.spreadLight(bank, light_sources); + } + { + //TimeTaker timer("blitBack"); + vmanip.blitBack(modified_blocks); + } + /*dstream<<"emerge_time="<<emerge_time<<std::endl; + emerge_time = 0;*/ + } //m_dout<<"Done ("<<getTimestamp()<<")"<<std::endl; } @@ -2220,7 +2254,8 @@ MapBlock * ServerMap::emergeBlock( } //dstream<<"Not found on disk, generating."<<std::endl; - //TimeTaker("emergeBlock()", g_irrlicht); + // 0ms + //TimeTaker("emergeBlock() generate"); /* Do not generate over-limit @@ -4138,7 +4173,10 @@ void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id) #endif #if 0 -void MapVoxelManipulator::emerge(VoxelArea a) +/* + NOTE: This is slow +*/ +void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id) { TimeTaker timer1("emerge", &emerge_time); @@ -4185,6 +4223,9 @@ void MapVoxelManipulator::blitBack return; //TimeTaker timer1("blitBack"); + + /*dstream<<"blitBack(): m_loaded_blocks.size()=" + <<m_loaded_blocks.size()<<std::endl;*/ /* Initialize block cache @@ -4241,4 +4282,90 @@ void MapVoxelManipulator::blitBack } } +ManualMapVoxelManipulator::ManualMapVoxelManipulator(Map *map): + MapVoxelManipulator(map) +{ +} + +ManualMapVoxelManipulator::~ManualMapVoxelManipulator() +{ +} + +void ManualMapVoxelManipulator::emerge(VoxelArea a, s32 caller_id) +{ + // Just create the area to avoid segfaults + VoxelManipulator::emerge(a, caller_id); + + /* + Just create the area to avoid segfaults + */ + /*addArea(a); + for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++) + for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++) + for(s32 x=a.MinEdge.X; x<=a.MaxEdge.X; x++) + { + s32 i = m_area.index(x,y,z); + // Don't touch nodes that have already been loaded + if(!(m_flags[i] & VOXELFLAG_NOT_LOADED)) + continue; + m_flags[i] = VOXELFLAG_INEXISTENT; + }*/ +} + +void ManualMapVoxelManipulator::initialEmerge( + v3s16 blockpos_min, v3s16 blockpos_max) +{ + TimeTaker timer1("emerge", &emerge_time); + + // Units of these are MapBlocks + v3s16 p_min = blockpos_min; + v3s16 p_max = blockpos_max; + + VoxelArea block_area_nodes + (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1)); + + addArea(block_area_nodes); + + for(s32 z=p_min.Z; z<=p_max.Z; z++) + for(s32 y=p_min.Y; y<=p_max.Y; y++) + for(s32 x=p_min.X; x<=p_max.X; x++) + { + v3s16 p(x,y,z); + core::map<v3s16, bool>::Node *n; + n = m_loaded_blocks.find(p); + if(n != NULL) + continue; + + bool block_data_inexistent = false; + try + { + TimeTaker timer1("emerge load", &emerge_load_time); + + MapBlock *block = m_map->getBlockNoCreate(p); + if(block->isDummy()) + block_data_inexistent = true; + else + block->copyTo(*this); + } + catch(InvalidPositionException &e) + { + block_data_inexistent = true; + } + + if(block_data_inexistent) + { + VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1)); + // Fill with VOXELFLAG_INEXISTENT + for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++) + for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++) + { + s32 i = m_area.index(a.MinEdge.X,y,z); + memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE); + } + } + + m_loaded_blocks.insert(p, true); + } +} + //END @@ -523,7 +523,7 @@ public: void blitBack(core::map<v3s16, MapBlock*> & modified_blocks); -private: +protected: Map *m_map; /* NOTE: This might be used or not @@ -534,5 +534,18 @@ private: core::map<v3s16, bool> m_loaded_blocks; }; +class ManualMapVoxelManipulator : public MapVoxelManipulator +{ +public: + ManualMapVoxelManipulator(Map *map); + virtual ~ManualMapVoxelManipulator(); + + virtual void emerge(VoxelArea a, s32 caller_id=-1); + + void initialEmerge(v3s16 blockpos_min, v3s16 blockpos_max); + +protected: +}; + #endif diff --git a/src/player.cpp b/src/player.cpp index bb25015b5..8aabb030c 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -412,8 +412,9 @@ void LocalPlayer::applyControl(float dtime) } else { - speed += move_direction; - superspeed = true; + // "Turbo button" + /*speed += move_direction; + superspeed = true;*/ } } diff --git a/src/server.cpp b/src/server.cpp index 65e390345..716ff77c6 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -168,7 +168,7 @@ void * EmergeThread::Thread() changed_blocks, lighting_invalidated_blocks); -#if 0 +#if 1 /* EXPERIMENTAL: Create a few other blocks too */ @@ -184,6 +184,19 @@ void * EmergeThread::Thread() only_from_disk, changed_blocks, lighting_invalidated_blocks); +#if 0 + map.emergeBlock( + p + v3s16(0,2,0), + only_from_disk, + changed_blocks, + lighting_invalidated_blocks); + + map.emergeBlock( + p + v3s16(0,-2,0), + only_from_disk, + changed_blocks, + lighting_invalidated_blocks); +#endif #endif } @@ -216,23 +229,6 @@ void * EmergeThread::Thread() dout_server<<std::endl; } -#if 0 - /* - Update water pressure - */ - - m_server->UpdateBlockWaterPressure(block, modified_blocks); - - for(core::map<v3s16, MapBlock*>::Iterator i = changed_blocks.getIterator(); - i.atEnd() == false; i++) - { - MapBlock *block = i.getNode()->getValue(); - m_server->UpdateBlockWaterPressure(block, modified_blocks); - //v3s16 p = i.getNode()->getKey(); - //m_server->UpdateBlockWaterPressure(p, modified_blocks); - } -#endif - /* Collect a list of blocks that have been modified in addition to the fetched one. @@ -249,7 +245,7 @@ void * EmergeThread::Thread() /*dstream<<"lighting "<<lighting_invalidated_blocks.size() <<" blocks"<<std::endl;*/ - //TimeTaker timer("** updateLighting", g_device); + //TimeTaker timer("** updateLighting"); // Update lighting without locking the environment mutex, // add modified blocks to changed blocks @@ -497,7 +493,8 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE) continue; - + + // If this is true, inexistent block will be made from scratch bool generate = d <= d_max_gen; if(haxmode) @@ -514,6 +511,35 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, } /* + If block is far away, don't generate it unless it is + near ground level + */ + if(d > 4) + { + v2s16 p2d(p.X, p.Z); + MapSector *sector = NULL; + try + { + sector = server->m_env.getMap().getSectorNoGenerate(p2d); + } + catch(InvalidPositionException &e) + { + } + + if(sector != NULL) + { + // Get center ground height in nodes + f32 gh = sector->getGroundHeight( + v2s16(MAP_BLOCKSIZE/2, MAP_BLOCKSIZE/2)); + // Block center y in nodes + f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2); + // If differs a lot, don't generate + if(fabs(gh - y) > MAP_BLOCKSIZE*2) + generate = false; + } + } + + /* Don't draw if not in sight */ diff --git a/src/voxel.cpp b/src/voxel.cpp index c045c949c..a0cc44d71 100644 --- a/src/voxel.cpp +++ b/src/voxel.cpp @@ -264,6 +264,395 @@ void VoxelManipulator::clearFlag(u8 flags) <<volume<<" nodes"<<std::endl;*/ } +void VoxelManipulator::unspreadLight(enum LightBank bank, v3s16 p, u8 oldlight, + core::map<v3s16, bool> & light_sources) +{ + 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 + }; + + emerge(VoxelArea(p - v3s16(1,1,1), p + v3s16(1,1,1))); + + // Loop through 6 neighbors + for(u16 i=0; i<6; i++) + { + // Get the position of the neighbor node + v3s16 n2pos = p + dirs[i]; + + u32 n2i = m_area.index(n2pos); + + if(m_flags[n2i] & VOXELFLAG_INEXISTENT) + continue; + + MapNode &n2 = m_data[n2i]; + + /* + If the neighbor is dimmer than what was specified + as oldlight (the light of the previous node) + */ + if(n2.getLight(bank) < oldlight) + { + /* + And the neighbor is transparent and it has some light + */ + if(n2.light_propagates() && n2.getLight(bank) != 0) + { + /* + Set light to 0 and add to queue + */ + + u8 current_light = n2.getLight(bank); + n2.setLight(bank, 0); + + unspreadLight(bank, n2pos, current_light, light_sources); + + /* + Remove from light_sources if it is there + NOTE: This doesn't happen nearly at all + */ + /*if(light_sources.find(n2pos)) + { + std::cout<<"Removed from light_sources"<<std::endl; + light_sources.remove(n2pos); + }*/ + } + } + else{ + light_sources.insert(n2pos, true); + } + } +} + +#if 1 +/* + Goes recursively through the neighbours of the node. + + Alters only transparent nodes. + + If the lighting of the neighbour is lower than the lighting of + the node was (before changing it to 0 at the step before), the + lighting of the neighbour is set to 0 and then the same stuff + repeats for the neighbour. + + The ending nodes of the routine are stored in light_sources. + This is useful when a light is removed. In such case, this + routine can be called for the light node and then again for + light_sources to re-light the area without the removed light. + + values of from_nodes are lighting values. +*/ +void VoxelManipulator::unspreadLight(enum LightBank bank, + core::map<v3s16, u8> & from_nodes, + core::map<v3s16, bool> & light_sources) +{ + if(from_nodes.size() == 0) + return; + + core::map<v3s16, u8>::Iterator j; + j = from_nodes.getIterator(); + + for(; j.atEnd() == false; j++) + { + v3s16 pos = j.getNode()->getKey(); + + //MapNode &n = m_data[m_area.index(pos)]; + + u8 oldlight = j.getNode()->getValue(); + + unspreadLight(bank, pos, oldlight, light_sources); + } +} +#endif + +#if 0 +/* + Goes recursively through the neighbours of the node. + + Alters only transparent nodes. + + If the lighting of the neighbour is lower than the lighting of + the node was (before changing it to 0 at the step before), the + lighting of the neighbour is set to 0 and then the same stuff + repeats for the neighbour. + + The ending nodes of the routine are stored in light_sources. + This is useful when a light is removed. In such case, this + routine can be called for the light node and then again for + light_sources to re-light the area without the removed light. + + values of from_nodes are lighting values. +*/ +void VoxelManipulator::unspreadLight(enum LightBank bank, + core::map<v3s16, u8> & from_nodes, + core::map<v3s16, bool> & light_sources) +{ + 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 + }; + + if(from_nodes.size() == 0) + return; + + core::map<v3s16, u8> unlighted_nodes; + core::map<v3s16, u8>::Iterator j; + j = from_nodes.getIterator(); + + for(; j.atEnd() == false; j++) + { + v3s16 pos = j.getNode()->getKey(); + + emerge(VoxelArea(pos - v3s16(1,1,1), pos + v3s16(1,1,1))); + + //MapNode &n = m_data[m_area.index(pos)]; + + u8 oldlight = j.getNode()->getValue(); + + // Loop through 6 neighbors + for(u16 i=0; i<6; i++) + { + // Get the position of the neighbor node + v3s16 n2pos = pos + dirs[i]; + + u32 n2i = m_area.index(n2pos); + + if(m_flags[n2i] & VOXELFLAG_INEXISTENT) + continue; + + MapNode &n2 = m_data[n2i]; + + /* + If the neighbor is dimmer than what was specified + as oldlight (the light of the previous node) + */ + if(n2.getLight(bank) < oldlight) + { + /* + And the neighbor is transparent and it has some light + */ + if(n2.light_propagates() && n2.getLight(bank) != 0) + { + /* + Set light to 0 and add to queue + */ + + u8 current_light = n2.getLight(bank); + n2.setLight(bank, 0); + + unlighted_nodes.insert(n2pos, current_light); + + /* + Remove from light_sources if it is there + NOTE: This doesn't happen nearly at all + */ + /*if(light_sources.find(n2pos)) + { + std::cout<<"Removed from light_sources"<<std::endl; + light_sources.remove(n2pos); + }*/ + } + } + else{ + light_sources.insert(n2pos, true); + } + } + } + + /*dstream<<"unspreadLight(): Changed block " + <<blockchangecount<<" times" + <<" for "<<from_nodes.size()<<" nodes" + <<std::endl;*/ + + if(unlighted_nodes.size() > 0) + unspreadLight(bank, unlighted_nodes, light_sources); +} +#endif + +void VoxelManipulator::spreadLight(enum LightBank bank, v3s16 p) +{ + const 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 + }; + + emerge(VoxelArea(p - v3s16(1,1,1), p + v3s16(1,1,1))); + + u32 i = m_area.index(p); + + if(m_flags[i] & VOXELFLAG_INEXISTENT) + return; + + MapNode &n = m_data[i]; + + u8 oldlight = n.getLight(bank); + u8 newlight = diminish_light(oldlight); + + // Loop through 6 neighbors + for(u16 i=0; i<6; i++) + { + // Get the position of the neighbor node + v3s16 n2pos = p + dirs[i]; + + u32 n2i = m_area.index(n2pos); + + if(m_flags[n2i] & VOXELFLAG_INEXISTENT) + continue; + + MapNode &n2 = m_data[n2i]; + + /* + If the neighbor is brighter than the current node, + add to list (it will light up this node on its turn) + */ + if(n2.getLight(bank) > undiminish_light(oldlight)) + { + spreadLight(bank, n2pos); + } + /* + If the neighbor is dimmer than how much light this node + would spread on it, add to list + */ + if(n2.getLight(bank) < newlight) + { + if(n2.light_propagates()) + { + n2.setLight(bank, newlight); + spreadLight(bank, n2pos); + } + } + } +} + +#if 1 +/* + Lights neighbors of from_nodes, collects all them and then + goes on recursively. +*/ +void VoxelManipulator::spreadLight(enum LightBank bank, + core::map<v3s16, bool> & from_nodes) +{ + if(from_nodes.size() == 0) + return; + + core::map<v3s16, bool> lighted_nodes; + core::map<v3s16, bool>::Iterator j; + j = from_nodes.getIterator(); + + for(; j.atEnd() == false; j++) + { + v3s16 pos = j.getNode()->getKey(); + + spreadLight(bank, pos); + } +} +#endif + +#if 0 +/* + Lights neighbors of from_nodes, collects all them and then + goes on recursively. +*/ +void VoxelManipulator::spreadLight(enum LightBank bank, + core::map<v3s16, bool> & from_nodes) +{ + const 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 + }; + + if(from_nodes.size() == 0) + return; + + core::map<v3s16, bool> lighted_nodes; + core::map<v3s16, bool>::Iterator j; + j = from_nodes.getIterator(); + + for(; j.atEnd() == false; j++) + { + v3s16 pos = j.getNode()->getKey(); + + emerge(VoxelArea(pos - v3s16(1,1,1), pos + v3s16(1,1,1))); + + u32 i = m_area.index(pos); + + if(m_flags[i] & VOXELFLAG_INEXISTENT) + continue; + + MapNode &n = m_data[i]; + + u8 oldlight = n.getLight(bank); + u8 newlight = diminish_light(oldlight); + + // Loop through 6 neighbors + for(u16 i=0; i<6; i++) + { + // Get the position of the neighbor node + v3s16 n2pos = pos + dirs[i]; + + try + { + u32 n2i = m_area.index(n2pos); + + if(m_flags[n2i] & VOXELFLAG_INEXISTENT) + continue; + + MapNode &n2 = m_data[n2i]; + + /* + If the neighbor is brighter than the current node, + add to list (it will light up this node on its turn) + */ + if(n2.getLight(bank) > undiminish_light(oldlight)) + { + lighted_nodes.insert(n2pos, true); + } + /* + If the neighbor is dimmer than how much light this node + would spread on it, add to list + */ + if(n2.getLight(bank) < newlight) + { + if(n2.light_propagates()) + { + n2.setLight(bank, newlight); + lighted_nodes.insert(n2pos, true); + } + } + } + catch(InvalidPositionException &e) + { + continue; + } + } + } + + /*dstream<<"spreadLight(): Changed block " + <<blockchangecount<<" times" + <<" for "<<from_nodes.size()<<" nodes" + <<std::endl;*/ + + if(lighted_nodes.size() > 0) + spreadLight(bank, lighted_nodes); +} +#endif + #if 0 int VoxelManipulator::getWaterPressure(v3s16 p, s16 &highest_y, int recur_count) { diff --git a/src/voxel.h b/src/voxel.h index c377dfe7a..80d292891 100644 --- a/src/voxel.h +++ b/src/voxel.h @@ -323,7 +323,11 @@ public: emerge(p); return !(m_flags[m_area.index(p)] & VOXELFLAG_INEXISTENT); }*/ - // These are a bit slow and shouldn't be used internally + + /* + These are a bit slow and shouldn't be used internally. + Use m_data[m_area.index(p)] instead. + */ MapNode getNode(v3s16 p) { emerge(p); @@ -396,7 +400,17 @@ public: */ void clearFlag(u8 flag); - + + void unspreadLight(enum LightBank bank, v3s16 p, u8 oldlight, + core::map<v3s16, bool> & light_sources); + void unspreadLight(enum LightBank bank, + core::map<v3s16, u8> & from_nodes, + core::map<v3s16, bool> & light_sources); + + void spreadLight(enum LightBank bank, v3s16 p); + void spreadLight(enum LightBank bank, + core::map<v3s16, bool> & from_nodes); + #if 0 // VOXELFLAG_CHECKED2s must usually be cleared before calling // -1: dead end, 0-255: pressure |