camera: store cinematic frames in camera module

This moves cinematic frames into a new common camera cinematic module;
they should only be changed on level reading.

This also adds checks to TR2 in case there are no frames and a
cinematic is loaded.

Resolves #2413.
This commit is contained in:
lahm86 2025-02-01 12:02:11 +00:00
parent adaf8fde1d
commit 71cd31d7ab
13 changed files with 70 additions and 32 deletions

View file

@ -32,6 +32,7 @@
- fixed Lara activating triggers one frame too early (#2208, regression from 4.3)
- fixed wrong underwater caustics speed with the turbo cheat (#2231)
- fixed 1-frame UI flicker on pause screen exit confirmation
- fixed the game crashing if a cinematic is triggered but the level contains no cinematic frames (#2413)
- fixed being able to use keys and puzzle items in keyholes/slots that have already been used (#2256, regression from 4.0)
- fixed textures animating during demo fade-outs (#2217, regression from 4.0)
- fixed waterfall mist not animating during demo (#2218, regression from 3.0)

View file

@ -459,6 +459,7 @@ Not all options are turned on by default. Refer to `TR1X_ConfigTool.exe` for det
- fixed collision issues with drawbridges, trapdoors, and bridges when stacked over each other, over slopes, and near the ground
- fixed a potential softlock when killing the Torso boss in Great Pyramid
- fixed being able to shoot the scion multiple times if save/load is used while it blows up
- fixed the game crashing if a cinematic is triggered but the level contains no cinematic frames
#### Cheats
- added a fly cheat

View file

@ -30,6 +30,7 @@
- fixed potential memory corruption when reading a custom level with more than 512 sprite textures (#2338)
- fixed the teleporting command sometimes putting Lara in invalid flipmap rooms (#2370)
- fixed teleporting to an item on a ledge sometimes pushing Lara to the room below (#2372)
- fixed the game crashing if a cinematic is triggered but the level contains no cinematic frames (#2413)
- fixed Lara activating triggers one frame too early (#2205, regression from 0.7)
- fixed savegame incompatibility with OG (#2271, regression from 0.8)
- fixed stopwatch showing wrong UI in some circumstances (#2221, regression from 0.8)

View file

@ -76,6 +76,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
- fixed the game crashing if a cinematic is triggered but the level contains no cinematic frames
- improved the animation of Lara's braid
#### Cheats

View file

@ -0,0 +1,27 @@
#include "game/camera/types.h"
#include "game/camera/vars.h"
#include "game/game_buf.h"
static CINE_FRAME *m_CineFrames = NULL;
void Camera_InitialiseCineFrames(const int32_t num_frames)
{
g_CineData.frame_count = num_frames;
g_CineData.frame_idx = 0;
m_CineFrames = num_frames == 0
? nullptr
: GameBuf_Alloc(num_frames * sizeof(CINE_FRAME), GBUF_CINEMATIC_FRAMES);
}
CINE_FRAME *Camera_GetCineFrame(const int32_t frame_idx)
{
if (m_CineFrames == nullptr) {
return nullptr;
}
return &m_CineFrames[frame_idx];
}
CINE_FRAME *Camera_GetCurrentCineFrame(void)
{
return Camera_GetCineFrame(g_CineData.frame_idx);
}

View file

@ -1,5 +1,6 @@
#pragma once
#include "./camera/cinematic.h"
#include "./camera/common.h"
#include "./camera/const.h"
#include "./camera/enum.h"

View file

@ -0,0 +1,7 @@
#pragma once
#include "./types.h"
void Camera_InitialiseCineFrames(int32_t num_frames);
CINE_FRAME *Camera_GetCineFrame(int32_t frame_idx);
CINE_FRAME *Camera_GetCurrentCineFrame(void);

View file

@ -63,7 +63,6 @@ typedef struct {
typedef struct {
int16_t frame_idx;
int16_t frame_count;
CINE_FRAME *frames;
struct {
XYZ_32 pos;
XYZ_16 rot;

View file

@ -81,6 +81,7 @@ sources = [
'game/anims/commands.c',
'game/anims/common.c',
'game/anims/frames.c',
'game/camera/cinematic.c',
'game/camera/photo_mode.c',
'game/camera/vars.c',
'game/clock/common.c',

View file

@ -815,11 +815,11 @@ void Camera_Update(void)
void Camera_UpdateCutscene(void)
{
if (g_CineData.frames == nullptr) {
if (g_CineData.frame_count == 0) {
return;
}
const CINE_FRAME *const ref = &g_CineData.frames[g_CineData.frame_idx];
const CINE_FRAME *const ref = Camera_GetCurrentCineFrame();
const int32_t c = Math_Cos(g_CineData.position.rot.y);
const int32_t s = Math_Sin(g_CineData.position.rot.y);
const XYZ_32 *const pos = &g_CineData.position.pos;

View file

@ -667,22 +667,19 @@ static void M_LoadItems(VFILE *file)
static void M_LoadCinematic(VFILE *file)
{
BENCHMARK *const benchmark = Benchmark_Start();
g_CineData.frame_count = VFile_ReadS16(file);
LOG_INFO("%d cinematic frames", g_CineData.frame_count);
if (g_CineData.frame_count != 0) {
g_CineData.frames = GameBuf_Alloc(
sizeof(CINE_FRAME) * g_CineData.frame_count, GBUF_CINEMATIC_FRAMES);
for (int32_t i = 0; i < g_CineData.frame_count; i++) {
CINE_FRAME *const frame = &g_CineData.frames[i];
frame->tx = VFile_ReadS16(file);
frame->ty = VFile_ReadS16(file);
frame->tz = VFile_ReadS16(file);
frame->cx = VFile_ReadS16(file);
frame->cy = VFile_ReadS16(file);
frame->cz = VFile_ReadS16(file);
frame->fov = VFile_ReadS16(file);
frame->roll = VFile_ReadS16(file);
}
const int16_t num_frames = VFile_ReadS16(file);
LOG_INFO("%d cinematic frames", num_frames);
Camera_InitialiseCineFrames(num_frames);
for (int32_t i = 0; i < num_frames; i++) {
CINE_FRAME *const frame = Camera_GetCineFrame(i);
frame->tx = VFile_ReadS16(file);
frame->ty = VFile_ReadS16(file);
frame->tz = VFile_ReadS16(file);
frame->cx = VFile_ReadS16(file);
frame->cy = VFile_ReadS16(file);
frame->cz = VFile_ReadS16(file);
frame->fov = VFile_ReadS16(file);
frame->roll = VFile_ReadS16(file);
}
Benchmark_End(benchmark, nullptr);
}

View file

@ -857,12 +857,16 @@ void Camera_Update(void)
void Camera_LoadCutsceneFrame(void)
{
if (g_CineData.frame_count == 0) {
return;
}
g_CineData.frame_idx++;
if (g_CineData.frame_idx >= g_CineData.frame_count) {
g_CineData.frame_idx = g_CineData.frame_count - 1;
}
const CINE_FRAME *frame = &g_CineData.frames[g_CineData.frame_idx];
const CINE_FRAME *frame = Camera_GetCurrentCineFrame();
int32_t tx = frame->tx;
int32_t ty = frame->ty;
int32_t tz = frame->tz;
@ -912,7 +916,11 @@ void Camera_LoadCutsceneFrame(void)
void Camera_UpdateCutscene(void)
{
const CINE_FRAME *const frame = &g_CineData.frames[g_CineData.frame_idx];
if (g_CineData.frame_count == 0) {
return;
}
const CINE_FRAME *const frame = Camera_GetCurrentCineFrame();
int32_t tx = frame->tx;
int32_t ty = frame->ty;
int32_t tz = frame->tz;

View file

@ -457,15 +457,11 @@ static void M_LoadAnimatedTextures(VFILE *const file)
static void M_LoadCinematic(VFILE *const file)
{
BENCHMARK *const benchmark = Benchmark_Start();
g_CineData.frame_count = VFile_ReadS16(file);
if (g_CineData.frame_count <= 0) {
goto finish;
}
g_CineData.frames = GameBuf_Alloc(
sizeof(CINE_FRAME) * g_CineData.frame_count, GBUF_CINEMATIC_FRAMES);
for (int32_t i = 0; i < g_CineData.frame_count; i++) {
CINE_FRAME *const frame = &g_CineData.frames[i];
const int16_t num_frames = VFile_ReadS16(file);
LOG_INFO("%d cinematic frames", num_frames);
Camera_InitialiseCineFrames(num_frames);
for (int32_t i = 0; i < num_frames; i++) {
CINE_FRAME *const frame = Camera_GetCineFrame(i);
frame->tx = VFile_ReadS16(file);
frame->ty = VFile_ReadS16(file);
frame->tz = VFile_ReadS16(file);
@ -475,8 +471,6 @@ static void M_LoadCinematic(VFILE *const file)
frame->fov = VFile_ReadS16(file);
frame->roll = VFile_ReadS16(file);
}
finish:
Benchmark_End(benchmark, nullptr);
}