more animation testing

This commit is contained in:
jacob 2026-01-27 13:54:40 -06:00
parent 0ee976cda2
commit fb180afbc5
12 changed files with 202 additions and 162 deletions

View File

@ -535,6 +535,11 @@ Vec2 RotateVec2(Vec2 v, f32 a)
return VEC2(v.x * c - v.y * s, v.x * s + v.y * c); return VEC2(v.x * c - v.y * s, v.x * s + v.y * c);
} }
Vec2 RotateVec2Vec2(Vec2 a, Vec2 b)
{
return VEC2(a.x * b.x - a.y * b.y, a.x * b.y + a.y * b.x);
}
Vec2 Vec2FromAngle(f32 a) Vec2 Vec2FromAngle(f32 a)
{ {
return VEC2(CosF32(a), SinF32(a)); return VEC2(CosF32(a), SinF32(a));
@ -837,14 +842,6 @@ Affine AffineFromScale(Vec2 scale)
return result; return result;
} }
Affine AffineFromTrs(Trs trs)
{
Affine af = AffineFromPos(trs.t);
af = RotateAffine(af, trs.r);
af = ScaleAffine(af, trs.s);
return af;
}
//- Translation //- Translation
Affine TranslateAffine(Affine af, Vec2 v) Affine TranslateAffine(Affine af, Vec2 v)
{ {
@ -924,7 +921,7 @@ Affine InvertAffine(Affine af)
af.bx = MulVec2Vec2(af.bx, VEC2(inv_det, -inv_det)); af.bx = MulVec2Vec2(af.bx, VEC2(inv_det, -inv_det));
af.by = MulVec2Vec2(af.by, VEC2(-inv_det, inv_det)); af.by = MulVec2Vec2(af.by, VEC2(-inv_det, inv_det));
af.og = MulAffineBasisV2(af, NegVec2(af.og)); af.og = MulAffineBasisVec2(af, NegVec2(af.og));
return af; return af;
} }
@ -937,11 +934,11 @@ Affine MulAffine(Affine a, Affine b)
result.bx.y = a.bx.y * b.bx.x + a.by.y * b.bx.y; result.bx.y = a.bx.y * b.bx.x + a.by.y * b.bx.y;
result.by.x = a.bx.x * b.by.x + a.by.x * b.by.y; result.by.x = a.bx.x * b.by.x + a.by.x * b.by.y;
result.by.y = a.bx.y * b.by.x + a.by.y * b.by.y; result.by.y = a.bx.y * b.by.x + a.by.y * b.by.y;
result.og = MulAffineV2(a, b.og); result.og = MulAffineVec2(a, b.og);
return result; return result;
} }
Vec2 MulAffineBasisV2(Affine af, Vec2 v) Vec2 MulAffineBasisVec2(Affine af, Vec2 v)
{ {
return VEC2( return VEC2(
af.bx.x * v.x + af.by.x * v.y, af.bx.x * v.x + af.by.x * v.y,
@ -949,26 +946,26 @@ Vec2 MulAffineBasisV2(Affine af, Vec2 v)
); );
} }
Vec2 MulAffineV2(Affine af, Vec2 v) Vec2 MulAffineVec2(Affine af, Vec2 v)
{ {
Vec2 result = MulAffineBasisV2(af, v); Vec2 result = MulAffineBasisVec2(af, v);
result = AddVec2(result, af.og); result = AddVec2(result, af.og);
return result; return result;
} }
Vec2 InvertAffineBasisMulV2(Affine af, Vec2 v) Vec2 InvertAffineBasisMulVec2(Affine af, Vec2 v)
{ {
Affine inv = InvertAffine(af); Affine inv = InvertAffine(af);
Vec2 result = MulAffineBasisV2(inv, v); Vec2 result = MulAffineBasisVec2(inv, v);
return result; return result;
} }
// TODO: Get rid of this? Just force caller to use invert manually since it's expensive. // TODO: Get rid of this? Just force caller to use invert manually since it's expensive.
Vec2 InvertAffineMulV2(Affine af, Vec2 v) Vec2 InvertAffineMulVec2(Affine af, Vec2 v)
{ {
Affine inv = InvertAffine(af); Affine inv = InvertAffine(af);
return MulAffineV2(inv, v); return MulAffineVec2(inv, v);
} }
//- Helpers //- Helpers
@ -1017,6 +1014,24 @@ Vec2 ScaleFromAffine(Affine af)
return VEC2(Vec2Len(af.bx), det_sign * Vec2Len(af.by)); return VEC2(Vec2Len(af.bx), det_sign * Vec2Len(af.by));
} }
////////////////////////////////////////////////////////////
//~ Xform
Xform MulXform(Xform a, Xform b)
{
Xform result = Zi;
result.r = RotateVec2Vec2(a.r, b.r);
result.t = AddVec2(RotateVec2Vec2(a.r, b.t), a.t);
return result;
}
Vec2 MulXformVec2(Xform xf, Vec2 v)
{
Vec2 result = Zi;
result = AddVec2(RotateVec2Vec2(v, xf.r), xf.t);
return result;
}
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Spring //~ Spring

View File

