code:
#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<CColModel*> 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);
};


code:
#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
};

license: mit


code:
#include "common.h"

#include "TempColModels.h"
#include "Game.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
}


code:
#pragma once

#include "ColModel.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);
};


code:
#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 &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
}
#endif


code:
#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);
}


code:
.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


code:
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:


code:
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:


code:
#include "common.h"

#include "AutoPilot.h"

#include "CarCtrl.h"
#include "Curves.h"
#include "PathFind.h"
#include "SaveBuf.h"

void CAutoPilot::ModifySpeed(float speed)
{
	m_fMaxTrafficSpeed = Max(0.01f, speed);
	float positionBetweenNodes = (float)(CTimer::GetTimeInMilliseconds() - m_nTimeEnteredCurve) / m_nTimeToSpendOnCurrentCurve;
	CCarPathLink* pCurrentLink = &ThePaths.m_carPathLinks[m_nCurrentPathNodeInfo];
	CCarPathLink* pNextLink = &ThePaths.m_carPathLinks[m_nNextPathNodeInfo];
	float currentPathLinkForwardX = m_nCurrentDirection * ThePaths.m_carPathLinks[m_nCurrentPathNodeInfo].GetDirX();
	float currentPathLinkForwardY = m_nCurrentDirection * ThePaths.m_carPathLinks[m_nCurrentPathNodeInfo].GetDirY();
	float nextPathLinkForwardX = m_nNextDirection * ThePaths.m_carPathLinks[m_nNextPathNodeInfo].GetDirX();
	float nextPathLinkForwardY = m_nNextDirection * ThePaths.m_carPathLinks[m_nNextPathNodeInfo].GetDirY();
	CVector positionOnCurrentLinkIncludingLane(
		pCurrentLink->GetX() + ((m_nCurrentLane + 0.5f) * LANE_WIDTH) * currentPathLinkForwardY,
		pCurrentLink->GetY() - ((m_nCurrentLane + 0.5f) * LANE_WIDTH) * currentPathLinkForwardX,
		0.0f);
	CVector positionOnNextLinkIncludingLane(
		pNextLink->GetX() + ((m_nNextLane + 0.5f) * LANE_WIDTH) * nextPathLinkForwardY,
		pNextLink->GetY() - ((m_nNextLane + 0.5f) * LANE_WIDTH) * nextPathLinkForwardX,
		0.0f);
	m_nTimeToSpendOnCurrentCurve = CCurves::CalcSpeedScaleFactor(
		&positionOnCurrentLinkIncludingLane,
		&positionOnNextLinkIncludingLane,
		currentPathLinkForwardX, currentPathLinkForwardY,
		nextPathLinkForwardX, nextPathLinkForwardY
	) * (1000.0f / m_fMaxTrafficSpeed);
#ifdef FIX_BUGS
	/* Casting timer to float is very unwanted, and in this case even causes crashes. */
	m_nTimeEnteredCurve = CTimer::GetTimeInMilliseconds() -
		(uint32)(positionBetweenNodes * m_nTimeToSpendOnCurrentCurve);
#else
	m_nTimeEnteredCurve = CTimer::GetTimeInMilliseconds() - positionBetweenNodes * m_nTimeToSpendOnCurrentCurve;
#endif
}

void CAutoPilot::RemoveOnePathNode()
{
	--m_nPathFindNodesCount;
	for (int i = 0; i < m_nPathFindNodesCount; i++)
		m_aPathFindNodesInfo[i] = m_aPathFindNodesInfo[i + 1];
}

