#include <ultra64.h>
#include <mk64.h>
#include <macros.h>
#include <math_util.h>
#include <main.h>
#include "buffers.h"
#include <PR/rcp.h>
#include "data/trig_tables.h"
#include "math.h"

#pragma intrinsic (sqrtf,fabs)

s32 D_802B91C0[2] = { 13, 13 };
Vec3f D_802B91C8 = { 0.0f, 0.0f, 0.0f };

// This functions looks similar to a segment of code from func_802A4A0C in skybox_and_splitscreen.c
UNUSED s32 func_802B4F60(UNUSED s32 arg0, Vec3f arg1, UNUSED s32 arg2, UNUSED f32 arg3, UNUSED f32 arg4)
{
  Mat4 sp30;
  f32 sp2C;
  f32 sp28;
  Vec3f sp1C;
  vec3f_copy_return(sp1C, arg1);
  sp28 = sp1C[0];
  sp2C = sp1C[1];
  // wut?
  if (sp2C && sp2C);
  sp2C = ((sp30[0][3] * sp28) + (sp30[1][3] * sp2C) + (sp30[2][3] * sp1C[2])) + sp30[3][3];
  // double wut?
  if (sp28 && sp28);
  mtxf_translate_vec3f_mat4(sp1C, sp30);
  if (0.0f >= sp2C)
  {
    return 0;
  } else {
    return 1;
  }
}

UNUSED void func_802B4FF0() {

}

/**
 * Inserts matrix into the rsp. Position, rotation and mode of where to render the next object and check number of object already render
 * Note that gMatrixObjectCount gets reset at the beginning of the game loop. So no cleanup needs to be performed.
*/
s32 render_set_position(Mat4 arg0, s32 arg1) {
    if (gMatrixObjectCount >= MTX_OBJECT_POOL_SIZE) {
        return 0;
    }
    mtxf_to_mtx(&gGfxPool->mtxObject[gMatrixObjectCount], arg0);
    switch (arg1) {                                 /* irregular */
        case 0:
            gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&gGfxPool->mtxObject[gMatrixObjectCount++]), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
            break;
        case 1:
            gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&gGfxPool->mtxObject[gMatrixObjectCount++]), G_MTX_PUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
            break;
        case 3:
            gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&gGfxPool->mtxObject[gMatrixObjectCount++]), G_MTX_PUSH | G_MTX_MUL | G_MTX_MODELVIEW);
            break;
        case 2:
            gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&gGfxPool->mtxObject[gMatrixObjectCount++]), G_MTX_NOPUSH | G_MTX_MUL | G_MTX_MODELVIEW);
            break;
    }
    return 1;
}

f32 func_802B51E8(Vec3f arg0, Vec3f arg1) {
    f32 sub_y;
    f32 sub_z;
    f32 sub_x;

    sub_x = arg1[0] - arg0[0];
    sub_y = arg1[1] - arg0[1];
    sub_z = arg1[2] - arg0[2];
    return (sub_x * sub_x) + (sub_y * sub_y) + sub_z + sub_z;
}

s32 get_angle_between_points(Vec3f arg0, Vec3f arg1) {
    f32 temp_v1;
    f32 temp_v2;
    temp_v1 = arg1[0] - arg0[0];
    temp_v2 = arg1[2] - arg0[2];

    return atan2s(temp_v1, temp_v2);
}

// get_angle_between_points
u32 func_802B5258(Vec3f arg0, Vec3s arg1) {
    f32 temp_v1;
    f32 temp_v2;
    temp_v1 = arg1[0] - arg0[0];
    temp_v2 = arg1[2] - arg0[2];

    return atan2s(temp_v1, temp_v2);
}

void vec3f_set(Vec3f arg0, f32 arg1, f32 arg2, f32 arg3) {
    arg0[0] = arg1;
    arg0[1] = arg2;
    arg0[2] = arg3;
}

void vec3s_set(Vec3s arg0, s16 arg1, s16 arg2, s16 arg3) {
    arg0[0] = arg1;
    arg0[1] = arg2;
    arg0[2] = arg3;
}

// These functions have bogus return values.
// Disable the compiler warning.
#pragma GCC diagnostic push

#ifdef __GNUC__
#if defined(__clang__)
  #pragma GCC diagnostic ignored "-Wreturn-stack-address"
#else
  #pragma GCC diagnostic ignored "-Wreturn-local-addr"
#endif
#endif

void *vec3f_copy_return(Vec3f dest, Vec3f src) {
    dest[0] = src[0];
    dest[1] = src[1];
    dest[2] = src[2];
    //! @warning function returns address of local variable
    return &dest; 
}

void vec3s_copy(Vec3s dest, Vec3s src) {
    dest[0] = src[0];
    dest[1] = src[1];
    dest[2] = src[2];
}

UNUSED void *vec3f_set_return(Vec3f dest, f32 x, f32 y, f32 z) {
    dest[0] = x;
    dest[1] = y;
    dest[2] = z;
    return &dest;
}

// Copy mat1 to mat2
void mtxf_copy(Mat4 mat1, Mat4 mat2) {
    s32 row;
    s32 column;

    for (row = 0; row < 4; row++) {
        for (column = 0; column < 4; column++) {
            mat2[row][column] = mat1[row][column];
        }
    }
}

// mtxf_copy
void mtxf_copy_n_element(s32 *dest, s32 *src, s32 n) {
   while (n-- > 0) {
        *dest++ = *src++;
   }
}

// Transform a matrix to a matrix identity
void mtxf_identity(Mat4 mtx) {
    register s32 i;
    register s32 k;

    for (i = 0; i < 4; i++) {
        for (k = 0; k < 4; k++) {
            mtx[i][k] = (i == k) ? 1.0f : 0.0f;
        }
    }
}

// Add a translation vector to a matrix, mat is the matrix to add, dest is the destination matrix, pos is the translation vector
void add_translate_mat4_vec3f(Mat4 mat, Mat4 dest, Vec3f pos) {
    dest[3][0] = mat[3][0] + pos[0];
    dest[3][1] = mat[3][1] + pos[1];
    dest[3][2] = mat[3][2] + pos[2];
    dest[3][3] = mat[3][3];
    dest[0][0] = mat[0][0];
    dest[0][1] = mat[0][1];
    dest[0][2] = mat[0][2];
    dest[0][3] = mat[0][3];
    dest[1][0] = mat[1][0];
    dest[1][1] = mat[1][1];
    dest[1][2] = mat[1][2];
    dest[1][3] = mat[1][3];
    dest[2][0] = mat[2][0];
    dest[2][1] = mat[2][1];
    dest[2][2] = mat[2][2];
    dest[2][3] = mat[2][3];

    /*
     * mat(0,0)        mat(0,1)        mat(0,2)        mat(0,3)
     * mat(1,0)        mat(1,1)        mat(1,2)        mat(1,3)
     * mat(2,0)        mat(2,1)        mat(2,2)        mat(2,3)
     * mat(3,0)+pos(0) mat(3,1)+pos(1) mat(3,2)+pos(2) mat(3,3)
     */
}

