diff options
Diffstat (limited to 'src/core/Collision.cpp')
-rw-r--r-- | src/core/Collision.cpp | 405 |
1 files changed, 145 insertions, 260 deletions
diff --git a/src/core/Collision.cpp b/src/core/Collision.cpp index 99be816f..268e3c5e 100644 --- a/src/core/Collision.cpp +++ b/src/core/Collision.cpp @@ -20,6 +20,10 @@ #include "SurfaceTable.h" #include "Lines.h" #include "Collision.h" +#include "Camera.h" +#include "ColStore.h" + +//--MIAMI: file done enum Direction { @@ -39,52 +43,22 @@ CCollision::Init(void) { ms_colModelCache.Init(NUMCOLCACHELINKS); ms_collisionInMemory = LEVEL_GENERIC; + CColStore::Initialise(); } void CCollision::Shutdown(void) { ms_colModelCache.Shutdown(); + CColStore::Shutdown(); } void CCollision::Update(void) { - CVector playerCoors; - playerCoors = FindPlayerCoors(); - eLevelName level = CTheZones::m_CurrLevel; - bool forceLevelChange = false; - - if(CTimer::GetTimeInMilliseconds() < 2000 || CCutsceneMgr::IsCutsceneProcessing()) - return; - - // hardcode a level if there are no zones - if(level == LEVEL_GENERIC){ - if(CGame::currLevel == LEVEL_INDUSTRIAL && - playerCoors.x < 400.0f){ - level = LEVEL_COMMERCIAL; - forceLevelChange = true; - }else if(CGame::currLevel == LEVEL_SUBURBAN && - playerCoors.x > -450.0f && playerCoors.y < -1400.0f){ - level = LEVEL_COMMERCIAL; - forceLevelChange = true; - }else{ - if(playerCoors.x > 800.0f){ - level = LEVEL_INDUSTRIAL; - forceLevelChange = true; - }else if(playerCoors.x < -800.0f){ - level = LEVEL_SUBURBAN; - forceLevelChange = true; - } - } - } - if(level != LEVEL_GENERIC && level != CGame::currLevel) - CGame::currLevel = level; - if(ms_collisionInMemory != CGame::currLevel) - LoadCollisionWhenINeedIt(forceLevelChange); - CStreaming::HaveAllBigBuildingsLoaded(CGame::currLevel); } +//--MIAMI: unused eLevelName GetCollisionInSectorList(CPtrList &list) { @@ -101,6 +75,7 @@ GetCollisionInSectorList(CPtrList &list) return LEVEL_GENERIC; } +//--MIAMI: unused // Get a level this sector is in based on collision models eLevelName GetCollisionInSector(CSector §) @@ -124,133 +99,13 @@ GetCollisionInSector(CSector §) void CCollision::LoadCollisionWhenINeedIt(bool forceChange) { - eLevelName level, l; - bool multipleLevels; - CVector playerCoors; - CVehicle *veh; - CEntryInfoNode *ei; - int sx, sy; - int xmin, xmax, ymin, ymax; - int x, y; - - level = LEVEL_GENERIC; - - playerCoors = FindPlayerCoors(); - sx = CWorld::GetSectorIndexX(playerCoors.x); - sy = CWorld::GetSectorIndexY(playerCoors.y); - multipleLevels = false; - - veh = FindPlayerVehicle(); - if(veh && veh->IsTrain()){ - if(((CTrain*)veh)->m_nDoorState != TRAIN_DOOR_OPEN) - return; - }else if(playerCoors.z < -4.0f && !CCullZones::DoINeedToLoadCollision()) - return; - - // Figure out whose level's collisions we're most likely to be interested in - if(!forceChange){ - if(veh && veh->IsBoat()){ - // on water we expect to be between levels - multipleLevels = true; - }else{ - xmin = Max(sx - 1, 0); - xmax = Min(sx + 1, NUMSECTORS_X-1); - ymin = Max(sy - 1, 0); - ymax = Min(sy + 1, NUMSECTORS_Y-1); - - for(x = xmin; x <= xmax; x++) - for(y = ymin; y <= ymax; y++){ - l = GetCollisionInSector(*CWorld::GetSector(x, y)); - if(l != LEVEL_GENERIC){ - if(level == LEVEL_GENERIC) - level = l; - if(level != l) - multipleLevels = true; - } - } - } - - if(multipleLevels && veh && veh->IsBoat()) - for(ei = veh->m_entryInfoList.first; ei; ei = ei->next){ - level = GetCollisionInSector(*ei->sector); - 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); - CStreaming::RemoveBigBuildings(LEVEL_INDUSTRIAL); - CStreaming::RemoveBigBuildings(LEVEL_COMMERCIAL); - CStreaming::RemoveBigBuildings(LEVEL_SUBURBAN); - CModelInfo::RemoveColModelsFromOtherLevels(CGame::currLevel); - CStreaming::RemoveUnusedModelsInLoadedList(); - CGame::TidyUpMemory(true, true); - CFileLoader::LoadCollisionFromDatFile(CGame::currLevel); -#endif - - ms_collisionInMemory = CGame::currLevel; - CReplay::EmptyReplayBuffer(); -#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 - } } void CCollision::SortOutCollisionAfterLoad(void) { - if(ms_collisionInMemory == CGame::currLevel) - return; -#ifndef NO_ISLAND_LOADING - CModelInfo::RemoveColModelsFromOtherLevels(CGame::currLevel); -#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)); - } - ms_collisionInMemory = CGame::currLevel; - CGame::TidyUpMemory(true, false); + CColStore::LoadCollision(TheCamera.GetPosition()); + CStreaming::LoadAllRequestedModels(false); } void @@ -274,14 +129,14 @@ CCollision::LoadCollisionScreen(eLevelName level) bool -CCollision::TestSphereSphere(const CColSphere &s1, const CColSphere &s2) +CCollision::TestSphereSphere(const CSphere &s1, const CSphere &s2) { float d = s1.radius + s2.radius; return (s1.center - s2.center).MagnitudeSqr() < d*d; } bool -CCollision::TestSphereBox(const CColSphere &sph, const CColBox &box) +CCollision::TestSphereBox(const CSphere &sph, const CBox &box) { if(sph.center.x + sph.radius < box.min.x) return false; if(sph.center.x - sph.radius > box.max.x) return false; @@ -293,7 +148,7 @@ CCollision::TestSphereBox(const CColSphere &sph, const CColBox &box) } bool -CCollision::TestLineBox(const CColLine &line, const CColBox &box) +CCollision::TestLineBox(const CColLine &line, const CBox &box) { float t, x, y, z; // If either line point is in the box, we have a collision @@ -378,7 +233,7 @@ CCollision::TestLineBox(const CColLine &line, const CColBox &box) } bool -CCollision::TestVerticalLineBox(const CColLine &line, const CColBox &box) +CCollision::TestVerticalLineBox(const CColLine &line, const CBox &box) { if(line.p0.x <= box.min.x) return false; if(line.p0.y <= box.min.y) return false; @@ -539,6 +394,8 @@ CCollision::TestSphereTriangle(const CColSphere &sphere, int testcase = insideAB + insideAC + insideBC; float dist = 0.0f; switch(testcase){ + case 0: + return false; // shouldn't happen case 1: // closest to a vertex if(insideAB) dist = (sphere.center - vc).Magnitude(); @@ -566,7 +423,7 @@ CCollision::TestSphereTriangle(const CColSphere &sphere, } bool -CCollision::TestLineOfSight(const CColLine &line, const CMatrix &matrix, CColModel &model, bool ignoreSeeThrough) +CCollision::TestLineOfSight(const CColLine &line, const CMatrix &matrix, CColModel &model, bool ignoreSeeThrough, bool ignoreShootThrough) { static CMatrix matTransform; int i; @@ -581,12 +438,14 @@ CCollision::TestLineOfSight(const CColLine &line, const CMatrix &matrix, CColMod for(i = 0; i < model.numSpheres; i++){ if(ignoreSeeThrough && IsSeeThrough(model.spheres[i].surface)) continue; + if(ignoreShootThrough && IsShootThrough(model.spheres[i].surface)) continue; if(TestLineSphere(newline, model.spheres[i])) return true; } for(i = 0; i < model.numBoxes; i++){ if(ignoreSeeThrough && IsSeeThrough(model.boxes[i].surface)) continue; + if(ignoreShootThrough && IsShootThrough(model.boxes[i].surface)) continue; if(TestLineBox(newline, model.boxes[i])) return true; } @@ -594,6 +453,7 @@ CCollision::TestLineOfSight(const CColLine &line, const CMatrix &matrix, CColMod CalculateTrianglePlanes(&model); for(i = 0; i < model.numTriangles; i++){ if(ignoreSeeThrough && IsSeeThrough(model.triangles[i].surface)) continue; + if(ignoreShootThrough && IsShootThrough(model.triangles[i].surface)) continue; if(TestLineTriangle(newline, model.vertices, model.triangles[i], model.trianglePlanes[i])) return true; } @@ -601,6 +461,7 @@ CCollision::TestLineOfSight(const CColLine &line, const CMatrix &matrix, CColMod return false; } +// TODO: TestPillWithSpheresInColModel, but only called from overloaded CWeapon::FireMelee which isn't used // // Process @@ -869,6 +730,7 @@ CCollision::ProcessLineSphere(const CColLine &line, const CColSphere &sphere, CC return true; } +//--MIAMI: unused bool CCollision::ProcessVerticalLineTriangle(const CColLine &line, const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, @@ -1042,7 +904,7 @@ CCollision::IsStoredPolyStillValidVerticalLine(const CVector &pos, float z, CCol bool CCollision::ProcessLineTriangle(const CColLine &line , const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, - CColPoint &point, float &mindist) + CColPoint &point, float &mindist, CStoredCollPoly *poly) { float t; CVector normal; @@ -1115,6 +977,12 @@ CCollision::ProcessLineTriangle(const CColLine &line , point.pieceA = 0; point.surfaceB = tri.surface; point.pieceB = 0; + if(poly){ + poly->verts[0] = va; + poly->verts[1] = vb; + poly->verts[2] = vc; + poly->valid = true; + } mindist = t; return true; } @@ -1160,6 +1028,8 @@ CCollision::ProcessSphereTriangle(const CColSphere &sphere, float dist = 0.0f; CVector p; switch(testcase){ + case 0: + return false; // shouldn't happen case 1: // closest to a vertex if(insideAB) p = vc; @@ -1203,7 +1073,7 @@ CCollision::ProcessSphereTriangle(const CColSphere &sphere, bool CCollision::ProcessLineOfSight(const CColLine &line, const CMatrix &matrix, CColModel &model, - CColPoint &point, float &mindist, bool ignoreSeeThrough) + CColPoint &point, float &mindist, bool ignoreSeeThrough, bool ignoreShootThrough) { static CMatrix matTransform; int i; @@ -1219,17 +1089,20 @@ CCollision::ProcessLineOfSight(const CColLine &line, float coldist = mindist; for(i = 0; i < model.numSpheres; i++){ if(ignoreSeeThrough && IsSeeThrough(model.spheres[i].surface)) continue; + if(ignoreShootThrough && IsShootThrough(model.spheres[i].surface)) continue; ProcessLineSphere(newline, model.spheres[i], point, coldist); } for(i = 0; i < model.numBoxes; i++){ if(ignoreSeeThrough && IsSeeThrough(model.boxes[i].surface)) continue; + if(ignoreShootThrough && IsShootThrough(model.boxes[i].surface)) continue; ProcessLineBox(newline, model.boxes[i], point, coldist); } CalculateTrianglePlanes(&model); for(i = 0; i < model.numTriangles; i++){ if(ignoreSeeThrough && IsSeeThrough(model.triangles[i].surface)) continue; + if(ignoreShootThrough && IsShootThrough(model.triangles[i].surface)) continue; ProcessLineTriangle(newline, model.vertices, model.triangles[i], model.trianglePlanes[i], point, coldist); } @@ -1245,7 +1118,7 @@ CCollision::ProcessLineOfSight(const CColLine &line, bool CCollision::ProcessVerticalLine(const CColLine &line, const CMatrix &matrix, CColModel &model, - CColPoint &point, float &mindist, bool ignoreSeeThrough, CStoredCollPoly *poly) + CColPoint &point, float &mindist, bool ignoreSeeThrough, bool ignoreShootThrough, CStoredCollPoly *poly) { static CStoredCollPoly TempStoredPoly; int i; @@ -1253,28 +1126,27 @@ CCollision::ProcessVerticalLine(const CColLine &line, // transform line to model space // Why does the game seem to do this differently than above? CColLine newline(MultiplyInverse(matrix, line.p0), MultiplyInverse(matrix, line.p1)); - newline.p1.x = newline.p0.x; - newline.p1.y = newline.p0.y; - if(!TestVerticalLineBox(newline, model.boundingBox)) + if(!TestLineBox(newline, model.boundingBox)) return false; + // BUG? is IsSeeThroughVertical really the right thing? also not checking shoot through float coldist = mindist; for(i = 0; i < model.numSpheres; i++){ - if(ignoreSeeThrough && IsSeeThrough(model.spheres[i].surface)) continue; + if(ignoreSeeThrough && IsSeeThroughVertical(model.spheres[i].surface)) continue; ProcessLineSphere(newline, model.spheres[i], point, coldist); } for(i = 0; i < model.numBoxes; i++){ - if(ignoreSeeThrough && IsSeeThrough(model.boxes[i].surface)) continue; + if(ignoreSeeThrough && IsSeeThroughVertical(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 && IsSeeThrough(model.triangles[i].surface)) continue; - ProcessVerticalLineTriangle(newline, model.vertices, model.triangles[i], model.trianglePlanes[i], point, coldist, &TempStoredPoly); + if(ignoreSeeThrough && IsSeeThroughVertical(model.triangles[i].surface)) continue; + ProcessLineTriangle(newline, model.vertices, model.triangles[i], model.trianglePlanes[i], point, coldist, &TempStoredPoly); } if(coldist < mindist){ @@ -1515,6 +1387,15 @@ CCollision::CalculateTrianglePlanes(CColModel *model) } void +CCollision::RemoveTrianglePlanes(CColModel *model) +{ + if(model->trianglePlanes){ + ms_colModelCache.Remove(model->GetLinkPtr()); + model->RemoveTrianglePlanes(); + } +} + +void CCollision::DrawColModel(const CMatrix &mat, const CColModel &colModel) { int i; @@ -1736,15 +1617,75 @@ CCollision::DrawColModel(const CMatrix &mat, const CColModel &colModel) RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE); } +static void +GetSurfaceColor(uint8 surf, uint8 &r, uint8 &g, uint8 &b) +{ + // game doesn't do this + r = 255; + g = 128; + b = 0; + + switch(CSurfaceTable::GetAdhesionGroup(surf)){ + case ADHESIVE_RUBBER: + r = 255; + g = 0; + b = 0; + break; + case ADHESIVE_HARD: + r = 255; + g = 255; + b = 128; + break; + case ADHESIVE_ROAD: + r = 128; + g = 128; + b = 128; + break; + case ADHESIVE_LOOSE: + r = 0; + g = 255; + b = 0; + break; + case ADHESIVE_SAND: + r = 255; + g = 128; + b = 128; + break; + case ADHESIVE_WET: + r = 0; + g = 0; + b = 255; + break; + } + + if(surf == SURFACE_SAND || surf == SURFACE_SAND_BEACH){ + r = 255; + g = 255; + b = 0; + } + + float f = (surf & 0xF)/32.0f + 0.5f; + r *= f; + g *= f; + b *= f; + + if(surf == SURFACE_TRANSPARENT_CLOTH || surf == SURFACE_METAL_CHAIN_FENCE || + surf == SURFACE_TRANSPARENT_STONE || surf == SURFACE_SCAFFOLD_POLE) + if(CTimer::GetFrameCounter() & 1){ + r = 0; + g = 0; + b = 0; + } +} + void CCollision::DrawColModel_Coloured(const CMatrix &mat, const CColModel &colModel, int32 id) { int i; int s; - float f; CVector verts[8]; CVector min, max; - int r, g, b; + uint8 r, g, b; RwImVertexIndex *iptr; RwIm3DVertex *vptr; @@ -1763,53 +1704,8 @@ CCollision::DrawColModel_Coloured(const CMatrix &mat, const CColModel &colModel, verts[1] = mat * verts[1]; verts[2] = mat * verts[2]; - // game doesn't do this - r = 255; - g = 128; - b = 0; - s = colModel.triangles[i].surface; - f = (s & 0xF)/32.0f + 0.5f; - switch(CSurfaceTable::GetAdhesionGroup(s)){ - case ADHESIVE_RUBBER: - r = f * 255.0f; - g = 0; - b = 0; - break; - case ADHESIVE_HARD: - r = f*255.0f; - g = f*255.0f; - b = f*128.0f; - break; - case ADHESIVE_ROAD: - r = f*128.0f; - g = f*128.0f; - b = f*128.0f; - break; - case ADHESIVE_LOOSE: - r = 0; - g = f * 255.0f; - b = 0; - break; - case ADHESIVE_WET: - r = 0; - g = 0; - b = f * 255.0f; - break; - default: - // this doesn't make much sense - r *= f; - g *= f; - b *= f; - } - - if(s == SURFACE_TRANSPARENT_CLOTH || s == SURFACE_METAL_CHAIN_FENCE || - s == SURFACE_TRANSPARENT_STONE || s == SURFACE_SCAFFOLD_POLE) - if(CTimer::GetFrameCounter() & 1){ - r = 0; - g = 0; - b = 0; - } + GetSurfaceColor(s, r, g, b); if(s > SURFACE_METAL_GATE){ r = CGeneral::GetRandomNumber(); @@ -1850,47 +1746,7 @@ CCollision::DrawColModel_Coloured(const CMatrix &mat, const CColModel &colModel, verts[7] = mat * CVector(max.x, max.y, max.z); s = colModel.boxes[i].surface; - f = (s & 0xF)/32.0f + 0.5f; - switch(CSurfaceTable::GetAdhesionGroup(s)){ - case ADHESIVE_RUBBER: - r = f * 255.0f; - g = 0; - b = 0; - break; - case ADHESIVE_HARD: - r = f*255.0f; - g = f*255.0f; - b = f*128.0f; - break; - case ADHESIVE_ROAD: - r = f*128.0f; - g = f*128.0f; - b = f*128.0f; - break; - case ADHESIVE_LOOSE: - r = 0; - g = f * 255.0f; - b = 0; - break; - case ADHESIVE_WET: - r = 0; - g = 0; - b = f * 255.0f; - break; - default: - // this doesn't make much sense - r *= f; - g *= f; - b *= f; - } - - if(s == SURFACE_TRANSPARENT_CLOTH || s == SURFACE_METAL_CHAIN_FENCE || - s == SURFACE_TRANSPARENT_STONE || s == SURFACE_SCAFFOLD_POLE) - if(CTimer::GetFrameCounter() & 1){ - r = 0; - g = 0; - b = 0; - } + GetSurfaceColor(s, r, g, b); RenderBuffer::StartStoring(36, 8, &iptr, &vptr); RwIm3DVertexSetRGBA(&vptr[0], r, g, b, 255); @@ -1962,6 +1818,21 @@ CColSphere::Set(float radius, const CVector ¢er, uint8 surf, uint8 piece) this->piece = piece; } +bool +CColSphere::IntersectRay(CVector const& from, CVector const& dir, CVector &entry, CVector &exit) +{ + CVector distToCenter = from - center; + float distToTouchSqr = distToCenter.MagnitudeSqr() - sq(radius); + float root1, root2; + + if (!CGeneral::SolveQuadratic(1.0f, DotProduct(distToCenter, dir) * 2.f, distToTouchSqr, root1, root2)) + return false; + + entry = from + dir * root1; + exit = from + dir * root2; + return true; +} + void CColBox::Set(const CVector &min, const CVector &max, uint8 surf, uint8 piece) { @@ -2003,6 +1874,19 @@ CColTrianglePlane::Set(const CVector &va, const CVector &vb, const CVector &vc) dir = normal.z < 0.0f ? DIR_Z_NEG : DIR_Z_POS; } +CColPoint& +CColPoint::operator=(const CColPoint& other) +{ + point = other.point; + normal = other.normal; + surfaceA = other.surfaceA; + pieceA = other.pieceA; + surfaceB = other.surfaceB; + pieceB = other.pieceB; + // doesn't copy depth + return *this; +} + CColModel::CColModel(void) { numSpheres = 0; @@ -2015,7 +1899,7 @@ CColModel::CColModel(void) vertices = nil; triangles = nil; trianglePlanes = nil; - level = CGame::currLevel; + level = 0; // generic col slot ownsCollisionVolumes = true; } @@ -2034,6 +1918,7 @@ CColModel::RemoveCollisionVolumes(void) RwFree(boxes); RwFree(vertices); RwFree(triangles); + CCollision::RemoveTrianglePlanes(this); } numSpheres = 0; numLines = 0; |