From b92148ab0b0f1cefd3c88a3509d14c8311f2bb97 Mon Sep 17 00:00:00 2001 From: Unnunu Date: Tue, 27 May 2025 21:09:54 +0300 Subject: [PATCH] match func_80060910 and func_80060AC8 (#589) * match func_80060AC8 * reworked func_80060C58 * match func_80060910 * non equivalent func_8006017C * format * match calc_env_mapping_for_object --- README.md | 16 +-- include/structs.h | 17 ++- src/hasm/math_util.c | 11 +- src/math_util.h | 2 +- src/object_models.c | 318 ++++++++++++++++++++++++++++++++++++++----- src/object_models.h | 1 + src/objects.c | 121 ++++++++++++++-- 7 files changed, 423 insertions(+), 63 deletions(-) diff --git a/README.md b/README.md index 467bf59c..24f1eb6e 100644 --- a/README.md +++ b/README.md @@ -5,9 +5,9 @@ This repo contains a work-in-progress decompilation of Diddy Kong Racing for the All versions are supported, and the US 1.0 version (SHA1 = 0cb115d8716dbbc2922fda38e533b9fe63bb9670) of the game is the default if not specified. -As of May 26, 2025, this is our current score: +As of May 27, 2025, this is our current score: -    Decomp progress: 88.37% +    Decomp progress: 88.58%     Documentation progress: 58.39% @@ -117,20 +117,20 @@ s32 is_drumstick_unlocked(void) { ``` -As of May 26, 2025, this is our current score: +As of May 27, 2025, this is our current score: ``` =================================================================== ADVENTURE ONE (ASM -> C Decompilation) - -------------- 88.37% Complete (89.33% NON_MATCHING) -------------- - # Decompiled functions: 1900 - # GLOBAL_ASM remaining: 51 + -------------- 88.58% Complete (89.54% NON_MATCHING) -------------- + # Decompiled functions: 1903 + # GLOBAL_ASM remaining: 48 # NON_MATCHING functions: 5 - # NON_EQUIVALENT WIP functions: 15 + # NON_EQUIVALENT WIP functions: 16 --------------------------- Game Status --------------------------- Balloons: 41/47, Keys: 4/4, Trophies: 4/5 T.T. Amulets: 4/4, Wizpig Amulets: 4/4 ------------------------------------------------------------------- - We are racing in Spaceport Alpha. (Lap 1/3) + We are racing in Spaceport Alpha. (Lap 2/3) =================================================================== ADVENTURE TWO (Cleanup & Documentation) ------------------------- 58.39% Complete ------------------------- diff --git a/include/structs.h b/include/structs.h index eaeb252a..1330ddbe 100644 --- a/include/structs.h +++ b/include/structs.h @@ -639,12 +639,23 @@ typedef struct ObjectModel_44 { /* 0x04 */ s32 unk4; // Number of frames in animation? } ObjectModel_44; +typedef struct ObjectModel_C { + u16 unk0[4]; +} ObjectModel_C; + +typedef struct ObjectModel_10 { + f32 A; + f32 B; + f32 C; + f32 D; +} ObjectModel_10; + typedef struct ObjectModel { /* 0x00 */ TextureInfo* textures; /* 0x04 */ Vertex* vertices; /* 0x08 */ Triangle* triangles; - /* 0x0C */ s32* unkC; - /* 0x10 */ s32* unk10; + /* 0x0C */ ObjectModel_C *unkC; + /* 0x10 */ ObjectModel_10 *unk10; /* 0x14 */ s16 *unk14; /* 0x18 */ s16 unk18; /* 0x1A */ s16 unk1A; @@ -662,7 +673,7 @@ typedef struct ObjectModel { /* 0x34 */ u8 pad34[4]; /* 0x38 */ TriangleBatchInfo* batches; /* 0x3C */ f32 unk3C; - /* 0x40 */ s32* unk40; + /* 0x40 */ Vec3s* unk40; /* 0x44 */ ObjectModel_44* animations; /* 0x48 */ s16 numberOfAnimations; /* 0x4A */ s16 unk4A; diff --git a/src/hasm/math_util.c b/src/hasm/math_util.c index dc195d81..0ade6311 100644 --- a/src/hasm/math_util.c +++ b/src/hasm/math_util.c @@ -214,14 +214,9 @@ GLOBAL_ASM("asm/math_util/rng.s") #ifdef NON_EQUIVALENT /* Official name: fastShortReflection */ -void s16_matrix_rotate(s16 *arg0[4][4], s16 arg1[4][4]) { - s32 temp_t6; - - temp_t6 = (s32) ((*arg0[0][0] * arg1[0][0]) + (*arg0[0][1] * arg1[0][1]) + (*arg0[0][2] * *arg0[0][2])) >> 12; - *arg0[1][0] = (s16) (((s32) (temp_t6 * arg1[0][0]) >> 13) - *arg0[0][0]); - *arg0[1][1] = (s16) (((s32) (temp_t6 * arg1[0][1]) >> 13) - *arg0[0][1]); - *arg0[1][2] = - (s16) (((s32) (temp_t6 * arg1[0][2]) >> 13) - *arg0[0][0]); // Did they mean to do `- *arg0[0][2]` here? +// name and code are incorrect +void s16_matrix_rotate(Vec3s *arg0, Vec3s *arg1) { + // TODO } #else GLOBAL_ASM("asm/math_util/s16_matrix_rotate.s") diff --git a/src/math_util.h b/src/math_util.h index a998ed7f..85ae974c 100644 --- a/src/math_util.h +++ b/src/math_util.h @@ -42,7 +42,7 @@ void guMtxXFMF(float mf[4][4], float x, float y, float z, float *ox, float *oy, void f32_matrix_dot(Matrix *mat1, Matrix *mat2, Matrix *output); void f32_matrix_mult(Matrix *mat1, Matrix *mat2, Matrix *output); void f32_matrix_to_s16_matrix(Matrix *input, MatrixS *output); -void s16_matrix_rotate(s16 *arg0[4][4], s16 arg1[4][4]); +void s16_matrix_rotate(Vec3s *arg0, Vec3s *arg1); void s16_vec3_mult_by_s32_matrix(MatrixS input, Vec3s *output); void object_transform_to_matrix(Matrix mtx, ObjectTransform *trans); void f32_matrix_scale_y_axis(Matrix *input, f32 scale); diff --git a/src/object_models.c b/src/object_models.c index 6dfe609c..bf393121 100644 --- a/src/object_models.c +++ b/src/object_models.c @@ -376,51 +376,299 @@ void free_model_data(ObjectModel *mdl) { mempool_free(mdl); } -#pragma GLOBAL_ASM("asm/nonmatchings/object_models/func_8006017C.s") -#pragma GLOBAL_ASM("asm/nonmatchings/object_models/func_80060910.s") -#pragma GLOBAL_ASM("asm/nonmatchings/object_models/func_80060AC8.s") +#ifdef NON_EQUIVALENT +// url: https://decomp.me/scratch/VJ34p +void func_8006017C(ObjectModel *arg0) { + s32 facesOffset; // v1 + s32 verticesOffset; // s5 + s32 nextFacesOffset; // spF4 + s32 s4; + s32 i; // spEC + s32 j; // s6 + Vertex *v; + s32 v1, v2; + f32 x5, y5, z5; // f20, f24, f26 + f32 x1, y1, z1; // spCC, spC8, spC4 + f32 x2, y2, z2; // f14, f16, f18 + f32 x3, y3, z3; // f22, spB0, f0 + f32 nx, ny, nz; // spA8, spA4, spA0 + f32 mag; + s32 s3; + s32 k; + s32 l; + s32 temp1, temp2, temp3; -s32 func_80060C58(Vertex *vertices, s32 arg1, s32 arg2, s32 arg3, s32 arg4) { + if (arg0->unkC != NULL) { + return; + } + + s4 = 0; + for (i = 0; i < arg0->numberOfBatches; i++) { + facesOffset = arg0->batches[i].facesOffset; + nextFacesOffset = arg0->batches[i + 1].facesOffset; + if (arg0->batches[i].flags & 0x200) { + continue; + } + s4 += nextFacesOffset - facesOffset; + } + + arg0->unkC = (ObjectModel_C *) mempool_alloc(s4 * sizeof(ObjectModel_C), COLOUR_TAG_RED); + if (v) {} // FAKE + if (arg0->unkC == NULL) { + return; + } + + arg0->unk10 = (ObjectModel_10 *) mempool_alloc(s4 * 64, COLOUR_TAG_RED); + if (arg0->unk10 == NULL) { + mempool_free(arg0->unkC); + arg0->unkC = NULL; + return; + } + + s4 = 0; + for (i = 0; i < arg0->numberOfBatches; i++) { + facesOffset = arg0->batches[i].facesOffset; + verticesOffset = arg0->batches[i].verticesOffset; + nextFacesOffset = arg0->batches[i + 1].facesOffset; + if (arg0->batches[i].flags & 0x200) { + nextFacesOffset = facesOffset - 1; + } + + for (j = facesOffset; j < nextFacesOffset; j++) { + v = &arg0->vertices[arg0->triangles[j].vi0 + verticesOffset]; + x1 = v->x; + y1 = v->y; + z1 = v->z; + + v = &arg0->vertices[arg0->triangles[j].vi1 + verticesOffset]; + x2 = v->x; + y2 = v->y; + z2 = v->z; + + v = &arg0->vertices[arg0->triangles[j].vi2 + verticesOffset]; + x3 = v->x; + y3 = v->y; + z3 = v->z; + + nx = y1 * (z2 - z3) + y2 * (z3 - z1) + y3 * (z1 - z2); + ny = z1 * (x2 - x3) + z2 * (x3 - x1) + z3 * (x1 - x2); + nz = x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2); + + mag = sqrtf(nx * nx + ny * ny + nz * nz); + if (mag > 0.0) { + nx /= mag; + ny /= mag; + nz /= mag; + } + + arg0->unk10[s4].A = nx; + arg0->unk10[s4].B = ny; + arg0->unk10[s4].C = nz; + arg0->unk10[s4].D = -(x1 * nx + y1 * ny + z1 * nz); + + arg0->unkC[s4].unk0[0] = s4; + arg0->unkC[s4].unk0[1] = s4; + arg0->unkC[s4].unk0[2] = s4; + arg0->unkC[s4].unk0[3] = s4; + + s4++; + } + } + + arg0->unk32 = s4; + + func_80060910(arg0); + + s3 = 0; + for (i = 0; i < arg0->numberOfBatches; i++) { + facesOffset = arg0->batches[i].facesOffset; + verticesOffset = arg0->batches[i].verticesOffset; + nextFacesOffset = arg0->batches[i + 1].facesOffset; + if (arg0->batches[i].flags & 0x200) { + nextFacesOffset = facesOffset - 1; + } + + for (j = facesOffset; j < nextFacesOffset; j++) { + nx = arg0->unk10[arg0->unkC[s3].unk0[0]].A; + ny = arg0->unk10[arg0->unkC[s3].unk0[0]].B; + nz = arg0->unk10[arg0->unkC[s3].unk0[0]].C; + + for (k = 0; k < 3; k++) { + l = k + 1; + if (l >= 3) { + l = 0; + } + + v1 = arg0->triangles[j].verticesArray[1 + k]; + v2 = arg0->triangles[j].verticesArray[1 + l]; + + x5 = nx + arg0->unk10[arg0->unkC[s3].unk0[l + 1]].A; + y5 = ny + arg0->unk10[arg0->unkC[s3].unk0[l + 1]].B; + z5 = nz + arg0->unk10[arg0->unkC[s3].unk0[l + 1]].C; + + v = &arg0->vertices[v1 + verticesOffset]; + x1 = v->x; + y1 = v->y; + z1 = v->z; + + v = &arg0->vertices[v2 + verticesOffset]; + x2 = v->x; + y2 = v->y; + z2 = v->z; + + x3 = x5 * 10.0f + x1; + y3 = y5 * 10.0f + y1; + z3 = z5 * 10.0f + z1; + + x5 = y1 * (z2 - z3) + y2 * (z3 - z1) + y3 * (z1 - z2); + y5 = z1 * (x2 - x3) + z2 * (x3 - x1) + z3 * (x1 - x2); + z5 = x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2); + + mag = sqrtf(x5 * x5 + y5 * y5 + z5 * z5); + if (mag > 0.0) { + x5 /= mag; + y5 /= mag; + z5 /= mag; + } + + arg0->unkC[s3].unk0[k + 1] = s4; + arg0->unk10[s4].A = x5; + arg0->unk10[s4].B = y5; + arg0->unk10[s4].C = z5; + arg0->unk10[s4].D = -(x1 * x5 + y1 * y5 + z1 * z5); + s4++; + } + + s3++; + } + } +} + +#else +#pragma GLOBAL_ASM("asm/nonmatchings/object_models/func_8006017C.s") +#endif + +void func_80060910(ObjectModel *mdl) { + s32 count; + s32 i; + s32 vertOffset; + s32 triIndex; + s32 startTri; + s32 endTri; + s32 nextVertIndex; + s32 vertIndex; + s32 vertIndex0; + s32 vertIndex1; + s32 result; + s32 sp60; + s32 sp5C; + + count = 0; + for (i = 0; i < mdl->numberOfBatches; i++) { + startTri = mdl->batches[i].facesOffset; + vertOffset = mdl->batches[i].verticesOffset; + endTri = mdl->batches[i + 1].facesOffset; + if (mdl->batches[i].flags & BATCH_FLAGS_UNK00000200) { + endTri = startTri - 1; + } + + for (triIndex = startTri; triIndex < endTri; triIndex++, count++) { + mdl->unkC[count].unk0[0] = count; + + for (vertIndex = 0; vertIndex < 3; vertIndex++) { + nextVertIndex = vertIndex + 1; + if (nextVertIndex >= 3) { + nextVertIndex = 0; + } + + vertIndex0 = mdl->triangles[triIndex].verticesArray[vertIndex + 1] + vertOffset; + vertIndex1 = mdl->triangles[triIndex].verticesArray[nextVertIndex + 1] + vertOffset; + + result = func_80060AC8(mdl, triIndex, vertIndex0, vertIndex1, &sp5C, &sp60); + if (result != -1) { + mdl->unkC[count].unk0[1 + vertIndex] = result; + } else { + mdl->unkC[count].unk0[1 + vertIndex] = count; + } + } + } + } +} + +s32 func_80060AC8(ObjectModel *mdl, s32 arg1, s32 arg2, s32 arg3, s32 *outBatchIndex, s32 *outVertexIndex) { + s32 i; + s32 endTri; + s32 count; + Triangle *tri; + s16 vertOffset; + s16 startTri; + s32 triIndex; + s32 nextVertIndex; + s32 vertIndex; + s32 vertIndex0; + s32 vertIndex1; + + count = 0; + for (i = 0; i < mdl->numberOfBatches; i++) { + startTri = mdl->batches[i].facesOffset; + vertOffset = mdl->batches[i].verticesOffset; + endTri = mdl->batches[i + 1].facesOffset; + if (mdl->batches[i].flags & BATCH_FLAGS_UNK00000200) { + endTri = startTri - 1; + } + for (triIndex = startTri; triIndex < endTri; triIndex++, count++) { + if (triIndex != arg1) { + for (vertIndex = 0; vertIndex < 3; vertIndex++) { + nextVertIndex = vertIndex + 1; + if (nextVertIndex >= 3) { + nextVertIndex = 0; + } + + vertIndex0 = mdl->triangles[triIndex].verticesArray[vertIndex + 1] + vertOffset; + vertIndex1 = mdl->triangles[triIndex].verticesArray[nextVertIndex + 1] + vertOffset; + if (func_80060C58(mdl->vertices, arg2, arg3, vertIndex0, vertIndex1) != 0) { + *outVertexIndex = vertIndex; + *outBatchIndex = i; + return count; + } + } + } + } + } + + return -1; +} + +s32 func_80060C58(Vertex *vertices, s32 i1, s32 i2, s32 i3, s32 i4) { Vertex *a; Vertex *b; Vertex *c; Vertex *d; - if (((arg1 == arg3) && (arg2 == arg4)) || ((arg1 == arg4) && (arg2 == arg3))) { + +#define NEARBY(a, b, x) (b->x - 4 < a->x && a->x < b->x + 4) + + if (i1 == i3 && i2 == i4 || i1 == i4 && i2 == i3) { return 1; } - a = &vertices[arg1]; - b = &vertices[arg2]; - c = &vertices[arg3]; - d = &vertices[arg4]; - if (((c->x - 4) < a->x) && (a->x < (c->x + 4))) { - if (((c->y - 4) < a->y) && (a->y < (c->y + 4))) { - if (((c->z - 4) < a->z) && (a->z < (c->z + 4))) { - if (((d->x - 4) < b->x) && (b->x < (d->x + 4))) { - if (((d->y - 4) < b->y) && (b->y < (d->y + 4))) { - if (((d->z - 4) < b->z) && (b->z < (d->z + 4))) { - return 2; - } - } - } - goto end; - } + + a = &vertices[i1]; + b = &vertices[i2]; + c = &vertices[i3]; + d = &vertices[i4]; + + if (NEARBY(a, c, x) && NEARBY(a, c, y) && NEARBY(a, c, z)) { + if (NEARBY(b, d, x) && NEARBY(b, d, y) && NEARBY(b, d, z)) { + return 2; + } + } else if (NEARBY(a, d, x) && NEARBY(a, d, y) && NEARBY(a, d, z)) { + if (NEARBY(b, c, x) && NEARBY(b, c, y) && NEARBY(b, c, z)) { + return 2; } } - if (((d->x - 4) < a->x) && (a->x < (d->x + 4))) { - if (((d->y - 4) < a->y) && (a->y < (d->y + 4))) { - if (((d->z - 4) < a->z) && (a->z < (d->z + 4))) { - if (((c->x - 4) < b->x) && (b->x < (c->x + 4))) { - if (((c->y - 4) < b->y) && (b->y < (c->y + 4))) { - if (((c->z - 4) < b->z) && (b->z < (c->z + 4))) { - return 2; - } - } - } - } - } - } -end: + return 0; + +#undef NEARBY } #pragma GLOBAL_ASM("asm/nonmatchings/object_models/func_80060EA8.s") diff --git a/src/object_models.h b/src/object_models.h index 74fc5fa7..f53288e9 100644 --- a/src/object_models.h +++ b/src/object_models.h @@ -28,6 +28,7 @@ s32 func_80061A00(ObjectModel *model, s32 animTableIndex); s32 check_nearby_vertices(Vertex *vertices, s32 arg1, s32 arg2, s32 arg3, s32 arg4); Object_68 *model_init_type(ObjectModel *model, s32 flags); Object_68 *object_model_init(s32 modelID, s32 flags); +s32 func_80060C58(Vertex *vertices, s32 arg1, s32 arg2, s32 arg3, s32 arg4); void free_model_data(ObjectModel *mdl); // Non Matching void func_80060910(ObjectModel *); diff --git a/src/objects.c b/src/objects.c index b8ce9559..feec2028 100644 --- a/src/objects.c +++ b/src/objects.c @@ -37,6 +37,10 @@ #define AINODE_COUNT 128 #define CAMCONTROL_COUNT 20 +#define SET_SHIFT_AND_MASK(varShift, varMask, x) \ + varShift = x; \ + varMask = 0xFFFF >> x; + /************ .data ************/ FadeTransition gTajChallengeTransition = FADE_TRANSITION(FADE_FULLSCREEN, FADE_FLAG_OUT, FADE_COLOR_BLACK, 30, 15); @@ -311,10 +315,8 @@ ShadeProperties *gWorldShading; // Effectively unused. s32 D_8011AF34; s32 D_8011AF38[10]; s32 D_8011AF60[2]; -s32 D_8011AF68[32]; -VertexPosition gEnvmapPos; -s16 D_8011AFEE; -s32 D_8011AFF0; +TexCoords D_8011AF68[32]; +Vec3s gEnvmapPos[2]; unk800179D0 *D_8011AFF4; s32 gBoostVertCount; s32 D_8011AFFC; @@ -5965,9 +5967,9 @@ void update_envmap_position(f32 x, f32 y, f32 z) { y *= normalizedLength; z *= normalizedLength; } - gEnvmapPos.x = x; - gEnvmapPos.y = y; - gEnvmapPos.z = z; + gEnvmapPos[0].x = x; + gEnvmapPos[0].y = y; + gEnvmapPos[0].z = z; } /** @@ -6011,7 +6013,110 @@ void obj_shade_fancy(ObjectModel *model, Object *object, s32 arg2, f32 intensity } #pragma GLOBAL_ASM("asm/nonmatchings/objects/calc_dynamic_lighting_for_object_1.s") -#pragma GLOBAL_ASM("asm/nonmatchings/objects/calc_env_mapping_for_object.s") + +void calc_env_mapping_for_object(ObjectModel *model, s16 zRot, s16 xRot, s16 yRot) { + MatrixS objRotMtxS32; + Matrix objRotMtxF32; + ObjectTransform objTrans; + s16 k; + s16 count; + Triangle *triangles; + Vec3s *model40Entries; + s32 sp70; + TextureHeader *tex; + s16 shiftS; + s16 maskS; + s16 shiftT; + s16 maskT; + s16 i; + s16 j; + s16 var_v0; + s16 var_v1; + + count = 0; + triangles = model->triangles; + model40Entries = model->unk40; + objTrans.rotation.z_rotation = zRot; + objTrans.rotation.x_rotation = xRot; + objTrans.rotation.y_rotation = yRot; + objTrans.x_position = 0.0f; + objTrans.y_position = 0.0f; + objTrans.z_position = 0.0f; + objTrans.scale = 1.0f; + object_transform_to_matrix(objRotMtxF32, &objTrans); + f32_matrix_to_s32_matrix(&objRotMtxF32, &objRotMtxS32); + + for (i = 0; i < model->numberOfBatches; i++) { + if (model->batches[i].flags & BATCH_FLAGS_ENVMAP) { + sp70 = ((model->batches[i].flags & BATCH_FLAGS_UNK00020000) | BATCH_FLAGS_ENVMAP) ^ BATCH_FLAGS_ENVMAP; + tex = model->textures[model->batches[i].textureIndex].texture; + k = 0; + + switch (tex->width) { + case 0x80: + SET_SHIFT_AND_MASK(shiftS, maskS, 4); + break; + case 0x40: + SET_SHIFT_AND_MASK(shiftS, maskS, 5); + break; + case 0x20: + SET_SHIFT_AND_MASK(shiftS, maskS, 6); + break; + default: + SET_SHIFT_AND_MASK(shiftS, maskS, 7); + break; + } + switch (tex->height) { + case 0x80: + SET_SHIFT_AND_MASK(shiftT, maskT, 4); + break; + case 0x40: + SET_SHIFT_AND_MASK(shiftT, maskT, 5); + break; + case 0x20: + SET_SHIFT_AND_MASK(shiftT, maskT, 6); + break; + default: + SET_SHIFT_AND_MASK(shiftT, maskT, 7); + break; + } + + for (j = model->batches[i].verticesOffset; j < model->batches[i + 1].verticesOffset; j++, k++) { + gEnvmapPos[1].x = model40Entries[count].x; + gEnvmapPos[1].y = model40Entries[count].y; + gEnvmapPos[1].z = model40Entries[count].z; + count++; + s16_vec3_mult_by_s32_matrix(objRotMtxS32, &gEnvmapPos[1]); + if (sp70 == 0) { + s16_matrix_rotate(&gEnvmapPos[0], &gEnvmapPos[1]); + } + var_v0 = gEnvmapPos[1].x; + var_v1 = gEnvmapPos[1].y; + if (var_v0 > 0) { + var_v0--; + } + if (var_v1 > 0) { + var_v1--; + } + var_v0 = (var_v0 << 2) + 0x8000; + var_v1 = (var_v1 << 2) + 0x8000; + D_8011AF68[k].u = (var_v0 >> shiftS) & maskS; + D_8011AF68[k].v = (var_v1 >> shiftT) & maskT; + } + + for (j = model->batches[i].facesOffset; j < model->batches[i + 1].facesOffset; j++) { + triangles[j].uv0.u = D_8011AF68[triangles[j].vi0].u; + triangles[j].uv0.v = D_8011AF68[triangles[j].vi0].v; + triangles[j].uv1.u = D_8011AF68[triangles[j].vi1].u; + triangles[j].uv1.v = D_8011AF68[triangles[j].vi1].v; + triangles[j].uv2.u = D_8011AF68[triangles[j].vi2].u; + triangles[j].uv2.v = D_8011AF68[triangles[j].vi2].v; + } + } else if (model->batches[i].unk6 < 0xFF) { + count += model->batches[i + 1].verticesOffset - model->batches[i].verticesOffset; + } + } +} /** * Find the racer object representing the player and directly set position and angle to new values.