Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

libtrx/anims/frames: migrate TR2 frame handling to TRX #2246

Merged
merged 3 commits into from
Jan 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 58 additions & 29 deletions src/libtrx/game/anims/frames.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,34 @@
#include "game/gamebuf.h"
#include "game/objects/common.h"
#include "log.h"
#include "utils.h"

static ANIM_FRAME *m_Frames = NULL;

static int32_t M_GetAnimFrameCount(int32_t anim_idx);
static int32_t M_GetAnimFrameCount(int32_t anim_idx, int32_t frame_data_length);
static OBJECT *M_GetAnimObject(int32_t anim_idx);
static ANIM_FRAME *M_FindFrameBase(uint32_t frame_ofs);
static int32_t M_ParseFrame(
ANIM_FRAME *frame, const int16_t *data_ptr, int16_t mesh_count);
ANIM_FRAME *frame, const int16_t *data_ptr, int16_t mesh_count,
uint8_t frame_size);
static void M_ParseMeshRotation(XYZ_16 *rot, const int16_t **data);
static void M_ExtractRotation(
XYZ_16 *rot, int16_t rot_val_1, int16_t rot_val_2);

static int32_t M_GetAnimFrameCount(const int32_t anim_idx)
static int32_t M_GetAnimFrameCount(
const int32_t anim_idx, const int32_t frame_data_length)
{
const ANIM *const anim = Anim_GetAnim(anim_idx);
#if TR_VERSION == 1
return (int32_t)ceil(
((anim->frame_end - anim->frame_base) / (float)anim->interpolation)
+ 1);
#else
ASSERT_FAIL();
return 0;
uint32_t next_ofs = anim_idx == Anim_GetTotalCount() - 1
? (unsigned)(sizeof(int16_t) * frame_data_length)
: Anim_GetAnim(anim_idx + 1)->frame_ofs;
return (next_ofs - anim->frame_ofs)
/ (int32_t)(sizeof(int16_t) * anim->frame_size);
#endif
}

Expand All @@ -41,15 +48,40 @@ static OBJECT *M_GetAnimObject(const int32_t anim_idx)
return NULL;
}

static ANIM_FRAME *M_FindFrameBase(const uint32_t frame_ofs)
{
const int32_t anim_count = Anim_GetTotalCount();
for (int32_t i = 0; i < anim_count; i++) {
const ANIM *const anim = Anim_GetAnim(i);
if (anim->frame_ofs == frame_ofs) {
return anim->frame_ptr;
}
}

return NULL;
}

static int32_t M_ParseFrame(
ANIM_FRAME *const frame, const int16_t *data_ptr, int16_t mesh_count)
ANIM_FRAME *const frame, const int16_t *data_ptr, int16_t mesh_count,
const uint8_t frame_size)
{
#if TR_VERSION > 1
ASSERT_FAIL();
return 0;
#else
const int16_t *const frame_start = data_ptr;
#if TR_VERSION > 1
frame->bounds.min_x = *data_ptr++;
frame->bounds.max_x = *data_ptr++;
frame->bounds.min_y = *data_ptr++;
frame->bounds.max_y = *data_ptr++;
frame->bounds.min_z = *data_ptr++;
frame->bounds.max_z = *data_ptr++;
frame->offset.x = *data_ptr++;
frame->offset.y = *data_ptr++;
frame->offset.z = *data_ptr++;

frame->mesh_rots =
GameBuf_Alloc(sizeof(int16_t) * (frame_size - 9), GBUF_ANIM_FRAMES);
memcpy(frame->mesh_rots, data_ptr, sizeof(int16_t) * (frame_size - 9));
data_ptr += MAX(0, frame_size - (data_ptr - frame_start));
#else
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this if test in the code below in the else still needed? Because the if above already checks for TR_VERSION > 1

    #if TR_VERSION == 1
    mesh_count = *data_ptr++;
    #endif

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll be tidying up this function after this, it's a bit untidy atm until we get TR2 rotations expanded and BOUNDS_16 working the same as TR1. The #ifs will become neater then. I could remove now but would re-introduce it more or less immediately anyway.

frame->bounds.min.x = *data_ptr++;
frame->bounds.max.x = *data_ptr++;
frame->bounds.min.y = *data_ptr++;
Expand All @@ -69,9 +101,8 @@ static int32_t M_ParseFrame(
XYZ_16 *const rot = &frame->mesh_rots[i];
M_ParseMeshRotation(rot, &data_ptr);
}

return data_ptr - frame_start;
#endif
return data_ptr - frame_start;
}

