diff --git a/src/base/base_math.c b/src/base/base_math.c index 63122e0c..dc302dd8 100644 --- a/src/base/base_math.c +++ b/src/base/base_math.c @@ -765,6 +765,11 @@ Rng2 IntersectRng2(Rng2 a, Rng2 b) return result; } +b32 IsIntersectingRng2(Rng2 a, Rng2 b) +{ + return !IsRng2Empty(IntersectRng2(a, b)); +} + Rng2 AddRng2Vec2(Rng2 r, Vec2 v) { Rng2 result = Zi; @@ -833,6 +838,11 @@ Rng2I32 IntersectRng2I32(Rng2I32 a, Rng2I32 b) return result; } +b32 IsIntersectingRng2I32(Rng2I32 a, Rng2I32 b) +{ + return !IsRng2I32Empty(IntersectRng2I32(a, b)); +} + Rng2I32 AddRng2I32Vec2I32(Rng2I32 r, Vec2I32 v) { Rng2I32 result = Zi; diff --git a/src/base/base_math.h b/src/base/base_math.h index fd2f106c..a0fd73c5 100644 --- a/src/base/base_math.h +++ b/src/base/base_math.h @@ -439,6 +439,7 @@ Vec2 CenterFromRng2(Rng2 r); Vec2 NormRng2(Rng2 r, Vec2 v); Rng2 UnionRng2(Rng2 a, Rng2 b); Rng2 IntersectRng2(Rng2 a, Rng2 b); +b32 IsIntersectingRng2(Rng2 a, Rng2 b); Rng2 AddRng2Vec2(Rng2 r, Vec2 v); Rng2 MulRng2Vec2(Rng2 a, Vec2 v); Rng2 DivRng2Vec2(Rng2 a, Vec2 v); @@ -449,6 +450,7 @@ Vec2I32 DimsFromRng2I32(Rng2I32 r); Vec2I32 CenterFromRng2I32(Rng2I32 r); Rng2I32 UnionRng2I32(Rng2I32 a, Rng2I32 b); Rng2I32 IntersectRng2I32(Rng2I32 a, Rng2I32 b); +b32 IsIntersectingRng2I32(Rng2I32 a, Rng2I32 b); Rng2I32 AddRng2I32Vec2I32(Rng2I32 r, Vec2I32 v); Rng2I32 MulRng2I32Vec2I32(Rng2I32 a, Vec2I32 v); Rng2I32 DivRng2I32Vec2I32(Rng2I32 a, Vec2I32 v); diff --git a/src/pp/pp.c b/src/pp/pp.c index a27ebe24..385304e0 100644 --- a/src/pp/pp.c +++ b/src/pp/pp.c @@ -1193,6 +1193,215 @@ P_Constraint *P_NextConstraint(P_Constraint *c) return result; } +//////////////////////////////////////////////////////////// +//~ Space + +P_Space P_SpaceFromFrame(Arena *arena, P_Frame *frame) +{ + P_Space space = Zi; + TempArena scratch = BeginScratch(arena); + P_World *world = frame->world; + i64 cells_count = P_WorldPitch * P_WorldPitch; + space.cells = PushStructs(arena, P_SpaceCell, cells_count); + + Rng2 space_aabb = RNG2( + VEC2(0, 0), + VEC2(P_WorldPitch, P_WorldPitch) + ); + + //- Insert entity shapes + for (P_Ent *ent = P_FirstEnt(frame); !P_IsEntNil(ent); ent = P_NextEnt(ent)) + { + b32 should_insert = ent->is_guy; + if (should_insert) + { + P_Shape shape = P_WorldShapeFromEnt(ent); + Rng2 aabb = P_BoundingBoxFromShape(shape); + aabb = AddRng2Vec2(aabb, VEC2(P_WorldPitch / 2.0, P_WorldPitch / 2.0)); + aabb.p0 = FloorVec2(aabb.p0); + aabb.p1 = CeilVec2(aabb.p1); + aabb.p1.x = MaxF32(aabb.p1.x, aabb.p0.x + 1); + aabb.p1.y = MaxF32(aabb.p1.y, aabb.p0.y + 1); + aabb = IntersectRng2(aabb, space_aabb); + if (!IsRng2Empty(aabb)) + { + for (i32 y = aabb.p0.y; y < aabb.p1.y; ++y) + { + for (i32 x = aabb.p0.x; x < aabb.p1.x; ++x) + { + i64 cell_idx = y * P_WorldPitch + x; + P_SpaceCell *cell = &space.cells[cell_idx]; + P_SpaceEntry *entry = PushStruct(arena, P_SpaceEntry); + SllStackPush(cell->first, entry); + entry->shape = shape; + entry->shape_id = ent->key.v; + } + } + } + } + } + + //- Generate wall shapes from tiles + // TODO: Cache walls in separate space + { + Enum(WallDir) + { + WallDir_None, + WallDir_Up, + WallDir_Right, + WallDir_Down, + WallDir_Left, + }; + + Struct(GenWall) + { + GenWall *next; + WallDir dir; + Vec2I32 start; + Vec2I32 end; + }; + + i64 walls_count = 0; + GenWall *first_wall = 0; + + + + + + // FIXME: Iterate to pitch + 1 + + + + //- Generate horizontal walls + for (i32 tile_y = 0; tile_y < P_TilesPitch + 1; ++tile_y) + { + i32 wall_start = -1; + WallDir prev_wall_dir = WallDir_None; + for (i32 tile_x = 0; tile_x < P_TilesPitch + 1; ++tile_x) + { + P_TileKind tile = P_TileKind_Empty; + P_TileKind tile_t = P_TileKind_Empty; + if (tile_x >= 0 && tile_x < P_TilesPitch) + { + if (tile_y >= 0 && tile_y < P_TilesPitch) + { + tile = world->tiles[tile_y * (i32)P_TilesPitch + tile_x]; + } + if ((tile_y - 1) >= 0 && (tile_y - 1) < P_TilesPitch) + { + tile_t = world->tiles[(tile_y - 1) * (i32)P_TilesPitch + tile_x]; + } + } + WallDir dir = WallDir_None; + if (tile == P_TileKind_Wall && tile_t != P_TileKind_Wall) + { + dir = WallDir_Up; + } + else if (tile != P_TileKind_Wall && tile_t == P_TileKind_Wall) + { + dir = WallDir_Down; + } + if (dir != prev_wall_dir) + { + if (prev_wall_dir != WallDir_None) + { + GenWall *wall = PushStruct(scratch.arena, GenWall); + ++walls_count; + SllStackPush(first_wall, wall); + wall->dir = prev_wall_dir; + wall->start = VEC2I32(wall_start, tile_y); + wall->end = VEC2I32(tile_x, tile_y); + } + wall_start = tile_x; + } + prev_wall_dir = dir; + } + } + + //- Generate vertical walls + for (i32 tile_x = 0; tile_x < P_TilesPitch + 1; ++tile_x) + { + i32 wall_start = -1; + WallDir prev_wall_dir = WallDir_None; + for (i32 tile_y = 0; tile_y < P_TilesPitch + 1; ++tile_y) + { + P_TileKind tile = P_TileKind_Empty; + P_TileKind tile_l = P_TileKind_Empty; + if (tile_y >= 0 && tile_y < P_TilesPitch) + { + if (tile_x >= 0 && tile_x < P_TilesPitch) + { + tile = world->tiles[tile_y * (i32)P_TilesPitch + tile_x]; + } + if ((tile_x - 1) >= 0 && (tile_x - 1) < P_TilesPitch) + { + tile_l = world->tiles[tile_y * (i32)P_TilesPitch + (tile_x - 1)]; + } + } + WallDir dir = WallDir_None; + if (tile == P_TileKind_Wall && tile_l != P_TileKind_Wall) + { + dir = WallDir_Left; + } + else if (tile != P_TileKind_Wall && tile_l == P_TileKind_Wall) + { + dir = WallDir_Right; + } + if (dir != prev_wall_dir) + { + if (prev_wall_dir != WallDir_None) + { + GenWall *wall = PushStruct(scratch.arena, GenWall); + ++walls_count; + SllStackPush(first_wall, wall); + wall->dir = prev_wall_dir; + wall->start = VEC2I32(tile_x, wall_start); + wall->end = VEC2I32(tile_x, tile_y); + } + wall_start = tile_y; + } + prev_wall_dir = dir; + } + } + + //- Debug draw walls + { + i64 wall_idx = 0; + for (GenWall *wall = first_wall; wall; wall = wall->next) + { + Vec2 p0 = VEC2(wall->start.x / P_TilesPerMeter - P_WorldPitch / 2, wall->start.y / P_TilesPerMeter - P_WorldPitch / 2); + Vec2 p1 = VEC2(wall->end.x / P_TilesPerMeter - P_WorldPitch / 2, wall->end.y / P_TilesPerMeter - P_WorldPitch / 2); + u64 color_seed0 = MixU64(wall_idx + 1); + u64 color_seed1 = MixU64(color_seed0); + u64 color_seed2 = MixU64(color_seed1); + Vec4 color = Color_White; + color.r = Norm24(color_seed0) * 0.75 + 0.25; + color.g = Norm24(color_seed1) * 0.75 + 0.25; + color.b = Norm24(color_seed2) * 0.75 + 0.25; + P_DebugDrawLine(p0, p1, color); + ++wall_idx; + } + ++wall_idx; + } + } + + + EndScratch(scratch); + return space; +} + +P_SpaceCell P_SpaceCellFromPos(P_Space *space, Vec2 pos) +{ + P_SpaceCell result = Zi; + pos = AddVec2(pos, VEC2(P_WorldPitch / 2.0, P_WorldPitch / 2.0)); + if (pos.x >= 0 && pos.x < P_WorldPitch && pos.y >= 0 && pos.y < P_WorldPitch) + { + i64 cell_idx = FloorF32(pos.y) * P_WorldPitch + FloorF32(pos.x); + result = space->cells[cell_idx]; + } + return result; +} + //////////////////////////////////////////////////////////// //~ List helpers @@ -1561,7 +1770,6 @@ P_Frame *P_PushFrame(P_World *world, P_Frame *src_frame, i64 tick) else { dst = PushStructNoZero(world->frames_arena, P_Constraint); - LogDebugF("RAAAAAAH"); } *dst = *src; P_ConstraintBin *bin = &frame->constraint_bins[src->key.v % frame->constraint_bins_count]; @@ -1817,11 +2025,8 @@ void P_StepFrame(P_Frame *frame) f32 solid_pushout_velocity = TweakFloat("Contact spring pushout", 3, 0, 50); // Gentle params - f32 gentle_pushout_factor = TweakFloat("Gentle pushout factor", 10, 0, 50); - - - - + // f32 gentle_pushout_factor = TweakFloat("Gentle pushout factor", 10, 0, 50); + f32 gentle_pushout_factor = TweakFloat("Gentle pushout factor", 0.1, 0, 50); @@ -1829,14 +2034,19 @@ void P_StepFrame(P_Frame *frame) ////////////////////////////// - //- Generate guy-on-guy constraints + //- Build pre-solve space + + P_Space space = P_SpaceFromFrame(scratch.arena, frame); + + + + ////////////////////////////// + //- Generate guy constraints // TODO: Not like this - - if (!is_predicting) { for (P_Ent *ent0 = P_FirstEnt(frame); !P_IsEntNil(ent0); ent0 = P_NextEnt(ent0)) @@ -1844,131 +2054,304 @@ void P_StepFrame(P_Frame *frame) if (ent0->is_guy) { P_Shape shape0 = P_WorldShapeFromEnt(ent0); - for (P_Ent *ent1 = P_FirstEnt(frame); !P_IsEntNil(ent1); ent1 = P_NextEnt(ent1)) + Rng2 aabb0 = P_BoundingBoxFromShape(shape0); + + Rng2 query_rect = Zi; + query_rect.p0 = FloorVec2(aabb0.p0); + query_rect.p1 = CeilVec2(aabb0.p1); + query_rect.p1.x = MaxF32(query_rect.p1.x, query_rect.p0.x + 1); + query_rect.p1.y = MaxF32(query_rect.p1.y, query_rect.p0.y + 1); + + for (i32 query_y = query_rect.p0.y; query_y < query_rect.p1.y; ++query_y) { - if (ent1->is_guy && ent1->key.v > ent0->key.v) + for (i32 query_x = query_rect.p0.x; query_x < query_rect.p1.x; ++query_x) { - P_Shape shape1 = P_WorldShapeFromEnt(ent1); - - // TODO: World query - P_CollisionResult collision = P_CollisionResultFromShapes(shape0, shape1); - if (collision.collision_points_count > 0) + P_SpaceCell cell = P_SpaceCellFromPos(&space, VEC2(query_x, query_y)); + for (P_SpaceEntry *space_entry = cell.first; space_entry; space_entry = space_entry->next) { - P_ConstraintKey constraint_key = P_ConstraintKeyFromU64s(ent0->key.v, ent1->key.v); - P_Constraint *constraint = P_ConstraintFromKey(frame, constraint_key); - if (constraint->last_touched_tick < frame->tick) + Rng2 aabb1 = P_BoundingBoxFromShape(space_entry->shape); + P_Ent *ent1 = P_EntFromKey(frame, (P_EntKey) { .v = space_entry->shape_id }); + if (!P_MatchEntKey(ent0->key, ent1->key) && IsIntersectingRng2(aabb0, aabb1)) { - if (P_IsConstraintNil(constraint)) + P_Shape shape1 = space_entry->shape; + b32 is_static_collision = P_IsEntNil(ent1); + b32 is_guy_on_guy_collision = ent0->is_guy && ent1->is_guy; + + if (is_static_collision || is_guy_on_guy_collision) { - constraint = P_PushConstraint(frame, constraint_key); - } - - constraint->flags = P_ConstraintFlag_Gentle | P_ConstraintFlag_NoWarmStart; - constraint->last_touched_tick = frame->tick; - constraint->normal = collision.collision_normal; - // constraint->friction = SqrtF32(ent0->friction * ent1->friction); - constraint->friction = 0; - - // TODO: Real masses - f32 inv_m0 = 10; - f32 inv_m1 = 10; - f32 inv_i0 = 0; - f32 inv_i1 = 0; - - // Treat non-predicted guys as infinite-mass - if (is_predicting && ent0 != local_guy) - { - inv_m0 = 0; - } - if (is_predicting && ent1 != local_guy) - { - inv_m1 = 0; - } - - constraint->ent0 = ent0->key; - constraint->ent1 = ent1->key; - // constraint->static_center1 = shape1.center_of_mass; - - constraint->inv_m0 = inv_m0; - constraint->inv_m1 = inv_m1; - constraint->inv_i0 = inv_i0; - constraint->inv_i1 = inv_i1; - - // Delete old contacts that are no longer present - for (i32 contact_point_idx = 0; contact_point_idx < constraint->points_count; ++contact_point_idx) - { - P_ContactPoint *contact = &constraint->points[contact_point_idx]; - u32 id = contact->id; - b32 match = 0; - for (i32 collision_point_idx = 0; collision_point_idx < collision.collision_points_count; ++collision_point_idx) + P_ConstraintKey constraint_key = Zi; { - if (collision.collision_points[collision_point_idx].id == id) + // Deterministic shape ID order for consistent constraint lookup + u64 shape_id0 = ent0->key.v; + u64 shape_id1 = space_entry->shape_id; + if (shape_id0 > shape_id1) { - match = 1; - break; + u64 tmp = shape_id0; + shape_id0 = shape_id1; + shape_id1 = tmp; } + constraint_key = P_ConstraintKeyFromU64s(shape_id0, shape_id1); } - if (!match) + P_Constraint *constraint = P_ConstraintFromKey(frame, constraint_key); + if (constraint->last_touched_tick < frame->tick) { - // Delete contact by replacing with last in array - *contact = constraint->points[constraint->points_count - 1]; - constraint->points_count -= 1; - contact_point_idx -= 1; - } - } - - // Create / update contacts from collision - for (i32 collision_point_idx = 0; collision_point_idx < collision.collision_points_count; ++collision_point_idx) - { - P_CollisionPoint collision_point = collision.collision_points[collision_point_idx]; - - u32 id = collision_point.id; - P_ContactPoint *contact = 0; - { - for (i32 contact_point_idx = 0; contact_point_idx < constraint->points_count; ++contact_point_idx) + P_CollisionResult collision = P_CollisionResultFromShapes(shape0, shape1); + if (collision.collision_points_count > 0) { - P_ContactPoint *tmp = &constraint->points[contact_point_idx]; - if (tmp->id == id) + if (P_IsConstraintNil(constraint)) { - contact = tmp; - break; + constraint = P_PushConstraint(frame, constraint_key); + } + constraint->last_touched_tick = frame->tick; + constraint->normal = collision.collision_normal; + // constraint->friction = SqrtF32(ent0->friction * ent1->friction); + constraint->friction = 0; + + if (is_static_collision) + { + constraint->flags |= P_ConstraintFlag_Solid; + } + else if (is_guy_on_guy_collision) + { + constraint->flags |= P_ConstraintFlag_Gentle; + // constraint->flags |= P_ConstraintFlag_NoWarmStart; + } + + // TODO: Real masses + f32 inv_m0 = 10; + f32 inv_m1 = 10; + f32 inv_i0 = 0; + f32 inv_i1 = 0; + + // Treat statics / non-predicted ents as infinite-mass + if (!ent0->is_guy || (is_predicting && !P_MatchEntKey(ent0->key, local_guy->key))) + { + inv_m0 = 0; + inv_i0 = 0; + } + if (!ent1->is_guy || (is_predicting && !P_MatchEntKey(ent1->key, local_guy->key))) + { + inv_m1 = 0; + inv_i1 = 0; + } + + constraint->ent0 = ent0->key; + constraint->ent1 = ent1->key; + constraint->static_center0 = shape0.center_of_mass; + constraint->static_center1 = shape1.center_of_mass; + + constraint->inv_m0 = inv_m0; + constraint->inv_m1 = inv_m1; + constraint->inv_i0 = inv_i0; + constraint->inv_i1 = inv_i1; + + // Delete old contacts that are no longer present + for (i32 contact_point_idx = 0; contact_point_idx < constraint->points_count; ++contact_point_idx) + { + P_ContactPoint *contact = &constraint->points[contact_point_idx]; + u32 id = contact->id; + b32 match = 0; + for (i32 collision_point_idx = 0; collision_point_idx < collision.collision_points_count; ++collision_point_idx) + { + if (collision.collision_points[collision_point_idx].id == id) + { + match = 1; + break; + } + } + if (!match) + { + // Delete contact by replacing with last in array + *contact = constraint->points[constraint->points_count - 1]; + constraint->points_count -= 1; + contact_point_idx -= 1; + } + } + + // Create / update contacts from collision + for (i32 collision_point_idx = 0; collision_point_idx < collision.collision_points_count; ++collision_point_idx) + { + P_CollisionPoint collision_point = collision.collision_points[collision_point_idx]; + + u32 id = collision_point.id; + P_ContactPoint *contact = 0; + { + for (i32 contact_point_idx = 0; contact_point_idx < constraint->points_count; ++contact_point_idx) + { + P_ContactPoint *tmp = &constraint->points[contact_point_idx]; + if (tmp->id == id) + { + contact = tmp; + break; + } + } + if (!contact) + { + contact = &constraint->points[constraint->points_count]; + constraint->points_count += 1; + ZeroStruct(contact); + } + } + contact->id = id; + + Vec2 vcp0 = SubVec2(collision_point.p, shape0.center_of_mass); + Vec2 vcp1 = SubVec2(collision_point.p, shape1.center_of_mass); + + contact->vcp0 = vcp0; + contact->vcp1 = vcp1; + contact->starting_separation = collision_point.separation; + + // Debug draw + // { + // // P_Ent *ent0 = P_EntFromKey(frame, constraint->ent0); + // // P_Ent *ent1 = P_EntFromKey(frame, constraint->ent1); + // Vec2 normal = constraint->normal; + // Vec2 center0 = Zi; + // Vec2 center1 = Zi; + // if (!P_IsEntNil(ent0)) center0 = P_WorldShapeFromEnt(ent0).center_of_mass; + // if (!P_IsEntNil(ent1)) center1 = P_WorldShapeFromEnt(ent1).center_of_mass; + // Vec2 p0 = AddVec2(center0, vcp0); + // Vec2 p1 = AddVec2(center1, vcp1); + // P_DebugDrawPoint(p0, Color_Cyan); + // P_DebugDrawLine(p0, AddVec2(p0, normal), Color_White); + // } } } - if (!contact) - { - contact = &constraint->points[constraint->points_count]; - constraint->points_count += 1; - ZeroStruct(contact); - } } - contact->id = id; - - Vec2 vcp0 = SubVec2(collision_point.p, shape0.center_of_mass); - Vec2 vcp1 = SubVec2(collision_point.p, shape1.center_of_mass); - - contact->vcp0 = vcp0; - contact->vcp1 = vcp1; - contact->starting_separation = collision_point.separation; - - // Debug draw - // { - // // P_Ent *ent0 = P_EntFromKey(frame, constraint->ent0); - // // P_Ent *ent1 = P_EntFromKey(frame, constraint->ent1); - // Vec2 normal = constraint->normal; - // Vec2 center0 = Zi; - // Vec2 center1 = Zi; - // if (!P_IsEntNil(ent0)) center0 = P_WorldShapeFromEnt(ent0).center_of_mass; - // if (!P_IsEntNil(ent1)) center1 = P_WorldShapeFromEnt(ent1).center_of_mass; - // Vec2 p0 = AddVec2(center0, vcp0); - // Vec2 p1 = AddVec2(center1, vcp1); - // P_DebugDrawPoint(p0, Color_Cyan); - // P_DebugDrawLine(p0, AddVec2(p0, normal), Color_White); - // } } } } } } + + + + + // for (P_Ent *ent1 = P_FirstEnt(frame); !P_IsEntNil(ent1); ent1 = P_NextEnt(ent1)) + // { + // if (ent1->is_guy && ent1->key.v > ent0->key.v) + // { + // P_Shape shape1 = P_WorldShapeFromEnt(ent1); + + // // TODO: World query + // P_CollisionResult collision = P_CollisionResultFromShapes(shape0, shape1); + // if (collision.collision_points_count > 0) + // { + // P_ConstraintKey constraint_key = P_ConstraintKeyFromU64s(ent0->key.v, ent1->key.v); + // P_Constraint *constraint = P_ConstraintFromKey(frame, constraint_key); + // if (constraint->last_touched_tick < frame->tick) + // { + // if (P_IsConstraintNil(constraint)) + // { + // constraint = P_PushConstraint(frame, constraint_key); + // } + + // constraint->flags = P_ConstraintFlag_Gentle | P_ConstraintFlag_NoWarmStart; + // constraint->last_touched_tick = frame->tick; + // constraint->normal = collision.collision_normal; + // // constraint->friction = SqrtF32(ent0->friction * ent1->friction); + // constraint->friction = 0; + + // // TODO: Real masses + // f32 inv_m0 = 10; + // f32 inv_m1 = 10; + // f32 inv_i0 = 0; + // f32 inv_i1 = 0; + + // // Treat non-predicted guys as infinite-mass + // if (is_predicting && ent0 != local_guy) + // { + // inv_m0 = 0; + // } + // if (is_predicting && ent1 != local_guy) + // { + // inv_m1 = 0; + // } + + // constraint->ent0 = ent0->key; + // constraint->ent1 = ent1->key; + // // constraint->static_center1 = shape1.center_of_mass; + + // constraint->inv_m0 = inv_m0; + // constraint->inv_m1 = inv_m1; + // constraint->inv_i0 = inv_i0; + // constraint->inv_i1 = inv_i1; + + // // Delete old contacts that are no longer present + // for (i32 contact_point_idx = 0; contact_point_idx < constraint->points_count; ++contact_point_idx) + // { + // P_ContactPoint *contact = &constraint->points[contact_point_idx]; + // u32 id = contact->id; + // b32 match = 0; + // for (i32 collision_point_idx = 0; collision_point_idx < collision.collision_points_count; ++collision_point_idx) + // { + // if (collision.collision_points[collision_point_idx].id == id) + // { + // match = 1; + // break; + // } + // } + // if (!match) + // { + // // Delete contact by replacing with last in array + // *contact = constraint->points[constraint->points_count - 1]; + // constraint->points_count -= 1; + // contact_point_idx -= 1; + // } + // } + + // // Create / update contacts from collision + // for (i32 collision_point_idx = 0; collision_point_idx < collision.collision_points_count; ++collision_point_idx) + // { + // P_CollisionPoint collision_point = collision.collision_points[collision_point_idx]; + + // u32 id = collision_point.id; + // P_ContactPoint *contact = 0; + // { + // for (i32 contact_point_idx = 0; contact_point_idx < constraint->points_count; ++contact_point_idx) + // { + // P_ContactPoint *tmp = &constraint->points[contact_point_idx]; + // if (tmp->id == id) + // { + // contact = tmp; + // break; + // } + // } + // if (!contact) + // { + // contact = &constraint->points[constraint->points_count]; + // constraint->points_count += 1; + // ZeroStruct(contact); + // } + // } + // contact->id = id; + + // Vec2 vcp0 = SubVec2(collision_point.p, shape0.center_of_mass); + // Vec2 vcp1 = SubVec2(collision_point.p, shape1.center_of_mass); + + // contact->vcp0 = vcp0; + // contact->vcp1 = vcp1; + // contact->starting_separation = collision_point.separation; + + // // Debug draw + // // { + // // // P_Ent *ent0 = P_EntFromKey(frame, constraint->ent0); + // // // P_Ent *ent1 = P_EntFromKey(frame, constraint->ent1); + // // Vec2 normal = constraint->normal; + // // Vec2 center0 = Zi; + // // Vec2 center1 = Zi; + // // if (!P_IsEntNil(ent0)) center0 = P_WorldShapeFromEnt(ent0).center_of_mass; + // // if (!P_IsEntNil(ent1)) center1 = P_WorldShapeFromEnt(ent1).center_of_mass; + // // Vec2 p0 = AddVec2(center0, vcp0); + // // Vec2 p1 = AddVec2(center1, vcp1); + // // P_DebugDrawPoint(p0, Color_Cyan); + // // P_DebugDrawLine(p0, AddVec2(p0, normal), Color_White); + // // } + // } + // } + // } + // } + // } } } } @@ -1992,7 +2375,9 @@ void P_StepFrame(P_Frame *frame) - // // TODO: Not like this + // TODO: Not like this + + // for (P_Ent *ent0 = P_FirstEnt(frame); !P_IsEntNil(ent0); ent0 = P_NextEnt(ent0)) // { @@ -2001,9 +2386,9 @@ void P_StepFrame(P_Frame *frame) // P_Shape shape0 = P_WorldShapeFromEnt(ent0); // Rng2 aabb = P_BoundingBoxFromShape(shape0); - // P_Query collisions = P_QueryFromRect(scratch.arena, aabb, P_QueryFlag_IncludeWalls); + // P_Query query = P_QueryFromRect(scratch.arena, aabb, P_QueryFlag_IncludeWalls); - // for (P_QueryItem *item = collisions.first; item; item = item->next) + // for (P_QueryItem *item = query.first; item; item = item->next) // { // P_Shape shape1 = item->shape; @@ -2427,6 +2812,8 @@ void P_StepFrame(P_Frame *frame) ////////////////////////////// //- Solve constraints + // TODO: Solve wall constraints last + for (P_Constraint *constraint = P_FirstConstraint(frame); !P_IsConstraintNil(constraint); constraint = P_NextConstraint(constraint)) { P_Ent *ent0 = P_EntFromKey(frame, constraint->ent0); diff --git a/src/pp/pp.h b/src/pp/pp.h index 3b066d36..8ba890fd 100644 --- a/src/pp/pp.h +++ b/src/pp/pp.h @@ -247,6 +247,26 @@ Struct(P_ConstraintBin) P_Constraint *last; }; +//////////////////////////////////////////////////////////// +//~ Space types + +Struct(P_SpaceEntry) +{ + P_SpaceEntry *next; + P_Shape shape; + u64 shape_id; +}; + +Struct(P_SpaceCell) +{ + P_SpaceEntry *first; +}; + +Struct(P_Space) +{ + P_SpaceCell *cells; +}; + //////////////////////////////////////////////////////////// //~ World types @@ -577,6 +597,12 @@ P_Ent *P_NextEnt(P_Ent *e); P_Constraint *P_FirstConstraint(P_Frame *frame); P_Constraint *P_NextConstraint(P_Constraint *c); +//////////////////////////////////////////////////////////// +//~ Space + +P_Space P_SpaceFromFrame(Arena *arena, P_Frame *frame); +P_SpaceCell P_SpaceCellFromPos(P_Space *space, Vec2 pos); + //////////////////////////////////////////////////////////// //~ List helpers diff --git a/src/pp/pp_sim/pp_sim_core.c b/src/pp/pp_sim/pp_sim_core.c index 7f05af57..7b94cfeb 100644 --- a/src/pp/pp_sim/pp_sim_core.c +++ b/src/pp/pp_sim/pp_sim_core.c @@ -88,7 +88,7 @@ void S_TickForever(WaveLaneCtx *lane) while (!shutdown) { shutdown = Atomic32Fetch(&S.shutdown); - P_tl.debug_draw_enabled = TweakBool("Simulation debug draw", 0); + P_tl.debug_draw_enabled = TweakBool("Simulation debug draw", 1); ResetArena(frame_arena); ////////////////////////////// diff --git a/src/pp/pp_vis/pp_vis_gpu.g b/src/pp/pp_vis/pp_vis_gpu.g index ac9c2000..bf9cc4e1 100644 --- a/src/pp/pp_vis/pp_vis_gpu.g +++ b/src/pp/pp_vis/pp_vis_gpu.g @@ -126,8 +126,6 @@ PixelShader(V_QuadPS, V_QuadPSOutput, V_QuadPSInput input) ////////////////////////////// //- Particle emitter shader -// TODO: Initialize particles in per-particle-sim-thread rather than sequentially in emitter thread - ComputeShader(V_EmitParticlesCS, 64) { V_SharedFrame frame = G_Dereference(V_ShaderConst_Frame)[0]; @@ -138,9 +136,9 @@ ComputeShader(V_EmitParticlesCS, 64) if (emitter_idx < frame.emitters_count) { V_Emitter emitter = emitters[emitter_idx]; - for (u32 i = 0; i < emitter.count; ++i) + for (u32 emitter_particle_idx = 0; emitter_particle_idx < emitter.count; ++emitter_particle_idx) { - u32 particle_seq = emitter.first_particle_seq + i; + u32 particle_seq = emitter.first_particle_seq + emitter_particle_idx; u32 particle_idx = particle_seq % (u32)V_ParticlesCap; particles[particle_idx].exists = 1; particles[particle_idx].emitter_init_num = emitter_idx + 1;