#ifdef COMPATIBLE_SAVES
void CAutoPilot::Save(uint8*& buf)
{
	WriteSaveBuf(buf, m_nCurrentRouteNode);
	WriteSaveBuf(buf, m_nNextRouteNode);
	WriteSaveBuf(buf, m_nPrevRouteNode);
	WriteSaveBuf(buf, m_nTimeEnteredCurve);
	WriteSaveBuf(buf, m_nTimeToSpendOnCurrentCurve);
	WriteSaveBuf(buf, m_nCurrentPathNodeInfo);
	WriteSaveBuf(buf, m_nNextPathNodeInfo);
	WriteSaveBuf(buf, m_nPreviousPathNodeInfo);
	WriteSaveBuf(buf, m_nAntiReverseTimer);
	WriteSaveBuf(buf, m_nTimeToStartMission);
	WriteSaveBuf(buf, m_nPreviousDirection);
	WriteSaveBuf(buf, m_nCurrentDirection);
	WriteSaveBuf(buf, m_nNextDirection);
	WriteSaveBuf(buf, m_nCurrentLane);
	WriteSaveBuf(buf, m_nNextLane);
	WriteSaveBuf(buf, m_nDrivingStyle);
	WriteSaveBuf(buf, m_nCarMission);
	WriteSaveBuf(buf, m_nTempAction);
	WriteSaveBuf(buf, m_nTimeTempAction);
	WriteSaveBuf(buf, m_fMaxTrafficSpeed);
	WriteSaveBuf(buf, m_nCruiseSpeed);
	uint8 flags = 0;
	if (m_bSlowedDownBecauseOfCars) flags |= BIT(0);
	if (m_bSlowedDownBecauseOfPeds) flags |= BIT(1);
	if (m_bStayInCurrentLevel) flags |= BIT(2);
	if (m_bStayInFastLane) flags |= BIT(3);
	if (m_bIgnorePathfinding) flags |= BIT(4);
	WriteSaveBuf(buf, flags);
	ZeroSaveBuf(buf, 2);
	WriteSaveBuf(buf, m_vecDestinationCoors.x);
	WriteSaveBuf(buf, m_vecDestinationCoors.y);
	WriteSaveBuf(buf, m_vecDestinationCoors.z);
	ZeroSaveBuf(buf, 32);
	WriteSaveBuf(buf, m_nPathFindNodesCount);
	ZeroSaveBuf(buf, 6);
}

void CAutoPilot::Load(uint8*& buf)
{
	ReadSaveBuf(&m_nCurrentRouteNode, buf);
	ReadSaveBuf(&m_nNextRouteNode, buf);
	ReadSaveBuf(&m_nPrevRouteNode, buf);
	ReadSaveBuf(&m_nTimeEnteredCurve, buf);
	ReadSaveBuf(&m_nTimeToSpendOnCurrentCurve, buf);
	ReadSaveBuf(&m_nCurrentPathNodeInfo, buf);
	ReadSaveBuf(&m_nNextPathNodeInfo, buf);
	ReadSaveBuf(&m_nPreviousPathNodeInfo, buf);
	ReadSaveBuf(&m_nAntiReverseTimer, buf);
	ReadSaveBuf(&m_nTimeToStartMission, buf);
	ReadSaveBuf(&m_nPreviousDirection, buf);
	ReadSaveBuf(&m_nCurrentDirection, buf);
	ReadSaveBuf(&m_nNextDirection, buf);
	ReadSaveBuf(&m_nCurrentLane, buf);
	ReadSaveBuf(&m_nNextLane, buf);
	ReadSaveBuf(&m_nDrivingStyle, buf);
	ReadSaveBuf(&m_nCarMission, buf);
	ReadSaveBuf(&m_nTempAction, buf);
	ReadSaveBuf(&m_nTimeTempAction, buf);
	ReadSaveBuf(&m_fMaxTrafficSpeed, buf);
	ReadSaveBuf(&m_nCruiseSpeed, buf);
	uint8 flags;
	ReadSaveBuf(&flags, buf);
	m_bSlowedDownBecauseOfCars = !!(flags & BIT(0));
	m_bSlowedDownBecauseOfPeds = !!(flags & BIT(1));
	m_bStayInCurrentLevel = !!(flags & BIT(2));
	m_bStayInFastLane = !!(flags & BIT(3));
	m_bIgnorePathfinding = !!(flags & BIT(4));
	SkipSaveBuf(buf, 2);
	ReadSaveBuf(&m_vecDestinationCoors.x, buf);
	ReadSaveBuf(&m_vecDestinationCoors.y, buf);
	ReadSaveBuf(&m_vecDestinationCoors.z, buf);
	SkipSaveBuf(buf, 32);
	ReadSaveBuf(&m_nPathFindNodesCount, buf);
	SkipSaveBuf(buf, 6);
}
#endif


