generate walls space separately during bake rather than every frame
This commit is contained in:
parent
ffa3378a54
commit
de86e12ba0
574
src/pp/pp.c
574
src/pp/pp.c
@ -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);
|
||||||
|
// }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
10
src/pp/pp.h
10
src/pp/pp.h
@ -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);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user