mk64/src/animation.c

180 lines
5.7 KiB
C

#include <ultra64.h>
#include <macros.h>
#include <mk64.h>
#include "math_util.h"
#include "animation.h"
#include "memory.h"
#include <main.h>
#include <PR/gbi.h>
#include "code_80057C60.h"
Vec3s sOriginalPosAnimation;
s16 isNotTheFirst;
s16 sMatrixShouldNotPop;
s16 sMatrixStackSize;
void convert_to_fixed_point_matrix_animation(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
}
void mtxf_translate_rotate2(Mat4 dest, Vec3f pos, Vec3s angle) {
register f32 sx = sins(angle[0]);
register f32 cx = coss(angle[0]);
register f32 sy = sins(angle[1]);
register f32 cy = coss(angle[1]);
register f32 sz = sins(angle[2]);
register f32 cz = coss(angle[2]);
dest[0][0] = cy * cz;
dest[0][1] = cy * sz;
dest[0][2] = -sy;
dest[0][3] = 0.0f;
dest[1][0] = sx * sy * cz - cx * sz;
dest[1][1] = sx * sy * sz + cx * cz;
dest[1][2] = sx * cy;
dest[1][3] = 0.0f;
dest[2][0] = cx * sy * cz + sx * sz;
dest[2][1] = cx * sy * sz - sx * cz;
dest[2][2] = cx * cy;
dest[2][3] = 0.0f;
dest[3][0] = pos[0];
dest[3][1] = pos[1];
dest[3][2] = pos[2];
dest[3][3] = 1.0f;
}
void render_limb_or_add_mtx(Armature* arg0, s16* arg1, AnimationLimbVector arg2, s32 timeCycle) {
Vec3f pos;
Vec3s angle;
Mat4 modelMatrix;
s32 i;
s32 some_offset;
Gfx* model;
Gfx* virtualModel;
virtualModel = arg0->model;
if (isNotTheFirst == 0) {
for (i = 0; i < 3; i++) {
pos[i] = sOriginalPosAnimation[i] + arg0->pos[i];
}
isNotTheFirst += 1;
} else {
for (i = 0; i < 3; i++) {
pos[i] = arg0->pos[i];
}
}
for (i = 0; i < 3; i++) {
if (timeCycle < arg2[i].animation_length) {
some_offset = timeCycle;
} else {
some_offset = 0;
}
angle[i] = arg1[arg2[i].indexCycle + some_offset];
}
mtxf_translate_rotate2(modelMatrix, pos, angle);
convert_to_fixed_point_matrix_animation(&gGfxPool->mtxHud[gMatrixHudCount], modelMatrix);
sMatrixStackSize += 1;
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL2(&gGfxPool->mtxHud[gMatrixHudCount++]),
G_MTX_PUSH | G_MTX_MUL | G_MTX_MODELVIEW);
if (virtualModel != NULL) {
model = segmented_to_virtual(virtualModel);
gSPDisplayList(gDisplayListHead++, model);
}
}
void render_armature(Armature* animation, Animation* arg1, s16 timeCycle) {
UNUSED u32* temp;
s16* angle_array;
s32 some_offset;
AnimationLimbVector* animation_cycle_list;
s32 animation_type;
s32 someIndex;
angle_array = segmented_to_virtual(arg1->angle_array);
animation_cycle_list = segmented_to_virtual(arg1->animation_cycle_spec_vector);
sMatrixStackSize = 0;
isNotTheFirst = 0;
for (someIndex = 0; someIndex < 3; someIndex++) {
if (timeCycle < (*animation_cycle_list)[someIndex].animation_length) {
some_offset = timeCycle;
} else {
some_offset = 0;
}
sOriginalPosAnimation[someIndex] = angle_array[(*animation_cycle_list)[someIndex].indexCycle + some_offset];
}
animation_cycle_list++;
sMatrixShouldNotPop = 0;
do {
animation_type = animation->type;
switch (animation_type) { /* irregular */
case STOP_ANIMATION:
break;
case DISABLE_AUTOMATIC_POP_MATRIX:
sMatrixShouldNotPop = 1;
break;
case POP_MATRIX:
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
sMatrixStackSize -= 1;
break;
case RENDER_MODEL_OR_ADD_POS:
if (sMatrixShouldNotPop == 0) {
gSPPopMatrix(gDisplayListHead++, G_MTX_MODELVIEW);
sMatrixStackSize -= 1;
}
render_limb_or_add_mtx(animation, angle_array, *animation_cycle_list, (s32) timeCycle);
sMatrixShouldNotPop = 0;
animation_cycle_list++;
break;
}
animation = (Armature*) ((u32*) animation + animation->size);
} while (animation_type != STOP_ANIMATION);
}
s16 render_animated_model(Armature* virtualArmature, Animation** virtualListAnimation, s16 animationIndex,
s16 timeCycle) {
Armature* armature;
Animation* animation;
Animation** listAnimation;
armature = segmented_to_virtual(virtualArmature);
listAnimation = segmented_to_virtual(virtualListAnimation); // Convert the array's address
animation = segmented_to_virtual(listAnimation[animationIndex]); // Convert an array element's address
if (timeCycle >= animation->animation_length) {
timeCycle = 0;
}
render_armature(armature, animation, timeCycle);
timeCycle++;
if (timeCycle >= animation->animation_length) {
timeCycle = 0;
}
return timeCycle;
}
s16 get_animation_length(Animation** addr, s16 offset) {
Animation** item = segmented_to_virtual(addr);
Animation* temp = (Animation*) segmented_to_virtual((void*) item[offset]);
return temp->animation_length - 1;
}