code:
#pragma once
#include "Timer.h"

class CVehicle;
struct CPathNode;

enum eCarMission
{
	MISSION_NONE,
	MISSION_CRUISE,
	MISSION_RAMPLAYER_FARAWAY,
	MISSION_RAMPLAYER_CLOSE,
	MISSION_BLOCKPLAYER_FARAWAY,
	MISSION_BLOCKPLAYER_CLOSE,
	MISSION_BLOCKPLAYER_HANDBRAKESTOP,
	MISSION_WAITFORDELETION,
	MISSION_GOTOCOORDS,
	MISSION_GOTOCOORDS_STRAIGHT,
	MISSION_EMERGENCYVEHICLE_STOP,
	MISSION_STOP_FOREVER,
	MISSION_GOTOCOORDS_ACCURATE,
	MISSION_GOTO_COORDS_STRAIGHT_ACCURATE,
	MISSION_GOTOCOORDS_ASTHECROWSWIMS,
	MISSION_RAMCAR_FARAWAY,
	MISSION_RAMCAR_CLOSE,
	MISSION_BLOCKCAR_FARAWAY,
	MISSION_BLOCKCAR_CLOSE,
	MISSION_BLOCKCAR_HANDBRAKESTOP,
};

enum eCarTempAction
{
	TEMPACT_NONE,
	TEMPACT_WAIT,
	TEMPACT_REVERSE,
	TEMPACT_HANDBRAKETURNLEFT,
	TEMPACT_HANDBRAKETURNRIGHT,
	TEMPACT_HANDBRAKESTRAIGHT,
	TEMPACT_TURNLEFT,
	TEMPACT_TURNRIGHT,
	TEMPACT_GOFORWARD,
	TEMPACT_SWERVELEFT,
	TEMPACT_SWERVERIGHT
};

enum eCarDrivingStyle
{
	DRIVINGSTYLE_STOP_FOR_CARS,
	DRIVINGSTYLE_SLOW_DOWN_FOR_CARS,
	DRIVINGSTYLE_AVOID_CARS,
	DRIVINGSTYLE_PLOUGH_THROUGH,
	DRIVINGSTYLE_STOP_FOR_CARS_IGNORE_LIGHTS
};

class CAutoPilot {
public:
	int32 m_nCurrentRouteNode;
	int32 m_nNextRouteNode;
	int32 m_nPrevRouteNode;
	int32 m_nTimeEnteredCurve;
	int32 m_nTimeToSpendOnCurrentCurve;
	uint32 m_nCurrentPathNodeInfo;
	uint32 m_nNextPathNodeInfo;
	uint32 m_nPreviousPathNodeInfo;
	uint32 m_nAntiReverseTimer;
	uint32 m_nTimeToStartMission;
	int8 m_nPreviousDirection;
	int8 m_nCurrentDirection;
	int8 m_nNextDirection;
	int8 m_nCurrentLane;
	int8 m_nNextLane;
	uint8 m_nDrivingStyle;
	uint8 m_nCarMission;
	uint8 m_nTempAction;
	uint32 m_nTimeTempAction;
	float m_fMaxTrafficSpeed;
	uint8 m_nCruiseSpeed;
	uint8 m_bSlowedDownBecauseOfCars : 1;
	uint8 m_bSlowedDownBecauseOfPeds : 1;
	uint8 m_bStayInCurrentLevel : 1;
	uint8 m_bStayInFastLane : 1;
	uint8 m_bIgnorePathfinding : 1;
	CVector m_vecDestinationCoors;
	CPathNode *m_aPathFindNodesInfo[NUM_PATH_NODES_IN_AUTOPILOT];
	int16 m_nPathFindNodesCount;
	CVehicle *m_pTargetCar;

