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/voxel.cpp | 389 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 389 insertions(+) (limited to 'src/voxel.cpp') 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) { -- cgit v1.2.3