@ -151,9 +151,9 @@ Struct(Rng3U64) { Vec3U64 p0, p1; };
Struct(Affine) Struct(Affine)
{ {
Vec2 bx; // X basis vector (x axis) Vec2 bx; // X basis
Vec2 by; // Y basis vector (y axis) Vec2 by; // Y basis
Vec2 og; // Translation vector (origin) Vec2 og; // Origin
}; };
// (T)ranslation, (R)otation, (S)cale // (T)ranslation, (R)otation, (S)cale
@ -164,6 +164,15 @@ Struct(Trs)
f32 r; f32 r;
}; };
////////////////////////////////////////////////////////////
//~ Xform types
Struct(Xform)
{
Vec2 t; // Translation
Vec2 r; // Rotation
};
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Spring types //~ Spring types
@ -375,6 +384,7 @@ Vec2 CeilVec2(Vec2 a);
//- Angle //- Angle
i32 WindingFromVec2(Vec2 a, Vec2 b); i32 WindingFromVec2(Vec2 a, Vec2 b);
Vec2 RotateVec2(Vec2 v, f32 a); Vec2 RotateVec2(Vec2 v, f32 a);
Vec2 RotateVec2Vec2(Vec2 a, Vec2 b);
Vec2 Vec2FromAngle(f32 a); Vec2 Vec2FromAngle(f32 a);
f32 AngleFromVec2(Vec2 v); f32 AngleFromVec2(Vec2 v);
f32 AngleFromVec2Dirs(Vec2 dir1, Vec2 dir2); f32 AngleFromVec2Dirs(Vec2 dir1, Vec2 dir2);
@ -438,15 +448,15 @@ Rng2I32 DivRng2I32Vec2I32(Rng2I32 a, Vec2I32 v);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Affine //~ Affine
#define AffineIdentity ((Affine) { .bx = { .x = 1 }, .by = { .y = 1 } })
#define CompAffineIdentity { .bx = { .x = 1 }, .by = { .y = 1 } }
b32 MatchAffine(Affine af1, Affine af2); b32 MatchAffine(Affine af1, Affine af2);
//- Initialization //- Initialization
#define AffineIdentity (Affine) { .bx = { .x = 1 }, .by = { .y = 1 } }
#define CompAffineIdentity { .bx = { .x = 1 }, .by = { .y = 1 } }
Affine AffineFromPos(Vec2 v); Affine AffineFromPos(Vec2 v);
Affine AffineFromRot(f32 r); Affine AffineFromRot(f32 r);
Affine AffineFromScale(Vec2 scale); Affine AffineFromScale(Vec2 scale);
Affine AffineFromTrs(Trs trs);
//- Translation //- Translation
Affine TranslateAffine(Affine af, Vec2 v); Affine TranslateAffine(Affine af, Vec2 v);
@ -469,11 +479,11 @@ Affine LerpAffine(Affine a, Affine b, f32 t);
Affine InvertAffine(Affine af); Affine InvertAffine(Affine af);
//- Mul //- Mul
Vec2 MulAffineV2(Affine af, Vec2 v); Vec2 MulAffineVec2(Affine af, Vec2 v);
Affine MulAffine(Affine a, Affine b); Affine MulAffine(Affine a, Affine b);
Vec2 MulAffineBasisV2(Affine af, Vec2 v); Vec2 MulAffineBasisVec2(Affine af, Vec2 v);
Vec2 InvertAffineMulV2(Affine af, Vec2 v); Vec2 InvertAffineMulVec2(Affine af, Vec2 v);
Vec2 InvertAffineBasisMulV2(Affine af, Vec2 v); Vec2 InvertAffineBasisMulVec2(Affine af, Vec2 v);
//- Helpers //- Helpers
Affine BasisFromAffine(Affine af); Affine BasisFromAffine(Affine af);
@ -485,8 +495,13 @@ Vec2 DownFromAffine(Affine af);
f32 RotationFromAffine(Affine af); f32 RotationFromAffine(Affine af);
Vec2 ScaleFromAffine(Affine af); Vec2 ScaleFromAffine(Affine af);
//- Trs ////////////////////////////////////////////////////////////
#define TRS(...) ((Trs) { .t = VEC2(0,0), .s = VEC2(1, 1), .r = 0, __VA_ARGS__ }) //~ Xform
#define XformIdentity ((Xform) { .r = { 1, 0 } })
#define CompXformIdentity { .r = { 1, 0 } }
Vec2 MulXformVec2(Xform xf, Vec2 v);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Spring //~ Spring

View File

