namespace voxalgo
{
-void setLight(VoxelManipulator &v, VoxelArea a, u8 light,
- INodeDefManager *ndef)
-{
- for(s32 x=a.MinEdge.X; x<=a.MaxEdge.X; x++)
- for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
- for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
- {
- v3s16 p(x,y,z);
- MapNode &n = v.getNodeRefUnsafe(p);
- n.setLight(LIGHTBANK_DAY, light, ndef);
- n.setLight(LIGHTBANK_NIGHT, light, ndef);
- }
-}
-
-void clearLightAndCollectSources(VoxelManipulator &v, VoxelArea a,
- enum LightBank bank, INodeDefManager *ndef,
- std::set<v3s16> & light_sources,
- std::map<v3s16, u8> & unlight_from)
-{
- // The full area we shall touch
- VoxelArea required_a = a;
- required_a.pad(v3s16(0,0,0));
- // Make sure we have access to it
- v.addArea(a);
-
- for(s32 x=a.MinEdge.X; x<=a.MaxEdge.X; x++)
- for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
- for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
- {
- v3s16 p(x,y,z);
- MapNode &n = v.getNodeRefUnsafe(p);
- u8 oldlight = n.getLight(bank, ndef);
- n.setLight(bank, 0, ndef);
-
- // If node sources light, add to list
- u8 source = ndef->get(n).light_source;
- if(source != 0)
- light_sources.insert(p);
-
- // Collect borders for unlighting
- if((x==a.MinEdge.X || x == a.MaxEdge.X
- || y==a.MinEdge.Y || y == a.MaxEdge.Y
- || z==a.MinEdge.Z || z == a.MaxEdge.Z)
- && oldlight != 0)
- {
- unlight_from[p] = oldlight;
- }
- }
-}
-
-SunlightPropagateResult propagateSunlight(VoxelManipulator &v, VoxelArea a,
- bool inexistent_top_provides_sunlight,
- std::set<v3s16> & light_sources,
- INodeDefManager *ndef)
-{
- // Return values
- bool bottom_sunlight_valid = true;
-
- // The full area we shall touch extends one extra at top and bottom
- VoxelArea required_a = a;
- required_a.pad(v3s16(0,1,0));
- // Make sure we have access to it
- v.addArea(a);
-
- s16 max_y = a.MaxEdge.Y;
- s16 min_y = a.MinEdge.Y;
-
- for(s32 x=a.MinEdge.X; x<=a.MaxEdge.X; x++)
- for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
- {
- v3s16 p_overtop(x, max_y+1, z);
- bool overtop_has_sunlight = false;
- // If overtop node does not exist, trust heuristics
- if(!v.exists(p_overtop))
- overtop_has_sunlight = inexistent_top_provides_sunlight;
- else if(v.getNodeRefUnsafe(p_overtop).getContent() == CONTENT_IGNORE)
- overtop_has_sunlight = inexistent_top_provides_sunlight;
- // Otherwise refer to it's light value
- else
- overtop_has_sunlight = (v.getNodeRefUnsafe(p_overtop).getLight(
- LIGHTBANK_DAY, ndef) == LIGHT_SUN);
-
- // Copy overtop's sunlight all over the place
- u8 incoming_light = overtop_has_sunlight ? LIGHT_SUN : 0;
- for(s32 y=max_y; y>=min_y; y--)
- {
- v3s16 p(x,y,z);
- MapNode &n = v.getNodeRefUnsafe(p);
- if(incoming_light == 0){
- // Do nothing
- } else if(incoming_light == LIGHT_SUN &&
- ndef->get(n).sunlight_propagates){
- // Do nothing
- } else if(ndef->get(n).sunlight_propagates == false){
- incoming_light = 0;
- } else {
- incoming_light = diminish_light(incoming_light);
- }
- u8 old_light = n.getLight(LIGHTBANK_DAY, ndef);
-
- if(incoming_light > old_light)
- n.setLight(LIGHTBANK_DAY, incoming_light, ndef);
-
- if(diminish_light(incoming_light) != 0)
- light_sources.insert(p);
- }
-
- // Check validity of sunlight at top of block below if it
- // hasn't already been proven invalid
- if(bottom_sunlight_valid)
- {
- bool sunlight_should_continue_down = (incoming_light == LIGHT_SUN);
- v3s16 p_overbottom(x, min_y-1, z);
- if(!v.exists(p_overbottom) ||
- v.getNodeRefUnsafe(p_overbottom
- ).getContent() == CONTENT_IGNORE){
- // Is not known, cannot compare
- } else {
- bool overbottom_has_sunlight = (v.getNodeRefUnsafe(p_overbottom
- ).getLight(LIGHTBANK_DAY, ndef) == LIGHT_SUN);
- if(sunlight_should_continue_down != overbottom_has_sunlight){
- bottom_sunlight_valid = false;
- }
- }
- }
- }
-
- return SunlightPropagateResult(bottom_sunlight_valid);
-}
-
/*!
* A direction.
* 0=X+
//! Position of the node's block.
mapblock_v3 block_position;
//! Pointer to the node's block.
- MapBlock *block;
+ MapBlock *block = NULL;
/*!
* Direction from the node that caused this node's changing
* to this node.
*/
- direction source_direction;
+ direction source_direction = 6;
- ChangingLight() :
- rel_position(),
- block_position(),
- block(NULL),
- source_direction(6)
- {}
+ ChangingLight() = default;
- ChangingLight(relative_v3 rel_pos, mapblock_v3 block_pos,
+ ChangingLight(const relative_v3 &rel_pos, const mapblock_v3 &block_pos,
MapBlock *b, direction source_dir) :
rel_position(rel_pos),
block_position(block_pos),
direction source_dir)
{
assert(light <= LIGHT_SUN);
- lights[light].push_back(
- ChangingLight(rel_pos, block_pos, block, source_dir));
+ lights[light].emplace_back(rel_pos, block_pos, block, source_dir);
}
};
* \param light_sources nodes that should be re-lighted
* \param modified_blocks output, all modified map blocks are added to this
*/
-void unspread_light(Map *map, INodeDefManager *nodemgr, LightBank bank,
+void unspread_light(Map *map, const NodeDefManager *nodemgr, LightBank bank,
UnlightQueue &from_nodes, ReLightQueue &light_sources,
std::map<v3s16, MapBlock*> &modified_blocks)
{
* \param light_sources starting nodes
* \param modified_blocks output, all modified map blocks are added to this
*/
-void spread_light(Map *map, INodeDefManager *nodemgr, LightBank bank,
+void spread_light(Map *map, const NodeDefManager *nodemgr, LightBank bank,
LightQueue &light_sources,
std::map<v3s16, MapBlock*> &modified_blocks)
{
*
* \param pos position of the node.
*/
-bool is_sunlight_above(Map *map, v3s16 pos, INodeDefManager *ndef)
+bool is_sunlight_above(Map *map, v3s16 pos, const NodeDefManager *ndef)
{
bool sunlight = true;
mapblock_v3 source_block_pos;
std::vector<std::pair<v3s16, MapNode> > &oldnodes,
std::map<v3s16, MapBlock*> &modified_blocks)
{
- INodeDefManager *ndef = map->getNodeDefManager();
+ const NodeDefManager *ndef = map->getNodeDefManager();
// For node getter functions
bool is_valid_position;
// Process each light bank separately
- for (s32 i = 0; i < 2; i++) {
- LightBank bank = banks[i];
+ for (LightBank bank : banks) {
UnlightQueue disappearing_lights(256);
ReLightQueue light_sources(256);
// Nodes that are brighter than the brightest modified node was
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];
+ for (const v3s16 &neighbor_dir : neighbor_dirs) {
+ v3s16 p2 = p + neighbor_dir;
bool is_valid;
- MapNode n2 = map->getNodeNoEx(p2, &is_valid);
+ MapNode n2 = map->getNode(p2, &is_valid);
if (is_valid) {
u8 spread = n2.getLight(bank, ndef);
// If it is sure that the neighbor won't be
MapNode n2;
- n2 = map->getNodeNoEx(n2pos, &is_valid_position);
+ n2 = map->getNode(n2pos, &is_valid_position);
if (!is_valid_position)
break;
MapNode n2;
- n2 = map->getNodeNoEx(n2pos, &is_valid_position);
+ n2 = map->getNode(n2pos, &is_valid_position);
if (!is_valid_position)
break;
* its light source and its brightest neighbor minus one.
* .
*/
-bool is_light_locally_correct(Map *map, INodeDefManager *ndef, LightBank bank,
- v3s16 pos)
+bool is_light_locally_correct(Map *map, const NodeDefManager *ndef,
+ LightBank bank, v3s16 pos)
{
bool is_valid_position;
- MapNode n = map->getNodeNoEx(pos, &is_valid_position);
+ MapNode n = map->getNode(pos, &is_valid_position);
const ContentFeatures &f = ndef->get(n);
if (f.param_type != CPT_LIGHT) {
return true;
u8 light = n.getLightNoChecks(bank, &f);
assert(f.light_source <= LIGHT_MAX);
u8 brightest_neighbor = f.light_source + 1;
- for (direction d = 0; d < 6; ++d) {
- MapNode n2 = map->getNodeNoEx(pos + neighbor_dirs[d],
+ for (const v3s16 &neighbor_dir : neighbor_dirs) {
+ MapNode n2 = map->getNode(pos + neighbor_dir,
&is_valid_position);
u8 light2 = n2.getLight(bank, ndef);
if (brightest_neighbor < light2) {
void update_block_border_lighting(Map *map, MapBlock *block,
std::map<v3s16, MapBlock*> &modified_blocks)
{
- INodeDefManager *ndef = map->getNodeDefManager();
+ const NodeDefManager *ndef = map->getNodeDefManager();
bool is_valid_position;
- for (s32 i = 0; i < 2; i++) {
- LightBank bank = banks[i];
+ for (LightBank bank : banks) {
// Since invalid light is not common, do not allocate
// memory if not needed.
UnlightQueue disappearing_lights(0);
* After the procedure returns, this contains outgoing light at
* the bottom of the voxel manipulator.
*/
-void fill_with_sunlight(MMVManip *vm, INodeDefManager *ndef, v2s16 offset,
+void fill_with_sunlight(MMVManip *vm, const NodeDefManager *ndef, v2s16 offset,
bool light[MAP_BLOCKSIZE][MAP_BLOCKSIZE])
{
// Distance in array between two nodes on top of each other.
* node coordinates.
*/
void is_sunlight_above_block(ServerMap *map, mapblock_v3 pos,
- INodeDefManager *ndef, bool light[MAP_BLOCKSIZE][MAP_BLOCKSIZE])
+ const NodeDefManager *ndef, bool light[MAP_BLOCKSIZE][MAP_BLOCKSIZE])
{
mapblock_v3 source_block_pos = pos + v3s16(0, 1, 0);
// Get or load source block.
*
* \returns true if the block was modified, false otherwise.
*/
-bool propagate_block_sunlight(Map *map, INodeDefManager *ndef,
+bool propagate_block_sunlight(Map *map, const NodeDefManager *ndef,
SunlightPropagationData *data, UnlightQueue *unlight, ReLightQueue *relight)
{
bool modified = false;
VoxelArea(v3s16(0, 0, 0), v3s16(0, 15, 15)) //X-
};
+/*!
+ * The common part of bulk light updates - it is always executed.
+ * The procedure takes the nodes that should be unlit, and the
+ * full modified area.
+ *
+ * The procedure handles the correction of all lighting except
+ * direct sunlight spreading.
+ *
+ * \param minblock least coordinates of the changed area in block
+ * coordinates
+ * \param maxblock greatest coordinates of the changed area in block
+ * coordinates
+ * \param unlight the first queue is for day light, the second is for
+ * night light. Contains all nodes on the borders that need to be unlit.
+ * \param relight the first queue is for day light, the second is for
+ * night light. Contains nodes that were not modified, but got sunlight
+ * because the changes.
+ * \param modified_blocks the procedure adds all modified blocks to
+ * this map
+ */
+void finish_bulk_light_update(Map *map, mapblock_v3 minblock,
+ mapblock_v3 maxblock, UnlightQueue unlight[2], ReLightQueue relight[2],
+ std::map<v3s16, MapBlock*> *modified_blocks)
+{
+ const NodeDefManager *ndef = map->getNodeDefManager();
+ // dummy boolean
+ bool is_valid;
+
+ // --- STEP 1: Do unlighting
+
+ for (size_t bank = 0; bank < 2; bank++) {
+ LightBank b = banks[bank];
+ unspread_light(map, ndef, b, unlight[bank], relight[bank],
+ *modified_blocks);
+ }
+
+ // --- STEP 2: Get all newly inserted light sources
+
+ // For each block:
+ v3s16 blockpos;
+ v3s16 relpos;
+ for (blockpos.X = minblock.X; blockpos.X <= maxblock.X; blockpos.X++)
+ for (blockpos.Y = minblock.Y; blockpos.Y <= maxblock.Y; blockpos.Y++)
+ for (blockpos.Z = minblock.Z; blockpos.Z <= maxblock.Z; blockpos.Z++) {
+ MapBlock *block = map->getBlockNoCreateNoEx(blockpos);
+ if (!block || block->isDummy())
+ // Skip not existing blocks
+ continue;
+ // For each node in the block:
+ for (relpos.X = 0; relpos.X < MAP_BLOCKSIZE; relpos.X++)
+ for (relpos.Z = 0; relpos.Z < MAP_BLOCKSIZE; relpos.Z++)
+ for (relpos.Y = 0; relpos.Y < MAP_BLOCKSIZE; relpos.Y++) {
+ MapNode node = block->getNodeNoCheck(relpos.X, relpos.Y, relpos.Z, &is_valid);
+ const ContentFeatures &f = ndef->get(node);
+
+ // For each light bank
+ for (size_t b = 0; b < 2; b++) {
+ LightBank bank = banks[b];
+ u8 light = f.param_type == CPT_LIGHT ?
+ node.getLightNoChecks(bank, &f):
+ f.light_source;
+ if (light > 1)
+ relight[b].push(light, relpos, blockpos, block, 6);
+ } // end of banks
+ } // end of nodes
+ } // end of blocks
+
+ // --- STEP 3: do light spreading
+
+ // For each light bank:
+ for (size_t b = 0; b < 2; b++) {
+ LightBank bank = banks[b];
+ // Sunlight is already initialized.
+ u8 maxlight = (b == 0) ? LIGHT_MAX : LIGHT_SUN;
+ // Initialize light values for light spreading.
+ for (u8 i = 0; i <= maxlight; i++) {
+ const std::vector<ChangingLight> &lights = relight[b].lights[i];
+ for (std::vector<ChangingLight>::const_iterator it = lights.begin();
+ it < lights.end(); ++it) {
+ MapNode n = it->block->getNodeNoCheck(it->rel_position,
+ &is_valid);
+ n.setLight(bank, i, ndef);
+ it->block->setNodeNoCheck(it->rel_position, n);
+ }
+ }
+ // Spread lights.
+ spread_light(map, ndef, bank, relight[b], *modified_blocks);
+ }
+}
+
void blit_back_with_light(ServerMap *map, MMVManip *vm,
std::map<v3s16, MapBlock*> *modified_blocks)
{
- INodeDefManager *ndef = map->getNodeDefManager();
+ const NodeDefManager *ndef = map->getNodeDefManager();
mapblock_v3 minblock = getNodeBlockPos(vm->m_area.MinEdge);
mapblock_v3 maxblock = getNodeBlockPos(vm->m_area.MaxEdge);
// First queue is for day light, second is for night light.
data.target_block = v3s16(x, minblock.Y - 1, z);
for (s16 z = 0; z < MAP_BLOCKSIZE; z++)
for (s16 x = 0; x < MAP_BLOCKSIZE; x++)
- data.data.push_back(
- SunlightPropagationUnit(v2s16(x, z), lights[z][x]));
+ data.data.emplace_back(v2s16(x, z), lights[z][x]);
// Propagate sunlight and shadow below the voxel manipulator.
while (!data.data.empty()) {
if (propagate_block_sunlight(map, ndef, &data, &unlight[0],
}
// --- STEP 2: Get nodes from borders to unlight
+ v3s16 blockpos;
+ v3s16 relpos;
// In case there are unloaded holes in the voxel manipulator
// unlight each block.
// For each block:
- for (s16 b_x = minblock.X; b_x <= maxblock.X; b_x++)
- for (s16 b_y = minblock.Y; b_y <= maxblock.Y; b_y++)
- for (s16 b_z = minblock.Z; b_z <= maxblock.Z; b_z++) {
- v3s16 blockpos(b_x, b_y, b_z);
+ for (blockpos.X = minblock.X; blockpos.X <= maxblock.X; blockpos.X++)
+ for (blockpos.Y = minblock.Y; blockpos.Y <= maxblock.Y; blockpos.Y++)
+ for (blockpos.Z = minblock.Z; blockpos.Z <= maxblock.Z; blockpos.Z++) {
MapBlock *block = map->getBlockNoCreateNoEx(blockpos);
if (!block || block->isDummy())
// Skip not existing blocks.
continue;
v3s16 offset = block->getPosRelative();
// For each border of the block:
- for (direction d = 0; d < 6; d++) {
- VoxelArea a = block_pad[d];
+ for (const VoxelArea &a : block_pad) {
// For each node of the border:
- for (s32 x = a.MinEdge.X; x <= a.MaxEdge.X; x++)
- for (s32 z = a.MinEdge.Z; z <= a.MaxEdge.Z; z++)
- for (s32 y = a.MinEdge.Y; y <= a.MaxEdge.Y; y++) {
- v3s16 relpos(x, y, z);
+ for (relpos.X = a.MinEdge.X; relpos.X <= a.MaxEdge.X; relpos.X++)
+ for (relpos.Z = a.MinEdge.Z; relpos.Z <= a.MaxEdge.Z; relpos.Z++)
+ for (relpos.Y = a.MinEdge.Y; relpos.Y <= a.MaxEdge.Y; relpos.Y++) {
+
// Get old and new node
- MapNode oldnode = block->getNodeNoCheck(x, y, z, &is_valid);
+ MapNode oldnode = block->getNodeNoCheck(relpos, &is_valid);
const ContentFeatures &oldf = ndef->get(oldnode);
MapNode newnode = vm->getNodeNoExNoEmerge(relpos + offset);
- const ContentFeatures &newf = ndef->get(newnode);
+ const ContentFeatures &newf = oldnode == newnode ? oldf :
+ ndef->get(newnode);
+
// For each light bank
for (size_t b = 0; b < 2; b++) {
LightBank bank = banks[b];
vm->blitBackAll(modified_blocks, true);
- // --- STEP 4: Do unlighting
+ // --- STEP 4: Finish light update
- for (size_t bank = 0; bank < 2; bank++) {
- LightBank b = banks[bank];
- unspread_light(map, ndef, b, unlight[bank], relight[bank],
- *modified_blocks);
+ finish_bulk_light_update(map, minblock, maxblock, unlight, relight,
+ modified_blocks);
+}
+
+/*!
+ * Resets the lighting of the given map block to
+ * complete darkness and full sunlight.
+ *
+ * \param light incoming sunlight, light[x][z] is true if there
+ * is sunlight above the map block at the given x-z coordinates.
+ * The array's indices are relative node coordinates in the block.
+ * After the procedure returns, this contains outgoing light at
+ * the bottom of the map block.
+ */
+void fill_with_sunlight(MapBlock *block, const NodeDefManager *ndef,
+ bool light[MAP_BLOCKSIZE][MAP_BLOCKSIZE])
+{
+ if (block->isDummy())
+ return;
+ // dummy boolean
+ bool is_valid;
+ // For each column of nodes:
+ for (s16 z = 0; z < MAP_BLOCKSIZE; z++)
+ for (s16 x = 0; x < MAP_BLOCKSIZE; x++) {
+ // True if the current node has sunlight.
+ bool lig = light[z][x];
+ // For each node, downwards:
+ for (s16 y = MAP_BLOCKSIZE - 1; y >= 0; y--) {
+ MapNode n = block->getNodeNoCheck(x, y, z, &is_valid);
+ // Ignore IGNORE nodes, these are not generated yet.
+ if (n.getContent() == CONTENT_IGNORE)
+ continue;
+ const ContentFeatures &f = ndef->get(n.getContent());
+ if (lig && !f.sunlight_propagates) {
+ // Sunlight is stopped.
+ lig = false;
+ }
+ // Reset light
+ n.setLight(LIGHTBANK_DAY, lig ? 15 : 0, f);
+ n.setLight(LIGHTBANK_NIGHT, 0, f);
+ block->setNodeNoCheck(x, y, z, n);
+ }
+ // Output outgoing light.
+ light[z][x] = lig;
+ }
+}
+
+void repair_block_light(ServerMap *map, MapBlock *block,
+ std::map<v3s16, MapBlock*> *modified_blocks)
+{
+ if (!block || block->isDummy())
+ return;
+ const NodeDefManager *ndef = map->getNodeDefManager();
+ // First queue is for day light, second is for night light.
+ UnlightQueue unlight[] = { UnlightQueue(256), UnlightQueue(256) };
+ ReLightQueue relight[] = { ReLightQueue(256), ReLightQueue(256) };
+ // Will hold sunlight data.
+ bool lights[MAP_BLOCKSIZE][MAP_BLOCKSIZE];
+ SunlightPropagationData data;
+ // Dummy boolean.
+ bool is_valid;
+
+ // --- STEP 1: reset everything to sunlight
+
+ mapblock_v3 blockpos = block->getPos();
+ (*modified_blocks)[blockpos] = block;
+ // For each map block:
+ // Extract sunlight above.
+ is_sunlight_above_block(map, blockpos, ndef, lights);
+ // Reset the voxel manipulator.
+ fill_with_sunlight(block, ndef, lights);
+ // Copy sunlight data
+ data.target_block = v3s16(blockpos.X, blockpos.Y - 1, blockpos.Z);
+ for (s16 z = 0; z < MAP_BLOCKSIZE; z++)
+ for (s16 x = 0; x < MAP_BLOCKSIZE; x++) {
+ data.data.emplace_back(v2s16(x, z), lights[z][x]);
+ }
+ // Propagate sunlight and shadow below the voxel manipulator.
+ while (!data.data.empty()) {
+ if (propagate_block_sunlight(map, ndef, &data, &unlight[0],
+ &relight[0]))
+ (*modified_blocks)[data.target_block] =
+ map->getBlockNoCreateNoEx(data.target_block);
+ // Step downwards.
+ data.target_block.Y--;
}
- // --- STEP 5: Get all newly inserted light sources
+ // --- STEP 2: Get nodes from borders to unlight
- // For each block:
- for (s16 b_x = minblock.X; b_x <= maxblock.X; b_x++)
- for (s16 b_y = minblock.Y; b_y <= maxblock.Y; b_y++)
- for (s16 b_z = minblock.Z; b_z <= maxblock.Z; b_z++) {
- v3s16 blockpos(b_x, b_y, b_z);
- MapBlock *block = map->getBlockNoCreateNoEx(blockpos);
- if (!block || block->isDummy())
- // Skip not existing blocks
- continue;
- // For each node in the block:
- for (s32 x = 0; x < MAP_BLOCKSIZE; x++)
- for (s32 z = 0; z < MAP_BLOCKSIZE; z++)
- for (s32 y = 0; y < MAP_BLOCKSIZE; y++) {
- v3s16 relpos(x, y, z);
- MapNode node = block->getNodeNoCheck(x, y, z, &is_valid);
+ // For each border of the block:
+ for (const VoxelArea &a : block_pad) {
+ v3s16 relpos;
+ // For each node of the border:
+ for (relpos.X = a.MinEdge.X; relpos.X <= a.MaxEdge.X; relpos.X++)
+ for (relpos.Z = a.MinEdge.Z; relpos.Z <= a.MaxEdge.Z; relpos.Z++)
+ for (relpos.Y = a.MinEdge.Y; relpos.Y <= a.MaxEdge.Y; relpos.Y++) {
+
+ // Get node
+ MapNode node = block->getNodeNoCheck(relpos, &is_valid);
const ContentFeatures &f = ndef->get(node);
// For each light bank
for (size_t b = 0; b < 2; b++) {
u8 light = f.param_type == CPT_LIGHT ?
node.getLightNoChecks(bank, &f):
f.light_source;
- if (light > 1)
- relight[b].push(light, relpos, blockpos, block, 6);
+ // If the new node is dimmer than sunlight, unlight.
+ // (if it has maximal light, it is pointless to remove
+ // surrounding light, as it can only become brighter)
+ if (LIGHT_SUN > light) {
+ unlight[b].push(
+ LIGHT_SUN, relpos, blockpos, block, 6);
+ }
} // end of banks
} // end of nodes
- } // end of blocks
+ } // end of borders
- // --- STEP 6: do light spreading
+ // STEP 3: Remove and spread light
- // For each light bank:
- for (size_t b = 0; b < 2; b++) {
- LightBank bank = banks[b];
- // Sunlight is already initialized.
- u8 maxlight = (b == 0) ? LIGHT_MAX : LIGHT_SUN;
- // Initialize light values for light spreading.
- for (u8 i = 0; i <= maxlight; i++) {
- const std::vector<ChangingLight> &lights = relight[b].lights[i];
- for (std::vector<ChangingLight>::const_iterator it = lights.begin();
- it < lights.end(); ++it) {
- MapNode n = it->block->getNodeNoCheck(it->rel_position,
- &is_valid);
- n.setLight(bank, i, ndef);
- it->block->setNodeNoCheck(it->rel_position, n);
- }
- }
- // Spread lights.
- spread_light(map, ndef, bank, relight[b], *modified_blocks);
- }
+ finish_bulk_light_update(map, blockpos, blockpos, unlight, relight,
+ modified_blocks);
}
-VoxelLineIterator::VoxelLineIterator(
- const v3f &start_position,
- const v3f &line_vector) :
+VoxelLineIterator::VoxelLineIterator(const v3f &start_position, const v3f &line_vector) :
m_start_position(start_position),
- m_line_vector(line_vector),
- m_next_intersection_multi(10000.0f, 10000.0f, 10000.0f),
- m_intersection_multi_inc(10000.0f, 10000.0f, 10000.0f),
- m_step_directions(1.0f, 1.0f, 1.0f)
+ m_line_vector(line_vector)
{
m_current_node_pos = floatToInt(m_start_position, 1);
+ m_start_node_pos = m_current_node_pos;
+ m_last_index = getIndex(floatToInt(start_position + line_vector, 1));
if (m_line_vector.X > 0) {
m_next_intersection_multi.X = (floorf(m_start_position.X - 0.5) + 1.5
m_intersection_multi_inc.Z = -1 / m_line_vector.Z;
m_step_directions.Z = -1;
}
-
- m_has_next = (m_next_intersection_multi.X <= 1)
- || (m_next_intersection_multi.Y <= 1)
- || (m_next_intersection_multi.Z <= 1);
}
void VoxelLineIterator::next()
{
+ m_current_index++;
if ((m_next_intersection_multi.X < m_next_intersection_multi.Y)
&& (m_next_intersection_multi.X < m_next_intersection_multi.Z)) {
m_next_intersection_multi.X += m_intersection_multi_inc.X;
m_next_intersection_multi.Z += m_intersection_multi_inc.Z;
m_current_node_pos.Z += m_step_directions.Z;
}
+}
- m_has_next = (m_next_intersection_multi.X <= 1)
- || (m_next_intersection_multi.Y <= 1)
- || (m_next_intersection_multi.Z <= 1);
+s16 VoxelLineIterator::getIndex(v3s16 voxel){
+ return
+ abs(voxel.X - m_start_node_pos.X) +
+ abs(voxel.Y - m_start_node_pos.Y) +
+ abs(voxel.Z - m_start_node_pos.Z);
}
} // namespace voxalgo