// Light version of add_translate_mat4_vec3f
UNUSED void add_translate_mat4_vec3f_lite(Mat4 mat, Mat4 dest, Vec3f pos) {
    dest[3][0] = mat[3][0] + pos[0];
    dest[3][1] = mat[3][1] + pos[1];
    dest[3][2] = mat[3][2] + pos[2];
}

// create a translation matrix
void mtxf_translate(Mat4 dest, Vec3f b) {
    mtxf_identity(dest);
    dest[3][0] = b[0];
    dest[3][1] = b[1];
    dest[3][2] = b[2];
}

// Note the use of `2` which generates diff asm than just using floats (2.0f).
void func_802B5564(Mat4 arg0, u16 *arg1, f32 arg2, f32 arg3, f32 arg4, f32 arg5, f32 arg6) {
    f32 temp;
    s32 i, j;
    mtxf_identity(arg0);
    arg2 *= 0.017453292222222222;
    temp = cosf(arg2 / 2) / sinf(arg2 / 2);
    arg0[0][0] = temp / arg3;
    arg0[1][1] = temp;
    arg0[2][2] = (arg4 + arg5) / (arg4 - arg5);
    arg0[2][3] = -1.0f;
    arg0[3][2] = (2 * arg4 * arg5) / (arg4 - arg5);
    arg0[3][3] = 0.0f;

    for (i = 0; i < 4; i++) {
        for (j = 0; j < 4; j++) {
            arg0[i][j] *= arg6;
        }
    }

    if (arg1 != 0) {
        if ((arg4 + arg5) <= 2.0) {
            *arg1 = 0xFFFF;
        }
        else {
            *arg1 = 131072.0 / (arg4 + arg5);
            if (*arg1 <= 0) {
                *arg1 = 1;
            }
        }
    }
}

// Appears to only be for the skybox. mtxf_lookat from sm64 with some modifications.
void func_802B5794(Mat4 mtx, Vec3f from, Vec3f to) {
    // register from sm64 but not required for matching.
    register f32 invLength;
    f32 xColY;
    f32 yColY;
    f32 zColY;
    f32 xColZ;
    f32 yColZ;
    f32 zColZ;
    f32 xColX;
    f32 yColX;
    f32 zColX;

    xColY = 0.0f;
    yColY = 1.0f;
    zColY = 0.0f;

    xColZ = to[0] - from[0];
    yColZ = to[1] - from[1];
    zColZ = to[2] - from[2];

    invLength = -1.0 / sqrtf(xColZ * xColZ + yColZ * yColZ + zColZ * zColZ);
    xColZ *= invLength;
    yColZ *= invLength;
    zColZ *= invLength;

    xColX = yColY * zColZ - zColY * yColZ;
    yColX = zColY * xColZ - xColY * zColZ;
    zColX = xColY * yColZ - yColY * xColZ;

    invLength = 1.0 / sqrtf(xColX * xColX + yColX * yColX + zColX * zColX);

    xColX *= invLength;
    yColX *= invLength;
    zColX *= invLength;

    xColY = yColZ * zColX - zColZ * yColX;
    yColY = zColZ * xColX - xColZ * zColX;
    zColY = xColZ * yColX - yColZ * xColX;

    invLength = 1.0 / sqrtf(xColY * xColY + yColY * yColY + zColY * zColY);
    xColY *= invLength;
    yColY *= invLength;
    zColY *= invLength;

    mtx[0][0] = xColX;
    mtx[1][0] = yColX;
    mtx[2][0] = zColX;
    mtx[3][0] = -(from[0] * xColX + from[1] * yColX + from[2] * zColX);

    mtx[0][1] = xColY;
    mtx[1][1] = yColY;
    mtx[2][1] = zColY;
    mtx[3][1] = -(from[0] * xColY + from[1] * yColY + from[2] * zColY);

    mtx[0][2] = xColZ;
    mtx[1][2] = yColZ;
    mtx[2][2] = zColZ;
    mtx[3][2] = -(from[0] * xColZ + from[1] * yColZ + from[2] * zColZ);

    mtx[0][3] = 0.0f;
    mtx[1][3] = 0.0f;
    mtx[2][3] = 0.0f;
    mtx[3][3] = 1.0f;
}

// create a rotation matrix around the x axis
void mtxf_rotate_x(Mat4 mat, s16 angle) {
    f32 sin_theta = sins(angle);
    f32 cos_theta = coss(angle);

    mtxf_identity(mat);
    mat[1][1] = cos_theta;
    mat[1][2] = sin_theta;
    mat[2][1] = -sin_theta;
    mat[2][2] = cos_theta;

    /*
     * 1, 0, 0, 0,
     * 0, cos_theta, sin_theta, 0,
     * 0, -sin_theta, cos_theta, 0,
     * 0, 0, 0, 1
     */
}

// create a rotation matrix around the y axis
void mtxf_rotate_y(Mat4 mat, s16 angle) {
    f32 sin_theta = sins(angle);
    f32 cos_theta = coss(angle);

    mtxf_identity(mat);
    mat[0][0] = cos_theta;
    mat[0][2] = -sin_theta;
    mat[2][0] = sin_theta;
    mat[2][2] = cos_theta;

    /*
     * cos_theta, 0, -sin_theta, 0,
     * 0, 1, 0, 0,
     * sin_theta, 0, cos_theta, 0,
     * 0, 0, 0, 1
     */
}

// create a rotation matrix around the z axis
void mtxf_s16_rotate_z(Mat4 mat, s16 angle) {
    f32 sin_theta = sins(angle);
    f32 cos_theta = coss(angle);

    mtxf_identity(mat);
    mat[0][0] = cos_theta;
    mat[0][1] = sin_theta;
    mat[1][0] = -sin_theta;
    mat[1][1] = cos_theta;

    /*
     * cos_theta, sin_theta, 0, 0,
     * -sin_theta, cos_theta, 0, 0,
     * 0, 0, 1, 0,
     * 0, 0, 0, 1
     */
}

