line shape drawing

This commit is contained in:
jacob 2025-11-13 19:47:06 -06:00
parent df2f7f0f1b
commit 331da6edba
5 changed files with 185 additions and 67 deletions

View File

@ -3,6 +3,7 @@ S_SharedState S_shared_state = ZI;
Readonly S_Ent S_nil_ent = { Readonly S_Ent S_nil_ent = {
.local_to_parent_xf = CompXformIdentity, .local_to_parent_xf = CompXformIdentity,
.final_local_to_world_xf = CompXformIdentity, .final_local_to_world_xf = CompXformIdentity,
.tint = { 0.5, 0.5, 0.5, 1 },
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -151,7 +152,7 @@ S_Ent *S_EntFromKey(S_Lookup *lookup, S_Key key)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Iteration helpers //~ Iteration helpers
void S_ResetIter(Arena *arena, S_Iter *iter, S_Lookup *lookup, S_Key key, S_IterKind kind) S_Ent *S_FirstEntEx(Arena *arena, S_Iter *iter, S_Lookup *lookup, S_Key key, S_IterKind kind)
{ {
iter->kind = kind; iter->kind = kind;
iter->lookup = lookup; iter->lookup = lookup;
@ -175,6 +176,7 @@ void S_ResetIter(Arena *arena, S_Iter *iter, S_Lookup *lookup, S_Key key, S_Iter
n->ent_key = key; n->ent_key = key;
SllStackPush(iter->first_dfs, n); SllStackPush(iter->first_dfs, n);
} }
return S_NextEnt(arena, iter);
} }
S_Ent *S_NextEnt(Arena *arena, S_Iter *iter) S_Ent *S_NextEnt(Arena *arena, S_Iter *iter)
@ -374,7 +376,7 @@ JobDef(S_SimWorker, _, __)
lookup = S_LookupFromWorld(frame_arena, world); lookup = S_LookupFromWorld(frame_arena, world);
////////////////////////////// //////////////////////////////
//- Rebuild entity tree //- Build entity tree
{ {
/* Reset tree links */ /* Reset tree links */
@ -454,9 +456,21 @@ JobDef(S_SimWorker, _, __)
////////////////////////////// //////////////////////////////
//- Update entities from user control //- Update entities from user control
S_ResetIter(frame_arena, &iter, &lookup, S_RootKey, S_IterKind_Pre); for (S_Ent *ent = S_FirstEnt(frame_arena, &iter, &lookup); !S_IsEntNil(ent); ent = S_NextEnt(frame_arena, &iter))
for (S_Ent *ent = S_NextEnt(frame_arena, &iter); !S_IsEntNil(ent); ent = S_NextEnt(frame_arena, &iter))
{ {
if (!S_IsKeyNil(ent->camera))
{
ent->local_to_parent_xf.og.x += 1;
}
}
//////////////////////////////
//- Compute final world transforms
for (S_Ent *ent = S_FirstEnt(frame_arena, &iter, &lookup); !S_IsEntNil(ent); ent = S_NextEnt(frame_arena, &iter))
{
S_Ent *parent = S_EntFromKey(&lookup, ent->parent);
ent->final_local_to_world_xf = MulXform(parent->final_local_to_world_xf, ent->local_to_parent_xf);
} }
////////////////////////////// //////////////////////////////

View File

@ -2,7 +2,7 @@
//~ Key types //~ Key types
#define S_NilKey ((S_Key) { 0 }) #define S_NilKey ((S_Key) { 0 })
#define S_RootKey ((S_Key) { .v.hi = 0x75ebb7a47d1ca753, .v.lo = 0x2d505fc8961e5576 }) #define S_RootKey ((S_Key) { .v.hi = 0xaaaaaaaaaaaaaaaa, .v.lo = 0xaaaaaaaaaaaaaaaa })
Struct(S_Key) Struct(S_Key)
{ {
@ -43,7 +43,9 @@ Struct(S_Ent)
S_Key key; S_Key key;
////////////////////////////// //////////////////////////////
//- Pre-solve data //- Build data
Vec4 tint;
S_Key follow; S_Key follow;
S_Key camera; S_Key camera;
@ -241,7 +243,8 @@ S_Ent *S_EntFromKey(S_Lookup *lookup, S_Key key);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Iteration helpers //~ Iteration helpers
void S_ResetIter(Arena *arena, S_Iter *iter, S_Lookup *lookup, S_Key key, S_IterKind kind); #define S_FirstEnt(arena, iter, lookup) S_FirstEntEx((arena), (iter), (lookup), S_RootKey, S_IterKind_Pre)
S_Ent *S_FirstEntEx(Arena *arena, S_Iter *iter, S_Lookup *lookup, S_Key key, S_IterKind kind);
S_Ent *S_NextEnt(Arena *arena, S_Iter *iter); S_Ent *S_NextEnt(Arena *arena, S_Iter *iter);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

View File

@ -28,9 +28,10 @@ void V_Shutdown(void)
void V_PushTestEnts(Arena *arena, S_EntList *list) void V_PushTestEnts(Arena *arena, S_EntList *list)
{ {
S_Key player_key = S_RandKey(); S_Key player_key = S_RandKey();
S_Key child_key = S_RandKey();
S_Key camera_key = S_RandKey(); S_Key camera_key = S_RandKey();
i32 count = 2; i32 count = 3;
for (u64 i = 0; i < count; ++i) for (u64 i = 0; i < count; ++i)
{ {
S_EntListNode *n = PushStruct(arena, S_EntListNode); S_EntListNode *n = PushStruct(arena, S_EntListNode);
@ -43,24 +44,42 @@ void V_PushTestEnts(Arena *arena, S_EntList *list)
/* Test player */ /* Test player */
case 0: case 0:
{ {
ent->tint = Color_Red;
ent->key = player_key; ent->key = player_key;
ent->camera = camera_key; ent->camera = camera_key;
{ {
S_Shape *shape = &ent->local_shape; S_Shape *shape = &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(200, 200);
shape->points[3] = VEC2(125, 200); shape->points[3] = VEC2(100, 200);
// shape->radius = 1; shape->radius = 0;
}
} break;
/* Test child */
case 1:
{
ent->tint = Color_Cyan;
ent->key = child_key;
ent->parent = player_key;
{
S_Shape *shape = &ent->local_shape;
shape->points_count = 1;
shape->points[0] = VEC2(100, 100);
// shape->points[1] = VEC2(200, 100);
// shape->points[2] = VEC2(150, 200);
// shape->points[3] = VEC2(125, 200);
shape->radius = 20;
// ent->local_to_parent_xf = XformFromPos(VEC2(500, 500));
} }
} break; } break;
/* Test camera */ /* Test camera */
case 1: case 2:
{ {
ent->key = camera_key; // ent->key = camera_key;
} break; } break;
default: default:
@ -417,19 +436,16 @@ JobDef(V_VisWorker, _, __)
//- Build render data //- Build render data
/* Build shapes */ /* Build shapes */
S_ResetIter(frame_arena, &iter, &lookup, S_RootKey, S_IterKind_Pre); for (S_Ent *ent = S_FirstEnt(frame_arena, &iter, &lookup); !S_IsEntNil(ent); ent = S_NextEnt(frame_arena, &iter))
for (S_Ent *ent = S_NextEnt(frame_arena, &iter); !S_IsEntNil(ent); ent = S_NextEnt(frame_arena, &iter))
{ {
Xform xf = ent->final_local_to_world_xf; b32 is_visible = ent->tint.w != 0;
S_Shape shape = S_MulXformShape(ent->final_local_to_world_xf, ent->local_shape); if (is_visible)
for (i32 point_idx = 0; point_idx < shape.points_count; ++point_idx)
{ {
Vec2 *p = &shape.points[point_idx]; Xform xf = ent->final_local_to_world_xf;
*p = MulXformV2(xf, *p); S_Shape shape = S_MulXformShape(ent->final_local_to_world_xf, ent->local_shape);
Vec4 color = ent->tint;
V_DrawShape(dverts_arena, dvert_idx_arena, shape, LinearFromSrgb(color), 16, V_DrawFlag_Line);
} }
Vec4 color = Color_Red;
V_DrawShape(dverts_arena, dvert_idx_arena, shape, LinearFromSrgb(color), 16);
} }
////////////////////////////// //////////////////////////////

View File

@ -1,51 +1,123 @@
void V_DrawShape(Arena *verts_arena, Arena *idx_arena, S_Shape shape, Vec4 color_lin, i32 detail) ////////////////////////////////////////////////////////////
{ //~ Shape helpers
TempArena scratch = BeginScratchNoConflict();
Vec2Array draw_points = ZI; void V_DrawPoly(Arena *verts_arena, Arena *idx_arena, Vec2Array points, Vec4 color_lin, V_DrawFlag flags)
if (shape.radius == 0) {
if (flags & V_DrawFlag_Line)
{ {
draw_points.points = shape.points; i32 verts_count = points.count;
draw_points.count = shape.points_count; if (verts_count >= 2)
{
TempArena scratch = BeginScratchNoConflict();
{
f32 half_thickness = 1;
i32 lines_count = verts_count == 2 ? 1 : verts_count;
i32 line_verts_count = lines_count * 4;
i32 idx_count = lines_count * 6;
i32 idx_offset = ArenaCount(verts_arena, V_DVert);
/* Push dverts */
V_DVert *dverts = PushStructsNoZero(verts_arena, V_DVert, line_verts_count);
for (i32 line_idx = 0; line_idx < lines_count; ++line_idx)
{
i32 a_idx = line_idx;
i32 b_idx = line_idx + 1;
if (b_idx >= lines_count)
{
b_idx = 0;
}
Vec2 a = points.points[a_idx];
Vec2 b = points.points[b_idx];
Vec2 a_to_b = SubVec2(b, a);
Vec2 perp = Vec2WithLen(PerpVec2(a_to_b), half_thickness);
Vec2 p0 = AddVec2(a, perp);
Vec2 p1 = SubVec2(a, perp);
Vec2 p2 = SubVec2(b, perp);
Vec2 p3 = AddVec2(b, perp);
i32 offset = line_idx * 4;
dverts[offset + 0] = (V_DVert) { .pos = p0, .color_lin = color_lin };
dverts[offset + 1] = (V_DVert) { .pos = p1, .color_lin = color_lin };
dverts[offset + 2] = (V_DVert) { .pos = p2, .color_lin = color_lin };
dverts[offset + 3] = (V_DVert) { .pos = p3, .color_lin = color_lin };
}
/* Generate indices */
i32 *indices = PushStructsNoZero(idx_arena, i32, idx_count);
for (i32 line_idx = 0; line_idx < lines_count; ++line_idx)
{
i32 indices_offset = line_idx * 6;
i32 vert_idx_offset = idx_offset + (line_idx * 4);
indices[indices_offset + 0] = vert_idx_offset + 0;
indices[indices_offset + 1] = vert_idx_offset + 1;
indices[indices_offset + 2] = vert_idx_offset + 2;
indices[indices_offset + 3] = vert_idx_offset + 0;
indices[indices_offset + 4] = vert_idx_offset + 2;
indices[indices_offset + 5] = vert_idx_offset + 3;
}
}
EndScratch(scratch);
}
} }
else else
{ {
draw_points.points = PushStructsNoZero(scratch.arena, Vec2, detail); i32 verts_count = points.count;
draw_points.count = detail; if (verts_count >= 3)
for (i32 i = 0; i < detail; ++i)
{ {
f32 rad = ((f32)i / (f32)detail) * Tau; i32 idx_offset = ArenaCount(verts_arena, V_DVert);
Vec2 dir = Vec2FromAngle(rad); i32 tris_count = verts_count - 2;
Vec2 sp = S_SupportPointFromShape(shape, dir); i32 idx_count = tris_count * 3;
draw_points.points[i] = sp;
/* Push dverts */
V_DVert *dverts = PushStructsNoZero(verts_arena, V_DVert, verts_count);
for (i32 point_idx = 0; point_idx < (i32)points.count; ++point_idx)
{
V_DVert *dvert = &dverts[point_idx];
dvert->pos = points.points[point_idx];
dvert->color_lin = color_lin;
}
/* Generate indices in a fan pattern */
i32 *indices = PushStructsNoZero(idx_arena, i32, idx_count);
for (i32 i = 0; i < tris_count; ++i)
{
i32 tri_offset = i * 3;
indices[tri_offset + 0] = idx_offset;
indices[tri_offset + 1] = idx_offset + i + 1;
indices[tri_offset + 2] = idx_offset + i + 2;
}
} }
} }
}
i32 verts_count = draw_points.count;
if (verts_count >= 3) void V_DrawShape(Arena *verts_arena, Arena *idx_arena, S_Shape shape, Vec4 color_lin, i32 detail, V_DrawFlag flags)
{ {
i32 idx_offset = ArenaCount(verts_arena, V_DVert); if (shape.radius == 0)
V_DVert *dverts = PushStructsNoZero(verts_arena, V_DVert, verts_count); {
for (i32 point_idx = 0; point_idx < (i32)draw_points.count; ++point_idx) Vec2Array draw_points = ZI;
{ draw_points.points = shape.points;
V_DVert *dvert = &dverts[point_idx]; draw_points.count = shape.points_count;
dvert->pos = draw_points.points[point_idx]; V_DrawPoly(verts_arena, idx_arena, draw_points, color_lin, flags);
dvert->color_lin = color_lin; }
} else
{
i32 tris_count = verts_count - 2; TempArena scratch = BeginScratchNoConflict();
i32 idx_count = tris_count * 3; {
i32 *indices = PushStructsNoZero(idx_arena, i32, idx_count); Vec2Array draw_points = ZI;
draw_points.points = PushStructsNoZero(scratch.arena, Vec2, detail);
/* Generate indices in a fan pattern */ draw_points.count = detail;
for (i32 i = 0; i < tris_count; ++i) for (i32 i = 0; i < detail; ++i)
{ {
i32 tri_offset = idx_offset + (i * 3); f32 rad = ((f32)i / (f32)detail) * Tau;
indices[tri_offset + 0] = idx_offset; Vec2 dir = Vec2FromAngle(rad);
indices[tri_offset + 1] = i + 1; Vec2 sp = S_SupportPointFromShape(shape, dir);
indices[tri_offset + 2] = i + 2; draw_points.points[i] = sp;
} }
} V_DrawPoly(verts_arena, idx_arena, draw_points, color_lin, flags);
}
EndScratch(scratch); EndScratch(scratch);
}
} }

View File

@ -1 +1,14 @@
void V_DrawShape(Arena *verts_arena, Arena *idx_arena, S_Shape shape, Vec4 color_lin, i32 detail); ////////////////////////////////////////////////////////////
//~ Flag types
Enum(V_DrawFlag)
{
V_DrawFlag_None = 0,
V_DrawFlag_Line = (1 << 0),
};
////////////////////////////////////////////////////////////
//~ Shape helpers
void V_DrawPoly(Arena *verts_arena, Arena *idx_arena, Vec2Array points, Vec4 color_lin, V_DrawFlag flags);
void V_DrawShape(Arena *verts_arena, Arena *idx_arena, S_Shape shape, Vec4 color_lin, i32 detail, V_DrawFlag flags);