From 50967aa046af01f0c760e26affd15868ca9823ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Madar=C3=A1sz?= Date: Sun, 16 Oct 2022 00:49:29 +0200 Subject: [PATCH] z ordering for outer blocks + improve entity aabb collisions --- code/foundation/src/core/game.c | 42 +++++++++++++++++------- code/foundation/src/debug/debug_draw.c | 6 ++-- code/foundation/src/debug/debug_ui.c | 1 + code/foundation/src/platform/profiler.c | 9 +++--- code/foundation/src/platform/profiler.h | 7 ++-- code/foundation/src/platform/renderer.h | 11 ++++++- code/foundation/src/systems/systems.c | 43 +++++++++++++++++++++---- code/foundation/src/world/world.c | 6 ++++ code/foundation/src/world/world.h | 1 + code/games/minimal/src/renderer.c | 23 ++++++------- code/games/sandbox/src/renderer.c | 42 +++++++++++++++--------- 11 files changed, 133 insertions(+), 58 deletions(-) diff --git a/code/foundation/src/core/game.c b/code/foundation/src/core/game.c index 5357503..3b87d6f 100644 --- a/code/foundation/src/core/game.c +++ b/code/foundation/src/core/game.c @@ -269,29 +269,46 @@ void game_request_close() { } } -typedef struct { - uint64_t key; - entity_view *data; - zpl_f32 y; -} game_world_render_entry; - static game_world_render_entry* render_queue = NULL; static void game__world_view_render_push_entry(uint64_t key, entity_view * data) { - if (data->kind == EKIND_CHUNK) return; if (!data) return; + if (data->kind == EKIND_CHUNK) { + world_view *view = game_world_view_get_active(); + float size = (float)(view->chunk_size * WORLD_BLOCK_SIZE); + float offset = 0.0; + for (size_t ty = 0; ty < view->chunk_size; ty++) { + for (size_t tx = 0; tx < view->chunk_size; tx++) { + block_id blk_id = data->outer_blocks[(ty*view->chunk_size)+tx]; + if (blk_id != 0) { + game_world_render_entry entry = { + .key = key, + .data = data, + .blk_id = blk_id, + .x = (data->x*size + offset) + (float)tx*WORLD_BLOCK_SIZE + WORLD_BLOCK_SIZE/2, + .y = (data->y*size + offset) + (float)ty*WORLD_BLOCK_SIZE + WORLD_BLOCK_SIZE/2, + }; + zpl_array_append(render_queue, entry); + } + } + } + return; + } + game_world_render_entry entry = { .key = key, .data = data, + .x = data->x, .y = data->y, + .blk_id = 0, }; zpl_array_append(render_queue, entry); } static void game__world_view_render_ground(uint64_t key, entity_view * data) { if (data->kind != EKIND_CHUNK) return; - renderer_draw_entry(key, data); + renderer_draw_entry(key, data, 0); } void game_world_view_render_world(void) { @@ -300,12 +317,15 @@ void game_world_view_render_world(void) { } zpl_array_clear(render_queue); - game_world_view_active_entity_map(game__world_view_render_push_entry); - zpl_sort_array(render_queue, zpl_array_count(render_queue), zpl_f32_cmp(zpl_offset_of(game_world_render_entry, y))); + + profile(PROF_RENDER_PUSH_AND_SORT_ENTRIES) { + game_world_view_active_entity_map(game__world_view_render_push_entry); + zpl_sort_array(render_queue, zpl_array_count(render_queue), zpl_f32_cmp(zpl_offset_of(game_world_render_entry, y))); + } game_world_view_active_entity_map(game__world_view_render_ground); for (zpl_isize i = 0; i < zpl_array_count(render_queue); i++) { - renderer_draw_entry(render_queue[i].key, render_queue[i].data); + renderer_draw_entry(render_queue[i].key, render_queue[i].data, &render_queue[i]); } } diff --git a/code/foundation/src/debug/debug_draw.c b/code/foundation/src/debug/debug_draw.c index a6b4982..38ecd96 100644 --- a/code/foundation/src/debug/debug_draw.c +++ b/code/foundation/src/debug/debug_draw.c @@ -36,7 +36,7 @@ void debug_push_line(debug_v2 a, debug_v2 b, int32_t color) { debug_push_entry((debug_draw_entry){ .kind = DDRAW_LINE, .color = color, - + .a = a, .b = b, }); @@ -46,7 +46,7 @@ void debug_push_circle(debug_v2 pos, float radius, int32_t color) { debug_push_entry((debug_draw_entry){ .kind = DDRAW_CIRCLE, .color = color, - + .pos = pos, .radius = radius, }); @@ -56,7 +56,7 @@ void debug_push_rect(debug_v2 bmin, debug_v2 bmax, int32_t color) { debug_push_entry((debug_draw_entry){ .kind = DDRAW_RECT, .color = color, - + .bmin = bmin, .bmax = bmax, }); diff --git a/code/foundation/src/debug/debug_ui.c b/code/foundation/src/debug/debug_ui.c index 25c555c..a6c934e 100644 --- a/code/foundation/src/debug/debug_ui.c +++ b/code/foundation/src/debug/debug_ui.c @@ -232,6 +232,7 @@ static debug_item items[] = { { .kind = DITEM_RAW, .val = PROF_UPDATE_SYSTEMS, .proc = DrawProfilerDelta }, { .kind = DITEM_RAW, .val = PROF_ENTITY_LERP, .proc = DrawProfilerDelta }, { .kind = DITEM_RAW, .val = PROF_INTEGRATE_POS, .proc = DrawProfilerDelta }, + { .kind = DITEM_RAW, .val = PROF_RENDER_PUSH_AND_SORT_ENTRIES, .proc = DrawProfilerDelta }, { .kind = DITEM_END }, }, .is_collapsed = 1 diff --git a/code/foundation/src/platform/profiler.c b/code/foundation/src/platform/profiler.c index e6a54b1..aad891b 100644 --- a/code/foundation/src/platform/profiler.c +++ b/code/foundation/src/platform/profiler.c @@ -15,6 +15,7 @@ static profiler profilers[] = { { .id = PROF_UPDATE_SYSTEMS, .name = "update systems" }, { .id = PROF_ENTITY_LERP, .name = "entity lerp" }, { .id = PROF_INTEGRATE_POS, .name = "entity movement" }, + { .id = PROF_RENDER_PUSH_AND_SORT_ENTRIES, .name = "push&sort entries" }, }; static_assert((sizeof(profilers)/sizeof(profilers[0])) == MAX_PROF, "mismatched profilers"); @@ -44,18 +45,18 @@ void profiler_collate() { } static double frame_counter = 0.0; static uint64_t frames = 0; - + frame_counter += GetFrameTime(); frames++; - + if (frame_counter >= PROF_COLLATE_WINDOW) { profilers[PROF_TOTAL_TIME].delta_time = frame_counter / (double)frames; - + for (uint32_t i = PROF_MAIN_LOOP; i < MAX_PROF; i += 1) { profiler *p = &profilers[i]; p->delta_time = p->num_invocations == 0 ? 0.0 : p->total_time / (double)p->num_invocations; } - + frame_counter = 0.0; frames = 0; } diff --git a/code/foundation/src/platform/profiler.h b/code/foundation/src/platform/profiler.h index bacd086..fb098c2 100644 --- a/code/foundation/src/platform/profiler.h +++ b/code/foundation/src/platform/profiler.h @@ -4,13 +4,14 @@ typedef enum { PROF_TOTAL_TIME, PROF_MAIN_LOOP, - + PROF_WORLD_WRITE, PROF_RENDER, PROF_UPDATE_SYSTEMS, PROF_ENTITY_LERP, PROF_INTEGRATE_POS, - + PROF_RENDER_PUSH_AND_SORT_ENTRIES, + MAX_PROF, PROF_FORCE_UINT8 = UINT8_MAX } profiler_kind; @@ -18,7 +19,7 @@ typedef enum { typedef struct { profiler_kind id; char const *name; - + uint32_t num_invocations; double start_time; double delta_time; diff --git a/code/foundation/src/platform/renderer.h b/code/foundation/src/platform/renderer.h index 3110bf2..5ba3db3 100644 --- a/code/foundation/src/platform/renderer.h +++ b/code/foundation/src/platform/renderer.h @@ -1,14 +1,23 @@ #pragma once #include "platform/system.h" #include "world/entity_view.h" +#include "world/blocks.h" #include "raylib.h" +typedef struct { + uint64_t key; + entity_view *data; + float x; + float y; + block_id blk_id; +} game_world_render_entry; + void renderer_draw(void); void renderer_init(void); void renderer_shutdown(void); void renderer_debug_draw(void); float renderer_zoom_get(void); void renderer_draw_single(float x, float y, asset_id id, Color color); -void renderer_draw_entry(uint64_t key, entity_view * data); +void renderer_draw_entry(uint64_t key, entity_view * data, game_world_render_entry* entry); void renderer_bake_chunk(uint64_t key, entity_view * data); void renderer_switch(int kind); diff --git a/code/foundation/src/systems/systems.c b/code/foundation/src/systems/systems.c index 4507083..ab10f0a 100644 --- a/code/foundation/src/systems/systems.c +++ b/code/foundation/src/systems/systems.c @@ -19,11 +19,15 @@ #include "modules/system_producer.c" #include "modules/system_blueprint.c" -static inline float physics_correction(float x, float vx, float bounce) { - float r = (((zpl_max(0.0f, (WORLD_BLOCK_SIZE/2.0f) - zpl_abs(x))*zpl_sign(x)))*(WORLD_BLOCK_SIZE/2.0f)); +static inline float physics_correction(float x, float vx, float bounce, float dim) { + float r = (((zpl_max(0.0f, dim - zpl_abs(x))*zpl_sign(x)))*dim); return r + (-vx*bounce); } +static inline bool physics_check_aabb(float a1x, float a2x, float a1y, float a2y, float b1x, float b2x, float b1y, float b2y) { + return (a1x < b2x && a2x > b1x && a1y < b2y && a2y > b1y); +} + void IntegratePositions(ecs_iter_t *it) { profile(PROF_INTEGRATE_POS) { Position *p = ecs_field(it, Position, 1); @@ -47,8 +51,15 @@ void IntegratePositions(ecs_iter_t *it) { world_block_lookup lookup = world_block_from_realpos(p[i].x+PHY_LOOKAHEAD(v[i].x), p[i].y); uint32_t flags = blocks_get_flags(lookup.bid); float bounce = blocks_get_bounce(lookup.bid); - if (flags & BLOCK_FLAG_COLLISION) { - v[i].x = physics_correction(lookup.ox, v[i].x, bounce); + if (flags & BLOCK_FLAG_COLLISION && physics_check_aabb(p[i].x-WORLD_BLOCK_SIZE/4, p[i].x+WORLD_BLOCK_SIZE/4, p[i].y-0.5f, p[i].y+0.5f, lookup.aox-WORLD_BLOCK_SIZE/2, lookup.aox+WORLD_BLOCK_SIZE/2, lookup.aoy-WORLD_BLOCK_SIZE/2, lookup.aoy+WORLD_BLOCK_SIZE/2)) { + #if 1 + { + debug_v2 a = {p[i].x-WORLD_BLOCK_SIZE/4 + PHY_LOOKAHEAD(v[i].x), p[i].y-0.5f}; + debug_v2 b = {p[i].x+WORLD_BLOCK_SIZE/4 + PHY_LOOKAHEAD(v[i].x), p[i].y+0.5f}; + debug_push_rect(a, b, 0xFF0000FF); + } + #endif + v[i].x = physics_correction(lookup.ox, v[i].x, bounce, WORLD_BLOCK_SIZE/2); } } @@ -57,8 +68,22 @@ void IntegratePositions(ecs_iter_t *it) { world_block_lookup lookup = world_block_from_realpos(p[i].x, p[i].y+PHY_LOOKAHEAD(v[i].y)); uint32_t flags = blocks_get_flags(lookup.bid); float bounce = blocks_get_bounce(lookup.bid); - if (flags & BLOCK_FLAG_COLLISION) { - v[i].y = physics_correction(lookup.oy, v[i].y, bounce); + #if 0 + { + debug_v2 a = {lookup.aox-WORLD_BLOCK_SIZE/2, lookup.aoy-WORLD_BLOCK_SIZE/2}; + debug_v2 b = {lookup.aox+WORLD_BLOCK_SIZE/2, lookup.aoy+WORLD_BLOCK_SIZE/2}; + debug_push_rect(a, b, 0xFFFFFFFF); + } + #endif + if (flags & BLOCK_FLAG_COLLISION && physics_check_aabb(p[i].x-WORLD_BLOCK_SIZE/4, p[i].x+WORLD_BLOCK_SIZE/4, p[i].y-0.5f, p[i].y+0.5f, lookup.aox-WORLD_BLOCK_SIZE/2, lookup.aox+WORLD_BLOCK_SIZE/2, lookup.aoy-WORLD_BLOCK_SIZE/2, lookup.aoy+WORLD_BLOCK_SIZE/2)) { + #if 1 + { + debug_v2 a = {p[i].x-WORLD_BLOCK_SIZE/4, p[i].y-0.5f + PHY_LOOKAHEAD(v[i].y)}; + debug_v2 b = {p[i].x+WORLD_BLOCK_SIZE/4, p[i].y+0.5f + PHY_LOOKAHEAD(v[i].y)}; + debug_push_rect(a, b, 0xFF0000FF); + } + #endif + v[i].y = physics_correction(lookup.oy, v[i].y, bounce, WORLD_BLOCK_SIZE/4); } } #endif @@ -71,6 +96,12 @@ void IntegratePositions(ecs_iter_t *it) { debug_v2 b = {p[i].x+v[i].x, p[i].y+v[i].y}; debug_push_line(a, b, 0xFFFFFFFF); } + + { + debug_v2 a = {p[i].x-WORLD_BLOCK_SIZE/4, p[i].y-0.5f}; + debug_v2 b = {p[i].x+WORLD_BLOCK_SIZE/4, p[i].y+0.5f}; + debug_push_rect(a, b, 0xFFFFFFFF); + } } } } diff --git a/code/foundation/src/world/world.c b/code/foundation/src/world/world.c index 18548a0..d5cfaf1 100644 --- a/code/foundation/src/world/world.c +++ b/code/foundation/src/world/world.c @@ -488,6 +488,10 @@ world_block_lookup world_block_from_realpos(float x, float y) { float box = chx - bx * WORLD_BLOCK_SIZE - WORLD_BLOCK_SIZE/2.0f; float boy = chy - by * WORLD_BLOCK_SIZE - WORLD_BLOCK_SIZE/2.0f; + // NOTE(zaklaus): absolute pos in world. + float abox = (uint16_t)(x / WORLD_BLOCK_SIZE) * (float)WORLD_BLOCK_SIZE + WORLD_BLOCK_SIZE/2.0f; + float aboy = (uint16_t)(y / WORLD_BLOCK_SIZE) * (float)WORLD_BLOCK_SIZE + WORLD_BLOCK_SIZE/2.0f; + world_block_lookup lookup = { .id = block_idx, .bid = bid, @@ -495,6 +499,8 @@ world_block_lookup world_block_from_realpos(float x, float y) { .chunk_e = e, .ox = box, .oy = boy, + .aox = abox, + .aoy = aboy, .is_outer = is_outer, }; diff --git a/code/foundation/src/world/world.h b/code/foundation/src/world/world.h index e7ef6a9..9316bd6 100644 --- a/code/foundation/src/world/world.h +++ b/code/foundation/src/world/world.h @@ -83,6 +83,7 @@ typedef struct { ecs_entity_t chunk_e; int64_t chunk_id; float ox, oy; + float aox, aoy; bool is_outer; } world_block_lookup; diff --git a/code/games/minimal/src/renderer.c b/code/games/minimal/src/renderer.c index e26b366..f7b732a 100644 --- a/code/games/minimal/src/renderer.c +++ b/code/games/minimal/src/renderer.c @@ -39,7 +39,7 @@ void DEBUG_draw_overlay(uint64_t key, entity_view * data) { } } -void renderer_draw_entry(uint64_t key, entity_view *data) { +void renderer_draw_entry(uint64_t key, entity_view *data, game_world_render_entry* entry) { float size = 16.f; switch (data->kind) { @@ -51,19 +51,14 @@ void renderer_draw_entry(uint64_t key, entity_view *data) { float x = data->x * size + offset; float y = data->y * size + offset; - RenderTexture2D tex = GetChunkTexture(key); - float scale = (size)/(float)(tex.texture.width); - tex.texture.width *= (int32_t)scale; - tex.texture.height *= (int32_t)scale; - DrawTextureRec(tex.texture, (Rectangle){0, 0, size, -size}, (Vector2){x, y}, ColorAlpha(WHITE, data->tran_time)); - - for (size_t ty = 0; ty < view->chunk_size; ty++) { - for (size_t tx = 0; tx < view->chunk_size; tx++) { - block_id blk_id = data->outer_blocks[(ty*view->chunk_size)+tx]; - if (blk_id != 0) { - DrawTextureRec(GetBlockImage(blk_id), ASSET_SRC_RECT(), (Vector2){x+tx*WORLD_BLOCK_SIZE, y+ty*WORLD_BLOCK_SIZE}, ColorAlpha(WHITE, data->tran_time)); - } - } + if (entry == NULL) { + RenderTexture2D tex = GetChunkTexture(key); + float scale = (size)/(float)(tex.texture.width); + tex.texture.width *= (int32_t)scale; + tex.texture.height *= (int32_t)scale; + DrawTextureRec(tex.texture, (Rectangle){0, 0, size, -size}, (Vector2){x, y}, ColorAlpha(WHITE, data->tran_time)); + } else { + DrawTextureRec(GetBlockImage(entry->blk_id), ASSET_SRC_RECT(), (Vector2){entry->x-(WORLD_BLOCK_SIZE/2), entry->y-(WORLD_BLOCK_SIZE/2)}, ColorAlpha(WHITE, data->tran_time)); } }break; case EKIND_VEHICLE: { diff --git a/code/games/sandbox/src/renderer.c b/code/games/sandbox/src/renderer.c index b709633..a152377 100644 --- a/code/games/sandbox/src/renderer.c +++ b/code/games/sandbox/src/renderer.c @@ -41,7 +41,7 @@ void DEBUG_draw_overlay(uint64_t key, entity_view * data) { extern bool inv_is_open; -void renderer_draw_entry(uint64_t key, entity_view *data) { +void renderer_draw_entry(uint64_t key, entity_view *data, game_world_render_entry* entry) { float size = 16.f; switch (data->kind) { @@ -53,19 +53,14 @@ void renderer_draw_entry(uint64_t key, entity_view *data) { float x = data->x * size + offset; float y = data->y * size + offset; - RenderTexture2D tex = GetChunkTexture(key); - float scale = (size)/(float)(tex.texture.width); - tex.texture.width *= (int32_t)scale; - tex.texture.height *= (int32_t)scale; - DrawTextureRec(tex.texture, (Rectangle){0, 0, size, -size}, (Vector2){x, y}, ColorAlpha(WHITE, data->tran_time)); - - for (size_t ty = 0; ty < view->chunk_size; ty++) { - for (size_t tx = 0; tx < view->chunk_size; tx++) { - block_id blk_id = data->outer_blocks[(ty*view->chunk_size)+tx]; - if (blk_id != 0) { - DrawTextureRec(GetBlockImage(blk_id), ASSET_SRC_RECT(), (Vector2){x+tx*WORLD_BLOCK_SIZE, y+ty*WORLD_BLOCK_SIZE}, ColorAlpha(WHITE, data->tran_time)); - } - } + if (entry == NULL) { + RenderTexture2D tex = GetChunkTexture(key); + float scale = (size)/(float)(tex.texture.width); + tex.texture.width *= (int32_t)scale; + tex.texture.height *= (int32_t)scale; + DrawTextureRec(tex.texture, (Rectangle){0, 0, size, -size}, (Vector2){x, y}, ColorAlpha(WHITE, data->tran_time)); + } else { + DrawTextureRec(GetBlockImage(entry->blk_id), ASSET_SRC_RECT(), (Vector2){entry->x-(WORLD_BLOCK_SIZE/2), entry->y-(WORLD_BLOCK_SIZE/2)}, ColorAlpha(WHITE, data->tran_time)); } }break; case EKIND_VEHICLE: { @@ -94,15 +89,25 @@ void renderer_draw_entry(uint64_t key, entity_view *data) { case EKIND_DEMO_NPC: { float x = data->x; float y = data->y; + if (!data->inside_vehicle) { + DrawCircleEco(x, y, size, ColorAlpha(BLUE, data->tran_time)); + } else { + y -= 32.f; + } DrawNametag("Demo", key, data, x, y); - DrawCircleEco(x, y, size, ColorAlpha(BLUE, data->tran_time)); }break; case EKIND_PLAYER: { float x = data->x; float y = data->y; float health = (data->hp / data->max_hp); + + if (!data->inside_vehicle) { + DrawCircleEco(x, y, size, ColorAlpha(YELLOW, data->tran_time)); + } else { + y -= 32.f; + } + DrawNametag("Player", key, data, x, y); - DrawCircleEco(x, y, size, ColorAlpha(YELLOW, data->tran_time)); if (data->has_items && !data->inside_vehicle) { float ix = data->x; @@ -120,6 +125,11 @@ void renderer_draw_entry(uint64_t key, entity_view *data) { case EKIND_MACRO_BOT: { float x = data->x; float y = data->y; + if (!data->inside_vehicle) { + DrawCircleEco(x, y, size, ColorAlpha(GREEN, data->tran_time)); + } else { + y -= 32.f; + } DrawNametag("Bot", key, data, x, y); }break; case EKIND_ITEM: {