#ifdef MIPS_TO_C
//generated by m2c commit beb457dabfc7a01ec6540a5404a6a05097a13602 on Oct-29-2023
void func_802B5B14(f32 *arg0, s16 *arg1) {
    f32 sp70;
    f32 sp6C;
    f32 sp68;
    f32 sp60;
    f32 sp5C;
    f32 sp58;
    f32 sp50;
    f32 sp4C;
    f32 sp48;
    f32 sp40;
    f32 sp3C;
    f32 sp38;
    f32 sp30;
    f32 sp2C;
    f32 sp28;
    f32 temp_f0;
    f32 temp_f10;
    f32 temp_f12;
    f32 temp_f18;
    f32 temp_f20;
    f32 temp_f4;
    f32 temp_f6;

    sp38 = sins((u16) arg1->unk0);
    temp_f20 = coss((u16) arg1->unk0);
    sp30 = sins(arg1->unk2);
    sp2C = coss(arg1->unk2);
    sp28 = sins(arg1->unk4);
    temp_f0 = coss(arg1->unk4);
    temp_f4 = arg0->unk0;
    temp_f12 = sp38 * sp30;
    sp3C = temp_f4;
    sp40 = arg0->unk4;
    temp_f6 = (sp2C * temp_f0) + (temp_f12 * sp28);
    sp48 = temp_f6;
    sp58 = (-sp2C * sp28) + (temp_f12 * temp_f0);
    sp68 = temp_f20 * sp30;
    sp4C = temp_f20 * sp28;
    temp_f18 = sp38 * sp2C;
    sp5C = temp_f20 * temp_f0;
    sp6C = -sp38;
    temp_f10 = (-sp30 * temp_f0) + (temp_f18 * sp28);
    sp50 = temp_f10;
    sp60 = (sp30 * sp28) + (temp_f18 * temp_f0);
    sp70 = temp_f20 * sp2C;
    arg0->unk0 = (temp_f10 * sp40) + ((temp_f4 * temp_f6) + (sp40 * sp4C));
    arg0->unk4 = (f32) ((sp60 * sp40) + ((temp_f4 * sp58) + (sp40 * sp5C)));
    arg0->unk8 = (f32) ((sp70 * sp40) + ((sp3C * sp68) + (sp40 * sp6C)));
}
#else
GLOBAL_ASM("asm/non_matchings/racing/math_util/func_802B5B14.s")
#endif

void func_802B5CAC(s16 arg0, s16 arg1, Vec3f arg2) {
    f32 sp2C = sins(arg1);
    f32 sp28 = coss(arg1);
    f32 sp24 = sins(arg0);
    f32 temp_f10 = coss(arg0);

    arg2[0] = sp28 * sp24;
    arg2[1] = sp2C;
    arg2[2] = -(sp28 * temp_f10);
}

void func_802B5D30(s16 arg0, s16 arg1, s32 arg2) {
    func_802B5D64(0x9000000, arg0, arg1, arg2);
}

void func_802B5D64(uintptr_t arg0, s16 arg1, s16 arg2, s32 arg3) {
    UNUSED s32 pad[3];
    f32 sp48;
    f32 sp44;
    f32 sp40;
    UNUSED s32 pad2[2];
    f32 temp_f10;
    s32 var_v0;
    s8 sp2C[3];
    Lights1 *var_s0;

    var_s0 = (Lights1 *) VIRTUAL_TO_PHYSICAL2(gSegmentTable[arg0 >> 0x18] + (arg0 & 0xFFFFFF));
    sp48 = sins(arg2);
    sp44 = coss(arg2);
    sp40 = sins(arg1);
    temp_f10 = coss(arg1);
    sp2C[0] = sp44 * sp40 * 120.0f;
    sp2C[1] = 120.0f * sp48;
    sp2C[2] = sp44 * temp_f10 * -120.0f;
    for (var_v0 = 0; var_v0 < arg3; var_v0++, var_s0++) {
        var_s0->l[0].l.dir[0] = sp2C[0];
        var_s0->l[0].l.dir[1] = sp2C[1];
        var_s0->l[0].l.dir[2] = sp2C[2];
    }
}

// multiply a matrix with a number
void mtxf_scale(Mat4 mat, f32 coef) {
    mat[0][0] *= coef;
    mat[1][0] *= coef;
    mat[2][0] *= coef;
    mat[0][1] *= coef;
    mat[1][1] *= coef;
    mat[2][1] *= coef;
    mat[0][2] *= coef;
    mat[1][2] *= coef;
    mat[2][2] *= coef;
}

// look like create a translation and rotation matrix with arg1 position and arg2 rotation
void func_802B5F74(Mat4 arg0, Vec3f arg1, Vec3s arg2) {
    f32 sine1;
    f32 cosine1;
    f32 sine2;
    f32 cosine2;
    f32 sine3;
    f32 cosine3;

    sine1   = sins(arg2[0]);
    cosine1 = coss(arg2[0]);
    sine2   = sins(arg2[1]);
    cosine2 = coss(arg2[1]);
    sine3   = sins(arg2[2]);
    cosine3 = coss(arg2[2]);
    arg0[0][0] = (cosine2 * cosine3) + ((sine1 * sine2) * sine3);
    arg0[1][0] = (-cosine2 * sine3) + ((sine1 * sine2) * cosine3);
    arg0[2][0] = cosine1 * sine2;
    arg0[3][0] = arg1[0];
    arg0[0][1] = cosine1 * sine3;
    arg0[1][1] = cosine1 * cosine3;
    arg0[2][1] = -sine1;
    arg0[3][1] = arg1[1];
    arg0[0][2] = (-sine2 * cosine3) + ((sine1 * cosine2) * sine3);
    arg0[1][2] = (sine2 * sine3) + ((sine1 * cosine2) * cosine3);
    arg0[2][2] = cosine1 * cosine2;
    arg0[3][2] = arg1[2];
    arg0[0][3] = 0.0f;
    arg0[1][3] = 0.0f;
    arg0[2][3] = 0.0f;
    arg0[3][3] = 1.0f;
}

