From 5a3f5ad12b767383dff8fa9ad53237fec8de7e18 Mon Sep 17 00:00:00 2001 From: jacob Date: Thu, 13 Nov 2025 15:02:31 -0600 Subject: [PATCH] rounded shape drawing --- src/base/base_math.h | 3 +- src/proto/pp_sim/pp_sim_core.c | 67 ++++++++++++++++++++++++++-------- src/proto/pp_sim/pp_sim_core.h | 38 ++++++++++++------- src/proto/pp_vis/pp_vis_core.c | 6 +-- src/proto/pp_vis/pp_vis_draw.c | 31 +++++++++++++--- src/proto/pp_vis/pp_vis_draw.h | 2 +- 6 files changed, 108 insertions(+), 39 deletions(-) diff --git a/src/base/base_math.h b/src/base/base_math.h index 1532067e..ffe4b042 100644 --- a/src/base/base_math.h +++ b/src/base/base_math.h @@ -348,7 +348,8 @@ PackedVec4 PackVec4(Vec4 v); b32 MatchXform(Xform xf1, Xform xf2); //- Initialization -#define XformIdentity (Xform) { .bx = VEC2(1, 0), .by = VEC2(0, 1) } +#define XformIdentity (Xform) { .bx = { .x = 1 }, .by = { .y = 1 } } +#define CompXformIdentity { .bx = { .x = 1 }, .by = { .y = 1 } } Xform XformFromPos(Vec2 v); Xform XformFromRot(f32 r); Xform XformFromScale(Vec2 scale); diff --git a/src/proto/pp_sim/pp_sim_core.c b/src/proto/pp_sim/pp_sim_core.c index 3472dce9..638ce4cd 100644 --- a/src/proto/pp_sim/pp_sim_core.c +++ b/src/proto/pp_sim/pp_sim_core.c @@ -1,5 +1,9 @@ S_SharedState S_shared_state = ZI; -Readonly S_Ent S_nil_ent = ZI; + +Readonly S_Ent S_nil_ent = { + .local_to_parent_xf = CompXformIdentity, + .final_local_to_world_xf = CompXformIdentity, +}; //////////////////////////////////////////////////////////// //~ Startup @@ -38,7 +42,7 @@ void S_Shutdown(void) //////////////////////////////////////////////////////////// //~ Nil helpers -b32 S_IsKeyNil(S_EntKey key) +b32 S_IsKeyNil(S_Key key) { return key.v.hi == 0 && key.v.lo == 0; } @@ -48,15 +52,48 @@ b32 S_IsEntNil(S_Ent *ent) return ent == 0 || ent == &S_nil_ent; } -b32 S_MatchEntKey(S_EntKey a, S_EntKey b) +b32 S_MatchKey(S_Key a, S_Key b) { return a.v.hi == b.v.hi && a.v.lo == b.v.lo; } +//////////////////////////////////////////////////////////// +//~ Shape helpers + +S_Shape S_MulXformShape(Xform xf, S_Shape shape) +{ + S_Shape result = shape; + for (i32 i = 0; i < shape.points_count; ++i) + { + shape.points[i] = MulXformV2(xf, shape.points[i]); + } + Vec2 scale = ScaleFromXform(xf); + result.radius *= MaxF32(scale.x, scale.y); + return result; +} + +Vec2 S_SupportPointFromShape(S_Shape shape, Vec2 dir) +{ + Vec2 result = ZI; + f32 max_dot = -F32Infinity; + for (i32 i = 0; i < shape.points_count; ++i) + { + Vec2 p = shape.points[i]; + f32 dot = DotVec2(p, dir); + if (dot > max_dot) + { + max_dot = dot; + result = p; + } + } + result = AddVec2(result, MulVec2(dir, shape.radius)); + return result; +} + //////////////////////////////////////////////////////////// //~ Lookup helpers -S_Ent *S_EntFromKey(S_World *world, S_EntKey key) +S_Ent *S_EntFromKey(S_World *world, S_Key key) { S_Ent *ent = &S_nil_ent; if (!S_IsKeyNil(key)) @@ -64,7 +101,7 @@ S_Ent *S_EntFromKey(S_World *world, S_EntKey key) S_EntLookupNode *n = world->ent_bins[key.v.lo % world->ent_bins_count]; for (; n; n = n->next) { - if (S_MatchEntKey(n->ent->key, key)) + if (S_MatchKey(n->ent->key, key)) { ent = n->ent; break; @@ -94,7 +131,7 @@ S_World *S_WorldFromSnapshot(Arena *arena, S_Snapshot *snapshot) for (i64 ent_idx = 0; ent_idx < world->allocated_ents_count; ++ent_idx) { S_Ent *ent = &world->ents[ent_idx]; - S_EntKey key = ent->key; + S_Key key = ent->key; S_EntLookupNode *n = PushStruct(arena, S_EntLookupNode); n->ent = ent; S_EntLookupNode **bin = &world->ent_bins[ent->key.v.lo % world->ent_bins_count]; @@ -116,7 +153,7 @@ S_World *S_WorldFromSnapshot(Arena *arena, S_Snapshot *snapshot) for (i64 ent_idx = 0; ent_idx < world->allocated_ents_count; ++ent_idx) { S_Ent *ent = &world->ents[ent_idx]; - if (S_MatchEntKey(ent->key, S_RootEntKey)) + if (S_MatchKey(ent->key, S_RootKey)) { n->ent = ent; break; @@ -180,7 +217,7 @@ JobDef(S_SimWorker, _, __) S_Ent *root_ent = &empty_ss->ents[empty_ss->ents_count++]; { *root_ent = S_nil_ent; - root_ent->key = S_RootEntKey; + root_ent->key = S_RootKey; } /* Create test ent */ S_Ent *test_ent = &empty_ss->ents[empty_ss->ents_count++]; @@ -188,19 +225,16 @@ JobDef(S_SimWorker, _, __) *test_ent = S_nil_ent; // test_ent->shape.points_count = 1; // test_ent->shape.radius = 0.25; - test_ent->key = ((S_EntKey) { .v.hi = 0x66444f20b7e41f3d, .v.lo = 0x5a2df684b9430943 }); - - - + test_ent->key = ((S_Key) { .v.hi = 0x66444f20b7e41f3d, .v.lo = 0x5a2df684b9430943 }); { - S_Shape *shape = &test_ent->shape; + S_Shape *shape = &test_ent->local_shape; shape->points_count = 4; shape->points[0] = VEC2(100, 100); shape->points[1] = VEC2(200, 100); shape->points[2] = VEC2(150, 200); shape->points[3] = VEC2(125, 200); - // test_ent->shape.radius = 0.25; + // shape->radius = 1; } @@ -218,7 +252,7 @@ JobDef(S_SimWorker, _, __) } ////////////////////////////// - //- Begin sim loop + //- Sim loop b32 shutdown = 0; while (!shutdown) @@ -260,6 +294,9 @@ JobDef(S_SimWorker, _, __) } } + ////////////////////////////// + //- Update entities from user control + ////////////////////////////// //- Publish sim state diff --git a/src/proto/pp_sim/pp_sim_core.h b/src/proto/pp_sim/pp_sim_core.h index daf102ae..2b19743e 100644 --- a/src/proto/pp_sim/pp_sim_core.h +++ b/src/proto/pp_sim/pp_sim_core.h @@ -1,10 +1,10 @@ //////////////////////////////////////////////////////////// //~ Key types -#define S_NilEntKey ((S_EntKey) { 0 }) -#define S_RootEntKey ((S_EntKey) { .v.hi = 0x75ebb7a47d1ca753, .v.lo = 0x2d505fc8961e5576 }) +#define S_NilKey ((S_Key) { 0 }) +#define S_RootKey ((S_Key) { .v.hi = 0x75ebb7a47d1ca753, .v.lo = 0x2d505fc8961e5576 }) -Struct(S_EntKey) +Struct(S_Key) { U128 v; }; @@ -15,7 +15,7 @@ Struct(S_EntKey) Struct(S_Shape) { f32 radius; - u32 points_count; + i32 points_count; Vec2 points[8]; }; @@ -36,18 +36,22 @@ Enum(S_EntProp) Struct(S_Ent) { //- Tree data - S_EntKey parent; - S_EntKey first; - S_EntKey last; - S_EntKey next; - S_EntKey prev; + S_Key parent; + S_Key first; + S_Key last; + S_Key next; + S_Key prev; i64 count; //- Persistent data - S_EntKey key; + S_Key key; //- Build data - S_Shape shape; + S_Shape local_shape; + Xform local_to_parent_xf; + + //- Final data + Xform final_local_to_world_xf; //- Per-world data i64 pre_idx; @@ -177,14 +181,20 @@ void S_Shutdown(void); //////////////////////////////////////////////////////////// //~ Nil helpers -b32 S_IsKeyNil(S_EntKey key); +b32 S_IsKeyNil(S_Key key); b32 S_IsEntNil(S_Ent *ent); -b32 S_MatchEntKey(S_EntKey a, S_EntKey b); +b32 S_MatchKey(S_Key a, S_Key b); + +//////////////////////////////////////////////////////////// +//~ Shape helpers + +S_Shape S_MulXformShape(Xform xf, S_Shape shape); +Vec2 S_SupportPointFromShape(S_Shape shape, Vec2 dir); //////////////////////////////////////////////////////////// //~ Lookup helpers -S_Ent *S_EntFromKey(S_World *world, S_EntKey key); +S_Ent *S_EntFromKey(S_World *world, S_Key key); //////////////////////////////////////////////////////////// //~ Snapshot helpers diff --git a/src/proto/pp_vis/pp_vis_core.c b/src/proto/pp_vis/pp_vis_core.c index fa828a74..9acbbdb1 100644 --- a/src/proto/pp_vis/pp_vis_core.c +++ b/src/proto/pp_vis/pp_vis_core.c @@ -352,15 +352,15 @@ JobDef(V_VisWorker, _, __) // Xform xf = ent->final_to_world_xf; Xform xf = XformIdentity; - S_Shape shape = ent->shape; - for (u32 point_idx = 0; point_idx < shape.points_count; ++point_idx) + S_Shape shape = S_MulXformShape(ent->final_local_to_world_xf, ent->local_shape); + for (i32 point_idx = 0; point_idx < shape.points_count; ++point_idx) { Vec2 *p = &shape.points[point_idx]; *p = MulXformV2(xf, *p); } Vec4 color = Color_Red; - V_DrawShape(dverts_arena, dvert_idx_arena, shape, LinearFromSrgb(color)); + V_DrawShape(dverts_arena, dvert_idx_arena, shape, LinearFromSrgb(color), 16); } ////////////////////////////// diff --git a/src/proto/pp_vis/pp_vis_draw.c b/src/proto/pp_vis/pp_vis_draw.c index db4e63b4..c6c1f01c 100644 --- a/src/proto/pp_vis/pp_vis_draw.c +++ b/src/proto/pp_vis/pp_vis_draw.c @@ -1,16 +1,35 @@ -void V_DrawShape(Arena *verts_arena, Arena *idx_arena, S_Shape shape, Vec4 color_lin) +void V_DrawShape(Arena *verts_arena, Arena *idx_arena, S_Shape shape, Vec4 color_lin, i32 detail) { - /* FIXME: Rounding */ + TempArena scratch = BeginScratchNoConflict(); - i32 verts_count = shape.points_count; + Vec2Array draw_points = ZI; + if (shape.radius == 0) + { + draw_points.points = shape.points; + draw_points.count = shape.points_count; + } + else + { + draw_points.points = PushStructsNoZero(scratch.arena, Vec2, detail); + draw_points.count = detail; + for (i32 i = 0; i < detail; ++i) + { + f32 rad = ((f32)i / (f32)detail) * Tau; + Vec2 dir = Vec2FromAngle(rad); + Vec2 sp = S_SupportPointFromShape(shape, dir); + draw_points.points[i] = sp; + } + } + + i32 verts_count = draw_points.count; if (verts_count >= 3) { i32 idx_offset = ArenaCount(verts_arena, V_DVert); V_DVert *dverts = PushStructsNoZero(verts_arena, V_DVert, verts_count); - for (i32 point_idx = 0; point_idx < (i32)shape.points_count; ++point_idx) + for (i32 point_idx = 0; point_idx < (i32)draw_points.count; ++point_idx) { V_DVert *dvert = &dverts[point_idx]; - dvert->pos = shape.points[point_idx]; + dvert->pos = draw_points.points[point_idx]; dvert->color_lin = color_lin; } @@ -27,4 +46,6 @@ void V_DrawShape(Arena *verts_arena, Arena *idx_arena, S_Shape shape, Vec4 color indices[tri_offset + 2] = i + 2; } } + + EndScratch(scratch); } diff --git a/src/proto/pp_vis/pp_vis_draw.h b/src/proto/pp_vis/pp_vis_draw.h index b535dc72..c18798e4 100644 --- a/src/proto/pp_vis/pp_vis_draw.h +++ b/src/proto/pp_vis/pp_vis_draw.h @@ -1 +1 @@ -void V_DrawShape(Arena *verts_arena, Arena *idx_arena, S_Shape shape, Vec4 color_lin); +void V_DrawShape(Arena *verts_arena, Arena *idx_arena, S_Shape shape, Vec4 color_lin, i32 detail);