Experimental interpolation (#309)

* Experimental 60 fps

* Fix compile error

* Fix compile error

* Fix compile error
This commit is contained in:
Emill 2022-05-14 00:43:55 +02:00 committed by GitHub
parent bcd57f45b2
commit 45e5e5ca72
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
43 changed files with 1206 additions and 49 deletions

View File

@ -190,8 +190,12 @@ static int game_framebuffer_msaa_resolved;
uint32_t gfx_msaa_level = 1;
static bool has_drawn_imgui_menu;
static bool dropped_frame;
static const std::unordered_map<Mtx *, MtxF> *current_mtx_replacements;
static float buf_vbo[MAX_BUFFERED * (32 * 3)]; // 3 vertices in a triangle and 32 floats per vtx
static size_t buf_vbo_len;
static size_t buf_vbo_num_tris;
@ -916,20 +920,31 @@ static void gfx_matrix_mul(float res[4][4], const float a[4][4], const float b[4
static void gfx_sp_matrix(uint8_t parameters, const int32_t *addr) {
float matrix[4][4];
#ifndef GBI_FLOATS
// Original GBI where fixed point matrices are used
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j += 2) {
int32_t int_part = addr[i * 2 + j / 2];
uint32_t frac_part = addr[8 + i * 2 + j / 2];
matrix[i][j] = (int32_t)((int_part & 0xffff0000) | (frac_part >> 16)) / 65536.0f;
matrix[i][j + 1] = (int32_t)((int_part << 16) | (frac_part & 0xffff)) / 65536.0f;
if (auto it = current_mtx_replacements->find((Mtx *)addr); it != current_mtx_replacements->end()) {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
float v = it->second.mf[i][j];
int as_int = (int)(v * 65536.0f);
matrix[i][j] = as_int * (1.0f / 65536.0f);
}
}
} else {
#ifndef GBI_FLOATS
// Original GBI where fixed point matrices are used
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j += 2) {
int32_t int_part = addr[i * 2 + j / 2];
uint32_t frac_part = addr[8 + i * 2 + j / 2];
matrix[i][j] = (int32_t)((int_part & 0xffff0000) | (frac_part >> 16)) / 65536.0f;
matrix[i][j + 1] = (int32_t)((int_part << 16) | (frac_part & 0xffff)) / 65536.0f;
}
}
}
#else
// For a modified GBI where fixed point values are replaced with floats
memcpy(matrix, addr, sizeof(matrix));
// For a modified GBI where fixed point values are replaced with floats
memcpy(matrix, addr, sizeof(matrix));
#endif
}
if (parameters & G_MTX_PROJECTION) {
if (parameters & G_MTX_LOAD) {
@ -2708,6 +2723,7 @@ void gfx_start_frame(void) {
gfx_wapi->handle_events();
gfx_wapi->get_dimensions(&gfx_current_window_dimensions.width, &gfx_current_window_dimensions.height);
SohImGui::DrawMainMenuAndCalculateGameSize();
has_drawn_imgui_menu = true;
if (gfx_current_dimensions.height == 0) {
// Avoid division by zero
gfx_current_dimensions.height = 1;
@ -2746,7 +2762,7 @@ void gfx_start_frame(void) {
fbActive = 0;
}
void gfx_run(Gfx *commands) {
void gfx_run(Gfx *commands, const std::unordered_map<Mtx *, MtxF>& mtx_replacements) {
gfx_sp_reset();
//puts("New frame");
@ -2755,12 +2771,21 @@ void gfx_run(Gfx *commands) {
if (!gfx_wapi->start_frame()) {
dropped_frame = true;
SohImGui::DrawFramebufferAndGameInput();
SohImGui::CancelFrame();
if (has_drawn_imgui_menu) {
SohImGui::DrawFramebufferAndGameInput();
SohImGui::CancelFrame();
has_drawn_imgui_menu = false;
}
return;
}
dropped_frame = false;
if (!has_drawn_imgui_menu) {
SohImGui::DrawMainMenuAndCalculateGameSize();
}
current_mtx_replacements = &mtx_replacements;
double t0 = gfx_wapi->get_time();
gfx_rapi->update_framebuffer_parameters(0, gfx_current_window_dimensions.width, gfx_current_window_dimensions.height, 1, false, true, true, !game_renders_to_framebuffer);
gfx_rapi->start_frame();
@ -2792,6 +2817,7 @@ void gfx_run(Gfx *commands) {
//printf("Process %f %f\n", t1, t1 - t0);
gfx_rapi->end_frame();
gfx_wapi->swap_buffers_begin();
has_drawn_imgui_menu = false;
}
void gfx_end_frame(void) {

View File

@ -6,6 +6,8 @@
#include <unordered_map>
#include <list>
#include "U64/PR/ultra64/types.h"
struct GfxRenderingAPI;
struct GfxWindowManagerAPI;
@ -52,26 +54,24 @@ struct TextureCacheValue {
#endif
};
#ifdef __cplusplus
extern "C" {
#endif
extern struct GfxDimensions gfx_current_window_dimensions; // The dimensions of the window
extern struct GfxDimensions gfx_current_dimensions; // The dimensions of the draw area the game draws to, before scaling (if applicable)
extern struct XYWidthHeight gfx_current_game_window_viewport; // The area of the window the game is drawn to, (0, 0) is top-left corner
extern uint32_t gfx_msaa_level;
}
void gfx_init(struct GfxWindowManagerAPI* wapi, struct GfxRenderingAPI* rapi, const char* game_name, bool start_in_fullscreen);
struct GfxRenderingAPI* gfx_get_current_rendering_api(void);
void gfx_start_frame(void);
void gfx_run(Gfx* commands);
void gfx_run(Gfx* commands, const std::unordered_map<Mtx*, MtxF>& mtx_replacements);
void gfx_end_frame(void);
void gfx_set_framedivisor(int);
void gfx_texture_cache_clear();
int gfx_create_framebuffer(uint32_t width, uint32_t height);
extern "C" int gfx_create_framebuffer(uint32_t width, uint32_t height);
void gfx_get_pixel_depth_prepare(float x, float y);
uint16_t gfx_get_pixel_depth(float x, float y);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -681,6 +681,7 @@ namespace SohImGui {
EXPERIMENTAL();
EnhancementCheckbox("60 fps interpolation", "g60FPS");
EnhancementCheckbox("Disable LOD", "gDisableLOD");
ImGui::EndMenu();

View File

@ -282,8 +282,12 @@ namespace Ship {
gfx_start_frame();
}
void Window::RunCommands(Gfx* Commands) {
gfx_run(Commands);
void Window::RunCommands(Gfx* Commands, const std::vector<std::unordered_map<Mtx*, MtxF>>& mtx_replacements) {
for (const auto& m : mtx_replacements) {
gfx_run(Commands, m);
gfx_end_frame();
}
gfx_run(Commands, {});
gfx_end_frame();
}

View File

@ -19,7 +19,7 @@ namespace Ship {
void MainLoop(void (*MainFunction)(void));
void Init();
void StartFrame();
void RunCommands(Gfx* Commands);
void RunCommands(Gfx* Commands, const std::vector<std::unordered_map<Mtx*, MtxF>>& mtx_replacements);
void SetFrameDivisor(int divisor);
void GetPixelDepthPrepare(float x, float y);
uint16_t GetPixelDepth(float x, float y);

View File

@ -138,6 +138,8 @@ extern GraphicsContext* __gfxCtx;
#ifndef NDEBUG
#define OPEN_DISPS(gfxCtx, file, line) \
{ \
void FrameInterpolation_RecordOpenChild(const void* a, int b); \
FrameInterpolation_RecordOpenChild(file, line); \
GraphicsContext* __gfxCtx; \
Gfx* dispRefs[4]; \
__gfxCtx = gfxCtx; \
@ -146,6 +148,8 @@ extern GraphicsContext* __gfxCtx;
#else
#define OPEN_DISPS(gfxCtx, file, line) \
{ \
void FrameInterpolation_RecordOpenChild(const void* a, int b); \
FrameInterpolation_RecordOpenChild(file, line); \
GraphicsContext* __gfxCtx; \
__gfxCtx = gfxCtx; \
(void)__gfxCtx;
@ -153,11 +157,15 @@ extern GraphicsContext* __gfxCtx;
#ifndef NDEBUG
#define CLOSE_DISPS(gfxCtx, file, line) \
{void FrameInterpolation_RecordCloseChild(void); \
FrameInterpolation_RecordCloseChild();} \
Graph_CloseDisps(dispRefs, gfxCtx, file, line); \
} \
(void)0
#else
#define CLOSE_DISPS(gfxCtx, file, line) \
{void FrameInterpolation_RecordCloseChild(void); \
FrameInterpolation_RecordCloseChild();} \
(void)0; \
} \
(void)0

View File

@ -225,6 +225,7 @@ typedef struct EffectSs {
/* 0x5C */ s16 life; // -1 means this entry is free
/* 0x5E */ u8 priority; // Lower value means higher priority
/* 0x5F */ u8 type;
u32 epoch;
} EffectSs; // size = 0x60
typedef struct {

View File

@ -173,6 +173,7 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="soh\frame_interpolation.cpp" />
<ClCompile Include="soh\Enhancements\bootcommands.c" />
<ClCompile Include="soh\Enhancements\debugconsole.cpp" />
<ClCompile Include="soh\Enhancements\debugger\colViewer.cpp" />
@ -878,6 +879,7 @@
<ClCompile Include="src\overlays\misc\ovl_map_mark_data\z_map_mark_data.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="soh\frame_interpolation.h" />
<ClInclude Include="include\alloca.h" />
<ClInclude Include="include\bgm.h" />
<ClInclude Include="include\color.h" />

View File

@ -2186,6 +2186,8 @@
</ClCompile>
<ClCompile Include="soh\Enhancements\debugger\ImGuiHelpers.cpp">
<Filter>Source Files\soh\Enhancements\debugger</Filter>
<ClCompile Include="soh\frame_interpolation.cpp">
<Filter>Source Files\soh</Filter>
</ClCompile>
<ClCompile Include="src\code\z_cheap_proc.c">
<Filter>Source Files</Filter>
@ -3748,6 +3750,8 @@
</ClInclude>
<ClInclude Include="soh\Enhancements\debugger\ImGuiHelpers.h">
<Filter>Header Files\soh\Enhancements\debugger</Filter>
<ClInclude Include="soh\frame_interpolation.h">
<Filter>Header Files\soh</Filter>
</ClInclude>
<ClInclude Include="soh\Enhancements\savestates.h">
<Filter>Source Files\soh\Enhancements</Filter>

View File

@ -1,6 +1,7 @@
#include "colViewer.h"
#include "../libultraship/SohImGuiImpl.h"
#include "ImGuiHelpers.h"
#include "../../frame_interpolation.h"
#include <vector>
#include <string>

View File

@ -29,6 +29,7 @@
#include "AudioPlayer.h"
#include "Enhancements/debugconsole.h"
#include "Enhancements/debugger/debugger.h"
#include "soh/frame_interpolation.h"
#include "Utils/BitConverter.h"
#include "variables.h"
#include "macros.h"
@ -174,7 +175,7 @@ extern "C" void Graph_StartFrame() {
// C->C++ Bridge
extern "C" void Graph_ProcessGfxCommands(Gfx* commands) {
OTRGlobals::Instance->context->GetWindow()->SetFrameDivisor(R_UPDATE_RATE);
OTRGlobals::Instance->context->GetWindow()->SetFrameDivisor(CVar_GetS32("g60FPS", 0) == 0 ? R_UPDATE_RATE : 1);
if (!audio.initialized) {
audio.initialized = true;
@ -224,7 +225,15 @@ extern "C" void Graph_ProcessGfxCommands(Gfx* commands) {
}
audio.cv_to_thread.notify_one();
OTRGlobals::Instance->context->GetWindow()->RunCommands(commands);
std::vector<std::unordered_map<Mtx*, MtxF>> mtx_replacements;
if (CVar_GetS32("g60FPS", 0) != 0) {
int to = R_UPDATE_RATE;
for (int i = 1; i < to; i++) {
mtx_replacements.push_back(FrameInterpolation_Interpolate(i / (float)to));
}
}
OTRGlobals::Instance->context->GetWindow()->RunCommands(commands, mtx_replacements);
{
std::unique_lock<std::mutex> Lock(audio.mutex);

View File

@ -0,0 +1,732 @@
#include "Cvar.h"
#include <vector>
#include <map>
#include <unordered_map>
#include <math.h>
#include "frame_interpolation.h"
/*
Frame interpolation.
The idea of this code is to interpolate all matrices.
The code contains two approaches. The first is to interpolate
all inputs in transformations, such as angles, scale and distances,
and then perform the same transformations with the interpolated values.
After evaluation for some reason some animations such rolling look strange.
The second approach is to simply interpolate the final matrices. This will
more or less simply interpolate the world coordinates for movements.
This will however make rotations ~180 degrees get the "paper effect".
The mitigation is to identify this case for actors and interpolate the
matrix but in model coordinates instead, by "removing" the rotation-
translation before interpolating, create a rotation matrix with the
interpolated angle which is then applied to the matrix.
Currently the code contains both methods but only the second one is currently
used.
Both approaches build a tree of instructions, containing matrices
at leaves. Every node is built from OPEN_DISPS/CLOSE_DISPS and manually
inserted FrameInterpolation_OpenChild/FrameInterpolation_Close child calls.
These nodes contain information that should suffice to identify the matrix,
so we can find it in an adjacent frame.
We can interpolate an arbitrary amount of frames between two original frames,
given a specific interpolation factor (0=old frame, 0.5=average of frames,
1.0=new frame).
*/
extern "C" {
void Matrix_Init(struct GameState* gameState);
void Matrix_Push(void);
void Matrix_Pop(void);
void Matrix_Get(MtxF* dest);
void Matrix_Put(MtxF* src);
void Matrix_Mult(MtxF* mf, u8 mode);
void Matrix_Translate(f32 x, f32 y, f32 z, u8 mode);
void Matrix_Scale(f32 x, f32 y, f32 z, u8 mode);
void Matrix_RotateX(f32 x, u8 mode);
void Matrix_RotateY(f32 y, u8 mode);
void Matrix_RotateZ(f32 z, u8 mode);
void Matrix_RotateZYX(s16 x, s16 y, s16 z, u8 mode);
void Matrix_TranslateRotateZYX(Vec3f* translation, Vec3s* rotation);
void Matrix_SetTranslateRotateYXZ(f32 translateX, f32 translateY, f32 translateZ, Vec3s* rot);
Mtx* Matrix_MtxFToMtx(MtxF* src, Mtx* dest);
Mtx* Matrix_ToMtx(Mtx* dest, char* file, s32 line);
Mtx* Matrix_NewMtx(struct GraphicsContext* gfxCtx, char* file, s32 line);
Mtx* Matrix_MtxFToNewMtx(MtxF* src, struct GraphicsContext* gfxCtx);
void Matrix_MultVec3f(Vec3f* src, Vec3f* dest);
void Matrix_MtxFCopy(MtxF* dest, MtxF* src);
void Matrix_MtxToMtxF(Mtx* src, MtxF* dest);
void Matrix_MultVec3fExt(Vec3f* src, Vec3f* dest, MtxF* mf);
void Matrix_Transpose(MtxF* mf);
void Matrix_ReplaceRotation(MtxF* mf);
void Matrix_MtxFToYXZRotS(MtxF* mf, Vec3s* rotDest, s32 flag);
void Matrix_MtxFToZYXRotS(MtxF* mf, Vec3s* rotDest, s32 flag);
void Matrix_RotateAxis(f32 angle, Vec3f* axis, u8 mode);
MtxF* Matrix_CheckFloats(MtxF* mf, char* file, s32 line);
void Matrix_SetTranslateScaleMtx2(Mtx* mtx, f32 scaleX, f32 scaleY, f32 scaleZ, f32 translateX, f32 translateY,
f32 translateZ);
MtxF* Matrix_GetCurrent(void);
void SkinMatrix_MtxFMtxFMult(MtxF* mfA, MtxF* mfB, MtxF* dest);
}
static bool invert_matrix(const float m[16], float invOut[16]);
using namespace std;
namespace {
enum class Op {
OpenChild,
CloseChild,
MatrixPush,
MatrixPop,
MatrixPut,
MatrixMult,
MatrixTranslate,
MatrixScale,
MatrixRotate1Coord,
MatrixRotateZYX,
MatrixTranslateRotateZYX,
MatrixSetTranslateRotateYXZ,
MatrixMtxFToMtx,
MatrixToMtx,
MatrixReplaceRotation,
MatrixRotateAxis,
SkinMatrixMtxFToMtx
};
typedef pair<const void*, int> label;
union Data {
Data() {
}
struct {
MtxF src;
} matrix_put;
struct {
MtxF mf;
u8 mode;
} matrix_mult;
struct {
f32 x, y, z;
u8 mode;
} matrix_translate, matrix_scale;
struct {
u32 coord;
f32 value;
u8 mode;
} matrix_rotate_1_coord;
struct {
s16 x, y, z;
u8 mode;
} matrix_rotate_zyx;
struct {
Vec3f translation;
Vec3s rotation;
} matrix_translate_rotate_zyx;
struct {
f32 translateX, translateY, translateZ;
Vec3s rot;
//MtxF mtx;
bool has_mtx;
} matrix_set_translate_rotate_yxz;
struct {
MtxF src;
Mtx* dest;
} matrix_mtxf_to_mtx;
struct {
Mtx* dest;
MtxF src;
bool has_adjusted;
} matrix_to_mtx;
struct {
MtxF mf;
} matrix_replace_rotation;
struct {
f32 angle;
Vec3f axis;
u8 mode;
} matrix_rotate_axis;
struct {
label key;
size_t idx;
} open_child;
};
struct Path {
map<label, vector<Path>> children;
map<Op, vector<Data>> ops;
vector<pair<Op, size_t>> items;
};
struct Recording {
Path root_path;
};
bool is_recording;
vector<Path*> current_path;
uint32_t camera_epoch;
uint32_t previous_camera_epoch;
Recording current_recording;
Recording previous_recording;
bool next_is_actor_pos_rot_matrix;
bool has_inv_actor_mtx;
MtxF inv_actor_mtx;
size_t inv_actor_mtx_path_index;
Data& append(Op op) {
auto& m = current_path.back()->ops[op];
current_path.back()->items.emplace_back(op, m.size());
return m.emplace_back();
}
struct InterpolateCtx {
float step;
float w;
unordered_map<Mtx*, MtxF> mtx_replacements;
MtxF tmp_mtxf, tmp_mtxf2;
Vec3f tmp_vec3f;
Vec3s tmp_vec3s;
MtxF actor_mtx;
MtxF* new_replacement(Mtx* addr) {
return &mtx_replacements[addr];
}
void interpolate_mtxf(MtxF* res, MtxF* o, MtxF* n) {
for (size_t i = 0; i < 4; i++) {
for (size_t j = 0; j < 4; j++) {
res->mf[i][j] = w * o->mf[i][j] + step * n->mf[i][j];
}
}
}
float lerp(f32 o, f32 n) {
return w * o + step * n;
}
void lerp_vec3f(Vec3f* res, Vec3f* o, Vec3f* n) {
res->x = lerp(o->x, n->x);
res->y = lerp(o->y, n->y);
res->z = lerp(o->z, n->z);
}
float interpolate_angle(f32 o, f32 n) {
if (o == n)
return n;
o = fmodf(o, 2 * M_PI);
if (o < 0.0f) {
o += 2 * M_PI;
}
n = fmodf(n, 2 * M_PI);
if (n < 0.0f) {
n += 2 * M_PI;
}
if (fabsf(o - n) > M_PI) {
if (o < n) {
o += 2 * M_PI;
} else {
n += 2 * M_PI;
}
}
if (fabsf(o - n) > M_PI / 2) {
//return n;
}
return lerp(o, n);
}
s16 interpolate_angle(s16 os, s16 ns) {
if (os == ns)
return ns;
int o = (u16)os;
int n = (u16)ns;
u16 res;
int diff = o - n;
if (-0x8000 <= diff && diff <= 0x8000) {
if (diff < -0x4000 || diff > 0x4000) {
return ns;
}
res = (u16)(w * o + step * n);
} else {
if (o < n) {
o += 0x10000;
} else {
n += 0x10000;
}
diff = o - n;
if (diff < -0x4000 || diff > 0x4000) {
return ns;
}
res = (u16)(w * o + step * n);
}
if (os / 327 == ns / 327 && (s16)res / 327 != os / 327) {
int bp = 0;
}
return res;
}
void interpolate_angles(Vec3s* res, Vec3s* o, Vec3s* n) {
res->x = interpolate_angle(o->x, n->x);
res->y = interpolate_angle(o->y, n->y);
res->z = interpolate_angle(o->z, n->z);
}
void interpolate_branch(Path* old_path, Path *new_path) {
for (auto& item : new_path->items) {
Data& new_op = new_path->ops[item.first][item.second];
if (item.first == Op::OpenChild) {
if (auto it = old_path->children.find(new_op.open_child.key);
it != old_path->children.end() && new_op.open_child.idx < it->second.size()) {
interpolate_branch(&it->second[new_op.open_child.idx],
&new_path->children.find(new_op.open_child.key)->second[new_op.open_child.idx]);
} else {
interpolate_branch(
&new_path->children.find(new_op.open_child.key)->second[new_op.open_child.idx],
&new_path->children.find(new_op.open_child.key)->second[new_op.open_child.idx]);
}
continue;
}
if (auto it = old_path->ops.find(item.first); it != old_path->ops.end()) {
if (item.second < it->second.size()) {
Data& old_op = it->second[item.second];
switch (item.first) {
case Op::OpenChild:
break;
case Op::CloseChild:
break;
case Op::MatrixPush:
Matrix_Push();
break;
case Op::MatrixPop:
Matrix_Pop();
break;
case Op::MatrixPut:
interpolate_mtxf(&tmp_mtxf, &old_op.matrix_put.src, &new_op.matrix_put.src);
Matrix_Put(&tmp_mtxf);
break;
case Op::MatrixMult:
interpolate_mtxf(&tmp_mtxf, &old_op.matrix_mult.mf, &new_op.matrix_mult.mf);
Matrix_Mult(&tmp_mtxf, new_op.matrix_mult.mode);
break;
case Op::MatrixTranslate:
Matrix_Translate(lerp(old_op.matrix_translate.x, new_op.matrix_translate.x),
lerp(old_op.matrix_translate.y, new_op.matrix_translate.y),
lerp(old_op.matrix_translate.z, new_op.matrix_translate.z),
new_op.matrix_translate.mode);
break;
case Op::MatrixScale:
Matrix_Scale(lerp(old_op.matrix_scale.x, new_op.matrix_scale.x),
lerp(old_op.matrix_scale.y, new_op.matrix_scale.y),
lerp(old_op.matrix_scale.z, new_op.matrix_scale.z),
new_op.matrix_scale.mode);
break;
case Op::MatrixRotate1Coord: {
float v = interpolate_angle(old_op.matrix_rotate_1_coord.value, new_op.matrix_rotate_1_coord.value);
u8 mode = new_op.matrix_rotate_1_coord.mode;
switch (new_op.matrix_rotate_1_coord.coord) {
case 0:
Matrix_RotateX(v, mode);
break;
case 1:
Matrix_RotateY(v, mode);
break;
case 2:
Matrix_RotateZ(v, mode);
break;
}
break;
}
case Op::MatrixRotateZYX:
Matrix_RotateZYX(interpolate_angle(old_op.matrix_rotate_zyx.x, new_op.matrix_rotate_zyx.x),
interpolate_angle(old_op.matrix_rotate_zyx.y, new_op.matrix_rotate_zyx.y),
interpolate_angle(old_op.matrix_rotate_zyx.z, new_op.matrix_rotate_zyx.z),
new_op.matrix_rotate_zyx.mode);
break;
case Op::MatrixTranslateRotateZYX:
lerp_vec3f(&tmp_vec3f, &old_op.matrix_translate_rotate_zyx.translation, &new_op.matrix_translate_rotate_zyx.translation);
interpolate_angles(&tmp_vec3s, &old_op.matrix_translate_rotate_zyx.rotation, &new_op.matrix_translate_rotate_zyx.rotation);
Matrix_TranslateRotateZYX(&tmp_vec3f, &tmp_vec3s);
break;
case Op::MatrixSetTranslateRotateYXZ:
interpolate_angles(&tmp_vec3s, &old_op.matrix_set_translate_rotate_yxz.rot,
&new_op.matrix_set_translate_rotate_yxz.rot);
Matrix_SetTranslateRotateYXZ(lerp(old_op.matrix_set_translate_rotate_yxz.translateX,
new_op.matrix_set_translate_rotate_yxz.translateX),
lerp(old_op.matrix_set_translate_rotate_yxz.translateY,
new_op.matrix_set_translate_rotate_yxz.translateY),
lerp(old_op.matrix_set_translate_rotate_yxz.translateZ,
new_op.matrix_set_translate_rotate_yxz.translateZ),
&tmp_vec3s);
if (new_op.matrix_set_translate_rotate_yxz.has_mtx && old_op.matrix_set_translate_rotate_yxz.has_mtx) {
actor_mtx = *Matrix_GetCurrent();
}
break;
case Op::MatrixMtxFToMtx:
interpolate_mtxf(new_replacement(new_op.matrix_mtxf_to_mtx.dest),
&old_op.matrix_mtxf_to_mtx.src, &new_op.matrix_mtxf_to_mtx.src);
break;
case Op::MatrixToMtx: {
//*new_replacement(new_op.matrix_to_mtx.dest) = *Matrix_GetCurrent();
if (old_op.matrix_to_mtx.has_adjusted && new_op.matrix_to_mtx.has_adjusted) {
interpolate_mtxf(&tmp_mtxf, &old_op.matrix_to_mtx.src, &new_op.matrix_to_mtx.src);
SkinMatrix_MtxFMtxFMult(&actor_mtx, &tmp_mtxf, new_replacement(new_op.matrix_to_mtx.dest));
} else {
interpolate_mtxf(new_replacement(new_op.matrix_to_mtx.dest),
&old_op.matrix_to_mtx.src, &new_op.matrix_to_mtx.src);
}
break;
}
case Op::MatrixReplaceRotation:
interpolate_mtxf(&tmp_mtxf, &old_op.matrix_replace_rotation.mf, &new_op.matrix_replace_rotation.mf);
Matrix_ReplaceRotation(&tmp_mtxf);
break;
case Op::MatrixRotateAxis:
lerp_vec3f(&tmp_vec3f, &old_op.matrix_rotate_axis.axis, &new_op.matrix_rotate_axis.axis);
Matrix_RotateAxis(interpolate_angle(old_op.matrix_rotate_axis.angle, new_op.matrix_rotate_axis.angle),
&tmp_vec3f, new_op.matrix_rotate_axis.mode);
break;
case Op::SkinMatrixMtxFToMtx:
break;
}
}
}
}
}
};
} // anonymous namespace
unordered_map<Mtx*, MtxF> FrameInterpolation_Interpolate(float step) {
InterpolateCtx ctx;
ctx.step = step;
ctx.w = 1.0f - step;
ctx.interpolate_branch(&previous_recording.root_path, &current_recording.root_path);
return ctx.mtx_replacements;
}
void FrameInterpolation_StartRecord(void) {
previous_recording = move(current_recording);
current_recording = {};
current_path.clear();
current_path.push_back(&current_recording.root_path);
if (CVar_GetS32("g60FPS", 0) != 0) {
is_recording = true;
}
}
void FrameInterpolation_StopRecord(void) {
previous_camera_epoch = camera_epoch;
is_recording = false;
}
void FrameInterpolation_RecordOpenChild(const void* a, int b) {
if (!is_recording)
return;
label key = { a, b };
auto& m = current_path.back()->children[key];
append(Op::OpenChild).open_child = { key, m.size() };
current_path.push_back(&m.emplace_back());
}
void FrameInterpolation_RecordCloseChild(void) {
if (!is_recording)
return;
//append(Op::CloseChild);
if (has_inv_actor_mtx && current_path.size() == inv_actor_mtx_path_index) {
has_inv_actor_mtx = false;
}
current_path.pop_back();
}
void FrameInterpolation_DontInterpolateCamera(void) {
camera_epoch = previous_camera_epoch + 1;
}
int FrameInterpolation_GetCameraEpoch(void) {
return (int)camera_epoch;
}
void FrameInterpolation_RecordActorPosRotMatrix(void) {
if (!is_recording)
return;
next_is_actor_pos_rot_matrix = true;
}
void FrameInterpolation_RecordMatrixPush(void) {
if (!is_recording)
return;
append(Op::MatrixPush);
}
void FrameInterpolation_RecordMatrixPop(void) {
if (!is_recording)
return;
append(Op::MatrixPop);
}
void FrameInterpolation_RecordMatrixPut(MtxF* src) {
if (!is_recording)
return;
append(Op::MatrixPut).matrix_put = { *src };
}
void FrameInterpolation_RecordMatrixMult(MtxF* mf, u8 mode) {
if (!is_recording)
return;
append(Op::MatrixMult).matrix_mult = { *mf, mode };
}
void FrameInterpolation_RecordMatrixTranslate(f32 x, f32 y, f32 z, u8 mode) {
if (!is_recording)
return;
append(Op::MatrixTranslate).matrix_translate = { x, y, z, mode };
}
void FrameInterpolation_RecordMatrixScale(f32 x, f32 y, f32 z, u8 mode) {
if (!is_recording)
return;
append(Op::MatrixScale).matrix_scale = { x, y, z, mode };
}
void FrameInterpolation_RecordMatrixRotate1Coord(u32 coord, f32 value, u8 mode) {
if (!is_recording)
return;
append(Op::MatrixRotate1Coord).matrix_rotate_1_coord = { coord, value, mode };
}
void FrameInterpolation_RecordMatrixRotateZYX(s16 x, s16 y, s16 z, u8 mode) {
if (!is_recording)
return;
append(Op::MatrixRotateZYX).matrix_rotate_zyx = { x, y, z, mode };
}
void FrameInterpolation_RecordMatrixTranslateRotateZYX(Vec3f* translation, Vec3s* rotation) {
if (!is_recording)
return;
append(Op::MatrixTranslateRotateZYX).matrix_translate_rotate_zyx = { *translation, *rotation };
}
void FrameInterpolation_RecordMatrixSetTranslateRotateYXZ(f32 translateX, f32 translateY, f32 translateZ, Vec3s* rot) {
if (!is_recording)
return;
auto& d = append(Op::MatrixSetTranslateRotateYXZ).matrix_set_translate_rotate_yxz = { translateX, translateY, translateZ,
*rot };
if (next_is_actor_pos_rot_matrix) {
d.has_mtx = true;
//d.mtx = *Matrix_GetCurrent();
invert_matrix((const float *)Matrix_GetCurrent()->mf, (float *)inv_actor_mtx.mf);
next_is_actor_pos_rot_matrix = false;
has_inv_actor_mtx = true;
inv_actor_mtx_path_index = current_path.size();
}
}
void FrameInterpolation_RecordMatrixMtxFToMtx(MtxF* src, Mtx* dest) {
if (!is_recording)
return;
append(Op::MatrixMtxFToMtx).matrix_mtxf_to_mtx = { *src, dest };
}
void FrameInterpolation_RecordMatrixToMtx(Mtx* dest, char* file, s32 line) {
if (!is_recording)
return;
auto& d = append(Op::MatrixToMtx).matrix_to_mtx = { dest };
if (has_inv_actor_mtx) {
d.has_adjusted = true;
SkinMatrix_MtxFMtxFMult(&inv_actor_mtx, Matrix_GetCurrent(), &d.src);
} else {
d.src = *Matrix_GetCurrent();
}
}
void FrameInterpolation_RecordMatrixReplaceRotation(MtxF* mf) {
if (!is_recording)
return;
append(Op::MatrixReplaceRotation).matrix_replace_rotation = { *mf };
}
void FrameInterpolation_RecordMatrixRotateAxis(f32 angle, Vec3f* axis, u8 mode) {
if (!is_recording)
return;
append(Op::MatrixRotateAxis).matrix_rotate_axis = { angle, *axis, mode };
}
void FrameInterpolation_RecordSkinMatrixMtxFToMtx(MtxF* src, Mtx* dest) {
if (!is_recording)
return;
FrameInterpolation_RecordMatrixMtxFToMtx(src, dest);
}
// https://stackoverflow.com/questions/1148309/inverting-a-4x4-matrix
static bool invert_matrix(const float m[16], float invOut[16]) {
float inv[16], det;
int i;
inv[0] = m[5] * m[10] * m[15] -
m[5] * m[11] * m[14] -
m[9] * m[6] * m[15] +
m[9] * m[7] * m[14] +
m[13] * m[6] * m[11] -
m[13] * m[7] * m[10];
inv[4] = -m[4] * m[10] * m[15] +
m[4] * m[11] * m[14] +
m[8] * m[6] * m[15] -
m[8] * m[7] * m[14] -
m[12] * m[6] * m[11] +
m[12] * m[7] * m[10];
inv[8] = m[4] * m[9] * m[15] -
m[4] * m[11] * m[13] -
m[8] * m[5] * m[15] +
m[8] * m[7] * m[13] +
m[12] * m[5] * m[11] -
m[12] * m[7] * m[9];
inv[12] = -m[4] * m[9] * m[14] +
m[4] * m[10] * m[13] +
m[8] * m[5] * m[14] -
m[8] * m[6] * m[13] -
m[12] * m[5] * m[10] +
m[12] * m[6] * m[9];
inv[1] = -m[1] * m[10] * m[15] +
m[1] * m[11] * m[14] +
m[9] * m[2] * m[15] -
m[9] * m[3] * m[14] -
m[13] * m[2] * m[11] +
m[13] * m[3] * m[10];
inv[5] = m[0] * m[10] * m[15] -
m[0] * m[11] * m[14] -
m[8] * m[2] * m[15] +
m[8] * m[3] * m[14] +
m[12] * m[2] * m[11] -
m[12] * m[3] * m[10];
inv[9] = -m[0] * m[9] * m[15] +
m[0] * m[11] * m[13] +
m[8] * m[1] * m[15] -
m[8] * m[3] * m[13] -
m[12] * m[1] * m[11] +
m[12] * m[3] * m[9];
inv[13] = m[0] * m[9] * m[14] -
m[0] * m[10] * m[13] -
m[8] * m[1] * m[14] +
m[8] * m[2] * m[13] +
m[12] * m[1] * m[10] -
m[12] * m[2] * m[9];
inv[2] = m[1] * m[6] * m[15] -
m[1] * m[7] * m[14] -
m[5] * m[2] * m[15] +
m[5] * m[3] * m[14] +
m[13] * m[2] * m[7] -
m[13] * m[3] * m[6];
inv[6] = -m[0] * m[6] * m[15] +
m[0] * m[7] * m[14] +
m[4] * m[2] * m[15] -
m[4] * m[3] * m[14] -
m[12] * m[2] * m[7] +
m[12] * m[3] * m[6];
inv[10] = m[0] * m[5] * m[15] -
m[0] * m[7] * m[13] -
m[4] * m[1] * m[15] +
m[4] * m[3] * m[13] +
m[12] * m[1] * m[7] -
m[12] * m[3] * m[5];
inv[14] = -m[0] * m[5] * m[14] +
m[0] * m[6] * m[13] +
m[4] * m[1] * m[14] -
m[4] * m[2] * m[13] -
m[12] * m[1] * m[6] +
m[12] * m[2] * m[5];
inv[3] = -m[1] * m[6] * m[11] +
m[1] * m[7] * m[10] +
m[5] * m[2] * m[11] -
m[5] * m[3] * m[10] -
m[9] * m[2] * m[7] +
m[9] * m[3] * m[6];
inv[7] = m[0] * m[6] * m[11] -
m[0] * m[7] * m[10] -
m[4] * m[2] * m[11] +
m[4] * m[3] * m[10] +
m[8] * m[2] * m[7] -
m[8] * m[3] * m[6];
inv[11] = -m[0] * m[5] * m[11] +
m[0] * m[7] * m[9] +
m[4] * m[1] * m[11] -
m[4] * m[3] * m[9] -
m[8] * m[1] * m[7] +
m[8] * m[3] * m[5];
inv[15] = m[0] * m[5] * m[10] -
m[0] * m[6] * m[9] -
m[4] * m[1] * m[10] +
m[4] * m[2] * m[9] +
m[8] * m[1] * m[6] -
m[8] * m[2] * m[5];
det = m[0] * inv[0] + m[1] * inv[4] + m[2] * inv[8] + m[3] * inv[12];
if (det == 0) {
return false;
}
det = 1.0 / det;
for (i = 0; i < 16; i++) {
invOut[i] = inv[i] * det;
}
return true;
}

View File

@ -0,0 +1,61 @@
#pragma once
#include "include/z64math.h"
#ifdef __cplusplus
#include <unordered_map>
std::unordered_map<Mtx*, MtxF> FrameInterpolation_Interpolate(float step);
extern "C" {
#endif
void FrameInterpolation_StartRecord(void);
void FrameInterpolation_StopRecord(void);
void FrameInterpolation_RecordOpenChild(const void* a, int b);
void FrameInterpolation_RecordCloseChild(void);
void FrameInterpolation_DontInterpolateCamera(void);
int FrameInterpolation_GetCameraEpoch(void);
void FrameInterpolation_RecordActorPosRotMatrix(void);
void FrameInterpolation_RecordMatrixPush(void);
void FrameInterpolation_RecordMatrixPop(void);
void FrameInterpolation_RecordMatrixPut(MtxF* src);
void FrameInterpolation_RecordMatrixMult(MtxF* mf, u8 mode);
void FrameInterpolation_RecordMatrixTranslate(f32 x, f32 y, f32 z, u8 mode);
void FrameInterpolation_RecordMatrixScale(f32 x, f32 y, f32 z, u8 mode);
void FrameInterpolation_RecordMatrixRotate1Coord(u32 coord, f32 value, u8 mode);
void FrameInterpolation_RecordMatrixRotateZYX(s16 x, s16 y, s16 z, u8 mode);
void FrameInterpolation_RecordMatrixTranslateRotateZYX(Vec3f* translation, Vec3s* rotation);
void FrameInterpolation_RecordMatrixSetTranslateRotateYXZ(f32 translateX, f32 translateY, f32 translateZ, Vec3s* rot);
void FrameInterpolation_RecordMatrixMtxFToMtx(MtxF* src, Mtx* dest);
void FrameInterpolation_RecordMatrixToMtx(Mtx* dest, char* file, s32 line);
void FrameInterpolation_RecordMatrixReplaceRotation(MtxF* mf);
void FrameInterpolation_RecordMatrixRotateAxis(f32 angle, Vec3f* axis, u8 mode);
void FrameInterpolation_RecordSkinMatrixMtxFToMtx(MtxF* src, Mtx* dest);
#ifdef __cplusplus
}
#endif

View File

@ -1,5 +1,7 @@
#include "global.h"
#include "soh/frame_interpolation.h"
// clang-format off
Mtx gMtxClear = {
65536, 0, 1, 0,
@ -25,11 +27,13 @@ void Matrix_Init(GameState* gameState) {
}
void Matrix_Push(void) {
FrameInterpolation_RecordMatrixPush();
Matrix_MtxFCopy(sCurrentMatrix + 1, sCurrentMatrix);
sCurrentMatrix++;
}
void Matrix_Pop(void) {
FrameInterpolation_RecordMatrixPop();
sCurrentMatrix--;
ASSERT(sCurrentMatrix >= sMatrixStack, "Matrix_now >= Matrix_stack", "../sys_matrix.c", 176);
}
@ -39,6 +43,7 @@ void Matrix_Get(MtxF* dest) {
}
void Matrix_Put(MtxF* src) {
FrameInterpolation_RecordMatrixPut(src);
Matrix_MtxFCopy(sCurrentMatrix, src);
}
@ -47,6 +52,7 @@ MtxF* Matrix_GetCurrent(void) {
}
void Matrix_Mult(MtxF* mf, u8 mode) {
FrameInterpolation_RecordMatrixMult(mf, mode);
MtxF* cmf = Matrix_GetCurrent();
if (mode == MTXMODE_APPLY) {
@ -57,6 +63,7 @@ void Matrix_Mult(MtxF* mf, u8 mode) {
}
void Matrix_Translate(f32 x, f32 y, f32 z, u8 mode) {
FrameInterpolation_RecordMatrixTranslate(x, y, z, mode);
MtxF* cmf = sCurrentMatrix;
f32 tx;
f32 ty;
@ -80,6 +87,7 @@ void Matrix_Translate(f32 x, f32 y, f32 z, u8 mode) {
}
void Matrix_Scale(f32 x, f32 y, f32 z, u8 mode) {
FrameInterpolation_RecordMatrixScale(x, y, z, mode);
MtxF* cmf = sCurrentMatrix;
if (mode == MTXMODE_APPLY) {
@ -101,6 +109,7 @@ void Matrix_Scale(f32 x, f32 y, f32 z, u8 mode) {
}
void Matrix_RotateX(f32 x, u8 mode) {
FrameInterpolation_RecordMatrixRotate1Coord(0, x, mode);
MtxF* cmf;
f32 sin;
f32 cos;
@ -165,6 +174,7 @@ void Matrix_RotateX(f32 x, u8 mode) {
}
void Matrix_RotateY(f32 y, u8 mode) {
FrameInterpolation_RecordMatrixRotate1Coord(1, y, mode);
MtxF* cmf;
f32 sin;
f32 cos;
@ -229,6 +239,7 @@ void Matrix_RotateY(f32 y, u8 mode) {
}
void Matrix_RotateZ(f32 z, u8 mode) {
FrameInterpolation_RecordMatrixRotate1Coord(2, z, mode);
MtxF* cmf;
f32 sin;
f32 cos;
@ -299,6 +310,7 @@ void Matrix_RotateZ(f32 z, u8 mode) {
* Original Name: Matrix_RotateXYZ, changed to reflect rotation order.
*/
void Matrix_RotateZYX(s16 x, s16 y, s16 z, u8 mode) {
FrameInterpolation_RecordMatrixRotateZYX(x, y, z, mode);
MtxF* cmf = sCurrentMatrix;
f32 temp1;
f32 temp2;
@ -389,6 +401,7 @@ void Matrix_RotateZYX(s16 x, s16 y, s16 z, u8 mode) {
* transformed according to whatever the matrix was previously.
*/
void Matrix_TranslateRotateZYX(Vec3f* translation, Vec3s* rotation) {
FrameInterpolation_RecordMatrixTranslateRotateZYX(translation, rotation);
MtxF* cmf = sCurrentMatrix;
f32 sin = Math_SinS(rotation->z);
f32 cos = Math_CosS(rotation->z);
@ -530,15 +543,20 @@ void Matrix_SetTranslateRotateYXZ(f32 translateX, f32 translateY, f32 translateZ
} else {
cmf->yx = 0.0f;
}
FrameInterpolation_RecordMatrixSetTranslateRotateYXZ(translateX, translateY, translateZ, rot);
}
Mtx* Matrix_MtxFToMtx(MtxF* src, Mtx* dest) {
FrameInterpolation_RecordMatrixMtxFToMtx(src, dest);
guMtxF2L(src, dest);
return dest;
}
Mtx* Matrix_ToMtx(Mtx* dest, char* file, s32 line) {
return Matrix_MtxFToMtx(Matrix_CheckFloats(sCurrentMatrix, file, line), dest);
FrameInterpolation_RecordMatrixToMtx(dest, file, line);
guMtxF2L(Matrix_CheckFloats(sCurrentMatrix, file, line), dest);
return dest;
//return Matrix_MtxFToMtx(Matrix_CheckFloats(sCurrentMatrix, file, line), dest);
}
Mtx* Matrix_NewMtx(GraphicsContext* gfxCtx, char* file, s32 line) {
@ -627,6 +645,7 @@ void Matrix_Transpose(MtxF* mf) {
* seen as replacing the R rotation with `mf`, hence the function name.
*/
void Matrix_ReplaceRotation(MtxF* mf) {
FrameInterpolation_RecordMatrixReplaceRotation(mf);
MtxF* cmf = sCurrentMatrix;
f32 acc;
f32 temp;
@ -779,6 +798,7 @@ void Matrix_MtxFToZYXRotS(MtxF* mf, Vec3s* rotDest, s32 flag) {
* NB: `axis` is assumed to be a unit vector.
*/
void Matrix_RotateAxis(f32 angle, Vec3f* axis, u8 mode) {
FrameInterpolation_RecordMatrixRotateAxis(angle, axis, mode);
MtxF* cmf;
f32 sin;
f32 cos;

View File

@ -6,6 +6,7 @@
#include "objects/gameplay_keep/gameplay_keep.h"
#include "objects/gameplay_dangeon_keep/gameplay_dangeon_keep.h"
#include "objects/object_bdoor/object_bdoor.h"
#include "soh/frame_interpolation.h"
#if defined(_MSC_VER) || defined(__GNUC__)
#include <string.h>
@ -410,6 +411,7 @@ void func_8002C124(TargetContext* targetCtx, GlobalContext* globalCtx) {
f32 var2;
s32 i;
FrameInterpolation_RecordOpenChild(actor, 0);
player = GET_PLAYER(globalCtx);
spCE = 0xFF;
@ -486,10 +488,12 @@ void func_8002C124(TargetContext* targetCtx, GlobalContext* globalCtx) {
}
}
}
FrameInterpolation_RecordCloseChild();
}
actor = targetCtx->unk_94;
if ((actor != NULL) && !(actor->flags & ACTOR_FLAG_27)) {
FrameInterpolation_RecordOpenChild(actor, 1);
NaviColor* naviColor = &sNaviColorList[actor->category];
POLY_XLU_DISP = Gfx_CallSetupDL(POLY_XLU_DISP, 0x7);
@ -503,6 +507,7 @@ void func_8002C124(TargetContext* targetCtx, GlobalContext* globalCtx) {
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_actor.c", 2153),
G_MTX_MODELVIEW | G_MTX_LOAD);
gSPDisplayList(POLY_XLU_DISP++, gZTargetArrowDL);
FrameInterpolation_RecordCloseChild();
}
CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_actor.c", 2158);
@ -2490,6 +2495,7 @@ void Actor_Draw(GlobalContext* globalCtx, Actor* actor) {
Fault_AddClient(&faultClient, Actor_FaultPrint, actor, "Actor_draw");
FrameInterpolation_RecordOpenChild(actor, 0);
OPEN_DISPS(globalCtx->state.gfxCtx, "../z_actor.c", 6035);
lights = LightContext_NewLights(&globalCtx->lightCtx, globalCtx->state.gfxCtx);
@ -2497,6 +2503,7 @@ void Actor_Draw(GlobalContext* globalCtx, Actor* actor) {
Lights_BindAll(lights, globalCtx->lightCtx.listHead, (actor->flags & ACTOR_FLAG_22) ? NULL : &actor->world.pos);
Lights_Draw(lights, globalCtx->state.gfxCtx);
FrameInterpolation_RecordActorPosRotMatrix();
if (actor->flags & ACTOR_FLAG_12) {
Matrix_SetTranslateRotateYXZ(
actor->world.pos.x + globalCtx->mainCamera.skyboxOffset.x,
@ -2546,6 +2553,7 @@ void Actor_Draw(GlobalContext* globalCtx, Actor* actor) {
}
CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_actor.c", 6119);
FrameInterpolation_RecordCloseChild();
Fault_RemoveClient(&faultClient);
}

View File

@ -6,6 +6,8 @@
#include "overlays/actors/ovl_En_Horse/z_en_horse.h"
#include "soh/frame_interpolation.h"
s16 Camera_ChangeSettingFlags(Camera* camera, s16 setting, s16 flags);
s32 Camera_ChangeModeFlags(Camera* camera, s16 mode, u8 flags);
s32 Camera_QRegInit(void);
@ -6675,6 +6677,7 @@ s32 Camera_Special9(Camera* camera) {
case 1:
spec9->doorParams.timer1--;
if (spec9->doorParams.timer1 <= 0) {
FrameInterpolation_DontInterpolateCamera();
camera->animState++;
if (params->interfaceFlags & 1) {
camPosData = Camera_GetCamBGData(camera);
@ -7968,6 +7971,8 @@ s32 Camera_SetCSParams(Camera* camera, CutsceneCameraPoint* atPoints, CutsceneCa
camera->speedRatio = 0.0f;
}
FrameInterpolation_DontInterpolateCamera();
return 1;
}

View File

@ -1,6 +1,8 @@
#include "global.h"
#include "objects/gameplay_keep/gameplay_keep.h"
#include "soh/frame_interpolation.h"
void EffectBlure_AddVertex(EffectBlure* this, Vec3f* p1, Vec3f* p2) {
EffectBlureElement* elem;
s32 numElements;
@ -946,6 +948,7 @@ void EffectBlure_Draw(void* thisx, GraphicsContext* gfxCtx) {
s32 j;
s32 phi_t2;
FrameInterpolation_RecordOpenChild(this, 0);
OPEN_DISPS(gfxCtx, "../z_eff_blure.c", 1596);
gSPMatrix(POLY_XLU_DISP++, &gMtxClear, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
@ -1059,4 +1062,5 @@ void EffectBlure_Draw(void* thisx, GraphicsContext* gfxCtx) {
}
CLOSE_DISPS(gfxCtx, "../z_eff_blure.c", 1823);
FrameInterpolation_RecordCloseChild();
}

View File

@ -2,6 +2,8 @@
#include "vt.h"
#include "objects/gameplay_keep/gameplay_keep.h"
#include "soh/frame_interpolation.h"
static Vtx sVertices[5] = {
VTX(-32, -32, 0, 0, 1024, 0xFF, 0xFF, 0xFF, 0xFF),
VTX(32, 32, 0, 1024, 0, 0xFF, 0xFF, 0xFF, 0xFF),
@ -154,6 +156,7 @@ void EffectShieldParticle_Draw(void* thisx, GraphicsContext* gfxCtx) {
Color_RGBA8 primColor;
Color_RGBA8 envColor;
FrameInterpolation_RecordOpenChild(this, 0);
OPEN_DISPS(gfxCtx, "../z_eff_shield_particle.c", 272);
if (this != NULL) {
@ -213,4 +216,5 @@ void EffectShieldParticle_Draw(void* thisx, GraphicsContext* gfxCtx) {
}
CLOSE_DISPS(gfxCtx, "../z_eff_shield_particle.c", 359);
FrameInterpolation_RecordCloseChild();
}

View File

@ -1,6 +1,8 @@
#include "global.h"
#include "objects/gameplay_keep/gameplay_keep.h"
#include "soh/frame_interpolation.h"
// original name: "spark"
void EffectSpark_Init(void* thisx, void* initParamsx) {
EffectSpark* this = (EffectSpark*)thisx;
@ -152,6 +154,7 @@ void EffectSpark_Draw(void* thisx, GraphicsContext* gfxCtx) {
u8 sp1C4;
f32 ratio;
FrameInterpolation_RecordOpenChild(this, 0);
OPEN_DISPS(gfxCtx, "../z_eff_spark.c", 293);
if (this != NULL) {
@ -274,4 +277,5 @@ void EffectSpark_Draw(void* thisx, GraphicsContext* gfxCtx) {
end:
CLOSE_DISPS(gfxCtx, "../z_eff_spark.c", 498);
FrameInterpolation_RecordCloseChild();
}

View File

@ -1,6 +1,8 @@
#include "global.h"
#include "vt.h"
#include "soh/frame_interpolation.h"
EffectSsInfo sEffectSsInfo = { 0 }; // "EffectSS2Info"
void EffectSs_InitInfo(GlobalContext* globalCtx, s32 tableSize) {
@ -233,6 +235,7 @@ void EffectSs_Spawn(GlobalContext* globalCtx, s32 type, s32 priority, void* init
sEffectSsInfo.table[index].type = type;
sEffectSsInfo.table[index].priority = priority;
sEffectSsInfo.table[index].epoch++;
if (initInfo->init(globalCtx, index, &sEffectSsInfo.table[index], initParams) == 0) {
osSyncPrintf(VT_FGCOL(GREEN));
@ -284,7 +287,9 @@ void EffectSs_Draw(GlobalContext* globalCtx, s32 index) {
EffectSs* effectSs = &sEffectSsInfo.table[index];
if (effectSs->draw != NULL) {
FrameInterpolation_RecordOpenChild(effectSs, effectSs->epoch);
effectSs->draw(globalCtx, index, effectSs);
FrameInterpolation_RecordCloseChild();
}
}

View File

@ -4,6 +4,8 @@
#include "objects/gameplay_keep/gameplay_keep.h"
#include "soh/frame_interpolation.h"
#define LIGHTS_BUFFER_SIZE 32
//#define LIGHTS_BUFFER_SIZE 1024 // Kill me
@ -434,12 +436,14 @@ void Lights_DrawGlow(GlobalContext* globalCtx) {
if ((info->type == LIGHT_POINT_GLOW) && (params->drawGlow)) {
scale = SQ(params->radius) * 0.0000026f;
FrameInterpolation_RecordOpenChild(node, 0);
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, params->color[0], params->color[1], params->color[2], 50);
Matrix_Translate(params->x, params->y, params->z, MTXMODE_NEW);
Matrix_Scale(scale, scale, scale, MTXMODE_APPLY);
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_lights.c", 918),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gGlowCircleDL);
FrameInterpolation_RecordCloseChild();
}
node = node->next;

View File

@ -5,6 +5,8 @@
#include "soh/Enhancements/gameconsole.h"
#include "soh/frame_interpolation.h"
void* D_8012D1F0 = NULL;
//UNK_TYPE D_8012D1F4 = 0; // unused
Input* D_8012D1F8 = NULL;
@ -1379,7 +1381,9 @@ void Gameplay_Main(GameState* thisx) {
LOG_NUM("1", 1, "../z_play.c", 4583);
}
FrameInterpolation_StartRecord();
Gameplay_Draw(globalCtx);
FrameInterpolation_StopRecord();
if (1 && HREG(63)) {
LOG_NUM("1", 1, "../z_play.c", 4587);

View File

@ -1,6 +1,8 @@
#include "global.h"
#include "vt.h"
#include "soh/frame_interpolation.h"
// clang-format off
MtxF sMtxFClear = {
1.0f, 0.0f, 0.0f, 0.0f,
@ -523,6 +525,7 @@ void SkinMatrix_Vec3sToVec3f(Vec3s* src, Vec3f* dest) {
}
void SkinMatrix_MtxFToMtx(MtxF* src, Mtx* dest) {
FrameInterpolation_RecordSkinMatrixMtxFToMtx(src, dest);
guMtxF2L(src, dest);
}

View File

@ -2,6 +2,9 @@
#include "vt.h"
#include <string.h>
#include <math.h>
#include "soh/frame_interpolation.h"
vu32 D_8012ABF0 = true;
@ -277,6 +280,10 @@ void func_800AAA50(View* view, s32 arg1) {
}
}
static float sqr(float a) {
return a * a;
}
s32 func_800AAA9C(View* view) {
f32 aspect;
s32 width;
@ -307,6 +314,85 @@ s32 func_800AAA9C(View* view) {
height = view->viewport.bottomY - view->viewport.topY;
aspect = (f32)width / (f32)height;
viewing = Graph_Alloc(gfxCtx, sizeof(Mtx));
LogUtils_CheckNullPointer("viewing", viewing, "../z_view.c", 667);
view->viewingPtr = viewing;
if (view->eye.x == view->lookAt.x && view->eye.y == view->lookAt.y && view->eye.z == view->lookAt.z) {
view->eye.x += 1.0f;
view->eye.y += 1.0f;
view->eye.z += 1.0f;
}
func_800ABE74(view->eye.x, view->eye.y, view->eye.z);
MtxF viewingF;
guLookAtF(viewingF.mf, view->eye.x, view->eye.y, view->eye.z, view->lookAt.x, view->lookAt.y, view->lookAt.z, view->up.x,
view->up.y, view->up.z);
// Some heuristics to identify instant camera movements and skip interpolation in that case
static View old_view;
float dirx = view->eye.x - view->lookAt.x;
float diry = view->eye.y - view->lookAt.y;
float dirz = view->eye.z - view->lookAt.z;
float dir_dist = sqrtf(sqr(dirx) + sqr(diry) + sqr(dirz));
dirx /= dir_dist;
diry /= dir_dist;
dirz /= dir_dist;
float odirx = old_view.eye.x - old_view.lookAt.x;
float odiry = old_view.eye.y - old_view.lookAt.y;
float odirz = old_view.eye.z - old_view.lookAt.z;
float odir_dist = sqrtf(sqr(odirx) + sqr(odiry) + sqr(odirz));
odirx /= odir_dist;
odiry /= odir_dist;
odirz /= odir_dist;
float eye_dist = sqrtf(sqr(view->eye.x - old_view.eye.x) + sqr(view->eye.y - old_view.eye.y) + sqr(view->eye.z - old_view.eye.z));
float look_dist = sqrtf(sqr(view->lookAt.x - old_view.lookAt.x) + sqr(view->lookAt.y - old_view.lookAt.y) + sqr(view->lookAt.z - old_view.lookAt.z));
float up_dist = sqrtf(sqr(view->up.x - old_view.up.x) + sqr(view->up.y - old_view.up.y) + sqr(view->up.z - old_view.up.z));
float d_dist = sqrtf(sqr(dirx - odirx) + sqr(diry - odiry) + sqr(dirz - odirz));
bool dont_interpolate = false;
if (up_dist < 0.01 && d_dist < 0.01) {
if (eye_dist + look_dist > 300) {
dont_interpolate = true;
}
} else {
if (eye_dist >= 400) {
dont_interpolate = true;
}
if (look_dist >= 100) {
dont_interpolate = true;
}
if (up_dist >= 1.50f) {
dont_interpolate = true;
}
if (d_dist >= 1.414f && look_dist >= 15) {
dont_interpolate = true;
}
if (d_dist >= 1.414f && up_dist >= 0.31f && look_dist >= 1 && eye_dist >= 300) {
dont_interpolate = true;
}
if (d_dist >= 0.5f && up_dist >= 0.31f && look_dist >= 3 && eye_dist >= 170) {
dont_interpolate = true;
}
if (look_dist >= 52 && eye_dist >= 52) {
dont_interpolate = true;
}
if (look_dist >= 30 && eye_dist >= 90) {
dont_interpolate = true;
}
}
if (dont_interpolate) {
FrameInterpolation_DontInterpolateCamera();
}
FrameInterpolation_RecordOpenChild(NULL, FrameInterpolation_GetCameraEpoch());
if (HREG(80) == 11) {
if (HREG(94) != 11) {
HREG(94) = 11;
@ -347,22 +433,17 @@ s32 func_800AAA9C(View* view) {
gSPPerspNormalize(POLY_KAL_DISP++, view->normal);
gSPMatrix(POLY_KAL_DISP++, projection, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION);
viewing = Graph_Alloc(gfxCtx, sizeof(Mtx));
LogUtils_CheckNullPointer("viewing", viewing, "../z_view.c", 667);
view->viewingPtr = viewing;
if (view->eye.x == view->lookAt.x && view->eye.y == view->lookAt.y && view->eye.z == view->lookAt.z) {
view->eye.x += 1.0f;
view->eye.y += 1.0f;
view->eye.z += 1.0f;
}
func_800ABE74(view->eye.x, view->eye.y, view->eye.z);
guLookAt(viewing, view->eye.x, view->eye.y, view->eye.z, view->lookAt.x, view->lookAt.y, view->lookAt.z, view->up.x,
view->up.y, view->up.z);
Matrix_MtxFToMtx(viewingF.mf, viewing);
view->viewing = *viewing;
/*if (eye_dist > 1 || look_dist > 1 || abs(up_dist) > 0.1 || abs(d_dist) > 0.1)
printf("%d %f %f %f, %f %f %f, %f %f %f, %f %f %f %f %d\n", (int)view->fovy, view->eye.x, view->eye.y, view->eye.z, view->lookAt.x, view->lookAt.y, view->lookAt.z,
view->up.x, view->up.y, view->up.z, eye_dist, look_dist, up_dist, d_dist, dont_interpolate);*/
old_view = *view;
if (QREG(88) & 2) {
s32 i;
MtxF mf;
@ -374,10 +455,10 @@ s32 func_800AAA9C(View* view) {
}
osSyncPrintf("\n");
}
gSPMatrix(POLY_OPA_DISP++, viewing, G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION);
gSPMatrix(POLY_XLU_DISP++, viewing, G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION);
gSPMatrix(POLY_KAL_DISP++, viewing, G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION);
FrameInterpolation_RecordCloseChild();
CLOSE_DISPS(gfxCtx, "../z_view.c", 711);

View File

@ -1,5 +1,7 @@
#include "global.h"
#include "soh/frame_interpolation.h"
Mtx* sSkyboxDrawMatrix;
Mtx* SkyboxDraw_UpdateMatrix(SkyboxContext* skyboxCtx, f32 x, f32 y, f32 z) {
@ -13,6 +15,7 @@ Mtx* SkyboxDraw_UpdateMatrix(SkyboxContext* skyboxCtx, f32 x, f32 y, f32 z) {
void SkyboxDraw_Draw(SkyboxContext* skyboxCtx, GraphicsContext* gfxCtx, s16 skyboxId, s16 blend, f32 x, f32 y, f32 z) {
OPEN_DISPS(gfxCtx, "../z_vr_box_draw.c", 52);
FrameInterpolation_RecordOpenChild(NULL, FrameInterpolation_GetCameraEpoch());
func_800945A0(gfxCtx);
@ -85,7 +88,7 @@ void SkyboxDraw_Draw(SkyboxContext* skyboxCtx, GraphicsContext* gfxCtx, s16 skyb
gDPPipeSync(POLY_OPA_DISP++);
//gsSPShaderTest2(POLY_OPA_DISP++);
FrameInterpolation_RecordCloseChild();
CLOSE_DISPS(gfxCtx, "../z_vr_box_draw.c", 125);
}

View File

@ -62,5 +62,6 @@ void guLookAt(Mtx* m, f32 xEye, f32 yEye, f32 zEye, f32 xAt, f32 yAt, f32 zAt, f
guLookAtF(mf, xEye, yEye, zEye, xAt, yAt, zAt, xUp, yUp, zUp);
guMtxF2L((MtxF*)mf, m);
//guMtxF2L((MtxF*)mf, m);
Matrix_MtxFToMtx((MtxF*)mf, m);
}

View File

@ -37,6 +37,6 @@ void guPerspective(Mtx* m, u16* perspNorm, f32 fovy, f32 aspect, f32 near, f32 f
f32 mf[4][4];
guPerspectiveF(mf, perspNorm, fovy, aspect, near, far, scale);
guMtxF2L((MtxF*)mf, m);
//guMtxF2L((MtxF*)mf, m);
Matrix_MtxFToMtx((MtxF*)mf, m);
}

View File

@ -1,5 +1,7 @@
#include "global.h"
#include "soh/frame_interpolation.h"
void guOrthoF(f32 mf[4][4], f32 left, f32 right, f32 bottom, f32 top, f32 near, f32 far, f32 scale) {
s32 i, j;
@ -25,5 +27,8 @@ void guOrtho(Mtx* mtx, f32 left, f32 right, f32 bottom, f32 top, f32 near, f32 f
guOrthoF(mf, left, right, bottom, top, near, far, scale);
guMtxF2L((MtxF*)mf, mtx);
//guMtxF2L((MtxF*)mf, mtx);
FrameInterpolation_RecordOpenChild("ortho", 0);
Matrix_MtxFToMtx((MtxF*)mf, mtx);
FrameInterpolation_RecordCloseChild();
}

View File

@ -8,6 +8,8 @@
#include "overlays/actors/ovl_Boss_Ganon/z_boss_ganon.h"
#include "vt.h"
#include "soh/frame_interpolation.h"
#define FLAGS (ACTOR_FLAG_4 | ACTOR_FLAG_5)
typedef enum {
@ -283,6 +285,7 @@ void BgGanonOtyuka_Draw(Actor* thisx, GlobalContext* globalCtx) {
platform = (BgGanonOtyuka*)actor;
if (platform->dyna.actor.projectedPos.z > spBC) {
FrameInterpolation_RecordOpenChild(platform, 0);
if (camera->eye.y > platform->dyna.actor.world.pos.y) {
phi_s2 = sPlatformTopDL;
} else {
@ -309,7 +312,7 @@ void BgGanonOtyuka_Draw(Actor* thisx, GlobalContext* globalCtx) {
}
for (i = 0; i < ARRAY_COUNT(sSides); i++) {
if (platform->visibleSides & sSides[i]) {
if ((platform->visibleSides & sSides[i]) || 1) { // || 1 for frame interpolation
Matrix_Push();
Matrix_Translate(sSideCenters[i].x, 0.0f, sSideCenters[i].z, MTXMODE_APPLY);
Matrix_RotateY(sSideAngles[i], MTXMODE_APPLY);
@ -320,6 +323,7 @@ void BgGanonOtyuka_Draw(Actor* thisx, GlobalContext* globalCtx) {
Matrix_Pop();
}
}
FrameInterpolation_RecordCloseChild();
}
}
@ -333,6 +337,7 @@ void BgGanonOtyuka_Draw(Actor* thisx, GlobalContext* globalCtx) {
platform = (BgGanonOtyuka*)actor;
if ((platform->dyna.actor.projectedPos.z > -30.0f) && (platform->flashState != FLASH_NONE)) {
FrameInterpolation_RecordOpenChild(platform, 0);
gSPSegment(POLY_XLU_DISP++, 0x08,
Gfx_TwoTexScroll(globalCtx->state.gfxCtx, 0, platform->flashTimer * 4, 0, 32, 64, 1,
platform->flashTimer * 4, 0, 32, 64));
@ -344,7 +349,7 @@ void BgGanonOtyuka_Draw(Actor* thisx, GlobalContext* globalCtx) {
Matrix_Translate(platform->dyna.actor.world.pos.x, 0.0f, platform->dyna.actor.world.pos.z, MTXMODE_NEW);
for (i = 0; i < ARRAY_COUNT(sSides); i++) {
if (platform->unwalledSides & sSides[i]) {
if ((platform->unwalledSides & sSides[i]) || 1) { // || 1 for frame interpolation
Matrix_Push();
Matrix_Translate(sSideCenters[i].x, 0.0f, sSideCenters[i].z, MTXMODE_APPLY);
Matrix_RotateY(sSideAngles[i], MTXMODE_APPLY);
@ -356,6 +361,7 @@ void BgGanonOtyuka_Draw(Actor* thisx, GlobalContext* globalCtx) {
Matrix_Pop();
}
}
FrameInterpolation_RecordCloseChild();
}
}

View File

@ -240,7 +240,8 @@ void BgHidanRsekizou_Draw(Actor* thisx, GlobalContext* globalCtx) {
POLY_XLU_DISP = Gfx_CallSetupDL(POLY_XLU_DISP, 0x14);
if ((s16)((Camera_GetCamDirYaw(GET_ACTIVE_CAM(globalCtx)) - this->dyna.actor.shape.rot.y) - 0x2E6C) >= 0) {
// Strange original code. Add || 1 for frame interpolation to get correct.
if ((s16)((Camera_GetCamDirYaw(GET_ACTIVE_CAM(globalCtx)) - this->dyna.actor.shape.rot.y) - 0x2E6C) >= 0 || 1) {
for (i = 3; i >= 0; i--) {
POLY_XLU_DISP = BgHidanRsekizou_DrawFireball(globalCtx, this, i, &mf, 0, POLY_XLU_DISP);
}

View File

@ -12,6 +12,8 @@
#include "overlays/actors/ovl_Door_Warp1/z_door_warp1.h"
#include "objects/gameplay_keep/gameplay_keep.h"
#include "soh/frame_interpolation.h"
#define FLAGS (ACTOR_FLAG_0 | ACTOR_FLAG_2 | ACTOR_FLAG_4 | ACTOR_FLAG_5)
typedef enum {
@ -78,6 +80,7 @@ void BossFd_SpawnEmber(BossFdEffect* effect, Vec3f* position, Vec3f* velocity, V
effect->scale = scale / 1000.0f;
effect->alpha = 255;
effect->timer1 = (s16)Rand_ZeroFloat(10.0f);
effect->epoch++;
break;
}
}
@ -95,6 +98,7 @@ void BossFd_SpawnDebris(BossFdEffect* effect, Vec3f* position, Vec3f* velocity,
effect->scale = scale / 1000.0f;
effect->vFdFxRotX = Rand_ZeroFloat(100.0f);
effect->vFdFxRotY = Rand_ZeroFloat(100.0f);
effect->epoch++;
break;
}
}
@ -111,6 +115,7 @@ void BossFd_SpawnDust(BossFdEffect* effect, Vec3f* position, Vec3f* velocity, Ve
effect->accel = *acceleration;
effect->timer2 = 0;
effect->scale = scale / 400.0f;
effect->epoch++;
break;
}
}
@ -136,6 +141,7 @@ void BossFd_SpawnFireBreath(BossFdEffect* effect, Vec3f* position, Vec3f* veloci
effect->timer2 = 0;
effect->scale = scale / 400.0f;
effect->kbAngle = kbAngle;
effect->epoch++;
break;
}
}
@ -1522,6 +1528,7 @@ void BossFd_DrawEffects(BossFdEffect* effect, GlobalContext* globalCtx) {
for (i = 0; i < 180; i++, effect++) {
if (effect->type == BFD_FX_EMBER) {
FrameInterpolation_RecordOpenChild(effect, effect->epoch);
if (!flag) {
func_80093D84(globalCtx->state.gfxCtx);
gSPDisplayList(POLY_XLU_DISP++, gVolvagiaEmberMaterialDL);
@ -1536,6 +1543,7 @@ void BossFd_DrawEffects(BossFdEffect* effect, GlobalContext* globalCtx) {
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_fd.c", 4046),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gVolvagiaEmberModelDL);
FrameInterpolation_RecordCloseChild();
}
}
@ -1543,6 +1551,7 @@ void BossFd_DrawEffects(BossFdEffect* effect, GlobalContext* globalCtx) {
flag = false;
for (i = 0; i < 180; i++, effect++) {
if (effect->type == BFD_FX_DEBRIS) {
FrameInterpolation_RecordOpenChild(effect, effect->epoch);
if (!flag) {
func_80093D18(globalCtx->state.gfxCtx);
gSPDisplayList(POLY_OPA_DISP++, gVolvagiaDebrisMaterialDL);
@ -1557,6 +1566,7 @@ void BossFd_DrawEffects(BossFdEffect* effect, GlobalContext* globalCtx) {
gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_fd.c", 4068),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_OPA_DISP++, gVolvagiaDebrisModelDL);
FrameInterpolation_RecordCloseChild();
}
}
@ -1564,6 +1574,7 @@ void BossFd_DrawEffects(BossFdEffect* effect, GlobalContext* globalCtx) {
flag = false;
for (i = 0; i < 180; i++, effect++) {
if (effect->type == BFD_FX_DUST) {
FrameInterpolation_RecordOpenChild(effect, effect->epoch);
if (!flag) {
POLY_XLU_DISP = Gfx_CallSetupDL(POLY_XLU_DISP, 0);
gSPDisplayList(POLY_XLU_DISP++, gVolvagiaDustMaterialDL);
@ -1580,6 +1591,7 @@ void BossFd_DrawEffects(BossFdEffect* effect, GlobalContext* globalCtx) {
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPSegment(POLY_XLU_DISP++, 0x08, SEGMENTED_TO_VIRTUAL(dustTex[effect->timer2]));
gSPDisplayList(POLY_XLU_DISP++, gVolvagiaDustModelDL);
FrameInterpolation_RecordCloseChild();
}
}
@ -1587,6 +1599,7 @@ void BossFd_DrawEffects(BossFdEffect* effect, GlobalContext* globalCtx) {
flag = false;
for (i = 0; i < 180; i++, effect++) {
if (effect->type == BFD_FX_FIRE_BREATH) {
FrameInterpolation_RecordOpenChild(effect, effect->epoch);
if (!flag) {
POLY_XLU_DISP = Gfx_CallSetupDL(POLY_XLU_DISP, 0);
gSPDisplayList(POLY_XLU_DISP++, gVolvagiaDustMaterialDL);
@ -1603,6 +1616,7 @@ void BossFd_DrawEffects(BossFdEffect* effect, GlobalContext* globalCtx) {
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPSegment(POLY_XLU_DISP++, 0x08, SEGMENTED_TO_VIRTUAL(dustTex[effect->timer2]));
gSPDisplayList(POLY_XLU_DISP++, gVolvagiaDustModelDL);
FrameInterpolation_RecordCloseChild();
}
}
@ -1610,6 +1624,7 @@ void BossFd_DrawEffects(BossFdEffect* effect, GlobalContext* globalCtx) {
flag = false;
for (i = 0; i < 180; i++, effect++) {
if (effect->type == BFD_FX_SKULL_PIECE) {
FrameInterpolation_RecordOpenChild(effect, effect->epoch);
if (!flag) {
func_80093D84(globalCtx->state.gfxCtx);
gSPDisplayList(POLY_XLU_DISP++, gVolvagiaSkullPieceMaterialDL);
@ -1624,6 +1639,7 @@ void BossFd_DrawEffects(BossFdEffect* effect, GlobalContext* globalCtx) {
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_fd.c", 4192),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gVolvagiaSkullPieceModelDL);
FrameInterpolation_RecordCloseChild();
}
}

View File

@ -49,6 +49,7 @@ typedef struct {
/* 0x30 */ f32 scale;
/* 0x34 */ f32 bFdFxFloat1;
/* 0x38 */ f32 bFdFxFloat2;
u32 epoch;
} BossFdEffect; // size = 0x3C
#define BOSSFD_EFFECT_COUNT 180

View File

@ -87,6 +87,7 @@ void BossFd2_SpawnDebris(GlobalContext* globalCtx, BossFdEffect* effect, Vec3f*
effect->scale = scale / 1000.0f;
effect->vFdFxRotX = Rand_ZeroFloat(100.0f);
effect->vFdFxRotY = Rand_ZeroFloat(100.0f);
effect->epoch++;
break;
}
}
@ -112,6 +113,7 @@ void BossFd2_SpawnFireBreath(GlobalContext* globalCtx, BossFdEffect* effect, Vec
effect->timer2 = 0;
effect->scale = scale / 400.0f;
effect->kbAngle = kbAngle;
effect->epoch++;
break;
}
}
@ -130,6 +132,7 @@ void BossFd2_SpawnEmber(GlobalContext* globalCtx, BossFdEffect* effect, Vec3f* p
effect->scale = scale / 1000.0f;
effect->alpha = 255;
effect->timer1 = (s16)Rand_ZeroFloat(10.0f);
effect->epoch++;
break;
}
}
@ -148,6 +151,7 @@ void BossFd2_SpawnSkullPiece(GlobalContext* globalCtx, BossFdEffect* effect, Vec
effect->scale = scale / 1000.0f;
effect->vFdFxRotX = Rand_ZeroFloat(100.0f);
effect->vFdFxRotY = Rand_ZeroFloat(100.0f);
effect->epoch++;
break;
}
}
@ -164,6 +168,7 @@ void BossFd2_SpawnDust(BossFdEffect* effect, Vec3f* position, Vec3f* velocity, V
effect->accel = *acceleration;
effect->timer2 = 0;
effect->scale = scale / 400.0f;
effect->epoch++;
break;
}
}

View File

@ -9,6 +9,8 @@
#include "assets/objects/object_ganon_anime2/object_ganon_anime2.h"
#include "assets/scenes/dungeons/ganon_boss/ganon_boss_scene.h"
#include "soh/frame_interpolation.h"
#include <string.h>
#define FLAGS (ACTOR_FLAG_0 | ACTOR_FLAG_2 | ACTOR_FLAG_4 | ACTOR_FLAG_5)
@ -138,6 +140,7 @@ void BossGanonEff_SpawnWindowShard(GlobalContext* globalCtx, Vec3f* pos, Vec3f*
eff->color.g = color->g;
eff->color.b = color->b;
eff->timer = (s16)Rand_ZeroFloat(20.0f);
eff->epoch++;
break;
}
}
@ -158,6 +161,7 @@ void BossGanonEff_SpawnSparkle(GlobalContext* globalCtx, Vec3f* pos, Vec3f* velo
eff->unk_2E = (s16)Rand_ZeroFloat(100.0f) + 0xC8;
eff->unk_30 = arg6;
eff->timer = (s16)Rand_ZeroFloat(10.0f);
eff->epoch++;
break;
}
}
@ -182,6 +186,7 @@ void BossGanonEff_SpawnLightRay(GlobalContext* globalCtx, Vec3f* pos, Vec3f* vel
eff->timer = (s16)Rand_ZeroFloat(10.0f);
eff->unk_48 = Math_Atan2F(eff->velocity.z, eff->velocity.x);
eff->unk_44 = -Math_Atan2F(sqrtf(SQXZ(eff->velocity)), eff->velocity.y);
eff->epoch++;
break;
}
}
@ -201,6 +206,7 @@ void BossGanonEff_SpawnShock(GlobalContext* globalCtx, f32 scale, s16 shockType)
eff->scale = scale / 1000.0f;
eff->unk_2E = shockType;
eff->timer = 0;
eff->epoch++;
break;
}
}
@ -220,6 +226,7 @@ void BossGanonEff_SpawnLightning(GlobalContext* globalCtx, f32 scale, f32 arg2,
eff->unk_48 = arg2;
eff->unk_3C = arg3;
eff->timer = 0;
eff->epoch++;
break;
}
}
@ -240,6 +247,7 @@ void BossGanonEff_SpawnDustDark(GlobalContext* globalCtx, Vec3f* pos, f32 scale,
eff->unk_38 = arg3;
eff->unk_30 = (s16)Rand_ZeroFloat(100.0f);
eff->unk_2E = eff->timer = eff->alpha = 0;
eff->epoch++;
break;
}
}
@ -257,6 +265,7 @@ void BossGanonEff_SpawnDustLight(GlobalContext* globalCtx, Vec3f* pos, f32 scale
effArr[bufIndex].unk_38 = arg3;
effArr[bufIndex].unk_30 = Rand_ZeroFloat(100.0f);
effArr[bufIndex].unk_2E = effArr[bufIndex].timer = effArr[bufIndex].alpha = 0;
effArr[bufIndex].epoch++;
}
void BossGanonEff_SpawnShockwave(GlobalContext* globalCtx, Vec3f* pos, f32 scale, f32 arg3) {
@ -275,6 +284,7 @@ void BossGanonEff_SpawnShockwave(GlobalContext* globalCtx, Vec3f* pos, f32 scale
eff->unk_38 = arg3;
eff->unk_30 = (s16)Rand_ZeroFloat(100.0f);
eff->unk_2E = eff->timer = 0;
eff->epoch++;
break;
}
}
@ -295,6 +305,7 @@ void BossGanonEff_SpawnBlackDot(GlobalContext* globalCtx, Vec3f* pos, f32 scale)
eff->timer = 0;
eff->alpha = 0;
eff->unk_2E = 0;
eff->epoch++;
break;
}
}
@ -4820,6 +4831,7 @@ void BossGanon_DrawEffects(GlobalContext* globalCtx) {
for (i = 0; i < 200; i++, eff++) {
if (eff->type == GDF_EFF_WINDOW_SHARD) {
FrameInterpolation_RecordOpenChild(eff, eff->epoch);
gDPPipeSync(POLY_OPA_DISP++);
if (flag == 0) {
gSPDisplayList(POLY_OPA_DISP++, gDorfWindowShardMaterialDL);
@ -4837,6 +4849,7 @@ void BossGanon_DrawEffects(GlobalContext* globalCtx) {
gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_ganon.c", 10898),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_OPA_DISP++, gDorfWindowShardModelDL);
FrameInterpolation_RecordCloseChild();
}
}
@ -4845,6 +4858,7 @@ void BossGanon_DrawEffects(GlobalContext* globalCtx) {
for (i = 0; i < 150; i++, eff++) {
if (eff->type == GDF_EFF_SPARKLE) {
FrameInterpolation_RecordOpenChild(eff, eff->epoch);
gDPPipeSync(POLY_XLU_DISP++);
if (flag == 0) {
gDPSetEnvColor(POLY_XLU_DISP++, 255, 255, 0, 0);
@ -4859,6 +4873,7 @@ void BossGanon_DrawEffects(GlobalContext* globalCtx) {
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_ganon.c", 10932),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gDorfSquareDL);
FrameInterpolation_RecordCloseChild();
}
}
@ -4867,6 +4882,7 @@ void BossGanon_DrawEffects(GlobalContext* globalCtx) {
for (i = 0; i < 150; i++, eff++) {
if (eff->type == GDF_EFF_LIGHT_RAY) {
FrameInterpolation_RecordOpenChild(eff, eff->epoch);
gDPPipeSync(POLY_XLU_DISP++);
if (flag == 0) {
gDPSetEnvColor(POLY_XLU_DISP++, 255, 255, 0, 0);
@ -4883,6 +4899,7 @@ void BossGanon_DrawEffects(GlobalContext* globalCtx) {
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_ganon.c", 10971),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gDorfSquareDL);
FrameInterpolation_RecordCloseChild();
}
}
@ -4891,6 +4908,7 @@ void BossGanon_DrawEffects(GlobalContext* globalCtx) {
for (i = 0; i < 150; i++, eff++) {
if (eff->type == GDF_EFF_SHOCK) {
FrameInterpolation_RecordOpenChild(eff, eff->epoch);
if (flag == 0) {
gDPPipeSync(POLY_XLU_DISP++);
if (eff->unk_2E == GDF_SHOCK_PLAYER_PURPLE) {
@ -4909,6 +4927,7 @@ void BossGanon_DrawEffects(GlobalContext* globalCtx) {
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_ganon.c", 11023),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gDorfShockDL);
FrameInterpolation_RecordCloseChild();
}
}
@ -4916,6 +4935,7 @@ void BossGanon_DrawEffects(GlobalContext* globalCtx) {
for (i = 0; i < 150; i++, eff++) {
if (eff->type == GDF_EFF_LIGHTNING) {
FrameInterpolation_RecordOpenChild(eff, eff->epoch);
gDPPipeSync(POLY_XLU_DISP++);
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, sLightningPrimColors[(eff->timer * 3) + 0],
sLightningPrimColors[(eff->timer * 3) + 1], sLightningPrimColors[(eff->timer * 3) + 2],
@ -4931,6 +4951,7 @@ void BossGanon_DrawEffects(GlobalContext* globalCtx) {
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPSegment(POLY_XLU_DISP++, 0x08, SEGMENTED_TO_VIRTUAL(sLightningTextures[eff->timer]));
gSPDisplayList(POLY_XLU_DISP++, gDorfLightningDL);
FrameInterpolation_RecordCloseChild();
}
}
@ -4938,6 +4959,7 @@ void BossGanon_DrawEffects(GlobalContext* globalCtx) {
for (i = 0; i < 150; i++, eff++) {
if (eff->type == GDF_EFF_IMPACT_DUST_DARK) {
FrameInterpolation_RecordOpenChild(eff, eff->epoch);
gDPPipeSync(POLY_XLU_DISP++);
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 0, 0, 0, eff->alpha);
gDPSetEnvColor(POLY_XLU_DISP++, 100, 70, 0, 128);
@ -4949,6 +4971,7 @@ void BossGanon_DrawEffects(GlobalContext* globalCtx) {
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_ganon.c", 11121),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gDorfImpactDarkDL);
FrameInterpolation_RecordCloseChild();
}
}
@ -4956,6 +4979,7 @@ void BossGanon_DrawEffects(GlobalContext* globalCtx) {
for (i = 0; i < 150; i++, eff++) {
if (eff->type == GDF_EFF_IMPACT_DUST_LIGHT) {
FrameInterpolation_RecordOpenChild(eff, eff->epoch);
gDPPipeSync(POLY_XLU_DISP++);
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 255, eff->alpha);
gDPSetEnvColor(POLY_XLU_DISP++, 200, 100, 0, 128);
@ -4967,6 +4991,7 @@ void BossGanon_DrawEffects(GlobalContext* globalCtx) {
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_ganon.c", 11165),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gDorfImpactLightDL);
FrameInterpolation_RecordCloseChild();
}
}
@ -4974,6 +4999,7 @@ void BossGanon_DrawEffects(GlobalContext* globalCtx) {
for (i = 0; i < 150; i++, eff++) {
if (eff->type == GDF_EFF_SHOCKWAVE) {
FrameInterpolation_RecordOpenChild(eff, eff->epoch);
gDPPipeSync(POLY_XLU_DISP++);
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 170, eff->alpha);
gDPSetEnvColor(POLY_XLU_DISP++, 150, 255, 0, 128);
@ -4986,6 +5012,7 @@ void BossGanon_DrawEffects(GlobalContext* globalCtx) {
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_ganon.c", 11209),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gDorfShockwaveDL);
FrameInterpolation_RecordCloseChild();
}
}
@ -4993,6 +5020,7 @@ void BossGanon_DrawEffects(GlobalContext* globalCtx) {
for (i = 0; i < 150; i++, eff++) {
if (eff->type == GDF_EFF_BLACK_DOT) {
FrameInterpolation_RecordOpenChild(eff, eff->epoch);
gDPPipeSync(POLY_XLU_DISP++);
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 150, 170, 0, eff->alpha);
gDPSetEnvColor(POLY_XLU_DISP++, 255, 255, 255, 128);
@ -5005,6 +5033,7 @@ void BossGanon_DrawEffects(GlobalContext* globalCtx) {
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_ganon.c", 11250),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gDorfDotDL);
FrameInterpolation_RecordCloseChild();
}
}

View File

@ -69,6 +69,7 @@ typedef struct {
/* 0x40 */ f32 unk_40;
/* 0x44 */ f32 unk_44; // mostly x rot
/* 0x48 */ f32 unk_48; // mostly y rot
u32 epoch;
} GanondorfEffect; // size = 0x4C
typedef struct BossGanon {

View File

@ -10,6 +10,8 @@
#include "objects/gameplay_keep/gameplay_keep.h"
#include "vt.h"
#include "soh/frame_interpolation.h"
#include <string.h>
#define FLAGS (ACTOR_FLAG_0 | ACTOR_FLAG_2 | ACTOR_FLAG_4 | ACTOR_FLAG_5)
@ -34,6 +36,7 @@ typedef struct {
/* 0x30 */ f32 scale;
/* 0x30 */ f32 fwork[2];
/* 0x3C */ Vec3f* targetPos;
u32 epoch;
} BossMoEffect; // size = 0x40
#define MO_FX_MAX_SIZE 0
@ -211,6 +214,7 @@ void BossMo_SpawnRipple(BossMoEffect* effect, Vec3f* pos, f32 scale, f32 maxScal
effect->rippleMode = 1;
effect->fwork[MO_FX_SPREAD_RATE] = (effect->fwork[MO_FX_MAX_SIZE] - effect->scale) * 0.1f;
}
effect->epoch++;
break;
}
}
@ -232,6 +236,7 @@ void BossMo_SpawnDroplet(s16 type, BossMoEffect* effect, Vec3f* pos, Vec3f* vel,
effect->scale = scale;
effect->fwork[MO_FX_SPREAD_RATE] = 1.0f;
effect->stopTimer = 0;
effect->epoch++;
break;
}
}
@ -250,6 +255,7 @@ void BossMo_SpawnStillDroplet(BossMoEffect* effect, Vec3f* pos, f32 scale) {
effect->accel = zeroVec;
effect->scale = scale;
effect->fwork[MO_FX_SPREAD_RATE] = 1.0f;
effect->epoch++;
break;
}
}
@ -274,6 +280,7 @@ void BossMo_SpawnBubble(BossMoEffect* effect, Vec3f* pos, Vec3f* vel, Vec3f* acc
effect->alpha = 0;
}
effect->timer = 0;
effect->epoch++;
break;
}
}
@ -2909,6 +2916,7 @@ void BossMo_DrawEffects(BossMoEffect* effect, GlobalContext* globalCtx) {
for (i = 0; i < ARRAY_COUNT(sEffects); i++, effect++) {
if (effect->type == MO_FX_BIG_RIPPLE) {
FrameInterpolation_RecordOpenChild(effect, effect->epoch);
if (flag == 0) {
func_80094BC4(gfxCtx);
@ -2925,6 +2933,7 @@ void BossMo_DrawEffects(BossMoEffect* effect, GlobalContext* globalCtx) {
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gEffWaterRippleDL);
FrameInterpolation_RecordCloseChild();
}
}
@ -2932,6 +2941,7 @@ void BossMo_DrawEffects(BossMoEffect* effect, GlobalContext* globalCtx) {
flag = 0;
for (i = 0; i < ARRAY_COUNT(sEffects); i++, effect++) {
if (effect->type == MO_FX_SMALL_RIPPLE) {
FrameInterpolation_RecordOpenChild(effect, effect->epoch);
if (flag == 0) {
func_80093D84(globalCtx->state.gfxCtx);
@ -2948,6 +2958,7 @@ void BossMo_DrawEffects(BossMoEffect* effect, GlobalContext* globalCtx) {
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gEffShockwaveDL);
FrameInterpolation_RecordCloseChild();
}
}
@ -2956,6 +2967,7 @@ void BossMo_DrawEffects(BossMoEffect* effect, GlobalContext* globalCtx) {
for (i = 0; i < ARRAY_COUNT(sEffects); i++, effect++) {
if (((effect->type == MO_FX_DROPLET) || (effect->type == MO_FX_SPLASH)) ||
(effect->type == MO_FX_SPLASH_TRAIL)) {
FrameInterpolation_RecordOpenChild(effect, effect->epoch);
if (flag == 0) {
POLY_XLU_DISP = Gfx_CallSetupDL(POLY_XLU_DISP, 0);
@ -2977,6 +2989,7 @@ void BossMo_DrawEffects(BossMoEffect* effect, GlobalContext* globalCtx) {
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gMorphaDropletModelDL);
FrameInterpolation_RecordCloseChild();
}
}
@ -2984,6 +2997,7 @@ void BossMo_DrawEffects(BossMoEffect* effect, GlobalContext* globalCtx) {
flag = 0;
for (i = 0; i < ARRAY_COUNT(sEffects); i++, effect++) {
if (effect->type == MO_FX_WET_SPOT) {
FrameInterpolation_RecordOpenChild(effect, effect->epoch);
if (flag == 0) {
func_80094044(gfxCtx);
@ -3003,6 +3017,7 @@ void BossMo_DrawEffects(BossMoEffect* effect, GlobalContext* globalCtx) {
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gMorphaWetSpotModelDL);
FrameInterpolation_RecordCloseChild();
}
}
@ -3010,6 +3025,7 @@ void BossMo_DrawEffects(BossMoEffect* effect, GlobalContext* globalCtx) {
flag = 0;
for (i = 0; i < ARRAY_COUNT(sEffects); i++, effect++) {
if (effect->type == MO_FX_BUBBLE) {
FrameInterpolation_RecordOpenChild(effect, effect->epoch);
if (flag == 0) {
func_80093D18(globalCtx->state.gfxCtx);
@ -3027,6 +3043,7 @@ void BossMo_DrawEffects(BossMoEffect* effect, GlobalContext* globalCtx) {
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_OPA_DISP++, gMorphaBubbleDL);
FrameInterpolation_RecordCloseChild();
}
}

View File

@ -12,6 +12,8 @@
#include "overlays/actors/ovl_En_Boom/z_en_boom.h"
#include "objects/gameplay_keep/gameplay_keep.h"
#include "soh/frame_interpolation.h"
#define FLAGS (ACTOR_FLAG_0 | ACTOR_FLAG_2 | ACTOR_FLAG_4 | ACTOR_FLAG_5)
#define GET_BODY(this) ((BossVa*)(this)->actor.parent)
@ -40,6 +42,7 @@ typedef struct BossVaEffect {
/* 0x44 */ f32 scaleMod;
/* 0x48 */ Vec3f offset;
/* 0x54 */ struct BossVa* parent;
u32 epoch;
} BossVaEffect; // size = 0x58
typedef enum {
@ -3519,6 +3522,7 @@ void BossVa_DrawEffects(BossVaEffect* effect, GlobalContext* globalCtx) {
for (i = 0; i < ARRAY_COUNT(sVaEffects); i++, effect++) {
if (effect->type == VA_LARGE_SPARK) {
FrameInterpolation_RecordOpenChild(effect, effect->epoch);
if (!flag) {
func_80093D84(globalCtx->state.gfxCtx);
gDPSetEnvColor(POLY_XLU_DISP++, 130, 130, 30, 0);
@ -3534,12 +3538,14 @@ void BossVa_DrawEffects(BossVaEffect* effect, GlobalContext* globalCtx) {
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_va.c", 4976),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gBarinadeDL_015710);
FrameInterpolation_RecordCloseChild();
}
}
effect = effectHead;
for (i = 0, flag = 0; i < ARRAY_COUNT(sVaEffects); i++, effect++) {
if (effect->type == VA_SPARK_BALL) {
FrameInterpolation_RecordOpenChild(effect, effect->epoch);
if (!flag) {
func_80093D84(globalCtx->state.gfxCtx);
gSPDisplayList(POLY_XLU_DISP++, gBarinadeDL_011738);
@ -3560,12 +3566,14 @@ void BossVa_DrawEffects(BossVaEffect* effect, GlobalContext* globalCtx) {
gDPSetEnvColor(POLY_XLU_DISP++, effect->envColor[0], effect->envColor[1], effect->envColor[2],
effect->envColor[3]);
gSPDisplayList(POLY_XLU_DISP++, gBarinadeDL_011768);
FrameInterpolation_RecordCloseChild();
}
}
effect = effectHead;
for (i = 0, flag = 0; i < ARRAY_COUNT(sVaEffects); i++, effect++) {
if (effect->type == VA_BLOOD) {
FrameInterpolation_RecordOpenChild(effect, effect->epoch);
if (!flag) {
func_80093D84(globalCtx->state.gfxCtx);
gSPDisplayList(POLY_XLU_DISP++, gBarinadeDL_009430);
@ -3590,6 +3598,7 @@ void BossVa_DrawEffects(BossVaEffect* effect, GlobalContext* globalCtx) {
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_va.c", 5052),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gBarinadeDL_009468);
FrameInterpolation_RecordCloseChild();
}
}
@ -3598,6 +3607,7 @@ void BossVa_DrawEffects(BossVaEffect* effect, GlobalContext* globalCtx) {
if (effect->type == VA_TUMOR) {
BossVa* parent = effect->parent;
FrameInterpolation_RecordOpenChild(effect, effect->epoch);
if (!flag) {
func_80093D18(globalCtx->state.gfxCtx);
gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, effect->envColor[3]);
@ -3614,12 +3624,14 @@ void BossVa_DrawEffects(BossVaEffect* effect, GlobalContext* globalCtx) {
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_OPA_DISP++, gBarinadeDL_012948);
}
FrameInterpolation_RecordCloseChild();
}
}
effect = effectHead;
for (i = 0, flag = 0; i < ARRAY_COUNT(sVaEffects); i++, effect++) {
if (effect->type == VA_GORE) {
FrameInterpolation_RecordOpenChild(effect, effect->epoch);
if (!flag) {
func_80093D18(globalCtx->state.gfxCtx);
gSPDisplayList(POLY_OPA_DISP++, gBarinadeDL_012BA0);
@ -3645,12 +3657,14 @@ void BossVa_DrawEffects(BossVaEffect* effect, GlobalContext* globalCtx) {
gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_va.c", 5124),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_OPA_DISP++, gBarinadeDL_012C50);
FrameInterpolation_RecordCloseChild();
}
}
effect = effectHead;
for (i = 0, flag = 0; i < ARRAY_COUNT(sVaEffects); i++, effect++) {
if (effect->type == VA_ZAP_CHARGE) {
FrameInterpolation_RecordOpenChild(effect, effect->epoch);
if (!flag) {
func_80093D84(globalCtx->state.gfxCtx);
gSPDisplayList(POLY_XLU_DISP++, gBarinadeDL_0135B0);
@ -3668,12 +3682,14 @@ void BossVa_DrawEffects(BossVaEffect* effect, GlobalContext* globalCtx) {
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_va.c", 5152),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gBarinadeDL_013638);
FrameInterpolation_RecordCloseChild();
}
}
effect = effectHead;
for (i = 0, flag = 0; i < ARRAY_COUNT(sVaEffects); i++, effect++) {
if (effect->type == VA_BLAST_SPARK) {
FrameInterpolation_RecordOpenChild(effect, effect->epoch);
if (!flag) {
func_80093C14(globalCtx->state.gfxCtx);
gDPSetEnvColor(POLY_XLU_DISP++, 130, 130, 30, 0);
@ -3690,12 +3706,14 @@ void BossVa_DrawEffects(BossVaEffect* effect, GlobalContext* globalCtx) {
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_va.c", 5180),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gBarinadeDL_015710);
FrameInterpolation_RecordCloseChild();
}
}
effect = effectHead;
for (i = 0, flag = 0; i < ARRAY_COUNT(sVaEffects); i++, effect++) {
if (effect->type == VA_SMALL_SPARK) {
FrameInterpolation_RecordOpenChild(effect, effect->epoch);
if (!flag) {
func_80093D84(globalCtx->state.gfxCtx);
gDPSetEnvColor(POLY_XLU_DISP++, 255, 255, 100, 0);
@ -3712,6 +3730,7 @@ void BossVa_DrawEffects(BossVaEffect* effect, GlobalContext* globalCtx) {
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx, "../z_boss_va.c", 5208),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gBarinadeDL_008F70);
FrameInterpolation_RecordCloseChild();
}
}
@ -3734,6 +3753,7 @@ void BossVa_SpawnSpark(GlobalContext* globalCtx, BossVaEffect* effect, BossVa* t
effect->timer = (s16)(Rand_ZeroOne() * 10.0f) + 111;
effect->velocity = effect->accel = sZeroVec;
effect->mode = mode;
effect->epoch++;
switch (mode) {
case SPARK_UNUSED:

View File

@ -7,6 +7,8 @@
#include "z_en_zo.h"
#include "objects/object_zo/object_zo.h"
#include "soh/frame_interpolation.h"
#define FLAGS (ACTOR_FLAG_0 | ACTOR_FLAG_3)
typedef enum {
@ -41,6 +43,7 @@ void EnZo_Ripple(EnZo* this, Vec3f* pos, f32 scale, f32 targetScale, u8 alpha) {
effect->scale = scale;
effect->targetScale = targetScale;
effect->color.a = alpha;
effect->epoch++;
break;
}
effect++;
@ -65,6 +68,7 @@ void EnZo_Bubble(EnZo* this, Vec3f* pos) {
effect->vec = *pos;
effect->vel = vel;
effect->scale = ((Rand_ZeroOne() - 0.5f) * 0.02f) + 0.12f;
effect->epoch++;
break;
}
}
@ -87,6 +91,7 @@ void EnZo_Splash(EnZo* this, Vec3f* pos, Vec3f* vel, f32 scale) {
effect->vel = *vel;
effect->color.a = (Rand_ZeroOne() * 100.0f) + 100.0f;
effect->scale = scale;
effect->epoch++;
break;
}
effect++;
@ -180,6 +185,7 @@ void EnZo_DrawRipples(EnZo* this, GlobalContext* globalCtx) {
func_80093D84(globalCtx->state.gfxCtx);
for (i = 0; i < ARRAY_COUNT(this->effects); i++) {
if (effect->type == ENZO_EFFECT_RIPPLE) {
FrameInterpolation_RecordOpenChild(effect, effect->epoch);
if (!setup) {
if (1) {}
gDPPipeSync(POLY_XLU_DISP++);
@ -194,6 +200,7 @@ void EnZo_DrawRipples(EnZo* this, GlobalContext* globalCtx) {
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_en_zo_eff.c", 242),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gZoraRipplesModelDL);
FrameInterpolation_RecordCloseChild();
}
effect++;
}
@ -210,6 +217,7 @@ void EnZo_DrawBubbles(EnZo* this, GlobalContext* globalCtx) {
func_80093D84(globalCtx->state.gfxCtx);
for (i = 0; i < ARRAY_COUNT(this->effects); i++) {
if (effect->type == ENZO_EFFECT_BUBBLE) {
FrameInterpolation_RecordOpenChild(effect, effect->epoch);
if (!setup) {
if (1) {}
gSPDisplayList(POLY_XLU_DISP++, gZoraBubblesMaterialDL);
@ -227,6 +235,7 @@ void EnZo_DrawBubbles(EnZo* this, GlobalContext* globalCtx) {
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_en_zo_eff.c", 281),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gZoraBubblesModelDL);
FrameInterpolation_RecordCloseChild();
}
effect++;
}
@ -244,6 +253,7 @@ void EnZo_DrawSplashes(EnZo* this, GlobalContext* globalCtx) {
func_80093D84(globalCtx->state.gfxCtx);
for (i = 0; i < ARRAY_COUNT(this->effects); i++) {
if (effect->type == ENZO_EFFECT_SPLASH) {
FrameInterpolation_RecordOpenChild(effect, effect->epoch);
if (!setup) {
if (1) {}
gSPDisplayList(POLY_XLU_DISP++, gZoraSplashesMaterialDL);
@ -260,6 +270,7 @@ void EnZo_DrawSplashes(EnZo* this, GlobalContext* globalCtx) {
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gZoraSplashesModelDL);
FrameInterpolation_RecordCloseChild();
}
effect++;
}

View File

@ -15,6 +15,7 @@ typedef struct {
/* 0x14 */ Vec3f pos;
/* 0x20 */ Vec3f vel;
/* 0x2C */ Vec3f vec; // Usage specific
u32 epoch;
} EnZoEffect; // size = 0x38
typedef void (*EnZoActionFunc)(struct EnZo*, GlobalContext*);

View File

@ -10,6 +10,8 @@
#include "objects/object_fish/object_fish.h"
#include "vt.h"
#include "soh/frame_interpolation.h"
#define FLAGS ACTOR_FLAG_4
#define WATER_SURFACE_Y(globalCtx) globalCtx->colCtx.colHeader->waterBoxes->ySurface
@ -56,6 +58,7 @@ typedef struct {
/* 0x34 */ f32 unk_34;
/* 0x38 */ f32 unk_38;
/* 0x3C */ f32 unk_3C;
u32 epoch;
} FishingEffect; // size = 0x40
#define POND_PROP_COUNT 140
@ -490,6 +493,8 @@ void Fishing_SpawnRipple(Vec3f* projectedPos, FishingEffect* effect, Vec3f* pos,
effect->unk_2C = 1;
effect->unk_38 = (effect->unk_34 - effect->unk_30) * 0.1f;
}
effect->epoch++;
break;
}
@ -514,6 +519,7 @@ void Fishing_SpawnDustSplash(Vec3f* projectedPos, FishingEffect* effect, Vec3f*
effect->accel = accel;
effect->alpha = 100 + (s16)Rand_ZeroFloat(100.0f);
effect->unk_30 = scale;
effect->epoch++;
break;
}
@ -539,6 +545,7 @@ void Fishing_SpawnWaterDust(Vec3f* projectedPos, FishingEffect* effect, Vec3f* p
effect->timer = (s16)Rand_ZeroFloat(100.0f);
effect->unk_30 = scale;
effect->unk_34 = 2.0f * scale;
effect->epoch++;
break;
}
@ -563,6 +570,7 @@ void Fishing_SpawnBubble(Vec3f* projectedPos, FishingEffect* effect, Vec3f* pos,
effect->timer = (s16)Rand_ZeroFloat(100.0f);
effect->unk_30 = scale;
effect->unk_2C = arg4;
effect->epoch++;
break;
}
@ -591,6 +599,7 @@ void Fishing_SpawnRainDrop(FishingEffect* effect, Vec3f* pos, Vec3f* rot) {
Matrix_RotateY(rot->y, MTXMODE_NEW);
Matrix_RotateX(rot->x, MTXMODE_APPLY);
Matrix_MultVec3f(&velSrc, &effect->vel);
effect->epoch++;
break;
}
@ -1182,6 +1191,7 @@ void Fishing_DrawEffects(FishingEffect* effect, GlobalContext* globalCtx) {
for (i = 0; i < 100; i++) {
if (effect->type == FS_EFF_RIPPLE) {
FrameInterpolation_RecordOpenChild(effect, effect->epoch);
if (flag == 0) {
gSPDisplayList(POLY_XLU_DISP++, gFishingRippleMaterialDL);
gDPSetEnvColor(POLY_XLU_DISP++, 155, 155, 155, 0);
@ -1197,6 +1207,7 @@ void Fishing_DrawEffects(FishingEffect* effect, GlobalContext* globalCtx) {
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gFishingRippleModelDL);
FrameInterpolation_RecordCloseChild();
}
effect++;
}
@ -1205,6 +1216,7 @@ void Fishing_DrawEffects(FishingEffect* effect, GlobalContext* globalCtx) {
flag = 0;
for (i = 0; i < 100; i++) {
if (effect->type == FS_EFF_DUST_SPLASH) {
FrameInterpolation_RecordOpenChild(effect, effect->epoch);
if (flag == 0) {
gSPDisplayList(POLY_XLU_DISP++, gFishingDustSplashMaterialDL);
gDPSetEnvColor(POLY_XLU_DISP++, 200, 200, 200, 0);
@ -1221,6 +1233,7 @@ void Fishing_DrawEffects(FishingEffect* effect, GlobalContext* globalCtx) {
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gFishingDustSplashModelDL);
FrameInterpolation_RecordCloseChild();
}
effect++;
}
@ -1229,6 +1242,7 @@ void Fishing_DrawEffects(FishingEffect* effect, GlobalContext* globalCtx) {
flag = 0;
for (i = 0; i < 100; i++) {
if (effect->type == FS_EFF_WATER_DUST) {
FrameInterpolation_RecordOpenChild(effect, effect->epoch);
if (flag == 0) {
gSPDisplayList(POLY_OPA_DISP++, gFishingWaterDustMaterialDL);
gDPSetEnvColor(POLY_OPA_DISP++, 40, 90, 80, 128);
@ -1249,6 +1263,7 @@ void Fishing_DrawEffects(FishingEffect* effect, GlobalContext* globalCtx) {
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_OPA_DISP++, gFishingWaterDustModelDL);
FrameInterpolation_RecordCloseChild();
}
effect++;
}
@ -1257,6 +1272,7 @@ void Fishing_DrawEffects(FishingEffect* effect, GlobalContext* globalCtx) {
flag = 0;
for (i = 0; i < 100; i++) {
if (effect->type == FS_EFF_BUBBLE) {
FrameInterpolation_RecordOpenChild(effect, effect->epoch);
if (flag == 0) {
gSPDisplayList(POLY_XLU_DISP++, gFishingBubbleMaterialDL);
gDPSetEnvColor(POLY_XLU_DISP++, 150, 150, 150, 0);
@ -1272,6 +1288,7 @@ void Fishing_DrawEffects(FishingEffect* effect, GlobalContext* globalCtx) {
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gFishingBubbleModelDL);
FrameInterpolation_RecordCloseChild();
}
effect++;
}
@ -1280,6 +1297,7 @@ void Fishing_DrawEffects(FishingEffect* effect, GlobalContext* globalCtx) {
flag = 0;
for (i = 30; i < EFFECT_COUNT; i++) {
if (effect->type == FS_EFF_RAIN_DROP) {
FrameInterpolation_RecordOpenChild(effect, effect->epoch);
if (flag == 0) {
POLY_XLU_DISP = Gfx_CallSetupDL(POLY_XLU_DISP, 0x14);
gDPSetCombineMode(POLY_XLU_DISP++, G_CC_PRIMITIVE, G_CC_PRIMITIVE);
@ -1297,6 +1315,7 @@ void Fishing_DrawEffects(FishingEffect* effect, GlobalContext* globalCtx) {
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gFishingRainDropModelDL);
FrameInterpolation_RecordCloseChild();
}
effect++;
}
@ -1307,6 +1326,7 @@ void Fishing_DrawEffects(FishingEffect* effect, GlobalContext* globalCtx) {
flag = 0;
for (i = 30; i < EFFECT_COUNT; i++) {
if (effect->type == FS_EFF_RAIN_RIPPLE) {
FrameInterpolation_RecordOpenChild(effect, effect->epoch);
if (flag == 0) {
gSPDisplayList(POLY_XLU_DISP++, gFishingRippleMaterialDL);
gDPSetEnvColor(POLY_XLU_DISP++, 155, 155, 155, 0);
@ -1321,6 +1341,7 @@ void Fishing_DrawEffects(FishingEffect* effect, GlobalContext* globalCtx) {
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gFishingRippleModelDL);
FrameInterpolation_RecordCloseChild();
}
effect++;
}
@ -1329,6 +1350,7 @@ void Fishing_DrawEffects(FishingEffect* effect, GlobalContext* globalCtx) {
flag = 0;
for (i = 30; i < EFFECT_COUNT; i++) {
if (effect->type == FS_EFF_RAIN_SPLASH) {
FrameInterpolation_RecordOpenChild(effect, effect->epoch);
if (flag == 0) {
gSPDisplayList(POLY_XLU_DISP++, gFishingRainSplashMaterialDL);
gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 255, KREG(19) + 80);
@ -1350,12 +1372,14 @@ void Fishing_DrawEffects(FishingEffect* effect, GlobalContext* globalCtx) {
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gFishingRainSplashModelDL);
FrameInterpolation_RecordCloseChild();
}
effect++;
}
effect = firstEffect;
if (effect->type == FS_EFF_OWNER_HAT) {
FrameInterpolation_RecordOpenChild(effect, effect->epoch);
Matrix_Translate(effect->pos.x, effect->pos.y, effect->pos.z, MTXMODE_NEW);
Matrix_RotateY((sEffOwnerHatRot.y * M_PI) / 32768, MTXMODE_APPLY);
Matrix_RotateX((sEffOwnerHatRot.x * M_PI) / 32768, MTXMODE_APPLY);
@ -1367,6 +1391,7 @@ void Fishing_DrawEffects(FishingEffect* effect, GlobalContext* globalCtx) {
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_OPA_DISP++, gFishingOwnerHatDL);
FrameInterpolation_RecordCloseChild();
}
Matrix_Pop();
@ -4398,6 +4423,7 @@ void Fishing_DrawPondProps(GlobalContext* globalCtx) {
}
if (prop->shouldDraw) {
FrameInterpolation_RecordOpenChild(prop, 0);
Matrix_Translate(prop->pos.x, prop->pos.y, prop->pos.z, MTXMODE_NEW);
Matrix_Scale(prop->scale, prop->scale, prop->scale, MTXMODE_APPLY);
Matrix_RotateY(prop->rotY, MTXMODE_APPLY);
@ -4407,6 +4433,7 @@ void Fishing_DrawPondProps(GlobalContext* globalCtx) {
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_fishing.c", 7726),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gFishingReedModelDL);
FrameInterpolation_RecordCloseChild();
}
}
@ -4423,12 +4450,14 @@ void Fishing_DrawPondProps(GlobalContext* globalCtx) {
}
if (prop->shouldDraw) {
FrameInterpolation_RecordOpenChild(prop, 0);
Matrix_Translate(prop->pos.x, prop->pos.y, prop->pos.z, MTXMODE_NEW);
Matrix_Scale(prop->scale, prop->scale, prop->scale, MTXMODE_APPLY);
gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_fishing.c", 7748),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_OPA_DISP++, gFishingWoodPostModelDL);
FrameInterpolation_RecordCloseChild();
}
}
@ -4445,6 +4474,7 @@ void Fishing_DrawPondProps(GlobalContext* globalCtx) {
}
if (prop->shouldDraw) {
FrameInterpolation_RecordOpenChild(prop, 0);
Matrix_Translate(prop->pos.x, prop->pos.y, prop->pos.z, MTXMODE_NEW);
Matrix_Scale(prop->scale, 1.0f, prop->scale, MTXMODE_APPLY);
Matrix_RotateY(prop->lilyPadAngle * (M_PI / 32768), MTXMODE_APPLY);
@ -4454,6 +4484,7 @@ void Fishing_DrawPondProps(GlobalContext* globalCtx) {
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_fishing.c", 7774),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_XLU_DISP++, gFishingLilyPadModelDL);
FrameInterpolation_RecordCloseChild();
}
}
@ -4470,6 +4501,7 @@ void Fishing_DrawPondProps(GlobalContext* globalCtx) {
}
if (prop->shouldDraw) {
FrameInterpolation_RecordOpenChild(prop, 0);
Matrix_Translate(prop->pos.x, prop->pos.y, prop->pos.z, MTXMODE_NEW);
Matrix_Scale(prop->scale, prop->scale, prop->scale, MTXMODE_APPLY);
Matrix_RotateY(prop->rotY, MTXMODE_APPLY);
@ -4477,6 +4509,7 @@ void Fishing_DrawPondProps(GlobalContext* globalCtx) {
gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_fishing.c", 7798),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPDisplayList(POLY_OPA_DISP++, gFishingRockModelDL);
FrameInterpolation_RecordCloseChild();
}
}

View File

@ -9,6 +9,8 @@
#include "objects/gameplay_keep/gameplay_keep.h"
#include "objects/object_spot02_objects/object_spot02_objects.h"
#include "soh/frame_interpolation.h"
#define FLAGS (ACTOR_FLAG_4 | ACTOR_FLAG_5 | ACTOR_FLAG_25)
void ObjectKankyo_Init(Actor* thisx, GlobalContext* globalCtx);
@ -260,6 +262,7 @@ void ObjectKankyo_Fairies(ObjectKankyo* this, GlobalContext* globalCtx) {
this->effects[i].dirPhase.z = Rand_ZeroOne() * 360.0f;
this->effects[i].state++;
this->effects[i].timer = 0;
this->effects[i].epoch++;
break;
case 1: // blinking fairies / inactive fairy trails
@ -417,26 +420,32 @@ void ObjectKankyo_Fairies(ObjectKankyo* this, GlobalContext* globalCtx) {
if (this->effects[i].base.x + this->effects[i].pos.x - baseX > maxDist) {
this->effects[i].base.x = baseX - maxDist;
this->effects[i].pos.x = 0.0f;
this->effects[i].epoch++;
}
if (this->effects[i].base.x + this->effects[i].pos.x - baseX < -maxDist) {
this->effects[i].base.x = baseX + maxDist;
this->effects[i].pos.x = 0.0f;
this->effects[i].epoch++;
}
if (this->effects[i].base.y + this->effects[i].pos.y - baseY > 50.0f) {
this->effects[i].base.y = baseY - 50.0f;
this->effects[i].pos.y = 0.0f;
this->effects[i].epoch++;
}
if (this->effects[i].base.y + this->effects[i].pos.y - baseY < -50.0f) {
this->effects[i].base.y = baseY + 50.0f;
this->effects[i].pos.y = 0.0f;
this->effects[i].epoch++;
}
if (this->effects[i].base.z + this->effects[i].pos.z - baseZ > maxDist) {
this->effects[i].base.z = baseZ - maxDist;
this->effects[i].pos.z = 0.0f;
this->effects[i].epoch++;
}
if (this->effects[i].base.z + this->effects[i].pos.z - baseZ < -maxDist) {
this->effects[i].base.z = baseZ + maxDist;
this->effects[i].pos.z = 0.0f;
this->effects[i].epoch++;
}
}
}
@ -496,6 +505,7 @@ void ObjectKankyo_DrawFairies(ObjectKankyo* this2, GlobalContext* globalCtx2) {
gSPDisplayList(POLY_XLU_DISP++, gKokiriDustMoteTextureLoadDL);
for (i = 0; i < globalCtx->envCtx.unk_EE[3]; i++) {
FrameInterpolation_RecordOpenChild(&this->effects[i], this->effects[i].epoch);
Matrix_Translate(this->effects[i].base.x + this->effects[i].pos.x,
this->effects[i].base.y + this->effects[i].pos.y,
this->effects[i].base.z + this->effects[i].pos.z, MTXMODE_NEW);
@ -561,6 +571,7 @@ void ObjectKankyo_DrawFairies(ObjectKankyo* this2, GlobalContext* globalCtx2) {
Matrix_RotateZ(DEG_TO_RAD(globalCtx->state.frames * 20.0f), MTXMODE_APPLY);
gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx, "../z_object_kankyo.c", 913), G_MTX_LOAD);
gSPDisplayList(POLY_XLU_DISP++, gKokiriDustMoteDL);
FrameInterpolation_RecordCloseChild();
}
CLOSE_DISPS(globalCtx->state.gfxCtx, "../z_object_kankyo.c", 922);
}

View File

@ -24,6 +24,7 @@ typedef struct ObjectKankyoEffect {
/* 0x4A */ u16 flightRadius;
/* 0x4C */ f32 amplitude;
/* 0x50 */ u16 timer;
u32 epoch;
} ObjectKankyoEffect; // size = 0x54
typedef struct ObjectKankyo {

View File

@ -14,6 +14,8 @@
#include "vt.h"
#include "SohHooks.h"
#include "soh/frame_interpolation.h"
static void* sEquipmentFRATexs[] = {
gPauseEquipment00FRATex, gPauseEquipment01Tex, gPauseEquipment02Tex, gPauseEquipment03Tex, gPauseEquipment04Tex,
gPauseEquipment10FRATex, gPauseEquipment11Tex, gPauseEquipment12Tex, gPauseEquipment13Tex, gPauseEquipment14Tex,
@ -1047,6 +1049,7 @@ void KaleidoScope_DrawPages(GlobalContext* globalCtx, GraphicsContext* gfxCtx) {
s16 stepG;
s16 stepB;
FrameInterpolation_RecordOpenChild(NULL, pauseCtx->state + pauseCtx->pageIndex * 100);
OPEN_DISPS(gfxCtx, "../z_kaleido_scope_PAL.c", 1100);
if ((pauseCtx->state < 8) || (pauseCtx->state > 0x11)) {
@ -1418,6 +1421,7 @@ void KaleidoScope_DrawPages(GlobalContext* globalCtx, GraphicsContext* gfxCtx) {
}
CLOSE_DISPS(gfxCtx, "../z_kaleido_scope_PAL.c", 1577);
FrameInterpolation_RecordCloseChild();
}
void KaleidoScope_DrawInfoPanel(GlobalContext* globalCtx) {