rounded shape drawing

This commit is contained in:
jacob 2025-11-13 15:02:31 -06:00
parent 03eed624c9
commit 5a3f5ad12b
6 changed files with 108 additions and 39 deletions

View File

@ -348,7 +348,8 @@ PackedVec4 PackVec4(Vec4 v);
b32 MatchXform(Xform xf1, Xform xf2); b32 MatchXform(Xform xf1, Xform xf2);
//- Initialization //- 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 XformFromPos(Vec2 v);
Xform XformFromRot(f32 r); Xform XformFromRot(f32 r);
Xform XformFromScale(Vec2 scale); Xform XformFromScale(Vec2 scale);

View File

@ -1,5 +1,9 @@
S_SharedState S_shared_state = ZI; 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 //~ Startup
@ -38,7 +42,7 @@ void S_Shutdown(void)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Nil helpers //~ Nil helpers
b32 S_IsKeyNil(S_EntKey key) b32 S_IsKeyNil(S_Key key)
{ {
return key.v.hi == 0 && key.v.lo == 0; 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; 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; 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 //~ 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; S_Ent *ent = &S_nil_ent;
if (!S_IsKeyNil(key)) 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]; S_EntLookupNode *n = world->ent_bins[key.v.lo % world->ent_bins_count];
for (; n; n = n->next) for (; n; n = n->next)
{ {
if (S_MatchEntKey(n->ent->key, key)) if (S_MatchKey(n->ent->key, key))
{ {
ent = n->ent; ent = n->ent;
break; 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) for (i64 ent_idx = 0; ent_idx < world->allocated_ents_count; ++ent_idx)
{ {
S_Ent *ent = &world->ents[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); S_EntLookupNode *n = PushStruct(arena, S_EntLookupNode);
n->ent = ent; n->ent = ent;
S_EntLookupNode **bin = &world->ent_bins[ent->key.v.lo % world->ent_bins_count]; 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) for (i64 ent_idx = 0; ent_idx < world->allocated_ents_count; ++ent_idx)
{ {
S_Ent *ent = &world->ents[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; n->ent = ent;
break; break;
@ -180,7 +217,7 @@ JobDef(S_SimWorker, _, __)
S_Ent *root_ent = &empty_ss->ents[empty_ss->ents_count++]; S_Ent *root_ent = &empty_ss->ents[empty_ss->ents_count++];
{ {
*root_ent = S_nil_ent; *root_ent = S_nil_ent;
root_ent->key = S_RootEntKey; root_ent->key = S_RootKey;
} }
/* Create test ent */ /* Create test ent */
S_Ent *test_ent = &empty_ss->ents[empty_ss->ents_count++]; 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 = S_nil_ent;
// test_ent->shape.points_count = 1; // test_ent->shape.points_count = 1;
// test_ent->shape.radius = 0.25; // 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_count = 4;
shape->points[0] = VEC2(100, 100); shape->points[0] = VEC2(100, 100);
shape->points[1] = VEC2(200, 100); shape->points[1] = VEC2(200, 100);
shape->points[2] = VEC2(150, 200); shape->points[2] = VEC2(150, 200);
shape->points[3] = VEC2(125, 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; b32 shutdown = 0;
while (!shutdown) while (!shutdown)
@ -260,6 +294,9 @@ JobDef(S_SimWorker, _, __)
} }
} }
//////////////////////////////
//- Update entities from user control
////////////////////////////// //////////////////////////////
//- Publish sim state //- Publish sim state

View File

@ -1,10 +1,10 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Key types //~ Key types
#define S_NilEntKey ((S_EntKey) { 0 }) #define S_NilKey ((S_Key) { 0 })
#define S_RootEntKey ((S_EntKey) { .v.hi = 0x75ebb7a47d1ca753, .v.lo = 0x2d505fc8961e5576 }) #define S_RootKey ((S_Key) { .v.hi = 0x75ebb7a47d1ca753, .v.lo = 0x2d505fc8961e5576 })
Struct(S_EntKey) Struct(S_Key)
{ {
U128 v; U128 v;
}; };
@ -15,7 +15,7 @@ Struct(S_EntKey)
Struct(S_Shape) Struct(S_Shape)
{ {
f32 radius; f32 radius;
u32 points_count; i32 points_count;
Vec2 points[8]; Vec2 points[8];
}; };
@ -36,18 +36,22 @@ Enum(S_EntProp)
Struct(S_Ent) Struct(S_Ent)
{ {
//- Tree data //- Tree data
S_EntKey parent; S_Key parent;
S_EntKey first; S_Key first;
S_EntKey last; S_Key last;
S_EntKey next; S_Key next;
S_EntKey prev; S_Key prev;
i64 count; i64 count;
//- Persistent data //- Persistent data
S_EntKey key; S_Key key;
//- Build data //- 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 //- Per-world data
i64 pre_idx; i64 pre_idx;
@ -177,14 +181,20 @@ void S_Shutdown(void);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Nil helpers //~ Nil helpers
b32 S_IsKeyNil(S_EntKey key); b32 S_IsKeyNil(S_Key key);
b32 S_IsEntNil(S_Ent *ent); 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 //~ Lookup helpers
S_Ent *S_EntFromKey(S_World *world, S_EntKey key); S_Ent *S_EntFromKey(S_World *world, S_Key key);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Snapshot helpers //~ Snapshot helpers

View File

@ -352,15 +352,15 @@ JobDef(V_VisWorker, _, __)
// Xform xf = ent->final_to_world_xf; // Xform xf = ent->final_to_world_xf;
Xform xf = XformIdentity; Xform xf = XformIdentity;
S_Shape shape = ent->shape; S_Shape shape = S_MulXformShape(ent->final_local_to_world_xf, ent->local_shape);
for (u32 point_idx = 0; point_idx < shape.points_count; ++point_idx) for (i32 point_idx = 0; point_idx < shape.points_count; ++point_idx)
{ {
Vec2 *p = &shape.points[point_idx]; Vec2 *p = &shape.points[point_idx];
*p = MulXformV2(xf, *p); *p = MulXformV2(xf, *p);
} }
Vec4 color = Color_Red; 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);
} }
////////////////////////////// //////////////////////////////

View File

@ -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) if (verts_count >= 3)
{ {
i32 idx_offset = ArenaCount(verts_arena, V_DVert); i32 idx_offset = ArenaCount(verts_arena, V_DVert);
V_DVert *dverts = PushStructsNoZero(verts_arena, V_DVert, verts_count); 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]; V_DVert *dvert = &dverts[point_idx];
dvert->pos = shape.points[point_idx]; dvert->pos = draw_points.points[point_idx];
dvert->color_lin = color_lin; 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; indices[tri_offset + 2] = i + 2;
} }
} }
EndScratch(scratch);
} }

View File

@ -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);