mirror of
https://github.com/xtreme8000/CavEX.git
synced 2025-01-22 09:11:55 -05:00
Add light propagation on block change
This commit is contained in:
parent
9c23f4aaf1
commit
103a70a642
37 changed files with 266 additions and 52 deletions
|
@ -96,6 +96,7 @@ struct block block_bed = {
|
|||
.luminance = 0,
|
||||
.double_sided = false,
|
||||
.can_see_through = true,
|
||||
.opacity = 1,
|
||||
.ignore_lighting = false,
|
||||
.flammable = false,
|
||||
.block_item = {
|
||||
|
|
|
@ -60,6 +60,7 @@ struct block block_brown_mushroom = {
|
|||
.luminance = 1,
|
||||
.double_sided = true,
|
||||
.can_see_through = true,
|
||||
.opacity = 0,
|
||||
.render_block_data.cross_random_displacement = false,
|
||||
.ignore_lighting = false,
|
||||
.flammable = false,
|
||||
|
|
|
@ -73,6 +73,7 @@ struct block block_cactus = {
|
|||
.luminance = 0,
|
||||
.double_sided = false,
|
||||
.can_see_through = true,
|
||||
.opacity = 0,
|
||||
.ignore_lighting = false,
|
||||
.flammable = false,
|
||||
.block_item = {
|
||||
|
|
|
@ -77,6 +77,7 @@ struct block block_cake = {
|
|||
.luminance = 0,
|
||||
.double_sided = false,
|
||||
.can_see_through = true,
|
||||
.opacity = 0,
|
||||
.ignore_lighting = false,
|
||||
.flammable = false,
|
||||
.block_item = {
|
||||
|
|
|
@ -60,6 +60,7 @@ struct block block_cobweb = {
|
|||
.luminance = 0,
|
||||
.double_sided = true,
|
||||
.can_see_through = true,
|
||||
.opacity = 1,
|
||||
.render_block_data.cross_random_displacement = false,
|
||||
.ignore_lighting = false,
|
||||
.flammable = false,
|
||||
|
|
|
@ -60,6 +60,7 @@ struct block block_crops = {
|
|||
.luminance = 0,
|
||||
.double_sided = true,
|
||||
.can_see_through = true,
|
||||
.opacity = 0,
|
||||
.ignore_lighting = false,
|
||||
.flammable = false,
|
||||
.block_item = {
|
||||
|
|
|
@ -69,6 +69,7 @@ struct block block_farmland = {
|
|||
.luminance = 0,
|
||||
.double_sided = false,
|
||||
.can_see_through = true,
|
||||
.opacity = 15,
|
||||
.ignore_lighting = true,
|
||||
.flammable = false,
|
||||
.block_item = {
|
||||
|
|
|
@ -69,6 +69,7 @@ struct block block_fence = {
|
|||
.luminance = 0,
|
||||
.double_sided = false,
|
||||
.can_see_through = true,
|
||||
.opacity = 0,
|
||||
.ignore_lighting = false,
|
||||
.flammable = true,
|
||||
.block_item = {
|
||||
|
|
|
@ -59,6 +59,7 @@ struct block block_fire = {
|
|||
.luminance = 15,
|
||||
.double_sided = false,
|
||||
.can_see_through = true,
|
||||
.opacity = 0,
|
||||
.ignore_lighting = false,
|
||||
.flammable = false,
|
||||
.block_item = {
|
||||
|
|
|
@ -60,6 +60,7 @@ struct block block_flower = {
|
|||
.luminance = 0,
|
||||
.double_sided = true,
|
||||
.can_see_through = true,
|
||||
.opacity = 0,
|
||||
.render_block_data.cross_random_displacement = false,
|
||||
.ignore_lighting = false,
|
||||
.flammable = false,
|
||||
|
|
|
@ -61,6 +61,7 @@ struct block block_glass = {
|
|||
.luminance = 0,
|
||||
.double_sided = false,
|
||||
.can_see_through = true,
|
||||
.opacity = 0,
|
||||
.ignore_lighting = false,
|
||||
.flammable = false,
|
||||
.block_item = {
|
||||
|
|
|
@ -61,6 +61,7 @@ struct block block_ice = {
|
|||
.luminance = 0,
|
||||
.double_sided = false,
|
||||
.can_see_through = true,
|
||||
.opacity = 1,
|
||||
.ignore_lighting = false,
|
||||
.flammable = false,
|
||||
.block_item = {
|
||||
|
|
|
@ -77,6 +77,7 @@ struct block block_ladder = {
|
|||
.luminance = 0,
|
||||
.double_sided = false,
|
||||
.can_see_through = true,
|
||||
.opacity = 0,
|
||||
.ignore_lighting = false,
|
||||
.flammable = false,
|
||||
.block_item = {
|
||||
|
|
|
@ -73,6 +73,7 @@ struct block block_lava = {
|
|||
.luminance = 15,
|
||||
.double_sided = false,
|
||||
.can_see_through = true,
|
||||
.opacity = 15,
|
||||
.ignore_lighting = false,
|
||||
.flammable = false,
|
||||
.block_item = {
|
||||
|
|
|
@ -78,6 +78,7 @@ struct block block_leaves = {
|
|||
.luminance = 0,
|
||||
.double_sided = true,
|
||||
.can_see_through = true,
|
||||
.opacity = 1,
|
||||
.ignore_lighting = false,
|
||||
.flammable = true,
|
||||
.block_item = {
|
||||
|
|
|
@ -59,6 +59,7 @@ struct block block_portal = {
|
|||
.luminance = 11,
|
||||
.double_sided = false,
|
||||
.can_see_through = true,
|
||||
.opacity = 1,
|
||||
.ignore_lighting = false,
|
||||
.flammable = false,
|
||||
.block_item = {
|
||||
|
|
|
@ -73,6 +73,7 @@ struct block block_stone_pressure_plate = {
|
|||
.luminance = 0,
|
||||
.double_sided = false,
|
||||
.can_see_through = true,
|
||||
.opacity = 0,
|
||||
.ignore_lighting = false,
|
||||
.flammable = false,
|
||||
.block_item = {
|
||||
|
@ -97,6 +98,7 @@ struct block block_wooden_pressure_plate = {
|
|||
.luminance = 0,
|
||||
.double_sided = false,
|
||||
.can_see_through = true,
|
||||
.opacity = 0,
|
||||
.ignore_lighting = false,
|
||||
.flammable = false,
|
||||
.block_item = {
|
||||
|
|
|
@ -75,6 +75,7 @@ struct block block_rail = {
|
|||
.luminance = 0,
|
||||
.double_sided = true,
|
||||
.can_see_through = true,
|
||||
.opacity = 0,
|
||||
.render_block_data.rail_curved_possible = true,
|
||||
.ignore_lighting = false,
|
||||
.flammable = false,
|
||||
|
@ -99,6 +100,7 @@ struct block block_powered_rail = {
|
|||
.luminance = 0,
|
||||
.double_sided = true,
|
||||
.can_see_through = true,
|
||||
.opacity = 0,
|
||||
.render_block_data.rail_curved_possible = false,
|
||||
.ignore_lighting = false,
|
||||
.flammable = false,
|
||||
|
@ -123,6 +125,7 @@ struct block block_detector_rail = {
|
|||
.luminance = 0,
|
||||
.double_sided = true,
|
||||
.can_see_through = true,
|
||||
.opacity = 0,
|
||||
.render_block_data.rail_curved_possible = false,
|
||||
.ignore_lighting = false,
|
||||
.flammable = false,
|
||||
|
|
|
@ -60,6 +60,7 @@ struct block block_red_mushroom = {
|
|||
.luminance = 0,
|
||||
.double_sided = true,
|
||||
.can_see_through = true,
|
||||
.opacity = 0,
|
||||
.render_block_data.cross_random_displacement = false,
|
||||
.ignore_lighting = false,
|
||||
.flammable = false,
|
||||
|
|
|
@ -60,6 +60,7 @@ struct block block_reed = {
|
|||
.luminance = 0,
|
||||
.double_sided = true,
|
||||
.can_see_through = true,
|
||||
.opacity = 0,
|
||||
.render_block_data.cross_random_displacement = false,
|
||||
.ignore_lighting = false,
|
||||
.flammable = false,
|
||||
|
|
|
@ -60,6 +60,7 @@ struct block block_rose = {
|
|||
.luminance = 0,
|
||||
.double_sided = true,
|
||||
.can_see_through = true,
|
||||
.opacity = 0,
|
||||
.render_block_data.cross_random_displacement = false,
|
||||
.ignore_lighting = false,
|
||||
.flammable = false,
|
||||
|
|
|
@ -64,6 +64,7 @@ struct block block_sapling = {
|
|||
.luminance = 0,
|
||||
.double_sided = true,
|
||||
.can_see_through = true,
|
||||
.opacity = 0,
|
||||
.render_block_data.cross_random_displacement = false,
|
||||
.ignore_lighting = false,
|
||||
.flammable = false,
|
||||
|
|
|
@ -77,6 +77,7 @@ struct block block_slab = {
|
|||
.luminance = 0,
|
||||
.double_sided = false,
|
||||
.can_see_through = true,
|
||||
.opacity = 15,
|
||||
.ignore_lighting = true,
|
||||
.flammable = false,
|
||||
.block_item = {
|
||||
|
|
|
@ -75,6 +75,7 @@ struct block block_snow = {
|
|||
.luminance = 0,
|
||||
.double_sided = false,
|
||||
.can_see_through = true,
|
||||
.opacity = 0,
|
||||
.ignore_lighting = false,
|
||||
.flammable = false,
|
||||
.block_item = {
|
||||
|
|
|
@ -60,6 +60,7 @@ struct block block_spawner = {
|
|||
.luminance = 0,
|
||||
.double_sided = false,
|
||||
.can_see_through = true,
|
||||
.opacity = 1,
|
||||
.ignore_lighting = false,
|
||||
.flammable = false,
|
||||
.block_item = {
|
||||
|
|
|
@ -127,6 +127,7 @@ struct block block_wooden_stairs = {
|
|||
.luminance = 0,
|
||||
.double_sided = false,
|
||||
.can_see_through = true,
|
||||
.opacity = 15,
|
||||
.ignore_lighting = true,
|
||||
.flammable = true,
|
||||
.block_item = {
|
||||
|
@ -153,6 +154,7 @@ struct block block_stone_stairs = {
|
|||
.luminance = 0,
|
||||
.double_sided = false,
|
||||
.can_see_through = true,
|
||||
.opacity = 15,
|
||||
.ignore_lighting = true,
|
||||
.flammable = false,
|
||||
.block_item = {
|
||||
|
|
|
@ -68,6 +68,7 @@ struct block block_tallgrass = {
|
|||
.luminance = 0,
|
||||
.double_sided = true,
|
||||
.can_see_through = true,
|
||||
.opacity = 0,
|
||||
.render_block_data.cross_random_displacement = true,
|
||||
.ignore_lighting = false,
|
||||
.flammable = true,
|
||||
|
@ -92,6 +93,7 @@ struct block block_deadbush = {
|
|||
.luminance = 0,
|
||||
.double_sided = true,
|
||||
.can_see_through = true,
|
||||
.opacity = 0,
|
||||
.render_block_data.cross_random_displacement = false,
|
||||
.ignore_lighting = false,
|
||||
.flammable = true,
|
||||
|
|
|
@ -77,6 +77,7 @@ struct block block_torch = {
|
|||
.luminance = 14,
|
||||
.double_sided = false,
|
||||
.can_see_through = true,
|
||||
.opacity = 0,
|
||||
.ignore_lighting = false,
|
||||
.flammable = false,
|
||||
.block_item = {
|
||||
|
@ -100,6 +101,7 @@ struct block block_redstone_torch = {
|
|||
.luminance = 0,
|
||||
.double_sided = false,
|
||||
.can_see_through = true,
|
||||
.opacity = 0,
|
||||
.ignore_lighting = false,
|
||||
.flammable = false,
|
||||
.block_item = {
|
||||
|
@ -123,6 +125,7 @@ struct block block_redstone_torch_lit = {
|
|||
.luminance = 7,
|
||||
.double_sided = false,
|
||||
.can_see_through = true,
|
||||
.opacity = 0,
|
||||
.ignore_lighting = false,
|
||||
.flammable = false,
|
||||
.block_item = {
|
||||
|
|
|
@ -77,6 +77,7 @@ struct block block_water_still = {
|
|||
.luminance = 0,
|
||||
.double_sided = false,
|
||||
.can_see_through = true,
|
||||
.opacity = 3,
|
||||
.ignore_lighting = false,
|
||||
.flammable = false,
|
||||
.block_item = {
|
||||
|
@ -100,6 +101,7 @@ struct block block_water_flowing = {
|
|||
.luminance = 0,
|
||||
.double_sided = false,
|
||||
.can_see_through = true,
|
||||
.opacity = 3,
|
||||
.ignore_lighting = false,
|
||||
.flammable = false,
|
||||
.block_item = {
|
||||
|
|
|
@ -104,7 +104,8 @@ struct block {
|
|||
size_t (*renderBlockAlways)(struct displaylist*, struct block_info*,
|
||||
enum side, struct block_info*, uint8_t*, bool);
|
||||
bool transparent;
|
||||
int luminance;
|
||||
uint8_t luminance : 4;
|
||||
uint8_t opacity : 4;
|
||||
bool double_sided;
|
||||
bool can_see_through;
|
||||
bool ignore_lighting;
|
||||
|
|
|
@ -126,20 +126,8 @@ struct block_data chunk_lookup_block(struct chunk* c, w_coord_t x, w_coord_t y,
|
|||
};
|
||||
}
|
||||
|
||||
void chunk_set_block(struct chunk* c, c_coord_t x, c_coord_t y, c_coord_t z,
|
||||
struct block_data blk) {
|
||||
assert(c && x < CHUNK_SIZE && y < CHUNK_SIZE && z < CHUNK_SIZE);
|
||||
|
||||
size_t idx = CHUNK_INDEX(x, y, z) / 2 * 5;
|
||||
size_t off = CHUNK_INDEX(x, y, z) % 2;
|
||||
|
||||
c->blocks[idx + off + 0] = blk.type;
|
||||
c->blocks[idx + off + 2] = (blk.torch_light << 4) | blk.sky_light;
|
||||
c->blocks[idx + 4] = (c->blocks[idx + 4] & ~(0x0F << (off * 4)))
|
||||
| (blk.metadata << (off * 4));
|
||||
c->rebuild_displist = true;
|
||||
|
||||
// trigger neighbour chunk updates
|
||||
static void chunk_trigger_neighbour_update(struct chunk* c, c_coord_t x,
|
||||
c_coord_t y, c_coord_t z) {
|
||||
// TODO: diagonal chunks, just sharing edge or single point
|
||||
|
||||
bool cond[6] = {
|
||||
|
@ -163,6 +151,35 @@ void chunk_set_block(struct chunk* c, c_coord_t x, c_coord_t y, c_coord_t z,
|
|||
}
|
||||
}
|
||||
|
||||
void chunk_set_light(struct chunk* c, c_coord_t x, c_coord_t y, c_coord_t z,
|
||||
uint8_t light) {
|
||||
assert(c && x < CHUNK_SIZE && y < CHUNK_SIZE && z < CHUNK_SIZE);
|
||||
|
||||
size_t idx = CHUNK_INDEX(x, y, z) / 2 * 5;
|
||||
size_t off = CHUNK_INDEX(x, y, z) % 2;
|
||||
|
||||
c->blocks[idx + off + 2] = light;
|
||||
c->rebuild_displist = true;
|
||||
|
||||
chunk_trigger_neighbour_update(c, x, y, z);
|
||||
}
|
||||
|
||||
void chunk_set_block(struct chunk* c, c_coord_t x, c_coord_t y, c_coord_t z,
|
||||
struct block_data blk) {
|
||||
assert(c && x < CHUNK_SIZE && y < CHUNK_SIZE && z < CHUNK_SIZE);
|
||||
|
||||
size_t idx = CHUNK_INDEX(x, y, z) / 2 * 5;
|
||||
size_t off = CHUNK_INDEX(x, y, z) % 2;
|
||||
|
||||
c->blocks[idx + off + 0] = blk.type;
|
||||
c->blocks[idx + off + 2] = (blk.torch_light << 4) | blk.sky_light;
|
||||
c->blocks[idx + 4] = (c->blocks[idx + 4] & ~(0x0F << (off * 4)))
|
||||
| (blk.metadata << (off * 4));
|
||||
c->rebuild_displist = true;
|
||||
|
||||
chunk_trigger_neighbour_update(c, x, y, z);
|
||||
}
|
||||
|
||||
bool chunk_check_built(struct chunk* c) {
|
||||
assert(c);
|
||||
|
||||
|
|
|
@ -79,6 +79,8 @@ struct block_data chunk_lookup_block(struct chunk* c, w_coord_t x, w_coord_t y,
|
|||
void chunk_set_block(struct chunk* c, c_coord_t x, c_coord_t y, c_coord_t z,
|
||||
struct block_data blk);
|
||||
bool chunk_check_built(struct chunk* c);
|
||||
void chunk_set_light(struct chunk* c, c_coord_t x, c_coord_t y, c_coord_t z,
|
||||
uint8_t light);
|
||||
void chunk_render(struct chunk* c, bool pass, float x, float y, float z);
|
||||
void chunk_pre_render(struct chunk* c, mat4 view, bool has_fog);
|
||||
|
||||
|
|
|
@ -94,9 +94,10 @@ static void screen_ingame_update(struct screen* s, float dt) {
|
|||
(struct block_data) {
|
||||
.type = BLOCK_AIR,
|
||||
.metadata = 0,
|
||||
.sky_light = 15,
|
||||
.sky_light = 0,
|
||||
.torch_light = 0,
|
||||
});
|
||||
},
|
||||
true);
|
||||
gstate.held_item_animation = (struct held_anim) {
|
||||
.start = time_get(),
|
||||
.type = false,
|
||||
|
@ -110,15 +111,16 @@ static void screen_ingame_update(struct screen* s, float dt) {
|
|||
&& item_is_block(&item)) {
|
||||
int x, y, z;
|
||||
blocks_side_offset(gstate.camera_hit.side, &x, &y, &z);
|
||||
world_set_block(
|
||||
&gstate.world, gstate.camera_hit.x + x,
|
||||
gstate.camera_hit.y + y, gstate.camera_hit.z + z,
|
||||
(struct block_data) {
|
||||
.type = item.id,
|
||||
.metadata = 0,
|
||||
.sky_light = blocks[item.id]->can_see_through ? 15 : 0,
|
||||
.torch_light = blocks[item.id]->luminance,
|
||||
});
|
||||
world_set_block(&gstate.world, gstate.camera_hit.x + x,
|
||||
gstate.camera_hit.y + y,
|
||||
gstate.camera_hit.z + z,
|
||||
(struct block_data) {
|
||||
.type = item.id,
|
||||
.metadata = 0,
|
||||
.sky_light = 0,
|
||||
.torch_light = 0,
|
||||
},
|
||||
true);
|
||||
}
|
||||
gstate.held_item_animation = (struct held_anim) {
|
||||
.start = time_get(),
|
||||
|
|
|
@ -143,6 +143,8 @@ int main(void) {
|
|||
gstate.current_screen->update(gstate.current_screen,
|
||||
gstate.stats.dt);
|
||||
|
||||
world_update_lighting(&gstate.world);
|
||||
|
||||
gfx_flip_buffers(&gstate.stats.dt_gpu, &gstate.stats.dt_vsync);
|
||||
|
||||
// must not modify displaylists while still rendering!
|
||||
|
|
|
@ -47,7 +47,8 @@ void clin_chunk(w_coord_t x, w_coord_t y, w_coord_t z, w_coord_t sx,
|
|||
.metadata = md,
|
||||
.sky_light = (*lighting_t) & 0xF,
|
||||
.torch_light = (*lighting_t) >> 4,
|
||||
});
|
||||
},
|
||||
false);
|
||||
ids_t++;
|
||||
lighting_t++;
|
||||
|
||||
|
|
189
source/world.c
189
source/world.c
|
@ -131,6 +131,8 @@ void world_create(struct world* w) {
|
|||
dict_wsection_init(w->sections);
|
||||
ilist_chunks_init(w->render);
|
||||
ilist_chunks2_init(w->gpu_busy_chunks);
|
||||
stack_create(&w->lighting_updates, 16,
|
||||
sizeof(struct world_modification_entry));
|
||||
w->world_chunk_cache = NULL;
|
||||
w->anim_timer = time_get();
|
||||
}
|
||||
|
@ -138,6 +140,20 @@ void world_create(struct world* w) {
|
|||
void world_destroy(struct world* w) {
|
||||
assert(w);
|
||||
|
||||
stack_destroy(&w->lighting_updates);
|
||||
|
||||
dict_wsection_it_t it;
|
||||
dict_wsection_it(it, w->sections);
|
||||
|
||||
while(!dict_wsection_end_p(it)) {
|
||||
struct world_section* s = &dict_wsection_ref(it)->value;
|
||||
for(size_t k = 0; k < COLUMN_HEIGHT; k++) {
|
||||
if(s->column[k])
|
||||
chunk_unref(s->column[k]);
|
||||
}
|
||||
dict_wsection_next(it);
|
||||
}
|
||||
|
||||
dict_wsection_clear(w->sections);
|
||||
}
|
||||
|
||||
|
@ -181,7 +197,8 @@ static void wsection_heightmap_update(struct world_section* s, c_coord_t x,
|
|||
|
||||
int8_t* height = s->heightmap + x + z * CHUNK_SIZE;
|
||||
|
||||
if(blocks[type]) {
|
||||
if(blocks[type]
|
||||
&& (!blocks[type]->can_see_through || blocks[type]->opacity > 0)) {
|
||||
if(y > *height)
|
||||
*height = y;
|
||||
} else if(y == *height) {
|
||||
|
@ -189,7 +206,9 @@ static void wsection_heightmap_update(struct world_section* s, c_coord_t x,
|
|||
struct chunk* c = s->column[y / CHUNK_SIZE];
|
||||
struct block_data blk = chunk_get_block(c, x, W2C_COORD(y), z);
|
||||
if(c) {
|
||||
if(blocks[blk.type])
|
||||
if(blocks[blk.type]
|
||||
&& (!blocks[blk.type]->can_see_through
|
||||
|| blocks[blk.type]->opacity > 0))
|
||||
break;
|
||||
y--;
|
||||
} else {
|
||||
|
@ -202,42 +221,158 @@ static void wsection_heightmap_update(struct world_section* s, c_coord_t x,
|
|||
}
|
||||
|
||||
void world_set_block(struct world* w, w_coord_t x, w_coord_t y, w_coord_t z,
|
||||
struct block_data blk) {
|
||||
struct block_data blk, bool light_update) {
|
||||
assert(w);
|
||||
|
||||
if(y < 0 || y >= WORLD_HEIGHT)
|
||||
return;
|
||||
|
||||
w_coord_t cx = WCOORD_CHUNK_OFFSET(x);
|
||||
w_coord_t cz = WCOORD_CHUNK_OFFSET(z);
|
||||
struct world_section* s
|
||||
= dict_wsection_get(w->sections, SECTION_TO_ID(cx, cz));
|
||||
if(light_update) {
|
||||
stack_push(&w->lighting_updates,
|
||||
&(struct world_modification_entry) {
|
||||
.x = x,
|
||||
.y = y,
|
||||
.z = z,
|
||||
.blk = blk,
|
||||
});
|
||||
} else {
|
||||
w_coord_t cx = WCOORD_CHUNK_OFFSET(x);
|
||||
w_coord_t cz = WCOORD_CHUNK_OFFSET(z);
|
||||
struct world_section* s
|
||||
= dict_wsection_get(w->sections, SECTION_TO_ID(cx, cz));
|
||||
|
||||
struct chunk* c = world_find_chunk(w, x, y, z);
|
||||
struct chunk* c = world_find_chunk(w, x, y, z);
|
||||
|
||||
if(!c) {
|
||||
c = malloc(sizeof(struct chunk));
|
||||
assert(c);
|
||||
if(!c) {
|
||||
c = malloc(sizeof(struct chunk));
|
||||
assert(c);
|
||||
|
||||
w_coord_t cy = y / CHUNK_SIZE;
|
||||
chunk_init(c, w, cx * CHUNK_SIZE, cy * CHUNK_SIZE, cz * CHUNK_SIZE);
|
||||
chunk_ref(c);
|
||||
w_coord_t cy = y / CHUNK_SIZE;
|
||||
chunk_init(c, w, cx * CHUNK_SIZE, cy * CHUNK_SIZE, cz * CHUNK_SIZE);
|
||||
chunk_ref(c);
|
||||
|
||||
w->world_chunk_cache = c;
|
||||
w->world_chunk_cache = c;
|
||||
|
||||
if(!s) {
|
||||
s = dict_wsection_safe_get(w->sections, SECTION_TO_ID(cx, cz));
|
||||
assert(s);
|
||||
memset(s->heightmap, -1, sizeof(s->heightmap));
|
||||
memset(s->column, 0, sizeof(s->column));
|
||||
if(!s) {
|
||||
s = dict_wsection_safe_get(w->sections, SECTION_TO_ID(cx, cz));
|
||||
assert(s);
|
||||
memset(s->heightmap, -1, sizeof(s->heightmap));
|
||||
memset(s->column, 0, sizeof(s->column));
|
||||
}
|
||||
|
||||
assert(s->column[cy] == NULL);
|
||||
s->column[cy] = c;
|
||||
}
|
||||
|
||||
assert(s->column[cy] == NULL);
|
||||
s->column[cy] = c;
|
||||
chunk_set_block(c, W2C_COORD(x), W2C_COORD(y), W2C_COORD(z), blk);
|
||||
wsection_heightmap_update(s, W2C_COORD(x), y, W2C_COORD(z), blk.type);
|
||||
}
|
||||
}
|
||||
|
||||
static inline int8_t MAX_I8(int8_t a, int8_t b) {
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
struct lighting_update_entry {
|
||||
w_coord_t x, y, z;
|
||||
};
|
||||
|
||||
void world_update_lighting(struct world* w) {
|
||||
assert(w);
|
||||
|
||||
if(stack_empty(&w->lighting_updates))
|
||||
return;
|
||||
|
||||
struct world_modification_entry source;
|
||||
stack_pop(&w->lighting_updates, &source);
|
||||
|
||||
struct stack queue;
|
||||
stack_create(&queue, 128, sizeof(struct lighting_update_entry));
|
||||
stack_push(&queue,
|
||||
&(struct lighting_update_entry) {
|
||||
.x = source.x,
|
||||
.y = source.y,
|
||||
.z = source.z,
|
||||
});
|
||||
|
||||
world_set_block(w, source.x, source.y, source.z, source.blk, false);
|
||||
|
||||
while(!stack_empty(&queue)) {
|
||||
struct lighting_update_entry current;
|
||||
stack_pop(&queue, ¤t);
|
||||
|
||||
struct world_section* s
|
||||
= dict_wsection_get(w->sections,
|
||||
SECTION_TO_ID(WCOORD_CHUNK_OFFSET(current.x),
|
||||
WCOORD_CHUNK_OFFSET(current.z)));
|
||||
struct chunk* c = world_chunk_from_section(w, s, current.y);
|
||||
struct block_data old
|
||||
= chunk_get_block(c, W2C_COORD(current.x), W2C_COORD(current.y),
|
||||
W2C_COORD(current.z));
|
||||
|
||||
uint8_t old_light = (old.torch_light << 4) | old.sky_light;
|
||||
uint8_t new_light_sky = 0, new_light_torch = 0;
|
||||
|
||||
if(current.y > s->heightmap[W2C_COORD(current.x)
|
||||
+ W2C_COORD(current.z) * CHUNK_SIZE])
|
||||
new_light_sky = 0xF;
|
||||
|
||||
if(blocks[old.type])
|
||||
new_light_torch = blocks[old.type]->luminance;
|
||||
|
||||
if(!blocks[old.type] || blocks[old.type]->can_see_through) {
|
||||
for(enum side s = 0; s < SIDE_MAX; s++) {
|
||||
int x, y, z;
|
||||
blocks_side_offset(s, &x, &y, &z);
|
||||
|
||||
struct chunk* c_other = world_find_chunk(
|
||||
w, current.x + x, current.y + y, current.z + z);
|
||||
|
||||
if(c_other) {
|
||||
struct block_data other = chunk_get_block(
|
||||
c_other, W2C_COORD(current.x + x),
|
||||
W2C_COORD(current.y + y), W2C_COORD(current.z + z));
|
||||
int8_t opacity = blocks[old.type] ?
|
||||
MAX_I8(blocks[old.type]->opacity, 1) :
|
||||
1;
|
||||
|
||||
new_light_sky
|
||||
= MAX_I8(MAX_I8((int8_t)other.sky_light - opacity, 0),
|
||||
new_light_sky);
|
||||
new_light_torch
|
||||
= MAX_I8(MAX_I8((int8_t)other.torch_light - opacity, 0),
|
||||
new_light_torch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t new_light = (new_light_torch << 4) | new_light_sky;
|
||||
|
||||
if(old_light != new_light
|
||||
|| (source.x == current.x && source.y == current.y
|
||||
&& source.z == current.z)) {
|
||||
chunk_set_light(c, W2C_COORD(current.x), W2C_COORD(current.y),
|
||||
W2C_COORD(current.z), new_light);
|
||||
|
||||
for(enum side s = 0; s < SIDE_MAX; s++) {
|
||||
int x, y, z;
|
||||
blocks_side_offset(s, &x, &y, &z);
|
||||
|
||||
struct chunk* c_other = world_find_chunk(
|
||||
w, current.x + x, current.y + y, current.z + z);
|
||||
|
||||
if(c_other)
|
||||
stack_push(&queue,
|
||||
&(struct lighting_update_entry) {
|
||||
.x = current.x + x,
|
||||
.y = current.y + y,
|
||||
.z = current.z + z,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
chunk_set_block(c, W2C_COORD(x), W2C_COORD(y), W2C_COORD(z), blk);
|
||||
wsection_heightmap_update(s, W2C_COORD(x), y, W2C_COORD(z), blk.type);
|
||||
stack_destroy(&queue);
|
||||
}
|
||||
|
||||
struct chunk* world_find_chunk_neighbour(struct world* w, struct chunk* c,
|
||||
|
@ -258,6 +393,12 @@ struct chunk* world_find_chunk_neighbour(struct world* w, struct chunk* c,
|
|||
return res ? res->column[y + c->y / CHUNK_SIZE] : NULL;
|
||||
}
|
||||
|
||||
struct chunk* world_chunk_from_section(struct world* w, struct world_section* s,
|
||||
w_coord_t y) {
|
||||
assert(w);
|
||||
return (y >= 0 && y < WORLD_HEIGHT && s) ? s->column[y / CHUNK_SIZE] : NULL;
|
||||
}
|
||||
|
||||
struct chunk* world_find_chunk(struct world* w, w_coord_t x, w_coord_t y,
|
||||
w_coord_t z) {
|
||||
assert(w);
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
|
||||
#include "cglm/cglm.h"
|
||||
|
||||
#include "stack.h"
|
||||
|
||||
#define WORLD_HEIGHT 128
|
||||
|
||||
typedef int32_t w_coord_t;
|
||||
|
@ -55,6 +57,11 @@ struct world_section {
|
|||
struct chunk* column[COLUMN_HEIGHT];
|
||||
};
|
||||
|
||||
struct world_modification_entry {
|
||||
w_coord_t x, y, z;
|
||||
struct block_data blk;
|
||||
};
|
||||
|
||||
#define SECTION_TO_ID(x, z) (((int64_t)(z) << 32) | (((int64_t)(x)&0xFFFFFFFF)))
|
||||
|
||||
DICT_DEF2(dict_wsection, int64_t, M_BASIC_OPLIST, struct world_section,
|
||||
|
@ -66,6 +73,7 @@ struct world {
|
|||
ilist_chunks_t render;
|
||||
ilist_chunks2_t gpu_busy_chunks;
|
||||
ptime_t anim_timer;
|
||||
struct stack lighting_updates;
|
||||
};
|
||||
|
||||
void world_create(struct world* w);
|
||||
|
@ -77,12 +85,15 @@ size_t world_build_chunks(struct world* w, size_t tokens);
|
|||
void world_render_completed(struct world* w, bool new_render);
|
||||
struct chunk* world_find_chunk_neighbour(struct world* w, struct chunk* c,
|
||||
enum side s);
|
||||
struct chunk* world_chunk_from_section(struct world* w, struct world_section* s,
|
||||
w_coord_t y);
|
||||
struct chunk* world_find_chunk(struct world* w, w_coord_t x, w_coord_t y,
|
||||
w_coord_t z);
|
||||
struct block_data world_get_block(struct world* w, w_coord_t x, w_coord_t y,
|
||||
w_coord_t z);
|
||||
void world_set_block(struct world* w, w_coord_t x, w_coord_t y, w_coord_t z,
|
||||
struct block_data blk);
|
||||
struct block_data blk, bool light_update);
|
||||
void world_update_lighting(struct world* w);
|
||||
void world_preload(struct world* w,
|
||||
void (*progress)(struct world* w, float percent));
|
||||
bool world_block_intersection(struct world* w, struct ray* r, w_coord_t x,
|
||||
|
|
Loading…
Reference in a new issue