Skip to content

Commit

Permalink
Use node lighting for liquid spreading
Browse files Browse the repository at this point in the history
This commit modifies the liquid transforming procedure to light and
unlight nodes instead of whole map blocks.
  • Loading branch information
juhdanad authored and nerzhul committed Oct 27, 2016
1 parent c071efa commit be39f61
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 121 deletions.
23 changes: 18 additions & 5 deletions src/map.cpp
Expand Up @@ -824,10 +824,15 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
} }


// Set the node on the map // 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); setNode(p, n);


// Update lighting // Update lighting
voxalgo::update_lighting_node(this, ndef, p, oldnode, modified_blocks); std::vector<std::pair<v3s16, MapNode> > oldnodes;
oldnodes.push_back(std::pair<v3s16, MapNode>(p, oldnode));
voxalgo::update_lighting_nodes(this, ndef, oldnodes, modified_blocks);


for(std::map<v3s16, MapBlock*>::iterator for(std::map<v3s16, MapBlock*>::iterator
i = modified_blocks.begin(); i = modified_blocks.begin();
Expand Down Expand Up @@ -1224,7 +1229,9 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> &modified_blocks)
std::deque<v3s16> must_reflow; std::deque<v3s16> must_reflow;


// List of MapBlocks that will require a lighting update (due to lava) // List of MapBlocks that will require a lighting update (due to lava)
std::map<v3s16, MapBlock *> lighting_modified_blocks; std::map<v3s16, MapBlock *> lighting_modified_blocks2;

std::vector<std::pair<v3s16, MapNode> > changed_nodes;


u32 liquid_loop_max = g_settings->getS32("liquid_loop_max"); u32 liquid_loop_max = g_settings->getS32("liquid_loop_max");
u32 loop_max = liquid_loop_max; u32 loop_max = liquid_loop_max;
Expand Down Expand Up @@ -1457,6 +1464,10 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> &modified_blocks)
} }
n0.setContent(new_node_content); 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 // Find out whether there is a suspect for this action
std::string suspect; std::string suspect;
if (m_gamedef->rollback()) if (m_gamedef->rollback())
Expand Down Expand Up @@ -1484,9 +1495,10 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> &modified_blocks)
if (block != NULL) { if (block != NULL) {
modified_blocks[blockpos] = block; modified_blocks[blockpos] = block;
// If new or old node emits light, MapBlock requires lighting update // 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) nodemgr->get(n00).light_source != 0)
lighting_modified_blocks[block->getPos()] = block; lighting_modified_blocks[block->getPos()] = block;*/
changed_nodes.push_back(std::pair<v3s16, MapNode>(p0, n00));
} }


