2022-01-08 11:11:20 +01:00
|
|
|
#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 */ s16 unk_06;
|
|
|
|
} ColliderBackupEntry; // size = 0x08
|
|
|
|
|
|
|
|
typedef struct HitFileHeader {
|
|
|
|
/* 0x00 */ s16 numColliders;
|
|
|
|
/* 0x02 */ s16 unk_02;
|
|
|
|
/* 0x04 */ s32 collidersOffset;
|
|
|
|
/* 0x08 */ s16 numVertices;
|
|
|
|
/* 0x0A */ s16 unk_0a;
|
|
|
|
/* 0x0C */ s32 verticesOffset;
|
|
|
|
/* 0x10 */ s16 boundingBoxesDataSize;
|
|
|
|
/* 0x12 */ s16 unk_12;
|
|
|
|
/* 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
|
|
|
|
|
|
|
|
typedef struct VertexIndexStruct {
|
|
|
|
/* 0x00 */ s16 i1;
|
|
|
|
/* 0x02 */ s16 i2;
|
|
|
|
/* 0x04 */ s16 i3;
|
|
|
|
} VertexIndexStruct; // size = 0x06
|
|
|
|
|
|
|
|
extern VertexIndexStruct gEntityColliderFaces[];
|
|
|
|
extern Vec3f gEntityColliderNormals[];
|
|
|
|
extern f32 gCollisionRayStartX;
|
|
|
|
extern f32 gCollisionRayStartY;
|
|
|
|
extern f32 gCollisionRayStartZ;
|
|
|
|
extern f32 gCollisionRayDirX;
|
|
|
|
extern f32 gCollisionRayDirY;
|
|
|
|
extern f32 gCollisionRayDirZ;
|
|
|
|
extern f32 gCollisionPointX;
|
|
|
|
extern f32 gCollisionPointY;
|
|
|
|
extern f32 gCollisionPointZ;
|
|
|
|
extern f32 gCollisionRayLength;
|
|
|
|
extern f32 gCollisionNormalX;
|
|
|
|
extern f32 gCollisionNormalY;
|
|
|
|
extern f32 gCollisionNormalZ;
|
|
|
|
extern ColliderBackupEntry* gCollisionDataBackup;
|
|
|
|
extern ColliderBackupEntry* gCollisionDataZoneBackup;
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2022-03-28 11:29:47 +02:00
|
|
|
gZoneCollisionData.numColliders = 0;
|
2022-01-08 11:11:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void func_8005AF84(void) {
|
|
|
|
}
|
|
|
|
|
|
|
|
void func_8005AF8C(void) {
|
|
|
|
}
|
|
|
|
|
|
|
|
void initialize_collision(void) {
|
|
|
|
gCollisionData.numColliders = 0;
|
2022-03-28 11:29:47 +02:00
|
|
|
gZoneCollisionData.numColliders = 0;
|
2022-01-08 11:11:20 +01:00
|
|
|
collision_heap_create();
|
|
|
|
}
|
|
|
|
|
|
|
|
void load_map_hit_asset(void) {
|
|
|
|
u32 assetSize;
|
|
|
|
MapConfig* map = get_current_map_header();
|
|
|
|
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);
|
|
|
|
load_hit_data(1, uncompressedData);
|
|
|
|
|
|
|
|
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 & 0x80000000) {
|
|
|
|
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 == NULL) {
|
|
|
|
gCollisionData.numColliders = 0;
|
|
|
|
} else {
|
|
|
|
u32 assetSize;
|
|
|
|
MapConfig* map = get_current_map_header();
|
|
|
|
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;
|
|
|
|
MapConfig* 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 e13_y, e21_z, e13_z, e21_y, e21_x, e13_x, normalX, normalY, normalZ, coeff;
|
|
|
|
|
|
|
|
assetCollisionData = NULL;
|
|
|
|
collisionData = NULL;
|
|
|
|
|
|
|
|
map = get_current_map_header();
|
|
|
|
|
|
|
|
switch (idx) {
|
|
|
|
case 0:
|
|
|
|
collisionOffset = map->hitAssetCollisionOffset;
|
|
|
|
if (collisionOffset == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
assetCollisionData = (HitFileHeader*)((void*)hit + collisionOffset);
|
|
|
|
collisionData = &gCollisionData;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 1:
|
|
|
|
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 = NULL;
|
|
|
|
} 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;
|
|
|
|
|
|
|
|
e13_x = triangle->e13.x;
|
|
|
|
e13_y = triangle->e13.y;
|
|
|
|
e13_z = triangle->e13.z;
|
|
|
|
e21_x = triangle->e21.x;
|
|
|
|
e21_y = triangle->e21.y;
|
|
|
|
e21_z = triangle->e21.z;
|
|
|
|
|
|
|
|
// vector product
|
|
|
|
normalX = e13_y * e21_z - e13_z * e21_y;
|
|
|
|
normalY = e13_z * e21_x - e13_x * e21_z;
|
|
|
|
normalZ = e13_x * e21_y - e13_y * e21_x;
|
|
|
|
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 |= 0x80000000;
|
|
|
|
|
|
|
|
vertexBuffer = collision_heap_malloc(collider->numTriangles * 0xC);
|
|
|
|
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 * 0x18);
|
|
|
|
for (i = 0, vertexTable = collider->vertexTable; i < vertexBufferSize; vertexPtr++, vertexTable += 2, i++) {
|
|
|
|
vertex = *vertexPtr;
|
|
|
|
vertexTable->x = vertexTable[1].x = vertex->x;
|
|
|
|
vertexTable->y = vertexTable[1].y = vertex->y;
|
|
|
|
vertexTable->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 min_x, min_y, min_z, max_x, max_y, max_z;
|
|
|
|
ColliderTriangle* triangle;
|
|
|
|
f32 e13_y, e21_z, e13_z, e21_y, e21_x, e13_x, normalX, normalY, normalZ, coeff;
|
|
|
|
|
|
|
|
collider = &gCollisionData.colliderList[colliderID];
|
|
|
|
model = get_model_from_list_index(collider->parentModelIndex);
|
|
|
|
|
|
|
|
if (!model->currentMatrix) {
|
|
|
|
copy_matrix(model->transformMatrix, matrix);
|
|
|
|
} else {
|
|
|
|
guMtxL2F(matrix, (Mtx*)model->currentMatrix);
|
|
|
|
guMtxCatF(model->transformMatrix, matrix, matrix);
|
|
|
|
}
|
|
|
|
|
|
|
|
triangle = collider->triangleTable;
|
|
|
|
vertexTable = collider->vertexTable;
|
|
|
|
|
|
|
|
min_x = min_y = min_z = 999999.9f;
|
|
|
|
max_x = max_y = max_z = -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 < min_x)
|
|
|
|
min_x = vertexTable[0].x;
|
|
|
|
if (vertexTable[0].x > max_x)
|
|
|
|
max_x = vertexTable[0].x;
|
|
|
|
if (vertexTable[0].y < min_y)
|
|
|
|
min_y = vertexTable[0].y;
|
|
|
|
if (vertexTable[0].y > max_y)
|
|
|
|
max_y = vertexTable[0].y;
|
|
|
|
if (vertexTable[0].z < min_z)
|
|
|
|
min_z = vertexTable[0].z;
|
|
|
|
if (vertexTable[0].z > max_z)
|
|
|
|
max_z = vertexTable[0].z;
|
|
|
|
}
|
|
|
|
|
|
|
|
collider->aabb->min.x = min_x;
|
|
|
|
collider->aabb->min.y = min_y;
|
|
|
|
collider->aabb->min.z = min_z;
|
|
|
|
collider->aabb->max.x = max_x;
|
|
|
|
collider->aabb->max.y = max_y;
|
|
|
|
collider->aabb->max.z = max_z;
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
e13_x = triangle->e13.x;
|
|
|
|
e13_y = triangle->e13.y;
|
|
|
|
e13_z = triangle->e13.z;
|
|
|
|
e21_x = triangle->e21.x;
|
|
|
|
e21_y = triangle->e21.y;
|
|
|
|
e21_z = triangle->e21.z;
|
|
|
|
|
|
|
|
// vector product
|
|
|
|
normalX = e13_y * e21_z - e13_z * e21_y;
|
|
|
|
normalY = e13_z * e21_x - e13_x * e21_z;
|
|
|
|
normalZ = e13_x * e21_y - e13_y * e21_x;
|
|
|
|
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_type_by_id(s32 colliderID) {
|
|
|
|
if (colliderID & 0x4000) {
|
|
|
|
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 min_x, min_y, min_z, max_x, max_y, max_z;
|
|
|
|
|
|
|
|
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 = -1;
|
|
|
|
|
|
|
|
if (dirX < 0) {
|
|
|
|
min_x = startX + dirX * gCollisionRayLength;
|
|
|
|
max_x = startX;
|
|
|
|
} else {
|
|
|
|
min_x = startX;
|
|
|
|
max_x = startX + dirX * gCollisionRayLength;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dirY < 0) {
|
|
|
|
min_y = startY + dirY * gCollisionRayLength;
|
|
|
|
max_y = startY;
|
|
|
|
} else {
|
|
|
|
min_y = startY;
|
|
|
|
max_y = startY + dirY * gCollisionRayLength;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dirZ < 0) {
|
|
|
|
min_z = startZ + dirZ * gCollisionRayLength;
|
|
|
|
max_z = startZ;
|
|
|
|
} else {
|
|
|
|
min_z = startZ;
|
|
|
|
max_z = startZ + dirZ * gCollisionRayLength;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < collisionData->numColliders; i++) {
|
|
|
|
collider = &collisionData->colliderList[i];
|
|
|
|
|
|
|
|
if ((collider->flags & ignoreFlags) ||
|
|
|
|
collider->numTriangles == 0 ||
|
|
|
|
max_x < collider->aabb->min.x ||
|
|
|
|
min_x > collider->aabb->max.x ||
|
|
|
|
max_z < collider->aabb->min.z ||
|
|
|
|
min_z > collider->aabb->max.z ||
|
|
|
|
max_y < collider->aabb->min.y ||
|
|
|
|
min_y > 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 >= 0) {
|
|
|
|
*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 = -1;
|
|
|
|
|
|
|
|
for (i = 0; i < collisionData->numColliders; i++) {
|
|
|
|
collider = &collisionData->colliderList[i];
|
|
|
|
|
|
|
|
if (collider->flags & 0x10000)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (collider->numTriangles == 0 || collider->aabb == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
triangle = collider->triangleTable;
|
|
|
|
for (j = 0; j < collider->numTriangles; j++)
|
|
|
|
if (test_ray_triangle_down(triangle++, collisionData->vertices))
|
|
|
|
colliderID = i;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (colliderID >= 0) {
|
|
|
|
*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(yaw * TAU / 360.0f, &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;
|
|
|
|
|
|
|
|
entityIndex = -1;
|
|
|
|
type = 0;
|
|
|
|
hitDepthDown = hitDepthHoriz = *hitDepth;
|
|
|
|
|
|
|
|
if (dirX == 0 && dirZ == 0 && dirY < 0) {
|
|
|
|
hitDepthHoriz = 0;
|
|
|
|
type = 1;
|
|
|
|
} else if (dirY == 0) {
|
|
|
|
hitDepthDown = 0;
|
|
|
|
type = 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
gCollisionRayLength = -1;
|
|
|
|
triangle->oneSided = TRUE;
|
|
|
|
for (i = 0; i < MAX_ENTITIES; i++) {
|
|
|
|
entity = get_entity_by_index(i);
|
|
|
|
|
|
|
|
if (entity == NULL || (entity->flags & 0x40000020))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
dist = hitDepthHoriz + entity->effectiveSize;
|
|
|
|
if (startX > entity->position.x + dist ||
|
|
|
|
startX < entity->position.x - dist)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (startZ > entity->position.z + dist ||
|
|
|
|
startZ < entity->position.z - dist)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case 0:
|
|
|
|
case 1:
|
|
|
|
dist = entity->position.y;
|
|
|
|
dist2 = hitDepthDown + entity->effectiveSize * 2;
|
|
|
|
if (dist + dist2 < startY || startY < dist - dist2)
|
|
|
|
continue;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
dist = entity->position.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->position.x, startY - entity->position.y,
|
|
|
|
startZ - entity->position.z, &gCollisionRayStartX, &gCollisionRayStartY, &gCollisionRayStartZ);
|
|
|
|
|
|
|
|
for (j = 0; j < 12; j++) {
|
|
|
|
Vec3f* v1 = triangle->v1 = &boxVertices[gEntityColliderFaces[j].i1];
|
|
|
|
Vec3f* v2 = triangle->v2 = &boxVertices[gEntityColliderFaces[j].i2];
|
|
|
|
Vec3f* v3 = triangle->v3 = &boxVertices[gEntityColliderFaces[j].i3];
|
|
|
|
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;
|
|
|
|
|
|
|
|
if (hasCollision = test_ray_triangle_general(&entityTriangle, boxVertices))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hasCollision && gCollisionRayLength < *hitDepth) {
|
|
|
|
entityIndex = i;
|
|
|
|
*hitDepth = gCollisionRayLength;
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case 0:
|
|
|
|
hitDepthDown = gCollisionRayLength;
|
|
|
|
hitDepthHoriz = gCollisionRayLength;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
hitDepthDown = gCollisionRayLength;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
hitDepthHoriz = gCollisionRayLength;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
guRotateF(tempMatrix1, entity->rotation.x, 1.0f, 0.0f, 0.0f);
|
|
|
|
guRotateF(tempMatrix2, entity->rotation.z, 0.0f, 0.0f, 1.0f);
|
|
|
|
guMtxCatF(tempMatrix1, tempMatrix2, tempMatrix1);
|
|
|
|
guRotateF(tempMatrix2, entity->rotation.y, 0.0f, 1.0f, 0.0f);
|
|
|
|
guMtxCatF(tempMatrix1, tempMatrix2, tempMatrix1);
|
|
|
|
guTranslateF(tempMatrix2, entity->position.x, entity->position.y, entity->position.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;
|
|
|
|
}
|
|
|
|
|
|
|
|
ApiStatus func_8005DB00(Evt* script, s32 isInitialCall) {
|
|
|
|
Npc* npc;
|
|
|
|
f32 targetDir, npcYaw;
|
|
|
|
PlayerStatus* playerStatus;
|
|
|
|
PartnerActionStatus* partnerStatus;
|
|
|
|
|
|
|
|
npc = get_npc_unsafe(script->owner1.enemy->npcID);
|
|
|
|
playerStatus = &gPlayerStatus;
|
|
|
|
partnerStatus = &gPartnerActionStatus;
|
|
|
|
|
|
|
|
if (isInitialCall)
|
|
|
|
script->functionTemp[0] = 0;
|
|
|
|
|
|
|
|
switch(script->functionTemp[0]) {
|
|
|
|
case 0:
|
|
|
|
npc->planarFlyDist = evt_get_float_variable(script, LW(0));
|
|
|
|
npc->duration = evt_get_variable(script, LW(1));
|
|
|
|
script->functionTemp[1] = evt_get_variable(script, LW(2));
|
|
|
|
script->functionTemp[2] = evt_get_variable(script, LW(3)) / 2;
|
|
|
|
npc->currentAnim.w = script->varTable[10];
|
|
|
|
script->functionTemp[0] = 1;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
if (partnerStatus->actionState.b[3] != 9) {
|
|
|
|
if (npc->duration != 0 && npc->duration != script->functionTemp[0])
|
|
|
|
return ApiStatus_BLOCK;
|
|
|
|
|
|
|
|
if (npc->duration == 0) {
|
|
|
|
if (sqrtf(SQ((playerStatus->position.x - npc->pos.x)) +
|
|
|
|
SQ((playerStatus->position.y - npc->pos.y)) +
|
|
|
|
SQ((playerStatus->position.z - npc->pos.z))) <= npc->planarFlyDist) {
|
|
|
|
targetDir = atan2(npc->pos.x, npc->pos.z, playerStatus->position.x, playerStatus->position.z);
|
|
|
|
npcYaw = script->functionTemp[1] == -1 ? npc->yaw : script->functionTemp[1];
|
|
|
|
|
|
|
|
if (fabsf(get_clamped_angle_diff(npcYaw, targetDir)) < script->functionTemp[2]) {
|
|
|
|
script->varTable[0] = 1;
|
|
|
|
return ApiStatus_DONE2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (dist2D(npc->pos.x, npc->pos.z, playerStatus->position.x, playerStatus->position.z) <= npc->planarFlyDist) {
|
|
|
|
targetDir = atan2(npc->pos.x, npc->pos.z, playerStatus->position.x, playerStatus->position.z);
|
|
|
|
npcYaw = script->functionTemp[1] == -1 ? npc->yaw : script->functionTemp[1];
|
|
|
|
|
|
|
|
if (fabsf(get_clamped_angle_diff(npcYaw, targetDir)) < script->functionTemp[2]) {
|
|
|
|
script->varTable[0] = 1;
|
|
|
|
return ApiStatus_DONE2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ApiStatus_BLOCK;
|
|
|
|
}
|
|
|
|
|
|
|
|
ApiStatus func_8005DD54(Evt* script, s32 isInitialCall) {
|
|
|
|
f32 angle = clamp_angle(script->varTable[0]);
|
|
|
|
|
|
|
|
script->varTable[0] = angle;
|
|
|
|
if (angle >= 180.0f) {
|
|
|
|
angle -= 180.0f;
|
|
|
|
}
|
|
|
|
if (angle >= 90.0f) {
|
|
|
|
angle = 180.0f - angle;
|
|
|
|
}
|
|
|
|
script->varTable[2] = (s32) (((90.0f - angle) * 95.0f) / 90.0f) + 160;
|
|
|
|
return ApiStatus_DONE2;
|
|
|
|
}
|
|
|
|
|
|
|
|
s32 func_8005DDF0(void) {
|
|
|
|
return ~gCurrentEncounter.unk_08 != 0;
|
|
|
|
}
|