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:
parent
c071efaa43
commit
be39f61359
3 changed files with 145 additions and 122 deletions
|
@ -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];
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue