//////////////////////////////////////////////////////////// //~ 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]; }; //////////////////////////////////////////////////////////// //~ 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; }; }; //////////////////////////////////////////////////////////// //~ Ent types // TODO: Move boolean fields into bitwise property flags // TODO: Pack efficiently, deduplicate redundant fields #define P_MinPlayerNameLen 1 #define P_MaxPlayerNameLen 24 Struct(P_Control) { i64 tick; i64 orig_tick; // Will differ from tick if this control was propagated from the control of another tick Vec2 move; Vec2 look; f32 fire_held; f32 fire_presses; }; 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; u64 rand_seq; i64 created_at_ns; //- Build data f32 exists; b32 is_guy; b32 is_dummy; f32 health; Xform prev_xf; Xform xf; // 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; //- Player / Guy P_Control control; //- Player b32 is_player; P_Key guy; u8 string_len; u8 string_text[P_MaxPlayerNameLen + 8]; //- Solver 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; }; //////////////////////////////////////////////////////////// //~ 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]; }; //////////////////////////////////////////////////////////// //~ World types Struct(P_Frame) { ////////////////////////////// //- Internal world state struct P_World *world; P_Frame *next; P_Frame *prev; P_Frame *next_in_bin; P_Frame *prev_in_bin; ////////////////////////////// //- Frame state i64 tick; i64 time_ns; i64 ents_count; P_Ent *first_ent; P_Ent *last_ent; i64 ent_bins_count; P_EntBin *ent_bins; i64 max_constraints; i64 constraints_count; P_Constraint *constraints; }; Struct(P_FrameBin) { P_Frame *first; P_Frame *last; }; Struct(P_World) { Arena *arena; Arena *frames_arena; Arena *statics_arena; u64 seed; RandState rand; P_Ent *first_free_ent; P_Frame *first_frame; P_Frame *last_frame; P_Frame *first_free_frame; i64 frame_bins_count; P_FrameBin *frame_bins; u64 tiles_hash; u8 *tiles; }; //////////////////////////////////////////////////////////// //~ Message types Enum(P_MsgKind) { P_MsgKind_None, P_MsgKind_Raw, // Server <-> Client P_MsgKind_Chat, P_MsgKind_Connect, // Client -> Server P_MsgKind_SaveWorld, P_MsgKind_ResetWorld, P_MsgKind_TileEdit, P_MsgKind_EntEdit, P_MsgKind_Delete, // Server -> Client P_MsgKind_Tiles, }; Struct(P_Msg) { P_MsgKind kind; NET_Key src; NET_Key dst; b32 affect_dummies; P_TileKind tile_kind; Rng2I32 tile_range; u64 tiles_hash; P_Key key; Vec2 pos; String data; }; Struct(P_MsgNode) { P_MsgNode *next; P_MsgNode *prev; P_Msg msg; }; Struct(P_MsgList) { P_MsgNode *first; P_MsgNode *last; i64 count; }; //////////////////////////////////////////////////////////// //~ 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; }; //////////////////////////////////////////////////////////// //~ State types Struct(P_Ctx) { // Sim -> Vis state TicketMutex s2v_tm; struct { i64 gen; Arena *arena; i64 debug_draw_nodes_count; P_DebugDrawNode *first_debug_draw_node; P_DebugDrawNode *last_debug_draw_node; NET_PipeStatistics pipe_stats; } s2v; }; Struct(P_ThreadLocalCtx) { //- Per-thread debug info Arena *debug_arena; b32 debug_draw_enabled; Vec4 debug_tint; P_DebugDrawNode *first_debug_draw_node; P_DebugDrawNode *last_debug_draw_node; i64 debug_draw_nodes_count; //- Per-thread outbound messages Arena *out_msgs_arena; P_MsgList out_msgs; }; extern P_Ctx P; extern ThreadLocal P_ThreadLocalCtx P_tl; extern Readonly P_Ent P_NilEnt; extern Readonly P_Frame P_NilFrame; //////////////////////////////////////////////////////////// //~ Bootstrap void P_Bootstrap(void); //////////////////////////////////////////////////////////// //~ Nil helpers b32 P_IsKeyNil(P_Key key); b32 P_IsEntNil(P_Ent *ent); b32 P_IsFrameNil(P_Frame *frame); //////////////////////////////////////////////////////////// //~ Key helpers b32 P_MatchKey(P_Key a, P_Key b); P_Key P_RandKey(void); u64 P_RandU64FromEnt(P_Ent *ent); #define P_FmtKey(key) FmtHandle((key).v) //////////////////////////////////////////////////////////// //~ String helpers String P_StringFromEnt(P_Ent *ent); void P_SetEntString(P_Ent *ent, String str); //////////////////////////////////////////////////////////// //~ Tile helpers String P_NameFromTileKind(P_TileKind kind); //////////////////////////////////////////////////////////// //~ 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_Frame *frame, P_Key key); //////////////////////////////////////////////////////////// //~ Iteration helpers P_Ent *P_FirstEnt(P_Frame *frame); P_Ent *P_NextEnt(P_Ent *e); //////////////////////////////////////////////////////////// //~ List helpers P_Ent *P_PushTempEnt(Arena *arena, P_EntList *list); //////////////////////////////////////////////////////////// //~ 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); void P_DebugDrawFrame(P_Frame *frame); //////////////////////////////////////////////////////////// //~ Msg P_Msg *P_PushMsg(P_MsgKind kind, String data); //////////////////////////////////////////////////////////// //~ World P_World *P_AcquireWorld(void); void P_SpawnEntsFromList(P_Frame *frame, P_EntList ents); P_Frame *P_FrameFromTick(P_World *world, i64 tick); void P_ClearFrames(P_World *world, i64 tick_min, i64 tick_max); P_Frame *P_PushFrame(P_World *world, P_Frame *src_frame, i64 tick); //////////////////////////////////////////////////////////// //~ Step void P_StepFrame(P_Frame *frame);