frame interp camera cleanups

This commit is contained in:
Jasper St. Pierre
2026-04-19 02:25:00 -07:00
parent 341e97ba82
commit bb9a88d7dc
7 changed files with 84 additions and 57 deletions
+6 -7
View File
@@ -1,5 +1,4 @@
#ifndef DUSK_FRAME_INTERP_H
#define DUSK_FRAME_INTERP_H
#pragma once
#include <dolphin/mtx.h>
#include <stdbool.h>
@@ -7,6 +6,7 @@
#include <stdint.h>
class camera_process_class;
class view_class;
#ifdef __cplusplus
namespace dusk {
@@ -16,7 +16,8 @@ void ensure_initialized();
void begin_record();
void end_record();
void interpolate(float step);
void begin_frame(bool is_sim_frame, float step);
void interpolate();
float get_interpolation_step();
void request_presentation_sync();
@@ -29,14 +30,14 @@ void set_ui_tick_pending(bool value);
bool get_ui_tick_pending();
void record_camera(::camera_process_class* cam, int camera_id);
void interp_view(::view_class* view);
void record_final_mtx(Mtx m, const void *key);
void record_final_mtx(Mtx m);
bool lookup_replacement(const void* key, Mtx out);
bool lookup_concat_replacement(const void* lhs, const void* rhs, Mtx out);
typedef void (*InterpolationCallBack)(void* pUserWork);
void reset_interpolation_callbacks();
typedef void (*InterpolationCallBack)(bool isSimFrame, void* pUserWork);
// call on a sim tick, will get called during presentation
void add_interpolation_callback(InterpolationCallBack pCallBack, void* pUserWork);
@@ -55,5 +56,3 @@ struct PresentationCameraScope {
} // namespace frame_interp
} // namespace dusk
#endif
#endif
@@ -80,7 +80,7 @@ public:
virtual ~J3DModel() {}
#if TARGET_PC
static void interp_callback(void* pUserWork);
static void interp_callback(bool isSimFrame, void* pUserWork);
#endif
J3DModelData* getModelData() { return mModelData; }
@@ -98,10 +98,12 @@ s32 J3DModel::entryModelData(J3DModelData* pModelData, u32 mdlFlags, u32 mtxNum)
}
#if TARGET_PC
void J3DModel::interp_callback(void* pUserWork) {
void J3DModel::interp_callback(bool isSimFrame, void* pUserWork) {
J3DModel* i_this = static_cast<J3DModel*>(pUserWork);
i_this->calcMaterial();
i_this->diff();
if (!isSimFrame) {
i_this->calcMaterial();
i_this->diff();
}
}
#endif
+9 -3
View File
@@ -11009,6 +11009,15 @@ static int camera_execute(camera_process_class* i_this) {
i_this->mCamera.CalcTrimSize();
store(i_this);
#ifdef TARGET_PC
// record new camera for our sim frame
dusk::frame_interp::record_camera(i_this, get_camera_id(i_this));
// interpolate the view now so that this sim frame's view matrix matches what
// we'll be rendering with later
dusk::frame_interp::interp_view(&i_this->view);
#endif
view_setup(i_this);
return 1;
}
@@ -11077,9 +11086,6 @@ static int camera_draw(camera_process_class* i_this) {
C_MTXPerspective(process->view.projMtx, process->view.fovy, process->view.aspect, process->view.near_, process->view.far_);
mDoMtx_lookAt(process->view.viewMtx, &process->view.lookat.eye, &process->view.lookat.center,
&process->view.lookat.up, process->view.bank);
#ifdef TARGET_PC
dusk::frame_interp::record_camera(process, camera_id);
#endif
#if WIDESCREEN_SUPPORT
mDoGph_gInf_c::setWideZoomProjection(process->view.projMtx);
+13
View File
@@ -35,6 +35,7 @@
#if TARGET_PC
#include "dusk/imgui/ImGuiBloomWindow.hpp"
#include "dusk/settings.h"
#include "dusk/frame_interpolation.h"
#endif
static void GxXFog_set();
@@ -8105,11 +8106,23 @@ void dKankyo_HIO_c::genMessage(JORMContext* mctx) {
#endif
#if TARGET_PC
static void interp_callback(bool isSimFrame, void* pUserWork) {
if (!isSimFrame) {
g_env_light.drawKankyo();
}
}
#endif
void dScnKy_env_light_c::drawKankyo() {
setSunpos();
SetBaseLight();
setLight();
dKy_setLight_nowroom(g_env_light.PrevCol);
#if TARGET_PC
dusk::frame_interp::add_interpolation_callback(interp_callback, nullptr);
#endif
}
void dKy_undwater_filter_draw() {
+48 -41
View File
@@ -19,6 +19,7 @@ bool g_interpolating = false;
bool g_sync_presentation = false;
float g_step = 0.0f;
bool g_is_sim_frame = false;
bool g_ui_tick_pending = false;
Recording g_current_recording;
@@ -141,6 +142,14 @@ bool is_enabled() {
return g_enabled;
}
void begin_frame(bool is_sim_frame, float step) {
g_is_sim_frame = is_sim_frame;
g_step = std::clamp(step, 0.0f, 1.0f);
if (is_sim_frame) {
s_interpolationCallBackWork.clear();
}
}
void begin_record() {
ensure_initialized();
@@ -167,11 +176,6 @@ void begin_record() {
s_cam_prev.valid = false;
s_cam_curr.valid = false;
return;
} else {
copy_view_to_snap(&s_cam_prev, cam->view);
#if WIDESCREEN_SUPPORT
s_cam_prev.wideZoom = s_cam_curr.valid ? s_cam_curr.wideZoom : false;
#endif
}
}
@@ -179,10 +183,9 @@ void end_record() {
g_recording = false;
}
void interpolate(float step) {
void interpolate() {
ensure_initialized();
clear_replacements();
g_step = std::clamp(step, 0.0f, 1.0f);
g_interpolating = g_enabled && !g_recording && !g_sync_presentation && has_recording_data(g_current_recording);
if (!g_interpolating) {
return;
@@ -274,25 +277,56 @@ void record_camera(::camera_process_class* cam, int camera_id) {
if (!g_enabled || camera_id != 0 || cam == nullptr) {
return;
}
s_cam_prev = std::move(s_cam_curr);
copy_view_to_snap(&s_cam_curr, cam->view);
#if WIDESCREEN_SUPPORT
s_cam_curr.wideZoom = mDoGph_gInf_c::isWideZoom();
#endif
}
void interp_view(::view_class* view) {
const f32 step = get_interpolation_step();
cXyz eye;
cXyz center;
cXyz up;
lerp_xyz(&eye, s_cam_prev.eye, s_cam_curr.eye, step);
lerp_xyz(&center, s_cam_prev.center, s_cam_curr.center, step);
lerp_xyz(&up, s_cam_prev.up, s_cam_curr.up, step);
if (!up.normalizeRS()) {
up = s_cam_curr.up;
up.normalizeRS();
}
view->lookat.eye = eye;
view->lookat.center = center;
view->lookat.up = up;
view->bank = lerp_bank(s_cam_prev.bank, s_cam_curr.bank, step);
view->fovy = s_cam_prev.fovy + (s_cam_curr.fovy - s_cam_prev.fovy) * step;
view->aspect = s_cam_prev.aspect + (s_cam_curr.aspect - s_cam_prev.aspect) * step;
view->near_ = s_cam_prev.near_ + (s_cam_curr.near_ - s_cam_prev.near_) * step;
view->far_ = s_cam_prev.far_ + (s_cam_curr.far_ - s_cam_prev.far_) * step;
// FRAME INTERP TODO: It might be better if I rewired the game to not clear this flag until the
// next sim frame, but I don't care enough to right now
#if WIDESCREEN_SUPPORT
if (mDoGph_gInf_c::isWide() && !mDoGph_gInf_c::isWideZoom() && step >= 0.5f ?
s_cam_curr.wideZoom :
s_cam_prev.wideZoom)
{
mDoGph_gInf_c::onWideZoom();
}
#endif
}
static void run_interpolation_callbacks() {
for (size_t i = 0; i < s_interpolationCallBackWork.size(); i++) {
auto const& work = s_interpolationCallBackWork[i];
work.pCallBack(work.pUserWork);
work.pCallBack(g_is_sim_frame, work.pUserWork);
}
}
void reset_interpolation_callbacks() {
s_interpolationCallBackWork.clear();
}
void add_interpolation_callback(InterpolationCallBack pCallBack, void* pUserWork) {
if (!is_enabled() || s_presentation_depth > 0)
if (!is_enabled() || s_presentation_depth > 0 || !g_is_sim_frame)
return;
s_interpolationCallBackWork.emplace_back(pCallBack, pUserWork);
@@ -317,34 +351,7 @@ void begin_presentation_camera() {
}
std::memcpy(&s_presentation_view_backup, view, sizeof(view_class));
const f32 step = get_interpolation_step();
cXyz eye;
cXyz center;
cXyz up;
lerp_xyz(&eye, s_cam_prev.eye, s_cam_curr.eye, step);
lerp_xyz(&center, s_cam_prev.center, s_cam_curr.center, step);
lerp_xyz(&up, s_cam_prev.up, s_cam_curr.up, step);
if (!up.normalizeRS()) {
up = s_cam_curr.up;
up.normalizeRS();
}
view->lookat.eye = eye;
view->lookat.center = center;
view->lookat.up = up;
view->bank = lerp_bank(s_cam_prev.bank, s_cam_curr.bank, step);
view->fovy = s_cam_prev.fovy + (s_cam_curr.fovy - s_cam_prev.fovy) * step;
view->aspect = s_cam_prev.aspect + (s_cam_curr.aspect - s_cam_prev.aspect) * step;
view->near_ = s_cam_prev.near_ + (s_cam_curr.near_ - s_cam_prev.near_) * step;
view->far_ = s_cam_prev.far_ + (s_cam_curr.far_ - s_cam_prev.far_) * step;
// FRAME INTERP TODO: It might be better if I rewired the game to not clear this flag until the next sim frame, but I don't care enough to right now
#if WIDESCREEN_SUPPORT
if (mDoGph_gInf_c::isWide() && !mDoGph_gInf_c::isWideZoom() && step >= 0.5f ? s_cam_curr.wideZoom : s_cam_prev.wideZoom) {
mDoGph_gInf_c::onWideZoom();
}
#endif
interp_view(view);
// FRAME INTERP TODO: Largely copied from d_camera's camera_draw function from this point, got any better ideas?
C_MTXPerspective(view->projMtx, view->fovy, view->aspect, view->near_, view->far_);
+2 -2
View File
@@ -234,8 +234,8 @@ void main01(void) {
mDoGph_gInf_c::updateRenderSize();
if (pacing.is_interpolating) {
dusk::frame_interp::begin_frame(pacing.do_sim_tick, pacing.interpolation_step);
if (pacing.do_sim_tick) {
dusk::frame_interp::reset_interpolation_callbacks();
dusk::frame_interp::set_ui_tick_pending(true);
mDoCPd_c::read();
dusk::gyro::read(pacing.sim_pace);
@@ -243,7 +243,7 @@ void main01(void) {
mDoAud_Execute();
dusk::game_clock::reset_accumulator();
}
dusk::frame_interp::interpolate(pacing.interpolation_step);
dusk::frame_interp::interpolate();
{
dusk::frame_interp::PresentationCameraScope presentation_camera;
cAPIGph_Painter();