From 3909e712a012c11793effc408fd348e438a9ac5b Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Mon, 24 Jan 2011 16:36:58 +0200 Subject: Faster lighting at map generation time --- src/defaultsettings.cpp | 1 + src/main.cpp | 3 +- src/map.cpp | 141 +++++++++++++++++- src/map.h | 15 +- src/player.cpp | 5 +- src/server.cpp | 66 +++++--- src/voxel.cpp | 389 ++++++++++++++++++++++++++++++++++++++++++++++++ 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 & modified_blocks) { /*m_dout< 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 "<::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="<::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 diff --git a/src/map.h b/src/map.h index 3b6b169e5..787e1240f 100644 --- a/src/map.h +++ b/src/map.h @@ -523,7 +523,7 @@ public: void blitBack(core::map & modified_blocks); -private: +protected: Map *m_map; /* NOTE: This might be used or not @@ -534,5 +534,18 @@ private: core::map 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<UpdateBlockWaterPressure(block, modified_blocks); - - for(core::map::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 "< 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) @@ -513,6 +510,35 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, generate = false; } + /* + 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) < & 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"< & from_nodes, + core::map & light_sources) +{ + if(from_nodes.size() == 0) + return; + + core::map::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 & from_nodes, + core::map & 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 unlighted_nodes; + core::map::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"< 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 & from_nodes) +{ + if(from_nodes.size() == 0) + return; + + core::map lighted_nodes; + core::map::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 & 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 lighted_nodes; + core::map::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 " + < 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 & light_sources); + void unspreadLight(enum LightBank bank, + core::map & from_nodes, + core::map & light_sources); + + void spreadLight(enum LightBank bank, v3s16 p); + void spreadLight(enum LightBank bank, + core::map & from_nodes); + #if 0 // VOXELFLAG_CHECKED2s must usually be cleared before calling // -1: dead end, 0-255: pressure -- cgit v1.2.3