simulation debug drawing. begin collision resolution work.

This commit is contained in:
jacob 2026-01-03 01:44:07 -06:00
parent 5f6c1f629e
commit 0224b27902
5 changed files with 460 additions and 44 deletions

View File

@ -148,6 +148,8 @@ S_Shape S_MulXformShape(Xform xf, S_Shape shape)
} }
Vec2 scale = ScaleFromXform(xf); Vec2 scale = ScaleFromXform(xf);
result.radius *= MaxF32(scale.x, scale.y); result.radius *= MaxF32(scale.x, scale.y);
result.centroid = MulXformV2(xf, shape.centroid);
result.center_of_mass = MulXformV2(xf, shape.center_of_mass);
return result; return result;
} }
@ -298,13 +300,63 @@ MergesortCompareFuncDef(S_SortEntsByKeyCmp, arg_a, arg_b, _)
return result; return result;
} }
////////////////////////////////////////////////////////////
//~ Debug draw
void S_DebugDrawPoint(Vec2 p, Vec4 srgb)
{
if (S.debug_draw_enabled)
{
S_DebugDrawDesc *desc = PushStruct(S.debug_draw_descs_arena, S_DebugDrawDesc);
desc->kind = S_DebugDrawKind_Point;
desc->srgb32 = U32FromVec4(srgb);
desc->point.p = p;
}
}
void S_DebugDrawLine(Vec2 p0, Vec2 p1, Vec4 srgb)
{
if (S.debug_draw_enabled)
{
S_DebugDrawDesc *desc = PushStruct(S.debug_draw_descs_arena, S_DebugDrawDesc);
desc->kind = S_DebugDrawKind_Line;
desc->srgb32 = U32FromVec4(srgb);
desc->line.p0 = p0;
desc->line.p1 = p1;
}
}
void S_DebugDrawRect(Rng2 rect, Vec4 srgb)
{
if (S.debug_draw_enabled)
{
S_DebugDrawDesc *desc = PushStruct(S.debug_draw_descs_arena, S_DebugDrawDesc);
desc->kind = S_DebugDrawKind_Rect;
desc->srgb32 = U32FromVec4(srgb);
desc->rect = rect;
}
}
void S_DebugDrawShape(S_Shape shape, Vec4 srgb)
{
if (S.debug_draw_enabled)
{
S_DebugDrawDesc *desc = PushStruct(S.debug_draw_descs_arena, S_DebugDrawDesc);
desc->kind = S_DebugDrawKind_Shape;
desc->srgb32 = U32FromVec4(srgb);
desc->shape = shape;
}
}
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Sim tick //~ Sim tick
void S_TickForever(WaveLaneCtx *lane) void S_TickForever(WaveLaneCtx *lane)
{ {
Arena *frame_arena = AcquireArena(Gibi(64));
Arena *perm = PermArena(); Arena *perm = PermArena();
Arena *frame_arena = AcquireArena(Gibi(64));
S.debug_draw_descs_arena = AcquireArena(Gibi(64));
//- World data //- World data
Arena *ents_arena = AcquireArena(Gibi(64)); Arena *ents_arena = AcquireArena(Gibi(64));
@ -324,6 +376,7 @@ void S_TickForever(WaveLaneCtx *lane)
while (!shutdown) while (!shutdown)
{ {
shutdown = Atomic32Fetch(&S.shutdown); shutdown = Atomic32Fetch(&S.shutdown);
S.debug_draw_enabled = TweakBool("Simulation debug draw", 1);
ResetArena(frame_arena); ResetArena(frame_arena);
S_Iter iter = Zi; S_Iter iter = Zi;
@ -392,6 +445,14 @@ void S_TickForever(WaveLaneCtx *lane)
} }
UnlockTicketMutex(&S.input_back_tm); UnlockTicketMutex(&S.input_back_tm);
//////////////////////////////
//- Store double-buffered entity data
for (S_Ent *ent = S_FirstEnt(&iter, world); ent->active; ent = S_NextEnt(&iter))
{
ent->last_xf = ent->xf;
}
////////////////////////////// //////////////////////////////
//- Process world edit commands //- Process world edit commands
@ -458,19 +519,223 @@ void S_TickForever(WaveLaneCtx *lane)
} }
////////////////////////////// //////////////////////////////
//- Apply control forces //- Integrate control forces
for (S_Ent *ent = S_FirstEnt(&iter, world); ent->active; ent = S_NextEnt(&iter)) for (S_Ent *ent = S_FirstEnt(&iter, world); ent->active; ent = S_NextEnt(&iter))
{ {
Xform xf = ent->xf; Xform xf = ent->xf;
Xform desired_xf = xf;
if (!IsVec2Zero(ent->look)) if (!IsVec2Zero(ent->look))
{ {
xf = XformWithWorldRotation(xf, AngleFromVec2(ent->look)); desired_xf = XformWithWorldRotation(xf, AngleFromVec2(ent->look));
} }
xf.og = AddVec2(xf.og, MulVec2(ent->move, ent->move_speed)); desired_xf.og = AddVec2(xf.og, MulVec2(ent->move, ent->move_speed));
Vec2 pos_diff = SubVec2(desired_xf.og, xf.og);
f32 angle_diff = UnwindAngleF32(RotationFromXform(desired_xf) - RotationFromXform(xf));
ent->solved_dv = pos_diff;
ent->solved_dw = angle_diff;
}
//////////////////////////////
//- Prune constraints
//////////////////////////////
//- Generate player wall constraints
// TODO: Not like this
i64 max_constraints = 4096;
i64 constraints_count = 0;
S_Constraint *constraints = PushStructsNoZero(frame_arena, S_Constraint, max_constraints);
// for (i32 tile_y = bb_tiles.p0.y; tile_y < bb_tiles.p1.y; ++tile_y)
// {
// for (i32 tile_x = bb_tiles.p0.x; tile_x < bb_tiles.p1.x; ++tile_x)
// {
// Vec2I32 tile_pos = VEC2I32(tile_x, tile_y);
// S_TileKind tile = S_TileFromPos(tile_pos);
// }
// }
for (S_Ent *ent = S_FirstEnt(&iter, world); ent->active; ent = S_NextEnt(&iter))
{
Xform last_xf = ent->last_xf;
S_Shape last_world_shape = S_MulXformShape(last_xf, ent->local_shape);
Xform xf = ent->xf;
S_Shape world_shape = S_MulXformShape(xf, ent->local_shape);
Rng2 bb0 = S_BoundingBoxFromShape(last_world_shape);
Rng2 bb1 = S_BoundingBoxFromShape(world_shape);
if (constraints_count < max_constraints)
{
S_Constraint *constraint = &constraints[constraints_count];
// TODO: Real constraint data
constraint->ent0 = ent->key;
constraint->shape0 = world_shape;
Rng2 test_rect = Zi;
test_rect.p0 = VEC2(-1, -1);
test_rect.p1 = VEC2(1, 1);
constraint->shape1 = S_ShapeFromDesc(
.count = 4,
.points[0] = VEC2(test_rect.p0.x, test_rect.p0.y),
.points[1] = VEC2(test_rect.p1.x, test_rect.p0.y),
.points[2] = VEC2(test_rect.p1.x, test_rect.p1.y),
.points[3] = VEC2(test_rect.p0.x, test_rect.p1.y),
);
constraints_count += 1;
}
}
//////////////////////////////
//- Solve constraints
for (i64 constraint_idx = 0; constraint_idx < constraints_count; ++constraint_idx)
{
S_Constraint *constraint = &constraints[constraint_idx];
S_Ent *ent0 = S_EntFromKey(&lookup, constraint->ent0);
S_Ent *ent1 = S_EntFromKey(&lookup, constraint->ent1);
Vec2 old_dv0 = ent0->solved_dv;
Vec2 old_dv1 = ent1->solved_dv;
Vec2 dv0 = VEC2(0, 0);
Vec2 dv1 = VEC2(0, 0);
f32 dw0 = 0;
f32 dw1 = 0;
{
// // Get shapes
// S_Shape shape0 = S_ShapeFromDesc(.count = 1);
// S_Shape shape1 = S_ShapeFromDesc(.count = 1);
// if (ent0->active)
// {
// shape0 = S_MulXformShape(ent0->xf, ent0->local_shape);
// }
// if (ent1->active)
// {
// shape1 = S_MulXformShape(ent1->xf, ent1->local_shape);
// }
S_Shape shape0 = constraint->shape0;
S_Shape shape1 = constraint->shape1;
S_DebugDrawShape(shape1, Color_Cyan);
// TODO: Real dir
Vec2 shape_dir = NormVec2(SubVec2(shape1.centroid, shape0.centroid));
Vec2 neg_shape_dir = NegVec2(shape_dir);
// TODO: Real relative velocity
Vec2 rel_vel = SubVec2(old_dv1, old_dv0);
// Vec2 normal = NormVec2(rel_vel);
// Vec2 neg_normal = NegVec2(normal);
Vec2 normal = NormVec2(shape_dir);
Vec2 neg_normal = NegVec2(normal);
Vec2 shape0_pt = S_SupportPointFromShape(shape0, shape_dir);
Vec2 shape1_pt = S_SupportPointFromShape(shape1, neg_shape_dir);
Vec2 sep = SubVec2(shape1_pt, shape0_pt);
f32 sep_along_normal = DotVec2(sep, normal);
f32 rel_vel_along_normal = DotVec2(rel_vel, normal);
// f32 sep_normal = DotVec2(sep, normal);
S_DebugDrawPoint(shape0_pt, Color_Cyan);
S_DebugDrawPoint(shape1_pt, Color_Cyan);
if (sep_along_normal < 0)
{
dv0 = AddVec2(dv0, MulVec2(normal, sep_along_normal));
}
// dv0 = VEC2(sep_normal, sep_normal);
// f32 separation = constraint->sep;
}
// Update solved velocity
if (ent0->active)
{
ent0->solved_dv = AddVec2(ent0->solved_dv, dv0);
ent0->solved_dw += dw0;
}
if (ent1->active)
{
ent1->solved_dv = AddVec2(ent1->solved_dv, dv1);
ent1->solved_dw += dw1;
}
}
//////////////////////////////
//- Integrate velocities
for (S_Ent *ent = S_FirstEnt(&iter, world); ent->active; ent = S_NextEnt(&iter))
{
Xform xf = ent->xf;
xf.og = AddVec2(xf.og, ent->solved_dv);
xf = RotateXform(xf, ent->solved_dw);
ent->xf = xf; ent->xf = xf;
} }
//////////////////////////////
//- Debug draw entities
if (S.debug_draw_enabled)
{
for (S_Ent *ent = S_FirstEnt(&iter, world); ent->active; ent = S_NextEnt(&iter))
{
Xform xf = ent->xf;
S_Shape world_shape = S_MulXformShape(xf, ent->local_shape);
// Draw aabb
{
Vec4 color = VEC4(0.4, 0.2, 0.2, 1);
Rng2 bb = S_BoundingBoxFromShape(world_shape);
S_DebugDrawRect(bb, color);
}
// Draw shape
{
// Vec4 color = Color_Cyan;
Vec4 color = VEC4(0.2, 0.4, 0.2, 1);
S_DebugDrawShape(world_shape, color);
}
// Draw look
{
Vec4 color = VEC4(0.8, 0.8, 0.8, 1);
Vec2 p0 = world_shape.centroid;
Vec2 p1 = S_SupportPointFromShape(world_shape, ent->look);
S_DebugDrawLine(p0, p1, color);
}
}
}
////////////////////////////// //////////////////////////////
//- Publish sim state //- Publish sim state
@ -528,6 +793,14 @@ void S_TickForever(WaveLaneCtx *lane)
} }
} }
} }
// Push debug draw information
{
output->debug_draw_descs_count = ArenaCount(S.debug_draw_descs_arena, S_DebugDrawDesc);
output->debug_draw_descs = PushStructsNoZero(output->arena, S_DebugDrawDesc, output->debug_draw_descs_count);
CopyStructs(output->debug_draw_descs, ArenaFirst(S.debug_draw_descs_arena, S_DebugDrawDesc), output->debug_draw_descs_count);
ResetArena(S.debug_draw_descs_arena);
}
} }
UnlockTicketMutex(&S.output_back_tm); UnlockTicketMutex(&S.output_back_tm);

