move shared vis-sim functionality to pp layer

This commit is contained in:
jacob 2026-01-10 16:04:39 -06:00
parent 4df1418aa5
commit 32938a9abe
19 changed files with 2232 additions and 2157 deletions

1258
src/pp/pp.c Normal file

File diff suppressed because it is too large Load Diff

454
src/pp/pp.h Normal file
View 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);

View File

@ -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
View 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
View 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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -4,7 +4,6 @@
//- Dependencies
@Dep pp
@Dep pp_sim
@Dep sprite
@Dep gpu
@Dep glyph_cache

View File

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

View File

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

View File

@ -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 &&

View File

@ -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];
};
////////////////////////////////////////////////////////////

View File

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