@ -69,7 +69,7 @@ CLD_SupportPoint CLD_SupportPointFromDirEx(CLD_Shape *shape, Affine af, Vec2 dir
furthest = AddVec2(furthest, dir); furthest = AddVec2(furthest, dir);
} }
furthest = MulAffineV2(af, furthest); furthest = MulAffineVec2(af, furthest);
CLD_SupportPoint result; CLD_SupportPoint result;
result.p = furthest; result.p = furthest;
@ -919,7 +919,7 @@ CLD_ClosestPointData CLD_ClosestPointDataFromShapes(CLD_Shape *shape0, CLD_Shape
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Time of impact //~ Time of impact
// Takes 2 shapes and their Affines at t=0 and t=1. // Takes 2 shapes and their affines at t=0 and t=1.
// Returns time of impact in range [0, 1]. // Returns time of impact in range [0, 1].
f32 CLD_TimeOfImpact(CLD_Shape *c0, CLD_Shape *c1, Affine af0_t0, Affine af1_t0, Affine af0_t1, Affine af1_t1, f32 tolerance, u32 max_iterations) f32 CLD_TimeOfImpact(CLD_Shape *c0, CLD_Shape *c1, Affine af0_t0, Affine af1_t0, Affine af0_t1, Affine af1_t1, f32 tolerance, u32 max_iterations)
{ {
@ -1031,10 +1031,10 @@ Vec2Array CLD_PointCloud(Arena *arena, CLD_Shape *shape0, CLD_Shape *shape1, Aff
u32 count1 = shape1->count; u32 count1 = shape1->count;
for (u64 i = 0; i < count0; ++i) for (u64 i = 0; i < count0; ++i)
{ {
Vec2 p0 = MulAffineV2(af0, points0[i]); Vec2 p0 = MulAffineVec2(af0, points0[i]);
for (u64 j = 0; j < count1; ++j) for (u64 j = 0; j < count1; ++j)
{ {
Vec2 p1 = MulAffineV2(af1, points1[j]); Vec2 p1 = MulAffineVec2(af1, points1[j]);
*PushStructNoZero(arena, Vec2) = SubVec2(p0, p1); *PushStructNoZero(arena, Vec2) = SubVec2(p0, p1);
++result.count; ++result.count;
} }

View File

@ -226,7 +226,7 @@ void D_DrawColliderLine(GPU_RenderSig *sig, CLD_Shape shape, Affine shape_af, f3
poly.points = PushStructsNoZero(scratch.arena, Vec2, shape.count); poly.points = PushStructsNoZero(scratch.arena, Vec2, shape.count);
for (u32 i = 0; i < shape.count; ++i) for (u32 i = 0; i < shape.count; ++i)
{ {
Vec2 p = MulAffineV2(shape_af, shape.points[i]); Vec2 p = MulAffineVec2(shape_af, shape.points[i]);
poly.points[i] = p; poly.points[i] = p;
} }
} }

View File

@ -2,8 +2,8 @@ P_Ctx P = Zi;
ThreadLocal P_ThreadLocalCtx P_tl = Zi; ThreadLocal P_ThreadLocalCtx P_tl = Zi;
Readonly P_Ent P_NilEnt = { Readonly P_Ent P_NilEnt = {
.af = CompAffineIdentity, .xf = CompXformIdentity,
.control.look = { 0, -1 }, .control.look = { 1, 0 },
}; };
Readonly P_Frame P_NilFrame = { Readonly P_Frame P_NilFrame = {
@ -124,17 +124,15 @@ P_Shape P_ShapeFromDescEx(P_ShapeDesc desc)
return result; return result;
} }
P_Shape P_MulAffineShape(Affine af, P_Shape shape) P_Shape P_MulXformShape(Xform xf, P_Shape shape)
{ {
P_Shape result = shape; P_Shape result = shape;
for (i32 i = 0; i < shape.points_count; ++i) for (i32 i = 0; i < shape.points_count; ++i)
{ {
result.points[i] = MulAffineV2(af, shape.points[i]); result.points[i] = MulXformVec2(xf, shape.points[i]);
} }
Vec2 scale = ScaleFromAffine(af); result.centroid = MulXformVec2(xf, shape.centroid);
result.radius *= MaxF32(scale.x, scale.y); result.center_of_mass = MulXformVec2(xf, shape.center_of_mass);
result.centroid = MulAffineV2(af, shape.centroid);
result.center_of_mass = MulAffineV2(af, shape.center_of_mass);
return result; return result;
} }
@ -193,7 +191,7 @@ P_Shape P_LocalShapeFromEnt(P_Ent *ent)
P_Shape P_WorldShapeFromEnt(P_Ent *ent) P_Shape P_WorldShapeFromEnt(P_Ent *ent)
{ {
P_Shape local = P_LocalShapeFromEnt(ent); P_Shape local = P_LocalShapeFromEnt(ent);
P_Shape world = P_MulAffineShape(ent->af, local); P_Shape world = P_MulXformShape(ent->xf, local);
return world; return world;
} }
@ -1363,7 +1361,7 @@ void P_DebugDrawFrame(P_Frame *frame)
{ {
Vec4 color = VEC4(0.8, 0.8, 0.8, 1); Vec4 color = VEC4(0.8, 0.8, 0.8, 1);
Vec2 p0 = world_shape.centroid; Vec2 p0 = world_shape.centroid;
Vec2 p1 = P_EdgePointFromShape(world_shape, UpFromAffine(ent->af)); Vec2 p1 = P_EdgePointFromShape(world_shape, ent->xf.r);
P_DebugDrawLine(p0, p1, color); P_DebugDrawLine(p0, p1, color);
} }
@ -1647,7 +1645,7 @@ void P_StepFrame(P_Frame *frame)
for (P_Ent *ent = P_FirstEnt(frame); !P_IsEntNil(ent); ent = P_NextEnt(ent)) for (P_Ent *ent = P_FirstEnt(frame); !P_IsEntNil(ent); ent = P_NextEnt(ent))
{ {
ent->prev_af = ent->af; ent->prev_xf = ent->xf;
} }
////////////////////////////// //////////////////////////////
@ -2405,10 +2403,10 @@ void P_StepFrame(P_Frame *frame)
{ {
if (!is_predicting || ent == local_guy) if (!is_predicting || ent == local_guy)
{ {
Affine af = ent->af; Xform xf = ent->xf;
af.og = AddVec2(af.og, MulVec2(ent->solved_v, solver_dt)); xf.t = AddVec2(xf.t, MulVec2(ent->solved_v, solver_dt));
af = RotateAffine(af, ent->solved_w * solver_dt); xf.r = RotateVec2(xf.r, ent->solved_w * solver_dt);
ent->af = af; ent->xf = xf;
} }
} }
} }
@ -2463,25 +2461,27 @@ void P_StepFrame(P_Frame *frame)
Vec2 base_pos = P_EdgePointFromShape(firer_world_shape, firer->control.look); Vec2 base_pos = P_EdgePointFromShape(firer_world_shape, firer->control.look);
Vec2 base_dir = firer->control.look; Vec2 base_dir = firer->control.look;
// Vec2 base_pos = Zi; // Xform base_xf = Zi;
// Vec2 base_dir = Zi;
// { // {
// P_Anim anim = P_AnimFromEnt(firer); // P_Anim anim = P_AnimFromEnt(firer, frame->time_ns);
// SPR_LayerKey origin_layer = SPR_LayerKeyFromName(Lit(".origin")); // SPR_LayerKey origin_layer = SPR_LayerKeyFromName(Lit(".origin"));
// SPR_LayerKey ap_layer = SPR_LayerKeyFromName(Lit(".ap")); // SPR_LayerKey ap_layer = SPR_LayerKeyFromName(Lit(".ap"));
// Vec2 firer_origin_ray = SPR_RayFromSheet(anim.sheet, anim.span, anim.frame_seq, origin_layer); // Xform firer_to_body_origin_xf = SPR_XformFromSheet(anim.sheet, origin_layer, anim.span, anim.frame_seq);
// Vec2 firer_ap_ray = SPR_RayFromSheet(anim.sheet, anim.span, anim.frame_seq, ap_layer); // Xform firer_to_body_ap_xf = SPR_XformFromSheet(anim.sheet, ap_layer, anim.span, anim.frame_seq);
// Vec2 wep_origin_ray = SPR_RayFromSheet(anim.wep_sheet, anim.span, anim.frame_seq, origin_layer); // Xform body_ap_to_wep_origin_xf = SPR_XformFromSheet(anim.wep_sheet, origin_layer, anim.span, anim.frame_seq);
// Vec2 wep_ap_ray = SPR_RayFromSheet(anim.wep_sheet, anim.span, anim.frame_seq, ap_layer); // Xform body_ap_to_wep_ap_xf = SPR_XformFromSheet(anim.wep_sheet, ap_layer, anim.span, anim.frame_seq);
// Vec2 fo2w = SubVec2(firer_ // // Xform fo2w = SubVec2(firer_
// base_pos = // Xform firer_to_world_xf = firer->xf;
// Xform bullet_xf = MulXform(firer_to_world_xf, firer_to_body_ap_xf);
// base_pos = bullet_xf.t;
// // FIXME: Real dir // // FIXME: Real dir
// base_dir = firer->control.look; // // base_dir = firer->control.look;
// base_dir = bullet_xf.r;
// } // }

View File

@ -112,8 +112,8 @@ Struct(P_Ent)
b32 is_dummy; b32 is_dummy;
f32 health; f32 health;
Affine prev_af; Xform prev_xf;
Affine af; Xform xf;
// TODO: Remove this (weapon testing) // TODO: Remove this (weapon testing)
i64 last_fire_ns; i64 last_fire_ns;
@ -328,7 +328,7 @@ Struct(P_Msg)
u64 tiles_hash; u64 tiles_hash;
P_Key key; P_Key key;
Vec2 pos; Xform xf;
String data; String data;
}; };
@ -481,7 +481,7 @@ String P_NameFromTileKind(P_TileKind kind);
P_Shape P_ShapeFromDescEx(P_ShapeDesc desc); P_Shape P_ShapeFromDescEx(P_ShapeDesc desc);
#define P_ShapeFromDesc(...) P_ShapeFromDescEx((P_ShapeDesc) { __VA_ARGS__ }) #define P_ShapeFromDesc(...) P_ShapeFromDescEx((P_ShapeDesc) { __VA_ARGS__ })
P_Shape P_MulAffineShape(Affine af, P_Shape shape); P_Shape P_MulXformShape(Xform xf, P_Shape shape);
Rng2 P_BoundingBoxFromShape(P_Shape shape); Rng2 P_BoundingBoxFromShape(P_Shape shape);
P_Shape P_LocalShapeFromEnt(P_Ent *ent); P_Shape P_LocalShapeFromEnt(P_Ent *ent);

View File

@ -594,7 +594,7 @@ void S_TickForever(WaveLaneCtx *lane)
P_Ent *guy = P_PushTempEnt(frame_arena, &ents); P_Ent *guy = P_PushTempEnt(frame_arena, &ents);
*guy = P_NilEnt; *guy = P_NilEnt;
guy->key = msg->key; guy->key = msg->key;
guy->af = AffineFromPos(msg->pos); guy->xf = msg->xf;
guy->is_guy = 1; guy->is_guy = 1;
guy->has_weapon = 1; guy->has_weapon = 1;
guy->exists = 1; guy->exists = 1;
@ -604,7 +604,7 @@ void S_TickForever(WaveLaneCtx *lane)
P_Ent *guy = P_PushTempEnt(frame_arena, &ents); P_Ent *guy = P_PushTempEnt(frame_arena, &ents);
*guy = P_NilEnt; *guy = P_NilEnt;
guy->key = P_RandKey(); guy->key = P_RandKey();
guy->af = AffineFromPos(msg->pos); guy->xf = msg->xf;
guy->is_guy = 1; guy->is_guy = 1;
guy->has_weapon = 1; guy->has_weapon = 1;
guy->exists = 1; guy->exists = 1;
@ -621,7 +621,7 @@ void S_TickForever(WaveLaneCtx *lane)
// P_Ent *ent = P_PushTempEnt(frame_arena, &ents); // P_Ent *ent = P_PushTempEnt(frame_arena, &ents);
// *ent = P_NilEnt; // *ent = P_NilEnt;
// ent->key = msg->key; // ent->key = msg->key;
// ent->af = AffineFromPos(msg->pos); // ent->xf = msg->xf;
// ent->is_guy = 1; // ent->is_guy = 1;
// ent->is_dummy = 1; // ent->is_dummy = 1;
// ent->has_weapon = 1; // ent->has_weapon = 1;
@ -710,6 +710,7 @@ void S_TickForever(WaveLaneCtx *lane)
msg->tile_range = RNG2I32(VEC2I32(0, 0), VEC2I32(P_TilesPitch, P_TilesPitch)); msg->tile_range = RNG2I32(VEC2I32(0, 0), VEC2I32(P_TilesPitch, P_TilesPitch));
msg->dst = client->net_key; msg->dst = client->net_key;
msg->data = STRING(P_TilesCount, world->tiles); msg->data = STRING(P_TilesCount, world->tiles);
msg->xf = XformIdentity;
client->remote_tiles_hash = world->tiles_hash; client->remote_tiles_hash = world->tiles_hash;
} }
} }

