diff options
Diffstat (limited to 'src/port/interpolation/matrix.c')
| -rw-r--r-- | src/port/interpolation/matrix.c | 450 |
1 files changed, 450 insertions, 0 deletions
diff --git a/src/port/interpolation/matrix.c b/src/port/interpolation/matrix.c new file mode 100644 index 000000000..4f8a7839b --- /dev/null +++ b/src/port/interpolation/matrix.c @@ -0,0 +1,450 @@ +#include <libultraship.h> +#include <math.h> +#include "matrix.h" +#include "common_structs.h" + +Mtx gIdentityMtx = gdSPDefMtx(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f); +Matrix gIdentityMatrix = { { + { 1.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 1.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 1.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f, 1.0f }, +} }; + +Matrix* gGfxMatrix; +Matrix sGfxMatrixStack[0x20]; +Matrix* gCalcMatrix; +Matrix sCalcMatrixStack[0x20]; + +Mtx gMainMatrixStack[0x480]; +Mtx* gGfxMtx; + +void Matrix_InitPerspective(Gfx** dList) { + u16 norm; + float near = 10.0f; + float far = 12800.0f; + float fov = 45.0f; + + guPerspective(gGfxMtx, &norm, fov, 320.0f / 240.0f, near, far, 1.0f); + gSPPerspNormalize((*dList)++, norm); + gSPMatrix((*dList)++, gGfxMtx++, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION); + guLookAt(gGfxMtx, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -12800.0f, 0.0f, 1.0f, 0.0f); + gSPMatrix((*dList)++, gGfxMtx++, G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION); + Matrix_Copy(gGfxMatrix, &gIdentityMatrix); +} + +void Matrix_InitOrtho(Gfx** dList) { + FrameInterpolation_RecordOpenChild("ortho", 0); + FrameInterpolation_RecordMarker(__FILE__, __LINE__); + guOrtho(gGfxMtx, -320.0f / 2, 320.0f / 2, -240.0f / 2, 240.0f / 2, 0.0f, 5.0f, 1.0f); + gSPMatrix((*dList)++, gGfxMtx++, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION); + guLookAt(gGfxMtx, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -12800.0f, 0.0f, 1.0f, 0.0f); + gSPMatrix((*dList)++, gGfxMtx++, G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION); + Matrix_Copy(gGfxMatrix, &gIdentityMatrix); + FrameInterpolation_RecordCloseChild(); +} + + +// Copies src Matrix into dst +void Matrix_Copy(Matrix* dst, Matrix* src) { + int32_t i; + + for (i = 0; i < 4; i++) { + dst->mf[i][0] = src->mf[i][0]; + dst->mf[i][1] = src->mf[i][1]; + dst->mf[i][2] = src->mf[i][2]; + dst->mf[i][3] = src->mf[i][3]; + } +} + +// Makes a copy of the stack's current matrix and puts it on the top of the stack +void Matrix_Push(Matrix** mtxStack) { + Matrix_Copy(*mtxStack + 1, *mtxStack); + (*mtxStack)++; +} + +// Removes the top matrix of the stack +void Matrix_Pop(Matrix** mtxStack) { + (*mtxStack)--; +} + +// Copies tf into mtx (MTXF_NEW) or applies it to mtx (MTXF_APPLY) +void Matrix_Mult(Matrix* mtx, Matrix* tf, u8 mode) { + f32 rx; + f32 ry; + f32 rz; + f32 rw; + s32 i0; + s32 i1; + s32 i2; + s32 i3; + + if (mode == 1) { + rx = mtx->mf[0][0]; + ry = mtx->mf[1][0]; + rz = mtx->mf[2][0]; + rw = mtx->mf[3][0]; + + for (i0 = 0; i0 < 4; i0++) { + mtx->mf[i0][0] = (rx * tf->mf[i0][0]) + (ry * tf->mf[i0][1]) + (rz * tf->mf[i0][2]) + (rw * tf->mf[i0][3]); + } + + rx = mtx->mf[0][1]; + ry = mtx->mf[1][1]; + rz = mtx->mf[2][1]; + rw = mtx->mf[3][1]; + + for (i1 = 0; i1 < 4; i1++) { + mtx->mf[i1][1] = (rx * tf->mf[i1][0]) + (ry * tf->mf[i1][1]) + (rz * tf->mf[i1][2]) + (rw * tf->mf[i1][3]); + } + + rx = mtx->mf[0][2]; + ry = mtx->mf[1][2]; + rz = mtx->mf[2][2]; + rw = mtx->mf[3][2]; + + for (i2 = 0; i2 < 4; i2++) { + mtx->mf[i2][2] = (rx * tf->mf[i2][0]) + (ry * tf->mf[i2][1]) + (rz * tf->mf[i2][2]) + (rw * tf->mf[i2][3]); + } + + rx = mtx->mf[0][3]; + ry = mtx->mf[1][3]; + rz = mtx->mf[2][3]; + rw = mtx->mf[3][3]; + + for (i3 = 0; i3 < 4; i3++) { + mtx->mf[i3][3] = (rx * tf->mf[i3][0]) + (ry * tf->mf[i3][1]) + (rz * tf->mf[i3][2]) + (rw * tf->mf[i3][3]); + } + } else { + Matrix_Copy(mtx, tf); + } +} + +// Creates a translation matrix in mtx (MTXF_NEW) or applies one to mtx (MTXF_APPLY) +void Matrix_Translate(Matrix* mtx, f32 x, f32 y, f32 z, u8 mode) { + f32 rx; + f32 ry; + s32 i; + + if (mode == 1) { + for (i = 0; i < 4; i++) { + rx = mtx->mf[0][i]; + ry = mtx->mf[1][i]; + + mtx->mf[3][i] += (rx * x) + (ry * y) + (mtx->mf[2][i] * z); + } + } else { + mtx->mf[3][0] = x; + mtx->mf[3][1] = y; + mtx->mf[3][2] = z; + mtx->mf[0][1] = mtx->mf[0][2] = mtx->mf[0][3] = mtx->mf[1][0] = mtx->mf[1][2] = mtx->mf[1][3] = mtx->mf[2][0] = + mtx->mf[2][1] = mtx->mf[2][3] = 0.0f; + mtx->mf[0][0] = mtx->mf[1][1] = mtx->mf[2][2] = mtx->mf[3][3] = 1.0f; + } +} + +// Creates a scale matrix in mtx (MTXF_NEW) or applies one to mtx (MTXF_APPLY) +void Matrix_Scale(Matrix* mtx, f32 xScale, f32 yScale, f32 zScale, u8 mode) { + f32 rx; + f32 ry; + s32 i; + + if (mode == 1) { + for (i = 0; i < 4; i++) { + rx = mtx->mf[0][i]; + ry = mtx->mf[1][i]; + + mtx->mf[0][i] = rx * xScale; + mtx->mf[1][i] = ry * yScale; + mtx->mf[2][i] *= zScale; + } + } else { + mtx->mf[0][0] = xScale; + mtx->mf[1][1] = yScale; + mtx->mf[2][2] = zScale; + mtx->mf[0][1] = mtx->mf[0][2] = mtx->mf[0][3] = mtx->mf[1][0] = mtx->mf[1][2] = mtx->mf[1][3] = mtx->mf[2][0] = + mtx->mf[2][1] = mtx->mf[2][3] = mtx->mf[3][0] = mtx->mf[3][1] = mtx->mf[3][2] = 0.0f; + mtx->mf[3][3] = 1.0f; + } +} + +// Creates rotation matrix about the X axis in mtx (MTXF_NEW) or applies one to mtx (MTXF_APPLY) +void Matrix_RotateX(Matrix* mtx, f32 angle, u8 mode) { + f32 cs; + f32 sn; + f32 ry; + f32 rz; + s32 i; + + sn = sinf(angle); + cs = cosf(angle); + if (mode == 1) { + for (i = 0; i < 4; i++) { + ry = mtx->mf[1][i]; + rz = mtx->mf[2][i]; + + mtx->mf[1][i] = (ry * cs) + (rz * sn); + mtx->mf[2][i] = (rz * cs) - (ry * sn); + } + } else { + mtx->mf[1][1] = mtx->mf[2][2] = cs; + mtx->mf[1][2] = sn; + mtx->mf[2][1] = -sn; + mtx->mf[0][0] = mtx->mf[3][3] = 1.0f; + mtx->mf[0][1] = mtx->mf[0][2] = mtx->mf[0][3] = mtx->mf[1][0] = mtx->mf[1][3] = mtx->mf[2][0] = mtx->mf[2][3] = + mtx->mf[3][0] = mtx->mf[3][1] = mtx->mf[3][2] = 0.0f; + } +} + +// Creates rotation matrix about the Y axis in mtx (MTXF_NEW) or applies one to mtx (MTXF_APPLY) +void Matrix_RotateY(Matrix* mtx, f32 angle, u8 mode) { + f32 cs; + f32 sn; + f32 rx; + f32 rz; + s32 i; + + sn = sinf(angle); + cs = cosf(angle); + if (mode == 1) { + for (i = 0; i < 4; i++) { + rx = mtx->mf[0][i]; + rz = mtx->mf[2][i]; + + mtx->mf[0][i] = (rx * cs) - (rz * sn); + mtx->mf[2][i] = (rx * sn) + (rz * cs); + } + } else { + mtx->mf[0][0] = mtx->mf[2][2] = cs; + mtx->mf[0][2] = -sn; + mtx->mf[2][0] = sn; + mtx->mf[1][1] = mtx->mf[3][3] = 1.0f; + mtx->mf[0][1] = mtx->mf[0][3] = mtx->mf[1][0] = mtx->mf[1][2] = mtx->mf[1][3] = mtx->mf[2][1] = mtx->mf[2][3] = + mtx->mf[3][0] = mtx->mf[3][1] = mtx->mf[3][2] = 0.0f; + } +} + +// Creates rotation matrix about the Z axis in mtx (MTXF_NEW) or applies one to mtx (MTXF_APPLY) +void Matrix_RotateZ(Matrix* mtx, f32 angle, u8 mode) { + f32 cs; + f32 sn; + f32 rx; + f32 ry; + s32 i; + + sn = sinf(angle); + cs = cosf(angle); + if (mode == 1) { + for (i = 0; i < 4; i++) { + rx = mtx->mf[0][i]; + ry = mtx->mf[1][i]; + + mtx->mf[0][i] = (rx * cs) + (ry * sn); + mtx->mf[1][i] = (ry * cs) - (rx * sn); + } + } else { + mtx->mf[0][0] = mtx->mf[1][1] = cs; + mtx->mf[0][1] = sn; + mtx->mf[1][0] = -sn; + mtx->mf[2][2] = mtx->mf[3][3] = 1.0f; + mtx->mf[0][2] = mtx->mf[0][3] = mtx->mf[1][2] = mtx->mf[1][3] = mtx->mf[2][0] = mtx->mf[2][1] = mtx->mf[2][3] = + mtx->mf[3][0] = mtx->mf[3][1] = mtx->mf[3][2] = 0.0f; + } +} + +// Creates rotation matrix about a given vector axis in mtx (MTXF_NEW) or applies one to mtx (MTXF_APPLY). +// The vector specifying the axis does not need to be a unit vector. +void Matrix_RotateAxis(Matrix* mtx, f32 angle, f32 axisX, f32 axisY, f32 axisZ, u8 mode) { + f32 rx; + f32 ry; + f32 rz; + f32 norm; + f32 cxx; + f32 cyx; + f32 czx; + f32 cxy; + f32 cyy; + f32 czy; + f32 cxz; + f32 cyz; + f32 czz; + f32 xx; + f32 yy; + f32 zz; + f32 xy; + f32 yz; + f32 xz; + f32 sinA; + f32 cosA; + + norm = sqrtf((axisX * axisX) + (axisY * axisY) + (axisZ * axisZ)); + if (norm != 0.0) { + axisX /= norm; + axisY /= norm; + axisZ /= norm; + sinA = sinf(angle); + cosA = cosf(angle); + xx = axisX * axisX; + yy = axisY * axisY; + zz = axisZ * axisZ; + xy = axisX * axisY; + yz = axisY * axisZ; + xz = axisX * axisZ; + + if (mode == 1) { + cxx = (1.0f - xx) * cosA + xx; + cyx = (1.0f - cosA) * xy + axisZ * sinA; + czx = (1.0f - cosA) * xz - axisY * sinA; + + cxy = (1.0f - cosA) * xy - axisZ * sinA; + cyy = (1.0f - yy) * cosA + yy; + czy = (1.0f - cosA) * yz + axisX * sinA; + + cxz = (1.0f - cosA) * xz + axisY * sinA; + cyz = (1.0f - cosA) * yz - axisX * sinA; + czz = (1.0f - zz) * cosA + zz; + + // loop doesn't seem to work here. + rx = mtx->mf[0][0]; + ry = mtx->mf[0][1]; + rz = mtx->mf[0][2]; + mtx->mf[0][0] = (rx * cxx) + (ry * cxy) + (rz * cxz); + mtx->mf[0][1] = (rx * cyx) + (ry * cyy) + (rz * cyz); + mtx->mf[0][2] = (rx * czx) + (ry * czy) + (rz * czz); + + rx = mtx->mf[1][0]; + ry = mtx->mf[1][1]; + rz = mtx->mf[1][2]; + mtx->mf[1][0] = (rx * cxx) + (ry * cxy) + (rz * cxz); + mtx->mf[1][1] = (rx * cyx) + (ry * cyy) + (rz * cyz); + mtx->mf[1][2] = (rx * czx) + (ry * czy) + (rz * czz); + + rx = mtx->mf[2][0]; + ry = mtx->mf[2][1]; + rz = mtx->mf[2][2]; + mtx->mf[2][0] = (rx * cxx) + (ry * cxy) + (rz * cxz); + mtx->mf[2][1] = (rx * cyx) + (ry * cyy) + (rz * cyz); + mtx->mf[2][2] = (rx * czx) + (ry * czy) + (rz * czz); + } else { + mtx->mf[0][0] = (1.0f - xx) * cosA + xx; + mtx->mf[0][1] = (1.0f - cosA) * xy + axisZ * sinA; + mtx->mf[0][2] = (1.0f - cosA) * xz - axisY * sinA; + mtx->mf[0][3] = 0.0f; + + mtx->mf[1][0] = (1.0f - cosA) * xy - axisZ * sinA; + mtx->mf[1][1] = (1.0f - yy) * cosA + yy; + mtx->mf[1][2] = (1.0f - cosA) * yz + axisX * sinA; + mtx->mf[1][3] = 0.0f; + + mtx->mf[2][0] = (1.0f - cosA) * xz + axisY * sinA; + mtx->mf[2][1] = (1.0f - cosA) * yz - axisX * sinA; + mtx->mf[2][2] = (1.0f - zz) * cosA + zz; + mtx->mf[2][3] = 0.0f; + + mtx->mf[3][0] = mtx->mf[3][1] = mtx->mf[3][2] = 0.0f; + mtx->mf[3][3] = 1.0f; + } + } +} + +// Converts the current Gfx matrix to a Mtx +void Matrix_ToMtx(Mtx* dest) { + // LTODO: We need to validate this + guMtxF2L(gGfxMatrix->mf, dest); +} + +// Converts the Mtx src to a Matrix, putting the result in dest +void Matrix_FromMtx(Mtx* src, Matrix* dest) { + guMtxF2L(src->m, dest->mf); +} + +// Applies the transform matrix mtx to the vector src, putting the result in dest +void Matrix_MultVec3f(Matrix* mtx, Vec3f* src, Vec3f* dest) { + *dest[0] = (mtx->mf[0][0] * *src[0]) + (mtx->mf[1][0] * *src[1]) + (mtx->mf[2][0] * *src[2]) + mtx->mf[3][0]; + *dest[1] = (mtx->mf[0][1] * *src[0]) + (mtx->mf[1][1] * *src[1]) + (mtx->mf[2][1] * *src[2]) + mtx->mf[3][1]; + *dest[2] = (mtx->mf[0][2] * *src[0]) + (mtx->mf[1][2] * *src[1]) + (mtx->mf[2][2] * *src[2]) + mtx->mf[3][2]; +} + +// Applies the linear part of the transformation matrix mtx to the vector src, ignoring any translation that mtx might +// have. Puts the result in dest. +void Matrix_MultVec3fNoTranslate(Matrix* mtx, Vec3f* src, Vec3f* dest) { + *dest[0] = (mtx->mf[0][0] * *src[0]) + (mtx->mf[1][0] * *src[1]) + (mtx->mf[2][0] * *src[2]); + *dest[1] = (mtx->mf[0][1] * *src[0]) + (mtx->mf[1][1] * *src[1]) + (mtx->mf[2][1] * *src[2]); + *dest[2] = (mtx->mf[0][2] * *src[0]) + (mtx->mf[1][2] * *src[1]) + (mtx->mf[2][2] * *src[2]); +} + +// Expresses the rotational part of the transform mtx as Tait-Bryan angles, in the yaw-pitch-roll (intrinsic YXZ) +// convention used in worldspace calculations +void Matrix_GetYRPAngles(Matrix* mtx, Vec3f* rot) { + Matrix invYP; + Vec3f origin = { 0.0f, 0.0f, 0.0f }; + Vec3f originP; + Vec3f zHat = { 0.0f, 0.0f, 1.0f }; + Vec3f zHatP; + Vec3f xHat = { 1.0f, 0.0f, 0.0f }; + Vec3f xHatP; + + Matrix_MultVec3fNoTranslate(mtx, &origin, &originP); + Matrix_MultVec3fNoTranslate(mtx, &zHat, &zHatP); + Matrix_MultVec3fNoTranslate(mtx, &xHat, &xHatP); + zHatP[0] -= originP[0]; + zHatP[1] -= originP[1]; + zHatP[2] -= originP[2]; + xHatP[0] -= originP[0]; + xHatP[1] -= originP[1]; + xHatP[2] -= originP[2]; + *rot[1] = atan2f(zHatP[0], zHatP[2]); + *rot[0] = -atan2f(zHatP[1], sqrtf(SQ(zHatP[0]) + SQ(zHatP[2]))); + Matrix_RotateX(&invYP, -*rot[0], MTXF_NEW); + Matrix_RotateY(&invYP, -*rot[1], MTXF_APPLY); + Matrix_MultVec3fNoTranslate(&invYP, &xHatP, &xHat); + *rot[0] *= M_RTOD; + *rot[1] *= M_RTOD; + *rot[2] = atan2f(xHat[1], xHat[0]) * M_RTOD; +} + +// Expresses the rotational part of the transform mtx as Tait-Bryan angles, in the extrinsic XYZ convention used in +// modelspace calculations +void Matrix_GetXYZAngles(Matrix* mtx, Vec3f* rot) { + Matrix invYZ; + Vec3f origin = { 0.0f, 0.0f, 0.0f }; + Vec3f originP; + Vec3f xHat = { 1.0f, 0.0f, 0.0f }; + Vec3f xHatP; + Vec3f yHat = { 0.0f, 1.0f, 0.0f }; + Vec3f yHatP; + + Matrix_MultVec3fNoTranslate(mtx, &origin, &originP); + Matrix_MultVec3fNoTranslate(mtx, &xHat, &xHatP); + Matrix_MultVec3fNoTranslate(mtx, &yHat, &yHatP); + xHatP[0] -= originP[0]; + xHatP[1] -= originP[1]; + xHatP[2] -= originP[2]; + yHatP[0] -= originP[0]; + yHatP[1] -= originP[1]; + yHatP[2] -= originP[2]; + *rot[2] = atan2f(xHatP[1], xHatP[0]); + *rot[1] = -atan2f(xHatP[2], sqrtf(SQ(xHatP[0]) + SQ(xHatP[1]))); + Matrix_RotateY(&invYZ, -*rot[1], MTXF_NEW); + Matrix_RotateZ(&invYZ, -*rot[2], MTXF_APPLY); + Matrix_MultVec3fNoTranslate(&invYZ, &yHatP, &yHat); + *rot[0] = atan2f(yHat[2], yHat[1]) * M_RTOD; + *rot[1] *= M_RTOD; + *rot[2] *= M_RTOD; +} + +// Creates a look-at matrix from Eye, At, and Up in mtx (MTXF_NEW) or applies one to mtx (MTXF_APPLY). +// A look-at matrix is a rotation-translation matrix that maps y to Up, z to (At - Eye), and translates to Eye +void Matrix_LookAt(Matrix* mtx, f32 xEye, f32 yEye, f32 zEye, f32 xAt, f32 yAt, f32 zAt, f32 xUp, f32 yUp, f32 zUp, + u8 mode) { + Matrix lookAt; + + guLookAtF(lookAt.mf, xEye, yEye, zEye, xAt, yAt, zAt, xUp, yUp, zUp); + Matrix_Mult(mtx, &lookAt, mode); +} + +// Converts the current Gfx matrix to a Mtx and sets it to the display list +void Matrix_SetGfxMtx(Gfx** gfx) { + Matrix_ToMtx(gGfxMtx); + gSPMatrix((*gfx)++, gGfxMtx++, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); +}
\ No newline at end of file |
