From be39f61359ad63f2c6d4aea14c1dfd8357eee03f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Juh=C3=A1sz?= Date: Sun, 23 Oct 2016 17:51:13 +0200 Subject: [PATCH] Use node lighting for liquid spreading This commit modifies the liquid transforming procedure to light and unlight nodes instead of whole map blocks. --- src/map.cpp | 23 +++- src/voxelalgorithms.cpp | 229 +++++++++++++++++++++------------------- src/voxelalgorithms.h | 13 +-- 3 files changed, 144 insertions(+), 121 deletions(-) diff --git a/src/map.cpp b/src/map.cpp index 1694582dbffe..5a1611c8940f 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -824,10 +824,15 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n, } // Set the node on the map + // Ignore light (because calling voxalgo::update_lighting_nodes) + n.setLight(LIGHTBANK_DAY, 0, ndef); + n.setLight(LIGHTBANK_NIGHT, 0, ndef); setNode(p, n); // Update lighting - voxalgo::update_lighting_node(this, ndef, p, oldnode, modified_blocks); + std::vector > oldnodes; + oldnodes.push_back(std::pair(p, oldnode)); + voxalgo::update_lighting_nodes(this, ndef, oldnodes, modified_blocks); for(std::map::iterator i = modified_blocks.begin(); @@ -1224,7 +1229,9 @@ void Map::transformLiquids(std::map &modified_blocks) std::deque must_reflow; // List of MapBlocks that will require a lighting update (due to lava) - std::map lighting_modified_blocks; + std::map lighting_modified_blocks2; + + std::vector > changed_nodes; u32 liquid_loop_max = g_settings->getS32("liquid_loop_max"); u32 loop_max = liquid_loop_max; @@ -1457,6 +1464,10 @@ void Map::transformLiquids(std::map &modified_blocks) } n0.setContent(new_node_content); + // Ignore light (because calling voxalgo::update_lighting_nodes) + n0.setLight(LIGHTBANK_DAY, 0, nodemgr); + n0.setLight(LIGHTBANK_NIGHT, 0, nodemgr); + // Find out whether there is a suspect for this action std::string suspect; if (m_gamedef->rollback()) @@ -1484,9 +1495,10 @@ void Map::transformLiquids(std::map &modified_blocks) if (block != NULL) { modified_blocks[blockpos] = block; // If new or old node emits light, MapBlock requires lighting update - if (nodemgr->get(n0).light_source != 0 || + /*if (nodemgr->get(n0).light_source != 0 || nodemgr->get(n00).light_source != 0) - lighting_modified_blocks[block->getPos()] = block; + lighting_modified_blocks[block->getPos()] = block;*/ + changed_nodes.push_back(std::pair(p0, n00)); } /* @@ -1515,7 +1527,8 @@ void Map::transformLiquids(std::map &modified_blocks) for (std::deque::iterator iter = must_reflow.begin(); iter != must_reflow.end(); ++iter) m_transforming_liquid.push_back(*iter); - updateLighting(lighting_modified_blocks, modified_blocks); + //updateLighting(lighting_modified_blocks, modified_blocks); + voxalgo::update_lighting_nodes(this, nodemgr, changed_nodes, modified_blocks); /* ---------------------------------------------------------------------- diff --git a/src/voxelalgorithms.cpp b/src/voxelalgorithms.cpp index 019ec1bc6ffc..83c1dd4ca570 100644 --- a/src/voxelalgorithms.cpp +++ b/src/voxelalgorithms.cpp @@ -583,144 +583,153 @@ bool isSunlightAbove(Map *map, v3s16 pos, INodeDefManager *ndef) static const LightBank banks[] = { LIGHTBANK_DAY, LIGHTBANK_NIGHT }; -void update_lighting_node(Map *map, INodeDefManager *ndef, v3s16 p, - MapNode oldnode, std::map & modified_blocks) +void update_lighting_nodes(Map *map, INodeDefManager *ndef, + std::vector > &oldnodes, + std::map & modified_blocks) { // For node getter functions bool is_valid_position; - // Get position and block of the changed node - relative_v3 rel_pos; - mapblock_v3 block_pos; - getNodeBlockPosWithOffset(p, block_pos, rel_pos); - MapBlock *block = map->getBlockNoCreateNoEx(block_pos); - if (block == NULL || block->isDummy()) { - return; - } - // Process each light bank separately for (s32 i = 0; i < 2; i++) { - // Get the new node - MapNode n = block->getNodeNoCheck(rel_pos, &is_valid_position); - if (!is_valid_position) { - break; - } LightBank bank = banks[i]; + UnlightQueue disappearing_lights(256); + ReLightQueue light_sources(256); + // For each changed node process sunlight and initialize + for (std::vector >::iterator it = + oldnodes.begin(); it < oldnodes.end(); it++) { + // Get position and block of the changed node + v3s16 p = it->first; + relative_v3 rel_pos; + mapblock_v3 block_pos; + getNodeBlockPosWithOffset(p, block_pos, rel_pos); + MapBlock *block = map->getBlockNoCreateNoEx(block_pos); + if (block == NULL || block->isDummy()) { + continue; + } + // Get the new node + MapNode n = block->getNodeNoCheck(rel_pos, &is_valid_position); + if (!is_valid_position) { + break; + } - // Light of the old node - u8 old_light = oldnode.getLight(bank, ndef); + // Light of the old node + u8 old_light = it->second.getLight(bank, ndef); - // Add the block of the added node to modified_blocks - modified_blocks[block_pos] = block; + // Add the block of the added node to modified_blocks + modified_blocks[block_pos] = block; - // Get new light level of the node - u8 new_light = 0; - if (ndef->get(n).light_propagates) { - if (bank == LIGHTBANK_DAY && ndef->get(n).sunlight_propagates + // Get new light level of the node + u8 new_light = 0; + if (ndef->get(n).light_propagates) { + if (bank == LIGHTBANK_DAY && ndef->get(n).sunlight_propagates && isSunlightAbove(map, p, ndef)) { - new_light = LIGHT_SUN; - } else { - new_light = ndef->get(n).light_source; - for (int i = 0; i < 6; i++) { - v3s16 p2 = p + neighbor_dirs[i]; - bool is_valid; - MapNode n2 = map->getNodeNoEx(p2, &is_valid); - if (is_valid) { - u8 spread = n2.getLight(bank, ndef); - // If the neighbor is at least as bright as - // this node then its light is not from - // this node. - // Its light can spread to this node. - if (spread > new_light && spread >= old_light) { - new_light = spread - 1; + new_light = LIGHT_SUN; + } else { + new_light = ndef->get(n).light_source; + for (int i = 0; i < 6; i++) { + v3s16 p2 = p + neighbor_dirs[i]; + bool is_valid; + MapNode n2 = map->getNodeNoEx(p2, &is_valid); + if (is_valid) { + u8 spread = n2.getLight(bank, ndef); + // If the neighbor is at least as bright as + // this node then its light is not from + // this node. + // Its light can spread to this node. + if (spread > new_light && spread >= old_light) { + new_light = spread - 1; + } } } } + } else { + // If this is an opaque node, it still can emit light. + new_light = ndef->get(n).light_source; } - } else { - // If this is an opaque node, it still can emit light. - new_light = ndef->get(n).light_source; - } - - ReLightQueue light_sources(256); - if (new_light > 0) { - light_sources.push(new_light, rel_pos, block_pos, block, 6); - } + if (new_light > 0) { + light_sources.push(new_light, rel_pos, block_pos, block, 6); + } - if (new_light < old_light) { - // The node became opaque or doesn't provide as much - // light as the previous one, so it must be unlighted. - LightQueue disappearing_lights(256); + if (new_light < old_light) { + // The node became opaque or doesn't provide as much + // light as the previous one, so it must be unlighted. - // Add to unlight queue - n.setLight(bank, 0, ndef); - block->setNodeNoCheck(rel_pos, n); - disappearing_lights.push(old_light, rel_pos, block_pos, block, 6); + // Add to unlight queue + n.setLight(bank, 0, ndef); + block->setNodeNoCheck(rel_pos, n); + disappearing_lights.push(old_light, rel_pos, block_pos, block, + 6); - // Remove sunlight, if there was any - if (bank == LIGHTBANK_DAY && old_light == LIGHT_SUN) { - for (s16 y = p.Y - 1;; y--) { - v3s16 n2pos(p.X, y, p.Z); + // Remove sunlight, if there was any + if (bank == LIGHTBANK_DAY && old_light == LIGHT_SUN) { + for (s16 y = p.Y - 1;; y--) { + v3s16 n2pos(p.X, y, p.Z); - MapNode n2; + MapNode n2; - n2 = map->getNodeNoEx(n2pos, &is_valid_position); - if (!is_valid_position) - break; + n2 = map->getNodeNoEx(n2pos, &is_valid_position); + if (!is_valid_position) + break; - // If this node doesn't have sunlight, the nodes below - // it don't have too. - if (n2.getLight(LIGHTBANK_DAY, ndef) != LIGHT_SUN) { - break; + // If this node doesn't have sunlight, the nodes below + // it don't have too. + if (n2.getLight(LIGHTBANK_DAY, ndef) != LIGHT_SUN) { + break; + } + // Remove sunlight and add to unlight queue. + n2.setLight(LIGHTBANK_DAY, 0, ndef); + map->setNode(n2pos, n2); + relative_v3 rel_pos2; + mapblock_v3 block_pos2; + getNodeBlockPosWithOffset(n2pos, block_pos2, rel_pos2); + MapBlock *block2 = map->getBlockNoCreateNoEx( + block_pos2); + disappearing_lights.push(LIGHT_SUN, rel_pos2, + block_pos2, block2, + 4 /* The node above caused the change */); } - // Remove sunlight and add to unlight queue. - n2.setLight(LIGHTBANK_DAY, 0, ndef); - map->setNode(n2pos, n2); - relative_v3 rel_pos2; - mapblock_v3 block_pos2; - getNodeBlockPosWithOffset(n2pos, block_pos2, rel_pos2); - MapBlock *block2 = map->getBlockNoCreateNoEx(block_pos2); - disappearing_lights.push(LIGHT_SUN, rel_pos2, block_pos2, - block2, 4 /* The node above caused the change */); } - } - // Remove lights - unspreadLight(map, ndef, bank, disappearing_lights, light_sources, - modified_blocks); - } else if (new_light > old_light) { - // It is sure that the node provides more light than the previous - // one, unlighting is not necessary. - // Propagate sunlight - if (bank == LIGHTBANK_DAY && new_light == LIGHT_SUN) { - for (s16 y = p.Y - 1;; y--) { - v3s16 n2pos(p.X, y, p.Z); - - MapNode n2; - - n2 = map->getNodeNoEx(n2pos, &is_valid_position); - if (!is_valid_position) - break; - - // This should not happen, but if the node has sunlight - // then the iteration should stop. - if (n2.getLight(LIGHTBANK_DAY, ndef) == LIGHT_SUN) { - break; - } - // If the node terminates sunlight, stop. - if (!ndef->get(n2).sunlight_propagates) { - break; + } else if (new_light > old_light) { + // It is sure that the node provides more light than the previous + // one, unlighting is not necessary. + // Propagate sunlight + if (bank == LIGHTBANK_DAY && new_light == LIGHT_SUN) { + for (s16 y = p.Y - 1;; y--) { + v3s16 n2pos(p.X, y, p.Z); + + MapNode n2; + + n2 = map->getNodeNoEx(n2pos, &is_valid_position); + if (!is_valid_position) + break; + + // This should not happen, but if the node has sunlight + // then the iteration should stop. + if (n2.getLight(LIGHTBANK_DAY, ndef) == LIGHT_SUN) { + break; + } + // If the node terminates sunlight, stop. + if (!ndef->get(n2).sunlight_propagates) { + break; + } + relative_v3 rel_pos2; + mapblock_v3 block_pos2; + getNodeBlockPosWithOffset(n2pos, block_pos2, rel_pos2); + MapBlock *block2 = map->getBlockNoCreateNoEx( + block_pos2); + // Mark node for lighting. + light_sources.push(LIGHT_SUN, rel_pos2, block_pos2, + block2, 4); } - relative_v3 rel_pos2; - mapblock_v3 block_pos2; - getNodeBlockPosWithOffset(n2pos, block_pos2, rel_pos2); - MapBlock *block2 = map->getBlockNoCreateNoEx(block_pos2); - // Mark node for lighting. - light_sources.push(LIGHT_SUN, rel_pos2, block_pos2, block2, - 4); } } + } + // Remove lights + unspreadLight(map, ndef, bank, disappearing_lights, light_sources, + modified_blocks); // Initialize light values for light spreading. for (u8 i = 0; i <= LIGHT_SUN; i++) { const std::vector &lights = light_sources.lights[i]; diff --git a/src/voxelalgorithms.h b/src/voxelalgorithms.h index f2b2fde32d88..3632546dde90 100644 --- a/src/voxelalgorithms.h +++ b/src/voxelalgorithms.h @@ -58,18 +58,19 @@ SunlightPropagateResult propagateSunlight(VoxelManipulator &v, VoxelArea a, /*! * Updates the lighting on the map. * The result will be correct only if - * no nodes were changed except the given one. + * no nodes were changed except the given ones. + * Before calling this procedure make sure that all new nodes on + * the map have zero light level! * - * \param p position of the changed node - * \param oldnode this node was overwritten on the map + * \param oldnodes contains the MapNodes that were replaced by the new + * MapNodes and their positions * \param modified_blocks output, contains all map blocks that * the function modified */ -void update_lighting_node( +void update_lighting_nodes( Map *map, INodeDefManager *ndef, - v3s16 p, - MapNode oldnode, + std::vector > &oldnodes, std::map &modified_blocks); } // namespace voxalgo