View File

@ -60,8 +60,8 @@ String P_PackWorld(Arena *arena, P_World *src_world)
} }
} }
result.len += StringF(arena, " }\n").len; result.len += StringF(arena, " }\n").len;
result.len += StringF(arena, " pos: \"%F\"\n", FmtFloat2(ent->af.og)).len; result.len += StringF(arena, " pos: \"%F\"\n", FmtFloat2(ent->xf.t)).len;
result.len += StringF(arena, " rot: \"%F\"\n", FmtFloat2(RightFromAffine(ent->af))).len; result.len += StringF(arena, " angle: \"%F\"\n", FmtFloat(AngleFromVec2(ent->xf.r))).len;
result.len += StringF(arena, " exists: \"%F\"\n", FmtFloat(ent->exists)).len; result.len += StringF(arena, " exists: \"%F\"\n", FmtFloat(ent->exists)).len;
result.len += StringF(arena, " look: \"%F\"\n", FmtFloat2(ent->control.look)).len; result.len += StringF(arena, " look: \"%F\"\n", FmtFloat2(ent->control.look)).len;
} }
@ -163,12 +163,11 @@ P_UnpackedWorld P_UnpackWorld(Arena *arena, String packed)
if (MatchString(attr->name, Lit("pos"))) if (MatchString(attr->name, Lit("pos")))
{ {
Vec2 pos = CR_Vec2FromString(attr->value); Vec2 pos = CR_Vec2FromString(attr->value);
ent->af.og = pos; ent->xf.t = pos;
} }
if (MatchString(attr->name, Lit("rot"))) if (MatchString(attr->name, Lit("angle")))
{ {
Vec2 rot = CR_Vec2FromString(attr->value); ent->xf.r = Vec2FromAngle(CR_FloatFromString(attr->value));
ent->af = AffineWithWorldRotation(ent->af, AngleFromVec2(rot));
} }
if (MatchString(attr->name, Lit("exists"))) if (MatchString(attr->name, Lit("exists")))
{ {

View File

@ -184,34 +184,37 @@ void V_DrawPoly(Vec2Array points, Vec4 srgb, V_DrawFlag flags)
} }
} }
void V_DrawShape(P_Shape shape, Vec4 srgb, i32 detail, V_DrawFlag flags) void V_DrawShape(P_Shape shape, Affine af, Vec4 srgb, i32 detail, V_DrawFlag flags)
{
TempArena scratch = BeginScratchNoConflict();
Vec2Array draw_points = Zi;
{ {
if (shape.radius == 0) if (shape.radius == 0)
{ {
Vec2Array draw_points = Zi;
draw_points.points = shape.points;
draw_points.count = shape.points_count; draw_points.count = shape.points_count;
draw_points.points = PushStructsNoZero(scratch.arena, Vec2, draw_points.count);
for (i32 point_idx = 0; point_idx < draw_points.count; ++point_idx)
{
draw_points.points[point_idx] = MulAffineVec2(af, shape.points[point_idx]);
}
V_DrawPoly(draw_points, srgb, flags); V_DrawPoly(draw_points, srgb, flags);
} }
else else
{ {
TempArena scratch = BeginScratchNoConflict();
{
Vec2Array draw_points = Zi;
draw_points.points = PushStructsNoZero(scratch.arena, Vec2, detail);
draw_points.count = detail; draw_points.count = detail;
for (i32 i = 0; i < detail; ++i) draw_points.points = PushStructsNoZero(scratch.arena, Vec2, draw_points.count);
for (i32 point_idx = 0; point_idx < detail; ++point_idx)
{ {
f32 rad = ((f32)i / (f32)detail) * Tau; f32 rad = ((f32)point_idx / (f32)detail) * Tau;
Vec2 dir = Vec2FromAngle(rad); Vec2 dir = Vec2FromAngle(rad);
Vec2 sp = P_SupportPointFromShape(shape, dir).p; Vec2 sp = P_SupportPointFromShape(shape, dir).p;
draw_points.points[i] = sp; draw_points.points[point_idx] = MulAffineVec2(af, sp);
}
}
} }
V_DrawPoly(draw_points, srgb, flags); V_DrawPoly(draw_points, srgb, flags);
}
EndScratch(scratch); EndScratch(scratch);
} }
}
void V_DrawLine(Vec2 p0, Vec2 p1, Vec4 srgb) void V_DrawLine(Vec2 p0, Vec2 p1, Vec4 srgb)
{ {
@ -246,7 +249,7 @@ void V_DrawPoint(Vec2 p, Vec4 srgb)
.points = { p }, .points = { p },
.radius = 5 .radius = 5
); );
V_DrawShape(ui_shape, srgb, 24, V_DrawFlag_None); V_DrawShape(ui_shape, AffineIdentity, srgb, 24, V_DrawFlag_None);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -836,8 +839,8 @@ void V_TickForever(WaveLaneCtx *lane)
edit_to_screen_af = TranslateAffine(edit_to_screen_af, NegVec2(frame->edit_camera_pos)); edit_to_screen_af = TranslateAffine(edit_to_screen_af, NegVec2(frame->edit_camera_pos));
edit_to_screen_af = WorldTranslateAffine(edit_to_screen_af, MulVec2(Vec2FromVec(frame->screen_dims), 0.5)); edit_to_screen_af = WorldTranslateAffine(edit_to_screen_af, MulVec2(Vec2FromVec(frame->screen_dims), 0.5));
} }
Vec2 prev_target_cursor = MulAffineV2(InvertAffine(prev_frame_edit_to_screen_af), prev_frame->screen_cursor); Vec2 prev_target_cursor = MulAffineVec2(InvertAffine(prev_frame_edit_to_screen_af), prev_frame->screen_cursor);
Vec2 target_cursor = MulAffineV2(InvertAffine(edit_to_screen_af), ui_frame->cursor_pos); Vec2 target_cursor = MulAffineVec2(InvertAffine(edit_to_screen_af), ui_frame->cursor_pos);
Vec2 diff = SubVec2(prev_target_cursor, target_cursor); Vec2 diff = SubVec2(prev_target_cursor, target_cursor);
frame->edit_camera_pos = AddVec2(frame->edit_camera_pos, diff); frame->edit_camera_pos = AddVec2(frame->edit_camera_pos, diff);
} }
@ -855,7 +858,7 @@ void V_TickForever(WaveLaneCtx *lane)
P_Ent *guy = P_EntFromKey(local_world->last_frame, player->guy); P_Ent *guy = P_EntFromKey(local_world->last_frame, player->guy);
Vec2 guy_center = P_WorldShapeFromEnt(guy).centroid; Vec2 guy_center = P_WorldShapeFromEnt(guy).centroid;
Vec2 screen_center = MulVec2(frame->screen_dims, 0.5); Vec2 screen_center = MulVec2(frame->screen_dims, 0.5);
Vec2 look = MulAffineBasisV2(prev_frame->af.screen_to_world, SubVec2(ui_frame->cursor_pos, screen_center)); Vec2 look = MulAffineBasisVec2(prev_frame->af.screen_to_world, SubVec2(ui_frame->cursor_pos, screen_center));
target_camera_pos = guy_center; target_camera_pos = guy_center;
target_camera_pos = AddVec2(target_camera_pos, MulVec2Vec2(look, look_ratio)); target_camera_pos = AddVec2(target_camera_pos, MulVec2Vec2(look, look_ratio));
target_camera_zoom = 1; target_camera_zoom = 1;
@ -895,7 +898,7 @@ void V_TickForever(WaveLaneCtx *lane)
} }
////////////////////////////// //////////////////////////////
//- Compute frame Affines //- Compute frame affines
// World <-> screen // World <-> screen
frame->af.world_to_screen = AffineIdentity; frame->af.world_to_screen = AffineIdentity;
@ -953,8 +956,8 @@ void V_TickForever(WaveLaneCtx *lane)
//- Update cursors / selection //- Update cursors / selection
frame->screen_cursor = ui_frame->cursor_pos; frame->screen_cursor = ui_frame->cursor_pos;
frame->shade_cursor = MulAffineV2(frame->af.screen_to_shade, frame->screen_cursor); frame->shade_cursor = MulAffineVec2(frame->af.screen_to_shade, frame->screen_cursor);
frame->world_cursor = MulAffineV2(frame->af.screen_to_world, frame->screen_cursor); frame->world_cursor = MulAffineVec2(frame->af.screen_to_world, frame->screen_cursor);
b32 show_editor_ui = TweakBool("Show editor UI", 1); b32 show_editor_ui = TweakBool("Show editor UI", 1);
@ -984,11 +987,11 @@ void V_TickForever(WaveLaneCtx *lane)
frame->world_selection.p1.x = MaxF32(frame->world_cursor.x, frame->world_selection_start.x); frame->world_selection.p1.x = MaxF32(frame->world_cursor.x, frame->world_selection_start.x);
frame->world_selection.p1.y = MaxF32(frame->world_cursor.y, frame->world_selection_start.y); frame->world_selection.p1.y = MaxF32(frame->world_cursor.y, frame->world_selection_start.y);
frame->screen_selection.p0 = MulAffineV2(frame->af.world_to_screen, frame->world_selection.p0); frame->screen_selection.p0 = MulAffineVec2(frame->af.world_to_screen, frame->world_selection.p0);
frame->screen_selection.p1 = MulAffineV2(frame->af.world_to_screen, frame->world_selection.p1); frame->screen_selection.p1 = MulAffineVec2(frame->af.world_to_screen, frame->world_selection.p1);
frame->shade_selection.p0 = MulAffineV2(frame->af.world_to_shade, frame->world_selection.p0); frame->shade_selection.p0 = MulAffineVec2(frame->af.world_to_shade, frame->world_selection.p0);
frame->shade_selection.p1 = MulAffineV2(frame->af.world_to_shade, frame->world_selection.p1); frame->shade_selection.p1 = MulAffineVec2(frame->af.world_to_shade, frame->world_selection.p1);
////////////////////////////// //////////////////////////////
//- Place tiles //- Place tiles
@ -1001,8 +1004,8 @@ void V_TickForever(WaveLaneCtx *lane)
{ {
// TODO: Fix clamp when both start & end are outside of world // TODO: Fix clamp when both start & end are outside of world
Rng2I32 tile_range = Zi; Rng2I32 tile_range = Zi;
tile_range.p0 = Vec2I32FromVec(FloorVec2(MulAffineV2(frame->af.world_to_tile, prev_frame->world_selection.p0))); tile_range.p0 = Vec2I32FromVec(FloorVec2(MulAffineVec2(frame->af.world_to_tile, prev_frame->world_selection.p0)));
tile_range.p1 = Vec2I32FromVec(CeilVec2(MulAffineV2(frame->af.world_to_tile, prev_frame->world_selection.p1))); tile_range.p1 = Vec2I32FromVec(CeilVec2(MulAffineVec2(frame->af.world_to_tile, prev_frame->world_selection.p1)));
P_Msg *msg = P_PushMsg(P_MsgKind_TileEdit, Zstr); P_Msg *msg = P_PushMsg(P_MsgKind_TileEdit, Zstr);
msg->tile_kind = prev_frame->equipped_tile; msg->tile_kind = prev_frame->equipped_tile;
@ -1831,50 +1834,50 @@ void V_TickForever(WaveLaneCtx *lane)
////////////////////////////// //////////////////////////////
//- Push guy quads //- Push guy quads
for (P_Ent *ent = P_FirstEnt(local_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent)) // for (P_Ent *ent = P_FirstEnt(local_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent))
{
if (ent->is_guy)
{
P_Anim anim = P_AnimFromEnt(ent, local_frame->time_ns);
SPR_Slice body_slice = SPR_SliceFromSheet(anim.sheet, anim.span, anim.frame_seq);
if (body_slice.ready)
{
Affine body_to_world_af = AffineIdentity;
{
// FIXME: Use origin ray
Vec2 world_dims = DivVec2(body_slice.dims, P_CellsPerMeter);
body_to_world_af.og = ent->af.og;
// body_to_world_af.og = SubVec2(body_to_world_af.og, MulVec2(world_dims, 0.25));
body_to_world_af = AffineWithWorldRotation(body_to_world_af, AngleFromVec2(ent->control.look));
body_to_world_af = TranslateAffine(body_to_world_af, MulVec2(world_dims, -0.5));
body_to_world_af = ScaleAffine(body_to_world_af, world_dims);
}
// Push body quad
{
V_Quad *quad = PushStruct(frame->quads_arena, V_Quad);
quad->to_shade_af = MulAffine(frame->af.world_to_shade, body_to_world_af);
quad->tex = body_slice.tex;
quad->uv_rect = body_slice.uv_rect;
}
}
// SPR_Slice wep_slice = SPR_FrameFromSheet(anim.weapon_sheet, anim.span, anim.frame_seq);
// Affine wep_to_world_af = AffineIdentity;
// { // {
// if (ent->is_guy)
// {
// P_Anim anim = P_AnimFromEnt(ent, local_frame->time_ns);
// SPR_Slice body_slice = SPR_SliceFromSheet(anim.sheet, anim.span, anim.frame_seq);
// if (body_slice.ready)
// {
// Affine body_to_world_af = AffineIdentity;
// {
// // FIXME: Use origin ray
// Vec2 world_dims = DivVec2(body_slice.dims, P_CellsPerMeter);
// body_to_world_af.og = ent->af.og;
// // body_to_world_af.og = SubVec2(body_to_world_af.og, MulVec2(world_dims, 0.25));
// body_to_world_af = AffineWithWorldRotation(body_to_world_af, AngleFromVec2(ent->control.look));
// body_to_world_af = TranslateAffine(body_to_world_af, MulVec2(world_dims, -0.5));
// body_to_world_af = ScaleAffine(body_to_world_af, world_dims);
// } // }
// // Push weapon quad
// // Push body quad
// { // {
// V_Quad *quad = PushStruct(frame->quads_arena, V_Quad); // V_Quad *quad = PushStruct(frame->quads_arena, V_Quad);
// quad->af = MulAffine(frame->af.world_to_shade, wep_to_world_af); // quad->to_shade_af = MulAffine(frame->af.world_to_shade, body_to_world_af);
// quad->slice = wep_sframe.slice; // quad->tex = body_slice.tex;
// quad->uv_rect = body_slice.uv_rect;
// }
// }
// // SPR_Slice wep_slice = SPR_FrameFromSheet(anim.weapon_sheet, anim.span, anim.frame_seq);
// // Affine wep_to_world_af = AffineIdentity;
// // {
// // }
// // // Push weapon quad
// // {
// // V_Quad *quad = PushStruct(frame->quads_arena, V_Quad);
// // quad->af = MulAffine(frame->af.world_to_shade, wep_to_world_af);
// // quad->slice = wep_sframe.slice;
// // }
// }
// } // }
}
}
@ -1904,8 +1907,8 @@ void V_TickForever(WaveLaneCtx *lane)
{ {
skip = 1; skip = 1;
} }
// V_DrawPoint(MulAffineV2(frame->af.world_to_screen, start), Color_Red); // V_DrawPoint(MulAffineVec2(frame->af.world_to_screen, start), Color_Red);
// V_DrawPoint(MulAffineV2(frame->af.world_to_screen, end), Color_Purple); // V_DrawPoint(MulAffineVec2(frame->af.world_to_screen, end), Color_Purple);
end = hit_pos; end = hit_pos;
} }
@ -2295,29 +2298,28 @@ void V_TickForever(WaveLaneCtx *lane)
{ {
case P_DebugDrawKind_Point: case P_DebugDrawKind_Point:
{ {
Vec2 ui_p = MulAffineV2(frame->af.world_to_screen, n->point.p); Vec2 ui_p = MulAffineVec2(frame->af.world_to_screen, n->point.p);
V_DrawPoint(ui_p, color); V_DrawPoint(ui_p, color);
} break; } break;
case P_DebugDrawKind_Line: case P_DebugDrawKind_Line:
{ {
Vec2 ui_p0 = MulAffineV2(frame->af.world_to_screen, n->line.p0); Vec2 ui_p0 = MulAffineVec2(frame->af.world_to_screen, n->line.p0);
Vec2 ui_p1 = MulAffineV2(frame->af.world_to_screen, n->line.p1); Vec2 ui_p1 = MulAffineVec2(frame->af.world_to_screen, n->line.p1);
V_DrawLine(ui_p0, ui_p1, color); V_DrawLine(ui_p0, ui_p1, color);
} break; } break;
case P_DebugDrawKind_Rect: case P_DebugDrawKind_Rect:
{ {
Rng2 ui_rect = Zi; Rng2 ui_rect = Zi;
ui_rect.p0 = MulAffineV2(frame->af.world_to_screen, n->rect.p0); ui_rect.p0 = MulAffineVec2(frame->af.world_to_screen, n->rect.p0);
ui_rect.p1 = MulAffineV2(frame->af.world_to_screen, n->rect.p1); ui_rect.p1 = MulAffineVec2(frame->af.world_to_screen, n->rect.p1);
V_DrawRect(ui_rect, color, V_DrawFlag_Line); V_DrawRect(ui_rect, color, V_DrawFlag_Line);
} break; } break;
case P_DebugDrawKind_Shape: case P_DebugDrawKind_Shape:
{ {
P_Shape ui_shape = P_MulAffineShape(frame->af.world_to_screen, n->shape); V_DrawShape(n->shape, frame->af.world_to_screen, color, detail, V_DrawFlag_Line);
V_DrawShape(ui_shape, color, detail, V_DrawFlag_Line);
} break; } break;
} }
} }
@ -3663,8 +3665,8 @@ void V_TickForever(WaveLaneCtx *lane)
} }
UI_BuildSpacer(UI_PIX(padding, 1), Axis_Y); UI_BuildSpacer(UI_PIX(padding, 1), Axis_Y);
{ {
Vec2 tile_pos = MulAffineV2(frame->af.world_to_tile, frame->world_cursor); Vec2 tile_pos = MulAffineVec2(frame->af.world_to_tile, frame->world_cursor);
Vec2 cell_pos = MulAffineV2(frame->af.world_to_cell, frame->world_cursor); Vec2 cell_pos = MulAffineVec2(frame->af.world_to_cell, frame->world_cursor);
i32 tile_idx = P_TileIdxFromTilePos(tile_pos); i32 tile_idx = P_TileIdxFromTilePos(tile_pos);
UI_BuildLabelF("Camera pos: %F", FmtFloat2(frame->camera_pos)); UI_BuildLabelF("Camera pos: %F", FmtFloat2(frame->camera_pos));
UI_BuildLabelF("Cursor world pos: %F", FmtFloat2(frame->world_cursor)); UI_BuildLabelF("Cursor world pos: %F", FmtFloat2(frame->world_cursor));
@ -4092,7 +4094,7 @@ void V_TickForever(WaveLaneCtx *lane)
{ {
P_Msg *msg = P_PushMsg(P_MsgKind_EntEdit, Lit("guy")); P_Msg *msg = P_PushMsg(P_MsgKind_EntEdit, Lit("guy"));
msg->key = local_guy->key; msg->key = local_guy->key;
msg->pos = guy_pos; msg->xf.t = guy_pos;
} }
} break; } break;
@ -4100,7 +4102,7 @@ void V_TickForever(WaveLaneCtx *lane)
{ {
P_Msg *msg = P_PushMsg(P_MsgKind_EntEdit, Lit("dummy")); P_Msg *msg = P_PushMsg(P_MsgKind_EntEdit, Lit("dummy"));
msg->key = P_RandKey(); msg->key = P_RandKey();
msg->pos = frame->world_cursor; msg->xf.t = frame->world_cursor;
} break; } break;
case V_CmdKind_delete: case V_CmdKind_delete:

