tr2/lara/hair: add interpolation control

This improves the overall animation of Lara's hair to respond to
interpolated frames in her main animation.

Resolves #2094.
This commit is contained in:
lahm86 2024-12-28 19:41:54 +00:00
parent 336d775410
commit 2d92771e2c
3 changed files with 183 additions and 75 deletions

View file

@ -17,6 +17,7 @@
- fixed the camera getting stuck at the start of Home Sweet Home (#2129, regression from 0.7)
- fixed bubbles spawning from flares if Lara is in shallow water (#1590)
- fixed flare sound effects not always playing when Lara is in shallow water (#1590)
- improved the animation of Lara's braid (#2094)
## [0.7.1](https://github.com/LostArtefacts/TRX/compare/tr2-0.7...tr2-0.7.1) - 2024-12-17
- fixed a crash when selecting the sound option (#2057, regression from 0.6)

View file

@ -62,6 +62,7 @@ game with new enhancements and features.
- **Ice Palace**: fixed door 143's position to resolve the invisible wall in front of it, and added an extra pickup trigger beside the Gong Hammer in room 29
- **Temple of Xian**: fixed missing death tiles in room 91
- **Floating Islands**: fixed door 72's position to resolve the invisible wall in front of it
- improved the animation of Lara's braid
#### Cheats
- added a fly cheat

View file

@ -45,9 +45,15 @@ void Lara_Hair_Initialise(void)
void Lara_Hair_Control(const bool in_cutscene)
{
const FRAME_INFO *frame;
const FRAME_INFO *frame1;
const FRAME_INFO *frame2;
int32_t frac;
int32_t rate;
if (g_Lara.hit_direction < 0) {
frame = Item_GetBestFrame(g_LaraItem);
FRAME_INFO *frmptr[2];
frac = Item_GetFrames(g_LaraItem, frmptr, &rate);
frame1 = frmptr[0];
frame2 = frmptr[1];
} else {
LARA_ANIMATION lara_anim;
switch (g_Lara.hit_direction) {
@ -67,13 +73,13 @@ void Lara_Hair_Control(const bool in_cutscene)
const int16_t *const frame_ptr = g_Anims[lara_anim].frame_ptr;
const int32_t interpolation = g_Anims[lara_anim].interpolation;
frame =
frame1 =
(FRAME_INFO *)&frame_ptr[g_Lara.hit_frame * (interpolation >> 8)];
frac = 0;
}
const int32_t *bone;
const int16_t *mesh;
const int16_t *mesh_rots;
SPHERE spheres[5];
Matrix_PushUnit();
@ -81,78 +87,175 @@ void Lara_Hair_Control(const bool in_cutscene)
g_MatrixPtr->_13 = g_LaraItem->pos.y << W2V_SHIFT;
g_MatrixPtr->_23 = g_LaraItem->pos.z << W2V_SHIFT;
Matrix_RotYXZ(g_LaraItem->rot.y, g_LaraItem->rot.x, g_LaraItem->rot.z);
mesh_rots = frame->mesh_rots;
Matrix_TranslateRel(frame->offset.x, frame->offset.y, frame->offset.z);
Matrix_RotYXZsuperpack(&mesh_rots, 0);
Matrix_Push();
mesh = g_Lara.mesh_ptrs[LM_HIPS];
Matrix_TranslateRel(mesh[0], mesh[1], mesh[2]);
spheres[0].x = g_MatrixPtr->_03 >> W2V_SHIFT;
spheres[0].y = g_MatrixPtr->_13 >> W2V_SHIFT;
spheres[0].z = g_MatrixPtr->_23 >> W2V_SHIFT;
spheres[0].r = mesh[3];
Matrix_Pop();
bone = &g_AnimBones[g_Objects[O_LARA].bone_idx];
Matrix_TranslateRel(bone[25], bone[26], bone[27]);
if (g_Lara.weapon_item != NO_ITEM && g_Lara.gun_type == LGT_M16
&& (g_Items[g_Lara.weapon_item].current_anim_state == 0
|| g_Items[g_Lara.weapon_item].current_anim_state == 2
|| g_Items[g_Lara.weapon_item].current_anim_state == 4)) {
mesh_rots =
&g_Lara.right_arm.frame_base
[g_Lara.right_arm.frame_num
* (g_Anims[g_Lara.right_arm.anim_num].interpolation >> 8)
+ FBBOX_ROT];
Matrix_RotYXZsuperpack(&mesh_rots, 7);
if (frac != 0) {
const int16_t *mesh_rots1 = frame1->mesh_rots;
const int16_t *mesh_rots2 = frame2->mesh_rots;
Matrix_InitInterpolate(frac, rate);
Matrix_TranslateRel_ID(
frame1->offset.x, frame1->offset.y, frame1->offset.z,
frame2->offset.x, frame2->offset.y, frame2->offset.z);
Matrix_RotYXZsuperpack_I(&mesh_rots1, &mesh_rots2, 0);
Matrix_Push_I();
mesh = g_Lara.mesh_ptrs[LM_HIPS];
Matrix_TranslateRel_I(mesh[0], mesh[1], mesh[2]);
Matrix_Interpolate();
spheres[0].x = g_MatrixPtr->_03 >> W2V_SHIFT;
spheres[0].y = g_MatrixPtr->_13 >> W2V_SHIFT;
spheres[0].z = g_MatrixPtr->_23 >> W2V_SHIFT;
spheres[0].r = mesh[3];
Matrix_Pop_I();
bone = &g_AnimBones[g_Objects[O_LARA].bone_idx];
Matrix_TranslateRel_I(bone[25], bone[26], bone[27]);
if (g_Lara.weapon_item != NO_ITEM && g_Lara.gun_type == LGT_M16
&& (g_Items[g_Lara.weapon_item].current_anim_state == 0
|| g_Items[g_Lara.weapon_item].current_anim_state == 2
|| g_Items[g_Lara.weapon_item].current_anim_state == 4)) {
mesh_rots1 =
&g_Lara.right_arm.frame_base
[g_Lara.right_arm.frame_num
* (g_Anims[g_Lara.right_arm.anim_num].interpolation
>> 8)
+ FBBOX_ROT];
mesh_rots2 = mesh_rots1;
Matrix_RotYXZsuperpack_I(&mesh_rots1, &mesh_rots2, 7);
} else {
Matrix_RotYXZsuperpack_I(&mesh_rots1, &mesh_rots2, 6);
}
Matrix_RotYXZ_I(
g_Lara.torso_y_rot, g_Lara.torso_x_rot, g_Lara.torso_z_rot);
Matrix_Push_I();
mesh = g_Lara.mesh_ptrs[LM_TORSO];
Matrix_TranslateRel_I(mesh[0], mesh[1], mesh[2]);
Matrix_Interpolate();
spheres[1].x = g_MatrixPtr->_03 >> W2V_SHIFT;
spheres[1].y = g_MatrixPtr->_13 >> W2V_SHIFT;
spheres[1].z = g_MatrixPtr->_23 >> W2V_SHIFT;
spheres[1].r = mesh[3];
Matrix_Pop_I();
Matrix_Push_I();
Matrix_TranslateRel_I(bone[29], bone[30], bone[31]);
Matrix_RotYXZsuperpack_I(&mesh_rots1, &mesh_rots2, 0);
mesh = g_Lara.mesh_ptrs[LM_UARM_R];
Matrix_TranslateRel_I(mesh[0], mesh[1], mesh[2]);
Matrix_Interpolate();
spheres[3].x = g_MatrixPtr->_03 >> W2V_SHIFT;
spheres[3].y = g_MatrixPtr->_13 >> W2V_SHIFT;
spheres[3].z = g_MatrixPtr->_23 >> W2V_SHIFT;
spheres[3].r = mesh[3] * 3 / 2;
Matrix_Pop_I();
Matrix_Push_I();
Matrix_TranslateRel_I(bone[41], bone[42], bone[43]);
Matrix_RotYXZsuperpack_I(&mesh_rots1, &mesh_rots2, 2);
mesh = g_Lara.mesh_ptrs[LM_UARM_L];
Matrix_TranslateRel_I(mesh[0], mesh[1], mesh[2]);
Matrix_Interpolate();
spheres[4].x = g_MatrixPtr->_03 >> W2V_SHIFT;
spheres[4].y = g_MatrixPtr->_13 >> W2V_SHIFT;
spheres[4].z = g_MatrixPtr->_23 >> W2V_SHIFT;
spheres[4].r = mesh[3] * 3 / 2;
Matrix_Pop_I();
Matrix_TranslateRel_I(bone[53], bone[54], bone[55]);
Matrix_RotYXZsuperpack_I(&mesh_rots1, &mesh_rots2, 2);
Matrix_RotYXZ_I(
g_Lara.head_y_rot, g_Lara.head_x_rot, g_Lara.head_z_rot);
Matrix_Push_I();
mesh = g_Lara.mesh_ptrs[LM_HEAD];
Matrix_TranslateRel_I(mesh[0], mesh[1], mesh[2]);
Matrix_Interpolate();
spheres[2].x = g_MatrixPtr->_03 >> W2V_SHIFT;
spheres[2].y = g_MatrixPtr->_13 >> W2V_SHIFT;
spheres[2].z = g_MatrixPtr->_23 >> W2V_SHIFT;
spheres[2].r = mesh[3];
Matrix_Pop_I();
Matrix_TranslateRel_I(0, -23, -55);
Matrix_Interpolate();
} else {
Matrix_RotYXZsuperpack(&mesh_rots, 6);
const int16_t *mesh_rots = frame1->mesh_rots;
Matrix_TranslateRel(
frame1->offset.x, frame1->offset.y, frame1->offset.z);
Matrix_RotYXZsuperpack(&mesh_rots, 0);
Matrix_Push();
mesh = g_Lara.mesh_ptrs[LM_HIPS];
Matrix_TranslateRel(mesh[0], mesh[1], mesh[2]);
spheres[0].x = g_MatrixPtr->_03 >> W2V_SHIFT;
spheres[0].y = g_MatrixPtr->_13 >> W2V_SHIFT;
spheres[0].z = g_MatrixPtr->_23 >> W2V_SHIFT;
spheres[0].r = mesh[3];
Matrix_Pop();
bone = &g_AnimBones[g_Objects[O_LARA].bone_idx];
Matrix_TranslateRel(bone[25], bone[26], bone[27]);
if (g_Lara.weapon_item != NO_ITEM && g_Lara.gun_type == LGT_M16
&& (g_Items[g_Lara.weapon_item].current_anim_state == 0
|| g_Items[g_Lara.weapon_item].current_anim_state == 2
|| g_Items[g_Lara.weapon_item].current_anim_state == 4)) {
mesh_rots =
&g_Lara.right_arm.frame_base
[g_Lara.right_arm.frame_num
* (g_Anims[g_Lara.right_arm.anim_num].interpolation
>> 8)
+ FBBOX_ROT];
Matrix_RotYXZsuperpack(&mesh_rots, 7);
} else {
Matrix_RotYXZsuperpack(&mesh_rots, 6);
}
Matrix_RotYXZ(
g_Lara.torso_y_rot, g_Lara.torso_x_rot, g_Lara.torso_z_rot);
Matrix_Push();
mesh = g_Lara.mesh_ptrs[LM_TORSO];
Matrix_TranslateRel(mesh[0], mesh[1], mesh[2]);
spheres[1].x = g_MatrixPtr->_03 >> W2V_SHIFT;
spheres[1].y = g_MatrixPtr->_13 >> W2V_SHIFT;
spheres[1].z = g_MatrixPtr->_23 >> W2V_SHIFT;
spheres[1].r = mesh[3];
Matrix_Pop();
Matrix_Push();
Matrix_TranslateRel(bone[29], bone[30], bone[31]);
Matrix_RotYXZsuperpack(&mesh_rots, 0);
mesh = g_Lara.mesh_ptrs[LM_UARM_R];
Matrix_TranslateRel(mesh[0], mesh[1], mesh[2]);
spheres[3].y = g_MatrixPtr->_13 >> W2V_SHIFT;
spheres[3].x = g_MatrixPtr->_03 >> W2V_SHIFT;
spheres[3].z = g_MatrixPtr->_23 >> W2V_SHIFT;
spheres[3].r = mesh[3] * 3 / 2;
Matrix_Pop();
Matrix_Push();
Matrix_TranslateRel(bone[41], bone[42], bone[43]);
Matrix_RotYXZsuperpack(&mesh_rots, 2);
mesh = g_Lara.mesh_ptrs[LM_UARM_L];
Matrix_TranslateRel(mesh[0], mesh[1], mesh[2]);
spheres[4].y = g_MatrixPtr->_13 >> W2V_SHIFT;
spheres[4].x = g_MatrixPtr->_03 >> W2V_SHIFT;
spheres[4].z = g_MatrixPtr->_23 >> W2V_SHIFT;
spheres[4].r = mesh[3] * 3 / 2;
Matrix_Pop();
Matrix_TranslateRel(bone[53], bone[54], bone[55]);
Matrix_RotYXZsuperpack(&mesh_rots, 2);
Matrix_RotYXZ(g_Lara.head_y_rot, g_Lara.head_x_rot, g_Lara.head_z_rot);
Matrix_Push();
mesh = g_Lara.mesh_ptrs[LM_HEAD];
Matrix_TranslateRel(mesh[0], mesh[1], mesh[2]);
spheres[2].x = g_MatrixPtr->_03 >> W2V_SHIFT;
spheres[2].y = g_MatrixPtr->_13 >> W2V_SHIFT;
spheres[2].z = g_MatrixPtr->_23 >> W2V_SHIFT;
spheres[2].r = mesh[3];
Matrix_Pop();
Matrix_TranslateRel(0, -23, -55);
}
Matrix_RotYXZ(g_Lara.torso_y_rot, g_Lara.torso_x_rot, g_Lara.torso_z_rot);
Matrix_Push();
mesh = g_Lara.mesh_ptrs[LM_TORSO];
Matrix_TranslateRel(mesh[0], mesh[1], mesh[2]);
spheres[1].x = g_MatrixPtr->_03 >> W2V_SHIFT;
spheres[1].y = g_MatrixPtr->_13 >> W2V_SHIFT;
spheres[1].z = g_MatrixPtr->_23 >> W2V_SHIFT;
spheres[1].r = mesh[3];
Matrix_Pop();
Matrix_Push();
Matrix_TranslateRel(bone[29], bone[30], bone[31]);
Matrix_RotYXZsuperpack(&mesh_rots, 0);
mesh = g_Lara.mesh_ptrs[LM_UARM_R];
Matrix_TranslateRel(mesh[0], mesh[1], mesh[2]);
spheres[3].y = g_MatrixPtr->_13 >> W2V_SHIFT;
spheres[3].x = g_MatrixPtr->_03 >> W2V_SHIFT;
spheres[3].z = g_MatrixPtr->_23 >> W2V_SHIFT;
spheres[3].r = mesh[3] * 3 / 2;
Matrix_Pop();
Matrix_Push();
Matrix_TranslateRel(bone[41], bone[42], bone[43]);
Matrix_RotYXZsuperpack(&mesh_rots, 2);
mesh = g_Lara.mesh_ptrs[LM_UARM_R];
Matrix_TranslateRel(mesh[0], mesh[1], mesh[2]);
spheres[4].y = g_MatrixPtr->_13 >> W2V_SHIFT;
spheres[4].x = g_MatrixPtr->_03 >> W2V_SHIFT;
spheres[4].z = g_MatrixPtr->_23 >> W2V_SHIFT;
spheres[4].r = mesh[3] * 3 / 2;
Matrix_Pop();
Matrix_TranslateRel(bone[53], bone[54], bone[55]);
Matrix_RotYXZsuperpack(&mesh_rots, 2);
Matrix_RotYXZ(g_Lara.head_y_rot, g_Lara.head_x_rot, g_Lara.head_z_rot);
Matrix_Push();
mesh = g_Lara.mesh_ptrs[LM_HEAD];
Matrix_TranslateRel(mesh[0], mesh[1], mesh[2]);
spheres[2].x = g_MatrixPtr->_03 >> W2V_SHIFT;
spheres[2].y = g_MatrixPtr->_13 >> W2V_SHIFT;
spheres[2].z = g_MatrixPtr->_23 >> W2V_SHIFT;
spheres[2].r = mesh[3];
Matrix_Pop();
Matrix_TranslateRel(0, -23, -55);
const XYZ_32 pos = {
.x = g_MatrixPtr->_03 >> W2V_SHIFT,
.y = g_MatrixPtr->_13 >> W2V_SHIFT,
@ -196,9 +299,12 @@ void Lara_Hair_Control(const bool in_cutscene)
water_height = NO_HEIGHT;
} else {
water_height = Room_GetWaterHeight(
g_LaraItem->pos.x + (frame->bounds.min_x + frame->bounds.max_x) / 2,
g_LaraItem->pos.y + (frame->bounds.max_y + frame->bounds.min_y) / 2,
g_LaraItem->pos.z + (frame->bounds.max_z + frame->bounds.min_z) / 2,
g_LaraItem->pos.x
+ (frame1->bounds.min_x + frame1->bounds.max_x) / 2,
g_LaraItem->pos.y
+ (frame1->bounds.max_y + frame1->bounds.min_y) / 2,
g_LaraItem->pos.z
+ (frame1->bounds.max_z + frame1->bounds.min_z) / 2,
room_num);
}