View File

@ -65,7 +65,9 @@ Struct(S_Ent)
////////////////////////////// //////////////////////////////
//- Build data //- Build data
Xform last_xf;
Xform xf; Xform xf;
S_Shape local_shape; S_Shape local_shape;
f32 move_speed; f32 move_speed;
@ -74,11 +76,16 @@ Struct(S_Ent)
b32 has_weapon; b32 has_weapon;
//////////////////////////////
//- Solver data
Vec2 solved_dv;
f32 solved_dw;
////////////////////////////// //////////////////////////////
//- Internal sim data //- Internal sim data
i64 next_free_ent_num; i64 next_free_ent_num;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -103,6 +110,18 @@ Struct(S_EntList)
u64 count; u64 count;
}; };
////////////////////////////////////////////////////////////
//~ Constraint types
Struct(S_Constraint)
{
S_Key ent0;
S_Key ent1;
S_Shape shape0;
S_Shape shape1;
};
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Lookup types //~ Lookup types
@ -190,6 +209,40 @@ Struct(S_CmdNode)
S_Cmd cmd; S_Cmd cmd;
}; };
////////////////////////////////////////////////////////////
//~ Debug visualization types
Enum(S_DebugDrawKind)
{
S_DebugDrawKind_Point,
S_DebugDrawKind_Line,
S_DebugDrawKind_Rect,
S_DebugDrawKind_Shape,
};
Struct(S_DebugDrawDesc)
{
S_DebugDrawKind kind;
u32 srgb32;
union
{
struct
{
Vec2 p;
} point;
struct
{
Vec2 p0;
Vec2 p1;
} line;
Rng2 rect;
S_Shape shape;
};
};
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ State types //~ State types
@ -204,9 +257,13 @@ Struct(S_InputState)
Struct(S_OutputState) Struct(S_OutputState)
{ {
Arena *arena; Arena *arena;
S_SnapshotNode *first_snapshot_node; S_SnapshotNode *first_snapshot_node;
S_SnapshotNode *last_snapshot_node; S_SnapshotNode *last_snapshot_node;
u64 snapshots_count; u64 snapshots_count;
u64 debug_draw_descs_count;
S_DebugDrawDesc *debug_draw_descs;
}; };
Struct(S_Ctx) Struct(S_Ctx)
@ -214,6 +271,9 @@ Struct(S_Ctx)
Atomic32 shutdown; Atomic32 shutdown;
Fence shutdown_fence; Fence shutdown_fence;
b32 debug_draw_enabled;
Arena *debug_draw_descs_arena;
//- Sim input //- Sim input
TicketMutex input_back_tm; TicketMutex input_back_tm;
i32 input_back_idx; i32 input_back_idx;
@ -290,6 +350,14 @@ S_World *S_WorldFromSnapshot(Arena *arena, S_Snapshot *snapshot);
MergesortCompareFuncDef(S_SortEntsByKeyCmp, arg_a, arg_b, _); MergesortCompareFuncDef(S_SortEntsByKeyCmp, arg_a, arg_b, _);
////////////////////////////////////////////////////////////
//~ Debug draw
void S_DebugDrawPoint(Vec2 p, Vec4 srgb);
void S_DebugDrawLine(Vec2 p0, Vec2 p1, Vec4 srgb);
void S_DebugDrawRect(Rng2 rect, Vec4 srgb);
void S_DebugDrawShape(S_Shape shape, Vec4 srgb);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Sim tick //~ Sim tick