UNUSED void func_802B60B4(Mat4 arg0, Vec3s arg1, Vec3s arg2) {
    f32 sine1;
    f32 cosine1;
    f32 sine2;
    f32 cosine2;
    f32 sine3;
    f32 cosine3;

    sine1   = sins(arg2[0]);
    cosine1 = coss(arg2[0]);
    sine2   = sins(arg2[1]);
    cosine2 = coss(arg2[1]);
    sine3   = sins(arg2[2]);
    cosine3 = coss(arg2[2]);
    arg0[0][0] = (cosine2 * cosine3) + ((sine1 * sine2) * sine3);
    arg0[0][1] = (-cosine2 * sine3) + ((sine1 * sine2) * cosine3);
    arg0[0][2] = cosine1 * sine2;
    arg0[0][3] = (f32) arg1[0];
    arg0[1][0] = (f32) (cosine1 * sine3);
    arg0[1][1] = (f32) (cosine1 * cosine3);
    arg0[1][2] = (f32) -sine1;
    arg0[1][3] = (f32) arg1[1];
    arg0[2][0] = (f32) ((-sine2 * cosine3) + ((sine1 * cosine2) * sine3));
    arg0[2][1] = (f32) ((sine2 * sine3) + ((sine1 * cosine2) * cosine3));
    arg0[2][2] = (f32) (cosine1 * cosine2);
    arg0[2][3] = (f32) arg1[2];
    arg0[3][0] = 0.0f;
    arg0[3][1] = 0.0f;
    arg0[3][2] = 0.0f;
    arg0[3][3] = 1.0f;
}

UNUSED void func_802B6214(Mat4 arg0, Vec3s arg1, Vec3s arg2) {
    f32 sine1;
    f32 cosine1;
    f32 sine2;
    f32 cosine2;
    f32 sine3;
    f32 cosine3;

    sine1   = sins(arg2[0]);
    cosine1 = coss(arg2[0]);
    sine2   = sins(arg2[1]);
    cosine2 = coss(arg2[1]);
    sine3   = sins(arg2[2]);
    cosine3 = coss(arg2[2]);
    arg0[0][0] = (cosine2 * cosine3) + ((sine1 * sine2) * sine3);
    arg0[1][0] = (-cosine2 * sine3) + ((sine1 * sine2) * cosine3);
    arg0[2][0] = cosine1 * sine2;
    arg0[3][0] = arg1[0];
    arg0[0][1] = cosine1 * sine3;
    arg0[1][1] = cosine1 * cosine3;
    arg0[2][1] = -sine1;
    arg0[3][1] = arg1[1];
    arg0[0][2] = (-sine2 * cosine3) + ((sine1 * cosine2) * sine3);
    arg0[1][2] = (sine2 * sine3) + ((sine1 * cosine2) * cosine3);
    arg0[2][2] = cosine1 * cosine2;
    arg0[3][2] = arg1[2];
    arg0[0][3] = 0.0f;
    arg0[1][3] = 0.0f;
    arg0[2][3] = 0.0f;
    arg0[3][3] = 1.0f;
}

// look like to normalise vector
UNUSED void func_802B6374(Vec3f arg0) {
    f32 temp_f0;
    temp_f0 = sqrtf((arg0[0] * arg0[0]) + (arg0[1] * arg0[1]) + (arg0[2] * arg0[2]));
    arg0[0] /= temp_f0;
    arg0[1] /= temp_f0;
    arg0[2] /= temp_f0;
}

// translate the vector with a matrix
void mtxf_translate_vec3f_mat3(Vec3f pos, Mat3 mat) {
    f32 new_x;
    f32 new_y;
    f32 new_z;

    new_x = (mat[0][0] * pos[0]) + (mat[0][1] * pos[1]) + (mat[0][2] * pos[2]);
    new_y = (mat[1][0] * pos[0]) + (mat[1][1] * pos[1]) + (mat[1][2] * pos[2]);
    new_z = (mat[2][0] * pos[0]) + (mat[2][1] * pos[1]) + (mat[2][2] * pos[2]);

    pos[0] = new_x;
    pos[1] = new_y;
    pos[2] = new_z;
}

// translate the vector with a matrix (with a matrix 4x4)
void mtxf_translate_vec3f_mat4(Vec3f pos, Mat4 mat) {
    f32 new_x;
    f32 new_y;
    f32 new_z;

    new_x = (mat[0][0] * pos[0]) + (mat[0][1] * pos[1]) + (mat[0][2] * pos[2]);
    new_y = (mat[1][0] * pos[0]) + (mat[1][1] * pos[1]) + (mat[1][2] * pos[2]);
    new_z = (mat[2][0] * pos[0]) + (mat[2][1] * pos[1]) + (mat[2][2] * pos[2]);


    pos[0] = new_x;
    pos[1] = new_y;
    pos[2] = new_z;
}

UNUSED void func_802B64B0(UNUSED s32 arg0, UNUSED s32 arg1, UNUSED s32 arg2, UNUSED s32 arg3) {

}

void func_802B64C4(Vec3f arg0, s16 arg1) {
    f32 sp2C = sins(arg1);
    f32 temp_f0 = coss(arg1);

    f32 temp1 = arg0[0];
    f32 temp2 = arg0[1];
    f32 temp3 = arg0[2];

    arg0[0] = temp_f0 * temp1 - (sp2C * temp3);
    arg0[1] = temp2;
    arg0[2] = sp2C * temp1 + (temp_f0 * temp3);
}

void calculate_orientation_matrix(Mat3 dest, f32 arg1, f32 arg2, f32 arg3, s16 rotationAngle) {
    Mat3 mtx_rot_y;
    Mat3 matrix;
    s32 i, j;
    f32 a;
    f32 b;
    f32 c;
    f32 d;
    UNUSED s32 pad[3];
    f32 sinValue;
    f32 cossValue;

    sinValue = sins(rotationAngle);
    cossValue = coss(rotationAngle);
    mtx_rot_y[0][0] = cossValue;
    mtx_rot_y[2][1] = 0;
    mtx_rot_y[1][2] = 0;

    mtx_rot_y[1][1] = 1;
    mtx_rot_y[2][0] = sinValue;
    mtx_rot_y[0][2] = -sinValue;

    mtx_rot_y[2][2] = cossValue;
    mtx_rot_y[1][0] = 0;
    mtx_rot_y[0][1] = 0;

    if (arg2 == 1) { // set matrix to identity

        for (i = 0; i < 3; i++) {
            for (j = 0; j < 3; j++) {
                matrix[i][j] = (i == j) ? 1.0f : 0.0f;
            }
        }

    } else if (arg2 == -1) { // set matrix to identity with the second column negative

        for (i = 0; i < 3; i++) {
            for (j = 0; j < 3; j++) {
                matrix[i][j] = (i == j) ? 1.0f : 0.0f;
            }
        }

        matrix[1][1] = -1;

    } else {
        a = (f32) -(360.0 - ((f64) (calculate_vector_angle_xy(arg2) * 180.0f) / M_PI));
        b = -arg3 / sqrtf((arg1 * arg1) + (arg3 * arg3));
        c = 0;
        d = arg1 / sqrtf((arg1 * arg1) + (arg3 * arg3));
        calculate_rotation_matrix(matrix, a, b, c, d);

    }
    dest[0][0] = (mtx_rot_y[0][0] * matrix[0][0]) + (mtx_rot_y[0][1] * matrix[1][0]) + (mtx_rot_y[0][2] * matrix[2][0]);
    dest[1][0] = (mtx_rot_y[1][0] * matrix[0][0]) + (mtx_rot_y[1][1] * matrix[1][0]) + (mtx_rot_y[1][2] * matrix[2][0]);
    dest[2][0] = (mtx_rot_y[2][0] * matrix[0][0]) + (mtx_rot_y[2][1] * matrix[1][0]) + (mtx_rot_y[2][2] * matrix[2][0]);

    dest[0][1] = (mtx_rot_y[0][0] * matrix[0][1]) + (mtx_rot_y[0][1] * matrix[1][1]) + (mtx_rot_y[0][2] * matrix[2][1]);
    dest[1][1] = (mtx_rot_y[1][0] * matrix[0][1]) + (mtx_rot_y[1][1] * matrix[1][1]) + (mtx_rot_y[1][2] * matrix[2][1]);
    dest[2][1] = (mtx_rot_y[2][0] * matrix[0][1]) + (mtx_rot_y[2][1] * matrix[1][1]) + (mtx_rot_y[2][2] * matrix[2][1]);

    dest[0][2] = (mtx_rot_y[0][0] * matrix[0][2]) + (mtx_rot_y[0][1] * matrix[1][2]) + (mtx_rot_y[0][2] * matrix[2][2]);
    dest[1][2] = (mtx_rot_y[1][0] * matrix[0][2]) + (mtx_rot_y[1][1] * matrix[1][2]) + (mtx_rot_y[1][2] * matrix[2][2]);
    dest[2][2] = (mtx_rot_y[2][0] * matrix[0][2]) + (mtx_rot_y[2][1] * matrix[1][2]) + (mtx_rot_y[2][2] * matrix[2][2]);

}

// include in calculate_orientation_matrix
UNUSED void func_802B68F8(Mat3 matrix, f32 arg1, f32 arg2, f32 arg3) {
    s32 i, j;
    f32 a;
    f32 b;
    f32 c;
    f32 d;
    UNUSED f32 pad;

    if (arg2 == 1) {
        for (i = 0; i < 3; i++) {
            for (j = 0; j < 3; j++) {
                matrix[i][j] = (i == j) ? 1.0f : 0.0f;
            }
        }
    } else if (arg2 == -1) {
        for (i = 0; i < 3; i++) {
            for (j = 0; j < 3; j++) {
                matrix[i][j] = (i == j) ? 1.0f : 0.0f;
            }
        }
        matrix[1][1] = -1.0f;
    } else {
        a = (f32) -(360.0 - ((f64) (calculate_vector_angle_xy(arg2) * 180.0f) / M_PI));
        b = -arg3 / sqrtf((arg1 * arg1) + (arg3 * arg3));
        c = 0;
        d = arg1 / sqrtf((arg1 * arg1) + (arg3 * arg3));
        calculate_rotation_matrix(matrix, a, b, c, d);
    }
}

void calculate_rotation_matrix(Mat3 destMatrix, s16 rotationAngle, f32 rotationX, f32 rotationY, f32 rotationZ) {
    f32 sinValue;
    f32 cossValue;
    f32 temp_f12;
    f32 temp_f10;
    f32 temp_f2;
    f32 temp;
    UNUSED s32 pad[2];

    sinValue = sins((u16) rotationAngle);
    cossValue = coss((u16) rotationAngle);

    temp_f12 = 1.0f - cossValue;

    temp_f10 = (rotationZ * rotationX) * temp_f12;
    temp_f2 = (rotationY * rotationZ) * temp_f12;
    temp = ((rotationX * rotationY) * temp_f12);

    temp_f12 = rotationX * rotationX;
    destMatrix[0][0] = ((1.0f - temp_f12) * cossValue) + temp_f12;
    destMatrix[2][1] = temp_f2 - (rotationX * sinValue);
    destMatrix[1][2] = temp_f2 + (rotationX * sinValue);

    temp_f12 = rotationY * rotationY;
    destMatrix[1][1] = (((1.0f - temp_f12) * cossValue) + temp_f12);
    destMatrix[2][0] = temp_f10 + (rotationY * sinValue);
    destMatrix[0][2] = temp_f10 - (rotationY * sinValue);

    temp_f12 = rotationZ * rotationZ;
    destMatrix[2][2] = (((1.0f - temp_f12) * cossValue) + temp_f12);
    destMatrix[1][0] = temp - (rotationZ * sinValue);
    destMatrix[0][1] = temp + (rotationZ * sinValue);
}

void func_802B6BC0(Mat4 arg0, s16 arg1, f32 arg2, f32 arg3, f32 arg4) {
    f32 sine;
    f32 cosine;
    f32 temp_f0;
    f32 temp_f12;

    sine = sins(arg1);
    cosine = coss(arg1);
    temp_f0 = sqrtf((arg2 * arg2) + (arg4 * arg4));
    if (temp_f0 != 0.0f) {
        temp_f12 = 1.0f / temp_f0;
        arg0[0][0] = ((-arg4 * cosine) - ((sine * arg3) * arg2)) * temp_f12;
        arg0[0][3] = ((arg4 * sine) - ((cosine * arg3) * arg2)) * temp_f12;
        arg0[1][2] = -arg2;
        arg0[0][1] = sine * temp_f0;
        arg0[1][0] = cosine * temp_f0;
        arg0[1][3] = -arg3;
        arg0[0][2] = ((cosine * arg2) - ((sine * arg3) * arg4)) * temp_f12;
        arg0[1][1] = ((-sine * arg2) - ((cosine * arg3) * arg4)) * temp_f12;
        arg0[2][0] = -arg4;
        arg0[0][3] = 0.0f;
        arg0[1][2] = 0.0f;
        arg0[2][1] = 0.0f;
    } else {
        arg0[0][1] = 0.0f;
        arg0[1][3] = 0.0f;
        arg0[0][2] = 0.0f;
        arg0[1][1] = 0.0f;
        arg0[0][3] = 0.0f;
        arg0[1][2] = 0.0f;
        arg0[2][1] = 0.0f;
        arg0[0][0] = 1.0f;
        arg0[1][0] = 1.0f;
        arg0[2][0] = 1.0f;
    }
}