View File

@ -270,7 +270,7 @@ Struct(V_Frame)
Vec2 camera_pos; Vec2 camera_pos;
f32 camera_zoom; f32 camera_zoom;
// Affines; // affines;
V_Affines af; V_Affines af;
// Cursors // Cursors
@ -346,7 +346,7 @@ void V_PushParticles(V_Emitter src);
//~ Draw helpers //~ Draw helpers
void V_DrawPoly(Vec2Array points, Vec4 srgb, V_DrawFlag flags); void V_DrawPoly(Vec2Array points, Vec4 srgb, V_DrawFlag flags);
void V_DrawShape(P_Shape shape, Vec4 srgb, i32 detail, V_DrawFlag flags); void V_DrawShape(P_Shape shape, Affine af, Vec4 srgb, i32 detail, V_DrawFlag flags);
void V_DrawLine(Vec2 p0, Vec2 p1, Vec4 srgb); 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);
void V_DrawPoint(Vec2 p, Vec4 srgb); void V_DrawPoint(Vec2 p, Vec4 srgb);

View File

@ -21,14 +21,14 @@ SPR_SheetKey SPR_SheetKeyFromResource(ResourceKey resource)
SPR_SpanKey SPR_SpanKeyFromName(String name) SPR_SpanKey SPR_SpanKeyFromName(String name)
{ {
SPR_SpanKey result = Zi; SPR_SpanKey result = Zi;
// TODO result.v = HashString(name);
return result; return result;
} }
SPR_LayerKey SPR_LayerKeyFromName(String name) SPR_LayerKey SPR_LayerKeyFromName(String name)
{ {
SPR_LayerKey result = Zi; SPR_LayerKey result = Zi;
// TODO result.v = HashString(name);
return result; return result;
} }
@ -38,12 +38,19 @@ SPR_LayerKey SPR_LayerKeyFromName(String name)
SPR_Slice SPR_SliceFromSheet(SPR_SheetKey sheet, SPR_SpanKey span, i64 frame_seq) SPR_Slice SPR_SliceFromSheet(SPR_SheetKey sheet, SPR_SpanKey span, i64 frame_seq)
{ {
SPR_Slice result = Zi; SPR_Slice result = Zi;
// TODO
return result; return result;
} }
Xform SPR_XformFromSheet(SPR_SheetKey sheet, SPR_LayerKey layer, SPR_SpanKey span, i64 frame_seq)
{
Xform result = Zi;
return result;
}
// SPR_Slice SPR_SliceFromSheet(SPR_SheetKey sheet, SPR_SpanKey span, i64 frame_seq) // SPR_Slice SPR_SliceFromSheet(SPR_SheetKey sheet, SPR_SpanKey span, i64 frame_seq)
// { // {
// // TODO: Ability to specify desired alpha modes (Straight, Premultiplied, Opaque) // // TODO: Ability to specify desired alpha modes (Straight, Premultiplied, Opaque)

View File

@ -113,6 +113,7 @@ SPR_LayerKey SPR_LayerKeyFromName(String name);
//~ Lookup //~ Lookup
SPR_Slice SPR_SliceFromSheet(SPR_SheetKey sheet, SPR_SpanKey span, i64 frame_seq); SPR_Slice SPR_SliceFromSheet(SPR_SheetKey sheet, SPR_SpanKey span, i64 frame_seq);
Xform SPR_XformFromSheet(SPR_SheetKey sheet, SPR_LayerKey layer, SPR_SpanKey span, i64 frame_seq);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Async //~ Async