View File

@ -82,18 +82,20 @@ S_TranscodeResult S_TranscodeLevel(Arena *arena, b32 pack, String packed, S_Worl
// TODO: Compress entity data // TODO: Compress entity data
// Write entity size & alignment
u32 ent_size = sizeof(S_Ent);
u32 ent_align = alignof(S_Ent);
if (result.ok) if (result.ok)
{ {
if (pack) if (pack)
{ {
BB_WriteUBits(&bw, sizeof(S_Ent), 32); BB_WriteUBits(&bw, ent_size, 32);
BB_WriteUBits(&bw, alignof(S_Ent), 32); BB_WriteUBits(&bw, ent_align, 32);
} }
else else
{ {
u32 ent_size = BB_ReadUBits(&br, 32); ent_size = BB_ReadUBits(&br, 32);
u32 ent_align = BB_ReadUBits(&br, 32); ent_align = BB_ReadUBits(&br, 32);
result.ok = ent_size == sizeof(S_Ent) && ent_align == alignof(S_Ent);
} }
} }
@ -116,9 +118,12 @@ S_TranscodeResult S_TranscodeLevel(Arena *arena, b32 pack, String packed, S_Worl
S_Ent *ents_raw = (S_Ent *)BB_ReadBytesRaw(&br, ents_count * sizeof(S_Ent)); S_Ent *ents_raw = (S_Ent *)BB_ReadBytesRaw(&br, ents_count * sizeof(S_Ent));
if (ents_raw) if (ents_raw)
{ {
result.unpacked.world.ents_count = ents_count; if (ent_size == sizeof(S_Ent) && ent_align == alignof(S_Ent))
result.unpacked.world.ents = PushStructsNoZero(arena, S_Ent, ents_count); {
CopyStructs(result.unpacked.world.ents, ents_raw, ents_count); result.unpacked.world.ents_count = ents_count;
result.unpacked.world.ents = PushStructsNoZero(arena, S_Ent, ents_count);
CopyStructs(result.unpacked.world.ents, ents_raw, ents_count);
}
} }
else else
{ {

View File

@ -100,7 +100,7 @@ void V_DrawPoly(Vec2Array points, Vec4 srgb, V_DrawFlag flags)
{ {
i32 a_idx = line_idx; i32 a_idx = line_idx;
i32 b_idx = line_idx + 1; i32 b_idx = line_idx + 1;
if (b_idx >= lines_count) if (b_idx >= points.count)
{ {
b_idx = 0; b_idx = 0;
} }
@ -200,13 +200,25 @@ void V_DrawShape(S_Shape shape, Vec4 srgb, i32 detail, V_DrawFlag flags)
} }
} }
void V_DrawLine(Vec2 p0, Vec2 p1, Vec4 srgb)
{
Vec2 points[2] = {
p0,
p1
};
Vec2Array points_arr = Zi;
points_arr.points = points;
points_arr.count = countof(points);
V_DrawPoly(points_arr, srgb, V_DrawFlag_Line);
}
void V_DrawRect(Rng2 rect, Vec4 srgb, V_DrawFlag flags) void V_DrawRect(Rng2 rect, Vec4 srgb, V_DrawFlag flags)
{ {
Vec2 points[4] = { Vec2 points[4] = {
VEC2(rect.p0.x, rect.p0.y), VEC2(rect.p0.x, rect.p0.y),
VEC2(rect.p1.x, rect.p0.y), VEC2(rect.p1.x, rect.p0.y),
VEC2(rect.p1.x, rect.p1.y), VEC2(rect.p1.x, rect.p1.y),
VEC2(rect.p0.x, rect.p1.y), VEC2(rect.p0.x, rect.p1.y)
}; };
Vec2Array points_arr = Zi; Vec2Array points_arr = Zi;
points_arr.points = points; points_arr.points = points;
@ -555,6 +567,11 @@ void V_TickForever(WaveLaneCtx *lane)
ResetArena(V.world_arena); ResetArena(V.world_arena);
V.world = S_WorldFromSnapshot(V.world_arena, &sim_output->last_snapshot_node->snapshot); V.world = S_WorldFromSnapshot(V.world_arena, &sim_output->last_snapshot_node->snapshot);
V.lookup = S_LookupFromWorld(V.world_arena, V.world); V.lookup = S_LookupFromWorld(V.world_arena, V.world);
// Copy sim debug info
V.debug_draw_descs_count = sim_output->debug_draw_descs_count;
V.debug_draw_descs = PushStructsNoZero(V.world_arena, S_DebugDrawDesc, V.debug_draw_descs_count);
CopyStructs(V.debug_draw_descs, sim_output->debug_draw_descs, V.debug_draw_descs_count);
} }
////////////////////////////// //////////////////////////////
@ -2353,7 +2370,7 @@ void V_TickForever(WaveLaneCtx *lane)
{ {
////////////////////////////// //////////////////////////////
//- Build render data //- Draw entities
// Build shape buffers // Build shape buffers
for (S_Ent *ent = S_FirstEnt(&iter, V.world); ent->active; ent = S_NextEnt(&iter)) for (S_Ent *ent = S_FirstEnt(&iter, V.world); ent->active; ent = S_NextEnt(&iter))
@ -2362,41 +2379,91 @@ void V_TickForever(WaveLaneCtx *lane)
Xform ent_to_draw_xf = MulXform(frame->world_to_draw_xf, ent_to_world_xf); Xform ent_to_draw_xf = MulXform(frame->world_to_draw_xf, ent_to_world_xf);
S_Shape draw_shape = S_MulXformShape(ent_to_draw_xf, ent->local_shape); S_Shape draw_shape = S_MulXformShape(ent_to_draw_xf, ent->local_shape);
f32 opacity = 0.5;
b32 is_visible = 1; b32 is_visible = 1;
if (is_visible) if (is_visible)
{ {
// Draw shape // // Draw shape
{ // {
Vec4 color = Color_Purple; // Vec4 color = Color_Purple;
i32 detail = 32; // color.w *= opacity;
V_DrawShape(draw_shape, color, detail, V_DrawFlag_Line); // i32 detail = 32;
} // V_DrawShape(draw_shape, color, detail, V_DrawFlag_Line);
// }
// Draw weapon // Draw weapon
if (ent->has_weapon) // if (ent->has_weapon)
{ // {
Vec4 color = Color_Cyan; // Vec4 color = Color_Cyan;
f32 width = 0.1; // color.w *= opacity;
f32 height = 0.75; // f32 width = 0.1;
S_Shape local_shape = S_ShapeFromDesc( // f32 height = 0.75;
.count = 4, // S_Shape local_shape = S_ShapeFromDesc(
.points = { // .count = 4,
VEC2(-width / 2, -height), VEC2(width / 2, -height), // .points = {
VEC2(width / 2, 0), VEC2(-width / 2, 0), // VEC2(-width / 2, -height), VEC2(width / 2, -height),
} // VEC2(width / 2, 0), VEC2(-width / 2, 0),
); // }
Xform local_xf = XformFromTrs(TRS(.t = { 0, 0 }, .r = Tau / 4)); // );
Xform xf = MulXform(ent_to_draw_xf, local_xf); // Xform local_xf = XformFromTrs(TRS(.t = { 0, 0 }, .r = Tau / 4));
S_Shape shape = S_MulXformShape(xf, local_shape); // Xform xf = MulXform(ent_to_draw_xf, local_xf);
V_DrawShape(shape, color, 10, V_DrawFlag_Line); // S_Shape shape = S_MulXformShape(xf, local_shape);
} // V_DrawShape(shape, color, 10, V_DrawFlag_Line);
// }
// Draw aabb // // Draw aabb
// {
// Vec4 color = Color_Orange;
// color.w *= opacity;
// Rng2 bb = S_BoundingBoxFromShape(draw_shape);
// V_DrawRect(bb, color, V_DrawFlag_Line);
// }
}
}
//////////////////////////////
//- Draw sim debug shapes
for (u64 desc_idx = 0; desc_idx < V.debug_draw_descs_count; ++desc_idx)
{
S_DebugDrawDesc *desc = &V.debug_draw_descs[desc_idx];
Vec4 color = Vec4FromU32(desc->srgb32);
i32 detail = 24;
f32 radius = 5;
switch(desc->kind)
{
case S_DebugDrawKind_Point:
{ {
Vec4 color = Color_Orange; Vec2 ui_p = MulXformV2(frame->world_to_ui_xf, desc->point.p);
Rng2 bb = S_BoundingBoxFromShape(draw_shape); S_Shape ui_shape = S_ShapeFromDesc(
V_DrawRect(bb, color, V_DrawFlag_Line); .count = 1,
} .points = { ui_p },
.radius = radius
);
V_DrawShape(ui_shape, color, detail, V_DrawFlag_None);
} break;
case S_DebugDrawKind_Line:
{
Vec2 ui_p0 = MulXformV2(frame->world_to_ui_xf, desc->line.p0);
Vec2 ui_p1 = MulXformV2(frame->world_to_ui_xf, desc->line.p1);
V_DrawLine(ui_p0, ui_p1, color);
} break;
case S_DebugDrawKind_Rect:
{
Rng2 ui_rect = Zi;
ui_rect.p0 = MulXformV2(frame->world_to_ui_xf, desc->rect.p0);
ui_rect.p1 = MulXformV2(frame->world_to_ui_xf, desc->rect.p1);
V_DrawRect(ui_rect, color, V_DrawFlag_Line);
} break;
case S_DebugDrawKind_Shape:
{
S_Shape ui_shape = S_MulXformShape(frame->world_to_ui_xf, desc->shape);
V_DrawShape(ui_shape, color, detail, V_DrawFlag_Line);
} break;
} }
} }

View File

@ -283,6 +283,8 @@ Struct(V_Ctx)
S_World *world; S_World *world;
S_Lookup lookup; S_Lookup lookup;
S_Key player_key; S_Key player_key;
u64 debug_draw_descs_count;
S_DebugDrawDesc *debug_draw_descs;
i64 panels_count; i64 panels_count;
i64 windows_count; i64 windows_count;
@ -318,6 +320,7 @@ String V_StringFromHotkey(Arena *arena, V_Hotkey hotkey);
void V_DrawPoly(Vec2Array points, Vec4 srgb, V_DrawFlag flags); void V_DrawPoly(Vec2Array points, Vec4 srgb, V_DrawFlag flags);
void V_DrawShape(S_Shape shape, Vec4 srgb, i32 detail, V_DrawFlag flags); void V_DrawShape(S_Shape shape, Vec4 srgb, i32 detail, V_DrawFlag flags);
void V_DrawLine(Vec2 p0, Vec2 p1, Vec4 srgb);
void V_DrawRect(Rng2 rect, Vec4 srgb, V_DrawFlag flags); void V_DrawRect(Rng2 rect, Vec4 srgb, V_DrawFlag flags);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////