// look like create a translation and rotation matrix with arg1 position and arg2 rotation
void func_802B6D58(Mat4 arg0, Vec3f arg1, Vec3f arg2) {
    f32 sine1;
    f32 cosine1;
    f32 sine2;
    f32 cosine2;
    f32 sine3;
    f32 cosine3;

    sine1 = sins(arg2[0]);
    cosine1 = coss(arg2[0]);
    sine2 = sins(arg2[1]);
    cosine2 = coss(arg2[1]);
    sine3 = sins(arg2[2]);
    cosine3 = coss(arg2[2]);
    arg0[0][0] = (cosine2 * cosine3) + ((sine1 * sine2) * sine3);
    arg0[1][0] = (-cosine2 * sine3) + (sine1 * sine2) * cosine3;
    arg0[2][0] = cosine1 * sine2;
    arg0[3][0] = arg1[0];
    arg0[0][1] = cosine1 * sine3;
    arg0[1][1] = cosine1 * cosine3;
    arg0[2][1] = -sine1;
    arg0[3][1] = arg1[1];
    arg0[0][2] = (-sine2 * cosine3) + ((sine1 * cosine2) * sine3);
    arg0[1][2] = (sine2 * sine3) + ((sine1 * cosine2) * cosine3);
    arg0[2][2] = cosine1 * cosine2;
    arg0[3][2] = arg1[2];
    arg0[0][3] = 0.0f;
    arg0[1][3] = 0.0f;
    arg0[2][3] = 0.0f;
    arg0[3][3] = 1.0f;
}

void mtxf_multiplication(Mat4 dest, Mat4 mat1, Mat4 mat2) {
    Mat4 product;
    product[0][0] = (mat1[0][0] * mat2[0][0]) + (mat1[0][1] * mat2[1][0]) + (mat1[0][2] * mat2[2][0]) + (mat1[0][3] * mat2[3][0]);
    product[0][1] = (mat1[0][0] * mat2[0][1]) + (mat1[0][1] * mat2[1][1]) + (mat1[0][2] * mat2[2][1]) + (mat1[0][3] * mat2[3][1]);
    product[0][2] = (mat1[0][0] * mat2[0][2]) + (mat1[0][1] * mat2[1][2]) + (mat1[0][2] * mat2[2][2]) + (mat1[0][3] * mat2[3][2]);
    product[0][3] = (mat1[0][0] * mat2[0][3]) + (mat1[0][1] * mat2[1][3]) + (mat1[0][2] * mat2[2][3]) + (mat1[0][3] * mat2[3][3]);
    product[1][0] = (mat1[1][0] * mat2[0][0]) + (mat1[1][1] * mat2[1][0]) + (mat1[1][2] * mat2[2][0]) + (mat1[1][3] * mat2[3][0]);
    product[1][1] = (mat1[1][0] * mat2[0][1]) + (mat1[1][1] * mat2[1][1]) + (mat1[1][2] * mat2[2][1]) + (mat1[1][3] * mat2[3][1]);
    product[1][2] = (mat1[1][0] * mat2[0][2]) + (mat1[1][1] * mat2[1][2]) + (mat1[1][2] * mat2[2][2]) + (mat1[1][3] * mat2[3][2]);
    product[1][3] = (mat1[1][0] * mat2[0][3]) + (mat1[1][1] * mat2[1][3]) + (mat1[1][2] * mat2[2][3]) + (mat1[1][3] * mat2[3][3]);
    product[2][0] = (mat1[2][0] * mat2[0][0]) + (mat1[2][1] * mat2[1][0]) + (mat1[2][2] * mat2[2][0]) + (mat1[2][3] * mat2[3][0]);
    product[2][1] = (mat1[2][0] * mat2[0][1]) + (mat1[2][1] * mat2[1][1]) + (mat1[2][2] * mat2[2][1]) + (mat1[2][3] * mat2[3][1]);
    product[2][2] = (mat1[2][0] * mat2[0][2]) + (mat1[2][1] * mat2[1][2]) + (mat1[2][2] * mat2[2][2]) + (mat1[2][3] * mat2[3][2]);
    product[2][3] = (mat1[2][0] * mat2[0][3]) + (mat1[2][1] * mat2[1][3]) + (mat1[2][2] * mat2[2][3]) + (mat1[2][3] * mat2[3][3]);
    product[3][0] = (mat1[3][0] * mat2[0][0]) + (mat1[3][1] * mat2[1][0]) + (mat1[3][2] * mat2[2][0]) + (mat1[3][3] * mat2[3][0]);
    product[3][1] = (mat1[3][0] * mat2[0][1]) + (mat1[3][1] * mat2[1][1]) + (mat1[3][2] * mat2[2][1]) + (mat1[3][3] * mat2[3][1]);
    product[3][2] = (mat1[3][0] * mat2[0][2]) + (mat1[3][1] * mat2[1][2]) + (mat1[3][2] * mat2[2][2]) + (mat1[3][3] * mat2[3][2]);
    product[3][3] = (mat1[3][0] * mat2[0][3]) + (mat1[3][1] * mat2[1][3]) + (mat1[3][2] * mat2[2][3]) + (mat1[3][3] * mat2[3][3]);
    mtxf_copy_n_element((s32 *)dest, (s32 *)product, 16);
}

/**
 * Convert float matrix 'src' to fixed point matrix 'dest'.
 * The float matrix may not contain entries larger than 65536 or the console
 * crashes. The fixed point matrix has entries with a 16-bit integer part, so
 * the floating point numbers are multiplied by 2^16 before being cast to a s32
 * integer. If this doesn't fit, the N64 and iQue consoles will throw an
 * exception. On Wii and Wii U Virtual Console the value will simply be clamped
 * and no crashes occur.
 */
void mtxf_to_mtx(Mtx *dest, Mat4 src) {
#ifdef AVOID_UB
    // Avoid type-casting which is technically UB by calling the equivalent
    // guMtxF2L function. This helps little-endian systems, as well.
    guMtxF2L(src, dest);
#else
    s32 asFixedPoint;
    register s32 i;
    register s16 *a3 = (s16 *) dest;      // all integer parts stored in first 16 bytes
    register s16 *t0 = (s16 *) dest + 16; // all fraction parts stored in last 16 bytes
    register f32 *t1 = (f32 *) src;

    for (i = 0; i < 16; i++) {
        asFixedPoint = *t1++ * (1 << 16); //! float-to-integer conversion responsible for PU crashes
        *a3++ = GET_HIGH_S16_OF_32(asFixedPoint); // integer part
        *t0++ = GET_LOW_S16_OF_32(asFixedPoint);  // fraction part
    }
#endif
}

/**
 * Comment from sm64 unverified. mk64 verison is modified
 *
 * Helper function for atan2s. Does a look up of the arctangent of y/x assuming
 * the resulting angle is in range [0, 0x2000] (1/8 of a circle).
 */