	CAutoPilot(void) {
		m_nPrevRouteNode = 0;
		m_nNextRouteNode = m_nPrevRouteNode;
		m_nCurrentRouteNode = m_nNextRouteNode;
		m_nTimeEnteredCurve = 0;
		m_nTimeToSpendOnCurrentCurve = 1000;
		m_nPreviousPathNodeInfo = 0;
		m_nNextPathNodeInfo = m_nPreviousPathNodeInfo;
		m_nCurrentPathNodeInfo = m_nNextPathNodeInfo;
		m_nNextDirection = 1;
		m_nCurrentDirection = m_nNextDirection;
		m_nCurrentLane = m_nNextLane = 0;
		m_nDrivingStyle = DRIVINGSTYLE_STOP_FOR_CARS;
		m_nCarMission = MISSION_NONE;
		m_nTempAction = TEMPACT_NONE;
		m_nCruiseSpeed = 10;
		m_fMaxTrafficSpeed = 10.0f;
		m_bSlowedDownBecauseOfPeds = false;
		m_bSlowedDownBecauseOfCars = false;
		m_nPathFindNodesCount = 0;
		m_pTargetCar = 0;
		m_nTimeToStartMission = CTimer::GetTimeInMilliseconds();
		m_nAntiReverseTimer = m_nTimeToStartMission;
		m_bStayInFastLane = false;
	}

	void ModifySpeed(float);
	void RemoveOnePathNode();
#ifdef COMPATIBLE_SAVES
	void Save(uint8*& buf);
	void Load(uint8*& buf);
#endif

};

VALIDATE_SIZE(CAutoPilot, 0x70);


code:
#include "common.h"

#include "Bridge.h"
#include "Pools.h"
#include "ModelIndices.h"
#include "PathFind.h"
#include "Stats.h"

CEntity *CBridge::pLiftRoad;
CEntity *CBridge::pLiftPart;
CEntity *CBridge::pWeight;

int CBridge::State;
int CBridge::OldState;

float CBridge::DefaultZLiftPart;
float CBridge::DefaultZLiftRoad;
float CBridge::DefaultZLiftWeight;

float CBridge::OldLift;

uint32 CBridge::TimeOfBridgeBecomingOperational;

void CBridge::Init()
{
	FindBridgeEntities();
	OldLift = -1.0f;
	if (pLiftPart && pWeight)
	{
		DefaultZLiftPart   = pLiftPart->GetPosition().z;
		DefaultZLiftWeight = pWeight->GetPosition().z;

		if (pLiftRoad)
			DefaultZLiftRoad = pLiftRoad->GetPosition().z;

		ThePaths.SetLinksBridgeLights(-330.0, -230.0, -700.0, -588.0, true);
	}
}

