summaryrefslogtreecommitdiffstats
path: root/src/core/Collision.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/Collision.cpp')
-rw-r--r--src/core/Collision.cpp233
1 files changed, 137 insertions, 96 deletions
diff --git a/src/core/Collision.cpp b/src/core/Collision.cpp
index 23eaa8dd..99be816f 100644
--- a/src/core/Collision.cpp
+++ b/src/core/Collision.cpp
@@ -38,7 +38,7 @@ void
CCollision::Init(void)
{
ms_colModelCache.Init(NUMCOLCACHELINKS);
- ms_collisionInMemory = LEVEL_NONE;
+ ms_collisionInMemory = LEVEL_GENERIC;
}
void
@@ -59,7 +59,7 @@ CCollision::Update(void)
return;
// hardcode a level if there are no zones
- if(level == LEVEL_NONE){
+ if(level == LEVEL_GENERIC){
if(CGame::currLevel == LEVEL_INDUSTRIAL &&
playerCoors.x < 400.0f){
level = LEVEL_COMMERCIAL;
@@ -78,7 +78,7 @@ CCollision::Update(void)
}
}
}
- if(level != LEVEL_NONE && level != CGame::currLevel)
+ if(level != LEVEL_GENERIC && level != CGame::currLevel)
CGame::currLevel = level;
if(ms_collisionInMemory != CGame::currLevel)
LoadCollisionWhenINeedIt(forceLevelChange);
@@ -95,10 +95,10 @@ GetCollisionInSectorList(CPtrList &list)
for(node = list.first; node; node = node->next){
e = (CEntity*)node->item;
level = CModelInfo::GetModelInfo(e->GetModelIndex())->GetColModel()->level;
- if(level != LEVEL_NONE)
+ if(level != LEVEL_GENERIC)
return (eLevelName)level;
}
- return LEVEL_NONE;
+ return LEVEL_GENERIC;
}
// Get a level this sector is in based on collision models
@@ -108,15 +108,15 @@ GetCollisionInSector(CSector &sect)
int level;
level = GetCollisionInSectorList(sect.m_lists[ENTITYLIST_BUILDINGS]);
- if(level == LEVEL_NONE)
+ if(level == LEVEL_GENERIC)
level = GetCollisionInSectorList(sect.m_lists[ENTITYLIST_BUILDINGS_OVERLAP]);
- if(level == LEVEL_NONE)
+ if(level == LEVEL_GENERIC)
level = GetCollisionInSectorList(sect.m_lists[ENTITYLIST_OBJECTS]);
- if(level == LEVEL_NONE)
+ if(level == LEVEL_GENERIC)
level = GetCollisionInSectorList(sect.m_lists[ENTITYLIST_OBJECTS_OVERLAP]);
- if(level == LEVEL_NONE)
+ if(level == LEVEL_GENERIC)
level = GetCollisionInSectorList(sect.m_lists[ENTITYLIST_DUMMIES]);
- if(level == LEVEL_NONE)
+ if(level == LEVEL_GENERIC)
level = GetCollisionInSectorList(sect.m_lists[ENTITYLIST_DUMMIES_OVERLAP]);
return (eLevelName)level;
}
@@ -133,7 +133,7 @@ CCollision::LoadCollisionWhenINeedIt(bool forceChange)
int xmin, xmax, ymin, ymax;
int x, y;
- level = LEVEL_NONE;
+ level = LEVEL_GENERIC;
playerCoors = FindPlayerCoors();
sx = CWorld::GetSectorIndexX(playerCoors.x);
@@ -161,8 +161,8 @@ CCollision::LoadCollisionWhenINeedIt(bool forceChange)
for(x = xmin; x <= xmax; x++)
for(y = ymin; y <= ymax; y++){
l = GetCollisionInSector(*CWorld::GetSector(x, y));
- if(l != LEVEL_NONE){
- if(level == LEVEL_NONE)
+ if(l != LEVEL_GENERIC){
+ if(level == LEVEL_GENERIC)
level = l;
if(level != l)
multipleLevels = true;
@@ -173,19 +173,23 @@ CCollision::LoadCollisionWhenINeedIt(bool forceChange)
if(multipleLevels && veh && veh->IsBoat())
for(ei = veh->m_entryInfoList.first; ei; ei = ei->next){
level = GetCollisionInSector(*ei->sector);
- if(level != LEVEL_NONE)
+ if(level != LEVEL_GENERIC)
break;
}
}
if(level == CGame::currLevel || forceChange){
CTimer::Stop();
+#ifndef NO_ISLAND_LOADING
DMAudio.SetEffectsFadeVol(0);
CPad::StopPadsShaking();
LoadCollisionScreen(CGame::currLevel);
DMAudio.Service();
+#endif
CPopulation::DealWithZoneChange(ms_collisionInMemory, CGame::currLevel, false);
+
+#ifndef NO_ISLAND_LOADING
CStreaming::RemoveIslandsNotUsed(LEVEL_INDUSTRIAL);
CStreaming::RemoveIslandsNotUsed(LEVEL_COMMERCIAL);
CStreaming::RemoveIslandsNotUsed(LEVEL_SUBURBAN);
@@ -196,19 +200,27 @@ CCollision::LoadCollisionWhenINeedIt(bool forceChange)
CStreaming::RemoveUnusedModelsInLoadedList();
CGame::TidyUpMemory(true, true);
CFileLoader::LoadCollisionFromDatFile(CGame::currLevel);
+#endif
+
ms_collisionInMemory = CGame::currLevel;
CReplay::EmptyReplayBuffer();
- if(CGame::currLevel != LEVEL_NONE)
+#ifndef NO_ISLAND_LOADING
+ if(CGame::currLevel != LEVEL_GENERIC)
LoadSplash(GetLevelSplashScreen(CGame::currLevel));
CStreaming::RemoveUnusedBigBuildings(CGame::currLevel);
CStreaming::RemoveUnusedBuildings(CGame::currLevel);
CStreaming::RequestBigBuildings(CGame::currLevel);
+#endif
CStreaming::LoadAllRequestedModels(true);
+#ifndef NO_ISLAND_LOADING
CStreaming::HaveAllBigBuildingsLoaded(CGame::currLevel);
CGame::TidyUpMemory(true, true);
+#endif
CTimer::Update();
+#ifndef NO_ISLAND_LOADING
DMAudio.SetEffectsFadeVol(127);
+#endif
}
}
@@ -217,10 +229,23 @@ CCollision::SortOutCollisionAfterLoad(void)
{
if(ms_collisionInMemory == CGame::currLevel)
return;
-
+#ifndef NO_ISLAND_LOADING
CModelInfo::RemoveColModelsFromOtherLevels(CGame::currLevel);
- if(CGame::currLevel != LEVEL_NONE){
+#endif
+ if (CGame::currLevel != LEVEL_GENERIC) {
+#ifdef NO_ISLAND_LOADING
+ static bool bAlreadyLoaded = false;
+ if (bAlreadyLoaded) {
+ ms_collisionInMemory = CGame::currLevel;
+ return;
+ }
+ bAlreadyLoaded = true;
+ CFileLoader::LoadCollisionFromDatFile(LEVEL_INDUSTRIAL);
+ CFileLoader::LoadCollisionFromDatFile(LEVEL_COMMERCIAL);
+ CFileLoader::LoadCollisionFromDatFile(LEVEL_SUBURBAN);
+#else
CFileLoader::LoadCollisionFromDatFile(CGame::currLevel);
+#endif
if(!CGame::playingIntro)
LoadSplash(GetLevelSplashScreen(CGame::currLevel));
}
@@ -370,7 +395,7 @@ CCollision::TestVerticalLineBox(const CColLine &line, const CColBox &box)
}
bool
-CCollision::TestLineTriangle(const CColLine &line, const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane)
+CCollision::TestLineTriangle(const CColLine &line, const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane)
{
float t;
CVector normal;
@@ -385,9 +410,9 @@ CCollision::TestLineTriangle(const CColLine &line, const CVector *verts, const C
// find point of intersection
CVector p = line.p0 + (line.p1-line.p0)*t;
- const CVector &va = verts[tri.a];
- const CVector &vb = verts[tri.b];
- const CVector &vc = verts[tri.c];
+ const CVector &va = verts[tri.a].Get();
+ const CVector &vb = verts[tri.b].Get();
+ const CVector &vc = verts[tri.c].Get();
CVector2D vec1, vec2, vec3, vect;
// We do the test in 2D. With the plane direction we
@@ -480,15 +505,16 @@ CCollision::TestLineSphere(const CColLine &line, const CColSphere &sph)
bool
CCollision::TestSphereTriangle(const CColSphere &sphere,
- const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane)
+ const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane)
{
// If sphere and plane don't intersect, no collision
- if(Abs(plane.CalcPoint(sphere.center)) > sphere.radius)
+ float planedist = plane.CalcPoint(sphere.center);
+ if(Abs(planedist) > sphere.radius)
return false;
- const CVector &va = verts[tri.a];
- const CVector &vb = verts[tri.b];
- const CVector &vc = verts[tri.c];
+ const CVector &va = verts[tri.a].Get();
+ const CVector &vb = verts[tri.b].Get();
+ const CVector &vc = verts[tri.c].Get();
// calculate two orthogonal basis vectors for the triangle
CVector vec2 = vb - va;
@@ -512,23 +538,29 @@ CCollision::TestSphereTriangle(const CColSphere &sphere,
int testcase = insideAB + insideAC + insideBC;
float dist = 0.0f;
- if(testcase == 1){
+ switch(testcase){
+ case 1:
// closest to a vertex
if(insideAB) dist = (sphere.center - vc).Magnitude();
else if(insideAC) dist = (sphere.center - vb).Magnitude();
else if(insideBC) dist = (sphere.center - va).Magnitude();
else assert(0);
- }else if(testcase == 2){
+ break;
+ case 2:
// closest to an edge
+ // looks like original game as DistToLine manually inlined
if(!insideAB) dist = DistToLine(&va, &vb, &sphere.center);
else if(!insideAC) dist = DistToLine(&va, &vc, &sphere.center);
else if(!insideBC) dist = DistToLine(&vb, &vc, &sphere.center);
else assert(0);
- }else if(testcase == 3){
+ break;
+ case 3:
// center is in triangle
- return true;
- }else
- assert(0); // front fell off
+ dist = Abs(planedist);
+ break;
+ default:
+ assert(0);
+ }
return dist < sphere.radius;
}
@@ -547,21 +579,24 @@ CCollision::TestLineOfSight(const CColLine &line, const CMatrix &matrix, CColMod
if(!TestLineBox(newline, model.boundingBox))
return false;
- for(i = 0; i < model.numSpheres; i++)
- if(!ignoreSeeThrough || model.spheres[i].surface != SURFACE_GLASS && model.spheres[i].surface != SURFACE_TRANSPARENT_CLOTH)
- if(TestLineSphere(newline, model.spheres[i]))
- return true;
+ for(i = 0; i < model.numSpheres; i++){
+ if(ignoreSeeThrough && IsSeeThrough(model.spheres[i].surface)) continue;
+ if(TestLineSphere(newline, model.spheres[i]))
+ return true;
+ }
- for(i = 0; i < model.numBoxes; i++)
- if(!ignoreSeeThrough || model.boxes[i].surface != SURFACE_GLASS && model.boxes[i].surface != SURFACE_TRANSPARENT_CLOTH)
- if(TestLineBox(newline, model.boxes[i]))
- return true;
+ for(i = 0; i < model.numBoxes; i++){
+ if(ignoreSeeThrough && IsSeeThrough(model.boxes[i].surface)) continue;
+ if(TestLineBox(newline, model.boxes[i]))
+ return true;
+ }
CalculateTrianglePlanes(&model);
- for(i = 0; i < model.numTriangles; i++)
- if(!ignoreSeeThrough || model.triangles[i].surface != SURFACE_GLASS && model.triangles[i].surface != SURFACE_TRANSPARENT_CLOTH)
- if(TestLineTriangle(newline, model.vertices, model.triangles[i], model.trianglePlanes[i]))
- return true;
+ for(i = 0; i < model.numTriangles; i++){
+ if(ignoreSeeThrough && IsSeeThrough(model.triangles[i].surface)) continue;
+ if(TestLineTriangle(newline, model.vertices, model.triangles[i], model.trianglePlanes[i]))
+ return true;
+ }
return false;
}
@@ -836,16 +871,16 @@ CCollision::ProcessLineSphere(const CColLine &line, const CColSphere &sphere, CC
bool
CCollision::ProcessVerticalLineTriangle(const CColLine &line,
- const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane,
+ const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane,
CColPoint &point, float &mindist, CStoredCollPoly *poly)
{
float t;
CVector normal;
const CVector &p0 = line.p0;
- const CVector &va = verts[tri.a];
- const CVector &vb = verts[tri.b];
- const CVector &vc = verts[tri.c];
+ const CVector &va = verts[tri.a].Get();
+ const CVector &vb = verts[tri.b].Get();
+ const CVector &vc = verts[tri.c].Get();
// early out bound rect test
if(p0.x < va.x && p0.x < vb.x && p0.x < vc.x) return false;
@@ -910,6 +945,7 @@ CCollision::ProcessVerticalLineTriangle(const CColLine &line,
if(CrossProduct2D(vec2-vec1, vect-vec1) < 0.0f) return false;
if(CrossProduct2D(vec3-vec1, vect-vec1) > 0.0f) return false;
if(CrossProduct2D(vec3-vec2, vect-vec2) < 0.0f) return false;
+ if(t >= mindist) return false;
point.point = p;
point.normal = normal;
point.surfaceA = 0;
@@ -935,16 +971,12 @@ CCollision::IsStoredPolyStillValidVerticalLine(const CVector &pos, float z, CCol
return false;
// maybe inlined?
- CColTriangle tri;
- tri.a = 0;
- tri.b = 1;
- tri.c = 2;
CColTrianglePlane plane;
- plane.Set(poly->verts, tri);
+ plane.Set(poly->verts[0], poly->verts[1], poly->verts[2]);
- const CVector &va = poly->verts[tri.a];
- const CVector &vb = poly->verts[tri.b];
- const CVector &vc = poly->verts[tri.c];
+ const CVector &va = poly->verts[0];
+ const CVector &vb = poly->verts[1];
+ const CVector &vc = poly->verts[2];
CVector p0 = pos;
CVector p1(pos.x, pos.y, z);
@@ -1009,7 +1041,7 @@ CCollision::IsStoredPolyStillValidVerticalLine(const CVector &pos, float z, CCol
bool
CCollision::ProcessLineTriangle(const CColLine &line ,
- const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane,
+ const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane,
CColPoint &point, float &mindist)
{
float t;
@@ -1028,9 +1060,9 @@ CCollision::ProcessLineTriangle(const CColLine &line ,
// find point of intersection
CVector p = line.p0 + (line.p1-line.p0)*t;
- const CVector &va = verts[tri.a];
- const CVector &vb = verts[tri.b];
- const CVector &vc = verts[tri.c];
+ const CVector &va = verts[tri.a].Get();
+ const CVector &vb = verts[tri.b].Get();
+ const CVector &vc = verts[tri.c].Get();
CVector2D vec1, vec2, vec3, vect;
switch(plane.dir){
@@ -1076,6 +1108,7 @@ CCollision::ProcessLineTriangle(const CColLine &line ,
if(CrossProduct2D(vec2-vec1, vect-vec1) < 0.0f) return false;
if(CrossProduct2D(vec3-vec1, vect-vec1) > 0.0f) return false;
if(CrossProduct2D(vec3-vec2, vect-vec2) < 0.0f) return false;
+ if(t >= mindist) return false;
point.point = p;
point.normal = normal;
point.surfaceA = 0;
@@ -1088,7 +1121,7 @@ CCollision::ProcessLineTriangle(const CColLine &line ,
bool
CCollision::ProcessSphereTriangle(const CColSphere &sphere,
- const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane,
+ const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane,
CColPoint &point, float &mindistsq)
{
// If sphere and plane don't intersect, no collision
@@ -1097,9 +1130,9 @@ CCollision::ProcessSphereTriangle(const CColSphere &sphere,
if(Abs(planedist) > sphere.radius || distsq > mindistsq)
return false;
- const CVector &va = verts[tri.a];
- const CVector &vb = verts[tri.b];
- const CVector &vc = verts[tri.c];
+ const CVector &va = verts[tri.a].Get();
+ const CVector &vb = verts[tri.b].Get();
+ const CVector &vc = verts[tri.c].Get();
// calculate two orthogonal basis vectors for the triangle
CVector normal;
@@ -1126,25 +1159,31 @@ CCollision::ProcessSphereTriangle(const CColSphere &sphere,
int testcase = insideAB + insideAC + insideBC;
float dist = 0.0f;
CVector p;
- if(testcase == 1){
+ switch(testcase){
+ case 1:
// closest to a vertex
if(insideAB) p = vc;
else if(insideAC) p = vb;
else if(insideBC) p = va;
else assert(0);
dist = (sphere.center - p).Magnitude();
- }else if(testcase == 2){
+ break;
+ case 2:
// closest to an edge
+ // looks like original game as DistToLine manually inlined
if(!insideAB) dist = DistToLine(&va, &vb, &sphere.center, p);
else if(!insideAC) dist = DistToLine(&va, &vc, &sphere.center, p);
else if(!insideBC) dist = DistToLine(&vb, &vc, &sphere.center, p);
else assert(0);
- }else if(testcase == 3){
+ break;
+ case 3:
// center is in triangle
dist = Abs(planedist);
p = sphere.center - normal*planedist;
- }else
- assert(0); // front fell off
+ break;
+ default:
+ assert(0);
+ }
if(dist >= sphere.radius || dist*dist >= mindistsq)
return false;
@@ -1178,18 +1217,21 @@ CCollision::ProcessLineOfSight(const CColLine &line,
return false;
float coldist = mindist;
- for(i = 0; i < model.numSpheres; i++)
- if(!ignoreSeeThrough || model.spheres[i].surface != SURFACE_GLASS && model.spheres[i].surface != SURFACE_TRANSPARENT_CLOTH)
- ProcessLineSphere(newline, model.spheres[i], point, coldist);
+ for(i = 0; i < model.numSpheres; i++){
+ if(ignoreSeeThrough && IsSeeThrough(model.spheres[i].surface)) continue;
+ ProcessLineSphere(newline, model.spheres[i], point, coldist);
+ }
- for(i = 0; i < model.numBoxes; i++)
- if(!ignoreSeeThrough || model.boxes[i].surface != SURFACE_GLASS && model.boxes[i].surface != SURFACE_TRANSPARENT_CLOTH)
- ProcessLineBox(newline, model.boxes[i], point, coldist);
+ for(i = 0; i < model.numBoxes; i++){
+ if(ignoreSeeThrough && IsSeeThrough(model.boxes[i].surface)) continue;
+ ProcessLineBox(newline, model.boxes[i], point, coldist);
+ }
CalculateTrianglePlanes(&model);
- for(i = 0; i < model.numTriangles; i++)
- if(!ignoreSeeThrough || model.triangles[i].surface != SURFACE_GLASS && model.triangles[i].surface != SURFACE_TRANSPARENT_CLOTH)
- ProcessLineTriangle(newline, model.vertices, model.triangles[i], model.trianglePlanes[i], point, coldist);
+ for(i = 0; i < model.numTriangles; i++){
+ if(ignoreSeeThrough && IsSeeThrough(model.triangles[i].surface)) continue;
+ ProcessLineTriangle(newline, model.vertices, model.triangles[i], model.trianglePlanes[i], point, coldist);
+ }
if(coldist < mindist){
point.point = matrix * point.point;
@@ -1218,24 +1260,27 @@ CCollision::ProcessVerticalLine(const CColLine &line,
return false;
float coldist = mindist;
- for(i = 0; i < model.numSpheres; i++)
- if(!ignoreSeeThrough || model.spheres[i].surface != SURFACE_GLASS && model.spheres[i].surface != SURFACE_TRANSPARENT_CLOTH)
- ProcessLineSphere(newline, model.spheres[i], point, coldist);
+ for(i = 0; i < model.numSpheres; i++){
+ if(ignoreSeeThrough && IsSeeThrough(model.spheres[i].surface)) continue;
+ ProcessLineSphere(newline, model.spheres[i], point, coldist);
+ }
- for(i = 0; i < model.numBoxes; i++)
- if(!ignoreSeeThrough || model.boxes[i].surface != SURFACE_GLASS && model.boxes[i].surface != SURFACE_TRANSPARENT_CLOTH)
- ProcessLineBox(newline, model.boxes[i], point, coldist);
+ for(i = 0; i < model.numBoxes; i++){
+ if(ignoreSeeThrough && IsSeeThrough(model.boxes[i].surface)) continue;
+ ProcessLineBox(newline, model.boxes[i], point, coldist);
+ }
CalculateTrianglePlanes(&model);
TempStoredPoly.valid = false;
- for(i = 0; i < model.numTriangles; i++)
- if(!ignoreSeeThrough || model.triangles[i].surface != SURFACE_GLASS && model.triangles[i].surface != SURFACE_TRANSPARENT_CLOTH)
- ProcessVerticalLineTriangle(newline, model.vertices, model.triangles[i], model.trianglePlanes[i], point, coldist, &TempStoredPoly);
+ for(i = 0; i < model.numTriangles; i++){
+ if(ignoreSeeThrough && IsSeeThrough(model.triangles[i].surface)) continue;
+ ProcessVerticalLineTriangle(newline, model.vertices, model.triangles[i], model.trianglePlanes[i], point, coldist, &TempStoredPoly);
+ }
if(coldist < mindist){
point.point = matrix * point.point;
point.normal = Multiply3x3(matrix, point.normal);
- if(poly && TempStoredPoly.valid){
+ if(TempStoredPoly.valid && poly){
*poly = TempStoredPoly;
poly->verts[0] = matrix * poly->verts[0];
poly->verts[1] = matrix * poly->verts[1];
@@ -1934,7 +1979,7 @@ CColLine::Set(const CVector &p0, const CVector &p1)
}
void
-CColTriangle::Set(const CVector *, int a, int b, int c, uint8 surf, uint8 piece)
+CColTriangle::Set(const CompressedVector *, int a, int b, int c, uint8 surf, uint8 piece)
{
this->a = a;
this->b = b;
@@ -1943,12 +1988,8 @@ CColTriangle::Set(const CVector *, int a, int b, int c, uint8 surf, uint8 piece)
}
void
-CColTrianglePlane::Set(const CVector *v, CColTriangle &tri)
+CColTrianglePlane::Set(const CVector &va, const CVector &vb, const CVector &vc)
{
- const CVector &va = v[tri.a];
- const CVector &vb = v[tri.b];
- const CVector &vc = v[tri.c];
-
normal = CrossProduct(vc-va, vb-va);
normal.Normalise();
dist = DotProduct(normal, va);
@@ -2038,7 +2079,7 @@ CColModel::GetLinkPtr(void)
void
CColModel::GetTrianglePoint(CVector &v, int i) const
{
- v = vertices[i];
+ v = vertices[i].Get();
}
CColModel&
@@ -2117,7 +2158,7 @@ CColModel::operator=(const CColModel &other)
if(vertices)
RwFree(vertices);
if(numVerts){
- vertices = (CVector*)RwMalloc(numVerts*sizeof(CVector));
+ vertices = (CompressedVector*)RwMalloc(numVerts*sizeof(CompressedVector));
for(i = 0; i < numVerts; i++)
vertices[i] = other.vertices[i];
}