generate walls space separately during bake rather than every frame

This commit is contained in:
jacob 2026-02-09 18:03:48 -06:00
parent ffa3378a54
commit de86e12ba0
2 changed files with 306 additions and 278 deletions

View File

@ -1196,7 +1196,7 @@ P_Constraint *P_NextConstraint(P_Constraint *c)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Space //~ Space
P_Space P_SpaceFromFrame(Arena *arena, P_Frame *frame) P_Space P_SpaceFromEnts(Arena *arena, P_Frame *frame)
{ {
P_Space space = Zi; P_Space space = Zi;
TempArena scratch = BeginScratch(arena); TempArena scratch = BeginScratch(arena);
@ -1241,163 +1241,168 @@ P_Space P_SpaceFromFrame(Arena *arena, P_Frame *frame)
} }
} }
//- Generate wall shapes from tiles EndScratch(scratch);
// TODO: Cache walls in separate space return space;
}
P_Space P_SpaceFromWalls(Arena *arena, P_Frame *frame)
{
P_Space space = Zi;
TempArena scratch = BeginScratch(arena);
P_World *world = frame->world;
space.dims = VEC2I32(P_WorldPitch, P_WorldPitch);
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)
);
Enum(WallDir)
{ {
Enum(WallDir) WallDir_None,
{ WallDir_Up,
WallDir_None, WallDir_Right,
WallDir_Up, WallDir_Down,
WallDir_Right, WallDir_Left,
WallDir_Down, };
WallDir_Left,
};
Struct(GenWall) Struct(GenWall)
{ {
GenWall *next; GenWall *next;
WallDir dir; WallDir dir;
Vec2I32 start; Vec2I32 start;
Vec2I32 end; Vec2I32 end;
}; };
i64 walls_count = 0; i64 walls_count = 0;
GenWall *first_wall = 0; GenWall *first_wall = 0;
//- Generate horizontal walls
for (i32 tile_y = 0; tile_y < P_TilesPitch + 1; ++tile_y)
{
i32 wall_start = -1;
// FIXME: Iterate to pitch + 1 WallDir prev_wall_dir = WallDir_None;
//- 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) for (i32 tile_x = 0; tile_x < P_TilesPitch + 1; ++tile_x)
{ {
i32 wall_start = -1; P_TileKind tile = P_TileKind_Empty;
WallDir prev_wall_dir = WallDir_None; P_TileKind tile_t = P_TileKind_Empty;
for (i32 tile_y = 0; tile_y < P_TilesPitch + 1; ++tile_y) if (tile_x >= 0 && tile_x < P_TilesPitch)
{ {
P_TileKind tile = P_TileKind_Empty;
P_TileKind tile_l = P_TileKind_Empty;
if (tile_y >= 0 && tile_y < P_TilesPitch) 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];
{
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_y - 1) >= 0 && (tile_y - 1) < P_TilesPitch)
if (tile == P_TileKind_Wall && tile_l != P_TileKind_Wall)
{ {
dir = WallDir_Left; tile_t = world->tiles[(tile_y - 1) * (i32)P_TilesPitch + tile_x];
} }
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;
} }
} WallDir dir = WallDir_None;
if (tile == P_TileKind_Wall && tile_t != P_TileKind_Wall)
//- Push walls to space
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);
P_Shape shape = P_ShapeFromDesc(.count = 2, .points = { p0, p1 }, .radius = 0.01 );
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);
u64 id = P_WallShapeIDBasis ^ MixU64s(
((u64)wall->start.x << 0) | ((u64)wall->start.y << 32),
((u64)wall->end.x << 0) | ((u64)wall->end.y << 32)
);
for (i32 y = aabb.p0.y; y < aabb.p1.y; ++y)
{ {
for (i32 x = aabb.p0.x; x < aabb.p1.x; ++x) dir = WallDir_Up;
{
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 = id;
entry->dir.x = (wall->dir == WallDir_Right) + ((wall->dir == WallDir_Left) * -1);
entry->dir.y = (wall->dir == WallDir_Down) + ((wall->dir == WallDir_Up) * -1);
}
} }
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;
}
}
//- Push walls to space
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);
P_Shape shape = P_ShapeFromDesc(.count = 2, .points = { p0, p1 }, .radius = 0.01 );
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);
u64 id = P_WallShapeIDBasis ^ MixU64s(
((u64)wall->start.x << 0) | ((u64)wall->start.y << 32),
((u64)wall->end.x << 0) | ((u64)wall->end.y << 32)
);
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 = id;
entry->dir.x = (wall->dir == WallDir_Right) + ((wall->dir == WallDir_Left) * -1);
entry->dir.y = (wall->dir == WallDir_Down) + ((wall->dir == WallDir_Up) * -1);
}
}
}
EndScratch(scratch); EndScratch(scratch);
return space; return space;
@ -1407,7 +1412,7 @@ P_SpaceCell P_SpaceCellFromPos(P_Space *space, Vec2 pos)
{ {
P_SpaceCell result = Zi; P_SpaceCell result = Zi;
pos = AddVec2(pos, VEC2(P_WorldPitch / 2.0, P_WorldPitch / 2.0)); 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) if (pos.x >= 0 && pos.x < space->dims.x && pos.y >= 0 && pos.y < space->dims.y)
{ {
i64 cell_idx = FloorF32(pos.y) * P_WorldPitch + FloorF32(pos.x); i64 cell_idx = FloorF32(pos.y) * P_WorldPitch + FloorF32(pos.x);
result = space->cells[cell_idx]; result = space->cells[cell_idx];
@ -1562,7 +1567,7 @@ P_World *P_AcquireWorld(void)
world->arena = arena; world->arena = arena;
} }
world->frames_arena = AcquireArena(Gibi(64)); world->frames_arena = AcquireArena(Gibi(64));
world->statics_arena = AcquireArena(Gibi(64)); world->bake_arena = AcquireArena(Gibi(64));
world->first_frame = &P_NilFrame; world->first_frame = &P_NilFrame;
world->last_frame = &P_NilFrame; world->last_frame = &P_NilFrame;
@ -2044,13 +2049,23 @@ void P_StepFrame(P_Frame *frame)
//////////////////////////////
//- Bake world
{
u64 desired_bake_hash = world->tiles_hash;
if (desired_bake_hash != world->baked_hash)
{
ResetArena(world->bake_arena);
world->walls_space = P_SpaceFromWalls(world->bake_arena, frame);
world->baked_hash = desired_bake_hash;
}
}
////////////////////////////// //////////////////////////////
//- Build pre-solve space //- Build pre-solve ents space
P_Space space = P_SpaceFromFrame(scratch.arena, frame);
P_Space ents_space = P_SpaceFromEnts(scratch.arena, frame);
////////////////////////////// //////////////////////////////
@ -2077,165 +2092,172 @@ void P_StepFrame(P_Frame *frame)
{ {
for (i32 query_x = query_rect.p0.x; query_x < query_rect.p1.x; ++query_x) for (i32 query_x = query_rect.p0.x; query_x < query_rect.p1.x; ++query_x)
{ {
P_SpaceCell cell = P_SpaceCellFromPos(&space, VEC2(query_x, query_y)); P_SpaceCell cells[] = {
for (P_SpaceEntry *space_entry = cell.first; space_entry; space_entry = space_entry->next) P_SpaceCellFromPos(&ents_space, VEC2(query_x, query_y)),
P_SpaceCellFromPos(&world->walls_space, VEC2(query_x, query_y)),
};
for (i64 cell_idx = 0; cell_idx < countof(cells); ++cell_idx)
{ {
Rng2 aabb1 = P_BoundingBoxFromShape(space_entry->shape); P_SpaceCell cell = cells[cell_idx];
P_Ent *ent1 = P_EntFromKey(frame, (P_EntKey) { .v = space_entry->shape_id }); for (P_SpaceEntry *space_entry = cell.first; space_entry; space_entry = space_entry->next)
if (!P_MatchEntKey(ent0->key, ent1->key) && IsIntersectingRng2(aabb0, aabb1))
{ {
P_Shape shape1 = space_entry->shape; Rng2 aabb1 = P_BoundingBoxFromShape(space_entry->shape);
b32 is_static_collision = P_IsEntNil(ent1); P_Ent *ent1 = P_EntFromKey(frame, (P_EntKey) { .v = space_entry->shape_id });
b32 is_guy_on_guy_collision = ent0->is_guy && ent1->is_guy; if (!P_MatchEntKey(ent0->key, ent1->key) && IsIntersectingRng2(aabb0, aabb1))
if (is_static_collision || is_guy_on_guy_collision)
{ {
P_ConstraintKey constraint_key = Zi; 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)
{ {
// Deterministic shape ID order for consistent constraint lookup P_ConstraintKey constraint_key = Zi;
u64 shape_id0 = ent0->key.v;
u64 shape_id1 = space_entry->shape_id;
if (shape_id0 > shape_id1)
{ {
u64 tmp = shape_id0; // Deterministic shape ID order for consistent constraint lookup
shape_id0 = shape_id1; u64 shape_id0 = ent0->key.v;
shape_id1 = tmp; u64 shape_id1 = space_entry->shape_id;
if (shape_id0 > shape_id1)
{
u64 tmp = shape_id0;
shape_id0 = shape_id1;
shape_id1 = tmp;
}
constraint_key = P_ConstraintKeyFromU64s(shape_id0, shape_id1);
} }
constraint_key = P_ConstraintKeyFromU64s(shape_id0, shape_id1); P_Constraint *constraint = P_ConstraintFromKey(frame, constraint_key);
} if (constraint->last_touched_tick < frame->tick)
P_Constraint *constraint = P_ConstraintFromKey(frame, constraint_key);
if (constraint->last_touched_tick < frame->tick)
{
P_CollisionResult collision = P_CollisionResultFromShapes(shape0, shape1);
b32 skip_collision = 0;
skip_collision = skip_collision || collision.collision_points_count <= 0;
if (!skip_collision && !IsVec2Zero(space_entry->dir))
{ {
// Skip collision if normal violates one-way direction P_CollisionResult collision = P_CollisionResultFromShapes(shape0, shape1);
f32 threshold = 0.5;
skip_collision = DotVec2(space_entry->dir, collision.collision_normal) >= threshold;
}
if (!skip_collision) b32 skip_collision = 0;
{ skip_collision = skip_collision || collision.collision_points_count <= 0;
if (P_IsConstraintNil(constraint)) if (!skip_collision && !IsVec2Zero(space_entry->dir))
{ {
constraint = P_PushConstraint(frame, constraint_key); // Skip collision if normal violates one-way direction
} f32 threshold = 0.5;
constraint->last_touched_tick = frame->tick; skip_collision = DotVec2(space_entry->dir, collision.collision_normal) >= threshold;
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 if (!skip_collision)
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; if (P_IsConstraintNil(constraint))
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) constraint = P_PushConstraint(frame, constraint_key);
{
match = 1;
break;
}
} }
if (!match) 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)
{ {
// Delete contact by replacing with last in array constraint->flags |= P_ConstraintFlag_Solid;
*contact = constraint->points[constraint->points_count - 1];
constraint->points_count -= 1;
contact_point_idx -= 1;
} }
} else if (is_guy_on_guy_collision)
// 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) 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)
{ {
P_ContactPoint *tmp = &constraint->points[contact_point_idx]; if (collision.collision_points[collision_point_idx].id == id)
if (tmp->id == id)
{ {
contact = tmp; match = 1;
break; break;
} }
} }
if (!contact) if (!match)
{ {
contact = &constraint->points[constraint->points_count]; // Delete contact by replacing with last in array
constraint->points_count += 1; *contact = constraint->points[constraint->points_count - 1];
ZeroStruct(contact); constraint->points_count -= 1;
contact_point_idx -= 1;
} }
} }
contact->id = id;
Vec2 vcp0 = SubVec2(collision_point.p, shape0.center_of_mass); // Create / update contacts from collision
Vec2 vcp1 = SubVec2(collision_point.p, shape1.center_of_mass); 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];
contact->vcp0 = vcp0; u32 id = collision_point.id;
contact->vcp1 = vcp1; P_ContactPoint *contact = 0;
contact->starting_separation = collision_point.separation; {
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;
// Debug draw Vec2 vcp0 = SubVec2(collision_point.p, shape0.center_of_mass);
// { Vec2 vcp1 = SubVec2(collision_point.p, shape1.center_of_mass);
// // P_Ent *ent0 = P_EntFromKey(frame, constraint->ent0);
// // P_Ent *ent1 = P_EntFromKey(frame, constraint->ent1); contact->vcp0 = vcp0;
// Vec2 normal = constraint->normal; contact->vcp1 = vcp1;
// Vec2 center0 = Zi; contact->starting_separation = collision_point.separation;
// Vec2 center1 = Zi;
// if (!P_IsEntNil(ent0)) center0 = P_WorldShapeFromEnt(ent0).center_of_mass; // Debug draw
// if (!P_IsEntNil(ent1)) center1 = P_WorldShapeFromEnt(ent1).center_of_mass; // {
// Vec2 p0 = AddVec2(center0, vcp0); // // P_Ent *ent0 = P_EntFromKey(frame, constraint->ent0);
// Vec2 p1 = AddVec2(center1, vcp1); // // P_Ent *ent1 = P_EntFromKey(frame, constraint->ent1);
// P_DebugDrawPoint(p0, Color_Cyan); // Vec2 normal = constraint->normal;
// P_DebugDrawLine(p0, AddVec2(p0, normal), Color_White); // 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);
// }
}
} }
} }
} }

View File

@ -267,6 +267,7 @@ Struct(P_SpaceCell)
Struct(P_Space) Struct(P_Space)
{ {
Vec2I32 dims;
P_SpaceCell *cells; P_SpaceCell *cells;
}; };
@ -330,7 +331,6 @@ Struct(P_World)
{ {
Arena *arena; Arena *arena;
Arena *frames_arena; Arena *frames_arena;
Arena *statics_arena;
u64 seed; u64 seed;
RandState rand; RandState rand;
@ -344,6 +344,11 @@ Struct(P_World)
i64 frame_bins_count; i64 frame_bins_count;
P_FrameBin *frame_bins; P_FrameBin *frame_bins;
//- Baked data
Arena *bake_arena;
P_Space walls_space;
u64 baked_hash;
u64 tiles_hash; u64 tiles_hash;
u8 *tiles; u8 *tiles;
}; };
@ -603,7 +608,8 @@ P_Constraint *P_NextConstraint(P_Constraint *c);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Space //~ Space
P_Space P_SpaceFromFrame(Arena *arena, P_Frame *frame); P_Space P_SpaceFromEnts(Arena *arena, P_Frame *frame);
P_Space P_SpaceFromWalls(Arena *arena, P_Frame *frame);
P_SpaceCell P_SpaceCellFromPos(P_Space *space, Vec2 pos); P_SpaceCell P_SpaceCellFromPos(P_Space *space, Vec2 pos);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////