void CBridge::Update()
{
	if (!pLiftPart || !pWeight)
		return;

	OldState = State;

	float liftHeight;

	// Set bridge height and state
	if (CStats::CommercialPassed)
	{
		if (TimeOfBridgeBecomingOperational == 0)
			TimeOfBridgeBecomingOperational = CTimer::GetTimeInMilliseconds();

		// Time remaining for bridge to become operational
		// uint16, so after about a minute it overflows to 0 and the cycle repeats
		uint16 timeElapsed = CTimer::GetTimeInMilliseconds() - TimeOfBridgeBecomingOperational;

		// Calculate lift part height and bridge state
		if (timeElapsed < 10000)
		{
			State = STATE_LIFT_PART_MOVING_DOWN;
			liftHeight = 25.0f - timeElapsed / 10000.0f * 25.0f;
		}
		else if (timeElapsed < 40000)
		{
			liftHeight = 0.0f;
			State = STATE_LIFT_PART_IS_DOWN;
		}
		else if (timeElapsed < 50000)
		{
			liftHeight = 0.0f;
			State = STATE_LIFT_PART_ABOUT_TO_MOVE_UP;
		}
		else if (timeElapsed < 60000)
		{
			State = STATE_LIFT_PART_MOVING_UP;
			liftHeight = (timeElapsed - 50000) / 10000.0f * 25.0f;
		}
		else
		{
			liftHeight = 25.0f;
			State = STATE_LIFT_PART_IS_UP;
		}
	}
	else
	{
		liftHeight = 25.0f;
		TimeOfBridgeBecomingOperational = 0;
		State = STATE_BRIDGE_LOCKED;
	}

	// Move bridge part
	if (liftHeight != OldLift)
	{
		pLiftPart->GetMatrix().GetPosition().z = DefaultZLiftPart + liftHeight;
		pLiftPart->GetMatrix().UpdateRW();
		pLiftPart->UpdateRwFrame();
		if (pLiftRoad)
		{
			pLiftRoad->GetMatrix().GetPosition().z = DefaultZLiftRoad + liftHeight;
			pLiftRoad->GetMatrix().UpdateRW();
			pLiftRoad->UpdateRwFrame();
		}
		pWeight->GetMatrix().GetPosition().z = DefaultZLiftWeight - liftHeight;
		pWeight->GetMatrix().UpdateRW();
		pWeight->UpdateRwFrame();

		OldLift = liftHeight;
	}

	if (State == STATE_LIFT_PART_ABOUT_TO_MOVE_UP && OldState == STATE_LIFT_PART_IS_DOWN)
		ThePaths.SetLinksBridgeLights(-330.0, -230.0, -700.0, -588.0, true);
	else if (State == STATE_LIFT_PART_IS_DOWN && OldState == STATE_LIFT_PART_MOVING_DOWN)
		ThePaths.SetLinksBridgeLights(-330.0, -230.0, -700.0, -588.0, false);
}

bool CBridge::ShouldLightsBeFlashing()
{
	return State != STATE_LIFT_PART_IS_DOWN;
}

void CBridge::FindBridgeEntities()
{
	pWeight   = nil;
	pLiftRoad = nil;
	pLiftPart = nil;

	for (int i = CPools::GetBuildingPool()->GetSize()-1; i >= 0; i--) {
		CBuilding* entry = CPools::GetBuildingPool()->GetSlot(i);
		if (entry)
		{
			if (entry->GetModelIndex() == MI_BRIDGELIFT)
				pLiftPart = entry;
			else if (entry->GetModelIndex() == MI_BRIDGEROADSEGMENT)
				pLiftRoad = entry;
			else if (entry->GetModelIndex() == MI_BRIDGEWEIGHT)
				pWeight = entry;
		}
	}
}

bool CBridge::ThisIsABridgeObjectMovingUp(int index)
{
	if (index != MI_BRIDGEROADSEGMENT && index != MI_BRIDGELIFT)
		return false;

	return State == STATE_LIFT_PART_ABOUT_TO_MOVE_UP || State == STATE_LIFT_PART_MOVING_UP;
}


code:
#pragma once

class CEntity;

enum bridgeStates {
    STATE_BRIDGE_LOCKED,
    STATE_LIFT_PART_IS_UP,
    STATE_LIFT_PART_MOVING_DOWN,
    STATE_LIFT_PART_IS_DOWN,
    STATE_LIFT_PART_ABOUT_TO_MOVE_UP,
    STATE_LIFT_PART_MOVING_UP
};

class CBridge
{
public:
	static CEntity *pLiftRoad, *pLiftPart, *pWeight;
	static int State, OldState;
	static float DefaultZLiftPart, DefaultZLiftRoad, DefaultZLiftWeight;
	static float OldLift;
	static uint32 TimeOfBridgeBecomingOperational;

	static void Init();
	static void Update();
	static bool ShouldLightsBeFlashing();
	static void FindBridgeEntities();
	static bool ThisIsABridgeObjectMovingUp(int);
};