mirror of
https://github.com/LostArtefacts/TRX.git
synced 2025-04-28 12:47:58 +03:00
items: handle null anims/frames for sprite objects
This ensures that sprite objects (or anything with no animation index defined) are assigned a default animation and as such allows us to handle null frames when getting item bounds. When Lara's animations are injected, animation index 0 (which sprite objects would previously default to) is no longer valid, hence sprites then pointing to a null entry.
This commit is contained in:
parent
6820532711
commit
2fb3824b3b
8 changed files with 59 additions and 36 deletions
|
@ -6,6 +6,7 @@
|
|||
- fixed mesh faces not being drawn under some circumstances (#2452, #2438)
|
||||
- fixed objects disappearing too early around screen edges (#2005)
|
||||
- fixed the trapezoid filter being toggled if Alt-F4 (either left or right) is used to close the game (#2690)
|
||||
- fixed a crash when 3D pickups are disabled and Lara crosses a trigger to look at a pickup item (#2711, regression from 4.8)
|
||||
- fixed trapezoid filter warping on faces close to the camera (#2629, regression from 4.9)
|
||||
- fixed Mac builds crashing upon start (regression from 4.9)
|
||||
- fixed sprites rendering black if no shade value is assigned in the level (#2701, regression from 4.9)
|
||||
|
|
|
@ -7,6 +7,7 @@ static ANIM *m_Anims = nullptr;
|
|||
static ANIM_CHANGE *m_Changes = nullptr;
|
||||
static ANIM_RANGE *m_Ranges = nullptr;
|
||||
static ANIM_BONE *m_Bones = nullptr;
|
||||
static ANIM m_NullAnim = {};
|
||||
|
||||
void Anim_InitialiseAnims(const int32_t num_anims)
|
||||
{
|
||||
|
@ -37,7 +38,7 @@ int32_t Anim_GetTotalCount(void)
|
|||
|
||||
ANIM *Anim_GetAnim(const int32_t anim_idx)
|
||||
{
|
||||
return &m_Anims[anim_idx];
|
||||
return anim_idx == NO_ANIM ? &m_NullAnim : &m_Anims[anim_idx];
|
||||
}
|
||||
|
||||
ANIM_CHANGE *Anim_GetChange(const int32_t change_idx)
|
||||
|
|
|
@ -201,7 +201,7 @@ void Anim_LoadFrames(const int16_t *data, const int32_t data_length)
|
|||
// so ensure everything that's loaded is configured as such.
|
||||
for (int32_t i = 0; i < O_NUMBER_OF; i++) {
|
||||
OBJECT *const obj = Object_Get(i);
|
||||
if (obj->loaded && obj->mesh_count >= 0 && obj->anim_idx == -1
|
||||
if (obj->loaded && obj->mesh_count >= 0 && obj->anim_idx == NO_ANIM
|
||||
&& obj->frame_base == nullptr) {
|
||||
obj->frame_base = M_FindFrameBase(obj->frame_ofs);
|
||||
}
|
||||
|
|
|
@ -301,7 +301,11 @@ void Item_SwitchToObjAnim(
|
|||
const GAME_OBJECT_ID obj_id)
|
||||
{
|
||||
const OBJECT *const obj = Object_Get(obj_id);
|
||||
item->anim_num = obj->anim_idx + anim_idx;
|
||||
if (obj->anim_idx == NO_ANIM) {
|
||||
item->anim_num = NO_ANIM;
|
||||
} else {
|
||||
item->anim_num = obj->anim_idx + anim_idx;
|
||||
}
|
||||
|
||||
const ANIM *const anim = Item_GetAnim(item);
|
||||
if (frame < 0) {
|
||||
|
|
|
@ -934,6 +934,7 @@ void Level_ReadSpriteSequences(VFILE *const file)
|
|||
OBJECT *const obj = Object_Get(object_id);
|
||||
obj->mesh_count = num_meshes;
|
||||
obj->mesh_idx = mesh_idx;
|
||||
obj->anim_idx = NO_ANIM;
|
||||
obj->loaded = true;
|
||||
} else if (object_id - O_NUMBER_OF < MAX_STATIC_OBJECTS) {
|
||||
STATIC_OBJECT_2D *const obj =
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
#include "./types.h"
|
||||
|
||||
#define NO_ANIM (-1)
|
||||
|
||||
void Anim_InitialiseAnims(int32_t num_anims);
|
||||
void Anim_InitialiseChanges(int32_t num_changes);
|
||||
void Anim_InitialiseRanges(int32_t num_ranges);
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
} \
|
||||
} while (0)
|
||||
|
||||
static BOUNDS_16 m_NullBounds = {};
|
||||
static BOUNDS_16 m_InterpolatedBounds = {};
|
||||
|
||||
void Item_Control(void)
|
||||
|
@ -411,28 +412,27 @@ bool Item_IsTriggerActive(ITEM *item)
|
|||
|
||||
ANIM_FRAME *Item_GetBestFrame(const ITEM *item)
|
||||
{
|
||||
ANIM_FRAME *frmptr[2];
|
||||
ANIM_FRAME *frames[2];
|
||||
int32_t rate;
|
||||
int32_t frac = Item_GetFrames(item, frmptr, &rate);
|
||||
if (frac <= rate / 2) {
|
||||
return frmptr[0];
|
||||
} else {
|
||||
return frmptr[1];
|
||||
}
|
||||
const int32_t frac = Item_GetFrames(item, frames, &rate);
|
||||
return frames[(frac > rate / 2) ? 1 : 0];
|
||||
}
|
||||
|
||||
const BOUNDS_16 *Item_GetBoundsAccurate(const ITEM *item)
|
||||
{
|
||||
int32_t rate;
|
||||
ANIM_FRAME *frmptr[2];
|
||||
|
||||
int32_t frac = Item_GetFrames(item, frmptr, &rate);
|
||||
if (!frac) {
|
||||
return &frmptr[0]->bounds;
|
||||
ANIM_FRAME *frames[2];
|
||||
const int32_t frac = Item_GetFrames(item, frames, &rate);
|
||||
if (frames[0] == nullptr) {
|
||||
return &m_NullBounds;
|
||||
}
|
||||
|
||||
const BOUNDS_16 *const a = &frmptr[0]->bounds;
|
||||
const BOUNDS_16 *const b = &frmptr[1]->bounds;
|
||||
if (frac == 0) {
|
||||
return &frames[0]->bounds;
|
||||
}
|
||||
|
||||
const BOUNDS_16 *const a = &frames[0]->bounds;
|
||||
const BOUNDS_16 *const b = &frames[1]->bounds;
|
||||
BOUNDS_16 *const result = &m_InterpolatedBounds;
|
||||
|
||||
result->min.x = a->min.x + (((b->min.x - a->min.x) * frac) / rate);
|
||||
|
@ -444,9 +444,13 @@ const BOUNDS_16 *Item_GetBoundsAccurate(const ITEM *item)
|
|||
return result;
|
||||
}
|
||||
|
||||
int32_t Item_GetFrames(const ITEM *item, ANIM_FRAME *frmptr[], int32_t *rate)
|
||||
int32_t Item_GetFrames(const ITEM *item, ANIM_FRAME *frames[], int32_t *rate)
|
||||
{
|
||||
const ANIM *const anim = Item_GetAnim(item);
|
||||
if (anim->frame_ptr == nullptr) {
|
||||
frames[0] = nullptr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const int32_t cur_frame_num = item->frame_num - anim->frame_base;
|
||||
const int32_t last_frame_num = anim->frame_end - anim->frame_base;
|
||||
|
@ -454,8 +458,8 @@ int32_t Item_GetFrames(const ITEM *item, ANIM_FRAME *frmptr[], int32_t *rate)
|
|||
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;
|
||||
|
||||
frmptr[0] = &anim->frame_ptr[first_key_frame_num];
|
||||
frmptr[1] = &anim->frame_ptr[second_key_frame_num];
|
||||
frames[0] = &anim->frame_ptr[first_key_frame_num];
|
||||
frames[1] = &anim->frame_ptr[second_key_frame_num];
|
||||
|
||||
const int32_t key_frame_shift = cur_frame_num % key_frame_span;
|
||||
const int32_t numerator = key_frame_shift;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <libtrx/game/matrix.h>
|
||||
#include <libtrx/utils.h>
|
||||
|
||||
static BOUNDS_16 m_NullBounds = {};
|
||||
static BOUNDS_16 m_InterpolatedBounds = {};
|
||||
|
||||
static OBJECT_BOUNDS M_ConvertBounds(const int16_t *bounds_in);
|
||||
|
@ -330,9 +331,14 @@ int32_t Item_IsTriggerActive(ITEM *const item)
|
|||
return ok;
|
||||
}
|
||||
|
||||
int32_t Item_GetFrames(const ITEM *item, ANIM_FRAME *frmptr[], int32_t *rate)
|
||||
int32_t Item_GetFrames(const ITEM *item, ANIM_FRAME *frames[], int32_t *rate)
|
||||
{
|
||||
const ANIM *const anim = Item_GetAnim(item);
|
||||
if (anim->frame_ptr == nullptr) {
|
||||
frames[0] = nullptr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const int32_t cur_frame_num = item->frame_num - anim->frame_base;
|
||||
const int32_t last_frame_num = anim->frame_end - anim->frame_base;
|
||||
const int32_t key_frame_span = anim->interpolation;
|
||||
|
@ -351,8 +357,8 @@ int32_t Item_GetFrames(const ITEM *item, ANIM_FRAME *frmptr[], int32_t *rate)
|
|||
}
|
||||
}
|
||||
|
||||
frmptr[0] = &anim->frame_ptr[first_key_frame_num];
|
||||
frmptr[1] = &anim->frame_ptr[second_key_frame_num];
|
||||
frames[0] = &anim->frame_ptr[first_key_frame_num];
|
||||
frames[1] = &anim->frame_ptr[second_key_frame_num];
|
||||
|
||||
// OG
|
||||
if (g_Config.rendering.fps == 30) {
|
||||
|
@ -386,31 +392,35 @@ int32_t Item_GetFrames(const ITEM *item, ANIM_FRAME *frmptr[], int32_t *rate)
|
|||
BOUNDS_16 *Item_GetBoundsAccurate(const ITEM *const item)
|
||||
{
|
||||
int32_t rate;
|
||||
ANIM_FRAME *frmptr[2];
|
||||
const int32_t frac = Item_GetFrames(item, frmptr, &rate);
|
||||
if (!frac) {
|
||||
return &frmptr[0]->bounds;
|
||||
ANIM_FRAME *frames[2];
|
||||
const int32_t frac = Item_GetFrames(item, frames, &rate);
|
||||
if (frames[0] == nullptr) {
|
||||
return &m_NullBounds;
|
||||
}
|
||||
|
||||
if (frac == 0) {
|
||||
return &frames[0]->bounds;
|
||||
}
|
||||
|
||||
#define CALC(target, b1, b2, prop) \
|
||||
target->prop = (b1)->prop + ((((b2)->prop - (b1)->prop) * frac) / rate);
|
||||
|
||||
BOUNDS_16 *const result = &m_InterpolatedBounds;
|
||||
CALC(result, &frmptr[0]->bounds, &frmptr[1]->bounds, min.x);
|
||||
CALC(result, &frmptr[0]->bounds, &frmptr[1]->bounds, max.x);
|
||||
CALC(result, &frmptr[0]->bounds, &frmptr[1]->bounds, min.y);
|
||||
CALC(result, &frmptr[0]->bounds, &frmptr[1]->bounds, max.y);
|
||||
CALC(result, &frmptr[0]->bounds, &frmptr[1]->bounds, min.z);
|
||||
CALC(result, &frmptr[0]->bounds, &frmptr[1]->bounds, max.z);
|
||||
CALC(result, &frames[0]->bounds, &frames[1]->bounds, min.x);
|
||||
CALC(result, &frames[0]->bounds, &frames[1]->bounds, max.x);
|
||||
CALC(result, &frames[0]->bounds, &frames[1]->bounds, min.y);
|
||||
CALC(result, &frames[0]->bounds, &frames[1]->bounds, max.y);
|
||||
CALC(result, &frames[0]->bounds, &frames[1]->bounds, min.z);
|
||||
CALC(result, &frames[0]->bounds, &frames[1]->bounds, max.z);
|
||||
return result;
|
||||
}
|
||||
|
||||
ANIM_FRAME *Item_GetBestFrame(const ITEM *const item)
|
||||
{
|
||||
ANIM_FRAME *frmptr[2];
|
||||
ANIM_FRAME *frames[2];
|
||||
int32_t rate;
|
||||
const int32_t frac = Item_GetFrames(item, frmptr, &rate);
|
||||
return frmptr[(frac > rate / 2) ? 1 : 0];
|
||||
const int32_t frac = Item_GetFrames(item, frames, &rate);
|
||||
return frames[(frac > rate / 2) ? 1 : 0];
|
||||
}
|
||||
|
||||
bool Item_IsNearItem(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue