Navigation Menu

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
// 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();
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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())
Expand Down Expand Up @@ -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));
}

/*
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)
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 };

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.
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<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.
* 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
Expand Down

0 comments on commit be39f61

Please sign in to comment.