static void M_ParseMeshRotation(XYZ_16 *const rot, const int16_t **data)
Expand All @@ -95,36 +126,24 @@ static void M_ExtractRotation(
rot->z = (rot_val_2 & 0x3FF) << 6;
}

int32_t Anim_GetTotalFrameCount(void)
int32_t Anim_GetTotalFrameCount(const int32_t frame_data_length)
{
#if TR_VERSION > 1
ASSERT_FAIL();
return 0;
#else
const int32_t anim_count = Anim_GetTotalCount();
int32_t total_frame_count = 0;
for (int32_t i = 0; i < anim_count; i++) {
total_frame_count += M_GetAnimFrameCount(i);
total_frame_count += M_GetAnimFrameCount(i, frame_data_length);
}
return total_frame_count;
#endif
}

void Anim_InitialiseFrames(const int32_t num_frames)
{
#if TR_VERSION > 1
ASSERT_FAIL();
#else
LOG_INFO("%d anim frames", num_frames);
m_Frames = GameBuf_Alloc(sizeof(ANIM_FRAME) * num_frames, GBUF_ANIM_FRAMES);
#endif
}

void Anim_LoadFrames(const int16_t *data, const int32_t data_length)
{
#if TR_VERSION > 1
ASSERT_FAIL();
#else
BENCHMARK *const benchmark = Benchmark_Start();

const int32_t anim_count = Anim_GetTotalCount();
Expand All @@ -143,7 +162,7 @@ void Anim_LoadFrames(const int16_t *data, const int32_t data_length)
}

ANIM *const anim = Anim_GetAnim(i);
const int32_t frame_count = M_GetAnimFrameCount(i);
const int32_t frame_count = M_GetAnimFrameCount(i, data_length);
const int16_t *data_ptr = &data[anim->frame_ofs / sizeof(int16_t)];
for (int32_t j = 0; j < frame_count; j++) {
ANIM_FRAME *const frame = &m_Frames[frame_idx++];
Expand All @@ -154,10 +173,20 @@ void Anim_LoadFrames(const int16_t *data, const int32_t data_length)
}
}

data_ptr += M_ParseFrame(frame, data_ptr, cur_obj->mesh_count);
data_ptr += M_ParseFrame(
frame, data_ptr, cur_obj->mesh_count, anim->frame_size);
}
}

// Some OG data contains objects that point to the previous object's frames,
// so ensure everything that's loaded is configured as such.
for (int32_t i = 0; i < O_NUMBER_OF; i++) {
OBJECT *const object = Object_GetObject(i);
if (object->loaded && object->mesh_count >= 0 && object->anim_idx == -1
&& object->frame_base == NULL) {
object->frame_base = M_FindFrameBase(object->frame_ofs);
}
}

Benchmark_End(benchmark, NULL);
#endif
}
14 changes: 1 addition & 13 deletions src/libtrx/game/level/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -215,26 +215,14 @@ void Level_ReadObjectMeshes(
}

