move shared vis-sim functionality to pp layer
This commit is contained in:
parent
4df1418aa5
commit
32938a9abe
1258
src/pp/pp.c
Normal file
1258
src/pp/pp.c
Normal file
File diff suppressed because it is too large
Load Diff
454
src/pp/pp.h
Normal file
454
src/pp/pp.h
Normal file
@ -0,0 +1,454 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Key types
|
||||
|
||||
#define P_NilKey ((P_Key) { 0 })
|
||||
|
||||
Struct(P_Key)
|
||||
{
|
||||
u64 v;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Shape types
|
||||
|
||||
Struct(P_ShapeDesc)
|
||||
{
|
||||
f32 radius;
|
||||
f32 mass;
|
||||
i32 count;
|
||||
Vec2 points[8];
|
||||
};
|
||||
|
||||
Struct(P_Shape)
|
||||
{
|
||||
f32 mass;
|
||||
Vec2 centroid;
|
||||
Vec2 center_of_mass;
|
||||
|
||||
f32 radius;
|
||||
i32 points_count;
|
||||
Vec2 points[8];
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Ent types
|
||||
|
||||
// TODO: Move boolean fields into bitwise property flags
|
||||
|
||||
// TODO: Pack efficiently, deduplicate redundant fields
|
||||
|
||||
Struct(P_Ent)
|
||||
{
|
||||
//////////////////////////////
|
||||
//- Internal world state
|
||||
|
||||
P_Ent *next;
|
||||
P_Ent *prev;
|
||||
|
||||
P_Ent *next_in_bin;
|
||||
P_Ent *prev_in_bin;
|
||||
|
||||
//////////////////////////////
|
||||
//- Persistent data
|
||||
|
||||
P_Key key;
|
||||
b32 valid;
|
||||
|
||||
//////////////////////////////
|
||||
//- Build data
|
||||
|
||||
f32 exists;
|
||||
|
||||
b32 is_player;
|
||||
f32 health;
|
||||
|
||||
Xform last_xf;
|
||||
Xform xf;
|
||||
|
||||
Vec2 move;
|
||||
Vec2 look;
|
||||
f32 fire_held;
|
||||
f32 fire_presses;
|
||||
|
||||
// TODO: Remove this (weapon testing)
|
||||
i64 last_fire_ns;
|
||||
b32 has_weapon;
|
||||
|
||||
P_Key bullet_firer;
|
||||
b32 is_bullet;
|
||||
Vec2 bullet_start;
|
||||
Vec2 bullet_end;
|
||||
|
||||
b32 has_hit;
|
||||
Vec2 hit_entry;
|
||||
Vec2 hit_entry_normal;
|
||||
|
||||
//////////////////////////////
|
||||
//- Solver data
|
||||
|
||||
Vec2 solved_v;
|
||||
f32 solved_w;
|
||||
};
|
||||
|
||||
Struct(P_EntListNode)
|
||||
{
|
||||
P_EntListNode *next;
|
||||
P_Ent ent;
|
||||
};
|
||||
|
||||
Struct(P_EntList)
|
||||
{
|
||||
P_EntListNode *first;
|
||||
P_EntListNode *last;
|
||||
i64 count;
|
||||
};
|
||||
|
||||
Struct(P_EntBin)
|
||||
{
|
||||
P_Ent *first;
|
||||
P_Ent *last;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ World types
|
||||
|
||||
Struct(P_World)
|
||||
{
|
||||
u64 seed;
|
||||
i64 tick;
|
||||
i64 time_ns;
|
||||
|
||||
i64 ents_count;
|
||||
P_Ent *first_ent;
|
||||
P_Ent *last_ent;
|
||||
|
||||
i64 ent_bins_count;
|
||||
P_EntBin *ent_bins;
|
||||
|
||||
u8 *tiles;
|
||||
};
|
||||
|
||||
Enum(P_DeltaKind)
|
||||
{
|
||||
P_DeltaKind_Reset,
|
||||
P_DeltaKind_RawEnt,
|
||||
P_DeltaKind_RawTiles,
|
||||
P_DeltaKind_Tile,
|
||||
};
|
||||
|
||||
Struct(P_Delta)
|
||||
{
|
||||
P_DeltaKind kind;
|
||||
|
||||
P_Ent ent;
|
||||
|
||||
u8 *raw_tiles;
|
||||
P_TileKind tile_kind;
|
||||
Rng2I32 tile_range;
|
||||
};
|
||||
|
||||
Struct(P_DeltaNode)
|
||||
{
|
||||
P_DeltaNode *next;
|
||||
P_Delta delta;
|
||||
};
|
||||
|
||||
Struct(P_Snapshot)
|
||||
{
|
||||
u64 seed;
|
||||
i64 tick;
|
||||
i64 time_ns;
|
||||
|
||||
i64 deltas_count;
|
||||
P_DeltaNode *first_delta_node;
|
||||
P_DeltaNode *last_delta_node;
|
||||
};
|
||||
|
||||
Struct(P_SnapshotNode)
|
||||
{
|
||||
P_SnapshotNode *next;
|
||||
P_Snapshot snapshot;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Collision types
|
||||
|
||||
Struct(P_SupportPoint)
|
||||
{
|
||||
Vec2 p;
|
||||
u32 id; // Index of the originating piont in the shape
|
||||
};
|
||||
|
||||
Struct(P_CollisionPoint)
|
||||
{
|
||||
Vec2 p;
|
||||
f32 separation;
|
||||
u32 id; // Based on polygon edge-to-edge
|
||||
};
|
||||
|
||||
Struct(P_MenkowskiPoint)
|
||||
{
|
||||
Vec2 p; // Menkowski difference point
|
||||
P_SupportPoint s0; // Support point of first shape in dir
|
||||
P_SupportPoint s1; // Support point of second shape in -dir
|
||||
};
|
||||
|
||||
Struct(P_MenkowskiSimplex)
|
||||
{
|
||||
i32 count;
|
||||
P_MenkowskiPoint a, b, c;
|
||||
};
|
||||
|
||||
Struct(P_ClippedLine)
|
||||
{
|
||||
Vec2 a0_clipped, b0_clipped;
|
||||
Vec2 a1_clipped, b1_clipped;
|
||||
};
|
||||
|
||||
Struct(P_CollisionResult)
|
||||
{
|
||||
// Collision manifold
|
||||
i32 collision_points_count;
|
||||
P_CollisionPoint collision_points[2];
|
||||
Vec2 collision_normal;
|
||||
|
||||
// Closest points
|
||||
Vec2 closest_p0;
|
||||
Vec2 closest_p1;
|
||||
};
|
||||
|
||||
Struct(P_RaycastResult)
|
||||
{
|
||||
b32 is_intersecting;
|
||||
Vec2 p;
|
||||
Vec2 normal;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Constraint types
|
||||
|
||||
Struct(P_ContactPoint)
|
||||
{
|
||||
Vec2 vcp0;
|
||||
Vec2 vcp1;
|
||||
f32 starting_separation;
|
||||
f32 inv_normal_mass;
|
||||
f32 inv_tangent_mass;
|
||||
u32 id;
|
||||
|
||||
f32 solved_normal_impulse;
|
||||
f32 solved_tangent_impulse;
|
||||
};
|
||||
|
||||
Struct(P_Constraint)
|
||||
{
|
||||
i64 last_touched_tick;
|
||||
P_Key ent0;
|
||||
P_Key ent1;
|
||||
|
||||
Vec2 static_center0;
|
||||
Vec2 static_center1;
|
||||
|
||||
f32 inv_m0;
|
||||
f32 inv_m1;
|
||||
f32 inv_i0;
|
||||
f32 inv_i1;
|
||||
|
||||
Vec2 normal;
|
||||
f32 friction;
|
||||
|
||||
i32 points_count;
|
||||
P_ContactPoint points[2];
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Debug visualization types
|
||||
|
||||
Enum(P_DebugDrawKind)
|
||||
{
|
||||
P_DebugDrawKind_Point,
|
||||
P_DebugDrawKind_Line,
|
||||
P_DebugDrawKind_Rect,
|
||||
P_DebugDrawKind_Shape,
|
||||
};
|
||||
|
||||
Struct(P_DebugDrawNode)
|
||||
{
|
||||
P_DebugDrawNode *next;
|
||||
P_DebugDrawKind kind;
|
||||
u32 srgb32;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
Vec2 p;
|
||||
} point;
|
||||
struct
|
||||
{
|
||||
Vec2 p0;
|
||||
Vec2 p1;
|
||||
} line;
|
||||
Rng2 rect;
|
||||
P_Shape shape;
|
||||
};
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Command types
|
||||
|
||||
Enum(P_CmdKind)
|
||||
{
|
||||
P_CmdKind_Nop,
|
||||
P_CmdKind_Save,
|
||||
P_CmdKind_Delta,
|
||||
P_CmdKind_Control,
|
||||
};
|
||||
|
||||
Struct(P_Cmd)
|
||||
{
|
||||
P_CmdKind kind;
|
||||
|
||||
// Delta
|
||||
P_Delta delta;
|
||||
|
||||
// Control
|
||||
P_Key target;
|
||||
Vec2 move;
|
||||
Vec2 look;
|
||||
b32 fire_held;
|
||||
i32 fire_presses;
|
||||
};
|
||||
|
||||
Struct(P_CmdNode)
|
||||
{
|
||||
P_CmdNode *next;
|
||||
P_Cmd cmd;
|
||||
};
|
||||
|
||||
Struct(P_InputState)
|
||||
{
|
||||
Arena *arena;
|
||||
P_CmdNode *first_cmd_node;
|
||||
P_CmdNode *last_cmd_node;
|
||||
u64 cmds_count;
|
||||
};
|
||||
|
||||
Struct(P_OutputState)
|
||||
{
|
||||
Arena *arena;
|
||||
P_SnapshotNode *first_snapshot_node;
|
||||
P_SnapshotNode *last_snapshot_node;
|
||||
u64 snapshots_count;
|
||||
|
||||
P_DebugDrawNode *first_debug_draw_node;
|
||||
P_DebugDrawNode *last_debug_draw_node;
|
||||
i64 debug_draw_nodes_count;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ State types
|
||||
|
||||
Struct(P_Ctx)
|
||||
{
|
||||
//- Sim input
|
||||
TicketMutex sim_input_back_tm;
|
||||
i32 sim_input_back_idx;
|
||||
P_InputState sim_input_states[2];
|
||||
|
||||
//- Sim output
|
||||
TicketMutex sim_output_back_tm;
|
||||
i32 sim_output_back_idx;
|
||||
P_OutputState sim_output_states[2];
|
||||
};
|
||||
|
||||
Struct(P_ThreadLocalCtx)
|
||||
{
|
||||
Arena *debug_arena;
|
||||
b32 debug_draw_enabled;
|
||||
P_DebugDrawNode *first_debug_draw_node;
|
||||
P_DebugDrawNode *last_debug_draw_node;
|
||||
i64 debug_draw_nodes_count;
|
||||
};
|
||||
|
||||
extern P_Ctx P;
|
||||
extern ThreadLocal P_ThreadLocalCtx P_tl;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Bootstrap
|
||||
|
||||
void P_Bootstrap(void);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Nil helpers
|
||||
|
||||
b32 P_IsKeyNil(P_Key key);
|
||||
b32 P_IsEntNil(P_Ent *ent);
|
||||
b32 P_MatchKey(P_Key a, P_Key b);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Key helpers
|
||||
|
||||
P_Key P_RandKey(void);
|
||||
|
||||
#define P_FmtKey(key) FmtHandle((key).v)
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Tile helpers
|
||||
|
||||
String P_NameFromTileKind(P_TileKind kind);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Delta helpers
|
||||
|
||||
void P_UpdateWorldFromDelta(Arena *arena, P_World *world, P_Delta *delta);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Shape helpers
|
||||
|
||||
P_Shape P_ShapeFromDescEx(P_ShapeDesc desc);
|
||||
#define P_ShapeFromDesc(...) P_ShapeFromDescEx((P_ShapeDesc) { __VA_ARGS__ })
|
||||
|
||||
P_Shape P_MulXformShape(Xform xf, P_Shape shape);
|
||||
Rng2 P_BoundingBoxFromShape(P_Shape shape);
|
||||
|
||||
P_Shape P_LocalShapeFromEnt(P_Ent *ent);
|
||||
P_Shape P_WorldShapeFromEnt(P_Ent *ent);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Collision
|
||||
|
||||
P_SupportPoint P_SupportPointFromShapeEx(P_Shape shape, Vec2 dir, i32 ignore_idx);
|
||||
P_SupportPoint P_SupportPointFromShape(P_Shape shape, Vec2 dir);
|
||||
P_MenkowskiPoint P_MenkowskiPointFromShapes(P_Shape shape0, P_Shape shape1, Vec2 dir);
|
||||
P_ClippedLine P_ClipLineToLine(Vec2 a0, Vec2 b0, Vec2 a1, Vec2 b1, Vec2 normal);
|
||||
Vec2 P_ClipPointToLine(Vec2 a, Vec2 b, Vec2 p, Vec2 normal);
|
||||
|
||||
P_CollisionResult P_CollisionResultFromShapes(P_Shape shape0, P_Shape shape1);
|
||||
P_RaycastResult P_RaycastShape(P_Shape shape, Vec2 ray_start, Vec2 ray_dir);
|
||||
|
||||
Vec2 P_EdgePointFromShape(P_Shape shape, Vec2 dir);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Lookup helpers
|
||||
|
||||
P_Ent *P_EntFromKey(P_World *world, P_Key key);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Iteration helpers
|
||||
|
||||
P_Ent *P_FirstEnt(P_World *world);
|
||||
P_Ent *P_NextEnt(P_Ent *e);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ List helpers
|
||||
|
||||
P_Ent *P_PushTempEnt(Arena *arena, P_EntList *list);
|
||||
void P_SpawnEntsFromList(Arena *arena, P_World *world, P_EntList ents);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Debug draw
|
||||
|
||||
void P_DebugDrawPoint(Vec2 p, Vec4 srgb);
|
||||
void P_DebugDrawLine(Vec2 p0, Vec2 p1, Vec4 srgb);
|
||||
void P_DebugDrawRect(Rng2 rect, Vec4 srgb);
|
||||
void P_DebugDrawShape(P_Shape shape, Vec4 srgb);
|
||||
@ -5,8 +5,23 @@
|
||||
|
||||
@EmbedDir P_Resources pp_res
|
||||
|
||||
//////////////////////////////
|
||||
//- Api
|
||||
|
||||
@IncludeC pp_shared.cgh
|
||||
@IncludeG pp_shared.cgh
|
||||
@IncludeC pp.h
|
||||
@IncludeC pp_transcode.h
|
||||
|
||||
@Bootstrap P_Bootstrap
|
||||
|
||||
//////////////////////////////
|
||||
//- Impl
|
||||
|
||||
@DefaultDownstream Any pp_vis
|
||||
@IncludeC pp_shared.cg
|
||||
@IncludeG pp_shared.cg
|
||||
@IncludeC pp.c
|
||||
@IncludeC pp_transcode.c
|
||||
|
||||
@DefaultDownstream Any pp_sim
|
||||
@DefaultDownstream Any pp_vis
|
||||
|
||||
27
src/pp/pp_shared.cg
Normal file
27
src/pp/pp_shared.cg
Normal file
@ -0,0 +1,27 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Tile helpers
|
||||
|
||||
i32 P_TileIdxFromTilePos(Vec2 p)
|
||||
{
|
||||
i32 x = ClampI32(FloorF32(p.x), 0, P_TilesPitch - 1);
|
||||
i32 y = ClampI32(FloorF32(p.y), 0, P_TilesPitch - 1);
|
||||
i32 result = x + (y * P_TilesPitch);
|
||||
return result;
|
||||
}
|
||||
|
||||
#if IsLanguageC
|
||||
String P_TileNameFromKind(P_TileKind kind)
|
||||
{
|
||||
PERSIST Readonly String tile_names[P_TileKind_COUNT] = {
|
||||
#define X(name, ...) [P_TileKind_##name] = CompLit(#name),
|
||||
P_TilesXMacro(X)
|
||||
#undef X
|
||||
};
|
||||
String result = Zi;
|
||||
if (kind >= 0 && kind < countof(tile_names))
|
||||
{
|
||||
result = tile_names[kind];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
35
src/pp/pp_shared.cgh
Normal file
35
src/pp/pp_shared.cgh
Normal file
@ -0,0 +1,35 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Tile types
|
||||
|
||||
#define P_WorldPitch 64.0
|
||||
|
||||
#define P_TilesPerMeter 2.0
|
||||
#define P_TilesPerSqMeter (V_TilesPerMeter * V_TilesPerMeter)
|
||||
|
||||
#define P_TilesPitch (P_WorldPitch * P_TilesPerMeter)
|
||||
#define P_TilesCount (P_TilesPitch * P_TilesPitch)
|
||||
|
||||
#define P_TilesXMacro(X) \
|
||||
X(Empty) \
|
||||
X(Tile) \
|
||||
X(Carpet) \
|
||||
X(Wall) \
|
||||
/* -------------------- */
|
||||
|
||||
//- Tiles kinds enum
|
||||
Enum(P_TileKind)
|
||||
{
|
||||
#define X(name, ...) P_TileKind_##name,
|
||||
P_TilesXMacro(X)
|
||||
#undef X
|
||||
P_TileKind_COUNT
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Tile helpers
|
||||
|
||||
i32 P_TileIdxFromTilePos(Vec2 p);
|
||||
|
||||
#if IsLanguageC
|
||||
String P_TileNameFromKind(P_TileKind kind);
|
||||
#endif
|
||||
@ -9,11 +9,7 @@
|
||||
//////////////////////////////
|
||||
//- Api
|
||||
|
||||
@IncludeC pp_sim_shared.cgh
|
||||
@IncludeG pp_sim_shared.cgh
|
||||
|
||||
@IncludeC pp_sim_core.h
|
||||
@IncludeC pp_sim_transcode.h
|
||||
|
||||
@Bootstrap S_Bootstrap
|
||||
|
||||
@ -21,6 +17,3 @@
|
||||
//- Impl
|
||||
|
||||
@IncludeC pp_sim_core.c
|
||||
@IncludeC pp_sim_transcode.c
|
||||
@IncludeC pp_sim_shared.cg
|
||||
@IncludeG pp_sim_shared.cg
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,382 +1,13 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Key types
|
||||
|
||||
#define S_NilKey ((S_Key) { 0 })
|
||||
|
||||
Struct(S_Key)
|
||||
{
|
||||
u64 v;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Shape types
|
||||
|
||||
Struct(S_ShapeDesc)
|
||||
{
|
||||
f32 radius;
|
||||
f32 mass;
|
||||
i32 count;
|
||||
Vec2 points[8];
|
||||
};
|
||||
|
||||
Struct(S_Shape)
|
||||
{
|
||||
f32 mass;
|
||||
Vec2 centroid;
|
||||
Vec2 center_of_mass;
|
||||
|
||||
f32 radius;
|
||||
i32 points_count;
|
||||
Vec2 points[8];
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Ent types
|
||||
|
||||
// TODO: Move boolean fields into bitwise property flags
|
||||
|
||||
// TODO: Pack efficiently, deduplicate redundant fields
|
||||
|
||||
Struct(S_Ent)
|
||||
{
|
||||
//////////////////////////////
|
||||
//- Internal world state
|
||||
|
||||
S_Ent *next;
|
||||
S_Ent *prev;
|
||||
|
||||
S_Ent *next_in_bin;
|
||||
S_Ent *prev_in_bin;
|
||||
|
||||
//////////////////////////////
|
||||
//- Persistent data
|
||||
|
||||
S_Key key;
|
||||
b32 valid;
|
||||
|
||||
//////////////////////////////
|
||||
//- Build data
|
||||
|
||||
f32 exists;
|
||||
|
||||
b32 is_player;
|
||||
f32 health;
|
||||
|
||||
Xform last_xf;
|
||||
Xform xf;
|
||||
|
||||
Vec2 move;
|
||||
Vec2 look;
|
||||
f32 fire_held;
|
||||
f32 fire_presses;
|
||||
|
||||
// TODO: Remove this (weapon testing)
|
||||
i64 last_fire_ns;
|
||||
b32 has_weapon;
|
||||
|
||||
S_Key bullet_firer;
|
||||
b32 is_bullet;
|
||||
Vec2 bullet_start;
|
||||
Vec2 bullet_end;
|
||||
|
||||
b32 has_hit;
|
||||
Vec2 hit_entry;
|
||||
Vec2 hit_entry_normal;
|
||||
|
||||
//////////////////////////////
|
||||
//- Solver data
|
||||
|
||||
Vec2 solved_v;
|
||||
f32 solved_w;
|
||||
};
|
||||
|
||||
Struct(S_EntListNode)
|
||||
{
|
||||
S_EntListNode *next;
|
||||
S_Ent ent;
|
||||
};
|
||||
|
||||
Struct(S_EntList)
|
||||
{
|
||||
S_EntListNode *first;
|
||||
S_EntListNode *last;
|
||||
i64 count;
|
||||
};
|
||||
|
||||
Struct(S_EntBin)
|
||||
{
|
||||
S_Ent *first;
|
||||
S_Ent *last;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Collision types
|
||||
|
||||
Struct(S_SupportPoint)
|
||||
{
|
||||
Vec2 p;
|
||||
u32 id; // Index of the originating piont in the shape
|
||||
};
|
||||
|
||||
Struct(S_CollisionPoint)
|
||||
{
|
||||
Vec2 p;
|
||||
f32 separation;
|
||||
u32 id; // Based on polygon edge-to-edge
|
||||
};
|
||||
|
||||
Struct(S_MenkowskiPoint)
|
||||
{
|
||||
Vec2 p; // Menkowski difference point
|
||||
S_SupportPoint s0; // Support point of first shape in dir
|
||||
S_SupportPoint s1; // Support point of second shape in -dir
|
||||
};
|
||||
|
||||
Struct(S_MenkowskiSimplex)
|
||||
{
|
||||
i32 count;
|
||||
S_MenkowskiPoint a, b, c;
|
||||
};
|
||||
|
||||
Struct(S_ClippedLine)
|
||||
{
|
||||
Vec2 a0_clipped, b0_clipped;
|
||||
Vec2 a1_clipped, b1_clipped;
|
||||
};
|
||||
|
||||
Struct(S_CollisionResult)
|
||||
{
|
||||
// Collision manifold
|
||||
i32 collision_points_count;
|
||||
S_CollisionPoint collision_points[2];
|
||||
Vec2 collision_normal;
|
||||
|
||||
// Closest points
|
||||
Vec2 closest_p0;
|
||||
Vec2 closest_p1;
|
||||
};
|
||||
|
||||
Struct(S_RaycastResult)
|
||||
{
|
||||
b32 is_intersecting;
|
||||
Vec2 p;
|
||||
Vec2 normal;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Constraint types
|
||||
|
||||
Struct(S_ContactPoint)
|
||||
{
|
||||
Vec2 vcp0;
|
||||
Vec2 vcp1;
|
||||
f32 starting_separation;
|
||||
f32 inv_normal_mass;
|
||||
f32 inv_tangent_mass;
|
||||
u32 id;
|
||||
|
||||
f32 solved_normal_impulse;
|
||||
f32 solved_tangent_impulse;
|
||||
};
|
||||
|
||||
Struct(S_Constraint)
|
||||
{
|
||||
i64 last_touched_tick;
|
||||
S_Key ent0;
|
||||
S_Key ent1;
|
||||
|
||||
Vec2 static_center0;
|
||||
Vec2 static_center1;
|
||||
|
||||
f32 inv_m0;
|
||||
f32 inv_m1;
|
||||
f32 inv_i0;
|
||||
f32 inv_i1;
|
||||
|
||||
Vec2 normal;
|
||||
f32 friction;
|
||||
|
||||
i32 points_count;
|
||||
S_ContactPoint points[2];
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ World types
|
||||
|
||||
Struct(S_World)
|
||||
{
|
||||
u64 seed;
|
||||
i64 tick;
|
||||
i64 time_ns;
|
||||
|
||||
i64 ents_count;
|
||||
S_Ent *first_ent;
|
||||
S_Ent *last_ent;
|
||||
|
||||
i64 ent_bins_count;
|
||||
S_EntBin *ent_bins;
|
||||
|
||||
u8 *tiles;
|
||||
};
|
||||
|
||||
Enum(S_DeltaKind)
|
||||
{
|
||||
S_DeltaKind_Reset,
|
||||
S_DeltaKind_RawEnt,
|
||||
S_DeltaKind_RawTiles,
|
||||
S_DeltaKind_Tile,
|
||||
};
|
||||
|
||||
Struct(S_Delta)
|
||||
{
|
||||
S_DeltaKind kind;
|
||||
|
||||
S_Ent ent;
|
||||
|
||||
u8 *raw_tiles;
|
||||
S_TileKind tile_kind;
|
||||
Rng2I32 tile_range;
|
||||
};
|
||||
|
||||
Struct(S_DeltaNode)
|
||||
{
|
||||
S_DeltaNode *next;
|
||||
S_Delta delta;
|
||||
};
|
||||
|
||||
Struct(S_Snapshot)
|
||||
{
|
||||
u64 seed;
|
||||
i64 tick;
|
||||
i64 time_ns;
|
||||
|
||||
i64 deltas_count;
|
||||
S_DeltaNode *first_delta_node;
|
||||
S_DeltaNode *last_delta_node;
|
||||
};
|
||||
|
||||
Struct(S_SnapshotNode)
|
||||
{
|
||||
S_SnapshotNode *next;
|
||||
S_Snapshot snapshot;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Command types
|
||||
|
||||
Enum(S_CmdKind)
|
||||
{
|
||||
S_CmdKind_Nop,
|
||||
S_CmdKind_Save,
|
||||
S_CmdKind_Delta,
|
||||
S_CmdKind_Control,
|
||||
};
|
||||
|
||||
Struct(S_Cmd)
|
||||
{
|
||||
S_CmdKind kind;
|
||||
|
||||
// Delta
|
||||
S_Delta delta;
|
||||
|
||||
// Control
|
||||
S_Key target;
|
||||
Vec2 move;
|
||||
Vec2 look;
|
||||
b32 fire_held;
|
||||
i32 fire_presses;
|
||||
};
|
||||
|
||||
Struct(S_CmdNode)
|
||||
{
|
||||
S_CmdNode *next;
|
||||
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
|
||||
|
||||
Struct(S_InputState)
|
||||
{
|
||||
Arena *arena;
|
||||
S_CmdNode *first_cmd_node;
|
||||
S_CmdNode *last_cmd_node;
|
||||
u64 cmds_count;
|
||||
};
|
||||
|
||||
Struct(S_OutputState)
|
||||
{
|
||||
Arena *arena;
|
||||
|
||||
S_SnapshotNode *first_snapshot_node;
|
||||
S_SnapshotNode *last_snapshot_node;
|
||||
u64 snapshots_count;
|
||||
|
||||
u64 debug_draw_descs_count;
|
||||
S_DebugDrawDesc *debug_draw_descs;
|
||||
};
|
||||
|
||||
Struct(S_Ctx)
|
||||
{
|
||||
Atomic32 shutdown;
|
||||
Fence shutdown_fence;
|
||||
|
||||
b32 debug_draw_enabled;
|
||||
Arena *debug_draw_descs_arena;
|
||||
|
||||
//- Sim input
|
||||
TicketMutex input_back_tm;
|
||||
i32 input_back_idx;
|
||||
S_InputState input_states[2];
|
||||
|
||||
//- Sim output
|
||||
TicketMutex output_back_tm;
|
||||
i32 output_back_idx;
|
||||
S_OutputState output_states[2];
|
||||
};
|
||||
|
||||
Struct(S_ThreadLocalCtx)
|
||||
{
|
||||
b32 is_sim_tick_thread;
|
||||
};
|
||||
|
||||
extern S_Ctx S;
|
||||
extern ThreadLocal S_ThreadLocalCtx S_tl;
|
||||
extern Readonly S_Ent S_NilEnt;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Bootstrap
|
||||
@ -384,81 +15,6 @@ extern Readonly S_Ent S_NilEnt;
|
||||
void S_Bootstrap(void);
|
||||
void S_Shutdown(void);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Nil helpers
|
||||
|
||||
b32 S_IsKeyNil(S_Key key);
|
||||
b32 S_IsEntNil(S_Ent *ent);
|
||||
b32 S_MatchKey(S_Key a, S_Key b);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Key helpers
|
||||
|
||||
S_Key S_RandKey(void);
|
||||
|
||||
#define S_FmtKey(key) FmtHandle((key).v)
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Tile helpers
|
||||
|
||||
String S_NameFromTileKind(S_TileKind kind);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Delta helpers
|
||||
|
||||
void S_UpdateWorldFromDelta(Arena *arena, S_World *world, S_Delta *delta);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Shape helpers
|
||||
|
||||
S_Shape S_ShapeFromDescEx(S_ShapeDesc desc);
|
||||
#define S_ShapeFromDesc(...) S_ShapeFromDescEx((S_ShapeDesc) { __VA_ARGS__ })
|
||||
|
||||
S_Shape S_MulXformShape(Xform xf, S_Shape shape);
|
||||
Rng2 S_BoundingBoxFromShape(S_Shape shape);
|
||||
|
||||
S_Shape S_LocalShapeFromEnt(S_Ent *ent);
|
||||
S_Shape S_WorldShapeFromEnt(S_Ent *ent);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Collision
|
||||
|
||||
S_SupportPoint S_SupportPointFromShapeEx(S_Shape shape, Vec2 dir, i32 ignore_idx);
|
||||
S_SupportPoint S_SupportPointFromShape(S_Shape shape, Vec2 dir);
|
||||
S_MenkowskiPoint S_MenkowskiPointFromShapes(S_Shape shape0, S_Shape shape1, Vec2 dir);
|
||||
S_ClippedLine S_ClipLineToLine(Vec2 a0, Vec2 b0, Vec2 a1, Vec2 b1, Vec2 normal);
|
||||
Vec2 S_ClipPointToLine(Vec2 a, Vec2 b, Vec2 p, Vec2 normal);
|
||||
|
||||
S_CollisionResult S_CollisionResultFromShapes(S_Shape shape0, S_Shape shape1);
|
||||
S_RaycastResult S_RaycastShape(S_Shape shape, Vec2 ray_start, Vec2 ray_dir);
|
||||
|
||||
Vec2 S_EdgePointFromShape(S_Shape shape, Vec2 dir);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Lookup helpers
|
||||
|
||||
S_Ent *S_EntFromKey(S_World *world, S_Key key);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Iteration helpers
|
||||
|
||||
S_Ent *S_FirstEnt(S_World *world);
|
||||
S_Ent *S_NextEnt(S_Ent *e);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ List helpers
|
||||
|
||||
S_Ent *S_PushTempEnt(Arena *arena, S_EntList *list);
|
||||
void S_SpawnEntsFromList(Arena *arena, S_World *world, S_EntList ents);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ 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
|
||||
|
||||
|
||||
@ -1,27 +0,0 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Tile helpers
|
||||
|
||||
i32 S_TileIdxFromTilePos(Vec2 p)
|
||||
{
|
||||
i32 x = ClampI32(FloorF32(p.x), 0, S_TilesPitch - 1);
|
||||
i32 y = ClampI32(FloorF32(p.y), 0, S_TilesPitch - 1);
|
||||
i32 result = x + (y * S_TilesPitch);
|
||||
return result;
|
||||
}
|
||||
|
||||
#if IsLanguageC
|
||||
String S_TileNameFromKind(S_TileKind kind)
|
||||
{
|
||||
PERSIST Readonly String tile_names[S_TileKind_COUNT] = {
|
||||
#define X(name, ...) [S_TileKind_##name] = CompLit(#name),
|
||||
S_TilesXMacro(X)
|
||||
#undef X
|
||||
};
|
||||
String result = Zi;
|
||||
if (kind >= 0 && kind < countof(tile_names))
|
||||
{
|
||||
result = tile_names[kind];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
@ -1,35 +0,0 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Tile types
|
||||
|
||||
#define S_WorldPitch 64.0
|
||||
|
||||
#define S_TilesPerMeter 2.0
|
||||
#define S_TilesPerSqMeter (V_TilesPerMeter * V_TilesPerMeter)
|
||||
|
||||
#define S_TilesPitch (S_WorldPitch * S_TilesPerMeter)
|
||||
#define S_TilesCount (S_TilesPitch * S_TilesPitch)
|
||||
|
||||
#define S_TilesXMacro(X) \
|
||||
X(Empty) \
|
||||
X(Tile) \
|
||||
X(Carpet) \
|
||||
X(Wall) \
|
||||
/* -------------------- */
|
||||
|
||||
//- Tiles kinds enum
|
||||
Enum(S_TileKind)
|
||||
{
|
||||
#define X(name, ...) S_TileKind_##name,
|
||||
S_TilesXMacro(X)
|
||||
#undef X
|
||||
S_TileKind_COUNT
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Tile helpers
|
||||
|
||||
i32 S_TileIdxFromTilePos(Vec2 p);
|
||||
|
||||
#if IsLanguageC
|
||||
String S_TileNameFromKind(S_TileKind kind);
|
||||
#endif
|
||||
@ -1,30 +0,0 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Transcode types
|
||||
|
||||
Enum(S_Tv)
|
||||
{
|
||||
S_Tv_None = 0,
|
||||
S_Tv_Initial = 1,
|
||||
|
||||
S_Tv_COUNT
|
||||
};
|
||||
|
||||
#define S_Tv_Latest (S_Tv_COUNT - 1)
|
||||
|
||||
Struct(S_UnpackedWorld)
|
||||
{
|
||||
S_Tv version;
|
||||
|
||||
u64 seed;
|
||||
i64 tick;
|
||||
i64 time_ns;
|
||||
|
||||
S_EntList ents;
|
||||
u8 *tiles;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Transcode
|
||||
|
||||
String S_PackWorld(Arena *arena, S_World *src_world);
|
||||
S_UnpackedWorld S_UnpackWorld(Arena *arena, String packed);
|
||||
@ -1,19 +1,13 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Transcode
|
||||
|
||||
|
||||
|
||||
// FIXME: Header
|
||||
|
||||
|
||||
|
||||
String S_PackWorld(Arena *arena, S_World *src_world)
|
||||
String P_PackWorld(Arena *arena, P_World *src_world)
|
||||
{
|
||||
String result = Zi;
|
||||
result.text = ArenaNext(arena, u8);
|
||||
TempArena scratch = BeginScratch(arena);
|
||||
|
||||
result.len += StringF(arena, "version: %F\n", FmtUint(S_Tv_Latest)).len;
|
||||
result.len += StringF(arena, "version: %F\n", FmtUint(P_Tv_Latest)).len;
|
||||
|
||||
result.len += StringF(arena, "\n").len;
|
||||
result.len += StringF(arena, "seed: 0x%F\n", FmtHex(src_world->seed)).len;
|
||||
@ -24,7 +18,7 @@ String S_PackWorld(Arena *arena, S_World *src_world)
|
||||
// FIXME: Precision
|
||||
result.len += PushString(arena, Lit("\nentities:\n")).len;
|
||||
result.len += PushString(arena, Lit("{\n")).len;
|
||||
for (S_Ent *ent = S_FirstEnt(src_world); ent->valid; ent = S_NextEnt(ent))
|
||||
for (P_Ent *ent = P_FirstEnt(src_world); ent->valid; ent = P_NextEnt(ent))
|
||||
{
|
||||
// TODO: Pack bullets
|
||||
if (!ent->is_bullet)
|
||||
@ -60,7 +54,7 @@ String S_PackWorld(Arena *arena, S_World *src_world)
|
||||
result.len += PushString(arena, Lit("\ntiles:\n")).len;
|
||||
result.len += PushString(arena, Lit("{\n")).len;
|
||||
{
|
||||
String tiles_str = Base64FromString(scratch.arena, STRING(S_TilesCount, src_world->tiles));
|
||||
String tiles_str = Base64FromString(scratch.arena, STRING(P_TilesCount, src_world->tiles));
|
||||
u64 tile_chars_per_line = 128;
|
||||
u64 tile_char_pos = 0;
|
||||
while (tile_char_pos < tiles_str.len)
|
||||
@ -80,15 +74,15 @@ String S_PackWorld(Arena *arena, S_World *src_world)
|
||||
return result;
|
||||
}
|
||||
|
||||
S_UnpackedWorld S_UnpackWorld(Arena *arena, String packed)
|
||||
P_UnpackedWorld P_UnpackWorld(Arena *arena, String packed)
|
||||
{
|
||||
S_UnpackedWorld result = Zi;
|
||||
P_UnpackedWorld result = Zi;
|
||||
TempArena scratch = BeginScratch(arena);
|
||||
|
||||
CR_Item *root = CR_ItemFromString(scratch.arena, packed);
|
||||
|
||||
// Unpack version
|
||||
S_Tv version = 0;
|
||||
P_Tv version = 0;
|
||||
for (CR_Item *root_item = root->first; root_item; root_item = root_item->next)
|
||||
{
|
||||
if (MatchString(root_item->name, Lit("version")))
|
||||
@ -119,8 +113,8 @@ S_UnpackedWorld S_UnpackWorld(Arena *arena, String packed)
|
||||
{
|
||||
for (CR_Item *ent_item = top_item->first; ent_item; ent_item = ent_item->next)
|
||||
{
|
||||
S_Ent *ent = S_PushTempEnt(arena, &result.ents);
|
||||
ent->key = (S_Key) { .v = CR_IntFromString(ent_item->name) };
|
||||
P_Ent *ent = P_PushTempEnt(arena, &result.ents);
|
||||
ent->key = (P_Key) { .v = CR_IntFromString(ent_item->name) };
|
||||
for (CR_Item *attr = ent_item->first; attr; attr = attr->next)
|
||||
{
|
||||
if (MatchString(attr->name, Lit("props")))
|
||||
@ -175,7 +169,7 @@ S_UnpackedWorld S_UnpackWorld(Arena *arena, String packed)
|
||||
tiles_base64.len += PushString(scratch.arena, tile_item->value).len;
|
||||
}
|
||||
}
|
||||
if (StringLenFromBase64Len(tiles_base64.len) == S_TilesCount)
|
||||
if (StringLenFromBase64Len(tiles_base64.len) == P_TilesCount)
|
||||
{
|
||||
result.tiles = StringFromBase64(arena, tiles_base64).text;
|
||||
}
|
||||
@ -183,7 +177,7 @@ S_UnpackedWorld S_UnpackWorld(Arena *arena, String packed)
|
||||
|
||||
if (!result.tiles)
|
||||
{
|
||||
result.tiles = PushStructs(arena, u8, S_TilesCount);
|
||||
result.tiles = PushStructs(arena, u8, P_TilesCount);
|
||||
}
|
||||
|
||||
EndScratch(scratch);
|
||||
30
src/pp/pp_transcode.h
Normal file
30
src/pp/pp_transcode.h
Normal file
@ -0,0 +1,30 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Transcode types
|
||||
|
||||
Enum(P_Tv)
|
||||
{
|
||||
P_Tv_None = 0,
|
||||
P_Tv_Initial = 1,
|
||||
|
||||
P_Tv_COUNT
|
||||
};
|
||||
|
||||
#define P_Tv_Latest (P_Tv_COUNT - 1)
|
||||
|
||||
Struct(P_UnpackedWorld)
|
||||
{
|
||||
P_Tv version;
|
||||
|
||||
u64 seed;
|
||||
i64 tick;
|
||||
i64 time_ns;
|
||||
|
||||
P_EntList ents;
|
||||
u8 *tiles;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Transcode
|
||||
|
||||
String P_PackWorld(Arena *arena, P_World *src_world);
|
||||
P_UnpackedWorld P_UnpackWorld(Arena *arena, String packed);
|
||||
@ -4,7 +4,6 @@
|
||||
//- Dependencies
|
||||
|
||||
@Dep pp
|
||||
@Dep pp_sim
|
||||
@Dep sprite
|
||||
@Dep gpu
|
||||
@Dep glyph_cache
|
||||
|
||||
@ -41,10 +41,10 @@ V_Cmd *V_PushVisCmd(String name)
|
||||
return cmd;
|
||||
}
|
||||
|
||||
S_Cmd *V_PushSimCmd(S_CmdKind kind)
|
||||
P_Cmd *V_PushSimCmd(P_CmdKind kind)
|
||||
{
|
||||
V_Frame *frame = V_CurrentFrame();
|
||||
S_CmdNode *n = PushStruct(frame->arena, S_CmdNode);
|
||||
P_CmdNode *n = PushStruct(frame->arena, P_CmdNode);
|
||||
n->cmd.kind = kind;
|
||||
SllQueuePush(frame->first_sim_cmd_node, frame->last_sim_cmd_node, n);
|
||||
++frame->sim_cmds_count;
|
||||
@ -198,7 +198,7 @@ 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(P_Shape shape, Vec4 srgb, i32 detail, V_DrawFlag flags)
|
||||
{
|
||||
if (shape.radius == 0)
|
||||
{
|
||||
@ -218,7 +218,7 @@ void V_DrawShape(S_Shape shape, Vec4 srgb, i32 detail, V_DrawFlag flags)
|
||||
{
|
||||
f32 rad = ((f32)i / (f32)detail) * Tau;
|
||||
Vec2 dir = Vec2FromAngle(rad);
|
||||
Vec2 sp = S_SupportPointFromShape(shape, dir).p;
|
||||
Vec2 sp = P_SupportPointFromShape(shape, dir).p;
|
||||
draw_points.points[i] = sp;
|
||||
}
|
||||
V_DrawPoly(draw_points, srgb, flags);
|
||||
@ -255,7 +255,7 @@ void V_DrawRect(Rng2 rect, Vec4 srgb, V_DrawFlag flags)
|
||||
|
||||
void V_DrawPoint(Vec2 p, Vec4 srgb)
|
||||
{
|
||||
S_Shape ui_shape = S_ShapeFromDesc(
|
||||
P_Shape ui_shape = P_ShapeFromDesc(
|
||||
.count = 1,
|
||||
.points = { p },
|
||||
.radius = 5
|
||||
@ -326,7 +326,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
Arena *perm = PermArena();
|
||||
G_ArenaHandle gpu_perm = G_PermArena();
|
||||
|
||||
const i32 world_pitch = S_WorldPitch;
|
||||
const i32 world_pitch = P_WorldPitch;
|
||||
const f32 zoom_rate = 1.50;
|
||||
const f32 min_zoom = 0.03;
|
||||
const f32 max_zoom = 15.0;
|
||||
@ -336,17 +336,17 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
//- Init vis state
|
||||
|
||||
Arena *sim_debug_arena = AcquireArena(Gibi(64));
|
||||
u64 sim_debug_draw_descs_count = 0;
|
||||
S_DebugDrawDesc *sim_debug_draw_descs = 0;
|
||||
P_DebugDrawNode *first_sim_debug_draw_node = 0;
|
||||
P_DebugDrawNode *last_sim_debug_draw_node = 0;
|
||||
|
||||
Arena *world_arena = AcquireArena(Gibi(64));
|
||||
S_World *world = PushStruct(world_arena, S_World);
|
||||
P_World *world = PushStruct(world_arena, P_World);
|
||||
world->ent_bins_count = Kibi(16);
|
||||
world->ent_bins = PushStructs(world_arena, S_EntBin, world->ent_bins_count);
|
||||
world->tiles = PushStructs(world_arena, u8, S_TilesCount);
|
||||
world->ent_bins = PushStructs(world_arena, P_EntBin, world->ent_bins_count);
|
||||
world->tiles = PushStructs(world_arena, u8, P_TilesCount);
|
||||
|
||||
Vec2I32 tiles_dims = VEC2I32(S_TilesPitch, S_TilesPitch);
|
||||
Vec2I32 cells_dims = VEC2I32(V_CellsPerMeter * S_WorldPitch, V_CellsPerMeter * S_WorldPitch);
|
||||
Vec2I32 tiles_dims = VEC2I32(P_TilesPitch, P_TilesPitch);
|
||||
Vec2I32 cells_dims = VEC2I32(V_CellsPerMeter * P_WorldPitch, V_CellsPerMeter * P_WorldPitch);
|
||||
|
||||
// Init gpu state
|
||||
G_ResourceHandle gpu_state = Zi;
|
||||
@ -489,6 +489,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
while (!shutdown)
|
||||
{
|
||||
shutdown = Atomic32Fetch(&V.shutdown);
|
||||
P_tl.debug_draw_enabled = 1;
|
||||
|
||||
//////////////////////////////
|
||||
//- Begin frame
|
||||
@ -532,9 +533,9 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
frame->dt = SecondsFromNs(frame->dt_ns);
|
||||
frame->rand = last_frame->rand;
|
||||
|
||||
if (S_IsKeyNil(V.player_key))
|
||||
if (P_IsKeyNil(V.player_key))
|
||||
{
|
||||
V.player_key = S_RandKey();
|
||||
V.player_key = P_RandKey();
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
@ -633,17 +634,17 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
//////////////////////////////
|
||||
//- Pop sim output
|
||||
|
||||
S_OutputState *sim_output = 0;
|
||||
LockTicketMutex(&S.output_back_tm);
|
||||
P_OutputState *sim_output = 0;
|
||||
LockTicketMutex(&P.sim_output_back_tm);
|
||||
{
|
||||
sim_output = &S.output_states[S.output_back_idx];
|
||||
++S.output_back_idx;
|
||||
if (S.output_back_idx >= countof(S.output_states))
|
||||
sim_output = &P.sim_output_states[P.sim_output_back_idx];
|
||||
++P.sim_output_back_idx;
|
||||
if (P.sim_output_back_idx >= countof(P.sim_output_states))
|
||||
{
|
||||
S.output_back_idx = 0;
|
||||
P.sim_output_back_idx = 0;
|
||||
}
|
||||
}
|
||||
UnlockTicketMutex(&S.output_back_tm);
|
||||
UnlockTicketMutex(&P.sim_output_back_tm);
|
||||
|
||||
//////////////////////////////
|
||||
//- Apply sim snapshots
|
||||
@ -653,59 +654,45 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
b32 received_unseen_tick = 0;
|
||||
b32 tiles_dirty = 0;
|
||||
b32 should_clear_particles = 0;
|
||||
for (S_SnapshotNode *n = sim_output->first_snapshot_node; n; n = n->next)
|
||||
for (P_SnapshotNode *n = sim_output->first_snapshot_node; n; n = n->next)
|
||||
{
|
||||
S_Snapshot *snapshot = &n->snapshot;
|
||||
P_Snapshot *snapshot = &n->snapshot;
|
||||
if (snapshot->tick > world->tick)
|
||||
{
|
||||
world->seed = snapshot->seed;
|
||||
world->tick = snapshot->tick;
|
||||
world->time_ns = snapshot->time_ns;
|
||||
for (S_DeltaNode *dn = snapshot->first_delta_node; dn; dn = dn->next)
|
||||
for (P_DeltaNode *dn = snapshot->first_delta_node; dn; dn = dn->next)
|
||||
{
|
||||
S_Delta *delta = &dn->delta;
|
||||
if (delta->kind == S_DeltaKind_Reset)
|
||||
P_Delta *delta = &dn->delta;
|
||||
if (delta->kind == P_DeltaKind_Reset)
|
||||
{
|
||||
tiles_dirty = 1;
|
||||
should_clear_particles = 1;
|
||||
}
|
||||
if (delta->kind == S_DeltaKind_RawTiles || delta->kind == S_DeltaKind_Tile)
|
||||
if (delta->kind == P_DeltaKind_RawTiles || delta->kind == P_DeltaKind_Tile)
|
||||
{
|
||||
tiles_dirty = 1;
|
||||
}
|
||||
S_UpdateWorldFromDelta(world_arena, world, delta);
|
||||
P_UpdateWorldFromDelta(world_arena, world, delta);
|
||||
}
|
||||
received_unseen_tick = 1;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- Copy sim debug info
|
||||
|
||||
if (received_unseen_tick)
|
||||
{
|
||||
ResetArena(sim_debug_arena);
|
||||
|
||||
// Copy sim debug info
|
||||
sim_debug_draw_descs_count = sim_output->debug_draw_descs_count;
|
||||
sim_debug_draw_descs = PushStructsNoZero(sim_debug_arena, S_DebugDrawDesc, sim_debug_draw_descs_count);
|
||||
CopyStructs(sim_debug_draw_descs, sim_output->debug_draw_descs, sim_debug_draw_descs_count);
|
||||
}
|
||||
|
||||
|
||||
// //////////////////////////////
|
||||
// //- Update tiles from sim
|
||||
|
||||
// {
|
||||
// for (S_SnapshotNode *n = sim_output->first_snapshot_node; n; n = n->next)
|
||||
// for (P_SnapshotNode *n = sim_output->first_snapshot_node; n; n = n->next)
|
||||
// {
|
||||
// S_Snapshot *snapshot = &n->snapshot;
|
||||
// P_Snapshot *snapshot = &n->snapshot;
|
||||
// if (snapshot->tick > world->tick)
|
||||
// {
|
||||
// for (u64 placement_idx = 0; placement_idx < snapshot->tile_placements_count; ++placement_idx)
|
||||
// {
|
||||
// S_TilePlacement placement = snapshot->tile_placements[placement_idx];
|
||||
// Rng2I32 dirty_rect = S_UpdateTilesInPlaceFromPlacement(tiles, placement);
|
||||
// P_TilePlacement placement = snapshot->tile_placements[placement_idx];
|
||||
// Rng2I32 dirty_rect = P_UpdateTilesInPlaceFromPlacement(tiles, placement);
|
||||
// G_CopyCpuToTexture(
|
||||
// frame->cl,
|
||||
// gpu_tiles, VEC3I32(dirty_rect.p0.x, dirty_rect.p0.y, 0),
|
||||
@ -723,12 +710,12 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
// if (sim_output->last_snapshot_node && sim_output->last_snapshot_node->snapshot.tick > world->tick)
|
||||
// {
|
||||
// ResetArena(world_arena);
|
||||
// world = S_WorldFromSnapshot(world_arena, &sim_output->last_snapshot_node->snapshot);
|
||||
// V.lookup = S_LookupFromWorld(world_arena, world);
|
||||
// world = P_WorldFromSnapshot(world_arena, &sim_output->last_snapshot_node->snapshot);
|
||||
// V.lookup = P_LookupFromWorld(world_arena, world);
|
||||
|
||||
// // Copy sim debug info
|
||||
// sim_debug_draw_descs_count = sim_output->debug_draw_descs_count;
|
||||
// sim_debug_draw_descs = PushStructsNoZero(world_arena, S_DebugDrawDesc, sim_debug_draw_descs_count);
|
||||
// sim_debug_draw_descs = PushStructsNoZero(world_arena, P_DebugDrawDesc, sim_debug_draw_descs_count);
|
||||
// CopyStructs(sim_debug_draw_descs, sim_output->debug_draw_descs, sim_debug_draw_descs_count);
|
||||
// }
|
||||
|
||||
@ -860,8 +847,8 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
Vec2 look_ratio = Zi;
|
||||
look_ratio.y = 0.25;
|
||||
look_ratio.x = look_ratio.y / (16.0 / 9.0);
|
||||
S_Ent *player = S_EntFromKey(world, V.player_key);
|
||||
target_camera_pos = S_WorldShapeFromEnt(player).centroid;
|
||||
P_Ent *player = P_EntFromKey(world, V.player_key);
|
||||
target_camera_pos = P_WorldShapeFromEnt(player).centroid;
|
||||
target_camera_pos = AddVec2(target_camera_pos, MulVec2Vec2(player->look, look_ratio));
|
||||
target_camera_zoom = 1;
|
||||
}
|
||||
@ -929,7 +916,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
frame->xf.cell_to_world = XformIdentity;
|
||||
{
|
||||
frame->xf.world_to_cell = ScaleXform(frame->xf.world_to_cell, VEC2(V_CellsPerMeter, V_CellsPerMeter));
|
||||
frame->xf.world_to_cell = TranslateXform(frame->xf.world_to_cell, VEC2((S_WorldPitch / 2.0), (S_WorldPitch / 2.0)));
|
||||
frame->xf.world_to_cell = TranslateXform(frame->xf.world_to_cell, VEC2((P_WorldPitch / 2.0), (P_WorldPitch / 2.0)));
|
||||
frame->xf.cell_to_world = InvertXform(frame->xf.world_to_cell);
|
||||
}
|
||||
|
||||
@ -938,8 +925,8 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
frame->xf.world_to_tile = XformIdentity;
|
||||
frame->xf.tile_to_world = XformIdentity;
|
||||
{
|
||||
frame->xf.world_to_tile = ScaleXform(frame->xf.world_to_tile, VEC2(S_TilesPerMeter, S_TilesPerMeter));
|
||||
frame->xf.world_to_tile = TranslateXform(frame->xf.world_to_tile, VEC2((S_WorldPitch / 2.0), (S_WorldPitch / 2.0)));
|
||||
frame->xf.world_to_tile = ScaleXform(frame->xf.world_to_tile, VEC2(P_TilesPerMeter, P_TilesPerMeter));
|
||||
frame->xf.world_to_tile = TranslateXform(frame->xf.world_to_tile, VEC2((P_WorldPitch / 2.0), (P_WorldPitch / 2.0)));
|
||||
frame->xf.tile_to_world = InvertXform(frame->xf.world_to_tile);
|
||||
}
|
||||
|
||||
@ -964,12 +951,12 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
if (m1_held)
|
||||
{
|
||||
frame->is_selecting = 1;
|
||||
// frame->equipped_tile = S_TileKind_Floor;
|
||||
// frame->equipped_tile = P_TileKind_Floor;
|
||||
}
|
||||
else if (m2_held)
|
||||
{
|
||||
frame->is_selecting = 1;
|
||||
// frame->equipped_tile = S_TileKind_Empty;
|
||||
// frame->equipped_tile = P_TileKind_Empty;
|
||||
}
|
||||
|
||||
if (frame->is_selecting && last_frame->is_selecting)
|
||||
@ -1003,8 +990,8 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
tile_range.p0 = Vec2I32FromVec(FloorVec2(MulXformV2(frame->xf.world_to_tile, last_frame->world_selection.p0)));
|
||||
tile_range.p1 = Vec2I32FromVec(CeilVec2(MulXformV2(frame->xf.world_to_tile, last_frame->world_selection.p1)));
|
||||
|
||||
S_Cmd *cmd = V_PushSimCmd(S_CmdKind_Delta);
|
||||
cmd->delta.kind = S_DeltaKind_Tile;
|
||||
P_Cmd *cmd = V_PushSimCmd(P_CmdKind_Delta);
|
||||
cmd->delta.kind = P_DeltaKind_Tile;
|
||||
cmd->delta.tile_kind = last_frame->equipped_tile;
|
||||
cmd->delta.tile_range = tile_range;
|
||||
}
|
||||
@ -1013,15 +1000,15 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
//////////////////////////////
|
||||
//- Query entities
|
||||
|
||||
S_Ent *player = S_EntFromKey(world, V.player_key);
|
||||
S_Ent *hovered_ent = &S_NilEnt;
|
||||
P_Ent *player = P_EntFromKey(world, V.player_key);
|
||||
P_Ent *hovered_ent = &P_NilEnt;
|
||||
{
|
||||
// TODO: Real world query
|
||||
S_Shape cursor_shape = S_ShapeFromDesc(.count = 1, .points = { frame->world_cursor });
|
||||
for (S_Ent *ent = S_FirstEnt(world); ent->valid; ent = S_NextEnt(ent))
|
||||
P_Shape cursor_shape = P_ShapeFromDesc(.count = 1, .points = { frame->world_cursor });
|
||||
for (P_Ent *ent = P_FirstEnt(world); ent->valid; ent = P_NextEnt(ent))
|
||||
{
|
||||
S_Shape ent_shape = S_WorldShapeFromEnt(ent);
|
||||
b32 is_hovered = S_CollisionResultFromShapes(ent_shape, cursor_shape).collision_points_count > 0;
|
||||
P_Shape ent_shape = P_WorldShapeFromEnt(ent);
|
||||
b32 is_hovered = P_CollisionResultFromShapes(ent_shape, cursor_shape).collision_points_count > 0;
|
||||
if (is_hovered)
|
||||
{
|
||||
hovered_ent = ent;
|
||||
@ -1551,9 +1538,9 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
UI_Push(Tag, window->key.v);
|
||||
if (window->is_tile_window)
|
||||
{
|
||||
for (S_TileKind tile_kind = 0; tile_kind < S_TileKind_COUNT; ++tile_kind)
|
||||
for (P_TileKind tile_kind = 0; tile_kind < P_TileKind_COUNT; ++tile_kind)
|
||||
{
|
||||
String name = S_NameFromTileKind(tile_kind);
|
||||
String name = P_NameFromTileKind(tile_kind);
|
||||
UI_Key key = UI_KeyF("Tile %F", FmtString(name));
|
||||
UI_BoxReport rep = UI_ReportsFromKey(key).draw;
|
||||
|
||||
@ -2232,13 +2219,13 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
UI_BuildSpacer(UI_PIX(padding, 1), Axis_Y);
|
||||
Vec2 tile_pos = MulXformV2(frame->xf.world_to_tile, frame->world_cursor);
|
||||
Vec2 cell_pos = MulXformV2(frame->xf.world_to_cell, frame->world_cursor);
|
||||
i32 tile_idx = S_TileIdxFromTilePos(tile_pos);
|
||||
i32 tile_idx = P_TileIdxFromTilePos(tile_pos);
|
||||
UI_BuildLabelF("Camera pos: %F", FmtFloat2(frame->camera_pos));
|
||||
UI_BuildLabelF("Cursor world pos: %F", FmtFloat2(frame->world_cursor));
|
||||
UI_BuildLabelF("Cursor tile pos: %F", FmtFloat2(tile_pos));
|
||||
UI_BuildLabelF("Cursor tile idx: %F", FmtSint(tile_idx));
|
||||
UI_BuildLabelF("Cursor cell pos: %F", FmtFloat2(cell_pos));
|
||||
UI_BuildLabelF("Hovered ent: %F", S_FmtKey(hovered_ent->key));
|
||||
UI_BuildLabelF("Hovered ent: %F", P_FmtKey(hovered_ent->key));
|
||||
}
|
||||
UI_BuildSpacer(UI_PIX(padding, 1), Axis_Y);
|
||||
{
|
||||
@ -2511,8 +2498,8 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
Vec2 player_pos = VEC2(5, 0);
|
||||
if (kind == V_CmdKind_reset_world)
|
||||
{
|
||||
S_Cmd *cmd = V_PushSimCmd(S_CmdKind_Delta);
|
||||
cmd->delta.kind = S_DeltaKind_Reset;
|
||||
P_Cmd *cmd = V_PushSimCmd(P_CmdKind_Delta);
|
||||
cmd->delta.kind = P_DeltaKind_Reset;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -2520,10 +2507,10 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
}
|
||||
// Spawn player
|
||||
{
|
||||
S_Cmd *cmd = V_PushSimCmd(S_CmdKind_Delta);
|
||||
cmd->delta.kind = S_DeltaKind_RawEnt;
|
||||
S_Ent *ent = &cmd->delta.ent;
|
||||
*ent = S_NilEnt;
|
||||
P_Cmd *cmd = V_PushSimCmd(P_CmdKind_Delta);
|
||||
cmd->delta.kind = P_DeltaKind_RawEnt;
|
||||
P_Ent *ent = &cmd->delta.ent;
|
||||
*ent = P_NilEnt;
|
||||
ent->key = V.player_key;
|
||||
ent->xf = XformFromPos(player_pos);
|
||||
ent->is_player = 1;
|
||||
@ -2534,11 +2521,11 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
|
||||
case V_CmdKind_spawn_dummy:
|
||||
{
|
||||
S_Cmd *cmd = V_PushSimCmd(S_CmdKind_Delta);
|
||||
cmd->delta.kind = S_DeltaKind_RawEnt;
|
||||
S_Ent *ent = &cmd->delta.ent;
|
||||
*ent = S_NilEnt;
|
||||
ent->key = S_RandKey();
|
||||
P_Cmd *cmd = V_PushSimCmd(P_CmdKind_Delta);
|
||||
cmd->delta.kind = P_DeltaKind_RawEnt;
|
||||
P_Ent *ent = &cmd->delta.ent;
|
||||
*ent = P_NilEnt;
|
||||
ent->key = P_RandKey();
|
||||
ent->xf = XformFromPos(frame->world_cursor);
|
||||
ent->is_player = 1;
|
||||
ent->has_weapon = 1;
|
||||
@ -2549,9 +2536,9 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
{
|
||||
if (hovered_ent->valid)
|
||||
{
|
||||
S_Cmd *cmd = V_PushSimCmd(S_CmdKind_Delta);
|
||||
cmd->delta.kind = S_DeltaKind_RawEnt;
|
||||
S_Ent *ent = &cmd->delta.ent;
|
||||
P_Cmd *cmd = V_PushSimCmd(P_CmdKind_Delta);
|
||||
cmd->delta.kind = P_DeltaKind_RawEnt;
|
||||
P_Ent *ent = &cmd->delta.ent;
|
||||
ent->key = hovered_ent->key;
|
||||
ent->exists = 0;
|
||||
}
|
||||
@ -2561,7 +2548,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
{
|
||||
if (frame->is_editing)
|
||||
{
|
||||
S_Cmd *cmd = V_PushSimCmd(S_CmdKind_Save);
|
||||
P_Cmd *cmd = V_PushSimCmd(P_CmdKind_Save);
|
||||
}
|
||||
} break;
|
||||
|
||||
@ -2587,7 +2574,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
f32 fire_presses = fire_held && !last_frame->held_buttons[Button_M1];
|
||||
Vec2 look = Zi;
|
||||
{
|
||||
Vec2 center = S_WorldShapeFromEnt(player).centroid;
|
||||
Vec2 center = P_WorldShapeFromEnt(player).centroid;
|
||||
look = SubVec2(frame->world_cursor, center);
|
||||
}
|
||||
if (frame->is_editing)
|
||||
@ -2609,7 +2596,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
|
||||
// Push control cmd
|
||||
{
|
||||
S_Cmd *cmd = V_PushSimCmd(S_CmdKind_Control);
|
||||
P_Cmd *cmd = V_PushSimCmd(P_CmdKind_Control);
|
||||
cmd->target = V.player_key;
|
||||
cmd->move = frame->move;
|
||||
cmd->look = frame->look;
|
||||
@ -2620,18 +2607,18 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
//////////////////////////////
|
||||
//- Submit sim commands
|
||||
|
||||
LockTicketMutex(&S.input_back_tm);
|
||||
LockTicketMutex(&P.sim_input_back_tm);
|
||||
{
|
||||
S_InputState *v2s = &S.input_states[S.input_back_idx];
|
||||
for (S_CmdNode *src = frame->first_sim_cmd_node; src; src = src->next)
|
||||
P_InputState *v2s = &P.sim_input_states[P.sim_input_back_idx];
|
||||
for (P_CmdNode *src = frame->first_sim_cmd_node; src; src = src->next)
|
||||
{
|
||||
S_CmdNode *cmd_node = PushStruct(v2s->arena, S_CmdNode);
|
||||
P_CmdNode *cmd_node = PushStruct(v2s->arena, P_CmdNode);
|
||||
cmd_node->cmd = src->cmd;
|
||||
SllQueuePush(v2s->first_cmd_node, v2s->last_cmd_node, cmd_node);
|
||||
++v2s->cmds_count;
|
||||
}
|
||||
}
|
||||
UnlockTicketMutex(&S.input_back_tm);
|
||||
UnlockTicketMutex(&P.sim_input_back_tm);
|
||||
|
||||
|
||||
|
||||
@ -2648,7 +2635,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
|
||||
|
||||
|
||||
for (S_Ent *bullet = S_FirstEnt(world); bullet->valid; bullet = S_NextEnt(bullet))
|
||||
for (P_Ent *bullet = P_FirstEnt(world); bullet->valid; bullet = P_NextEnt(bullet))
|
||||
{
|
||||
if (bullet->is_bullet)
|
||||
{
|
||||
@ -2828,7 +2815,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
|
||||
if (0)
|
||||
{
|
||||
for (S_Ent *bullet = S_FirstEnt(world); bullet->valid; bullet = S_NextEnt(bullet))
|
||||
for (P_Ent *bullet = P_FirstEnt(world); bullet->valid; bullet = P_NextEnt(bullet))
|
||||
{
|
||||
if (bullet->is_bullet && bullet->has_hit)
|
||||
{
|
||||
@ -2905,29 +2892,29 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
|
||||
|
||||
// {
|
||||
// for (S_Ent *firer = S_FirstEnt(world); firer->valid; firer = S_NextEnt(firer))
|
||||
// for (P_Ent *firer = P_FirstEnt(world); firer->valid; firer = P_NextEnt(firer))
|
||||
// {
|
||||
// if (firer->fire_held)
|
||||
// {
|
||||
// Xform firer_xf = firer->xf;
|
||||
// S_Shape firer_world_shape = S_MulXformShape(firer_xf, firer->local_shape);
|
||||
// P_Shape firer_world_shape = P_MulXformShape(firer_xf, firer->local_shape);
|
||||
|
||||
// Vec2 ray_start = firer_world_shape.centroid;
|
||||
// Vec2 ray_dir = firer->look;
|
||||
|
||||
// // TODO: Real raycast query
|
||||
// S_Ent *closest_victim = &S_NilEnt;
|
||||
// S_RaycastResult victim_raycast = Zi;
|
||||
// P_Ent *closest_victim = &P_NilEnt;
|
||||
// P_RaycastResult victim_raycast = Zi;
|
||||
// {
|
||||
// f32 closest_len_sq = Inf;
|
||||
// for (S_Ent *victim = S_FirstEnt(world); victim->valid; victim = S_NextEnt(victim))
|
||||
// for (P_Ent *victim = P_FirstEnt(world); victim->valid; victim = P_NextEnt(victim))
|
||||
// {
|
||||
// if (victim != firer)
|
||||
// {
|
||||
// Xform victim_xf = victim->xf;
|
||||
// S_Shape victim_world_shape = S_MulXformShape(victim_xf, victim->local_shape);
|
||||
// P_Shape victim_world_shape = P_MulXformShape(victim_xf, victim->local_shape);
|
||||
|
||||
// S_RaycastResult raycast = S_RaycastShape(victim_world_shape, ray_start, ray_dir);
|
||||
// P_RaycastResult raycast = P_RaycastShape(victim_world_shape, ray_start, ray_dir);
|
||||
// if (raycast.is_intersecting)
|
||||
// {
|
||||
// f32 len_sq = Vec2LenSq(SubVec2(raycast.p, ray_start));
|
||||
@ -2990,8 +2977,8 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
// }
|
||||
|
||||
|
||||
// // for (S_QueryResult query = S_FirstRaycast(wrold, ray_start, ray_dir); query.
|
||||
// // S_RaycastWorldResult hits = S_RaycastWorld(world, ray_start, ray_dir)
|
||||
// // for (P_QueryResult query = P_FirstRaycast(wrold, ray_start, ray_dir); query.
|
||||
// // P_RaycastWorldResult hits = P_RaycastWorld(world, ray_start, ray_dir)
|
||||
// // {
|
||||
// // }
|
||||
// }
|
||||
@ -3027,14 +3014,98 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
V_PushParticles(emitter);
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- Debug draw
|
||||
|
||||
{
|
||||
// Copy debug draw data from sim
|
||||
if (received_unseen_tick)
|
||||
{
|
||||
ResetArena(sim_debug_arena);
|
||||
first_sim_debug_draw_node = 0;
|
||||
last_sim_debug_draw_node = 0;
|
||||
{
|
||||
i64 dst_idx = 0;
|
||||
P_DebugDrawNode *dst_nodes = PushStructsNoZero(sim_debug_arena, P_DebugDrawNode, sim_output->debug_draw_nodes_count);
|
||||
for (P_DebugDrawNode *src = sim_output->first_debug_draw_node; src; src = src->next)
|
||||
{
|
||||
P_DebugDrawNode *dst = &dst_nodes[dst_idx];
|
||||
*dst = *src;
|
||||
dst_idx += 1;
|
||||
SllQueuePush(first_sim_debug_draw_node, last_sim_debug_draw_node, dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Merge vis debug draws with sim debug draws
|
||||
P_DebugDrawNode *first_debug_draw_node = first_sim_debug_draw_node;
|
||||
P_DebugDrawNode *last_debug_draw_node = last_sim_debug_draw_node;
|
||||
if (P_tl.first_debug_draw_node)
|
||||
{
|
||||
if (last_debug_draw_node)
|
||||
{
|
||||
last_debug_draw_node->next = P_tl.first_debug_draw_node;
|
||||
}
|
||||
else
|
||||
{
|
||||
first_debug_draw_node = P_tl.first_debug_draw_node;
|
||||
}
|
||||
last_debug_draw_node = P_tl.last_debug_draw_node;
|
||||
}
|
||||
|
||||
for (P_DebugDrawNode *n = first_debug_draw_node; n; n = n->next)
|
||||
{
|
||||
Vec4 color = Vec4FromU32(n->srgb32);
|
||||
i32 detail = 24;
|
||||
f32 radius = 5;
|
||||
switch(n->kind)
|
||||
{
|
||||
case P_DebugDrawKind_Point:
|
||||
{
|
||||
Vec2 ui_p = MulXformV2(frame->xf.world_to_ui, n->point.p);
|
||||
V_DrawPoint(ui_p, color);
|
||||
} break;
|
||||
|
||||
case P_DebugDrawKind_Line:
|
||||
{
|
||||
Vec2 ui_p0 = MulXformV2(frame->xf.world_to_ui, n->line.p0);
|
||||
Vec2 ui_p1 = MulXformV2(frame->xf.world_to_ui, n->line.p1);
|
||||
V_DrawLine(ui_p0, ui_p1, color);
|
||||
} break;
|
||||
|
||||
case P_DebugDrawKind_Rect:
|
||||
{
|
||||
Rng2 ui_rect = Zi;
|
||||
ui_rect.p0 = MulXformV2(frame->xf.world_to_ui, n->rect.p0);
|
||||
ui_rect.p1 = MulXformV2(frame->xf.world_to_ui, n->rect.p1);
|
||||
V_DrawRect(ui_rect, color, V_DrawFlag_Line);
|
||||
} break;
|
||||
|
||||
case P_DebugDrawKind_Shape:
|
||||
{
|
||||
P_Shape ui_shape = P_MulXformShape(frame->xf.world_to_ui, n->shape);
|
||||
V_DrawShape(ui_shape, color, detail, V_DrawFlag_Line);
|
||||
// V_DrawShape(ui_shape, color, detail, V_DrawFlag_None);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
// Reset vis debug draws
|
||||
ResetArena(P_tl.debug_arena);
|
||||
P_tl.first_debug_draw_node = 0;
|
||||
P_tl.last_debug_draw_node = 0;
|
||||
P_tl.debug_draw_nodes_count = 0;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
//- Draw entities
|
||||
|
||||
// for (S_Ent *ent = S_FirstEnt(world); ent->valid; ent = S_NextEnt(ent))
|
||||
// for (P_Ent *ent = P_FirstEnt(world); ent->valid; ent = P_NextEnt(ent))
|
||||
// {
|
||||
// Xform ent_to_world_xf = ent->xf;
|
||||
// Xform ent_to_draw_xf = MulXform(frame->xf.world_to_draw, ent_to_world_xf);
|
||||
// S_Shape draw_shape = S_MulXformShape(ent_to_draw_xf, ent->local_shape);
|
||||
// P_Shape draw_shape = P_MulXformShape(ent_to_draw_xf, ent->local_shape);
|
||||
|
||||
// f32 opacity = 0.5;
|
||||
|
||||
@ -3056,7 +3127,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
// // color.w *= opacity;
|
||||
// // f32 width = 0.1;
|
||||
// // f32 height = 0.75;
|
||||
// // S_Shape local_shape = S_ShapeFromDesc(
|
||||
// // P_Shape local_shape = P_ShapeFromDesc(
|
||||
// // .count = 4,
|
||||
// // .points = {
|
||||
// // VEC2(-width / 2, -height), VEC2(width / 2, -height),
|
||||
@ -3065,7 +3136,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
// // );
|
||||
// // Xform local_xf = XformFromTrs(TRS(.t = { 0, 0 }, .r = Tau / 4));
|
||||
// // Xform xf = MulXform(ent_to_draw_xf, local_xf);
|
||||
// // S_Shape shape = S_MulXformShape(xf, local_shape);
|
||||
// // P_Shape shape = P_MulXformShape(xf, local_shape);
|
||||
// // V_DrawShape(shape, color, 10, V_DrawFlag_Line);
|
||||
// // }
|
||||
|
||||
@ -3073,53 +3144,12 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
// // {
|
||||
// // Vec4 color = Color_Orange;
|
||||
// // color.w *= opacity;
|
||||
// // Rng2 bb = S_BoundingBoxFromShape(draw_shape);
|
||||
// // Rng2 bb = P_BoundingBoxFromShape(draw_shape);
|
||||
// // V_DrawRect(bb, color, V_DrawFlag_Line);
|
||||
// // }
|
||||
// }
|
||||
// }
|
||||
|
||||
//////////////////////////////
|
||||
//- Draw sim debug shapes
|
||||
|
||||
for (u64 desc_idx = 0; desc_idx < sim_debug_draw_descs_count; ++desc_idx)
|
||||
{
|
||||
S_DebugDrawDesc *desc = &sim_debug_draw_descs[desc_idx];
|
||||
Vec4 color = Vec4FromU32(desc->srgb32);
|
||||
i32 detail = 24;
|
||||
f32 radius = 5;
|
||||
switch(desc->kind)
|
||||
{
|
||||
case S_DebugDrawKind_Point:
|
||||
{
|
||||
Vec2 ui_p = MulXformV2(frame->xf.world_to_ui, desc->point.p);
|
||||
V_DrawPoint(ui_p, color);
|
||||
} break;
|
||||
|
||||
case S_DebugDrawKind_Line:
|
||||
{
|
||||
Vec2 ui_p0 = MulXformV2(frame->xf.world_to_ui, desc->line.p0);
|
||||
Vec2 ui_p1 = MulXformV2(frame->xf.world_to_ui, desc->line.p1);
|
||||
V_DrawLine(ui_p0, ui_p1, color);
|
||||
} break;
|
||||
|
||||
case S_DebugDrawKind_Rect:
|
||||
{
|
||||
Rng2 ui_rect = Zi;
|
||||
ui_rect.p0 = MulXformV2(frame->xf.world_to_ui, desc->rect.p0);
|
||||
ui_rect.p1 = MulXformV2(frame->xf.world_to_ui, desc->rect.p1);
|
||||
V_DrawRect(ui_rect, color, V_DrawFlag_Line);
|
||||
} break;
|
||||
|
||||
case S_DebugDrawKind_Shape:
|
||||
{
|
||||
S_Shape ui_shape = S_MulXformShape(frame->xf.world_to_ui, desc->shape);
|
||||
V_DrawShape(ui_shape, color, detail, V_DrawFlag_Line);
|
||||
// V_DrawShape(ui_shape, color, detail, V_DrawFlag_None);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- Render
|
||||
|
||||
@ -3207,9 +3237,9 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
|
||||
// Fill tile textures
|
||||
{
|
||||
for (S_TileKind tile_kind = 0; tile_kind < S_TileKind_COUNT; ++tile_kind)
|
||||
for (P_TileKind tile_kind = 0; tile_kind < P_TileKind_COUNT; ++tile_kind)
|
||||
{
|
||||
String tile_name = S_TileNameFromKind(tile_kind);
|
||||
String tile_name = P_TileNameFromKind(tile_kind);
|
||||
String sheet_name = StringF(frame->arena, "tile/%F.ase", FmtString(tile_name));
|
||||
ResourceKey sheet_resource = ResourceKeyFromStore(&P_Resources, sheet_name);
|
||||
SPR_SheetKey sheet = SPR_SheetKeyFromResource(sheet_resource);
|
||||
@ -3343,8 +3373,8 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
|
||||
{
|
||||
i64 ents_to_prune_count = 0;
|
||||
S_Ent **ents_to_prune = PushStructsNoZero(frame->arena, S_Ent *, world->ents_count);
|
||||
for (S_Ent *ent = S_FirstEnt(world); ent->valid; ent = S_NextEnt(ent))
|
||||
P_Ent **ents_to_prune = PushStructsNoZero(frame->arena, P_Ent *, world->ents_count);
|
||||
for (P_Ent *ent = P_FirstEnt(world); ent->valid; ent = P_NextEnt(ent))
|
||||
{
|
||||
if (ent->exists <= 0)
|
||||
{
|
||||
@ -3356,8 +3386,8 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
for (i64 prune_idx = 0; prune_idx < ents_to_prune_count; ++prune_idx)
|
||||
{
|
||||
// FIXME: Add to free list
|
||||
S_Ent *ent = ents_to_prune[prune_idx];
|
||||
S_EntBin *bin = &world->ent_bins[ent->key.v % world->ent_bins_count];
|
||||
P_Ent *ent = ents_to_prune[prune_idx];
|
||||
P_EntBin *bin = &world->ent_bins[ent->key.v % world->ent_bins_count];
|
||||
DllQueueRemoveNP(bin->first, bin->last, ent, next_in_bin, prev_in_bin);
|
||||
DllQueueRemove(world->first_ent, world->last_ent, ent);
|
||||
world->ents_count -= 1;
|
||||
|
||||
@ -234,7 +234,7 @@ Struct(V_Frame)
|
||||
|
||||
// Editor state
|
||||
V_EditMode edit_mode;
|
||||
S_TileKind equipped_tile;
|
||||
P_TileKind equipped_tile;
|
||||
|
||||
// Editor
|
||||
b32 is_selecting;
|
||||
@ -273,8 +273,8 @@ Struct(V_Frame)
|
||||
|
||||
// Sim cmds
|
||||
u64 sim_cmds_count;
|
||||
S_CmdNode *first_sim_cmd_node;
|
||||
S_CmdNode *last_sim_cmd_node;
|
||||
P_CmdNode *first_sim_cmd_node;
|
||||
P_CmdNode *last_sim_cmd_node;
|
||||
|
||||
// Emitters
|
||||
i64 emitters_count;
|
||||
@ -284,7 +284,7 @@ Struct(V_Frame)
|
||||
|
||||
Struct(V_Ctx)
|
||||
{
|
||||
S_Key player_key;
|
||||
P_Key player_key;
|
||||
|
||||
i64 panels_count;
|
||||
i64 windows_count;
|
||||
@ -315,7 +315,7 @@ void V_Shutdown(void);
|
||||
V_Frame *V_CurrentFrame(void);
|
||||
V_Frame *V_LastFrame(void);
|
||||
V_Cmd *V_PushVisCmd(String name);
|
||||
S_Cmd *V_PushSimCmd(S_CmdKind kind);
|
||||
P_Cmd *V_PushSimCmd(P_CmdKind kind);
|
||||
String V_StringFromHotkey(Arena *arena, V_Hotkey hotkey);
|
||||
void V_PushParticles(V_Emitter src);
|
||||
|
||||
@ -323,7 +323,7 @@ void V_PushParticles(V_Emitter src);
|
||||
//~ Draw helpers
|
||||
|
||||
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(P_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_DrawPoint(Vec2 p, Vec4 srgb);
|
||||
|
||||
@ -69,7 +69,7 @@ ComputeShader2D(V_BackdropCS, 8, 8)
|
||||
{
|
||||
V_GpuParams params = G_Dereference<V_GpuParams>(V_ShaderConst_Params)[0];
|
||||
RWTexture2D<Vec4> target = G_Dereference<Vec4>(params.target_rw);
|
||||
Texture2D<S_TileKind> tiles = G_Dereference<S_TileKind>(params.tiles);
|
||||
Texture2D<P_TileKind> tiles = G_Dereference<P_TileKind>(params.tiles);
|
||||
|
||||
const Vec4 background_color_a = LinearFromSrgb(Vec4(0.30, 0.30, 0.30, 1));
|
||||
const Vec4 background_color_b = LinearFromSrgb(Vec4(0.15, 0.15, 0.15, 1));
|
||||
@ -82,10 +82,10 @@ ComputeShader2D(V_BackdropCS, 8, 8)
|
||||
Vec2 cell_pos = floor(mul(params.xf.world_to_cell, Vec3(world_pos, 1)));
|
||||
Vec2 tile_pos = mul(params.xf.world_to_tile, Vec3(world_pos, 1));
|
||||
|
||||
S_TileKind tile = tiles.Load(Vec3(tile_pos, 0));
|
||||
P_TileKind tile = tiles.Load(Vec3(tile_pos, 0));
|
||||
|
||||
f32 half_thickness = 1;
|
||||
f32 half_bounds_size = S_WorldPitch * 0.5;
|
||||
f32 half_bounds_size = P_WorldPitch * 0.5;
|
||||
Vec2 bounds_screen_p0 = mul(params.xf.world_to_ui, Vec3(-half_bounds_size, -half_bounds_size, 1));
|
||||
Vec2 bounds_screen_p1 = mul(params.xf.world_to_ui, Vec3(half_bounds_size, half_bounds_size, 1));
|
||||
bool is_in_bounds = ui_pos.x > (bounds_screen_p0.x - half_thickness) &&
|
||||
@ -125,17 +125,17 @@ ComputeShader2D(V_BackdropCS, 8, 8)
|
||||
// Tile test
|
||||
// TODO: Remove this
|
||||
{
|
||||
S_TileKind tile_tl = tiles.Load(Vec3(tile_pos.x - 1, tile_pos.y - 1, 0));
|
||||
S_TileKind tile_tr = tiles.Load(Vec3(tile_pos.x + 1, tile_pos.y - 1, 0));
|
||||
S_TileKind tile_br = tiles.Load(Vec3(tile_pos.x + 1, tile_pos.y + 1, 0));
|
||||
S_TileKind tile_bl = tiles.Load(Vec3(tile_pos.x - 1, tile_pos.y + 1, 0));
|
||||
S_TileKind tile_t = tiles.Load(Vec3(tile_pos.x, tile_pos.y - 1, 0));
|
||||
S_TileKind tile_r = tiles.Load(Vec3(tile_pos.x + 1, tile_pos.y, 0));
|
||||
S_TileKind tile_b = tiles.Load(Vec3(tile_pos.x, tile_pos.y + 1, 0));
|
||||
S_TileKind tile_l = tiles.Load(Vec3(tile_pos.x - 1, tile_pos.y, 0));
|
||||
P_TileKind tile_tl = tiles.Load(Vec3(tile_pos.x - 1, tile_pos.y - 1, 0));
|
||||
P_TileKind tile_tr = tiles.Load(Vec3(tile_pos.x + 1, tile_pos.y - 1, 0));
|
||||
P_TileKind tile_br = tiles.Load(Vec3(tile_pos.x + 1, tile_pos.y + 1, 0));
|
||||
P_TileKind tile_bl = tiles.Load(Vec3(tile_pos.x - 1, tile_pos.y + 1, 0));
|
||||
P_TileKind tile_t = tiles.Load(Vec3(tile_pos.x, tile_pos.y - 1, 0));
|
||||
P_TileKind tile_r = tiles.Load(Vec3(tile_pos.x + 1, tile_pos.y, 0));
|
||||
P_TileKind tile_b = tiles.Load(Vec3(tile_pos.x, tile_pos.y + 1, 0));
|
||||
P_TileKind tile_l = tiles.Load(Vec3(tile_pos.x - 1, tile_pos.y, 0));
|
||||
|
||||
f32 tile_edge_dist = Inf;
|
||||
S_TileKind edge_tile = tile;
|
||||
P_TileKind edge_tile = tile;
|
||||
if (tile_tl != tile) { edge_tile = tile_tl; tile_edge_dist = min(tile_edge_dist, length(tile_pos - Vec2(floor(tile_pos.x), floor(tile_pos.y)))); }
|
||||
if (tile_tr != tile) { edge_tile = tile_tr; tile_edge_dist = min(tile_edge_dist, length(tile_pos - Vec2(ceil(tile_pos.x), floor(tile_pos.y)))); }
|
||||
if (tile_br != tile) { edge_tile = tile_br; tile_edge_dist = min(tile_edge_dist, length(tile_pos - Vec2(ceil(tile_pos.x), ceil(tile_pos.y)))); }
|
||||
@ -145,14 +145,14 @@ ComputeShader2D(V_BackdropCS, 8, 8)
|
||||
if (tile_t != tile) { edge_tile = tile_t; tile_edge_dist = min(tile_edge_dist, frac(tile_pos.y)); }
|
||||
if (tile_b != tile) { edge_tile = tile_b; tile_edge_dist = min(tile_edge_dist, 1.0 - frac(tile_pos.y)); }
|
||||
|
||||
if (tile == S_TileKind_Wall)
|
||||
if (tile == P_TileKind_Wall)
|
||||
{
|
||||
Vec4 outer = LinearFromSrgb(Vec4(0.05, 0.05, 0.05, 1));
|
||||
Vec4 inner = LinearFromSrgb(Vec4(0.10, 0.10, 0.10, 1));
|
||||
result = lerp(outer, inner, smoothstep(0, 1, tile_edge_dist / 0.375));
|
||||
// result = lerp(outer, inner, smoothstep(0, 1, tile_edge_dist / 0.5));
|
||||
}
|
||||
else if (tile != S_TileKind_Empty)
|
||||
else if (tile != P_TileKind_Empty)
|
||||
{
|
||||
SamplerState wrap_sampler = G_Dereference(params.pt_wrap_sampler);
|
||||
SPR_Slice slice = params.tile_slices[tile];
|
||||
@ -166,12 +166,12 @@ ComputeShader2D(V_BackdropCS, 8, 8)
|
||||
// {
|
||||
// default: break;
|
||||
|
||||
// case S_TileKind_Floor:
|
||||
// case P_TileKind_Floor:
|
||||
// {
|
||||
// result = Color_Blue;
|
||||
// } break;
|
||||
|
||||
// case S_TileKind_Wall:
|
||||
// case P_TileKind_Wall:
|
||||
// {
|
||||
// // result = Color_Red;
|
||||
// result = Color_Black;
|
||||
@ -517,10 +517,10 @@ PixelShader(V_OverlayPS, V_OverlayPSOutput, V_OverlayPSInput input)
|
||||
|
||||
Vec2 world_pos = mul(params.xf.ui_to_world, Vec3(ui_pos, 1));
|
||||
Vec2 tile_pos = mul(params.xf.world_to_tile, Vec3(world_pos, 1));
|
||||
S_TileKind equipped_tile = params.equipped_tile;
|
||||
P_TileKind equipped_tile = params.equipped_tile;
|
||||
|
||||
f32 half_thickness = 1;
|
||||
f32 half_bounds_size = S_WorldPitch * 0.5;
|
||||
f32 half_bounds_size = P_WorldPitch * 0.5;
|
||||
Vec2 bounds_screen_p0 = mul(params.xf.world_to_ui, Vec3(-half_bounds_size, -half_bounds_size, 1));
|
||||
Vec2 bounds_screen_p1 = mul(params.xf.world_to_ui, Vec3(half_bounds_size, half_bounds_size, 1));
|
||||
bool is_in_bounds = ui_pos.x > (bounds_screen_p0.x - half_thickness) &&
|
||||
@ -558,10 +558,10 @@ PixelShader(V_OverlayPS, V_OverlayPSOutput, V_OverlayPSInput input)
|
||||
// else
|
||||
{
|
||||
if (
|
||||
world_pos.x > -(S_WorldPitch / 2) &&
|
||||
world_pos.y > -(S_WorldPitch / 2) &&
|
||||
world_pos.x < (S_WorldPitch / 2) &&
|
||||
world_pos.y < (S_WorldPitch / 2) &&
|
||||
world_pos.x > -(P_WorldPitch / 2) &&
|
||||
world_pos.y > -(P_WorldPitch / 2) &&
|
||||
world_pos.x < (P_WorldPitch / 2) &&
|
||||
world_pos.y < (P_WorldPitch / 2) &&
|
||||
tile_pos.x >= tile_selection.p0.x &&
|
||||
tile_pos.x <= tile_selection.p1.x &&
|
||||
tile_pos.y >= tile_selection.p0.y &&
|
||||
|
||||
@ -71,7 +71,7 @@ Struct(V_GpuParams)
|
||||
G_SamplerStateRef pt_wrap_sampler;
|
||||
|
||||
V_SelectionMode selection_mode;
|
||||
S_TileKind equipped_tile;
|
||||
P_TileKind equipped_tile;
|
||||
|
||||
b32 has_mouse_focus;
|
||||
b32 has_keyboard_focus;
|
||||
@ -99,7 +99,7 @@ Struct(V_GpuParams)
|
||||
G_RWTexture2DRef stains;
|
||||
G_RWTexture2DRef drynesses;
|
||||
|
||||
SPR_Slice tile_slices[S_TileKind_COUNT];
|
||||
SPR_Slice tile_slices[P_TileKind_COUNT];
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
@ -92,6 +92,7 @@ SPR_Slice SPR_SliceFromSheet(SPR_SheetKey sheet, String slice_name)
|
||||
SPR_CmdNode *n = SPR.submit.first_free;
|
||||
if (n)
|
||||
{
|
||||
SllStackPop(SPR.submit.first_free);
|
||||
ZeroStruct(n);
|
||||
}
|
||||
else
|
||||
|
||||
Loading…
Reference in New Issue
Block a user