From 478f077030d45e5e125c1b6ac56e912ac7af0cde Mon Sep 17 00:00:00 2001 From: jacob Date: Wed, 21 May 2025 16:59:54 -0500 Subject: [PATCH] tile chunk testing --- src/font.c | 2 +- src/math.h | 15 +++++ src/renderer.h | 3 +- src/renderer_d3d11.c | 10 +++- src/sim.c | 76 ++++++++++++++++++++++++ src/sim.h | 13 +++- src/sim_ent.c | 22 +++---- src/sim_ent.h | 20 +++++-- src/sim_step.c | 138 +++++++++++++++++++++++++++++++++---------- src/string.h | 2 +- src/user.c | 83 +++++++++++++++++++------- src/util.h | 34 +++++++---- 12 files changed, 332 insertions(+), 86 deletions(-) diff --git a/src/font.c b/src/font.c index 56c9a481..6c56bb79 100644 --- a/src/font.c +++ b/src/font.c @@ -174,7 +174,7 @@ struct asset *font_load_asset(struct string path, f32 point_size, b32 help) struct string key = string_format(scratch.arena, LIT("%F%F_font"), FMT_STR(path), - FMT_FLOAT_P((f64)point_size, 3)); + FMT_FLOAT_P((f64)point_size, 1)); u64 hash = asset_cache_hash(key); b32 is_first_touch; struct asset *asset = asset_cache_touch(key, hash, &is_first_touch); diff --git a/src/math.h b/src/math.h index 2f3be9a2..03fcc4a2 100644 --- a/src/math.h +++ b/src/math.h @@ -839,6 +839,21 @@ INLINE b32 v2i32_eq(struct v2i32 a, struct v2i32 b) return a.x == b.x && a.y == b.y; } +INLINE struct v2i32 v2i32_neg(struct v2i32 a) +{ + return V2I32(-a.x, -a.y); +} + +INLINE struct v2i32 v2i32_add(struct v2i32 a, struct v2i32 b) +{ + return V2I32(a.x + b.x, a.y + b.y); +} + +INLINE struct v2i32 v2i32_sub(struct v2i32 a, struct v2i32 b) +{ + return V2I32(a.x - b.x, a.y - b.y); +} + /* ========================== * * Mat4x4 * ========================== */ diff --git a/src/renderer.h b/src/renderer.h index 4c0b2047..5374e2c2 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -2,7 +2,6 @@ #define RENDERER_H struct sys_window; -struct sprite_scope; #define RENDERER_TEXTURE_MAX_WIDTH 16384 #define RENDERER_TEXTURE_MAX_HEIGHT 16384 @@ -81,7 +80,7 @@ struct renderer_texture renderer_texture_alloc(enum renderer_texture_format form void renderer_texture_release(struct renderer_texture t); void renderer_texture_clear(struct renderer_texture target_texture, u32 clear_color); -void renderer_texture_render(struct renderer_texture texture, struct renderer_cmd_buffer *cmdbuff, struct xform view, struct rect viewport, struct sprite_scope *sprite_scope); +void renderer_texture_render(struct renderer_texture texture, struct renderer_cmd_buffer *cmdbuff, struct xform view, struct rect viewport); struct v2i32 renderer_texture_get_size(struct renderer_texture texture); /* ========================== * diff --git a/src/renderer_d3d11.c b/src/renderer_d3d11.c index 18048967..889c823f 100644 --- a/src/renderer_d3d11.c +++ b/src/renderer_d3d11.c @@ -638,10 +638,12 @@ struct renderer_startup_receipt renderer_startup(struct sys_window *window) * Another option is to store a separate device on each cmdbuff? * * I'm thinking we may also just need to lock texture modification access while presenting */ -INTERNAL void dx11_render(ID3D11RenderTargetView *target, struct renderer_cmd_buffer *cmdbuff, struct xform view, struct rect viewport, struct sprite_scope *sprite_scope) +INTERNAL void dx11_render(ID3D11RenderTargetView *target, struct renderer_cmd_buffer *cmdbuff, struct xform view, struct rect viewport) { __prof; __profscope_d3d11(G.profiling_ctx, Render); + struct sprite_scope *sprite_scope = sprite_scope_begin(); + ID3D11DeviceContext_OMSetRenderTargets(G.devcon, 1, &target, NULL); D3D11_VIEWPORT d3d11_viewport = ZI; @@ -754,6 +756,8 @@ INTERNAL void dx11_render(ID3D11RenderTargetView *target, struct renderer_cmd_bu } break; } } + + sprite_scope_end(sprite_scope); } /* ========================== * @@ -900,7 +904,7 @@ void renderer_texture_clear(struct renderer_texture target_texture, u32 clear_co } } -void renderer_texture_render(struct renderer_texture texture, struct renderer_cmd_buffer *cmdbuff, struct xform view, struct rect viewport, struct sprite_scope *sprite_scope) +void renderer_texture_render(struct renderer_texture texture, struct renderer_cmd_buffer *cmdbuff, struct xform view, struct rect viewport) { __prof; @@ -909,7 +913,7 @@ void renderer_texture_render(struct renderer_texture texture, struct renderer_cm ID3D11RenderTargetView *target_view = NULL; ID3D11Device_CreateRenderTargetView(G.dev, (ID3D11Resource *)t->texture, NULL, &target_view); if (target_view) { - dx11_render(target_view, cmdbuff, view, viewport, sprite_scope); + dx11_render(target_view, cmdbuff, view, viewport); } if (target_view) { diff --git a/src/sim.c b/src/sim.c index 01e1c307..3bebb15f 100644 --- a/src/sim.c +++ b/src/sim.c @@ -543,6 +543,82 @@ struct sim_snapshot *sim_snapshot_from_closest_tick_gte(struct sim_client *clien return ss; } +/* ========================== * + * Tile + * ========================== */ + +struct v2i32 sim_world_tile_index_from_pos(struct v2 pos) +{ + struct v2i32 res = V2I32(pos.x * SIM_TILES_PER_UNIT_SQRT, pos.y * SIM_TILES_PER_UNIT_SQRT); + res.x -= pos.x < 0; + res.y -= pos.y < 0; + return res; +} + +struct v2 sim_pos_from_world_tile_index(struct v2i32 world_tile_index) +{ + struct v2 res = ZI; + f32 tile_size = 1.f / SIM_TILES_PER_UNIT_SQRT; + res.x = (f32)world_tile_index.x * tile_size; + res.y = (f32)world_tile_index.y * tile_size; + if (world_tile_index.x < 0) { + res.x += tile_size; + } + if (world_tile_index.y < 0) { + res.y += tile_size; + } + return res; +} + +struct v2i32 sim_local_tile_index_from_world_tile_index(struct v2i32 world_tile_index) +{ + struct v2i32 res = ZI; + res.x = world_tile_index.x % SIM_TILES_PER_CHUNK_SQRT; + res.y = world_tile_index.y % SIM_TILES_PER_CHUNK_SQRT; + if (world_tile_index.x < 0) { + res.x = SIM_TILES_PER_CHUNK_SQRT + res.x - 1; + } + if (world_tile_index.y < 0) { + res.y = SIM_TILES_PER_CHUNK_SQRT + res.y - 1; + } + return res; +} + +struct v2i32 sim_world_tile_index_from_local_tile_index(struct v2i32 tile_chunk_index, struct v2i32 local_tile_index) +{ + struct v2i32 res = ZI; + res.x = (tile_chunk_index.x * SIM_TILES_PER_CHUNK_SQRT) + local_tile_index.x; + res.y = (tile_chunk_index.y * SIM_TILES_PER_CHUNK_SQRT) + local_tile_index.y; + return res; +} + +struct v2i32 sim_tile_chunk_index_from_world_tile_index(struct v2i32 world_tile_index) +{ + struct v2i32 res = ZI; + res.x = world_tile_index.x / SIM_TILES_PER_CHUNK_SQRT; + res.y = world_tile_index.y / SIM_TILES_PER_CHUNK_SQRT; + res.x -= world_tile_index.x < 0; + res.y -= world_tile_index.y < 0; + return res; +} + +void sim_snapshot_set_tile(struct sim_snapshot *ss, struct v2i32 world_tile_index, enum sim_tile_kind tile_kind) +{ + struct v2i32 chunk_index = sim_tile_chunk_index_from_world_tile_index(world_tile_index); + + struct sim_ent_id chunk_id = sim_ent_tile_chunk_id_from_tile_chunk_index(chunk_index); + struct sim_ent *chunk_ent = sim_ent_from_id(ss, chunk_id); + if (!chunk_ent->valid) { + struct sim_ent *root = sim_ent_from_id(ss, SIM_ENT_ROOT_ID); + chunk_ent = sim_ent_alloc_sync_src_with_id(root, chunk_id); + sim_ent_enable_prop(chunk_ent, SEPROP_TILE_CHUNK); + chunk_ent->tile_chunk_index = chunk_index; + } + + struct v2i32 local_index = sim_local_tile_index_from_world_tile_index(world_tile_index); + chunk_ent->tile_chunk_tiles[local_index.x + (local_index.y * SIM_TILES_PER_CHUNK_SQRT)] = tile_kind; +} + /* ========================== * * Snapshot lerp * ========================== */ diff --git a/src/sim.h b/src/sim.h index 6e74dd16..119324f8 100644 --- a/src/sim.h +++ b/src/sim.h @@ -167,8 +167,11 @@ enum sim_cmd_kind { enum sim_tile_kind { SIM_TILE_KIND_NONE, - SIM_TILE_KIND_TEST + SIM_TILE_KIND_WALL, + + NUM_SIM_TILE_KINDS }; +CT_ASSERT(NUM_SIM_TILE_KINDS < 256); /* Tile kind must fit in 8 bits */ struct sim_ent_bin; @@ -228,6 +231,14 @@ struct sim_snapshot *sim_snapshot_from_tick(struct sim_client *client, u64 tick) struct sim_snapshot *sim_snapshot_from_closest_tick_lte(struct sim_client *client, u64 tick); struct sim_snapshot *sim_snapshot_from_closest_tick_gte(struct sim_client *client, u64 tick); +/* Tile */ +struct v2i32 sim_world_tile_index_from_pos(struct v2 pos); +struct v2 sim_pos_from_world_tile_index(struct v2i32 world_tile_index); +struct v2i32 sim_local_tile_index_from_world_tile_index(struct v2i32 world_tile_index); +struct v2i32 sim_world_tile_index_from_local_tile_index(struct v2i32 tile_chunk_index, struct v2i32 local_tile_index); +struct v2i32 sim_tile_chunk_index_from_world_tile_index(struct v2i32 world_tile_index); +void sim_snapshot_set_tile(struct sim_snapshot *ss, struct v2i32 world_tile_index, enum sim_tile_kind tile_kind); + /* Lerp */ struct sim_snapshot *sim_snapshot_alloc_from_lerp(struct sim_client *client, struct sim_snapshot *ss0, struct sim_snapshot *ss1, f64 blend); diff --git a/src/sim_ent.c b/src/sim_ent.c index fb8ea438..f4172c4a 100644 --- a/src/sim_ent.c +++ b/src/sim_ent.c @@ -296,12 +296,11 @@ struct sim_ent_id sim_ent_collision_debug_id_from_ids(struct sim_ent_id player_i } /* Returns the deterministic id of the tile chunk that should be produced at chunk pos */ -struct sim_ent_id sim_ent_chunk_id_from_chunk_pos(struct sim_ent_id player_id, struct v2i32 chunk_pos) +struct sim_ent_id sim_ent_tile_chunk_id_from_tile_chunk_index(struct v2i32 chunk_index) { struct sim_ent_id res = ZI; res.uid = SIM_ENT_TILE_CHUNK_BASIS_UID; - res.uid = uid_combine(res.uid, player_id.uid); - res.uid = uid_combine(res.uid, UID(rand_u64_from_seed(chunk_pos.x), rand_u64_from_seed(chunk_pos.y))); + res.uid = uid_combine(res.uid, UID(rand_u64_from_seed(chunk_index.x), rand_u64_from_seed(chunk_index.y))); return res; } @@ -564,20 +563,21 @@ void sim_ent_apply_torque(struct sim_ent *ent, f32 torque) } /* ========================== * - * Tile chunk + * Tile * ========================== */ -struct string sim_ent_get_tile_chunk_data(struct sim_ent *ent) +struct sim_ent *sim_tile_chunk_from_world_tile_index(struct sim_snapshot *ss, struct v2i32 world_tile_index) { - (UNUSED)ent; - struct string res = ZI; - return res; + struct v2i32 chunk_index = sim_tile_chunk_index_from_world_tile_index(world_tile_index); + struct sim_ent_id chunk_id = sim_ent_tile_chunk_id_from_tile_chunk_index(chunk_index); + struct sim_ent *chunk_ent = sim_ent_from_id(ss, chunk_id); + return chunk_ent; } -void sim_ent_set_tile_chunk_data(struct sim_ent *ent, struct string data) +enum sim_tile_kind sim_get_chunk_tile(struct sim_ent *chunk_ent, struct v2i32 local_tile_index) { - (UNUSED)ent; - (UNUSED)data; + enum sim_tile_kind res = chunk_ent->tile_chunk_tiles[local_tile_index.x + (local_tile_index.y * SIM_TILES_PER_CHUNK_SQRT)]; + return res; } /* ========================== * diff --git a/src/sim_ent.h b/src/sim_ent.h index 4668925a..aeef2597 100644 --- a/src/sim_ent.h +++ b/src/sim_ent.h @@ -25,6 +25,7 @@ enum sim_ent_prop { SEPROP_CMD, SEPROP_TILE_CHUNK, + SEPROP_WALL, /* Physics collision */ SEPROP_SENSOR, /* This entity's collisions generate contacts */ @@ -158,6 +159,17 @@ struct sim_ent { struct sim_ent_id chat_player; //struct string chat_msg; + + /* ====================================================================== */ + /* Tile */ + + /* SEPROP_TILE_CHUNK */ + + /* FIXME: Move out of here */ + u8 tile_chunk_tiles[SIM_TILES_PER_CHUNK_SQRT * SIM_TILES_PER_CHUNK_SQRT]; + struct v2i32 tile_chunk_index; + + /* ====================================================================== */ /* Client */ @@ -505,7 +517,7 @@ struct sim_ent *sim_ent_from_id(struct sim_snapshot *ss, struct sim_ent_id id); struct sim_ent_id sim_ent_random_id(void); struct sim_ent_id sim_ent_contact_constraint_id_from_contacting_ids(struct sim_ent_id player_id, struct sim_ent_id id0, struct sim_ent_id id1); struct sim_ent_id sim_ent_collision_debug_id_from_ids(struct sim_ent_id player_id, struct sim_ent_id id0, struct sim_ent_id id1); -struct sim_ent_id sim_ent_chunk_id_from_chunk_pos(struct sim_ent_id player_id, struct v2i32 chunk_pos); +struct sim_ent_id sim_ent_tile_chunk_id_from_tile_chunk_index(struct v2i32 chunk_start); /* Query */ struct sim_ent *sim_ent_find_first_match_one(struct sim_snapshot *ss, enum sim_ent_prop prop); @@ -530,9 +542,9 @@ void sim_ent_apply_force_to_center(struct sim_ent *ent, struct v2 force); void sim_ent_apply_angular_impulse(struct sim_ent *ent, f32 impulse); void sim_ent_apply_torque(struct sim_ent *ent, f32 torque); -/* Tile chunk */ -struct string sim_ent_get_tile_chunk_data(struct sim_ent *ent); -void sim_ent_set_tile_chunk_data(struct sim_ent *ent, struct string data); +/* Tile */ +struct sim_ent *sim_tile_chunk_from_world_tile_index(struct sim_snapshot *ss, struct v2i32 world_tile_index); +enum sim_tile_kind sim_get_chunk_tile(struct sim_ent *chunk_ent, struct v2i32 local_tile_index); /* Lerp */ void sim_ent_lerp(struct sim_ent *e, struct sim_ent *e0, struct sim_ent *e1, f64 blend); diff --git a/src/sim_step.c b/src/sim_step.c index 042e2dd5..90555a25 100644 --- a/src/sim_step.c +++ b/src/sim_step.c @@ -327,15 +327,16 @@ INTERNAL void test_spawn_entities3(struct sim_ent *parent, struct v2 pos) } } -INTERNAL void test_spawn_tile(struct sim_ent *parent, struct v2 cursor_pos) +INTERNAL void test_spawn_tile(struct sim_snapshot *world, struct v2 world_pos) { +#if 0 struct sim_ent *e = sim_ent_alloc_sync_src(parent); - i32 sign_x = (cursor_pos.x >= 0) - (cursor_pos.x < 0); - i32 sign_y = (cursor_pos.y >= 0) - (cursor_pos.y < 0); - struct v2i32 tile_index = V2I32(cursor_pos.x * SIM_TILES_PER_UNIT_SQRT, cursor_pos.y * SIM_TILES_PER_UNIT_SQRT); - cursor_pos.x -= sign_x < 0; - cursor_pos.y -= sign_y < 0; + i32 sign_x = (world_pos.x >= 0) - (world_pos.x < 0); + i32 sign_y = (world_pos.y >= 0) - (world_pos.y < 0); + struct v2i32 tile_index = V2I32(world_pos.x * SIM_TILES_PER_UNIT_SQRT, world_pos.y * SIM_TILES_PER_UNIT_SQRT); + world_pos.x -= sign_x < 0; + world_pos.y -= sign_y < 0; struct v2 tile_size = V2(1.f / SIM_TILES_PER_UNIT_SQRT, 1.f / SIM_TILES_PER_UNIT_SQRT); @@ -359,6 +360,10 @@ INTERNAL void test_spawn_tile(struct sim_ent *parent, struct v2 cursor_pos) sim_ent_enable_prop(e, SEPROP_SOLID); struct quad collider_quad = quad_from_rect(RECT(-tile_size.x / 2, -tile_size.y / 2, tile_size.y, tile_size.y)); e->local_collider = collider_from_quad(collider_quad); +#else + struct v2i32 tile_index = sim_world_tile_index_from_pos(world_pos); + sim_snapshot_set_tile(world, tile_index, SIM_TILE_KIND_WALL); +#endif } @@ -369,19 +374,22 @@ INTERNAL void test_spawn_tile(struct sim_ent *parent, struct v2 cursor_pos) +INTERNAL SORT_COMPARE_FUNC_DEF(tile_chunk_sort, arg_a, arg_b, udata) +{ + (UNUSED)udata; + struct sim_ent *a = (struct sim_ent *)arg_a; + struct sim_ent *b = (struct sim_ent *)arg_b; + struct v2i32 index_a = a->tile_chunk_index; + struct v2i32 index_b = b->tile_chunk_index; - - -/* TODO: Move this */ -enum tile_kind { - TILE_KIND_NONE, - TILE_KIND_WALL -}; - + i32 res = 0; + res = 2 * ((index_a.y > index_b.y) - (index_a.y < index_b.y)) + ((index_a.x > index_b.x) - (index_a.x < index_b.x)); + return res; +} INTERNAL void test_generate_walls(struct sim_ent *parent) { -#if 0 +#if 1 struct temp_arena scratch = scratch_begin_no_conflict(); struct sim_snapshot *world = parent->ss; @@ -395,33 +403,103 @@ INTERNAL void test_generate_walls(struct sim_ent *parent) } /* Sort tile chunks */ + struct sim_ent **tile_chunks = arena_dry_push(scratch.arena, struct sim_ent *); + u64 tile_chunks_count = 0; for (u64 ent_index = 0; ent_index < world->num_ents_reserved; ++ent_index) { struct sim_ent *ent = &world->ents[ent_index]; if (!ent->valid) continue; if (sim_ent_has_prop(ent, SEPROP_TILE_CHUNK)) { + *arena_push_no_zero(scratch.arena, struct sim_ent *) = ent; + ++tile_chunks_count; } } + merge_sort(tile_chunks, tile_chunks_count, sizeof(*tile_chunks), tile_chunk_sort, NULL); - /* Generate horizontal walls */ + struct wall_node { + struct v2i32 start; + struct v2i32 end; + struct wall_node *next; + }; + + struct wall_node *first_wall = NULL; + + /* Generate horizontal wall nodes */ for (u64 ent_index = 0; ent_index < world->num_ents_reserved; ++ent_index) { - struct sim_ent *ent = &world->ents[ent_index]; - if (!ent->valid) continue; - if (sim_ent_has_prop(ent, SEPROP_TILE_CHUNK)) { - //struct v2i32 chunk_start = ent->tile_chunk_start; - //struct v2i32 chunk_end = v2_add(chunk_start, V2(SIM_TILES_PER_CHUNK_SQRT, SIM_TILES_PER_CHUNK_SQRT)); - //struct sim_ent *left_chunk = sim_chunk_from_index(world, v2i32(chunk_start.x - 1, chunk_start.y)); - //struct sim_ent *right_chunk = sim_chunk_from_index(world, v2i32(chunk_end.x, chunk_start.y)); - //struct sim_ent *top_chunk = sim_chunk_from_index(world, v2i32(chunk_start.x, chunk_start.y - 1); - //struct sim_ent *bottom_chunk = sim_chunk_from_index(world, v2i32(chunk_start.x, chunk_start.y)); - for (i64 tile_y = 0; tile_y < SIM_TILES_PER_CHUNK_SQRT; ++tile_y) { - i64 tile_x = 0; - while (true) { - + struct sim_ent *chunk = &world->ents[ent_index]; + if (!chunk->valid) continue; + if (sim_ent_has_prop(chunk, SEPROP_TILE_CHUNK)) { + struct v2i32 chunk_index = chunk->tile_chunk_index; + struct sim_ent *top_chunk = sim_tile_chunk_from_world_tile_index(world, V2I32(chunk_index.x, chunk_index.y - 1)); + struct sim_ent *bottom_chunk = sim_tile_chunk_from_world_tile_index(world, V2I32(chunk_index.x, chunk_index.y + 1)); + /* If there's no chunk below this one, then do an extra iteration (since walls are created at the top of each tile) */ + i32 y_iterations = SIM_TILES_PER_CHUNK_SQRT + !bottom_chunk->valid; + i32 x_iterations = SIM_TILES_PER_CHUNK_SQRT + 1; + for (i32 tile_y = 0; tile_y < y_iterations; ++tile_y) { + i32 wall_start = -1; + i32 wall_end = -1; + for (i32 tile_x = 0; tile_x < x_iterations; ++tile_x) { + enum sim_tile_kind tile = SIM_TILE_KIND_NONE; + enum sim_tile_kind top_tile = SIM_TILE_KIND_NONE; + if (tile_x < SIM_TILES_PER_CHUNK_SQRT && tile_y < SIM_TILES_PER_CHUNK_SQRT) { + tile = sim_get_chunk_tile(chunk, V2I32(tile_x, tile_y)); + } + if (tile == SIM_TILE_KIND_NONE && tile_x < SIM_TILES_PER_CHUNK_SQRT) { + if (tile_y == 0) { + if (top_chunk->valid) { + top_tile = sim_get_chunk_tile(top_chunk, V2I32(tile_x, SIM_TILES_PER_CHUNK_SQRT - 1)); + } + } else { + top_tile = sim_get_chunk_tile(chunk, V2I32(tile_x, tile_y - 1)); + } + } + if (top_tile == SIM_TILE_KIND_WALL && tile != SIM_TILE_KIND_WALL) { + if (wall_start < 0) { + /* Start wall */ + wall_start = tile_x; + } + /* Extend wall */ + wall_end = tile_x + 1; + } else if (wall_end >= 0) { + /* Stop wall */ + struct v2i32 start = sim_world_tile_index_from_local_tile_index(chunk_index, V2I32(wall_start, tile_y)); + struct v2i32 end = sim_world_tile_index_from_local_tile_index(chunk_index, V2I32(wall_end, tile_y)); + struct wall_node *node = arena_push(scratch.arena, struct wall_node); + node->start = start; + node->end = end; + node->next = first_wall; + first_wall = node; + wall_start = -1; + wall_end = -1; + } } } } } + /* Create wall entities */ + for (struct wall_node *node = first_wall; node; node = node->next) { + struct sim_ent *wall_ent = sim_ent_alloc_sync_src(parent); + sim_ent_enable_prop(wall_ent, SEPROP_WALL); + +#if 0 + struct v2i32 node_start = node->start; + struct v2i32 node_end = node->end; + + struct v2 start = V2(node_start.x / SIM_TILES_PER_UNIT_SQRT, node_start.y / SIM_TILES_PER_UNIT_SQRT); + struct v2 end = V2(node_end.x / SIM_TILES_PER_UNIT_SQRT, node_end.y / SIM_TILES_PER_UNIT_SQRT); +#endif + + struct v2 start = sim_pos_from_world_tile_index(node->start); + struct v2 end = sim_pos_from_world_tile_index(node->end); + + struct xform xf = XFORM_POS(start); + sim_ent_set_xform(wall_ent, xf); + + sim_ent_enable_prop(wall_ent, SEPROP_SOLID); + wall_ent->local_collider.count = 2; + wall_ent->local_collider.points[1] = v2_sub(end, start); + } + scratch_end(scratch); #else (UNUSED)parent; @@ -840,7 +918,7 @@ void sim_step(struct sim_step_ctx *ctx) sim_ent_set_tile_chunk_data(chunk_ent, new_data); } #else - test_spawn_tile(root, player->player_cursor_pos); + test_spawn_tile(world, player->player_cursor_pos); #endif } } diff --git a/src/string.h b/src/string.h index 945df597..612f76e9 100644 --- a/src/string.h +++ b/src/string.h @@ -39,7 +39,7 @@ b32 string_ends_with(struct string str, struct string substring); * Format * ========================== */ -#define DEFAULT_FMT_PRECISION 6 +#define DEFAULT_FMT_PRECISION 3 enum fmt_type { FMT_TYPE_NONE, diff --git a/src/user.c b/src/user.c index 07884885..ed1ac310 100644 --- a/src/user.c +++ b/src/user.c @@ -408,9 +408,9 @@ INTERNAL struct string get_ent_debug_text(struct arena *arena, struct sim_ent *e struct xform xf = sim_ent_get_xform(ent); struct v2 linear_velocity = ent->linear_velocity; f32 angular_velocity = ent->angular_velocity; - res.len += string_format(arena, LIT("pos: (%F, %F)\n"), FMT_FLOAT_P(xf.og.x, 3), FMT_FLOAT_P(xf.og.y, 3)).len; - res.len += string_format(arena, LIT("linear velocity: (%F, %F)\n"), FMT_FLOAT_P(linear_velocity.x, 3), FMT_FLOAT_P(linear_velocity.y, 3)).len; - res.len += string_format(arena, LIT("angular velocity: %F\n"), FMT_FLOAT_P(angular_velocity, 3)).len; + res.len += string_format(arena, LIT("pos: (%F, %F)\n"), FMT_FLOAT(xf.og.x), FMT_FLOAT(xf.og.y)).len; + res.len += string_format(arena, LIT("linear velocity: (%F, %F)\n"), FMT_FLOAT(linear_velocity.x), FMT_FLOAT(linear_velocity.y)).len; + res.len += string_format(arena, LIT("angular velocity: %F\n"), FMT_FLOAT(angular_velocity)).len; /* Children */ if (!sim_ent_id_is_nil(ent->first) || !sim_ent_id_is_nil(ent->last)) { @@ -1103,6 +1103,30 @@ INTERNAL void user_update(void) } } + /* Draw tiles */ + /* TODO: Something better */ + if (sim_ent_has_prop(ent, SEPROP_TILE_CHUNK)) { + struct v2i32 chunk_index = ent->tile_chunk_index; + struct sprite_tag tile_sprite = sprite_tag_from_path(LIT("res/graphics/tile.ase")); + f32 tile_size = 1.f / SIM_TILES_PER_UNIT_SQRT; + for (i32 tile_y = 0; tile_y < SIM_TILES_PER_CHUNK_SQRT; ++tile_y) { + for (i32 tile_x = 0; tile_x < SIM_TILES_PER_CHUNK_SQRT; ++tile_x) { + struct v2i32 local_tile_index = V2I32(tile_x, tile_y); + enum sim_tile_kind tile = ent->tile_chunk_tiles[local_tile_index.x + (local_tile_index.y * SIM_TILES_PER_CHUNK_SQRT)]; + //if (tile > -1) { + if (tile == SIM_TILE_KIND_WALL) { + struct v2i32 world_tile_index = sim_world_tile_index_from_local_tile_index(chunk_index, local_tile_index); + + struct v2 pos = sim_pos_from_world_tile_index(world_tile_index); + + struct quad quad = quad_from_rect(RECT(pos.x, pos.y, tile_size, tile_size)); + struct draw_texture_params params = DRAW_TEXTURE_PARAMS(.sprite = tile_sprite); + draw_quad_texture(G.world_cmd_buffer, params, quad); + } + } + } + } + /* Debug draw entity info */ if (G.debug_draw && !skip_debug_draw) { struct temp_arena temp = arena_temp_begin(scratch.arena); @@ -1298,8 +1322,8 @@ INTERNAL void user_update(void) FMT_UINT(e0->handle.idx), FMT_UINT(e1->handle.idx), FMT_HEX(point.id), - FMT_FLOAT_P(point.normal_impulse, 3), - FMT_FLOAT_P(point.tangent_impulse, 3), + FMT_FLOAT(point.normal_impulse), + FMT_FLOAT(point.tangent_impulse), FMT_FLOAT_P(point.starting_separation, 6), FMT_FLOAT_P(data->normal.x, 6), FMT_FLOAT_P(data->normal.y, 6), FMT_UINT(data->num_points)); @@ -1768,26 +1792,26 @@ INTERNAL void user_update(void) draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("blended world tick: %F"), FMT_UINT(G.ss_blended->tick))); pos.y += spacing; - draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("blended world time: %F"), FMT_FLOAT_P(SECONDS_FROM_NS(G.ss_blended->sim_time_ns), 3))); + draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("blended world time: %F"), FMT_FLOAT(SECONDS_FROM_NS(G.ss_blended->sim_time_ns)))); pos.y += spacing; pos.y += spacing; - draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("average local sim publish dt: %F"), FMT_FLOAT_P(SECONDS_FROM_NS(G.average_local_to_user_snapshot_publish_dt_ns), 3))); + draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("average local sim publish dt: %F"), FMT_FLOAT(SECONDS_FROM_NS(G.average_local_to_user_snapshot_publish_dt_ns)))); pos.y += spacing; draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("local sim last known tick: %F"), FMT_UINT(G.local_sim_last_known_tick))); pos.y += spacing; - draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("local sim last known time: %F"), FMT_FLOAT_P(SECONDS_FROM_NS(G.local_sim_last_known_time_ns), 3))); + draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("local sim last known time: %F"), FMT_FLOAT(SECONDS_FROM_NS(G.local_sim_last_known_time_ns)))); pos.y += spacing; - draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("local sim predicted time: %F"), FMT_FLOAT_P(SECONDS_FROM_NS(G.local_sim_predicted_time_ns), 3))); + draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("local sim predicted time: %F"), FMT_FLOAT(SECONDS_FROM_NS(G.local_sim_predicted_time_ns)))); pos.y += spacing; - draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("render time target: %F"), FMT_FLOAT_P(SECONDS_FROM_NS(G.render_time_target_ns), 3))); + draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("render time target: %F"), FMT_FLOAT(SECONDS_FROM_NS(G.render_time_target_ns)))); pos.y += spacing; - draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("render time: %F"), FMT_FLOAT_P(SECONDS_FROM_NS(G.render_time_ns), 3))); + draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("render time: %F"), FMT_FLOAT(SECONDS_FROM_NS(G.render_time_ns)))); pos.y += spacing; pos.y += spacing; @@ -1795,23 +1819,40 @@ INTERNAL void user_update(void) pos.y += spacing; pos.y += spacing; - draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Network read: %F mbit/s"), FMT_FLOAT_P((f64)G.net_bytes_read.last_second * 8 / 1000 / 1000, 3))); + struct v2 world_cursor = G.world_cursor; + draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("cursor world: %F, %F"), FMT_FLOAT(world_cursor.x), FMT_FLOAT(world_cursor.y))); pos.y += spacing; - draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Network write: %F mbit/s"), FMT_FLOAT_P((f64)G.net_bytes_sent.last_second * 8 / 1000 / 1000, 3))); + struct v2i32 world_tile_cursor = sim_world_tile_index_from_pos(world_cursor); + draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("cursor world tile: %F, %F"), FMT_SINT(world_tile_cursor.x), FMT_SINT(world_tile_cursor.y))); pos.y += spacing; - draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Ping (real): %F ms"), FMT_FLOAT_P(SECONDS_FROM_NS(local_player->player_last_rtt_ns) * 1000, 3))); + struct v2i32 local_tile_cursor = sim_local_tile_index_from_world_tile_index(world_tile_cursor); + draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("cursor local tile: %F, %F"), FMT_SINT(local_tile_cursor.x), FMT_SINT(local_tile_cursor.y))); pos.y += spacing; - draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Ping (average): %F ms"), FMT_FLOAT_P(local_player->player_average_rtt_seconds * 1000, 3))); + struct v2i32 tile_chunk_cursor = sim_tile_chunk_index_from_world_tile_index(world_tile_cursor); + draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("cursor tile chunk: %F, %F"), FMT_SINT(tile_chunk_cursor.x), FMT_SINT(tile_chunk_cursor.y))); pos.y += spacing; pos.y += spacing; - draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Memory usage: %F MiB"), FMT_FLOAT_P((f64)gstat_get(GSTAT_MEMORY_COMMITTED) / 1024 / 1024, 3))); + draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Network read: %F mbit/s"), FMT_FLOAT((f64)G.net_bytes_read.last_second * 8 / 1000 / 1000))); pos.y += spacing; - draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Virtual memory usage: %F TiB"), FMT_FLOAT_P((f64)gstat_get(GSTAT_MEMORY_RESERVED) / 1024 / 1024 / 1024 / 1024, 3))); + draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Network write: %F mbit/s"), FMT_FLOAT((f64)G.net_bytes_sent.last_second * 8 / 1000 / 1000))); + pos.y += spacing; + + draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Ping (real): %F ms"), FMT_FLOAT(SECONDS_FROM_NS(local_player->player_last_rtt_ns) * 1000))); + pos.y += spacing; + + draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Ping (average): %F ms"), FMT_FLOAT(local_player->player_average_rtt_seconds * 1000))); + pos.y += spacing; + pos.y += spacing; + + draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Memory usage: %F MiB"), FMT_FLOAT((f64)gstat_get(GSTAT_MEMORY_COMMITTED) / 1024 / 1024))); + pos.y += spacing; + + draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Virtual memory usage: %F TiB"), FMT_FLOAT((f64)gstat_get(GSTAT_MEMORY_RESERVED) / 1024 / 1024 / 1024 / 1024))); pos.y += spacing; draw_text(G.ui_cmd_buffer, font, pos, string_format(temp.arena, LIT("Arenas allocated: %F"), FMT_UINT(gstat_get(GSTAT_NUM_ARENAS)))); @@ -1956,16 +1997,16 @@ INTERNAL void user_update(void) renderer_texture_clear(G.backbuffer_texture, RGBA_F(0, 0, 0, 1)); /* Render to world texture */ - renderer_texture_render(G.world_texture, G.world_cmd_buffer, G.world_to_ui_xf, ui_viewport, sprite_frame_scope); + renderer_texture_render(G.world_texture, G.world_cmd_buffer, G.world_to_ui_xf, ui_viewport); /* Render to UI texture */ - renderer_texture_render(G.ui_texture, G.ui_cmd_buffer, XFORM_IDENT, ui_viewport, sprite_frame_scope); + renderer_texture_render(G.ui_texture, G.ui_cmd_buffer, XFORM_IDENT, ui_viewport); /* Render to final texture */ - renderer_texture_render(G.final_texture, G.final_cmd_buffer, XFORM_IDENT, ui_viewport, sprite_frame_scope); + renderer_texture_render(G.final_texture, G.final_cmd_buffer, XFORM_IDENT, ui_viewport); /* Render to backbuffer */ - renderer_texture_render(G.backbuffer_texture, G.backbuffer_cmd_buffer, XFORM_IDENT, backbuffer_viewport, sprite_frame_scope); + renderer_texture_render(G.backbuffer_texture, G.backbuffer_cmd_buffer, XFORM_IDENT, backbuffer_viewport); } /* Present */ diff --git a/src/util.h b/src/util.h index fe3dbc7e..fce556dc 100644 --- a/src/util.h +++ b/src/util.h @@ -108,25 +108,26 @@ INLINE void merge_sort(void *items, u64 item_count, u64 item_size, sort_compare_ struct dict_entry { u64 hash; u64 value; + struct dict_entry *next_in_bin; struct dict_entry *next; }; struct dict_bin { - struct dict_entry *entry_head; + struct dict_entry *first; }; struct dict { u64 bins_count; struct dict_bin *bins; + struct dict_entry *first; }; INLINE struct dict dict_init(struct arena *arena, u64 bins_count) { __prof; struct dict dict = ZI; - bins_count = max_u64(bins_count, 1); /* Ensure at least 1 bin */ - dict.bins_count = bins_count; - dict.bins = arena_push_array(arena, struct dict_bin, bins_count); + dict.bins_count = max_u64(bins_count, 1); /* Ensure at least 1 bin */ + dict.bins = arena_push_array(arena, struct dict_bin, dict.bins_count); return dict; } @@ -136,13 +137,13 @@ INLINE void dict_set(struct arena *arena, struct dict *dict, u64 hash, u64 value struct dict_bin *bin = &dict->bins[hash % dict->bins_count]; - struct dict_entry *entry = bin->entry_head; + struct dict_entry *entry = bin->first; while (entry) { if (hash == entry->hash) { /* Existing match found */ break; } - entry = entry->next; + entry = entry->next_in_bin; } /* No match found, create new entry */ @@ -150,28 +151,37 @@ INLINE void dict_set(struct arena *arena, struct dict *dict, u64 hash, u64 value entry = arena_push(arena, struct dict_entry); entry->value = value; entry->hash = hash; - entry->next = bin->entry_head; - bin->entry_head = entry; + entry->next_in_bin = bin->first; + entry->next = dict->first; + dict->first = entry; + bin->first = entry; } entry->value = value; } -INLINE u64 dict_get(const struct dict *dict, u64 hash) +INLINE struct dict_entry *dict_get_entry(const struct dict *dict, u64 hash) { __prof; - u64 result = 0; + struct dict_entry *result = NULL; struct dict_bin *bin = &dict->bins[hash % dict->bins_count]; - for (struct dict_entry *entry = bin->entry_head; entry; entry = entry->next) { + for (struct dict_entry *entry = bin->first; entry; entry = entry->next_in_bin) { if (hash == entry->hash) { /* Match found */ - result = entry->value; + result = entry; break; } } return result; } +INLINE u64 dict_get(const struct dict *dict, u64 hash) +{ + __prof; + struct dict_entry *entry = dict_get_entry(dict, hash); + return entry ? entry->value : 0; +} + /* ========================== * * Sync flag * ========================== */