void Level_ReadAnims(
const int32_t base_idx, const int32_t num_anims, VFILE *const file,
int32_t **frame_pointers)
const int32_t base_idx, const int32_t num_anims, VFILE *const file)
{
for (int32_t i = 0; i < num_anims; i++) {
ANIM *const anim = Anim_GetAnim(base_idx + i);
#if TR_VERSION == 1
anim->frame_ofs = VFile_ReadU32(file);
const int16_t interpolation = VFile_ReadS16(file);
ASSERT(interpolation <= 0xFF);
anim->interpolation = interpolation & 0xFF;
anim->frame_size = 0;
#else
const int32_t frame_idx = VFile_ReadS32(file);
if (frame_pointers != NULL) {
(*frame_pointers)[i] = frame_idx;
}
anim->frame_ptr = NULL; // filled later by the animation frame loader
rr- marked this conversation as resolved.
Show resolved Hide resolved
anim->interpolation = VFile_ReadU8(file);
anim->frame_size = VFile_ReadU8(file);
#endif
anim->current_anim_state = VFile_ReadS16(file);
anim->velocity = VFile_ReadS32(file);
anim->acceleration = VFile_ReadS32(file);
Expand Down
2 changes: 1 addition & 1 deletion src/libtrx/include/libtrx/game/anims/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ void Anim_InitialiseRanges(int32_t num_ranges);
void Anim_InitialiseCommands(int32_t num_cmds);
void Anim_InitialiseBones(int32_t num_bones);

int32_t Anim_GetTotalFrameCount(void);
int32_t Anim_GetTotalFrameCount(int32_t frame_data_length);
void Anim_InitialiseFrames(int32_t num_frames);
void Anim_LoadFrames(const int16_t *data, int32_t data_length);

Expand Down
6 changes: 1 addition & 5 deletions src/libtrx/include/libtrx/game/anims/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,13 @@ typedef struct {
#if TR_VERSION == 1
XYZ_16 *mesh_rots;
#else
int16_t mesh_rots[];
int16_t *mesh_rots;
#endif
} ANIM_FRAME;

typedef struct {
#if TR_VERSION == 1
ANIM_FRAME *frame_ptr;
uint32_t frame_ofs;
#elif TR_VERSION == 2
int16_t *frame_ptr;
#endif
uint8_t interpolation;
uint8_t frame_size;
int16_t current_anim_state;
Expand Down
2 changes: 1 addition & 1 deletion src/libtrx/include/libtrx/game/lara/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ typedef struct {
} AMMO_INFO;

typedef struct {
int16_t *frame_base;
ANIM_FRAME *frame_base;
int16_t frame_num;
int16_t anim_num;
int16_t lock;
Expand Down
3 changes: 1 addition & 2 deletions src/libtrx/include/libtrx/game/level/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@
void Level_ReadRoomMesh(int32_t room_num, VFILE *file);
void Level_ReadObjectMeshes(
int32_t num_indices, const int32_t *indices, VFILE *file);
void Level_ReadAnims(
int32_t base_idx, int32_t num_anims, VFILE *file, int32_t **frame_pointers);
void Level_ReadAnims(int32_t base_idx, int32_t num_anims, VFILE *file);
void Level_ReadAnimChanges(int32_t base_idx, int32_t num_changes, VFILE *file);
void Level_ReadAnimRanges(int32_t base_idx, int32_t num_ranges, VFILE *file);
void Level_ReadAnimCommands(int32_t base_idx, int32_t num_cmds, VFILE *file);
Expand Down
4 changes: 3 additions & 1 deletion src/libtrx/include/libtrx/game/objects/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ typedef struct {
int16_t mesh_count;
int16_t mesh_idx;
int32_t bone_idx;
uint32_t frame_ofs;
ANIM_FRAME *frame_base;
void (*initialise)(int16_t item_num);
void (*control)(int16_t item_num);
Expand Down Expand Up @@ -70,7 +71,8 @@ typedef struct {
int16_t mesh_count;
int16_t mesh_idx;
int32_t bone_idx;
int16_t *frame_base; // TODO: make me ANIM_FRAME
uint32_t frame_ofs;
ANIM_FRAME *frame_base;

void (*initialise)(int16_t item_num);
void (*control)(int16_t item_num);
Expand Down
5 changes: 3 additions & 2 deletions src/tr1/game/inject.c
Original file line number Diff line number Diff line change
Expand Up @@ -507,7 +507,7 @@ static void M_AnimData(INJECTION *injection, LEVEL_INFO *level_info)
fp, level_info->anim_frame_data + level_info->anim_frame_data_count,
inj_info->anim_frame_data_count * sizeof(int16_t));

Level_ReadAnims(level_info->anim_count, inj_info->anim_count, fp, NULL);
Level_ReadAnims(level_info->anim_count, inj_info->anim_count, fp);
for (int32_t i = 0; i < inj_info->anim_count; i++) {
ANIM *const anim = Anim_GetAnim(level_info->anim_count + i);

Expand Down Expand Up @@ -624,7 +624,8 @@ static void M_ObjectData(
object->bone_idx = bone_idx + level_info->anim_bone_count;
}

VFile_Skip(fp, sizeof(int32_t));
object->frame_ofs = VFile_ReadU32(fp);
object->frame_base = NULL;
object->anim_idx = VFile_ReadS16(fp);
if (object->anim_idx != -1) {
object->anim_idx += level_info->anim_count;
Expand Down
9 changes: 5 additions & 4 deletions src/tr1/game/level.c
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ static void M_LoadAnims(VFILE *file)
m_LevelInfo.anim_count = VFile_ReadS32(file);
LOG_INFO("%d anims", m_LevelInfo.anim_count);
Anim_InitialiseAnims(m_LevelInfo.anim_count + m_InjectionInfo->anim_count);
Level_ReadAnims(0, m_LevelInfo.anim_count, file, NULL);
Level_ReadAnims(0, m_LevelInfo.anim_count, file);
Benchmark_End(benchmark, NULL);
}

Expand Down Expand Up @@ -370,8 +370,8 @@ static void M_LoadObjects(VFILE *file)
object->mesh_count = VFile_ReadS16(file);
object->mesh_idx = VFile_ReadS16(file);
object->bone_idx = VFile_ReadS32(file) / ANIM_BONE_SIZE;

VFile_Skip(file, sizeof(int32_t)); // Frame offset implied by anim_idx
object->frame_ofs = VFile_ReadU32(file);
object->frame_base = NULL;
object->anim_idx = VFile_ReadS16(file);
object->loaded = true;
}
Expand Down Expand Up @@ -793,7 +793,8 @@ static void M_CompleteSetup(int32_t level_num)

Inject_AllInjections(&m_LevelInfo);

const int32_t frame_count = Anim_GetTotalFrameCount();
const int32_t frame_count =
Anim_GetTotalFrameCount(m_LevelInfo.anim_frame_data_count);
Anim_InitialiseFrames(frame_count);
Anim_LoadFrames(
m_LevelInfo.anim_frame_data, m_LevelInfo.anim_frame_data_count);
Expand Down
6 changes: 2 additions & 4 deletions src/tr2/decomp/savegame.c
Original file line number Diff line number Diff line change
Expand Up @@ -315,8 +315,7 @@ static void M_ReadLara(LARA_INFO *const lara)

static void M_ReadLaraArm(LARA_ARM *const arm)
{
arm->frame_base =
(int16_t *)((intptr_t)g_AnimFrames + (intptr_t)M_ReadS32());
M_ReadS32(); // arm frame_base is not required
arm->frame_num = M_ReadS16();
arm->anim_num = M_ReadS16();
arm->lock = M_ReadS16();
Expand Down Expand Up @@ -500,8 +499,7 @@ static void M_WriteLara(const LARA_INFO *const lara)

static void M_WriteLaraArm(const LARA_ARM *const arm)
{
const int32_t frame_base =
(intptr_t)arm->frame_base - (intptr_t)g_AnimFrames;
const int32_t frame_base = 0; // not required
M_WriteS32(frame_base);
M_WriteS16(arm->frame_num);
M_WriteS16(arm->anim_num);
Expand Down
4 changes: 1 addition & 3 deletions src/tr2/game/inventory_ring/draw.c
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,7 @@ static void M_DrawItem(
}
}

ANIM_FRAME *frame_ptr =
(ANIM_FRAME *)&obj->frame_base
[inv_item->current_frame * Object_GetAnim(obj, 0)->frame_size];
ANIM_FRAME *frame_ptr = &obj->frame_base[inv_item->current_frame];

Matrix_Push();
const int32_t clip = Output_GetObjectBounds(&frame_ptr->bounds);
Expand Down
9 changes: 4 additions & 5 deletions src/tr2/game/items.c
Original file line number Diff line number Diff line change
Expand Up @@ -640,11 +640,10 @@ int32_t Item_GetFrames(const ITEM *item, ANIM_FRAME *frmptr[], int32_t *rate)
{
const ANIM *const anim = Item_GetAnim(item);
const int32_t cur_frame_num = item->frame_num - anim->frame_base;
const int32_t size = anim->frame_size;
const int32_t key_frame_span = anim->interpolation;
const int32_t key_frame_shift = cur_frame_num % key_frame_span;
const int32_t first_key_frame_num = cur_frame_num / key_frame_span * size;
const int32_t second_key_frame_num = first_key_frame_num + size;
const int32_t first_key_frame_num = cur_frame_num / key_frame_span;
const int32_t second_key_frame_num = first_key_frame_num + 1;

const int32_t numerator = key_frame_shift;
int32_t denominator = key_frame_span;
Expand All @@ -657,8 +656,8 @@ int32_t Item_GetFrames(const ITEM *item, ANIM_FRAME *frmptr[], int32_t *rate)
}
}

frmptr[0] = (ANIM_FRAME *)(anim->frame_ptr + first_key_frame_num);
frmptr[1] = (ANIM_FRAME *)(anim->frame_ptr + second_key_frame_num);
frmptr[0] = &anim->frame_ptr[first_key_frame_num];
frmptr[1] = &anim->frame_ptr[second_key_frame_num];
*rate = denominator;
return numerator;
}
Expand Down
Loading
Loading