summaryrefslogtreecommitdiff
path: root/src/animation.c
blob: 85b003d6484414bdf34a6a539d1b4baed27d117f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
#include <libultraship.h>
#include <macros.h>
#include <mk64.h>
#include "racing/math_util.h"
#include "animation.h"
#include "memory.h"
#include <main.h>
#include <libultra/gbi.h>
#include "code_80057C60.h"
#include "engine/Matrix.h"
#include "port/interpolation/FrameInterpolation.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;
    s32 i;
    s16* a3 = (s16*) dest;      // all integer parts stored in first 16 bytes
    s16* t0 = (s16*) dest + 16; // all fraction parts stored in last 16 bytes
    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) {

    FrameInterpolation_RecordMatrixPosRotXYZ(&dest, pos, angle);

    f32 sx = sins(angle[0]);
    f32 cx = coss(angle[0]);

    f32 sy = sins(angle[1]);
    f32 cy = coss(angle[1]);

    f32 sz = sins(angle[2]);
    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];
    }
    FrameInterpolation_RecordOpenChild("animation", TAG_OBJECT(arg0));
    mtxf_translate_rotate2(modelMatrix, pos, angle);
    //convert_to_fixed_point_matrix_animation(&gGfxPool->mtxHud[gMatrixHudCount], modelMatrix);
    sMatrixStackSize += 1;
    // gSPMatrix(gDisplayListHead++, (&gGfxPool->mtxHud[gMatrixHudCount++]),
    //           G_MTX_PUSH | G_MTX_MUL | G_MTX_MODELVIEW);

    AddHudMatrix(modelMatrix, G_MTX_PUSH | G_MTX_MUL | G_MTX_MODELVIEW);
    if (virtualModel != NULL) {
        model = (virtualModel);
        gSPDisplayList(gDisplayListHead++, model);
    }
    FrameInterpolation_RecordCloseChild();
}

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 = (arg1->angle_array);
    animation_cycle_list = (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*) ((uintptr_t*) 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 = (virtualArmature);
    listAnimation = (virtualListAnimation);      // Convert the array's address
    animation = (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 = (addr);
    Animation* temp = (Animation*) ((void*) item[offset]);
    return temp->animation_length - 1;
}