Files
Diddy-Kong-Racing/src/hasm/math_util.c
T
UnnunuandGitHub b41c206cfd document audio_vehicle.c (#588)
* wip

* wip

* wip

* wip

* document audio_vehicle.c

* update score once again

* unify function prefix

* small tweaks
2025-05-26 18:49:55 +03:00

802 lines
23 KiB
C

#include "math_util.h"
#include <math.h>
#include "types.h"
#include "macros.h"
#include "structs.h"
#include "game.h"
#include "string.h"
#include "PR/os_internal_reg.h"
extern s32 gIntDisFlag;
extern s32 gCurrentRNGSeed; // Official Name: rngSeed
extern s32 gPrevRNGSeed;
extern s16 gSineTable[];
extern s16 gArcTanTable[];
/**
* Most files below are handwritten assembly. Because of this, matching C code is impossible.
* Nonmatching is not, so functionally equivalent C code can be here to replace these handwritten functions in
* nonmatching builds. Variables cannot be declared here because of the way they're aligned, so they have to stay in an
* assembly file.
*/
/******************************/
#ifdef NON_MATCHING
/**
* Zero out the interrupt mask. This stops this thread
* from being interrupted by others, letting you safely
* work with delicate areas in memory. Kind of like a mutex.
* Returns what the interrupt mask wask before.
* Official Name: disableInterrupts */
u32 interrupts_disable(void) {
if (gIntDisFlag) {
return __osDisableInt();
}
}
#else
GLOBAL_ASM("asm/math_util/disable_interrupts.s")
#endif
#ifdef NON_MATCHING
/**
* Set the interrupt mask to whichever flags were given.
* Required after zeroing them out, otherwise system
* operation won't work as normal.
* Official Name: enableInterrupts */
void interrupts_enable(u32 flags) {
if (gIntDisFlag) {
__osRestoreInt(flags);
}
}
#else
GLOBAL_ASM("asm/math_util/enable_interrupts.s")
#endif
#ifdef NON_MATCHING
/* Official Name: setIntDisFlag */
void set_gIntDisFlag(s8 setting) {
gIntDisFlag = setting;
}
#else
GLOBAL_ASM("asm/math_util/set_gIntDisFlag.s")
#endif
#ifdef NON_MATCHING
/* Official Name: getIntDisFlag */
s8 get_gIntDisFlag(void) {
return gIntDisFlag;
}
#else
GLOBAL_ASM("asm/math_util/get_gIntDisFlag.s")
#endif
#ifdef NON_EQUIVALENT // Untested
UNUSED void s32_matrix_to_s16_matrix(s32 **input, s16 **output) {
s32 i;
for (i = 0; i < 4; i++) {
output[i][2] = input[i][0];
output[i][3] = input[i + 4][0];
output[i][6] = input[i][1];
output[i][7] = input[i + 4][1];
output[i][0] = input[i][0] >> 16;
output[i][1] = input[i + 4][0] >> 16;
output[i][4] = input[i][1] >> 16;
output[i][5] = input[i + 4][1] >> 16;
}
}
#else
GLOBAL_ASM("asm/math_util/s32_matrix_to_s16_matrix.s")
#endif
#ifdef NON_MATCHING
void f32_matrix_to_s32_matrix(Matrix *input, MatrixS *output) {
s32 i;
for (i = 0; i < 4; i++) {
(*output)[i][0] = (s32) ((*input)[i][0] * 65536.0f);
(*output)[i][1] = (s32) ((*input)[i][1] * 65536.0f);
(*output)[i][2] = (s32) ((*input)[i][2] * 65536.0f);
(*output)[i][3] = (s32) ((*input)[i][3] * 65536.0f);
}
}
#else
GLOBAL_ASM("asm/math_util/f32_matrix_to_s32_matrix.s")
#endif
#ifdef NON_MATCHING
/* Official name: mathMtxXFMF */
void guMtxXFMF(Matrix mf, float x, float y, float z, float *ox, float *oy, float *oz) {
*ox = mf[0][0] * x + mf[1][0] * y + mf[2][0] * z + mf[3][0];
*oy = mf[0][1] * x + mf[1][1] * y + mf[2][1] * z + mf[3][1];
*oz = mf[0][2] * x + mf[1][2] * y + mf[2][2] * z + mf[3][2];
}
#else
GLOBAL_ASM("asm/math_util/guMtxXFMF.s")
#endif
#ifdef NON_MATCHING
/* Official name: mathMtxFastXFMF */
void f32_matrix_dot(Matrix *mat1, Matrix *mat2, Matrix *output) {
f32 temp_f4;
f32 temp_f6;
f32 temp_f8;
temp_f4 = (*mat2)[0][0];
temp_f6 = (*mat2)[0][1];
temp_f8 = (*mat2)[0][2];
(*output)[0][0] = (temp_f4 * (*mat1)[0][0]) + (temp_f6 * (*mat1)[1][0]) + (temp_f8 * (*mat1)[2][0]);
(*output)[0][1] = (temp_f4 * (*mat1)[0][1]) + (temp_f6 * (*mat1)[1][1]) + (temp_f8 * (*mat1)[2][1]);
(*output)[0][2] = (temp_f4 * (*mat1)[0][2]) + (temp_f6 * (*mat1)[1][2]) + (temp_f8 * (*mat1)[2][2]);
}
#else
GLOBAL_ASM("asm/math_util/f32_matrix_dot.s")
#endif
#ifdef NON_MATCHING
/* Official name: mathMtxCatF */
void f32_matrix_mult(Matrix *mat1, Matrix *mat2, Matrix *output) {
s32 i;
f32 x;
f32 y;
f32 z;
f32 w;
for (i = 0; i < 4; i++) {
x = (*mat1)[i][0];
y = (*mat1)[i][1];
z = (*mat1)[i][2];
w = (*mat1)[i][3];
(*output)[i][0] =
(f32) ((y * (*mat2)[1][0]) + (z * (*mat2)[2][0]) + ((x * (*mat2)[0][0]) + (w * (*mat2)[3][0])));
(*output)[i][1] =
(f32) ((y * (*mat2)[1][1]) + (z * (*mat2)[2][1]) + ((x * (*mat2)[0][1]) + (w * (*mat2)[3][1])));
(*output)[i][2] =
(f32) ((y * (*mat2)[1][2]) + (z * (*mat2)[2][2]) + ((x * (*mat2)[0][2]) + (w * (*mat2)[3][2])));
(*output)[i][3] =
(f32) ((y * (*mat2)[1][3]) + (z * (*mat2)[2][3]) + ((x * (*mat2)[0][3]) + (w * (*mat2)[3][3])));
}
}
#else
GLOBAL_ASM("asm/math_util/f32_matrix_mult.s")
#endif
#ifdef NON_MATCHING
/* Official name: mathMtxF2L */
void f32_matrix_to_s16_matrix(Matrix *input, MatrixS *output) {
guMtxF2L((float (*)[4]) input, (Mtx *) output);
}
#else
GLOBAL_ASM("asm/math_util/f32_matrix_to_s16_matrix.s")
#endif
/* Official Name: mathSeed */
void set_rng_seed(s32 num) {
gCurrentRNGSeed = num;
}
#ifdef NON_MATCHING
void save_rng_seed(void) {
s32 num = gCurrentRNGSeed;
gPrevRNGSeed = num;
}
#else
GLOBAL_ASM("asm/math_util/save_rng_seed.s")
#endif
#ifdef NON_MATCHING
void load_rng_seed(void) {
s32 num = gPrevRNGSeed;
gCurrentRNGSeed = num;
}
#else
GLOBAL_ASM("asm/math_util/load_rng_seed.s")
#endif
s32 get_rng_seed(void) {
return gCurrentRNGSeed;
}
#ifdef NON_MATCHING
/* Official Name: mathRnd */
s32 get_random_number_from_range(s32 min, s32 max) {
s32 newSeed;
u64 curSeed;
curSeed = (((u64) ((s64) gCurrentRNGSeed << 0x3F) >> 0x1F) | ((u64) ((s64) gCurrentRNGSeed << 0x1F) >> 0x20)) ^
((u64) ((s64) gCurrentRNGSeed << 0x2C) >> 0x20);
newSeed = ((curSeed >> 0x14) & 0xFFF) ^ curSeed;
gCurrentRNGSeed = newSeed;
return ((u32) (newSeed - min) % (u32) ((max - min) + 1)) + min;
}
#else
GLOBAL_ASM("asm/math_util/rng.s")
#endif
#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?
}
#else
GLOBAL_ASM("asm/math_util/s16_matrix_rotate.s")
#endif
#ifdef NON_EQUIVALENT // Untested
UNUSED void s16_matrix_to_s32_matrix(s16 **arg0, s32 **arg1) {
s32 i, j;
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
arg1[i][j] = (arg0[i][j] << 16) | arg0[i + 4][j];
}
}
}
#else
GLOBAL_ASM("asm/math_util/s16_matrix_to_s32_matrix.s")
#endif
#ifdef NON_EQUIVALENT // Untested
UNUSED void s16_vec3_mult_by_s32_matrix_full(s32 **input, s16 *output) {
output[0] = ((output[0] * input[0][0]) + (output[1] * input[1][0]) + (output[2] * input[2][0]) + input[3][0]) >> 16;
output[1] = ((output[0] * input[0][1]) + (output[1] * input[1][1]) + (output[2] * input[2][1]) + input[3][1]) >> 16;
output[2] = ((output[0] * input[0][2]) + (output[1] * input[1][2]) + (output[2] * input[2][2]) + input[3][2]) >> 16;
}
#else
GLOBAL_ASM("asm/math_util/s16_vec3_mult_by_s32_matrix_full.s")
#endif
#ifdef NON_MATCHING
void s16_vec3_mult_by_s32_matrix(MatrixS input, Vec3s *output) {
s32 x;
s32 y;
s32 z;
x = output->x;
y = output->y;
z = output->z;
output->x = ((x * input[0][0]) + (y * input[1][0]) + (z * input[2][0])) >> 16;
output->y = ((x * input[0][1]) + (y * input[1][1]) + (z * input[2][1])) >> 16;
output->z = ((x * input[0][2]) + (y * input[1][2]) + (z * input[2][2])) >> 16;
}
#else
GLOBAL_ASM("asm/math_util/s16_vec3_mult_by_s32_matrix.s")
#endif
#ifdef NON_MATCHING
/**
* Converts an ObjectTransform into a transformation matrix and writes it to `mtx`.
* The matrix is built by applying the following operations in order:
* 1. Scaling
* 2. Rotation around Z axis (roll)
* 3. Rotation around X axis (pitch)
* 4. Rotation around Y axis (yaw)
* 5. Translation
*/
void object_transform_to_matrix(Matrix mtx, ObjectTransform *trans) {
f32 yRotSine;
f32 yRotCosine;
f32 xRotSine;
f32 xRotCosine;
f32 zRotSine;
f32 zRotCosine;
f32 scale;
yRotSine = sins_s16(trans->rotation.y_rotation) * (1.0f / 0x10000);
yRotCosine = coss_s16(trans->rotation.y_rotation) * (1.0f / 0x10000);
xRotSine = sins_s16(trans->rotation.x_rotation) * (1.0f / 0x10000);
xRotCosine = coss_s16(trans->rotation.x_rotation) * (1.0f / 0x10000);
zRotSine = sins_s16(trans->rotation.z_rotation) * (1.0f / 0x10000);
zRotCosine = coss_s16(trans->rotation.z_rotation) * (1.0f / 0x10000);
scale = trans->scale;
mtx[0][0] = (xRotSine * yRotSine * zRotSine + zRotCosine * yRotCosine) * scale;
mtx[0][1] = (zRotSine * xRotCosine) * scale;
mtx[0][2] = (xRotSine * yRotCosine * zRotSine - zRotCosine * yRotSine) * scale;
mtx[0][3] = 0;
mtx[1][0] = (xRotSine * yRotSine * zRotCosine - zRotSine * yRotCosine) * scale;
mtx[1][1] = (zRotCosine * xRotCosine) * scale;
mtx[1][2] = (xRotSine * yRotCosine * zRotCosine + zRotSine * yRotSine) * scale;
mtx[1][3] = 0;
mtx[2][0] = (xRotCosine * yRotSine) * scale;
mtx[2][1] = -(xRotSine * scale);
mtx[2][2] = (xRotCosine * yRotCosine) * scale;
mtx[2][3] = 0;
mtx[3][0] = trans->x_position;
mtx[3][1] = trans->y_position;
mtx[3][2] = trans->z_position;
mtx[3][3] = 1.0f;
}
#else
GLOBAL_ASM("asm/math_util/object_transform_to_matrix.s")
#endif
#ifdef NON_MATCHING
/* Official name: mathSquashY */
void f32_matrix_scale_y_axis(Matrix *input, f32 scale) {
input[0][1][0] *= scale;
input[0][1][1] *= scale;
input[0][1][2] *= scale;
}
#else
GLOBAL_ASM("asm/math_util/f32_matrix_scale_y_axis.s")
#endif
#ifdef NON_MATCHING
/* Official name: mathTransY */
void f32_matrix_translate_y_axis(Matrix *input, f32 offset) {
input[0][3][0] += input[0][1][0] * offset;
input[0][3][1] += input[0][1][1] * offset;
input[0][3][2] += input[0][1][2] * offset;
}
#else
GLOBAL_ASM("asm/math_util/f32_matrix_translate_y_axis.s")
#endif
#ifdef NON_EQUIVALENT
/**
* Writes an inverse transformation matrix to `mtx` based on a pre-inverted `ObjectTransform`.
* This is used to convert world-space coordinates to local object-space coordinates.
* Unlike the standard transform, this version:
* - Omits scaling
* - Applies the transformation steps in reverse order
* - Assumes that the translation and rotation values in `trans` are already negated
*
* Operation order:
* 1. Translate (negative offset)
* 2. Rotate Y (negative yaw)
* 3. Rotate X (negative pitch)
* 4. Rotate Z (negative roll)
*/
/* Official Name: mathRpyXyzMtx */
void object_inverse_transform_to_matrix(Matrix mtx, ObjectTransform *trans) {
f32 yRotSine;
f32 yRotCosine;
f32 xRotSine;
f32 xRotCosine;
f32 zRotSine;
f32 zRotCosine;
yRotCosine = coss_s16(trans->rotation.y_rotation) * (1.0f / 0x10000);
yRotSine = sins_s16(trans->rotation.y_rotation) * (1.0f / 0x10000);
xRotCosine = coss_s16(trans->rotation.x_rotation) * (1.0f / 0x10000);
xRotSine = sins_s16(trans->rotation.x_rotation) * (1.0f / 0x10000);
zRotCosine = coss_s16(trans->rotation.z_rotation) * (1.0f / 0x10000);
zRotSine = sins_s16(trans->rotation.z_rotation) * (1.0f / 0x10000);
mtx[0][0] = yRotCosine * zRotCosine - xRotSine * zRotSine * yRotSine;
mtx[0][1] = xRotSine * zRotCosine * yRotSine + yRotCosine * zRotSine;
mtx[0][2] = -(yRotSine * xRotCosine);
mtx[0][3] = 0;
mtx[1][0] = -(xRotCosine * zRotSine);
mtx[1][1] = xRotCosine * zRotCosine;
mtx[1][2] = xRotSine;
mtx[1][3] = 0;
mtx[2][0] = xRotSine * zRotSine * yRotCosine + yRotSine * zRotCosine;
mtx[2][1] = yRotSine * zRotSine - xRotSine * zRotCosine * yRotCosine;
mtx[2][2] = yRotCosine * xRotCosine;
mtx[2][3] = 0;
mtx[3][0] = (mtx[0][0] * trans->x_position) + (mtx[1][0] * trans->y_position) + (mtx[2][0] * trans->z_position);
mtx[3][1] = (mtx[0][1] * trans->x_position) + (mtx[1][1] * trans->y_position) + (mtx[2][1] * trans->z_position);
mtx[3][2] = (mtx[0][2] * trans->x_position) + (mtx[1][2] * trans->y_position) + (mtx[2][2] * trans->z_position);
mtx[3][3] = 1.0f;
}
#else
GLOBAL_ASM("asm/math_util/object_inverse_transform_to_matrix.s")
#endif
GLOBAL_ASM("asm/math_util/func_80070058.s")
#ifdef NON_MATCHING
void f32_matrix_from_rotation_and_scale(Matrix mtx, s32 angle, f32 scale, f32 scaleY) {
f32 cosine, sine;
sine = sins_s16(angle) * (1.0f / 0x10000);
cosine = coss_s16(angle) * (1.0f / 0x10000);
mtx[0][0] = cosine * scale;
mtx[0][1] = sine * scale;
mtx[0][2] = 0;
mtx[0][3] = 0;
mtx[1][0] = -sine * scale;
mtx[1][1] = (cosine * scale) * scaleY;
mtx[1][2] = 0;
mtx[1][3] = 0;
mtx[2][0] = 0;
mtx[2][1] = 0;
mtx[2][2] = scale;
mtx[2][3] = 0;
mtx[3][0] = 0;
mtx[3][1] = 0;
mtx[3][2] = 0;
mtx[3][3] = 1.0f;
}
#else
GLOBAL_ASM("asm/math_util/f32_matrix_from_rotation_and_scale.s")
#endif
#ifdef NON_EQUIVALENT
void s16_vec3_apply_object_rotation(ObjectTransform *trans, s16 *vec3Arg) {
s32 yRotSine;
s32 yRotCosine;
s32 xRotSine;
s32 xRotCosine;
s32 zRotSine;
s32 zRotCosine;
s32 temp_t3;
s32 temp_t4;
s32 temp_t5;
yRotCosine = coss_s16(trans->rotation.y_rotation);
yRotSine = sins_s16(trans->rotation.y_rotation);
xRotCosine = coss_s16(trans->rotation.x_rotation);
xRotSine = sins_s16(trans->rotation.x_rotation);
zRotCosine = coss_s16(trans->rotation.z_rotation);
zRotSine = sins_s16(trans->rotation.z_rotation);
temp_t3 = ((vec3Arg[0] * yRotSine) - (vec3Arg[1] * yRotCosine)) >> 16;
temp_t4 = ((vec3Arg[1] * yRotSine) + (vec3Arg[0] * yRotCosine)) >> 16;
temp_t4 = ((temp_t4 * xRotSine) - (vec3Arg[2] * xRotCosine)) >> 16;
temp_t5 = ((vec3Arg[2] * xRotSine) + (temp_t4 * xRotCosine)) >> 16;
vec3Arg[1] = temp_t4;
temp_t3 = ((temp_t3 * zRotSine) + (temp_t5 * zRotCosine)) >> 16;
temp_t5 = ((temp_t5 * zRotSine) - (temp_t3 * zRotCosine)) >> 16;
vec3Arg[0] = temp_t3;
vec3Arg[2] = temp_t5;
}
#else
GLOBAL_ASM("asm/math_util/s16_vec3_apply_object_rotation.s")
#endif
#ifdef NON_EQUIVALENT
/* Official Name: mathOneFloatRPY */
void f32_vec3_apply_object_rotation(ObjectTransform *trans, f32 *vec3_f32) {
f32 yRotSine;
f32 yRotCosine;
f32 xRotSine;
f32 xRotCosine;
f32 zRotSine;
f32 zRotCosine;
f32 x, y, z;
f32 temp;
zRotSine = sinf(trans->rotation.z_rotation);
zRotCosine = cosf(trans->rotation.z_rotation);
xRotSine = sinf(trans->rotation.x_rotation);
xRotCosine = cosf(trans->rotation.x_rotation);
yRotSine = sinf(trans->rotation.y_rotation);
yRotCosine = cosf(trans->rotation.y_rotation);
x = vec3_f32[0];
y = vec3_f32[1];
z = vec3_f32[2];
x = (vec3_f32[0] * zRotCosine) - (vec3_f32[1] * zRotSine);
y = (vec3_f32[1] * zRotCosine) + (vec3_f32[0] * zRotSine);
temp = y;
y = (temp * xRotCosine) - (vec3_f32[2] * xRotSine);
z = (vec3_f32[2] * xRotCosine) + (temp * xRotSine);
temp = x;
x = (temp * yRotCosine) + (z * yRotSine);
z = (z * yRotCosine) - (temp * yRotSine);
vec3_f32[0] = x;
vec3_f32[1] = y;
vec3_f32[2] = z;
}
#else
GLOBAL_ASM("asm/math_util/f32_vec3_apply_object_rotation.s")
#endif
#ifdef NON_EQUIVALENT
/* Official Name: mathOneFloatYPR */
void f32_vec3_apply_object_rotation2(ObjectTransform *trans, f32 *arg1) {
f32 yRotSine;
f32 yRotCosine;
f32 xRotSine;
f32 xRotCosine;
f32 zRotSine;
f32 zRotCosine;
f32 temp_f4;
f32 temp_f6;
f32 temp_f8;
xRotSine = sinf(trans->rotation.x_rotation);
xRotCosine = cosf(trans->rotation.x_rotation);
yRotSine = sinf(trans->rotation.y_rotation);
yRotCosine = cosf(trans->rotation.y_rotation);
zRotCosine = cosf(trans->rotation.z_rotation);
zRotSine = sinf(trans->rotation.z_rotation);
temp_f4 = (arg1[0] * xRotSine) + (arg1[2] * xRotCosine);
temp_f8 = (arg1[2] * xRotSine) - (arg1[0] * xRotCosine);
temp_f6 = (arg1[1] * yRotSine) - (temp_f8 * yRotCosine);
temp_f8 = (temp_f8 * yRotSine) + (arg1[1] * yRotCosine);
arg1[2] = temp_f8;
temp_f4 = (temp_f4 * zRotSine) - (temp_f6 * zRotCosine);
temp_f6 = (temp_f6 * zRotSine) + (temp_f4 * zRotCosine);
arg1[0] = temp_f4;
arg1[1] = temp_f6;
}
#else
GLOBAL_ASM("asm/math_util/f32_vec3_apply_object_rotation2.s")
#endif
#ifdef NON_EQUIVALENT
/* Official Name: mathOneFloatPY */
void f32_vec3_apply_object_rotation3(Vec3s *trans, f32 *vec3_f32) {
f32 xRotSine;
f32 xRotCosine;
f32 yRotSine;
f32 yRotCosine;
f32 x, y, z;
xRotSine = sinf(trans->x_rotation);
xRotCosine = cosf(trans->x_rotation);
yRotSine = sinf(trans->y_rotation);
yRotCosine = cosf(trans->y_rotation);
z = vec3_f32[2];
y = -(z * xRotSine);
z = z * xRotCosine;
x = (z * yRotSine);
z = z * yRotCosine;
vec3_f32[0] = x;
vec3_f32[1] = y;
vec3_f32[2] = z;
}
#else
GLOBAL_ASM("asm/math_util/f32_vec3_apply_object_rotation3.s")
#endif
#ifdef NON_MATCHING
/* Official Name: mathXZInTri */
s32 point_triangle_2d_xz_intersection(s32 x, s32 z, s16 *vec3A, s16 *vec3B, s16 *vec3C) {
s32 result;
s32 aX;
s32 aZ;
s32 bX;
s32 bZ;
s32 cX;
s32 cZ;
s32 var_a1;
s32 var_a2;
s32 var_a3;
aX = vec3A[0];
aZ = vec3A[2];
bX = vec3B[0];
bZ = vec3B[2];
cX = vec3C[0];
cZ = vec3C[2];
result = FALSE;
var_a1 = 1;
var_a2 = 1;
var_a3 = 1;
if ((((x - aX) * (bZ - aZ)) - ((bX - aX) * (z - aZ))) < 0) {
var_a3 ^= 1;
}
if ((((x - bX) * (cZ - bZ)) - ((cX - bX) * (z - bZ))) < 0) {
var_a2 ^= 1;
}
if (var_a3 == var_a2) {
if ((((x - cX) * (aZ - cZ)) - ((aX - cX) * (z - cZ))) < 0) {
var_a1 ^= 1;
}
if (var_a1 == var_a2) {
result = TRUE;
}
}
return result;
}
#else
GLOBAL_ASM("asm/math_util/point_triangle_2d_xz_intersection.s")
#endif
#ifdef NON_EQUIVALENT
/* Official Name: mathTranslateMtx */
void f32_matrix_from_position(Matrix *mtx, f32 x, f32 y, f32 z) {
s32 j;
s32 i;
// Clear matrix
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
*mtx[i][j] = 0;
}
}
*mtx[0][0] = 1.0f;
*mtx[1][1] = 1.0f;
*mtx[2][2] = 1.0f;
*mtx[3][3] = 1.0f;
*mtx[3][0] = x;
*mtx[3][1] = y;
*mtx[3][2] = z;
}
#else
GLOBAL_ASM("asm/math_util/f32_matrix_from_position.s")
#endif
/* Official Name: mathScaleMtx */
GLOBAL_ASM("asm/math_util/f32_matrix_from_scale.s")
#ifdef NON_MATCHING
// Blatantly stolen from SM64 :)
static u16 atan2_lookup(f32 y, f32 x) {
u16 ret;
if (x == 0) {
ret = gArcTanTable[0];
} else {
ret = gArcTanTable[(s32) (y / x * 1024 + 0.5f)];
}
return ret;
}
s32 atan2s(s32 xDelta, s32 zDelta) {
u16 ret;
if (xDelta >= 0) {
if (zDelta >= 0) {
if (zDelta >= xDelta) {
ret = atan2_lookup(xDelta, zDelta);
} else {
ret = 0x4000 - atan2_lookup(zDelta, xDelta);
}
} else {
zDelta = -zDelta;
if (zDelta < xDelta) {
ret = 0x4000 + atan2_lookup(zDelta, xDelta);
} else {
ret = 0x8000 - atan2_lookup(xDelta, zDelta);
}
}
} else {
xDelta = -xDelta;
if (zDelta < 0) {
zDelta = -zDelta;
if (zDelta >= xDelta) {
ret = 0x8000 + atan2_lookup(xDelta, zDelta);
} else {
ret = 0xC000 - atan2_lookup(zDelta, xDelta);
}
} else {
if (zDelta < xDelta) {
ret = 0xC000 + atan2_lookup(zDelta, xDelta);
} else {
ret = -atan2_lookup(xDelta, zDelta);
}
}
}
return ret;
}
#else
GLOBAL_ASM("asm/math_util/atan2s.s")
#endif
#ifdef NON_MATCHING
u16 arctan2_f(f32 y, f32 x) {
return atan2s((s32) (y * 255.0f), (s32) (x * 255.0f));
}
#else
GLOBAL_ASM("asm/math_util/arctan2_f.s")
#endif
#ifdef NON_EQUIVALENT // Untested
UNUSED s32 s32_matrix_cell_sqrt(s32 arg0) {
return (s32) (sqrtf((f32) arg0 / 65536.0f) * 65536.0f);
}
#else
GLOBAL_ASM("asm/math_util/s32_matrix_cell_sqrt.s")
#endif
#ifdef NON_EQUIVALENT // Untested
UNUSED s32 bad_int_sqrt(s32 arg0) {
return (s32) (sqrtf((f32) arg0 / 65536.0f) * 65536.0f);
}
#else
GLOBAL_ASM("asm/math_util/bad_int_sqrt.s")
#endif
GLOBAL_ASM("asm/math_util/sins_f.s")
GLOBAL_ASM("asm/math_util/coss_f.s")
GLOBAL_ASM("asm/math_util/coss.s")
GLOBAL_ASM("asm/math_util/sins_2.s")
#ifdef NON_EQUIVALENT // Untested
UNUSED s32 calc_dyn_lighting_for_level_segment(LevelModelSegment *segment, s32 *vec3_ints) {
s32 dotProduct;
s32 numVertsInBatch;
s32 vertCount;
s32 upperColor;
s32 alpha;
s32 numBatches;
s32 i, j;
Vertex *verts;
Vertex *verts2C;
TriangleBatchInfo *batches;
numBatches = segment->numberOfBatches;
batches = segment->batches;
vertCount = 0;
for (i = 0; i < numBatches; i++) {
// batches[i].unk6 is 0xFF if vertex colors are used. Otherwise dynamic lighting is used.
if ((batches[i].unk6 - 0xFF) != 0) {
verts = &segment->vertices[vertCount];
verts2C = &segment->unk2C[vertCount];
numVertsInBatch = batches[i + 1].verticesOffset - batches[i].verticesOffset;
for (j = 0; j < numVertsInBatch; j++) {
alpha = verts2C[j].a;
dotProduct =
(verts2C[j].x * vec3_ints[0]) + (verts2C[j].y * vec3_ints[1]) + (verts2C[j].z * vec3_ints[2]);
if (dotProduct > 0) {
alpha += dotProduct >> 22;
if (alpha > 128) {
alpha = 128;
}
}
upperColor = (alpha * (verts2C[j].r | (verts2C[j].g << 16))) >> 7;
verts[j].r = (s8) upperColor;
verts[j].g = (s8) (upperColor >> 16);
verts[j].b = (s8) ((u32) (alpha * verts2C[j].b) >> 7);
}
vertCount += numVertsInBatch;
} else {
vertCount += batches[i + 1].verticesOffset - batches[i].verticesOffset;
}
}
return vertCount;
}
#else
GLOBAL_ASM("asm/math_util/calc_dyn_lighting_for_level_segment.s")
#endif
#ifdef NON_MATCHING
/**
* Signed distance field calculation. It's used to calculate the level of intersection between a point and a triangle.
*/
f32 area_triangle_2d(f32 x0, f32 z0, f32 x1, f32 z1, f32 x2, f32 z2) {
f32 dx0 = x1 - x0;
f32 dz0 = z1 - z0;
f32 dx1 = x2 - x1;
f32 dz1 = z2 - z1;
f32 dx2 = x0 - x2;
f32 dz2 = z0 - z2;
f32 d0 = sqrtf((dx0 * dx0) + (dz0 * dz0)); // Distance between points 0 & 1
f32 d1 = sqrtf((dx1 * dx1) + (dz1 * dz1)); // Distance between points 1 & 2
f32 d2 = sqrtf((dx2 * dx2) + (dz2 * dz2)); // Distance between points 2 & 0
f32 m = 0.5f * (d0 + d1 + d2); // Half the sum of the distances?
f32 result = m * (m - d0) * (m - d1) * (m - d2);
if (result < 0.0f) {
result = 0.0f;
}
return sqrtf(result);
}
#else
GLOBAL_ASM("asm/math_util/area_triangle_2d.s")
#endif
GLOBAL_ASM("asm/math_util/set_breakpoint.s")
#ifdef NON_MATCHING
void dmacopy_doubleword(void *src, void *dst, s32 end) {
s32 size = end - (u32) dst;
memcpy(dst, src, size);
}
#else
GLOBAL_ASM("asm/math_util/dmacopy_doubleword.s")
#endif