From eae6b6c4aa12fb03c294543b41f3ab6d14bd416d Mon Sep 17 00:00:00 2001 From: xtreme8000 Date: Wed, 25 Mar 2020 13:57:03 +0100 Subject: [PATCH] See desc * use libvxl for map access * much faster chunk generation * cleaned up chunk code a bit, still wip * death camera effect * fix some includes * NOTE: greedy meshing not working yet --- src/CMakeLists.txt | 3 + src/camera.c | 4 +- src/camera.h | 13 +- src/cameracontroller.c | 46 +++ src/cameracontroller.h | 4 + src/chunk.c | 632 +++++++++++++++++++++++------------------ src/chunk.h | 37 +-- src/common.h | 1 + src/config.c | 1 + src/hud.c | 4 +- src/main.c | 7 +- src/map.c | 167 ++++------- src/map.h | 13 +- src/network.c | 11 +- src/player.c | 3 +- src/rpc.c | 7 + src/tracer.c | 2 +- 17 files changed, 528 insertions(+), 427 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5ab5dc1..0333846 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -28,6 +28,8 @@ download_file_if_it_doesnt_exist(hashtable.c https://raw.githubusercontent.com/g download_file_if_it_doesnt_exist(hashtable.h https://raw.githubusercontent.com/goldsborough/hashtable/master/hashtable.h) download_file_if_it_doesnt_exist(../deps/libdeflate.h https://raw.githubusercontent.com/ebiggers/libdeflate/master/libdeflate.h) download_file_if_it_doesnt_exist(../bsresources.zip http://aos.party/bsresources.zip) +download_file_if_it_doesnt_exist(libvxl.c https://raw.githubusercontent.com/xtreme8000/libvxl/master/libvxl.c) +download_file_if_it_doesnt_exist(libvxl.h https://raw.githubusercontent.com/xtreme8000/libvxl/master/libvxl.h) list(APPEND CLIENT_SOURCES aabb.c) list(APPEND CLIENT_SOURCES camera.c) @@ -64,6 +66,7 @@ list(APPEND CLIENT_SOURCES minheap.c) list(APPEND CLIENT_SOURCES hashtable.c) list(APPEND CLIENT_SOURCES rpc.c) list(APPEND CLIENT_SOURCES tesselator.c) +list(APPEND CLIENT_SOURCES libvxl.c) list(APPEND CLIENT_SOURCES ${BetterSpades_SOURCE_DIR}/resources/icon.rc) add_executable(client ${CLIENT_SOURCES}) diff --git a/src/camera.c b/src/camera.c index d8fcd19..4f24929 100644 --- a/src/camera.c +++ b/src/camera.c @@ -28,7 +28,7 @@ #include "matrix.h" #include "camera.h" -unsigned char camera_mode = CAMERAMODE_SPECTATOR; +enum camera_mode camera_mode = CAMERAMODE_SPECTATOR; float frustum[6][4]; float camera_rot_x = 2.04F, camera_rot_y = 1.79F; @@ -77,6 +77,7 @@ void camera_apply() { case CAMERAMODE_BODYVIEW: cameracontroller_bodyview_render(); break; case CAMERAMODE_SPECTATOR: cameracontroller_spectator_render(); break; case CAMERAMODE_SELECTION: cameracontroller_selection_render(); break; + case CAMERAMODE_DEATH: cameracontroller_death_render(); break; } } @@ -86,6 +87,7 @@ void camera_update(float dt) { case CAMERAMODE_BODYVIEW: cameracontroller_bodyview(dt); break; case CAMERAMODE_SPECTATOR: cameracontroller_spectator(dt); break; case CAMERAMODE_SELECTION: cameracontroller_selection(dt); break; + case CAMERAMODE_DEATH: cameracontroller_death(dt); break; } } diff --git a/src/camera.h b/src/camera.h index 240b3ef..5734a68 100644 --- a/src/camera.h +++ b/src/camera.h @@ -20,14 +20,17 @@ #ifndef CAMERA_H #define CAMERA_H -#define CAMERAMODE_SELECTION 0 -#define CAMERAMODE_FPS 1 -#define CAMERAMODE_SPECTATOR 2 -#define CAMERAMODE_BODYVIEW 3 +enum camera_mode { + CAMERAMODE_SELECTION, + CAMERAMODE_FPS, + CAMERAMODE_SPECTATOR, + CAMERAMODE_BODYVIEW, + CAMERAMODE_DEATH, +}; #define CAMERA_DEFAULT_FOV 70.0F -extern unsigned char camera_mode; +extern enum camera_mode camera_mode; extern float frustum[6][4]; extern float camera_rot_x, camera_rot_y; diff --git a/src/cameracontroller.c b/src/cameracontroller.c index d0fade4..718931f 100644 --- a/src/cameracontroller.c +++ b/src/cameracontroller.c @@ -30,6 +30,52 @@ int cameracontroller_bodyview_mode = 0; int cameracontroller_bodyview_player = 0; float cameracontroller_bodyview_zoom = 0.0F; +float cameracontroller_death_velocity_x, cameracontroller_death_velocity_y, cameracontroller_death_velocity_z; + +void cameracontroller_death_init(int player, float x, float y, float z) { + camera_mode = CAMERAMODE_DEATH; + float len = len3D(camera_x - x, camera_y - y, camera_z - z); + cameracontroller_death_velocity_x = (camera_x - x) / len * 3; + cameracontroller_death_velocity_y = (camera_y - y) / len * 3; + cameracontroller_death_velocity_z = (camera_z - z) / len * 3; + + cameracontroller_bodyview_player = player; + cameracontroller_bodyview_zoom = 0.0F; +} + +void cameracontroller_death(float dt) { + cameracontroller_death_velocity_y -= dt * 32.0F; + + AABB box; + aabb_set_size(&box, camera_size, camera_height, camera_size); + aabb_set_center(&box, camera_x + cameracontroller_death_velocity_x * dt, + camera_y + cameracontroller_death_velocity_y * dt, + camera_z + cameracontroller_death_velocity_z * dt); + + if(!aabb_intersection_terrain(&box, 0)) { + cameracontroller_death_velocity_y -= dt * 32.0F; + camera_x += cameracontroller_death_velocity_x * dt; + camera_y += cameracontroller_death_velocity_y * dt; + camera_z += cameracontroller_death_velocity_z * dt; + } else { + cameracontroller_death_velocity_x *= 0.5F; + cameracontroller_death_velocity_y *= -0.5F; + cameracontroller_death_velocity_z *= 0.5F; + + if(len3D(cameracontroller_death_velocity_x, cameracontroller_death_velocity_y, + cameracontroller_death_velocity_z) + < 0.05F) { + camera_mode = CAMERAMODE_BODYVIEW; + } + } +} + +void cameracontroller_death_render() { + matrix_lookAt(camera_x, camera_y, camera_z, camera_x + players[local_player_id].orientation.x, + camera_y + players[local_player_id].orientation.y, camera_z + players[local_player_id].orientation.z, + 0.0F, 1.0F, 0.0F); +} + float last_cy; void cameracontroller_fps(float dt) { players[local_player_id].connected = 1; diff --git a/src/cameracontroller.h b/src/cameracontroller.h index 40b8746..9c1c2f7 100644 --- a/src/cameracontroller.h +++ b/src/cameracontroller.h @@ -24,14 +24,18 @@ extern int cameracontroller_bodyview_mode; extern int cameracontroller_bodyview_player; extern float cameracontroller_bodyview_zoom; +void cameracontroller_death_init(int player, float x, float y, float z); + void cameracontroller_fps(float dt); void cameracontroller_spectator(float dt); void cameracontroller_bodyview(float dt); void cameracontroller_selection(float dt); +void cameracontroller_death(float dt); void cameracontroller_fps_render(void); void cameracontroller_spectator_render(void); void cameracontroller_bodyview_render(void); void cameracontroller_selection_render(void); +void cameracontroller_death_render(void); #endif diff --git a/src/chunk.c b/src/chunk.c index 5de8624..ecfd70b 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -35,40 +35,28 @@ #include "tesselator.h" #include "chunk.h" -struct chunk chunks[CHUNKS_PER_DIM * CHUNKS_PER_DIM] = {0}; +struct chunk chunks[CHUNKS_PER_DIM * CHUNKS_PER_DIM]; -int chunk_geometry_changed[CHUNKS_PER_DIM * CHUNKS_PER_DIM * 2]; +struct chunk* chunk_geometry_changed[CHUNKS_PER_DIM * CHUNKS_PER_DIM * 2]; int chunk_geometry_changed_lenght = 0; -int chunk_lighting_changed[CHUNKS_PER_DIM * CHUNKS_PER_DIM * 2]; -int chunk_lighting_changed_lenght = 0; - -int chunk_render_mode = 0; - -struct chunk_d { - int x, y; -}; - struct chunk_worker chunk_workers[CHUNK_WORKERS_MAX]; int chunk_enabled_cores; -pthread_rwlock_t* chunk_map_locks; - -static int chunk_sort(const void* a, const void* b) { - struct chunk_d* aa = (struct chunk_d*)a; - struct chunk_d* bb = (struct chunk_d*)b; - return distance2D(aa->x + CHUNK_SIZE / 2, aa->y + CHUNK_SIZE / 2, camera_x, camera_z) - - distance2D(bb->x + CHUNK_SIZE / 2, bb->y + CHUNK_SIZE / 2, camera_x, camera_z); -} - void chunk_init() { + for(int x = 0; x < CHUNKS_PER_DIM; x++) { + for(int y = 0; y < CHUNKS_PER_DIM; y++) { + struct chunk* c = chunks + x + y * CHUNKS_PER_DIM; + c->created = 0; + c->max_height = 1; + c->x = x; + c->y = y; + } + } + chunk_enabled_cores = min(max(window_cpucores() / 2, 1), CHUNK_WORKERS_MAX); log_info("%i cores enabled for chunk generation", chunk_enabled_cores); - chunk_map_locks = malloc(map_size_x * map_size_z * sizeof(pthread_rwlock_t)); - CHECK_ALLOCATION_ERROR(chunk_map_locks); - for(int k = 0; k < map_size_x * map_size_z; k++) - pthread_rwlock_init(&chunk_map_locks[k], NULL); for(int k = 0; k < chunk_enabled_cores; k++) { chunk_workers[k].state = CHUNK_WORKERSTATE_IDLE; pthread_mutex_init(&chunk_workers[k].state_lock, NULL); @@ -77,8 +65,17 @@ void chunk_init() { } } +static int chunk_sort(const void* a, const void* b) { + struct chunk_render_call* aa = (struct chunk_render_call*)a; + struct chunk_render_call* bb = (struct chunk_render_call*)b; + return distance2D(aa->chunk->x * CHUNK_SIZE + CHUNK_SIZE / 2, aa->chunk->y * CHUNK_SIZE + CHUNK_SIZE / 2, camera_x, + camera_z) + - distance2D(bb->chunk->x * CHUNK_SIZE + CHUNK_SIZE / 2, bb->chunk->y * CHUNK_SIZE + CHUNK_SIZE / 2, camera_x, + camera_z); +} + void chunk_draw_visible() { - struct chunk_d chunks_draw[CHUNKS_PER_DIM * CHUNKS_PER_DIM * 2]; + struct chunk_render_call chunks_draw[CHUNKS_PER_DIM * CHUNKS_PER_DIM * 2]; int index = 0; // go through all possible chunks and store all in range and view @@ -86,64 +83,68 @@ void chunk_draw_visible() { for(int x = -9; x < CHUNKS_PER_DIM + 9; x++) { if(distance2D((x + 0.5F) * CHUNK_SIZE, (y + 0.5F) * CHUNK_SIZE, camera_x, camera_z) <= pow(settings.render_distance + 1.414F * CHUNK_SIZE, 2)) { - int tmp_x = x, tmp_y = y; - if(tmp_x < 0) - tmp_x += CHUNKS_PER_DIM; - if(tmp_y < 0) - tmp_y += CHUNKS_PER_DIM; - if(tmp_x >= CHUNKS_PER_DIM) - tmp_x -= CHUNKS_PER_DIM; - if(tmp_y >= CHUNKS_PER_DIM) - tmp_y -= CHUNKS_PER_DIM; + uint32_t tmp_x = ((uint32_t)x) % CHUNKS_PER_DIM; + uint32_t tmp_y = ((uint32_t)y) % CHUNKS_PER_DIM; + + struct chunk* c = chunks + tmp_x + tmp_y * CHUNKS_PER_DIM; if(camera_CubeInFrustum((x + 0.5F) * CHUNK_SIZE, 0.0F, (y + 0.5F) * CHUNK_SIZE, CHUNK_SIZE / 2, - chunks[tmp_y * CHUNKS_PER_DIM + tmp_x].max_height)) - chunks_draw[index++] = (struct chunk_d) {x * CHUNK_SIZE, y * CHUNK_SIZE}; + c->max_height)) + chunks_draw[index++] = (struct chunk_render_call) { + .chunk = c, + .mirror_x = (x < 0) ? -1 : ((x >= CHUNKS_PER_DIM) ? 1 : 0), + .mirror_y = (y < 0) ? -1 : ((y >= CHUNKS_PER_DIM) ? 1 : 0), + }; } } } // sort all chunks to draw those in front first - qsort(chunks_draw, index, sizeof(struct chunk_d), chunk_sort); + qsort(chunks_draw, index, sizeof(struct chunk_render_call), chunk_sort); for(int k = 0; k < index; k++) - chunk_render(chunks_draw[k].x / CHUNK_SIZE, chunks_draw[k].y / CHUNK_SIZE); + chunk_render(chunks_draw + k); } -void chunk_set_render_mode(int r) { - chunk_render_mode = r; -} +void chunk_render(struct chunk_render_call* c) { + if(c->chunk->created) { + matrix_push(); + matrix_translate(c->mirror_x * map_size_x, 0.0F, c->mirror_y * map_size_z); + matrix_upload(); -void chunk_rebuild_all() { - for(int d = 0; d < CHUNKS_PER_DIM * CHUNKS_PER_DIM; d++) { - chunk_geometry_changed[d] = d; + // glPolygonMode(GL_FRONT, GL_LINE); + + glx_displaylist_draw(&c->chunk->display_list, GLX_DISPLAYLIST_NORMAL); + + // glPolygonMode(GL_FRONT, GL_FILL); + + matrix_pop(); } - chunk_geometry_changed_lenght = CHUNKS_PER_DIM * CHUNKS_PER_DIM; } -void chunk_render(int x, int y) { - matrix_push(); - matrix_translate((x < 0) * -map_size_x + (x >= CHUNKS_PER_DIM) * map_size_x, 0.0F, - (y < 0) * -map_size_z + (y >= CHUNKS_PER_DIM) * map_size_z); - matrix_upload(); - - if(x < 0) - x += CHUNKS_PER_DIM; +static __attribute__((always_inline)) inline uint32_t +solid_array_isair(int32_t start_x, int32_t start_z, uint32_t* array, uint32_t x, uint32_t y, uint32_t z) { if(y < 0) - y += CHUNKS_PER_DIM; - if(x >= CHUNKS_PER_DIM) - x -= CHUNKS_PER_DIM; - if(y >= CHUNKS_PER_DIM) - y -= CHUNKS_PER_DIM; + return 0; + if(y >= map_size_y) + return 1; - // glPolygonMode(GL_FRONT, GL_LINE); + size_t offset = (map_size_y - 1 - y) + ((x % map_size_x) + (z % map_size_z) * map_size_x) * map_size_y; - if(chunks[((y * CHUNKS_PER_DIM) | x)].created) - glx_displaylist_draw(&chunks[((y * CHUNKS_PER_DIM) | x)].display_list, GLX_DISPLAYLIST_NORMAL); + return !(array[offset / (sizeof(uint32_t) * 8)] & (1 << (offset % (sizeof(uint32_t) * 8)))); +} - // glPolygonMode(GL_FRONT, GL_FILL); +static __attribute__((always_inline)) inline float solid_sunblock(int32_t start_x, int32_t start_z, uint32_t* array, + int x, int y, int z) { + int dec = 18; + int i = 127; - matrix_pop(); + while(dec && y < 64) { + if(!solid_array_isair(start_x, start_z, array, x, ++y, --z)) + i -= dec; + dec -= 2; + } + return (float)i / 127.0F; } void* chunk_generate(void* data) { @@ -151,29 +152,42 @@ void* chunk_generate(void* data) { struct chunk_worker* worker = (struct chunk_worker*)data; + int first_start = 1; + while(1) { pthread_mutex_lock(&worker->state_lock); - worker->state = CHUNK_WORKERSTATE_FINISHED; + if(!first_start) { + worker->state = CHUNK_WORKERSTATE_FINISHED; + } while(worker->state != CHUNK_WORKERSTATE_BUSY) pthread_cond_wait(&worker->can_work, &worker->state_lock); pthread_mutex_unlock(&worker->state_lock); - if(settings.greedy_meshing) + first_start = 0; + + /*if(settings.greedy_meshing) chunk_generate_greedy(worker->chunk_x, worker->chunk_y, &worker->tesselator, &worker->max_height); - else - chunk_generate_naive(worker->chunk_x, worker->chunk_y, &worker->tesselator, &worker->max_height, - settings.ambient_occlusion); + else*/ + chunk_generate_naive(worker->chunk_x, worker->chunk_y, worker->blocks, worker->blocks_count, + worker->blocks_solid, &worker->tesselator, &worker->max_height, + settings.ambient_occlusion); + + // use the fact that libvxl orders libvxl_blocks by top-down coordinate first in its data structure + uint32_t last_position = 0; + for(int k = worker->blocks_count - 1; k >= 0; k--) { + struct libvxl_block* blk = worker->blocks + k; + + if(blk->position != last_position || k == worker->blocks_count - 1) { + last_position = blk->position; + + int x = key_getx(blk->position); + int z = key_gety(blk->position); - for(int x = worker->chunk_x; x < worker->chunk_x + CHUNK_SIZE; x++) { - for(int z = worker->chunk_y; z < worker->chunk_y + CHUNK_SIZE; z++) { uint32_t* out = worker->minimap_data + (x - worker->chunk_x + (z - worker->chunk_y) * CHUNK_SIZE); - if((x % 64) > 0 && (z % 64) > 0) { - pthread_rwlock_rdlock(&chunk_map_locks[x + z * map_size_x]); - uint32_t color = map_colors[x + (map_heights[x + z * map_size_x] * map_size_z + z) * map_size_x]; - pthread_rwlock_unlock(&chunk_map_locks[x + z * map_size_x]); - *out = rgba(red(color), green(color), blue(color), 255); + if((x % 64) > 0 && (z % 64) > 0) { + *out = rgb2bgr(blk->color) | 0xFF000000; } else { *out = rgba(255, 255, 255, 255); } @@ -508,179 +522,198 @@ static float vertexAO(int side1, int side2, int corner) { return 0.75F - (!side1 + !side2 + !corner) * 0.25F + 0.25F; } -void chunk_generate_naive(int start_x, int start_z, struct tesselator* tess, int* max_height, int ao) { +void chunk_generate_naive(int sx, int sz, struct libvxl_block* blocks, int count, uint32_t* solid, + struct tesselator* tess, int* max_height, int ao) { *max_height = 0; - for(int z = start_z; z < start_z + CHUNK_SIZE; z++) { - for(int x = start_x; x < start_x + CHUNK_SIZE; x++) { - for(int y = 0; y < map_size_y; y++) { - if(!map_isair(x, y, z)) { - if(*max_height < y) { - *max_height = y; - } + for(int k = 0; k < count; k++) { + struct libvxl_block* blk = blocks + k; - uint32_t col = map_get(x, y, z); - int r = red(col); - int g = green(col); - int b = blue(col); + int x = key_getx(blk->position); + int y = map_size_y - 1 - key_getz(blk->position); + int z = key_gety(blk->position); - float shade = map_sunblock(x, y, z); - r *= shade; - g *= shade; - b *= shade; - - if((z == 0 && map_isair(x, y, map_size_z - 1)) || map_isair(x, y, z - 1)) { - if(ao) { - float A = vertexAO(map_isair(x - 1, y, z - 1), map_isair(x, y - 1, z - 1), - map_isair(x - 1, y - 1, z - 1)); - float B = vertexAO(map_isair(x - 1, y, z - 1), map_isair(x, y + 1, z - 1), - map_isair(x - 1, y + 1, z - 1)); - float C = vertexAO(map_isair(x + 1, y, z - 1), map_isair(x, y + 1, z - 1), - map_isair(x + 1, y + 1, z - 1)); - float D = vertexAO(map_isair(x + 1, y, z - 1), map_isair(x, y - 1, z - 1), - map_isair(x + 1, y - 1, z - 1)); - - tesselator_add(tess, (int16_t[]) {x, y, z, x, y + 1, z, x + 1, y + 1, z, x + 1, y, z}, - (uint32_t[]) { - rgba(r * 0.875F * A, g * 0.875F * A, b * 0.875F * A, 255), - rgba(r * 0.875F * B, g * 0.875F * B, b * 0.875F * B, 255), - rgba(r * 0.875F * C, g * 0.875F * C, b * 0.875F * C, 255), - rgba(r * 0.875F * D, g * 0.875F * D, b * 0.875F * D, 255), - }); - } else { - tesselator_set_color(tess, rgba(r * 0.875F, g * 0.875F, b * 0.875F, 255)); - tesselator_add_simple(tess, - (int16_t[]) {x, y, z, x, y + 1, z, x + 1, y + 1, z, x + 1, y, z}); - } - } + if(*max_height < y) { + *max_height = y; + } - if((z == map_size_z - 1 && map_isair(x, y, 0)) || (z < map_size_z - 1 && map_isair(x, y, z + 1))) { - if(ao) { - float A = vertexAO(map_isair(x - 1, y, z + 1), map_isair(x, y - 1, z + 1), - map_isair(x - 1, y - 1, z + 1)); - float B = vertexAO(map_isair(x + 1, y, z + 1), map_isair(x, y - 1, z + 1), - map_isair(x + 1, y - 1, z + 1)); - float C = vertexAO(map_isair(x + 1, y, z + 1), map_isair(x, y + 1, z + 1), - map_isair(x + 1, y + 1, z + 1)); - float D = vertexAO(map_isair(x - 1, y, z + 1), map_isair(x, y + 1, z + 1), - map_isair(x - 1, y + 1, z + 1)); - tesselator_add( - tess, (int16_t[]) {x, y, z + 1, x + 1, y, z + 1, x + 1, y + 1, z + 1, x, y + 1, z + 1}, - (uint32_t[]) { - rgba(r * 0.625F * A, g * 0.625F * A, b * 0.625F * A, 255), - rgba(r * 0.625F * B, g * 0.625F * B, b * 0.625F * B, 255), - rgba(r * 0.625F * C, g * 0.625F * C, b * 0.625F * C, 255), - rgba(r * 0.625F * D, g * 0.625F * D, b * 0.625F * D, 255), - }); - } else { - tesselator_set_color(tess, rgba(r * 0.625F, g * 0.625F, b * 0.625F, 255)); - tesselator_add_simple( - tess, (int16_t[]) {x, y, z + 1, x + 1, y, z + 1, x + 1, y + 1, z + 1, x, y + 1, z + 1}); - } - } + uint32_t col = blk->color; + int r = blue(col); + int g = green(col); + int b = red(col); + + float shade = solid_sunblock(sx, sz, solid, x, y, z); + r *= shade; + g *= shade; + b *= shade; + + if(solid_array_isair(sx, sz, solid, x, y, z - 1)) { + if(ao) { + float A = vertexAO(solid_array_isair(sx, sz, solid, x - 1, y, z - 1), + solid_array_isair(sx, sz, solid, x, y - 1, z - 1), + solid_array_isair(sx, sz, solid, x - 1, y - 1, z - 1)); + float B = vertexAO(solid_array_isair(sx, sz, solid, x - 1, y, z - 1), + solid_array_isair(sx, sz, solid, x, y + 1, z - 1), + solid_array_isair(sx, sz, solid, x - 1, y + 1, z - 1)); + float C = vertexAO(solid_array_isair(sx, sz, solid, x + 1, y, z - 1), + solid_array_isair(sx, sz, solid, x, y + 1, z - 1), + solid_array_isair(sx, sz, solid, x + 1, y + 1, z - 1)); + float D = vertexAO(solid_array_isair(sx, sz, solid, x + 1, y, z - 1), + solid_array_isair(sx, sz, solid, x, y - 1, z - 1), + solid_array_isair(sx, sz, solid, x + 1, y - 1, z - 1)); + + tesselator_add(tess, (int16_t[]) {x, y, z, x, y + 1, z, x + 1, y + 1, z, x + 1, y, z}, + (uint32_t[]) { + rgba(r * 0.875F * A, g * 0.875F * A, b * 0.875F * A, 255), + rgba(r * 0.875F * B, g * 0.875F * B, b * 0.875F * B, 255), + rgba(r * 0.875F * C, g * 0.875F * C, b * 0.875F * C, 255), + rgba(r * 0.875F * D, g * 0.875F * D, b * 0.875F * D, 255), + }); + } else { + tesselator_set_color(tess, rgba(r * 0.875F, g * 0.875F, b * 0.875F, 255)); + tesselator_add_simple(tess, (int16_t[]) {x, y, z, x, y + 1, z, x + 1, y + 1, z, x + 1, y, z}); + } + } - if((x == 0 && map_isair(map_size_x - 1, y, z)) || (x > 0 && map_isair(x - 1, y, z))) { - if(ao) { - float A = vertexAO(map_isair(x - 1, y - 1, z), map_isair(x - 1, y, z - 1), - map_isair(x - 1, y - 1, z - 1)); - float B = vertexAO(map_isair(x - 1, y - 1, z), map_isair(x - 1, y, z + 1), - map_isair(x - 1, y - 1, z + 1)); - float C = vertexAO(map_isair(x - 1, y + 1, z), map_isair(x - 1, y, z + 1), - map_isair(x - 1, y + 1, z + 1)); - float D = vertexAO(map_isair(x - 1, y + 1, z), map_isair(x - 1, y, z - 1), - map_isair(x - 1, y + 1, z - 1)); - - tesselator_add(tess, (int16_t[]) {x, y, z, x, y, z + 1, x, y + 1, z + 1, x, y + 1, z}, - (uint32_t[]) { - rgba(r * 0.75F * A, g * 0.75F * A, b * 0.75F * A, 255), - rgba(r * 0.75F * B, g * 0.75F * B, b * 0.75F * B, 255), - rgba(r * 0.75F * C, g * 0.75F * C, b * 0.75F * C, 255), - rgba(r * 0.75F * D, g * 0.75F * D, b * 0.75F * D, 255), - }); - } else { - tesselator_set_color(tess, rgba(r * 0.75F, g * 0.75F, b * 0.75F, 255)); - tesselator_add_simple(tess, - (int16_t[]) {x, y, z, x, y, z + 1, x, y + 1, z + 1, x, y + 1, z}); - } - } + if(solid_array_isair(sx, sz, solid, x, y, z + 1)) { + if(ao) { + float A = vertexAO(solid_array_isair(sx, sz, solid, x - 1, y, z + 1), + solid_array_isair(sx, sz, solid, x, y - 1, z + 1), + solid_array_isair(sx, sz, solid, x - 1, y - 1, z + 1)); + float B = vertexAO(solid_array_isair(sx, sz, solid, x + 1, y, z + 1), + solid_array_isair(sx, sz, solid, x, y - 1, z + 1), + solid_array_isair(sx, sz, solid, x + 1, y - 1, z + 1)); + float C = vertexAO(solid_array_isair(sx, sz, solid, x + 1, y, z + 1), + solid_array_isair(sx, sz, solid, x, y + 1, z + 1), + solid_array_isair(sx, sz, solid, x + 1, y + 1, z + 1)); + float D = vertexAO(solid_array_isair(sx, sz, solid, x - 1, y, z + 1), + solid_array_isair(sx, sz, solid, x, y + 1, z + 1), + solid_array_isair(sx, sz, solid, x - 1, y + 1, z + 1)); + tesselator_add(tess, (int16_t[]) {x, y, z + 1, x + 1, y, z + 1, x + 1, y + 1, z + 1, x, y + 1, z + 1}, + (uint32_t[]) { + rgba(r * 0.625F * A, g * 0.625F * A, b * 0.625F * A, 255), + rgba(r * 0.625F * B, g * 0.625F * B, b * 0.625F * B, 255), + rgba(r * 0.625F * C, g * 0.625F * C, b * 0.625F * C, 255), + rgba(r * 0.625F * D, g * 0.625F * D, b * 0.625F * D, 255), + }); + } else { + tesselator_set_color(tess, rgba(r * 0.625F, g * 0.625F, b * 0.625F, 255)); + tesselator_add_simple(tess, + (int16_t[]) {x, y, z + 1, x + 1, y, z + 1, x + 1, y + 1, z + 1, x, y + 1, z + 1}); + } + } - if((x == map_size_x - 1 && map_isair(0, y, z)) || (x < map_size_x - 1 && map_isair(x + 1, y, z))) { - if(ao) { - float A = vertexAO(map_isair(x + 1, y - 1, z), map_isair(x + 1, y, z - 1), - map_isair(x + 1, y - 1, z - 1)); - float B = vertexAO(map_isair(x + 1, y + 1, z), map_isair(x + 1, y, z - 1), - map_isair(x + 1, y + 1, z - 1)); - float C = vertexAO(map_isair(x + 1, y + 1, z), map_isair(x + 1, y, z + 1), - map_isair(x + 1, y + 1, z + 1)); - float D = vertexAO(map_isair(x + 1, y - 1, z), map_isair(x + 1, y, z + 1), - map_isair(x + 1, y - 1, z + 1)); - - tesselator_add( - tess, (int16_t[]) {x + 1, y, z, x + 1, y + 1, z, x + 1, y + 1, z + 1, x + 1, y, z + 1}, - (uint32_t[]) { - rgba(r * 0.75F * A, g * 0.75F * A, b * 0.75F * A, 255), - rgba(r * 0.75F * B, g * 0.75F * B, b * 0.75F * B, 255), - rgba(r * 0.75F * C, g * 0.75F * C, b * 0.75F * C, 255), - rgba(r * 0.75F * D, g * 0.75F * D, b * 0.75F * D, 255), - }); - } else { - tesselator_set_color(tess, rgba(r * 0.75F, g * 0.75F, b * 0.75F, 255)); - tesselator_add_simple( - tess, (int16_t[]) {x + 1, y, z, x + 1, y + 1, z, x + 1, y + 1, z + 1, x + 1, y, z + 1}); - } - } + if(solid_array_isair(sx, sz, solid, x - 1, y, z)) { + if(ao) { + float A = vertexAO(solid_array_isair(sx, sz, solid, x - 1, y - 1, z), + solid_array_isair(sx, sz, solid, x - 1, y, z - 1), + solid_array_isair(sx, sz, solid, x - 1, y - 1, z - 1)); + float B = vertexAO(solid_array_isair(sx, sz, solid, x - 1, y - 1, z), + solid_array_isair(sx, sz, solid, x - 1, y, z + 1), + solid_array_isair(sx, sz, solid, x - 1, y - 1, z + 1)); + float C = vertexAO(solid_array_isair(sx, sz, solid, x - 1, y + 1, z), + solid_array_isair(sx, sz, solid, x - 1, y, z + 1), + solid_array_isair(sx, sz, solid, x - 1, y + 1, z + 1)); + float D = vertexAO(solid_array_isair(sx, sz, solid, x - 1, y + 1, z), + solid_array_isair(sx, sz, solid, x - 1, y, z - 1), + solid_array_isair(sx, sz, solid, x - 1, y + 1, z - 1)); + + tesselator_add(tess, (int16_t[]) {x, y, z, x, y, z + 1, x, y + 1, z + 1, x, y + 1, z}, + (uint32_t[]) { + rgba(r * 0.75F * A, g * 0.75F * A, b * 0.75F * A, 255), + rgba(r * 0.75F * B, g * 0.75F * B, b * 0.75F * B, 255), + rgba(r * 0.75F * C, g * 0.75F * C, b * 0.75F * C, 255), + rgba(r * 0.75F * D, g * 0.75F * D, b * 0.75F * D, 255), + }); + } else { + tesselator_set_color(tess, rgba(r * 0.75F, g * 0.75F, b * 0.75F, 255)); + tesselator_add_simple(tess, (int16_t[]) {x, y, z, x, y, z + 1, x, y + 1, z + 1, x, y + 1, z}); + } + } - if(y == map_size_y - 1 || map_isair(x, y + 1, z)) { - if(ao) { - float A = vertexAO(map_isair(x - 1, y + 1, z), map_isair(x, y + 1, z - 1), - map_isair(x - 1, y + 1, z - 1)); - float B = vertexAO(map_isair(x - 1, y + 1, z), map_isair(x, y + 1, z + 1), - map_isair(x - 1, y + 1, z + 1)); - float C = vertexAO(map_isair(x + 1, y + 1, z), map_isair(x, y + 1, z + 1), - map_isair(x + 1, y + 1, z + 1)); - float D = vertexAO(map_isair(x + 1, y + 1, z), map_isair(x, y + 1, z - 1), - map_isair(x + 1, y + 1, z - 1)); - - tesselator_add( - tess, (int16_t[]) {x, y + 1, z, x, y + 1, z + 1, x + 1, y + 1, z + 1, x + 1, y + 1, z}, - (uint32_t[]) { - rgba(r * A, g * A, b * A, 255), - rgba(r * B, g * B, b * B, 255), - rgba(r * C, g * C, b * C, 255), - rgba(r * D, g * D, b * D, 255), - }); - } else { - tesselator_set_color(tess, rgba(r, g, b, 255)); - tesselator_add_simple( - tess, (int16_t[]) {x, y + 1, z, x, y + 1, z + 1, x + 1, y + 1, z + 1, x + 1, y + 1, z}); - } - } + if(solid_array_isair(sx, sz, solid, x + 1, y, z)) { + if(ao) { + float A = vertexAO(solid_array_isair(sx, sz, solid, x + 1, y - 1, z), + solid_array_isair(sx, sz, solid, x + 1, y, z - 1), + solid_array_isair(sx, sz, solid, x + 1, y - 1, z - 1)); + float B = vertexAO(solid_array_isair(sx, sz, solid, x + 1, y + 1, z), + solid_array_isair(sx, sz, solid, x + 1, y, z - 1), + solid_array_isair(sx, sz, solid, x + 1, y + 1, z - 1)); + float C = vertexAO(solid_array_isair(sx, sz, solid, x + 1, y + 1, z), + solid_array_isair(sx, sz, solid, x + 1, y, z + 1), + solid_array_isair(sx, sz, solid, x + 1, y + 1, z + 1)); + float D = vertexAO(solid_array_isair(sx, sz, solid, x + 1, y - 1, z), + solid_array_isair(sx, sz, solid, x + 1, y, z + 1), + solid_array_isair(sx, sz, solid, x + 1, y - 1, z + 1)); + + tesselator_add(tess, (int16_t[]) {x + 1, y, z, x + 1, y + 1, z, x + 1, y + 1, z + 1, x + 1, y, z + 1}, + (uint32_t[]) { + rgba(r * 0.75F * A, g * 0.75F * A, b * 0.75F * A, 255), + rgba(r * 0.75F * B, g * 0.75F * B, b * 0.75F * B, 255), + rgba(r * 0.75F * C, g * 0.75F * C, b * 0.75F * C, 255), + rgba(r * 0.75F * D, g * 0.75F * D, b * 0.75F * D, 255), + }); + } else { + tesselator_set_color(tess, rgba(r * 0.75F, g * 0.75F, b * 0.75F, 255)); + tesselator_add_simple(tess, + (int16_t[]) {x + 1, y, z, x + 1, y + 1, z, x + 1, y + 1, z + 1, x + 1, y, z + 1}); + } + } - if(y > 0 && map_isair(x, y - 1, z)) { - if(ao) { - float A = vertexAO(map_isair(x - 1, y - 1, z), map_isair(x, y - 1, z - 1), - map_isair(x - 1, y - 1, z - 1)); - float B = vertexAO(map_isair(x + 1, y - 1, z), map_isair(x, y - 1, z - 1), - map_isair(x + 1, y - 1, z - 1)); - float C = vertexAO(map_isair(x + 1, y - 1, z), map_isair(x, y - 1, z + 1), - map_isair(x + 1, y - 1, z + 1)); - float D = vertexAO(map_isair(x - 1, y - 1, z), map_isair(x, y - 1, z + 1), - map_isair(x - 1, y - 1, z + 1)); - - tesselator_add(tess, (int16_t[]) {x, y, z, x + 1, y, z, x + 1, y, z + 1, x, y, z + 1}, - (uint32_t[]) { - rgba(r * 0.5F * A, g * 0.5F * A, b * 0.5F * A, 255), - rgba(r * 0.5F * B, g * 0.5F * B, b * 0.5F * B, 255), - rgba(r * 0.5F * C, g * 0.5F * C, b * 0.5F * C, 255), - rgba(r * 0.5F * D, g * 0.5F * D, b * 0.5F * D, 255), - }); - } else { - tesselator_set_color(tess, rgba(r * 0.5F, g * 0.5F, b * 0.5F, 255)); - tesselator_add_simple(tess, - (int16_t[]) {x, y, z, x + 1, y, z, x + 1, y, z + 1, x, y, z + 1}); - } - } - } + if(y == map_size_y - 1 || solid_array_isair(sx, sz, solid, x, y + 1, z)) { + if(ao) { + float A = vertexAO(solid_array_isair(sx, sz, solid, x - 1, y + 1, z), + solid_array_isair(sx, sz, solid, x, y + 1, z - 1), + solid_array_isair(sx, sz, solid, x - 1, y + 1, z - 1)); + float B = vertexAO(solid_array_isair(sx, sz, solid, x - 1, y + 1, z), + solid_array_isair(sx, sz, solid, x, y + 1, z + 1), + solid_array_isair(sx, sz, solid, x - 1, y + 1, z + 1)); + float C = vertexAO(solid_array_isair(sx, sz, solid, x + 1, y + 1, z), + solid_array_isair(sx, sz, solid, x, y + 1, z + 1), + solid_array_isair(sx, sz, solid, x + 1, y + 1, z + 1)); + float D = vertexAO(solid_array_isair(sx, sz, solid, x + 1, y + 1, z), + solid_array_isair(sx, sz, solid, x, y + 1, z - 1), + solid_array_isair(sx, sz, solid, x + 1, y + 1, z - 1)); + + tesselator_add(tess, (int16_t[]) {x, y + 1, z, x, y + 1, z + 1, x + 1, y + 1, z + 1, x + 1, y + 1, z}, + (uint32_t[]) { + rgba(r * A, g * A, b * A, 255), + rgba(r * B, g * B, b * B, 255), + rgba(r * C, g * C, b * C, 255), + rgba(r * D, g * D, b * D, 255), + }); + } else { + tesselator_set_color(tess, rgba(r, g, b, 255)); + tesselator_add_simple(tess, + (int16_t[]) {x, y + 1, z, x, y + 1, z + 1, x + 1, y + 1, z + 1, x + 1, y + 1, z}); + } + } + + if(y > 0 && solid_array_isair(sx, sz, solid, x, y - 1, z)) { + if(ao) { + float A = vertexAO(solid_array_isair(sx, sz, solid, x - 1, y - 1, z), + solid_array_isair(sx, sz, solid, x, y - 1, z - 1), + solid_array_isair(sx, sz, solid, x - 1, y - 1, z - 1)); + float B = vertexAO(solid_array_isair(sx, sz, solid, x + 1, y - 1, z), + solid_array_isair(sx, sz, solid, x, y - 1, z - 1), + solid_array_isair(sx, sz, solid, x + 1, y - 1, z - 1)); + float C = vertexAO(solid_array_isair(sx, sz, solid, x + 1, y - 1, z), + solid_array_isair(sx, sz, solid, x, y - 1, z + 1), + solid_array_isair(sx, sz, solid, x + 1, y - 1, z + 1)); + float D = vertexAO(solid_array_isair(sx, sz, solid, x - 1, y - 1, z), + solid_array_isair(sx, sz, solid, x, y - 1, z + 1), + solid_array_isair(sx, sz, solid, x - 1, y - 1, z + 1)); + + tesselator_add(tess, (int16_t[]) {x, y, z, x + 1, y, z, x + 1, y, z + 1, x, y, z + 1}, + (uint32_t[]) { + rgba(r * 0.5F * A, g * 0.5F * A, b * 0.5F * A, 255), + rgba(r * 0.5F * B, g * 0.5F * B, b * 0.5F * B, 255), + rgba(r * 0.5F * C, g * 0.5F * C, b * 0.5F * C, 255), + rgba(r * 0.5F * D, g * 0.5F * D, b * 0.5F * D, 255), + }); + } else { + tesselator_set_color(tess, rgba(r * 0.5F, g * 0.5F, b * 0.5F, 255)); + tesselator_add_simple(tess, (int16_t[]) {x, y, z, x + 1, y, z, x + 1, y, z + 1, x, y, z + 1}); } } } @@ -689,68 +722,113 @@ void chunk_generate_naive(int start_x, int start_z, struct tesselator* tess, int } void chunk_update_all() { + struct chunk* in_progress[chunk_enabled_cores]; + + // collect all chunks that are currently processed for(int j = 0; j < chunk_enabled_cores; j++) { - pthread_mutex_lock(&chunk_workers[j].state_lock); - if(chunk_workers[j].state == CHUNK_WORKERSTATE_FINISHED) { - chunk_workers[j].state = CHUNK_WORKERSTATE_IDLE; - chunks[chunk_workers[j].chunk_id].max_height = chunk_workers[j].max_height; + struct chunk_worker* worker = chunk_workers + j; + pthread_mutex_lock(&worker->state_lock); + in_progress[j] = (worker->state != CHUNK_WORKERSTATE_IDLE) ? worker->chunk : NULL; + pthread_mutex_unlock(&worker->state_lock); + } - tesselator_glx(&chunk_workers[j].tesselator, &chunks[chunk_workers[j].chunk_id].display_list); - tesselator_free(&chunk_workers[j].tesselator); + for(int j = 0; j < chunk_enabled_cores; j++) { + struct chunk_worker* worker = chunk_workers + j; + + pthread_mutex_lock(&worker->state_lock); + + if(worker->state == CHUNK_WORKERSTATE_FINISHED) { + // chunk of this worker is no longer in progress + in_progress[j] = NULL; + + worker->state = CHUNK_WORKERSTATE_IDLE; + worker->chunk->max_height = worker->max_height; + + free(worker->blocks); + free(worker->blocks_solid); + + tesselator_glx(&worker->tesselator, &worker->chunk->display_list); + tesselator_free(&worker->tesselator); glBindTexture(GL_TEXTURE_2D, texture_minimap.texture_id); - glTexSubImage2D(GL_TEXTURE_2D, 0, chunk_workers[j].chunk_x, chunk_workers[j].chunk_y, CHUNK_SIZE, - CHUNK_SIZE, GL_RGBA, GL_UNSIGNED_BYTE, chunk_workers[j].minimap_data); + glTexSubImage2D(GL_TEXTURE_2D, 0, worker->chunk_x, worker->chunk_y, CHUNK_SIZE, CHUNK_SIZE, GL_RGBA, + GL_UNSIGNED_BYTE, worker->minimap_data); glBindTexture(GL_TEXTURE_2D, 0); } - if(chunk_workers[j].state == CHUNK_WORKERSTATE_IDLE && chunk_geometry_changed_lenght > 0) { + + if(worker->state == CHUNK_WORKERSTATE_IDLE && chunk_geometry_changed_lenght > 0) { float closest_dist = FLT_MAX; - int closest_index = 0; + int closest_index = -1; for(int k = 0; k < chunk_geometry_changed_lenght; k++) { - int chunk_x = (chunk_geometry_changed[k] % CHUNKS_PER_DIM) * CHUNK_SIZE; - int chunk_y = (chunk_geometry_changed[k] / CHUNKS_PER_DIM) * CHUNK_SIZE; - float l = (chunk_x - camera_x) * (chunk_x - camera_x) + (chunk_y - camera_z) * (chunk_y - camera_z); - if(l < closest_dist) { - closest_dist = l; - closest_index = k; + int can_take = 1; + + for(int i = 0; i < chunk_enabled_cores; i++) { + if(in_progress[i] && in_progress[i] == chunk_geometry_changed[k]) { + can_take = 0; + break; + } } - } - int chunk_x = (chunk_geometry_changed[closest_index] % CHUNKS_PER_DIM) * CHUNK_SIZE; - int chunk_y = (chunk_geometry_changed[closest_index] / CHUNKS_PER_DIM) * CHUNK_SIZE; - if(!chunks[chunk_geometry_changed[closest_index]].created) { - glx_displaylist_create(&chunks[chunk_geometry_changed[closest_index]].display_list); + if(can_take) { + float l = distance2D(chunk_geometry_changed[k]->x * CHUNK_SIZE, + chunk_geometry_changed[k]->y * CHUNK_SIZE, camera_x, camera_z); + if(l < closest_dist) { + closest_dist = l; + closest_index = k; + } + } } - chunk_workers[j].chunk_id = chunk_geometry_changed[closest_index]; - chunk_workers[j].chunk_x = chunk_x; - chunk_workers[j].chunk_y = chunk_y; - chunk_workers[j].state = CHUNK_WORKERSTATE_BUSY; - chunks[chunk_geometry_changed[closest_index]].last_update = window_time(); - chunks[chunk_geometry_changed[closest_index]].created = 1; + + if(closest_index >= 0) { + struct chunk* c = chunk_geometry_changed[closest_index]; + + in_progress[j] = c; + + chunk_geometry_changed[closest_index] = chunk_geometry_changed[--chunk_geometry_changed_lenght]; + + if(!c->created) { + glx_displaylist_create(&c->display_list); + c->created = 1; + } + + c->last_update = window_time(); + worker->chunk = c; + worker->chunk_x = c->x * CHUNK_SIZE; + worker->chunk_y = c->y * CHUNK_SIZE; + worker->state = CHUNK_WORKERSTATE_BUSY; + worker->blocks = map_copy_blocks(c->x, c->y, &worker->blocks_count); + worker->blocks_solid = map_copy_solids(); #ifdef OPENGL_ES - tesselator_create(&chunk_workers[j].tesselator, TESSELATE_TRIANGLES); + tesselator_create(&worker->tesselator, TESSELATE_TRIANGLES); #else - tesselator_create(&chunk_workers[j].tesselator, TESSELATE_QUADS); + tesselator_create(&worker->tesselator, TESSELATE_QUADS); #endif - pthread_cond_signal(&chunk_workers[j].can_work); - - for(int i = closest_index; i < chunk_geometry_changed_lenght - 1; i++) { - chunk_geometry_changed[i] = chunk_geometry_changed[i + 1]; + pthread_cond_signal(&worker->can_work); } - chunk_geometry_changed_lenght--; } - pthread_mutex_unlock(&chunk_workers[j].state_lock); + + pthread_mutex_unlock(&worker->state_lock); + } +} + +void chunk_rebuild_all() { + for(int d = 0; d < CHUNKS_PER_DIM * CHUNKS_PER_DIM; d++) { + chunk_geometry_changed[d] = chunks + d; } + + chunk_geometry_changed_lenght = CHUNKS_PER_DIM * CHUNKS_PER_DIM; } void chunk_block_update(int x, int y, int z) { - int d = (z / CHUNK_SIZE) * CHUNKS_PER_DIM + (x / CHUNK_SIZE); + struct chunk* c = chunks + (x / CHUNK_SIZE) + (z / CHUNK_SIZE) * CHUNKS_PER_DIM; + for(int k = 0; k < chunk_geometry_changed_lenght; k++) { - if(chunk_geometry_changed[k] == d) { + if(chunk_geometry_changed[k] == c) { return; } } - chunk_geometry_changed[chunk_geometry_changed_lenght++] = d; + + chunk_geometry_changed[chunk_geometry_changed_lenght++] = c; } diff --git a/src/chunk.h b/src/chunk.h index 86b2a51..7c45aac 100644 --- a/src/chunk.h +++ b/src/chunk.h @@ -25,6 +25,7 @@ #include "glx.h" #include "tesselator.h" +#include "libvxl.h" #define CHUNK_SIZE 16 #define CHUNKS_PER_DIM 32 @@ -34,37 +35,39 @@ extern struct chunk { int max_height; float last_update; int created; + int x, y; } chunks[CHUNKS_PER_DIM * CHUNKS_PER_DIM]; -extern int chunk_geometry_changed[CHUNKS_PER_DIM * CHUNKS_PER_DIM * 2]; -extern int chunk_geometry_changed_lenght; - -extern int chunk_lighting_changed[CHUNKS_PER_DIM * CHUNKS_PER_DIM * 2]; -extern int chunk_lighting_changed_lenght; - -extern int chunk_render_mode; - extern int chunk_enabled_cores; #define CHUNK_WORKERS_MAX 16 -#define CHUNK_WORKERSTATE_BUSY 0 -#define CHUNK_WORKERSTATE_IDLE 1 -#define CHUNK_WORKERSTATE_FINISHED 2 +enum chunk_worker_state { + CHUNK_WORKERSTATE_BUSY, + CHUNK_WORKERSTATE_IDLE, + CHUNK_WORKERSTATE_FINISHED, +}; extern struct chunk_worker { - int chunk_id; + struct chunk* chunk; int chunk_x, chunk_y; pthread_mutex_t state_lock; pthread_cond_t can_work; - int state; + enum chunk_worker_state state; pthread_t thread; int max_height; struct tesselator tesselator; + struct libvxl_block* blocks; + uint32_t blocks_count; + uint32_t* blocks_solid; uint32_t minimap_data[CHUNK_SIZE * CHUNK_SIZE]; } chunk_workers[CHUNK_WORKERS_MAX]; -extern pthread_rwlock_t* chunk_map_locks; +struct chunk_render_call { + struct chunk* chunk; + int mirror_x; + int mirror_y; +}; void chunk_init(void); @@ -72,10 +75,10 @@ void chunk_block_update(int x, int y, int z); void chunk_update_all(void); void* chunk_generate(void* data); void chunk_generate_greedy(int start_x, int start_z, struct tesselator* tess, int* max_height); -void chunk_generate_naive(int start_x, int start_z, struct tesselator* tess, int* max_height, int ao); -void chunk_render(int x, int y); +void chunk_generate_naive(int sx, int sz, struct libvxl_block* blocks, int count, uint32_t* solid, + struct tesselator* tess, int* max_height, int ao); +void chunk_render(struct chunk_render_call* c); void chunk_rebuild_all(void); -void chunk_set_render_mode(int r); void chunk_draw_visible(void); void chunk_draw_shadow_volume(float* data, int max); diff --git a/src/common.h b/src/common.h index 3e18521..a0369c9 100644 --- a/src/common.h +++ b/src/common.h @@ -76,6 +76,7 @@ void glClearDepth(float x); #define rgba(r, g, b, a) (((int)(a) << 24) | ((int)(b) << 16) | ((int)(g) << 8) | (int)(r)) #define rgb(r, g, b) (((b) << 16) | ((g) << 8) | (r)) +#define rgb2bgr(col) rgb(blue(col), green(col), red(col)) #define red(col) ((col)&0xFF) #define green(col) (((col) >> 8) & 0xFF) #define blue(col) (((col) >> 16) & 0xFF) diff --git a/src/config.c b/src/config.c index aa96411..da4fcbc 100644 --- a/src/config.c +++ b/src/config.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "window.h" #include "file.h" diff --git a/src/hud.c b/src/hud.c index 81898e8..28e56a2 100644 --- a/src/hud.c +++ b/src/hud.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include "lodepng/lodepng.h" #include "main.h" @@ -2389,7 +2391,7 @@ static void hud_serverlist_scroll(double yoffset) { static void server_c(char* address, char* name) { if(file_exists(address)) { - map_vxl_load(file_load(address), map_colors); + map_vxl_load(file_load(address), file_size(address)); chunk_rebuild_all(); camera_mode = CAMERAMODE_FPS; players[local_player_id].pos.x = map_size_x / 2.0F; diff --git a/src/main.c b/src/main.c index 9efb027..3bf9e97 100644 --- a/src/main.c +++ b/src/main.c @@ -455,12 +455,7 @@ void init() { glShadeModel(GL_SMOOTH); glDisable(GL_FOG); - map_colors = malloc(map_size_x * map_size_y * map_size_z * sizeof(unsigned int)); - CHECK_ALLOCATION_ERROR(map_colors) - memset(map_colors, (unsigned int)0xFFFFFFFF, map_size_x * map_size_y * map_size_z); - - map_heights = malloc(map_size_x * map_size_z * sizeof(uint8_t)); - CHECK_ALLOCATION_ERROR(map_heights) + map_init(); map_minimap = malloc(map_size_x * map_size_z * sizeof(unsigned char) * 4); CHECK_ALLOCATION_ERROR(map_minimap) diff --git a/src/map.c b/src/map.c index 557811a..f38e8e9 100644 --- a/src/map.c +++ b/src/map.c @@ -25,7 +25,6 @@ #include "window.h" #include "hashtable.h" -#include "minheap.h" #include "sound.h" #include "matrix.h" #include "glx.h" @@ -35,13 +34,17 @@ #include "camera.h" #include "log.h" #include "particle.h" +#include "minheap.h" + +pthread_rwlock_t map_lock; -unsigned int* map_colors; uint8_t* map_heights; int map_size_x = 512; int map_size_y = 64; int map_size_z = 512; +struct libvxl_map map; + float fog_color[4] = {0.5F, 0.9098F, 1.0F, 1.0F}; float map_sun[4]; @@ -115,7 +118,7 @@ void map_damaged_voxels_render() { glDepthFunc(GL_EQUAL); glEnable(GL_BLEND); for(int k = 0; k < 8; k++) { - if(map_get(map_damaged_voxels[k].x, map_damaged_voxels[k].y, map_damaged_voxels[k].z) == 0xFFFFFFFF) { + if(map_isair(map_damaged_voxels[k].x, map_damaged_voxels[k].y, map_damaged_voxels[k].z)) { map_damaged_voxels[k].timer = 0; } else { if(window_time() - map_damaged_voxels[k].timer <= 10.0F) { @@ -652,61 +655,49 @@ float map_sunblock(int x, int y, int z) { return (float)i / 127.0F; } -int map_isair(int x, int y, int z) { - return map_get(x, y, z) == 0xFFFFFFFF; +void map_init() { + libvxl_create(&map, 512, 512, 64, NULL, 0); + pthread_rwlock_init(&map_lock, NULL); } -unsigned int map_get(int x, int y, int z) { - if(x < 0 || y < 0 || z < 0 || x >= map_size_x || y >= map_size_y || z >= map_size_z) - return 0xFFFFFFFF; - - pthread_rwlock_rdlock(&chunk_map_locks[x + z * map_size_x]); - unsigned int ret = map_colors[x + (y * map_size_z + z) * map_size_x]; - pthread_rwlock_unlock(&chunk_map_locks[x + z * map_size_x]); - return ret; +int map_height_at(int x, int z) { + int result[2]; + pthread_rwlock_rdlock(&map_lock); + libvxl_map_gettop(&map, x, z, result); + pthread_rwlock_unlock(&map_lock); + return map_size_y - 1 - result[1]; } -int map_height(int x, int z) { - if(x < 0 || z < 0 || x >= map_size_x || z >= map_size_z) - return 0; - pthread_rwlock_rdlock(&chunk_map_locks[x + z * map_size_x]); - int ret = map_heights[x + z * map_size_x]; - pthread_rwlock_unlock(&chunk_map_locks[x + z * map_size_x]); - return ret; +int map_isair(int x, int y, int z) { + pthread_rwlock_rdlock(&map_lock); + int result = libvxl_map_issolid(&map, x, z, map_size_y - 1 - y); + pthread_rwlock_unlock(&map_lock); + return !result; } -unsigned int map_get_unblocked(int x, int y, int z) { - if(x < 0 || y < 0 || z < 0 || x >= map_size_x || y >= map_size_y || z >= map_size_z) - return 0xFFFFFFFF; - - return map_colors[x + (y * map_size_z + z) * map_size_x]; +unsigned int map_get(int x, int y, int z) { + pthread_rwlock_rdlock(&map_lock); + unsigned int result = libvxl_map_get(&map, x, z, map_size_y - 1 - y); + pthread_rwlock_unlock(&map_lock); + return rgb2bgr(result); } void map_set(int x, int y, int z, unsigned int color) { if(x < 0 || y < 0 || z < 0 || x >= map_size_x || y >= map_size_y || z >= map_size_z) return; - int offset = x + z * map_size_x; - pthread_rwlock_wrlock(&chunk_map_locks[offset]); - map_colors[x + (y * map_size_z + z) * map_size_x] = color; - if(color != 0xFFFFFFFF) { - map_heights[offset] = max(map_heights[offset], y); + pthread_rwlock_wrlock(&map_lock); + if(color == 0xFFFFFFFF) { + libvxl_map_setair(&map, x, z, map_size_y - 1 - y); } else { - if(map_heights[offset] == y) { - for(int k = y - 1; k >= 0; k--) { - if(map_get_unblocked(x, k, z) != 0xFFFFFFFF || k == 0) { - map_heights[offset] = k; - break; - } - } - } + libvxl_map_set(&map, x, z, map_size_y - 1 - y, rgb2bgr(color)); } - pthread_rwlock_unlock(&chunk_map_locks[offset]); + pthread_rwlock_unlock(&map_lock); chunk_block_update(x, y, z); - unsigned char x_off = x % CHUNK_SIZE; - unsigned char z_off = z % CHUNK_SIZE; + int x_off = x % CHUNK_SIZE; + int z_off = z % CHUNK_SIZE; if(x > 0 && x_off == 0) chunk_block_update(x - 1, y, z); @@ -735,22 +726,6 @@ void map_set(int x, int y, int z, unsigned int color) { chunk_block_update(x, y, 0); } -void map_vxl_setgeom(int x, int y, int z, unsigned int t, unsigned int* map) { - if(x < 0 || y < 0 || z < 0 || x >= map_size_x || y >= map_size_z || z >= map_size_y) - return; - - map[x + ((map_size_y - 1 - z) * map_size_z + y) * map_size_x] = t; -} - -void map_vxl_setcolor(int x, int y, int z, unsigned int t, unsigned int* map) { - if(x < 0 || y < 0 || z < 0 || x >= map_size_x || y >= map_size_z || z >= map_size_y) - return; - unsigned char r = t & 255; - unsigned char g = (t >> 8) & 255; - unsigned char b = (t >> 16) & 255; - map[x + ((map_size_y - 1 - z) * map_size_z + y) * map_size_x] = (r << 16) | (g << 8) | b; -} - // Copyright (c) Mathias Kaerlev 2011-2012 (but might be original code by Ben himself) int map_cube_line(int x1, int y1, int z1, int x2, int y2, int z2, struct Point* cube_array) { struct Point c, d; @@ -872,61 +847,37 @@ int map_placedblock_color(int color) { return color ^ (gkrand & 0x70707); } -void map_vxl_load(unsigned char* v, unsigned int* map) { - for(int k = 0; k < map_size_x * map_size_z; k++) - pthread_rwlock_wrlock(&chunk_map_locks[k]); - for(int y = 0; y < map_size_z; y++) { - for(int x = 0; x < map_size_x; x++) { - int z; - for(z = 0; z < map_size_y; z++) { - map_vxl_setgeom(x, y, z, map_dirt_color(x, map_size_y - 1 - z, y), map); - } - z = 0; - map_heights[x + y * map_size_x] = map_size_y - 1 - v[1]; - while(1) { - unsigned int* color; - int i; - int number_4byte_chunks = v[0]; - int top_color_start = v[1]; - int top_color_end = v[2]; // inclusive - int bottom_color_start; - int bottom_color_end; // exclusive - int len_top; - int len_bottom; - - for(i = z; i < top_color_start; i++) { - map_vxl_setgeom(x, y, i, 0xFFFFFFFF, map); - } - - color = (unsigned int*)(v + 4); - for(z = top_color_start; z <= top_color_end; z++) { - map_vxl_setcolor(x, y, z, *color++, map); - } +void map_vxl_load(void* v, size_t size) { + pthread_rwlock_wrlock(&map_lock); + libvxl_free(&map); + libvxl_create(&map, 512, 512, 64, v, size); + pthread_rwlock_unlock(&map_lock); +} - len_bottom = top_color_end - top_color_start + 1; +struct libvxl_block* map_copy_blocks(int chunk_x, int chunk_y, uint32_t* count) { + struct libvxl_chunk* chunk + = map.chunks + chunk_x + chunk_y * ((map_size_x + LIBVXL_CHUNK_SIZE - 1) / LIBVXL_CHUNK_SIZE); - // check for end of data marker - if(number_4byte_chunks == 0) { - // infer ACTUAL number of 4-byte chunks from the length of the color data - v += 4 * (len_bottom + 1); - break; - } + pthread_rwlock_rdlock(&map_lock); + struct libvxl_block* blocks = malloc(chunk->index * sizeof(struct libvxl_block)); + CHECK_ALLOCATION_ERROR(blocks) + memcpy(blocks, chunk->blocks, chunk->index * sizeof(struct libvxl_block)); + pthread_rwlock_unlock(&map_lock); - // infer the number of bottom colors in next span from chunk length - len_top = (number_4byte_chunks - 1) - len_bottom; + if(count) + *count = chunk->index; - // now skip the v pointer past the data to the beginning of the next span - v += v[0] * 4; + return blocks; +} - bottom_color_end = v[3]; // aka air start - bottom_color_start = bottom_color_end - len_top; +uint32_t* map_copy_solids() { + pthread_rwlock_rdlock(&map_lock); + size_t sg + = (map.width * map.height * map.depth + (sizeof(uint32_t) * 8 - 1)) / (sizeof(uint32_t) * 8) * sizeof(uint32_t); + uint32_t* blocks = malloc(sg); + CHECK_ALLOCATION_ERROR(blocks) + memcpy(blocks, map.geometry, sg); + pthread_rwlock_unlock(&map_lock); - for(z = bottom_color_start; z < bottom_color_end; z++) { - map_vxl_setcolor(x, y, z, *color++, map); - } - } - } - } - for(int k = 0; k < map_size_x * map_size_z; k++) - pthread_rwlock_unlock(&chunk_map_locks[k]); + return blocks; } diff --git a/src/map.h b/src/map.h index fd286ef..0de2e1d 100644 --- a/src/map.h +++ b/src/map.h @@ -22,8 +22,9 @@ #include -extern unsigned int* map_colors; -extern uint8_t* map_heights; +#include "libvxl.h" +#undef pos_key + extern int map_size_x; extern int map_size_y; extern int map_size_z; @@ -43,6 +44,7 @@ struct Point { int x, y, z; }; +void map_init(); int map_object_visible(float x, float y, float z); int map_damage(int x, int y, int z, int damage); int map_damage_get(int x, int y, int z); @@ -51,16 +53,17 @@ void map_update_physics(int x, int y, int z); float map_sunblock(int x, int y, int z); int map_isair(int x, int y, int z); unsigned int map_get(int x, int y, int z); -unsigned int map_get_unblocked(int x, int y, int z); -int map_height(int x, int z); void map_set(int x, int y, int z, unsigned int color); int map_cube_line(int x1, int y1, int z1, int x2, int y2, int z2, struct Point* cube_array); void map_vxl_setgeom(int x, int y, int z, unsigned int t, unsigned int* map); void map_vxl_setcolor(int x, int y, int z, unsigned int t, unsigned int* map); int map_dirt_color(int x, int y, int z); int map_placedblock_color(int color); -void map_vxl_load(unsigned char* v, unsigned int* map); +void map_vxl_load(void* v, size_t size); void map_collapsing_render(void); void map_collapsing_update(float dt); +int map_height_at(int x, int z); +struct libvxl_block* map_copy_blocks(int chunk_x, int chunk_y, uint32_t* count); +uint32_t* map_copy_solids(void); #endif diff --git a/src/network.c b/src/network.c index ddf8c5b..a398321 100644 --- a/src/network.c +++ b/src/network.c @@ -305,7 +305,7 @@ void read_PacketStateData(void* data, int len) { CHECK_ALLOCATION_ERROR(decompressed) } if(r == LIBDEFLATE_SUCCESS) { - map_vxl_load(decompressed, map_colors); + map_vxl_load(decompressed, decompressed_size); #ifndef USE_TOUCH char filename[128]; sprintf(filename, "cache/%08X.vxl", libdeflate_crc32(0, decompressed, decompressed_size)); @@ -438,7 +438,7 @@ void read_PacketMapStart(void* data, int len) { if(file_exists(filename)) { network_map_cached = 1; void* mapd = file_load(filename); - map_vxl_load(mapd, map_colors); + map_vxl_load(mapd, file_size(filename)); free(mapd); chunk_rebuild_all(); } @@ -552,9 +552,6 @@ void read_PacketKillAction(void* data, int len) { struct PacketKillAction* p = (struct PacketKillAction*)data; if(p->player_id < PLAYERS_MAX && p->killer_id < PLAYERS_MAX && p->kill_type >= 0 && p->kill_type < 7) { if(p->player_id == local_player_id) { - camera_mode = CAMERAMODE_BODYVIEW; - cameracontroller_bodyview_player = local_player_id; - cameracontroller_bodyview_zoom = 0.0F; local_player_death_time = window_time(); local_player_respawn_time = p->respawn_time; local_player_respawn_cnt_last = 255; @@ -565,6 +562,10 @@ void read_PacketKillAction(void* data, int len) { local_player_last_damage_x = players[p->killer_id].pos.x; local_player_last_damage_y = players[p->killer_id].pos.y; local_player_last_damage_z = players[p->killer_id].pos.z; + cameracontroller_death_init(local_player_id, players[p->killer_id].pos.x, players[p->killer_id].pos.y, + players[p->killer_id].pos.z); + } else { + cameracontroller_death_init(local_player_id, 0, 0, 0); } } players[p->player_id].alive = 0; diff --git a/src/player.c b/src/player.c index 3ab4896..a2b1d7c 100644 --- a/src/player.c +++ b/src/player.c @@ -19,6 +19,7 @@ #include #include +#include #include "common.h" #include "camera.h" @@ -498,7 +499,7 @@ void player_render(struct Player* p, int id, Ray* ray, char render, struct playe float oz = p->orientation_smooth.z / l; if(!p->alive) { - if(render) { + if(render && (id != local_player_id || camera_mode != CAMERAMODE_DEATH)) { matrix_push(); matrix_translate(p->pos.x, p->pos.y + 0.25F, p->pos.z); matrix_pointAt(ox, 0.0F, oz); diff --git a/src/rpc.c b/src/rpc.c index 4e60fc4..88df6a2 100644 --- a/src/rpc.c +++ b/src/rpc.c @@ -19,6 +19,13 @@ #include +#ifdef USE_RPC +#include +#endif + +#include "common.h" +#include "log.h" +#include "player.h" #include "rpc.h" struct rpc { diff --git a/src/tracer.c b/src/tracer.c index a6393bf..342c1a9 100644 --- a/src/tracer.c +++ b/src/tracer.c @@ -100,6 +100,6 @@ void tracer_update(float dt) { } void tracer_init() { - tracers = calloc(sizeof(struct Tracer) * TRACER_MAX, 1); + tracers = calloc(TRACER_MAX, sizeof(struct Tracer)); CHECK_ALLOCATION_ERROR(tracers) }