1
0
Fork 0
mirror of https://github.com/luanti-org/luanti.git synced 2025-08-11 17:51:04 +00:00

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

View file

@ -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];