basin/src/light.c

173 lines
8.1 KiB
C

#include <avuna/util.h>
#include "light.h"
/*
void light_proc(struct world* world, struct chunk* chunk, int32_t x, int32_t y, int32_t z, uint8_t light) {
uint8_t cl = world_get_raw_light_guess(world, chunk, x, y, z, 1);
if (cl < light) world_set_light_guess(world, chunk, (uint8_t) (light & 0x0f), x, y, z, 1);
}
*/
// a layer-buffered BFS could do this a good bit faster due to re-iteration of nodes in this DFS at the cost of more memory overhead
// `avoid` is a low overhead way to prevent direct back-recursion, but ofc is not perfect to avoid overhead of a set
void light_check_floodfill_positive(struct world* world, struct chunk* chunk, int32_t x, int32_t y, int32_t z, uint8_t blocklight, uint8_t new_level, uint8_t avoid) {
int current_light = world_get_raw_light_guess(world, chunk, x, y, z, blocklight);
if (new_level <= current_light) {
return;
}
block b = world_get_block_guess(world, chunk, x, y, z);
struct block_info* info = getBlockInfo(b);
int opacity = info == NULL ? 1 : info->lightOpacity;
if (opacity < 1) opacity = 1;
int opacified_level = (int) new_level - opacity;
if (opacified_level <= current_light || opacified_level < 0) {
return;
}
world_set_light_guess(world, chunk, (uint8_t) opacified_level, x, y, z, blocklight);
if (opacified_level > 1) { // if 1, they cannot increase from 0 as 0 would be their new minimum.
if (avoid != 1) light_check_floodfill_positive(world, chunk, x + 1, y, z, blocklight, new_level, 0);
if (avoid != 0) light_check_floodfill_positive(world, chunk, x - 1, y, z, blocklight, new_level, 1);
if (avoid != 3) light_check_floodfill_positive(world, chunk, x, y + 1, z, blocklight, new_level, 2);
if (avoid != 2) light_check_floodfill_positive(world, chunk, x, y - 1, z, blocklight, new_level, 3);
if (avoid != 5) light_check_floodfill_positive(world, chunk, x, y, z + 1, blocklight, new_level, 4);
if (avoid != 4) light_check_floodfill_positive(world, chunk, x, y, z - 1, blocklight, new_level, 5);
}
}
void light_update(struct world* world, struct chunk* chunk, int32_t x, int32_t y, int32_t z, uint8_t blocklight, uint8_t new_level) {
if (y < 0 || y > 255) return;
uint8_t current_light = world_get_raw_light_guess(world, chunk, x, y, z, blocklight);
world_set_light_guess(world, chunk, (uint8_t) (new_level > 15 ? 15 : new_level), x, y, z, blocklight);
if (new_level > current_light) {
// increase
light_check_floodfill_positive(world, chunk, x + 1, y, z, blocklight, new_level, 0);
light_check_floodfill_positive(world, chunk, x - 1, y, z, blocklight, new_level, 1);
light_check_floodfill_positive(world, chunk, x, y + 1, z, blocklight, new_level, 2);
light_check_floodfill_positive(world, chunk, x, y - 1, z, blocklight, new_level, 3);
light_check_floodfill_positive(world, chunk, x, y, z + 1, blocklight, new_level, 4);
light_check_floodfill_positive(world, chunk, x, y, z - 1, blocklight, new_level, 5);
} else {
// clear area
// fill back in reverse
}
}
/*
int light_floodfill(struct world* world, struct chunk* chunk, struct world_lightpos* lp, int skylight, int subtract, struct hashmap* updates) {
if (lp->y < 0 || lp->y > 255) return 0;
if (skylight && lp->y <= world_height_guess(world, chunk, lp->x, lp->z)) {
struct block_info* bi = getBlockInfo(world_get_block_guess(world, chunk, lp->x, lp->y + 1, lp->z));
if (bi != NULL && bi->lightOpacity <= 16) {
struct world_lightpos lp2;
lp2.x = lp->x;
lp2.y = lp->y + 1;
lp2.z = lp->z;
light_floodfill(world, chunk, &lp2, skylight, subtract, updates);
}
}
struct block_info* bi = getBlockInfo(world_get_block_guess(world, chunk, lp->x, lp->y, lp->z));
int lo = bi == NULL ? 1 : bi->lightOpacity;
if (lo < 1) lo = 1;
int le = bi == NULL ? 0 : bi->lightEmission;
int16_t maxl = 0;
uint8_t xpl = world_get_raw_light_guess(world, chunk, lp->x + 1, lp->y, lp->z, !skylight);
uint8_t xnl = world_get_raw_light_guess(world, chunk, lp->x - 1, lp->y, lp->z, !skylight);
uint8_t ypl = world_get_raw_light_guess(world, chunk, lp->x, lp->y + 1, lp->z, !skylight);
uint8_t ynl = world_get_raw_light_guess(world, chunk, lp->x, lp->y - 1, lp->z, !skylight);
uint8_t zpl = world_get_raw_light_guess(world, chunk, lp->x, lp->y, lp->z + 1, !skylight);
uint8_t znl = world_get_raw_light_guess(world, chunk, lp->x, lp->y, lp->z - 1, !skylight);
if (subtract) {
maxl = (int16_t) (world_get_raw_light_guess(world, chunk, lp->x, lp->y, lp->z, !skylight) - subtract);
} else {
maxl = xpl;
if (xnl > maxl) maxl = xnl;
if (ypl > maxl) maxl = ypl;
if (ynl > maxl) maxl = ynl;
if (zpl > maxl) maxl = zpl;
if (znl > maxl) maxl = znl;
}
if (!subtract) maxl -= lo;
else maxl += lo;
//printf("%s %i at %i, %i, %i\n", subtract ? "subtract" : "add", maxl, lp->x, lp->y, lp->z);
//if (maxl < 15) {
int ks = 0;
if ((subtract - lo) > 0) {
subtract -= lo;
} else {
ks = 1;
}
//}
int sslf = 0;
if (skylight) {
int hm = world_height_guess(world, chunk, lp->x, lp->z);
if (lp->y >= hm) {
maxl = 15;
if (subtract) sslf = 1;
}
//else maxl = -1;
}
if (maxl < le && !skylight) maxl = le;
if (maxl < 0) maxl = 0;
if (maxl > 15) maxl = 15;
uint8_t pl = world_get_raw_light_guess(world, chunk, lp->x, lp->y, lp->z, !skylight);
if (pl == maxl) return sslf;
world_set_light_guess(world, chunk, maxl, lp->x, lp->y, lp->z, !skylight);
if (ks) return 1;
if (subtract ? (maxl < 15) : (maxl > 0)) {
if (subtract ? xpl > maxl : xpl < maxl) {
lp->x++;
if (light_floodfill(world, chunk, lp, skylight, subtract, updates) && subtract) {
lp->x--;
void* n = xcopy(lp, sizeof(struct world_lightpos), 0);
put_hashmap(updates, (uint64_t) n, n);
//light_floodfill(world, chunk, lp, skylight, 0, 0);
} else lp->x--;
}
if (subtract ? xnl > maxl : xnl < maxl) {
lp->x--;
if (light_floodfill(world, chunk, lp, skylight, subtract, updates) && subtract) {
lp->x++;
void* n = xcopy(lp, sizeof(struct world_lightpos), 0);
put_hashmap(updates, (uint64_t) n, n);
//light_floodfill(world, chunk, lp, skylight, 0, 0);
} else lp->x++;
}
if (!skylight && (subtract ? ypl > maxl : ypl < maxl)) {
lp->y++;
if (light_floodfill(world, chunk, lp, skylight, subtract, updates) && subtract) {
lp->y--;
//light_floodfill(world, chunk, lp, skylight, 0, 0);
} else lp->y--;
}
if (subtract ? ynl > maxl : ynl < maxl) {
lp->y--;
if (light_floodfill(world, chunk, lp, skylight, subtract, updates) && subtract) {
lp->y++;
void* n = xcopy(lp, sizeof(struct world_lightpos), 0);
put_hashmap(updates, (uint64_t) n, n);
//light_update(world, chunk, lp, skylight, 0, 0);
} else lp->y++;
}
if (subtract ? zpl > maxl : zpl < maxl) {
lp->z++;
if (light_floodfill(world, chunk, lp, skylight, subtract, updates) && subtract) {
lp->z--;
void* n = xcopy(lp, sizeof(struct world_lightpos), 0);
put_hashmap(updates, (uint64_t) n, n);
//light_floodfill(world, chunk, lp, skylight, 0, 0);
} else lp->z--;
}
if (subtract ? znl > maxl : znl < maxl) {
lp->z--;
if (light_floodfill(world, chunk, lp, skylight, subtract, updates) && subtract) {
lp->z++;
void* n = xcopy(lp, sizeof(struct world_lightpos), 0);
put_hashmap(updates, (uint64_t) n, n);
//light_floodfill(world, chunk, lp, skylight, 0, 0);
} else lp->z++;
}
}
return sslf;
}*/