From 0f67701761925aeb9aaf3e8ba3903774f8439a03 Mon Sep 17 00:00:00 2001 From: jacob Date: Mon, 11 Mar 2024 19:39:26 -0500 Subject: [PATCH] proper xform tree iteration --- src/arena.h | 22 +++++++---- src/draw.c | 70 ++++++++++++++++++++++++++++------- src/draw.h | 4 +- src/entity.c | 8 +++- src/game.c | 101 +++++++++++++++++++++++++++++++++++++-------------- src/user.c | 37 +++++++++++++++---- src/world.c | 11 +++--- 7 files changed, 188 insertions(+), 65 deletions(-) diff --git a/src/arena.h b/src/arena.h index 4539cb0b..b85dc9d9 100644 --- a/src/arena.h +++ b/src/arena.h @@ -3,14 +3,15 @@ #include "memory.h" -// #define arena_clear(a) (a->pos = 0) - #define arena_push(a, type) ((type *)_arena_push_bytes((a), sizeof(type), ALIGNOF(type))) #define arena_push_zero(a, type) ((type *)_arena_push_bytes_zero((a), sizeof(type), ALIGNOF(type))) #define arena_push_array(a, type, n) ((type *)_arena_push_bytes((a), (sizeof(type) * (n)), ALIGNOF(type))) #define arena_push_array_zero(a, type, n) ((type *)_arena_push_bytes_zero((a), (sizeof(type) * (n)), ALIGNOF(type))) +#define arena_pop(a, type) ((type *)_arena_pop((a), sizeof(type))) +#define arena_pop_array(a, type, n) ((type *)_arena_pop((a), sizeof(type) * (n))) + /* Returns a pointer to where the next allocation would be (at alignment of type). * Equivalent arena_push but without actually allocating anything. */ #define arena_dry_push(a, type) (type *)(_arena_dry_push((a), ALIGNOF(type))) @@ -39,11 +40,18 @@ INLINE void *_arena_push_bytes_zero(struct arena *arena, u64 size, u64 align) return p; } -INLINE void arena_pop_to(struct arena *arena, u64 pos) +INLINE void *_arena_pop_to(struct arena *arena, u64 pos) { ASSERT(arena->pos >= pos); ASAN_POISON(arena->base + pos, arena->pos - pos); arena->pos = pos; + return (void *)(arena->base + arena->pos); +} + +INLINE void *_arena_pop(struct arena *arena, u64 size) +{ + ASSERT(arena->pos >= size); + return _arena_pop_to(arena, arena->pos - size); } INLINE struct temp_arena arena_temp_begin(struct arena *arena) @@ -56,12 +64,12 @@ INLINE struct temp_arena arena_temp_begin(struct arena *arena) INLINE void arena_temp_end(struct temp_arena temp) { - arena_pop_to(temp.arena, temp.start_pos); + _arena_pop_to(temp.arena, temp.start_pos); } INLINE void arena_reset(struct arena *arena) { - arena_pop_to(arena, 0); + _arena_pop_to(arena, 0); } INLINE struct buffer arena_to_buffer(struct arena *arena) @@ -89,12 +97,12 @@ INLINE void *_arena_align(struct arena *arena, u64 align) if (align_bytes > 0) { return (void *)arena_push_array(arena, u8, align_bytes); } else { - return (void *)arena->pos; + return (void *)(arena->base + arena->pos); } } else { /* 0 alignment */ ASSERT(false); - return (void *)arena->pos; + return (void *)(arena->base + arena->pos); } } diff --git a/src/draw.c b/src/draw.c index dbf8c17b..09ff6e96 100644 --- a/src/draw.c +++ b/src/draw.c @@ -93,14 +93,8 @@ void draw_texture_rect(struct renderer_canvas *canvas, struct draw_texture_param * Solid fill shapes * ========================== */ -void draw_solid_poly(struct renderer_canvas *canvas, struct v2_array array, u32 color) +INTERNAL void draw_solid_poly_internal(struct renderer_canvas *canvas, struct v2_array array, u32 color) { - if (array.count < 3) { - return; - } - - renderer_canvas_ensure_texture_cmd(canvas, (struct texture_shader_parameters) { .texture = L.solid_white }); - u32 num_tris = array.count - 2; u32 num_indices = num_tris * 3; @@ -125,6 +119,16 @@ void draw_solid_poly(struct renderer_canvas *canvas, struct v2_array array, u32 } } +void draw_solid_poly(struct renderer_canvas *canvas, struct v2_array array, u32 color) +{ + if (array.count < 3) { + return; + } + + renderer_canvas_ensure_texture_cmd(canvas, (struct texture_shader_parameters) { .texture = L.solid_white }); + draw_solid_poly_internal(canvas, array, color); +} + void draw_solid_circle(struct renderer_canvas *canvas, struct v2 pos, f32 radius, u32 color, u32 detail) { struct temp_arena scratch = scratch_begin_no_conflict(); @@ -164,13 +168,6 @@ void draw_solid_rect(struct renderer_canvas *canvas, struct rect rect, u32 color * Solid line shapes * ========================== */ -void draw_solid_ray(struct renderer_canvas *canvas, struct v2 pos, struct v2 rel, f32 thickness, u32 color) -{ - renderer_canvas_ensure_texture_cmd(canvas, (struct texture_shader_parameters) { .texture = L.solid_white }); - struct quad quad = quad_from_ray(pos, rel, thickness); - draw_texture_quad_internal(canvas, CLIP_ALL, color, quad); -} - void draw_solid_line(struct renderer_canvas *canvas, struct v2 start, struct v2 end, f32 thickness, u32 color) { renderer_canvas_ensure_texture_cmd(canvas, (struct texture_shader_parameters) { .texture = L.solid_white }); @@ -178,6 +175,13 @@ void draw_solid_line(struct renderer_canvas *canvas, struct v2 start, struct v2 draw_texture_quad_internal(canvas, CLIP_ALL, color, quad); } +void draw_solid_ray(struct renderer_canvas *canvas, struct v2 pos, struct v2 rel, f32 thickness, u32 color) +{ + renderer_canvas_ensure_texture_cmd(canvas, (struct texture_shader_parameters) { .texture = L.solid_white }); + struct quad quad = quad_from_ray(pos, rel, thickness); + draw_texture_quad_internal(canvas, CLIP_ALL, color, quad); +} + void draw_solid_poly_line(struct renderer_canvas *canvas, struct v2_array array, b32 loop, f32 thickness, u32 color) { if (array.count < 2) { @@ -212,6 +216,44 @@ void draw_solid_rect_line(struct renderer_canvas *canvas, struct rect rect, f32 draw_solid_quad_line(canvas, q, thickness, color); } +void draw_solid_arrow_line(struct renderer_canvas *canvas, struct v2 start, struct v2 end, f32 thickness, f32 arrowhead_height, u32 color) +{ + renderer_canvas_ensure_texture_cmd(canvas, (struct texture_shader_parameters) { .texture = L.solid_white }); + + const f32 head_width_ratio = 0.5f; /* Width of arrowhead relative to its length */ + + const f32 max_height_to_line_ratio = 0.9f; /* Maximum length of arrowhead relative to total line length */ + arrowhead_height = min_f32(arrowhead_height, v2_len(v2_sub(end, start)) * max_height_to_line_ratio); + + struct v2 head_start_dir = v2_sub(start, end); + head_start_dir = v2_norm(head_start_dir); + head_start_dir = v2_mul(head_start_dir, arrowhead_height); + + struct v2 head_start = v2_add(end, head_start_dir); + + struct v2 head_p1_dir = v2_mul(v2_perp(head_start_dir), head_width_ratio); + struct v2 head_p2_dir = v2_neg(head_p1_dir); + + struct v2 head_p1 = v2_add(head_start, head_p1_dir); + struct v2 head_p2 = v2_add(head_start, head_p2_dir); + + struct v2 head_points[] = { end, head_p1, head_p2 }; + struct v2_array head_points_v2_array = { + .points = head_points, + .count = ARRAY_COUNT(head_points) + }; + draw_solid_poly_internal(canvas, head_points_v2_array, color); + + struct quad line_quad = quad_from_line(start, head_start, thickness); + draw_texture_quad_internal(canvas, CLIP_ALL, color, line_quad); +} + +void draw_solid_arrow_ray(struct renderer_canvas *canvas, struct v2 pos, struct v2 rel, f32 thickness, f32 arrowhead_height, u32 color) +{ + struct v2 end = v2_add(pos, rel); + draw_solid_arrow_line(canvas, pos, end, thickness, arrowhead_height, color); +} + /* ========================== * * Text * ========================== */ diff --git a/src/draw.h b/src/draw.h index 54e0c126..1e0ef4d9 100644 --- a/src/draw.h +++ b/src/draw.h @@ -25,11 +25,13 @@ void draw_solid_circle(struct renderer_canvas *canvas, struct v2 pos, f32 radius void draw_solid_quad(struct renderer_canvas *canvas, struct quad quad, u32 color); void draw_solid_rect(struct renderer_canvas *canvas, struct rect rect, u32 color); -void draw_solid_ray(struct renderer_canvas *canvas, struct v2 start, struct v2 ray, f32 thickness, u32 color); void draw_solid_line(struct renderer_canvas *canvas, struct v2 start, struct v2 end, f32 thickness, u32 color); +void draw_solid_ray(struct renderer_canvas *canvas, struct v2 start, struct v2 ray, f32 thickness, u32 color); void draw_solid_poly_line(struct renderer_canvas *canvas, struct v2_array array, b32 loop, f32 thickness, u32 color); void draw_solid_quad_line(struct renderer_canvas *canvas, struct quad quad, f32 thickness, u32 color); void draw_solid_rect_line(struct renderer_canvas *canvas, struct rect rect, f32 thickness, u32 color); +void draw_solid_arrow_line(struct renderer_canvas *canvas, struct v2 start, struct v2 end, f32 thickness, f32 arrowhead_height, u32 color); +void draw_solid_arrow_ray(struct renderer_canvas *canvas, struct v2 pos, struct v2 rel, f32 thickness, f32 arrowhead_height, u32 color); void draw_text(struct renderer_canvas *canvas, struct font *font, struct v2 pos, struct string str); void draw_text_ex(struct renderer_canvas *canvas, struct font *font, struct v2 pos, f32 scale, struct string str); diff --git a/src/entity.c b/src/entity.c index 2e6d5bf2..9a169c97 100644 --- a/src/entity.c +++ b/src/entity.c @@ -1,3 +1,9 @@ #include "entity.h" +#include "math.h" -READONLY struct entity _g_entity_nil = { 0 }; +READONLY struct entity _g_entity_nil = { + .rel_xform = XFORM_IDENT, + .world_xform = XFORM_IDENT, + .sprite_xform = XFORM_IDENT, + .sprite_tint = COLOR_WHITE +}; diff --git a/src/game.c b/src/game.c index c549c73d..9fd8a6bc 100644 --- a/src/game.c +++ b/src/game.c @@ -95,7 +95,7 @@ INTERNAL void game_update(void) /* Player ent */ struct entity *player_ent; { - struct v2 pos = V2(0, 0); + struct v2 pos = V2(1, 1); struct v2 size = V2(1, 1); f32 r = 0; @@ -143,9 +143,36 @@ INTERNAL void game_update(void) } /* Child ent */ - for (u64 i = 0; i < 100; ++i) { - //struct v2 pos = V2(0, 0.001); - struct v2 pos = V2(0, 0.25 * (i + 1)); + struct entity *parent = player_ent; + { +#if 0 + f32 x_pos = 0; + f32 y_pos = 0; + if (parent == player_ent) { + x_pos = (((f32)sys_rand_u32() - (U32_MAX / 2)) / U32_MAX) * 10; + y_pos = (((f32)sys_rand_u32() - (U32_MAX / 2)) / U32_MAX) * 10; + } else { + u64 child_count = 0; + struct entity *sibling = world_entity_from_handle(&L.world, parent->first); + while (sibling->valid) { + ++child_count; + sibling = world_entity_from_handle(&L.world, sibling->next); + } + + x_pos = 0.5f * child_count; + //if (child_count % 2 != 0) { + //x_pos = -x_pos; + //} + + y_pos = 1.0; + } + struct v2 pos = V2(x_pos, y_pos); +#else + struct v2 pos = V2(0, 0.25); +#endif + + + //struct v2 pos = V2(0, 0.25 * (i + 1)); struct v2 size = V2(1, 1); f32 r = 0; @@ -178,7 +205,7 @@ INTERNAL void game_update(void) e->sprite_name = sprite_name; e->sprite_tag_name = sprite_tag_name; - e->sprite_tint = RGBA_F(0.3, 0.3, 0.3, 0.3); + e->sprite_tint = RGBA_F(0.5, 0.5, 0, 1); //entity_enable_prop(e, ENTITY_PROP_PLAYER_CONTROLLED); //e->player_max_speed = 5.f; @@ -189,7 +216,17 @@ INTERNAL void game_update(void) //entity_enable_prop(e, ENTITY_PROP_TEST); //entity_enable_prop(e, ENTITY_PROP_TEST_FOLLOW_MOUSE); - world_link_entities(&L.world, player_ent, e); + world_link_entities(&L.world, parent, e); + + if (sys_rand_u32() % 2 == 0) { + u64 parent_idx = sys_rand_u32() % L.world.entities_count; + struct entity *rand_ent = world_entity_from_handle(&L.world, (struct entity_handle) { .idx = parent_idx, .gen = 1 }); + if (rand_ent->valid) { + parent = rand_ent; + } else { + parent = e; + } + } } /* Camera ent */ @@ -380,32 +417,40 @@ INTERNAL void game_update(void) * Calculate xforms * ========================== */ - ent->world_xform = ent->rel_xform; + { + struct temp_arena stack = arena_temp_begin(scratch.arena); - struct entity *child = world_entity_from_handle(&L.world, ent->first); - struct xform parent_xform = ent->world_xform; - while (child->valid) { - - /* Calculate child world xform */ - child->world_xform = xform_mul(parent_xform, child->rel_xform); + struct xform_stack_node { + struct entity *entity; + struct xform parent_xform; + }; /* Depth first iteration */ - if (child->first.gen) { - /* Next child */ - parent_xform = child->world_xform; - child = world_entity_from_handle(&L.world, child->first); - } else if (child->next.gen) { - /* Next sibling */ - child = world_entity_from_handle(&L.world, child->next); - } else if (child->parent.gen && world_entity_from_handle(&L.world, child->parent)->next.gen) { - /* Next parent sibling */ - struct entity *parent = world_entity_from_handle(&L.world, child->parent); - struct entity *grandparent = world_entity_from_handle(&L.world, parent->parent); - parent_xform = grandparent->world_xform; - child = world_entity_from_handle(&L.world, parent->next); - } else { - child = entity_nil(); + *arena_push(stack.arena, struct xform_stack_node) = (struct xform_stack_node) { .entity = ent, .parent_xform = XFORM_IDENT }; + u64 stack_count = 1; + while (stack_count > 0) { + /* Pull from top of stack */ + struct xform_stack_node node = *arena_pop(stack.arena, struct xform_stack_node); + --stack_count; + + /* Calculate child world xform */ + struct entity *child = node.entity; + struct xform world_xform = xform_mul(node.parent_xform, child->rel_xform); + child->world_xform = world_xform; + + /* Append sub-children to stack */ + struct entity *subchild = world_entity_from_handle(&L.world, child->last); + while (subchild->valid) { + *arena_push(stack.arena, struct xform_stack_node) = (struct xform_stack_node) { + .entity = subchild, + .parent_xform = world_xform + }; + ++stack_count; + subchild = world_entity_from_handle(&L.world, subchild->prev); + } } + + arena_temp_end(stack); } } diff --git a/src/user.c b/src/user.c index 837f5dc1..879c620d 100644 --- a/src/user.c +++ b/src/user.c @@ -255,6 +255,7 @@ INTERNAL struct v2 view_mouse_pos(struct view view) INTERNAL void debug_draw_xform(struct xform xf) { f32 thickness = 2.f / PIXELS_PER_UNIT / L.world_view.zoom; + f32 arrowhead_len = 15.f / PIXELS_PER_UNIT / L.world_view.zoom; u32 color = RGBA_F(0, 1, 1, 0.3); u32 color_x = RGBA_F(1, 0, 0, 0.3); u32 color_y = RGBA_F(0, 1, 0, 0.3); @@ -266,8 +267,8 @@ INTERNAL void debug_draw_xform(struct xform xf) struct quad quad = quad_from_rect(RECT(0, 0, 1, -1)); quad = quad_mul_xform(quad_scale(quad, 0.075), xf); - draw_solid_ray(L.world_canvas, pos, x_ray, thickness, color_x); - draw_solid_ray(L.world_canvas, pos, y_ray, thickness, color_y); + draw_solid_arrow_ray(L.world_canvas, pos, x_ray, thickness, arrowhead_len, color_x); + draw_solid_arrow_ray(L.world_canvas, pos, y_ray, thickness, arrowhead_len, color_y); draw_solid_quad(L.world_canvas, quad, color); } @@ -650,8 +651,8 @@ INTERNAL void user_update(void) draw_texture_quad(L.world_canvas, params, quad); - if (L.debug_draw && !is_camera) { #if 0 + if (L.debug_draw && !is_camera) { /* Debug draw sprite quad */ { f32 thickness = 2.f; @@ -669,8 +670,8 @@ INTERNAL void user_update(void) u32 color = RGBA_F(1, 0, 0, 1); draw_solid_circle(L.world_canvas, ent->world_xform.og, 0.02, color, 20); } -#endif } +#endif } } @@ -678,6 +679,7 @@ INTERNAL void user_update(void) if (L.debug_draw && !is_camera) { struct temp_arena temp = arena_temp_begin(scratch.arena); +#if 0 struct font *disp_font = font_load_async(STR("res/fonts/fixedsys.ttf"), 12.0f); if (disp_font) { struct xform xf = ent->world_xform; @@ -715,6 +717,23 @@ INTERNAL void user_update(void) debug_draw_xform(ent->world_xform); debug_draw_movement(ent); +#else + (UNUSED)view_xform_point; + (UNUSED)debug_draw_xform; + (UNUSED)debug_draw_movement; +#endif + + /* Draw hierarchy */ + struct entity *parent = world_entity_from_handle(&L.world, ent->parent); + if (parent->valid && !v2_eq(ent->world_xform.og, V2(0, 0))) { + u32 color = RGBA_F(1, 0.7, 0.7, 0.75); + f32 thickness = 3; + f32 arrow_height = 15; + + struct v2 start = view_xform_point(L.world_view, ent->world_xform.og); + struct v2 end = view_xform_point(L.world_view, parent->world_xform.og); + draw_solid_arrow_line(L.ui_canvas, start, end, thickness, arrow_height, color); + } arena_temp_end(temp); } @@ -728,10 +747,12 @@ INTERNAL void user_update(void) /* Send world mouse pos */ struct v2 world_mouse = view_mouse_pos(L.world_view); - queue_game_cmd(&cmd_list, (struct game_cmd) { - .kind = GAME_CMD_KIND_PLAYER_FOCUS, - .pos = world_mouse - }); + if (!L.debug_camera) { + queue_game_cmd(&cmd_list, (struct game_cmd) { + .kind = GAME_CMD_KIND_PLAYER_FOCUS, + .pos = world_mouse + }); + } /* Debug draw info */ if (L.debug_draw) { diff --git a/src/world.c b/src/world.c index dbadf6e8..77e6648f 100644 --- a/src/world.c +++ b/src/world.c @@ -30,21 +30,20 @@ void world_copy_replace(struct world *dest, struct world *src) struct entity *world_alloc_entity(struct world *world) { struct entity *entity = NULL; + struct entity_handle handle; if (world->first_free_entity.gen) { /* Reuse from free list */ entity = world_entity_from_handle(world, world->first_free_entity); world->first_free_entity = entity->next_free; - *entity = (struct entity) { - .handle = entity->handle - }; + handle = entity->handle; } else { /* Make new */ u64 idx = world->entities_count++; entity = arena_push(&world->entities_arena, struct entity); - *entity = (struct entity) { - .handle = { .gen = 1, .idx = idx } - }; + handle = (struct entity_handle) { .gen = 1, .idx = idx }; } + *entity = *entity_nil(); + entity->handle = handle; return entity; }