From 103a70a642fadfcccb52072e240ea8ee4c05422f Mon Sep 17 00:00:00 2001 From: xtreme8000 Date: Sun, 15 Jan 2023 19:24:42 +0100 Subject: [PATCH] Add light propagation on block change --- source/block/block_bed.c | 1 + source/block/block_brown_mushroom.c | 1 + source/block/block_cactus.c | 1 + source/block/block_cake.c | 1 + source/block/block_cobweb.c | 1 + source/block/block_crops.c | 1 + source/block/block_farmland.c | 1 + source/block/block_fence.c | 1 + source/block/block_fire.c | 1 + source/block/block_flower.c | 1 + source/block/block_glass.c | 1 + source/block/block_ice.c | 1 + source/block/block_ladder.c | 1 + source/block/block_lava.c | 1 + source/block/block_leaves.c | 1 + source/block/block_portal.c | 1 + source/block/block_pressure_plate.c | 2 + source/block/block_rail.c | 3 + source/block/block_red_mushroom.c | 1 + source/block/block_reed.c | 1 + source/block/block_rose.c | 1 + source/block/block_sapling.c | 1 + source/block/block_slab.c | 1 + source/block/block_snow.c | 1 + source/block/block_spawner.c | 1 + source/block/block_stairs.c | 2 + source/block/block_tallgrass.c | 2 + source/block/block_torch.c | 3 + source/block/block_water.c | 2 + source/block/blocks.h | 3 +- source/chunk.c | 45 ++++--- source/chunk.h | 2 + source/game/gui/screen_ingame.c | 24 ++-- source/main.c | 2 + source/network/client_interface.c | 3 +- source/world.c | 189 ++++++++++++++++++++++++---- source/world.h | 13 +- 37 files changed, 266 insertions(+), 52 deletions(-) diff --git a/source/block/block_bed.c b/source/block/block_bed.c index ded4d68..30626a4 100644 --- a/source/block/block_bed.c +++ b/source/block/block_bed.c @@ -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 = { diff --git a/source/block/block_brown_mushroom.c b/source/block/block_brown_mushroom.c index 22d1da9..30a783b 100644 --- a/source/block/block_brown_mushroom.c +++ b/source/block/block_brown_mushroom.c @@ -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, diff --git a/source/block/block_cactus.c b/source/block/block_cactus.c index ce45136..08259c4 100644 --- a/source/block/block_cactus.c +++ b/source/block/block_cactus.c @@ -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 = { diff --git a/source/block/block_cake.c b/source/block/block_cake.c index c1e7f6e..8908113 100644 --- a/source/block/block_cake.c +++ b/source/block/block_cake.c @@ -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 = { diff --git a/source/block/block_cobweb.c b/source/block/block_cobweb.c index 34f54df..2925cec 100644 --- a/source/block/block_cobweb.c +++ b/source/block/block_cobweb.c @@ -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, diff --git a/source/block/block_crops.c b/source/block/block_crops.c index 46df26a..93fdca2 100644 --- a/source/block/block_crops.c +++ b/source/block/block_crops.c @@ -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 = { diff --git a/source/block/block_farmland.c b/source/block/block_farmland.c index 1c7554d..e30743e 100644 --- a/source/block/block_farmland.c +++ b/source/block/block_farmland.c @@ -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 = { diff --git a/source/block/block_fence.c b/source/block/block_fence.c index 5e6808b..3f7f9ba 100644 --- a/source/block/block_fence.c +++ b/source/block/block_fence.c @@ -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 = { diff --git a/source/block/block_fire.c b/source/block/block_fire.c index 60754b1..b80d161 100644 --- a/source/block/block_fire.c +++ b/source/block/block_fire.c @@ -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 = { diff --git a/source/block/block_flower.c b/source/block/block_flower.c index b934c3f..40ce20b 100644 --- a/source/block/block_flower.c +++ b/source/block/block_flower.c @@ -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, diff --git a/source/block/block_glass.c b/source/block/block_glass.c index ab4b711..5e5172e 100644 --- a/source/block/block_glass.c +++ b/source/block/block_glass.c @@ -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 = { diff --git a/source/block/block_ice.c b/source/block/block_ice.c index 3265b76..a617818 100644 --- a/source/block/block_ice.c +++ b/source/block/block_ice.c @@ -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 = { diff --git a/source/block/block_ladder.c b/source/block/block_ladder.c index 39af7db..ce3a71a 100644 --- a/source/block/block_ladder.c +++ b/source/block/block_ladder.c @@ -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 = { diff --git a/source/block/block_lava.c b/source/block/block_lava.c index 8532bb0..ee0d8c1 100644 --- a/source/block/block_lava.c +++ b/source/block/block_lava.c @@ -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 = { diff --git a/source/block/block_leaves.c b/source/block/block_leaves.c index cefb111..b92e548 100644 --- a/source/block/block_leaves.c +++ b/source/block/block_leaves.c @@ -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 = { diff --git a/source/block/block_portal.c b/source/block/block_portal.c index 2797975..80d0df6 100644 --- a/source/block/block_portal.c +++ b/source/block/block_portal.c @@ -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 = { diff --git a/source/block/block_pressure_plate.c b/source/block/block_pressure_plate.c index 92bee8b..685723b 100644 --- a/source/block/block_pressure_plate.c +++ b/source/block/block_pressure_plate.c @@ -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 = { diff --git a/source/block/block_rail.c b/source/block/block_rail.c index ee786d8..bdb05bb 100644 --- a/source/block/block_rail.c +++ b/source/block/block_rail.c @@ -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, diff --git a/source/block/block_red_mushroom.c b/source/block/block_red_mushroom.c index 288dad3..a225281 100644 --- a/source/block/block_red_mushroom.c +++ b/source/block/block_red_mushroom.c @@ -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, diff --git a/source/block/block_reed.c b/source/block/block_reed.c index bf19643..9613543 100644 --- a/source/block/block_reed.c +++ b/source/block/block_reed.c @@ -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, diff --git a/source/block/block_rose.c b/source/block/block_rose.c index cc6a416..4de0504 100644 --- a/source/block/block_rose.c +++ b/source/block/block_rose.c @@ -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, diff --git a/source/block/block_sapling.c b/source/block/block_sapling.c index 4af088c..03c3e21 100644 --- a/source/block/block_sapling.c +++ b/source/block/block_sapling.c @@ -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, diff --git a/source/block/block_slab.c b/source/block/block_slab.c index 8fe1c5d..464324d 100644 --- a/source/block/block_slab.c +++ b/source/block/block_slab.c @@ -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 = { diff --git a/source/block/block_snow.c b/source/block/block_snow.c index 15c8595..cc767a2 100644 --- a/source/block/block_snow.c +++ b/source/block/block_snow.c @@ -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 = { diff --git a/source/block/block_spawner.c b/source/block/block_spawner.c index 0f22949..2f869d9 100644 --- a/source/block/block_spawner.c +++ b/source/block/block_spawner.c @@ -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 = { diff --git a/source/block/block_stairs.c b/source/block/block_stairs.c index bcc37d3..b974076 100644 --- a/source/block/block_stairs.c +++ b/source/block/block_stairs.c @@ -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 = { diff --git a/source/block/block_tallgrass.c b/source/block/block_tallgrass.c index c21520a..198d2d1 100644 --- a/source/block/block_tallgrass.c +++ b/source/block/block_tallgrass.c @@ -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, diff --git a/source/block/block_torch.c b/source/block/block_torch.c index 0d45226..95cfbf2 100644 --- a/source/block/block_torch.c +++ b/source/block/block_torch.c @@ -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 = { diff --git a/source/block/block_water.c b/source/block/block_water.c index dbba57f..ea13e25 100644 --- a/source/block/block_water.c +++ b/source/block/block_water.c @@ -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 = { diff --git a/source/block/blocks.h b/source/block/blocks.h index 6fde74f..193ae30 100755 --- a/source/block/blocks.h +++ b/source/block/blocks.h @@ -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; diff --git a/source/chunk.c b/source/chunk.c index e6ccf91..58a6980 100644 --- a/source/chunk.c +++ b/source/chunk.c @@ -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); diff --git a/source/chunk.h b/source/chunk.h index a71c0d9..fa53e55 100644 --- a/source/chunk.h +++ b/source/chunk.h @@ -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); diff --git a/source/game/gui/screen_ingame.c b/source/game/gui/screen_ingame.c index 8461e0d..e5bc61d 100644 --- a/source/game/gui/screen_ingame.c +++ b/source/game/gui/screen_ingame.c @@ -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(), diff --git a/source/main.c b/source/main.c index 42df679..100f23e 100644 --- a/source/main.c +++ b/source/main.c @@ -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! diff --git a/source/network/client_interface.c b/source/network/client_interface.c index 65eeaef..7d7a13f 100644 --- a/source/network/client_interface.c +++ b/source/network/client_interface.c @@ -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++; diff --git a/source/world.c b/source/world.c index c829d8f..481e752 100644 --- a/source/world.c +++ b/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); diff --git a/source/world.h b/source/world.h index 34f8f50..b8a64ce 100644 --- a/source/world.h +++ b/source/world.h @@ -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,