tile -> wall generation

This commit is contained in:
jacob 2026-02-09 16:56:35 -06:00
parent b7f2c3d185
commit bf56bd7155
6 changed files with 545 additions and 122 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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