diff --git a/include/c_keyframe.h b/include/c_keyframe.h index 8ea09b2e..9cfcda24 100644 --- a/include/c_keyframe.h +++ b/include/c_keyframe.h @@ -10,73 +10,89 @@ extern "C" { #endif -enum { - cKF_STATE_NONE, - cKF_STATE_STOPPED, - cKF_STATE_CONTINUE, +#define cKF_JOINT_FLAG_DISP_OPA (0 << 0) // Joint rendered in OPA display list +#define cKF_JOINT_FLAG_DISP_XLU (1 << 0) // When set, joint is rendered in XLU display list - cKF_STATE_NUM +/* Flags for animation components to apply to each joint */ +#define cKF_ANIMITION_BIT_NONE (0 << 0) // No translation or rotation +#define cKF_ANIMATION_BIT_TRANS_X (1 << 5) +#define cKF_ANIMATION_BIT_TRANS_Y (1 << 4) +#define cKF_ANIMATION_BIT_TRANS_Z (1 << 3) +#define cKF_ANIMATION_BIT_ROT_X (1 << 2) +#define cKF_ANIMATION_BIT_ROT_Y (1 << 1) +#define cKF_ANIMATION_BIT_ROT_Z (1 << 0) + +#define cKF_ANIMATION_TRANS_XZ (1 << 0) // Translation on XZ +#define cKF_ANIMATION_TRANS_Y (1 << 1) // Translation on Y +#define cKF_ANIMATION_ROT_X (1 << 2) // Rotation on the X axis + +enum { + cKF_STATE_NONE, + cKF_STATE_STOPPED, + cKF_STATE_CONTINUE, + + cKF_STATE_NUM }; typedef struct joint_s { - Gfx* model; - u8 child; - u8 flags; - s_xyz translation; + Gfx* model; + u8 child; + u8 flags; + s_xyz translation; } cKF_Joint_R_c; typedef struct skeleton_s { - u8 num_joints; - u8 num_shown_joints; - cKF_Joint_R_c* joint_table; + u8 num_joints; + u8 num_shown_joints; + cKF_Joint_R_c* joint_table; } cKF_Skeleton_R_c; typedef struct animation_s { - u8* flag_table; - s16* data_table; - s16* key_table; - s16* fixed_table; - s16 pad; - s16 frames; + u8* flag_table; + s16* data_table; + s16* key_table; + s16* fixed_table; + s16 pad; + s16 frames; } cKF_Animation_R_c; enum { - cKF_FRAMECONTROL_STOP, - cKF_FRAMECONTROL_REPEAT, + cKF_FRAMECONTROL_STOP, + cKF_FRAMECONTROL_REPEAT, - cKF_FRAMECONTROL_NUM + cKF_FRAMECONTROL_NUM }; typedef struct frame_control_s { - f32 start_frame; - f32 end_frame; - f32 max_frames; - f32 speed; - f32 current_frame; - int mode; + f32 start_frame; + f32 end_frame; + f32 max_frames; + f32 speed; + f32 current_frame; + int mode; } cKF_FrameControl_c; typedef struct skeleton_info_s { - cKF_FrameControl_c frame_control; - cKF_Skeleton_R_c* skeleton; - cKF_Animation_R_c* animation; + cKF_FrameControl_c frame_control; + cKF_Skeleton_R_c* skeleton; + cKF_Animation_R_c* animation; - f32 morph_counter; - s_xyz* current_joint; - s_xyz* target_joint; - s_xyz* rotation_diff_table; + f32 morph_counter; + s_xyz* current_joint; + s_xyz* target_joint; + s_xyz* rotation_diff_table; - int animation_enabled; - xyz_t base_world_position; - s16 base_angle_y; + int animation_enabled; + xyz_t base_world_position; + s16 base_angle_y; - xyz_t base_model_translation; - s_xyz base_model_rotation; - s_xyz updated_base_model_rotation; + xyz_t base_model_translation; + s_xyz base_model_rotation; + s_xyz updated_base_model_rotation; - f32 fixed_counter; - xyz_t model_world_position_correction; - s16 model_angle_correction; + f32 fixed_counter; + xyz_t model_world_position_correction; + s16 model_angle_correction; } cKF_SkeletonInfo_R_c; typedef struct combine_work_set_s { @@ -88,59 +104,379 @@ typedef struct combine_work_set_s { int anm_key_num_idx; int anm_const_val_tbl_idx; int anm_data_src_idx; -}cKF_SkeletonInfo_R_combine_work_c; +} cKF_SkeletonInfo_R_combine_work_c; typedef struct tex_anim_s { - s16 frame; - s16 timer; + s16 frame; + s16 timer; } cKF_TextureAnimation_c; typedef int (*cKF_draw_callback)(GAME*, cKF_SkeletonInfo_R_c*, int, Gfx**, u8*, void*, s_xyz*, xyz_t*); - #define cKF_FRAMERATE 30.0f #define cKF_FRAMETIME (1.0f / cKF_FRAMERATE) #define cKF_EPSILON 0.008f +/** + * Determines if the current frame has passed a specified frame, considering direction. + * + * @param fc Pointer to the frame control structure. + * @param current The frame to check against the current frame. + * @return Returns 1 if the current frame is past the specified frame, 0 otherwise. + */ extern int cKF_FrameControl_passCheck_now(cKF_FrameControl_c* fc, f32 current); -extern f32 cKF_HermitCalc(f32 t, f32 tension, f32 p0, f32 p1, f32 m0, f32 m1); +/** + * Stops animation at its end frame. + * + * Adjusts the current frame to the end frame if it's determined to surpass the end or start frame, + * effectively stopping the animation. + * + * @param fc Pointer to the frame control structure. + * @return cKF_STATE_STOPPED if animation stops; cKF_STATE_NONE otherwise. + */ +extern int cKF_FrameControl_stop_proc(cKF_FrameControl_c* fc); + +/** + * Computes a point on a Hermite curve for given time and tension. + * + * @param time Normalized time (0 to 1) along the curve. + * @param tension Controls curve tightness around control points. + * @param startPos Position of the start point. + * @param endPos Position of the end point. + * @param startTangent Tangent at the start point. + * @param endTangent Tangent at the end point. + * @return Position of the point on the curve. + */ +extern f32 cKF_HermitCalc(f32 time, f32 tension, f32 startPos, f32 endPos, f32 startTangent, f32 endTangent); + +/** + * Interpolates rotation values for skeletal animation blending. + * + * Determines the shortest rotation path and interpolates based on a given fraction (t), + * considering both signed and unsigned differences to handle wraparound cases. + * + * @param t Interpolation factor between 0 and 1. + * @param out Pointer to store interpolated rotation result. + * @param rot1 Start rotation value. + * @param rot2 End rotation value. + */ extern void cKF_SkeletonInfo_subRotInterpolation(f32 t, s16* out, s16 rot1, s16 rot2); -extern void cKF_SkeletonInfo_R_ct(cKF_SkeletonInfo_R_c* keyframe, cKF_Skeleton_R_c* skeleton, cKF_Animation_R_c* animation, s_xyz* work_table, s_xyz* target_table); +/** + * Initializes a skeleton info structure with skeleton and animation data. + * + * Sets up the skeleton info structure for use, linking it with its skeleton structure, + * animation data, and joint work and target tables. + * + * @param keyframe Pointer to the skeleton info structure. + * @param skeleton Pointer to the associated skeleton structure. + * @param animation Pointer to the animation data to use. + * @param work_table Pointer to the work table for current joint positions. + * @param target_table Pointer to the target table for target joint positions. + */ +extern void cKF_SkeletonInfo_R_ct(cKF_SkeletonInfo_R_c* keyframe, cKF_Skeleton_R_c* skeleton, + cKF_Animation_R_c* animation, s_xyz* work_table, s_xyz* target_table); + +/** + * Destructor for a skeleton info structure. Currently a stub with no operation. + * + * @param keyframe Pointer to the skeleton info structure to destruct. + */ extern void cKF_SkeletonInfo_R_dt(cKF_SkeletonInfo_R_c* keyframe); -extern void cKF_SkeletonInfo_R_init_standard_stop(cKF_SkeletonInfo_R_c* keyframe, cKF_Animation_R_c* animation, s_xyz* rotation_diff_table); -extern void cKF_SkeletonInfo_R_init_standard_stop_morph(cKF_SkeletonInfo_R_c* keyframe, cKF_Animation_R_c* animation, s_xyz* rotation_diff_table, f32 morph); -extern void cKF_SkeletonInfo_R_init_standard_repeat(cKF_SkeletonInfo_R_c* keyframe, cKF_Animation_R_c* animation, s_xyz* rotation_diff_table); -extern void cKF_SkeletonInfo_R_init_standard_repeat_morph(cKF_SkeletonInfo_R_c* keyframe, cKF_Animation_R_c* animation, s_xyz* rotation_diff_table, f32 morph); +/** + * Initializes a skeleton info structure for standard stop animation. + * + * Sets up the animation to stop at the last frame. + * + * @param keyframe Pointer to the skeleton info structure. + * @param animation Pointer to the animation data. + * @param rotation_diff_table Pointer to the rotation difference table. + */ +extern void cKF_SkeletonInfo_R_init_standard_stop(cKF_SkeletonInfo_R_c* keyframe, cKF_Animation_R_c* animation, + s_xyz* rotation_diff_table); -extern void cKF_SkeletonInfo_R_init(cKF_SkeletonInfo_R_c* keyframe, cKF_Skeleton_R_c* skeleton, cKF_Animation_R_c* animation, f32 start_frame, f32 end_frame, -f32 current_frame, f32 frame_speed, f32 morph_counter,int mode,s_xyz* rotation_diff_table); +/** + * Initializes a skeleton info structure for standard stop animation with morphing. + * + * Similar to standard stop but includes a morph counter to blend animations. + * + * @param keyframe Pointer to the skeleton info structure. + * @param animation Pointer to the animation data. + * @param rotation_diff_table Pointer to the rotation difference table. + * @param morph Morph counter for animation blending. + */ +extern void cKF_SkeletonInfo_R_init_standard_stop_morph(cKF_SkeletonInfo_R_c* keyframe, cKF_Animation_R_c* animation, + s_xyz* rotation_diff_table, f32 morph); +/** + * Initializes a skeleton info structure for standard repeat animation. + * + * Sets up the animation to repeat from start to end frame. + * + * @param keyframe Pointer to the skeleton info structure. + * @param animation Pointer to the animation data. + * @param rotation_diff_table Pointer to the rotation difference table. + */ +extern void cKF_SkeletonInfo_R_init_standard_repeat(cKF_SkeletonInfo_R_c* keyframe, cKF_Animation_R_c* animation, + s_xyz* rotation_diff_table); + +/** + * Initializes a skeleton info structure for standard repeat animation with morphing. + * + * Similar to standard repeat but includes a morph counter for blending animations. + * + * @param keyframe Pointer to the skeleton info structure. + * @param animation Pointer to the animation data. + * @param rotation_diff_table Pointer to the rotation difference table. + * @param morph Morph counter for animation blending. + */ +extern void cKF_SkeletonInfo_R_init_standard_repeat_morph(cKF_SkeletonInfo_R_c* keyframe, cKF_Animation_R_c* animation, + s_xyz* rotation_diff_table, f32 morph); + +/** + * Generic initializer for a skeleton info structure with detailed animation control. + * + * Allows for custom start, end, current frame, and frame speed settings, including + * the animation mode and morph counter. + * + * @param keyframe Pointer to the skeleton info structure. + * @param skeleton Pointer to the skeleton structure. + * @param animation Pointer to the animation data. + * @param start_frame Animation start frame. + * @param end_frame Animation end frame. + * @param current_frame Current frame of animation. + * @param frame_speed Speed of frame progression. + * @param morph_counter Counter for morphing between animations. + * @param mode Animation mode (stop or repeat). + * @param rotation_diff_table Pointer to the rotation difference table. + */ +extern void cKF_SkeletonInfo_R_init(cKF_SkeletonInfo_R_c* keyframe, cKF_Skeleton_R_c* skeleton, + cKF_Animation_R_c* animation, f32 start_frame, f32 end_frame, f32 current_frame, + f32 frame_speed, f32 morph_counter, int mode, s_xyz* rotation_diff_table); + +/** + * Plays the animation for a given skeleton info structure, applying keyframe data and morphing. + * + * Advances the animation based on the current frame, applying keyframe data for each joint. + * Handles morphing between the current and target joint positions if a morph counter is set. + * Updates joint positions based on animation flags, fixed values, and calculated keyframe values. + * Also applies rotation differences and updates the frame control state based on the animation mode. + * + * @param keyframe Pointer to the skeleton info structure containing animation and joint data. + * @return The state of the animation after processing (e.g., stopped, none, continued). + */ extern int cKF_SkeletonInfo_R_play(cKF_SkeletonInfo_R_c* keyframe); -extern void cKF_Si3_draw_SV_R_child(GAME* game, cKF_SkeletonInfo_R_c* keyframe, int* joint_num, cKF_draw_callback prerender_callback, cKF_draw_callback postrender_callback, void* arg, Mtx** mtxpp); -extern void cKF_Si3_draw_R_SV(GAME* game, cKF_SkeletonInfo_R_c* keyframe, Mtx* mtxp, cKF_draw_callback prerender_callback, cKF_draw_callback postrender_callback, void* arg); +/** + * Recursively draws child joints of a skeleton, applying transformations and rendering callbacks. + * + * @param game Pointer to the game structure. + * @param keyframe Pointer to the skeleton info structure for joint data and animation state. + * @param joint_num Pointer to the current joint index being processed. + * @param prerender_callback Callback function executed before rendering each joint. + * @param postrender_callback Callback function executed after rendering each joint. + * @param arg Additional arguments passed to the callbacks. + * @param mtxpp Pointer to the transformation matrix for the current joint. + */ +extern void cKF_Si3_draw_SV_R_child(GAME* game, cKF_SkeletonInfo_R_c* keyframe, int* joint_num, + cKF_draw_callback prerender_callback, cKF_draw_callback postrender_callback, + void* arg, Mtx** mtxpp); -extern void cKF_SkeletonInfo_R_init_standard_repeat_speedsetandmorph(cKF_SkeletonInfo_R_c* keyframe, cKF_Animation_R_c* animation, s_xyz* rotation_diff_table, f32 frame_speed, f32 morph_counter); -extern void cKF_SkeletonInfo_R_init_standard_repeat_setframeandspeedandmorph(cKF_SkeletonInfo_R_c* keyframe, cKF_Animation_R_c* animation, s_xyz* rotation_diff_table, f32 frame, f32 frame_speed, f32 morph_counter); -extern void cKF_SkeletonInfo_R_init_standard_setframeandspeedandmorphandmode(cKF_SkeletonInfo_R_c* keyframe, cKF_Animation_R_c* animation, s_xyz* rotation_diff_table, f32 frame, f32 frame_speed, f32 morph_counter, int mode); -extern void cKF_SkeletonInfo_R_init_reverse_setspeedandmorphandmode(cKF_SkeletonInfo_R_c* keyframe, cKF_Animation_R_c* animation, s_xyz* rotation_diff_table, f32 frame_speed, f32 morph_counter, int mode); +/** + * Renders a skeleton before and after applying transformations, using callbacks for custom rendering logic. + * + * @param game Pointer to the game structure. + * @param keyframe Pointer to the skeleton info structure. + * @param mtxp Pointer to the transformation matrix. + * @param prerender_callback Function called before rendering the skeleton. + * @param postrender_callback Function called after rendering the skeleton. + * @param arg Additional arguments passed to the callbacks. + */ +extern void cKF_Si3_draw_R_SV(GAME* game, cKF_SkeletonInfo_R_c* keyframe, Mtx* mtxp, + cKF_draw_callback prerender_callback, cKF_draw_callback postrender_callback, void* arg); -extern void cKF_SkeletonInfo_R_combine_work_set(cKF_SkeletonInfo_R_combine_work_c* combine, cKF_SkeletonInfo_R_c* keyframe); -extern void cKF_SkeletonInfo_R_combine_translation(s16** joint, int* flag, cKF_SkeletonInfo_R_combine_work_c* combine , s8* cwork_num); -extern void cKF_SkeletonInfo_R_combine_rotation(s16** joint, int* flag, cKF_SkeletonInfo_R_combine_work_c* combine , s8* cwork_num); +/** + * Initializes a skeleton info structure for repeating animation with specified speed and morph counter. + * + * @param keyframe Pointer to the skeleton info structure. + * @param animation Pointer to the animation data. + * @param rotation_diff_table Pointer to the rotation difference table. + * @param frame_speed Animation playback speed. + * @param morph_counter Counter for morphing between animations. + */ +extern void cKF_SkeletonInfo_R_init_standard_repeat_speedsetandmorph(cKF_SkeletonInfo_R_c* keyframe, + cKF_Animation_R_c* animation, + s_xyz* rotation_diff_table, f32 frame_speed, + f32 morph_counter); -extern int cKF_SkeletonInfo_R_combine_play(cKF_SkeletonInfo_R_c* info1, cKF_SkeletonInfo_R_c* info2,s8* flag); +/** + * Initializes a skeleton info structure for repeating animation, setting frame, speed, and morph counter. + * + * @param keyframe Pointer to the skeleton info structure. + * @param animation Pointer to the animation data. + * @param rotation_diff_table Pointer to the rotation difference table. + * @param frame Starting frame for animation. + * @param frame_speed Animation playback speed. + * @param morph_counter Counter for morphing between animations. + */ +extern void cKF_SkeletonInfo_R_init_standard_repeat_setframeandspeedandmorph(cKF_SkeletonInfo_R_c* keyframe, + cKF_Animation_R_c* animation, + s_xyz* rotation_diff_table, f32 frame, + f32 frame_speed, f32 morph_counter); -extern void cKF_SkeletonInfo_R_T_combine_play(int* arg1, int* arg2, int* arg3,cKF_SkeletonInfo_R_c* info1, cKF_SkeletonInfo_R_c* info2, cKF_SkeletonInfo_R_c* info3,s8* flag); -extern void cKF_SkeletonInfo_R_Animation_Set_base_shape_trs(f32 transx, f32 transy, f32 transz, cKF_SkeletonInfo_R_c* keyframe, s16 anglex, s16 angley, s16 anglez); -extern void cKF_SkeletonInfo_R_AnimationMove_ct_base(f32 counter, xyz_t* basepos, xyz_t* correctpos, s16 ybase, s16 yidle, cKF_SkeletonInfo_R_c* keyframe, int animation_flag); +/** + * Initializes a skeleton info structure with custom settings including frame, speed, morph counter, and mode. + * + * @param keyframe Pointer to the skeleton info structure. + * @param animation Pointer to the animation data. + * @param rotation_diff_table Pointer to the rotation difference table. + * @param frame Starting frame for animation. + * @param frame_speed Animation playback speed. + * @param morph_counter Counter for morphing between animations. + * @param mode Animation mode (e.g., repeat, stop). + */ +extern void cKF_SkeletonInfo_R_init_standard_setframeandspeedandmorphandmode(cKF_SkeletonInfo_R_c* keyframe, + cKF_Animation_R_c* animation, + s_xyz* rotation_diff_table, f32 frame, + f32 frame_speed, f32 morph_counter, + int mode); + +/** + * Initializes a skeleton info structure for reverse playback with specified speed, morph counter, and mode. + * + * @param keyframe Pointer to the skeleton info structure. + * @param animation Pointer to the animation data. + * @param rotation_diff_table Pointer to the rotation difference table. + * @param frame_speed Animation playback speed in reverse. + * @param morph_counter Counter for morphing between animations. + * @param mode Animation mode (e.g., repeat, stop). + */ +extern void cKF_SkeletonInfo_R_init_reverse_setspeedandmorphandmode(cKF_SkeletonInfo_R_c* keyframe, + cKF_Animation_R_c* animation, + s_xyz* rotation_diff_table, f32 frame_speed, + f32 morph_counter, int mode); + +/** + * Prepares combine work set structure for joint animation combination. + * + * @param combine Pointer to the combine work set structure. + * @param keyframe Pointer to the skeleton info structure. + */ +extern void cKF_SkeletonInfo_R_combine_work_set(cKF_SkeletonInfo_R_combine_work_c* combine, + cKF_SkeletonInfo_R_c* keyframe); + +/** + * Combines translation data for joints based on animation flags, supporting up to three animation layers. + * + * @param joint Pointer to the joint data. + * @param flag Pointer to the current joint flag. + * @param combine Pointer to the combine work set structure. + * @param cwork_num Pointer to the current work layer number. + */ +extern void cKF_SkeletonInfo_R_combine_translation(s16** joint, int* flag, cKF_SkeletonInfo_R_combine_work_c* combine, + s8* cwork_num); + +/** + * Combines rotation data from multiple animation layers for a joint, modifying it based on animation flags. + * + * @param joint Pointer to the current joint's rotation data. + * @param flag Pointer to the animation flag affecting the current joint. + * @param combine Pointer to the combine work set structure containing animation layer data. + * @param cwork_num Pointer to the layer number being processed. + */ +extern void cKF_SkeletonInfo_R_combine_rotation(s16** joint, int* flag, cKF_SkeletonInfo_R_combine_work_c* combine, + s8* cwork_num); + +/** + * Combines and plays two sets of animation data, applying translations and rotations from both. + * + * @param info1 First skeleton info structure to combine. + * @param info2 Second skeleton info structure to combine. + * @param flag Pointer to a flag determining the combination behavior. + * @return Status of the combination and play operation. + */ +extern int cKF_SkeletonInfo_R_combine_play(cKF_SkeletonInfo_R_c* info1, cKF_SkeletonInfo_R_c* info2, s8* flag); + +/** + * Combines and plays three sets of animation data, applying translations and rotations, and updates playback state. + * + * @param arg1 Result of playing first animation. + * @param arg2 Result of playing second animation. + * @param arg3 Result of playing third animation. + * @param info1 First skeleton info structure to combine. + * @param info2 Second skeleton info structure to combine. + * @param info3 Third skeleton info structure to combine. + * @param flag Pointer to a flag determining the combination behavior. + */ +extern void cKF_SkeletonInfo_R_T_combine_play(int* arg1, int* arg2, int* arg3, cKF_SkeletonInfo_R_c* info1, + cKF_SkeletonInfo_R_c* info2, cKF_SkeletonInfo_R_c* info3, s8* flag); + +/** + * Sets base shape translation and rotation for a skeleton info structure. + * + * @param transx X translation of the base model. + * @param transy Y translation of the base model. + * @param transz Z translation of the base model. + * @param keyframe Skeleton info structure to modify. + * @param anglex X angle for base model rotation. + * @param angley Y angle for base model rotation. + * @param anglez Z angle for base model rotation. + */ +extern void cKF_SkeletonInfo_R_Animation_Set_base_shape_trs(f32 transx, f32 transy, f32 transz, + cKF_SkeletonInfo_R_c* keyframe, s16 anglex, s16 angley, + s16 anglez); + +/** + * Adjusts the base position and correction for a skeleton info structure based on animation flags. + * + * @param counter Animation counter to determine the phase of movement. + * @param basepos Original base position of the model. + * @param correctpos Corrected base position of the model. + * @param ybase Base Y angle for rotation. + * @param yidle Idle Y angle for rotation. + * @param keyframe Skeleton info structure to modify. + * @param an_flag Animation flags to determine which corrections to apply. + */ +extern void cKF_SkeletonInfo_R_AnimationMove_ct_base(f32 counter, xyz_t* basepos, xyz_t* correctpos, s16 ybase, + s16 yidle, cKF_SkeletonInfo_R_c* keyframe, int animation_flag); + +/** + * Resets animation movement and flags for a skeleton info structure. + * + * @param keyframe The skeleton info structure to reset. + */ extern void cKF_SkeletonInfo_R_AnimationMove_dt(cKF_SkeletonInfo_R_c* keyframe); -extern void cKF_SkeletonInfo_R_AnimationMove_base(xyz_t* base, s_xyz* sbase, xyz_t* move, s16 yidle, cKF_SkeletonInfo_R_c* keyframe); -extern void cKF_SkeletonInfo_R_AnimationMove_CulcTransToWorld(f32 calcx, f32 calcy, f32 calcz, xyz_t* base, xyz_t* calcp, s16 val, xyz_t* trans, cKF_SkeletonInfo_R_c* keyframe, int animation_flag); +/** + * Applies base movement and adjustment based on animation counter and flags. + * + * @param base Base position to modify. + * @param sbase Base rotation to modify. + * @param move Movement amount to apply. + * @param yidle Y-axis idle angle. + * @param keyframe Skeleton info structure containing animation data. + */ +extern void cKF_SkeletonInfo_R_AnimationMove_base(xyz_t* base, s_xyz* sbase, xyz_t* move, s16 yidle, + cKF_SkeletonInfo_R_c* keyframe); + +/** + * Calculates and applies transformation to world coordinates based on animation data. + * + * @param calcx X-coordinate for calculation base. + * @param calcy Y-coordinate for calculation base. + * @param calcz Z-coordinate for calculation base. + * @param base Base position result. + * @param calcp Position calculation parameters. + * @param val Angle value for rotation. + * @param trans Transformation to apply. + * @param keyframe Skeleton info structure containing animation data. + * @param animation_flag Flags determining which transformations to apply. + */ +extern void cKF_SkeletonInfo_R_AnimationMove_CulcTransToWorld(f32 calcx, f32 calcy, f32 calcz, xyz_t* base, + xyz_t* calcp, s16 val, xyz_t* trans, + cKF_SkeletonInfo_R_c* keyframe, int animation_flag); #ifdef __cplusplus } diff --git a/include/m_lib.h b/include/m_lib.h index dbc772be..97cf85b9 100644 --- a/include/m_lib.h +++ b/include/m_lib.h @@ -23,6 +23,9 @@ extern "C" { #define SQ(x) ((x)*(x)) #define CLAMP_MAX(x, min) ((min) < (x) ? (min) : (x)) +/* Percent of 360 deg */ +#define MOD_F(a, m) (a - (int)((a) * (1.0f / (m))) * (m)) + /* radians -> short angle */ #define RAD2SHORT_ANGLE(rad) ((s16)(int)((rad) * (65536.0f / (2.0f * F_PI)))) #define RAD2SHORTANGLE(rad) ((s16)((32768.0f / F_PI) * ((f32)(rad)))) diff --git a/src/c_keyframe.c b/src/c_keyframe.c index 689da84f..b467b89a 100644 --- a/src/c_keyframe.c +++ b/src/c_keyframe.c @@ -6,1153 +6,1228 @@ #include "sys_math3d.h" #include "sys_matrix.h" +/** + * Resets and initializes a frame control structure with default parameters. + * Sets all numerical properties to 1.0f and mode to cKF_FRAMECONTROL_STOP. + * + * @param frame_control Pointer to the frame control structure. + */ static void cKF_FrameControl_zeroClera(cKF_FrameControl_c* frame_control) { - bzero(frame_control, sizeof(cKF_FrameControl_c)); - frame_control->max_frames = 1.0f; - frame_control->current_frame = 1.0f; - frame_control->speed = 1.0f; - frame_control->end_frame = 1.0f; - frame_control->start_frame = 1.0f; - frame_control->mode = cKF_FRAMECONTROL_STOP; + bzero(frame_control, sizeof(cKF_FrameControl_c)); + frame_control->max_frames = 1.0f; + frame_control->current_frame = 1.0f; + frame_control->speed = 1.0f; + frame_control->end_frame = 1.0f; + frame_control->start_frame = 1.0f; + frame_control->mode = cKF_FRAMECONTROL_STOP; } +/** + * Initializes a frame control structure. + * Wrapper for cKF_FrameControl_zeroClera to provide a clear constructor interface. + * + * @param frame_control Pointer to the frame control structure to initialize. + */ static void cKF_FrameControl_ct(cKF_FrameControl_c* frame_control) { - cKF_FrameControl_zeroClera(frame_control); + cKF_FrameControl_zeroClera(frame_control); } -static void cKF_FrameControl_setFrame(cKF_FrameControl_c* frame_control, - f32 start_frame, f32 end_frame, - f32 max_frames, f32 current_frame, - f32 speed, int mode) { - frame_control->start_frame = start_frame; +/** + * Sets the frame control parameters for an animation sequence. + * + * @param frame_control Pointer to the frame control structure. + * @param start_frame Starting frame of the animation sequence. + * @param end_frame Ending frame of the animation sequence; if less than 1.0f, max_frames is used. + * @param max_frames Maximum number of frames in the animation sequence. + * @param current_frame The current frame number in the animation sequence. + * @param speed The speed at which the animation should play. + * @param mode The mode of the animation (e.g., stop, repeat). + */ +static void cKF_FrameControl_setFrame(cKF_FrameControl_c* frame_control, f32 start_frame, f32 end_frame, f32 max_frames, + f32 current_frame, f32 speed, int mode) { + frame_control->start_frame = start_frame; - if (end_frame < 1.0f) { - frame_control->end_frame = max_frames; - } else { - frame_control->end_frame = end_frame; - } + if (end_frame < 1.0f) { + frame_control->end_frame = max_frames; + } else { + frame_control->end_frame = end_frame; + } - frame_control->max_frames = max_frames; - frame_control->speed = speed; - frame_control->current_frame = current_frame; - frame_control->mode = mode; + frame_control->max_frames = max_frames; + frame_control->speed = speed; + frame_control->current_frame = current_frame; + frame_control->mode = mode; } -static int cKF_FrameControl_passCheck(cKF_FrameControl_c* fc, f32 current, - f32* out) { - f32 cur; - f32 speed; +/** + * Checks if the current frame is within a certain range and calculates the overshoot. + * + * @param fc Pointer to the frame control structure. + * @param current The target frame to compare against the current frame. + * @param out Pointer to a float where the overshoot amount will be stored. + * @return Returns 1 if within the range and adjustments were made, 0 otherwise. + */ +static int cKF_FrameControl_passCheck(cKF_FrameControl_c* fc, f32 current, f32* out) { + f32 cur; + f32 speed; - *out = 0.0f; - cur = fc->current_frame; - if (cur == current) { + *out = 0.0f; + cur = fc->current_frame; + if (cur == current) { + return 0; + } + + speed = (fc->start_frame < fc->end_frame) ? fc->speed : -fc->speed; + + // Check if current frame within target range considering speed + if ((speed >= 0.0f && cur < current && cur + speed >= current) || + (speed < 0.0f && cur > current && cur + speed <= current)) { + *out = cur + speed - current; // Calculate overshoot + return 1; + } return 0; - } - - speed = (fc->start_frame < fc->end_frame) ? fc->speed : -fc->speed; - - if ((speed >= 0.0f && cur < current && cur + speed >= current) || - (speed < 0.0f && cur > current && cur + speed <= current)) { - *out = cur + speed - current; - return 1; - } - return 0; } extern int cKF_FrameControl_passCheck_now(cKF_FrameControl_c* fc, f32 current) { - f32 cur = fc->current_frame; - f32 speed; - int ret = 0; - if (cur != current) { - speed = (fc->start_frame < fc->end_frame) ? fc->speed : -fc->speed; - if ((speed >= 0.0f && cur >= current && cur - speed < current) || - (speed < 0.0f && cur <= current && cur - speed > current)) { - ret = 1; + f32 cur = fc->current_frame; + f32 speed; + int ret = 0; + + if (cur != current) { + speed = (fc->start_frame < fc->end_frame) ? fc->speed : -fc->speed; + if ((speed >= 0.0f && cur >= current && cur - speed < current) || + (speed < 0.0f && cur <= current && cur - speed > current)) { + ret = 1; + } + } else { + ret = 1; } - } else { - ret = 1; - } - return ret; + return ret; } extern int cKF_FrameControl_stop_proc(cKF_FrameControl_c* fc) { - f32 out; + f32 out; - if (fc->current_frame == fc->end_frame) { - return cKF_STATE_STOPPED; - } - if (cKF_FrameControl_passCheck(fc, fc->end_frame, &out)) { - fc->current_frame = fc->end_frame; - return cKF_STATE_STOPPED; - } - if (cKF_FrameControl_passCheck(fc, fc->start_frame, &out)) { - fc->current_frame = fc->end_frame; - return cKF_STATE_STOPPED; - } - return cKF_STATE_NONE; + if (fc->current_frame == fc->end_frame) { + return cKF_STATE_STOPPED; + } + if (cKF_FrameControl_passCheck(fc, fc->end_frame, &out)) { + fc->current_frame = fc->end_frame; + return cKF_STATE_STOPPED; + } + if (cKF_FrameControl_passCheck(fc, fc->start_frame, &out)) { + fc->current_frame = fc->end_frame; + return cKF_STATE_STOPPED; + } + return cKF_STATE_NONE; } +/** + * Repeats animation by looping from start to end frame. + * + * Loops the current frame back to the start or end, based on the animation's progression, + * allowing for continuous playback. + * + * @param fc Pointer to the frame control structure. + * @return cKF_STATE_CONTINUE if animation continues; cKF_STATE_NONE otherwise. + */ static int cKF_FrameControl_repeat_proc(cKF_FrameControl_c* fc) { - f32 out; + f32 out; - if (cKF_FrameControl_passCheck(fc, fc->end_frame, &out)) { - fc->current_frame = fc->start_frame + out; - return cKF_STATE_CONTINUE; - } - if (cKF_FrameControl_passCheck(fc, fc->start_frame, &out)) { - fc->current_frame = fc->end_frame + out; - return cKF_STATE_CONTINUE; - } - return cKF_STATE_NONE; + if (cKF_FrameControl_passCheck(fc, fc->end_frame, &out)) { + fc->current_frame = fc->start_frame + out; + return cKF_STATE_CONTINUE; + } + if (cKF_FrameControl_passCheck(fc, fc->start_frame, &out)) { + fc->current_frame = fc->end_frame + out; + return cKF_STATE_CONTINUE; + } + return cKF_STATE_NONE; } +/** + * Plays animation based on current mode. + * + * Updates current frame according to animation speed and mode, ensuring playback within + * the animation's frame range. + * + * @param fc Pointer to the frame control structure. + * @return Animation state after update. + */ static int cKF_FrameControl_play(cKF_FrameControl_c* fc) { - int rec; - f32 frame; + int rec; + f32 frame; - if (fc->mode == cKF_FRAMECONTROL_STOP) { - rec = cKF_FrameControl_stop_proc(fc); - } else { - rec = cKF_FrameControl_repeat_proc(fc); - } + if (fc->mode == cKF_FRAMECONTROL_STOP) { + rec = cKF_FrameControl_stop_proc(fc); + } else { + rec = cKF_FrameControl_repeat_proc(fc); + } - if (rec == cKF_STATE_NONE) { - frame = (fc->start_frame < fc->end_frame) ? fc->speed : -fc->speed; - fc->current_frame += frame; - } - if (fc->current_frame < 1.0f) { - fc->current_frame = (fc->current_frame - 1.0f) + fc->max_frames; - } else if (fc->current_frame > fc->max_frames) { - fc->current_frame = (fc->current_frame - fc->max_frames) + 1.0f; - } - return rec; + if (rec == cKF_STATE_NONE) { + frame = (fc->start_frame < fc->end_frame) ? fc->speed : -fc->speed; + fc->current_frame += frame; + } + if (fc->current_frame < 1.0f) { + fc->current_frame = (fc->current_frame - 1.0f) + fc->max_frames; + } else if (fc->current_frame > fc->max_frames) { + fc->current_frame = (fc->current_frame - fc->max_frames) + 1.0f; + } + return rec; } -extern f32 cKF_HermitCalc(f32 t, f32 tension, f32 p0, f32 p1, f32 m0, f32 m1) { - f32 p; - f32 sq; - f32 cb; - f32 h10; - f32 h11; +extern f32 cKF_HermitCalc(f32 time, f32 tension, f32 startPos, f32 endPos, f32 startTangent, f32 endTangent) { + f32 position; + f32 timeSquared; + f32 timeCubed; + f32 basisH10; + f32 basisH11; - sq = t * t; - cb = sq * t; - p = -(cb * 2.0f) + (3.0f * sq); - h10 = t + (cb - (sq * 2.0f)); - h11 = cb - sq; + timeSquared = time * time; + timeCubed = timeSquared * time; + position = -(timeCubed * 2.0f) + (3.0f * timeSquared); + basisH10 = time + (timeCubed - (timeSquared * 2.0f)); + basisH11 = timeCubed - timeSquared; - return (((1.0f - p) * p0) + (p * p1)) + (tension * ((h10 * m0) + (h11 * m1))); + return (((1.0f - position) * startPos) + (position * endPos)) + + (tension * ((basisH10 * startTangent) + (basisH11 * endTangent))); } -static s16 cKF_KeyCalc(s16 index, s16 next_index, s16* data_src, f32 frame) { - int j; - int i; - f32 sub; - s_xyz* s_vec = (s_xyz*)&data_src[index * 3]; - int key; +typedef struct { + s16 frame; + s16 value; + s16 tangent; +} cKF_AnimKey_c; - if (s_vec->x >= frame) { - return s_vec->y; - } - if (s_vec[next_index - 1].x <= frame) { - return s_vec[next_index - 1].y; - } +/** + * Calculates keyframe value based on frame position within keyframe data. + * + * Interpolates or directly retrieves the y-component of a keyframe based on the given frame number. + * Uses linear or Hermite interpolation depending on the proximity of frame to keyframe positions. + * + * @param start_idx Starting index of the keyframe data. + * @param n_frames Number of frames in the keyframe sequence. + * @param data_src Pointer to the keyframe data source. + * @param frame Current frame number for which to calculate the keyframe value. + * @return Interpolated or directly retrieved keyframe value. + */ +static s16 cKF_KeyCalc(s16 start_idx, s16 n_frames, s16* data_src, f32 frame) { + int now; + int next; + cKF_AnimKey_c* key_p = (cKF_AnimKey_c*)&data_src[start_idx * 3]; - for (j = 0, i = 1; 1; j++, i++) { - if (s_vec[i].x > frame) { - sub = s_vec[i].x - s_vec[j].x; + /* If the first frame is greater than the current frame then the first value is held */ + if (key_p[0].frame >= frame) { + return key_p[0].value; + } - if (!(F32_IS_ZERO(sub))) { - f32 t = (frame - s_vec[j].x) / sub; - f32 tension = sub * (1.0f / 30.0f); - f32 calc = cKF_HermitCalc(t, tension, s_vec[j].y, s_vec[i].y, s_vec[j].z, s_vec[i].z); - key = calc + 0.5; + /* If the current frame is greater than the last frame then the last value is held */ + if (key_p[n_frames - 1].frame <= frame) { + return key_p[n_frames - 1].value; + } + + // Search through all frames + now = 0; + next = 1; + + while (TRUE) { + if (key_p[next].frame > frame) { + f32 delta_frame = key_p[next].frame - key_p[now].frame; + + if (!(F32_IS_ZERO(delta_frame))) { + f32 t = (frame - key_p[now].frame) / delta_frame; // progress towards the next frame + f32 tension = delta_frame * (1.0f / 30.0f); + f32 calc = cKF_HermitCalc(t, tension, key_p[now].value, key_p[next].value, key_p[now].tangent, key_p[next].tangent); + int key = calc + 0.5; + + return key; + } else { + return key_p[now].value; + } + } - return key; - } else { - return s_vec[j].y; - } + now++; + next++; } - } } -extern void cKF_SkeletonInfo_subRotInterpolation(f32 t, s16* out, s16 rot1, - s16 rot2) { - u16 urot1 = rot1; - s32 pad; - u16 urot2 = rot2; - f32 f1 = rot1; - f32 signedDiff = rot2 - f1; - f32 f2 = urot1; - f32 unsignedDiff = urot2 - f2; +extern void cKF_SkeletonInfo_subRotInterpolation(f32 t, s16* out, s16 rot1, s16 rot2) { + u16 urot1 = rot1; + s32 pad; + u16 urot2 = rot2; + f32 f1 = rot1; + f32 signedDiff = rot2 - f1; + f32 f2 = urot1; + f32 unsignedDiff = urot2 - f2; - if (fabsf(signedDiff) < fabsf(unsignedDiff)) { - *out = f1 + signedDiff * t; - } else { - *out = f2 + unsignedDiff * t; - } + if (fabsf(signedDiff) < fabsf(unsignedDiff)) { + *out = f1 + signedDiff * t; + } else { + *out = f2 + unsignedDiff * t; + } } +/** + * Morphs current state towards a target state with a given step size. + * + * Adjusts 'now' values towards 'target' values based on 'step', performing this operation + * for three consecutive s16 values starting from 'now' and 'target'. + * + * @param now Pointer to the current values. + * @param target Pointer to the target values to morph towards. + * @param step Fractional step size for morphing. + */ static void cKF_SkeletonInfo_morphST(s16* now, s16* target, f32 step) { - int i; + int i; - for (i = 0; i < 3; i++) { - if (*now != *target) { - f32 now_f = (f32)*now; - f32 target_f = (f32)*target; - f32 diff = (target_f - now_f); - *now = (diff * step) + now_f; + for (i = 0; i < 3; i++) { + if (*now != *target) { + f32 now_f = (f32)*now; + f32 target_f = (f32)*target; + f32 diff = (target_f - now_f); + *now = (diff * step) + now_f; + } + + now++; + target++; } - - now++; - target++; - } } +/** + * Zeroes out and initializes a skeleton info structure. + * + * Clears all data within cKF_SkeletonInfo_R_c structure, effectively resetting it. + * + * @param keyframe Pointer to the skeleton info structure to be cleared. + */ static void cKF_SkeletonInfo_R_zeroClear(cKF_SkeletonInfo_R_c* keyframe) { - bzero(keyframe, sizeof(cKF_SkeletonInfo_R_c)); + bzero(keyframe, sizeof(cKF_SkeletonInfo_R_c)); } -extern void cKF_SkeletonInfo_R_ct(cKF_SkeletonInfo_R_c* keyframe, - cKF_Skeleton_R_c* skeleton, - cKF_Animation_R_c* animation, - s_xyz* work_table, s_xyz* target_table) { - cKF_SkeletonInfo_R_zeroClear(keyframe); - cKF_FrameControl_ct(&keyframe->frame_control); +extern void cKF_SkeletonInfo_R_ct(cKF_SkeletonInfo_R_c* keyframe, cKF_Skeleton_R_c* skeleton, + cKF_Animation_R_c* animation, s_xyz* work_table, s_xyz* target_table) { + cKF_SkeletonInfo_R_zeroClear(keyframe); + cKF_FrameControl_ct(&keyframe->frame_control); - keyframe->skeleton = skeleton; - keyframe->animation = animation; - keyframe->current_joint = work_table; - keyframe->target_joint = target_table; + keyframe->skeleton = skeleton; + keyframe->animation = animation; + keyframe->current_joint = work_table; + keyframe->target_joint = target_table; } -extern void cKF_SkeletonInfo_R_dt(cKF_SkeletonInfo_R_c* keyframe) {} - -extern void cKF_SkeletonInfo_R_init_standard_stop( - cKF_SkeletonInfo_R_c* keyframe, cKF_Animation_R_c* animation, - s_xyz* rotation_diff_table) { - cKF_SkeletonInfo_R_init(keyframe, keyframe->skeleton, animation, 1.0f, - animation->frames, 1.0f, 0.5f, 0.0f, - cKF_FRAMECONTROL_STOP, rotation_diff_table); +extern void cKF_SkeletonInfo_R_dt(cKF_SkeletonInfo_R_c* keyframe) { } -extern void cKF_SkeletonInfo_R_init_standard_stop_morph( - cKF_SkeletonInfo_R_c* keyframe, cKF_Animation_R_c* animation, - s_xyz* rotation_diff_table, f32 morph) { - cKF_SkeletonInfo_R_init(keyframe, keyframe->skeleton, animation, 1.0f, - animation->frames, 1.0f, 0.5f, morph, - cKF_FRAMECONTROL_STOP, rotation_diff_table); +extern void cKF_SkeletonInfo_R_init_standard_stop(cKF_SkeletonInfo_R_c* keyframe, cKF_Animation_R_c* animation, + s_xyz* rotation_diff_table) { + cKF_SkeletonInfo_R_init(keyframe, keyframe->skeleton, animation, 1.0f, animation->frames, 1.0f, 0.5f, 0.0f, + cKF_FRAMECONTROL_STOP, rotation_diff_table); } -extern void cKF_SkeletonInfo_R_init_standard_repeat( - cKF_SkeletonInfo_R_c* keyframe, cKF_Animation_R_c* animation, - s_xyz* rotation_diff_table) { - cKF_SkeletonInfo_R_init(keyframe, keyframe->skeleton, animation, 1.0f, - animation->frames, 1.0f, 0.5f, 0.0f, - cKF_FRAMECONTROL_REPEAT, rotation_diff_table); +extern void cKF_SkeletonInfo_R_init_standard_stop_morph(cKF_SkeletonInfo_R_c* keyframe, cKF_Animation_R_c* animation, + s_xyz* rotation_diff_table, f32 morph) { + cKF_SkeletonInfo_R_init(keyframe, keyframe->skeleton, animation, 1.0f, animation->frames, 1.0f, 0.5f, morph, + cKF_FRAMECONTROL_STOP, rotation_diff_table); } -extern void cKF_SkeletonInfo_R_init_standard_repeat_morph( - cKF_SkeletonInfo_R_c* keyframe, cKF_Animation_R_c* animation, - s_xyz* rotation_diff_table, f32 morph) { - cKF_SkeletonInfo_R_init(keyframe, keyframe->skeleton, animation, 1.0f, - animation->frames, 1.0f, 0.5f, morph, - cKF_FRAMECONTROL_REPEAT, rotation_diff_table); +extern void cKF_SkeletonInfo_R_init_standard_repeat(cKF_SkeletonInfo_R_c* keyframe, cKF_Animation_R_c* animation, + s_xyz* rotation_diff_table) { + cKF_SkeletonInfo_R_init(keyframe, keyframe->skeleton, animation, 1.0f, animation->frames, 1.0f, 0.5f, 0.0f, + cKF_FRAMECONTROL_REPEAT, rotation_diff_table); } -extern void cKF_SkeletonInfo_R_init(cKF_SkeletonInfo_R_c* keyframe, - cKF_Skeleton_R_c* skeleton, - cKF_Animation_R_c* animation, - f32 start_frame, f32 end_frame, - f32 current_frame, f32 frame_speed, - f32 morph_counter, int mode, - s_xyz* rotation_diff_table) { - keyframe->morph_counter = morph_counter; - keyframe->skeleton = skeleton; - keyframe->animation = animation; - - cKF_FrameControl_setFrame(&keyframe->frame_control, start_frame, end_frame, - keyframe->animation->frames, current_frame, - frame_speed, mode); - keyframe->rotation_diff_table = rotation_diff_table; +extern void cKF_SkeletonInfo_R_init_standard_repeat_morph(cKF_SkeletonInfo_R_c* keyframe, cKF_Animation_R_c* animation, + s_xyz* rotation_diff_table, f32 morph) { + cKF_SkeletonInfo_R_init(keyframe, keyframe->skeleton, animation, 1.0f, animation->frames, 1.0f, 0.5f, morph, + cKF_FRAMECONTROL_REPEAT, rotation_diff_table); } +extern void cKF_SkeletonInfo_R_init(cKF_SkeletonInfo_R_c* keyframe, cKF_Skeleton_R_c* skeleton, + cKF_Animation_R_c* animation, f32 start_frame, f32 end_frame, f32 current_frame, + f32 frame_speed, f32 morph_counter, int mode, s_xyz* rotation_diff_table) { + keyframe->morph_counter = morph_counter; + keyframe->skeleton = skeleton; + keyframe->animation = animation; + + cKF_FrameControl_setFrame(&keyframe->frame_control, start_frame, end_frame, keyframe->animation->frames, + current_frame, frame_speed, mode); + keyframe->rotation_diff_table = rotation_diff_table; +} + +/** + * Morphs joint positions towards target positions based on the morph counter. + * + * Adjusts each joint's position in the skeleton towards its target position using interpolation, + * based on a calculated step size derived from the morph counter. If the morph counter is zero, + * no morphing occurs. + * + * @param keyframe Pointer to the skeleton info structure containing joint and target positions. + */ static void cKF_SkeletonInfo_R_morphJoint(cKF_SkeletonInfo_R_c* keyframe) { - f32 step; - int i; - s_xyz* current_joint = keyframe->current_joint; - s_xyz* target_joint = keyframe->target_joint; + f32 step; + int i; + s_xyz* current_joint = keyframe->current_joint; + s_xyz* target_joint = keyframe->target_joint; - if (!(F32_IS_ZERO(keyframe->morph_counter))) { - step = 0.5f / fabsf(keyframe->morph_counter); - } else { - step = 0.0f; - } - - cKF_SkeletonInfo_morphST(¤t_joint->x, &target_joint->x, step); - - current_joint++; - target_joint++; - - for (i = 0; i < keyframe->skeleton->num_joints; i++) { - s16 next_joint_x = current_joint->x; - s16 next_target_x = target_joint->x; - - s16 next_joint_y = current_joint->y; - s16 next_joint_z = current_joint->z; - - s16 next_target_y = target_joint->y; - s16 next_target_z = target_joint->z; - - if (next_joint_x != next_target_x || next_joint_y != next_target_y || - next_joint_z != next_target_z) { - f32 difxyz = fabsf((f32)next_target_x - (f32)next_joint_x) + - fabsf((f32)next_target_y - (f32)next_joint_y) + - fabsf((f32)next_target_z - (f32)next_joint_z); - - s16 temp_vec_x = 0x7FFF + next_joint_x; - s16 temp_vec_y = 0x7FFF - next_joint_y; - s16 temp_vec_z = 0x7FFF + next_joint_z; - - f32 dif_xyz2 = fabsf((f32)next_target_x - (f32)temp_vec_x) + - fabsf((f32)next_target_y - (f32)temp_vec_y) + - fabsf((f32)next_target_z - (f32)temp_vec_z); - - if (difxyz < dif_xyz2) { - cKF_SkeletonInfo_subRotInterpolation(step, ¤t_joint->x, - next_joint_x, next_target_x); - cKF_SkeletonInfo_subRotInterpolation(step, ¤t_joint->y, - next_joint_y, next_target_y); - cKF_SkeletonInfo_subRotInterpolation(step, ¤t_joint->z, - next_joint_z, next_target_z); - } else { - cKF_SkeletonInfo_subRotInterpolation(step, ¤t_joint->x, - temp_vec_x, next_target_x); - cKF_SkeletonInfo_subRotInterpolation(step, ¤t_joint->y, - temp_vec_y, next_target_y); - cKF_SkeletonInfo_subRotInterpolation(step, ¤t_joint->z, - temp_vec_z, next_target_z); - } + if (!(F32_IS_ZERO(keyframe->morph_counter))) { + step = 0.5f / fabsf(keyframe->morph_counter); + } else { + step = 0.0f; } - target_joint++; + + cKF_SkeletonInfo_morphST(¤t_joint->x, &target_joint->x, step); + current_joint++; - } + target_joint++; + + for (i = 0; i < keyframe->skeleton->num_joints; i++) { + s16 next_joint_x = current_joint->x; + s16 next_target_x = target_joint->x; + + s16 next_joint_y = current_joint->y; + s16 next_joint_z = current_joint->z; + + s16 next_target_y = target_joint->y; + s16 next_target_z = target_joint->z; + + if (next_joint_x != next_target_x || next_joint_y != next_target_y || next_joint_z != next_target_z) { + f32 difxyz = fabsf((f32)next_target_x - (f32)next_joint_x) + fabsf((f32)next_target_y - (f32)next_joint_y) + + fabsf((f32)next_target_z - (f32)next_joint_z); + + s16 temp_vec_x = 0x7FFF + next_joint_x; + s16 temp_vec_y = 0x7FFF - next_joint_y; + s16 temp_vec_z = 0x7FFF + next_joint_z; + + f32 dif_xyz2 = fabsf((f32)next_target_x - (f32)temp_vec_x) + fabsf((f32)next_target_y - (f32)temp_vec_y) + + fabsf((f32)next_target_z - (f32)temp_vec_z); + + if (difxyz < dif_xyz2) { + cKF_SkeletonInfo_subRotInterpolation(step, ¤t_joint->x, next_joint_x, next_target_x); + cKF_SkeletonInfo_subRotInterpolation(step, ¤t_joint->y, next_joint_y, next_target_y); + cKF_SkeletonInfo_subRotInterpolation(step, ¤t_joint->z, next_joint_z, next_target_z); + } else { + cKF_SkeletonInfo_subRotInterpolation(step, ¤t_joint->x, temp_vec_x, next_target_x); + cKF_SkeletonInfo_subRotInterpolation(step, ¤t_joint->y, temp_vec_y, next_target_y); + cKF_SkeletonInfo_subRotInterpolation(step, ¤t_joint->z, temp_vec_z, next_target_z); + } + } + target_joint++; + current_joint++; + } } +/** + * Retrieves the flag table from an animation structure. + * + * Provides direct access to the flag table indicating the state or properties of each frame + * or keyframe in the animation sequence. + * + * @param keyframe Pointer to the animation structure. + * @return Pointer to the flag table. + */ inline u8* cKF_Animation_R_getFlagTable(cKF_Animation_R_c* keyframe) { - return keyframe->flag_table; + return keyframe->flag_table; } +/** + * Retrieves the fixed table from an animation structure. + * + * Provides direct access to the fixed table containing fixed values used in the animation, + * possibly for static or non-interpolated properties. + * + * @param keyframe Pointer to the animation structure. + * @return Pointer to the fixed table. + */ inline s16* cKF_Animation_R_getFixedTable(cKF_Animation_R_c* keyframe) { - return keyframe->fixed_table; + return keyframe->fixed_table; } +/** + * Retrieves the key table from an animation structure. + * + * Provides direct access to the key table containing key points used for interpolating + * animation values. + * + * @param keyframe Pointer to the animation structure. + * @return Pointer to the key table. + */ inline s16* cKF_Animation_R_getKeyTable(cKF_Animation_R_c* keyframe) { - return keyframe->key_table; + return keyframe->key_table; } +/** + * Retrieves the data table from an animation structure. + * + * Provides direct access to the data table containing all numerical data points used for + * animating properties over time. + * + * @param keyframe Pointer to the animation structure. + * @return Pointer to the data table. + */ inline s16* cKF_Animation_R_getDataTable(cKF_Animation_R_c* keyframe) { - return keyframe->data_table; + return keyframe->data_table; } extern int cKF_SkeletonInfo_R_play(cKF_SkeletonInfo_R_c* keyframe) { - int ret; - int s; - s_xyz* c_joint; - s16 j_fix_tbl; - s16* cur_joint; - cKF_Animation_R_c* key_an; - int i; - f32 calc_joint; - s16* an_tblp; + int state; + int jointIndex; + s_xyz* currentJointPtr; + s16 fixedJointValue; + s16* currentJointValue; + cKF_Animation_R_c* animationData; + int component; + f32 adjustedJointValue; - int j = 0; - int t = 0; + int keyTableIndex = 0; + int fixedTableIndex = 0; - int index = 0; - s16* joint = (F32_IS_ZERO(keyframe->morph_counter)) - ? &keyframe->current_joint->x - : &keyframe->target_joint->x; - int joint_num = 32; + int dataIndex = 0; + // Choose between current and target joint based on morph counter + s16* jointValuePtr = + (F32_IS_ZERO(keyframe->morph_counter)) ? &keyframe->current_joint->x : &keyframe->target_joint->x; + u32 jointFlag = cKF_ANIMATION_BIT_TRANS_X; // Check translation (xyz) - s16* an_fix_tbl = cKF_Animation_R_getFixedTable(keyframe->animation); - s16* an_key_tbl = cKF_Animation_R_getKeyTable(keyframe->animation); - s16* an_data_tbl = cKF_Animation_R_getDataTable(keyframe->animation); - u8* an_flag_tbl = cKF_Animation_R_getFlagTable(keyframe->animation); + // Retrieve animation tables + s16* fixedTable = cKF_Animation_R_getFixedTable(keyframe->animation); + s16* keyTable = cKF_Animation_R_getKeyTable(keyframe->animation); + s16* dataTable = cKF_Animation_R_getDataTable(keyframe->animation); + u8* flagTable = cKF_Animation_R_getFlagTable(keyframe->animation); - for (i = 0; i < 3; i++) { - if (*an_flag_tbl & joint_num) { - an_tblp = &an_key_tbl[j]; - *joint = cKF_KeyCalc(index, *an_tblp, an_data_tbl, - keyframe->frame_control.current_frame); - index += an_key_tbl[j]; - j++; + // Process root translation x -> y -> z + for (component = 0; component < 3; component++) { + if (flagTable[0] & jointFlag) { + // Apply joint translation + *jointValuePtr = + cKF_KeyCalc(dataIndex, keyTable[keyTableIndex], dataTable, keyframe->frame_control.current_frame); + dataIndex += keyTable[keyTableIndex++]; + } else { + // Use fixed value if not flagged for keyframe animation + *jointValuePtr = fixedTable[fixedTableIndex++]; + } + + jointFlag >>= 1; // Shift x -> y -> z + jointValuePtr++; // Move to next joint + } + + // Process remaining joint rotations + for (jointIndex = 0; jointIndex < keyframe->skeleton->num_joints; jointIndex++) { + jointFlag = cKF_ANIMATION_BIT_ROT_X; // Reset flag for new joint + + // Process each joint x -> y -> z + for (component = 0; component < 3; component++) { + // Similar logic to above, but for each joint in the skeleton + if (jointFlag & flagTable[jointIndex]) { + *jointValuePtr = + cKF_KeyCalc(dataIndex, keyTable[keyTableIndex], dataTable, keyframe->frame_control.current_frame); + dataIndex += keyTable[keyTableIndex++]; + } else { + *jointValuePtr = fixedTable[fixedTableIndex++]; + } + + // Convert joint value to fixed-point format after scaling + jointFlag >>= 1; // Shift flag for next component x -> y -> z + + // Reduce the value by 10% and clamp to [0, 360) degrees converted back to binangle (s16) + adjustedJointValue = *jointValuePtr * 0.1f; + *jointValuePtr++ = DEG2SHORT_ANGLE(MOD_F(adjustedJointValue, 360.0f)); + } + } + + // Apply rotation differences if available + if (keyframe->rotation_diff_table != NULL) { + currentJointPtr = (F32_IS_ZERO(keyframe->morph_counter)) ? keyframe->current_joint : keyframe->target_joint; + + currentJointPtr++; // Skip first joint, usually root, which is handled separately + for (component = 0; component < keyframe->skeleton->num_joints; component++) { + // Apply rotation differences to each joint + currentJointPtr->x += keyframe->rotation_diff_table[component].x; + currentJointPtr->y += keyframe->rotation_diff_table[component].y; + currentJointPtr->z += keyframe->rotation_diff_table[component].z; + + currentJointPtr++; // Move to next joint + } + } + + // Handle morphing and play control based on morph counter + if (F32_IS_ZERO(keyframe->morph_counter)) { + // Play normally if no morphing is needed + state = cKF_FrameControl_play(&keyframe->frame_control); + } else if (keyframe->morph_counter > 0.0f) { + // Morph towards target, decreasing morph counter + cKF_SkeletonInfo_R_morphJoint(keyframe); + keyframe->morph_counter -= 0.5f; + if (keyframe->morph_counter <= 0.0f) { + keyframe->morph_counter = 0.0f; // Clamp to zero if over-decremented + } + state = cKF_STATE_NONE; } else { - j_fix_tbl = an_fix_tbl[t]; - t++; - *joint = j_fix_tbl; + // Morph from target, increasing morph counter towards zero + cKF_SkeletonInfo_R_morphJoint(keyframe); + keyframe->morph_counter += 0.5f; + if (keyframe->morph_counter >= 0.0f) { + keyframe->morph_counter = 0.0f; // Clamp to zero if over-incremented + } + state = cKF_FrameControl_play(&keyframe->frame_control); } - joint_num = (u32)joint_num >> 1; - joint += 1; - } - - for (s = 0; s < keyframe->skeleton->num_joints; s++) { - joint_num = 4; - - for (i = 0; i < 3; i++) { - if (joint_num & an_flag_tbl[s]) { - an_tblp = &an_key_tbl[j]; - *joint = cKF_KeyCalc(index, *an_tblp, an_data_tbl, - keyframe->frame_control.current_frame); - index += an_key_tbl[j]; - j++; - } else { - j_fix_tbl = an_fix_tbl[t]; - t++; - *joint = j_fix_tbl; - } - - calc_joint = *joint * 0.1f; - joint_num = (u32)joint_num >> 1; - *joint = - (s16)(int)((calc_joint - - ((f32)(int)(calc_joint * (1.0f / 360.0f)) * 360.0f)) * - (65536.0f / 360.0f)); - - joint++; - } - } - - if (keyframe->rotation_diff_table != NULL) { - c_joint = (F32_IS_ZERO(keyframe->morph_counter)) - ? keyframe->current_joint - : keyframe->target_joint; - - c_joint += 1; - for (i = 0; i < keyframe->skeleton->num_joints; i++) { - c_joint->x += keyframe->rotation_diff_table[i].x; - c_joint->y += keyframe->rotation_diff_table[i].y; - c_joint->z += keyframe->rotation_diff_table[i].z; - - c_joint++; - } - } - - if (F32_IS_ZERO(keyframe->morph_counter)) { - ret = cKF_FrameControl_play(&keyframe->frame_control); - } else if (keyframe->morph_counter > 0.0f) { - cKF_SkeletonInfo_R_morphJoint(keyframe); - keyframe->morph_counter -= 0.5f; - if (keyframe->morph_counter <= 0.0f) { - keyframe->morph_counter = 0.0f; - } - ret = cKF_STATE_NONE; - } else { - cKF_SkeletonInfo_R_morphJoint(keyframe); - keyframe->morph_counter += 0.5f; - if (keyframe->morph_counter >= 0.0f) { - keyframe->morph_counter = 0.0f; - } - ret = cKF_FrameControl_play(&keyframe->frame_control); - } - return ret; + return state; } -extern void cKF_Si3_draw_SV_R_child(GAME* game, cKF_SkeletonInfo_R_c* keyframe, - int* joint_num, - cKF_draw_callback prerender_callback, - cKF_draw_callback postrender_callback, +extern void cKF_Si3_draw_SV_R_child(GAME* game, cKF_SkeletonInfo_R_c* keyframe, int* joint_num, + cKF_draw_callback prerender_callback, cKF_draw_callback postrender_callback, void* arg, Mtx** mtxpp) { - int i; - int an_flag; - Gfx* joint_m; - Gfx* mjoint_m; - u8 joint_f; - xyz_t def_joint; - s_xyz joint1; - cKF_Joint_R_c* skel_c_joint; - s_xyz* cur_joint; - GRAPH* graph; + int i; + int an_flag; + Gfx* joint_m; + Gfx* mjoint_m; + u8 joint_f; + xyz_t trans; + s_xyz joint1; + cKF_Joint_R_c* skel_c_joint; + s_xyz* cur_joint; + GRAPH* graph; - skel_c_joint = keyframe->skeleton->joint_table; - skel_c_joint += *joint_num; - cur_joint = &keyframe->current_joint[*joint_num]; + skel_c_joint = keyframe->skeleton->joint_table; + skel_c_joint += *joint_num; + cur_joint = &keyframe->current_joint[*joint_num]; - if (*joint_num != 0) { - def_joint.x = skel_c_joint->translation.x; - def_joint.y = skel_c_joint->translation.y; - def_joint.z = skel_c_joint->translation.z; - } else { - an_flag = keyframe->animation_enabled; - if (an_flag & 1) { - def_joint.x = keyframe->base_model_translation.x; - def_joint.z = keyframe->base_model_translation.z; + if (*joint_num != 0) { + // Since we have joints, take the current joint's translation + trans.x = skel_c_joint->translation.x; + trans.y = skel_c_joint->translation.y; + trans.z = skel_c_joint->translation.z; } else { - def_joint.x = cur_joint->x; - def_joint.z = cur_joint->z; + // No joints, take the base model translation w/ respect to flags + an_flag = keyframe->animation_enabled; + if (an_flag & cKF_ANIMATION_TRANS_XZ) { + trans.x = keyframe->base_model_translation.x; + trans.z = keyframe->base_model_translation.z; + } else { + trans.x = cur_joint->x; + trans.z = cur_joint->z; + } + if (an_flag & cKF_ANIMATION_TRANS_Y) { + trans.y = keyframe->base_model_translation.y; + } else { + trans.y = cur_joint->y; + } } - if (an_flag & 2) { - def_joint.y = keyframe->base_model_translation.y; - } else { - def_joint.y = cur_joint->y; + + joint1 = cur_joint[1]; + + if ((joint_num[0] == 0) && (keyframe->animation_enabled & cKF_ANIMATION_ROT_X)) { + joint1.x = keyframe->base_model_rotation.x; + joint1.y = keyframe->updated_base_model_rotation.y; + joint1.z = keyframe->updated_base_model_rotation.z; } - } - joint1 = cur_joint[1]; - - if ((joint_num[0] == 0) && (keyframe->animation_enabled & 4)) { - joint1.x = keyframe->base_model_rotation.x; - joint1.y = keyframe->updated_base_model_rotation.y; - joint1.z = keyframe->updated_base_model_rotation.z; - } - graph = game->graph; - - OPEN_DISP(graph); - Matrix_push(); - joint_m = skel_c_joint->model; - mjoint_m = joint_m; - joint_f = skel_c_joint->flags; - - if ((prerender_callback == NULL) || - ((prerender_callback != NULL) && - prerender_callback(game, keyframe, *joint_num, &mjoint_m, &joint_f, arg, - &joint1, &def_joint) != 0)) { - Matrix_softcv3_mult(&def_joint, &joint1); - if (mjoint_m != NULL) { - _Matrix_to_Mtx(*mtxpp); - if (joint_f & 1) { - gSPMatrix(NOW_POLY_XLU_DISP++, *mtxpp, - G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); - gSPDisplayList(NOW_POLY_XLU_DISP++, mjoint_m); - } else { - gSPMatrix(NOW_POLY_OPA_DISP++, *mtxpp, - G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); - gSPDisplayList(NOW_POLY_OPA_DISP++, mjoint_m); - } - *mtxpp += 1; - } else if (joint_m != NULL) { - _Matrix_to_Mtx(*mtxpp); - gSPMatrix(NOW_POLY_OPA_DISP++, *mtxpp, - G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); - *mtxpp += 1; - } - } - - CLOSE_DISP(graph); - - if (postrender_callback != NULL) { - postrender_callback(game, keyframe, *joint_num, &mjoint_m, &joint_f, arg, - &joint1, &def_joint); - } - i = 0; - *joint_num += 1; - - for (i; i < skel_c_joint->child; i++) { - cKF_Si3_draw_SV_R_child(game, keyframe, joint_num, prerender_callback, - postrender_callback, arg, mtxpp); - } - Matrix_pull(); -} - -extern void cKF_Si3_draw_R_SV(GAME* game, cKF_SkeletonInfo_R_c* keyframe, - Mtx* mtxp, cKF_draw_callback prerender_callback, - cKF_draw_callback postrender_callback, - void* arg) { - int joint_num; - Mtx* mtx_p = mtxp; - - if (mtxp != NULL) { - GRAPH* graph = game->graph; + graph = game->graph; OPEN_DISP(graph); + Matrix_push(); - /* TODO: these should probably be made into a custom macro somewhere */ - gSPSegment(NOW_POLY_OPA_DISP++, G_MWO_SEGMENT_D, - mtx_p); // Load matrix (opaque) - gSPSegment(NOW_POLY_XLU_DISP++, G_MWO_SEGMENT_D, - mtx_p); // Load matrix (translucent) + joint_m = skel_c_joint->model; + mjoint_m = joint_m; + joint_f = skel_c_joint->flags; + + // Render joint if prerender callback wasn't supplied or the callback does not return FALSE + if ((prerender_callback == NULL) || + ((prerender_callback != NULL) && + prerender_callback(game, keyframe, *joint_num, &mjoint_m, &joint_f, arg, &joint1, &trans) != FALSE)) { + Matrix_softcv3_mult(&trans, &joint1); + if (mjoint_m != NULL) { + _Matrix_to_Mtx(*mtxpp); + if (joint_f & cKF_JOINT_FLAG_DISP_XLU) { + // Joint translated & drawn in XLU display list + gSPMatrix(NOW_POLY_XLU_DISP++, *mtxpp, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(NOW_POLY_XLU_DISP++, mjoint_m); + } else { + // Joint translated & drawin OPA display list + gSPMatrix(NOW_POLY_OPA_DISP++, *mtxpp, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(NOW_POLY_OPA_DISP++, mjoint_m); + } + mtxpp[0]++; + } else if (joint_m != NULL) { + // Joint has a rendered model but the prerender callback chose not to render it + // so we apply the translation still + _Matrix_to_Mtx(*mtxpp); + gSPMatrix(NOW_POLY_OPA_DISP++, *mtxpp, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + mtxpp[0]++; + } + } CLOSE_DISP(graph); - joint_num = 0; - cKF_Si3_draw_SV_R_child(game, keyframe, &joint_num, prerender_callback, - postrender_callback, arg, &mtx_p); - } + // Call postrender callback if supplied + if (postrender_callback != NULL) { + postrender_callback(game, keyframe, *joint_num, &mjoint_m, &joint_f, arg, &joint1, &trans); + } + + joint_num[0]++; // Move onto next joint + + // Render all children + for (i = 0; i < skel_c_joint->child; i++) { + cKF_Si3_draw_SV_R_child(game, keyframe, joint_num, prerender_callback, postrender_callback, arg, mtxpp); + } + + // Remove the effect of this joint's translation & rotatation + Matrix_pull(); } -extern void cKF_SkeletonInfo_R_init_standard_repeat_speedsetandmorph( - cKF_SkeletonInfo_R_c* keyframe, cKF_Animation_R_c* animation, - s_xyz* rotation_diff_table, f32 frame_speed, f32 morph_counter) { - cKF_SkeletonInfo_R_init(keyframe, keyframe->skeleton, animation, 1.0f, - animation->frames, 1.0f, frame_speed, morph_counter, - cKF_FRAMECONTROL_REPEAT, rotation_diff_table); +extern void cKF_Si3_draw_R_SV(GAME* game, cKF_SkeletonInfo_R_c* keyframe, Mtx* mtxp, + cKF_draw_callback prerender_callback, cKF_draw_callback postrender_callback, void* arg) { + int joint_num; + Mtx* mtx_p = mtxp; + + if (mtxp != NULL) { + GRAPH* graph = game->graph; + OPEN_DISP(graph); + + /* TODO: these should probably be made into a custom macro somewhere */ + gSPSegment(NOW_POLY_OPA_DISP++, G_MWO_SEGMENT_D, + mtx_p); // Load matrix (opaque) + gSPSegment(NOW_POLY_XLU_DISP++, G_MWO_SEGMENT_D, + mtx_p); // Load matrix (translucent) + + CLOSE_DISP(graph); + joint_num = 0; + + cKF_Si3_draw_SV_R_child(game, keyframe, &joint_num, prerender_callback, postrender_callback, arg, &mtx_p); + } } -extern void cKF_SkeletonInfo_R_init_standard_repeat_setframeandspeedandmorph( - cKF_SkeletonInfo_R_c* keyframe, cKF_Animation_R_c* animation, - s_xyz* rotation_diff_table, f32 frame, f32 frame_speed, f32 morph_counter) { - cKF_SkeletonInfo_R_init(keyframe, keyframe->skeleton, animation, 1.0f, - animation->frames, frame, frame_speed, morph_counter, - cKF_FRAMECONTROL_REPEAT, rotation_diff_table); +extern void cKF_SkeletonInfo_R_init_standard_repeat_speedsetandmorph(cKF_SkeletonInfo_R_c* keyframe, + cKF_Animation_R_c* animation, + s_xyz* rotation_diff_table, f32 frame_speed, + f32 morph_counter) { + cKF_SkeletonInfo_R_init(keyframe, keyframe->skeleton, animation, 1.0f, animation->frames, 1.0f, frame_speed, + morph_counter, cKF_FRAMECONTROL_REPEAT, rotation_diff_table); } -extern void cKF_SkeletonInfo_R_init_standard_setframeandspeedandmorphandmode( - cKF_SkeletonInfo_R_c* keyframe, cKF_Animation_R_c* animation, - s_xyz* rotation_diff_table, f32 frame, f32 frame_speed, f32 morph_counter, - int mode) { - cKF_SkeletonInfo_R_init(keyframe, keyframe->skeleton, animation, 1.0f, - animation->frames, frame, frame_speed, morph_counter, - mode, rotation_diff_table); +extern void cKF_SkeletonInfo_R_init_standard_repeat_setframeandspeedandmorph(cKF_SkeletonInfo_R_c* keyframe, + cKF_Animation_R_c* animation, + s_xyz* rotation_diff_table, f32 frame, + f32 frame_speed, f32 morph_counter) { + cKF_SkeletonInfo_R_init(keyframe, keyframe->skeleton, animation, 1.0f, animation->frames, frame, frame_speed, + morph_counter, cKF_FRAMECONTROL_REPEAT, rotation_diff_table); } -extern void cKF_SkeletonInfo_R_init_reverse_setspeedandmorphandmode( - cKF_SkeletonInfo_R_c* keyframe, cKF_Animation_R_c* animation, - s_xyz* rotation_diff_table, f32 frame_speed, f32 morph_counter, int mode) { - cKF_SkeletonInfo_R_init( - keyframe, keyframe->skeleton, animation, animation->frames, 1.0f, - animation->frames, frame_speed, morph_counter, mode, rotation_diff_table); +extern void cKF_SkeletonInfo_R_init_standard_setframeandspeedandmorphandmode(cKF_SkeletonInfo_R_c* keyframe, + cKF_Animation_R_c* animation, + s_xyz* rotation_diff_table, f32 frame, + f32 frame_speed, f32 morph_counter, + int mode) { + cKF_SkeletonInfo_R_init(keyframe, keyframe->skeleton, animation, 1.0f, animation->frames, frame, frame_speed, + morph_counter, mode, rotation_diff_table); } -extern void cKF_SkeletonInfo_R_combine_work_set( - cKF_SkeletonInfo_R_combine_work_c* combine, - cKF_SkeletonInfo_R_c* keyframe) { - combine->keyframe = keyframe; - combine->anm_const_val_tbl = keyframe->animation->fixed_table; - combine->anm_key_num = keyframe->animation->key_table; - combine->anm_data_src = keyframe->animation->data_table; - combine->anm_check_bit_tbl = keyframe->animation->flag_table; - combine->anm_key_num_idx = 0; - combine->anm_const_val_tbl_idx = 0; - combine->anm_data_src_idx = 0; +extern void cKF_SkeletonInfo_R_init_reverse_setspeedandmorphandmode(cKF_SkeletonInfo_R_c* keyframe, + cKF_Animation_R_c* animation, + s_xyz* rotation_diff_table, f32 frame_speed, + f32 morph_counter, int mode) { + cKF_SkeletonInfo_R_init(keyframe, keyframe->skeleton, animation, animation->frames, 1.0f, animation->frames, + frame_speed, morph_counter, mode, rotation_diff_table); } -extern void cKF_SkeletonInfo_R_combine_translation( - s16** joint, int* flag, cKF_SkeletonInfo_R_combine_work_c* combine, - s8* cwork_num) { - int i = 0; +extern void cKF_SkeletonInfo_R_combine_work_set(cKF_SkeletonInfo_R_combine_work_c* combine, + cKF_SkeletonInfo_R_c* keyframe) { + combine->keyframe = keyframe; + combine->anm_const_val_tbl = keyframe->animation->fixed_table; + combine->anm_key_num = keyframe->animation->key_table; + combine->anm_data_src = keyframe->animation->data_table; + combine->anm_check_bit_tbl = keyframe->animation->flag_table; + combine->anm_key_num_idx = 0; + combine->anm_const_val_tbl_idx = 0; + combine->anm_data_src_idx = 0; +} - for (i; i < 3; i++) { - switch (*cwork_num) { - case 0: +extern void cKF_SkeletonInfo_R_combine_translation(s16** joint, int* flag, cKF_SkeletonInfo_R_combine_work_c* combine, + s8* cwork_num) { + int i = 0; + + for (i; i < 3; i++) { + switch (*cwork_num) { + case 0: + + if (*combine[0].anm_check_bit_tbl & *flag) { + (**joint) = + cKF_KeyCalc(combine[0].anm_data_src_idx, combine[0].anm_key_num[combine[0].anm_key_num_idx], + combine[0].anm_data_src, combine[0].keyframe->frame_control.current_frame); + } else { + (**joint) = combine[0].anm_const_val_tbl[combine[0].anm_const_val_tbl_idx]; + } + + break; + case 1: + + if (*combine[1].anm_check_bit_tbl & *flag) { + (**joint) = + cKF_KeyCalc(combine[1].anm_data_src_idx, combine[1].anm_key_num[combine[1].anm_key_num_idx], + combine[1].anm_data_src, combine[1].keyframe->frame_control.current_frame); + } else { + (**joint) = combine[1].anm_const_val_tbl[combine[1].anm_const_val_tbl_idx]; + } + + break; + case 2: + + if (*combine[2].anm_check_bit_tbl & *flag) { + (**joint) = + cKF_KeyCalc(combine[2].anm_data_src_idx, combine[2].anm_key_num[combine[2].anm_key_num_idx], + combine[2].anm_data_src, combine[2].keyframe->frame_control.current_frame); + } else { + (**joint) = combine[2].anm_const_val_tbl[combine[2].anm_const_val_tbl_idx]; + } + + break; + } if (*combine[0].anm_check_bit_tbl & *flag) { - (**joint) = - cKF_KeyCalc(combine[0].anm_data_src_idx, - combine[0].anm_key_num[combine[0].anm_key_num_idx], - combine[0].anm_data_src, - combine[0].keyframe->frame_control.current_frame); + combine[0].anm_data_src_idx += combine[0].anm_key_num[combine[0].anm_key_num_idx]; + combine[0].anm_key_num_idx++; } else { - (**joint) = - combine[0].anm_const_val_tbl[combine[0].anm_const_val_tbl_idx]; + combine[0].anm_const_val_tbl_idx++; } - - break; - case 1: - if (*combine[1].anm_check_bit_tbl & *flag) { - (**joint) = - cKF_KeyCalc(combine[1].anm_data_src_idx, - combine[1].anm_key_num[combine[1].anm_key_num_idx], - combine[1].anm_data_src, - combine[1].keyframe->frame_control.current_frame); + combine[1].anm_data_src_idx += combine[1].anm_key_num[combine[1].anm_key_num_idx]; + combine[1].anm_key_num_idx++; } else { - (**joint) = - combine[1].anm_const_val_tbl[combine[1].anm_const_val_tbl_idx]; + combine[1].anm_const_val_tbl_idx++; } - - break; - case 2: - if (*combine[2].anm_check_bit_tbl & *flag) { - (**joint) = - cKF_KeyCalc(combine[2].anm_data_src_idx, - combine[2].anm_key_num[combine[2].anm_key_num_idx], - combine[2].anm_data_src, - combine[2].keyframe->frame_control.current_frame); + combine[2].anm_data_src_idx += combine[2].anm_key_num[combine[2].anm_key_num_idx]; + combine[2].anm_key_num_idx++; } else { - (**joint) = - combine[2].anm_const_val_tbl[combine[2].anm_const_val_tbl_idx]; + combine[2].anm_const_val_tbl_idx++; } - break; + *flag = (u32)*flag >> 1; + *joint += 1; } - - if (*combine[0].anm_check_bit_tbl & *flag) { - combine[0].anm_data_src_idx += - combine[0].anm_key_num[combine[0].anm_key_num_idx]; - combine[0].anm_key_num_idx++; - } else { - combine[0].anm_const_val_tbl_idx++; - } - if (*combine[1].anm_check_bit_tbl & *flag) { - combine[1].anm_data_src_idx += - combine[1].anm_key_num[combine[1].anm_key_num_idx]; - combine[1].anm_key_num_idx++; - } else { - combine[1].anm_const_val_tbl_idx++; - } - if (*combine[2].anm_check_bit_tbl & *flag) { - combine[2].anm_data_src_idx += - combine[2].anm_key_num[combine[2].anm_key_num_idx]; - combine[2].anm_key_num_idx++; - } else { - combine[2].anm_const_val_tbl_idx++; - } - - *flag = (u32)*flag >> 1; - *joint += 1; - } -} -extern void cKF_SkeletonInfo_R_combine_rotation( - s16** joint, int* flag, cKF_SkeletonInfo_R_combine_work_c* combine, - s8* cwork_num) { - int i = 0; - int j; - s16* temp; - f32 calc_joint; - - for (i; i < combine->keyframe->skeleton->num_joints; i++) { - *flag = 4; - - for (j = 0; j < 3; j++) { - switch (cwork_num[i + 1]) { - case 0: - if (*flag & combine[0].anm_check_bit_tbl[i]) { - (**joint) = - cKF_KeyCalc(combine[0].anm_data_src_idx, - combine[0].anm_key_num[combine[0].anm_key_num_idx], - combine[0].anm_data_src, - combine[0].keyframe->frame_control.current_frame); - } else { - (**joint) = - combine[0].anm_const_val_tbl[combine[0].anm_const_val_tbl_idx]; - } - break; - - case 1: - if (*flag & combine[1].anm_check_bit_tbl[i]) { - (**joint) = - cKF_KeyCalc(combine[1].anm_data_src_idx, - combine[1].anm_key_num[combine[1].anm_key_num_idx], - combine[1].anm_data_src, - combine[1].keyframe->frame_control.current_frame); - } else { - (**joint) = - combine[1].anm_const_val_tbl[combine[1].anm_const_val_tbl_idx]; - } - break; - - case 2: - if (*flag & combine[2].anm_check_bit_tbl[i]) { - (**joint) = - cKF_KeyCalc(combine[2].anm_data_src_idx, - combine[2].anm_key_num[combine[2].anm_key_num_idx], - combine[2].anm_data_src, - combine[2].keyframe->frame_control.current_frame); - } else { - (**joint) = - combine[2].anm_const_val_tbl[combine[2].anm_const_val_tbl_idx]; - } - break; - } - if (*flag & combine[0].anm_check_bit_tbl[i]) { - combine[0].anm_data_src_idx += - combine[0].anm_key_num[combine[0].anm_key_num_idx]; - combine[0].anm_key_num_idx++; - } else { - combine[0].anm_const_val_tbl_idx++; - } - if (*flag & combine[1].anm_check_bit_tbl[i]) { - combine[1].anm_data_src_idx += - combine[1].anm_key_num[combine[1].anm_key_num_idx]; - combine[1].anm_key_num_idx++; - } else { - combine[1].anm_const_val_tbl_idx++; - } - if (*flag & combine[2].anm_check_bit_tbl[i]) { - combine[2].anm_data_src_idx += - combine[2].anm_key_num[combine[2].anm_key_num_idx]; - combine[2].anm_key_num_idx++; - } else { - combine[2].anm_const_val_tbl_idx++; - } - - temp = *joint; - calc_joint = 0.1f * (*temp); - **joint = (s16)(int)((calc_joint - - ((f32)(int)(calc_joint * 0.0027777778f) * 360.0f)) * - 182.04445f); - - *flag = (u32)*flag >> 1; - *joint += 1; - } - } } -extern int cKF_SkeletonInfo_R_combine_play(cKF_SkeletonInfo_R_c* info1, - cKF_SkeletonInfo_R_c* info2, - s8* flag) { - int combinet; - s16* joint; +extern void cKF_SkeletonInfo_R_combine_rotation(s16** joint, int* flag, cKF_SkeletonInfo_R_combine_work_c* combine, + s8* cwork_num) { + int i = 0; + int j; + s16* temp; + f32 calc_joint; - cKF_SkeletonInfo_R_combine_work_c combine1; - cKF_SkeletonInfo_R_combine_work_c combine2; - cKF_SkeletonInfo_R_combine_work_c combine3; + for (i; i < combine->keyframe->skeleton->num_joints; i++) { + *flag = 4; - int i; - int j; + for (j = 0; j < 3; j++) { + switch (cwork_num[i + 1]) { + case 0: + if (*flag & combine[0].anm_check_bit_tbl[i]) { + (**joint) = + cKF_KeyCalc(combine[0].anm_data_src_idx, combine[0].anm_key_num[combine[0].anm_key_num_idx], + combine[0].anm_data_src, combine[0].keyframe->frame_control.current_frame); + } else { + (**joint) = combine[0].anm_const_val_tbl[combine[0].anm_const_val_tbl_idx]; + } + break; - s_xyz* joint2; - s_xyz* applyjoint; + case 1: + if (*flag & combine[1].anm_check_bit_tbl[i]) { + (**joint) = + cKF_KeyCalc(combine[1].anm_data_src_idx, combine[1].anm_key_num[combine[1].anm_key_num_idx], + combine[1].anm_data_src, combine[1].keyframe->frame_control.current_frame); + } else { + (**joint) = combine[1].anm_const_val_tbl[combine[1].anm_const_val_tbl_idx]; + } + break; - if ((info1 == NULL) || (info2 == NULL) || (flag == NULL)) { - return 0; - } - joint = (F32_IS_ZERO(info1->morph_counter)) ? &info1->current_joint->x - : &info1->target_joint->x; + case 2: + if (*flag & combine[2].anm_check_bit_tbl[i]) { + (**joint) = + cKF_KeyCalc(combine[2].anm_data_src_idx, combine[2].anm_key_num[combine[2].anm_key_num_idx], + combine[2].anm_data_src, combine[2].keyframe->frame_control.current_frame); + } else { + (**joint) = combine[2].anm_const_val_tbl[combine[2].anm_const_val_tbl_idx]; + } + break; + } + if (*flag & combine[0].anm_check_bit_tbl[i]) { + combine[0].anm_data_src_idx += combine[0].anm_key_num[combine[0].anm_key_num_idx]; + combine[0].anm_key_num_idx++; + } else { + combine[0].anm_const_val_tbl_idx++; + } + if (*flag & combine[1].anm_check_bit_tbl[i]) { + combine[1].anm_data_src_idx += combine[1].anm_key_num[combine[1].anm_key_num_idx]; + combine[1].anm_key_num_idx++; + } else { + combine[1].anm_const_val_tbl_idx++; + } + if (*flag & combine[2].anm_check_bit_tbl[i]) { + combine[2].anm_data_src_idx += combine[2].anm_key_num[combine[2].anm_key_num_idx]; + combine[2].anm_key_num_idx++; + } else { + combine[2].anm_const_val_tbl_idx++; + } - if (info1 != NULL) { - cKF_SkeletonInfo_R_combine_work_set(&combine3, info1); - } - if (info2 != NULL) { - cKF_SkeletonInfo_R_combine_work_set(&combine2, info2); - cKF_SkeletonInfo_R_combine_work_set(&combine1, info2); - } - combinet = 0x20; - cKF_SkeletonInfo_R_combine_translation(&joint, &combinet, &combine3, flag); - cKF_SkeletonInfo_R_combine_rotation(&joint, &combinet, &combine3, flag); + temp = *joint; + calc_joint = 0.1f * (*temp); + **joint = (s16)(int)((calc_joint - ((f32)(int)(calc_joint * 0.0027777778f) * 360.0f)) * 182.04445f); - if (info1->rotation_diff_table != NULL) { - applyjoint = (F32_IS_ZERO(info1->morph_counter)) ? info1->current_joint - : info1->target_joint; - - applyjoint += 1; - for (i = 0, j = 0; i < info1->skeleton->num_joints; i++, j++) { - applyjoint->x += info1->rotation_diff_table[j].x; - applyjoint->y += info1->rotation_diff_table[j].y; - applyjoint->z += info1->rotation_diff_table[j].z; - - applyjoint++; + *flag = (u32)*flag >> 1; + *joint += 1; + } + } +} + +extern int cKF_SkeletonInfo_R_combine_play(cKF_SkeletonInfo_R_c* info1, cKF_SkeletonInfo_R_c* info2, s8* flag) { + int combinet; + s16* joint; + + cKF_SkeletonInfo_R_combine_work_c combine1; + cKF_SkeletonInfo_R_combine_work_c combine2; + cKF_SkeletonInfo_R_combine_work_c combine3; + + int i; + int j; + + s_xyz* joint2; + s_xyz* applyjoint; + + if ((info1 == NULL) || (info2 == NULL) || (flag == NULL)) { + return 0; + } + joint = (F32_IS_ZERO(info1->morph_counter)) ? &info1->current_joint->x : &info1->target_joint->x; + + if (info1 != NULL) { + cKF_SkeletonInfo_R_combine_work_set(&combine3, info1); + } + if (info2 != NULL) { + cKF_SkeletonInfo_R_combine_work_set(&combine2, info2); + cKF_SkeletonInfo_R_combine_work_set(&combine1, info2); + } + combinet = 0x20; + cKF_SkeletonInfo_R_combine_translation(&joint, &combinet, &combine3, flag); + cKF_SkeletonInfo_R_combine_rotation(&joint, &combinet, &combine3, flag); + + if (info1->rotation_diff_table != NULL) { + applyjoint = (F32_IS_ZERO(info1->morph_counter)) ? info1->current_joint : info1->target_joint; + + applyjoint += 1; + for (i = 0, j = 0; i < info1->skeleton->num_joints; i++, j++) { + applyjoint->x += info1->rotation_diff_table[j].x; + applyjoint->y += info1->rotation_diff_table[j].y; + applyjoint->z += info1->rotation_diff_table[j].z; + + applyjoint++; + } + } + if (F32_IS_ZERO(info1->morph_counter)) { + cKF_FrameControl_play(&info2->frame_control); + return cKF_FrameControl_play(&info1->frame_control); + } + if (info1->morph_counter > 0.0f) { + cKF_SkeletonInfo_R_morphJoint(info1); + info1->morph_counter -= 0.5f; + if (info1->morph_counter <= 0.0f) { + info1->morph_counter = 0.0f; + } + return 0; + } + cKF_SkeletonInfo_R_morphJoint(info1); + info1->morph_counter += 0.5f; + if (info1->morph_counter >= 0.0f) { + info1->morph_counter = 0.0f; } - } - if (F32_IS_ZERO(info1->morph_counter)) { cKF_FrameControl_play(&info2->frame_control); return cKF_FrameControl_play(&info1->frame_control); - } - if (info1->morph_counter > 0.0f) { - cKF_SkeletonInfo_R_morphJoint(info1); - info1->morph_counter -= 0.5f; - if (info1->morph_counter <= 0.0f) { - info1->morph_counter = 0.0f; - } - return 0; - } - cKF_SkeletonInfo_R_morphJoint(info1); - info1->morph_counter += 0.5f; - if (info1->morph_counter >= 0.0f) { - info1->morph_counter = 0.0f; - } - cKF_FrameControl_play(&info2->frame_control); - return cKF_FrameControl_play(&info1->frame_control); } -extern void cKF_SkeletonInfo_R_T_combine_play(int* arg1, int* arg2, int* arg3, - cKF_SkeletonInfo_R_c* info1, - cKF_SkeletonInfo_R_c* info2, - cKF_SkeletonInfo_R_c* info3, - s8* flag) { - int combinet; - s16* joint; +extern void cKF_SkeletonInfo_R_T_combine_play(int* arg1, int* arg2, int* arg3, cKF_SkeletonInfo_R_c* info1, + cKF_SkeletonInfo_R_c* info2, cKF_SkeletonInfo_R_c* info3, s8* flag) { + int combinet; + s16* joint; - cKF_SkeletonInfo_R_combine_work_c combine1; - cKF_SkeletonInfo_R_combine_work_c combine2; - cKF_SkeletonInfo_R_combine_work_c combine3; - int i; - int j; + cKF_SkeletonInfo_R_combine_work_c combine1; + cKF_SkeletonInfo_R_combine_work_c combine2; + cKF_SkeletonInfo_R_combine_work_c combine3; + int i; + int j; - s_xyz* joint2; - s_xyz* applyjoint; + s_xyz* joint2; + s_xyz* applyjoint; - if ((info1 == NULL) || (info2 == NULL) || (info3 == NULL) || (flag == NULL)) { - return; - } - - joint = (F32_IS_ZERO(info1->morph_counter)) ? &info1->current_joint->x - : &info1->target_joint->x; - - if (info1 != NULL) { - cKF_SkeletonInfo_R_combine_work_set(&combine3, info1); - } - if (info2 != NULL) { - cKF_SkeletonInfo_R_combine_work_set(&combine2, info2); - } - if (info3 != NULL) { - cKF_SkeletonInfo_R_combine_work_set(&combine1, info3); - } - - combinet = 0x20; - cKF_SkeletonInfo_R_combine_translation(&joint, &combinet, &combine3, flag); - cKF_SkeletonInfo_R_combine_rotation(&joint, &combinet, &combine3, flag); - - if (info1->rotation_diff_table != NULL) { - applyjoint = (F32_IS_ZERO(info1->morph_counter)) ? info1->current_joint - : info1->target_joint; - - applyjoint += 1; - for (i = 0, j = 0; i < info1->skeleton->num_joints; i++, j++) { - applyjoint->x += info1->rotation_diff_table[j].x; - applyjoint->y += info1->rotation_diff_table[j].y; - applyjoint->z += info1->rotation_diff_table[j].z; - - applyjoint++; + if ((info1 == NULL) || (info2 == NULL) || (info3 == NULL) || (flag == NULL)) { + return; + } + + joint = (F32_IS_ZERO(info1->morph_counter)) ? &info1->current_joint->x : &info1->target_joint->x; + + if (info1 != NULL) { + cKF_SkeletonInfo_R_combine_work_set(&combine3, info1); + } + if (info2 != NULL) { + cKF_SkeletonInfo_R_combine_work_set(&combine2, info2); + } + if (info3 != NULL) { + cKF_SkeletonInfo_R_combine_work_set(&combine1, info3); + } + + combinet = 0x20; + cKF_SkeletonInfo_R_combine_translation(&joint, &combinet, &combine3, flag); + cKF_SkeletonInfo_R_combine_rotation(&joint, &combinet, &combine3, flag); + + if (info1->rotation_diff_table != NULL) { + applyjoint = (F32_IS_ZERO(info1->morph_counter)) ? info1->current_joint : info1->target_joint; + + applyjoint += 1; + for (i = 0, j = 0; i < info1->skeleton->num_joints; i++, j++) { + applyjoint->x += info1->rotation_diff_table[j].x; + applyjoint->y += info1->rotation_diff_table[j].y; + applyjoint->z += info1->rotation_diff_table[j].z; + + applyjoint++; + } + } + if (F32_IS_ZERO(info1->morph_counter)) { + *arg1 = cKF_FrameControl_play(&info1->frame_control); + *arg2 = cKF_FrameControl_play(&info2->frame_control); + *arg3 = cKF_FrameControl_play(&info3->frame_control); + return; + } + if (info1->morph_counter > 0.0f) { + cKF_SkeletonInfo_R_morphJoint(info1); + info1->morph_counter -= 0.5f; + if (info1->morph_counter <= 0.0f) { + info1->morph_counter = 0.0f; + } + *arg1 = 0; + *arg2 = 0; + *arg3 = 0; + return; + } + cKF_SkeletonInfo_R_morphJoint(info1); + info1->morph_counter += 0.5f; + if (info1->morph_counter >= 0.0f) { + info1->morph_counter = 0.0f; } - } - if (F32_IS_ZERO(info1->morph_counter)) { *arg1 = cKF_FrameControl_play(&info1->frame_control); *arg2 = cKF_FrameControl_play(&info2->frame_control); *arg3 = cKF_FrameControl_play(&info3->frame_control); - return; - } - if (info1->morph_counter > 0.0f) { - cKF_SkeletonInfo_R_morphJoint(info1); - info1->morph_counter -= 0.5f; - if (info1->morph_counter <= 0.0f) { - info1->morph_counter = 0.0f; - } - *arg1 = 0; - *arg2 = 0; - *arg3 = 0; - return; - } - cKF_SkeletonInfo_R_morphJoint(info1); - info1->morph_counter += 0.5f; - if (info1->morph_counter >= 0.0f) { - info1->morph_counter = 0.0f; - } - *arg1 = cKF_FrameControl_play(&info1->frame_control); - *arg2 = cKF_FrameControl_play(&info2->frame_control); - *arg3 = cKF_FrameControl_play(&info3->frame_control); } -extern void cKF_SkeletonInfo_R_Animation_Set_base_shape_trs( - f32 transx, f32 transy, f32 transz, cKF_SkeletonInfo_R_c* keyframe, - s16 anglex, s16 angley, s16 anglez) { - keyframe->base_model_translation.x = transx; - keyframe->base_model_translation.y = transy; - keyframe->base_model_translation.z = transz; +extern void cKF_SkeletonInfo_R_Animation_Set_base_shape_trs(f32 transx, f32 transy, f32 transz, + cKF_SkeletonInfo_R_c* keyframe, s16 anglex, s16 angley, + s16 anglez) { + keyframe->base_model_translation.x = transx; + keyframe->base_model_translation.y = transy; + keyframe->base_model_translation.z = transz; - keyframe->base_model_rotation.x = anglex; - keyframe->updated_base_model_rotation.x = anglex; + keyframe->base_model_rotation.x = anglex; + keyframe->updated_base_model_rotation.x = anglex; - keyframe->base_model_rotation.y = angley; - keyframe->updated_base_model_rotation.y = angley; + keyframe->base_model_rotation.y = angley; + keyframe->updated_base_model_rotation.y = angley; - keyframe->base_model_rotation.z = anglez; - keyframe->updated_base_model_rotation.z = anglez; + keyframe->base_model_rotation.z = anglez; + keyframe->updated_base_model_rotation.z = anglez; } -extern void cKF_SkeletonInfo_R_AnimationMove_ct_base( - f32 counter, xyz_t* basepos, xyz_t* correctpos, s16 ybase, s16 yidle, - cKF_SkeletonInfo_R_c* keyframe, int an_flag) { - int sub; +extern void cKF_SkeletonInfo_R_AnimationMove_ct_base(f32 counter, xyz_t* basepos, xyz_t* correctpos, s16 ybase, + s16 yidle, cKF_SkeletonInfo_R_c* keyframe, int an_flag) { + int sub; - keyframe->animation_enabled = an_flag; + keyframe->animation_enabled = an_flag; - keyframe->fixed_counter = (counter >= 0.0f) ? counter : -counter; + keyframe->fixed_counter = (counter >= 0.0f) ? counter : -counter; - keyframe->base_world_position = ZeroVec; - keyframe->model_world_position_correction = ZeroVec; + keyframe->base_world_position = ZeroVec; + keyframe->model_world_position_correction = ZeroVec; - if (basepos != NULL) { - if (correctpos == NULL) { - correctpos = basepos; - } - if (an_flag & 1) { - keyframe->base_world_position.x = correctpos->x; - keyframe->base_world_position.z = correctpos->z; - keyframe->model_world_position_correction.x = basepos->x - correctpos->x; - keyframe->model_world_position_correction.z = basepos->z - correctpos->z; - } - if (an_flag & 2) { - keyframe->base_world_position.y = correctpos->y; - keyframe->model_world_position_correction.y = basepos->y - correctpos->y; - } - } - keyframe->base_angle_y = yidle; - keyframe->model_angle_correction = 0; - - if (an_flag & 4) { - sub = ybase - yidle; - if (sub > 0x8000) { - sub = -(0x10000 - sub); - } else if (sub < -0x8000) { - sub += 0x10000; + if (basepos != NULL) { + if (correctpos == NULL) { + correctpos = basepos; + } + if (an_flag & cKF_ANIMATION_TRANS_XZ) { + keyframe->base_world_position.x = correctpos->x; + keyframe->base_world_position.z = correctpos->z; + keyframe->model_world_position_correction.x = basepos->x - correctpos->x; + keyframe->model_world_position_correction.z = basepos->z - correctpos->z; + } + if (an_flag & cKF_ANIMATION_TRANS_Y) { + keyframe->base_world_position.y = correctpos->y; + keyframe->model_world_position_correction.y = basepos->y - correctpos->y; + } } keyframe->base_angle_y = yidle; - keyframe->model_angle_correction = sub; - } + keyframe->model_angle_correction = 0; + + if (an_flag & cKF_ANIMATION_ROT_X) { + sub = ybase - yidle; + if (sub > 0x8000) { + sub = -(0x10000 - sub); + } else if (sub < -0x8000) { + sub += 0x10000; + } + keyframe->base_angle_y = yidle; + keyframe->model_angle_correction = sub; + } } -extern void cKF_SkeletonInfo_R_AnimationMove_dt( - cKF_SkeletonInfo_R_c* keyframe) { - int an_flag = keyframe->animation_enabled; - s_xyz* cur_joint = keyframe->current_joint; +extern void cKF_SkeletonInfo_R_AnimationMove_dt(cKF_SkeletonInfo_R_c* keyframe) { + int an_flag = keyframe->animation_enabled; + s_xyz* cur_joint = keyframe->current_joint; - if (an_flag & 1) { - cur_joint->x = keyframe->base_model_translation.x; - cur_joint->z = keyframe->base_model_translation.z; - } - if (an_flag & 2) { - cur_joint->y = keyframe->base_model_translation.y; - } - if (an_flag & 4) { - cur_joint = keyframe->current_joint; - cur_joint[1].x = keyframe->base_model_rotation.x; - cur_joint[1].y = keyframe->base_model_rotation.y; - cur_joint[1].z = keyframe->base_model_rotation.z; - } - keyframe->animation_enabled = 0; + if (an_flag & cKF_ANIMATION_TRANS_XZ) { + cur_joint->x = keyframe->base_model_translation.x; + cur_joint->z = keyframe->base_model_translation.z; + } + if (an_flag & cKF_ANIMATION_TRANS_Y) { + cur_joint->y = keyframe->base_model_translation.y; + } + if (an_flag & cKF_ANIMATION_ROT_X) { + cur_joint = keyframe->current_joint; + cur_joint[1].x = keyframe->base_model_rotation.x; + cur_joint[1].y = keyframe->base_model_rotation.y; + cur_joint[1].z = keyframe->base_model_rotation.z; + } + keyframe->animation_enabled = 0; } -extern void cKF_SkeletonInfo_R_AnimationMove_base( - xyz_t* base, s_xyz* sbase, xyz_t* move, s16 yidle, - cKF_SkeletonInfo_R_c* keyframe) { - f32 fc = keyframe->fixed_counter; - f32 count = 1.0f + fc; - int an_flag = keyframe->animation_enabled; - f32 correct_y; - f32 mangle_y; - s16 angley; - s16 angle_c; - s_xyz* update_base; - s16 base_x; - s_xyz* cur_joint; - s16 sub; - f32 trans_x; - f32 trans_z; - f32 move_x; - f32 move_z; - f32 temp; - f32 sin, cos; +extern void cKF_SkeletonInfo_R_AnimationMove_base(xyz_t* base, s_xyz* sbase, xyz_t* move, s16 yidle, + cKF_SkeletonInfo_R_c* keyframe) { + f32 fc = keyframe->fixed_counter; + f32 count = 1.0f + fc; + int an_flag = keyframe->animation_enabled; + f32 correct_y; + f32 mangle_y; + s16 angley; + s16 angle_c; + s_xyz* update_base; + s16 base_x; + s_xyz* cur_joint; + s16 sub; + f32 trans_x; + f32 trans_z; + f32 move_x; + f32 move_z; + f32 temp; + f32 sin, cos; - if (count > 0.5f) { - correct_y = 0.5f / count; - } else { - correct_y = 0.0f; - } - - if (an_flag & 4) { - mangle_y = keyframe->model_angle_correction; if (count > 0.5f) { - keyframe->model_angle_correction -= (s16)(int)(mangle_y * correct_y); + correct_y = 0.5f / count; } else { - keyframe->model_angle_correction = 0; + correct_y = 0.0f; } - } - if (count > 0.5f) { - if (an_flag & 1) { - f32 cx, cz; - - cx = keyframe->model_world_position_correction.x; - cx *= correct_y; - - cz = keyframe->model_world_position_correction.z; - cz *= correct_y; - - keyframe->model_world_position_correction.x -= cx; - keyframe->model_world_position_correction.z -= cz; + if (an_flag & cKF_ANIMATION_ROT_X) { + mangle_y = keyframe->model_angle_correction; + if (count > 0.5f) { + keyframe->model_angle_correction -= (s16)(int)(mangle_y * correct_y); + } else { + keyframe->model_angle_correction = 0; + } } - if (an_flag & 2) { - f32 cy; - cy = keyframe->model_world_position_correction.y; - cy *= correct_y; + if (count > 0.5f) { + if (an_flag & cKF_ANIMATION_TRANS_XZ) { + f32 cx, cz; - keyframe->model_world_position_correction.y -= cy; + cx = keyframe->model_world_position_correction.x; + cx *= correct_y; + + cz = keyframe->model_world_position_correction.z; + cz *= correct_y; + + keyframe->model_world_position_correction.x -= cx; + keyframe->model_world_position_correction.z -= cz; + } + if (an_flag & cKF_ANIMATION_TRANS_Y) { + f32 cy; + + cy = keyframe->model_world_position_correction.y; + cy *= correct_y; + + keyframe->model_world_position_correction.y -= cy; + } + } else { + keyframe->model_world_position_correction.x = 0.0f; + keyframe->model_world_position_correction.y = 0.0f; + keyframe->model_world_position_correction.z = 0.0f; } - } else { - keyframe->model_world_position_correction.x = 0.0f; - keyframe->model_world_position_correction.y = 0.0f; - keyframe->model_world_position_correction.z = 0.0f; - } - if ((sbase != NULL) && (an_flag & 4)) { - angley = keyframe->base_angle_y; - angle_c = keyframe->model_angle_correction; - base_x = keyframe->base_model_rotation.x; - update_base = &keyframe->updated_base_model_rotation; - Matrix_push(); - Matrix_rotateXYZ(keyframe->current_joint[1].x, keyframe->current_joint[1].y, - keyframe->current_joint[1].z, 0); - Matrix_to_rotate2_new(get_Matrix_now(), update_base, 0); - Matrix_pull(); - sbase->x = angley + angle_c + (update_base->x - base_x); - } - if (base != NULL) { - cur_joint = keyframe->current_joint; - sub = 0; - if (sbase != NULL) { - sub = sbase->x - yidle; + if ((sbase != NULL) && (an_flag & cKF_ANIMATION_ROT_X)) { + angley = keyframe->base_angle_y; + angle_c = keyframe->model_angle_correction; + base_x = keyframe->base_model_rotation.x; + update_base = &keyframe->updated_base_model_rotation; + Matrix_push(); + Matrix_rotateXYZ(keyframe->current_joint[1].x, keyframe->current_joint[1].y, keyframe->current_joint[1].z, 0); + Matrix_to_rotate2_new(get_Matrix_now(), update_base, 0); + Matrix_pull(); + sbase->x = angley + angle_c + (update_base->x - base_x); } - if (an_flag & 1) { - f32 move_x, move_z; - f32 base_x, base_z; - f32 temp2; - f32 temp1; - trans_x = keyframe->base_model_translation.x; - trans_z = keyframe->base_model_translation.z; + if (base != NULL) { + cur_joint = keyframe->current_joint; + sub = 0; + if (sbase != NULL) { + sub = sbase->x - yidle; + } + if (an_flag & cKF_ANIMATION_TRANS_XZ) { + f32 move_x, move_z; + f32 base_x, base_z; + f32 temp2; + f32 temp1; - sin = sin_s(sub); - cos = cos_s(sub); + trans_x = keyframe->base_model_translation.x; + trans_z = keyframe->base_model_translation.z; - temp1 = (trans_x * cos) + (trans_z * sin); - move_x = move->x * (cur_joint->x - temp1); - temp1 = (-trans_x * sin) + (trans_z * cos); - move_z = move->z * (cur_joint->z - temp1); + sin = sin_s(sub); + cos = cos_s(sub); - sin = sin_s(yidle); - cos = cos_s(yidle); + temp1 = (trans_x * cos) + (trans_z * sin); + move_x = move->x * (cur_joint->x - temp1); + temp1 = (-trans_x * sin) + (trans_z * cos); + move_z = move->z * (cur_joint->z - temp1); - base_x = keyframe->model_world_position_correction.x; - base_z = keyframe->model_world_position_correction.z; - temp2 = (move_x * cos) + (move_z * sin); - base->x = temp2 + (keyframe->base_world_position.x + base_x); - temp2 = (-move_x * sin) + (move_z * cos); - base->z = temp2 + (keyframe->base_world_position.z + base_z); + sin = sin_s(yidle); + cos = cos_s(yidle); + + base_x = keyframe->model_world_position_correction.x; + base_z = keyframe->model_world_position_correction.z; + temp2 = (move_x * cos) + (move_z * sin); + base->x = temp2 + (keyframe->base_world_position.x + base_x); + temp2 = (-move_x * sin) + (move_z * cos); + base->z = temp2 + (keyframe->base_world_position.z + base_z); + } + if (an_flag & cKF_ANIMATION_TRANS_Y) { + base->y = move->y * (cur_joint->y - keyframe->base_model_translation.y) + + (keyframe->base_world_position.y + keyframe->model_world_position_correction.y); + } } - if (an_flag & 2) { - base->y = move->y * (cur_joint->y - keyframe->base_model_translation.y) + - (keyframe->base_world_position.y + - keyframe->model_world_position_correction.y); + count = fc - 0.5f; + if (count < 0.0f) { + count = 0.0f; } - } - count = fc - 0.5f; - if (count < 0.0f) { - count = 0.0f; - } - keyframe->fixed_counter = count; + keyframe->fixed_counter = count; } -extern void cKF_SkeletonInfo_R_AnimationMove_CulcTransToWorld( - f32 calcx, f32 calcy, f32 calcz, xyz_t* base, xyz_t* calcp, s16 val, - xyz_t* trans, cKF_SkeletonInfo_R_c* keyframe, int animation_flag) { - f32 sin, cos; - f32 j_x, j_z; - s_xyz* cur_joint = keyframe->current_joint; +extern void cKF_SkeletonInfo_R_AnimationMove_CulcTransToWorld(f32 calcx, f32 calcy, f32 calcz, xyz_t* base, + xyz_t* calcp, s16 val, xyz_t* trans, + cKF_SkeletonInfo_R_c* keyframe, int animation_flag) { + f32 sin, cos; + f32 j_x, j_z; + s_xyz* cur_joint = keyframe->current_joint; - if (animation_flag & 1) { - j_x = cur_joint->x - calcx; - j_z = cur_joint->z - calcz; + if (animation_flag & cKF_ANIMATION_TRANS_XZ) { + j_x = cur_joint->x - calcx; + j_z = cur_joint->z - calcz; - sin = sin_s(val); - cos = cos_s(val); + sin = sin_s(val); + cos = cos_s(val); - base->x = calcp->x + trans->x * ((j_x * cos) + (j_z * sin)); - base->z = calcp->z + trans->z * ((-j_x * sin) + (j_z * cos)); - } - if (animation_flag & 2) { - base->y = calcp->y + trans->y * (cur_joint->y - calcy); - } + base->x = calcp->x + trans->x * ((j_x * cos) + (j_z * sin)); + base->z = calcp->z + trans->z * ((-j_x * sin) + (j_z * cos)); + } + + if (animation_flag & cKF_ANIMATION_TRANS_Y) { + base->y = calcp->y + trans->y * (cur_joint->y - calcy); + } } diff --git a/src/data/model/obj_e_boat/obj_e_boat.c b/src/data/model/obj_e_boat/obj_e_boat.c new file mode 100644 index 00000000..0b123c0e --- /dev/null +++ b/src/data/model/obj_e_boat/obj_e_boat.c @@ -0,0 +1,408 @@ +#include "types.h" +#include "c_keyframe.h" +#include "libforest/gbi_extensions.h" + +// TODO: assetrip textures & vertices then link + +static u8 obj_s_boat_t10_tex_txt[128]; +static u8 obj_s_boat_t11_tex_txt[128]; +static u8 obj_s_boat_t9_tex_txt[192]; +static u8 obj_s_boat_t6_tex_txt[256]; +static u8 obj_s_boat_t7_tex_txt[128]; +static u8 obj_s_boat_t1_tex_txt[1024]; +static u8 obj_s_boat_t3_tex_txt[1024]; +static u8 obj_s_boat_t2_tex_txt[128]; +static u8 obj_s_boat_t5_tex_txt[128]; +static u8 obj_s_boat_t8_tex_txt[128]; +static u8 obj_s_boat_t4_tex_txt[128]; + +static u8 obj_s_boat_water1_pic_i4[512]; +static u8 obj_s_boat_water2_pic_i4[256]; + +static Vtx obj_e_boat_v[156]; + +static Gfx obj_e_boat_boat1_model[] = { + gsSPTexture(0, 0, 0, 0, G_ON), + gsDPSetCombineLERP(TEXEL0, 0, SHADE, 0, 0, 0, 0, TEXEL0, PRIMITIVE, 0, COMBINED, 0, 0, 0, 0, COMBINED), + gsDPSetRenderMode(G_RM_FOG_SHADE_A, G_RM_AA_ZB_TEX_EDGE2), + gsDPLoadTextureBlock_4b_Dolphin(obj_s_boat_t6_tex_txt, G_IM_FMT_CI, 16, 32, 15, GX_REPEAT, GX_REPEAT, 0, 0), + gsDPSetPrimColor(0, 128, 255, 255, 255, 255), + gsSPLoadGeometryMode(G_ZBUFFER | G_SHADE | G_CULL_BACK | G_FOG | G_LIGHTING | G_SHADING_SMOOTH), + gsSPVertex(&obj_e_boat_v[30], 30, 0), + gsSPNTrianglesInit_5b( + 4, // tri count + 0, 1, 2, // tri0 + 0, 2, 3, // tri1 + 4, 5, 6 // tri2 + ), + gsSPNTriangles_5b( + 4, 6, 7, // tri0 + 0, 0, 0, // tri1 + 0, 0, 0, // tri2 + 0, 0, 0 // tri3 + ), + gsDPLoadTextureBlock_4b_Dolphin(obj_s_boat_t7_tex_txt, G_IM_FMT_CI, 16, 16, 15, GX_REPEAT, GX_REPEAT, 0, 0), + gsSPNTrianglesInit_5b( + 2, // tri count + 8, 9, 10, // tri0 + 8, 10, 11, // tri1 + 0, 0, 0 // tri2 + ), + gsSPLoadGeometryMode(G_ZBUFFER | G_SHADE | G_FOG | G_LIGHTING | G_SHADING_SMOOTH), + gsSPNTrianglesInit_5b( + 2, // tri count + 12, 13, 14, // tri0 + 12, 14, 15, // tri1 + 0, 0, 0 // tri2 + ), + gsDPLoadTextureBlock_4b_Dolphin(obj_s_boat_t1_tex_txt, G_IM_FMT_CI, 32, 64, 15, GX_REPEAT, GX_REPEAT, 0, 0), + gsSPLoadGeometryMode(G_ZBUFFER | G_SHADE | G_CULL_BACK | G_FOG | G_LIGHTING | G_SHADING_SMOOTH), + gsSPNTrianglesInit_5b( + 5, // tri count + 16, 17, 18, // tri0 + 16, 18, 19, // tri1 + 16, 20, 21 // tri2 + ), + gsSPNTriangles_5b( + 16, 21, 17, // tri0 + 20, 22, 21, // tri1 + 0, 0, 0, // tri2 + 0, 0, 0 // tri3 + ), + gsDPLoadTextureBlock_4b_Dolphin(obj_s_boat_t3_tex_txt, G_IM_FMT_CI, 32, 64, 15, GX_REPEAT, GX_REPEAT, 0, 0), + gsSPNTrianglesInit_5b( + 5, // tri count + 23, 24, 25, // tri0 + 23, 25, 26, // tri1 + 23, 27, 24 // tri2 + ), + gsSPNTriangles_5b( + 26, 25, 28, // tri0 + 26, 28, 29, // tri1 + 0, 0, 0, // tri2 + 0, 0, 0 // tri3 + ), + gsDPLoadTextureBlock_4b_Dolphin(obj_s_boat_t2_tex_txt, G_IM_FMT_CI, 16, 16, 15, GX_CLAMP, GX_CLAMP, 0, 0), + gsSPLoadGeometryMode(G_ZBUFFER | G_SHADE | G_FOG | G_LIGHTING | G_SHADING_SMOOTH), + gsSPVertex(&obj_e_boat_v[60], 31, 0), + gsSPNTrianglesInit_5b( + 8, // tri count + 0, 1, 2, // tri0 + 0, 2, 3, // tri1 + 4, 5, 6 // tri2 + ), + gsSPNTriangles_5b( + 4, 6, 7, // tri0 + 8, 9, 10, // tri1 + 8, 10, 11, // tri2 + 12, 13, 14 // tri3 + ), + gsSPNTriangles_5b( + 12, 14, 15, // tri0 + 0, 0, 0, // tri1 + 0, 0, 0, // tri2 + 0, 0, 0 // tri3 + ), + gsDPLoadTextureBlock_4b_Dolphin(obj_s_boat_t5_tex_txt, G_IM_FMT_CI, 16, 16, 15, GX_CLAMP, GX_CLAMP, 0, 0), + gsSPNTrianglesInit_5b( + 4, // tri count + 16, 17, 18, // tri0 + 16, 18, 19, // tri1 + 20, 21, 22 // tri2 + ), + gsSPNTriangles_5b( + 20, 22, 16, // tri0 + 0, 0, 0, // tri1 + 0, 0, 0, // tri2 + 0, 0, 0 // tri3 + ), + gsDPLoadTextureBlock_4b_Dolphin(obj_s_boat_t8_tex_txt, G_IM_FMT_CI, 16, 16, 15, GX_REPEAT, GX_REPEAT, 0, 0), + gsSPLoadGeometryMode(G_ZBUFFER | G_SHADE | G_CULL_BACK | G_FOG | G_LIGHTING | G_SHADING_SMOOTH), + gsSPNTrianglesInit_5b( + 2, // tri count + 23, 24, 25, // tri0 + 23, 25, 26, // tri1 + 0, 0, 0 // tri2 + ), + gsDPLoadTextureBlock_4b_Dolphin(obj_s_boat_t4_tex_txt, G_IM_FMT_CI, 16, 16, 15, GX_CLAMP, GX_CLAMP, 0, 0), + gsSPLoadGeometryMode(G_ZBUFFER | G_SHADE | G_FOG | G_LIGHTING | G_SHADING_SMOOTH), + gsSPNTrianglesInit_5b( + 2, // tri count + 27, 28, 29, // tri0 + 27, 29, 30, // tri1 + 0, 0, 0 // tri2 + ), + gsDPLoadTextureBlock_4b_Dolphin(obj_s_boat_t3_tex_txt, G_IM_FMT_CI, 32, 64, 15, GX_REPEAT, GX_REPEAT, 0, 0), + gsSPVertex(&obj_e_boat_v[91], 7, 0), + gsSPNTrianglesInit_5b( + 5, // tri count + 0, 1, 2, // tri0 + 0, 3, 1, // tri1 + 4, 5, 6 // tri2 + ), + gsSPNTriangles_5b( + 4, 3, 0, // tri0 + 4, 6, 3, // tri1 + 0, 0, 0, // tri2 + 0, 0, 0 // tri3 + ), + gsSPEndDisplayList(), +}; + +static Gfx obj_e_boat_water1_model[] = { + gsSPTexture(0, 0, 0, 0, G_ON), + gsDPSetCombineLERP(PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, ENVIRONMENT, 0, 0, 0, 0, COMBINED, COMBINED, 0, TEXEL0, 0), + gsDPSetPrimColor(0, 255, 190, 210, 255, 230), + gsDPSetRenderMode(G_RM_FOG_SHADE_A, G_RM_ZB_XLU_SURF2), + gsDPLoadTextureBlock_4b_Dolphin(obj_s_boat_water2_pic_i4, G_IM_FMT_I, 32, 32, 15, GX_REPEAT, GX_REPEAT, 0, 0), + gsDPLoadTextureBlock_4b_Dolphin(obj_s_boat_water1_pic_i4, G_IM_FMT_I, 32, 32, 15, GX_REPEAT, GX_REPEAT, 0, 14), + gsSPDisplayList(0x09000000), + gsSPLoadGeometryMode(G_ZBUFFER | G_SHADE | G_CULL_BACK | G_FOG | G_LIGHTING | G_SHADING_SMOOTH), + gsSPVertex(&obj_e_boat_v[142], 14, 0), + gsSPNTrianglesInit_5b( + 14, // tri count + 0, 1, 2, // tri0 + 2, 1, 3, // tri1 + 4, 5, 6 // tri2 + ), + gsSPNTriangles_5b( + 2, 7, 8, // tri0 + 2, 9, 0, // tri1 + 10, 11, 12, // tri2 + 8, 9, 2 // tri3 + ), + gsSPNTriangles_5b( + 3, 7, 2, // tri0 + 8, 13, 10, // tri1 + 6, 13, 8, // tri2 + 8, 12, 9 // tri3 + ), + gsSPNTriangles_5b( + 10, 12, 8, // tri0 + 8, 4, 6, // tri1 + 7, 4, 8, // tri2 + 0, 0, 0 // tri3 + ), + gsSPEndDisplayList(), +}; + +static Gfx obj_e_boat_water2_model[] = { + gsSPTexture(0, 0, 0, 0, G_ON), + gsDPSetCombineLERP(PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, ENVIRONMENT, 0, 0, 0, 0, COMBINED, COMBINED, 0, TEXEL0, 0), + gsDPSetPrimColor(0, 255, 190, 210, 255, 230), + gsDPSetRenderMode(G_RM_FOG_SHADE_A, G_RM_ZB_XLU_SURF2), + gsDPLoadTextureBlock_4b_Dolphin(obj_s_boat_water2_pic_i4, G_IM_FMT_I, 32, 32, 15, GX_REPEAT, GX_REPEAT, 0, 0), + gsDPLoadTextureBlock_4b_Dolphin(obj_s_boat_water1_pic_i4, G_IM_FMT_I, 32, 32, 15, GX_REPEAT, GX_REPEAT, 0, 14), + gsSPDisplayList(0x09000000), + gsSPMatrix(0x0D000080, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW), + gsSPLoadGeometryMode(G_ZBUFFER | G_SHADE | G_CULL_BACK | G_FOG | G_LIGHTING | G_SHADING_SMOOTH), + gsSPVertex(&obj_e_boat_v[125], 5, 0), + gsSPMatrix(0x0D0000C0, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW), + gsSPVertex(&obj_e_boat_v[130], 12, 5), + gsSPNTrianglesInit_5b( + 8, // tri count + 1, 5, 6, // tri0 + 3, 7, 8, // tri1 + 0, 4, 9 // tri2 + ), + gsSPNTriangles_5b( + 4, 10, 11, // tri0 + 0, 12, 13, // tri1 + 4, 2, 14, // tri2 + 3, 1, 15 // tri3 + ), + gsSPNTriangles_5b( + 2, 3, 16, // tri0 + 0, 0, 0, // tri1 + 0, 0, 0, // tri2 + 0, 0, 0 // tri3 + ), + gsSPEndDisplayList(), +}; + +static Gfx obj_e_boat_water3_model[] = { + gsSPTexture(0, 0, 0, 0, G_ON), + gsDPSetCombineLERP(PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, ENVIRONMENT, 0, 0, 0, 0, COMBINED, COMBINED, 0, TEXEL0, 0), + gsDPSetPrimColor(0, 255, 190, 210, 255, 230), + gsDPSetRenderMode(G_RM_FOG_SHADE_A, G_RM_ZB_XLU_SURF2), + gsDPLoadTextureBlock_4b_Dolphin(obj_s_boat_water2_pic_i4, G_IM_FMT_I, 32, 32, 15, GX_REPEAT, GX_REPEAT, 0, 0), + gsDPLoadTextureBlock_4b_Dolphin(obj_s_boat_water1_pic_i4, G_IM_FMT_I, 32, 32, 15, GX_REPEAT, GX_REPEAT, 0, 14), + gsSPDisplayList(0x09000000), + gsSPMatrix(0x0D0000C0, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW), + gsSPLoadGeometryMode(G_ZBUFFER | G_SHADE | G_CULL_BACK | G_FOG | G_LIGHTING | G_SHADING_SMOOTH), + gsSPVertex(&obj_e_boat_v[98], 5, 0), + gsSPMatrix(0x0D000100, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW), + gsSPVertex(&obj_e_boat_v[103], 22, 5), + gsSPNTrianglesInit_5b( + 8, // tri count + 0, 1, 5, // tri0 + 0, 6, 7, // tri1 + 1, 2, 8 // tri2 + ), + gsSPNTriangles_5b( + 2, 3, 9, // tri0 + 3, 4, 10, // tri1 + 4, 11, 12, // tri2 + 3, 13, 14 // tri3 + ), + gsSPNTriangles_5b( + 1, 15, 16, // tri0 + 0, 0, 0, // tri1 + 0, 0, 0, // tri2 + 0, 0, 0 // tri3 + ), + gsSPNTrianglesInit_5b( + 8, // tri count + 17, 18, 19, // tri0 + 20, 21, 22, // tri1 + 19, 23, 24 // tri2 + ), + gsSPNTriangles_5b( + 20, 22, 25, // tri0 + 23, 26, 24, // tri1 + 25, 26, 23, // tri2 + 25, 23, 20 // tri3 + ), + gsSPNTriangles_5b( + 24, 17, 19, // tri0 + 0, 0, 0, // tri1 + 0, 0, 0, // tri2 + 0, 0, 0 // tri3 + ), + gsSPEndDisplayList(), +}; + +static Gfx obj_e_boat_oar1_model[] = { + gsSPTexture(0, 0, 0, 0, G_ON), + gsDPSetCombineLERP(TEXEL0, 0, SHADE, 0, 0, 0, 0, TEXEL0, PRIMITIVE, 0, COMBINED, 0, 0, 0, 0, COMBINED), + gsDPSetRenderMode(G_RM_FOG_SHADE_A, G_RM_AA_ZB_TEX_EDGE2), + gsDPLoadTextureBlock_4b_Dolphin(obj_s_boat_t10_tex_txt, G_IM_FMT_CI, 16, 16, 15, GX_MIRROR, GX_MIRROR, 0, 0), + gsDPSetPrimColor(0, 128, 255, 255, 255, 255), + gsSPLoadGeometryMode(G_ZBUFFER | G_SHADE | G_CULL_BACK | G_FOG | G_LIGHTING | G_SHADING_SMOOTH), + gsSPVertex(&obj_e_boat_v[0], 30, 0), + gsSPNTrianglesInit_5b( + 2, // tri count + 0, 1, 2, // tri0 + 3, 4, 5, // tri1 + 0, 0, 0 // tri2 + ), + gsDPLoadTextureBlock_4b_Dolphin(obj_s_boat_t11_tex_txt, G_IM_FMT_CI, 16, 16, 15, GX_MIRROR, GX_MIRROR, 0, 0), + gsSPNTrianglesInit_5b( + 6, // tri count + 6, 7, 8, // tri0 + 6, 8, 9, // tri1 + 10, 11, 12 // tri2 + ), + gsSPNTriangles_5b( + 10, 12, 13, // tri0 + 14, 15, 16, // tri1 + 14, 16, 17, // tri2 + 0, 0, 0 // tri3 + ), + gsDPLoadTextureBlock_4b_Dolphin(obj_s_boat_t9_tex_txt, G_IM_FMT_CI, 48, 8, 15, GX_CLAMP, GX_MIRROR, 0, 0), + gsSPLoadGeometryMode(G_ZBUFFER | G_SHADE | G_FOG | G_LIGHTING | G_SHADING_SMOOTH), + gsSPNTrianglesInit_5b( + 4, // tri count + 18, 19, 20, // tri0 + 21, 18, 20, // tri1 + 22, 23, 24 // tri2 + ), + gsSPNTriangles_5b( + 25, 22, 24, // tri0 + 0, 0, 0, // tri1 + 0, 0, 0, // tri2 + 0, 0, 0 // tri3 + ), + gsDPLoadTextureBlock_4b_Dolphin(obj_s_boat_t9_tex_txt, G_IM_FMT_CI, 48, 8, 15, GX_CLAMP, GX_CLAMP, 0, 0), + gsSPLoadGeometryMode(G_ZBUFFER | G_SHADE | G_CULL_BACK | G_FOG | G_LIGHTING | G_SHADING_SMOOTH), + gsSPNTrianglesInit_5b( + 2, // tri count + 26, 27, 28, // tri0 + 26, 28, 29, // tri1 + 0, 0, 0 // tri2 + ), + gsSPEndDisplayList(), +}; + +extern cKF_Joint_R_c cKF_je_r_obj_e_boat_tbl[] = { + /* joint 0 */ obj_e_boat_boat1_model, 2, cKF_JOINT_FLAG_DISP_OPA, 0,0,0, + /* joint 1 */ NULL, 1, cKF_JOINT_FLAG_DISP_OPA, 300,2200,-4500, + /* joint 2 */ obj_e_boat_oar1_model, 0, cKF_JOINT_FLAG_DISP_OPA, 0,0,0, + /* joint 3 */ NULL, 1, cKF_JOINT_FLAG_DISP_OPA, 0,0,4000, + /* joint 4 */ obj_e_boat_water1_model, 1, cKF_JOINT_FLAG_DISP_XLU, 0,0,0, + /* joint 5 */ obj_e_boat_water2_model, 1, cKF_JOINT_FLAG_DISP_XLU, 8400,0,0, + /* joint 6 */ obj_e_boat_water3_model, 0, cKF_JOINT_FLAG_DISP_XLU, 4600,0,0, +}; + +extern cKF_Skeleton_R_c cKF_bs_r_obj_e_boat = { + 7, // 7 total joints + 5, // 5 displayed joints (rendered joints) + cKF_je_r_obj_e_boat_tbl +}; + +static u8 cKF_ckcb_r_obj_e_boat_tbl[] = { + /* joint 0 */ cKF_ANIMITION_BIT_NONE, + /* joint 1 */ cKF_ANIMITION_BIT_NONE, + /* joint 2 */ cKF_ANIMATION_BIT_ROT_X | cKF_ANIMATION_BIT_ROT_Y | cKF_ANIMATION_BIT_ROT_Z, + /* joint 3 */ cKF_ANIMITION_BIT_NONE, + /* joint 4 */ cKF_ANIMITION_BIT_NONE, + /* joint 5 */ cKF_ANIMITION_BIT_NONE, + /* joint 6 */ cKF_ANIMITION_BIT_NONE +}; + +static s16 cKF_kn_obj_e_boat_tbl[] = { + 8, + 5, + 9 +}; + +// Fixed position table (used when the joint has no translation) +static s16 cKF_c_obj_e_boat_tbl[] = { + /* joint 0 */ 0, 0, 0, + /* joint 1 */ 0, 0, 0, + /* joint 2 */ 0, 900, 900, + /* joint 3 */ -450, 900, 450, + /* joint 4 */ 0, 0, 0, + /* joint 5 */ 0, 0, 0, + /* joint 6 */ 0, 0, 0 +}; + +/* frame value slope */ +static s16 cKF_ds_obj_e_boat_tbl[] = { + /* joint 2 X rotational frames */ + 1, 904, 648, + 13, 1075, 212, + 23, 1099, -60, + 40, 920, -572, + 45, 828, -481, + 62, 701, 20, + 80, 877, 651, + 81, 900, 675, + + /* joint 2 Y rotational frames */ + 1, 449, 134, + 27, 495, -50, + 43, 442, -124, + 67, 405, 49, + 81, 449, 132, + + /* joint 2 Z rotational frames */ + 1, -180, 143, + 5, -143, 443, + 20, 141, 303, + 26, 177, 119, + 40, 183, -81, + 44, 156, -370, + 60, -141, -305, + 65, -173, -137, + 81, -180, 83 +}; + +extern cKF_Animation_R_c cKF_ba_r_obj_e_boat = { + cKF_ckcb_r_obj_e_boat_tbl, + cKF_ds_obj_e_boat_tbl, + cKF_kn_obj_e_boat_tbl, + cKF_c_obj_e_boat_tbl, + -1, + 81 +};