u16 atan2_lookup(f32 y, f32 x) {
    u16 ret;

    if (x == 0) {
        ret = gArctanTable[0];
    } else {
        if (1000000.0f < y / x) {
            if (y > 0.0f) {
                ret = 0x4000;
            } else {
                ret = 0xC000;
            }
        } else {
            ret = gArctanTable[(s32)(y / x * 1024 + 0.5f)];
        }
    }
    return ret;
}

/**
 * Compute the angle from (0, 0) to (x, y) as a u16. Given that terrain is in
 * the xz-plane, this is commonly called with (z, x) to get a yaw angle.
 * sm64 but x, y swapped and returns u16.
 */
u16 atan2s(f32 x, f32 y) {
    u16 ret;
    if (x >= 0) {
        if (y >= 0) {
            if (y >= x) {
                ret = atan2_lookup(x, y);
            } else {
                ret = 0x4000 - atan2_lookup(y, x);
            }
        } else {
            y = -y;
            if (y < x) {
                ret = 0x4000 + atan2_lookup(y, x);
            } else {
                ret = 0x8000 - atan2_lookup(x, y);
            }
        }
    } else {
        x = -x;
        if (y < 0) {
            y = -y;
            if (y >= x) {
                ret = 0x8000 + atan2_lookup(x, y);
            } else {
                ret = 0xC000 - atan2_lookup(y, x);
            }
        } else {
            if (y < x) {
                ret = 0xC000 + atan2_lookup(y, x);
            } else {
                ret = -atan2_lookup(x, y);
            }
        }
    }
    return ret;
}

f32 atan2f(f32 arg0, f32 arg1) {
    return atan2s(arg0, arg1);
}

UNUSED f32 func_802B79F0(f32 arg0, f32 arg1) {
    f64 halfpi;
    f32 temp_f0;
    UNUSED f32 pad;
    f32 temp_f2;
    f32 var_f16;
    f32 var_f2;
    s32 var_v0;

    var_f16 = arg0 / arg1;
    var_v0 = 0;
    if (fabs(arg1) < fabs(arg0)) {
        var_v0 = 1;
    }
    if (var_v0 != 0) {
        var_f16 = arg1 / arg0;
    }
    temp_f0 = var_f16 * var_f16;
    temp_f2 = temp_f0 * temp_f0;
    var_f16 += ((((((((temp_f2 * ((-0.01600503f) + (temp_f0 * 0.00283406f))) + (-0.07495445f)) + (temp_f0 * 0.04258761f)) * (temp_f2 * temp_f2)) + (((-0.14202571f) + (temp_f0 * 0.10636754f)) * temp_f2)) + (-0.33333066f)) + (temp_f0 * 0.19992484f)) * (var_f16 * temp_f0));

    if (var_v0 != 0) {
        halfpi = 1.5707963267948966;
        return (arg0 < 0.0f ? -halfpi : halfpi) - var_f16;
    }
    if (arg1 >= 0.0f) {
        return var_f16;
    }
    var_f2 = var_f16 + 3.1415927f;
    if (arg0 < 0.0f) {
        var_f2 = var_f16 - 3.1415927f;
    }
    return var_f2;
}

UNUSED u16 func_802B7B50(f32 arg0, f32 arg1) {
    return ((atan2f(arg0, arg1) * 32768.0f) / M_PI);
}

UNUSED void func_802B7C18(f32 arg0) {
    atan2f(arg0, 1.0f);
}

s16 func_802B7C40(f32 arg0) {
    return atan2s(arg0, 1.0f);
}

UNUSED void func_802B7C6C(f32 arg0) {
    atan2f(arg0, sqrtf(1.0 - (arg0 * arg0)));
}

s16 func_802B7CA8(f32 arg0) {
    return atan2s(arg0, sqrtf(1.0 - (arg0 * arg0)));
}

f32 calculate_vector_angle_xy(f32 vectorX) {
    return atan2f(sqrtf(1.0 - (vectorX * vectorX)), vectorX);
}

UNUSED s16 func_802B7D28(f32 arg0) {
    return atan2f(sqrtf(1.0 - (f64)(arg0 * arg0)), arg0) * 32768.0f / M_PI;
}

u16 random_u16(void) {
    u16 temp1, temp2;

    if (gRandomSeed16 == 22026) {
        gRandomSeed16 = 0;
    }

    temp1 = (gRandomSeed16 & 0x00FF) << 8;
    temp1 = temp1 ^ gRandomSeed16;

    gRandomSeed16 = ((temp1 & 0x00FF) << 8) + ((temp1 & 0xFF00) >> 8);

    temp1 = ((temp1 & 0x00FF) << 1) ^ gRandomSeed16;
    temp2 = (temp1 >> 1) ^ 0xFF80;

    if ((temp1 & 1) == 0) {
        if (temp2 == 43605) {
            gRandomSeed16 = 0;
        } else {
            gRandomSeed16 = temp2 ^ 0x1FF4;
        }
    } else {
        gRandomSeed16 = temp2 ^ 0x8180;
    }

    return gRandomSeed16;
}

u16 random_int(u16 arg0) {
    return arg0 * (( (f32) random_u16() )  / 65535.0);
}

s16 func_802B7F34(f32 arg0, f32 arg1, f32 arg2, f32 arg3) {
    return atan2s(arg2 - arg0, arg3 - arg1);
}

void func_802B7F7C(Vec3f arg0, Vec3f arg1, Vec3s dest) {
    f32 x1 = arg0[0];
    f32 y1 = arg0[1];
    f32 z1 = arg0[2];

    f32 x2 = arg1[0];
    f32 y2 = arg1[1];
    f32 z2 = arg1[2];

    dest[1] = func_802B7F34(z1, x1, z2, x2);
    dest[0] = func_802B7F34(y1, z1, y2, z2);
    dest[2] = func_802B7F34(x1, y1, x2, y2);
}

f32 sins(u16 arg0) {
    return gSineTable[arg0 >> 4];
}

f32 coss(u16 arg0) {
    return gCosineTable[arg0 >> 4];
}

s32 is_visible_between_angle(u16 arg0, u16 arg1, u16 arg2) {
    if (arg1 < arg0) {
        if (arg1 >= arg2) {
            return 0;
        }
        if (arg2 >= arg0) {
            return 0;
        }
    } else {
        if ((arg1 >= arg2) && (arg2 >= arg0)) {
            return 0;
        }
    }
    return 1;
}

/**
 * Determines whether an object is within the render distance of a camera.
 *
 * @param cameraPos       The position of the camera in 3D space.
 * @param objectPos       The position of the object in 3D space.
 * @param orientationY    The orientation angle of the object around the Y-axis.
 * @param minDistance     The minimum distance at which the object is considered within render distance.
 * @param fov             The field of view (FOV) of the camera.
 * @param maxDistance     The maximum render distance.
 * @return                The distance between the camera and the object if it's within render distance,
 *                        or -1.0f if it exceeds the render distance.
 */

f32 is_within_render_distance(Vec3f cameraPos, Vec3f objectPos, u16 orientationY, f32 minDistance, f32 fov, f32 maxDistance) {
    u16 angleObject;
    UNUSED u16 pad;
    u16 temp_v0;
    f32 distanceX;
    f32 distance;
    f32 distanceY;
    s32 plus_fov_angle;
    s32 minus_fov_angle;
    u16 temp;
    UNUSED s32 pad2[3];
    u16 extended_fov = ((u16) fov * 0xB6);

    distanceX = objectPos[0] - cameraPos[0];
    distanceX = distanceX * distanceX;
    if (maxDistance < distanceX) {
        return -1.0f;
    }

    distanceY = objectPos[2] - cameraPos[2];
    distanceY = distanceY * distanceY;
    if (maxDistance < distanceY) {
        return -1.0f;
    }

    distance = distanceX + distanceY;
    if (distance < minDistance) {
        return distance;
    }

    if (distance > maxDistance) {
        return -1.0f;
    }

    angleObject = get_angle_between_points(cameraPos, objectPos);
    minus_fov_angle = (orientationY - extended_fov);
    plus_fov_angle = (orientationY + extended_fov);

    if (minDistance == 0.0f) {
        if (is_visible_between_angle((orientationY + extended_fov), (orientationY - extended_fov), angleObject) == 1) {
            return distance;
        }
        return -1.0f;
    }

    if (is_visible_between_angle((u16) plus_fov_angle, (u16) minus_fov_angle, angleObject) == 1) {
        return distance;
    }
    temp_v0 = func_802B7CA8(minDistance / distance);
    temp = angleObject + temp_v0;

    if (is_visible_between_angle(plus_fov_angle, minus_fov_angle, temp) == 1) {
        return distance;
    }

    temp = angleObject - temp_v0;
    if (is_visible_between_angle(plus_fov_angle, minus_fov_angle, temp) == 1) {
        return distance;
    }
    return -1.0f;
}

// No idea if arg1 is actually a Mat4 or not, but since this function is unused
// its impossible to know with certainty either way, very close of func_802B5D64
UNUSED void func_802B8414(uintptr_t arg0, Mat4 arg1, s16 arg2, s16 arg3, s32 arg4) {
    UNUSED s32 pad[3];
    Vec3f sp40;
    s8 sp3C[3];
    s32 var_v0;
    UNUSED s32 pad2[3];
    Lights1 *var_s0;

    var_s0 = (Lights1 *) VIRTUAL_TO_PHYSICAL2(gSegmentTable[arg0 >> 0x18] + (arg0 & 0xFFFFFF));
    sins(arg3);
    coss(arg3);
    sins(arg2);
    coss(arg2);
    sp40[0] = 0.0f;
    sp40[1] = 0.0f;
    sp40[2] = 1.0f;
    sp3C[0] = ((sp40[0] * arg1[0][0]) + (sp40[1] * arg1[1][0]) + (sp40[2] * arg1[2][0])) * 127.0f;
    sp3C[1] = ((sp40[0] * arg1[0][1]) + (sp40[1] * arg1[1][1]) + (sp40[2] * arg1[2][1])) * 127.0f;
    sp3C[2] = ((sp40[0] * arg1[0][2]) + (sp40[1] * arg1[1][2]) + (sp40[2] * arg1[2][2])) * 127.0f;
    for (var_v0 = 0; var_v0 < arg4; var_v0++, var_s0++) {
        var_s0->l[0].l.dir[0] = sp3C[0];
        var_s0->l[0].l.dir[1] = sp3C[1];
        var_s0->l[0].l.dir[2] = sp3C[2];
    }
}

#ifdef MIPS_TO_C
//generated by m2c commit beb457dabfc7a01ec6540a5404a6a05097a13602 on Oct-29-2023
void func_802B8614(Player *arg0) {
    f64 sp78;
    f64 sp70;
    f64 sp68;
    f64 sp58;
    f64 sp50;
    f64 sp48;
    f64 sp40;
    f64 sp38;
    f64 temp_f12;
    f64 temp_f14;
    f64 temp_f16;
    f64 temp_f18;
    f64 temp_f20;
    f64 temp_f2;
    f64 temp_f30;
    f64 temp_f4;
    f64 temp_f6;

    temp_f6 = (f64) arg0->boundingBoxCorners[1].cornerPos[0];
    sp78 = temp_f6;
    sp70 = (f64) arg0->boundingBoxCorners[1].cornerGroundY;
    sp68 = (f64) arg0->boundingBoxCorners[1].cornerPos[2];
    temp_f30 = (f64) arg0->boundingBoxCorners[0].cornerPos[0];
    sp58 = (f64) arg0->boundingBoxCorners[0].cornerGroundY;
    sp50 = (f64) arg0->boundingBoxCorners[0].cornerPos[2];
    sp48 = (f64) arg0->boundingBoxCorners[3].cornerPos[0];
    sp40 = (f64) arg0->boundingBoxCorners[3].cornerGroundY;
    temp_f4 = (f64) arg0->boundingBoxCorners[3].cornerPos[2];
    temp_f2 = sp58 - sp70;
    sp38 = temp_f4;
    temp_f12 = temp_f4 - sp50;
    temp_f14 = sp50 - sp68;
    temp_f16 = sp40 - sp58;
    temp_f18 = sp48 - temp_f30;
    temp_f20 = temp_f30 - temp_f6;
    if (0.0 == 0.0) {
        arg0->unk_058 = 0.0f;
        arg0->unk_060 = 0.0f;
        arg0->unk_05C = 1.0f;
        return;
    }
    arg0->unk_058 = (f32) ((f64) (f32) ((temp_f2 * temp_f12) - (temp_f14 * temp_f16)) / 0.0);
    arg0->unk_05C = (f32) ((f64) (f32) ((temp_f14 * temp_f18) - (temp_f20 * temp_f12)) / 0.0);
    arg0->unk_060 = (f32) ((f64) (f32) ((temp_f20 * temp_f16) - (temp_f2 * temp_f18)) / 0.0);
}
#else
GLOBAL_ASM("asm/non_matchings/racing/math_util/func_802B8614.s")
#endif
