Something went wrong. Try again.
Base for making Paper Mario (N64) mods, built on the decompilation docs.starhaven.dev/papermario-dx
paper-mario n64
Something went wrong. Try again.
40 kB · 1141 lines
C
at main
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142#include "common.h"#include "model.h"
typedef struct HitFile { /* 0x00 */ u32 collisionOffset; /* 0x04 */ u32 zoneOffset;} HitFile; // size = 0x08
typedef struct ColliderBackupEntry { /* 0x00 */ s32 flags; /* 0x04 */ s16 parentModelIndex; /* 0x06 */ PAD(2);} ColliderBackupEntry; // size = 0x08
typedef struct HitFileHeader { /* 0x00 */ s16 numColliders; /* 0x02 */ PAD(2); /* 0x04 */ s32 collidersOffset; /* 0x08 */ s16 numVertices; /* 0x0A */ PAD(2); /* 0x0C */ s32 verticesOffset; /* 0x10 */ s16 boundingBoxesDataSize; /* 0x12 */ PAD(2); /* 0x14 */ s32 boundingBoxesOffset;} HitFileHeader; // size = 0x18
typedef struct HitAssetCollider { /* 0x00 */ s16 boundingBoxOffset; /* 0x02 */ s16 nextSibling; /* 0x04 */ s16 firstChild; /* 0x06 */ s16 numTriangles; /* 0x08 */ s32 trianglesOffset;} HitAssetCollider; // size = 0x0C
CollisionData gCollisionData;CollisionData gZoneCollisionData;
BSS f32 gCollisionRayStartX;BSS f32 gCollisionRayStartY;BSS f32 gCollisionRayStartZ;BSS f32 gCollisionRayDirX;BSS f32 gCollisionRayDirY;BSS f32 gCollisionRayDirZ;BSS f32 gCollisionPointX;BSS f32 gCollisionPointY;BSS f32 gCollisionPointZ;BSS f32 gCollisionRayLength;BSS f32 gCollisionNormalX;BSS f32 gCollisionNormalY;BSS f32 gCollisionNormalZ;BSS ColliderBackupEntry* gCollisionDataBackup;BSS ColliderBackupEntry* gCollisionDataZoneBackup;
Vec3s gEntityColliderFaces[] = { { 4, 6, 5 }, { 4, 7, 6 }, { 0, 3, 4 }, { 3, 7, 4 }, { 3, 2, 7 }, { 2, 6, 7 }, { 2, 1, 6 }, { 1, 5, 6 }, { 1, 0, 5 }, { 0, 4, 5 }, { 0, 1, 2 }, { 0, 2, 3 },};
Vec3f gEntityColliderNormals[] = { { 0.0f, 1.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, { 1.0f, 0.0f, 0.0f }, { 1.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, -1.0f }, { 0.0f, 0.0f, -1.0f }, { -1.0f, 0.0f, 0.0f }, { -1.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 1.0f }, { 0.0f, 0.0f, 1.0f }, { 0.0f, -1.0f, 0.0f }, { 0.0f, -1.0f, 0.0f },};
s32 collision_heap_create(void);void* collision_heap_malloc(s32 size);void collision_heap_free(void*);
void load_hit_data(s32 idx, HitFile* hit);void _add_hit_vert_to_buffer(Vec3f** buf, Vec3f* vert, s32* bufSize);s32 _get_hit_vert_index_from_buffer(Vec3f** buffer, Vec3f* vert, s32* bufferSize);
void backup_map_collision_data(void) { CollisionData* collisionData; Collider* collider; ColliderBackupEntry* backupEntry; s32 i;
collisionData = &gCollisionData; gCollisionDataBackup = general_heap_malloc(collisionData->numColliders * sizeof(ColliderBackupEntry)); for (i = 0, backupEntry = gCollisionDataBackup; i < collisionData->numColliders; i++, backupEntry++) { collider = &collisionData->colliderList[i]; backupEntry->flags = collider->flags; backupEntry->parentModelIndex = collider->parentModelIndex; }
collisionData = &gZoneCollisionData; gCollisionDataZoneBackup = general_heap_malloc(collisionData->numColliders * sizeof(ColliderBackupEntry)); for (i = 0, backupEntry = gCollisionDataZoneBackup; i < collisionData->numColliders; i++, backupEntry++) { collider = &collisionData->colliderList[i]; backupEntry->flags = collider->flags; backupEntry->parentModelIndex = collider->parentModelIndex; }
gZoneCollisionData.numColliders = 0;}
void initialize_collision(void) { gCollisionData.numColliders = 0; gZoneCollisionData.numColliders = 0; collision_heap_create();}
void load_map_hit_asset(void) { u32 assetSize; MapSettings* map = get_current_map_settings(); void* compressedData = load_asset_by_name(wMapHitName, &assetSize); HitFile* uncompressedData = heap_malloc(assetSize);
decode_yay0(compressedData, uncompressedData); general_heap_free(compressedData);
map->hitAssetCollisionOffset = uncompressedData->collisionOffset; map->hitAssetZoneOffset = uncompressedData->zoneOffset;
load_hit_data(0, uncompressedData); // Colliders load_hit_data(1, uncompressedData); // Zones
heap_free(uncompressedData);}
void restore_map_collision_data(void) { CollisionData* collisionData; Collider* collider; ColliderBackupEntry* backupEntry; s32 i;
load_map_hit_asset();
collisionData = &gCollisionData; for (i = 0, backupEntry = gCollisionDataBackup; i < collisionData->numColliders; i++, backupEntry++) { collider = &collisionData->colliderList[i]; collider->flags = backupEntry->flags; collider->parentModelIndex = backupEntry->parentModelIndex;
if (collider->flags != -1 && collider->flags & COLLIDER_FLAG_HAS_MODEL_PARENT) { parent_collider_to_model(i, collider->parentModelIndex); update_collider_transform(i); } }
collisionData = &gZoneCollisionData; for (i = 0, backupEntry = gCollisionDataZoneBackup; i < collisionData->numColliders; i++, backupEntry++) { collider = &collisionData->colliderList[i]; collider->flags = backupEntry->flags; collider->parentModelIndex = backupEntry->parentModelIndex; }
general_heap_free(gCollisionDataBackup); general_heap_free(gCollisionDataZoneBackup);}
void load_battle_hit_asset(const char* hitName) { if (hitName == nullptr) { gCollisionData.numColliders = 0; } else { u32 assetSize; MapSettings* map = get_current_map_settings(); void* compressedData = load_asset_by_name(hitName, &assetSize); HitFile* uncompressedData = heap_malloc(assetSize);
decode_yay0(compressedData, uncompressedData); general_heap_free(compressedData);
map->hitAssetCollisionOffset = uncompressedData->collisionOffset;
load_hit_data(0, uncompressedData);
heap_free(uncompressedData); }}
void load_hit_data(s32 idx, HitFile* hit) { s32 collisionOffset; MapSettings* map; CollisionData* collisionData; HitFileHeader* assetCollisionData; Vec3f* vertices; Vec3s* assetVertices; u32* boundingBox; u32* assetBoundingBox; Collider* collider; HitAssetCollider* assetCollider; ColliderTriangle* triangle; s32* trianglePacked; s16 numTriangles; s32 i, j; f32 e13Y, e21Z, e13Z, e21Y, e21X, e13X, normalX, normalY, normalZ, coeff;
assetCollisionData = nullptr; collisionData = nullptr;
map = get_current_map_settings();
switch (idx) { case 0: // Colliders collisionOffset = map->hitAssetCollisionOffset; if (collisionOffset == 0) { return; }
assetCollisionData = (HitFileHeader*) ((void*) hit + collisionOffset); collisionData = &gCollisionData; break; case 1: // Zones collisionOffset = map->hitAssetZoneOffset; if (collisionOffset == 0) { return; }
assetCollisionData = (HitFileHeader*) ((void*) hit + collisionOffset); collisionData = &gZoneCollisionData; break; }
assetBoundingBox = (u32*) ((void*) hit + assetCollisionData->boundingBoxesOffset); collisionData->aabbs = collision_heap_malloc(assetCollisionData->boundingBoxesDataSize * 4); for (i = 0, boundingBox = (u32*) (collisionData->aabbs); i < assetCollisionData->boundingBoxesDataSize; assetBoundingBox++, boundingBox++, i++) { *boundingBox = *assetBoundingBox; }
assetVertices = (Vec3s*) ((void*) hit + assetCollisionData->verticesOffset); collisionData->vertices = collision_heap_malloc(assetCollisionData->numVertices * sizeof(Vec3f)); for (i = 0, vertices = collisionData->vertices; i < assetCollisionData->numVertices; vertices++, assetVertices++, i++) { vertices->x = assetVertices->x; vertices->y = assetVertices->y; vertices->z = assetVertices->z; }
assetCollider = (HitAssetCollider*) ((void*) hit + assetCollisionData->collidersOffset); collider = collisionData->colliderList = collision_heap_malloc(assetCollisionData->numColliders * sizeof(Collider)); collisionData->numColliders = assetCollisionData->numColliders; for (i = 0; i < assetCollisionData->numColliders; assetCollider++, collider++, i++) { collider->flags = 0; collider->nextSibling = assetCollider->nextSibling; collider->firstChild = assetCollider->firstChild; collider->numTriangles = assetCollider->numTriangles;
numTriangles = collider->numTriangles;
if (numTriangles) { collider->triangleTable = triangle = collision_heap_malloc(assetCollider->numTriangles * sizeof(ColliderTriangle));
if (assetCollider->boundingBoxOffset < 0) { collider->aabb = nullptr; } else { collider->aabb = (ColliderBoundingBox*) ((u32*) (collisionData->aabbs) + assetCollider->boundingBoxOffset);
if (idx == 0) { collider->aabb->min.x -= 1; collider->aabb->min.y -= 1; collider->aabb->min.z -= 1; collider->aabb->max.x += 1; collider->aabb->max.y += 1; collider->aabb->max.z += 1; collider->flags = collider->aabb->flagsForCollider; } }
trianglePacked = (s32*) ((void*) hit + assetCollider->trianglesOffset);
for (j = 0; j < assetCollider->numTriangles; trianglePacked++, triangle++, j++) { Vec3f* v1 = triangle->v1 = &collisionData->vertices[(*trianglePacked) & 0x3FF]; Vec3f* v2 = triangle->v2 = &collisionData->vertices[(*trianglePacked >> 10) & 0x3FF]; Vec3f* v3 = triangle->v3 = &collisionData->vertices[(*trianglePacked >> 20) & 0x3FF]; triangle->oneSided = (*trianglePacked >> 30) & 1;
triangle->e13.x = v3->x - v1->x; triangle->e13.y = v3->y - v1->y; triangle->e13.z = v3->z - v1->z; triangle->e21.x = v1->x - v2->x; triangle->e21.y = v1->y - v2->y; triangle->e21.z = v1->z - v2->z; triangle->e32.x = v2->x - v3->x; triangle->e32.y = v2->y - v3->y; triangle->e32.z = v2->z - v3->z;
e13X = triangle->e13.x; e13Y = triangle->e13.y; e13Z = triangle->e13.z; e21X = triangle->e21.x; e21Y = triangle->e21.y; e21Z = triangle->e21.z;
// cross product normalX = e13Y * e21Z - e13Z * e21Y; normalY = e13Z * e21X - e13X * e21Z; normalZ = e13X * e21Y - e13Y * e21X; coeff = SQ(normalX) + SQ(normalY) + SQ(normalZ);
if (coeff != 0) { coeff = 1.0f / sqrtf(coeff); } else { coeff = 0.0f; }
triangle->normal.x = normalX * coeff; triangle->normal.y = normalY * coeff; triangle->normal.z = normalZ * coeff; } } }}
void parent_collider_to_model(s16 colliderID, s16 modelIndex) { Collider* collider; ColliderTriangle* triangle; s32 i; Vec3f** vertexBuffer; Vec3f** vertexPtr; s32 vertexBufferSize; Vec3f* vertexTable; Vec3f* vertex;
collider = &gCollisionData.colliderList[colliderID]; collider->parentModelIndex = modelIndex; collider->flags |= COLLIDER_FLAG_HAS_MODEL_PARENT;
vertexBuffer = collision_heap_malloc(collider->numTriangles * sizeof(Vec3f)); vertexBufferSize = 0; vertexPtr = vertexBuffer;
for (i = 0, triangle = collider->triangleTable; i < collider->numTriangles; i++, triangle++) { _add_hit_vert_to_buffer(vertexBuffer, triangle->v1, &vertexBufferSize); _add_hit_vert_to_buffer(vertexBuffer, triangle->v2, &vertexBufferSize); _add_hit_vert_to_buffer(vertexBuffer, triangle->v3, &vertexBufferSize); }
collider->numVertices = vertexBufferSize; collider->vertexTable = collision_heap_malloc(vertexBufferSize * 2 * sizeof(Vec3f)); for (i = 0, vertexTable = collider->vertexTable; i < vertexBufferSize; vertexPtr++, vertexTable += 2, i++) { vertex = *vertexPtr; vertexTable[0].x = vertexTable[1].x = vertex->x; vertexTable[0].y = vertexTable[1].y = vertex->y; vertexTable[0].z = vertexTable[1].z = vertex->z; }
vertexTable = collider->vertexTable; for (i = 0, triangle = collider->triangleTable; i < collider->numTriangles; triangle++, i++) { triangle->v1 = &vertexTable[_get_hit_vert_index_from_buffer(vertexBuffer, triangle->v1, &vertexBufferSize) * 2]; triangle->v2 = &vertexTable[_get_hit_vert_index_from_buffer(vertexBuffer, triangle->v2, &vertexBufferSize) * 2]; triangle->v3 = &vertexTable[_get_hit_vert_index_from_buffer(vertexBuffer, triangle->v3, &vertexBufferSize) * 2]; }
collision_heap_free(vertexBuffer);}
void _add_hit_vert_to_buffer(Vec3f** buf, Vec3f* vert, s32* bufSize) { s32 i;
for (i = 0; i < *bufSize; i++) { if (buf[i] == vert) { break; } }
if (i == *bufSize) { buf[i] = vert; (*bufSize)++; }}
s32 _get_hit_vert_index_from_buffer(Vec3f** buffer, Vec3f* vert, s32* bufferSize) { s32 i;
for (i = 0; i < *bufferSize; i++) { if (*buffer == vert) { break; } buffer++; }
return i;}
void update_collider_transform(s16 colliderID) { Collider* collider; struct Model* model; Matrix4f matrix; s32 i; Vec3f* vertexTable; f32 minX, minY, minZ, maxX, maxY, maxZ; ColliderTriangle* triangle; f32 e13Y, e21Z, e13Z, e21Y, e21X, e13X, normalX, normalY, normalZ, coeff;
collider = &gCollisionData.colliderList[colliderID]; model = get_model_from_list_index(collider->parentModelIndex);
if (model->bakedMtx == nullptr) { copy_matrix(model->userTransformMtx, matrix); } else { guMtxL2F(matrix, model->bakedMtx); guMtxCatF(model->userTransformMtx, matrix, matrix); }
triangle = collider->triangleTable; vertexTable = collider->vertexTable;
minX = minY = minZ = 999999.9f; maxX = maxY = maxZ = -999999.9f;
for (i = 0; i < collider->numVertices; vertexTable += 2, i++) { guMtxXFMF( matrix, vertexTable[1].x, vertexTable[1].y, vertexTable[1].z, &vertexTable[0].x, &vertexTable[0].y, &vertexTable[0].z );
if (vertexTable[0].x < minX) minX = vertexTable[0].x; if (vertexTable[0].x > maxX) maxX = vertexTable[0].x; if (vertexTable[0].y < minY) minY = vertexTable[0].y; if (vertexTable[0].y > maxY) maxY = vertexTable[0].y; if (vertexTable[0].z < minZ) minZ = vertexTable[0].z; if (vertexTable[0].z > maxZ) maxZ = vertexTable[0].z; }
collider->aabb->min.x = minX; collider->aabb->min.y = minY; collider->aabb->min.z = minZ; collider->aabb->max.x = maxX; collider->aabb->max.y = maxY; collider->aabb->max.z = maxZ;
for (i = 0; i < collider->numTriangles; triangle++, i++) { Vec3f* v1 = triangle->v1; Vec3f* v2 = triangle->v2; Vec3f* v3 = triangle->v3;
triangle->e13.x = v3->x - v1->x; triangle->e13.y = v3->y - v1->y; triangle->e13.z = v3->z - v1->z; triangle->e21.x = v1->x - v2->x; triangle->e21.y = v1->y - v2->y; triangle->e21.z = v1->z - v2->z; triangle->e32.x = v2->x - v3->x; triangle->e32.y = v2->y - v3->y; triangle->e32.z = v2->z - v3->z;
e13X = triangle->e13.x; e13Y = triangle->e13.y; e13Z = triangle->e13.z; e21X = triangle->e21.x; e21Y = triangle->e21.y; e21Z = triangle->e21.z;
// vector product normalX = e13Y * e21Z - e13Z * e21Y; normalY = e13Z * e21X - e13X * e21Z; normalZ = e13X * e21Y - e13Y * e21X; coeff = SQ(normalX) + SQ(normalY) + SQ(normalZ);
if (coeff != 0) { coeff = 1.0f / sqrtf(coeff); } else { coeff = 0.0f; }
triangle->normal.x = normalX * coeff; triangle->normal.y = normalY * coeff; triangle->normal.z = normalZ * coeff; }}
s32 get_collider_flags(s32 colliderID) { if (colliderID & COLLISION_WITH_ENTITY_BIT) { return 0; } else { return gCollisionData.colliderList[colliderID].flags; }}
void get_flat_collider_normal(s32 colliderID, f32* x, f32* y, f32* z) { ColliderTriangle* triangle = &gCollisionData.colliderList[colliderID].triangleTable[0];
*x = triangle->normal.x; *y = triangle->normal.y; *z = triangle->normal.z;}
void get_collider_center(s32 colliderID, f32* x, f32* y, f32* z) { ColliderBoundingBox* aabb = gCollisionData.colliderList[colliderID].aabb;
*x = (aabb->min.x + aabb->max.x) * 0.5f; *y = (aabb->min.y + aabb->max.y) * 0.5f; *z = (aabb->min.z + aabb->max.z) * 0.5f;}
s32 test_ray_triangle_general(ColliderTriangle* triangle, Vec3f* vertices) { f32 distToTrianglePlane; f32 cosAngle; Vec3f* v1; Vec3f* v2; Vec3f* v3;
if (triangle->normal.x == 0 && triangle->normal.y == 0 && triangle->normal.z == 0) return false;
v1 = triangle->v1; v2 = triangle->v2; v3 = triangle->v3;
distToTrianglePlane = triangle->normal.x * (gCollisionRayStartX - v1->x) + triangle->normal.y * (gCollisionRayStartY - v1->y) + triangle->normal.z * (gCollisionRayStartZ - v1->z);
if (triangle->oneSided) { if (distToTrianglePlane < 0) { return false; }
if (triangle->normal.x * gCollisionRayDirX + triangle->normal.y * gCollisionRayDirY + triangle->normal.z * gCollisionRayDirZ >= 0) { return false; }
if ((gCollisionRayStartX - v1->x) * (triangle->e13.z * gCollisionRayDirY - triangle->e13.y * gCollisionRayDirZ) + (gCollisionRayStartY - v1->y) * (triangle->e13.x * gCollisionRayDirZ - triangle->e13.z * gCollisionRayDirX) + (gCollisionRayStartZ - v1->z) * (triangle->e13.y * gCollisionRayDirX - triangle->e13.x * gCollisionRayDirY) < 0) { return false; }
if ((gCollisionRayStartX - v2->x) * (triangle->e21.z * gCollisionRayDirY - triangle->e21.y * gCollisionRayDirZ) + (gCollisionRayStartY - v2->y) * (triangle->e21.x * gCollisionRayDirZ - triangle->e21.z * gCollisionRayDirX) + (gCollisionRayStartZ - v2->z) * (triangle->e21.y * gCollisionRayDirX - triangle->e21.x * gCollisionRayDirY) < 0) { return false; }
if ((gCollisionRayStartX - v3->x) * (triangle->e32.z * gCollisionRayDirY - triangle->e32.y * gCollisionRayDirZ) + (gCollisionRayStartY - v3->y) * (triangle->e32.x * gCollisionRayDirZ - triangle->e32.z * gCollisionRayDirX) + (gCollisionRayStartZ - v3->z) * (triangle->e32.y * gCollisionRayDirX - triangle->e32.x * gCollisionRayDirY) < 0) { return false; } } else { if ((triangle->normal.x * gCollisionRayDirX + triangle->normal.y * gCollisionRayDirY + triangle->normal.z * gCollisionRayDirZ) * distToTrianglePlane >= 0) { return false; }
if (((gCollisionRayStartX - v1->x) * (triangle->e13.z * gCollisionRayDirY - triangle->e13.y * gCollisionRayDirZ) + (gCollisionRayStartY - v1->y) * (triangle->e13.x * gCollisionRayDirZ - triangle->e13.z * gCollisionRayDirX) + (gCollisionRayStartZ - v1->z) * (triangle->e13.y * gCollisionRayDirX - triangle->e13.x * gCollisionRayDirY)) * distToTrianglePlane < 0) { return false; }
if (((gCollisionRayStartX - v2->x) * (triangle->e21.z * gCollisionRayDirY - triangle->e21.y * gCollisionRayDirZ) + (gCollisionRayStartY - v2->y) * (triangle->e21.x * gCollisionRayDirZ - triangle->e21.z * gCollisionRayDirX) + (gCollisionRayStartZ - v2->z) * (triangle->e21.y * gCollisionRayDirX - triangle->e21.x * gCollisionRayDirY)) * distToTrianglePlane < 0) { return false; }
if (((gCollisionRayStartX - v3->x) * (triangle->e32.z * gCollisionRayDirY - triangle->e32.y * gCollisionRayDirZ) + (gCollisionRayStartY - v3->y) * (triangle->e32.x * gCollisionRayDirZ - triangle->e32.z * gCollisionRayDirX) + (gCollisionRayStartZ - v3->z) * (triangle->e32.y * gCollisionRayDirX - triangle->e32.x * gCollisionRayDirY)) * distToTrianglePlane < 0) { return false; } }
cosAngle = triangle->normal.x * gCollisionRayDirX + triangle->normal.y * gCollisionRayDirY + triangle->normal.z * gCollisionRayDirZ; if (gCollisionRayLength >= 0 && gCollisionRayLength <= -distToTrianglePlane / cosAngle) { return false; }
gCollisionRayLength = -distToTrianglePlane / cosAngle;
gCollisionPointX = gCollisionRayStartX + gCollisionRayDirX * gCollisionRayLength; gCollisionPointY = gCollisionRayStartY + gCollisionRayDirY * gCollisionRayLength; gCollisionPointZ = gCollisionRayStartZ + gCollisionRayDirZ * gCollisionRayLength;
gCollisionNormalX = triangle->normal.x; gCollisionNormalY = triangle->normal.y; gCollisionNormalZ = triangle->normal.z;
return true;}
s32 test_ray_triangle_down(ColliderTriangle* triangle, Vec3f* vertices) { f32 distToTrianglePlane, cosAngle; Vec3f* v1; Vec3f* v2; Vec3f* v3;
if (triangle->normal.x == 0 && triangle->normal.y == 0 && triangle->normal.z == 0) { return false; }
v1 = triangle->v1; v2 = triangle->v2; v3 = triangle->v3;
distToTrianglePlane = triangle->normal.x * (gCollisionRayStartX - v1->x) + triangle->normal.y * (gCollisionRayStartY - v1->y) + triangle->normal.z * (gCollisionRayStartZ - v1->z);
if (triangle->oneSided) { if (distToTrianglePlane < 0) { return false; }
if (triangle->normal.y <= 0) return false;
if ((gCollisionRayStartZ - v1->z) * triangle->e13.x - (gCollisionRayStartX - v1->x) * triangle->e13.z < 0) { return false; }
if ((gCollisionRayStartZ - v2->z) * triangle->e21.x - (gCollisionRayStartX - v2->x) * triangle->e21.z < 0) { return false; }
if ((gCollisionRayStartZ - v3->z) * triangle->e32.x - (gCollisionRayStartX - v3->x) * triangle->e32.z < 0) { return false; } } else { if (triangle->normal.y * distToTrianglePlane <= 0) { return false; }
if (((gCollisionRayStartZ - v1->z) * triangle->e13.x - (gCollisionRayStartX - v1->x) * triangle->e13.z) * distToTrianglePlane < 0) { return false; }
if (((gCollisionRayStartZ - v2->z) * triangle->e21.x - (gCollisionRayStartX - v2->x) * triangle->e21.z) * distToTrianglePlane < 0) { return false; }
if (((gCollisionRayStartZ - v3->z) * triangle->e32.x - (gCollisionRayStartX - v3->x) * triangle->e32.z) * distToTrianglePlane < 0) { return false; } }
cosAngle = -triangle->normal.y; if (gCollisionRayLength >= 0 && gCollisionRayLength <= -distToTrianglePlane / cosAngle) { return false; }
gCollisionRayLength = -distToTrianglePlane / cosAngle;
gCollisionPointX = gCollisionRayStartX; gCollisionPointY = gCollisionRayStartY - gCollisionRayLength; gCollisionPointZ = gCollisionRayStartZ;
gCollisionNormalX = triangle->normal.x; gCollisionNormalY = triangle->normal.y; gCollisionNormalZ = triangle->normal.z;
return true;}
s32 test_ray_triangle_horizontal(ColliderTriangle* triangle, Vec3f* vertices) { f32 distToTrianglePlane, cosAngle; Vec3f* v1; Vec3f* v2; Vec3f* v3;
if (triangle->normal.x == 0 && triangle->normal.y == 0 && triangle->normal.z == 0) { return false; }
v1 = triangle->v1; v2 = triangle->v2; v3 = triangle->v3;
distToTrianglePlane = triangle->normal.x * (gCollisionRayStartX - v1->x) + triangle->normal.y * (gCollisionRayStartY - v1->y) + triangle->normal.z * (gCollisionRayStartZ - v1->z);
if (triangle->oneSided) { if (distToTrianglePlane < 0) { return false; }
if (triangle->normal.x * gCollisionRayDirX + triangle->normal.z * gCollisionRayDirZ >= 0) { return false; }
if ((gCollisionRayStartX - v1->x) * (-triangle->e13.y * gCollisionRayDirZ) + (gCollisionRayStartY - v1->y) * (triangle->e13.x * gCollisionRayDirZ - triangle->e13.z * gCollisionRayDirX) + (gCollisionRayStartZ - v1->z) * (triangle->e13.y * gCollisionRayDirX) < 0) { return false; }
if ((gCollisionRayStartX - v2->x) * (-triangle->e21.y * gCollisionRayDirZ) + (gCollisionRayStartY - v2->y) * (triangle->e21.x * gCollisionRayDirZ - triangle->e21.z * gCollisionRayDirX) + (gCollisionRayStartZ - v2->z) * (triangle->e21.y * gCollisionRayDirX) < 0) { return false; }
if ((gCollisionRayStartX - v3->x) * (-triangle->e32.y * gCollisionRayDirZ) + (gCollisionRayStartY - v3->y) * (triangle->e32.x * gCollisionRayDirZ - triangle->e32.z * gCollisionRayDirX) + (gCollisionRayStartZ - v3->z) * (triangle->e32.y * gCollisionRayDirX) < 0) { return false; } } else { if ((triangle->normal.x * gCollisionRayDirX + triangle->normal.z * gCollisionRayDirZ) * distToTrianglePlane >= 0) { return false; }
if (((gCollisionRayStartX - v1->x) * (-triangle->e13.y * gCollisionRayDirZ) + (gCollisionRayStartY - v1->y) * (triangle->e13.x * gCollisionRayDirZ - triangle->e13.z * gCollisionRayDirX) + (gCollisionRayStartZ - v1->z) * (triangle->e13.y * gCollisionRayDirX)) * distToTrianglePlane < 0) { return false; }
if (((gCollisionRayStartX - v2->x) * (-triangle->e21.y * gCollisionRayDirZ) + (gCollisionRayStartY - v2->y) * (triangle->e21.x * gCollisionRayDirZ - triangle->e21.z * gCollisionRayDirX) + (gCollisionRayStartZ - v2->z) * (triangle->e21.y * gCollisionRayDirX)) * distToTrianglePlane < 0) { return false; }
if (((gCollisionRayStartX - v3->x) * (-triangle->e32.y * gCollisionRayDirZ) + (gCollisionRayStartY - v3->y) * (triangle->e32.x * gCollisionRayDirZ - triangle->e32.z * gCollisionRayDirX) + (gCollisionRayStartZ - v3->z) * (triangle->e32.y * gCollisionRayDirX)) * distToTrianglePlane < 0) { return false; } }
cosAngle = triangle->normal.x * gCollisionRayDirX + triangle->normal.z * gCollisionRayDirZ; if (gCollisionRayLength >= 0 && gCollisionRayLength <= -distToTrianglePlane / cosAngle) { return false; }
gCollisionRayLength = -distToTrianglePlane / cosAngle;
gCollisionPointX = gCollisionRayStartX + gCollisionRayDirX * gCollisionRayLength; gCollisionPointY = gCollisionRayStartY; gCollisionPointZ = gCollisionRayStartZ + gCollisionRayDirZ * gCollisionRayLength;
gCollisionNormalX = triangle->normal.x; gCollisionNormalY = triangle->normal.y; gCollisionNormalZ = triangle->normal.z;
return true;}
s32 test_ray_colliders( s32 ignoreFlags, f32 startX, f32 startY, f32 startZ, f32 dirX, f32 dirY, f32 dirZ, f32* hitX, f32* hitY, f32* hitZ, f32* hitDepth, f32* hitNx, f32* hitNy, f32* hitNz) { Collider* collider; CollisionData* collisionData; ColliderTriangle* triangle; s32 i, j; s32 colliderID; f32 minX, minY, minZ, maxX, maxY, maxZ;
if (dirX == 0 && dirY == 0 && dirZ == 0) { return 0; }
collisionData = &gCollisionData; gCollisionRayDirX = dirX; gCollisionRayDirY = dirY; gCollisionRayDirZ = dirZ; gCollisionRayStartX = startX; gCollisionRayStartY = startY; gCollisionRayStartZ = startZ; gCollisionRayLength = *hitDepth; colliderID = NO_COLLIDER;
if (dirX < 0) { minX = startX + dirX * gCollisionRayLength; maxX = startX; } else { minX = startX; maxX = startX + dirX * gCollisionRayLength; }
if (dirY < 0) { minY = startY + dirY * gCollisionRayLength; maxY = startY; } else { minY = startY; maxY = startY + dirY * gCollisionRayLength; }
if (dirZ < 0) { minZ = startZ + dirZ * gCollisionRayLength; maxZ = startZ; } else { minZ = startZ; maxZ = startZ + dirZ * gCollisionRayLength; }
for (i = 0; i < collisionData->numColliders; i++) { collider = &collisionData->colliderList[i];
if ((collider->flags & ignoreFlags) || collider->numTriangles == 0 || maxX < collider->aabb->min.x || minX > collider->aabb->max.x || maxZ < collider->aabb->min.z || minZ > collider->aabb->max.z || maxY < collider->aabb->min.y || minY > collider->aabb->max.y) { continue; }
triangle = collider->triangleTable; if (gCollisionRayDirX == 0 && gCollisionRayDirZ == 0 && gCollisionRayDirY == -1.0) { for (j = 0; j < collider->numTriangles; j++) { if (test_ray_triangle_down(triangle++, collisionData->vertices)) { colliderID = i; } } } else if (gCollisionRayDirY == 0) { for (j = 0; j < collider->numTriangles; j++) { if (test_ray_triangle_horizontal(triangle++, collisionData->vertices)) { colliderID = i; } } } else { for (j = 0; j < collider->numTriangles; j++) { if (test_ray_triangle_general(triangle++, collisionData->vertices)) { colliderID = i; } } } }
if (colliderID > NO_COLLIDER) { *hitX = gCollisionPointX; *hitY = gCollisionPointY; *hitZ = gCollisionPointZ; *hitDepth = gCollisionRayLength; *hitNx = gCollisionNormalX; *hitNy = gCollisionNormalY; *hitNz = gCollisionNormalZ; return colliderID; } else { return colliderID; }}
s32 test_ray_zones( f32 startX, f32 startY, f32 startZ, f32 dirX, f32 dirY, f32 dirZ, f32* hitX, f32* hitY, f32* hitZ, f32* hitDepth, f32* hitNx, f32* hitNy, f32* hitNz) { Collider* collider; CollisionData* collisionData; ColliderTriangle* triangle; s32 i, j; s32 colliderID;
collisionData = &gZoneCollisionData; gCollisionRayDirX = dirX; gCollisionRayDirY = dirY; gCollisionRayDirZ = dirZ; gCollisionRayStartX = startX; gCollisionRayStartY = startY; gCollisionRayStartZ = startZ; gCollisionRayLength = *hitDepth; colliderID = NO_COLLIDER;
for (i = 0; i < collisionData->numColliders; i++) { collider = &collisionData->colliderList[i];
if (collider->flags & COLLIDER_FLAG_IGNORE_PLAYER) continue;
if (collider->numTriangles == 0 || collider->aabb == nullptr) continue;
triangle = collider->triangleTable; for (j = 0; j < collider->numTriangles; j++) { if (test_ray_triangle_down(triangle++, collisionData->vertices)) { colliderID = i; } } }
if (colliderID > NO_COLLIDER) { *hitX = gCollisionPointX; *hitY = gCollisionPointY; *hitZ = gCollisionPointZ; *hitDepth = gCollisionRayLength; *hitNx = gCollisionNormalX; *hitNy = gCollisionNormalY; *hitNz = gCollisionNormalZ; return colliderID; } else { return colliderID; }}
f32 test_ray_collider_horizontal(s32 ignoreFlags, s32 colliderID, f32 x, f32 y, f32 z, f32 length, f32 yaw) { CollisionData* collisionData = &gCollisionData; f32 cosTheta; f32 sinTheta; Collider* collider; ColliderTriangle* triangleTable; s32 i; f32 ret;
sin_cos_rad(DEG_TO_RAD(yaw), &sinTheta, &cosTheta); collider = &collisionData->colliderList[colliderID];
gCollisionRayDirY = 0; gCollisionRayStartX = x; gCollisionRayStartY = y; gCollisionRayStartZ = z; gCollisionRayLength = length; gCollisionRayDirX = sinTheta; gCollisionRayDirZ = -cosTheta; ret = -1.0f;
if (!(collider->flags & ignoreFlags) && collider->numTriangles != 0) { triangleTable = collider->triangleTable;
for (i = 0; i < collider->numTriangles; i++) if (test_ray_triangle_horizontal(triangleTable++, collisionData->vertices)) ret = gCollisionRayLength; }
return ret;}
s32 test_ray_entities( f32 startX, f32 startY, f32 startZ, f32 dirX, f32 dirY, f32 dirZ, f32* hitX, f32* hitY, f32* hitZ, f32* hitDepth, f32* hitNx, f32* hitNy, f32* hitNz) { f32 hitDepthDown, hitDepthHoriz; s32 type; s32 i, j; Entity* entity; Matrix4f tempMatrix1; Matrix4f tempMatrix2; Vec3f boxVertices[8]; ColliderTriangle entityTriangle; s32 entityIndex; f32 h; f32 aabbX, aabbZ; s32 hasCollision; f32 dist, dist2; ColliderTriangle* triangle = &entityTriangle;
enum { ENTITY_TEST_ANY = 0, ENTITY_TEST_DOWN = 1, ENTITY_TEST_LATERAL = 2, };
entityIndex = NO_COLLIDER; type = ENTITY_TEST_ANY; hitDepthDown = hitDepthHoriz = *hitDepth;
if (dirX == 0 && dirZ == 0 && dirY < 0) { hitDepthHoriz = 0; type = ENTITY_TEST_DOWN; } else if (dirY == 0) { hitDepthDown = 0; type = ENTITY_TEST_LATERAL; }
gCollisionRayLength = -1; triangle->oneSided = true; for (i = 0; i < MAX_ENTITIES; i++) { entity = get_entity_by_index(i);
if (entity == nullptr || (entity->flags & (ENTITY_FLAG_SKIP_UPDATE | ENTITY_FLAG_DISABLE_COLLISION))) { continue; }
dist = hitDepthHoriz + entity->effectiveSize; if (startX > entity->pos.x + dist || startX < entity->pos.x - dist) { continue; }
if (startZ > entity->pos.z + dist || startZ < entity->pos.z - dist) { continue; }
switch (type) { case ENTITY_TEST_ANY: case ENTITY_TEST_DOWN: dist = entity->pos.y; dist2 = hitDepthDown + entity->effectiveSize * 2; if (dist + dist2 < startY || startY < dist - dist2) { continue; } break; case ENTITY_TEST_LATERAL: dist = entity->pos.y; dist2 = entity->effectiveSize * 2; if (dist + dist2 < startY || startY < dist - dist2) { continue; } break; }
aabbX = entity->aabb.x / 2; aabbZ = entity->aabb.z / 2;
boxVertices[1].x = boxVertices[2].x = boxVertices[5].x = boxVertices[6].x = -aabbX; boxVertices[0].x = boxVertices[3].x = boxVertices[4].x = boxVertices[7].x = aabbX; boxVertices[0].y = boxVertices[1].y = boxVertices[2].y = boxVertices[3].y = 0; boxVertices[4].y = boxVertices[5].y = boxVertices[6].y = boxVertices[7].y = entity->aabb.y; boxVertices[0].z = boxVertices[1].z = boxVertices[4].z = boxVertices[5].z = aabbZ; boxVertices[2].z = boxVertices[3].z = boxVertices[6].z = boxVertices[7].z = -aabbZ;
guMtxXFMF( entity->inverseTransformMatrix, dirX, dirY, dirZ, &gCollisionRayDirX, &gCollisionRayDirY, &gCollisionRayDirZ ); guMtxXFMF( entity->inverseTransformMatrix, startX - entity->pos.x, startY - entity->pos.y, startZ - entity->pos.z, &gCollisionRayStartX, &gCollisionRayStartY, &gCollisionRayStartZ );
for (j = 0; j < 12; j++) { Vec3f* v1 = triangle->v1 = &boxVertices[gEntityColliderFaces[j].x]; Vec3f* v2 = triangle->v2 = &boxVertices[gEntityColliderFaces[j].y]; Vec3f* v3 = triangle->v3 = &boxVertices[gEntityColliderFaces[j].z]; triangle->e13.x = v3->x - v1->x; triangle->e13.y = v3->y - v1->y; triangle->e13.z = v3->z - v1->z; triangle->e21.x = v1->x - v2->x; triangle->e21.y = v1->y - v2->y; triangle->e21.z = v1->z - v2->z; triangle->e32.x = v2->x - v3->x; triangle->e32.y = v2->y - v3->y; triangle->e32.z = v2->z - v3->z; triangle->normal.x = gEntityColliderNormals[j].x; triangle->normal.y = gEntityColliderNormals[j].y; triangle->normal.z = gEntityColliderNormals[j].z;
hasCollision = test_ray_triangle_general(&entityTriangle, boxVertices); if (hasCollision) { break; } }
if (hasCollision && gCollisionRayLength < *hitDepth) { entityIndex = i; *hitDepth = gCollisionRayLength;
switch (type) { case ENTITY_TEST_ANY: hitDepthDown = gCollisionRayLength; hitDepthHoriz = gCollisionRayLength; break; case ENTITY_TEST_DOWN: hitDepthDown = gCollisionRayLength; break; case ENTITY_TEST_LATERAL: hitDepthHoriz = gCollisionRayLength; break; }
guRotateF(tempMatrix1, entity->rot.x, 1.0f, 0.0f, 0.0f); guRotateF(tempMatrix2, entity->rot.z, 0.0f, 0.0f, 1.0f); guMtxCatF(tempMatrix1, tempMatrix2, tempMatrix1); guRotateF(tempMatrix2, entity->rot.y, 0.0f, 1.0f, 0.0f); guMtxCatF(tempMatrix1, tempMatrix2, tempMatrix1); guTranslateF(tempMatrix2, entity->pos.x, entity->pos.y, entity->pos.z); guMtxCatF(tempMatrix1, tempMatrix2, tempMatrix1); guMtxXFMF(tempMatrix1, gCollisionPointX, gCollisionPointY, gCollisionPointZ, hitX, hitY, hitZ);
h = 1.0f / sqrtf(SQ(gCollisionNormalX) + SQ(gCollisionNormalY) + SQ(gCollisionNormalZ)); *hitNx = gCollisionNormalX * h; *hitNy = gCollisionNormalY * h; *hitNz = gCollisionNormalZ * h; } }
return entityIndex;}