Use node lighting for liquid spreading

This commit modifies the liquid transforming procedure to light and
unlight nodes instead of whole map blocks.
This commit is contained in:
Dániel Juhász 2016-10-23 17:51:13 +02:00 committed by Ner'zhul
parent c071efaa43
commit be39f61359
3 changed files with 145 additions and 122 deletions

@ -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<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
i = modified_blocks.begin();
@ -1224,7 +1229,9 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> &modified_blocks)
std::deque<v3s16> must_reflow;
// 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 loop_max = liquid_loop_max;
@ -1457,6 +1464,10 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> &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<v3s16, MapBlock*> &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<v3s16, MapNode>(p0, n00));
}
/*
@ -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)
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);
/* ----------------------------------------------------------------------

@ -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<v3s16, MapBlock*> & modified_blocks)
void update_lighting_nodes(Map *map, INodeDefManager *ndef,
std::vector<std::pair<v3s16, MapNode> > &oldnodes,
std::map<v3s16, MapBlock*> & 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<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
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.
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);
// 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 */);
}
}
} 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);
}
// 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;
}
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<ChangingLight> &lights = light_sources.lights[i];

@ -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<std::pair<v3s16, MapNode> > &oldnodes,
std::map<v3s16, MapBlock*> &modified_blocks);
} // namespace voxalgo