/* /*
Expand Down Expand Up @@ -1515,7 +1527,8 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> &modified_blocks)
for (std::deque<v3s16>::iterator iter = must_reflow.begin(); iter != must_reflow.end(); ++iter) for (std::deque<v3s16>::iterator iter = must_reflow.begin(); iter != must_reflow.end(); ++iter)
m_transforming_liquid.push_back(*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);




/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
Expand Down
229 changes: 119 additions & 110 deletions src/voxelalgorithms.cpp
Expand Up @@ -583,144 +583,153 @@ bool isSunlightAbove(Map *map, v3s16 pos, INodeDefManager *ndef)


static const LightBank banks[] = { LIGHTBANK_DAY, LIGHTBANK_NIGHT }; static const LightBank banks[] = { LIGHTBANK_DAY, LIGHTBANK_NIGHT };


void update_lighting_node(Map *map, INodeDefManager *ndef, v3s16 p, void update_lighting_nodes(Map *map, INodeDefManager *ndef,
MapNode oldnode, std::map<v3s16, MapBlock*> & modified_blocks) std::vector<std::pair<v3s16, MapNode> > &oldnodes,
std::map<v3s16, MapBlock*> & modified_blocks)
{ {
// For node getter functions // For node getter functions
bool is_valid_position; 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 // Process each light bank separately
for (s32 i = 0; i < 2; i++) { 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]; LightBank bank = banks[i];
UnlightQueue disappearing_lights(256);
ReLightQueue light_sources(256);
// For each changed node process sunlight and initialize
for (std::vector<std::pair<v3s16, MapNode> >::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 // Light of the old node
u8 old_light = oldnode.getLight(bank, ndef); u8 old_light = it->second.getLight(bank, ndef);


// Add the block of the added node to modified_blocks // Add the block of the added node to modified_blocks
modified_blocks[block_pos] = block; modified_blocks[block_pos] = block;


// Get new light level of the node // Get new light level of the node
u8 new_light = 0; u8 new_light = 0;
if (ndef->get(n).light_propagates) { if (ndef->get(n).light_propagates) {
if (bank == LIGHTBANK_DAY && ndef->get(n).sunlight_propagates if (bank == LIGHTBANK_DAY && ndef->get(n).sunlight_propagates
&& isSunlightAbove(map, p, ndef)) { && isSunlightAbove(map, p, ndef)) {
new_light = LIGHT_SUN; new_light = LIGHT_SUN;
} else { } else {
new_light = ndef->get(n).light_source; new_light = ndef->get(n).light_source;
for (int i = 0; i < 6; i++) { for (int i = 0; i < 6; i++) {
v3s16 p2 = p + neighbor_dirs[i]; v3s16 p2 = p + neighbor_dirs[i];
bool is_valid; bool is_valid;
MapNode n2 = map->getNodeNoEx(p2, &is_valid); MapNode n2 = map->getNodeNoEx(p2, &is_valid);
if (is_valid) { if (is_valid) {
u8 spread = n2.getLight(bank, ndef); u8 spread = n2.getLight(bank, ndef);
// If the neighbor is at least as bright as // If the neighbor is at least as bright as
// this node then its light is not from // this node then its light is not from
// this node. // this node.
// Its light can spread to this node. // Its light can spread to this node.
if (spread > new_light && spread >= old_light) { if (spread > new_light && spread >= old_light) {
new_light = spread - 1; 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) { if (new_light > 0) {
light_sources.push(new_light, rel_pos, block_pos, block, 6); light_sources.push(new_light, rel_pos, block_pos, block, 6);
} }


if (new_light < old_light) { if (new_light < old_light) {
// The node became opaque or doesn't provide as much // The node became opaque or doesn't provide as much
// light as the previous one, so it must be unlighted. // light as the previous one, so it must be unlighted.
LightQueue disappearing_lights(256);


// Add to unlight queue // Add to unlight queue
n.setLight(bank, 0, ndef); n.setLight(bank, 0, ndef);
block->setNodeNoCheck(rel_pos, n); block->setNodeNoCheck(rel_pos, n);
disappearing_lights.push(old_light, rel_pos, block_pos, block, 6); disappearing_lights.push(old_light, rel_pos, block_pos, block,
6);


// Remove sunlight, if there was any // Remove sunlight, if there was any
if (bank == LIGHTBANK_DAY && old_light == LIGHT_SUN) { if (bank == LIGHTBANK_DAY && old_light == LIGHT_SUN) {
for (s16 y = p.Y - 1;; y--) { for (s16 y = p.Y - 1;; y--) {
v3s16 n2pos(p.X, y, p.Z); v3s16 n2pos(p.X, y, p.Z);


MapNode n2; MapNode n2;


n2 = map->getNodeNoEx(n2pos, &is_valid_position); n2 = map->getNodeNoEx(n2pos, &is_valid_position);
if (!is_valid_position) if (!is_valid_position)
break; break;


// If this node doesn't have sunlight, the nodes below // If this node doesn't have sunlight, the nodes below
// it don't have too. // it don't have too.
if (n2.getLight(LIGHTBANK_DAY, ndef) != LIGHT_SUN) { if (n2.getLight(LIGHTBANK_DAY, ndef) != LIGHT_SUN) {
break; 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 */);
} }
} } else if (new_light > old_light) {
// Remove lights // It is sure that the node provides more light than the previous
unspreadLight(map, ndef, bank, disappearing_lights, light_sources, // one, unlighting is not necessary.
modified_blocks); // Propagate sunlight
} else if (new_light > old_light) { if (bank == LIGHTBANK_DAY && new_light == LIGHT_SUN) {
// It is sure that the node provides more light than the previous for (s16 y = p.Y - 1;; y--) {
// one, unlighting is not necessary. v3s16 n2pos(p.X, y, p.Z);
// Propagate sunlight
if (bank == LIGHTBANK_DAY && new_light == LIGHT_SUN) { MapNode n2;
for (s16 y = p.Y - 1;; y--) {
v3s16 n2pos(p.X, y, p.Z); n2 = map->getNodeNoEx(n2pos, &is_valid_position);

if (!is_valid_position)
MapNode n2; break;


n2 = map->getNodeNoEx(n2pos, &is_valid_position); // This should not happen, but if the node has sunlight
if (!is_valid_position) // then the iteration should stop.
break; if (n2.getLight(LIGHTBANK_DAY, ndef) == LIGHT_SUN) {

break;
// This should not happen, but if the node has sunlight }
// then the iteration should stop. // If the node terminates sunlight, stop.
if (n2.getLight(LIGHTBANK_DAY, ndef) == LIGHT_SUN) { if (!ndef->get(n2).sunlight_propagates) {
break; break;
} }
// If the node terminates sunlight, stop. relative_v3 rel_pos2;
if (!ndef->get(n2).sunlight_propagates) { mapblock_v3 block_pos2;
break; 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. // Initialize light values for light spreading.
for (u8 i = 0; i <= LIGHT_SUN; i++) { for (u8 i = 0; i <= LIGHT_SUN; i++) {
const std::vector<ChangingLight> &lights = light_sources.lights[i]; const std::vector<ChangingLight> &lights = light_sources.lights[i];
Expand Down
13 changes: 7 additions & 6 deletions src/voxelalgorithms.h
Expand Up @@ -58,18 +58,19 @@ SunlightPropagateResult propagateSunlight(VoxelManipulator &v, VoxelArea a,
/*! /*!
* Updates the lighting on the map. * Updates the lighting on the map.
* The result will be correct only if * 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 oldnodes contains the MapNodes that were replaced by the new
* \param oldnode this node was overwritten on the map * MapNodes and their positions
* \param modified_blocks output, contains all map blocks that * \param modified_blocks output, contains all map blocks that
* the function modified * the function modified
*/ */
void update_lighting_node( void update_lighting_nodes(
Map *map, Map *map,
INodeDefManager *ndef, INodeDefManager *ndef,
v3s16 p, std::vector<std::pair<v3s16, MapNode> > &oldnodes,
MapNode oldnode,
std::map<v3s16, MapBlock*> &modified_blocks); std::map<v3s16, MapBlock*> &modified_blocks);


} // namespace voxalgo } // namespace voxalgo
Expand Down

0 comments on commit be39f61

Please sign in to comment.