diff --git a/soh/soh/Enhancements/Graphics/Disable2DBackgrounds.cpp b/soh/soh/Enhancements/Graphics/Disable2DBackgrounds.cpp new file mode 100644 index 000000000..9e9faafac --- /dev/null +++ b/soh/soh/Enhancements/Graphics/Disable2DBackgrounds.cpp @@ -0,0 +1,161 @@ +#include +#include "soh/Enhancements/enhancementTypes.h" +#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" +#include "soh/ShipInit.hpp" + +extern "C" { +extern SaveContext gSaveContext; +extern PlayState* gPlayState; +#include "macros.h" +#include "variables.h" +} + +#define CVAR_NAME CVAR_ENHANCEMENT("3DSceneRender") +#define CVAR_VALUE CVarGetInteger(CVAR_NAME, 0) + +std::vector fogControlList = { + SCENE_MARKET_ENTRANCE_DAY, + SCENE_MARKET_ENTRANCE_NIGHT, + SCENE_MARKET_ENTRANCE_RUINS, + SCENE_BACK_ALLEY_DAY, + SCENE_BACK_ALLEY_NIGHT, + SCENE_MARKET_DAY, + SCENE_MARKET_NIGHT, + SCENE_MARKET_RUINS, + SCENE_TEMPLE_OF_TIME_EXTERIOR_DAY, + SCENE_TEMPLE_OF_TIME_EXTERIOR_NIGHT, + SCENE_TEMPLE_OF_TIME_EXTERIOR_RUINS, + SCENE_KNOW_IT_ALL_BROS_HOUSE, + SCENE_TWINS_HOUSE, + SCENE_MIDOS_HOUSE, + SCENE_SARIAS_HOUSE, + SCENE_BACK_ALLEY_HOUSE, + SCENE_BAZAAR, + SCENE_KOKIRI_SHOP, + SCENE_GORON_SHOP, + SCENE_ZORA_SHOP, + SCENE_POTION_SHOP_KAKARIKO, + SCENE_POTION_SHOP_MARKET, + SCENE_BOMBCHU_SHOP, + SCENE_HAPPY_MASK_SHOP, + SCENE_LINKS_HOUSE, + SCENE_DOG_LADY_HOUSE, + SCENE_STABLE, + SCENE_IMPAS_HOUSE, + SCENE_CARPENTERS_TENT, + SCENE_GRAVEKEEPERS_HUT, +}; + +std::vector skyboxSceneControlList = { + SCENE_MARKET_ENTRANCE_DAY, + SCENE_MARKET_ENTRANCE_NIGHT, + SCENE_MARKET_ENTRANCE_RUINS, + SCENE_BACK_ALLEY_DAY, + SCENE_BACK_ALLEY_NIGHT, + SCENE_MARKET_DAY, + SCENE_MARKET_NIGHT, + SCENE_MARKET_RUINS, + SCENE_CASTLE_COURTYARD_ZELDA, + SCENE_TEMPLE_OF_TIME_EXTERIOR_DAY, + SCENE_TEMPLE_OF_TIME_EXTERIOR_NIGHT, + SCENE_TEMPLE_OF_TIME_EXTERIOR_RUINS, + SCENE_FOREST_TEMPLE, +}; + +std::vector skyboxIdControlList = { + SKYBOX_BAZAAR, + SKYBOX_HOUSE_LINK, + SKYBOX_MARKET_ADULT, + SKYBOX_MARKET_CHILD_DAY, + SKYBOX_MARKET_CHILD_NIGHT, + SKYBOX_HAPPY_MASK_SHOP, + SKYBOX_HOUSE_KNOW_IT_ALL_BROTHERS, + SKYBOX_HOUSE_OF_TWINS, + SKYBOX_STABLES, + SKYBOX_HOUSE_KAKARIKO, + SKYBOX_KOKIRI_SHOP, + SKYBOX_GORON_SHOP, + SKYBOX_ZORA_SHOP, + SKYBOX_POTION_SHOP_KAKARIKO, + SKYBOX_POTION_SHOP_MARKET, + SKYBOX_HOUSE_RICHARD, + SKYBOX_HOUSE_IMPA, + SKYBOX_TENT, + SKYBOX_HOUSE_MIDO, + SKYBOX_HOUSE_SARIA, + SKYBOX_HOUSE_ALLEY, +}; + +void Register3DPreRenderedScenes() { + COND_HOOK(AfterSceneCommands, CVAR_VALUE, [](int16_t sceneNum) { + // Check if this scene is in the skyboxControlList + bool shouldControlSkybox = false; + for (const auto& scene : skyboxSceneControlList) { + if (sceneNum == scene) { + shouldControlSkybox = true; + break; + } + } + + if (shouldControlSkybox) { + // Add a skybox on scenes from skyboxSceneControlList + gPlayState->envCtx.skyboxDisabled = false; + + // Replace skybox with normal sky + gPlayState->skyboxId = SKYBOX_NORMAL_SKY; + // Apply the always cloudy skybox as an adult for Temple of Time and the Market + if (sceneNum == SCENE_TEMPLE_OF_TIME_EXTERIOR_RUINS || sceneNum == SCENE_MARKET_RUINS || + sceneNum == SCENE_MARKET_ENTRANCE_RUINS) { + gWeatherMode = 3; + } + } + }); + + COND_HOOK(OnPlayDrawBegin, CVAR_VALUE, []() { + if (!CVarGetInteger(CVAR_ENHANCEMENT("3DSceneRender"), 0)) { + return; + } + + for (auto& scene : fogControlList) { + if (scene == gPlayState->sceneNum) { + if ((HREG(80) != 10) || (HREG(82) != 0)) { + // Furthest possible fog and zFar + gPlayState->view.zFar = 12800; + gPlayState->lightCtx.fogNear = 996; // Set to 1000 to complete disable fog entirely + gPlayState->lightCtx.fogFar = 12800; + // General gray fog color + gPlayState->lightCtx.fogColor[0] = 100; + gPlayState->lightCtx.fogColor[1] = 100; + gPlayState->lightCtx.fogColor[2] = 100; + } + break; + } + } + }); + REGISTER_VB_SHOULD(VB_DRAW_2D_BACKGROUND, { + if (CVAR_VALUE) { + *should = false; + return; + } + }); + + REGISTER_VB_SHOULD(VB_LOAD_SKYBOX, { + if (!gPlayState) { + return; + } + + if (!CVAR_VALUE) { + return; + } + + for (auto& skybox : skyboxIdControlList) { + if (gPlayState->skyboxCtx.skyboxId == skybox) { + gPlayState->skyboxCtx.unk_140 = 0; + *should = false; + return; + } + } + }); +} + +static RegisterShipInitFunc PreRender3DInitFunc(Register3DPreRenderedScenes, { CVAR_NAME }); \ No newline at end of file diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor_HookTable.h b/soh/soh/Enhancements/game-interactor/GameInteractor_HookTable.h index 2b28198d6..b5b1cfbfe 100644 --- a/soh/soh/Enhancements/game-interactor/GameInteractor_HookTable.h +++ b/soh/soh/Enhancements/game-interactor/GameInteractor_HookTable.h @@ -42,6 +42,7 @@ DEFINE_HOOK(OnPlayerFirstPersonControl, (Player * player)); DEFINE_HOOK(OnPlayerProcessStick, ()); DEFINE_HOOK(OnPlayerShieldControl, (float_t * sp50, float_t* sp54)); DEFINE_HOOK(OnPlayDestroy, ()); +DEFINE_HOOK(OnPlayDrawBegin, ()); DEFINE_HOOK(OnPlayDrawEnd, ()); DEFINE_HOOK(OnVanillaBehavior, (GIVanillaBehavior flag, bool* result, va_list originalArgs)); DEFINE_HOOK(OnSaveFile, (int32_t fileNum)); diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.cpp b/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.cpp index f69cc29af..f374aa2d7 100644 --- a/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.cpp +++ b/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.cpp @@ -186,6 +186,10 @@ void GameInteractor_ExecuteOnPlayDestroy() { GameInteractor::Instance->ExecuteHooks(); } +void GameInteractor_ExecuteOnPlayDrawBegin() { + GameInteractor::Instance->ExecuteHooks(); +} + void GameInteractor_ExecuteOnPlayDrawEnd() { GameInteractor::Instance->ExecuteHooks(); } diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.h b/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.h index a6f1563f2..e22d12dbd 100644 --- a/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.h +++ b/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.h @@ -45,6 +45,7 @@ void GameInteractor_ExecuteOnPlayerShieldControl(float_t* sp50, float_t* sp54); void GameInteractor_ExecuteOnPlayerProcessStick(); void GameInteractor_ExecuteOnShopSlotChangeHooks(uint8_t cursorIndex, int16_t price); void GameInteractor_ExecuteOnPlayDestroy(); +void GameInteractor_ExecuteOnPlayDrawBegin(); void GameInteractor_ExecuteOnPlayDrawEnd(); bool GameInteractor_Should(GIVanillaBehavior flag, uint32_t result, ...); diff --git a/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h b/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h index 6eada52f6..cc32829b7 100644 --- a/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h +++ b/soh/soh/Enhancements/game-interactor/vanilla-behavior/GIVanillaBehavior.h @@ -2257,6 +2257,20 @@ typedef enum { // #### `result` // ```c + // CVarGetInteger(CVAR_ENHANCEMENT("3DSceneRender"), 0) + // ``` + // #### `args` + // - None + VB_DRAW_2D_BACKGROUND, + + // #### `result` + // ```c + // CVarGetInteger(CVAR_ENHANCEMENT("3DSceneRender"), 0) + // ``` + // #### `args` + // - None + VB_LOAD_SKYBOX, + // true // ``` // #### `args` @@ -2270,6 +2284,7 @@ typedef enum { // #### `args` // - `*Player` VB_SET_STATIC_FLOOR_TYPE, + } GIVanillaBehavior; #endif diff --git a/soh/soh/SohGui/SohMenuEnhancements.cpp b/soh/soh/SohGui/SohMenuEnhancements.cpp index 6e967951d..2f37291af 100644 --- a/soh/soh/SohGui/SohMenuEnhancements.cpp +++ b/soh/soh/SohGui/SohMenuEnhancements.cpp @@ -555,12 +555,17 @@ void SohMenu::AddMenuEnhancements() { .Options(CheckboxOptions().Tooltip( "Disables Grottos rotating with the Camera. To be used in conjuction with mods that want to " "replace grottos with 3D objects.")); + AddWidget(path, "Disable 2D Pre-Rendered Scenes", WIDGET_CVAR_CHECKBOX) + .CVar(CVAR_ENHANCEMENT("3DSceneRender")) + .RaceDisable(false) + .Options(CheckboxOptions().Tooltip("Disables 2D pre-rendered backgrounds. Enable this when using a mod that " + "implements 3D backdrops for these areas.\n" + "Requires Scene Change to alter.")); AddWidget(path, "Ingame Text Spacing: %d", WIDGET_CVAR_SLIDER_INT) .CVar(CVAR_ENHANCEMENT("TextSpacing")) .RaceDisable(false) .Options(IntSliderOptions().Min(4).Max(6).DefaultValue(6).Tooltip( "Space between text characters (useful for HD font textures).")); - AddWidget(path, "Models & Textures", WIDGET_SEPARATOR_TEXT); AddWidget(path, "Disable LOD", WIDGET_CVAR_CHECKBOX) .CVar(CVAR_ENHANCEMENT("DisableLOD")) diff --git a/soh/soh/z_play_otr.cpp b/soh/soh/z_play_otr.cpp index 23e61261c..5055b969b 100644 --- a/soh/soh/z_play_otr.cpp +++ b/soh/soh/z_play_otr.cpp @@ -79,6 +79,7 @@ void OTRPlay_InitScene(PlayState* play, s32 spawn) { YREG(15) = 0; gSaveContext.worldMapArea = 0; OTRScene_ExecuteCommands(play, (SOH::Scene*)play->sceneSegment); + GameInteractor_ExecuteAfterSceneCommands(play->sceneNum); Play_InitEnvironment(play, play->skyboxId); /* auto data = static_cast(Ship::Context::GetInstance() diff --git a/soh/soh/z_scene_otr.cpp b/soh/soh/z_scene_otr.cpp index b4f8a29e8..1baf6151d 100644 --- a/soh/soh/z_scene_otr.cpp +++ b/soh/soh/z_scene_otr.cpp @@ -472,6 +472,10 @@ extern "C" s32 OTRfunc_800973FC(PlayState* play, RoomContext* roomCtx) { gSegments[3] = VIRTUAL_TO_PHYSICAL(roomCtx->unk_34); OTRScene_ExecuteCommands(play, (SOH::Scene*)roomCtx->roomToLoad); + if (!GameInteractor_Should(VB_DRAW_2D_BACKGROUND, true)) { + play->envCtx.skyboxDisabled = false; + } + Player_SetBootData(play, GET_PLAYER(play)); Actor_SpawnTransitionActors(play, &play->actorCtx); diff --git a/soh/src/code/z_play.c b/soh/src/code/z_play.c index dfc832fc7..b1a714dcb 100644 --- a/soh/src/code/z_play.c +++ b/soh/src/code/z_play.c @@ -1390,6 +1390,8 @@ void Play_Draw(PlayState* play) { Gfx_SetupFrame(gfxCtx, 0, 0, 0); if ((HREG(80) != 10) || (HREG(82) != 0)) { + GameInteractor_ExecuteOnPlayDrawBegin(); + POLY_OPA_DISP = Play_SetFog(play, POLY_OPA_DISP); POLY_XLU_DISP = Play_SetFog(play, POLY_XLU_DISP); diff --git a/soh/src/code/z_room.c b/soh/src/code/z_room.c index 60fa3f0ff..493752555 100644 --- a/soh/src/code/z_room.c +++ b/soh/src/code/z_room.c @@ -5,6 +5,7 @@ #include "global.h" #include "vt.h" #include "soh/Enhancements/game-interactor/GameInteractor.h" +#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" #include #include @@ -256,6 +257,9 @@ s32 swapAndConvertJPEG(void* data) { void Room_DrawBackground2D(Gfx** gfxP, void* tex, void* tlut, u16 width, u16 height, u8 fmt, u8 siz, u16 tlutMode, u16 tlutCount, f32 offsetX, f32 offsetY) { + if (!GameInteractor_Should(VB_DRAW_2D_BACKGROUND, true)) { + return; + } Gfx* gfx = *gfxP; uObjBg* bg; diff --git a/soh/src/code/z_vr_box.c b/soh/src/code/z_vr_box.c index c11db1605..f03f9dc7f 100644 --- a/soh/src/code/z_vr_box.c +++ b/soh/src/code/z_vr_box.c @@ -71,6 +71,9 @@ #include "assets/textures/skyboxes/vr_holy1_static.h" #include "assets/textures/skyboxes/vr_holy1_pal_static.h" +#include "soh/Enhancements/game-interactor/GameInteractor.h" +#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" + u32 D_8012AC90[4] = { 0x00000000, 0x00010000, @@ -449,17 +452,23 @@ void func_800AF178(SkyboxContext* skyboxCtx, s32 arg1) { void LoadSkyboxTex(SkyboxContext* skyboxCtx, int segmentIndex, int imageIndex, char* tex, int width, int height, int offsetW, int offsetH) { - skyboxCtx->textures[segmentIndex][imageIndex] = tex; + if (GameInteractor_Should(VB_LOAD_SKYBOX, true)) { + skyboxCtx->textures[segmentIndex][imageIndex] = tex; + } } void LoadSkyboxTexAtOffset(SkyboxContext* skyboxCtx, int segmentIndex, int imageIndex, char* tex, int width, int height, int offset) { - skyboxCtx->textures[segmentIndex][imageIndex] = tex; + if (GameInteractor_Should(VB_LOAD_SKYBOX, true)) { + skyboxCtx->textures[segmentIndex][imageIndex] = tex; + } } void LoadSkyboxPalette(SkyboxContext* skyboxCtx, int paletteIndex, char* palTex, int width, int height) { - skyboxCtx->palettes[paletteIndex] = palTex; - skyboxCtx->palette_size = width * height; + if (GameInteractor_Should(VB_LOAD_SKYBOX, true)) { + skyboxCtx->palettes[paletteIndex] = palTex; + skyboxCtx->palette_size = width * height; + } } static const char* sSBVRFine0Tex[] = { gSunriseSkybox1Tex, gSunriseSkybox2Tex, gSunriseSkybox3Tex, gSunriseSkybox4Tex,