From 37e47e64514bcb5799afe2c718ec2edd54a2187f Mon Sep 17 00:00:00 2001 From: Llennpie <44985633+Llennpie@users.noreply.github.com> Date: Thu, 7 Oct 2021 19:53:55 -0400 Subject: [PATCH] Add base editor, with improved UI and support for color codes --- Makefile | 10 +- actors/mario/model.inc.c | 4 +- include/types.h | 19 + platform/win/icon.ico | Bin 0 -> 35670 bytes platform/win/info.rc | 18 + src/.vscode/settings.json | 72 ++++ src/engine/graph_node.h | 16 +- src/engine/surface_collision.c | 62 ++- src/engine/surface_load.c | 6 + src/game/camera.c | 2 +- src/game/camera.h | 5 + src/game/envfx_bubbles.c | 58 ++- src/game/envfx_snow.c | 45 ++- src/game/envfx_snow.h | 3 +- src/game/hud.c | 25 +- src/game/ingame_menu.c | 66 ++- src/game/level_geo.c | 4 + src/game/mario.c | 14 +- src/game/mario.h | 4 + src/game/mario_actions_airborne.c | 7 +- src/game/mario_actions_cutscene.c | 4 +- src/game/mario_actions_moving.c | 34 +- src/game/mario_actions_stationary.c | 19 +- src/game/mario_actions_submerged.c | 4 +- src/game/object_helpers.c | 1 + src/game/paintings.c | 45 +++ src/game/rendering_graph_node.c | 471 +++++++++++++++++++--- src/game/screen_transition.c | 82 +++- src/game/shadow.c | 6 + src/menu/intro_geo.c | 20 + src/moon/achievements/achievements.cpp | 2 +- src/moon/imgui/imgui_impl.cpp | 335 +++++++++++++-- src/moon/moon64.cpp | 2 + src/moon/saturn/saturn.cpp | 130 ++++++ src/moon/saturn/saturn.h | 19 + src/moon/saturn/saturn_colors.cpp | 343 ++++++++++++++++ src/moon/saturn/saturn_colors.h | 14 + src/moon/saturn/saturn_types.h | 54 +++ src/moon/ui/moon-ui-manager.cpp | 2 + src/moon/ui/screens/options/main-view.cpp | 2 +- src/pc/configfile.c | 16 +- src/pc/configfile.h | 4 + src/pc/discord/discordrpc.cpp | 42 +- src/pc/gfx/gfx_pc.c | 87 +++- src/pc/gfx/gfx_screen_config.h | 4 +- src/pc/gfx/gfx_sdl2.c | 10 +- src/pc/pc_main.c | 27 +- 47 files changed, 2054 insertions(+), 165 deletions(-) create mode 100644 platform/win/icon.ico create mode 100644 platform/win/info.rc create mode 100644 src/.vscode/settings.json create mode 100644 src/moon/saturn/saturn.cpp create mode 100644 src/moon/saturn/saturn.h create mode 100644 src/moon/saturn/saturn_colors.cpp create mode 100644 src/moon/saturn/saturn_colors.h create mode 100644 src/moon/saturn/saturn_types.h diff --git a/Makefile b/Makefile index 5ba0bd0c..156c6b91 100644 --- a/Makefile +++ b/Makefile @@ -123,7 +123,7 @@ endif # Release (version) flag defs VERSION_DEF := VERSION_US -TARGET := moon64.$(VERSION) +TARGET := saturn.$(VERSION) VERSION_CFLAGS := -D$(VERSION_DEF) -D_LANGUAGE_C VERSION_ASFLAGS := --defsym $(VERSION_DEF)=1 @@ -672,8 +672,10 @@ ifeq ($(TARGET_SWITCH),1) all: $(EXE).nro endif -ADDONS := addons -ADDONS_PATH := $(BUILD_DIR)/$(ADDONS)/ +ADDONS := addons +ADDONS_PATH := $(BUILD_DIR)/$(ADDONS)/ +MACHINIMA := machinima +MACHINIMA_PATH := $(BUILD_DIR)/$(MACHINIMA)/ BASEPACK_LST := $(BUILD_DIR)/basepack.lst # depend on resources as well @@ -721,7 +723,7 @@ $(BUILD_DIR)/src/game/crash_screen.o: $(CRASH_TEXTURE_C_FILES) $(BUILD_DIR)/lib/rsp.o: $(BUILD_DIR)/rsp/rspboot.bin $(BUILD_DIR)/rsp/fast3d.bin $(BUILD_DIR)/rsp/audio.bin RSP_DIRS := $(BUILD_DIR)/rsp -ALL_DIRS := $(BUILD_DIR) $(addprefix $(BUILD_DIR)/,$(SRC_DIRS) $(ASM_DIRS) $(GODDARD_SRC_DIRS) $(ULTRA_SRC_DIRS) $(ULTRA_ASM_DIRS) $(ULTRA_BIN_DIRS) $(BIN_DIRS) $(TEXTURE_DIRS) $(SOUND_SAMPLE_DIRS) $(addprefix levels/,$(LEVEL_DIRS)) include) $(MIO0_DIR) $(addprefix $(MIO0_DIR)/,$(VERSION)) $(SOUND_BIN_DIR) $(SOUND_BIN_DIR)/sequences/$(VERSION) $(RSP_DIRS) $(ADDONS_PATH) +ALL_DIRS := $(BUILD_DIR) $(addprefix $(BUILD_DIR)/,$(SRC_DIRS) $(ASM_DIRS) $(GODDARD_SRC_DIRS) $(ULTRA_SRC_DIRS) $(ULTRA_ASM_DIRS) $(ULTRA_BIN_DIRS) $(BIN_DIRS) $(TEXTURE_DIRS) $(SOUND_SAMPLE_DIRS) $(addprefix levels/,$(LEVEL_DIRS)) include) $(MIO0_DIR) $(addprefix $(MIO0_DIR)/,$(VERSION)) $(SOUND_BIN_DIR) $(SOUND_BIN_DIR)/sequences/$(VERSION) $(RSP_DIRS) $(ADDONS_PATH) $(MACHINIMA_PATH) # Make sure build directory exists before compiling anything DUMMY != mkdir -p $(ALL_DIRS) diff --git a/actors/mario/model.inc.c b/actors/mario/model.inc.c index f7a2b272..614038d1 100644 --- a/actors/mario/model.inc.c +++ b/actors/mario/model.inc.c @@ -14,8 +14,8 @@ static const Lights1 mario_red_lights_group = gdSPDefLights1( // 0x04000030 # solid color white - metal butt & left thigh - normal left & right hand closed & open (with cap too) and all wings - all poly types static const Lights1 mario_white_lights_group = gdSPDefLights1( - 0x7f, 0x7f, 0x7f, - 0xff, 0xff, 0xff, 0x28, 0x28, 0x28 + 0x00, 0x7f, 0x00, + 0x00, 0xff, 0x00, 0x28, 0x28, 0x28 ); // 0x04000048 # solid color brown 1 - foot - all poly types diff --git a/include/types.h b/include/types.h index b3dc27e2..c46bdf01 100644 --- a/include/types.h +++ b/include/types.h @@ -118,6 +118,10 @@ struct GraphNodeObject_sub /*0x0A 0x42*/ u16 animTimer; /*0x0C 0x44*/ s32 animFrameAccelAssist; /*0x10 0x48*/ s32 animAccel; + s16 prevAnimFrame; + s16 prevAnimID; + u32 prevAnimFrameTimestamp; + struct Animation *prevAnimPtr; }; struct GraphNodeObject @@ -128,11 +132,22 @@ struct GraphNodeObject /*0x19*/ s8 unk19; /*0x1A*/ Vec3s angle; /*0x20*/ Vec3f pos; + Vec3s prevAngle; + Vec3f prevPos; + u32 prevTimestamp; + Vec3f prevShadowPos; + u32 prevShadowPosTimestamp; /*0x2C*/ Vec3f scale; + Vec3f prevScale; + u32 prevScaleTimestamp; /*0x38*/ struct GraphNodeObject_sub unk38; /*0x4C*/ struct SpawnInfo *unk4C; /*0x50*/ Mat4 *throwMatrix; // matrix ptr + Mat4 prevThrowMatrix; + u32 prevThrowMatrixTimestamp; + Mat4 *throwMatrixInterpolated; /*0x54*/ Vec3f cameraToObject; + u32 skipInterpolationTimestamp; }; struct ObjectNode @@ -243,6 +258,10 @@ struct Surface } normal; /*0x28*/ f32 originOffset; /*0x2C*/ struct Object *object; + Vec3s prevVertex1; + Vec3s prevVertex2; + Vec3s prevVertex3; + u32 modifiedTimestamp; }; struct MarioBodyState diff --git a/platform/win/icon.ico b/platform/win/icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..78b51ae235c5d7302149bae3caa4a7e803dda0be GIT binary patch literal 35670 zcmeHQzmFqH6|UIF4r8_Ehzt&3X}?z3hb)Dm%bMxk6ki6_l=*#$b)t7 z1Ls)o0@s*xHaU04RsYa*F21pRjW?%X^8f!{|GD*`e5Jqo!x(vd|7S7o8@isp{DT;I zsC}h#>ovz$drGUm@|EV?9p9I`^Gg2R8gTC&*ZL~0{TWNEJ*Cy2@|AvQ{nz!W`Q&KL zHz$ABeC^Lzy5!%zMvd)H>3{e2ZfyOg%8y;|Du4ak7#20<|NirT-`aPc)^jYa>sj@cuXJwx|KWoed8mEuf0W~2|Bi9r`1n6D z?i=baN9*~k`6^xV-+%q*-aD@KFa7VH|FZn|u6;i*_N{&AX}xpw*!8deRbTz-^-Ry7 z=hrdv`0h_*bz2n?_ z$8-A19~)mz{?p$7Tz!fiDy{aFo*MsDeT`>ozN)YGm7W^^RDF#{5_l<^E3{e9=e6&6ZvE)`Q(D*WUDFz$`p?nY z|D1e|f7kit?3MhxYc$s%<(K|<&ws7YSUR^}56#!}LErByU*l2!Sbep3-}Kb@r|RE# zzUpsk{8RNcp8KY!#y?g6zVj{qN(D*<9&QEn^NC8|M9(e8BwRUv6>n0|+0Ne&S8IL( zhV}d{U>nzJ9bX?dk$HX|K_A8@|CN=c&7%j~z)i79@a|#C?`Hlc+*sW1csJCJc4_}R z5l?OW$j0XHM10+da+C@jr~>?+Cgp^s}x^~1aO)b}X$J4~S2W(w!^%rP@w;%~cftooy$4!K|4Q(n{Duhe((*iH&(`z*ur zL%wTQ;%~nbIre*yT<0nE=k>sL_#EeXzAo|SdHB0L{5>9)=kM>ZP0l6dm**KT@weZp zJ68RC})ZC{dou}z+5yu{zX581Ek?Pj>n+=~>>>nA0Xn!jCy`?X5^{k3tQ_2=$zFL=+x z^Hbzm_YgS8S>kW+`5mIp#b&8MssimDZ~ugpA6xj!KKHaTTH!};+vkaFz6Z@gGrtS| z&E$PvVE9ZsKM1;C*BAKelXaW|{c~F$PY+&OAaB|HRG6~=N%+X?78Oc;8`9+bb6Qt6 zp4r%ZPRl3Cv9khrtyL!Wtl*D@YA;2@uJZ5Ozs3O?5YHC*HP&&&iO;`49#HdA8ghW( zg9bd5f8+x{3gK7hhtkL=1&{3?`=nGHnm<1;bUarFJd;Aa$iKb5_Wvd^ zKcjRUdJ0irT4+#4>|FK?Cf6&T@K48u-_>c#@ zZ~w>#{y_sG9^{XE(8`BCAo9yW*nu8sz(e~-eDH@j6e53}R~q)l!ejeKyodwmJ?No) z$lVsg-?9APHtyG55Bu2izuH|4A1}A#O~ZYh@GzM-eSG-R^laEIhqrwE*KV8a z8sNv5FJm*-j=T3M7NI%Tpe5S>eV^gy8s2O8`%K@H`*pytJ^tA^Un9?Lf9h+*_hG&_ z^L?7{&3xbK*Jk`?g1a}%Wt19}HSjRj0ACJnjnC&No1?0Bn3-+Z4YHMJr7N4A&1yU5 z^V8F=g@!VLE&t?X>!Pk(%d^IV+cEBz9m2e7CO7YIn5eHxkv!VjjZTx$~DxLqlDkpI=;@+p#)7J9Dlj?*E1Pa&EsxAF8vn zhJUtNefG?(`_aVTN*UorwHc}2TFRw8apN}?YV_&9Cga9}W83O(L|ohdHPB@?97DXI z^ZC+_4P>_CYkpNhj(xb%`TXL-Drc2wV3XU{i0Lhu@1brF>p0o^C^v*zaE{}b4^!S^}fzE{E?+HLZ0-&N4&){Am+i`!;cRu{PPq*j$LhKQp2R@+h51|kLPCMV@@V%q& zCGndh_-zry?Q+m(+~*Ld?_c#d3!syN&;@iGzyWi*-fz#zhwCWqbGvN7zRP?5o|pS~ z2pTfG^j*&R4t=;C*T>%}bb6n@+k_3sjmaM|xee_p(~!Fh=#_lm{)Wgq_6+*khrOm< zztN6&4F9w7Zv6SQU12et{`fbx2{YX%7R2^Cv%bK{Mc(5q?}y5JH(LgN-j?y{tbtz! z+II#fWE=j=Sye3``DQZA zf^F~@cJW&J#{H~$H_$kCOP&3(@2FwWx5CS1Wn&ZM?4l0!Me{Df<`!X5&u#G4&GGGq O`P5wb*l|p~&i)UbK#&js literal 0 HcmV?d00001 diff --git a/platform/win/info.rc b/platform/win/info.rc new file mode 100644 index 00000000..f65b2d27 --- /dev/null +++ b/platform/win/info.rc @@ -0,0 +1,18 @@ +IDI_ICON1 ICON DISCARDABLE "icon.ico" +1 VERSIONINFO +FILEVERSION 1,0,0,0 +PRODUCTVERSION 1,0,0,0 +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904E4" + BEGIN + VALUE "InternalName", "v64saturn" + VALUE "ProductName", "Saturn" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 0 + END +END diff --git a/src/.vscode/settings.json b/src/.vscode/settings.json new file mode 100644 index 00000000..de362293 --- /dev/null +++ b/src/.vscode/settings.json @@ -0,0 +1,72 @@ +{ + "files.associations": { + "random": "c", + "saturn.h": "c", + "achievements.h": "c", + "cheats.h": "c", + "save_file.h": "c", + "saturn_types.h": "c", + "object_list_processor.h": "c", + "typeinfo": "c", + "vector": "cpp", + "array": "cpp", + "atomic": "cpp", + "bit": "cpp", + "*.tcc": "cpp", + "bitset": "cpp", + "cctype": "cpp", + "chrono": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "codecvt": "cpp", + "condition_variable": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "deque": "cpp", + "forward_list": "cpp", + "list": "cpp", + "map": "cpp", + "unordered_map": "cpp", + "exception": "cpp", + "algorithm": "cpp", + "functional": "cpp", + "iterator": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "numeric": "cpp", + "optional": "cpp", + "ratio": "cpp", + "regex": "cpp", + "string": "cpp", + "string_view": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "fstream": "cpp", + "initializer_list": "cpp", + "iomanip": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "limits": "cpp", + "new": "cpp", + "ostream": "cpp", + "shared_mutex": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "streambuf": "cpp", + "cinttypes": "cpp", + "valarray": "cpp", + "compare": "cpp", + "concepts": "cpp", + "ranges": "cpp" + } +} \ No newline at end of file diff --git a/src/engine/graph_node.h b/src/engine/graph_node.h index 802d97a8..1b0d6772 100644 --- a/src/engine/graph_node.h +++ b/src/engine/graph_node.h @@ -110,6 +110,8 @@ struct GraphNodePerspective /*0x1C*/ f32 fov; // horizontal field of view in degrees /*0x20*/ s16 near; // near clipping plane /*0x22*/ s16 far; // far clipping plane + f32 prevFov; + f32 prevTimestamp; }; /** An entry in the master list. It is a linked list of display lists @@ -118,7 +120,9 @@ struct GraphNodePerspective struct DisplayListNode { Mtx *transform; + void *transformInterpolated; void *displayList; + void *displayListInterpolated; struct DisplayListNode *next; }; @@ -185,7 +189,11 @@ struct GraphNodeCamera } config; /*0x1C*/ Vec3f pos; /*0x28*/ Vec3f focus; + Vec3f prevPos; + Vec3f prevFocus; + u32 prevTimestamp; /*0x34*/ Mat4 *matrixPtr; // pointer to look-at matrix of this camera as a Mat4 + Mat4 *matrixPtrInterpolated; /*0x38*/ s16 roll; // roll in look at matrix. Doesn't account for light direction unlike rollScreen. /*0x3A*/ s16 rollScreen; // rolls screen while keeping the light direction consistent }; @@ -226,7 +234,8 @@ struct GraphNodeRotation /*0x00*/ struct GraphNode node; /*0x14*/ void *displayList; /*0x18*/ Vec3s rotation; - u8 pad1E[2]; + Vec3s prevRotation; + u32 prevTimestamp; }; /** GraphNode part that transforms itself and its children based on animation @@ -323,6 +332,9 @@ struct GraphNodeBackground /*0x00*/ struct FnGraphNode fnNode; /*0x18*/ s32 unused; /*0x1C*/ s32 background; // background ID, or rgba5551 color if fnNode.func is null + Vec3f prevCameraPos; + Vec3f prevCameraFocus; + u32 prevCameraTimestamp; }; /** Renders the object that Mario is holding. @@ -333,6 +345,8 @@ struct GraphNodeHeldObject /*0x18*/ s32 playerIndex; /*0x1C*/ struct Object *objNode; /*0x20*/ Vec3s translation; + Vec3f prevShadowPos; + u32 prevShadowPosTimestamp; }; /** A node that allows an object to specify a different culling radius than the diff --git a/src/engine/surface_collision.c b/src/engine/surface_collision.c index 5b6775fe..2c11e254 100644 --- a/src/engine/surface_collision.c +++ b/src/engine/surface_collision.c @@ -8,6 +8,7 @@ #include "surface_collision.h" #include "surface_load.h" #include "math_util.h" +#include "game/game_init.h" /************************************************** * WALLS * @@ -394,26 +395,44 @@ f32 find_floor_height_and_data(f32 xPos, f32 yPos, f32 zPos, struct FloorGeometr return floorHeight; } +u8 gInterpolatingSurfaces; + /** * Iterate through the list of floors and find the first floor under a given point. */ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32 x, s32 y, s32 z, f32 *pheight) { register struct Surface *surf; - register s32 x1, z1, x2, z2, x3, z3; + register f32 x1, z1, x2, z2, x3, z3; f32 nx, ny, nz; f32 oo; f32 height; struct Surface *floor = NULL; + s32 interpolate; // Iterate through the list of floors until there are no more floors. while (surfaceNode != NULL) { surf = surfaceNode->surface; surfaceNode = surfaceNode->next; + interpolate = gInterpolatingSurfaces && surf->modifiedTimestamp == gGlobalTimer; x1 = surf->vertex1[0]; z1 = surf->vertex1[2]; x2 = surf->vertex2[0]; z2 = surf->vertex2[2]; + if (interpolate) { + f32 diff = (surf->prevVertex1[0] - x1) * (surf->prevVertex1[0] - x1); + diff += (surf->prevVertex1[1] - surf->vertex1[1]) * (surf->prevVertex1[1] - surf->vertex1[1]); + diff += (surf->prevVertex1[2] - z1) * (surf->prevVertex1[2] - z1); + //printf("%f\n", sqrtf(diff)); + if (diff > 10000) { + interpolate = FALSE; + } else { + x1 = (surf->prevVertex1[0] + x1) / 2; + z1 = (surf->prevVertex1[2] + z1) / 2; + x2 = (surf->prevVertex2[0] + x2) / 2; + z2 = (surf->prevVertex2[2] + z2) / 2; + } + } // Check that the point is within the triangle bounds. if ((z1 - z) * (x2 - x1) - (x1 - x) * (z2 - z1) < 0) { @@ -423,6 +442,10 @@ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32 // To slightly save on computation time, set this later. x3 = surf->vertex3[0]; z3 = surf->vertex3[2]; + if (interpolate) { + x3 = (surf->prevVertex3[0] + x3) / 2; + z3 = (surf->prevVertex3[2] + z3) / 2; + } if ((z2 - z) * (x3 - x2) - (x2 - x) * (z3 - z2) < 0) { continue; @@ -442,10 +465,30 @@ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32 continue; } - nx = surf->normal.x; - ny = surf->normal.y; - nz = surf->normal.z; - oo = surf->originOffset; + if (interpolate) { + f32 y1, y2, y3; + f32 mag; + y1 = (surf->prevVertex1[1] + surf->vertex1[1]) / 2; + y2 = (surf->prevVertex2[1] + surf->vertex2[1]) / 2; + y3 = (surf->prevVertex3[1] + surf->vertex3[1]) / 2; + nx = (y2 - y1) * (z3 - z2) - (z2 - z1) * (y3 - y2); + ny = (z2 - z1) * (x3 - x2) - (x2 - x1) * (z3 - z2); + nz = (x2 - x1) * (y3 - y2) - (y2 - y1) * (x3 - x2); + mag = sqrtf(nx * nx + ny * ny + nz * nz); + if (mag < 0.0001) { + continue; + } + mag = (f32)(1.0 / mag); + nx *= mag; + ny *= mag; + nz *= mag; + oo = -(nx * x1 + ny * y1 + nz * z1); + } else { + nx = surf->normal.x; + ny = surf->normal.y; + nz = surf->normal.z; + oo = surf->originOffset; + } // If a wall, ignore it. Likely a remnant, should never occur. if (ny == 0.0f) { @@ -460,6 +503,15 @@ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32 } *pheight = height; + if (interpolate) { + static struct Surface s; + s.type = surf->type; + s.normal.x = nx; + s.normal.y = ny; + s.normal.z = nz; + s.originOffset = oo; + return &s; + } floor = surf; break; } diff --git a/src/engine/surface_load.c b/src/engine/surface_load.c index bb72c869..75a49031 100644 --- a/src/engine/surface_load.c +++ b/src/engine/surface_load.c @@ -14,6 +14,7 @@ #include "game/mario.h" #include "game/object_list_processor.h" #include "surface_load.h" +#include "game/game_init.h" s32 unused8038BE90; @@ -354,6 +355,11 @@ static struct Surface *read_surface_data(s16 *vertexData, s16 **vertexIndices) { surface = alloc_surface(); + vec3s_copy(surface->prevVertex1, surface->vertex1); + vec3s_copy(surface->prevVertex2, surface->vertex2); + vec3s_copy(surface->prevVertex3, surface->vertex3); + surface->modifiedTimestamp = gGlobalTimer; + surface->vertex1[0] = x1; surface->vertex2[0] = x2; surface->vertex3[0] = x3; diff --git a/src/game/camera.c b/src/game/camera.c index be7ae4f0..da1f1964 100644 --- a/src/game/camera.c +++ b/src/game/camera.c @@ -11617,4 +11617,4 @@ void obj_rotate_towards_point(struct Object *o, Vec3f point, s16 pitchOff, s16 y #include "behaviors/intro_lakitu.inc.c" #include "behaviors/end_birds_1.inc.c" #include "behaviors/end_birds_2.inc.c" -#include "behaviors/intro_scene.inc.c" +#include "behaviors/intro_scene.inc.c" \ No newline at end of file diff --git a/src/game/camera.h b/src/game/camera.h index 173ab8a7..09ed5c05 100644 --- a/src/game/camera.h +++ b/src/game/camera.h @@ -657,6 +657,8 @@ struct LakituState /// Mario's action from the previous frame. Only used to determine if Mario just finished a dive. /*0xB8*/ u32 lastFrameAction; /*0xBC*/ s16 unused; + + u32 skipCameraInterpolationTimestamp; }; // bss order hack to not affect BSS order. if possible, remove me, but it will be hard to match otherwise @@ -773,4 +775,7 @@ void obj_rotate_towards_point(struct Object *o, Vec3f point, s16 pitchOff, s16 y Gfx *geo_camera_fov(s32 callContext, struct GraphNode *g, UNUSED void *context); +extern u8 machinimaMode; +extern f32 camVelSpeed; + #endif // CAMERA_H diff --git a/src/game/envfx_bubbles.c b/src/game/envfx_bubbles.c index 060a12da..b866a914 100644 --- a/src/game/envfx_bubbles.c +++ b/src/game/envfx_bubbles.c @@ -35,6 +35,20 @@ Vtx_t gBubbleTempVtx[3] = { { { 0, 0, 0 }, 0, { -498, 964 }, { 0xFF, 0xFF, 0xFF, 0xFF } }, }; +static Gfx sGfxSaved[60 / 5]; +static Gfx *sBubbleInterpolatedDisplayListPos[60 / 5]; +static Vec3s sPrevBubblePositions[60]; + +void patch_interpolated_bubble_particles(void) { + s32 i; + for (i = 0; i < 60 / 5; i++) { + if (sBubbleInterpolatedDisplayListPos[i] != NULL) { + *sBubbleInterpolatedDisplayListPos[i] = sGfxSaved[i]; + sBubbleInterpolatedDisplayListPos[i] = NULL; + } + } +} + /** * Check whether the particle with the given index is * laterally within distance of point (x, z). Used to @@ -241,6 +255,7 @@ void envfx_update_whirlpool(void) { (gEnvFxBuffer + i)->yPos = (i + gEnvFxBuffer)->bubbleY; (gEnvFxBuffer + i)->unusedBubbleVar = 0; (gEnvFxBuffer + i)->isAlive = 1; + (gEnvFxBuffer + i)->spawnTimestamp = gGlobalTimer; envfx_rotate_around_whirlpool(&(gEnvFxBuffer + i)->xPos, &(gEnvFxBuffer + i)->yPos, &(gEnvFxBuffer + i)->zPos); @@ -299,6 +314,7 @@ void envfx_update_jetstream(void) { + coss((gEnvFxBuffer + i)->angleAndDist[0]) * (gEnvFxBuffer + i)->angleAndDist[1]; (gEnvFxBuffer + i)->yPos = gEnvFxBubbleConfig[ENVFX_STATE_SRC_Y] + (random_float() * 400.0f - 200.0f); + (gEnvFxBuffer + i)->spawnTimestamp = gGlobalTimer; } else { (gEnvFxBuffer + i)->angleAndDist[1] += 10; (gEnvFxBuffer + i)->xPos += sins((gEnvFxBuffer + i)->angleAndDist[0]) * 10.0f; @@ -506,6 +522,12 @@ Gfx *envfx_update_bubble_particles(s32 mode, UNUSED Vec3s marioPos, Vec3s camFro Vec3s vertex1; Vec3s vertex2; Vec3s vertex3; + Vec3s interpolatedVertices[3]; + + static Vec3s prevVertex1; + static Vec3s prevVertex2; + static Vec3s prevVertex3; + static u32 prevTimestamp; Gfx *gfxStart; @@ -521,18 +543,52 @@ Gfx *envfx_update_bubble_particles(s32 mode, UNUSED Vec3s marioPos, Vec3s camFro envfx_bubbles_update_switch(mode, camTo, vertex1, vertex2, vertex3); rotate_triangle_vertices(vertex1, vertex2, vertex3, pitch, yaw); + if (gGlobalTimer == prevTimestamp + 1) { + interpolate_vectors_s16(interpolatedVertices[0], prevVertex1, vertex1); + interpolate_vectors_s16(interpolatedVertices[1], prevVertex2, vertex2); + interpolate_vectors_s16(interpolatedVertices[2], prevVertex3, vertex3); + } + vec3s_copy(prevVertex1, vertex1); + vec3s_copy(prevVertex2, vertex2); + vec3s_copy(prevVertex3, vertex3); + prevTimestamp = gGlobalTimer; + gSPDisplayList(sGfxCursor++, &tiny_bubble_dl_0B006D38); for (i = 0; i < sBubbleParticleMaxCount; i += 5) { + Vtx *interpolatedVertBuf = alloc_display_list(15 * sizeof(Vtx)); + s32 j, k; gDPPipeSync(sGfxCursor++); envfx_set_bubble_texture(mode, i); - append_bubble_vertex_buffer(sGfxCursor++, i, vertex1, vertex2, vertex3, (Vtx *) gBubbleTempVtx); + sBubbleInterpolatedDisplayListPos[i / 5] = sGfxCursor; + for (j = 0; j < 5; j++) { + for (k = 0; k < 3; k++) { + Vtx *v = &interpolatedVertBuf[j * 3 + k]; + v->v = gBubbleTempVtx[k]; + if (gGlobalTimer != gEnvFxBuffer[i + j].spawnTimestamp && mode != ENVFX_LAVA_BUBBLES) { + v->v.ob[0] = (sPrevBubblePositions[i + j][0] + gEnvFxBuffer[i + j].xPos) / 2.0f + interpolatedVertices[k][0]; + v->v.ob[1] = (sPrevBubblePositions[i + j][1] + gEnvFxBuffer[i + j].yPos) / 2.0f + interpolatedVertices[k][1]; + v->v.ob[2] = (sPrevBubblePositions[i + j][2] + gEnvFxBuffer[i + j].zPos) / 2.0f + interpolatedVertices[k][2]; + } else { + v->v.ob[0] = gEnvFxBuffer[i + j].xPos + interpolatedVertices[k][0]; + v->v.ob[1] = gEnvFxBuffer[i + j].yPos + interpolatedVertices[k][1]; + v->v.ob[2] = gEnvFxBuffer[i + j].zPos + interpolatedVertices[k][2]; + } + } + } + gSPVertex(sGfxCursor++, VIRTUAL_TO_PHYSICAL(interpolatedVertBuf), 15, 0); + append_bubble_vertex_buffer(&sGfxSaved[i / 5], i, vertex1, vertex2, vertex3, (Vtx *) gBubbleTempVtx); gSP1Triangle(sGfxCursor++, 0, 1, 2, 0); gSP1Triangle(sGfxCursor++, 3, 4, 5, 0); gSP1Triangle(sGfxCursor++, 6, 7, 8, 0); gSP1Triangle(sGfxCursor++, 9, 10, 11, 0); gSP1Triangle(sGfxCursor++, 12, 13, 14, 0); } + for (i = 0; i < sBubbleParticleMaxCount; i++) { + sPrevBubblePositions[i][0] = gEnvFxBuffer[i].xPos; + sPrevBubblePositions[i][1] = gEnvFxBuffer[i].yPos; + sPrevBubblePositions[i][2] = gEnvFxBuffer[i].zPos; + } gSPDisplayList(sGfxCursor++, &tiny_bubble_dl_0B006AB0); gSPEndDisplayList(sGfxCursor++); diff --git a/src/game/envfx_snow.c b/src/game/envfx_snow.c index c3c14a5c..d2212ef6 100644 --- a/src/game/envfx_snow.c +++ b/src/game/envfx_snow.c @@ -54,6 +54,26 @@ extern void *tiny_bubble_dl_0B006AB0; extern void *tiny_bubble_dl_0B006A50; extern void *tiny_bubble_dl_0B006CD8; +static struct { + Gfx *pos; + Vtx vertices[15]; +} sPrevSnowVertices[140 / 5]; +static s16 sPrevSnowParticleCount; +static u32 sPrevSnowTimestamp; + +void patch_interpolated_snow_particles(void) { + int i; + + if (gGlobalTimer != sPrevSnowTimestamp + 1) { + return; + } + + for (i = 0; i < sPrevSnowParticleCount; i += 5) { + gSPVertex(sPrevSnowVertices[i / 5].pos, + VIRTUAL_TO_PHYSICAL(sPrevSnowVertices[i / 5].vertices), 15, 0); + } +} + /** * Initialize snow particles by allocating a buffer for storing their state * and setting a start amount. @@ -217,6 +237,7 @@ void envfx_update_snow_normal(s32 snowCylinderX, s32 snowCylinderY, s32 snowCyli 400.0f * random_float() - 200.0f + snowCylinderZ + (s16)(deltaZ * 2); (gEnvFxBuffer + i)->yPos = 200.0f * random_float() + snowCylinderY; (gEnvFxBuffer + i)->isAlive = 1; + (gEnvFxBuffer + i)->spawnTimestamp = gGlobalTimer; } else { (gEnvFxBuffer + i)->xPos += random_float() * 2 - 1.0f + (s16)(deltaX / 1.2); (gEnvFxBuffer + i)->yPos -= 2 -(s16)(deltaY * 0.8); @@ -251,6 +272,7 @@ void envfx_update_snow_blizzard(s32 snowCylinderX, s32 snowCylinderY, s32 snowCy 400.0f * random_float() - 200.0f + snowCylinderZ + (s16)(deltaZ * 2); (gEnvFxBuffer + i)->yPos = 400.0f * random_float() - 200.0f + snowCylinderY; (gEnvFxBuffer + i)->isAlive = 1; + (gEnvFxBuffer + i)->spawnTimestamp = gGlobalTimer; } else { (gEnvFxBuffer + i)->xPos += random_float() * 2 - 1.0f + (s16)(deltaX / 1.2) + 20.0f; (gEnvFxBuffer + i)->yPos -= 5 -(s16)(deltaY * 0.8); @@ -294,6 +316,7 @@ void envfx_update_snow_water(s32 snowCylinderX, s32 snowCylinderY, s32 snowCylin (gEnvFxBuffer + i)->zPos = 400.0f * random_float() - 200.0f + snowCylinderZ; (gEnvFxBuffer + i)->yPos = 400.0f * random_float() - 200.0f + snowCylinderY; (gEnvFxBuffer + i)->isAlive = 1; + (gEnvFxBuffer + i)->spawnTimestamp = gGlobalTimer; } } } @@ -346,6 +369,8 @@ void rotate_triangle_vertices(Vec3s vertex1, Vec3s vertex2, Vec3s vertex3, s16 p void append_snowflake_vertex_buffer(Gfx *gfx, s32 index, Vec3s vertex1, Vec3s vertex2, Vec3s vertex3) { s32 i = 0; Vtx *vertBuf = (Vtx *) alloc_display_list(15 * sizeof(Vtx)); + Vtx *vertBufInterpolated = (Vtx *) alloc_display_list(15 * sizeof(Vtx)); + Vtx *v; #ifdef VERSION_EU Vtx *p; #endif @@ -395,7 +420,23 @@ void append_snowflake_vertex_buffer(Gfx *gfx, s32 index, Vec3s vertex1, Vec3s ve #endif } - gSPVertex(gfx, VIRTUAL_TO_PHYSICAL(vertBuf), 15, 0); + for (i = 0; i < 15; i++) { + v = &sPrevSnowVertices[index / 5].vertices[i]; + vertBufInterpolated[i] = gSnowTempVtx[i % 3]; + if (index < sPrevSnowParticleCount && gGlobalTimer == sPrevSnowTimestamp + 1 && + gGlobalTimer != gEnvFxBuffer[index + i / 3].spawnTimestamp) { + vertBufInterpolated[i].v.ob[0] = (v->v.ob[0] + vertBuf[i].v.ob[0]) / 2; + vertBufInterpolated[i].v.ob[1] = (v->v.ob[1] + vertBuf[i].v.ob[1]) / 2; + vertBufInterpolated[i].v.ob[2] = (v->v.ob[2] + vertBuf[i].v.ob[2]) / 2; + } else { + vertBufInterpolated[i].v.ob[0] = vertBuf[i].v.ob[0]; + vertBufInterpolated[i].v.ob[1] = vertBuf[i].v.ob[1]; + vertBufInterpolated[i].v.ob[2] = vertBuf[i].v.ob[2]; + } + *v = vertBuf[i]; + } + sPrevSnowVertices[index / 5].pos = gfx; + gSPVertex(gfx, VIRTUAL_TO_PHYSICAL(vertBufInterpolated), 15, 0); } /** @@ -479,6 +520,8 @@ Gfx *envfx_update_snow(s32 snowMode, Vec3s marioPos, Vec3s camFrom, Vec3s camTo) gSP1Triangle(gfx++, 9, 10, 11, 0); gSP1Triangle(gfx++, 12, 13, 14, 0); } + sPrevSnowParticleCount = gSnowParticleCount; + sPrevSnowTimestamp = gGlobalTimer; gSPDisplayList(gfx++, &tiny_bubble_dl_0B006AB0) gSPEndDisplayList(gfx++); diff --git a/src/game/envfx_snow.h b/src/game/envfx_snow.h index 7a83b536..f4acc2de 100644 --- a/src/game/envfx_snow.h +++ b/src/game/envfx_snow.h @@ -25,7 +25,8 @@ struct EnvFxParticle { s32 angleAndDist[2]; // for whirpools, [0] = angle from center, [1] = distance from center s32 unusedBubbleVar; // set to zero for bubbles when respawning, never used elsewhere s32 bubbleY; // for Bubbles, yPos is always set to this - s8 filler20[56 - 0x20]; + //s8 filler20[56 - 0x20]; + u32 spawnTimestamp; }; extern s8 gEnvFxMode; diff --git a/src/game/hud.c b/src/game/hud.c index 86233d3e..26912f80 100644 --- a/src/game/hud.c +++ b/src/game/hud.c @@ -82,6 +82,20 @@ void render_hud_texture(s32 x, s32 y, u32 w, u32 h, u8 *texture) { gSPDisplayList(gDisplayListHead++, dl_hud_img_end); } +static u32 sPowerMeterLastRenderTimestamp; +static s16 sPowerMeterLastY; +static Gfx *sPowerMeterDisplayListPos; + +void patch_interpolated_hud(void) { + if (sPowerMeterDisplayListPos != NULL) { + Mtx *mtx = alloc_display_list(sizeof(Mtx)); + guTranslate(mtx, (f32) sPowerMeterHUD.x, (f32) sPowerMeterHUD.y, 0); + gSPMatrix(sPowerMeterDisplayListPos, VIRTUAL_TO_PHYSICAL(mtx), + G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_PUSH); + sPowerMeterDisplayListPos = NULL; + } +} + /** * Renders a rgba16 16x16 glyph texture from a table list. */ @@ -134,6 +148,7 @@ void render_power_meter_health_segment(s16 numHealthWedges) { */ void render_dl_power_meter(s16 numHealthWedges) { Mtx *mtx; + f32 interpolatedY; mtx = alloc_display_list(sizeof(Mtx)); @@ -141,7 +156,15 @@ void render_dl_power_meter(s16 numHealthWedges) { return; } - guTranslate(mtx, (f32) sPowerMeterHUD.x, (f32) sPowerMeterHUD.y, 0); + if (gGlobalTimer == sPowerMeterLastRenderTimestamp + 1) { + interpolatedY = (sPowerMeterLastY + sPowerMeterHUD.y) / 2.0f; + } else { + interpolatedY = sPowerMeterHUD.y; + } + guTranslate(mtx, (f32) sPowerMeterHUD.x, interpolatedY, 0); + sPowerMeterLastY = sPowerMeterHUD.y; + sPowerMeterLastRenderTimestamp = gGlobalTimer; + sPowerMeterDisplayListPos = gDisplayListHead; gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(mtx++), G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_PUSH); diff --git a/src/game/ingame_menu.c b/src/game/ingame_menu.c index d292d807..4518271f 100644 --- a/src/game/ingame_menu.c +++ b/src/game/ingame_menu.c @@ -78,6 +78,47 @@ s8 gLastDialogResponse = 0; u8 gMenuHoldKeyIndex = 0; u8 gMenuHoldKeyTimer = 0; s32 gDialogResponse = 0; +static Gfx *sInterpolatedDialogOffsetPos; +static f32 sInterpolatedDialogOffset; +static Gfx *sInterpolatedDialogRotationPos; +static f32 sInterpolatedDialogScale; +static f32 sInterpolatedDialogRotation; +static Gfx *sInterpolatedDialogZoomPos; + +void patch_interpolated_dialog(void) { + Mtx *matrix; + + if (sInterpolatedDialogOffsetPos != NULL) { + matrix = (Mtx *) alloc_display_list(sizeof(Mtx)); + guTranslate(matrix, 0, sInterpolatedDialogOffset, 0); + gSPMatrix(sInterpolatedDialogOffsetPos, VIRTUAL_TO_PHYSICAL(matrix), + G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_NOPUSH); + sInterpolatedDialogOffsetPos = NULL; + } + if (sInterpolatedDialogRotationPos != NULL) { + matrix = (Mtx *) alloc_display_list(sizeof(Mtx)); + guScale(matrix, 1.0 / sInterpolatedDialogScale, 1.0 / sInterpolatedDialogScale, 1.0f); + gSPMatrix(sInterpolatedDialogRotationPos++, VIRTUAL_TO_PHYSICAL(matrix), + G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_NOPUSH); + matrix = (Mtx *) alloc_display_list(sizeof(Mtx)); + guRotate(matrix, sInterpolatedDialogRotation * 4.0f, 0, 0, 1.0f); + gSPMatrix(sInterpolatedDialogRotationPos, VIRTUAL_TO_PHYSICAL(matrix), + G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_NOPUSH); + sInterpolatedDialogRotationPos = NULL; + } + if (sInterpolatedDialogZoomPos != NULL) { + matrix = (Mtx *) alloc_display_list(sizeof(Mtx)); + guTranslate(matrix, 65.0 - (65.0 / sInterpolatedDialogScale), + (40.0 / sInterpolatedDialogScale) - 40, 0); + gSPMatrix(sInterpolatedDialogZoomPos++, VIRTUAL_TO_PHYSICAL(matrix), + G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_NOPUSH); + matrix = (Mtx *) alloc_display_list(sizeof(Mtx)); + guScale(matrix, 1.0 / sInterpolatedDialogScale, 1.0 / sInterpolatedDialogScale, 1.0f); + gSPMatrix(sInterpolatedDialogZoomPos, VIRTUAL_TO_PHYSICAL(matrix), + G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_NOPUSH); + sInterpolatedDialogZoomPos = NULL; + } +} void create_dl_identity_matrix(void) { Mtx *matrix = (Mtx *) alloc_display_list(sizeof(Mtx)); @@ -541,6 +582,14 @@ void render_dialog_box_type(struct DialogEntry *dialog, s8 linesPerBox) { switch (gDialogBoxType) { case DIALOG_TYPE_ROTATE: // Renders a dialog black box with zoom and rotation if (gDialogBoxState == DIALOG_STATE_OPENING || gDialogBoxState == DIALOG_STATE_CLOSING) { + sInterpolatedDialogRotationPos = gDisplayListHead; + if (gDialogBoxState == DIALOG_STATE_OPENING) { + sInterpolatedDialogScale = gDialogBoxScale - 2 / 2; + sInterpolatedDialogRotation = gDialogBoxOpenTimer - 7.5f / 2; + } else { + sInterpolatedDialogScale = gDialogBoxScale + 2 / 2; + sInterpolatedDialogRotation = gDialogBoxOpenTimer + 7.5f / 2; + } create_dl_scale_matrix(MENU_MTX_NOPUSH, 1.0 / gDialogBoxScale, 1.0 / gDialogBoxScale, 1.0f); // convert the speed into angle create_dl_rotation_matrix(MENU_MTX_NOPUSH, gDialogBoxOpenTimer * 4.0f, 0, 0, 1.0f); @@ -549,6 +598,12 @@ void render_dialog_box_type(struct DialogEntry *dialog, s8 linesPerBox) { break; case DIALOG_TYPE_ZOOM: // Renders a dialog white box with zoom if (gDialogBoxState == DIALOG_STATE_OPENING || gDialogBoxState == DIALOG_STATE_CLOSING) { + sInterpolatedDialogZoomPos = gDisplayListHead; + if (gDialogBoxState == DIALOG_STATE_OPENING) { + sInterpolatedDialogScale = gDialogBoxScale - 2 / 2; + } else { + sInterpolatedDialogScale = gDialogBoxScale + 2 / 2; + } create_dl_translation_matrix(MENU_MTX_NOPUSH, 65.0 - (65.0 / gDialogBoxScale), (40.0 / gDialogBoxScale) - 40, 0); create_dl_scale_matrix(MENU_MTX_NOPUSH, 1.0 / gDialogBoxScale, 1.0 / gDialogBoxScale, 1.0f); @@ -659,7 +714,8 @@ u32 ensure_nonnegative(s16 value) { return value; } -void handle_dialog_text_and_pages(s8 colorMode, struct DialogEntry *dialog, s8 lowerBound) { +void handle_dialog_text_and_pages(s8 colorMode, struct DialogEntry *dialog, s8 lowerBound) +{ UNUSED s32 pad[2]; u8 strChar; @@ -689,9 +745,11 @@ void handle_dialog_text_and_pages(s8 colorMode, struct DialogEntry *dialog, s8 l gSPDisplayList(gDisplayListHead++, dl_ia_text_begin); strIdx = gDialogTextPos; - if (gDialogBoxState == DIALOG_STATE_HORIZONTAL) + if (gDialogBoxState == DIALOG_STATE_HORIZONTAL) { + sInterpolatedDialogOffset = gDialogScrollOffsetY + dialog->linesPerBox; + sInterpolatedDialogOffsetPos = gDisplayListHead; create_dl_translation_matrix(MENU_MTX_NOPUSH, 0, (f32) gDialogScrollOffsetY, 0); - + } create_dl_translation_matrix(MENU_MTX_PUSH, X_VAL3, 2 - lineNum * Y_VAL3, 0); while (pageState == DIALOG_PAGE_STATE_NONE) { @@ -716,7 +774,6 @@ void handle_dialog_text_and_pages(s8 colorMode, struct DialogEntry *dialog, s8 l case DIALOG_CHAR_SPACE: xMatrix++; linePos++; - break; case DIALOG_CHAR_SLASH: xMatrix += 2; @@ -748,7 +805,6 @@ void handle_dialog_text_and_pages(s8 colorMode, struct DialogEntry *dialog, s8 l } strIdx++; } - gSPDisplayList(gDisplayListHead++, dl_ia_text_end); if (gDialogBoxState == DIALOG_STATE_VERTICAL) { diff --git a/src/game/level_geo.c b/src/game/level_geo.c index 4c98e705..abc51213 100644 --- a/src/game/level_geo.c +++ b/src/game/level_geo.c @@ -34,12 +34,16 @@ Gfx *geo_envfx_main(s32 callContext, struct GraphNode *node, Mat4 mtxf) { vec3f_to_vec3s(marioPos, gPlayerCameraState->pos); particleList = envfx_update_particles(snowMode, marioPos, camTo, camFrom); if (particleList != NULL) { +#if 0 Mtx *mtx = alloc_display_list(sizeof(*mtx)); gfx = alloc_display_list(2 * sizeof(*gfx)); mtxf_to_mtx(mtx, mtxf); gSPMatrix(&gfx[0], VIRTUAL_TO_PHYSICAL(mtx), G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH); gSPBranchList(&gfx[1], VIRTUAL_TO_PHYSICAL(particleList)); +#else + gfx = particleList; +#endif execNode->fnNode.node.flags = (execNode->fnNode.node.flags & 0xFF) | 0x400; } SET_HIGH_U16_OF_32(*params, gAreaUpdateCounter); diff --git a/src/game/mario.c b/src/game/mario.c index 1ccf2e7f..41dc4a56 100644 --- a/src/game/mario.c +++ b/src/game/mario.c @@ -1560,15 +1560,19 @@ void update_mario_info_for_cam(struct MarioState *m) { } } +int current_cap_state = MARIO_HAS_DEFAULT_CAP_ON; +int current_eye_state = MARIO_EYES_BLINK; +int current_hand_state = MARIO_HAND_FISTS; + /** * Resets Mario's model, done every time an action is executed. */ void mario_reset_bodystate(struct MarioState *m) { struct MarioBodyState *bodyState = m->marioBodyState; - bodyState->capState = MARIO_HAS_DEFAULT_CAP_OFF; - bodyState->eyeState = MARIO_EYES_BLINK; - bodyState->handState = MARIO_HAND_FISTS; + bodyState->capState = current_cap_state; + bodyState->eyeState = current_eye_state; + bodyState->handState = current_hand_state; bodyState->modelState = 0; bodyState->wingFlutter = FALSE; @@ -1669,6 +1673,8 @@ void mario_update_hitbox_and_cap_model(struct MarioState *m) { } } + /* + if (flags & MARIO_CAP_IN_HAND) { if (flags & MARIO_WING_CAP) { bodyState->handState = MARIO_HAND_HOLDING_WING_CAP; @@ -1685,6 +1691,8 @@ void mario_update_hitbox_and_cap_model(struct MarioState *m) { } } + */ + // Short hitbox for crouching/crawling/etc. if (m->action & ACT_FLAG_SHORT_HITBOX) { m->marioObj->hitboxHeight = 100.0f; diff --git a/src/game/mario.h b/src/game/mario.h index ad0d005a..0859fb81 100644 --- a/src/game/mario.h +++ b/src/game/mario.h @@ -51,4 +51,8 @@ s32 execute_mario_action(UNUSED struct Object *o); void init_mario(void); void init_mario_from_save_file(void); +extern int current_cap_state; +extern int current_eye_state; +extern int current_hand_state; + #endif // MARIO_H diff --git a/src/game/mario_actions_airborne.c b/src/game/mario_actions_airborne.c index 9c2e0ffb..a2f2c255 100644 --- a/src/game/mario_actions_airborne.c +++ b/src/game/mario_actions_airborne.c @@ -18,6 +18,7 @@ #ifdef BETTERCAMERA #include "bettercamera.h" #endif +#include "moon/saturn/saturn_types.h" void play_flip_sounds(struct MarioState *m, s16 frame1, s16 frame2, s16 frame3) { s32 animFrame = m->marioObj->header.gfx.unk38.animFrame; @@ -1707,7 +1708,8 @@ s32 act_shot_from_cannon(struct MarioState *m) { } if (m->vel[1] > 0.0f) { - m->particleFlags |= PARTICLE_DUST; + if (enable_dust_particles) + m->particleFlags |= PARTICLE_DUST; } reset_rumble_timers(); @@ -1867,7 +1869,8 @@ s32 act_flying(struct MarioState *m) { } if (m->faceAngle[0] > 0x800 && m->forwardVel >= 48.0f) { - m->particleFlags |= PARTICLE_DUST; + if (enable_dust_particles) + m->particleFlags |= PARTICLE_DUST; } if (startPitch <= 0 && m->faceAngle[0] > 0 && m->forwardVel >= 48.0f) { diff --git a/src/game/mario_actions_cutscene.c b/src/game/mario_actions_cutscene.c index c5d34fc9..416a8d0e 100644 --- a/src/game/mario_actions_cutscene.c +++ b/src/game/mario_actions_cutscene.c @@ -31,6 +31,7 @@ #include "../../include/libc/stdlib.h" #include "pc/pc_main.h" #include "moon/achievements/achievements.h" +#include "moon/saturn/saturn_types.h" // TODO: put this elsewhere enum SaveOption { SAVE_OPT_SAVE_AND_CONTINUE = 1, SAVE_OPT_SAVE_AND_QUIT, SAVE_OPT_SAVE_EXIT_GAME, SAVE_OPT_CONTINUE_DONT_SAVE }; @@ -2152,7 +2153,8 @@ static void end_peach_cutscene_run_to_peach(struct MarioState *m) { play_step_sound(m, 9, 45); vec3f_copy(m->marioObj->header.gfx.pos, m->pos); - m->particleFlags |= PARTICLE_DUST; + if (enable_dust_particles) + m->particleFlags |= PARTICLE_DUST; } // dialog 1 diff --git a/src/game/mario_actions_moving.c b/src/game/mario_actions_moving.c index 1cb4e3cc..a181715c 100644 --- a/src/game/mario_actions_moving.c +++ b/src/game/mario_actions_moving.c @@ -15,6 +15,7 @@ #include "pc/configfile.h" #include "pc/cheats.h" #include "moon/achievements/achievements.h" +#include "moon/saturn/saturn_types.h" struct LandingAction { s16 numFrames; @@ -709,7 +710,8 @@ void push_or_sidle_wall(struct MarioState *m, Vec3f startPos) { if (m->marioObj->header.gfx.unk38.animFrame < 20) { play_sound(SOUND_MOVING_TERRAIN_SLIDE + m->terrainSoundAddend, m->marioObj->header.gfx.cameraToObject); - m->particleFlags |= PARTICLE_DUST; + if (enable_dust_particles) + m->particleFlags |= PARTICLE_DUST; } m->actionState = 1; @@ -837,7 +839,8 @@ s32 act_walking(struct MarioState *m) { case GROUND_STEP_NONE: anim_and_audio_for_walk(m); if (m->intendedMag - m->forwardVel > 16.0f) { - m->particleFlags |= PARTICLE_DUST; + if (enable_dust_particles) + m->particleFlags |= PARTICLE_DUST; } break; @@ -880,7 +883,8 @@ s32 act_move_punching(struct MarioState *m) { break; case GROUND_STEP_NONE: - m->particleFlags |= PARTICLE_DUST; + if (enable_dust_particles) + m->particleFlags |= PARTICLE_DUST; break; } @@ -935,7 +939,8 @@ s32 act_hold_walking(struct MarioState *m) { anim_and_audio_for_hold_walk(m); if (0.4f * m->intendedMag - m->forwardVel > 10.0f) { - m->particleFlags |= PARTICLE_DUST; + if (enable_dust_particles) + m->particleFlags |= PARTICLE_DUST; } return FALSE; @@ -1005,7 +1010,8 @@ s32 act_turning_around(struct MarioState *m) { break; case GROUND_STEP_NONE: - m->particleFlags |= PARTICLE_DUST; + if (enable_dust_particles) + m->particleFlags |= PARTICLE_DUST; break; } @@ -1070,7 +1076,8 @@ s32 act_braking(struct MarioState *m) { break; case GROUND_STEP_NONE: - m->particleFlags |= PARTICLE_DUST; + if (enable_dust_particles) + m->particleFlags |= PARTICLE_DUST; break; case GROUND_STEP_HIT_WALL: @@ -1132,7 +1139,8 @@ s32 act_decelerating(struct MarioState *m) { set_mario_animation(m, MARIO_ANIM_IDLE_HEAD_LEFT); play_sound(SOUND_MOVING_TERRAIN_SLIDE + m->terrainSoundAddend, m->marioObj->header.gfx.cameraToObject); adjust_sound_for_speed(m); - m->particleFlags |= PARTICLE_DUST; + if (enable_dust_particles) + m->particleFlags |= PARTICLE_DUST; } else { // (Speed Crash) Crashes if speed exceeds 2^17. if ((val0C = (s32)(m->forwardVel / 4.0f * 0x10000)) < 0x1000) { @@ -1198,7 +1206,8 @@ s32 act_hold_decelerating(struct MarioState *m) { set_mario_animation(m, MARIO_ANIM_IDLE_WITH_LIGHT_OBJ); play_sound(SOUND_MOVING_TERRAIN_SLIDE + m->terrainSoundAddend, m->marioObj->header.gfx.cameraToObject); adjust_sound_for_speed(m); - m->particleFlags |= PARTICLE_DUST; + if (enable_dust_particles) + m->particleFlags |= PARTICLE_DUST; } else { //! (Speed Crash) This crashes if Mario has more speed than 2^15 speed. if ((val0C = (s32)(m->forwardVel * 0x10000)) < 0x1000) { @@ -1391,7 +1400,8 @@ void common_slide_action(struct MarioState *m, u32 endAction, u32 airAction, s32 case GROUND_STEP_NONE: set_mario_animation(m, animation); align_with_floor(m); - m->particleFlags |= PARTICLE_DUST; + if (enable_dust_particles) + m->particleFlags |= PARTICLE_DUST; break; case GROUND_STEP_HIT_WALL: @@ -1523,7 +1533,8 @@ s32 act_slide_kick_slide(struct MarioState *m) { } play_sound(SOUND_MOVING_TERRAIN_SLIDE + m->terrainSoundAddend, m->marioObj->header.gfx.cameraToObject); - m->particleFlags |= PARTICLE_DUST; + if (enable_dust_particles) + m->particleFlags |= PARTICLE_DUST; return FALSE; } @@ -1746,7 +1757,8 @@ u32 common_landing_action(struct MarioState *m, s16 animation, u32 airAction) { } if (m->forwardVel > 16.0f) { - m->particleFlags |= PARTICLE_DUST; + if (enable_dust_particles) + m->particleFlags |= PARTICLE_DUST; } set_mario_animation(m, animation); diff --git a/src/game/mario_actions_stationary.c b/src/game/mario_actions_stationary.c index 4852877e..d2bfba1d 100644 --- a/src/game/mario_actions_stationary.c +++ b/src/game/mario_actions_stationary.c @@ -17,6 +17,7 @@ #include "sound_init.h" #include "surface_terrains.h" #include "thread6.h" +#include "moon/saturn/saturn_types.h" s32 check_common_idle_cancels(struct MarioState *m) { mario_drop_held_object(m); @@ -133,15 +134,27 @@ s32 act_idle(struct MarioState *m) { } else { switch (m->actionState) { case 0: - set_mario_animation(m, MARIO_ANIM_IDLE_HEAD_LEFT); + if (enable_head_rotations) { + set_mario_animation(m, MARIO_ANIM_IDLE_HEAD_LEFT); + } else { + set_mario_animation(m, MARIO_ANIM_FIRST_PERSON); + } break; case 1: - set_mario_animation(m, MARIO_ANIM_IDLE_HEAD_RIGHT); + if (enable_head_rotations) { + set_mario_animation(m, MARIO_ANIM_IDLE_HEAD_RIGHT); + } else { + set_mario_animation(m, MARIO_ANIM_FIRST_PERSON); + } break; case 2: - set_mario_animation(m, MARIO_ANIM_IDLE_HEAD_CENTER); + if (enable_head_rotations) { + set_mario_animation(m, MARIO_ANIM_IDLE_HEAD_CENTER); + } else { + set_mario_animation(m, MARIO_ANIM_FIRST_PERSON); + } break; } diff --git a/src/game/mario_actions_submerged.c b/src/game/mario_actions_submerged.c index 1256a59b..9316f09e 100644 --- a/src/game/mario_actions_submerged.c +++ b/src/game/mario_actions_submerged.c @@ -16,6 +16,7 @@ #include "behavior_data.h" #include "level_table.h" #include "thread6.h" +#include "moon/saturn/saturn_types.h" #define MIN_SWIM_STRENGTH 160 #define MIN_SWIM_SPEED 16.0f @@ -1099,7 +1100,8 @@ static void play_metal_water_jumping_sound(struct MarioState *m, u32 landing) { static void play_metal_water_walking_sound(struct MarioState *m) { if (is_anim_past_frame(m, 10) || is_anim_past_frame(m, 49)) { play_sound(SOUND_ACTION_METAL_STEP_WATER, m->marioObj->header.gfx.cameraToObject); - m->particleFlags |= PARTICLE_DUST; + if (enable_dust_particles) + m->particleFlags |= PARTICLE_DUST; } } diff --git a/src/game/object_helpers.c b/src/game/object_helpers.c index 15818f70..190d30ca 100644 --- a/src/game/object_helpers.c +++ b/src/game/object_helpers.c @@ -1550,6 +1550,7 @@ void cur_obj_set_pos_to_home(void) { o->oPosX = o->oHomeX; o->oPosY = o->oHomeY; o->oPosZ = o->oHomeZ; + o->header.gfx.skipInterpolationTimestamp = gGlobalTimer; } void cur_obj_set_pos_to_home_and_stop(void) { diff --git a/src/game/paintings.c b/src/game/paintings.c index 6cae19c0..a304d4ae 100644 --- a/src/game/paintings.c +++ b/src/game/paintings.c @@ -189,6 +189,32 @@ struct Painting **sPaintingGroups[] = { s16 gPaintingUpdateCounter = 1; s16 gLastPaintingUpdateCounter = 0; +static Vtx sLastVertices[2 * 264 * 3]; +static u32 sLastVerticesTimestamp; +static Vtx *sVerticesPtr[2]; +static s32 sVerticesCount; + +void patch_interpolated_paintings(void) { + if (sVerticesPtr[0] != NULL) { + s32 i; + if (sVerticesPtr[1] != NULL) { + for (i = 0; i < sVerticesCount / 2; i++) { + sVerticesPtr[0][i] = sLastVertices[i]; + } + for (; i < sVerticesCount; i++) { + sVerticesPtr[1][i - sVerticesCount / 2] = sLastVertices[i]; + } + } else { + for (i = 0; i < sVerticesCount; i++) { + sVerticesPtr[0][i] = sLastVertices[i]; + } + } + sVerticesPtr[0] = NULL; + sVerticesPtr[1] = NULL; + sVerticesCount = 0; + } +} + /** * Stop paintings in paintingGroup from rippling if their id is different from *idptr. */ @@ -890,6 +916,23 @@ Gfx *render_painting(u8 *img, s16 tWidth, s16 tHeight, s16 *textureMap, s16 mapV gSP1Triangle(gfx++, group * 3, group * 3 + 1, group * 3 + 2, 0); } + if (sVerticesCount >= numVtx * 2) { + sVerticesCount = 0; + } + for (map = 0; map < numVtx; map++) { + Vtx v = verts[map]; + if (gGlobalTimer == sLastVerticesTimestamp + 1) { + s32 i; + for (i = 0; i < 3; i++) { + verts[map].n.ob[i] = (v.n.ob[i] + sLastVertices[sVerticesCount + map].n.ob[i]) / 2; + verts[map].n.n[i] = (v.n.n[i] + sLastVertices[sVerticesCount + map].n.n[i]) / 2; + } + } + sLastVertices[sVerticesCount + map] = v; + } + sVerticesPtr[sVerticesCount / numVtx] = verts; + sVerticesCount += numVtx; + gSPEndDisplayList(gfx); return dlist; } @@ -954,6 +997,7 @@ Gfx *painting_ripple_image(struct Painting *painting) { meshTris = textureMap[meshVerts * 3 + 1]; gSPDisplayList(gfx++, render_painting(textures[i], tWidth, tHeight, textureMap, meshVerts, meshTris, painting->alpha)); } + sLastVerticesTimestamp = gGlobalTimer; // Update the ripple, may automatically reset the painting's state. painting_update_ripple_state(painting); @@ -991,6 +1035,7 @@ Gfx *painting_ripple_env_mapped(struct Painting *painting) { meshVerts = textureMap[0]; meshTris = textureMap[meshVerts * 3 + 1]; gSPDisplayList(gfx++, render_painting(tArray[0], tWidth, tHeight, textureMap, meshVerts, meshTris, painting->alpha)); + sLastVerticesTimestamp = gGlobalTimer; // Update the ripple, may automatically reset the painting's state. painting_update_ripple_state(painting); diff --git a/src/game/rendering_graph_node.c b/src/game/rendering_graph_node.c index c0111a27..6bf3d0ac 100644 --- a/src/game/rendering_graph_node.c +++ b/src/game/rendering_graph_node.c @@ -40,6 +40,8 @@ s16 gMatStackIndex; Mat4 gMatStack[32]; Mtx *gMatStackFixed[32]; +Mat4 gMatStackInterpolated[32]; +Mtx *gMatStackInterpolatedFixed[32]; /** * Animation nodes have state in global variables, so this struct captures @@ -53,6 +55,7 @@ struct GeoAnimState { /*0x04*/ f32 translationMultiplier; /*0x08*/ u16 *attribute; /*0x0C*/ s16 *data; + s16 prevFrame; }; // For some reason, this is a GeoAnimState struct, but the current state consists @@ -62,6 +65,7 @@ struct GeoAnimState gGeoTempState; u8 gCurAnimType; u8 gCurAnimEnabled; s16 gCurrAnimFrame; +s16 gPrevAnimFrame; f32 gCurAnimTranslationMultiplier; u16 *gCurrAnimAttribute; s16 *gCurAnimData; @@ -130,6 +134,46 @@ u16 gAreaUpdateCounter = 0; LookAt lookAt; #endif +static Gfx *sPerspectivePos; +static Mtx *sPerspectiveMtx; + +struct { + Gfx *pos; + void *mtx; + void *displayList; +} gMtxTbl[6400]; +s32 gMtxTblSize; + +static Gfx *sViewportPos; +static Vp sPrevViewport; + +void mtx_patch_interpolated(void) { + s32 i; + + if (sPerspectivePos != NULL) { + gSPMatrix(sPerspectivePos, VIRTUAL_TO_PHYSICAL(sPerspectiveMtx), G_MTX_PROJECTION | G_MTX_LOAD | G_MTX_NOPUSH); + } + + for (i = 0; i < gMtxTblSize; i++) { + Gfx *pos = gMtxTbl[i].pos; + gSPMatrix(pos++, VIRTUAL_TO_PHYSICAL(gMtxTbl[i].mtx), + G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH); + gSPDisplayList(pos++, gMtxTbl[i].displayList); + } + + if (sViewportPos != NULL) { + Gfx *saved = gDisplayListHead; + gDisplayListHead = sViewportPos; + make_viewport_clip_rect(&sPrevViewport); + gSPViewport(gDisplayListHead, VIRTUAL_TO_PHYSICAL(&sPrevViewport)); + gDisplayListHead = saved; + } + + gMtxTblSize = 0; + sPerspectivePos = NULL; + sViewportPos = NULL; +} + /** * Process a master list node. */ @@ -157,9 +201,14 @@ static void geo_process_master_list_sub(struct GraphNodeMasterList *node) { if ((currList = node->listHeads[i]) != NULL) { gDPSetRenderMode(gDisplayListHead++, modeList->modes[i], mode2List->modes[i]); while (currList != NULL) { - gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(currList->transform), + if ((u32) gMtxTblSize < sizeof(gMtxTbl) / sizeof(gMtxTbl[0])) { + gMtxTbl[gMtxTblSize].pos = gDisplayListHead; + gMtxTbl[gMtxTblSize].mtx = currList->transform; + gMtxTbl[gMtxTblSize++].displayList = currList->displayList; + } + gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(currList->transformInterpolated), G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH); - gSPDisplayList(gDisplayListHead++, currList->displayList); + gSPDisplayList(gDisplayListHead++, currList->displayListInterpolated); currList = currList->next; } } @@ -175,7 +224,7 @@ static void geo_process_master_list_sub(struct GraphNodeMasterList *node) { * parameter. Look at the RenderModeContainer struct to see the corresponding * render modes of layers. */ -static void geo_append_display_list(void *displayList, s16 layer) { +static void geo_append_display_list2(void *displayList, void *displayListInterpolated, s16 layer) { #ifdef F3DEX_GBI_2 gSPLookAt(gDisplayListHead++, &lookAt); @@ -185,7 +234,9 @@ static void geo_append_display_list(void *displayList, s16 layer) { alloc_only_pool_alloc(gDisplayListHeap, sizeof(struct DisplayListNode)); listNode->transform = gMatStackFixed[gMatStackIndex]; + listNode->transformInterpolated = gMatStackInterpolatedFixed[gMatStackIndex]; listNode->displayList = displayList; + listNode->displayListInterpolated = displayListInterpolated; listNode->next = 0; if (gCurGraphNodeMasterList->listHeads[layer] == 0) { gCurGraphNodeMasterList->listHeads[layer] = listNode; @@ -196,6 +247,10 @@ static void geo_append_display_list(void *displayList, s16 layer) { } } +static void geo_append_display_list(void *displayList, s16 layer) { + geo_append_display_list2(displayList, displayList, layer); +} + /** * Process the master list node. */ @@ -242,7 +297,9 @@ static void geo_process_perspective(struct GraphNodePerspective *node) { } if (node->fnNode.node.children != NULL) { u16 perspNorm; + Mtx *mtxInterpolated = alloc_display_list(sizeof(*mtxInterpolated)); Mtx *mtx = alloc_display_list(sizeof(*mtx)); + f32 fovInterpolated; #ifdef VERSION_EU f32 aspect = ((f32) gCurGraphNodeRoot->width / (f32) gCurGraphNodeRoot->height) * 1.1f; @@ -251,9 +308,23 @@ static void geo_process_perspective(struct GraphNodePerspective *node) { #endif guPerspective(mtx, &perspNorm, node->fov, aspect, node->near, node->far, 1.0f); - gSPPerspNormalize(gDisplayListHead++, perspNorm); - gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(mtx), G_MTX_PROJECTION | G_MTX_LOAD | G_MTX_NOPUSH); + if (gGlobalTimer == node->prevTimestamp + 1 && gGlobalTimer != gLakituState.skipCameraInterpolationTimestamp) { + + fovInterpolated = (node->prevFov + node->fov) / 2.0f; + guPerspective(mtxInterpolated, &perspNorm, fovInterpolated, aspect, node->near, node->far, 1.0f); + gSPPerspNormalize(gDisplayListHead++, perspNorm); + + sPerspectivePos = gDisplayListHead; + sPerspectiveMtx = mtx; + gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(mtxInterpolated), + G_MTX_PROJECTION | G_MTX_LOAD | G_MTX_NOPUSH); + } else { + gSPPerspNormalize(gDisplayListHead++, perspNorm); + gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(mtx), G_MTX_PROJECTION | G_MTX_LOAD | G_MTX_NOPUSH); + } + node->prevFov = node->fov; + node->prevTimestamp = gGlobalTimer; gCurGraphNodeCamFrustum = node; geo_process_node_and_siblings(node->fnNode.node.children); @@ -305,6 +376,39 @@ static void geo_process_switch(struct GraphNodeSwitchCase *node) { } } +void interpolate_vectors(Vec3f res, Vec3f a, Vec3f b) { + res[0] = (a[0] + b[0]) / 2.0f; + res[1] = (a[1] + b[1]) / 2.0f; + res[2] = (a[2] + b[2]) / 2.0f; +} + +void interpolate_vectors_s16(Vec3s res, Vec3s a, Vec3s b) { + res[0] = (a[0] + b[0]) / 2; + res[1] = (a[1] + b[1]) / 2; + res[2] = (a[2] + b[2]) / 2; +} + +static s16 interpolate_angle(s16 a, s16 b) { + s32 absDiff = b - a; + if (absDiff < 0) { + absDiff = -absDiff; + } + if (absDiff >= 0x4000 && absDiff <= 0xC000) { + return b; + } + if (absDiff <= 0x8000) { + return (a + b) / 2; + } else { + return (a + b) / 2 + 0x8000; + } +} + +static void interpolate_angles(Vec3s res, Vec3s a, Vec3s b) { + res[0] = interpolate_angle(a[0], b[0]); + res[1] = interpolate_angle(a[1], b[1]); + res[2] = interpolate_angle(a[2], b[2]); +} + /** * Process a camera node. */ @@ -312,6 +416,9 @@ static void geo_process_camera(struct GraphNodeCamera *node) { Mat4 cameraTransform; Mtx *rollMtx = alloc_display_list(sizeof(*rollMtx)); Mtx *mtx = alloc_display_list(sizeof(*mtx)); + Mtx *mtxInterpolated = alloc_display_list(sizeof(*mtxInterpolated)); + Vec3f posInterpolated; + Vec3f focusInterpolated; if (node->fnNode.func != NULL) { node->fnNode.func(GEO_CONTEXT_RENDER, &node->fnNode.node, gMatStack[gMatStackIndex]); @@ -322,12 +429,40 @@ static void geo_process_camera(struct GraphNodeCamera *node) { mtxf_lookat(cameraTransform, node->pos, node->focus, node->roll); mtxf_mul(gMatStack[gMatStackIndex + 1], cameraTransform, gMatStack[gMatStackIndex]); + + if (gGlobalTimer == node->prevTimestamp + 1 && gGlobalTimer != gLakituState.skipCameraInterpolationTimestamp) { + interpolate_vectors(posInterpolated, node->prevPos, node->pos); + interpolate_vectors(focusInterpolated, node->prevFocus, node->focus); + float magnitude = 0; + for (int i = 0; i < 3; i++) { + float diff = node->pos[i] - node->prevPos[i]; + magnitude += diff * diff; + } + if (magnitude > 500000) { + // Observed ~479000 in BBH when toggling R camera + // Can get over 3 million in VCUTM though... + vec3f_copy(posInterpolated, node->pos); + vec3f_copy(focusInterpolated, node->focus); + } + } else { + vec3f_copy(posInterpolated, node->pos); + vec3f_copy(focusInterpolated, node->focus); + } + vec3f_copy(node->prevPos, node->pos); + vec3f_copy(node->prevFocus, node->focus); + node->prevTimestamp = gGlobalTimer; + mtxf_lookat(cameraTransform, posInterpolated, focusInterpolated, node->roll); + mtxf_mul(gMatStackInterpolated[gMatStackIndex + 1], cameraTransform, gMatStackInterpolated[gMatStackIndex]); + gMatStackIndex++; mtxf_to_mtx(mtx, gMatStack[gMatStackIndex]); gMatStackFixed[gMatStackIndex] = mtx; + mtxf_to_mtx(mtxInterpolated, gMatStackInterpolated[gMatStackIndex]); + gMatStackInterpolatedFixed[gMatStackIndex] = mtxInterpolated; if (node->fnNode.node.children != 0) { gCurGraphNodeCamera = node; node->matrixPtr = &gMatStack[gMatStackIndex]; + node->matrixPtrInterpolated = &gMatStackInterpolated[gMatStackIndex]; geo_process_node_and_siblings(node->fnNode.node.children); gCurGraphNodeCamera = NULL; } @@ -344,13 +479,17 @@ static void geo_process_translation_rotation(struct GraphNodeTranslationRotation Mat4 mtxf; Vec3f translation; Mtx *mtx = alloc_display_list(sizeof(*mtx)); + Mtx *mtxInterpolated = alloc_display_list(sizeof(*mtxInterpolated)); vec3s_to_vec3f(translation, node->translation); mtxf_rotate_zxy_and_translate(mtxf, translation, node->rotation); mtxf_mul(gMatStack[gMatStackIndex + 1], mtxf, gMatStack[gMatStackIndex]); + mtxf_mul(gMatStackInterpolated[gMatStackIndex + 1], mtxf, gMatStackInterpolated[gMatStackIndex]); gMatStackIndex++; mtxf_to_mtx(mtx, gMatStack[gMatStackIndex]); gMatStackFixed[gMatStackIndex] = mtx; + mtxf_to_mtx(mtxInterpolated, gMatStackInterpolated[gMatStackIndex]); + gMatStackInterpolatedFixed[gMatStackIndex] = mtxInterpolated; if (node->displayList != NULL) { geo_append_display_list(node->displayList, node->node.flags >> 8); } @@ -369,13 +508,17 @@ static void geo_process_translation(struct GraphNodeTranslation *node) { Mat4 mtxf; Vec3f translation; Mtx *mtx = alloc_display_list(sizeof(*mtx)); + Mtx *mtxInterpolated = alloc_display_list(sizeof(*mtxInterpolated)); vec3s_to_vec3f(translation, node->translation); mtxf_rotate_zxy_and_translate(mtxf, translation, gVec3sZero); mtxf_mul(gMatStack[gMatStackIndex + 1], mtxf, gMatStack[gMatStackIndex]); + mtxf_mul(gMatStackInterpolated[gMatStackIndex + 1], mtxf, gMatStackInterpolated[gMatStackIndex]); gMatStackIndex++; mtxf_to_mtx(mtx, gMatStack[gMatStackIndex]); gMatStackFixed[gMatStackIndex] = mtx; + mtxf_to_mtx(mtxInterpolated, gMatStackInterpolated[gMatStackIndex]); + gMatStackInterpolatedFixed[gMatStackIndex] = mtxInterpolated; if (node->displayList != NULL) { geo_append_display_list(node->displayList, node->node.flags >> 8); } @@ -393,12 +536,23 @@ static void geo_process_translation(struct GraphNodeTranslation *node) { static void geo_process_rotation(struct GraphNodeRotation *node) { Mat4 mtxf; Mtx *mtx = alloc_display_list(sizeof(*mtx)); + Mtx *mtxInterpolated = alloc_display_list(sizeof(*mtxInterpolated)); + Vec3s rotationInterpolated; mtxf_rotate_zxy_and_translate(mtxf, gVec3fZero, node->rotation); mtxf_mul(gMatStack[gMatStackIndex + 1], mtxf, gMatStack[gMatStackIndex]); + if (gGlobalTimer == node->prevTimestamp + 1) { + interpolate_angles(rotationInterpolated, node->prevRotation, node->rotation); + mtxf_rotate_zxy_and_translate(mtxf, gVec3fZero, rotationInterpolated); + } + vec3s_copy(node->prevRotation, node->rotation); + node->prevTimestamp = gGlobalTimer; + mtxf_mul(gMatStackInterpolated[gMatStackIndex + 1], mtxf, gMatStackInterpolated[gMatStackIndex]); gMatStackIndex++; mtxf_to_mtx(mtx, gMatStack[gMatStackIndex]); gMatStackFixed[gMatStackIndex] = mtx; + mtxf_to_mtx(mtxInterpolated, gMatStackInterpolated[gMatStackIndex]); + gMatStackInterpolatedFixed[gMatStackIndex] = mtxInterpolated; if (node->displayList != NULL) { geo_append_display_list(node->displayList, node->node.flags >> 8); } @@ -417,12 +571,16 @@ static void geo_process_scale(struct GraphNodeScale *node) { UNUSED Mat4 transform; Vec3f scaleVec; Mtx *mtx = alloc_display_list(sizeof(*mtx)); + Mtx *mtxInterpolated = alloc_display_list(sizeof(*mtxInterpolated)); vec3f_set(scaleVec, node->scale, node->scale, node->scale); mtxf_scale_vec3f(gMatStack[gMatStackIndex + 1], gMatStack[gMatStackIndex], scaleVec); + mtxf_scale_vec3f(gMatStackInterpolated[gMatStackIndex + 1], gMatStackInterpolated[gMatStackIndex], scaleVec); gMatStackIndex++; mtxf_to_mtx(mtx, gMatStack[gMatStackIndex]); gMatStackFixed[gMatStackIndex] = mtx; + mtxf_to_mtx(mtxInterpolated, gMatStackInterpolated[gMatStackIndex]); + gMatStackInterpolatedFixed[gMatStackIndex] = mtxInterpolated; if (node->displayList != NULL) { geo_append_display_list(node->displayList, node->node.flags >> 8); } @@ -441,21 +599,30 @@ static void geo_process_scale(struct GraphNodeScale *node) { static void geo_process_billboard(struct GraphNodeBillboard *node) { Vec3f translation; Mtx *mtx = alloc_display_list(sizeof(*mtx)); + Mtx *mtxInterpolated = alloc_display_list(sizeof(*mtxInterpolated)); gMatStackIndex++; vec3s_to_vec3f(translation, node->translation); mtxf_billboard(gMatStack[gMatStackIndex], gMatStack[gMatStackIndex - 1], translation, gCurGraphNodeCamera->roll); + mtxf_billboard(gMatStackInterpolated[gMatStackIndex], gMatStackInterpolated[gMatStackIndex - 1], translation, + gCurGraphNodeCamera->roll); if (gCurGraphNodeHeldObject != NULL) { mtxf_scale_vec3f(gMatStack[gMatStackIndex], gMatStack[gMatStackIndex], gCurGraphNodeHeldObject->objNode->header.gfx.scale); + mtxf_scale_vec3f(gMatStackInterpolated[gMatStackIndex], gMatStackInterpolated[gMatStackIndex], + gCurGraphNodeHeldObject->objNode->header.gfx.scale); } else if (gCurGraphNodeObject != NULL) { mtxf_scale_vec3f(gMatStack[gMatStackIndex], gMatStack[gMatStackIndex], gCurGraphNodeObject->scale); + mtxf_scale_vec3f(gMatStackInterpolated[gMatStackIndex], gMatStackInterpolated[gMatStackIndex], + gCurGraphNodeObject->scale); } mtxf_to_mtx(mtx, gMatStack[gMatStackIndex]); gMatStackFixed[gMatStackIndex] = mtx; + mtxf_to_mtx(mtxInterpolated, gMatStackInterpolated[gMatStackIndex]); + gMatStackInterpolatedFixed[gMatStackIndex] = mtxInterpolated; if (node->displayList != NULL) { geo_append_display_list(node->displayList, node->node.flags >> 8); } @@ -504,13 +671,39 @@ static void geo_process_generated_list(struct GraphNodeGenerated *node) { */ static void geo_process_background(struct GraphNodeBackground *node) { Gfx *list = NULL; + Gfx *listInterpolated = NULL; if (node->fnNode.func != NULL) { + Vec3f posCopy; + Vec3f focusCopy; + Vec3f posInterpolated; + Vec3f focusInterpolated; + + if (gGlobalTimer == node->prevCameraTimestamp + 1 && + gGlobalTimer != gLakituState.skipCameraInterpolationTimestamp) { + interpolate_vectors(posInterpolated, node->prevCameraPos, gLakituState.pos); + interpolate_vectors(focusInterpolated, node->prevCameraFocus, gLakituState.focus); + } else { + vec3f_copy(posInterpolated, gLakituState.pos); + vec3f_copy(focusInterpolated, gLakituState.focus); + } + vec3f_copy(node->prevCameraPos, gLakituState.pos); + vec3f_copy(node->prevCameraFocus, gLakituState.focus); + node->prevCameraTimestamp = gGlobalTimer; + list = node->fnNode.func(GEO_CONTEXT_RENDER, &node->fnNode.node, (struct AllocOnlyPool *) gMatStack[gMatStackIndex]); + vec3f_copy(posCopy, gLakituState.pos); + vec3f_copy(focusCopy, gLakituState.focus); + vec3f_copy(gLakituState.pos, posInterpolated); + vec3f_copy(gLakituState.focus, focusInterpolated); + listInterpolated = node->fnNode.func(GEO_CONTEXT_RENDER, &node->fnNode.node, NULL); + vec3f_copy(gLakituState.pos, posCopy); + vec3f_copy(gLakituState.focus, focusCopy); } if (list != 0) { - geo_append_display_list((void *) VIRTUAL_TO_PHYSICAL(list), node->fnNode.node.flags >> 8); + geo_append_display_list2((void *) VIRTUAL_TO_PHYSICAL(list), + (void *) VIRTUAL_TO_PHYSICAL(listInterpolated), node->fnNode.node.flags >> 8); } else if (gCurGraphNodeMasterList != NULL) { #ifndef F3DEX_GBI_2E Gfx *gfxStart = alloc_display_list(sizeof(Gfx) * 7); @@ -535,6 +728,47 @@ static void geo_process_background(struct GraphNodeBackground *node) { } } +static void anim_process(Vec3f translation, Vec3s rotation, u8 *animType, s16 animFrame, u16 **animAttribute) { + if (*animType == ANIM_TYPE_TRANSLATION) { + translation[0] += gCurAnimData[retrieve_animation_index(animFrame, animAttribute)] + * gCurAnimTranslationMultiplier; + translation[1] += gCurAnimData[retrieve_animation_index(animFrame, animAttribute)] + * gCurAnimTranslationMultiplier; + translation[2] += gCurAnimData[retrieve_animation_index(animFrame, animAttribute)] + * gCurAnimTranslationMultiplier; + *animType = ANIM_TYPE_ROTATION; + } else { + if (*animType == ANIM_TYPE_LATERAL_TRANSLATION) { + translation[0] += + gCurAnimData[retrieve_animation_index(animFrame, animAttribute)] + * gCurAnimTranslationMultiplier; + *animAttribute += 2; + translation[2] += + gCurAnimData[retrieve_animation_index(animFrame, animAttribute)] + * gCurAnimTranslationMultiplier; + *animType = ANIM_TYPE_ROTATION; + } else { + if (*animType == ANIM_TYPE_VERTICAL_TRANSLATION) { + *animAttribute += 2; + translation[1] += + gCurAnimData[retrieve_animation_index(animFrame, animAttribute)] + * gCurAnimTranslationMultiplier; + *animAttribute += 2; + *animType = ANIM_TYPE_ROTATION; + } else if (*animType == ANIM_TYPE_NO_TRANSLATION) { + *animAttribute += 6; + *animType = ANIM_TYPE_ROTATION; + } + } + } + + if (*animType == ANIM_TYPE_ROTATION) { + rotation[0] = gCurAnimData[retrieve_animation_index(animFrame, animAttribute)]; + rotation[1] = gCurAnimData[retrieve_animation_index(animFrame, animAttribute)]; + rotation[2] = gCurAnimData[retrieve_animation_index(animFrame, animAttribute)]; + } +} + /** * Render an animated part. The current animation state is not part of the node * but set in global variables. If an animated part is skipped, everything afterwards desyncs. @@ -543,53 +777,32 @@ static void geo_process_animated_part(struct GraphNodeAnimatedPart *node) { Mat4 matrix; Vec3s rotation; Vec3f translation; + Vec3s rotationInterpolated; + Vec3f translationInterpolated; Mtx *matrixPtr = alloc_display_list(sizeof(*matrixPtr)); + Mtx *mtxInterpolated = alloc_display_list(sizeof(*mtxInterpolated)); + u16 *animAttribute = gCurrAnimAttribute; + u8 animType = gCurAnimType; vec3s_copy(rotation, gVec3sZero); vec3f_set(translation, node->translation[0], node->translation[1], node->translation[2]); - if (gCurAnimType == ANIM_TYPE_TRANSLATION) { - translation[0] += gCurAnimData[retrieve_animation_index(gCurrAnimFrame, &gCurrAnimAttribute)] - * gCurAnimTranslationMultiplier; - translation[1] += gCurAnimData[retrieve_animation_index(gCurrAnimFrame, &gCurrAnimAttribute)] - * gCurAnimTranslationMultiplier; - translation[2] += gCurAnimData[retrieve_animation_index(gCurrAnimFrame, &gCurrAnimAttribute)] - * gCurAnimTranslationMultiplier; - gCurAnimType = ANIM_TYPE_ROTATION; - } else { - if (gCurAnimType == ANIM_TYPE_LATERAL_TRANSLATION) { - translation[0] += - gCurAnimData[retrieve_animation_index(gCurrAnimFrame, &gCurrAnimAttribute)] - * gCurAnimTranslationMultiplier; - gCurrAnimAttribute += 2; - translation[2] += - gCurAnimData[retrieve_animation_index(gCurrAnimFrame, &gCurrAnimAttribute)] - * gCurAnimTranslationMultiplier; - gCurAnimType = ANIM_TYPE_ROTATION; - } else { - if (gCurAnimType == ANIM_TYPE_VERTICAL_TRANSLATION) { - gCurrAnimAttribute += 2; - translation[1] += - gCurAnimData[retrieve_animation_index(gCurrAnimFrame, &gCurrAnimAttribute)] - * gCurAnimTranslationMultiplier; - gCurrAnimAttribute += 2; - gCurAnimType = ANIM_TYPE_ROTATION; - } else if (gCurAnimType == ANIM_TYPE_NO_TRANSLATION) { - gCurrAnimAttribute += 6; - gCurAnimType = ANIM_TYPE_ROTATION; - } - } - } + vec3s_copy(rotationInterpolated, rotation); + vec3f_copy(translationInterpolated, translation); + + anim_process(translationInterpolated, rotationInterpolated, &animType, gPrevAnimFrame, &animAttribute); + anim_process(translation, rotation, &gCurAnimType, gCurrAnimFrame, &gCurrAnimAttribute); + interpolate_vectors(translationInterpolated, translationInterpolated, translation); + interpolate_angles(rotationInterpolated, rotationInterpolated, rotation); - if (gCurAnimType == ANIM_TYPE_ROTATION) { - rotation[0] = gCurAnimData[retrieve_animation_index(gCurrAnimFrame, &gCurrAnimAttribute)]; - rotation[1] = gCurAnimData[retrieve_animation_index(gCurrAnimFrame, &gCurrAnimAttribute)]; - rotation[2] = gCurAnimData[retrieve_animation_index(gCurrAnimFrame, &gCurrAnimAttribute)]; - } mtxf_rotate_xyz_and_translate(matrix, translation, rotation); mtxf_mul(gMatStack[gMatStackIndex + 1], matrix, gMatStack[gMatStackIndex]); + mtxf_rotate_xyz_and_translate(matrix, translationInterpolated, rotationInterpolated); + mtxf_mul(gMatStackInterpolated[gMatStackIndex + 1], matrix, gMatStackInterpolated[gMatStackIndex]); gMatStackIndex++; mtxf_to_mtx(matrixPtr, gMatStack[gMatStackIndex]); gMatStackFixed[gMatStackIndex] = matrixPtr; + mtxf_to_mtx(mtxInterpolated, gMatStackInterpolated[gMatStackIndex]); + gMatStackInterpolatedFixed[gMatStackIndex] = mtxInterpolated; if (node->displayList != NULL) { geo_append_display_list(node->displayList, node->node.flags >> 8); } @@ -621,6 +834,17 @@ void geo_set_animation_globals(struct GraphNodeObject_sub *node, s32 hasAnimatio } gCurrAnimFrame = node->animFrame; + if (node->prevAnimPtr == anim && node->prevAnimID == node->animID && + gGlobalTimer == node->prevAnimFrameTimestamp + 1) { + gPrevAnimFrame = node->prevAnimFrame; + } else { + gPrevAnimFrame = node->animFrame; + } + node->prevAnimPtr = anim; + node->prevAnimID = node->animID; + node->prevAnimFrame = node->animFrame; + node->prevAnimFrameTimestamp = gGlobalTimer; + gCurAnimEnabled = (anim->flags & ANIM_FLAG_5) == 0; gCurrAnimAttribute = segmented_to_virtual((void *) anim->index); gCurAnimData = segmented_to_virtual((void *) anim->values); @@ -639,8 +863,10 @@ void geo_set_animation_globals(struct GraphNodeObject_sub *node, s32 hasAnimatio */ static void geo_process_shadow(struct GraphNodeShadow *node) { Gfx *shadowList; + Gfx *shadowListInterpolated; Mat4 mtxf; Vec3f shadowPos; + Vec3f shadowPosInterpolated; Vec3f animOffset; f32 objScale; f32 shadowScale; @@ -648,6 +874,7 @@ static void geo_process_shadow(struct GraphNodeShadow *node) { f32 cosAng; struct GraphNode *geo; Mtx *mtx; + Mtx *mtxInterpolated; if (gCurGraphNodeCamera != NULL && gCurGraphNodeObject != NULL) { if (gCurGraphNodeHeldObject != NULL) { @@ -686,21 +913,57 @@ static void geo_process_shadow(struct GraphNodeShadow *node) { } } + if (gCurGraphNodeHeldObject != NULL) { + if (gGlobalTimer == gCurGraphNodeHeldObject->prevShadowPosTimestamp + 1) { + interpolate_vectors(shadowPosInterpolated, gCurGraphNodeHeldObject->prevShadowPos, shadowPos); + } else { + vec3f_copy(shadowPosInterpolated, shadowPos); + } + vec3f_copy(gCurGraphNodeHeldObject->prevShadowPos, shadowPos); + gCurGraphNodeHeldObject->prevShadowPosTimestamp = gGlobalTimer; + } else { + if (gGlobalTimer == gCurGraphNodeObject->prevShadowPosTimestamp + 1 && + gGlobalTimer != gCurGraphNodeObject->skipInterpolationTimestamp) { + interpolate_vectors(shadowPosInterpolated, gCurGraphNodeObject->prevShadowPos, shadowPos); + } else { + vec3f_copy(shadowPosInterpolated, shadowPos); + } + vec3f_copy(gCurGraphNodeObject->prevShadowPos, shadowPos); + gCurGraphNodeObject->prevShadowPosTimestamp = gGlobalTimer; + } + + extern u8 gInterpolatingSurfaces; + gInterpolatingSurfaces = TRUE; + shadowListInterpolated = create_shadow_below_xyz(shadowPosInterpolated[0], shadowPosInterpolated[1], + shadowPosInterpolated[2], shadowScale, + node->shadowSolidity, node->shadowType); + gInterpolatingSurfaces = FALSE; shadowList = create_shadow_below_xyz(shadowPos[0], shadowPos[1], shadowPos[2], shadowScale, node->shadowSolidity, node->shadowType); - if (shadowList != NULL) { + if (shadowListInterpolated != NULL && shadowList != NULL) { mtx = alloc_display_list(sizeof(*mtx)); + mtxInterpolated = alloc_display_list(sizeof(*mtxInterpolated)); gMatStackIndex++; + mtxf_translate(mtxf, shadowPos); mtxf_mul(gMatStack[gMatStackIndex], mtxf, *gCurGraphNodeCamera->matrixPtr); mtxf_to_mtx(mtx, gMatStack[gMatStackIndex]); gMatStackFixed[gMatStackIndex] = mtx; + + mtxf_translate(mtxf, shadowPosInterpolated); + mtxf_mul(gMatStackInterpolated[gMatStackIndex], mtxf, *gCurGraphNodeCamera->matrixPtrInterpolated); + mtxf_to_mtx(mtxInterpolated, gMatStackInterpolated[gMatStackIndex]); + gMatStackInterpolatedFixed[gMatStackIndex] = mtxInterpolated; + if (gShadowAboveWaterOrLava == 1) { - geo_append_display_list((void *) VIRTUAL_TO_PHYSICAL(shadowList), 4); + geo_append_display_list2((void *) VIRTUAL_TO_PHYSICAL(shadowList), + (void *) VIRTUAL_TO_PHYSICAL(shadowListInterpolated), 4); } else if (gMarioOnIceOrCarpet == 1) { - geo_append_display_list((void *) VIRTUAL_TO_PHYSICAL(shadowList), 5); + geo_append_display_list2((void *) VIRTUAL_TO_PHYSICAL(shadowList), + (void *) VIRTUAL_TO_PHYSICAL(shadowListInterpolated), 5); } else { - geo_append_display_list((void *) VIRTUAL_TO_PHYSICAL(shadowList), 6); + geo_append_display_list2((void *) VIRTUAL_TO_PHYSICAL(shadowList), + (void *) VIRTUAL_TO_PHYSICAL(shadowListInterpolated), 6); } gMatStackIndex--; } @@ -797,31 +1060,101 @@ static int obj_is_in_view(struct GraphNodeObject *node, Mat4 matrix) { return TRUE; } +static void interpolate_matrix(Mat4 result, Mat4 a, Mat4 b) { + s32 i, j; + for (i = 0; i < 4; i++) { + for (j = 0; j < 4; j++) { + result[i][j] = (a[i][j] + b[i][j]) / 2.0f; + } + } +} + /** * Process an object node. */ static void geo_process_object(struct Object *node) { Mat4 mtxf; s32 hasAnimation = (node->header.gfx.node.flags & GRAPH_RENDER_HAS_ANIMATION) != 0; + Vec3f scaleInterpolated; if (node->header.gfx.unk18 == gCurGraphNodeRoot->areaIndex) { if (node->header.gfx.throwMatrix != NULL) { mtxf_mul(gMatStack[gMatStackIndex + 1], *node->header.gfx.throwMatrix, gMatStack[gMatStackIndex]); + if (gGlobalTimer == node->header.gfx.prevThrowMatrixTimestamp + 1 && + gGlobalTimer != node->header.gfx.skipInterpolationTimestamp) { + interpolate_matrix(mtxf, *node->header.gfx.throwMatrix, node->header.gfx.prevThrowMatrix); + mtxf_mul(gMatStackInterpolated[gMatStackIndex + 1], mtxf, + gMatStackInterpolated[gMatStackIndex]); + } else { + mtxf_mul(gMatStackInterpolated[gMatStackIndex + 1], (void *) node->header.gfx.throwMatrix, + gMatStackInterpolated[gMatStackIndex]); + } + mtxf_copy(node->header.gfx.prevThrowMatrix, *node->header.gfx.throwMatrix); + node->header.gfx.prevThrowMatrixTimestamp = gGlobalTimer; } else if (node->header.gfx.node.flags & GRAPH_RENDER_CYLBOARD) { + Vec3f posInterpolated; + if (gGlobalTimer == node->header.gfx.prevTimestamp + 1 && + gGlobalTimer != node->header.gfx.skipInterpolationTimestamp) { + interpolate_vectors(posInterpolated, node->header.gfx.prevPos, node->header.gfx.pos); + } else { + vec3f_copy(posInterpolated, node->header.gfx.pos); + } + vec3f_copy(node->header.gfx.prevPos, node->header.gfx.pos); + node->header.gfx.prevTimestamp = gGlobalTimer; mtxf_cylboard(gMatStack[gMatStackIndex + 1], gMatStack[gMatStackIndex], node->header.gfx.pos, gCurGraphNodeCamera->roll); + mtxf_cylboard(gMatStackInterpolated[gMatStackIndex + 1], gMatStackInterpolated[gMatStackIndex], + posInterpolated, gCurGraphNodeCamera->roll); } else if (node->header.gfx.node.flags & GRAPH_RENDER_BILLBOARD) { + Vec3f posInterpolated; + if (gGlobalTimer == node->header.gfx.prevTimestamp + 1 && + gGlobalTimer != node->header.gfx.skipInterpolationTimestamp) { + interpolate_vectors(posInterpolated, node->header.gfx.prevPos, node->header.gfx.pos); + } else { + vec3f_copy(posInterpolated, node->header.gfx.pos); + } + vec3f_copy(node->header.gfx.prevPos, node->header.gfx.pos); + node->header.gfx.prevTimestamp = gGlobalTimer; mtxf_billboard(gMatStack[gMatStackIndex + 1], gMatStack[gMatStackIndex], node->header.gfx.pos, gCurGraphNodeCamera->roll); + mtxf_billboard(gMatStackInterpolated[gMatStackIndex + 1], gMatStackInterpolated[gMatStackIndex], + posInterpolated, gCurGraphNodeCamera->roll); } else { + Vec3f posInterpolated; + Vec3s angleInterpolated; + if (gGlobalTimer == node->header.gfx.prevTimestamp + 1 && + gGlobalTimer != node->header.gfx.skipInterpolationTimestamp) { + interpolate_vectors(posInterpolated, node->header.gfx.prevPos, node->header.gfx.pos); + interpolate_angles(angleInterpolated, node->header.gfx.prevAngle, node->header.gfx.angle); + } else { + vec3f_copy(posInterpolated, node->header.gfx.pos); + vec3s_copy(angleInterpolated, node->header.gfx.angle); + } + vec3f_copy(node->header.gfx.prevPos, node->header.gfx.pos); + vec3s_copy(node->header.gfx.prevAngle, node->header.gfx.angle); + node->header.gfx.prevTimestamp = gGlobalTimer; mtxf_rotate_zxy_and_translate(mtxf, node->header.gfx.pos, node->header.gfx.angle); mtxf_mul(gMatStack[gMatStackIndex + 1], mtxf, gMatStack[gMatStackIndex]); + mtxf_rotate_zxy_and_translate(mtxf, posInterpolated, angleInterpolated); + mtxf_mul(gMatStackInterpolated[gMatStackIndex + 1], mtxf, gMatStackInterpolated[gMatStackIndex]); } + if (gGlobalTimer == node->header.gfx.prevScaleTimestamp + 1 && + gGlobalTimer != node->header.gfx.skipInterpolationTimestamp) { + interpolate_vectors(scaleInterpolated, node->header.gfx.prevScale, node->header.gfx.scale); + } else { + vec3f_copy(scaleInterpolated, node->header.gfx.scale); + } + vec3f_copy(node->header.gfx.prevScale, node->header.gfx.scale); + node->header.gfx.prevScaleTimestamp = gGlobalTimer; + mtxf_scale_vec3f(gMatStack[gMatStackIndex + 1], gMatStack[gMatStackIndex + 1], node->header.gfx.scale); + mtxf_scale_vec3f(gMatStackInterpolated[gMatStackIndex + 1], gMatStackInterpolated[gMatStackIndex + 1], + scaleInterpolated); node->header.gfx.throwMatrix = &gMatStack[++gMatStackIndex]; + node->header.gfx.throwMatrixInterpolated = &gMatStackInterpolated[gMatStackIndex]; node->header.gfx.cameraToObject[0] = gMatStack[gMatStackIndex][3][0]; node->header.gfx.cameraToObject[1] = gMatStack[gMatStackIndex][3][1]; node->header.gfx.cameraToObject[2] = gMatStack[gMatStackIndex][3][2]; @@ -832,9 +1165,12 @@ static void geo_process_object(struct Object *node) { } if (obj_is_in_view(&node->header.gfx, gMatStack[gMatStackIndex])) { Mtx *mtx = alloc_display_list(sizeof(*mtx)); + Mtx *mtxInterpolated = alloc_display_list(sizeof(*mtxInterpolated)); mtxf_to_mtx(mtx, gMatStack[gMatStackIndex]); gMatStackFixed[gMatStackIndex] = mtx; + mtxf_to_mtx(mtxInterpolated, gMatStackInterpolated[gMatStackIndex]); + gMatStackInterpolatedFixed[gMatStackIndex] = mtxInterpolated; if (node->header.gfx.sharedChild != NULL) { gCurGraphNodeObject = (struct GraphNodeObject *) node; node->header.gfx.sharedChild->parent = &node->header.gfx.node; @@ -845,11 +1181,16 @@ static void geo_process_object(struct Object *node) { if (node->header.gfx.node.children != NULL) { geo_process_node_and_siblings(node->header.gfx.node.children); } + } else { + node->header.gfx.prevThrowMatrixTimestamp = 0; + node->header.gfx.prevTimestamp = 0; + node->header.gfx.prevScaleTimestamp = 0; } gMatStackIndex--; gCurAnimType = ANIM_TYPE_NONE; node->header.gfx.throwMatrix = NULL; + node->header.gfx.throwMatrixInterpolated = NULL; } } @@ -876,6 +1217,8 @@ void geo_process_held_object(struct GraphNodeHeldObject *node) { Mat4 mat; Vec3f translation; Mtx *mtx = alloc_display_list(sizeof(*mtx)); + Mtx *mtxInterpolated = alloc_display_list(sizeof(*mtxInterpolated)); + Vec3f scaleInterpolated; #ifdef F3DEX_GBI_2 gSPLookAt(gDisplayListHead++, &lookAt); @@ -891,6 +1234,14 @@ void geo_process_held_object(struct GraphNodeHeldObject *node) { translation[1] = node->translation[1] / 4.0f; translation[2] = node->translation[2] / 4.0f; + if (gGlobalTimer == node->objNode->header.gfx.prevScaleTimestamp + 1) { + interpolate_vectors(scaleInterpolated, node->objNode->header.gfx.prevScale, node->objNode->header.gfx.scale); + } else { + vec3f_copy(scaleInterpolated, node->objNode->header.gfx.scale); + } + vec3f_copy(node->objNode->header.gfx.prevScale, node->objNode->header.gfx.scale); + node->objNode->header.gfx.prevScaleTimestamp = gGlobalTimer; + mtxf_translate(mat, translation); mtxf_copy(gMatStack[gMatStackIndex + 1], *gCurGraphNodeObject->throwMatrix); gMatStack[gMatStackIndex + 1][3][0] = gMatStack[gMatStackIndex][3][0]; @@ -899,6 +1250,13 @@ void geo_process_held_object(struct GraphNodeHeldObject *node) { mtxf_mul(gMatStack[gMatStackIndex + 1], mat, gMatStack[gMatStackIndex + 1]); mtxf_scale_vec3f(gMatStack[gMatStackIndex + 1], gMatStack[gMatStackIndex + 1], node->objNode->header.gfx.scale); + mtxf_copy(gMatStackInterpolated[gMatStackIndex + 1], (void *) gCurGraphNodeObject->throwMatrixInterpolated); + gMatStackInterpolated[gMatStackIndex + 1][3][0] = gMatStackInterpolated[gMatStackIndex][3][0]; + gMatStackInterpolated[gMatStackIndex + 1][3][1] = gMatStackInterpolated[gMatStackIndex][3][1]; + gMatStackInterpolated[gMatStackIndex + 1][3][2] = gMatStackInterpolated[gMatStackIndex][3][2]; + mtxf_mul(gMatStackInterpolated[gMatStackIndex + 1], mat, gMatStackInterpolated[gMatStackIndex + 1]); + mtxf_scale_vec3f(gMatStackInterpolated[gMatStackIndex + 1], gMatStackInterpolated[gMatStackIndex + 1], + scaleInterpolated); if (node->fnNode.func != NULL) { node->fnNode.func(GEO_CONTEXT_HELD_OBJ, &node->fnNode.node, (struct AllocOnlyPool *) gMatStack[gMatStackIndex + 1]); @@ -906,12 +1264,15 @@ void geo_process_held_object(struct GraphNodeHeldObject *node) { gMatStackIndex++; mtxf_to_mtx(mtx, gMatStack[gMatStackIndex]); gMatStackFixed[gMatStackIndex] = mtx; + mtxf_to_mtx(mtxInterpolated, gMatStackInterpolated[gMatStackIndex]); + gMatStackInterpolatedFixed[gMatStackIndex] = mtxInterpolated; gGeoTempState.type = gCurAnimType; gGeoTempState.enabled = gCurAnimEnabled; gGeoTempState.frame = gCurrAnimFrame; gGeoTempState.translationMultiplier = gCurAnimTranslationMultiplier; gGeoTempState.attribute = gCurrAnimAttribute; gGeoTempState.data = gCurAnimData; + gGeoTempState.prevFrame = gPrevAnimFrame; gCurAnimType = 0; gCurGraphNodeHeldObject = (void *) node; if (node->objNode->header.gfx.unk38.curAnim != NULL) { @@ -926,6 +1287,7 @@ void geo_process_held_object(struct GraphNodeHeldObject *node) { gCurAnimTranslationMultiplier = gGeoTempState.translationMultiplier; gCurrAnimAttribute = gGeoTempState.attribute; gCurAnimData = gGeoTempState.data; + gPrevAnimFrame = gGeoTempState.prevFrame; gMatStackIndex--; } @@ -1047,6 +1409,7 @@ void geo_process_root(struct GraphNodeRoot *node, Vp *b, Vp *c, s32 clearColor) if (node->node.flags & GRAPH_RENDER_ACTIVE) { Mtx *initialMatrix; Vp *viewport = alloc_display_list(sizeof(*viewport)); + Vp *viewportInterpolated = viewport; gDisplayListHeap = alloc_only_pool_init(); initialMatrix = alloc_display_list(sizeof(*initialMatrix)); @@ -1056,7 +1419,12 @@ void geo_process_root(struct GraphNodeRoot *node, Vp *b, Vp *c, s32 clearColor) vec3s_set(viewport->vp.vscale, node->width * 4, node->height * 4, 511); if (b != NULL) { clear_frame_buffer(clearColor); - make_viewport_clip_rect(b); + viewportInterpolated = alloc_display_list(sizeof(*viewportInterpolated)); + interpolate_vectors_s16(viewportInterpolated->vp.vtrans, sPrevViewport.vp.vtrans, b->vp.vtrans); + interpolate_vectors_s16(viewportInterpolated->vp.vscale, sPrevViewport.vp.vscale, b->vp.vscale); + + sViewportPos = gDisplayListHead; + make_viewport_clip_rect(viewportInterpolated); *viewport = *b; } @@ -1064,11 +1432,16 @@ void geo_process_root(struct GraphNodeRoot *node, Vp *b, Vp *c, s32 clearColor) clear_frame_buffer(clearColor); make_viewport_clip_rect(c); } + sPrevViewport = *viewport; mtxf_identity(gMatStack[gMatStackIndex]); mtxf_to_mtx(initialMatrix, gMatStack[gMatStackIndex]); gMatStackFixed[gMatStackIndex] = initialMatrix; - gSPViewport(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(viewport)); + + mtxf_identity(gMatStackInterpolated[gMatStackIndex]); + gMatStackInterpolatedFixed[gMatStackIndex] = initialMatrix; + + gSPViewport(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(viewportInterpolated)); gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(gMatStackFixed[gMatStackIndex]), G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH); gCurGraphNodeRoot = node; diff --git a/src/game/screen_transition.c b/src/game/screen_transition.c index b49ddaf5..d6656af2 100644 --- a/src/game/screen_transition.c +++ b/src/game/screen_transition.c @@ -16,6 +16,19 @@ u8 sTransitionColorFadeCount[4] = { 0 }; u16 sTransitionTextureFadeCount[2] = { 0 }; +static Gfx *sScreenTransitionVerticesPos[2]; +static Vtx *sScreenTransitionVertices; + +void patch_screen_transition_interpolated(void) { + if (sScreenTransitionVerticesPos[0] != NULL) { + gSPVertex(sScreenTransitionVerticesPos[0], VIRTUAL_TO_PHYSICAL(sScreenTransitionVertices), 8, 0); + gSPVertex(sScreenTransitionVerticesPos[1], VIRTUAL_TO_PHYSICAL(sScreenTransitionVertices), 4, 0); + sScreenTransitionVerticesPos[0] = NULL; + sScreenTransitionVerticesPos[1] = NULL; + sScreenTransitionVertices = NULL; + } +} + s32 set_and_reset_transition_fade_timer(s8 fadeTimer, u8 transTime) { s32 reset = FALSE; @@ -85,14 +98,29 @@ s32 render_fade_transition_into_color(s8 fadeTimer, u8 transTime, struct WarpTra return dl_transition_color(fadeTimer, transTime, transData, alpha); } +#if 0 + s16 calc_tex_transition_radius(s8 fadeTimer, s8 transTime, struct WarpTransitionData *transData) { f32 texRadius = transData->endTexRadius - transData->startTexRadius; f32 radiusTime = sTransitionColorFadeCount[fadeTimer] * texRadius / (f32)(transTime - 1); f32 result = transData->startTexRadius + radiusTime; - return (s16)(result + 0.5);; + return (s16)(result + 0.5); } +#else + +s16 calc_tex_transition_radius(s8 fadeTimer, f32 interpolationFraction, s8 transTime, struct WarpTransitionData *transData) { + f32 texRadius = transData->endTexRadius - transData->startTexRadius; + f32 radiusTime = (sTransitionColorFadeCount[fadeTimer] == 0 ? 0 : + sTransitionColorFadeCount[fadeTimer] - 1 + interpolationFraction) * texRadius / (f32)(transTime - 1); + f32 result = transData->startTexRadius + radiusTime; + + return (s16)(result + 0.5); +} + +#endif + f32 calc_tex_transition_time(s8 fadeTimer, s8 transTime, struct WarpTransitionData *transData) { f32 startX = transData->startTexX; f32 startY = transData->startTexY; @@ -166,6 +194,8 @@ void *sTextureTransitionID[] = { texture_transition_bowser_half, }; +#if 0 + s32 render_textured_transition(s8 fadeTimer, s8 transTime, struct WarpTransitionData *transData, s8 texID, s8 transTexType) { f32 texTransTime = calc_tex_transition_time(fadeTimer, transTime, transData); u16 texTransPos = convert_tex_transition_angle_to_pos(transData); @@ -206,6 +236,56 @@ s32 render_textured_transition(s8 fadeTimer, s8 transTime, struct WarpTransition return set_and_reset_transition_fade_timer(fadeTimer, transTime); } +#else + +s32 render_textured_transition(s8 fadeTimer, s8 transTime, struct WarpTransitionData *transData, s8 texID, s8 transTexType) { + f32 texTransTime = calc_tex_transition_time(fadeTimer, transTime, transData); + u16 texTransPos = convert_tex_transition_angle_to_pos(transData); + s16 centerTransX = center_tex_transition_x(transData, texTransTime, texTransPos); + s16 centerTransY = center_tex_transition_y(transData, texTransTime, texTransPos); + s16 texTransRadius = calc_tex_transition_radius(fadeTimer, 1.0f, transTime, transData); + s16 texTransRadiusInterpolated = calc_tex_transition_radius(fadeTimer, 0.5f, transTime, transData); + Vtx *verts = alloc_display_list(8 * sizeof(*verts)); + Vtx *vertsInterpolated = alloc_display_list(8 * sizeof(*vertsInterpolated)); + + if (verts != NULL && vertsInterpolated != NULL) { + load_tex_transition_vertex(verts, fadeTimer, transData, centerTransX, centerTransY, texTransRadius, transTexType); + load_tex_transition_vertex(vertsInterpolated, fadeTimer, transData, centerTransX, centerTransY, texTransRadiusInterpolated, transTexType); + sScreenTransitionVertices = verts; + gSPDisplayList(gDisplayListHead++, dl_proj_mtx_fullscreen) + gDPSetCombineMode(gDisplayListHead++, G_CC_SHADE, G_CC_SHADE); + gDPSetRenderMode(gDisplayListHead++, G_RM_AA_OPA_SURF, G_RM_AA_OPA_SURF2); + sScreenTransitionVerticesPos[0] = gDisplayListHead; + gSPVertex(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(vertsInterpolated), 8, 0); + gSPDisplayList(gDisplayListHead++, dl_transition_draw_filled_region); + gDPPipeSync(gDisplayListHead++); + gDPSetCombineMode(gDisplayListHead++, G_CC_MODULATEIDECALA, G_CC_MODULATEIDECALA); + gDPSetRenderMode(gDisplayListHead++, G_RM_AA_XLU_SURF, G_RM_AA_XLU_SURF2); + gDPSetTextureFilter(gDisplayListHead++, G_TF_BILERP); + switch (transTexType) { + case TRANS_TYPE_MIRROR: + gDPLoadTextureBlock(gDisplayListHead++, sTextureTransitionID[texID], G_IM_FMT_IA, G_IM_SIZ_8b, 32, 64, 0, + G_TX_WRAP | G_TX_MIRROR, G_TX_WRAP | G_TX_MIRROR, 5, 6, G_TX_NOLOD, G_TX_NOLOD); + break; + case TRANS_TYPE_CLAMP: + gDPLoadTextureBlock(gDisplayListHead++, sTextureTransitionID[texID], G_IM_FMT_IA, G_IM_SIZ_8b, 64, 64, 0, + G_TX_CLAMP, G_TX_CLAMP, 6, 6, G_TX_NOLOD, G_TX_NOLOD); + break; + } + gSPTexture(gDisplayListHead++, 0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_ON); + sScreenTransitionVerticesPos[1] = gDisplayListHead; + gSPVertex(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(vertsInterpolated), 4, 0); + gSPDisplayList(gDisplayListHead++, dl_draw_quad_verts_0123); + gSPTexture(gDisplayListHead++, 0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_OFF); + gSPDisplayList(gDisplayListHead++, dl_screen_transition_end); + sTransitionTextureFadeCount[fadeTimer] += transData->texTimer; + } else { + } + return set_and_reset_transition_fade_timer(fadeTimer, transTime); +} + +#endif + int render_screen_transition(s8 fadeTimer, s8 transType, u8 transTime, struct WarpTransitionData *transData) { switch (transType) { case WARP_TRANSITION_FADE_FROM_COLOR: diff --git a/src/game/shadow.c b/src/game/shadow.c index 324400e5..123a030c 100644 --- a/src/game/shadow.c +++ b/src/game/shadow.c @@ -12,6 +12,7 @@ #include "segment2.h" #include "shadow.h" #include "sm64.h" +#include "moon/saturn/saturn_types.h" // Avoid Z-fighting #define find_floor_height_and_data 0.4 + find_floor_height_and_data @@ -851,6 +852,11 @@ Gfx *create_shadow_hardcoded_rectangle(f32 xPos, f32 yPos, f32 zPos, UNUSED s16 */ Gfx *create_shadow_below_xyz(f32 xPos, f32 yPos, f32 zPos, s16 shadowScale, u8 shadowSolidity, s8 shadowType) { + + if (!enable_shadows) { + return NULL; + } + Gfx *displayList = NULL; struct Surface *pfloor; find_floor(xPos, yPos, zPos, &pfloor); diff --git a/src/menu/intro_geo.c b/src/menu/intro_geo.c index 2ae81f5b..2a9aee5a 100644 --- a/src/menu/intro_geo.c +++ b/src/menu/intro_geo.c @@ -1,5 +1,6 @@ #include +#include "engine/math_util.h" #include "game/memory.h" #include "game/segment2.h" #include "game/segment7.h" @@ -146,6 +147,18 @@ Gfx *geo_n64_screen(s32 sp50, struct GraphNode *sp54, UNUSED void *context) { } +static Gfx *sIntroScalePos; +static Vec3f sIntroScale; + +void patch_title_screen_scales(void) { + if (sIntroScalePos != NULL) { + Mtx *scaleMat = alloc_display_list(sizeof(*scaleMat)); + guScale(scaleMat, sIntroScale[0], sIntroScale[1], sIntroScale[2]); + gSPMatrix(sIntroScalePos, scaleMat, G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_PUSH); + sIntroScalePos = NULL; + } +} + Gfx *geo_title_screen(s32 sp50, struct GraphNode *sp54, UNUSED void *context) { struct GraphNode *graphNode; // sp4c Gfx *displayList; // sp48 @@ -156,6 +169,8 @@ Gfx *geo_title_screen(s32 sp50, struct GraphNode *sp54, UNUSED void *context) { f32 scaleX; // sp34 f32 scaleY; // sp30 f32 scaleZ; // sp2c + Vec3f scale; + Vec3f scaleInterpolated; graphNode = sp54; displayList = NULL; displayListIter = NULL; @@ -187,6 +202,11 @@ Gfx *geo_title_screen(s32 sp50, struct GraphNode *sp54, UNUSED void *context) { scaleZ = 0.0f; } guScale(scaleMat, scaleX, scaleY, scaleZ); + vec3f_set(scale, scaleX, scaleY, scaleZ); + interpolate_vectors(scaleInterpolated, sIntroScale, scale); + vec3f_set(sIntroScale, scaleX, scaleY, scaleZ); + guScale(scaleMat, scaleInterpolated[0], scaleInterpolated[1], scaleInterpolated[2]); + sIntroScalePos = displayListIter; gSPMatrix(displayListIter++, scaleMat, G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_PUSH); gSPDisplayList(displayListIter++, &intro_seg7_dl_0700B3A0); gSPPopMatrix(displayListIter++, G_MTX_MODELVIEW); diff --git a/src/moon/achievements/achievements.cpp b/src/moon/achievements/achievements.cpp index 86d4bc1b..cee14def 100644 --- a/src/moon/achievements/achievements.cpp +++ b/src/moon/achievements/achievements.cpp @@ -30,7 +30,7 @@ using namespace std; map registeredAchievements; map> entries; -bool cheatsGotEnabled = false; +bool cheatsGotEnabled = true; namespace AchievementList { /* Star achievements */ diff --git a/src/moon/imgui/imgui_impl.cpp b/src/moon/imgui/imgui_impl.cpp index b162e82e..3f80f25e 100644 --- a/src/moon/imgui/imgui_impl.cpp +++ b/src/moon/imgui/imgui_impl.cpp @@ -12,6 +12,9 @@ #include "moon/mod-engine/hooks/hook.h" #include "moon/mod-engine/textures/mod-texture.h" #include "moon/mod-engine/engine.h" +#include "moon/saturn/saturn.h" +#include "moon/saturn/saturn_colors.h" +#include "moon/saturn/saturn_types.h" #include "icons/IconsForkAwesome.h" #include "icons/IconsMaterialDesign.h" #include "moon/utils/moon-env.h" @@ -63,6 +66,8 @@ extern "C" { extern "C" { #include "pc/gfx/gfx_pc.h" #include "pc/pc_main.h" +#include "game/camera.h" +#include "game/mario.h" } #include "pc/configfile.h" @@ -133,6 +138,26 @@ namespace MoonInternal { map fontMap; + // Colors + static ImVec4 uiHatColor = ImVec4(255.0f / 255.0f, 0.0f / 255.0f, 0.0f / 255.0f, 255.0f / 255.0f); + static ImVec4 uiHatShadeColor = ImVec4(127.0f / 255.0f, 0.0f / 255.0f, 0.0f / 255.0f, 255.0f / 255.0f); + static ImVec4 uiOverallsColor = ImVec4(0.0f / 255.0f, 0.0f / 255.0f, 255.0f / 255.0f, 255.0f / 255.0f); + static ImVec4 uiOverallsShadeColor = ImVec4(0.0f / 255.0f, 0.0f / 255.0f, 127.0f / 255.0f, 255.0f / 255.0f); + static ImVec4 uiGlovesColor = ImVec4(255.0f / 255.0f, 255.0f / 255.0f, 255.0f / 255.0f, 255.0f / 255.0f); + static ImVec4 uiGlovesShadeColor = ImVec4(127.0f / 255.0f, 127.0f / 255.0f, 127.0f / 255.0f, 255.0f / 255.0f); + static ImVec4 uiShoesColor = ImVec4(114.0f / 255.0f, 28.0f / 255.0f, 14.0f / 255.0f, 255.0f / 255.0f); + static ImVec4 uiShoesShadeColor = ImVec4(57.0f / 255.0f, 14.0f / 255.0f, 7.0f / 255.0f, 255.0f / 255.0f); + static ImVec4 uiSkinColor = ImVec4(254.0f / 255.0f, 193.0f / 255.0f, 121.0f / 255.0f, 255.0f / 255.0f); + static ImVec4 uiSkinShadeColor = ImVec4(127.0f / 255.0f, 96.0f / 255.0f, 60.0f / 255.0f, 255.0f / 255.0f); + static ImVec4 uiHairColor = ImVec4(115.0f / 255.0f, 6.0f / 255.0f, 0.0f / 255.0f, 255.0f / 255.0f); + static ImVec4 uiHairShadeColor = ImVec4(57.0f / 255.0f, 3.0f / 255.0f, 0.0f / 255.0f, 255.0f / 255.0f); + + static char bufname[128] = "Sample"; + + bool hasChangedFullscreen; + int tempXRes; + int tempYRes; + void setupFonts() { ImGuiIO& io = ImGui::GetIO(); // for (auto entry = Moon::fonts.begin(); entry != Moon::fonts.end(); entry++){ @@ -156,6 +181,45 @@ namespace MoonInternal { io.Fonts->Build(); } + void apply_cc_from_editor() { + defaultColorHatRLight = (int)(uiHatColor.x * 255); + defaultColorHatGLight = (int)(uiHatColor.y * 255); + defaultColorHatBLight = (int)(uiHatColor.z * 255); + defaultColorHatRDark = (int)(uiHatShadeColor.x * 255); + defaultColorHatGDark = (int)(uiHatShadeColor.y * 255); + defaultColorHatBDark = (int)(uiHatShadeColor.z * 255); + defaultColorOverallsRLight = (int)(uiOverallsColor.x * 255); + defaultColorOverallsGLight = (int)(uiOverallsColor.y * 255); + defaultColorOverallsBLight = (int)(uiOverallsColor.z * 255); + defaultColorOverallsRDark = (int)(uiOverallsShadeColor.x * 255); + defaultColorOverallsGDark = (int)(uiOverallsShadeColor.y * 255); + defaultColorOverallsBDark = (int)(uiOverallsShadeColor.z * 255); + defaultColorGlovesRLight = (int)(uiGlovesColor.x * 255); + defaultColorGlovesGLight = (int)(uiGlovesColor.y * 255); + defaultColorGlovesBLight = (int)(uiGlovesColor.z * 255); + defaultColorGlovesRDark = (int)(uiGlovesShadeColor.x * 255); + defaultColorGlovesGDark = (int)(uiGlovesShadeColor.y * 255); + defaultColorGlovesBDark = (int)(uiGlovesShadeColor.z * 255); + defaultColorShoesRLight = (int)(uiShoesColor.x * 255); + defaultColorShoesGLight = (int)(uiShoesColor.y * 255); + defaultColorShoesBLight = (int)(uiShoesColor.z * 255); + defaultColorShoesRDark = (int)(uiShoesShadeColor.x * 255); + defaultColorShoesGDark = (int)(uiShoesShadeColor.y * 255); + defaultColorShoesBDark = (int)(uiShoesShadeColor.z * 255); + defaultColorSkinRLight = (int)(uiSkinColor.x * 255); + defaultColorSkinGLight = (int)(uiSkinColor.y * 255); + defaultColorSkinBLight = (int)(uiSkinColor.z * 255); + defaultColorSkinRDark = (int)(uiSkinShadeColor.x * 255); + defaultColorSkinGDark = (int)(uiSkinShadeColor.y * 255); + defaultColorSkinBDark = (int)(uiSkinShadeColor.z * 255); + defaultColorHairRLight = (int)(uiHairColor.x * 255); + defaultColorHairGLight = (int)(uiHairColor.y * 255); + defaultColorHairBLight = (int)(uiHairColor.z * 255); + defaultColorHairRDark = (int)(uiHairShadeColor.x * 255); + defaultColorHairGDark = (int)(uiHairShadeColor.y * 255); + defaultColorHairBDark = (int)(uiHairShadeColor.z * 255); + } + void setupImGuiModule(string status) { MoonInternal::setupWindowHook(status); if(status == "PreStartup"){ @@ -182,6 +246,9 @@ namespace MoonInternal { ImGui_ImplSDL2_InitForOpenGL(window, call.baseArgs["context"]); ImGui_ImplOpenGL3_Init(glsl_version); + tempXRes = configWindow.w; + tempYRes = configWindow.h; + #ifdef TARGET_SWITCH MoonNX::handleVirtualKeyboard("Init"); #endif @@ -227,7 +294,7 @@ namespace MoonInternal { if (!ImGui::DockBuilderGetNode(dockspace_id)) { ImGui::DockBuilderRemoveNode(dockspace_id); - ImGui::DockBuilderAddNode(dockspace_id, ImGuiDockNodeFlags_None); + ImGui::DockBuilderAddNode(dockspace_id, ImGuiDockNodeFlags_NoTabBar); ImGui::DockBuilderDockWindow("Game", dockspace_id); @@ -236,24 +303,39 @@ namespace MoonInternal { ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspace_flags); - if (ImGui::BeginMenuBar()) { - TextureData* tmp = forceTextureLoad("mod-icons://Moon64"); - if(tmp != nullptr) { - ImGui::SetCursorPos(ImVec2(0, 0)); - ImGui::Image((ImTextureID) tmp->texture_id, ImVec2(25.0f, 25.0f)); + //if (show_menu_bar) { + if (ImGui::BeginMenuBar()) { + /* + TextureData* tmp = forceTextureLoad("mod-icons://Moon64"); + if(tmp != nullptr) { + ImGui::SetCursorPos(ImVec2(0, 0)); + ImGui::Image((ImTextureID) tmp->texture_id, ImVec2(25.0f, 25.0f)); + ImGui::SameLine(); + } + */ + ImGui::Text("Saturn"); ImGui::SameLine(); + ImGui::Separator(); + if (ImGui::BeginMenu("Tools")) { + ImGui::MenuItem("Toggle View (F1)", NULL, &show_menu_bar); + ImGui::MenuItem("N64 Mode", NULL, &configImGui.n64Mode); + ImGui::EndMenu(); + } + if (ImGui::BeginMenu("View")) { + ImGui::MenuItem("Stats", NULL, &configImGui.moon64); + ImGui::MenuItem("Machinima", NULL, &configImGui.s_machinima); + ImGui::MenuItem("Quick Toggles", NULL, &configImGui.s_toggles); + ImGui::MenuItem("CC Editor", NULL, &configImGui.s_cceditor); + //ImGui::MenuItem("Debug Textures", NULL, &configImGui.texture_debug); + ImGui::EndMenu(); + } + if (ImGui::BeginMenu("Misc")) { + ImGui::MenuItem("Settings", NULL, &configImGui.s_options); + ImGui::EndMenu(); + } + ImGui::EndMenuBar(); } - ImGui::Text("Moon64"); - ImGui::SameLine(); - ImGui::Separator(); - if (ImGui::BeginMenu("View")) { - ImGui::MenuItem("Moon64", NULL, &configImGui.moon64); - ImGui::MenuItem("Textures", NULL, &configImGui.texture_debug); - ImGui::MenuItem("N64 Mode", NULL, &configImGui.n64Mode); - ImGui::EndMenu(); - } - ImGui::EndMenuBar(); - } + //} ImGui::End(); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0,0)); ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0.0f, 0.0f, 0.0f, 1.0f)); // Set window background to red @@ -264,6 +346,27 @@ namespace MoonInternal { ImVec2 size = ImGui::GetContentRegionAvail(); ImVec2 pos = ImVec2(0, 0); + if (configWindow.fullscreen) { + if (!hasChangedFullscreen) { + std::cout << "fullscreen test" << std::endl; + tempXRes = configWindow.w; + tempYRes = configWindow.h; + SDL_DisplayMode DM; + SDL_GetCurrentDisplayMode(0, &DM); + configWindow.w = DM.w; + configWindow.h = DM.h; + hasChangedFullscreen = true; + } + } else { + if (hasChangedFullscreen) { + std::cout << "test2 fsd" << std::endl; + configWindow.w = tempXRes; + configWindow.h = tempYRes; + SDL_SetWindowSize(window, tempXRes, tempYRes); + hasChangedFullscreen = false; + } + } + configWindow.internal_w = configImGui.n64Mode ? SM64_WIDTH : size.x; configWindow.internal_h = configImGui.n64Mode ? SM64_HEIGHT : size.y; @@ -278,27 +381,203 @@ namespace MoonInternal { ImGui::ImageRotated((ImTextureID) fbuf, pos, size, 180.0f); ImGui::End(); - if (configImGui.moon64){ + if (configImGui.moon64 && show_menu_bar){ ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0)); - ImGui::Begin("Moon64 Game Stats", NULL, ImGuiWindowFlags_None); + ImGui::Begin("Stats", NULL, ImGuiWindowFlags_None); ImGui::Text("Platform: " PLATFORM " (" RAPI_NAME ")"); - ImGui::Text("Status: %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); + ImGui::Text("View: %.0fx%.0f (%.1f FPS)", configWindow.internal_w * configWindow.multiplier, configWindow.internal_h * configWindow.multiplier, ImGui::GetIO().Framerate); ImGui::Text("Version: " GIT_BRANCH " " GIT_HASH); - ImGui::Text("Addons: %d\n", Moon::addons.size()); - ImGui::Text("Resolution: %.0fx%.0f\n", configWindow.internal_w * configWindow.multiplier, configWindow.internal_h * configWindow.multiplier); - ImGui::Text("Internal Resolution:"); - if(!configImGui.n64Mode) - ImGui::SliderFloat("Mul", &configWindow.multiplier, 0.0f, 4.0f); - else - ImGui::SliderInt("Mul", &n64Mul, 1, 8); + ImGui::End(); + ImGui::PopStyleColor(); + } + if (configImGui.s_toggles && show_menu_bar){ + ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0)); + ImGui::Begin("Quick Toggles", NULL, ImGuiWindowFlags_None); + + if (ImGui::BeginTable("quick_toggles", 1)) + { + ImGui::TableNextColumn(); + ImGui::Checkbox("HUD", &configHUD); + ImGui::TableNextColumn(); + ImGui::Checkbox("Head Rotations", &enable_head_rotations); + ImGui::TableNextColumn(); + ImGui::Checkbox("Shadows", &enable_shadows); + ImGui::TableNextColumn(); + ImGui::Checkbox("Dust Particles", &enable_dust_particles); + ImGui::EndTable(); + } ImGui::End(); ImGui::PopStyleColor(); } - if(configImGui.texture_debug) { + if (configImGui.s_machinima && show_menu_bar) { + ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0)); + ImGui::Begin("Machinima", NULL, ImGuiWindowFlags_None); + + ImGui::Checkbox("Machinima Camera", &camera_frozen); + if (camera_frozen == true) { + ImGui::SliderFloat("Speed", &camera_speed, 0.0f, 0.3f); + } + + ImGui::Dummy(ImVec2(0, 10)); + + ImGui::Text("Body States"); + const char* eyeStates[] = { "Default", "Open", "Half", "Closed", "Left", "Right", "Up", "Down", "Dead" }; + ImGui::Combo("Eyes", ¤t_eye_state, eyeStates, IM_ARRAYSIZE(eyeStates)); + const char* handStates[] = { "Fists", "Open", "Peace", "With Cap", "With Wing Cap", "Right Open" }; + ImGui::Combo("Hands", ¤t_hand_state, handStates, IM_ARRAYSIZE(handStates)); + const char* capStates[] = { "Cap On", "Cap Off", "Wing Cap" }; // unused "wing cap off" not included + ImGui::Combo("Cap", ¤t_cap_state, capStates, IM_ARRAYSIZE(capStates)); + + ImGui::Dummy(ImVec2(0, 10)); + + ImGui::Text("Select Color Code"); + static int current_cc_id = 0; + string cc_name = MoonInternal::cc_array[current_cc_id].substr(0, MoonInternal::cc_array[current_cc_id].size() - 3); + if (ImGui::BeginCombo(".gs", cc_name.c_str())) + { + for (int n = 0; n < MoonInternal::cc_array.size(); n++) + { + const bool is_selected = (current_cc_id == n); + cc_name = MoonInternal::cc_array[n].substr(0, MoonInternal::cc_array[n].size() - 3); + if (ImGui::Selectable(cc_name.c_str(), is_selected)) { + current_cc_id = n; + } + + // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) + if (is_selected) + ImGui::SetItemDefaultFocus(); + } + ImGui::EndCombo(); + } + if (ImGui::Button("Load")) { + load_cc_file(cc_array[current_cc_id]); + + uiHatColor = ImVec4(float(defaultColorHatRLight) / 255.0f, float(defaultColorHatGLight) / 255.0f, float(defaultColorHatBLight) / 255.0f, 255.0f / 255.0f); + uiHatShadeColor = ImVec4(float(defaultColorHatRDark) / 255.0f, float(defaultColorHatGDark) / 255.0f, float(defaultColorHatBDark) / 255.0f, 255.0f / 255.0f); + uiOverallsColor = ImVec4(float(defaultColorOverallsRLight) / 255.0f, float(defaultColorOverallsGLight) / 255.0f, float(defaultColorOverallsBLight) / 255.0f, 255.0f / 255.0f); + uiOverallsShadeColor = ImVec4(float(defaultColorOverallsRDark) / 255.0f, float(defaultColorOverallsGDark) / 255.0f, float(defaultColorOverallsBDark) / 255.0f, 255.0f / 255.0f); + uiGlovesColor = ImVec4(float(defaultColorGlovesRLight) / 255.0f, float(defaultColorGlovesGLight) / 255.0f, float(defaultColorGlovesBLight) / 255.0f, 255.0f / 255.0f); + uiGlovesShadeColor = ImVec4(float(defaultColorGlovesRDark) / 255.0f, float(defaultColorGlovesGDark) / 255.0f, float(defaultColorGlovesBDark) / 255.0f, 255.0f / 255.0f); + uiShoesColor = ImVec4(float(defaultColorShoesRLight) / 255.0f, float(defaultColorShoesGLight) / 255.0f, float(defaultColorShoesBLight) / 255.0f, 255.0f / 255.0f); + uiShoesShadeColor = ImVec4(float(defaultColorShoesRDark) / 255.0f, float(defaultColorShoesGDark) / 255.0f, float(defaultColorShoesBDark) / 255.0f, 255.0f / 255.0f); + uiSkinColor = ImVec4(float(defaultColorSkinRLight) / 255.0f, float(defaultColorSkinGLight) / 255.0f, float(defaultColorSkinBLight) / 255.0f, 255.0f / 255.0f); + uiSkinShadeColor = ImVec4(float(defaultColorSkinRDark) / 255.0f, float(defaultColorSkinGDark) / 255.0f, float(defaultColorSkinBDark) / 255.0f, 255.0f / 255.0f); + uiHairColor = ImVec4(float(defaultColorHairRLight) / 255.0f, float(defaultColorHairGLight) / 255.0f, float(defaultColorHairBLight) / 255.0f, 255.0f / 255.0f); + uiHairShadeColor = ImVec4(float(defaultColorHairRDark) / 255.0f, float(defaultColorHairGDark) / 255.0f, float(defaultColorHairBDark) / 255.0f, 255.0f / 255.0f); + + // We never want to use the name "Mario" when saving/loading a CC, as it will cause file issues. + if (cc_name == "Mario") { + strcpy(bufname, "Sample"); + } else { + strcpy(bufname, cc_name.c_str()); + } + } + + ImGui::End(); + ImGui::PopStyleColor(); + } + if (configImGui.s_cceditor && show_menu_bar) { + ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0)); + ImGui::Begin("CC Editor", NULL, ImGuiWindowFlags_None); + + ImGui::Text("Shirt/Cap"); + ImGui::ColorEdit4("Hat Main", (float*)&uiHatColor, ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_NoLabel); + ImGui::ColorEdit4("Hat Shade", (float*)&uiHatShadeColor, ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_NoLabel); + ImGui::Text("Overalls"); + ImGui::ColorEdit4("Overalls Main", (float*)&uiOverallsColor, ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_NoLabel); + ImGui::ColorEdit4("Overalls Shade", (float*)&uiOverallsShadeColor, ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_NoLabel); + ImGui::Text("Gloves"); + ImGui::ColorEdit4("Gloves Main", (float*)&uiGlovesColor, ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_NoLabel); + ImGui::ColorEdit4("Gloves Shade", (float*)&uiGlovesShadeColor, ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_NoLabel); + ImGui::Text("Shoes"); + ImGui::ColorEdit4("Shoes Main", (float*)&uiShoesColor, ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_NoLabel); + ImGui::ColorEdit4("Shoes Shade", (float*)&uiShoesShadeColor, ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_NoLabel); + ImGui::Text("Skin"); + ImGui::ColorEdit4("Skin Main", (float*)&uiSkinColor, ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_NoLabel); + ImGui::ColorEdit4("Skin Shade", (float*)&uiSkinShadeColor, ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_NoLabel); + ImGui::Text("Hair"); + ImGui::ColorEdit4("Hair Main", (float*)&uiHairColor, ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_NoLabel); + ImGui::ColorEdit4("Hair Shade", (float*)&uiHairShadeColor, ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_NoLabel); + + ImGui::Dummy(ImVec2(0, 5)); + + if (ImGui::Button("Load")) { + apply_cc_from_editor(); + } + + ImGui::Dummy(ImVec2(0, 5)); + + ImGui::InputText(".gs", bufname, IM_ARRAYSIZE(bufname)); + if (ImGui::Button("Save")) { + apply_cc_from_editor(); + + std::string cc_name = bufname; + // We don't want to save a CC named "Mario", as it may cause file issues. + if (cc_name != "Mario") { + save_cc_file(cc_name); + } else { + strcpy(bufname, "Sample"); + save_cc_file("Sample"); + } + + load_cc_directory(); + } + + ImGui::End(); + ImGui::PopStyleColor(); + } + + //ImGui::ShowDemoWindow(); + + if (configImGui.s_options && show_menu_bar) { + ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0)); + ImGui::Begin("Settings", NULL, ImGuiWindowFlags_None); + + if (ImGui::CollapsingHeader("Graphics")) { + if (ImGui::Button("Toggle Fullscreen")) { + configWindow.fullscreen = !configWindow.fullscreen; + configWindow.settings_changed = true; + } + if (!configWindow.fullscreen) { + if (ImGui::Button("Reset Window Size")) { + configWindow.w = 1280; + configWindow.h = 768; // 720 + 48 for the top bar + SDL_SetWindowSize(window, 1280, 768); + } + } + ImGui::Checkbox("VSync", &configWindow.vsync); + ImGui::Text("Graphics Quality"); + const char* lod_modes[] = { "Auto", "Low", "High" }; + ImGui::Combo("###lod_modes", (int*)&configLODMode, lod_modes, IM_ARRAYSIZE(lod_modes)); + ImGui::Text("Texture Filtering"); + const char* texture_filters[] = { "Nearest", "Linear", "Three-point" }; + ImGui::Combo("###texture_filters", (int*)&configFiltering, texture_filters, IM_ARRAYSIZE(texture_filters)); + } + if (ImGui::CollapsingHeader("Audio")) { + ImGui::Text("Volume"); + ImGui::SliderInt("Master", (int*)&configMasterVolume, 0, MAX_VOLUME); + ImGui::SliderInt("SFX", (int*)&configSfxVolume, 0, MAX_VOLUME); + ImGui::SliderInt("Music", (int*)&configMusicVolume, 0, MAX_VOLUME); + ImGui::SliderInt("Environment", (int*)&configEnvVolume, 0, MAX_VOLUME); + } + if (ImGui::CollapsingHeader("Gameplay")) { + ImGui::Text("Rumble Strength"); + ImGui::SliderInt("###rumble_strength", (int*)&configRumbleStrength, 0, 50); + ImGui::Checkbox("Skip Intro", &configSkipIntro); +#ifdef DISCORDRPC + ImGui::Checkbox("Discord Activity Status", &configDiscordRPC); +#endif + } + + ImGui::End(); + ImGui::PopStyleColor(); + } + + if(configImGui.texture_debug && show_menu_bar) { ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0)); ImGui::Begin("Loaded textures", NULL, ImGuiWindowFlags_None); diff --git a/src/moon/moon64.cpp b/src/moon/moon64.cpp index 19cabe2a..3edca85f 100644 --- a/src/moon/moon64.cpp +++ b/src/moon/moon64.cpp @@ -8,6 +8,7 @@ #include "moon/utils/moon-env.h" #include "moon/mod-engine/engine.h" #include "moon/mod-engine/test.h" +#include "moon/saturn/saturn.h" #include "moon/io/moon-io.h" #include "moon/imgui/imgui_impl.h" @@ -28,6 +29,7 @@ void moon_setup(char *state){ MoonInternal::setupImGuiModule(string(state)); // MoonRenderer::setupSkyboxRenderer(string(state)); // MoonInternal::setupSoundModule(string(state)); + MoonInternal::setupSaturnModule(string(state)); } /* diff --git a/src/moon/saturn/saturn.cpp b/src/moon/saturn/saturn.cpp new file mode 100644 index 00000000..284c111c --- /dev/null +++ b/src/moon/saturn/saturn.cpp @@ -0,0 +1,130 @@ +#include "saturn.h" +#include "moon/mod-engine/hooks/hook.h" + +#include "moon/utils/moon-env.h" +#include "moon/fs/moonfs.h" +#include "pc/configfile.h" + +#include "saturn_colors.h" + +#include + +#include +#include +#include +using namespace std; +#include +#include +#include +namespace fs = std::filesystem; + +extern "C" { +#include "game/camera.h" +#include "game/level_update.h" +#include "game/mario.h" +#include "sm64.h" +} + +bool camera_frozen; +bool enable_head_rotations; +bool enable_shadows; +bool enable_dust_particles; + +bool show_menu_bar; + +float camera_speed = 0.0f; + +namespace MoonInternal { + + // Machinima + + void freeze_camera() { + camera_frozen = !camera_frozen; + //camVelSpeed = 1.0f; + } + void cycle_eye_state(int cycle) { + current_eye_state += cycle; + } + + // Setup Module + + void setupSaturnModule(string status){ + if(status == "PreStartup"){ + + Moon::registerHookListener({.hookName = WINDOW_API_INIT, .callback = [&](HookCall call){ + camera_frozen = false; + enable_shadows = true; + current_eye_state = 0; + + show_menu_bar = false; + + MoonInternal::load_cc_directory(); + }}); + + Moon::registerHookListener({.hookName = WINDOW_API_HANDLE_EVENTS, .callback = [&](HookCall call){ + SDL_Event* ev = (SDL_Event*) call.baseArgs["event"]; + switch (ev->type){ + case SDL_KEYDOWN: + if(ev->key.keysym.sym == SDLK_f){ + freeze_camera(); + } + if(ev->key.keysym.sym == SDLK_x){ + cycle_eye_state(1); + } + if(ev->key.keysym.sym == SDLK_z){ + cycle_eye_state(-1); + } + if(ev->key.keysym.sym == SDLK_F1){ + show_menu_bar = !show_menu_bar; + } + case SDL_CONTROLLERBUTTONDOWN: + if (ev->cbutton.button == SDL_CONTROLLER_BUTTON_DPAD_UP) { + freeze_camera(); + } + if (ev->cbutton.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) { + cycle_eye_state(1); + } + if (ev->cbutton.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) { + cycle_eye_state(-1); + } + if(ev->cbutton.button == SDL_CONTROLLER_BUTTON_BACK){ + show_menu_bar = !show_menu_bar; + } + break; + } + }}); + + Moon::registerHookListener({.hookName = GFX_PRE_START_FRAME, .callback = [&](HookCall call){ + // Machinima Camera + + if (camera_frozen == true) { + if (set_cam_angle(0) != CAM_ANGLE_MARIO) { + gLakituState.focVSpeed = camera_speed; + gLakituState.focHSpeed = camera_speed; + } + gLakituState.posVSpeed = camera_speed; + gLakituState.posHSpeed = camera_speed; + gCamera->nextYaw = calculate_yaw(gLakituState.focus, gLakituState.pos); + gCamera->yaw = gCamera->nextYaw; + gCameraMovementFlags &= ~CAM_MOVE_FIX_IN_PLACE; + } + + // Body States + + if (current_cap_state >= 3) { + current_cap_state = 0; + } + + if (current_eye_state >= 9) { + current_eye_state = 0; + } else if (current_eye_state <= -1) { + current_eye_state = 8; + } + + if (current_hand_state >= 6) { + current_hand_state = 0; + } + }}); + } + } +} \ No newline at end of file diff --git a/src/moon/saturn/saturn.h b/src/moon/saturn/saturn.h new file mode 100644 index 00000000..4574a286 --- /dev/null +++ b/src/moon/saturn/saturn.h @@ -0,0 +1,19 @@ +#ifndef MoonSaturnEngine +#define MoonSaturnEngine + +#include +#include + +namespace MoonInternal { + void setupSaturnModule(std::string status); + void freeze_camera(); +} + +extern bool camera_frozen; +#include "saturn_types.h" + +extern bool show_menu_bar; + +extern float camera_speed; + +#endif \ No newline at end of file diff --git a/src/moon/saturn/saturn_colors.cpp b/src/moon/saturn/saturn_colors.cpp new file mode 100644 index 00000000..f9f453b4 --- /dev/null +++ b/src/moon/saturn/saturn_colors.cpp @@ -0,0 +1,343 @@ +#include "saturn_colors.h" +#include "saturn.h" +#include "moon/mod-engine/hooks/hook.h" + +#include "moon/utils/moon-env.h" +#include "moon/fs/moonfs.h" +#include "pc/configfile.h" +#include "moon/imgui/imgui_impl.h" +#include "moon/libs/imgui/imgui.h" +#include "moon/libs/imgui/imgui_internal.h" +#include "moon/libs/imgui/imgui_impl_sdl.h" + +#include + +#include +#include +#include +using namespace std; +#include +#include +#include +namespace fs = std::filesystem; + +extern "C" { +#include "game/camera.h" +#include "game/level_update.h" +#include "sm64.h" +} + +unsigned int defaultColorHatRLight = 255; +unsigned int defaultColorHatRDark = 127; +unsigned int defaultColorHatGLight = 0; +unsigned int defaultColorHatGDark = 0; +unsigned int defaultColorHatBLight = 0; +unsigned int defaultColorHatBDark = 0; + +unsigned int defaultColorOverallsRLight = 0; +unsigned int defaultColorOverallsRDark = 0; +unsigned int defaultColorOverallsGLight = 0; +unsigned int defaultColorOverallsGDark = 0; +unsigned int defaultColorOverallsBLight = 255; +unsigned int defaultColorOverallsBDark = 127; + +unsigned int defaultColorGlovesRLight = 255; +unsigned int defaultColorGlovesRDark = 127; +unsigned int defaultColorGlovesGLight = 255; +unsigned int defaultColorGlovesGDark = 127; +unsigned int defaultColorGlovesBLight = 255; +unsigned int defaultColorGlovesBDark = 127; + +unsigned int defaultColorShoesRLight = 114; +unsigned int defaultColorShoesRDark = 57; +unsigned int defaultColorShoesGLight = 28; +unsigned int defaultColorShoesGDark = 14; +unsigned int defaultColorShoesBLight = 14; +unsigned int defaultColorShoesBDark = 7; + +unsigned int defaultColorSkinRLight = 254; +unsigned int defaultColorSkinRDark = 127; +unsigned int defaultColorSkinGLight = 193; +unsigned int defaultColorSkinGDark = 96; +unsigned int defaultColorSkinBLight = 121; +unsigned int defaultColorSkinBDark = 60; + +unsigned int defaultColorHairRLight = 115; +unsigned int defaultColorHairRDark = 57; +unsigned int defaultColorHairGLight = 6; +unsigned int defaultColorHairGDark = 3; +unsigned int defaultColorHairBLight = 0; +unsigned int defaultColorHairBDark = 0; + +// Color Codes + +namespace MoonInternal { + + std::vector cc_array; + string colorCodeDir; + + void load_cc_directory() { + cc_array.clear(); + cc_array.push_back("Mario.gs"); + + string cwd = MoonInternal::getEnvironmentVar("MOON_CWD"); +#ifdef __MINGW32__ + // Windows moment + colorCodeDir = cwd.substr(0, cwd.find_last_of("/\\")) + "\\machinima\\colorcodes\\"; +#else + colorCodeDir = cwd.substr(0, cwd.find_last_of("/\\")) + "/machinima/colorcodes/"; +#endif + + for (const auto & entry : fs::directory_iterator(colorCodeDir)) + cc_array.push_back(entry.path().filename().u8string()); + + //std::cout << cc_array[0] << std::endl; + } + + void reset_cc_colors() { + defaultColorHatRLight = 255; + defaultColorHatRDark = 127; + defaultColorHatGLight = 0; + defaultColorHatGDark = 0; + defaultColorHatBLight = 0; + defaultColorHatBDark = 0; + + defaultColorOverallsRLight = 0; + defaultColorOverallsRDark = 0; + defaultColorOverallsGLight = 0; + defaultColorOverallsGDark = 0; + defaultColorOverallsBLight = 255; + defaultColorOverallsBDark = 127; + + defaultColorGlovesRLight = 255; + defaultColorGlovesRDark = 127; + defaultColorGlovesGLight = 255; + defaultColorGlovesGDark = 127; + defaultColorGlovesBLight = 255; + defaultColorGlovesBDark = 127; + + defaultColorShoesRLight = 114; + defaultColorShoesRDark = 57; + defaultColorShoesGLight = 28; + defaultColorShoesGDark = 14; + defaultColorShoesBLight = 14; + defaultColorShoesBDark = 7; + + defaultColorSkinRLight = 254; + defaultColorSkinRDark = 127; + defaultColorSkinGLight = 193; + defaultColorSkinGDark = 96; + defaultColorSkinBLight = 121; + defaultColorSkinBDark = 60; + + defaultColorHairRLight = 115; + defaultColorHairRDark = 57; + defaultColorHairGLight = 6; + defaultColorHairGDark = 3; + defaultColorHairBLight = 0; + defaultColorHairBDark = 0; + } + + void load_cc_file(string cc_filename) { + if (cc_filename == "Mario.gs") { + reset_cc_colors(); + return; + } + + std::ifstream file(colorCodeDir + cc_filename, std::ios::in | std::ios::binary); + + // If the color code was previously deleted, reload the list and cancel. + if (!file.good()) { + load_cc_directory(); + return; + } + + const std::size_t& size = std::filesystem::file_size(colorCodeDir + cc_filename); + std::string content(size, '\0'); + file.read(content.data(), size); + + file.close(); + + std::istringstream f(content); + std::string line; + + while (std::getline(f, line)) { + std::string address = line.substr(2, 6); + int value1 = std::stoi(line.substr(9, 2), 0, 16); + int value2 = std::stoi(line.substr(11, 2), 0, 16); + + // Hat + if (address == "07EC40") { + defaultColorHatRLight = value1; + defaultColorHatGLight = value2; + } + if (address == "07EC42") { + defaultColorHatBLight = value1; + } + if (address == "07EC38") { + defaultColorHatRDark = value1; + defaultColorHatGDark = value2; + } + if (address == "07EC3A") { + defaultColorHatBDark = value1; + } + + // Overalls + if (address == "07EC28") { + defaultColorOverallsRLight = value1; + defaultColorOverallsGLight = value2; + } + if (address == "07EC2A") { + defaultColorOverallsBLight = value1; + } + if (address == "07EC20") { + defaultColorOverallsRDark = value1; + defaultColorOverallsGDark = value2; + } + if (address == "07EC22") { + defaultColorOverallsBDark = value1; + } + + // Gloves + if (address == "07EC58") { + defaultColorGlovesRLight = value1; + defaultColorGlovesGLight = value2; + } + if (address == "07EC5A") { + defaultColorGlovesBLight = value1; + } + if (address == "07EC50") { + defaultColorGlovesRDark = value1; + defaultColorGlovesGDark = value2; + } + if (address == "07EC52") { + defaultColorGlovesBDark = value1; + } + + // Shoes + if (address == "07EC70") { + defaultColorShoesRLight = value1; + defaultColorShoesGLight = value2; + } + if (address == "07EC72") { + defaultColorShoesBLight = value1; + } + if (address == "07EC68") { + defaultColorShoesRDark = value1; + defaultColorShoesGDark = value2; + } + if (address == "07EC6A") { + defaultColorShoesBDark = value1; + } + + // Skin + if (address == "07EC88") { + defaultColorSkinRLight = value1; + defaultColorSkinGLight = value2; + } + if (address == "07EC8A") { + defaultColorSkinBLight = value1; + } + if (address == "07EC80") { + defaultColorSkinRDark = value1; + defaultColorSkinGDark = value2; + } + if (address == "07EC82") { + defaultColorSkinBDark = value1; + } + + // Hair + if (address == "07ECA0") { + defaultColorHairRLight = value1; + defaultColorHairGLight = value2; + } + if (address == "07ECA2") { + defaultColorHairBLight = value1; + } + if (address == "07EC98") { + defaultColorHairRDark = value1; + defaultColorHairGDark = value2; + } + if (address == "07EC9A") { + defaultColorHairBDark = value1; + } + + //std::cout << address << std::endl; + } + } + + void save_cc_file(std::string name) { + std::string gameshark; + + char col1char[64]; + ImFormatString(col1char, IM_ARRAYSIZE(col1char), "%02X%02X%02X", ImClamp((int)defaultColorHatRLight, 0, 255), ImClamp((int)defaultColorHatGLight, 0, 255), ImClamp((int)defaultColorHatBLight, 0, 255)); + std::string col1 = col1char; + char col2char[64]; + ImFormatString(col2char, IM_ARRAYSIZE(col2char), "%02X%02X%02X", ImClamp((int)defaultColorHatRDark, 0, 255), ImClamp((int)defaultColorHatGDark, 0, 255), ImClamp((int)defaultColorHatBDark, 0, 255)); + std::string col2 = col2char; + char col3char[64]; + ImFormatString(col3char, IM_ARRAYSIZE(col3char), "%02X%02X%02X", ImClamp((int)defaultColorOverallsRLight, 0, 255), ImClamp((int)defaultColorOverallsGLight, 0, 255), ImClamp((int)defaultColorOverallsBLight, 0, 255)); + std::string col3 = col3char; + char col4char[64]; + ImFormatString(col4char, IM_ARRAYSIZE(col4char), "%02X%02X%02X", ImClamp((int)defaultColorOverallsRDark, 0, 255), ImClamp((int)defaultColorOverallsGDark, 0, 255), ImClamp((int)defaultColorOverallsBDark, 0, 255)); + std::string col4 = col4char; + char col5char[64]; + ImFormatString(col5char, IM_ARRAYSIZE(col5char), "%02X%02X%02X", ImClamp((int)defaultColorGlovesRLight, 0, 255), ImClamp((int)defaultColorGlovesGLight, 0, 255), ImClamp((int)defaultColorGlovesBLight, 0, 255)); + std::string col5 = col5char; + char col6char[64]; + ImFormatString(col6char, IM_ARRAYSIZE(col6char), "%02X%02X%02X", ImClamp((int)defaultColorGlovesRDark, 0, 255), ImClamp((int)defaultColorGlovesGDark, 0, 255), ImClamp((int)defaultColorGlovesBDark, 0, 255)); + std::string col6 = col6char; + char col7char[64]; + ImFormatString(col7char, IM_ARRAYSIZE(col7char), "%02X%02X%02X", ImClamp((int)defaultColorShoesRLight, 0, 255), ImClamp((int)defaultColorShoesGLight, 0, 255), ImClamp((int)defaultColorShoesBLight, 0, 255)); + std::string col7 = col7char; + char col8char[64]; + ImFormatString(col8char, IM_ARRAYSIZE(col8char), "%02X%02X%02X", ImClamp((int)defaultColorShoesRDark, 0, 255), ImClamp((int)defaultColorShoesGDark, 0, 255), ImClamp((int)defaultColorShoesBDark, 0, 255)); + std::string col8 = col8char; + char col9char[64]; + ImFormatString(col9char, IM_ARRAYSIZE(col9char), "%02X%02X%02X", ImClamp((int)defaultColorSkinRLight, 0, 255), ImClamp((int)defaultColorSkinGLight, 0, 255), ImClamp((int)defaultColorSkinBLight, 0, 255)); + std::string col9 = col9char; + char col10char[64]; + ImFormatString(col10char, IM_ARRAYSIZE(col10char), "%02X%02X%02X", ImClamp((int)defaultColorSkinRDark, 0, 255), ImClamp((int)defaultColorSkinGDark, 0, 255), ImClamp((int)defaultColorSkinBDark, 0, 255)); + std::string col10 = col10char; + char col11char[64]; + ImFormatString(col11char, IM_ARRAYSIZE(col11char), "%02X%02X%02X", ImClamp((int)defaultColorHairRLight, 0, 255), ImClamp((int)defaultColorHairGLight, 0, 255), ImClamp((int)defaultColorHairBLight, 0, 255)); + std::string col11 = col11char; + char col12char[64]; + ImFormatString(col12char, IM_ARRAYSIZE(col12char), "%02X%02X%02X", ImClamp((int)defaultColorHairRDark, 0, 255), ImClamp((int)defaultColorHairGDark, 0, 255), ImClamp((int)defaultColorHairBDark, 0, 255)); + std::string col12 = col12char; + + gameshark += "8107EC40 " + col1.substr(0, 2) + col1.substr(2, 2) + "\n"; + gameshark += "8107EC42 " + col1.substr(4, 2) + "00\n"; + gameshark += "8107EC38 " + col2.substr(0, 2) + col2.substr(2, 2) + "\n"; + gameshark += "8107EC3A " + col2.substr(4, 2) + "00\n"; + gameshark += "8107EC28 " + col3.substr(0, 2) + col3.substr(2, 2) + "\n"; + gameshark += "8107EC2A " + col3.substr(4, 2) + "00\n"; + gameshark += "8107EC20 " + col4.substr(0, 2) + col4.substr(2, 2) + "\n"; + gameshark += "8107EC22 " + col4.substr(4, 2) + "00\n"; + gameshark += "8107EC58 " + col5.substr(0, 2) + col5.substr(2, 2) + "\n"; + gameshark += "8107EC5A " + col5.substr(4, 2) + "00\n"; + gameshark += "8107EC50 " + col6.substr(0, 2) + col6.substr(2, 2) + "\n"; + gameshark += "8107EC52 " + col6.substr(4, 2) + "00\n"; + gameshark += "8107EC70 " + col7.substr(0, 2) + col7.substr(2, 2) + "\n"; + gameshark += "8107EC72 " + col7.substr(4, 2) + "00\n"; + gameshark += "8107EC68 " + col8.substr(0, 2) + col8.substr(2, 2) + "\n"; + gameshark += "8107EC6A " + col8.substr(4, 2) + "00\n"; + gameshark += "8107EC88 " + col9.substr(0, 2) + col9.substr(2, 2) + "\n"; + gameshark += "8107EC8A " + col9.substr(4, 2) + "00\n"; + gameshark += "8107EC80 " + col10.substr(0, 2) + col10.substr(2, 2) + "\n"; + gameshark += "8107EC82 " + col10.substr(4, 2) + "00\n"; + gameshark += "8107ECA0 " + col11.substr(0, 2) + col11.substr(2, 2) + "\n"; + gameshark += "8107ECA2 " + col11.substr(4, 2) + "00\n"; + gameshark += "8107EC98 " + col12.substr(0, 2) + col12.substr(2, 2) + "\n"; + gameshark += "8107EC9A " + col12.substr(4, 2) + "00"; + + //std::cout << gameshark << std::endl; + +#ifdef __MINGW32__ + std::ofstream file("machinima\\colorcodes\\" + name + ".gs"); +#else + std::ofstream file("machinima/colorcodes/" + name + ".gs"); +#endif + file << gameshark; + } +} \ No newline at end of file diff --git a/src/moon/saturn/saturn_colors.h b/src/moon/saturn/saturn_colors.h new file mode 100644 index 00000000..87f42d3a --- /dev/null +++ b/src/moon/saturn/saturn_colors.h @@ -0,0 +1,14 @@ +#ifndef SaturnColors +#define SaturnColors + +#include +#include + +namespace MoonInternal { + extern std::vector cc_array; + void load_cc_directory(void); + void load_cc_file(std::string cc_path); + void save_cc_file(std::string name); +} + +#endif \ No newline at end of file diff --git a/src/moon/saturn/saturn_types.h b/src/moon/saturn/saturn_types.h new file mode 100644 index 00000000..5606a3f9 --- /dev/null +++ b/src/moon/saturn/saturn_types.h @@ -0,0 +1,54 @@ +#ifndef MoonSaturnTypes +#define MoonSaturnTypes + +#include + +extern bool enable_head_rotations; +extern bool enable_shadows; +extern bool enable_dust_particles; + +// Color Codes + +extern unsigned int defaultColorHatRLight; +extern unsigned int defaultColorHatRDark; +extern unsigned int defaultColorHatGLight; +extern unsigned int defaultColorHatGDark; +extern unsigned int defaultColorHatBLight; +extern unsigned int defaultColorHatBDark; + +extern unsigned int defaultColorOverallsRLight; +extern unsigned int defaultColorOverallsRDark; +extern unsigned int defaultColorOverallsGLight; +extern unsigned int defaultColorOverallsGDark; +extern unsigned int defaultColorOverallsBLight; +extern unsigned int defaultColorOverallsBDark; + +extern unsigned int defaultColorGlovesRLight; +extern unsigned int defaultColorGlovesRDark; +extern unsigned int defaultColorGlovesGLight; +extern unsigned int defaultColorGlovesGDark; +extern unsigned int defaultColorGlovesBLight; +extern unsigned int defaultColorGlovesBDark; + +extern unsigned int defaultColorShoesRLight; +extern unsigned int defaultColorShoesRDark; +extern unsigned int defaultColorShoesGLight; +extern unsigned int defaultColorShoesGDark; +extern unsigned int defaultColorShoesBLight; +extern unsigned int defaultColorShoesBDark; + +extern unsigned int defaultColorSkinRLight; +extern unsigned int defaultColorSkinRDark; +extern unsigned int defaultColorSkinGLight; +extern unsigned int defaultColorSkinGDark; +extern unsigned int defaultColorSkinBLight; +extern unsigned int defaultColorSkinBDark; + +extern unsigned int defaultColorHairRLight; +extern unsigned int defaultColorHairRDark; +extern unsigned int defaultColorHairGLight; +extern unsigned int defaultColorHairGDark; +extern unsigned int defaultColorHairBLight; +extern unsigned int defaultColorHairBDark; + +#endif \ No newline at end of file diff --git a/src/moon/ui/moon-ui-manager.cpp b/src/moon/ui/moon-ui-manager.cpp index a29bf665..43d86f7d 100644 --- a/src/moon/ui/moon-ui-manager.cpp +++ b/src/moon/ui/moon-ui-manager.cpp @@ -54,11 +54,13 @@ void MoonChangeUI(int index){ } void MoonHandleToggle(){ + /* if(gPlayer1Controller->buttonPressed & toggle){ currentScreen = 0; isOpen = !isOpen; MoonUpdateStatus(); } + */ } void MoonUpdateStatus() { diff --git a/src/moon/ui/screens/options/main-view.cpp b/src/moon/ui/screens/options/main-view.cpp index 234b1437..9729cdfb 100644 --- a/src/moon/ui/screens/options/main-view.cpp +++ b/src/moon/ui/screens/options/main-view.cpp @@ -153,7 +153,7 @@ extern "C" { basePath.append(stickAnim ? "stick-down.rgba16" : "stick-up.rgba16"); MoonDrawButton(5, GetScreenHeight() - 24, "Move", basePath, 16, 0, false, false); - MoonDrawButton(7, GetScreenHeight() - 24, "Open settings", "textures/moon/controller/r-btn.rgba16", 10, 4, true, false); + //MoonDrawButton(7, GetScreenHeight() - 24, "Open settings", "textures/moon/controller/r-btn.rgba16", 10, 4, true, false); } } diff --git a/src/pc/configfile.c b/src/pc/configfile.c index 1c2578e6..0b34173b 100644 --- a/src/pc/configfile.c +++ b/src/pc/configfile.c @@ -58,6 +58,10 @@ ConfigWindow configWindow = { ImGuiConfig configImGui = { .moon64 = false, .texture_debug = false, + .s_toggles = false, + .s_machinima = false, + .s_cceditor = false, + .s_options = false, .n64Mode = false }; @@ -71,7 +75,7 @@ bool configPrecacheRes = true; unsigned int configFiltering = 1; // 0=force nearest, 1=linear, (TODO) 2=three-point unsigned int configMasterVolume = MAX_VOLUME; // 0 - MAX_VOLUME -unsigned int configMusicVolume = MAX_VOLUME; +unsigned int configMusicVolume = 0; unsigned int configSfxVolume = MAX_VOLUME; unsigned int configEnvVolume = MAX_VOLUME; @@ -105,8 +109,8 @@ bool configEnableCamera = false; bool configCameraAnalog = true; bool configCameraMouse = false; #endif -bool configSkipIntro = 0; -bool configHUD = true; +bool configSkipIntro = 1; +bool configHUD = false; #ifdef DISCORDRPC bool configDiscordRPC = true; #endif @@ -117,7 +121,7 @@ bool configDiscordRPC = true; ################################ */ -unsigned int configLODMode = 0; +unsigned int configLODMode = 2; static const struct ConfigOption options[] = { {.name = "fullscreen", .type = CONFIG_TYPE_BOOL, .boolValue = &configWindow.fullscreen}, @@ -177,6 +181,10 @@ static const struct ConfigOption options[] = { {.name = "moon64_win", .type = CONFIG_TYPE_BOOL, .boolValue = &configImGui.moon64}, {.name = "texture_debug_win", .type = CONFIG_TYPE_BOOL, .boolValue = &configImGui.texture_debug}, + {.name = "s_toggles_win", .type = CONFIG_TYPE_BOOL, .boolValue = &configImGui.s_toggles}, + {.name = "s_machinima", .type = CONFIG_TYPE_BOOL, .boolValue = &configImGui.s_machinima}, + {.name = "s_cceditor_win", .type = CONFIG_TYPE_BOOL, .boolValue = &configImGui.s_cceditor}, + {.name = "s_options_win", .type = CONFIG_TYPE_BOOL, .boolValue = &configImGui.s_options}, {.name = "n64Mode", .type = CONFIG_TYPE_BOOL, .boolValue = &configImGui.n64Mode} }; diff --git a/src/pc/configfile.h b/src/pc/configfile.h index 65c4f001..952968d3 100644 --- a/src/pc/configfile.h +++ b/src/pc/configfile.h @@ -23,6 +23,10 @@ typedef struct { typedef struct { bool moon64; + bool s_toggles; + bool s_machinima; + bool s_cceditor; + bool s_options; bool texture_debug; bool n64Mode; } ImGuiConfig; diff --git a/src/pc/discord/discordrpc.cpp b/src/pc/discord/discordrpc.cpp index f6d248e7..d0c9cfff 100644 --- a/src/pc/discord/discordrpc.cpp +++ b/src/pc/discord/discordrpc.cpp @@ -42,7 +42,7 @@ extern "C" { #endif #define DISCORDLIB DISCORDLIBFILE DISCORDLIBEXT -#define DISCORD_APP_ID "856717153431453716" +#define DISCORD_APP_ID "895788060518793226" #define DISCORD_UPDATE_RATE 3 using namespace std; @@ -228,35 +228,22 @@ string getLevelLogo(){ } void set_logo(void) { - discordRichPresence.largeImageKey = sys_strdup(getLevelLogo().data()); + discordRichPresence.largeImageKey = "saturn-logo-star-bg"; + discordRichPresence.largeImageText = "https://github.com/Llennpie/Saturn"; } void DiscordReloadPresence() { reloadRPC = true; } -void set_health(){ - if(gCurrCourseNum == 0) return; - if(lastHealth != gHudDisplay.wedges){ - lastHealth = gHudDisplay.wedges; - string new_health_icon = "health-"+to_string(lastHealth); - string new_health_text = to_string(gHudDisplay.lives) + " Lives"; - discordRichPresence.smallImageKey = sys_strdup(new_health_icon.data()); - discordRichPresence.smallImageText = sys_strdup(new_health_text.data()); - } -} - -void set_image_key(){ - if(gCurrCourseNum == 0) return; - int size = entries[gCurrSaveFileNum - 1].size(); - if(lastAchievements != size || lastStarAmount != gHudDisplay.stars){ - lastAchievements = size; - lastStarAmount = gHudDisplay.stars; - - string new_text = to_string(lastStarAmount) + "/120 Stars - " + to_string(lastAchievements) + "/" + to_string(registeredAchievements.size()) + " Achievements"; - - discordRichPresence.largeImageText = sys_strdup(new_text.data()); - } +void set_platform(){ +#ifdef __MINGW32__ + discordRichPresence.smallImageKey = "windows"; + discordRichPresence.smallImageText = "Windows"; +#else + discordRichPresence.smallImageKey = "linux"; + discordRichPresence.smallImageText = "Linux"; +#endif } void DiscordUpdatePresence(){ @@ -268,8 +255,7 @@ void DiscordUpdatePresence(){ set_state(); set_details(); set_logo(); - set_health(); - set_image_key(); + set_platform(); discordUpdatePresence(&discordRichPresence); reloadRPC = false; } @@ -306,8 +292,8 @@ void discord_init(void) { discordUpdatePresence = (Discord_UpdatePresence) dlsym(handle, "Discord_UpdatePresence"); init_discord(); - discordRichPresence.details = stage; - discordRichPresence.state = act; + discordRichPresence.details = "Making Machinima"; + discordRichPresence.state = stage; lastUpdatedTime = 0; } diff --git a/src/pc/gfx/gfx_pc.c b/src/pc/gfx/gfx_pc.c index a34d77c6..ff72b40a 100644 --- a/src/pc/gfx/gfx_pc.c +++ b/src/pc/gfx/gfx_pc.c @@ -24,6 +24,7 @@ #include "../fs/fs.h" #include "moon/moon64.h" #include "moon/mod-engine/hooks/hook.h" +#include "moon/saturn/saturn_types.h" #define SUPPORT_CHECK(x) assert(x) @@ -447,6 +448,48 @@ static void gfx_sp_vertex(size_t n_vertices, size_t dest_index, const Vtx *verti int g = rsp.current_lights[rsp.current_num_lights - 1].col[1]; int b = rsp.current_lights[rsp.current_num_lights - 1].col[2]; + // sm64plus saves the day... + + // Detect if these are one of Mario's colors + bool mario_hat = (r == 0x7f && g == 0x00 && b == 0x00); + bool mario_overalls = (r == 0x00 && g == 0x00 && b == 0x7f); + bool mario_gloves = (r == 0x00 && g == 0x7f && b == 0x00); + bool mario_shoes = (r == 0x39 && g == 0x0e && b == 0x07); + bool mario_skin = (r == 0x7f && g == 0x60 && b == 0x3c); + bool mario_hair = (r == 0x39 && g == 0x03 && b == 0x00); + + // Override them lazily + if (mario_hat) { + r = defaultColorHatRDark; + g = defaultColorHatGDark; + b = defaultColorHatBDark; + } + if (mario_overalls) { + r = defaultColorOverallsRDark; + g = defaultColorOverallsGDark; + b = defaultColorOverallsBDark; + } + if (mario_gloves) { + r = defaultColorGlovesRDark; + g = defaultColorGlovesGDark; + b = defaultColorGlovesBDark; + } + if (mario_shoes) { + r = defaultColorShoesRDark; + g = defaultColorShoesGDark; + b = defaultColorShoesBDark; + } + if (mario_skin) { + r = defaultColorSkinRDark; + g = defaultColorSkinGDark; + b = defaultColorSkinBDark; + } + if (mario_hair) { + r = defaultColorHairRDark; + g = defaultColorHairGDark; + b = defaultColorHairBDark; + } + for (int i = 0; i < rsp.current_num_lights - 1; i++) { float intensity = 0; intensity += vn->n[0] * rsp.current_lights_coeffs[i][0]; @@ -454,9 +497,47 @@ static void gfx_sp_vertex(size_t n_vertices, size_t dest_index, const Vtx *verti intensity += vn->n[2] * rsp.current_lights_coeffs[i][2]; intensity /= 127.0f; if (intensity > 0.0f) { - r += intensity * rsp.current_lights[i].col[0]; - g += intensity * rsp.current_lights[i].col[1]; - b += intensity * rsp.current_lights[i].col[2]; + // Light colors + int lightr = rsp.current_lights[i].col[0]; + int lightg = rsp.current_lights[i].col[1]; + int lightb = rsp.current_lights[i].col[2]; + + // Override these too + if (mario_hat) { + r += intensity * defaultColorHatRLight; + g += intensity * defaultColorHatGLight; + b += intensity * defaultColorHatBLight; + } + else if (mario_overalls) { + r += intensity * defaultColorOverallsRLight; + g += intensity * defaultColorOverallsGLight; + b += intensity * defaultColorOverallsBLight; + } + else if (mario_gloves) { + r += intensity * defaultColorGlovesRLight; + g += intensity * defaultColorGlovesGLight; + b += intensity * defaultColorGlovesBLight; + } + else if (mario_shoes) { + r += intensity * defaultColorShoesRLight; + g += intensity * defaultColorShoesGLight; + b += intensity * defaultColorShoesBLight; + } + else if (mario_skin) { + r += intensity * defaultColorSkinRLight; + g += intensity * defaultColorSkinGLight; + b += intensity * defaultColorSkinBLight; + } + else if (mario_hair) { + r += intensity * defaultColorHairRLight; + g += intensity * defaultColorHairGLight; + b += intensity * defaultColorHairBLight; + } + else { + r += intensity * lightr; + g += intensity * lightg; + b += intensity * lightb; + } } } diff --git a/src/pc/gfx/gfx_screen_config.h b/src/pc/gfx/gfx_screen_config.h index 5b933f85..02820317 100644 --- a/src/pc/gfx/gfx_screen_config.h +++ b/src/pc/gfx/gfx_screen_config.h @@ -1,7 +1,7 @@ #ifndef GFX_SCREEN_CONFIG_H #define GFX_SCREEN_CONFIG_H -#define DESIRED_SCREEN_WIDTH 640 -#define DESIRED_SCREEN_HEIGHT 480 +#define DESIRED_SCREEN_WIDTH 1280 +#define DESIRED_SCREEN_HEIGHT 768 #endif diff --git a/src/pc/gfx/gfx_sdl2.c b/src/pc/gfx/gfx_sdl2.c index a4c3c138..53ae62d9 100644 --- a/src/pc/gfx/gfx_sdl2.c +++ b/src/pc/gfx/gfx_sdl2.c @@ -62,7 +62,7 @@ static void (*kb_all_keys_up)(void) = NULL; // whether to use timer for frame control static bool use_timer = true; // time between consequtive game frames -static const int frame_time = 1000 / FRAMERATE; +static const int frame_time = 1000 / (2 * FRAMERATE); const SDL_Scancode windows_scancode_table[] = { /* 0 1 2 3 4 5 6 7 */ @@ -149,13 +149,17 @@ int test_vsync(void) { static inline void gfx_sdl_set_vsync(const bool enabled) { #ifdef TARGET_SWITCH - SDL_GL_SetSwapInterval(2); + SDL_GL_SetSwapInterval(1); use_timer = false; #else if (enabled) { // try to detect refresh rate SDL_GL_SetSwapInterval(1); - const int vblanks = test_vsync(); + int vblanks = test_vsync(); + if (vblanks & 1) + vblanks = 0; // not divisible by 60, fuck that + else + vblanks /= 2; if (vblanks) { printf("determined swap interval: %d\n", vblanks); SDL_GL_SetSwapInterval(vblanks); diff --git a/src/pc/pc_main.c b/src/pc/pc_main.c index 9884438d..111e5198 100644 --- a/src/pc/pc_main.c +++ b/src/pc/pc_main.c @@ -86,6 +86,25 @@ void send_display_list(struct SPTask *spTask) { #define SAMPLES_LOW 528 #endif +static inline void patch_interpolations(void) { + extern void mtx_patch_interpolated(void); + extern void patch_screen_transition_interpolated(void); + extern void patch_title_screen_scales(void); + extern void patch_interpolated_dialog(void); + extern void patch_interpolated_hud(void); + extern void patch_interpolated_paintings(void); + extern void patch_interpolated_bubble_particles(void); + extern void patch_interpolated_snow_particles(void); + mtx_patch_interpolated(); + patch_screen_transition_interpolated(); + patch_title_screen_scales(); + patch_interpolated_dialog(); + patch_interpolated_hud(); + patch_interpolated_paintings(); + patch_interpolated_bubble_particles(); + patch_interpolated_snow_particles(); +} + void produce_one_frame(void) { moon_setup("Update"); gfx_start_frame(); @@ -114,6 +133,11 @@ void produce_one_frame(void) { } //printf("Audio samples before submitting: %d\n", audio_api->buffered()); + gfx_start_frame(); + patch_interpolations(); + send_display_list(gGfxSPTask); + gfx_end_frame(); + audio_api->play((u8 *)audio_buffer, 2 * num_audio_samples * 4); gfx_end_frame(); @@ -211,8 +235,7 @@ void main_func(char *argv[]) { # define RAPI_NAME "OpenGL" # endif - char window_title[96] = - "Super Mario 64 - Moon64 (" RAPI_NAME ")"; + char window_title[96] = "Saturn"; gfx_init(wm_api, rendering_api, window_title); wm_api->set_keyboard_callbacks(keyboard_on_key_down, keyboard_on_key_up, keyboard_on_all_keys_up);