diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index b9c8c97..d7f498f 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -9,7 +9,7 @@ on: N64RECOMP_COMMIT: type: string required: false - default: '989a86b36912403cd323de884bf834f2605ea770' + default: 'a13e5cff96686776b0e03baf23923e3c1927b770' DXC_CHECKSUM: type: string required: false diff --git a/CMakeLists.txt b/CMakeLists.txt index 54a4949..1cdda09 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -291,7 +291,7 @@ if (WIN32) ) target_sources(Zelda64Recompiled PRIVATE ${CMAKE_SOURCE_DIR}/icons/app.rc) - target_link_libraries(Zelda64Recompiled PRIVATE SDL2) + target_link_libraries(Zelda64Recompiled PRIVATE SDL2 Winmm.lib) endif() if (APPLE) diff --git a/README.md b/README.md index 0e6f2bd..3de82f7 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ A GPU supporting Direct3D 12.0 (Shader Model 6), Vulkan 1.2, or Metal Argument B * Intel HD 510 (Skylake) * A Mac with Apple Silicon or an Intel 7th Gen CPU with MacOS 13.0+ -On x86-64 PCs, a CPU supporting the AVX instruction set is also required (Intel Core 2000 series or AMD Bulldozer and newer). ARM64 builds will work on any ARM64 CPU. +On x86-64 PCs, a CPU supporting the SSE4.1 instruction set is also required (Intel Core 2 Penryn series or AMD Bulldozer and newer). ARM64 builds will work on any ARM64 CPU. If you have issues with crashes on startup, make sure your graphics drivers are fully up to date. diff --git a/include/zelda_render.h b/include/zelda_render.h index 451c66b..15397f9 100644 --- a/include/zelda_render.h +++ b/include/zelda_render.h @@ -27,7 +27,7 @@ namespace zelda64 { void enable_instant_present() override; void send_dl(const OSTask *task) override; - void update_screen(uint32_t vi_origin) override; + void update_screen() override; void shutdown() override; uint32_t get_display_framerate() const override; float get_resolution_scale() const override; diff --git a/launch.vs.json b/launch.vs.json index bdc4cdc..2cd1199 100644 --- a/launch.vs.json +++ b/launch.vs.json @@ -7,7 +7,8 @@ "project": "CMakeLists.txt", "projectTarget": "Zelda64Recompiled.exe", "name": "Zelda64Recompiled.exe", - "currentDir": "${workspaceRoot}" + "currentDir": "${workspaceRoot}", + "args": ["--show-console"] } ] } \ No newline at end of file diff --git a/lib/N64ModernRuntime b/lib/N64ModernRuntime index c5e268a..df7e820 160000 --- a/lib/N64ModernRuntime +++ b/lib/N64ModernRuntime @@ -1 +1 @@ -Subproject commit c5e268aa0f71cf06a10a001da981dc3e02e7dff0 +Subproject commit df7e820d8c55e4fcb4616c210cbb2c01b25cd48c diff --git a/lib/rt64 b/lib/rt64 index ada6cc6..b552151 160000 --- a/lib/rt64 +++ b/lib/rt64 @@ -1 +1 @@ -Subproject commit ada6cc62c421b142d9d90154765e44348115bd9e +Subproject commit b552151c3498dc45ba06e98f57aaf0fa709cdf9f diff --git a/patches/camera_transform_tagging.c b/patches/camera_transform_tagging.c index b077b28..60f0d00 100644 --- a/patches/camera_transform_tagging.c +++ b/patches/camera_transform_tagging.c @@ -76,6 +76,17 @@ void camera_post_play_update(PlayState* play) { if (force_interpolation) { force_camera_interpolation(); } + // Dedicated section for workarounds where the heuristic fails to detect small camera teleports. + bool force_no_interpolation = false; + + // Music Box House. The camera gets teleported by a very small amount when Link gets the Gibdo mask. + if (play->sceneId == SCENE_MUSICHOUSE && play->csCtx.scriptIndex == 2 && play->csCtx.curFrame == 525 && active_cam->setting == CAM_SET_FREE0) { + force_no_interpolation = true; + } + + if (force_no_interpolation) { + force_camera_skip_interpolation(); + } } } } diff --git a/patches/custom_syms.toml b/patches/custom_syms.toml index 9128278..c04a941 100644 --- a/patches/custom_syms.toml +++ b/patches/custom_syms.toml @@ -14,3 +14,33 @@ symbols = [ { name = "FileSelect_Init_NORELOCATE", vram = 0x80813C98 }, { name = "DayTelop_Init_NORELOCATE", vram = 0x80815820 }, ] + +[[section]] +name = "..ovl_En_Hg" +rom = 0x01034170 +vram = 0x80BCF1D0 +size = 0x10E0 + +symbols = [ + { name = "sPamelasFatherGibdoAnimationInfo", vram = 0x80bd0008 }, +] + +[[section]] +name = "..ovl_En_Hgo" +rom = 0x01035250 +vram = 0x80BD02B0 +size = 0xF30 + +symbols = [ + { name = "sPamelasFatherHumanAnimationInfo", vram = 0x80BD0EA0 }, +] + +[[section]] +name = "..ovl_En_Pamera" +rom = 0x0103D250 +vram = 0x80BD82B0 +size = 0x2780 + +symbols = [ + { name = "sPamelaAnimationInfo", vram = 0x80BDA4B8 }, +] diff --git a/patches/dummy_headers/objects/object_harfgibud/object_harfgibud.h b/patches/dummy_headers/objects/object_harfgibud/object_harfgibud.h new file mode 100644 index 0000000..97e77d1 --- /dev/null +++ b/patches/dummy_headers/objects/object_harfgibud/object_harfgibud.h @@ -0,0 +1,45 @@ +typedef enum PamelasFatherGibdoLimb { + /* 0x00 */ PAMELAS_FATHER_GIBDO_LIMB_NONE, + /* 0x01 */ PAMELAS_FATHER_GIBDO_LIMB_ROOT, + /* 0x02 */ PAMELAS_FATHER_GIBDO_LIMB_ABDOMEN, + /* 0x03 */ PAMELAS_FATHER_GIBDO_LIMB_CHEST, + /* 0x04 */ PAMELAS_FATHER_GIBDO_LIMB_LEFT_UPPER_ARM, + /* 0x05 */ PAMELAS_FATHER_GIBDO_LIMB_LEFT_FOREARM, + /* 0x06 */ PAMELAS_FATHER_GIBDO_LIMB_LEFT_HAND, + /* 0x07 */ PAMELAS_FATHER_GIBDO_LIMB_RIGHT_UPPER_ARM, + /* 0x08 */ PAMELAS_FATHER_GIBDO_LIMB_RIGHT_FOREARM, + /* 0x09 */ PAMELAS_FATHER_GIBDO_LIMB_RIGHT_HAND, + /* 0x0A */ PAMELAS_FATHER_GIBDO_LIMB_EYEBROWS, + /* 0x0B */ PAMELAS_FATHER_GIBDO_LIMB_HEAD, + /* 0x0C */ PAMELAS_FATHER_GIBDO_LIMB_PELVIS, + /* 0x0D */ PAMELAS_FATHER_GIBDO_LIMB_LEFT_THIGH, + /* 0x0E */ PAMELAS_FATHER_GIBDO_LIMB_LEFT_SHIN, + /* 0x0F */ PAMELAS_FATHER_GIBDO_LIMB_LEFT_FOOT, + /* 0x10 */ PAMELAS_FATHER_GIBDO_LIMB_RIGHT_THIGH, + /* 0x11 */ PAMELAS_FATHER_GIBDO_LIMB_RIGHT_SHIN, + /* 0x12 */ PAMELAS_FATHER_GIBDO_LIMB_RIGHT_FOOT, + /* 0x13 */ PAMELAS_FATHER_GIBDO_LIMB_MAX +} PamelasFatherGibdoLimb; + +typedef enum PamelasFatherHumanLimb { + /* 0x00 */ PAMELAS_FATHER_HUMAN_LIMB_NONE, + /* 0x01 */ PAMELAS_FATHER_HUMAN_LIMB_ROOT, + /* 0x02 */ PAMELAS_FATHER_HUMAN_LIMB_ABDOMEN, + /* 0x03 */ PAMELAS_FATHER_HUMAN_LIMB_CHEST, + /* 0x04 */ PAMELAS_FATHER_HUMAN_LIMB_LEFT_UPPER_ARM, + /* 0x05 */ PAMELAS_FATHER_HUMAN_LIMB_LEFT_FOREARM, + /* 0x06 */ PAMELAS_FATHER_HUMAN_LIMB_LEFT_HAND, + /* 0x07 */ PAMELAS_FATHER_HUMAN_LIMB_RIGHT_UPPER_ARM, + /* 0x08 */ PAMELAS_FATHER_HUMAN_LIMB_RIGHT_FOREARM, + /* 0x09 */ PAMELAS_FATHER_HUMAN_LIMB_RIGHT_HAND, + /* 0x0A */ PAMELAS_FATHER_HUMAN_LIMB_EYEBROWS, + /* 0x0B */ PAMELAS_FATHER_HUMAN_LIMB_HEAD, + /* 0x0C */ PAMELAS_FATHER_HUMAN_LIMB_PELVIS, + /* 0x0D */ PAMELAS_FATHER_HUMAN_LIMB_LEFT_THIGH, + /* 0x0E */ PAMELAS_FATHER_HUMAN_LIMB_LEFT_SHIN, + /* 0x0F */ PAMELAS_FATHER_HUMAN_LIMB_LEFT_FOOT, + /* 0x10 */ PAMELAS_FATHER_HUMAN_LIMB_RIGHT_THIGH, + /* 0x11 */ PAMELAS_FATHER_HUMAN_LIMB_RIGHT_SHIN, + /* 0x12 */ PAMELAS_FATHER_HUMAN_LIMB_RIGHT_FOOT, + /* 0x13 */ PAMELAS_FATHER_HUMAN_LIMB_MAX +} PamelasFatherHumanLimb; diff --git a/patches/dummy_headers/objects/object_pamera/object_pamera.h b/patches/dummy_headers/objects/object_pamera/object_pamera.h new file mode 100644 index 0000000..5baeacf --- /dev/null +++ b/patches/dummy_headers/objects/object_pamera/object_pamera.h @@ -0,0 +1,26 @@ +typedef enum PamelaLimb { + /* 0x00 */ PAMELA_LIMB_NONE, + /* 0x01 */ PAMELA_LIMB_ROOT, + /* 0x02 */ PAMELA_LIMB_UPPER_BODY_ROOT, + /* 0x03 */ PAMELA_LIMB_LEFT_UPPER_ARM, + /* 0x04 */ PAMELA_LIMB_LEFT_FOREARM, + /* 0x05 */ PAMELA_LIMB_LEFT_HAND, + /* 0x06 */ PAMELA_LIMB_RIGHT_UPPER_ARM, + /* 0x07 */ PAMELA_LIMB_RIGHT_FOREARM, + /* 0x08 */ PAMELA_LIMB_RIGHT_HAND, + /* 0x09 */ PAMELA_LIMB_HEAD, + /* 0x0A */ PAMELA_LIMB_HAIR_END, + /* 0x0B */ PAMELA_LIMB_CHEST, + /* 0x0C */ PAMELA_LIMB_NECK, + /* 0x0D */ PAMELA_LIMB_LEFT_THIGH, + /* 0x0E */ PAMELA_LIMB_LEFT_LEG, + /* 0x0F */ PAMELA_LIMB_LEFT_FOOT, + /* 0x10 */ PAMELA_LIMB_RIGHT_THIGH, + /* 0x11 */ PAMELA_LIMB_RIGHT_LEG, + /* 0x12 */ PAMELA_LIMB_RIGHT_FOOT, + /* 0x13 */ PAMELA_LIMB_FRONT_DRESS, + /* 0x14 */ PAMELA_LIMB_BACK_DRESS, + /* 0x15 */ PAMELA_LIMB_ABDOMEN, + /* 0x16 */ PAMELA_LIMB_PELVIS, + /* 0x17 */ PAMELA_LIMB_MAX +} PamelaLimb; diff --git a/patches/gibdo_mask_cutscene_father_human.c b/patches/gibdo_mask_cutscene_father_human.c new file mode 100644 index 0000000..2ed5fee --- /dev/null +++ b/patches/gibdo_mask_cutscene_father_human.c @@ -0,0 +1,107 @@ +#include "patches.h" +#include "transform_ids.h" +#include "overlays/actors/ovl_En_Hgo/z_en_hgo.h" + +typedef enum { + /* 0 */ HGO_ANIM_ARMS_FOLDED, + /* 1 */ HGO_ANIM_ASTONISHED, + /* 2 */ HGO_ANIM_KNEEL_DOWN_AND_HUG, + /* 3 */ HGO_ANIM_CONSOLE, + /* 4 */ HGO_ANIM_CONSOLE_HEAD_UP, + /* 5 */ HGO_ANIM_REACH_DOWN_TO_LIFT, + /* 6 */ HGO_ANIM_TOSS, + /* 7 */ HGO_ANIM_MAX +} HgoAnimation; + +extern AnimationInfo sPamelasFatherHumanAnimationInfo[]; +extern void EnHgo_Draw(Actor* thisx, PlayState* play); +extern void EnHgo_DoNothing(EnHgo* this, PlayState* play); +extern void EnHgo_SetupInitCollision(EnHgo* this); + +// @recomp Skip interpolation when the animations change during the cutscene, as the +// animation changes are meant to happen at the same time as the camera cuts. +RECOMP_PATCH s32 EnHgo_HandleCsAction(EnHgo* this, PlayState* play) { + s32 cueChannel; + + if (Cutscene_IsCueInChannel(play, CS_CMD_ACTOR_CUE_486)) { + cueChannel = Cutscene_GetCueChannel(play, CS_CMD_ACTOR_CUE_486); + if (this->cueId != play->csCtx.actorCues[cueChannel]->id) { + this->cueId = play->csCtx.actorCues[cueChannel]->id; + switch (play->csCtx.actorCues[cueChannel]->id) { + case 1: + this->animIndex = HGO_ANIM_ARMS_FOLDED; + Actor_ChangeAnimationByInfo(&this->skelAnime, sPamelasFatherHumanAnimationInfo, HGO_ANIM_ARMS_FOLDED); + break; + + case 2: + this->actor.draw = EnHgo_Draw; + this->animIndex = HGO_ANIM_ASTONISHED; + Actor_ChangeAnimationByInfo(&this->skelAnime, sPamelasFatherHumanAnimationInfo, HGO_ANIM_ASTONISHED); + break; + + case 3: + this->animIndex = HGO_ANIM_KNEEL_DOWN_AND_HUG; + Actor_ChangeAnimationByInfo(&this->skelAnime, sPamelasFatherHumanAnimationInfo, HGO_ANIM_KNEEL_DOWN_AND_HUG); + break; + + case 4: + this->animIndex = HGO_ANIM_CONSOLE; + Actor_ChangeAnimationByInfo(&this->skelAnime, sPamelasFatherHumanAnimationInfo, HGO_ANIM_CONSOLE); + break; + + case 5: + this->animIndex = HGO_ANIM_CONSOLE_HEAD_UP; + Actor_ChangeAnimationByInfo(&this->skelAnime, sPamelasFatherHumanAnimationInfo, HGO_ANIM_CONSOLE_HEAD_UP); + break; + + case 6: + this->animIndex = HGO_ANIM_REACH_DOWN_TO_LIFT; + Actor_ChangeAnimationByInfo(&this->skelAnime, sPamelasFatherHumanAnimationInfo, HGO_ANIM_REACH_DOWN_TO_LIFT); + break; + + default: + break; + } + actor_set_interpolation_skipped(&this->actor); + } else if (Animation_OnFrame(&this->skelAnime, this->skelAnime.endFrame)) { + switch (this->animIndex) { + case HGO_ANIM_ASTONISHED: + if (Animation_OnFrame(&this->skelAnime, this->skelAnime.endFrame) && !this->isInCutscene) { + this->isInCutscene = true; + if ((gSaveContext.sceneLayer == 0) && + ((play->csCtx.scriptIndex == 2) || (play->csCtx.scriptIndex == 4))) { + Actor_PlaySfx(&this->actor, NA_SE_VO_GBVO02); + } + } + break; + + case HGO_ANIM_KNEEL_DOWN_AND_HUG: + this->animIndex = HGO_ANIM_CONSOLE; + Actor_ChangeAnimationByInfo(&this->skelAnime, sPamelasFatherHumanAnimationInfo, HGO_ANIM_CONSOLE); + break; + + case HGO_ANIM_REACH_DOWN_TO_LIFT: + this->animIndex = HGO_ANIM_TOSS; + Actor_ChangeAnimationByInfo(&this->skelAnime, sPamelasFatherHumanAnimationInfo, HGO_ANIM_TOSS); + + default: + break; + + } + } + + Cutscene_ActorTranslateAndYaw(&this->actor, play, cueChannel); + return true; + } + + if ((play->csCtx.state == CS_STATE_IDLE) && CHECK_WEEKEVENTREG(WEEKEVENTREG_75_20) && + (this->actionFunc == EnHgo_DoNothing)) { + this->actor.shape.rot.y = this->actor.world.rot.y; + Actor_Spawn(&play->actorCtx, play, ACTOR_ELF_MSG2, this->actor.focus.pos.x, this->actor.focus.pos.y, + this->actor.focus.pos.z, 7, 0, 0, 0x7F5A); + EnHgo_SetupInitCollision(this); + } + + this->cueId = 99; + return false; +} diff --git a/patches/gibdo_mask_cutscene_mask.c b/patches/gibdo_mask_cutscene_mask.c new file mode 100644 index 0000000..7923f87 --- /dev/null +++ b/patches/gibdo_mask_cutscene_mask.c @@ -0,0 +1,26 @@ +#include "patches.h" +#include "transform_ids.h" +#include "overlays/actors/ovl_Dm_Char05/z_dm_char05.h" + +extern void func_80AADF54(PlayState* play, DmChar05* this); + +// @recomp Patched to avoid an interpolation glitch in Pamela's dad's cutscene +// that happens when the mask is meant to teleport offscreen. +RECOMP_PATCH void func_80AADB4C(Actor* thisx, PlayState* play) { + DmChar05* this = (DmChar05*)thisx; + if (this->unk_18E == 0) { + if (Cutscene_IsCueInChannel(play, CS_CMD_ACTOR_CUE_518) && + (play->csCtx.actorCues[Cutscene_GetCueChannel(play, CS_CMD_ACTOR_CUE_518)]->id != 1)) { + // @recomp During this cue the mask does nothing other than teleport offscreen and stay still, + // so we can just skip interpolation the entire time. + if (play->csCtx.actorCues[Cutscene_GetCueChannel(play, CS_CMD_ACTOR_CUE_518)]->id == 3) { + actor_set_interpolation_skipped(thisx); + } + Gfx_SetupDL25_Opa(play->state.gfxCtx); + SkelAnime_DrawFlexOpa(play, this->skelAnime.skeleton, this->skelAnime.jointTable, + this->skelAnime.dListCount, NULL, NULL, &this->actor); + } + } else if (this->unk_18E == 1) { + func_80AADF54(play, this); + } +} diff --git a/patches/gibdo_mask_cutscene_pamela.c b/patches/gibdo_mask_cutscene_pamela.c new file mode 100644 index 0000000..1f7f5a8 --- /dev/null +++ b/patches/gibdo_mask_cutscene_pamela.c @@ -0,0 +1,74 @@ +#include "patches.h" +#include "transform_ids.h" +#include "overlays/actors/ovl_En_Pamera/z_en_pamera.h" + +extern void EnPamera_Draw(Actor* thisx, PlayState* play); +extern void func_80BD9E88(EnPamera* this); +extern void func_80BD9EE0(EnPamera* this); +extern void func_80BDA038(EnPamera* this); +extern void func_80BDA0A0(EnPamera* this); +extern void func_80BDA170(EnPamera* this); +extern void func_80BDA288(EnPamera* this); +extern void func_80BD994C(EnPamera* this, PlayState* play); +extern void EnPamera_HandleDialogue(EnPamera* this, PlayState* play); +extern void func_80BD9904(EnPamera* this); +extern void func_80BD9E60(EnPamera* this); + +// @recomp Skip interpolation when the animations change during the cutscene, as the +// animation changes are meant to happen at the same time as the camera cuts. +RECOMP_PATCH s32 func_80BD9CB8(EnPamera* this, PlayState* play) { + s32 cueChannel; + + if (Cutscene_IsCueInChannel(play, CS_CMD_ACTOR_CUE_485)) { + cueChannel = Cutscene_GetCueChannel(play, CS_CMD_ACTOR_CUE_485); + if (this->cueId != play->csCtx.actorCues[cueChannel]->id) { + this->cueId = play->csCtx.actorCues[cueChannel]->id; + + switch (play->csCtx.actorCues[cueChannel]->id) { + case 1: + func_80BD9E88(this); + break; + + case 2: + if (this->actor.draw == NULL) { + this->actor.draw = EnPamera_Draw; + this->actor.flags |= ACTOR_FLAG_TARGETABLE; + } + func_80BD9EE0(this); + break; + + case 3: + func_80BDA038(this); + break; + + case 4: + func_80BDA0A0(this); + break; + + case 5: + func_80BDA170(this); + break; + + case 6: + func_80BDA288(this); + break; + + default: + break; + } + actor_set_interpolation_skipped(&this->actor); + } + Cutscene_ActorTranslateAndYaw(&this->actor, play, cueChannel); + this->setupFunc(this, play); + return true; + } + if ((play->csCtx.state == CS_STATE_IDLE) && CHECK_WEEKEVENTREG(WEEKEVENTREG_75_20)) { + if ((this->actionFunc != func_80BD994C) && (this->actionFunc != EnPamera_HandleDialogue)) { + this->actor.shape.rot.y = this->actor.world.rot.y; + func_80BD9904(this); + func_80BD9E60(this); + } + } + this->cueId = 99; + return false; +} diff --git a/patches/item_transform_tagging.c b/patches/item_transform_tagging.c index 0811c46..3f63edb 100644 --- a/patches/item_transform_tagging.c +++ b/patches/item_transform_tagging.c @@ -185,3 +185,6 @@ RECOMP_PATCH void Player_DrawGameplay(PlayState* play, Player* this, s32 lod, Gf CLOSE_DISPS(play->state.gfxCtx); } +RECOMP_EXPORT u32 z64recomp_get_bowstring_transform_id() { + return BOWSTRING_TRANSFORM_ID; +} diff --git a/patches/specific_actor_transform_tagging.c b/patches/specific_actor_transform_tagging.c index 78d2463..dc5dd3b 100644 --- a/patches/specific_actor_transform_tagging.c +++ b/patches/specific_actor_transform_tagging.c @@ -12,6 +12,8 @@ #include "overlays/actors/ovl_En_Twig/z_en_twig.h" #include "overlays/actors/ovl_En_Honotrap/z_en_honotrap.h" #include "overlays/actors/ovl_En_Tanron1/z_en_tanron1.h" +#include "overlays/actors/ovl_En_Kusa2/z_en_kusa2.h" +#include "overlays/actors/ovl_Obj_Grass/z_obj_grass.h" // Decomp renames, TODO update decomp and remove these #define EnHonotrap_FlameGroup func_8092F878 @@ -1331,3 +1333,154 @@ RECOMP_PATCH void func_80BB5AAC(EnTanron1* this, PlayState* play) { CLOSE_DISPS(play->state.gfxCtx); } + +extern Gfx gKakeraLeafTipDL[]; +extern Gfx gKakeraLeafMiddleDL[]; +extern EnKusa2UnkBssStruct D_80A5F1C0; + +// Patched to tag the particles that spawn from Keaton grass. +RECOMP_PATCH void func_80A5E6F0(Actor* thisx, PlayState* play) { + static Gfx* D_80A5EB68[] = { + gKakeraLeafTipDL, + gKakeraLeafMiddleDL, + }; + EnKusa2* this = (EnKusa2*)thisx; + s32 i; + + OPEN_DISPS(play->state.gfxCtx); + + Gfx_SetupDL25_Opa(play->state.gfxCtx); + + // @recomp Get the base transform ID for this actor. + u32 cur_transform_id = actor_transform_id(thisx); + + for (i = 0; i < ARRAY_COUNT(D_80A5F1C0.unk_0480); i++) { + EnKusa2UnkBssSubStruct2* s = &D_80A5F1C0.unk_0480[i]; + + if (s->unk_2C > 0) { + Matrix_SetTranslateRotateYXZ(s->unk_04.x, s->unk_04.y, s->unk_04.z, &s->unk_20); + Matrix_Scale(s->unk_00, s->unk_00, s->unk_00, MTXMODE_APPLY); + + // @recomp Create a matrix group for this particle. + gEXMatrixGroupDecomposedNormal(POLY_OPA_DISP++, cur_transform_id + i, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_ALLOW); + + gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(POLY_OPA_DISP++, D_80A5EB68[i & 1]); + + // @recomp Pop the matrix group. + gEXPopMatrixGroup(POLY_OPA_DISP++, G_MTX_MODELVIEW); + } + } + + CLOSE_DISPS(play->state.gfxCtx); +} + +extern Gfx gObjGrass_D_809AA9F0[]; +extern Gfx gObjGrass_D_809AAA68[]; +extern Gfx gObjGrass_D_809AAAE0[]; +void ObjGrass_OverrideMatrixCurrent(MtxF* matrix); + +// @recomp Patched to set matrix groups for grass. +RECOMP_PATCH void ObjGrass_DrawOpa(Actor* thisx, PlayState* play2) { + ObjGrass* this = (ObjGrass*)thisx; + PlayState* play = play2; + Lights* lights; + ObjGrassGroup* grassGroup; + s32 i; + s32 j; + Vec3s rot = { 0, 0, 0 }; + ObjGrassElement* grassElem; + + OPEN_DISPS(play->state.gfxCtx); + + Gfx_SetupDL25_Opa(play->state.gfxCtx); + + gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 255, 255, 255, 255); + gSPDisplayList(POLY_OPA_DISP++, gObjGrass_D_809AA9F0); + + // @recomp Extract this actor's ID. + u32 actor_id = actor_transform_id(thisx); + + for (i = 0; i < this->activeGrassGroups; i++) { + grassGroup = &this->grassGroups[i]; + + if (grassGroup->flags & OBJ_GRASS_GROUP_DRAW) { + lights = LightContext_NewLights(&play->lightCtx, play->state.gfxCtx); + Lights_BindAll(lights, play->lightCtx.listHead, &grassGroup->homePos, play); + Lights_Draw(lights, play->state.gfxCtx); + + for (j = 0; j < grassGroup->count; j++) { + grassElem = &grassGroup->elements[j]; + + if ((grassElem->flags & OBJ_GRASS_ELEM_DRAW) && (grassElem->alpha == 255)) { + rot.y = grassElem->rotY; + Matrix_SetTranslateRotateYXZ(grassElem->pos.x, grassElem->pos.y, grassElem->pos.z, &rot); + Matrix_Scale(this->actor.scale.x, this->actor.scale.y, this->actor.scale.z, MTXMODE_APPLY); + if (grassElem->flags & OBJ_GRASS_ELEM_ANIM) { + ObjGrass_OverrideMatrixCurrent(&this->distortionMtx[j]); + } + + // @recomp Push a matrix group. + gEXMatrixGroupDecomposedNormal(POLY_OPA_DISP++, actor_id + i * OBJ_GRASS_GROUP_ELEM_COUNT_MAX + j, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_NONE); + + gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(play->state.gfxCtx), + G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(POLY_OPA_DISP++, gObjGrass_D_809AAAE0); + + // @recomp Pop the matrix group. + gEXPopMatrixGroup(POLY_OPA_DISP++, G_MTX_MODELVIEW); + } + } + } + } + + CLOSE_DISPS(play->state.gfxCtx); +} + +// @recomp Patched to set matrix groups for grass. +RECOMP_PATCH void ObjGrass_DrawXlu(Actor* thisx, PlayState* play) { + ObjGrass* this = (ObjGrass*)thisx; + ObjGrassGroup* grassGroup; + ObjGrassElement* grassElem; + s32 i; + s32 j; + Vec3s rot = { 0, 0, 0 }; + + OPEN_DISPS(play->state.gfxCtx); + + Gfx_SetupDL25_Xlu(play->state.gfxCtx); + + gSPDisplayList(POLY_XLU_DISP++, gObjGrass_D_809AAA68); + + // @recomp Extract this actor's ID. + u32 actor_id = actor_transform_id(thisx); + + for (i = 0; i < this->activeGrassGroups; i++) { + grassGroup = &this->grassGroups[i]; + + if (grassGroup->flags & OBJ_GRASS_GROUP_DRAW) { + for (j = 0; j < grassGroup->count; j++) { + grassElem = &grassGroup->elements[j]; + + if ((grassElem->flags & OBJ_GRASS_ELEM_DRAW) && (grassElem->alpha > 0) && (grassElem->alpha < 255)) { + rot.y = grassElem->rotY; + Matrix_SetTranslateRotateYXZ(grassElem->pos.x, grassElem->pos.y, grassElem->pos.z, &rot); + Matrix_Scale(this->actor.scale.x, this->actor.scale.y, this->actor.scale.z, MTXMODE_APPLY); + + // @recomp Push a matrix group. + gEXMatrixGroupDecomposedNormal(POLY_XLU_DISP++, actor_id + i * OBJ_GRASS_GROUP_ELEM_COUNT_MAX + j, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_NONE); + + gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(play->state.gfxCtx), + G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 255, grassElem->alpha); + gSPDisplayList(POLY_XLU_DISP++, gObjGrass_D_809AAAE0); + + // @recomp Pop the matrix group. + gEXPopMatrixGroup(POLY_XLU_DISP++, G_MTX_MODELVIEW); + } + } + } + } + + CLOSE_DISPS(play->state.gfxCtx); +} diff --git a/patches/sword_trail_transform_tagging.c b/patches/sword_trail_transform_tagging.c new file mode 100644 index 0000000..5bd8543 --- /dev/null +++ b/patches/sword_trail_transform_tagging.c @@ -0,0 +1,509 @@ +#include "patches.h" + +#define VTX_EX_T(x, y, z, s, t, cr, cg, cb, a, px, py, pz) \ + { { x, y, z }, 0, { s, t }, { cr, cg, cb, a }, {px, py, pz} } + +void EffectBlure_GetComputedValues(EffectBlure* this, s32 index, f32 ratio, Vec3s* vec1, Vec3s* vec2, + Color_RGBA8* color1, Color_RGBA8* color2); +void EffectBlure_DrawSimple(EffectBlure* this2, GraphicsContext* gfxCtx); +void EffectBlure_DrawSmooth(EffectBlure* this2, GraphicsContext* gfxCtx); + +// @recomp Patched to interpolate the vertices towards the front of the trail section if this is the last trail being drawn currently. +RECOMP_PATCH void EffectBlure_DrawElemNoInterpolation(EffectBlure* this, EffectBlureElement* elem, s32 index, + GraphicsContext* gfxCtx) { + // @recomp Change baseVtx to a VertexEX. + static VertexEXColor baseVtx = VTX_EX_T(/* pos */ 0, 0, 0, /* st */ 0, 0, /* color */ 255, 255, 255, 255, /* prev pos */ 0, 0, 0); + // @recomp Change the vertex type to VertexEX. + VertexEX* vtx; + Vec3s sp8C; + Vec3s sp84; + f32 ratio; + Color_RGBA8 sp7C; + Color_RGBA8 sp78; + Vec3f sp6C; + Vec3f sp60; + Vec3f sp54; + + OPEN_DISPS(gfxCtx); + + Math_Vec3s_ToVec3f(&sp6C, &this->elements[0].p2); + + // @recomp Debug print. + // recomp_printf("No interpolation index %d:\n" + // " Blure: calcMode %08X flags: %04X addAngle %04X addAngle %04X elemDuration %d\n" + // " Element: state %08X timer: %d flags %04X\n", + // index, + // this->calcMode, this->flags, (u16)this->addAngleChange, (u16)this->addAngle, this->elemDuration, + // elem->state, elem->timer, elem->flags); + + // @recomp Allocate using the size of VertexEX instead. + vtx = GRAPH_ALLOC(gfxCtx, 4 * sizeof(VertexEX)); + if (vtx == NULL) { + } else { + vtx[0].v = baseVtx; + vtx[1].v = baseVtx; + vtx[2].v = baseVtx; + vtx[3].v = baseVtx; + + ratio = (f32)elem->timer / (f32)this->elemDuration; + EffectBlure_GetComputedValues(this, index, ratio, &sp8C, &sp84, &sp7C, &sp78); + + sp60.x = sp84.x; + sp60.y = sp84.y; + sp60.z = sp84.z; + Math_Vec3f_Diff(&sp60, &sp6C, &sp54); + Math_Vec3f_Scale(&sp54, 10.0f); + vtx[0].v.ob[0] = sp54.x; + vtx[0].v.ob[1] = sp54.y; + vtx[0].v.ob[2] = sp54.z; + vtx[0].v.cn[0] = sp78.r; + vtx[0].v.cn[1] = sp78.g; + vtx[0].v.cn[2] = sp78.b; + vtx[0].v.cn[3] = sp78.a; + + sp60.x = sp8C.x; + sp60.y = sp8C.y; + sp60.z = sp8C.z; + Math_Vec3f_Diff(&sp60, &sp6C, &sp54); + Math_Vec3f_Scale(&sp54, 10.0f); + vtx[1].v.ob[0] = sp54.x; + vtx[1].v.ob[1] = sp54.y; + vtx[1].v.ob[2] = sp54.z; + vtx[1].v.cn[0] = sp7C.r; + vtx[1].v.cn[1] = sp7C.g; + vtx[1].v.cn[2] = sp7C.b; + vtx[1].v.cn[3] = sp7C.a; + + ratio = (f32)(elem + 1)->timer / (f32)this->elemDuration; + EffectBlure_GetComputedValues(this, index + 1, ratio, &sp8C, &sp84, &sp7C, &sp78); + + sp60.x = sp8C.x; + sp60.y = sp8C.y; + sp60.z = sp8C.z; + Math_Vec3f_Diff(&sp60, &sp6C, &sp54); + Math_Vec3f_Scale(&sp54, 10.0f); + vtx[2].v.ob[0] = sp54.x; + vtx[2].v.ob[1] = sp54.y; + vtx[2].v.ob[2] = sp54.z; + vtx[2].v.cn[0] = sp7C.r; + vtx[2].v.cn[1] = sp7C.g; + vtx[2].v.cn[2] = sp7C.b; + vtx[2].v.cn[3] = sp7C.a; + + sp60.x = sp84.x; + sp60.y = sp84.y; + sp60.z = sp84.z; + Math_Vec3f_Diff(&sp60, &sp6C, &sp54); + Math_Vec3f_Scale(&sp54, 10.0f); + vtx[3].v.ob[0] = sp54.x; + vtx[3].v.ob[1] = sp54.y; + vtx[3].v.ob[2] = sp54.z; + vtx[3].v.cn[0] = sp78.r; + vtx[3].v.cn[1] = sp78.g; + vtx[3].v.cn[2] = sp78.b; + vtx[3].v.cn[3] = sp78.a; + + // @recomp Set the previous position of the first two vertices to their current position. + vtx[0].v.obp[0] = vtx[0].v.ob[0]; + vtx[0].v.obp[1] = vtx[0].v.ob[1]; + vtx[0].v.obp[2] = vtx[0].v.ob[2]; + vtx[1].v.obp[0] = vtx[1].v.ob[0]; + vtx[1].v.obp[1] = vtx[1].v.ob[1]; + vtx[1].v.obp[2] = vtx[1].v.ob[2]; + + // @recomp If this trail just spawned (timer == 2), set the previous vertex positions for the last two vertices to the positions of the last two (interpolation). + // Otherwise, set them to the current position of the respective vertex (no interpolation). + if (elem->timer == 2) { + // Vertex 2 interpolates from a start position equal to the position of vertex 1. + vtx[2].v.obp[0] = vtx[1].v.ob[0]; + vtx[2].v.obp[1] = vtx[1].v.ob[1]; + vtx[2].v.obp[2] = vtx[1].v.ob[2]; + // Vertex 3 interpolates from a start position equal to the position of vertex 0. + vtx[3].v.obp[0] = vtx[0].v.ob[0]; + vtx[3].v.obp[1] = vtx[0].v.ob[1]; + vtx[3].v.obp[2] = vtx[0].v.ob[2]; + } + else { + vtx[2].v.obp[0] = vtx[2].v.ob[0]; + vtx[2].v.obp[1] = vtx[2].v.ob[1]; + vtx[2].v.obp[2] = vtx[2].v.ob[2]; + vtx[3].v.obp[0] = vtx[3].v.ob[0]; + vtx[3].v.obp[1] = vtx[3].v.ob[1]; + vtx[3].v.obp[2] = vtx[3].v.ob[2]; + } + + // @recomp Use gEXVertex in place of gSPVertex. + gEXVertex(POLY_XLU_DISP++, vtx, 4, 0); + gSP2Triangles(POLY_XLU_DISP++, 0, 1, 2, 0, 0, 2, 3, 0); + } + + CLOSE_DISPS(gfxCtx); +} + +// @recomp Patched to interpolate the vertices towards the front of the trail section if this is the last trail being drawn currently. +RECOMP_PATCH void EffectBlure_DrawElemHermiteInterpolation(EffectBlure* this, EffectBlureElement* elem, s32 index, + GraphicsContext* gfxCtx) { + // @recomp Change baseVtx to a VertexEX. + static VertexEXColor baseVtx = VTX_EX_T(/* pos */ 0, 0, 0, /* st */ 0, 0, /* color */ 255, 255, 255, 255, /* prev pos */ 0, 0, 0); + // @recomp Change the vertex type to VertexEX. + VertexEX* vtx; + Vec3s sp1EC; + Vec3s sp1E4; + f32 ratio; + Color_RGBA8 sp1DC; + Color_RGBA8 sp1D8; + Vec3f sp1CC; + Vec3f sp1C0; + Vec3f sp1B4; + Vec3f sp1A8; + Color_RGBA8 sp1A4; + Color_RGBA8 sp1A0; + Color_RGBA8 sp19C; + Color_RGBA8 sp198; + Vec3f sp18C; + Vec3f sp180; + Vec3f sp174; + Vec3f sp168; + s32 i; + Vec3f sp158; + Vec3f sp14C; + Color_RGBA8 sp148; + Color_RGBA8 sp144; + Vec3f sp138; + + // @recomp Debug print. + // recomp_printf("Hermite interpolation index %d:\n" + // " Blure: calcMode %08X flags: %04X addAngle %04X addAngle %04X elemDuration %d\n" + // " Element: state %08X timer: %d flags %04X\n", + // index, + // this->calcMode, this->flags, (u16)this->addAngleChange, (u16)this->addAngle, this->elemDuration, + // elem->state, elem->timer, elem->flags); + + OPEN_DISPS(gfxCtx); + + Math_Vec3s_ToVec3f(&sp138, &this->elements[0].p2); + + ratio = (f32)elem->timer / (f32)this->elemDuration; + EffectBlure_GetComputedValues(this, index, ratio, &sp1EC, &sp1E4, &sp1A4, &sp1A0); + Math_Vec3s_ToVec3f(&sp1CC, &sp1EC); + Math_Vec3s_ToVec3f(&sp1C0, &sp1E4); + + ratio = (f32)(elem + 1)->timer / (f32)this->elemDuration; + EffectBlure_GetComputedValues(this, index + 1, ratio, &sp1EC, &sp1E4, &sp19C, &sp198); + Math_Vec3s_ToVec3f(&sp18C, &sp1EC); + Math_Vec3s_ToVec3f(&sp180, &sp1E4); + + if ((elem->flags & (EFFECT_BLURE_ELEMENT_FLAG_1 | EFFECT_BLURE_ELEMENT_FLAG_2)) == EFFECT_BLURE_ELEMENT_FLAG_2) { + Math_Vec3f_Diff(&sp18C, &sp1CC, &sp1B4); + Math_Vec3f_Diff(&sp180, &sp1C0, &sp1A8); + } else { + Vec3f sp118; + Vec3f sp10C; + + ratio = (f32)(elem - 1)->timer / (f32)this->elemDuration; + EffectBlure_GetComputedValues(this, index - 1, ratio, &sp1EC, &sp1E4, &sp1DC, &sp1D8); + Math_Vec3s_ToVec3f(&sp118, &sp1EC); + Math_Vec3s_ToVec3f(&sp10C, &sp1E4); + Math_Vec3f_Diff(&sp18C, &sp118, &sp1B4); + Math_Vec3f_Diff(&sp180, &sp10C, &sp1A8); + } + + Math_Vec3f_Scale(&sp1B4, 0.5f); + Math_Vec3f_Scale(&sp1A8, 0.5f); + + if (((elem + 1)->flags & (EFFECT_BLURE_ELEMENT_FLAG_1 | EFFECT_BLURE_ELEMENT_FLAG_2)) == + EFFECT_BLURE_ELEMENT_FLAG_2) { + Math_Vec3f_Diff(&sp18C, &sp1CC, &sp174); + Math_Vec3f_Diff(&sp180, &sp1C0, &sp168); + } else { + Vec3f sp100; + Vec3f spF4; + + ratio = (f32)(elem + 2)->timer / (f32)this->elemDuration; + EffectBlure_GetComputedValues(this, index + 2, ratio, &sp1EC, &sp1E4, &sp1DC, &sp1D8); + Math_Vec3s_ToVec3f(&sp100, &sp1EC); + Math_Vec3s_ToVec3f(&spF4, &sp1E4); + Math_Vec3f_Diff(&sp100, &sp1CC, &sp174); + Math_Vec3f_Diff(&spF4, &sp1C0, &sp168); + } + + Math_Vec3f_Scale(&sp174, 0.5f); + Math_Vec3f_Scale(&sp168, 0.5f); + + // @recomp Allocate using the size of VertexEX instead. + vtx = GRAPH_ALLOC(gfxCtx, 16 * sizeof(VertexEX)); + if (vtx == NULL) { + } else { + Math_Vec3f_Diff(&sp1CC, &sp138, &sp158); + Math_Vec3f_Scale(&sp158, 10.0f); + Math_Vec3f_Diff(&sp1C0, &sp138, &sp14C); + Math_Vec3f_Scale(&sp14C, 10.0f); + + Color_RGBA8_Copy(&sp148, &sp1A4); + Color_RGBA8_Copy(&sp144, &sp1A0); + + vtx[0].v = baseVtx; + vtx[1].v = baseVtx; + + vtx[0].v.ob[0] = Math_FNearbyIntF(sp158.x); + vtx[0].v.ob[1] = Math_FNearbyIntF(sp158.y); + vtx[0].v.ob[2] = Math_FNearbyIntF(sp158.z); + vtx[0].v.cn[0] = sp148.r; + vtx[0].v.cn[1] = sp148.g; + vtx[0].v.cn[2] = sp148.b; + vtx[0].v.cn[3] = sp148.a; + vtx[1].v.ob[0] = Math_FNearbyIntF(sp14C.x); + vtx[1].v.ob[1] = Math_FNearbyIntF(sp14C.y); + vtx[1].v.ob[2] = Math_FNearbyIntF(sp14C.z); + vtx[1].v.cn[0] = sp144.r; + vtx[1].v.cn[1] = sp144.g; + vtx[1].v.cn[2] = sp144.b; + vtx[1].v.cn[3] = sp144.a; + + // @recomp Set the previous position of the first two vertices to their current position. + vtx[0].v.obp[0] = vtx[0].v.ob[0]; + vtx[0].v.obp[1] = vtx[0].v.ob[1]; + vtx[0].v.obp[2] = vtx[0].v.ob[2]; + vtx[1].v.obp[0] = vtx[1].v.ob[0]; + vtx[1].v.obp[1] = vtx[1].v.ob[1]; + vtx[1].v.obp[2] = vtx[1].v.ob[2]; + + for (i = 1; i < 8; i++) { + s32 j1 = 2 * i; + s32 j2 = 2 * i + 1; + Vec3f spE0; + f32 temp_f28 = i / 7.0f; // t + f32 temp_f0 = SQ(temp_f28); // t^2 + f32 temp_f2 = temp_f0 * temp_f28; // t^3 + f32 temp_f20 = temp_f2 - temp_f0; // t^3 - t^2 + f32 temp_f22 = temp_f2 - 2.0f * temp_f0 + temp_f28; // t^3 - 2t^2 + t + f32 temp_f24 = 2.0f * temp_f2 - temp_f0 * 3.0f + 1.0f; // 2t^3 - 3t^2 + 1 + f32 temp_f26 = temp_f0 * 3.0f - 2.0f * temp_f2; // 3t^2 - 2t^3 + s32 pad1; + s32 pad2; + + // p = (2t^3 - 3t^2 + 1)p0 + (3t^2 - 2t^3)p1 + (t^3 - 2t^2 + t)m0 + (t^3 - t^2)m1 + spE0.x = (temp_f24 * sp1CC.x) + (temp_f26 * sp18C.x) + (temp_f22 * sp1B4.x) + (temp_f20 * sp174.x); + spE0.y = (temp_f24 * sp1CC.y) + (temp_f26 * sp18C.y) + (temp_f22 * sp1B4.y) + (temp_f20 * sp174.y); + spE0.z = (temp_f24 * sp1CC.z) + (temp_f26 * sp18C.z) + (temp_f22 * sp1B4.z) + (temp_f20 * sp174.z); + Math_Vec3f_Diff(&spE0, &sp138, &sp158); + Math_Vec3f_Scale(&sp158, 10.0f); + + spE0.x = (temp_f24 * sp1C0.x) + (temp_f26 * sp180.x) + (temp_f22 * sp1A8.x) + (temp_f20 * sp168.x); + spE0.y = (temp_f24 * sp1C0.y) + (temp_f26 * sp180.y) + (temp_f22 * sp1A8.y) + (temp_f20 * sp168.y); + spE0.z = (temp_f24 * sp1C0.z) + (temp_f26 * sp180.z) + (temp_f22 * sp1A8.z) + (temp_f20 * sp168.z); + Math_Vec3f_Diff(&spE0, &sp138, &sp14C); + Math_Vec3f_Scale(&sp14C, 10.0f); + + vtx[j1].v = baseVtx; + vtx[j2].v = baseVtx; + + vtx[j1].v.ob[0] = Math_FNearbyIntF(sp158.x); + vtx[j1].v.ob[1] = Math_FNearbyIntF(sp158.y); + vtx[j1].v.ob[2] = Math_FNearbyIntF(sp158.z); + vtx[j1].v.cn[0] = func_800B0A24(sp1A4.r, sp19C.r, temp_f28); + vtx[j1].v.cn[1] = func_800B0A24(sp1A4.g, sp19C.g, temp_f28); + vtx[j1].v.cn[2] = func_800B0A24(sp1A4.b, sp19C.b, temp_f28); + vtx[j1].v.cn[3] = func_800B0A24(sp1A4.a, sp19C.a, temp_f28); + + vtx[j2].v.ob[0] = Math_FNearbyIntF(sp14C.x); + vtx[j2].v.ob[1] = Math_FNearbyIntF(sp14C.y); + vtx[j2].v.ob[2] = Math_FNearbyIntF(sp14C.z); + vtx[j2].v.cn[0] = func_800B0A24(sp1A0.r, sp198.r, temp_f28); + vtx[j2].v.cn[1] = func_800B0A24(sp1A0.g, sp198.g, temp_f28); + vtx[j2].v.cn[2] = func_800B0A24(sp1A0.b, sp198.b, temp_f28); + vtx[j2].v.cn[3] = func_800B0A24(sp1A0.a, sp198.a, temp_f28); + + // @recomp If this trail just spawned (timer == 2), set the previous vertex positions for the remaining vertices to the positions of the first two (interpolation). + // Otherwise, set them to the current position of the respective vertex (no interpolation). + if (elem->timer == 2) { + vtx[j1].v.obp[0] = vtx[0].v.ob[0]; + vtx[j1].v.obp[1] = vtx[0].v.ob[1]; + vtx[j1].v.obp[2] = vtx[0].v.ob[2]; + vtx[j2].v.obp[0] = vtx[1].v.ob[0]; + vtx[j2].v.obp[1] = vtx[1].v.ob[1]; + vtx[j2].v.obp[2] = vtx[1].v.ob[2]; + } + else { + vtx[j1].v.obp[0] = vtx[j1].v.ob[0]; + vtx[j1].v.obp[1] = vtx[j1].v.ob[1]; + vtx[j1].v.obp[2] = vtx[j1].v.ob[2]; + vtx[j2].v.obp[0] = vtx[j2].v.ob[0]; + vtx[j2].v.obp[1] = vtx[j2].v.ob[1]; + vtx[j2].v.obp[2] = vtx[j2].v.ob[2]; + } + } + + // @recomp Use gEXVertex in place of gSPVertex. + gEXVertex(POLY_XLU_DISP++, vtx, 16, 0); + gSP2Triangles(POLY_XLU_DISP++, 0, 1, 3, 0, 0, 3, 2, 0); + gSP2Triangles(POLY_XLU_DISP++, 2, 3, 5, 0, 2, 5, 4, 0); + gSP2Triangles(POLY_XLU_DISP++, 4, 5, 7, 0, 4, 7, 6, 0); + gSP2Triangles(POLY_XLU_DISP++, 6, 7, 9, 0, 6, 9, 8, 0); + gSP2Triangles(POLY_XLU_DISP++, 8, 9, 11, 0, 8, 11, 10, 0); + gSP2Triangles(POLY_XLU_DISP++, 10, 11, 13, 0, 10, 13, 12, 0); + gSP2Triangles(POLY_XLU_DISP++, 12, 13, 15, 0, 12, 15, 14, 0); + } + + CLOSE_DISPS(gfxCtx); +} + +// @recomp Patched to interpolate the vertices towards the front of the trail section if this is the last trail being drawn currently. +RECOMP_PATCH void EffectBlure_Draw(void* thisx, GraphicsContext* gfxCtx) { + EffectBlure* this = (EffectBlure*)thisx; + // @recomp Change the vertex type to VertexEX. + VertexEX* vtx; + EffectBlureElement* elem; + s32 i; + s32 j; + s32 phi_t2; + + OPEN_DISPS(gfxCtx); + + gSPMatrix(POLY_XLU_DISP++, &gIdentityMtx, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + + if (this->numElements != 0) { + if (this->flags == 0) { + Gfx_SetupDL38_Xlu(gfxCtx); + gDPPipeSync(POLY_XLU_DISP++); + + // @recomp Allocate using the size of VertexEX instead. + vtx = GRAPH_ALLOC(gfxCtx, 32 * sizeof(VertexEX)); + if (vtx == NULL) { + } else { + j = 0; + for (i = 0; i < this->numElements; i++) { + elem = &this->elements[i]; + + // @recomp Debug print. + // recomp_printf("Flag 0 %d:\n" + // " Blure: calcMode %08X flags: %04X addAngle %04X addAngle %04X elemDuration %d\n" + // " Element: state %08X timer: %d flags %04X\n", + // i, + // this->calcMode, this->flags, (u16)this->addAngleChange, (u16)this->addAngle, this->elemDuration, + // elem->state, elem->timer, elem->flags); + + if (elem->state == 1) { + f32 ratio = (f32)elem->timer / (f32)this->elemDuration; + + switch (this->calcMode) { + case 1: + vtx[j].v.ob[0] = func_800B09D0(elem->p1.x, elem->p2.x, ratio); + vtx[j].v.ob[1] = func_800B09D0(elem->p1.y, elem->p2.y, ratio); + vtx[j].v.ob[2] = func_800B09D0(elem->p1.z, elem->p2.z, ratio); + vtx[j + 1].v.ob[0] = elem->p2.x; + vtx[j + 1].v.ob[1] = elem->p2.y; + vtx[j + 1].v.ob[2] = elem->p2.z; + break; + + case 2: + vtx[j].v.ob[0] = elem->p1.x; + vtx[j].v.ob[1] = elem->p1.y; + vtx[j].v.ob[2] = elem->p1.z; + vtx[j + 1].v.ob[0] = func_800B09D0(elem->p2.x, elem->p1.x, ratio); + vtx[j + 1].v.ob[1] = func_800B09D0(elem->p2.y, elem->p1.y, ratio); + vtx[j + 1].v.ob[2] = func_800B09D0(elem->p2.z, elem->p1.z, ratio); + break; + + case 3: + ratio *= 0.5f; + vtx[j].v.ob[0] = func_800B09D0(elem->p1.x, elem->p2.x, ratio); + vtx[j].v.ob[1] = func_800B09D0(elem->p1.y, elem->p2.y, ratio); + vtx[j].v.ob[2] = func_800B09D0(elem->p1.z, elem->p2.z, ratio); + vtx[j + 1].v.ob[0] = func_800B09D0(elem->p2.x, elem->p1.x, ratio); + vtx[j + 1].v.ob[1] = func_800B09D0(elem->p2.y, elem->p1.y, ratio); + vtx[j + 1].v.ob[2] = func_800B09D0(elem->p2.z, elem->p1.z, ratio); + ratio *= 2.0f; + break; + + case 0: + default: + vtx[j].v.ob[0] = elem->p1.x; + vtx[j].v.ob[1] = elem->p1.y; + vtx[j].v.ob[2] = elem->p1.z; + vtx[j + 1].v.ob[0] = elem->p2.x; + vtx[j + 1].v.ob[1] = elem->p2.y; + vtx[j + 1].v.ob[2] = elem->p2.z; + break; + } + + // @recomp If this trail just spawned (timer == 1), set the previous vertex positions for this vertex that of the second previous vertex (interpolation). + // Otherwise, set them to the current position of the respective vertex (no interpolation). + if (elem->timer == 1 && j >= 2) { + vtx[j].v.obp[0] = vtx[j - 2].v.ob[0]; + vtx[j].v.obp[1] = vtx[j - 2].v.ob[1]; + vtx[j].v.obp[2] = vtx[j - 2].v.ob[2]; + } + else { + vtx[j].v.obp[0] = vtx[j].v.ob[0]; + vtx[j].v.obp[1] = vtx[j].v.ob[1]; + vtx[j].v.obp[2] = vtx[j].v.ob[2]; + } + + vtx[j].v.flag = 0; + vtx[j].v.tc[0] = 0; + vtx[j].v.tc[1] = 0; + vtx[j].v.cn[0] = func_800B0A24(this->p1StartColor[0], this->p1EndColor[0], ratio); + vtx[j].v.cn[1] = func_800B0A24(this->p1StartColor[1], this->p1EndColor[1], ratio); + vtx[j].v.cn[2] = func_800B0A24(this->p1StartColor[2], this->p1EndColor[2], ratio); + vtx[j].v.cn[3] = func_800B0A24(this->p1StartColor[3], this->p1EndColor[3], ratio); + j++; + + // @recomp If this trail just spawned (timer == 1), set the previous vertex positions for this vertex that of the second previous vertex (interpolation). + // Otherwise, set them to the current position of the respective vertex (no interpolation). + if (elem->timer == 1 && j >= 2) { + vtx[j].v.obp[0] = vtx[j - 2].v.ob[0]; + vtx[j].v.obp[1] = vtx[j - 2].v.ob[1]; + vtx[j].v.obp[2] = vtx[j - 2].v.ob[2]; + } + else { + vtx[j].v.obp[0] = vtx[j].v.ob[0]; + vtx[j].v.obp[1] = vtx[j].v.ob[1]; + vtx[j].v.obp[2] = vtx[j].v.ob[2]; + } + + vtx[j].v.flag = 0; + vtx[j].v.tc[0] = 0; + vtx[j].v.tc[1] = 0; + vtx[j].v.cn[0] = func_800B0A24(this->p2StartColor[0], this->p2EndColor[0], ratio); + vtx[j].v.cn[1] = func_800B0A24(this->p2StartColor[1], this->p2EndColor[1], ratio); + vtx[j].v.cn[2] = func_800B0A24(this->p2StartColor[2], this->p2EndColor[2], ratio); + vtx[j].v.cn[3] = func_800B0A24(this->p2StartColor[3], this->p2EndColor[3], ratio); + j++; + } + } + + phi_t2 = 0; + j = 0; + + // @recomp Use gEXVertex in place of gSPVertex. + gEXVertex(POLY_XLU_DISP++, vtx, 32, 0); + + for (i = 0; i < this->numElements; i++) { + elem = &this->elements[i]; + + if (elem->state == 0) { + phi_t2 = 0; + } else { + if (phi_t2 == 0) { + phi_t2 = 1; + } else { + gSP1Quadrangle(POLY_XLU_DISP++, j - 2, j - 1, j + 1, j, 0); + + if (this->unkFlag == 1) { + phi_t2 = 0; + } + } + j += 2; + } + } + } + } else if (this->drawMode <= EFF_BLURE_DRAW_MODE_SIMPLE_ALT_COLORS) { + EffectBlure_DrawSimple(this, gfxCtx); + } else { + EffectBlure_DrawSmooth(this, gfxCtx); + } + } + + CLOSE_DISPS(gfxCtx); +} diff --git a/recompcontrollerdb.txt b/recompcontrollerdb.txt index a4436a3..bbf3852 100644 --- a/recompcontrollerdb.txt +++ b/recompcontrollerdb.txt @@ -17,8 +17,12 @@ 03000000790000004e95000000000000,Hyperkin N64 Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a5,righty:a2,start:b9,platform:Windows, 03000000790000004418000000000000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Windows, 03000000790000004318000000000000,Mayflash GameCube Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Windows, +03000000242f00007300000000000000,Mayflash Magic NS,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows, +0300000079000000d218000000000000,Mayflash Magic NS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000d620000010a7000000000000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 03000000242f0000f400000000000000,Mayflash N64 Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a5,start:b9,platform:Windows, 03000000790000007918000000000000,Mayflash N64 Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,righttrigger:b7,rightx:a3,righty:a2,start:b8,platform:Windows, +030000008f0e00001330000000000000,Mayflash Controller Adapter,a:b1,b:b2,back:b8,dpdown:h0.8,dpleft:h0.2,dpright:h0.1,dpup:h0.4,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a3~,righty:a2,start:b9,x:b0,y:b3,platform:Windows, 03000000f70600000100000000000000,N64 Adaptoid,+rightx:b2,+righty:b1,-rightx:b4,-righty:b5,a:b0,b:b3,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,platform:Windows, 030000006f0e00001311000000000000,N64 Controller,+rightx:b10,+righty:b3,-rightx:b0,-righty:b11,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,platform:Windows, 03000000790000004518000000000000,NEXILUX GameCube Controller Adapter,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows, @@ -30,8 +34,10 @@ 030000009b2800006000000000000000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows, 030000009b2800006100000000000000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Windows, 030000009b2800006300000000000000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Windows, +030000009b2800006400000000000000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Windows, 03000000341200000400000000000000,RetroUSB N64 RetroPort,+rightx:b8,+righty:b10,-rightx:b9,-righty:b11,a:b7,b:b6,dpdown:b2,dpleft:b1,dpright:b0,dpup:b3,leftshoulder:b13,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b12,start:b4,platform:Windows, 03000000c82d00006928000000010000,8BitDo N64,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,platform:Mac OS X, +03000000c82d00001930000000000000,8bitdo 64 BT,platform:Windows,a:b0,b:b1,back:b17,guide:b10,start:b11,leftstick:b13,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b8,righttrigger:b9, 03000000260900008888000088020000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Mac OS X, 03000000790000004618000000010000,GameCube Controller Adapter,a:b4,b:b0,dpdown:b56,dpleft:b60,dpright:b52,dpup:b48,lefttrigger:a12,leftx:a0,lefty:a4,rightshoulder:b28,righttrigger:a16,rightx:a20,righty:a8,start:b36,x:b8,y:b12,platform:Mac OS X, 03000000242e0000ff0b000000010000,Hyperkin N64 Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,platform:Mac OS X, diff --git a/src/game/recomp_actor_api.cpp b/src/game/recomp_actor_api.cpp index 8cbe5a6..759b9a0 100644 --- a/src/game/recomp_actor_api.cpp +++ b/src/game/recomp_actor_api.cpp @@ -79,7 +79,7 @@ extern "C" void recomp_register_actor_extension(uint8_t* rdram, recomp_context* } if (actor_data_sizes.size() <= actor_type) { - actor_data_sizes.resize(2 * actor_type); + actor_data_sizes.resize(actor_type + 1); } // Increase the actor type's extension data size by the provided size (rounded up to a multiple of 16). diff --git a/src/game/recomp_data_api.cpp b/src/game/recomp_data_api.cpp index 2557abf..b07dbcf 100644 --- a/src/game/recomp_data_api.cpp +++ b/src/game/recomp_data_api.cpp @@ -569,8 +569,18 @@ void recomputil_u32_slotmap_size(uint8_t* rdram, recomp_context* ctx) { // memory slotmap. void recomputil_create_memory_slotmap(uint8_t* rdram, recomp_context* ctx) { - (void)rdram; - _return(ctx, memory_slotmaps.create()); + uint32_t element_size = _arg<0, uint32_t>(rdram, ctx); + + // Create the map. + uint32_t map_key = memory_slotmaps.create(); + + // Retrieve the map and set its element size to the provided value. + MemorySlotmap* map; + memory_slotmaps.get(map_key, &map); + map->second = element_size; + + // Return the created map's key. + _return(ctx, map_key); } void recomputil_destroy_memory_slotmap(uint8_t* rdram, recomp_context* ctx) { @@ -628,7 +638,7 @@ void recomputil_memory_slotmap_create(uint8_t* rdram, recomp_context* ctx) { // Store the allocated pointer. PTR(void)* value_ptr; map->first.get(key, &value_ptr); - MEM_W(0, *value_ptr) = addr; + *value_ptr = static_cast(addr); // Return the key. _return(ctx, key); diff --git a/src/main/main.cpp b/src/main/main.cpp index fbc5196..763344b 100644 --- a/src/main/main.cpp +++ b/src/main/main.cpp @@ -18,6 +18,13 @@ #else #include "SDL2/SDL.h" #include "SDL2/SDL_syswm.h" +// Undefine x11 macros that get included by SDL_syswm.h. +#undef None +#undef Status +#undef LockMask +#undef ControlMask +#undef Success +#undef Always #endif #include "recomp_ui.h" @@ -43,12 +50,13 @@ #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN #include +#include #include "SDL_syswm.h" #endif #include "../../lib/rt64/src/contrib/stb/stb_image.h" -const std::string version_string = "1.2.0"; +const std::string version_string = "1.2.1-dev"; template void exit_error(const char* str, Ts ...args) { @@ -579,6 +587,26 @@ int main(int argc, char** argv) { } #ifdef _WIN32 + // Set up high resolution timing period. + timeBeginPeriod(1); + + // Process arguments. + for (int i = 1; i < argc; i++) + { + if (strcmp(argv[i], "--show-console") == 0) + { + if (GetConsoleWindow() == nullptr) + { + AllocConsole(); + freopen("CONIN$", "r", stdin); + freopen("CONOUT$", "w", stderr); + freopen("CONOUT$", "w", stdout); + } + + break; + } + } + // Set up console output to accept UTF-8 on windows SetConsoleOutputCP(CP_UTF8); @@ -722,5 +750,10 @@ int main(int argc, char** argv) { release_preload(preload_context); } +#ifdef _WIN32 + // End high resolution timing period. + timeEndPeriod(1); +#endif + return EXIT_SUCCESS; } diff --git a/src/main/rt64_render_context.cpp b/src/main/rt64_render_context.cpp index 4994f34..2eff6f8 100644 --- a/src/main/rt64_render_context.cpp +++ b/src/main/rt64_render_context.cpp @@ -56,21 +56,6 @@ unsigned int DPC_BUFBUSY_REG = 0; unsigned int DPC_PIPEBUSY_REG = 0; unsigned int DPC_TMEM_REG = 0; -unsigned int VI_STATUS_REG = 0; -unsigned int VI_ORIGIN_REG = 0; -unsigned int VI_WIDTH_REG = 0; -unsigned int VI_INTR_REG = 0; -unsigned int VI_V_CURRENT_LINE_REG = 0; -unsigned int VI_TIMING_REG = 0; -unsigned int VI_V_SYNC_REG = 0; -unsigned int VI_H_SYNC_REG = 0; -unsigned int VI_LEAP_REG = 0; -unsigned int VI_H_START_REG = 0; -unsigned int VI_V_START_REG = 0; -unsigned int VI_V_BURST_REG = 0; -unsigned int VI_X_SCALE_REG = 0; -unsigned int VI_Y_SCALE_REG = 0; - void dummy_check_interrupts() {} RT64::UserConfiguration::Antialiasing compute_max_supported_aa(RT64::RenderSampleCounts bits) { @@ -250,20 +235,22 @@ zelda64::renderer::RT64Context::RT64Context(uint8_t* rdram, ultramodern::rendere appCore.DPC_PIPEBUSY_REG = &DPC_PIPEBUSY_REG; appCore.DPC_TMEM_REG = &DPC_TMEM_REG; - appCore.VI_STATUS_REG = &VI_STATUS_REG; - appCore.VI_ORIGIN_REG = &VI_ORIGIN_REG; - appCore.VI_WIDTH_REG = &VI_WIDTH_REG; - appCore.VI_INTR_REG = &VI_INTR_REG; - appCore.VI_V_CURRENT_LINE_REG = &VI_V_CURRENT_LINE_REG; - appCore.VI_TIMING_REG = &VI_TIMING_REG; - appCore.VI_V_SYNC_REG = &VI_V_SYNC_REG; - appCore.VI_H_SYNC_REG = &VI_H_SYNC_REG; - appCore.VI_LEAP_REG = &VI_LEAP_REG; - appCore.VI_H_START_REG = &VI_H_START_REG; - appCore.VI_V_START_REG = &VI_V_START_REG; - appCore.VI_V_BURST_REG = &VI_V_BURST_REG; - appCore.VI_X_SCALE_REG = &VI_X_SCALE_REG; - appCore.VI_Y_SCALE_REG = &VI_Y_SCALE_REG; + ultramodern::renderer::ViRegs* vi_regs = ultramodern::renderer::get_vi_regs(); + + appCore.VI_STATUS_REG = &vi_regs->VI_STATUS_REG; + appCore.VI_ORIGIN_REG = &vi_regs->VI_ORIGIN_REG; + appCore.VI_WIDTH_REG = &vi_regs->VI_WIDTH_REG; + appCore.VI_INTR_REG = &vi_regs->VI_INTR_REG; + appCore.VI_V_CURRENT_LINE_REG = &vi_regs->VI_V_CURRENT_LINE_REG; + appCore.VI_TIMING_REG = &vi_regs->VI_TIMING_REG; + appCore.VI_V_SYNC_REG = &vi_regs->VI_V_SYNC_REG; + appCore.VI_H_SYNC_REG = &vi_regs->VI_H_SYNC_REG; + appCore.VI_LEAP_REG = &vi_regs->VI_LEAP_REG; + appCore.VI_H_START_REG = &vi_regs->VI_H_START_REG; + appCore.VI_V_START_REG = &vi_regs->VI_V_START_REG; + appCore.VI_V_BURST_REG = &vi_regs->VI_V_BURST_REG; + appCore.VI_X_SCALE_REG = &vi_regs->VI_X_SCALE_REG; + appCore.VI_Y_SCALE_REG = &vi_regs->VI_Y_SCALE_REG; // Set up the RT64 application configuration fields. RT64::ApplicationConfiguration appConfig; @@ -338,9 +325,7 @@ void zelda64::renderer::RT64Context::send_dl(const OSTask* task) { app->processDisplayLists(app->core.RDRAM, task->t.data_ptr & 0x3FFFFFF, 0, true); } -void zelda64::renderer::RT64Context::update_screen(uint32_t vi_origin) { - VI_ORIGIN_REG = vi_origin; - +void zelda64::renderer::RT64Context::update_screen() { app->updateScreen(); } diff --git a/src/ui/ui_state.cpp b/src/ui/ui_state.cpp index d1201fb..1941c5c 100644 --- a/src/ui/ui_state.cpp +++ b/src/ui/ui_state.cpp @@ -900,6 +900,13 @@ void recompui::drop_files(const std::list &file_list) { return; } + recompui::set_config_tab(recompui::ConfigTab::Mods); + // If the config menu isn't open, open it in the mods tab. + if (!recompui::is_context_shown(recompui::get_config_context_id())) { + recompui::hide_all_contexts(); + recompui::show_context(recompui::get_config_context_id(), ""); + } + recompui::open_notification("Installing Mods", "Please Wait"); // TODO: Needs a progress callback and a prompt for every mod that needs to be confirmed to be overwritten. // TODO: Run this on a background thread and use the callbacks to advance the state instead of blocking.