cutscene system
This commit is contained in:
115
src/cutscene.hh
Normal file
115
src/cutscene.hh
Normal file
@@ -0,0 +1,115 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <psyqo/fixed-point.hh>
|
||||
#include <psyqo/trigonometry.hh>
|
||||
#include <psyqo/soft-math.hh>
|
||||
|
||||
#include "camera.hh"
|
||||
#include "gameobject.hh"
|
||||
#include "audiomanager.hh"
|
||||
|
||||
namespace psxsplash {
|
||||
|
||||
static constexpr int MAX_CUTSCENES = 16;
|
||||
static constexpr int MAX_TRACKS = 8;
|
||||
static constexpr int MAX_KEYFRAMES = 64;
|
||||
static constexpr int MAX_AUDIO_EVENTS = 64;
|
||||
|
||||
enum class TrackType : uint8_t {
|
||||
CameraPosition = 0,
|
||||
CameraRotation = 1,
|
||||
ObjectPosition = 2,
|
||||
ObjectRotationY = 3,
|
||||
ObjectActive = 4,
|
||||
};
|
||||
|
||||
/// Per-keyframe interpolation mode.
|
||||
/// Packed into upper 3 bits of the frame field in CutsceneKeyframe.
|
||||
enum class InterpMode : uint8_t {
|
||||
Linear = 0, // Default linear interpolation
|
||||
Step = 1, // Instant jump (no interpolation)
|
||||
EaseIn = 2, // Slow start, fast end (quadratic)
|
||||
EaseOut = 3, // Fast start, slow end (quadratic)
|
||||
EaseInOut = 4, // Smooth start and end (smoothstep)
|
||||
};
|
||||
|
||||
struct CutsceneKeyframe {
|
||||
// Upper 3 bits = InterpMode (0-7), lower 13 bits = frame number (0-8191).
|
||||
// At 30fps, max frame 8191 ≈ 4.5 minutes.
|
||||
uint16_t frameAndInterp;
|
||||
int16_t values[3];
|
||||
|
||||
uint16_t getFrame() const { return frameAndInterp & 0x1FFF; }
|
||||
InterpMode getInterp() const { return static_cast<InterpMode>(frameAndInterp >> 13); }
|
||||
};
|
||||
static_assert(sizeof(CutsceneKeyframe) == 8, "CutsceneKeyframe must be 8 bytes");
|
||||
|
||||
struct CutsceneAudioEvent {
|
||||
uint16_t frame;
|
||||
uint8_t clipIndex;
|
||||
uint8_t volume;
|
||||
uint8_t pan;
|
||||
uint8_t pad[3];
|
||||
};
|
||||
static_assert(sizeof(CutsceneAudioEvent) == 8, "CutsceneAudioEvent must be 8 bytes");
|
||||
|
||||
struct CutsceneTrack {
|
||||
TrackType trackType;
|
||||
uint8_t keyframeCount;
|
||||
uint8_t pad[2];
|
||||
CutsceneKeyframe* keyframes; // Points into splashpack data (resolved at load time)
|
||||
GameObject* target; // nullptr = camera track
|
||||
|
||||
/// Initial values captured at play() time for pre-first-keyframe blending.
|
||||
/// For position tracks: fp12 x,y,z. For rotation tracks: raw angle values.
|
||||
/// For ObjectActive: values[0] = 1 (active) or 0 (inactive).
|
||||
int16_t initialValues[3];
|
||||
int16_t _initPad;
|
||||
};
|
||||
|
||||
struct Cutscene {
|
||||
const char* name; // Points into splashpack data
|
||||
uint16_t totalFrames;
|
||||
uint8_t trackCount;
|
||||
uint8_t audioEventCount;
|
||||
CutsceneTrack tracks[MAX_TRACKS];
|
||||
CutsceneAudioEvent* audioEvents; // Points into splashpack data
|
||||
};
|
||||
|
||||
/// Zero-allocation cutscene player. Call init() once after splashpack is loaded,
|
||||
/// then tick() once per frame from the scene loop.
|
||||
class CutscenePlayer {
|
||||
public:
|
||||
/// Initialize with loaded cutscene data. Safe to pass nullptr/0 if no cutscenes.
|
||||
void init(Cutscene* cutscenes, int count, Camera* camera, AudioManager* audio);
|
||||
|
||||
/// Play cutscene by name. Returns false if not found.
|
||||
bool play(const char* name);
|
||||
|
||||
/// Stop the current cutscene immediately.
|
||||
void stop();
|
||||
|
||||
/// True if a cutscene is currently active.
|
||||
bool isPlaying() const { return m_active != nullptr; }
|
||||
|
||||
/// Advance one frame. Call once per frame. Does nothing when idle.
|
||||
void tick();
|
||||
|
||||
private:
|
||||
Cutscene* m_cutscenes = nullptr;
|
||||
int m_count = 0;
|
||||
Cutscene* m_active = nullptr;
|
||||
uint16_t m_frame = 0;
|
||||
uint8_t m_nextAudio = 0;
|
||||
Camera* m_camera = nullptr;
|
||||
AudioManager* m_audio = nullptr;
|
||||
|
||||
psyqo::Trig<> m_trig;
|
||||
|
||||
void applyTrack(CutsceneTrack& track);
|
||||
void lerpKeyframes(CutsceneKeyframe* kf, uint8_t count, const int16_t initial[3], int16_t out[3]);
|
||||
void lerpAngles(CutsceneKeyframe* kf, uint8_t count, const int16_t initial[3], int16_t out[3]);
|
||||
};
|
||||
|
||||
} // namespace psxsplash
|
||||
Reference in New Issue
Block a user