From 4dee19e2c8da139269571c473df6e521e139e031 Mon Sep 17 00:00:00 2001 From: mrshigure Date: Sun, 14 Jan 2024 18:09:01 -0800 Subject: [PATCH] Matched hsfex --- configure.py | 2 +- include/game/hsfex.h | 15 ++ include/unsplit.h | 2 +- src/game/hsfex.c | 581 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 598 insertions(+), 2 deletions(-) create mode 100644 include/game/hsfex.h create mode 100644 src/game/hsfex.c diff --git a/configure.py b/configure.py index eda83503..f8532bf9 100644 --- a/configure.py +++ b/configure.py @@ -329,7 +329,7 @@ config.libs = [ Object(Matching, "game/hsfman.c"), Object(NonMatching, "game/hsfmotion.c"), Object(Matching, "game/hsfanim.c"), - Object(NonMatching, "game/hsfex.c"), + Object(Matching, "game/hsfex.c"), Object(Matching, "game/perf.c"), Object(Matching, "game/objmain.c"), Object(NonMatching, "game/fault.c"), diff --git a/include/game/hsfex.h b/include/game/hsfex.h new file mode 100644 index 00000000..a84695c1 --- /dev/null +++ b/include/game/hsfex.h @@ -0,0 +1,15 @@ +#ifndef _GAME_HSFEX_H +#define _GAME_HSFEX_H + +#include "dolphin.h" + +void CamMotionEx2(s16 arg0, s16 arg1, float arg2, s16 arg3); +void CamMotionEx(s16 arg0, s16 arg1, Vec *arg2, Vec *arg3, Vec *arg4, float arg5, s16 arg6); +float InterpolateBMLine(float *arg0, float *arg1, float arg2); +void Hu3D2Dto3D(Vec *arg0, s16 arg1, Vec *arg2); +void Hu3D3Dto2D(Vec *arg0, s16 arg1, Vec *arg2); +void Hu3DMtxTransGet(Mtx arg0, Vec *arg1); +void Hu3DMtxRotGet(Mtx arg0, Vec *arg1); +void Hu3DMtxScaleGet(Mtx arg0, Vec *arg1); + +#endif diff --git a/include/unsplit.h b/include/unsplit.h index 06e6374f..79446cc8 100644 --- a/include/unsplit.h +++ b/include/unsplit.h @@ -3,7 +3,7 @@ #include "dolphin.h" -void Hu3D2Dto3D(Vec*, s32, Vec*); +void Hu3D2Dto3D(Vec*, s16, Vec*); void HuAudFadeOut(s32 arg0); void Hu3DModelPosSet(s16 index, float x, float y, float z); diff --git a/src/game/hsfex.c b/src/game/hsfex.c new file mode 100644 index 00000000..4b1a37c7 --- /dev/null +++ b/src/game/hsfex.c @@ -0,0 +1,581 @@ +#include "game/hsfex.h" +#include "game/hsfman.h" + +#include "math.h" + +typedef struct { + /* 0x00 */ float unk00; + /* 0x04 */ float unk04; + /* 0x08 */ Vec unk08; + /* 0x14 */ Vec unk14; + /* 0x20 */ Vec unk20; +} HsfexStruct02; // Size 0x2C + +static void SetObjCamMotion(s16 arg0, HsfTrack *arg1, float arg2, HsfexStruct02 *arg3); + +float GetCurve(void*, float); + +void CamMotionEx2(s16 arg0, s16 arg1, float arg2, s16 arg3) { + CameraData *temp_r30; + s16 i; + + for (i = 0; i < 16; i++) { + if (arg1 & (1 << i)) { + break; + } + } + temp_r30 = &Hu3DCamera[i]; + CamMotionEx(arg0, arg1, &temp_r30->pos, &temp_r30->up, &temp_r30->target, arg2, arg3); +} + +void CamMotionEx(s16 arg0, s16 arg1, Vec *arg2, Vec *arg3, Vec *arg4, float arg5, s16 arg6) { + Vec sp3C; + float sp2C[4]; + float sp1C[4]; + float temp_f29; + float var_f27; + float var_f26; + float var_f30; + float var_f31; + s16 sp1A; + s16 var_r25; + s16 var_r29; + s16 var_r30; + HsfexStruct02 *var_r31; + CameraData *temp_r27; + ModelData *temp_r23; + HsfData *temp_r22; + MotionData *temp_r19; + HsfData *temp_r18; + HsfObject *temp_r24; + HsfTrack *temp_r20; + HsfMotion *temp_r26; + HsfexStruct02 *temp_r21; + HsfTrack *var_r28; + + temp_r23 = &Hu3DData[arg0]; + temp_r19 = &Hu3DMotion[temp_r23->unk_08]; + temp_r22 = temp_r23->hsfData; + temp_r18 = temp_r19->unk_04; + temp_r26 = temp_r18->motion; + for (var_r25 = 0; var_r25 < 16; var_r25++) { + if (arg1 & (1 << var_r25)) { + break; + } + } + temp_r27 = &Hu3DCamera[var_r25]; + temp_f29 = temp_r26->len; + sp1A = 0.5f + (temp_f29 / 6.0f) + 1.0f; + var_r31 = temp_r21 = HuMemDirectMallocNum(HEAP_SYSTEM, (sp1A + 1) * sizeof(HsfexStruct02), MEMORY_DEFAULT_NUM); + var_r31->unk00 = 0.0f; + var_r31->unk08 = *arg2; + var_r31->unk20 = *arg4; + var_r31->unk14 = *arg3; + var_r31++; + for (var_r29 = 1, var_f31 = 0.0f; var_f31 <= temp_f29; var_r31++, var_r29++) { + var_r31->unk00 = var_f31; + var_r28 = temp_r26->track; + temp_r20 = &var_r28[temp_r26->numTracks]; + while (var_r28 < temp_r20) { + if (var_r28->type == 2) { + temp_r24 = &temp_r22->object[var_r28->target]; + if (temp_r24->type == 7) { + SetObjCamMotion(arg0, var_r28, GetCurve(var_r28, var_f31), var_r31); + } + } + var_r28++; + } + var_f31 += 6.0f; + } + if (var_f31 != temp_f29) { + var_r31->unk00 = temp_f29; + var_r28 = temp_r26->track; + temp_r20 = &var_r28[temp_r26->numTracks]; + while (var_r28 < temp_r20) { + if (var_r28->type == 2) { + temp_r24 = &temp_r22->object[var_r28->target]; + if (temp_r24->type == 7) { + SetObjCamMotion(arg0, var_r28, GetCurve(var_r28, temp_f29), var_r31); + } + } + var_r28++; + } + var_r29++; + } + var_r31 = temp_r21; + var_r31->unk04 = 0.0f; + var_f26 = 0.0f; + for (var_f31 = var_f26; var_f31 < var_r29 - 1; var_f31 += 1.0f, var_r31++) { + PSVECSubtract(&var_r31[1].unk08, &var_r31[0].unk08, &sp3C); + var_r31[1].unk04 = PSVECMag(&sp3C); + var_f26 += var_r31[1].unk04; + } + var_r31 = temp_r21; + var_f27 = 0.0f; + var_f31 = var_f27; + while (var_f31 < var_r29) { + var_f27 += var_r31->unk04; + var_r31->unk00 = arg5 * (var_f27 / var_f26); + var_f31 += 1.0f; + var_r31++; + } + var_f31 = 0.0f; + while (var_f31 <= arg5) { + switch (arg6) { + case 0: + var_f30 = var_f31; + break; + case 1: + var_f30 = arg5 * sin(90.0f * (var_f31 / arg5) * M_PI / 180.0); + break; + case 2: + var_f30 = arg5 * (1.0 - cos(90.0f * (var_f31 / arg5) * M_PI / 180.0)); + break; + } + var_r31 = temp_r21; + for (var_r30 = 0; var_r30 < var_r29; var_r30++, var_r31++) { + if (var_r31->unk00 <= var_f30 && var_r31[1].unk00 > var_f30) { + break; + } + } + if (var_r30 != var_r29) { + if (var_r30 == 0) { + sp1C[0] = -1.0f; + } else { + sp1C[0] = var_r31[-1].unk00; + } + sp1C[1] = var_r31->unk00; + if (var_r30 >= var_r29 - 1) { + sp1C[2] = 1.0f + var_r31->unk00; + } + sp1C[2] = var_r31[1].unk00; + if (var_r30 >= var_r29 - 2) { + sp1C[3] = 1.0f + sp1C[2]; + } else { + sp1C[3] = var_r31[2].unk00; + } + if (var_r30 == 0) { + sp2C[0] = var_r31[0].unk08.x; + } else { + sp2C[0] = var_r31[-1].unk08.x; + } + sp2C[1] = var_r31[0].unk08.x; + if (var_r30 >= var_r29 - 1) { + sp2C[2] = sp2C[1]; + } else { + sp2C[2] = var_r31[1].unk08.x; + } + if (var_r30 >= var_r29 - 2) { + sp2C[3] = sp2C[2]; + } else { + sp2C[3] = var_r31[2].unk08.x; + } + temp_r27->pos.x = InterpolateBMLine(sp2C, sp1C, var_f30); + if (var_r30 == 0) { + sp2C[0] = var_r31[0].unk08.y; + } else { + sp2C[0] = var_r31[-1].unk08.y; + } + sp2C[1] = var_r31[0].unk08.y; + if (var_r30 >= var_r29 - 1) { + sp2C[2] = sp2C[1]; + } else { + sp2C[2] = var_r31[1].unk08.y; + } + if (var_r30 >= var_r29 - 2) { + sp2C[3] = sp2C[2]; + } else { + sp2C[3] = var_r31[2].unk08.y; + } + temp_r27->pos.y = InterpolateBMLine(sp2C, sp1C, var_f30); + if (var_r30 == 0) { + sp2C[0] = var_r31[0].unk08.z; + } else { + sp2C[0] = var_r31[-1].unk08.z; + } + sp2C[1] = var_r31[0].unk08.z; + if (var_r30 >= var_r29 - 1) { + sp2C[2] = sp2C[1]; + } else { + sp2C[2] = var_r31[1].unk08.z; + } + if (var_r30 >= var_r29 - 2) { + sp2C[3] = sp2C[2]; + } else { + sp2C[3] = var_r31[2].unk08.z; + } + temp_r27->pos.z = InterpolateBMLine(sp2C, sp1C, var_f30); + if (var_r30 == 0) { + sp2C[0] = var_r31[0].unk20.x; + } else { + sp2C[0] = var_r31[-1].unk20.x; + } + sp2C[1] = var_r31[0].unk20.x; + if (var_r30 >= var_r29 - 1) { + sp2C[2] = sp2C[1]; + } else { + sp2C[2] = var_r31[1].unk20.x; + } + if (var_r30 >= var_r29 - 2) { + sp2C[3] = sp2C[2]; + } else { + sp2C[3] = var_r31[2].unk20.x; + } + temp_r27->target.x = InterpolateBMLine(sp2C, sp1C, var_f30); + if (var_r30 == 0) { + sp2C[0] = var_r31->unk20.y; + } else { + sp2C[0] = var_r31[-1].unk20.y; + } + sp2C[1] = var_r31->unk20.y; + if (var_r30 >= var_r29 - 1) { + sp2C[2] = sp2C[1]; + } else { + sp2C[2] = var_r31[1].unk20.y; + } + if (var_r30 >= var_r29 - 2) { + sp2C[3] = sp2C[2]; + } else { + sp2C[3] = var_r31[2].unk20.y; + } + temp_r27->target.y = InterpolateBMLine(sp2C, sp1C, var_f30); + if (var_r30 == 0) { + sp2C[0] = var_r31->unk20.z; + } else { + sp2C[0] = var_r31[-1].unk20.z; + } + sp2C[1] = var_r31->unk20.z; + if (var_r30 >= var_r29 - 1) { + sp2C[2] = sp2C[1]; + } else { + sp2C[2] = var_r31[1].unk20.z; + } + if (var_r30 >= var_r29 - 2) { + sp2C[3] = sp2C[2]; + } else { + sp2C[3] = var_r31[2].unk20.z; + } + temp_r27->target.z = InterpolateBMLine(sp2C, sp1C, var_f30); + if (var_r30 == 0) { + sp2C[0] = var_r31->unk14.x; + } else { + sp2C[0] = var_r31[-1].unk14.x; + } + sp2C[1] = var_r31->unk14.x; + if (var_r30 >= var_r29 - 1) { + sp2C[2] = sp2C[1]; + } else { + sp2C[2] = var_r31[1].unk14.x; + } + if (var_r30 >= var_r29 - 2) { + sp2C[3] = sp2C[2]; + } else { + sp2C[3] = var_r31[2].unk14.x; + } + temp_r27->up.x = InterpolateBMLine(sp2C, sp1C, var_f30); + if (var_r30 == 0) { + sp2C[0] = var_r31->unk14.y; + } else { + sp2C[0] = var_r31[-1].unk14.y; + } + sp2C[1] = var_r31->unk14.y; + if (var_r30 >= var_r29 - 1) { + sp2C[2] = sp2C[1]; + } else { + sp2C[2] = var_r31[1].unk14.y; + } + if (var_r30 >= var_r29 - 2) { + sp2C[3] = sp2C[2]; + } else { + sp2C[3] = var_r31[2].unk14.y; + } + temp_r27->up.y = InterpolateBMLine(sp2C, sp1C, var_f30); + if (var_r30 == 0) { + sp2C[0] = var_r31->unk14.z; + } else { + sp2C[0] = var_r31[-1].unk14.z; + } + sp2C[1] = var_r31->unk14.z; + if (var_r30 >= var_r29 - 1) { + sp2C[2] = sp2C[1]; + } else { + sp2C[2] = var_r31[1].unk14.z; + } + if (var_r30 >= var_r29 - 2) { + sp2C[3] = sp2C[2]; + } else { + sp2C[3] = var_r31[2].unk14.z; + } + temp_r27->up.z = InterpolateBMLine(sp2C, sp1C, var_f30); + HuPrcVSleep(); + var_f31 += 1.0f; + } else { + break; + } + } + HuMemDirectFree(temp_r21); +} + +static void SetObjCamMotion(s16 arg0, HsfTrack *arg1, float arg2, HsfexStruct02 *arg3) { + ModelData *temp_r31 = &Hu3DData[arg0]; + Vec sp18; + Vec spC; + + switch (arg1->channel) { + case 8: + arg3->unk08.x = temp_r31->scale.x * (arg2 + temp_r31->pos.x); + break; + case 9: + arg3->unk08.y = temp_r31->scale.y * (arg2 + temp_r31->pos.y); + break; + case 10: + arg3->unk08.z = temp_r31->scale.z * (arg2 + temp_r31->pos.z); + break; + case 11: + arg3->unk20.x = temp_r31->scale.x * (arg2 + temp_r31->pos.x); + break; + case 12: + arg3->unk20.y = temp_r31->scale.y * (arg2 + temp_r31->pos.y); + break; + case 13: + arg3->unk20.z = temp_r31->scale.z * (arg2 + temp_r31->pos.z); + break; + case 14: + PSVECSubtract(&arg3->unk08, &arg3->unk20, &spC); + PSVECNormalize(&spC, &spC); + sp18.x = spC.x * spC.y * (1.0 - cos(M_PI * arg2 / 180.0)) - spC.z * sin(M_PI * arg2 / 180.0); + sp18.y = spC.y * spC.y + (1.0f - spC.y * spC.y) * cos(M_PI * arg2 / 180.0); + sp18.z = spC.y * spC.z * (1.0 - cos(M_PI * arg2 / 180.0)) + spC.x * sin(M_PI * arg2 / 180.0); + PSVECNormalize(&sp18, &arg3->unk14); + break; + } +} + +float InterpolateBMLine(float *arg0, float *arg1, float arg2) { + float sp8[2]; + float temp_f22; + float var_f21; + float temp_f20; + float temp_f29; + float temp_f31; + float var_f28; + float var_f27; + float var_f26; + float var_f25; + float var_f24; + float var_f23; + float var_f30; + s32 var_r30; + s32 var_r29; + s32 i; + + if (arg0[0] == arg0[1] && arg0[0] == arg0[2] && arg0[0] == arg0[3]) { + return arg0[0]; + } + for (i = 1; i <= 2; i++) { + sp8[i - 1] = 0.5f * ((arg0[i] - arg0[i - 1]) / (arg1[i] - arg1[i - 1]) + (arg0[i + 1] - arg0[i]) / (arg1[i + 1] - arg1[i])); + } + temp_f29 = 0.5f * (arg1[2] + arg1[1]); + var_r30 = 0; + if (sp8[1] - sp8[0] != 0.0f) { + temp_f22 = (sp8[1] * arg1[2] - sp8[0] * arg1[1] - (arg0[2] - arg0[1])) / (sp8[1] - sp8[0]); + var_r29 = 0; + if (arg1[1] <= temp_f22 && temp_f22 <= arg1[2]) { + var_r29 = 1; + } + var_r30 = (var_r29 != 0) ? 1 : 0; + } + if (var_r30 == 1) { + temp_f31 = temp_f29 - arg1[1]; + temp_f20 = (arg0[2] - arg0[1]) / (arg1[2] - arg1[1]) - (sp8[1] - sp8[0]) / 2; + var_f28 = temp_f20 * temp_f31 + ((sp8[1] - sp8[0]) / (2.0f * (arg1[2] - arg1[1]))) * temp_f31 * temp_f31 + arg0[1]; + var_f27 = temp_f20 + temp_f31 * ((sp8[1] - sp8[0]) / (arg1[2] - arg1[1])); + } else { + temp_f31 = temp_f29 - arg1[1]; + var_f28 = (arg0[2] + arg0[1]) * (temp_f31 / (arg1[2] - arg1[1])); + var_f27 = 2.0f * (arg0[2] - arg0[1]) / (arg1[2] - arg1[1]) - (sp8[1] + sp8[0]) * (temp_f31 / (arg1[2] - arg1[1])); + } + if (arg2 < temp_f29) { + var_f30 = arg1[1]; + var_f26 = arg0[1]; + var_f25 = sp8[0]; + var_f24 = temp_f29; + var_f21 = var_f28; + var_f23 = var_f27; + } else { + var_f30 = temp_f29; + var_f26 = var_f28; + var_f25 = var_f27; + var_f24 = arg1[2]; + var_f21 = arg0[2]; + var_f23 = sp8[1]; + } + return ((var_f23 - var_f25) / (2.0f * (var_f24 - var_f30))) * (arg2 - var_f30) * (arg2 - var_f30) + (arg2 - var_f30) * ((var_f21 - var_f26) / (var_f24 - var_f30) - (var_f23 - var_f25) / 2) + var_f26; +} + +void Hu3D2Dto3D(Vec *arg0, s16 arg1, Vec *arg2) { + CameraData *temp_r31; + float temp_f31; + float temp_f30; + float temp_f29; + float temp_f28; + float temp_f27; + s16 i; + Mtx spC; + + for (i = 0; i < 16; i++) { + if (arg1 & (1 << i)) { + break; + } + } + temp_r31 = &Hu3DCamera[i]; + temp_f30 = sin((temp_r31->fov / 2) * M_PI / 180.0) / cos((temp_r31->fov / 2) * M_PI / 180.0); + temp_f31 = temp_f30 * arg0->z * 2.0f; + temp_f29 = temp_f31 * 1.2f; + temp_f28 = arg0->x / 576.0f; + temp_f27 = arg0->y / 480.0f; + arg2->x = (temp_f28 - 0.5) * temp_f29; + arg2->y = -(temp_f27 - 0.5) * temp_f31; + arg2->z = -arg0->z; + C_MTXLookAt(spC, &temp_r31->pos, &temp_r31->up, &temp_r31->target); + PSMTXInverse(spC, spC); + PSMTXMultVec(spC, arg2, arg2); +} + +void Hu3D3Dto2D(Vec *arg0, s16 arg1, Vec *arg2) { + Vec sp10; + CameraData *temp_r31; + float temp_f31; + float temp_f30; + s16 i; + Mtx sp1C; + + for (i = 0; i < 16; i++) { + if (arg1 & (1 << i)) { + break; + } + } + temp_r31 = &Hu3DCamera[i]; + C_MTXLookAt(sp1C, &temp_r31->pos, &temp_r31->up, &temp_r31->target); + PSMTXMultVec(sp1C, arg0, &sp10); + temp_f31 = (sin((temp_r31->fov / 2) * M_PI / 180.0) / cos((temp_r31->fov / 2) * M_PI / 180.0)) * sp10.z * 1.2000000476837158; + temp_f30 = (sin((temp_r31->fov / 2) * M_PI / 180.0) / cos((temp_r31->fov / 2) * M_PI / 180.0)) * sp10.z; + arg2->x = 288.0f + sp10.x * (288.0f / -temp_f31); + arg2->y = 240.0f + sp10.y * (240.0f / temp_f30); + arg2->z = 0.0f; +} + +void Hu3DMtxTransGet(Mtx arg0, Vec *arg1) { + arg1->x = arg0[0][3]; + arg1->y = arg0[1][3]; + arg1->z = arg0[2][3]; +} + +static inline float Hu3DMtxRotGetInlineFunc01(float arg0, float arg1) { + return atan2(arg0, arg1); +} + +static inline float Hu3DMtxRotGetInlineFunc02(float arg0) { + return asin(arg0); +} + +static inline float Hu3DMtxRotGetInlineFunc03(float arg0, float arg1) { + if (arg1 == 0.0f) { + if (arg0 >= 0.0f) { + return M_PI / 2; + } else { + return -(M_PI / 2); + } + } else { + return Hu3DMtxRotGetInlineFunc01(arg0, arg1); + } +} + +void Hu3DMtxRotGet(Mtx arg0, Vec *arg1) { + float sp48; + float sp44; + float sp3C; + float sp34; + float temp_f28; + float temp_f27; + float temp_f26; + float var_f25; + float temp_f24; + + temp_f28 = arg0[0][0] * arg0[0][0] + arg0[1][0] * arg0[1][0] + arg0[2][0] * arg0[2][0]; + sp44 = sqrtf(temp_f28); + if (!(sp44 < 0.00000001f)) { + temp_f27 = arg0[0][1] * arg0[0][1] + arg0[1][1] * arg0[1][1] + arg0[2][1] * arg0[2][1]; + sp3C = sqrtf(temp_f27); + if (!(sp3C < 0.00000001f)) { + temp_f26 = arg0[0][2] * arg0[0][2] + arg0[1][2] * arg0[1][2] + arg0[2][2] * arg0[2][2]; + sp34 = sqrtf(temp_f26); + if (!(sp34 < 0.00000001f)) { + temp_f24 = -arg0[2][0] / sp44; + if (temp_f24 >= 1.0f) { + var_f25 = M_PI / 2; + } else if (temp_f24 <= -1.0f) { + var_f25 = -(M_PI / 2); + } else { + var_f25 = Hu3DMtxRotGetInlineFunc02(temp_f24); + } + arg1->y = var_f25; + sp48 = cos(arg1->y); + if (sp48 >= 0.00000001f) { + arg1->x = Hu3DMtxRotGetInlineFunc03(arg0[2][1] / sp3C, arg0[2][2] / sp34); + arg1->z = Hu3DMtxRotGetInlineFunc03(arg0[1][0], arg0[0][0]); + } else { + arg1->x = Hu3DMtxRotGetInlineFunc03(arg0[0][1], arg0[1][1]); + arg1->z = 0.0f; + } + arg1->x = arg1->x * 57.29578f; + arg1->y = arg1->y * 57.29578f; + arg1->z = arg1->z * 57.29578f; + return; + } + } + } + arg1->x = 0.0f; + arg1->y = 0.0f; + arg1->z = 0.0f; +} + +void Hu3DMtxScaleGet(Mtx arg0, Vec *arg1) { + Vec sp38; + Vec sp2C; + Vec sp20; + Vec sp14; + Vec sp8; + + sp2C.x = arg0[0][0]; + sp2C.y = arg0[1][0]; + sp2C.z = arg0[2][0]; + arg1->x = PSVECMag(&sp2C); + PSVECNormalize(&sp2C, &sp2C); + sp20.x = arg0[0][1]; + sp20.y = arg0[1][1]; + sp20.z = arg0[2][1]; + sp38.x = PSVECDotProduct(&sp2C, &sp20); + PSVECScale(&sp2C, &sp8, sp38.x); + PSVECSubtract(&sp20, &sp8, &sp20); + arg1->y = PSVECMag(&sp20); + PSVECNormalize(&sp20, &sp20); + sp38.x /= arg1->y; + sp14.x = arg0[0][2]; + sp14.y = arg0[1][2]; + sp14.z = arg0[2][2]; + sp38.z = PSVECDotProduct(&sp20, &sp14); + PSVECScale(&sp20, &sp8, sp38.z); + PSVECSubtract(&sp14, &sp8, &sp14); + sp38.y = PSVECDotProduct(&sp2C, &sp14); + PSVECScale(&sp2C, &sp8, sp38.y); + PSVECSubtract(&sp14, &sp8, &sp14); + arg1->z = PSVECMag(&sp14); + PSVECNormalize(&sp14, &sp14); + PSVECCrossProduct(&sp20, &sp14, &sp8); + if (PSVECDotProduct(&sp2C, &sp8) < 0.0) { + arg1->x *= -1.0; + arg1->y *= -1.0; + arg1->z *= -1.0; + } +}