From a6f5f4634c63a515196a0f650682953356cb8e18 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Sat, 14 Nov 2020 22:13:32 +0200 Subject: Make collision code placement more like original (+ small fixes) --- src/CMakeLists.txt | 1 + src/collision/ColBox.cpp | 21 + src/collision/ColBox.h | 16 + src/collision/ColLine.cpp | 9 + src/collision/ColLine.h | 14 + src/collision/ColModel.cpp | 184 +++ src/collision/ColModel.h | 37 + src/collision/ColPoint.cpp | 16 + src/collision/ColPoint.h | 34 + src/collision/ColSphere.cpp | 11 + src/collision/ColSphere.h | 13 + src/collision/ColTriangle.cpp | 41 + src/collision/ColTriangle.h | 68 + src/collision/Collision.cpp | 2736 +++++++++++++++++++++++++++++++ src/collision/Collision.h | 70 + src/collision/CompressedVector.h | 36 + src/collision/TempColModels.cpp | 296 ++++ src/collision/TempColModels.h | 23 + src/collision/VuCollision.cpp | 282 ++++ src/collision/VuCollision.h | 32 + src/collision/vu0Collision.dsm | 21 + src/collision/vu0Collision_1.s | 610 +++++++ src/collision/vu0Collision_2.s | 191 +++ src/core/Collision.cpp | 3290 -------------------------------------- src/core/Collision.h | 254 --- src/core/TempColModels.cpp | 297 ---- src/core/TempColModels.h | 23 - src/core/vu0Collision.dsm | 21 - src/core/vu0Collision_1.s | 610 ------- src/core/vu0Collision_2.s | 191 --- src/entities/Physical.cpp | 24 +- 31 files changed, 4774 insertions(+), 4698 deletions(-) create mode 100644 src/collision/ColBox.cpp create mode 100644 src/collision/ColBox.h create mode 100644 src/collision/ColLine.cpp create mode 100644 src/collision/ColLine.h create mode 100644 src/collision/ColModel.cpp create mode 100644 src/collision/ColModel.h create mode 100644 src/collision/ColPoint.cpp create mode 100644 src/collision/ColPoint.h create mode 100644 src/collision/ColSphere.cpp create mode 100644 src/collision/ColSphere.h create mode 100644 src/collision/ColTriangle.cpp create mode 100644 src/collision/ColTriangle.h create mode 100644 src/collision/Collision.cpp create mode 100644 src/collision/Collision.h create mode 100644 src/collision/CompressedVector.h create mode 100644 src/collision/TempColModels.cpp create mode 100644 src/collision/TempColModels.h create mode 100644 src/collision/VuCollision.cpp create mode 100644 src/collision/VuCollision.h create mode 100644 src/collision/vu0Collision.dsm create mode 100644 src/collision/vu0Collision_1.s create mode 100644 src/collision/vu0Collision_2.s delete mode 100644 src/core/Collision.cpp delete mode 100644 src/core/Collision.h delete mode 100644 src/core/TempColModels.cpp delete mode 100644 src/core/TempColModels.h delete mode 100644 src/core/vu0Collision.dsm delete mode 100644 src/core/vu0Collision_1.s delete mode 100644 src/core/vu0Collision_2.s (limited to 'src') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index eca69d30..ef322a9a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -13,6 +13,7 @@ MACRO(HEADER_DIRECTORIES return_list) FILE(GLOB_RECURSE new_list *.cpp) SET(dir_list "animation" "audio" + "collision" "control" "core" "entities" diff --git a/src/collision/ColBox.cpp b/src/collision/ColBox.cpp new file mode 100644 index 00000000..53cba88b --- /dev/null +++ b/src/collision/ColBox.cpp @@ -0,0 +1,21 @@ +#include "common.h" +#include "ColBox.h" + +void +CColBox::Set(const CVector &min, const CVector &max, uint8 surf, uint8 piece) +{ + this->min = min; + this->max = max; + this->surface = surf; + this->piece = piece; +} + +CColBox& +CColBox::operator=(const CColBox& other) +{ + min = other.min; + max = other.max; + surface = other.surface; + piece = other.piece; + return *this; +} \ No newline at end of file diff --git a/src/collision/ColBox.h b/src/collision/ColBox.h new file mode 100644 index 00000000..ac2cd675 --- /dev/null +++ b/src/collision/ColBox.h @@ -0,0 +1,16 @@ +#pragma once + +#include "SurfaceTable.h" + +struct CColBox +{ + CVector min; + CVector max; + uint8 surface; + uint8 piece; + + void Set(const CVector &min, const CVector &max, uint8 surf = SURFACE_DEFAULT, uint8 piece = 0); + CVector GetSize(void) { return max - min; } + + CColBox& operator=(const CColBox &other); +}; \ No newline at end of file diff --git a/src/collision/ColLine.cpp b/src/collision/ColLine.cpp new file mode 100644 index 00000000..c6247449 --- /dev/null +++ b/src/collision/ColLine.cpp @@ -0,0 +1,9 @@ +#include "common.h" +#include "ColLine.h" + +void +CColLine::Set(const CVector &p0, const CVector &p1) +{ + this->p0 = p0; + this->p1 = p1; +} \ No newline at end of file diff --git a/src/collision/ColLine.h b/src/collision/ColLine.h new file mode 100644 index 00000000..21587a06 --- /dev/null +++ b/src/collision/ColLine.h @@ -0,0 +1,14 @@ +#pragma once + +struct CColLine +{ + // NB: this has to be compatible with two CVuVectors + CVector p0; + int pad0; + CVector p1; + int pad1; + + CColLine(void) { }; + CColLine(const CVector &p0, const CVector &p1) { this->p0 = p0; this->p1 = p1; }; + void Set(const CVector &p0, const CVector &p1); +}; \ No newline at end of file diff --git a/src/collision/ColModel.cpp b/src/collision/ColModel.cpp new file mode 100644 index 00000000..650e6958 --- /dev/null +++ b/src/collision/ColModel.cpp @@ -0,0 +1,184 @@ +#include "common.h" +#include "ColModel.h" +#include "Game.h" + +CColModel::CColModel(void) +{ + numSpheres = 0; + spheres = nil; + numLines = 0; + lines = nil; + numBoxes = 0; + boxes = nil; + numTriangles = 0; + vertices = nil; + triangles = nil; + trianglePlanes = nil; + level = CGame::currLevel; + ownsCollisionVolumes = true; +} + +CColModel::~CColModel(void) +{ + RemoveCollisionVolumes(); + RemoveTrianglePlanes(); +} + +void +CColModel::RemoveCollisionVolumes(void) +{ + if(ownsCollisionVolumes){ + RwFree(spheres); + RwFree(lines); + RwFree(boxes); + RwFree(vertices); + RwFree(triangles); + } + numSpheres = 0; + numLines = 0; + numBoxes = 0; + numTriangles = 0; + spheres = nil; + lines = nil; + boxes = nil; + vertices = nil; + triangles = nil; +} + +void +CColModel::CalculateTrianglePlanes(void) +{ + // HACK: allocate space for one more element to stuff the link pointer into + trianglePlanes = (CColTrianglePlane*)RwMalloc(sizeof(CColTrianglePlane) * (numTriangles+1)); + for(int i = 0; i < numTriangles; i++) + trianglePlanes[i].Set(vertices, triangles[i]); +} + +void +CColModel::RemoveTrianglePlanes(void) +{ + RwFree(trianglePlanes); + trianglePlanes = nil; +} + +void +CColModel::SetLinkPtr(CLink *lptr) +{ + assert(trianglePlanes); + *(CLink**)ALIGNPTR(&trianglePlanes[numTriangles]) = lptr; +} + +CLink* +CColModel::GetLinkPtr(void) +{ + assert(trianglePlanes); + return *(CLink**)ALIGNPTR(&trianglePlanes[numTriangles]); +} + +void +CColModel::GetTrianglePoint(CVector &v, int i) const +{ + v = vertices[i].Get(); +} + +CColModel& +CColModel::operator=(const CColModel &other) +{ + int i; + int numVerts; + + boundingSphere = other.boundingSphere; + boundingBox = other.boundingBox; + + // copy spheres + if(other.numSpheres){ + if(numSpheres != other.numSpheres){ + numSpheres = other.numSpheres; + if(spheres) + RwFree(spheres); + spheres = (CColSphere*)RwMalloc(numSpheres*sizeof(CColSphere)); + } + for(i = 0; i < numSpheres; i++) + spheres[i] = other.spheres[i]; + }else{ + numSpheres = 0; + if(spheres) + RwFree(spheres); + spheres = nil; + } + + // copy lines + if(other.numLines){ + if(numLines != other.numLines){ + numLines = other.numLines; + if(lines) + RwFree(lines); + lines = (CColLine*)RwMalloc(numLines*sizeof(CColLine)); + } + for(i = 0; i < numLines; i++) + lines[i] = other.lines[i]; + }else{ + numLines = 0; + if(lines) + RwFree(lines); + lines = nil; + } + + // copy boxes + if(other.numBoxes){ + if(numBoxes != other.numBoxes){ + numBoxes = other.numBoxes; + if(boxes) + RwFree(boxes); + boxes = (CColBox*)RwMalloc(numBoxes*sizeof(CColBox)); + } + for(i = 0; i < numBoxes; i++) + boxes[i] = other.boxes[i]; + }else{ + numBoxes = 0; + if(boxes) + RwFree(boxes); + boxes = nil; + } + + // copy mesh + if(other.numTriangles){ + // copy vertices + numVerts = 0; + for(i = 0; i < other.numTriangles; i++){ + if(other.triangles[i].a > numVerts) + numVerts = other.triangles[i].a; + if(other.triangles[i].b > numVerts) + numVerts = other.triangles[i].b; + if(other.triangles[i].c > numVerts) + numVerts = other.triangles[i].c; + } + numVerts++; + if(vertices) + RwFree(vertices); + if(numVerts){ + vertices = (CompressedVector*)RwMalloc(numVerts*sizeof(CompressedVector)); + for(i = 0; i < numVerts; i++) + vertices[i] = other.vertices[i]; + } + + // copy triangles + if(numTriangles != other.numTriangles){ + numTriangles = other.numTriangles; + if(triangles) + RwFree(triangles); + triangles = (CColTriangle*)RwMalloc(numTriangles*sizeof(CColTriangle)); + } + for(i = 0; i < numTriangles; i++) + triangles[i] = other.triangles[i]; + }else{ + numTriangles = 0; + if(triangles) + RwFree(triangles); + triangles = nil; + if(vertices) + RwFree(vertices); + vertices = nil; + } + return *this; +} diff --git a/src/collision/ColModel.h b/src/collision/ColModel.h new file mode 100644 index 00000000..7dcdfa4d --- /dev/null +++ b/src/collision/ColModel.h @@ -0,0 +1,37 @@ +#pragma once + +#include "templates.h" +#include "ColBox.h" +#include "ColSphere.h" +#include "ColLine.h" +#include "ColPoint.h" +#include "ColTriangle.h" + +struct CColModel +{ + CColSphere boundingSphere; + CColBox boundingBox; + int16 numSpheres; + int16 numLines; + int16 numBoxes; + int16 numTriangles; + int32 level; + bool ownsCollisionVolumes; // missing on PS2 + CColSphere *spheres; + CColLine *lines; + CColBox *boxes; + CompressedVector *vertices; + CColTriangle *triangles; + CColTrianglePlane *trianglePlanes; + + CColModel(void); + ~CColModel(void); + void RemoveCollisionVolumes(void); + void CalculateTrianglePlanes(void); + void RemoveTrianglePlanes(void); + CLink *GetLinkPtr(void); + void SetLinkPtr(CLink*); + void GetTrianglePoint(CVector &v, int i) const; + + CColModel& operator=(const CColModel& other); +}; \ No newline at end of file diff --git a/src/collision/ColPoint.cpp b/src/collision/ColPoint.cpp new file mode 100644 index 00000000..fbf9e8c3 --- /dev/null +++ b/src/collision/ColPoint.cpp @@ -0,0 +1,16 @@ +#include "common.h" +#include "ColPoint.h" + +CColPoint& +CColPoint::operator=(const CColPoint &other) +{ + point = other.point; + normal = other.normal; + surfaceA = other.surfaceA; + pieceA = other.pieceA; + surfaceB = other.surfaceB; + pieceB = other.pieceB; + + // no depth? + return *this; +} diff --git a/src/collision/ColPoint.h b/src/collision/ColPoint.h new file mode 100644 index 00000000..a15b2345 --- /dev/null +++ b/src/collision/ColPoint.h @@ -0,0 +1,34 @@ +#pragma once + +struct CColPoint +{ + CVector point; + int pad1; + // the surface normal on the surface of point + CVector normal; + int pad2; + uint8 surfaceA; + uint8 pieceA; + uint8 surfaceB; + uint8 pieceB; + float depth; + + const CVector &GetNormal() { return normal; } + float GetDepth() { return depth; } + void Set(float depth, uint8 surfA, uint8 pieceA, uint8 surfB, uint8 pieceB) { + this->depth = depth; + this->surfaceA = surfA; + this->pieceA = pieceA; + this->surfaceB = surfB; + this->pieceB = pieceB; + } + void Set(uint8 surfA, uint8 pieceA, uint8 surfB, uint8 pieceB) { + this->surfaceA = surfA; + this->pieceA = pieceA; + this->surfaceB = surfB; + this->pieceB = pieceB; + } + + CColPoint &operator=(const CColPoint &other); +}; + diff --git a/src/collision/ColSphere.cpp b/src/collision/ColSphere.cpp new file mode 100644 index 00000000..9aac01e0 --- /dev/null +++ b/src/collision/ColSphere.cpp @@ -0,0 +1,11 @@ +#include "common.h" +#include "ColSphere.h" + +void +CColSphere::Set(float radius, const CVector ¢er, uint8 surf, uint8 piece) +{ + this->radius = radius; + this->center = center; + this->surface = surf; + this->piece = piece; +} \ No newline at end of file diff --git a/src/collision/ColSphere.h b/src/collision/ColSphere.h new file mode 100644 index 00000000..70e29763 --- /dev/null +++ b/src/collision/ColSphere.h @@ -0,0 +1,13 @@ +#pragma once + +#include "SurfaceTable.h" + +struct CColSphere +{ + // NB: this has to be compatible with a CVuVector + CVector center; + float radius; + uint8 surface; + uint8 piece; + void Set(float radius, const CVector ¢er, uint8 surf = SURFACE_DEFAULT, uint8 piece = 0); +}; \ No newline at end of file diff --git a/src/collision/ColTriangle.cpp b/src/collision/ColTriangle.cpp new file mode 100644 index 00000000..9120fcff --- /dev/null +++ b/src/collision/ColTriangle.cpp @@ -0,0 +1,41 @@ +#include "common.h" +#include "ColTriangle.h" + +void +CColTriangle::Set(const CompressedVector *, int a, int b, int c, uint8 surf, uint8 piece) +{ + this->a = a; + this->b = b; + this->c = c; + this->surface = surf; +} + +#ifdef VU_COLLISION +void +CColTrianglePlane::Set(const CVector &va, const CVector &vb, const CVector &vc) +{ + CVector norm = CrossProduct(vc-va, vb-va); + norm.Normalise(); + float d = DotProduct(norm, va); + normal.x = norm.x*4096.0f; + normal.y = norm.y*4096.0f; + normal.z = norm.z*4096.0f; + dist = d*128.0f; +} +#else +void +CColTrianglePlane::Set(const CVector &va, const CVector &vb, const CVector &vc) +{ + normal = CrossProduct(vc-va, vb-va); + normal.Normalise(); + dist = DotProduct(normal, va); + CVector an(Abs(normal.x), Abs(normal.y), Abs(normal.z)); + // find out largest component and its direction + if(an.x > an.y && an.x > an.z) + dir = normal.x < 0.0f ? DIR_X_NEG : DIR_X_POS; + else if(an.y > an.z) + dir = normal.y < 0.0f ? DIR_Y_NEG : DIR_Y_POS; + else + dir = normal.z < 0.0f ? DIR_Z_NEG : DIR_Z_POS; +} +#endif \ No newline at end of file diff --git a/src/collision/ColTriangle.h b/src/collision/ColTriangle.h new file mode 100644 index 00000000..9e918e38 --- /dev/null +++ b/src/collision/ColTriangle.h @@ -0,0 +1,68 @@ +#pragma once + +#include "CompressedVector.h" + +enum Direction { + DIR_X_POS, + DIR_X_NEG, + DIR_Y_POS, + DIR_Y_NEG, + DIR_Z_POS, + DIR_Z_NEG, +}; + +struct CColTriangle +{ + uint16 a; + uint16 b; + uint16 c; + uint8 surface; + + void Set(const CompressedVector *v, int a, int b, int c, uint8 surf, uint8 piece); +}; + +struct CColTrianglePlane +{ +#ifdef VU_COLLISION + CompressedVector normal; + int16 dist; + + void Set(const CVector &va, const CVector &vb, const CVector &vc); + void Set(const CompressedVector *v, CColTriangle &tri) { Set(v[tri.a].Get(), v[tri.b].Get(), v[tri.c].Get()); } + void GetNormal(CVector &n) const { n.x = normal.x/4096.0f; n.y = normal.y/4096.0f; n.z = normal.z/4096.0f; } + float CalcPoint(const CVector &v) const { CVector n; GetNormal(n); return DotProduct(n, v) - dist/128.0f; }; +#ifdef GTA_PS2 + void Unpack(uint128 &qword) const { + __asm__ volatile ( + "lh $8, 0(%1)\n" + "lh $9, 2(%1)\n" + "lh $10, 4(%1)\n" + "lh $11, 6(%1)\n" + "pextlw $10, $8\n" + "pextlw $11, $9\n" + "pextlw $2, $11, $10\n" + "sq $2, %0\n" + : "=m" (qword) + : "r" (this) + : "$8", "$9", "$10", "$11", "$2" + ); + } +#else + void Unpack(int32 *qword) const { + qword[0] = normal.x; + qword[1] = normal.y; + qword[2] = normal.z; + qword[3] = dist; + } +#endif +#else + CVector normal; + float dist; + uint8 dir; + + void Set(const CVector &va, const CVector &vb, const CVector &vc); + void Set(const CompressedVector *v, CColTriangle &tri) { Set(v[tri.a].Get(), v[tri.b].Get(), v[tri.c].Get()); } + void GetNormal(CVector &n) const { n = normal; } + float CalcPoint(const CVector &v) const { return DotProduct(normal, v) - dist; }; +#endif +}; \ No newline at end of file diff --git a/src/collision/Collision.cpp b/src/collision/Collision.cpp new file mode 100644 index 00000000..41997e32 --- /dev/null +++ b/src/collision/Collision.cpp @@ -0,0 +1,2736 @@ +#include "common.h" + +#include "VuVector.h" +#include "main.h" +#include "Lists.h" +#include "Game.h" +#include "Zones.h" +#include "General.h" +#include "ZoneCull.h" +#include "World.h" +#include "Entity.h" +#include "Train.h" +#include "Streaming.h" +#include "Pad.h" +#include "DMAudio.h" +#include "Population.h" +#include "FileLoader.h" +#include "Replay.h" +#include "CutsceneMgr.h" +#include "RenderBuffer.h" +#include "SurfaceTable.h" +#include "Lines.h" +#include "Collision.h" +#include "Frontend.h" + +#ifdef VU_COLLISION +#include "VuCollision.h" + +inline int +GetVUresult(void) +{ +#ifdef GTA_PS2 + int ret; + __asm__ volatile ( + "cfc2.i %0,vi01\n" // .i important! wait for VU0 to finish + : "=r" (ret) + ); + return ret; +#else + return vi01; +#endif +} + +inline int +GetVUresult(CVuVector &point, CVuVector &normal, float &dist) +{ +#ifdef GTA_PS2 + int ret; + __asm__ volatile ( + "cfc2.i %0,vi01\n" // .i important! wait for VU0 to finish + "sqc2 vf01,(%1)\n" + "sqc2 vf02,(%2)\n" + "qmfc2 $12,vf03\n" + "sw $12,(%3)\n" + : "=r" (ret) + : "r" (&point), "r" (&normal), "r" (&dist) + : "$12" + ); + return ret; +#else + point = vf01; + normal = vf02; + dist = vf03.x; + return vi01; +#endif +} + +#endif + +eLevelName CCollision::ms_collisionInMemory; +CLinkList CCollision::ms_colModelCache; + +void +CCollision::Init(void) +{ + ms_colModelCache.Init(NUMCOLCACHELINKS); + ms_collisionInMemory = LEVEL_GENERIC; +} + +void +CCollision::Shutdown(void) +{ + ms_colModelCache.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); +} + +eLevelName +GetCollisionInSectorList(CPtrList &list) +{ + CPtrNode *node; + CEntity *e; + int level; + + for(node = list.first; node; node = node->next){ + e = (CEntity*)node->item; + level = CModelInfo::GetModelInfo(e->GetModelIndex())->GetColModel()->level; + if(level != LEVEL_GENERIC) + return (eLevelName)level; + } + return LEVEL_GENERIC; +} + +// Get a level this sector is in based on collision models +eLevelName +GetCollisionInSector(CSector §) +{ + int level; + + level = GetCollisionInSectorList(sect.m_lists[ENTITYLIST_BUILDINGS]); + if(level == LEVEL_GENERIC) + level = GetCollisionInSectorList(sect.m_lists[ENTITYLIST_BUILDINGS_OVERLAP]); + if(level == LEVEL_GENERIC) + level = GetCollisionInSectorList(sect.m_lists[ENTITYLIST_OBJECTS]); + if(level == LEVEL_GENERIC) + level = GetCollisionInSectorList(sect.m_lists[ENTITYLIST_OBJECTS_OVERLAP]); + if(level == LEVEL_GENERIC) + level = GetCollisionInSectorList(sect.m_lists[ENTITYLIST_DUMMIES]); + if(level == LEVEL_GENERIC) + level = GetCollisionInSectorList(sect.m_lists[ENTITYLIST_DUMMIES_OVERLAP]); + return (eLevelName)level; +} + +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) { +#ifdef FIX_BUGS + CTimer::Suspend(); +#else + CTimer::Stop(); +#endif + ISLAND_LOADING_IS(LOW) + { + DMAudio.SetEffectsFadeVol(0); + CPad::StopPadsShaking(); + LoadCollisionScreen(CGame::currLevel); + DMAudio.Service(); + } + + CPopulation::DealWithZoneChange(ms_collisionInMemory, CGame::currLevel, false); + + ISLAND_LOADING_ISNT(HIGH) + { + CStreaming::RemoveIslandsNotUsed(LEVEL_INDUSTRIAL); + CStreaming::RemoveIslandsNotUsed(LEVEL_COMMERCIAL); + CStreaming::RemoveIslandsNotUsed(LEVEL_SUBURBAN); + } + ISLAND_LOADING_IS(LOW) + { + 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); + } + + ms_collisionInMemory = CGame::currLevel; + CReplay::EmptyReplayBuffer(); + ISLAND_LOADING_IS(LOW) + { + if (CGame::currLevel != LEVEL_GENERIC) + LoadSplash(GetLevelSplashScreen(CGame::currLevel)); + CStreaming::RemoveUnusedBigBuildings(CGame::currLevel); + CStreaming::RemoveUnusedBuildings(CGame::currLevel); + CStreaming::RequestBigBuildings(CGame::currLevel); + } +#ifdef NO_ISLAND_LOADING + else if (CMenuManager::m_PrefsIslandLoading == CMenuManager::ISLAND_LOADING_MEDIUM) + CStreaming::RequestIslands(CGame::currLevel); +#endif + CStreaming::LoadAllRequestedModels(true); + + ISLAND_LOADING_IS(LOW) + { + CStreaming::HaveAllBigBuildingsLoaded(CGame::currLevel); + + CGame::TidyUpMemory(true, true); + } +#ifdef FIX_BUGS + CTimer::Resume(); +#else + CTimer::Update(); +#endif + ISLAND_LOADING_IS(LOW) + DMAudio.SetEffectsFadeVol(127); + } +} + +#ifdef NO_ISLAND_LOADING +bool CCollision::bAlreadyLoaded = false; +#endif +void +CCollision::SortOutCollisionAfterLoad(void) +{ + if(ms_collisionInMemory == CGame::currLevel) + return; + ISLAND_LOADING_IS(LOW) + CModelInfo::RemoveColModelsFromOtherLevels(CGame::currLevel); + + if (CGame::currLevel != LEVEL_GENERIC) { +#ifdef NO_ISLAND_LOADING + if (CMenuManager::m_PrefsIslandLoading != CMenuManager::ISLAND_LOADING_LOW) { + if (bAlreadyLoaded) { + ms_collisionInMemory = CGame::currLevel; + return; + } + bAlreadyLoaded = true; + CFileLoader::LoadCollisionFromDatFile(LEVEL_INDUSTRIAL); + CFileLoader::LoadCollisionFromDatFile(LEVEL_COMMERCIAL); + CFileLoader::LoadCollisionFromDatFile(LEVEL_SUBURBAN); + } else +#endif + CFileLoader::LoadCollisionFromDatFile(CGame::currLevel); + if(!CGame::playingIntro) + LoadSplash(GetLevelSplashScreen(CGame::currLevel)); + } + ms_collisionInMemory = CGame::currLevel; + CGame::TidyUpMemory(true, false); +} + +void +CCollision::LoadCollisionScreen(eLevelName level) +{ + static Const char *levelNames[4] = { + "", + "IND_ZON", + "COM_ZON", + "SUB_ZON" + }; + + // Why twice? + LoadingIslandScreen(levelNames[level]); + LoadingIslandScreen(levelNames[level]); +} + +// +// Test +// + + +bool +CCollision::TestSphereSphere(const CColSphere &s1, const CColSphere &s2) +{ + float d = s1.radius + s2.radius; + return (s1.center - s2.center).MagnitudeSqr() < d*d; +} + +bool +CCollision::TestSphereBox(const CColSphere &sph, const CColBox &box) +{ + if(sph.center.x + sph.radius < box.min.x) return false; + if(sph.center.x - sph.radius > box.max.x) return false; + if(sph.center.y + sph.radius < box.min.y) return false; + if(sph.center.y - sph.radius > box.max.y) return false; + if(sph.center.z + sph.radius < box.min.z) return false; + if(sph.center.z - sph.radius > box.max.z) return false; + return true; +} + +bool +CCollision::TestLineBox(const CColLine &line, const CColBox &box) +{ + float t, x, y, z; + // If either line point is in the box, we have a collision + if(line.p0.x > box.min.x && line.p0.x < box.max.x && + line.p0.y > box.min.y && line.p0.y < box.max.y && + line.p0.z > box.min.z && line.p0.z < box.max.z) + return true; + if(line.p1.x > box.min.x && line.p1.x < box.max.x && + line.p1.y > box.min.y && line.p1.y < box.max.y && + line.p1.z > box.min.z && line.p1.z < box.max.z) + return true; + + // check if points are on opposite sides of min x plane + if((box.min.x - line.p1.x) * (box.min.x - line.p0.x) < 0.0f){ + // parameter along line where we intersect + t = (box.min.x - line.p0.x) / (line.p1.x - line.p0.x); + // y of intersection + y = line.p0.y + (line.p1.y - line.p0.y)*t; + if(y > box.min.y && y < box.max.y){ + // z of intersection + z = line.p0.z + (line.p1.z - line.p0.z)*t; + if(z > box.min.z && z < box.max.z) + return true; + } + } + + // same test with max x plane + if((line.p1.x - box.max.x) * (line.p0.x - box.max.x) < 0.0f){ + t = (line.p0.x - box.max.x) / (line.p0.x - line.p1.x); + y = line.p0.y + (line.p1.y - line.p0.y)*t; + if(y > box.min.y && y < box.max.y){ + z = line.p0.z + (line.p1.z - line.p0.z)*t; + if(z > box.min.z && z < box.max.z) + return true; + } + } + + // min y plne + if((box.min.y - line.p0.y) * (box.min.y - line.p1.y) < 0.0f){ + t = (box.min.y - line.p0.y) / (line.p1.y - line.p0.y); + x = line.p0.x + (line.p1.x - line.p0.x)*t; + if(x > box.min.x && x < box.max.x){ + z = line.p0.z + (line.p1.z - line.p0.z)*t; + if(z > box.min.z && z < box.max.z) + return true; + } + } + + // max y plane + if((line.p0.y - box.max.y) * (line.p1.y - box.max.y) < 0.0f){ + t = (line.p0.y - box.max.y) / (line.p0.y - line.p1.y); + x = line.p0.x + (line.p1.x - line.p0.x)*t; + if(x > box.min.x && x < box.max.x){ + z = line.p0.z + (line.p1.z - line.p0.z)*t; + if(z > box.min.z && z < box.max.z) + return true; + } + } + + // min z plne + if((box.min.z - line.p0.z) * (box.min.z - line.p1.z) < 0.0f){ + t = (box.min.z - line.p0.z) / (line.p1.z - line.p0.z); + x = line.p0.x + (line.p1.x - line.p0.x)*t; + if(x > box.min.x && x < box.max.x){ + y = line.p0.y + (line.p1.y - line.p0.y)*t; + if(y > box.min.y && y < box.max.y) + return true; + } + } + + // max z plane + if((line.p0.z - box.max.z) * (line.p1.z - box.max.z) < 0.0f){ + t = (line.p0.z - box.max.z) / (line.p0.z - line.p1.z); + x = line.p0.x + (line.p1.x - line.p0.x)*t; + if(x > box.min.x && x < box.max.x){ + y = line.p0.y + (line.p1.y - line.p0.y)*t; + if(y > box.min.y && y < box.max.y) + return true; + } + } + return false; +} + +bool +CCollision::TestVerticalLineBox(const CColLine &line, const CColBox &box) +{ + if(line.p0.x <= box.min.x) return false; + if(line.p0.y <= box.min.y) return false; + if(line.p0.x >= box.max.x) return false; + if(line.p0.y >= box.max.y) return false; + if(line.p0.z < line.p1.z){ + if(line.p0.z > box.max.z) return false; + if(line.p1.z < box.min.z) return false; + }else{ + if(line.p1.z > box.max.z) return false; + if(line.p0.z < box.min.z) return false; + } + return true; +} + +bool +CCollision::TestLineTriangle(const CColLine &line, const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane) +{ +#ifdef VU_COLLISION + // not used in favour of optimized loops + VuTriangle vutri; + verts[tri.a].Unpack(vutri.v0); + verts[tri.b].Unpack(vutri.v1); + verts[tri.c].Unpack(vutri.v2); + plane.Unpack(vutri.plane); + + LineToTriangleCollisionCompressed(*(CVuVector*)&line.p0, *(CVuVector*)&line.p1, vutri); + + if(GetVUresult()) + return true; + return false; +#else + float t; + CVector normal; + plane.GetNormal(normal); + + // if points are on the same side, no collision + if(plane.CalcPoint(line.p0) * plane.CalcPoint(line.p1) > 0.0f) + return false; + + // intersection parameter on line + t = -plane.CalcPoint(line.p0) / DotProduct(line.p1 - line.p0, normal); + // find point of intersection + CVector p = line.p0 + (line.p1-line.p0)*t; + + 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 + // can figure out how to project the vectors. + // normal = (c-a) x (b-a) + switch(plane.dir){ + case DIR_X_POS: + vec1.x = va.y; vec1.y = va.z; + vec2.x = vc.y; vec2.y = vc.z; + vec3.x = vb.y; vec3.y = vb.z; + vect.x = p.y; vect.y = p.z; + break; + case DIR_X_NEG: + vec1.x = va.y; vec1.y = va.z; + vec2.x = vb.y; vec2.y = vb.z; + vec3.x = vc.y; vec3.y = vc.z; + vect.x = p.y; vect.y = p.z; + break; + case DIR_Y_POS: + vec1.x = va.z; vec1.y = va.x; + vec2.x = vc.z; vec2.y = vc.x; + vec3.x = vb.z; vec3.y = vb.x; + vect.x = p.z; vect.y = p.x; + break; + case DIR_Y_NEG: + vec1.x = va.z; vec1.y = va.x; + vec2.x = vb.z; vec2.y = vb.x; + vec3.x = vc.z; vec3.y = vc.x; + vect.x = p.z; vect.y = p.x; + break; + case DIR_Z_POS: + vec1.x = va.x; vec1.y = va.y; + vec2.x = vc.x; vec2.y = vc.y; + vec3.x = vb.x; vec3.y = vb.y; + vect.x = p.x; vect.y = p.y; + break; + case DIR_Z_NEG: + vec1.x = va.x; vec1.y = va.y; + vec2.x = vb.x; vec2.y = vb.y; + vec3.x = vc.x; vec3.y = vc.y; + vect.x = p.x; vect.y = p.y; + break; + default: + assert(0); + } + // This is our triangle: + // 3-------2 + // \ P / + // \ / + // \ / + // 1 + // We can use the "2d cross product" to check on which side + // a vector is of another. Test is true if point is inside of all edges. + 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; + return true; +#endif +} + +// Test if line segment intersects with sphere. +// If the first point is inside the sphere this test does not register a collision! +// The code is reversed from the original code and rather ugly, see Process for a clear version. +// TODO: actually rewrite this mess +bool +CCollision::TestLineSphere(const CColLine &line, const CColSphere &sph) +{ + CVector v01 = line.p1 - line.p0; // vector from p0 to p1 + CVector v0c = sph.center - line.p0; // vector from p0 to center + float linesq = v01.MagnitudeSqr(); + // I leave in the strange -2 factors even though they serve no real purpose + float projline = -2.0f * DotProduct(v01, v0c); // project v0c onto line + // Square of tangent from p0 multiplied by line length so we can compare with projline. + // The length of the tangent would be this: Sqrt((c-p0)^2 - r^2). + // Negative if p0 is inside the sphere! This breaks the test! + float tansq = 4.0f * linesq * + (sph.center.MagnitudeSqr() - 2.0f*DotProduct(sph.center, line.p0) + line.p0.MagnitudeSqr() - sph.radius*sph.radius); + float diffsq = projline*projline - tansq; + // if diffsq < 0 that means the line is a passant, so no intersection + if(diffsq < 0.0f) + return false; + // projline (negative in GTA for some reason) is the point on the line + // in the middle of the two intersection points (startin from p0). + // Sqrt(diffsq) somehow works out to be the distance from that + // midpoint to the intersection points. + // So subtract that and get rid of the awkward scaling: + float f = (-projline - Sqrt(diffsq)) / (2.0f*linesq); + // f should now be in range [0, 1] for [p0, p1] + return f >= 0.0f && f <= 1.0f; +} + +bool +CCollision::TestSphereTriangle(const CColSphere &sphere, + const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane) +{ +#ifdef VU_COLLISION + // not used in favour of optimized loops + VuTriangle vutri; + verts[tri.a].Unpack(vutri.v0); + verts[tri.b].Unpack(vutri.v1); + verts[tri.c].Unpack(vutri.v2); + plane.Unpack(vutri.plane); + + SphereToTriangleCollisionCompressed(*(CVuVector*)&sphere, vutri); + + if(GetVUresult()) + return true; + return false; +#else + // If sphere and plane don't intersect, no collision + float planedist = plane.CalcPoint(sphere.center); + if(Abs(planedist) > sphere.radius) + return false; + + 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; + float len = vec2.Magnitude(); + vec2 = vec2 * (1.0f/len); + CVector normal; + plane.GetNormal(normal); + CVector vec1 = CrossProduct(vec2, normal); + + // We know A has local coordinate [0,0] and B has [0,len]. + // Now calculate coordinates on triangle for these two vectors: + CVector vac = vc - va; + CVector vas = sphere.center - va; + CVector2D b(0.0f, len); + CVector2D c(DotProduct(vec1, vac), DotProduct(vec2, vac)); + CVector2D s(DotProduct(vec1, vas), DotProduct(vec2, vas)); + + // The three triangle lines partition the space into 6 sectors, + // find out in which the center lies. + int insideAB = CrossProduct2D(s, b) >= 0.0f; + int insideAC = CrossProduct2D(c, s) >= 0.0f; + int insideBC = CrossProduct2D(s-b, c-b) >= 0.0f; + + int testcase = insideAB + insideAC + insideBC; + float dist = 0.0f; + 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); + 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); + break; + case 3: + // center is in triangle + dist = Abs(planedist); + break; + default: + assert(0); + } + + return dist < sphere.radius; +#endif +} + +bool +CCollision::TestLineOfSight(const CColLine &line, const CMatrix &matrix, CColModel &model, bool ignoreSeeThrough) +{ +#ifdef VU_COLLISION + CMatrix matTransform; + int i; + + // transform line to model space + Invert(matrix, matTransform); + CVuVector newline[2]; + TransformPoints(newline, 2, matTransform, (RwV3d*)&line.p0, sizeof(CColLine)/2); + + // If we don't intersect with the bounding box, no chance on the rest + if(!TestLineBox(*(CColLine*)newline, model.boundingBox)) + return false; + + for(i = 0; i < model.numSpheres; i++){ + if(ignoreSeeThrough && IsSeeThrough(model.spheres[i].surface)) continue; + if(TestLineSphere(*(CColLine*)newline, model.spheres[i])) + return true; + } + + for(i = 0; i < model.numBoxes; i++){ + if(ignoreSeeThrough && IsSeeThrough(model.boxes[i].surface)) continue; + if(TestLineBox(*(CColLine*)newline, model.boxes[i])) + return true; + } + + CalculateTrianglePlanes(&model); + int lastTest = -1; + VuTriangle vutri; + for(i = 0; i < model.numTriangles; i++){ + if(ignoreSeeThrough && IsSeeThrough(model.triangles[i].surface)) continue; + + CColTriangle *tri = &model.triangles[i]; + model.vertices[tri->a].Unpack(vutri.v0); + model.vertices[tri->b].Unpack(vutri.v1); + model.vertices[tri->c].Unpack(vutri.v2); + model.trianglePlanes[i].Unpack(vutri.plane); + + LineToTriangleCollisionCompressed(newline[0], newline[1], vutri); + lastTest = i; + break; + } +#ifdef FIX_BUGS + // no need to check first again + i++; +#endif + for(; i < model.numTriangles; i++){ + if(ignoreSeeThrough && IsSeeThrough(model.triangles[i].surface)) continue; + + CColTriangle *tri = &model.triangles[i]; + model.vertices[tri->a].Unpack(vutri.v0); + model.vertices[tri->b].Unpack(vutri.v1); + model.vertices[tri->c].Unpack(vutri.v2); + model.trianglePlanes[i].Unpack(vutri.plane); + + if(GetVUresult()) + return true; + + LineToTriangleCollisionCompressed(newline[0], newline[1], vutri); + lastTest = i; + + } + if(lastTest != -1 && GetVUresult()) + return true; + + return false; +#else + static CMatrix matTransform; + int i; + + // transform line to model space + Invert(matrix, matTransform); + CColLine newline(matTransform * line.p0, matTransform * line.p1); + + // If we don't intersect with the bounding box, no chance on the rest + if(!TestLineBox(newline, model.boundingBox)) + return false; + + 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 && 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 && IsSeeThrough(model.triangles[i].surface)) continue; + if(TestLineTriangle(newline, model.vertices, model.triangles[i], model.trianglePlanes[i])) + return true; + } + + return false; +#endif +} + + +// +// Process +// + +// For Spheres mindist is the squared distance to its center +// For Lines mindist is between [0,1] + +bool +CCollision::ProcessSphereSphere(const CColSphere &s1, const CColSphere &s2, CColPoint &point, float &mindistsq) +{ + CVector dist = s1.center - s2.center; + float d = dist.Magnitude() - s2.radius; // distance from s1's center to s2 + float depth = s1.radius - d; // sphere overlap + if(d < 0.0f) d = 0.0f; // clamp to zero, i.e. if s1's center is inside s2 + // no collision if sphere is not close enough + if(d*d < mindistsq && d < s1.radius){ + dist.Normalise(); + point.point = s1.center - dist*d; + point.normal = dist; +#ifndef VU_COLLISION + point.surfaceA = s1.surface; + point.pieceA = s1.piece; + point.surfaceB = s2.surface; + point.pieceB = s2.piece; +#endif + point.depth = depth; + mindistsq = d*d; // collision radius + return true; + } + return false; +} + +bool +CCollision::ProcessSphereBox(const CColSphere &sph, const CColBox &box, CColPoint &point, float &mindistsq) +{ + CVector p; + CVector dist; + + // GTA's code is too complicated, uses a huge 3x3x3 if statement + // we can simplify the structure a lot + + // first make sure we have a collision at all + if(sph.center.x + sph.radius < box.min.x) return false; + if(sph.center.x - sph.radius > box.max.x) return false; + if(sph.center.y + sph.radius < box.min.y) return false; + if(sph.center.y - sph.radius > box.max.y) return false; + if(sph.center.z + sph.radius < box.min.z) return false; + if(sph.center.z - sph.radius > box.max.z) return false; + + // Now find out where the sphere center lies in relation to all the sides + int xpos = sph.center.x < box.min.x ? 1 : + sph.center.x > box.max.x ? 2 : + 0; + int ypos = sph.center.y < box.min.y ? 1 : + sph.center.y > box.max.y ? 2 : + 0; + int zpos = sph.center.z < box.min.z ? 1 : + sph.center.z > box.max.z ? 2 : + 0; + + if(xpos == 0 && ypos == 0 && zpos == 0){ + // sphere is inside the box + p = (box.min + box.max)*0.5f; + + dist = sph.center - p; + float lensq = dist.MagnitudeSqr(); + if(lensq < mindistsq){ + point.normal = dist * (1.0f/Sqrt(lensq)); + point.point = sph.center - point.normal; +#ifndef VU_COLLISION + point.surfaceA = sph.surface; + point.pieceA = sph.piece; + point.surfaceB = box.surface; + point.pieceB = box.piece; +#endif + + // find absolute distance to the closer side in each dimension + float dx = dist.x > 0.0f ? + box.max.x - sph.center.x : + sph.center.x - box.min.x; + float dy = dist.y > 0.0f ? + box.max.y - sph.center.y : + sph.center.y - box.min.y; + float dz = dist.z > 0.0f ? + box.max.z - sph.center.z : + sph.center.z - box.min.z; + // collision depth is maximum of that: + if(dx > dy && dx > dz) + point.depth = dx; + else if(dy > dz) + point.depth = dy; + else + point.depth = dz; + return true; + } + }else{ + // sphere is outside. + // closest point on box: + p.x = xpos == 1 ? box.min.x : + xpos == 2 ? box.max.x : + sph.center.x; + p.y = ypos == 1 ? box.min.y : + ypos == 2 ? box.max.y : + sph.center.y; + p.z = zpos == 1 ? box.min.z : + zpos == 2 ? box.max.z : + sph.center.z; + + dist = sph.center - p; + float lensq = dist.MagnitudeSqr(); + if(lensq < mindistsq){ + float len = Sqrt(lensq); + point.point = p; + point.normal = dist * (1.0f/len); +#ifndef VU_COLLISION + point.surfaceA = sph.surface; + point.pieceA = sph.piece; + point.surfaceB = box.surface; + point.pieceB = box.piece; +#endif + point.depth = sph.radius - len; + mindistsq = lensq; + return true; + } + } + return false; +} + +bool +CCollision::ProcessLineBox(const CColLine &line, const CColBox &box, CColPoint &point, float &mindist) +{ + float mint, t, x, y, z; + CVector normal; + CVector p; + + mint = 1.0f; + // check if points are on opposite sides of min x plane + if((box.min.x - line.p1.x) * (box.min.x - line.p0.x) < 0.0f){ + // parameter along line where we intersect + t = (box.min.x - line.p0.x) / (line.p1.x - line.p0.x); + // y of intersection + y = line.p0.y + (line.p1.y - line.p0.y)*t; + if(y > box.min.y && y < box.max.y){ + // z of intersection + z = line.p0.z + (line.p1.z - line.p0.z)*t; + if(z > box.min.z && z < box.max.z) + if(t < mint){ + mint = t; + p = CVector(box.min.x, y, z); + normal = CVector(-1.0f, 0.0f, 0.0f); + } + } + } + + // max x plane + if((line.p1.x - box.max.x) * (line.p0.x - box.max.x) < 0.0f){ + t = (line.p0.x - box.max.x) / (line.p0.x - line.p1.x); + y = line.p0.y + (line.p1.y - line.p0.y)*t; + if(y > box.min.y && y < box.max.y){ + z = line.p0.z + (line.p1.z - line.p0.z)*t; + if(z > box.min.z && z < box.max.z) + if(t < mint){ + mint = t; + p = CVector(box.max.x, y, z); + normal = CVector(1.0f, 0.0f, 0.0f); + } + } + } + + // min y plne + if((box.min.y - line.p0.y) * (box.min.y - line.p1.y) < 0.0f){ + t = (box.min.y - line.p0.y) / (line.p1.y - line.p0.y); + x = line.p0.x + (line.p1.x - line.p0.x)*t; + if(x > box.min.x && x < box.max.x){ + z = line.p0.z + (line.p1.z - line.p0.z)*t; + if(z > box.min.z && z < box.max.z) + if(t < mint){ + mint = t; + p = CVector(x, box.min.y, z); + normal = CVector(0.0f, -1.0f, 0.0f); + } + } + } + + // max y plane + if((line.p0.y - box.max.y) * (line.p1.y - box.max.y) < 0.0f){ + t = (line.p0.y - box.max.y) / (line.p0.y - line.p1.y); + x = line.p0.x + (line.p1.x - line.p0.x)*t; + if(x > box.min.x && x < box.max.x){ + z = line.p0.z + (line.p1.z - line.p0.z)*t; + if(z > box.min.z && z < box.max.z) + if(t < mint){ + mint = t; + p = CVector(x, box.max.y, z); + normal = CVector(0.0f, 1.0f, 0.0f); + } + } + } + + // min z plne + if((box.min.z - line.p0.z) * (box.min.z - line.p1.z) < 0.0f){ + t = (box.min.z - line.p0.z) / (line.p1.z - line.p0.z); + x = line.p0.x + (line.p1.x - line.p0.x)*t; + if(x > box.min.x && x < box.max.x){ + y = line.p0.y + (line.p1.y - line.p0.y)*t; + if(y > box.min.y && y < box.max.y) + if(t < mint){ + mint = t; + p = CVector(x, y, box.min.z); + normal = CVector(0.0f, 0.0f, -1.0f); + } + } + } + + // max z plane + if((line.p0.z - box.max.z) * (line.p1.z - box.max.z) < 0.0f){ + t = (line.p0.z - box.max.z) / (line.p0.z - line.p1.z); + x = line.p0.x + (line.p1.x - line.p0.x)*t; + if(x > box.min.x && x < box.max.x){ + y = line.p0.y + (line.p1.y - line.p0.y)*t; + if(y > box.min.y && y < box.max.y) + if(t < mint){ + mint = t; + p = CVector(x, y, box.max.z); + normal = CVector(0.0f, 0.0f, 1.0f); + } + } + } + + if(mint >= mindist) + return false; + + point.point = p; + point.normal = normal; +#ifndef VU_COLLISION + point.surfaceA = 0; + point.pieceA = 0; + point.surfaceB = box.surface; + point.pieceB = box.piece; +#endif + mindist = mint; + + return true; +} + +// If line.p0 lies inside sphere, no collision is registered. +bool +CCollision::ProcessLineSphere(const CColLine &line, const CColSphere &sphere, CColPoint &point, float &mindist) +{ + CVector v01 = line.p1 - line.p0; + CVector v0c = sphere.center - line.p0; + float linesq = v01.MagnitudeSqr(); + // project v0c onto v01, scaled by |v01| this is the midpoint of the two intersections + float projline = DotProduct(v01, v0c); + // tangent of p0 to sphere, scaled by linesq just like projline^2 + float tansq = (v0c.MagnitudeSqr() - sphere.radius*sphere.radius) * linesq; + // this works out to be the square of the distance between the midpoint and the intersections + float diffsq = projline*projline - tansq; + // no intersection + if(diffsq < 0.0f) + return false; + // point of first intersection, in range [0,1] between p0 and p1 + float t = (projline - Sqrt(diffsq)) / linesq; + // if not on line or beyond mindist, no intersection + if(t < 0.0f || t > 1.0f || t >= mindist) + return false; + point.point = line.p0 + v01*t; + point.normal = point.point - sphere.center; + point.normal.Normalise(); +#ifndef VU_COLLISION + point.surfaceA = 0; + point.pieceA = 0; + point.surfaceB = sphere.surface; + point.pieceB = sphere.piece; +#endif + mindist = t; + return true; +} + +bool +CCollision::ProcessVerticalLineTriangle(const CColLine &line, + const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, + CColPoint &point, float &mindist, CStoredCollPoly *poly) +{ +#ifdef VU_COLLISION + // not used in favour of optimized loops + bool res = ProcessLineTriangle(line, verts, tri, plane, point, mindist); + if(res && poly){ + poly->verts[0] = verts[tri.a].Get(); + poly->verts[1] = verts[tri.b].Get(); + poly->verts[2] = verts[tri.c].Get(); + poly->valid = true; + } + return res; +#else + float t; + CVector normal; + + const CVector &p0 = line.p0; + 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; + if(p0.x > va.x && p0.x > vb.x && p0.x > vc.x) return false; + if(p0.y < va.y && p0.y < vb.y && p0.y < vc.y) return false; + if(p0.y > va.y && p0.y > vb.y && p0.y > vc.y) return false; + + plane.GetNormal(normal); + // if points are on the same side, no collision + if(plane.CalcPoint(p0) * plane.CalcPoint(line.p1) > 0.0f) + return false; + + // intersection parameter on line + float h = (line.p1 - p0).z; + t = -plane.CalcPoint(p0) / (h * normal.z); + // early out if we're beyond the mindist + if(t >= mindist) + return false; + CVector p(p0.x, p0.y, p0.z + h*t); + + CVector2D vec1, vec2, vec3, vect; + switch(plane.dir){ + case DIR_X_POS: + vec1.x = va.y; vec1.y = va.z; + vec2.x = vc.y; vec2.y = vc.z; + vec3.x = vb.y; vec3.y = vb.z; + vect.x = p.y; vect.y = p.z; + break; + case DIR_X_NEG: + vec1.x = va.y; vec1.y = va.z; + vec2.x = vb.y; vec2.y = vb.z; + vec3.x = vc.y; vec3.y = vc.z; + vect.x = p.y; vect.y = p.z; + break; + case DIR_Y_POS: + vec1.x = va.z; vec1.y = va.x; + vec2.x = vc.z; vec2.y = vc.x; + vec3.x = vb.z; vec3.y = vb.x; + vect.x = p.z; vect.y = p.x; + break; + case DIR_Y_NEG: + vec1.x = va.z; vec1.y = va.x; + vec2.x = vb.z; vec2.y = vb.x; + vec3.x = vc.z; vec3.y = vc.x; + vect.x = p.z; vect.y = p.x; + break; + case DIR_Z_POS: + vec1.x = va.x; vec1.y = va.y; + vec2.x = vc.x; vec2.y = vc.y; + vec3.x = vb.x; vec3.y = vb.y; + vect.x = p.x; vect.y = p.y; + break; + case DIR_Z_NEG: + vec1.x = va.x; vec1.y = va.y; + vec2.x = vb.x; vec2.y = vb.y; + vec3.x = vc.x; vec3.y = vc.y; + vect.x = p.x; vect.y = p.y; + break; + default: + assert(0); + } + 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; + 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; +#endif +} + +bool +CCollision::IsStoredPolyStillValidVerticalLine(const CVector &pos, float z, CColPoint &point, CStoredCollPoly *poly) +{ +#ifdef VU_COLLISION + if(!poly->valid) + return false; + + CVuVector p0 = pos; + CVuVector p1 = pos; + p1.z = z; + + CVector v01 = poly->verts[1] - poly->verts[0]; + CVector v02 = poly->verts[2] - poly->verts[0]; + CVuVector plane = CrossProduct(v02, v01); + plane.Normalise(); + plane.w = DotProduct(plane, poly->verts[0]); + + LineToTriangleCollision(p0, p1, poly->verts[0], poly->verts[1], poly->verts[2], plane); + + CVuVector pnt; + float dist; + if(!GetVUresult(pnt, plane, dist)) +#ifdef FIX_BUGS + // perhaps not needed but be safe + return poly->valid = false; +#else + return false; +#endif + point.point = pnt; + return true; +#else + float t; + + if(!poly->valid) + return false; + + // maybe inlined? + CColTrianglePlane plane; + plane.Set(poly->verts[0], poly->verts[1], poly->verts[2]); + + 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); + + // The rest is pretty much CCollision::ProcessLineTriangle + + // if points are on the same side, no collision + if(plane.CalcPoint(p0) * plane.CalcPoint(p1) > 0.0f) + return poly->valid = false; + + // intersection parameter on line + CVector normal; + plane.GetNormal(normal); + t = -plane.CalcPoint(p0) / DotProduct(p1 - p0, normal); + // find point of intersection + CVector p = p0 + (p1-p0)*t; + + CVector2D vec1, vec2, vec3, vect; + switch(plane.dir){ + case DIR_X_POS: + vec1.x = va.y; vec1.y = va.z; + vec2.x = vc.y; vec2.y = vc.z; + vec3.x = vb.y; vec3.y = vb.z; + vect.x = p.y; vect.y = p.z; + break; + case DIR_X_NEG: + vec1.x = va.y; vec1.y = va.z; + vec2.x = vb.y; vec2.y = vb.z; + vec3.x = vc.y; vec3.y = vc.z; + vect.x = p.y; vect.y = p.z; + break; + case DIR_Y_POS: + vec1.x = va.z; vec1.y = va.x; + vec2.x = vc.z; vec2.y = vc.x; + vec3.x = vb.z; vec3.y = vb.x; + vect.x = p.z; vect.y = p.x; + break; + case DIR_Y_NEG: + vec1.x = va.z; vec1.y = va.x; + vec2.x = vb.z; vec2.y = vb.x; + vec3.x = vc.z; vec3.y = vc.x; + vect.x = p.z; vect.y = p.x; + break; + case DIR_Z_POS: + vec1.x = va.x; vec1.y = va.y; + vec2.x = vc.x; vec2.y = vc.y; + vec3.x = vb.x; vec3.y = vb.y; + vect.x = p.x; vect.y = p.y; + break; + case DIR_Z_NEG: + vec1.x = va.x; vec1.y = va.y; + vec2.x = vb.x; vec2.y = vb.y; + vec3.x = vc.x; vec3.y = vc.y; + vect.x = p.x; vect.y = p.y; + break; + default: + assert(0); + } + if(CrossProduct2D(vec2-vec1, vect-vec1) < 0.0f) return poly->valid = false; + if(CrossProduct2D(vec3-vec1, vect-vec1) > 0.0f) return poly->valid = false; + if(CrossProduct2D(vec3-vec2, vect-vec2) < 0.0f) return poly->valid = false; + point.point = p; + return poly->valid = true; +#endif +} + +bool +CCollision::ProcessLineTriangle(const CColLine &line, + const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, + CColPoint &point, float &mindist) +{ +#ifdef VU_COLLISION + // not used in favour of optimized loops + VuTriangle vutri; + verts[tri.a].Unpack(vutri.v0); + verts[tri.b].Unpack(vutri.v1); + verts[tri.c].Unpack(vutri.v2); + plane.Unpack(vutri.plane); + + LineToTriangleCollisionCompressed(*(CVuVector*)&line.p0, *(CVuVector*)&line.p1, vutri); + + CVuVector pnt, normal; + float dist; + if(GetVUresult(pnt, normal, dist)){ + if(dist < mindist){ + point.point = pnt; + point.normal = normal; + mindist = dist; + return true; + } + } + return false; +#else + float t; + CVector normal; + plane.GetNormal(normal); + + // if points are on the same side, no collision + if(plane.CalcPoint(line.p0) * plane.CalcPoint(line.p1) > 0.0f) + return false; + + // intersection parameter on line + t = -plane.CalcPoint(line.p0) / DotProduct(line.p1 - line.p0, normal); + // early out if we're beyond the mindist + if(t >= mindist) + return false; + // find point of intersection + CVector p = line.p0 + (line.p1-line.p0)*t; + + 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){ + case DIR_X_POS: + vec1.x = va.y; vec1.y = va.z; + vec2.x = vc.y; vec2.y = vc.z; + vec3.x = vb.y; vec3.y = vb.z; + vect.x = p.y; vect.y = p.z; + break; + case DIR_X_NEG: + vec1.x = va.y; vec1.y = va.z; + vec2.x = vb.y; vec2.y = vb.z; + vec3.x = vc.y; vec3.y = vc.z; + vect.x = p.y; vect.y = p.z; + break; + case DIR_Y_POS: + vec1.x = va.z; vec1.y = va.x; + vec2.x = vc.z; vec2.y = vc.x; + vec3.x = vb.z; vec3.y = vb.x; + vect.x = p.z; vect.y = p.x; + break; + case DIR_Y_NEG: + vec1.x = va.z; vec1.y = va.x; + vec2.x = vb.z; vec2.y = vb.x; + vec3.x = vc.z; vec3.y = vc.x; + vect.x = p.z; vect.y = p.x; + break; + case DIR_Z_POS: + vec1.x = va.x; vec1.y = va.y; + vec2.x = vc.x; vec2.y = vc.y; + vec3.x = vb.x; vec3.y = vb.y; + vect.x = p.x; vect.y = p.y; + break; + case DIR_Z_NEG: + vec1.x = va.x; vec1.y = va.y; + vec2.x = vb.x; vec2.y = vb.y; + vec3.x = vc.x; vec3.y = vc.y; + vect.x = p.x; vect.y = p.y; + break; + default: + assert(0); + } + 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; + point.pieceA = 0; + point.surfaceB = tri.surface; + point.pieceB = 0; + mindist = t; + return true; +#endif +} + +bool +CCollision::ProcessSphereTriangle(const CColSphere &sphere, + const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, + CColPoint &point, float &mindistsq) +{ +#ifdef VU_COLLISION + // not used in favour of optimized loops + VuTriangle vutri; + verts[tri.a].Unpack(vutri.v0); + verts[tri.b].Unpack(vutri.v1); + verts[tri.c].Unpack(vutri.v2); + plane.Unpack(vutri.plane); + + SphereToTriangleCollisionCompressed(*(CVuVector*)&sphere, vutri); + + CVuVector pnt, normal; + float dist; + if(GetVUresult(pnt, normal, dist) && dist*dist < mindistsq){ + float depth = sphere.radius - dist; + if(depth > point.depth){ + point.point = pnt; + point.normal = normal; + point.depth = depth; + mindistsq = dist*dist; + return true; + } + } + return false; +#else + // If sphere and plane don't intersect, no collision + float planedist = plane.CalcPoint(sphere.center); + float distsq = planedist*planedist; + if(Abs(planedist) > sphere.radius || distsq > mindistsq) + return false; + + 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; + plane.GetNormal(normal); + CVector vec2 = vb - va; + float len = vec2.Magnitude(); + vec2 = vec2 * (1.0f/len); + CVector vec1 = CrossProduct(vec2, normal); + + // We know A has local coordinate [0,0] and B has [0,len]. + // Now calculate coordinates on triangle for these two vectors: + CVector vac = vc - va; + CVector vas = sphere.center - va; + CVector2D b(0.0f, len); + CVector2D c(DotProduct(vec1, vac), DotProduct(vec2, vac)); + CVector2D s(DotProduct(vec1, vas), DotProduct(vec2, vas)); + + // The three triangle lines partition the space into 6 sectors, + // find out in which the center lies. + int insideAB = CrossProduct2D(s, b) >= 0.0f; + int insideAC = CrossProduct2D(c, s) >= 0.0f; + int insideBC = CrossProduct2D(s-b, c-b) >= 0.0f; + + int testcase = insideAB + insideAC + insideBC; + float dist = 0.0f; + CVector p; + 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(); + 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); + break; + case 3: + // center is in triangle + dist = Abs(planedist); + p = sphere.center - normal*planedist; + break; + default: + assert(0); + } + + if(dist >= sphere.radius || dist*dist >= mindistsq) + return false; + + point.point = p; + point.normal = sphere.center - p; + point.normal.Normalise(); +#ifndef VU_COLLISION + point.surfaceA = sphere.surface; + point.pieceA = sphere.piece; + point.surfaceB = tri.surface; + point.pieceB = 0; +#endif + point.depth = sphere.radius - dist; + mindistsq = dist*dist; + return true; +#endif +} + +bool +CCollision::ProcessLineOfSight(const CColLine &line, + const CMatrix &matrix, CColModel &model, + CColPoint &point, float &mindist, bool ignoreSeeThrough) +{ +#ifdef VU_COLLISION + CMatrix matTransform; + int i; + + // transform line to model space + Invert(matrix, matTransform); + CVuVector newline[2]; + TransformPoints(newline, 2, matTransform, (RwV3d*)&line.p0, sizeof(CColLine)/2); + + if(mindist < 1.0f) + newline[1] = newline[0] + (newline[1] - newline[0])*mindist; + + // If we don't intersect with the bounding box, no chance on the rest + if(!TestLineBox(*(CColLine*)newline, model.boundingBox)) + return false; + + float coldist = 1.0f; + for(i = 0; i < model.numSpheres; i++){ + if(ignoreSeeThrough && IsSeeThrough(model.spheres[i].surface)) continue; + if(ProcessLineSphere(*(CColLine*)newline, model.spheres[i], point, coldist)) + point.Set(0, 0, model.spheres[i].surface, model.spheres[i].piece); + } + + for(i = 0; i < model.numBoxes; i++){ + if(ignoreSeeThrough && IsSeeThrough(model.boxes[i].surface)) continue; + if(ProcessLineBox(*(CColLine*)newline, model.boxes[i], point, coldist)) + point.Set(0, 0, model.boxes[i].surface, model.boxes[i].piece); + } + + CalculateTrianglePlanes(&model); + VuTriangle vutri; + CColTriangle *lasttri = nil; + for(i = 0; i < model.numTriangles; i++){ + if(ignoreSeeThrough && IsSeeThrough(model.triangles[i].surface)) continue; + + CColTriangle *tri = &model.triangles[i]; + model.vertices[tri->a].Unpack(vutri.v0); + model.vertices[tri->b].Unpack(vutri.v1); + model.vertices[tri->c].Unpack(vutri.v2); + model.trianglePlanes[i].Unpack(vutri.plane); + + LineToTriangleCollisionCompressed(newline[0], newline[1], vutri); + lasttri = tri; + break; + } +#ifdef FIX_BUGS + // no need to check first again + i++; +#endif + CVuVector pnt, normal; + float dist; + for(; i < model.numTriangles; i++){ + if(ignoreSeeThrough && IsSeeThrough(model.triangles[i].surface)) continue; + + CColTriangle *tri = &model.triangles[i]; + model.vertices[tri->a].Unpack(vutri.v0); + model.vertices[tri->b].Unpack(vutri.v1); + model.vertices[tri->c].Unpack(vutri.v2); + model.trianglePlanes[i].Unpack(vutri.plane); + + if(GetVUresult(pnt, normal, dist)) + if(dist < coldist){ + point.point = pnt; + point.normal = normal; + point.Set(0, 0, lasttri->surface, 0); + coldist = dist; + } + + LineToTriangleCollisionCompressed(newline[0], newline[1], vutri); + lasttri = tri; + } + if(lasttri && GetVUresult(pnt, normal, dist)) + if(dist < coldist){ + point.point = pnt; + point.normal = normal; + point.Set(0, 0, lasttri->surface, 0); + coldist = dist; + } + + + if(coldist < 1.0f){ + point.point = matrix * point.point; + point.normal = Multiply3x3(matrix, point.normal); + mindist *= coldist; + return true; + } + return false; +#else + static CMatrix matTransform; + int i; + + // transform line to model space + Invert(matrix, matTransform); + CColLine newline(matTransform * line.p0, matTransform * line.p1); + + // If we don't intersect with the bounding box, no chance on the rest + if(!TestLineBox(newline, model.boundingBox)) + return false; + + float coldist = mindist; + 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 && IsSeeThrough(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; + ProcessLineTriangle(newline, model.vertices, model.triangles[i], model.trianglePlanes[i], point, coldist); + } + + if(coldist < mindist){ + point.point = matrix * point.point; + point.normal = Multiply3x3(matrix, point.normal); + mindist = coldist; + return true; + } + return false; +#endif +} + +bool +CCollision::ProcessVerticalLine(const CColLine &line, + const CMatrix &matrix, CColModel &model, + CColPoint &point, float &mindist, bool ignoreSeeThrough, CStoredCollPoly *poly) +{ +#ifdef VU_COLLISION + static CStoredCollPoly TempStoredPoly; + CMatrix matTransform; + int i; + + // transform line to model space + Invert(matrix, matTransform); + CVuVector newline[2]; + TransformPoints(newline, 2, matTransform, (RwV3d*)&line.p0, sizeof(CColLine)/2); + + if(mindist < 1.0f) + newline[1] = newline[0] + (newline[1] - newline[0])*mindist; + + if(!TestLineBox(*(CColLine*)newline, model.boundingBox)) + return false; + + float coldist = 1.0f; + for(i = 0; i < model.numSpheres; i++){ + if(ignoreSeeThrough && IsSeeThrough(model.spheres[i].surface)) continue; + if(ProcessLineSphere(*(CColLine*)newline, model.spheres[i], point, coldist)) + point.Set(0, 0, model.spheres[i].surface, model.spheres[i].piece); + } + + for(i = 0; i < model.numBoxes; i++){ + if(ignoreSeeThrough && IsSeeThrough(model.boxes[i].surface)) continue; + if(ProcessLineBox(*(CColLine*)newline, model.boxes[i], point, coldist)) + point.Set(0, 0, model.boxes[i].surface, model.boxes[i].piece); + } + + CalculateTrianglePlanes(&model); + TempStoredPoly.valid = false; + if(model.numTriangles){ + bool registeredCol; + CColTriangle *lasttri = nil; + VuTriangle vutri; + for(i = 0; i < model.numTriangles; i++){ + if(ignoreSeeThrough && IsSeeThrough(model.triangles[i].surface)) continue; + + CColTriangle *tri = &model.triangles[i]; + model.vertices[tri->a].Unpack(vutri.v0); + model.vertices[tri->b].Unpack(vutri.v1); + model.vertices[tri->c].Unpack(vutri.v2); + model.trianglePlanes[i].Unpack(vutri.plane); + + LineToTriangleCollisionCompressed(newline[0], newline[1], vutri); + lasttri = tri; + break; + } +#ifdef FIX_BUGS + // no need to check first again + i++; +#endif + CVuVector pnt, normal; + float dist; + for(; i < model.numTriangles; i++){ + if(ignoreSeeThrough && IsSeeThrough(model.triangles[i].surface)) continue; + + CColTriangle *tri = &model.triangles[i]; + model.vertices[tri->a].Unpack(vutri.v0); + model.vertices[tri->b].Unpack(vutri.v1); + model.vertices[tri->c].Unpack(vutri.v2); + model.trianglePlanes[i].Unpack(vutri.plane); + + if(GetVUresult(pnt, normal, dist)){ + if(dist < coldist){ + point.point = pnt; + point.normal = normal; + point.Set(0, 0, lasttri->surface, 0); + coldist = dist; + registeredCol = true; + }else + registeredCol = false; + }else + registeredCol = false; + + if(registeredCol){ + TempStoredPoly.verts[0] = model.vertices[lasttri->a].Get(); + TempStoredPoly.verts[1] = model.vertices[lasttri->b].Get(); + TempStoredPoly.verts[2] = model.vertices[lasttri->c].Get(); + TempStoredPoly.valid = true; + } + + LineToTriangleCollisionCompressed(newline[0], newline[1], vutri); + lasttri = tri; + } + if(lasttri && GetVUresult(pnt, normal, dist)){ + if(dist < coldist){ + point.point = pnt; + point.normal = normal; + point.Set(0, 0, lasttri->surface, 0); + coldist = dist; + registeredCol = true; + }else + registeredCol = false; + }else + registeredCol = false; + + if(registeredCol){ + TempStoredPoly.verts[0] = model.vertices[lasttri->a].Get(); + TempStoredPoly.verts[1] = model.vertices[lasttri->b].Get(); + TempStoredPoly.verts[2] = model.vertices[lasttri->c].Get(); + TempStoredPoly.valid = true; + } + } + + if(coldist < 1.0f){ + point.point = matrix * point.point; + point.normal = Multiply3x3(matrix, point.normal); + if(TempStoredPoly.valid && poly){ + *poly = TempStoredPoly; + poly->verts[0] = matrix * CVector(poly->verts[0]); + poly->verts[1] = matrix * CVector(poly->verts[1]); + poly->verts[2] = matrix * CVector(poly->verts[2]); + } + mindist *= coldist; + return true; + } + return false; +#else + static CStoredCollPoly TempStoredPoly; + int i; + + // 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)) + return false; + + float coldist = mindist; + 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 && 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 && 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(TempStoredPoly.valid && poly){ + *poly = TempStoredPoly; + poly->verts[0] = matrix * poly->verts[0]; + poly->verts[1] = matrix * poly->verts[1]; + poly->verts[2] = matrix * poly->verts[2]; + } + mindist = coldist; + return true; + } + return false; +#endif +} + +enum { + MAXNUMSPHERES = 128, + MAXNUMBOXES = 32, + MAXNUMLINES = 16, + MAXNUMTRIS = 600 +}; + +#ifdef VU_COLLISION +#ifdef GTA_PS2 +#define SPR(off) ((uint8*)(0x70000000 + (off))) +#else +static uint8 fakeSPR[16*1024]; +#define SPR(off) ((uint8*)(fakeSPR + (off))) +#endif +#endif + +// This checks model A's spheres and lines against model B's spheres, boxes and triangles. +// Returns the number of A's spheres that collide. +// Returned ColPoints are in world space. +// NB: only vehicles can have col models with lines, exactly 4, one for each wheel +int32 +CCollision::ProcessColModels(const CMatrix &matrixA, CColModel &modelA, + const CMatrix &matrixB, CColModel &modelB, + CColPoint *spherepoints, CColPoint *linepoints, float *linedists) +{ +#ifdef VU_COLLISION + CVuVector *aSpheresA = (CVuVector*)SPR(0x0000); + CVuVector *aSpheresB = (CVuVector*)SPR(0x0800); + CVuVector *aLinesA = (CVuVector*)SPR(0x1000); + int32 *aSphereIndicesA = (int32*)SPR(0x1200); + int32 *aSphereIndicesB = (int32*)SPR(0x1400); + int32 *aBoxIndicesB = (int32*)SPR(0x1600); + int32 *aTriangleIndicesB = (int32*)SPR(0x1680); + bool *aCollided = (bool*)SPR(0x1FE0); + CMatrix &matAB = *(CMatrix*)SPR(0x1FF0); + CMatrix &matBA = *(CMatrix*)SPR(0x2040); + int i, j, k; + + // From model A space to model B space + Invert(matrixB, matAB); + matAB *= matrixA; + + CVuVector bsphereAB; // bounding sphere of A in B space + TransformPoint(bsphereAB, matAB, *(RwV3d*)modelA.boundingSphere.center); // inlined + bsphereAB.w = modelA.boundingSphere.radius; + if(!TestSphereBox(*(CColSphere*)&bsphereAB, modelB.boundingBox)) + return 0; + + // transform modelA's spheres and lines to B space + TransformPoints(aSpheresA, modelA.numSpheres, matAB, (RwV3d*)&modelA.spheres->center, sizeof(CColSphere)); + for(i = 0; i < modelA.numSpheres; i++) + aSpheresA[i].w = modelA.spheres[i].radius; + TransformPoints(aLinesA, modelA.numLines*2, matAB, (RwV3d*)&modelA.lines->p0, sizeof(CColLine)/2); + + // Test them against model B's bounding volumes + int numSpheresA = 0; + for(i = 0; i < modelA.numSpheres; i++) + if(TestSphereBox(*(CColSphere*)&aSpheresA[i], modelB.boundingBox)) + aSphereIndicesA[numSpheresA++] = i; + // No collision + if(numSpheresA == 0 && modelA.numLines == 0) + return 0; + + + // B to A space + Invert(matrixA, matBA); + matBA *= matrixB; + + // transform modelB's spheres to A space + TransformPoints(aSpheresB, modelB.numSpheres, matBA, (RwV3d*)&modelB.spheres->center, sizeof(CColSphere)); + for(i = 0; i < modelB.numSpheres; i++) + aSpheresB[i].w = modelB.spheres[i].radius; + + // Check model B against A's bounding volumes + int numSpheresB = 0; + int numBoxesB = 0; + int numTrianglesB = 0; + for(i = 0; i < modelB.numSpheres; i++) + if(TestSphereBox(*(CColSphere*)&aSpheresB[i], modelA.boundingBox)) + aSphereIndicesB[numSpheresB++] = i; + for(i = 0; i < modelB.numBoxes; i++) + if(TestSphereBox(*(CColSphere*)&bsphereAB, modelB.boxes[i])) + aBoxIndicesB[numBoxesB++] = i; + CalculateTrianglePlanes(&modelB); + if(modelB.numTriangles){ + VuTriangle vutri; + // process the first triangle + CColTriangle *tri = &modelB.triangles[0]; + modelB.vertices[tri->a].Unpack(vutri.v0); + modelB.vertices[tri->b].Unpack(vutri.v1); + modelB.vertices[tri->c].Unpack(vutri.v2); + modelB.trianglePlanes[0].Unpack(vutri.plane); + + SphereToTriangleCollisionCompressed(bsphereAB, vutri); + + for(i = 1; i < modelB.numTriangles; i++){ + // set up the next triangle while VU0 is running + tri = &modelB.triangles[i]; + modelB.vertices[tri->a].Unpack(vutri.v0); + modelB.vertices[tri->b].Unpack(vutri.v1); + modelB.vertices[tri->c].Unpack(vutri.v2); + modelB.trianglePlanes[i].Unpack(vutri.plane); + + // check previous result + if(GetVUresult()) + aTriangleIndicesB[numTrianglesB++] = i-1; + + // kick off this one + SphereToTriangleCollisionCompressed(bsphereAB, vutri); + } + + // check last result + if(GetVUresult()) + aTriangleIndicesB[numTrianglesB++] = i-1; + } + // No collision + if(numSpheresB == 0 && numBoxesB == 0 && numTrianglesB == 0) + return 0; + + // We now have the collision volumes in A and B that are worth processing. + + // Process A's spheres against B's collision volumes + int numCollisions = 0; + spherepoints[numCollisions].depth = -1.0f; + for(i = 0; i < numSpheresA; i++){ + float coldist = 1.0e24f; + bool hasCollided = false; + CColSphere *sphA = &modelA.spheres[aSphereIndicesA[i]]; + CVuVector *vusphA = &aSpheresA[aSphereIndicesA[i]]; + + for(j = 0; j < numSpheresB; j++) + // This actually looks like something was inlined here + if(ProcessSphereSphere(*(CColSphere*)vusphA, modelB.spheres[aSphereIndicesB[j]], + spherepoints[numCollisions], coldist)){ + spherepoints[numCollisions].Set( + sphA->surface, sphA->piece, + modelB.spheres[aSphereIndicesB[j]].surface, modelB.spheres[aSphereIndicesB[j]].piece); + hasCollided = true; + } + for(j = 0; j < numBoxesB; j++) + if(ProcessSphereBox(*(CColSphere*)vusphA, modelB.boxes[aBoxIndicesB[j]], + spherepoints[numCollisions], coldist)){ + spherepoints[numCollisions].Set( + sphA->surface, sphA->piece, + modelB.boxes[aBoxIndicesB[j]].surface, modelB.boxes[aBoxIndicesB[j]].piece); + hasCollided = true; + } + if(numTrianglesB){ + CVuVector point, normal; + float depth; + bool registeredCol; + CColTriangle *lasttri; + + VuTriangle vutri; + // process the first triangle + k = aTriangleIndicesB[0]; + CColTriangle *tri = &modelB.triangles[k]; + modelB.vertices[tri->a].Unpack(vutri.v0); + modelB.vertices[tri->b].Unpack(vutri.v1); + modelB.vertices[tri->c].Unpack(vutri.v2); + modelB.trianglePlanes[k].Unpack(vutri.plane); + + SphereToTriangleCollisionCompressed(*vusphA, vutri); + lasttri = tri; + + for(j = 1; j < numTrianglesB; j++){ + k = aTriangleIndicesB[j]; + // set up the next triangle while VU0 is running + tri = &modelB.triangles[k]; + modelB.vertices[tri->a].Unpack(vutri.v0); + modelB.vertices[tri->b].Unpack(vutri.v1); + modelB.vertices[tri->c].Unpack(vutri.v2); + modelB.trianglePlanes[k].Unpack(vutri.plane); + + // check previous result + // TODO: this looks inlined but spherepoints[numCollisions] does not... + if(GetVUresult(point, normal, depth)){ + depth = sphA->radius - depth; + if(depth > spherepoints[numCollisions].depth){ + spherepoints[numCollisions].point = point; + spherepoints[numCollisions].normal = normal; + spherepoints[numCollisions].Set(depth, + sphA->surface, sphA->piece, lasttri->surface, 0); + registeredCol = true; + }else + registeredCol = false; + }else + registeredCol = false; + + if(registeredCol) + hasCollided = true; + + // kick off this one + SphereToTriangleCollisionCompressed(*vusphA, vutri); + lasttri = tri; + } + + // check last result + // TODO: this looks inlined but spherepoints[numCollisions] does not... + if(GetVUresult(point, normal, depth)){ + depth = sphA->radius - depth; + if(depth > spherepoints[numCollisions].depth){ + spherepoints[numCollisions].point = point; + spherepoints[numCollisions].normal = normal; + spherepoints[numCollisions].Set(depth, + sphA->surface, sphA->piece, lasttri->surface, 0); + registeredCol = true; + }else + registeredCol = false; + }else + registeredCol = false; + + if(registeredCol) + hasCollided = true; + } + + if(hasCollided){ + numCollisions++; + if(numCollisions == MAX_COLLISION_POINTS) + break; + spherepoints[numCollisions].depth = -1.0f; + } + } + for(i = 0; i < numCollisions; i++){ + // TODO: both VU0 macros + spherepoints[i].point = matrixB * spherepoints[i].point; + spherepoints[i].normal = Multiply3x3(matrixB, spherepoints[i].normal); + } + + // And the same thing for the lines in A + for(i = 0; i < modelA.numLines; i++){ + aCollided[i] = false; + CVuVector *lineA = &aLinesA[i*2]; + + for(j = 0; j < numSpheresB; j++) + if(ProcessLineSphere(*(CColLine*)lineA, modelB.spheres[aSphereIndicesB[j]], + linepoints[i], linedists[i])){ + linepoints[i].Set(0, 0, +#ifdef FIX_BUGS + modelB.spheres[aSphereIndicesB[j]].surface, modelB.spheres[aSphereIndicesB[j]].piece); +#else + modelB.spheres[j].surface, modelB.spheres[j].piece); +#endif + aCollided[i] = true; + } + for(j = 0; j < numBoxesB; j++) + if(ProcessLineBox(*(CColLine*)lineA, modelB.boxes[aBoxIndicesB[j]], + linepoints[i], linedists[i])){ + linepoints[i].Set(0, 0, + modelB.boxes[aBoxIndicesB[j]].surface, modelB.boxes[aBoxIndicesB[j]].piece); + aCollided[i] = true; + } + if(numTrianglesB){ + CVuVector point, normal; + float dist; + bool registeredCol; + CColTriangle *lasttri; + + VuTriangle vutri; + // process the first triangle + k = aTriangleIndicesB[0]; + CColTriangle *tri = &modelB.triangles[k]; + modelB.vertices[tri->a].Unpack(vutri.v0); + modelB.vertices[tri->b].Unpack(vutri.v1); + modelB.vertices[tri->c].Unpack(vutri.v2); + modelB.trianglePlanes[k].Unpack(vutri.plane); + + LineToTriangleCollisionCompressed(lineA[0], lineA[1], vutri); + lasttri = tri; + + for(j = 1; j < numTrianglesB; j++){ + k = aTriangleIndicesB[j]; + // set up the next triangle while VU0 is running + CColTriangle *tri = &modelB.triangles[k]; + modelB.vertices[tri->a].Unpack(vutri.v0); + modelB.vertices[tri->b].Unpack(vutri.v1); + modelB.vertices[tri->c].Unpack(vutri.v2); + modelB.trianglePlanes[k].Unpack(vutri.plane); + + // check previous result + // TODO: this again somewhat looks inlined + if(GetVUresult(point, normal, dist)){ + if(dist < linedists[i]){ + linepoints[i].point = point; + linepoints[i].normal = normal; + linedists[i] = dist; + linepoints[i].Set(0, 0, lasttri->surface, 0); + registeredCol = true; + }else + registeredCol = false; + }else + registeredCol = false; + + if(registeredCol) + aCollided[i] = true; + + // kick of this one + LineToTriangleCollisionCompressed(lineA[0], lineA[1], vutri); + lasttri = tri; + } + + // check last result + if(GetVUresult(point, normal, dist)){ + if(dist < linedists[i]){ + linepoints[i].point = point; + linepoints[i].normal = normal; + linedists[i] = dist; + linepoints[i].Set(0, 0, lasttri->surface, 0); + registeredCol = true; + }else + registeredCol = false; + }else + registeredCol = false; + + if(registeredCol) + aCollided[i] = true; + } + + if(aCollided[i]){ + // TODO: both VU0 macros + linepoints[i].point = matrixB * linepoints[i].point; + linepoints[i].normal = Multiply3x3(matrixB, linepoints[i].normal); + } + } + + return numCollisions; // sphere collisions +#else + static int aSphereIndicesA[MAXNUMSPHERES]; + static int aLineIndicesA[MAXNUMLINES]; + static int aSphereIndicesB[MAXNUMSPHERES]; + static int aBoxIndicesB[MAXNUMBOXES]; + static int aTriangleIndicesB[MAXNUMTRIS]; + static bool aCollided[MAXNUMLINES]; + static CColSphere aSpheresA[MAXNUMSPHERES]; + static CColLine aLinesA[MAXNUMLINES]; + static CMatrix matAB, matBA; + CColSphere s; + int i, j; + + assert(modelA.numSpheres <= MAXNUMSPHERES); + assert(modelA.numLines <= MAXNUMLINES); + + // From model A space to model B space + matAB = Invert(matrixB, matAB); + matAB *= matrixA; + + CColSphere bsphereAB; // bounding sphere of A in B space + bsphereAB.radius = modelA.boundingSphere.radius; + bsphereAB.center = matAB * modelA.boundingSphere.center; + if(!TestSphereBox(bsphereAB, modelB.boundingBox)) + return 0; + // B to A space + matBA = Invert(matrixA, matBA); + matBA *= matrixB; + + // transform modelA's spheres and lines to B space + for(i = 0; i < modelA.numSpheres; i++){ + CColSphere &s = modelA.spheres[i]; + aSpheresA[i].Set(s.radius, matAB * s.center, s.surface, s.piece); + } + for(i = 0; i < modelA.numLines; i++) + aLinesA[i].Set(matAB * modelA.lines[i].p0, matAB * modelA.lines[i].p1); + + // Test them against model B's bounding volumes + int numSpheresA = 0; + int numLinesA = 0; + for(i = 0; i < modelA.numSpheres; i++) + if(TestSphereBox(aSpheresA[i], modelB.boundingBox)) + aSphereIndicesA[numSpheresA++] = i; + // no actual check??? + for(i = 0; i < modelA.numLines; i++) + aLineIndicesA[numLinesA++] = i; + // No collision + if(numSpheresA == 0 && numLinesA == 0) + return 0; + + // Check model B against A's bounding volumes + int numSpheresB = 0; + int numBoxesB = 0; + int numTrianglesB = 0; + for(i = 0; i < modelB.numSpheres; i++){ + s.radius = modelB.spheres[i].radius; + s.center = matBA * modelB.spheres[i].center; + if(TestSphereBox(s, modelA.boundingBox)) + aSphereIndicesB[numSpheresB++] = i; + } + for(i = 0; i < modelB.numBoxes; i++) + if(TestSphereBox(bsphereAB, modelB.boxes[i])) + aBoxIndicesB[numBoxesB++] = i; + CalculateTrianglePlanes(&modelB); + for(i = 0; i < modelB.numTriangles; i++) + if(TestSphereTriangle(bsphereAB, modelB.vertices, modelB.triangles[i], modelB.trianglePlanes[i])) + aTriangleIndicesB[numTrianglesB++] = i; + assert(numSpheresB <= MAXNUMSPHERES); + assert(numBoxesB <= MAXNUMBOXES); + assert(numTrianglesB <= MAXNUMTRIS); + // No collision + if(numSpheresB == 0 && numBoxesB == 0 && numTrianglesB == 0) + return 0; + + // We now have the collision volumes in A and B that are worth processing. + + // Process A's spheres against B's collision volumes + int numCollisions = 0; + for(i = 0; i < numSpheresA; i++){ + float coldist = 1.0e24f; + bool hasCollided = false; + + for(j = 0; j < numSpheresB; j++) + hasCollided |= ProcessSphereSphere( + aSpheresA[aSphereIndicesA[i]], + modelB.spheres[aSphereIndicesB[j]], + spherepoints[numCollisions], coldist); + for(j = 0; j < numBoxesB; j++) + hasCollided |= ProcessSphereBox( + aSpheresA[aSphereIndicesA[i]], + modelB.boxes[aBoxIndicesB[j]], + spherepoints[numCollisions], coldist); + for(j = 0; j < numTrianglesB; j++) + hasCollided |= ProcessSphereTriangle( + aSpheresA[aSphereIndicesA[i]], + modelB.vertices, + modelB.triangles[aTriangleIndicesB[j]], + modelB.trianglePlanes[aTriangleIndicesB[j]], + spherepoints[numCollisions], coldist); + + if(hasCollided) + numCollisions++; + } + for(i = 0; i < numCollisions; i++){ + spherepoints[i].point = matrixB * spherepoints[i].point; + spherepoints[i].normal = Multiply3x3(matrixB, spherepoints[i].normal); + } + + // And the same thing for the lines in A + for(i = 0; i < numLinesA; i++){ + aCollided[i] = false; + + for(j = 0; j < numSpheresB; j++) + aCollided[i] |= ProcessLineSphere( + aLinesA[aLineIndicesA[i]], + modelB.spheres[aSphereIndicesB[j]], + linepoints[aLineIndicesA[i]], + linedists[aLineIndicesA[i]]); + for(j = 0; j < numBoxesB; j++) + aCollided[i] |= ProcessLineBox( + aLinesA[aLineIndicesA[i]], + modelB.boxes[aBoxIndicesB[j]], + linepoints[aLineIndicesA[i]], + linedists[aLineIndicesA[i]]); + for(j = 0; j < numTrianglesB; j++) + aCollided[i] |= ProcessLineTriangle( + aLinesA[aLineIndicesA[i]], + modelB.vertices, + modelB.triangles[aTriangleIndicesB[j]], + modelB.trianglePlanes[aTriangleIndicesB[j]], + linepoints[aLineIndicesA[i]], + linedists[aLineIndicesA[i]]); + } + for(i = 0; i < numLinesA; i++) + if(aCollided[i]){ + j = aLineIndicesA[i]; + linepoints[j].point = matrixB * linepoints[j].point; + linepoints[j].normal = Multiply3x3(matrixB, linepoints[j].normal); + } + + return numCollisions; // sphere collisions +#endif +} + + +// +// Misc +// + +float +CCollision::DistToLine(const CVector *l0, const CVector *l1, const CVector *point) +{ + float lensq = (*l1 - *l0).MagnitudeSqr(); + float dot = DotProduct(*point - *l0, *l1 - *l0); + // Between 0 and len we're above the line. + // if not, calculate distance to endpoint + if(dot <= 0.0f) + return (*point - *l0).Magnitude(); + if(dot >= lensq) + return (*point - *l1).Magnitude(); + // distance to line + return Sqrt((*point - *l0).MagnitudeSqr() - dot*dot/lensq); +} + +// same as above but also return the point on the line +float +CCollision::DistToLine(const CVector *l0, const CVector *l1, const CVector *point, CVector &closest) +{ + float lensq = (*l1 - *l0).MagnitudeSqr(); + float dot = DotProduct(*point - *l0, *l1 - *l0); + // find out which point we're closest to + if(dot <= 0.0f) + closest = *l0; + else if(dot >= lensq) + closest = *l1; + else + closest = *l0 + (*l1 - *l0)*(dot/lensq); + // this is the distance + return (*point - closest).Magnitude(); +} + +void +CCollision::CalculateTrianglePlanes(CColModel *model) +{ + assert(model); + if(model->numTriangles == 0) + return; + + CLink *lptr; + if(model->trianglePlanes){ + // re-insert at front so it's not removed again soon + lptr = model->GetLinkPtr(); + lptr->Remove(); + ms_colModelCache.head.Insert(lptr); + }else{ + lptr = ms_colModelCache.Insert(model); + if(lptr == nil){ + // make room if we have to, remove last in list + lptr = ms_colModelCache.tail.prev; + assert(lptr); + assert(lptr->item); + lptr->item->RemoveTrianglePlanes(); + ms_colModelCache.Remove(lptr); + // now this cannot fail + lptr = ms_colModelCache.Insert(model); + assert(lptr); + } + model->CalculateTrianglePlanes(); + model->SetLinkPtr(lptr); + } +} + +void +CCollision::DrawColModel(const CMatrix &mat, const CColModel &colModel) +{ + int i; + CVector min, max; + CVector verts[8]; + CVector c; + float r; + + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil); + + min = colModel.boundingBox.min; + max = colModel.boundingBox.max; + + verts[0] = mat * CVector(min.x, min.y, min.z); + verts[1] = mat * CVector(min.x, min.y, max.z); + verts[2] = mat * CVector(min.x, max.y, min.z); + verts[3] = mat * CVector(min.x, max.y, max.z); + verts[4] = mat * CVector(max.x, min.y, min.z); + verts[5] = mat * CVector(max.x, min.y, max.z); + verts[6] = mat * CVector(max.x, max.y, min.z); + verts[7] = mat * CVector(max.x, max.y, max.z); + + CLines::RenderLineWithClipping( + verts[0].x, verts[0].y, verts[0].z, + verts[1].x, verts[1].y, verts[1].z, + 0xFF0000FF, 0xFF0000FF); + CLines::RenderLineWithClipping( + verts[1].x, verts[1].y, verts[1].z, + verts[3].x, verts[3].y, verts[3].z, + 0xFF0000FF, 0xFF0000FF); + CLines::RenderLineWithClipping( + verts[3].x, verts[3].y, verts[3].z, + verts[2].x, verts[2].y, verts[2].z, + 0xFF0000FF, 0xFF0000FF); + CLines::RenderLineWithClipping( + verts[2].x, verts[2].y, verts[2].z, + verts[0].x, verts[0].y, verts[0].z, + 0xFF0000FF, 0xFF0000FF); + + CLines::RenderLineWithClipping( + verts[4].x, verts[4].y, verts[4].z, + verts[5].x, verts[5].y, verts[5].z, + 0xFF0000FF, 0xFF0000FF); + CLines::RenderLineWithClipping( + verts[5].x, verts[5].y, verts[5].z, + verts[7].x, verts[7].y, verts[7].z, + 0xFF0000FF, 0xFF0000FF); + CLines::RenderLineWithClipping( + verts[7].x, verts[7].y, verts[7].z, + verts[6].x, verts[6].y, verts[6].z, + 0xFF0000FF, 0xFF0000FF); + CLines::RenderLineWithClipping( + verts[6].x, verts[6].y, verts[6].z, + verts[4].x, verts[4].y, verts[4].z, + 0xFF0000FF, 0xFF0000FF); + + CLines::RenderLineWithClipping( + verts[0].x, verts[0].y, verts[0].z, + verts[4].x, verts[4].y, verts[4].z, + 0xFF0000FF, 0xFF0000FF); + CLines::RenderLineWithClipping( + verts[1].x, verts[1].y, verts[1].z, + verts[5].x, verts[5].y, verts[5].z, + 0xFF0000FF, 0xFF0000FF); + CLines::RenderLineWithClipping( + verts[2].x, verts[2].y, verts[2].z, + verts[6].x, verts[6].y, verts[6].z, + 0xFF0000FF, 0xFF0000FF); + CLines::RenderLineWithClipping( + verts[3].x, verts[3].y, verts[3].z, + verts[7].x, verts[7].y, verts[7].z, + 0xFF0000FF, 0xFF0000FF); + + for(i = 0; i < colModel.numSpheres; i++){ + c = mat * colModel.spheres[i].center; + r = colModel.spheres[i].radius; + + CLines::RenderLineWithClipping( + c.x, c.y, c.z-r, + c.x-r, c.y-r, c.z, + 0xFF00FFFF, 0xFF00FFFF); + CLines::RenderLineWithClipping( + c.x, c.y, c.z-r, + c.x-r, c.y+r, c.z, + 0xFF00FFFF, 0xFF00FFFF); + CLines::RenderLineWithClipping( + c.x, c.y, c.z-r, + c.x+r, c.y-r, c.z, + 0xFF00FFFF, 0xFF00FFFF); + CLines::RenderLineWithClipping( + c.x, c.y, c.z-r, + c.x+r, c.y+r, c.z, + 0xFF00FFFF, 0xFF00FFFF); + CLines::RenderLineWithClipping( + c.x-r, c.y-r, c.z, + c.x, c.y, c.z+r, + 0xFF00FFFF, 0xFF00FFFF); + CLines::RenderLineWithClipping( + c.x-r, c.y+r, c.z, + c.x, c.y, c.z+r, + 0xFF00FFFF, 0xFF00FFFF); + CLines::RenderLineWithClipping( + c.x+r, c.y-r, c.z, + c.x, c.y, c.z+r, + 0xFF00FFFF, 0xFF00FFFF); + CLines::RenderLineWithClipping( + c.x+r, c.y+r, c.z, + c.x, c.y, c.z+r, + 0xFF00FFFF, 0xFF00FFFF); + } + + for(i = 0; i < colModel.numLines; i++){ + verts[0] = colModel.lines[i].p0; + verts[1] = colModel.lines[i].p1; + + verts[0] = mat * verts[0]; + verts[1] = mat * verts[1]; + + CLines::RenderLineWithClipping( + verts[0].x, verts[0].y, verts[0].z, + verts[1].x, verts[1].y, verts[1].z, + 0x00FFFFFF, 0x00FFFFFF); + } + + for(i = 0; i < colModel.numBoxes; i++){ + min = colModel.boxes[i].min; + max = colModel.boxes[i].max; + + verts[0] = mat * CVector(min.x, min.y, min.z); + verts[1] = mat * CVector(min.x, min.y, max.z); + verts[2] = mat * CVector(min.x, max.y, min.z); + verts[3] = mat * CVector(min.x, max.y, max.z); + verts[4] = mat * CVector(max.x, min.y, min.z); + verts[5] = mat * CVector(max.x, min.y, max.z); + verts[6] = mat * CVector(max.x, max.y, min.z); + verts[7] = mat * CVector(max.x, max.y, max.z); + + CLines::RenderLineWithClipping( + verts[0].x, verts[0].y, verts[0].z, + verts[1].x, verts[1].y, verts[1].z, + 0xFFFFFFFF, 0xFFFFFFFF); + CLines::RenderLineWithClipping( + verts[1].x, verts[1].y, verts[1].z, + verts[3].x, verts[3].y, verts[3].z, + 0xFFFFFFFF, 0xFFFFFFFF); + CLines::RenderLineWithClipping( + verts[3].x, verts[3].y, verts[3].z, + verts[2].x, verts[2].y, verts[2].z, + 0xFFFFFFFF, 0xFFFFFFFF); + CLines::RenderLineWithClipping( + verts[2].x, verts[2].y, verts[2].z, + verts[0].x, verts[0].y, verts[0].z, + 0xFFFFFFFF, 0xFFFFFFFF); + + CLines::RenderLineWithClipping( + verts[4].x, verts[4].y, verts[4].z, + verts[5].x, verts[5].y, verts[5].z, + 0xFFFFFFFF, 0xFFFFFFFF); + CLines::RenderLineWithClipping( + verts[5].x, verts[5].y, verts[5].z, + verts[7].x, verts[7].y, verts[7].z, + 0xFFFFFFFF, 0xFFFFFFFF); + CLines::RenderLineWithClipping( + verts[7].x, verts[7].y, verts[7].z, + verts[6].x, verts[6].y, verts[6].z, + 0xFFFFFFFF, 0xFFFFFFFF); + CLines::RenderLineWithClipping( + verts[6].x, verts[6].y, verts[6].z, + verts[4].x, verts[4].y, verts[4].z, + 0xFFFFFFFF, 0xFFFFFFFF); + + CLines::RenderLineWithClipping( + verts[0].x, verts[0].y, verts[0].z, + verts[4].x, verts[4].y, verts[4].z, + 0xFFFFFFFF, 0xFFFFFFFF); + CLines::RenderLineWithClipping( + verts[1].x, verts[1].y, verts[1].z, + verts[5].x, verts[5].y, verts[5].z, + 0xFFFFFFFF, 0xFFFFFFFF); + CLines::RenderLineWithClipping( + verts[2].x, verts[2].y, verts[2].z, + verts[6].x, verts[6].y, verts[6].z, + 0xFFFFFFFF, 0xFFFFFFFF); + CLines::RenderLineWithClipping( + verts[3].x, verts[3].y, verts[3].z, + verts[7].x, verts[7].y, verts[7].z, + 0xFFFFFFFF, 0xFFFFFFFF); + } + + for(i = 0; i < colModel.numTriangles; i++){ + colModel.GetTrianglePoint(verts[0], colModel.triangles[i].a); + colModel.GetTrianglePoint(verts[1], colModel.triangles[i].b); + colModel.GetTrianglePoint(verts[2], colModel.triangles[i].c); + verts[0] = mat * verts[0]; + verts[1] = mat * verts[1]; + verts[2] = mat * verts[2]; + CLines::RenderLineWithClipping( + verts[0].x, verts[0].y, verts[0].z, + verts[1].x, verts[1].y, verts[1].z, + 0x00FF00FF, 0x00FF00FF); + CLines::RenderLineWithClipping( + verts[0].x, verts[0].y, verts[0].z, + verts[2].x, verts[2].y, verts[2].z, + 0x00FF00FF, 0x00FF00FF); + CLines::RenderLineWithClipping( + verts[1].x, verts[1].y, verts[1].z, + verts[2].x, verts[2].y, verts[2].z, + 0x00FF00FF, 0x00FF00FF); + } + + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE); +} + +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; + RwImVertexIndex *iptr; + RwIm3DVertex *vptr; + + RenderBuffer::ClearRenderBuffer(); + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil); + + for(i = 0; i < colModel.numTriangles; i++){ + colModel.GetTrianglePoint(verts[0], colModel.triangles[i].a); + colModel.GetTrianglePoint(verts[1], colModel.triangles[i].b); + colModel.GetTrianglePoint(verts[2], colModel.triangles[i].c); + verts[0] = mat * verts[0]; + 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; + } + + if(s > SURFACE_METAL_GATE){ + r = CGeneral::GetRandomNumber(); + g = CGeneral::GetRandomNumber(); + b = CGeneral::GetRandomNumber(); + printf("Illegal surfacetype:%d on MI:%d\n", s, id); + } + + RenderBuffer::StartStoring(6, 3, &iptr, &vptr); + RwIm3DVertexSetRGBA(&vptr[0], r, g, b, 255); + RwIm3DVertexSetRGBA(&vptr[1], r, g, b, 255); + RwIm3DVertexSetRGBA(&vptr[2], r, g, b, 255); + RwIm3DVertexSetU(&vptr[0], 0.0f); + RwIm3DVertexSetV(&vptr[0], 0.0f); + RwIm3DVertexSetU(&vptr[1], 0.0f); + RwIm3DVertexSetV(&vptr[1], 1.0f); + RwIm3DVertexSetU(&vptr[2], 1.0f); + RwIm3DVertexSetV(&vptr[2], 1.0f); + RwIm3DVertexSetPos(&vptr[0], verts[0].x, verts[0].y, verts[0].z); + RwIm3DVertexSetPos(&vptr[1], verts[1].x, verts[1].y, verts[1].z); + RwIm3DVertexSetPos(&vptr[2], verts[2].x, verts[2].y, verts[2].z); + iptr[0] = 0; iptr[1] = 1; iptr[2] = 2; + iptr[3] = 0; iptr[4] = 2; iptr[5] = 1; + RenderBuffer::StopStoring(); + } + + for(i = 0; i < colModel.numBoxes; i++){ + min = colModel.boxes[i].min; + max = colModel.boxes[i].max; + + verts[0] = mat * CVector(min.x, min.y, min.z); + verts[1] = mat * CVector(min.x, min.y, max.z); + verts[2] = mat * CVector(min.x, max.y, min.z); + verts[3] = mat * CVector(min.x, max.y, max.z); + verts[4] = mat * CVector(max.x, min.y, min.z); + verts[5] = mat * CVector(max.x, min.y, max.z); + verts[6] = mat * CVector(max.x, max.y, min.z); + 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; + } + + RenderBuffer::StartStoring(36, 8, &iptr, &vptr); + RwIm3DVertexSetRGBA(&vptr[0], r, g, b, 255); + RwIm3DVertexSetRGBA(&vptr[1], r, g, b, 255); + RwIm3DVertexSetRGBA(&vptr[2], r, g, b, 255); + RwIm3DVertexSetRGBA(&vptr[3], r, g, b, 255); + RwIm3DVertexSetRGBA(&vptr[4], r, g, b, 255); + RwIm3DVertexSetRGBA(&vptr[5], r, g, b, 255); + RwIm3DVertexSetRGBA(&vptr[6], r, g, b, 255); + RwIm3DVertexSetRGBA(&vptr[7], r, g, b, 255); + RwIm3DVertexSetU(&vptr[0], 0.0f); + RwIm3DVertexSetV(&vptr[0], 0.0f); + RwIm3DVertexSetU(&vptr[1], 0.0f); + RwIm3DVertexSetV(&vptr[1], 1.0f); + RwIm3DVertexSetU(&vptr[2], 1.0f); + RwIm3DVertexSetV(&vptr[2], 1.0f); + RwIm3DVertexSetU(&vptr[3], 0.0f); + RwIm3DVertexSetV(&vptr[3], 0.0f); + RwIm3DVertexSetU(&vptr[4], 0.0f); + RwIm3DVertexSetV(&vptr[4], 1.0f); + RwIm3DVertexSetU(&vptr[5], 1.0f); + RwIm3DVertexSetV(&vptr[5], 1.0f); + RwIm3DVertexSetU(&vptr[6], 0.0f); + RwIm3DVertexSetV(&vptr[6], 1.0f); + RwIm3DVertexSetU(&vptr[7], 1.0f); + RwIm3DVertexSetV(&vptr[7], 1.0f); + RwIm3DVertexSetPos(&vptr[0], verts[0].x, verts[0].y, verts[0].z); + RwIm3DVertexSetPos(&vptr[1], verts[1].x, verts[1].y, verts[1].z); + RwIm3DVertexSetPos(&vptr[2], verts[2].x, verts[2].y, verts[2].z); + RwIm3DVertexSetPos(&vptr[3], verts[3].x, verts[3].y, verts[3].z); + RwIm3DVertexSetPos(&vptr[4], verts[4].x, verts[4].y, verts[4].z); + RwIm3DVertexSetPos(&vptr[5], verts[5].x, verts[5].y, verts[5].z); + RwIm3DVertexSetPos(&vptr[6], verts[6].x, verts[6].y, verts[6].z); + RwIm3DVertexSetPos(&vptr[7], verts[7].x, verts[7].y, verts[7].z); + iptr[0] = 0; iptr[1] = 1; iptr[2] = 2; + iptr[3] = 1; iptr[4] = 3; iptr[5] = 2; + iptr[6] = 1; iptr[7] = 5; iptr[8] = 7; + iptr[9] = 1; iptr[10] = 7; iptr[11] = 3; + iptr[12] = 2; iptr[13] = 3; iptr[14] = 7; + iptr[15] = 2; iptr[16] = 7; iptr[17] = 6; + iptr[18] = 0; iptr[19] = 5; iptr[20] = 1; + iptr[21] = 0; iptr[22] = 4; iptr[23] = 5; + iptr[24] = 0; iptr[25] = 2; iptr[26] = 4; + iptr[27] = 2; iptr[28] = 6; iptr[29] = 4; + iptr[30] = 4; iptr[31] = 6; iptr[32] = 7; + iptr[33] = 4; iptr[34] = 7; iptr[35] = 5; + RenderBuffer::StopStoring(); + } + + RenderBuffer::RenderStuffInBuffer(); + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE); +} \ No newline at end of file diff --git a/src/collision/Collision.h b/src/collision/Collision.h new file mode 100644 index 00000000..f4270bc5 --- /dev/null +++ b/src/collision/Collision.h @@ -0,0 +1,70 @@ +#pragma once + +#include "ColModel.h" +#include "Game.h" // for eLevelName +#ifdef VU_COLLISION +#include "VuVector.h" +#endif + +struct CStoredCollPoly +{ +#ifdef VU_COLLISION + CVuVector verts[3]; +#else + CVector verts[3]; +#endif + bool valid; +}; + +// If you spawn many tanks at once, you will see that collisions of two entity exceeds 32. +#if defined(FIX_BUGS) && !defined(SQUEEZE_PERFORMANCE) +#define MAX_COLLISION_POINTS 64 +#else +#define MAX_COLLISION_POINTS 32 +#endif + +class CCollision +{ +public: + static eLevelName ms_collisionInMemory; + static CLinkList ms_colModelCache; +#ifdef NO_ISLAND_LOADING + static bool bAlreadyLoaded; +#endif + + static void Init(void); + static void Shutdown(void); + static void Update(void); + static void LoadCollisionWhenINeedIt(bool changeLevel); + static void SortOutCollisionAfterLoad(void); + static void LoadCollisionScreen(eLevelName level); + static void DrawColModel(const CMatrix &mat, const CColModel &colModel); + static void DrawColModel_Coloured(const CMatrix &mat, const CColModel &colModel, int32 id); + + static void CalculateTrianglePlanes(CColModel *model); + + // all these return true if there's a collision + static bool TestSphereSphere(const CColSphere &s1, const CColSphere &s2); + static bool TestSphereBox(const CColSphere &sph, const CColBox &box); + static bool TestLineBox(const CColLine &line, const CColBox &box); + static bool TestVerticalLineBox(const CColLine &line, const CColBox &box); + static bool TestLineTriangle(const CColLine &line, const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane); + static bool TestLineSphere(const CColLine &line, const CColSphere &sph); + static bool TestSphereTriangle(const CColSphere &sphere, const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane); + static bool TestLineOfSight(const CColLine &line, const CMatrix &matrix, CColModel &model, bool ignoreSeeThrough); + + static bool ProcessSphereSphere(const CColSphere &s1, const CColSphere &s2, CColPoint &point, float &mindistsq); + static bool ProcessSphereBox(const CColSphere &sph, const CColBox &box, CColPoint &point, float &mindistsq); + static bool ProcessLineBox(const CColLine &line, const CColBox &box, CColPoint &point, float &mindist); + static bool ProcessVerticalLineTriangle(const CColLine &line, const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, CColPoint &point, float &mindist, CStoredCollPoly *poly); + static bool ProcessLineTriangle(const CColLine &line , const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, CColPoint &point, float &mindist); + static bool ProcessLineSphere(const CColLine &line, const CColSphere &sphere, CColPoint &point, float &mindist); + static bool ProcessSphereTriangle(const CColSphere &sph, const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, CColPoint &point, float &mindistsq); + static bool ProcessLineOfSight(const CColLine &line, const CMatrix &matrix, CColModel &model, CColPoint &point, float &mindist, bool ignoreSeeThrough); + static bool ProcessVerticalLine(const CColLine &line, const CMatrix &matrix, CColModel &model, CColPoint &point, float &mindist, bool ignoreSeeThrough, CStoredCollPoly *poly); + static int32 ProcessColModels(const CMatrix &matrixA, CColModel &modelA, const CMatrix &matrixB, CColModel &modelB, CColPoint *spherepoints, CColPoint *linepoints, float *linedists); + static bool IsStoredPolyStillValidVerticalLine(const CVector &pos, float z, CColPoint &point, CStoredCollPoly *poly); + + static float DistToLine(const CVector *l0, const CVector *l1, const CVector *point); + static float DistToLine(const CVector *l0, const CVector *l1, const CVector *point, CVector &closest); +}; diff --git a/src/collision/CompressedVector.h b/src/collision/CompressedVector.h new file mode 100644 index 00000000..d54e49b1 --- /dev/null +++ b/src/collision/CompressedVector.h @@ -0,0 +1,36 @@ +#pragma once + +struct CompressedVector +{ +#ifdef COMPRESSED_COL_VECTORS + int16 x, y, z; + CVector Get(void) const { return CVector(x, y, z)/128.0f; }; + void Set(float x, float y, float z) { this->x = x*128.0f; this->y = y*128.0f; this->z = z*128.0f; }; +#ifdef GTA_PS2 + void Unpack(uint128 &qword) const { + __asm__ volatile ( + "lh $8, 0(%1)\n" + "lh $9, 2(%1)\n" + "lh $10, 4(%1)\n" + "pextlw $10, $8\n" + "pextlw $2, $9, $10\n" + "sq $2, %0\n" + : "=m" (qword) + : "r" (this) + : "$8", "$9", "$10", "$2" + ); + } +#else + void Unpack(int32 *qword) const { + qword[0] = x; + qword[1] = y; + qword[2] = z; + qword[3] = 0; // junk + } +#endif +#else + float x, y, z; + CVector Get(void) const { return CVector(x, y, z); }; + void Set(float x, float y, float z) { this->x = x; this->y = y; this->z = z; }; +#endif +}; \ No newline at end of file diff --git a/src/collision/TempColModels.cpp b/src/collision/TempColModels.cpp new file mode 100644 index 00000000..849eb01e --- /dev/null +++ b/src/collision/TempColModels.cpp @@ -0,0 +1,296 @@ +#include "common.h" + +#include "TempColModels.h" + +CColModel CTempColModels::ms_colModelPed1; +CColModel CTempColModels::ms_colModelPed2; +CColModel CTempColModels::ms_colModelBBox; +CColModel CTempColModels::ms_colModelBumper1; +CColModel CTempColModels::ms_colModelWheel1; +CColModel CTempColModels::ms_colModelPanel1; +CColModel CTempColModels::ms_colModelBodyPart2; +CColModel CTempColModels::ms_colModelBodyPart1; +CColModel CTempColModels::ms_colModelCutObj[5]; +CColModel CTempColModels::ms_colModelPedGroundHit; +CColModel CTempColModels::ms_colModelBoot1; +CColModel CTempColModels::ms_colModelDoor1; +CColModel CTempColModels::ms_colModelBonnet1; + + +CColSphere s_aPedSpheres[3]; +CColSphere s_aPed2Spheres[3]; +CColSphere s_aPedGSpheres[4]; +#ifdef FIX_BUGS +CColSphere s_aDoorSpheres[3]; +#else +CColSphere s_aDoorSpheres[4]; +#endif +CColSphere s_aBumperSpheres[4]; +CColSphere s_aPanelSpheres[4]; +CColSphere s_aBonnetSpheres[4]; +CColSphere s_aBootSpheres[4]; +CColSphere s_aWheelSpheres[2]; +CColSphere s_aBodyPartSpheres1[2]; +CColSphere s_aBodyPartSpheres2[2]; + +void +CTempColModels::Initialise(void) +{ +#define SET_COLMODEL_SPHERES(colmodel, sphrs)\ + colmodel.numSpheres = ARRAY_SIZE(sphrs);\ + colmodel.spheres = sphrs;\ + colmodel.level = LEVEL_GENERIC;\ + colmodel.ownsCollisionVolumes = false;\ + + int i; + + ms_colModelBBox.boundingSphere.Set(2.0f, CVector(0.0f, 0.0f, 0.0f)); + ms_colModelBBox.boundingBox.Set(CVector(-2.0f, -2.0f, -2.0f), CVector(2.0f, 2.0f, 2.0f)); + ms_colModelBBox.level = LEVEL_GENERIC; + + for (i = 0; i < ARRAY_SIZE(ms_colModelCutObj); i++) { + ms_colModelCutObj[i].boundingSphere.Set(2.0f, CVector(0.0f, 0.0f, 0.0f)); + ms_colModelCutObj[i].boundingBox.Set(CVector(-2.0f, -2.0f, -2.0f), CVector(2.0f, 2.0f, 2.0f)); + ms_colModelCutObj[i].level = LEVEL_GENERIC; + } + + // Ped Spheres + + for (i = 0; i < ARRAY_SIZE(s_aPedSpheres); i++) + s_aPedSpheres[i].radius = 0.35f; + + s_aPedSpheres[0].center = CVector(0.0f, 0.0f, -0.25f); + s_aPedSpheres[1].center = CVector(0.0f, 0.0f, 0.15f); + s_aPedSpheres[2].center = CVector(0.0f, 0.0f, 0.55f); + +#ifdef FIX_BUGS + for (i = 0; i < ARRAY_SIZE(s_aPedSpheres); i++) { +#else + for (i = 0; i < ARRAY_SIZE(s_aPedGSpheres); i++) { +#endif + s_aPedSpheres[i].surface = SURFACE_PED; + s_aPedSpheres[i].piece = 0; + } + + ms_colModelPed1.boundingSphere.Set(1.25f, CVector(0.0f, 0.0f, 0.0f)); + ms_colModelPed1.boundingBox.Set(CVector(-0.35f, -0.35f, -1.0f), CVector(0.35f, 0.35f, 0.9f)); + SET_COLMODEL_SPHERES(ms_colModelPed1, s_aPedSpheres); + + // Ped 2 Spheres + + s_aPed2Spheres[0].radius = 0.3f; + s_aPed2Spheres[1].radius = 0.4f; + s_aPed2Spheres[2].radius = 0.3f; + + s_aPed2Spheres[0].center = CVector(0.0f, 0.35f, -0.9f); + s_aPed2Spheres[1].center = CVector(0.0f, 0.0f, -0.9f); + s_aPed2Spheres[2].center = CVector(0.0f, -0.35f, -0.9f); + + for (i = 0; i < ARRAY_SIZE(s_aPed2Spheres); i++) { + s_aPed2Spheres[i].surface = SURFACE_PED; + s_aPed2Spheres[i].piece = 0; + } + + ms_colModelPed2.boundingSphere.Set(2.0f, CVector(0.0f, 0.0f, 0.0f)); + ms_colModelPed2.boundingBox.Set(CVector(-0.7f, -0.7f, -1.2f), CVector(0.7f, 0.7f, 0.0f)); + + SET_COLMODEL_SPHERES(ms_colModelPed2, s_aPed2Spheres); + + // Ped ground collision + + s_aPedGSpheres[0].radius = 0.35f; + s_aPedGSpheres[1].radius = 0.35f; + s_aPedGSpheres[2].radius = 0.35f; + s_aPedGSpheres[3].radius = 0.3f; + + s_aPedGSpheres[0].center = CVector(0.0f, -0.4f, -0.9f); + s_aPedGSpheres[1].center = CVector(0.0f, -0.1f, -0.9f); + s_aPedGSpheres[2].center = CVector(0.0f, 0.25f, -0.9f); + s_aPedGSpheres[3].center = CVector(0.0f, 0.65f, -0.9f); + + s_aPedGSpheres[0].surface = SURFACE_PED; + s_aPedGSpheres[1].surface = SURFACE_PED; + s_aPedGSpheres[2].surface = SURFACE_PED; + s_aPedGSpheres[3].surface = SURFACE_PED; + s_aPedGSpheres[0].piece = 4; + s_aPedGSpheres[1].piece = 1; + s_aPedGSpheres[2].piece = 0; + s_aPedGSpheres[3].piece = 6; + + ms_colModelPedGroundHit.boundingSphere.Set(2.0f, CVector(0.0f, 0.0f, 0.0f)); + ms_colModelPedGroundHit.boundingBox.Set(CVector(-0.4f, -1.0f, -1.25f), CVector(0.4f, 1.2f, -0.5f)); + + SET_COLMODEL_SPHERES(ms_colModelPedGroundHit, s_aPedGSpheres); + + // Door Spheres + + s_aDoorSpheres[0].radius = 0.15f; + s_aDoorSpheres[1].radius = 0.15f; + s_aDoorSpheres[2].radius = 0.25f; + + s_aDoorSpheres[0].center = CVector(0.0f, -0.25f, -0.35f); + s_aDoorSpheres[1].center = CVector(0.0f, -0.95f, -0.35f); + s_aDoorSpheres[2].center = CVector(0.0f, -0.6f, 0.25f); + +#ifdef FIX_BUGS + for (i = 0; i < ARRAY_SIZE(s_aDoorSpheres); i++) { +#else + for (i = 0; i < ARRAY_SIZE(s_aPed2Spheres); i++) { +#endif + s_aDoorSpheres[i].surface = SURFACE_CAR_PANEL; + s_aDoorSpheres[i].piece = 0; + } + + ms_colModelDoor1.boundingSphere.Set(1.5f, CVector(0.0f, -0.6f, 0.0f)); + ms_colModelDoor1.boundingBox.Set(CVector(-0.3f, 0.0f, -0.6f), CVector(0.3f, -1.2f, 0.6f)); + + SET_COLMODEL_SPHERES(ms_colModelDoor1, s_aDoorSpheres); + + // Bumper Spheres + + for (i = 0; i < ARRAY_SIZE(s_aBumperSpheres); i++) + s_aBumperSpheres[i].radius = 0.15f; + + s_aBumperSpheres[0].center = CVector(0.85f, -0.05f, 0.0f); + s_aBumperSpheres[1].center = CVector(0.4f, 0.05f, 0.0f); + s_aBumperSpheres[2].center = CVector(-0.4f, 0.05f, 0.0f); + s_aBumperSpheres[3].center = CVector(-0.85f, -0.05f, 0.0f); + + for (i = 0; i < ARRAY_SIZE(s_aBumperSpheres); i++) { + s_aBumperSpheres[i].surface = SURFACE_CAR_PANEL; + s_aBumperSpheres[i].piece = 0; + } + + ms_colModelBumper1.boundingSphere.Set(2.2f, CVector(0.0f, -0.6f, 0.0f)); + ms_colModelBumper1.boundingBox.Set(CVector(-1.2f, -0.3f, -0.2f), CVector(1.2f, 0.3f, 0.2f)); + + SET_COLMODEL_SPHERES(ms_colModelBumper1, s_aBumperSpheres); + + // Panel Spheres + + for (i = 0; i < ARRAY_SIZE(s_aPanelSpheres); i++) + s_aPanelSpheres[i].radius = 0.15f; + + s_aPanelSpheres[0].center = CVector(0.15f, 0.45f, 0.0f); + s_aPanelSpheres[1].center = CVector(0.15f, -0.45f, 0.0f); + s_aPanelSpheres[2].center = CVector(-0.15f, -0.45f, 0.0f); + s_aPanelSpheres[3].center = CVector(-0.15f, 0.45f, 0.0f); + + for (i = 0; i < ARRAY_SIZE(s_aPanelSpheres); i++) { + s_aPanelSpheres[i].surface = SURFACE_CAR_PANEL; + s_aPanelSpheres[i].piece = 0; + } + + ms_colModelPanel1.boundingSphere.Set(1.4f, CVector(0.0f, 0.0f, 0.0f)); + ms_colModelPanel1.boundingBox.Set(CVector(-0.3f, -0.6f, -0.15f), CVector(0.3f, 0.6f, 0.15f)); + + SET_COLMODEL_SPHERES(ms_colModelPanel1, s_aPanelSpheres); + + // Bonnet Spheres + + for (i = 0; i < ARRAY_SIZE(s_aBonnetSpheres); i++) + s_aBonnetSpheres[i].radius = 0.2f; + + s_aBonnetSpheres[0].center = CVector(-0.4f, 0.1f, 0.0f); + s_aBonnetSpheres[1].center = CVector(-0.4f, 0.9f, 0.0f); + s_aBonnetSpheres[2].center = CVector(0.4f, 0.1f, 0.0f); + s_aBonnetSpheres[3].center = CVector(0.4f, 0.9f, 0.0f); + + for (i = 0; i < ARRAY_SIZE(s_aBonnetSpheres); i++) { + s_aBonnetSpheres[i].surface = SURFACE_CAR_PANEL; + s_aBonnetSpheres[i].piece = 0; + } + + ms_colModelBonnet1.boundingSphere.Set(1.7f, CVector(0.0f, 0.5f, 0.0f)); + ms_colModelBonnet1.boundingBox.Set(CVector(-0.7f, -0.2f, -0.3f), CVector(0.7f, 1.2f, 0.3f)); + + SET_COLMODEL_SPHERES(ms_colModelBonnet1, s_aBonnetSpheres); + + // Boot Spheres + + for (i = 0; i < ARRAY_SIZE(s_aBootSpheres); i++) + s_aBootSpheres[i].radius = 0.2f; + + s_aBootSpheres[0].center = CVector(-0.4f, -0.1f, 0.0f); + s_aBootSpheres[1].center = CVector(-0.4f, -0.6f, 0.0f); + s_aBootSpheres[2].center = CVector(0.4f, -0.1f, 0.0f); + s_aBootSpheres[3].center = CVector(0.4f, -0.6f, 0.0f); + + for (i = 0; i < ARRAY_SIZE(s_aBootSpheres); i++) { + s_aBootSpheres[i].surface = SURFACE_CAR_PANEL; + s_aBootSpheres[i].piece = 0; + } + + ms_colModelBoot1.boundingSphere.Set(1.4f, CVector(0.0f, -0.4f, 0.0f)); + ms_colModelBoot1.boundingBox.Set(CVector(-0.7f, -0.9f, -0.3f), CVector(0.7f, 0.2f, 0.3f)); + + SET_COLMODEL_SPHERES(ms_colModelBoot1, s_aBootSpheres); + + // Wheel Spheres + + s_aWheelSpheres[0].radius = 0.35f; + s_aWheelSpheres[1].radius = 0.35f; + + s_aWheelSpheres[0].center = CVector(-0.3f, 0.0f, 0.0f); + s_aWheelSpheres[1].center = CVector(0.3f, 0.0f, 0.0f); + +#ifdef FIX_BUGS + for (i = 0; i < ARRAY_SIZE(s_aWheelSpheres); i++) { +#else + for (i = 0; i < ARRAY_SIZE(s_aBootSpheres); i++) { +#endif + s_aWheelSpheres[i].surface = SURFACE_WHEELBASE; + s_aWheelSpheres[i].piece = 0; + } + + ms_colModelWheel1.boundingSphere.Set(1.4f, CVector(0.0f, 0.0f, 0.0f)); + ms_colModelWheel1.boundingBox.Set(CVector(-0.7f, -0.4f, -0.4f), CVector(0.7f, 0.4f, 0.4f)); + + SET_COLMODEL_SPHERES(ms_colModelWheel1, s_aWheelSpheres); + + // Body Part Spheres 1 + + s_aBodyPartSpheres1[0].radius = 0.2f; + s_aBodyPartSpheres1[1].radius = 0.2f; + + s_aBodyPartSpheres1[0].center = CVector(0.0f, 0.0f, 0.0f); + s_aBodyPartSpheres1[1].center = CVector(0.8f, 0.0f, 0.0f); + +#ifdef FIX_BUGS + for (i = 0; i < ARRAY_SIZE(s_aBodyPartSpheres1); i++) { +#else + for (i = 0; i < ARRAY_SIZE(s_aBootSpheres); i++) { +#endif + s_aBodyPartSpheres1[i].surface = SURFACE_PED; + s_aBodyPartSpheres1[i].piece = 0; + } + + ms_colModelBodyPart1.boundingSphere.Set(0.7f, CVector(0.4f, 0.0f, 0.0f)); + ms_colModelBodyPart1.boundingBox.Set(CVector(-0.3f, -0.3f, -0.3f), CVector(1.1f, 0.3f, 0.3f)); + + SET_COLMODEL_SPHERES(ms_colModelBodyPart1, s_aBodyPartSpheres1); + + // Body Part Spheres 2 + + s_aBodyPartSpheres2[0].radius = 0.15f; + s_aBodyPartSpheres2[1].radius = 0.15f; + + s_aBodyPartSpheres2[0].center = CVector(0.0f, 0.0f, 0.0f); + s_aBodyPartSpheres2[1].center = CVector(0.5f, 0.0f, 0.0f); + +#ifdef FIX_BUGS + for (i = 0; i < ARRAY_SIZE(s_aBodyPartSpheres2); i++) { +#else + for (i = 0; i < ARRAY_SIZE(s_aBootSpheres); i++) { +#endif + s_aBodyPartSpheres2[i].surface = SURFACE_PED; + s_aBodyPartSpheres2[i].piece = 0; + } + + ms_colModelBodyPart2.boundingSphere.Set(0.5f, CVector(0.25f, 0.0f, 0.0f)); + ms_colModelBodyPart2.boundingBox.Set(CVector(-0.2f, -0.2f, -0.2f), CVector(0.7f, 0.2f, 0.2f)); + + SET_COLMODEL_SPHERES(ms_colModelBodyPart2, s_aBodyPartSpheres2); + +#undef SET_COLMODEL_SPHERES +} diff --git a/src/collision/TempColModels.h b/src/collision/TempColModels.h new file mode 100644 index 00000000..3e1dd5e1 --- /dev/null +++ b/src/collision/TempColModels.h @@ -0,0 +1,23 @@ +#pragma once + +#include "Collision.h" + +class CTempColModels +{ +public: + static CColModel ms_colModelPed1; + static CColModel ms_colModelPed2; + static CColModel ms_colModelBBox; + static CColModel ms_colModelBumper1; + static CColModel ms_colModelWheel1; + static CColModel ms_colModelPanel1; + static CColModel ms_colModelBodyPart2; + static CColModel ms_colModelBodyPart1; + static CColModel ms_colModelCutObj[5]; + static CColModel ms_colModelPedGroundHit; + static CColModel ms_colModelBoot1; + static CColModel ms_colModelDoor1; + static CColModel ms_colModelBonnet1; + + static void Initialise(void); +}; diff --git a/src/collision/VuCollision.cpp b/src/collision/VuCollision.cpp new file mode 100644 index 00000000..8828d2e1 --- /dev/null +++ b/src/collision/VuCollision.cpp @@ -0,0 +1,282 @@ +#include "common.h" +#ifdef VU_COLLISION +#include "VuVector.h" +#include "VuCollision.h" + +#ifndef GTA_PS2 +int16 vi01; +CVuVector vf01; +CVuVector vf02; +CVuVector vf03; + +CVuVector +DistanceBetweenSphereAndLine(const CVuVector ¢er, const CVuVector &p0, const CVuVector &line) +{ + // center VF12 + // p0 VF14 + // line VF15 + CVuVector ret; // VF16 + CVuVector p1 = p0+line; + CVuVector dist0 = center - p0; // VF20 + CVuVector dist1 = center - p1; // VF25 + float lenSq = line.MagnitudeSqr(); // VF21 + float distSq0 = dist0.MagnitudeSqr(); // VF22 + float distSq1 = dist1.MagnitudeSqr(); + float dot = DotProduct(dist0, line); // VF23 + if(dot < 0.0f){ + // not above line, closest to p0 + ret = p0; + ret.w = distSq0; + return ret; + } + float t = dot/lenSq; // param of nearest point on infinite line + if(t > 1.0f){ + // not above line, closest to p1 + ret = p1; + ret.w = distSq1; + return ret; + } + // closest to line + ret = p0 + line*t; + ret.w = (ret - center).MagnitudeSqr(); + return ret; +} +inline int SignFlags(const CVector &v) +{ + int f = 0; + if(v.x < 0.0f) f |= 1; + if(v.y < 0.0f) f |= 2; + if(v.z < 0.0f) f |= 4; + return f; +} +#endif + +extern "C" void +LineToTriangleCollision(const CVuVector &p0, const CVuVector &p1, + const CVuVector &v0, const CVuVector &v1, const CVuVector &v2, + const CVuVector &plane) +{ +#ifdef GTA_PS2 + __asm__ volatile ( + ".set noreorder\n" + "lqc2 vf12, 0x0(%0)\n" + "lqc2 vf13, 0x0(%1)\n" + "lqc2 vf14, 0x0(%2)\n" + "lqc2 vf15, 0x0(%3)\n" + "lqc2 vf16, 0x0(%4)\n" + "lqc2 vf17, 0x0(%5)\n" + "vcallms Vu0LineToTriangleCollisionStart\n" + ".set reorder\n" + : + : "r" (&p0), "r" (&p1), "r" (&v0), "r" (&v1), "r" (&v2), "r" (&plane) + ); +#else + float dot0 = DotProduct(plane, p0); + float dot1 = DotProduct(plane, p1); + float dist0 = plane.w - dot0; + float dist1 = plane.w - dot1; + + // if points are on the same side, no collision + if(dist0 * dist1 > 0.0f){ + vi01 = 0; + return; + } + + CVuVector diff = p1 - p0; + float t = dist0/(dot1 - dot0); + CVuVector p = p0 + diff*t; + p.w = 0.0f; + vf01 = p; + vf03.x = t; + + // Check if point is inside + CVector cross1 = CrossProduct(p-v0, v1-v0); + CVector cross2 = CrossProduct(p-v1, v2-v1); + CVector cross3 = CrossProduct(p-v2, v0-v2); + // Only check relevant directions + int flagmask = 0; + if(Abs(plane.x) > 0.5f) flagmask |= 1; + if(Abs(plane.y) > 0.5f) flagmask |= 2; + if(Abs(plane.z) > 0.5f) flagmask |= 4; + int flags1 = SignFlags(cross1) & flagmask; + int flags2 = SignFlags(cross2) & flagmask; + int flags3 = SignFlags(cross3) & flagmask; + // inside if on the same side of all edges + if(flags1 != flags2 || flags1 != flags3){ + vi01 = 0; + return; + } + vi01 = 1; + vf02 = plane; + return; +#endif +} + +extern "C" void +LineToTriangleCollisionCompressed(const CVuVector &p0, const CVuVector &p1, VuTriangle &tri) +{ +#ifdef GTA_PS2 + __asm__ volatile ( + ".set noreorder\n" + "lqc2 vf12, 0x0(%0)\n" + "lqc2 vf13, 0x0(%1)\n" + "lqc2 vf14, 0x0(%2)\n" + "lqc2 vf15, 0x10(%2)\n" + "lqc2 vf16, 0x20(%2)\n" + "lqc2 vf17, 0x30(%2)\n" + "vcallms Vu0LineToTriangleCollisionCompressedStart\n" + ".set reorder\n" + : + : "r" (&p0), "r" (&p1), "r" (&tri) + ); +#else + CVuVector v0, v1, v2, plane; + v0.x = tri.v0[0]/128.0f; + v0.y = tri.v0[1]/128.0f; + v0.z = tri.v0[2]/128.0f; + v0.w = tri.v0[3]/128.0f; + v1.x = tri.v1[0]/128.0f; + v1.y = tri.v1[1]/128.0f; + v1.z = tri.v1[2]/128.0f; + v1.w = tri.v1[3]/128.0f; + v2.x = tri.v2[0]/128.0f; + v2.y = tri.v2[1]/128.0f; + v2.z = tri.v2[2]/128.0f; + v2.w = tri.v2[3]/128.0f; + plane.x = tri.plane[0]/4096.0f; + plane.y = tri.plane[1]/4096.0f; + plane.z = tri.plane[2]/4096.0f; + plane.w = tri.plane[3]/128.0f; + LineToTriangleCollision(p0, p1, v0, v1, v2, plane); +#endif +} + +extern "C" void +SphereToTriangleCollision(const CVuVector &sph, + const CVuVector &v0, const CVuVector &v1, const CVuVector &v2, + const CVuVector &plane) +{ +#ifdef GTA_PS2 + __asm__ volatile ( + ".set noreorder\n" + "lqc2 vf12, 0x0(%0)\n" + "lqc2 vf14, 0x0(%1)\n" + "lqc2 vf15, 0x0(%2)\n" + "lqc2 vf16, 0x0(%3)\n" + "lqc2 vf17, 0x0(%4)\n" + "vcallms Vu0SphereToTriangleCollisionStart\n" + ".set reorder\n" + : + : "r" (&sph), "r" (&v0), "r" (&v1), "r" (&v2), "r" (&plane) + ); +#else + float planedist = DotProduct(plane, sph) - plane.w; // VF02 + if(Abs(planedist) > sph.w){ + vi01 = 0; + return; + } + // point on plane + CVuVector p = sph - planedist*plane; + p.w = 0.0f; + vf01 = p; + planedist = Abs(planedist); + // edges + CVuVector v01 = v1 - v0; + CVuVector v12 = v2 - v1; + CVuVector v20 = v0 - v2; + // VU code calculates normal again for some weird reason... + // Check sides of point + CVector cross1 = CrossProduct(p-v0, v01); + CVector cross2 = CrossProduct(p-v1, v12); + CVector cross3 = CrossProduct(p-v2, v20); + // Only check relevant directions + int flagmask = 0; + if(Abs(plane.x) > 0.1f) flagmask |= 1; + if(Abs(plane.y) > 0.1f) flagmask |= 2; + if(Abs(plane.z) > 0.1f) flagmask |= 4; + int nflags = SignFlags(plane) & flagmask; + int flags1 = SignFlags(cross1) & flagmask; + int flags2 = SignFlags(cross2) & flagmask; + int flags3 = SignFlags(cross3) & flagmask; + int testcase = 0; + CVuVector closest(0.0f, 0.0f, 0.0f); // VF04 + if(flags1 == nflags){ + closest += v2; + testcase++; + } + if(flags2 == nflags){ + closest += v0; + testcase++; + } + if(flags3 == nflags){ + closest += v1; + testcase++; + } + if(testcase == 3){ + // inside triangle - dist to plane already checked + vf02 = plane; + vf02.w = vf03.x = planedist; + vi01 = 1; + }else if(testcase == 1){ + // outside two sides - closest to point opposide inside edge + vf01 = closest; + vf02 = sph - closest; + float distSq = vf02.MagnitudeSqr(); + vi01 = sph.w*sph.w > distSq; + vf03.x = Sqrt(distSq); + vf02 *= 1.0f/vf03.x; + }else{ + // inside two sides - closest to third edge + if(flags1 != nflags) + closest = DistanceBetweenSphereAndLine(sph, v0, v01); + else if(flags2 != nflags) + closest = DistanceBetweenSphereAndLine(sph, v1, v12); + else + closest = DistanceBetweenSphereAndLine(sph, v2, v20); + vi01 = sph.w*sph.w > closest.w; + vf01 = closest; + vf02 = sph - closest; + vf03.x = Sqrt(closest.w); + vf02 *= 1.0f/vf03.x; + } +#endif +} + +extern "C" void +SphereToTriangleCollisionCompressed(const CVuVector &sph, VuTriangle &tri) +{ +#ifdef GTA_PS2 + __asm__ volatile ( + ".set noreorder\n" + "lqc2 vf12, 0x0(%0)\n" + "lqc2 vf14, 0x0(%1)\n" + "lqc2 vf15, 0x10(%1)\n" + "lqc2 vf16, 0x20(%1)\n" + "lqc2 vf17, 0x30(%1)\n" + "vcallms Vu0SphereToTriangleCollisionCompressedStart\n" + ".set reorder\n" + : + : "r" (&sph), "r" (&tri) + ); +#else + CVuVector v0, v1, v2, plane; + v0.x = tri.v0[0]/128.0f; + v0.y = tri.v0[1]/128.0f; + v0.z = tri.v0[2]/128.0f; + v0.w = tri.v0[3]/128.0f; + v1.x = tri.v1[0]/128.0f; + v1.y = tri.v1[1]/128.0f; + v1.z = tri.v1[2]/128.0f; + v1.w = tri.v1[3]/128.0f; + v2.x = tri.v2[0]/128.0f; + v2.y = tri.v2[1]/128.0f; + v2.z = tri.v2[2]/128.0f; + v2.w = tri.v2[3]/128.0f; + plane.x = tri.plane[0]/4096.0f; + plane.y = tri.plane[1]/4096.0f; + plane.z = tri.plane[2]/4096.0f; + plane.w = tri.plane[3]/128.0f; + SphereToTriangleCollision(sph, v0, v1, v2, plane); +#endif +} +#endif \ No newline at end of file diff --git a/src/collision/VuCollision.h b/src/collision/VuCollision.h new file mode 100644 index 00000000..29ca4cbf --- /dev/null +++ b/src/collision/VuCollision.h @@ -0,0 +1,32 @@ +#pragma once + + +struct VuTriangle +{ + // Compressed int16 but unpacked +#ifdef GTA_PS2 + uint128 v0; + uint128 v1; + uint128 v2; + uint128 plane; +#else + int32 v0[4]; + int32 v1[4]; + int32 v2[4]; + int32 plane[4]; +#endif +}; + +#ifndef GTA_PS2 +extern int16 vi01; +extern CVuVector vf01; +extern CVuVector vf02; +extern CVuVector vf03; +#endif + +extern "C" { +void LineToTriangleCollision(const CVuVector &p0, const CVuVector &p1, const CVuVector &v0, const CVuVector &v1, const CVuVector &v2, const CVuVector &plane); +void LineToTriangleCollisionCompressed(const CVuVector &p0, const CVuVector &p1, VuTriangle &tri); +void SphereToTriangleCollision(const CVuVector &sph, const CVuVector &v0, const CVuVector &v1, const CVuVector &v2, const CVuVector &plane); +void SphereToTriangleCollisionCompressed(const CVuVector &sph, VuTriangle &tri); +} diff --git a/src/collision/vu0Collision.dsm b/src/collision/vu0Collision.dsm new file mode 100644 index 00000000..657c8b81 --- /dev/null +++ b/src/collision/vu0Collision.dsm @@ -0,0 +1,21 @@ +.align 4 +.global Vu0CollisionDmaTag +Vu0CollisionDmaTag: +DMAcnt * +MPG 0, * +.vu +.include "vu0Collision_1.s" +.EndMPG +.EndDmaData +DMAend + +.global Vu0Collision2DmaTag +Vu0Collision2DmaTag: +DMAcnt * +MPG 0, * +.vu +.include "vu0Collision_2.s" +.EndMPG +.EndDmaData +DMAend +.end diff --git a/src/collision/vu0Collision_1.s b/src/collision/vu0Collision_1.s new file mode 100644 index 00000000..055c8640 --- /dev/null +++ b/src/collision/vu0Collision_1.s @@ -0,0 +1,610 @@ +QuitAndFail: + NOP[E] IADDIU VI01, VI00, 0 + NOP NOP + + +QuitAndSucceed: + NOP[E] IADDIU VI01, VI00, 1 + NOP NOP + + +; 20 -- unused +; VF12, VF13 xyz: sphere centers +; VF14, VF15 x: sphere radii +; out: +; VI01: set when collision +; VF01: supposed to be intersection point? +; VF02: normal (pointing towards s1, not normalized) +.globl Vu0SphereToSphereCollision +Vu0SphereToSphereCollision: + SUB.xyz VF02, VF13, VF12 NOP ; dist of centers + ADD.x VF04, VF14, VF15 NOP ; s = sum of radii + MUL.xyzw VF03, VF02, VF02 NOP ; + MUL.x VF04, VF04, VF04 DIV Q, VF14x, VF04x ; square s + NOP NOP ; + NOP NOP ; + MULAx.w ACC, VF00, VF03 NOP ; + MADDAy.w ACC, VF00, VF03 NOP ; + MADDz.w VF03, VF00, VF03 NOP ; d = DistSq of centers + NOP NOP ; + MULAw.xyz ACC, VF12, VF00 NOP ; + MADDq.xyz VF01, VF02, Q NOP ; intersection, but wrong + CLIPw.xyz VF04, VF03 NOP ; compare s and d + SUB.xyz VF02, VF00, VF02 NOP ; compute normal + NOP NOP ; + NOP NOP ; + NOP FCAND VI01, 0x3 ; 0x2 cannot be set here + NOP[E] NOP ; + NOP NOP ; + + +; B8 -- unused +; VF12: +; VF13: radius +; VF14: +; VF15: box dimensions (?) +.globl Vu0SphereToAABBCollision +Vu0SphereToAABBCollision: + SUB.xyz VF03, VF12, VF14 LOI 0.5 + MULi.xyz VF15, VF15, I NOP + MUL.x VF13, VF13, VF13 NOP + SUB.xyz VF04, VF03, VF15 NOP + ADD.xyz VF05, VF03, VF15 MR32.xyzw VF16, VF15 + CLIPw.xyz VF03, VF16 MR32.xyzw VF17, VF16 + MUL.xyz VF04, VF04, VF04 NOP + MUL.xyz VF05, VF05, VF05 NOP + CLIPw.xyz VF03, VF17 MR32.xyzw VF16, VF17 + NOP FCAND VI01, 0x1 + MINI.xyz VF04, VF04, VF05 MFIR.x VF09, VI01 + NOP NOP + CLIPw.xyz VF03, VF16 FCAND VI01, 0x4 + NOP MFIR.y VF09, VI01 + NOP NOP + MULAx.w ACC, VF00, VF00 NOP + ADD.xyz VF01, VF00, VF03 FCAND VI01, 0x10 + NOP MFIR.z VF09, VI01 + NOP LOI 2 + NOP FCAND VI01, 0x30 + SUBAw.xyz ACC, VF00, VF00 IADD VI04, VI00, VI01 + ITOF0.xyz VF09, VF09 FCAND VI01, 0x300 + NOP IADD VI03, VI00, VI01 + NOP FCAND VI01, 0x3000 + NOP IADD VI02, VI00, VI01 + MADDi.xyzw VF09, VF09, I NOP + NOP IBEQ VI04, VI00, IgnoreZValue + NOP NOP + MADDAz.w ACC, VF00, VF04 NOP + MUL.z VF01, VF09, VF15 NOP +IgnoreZValue: + NOP IBEQ VI03, VI00, IgnoreYValue + NOP NOP + MADDAy.w ACC, VF00, VF04 NOP + MUL.y VF01, VF09, VF15 NOP +IgnoreYValue: + NOP IBEQ VI02, VI00, IgnoreXValue + NOP NOP + MADDAx.w ACC, VF00, VF04 NOP + MUL.x VF01, VF09, VF15 NOP +IgnoreXValue: + MADDx.w VF06, VF00, VF00 NOP + SUB.xyz VF02, VF03, VF01 NOP + ADD.xyz VF01, VF01, VF14 NOP + MULx.w VF01, VF00, VF00 NOP + CLIPw.xyz VF13, VF06 NOP + NOP NOP + NOP NOP + NOP NOP + NOP FCAND VI01, 0x1 +QuitMicrocode: + NOP[E] NOP + NOP NOP + + +; 240 +.globl Vu0LineToSphereCollision +Vu0LineToSphereCollision: + SUB.xyzw VF01, VF13, VF12 NOP + SUB.xyzw VF02, VF14, VF12 NOP + MUL.xyz VF03, VF01, VF02 NOP + MUL.xyz VF04, VF01, VF01 NOP + MUL.x VF15, VF15, VF15 NOP + MUL.xyz VF02, VF02, VF02 NOP + MULAx.w ACC, VF00, VF03 NOP + MADDAy.w ACC, VF00, VF03 NOP + MADDz.w VF03, VF00, VF03 NOP + MULAx.w ACC, VF00, VF04 NOP + MADDAy.w ACC, VF00, VF04 NOP + MADDz.w VF01, VF00, VF04 NOP + MULAx.w ACC, VF00, VF02 NOP + MADDAy.w ACC, VF00, VF02 NOP + MADDz.w VF02, VF00, VF02 NOP + MULA.w ACC, VF03, VF03 NOP + MADDAx.w ACC, VF01, VF15 NOP + MSUB.w VF05, VF01, VF02 NOP + NOP NOP + NOP NOP + NOP IADDIU VI02, VI00, 0x10 + NOP FMAND VI01, VI02 + NOP IBNE VI01, VI00, QuitAndFail + NOP NOP + CLIPw.xyz VF15, VF02 SQRT Q, VF05w + NOP NOP + NOP NOP + NOP NOP + NOP FCAND VI01, 0x1 + NOP IBNE VI00, VI01, LineStartInsideSphere + NOP NOP + SUBq.w VF05, VF03, Q NOP + SUB.w VF05, VF05, VF01 DIV Q, VF05w, VF01w + NOP FMAND VI01, VI02 + NOP IBNE VI01, VI00, QuitAndFail + NOP NOP + NOP FMAND VI01, VI02 + NOP IBEQ VI01, VI00, QuitAndFail + NOP NOP + ADDA.xyz ACC, VF12, VF00 NOP + MADDq.xyz VF01, VF01, Q NOP + MULx.w VF01, VF00, VF00 NOP + SUB.xyz VF02, VF01, VF14 NOP + NOP[E] NOP + NOP NOP +LineStartInsideSphere: + NOP MOVE.xyzw VF01, VF12 + NOP[E] IADDIU VI01, VI00, 0x1 + NOP NOP + + +; 3C0 +.globl Vu0LineToAABBCollision +Vu0LineToAABBCollision: + SUB.xyzw VF08, VF13, VF12 LOI 0.5 + MULi.xyz VF15, VF15, I IADDIU VI08, VI00, 0x0 + SUB.xyzw VF12, VF12, VF14 NOP + SUB.xyzw VF13, VF13, VF14 NOP + NOP DIV Q, VF00w, VF08x + NOP MR32.xyzw VF03, VF15 + SUB.xyz VF06, VF15, VF12 NOP + ADD.xyz VF07, VF15, VF12 NOP + NOP NOP + CLIPw.xyz VF12, VF03 MR32.xyzw VF04, VF03 + NOP NOP + ADDq.x VF09, VF00, Q DIV Q, VF00w, VF08y + NOP NOP + CLIPw.xyz VF12, VF04 MR32.xyzw VF05, VF04 + SUB.xyz VF07, VF00, VF07 IADDIU VI06, VI00, 0xCC + NOP IADDIU VI07, VI00, 0x30 + NOP NOP + CLIPw.xyz VF12, VF05 FCGET VI02 + NOP IAND VI02, VI02, VI06 + ADDq.y VF09, VF00, Q DIV Q, VF00w, VF08z + SUB.xyz VF10, VF00, VF10 NOP + CLIPw.xyz VF13, VF03 FCGET VI03 + CLIPw.xyz VF13, VF04 IAND VI03, VI03, VI07 + CLIPw.xyz VF13, VF05 FCAND VI01, 0x3330 + NOP IBEQ VI01, VI00, StartPointInsideAABB + NOP NOP + ADDq.z VF09, VF00, Q FCGET VI04 + NOP FCGET VI05 + NOP IAND VI04, VI04, VI06 + NOP IAND VI05, VI05, VI07 + MULx.xyz VF17, VF08, VF09 NOP + MULy.xyz VF18, VF08, VF09 IADDIU VI07, VI00, 0x80 + MULz.xyz VF19, VF08, VF09 IAND VI06, VI02, VI07 + MUL.w VF10, VF00, VF00 IAND VI07, VI04, VI07 + NOP NOP + NOP IBEQ VI06, VI07, CheckMaxXSide + NOP NOP + MULAx.xyz ACC, VF17, VF07 NOP + MADDw.xyz VF16, VF12, VF00 NOP + MUL.x VF10, VF07, VF09 NOP + CLIPw.xyz VF16, VF04 NOP + CLIPw.xyz VF16, VF05 NOP + NOP NOP + NOP NOP + NOP NOP + NOP FCAND VI01, 0x330 + NOP IBNE VI01, VI00, CheckMaxXSide + NOP NOP + MULx.w VF10, VF00, VF10 IADDIU VI08, VI00, 0x1 + ADD.yz VF02, VF00, VF00 MOVE.xyzw VF01, VF16 + SUBw.x VF02, VF00, VF00 NOP +CheckMaxXSide: + MULAx.xyz ACC, VF17, VF06 IADDIU VI07, VI00, 0x40 + MADDw.xyz VF16, VF12, VF00 IAND VI06, VI02, VI07 + MUL.x VF10, VF06, VF09 IAND VI07, VI04, VI07 + NOP NOP + NOP IBEQ VI06, VI07, CheckMinYSide + NOP NOP + CLIPw.xyz VF16, VF04 NOP + CLIPw.xyz VF16, VF05 NOP + CLIPw.xyz VF10, VF10 NOP + NOP NOP + NOP NOP + NOP NOP + NOP FCAND VI01, 0xCC03 + NOP IBNE VI01, VI00, CheckMinYSide + NOP NOP + MULx.w VF10, VF00, VF10 IADDIU VI08, VI00, 0x1 + ADD.yz VF02, VF00, VF00 MOVE.xyzw VF01, VF16 + ADDw.x VF02, VF00, VF00 NOP +CheckMinYSide: + MULAy.xyz ACC, VF18, VF07 IADDIU VI07, VI00, 0x8 + MADDw.xyz VF16, VF12, VF00 IAND VI06, VI02, VI07 + MUL.y VF10, VF07, VF09 IAND VI07, VI04, VI07 + NOP NOP + NOP IBEQ VI06, VI07, CheckMaxYSide + NOP NOP + CLIPw.xyz VF16, VF03 NOP + CLIPw.xyz VF16, VF05 NOP + CLIPw.xyz VF10, VF10 NOP + NOP NOP + NOP NOP + NOP NOP + NOP FCAND VI01, 0x3C0C + NOP IBNE VI01, VI00, CheckMaxYSide + NOP NOP + MULy.w VF10, VF00, VF10 IADDIU VI08, VI00, 0x1 + ADD.xz VF02, VF00, VF00 MOVE.xyzw VF01, VF16 + SUBw.y VF02, VF00, VF00 NOP +CheckMaxYSide: + MULAy.xyz ACC, VF18, VF06 IADDIU VI07, VI00, 0x4 + MADDw.xyz VF16, VF12, VF00 IAND VI06, VI02, VI07 + MUL.y VF10, VF06, VF09 IAND VI07, VI04, VI07 + NOP NOP + NOP IBEQ VI06, VI07, CheckMinZSide + NOP NOP + CLIPw.xyz VF16, VF03 NOP + CLIPw.xyz VF16, VF05 NOP + CLIPw.xyz VF10, VF10 NOP + NOP NOP + NOP NOP + NOP NOP + NOP FCAND VI01, 0x3C0C + NOP IBNE VI01, VI00, CheckMinZSide + NOP NOP + MULy.w VF10, VF00, VF10 IADDIU VI08, VI00, 0x1 + ADD.xz VF02, VF00, VF00 MOVE.xyzw VF01, VF16 + ADDw.y VF02, VF00, VF00 NOP +CheckMinZSide: + MULAz.xyz ACC, VF19, VF07 IADDIU VI07, VI00, 0x20 + MADDw.xyz VF16, VF12, VF00 IAND VI06, VI03, VI07 + MUL.z VF10, VF07, VF09 IAND VI07, VI05, VI07 + NOP NOP + NOP IBEQ VI06, VI07, CheckMaxZSide + NOP NOP + CLIPw.xyz VF16, VF03 NOP + CLIPw.xyz VF16, VF04 NOP + CLIPw.xyz VF10, VF10 NOP + NOP NOP + NOP NOP + NOP NOP + NOP FCAND VI01, 0x3330 + NOP IBNE VI01, VI00, CheckMaxZSide + NOP NOP + MULz.w VF10, VF00, VF10 IADDIU VI08, VI00, 0x1 + ADD.xy VF02, VF00, VF00 MOVE.xyzw VF01, VF16 + SUBw.z VF02, VF00, VF00 NOP +CheckMaxZSide: + MULAz.xyz ACC, VF19, VF06 IADDIU VI07, VI00, 0x10 + MADDw.xyz VF16, VF12, VF00 IAND VI06, VI03, VI07 + MUL.z VF10, VF06, VF09 IAND VI07, VI05, VI07 + NOP NOP + NOP IBEQ VI06, VI07, DoneAllChecks + NOP NOP + CLIPw.xyz VF16, VF03 NOP + CLIPw.xyz VF16, VF04 NOP + CLIPw.xyz VF10, VF10 NOP + NOP NOP + NOP NOP + NOP NOP + NOP FCAND VI01, 0x3330 + NOP IBNE VI01, VI00, DoneAllChecks + NOP NOP + MULz.w VF10, VF00, VF10 IADDIU VI08, VI00, 0x1 + ADD.xy VF02, VF00, VF00 MOVE.xyzw VF01, VF16 + ADDw.z VF02, VF00, VF00 NOP +DoneAllChecks: + ADD.xyz VF01, VF01, VF14 IADD VI01, VI00, VI08 + NOP[E] NOP + NOP NOP +StartPointInsideAABB: + ADD.xyz VF01, VF12, VF14 WAITQ + NOP IADDIU VI01, VI00, 0x1 + NOP[E] NOP + NOP NOP + + +; 860 +.globl Vu0LineToTriangleCollisionCompressedStart +Vu0LineToTriangleCollisionCompressedStart: + ITOF0.xyzw VF17, VF17 LOI 0.000244140625 ; 1.0/4096.0 + ITOF0.xyzw VF14, VF14 NOP + ITOF0.xyzw VF15, VF15 NOP + ITOF0.xyzw VF16, VF16 NOP + MULi.xyz VF17, VF17, I LOI 0.0078125 ; 1.0/128.0 + MULi.w VF17, VF17, I NOP + MULi.xyzw VF14, VF14, I NOP + MULi.xyzw VF15, VF15, I NOP + MULi.xyzw VF16, VF16, I NOP +; fall through + +; 8A8 +; VF12: point0 +; VF13: point1 +; VF14-16: verts +; VF17: plane +; out: +; VF01: intersection point +; VF02: triangle normal +; VF03 x: intersection parameter +.globl Vu0LineToTriangleCollisionStart +Vu0LineToTriangleCollisionStart: + MUL.xyz VF10, VF17, VF12 LOI 0.5 + MUL.xyz VF11, VF17, VF13 NOP + SUB.xyz VF02, VF13, VF12 NOP ; line dist + ADD.xyz VF17, VF17, VF00 NOP + MULi.w VF03, VF00, I NOP + MULAx.w ACC, VF00, VF10 NOP + MADDAy.w ACC, VF00, VF10 IADDIU VI06, VI00, 0xE0 + MADDz.w VF10, VF00, VF10 FMAND VI05, VI06 ; -- normal sign flags, unused + MULAx.w ACC, VF00, VF11 NOP + MADDAy.w ACC, VF00, VF11 NOP + MADDz.w VF11, VF00, VF11 NOP + SUB.w VF09, VF17, VF10 NOP ; plane-pos 0 + CLIPw.xyz VF17, VF03 NOP ; compare normal against 0.5 to figure out which in which dimension to compare + NOP IADDIU VI02, VI00, 0x10 ; Sw flag + SUBA.w ACC, VF17, VF11 NOP ; plane-pos 1 + SUB.w VF08, VF11, VF10 FMAND VI01, VI02 + NOP NOP + NOP NOP + NOP FMAND VI02, VI02 + NOP IBEQ VI01, VI02, QuitAndFail ; if on same side, no collision + NOP NOP + NOP DIV Q, VF09w, VF08w ; parameter of intersection + NOP FCAND VI01, 0x3 ; check x direction + NOP IADDIU VI02, VI01, 0x7F + NOP IADDIU VI06, VI00, 0x80 + NOP IAND VI02, VI02, VI06 ; Sx flag + NOP FCAND VI01, 0xC ; check y direction + NOP IADDIU VI03, VI01, 0x3F + MULAw.xyz ACC, VF12, VF00 IADDIU VI06, VI00, 0x40 + MADDq.xyz VF01, VF02, Q IAND VI03, VI03, VI06 ; point of intersection -- Sy flag + MULx.w VF01, VF00, VF00 FCAND VI01, 0x30 ; -- check z direction + ADDq.x VF03, VF00, Q IADDIU VI04, VI01, 0x1F ; output parameter + SUB.xyz VF05, VF15, VF14 IADDIU VI06, VI00, 0x20 ; edge vectors + SUB.xyz VF08, VF01, VF14 IAND VI04, VI04, VI06 ; edge vectors -- Sz flag + SUB.xyz VF06, VF16, VF15 IADD VI06, VI02, VI03 ; edge vectors + SUB.xyz VF09, VF01, VF15 IADD VI06, VI06, VI04 ; edge vectors -- combine flags + SUB.xyz VF07, VF14, VF16 NOP ; edge vectors + SUB.xyz VF10, VF01, VF16 NOP ; edge vectors + OPMULA.xyz ACC, VF08, VF05 NOP + OPMSUB.xyz VF18, VF05, VF08 NOP ; cross1 + OPMULA.xyz ACC, VF09, VF06 NOP + OPMSUB.xyz VF19, VF06, VF09 NOP ; cross2 + OPMULA.xyz ACC, VF10, VF07 NOP + OPMSUB.xyz VF20, VF07, VF10 FMAND VI02, VI06 ; cross3 + NOP NOP + NOP FMAND VI03, VI06 + NOP NOP + NOP FMAND VI04, VI06 + NOP NOP + NOP IBNE VI03, VI02, QuitAndFail ; point has to lie on the same side of all edges (i.e. inside) + NOP NOP + NOP IBNE VI04, VI02, QuitAndFail + NOP NOP + MULw.xyz VF02, VF17, VF00 IADDIU VI01, VI00, 0x1 ; success + NOP[E] NOP + NOP NOP + + +; A68 +; VF12: center +; VF14: line origin +; VF15: line vector to other point +; out: VF16 xyz: nearest point on line; w: distance to that point +DistanceBetweenSphereAndLine: + SUB.xyz VF20, VF12, VF14 NOP + MUL.xyz VF21, VF15, VF15 NOP + ADDA.xyz ACC, VF14, VF15 NOP + MSUBw.xyz VF25, VF12, VF00 NOP ; VF25 = VF12 - (VF14+VF15) + MUL.xyz VF22, VF20, VF20 NOP + MUL.xyz VF23, VF20, VF15 NOP + MULAx.w ACC, VF00, VF21 NOP + MADDAy.w ACC, VF00, VF21 NOP + MADDz.w VF21, VF00, VF21 NOP ; MagSq VF15 (line length) + MULAx.w ACC, VF00, VF23 NOP + MADDAy.w ACC, VF00, VF23 NOP + MADDz.w VF23, VF00, VF23 NOP ; dot(VF12-VF14, VF15) + MULAx.w ACC, VF00, VF22 NOP + MADDAy.w ACC, VF00, VF22 NOP + MADDz.w VF22, VF00, VF22 IADDIU VI08, VI00, 0x10 ; MagSq VF12-VF14 -- Sw bit + MUL.xyz VF25, VF25, VF25 FMAND VI08, VI08 + NOP DIV Q, VF23w, VF21w + NOP IBNE VI00, VI08, NegativeRatio + NOP NOP + ADDA.xyz ACC, VF00, VF14 NOP + MADDq.xyz VF16, VF15, Q WAITQ ; nearest point on infinte line + ADDq.x VF24, VF00, Q NOP ; ratio + NOP NOP + NOP NOP + SUB.xyz VF26, VF16, VF12 NOP + CLIPw.xyz VF24, VF00 NOP ; compare ratio to 1.0 + NOP NOP + NOP NOP + MUL.xyz VF26, VF26, VF26 NOP + NOP FCAND VI01, 0x1 + NOP IBNE VI00, VI01, RatioGreaterThanOne + NOP NOP + MULAx.w ACC, VF00, VF26 NOP + MADDAy.w ACC, VF00, VF26 NOP + MADDz.w VF16, VF00, VF26 NOP ; distance + NOP JR VI15 + NOP NOP +NegativeRatio: + ADD.xyz VF16, VF00, VF14 NOP ; return line origin + MUL.w VF16, VF00, VF22 NOP ; and DistSq to it + NOP JR VI15 + NOP NOP +RatioGreaterThanOne: + MULAx.w ACC, VF00, VF25 NOP + MADDAy.w ACC, VF00, VF25 NOP + MADDz.w VF16, VF00, VF25 NOP + ADD.xyz VF16, VF14, VF15 NOP ; return toerh line point + NOP JR VI15 + NOP NOP + + +; BE0 +.globl Vu0SphereToTriangleCollisionCompressedStart +Vu0SphereToTriangleCollisionCompressedStart: + ITOF0.xyzw VF17, VF17 LOI 0.000244140625 ; 1.0/4096.0 + ITOF0.xyzw VF14, VF14 NOP + ITOF0.xyzw VF15, VF15 NOP + ITOF0.xyzw VF16, VF16 NOP + MULi.xyz VF17, VF17, I LOI 0.0078125 ; 1.0/128.0 + MULi.w VF17, VF17, I NOP + MULi.xyzw VF14, VF14, I NOP + MULi.xyzw VF15, VF15, I NOP + MULi.xyzw VF16, VF16, I NOP +; fall through + +; C28 +; VF12: sphere +; VF14-16: verts +; VF17: plane +; out: +; VF01: intersection point +; VF02: triangle normal +; VF03 x: intersection parameter +.globl Vu0SphereToTriangleCollisionStart +Vu0SphereToTriangleCollisionStart: + MUL.xyz VF02, VF12, VF17 LOI 0.1 + ADD.xyz VF17, VF17, VF00 NOP + ADDw.x VF13, VF00, VF12 NOP + NOP NOP + MULAx.w ACC, VF00, VF02 IADDIU VI06, VI00, 0xE0 + MADDAy.w ACC, VF00, VF02 FMAND VI05, VI06 ; normal sign flags + MADDAz.w ACC, VF00, VF02 NOP + MSUB.w VF02, VF00, VF17 NOP ; center plane pos + MULi.w VF03, VF00, I MOVE.xyzw VF04, VF03 + NOP NOP + NOP NOP + CLIPw.xyz VF13, VF02 NOP ; compare dist and radius + CLIPw.xyz VF17, VF03 NOP + MULAw.xyz ACC, VF12, VF00 IADDIU VI07, VI00, 0x0 ; -- clear test case + MSUBw.xyz VF01, VF17, VF02 NOP + MULx.w VF01, VF00, VF00 FCAND VI01, 0x3 ; projected center on plane + ABS.w VF02, VF02 IBEQ VI00, VI01, QuitAndFail ; no intersection + NOP NOP + NOP FCAND VI01, 0x3 ; -- check x direction + SUB.xyz VF02, VF12, VF01 IADDIU VI02, VI01, 0x7F + NOP IADDIU VI06, VI00, 0x80 + SUB.xyz VF05, VF15, VF14 IAND VI02, VI02, VI06 + SUB.xyz VF08, VF01, VF14 FCAND VI01, 0xC ; -- check y direction + SUB.xyz VF06, VF16, VF15 IADDIU VI03, VI01, 0x3F + SUB.xyz VF09, VF01, VF15 IADDIU VI06, VI00, 0x40 + SUB.xyz VF07, VF14, VF16 IAND VI03, VI03, VI06 + SUB.xyz VF10, VF01, VF16 FCAND VI01, 0x30 ; -- check z direction + MUL.xyz VF03, VF02, VF02 IADDIU VI04, VI01, 0x1F + OPMULA.xyz ACC, VF08, VF05 IADDIU VI06, VI00, 0x20 + OPMSUB.xyz VF18, VF05, VF08 IAND VI04, VI04, VI06 + OPMULA.xyz ACC, VF09, VF06 NOP + OPMSUB.xyz VF19, VF06, VF09 IADD VI06, VI02, VI03 + OPMULA.xyz ACC, VF10, VF07 IADD VI06, VI06, VI04 ; -- combine flags + OPMSUB.xyz VF20, VF07, VF10 FMAND VI02, VI06 ; -- cross 1 flags + MULAx.w ACC, VF00, VF03 IAND VI05, VI05, VI06 + MADDAy.w ACC, VF00, VF03 FMAND VI03, VI06 ; -- cross 2 flags + MADDz.w VF03, VF00, VF03 IADDIU VI08, VI00, 0x3 + NOP FMAND VI04, VI06 ; -- cross 3 flags + NOP NOP + NOP IBNE VI02, VI05, CheckSide2 + NOP RSQRT Q, VF00w, VF03w + ADD.xyz VF04, VF00, VF16 IADDIU VI07, VI07, 0x1 ; inside side 1 +CheckSide2: + NOP IBNE VI03, VI05, CheckSide3 + NOP NOP + ADD.xyz VF04, VF00, VF14 IADDIU VI07, VI07, 0x1 ; inside side 2 +CheckSide3: + NOP IBNE VI04, VI05, FinishCheckingSides + NOP NOP + ADD.xyz VF04, VF00, VF15 IADDIU VI07, VI07, 0x1 ; inside side 3 + NOP NOP + NOP IBEQ VI07, VI08, TotallyInsideTriangle + NOP NOP +FinishCheckingSides: + MUL.x VF13, VF13, VF13 IADDIU VI08, VI00, 0x2 + MULq.xyz VF02, VF02, Q WAITQ + NOP IBNE VI07, VI08, IntersectionOutsideTwoSides + NOP NOP + NOP IBEQ VI02, VI05, CheckDistanceSide2 + NOP NOP + NOP MOVE.xyzw VF15, VF05 + NOP BAL VI15, DistanceBetweenSphereAndLine + NOP NOP + NOP B ProcessLineResult + NOP NOP +CheckDistanceSide2: + NOP IBEQ VI03, VI05, CheckDistanceSide3 + NOP NOP + NOP MOVE.xyzw VF14, VF15 + NOP MOVE.xyzw VF15, VF06 + NOP BAL VI15, DistanceBetweenSphereAndLine + NOP NOP + NOP B ProcessLineResult + NOP NOP +CheckDistanceSide3: + NOP MOVE.xyzw VF14, VF16 + NOP MOVE.xyzw VF15, VF07 + NOP BAL VI15, DistanceBetweenSphereAndLine + NOP NOP + NOP B ProcessLineResult + NOP NOP +IntersectionOutsideTwoSides: + SUB.xyz VF05, VF04, VF12 NOP + ADD.xyz VF01, VF00, VF04 NOP ; col point + SUB.xyz VF02, VF12, VF04 NOP + NOP NOP + MUL.xyz VF05, VF05, VF05 NOP + NOP NOP + NOP NOP + NOP NOP + MULAx.w ACC, VF00, VF05 NOP + MADDAy.w ACC, VF00, VF05 NOP + MADDz.w VF05, VF00, VF05 NOP ; distSq to vertex + NOP NOP + NOP NOP + NOP NOP + CLIPw.xyz VF13, VF05 SQRT Q, VF05w ; compare radiusSq and distSq + NOP NOP + NOP NOP + NOP NOP + NOP FCAND VI01, 0x1 + ADDq.x VF03, VF00, Q WAITQ ; dist to vertex + NOP IBEQ VI00, VI01, QuitAndFail ; too far + NOP NOP + NOP NOP + NOP DIV Q, VF00w, VF03x + MULq.xyz VF02, VF02, Q WAITQ ; col normal + NOP[E] NOP + NOP NOP +TotallyInsideTriangle: + ADDw.x VF03, VF00, VF02 WAITQ + MULq.xyz VF02, VF02, Q NOP + NOP[E] IADDIU VI01, VI00, 0x1 + NOP NOP +ProcessLineResult: + CLIPw.xyz VF13, VF16 SQRT Q, VF16w + ADD.xyz VF01, VF00, VF16 NOP + SUB.xyz VF02, VF12, VF16 NOP + NOP NOP + NOP FCAND VI01, 0x1 + ADDq.x VF03, VF00, Q WAITQ + NOP IBEQ VI00, VI01, QuitAndFail + NOP NOP + NOP NOP + NOP DIV Q, VF00w, VF03x + MULq.xyz VF02, VF02, Q WAITQ + NOP[E] NOP + NOP NOP + +EndOfMicrocode: diff --git a/src/collision/vu0Collision_2.s b/src/collision/vu0Collision_2.s new file mode 100644 index 00000000..716c29ac --- /dev/null +++ b/src/collision/vu0Collision_2.s @@ -0,0 +1,191 @@ +QuitAndFail2: + NOP[E] IADDIU VI01, VI00, 0x0 + NOP NOP + + +QuitAndSucceed2: + NOP[E] IADDIU VI01, VI00, 0x1 + NOP NOP + + +; 20 +GetBBVertices: + MULw.xy VF02, VF01, VF00 NOP + MUL.z VF02, VF01, VF11 NOP + MULw.xz VF03, VF01, VF00 NOP + MUL.y VF03, VF01, VF11 NOP + MULw.x VF04, VF01, VF00 NOP + MUL.yz VF04, VF01, VF11 NOP + NOP JR VI15 + NOP NOP + + +; 60 +Vu0OBBToOBBCollision: + SUBw.xyz VF11, VF00, VF00 LOI 0.5 + MULi.xyz VF12, VF12, I NOP + MULi.xyz VF13, VF13, I NOP + NOP NOP + NOP NOP + NOP MOVE.xyz VF01, VF12 + NOP BAL VI15, GetBBVertices + NOP NOP + MULAx.xyz ACC, VF14, VF01 NOP + MADDAy.xyz ACC, VF15, VF01 NOP + MADDz.xyz VF01, VF16, VF01 NOP + MULAx.xyz ACC, VF14, VF02 NOP + MADDAy.xyz ACC, VF15, VF02 NOP + MADDz.xyz VF02, VF16, VF02 NOP + MULAx.xyz ACC, VF14, VF03 NOP + MADDAy.xyz ACC, VF15, VF03 NOP + MADDz.xyz VF03, VF16, VF03 NOP + MULAx.xyz ACC, VF14, VF04 NOP + MADDAy.xyz ACC, VF15, VF04 NOP + MADDz.xyz VF04, VF16, VF04 NOP + ABS.xyz VF05, VF01 NOP + ABS.xyz VF06, VF02 NOP + ABS.xyz VF07, VF03 NOP + ABS.xyz VF08, VF04 NOP + NOP NOP + MAX.xyz VF05, VF05, VF06 NOP + NOP NOP + MAX.xyz VF07, VF07, VF08 NOP + NOP NOP + NOP NOP + NOP NOP + MAX.xyz VF05, VF05, VF07 NOP + NOP NOP + NOP NOP + NOP NOP + ADD.xyz VF09, VF05, VF13 NOP + NOP NOP + NOP NOP + NOP NOP + MULx.w VF05, VF00, VF09 NOP + MULy.w VF06, VF00, VF09 NOP + MULz.w VF07, VF00, VF09 NOP + CLIPw.xyz VF17, VF05 NOP + CLIPw.xyz VF17, VF06 NOP + CLIPw.xyz VF17, VF07 MOVE.xyz VF01, VF13 + NOP NOP + NOP NOP + NOP NOP + NOP FCAND VI01, 0x3330 + NOP IBNE VI01, VI00, QuitAndFail2 + NOP NOP + NOP BAL VI15, GetBBVertices + NOP NOP + MULAx.xyz ACC, VF18, VF01 NOP + MADDAy.xyz ACC, VF19, VF01 NOP + MADDz.xyz VF01, VF20, VF01 NOP + MULAx.xyz ACC, VF18, VF02 NOP + MADDAy.xyz ACC, VF19, VF02 NOP + MADDz.xyz VF02, VF20, VF02 NOP + MULAx.xyz ACC, VF18, VF03 NOP + MADDAy.xyz ACC, VF19, VF03 NOP + MADDz.xyz VF03, VF20, VF03 NOP + MULAx.xyz ACC, VF18, VF04 NOP + MADDAy.xyz ACC, VF19, VF04 NOP + MADDz.xyz VF04, VF20, VF04 NOP + ABS.xyz VF05, VF01 NOP + ABS.xyz VF06, VF02 NOP + ABS.xyz VF07, VF03 NOP + ABS.xyz VF08, VF04 NOP + NOP NOP + MAX.xyz VF05, VF05, VF06 NOP + NOP NOP + MAX.xyz VF07, VF07, VF08 NOP + NOP NOP + NOP NOP + NOP NOP + MAX.xyz VF05, VF05, VF07 NOP + NOP NOP + NOP NOP + NOP NOP + ADD.xyz VF09, VF05, VF12 NOP + NOP NOP + NOP NOP + NOP NOP + MULx.w VF05, VF00, VF09 NOP + MULy.w VF06, VF00, VF09 NOP + MULz.w VF07, VF00, VF09 NOP + CLIPw.xyz VF21, VF05 NOP + CLIPw.xyz VF21, VF06 NOP + CLIPw.xyz VF21, VF07 NOP + NOP NOP + NOP NOP + NOP NOP + NOP FCAND VI01, 0x3330 + NOP IBNE VI01, VI00, QuitAndFail2 + NOP NOP + SUB.xyz VF06, VF02, VF01 NOP + SUB.xyz VF07, VF03, VF01 NOP + ADD.xyz VF08, VF04, VF01 NOP + ADD.x VF09, VF00, VF12 NOP + ADD.yz VF09, VF00, VF00 NOP + ADD.y VF10, VF00, VF12 NOP + ADD.xz VF10, VF00, VF00 NOP + ADD.z VF11, VF00, VF12 IADDI VI04, VI00, 0x0 + ADD.xy VF11, VF00, VF00 IADD VI02, VI00, VI00 + OPMULA.xyz ACC, VF06, VF09 NOP + OPMSUB.xyz VF01, VF09, VF06 NOP + OPMULA.xyz ACC, VF06, VF10 NOP + OPMSUB.xyz VF02, VF10, VF06 NOP + OPMULA.xyz ACC, VF06, VF11 NOP + OPMSUB.xyz VF03, VF11, VF06 SQI.xyzw VF01, (VI02++) + OPMULA.xyz ACC, VF07, VF09 NOP + OPMSUB.xyz VF01, VF09, VF07 SQI.xyzw VF02, (VI02++) + OPMULA.xyz ACC, VF07, VF10 NOP + OPMSUB.xyz VF02, VF10, VF07 SQI.xyzw VF03, (VI02++) + OPMULA.xyz ACC, VF07, VF11 NOP + OPMSUB.xyz VF03, VF11, VF07 SQI.xyzw VF01, (VI02++) + OPMULA.xyz ACC, VF08, VF09 NOP + OPMSUB.xyz VF01, VF09, VF08 SQI.xyzw VF02, (VI02++) + OPMULA.xyz ACC, VF08, VF10 NOP + OPMSUB.xyz VF02, VF10, VF08 SQI.xyzw VF03, (VI02++) + OPMULA.xyz ACC, VF08, VF11 LOI 0.5 + OPMSUB.xyz VF01, VF11, VF08 SQI.xyzw VF01, (VI02++) + MULi.xyz VF06, VF06, I NOP + MULi.xyz VF07, VF07, I SQI.xyzw VF02, (VI02++) + MULi.xyz VF08, VF08, I NOP + MUL.xyz VF02, VF21, VF01 NOP + MUL.xyz VF03, VF12, VF01 NOP + MUL.xyz VF09, VF06, VF01 NOP + MUL.xyz VF10, VF07, VF01 NOP + MUL.xyz VF11, VF08, VF01 NOP + ABS.xyz VF03, VF03 NOP + ADDy.x VF05, VF09, VF09 NOP + ADDx.y VF05, VF10, VF10 NOP + ADDx.z VF05, VF11, VF11 NOP + NOP NOP +EdgePairLoop: + ADDz.x VF05, VF05, VF09 NOP + ADDz.y VF05, VF05, VF10 NOP + ADDy.z VF05, VF05, VF11 NOP + MULAx.w ACC, VF00, VF02 IADD VI03, VI02, VI00 + MADDAy.w ACC, VF00, VF02 LQD.xyzw VF01, (--VI02) + MADDz.w VF02, VF00, VF02 NOP + ABS.xyz VF05, VF05 NOP + MULAx.w ACC, VF00, VF03 NOP + MADDAy.w ACC, VF00, VF03 NOP + MADDAz.w ACC, VF00, VF03 NOP + MADDAx.w ACC, VF00, VF05 NOP + MADDAy.w ACC, VF00, VF05 NOP + MADDz.w VF03, VF00, VF05 NOP + ADDw.x VF04, VF00, VF02 NOP + MUL.xyz VF02, VF21, VF01 NOP + MUL.xyz VF03, VF12, VF01 NOP + MUL.xyz VF09, VF06, VF01 NOP + CLIPw.xyz VF04, VF03 NOP + MUL.xyz VF10, VF07, VF01 NOP + MUL.xyz VF11, VF08, VF01 NOP + ABS.xyz VF03, VF03 NOP + ADDy.x VF05, VF09, VF09 FCAND VI01, 0x3 + ADDx.y VF05, VF10, VF10 IBNE VI01, VI00, QuitAndFail2 + ADDx.z VF05, VF11, VF11 NOP + NOP IBNE VI03, VI00, EdgePairLoop + NOP NOP + NOP[E] IADDIU VI01, VI00, 0x1 + NOP NOP + +EndOfMicrocode2: diff --git a/src/core/Collision.cpp b/src/core/Collision.cpp deleted file mode 100644 index d8603cd8..00000000 --- a/src/core/Collision.cpp +++ /dev/null @@ -1,3290 +0,0 @@ -#include "common.h" - -#include "VuVector.h" -#include "main.h" -#include "Lists.h" -#include "Game.h" -#include "Zones.h" -#include "General.h" -#include "ZoneCull.h" -#include "World.h" -#include "Entity.h" -#include "Train.h" -#include "Streaming.h" -#include "Pad.h" -#include "DMAudio.h" -#include "Population.h" -#include "FileLoader.h" -#include "Replay.h" -#include "CutsceneMgr.h" -#include "RenderBuffer.h" -#include "SurfaceTable.h" -#include "Lines.h" -#include "Collision.h" -#include "Frontend.h" - - -// TODO: where do these go? - -#ifdef VU_COLLISION - -struct VuTriangle -{ - // Compressed int16 but unpacked -#ifdef GTA_PS2 - uint128 v0; - uint128 v1; - uint128 v2; - uint128 plane; -#else - int32 v0[4]; - int32 v1[4]; - int32 v2[4]; - int32 plane[4]; -#endif -}; - -#ifndef GTA_PS2 -static int16 vi01; -static CVuVector vf01; -static CVuVector vf02; -static CVuVector vf03; - -CVuVector -DistanceBetweenSphereAndLine(const CVuVector ¢er, const CVuVector &p0, const CVuVector &line) -{ - // center VF12 - // p0 VF14 - // line VF15 - CVuVector ret; // VF16 - CVuVector p1 = p0+line; - CVuVector dist0 = center - p0; // VF20 - CVuVector dist1 = center - p1; // VF25 - float lenSq = line.MagnitudeSqr(); // VF21 - float distSq0 = dist0.MagnitudeSqr(); // VF22 - float distSq1 = dist1.MagnitudeSqr(); - float dot = DotProduct(dist0, line); // VF23 - if(dot < 0.0f){ - // not above line, closest to p0 - ret = p0; - ret.w = distSq0; - return ret; - } - float t = dot/lenSq; // param of nearest point on infinite line - if(t > 1.0f){ - // not above line, closest to p1 - ret = p1; - ret.w = distSq1; - return ret; - } - // closest to line - ret = p0 + line*t; - ret.w = (ret - center).MagnitudeSqr(); - return ret; -} -inline int SignFlags(const CVector &v) -{ - int f = 0; - if(v.x < 0.0f) f |= 1; - if(v.y < 0.0f) f |= 2; - if(v.z < 0.0f) f |= 4; - return f; -} -#endif - -extern "C" void -LineToTriangleCollision(const CVuVector &p0, const CVuVector &p1, - const CVuVector &v0, const CVuVector &v1, const CVuVector &v2, - const CVuVector &plane) -{ -#ifdef GTA_PS2 - __asm__ volatile ( - ".set noreorder\n" - "lqc2 vf12, 0x0(%0)\n" - "lqc2 vf13, 0x0(%1)\n" - "lqc2 vf14, 0x0(%2)\n" - "lqc2 vf15, 0x0(%3)\n" - "lqc2 vf16, 0x0(%4)\n" - "lqc2 vf17, 0x0(%5)\n" - "vcallms Vu0LineToTriangleCollisionStart\n" - ".set reorder\n" - : - : "r" (&p0), "r" (&p1), "r" (&v0), "r" (&v1), "r" (&v2), "r" (&plane) - ); -#else - float dot0 = DotProduct(plane, p0); - float dot1 = DotProduct(plane, p1); - float dist0 = plane.w - dot0; - float dist1 = plane.w - dot1; - - // if points are on the same side, no collision - if(dist0 * dist1 > 0.0f){ - vi01 = 0; - return; - } - - CVuVector diff = p1 - p0; - float t = dist0/(dot1 - dot0); - CVuVector p = p0 + diff*t; - p.w = 0.0f; - vf01 = p; - vf03.x = t; - - // Check if point is inside - CVector cross1 = CrossProduct(p-v0, v1-v0); - CVector cross2 = CrossProduct(p-v1, v2-v1); - CVector cross3 = CrossProduct(p-v2, v0-v2); - // Only check relevant directions - int flagmask = 0; - if(Abs(plane.x) > 0.5f) flagmask |= 1; - if(Abs(plane.y) > 0.5f) flagmask |= 2; - if(Abs(plane.z) > 0.5f) flagmask |= 4; - int flags1 = SignFlags(cross1) & flagmask; - int flags2 = SignFlags(cross2) & flagmask; - int flags3 = SignFlags(cross3) & flagmask; - // inside if on the same side of all edges - if(flags1 != flags2 || flags1 != flags3){ - vi01 = 0; - return; - } - vi01 = 1; - vf02 = plane; - return; -#endif -} - -extern "C" void -LineToTriangleCollisionCompressed(const CVuVector &p0, const CVuVector &p1, VuTriangle &tri) -{ -#ifdef GTA_PS2 - __asm__ volatile ( - ".set noreorder\n" - "lqc2 vf12, 0x0(%0)\n" - "lqc2 vf13, 0x0(%1)\n" - "lqc2 vf14, 0x0(%2)\n" - "lqc2 vf15, 0x10(%2)\n" - "lqc2 vf16, 0x20(%2)\n" - "lqc2 vf17, 0x30(%2)\n" - "vcallms Vu0LineToTriangleCollisionCompressedStart\n" - ".set reorder\n" - : - : "r" (&p0), "r" (&p1), "r" (&tri) - ); -#else - CVuVector v0, v1, v2, plane; - v0.x = tri.v0[0]/128.0f; - v0.y = tri.v0[1]/128.0f; - v0.z = tri.v0[2]/128.0f; - v0.w = tri.v0[3]/128.0f; - v1.x = tri.v1[0]/128.0f; - v1.y = tri.v1[1]/128.0f; - v1.z = tri.v1[2]/128.0f; - v1.w = tri.v1[3]/128.0f; - v2.x = tri.v2[0]/128.0f; - v2.y = tri.v2[1]/128.0f; - v2.z = tri.v2[2]/128.0f; - v2.w = tri.v2[3]/128.0f; - plane.x = tri.plane[0]/4096.0f; - plane.y = tri.plane[1]/4096.0f; - plane.z = tri.plane[2]/4096.0f; - plane.w = tri.plane[3]/128.0f; - LineToTriangleCollision(p0, p1, v0, v1, v2, plane); -#endif -} - -extern "C" void -SphereToTriangleCollision(const CVuVector &sph, - const CVuVector &v0, const CVuVector &v1, const CVuVector &v2, - const CVuVector &plane) -{ -#ifdef GTA_PS2 - __asm__ volatile ( - ".set noreorder\n" - "lqc2 vf12, 0x0(%0)\n" - "lqc2 vf14, 0x0(%1)\n" - "lqc2 vf15, 0x0(%2)\n" - "lqc2 vf16, 0x0(%3)\n" - "lqc2 vf17, 0x0(%4)\n" - "vcallms Vu0SphereToTriangleCollisionStart\n" - ".set reorder\n" - : - : "r" (&sph), "r" (&v0), "r" (&v1), "r" (&v2), "r" (&plane) - ); -#else - float planedist = DotProduct(plane, sph) - plane.w; // VF02 - if(Abs(planedist) > sph.w){ - vi01 = 0; - return; - } - // point on plane - CVuVector p = sph - planedist*plane; - p.w = 0.0f; - vf01 = p; - planedist = Abs(planedist); - // edges - CVuVector v01 = v1 - v0; - CVuVector v12 = v2 - v1; - CVuVector v20 = v0 - v2; - // VU code calculates normal again for some weird reason... - // Check sides of point - CVector cross1 = CrossProduct(p-v0, v01); - CVector cross2 = CrossProduct(p-v1, v12); - CVector cross3 = CrossProduct(p-v2, v20); - // Only check relevant directions - int flagmask = 0; - if(Abs(plane.x) > 0.1f) flagmask |= 1; - if(Abs(plane.y) > 0.1f) flagmask |= 2; - if(Abs(plane.z) > 0.1f) flagmask |= 4; - int nflags = SignFlags(plane) & flagmask; - int flags1 = SignFlags(cross1) & flagmask; - int flags2 = SignFlags(cross2) & flagmask; - int flags3 = SignFlags(cross3) & flagmask; - int testcase = 0; - CVuVector closest(0.0f, 0.0f, 0.0f); // VF04 - if(flags1 == nflags){ - closest += v2; - testcase++; - } - if(flags2 == nflags){ - closest += v0; - testcase++; - } - if(flags3 == nflags){ - closest += v1; - testcase++; - } - if(testcase == 3){ - // inside triangle - dist to plane already checked - vf02 = plane; - vf02.w = vf03.x = planedist; - vi01 = 1; - }else if(testcase == 1){ - // outside two sides - closest to point opposide inside edge - vf01 = closest; - vf02 = sph - closest; - float distSq = vf02.MagnitudeSqr(); - vi01 = sph.w*sph.w > distSq; - vf03.x = Sqrt(distSq); - vf02 *= 1.0f/vf03.x; - }else{ - // inside two sides - closest to third edge - if(flags1 != nflags) - closest = DistanceBetweenSphereAndLine(sph, v0, v01); - else if(flags2 != nflags) - closest = DistanceBetweenSphereAndLine(sph, v1, v12); - else - closest = DistanceBetweenSphereAndLine(sph, v2, v20); - vi01 = sph.w*sph.w > closest.w; - vf01 = closest; - vf02 = sph - closest; - vf03.x = Sqrt(closest.w); - vf02 *= 1.0f/vf03.x; - } -#endif -} - -extern "C" void -SphereToTriangleCollisionCompressed(const CVuVector &sph, VuTriangle &tri) -{ -#ifdef GTA_PS2 - __asm__ volatile ( - ".set noreorder\n" - "lqc2 vf12, 0x0(%0)\n" - "lqc2 vf14, 0x0(%1)\n" - "lqc2 vf15, 0x10(%1)\n" - "lqc2 vf16, 0x20(%1)\n" - "lqc2 vf17, 0x30(%1)\n" - "vcallms Vu0SphereToTriangleCollisionCompressedStart\n" - ".set reorder\n" - : - : "r" (&sph), "r" (&tri) - ); -#else - CVuVector v0, v1, v2, plane; - v0.x = tri.v0[0]/128.0f; - v0.y = tri.v0[1]/128.0f; - v0.z = tri.v0[2]/128.0f; - v0.w = tri.v0[3]/128.0f; - v1.x = tri.v1[0]/128.0f; - v1.y = tri.v1[1]/128.0f; - v1.z = tri.v1[2]/128.0f; - v1.w = tri.v1[3]/128.0f; - v2.x = tri.v2[0]/128.0f; - v2.y = tri.v2[1]/128.0f; - v2.z = tri.v2[2]/128.0f; - v2.w = tri.v2[3]/128.0f; - plane.x = tri.plane[0]/4096.0f; - plane.y = tri.plane[1]/4096.0f; - plane.z = tri.plane[2]/4096.0f; - plane.w = tri.plane[3]/128.0f; - SphereToTriangleCollision(sph, v0, v1, v2, plane); -#endif -} - -inline int -GetVUresult(void) -{ -#ifdef GTA_PS2 - int ret; - __asm__ volatile ( - "cfc2.i %0,vi01\n" // .i important! wait for VU0 to finish - : "=r" (ret) - ); - return ret; -#else - return vi01; -#endif -} - -inline int -GetVUresult(CVuVector &point, CVuVector &normal, float &dist) -{ -#ifdef GTA_PS2 - int ret; - __asm__ volatile ( - "cfc2.i %0,vi01\n" // .i important! wait for VU0 to finish - "sqc2 vf01,(%1)\n" - "sqc2 vf02,(%2)\n" - "qmfc2 $12,vf03\n" - "sw $12,(%3)\n" - : "=r" (ret) - : "r" (&point), "r" (&normal), "r" (&dist) - : "$12" - ); - return ret; -#else - point = vf01; - normal = vf02; - dist = vf03.x; - return vi01; -#endif -} - -#endif - - -enum Direction -{ - DIR_X_POS, - DIR_X_NEG, - DIR_Y_POS, - DIR_Y_NEG, - DIR_Z_POS, - DIR_Z_NEG, -}; - -eLevelName CCollision::ms_collisionInMemory; -CLinkList CCollision::ms_colModelCache; - -void -CCollision::Init(void) -{ - ms_colModelCache.Init(NUMCOLCACHELINKS); - ms_collisionInMemory = LEVEL_GENERIC; -} - -void -CCollision::Shutdown(void) -{ - ms_colModelCache.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); -} - -eLevelName -GetCollisionInSectorList(CPtrList &list) -{ - CPtrNode *node; - CEntity *e; - int level; - - for(node = list.first; node; node = node->next){ - e = (CEntity*)node->item; - level = CModelInfo::GetModelInfo(e->GetModelIndex())->GetColModel()->level; - if(level != LEVEL_GENERIC) - return (eLevelName)level; - } - return LEVEL_GENERIC; -} - -// Get a level this sector is in based on collision models -eLevelName -GetCollisionInSector(CSector §) -{ - int level; - - level = GetCollisionInSectorList(sect.m_lists[ENTITYLIST_BUILDINGS]); - if(level == LEVEL_GENERIC) - level = GetCollisionInSectorList(sect.m_lists[ENTITYLIST_BUILDINGS_OVERLAP]); - if(level == LEVEL_GENERIC) - level = GetCollisionInSectorList(sect.m_lists[ENTITYLIST_OBJECTS]); - if(level == LEVEL_GENERIC) - level = GetCollisionInSectorList(sect.m_lists[ENTITYLIST_OBJECTS_OVERLAP]); - if(level == LEVEL_GENERIC) - level = GetCollisionInSectorList(sect.m_lists[ENTITYLIST_DUMMIES]); - if(level == LEVEL_GENERIC) - level = GetCollisionInSectorList(sect.m_lists[ENTITYLIST_DUMMIES_OVERLAP]); - return (eLevelName)level; -} - -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) { -#ifdef FIX_BUGS - CTimer::Suspend(); -#else - CTimer::Stop(); -#endif - ISLAND_LOADING_IS(LOW) - { - DMAudio.SetEffectsFadeVol(0); - CPad::StopPadsShaking(); - LoadCollisionScreen(CGame::currLevel); - DMAudio.Service(); - } - - CPopulation::DealWithZoneChange(ms_collisionInMemory, CGame::currLevel, false); - - ISLAND_LOADING_ISNT(HIGH) - { - CStreaming::RemoveIslandsNotUsed(LEVEL_INDUSTRIAL); - CStreaming::RemoveIslandsNotUsed(LEVEL_COMMERCIAL); - CStreaming::RemoveIslandsNotUsed(LEVEL_SUBURBAN); - } - ISLAND_LOADING_IS(LOW) - { - 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); - } - - ms_collisionInMemory = CGame::currLevel; - CReplay::EmptyReplayBuffer(); - ISLAND_LOADING_IS(LOW) - { - if (CGame::currLevel != LEVEL_GENERIC) - LoadSplash(GetLevelSplashScreen(CGame::currLevel)); - CStreaming::RemoveUnusedBigBuildings(CGame::currLevel); - CStreaming::RemoveUnusedBuildings(CGame::currLevel); - CStreaming::RequestBigBuildings(CGame::currLevel); - } -#ifdef NO_ISLAND_LOADING - else if (CMenuManager::m_PrefsIslandLoading == CMenuManager::ISLAND_LOADING_MEDIUM) - CStreaming::RequestIslands(CGame::currLevel); -#endif - CStreaming::LoadAllRequestedModels(true); - - ISLAND_LOADING_IS(LOW) - { - CStreaming::HaveAllBigBuildingsLoaded(CGame::currLevel); - - CGame::TidyUpMemory(true, true); - } -#ifdef FIX_BUGS - CTimer::Resume(); -#else - CTimer::Update(); -#endif - ISLAND_LOADING_IS(LOW) - DMAudio.SetEffectsFadeVol(127); - } -} - -#ifdef NO_ISLAND_LOADING -bool CCollision::bAlreadyLoaded = false; -#endif -void -CCollision::SortOutCollisionAfterLoad(void) -{ - if(ms_collisionInMemory == CGame::currLevel) - return; - ISLAND_LOADING_IS(LOW) - CModelInfo::RemoveColModelsFromOtherLevels(CGame::currLevel); - - if (CGame::currLevel != LEVEL_GENERIC) { -#ifdef NO_ISLAND_LOADING - if (CMenuManager::m_PrefsIslandLoading != CMenuManager::ISLAND_LOADING_LOW) { - if (bAlreadyLoaded) { - ms_collisionInMemory = CGame::currLevel; - return; - } - bAlreadyLoaded = true; - CFileLoader::LoadCollisionFromDatFile(LEVEL_INDUSTRIAL); - CFileLoader::LoadCollisionFromDatFile(LEVEL_COMMERCIAL); - CFileLoader::LoadCollisionFromDatFile(LEVEL_SUBURBAN); - } else -#endif - CFileLoader::LoadCollisionFromDatFile(CGame::currLevel); - if(!CGame::playingIntro) - LoadSplash(GetLevelSplashScreen(CGame::currLevel)); - } - ms_collisionInMemory = CGame::currLevel; - CGame::TidyUpMemory(true, false); -} - -void -CCollision::LoadCollisionScreen(eLevelName level) -{ - static Const char *levelNames[4] = { - "", - "IND_ZON", - "COM_ZON", - "SUB_ZON" - }; - - // Why twice? - LoadingIslandScreen(levelNames[level]); - LoadingIslandScreen(levelNames[level]); -} - -// -// Test -// - - -bool -CCollision::TestSphereSphere(const CColSphere &s1, const CColSphere &s2) -{ - float d = s1.radius + s2.radius; - return (s1.center - s2.center).MagnitudeSqr() < d*d; -} - -bool -CCollision::TestSphereBox(const CColSphere &sph, const CColBox &box) -{ - if(sph.center.x + sph.radius < box.min.x) return false; - if(sph.center.x - sph.radius > box.max.x) return false; - if(sph.center.y + sph.radius < box.min.y) return false; - if(sph.center.y - sph.radius > box.max.y) return false; - if(sph.center.z + sph.radius < box.min.z) return false; - if(sph.center.z - sph.radius > box.max.z) return false; - return true; -} - -bool -CCollision::TestLineBox(const CColLine &line, const CColBox &box) -{ - float t, x, y, z; - // If either line point is in the box, we have a collision - if(line.p0.x > box.min.x && line.p0.x < box.max.x && - line.p0.y > box.min.y && line.p0.y < box.max.y && - line.p0.z > box.min.z && line.p0.z < box.max.z) - return true; - if(line.p1.x > box.min.x && line.p1.x < box.max.x && - line.p1.y > box.min.y && line.p1.y < box.max.y && - line.p1.z > box.min.z && line.p1.z < box.max.z) - return true; - - // check if points are on opposite sides of min x plane - if((box.min.x - line.p1.x) * (box.min.x - line.p0.x) < 0.0f){ - // parameter along line where we intersect - t = (box.min.x - line.p0.x) / (line.p1.x - line.p0.x); - // y of intersection - y = line.p0.y + (line.p1.y - line.p0.y)*t; - if(y > box.min.y && y < box.max.y){ - // z of intersection - z = line.p0.z + (line.p1.z - line.p0.z)*t; - if(z > box.min.z && z < box.max.z) - return true; - } - } - - // same test with max x plane - if((line.p1.x - box.max.x) * (line.p0.x - box.max.x) < 0.0f){ - t = (line.p0.x - box.max.x) / (line.p0.x - line.p1.x); - y = line.p0.y + (line.p1.y - line.p0.y)*t; - if(y > box.min.y && y < box.max.y){ - z = line.p0.z + (line.p1.z - line.p0.z)*t; - if(z > box.min.z && z < box.max.z) - return true; - } - } - - // min y plne - if((box.min.y - line.p0.y) * (box.min.y - line.p1.y) < 0.0f){ - t = (box.min.y - line.p0.y) / (line.p1.y - line.p0.y); - x = line.p0.x + (line.p1.x - line.p0.x)*t; - if(x > box.min.x && x < box.max.x){ - z = line.p0.z + (line.p1.z - line.p0.z)*t; - if(z > box.min.z && z < box.max.z) - return true; - } - } - - // max y plane - if((line.p0.y - box.max.y) * (line.p1.y - box.max.y) < 0.0f){ - t = (line.p0.y - box.max.y) / (line.p0.y - line.p1.y); - x = line.p0.x + (line.p1.x - line.p0.x)*t; - if(x > box.min.x && x < box.max.x){ - z = line.p0.z + (line.p1.z - line.p0.z)*t; - if(z > box.min.z && z < box.max.z) - return true; - } - } - - // min z plne - if((box.min.z - line.p0.z) * (box.min.z - line.p1.z) < 0.0f){ - t = (box.min.z - line.p0.z) / (line.p1.z - line.p0.z); - x = line.p0.x + (line.p1.x - line.p0.x)*t; - if(x > box.min.x && x < box.max.x){ - y = line.p0.y + (line.p1.y - line.p0.y)*t; - if(y > box.min.y && y < box.max.y) - return true; - } - } - - // max z plane - if((line.p0.z - box.max.z) * (line.p1.z - box.max.z) < 0.0f){ - t = (line.p0.z - box.max.z) / (line.p0.z - line.p1.z); - x = line.p0.x + (line.p1.x - line.p0.x)*t; - if(x > box.min.x && x < box.max.x){ - y = line.p0.y + (line.p1.y - line.p0.y)*t; - if(y > box.min.y && y < box.max.y) - return true; - } - } - return false; -} - -bool -CCollision::TestVerticalLineBox(const CColLine &line, const CColBox &box) -{ - if(line.p0.x <= box.min.x) return false; - if(line.p0.y <= box.min.y) return false; - if(line.p0.x >= box.max.x) return false; - if(line.p0.y >= box.max.y) return false; - if(line.p0.z < line.p1.z){ - if(line.p0.z > box.max.z) return false; - if(line.p1.z < box.min.z) return false; - }else{ - if(line.p1.z > box.max.z) return false; - if(line.p0.z < box.min.z) return false; - } - return true; -} - -bool -CCollision::TestLineTriangle(const CColLine &line, const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane) -{ -#ifdef VU_COLLISION - // not used in favour of optimized loops - VuTriangle vutri; - verts[tri.a].Unpack(vutri.v0); - verts[tri.b].Unpack(vutri.v1); - verts[tri.c].Unpack(vutri.v2); - plane.Unpack(vutri.plane); - - LineToTriangleCollisionCompressed(*(CVuVector*)&line.p0, *(CVuVector*)&line.p1, vutri); - - if(GetVUresult()) - return true; - return false; -#else - float t; - CVector normal; - plane.GetNormal(normal); - - // if points are on the same side, no collision - if(plane.CalcPoint(line.p0) * plane.CalcPoint(line.p1) > 0.0f) - return false; - - // intersection parameter on line - t = -plane.CalcPoint(line.p0) / DotProduct(line.p1 - line.p0, normal); - // find point of intersection - CVector p = line.p0 + (line.p1-line.p0)*t; - - 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 - // can figure out how to project the vectors. - // normal = (c-a) x (b-a) - switch(plane.dir){ - case DIR_X_POS: - vec1.x = va.y; vec1.y = va.z; - vec2.x = vc.y; vec2.y = vc.z; - vec3.x = vb.y; vec3.y = vb.z; - vect.x = p.y; vect.y = p.z; - break; - case DIR_X_NEG: - vec1.x = va.y; vec1.y = va.z; - vec2.x = vb.y; vec2.y = vb.z; - vec3.x = vc.y; vec3.y = vc.z; - vect.x = p.y; vect.y = p.z; - break; - case DIR_Y_POS: - vec1.x = va.z; vec1.y = va.x; - vec2.x = vc.z; vec2.y = vc.x; - vec3.x = vb.z; vec3.y = vb.x; - vect.x = p.z; vect.y = p.x; - break; - case DIR_Y_NEG: - vec1.x = va.z; vec1.y = va.x; - vec2.x = vb.z; vec2.y = vb.x; - vec3.x = vc.z; vec3.y = vc.x; - vect.x = p.z; vect.y = p.x; - break; - case DIR_Z_POS: - vec1.x = va.x; vec1.y = va.y; - vec2.x = vc.x; vec2.y = vc.y; - vec3.x = vb.x; vec3.y = vb.y; - vect.x = p.x; vect.y = p.y; - break; - case DIR_Z_NEG: - vec1.x = va.x; vec1.y = va.y; - vec2.x = vb.x; vec2.y = vb.y; - vec3.x = vc.x; vec3.y = vc.y; - vect.x = p.x; vect.y = p.y; - break; - default: - assert(0); - } - // This is our triangle: - // 3-------2 - // \ P / - // \ / - // \ / - // 1 - // We can use the "2d cross product" to check on which side - // a vector is of another. Test is true if point is inside of all edges. - 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; - return true; -#endif -} - -// Test if line segment intersects with sphere. -// If the first point is inside the sphere this test does not register a collision! -// The code is reversed from the original code and rather ugly, see Process for a clear version. -// TODO: actually rewrite this mess -bool -CCollision::TestLineSphere(const CColLine &line, const CColSphere &sph) -{ - CVector v01 = line.p1 - line.p0; // vector from p0 to p1 - CVector v0c = sph.center - line.p0; // vector from p0 to center - float linesq = v01.MagnitudeSqr(); - // I leave in the strange -2 factors even though they serve no real purpose - float projline = -2.0f * DotProduct(v01, v0c); // project v0c onto line - // Square of tangent from p0 multiplied by line length so we can compare with projline. - // The length of the tangent would be this: Sqrt((c-p0)^2 - r^2). - // Negative if p0 is inside the sphere! This breaks the test! - float tansq = 4.0f * linesq * - (sph.center.MagnitudeSqr() - 2.0f*DotProduct(sph.center, line.p0) + line.p0.MagnitudeSqr() - sph.radius*sph.radius); - float diffsq = projline*projline - tansq; - // if diffsq < 0 that means the line is a passant, so no intersection - if(diffsq < 0.0f) - return false; - // projline (negative in GTA for some reason) is the point on the line - // in the middle of the two intersection points (startin from p0). - // Sqrt(diffsq) somehow works out to be the distance from that - // midpoint to the intersection points. - // So subtract that and get rid of the awkward scaling: - float f = (-projline - Sqrt(diffsq)) / (2.0f*linesq); - // f should now be in range [0, 1] for [p0, p1] - return f >= 0.0f && f <= 1.0f; -} - -bool -CCollision::TestSphereTriangle(const CColSphere &sphere, - const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane) -{ -#ifdef VU_COLLISION - // not used in favour of optimized loops - VuTriangle vutri; - verts[tri.a].Unpack(vutri.v0); - verts[tri.b].Unpack(vutri.v1); - verts[tri.c].Unpack(vutri.v2); - plane.Unpack(vutri.plane); - - SphereToTriangleCollisionCompressed(*(CVuVector*)&sphere, vutri); - - if(GetVUresult()) - return true; - return false; -#else - // If sphere and plane don't intersect, no collision - float planedist = plane.CalcPoint(sphere.center); - if(Abs(planedist) > sphere.radius) - return false; - - 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; - float len = vec2.Magnitude(); - vec2 = vec2 * (1.0f/len); - CVector normal; - plane.GetNormal(normal); - CVector vec1 = CrossProduct(vec2, normal); - - // We know A has local coordinate [0,0] and B has [0,len]. - // Now calculate coordinates on triangle for these two vectors: - CVector vac = vc - va; - CVector vas = sphere.center - va; - CVector2D b(0.0f, len); - CVector2D c(DotProduct(vec1, vac), DotProduct(vec2, vac)); - CVector2D s(DotProduct(vec1, vas), DotProduct(vec2, vas)); - - // The three triangle lines partition the space into 6 sectors, - // find out in which the center lies. - int insideAB = CrossProduct2D(s, b) >= 0.0f; - int insideAC = CrossProduct2D(c, s) >= 0.0f; - int insideBC = CrossProduct2D(s-b, c-b) >= 0.0f; - - int testcase = insideAB + insideAC + insideBC; - float dist = 0.0f; - 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); - 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); - break; - case 3: - // center is in triangle - dist = Abs(planedist); - break; - default: - assert(0); - } - - return dist < sphere.radius; -#endif -} - -bool -CCollision::TestLineOfSight(const CColLine &line, const CMatrix &matrix, CColModel &model, bool ignoreSeeThrough) -{ -#ifdef VU_COLLISION - CMatrix matTransform; - int i; - - // transform line to model space - Invert(matrix, matTransform); - CVuVector newline[2]; - TransformPoints(newline, 2, matTransform, (RwV3d*)&line.p0, sizeof(CColLine)/2); - - // If we don't intersect with the bounding box, no chance on the rest - if(!TestLineBox(*(CColLine*)newline, model.boundingBox)) - return false; - - for(i = 0; i < model.numSpheres; i++){ - if(ignoreSeeThrough && IsSeeThrough(model.spheres[i].surface)) continue; - if(TestLineSphere(*(CColLine*)newline, model.spheres[i])) - return true; - } - - for(i = 0; i < model.numBoxes; i++){ - if(ignoreSeeThrough && IsSeeThrough(model.boxes[i].surface)) continue; - if(TestLineBox(*(CColLine*)newline, model.boxes[i])) - return true; - } - - CalculateTrianglePlanes(&model); - int lastTest = -1; - VuTriangle vutri; - for(i = 0; i < model.numTriangles; i++){ - if(ignoreSeeThrough && IsSeeThrough(model.triangles[i].surface)) continue; - - CColTriangle *tri = &model.triangles[i]; - model.vertices[tri->a].Unpack(vutri.v0); - model.vertices[tri->b].Unpack(vutri.v1); - model.vertices[tri->c].Unpack(vutri.v2); - model.trianglePlanes[i].Unpack(vutri.plane); - - LineToTriangleCollisionCompressed(newline[0], newline[1], vutri); - lastTest = i; - break; - } -#ifdef FIX_BUGS - // no need to check first again - i++; -#endif - for(; i < model.numTriangles; i++){ - if(ignoreSeeThrough && IsSeeThrough(model.triangles[i].surface)) continue; - - CColTriangle *tri = &model.triangles[i]; - model.vertices[tri->a].Unpack(vutri.v0); - model.vertices[tri->b].Unpack(vutri.v1); - model.vertices[tri->c].Unpack(vutri.v2); - model.trianglePlanes[i].Unpack(vutri.plane); - - if(GetVUresult()) - return true; - - LineToTriangleCollisionCompressed(newline[0], newline[1], vutri); - lastTest = i; - - } - if(lastTest != -1 && GetVUresult()) - return true; - - return false; -#else - static CMatrix matTransform; - int i; - - // transform line to model space - Invert(matrix, matTransform); - CColLine newline(matTransform * line.p0, matTransform * line.p1); - - // If we don't intersect with the bounding box, no chance on the rest - if(!TestLineBox(newline, model.boundingBox)) - return false; - - 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 && 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 && IsSeeThrough(model.triangles[i].surface)) continue; - if(TestLineTriangle(newline, model.vertices, model.triangles[i], model.trianglePlanes[i])) - return true; - } - - return false; -#endif -} - - -// -// Process -// - -// For Spheres mindist is the squared distance to its center -// For Lines mindist is between [0,1] - -bool -CCollision::ProcessSphereSphere(const CColSphere &s1, const CColSphere &s2, CColPoint &point, float &mindistsq) -{ - CVector dist = s1.center - s2.center; - float d = dist.Magnitude() - s2.radius; // distance from s1's center to s2 - float depth = s1.radius - d; // sphere overlap - if(d < 0.0f) d = 0.0f; // clamp to zero, i.e. if s1's center is inside s2 - // no collision if sphere is not close enough - if(d*d < mindistsq && d < s1.radius){ - dist.Normalise(); - point.point = s1.center - dist*d; - point.normal = dist; -#ifndef VU_COLLISION - point.surfaceA = s1.surface; - point.pieceA = s1.piece; - point.surfaceB = s2.surface; - point.pieceB = s2.piece; -#endif - point.depth = depth; - mindistsq = d*d; // collision radius - return true; - } - return false; -} - -bool -CCollision::ProcessSphereBox(const CColSphere &sph, const CColBox &box, CColPoint &point, float &mindistsq) -{ - CVector p; - CVector dist; - - // GTA's code is too complicated, uses a huge 3x3x3 if statement - // we can simplify the structure a lot - - // first make sure we have a collision at all - if(sph.center.x + sph.radius < box.min.x) return false; - if(sph.center.x - sph.radius > box.max.x) return false; - if(sph.center.y + sph.radius < box.min.y) return false; - if(sph.center.y - sph.radius > box.max.y) return false; - if(sph.center.z + sph.radius < box.min.z) return false; - if(sph.center.z - sph.radius > box.max.z) return false; - - // Now find out where the sphere center lies in relation to all the sides - int xpos = sph.center.x < box.min.x ? 1 : - sph.center.x > box.max.x ? 2 : - 0; - int ypos = sph.center.y < box.min.y ? 1 : - sph.center.y > box.max.y ? 2 : - 0; - int zpos = sph.center.z < box.min.z ? 1 : - sph.center.z > box.max.z ? 2 : - 0; - - if(xpos == 0 && ypos == 0 && zpos == 0){ - // sphere is inside the box - p = (box.min + box.max)*0.5f; - - dist = sph.center - p; - float lensq = dist.MagnitudeSqr(); - if(lensq < mindistsq){ - point.normal = dist * (1.0f/Sqrt(lensq)); - point.point = sph.center - point.normal; -#ifndef VU_COLLISION - point.surfaceA = sph.surface; - point.pieceA = sph.piece; - point.surfaceB = box.surface; - point.pieceB = box.piece; -#endif - - // find absolute distance to the closer side in each dimension - float dx = dist.x > 0.0f ? - box.max.x - sph.center.x : - sph.center.x - box.min.x; - float dy = dist.y > 0.0f ? - box.max.y - sph.center.y : - sph.center.y - box.min.y; - float dz = dist.z > 0.0f ? - box.max.z - sph.center.z : - sph.center.z - box.min.z; - // collision depth is maximum of that: - if(dx > dy && dx > dz) - point.depth = dx; - else if(dy > dz) - point.depth = dy; - else - point.depth = dz; - return true; - } - }else{ - // sphere is outside. - // closest point on box: - p.x = xpos == 1 ? box.min.x : - xpos == 2 ? box.max.x : - sph.center.x; - p.y = ypos == 1 ? box.min.y : - ypos == 2 ? box.max.y : - sph.center.y; - p.z = zpos == 1 ? box.min.z : - zpos == 2 ? box.max.z : - sph.center.z; - - dist = sph.center - p; - float lensq = dist.MagnitudeSqr(); - if(lensq < mindistsq){ - float len = Sqrt(lensq); - point.point = p; - point.normal = dist * (1.0f/len); -#ifndef VU_COLLISION - point.surfaceA = sph.surface; - point.pieceA = sph.piece; - point.surfaceB = box.surface; - point.pieceB = box.piece; -#endif - point.depth = sph.radius - len; - mindistsq = lensq; - return true; - } - } - return false; -} - -bool -CCollision::ProcessLineBox(const CColLine &line, const CColBox &box, CColPoint &point, float &mindist) -{ - float mint, t, x, y, z; - CVector normal; - CVector p; - - mint = 1.0f; - // check if points are on opposite sides of min x plane - if((box.min.x - line.p1.x) * (box.min.x - line.p0.x) < 0.0f){ - // parameter along line where we intersect - t = (box.min.x - line.p0.x) / (line.p1.x - line.p0.x); - // y of intersection - y = line.p0.y + (line.p1.y - line.p0.y)*t; - if(y > box.min.y && y < box.max.y){ - // z of intersection - z = line.p0.z + (line.p1.z - line.p0.z)*t; - if(z > box.min.z && z < box.max.z) - if(t < mint){ - mint = t; - p = CVector(box.min.x, y, z); - normal = CVector(-1.0f, 0.0f, 0.0f); - } - } - } - - // max x plane - if((line.p1.x - box.max.x) * (line.p0.x - box.max.x) < 0.0f){ - t = (line.p0.x - box.max.x) / (line.p0.x - line.p1.x); - y = line.p0.y + (line.p1.y - line.p0.y)*t; - if(y > box.min.y && y < box.max.y){ - z = line.p0.z + (line.p1.z - line.p0.z)*t; - if(z > box.min.z && z < box.max.z) - if(t < mint){ - mint = t; - p = CVector(box.max.x, y, z); - normal = CVector(1.0f, 0.0f, 0.0f); - } - } - } - - // min y plne - if((box.min.y - line.p0.y) * (box.min.y - line.p1.y) < 0.0f){ - t = (box.min.y - line.p0.y) / (line.p1.y - line.p0.y); - x = line.p0.x + (line.p1.x - line.p0.x)*t; - if(x > box.min.x && x < box.max.x){ - z = line.p0.z + (line.p1.z - line.p0.z)*t; - if(z > box.min.z && z < box.max.z) - if(t < mint){ - mint = t; - p = CVector(x, box.min.y, z); - normal = CVector(0.0f, -1.0f, 0.0f); - } - } - } - - // max y plane - if((line.p0.y - box.max.y) * (line.p1.y - box.max.y) < 0.0f){ - t = (line.p0.y - box.max.y) / (line.p0.y - line.p1.y); - x = line.p0.x + (line.p1.x - line.p0.x)*t; - if(x > box.min.x && x < box.max.x){ - z = line.p0.z + (line.p1.z - line.p0.z)*t; - if(z > box.min.z && z < box.max.z) - if(t < mint){ - mint = t; - p = CVector(x, box.max.y, z); - normal = CVector(0.0f, 1.0f, 0.0f); - } - } - } - - // min z plne - if((box.min.z - line.p0.z) * (box.min.z - line.p1.z) < 0.0f){ - t = (box.min.z - line.p0.z) / (line.p1.z - line.p0.z); - x = line.p0.x + (line.p1.x - line.p0.x)*t; - if(x > box.min.x && x < box.max.x){ - y = line.p0.y + (line.p1.y - line.p0.y)*t; - if(y > box.min.y && y < box.max.y) - if(t < mint){ - mint = t; - p = CVector(x, y, box.min.z); - normal = CVector(0.0f, 0.0f, -1.0f); - } - } - } - - // max z plane - if((line.p0.z - box.max.z) * (line.p1.z - box.max.z) < 0.0f){ - t = (line.p0.z - box.max.z) / (line.p0.z - line.p1.z); - x = line.p0.x + (line.p1.x - line.p0.x)*t; - if(x > box.min.x && x < box.max.x){ - y = line.p0.y + (line.p1.y - line.p0.y)*t; - if(y > box.min.y && y < box.max.y) - if(t < mint){ - mint = t; - p = CVector(x, y, box.max.z); - normal = CVector(0.0f, 0.0f, 1.0f); - } - } - } - - if(mint >= mindist) - return false; - - point.point = p; - point.normal = normal; -#ifndef VU_COLLISION - point.surfaceA = 0; - point.pieceA = 0; - point.surfaceB = box.surface; - point.pieceB = box.piece; -#endif - mindist = mint; - - return true; -} - -// If line.p0 lies inside sphere, no collision is registered. -bool -CCollision::ProcessLineSphere(const CColLine &line, const CColSphere &sphere, CColPoint &point, float &mindist) -{ - CVector v01 = line.p1 - line.p0; - CVector v0c = sphere.center - line.p0; - float linesq = v01.MagnitudeSqr(); - // project v0c onto v01, scaled by |v01| this is the midpoint of the two intersections - float projline = DotProduct(v01, v0c); - // tangent of p0 to sphere, scaled by linesq just like projline^2 - float tansq = (v0c.MagnitudeSqr() - sphere.radius*sphere.radius) * linesq; - // this works out to be the square of the distance between the midpoint and the intersections - float diffsq = projline*projline - tansq; - // no intersection - if(diffsq < 0.0f) - return false; - // point of first intersection, in range [0,1] between p0 and p1 - float t = (projline - Sqrt(diffsq)) / linesq; - // if not on line or beyond mindist, no intersection - if(t < 0.0f || t > 1.0f || t >= mindist) - return false; - point.point = line.p0 + v01*t; - point.normal = point.point - sphere.center; - point.normal.Normalise(); -#ifndef VU_COLLISION - point.surfaceA = 0; - point.pieceA = 0; - point.surfaceB = sphere.surface; - point.pieceB = sphere.piece; -#endif - mindist = t; - return true; -} - -bool -CCollision::ProcessVerticalLineTriangle(const CColLine &line, - const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, - CColPoint &point, float &mindist, CStoredCollPoly *poly) -{ -#ifdef VU_COLLISION - // not used in favour of optimized loops - bool res = ProcessLineTriangle(line, verts, tri, plane, point, mindist); - if(res && poly){ - poly->verts[0] = verts[tri.a].Get(); - poly->verts[1] = verts[tri.b].Get(); - poly->verts[2] = verts[tri.c].Get(); - poly->valid = true; - } - return res; -#else - float t; - CVector normal; - - const CVector &p0 = line.p0; - 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; - if(p0.x > va.x && p0.x > vb.x && p0.x > vc.x) return false; - if(p0.y < va.y && p0.y < vb.y && p0.y < vc.y) return false; - if(p0.y > va.y && p0.y > vb.y && p0.y > vc.y) return false; - - plane.GetNormal(normal); - // if points are on the same side, no collision - if(plane.CalcPoint(p0) * plane.CalcPoint(line.p1) > 0.0f) - return false; - - // intersection parameter on line - float h = (line.p1 - p0).z; - t = -plane.CalcPoint(p0) / (h * normal.z); - // early out if we're beyond the mindist - if(t >= mindist) - return false; - CVector p(p0.x, p0.y, p0.z + h*t); - - CVector2D vec1, vec2, vec3, vect; - switch(plane.dir){ - case DIR_X_POS: - vec1.x = va.y; vec1.y = va.z; - vec2.x = vc.y; vec2.y = vc.z; - vec3.x = vb.y; vec3.y = vb.z; - vect.x = p.y; vect.y = p.z; - break; - case DIR_X_NEG: - vec1.x = va.y; vec1.y = va.z; - vec2.x = vb.y; vec2.y = vb.z; - vec3.x = vc.y; vec3.y = vc.z; - vect.x = p.y; vect.y = p.z; - break; - case DIR_Y_POS: - vec1.x = va.z; vec1.y = va.x; - vec2.x = vc.z; vec2.y = vc.x; - vec3.x = vb.z; vec3.y = vb.x; - vect.x = p.z; vect.y = p.x; - break; - case DIR_Y_NEG: - vec1.x = va.z; vec1.y = va.x; - vec2.x = vb.z; vec2.y = vb.x; - vec3.x = vc.z; vec3.y = vc.x; - vect.x = p.z; vect.y = p.x; - break; - case DIR_Z_POS: - vec1.x = va.x; vec1.y = va.y; - vec2.x = vc.x; vec2.y = vc.y; - vec3.x = vb.x; vec3.y = vb.y; - vect.x = p.x; vect.y = p.y; - break; - case DIR_Z_NEG: - vec1.x = va.x; vec1.y = va.y; - vec2.x = vb.x; vec2.y = vb.y; - vec3.x = vc.x; vec3.y = vc.y; - vect.x = p.x; vect.y = p.y; - break; - default: - assert(0); - } - 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; - 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; -#endif -} - -bool -CCollision::IsStoredPolyStillValidVerticalLine(const CVector &pos, float z, CColPoint &point, CStoredCollPoly *poly) -{ -#ifdef VU_COLLISION - if(!poly->valid) - return false; - - CVuVector p0 = pos; - CVuVector p1 = pos; - p1.z = z; - - CVector v01 = poly->verts[1] - poly->verts[0]; - CVector v02 = poly->verts[2] - poly->verts[0]; - CVuVector plane = CrossProduct(v02, v01); - plane.Normalise(); - plane.w = DotProduct(plane, poly->verts[0]); - - LineToTriangleCollision(p0, p1, poly->verts[0], poly->verts[1], poly->verts[2], plane); - - CVuVector pnt; - float dist; - if(!GetVUresult(pnt, plane, dist)) -#ifdef FIX_BUGS - // perhaps not needed but be safe - return poly->valid = false; -#else - return false; -#endif - point.point = pnt; - return true; -#else - float t; - - if(!poly->valid) - return false; - - // maybe inlined? - CColTrianglePlane plane; - plane.Set(poly->verts[0], poly->verts[1], poly->verts[2]); - - 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); - - // The rest is pretty much CCollision::ProcessLineTriangle - - // if points are on the same side, no collision - if(plane.CalcPoint(p0) * plane.CalcPoint(p1) > 0.0f) - return poly->valid = false; - - // intersection parameter on line - CVector normal; - plane.GetNormal(normal); - t = -plane.CalcPoint(p0) / DotProduct(p1 - p0, normal); - // find point of intersection - CVector p = p0 + (p1-p0)*t; - - CVector2D vec1, vec2, vec3, vect; - switch(plane.dir){ - case DIR_X_POS: - vec1.x = va.y; vec1.y = va.z; - vec2.x = vc.y; vec2.y = vc.z; - vec3.x = vb.y; vec3.y = vb.z; - vect.x = p.y; vect.y = p.z; - break; - case DIR_X_NEG: - vec1.x = va.y; vec1.y = va.z; - vec2.x = vb.y; vec2.y = vb.z; - vec3.x = vc.y; vec3.y = vc.z; - vect.x = p.y; vect.y = p.z; - break; - case DIR_Y_POS: - vec1.x = va.z; vec1.y = va.x; - vec2.x = vc.z; vec2.y = vc.x; - vec3.x = vb.z; vec3.y = vb.x; - vect.x = p.z; vect.y = p.x; - break; - case DIR_Y_NEG: - vec1.x = va.z; vec1.y = va.x; - vec2.x = vb.z; vec2.y = vb.x; - vec3.x = vc.z; vec3.y = vc.x; - vect.x = p.z; vect.y = p.x; - break; - case DIR_Z_POS: - vec1.x = va.x; vec1.y = va.y; - vec2.x = vc.x; vec2.y = vc.y; - vec3.x = vb.x; vec3.y = vb.y; - vect.x = p.x; vect.y = p.y; - break; - case DIR_Z_NEG: - vec1.x = va.x; vec1.y = va.y; - vec2.x = vb.x; vec2.y = vb.y; - vec3.x = vc.x; vec3.y = vc.y; - vect.x = p.x; vect.y = p.y; - break; - default: - assert(0); - } - if(CrossProduct2D(vec2-vec1, vect-vec1) < 0.0f) return poly->valid = false; - if(CrossProduct2D(vec3-vec1, vect-vec1) > 0.0f) return poly->valid = false; - if(CrossProduct2D(vec3-vec2, vect-vec2) < 0.0f) return poly->valid = false; - point.point = p; - return poly->valid = true; -#endif -} - -bool -CCollision::ProcessLineTriangle(const CColLine &line, - const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, - CColPoint &point, float &mindist) -{ -#ifdef VU_COLLISION - // not used in favour of optimized loops - VuTriangle vutri; - verts[tri.a].Unpack(vutri.v0); - verts[tri.b].Unpack(vutri.v1); - verts[tri.c].Unpack(vutri.v2); - plane.Unpack(vutri.plane); - - LineToTriangleCollisionCompressed(*(CVuVector*)&line.p0, *(CVuVector*)&line.p1, vutri); - - CVuVector pnt, normal; - float dist; - if(GetVUresult(pnt, normal, dist)){ - if(dist < mindist){ - point.point = pnt; - point.normal = normal; - mindist = dist; - return true; - } - } - return false; -#else - float t; - CVector normal; - plane.GetNormal(normal); - - // if points are on the same side, no collision - if(plane.CalcPoint(line.p0) * plane.CalcPoint(line.p1) > 0.0f) - return false; - - // intersection parameter on line - t = -plane.CalcPoint(line.p0) / DotProduct(line.p1 - line.p0, normal); - // early out if we're beyond the mindist - if(t >= mindist) - return false; - // find point of intersection - CVector p = line.p0 + (line.p1-line.p0)*t; - - 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){ - case DIR_X_POS: - vec1.x = va.y; vec1.y = va.z; - vec2.x = vc.y; vec2.y = vc.z; - vec3.x = vb.y; vec3.y = vb.z; - vect.x = p.y; vect.y = p.z; - break; - case DIR_X_NEG: - vec1.x = va.y; vec1.y = va.z; - vec2.x = vb.y; vec2.y = vb.z; - vec3.x = vc.y; vec3.y = vc.z; - vect.x = p.y; vect.y = p.z; - break; - case DIR_Y_POS: - vec1.x = va.z; vec1.y = va.x; - vec2.x = vc.z; vec2.y = vc.x; - vec3.x = vb.z; vec3.y = vb.x; - vect.x = p.z; vect.y = p.x; - break; - case DIR_Y_NEG: - vec1.x = va.z; vec1.y = va.x; - vec2.x = vb.z; vec2.y = vb.x; - vec3.x = vc.z; vec3.y = vc.x; - vect.x = p.z; vect.y = p.x; - break; - case DIR_Z_POS: - vec1.x = va.x; vec1.y = va.y; - vec2.x = vc.x; vec2.y = vc.y; - vec3.x = vb.x; vec3.y = vb.y; - vect.x = p.x; vect.y = p.y; - break; - case DIR_Z_NEG: - vec1.x = va.x; vec1.y = va.y; - vec2.x = vb.x; vec2.y = vb.y; - vec3.x = vc.x; vec3.y = vc.y; - vect.x = p.x; vect.y = p.y; - break; - default: - assert(0); - } - 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; - point.pieceA = 0; - point.surfaceB = tri.surface; - point.pieceB = 0; - mindist = t; - return true; -#endif -} - -bool -CCollision::ProcessSphereTriangle(const CColSphere &sphere, - const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, - CColPoint &point, float &mindistsq) -{ -#ifdef VU_COLLISION - // not used in favour of optimized loops - VuTriangle vutri; - verts[tri.a].Unpack(vutri.v0); - verts[tri.b].Unpack(vutri.v1); - verts[tri.c].Unpack(vutri.v2); - plane.Unpack(vutri.plane); - - SphereToTriangleCollisionCompressed(*(CVuVector*)&sphere, vutri); - - CVuVector pnt, normal; - float dist; - if(GetVUresult(pnt, normal, dist) && dist*dist < mindistsq){ - float depth = sphere.radius - dist; - if(depth > point.depth){ - point.point = pnt; - point.normal = normal; - point.depth = depth; - mindistsq = dist*dist; - return true; - } - } - return false; -#else - // If sphere and plane don't intersect, no collision - float planedist = plane.CalcPoint(sphere.center); - float distsq = planedist*planedist; - if(Abs(planedist) > sphere.radius || distsq > mindistsq) - return false; - - 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; - plane.GetNormal(normal); - CVector vec2 = vb - va; - float len = vec2.Magnitude(); - vec2 = vec2 * (1.0f/len); - CVector vec1 = CrossProduct(vec2, normal); - - // We know A has local coordinate [0,0] and B has [0,len]. - // Now calculate coordinates on triangle for these two vectors: - CVector vac = vc - va; - CVector vas = sphere.center - va; - CVector2D b(0.0f, len); - CVector2D c(DotProduct(vec1, vac), DotProduct(vec2, vac)); - CVector2D s(DotProduct(vec1, vas), DotProduct(vec2, vas)); - - // The three triangle lines partition the space into 6 sectors, - // find out in which the center lies. - int insideAB = CrossProduct2D(s, b) >= 0.0f; - int insideAC = CrossProduct2D(c, s) >= 0.0f; - int insideBC = CrossProduct2D(s-b, c-b) >= 0.0f; - - int testcase = insideAB + insideAC + insideBC; - float dist = 0.0f; - CVector p; - 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(); - 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); - break; - case 3: - // center is in triangle - dist = Abs(planedist); - p = sphere.center - normal*planedist; - break; - default: - assert(0); - } - - if(dist >= sphere.radius || dist*dist >= mindistsq) - return false; - - point.point = p; - point.normal = sphere.center - p; - point.normal.Normalise(); -#ifndef VU_COLLISION - point.surfaceA = sphere.surface; - point.pieceA = sphere.piece; - point.surfaceB = tri.surface; - point.pieceB = 0; -#endif - point.depth = sphere.radius - dist; - mindistsq = dist*dist; - return true; -#endif -} - -bool -CCollision::ProcessLineOfSight(const CColLine &line, - const CMatrix &matrix, CColModel &model, - CColPoint &point, float &mindist, bool ignoreSeeThrough) -{ -#ifdef VU_COLLISION - CMatrix matTransform; - int i; - - // transform line to model space - Invert(matrix, matTransform); - CVuVector newline[2]; - TransformPoints(newline, 2, matTransform, (RwV3d*)&line.p0, sizeof(CColLine)/2); - - if(mindist < 1.0f) - newline[1] = newline[0] + (newline[1] - newline[0])*mindist; - - // If we don't intersect with the bounding box, no chance on the rest - if(!TestLineBox(*(CColLine*)newline, model.boundingBox)) - return false; - - float coldist = 1.0f; - for(i = 0; i < model.numSpheres; i++){ - if(ignoreSeeThrough && IsSeeThrough(model.spheres[i].surface)) continue; - if(ProcessLineSphere(*(CColLine*)newline, model.spheres[i], point, coldist)) - point.Set(0, 0, model.spheres[i].surface, model.spheres[i].piece); - } - - for(i = 0; i < model.numBoxes; i++){ - if(ignoreSeeThrough && IsSeeThrough(model.boxes[i].surface)) continue; - if(ProcessLineBox(*(CColLine*)newline, model.boxes[i], point, coldist)) - point.Set(0, 0, model.boxes[i].surface, model.boxes[i].piece); - } - - CalculateTrianglePlanes(&model); - VuTriangle vutri; - CColTriangle *lasttri = nil; - for(i = 0; i < model.numTriangles; i++){ - if(ignoreSeeThrough && IsSeeThrough(model.triangles[i].surface)) continue; - - CColTriangle *tri = &model.triangles[i]; - model.vertices[tri->a].Unpack(vutri.v0); - model.vertices[tri->b].Unpack(vutri.v1); - model.vertices[tri->c].Unpack(vutri.v2); - model.trianglePlanes[i].Unpack(vutri.plane); - - LineToTriangleCollisionCompressed(newline[0], newline[1], vutri); - lasttri = tri; - break; - } -#ifdef FIX_BUGS - // no need to check first again - i++; -#endif - CVuVector pnt, normal; - float dist; - for(; i < model.numTriangles; i++){ - if(ignoreSeeThrough && IsSeeThrough(model.triangles[i].surface)) continue; - - CColTriangle *tri = &model.triangles[i]; - model.vertices[tri->a].Unpack(vutri.v0); - model.vertices[tri->b].Unpack(vutri.v1); - model.vertices[tri->c].Unpack(vutri.v2); - model.trianglePlanes[i].Unpack(vutri.plane); - - if(GetVUresult(pnt, normal, dist)) - if(dist < coldist){ - point.point = pnt; - point.normal = normal; - point.Set(0, 0, lasttri->surface, 0); - coldist = dist; - } - - LineToTriangleCollisionCompressed(newline[0], newline[1], vutri); - lasttri = tri; - } - if(lasttri && GetVUresult(pnt, normal, dist)) - if(dist < coldist){ - point.point = pnt; - point.normal = normal; - point.Set(0, 0, lasttri->surface, 0); - coldist = dist; - } - - - if(coldist < 1.0f){ - point.point = matrix * point.point; - point.normal = Multiply3x3(matrix, point.normal); - mindist *= coldist; - return true; - } - return false; -#else - static CMatrix matTransform; - int i; - - // transform line to model space - Invert(matrix, matTransform); - CColLine newline(matTransform * line.p0, matTransform * line.p1); - - // If we don't intersect with the bounding box, no chance on the rest - if(!TestLineBox(newline, model.boundingBox)) - return false; - - float coldist = mindist; - 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 && IsSeeThrough(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; - ProcessLineTriangle(newline, model.vertices, model.triangles[i], model.trianglePlanes[i], point, coldist); - } - - if(coldist < mindist){ - point.point = matrix * point.point; - point.normal = Multiply3x3(matrix, point.normal); - mindist = coldist; - return true; - } - return false; -#endif -} - -bool -CCollision::ProcessVerticalLine(const CColLine &line, - const CMatrix &matrix, CColModel &model, - CColPoint &point, float &mindist, bool ignoreSeeThrough, CStoredCollPoly *poly) -{ -#ifdef VU_COLLISION - static CStoredCollPoly TempStoredPoly; - CMatrix matTransform; - int i; - - // transform line to model space - Invert(matrix, matTransform); - CVuVector newline[2]; - TransformPoints(newline, 2, matTransform, (RwV3d*)&line.p0, sizeof(CColLine)/2); - - if(mindist < 1.0f) - newline[1] = newline[0] + (newline[1] - newline[0])*mindist; - - if(!TestLineBox(*(CColLine*)newline, model.boundingBox)) - return false; - - float coldist = 1.0f; - for(i = 0; i < model.numSpheres; i++){ - if(ignoreSeeThrough && IsSeeThrough(model.spheres[i].surface)) continue; - if(ProcessLineSphere(*(CColLine*)newline, model.spheres[i], point, coldist)) - point.Set(0, 0, model.spheres[i].surface, model.spheres[i].piece); - } - - for(i = 0; i < model.numBoxes; i++){ - if(ignoreSeeThrough && IsSeeThrough(model.boxes[i].surface)) continue; - if(ProcessLineBox(*(CColLine*)newline, model.boxes[i], point, coldist)) - point.Set(0, 0, model.boxes[i].surface, model.boxes[i].piece); - } - - CalculateTrianglePlanes(&model); - TempStoredPoly.valid = false; - if(model.numTriangles){ - bool registeredCol; - CColTriangle *lasttri = nil; - VuTriangle vutri; - for(i = 0; i < model.numTriangles; i++){ - if(ignoreSeeThrough && IsSeeThrough(model.triangles[i].surface)) continue; - - CColTriangle *tri = &model.triangles[i]; - model.vertices[tri->a].Unpack(vutri.v0); - model.vertices[tri->b].Unpack(vutri.v1); - model.vertices[tri->c].Unpack(vutri.v2); - model.trianglePlanes[i].Unpack(vutri.plane); - - LineToTriangleCollisionCompressed(newline[0], newline[1], vutri); - lasttri = tri; - break; - } -#ifdef FIX_BUGS - // no need to check first again - i++; -#endif - CVuVector pnt, normal; - float dist; - for(; i < model.numTriangles; i++){ - if(ignoreSeeThrough && IsSeeThrough(model.triangles[i].surface)) continue; - - CColTriangle *tri = &model.triangles[i]; - model.vertices[tri->a].Unpack(vutri.v0); - model.vertices[tri->b].Unpack(vutri.v1); - model.vertices[tri->c].Unpack(vutri.v2); - model.trianglePlanes[i].Unpack(vutri.plane); - - if(GetVUresult(pnt, normal, dist)){ - if(dist < coldist){ - point.point = pnt; - point.normal = normal; - point.Set(0, 0, lasttri->surface, 0); - coldist = dist; - registeredCol = true; - }else - registeredCol = false; - }else - registeredCol = false; - - if(registeredCol){ - TempStoredPoly.verts[0] = model.vertices[lasttri->a].Get(); - TempStoredPoly.verts[1] = model.vertices[lasttri->b].Get(); - TempStoredPoly.verts[2] = model.vertices[lasttri->c].Get(); - TempStoredPoly.valid = true; - } - - LineToTriangleCollisionCompressed(newline[0], newline[1], vutri); - lasttri = tri; - } - if(lasttri && GetVUresult(pnt, normal, dist)){ - if(dist < coldist){ - point.point = pnt; - point.normal = normal; - point.Set(0, 0, lasttri->surface, 0); - coldist = dist; - registeredCol = true; - }else - registeredCol = false; - }else - registeredCol = false; - - if(registeredCol){ - TempStoredPoly.verts[0] = model.vertices[lasttri->a].Get(); - TempStoredPoly.verts[1] = model.vertices[lasttri->b].Get(); - TempStoredPoly.verts[2] = model.vertices[lasttri->c].Get(); - TempStoredPoly.valid = true; - } - } - - if(coldist < 1.0f){ - point.point = matrix * point.point; - point.normal = Multiply3x3(matrix, point.normal); - if(TempStoredPoly.valid && poly){ - *poly = TempStoredPoly; - poly->verts[0] = matrix * CVector(poly->verts[0]); - poly->verts[1] = matrix * CVector(poly->verts[1]); - poly->verts[2] = matrix * CVector(poly->verts[2]); - } - mindist *= coldist; - return true; - } - return false; -#else - static CStoredCollPoly TempStoredPoly; - int i; - - // 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)) - return false; - - float coldist = mindist; - 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 && 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 && 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(TempStoredPoly.valid && poly){ - *poly = TempStoredPoly; - poly->verts[0] = matrix * poly->verts[0]; - poly->verts[1] = matrix * poly->verts[1]; - poly->verts[2] = matrix * poly->verts[2]; - } - mindist = coldist; - return true; - } - return false; -#endif -} - -enum { - MAXNUMSPHERES = 128, - MAXNUMBOXES = 32, - MAXNUMLINES = 16, - MAXNUMTRIS = 600 -}; - -#ifdef VU_COLLISION -#ifdef GTA_PS2 -#define SPR(off) ((uint8*)(0x70000000 + (off))) -#else -static uint8 fakeSPR[16*1024]; -#define SPR(off) ((uint8*)(fakeSPR + (off))) -#endif -#endif - -// This checks model A's spheres and lines against model B's spheres, boxes and triangles. -// Returns the number of A's spheres that collide. -// Returned ColPoints are in world space. -// NB: only vehicles can have col models with lines, exactly 4, one for each wheel -int32 -CCollision::ProcessColModels(const CMatrix &matrixA, CColModel &modelA, - const CMatrix &matrixB, CColModel &modelB, - CColPoint *spherepoints, CColPoint *linepoints, float *linedists) -{ -#ifdef VU_COLLISION - CVuVector *aSpheresA = (CVuVector*)SPR(0x0000); - CVuVector *aSpheresB = (CVuVector*)SPR(0x0800); - CVuVector *aLinesA = (CVuVector*)SPR(0x1000); - int32 *aSphereIndicesA = (int32*)SPR(0x1200); - int32 *aSphereIndicesB = (int32*)SPR(0x1400); - int32 *aBoxIndicesB = (int32*)SPR(0x1600); - int32 *aTriangleIndicesB = (int32*)SPR(0x1680); - bool *aCollided = (bool*)SPR(0x1FE0); - CMatrix &matAB = *(CMatrix*)SPR(0x1FF0); - CMatrix &matBA = *(CMatrix*)SPR(0x2040); - int i, j, k; - - // From model A space to model B space - Invert(matrixB, matAB); - matAB *= matrixA; - - CVuVector bsphereAB; // bounding sphere of A in B space - TransformPoint(bsphereAB, matAB, *(RwV3d*)modelA.boundingSphere.center); // inlined - bsphereAB.w = modelA.boundingSphere.radius; - if(!TestSphereBox(*(CColSphere*)&bsphereAB, modelB.boundingBox)) - return 0; - - // transform modelA's spheres and lines to B space - TransformPoints(aSpheresA, modelA.numSpheres, matAB, (RwV3d*)&modelA.spheres->center, sizeof(CColSphere)); - for(i = 0; i < modelA.numSpheres; i++) - aSpheresA[i].w = modelA.spheres[i].radius; - TransformPoints(aLinesA, modelA.numLines*2, matAB, (RwV3d*)&modelA.lines->p0, sizeof(CColLine)/2); - - // Test them against model B's bounding volumes - int numSpheresA = 0; - for(i = 0; i < modelA.numSpheres; i++) - if(TestSphereBox(*(CColSphere*)&aSpheresA[i], modelB.boundingBox)) - aSphereIndicesA[numSpheresA++] = i; - // No collision - if(numSpheresA == 0 && modelA.numLines == 0) - return 0; - - - // B to A space - Invert(matrixA, matBA); - matBA *= matrixB; - - // transform modelB's spheres to A space - TransformPoints(aSpheresB, modelB.numSpheres, matBA, (RwV3d*)&modelB.spheres->center, sizeof(CColSphere)); - for(i = 0; i < modelB.numSpheres; i++) - aSpheresB[i].w = modelB.spheres[i].radius; - - // Check model B against A's bounding volumes - int numSpheresB = 0; - int numBoxesB = 0; - int numTrianglesB = 0; - for(i = 0; i < modelB.numSpheres; i++) - if(TestSphereBox(*(CColSphere*)&aSpheresB[i], modelA.boundingBox)) - aSphereIndicesB[numSpheresB++] = i; - for(i = 0; i < modelB.numBoxes; i++) - if(TestSphereBox(*(CColSphere*)&bsphereAB, modelB.boxes[i])) - aBoxIndicesB[numBoxesB++] = i; - CalculateTrianglePlanes(&modelB); - if(modelB.numTriangles){ - VuTriangle vutri; - // process the first triangle - CColTriangle *tri = &modelB.triangles[0]; - modelB.vertices[tri->a].Unpack(vutri.v0); - modelB.vertices[tri->b].Unpack(vutri.v1); - modelB.vertices[tri->c].Unpack(vutri.v2); - modelB.trianglePlanes[0].Unpack(vutri.plane); - - SphereToTriangleCollisionCompressed(bsphereAB, vutri); - - for(i = 1; i < modelB.numTriangles; i++){ - // set up the next triangle while VU0 is running - tri = &modelB.triangles[i]; - modelB.vertices[tri->a].Unpack(vutri.v0); - modelB.vertices[tri->b].Unpack(vutri.v1); - modelB.vertices[tri->c].Unpack(vutri.v2); - modelB.trianglePlanes[i].Unpack(vutri.plane); - - // check previous result - if(GetVUresult()) - aTriangleIndicesB[numTrianglesB++] = i-1; - - // kick off this one - SphereToTriangleCollisionCompressed(bsphereAB, vutri); - } - - // check last result - if(GetVUresult()) - aTriangleIndicesB[numTrianglesB++] = i-1; - } - // No collision - if(numSpheresB == 0 && numBoxesB == 0 && numTrianglesB == 0) - return 0; - - // We now have the collision volumes in A and B that are worth processing. - - // Process A's spheres against B's collision volumes - int numCollisions = 0; - spherepoints[numCollisions].depth = -1.0f; - for(i = 0; i < numSpheresA; i++){ - float coldist = 1.0e24f; - bool hasCollided = false; - CColSphere *sphA = &modelA.spheres[aSphereIndicesA[i]]; - CVuVector *vusphA = &aSpheresA[aSphereIndicesA[i]]; - - for(j = 0; j < numSpheresB; j++) - // This actually looks like something was inlined here - if(ProcessSphereSphere(*(CColSphere*)vusphA, modelB.spheres[aSphereIndicesB[j]], - spherepoints[numCollisions], coldist)){ - spherepoints[numCollisions].Set( - sphA->surface, sphA->piece, - modelB.spheres[aSphereIndicesB[j]].surface, modelB.spheres[aSphereIndicesB[j]].piece); - hasCollided = true; - } - for(j = 0; j < numBoxesB; j++) - if(ProcessSphereBox(*(CColSphere*)vusphA, modelB.boxes[aBoxIndicesB[j]], - spherepoints[numCollisions], coldist)){ - spherepoints[numCollisions].Set( - sphA->surface, sphA->piece, - modelB.boxes[aBoxIndicesB[j]].surface, modelB.boxes[aBoxIndicesB[j]].piece); - hasCollided = true; - } - if(numTrianglesB){ - CVuVector point, normal; - float depth; - bool registeredCol; - CColTriangle *lasttri; - - VuTriangle vutri; - // process the first triangle - k = aTriangleIndicesB[0]; - CColTriangle *tri = &modelB.triangles[k]; - modelB.vertices[tri->a].Unpack(vutri.v0); - modelB.vertices[tri->b].Unpack(vutri.v1); - modelB.vertices[tri->c].Unpack(vutri.v2); - modelB.trianglePlanes[k].Unpack(vutri.plane); - - SphereToTriangleCollisionCompressed(*vusphA, vutri); - lasttri = tri; - - for(j = 1; j < numTrianglesB; j++){ - k = aTriangleIndicesB[j]; - // set up the next triangle while VU0 is running - tri = &modelB.triangles[k]; - modelB.vertices[tri->a].Unpack(vutri.v0); - modelB.vertices[tri->b].Unpack(vutri.v1); - modelB.vertices[tri->c].Unpack(vutri.v2); - modelB.trianglePlanes[k].Unpack(vutri.plane); - - // check previous result - // TODO: this looks inlined but spherepoints[numCollisions] does not... - if(GetVUresult(point, normal, depth)){ - depth = sphA->radius - depth; - if(depth > spherepoints[numCollisions].depth){ - spherepoints[numCollisions].point = point; - spherepoints[numCollisions].normal = normal; - spherepoints[numCollisions].Set(depth, - sphA->surface, sphA->piece, lasttri->surface, 0); - registeredCol = true; - }else - registeredCol = false; - }else - registeredCol = false; - - if(registeredCol) - hasCollided = true; - - // kick off this one - SphereToTriangleCollisionCompressed(*vusphA, vutri); - lasttri = tri; - } - - // check last result - // TODO: this looks inlined but spherepoints[numCollisions] does not... - if(GetVUresult(point, normal, depth)){ - depth = sphA->radius - depth; - if(depth > spherepoints[numCollisions].depth){ - spherepoints[numCollisions].point = point; - spherepoints[numCollisions].normal = normal; - spherepoints[numCollisions].Set(depth, - sphA->surface, sphA->piece, lasttri->surface, 0); - registeredCol = true; - }else - registeredCol = false; - }else - registeredCol = false; - - if(registeredCol) - hasCollided = true; - } - - if(hasCollided){ - numCollisions++; - if(numCollisions == MAX_COLLISION_POINTS) - break; - spherepoints[numCollisions].depth = -1.0f; - } - } - for(i = 0; i < numCollisions; i++){ - // TODO: both VU0 macros - spherepoints[i].point = matrixB * spherepoints[i].point; - spherepoints[i].normal = Multiply3x3(matrixB, spherepoints[i].normal); - } - - // And the same thing for the lines in A - for(i = 0; i < modelA.numLines; i++){ - aCollided[i] = false; - CVuVector *lineA = &aLinesA[i*2]; - - for(j = 0; j < numSpheresB; j++) - if(ProcessLineSphere(*(CColLine*)lineA, modelB.spheres[aSphereIndicesB[j]], - linepoints[i], linedists[i])){ - linepoints[i].Set(0, 0, -#ifdef FIX_BUGS - modelB.spheres[aSphereIndicesB[j]].surface, modelB.spheres[aSphereIndicesB[j]].piece); -#else - modelB.spheres[j].surface, modelB.spheres[j].piece); -#endif - aCollided[i] = true; - } - for(j = 0; j < numBoxesB; j++) - if(ProcessLineBox(*(CColLine*)lineA, modelB.boxes[aBoxIndicesB[j]], - linepoints[i], linedists[i])){ - linepoints[i].Set(0, 0, - modelB.boxes[aBoxIndicesB[j]].surface, modelB.boxes[aBoxIndicesB[j]].piece); - aCollided[i] = true; - } - if(numTrianglesB){ - CVuVector point, normal; - float dist; - bool registeredCol; - CColTriangle *lasttri; - - VuTriangle vutri; - // process the first triangle - k = aTriangleIndicesB[0]; - CColTriangle *tri = &modelB.triangles[k]; - modelB.vertices[tri->a].Unpack(vutri.v0); - modelB.vertices[tri->b].Unpack(vutri.v1); - modelB.vertices[tri->c].Unpack(vutri.v2); - modelB.trianglePlanes[k].Unpack(vutri.plane); - - LineToTriangleCollisionCompressed(lineA[0], lineA[1], vutri); - lasttri = tri; - - for(j = 1; j < numTrianglesB; j++){ - k = aTriangleIndicesB[j]; - // set up the next triangle while VU0 is running - CColTriangle *tri = &modelB.triangles[k]; - modelB.vertices[tri->a].Unpack(vutri.v0); - modelB.vertices[tri->b].Unpack(vutri.v1); - modelB.vertices[tri->c].Unpack(vutri.v2); - modelB.trianglePlanes[k].Unpack(vutri.plane); - - // check previous result - // TODO: this again somewhat looks inlined - if(GetVUresult(point, normal, dist)){ - if(dist < linedists[i]){ - linepoints[i].point = point; - linepoints[i].normal = normal; - linedists[i] = dist; - linepoints[i].Set(0, 0, lasttri->surface, 0); - registeredCol = true; - }else - registeredCol = false; - }else - registeredCol = false; - - if(registeredCol) - aCollided[i] = true; - - // kick of this one - LineToTriangleCollisionCompressed(lineA[0], lineA[1], vutri); - lasttri = tri; - } - - // check last result - if(GetVUresult(point, normal, dist)){ - if(dist < linedists[i]){ - linepoints[i].point = point; - linepoints[i].normal = normal; - linedists[i] = dist; - linepoints[i].Set(0, 0, lasttri->surface, 0); - registeredCol = true; - }else - registeredCol = false; - }else - registeredCol = false; - - if(registeredCol) - aCollided[i] = true; - } - - if(aCollided[i]){ - // TODO: both VU0 macros - linepoints[i].point = matrixB * linepoints[i].point; - linepoints[i].normal = Multiply3x3(matrixB, linepoints[i].normal); - } - } - - return numCollisions; // sphere collisions -#else - static int aSphereIndicesA[MAXNUMSPHERES]; - static int aLineIndicesA[MAXNUMLINES]; - static int aSphereIndicesB[MAXNUMSPHERES]; - static int aBoxIndicesB[MAXNUMBOXES]; - static int aTriangleIndicesB[MAXNUMTRIS]; - static bool aCollided[MAXNUMLINES]; - static CColSphere aSpheresA[MAXNUMSPHERES]; - static CColLine aLinesA[MAXNUMLINES]; - static CMatrix matAB, matBA; - CColSphere s; - int i, j; - - assert(modelA.numSpheres <= MAXNUMSPHERES); - assert(modelA.numLines <= MAXNUMLINES); - - // From model A space to model B space - Invert(matrixB, matAB); - matAB *= matrixA; - - CColSphere bsphereAB; // bounding sphere of A in B space - bsphereAB.Set(modelA.boundingSphere.radius, matAB * modelA.boundingSphere.center); - if(!TestSphereBox(bsphereAB, modelB.boundingBox)) - return 0; - // B to A space - matBA = Invert(matrixA, matBA); - matBA *= matrixB; - - // transform modelA's spheres and lines to B space - for(i = 0; i < modelA.numSpheres; i++){ - CColSphere &s = modelA.spheres[i]; - aSpheresA[i].Set(s.radius, matAB * s.center, s.surface, s.piece); - } - for(i = 0; i < modelA.numLines; i++) - aLinesA[i].Set(matAB * modelA.lines[i].p0, matAB * modelA.lines[i].p1); - - // Test them against model B's bounding volumes - int numSpheresA = 0; - int numLinesA = 0; - for(i = 0; i < modelA.numSpheres; i++) - if(TestSphereBox(aSpheresA[i], modelB.boundingBox)) - aSphereIndicesA[numSpheresA++] = i; - // no actual check??? - for(i = 0; i < modelA.numLines; i++) - aLineIndicesA[numLinesA++] = i; - // No collision - if(numSpheresA == 0 && numLinesA == 0) - return 0; - - // Check model B against A's bounding volumes - int numSpheresB = 0; - int numBoxesB = 0; - int numTrianglesB = 0; - for(i = 0; i < modelB.numSpheres; i++){ - s.Set(modelB.spheres[i].radius, matBA * modelB.spheres[i].center); - if(TestSphereBox(s, modelA.boundingBox)) - aSphereIndicesB[numSpheresB++] = i; - } - for(i = 0; i < modelB.numBoxes; i++) - if(TestSphereBox(bsphereAB, modelB.boxes[i])) - aBoxIndicesB[numBoxesB++] = i; - CalculateTrianglePlanes(&modelB); - for(i = 0; i < modelB.numTriangles; i++) - if(TestSphereTriangle(bsphereAB, modelB.vertices, modelB.triangles[i], modelB.trianglePlanes[i])) - aTriangleIndicesB[numTrianglesB++] = i; - assert(numSpheresB <= MAXNUMSPHERES); - assert(numBoxesB <= MAXNUMBOXES); - assert(numTrianglesB <= MAXNUMTRIS); - // No collision - if(numSpheresB == 0 && numBoxesB == 0 && numTrianglesB == 0) - return 0; - - // We now have the collision volumes in A and B that are worth processing. - - // Process A's spheres against B's collision volumes - int numCollisions = 0; - for(i = 0; i < numSpheresA; i++){ - float coldist = 1.0e24f; - bool hasCollided = false; - - for(j = 0; j < numSpheresB; j++) - hasCollided |= ProcessSphereSphere( - aSpheresA[aSphereIndicesA[i]], - modelB.spheres[aSphereIndicesB[j]], - spherepoints[numCollisions], coldist); - for(j = 0; j < numBoxesB; j++) - hasCollided |= ProcessSphereBox( - aSpheresA[aSphereIndicesA[i]], - modelB.boxes[aBoxIndicesB[j]], - spherepoints[numCollisions], coldist); - for(j = 0; j < numTrianglesB; j++) - hasCollided |= ProcessSphereTriangle( - aSpheresA[aSphereIndicesA[i]], - modelB.vertices, - modelB.triangles[aTriangleIndicesB[j]], - modelB.trianglePlanes[aTriangleIndicesB[j]], - spherepoints[numCollisions], coldist); - - if(hasCollided) - numCollisions++; - } - for(i = 0; i < numCollisions; i++){ - spherepoints[i].point = matrixB * spherepoints[i].point; - spherepoints[i].normal = Multiply3x3(matrixB, spherepoints[i].normal); - } - - // And the same thing for the lines in A - for(i = 0; i < numLinesA; i++){ - aCollided[i] = false; - - for(j = 0; j < numSpheresB; j++) - aCollided[i] |= ProcessLineSphere( - aLinesA[aLineIndicesA[i]], - modelB.spheres[aSphereIndicesB[j]], - linepoints[aLineIndicesA[i]], - linedists[aLineIndicesA[i]]); - for(j = 0; j < numBoxesB; j++) - aCollided[i] |= ProcessLineBox( - aLinesA[aLineIndicesA[i]], - modelB.boxes[aBoxIndicesB[j]], - linepoints[aLineIndicesA[i]], - linedists[aLineIndicesA[i]]); - for(j = 0; j < numTrianglesB; j++) - aCollided[i] |= ProcessLineTriangle( - aLinesA[aLineIndicesA[i]], - modelB.vertices, - modelB.triangles[aTriangleIndicesB[j]], - modelB.trianglePlanes[aTriangleIndicesB[j]], - linepoints[aLineIndicesA[i]], - linedists[aLineIndicesA[i]]); - } - for(i = 0; i < numLinesA; i++) - if(aCollided[i]){ - j = aLineIndicesA[i]; - linepoints[j].point = matrixB * linepoints[j].point; - linepoints[j].normal = Multiply3x3(matrixB, linepoints[j].normal); - } - - return numCollisions; // sphere collisions -#endif -} - - -// -// Misc -// - -float -CCollision::DistToLine(const CVector *l0, const CVector *l1, const CVector *point) -{ - float lensq = (*l1 - *l0).MagnitudeSqr(); - float dot = DotProduct(*point - *l0, *l1 - *l0); - // Between 0 and len we're above the line. - // if not, calculate distance to endpoint - if(dot <= 0.0f) - return (*point - *l0).Magnitude(); - if(dot >= lensq) - return (*point - *l1).Magnitude(); - // distance to line - return Sqrt((*point - *l0).MagnitudeSqr() - dot*dot/lensq); -} - -// same as above but also return the point on the line -float -CCollision::DistToLine(const CVector *l0, const CVector *l1, const CVector *point, CVector &closest) -{ - float lensq = (*l1 - *l0).MagnitudeSqr(); - float dot = DotProduct(*point - *l0, *l1 - *l0); - // find out which point we're closest to - if(dot <= 0.0f) - closest = *l0; - else if(dot >= lensq) - closest = *l1; - else - closest = *l0 + (*l1 - *l0)*(dot/lensq); - // this is the distance - return (*point - closest).Magnitude(); -} - -void -CCollision::CalculateTrianglePlanes(CColModel *model) -{ - assert(model); - if(model->numTriangles == 0) - return; - - CLink *lptr; - if(model->trianglePlanes){ - // re-insert at front so it's not removed again soon - lptr = model->GetLinkPtr(); - lptr->Remove(); - ms_colModelCache.head.Insert(lptr); - }else{ - lptr = ms_colModelCache.Insert(model); - if(lptr == nil){ - // make room if we have to, remove last in list - lptr = ms_colModelCache.tail.prev; - assert(lptr); - assert(lptr->item); - lptr->item->RemoveTrianglePlanes(); - ms_colModelCache.Remove(lptr); - // now this cannot fail - lptr = ms_colModelCache.Insert(model); - assert(lptr); - } - model->CalculateTrianglePlanes(); - model->SetLinkPtr(lptr); - } -} - -void -CCollision::DrawColModel(const CMatrix &mat, const CColModel &colModel) -{ - int i; - CVector min, max; - CVector verts[8]; - CVector c; - float r; - - RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE); - RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); - RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); - RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); - RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil); - - min = colModel.boundingBox.min; - max = colModel.boundingBox.max; - - verts[0] = mat * CVector(min.x, min.y, min.z); - verts[1] = mat * CVector(min.x, min.y, max.z); - verts[2] = mat * CVector(min.x, max.y, min.z); - verts[3] = mat * CVector(min.x, max.y, max.z); - verts[4] = mat * CVector(max.x, min.y, min.z); - verts[5] = mat * CVector(max.x, min.y, max.z); - verts[6] = mat * CVector(max.x, max.y, min.z); - verts[7] = mat * CVector(max.x, max.y, max.z); - - CLines::RenderLineWithClipping( - verts[0].x, verts[0].y, verts[0].z, - verts[1].x, verts[1].y, verts[1].z, - 0xFF0000FF, 0xFF0000FF); - CLines::RenderLineWithClipping( - verts[1].x, verts[1].y, verts[1].z, - verts[3].x, verts[3].y, verts[3].z, - 0xFF0000FF, 0xFF0000FF); - CLines::RenderLineWithClipping( - verts[3].x, verts[3].y, verts[3].z, - verts[2].x, verts[2].y, verts[2].z, - 0xFF0000FF, 0xFF0000FF); - CLines::RenderLineWithClipping( - verts[2].x, verts[2].y, verts[2].z, - verts[0].x, verts[0].y, verts[0].z, - 0xFF0000FF, 0xFF0000FF); - - CLines::RenderLineWithClipping( - verts[4].x, verts[4].y, verts[4].z, - verts[5].x, verts[5].y, verts[5].z, - 0xFF0000FF, 0xFF0000FF); - CLines::RenderLineWithClipping( - verts[5].x, verts[5].y, verts[5].z, - verts[7].x, verts[7].y, verts[7].z, - 0xFF0000FF, 0xFF0000FF); - CLines::RenderLineWithClipping( - verts[7].x, verts[7].y, verts[7].z, - verts[6].x, verts[6].y, verts[6].z, - 0xFF0000FF, 0xFF0000FF); - CLines::RenderLineWithClipping( - verts[6].x, verts[6].y, verts[6].z, - verts[4].x, verts[4].y, verts[4].z, - 0xFF0000FF, 0xFF0000FF); - - CLines::RenderLineWithClipping( - verts[0].x, verts[0].y, verts[0].z, - verts[4].x, verts[4].y, verts[4].z, - 0xFF0000FF, 0xFF0000FF); - CLines::RenderLineWithClipping( - verts[1].x, verts[1].y, verts[1].z, - verts[5].x, verts[5].y, verts[5].z, - 0xFF0000FF, 0xFF0000FF); - CLines::RenderLineWithClipping( - verts[2].x, verts[2].y, verts[2].z, - verts[6].x, verts[6].y, verts[6].z, - 0xFF0000FF, 0xFF0000FF); - CLines::RenderLineWithClipping( - verts[3].x, verts[3].y, verts[3].z, - verts[7].x, verts[7].y, verts[7].z, - 0xFF0000FF, 0xFF0000FF); - - for(i = 0; i < colModel.numSpheres; i++){ - c = mat * colModel.spheres[i].center; - r = colModel.spheres[i].radius; - - CLines::RenderLineWithClipping( - c.x, c.y, c.z-r, - c.x-r, c.y-r, c.z, - 0xFF00FFFF, 0xFF00FFFF); - CLines::RenderLineWithClipping( - c.x, c.y, c.z-r, - c.x-r, c.y+r, c.z, - 0xFF00FFFF, 0xFF00FFFF); - CLines::RenderLineWithClipping( - c.x, c.y, c.z-r, - c.x+r, c.y-r, c.z, - 0xFF00FFFF, 0xFF00FFFF); - CLines::RenderLineWithClipping( - c.x, c.y, c.z-r, - c.x+r, c.y+r, c.z, - 0xFF00FFFF, 0xFF00FFFF); - CLines::RenderLineWithClipping( - c.x-r, c.y-r, c.z, - c.x, c.y, c.z+r, - 0xFF00FFFF, 0xFF00FFFF); - CLines::RenderLineWithClipping( - c.x-r, c.y+r, c.z, - c.x, c.y, c.z+r, - 0xFF00FFFF, 0xFF00FFFF); - CLines::RenderLineWithClipping( - c.x+r, c.y-r, c.z, - c.x, c.y, c.z+r, - 0xFF00FFFF, 0xFF00FFFF); - CLines::RenderLineWithClipping( - c.x+r, c.y+r, c.z, - c.x, c.y, c.z+r, - 0xFF00FFFF, 0xFF00FFFF); - } - - for(i = 0; i < colModel.numLines; i++){ - verts[0] = colModel.lines[i].p0; - verts[1] = colModel.lines[i].p1; - - verts[0] = mat * verts[0]; - verts[1] = mat * verts[1]; - - CLines::RenderLineWithClipping( - verts[0].x, verts[0].y, verts[0].z, - verts[1].x, verts[1].y, verts[1].z, - 0x00FFFFFF, 0x00FFFFFF); - } - - for(i = 0; i < colModel.numBoxes; i++){ - min = colModel.boxes[i].min; - max = colModel.boxes[i].max; - - verts[0] = mat * CVector(min.x, min.y, min.z); - verts[1] = mat * CVector(min.x, min.y, max.z); - verts[2] = mat * CVector(min.x, max.y, min.z); - verts[3] = mat * CVector(min.x, max.y, max.z); - verts[4] = mat * CVector(max.x, min.y, min.z); - verts[5] = mat * CVector(max.x, min.y, max.z); - verts[6] = mat * CVector(max.x, max.y, min.z); - verts[7] = mat * CVector(max.x, max.y, max.z); - - CLines::RenderLineWithClipping( - verts[0].x, verts[0].y, verts[0].z, - verts[1].x, verts[1].y, verts[1].z, - 0xFFFFFFFF, 0xFFFFFFFF); - CLines::RenderLineWithClipping( - verts[1].x, verts[1].y, verts[1].z, - verts[3].x, verts[3].y, verts[3].z, - 0xFFFFFFFF, 0xFFFFFFFF); - CLines::RenderLineWithClipping( - verts[3].x, verts[3].y, verts[3].z, - verts[2].x, verts[2].y, verts[2].z, - 0xFFFFFFFF, 0xFFFFFFFF); - CLines::RenderLineWithClipping( - verts[2].x, verts[2].y, verts[2].z, - verts[0].x, verts[0].y, verts[0].z, - 0xFFFFFFFF, 0xFFFFFFFF); - - CLines::RenderLineWithClipping( - verts[4].x, verts[4].y, verts[4].z, - verts[5].x, verts[5].y, verts[5].z, - 0xFFFFFFFF, 0xFFFFFFFF); - CLines::RenderLineWithClipping( - verts[5].x, verts[5].y, verts[5].z, - verts[7].x, verts[7].y, verts[7].z, - 0xFFFFFFFF, 0xFFFFFFFF); - CLines::RenderLineWithClipping( - verts[7].x, verts[7].y, verts[7].z, - verts[6].x, verts[6].y, verts[6].z, - 0xFFFFFFFF, 0xFFFFFFFF); - CLines::RenderLineWithClipping( - verts[6].x, verts[6].y, verts[6].z, - verts[4].x, verts[4].y, verts[4].z, - 0xFFFFFFFF, 0xFFFFFFFF); - - CLines::RenderLineWithClipping( - verts[0].x, verts[0].y, verts[0].z, - verts[4].x, verts[4].y, verts[4].z, - 0xFFFFFFFF, 0xFFFFFFFF); - CLines::RenderLineWithClipping( - verts[1].x, verts[1].y, verts[1].z, - verts[5].x, verts[5].y, verts[5].z, - 0xFFFFFFFF, 0xFFFFFFFF); - CLines::RenderLineWithClipping( - verts[2].x, verts[2].y, verts[2].z, - verts[6].x, verts[6].y, verts[6].z, - 0xFFFFFFFF, 0xFFFFFFFF); - CLines::RenderLineWithClipping( - verts[3].x, verts[3].y, verts[3].z, - verts[7].x, verts[7].y, verts[7].z, - 0xFFFFFFFF, 0xFFFFFFFF); - } - - for(i = 0; i < colModel.numTriangles; i++){ - colModel.GetTrianglePoint(verts[0], colModel.triangles[i].a); - colModel.GetTrianglePoint(verts[1], colModel.triangles[i].b); - colModel.GetTrianglePoint(verts[2], colModel.triangles[i].c); - verts[0] = mat * verts[0]; - verts[1] = mat * verts[1]; - verts[2] = mat * verts[2]; - CLines::RenderLineWithClipping( - verts[0].x, verts[0].y, verts[0].z, - verts[1].x, verts[1].y, verts[1].z, - 0x00FF00FF, 0x00FF00FF); - CLines::RenderLineWithClipping( - verts[0].x, verts[0].y, verts[0].z, - verts[2].x, verts[2].y, verts[2].z, - 0x00FF00FF, 0x00FF00FF); - CLines::RenderLineWithClipping( - verts[1].x, verts[1].y, verts[1].z, - verts[2].x, verts[2].y, verts[2].z, - 0x00FF00FF, 0x00FF00FF); - } - - RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); - RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); - RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE); - RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE); - RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE); -} - -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; - RwImVertexIndex *iptr; - RwIm3DVertex *vptr; - - RenderBuffer::ClearRenderBuffer(); - RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE); - RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); - RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); - RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); - RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil); - - for(i = 0; i < colModel.numTriangles; i++){ - colModel.GetTrianglePoint(verts[0], colModel.triangles[i].a); - colModel.GetTrianglePoint(verts[1], colModel.triangles[i].b); - colModel.GetTrianglePoint(verts[2], colModel.triangles[i].c); - verts[0] = mat * verts[0]; - 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; - } - - if(s > SURFACE_METAL_GATE){ - r = CGeneral::GetRandomNumber(); - g = CGeneral::GetRandomNumber(); - b = CGeneral::GetRandomNumber(); - printf("Illegal surfacetype:%d on MI:%d\n", s, id); - } - - RenderBuffer::StartStoring(6, 3, &iptr, &vptr); - RwIm3DVertexSetRGBA(&vptr[0], r, g, b, 255); - RwIm3DVertexSetRGBA(&vptr[1], r, g, b, 255); - RwIm3DVertexSetRGBA(&vptr[2], r, g, b, 255); - RwIm3DVertexSetU(&vptr[0], 0.0f); - RwIm3DVertexSetV(&vptr[0], 0.0f); - RwIm3DVertexSetU(&vptr[1], 0.0f); - RwIm3DVertexSetV(&vptr[1], 1.0f); - RwIm3DVertexSetU(&vptr[2], 1.0f); - RwIm3DVertexSetV(&vptr[2], 1.0f); - RwIm3DVertexSetPos(&vptr[0], verts[0].x, verts[0].y, verts[0].z); - RwIm3DVertexSetPos(&vptr[1], verts[1].x, verts[1].y, verts[1].z); - RwIm3DVertexSetPos(&vptr[2], verts[2].x, verts[2].y, verts[2].z); - iptr[0] = 0; iptr[1] = 1; iptr[2] = 2; - iptr[3] = 0; iptr[4] = 2; iptr[5] = 1; - RenderBuffer::StopStoring(); - } - - for(i = 0; i < colModel.numBoxes; i++){ - min = colModel.boxes[i].min; - max = colModel.boxes[i].max; - - verts[0] = mat * CVector(min.x, min.y, min.z); - verts[1] = mat * CVector(min.x, min.y, max.z); - verts[2] = mat * CVector(min.x, max.y, min.z); - verts[3] = mat * CVector(min.x, max.y, max.z); - verts[4] = mat * CVector(max.x, min.y, min.z); - verts[5] = mat * CVector(max.x, min.y, max.z); - verts[6] = mat * CVector(max.x, max.y, min.z); - 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; - } - - RenderBuffer::StartStoring(36, 8, &iptr, &vptr); - RwIm3DVertexSetRGBA(&vptr[0], r, g, b, 255); - RwIm3DVertexSetRGBA(&vptr[1], r, g, b, 255); - RwIm3DVertexSetRGBA(&vptr[2], r, g, b, 255); - RwIm3DVertexSetRGBA(&vptr[3], r, g, b, 255); - RwIm3DVertexSetRGBA(&vptr[4], r, g, b, 255); - RwIm3DVertexSetRGBA(&vptr[5], r, g, b, 255); - RwIm3DVertexSetRGBA(&vptr[6], r, g, b, 255); - RwIm3DVertexSetRGBA(&vptr[7], r, g, b, 255); - RwIm3DVertexSetU(&vptr[0], 0.0f); - RwIm3DVertexSetV(&vptr[0], 0.0f); - RwIm3DVertexSetU(&vptr[1], 0.0f); - RwIm3DVertexSetV(&vptr[1], 1.0f); - RwIm3DVertexSetU(&vptr[2], 1.0f); - RwIm3DVertexSetV(&vptr[2], 1.0f); - RwIm3DVertexSetU(&vptr[3], 0.0f); - RwIm3DVertexSetV(&vptr[3], 0.0f); - RwIm3DVertexSetU(&vptr[4], 0.0f); - RwIm3DVertexSetV(&vptr[4], 1.0f); - RwIm3DVertexSetU(&vptr[5], 1.0f); - RwIm3DVertexSetV(&vptr[5], 1.0f); - RwIm3DVertexSetU(&vptr[6], 0.0f); - RwIm3DVertexSetV(&vptr[6], 1.0f); - RwIm3DVertexSetU(&vptr[7], 1.0f); - RwIm3DVertexSetV(&vptr[7], 1.0f); - RwIm3DVertexSetPos(&vptr[0], verts[0].x, verts[0].y, verts[0].z); - RwIm3DVertexSetPos(&vptr[1], verts[1].x, verts[1].y, verts[1].z); - RwIm3DVertexSetPos(&vptr[2], verts[2].x, verts[2].y, verts[2].z); - RwIm3DVertexSetPos(&vptr[3], verts[3].x, verts[3].y, verts[3].z); - RwIm3DVertexSetPos(&vptr[4], verts[4].x, verts[4].y, verts[4].z); - RwIm3DVertexSetPos(&vptr[5], verts[5].x, verts[5].y, verts[5].z); - RwIm3DVertexSetPos(&vptr[6], verts[6].x, verts[6].y, verts[6].z); - RwIm3DVertexSetPos(&vptr[7], verts[7].x, verts[7].y, verts[7].z); - iptr[0] = 0; iptr[1] = 1; iptr[2] = 2; - iptr[3] = 1; iptr[4] = 3; iptr[5] = 2; - iptr[6] = 1; iptr[7] = 5; iptr[8] = 7; - iptr[9] = 1; iptr[10] = 7; iptr[11] = 3; - iptr[12] = 2; iptr[13] = 3; iptr[14] = 7; - iptr[15] = 2; iptr[16] = 7; iptr[17] = 6; - iptr[18] = 0; iptr[19] = 5; iptr[20] = 1; - iptr[21] = 0; iptr[22] = 4; iptr[23] = 5; - iptr[24] = 0; iptr[25] = 2; iptr[26] = 4; - iptr[27] = 2; iptr[28] = 6; iptr[29] = 4; - iptr[30] = 4; iptr[31] = 6; iptr[32] = 7; - iptr[33] = 4; iptr[34] = 7; iptr[35] = 5; - RenderBuffer::StopStoring(); - } - - RenderBuffer::RenderStuffInBuffer(); - RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); - RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); - RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE); - RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE); - RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE); -} - - -/* - * ColModel code - */ - -void -CColSphere::Set(float radius, const CVector ¢er, uint8 surf, uint8 piece) -{ - this->radius = radius; - this->center = center; - this->surface = surf; - this->piece = piece; -} - -void -CColBox::Set(const CVector &min, const CVector &max, uint8 surf, uint8 piece) -{ - this->min = min; - this->max = max; - this->surface = surf; - this->piece = piece; -} - -void -CColLine::Set(const CVector &p0, const CVector &p1) -{ - this->p0 = p0; - this->p1 = p1; -} - -void -CColTriangle::Set(const CompressedVector *, int a, int b, int c, uint8 surf, uint8 piece) -{ - this->a = a; - this->b = b; - this->c = c; - this->surface = surf; -} - -#ifdef VU_COLLISION -void -CColTrianglePlane::Set(const CVector &va, const CVector &vb, const CVector &vc) -{ - CVector norm = CrossProduct(vc-va, vb-va); - norm.Normalise(); - float d = DotProduct(norm, va); - normal.x = norm.x*4096.0f; - normal.y = norm.y*4096.0f; - normal.z = norm.z*4096.0f; - dist = d*128.0f; -} -#else -void -CColTrianglePlane::Set(const CVector &va, const CVector &vb, const CVector &vc) -{ - normal = CrossProduct(vc-va, vb-va); - normal.Normalise(); - dist = DotProduct(normal, va); - CVector an(Abs(normal.x), Abs(normal.y), Abs(normal.z)); - // find out largest component and its direction - if(an.x > an.y && an.x > an.z) - dir = normal.x < 0.0f ? DIR_X_NEG : DIR_X_POS; - else if(an.y > an.z) - dir = normal.y < 0.0f ? DIR_Y_NEG : DIR_Y_POS; - else - dir = normal.z < 0.0f ? DIR_Z_NEG : DIR_Z_POS; -} -#endif - -CColModel::CColModel(void) -{ - numSpheres = 0; - spheres = nil; - numLines = 0; - lines = nil; - numBoxes = 0; - boxes = nil; - numTriangles = 0; - vertices = nil; - triangles = nil; - trianglePlanes = nil; - level = CGame::currLevel; - ownsCollisionVolumes = true; -} - -CColModel::~CColModel(void) -{ - RemoveCollisionVolumes(); - RemoveTrianglePlanes(); -} - -void -CColModel::RemoveCollisionVolumes(void) -{ - if(ownsCollisionVolumes){ - RwFree(spheres); - RwFree(lines); - RwFree(boxes); - RwFree(vertices); - RwFree(triangles); - } - numSpheres = 0; - numLines = 0; - numBoxes = 0; - numTriangles = 0; - spheres = nil; - lines = nil; - boxes = nil; - vertices = nil; - triangles = nil; -} - -void -CColModel::CalculateTrianglePlanes(void) -{ - // HACK: allocate space for one more element to stuff the link pointer into - trianglePlanes = (CColTrianglePlane*)RwMalloc(sizeof(CColTrianglePlane) * (numTriangles+1)); - for(int i = 0; i < numTriangles; i++) - trianglePlanes[i].Set(vertices, triangles[i]); -} - -void -CColModel::RemoveTrianglePlanes(void) -{ - RwFree(trianglePlanes); - trianglePlanes = nil; -} - -void -CColModel::SetLinkPtr(CLink *lptr) -{ - assert(trianglePlanes); - *(CLink**)ALIGNPTR(&trianglePlanes[numTriangles]) = lptr; -} - -CLink* -CColModel::GetLinkPtr(void) -{ - assert(trianglePlanes); - return *(CLink**)ALIGNPTR(&trianglePlanes[numTriangles]); -} - -void -CColModel::GetTrianglePoint(CVector &v, int i) const -{ - v = vertices[i].Get(); -} - -CColModel& -CColModel::operator=(const CColModel &other) -{ - int i; - int numVerts; - - boundingSphere = other.boundingSphere; - boundingBox = other.boundingBox; - - // copy spheres - if(other.numSpheres){ - if(numSpheres != other.numSpheres){ - numSpheres = other.numSpheres; - if(spheres) - RwFree(spheres); - spheres = (CColSphere*)RwMalloc(numSpheres*sizeof(CColSphere)); - } - for(i = 0; i < numSpheres; i++) - spheres[i] = other.spheres[i]; - }else{ - numSpheres = 0; - if(spheres) - RwFree(spheres); - spheres = nil; - } - - // copy lines - if(other.numLines){ - if(numLines != other.numLines){ - numLines = other.numLines; - if(lines) - RwFree(lines); - lines = (CColLine*)RwMalloc(numLines*sizeof(CColLine)); - } - for(i = 0; i < numLines; i++) - lines[i] = other.lines[i]; - }else{ - numLines = 0; - if(lines) - RwFree(lines); - lines = nil; - } - - // copy boxes - if(other.numBoxes){ - if(numBoxes != other.numBoxes){ - numBoxes = other.numBoxes; - if(boxes) - RwFree(boxes); - boxes = (CColBox*)RwMalloc(numBoxes*sizeof(CColBox)); - } - for(i = 0; i < numBoxes; i++) - boxes[i] = other.boxes[i]; - }else{ - numBoxes = 0; - if(boxes) - RwFree(boxes); - boxes = nil; - } - - // copy mesh - if(other.numTriangles){ - // copy vertices - numVerts = 0; - for(i = 0; i < other.numTriangles; i++){ - if(other.triangles[i].a > numVerts) - numVerts = other.triangles[i].a; - if(other.triangles[i].b > numVerts) - numVerts = other.triangles[i].b; - if(other.triangles[i].c > numVerts) - numVerts = other.triangles[i].c; - } - numVerts++; - if(vertices) - RwFree(vertices); - if(numVerts){ - vertices = (CompressedVector*)RwMalloc(numVerts*sizeof(CompressedVector)); - for(i = 0; i < numVerts; i++) - vertices[i] = other.vertices[i]; - } - - // copy triangles - if(numTriangles != other.numTriangles){ - numTriangles = other.numTriangles; - if(triangles) - RwFree(triangles); - triangles = (CColTriangle*)RwMalloc(numTriangles*sizeof(CColTriangle)); - } - for(i = 0; i < numTriangles; i++) - triangles[i] = other.triangles[i]; - }else{ - numTriangles = 0; - if(triangles) - RwFree(triangles); - triangles = nil; - if(vertices) - RwFree(vertices); - vertices = nil; - } - return *this; -} diff --git a/src/core/Collision.h b/src/core/Collision.h deleted file mode 100644 index da94dd34..00000000 --- a/src/core/Collision.h +++ /dev/null @@ -1,254 +0,0 @@ -#pragma once - -#include "templates.h" -#include "Game.h" // for eLevelName -#ifdef VU_COLLISION -#include "VuVector.h" -#endif - -// If you spawn many tanks at once, you will see that collisions of two entity exceeds 32. -#if defined(FIX_BUGS) && !defined(SQUEEZE_PERFORMANCE) -#define MAX_COLLISION_POINTS 64 -#else -#define MAX_COLLISION_POINTS 32 -#endif - -struct CompressedVector -{ -#ifdef COMPRESSED_COL_VECTORS - int16 x, y, z; - CVector Get(void) const { return CVector(x, y, z)/128.0f; }; - void Set(float x, float y, float z) { this->x = x*128.0f; this->y = y*128.0f; this->z = z*128.0f; }; -#ifdef GTA_PS2 - void Unpack(uint128 &qword) const { - __asm__ volatile ( - "lh $8, 0(%1)\n" - "lh $9, 2(%1)\n" - "lh $10, 4(%1)\n" - "pextlw $10, $8\n" - "pextlw $2, $9, $10\n" - "sq $2, %0\n" - : "=m" (qword) - : "r" (this) - : "$8", "$9", "$10", "$2" - ); - } -#else - void Unpack(int32 *qword) const { - qword[0] = x; - qword[1] = y; - qword[2] = z; - qword[3] = 0; // junk - } -#endif -#else - float x, y, z; - CVector Get(void) const { return CVector(x, y, z); }; - void Set(float x, float y, float z) { this->x = x; this->y = y; this->z = z; }; -#endif -}; - -struct CColSphere -{ - // NB: this has to be compatible with a CVuVector - CVector center; - float radius; - uint8 surface; - uint8 piece; - - void Set(float radius, const CVector ¢er, uint8 surf, uint8 piece); - void Set(float radius, const CVector ¢er) { this->center = center; this->radius = radius; } -}; - -struct CColBox -{ - CVector min; - CVector max; - uint8 surface; - uint8 piece; - - void Set(const CVector &min, const CVector &max, uint8 surf, uint8 piece); - CVector GetSize(void) { return max - min; } -}; - -struct CColLine -{ - // NB: this has to be compatible with two CVuVectors - CVector p0; - int pad0; - CVector p1; - int pad1; - - CColLine(void) { }; - CColLine(const CVector &p0, const CVector &p1) { this->p0 = p0; this->p1 = p1; }; - void Set(const CVector &p0, const CVector &p1); -}; - -struct CColTriangle -{ - uint16 a; - uint16 b; - uint16 c; - uint8 surface; - - void Set(const CompressedVector *v, int a, int b, int c, uint8 surf, uint8 piece); -}; - -struct CColTrianglePlane -{ -#ifdef VU_COLLISION - CompressedVector normal; - int16 dist; - - void Set(const CVector &va, const CVector &vb, const CVector &vc); - void Set(const CompressedVector *v, CColTriangle &tri) { Set(v[tri.a].Get(), v[tri.b].Get(), v[tri.c].Get()); } - void GetNormal(CVector &n) const { n.x = normal.x/4096.0f; n.y = normal.y/4096.0f; n.z = normal.z/4096.0f; } - float CalcPoint(const CVector &v) const { CVector n; GetNormal(n); return DotProduct(n, v) - dist/128.0f; }; -#ifdef GTA_PS2 - void Unpack(uint128 &qword) const { - __asm__ volatile ( - "lh $8, 0(%1)\n" - "lh $9, 2(%1)\n" - "lh $10, 4(%1)\n" - "lh $11, 6(%1)\n" - "pextlw $10, $8\n" - "pextlw $11, $9\n" - "pextlw $2, $11, $10\n" - "sq $2, %0\n" - : "=m" (qword) - : "r" (this) - : "$8", "$9", "$10", "$11", "$2" - ); - } -#else - void Unpack(int32 *qword) const { - qword[0] = normal.x; - qword[1] = normal.y; - qword[2] = normal.z; - qword[3] = dist; - } -#endif -#else - CVector normal; - float dist; - uint8 dir; - - void Set(const CVector &va, const CVector &vb, const CVector &vc); - void Set(const CompressedVector *v, CColTriangle &tri) { Set(v[tri.a].Get(), v[tri.b].Get(), v[tri.c].Get()); } - void GetNormal(CVector &n) const { n = normal; } - float CalcPoint(const CVector &v) const { return DotProduct(normal, v) - dist; }; -#endif -}; - -struct CColPoint -{ - CVector point; - int pad1; - // the surface normal on the surface of point - CVector normal; - int pad2; - uint8 surfaceA; - uint8 pieceA; - uint8 surfaceB; - uint8 pieceB; - float depth; - - void Set(float depth, uint8 surfA, uint8 pieceA, uint8 surfB, uint8 pieceB) { - this->depth = depth; - this->surfaceA = surfA; - this->pieceA = pieceA; - this->surfaceB = surfB; - this->pieceB = pieceB; - } - void Set(uint8 surfA, uint8 pieceA, uint8 surfB, uint8 pieceB) { - this->surfaceA = surfA; - this->pieceA = pieceA; - this->surfaceB = surfB; - this->pieceB = pieceB; - } -}; - -struct CStoredCollPoly -{ -#ifdef VU_COLLISION - CVuVector verts[3]; -#else - CVector verts[3]; -#endif - bool valid; -}; - -struct CColModel -{ - CColSphere boundingSphere; - CColBox boundingBox; - int16 numSpheres; - int16 numLines; - int16 numBoxes; - int16 numTriangles; - int32 level; - bool ownsCollisionVolumes; // missing on PS2 - CColSphere *spheres; - CColLine *lines; - CColBox *boxes; - CompressedVector *vertices; - CColTriangle *triangles; - CColTrianglePlane *trianglePlanes; - - CColModel(void); - ~CColModel(void); - void RemoveCollisionVolumes(void); - void CalculateTrianglePlanes(void); - void RemoveTrianglePlanes(void); - CLink *GetLinkPtr(void); - void SetLinkPtr(CLink*); - void GetTrianglePoint(CVector &v, int i) const; - - CColModel& operator=(const CColModel& other); -}; - -class CCollision -{ -public: - static eLevelName ms_collisionInMemory; - static CLinkList ms_colModelCache; -#ifdef NO_ISLAND_LOADING - static bool bAlreadyLoaded; -#endif - - static void Init(void); - static void Shutdown(void); - static void Update(void); - static void LoadCollisionWhenINeedIt(bool changeLevel); - static void SortOutCollisionAfterLoad(void); - static void LoadCollisionScreen(eLevelName level); - static void DrawColModel(const CMatrix &mat, const CColModel &colModel); - static void DrawColModel_Coloured(const CMatrix &mat, const CColModel &colModel, int32 id); - - static void CalculateTrianglePlanes(CColModel *model); - - // all these return true if there's a collision - static bool TestSphereSphere(const CColSphere &s1, const CColSphere &s2); - static bool TestSphereBox(const CColSphere &sph, const CColBox &box); - static bool TestLineBox(const CColLine &line, const CColBox &box); - static bool TestVerticalLineBox(const CColLine &line, const CColBox &box); - static bool TestLineTriangle(const CColLine &line, const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane); - static bool TestLineSphere(const CColLine &line, const CColSphere &sph); - static bool TestSphereTriangle(const CColSphere &sphere, const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane); - static bool TestLineOfSight(const CColLine &line, const CMatrix &matrix, CColModel &model, bool ignoreSeeThrough); - - static bool ProcessSphereSphere(const CColSphere &s1, const CColSphere &s2, CColPoint &point, float &mindistsq); - static bool ProcessSphereBox(const CColSphere &sph, const CColBox &box, CColPoint &point, float &mindistsq); - static bool ProcessLineBox(const CColLine &line, const CColBox &box, CColPoint &point, float &mindist); - static bool ProcessVerticalLineTriangle(const CColLine &line, const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, CColPoint &point, float &mindist, CStoredCollPoly *poly); - static bool ProcessLineTriangle(const CColLine &line , const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, CColPoint &point, float &mindist); - static bool ProcessLineSphere(const CColLine &line, const CColSphere &sphere, CColPoint &point, float &mindist); - static bool ProcessSphereTriangle(const CColSphere &sph, const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, CColPoint &point, float &mindistsq); - static bool ProcessLineOfSight(const CColLine &line, const CMatrix &matrix, CColModel &model, CColPoint &point, float &mindist, bool ignoreSeeThrough); - static bool ProcessVerticalLine(const CColLine &line, const CMatrix &matrix, CColModel &model, CColPoint &point, float &mindist, bool ignoreSeeThrough, CStoredCollPoly *poly); - static int32 ProcessColModels(const CMatrix &matrixA, CColModel &modelA, const CMatrix &matrixB, CColModel &modelB, CColPoint *spherepoints, CColPoint *linepoints, float *linedists); - static bool IsStoredPolyStillValidVerticalLine(const CVector &pos, float z, CColPoint &point, CStoredCollPoly *poly); - - static float DistToLine(const CVector *l0, const CVector *l1, const CVector *point); - static float DistToLine(const CVector *l0, const CVector *l1, const CVector *point, CVector &closest); -}; diff --git a/src/core/TempColModels.cpp b/src/core/TempColModels.cpp deleted file mode 100644 index f6796909..00000000 --- a/src/core/TempColModels.cpp +++ /dev/null @@ -1,297 +0,0 @@ -#include "common.h" - -#include "TempColModels.h" -#include "SurfaceTable.h" - -CColModel CTempColModels::ms_colModelPed1; -CColModel CTempColModels::ms_colModelPed2; -CColModel CTempColModels::ms_colModelBBox; -CColModel CTempColModels::ms_colModelBumper1; -CColModel CTempColModels::ms_colModelWheel1; -CColModel CTempColModels::ms_colModelPanel1; -CColModel CTempColModels::ms_colModelBodyPart2; -CColModel CTempColModels::ms_colModelBodyPart1; -CColModel CTempColModels::ms_colModelCutObj[5]; -CColModel CTempColModels::ms_colModelPedGroundHit; -CColModel CTempColModels::ms_colModelBoot1; -CColModel CTempColModels::ms_colModelDoor1; -CColModel CTempColModels::ms_colModelBonnet1; - - -CColSphere s_aPedSpheres[3]; -CColSphere s_aPed2Spheres[3]; -CColSphere s_aPedGSpheres[4]; -#ifdef FIX_BUGS -CColSphere s_aDoorSpheres[3]; -#else -CColSphere s_aDoorSpheres[4]; -#endif -CColSphere s_aBumperSpheres[4]; -CColSphere s_aPanelSpheres[4]; -CColSphere s_aBonnetSpheres[4]; -CColSphere s_aBootSpheres[4]; -CColSphere s_aWheelSpheres[2]; -CColSphere s_aBodyPartSpheres1[2]; -CColSphere s_aBodyPartSpheres2[2]; - -void -CTempColModels::Initialise(void) -{ -#define SET_COLMODEL_SPHERES(colmodel, sphrs)\ - colmodel.numSpheres = ARRAY_SIZE(sphrs);\ - colmodel.spheres = sphrs;\ - colmodel.level = LEVEL_GENERIC;\ - colmodel.ownsCollisionVolumes = false;\ - - int i; - - ms_colModelBBox.boundingSphere.Set(2.0f, CVector(0.0f, 0.0f, 0.0f), SURFACE_DEFAULT, 0); - ms_colModelBBox.boundingBox.Set(CVector(-2.0f, -2.0f, -2.0f), CVector(2.0f, 2.0f, 2.0f), SURFACE_DEFAULT, 0); - ms_colModelBBox.level = LEVEL_GENERIC; - - for (i = 0; i < ARRAY_SIZE(ms_colModelCutObj); i++) { - ms_colModelCutObj[i].boundingSphere.Set(2.0f, CVector(0.0f, 0.0f, 0.0f), SURFACE_DEFAULT, 0); - ms_colModelCutObj[i].boundingBox.Set(CVector(-2.0f, -2.0f, -2.0f), CVector(2.0f, 2.0f, 2.0f), SURFACE_DEFAULT, 0); - ms_colModelCutObj[i].level = LEVEL_GENERIC; - } - - // Ped Spheres - - for (i = 0; i < ARRAY_SIZE(s_aPedSpheres); i++) - s_aPedSpheres[i].radius = 0.35f; - - s_aPedSpheres[0].center = CVector(0.0f, 0.0f, -0.25f); - s_aPedSpheres[1].center = CVector(0.0f, 0.0f, 0.15f); - s_aPedSpheres[2].center = CVector(0.0f, 0.0f, 0.55f); - -#ifdef FIX_BUGS - for (i = 0; i < ARRAY_SIZE(s_aPedSpheres); i++) { -#else - for (i = 0; i < ARRAY_SIZE(s_aPedGSpheres); i++) { -#endif - s_aPedSpheres[i].surface = SURFACE_PED; - s_aPedSpheres[i].piece = 0; - } - - ms_colModelPed1.boundingSphere.Set(1.25f, CVector(0.0f, 0.0f, 0.0f), SURFACE_DEFAULT, 0); - ms_colModelPed1.boundingBox.Set(CVector(-0.35f, -0.35f, -1.0f), CVector(0.35f, 0.35f, 0.9f), SURFACE_DEFAULT, 0); - SET_COLMODEL_SPHERES(ms_colModelPed1, s_aPedSpheres); - - // Ped 2 Spheres - - s_aPed2Spheres[0].radius = 0.3f; - s_aPed2Spheres[1].radius = 0.4f; - s_aPed2Spheres[2].radius = 0.3f; - - s_aPed2Spheres[0].center = CVector(0.0f, 0.35f, -0.9f); - s_aPed2Spheres[1].center = CVector(0.0f, 0.0f, -0.9f); - s_aPed2Spheres[2].center = CVector(0.0f, -0.35f, -0.9f); - - for (i = 0; i < ARRAY_SIZE(s_aPed2Spheres); i++) { - s_aPed2Spheres[i].surface = SURFACE_PED; - s_aPed2Spheres[i].piece = 0; - } - - ms_colModelPed2.boundingSphere.Set(2.0f, CVector(0.0f, 0.0f, 0.0f), SURFACE_DEFAULT, 0); - ms_colModelPed2.boundingBox.Set(CVector(-0.7f, -0.7f, -1.2f), CVector(0.7f, 0.7f, 0.0f), SURFACE_DEFAULT, 0); - - SET_COLMODEL_SPHERES(ms_colModelPed2, s_aPed2Spheres); - - // Ped ground collision - - s_aPedGSpheres[0].radius = 0.35f; - s_aPedGSpheres[1].radius = 0.35f; - s_aPedGSpheres[2].radius = 0.35f; - s_aPedGSpheres[3].radius = 0.3f; - - s_aPedGSpheres[0].center = CVector(0.0f, -0.4f, -0.9f); - s_aPedGSpheres[1].center = CVector(0.0f, -0.1f, -0.9f); - s_aPedGSpheres[2].center = CVector(0.0f, 0.25f, -0.9f); - s_aPedGSpheres[3].center = CVector(0.0f, 0.65f, -0.9f); - - s_aPedGSpheres[0].surface = SURFACE_PED; - s_aPedGSpheres[1].surface = SURFACE_PED; - s_aPedGSpheres[2].surface = SURFACE_PED; - s_aPedGSpheres[3].surface = SURFACE_PED; - s_aPedGSpheres[0].piece = 4; - s_aPedGSpheres[1].piece = 1; - s_aPedGSpheres[2].piece = 0; - s_aPedGSpheres[3].piece = 6; - - ms_colModelPedGroundHit.boundingSphere.Set(2.0f, CVector(0.0f, 0.0f, 0.0f), SURFACE_DEFAULT, 0); - ms_colModelPedGroundHit.boundingBox.Set(CVector(-0.4f, -1.0f, -1.25f), CVector(0.4f, 1.2f, -0.5f), SURFACE_DEFAULT, 0); - - SET_COLMODEL_SPHERES(ms_colModelPedGroundHit, s_aPedGSpheres); - - // Door Spheres - - s_aDoorSpheres[0].radius = 0.15f; - s_aDoorSpheres[1].radius = 0.15f; - s_aDoorSpheres[2].radius = 0.25f; - - s_aDoorSpheres[0].center = CVector(0.0f, -0.25f, -0.35f); - s_aDoorSpheres[1].center = CVector(0.0f, -0.95f, -0.35f); - s_aDoorSpheres[2].center = CVector(0.0f, -0.6f, 0.25f); - -#ifdef FIX_BUGS - for (i = 0; i < ARRAY_SIZE(s_aDoorSpheres); i++) { -#else - for (i = 0; i < ARRAY_SIZE(s_aPed2Spheres); i++) { -#endif - s_aDoorSpheres[i].surface = SURFACE_CAR_PANEL; - s_aDoorSpheres[i].piece = 0; - } - - ms_colModelDoor1.boundingSphere.Set(1.5f, CVector(0.0f, -0.6f, 0.0f), SURFACE_DEFAULT, 0); - ms_colModelDoor1.boundingBox.Set(CVector(-0.3f, 0.0f, -0.6f), CVector(0.3f, -1.2f, 0.6f), SURFACE_DEFAULT, 0); - - SET_COLMODEL_SPHERES(ms_colModelDoor1, s_aDoorSpheres); - - // Bumper Spheres - - for (i = 0; i < ARRAY_SIZE(s_aBumperSpheres); i++) - s_aBumperSpheres[i].radius = 0.15f; - - s_aBumperSpheres[0].center = CVector(0.85f, -0.05f, 0.0f); - s_aBumperSpheres[1].center = CVector(0.4f, 0.05f, 0.0f); - s_aBumperSpheres[2].center = CVector(-0.4f, 0.05f, 0.0f); - s_aBumperSpheres[3].center = CVector(-0.85f, -0.05f, 0.0f); - - for (i = 0; i < ARRAY_SIZE(s_aBumperSpheres); i++) { - s_aBumperSpheres[i].surface = SURFACE_CAR_PANEL; - s_aBumperSpheres[i].piece = 0; - } - - ms_colModelBumper1.boundingSphere.Set(2.2f, CVector(0.0f, -0.6f, 0.0f), SURFACE_DEFAULT, 0); - ms_colModelBumper1.boundingBox.Set(CVector(-1.2f, -0.3f, -0.2f), CVector(1.2f, 0.3f, 0.2f), SURFACE_DEFAULT, 0); - - SET_COLMODEL_SPHERES(ms_colModelBumper1, s_aBumperSpheres); - - // Panel Spheres - - for (i = 0; i < ARRAY_SIZE(s_aPanelSpheres); i++) - s_aPanelSpheres[i].radius = 0.15f; - - s_aPanelSpheres[0].center = CVector(0.15f, 0.45f, 0.0f); - s_aPanelSpheres[1].center = CVector(0.15f, -0.45f, 0.0f); - s_aPanelSpheres[2].center = CVector(-0.15f, -0.45f, 0.0f); - s_aPanelSpheres[3].center = CVector(-0.15f, 0.45f, 0.0f); - - for (i = 0; i < ARRAY_SIZE(s_aPanelSpheres); i++) { - s_aPanelSpheres[i].surface = SURFACE_CAR_PANEL; - s_aPanelSpheres[i].piece = 0; - } - - ms_colModelPanel1.boundingSphere.Set(1.4f, CVector(0.0f, 0.0f, 0.0f), SURFACE_DEFAULT, 0); - ms_colModelPanel1.boundingBox.Set(CVector(-0.3f, -0.6f, -0.15f), CVector(0.3f, 0.6f, 0.15f), SURFACE_DEFAULT, 0); - - SET_COLMODEL_SPHERES(ms_colModelPanel1, s_aPanelSpheres); - - // Bonnet Spheres - - for (i = 0; i < ARRAY_SIZE(s_aBonnetSpheres); i++) - s_aBonnetSpheres[i].radius = 0.2f; - - s_aBonnetSpheres[0].center = CVector(-0.4f, 0.1f, 0.0f); - s_aBonnetSpheres[1].center = CVector(-0.4f, 0.9f, 0.0f); - s_aBonnetSpheres[2].center = CVector(0.4f, 0.1f, 0.0f); - s_aBonnetSpheres[3].center = CVector(0.4f, 0.9f, 0.0f); - - for (i = 0; i < ARRAY_SIZE(s_aBonnetSpheres); i++) { - s_aBonnetSpheres[i].surface = SURFACE_CAR_PANEL; - s_aBonnetSpheres[i].piece = 0; - } - - ms_colModelBonnet1.boundingSphere.Set(1.7f, CVector(0.0f, 0.5f, 0.0f), SURFACE_DEFAULT, 0); - ms_colModelBonnet1.boundingBox.Set(CVector(-0.7f, -0.2f, -0.3f), CVector(0.7f, 1.2f, 0.3f), SURFACE_DEFAULT, 0); - - SET_COLMODEL_SPHERES(ms_colModelBonnet1, s_aBonnetSpheres); - - // Boot Spheres - - for (i = 0; i < ARRAY_SIZE(s_aBootSpheres); i++) - s_aBootSpheres[i].radius = 0.2f; - - s_aBootSpheres[0].center = CVector(-0.4f, -0.1f, 0.0f); - s_aBootSpheres[1].center = CVector(-0.4f, -0.6f, 0.0f); - s_aBootSpheres[2].center = CVector(0.4f, -0.1f, 0.0f); - s_aBootSpheres[3].center = CVector(0.4f, -0.6f, 0.0f); - - for (i = 0; i < ARRAY_SIZE(s_aBootSpheres); i++) { - s_aBootSpheres[i].surface = SURFACE_CAR_PANEL; - s_aBootSpheres[i].piece = 0; - } - - ms_colModelBoot1.boundingSphere.Set(1.4f, CVector(0.0f, -0.4f, 0.0f), SURFACE_DEFAULT, 0); - ms_colModelBoot1.boundingBox.Set(CVector(-0.7f, -0.9f, -0.3f), CVector(0.7f, 0.2f, 0.3f), SURFACE_DEFAULT, 0); - - SET_COLMODEL_SPHERES(ms_colModelBoot1, s_aBootSpheres); - - // Wheel Spheres - - s_aWheelSpheres[0].radius = 0.35f; - s_aWheelSpheres[1].radius = 0.35f; - - s_aWheelSpheres[0].center = CVector(-0.3f, 0.0f, 0.0f); - s_aWheelSpheres[1].center = CVector(0.3f, 0.0f, 0.0f); - -#ifdef FIX_BUGS - for (i = 0; i < ARRAY_SIZE(s_aWheelSpheres); i++) { -#else - for (i = 0; i < ARRAY_SIZE(s_aBootSpheres); i++) { -#endif - s_aWheelSpheres[i].surface = SURFACE_WHEELBASE; - s_aWheelSpheres[i].piece = 0; - } - - ms_colModelWheel1.boundingSphere.Set(1.4f, CVector(0.0f, 0.0f, 0.0f), SURFACE_DEFAULT, 0); - ms_colModelWheel1.boundingBox.Set(CVector(-0.7f, -0.4f, -0.4f), CVector(0.7f, 0.4f, 0.4f), SURFACE_DEFAULT, 0); - - SET_COLMODEL_SPHERES(ms_colModelWheel1, s_aWheelSpheres); - - // Body Part Spheres 1 - - s_aBodyPartSpheres1[0].radius = 0.2f; - s_aBodyPartSpheres1[1].radius = 0.2f; - - s_aBodyPartSpheres1[0].center = CVector(0.0f, 0.0f, 0.0f); - s_aBodyPartSpheres1[1].center = CVector(0.8f, 0.0f, 0.0f); - -#ifdef FIX_BUGS - for (i = 0; i < ARRAY_SIZE(s_aBodyPartSpheres1); i++) { -#else - for (i = 0; i < ARRAY_SIZE(s_aBootSpheres); i++) { -#endif - s_aBodyPartSpheres1[i].surface = SURFACE_PED; - s_aBodyPartSpheres1[i].piece = 0; - } - - ms_colModelBodyPart1.boundingSphere.Set(0.7f, CVector(0.4f, 0.0f, 0.0f), SURFACE_DEFAULT, 0); - ms_colModelBodyPart1.boundingBox.Set(CVector(-0.3f, -0.3f, -0.3f), CVector(1.1f, 0.3f, 0.3f), SURFACE_DEFAULT, 0); - - SET_COLMODEL_SPHERES(ms_colModelBodyPart1, s_aBodyPartSpheres1); - - // Body Part Spheres 2 - - s_aBodyPartSpheres2[0].radius = 0.15f; - s_aBodyPartSpheres2[1].radius = 0.15f; - - s_aBodyPartSpheres2[0].center = CVector(0.0f, 0.0f, 0.0f); - s_aBodyPartSpheres2[1].center = CVector(0.5f, 0.0f, 0.0f); - -#ifdef FIX_BUGS - for (i = 0; i < ARRAY_SIZE(s_aBodyPartSpheres2); i++) { -#else - for (i = 0; i < ARRAY_SIZE(s_aBootSpheres); i++) { -#endif - s_aBodyPartSpheres2[i].surface = SURFACE_PED; - s_aBodyPartSpheres2[i].piece = 0; - } - - ms_colModelBodyPart2.boundingSphere.Set(0.5f, CVector(0.25f, 0.0f, 0.0f), SURFACE_DEFAULT, 0); - ms_colModelBodyPart2.boundingBox.Set(CVector(-0.2f, -0.2f, -0.2f), CVector(0.7f, 0.2f, 0.2f), SURFACE_DEFAULT, 0); - - SET_COLMODEL_SPHERES(ms_colModelBodyPart2, s_aBodyPartSpheres2); - -#undef SET_COLMODEL_SPHERES -} diff --git a/src/core/TempColModels.h b/src/core/TempColModels.h deleted file mode 100644 index 3e1dd5e1..00000000 --- a/src/core/TempColModels.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include "Collision.h" - -class CTempColModels -{ -public: - static CColModel ms_colModelPed1; - static CColModel ms_colModelPed2; - static CColModel ms_colModelBBox; - static CColModel ms_colModelBumper1; - static CColModel ms_colModelWheel1; - static CColModel ms_colModelPanel1; - static CColModel ms_colModelBodyPart2; - static CColModel ms_colModelBodyPart1; - static CColModel ms_colModelCutObj[5]; - static CColModel ms_colModelPedGroundHit; - static CColModel ms_colModelBoot1; - static CColModel ms_colModelDoor1; - static CColModel ms_colModelBonnet1; - - static void Initialise(void); -}; diff --git a/src/core/vu0Collision.dsm b/src/core/vu0Collision.dsm deleted file mode 100644 index 657c8b81..00000000 --- a/src/core/vu0Collision.dsm +++ /dev/null @@ -1,21 +0,0 @@ -.align 4 -.global Vu0CollisionDmaTag -Vu0CollisionDmaTag: -DMAcnt * -MPG 0, * -.vu -.include "vu0Collision_1.s" -.EndMPG -.EndDmaData -DMAend - -.global Vu0Collision2DmaTag -Vu0Collision2DmaTag: -DMAcnt * -MPG 0, * -.vu -.include "vu0Collision_2.s" -.EndMPG -.EndDmaData -DMAend -.end diff --git a/src/core/vu0Collision_1.s b/src/core/vu0Collision_1.s deleted file mode 100644 index 055c8640..00000000 --- a/src/core/vu0Collision_1.s +++ /dev/null @@ -1,610 +0,0 @@ -QuitAndFail: - NOP[E] IADDIU VI01, VI00, 0 - NOP NOP - - -QuitAndSucceed: - NOP[E] IADDIU VI01, VI00, 1 - NOP NOP - - -; 20 -- unused -; VF12, VF13 xyz: sphere centers -; VF14, VF15 x: sphere radii -; out: -; VI01: set when collision -; VF01: supposed to be intersection point? -; VF02: normal (pointing towards s1, not normalized) -.globl Vu0SphereToSphereCollision -Vu0SphereToSphereCollision: - SUB.xyz VF02, VF13, VF12 NOP ; dist of centers - ADD.x VF04, VF14, VF15 NOP ; s = sum of radii - MUL.xyzw VF03, VF02, VF02 NOP ; - MUL.x VF04, VF04, VF04 DIV Q, VF14x, VF04x ; square s - NOP NOP ; - NOP NOP ; - MULAx.w ACC, VF00, VF03 NOP ; - MADDAy.w ACC, VF00, VF03 NOP ; - MADDz.w VF03, VF00, VF03 NOP ; d = DistSq of centers - NOP NOP ; - MULAw.xyz ACC, VF12, VF00 NOP ; - MADDq.xyz VF01, VF02, Q NOP ; intersection, but wrong - CLIPw.xyz VF04, VF03 NOP ; compare s and d - SUB.xyz VF02, VF00, VF02 NOP ; compute normal - NOP NOP ; - NOP NOP ; - NOP FCAND VI01, 0x3 ; 0x2 cannot be set here - NOP[E] NOP ; - NOP NOP ; - - -; B8 -- unused -; VF12: -; VF13: radius -; VF14: -; VF15: box dimensions (?) -.globl Vu0SphereToAABBCollision -Vu0SphereToAABBCollision: - SUB.xyz VF03, VF12, VF14 LOI 0.5 - MULi.xyz VF15, VF15, I NOP - MUL.x VF13, VF13, VF13 NOP - SUB.xyz VF04, VF03, VF15 NOP - ADD.xyz VF05, VF03, VF15 MR32.xyzw VF16, VF15 - CLIPw.xyz VF03, VF16 MR32.xyzw VF17, VF16 - MUL.xyz VF04, VF04, VF04 NOP - MUL.xyz VF05, VF05, VF05 NOP - CLIPw.xyz VF03, VF17 MR32.xyzw VF16, VF17 - NOP FCAND VI01, 0x1 - MINI.xyz VF04, VF04, VF05 MFIR.x VF09, VI01 - NOP NOP - CLIPw.xyz VF03, VF16 FCAND VI01, 0x4 - NOP MFIR.y VF09, VI01 - NOP NOP - MULAx.w ACC, VF00, VF00 NOP - ADD.xyz VF01, VF00, VF03 FCAND VI01, 0x10 - NOP MFIR.z VF09, VI01 - NOP LOI 2 - NOP FCAND VI01, 0x30 - SUBAw.xyz ACC, VF00, VF00 IADD VI04, VI00, VI01 - ITOF0.xyz VF09, VF09 FCAND VI01, 0x300 - NOP IADD VI03, VI00, VI01 - NOP FCAND VI01, 0x3000 - NOP IADD VI02, VI00, VI01 - MADDi.xyzw VF09, VF09, I NOP - NOP IBEQ VI04, VI00, IgnoreZValue - NOP NOP - MADDAz.w ACC, VF00, VF04 NOP - MUL.z VF01, VF09, VF15 NOP -IgnoreZValue: - NOP IBEQ VI03, VI00, IgnoreYValue - NOP NOP - MADDAy.w ACC, VF00, VF04 NOP - MUL.y VF01, VF09, VF15 NOP -IgnoreYValue: - NOP IBEQ VI02, VI00, IgnoreXValue - NOP NOP - MADDAx.w ACC, VF00, VF04 NOP - MUL.x VF01, VF09, VF15 NOP -IgnoreXValue: - MADDx.w VF06, VF00, VF00 NOP - SUB.xyz VF02, VF03, VF01 NOP - ADD.xyz VF01, VF01, VF14 NOP - MULx.w VF01, VF00, VF00 NOP - CLIPw.xyz VF13, VF06 NOP - NOP NOP - NOP NOP - NOP NOP - NOP FCAND VI01, 0x1 -QuitMicrocode: - NOP[E] NOP - NOP NOP - - -; 240 -.globl Vu0LineToSphereCollision -Vu0LineToSphereCollision: - SUB.xyzw VF01, VF13, VF12 NOP - SUB.xyzw VF02, VF14, VF12 NOP - MUL.xyz VF03, VF01, VF02 NOP - MUL.xyz VF04, VF01, VF01 NOP - MUL.x VF15, VF15, VF15 NOP - MUL.xyz VF02, VF02, VF02 NOP - MULAx.w ACC, VF00, VF03 NOP - MADDAy.w ACC, VF00, VF03 NOP - MADDz.w VF03, VF00, VF03 NOP - MULAx.w ACC, VF00, VF04 NOP - MADDAy.w ACC, VF00, VF04 NOP - MADDz.w VF01, VF00, VF04 NOP - MULAx.w ACC, VF00, VF02 NOP - MADDAy.w ACC, VF00, VF02 NOP - MADDz.w VF02, VF00, VF02 NOP - MULA.w ACC, VF03, VF03 NOP - MADDAx.w ACC, VF01, VF15 NOP - MSUB.w VF05, VF01, VF02 NOP - NOP NOP - NOP NOP - NOP IADDIU VI02, VI00, 0x10 - NOP FMAND VI01, VI02 - NOP IBNE VI01, VI00, QuitAndFail - NOP NOP - CLIPw.xyz VF15, VF02 SQRT Q, VF05w - NOP NOP - NOP NOP - NOP NOP - NOP FCAND VI01, 0x1 - NOP IBNE VI00, VI01, LineStartInsideSphere - NOP NOP - SUBq.w VF05, VF03, Q NOP - SUB.w VF05, VF05, VF01 DIV Q, VF05w, VF01w - NOP FMAND VI01, VI02 - NOP IBNE VI01, VI00, QuitAndFail - NOP NOP - NOP FMAND VI01, VI02 - NOP IBEQ VI01, VI00, QuitAndFail - NOP NOP - ADDA.xyz ACC, VF12, VF00 NOP - MADDq.xyz VF01, VF01, Q NOP - MULx.w VF01, VF00, VF00 NOP - SUB.xyz VF02, VF01, VF14 NOP - NOP[E] NOP - NOP NOP -LineStartInsideSphere: - NOP MOVE.xyzw VF01, VF12 - NOP[E] IADDIU VI01, VI00, 0x1 - NOP NOP - - -; 3C0 -.globl Vu0LineToAABBCollision -Vu0LineToAABBCollision: - SUB.xyzw VF08, VF13, VF12 LOI 0.5 - MULi.xyz VF15, VF15, I IADDIU VI08, VI00, 0x0 - SUB.xyzw VF12, VF12, VF14 NOP - SUB.xyzw VF13, VF13, VF14 NOP - NOP DIV Q, VF00w, VF08x - NOP MR32.xyzw VF03, VF15 - SUB.xyz VF06, VF15, VF12 NOP - ADD.xyz VF07, VF15, VF12 NOP - NOP NOP - CLIPw.xyz VF12, VF03 MR32.xyzw VF04, VF03 - NOP NOP - ADDq.x VF09, VF00, Q DIV Q, VF00w, VF08y - NOP NOP - CLIPw.xyz VF12, VF04 MR32.xyzw VF05, VF04 - SUB.xyz VF07, VF00, VF07 IADDIU VI06, VI00, 0xCC - NOP IADDIU VI07, VI00, 0x30 - NOP NOP - CLIPw.xyz VF12, VF05 FCGET VI02 - NOP IAND VI02, VI02, VI06 - ADDq.y VF09, VF00, Q DIV Q, VF00w, VF08z - SUB.xyz VF10, VF00, VF10 NOP - CLIPw.xyz VF13, VF03 FCGET VI03 - CLIPw.xyz VF13, VF04 IAND VI03, VI03, VI07 - CLIPw.xyz VF13, VF05 FCAND VI01, 0x3330 - NOP IBEQ VI01, VI00, StartPointInsideAABB - NOP NOP - ADDq.z VF09, VF00, Q FCGET VI04 - NOP FCGET VI05 - NOP IAND VI04, VI04, VI06 - NOP IAND VI05, VI05, VI07 - MULx.xyz VF17, VF08, VF09 NOP - MULy.xyz VF18, VF08, VF09 IADDIU VI07, VI00, 0x80 - MULz.xyz VF19, VF08, VF09 IAND VI06, VI02, VI07 - MUL.w VF10, VF00, VF00 IAND VI07, VI04, VI07 - NOP NOP - NOP IBEQ VI06, VI07, CheckMaxXSide - NOP NOP - MULAx.xyz ACC, VF17, VF07 NOP - MADDw.xyz VF16, VF12, VF00 NOP - MUL.x VF10, VF07, VF09 NOP - CLIPw.xyz VF16, VF04 NOP - CLIPw.xyz VF16, VF05 NOP - NOP NOP - NOP NOP - NOP NOP - NOP FCAND VI01, 0x330 - NOP IBNE VI01, VI00, CheckMaxXSide - NOP NOP - MULx.w VF10, VF00, VF10 IADDIU VI08, VI00, 0x1 - ADD.yz VF02, VF00, VF00 MOVE.xyzw VF01, VF16 - SUBw.x VF02, VF00, VF00 NOP -CheckMaxXSide: - MULAx.xyz ACC, VF17, VF06 IADDIU VI07, VI00, 0x40 - MADDw.xyz VF16, VF12, VF00 IAND VI06, VI02, VI07 - MUL.x VF10, VF06, VF09 IAND VI07, VI04, VI07 - NOP NOP - NOP IBEQ VI06, VI07, CheckMinYSide - NOP NOP - CLIPw.xyz VF16, VF04 NOP - CLIPw.xyz VF16, VF05 NOP - CLIPw.xyz VF10, VF10 NOP - NOP NOP - NOP NOP - NOP NOP - NOP FCAND VI01, 0xCC03 - NOP IBNE VI01, VI00, CheckMinYSide - NOP NOP - MULx.w VF10, VF00, VF10 IADDIU VI08, VI00, 0x1 - ADD.yz VF02, VF00, VF00 MOVE.xyzw VF01, VF16 - ADDw.x VF02, VF00, VF00 NOP -CheckMinYSide: - MULAy.xyz ACC, VF18, VF07 IADDIU VI07, VI00, 0x8 - MADDw.xyz VF16, VF12, VF00 IAND VI06, VI02, VI07 - MUL.y VF10, VF07, VF09 IAND VI07, VI04, VI07 - NOP NOP - NOP IBEQ VI06, VI07, CheckMaxYSide - NOP NOP - CLIPw.xyz VF16, VF03 NOP - CLIPw.xyz VF16, VF05 NOP - CLIPw.xyz VF10, VF10 NOP - NOP NOP - NOP NOP - NOP NOP - NOP FCAND VI01, 0x3C0C - NOP IBNE VI01, VI00, CheckMaxYSide - NOP NOP - MULy.w VF10, VF00, VF10 IADDIU VI08, VI00, 0x1 - ADD.xz VF02, VF00, VF00 MOVE.xyzw VF01, VF16 - SUBw.y VF02, VF00, VF00 NOP -CheckMaxYSide: - MULAy.xyz ACC, VF18, VF06 IADDIU VI07, VI00, 0x4 - MADDw.xyz VF16, VF12, VF00 IAND VI06, VI02, VI07 - MUL.y VF10, VF06, VF09 IAND VI07, VI04, VI07 - NOP NOP - NOP IBEQ VI06, VI07, CheckMinZSide - NOP NOP - CLIPw.xyz VF16, VF03 NOP - CLIPw.xyz VF16, VF05 NOP - CLIPw.xyz VF10, VF10 NOP - NOP NOP - NOP NOP - NOP NOP - NOP FCAND VI01, 0x3C0C - NOP IBNE VI01, VI00, CheckMinZSide - NOP NOP - MULy.w VF10, VF00, VF10 IADDIU VI08, VI00, 0x1 - ADD.xz VF02, VF00, VF00 MOVE.xyzw VF01, VF16 - ADDw.y VF02, VF00, VF00 NOP -CheckMinZSide: - MULAz.xyz ACC, VF19, VF07 IADDIU VI07, VI00, 0x20 - MADDw.xyz VF16, VF12, VF00 IAND VI06, VI03, VI07 - MUL.z VF10, VF07, VF09 IAND VI07, VI05, VI07 - NOP NOP - NOP IBEQ VI06, VI07, CheckMaxZSide - NOP NOP - CLIPw.xyz VF16, VF03 NOP - CLIPw.xyz VF16, VF04 NOP - CLIPw.xyz VF10, VF10 NOP - NOP NOP - NOP NOP - NOP NOP - NOP FCAND VI01, 0x3330 - NOP IBNE VI01, VI00, CheckMaxZSide - NOP NOP - MULz.w VF10, VF00, VF10 IADDIU VI08, VI00, 0x1 - ADD.xy VF02, VF00, VF00 MOVE.xyzw VF01, VF16 - SUBw.z VF02, VF00, VF00 NOP -CheckMaxZSide: - MULAz.xyz ACC, VF19, VF06 IADDIU VI07, VI00, 0x10 - MADDw.xyz VF16, VF12, VF00 IAND VI06, VI03, VI07 - MUL.z VF10, VF06, VF09 IAND VI07, VI05, VI07 - NOP NOP - NOP IBEQ VI06, VI07, DoneAllChecks - NOP NOP - CLIPw.xyz VF16, VF03 NOP - CLIPw.xyz VF16, VF04 NOP - CLIPw.xyz VF10, VF10 NOP - NOP NOP - NOP NOP - NOP NOP - NOP FCAND VI01, 0x3330 - NOP IBNE VI01, VI00, DoneAllChecks - NOP NOP - MULz.w VF10, VF00, VF10 IADDIU VI08, VI00, 0x1 - ADD.xy VF02, VF00, VF00 MOVE.xyzw VF01, VF16 - ADDw.z VF02, VF00, VF00 NOP -DoneAllChecks: - ADD.xyz VF01, VF01, VF14 IADD VI01, VI00, VI08 - NOP[E] NOP - NOP NOP -StartPointInsideAABB: - ADD.xyz VF01, VF12, VF14 WAITQ - NOP IADDIU VI01, VI00, 0x1 - NOP[E] NOP - NOP NOP - - -; 860 -.globl Vu0LineToTriangleCollisionCompressedStart -Vu0LineToTriangleCollisionCompressedStart: - ITOF0.xyzw VF17, VF17 LOI 0.000244140625 ; 1.0/4096.0 - ITOF0.xyzw VF14, VF14 NOP - ITOF0.xyzw VF15, VF15 NOP - ITOF0.xyzw VF16, VF16 NOP - MULi.xyz VF17, VF17, I LOI 0.0078125 ; 1.0/128.0 - MULi.w VF17, VF17, I NOP - MULi.xyzw VF14, VF14, I NOP - MULi.xyzw VF15, VF15, I NOP - MULi.xyzw VF16, VF16, I NOP -; fall through - -; 8A8 -; VF12: point0 -; VF13: point1 -; VF14-16: verts -; VF17: plane -; out: -; VF01: intersection point -; VF02: triangle normal -; VF03 x: intersection parameter -.globl Vu0LineToTriangleCollisionStart -Vu0LineToTriangleCollisionStart: - MUL.xyz VF10, VF17, VF12 LOI 0.5 - MUL.xyz VF11, VF17, VF13 NOP - SUB.xyz VF02, VF13, VF12 NOP ; line dist - ADD.xyz VF17, VF17, VF00 NOP - MULi.w VF03, VF00, I NOP - MULAx.w ACC, VF00, VF10 NOP - MADDAy.w ACC, VF00, VF10 IADDIU VI06, VI00, 0xE0 - MADDz.w VF10, VF00, VF10 FMAND VI05, VI06 ; -- normal sign flags, unused - MULAx.w ACC, VF00, VF11 NOP - MADDAy.w ACC, VF00, VF11 NOP - MADDz.w VF11, VF00, VF11 NOP - SUB.w VF09, VF17, VF10 NOP ; plane-pos 0 - CLIPw.xyz VF17, VF03 NOP ; compare normal against 0.5 to figure out which in which dimension to compare - NOP IADDIU VI02, VI00, 0x10 ; Sw flag - SUBA.w ACC, VF17, VF11 NOP ; plane-pos 1 - SUB.w VF08, VF11, VF10 FMAND VI01, VI02 - NOP NOP - NOP NOP - NOP FMAND VI02, VI02 - NOP IBEQ VI01, VI02, QuitAndFail ; if on same side, no collision - NOP NOP - NOP DIV Q, VF09w, VF08w ; parameter of intersection - NOP FCAND VI01, 0x3 ; check x direction - NOP IADDIU VI02, VI01, 0x7F - NOP IADDIU VI06, VI00, 0x80 - NOP IAND VI02, VI02, VI06 ; Sx flag - NOP FCAND VI01, 0xC ; check y direction - NOP IADDIU VI03, VI01, 0x3F - MULAw.xyz ACC, VF12, VF00 IADDIU VI06, VI00, 0x40 - MADDq.xyz VF01, VF02, Q IAND VI03, VI03, VI06 ; point of intersection -- Sy flag - MULx.w VF01, VF00, VF00 FCAND VI01, 0x30 ; -- check z direction - ADDq.x VF03, VF00, Q IADDIU VI04, VI01, 0x1F ; output parameter - SUB.xyz VF05, VF15, VF14 IADDIU VI06, VI00, 0x20 ; edge vectors - SUB.xyz VF08, VF01, VF14 IAND VI04, VI04, VI06 ; edge vectors -- Sz flag - SUB.xyz VF06, VF16, VF15 IADD VI06, VI02, VI03 ; edge vectors - SUB.xyz VF09, VF01, VF15 IADD VI06, VI06, VI04 ; edge vectors -- combine flags - SUB.xyz VF07, VF14, VF16 NOP ; edge vectors - SUB.xyz VF10, VF01, VF16 NOP ; edge vectors - OPMULA.xyz ACC, VF08, VF05 NOP - OPMSUB.xyz VF18, VF05, VF08 NOP ; cross1 - OPMULA.xyz ACC, VF09, VF06 NOP - OPMSUB.xyz VF19, VF06, VF09 NOP ; cross2 - OPMULA.xyz ACC, VF10, VF07 NOP - OPMSUB.xyz VF20, VF07, VF10 FMAND VI02, VI06 ; cross3 - NOP NOP - NOP FMAND VI03, VI06 - NOP NOP - NOP FMAND VI04, VI06 - NOP NOP - NOP IBNE VI03, VI02, QuitAndFail ; point has to lie on the same side of all edges (i.e. inside) - NOP NOP - NOP IBNE VI04, VI02, QuitAndFail - NOP NOP - MULw.xyz VF02, VF17, VF00 IADDIU VI01, VI00, 0x1 ; success - NOP[E] NOP - NOP NOP - - -; A68 -; VF12: center -; VF14: line origin -; VF15: line vector to other point -; out: VF16 xyz: nearest point on line; w: distance to that point -DistanceBetweenSphereAndLine: - SUB.xyz VF20, VF12, VF14 NOP - MUL.xyz VF21, VF15, VF15 NOP - ADDA.xyz ACC, VF14, VF15 NOP - MSUBw.xyz VF25, VF12, VF00 NOP ; VF25 = VF12 - (VF14+VF15) - MUL.xyz VF22, VF20, VF20 NOP - MUL.xyz VF23, VF20, VF15 NOP - MULAx.w ACC, VF00, VF21 NOP - MADDAy.w ACC, VF00, VF21 NOP - MADDz.w VF21, VF00, VF21 NOP ; MagSq VF15 (line length) - MULAx.w ACC, VF00, VF23 NOP - MADDAy.w ACC, VF00, VF23 NOP - MADDz.w VF23, VF00, VF23 NOP ; dot(VF12-VF14, VF15) - MULAx.w ACC, VF00, VF22 NOP - MADDAy.w ACC, VF00, VF22 NOP - MADDz.w VF22, VF00, VF22 IADDIU VI08, VI00, 0x10 ; MagSq VF12-VF14 -- Sw bit - MUL.xyz VF25, VF25, VF25 FMAND VI08, VI08 - NOP DIV Q, VF23w, VF21w - NOP IBNE VI00, VI08, NegativeRatio - NOP NOP - ADDA.xyz ACC, VF00, VF14 NOP - MADDq.xyz VF16, VF15, Q WAITQ ; nearest point on infinte line - ADDq.x VF24, VF00, Q NOP ; ratio - NOP NOP - NOP NOP - SUB.xyz VF26, VF16, VF12 NOP - CLIPw.xyz VF24, VF00 NOP ; compare ratio to 1.0 - NOP NOP - NOP NOP - MUL.xyz VF26, VF26, VF26 NOP - NOP FCAND VI01, 0x1 - NOP IBNE VI00, VI01, RatioGreaterThanOne - NOP NOP - MULAx.w ACC, VF00, VF26 NOP - MADDAy.w ACC, VF00, VF26 NOP - MADDz.w VF16, VF00, VF26 NOP ; distance - NOP JR VI15 - NOP NOP -NegativeRatio: - ADD.xyz VF16, VF00, VF14 NOP ; return line origin - MUL.w VF16, VF00, VF22 NOP ; and DistSq to it - NOP JR VI15 - NOP NOP -RatioGreaterThanOne: - MULAx.w ACC, VF00, VF25 NOP - MADDAy.w ACC, VF00, VF25 NOP - MADDz.w VF16, VF00, VF25 NOP - ADD.xyz VF16, VF14, VF15 NOP ; return toerh line point - NOP JR VI15 - NOP NOP - - -; BE0 -.globl Vu0SphereToTriangleCollisionCompressedStart -Vu0SphereToTriangleCollisionCompressedStart: - ITOF0.xyzw VF17, VF17 LOI 0.000244140625 ; 1.0/4096.0 - ITOF0.xyzw VF14, VF14 NOP - ITOF0.xyzw VF15, VF15 NOP - ITOF0.xyzw VF16, VF16 NOP - MULi.xyz VF17, VF17, I LOI 0.0078125 ; 1.0/128.0 - MULi.w VF17, VF17, I NOP - MULi.xyzw VF14, VF14, I NOP - MULi.xyzw VF15, VF15, I NOP - MULi.xyzw VF16, VF16, I NOP -; fall through - -; C28 -; VF12: sphere -; VF14-16: verts -; VF17: plane -; out: -; VF01: intersection point -; VF02: triangle normal -; VF03 x: intersection parameter -.globl Vu0SphereToTriangleCollisionStart -Vu0SphereToTriangleCollisionStart: - MUL.xyz VF02, VF12, VF17 LOI 0.1 - ADD.xyz VF17, VF17, VF00 NOP - ADDw.x VF13, VF00, VF12 NOP - NOP NOP - MULAx.w ACC, VF00, VF02 IADDIU VI06, VI00, 0xE0 - MADDAy.w ACC, VF00, VF02 FMAND VI05, VI06 ; normal sign flags - MADDAz.w ACC, VF00, VF02 NOP - MSUB.w VF02, VF00, VF17 NOP ; center plane pos - MULi.w VF03, VF00, I MOVE.xyzw VF04, VF03 - NOP NOP - NOP NOP - CLIPw.xyz VF13, VF02 NOP ; compare dist and radius - CLIPw.xyz VF17, VF03 NOP - MULAw.xyz ACC, VF12, VF00 IADDIU VI07, VI00, 0x0 ; -- clear test case - MSUBw.xyz VF01, VF17, VF02 NOP - MULx.w VF01, VF00, VF00 FCAND VI01, 0x3 ; projected center on plane - ABS.w VF02, VF02 IBEQ VI00, VI01, QuitAndFail ; no intersection - NOP NOP - NOP FCAND VI01, 0x3 ; -- check x direction - SUB.xyz VF02, VF12, VF01 IADDIU VI02, VI01, 0x7F - NOP IADDIU VI06, VI00, 0x80 - SUB.xyz VF05, VF15, VF14 IAND VI02, VI02, VI06 - SUB.xyz VF08, VF01, VF14 FCAND VI01, 0xC ; -- check y direction - SUB.xyz VF06, VF16, VF15 IADDIU VI03, VI01, 0x3F - SUB.xyz VF09, VF01, VF15 IADDIU VI06, VI00, 0x40 - SUB.xyz VF07, VF14, VF16 IAND VI03, VI03, VI06 - SUB.xyz VF10, VF01, VF16 FCAND VI01, 0x30 ; -- check z direction - MUL.xyz VF03, VF02, VF02 IADDIU VI04, VI01, 0x1F - OPMULA.xyz ACC, VF08, VF05 IADDIU VI06, VI00, 0x20 - OPMSUB.xyz VF18, VF05, VF08 IAND VI04, VI04, VI06 - OPMULA.xyz ACC, VF09, VF06 NOP - OPMSUB.xyz VF19, VF06, VF09 IADD VI06, VI02, VI03 - OPMULA.xyz ACC, VF10, VF07 IADD VI06, VI06, VI04 ; -- combine flags - OPMSUB.xyz VF20, VF07, VF10 FMAND VI02, VI06 ; -- cross 1 flags - MULAx.w ACC, VF00, VF03 IAND VI05, VI05, VI06 - MADDAy.w ACC, VF00, VF03 FMAND VI03, VI06 ; -- cross 2 flags - MADDz.w VF03, VF00, VF03 IADDIU VI08, VI00, 0x3 - NOP FMAND VI04, VI06 ; -- cross 3 flags - NOP NOP - NOP IBNE VI02, VI05, CheckSide2 - NOP RSQRT Q, VF00w, VF03w - ADD.xyz VF04, VF00, VF16 IADDIU VI07, VI07, 0x1 ; inside side 1 -CheckSide2: - NOP IBNE VI03, VI05, CheckSide3 - NOP NOP - ADD.xyz VF04, VF00, VF14 IADDIU VI07, VI07, 0x1 ; inside side 2 -CheckSide3: - NOP IBNE VI04, VI05, FinishCheckingSides - NOP NOP - ADD.xyz VF04, VF00, VF15 IADDIU VI07, VI07, 0x1 ; inside side 3 - NOP NOP - NOP IBEQ VI07, VI08, TotallyInsideTriangle - NOP NOP -FinishCheckingSides: - MUL.x VF13, VF13, VF13 IADDIU VI08, VI00, 0x2 - MULq.xyz VF02, VF02, Q WAITQ - NOP IBNE VI07, VI08, IntersectionOutsideTwoSides - NOP NOP - NOP IBEQ VI02, VI05, CheckDistanceSide2 - NOP NOP - NOP MOVE.xyzw VF15, VF05 - NOP BAL VI15, DistanceBetweenSphereAndLine - NOP NOP - NOP B ProcessLineResult - NOP NOP -CheckDistanceSide2: - NOP IBEQ VI03, VI05, CheckDistanceSide3 - NOP NOP - NOP MOVE.xyzw VF14, VF15 - NOP MOVE.xyzw VF15, VF06 - NOP BAL VI15, DistanceBetweenSphereAndLine - NOP NOP - NOP B ProcessLineResult - NOP NOP -CheckDistanceSide3: - NOP MOVE.xyzw VF14, VF16 - NOP MOVE.xyzw VF15, VF07 - NOP BAL VI15, DistanceBetweenSphereAndLine - NOP NOP - NOP B ProcessLineResult - NOP NOP -IntersectionOutsideTwoSides: - SUB.xyz VF05, VF04, VF12 NOP - ADD.xyz VF01, VF00, VF04 NOP ; col point - SUB.xyz VF02, VF12, VF04 NOP - NOP NOP - MUL.xyz VF05, VF05, VF05 NOP - NOP NOP - NOP NOP - NOP NOP - MULAx.w ACC, VF00, VF05 NOP - MADDAy.w ACC, VF00, VF05 NOP - MADDz.w VF05, VF00, VF05 NOP ; distSq to vertex - NOP NOP - NOP NOP - NOP NOP - CLIPw.xyz VF13, VF05 SQRT Q, VF05w ; compare radiusSq and distSq - NOP NOP - NOP NOP - NOP NOP - NOP FCAND VI01, 0x1 - ADDq.x VF03, VF00, Q WAITQ ; dist to vertex - NOP IBEQ VI00, VI01, QuitAndFail ; too far - NOP NOP - NOP NOP - NOP DIV Q, VF00w, VF03x - MULq.xyz VF02, VF02, Q WAITQ ; col normal - NOP[E] NOP - NOP NOP -TotallyInsideTriangle: - ADDw.x VF03, VF00, VF02 WAITQ - MULq.xyz VF02, VF02, Q NOP - NOP[E] IADDIU VI01, VI00, 0x1 - NOP NOP -ProcessLineResult: - CLIPw.xyz VF13, VF16 SQRT Q, VF16w - ADD.xyz VF01, VF00, VF16 NOP - SUB.xyz VF02, VF12, VF16 NOP - NOP NOP - NOP FCAND VI01, 0x1 - ADDq.x VF03, VF00, Q WAITQ - NOP IBEQ VI00, VI01, QuitAndFail - NOP NOP - NOP NOP - NOP DIV Q, VF00w, VF03x - MULq.xyz VF02, VF02, Q WAITQ - NOP[E] NOP - NOP NOP - -EndOfMicrocode: diff --git a/src/core/vu0Collision_2.s b/src/core/vu0Collision_2.s deleted file mode 100644 index 716c29ac..00000000 --- a/src/core/vu0Collision_2.s +++ /dev/null @@ -1,191 +0,0 @@ -QuitAndFail2: - NOP[E] IADDIU VI01, VI00, 0x0 - NOP NOP - - -QuitAndSucceed2: - NOP[E] IADDIU VI01, VI00, 0x1 - NOP NOP - - -; 20 -GetBBVertices: - MULw.xy VF02, VF01, VF00 NOP - MUL.z VF02, VF01, VF11 NOP - MULw.xz VF03, VF01, VF00 NOP - MUL.y VF03, VF01, VF11 NOP - MULw.x VF04, VF01, VF00 NOP - MUL.yz VF04, VF01, VF11 NOP - NOP JR VI15 - NOP NOP - - -; 60 -Vu0OBBToOBBCollision: - SUBw.xyz VF11, VF00, VF00 LOI 0.5 - MULi.xyz VF12, VF12, I NOP - MULi.xyz VF13, VF13, I NOP - NOP NOP - NOP NOP - NOP MOVE.xyz VF01, VF12 - NOP BAL VI15, GetBBVertices - NOP NOP - MULAx.xyz ACC, VF14, VF01 NOP - MADDAy.xyz ACC, VF15, VF01 NOP - MADDz.xyz VF01, VF16, VF01 NOP - MULAx.xyz ACC, VF14, VF02 NOP - MADDAy.xyz ACC, VF15, VF02 NOP - MADDz.xyz VF02, VF16, VF02 NOP - MULAx.xyz ACC, VF14, VF03 NOP - MADDAy.xyz ACC, VF15, VF03 NOP - MADDz.xyz VF03, VF16, VF03 NOP - MULAx.xyz ACC, VF14, VF04 NOP - MADDAy.xyz ACC, VF15, VF04 NOP - MADDz.xyz VF04, VF16, VF04 NOP - ABS.xyz VF05, VF01 NOP - ABS.xyz VF06, VF02 NOP - ABS.xyz VF07, VF03 NOP - ABS.xyz VF08, VF04 NOP - NOP NOP - MAX.xyz VF05, VF05, VF06 NOP - NOP NOP - MAX.xyz VF07, VF07, VF08 NOP - NOP NOP - NOP NOP - NOP NOP - MAX.xyz VF05, VF05, VF07 NOP - NOP NOP - NOP NOP - NOP NOP - ADD.xyz VF09, VF05, VF13 NOP - NOP NOP - NOP NOP - NOP NOP - MULx.w VF05, VF00, VF09 NOP - MULy.w VF06, VF00, VF09 NOP - MULz.w VF07, VF00, VF09 NOP - CLIPw.xyz VF17, VF05 NOP - CLIPw.xyz VF17, VF06 NOP - CLIPw.xyz VF17, VF07 MOVE.xyz VF01, VF13 - NOP NOP - NOP NOP - NOP NOP - NOP FCAND VI01, 0x3330 - NOP IBNE VI01, VI00, QuitAndFail2 - NOP NOP - NOP BAL VI15, GetBBVertices - NOP NOP - MULAx.xyz ACC, VF18, VF01 NOP - MADDAy.xyz ACC, VF19, VF01 NOP - MADDz.xyz VF01, VF20, VF01 NOP - MULAx.xyz ACC, VF18, VF02 NOP - MADDAy.xyz ACC, VF19, VF02 NOP - MADDz.xyz VF02, VF20, VF02 NOP - MULAx.xyz ACC, VF18, VF03 NOP - MADDAy.xyz ACC, VF19, VF03 NOP - MADDz.xyz VF03, VF20, VF03 NOP - MULAx.xyz ACC, VF18, VF04 NOP - MADDAy.xyz ACC, VF19, VF04 NOP - MADDz.xyz VF04, VF20, VF04 NOP - ABS.xyz VF05, VF01 NOP - ABS.xyz VF06, VF02 NOP - ABS.xyz VF07, VF03 NOP - ABS.xyz VF08, VF04 NOP - NOP NOP - MAX.xyz VF05, VF05, VF06 NOP - NOP NOP - MAX.xyz VF07, VF07, VF08 NOP - NOP NOP - NOP NOP - NOP NOP - MAX.xyz VF05, VF05, VF07 NOP - NOP NOP - NOP NOP - NOP NOP - ADD.xyz VF09, VF05, VF12 NOP - NOP NOP - NOP NOP - NOP NOP - MULx.w VF05, VF00, VF09 NOP - MULy.w VF06, VF00, VF09 NOP - MULz.w VF07, VF00, VF09 NOP - CLIPw.xyz VF21, VF05 NOP - CLIPw.xyz VF21, VF06 NOP - CLIPw.xyz VF21, VF07 NOP - NOP NOP - NOP NOP - NOP NOP - NOP FCAND VI01, 0x3330 - NOP IBNE VI01, VI00, QuitAndFail2 - NOP NOP - SUB.xyz VF06, VF02, VF01 NOP - SUB.xyz VF07, VF03, VF01 NOP - ADD.xyz VF08, VF04, VF01 NOP - ADD.x VF09, VF00, VF12 NOP - ADD.yz VF09, VF00, VF00 NOP - ADD.y VF10, VF00, VF12 NOP - ADD.xz VF10, VF00, VF00 NOP - ADD.z VF11, VF00, VF12 IADDI VI04, VI00, 0x0 - ADD.xy VF11, VF00, VF00 IADD VI02, VI00, VI00 - OPMULA.xyz ACC, VF06, VF09 NOP - OPMSUB.xyz VF01, VF09, VF06 NOP - OPMULA.xyz ACC, VF06, VF10 NOP - OPMSUB.xyz VF02, VF10, VF06 NOP - OPMULA.xyz ACC, VF06, VF11 NOP - OPMSUB.xyz VF03, VF11, VF06 SQI.xyzw VF01, (VI02++) - OPMULA.xyz ACC, VF07, VF09 NOP - OPMSUB.xyz VF01, VF09, VF07 SQI.xyzw VF02, (VI02++) - OPMULA.xyz ACC, VF07, VF10 NOP - OPMSUB.xyz VF02, VF10, VF07 SQI.xyzw VF03, (VI02++) - OPMULA.xyz ACC, VF07, VF11 NOP - OPMSUB.xyz VF03, VF11, VF07 SQI.xyzw VF01, (VI02++) - OPMULA.xyz ACC, VF08, VF09 NOP - OPMSUB.xyz VF01, VF09, VF08 SQI.xyzw VF02, (VI02++) - OPMULA.xyz ACC, VF08, VF10 NOP - OPMSUB.xyz VF02, VF10, VF08 SQI.xyzw VF03, (VI02++) - OPMULA.xyz ACC, VF08, VF11 LOI 0.5 - OPMSUB.xyz VF01, VF11, VF08 SQI.xyzw VF01, (VI02++) - MULi.xyz VF06, VF06, I NOP - MULi.xyz VF07, VF07, I SQI.xyzw VF02, (VI02++) - MULi.xyz VF08, VF08, I NOP - MUL.xyz VF02, VF21, VF01 NOP - MUL.xyz VF03, VF12, VF01 NOP - MUL.xyz VF09, VF06, VF01 NOP - MUL.xyz VF10, VF07, VF01 NOP - MUL.xyz VF11, VF08, VF01 NOP - ABS.xyz VF03, VF03 NOP - ADDy.x VF05, VF09, VF09 NOP - ADDx.y VF05, VF10, VF10 NOP - ADDx.z VF05, VF11, VF11 NOP - NOP NOP -EdgePairLoop: - ADDz.x VF05, VF05, VF09 NOP - ADDz.y VF05, VF05, VF10 NOP - ADDy.z VF05, VF05, VF11 NOP - MULAx.w ACC, VF00, VF02 IADD VI03, VI02, VI00 - MADDAy.w ACC, VF00, VF02 LQD.xyzw VF01, (--VI02) - MADDz.w VF02, VF00, VF02 NOP - ABS.xyz VF05, VF05 NOP - MULAx.w ACC, VF00, VF03 NOP - MADDAy.w ACC, VF00, VF03 NOP - MADDAz.w ACC, VF00, VF03 NOP - MADDAx.w ACC, VF00, VF05 NOP - MADDAy.w ACC, VF00, VF05 NOP - MADDz.w VF03, VF00, VF05 NOP - ADDw.x VF04, VF00, VF02 NOP - MUL.xyz VF02, VF21, VF01 NOP - MUL.xyz VF03, VF12, VF01 NOP - MUL.xyz VF09, VF06, VF01 NOP - CLIPw.xyz VF04, VF03 NOP - MUL.xyz VF10, VF07, VF01 NOP - MUL.xyz VF11, VF08, VF01 NOP - ABS.xyz VF03, VF03 NOP - ADDy.x VF05, VF09, VF09 FCAND VI01, 0x3 - ADDx.y VF05, VF10, VF10 IBNE VI01, VI00, QuitAndFail2 - ADDx.z VF05, VF11, VF11 NOP - NOP IBNE VI03, VI00, EdgePairLoop - NOP NOP - NOP[E] IADDIU VI01, VI00, 0x1 - NOP NOP - -EndOfMicrocode2: diff --git a/src/entities/Physical.cpp b/src/entities/Physical.cpp index a08e68f8..172bae3f 100644 --- a/src/entities/Physical.cpp +++ b/src/entities/Physical.cpp @@ -572,7 +572,7 @@ CPhysical::ApplyCollision(CPhysical *B, CColPoint &colpoint, float &impulseA, fl if(IsGlass(B->GetModelIndex())) CGlass::WindowRespondsToSoftCollision(B, impulseA); if(!A->bInfiniteMass) - A->ApplyMoveForce(colpoint.normal*(1.0f + A->m_fElasticity)*impulseA); + A->ApplyMoveForce(colpoint.GetNormal() * (1.0f + A->m_fElasticity) * impulseA); return true; } }else if(!B->bInfiniteMass) @@ -624,7 +624,7 @@ CPhysical::ApplyCollision(CPhysical *B, CColPoint &colpoint, float &impulseA, fl }else{ if(IsGlass(B->GetModelIndex())) CGlass::WindowRespondsToSoftCollision(B, impulseA); - CVector f = colpoint.normal * impulseA; + CVector f = colpoint.GetNormal() * impulseA; if(A->IsVehicle() && colpoint.normal.z < 0.7f) f.z *= 0.3f; if(!A->bInfiniteMass){ @@ -1146,43 +1146,43 @@ CPhysical::ProcessShiftSectorList(CPtrList *lists) mostColliding = 0; for(j = 1; j < numCollisions; j++) - if(colpoints[j].depth > colpoints[mostColliding].depth) + if (colpoints[j].GetDepth() > colpoints[mostColliding].GetDepth()) mostColliding = j; if(CWorld::bSecondShift) for(j = 0; j < numCollisions; j++) - shift += colpoints[j].normal * colpoints[j].depth * 1.5f/numCollisions; + shift += colpoints[j].GetNormal() * colpoints[j].GetDepth() * 1.5f / numCollisions; else for(j = 0; j < numCollisions; j++) - shift += colpoints[j].normal * colpoints[j].depth * 1.2f/numCollisions; + shift += colpoints[j].GetNormal() * colpoints[j].GetDepth() * 1.2f / numCollisions; if(A->IsVehicle() && B->IsVehicle()){ CVector dir = A->GetPosition() - B->GetPosition(); dir.Normalise(); if(dir.z < 0.0f && dir.z < A->GetForward().z && dir.z < A->GetRight().z) dir.z = Min(0.0f, Min(A->GetForward().z, A->GetRight().z)); - shift += dir * colpoints[mostColliding].depth * 0.5f; + shift += dir * colpoints[mostColliding].GetDepth() * 0.5f; }else if(A->IsPed() && B->IsVehicle() && ((CVehicle*)B)->IsBoat()){ - CVector dir = colpoints[mostColliding].normal; + CVector dir = colpoints[mostColliding].GetNormal(); float f = Min(Abs(dir.z), 0.9f); dir.z = 0.0f; dir.Normalise(); - shift += dir * colpoints[mostColliding].depth / (1.0f - f); + shift += dir * colpoints[mostColliding].GetDepth() / (1.0f - f); boat = B; }else if(B->IsPed() && A->IsVehicle() && ((CVehicle*)A)->IsBoat()){ - CVector dir = colpoints[mostColliding].normal * -1.0f; + CVector dir = colpoints[mostColliding].GetNormal() * -1.0f; float f = Min(Abs(dir.z), 0.9f); dir.z = 0.0f; dir.Normalise(); - B->GetMatrix().Translate(dir * colpoints[mostColliding].depth / (1.0f - f)); + B->GetMatrix().Translate(dir * colpoints[mostColliding].GetDepth() / (1.0f - f)); // BUG? how can that ever happen? A is a Ped if(B->IsVehicle()) B->ProcessEntityCollision(A, colpoints); }else{ if(CWorld::bSecondShift) - shift += colpoints[mostColliding].normal * colpoints[mostColliding].depth * 0.4f; + shift += colpoints[mostColliding].GetNormal() * colpoints[mostColliding].GetDepth() * 0.4f; else - shift += colpoints[mostColliding].normal * colpoints[mostColliding].depth * 0.2f; + shift += colpoints[mostColliding].GetNormal() * colpoints[mostColliding].GetDepth() * 0.2f; } doShift = true; -- cgit v1.2.3