summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
authormajestic <majesticcoding@gmail.com>2020-08-09 12:54:00 -0700
committermajestic <majesticcoding@gmail.com>2020-08-09 21:42:12 -0700
commit70029752f517dfe8c8837f7e6f94e6184c14cbfe (patch)
treeb472c4a75ad4f162933bd6f4abd7106dd7adfdf8 /src/core
parentb73b6b8e130a545687aad4024465fc977e3f01ee (diff)
parente57d4508098a9a930724d018a2132a4e704b1cf1 (diff)
CWindModifiers
Diffstat (limited to 'src/core')
-rw-r--r--src/core/Accident.cpp4
-rw-r--r--src/core/Accident.h1
-rw-r--r--src/core/Cam.cpp4
-rw-r--r--src/core/Collision.cpp1118
-rw-r--r--src/core/Collision.h70
-rw-r--r--src/core/EventList.cpp8
-rw-r--r--src/core/Game.cpp2
-rw-r--r--src/core/Stats.cpp1
-rw-r--r--src/core/Stats.h1
-rw-r--r--src/core/World.cpp5
-rw-r--r--src/core/Zones.cpp5
-rw-r--r--src/core/common.h10
-rw-r--r--src/core/config.h20
-rw-r--r--src/core/main.cpp2
-rw-r--r--src/core/re3.cpp26
-rw-r--r--src/core/vu0Collision.dsm21
-rw-r--r--src/core/vu0Collision_1.s610
-rw-r--r--src/core/vu0Collision_2.s191
18 files changed, 2071 insertions, 28 deletions
diff --git a/src/core/Accident.cpp b/src/core/Accident.cpp
index 1fd6c123..c8611323 100644
--- a/src/core/Accident.cpp
+++ b/src/core/Accident.cpp
@@ -53,6 +53,10 @@ CAccidentManager::ReportAccident(CPed *ped)
void
CAccidentManager::Update()
{
+#ifdef SQUEEZE_PERFORMANCE
+ // Handled after injury registered.
+ return;
+#endif
int32 e;
if (CEventList::GetEvent(EVENT_INJURED_PED, &e)) {
CPed *ped = CPools::GetPed(gaEvent[e].entityRef);
diff --git a/src/core/Accident.h b/src/core/Accident.h
index 949d5fb9..568e1149 100644
--- a/src/core/Accident.h
+++ b/src/core/Accident.h
@@ -1,5 +1,4 @@
#pragma once
-#include "common.h"
#include "config.h"
class CPed;
diff --git a/src/core/Cam.cpp b/src/core/Cam.cpp
index 3b11e16f..375e9d5b 100644
--- a/src/core/Cam.cpp
+++ b/src/core/Cam.cpp
@@ -3958,7 +3958,7 @@ CCam::Process_Debug(const CVector&, float, float, float)
if(CPad::GetPad(1)->GetLeftShockJustDown() && gbBigWhiteDebugLightSwitchedOn)
CShadows::StoreShadowToBeRendered(SHADOWTYPE_ADDITIVE, gpShadowExplosionTex, &Source,
12.0f, 0.0f, 0.0f, -12.0f,
- 128, 128, 128, 128, 1000.0f, false, 1.0f);
+ 128, 128, 128, 128, 1000.0f, false, 1.0f, nil, false);
if(CHud::m_Wants_To_Draw_Hud){
char str[256];
@@ -4103,7 +4103,7 @@ CCam::Process_Editor(const CVector&, float, float, float)
if(CPad::GetPad(1)->GetLeftShockJustDown() && gbBigWhiteDebugLightSwitchedOn)
CShadows::StoreShadowToBeRendered(SHADOWTYPE_ADDITIVE, gpShadowExplosionTex, &Source,
12.0f, 0.0f, 0.0f, -12.0f,
- 128, 128, 128, 128, 1000.0f, false, 1.0f);
+ 128, 128, 128, 128, 1000.0f, false, 1.0f, nil, false);
if(CHud::m_Wants_To_Draw_Hud){
char str[256];
diff --git a/src/core/Collision.cpp b/src/core/Collision.cpp
index 268e3c5e..c2037dc5 100644
--- a/src/core/Collision.cpp
+++ b/src/core/Collision.cpp
@@ -1,5 +1,6 @@
#include "common.h"
+#include "VuVector.h"
#include "main.h"
#include "Lists.h"
#include "Game.h"
@@ -25,6 +26,346 @@
//--MIAMI: file done
+
+// 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 &center, 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,
@@ -252,6 +593,20 @@ CCollision::TestVerticalLineBox(const CColLine &line, const CBox &box)
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);
@@ -325,6 +680,7 @@ CCollision::TestLineTriangle(const CColLine &line, const CompressedVector *verts
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.
@@ -362,6 +718,20 @@ 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)
@@ -375,7 +745,9 @@ CCollision::TestSphereTriangle(const CColSphere &sphere,
CVector vec2 = vb - va;
float len = vec2.Magnitude();
vec2 = vec2 * (1.0f/len);
- CVector vec1 = CrossProduct(vec2, plane.normal);
+ 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:
@@ -420,11 +792,78 @@ CCollision::TestSphereTriangle(const CColSphere &sphere,
}
return dist < sphere.radius;
+#endif
}
bool
CCollision::TestLineOfSight(const CColLine &line, const CMatrix &matrix, CColModel &model, bool ignoreSeeThrough, bool ignoreShootThrough)
{
+#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;
@@ -459,6 +898,7 @@ CCollision::TestLineOfSight(const CColLine &line, const CMatrix &matrix, CColMod
}
return false;
+#endif
}
// TODO: TestPillWithSpheresInColModel, but only called from overloaded CWeapon::FireMelee which isn't used
@@ -475,20 +915,24 @@ CCollision::ProcessSphereSphere(const CColSphere &s1, const CColSphere &s2, CCol
{
CVector dist = s1.center - s2.center;
float d = dist.Magnitude() - s2.radius; // distance from s1's center to s2
- float dc = d < 0.0f ? 0.0f : d; // clamp to zero, i.e. if s1's center is inside 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(mindistsq <= dc*dc || s1.radius <= dc)
- return false;
- dist.Normalise();
- point.point = s1.center - dist*dc;
- point.normal = dist;
- point.surfaceA = s1.surface;
- point.pieceA = s1.piece;
- point.surfaceB = s2.surface;
- point.pieceB = s2.piece;
- point.depth = s1.radius - d; // sphere overlap
- mindistsq = dc*dc; // collision radius
- return true;
+ 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
@@ -528,10 +972,12 @@ CCollision::ProcessSphereBox(const CColSphere &sph, const CColBox &box, CColPoin
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 ?
@@ -571,10 +1017,12 @@ CCollision::ProcessSphereBox(const CColSphere &sph, const CColBox &box, CColPoin
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;
@@ -689,10 +1137,12 @@ CCollision::ProcessLineBox(const CColLine &line, const CColBox &box, CColPoint &
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;
@@ -722,10 +1172,12 @@ CCollision::ProcessLineSphere(const CColLine &line, const CColSphere &sphere, CC
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;
}
@@ -736,6 +1188,17 @@ 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;
@@ -822,11 +1285,40 @@ CCollision::ProcessVerticalLineTriangle(const CColLine &line,
}
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)
@@ -849,7 +1341,9 @@ CCollision::IsStoredPolyStillValidVerticalLine(const CVector &pos, float z, CCol
return poly->valid = false;
// intersection parameter on line
- t = -plane.CalcPoint(p0) / DotProduct(p1 - p0, plane.normal);
+ CVector normal;
+ plane.GetNormal(normal);
+ t = -plane.CalcPoint(p0) / DotProduct(p1 - p0, normal);
// find point of intersection
CVector p = p0 + (p1-p0)*t;
@@ -899,13 +1393,36 @@ CCollision::IsStoredPolyStillValidVerticalLine(const CVector &pos, float z, CCol
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 ,
+CCollision::ProcessLineTriangle(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
+ 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);
@@ -985,6 +1502,7 @@ CCollision::ProcessLineTriangle(const CColLine &line ,
}
mindist = t;
return true;
+#endif
}
bool
@@ -992,6 +1510,30 @@ 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;
@@ -1061,13 +1603,16 @@ CCollision::ProcessSphereTriangle(const CColSphere &sphere,
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
@@ -1075,6 +1620,94 @@ CCollision::ProcessLineOfSight(const CColLine &line,
const CMatrix &matrix, CColModel &model,
CColPoint &point, float &mindist, bool ignoreSeeThrough, bool ignoreShootThrough)
{
+#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;
@@ -1113,6 +1746,7 @@ CCollision::ProcessLineOfSight(const CColLine &line,
return true;
}
return false;
+#endif
}
bool
@@ -1120,6 +1754,125 @@ CCollision::ProcessVerticalLine(const CColLine &line,
const CMatrix &matrix, CColModel &model,
CColPoint &point, float &mindist, bool ignoreSeeThrough, bool ignoreShootThrough, 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;
@@ -1162,6 +1915,7 @@ CCollision::ProcessVerticalLine(const CColLine &line,
return true;
}
return false;
+#endif
}
enum {
@@ -1171,6 +1925,15 @@ enum {
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.
@@ -1180,6 +1943,308 @@ 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];
@@ -1196,14 +2261,16 @@ CCollision::ProcessColModels(const CMatrix &matrixA, CColModel &modelA,
assert(modelA.numLines <= MAXNUMLINES);
// From model A space to model B space
- matAB = Invert(matrixB, matAB) * matrixA;
+ 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) * matrixB;
+ matBA = Invert(matrixA, matBA);
+ matBA *= matrixB;
// transform modelA's spheres and lines to B space
for(i = 0; i < modelA.numSpheres; i++){
@@ -1316,6 +2383,7 @@ CCollision::ProcessColModels(const CMatrix &matrixA, CColModel &modelA,
}
return numCollisions; // sphere collisions
+#endif
}
@@ -1858,6 +2926,19 @@ CColTriangle::Set(const CompressedVector *, int a, int b, int c, uint8 surf, uin
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)
{
@@ -1873,6 +2954,7 @@ CColTrianglePlane::Set(const CVector &va, const CVector &vb, const CVector &vc)
else
dir = normal.z < 0.0f ? DIR_Z_NEG : DIR_Z_POS;
}
+#endif
CColPoint&
CColPoint::operator=(const CColPoint& other)
diff --git a/src/core/Collision.h b/src/core/Collision.h
index eb11d8c4..fd079028 100644
--- a/src/core/Collision.h
+++ b/src/core/Collision.h
@@ -2,9 +2,12 @@
#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.
-#ifdef FIX_BUGS
+#if defined(FIX_BUGS) && !defined(SQUEEZE_PERFORMANCE)
#define MAX_COLLISION_POINTS 64
#else
#define MAX_COLLISION_POINTS 32
@@ -16,6 +19,28 @@ struct CompressedVector
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); };
@@ -25,6 +50,7 @@ struct CompressedVector
struct CSphere
{
+ // NB: this has to be compatible with a CVuVector
CVector center;
float radius;
void Set(float radius, const CVector &center) { this->center = center; this->radius = radius; }
@@ -59,6 +85,7 @@ struct CColBox : public CBox
struct CColLine
{
+ // NB: this has to be compatible with two CVuVectors
CVector p0;
int pad0;
CVector p1;
@@ -81,6 +108,39 @@ struct CColTriangle
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;
@@ -88,7 +148,11 @@ struct CColTrianglePlane
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 GetNormalX() const { return normal.x; }
+ float GetNormalY() const { return normal.y; }
+ float GetNormalZ() const { return normal.z; }
float CalcPoint(const CVector &v) const { return DotProduct(normal, v) - dist; };
+#endif
};
struct CColPoint
@@ -109,7 +173,11 @@ struct CColPoint
struct CStoredCollPoly
{
+#ifdef VU_COLLISION
+ CVuVector verts[3];
+#else
CVector verts[3];
+#endif
bool valid;
};
diff --git a/src/core/EventList.cpp b/src/core/EventList.cpp
index e5f264c7..da0a5967 100644
--- a/src/core/EventList.cpp
+++ b/src/core/EventList.cpp
@@ -8,6 +8,7 @@
#include "Messages.h"
#include "Text.h"
#include "main.h"
+#include "Accident.h"
int32 CEventList::ms_nFirstFreeSlotIndex;
CEvent gaEvent[NUMEVENTS];
@@ -63,6 +64,13 @@ CEventList::RegisterEvent(eEventType type, eEventEntity entityType, CEntity *ent
int ref;
bool copsDontCare;
+#ifdef SQUEEZE_PERFORMANCE
+ if (type == EVENT_INJURED_PED) {
+ gAccidentManager.ReportAccident((CPed*)ent);
+ return;
+ }
+#endif
+
copsDontCare = false;
switch(entityType){
case EVENT_ENTITY_PED:
diff --git a/src/core/Game.cpp b/src/core/Game.cpp
index 6573ac22..7b113d89 100644
--- a/src/core/Game.cpp
+++ b/src/core/Game.cpp
@@ -110,6 +110,7 @@ int gameTxdSlot;
bool DoRWStuffStartOfFrame(int16 TopRed, int16 TopGreen, int16 TopBlue, int16 BottomRed, int16 BottomGreen, int16 BottomBlue, int16 Alpha);
void DoRWStuffEndOfFrame(void);
+#ifdef PS2_MENU
void MessageScreen(char *msg)
{
//TODO: stretch_screen
@@ -143,6 +144,7 @@ void MessageScreen(char *msg)
DoRWStuffEndOfFrame();
}
+#endif
bool
CGame::InitialiseOnceBeforeRW(void)
diff --git a/src/core/Stats.cpp b/src/core/Stats.cpp
index 2e3a27b2..29087b34 100644
--- a/src/core/Stats.cpp
+++ b/src/core/Stats.cpp
@@ -61,6 +61,7 @@ int32 CStats::FastestTimes[CStats::TOTAL_FASTEST_TIMES];
int32 CStats::HighestScores[CStats::TOTAL_HIGHEST_SCORES];
int32 CStats::BestPositions[CStats::TOTAL_BEST_POSITIONS];
int32 CStats::PropertyDestroyed;
+int32 CStats::PamphletMissionPassed;
int32 CStats::Sprayings;
float CStats::AutoPaintingBudget;
diff --git a/src/core/Stats.h b/src/core/Stats.h
index 7dd527ea..e6b8df6a 100644
--- a/src/core/Stats.h
+++ b/src/core/Stats.h
@@ -65,6 +65,7 @@ public:
static int32 HighestScores[TOTAL_HIGHEST_SCORES];
static int32 BestPositions[TOTAL_BEST_POSITIONS];
static int32 PropertyDestroyed;
+ static int32 PamphletMissionPassed;
static int32 Sprayings;
static float AutoPaintingBudget;
static int32 NoMoreHurricanes;
diff --git a/src/core/World.cpp b/src/core/World.cpp
index 7126b26f..fb2dbad3 100644
--- a/src/core/World.cpp
+++ b/src/core/World.cpp
@@ -1933,6 +1933,11 @@ CWorld::Process(void)
} else {
for(CPtrNode *node = ms_listMovingEntityPtrs.first; node; node = node->next) {
CEntity *movingEnt = (CEntity *)node->item;
+#ifdef SQUEEZE_PERFORMANCE
+ if (movingEnt->bRemoveFromWorld) {
+ RemoveEntityInsteadOfProcessingIt(movingEnt);
+ } else
+#endif
if(movingEnt->m_rwObject && RwObjectGetType(movingEnt->m_rwObject) == rpCLUMP &&
RpAnimBlendClumpGetFirstAssociation(movingEnt->GetClump())) {
// TODO(MIAMI): doRender argument
diff --git a/src/core/Zones.cpp b/src/core/Zones.cpp
index 3095b36d..96f5dc62 100644
--- a/src/core/Zones.cpp
+++ b/src/core/Zones.cpp
@@ -7,6 +7,7 @@
#include "Clock.h"
#include "Text.h"
#include "World.h"
+#include "Timer.h"
eLevelName CTheZones::m_CurrLevel;
int16 CTheZones::FindIndex;
@@ -127,6 +128,10 @@ CTheZones::Init(void)
void
CTheZones::Update(void)
{
+#ifdef SQUEEZE_PERFORMANCE
+ if (CTimer::GetFrameCounter() % 5 != 0)
+ return;
+#endif
CVector pos;
pos = FindPlayerCoors();
m_CurrLevel = GetLevelFromPosition(&pos);
diff --git a/src/core/common.h b/src/core/common.h
index d22c1715..ba1d24ef 100644
--- a/src/core/common.h
+++ b/src/core/common.h
@@ -89,6 +89,16 @@ typedef uint16_t wchar;
#include <rpskin.h>
#endif
+#ifdef __GNUC__
+#define TYPEALIGN(n) __attribute__ ((aligned (n)))
+#else
+#ifdef _MSC_VER
+#define TYPEALIGN(n) __declspec(align(n))
+#else
+#define TYPEALIGN(n) // unknown compiler...ignore
+#endif
+#endif
+
#define ALIGNPTR(p) (void*)((((uintptr)(void*)p) + sizeof(void*)-1) & ~(sizeof(void*)-1))
// PDP-10 like byte functions
diff --git a/src/core/config.h b/src/core/config.h
index 4cd4cbe1..469f9017 100644
--- a/src/core/config.h
+++ b/src/core/config.h
@@ -167,7 +167,7 @@ enum Config {
#if defined GTA_PS2
# define GTA_PS2_STUFF
# define RANDOMSPLASH
-# define COMPRESSED_COL_VECTORS
+# define VU_COLLISION
#elif defined GTA_PC
# define GTA3_1_1_PATCH
//# define GTA3_STEAM_PATCH
@@ -180,6 +180,10 @@ enum Config {
#elif defined GTA_XBOX
#endif
+#ifdef VU_COLLISION
+#define COMPRESSED_COL_VECTORS // current need compressed vectors in this code
+#endif
+
#ifdef MASTER
// only in master builds
#else
@@ -228,6 +232,9 @@ enum Config {
// #define PC_WATER
#define WATER_CHEATS
+//#define USE_CUTSCENE_SHADOW_FOR_PED
+#define DISABLE_CUTSCENE_SHADOWS
+
// Pad
#if !defined(RW_GL3) && defined(_WIN32)
#define XINPUT
@@ -297,4 +304,13 @@ enum Config {
#ifndef AUDIO_OAL // is not working yet for openal
#define AUDIO_CACHE // cache sound lengths to speed up the cold boot
#endif
-//#define PS2_AUDIO // changes audio paths for cutscenes and radio to PS2 paths, needs vbdec to support VB with MSS \ No newline at end of file
+//#define PS2_AUDIO // changes audio paths for cutscenes and radio to PS2 paths, needs vbdec to support VB with MSS
+
+
+//#define SQUEEZE_PERFORMANCE
+#ifdef SQUEEZE_PERFORMANCE
+ #undef PS2_ALPHA_TEST
+ #undef NO_ISLAND_LOADING
+ #define PC_PARTICLE
+ #define VC_PED_PORTS // To not process collisions always. But should be tested if that's really beneficial
+#endif \ No newline at end of file
diff --git a/src/core/main.cpp b/src/core/main.cpp
index d4ef8c4b..83d4b66e 100644
--- a/src/core/main.cpp
+++ b/src/core/main.cpp
@@ -852,7 +852,7 @@ RenderScene(void)
CRenderer::RenderFadingInEntities();
RwRenderStateSet(rwRENDERSTATECULLMODE, (void*)rwCULLMODECULLNONE);
CWeather::RenderRainStreaks();
- // CCoronas::RenderSunReflection
+ CCoronas::RenderSunReflection();
}
void
diff --git a/src/core/re3.cpp b/src/core/re3.cpp
index 81b2bfc0..e9c643ac 100644
--- a/src/core/re3.cpp
+++ b/src/core/re3.cpp
@@ -7,6 +7,7 @@
#include "Credits.h"
#include "Camera.h"
#include "Weather.h"
+#include "Timecycle.h"
#include "Clock.h"
#include "World.h"
#include "Vehicle.h"
@@ -406,6 +407,26 @@ DebugMenuPopulate(void)
static const char *weathers[] = {
"Sunny", "Cloudy", "Rainy", "Foggy", "Extrasunny", "Stormy"
};
+ static const char *extracols[] = {
+ "1 - Malibu club",
+ "2 - Strib club",
+ "3 - Hotel",
+ "4 - Bank",
+ "5 - Police HQ",
+ "6 - Mall",
+ "7 - Rifle Range",
+ "8 - Mansion",
+ "9 - Dirt ring",
+ "10 - Blood ring",
+ "11 - Hot ring",
+ "12 - Concert hall",
+ "13 - Auntie Poulets",
+ "14 - Intro at docks",
+ "15 - Biker bar",
+ "16 - Intro cafe",
+ "17 - Studio",
+ "18", "19", "20", "21", "22", "23", "24"
+ };
DebugMenuEntry *e;
e = DebugMenuAddVar("Time & Weather", "Current Hour", &CClock::GetHoursRef(), nil, 1, 0, 23, nil);
DebugMenuEntrySetWrap(e, true);
@@ -416,7 +437,8 @@ DebugMenuPopulate(void)
DebugMenuEntrySetWrap(e, true);
e = DebugMenuAddVar("Time & Weather", "New Weather", (int16*)&CWeather::NewWeatherType, nil, 1, 0, 5, weathers);
DebugMenuEntrySetWrap(e, true);
- DebugMenuAddVar("Time & Weather", "Wind", (float*)&CWeather::Wind, nil, 0.1f, 0.0f, 1.0f);
+ DebugMenuAddVarBool8("Time & Weather", "Extracolours On", &CTimeCycle::m_bExtraColourOn, nil);
+ DebugMenuAddVar("Time & Weather", "Extracolour", &CTimeCycle::m_ExtraColour, nil, 1, 0, 23, extracols);
DebugMenuAddVar("Time & Weather", "Time scale", (float*)&CTimer::GetTimeScale(), nil, 0.1f, 0.0f, 10.0f);
DebugMenuAddCmd("Cheats", "Weapon set 1", WeaponCheat1);
@@ -489,9 +511,7 @@ DebugMenuPopulate(void)
DebugMenuAddVarBool8("Render", "Draw hud", &CHud::m_Wants_To_Draw_Hud, nil);
DebugMenuAddVarBool8("Render", "Backface Culling", &gBackfaceCulling, nil);
-#ifdef LIBRW
DebugMenuAddVarBool8("Render", "PS2 Alpha test Emu", &gPS2alphaTest, nil);
-#endif
DebugMenuAddVarBool8("Render", "Frame limiter", &FrontEndMenuManager.m_PrefsFrameLimiter, nil);
DebugMenuAddVarBool8("Render", "VSynch", &FrontEndMenuManager.m_PrefsVsync, nil);
DebugMenuAddVar("Render", "Max FPS", &RsGlobal.maxFPS, nil, 1, 1, 1000, nil);
diff --git a/src/core/vu0Collision.dsm b/src/core/vu0Collision.dsm
new file mode 100644
index 00000000..657c8b81
--- /dev/null
+++ b/src/core/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/core/vu0Collision_1.s b/src/core/vu0Collision_1.s
new file mode 100644
index 00000000..055c8640
--- /dev/null
+++ b/src/core/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/core/vu0Collision_2.s b/src/core/vu0Collision_2.s
new file mode 100644
index 00000000..716c29ac
--- /dev/null
+++ b/src/core/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: