diff options
| author | Louis <35883445+louist103@users.noreply.github.com> | 2023-11-14 23:56:51 -0500 |
|---|---|---|
| committer | Louis <35883445+louist103@users.noreply.github.com> | 2023-11-15 18:48:39 -0500 |
| commit | 4971e8ca91fe32a2f88e9d971685d95e2582e912 (patch) | |
| tree | 8c9885bb468bc45d6015a52772ad2bf6751222d2 | |
| parent | 2de8af4d4ea9bfc4759f262f9d0d21bb09fe6911 (diff) | |
ZAPD builds an OTR
add 2s2h
206 files changed, 15105 insertions, 164 deletions
diff --git a/mm/.gitignore b/mm/.gitignore index 8c5705f18..dc0447c84 100644 --- a/mm/.gitignore +++ b/mm/.gitignore @@ -7,7 +7,6 @@ __pycache__/ .vscode/ .vs/ .idea/ -CMakeLists.txt cmake-build-debug venv/ tags @@ -55,3 +54,4 @@ docs/doxygen/ .python-version .make_options .*env +*.otr
\ No newline at end of file diff --git a/mm/2s2h/BenPort.cpp b/mm/2s2h/BenPort.cpp new file mode 100644 index 000000000..efc63589f --- /dev/null +++ b/mm/2s2h/BenPort.cpp @@ -0,0 +1,1340 @@ +#include "BenPort.h" +#include <iostream> +#include <algorithm> +#include <filesystem> +#include <fstream> +#include <chrono> + +#include <ResourceManager.h> +#include <File.h> +#include <DisplayList.h> +#include <Window.h> +#include <GameVersions.h> + +#include "z64animation.h" +#include "z64bgcheck.h" +#include <libultraship/libultra/gbi.h> +#ifdef _WIN32 +#include <Windows.h> +#else +#include <time.h> +#endif +#include <Array.h> +#include <stb/stb_image.h> +#define DRMP3_IMPLEMENTATION +#include <dr_libs/mp3.h> +#define DRWAV_IMPLEMENTATION +#include <dr_libs/wav.h> +#include <AudioPlayer.h> +#include "variables.h" +#include "z64.h" +#include "macros.h" +#include <Utils/StringHelper.h> + +#include <Fast3D/gfx_pc.h> +#include <Fast3D/gfx_rendering_api.h> + +#ifdef __APPLE__ +#include <SDL_scancode.h> +#else +#include <SDL2/SDL_scancode.h> +#endif +#include "Extractor/Extract.h" +// OTRTODO +//#include <functions.h> + + +#ifdef ENABLE_CROWD_CONTROL +#include "Enhancements/crowd-control/CrowdControl.h" +CrowdControl* CrowdControl::Instance; +#endif + +#include <libultraship/libultraship.h> +#include <SohGui.hpp> + +// Resource Types/Factories +#include "2s2h/resource/type/Animation.h" +#include "2s2h/resource/type/AudioSample.h" +#include "2s2h/resource/type/AudioSequence.h" +#include "2s2h/resource/type/AudioSoundFont.h" +#include "2s2h/resource/type/CollisionHeader.h" +#include "2s2h/resource/type/Cutscene.h" +#include "2s2h/resource/type/Path.h" +#include "2s2h/resource/type/PlayerAnimation.h" +#include "2s2h/resource/type/Scene.h" +#include "2s2h/resource/type/Skeleton.h" +#include "2s2h/resource/type/SkeletonLimb.h" +#include "2s2h/resource/type/Text.h" +#include "2s2h/resource/importer/AnimationFactory.h" +#include "2s2h/resource/importer/AudioSampleFactory.h" +#include "2s2h/resource/importer/AudioSequenceFactory.h" +#include "2s2h/resource/importer/AudioSoundFontFactory.h" +#include "2s2h/resource/importer/CollisionHeaderFactory.h" +#include "2s2h/resource/importer/CutsceneFactory.h" +#include "2s2h/resource/importer/PathFactory.h" +#include "2s2h/resource/importer/PlayerAnimationFactory.h" +#include "2s2h/resource/importer/SceneFactory.h" +#include "2s2h/resource/importer/SkeletonFactory.h" +#include "2s2h/resource/importer/SkeletonLimbFactory.h" +#include "2s2h/resource/importer/TextFactory.h" +#include "2s2h/resource/importer/TextMMFactory.h" +#include "2s2h/resource/importer/BackgroundFactory.h" +#include "2s2h/resource/importer/TextureAnimationFactory.h" + +OTRGlobals* OTRGlobals::Instance; + +extern "C" char** cameraStrings; +std::vector<std::shared_ptr<std::string>> cameraStdStrings; + +Color_RGB8 kokiriColor = { 0x1E, 0x69, 0x1B }; +Color_RGB8 goronColor = { 0x64, 0x14, 0x00 }; +Color_RGB8 zoraColor = { 0x00, 0xEC, 0x64 }; + + +OTRGlobals::OTRGlobals() { + std::vector<std::string> OTRFiles; + //std::string mqPath = LUS::Context::LocateFileAcrossAppDirs("oot-mq.otr", appShortName); + //if (std::filesystem::exists(mqPath)) { + // OTRFiles.push_back(mqPath); + //} + std::string ootPath = LUS::Context::LocateFileAcrossAppDirs("mm.otr", appShortName); + if (std::filesystem::exists(ootPath)) { + OTRFiles.push_back(ootPath); + } + std::string sohOtrPath = LUS::Context::GetPathRelativeToAppBundle("soh.otr"); + if (std::filesystem::exists(sohOtrPath)) { + OTRFiles.push_back(sohOtrPath); + } + std::string patchesPath = LUS::Context::LocateFileAcrossAppDirs("mods", appShortName); + if (patchesPath.length() > 0 && std::filesystem::exists(patchesPath)) { + if (std::filesystem::is_directory(patchesPath)) { + for (const auto& p : std::filesystem::recursive_directory_iterator(patchesPath)) { + if (StringHelper::IEquals(p.path().extension().string(), ".otr")) { + OTRFiles.push_back(p.path().generic_string()); + } + } + } + } + std::unordered_set<uint32_t> ValidHashes = { OOT_PAL_MQ, OOT_NTSC_JP_MQ, OOT_NTSC_US_MQ, OOT_PAL_GC_MQ_DBG, + OOT_NTSC_US_10, OOT_NTSC_US_11, OOT_NTSC_US_12, OOT_PAL_10, + OOT_PAL_11, OOT_NTSC_JP_GC_CE, OOT_NTSC_JP_GC, OOT_NTSC_US_GC, + OOT_PAL_GC, OOT_PAL_GC_DBG1, OOT_PAL_GC_DBG2 }; + // tell LUS to reserve 3 SoH specific threads (Game, Audio, Save) + context = LUS::Context::CreateInstance("2 Ship 2 Harkinian", appShortName, "shipofharkinian.json", OTRFiles, {}, 3); + context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory( + LUS::ResourceType::SOH_Animation, "Animation", std::make_shared<LUS::AnimationFactory>()); + context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory( + LUS::ResourceType::SOH_PlayerAnimation, "PlayerAnimation", std::make_shared<LUS::PlayerAnimationFactory>()); + context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory( + LUS::ResourceType::SOH_Room, "Room", std::make_shared<LUS::SceneFactory>()); // Is room scene? maybe? + context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory( + LUS::ResourceType::SOH_CollisionHeader, "CollisionHeader", std::make_shared<LUS::CollisionHeaderFactory>()); + context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory( + LUS::ResourceType::SOH_Skeleton, "Skeleton", std::make_shared<LUS::SkeletonFactory>()); + context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory( + LUS::ResourceType::SOH_SkeletonLimb, "SkeletonLimb", std::make_shared<LUS::SkeletonLimbFactory>()); + // TODO should we use a custom command for this? + context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SOH_Path, "Path", + std::make_shared<LUS::PathFactoryMM>()); + context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory( + LUS::ResourceType::SOH_Cutscene, "Cutscene", std::make_shared<LUS::CutsceneFactory>()); + context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SOH_Text, "Text", + std::make_shared<LUS::TextFactory>()); + context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SOH_TextMM, "TextMM", + std::make_shared<LUS::TextMMFactory>()); + context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory( + LUS::ResourceType::SOH_AudioSample, "AudioSample", std::make_shared<LUS::AudioSampleFactory>()); + context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory( + LUS::ResourceType::SOH_AudioSoundFont, "AudioSoundFont", std::make_shared<LUS::AudioSoundFontFactory>()); + context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory( + LUS::ResourceType::SOH_AudioSequence, "AudioSequence", std::make_shared<LUS::AudioSequenceFactory>()); + context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory( + LUS::ResourceType::SOH_Background, "Background", std::make_shared<LUS::BackgroundFactory>()); + context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory( + LUS::ResourceType::TSH_TexAnim, "TextureAnimation", std::make_shared<LUS::TextureAnimationFactory>()); + + //gSaveStateMgr = std::make_shared<SaveStateMgr>(); + //gRandomizer = std::make_shared<Randomizer>(); + hasMasterQuest = hasOriginal = false; + + // Move the camera strings from read only memory onto the heap (writable memory) + // This is in OTRGlobals right now because this is a place that will only ever be run once at the beginning of + // startup. We should probably find some code in db_camera that does initialization and only run once, and then + // dealloc on deinitialization. + //cameraStrings = (char**)malloc(sizeof(constCameraStrings)); + //for (int32_t i = 0; i < sizeof(constCameraStrings) / sizeof(char*); i++) { + // // OTRTODO: never deallocated... + // auto dup = strdup(constCameraStrings[i]); + // cameraStrings[i] = dup; + //} + + auto versions = context->GetResourceManager()->GetArchive()->GetGameVersions(); + #if 0 + for (uint32_t version : versions) { + if (!ValidHashes.contains(version)) { +#if defined(__SWITCH__) + SPDLOG_ERROR("Invalid OTR File!"); +#elif defined(__WIIU__) + LUS::WiiU::ThrowInvalidOTR(); +#else + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Invalid OTR File", + "Attempted to load an invalid OTR file. Try regenerating.", nullptr); + SPDLOG_ERROR("Invalid OTR File!"); +#endif + exit(1); + } + switch (version) { + case OOT_PAL_MQ: + case OOT_NTSC_JP_MQ: + case OOT_NTSC_US_MQ: + case OOT_PAL_GC_MQ_DBG: + hasMasterQuest = true; + break; + case OOT_NTSC_US_10: + case OOT_NTSC_US_11: + case OOT_NTSC_US_12: + case OOT_PAL_10: + case OOT_PAL_11: + case OOT_NTSC_JP_GC_CE: + case OOT_NTSC_JP_GC: + case OOT_NTSC_US_GC: + case OOT_PAL_GC: + case OOT_PAL_GC_DBG1: + case OOT_PAL_GC_DBG2: + hasOriginal = true; + break; + default: + break; + } + } + #endif +} + +OTRGlobals::~OTRGlobals() { +} + +bool OTRGlobals::HasMasterQuest() { + return hasMasterQuest; +} + +bool OTRGlobals::HasOriginal() { + return hasOriginal; +} + +uint32_t OTRGlobals::GetInterpolationFPS() { + if (LUS::Context::GetInstance()->GetWindow()->GetWindowBackend() == LUS::WindowBackend::DX11) { + return CVarGetInteger("gInterpolationFPS", 20); + } + + if (CVarGetInteger("gMatchRefreshRate", 0)) { + return LUS::Context::GetInstance()->GetWindow()->GetCurrentRefreshRate(); + } + + return std::min<uint32_t>(LUS::Context::GetInstance()->GetWindow()->GetCurrentRefreshRate(), + CVarGetInteger("gInterpolationFPS", 20)); +} + +struct ExtensionEntry { + std::string path; + std::string ext; +}; + +extern uintptr_t clearMtx; +extern "C" Mtx gMtxClear; +extern "C" MtxF gMtxFClear; +extern "C" void OTRMessage_Init(); +extern "C" void AudioMgr_CreateNextAudioBuffer(s16* samples, u32 num_samples); +extern "C" void AudioPlayer_Play(const uint8_t* buf, uint32_t len); +extern "C" int AudioPlayer_Buffered(void); +extern "C" int AudioPlayer_GetDesiredBuffered(void); +extern "C" void ResourceMgr_LoadDirectory(const char* resName); +std::unordered_map<std::string, ExtensionEntry> ExtensionCache; + +extern "C" void OTRExtScanner() { + auto lst = *LUS::Context::GetInstance()->GetResourceManager()->GetArchive()->ListFiles("*").get(); + + for (auto& rPath : lst) { + std::vector<std::string> raw = StringHelper::Split(rPath, "."); + std::string ext = raw[raw.size() - 1]; + std::string nPath = rPath.substr(0, rPath.size() - (ext.size() + 1)); + replace(nPath.begin(), nPath.end(), '\\', '/'); + + ExtensionCache[nPath] = { rPath, ext }; + } +} + +extern "C" void InitOTR() { +#if not defined(__SWITCH__) && not defined(__WIIU__) + if (!std::filesystem::exists(LUS::Context::LocateFileAcrossAppDirs("mm.otr", appShortName))) { + std::string installPath = LUS::Context::GetAppBundlePath(); + if (!std::filesystem::exists(installPath + "/assets/extractor")) { + Extractor::ShowErrorBox( + "Extractor assets not found", + "No OTR files found. Missing assets/extractor folder needed to generate OTR file. Exiting..."); + exit(1); + } + + bool generatedOtrIsMQ = false; + if (Extractor::ShowYesNoBox("No OTR Files", "No OTR files found. Generate one now?") == IDYES) { + Extractor extract; + if (!extract.Run()) { + Extractor::ShowErrorBox("Error", "An error occured, no OTR file was generated. Exiting..."); + exit(1); + } + extract.CallZapd(installPath, LUS::Context::GetAppDirectoryPath(appShortName)); + generatedOtrIsMQ = extract.IsMasterQuest(); + } else { + exit(1); + } + } +#endif + +#ifdef __SWITCH__ + LUS::Switch::Init(LUS::PreInitPhase); +#elif defined(__WIIU__) + LUS::WiiU::Init("soh"); +#endif + + OTRGlobals::Instance = new OTRGlobals(); + SohGui::SetupGuiElements(); + + clearMtx = (uintptr_t)&gMtxClear; + //OTRMessage_Init(); + //OTRExtScanner(); + time_t now = time(NULL); + tm* tm_now = localtime(&now); + if (tm_now->tm_mon == 11 && tm_now->tm_mday >= 24 && tm_now->tm_mday <= 25) { + CVarRegisterInteger("gLetItSnow", 1); + } else { + CVarClear("gLetItSnow"); + } + + srand(now); +#ifdef ENABLE_CROWD_CONTROL + CrowdControl::Instance = new CrowdControl(); + CrowdControl::Instance->Init(); + if (CVarGetInteger("gCrowdControl", 0)) { + CrowdControl::Instance->Enable(); + } else { + CrowdControl::Instance->Disable(); + } +#endif + + std::shared_ptr<LUS::Config> conf = OTRGlobals::Instance->context->GetConfig(); + +} + +extern "C" void SaveManager_ThreadPoolWait() { + //SaveManager::Instance->ThreadPoolWait(); +} + +extern "C" void DeinitOTR() { + SaveManager_ThreadPoolWait(); +#ifdef ENABLE_CROWD_CONTROL + CrowdControl::Instance->Disable(); + CrowdControl::Instance->Shutdown(); +#endif + + // Destroying gui here because we have shared ptrs to LUS objects which output to SPDLOG which is destroyed before + // these shared ptrs. + //SohGui::Destroy(); + + OTRGlobals::Instance->context = nullptr; +} + +#ifdef _WIN32 +extern "C" uint64_t GetFrequency() { + LARGE_INTEGER nFreq; + + QueryPerformanceFrequency(&nFreq); + + return nFreq.QuadPart; +} + +extern "C" uint64_t GetPerfCounter() { + LARGE_INTEGER ticks; + QueryPerformanceCounter(&ticks); + + return ticks.QuadPart; +} +#else +extern "C" uint64_t GetFrequency() { + return 1000; // sec -> ms +} + +extern "C" uint64_t GetPerfCounter() { + struct timespec monotime; + clock_gettime(CLOCK_MONOTONIC, &monotime); + + uint64_t remainingMs = (monotime.tv_nsec / 1000000); + + // in milliseconds + return monotime.tv_sec * 1000 + remainingMs; +} +#endif + +extern "C" uint64_t GetUnixTimestamp() { + auto time = std::chrono::system_clock::now(); + auto since_epoch = time.time_since_epoch(); + auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(since_epoch); + long now = millis.count(); + return now; +} + +// C->C++ Bridge +extern "C" void Graph_ProcessFrame(void (*run_one_game_iter)(void)) { + OTRGlobals::Instance->context->GetWindow()->MainLoop(run_one_game_iter); +} + +extern bool ShouldClearTextureCacheAtEndOfFrame; + +extern "C" void Graph_StartFrame() { +#ifndef __WIIU__ + using LUS::KbScancode; + int32_t dwScancode = OTRGlobals::Instance->context->GetWindow()->GetLastScancode(); + OTRGlobals::Instance->context->GetWindow()->SetLastScancode(-1); + + switch (dwScancode) { + #if 0 + case KbScancode::LUS_KB_F5: { + if (CVarGetInteger("gSaveStatesEnabled", 0) == 0) { + LUS::Context::GetInstance()->GetWindow()->GetGui()->GetGameOverlay()->TextDrawNotification( + 6.0f, true, "Save states not enabled. Check Cheats Menu."); + return; + } + const unsigned int slot = OTRGlobals::Instance->gSaveStateMgr->GetCurrentSlot(); + const SaveStateReturn stateReturn = + OTRGlobals::Instance->gSaveStateMgr->AddRequest({ slot, RequestType::SAVE }); + + switch (stateReturn) { + case SaveStateReturn::SUCCESS: + SPDLOG_INFO("[SOH] Saved state to slot {}", slot); + break; + case SaveStateReturn::FAIL_WRONG_GAMESTATE: + SPDLOG_ERROR("[SOH] Can not save a state outside of \"GamePlay\""); + break; + [[unlikely]] default : break; + } + break; + } + case KbScancode::LUS_KB_F6: { + if (CVarGetInteger("gSaveStatesEnabled", 0) == 0) { + LUS::Context::GetInstance()->GetWindow()->GetGui()->GetGameOverlay()->TextDrawNotification( + 6.0f, true, "Save states not enabled. Check Cheats Menu."); + return; + } + unsigned int slot = OTRGlobals::Instance->gSaveStateMgr->GetCurrentSlot(); + slot++; + if (slot > 5) { + slot = 0; + } + OTRGlobals::Instance->gSaveStateMgr->SetCurrentSlot(slot); + SPDLOG_INFO("Set SaveState slot to {}.", slot); + break; + } + case KbScancode::LUS_KB_F7: { + if (CVarGetInteger("gSaveStatesEnabled", 0) == 0) { + LUS::Context::GetInstance()->GetWindow()->GetGui()->GetGameOverlay()->TextDrawNotification( + 6.0f, true, "Save states not enabled. Check Cheats Menu."); + return; + } + const unsigned int slot = OTRGlobals::Instance->gSaveStateMgr->GetCurrentSlot(); + const SaveStateReturn stateReturn = + OTRGlobals::Instance->gSaveStateMgr->AddRequest({ slot, RequestType::LOAD }); + + switch (stateReturn) { + case SaveStateReturn::SUCCESS: + SPDLOG_INFO("[SOH] Loaded state from slot {}", slot); + break; + case SaveStateReturn::FAIL_INVALID_SLOT: + SPDLOG_ERROR("[SOH] Invalid State Slot Number {}", slot); + break; + case SaveStateReturn::FAIL_STATE_EMPTY: + SPDLOG_ERROR("[SOH] State Slot {} is empty", slot); + break; + case SaveStateReturn::FAIL_WRONG_GAMESTATE: + SPDLOG_ERROR("[SOH] Can not load a state outside of \"GamePlay\""); + break; + [[unlikely]] default : break; + } + + break; + } +#endif +#if defined(_WIN32) || defined(__APPLE__) + case KbScancode::LUS_KB_F9: { + // Toggle TTS + CVarSetInteger("gA11yTTS", !CVarGetInteger("gA11yTTS", 0)); + break; + } +#endif + case KbScancode::LUS_KB_TAB: { + // Toggle HD Assets + CVarSetInteger("gAltAssets", !CVarGetInteger("gAltAssets", 0)); + //ShouldClearTextureCacheAtEndOfFrame = true; + break; + } + } +#endif + OTRGlobals::Instance->context->GetWindow()->StartFrame(); +} + +void RunCommands(Gfx* Commands, const std::vector<std::unordered_map<Mtx*, MtxF>>& mtx_replacements) { + //for (const auto& m : mtx_replacements) { + gfx_run(Commands, {}); + gfx_end_frame(); + // } +} + +// C->C++ Bridge +extern "C" void Graph_ProcessGfxCommands(Gfx* commands) { + { + //std::unique_lock<std::mutex> Lock(audio.mutex); + //audio.processing = true; + } + + //audio.cv_to_thread.notify_one(); + std::vector<std::unordered_map<Mtx*, MtxF>> mtx_replacements; + int target_fps = 20; + //OTRGlobals::Instance->GetInterpolationFPS(); + static int last_fps; + static int last_update_rate; + static int time; + int fps = target_fps; + int original_fps = 60 / R_UPDATE_RATE; + + if (target_fps == 20 || original_fps > target_fps) { + fps = original_fps; + } + + if (last_fps != fps || last_update_rate != R_UPDATE_RATE) { + time = 0; + } + + // time_base = fps * original_fps (one second) + // int next_original_frame = fps; + + //while (time + original_fps <= next_original_frame) { + // time += original_fps; + // if (time != next_original_frame) { + // mtx_replacements.push_back(FrameInterpolation_Interpolate((float)time / next_original_frame)); + // } else { + // mtx_replacements.emplace_back(); + // } + //} + + //time -= fps; + + OTRGlobals::Instance->context->GetWindow()->SetTargetFps(original_fps); + // OTRGlobals::Instance->context->GetWindow()->SetTargetFps(20); + //OTRGlobals::Instance->context->GetWindow()->SetTargetFps(60); + + //int threshold = CVarGetInteger("gExtraLatencyThreshold", 80); + //OTRGlobals::Instance->context->GetWindow()->SetMaximumFrameLatency(threshold > 0 && target_fps >= threshold ? 2 + //: 1); + + RunCommands(commands, mtx_replacements); + + //last_fps = fps; + //last_update_rate = R_UPDATE_RATE; + + //{ + // std::unique_lock<std::mutex> Lock(audio.mutex); + // while (audio.processing) { + // audio.cv_from_thread.wait(Lock); + // } + //} + // + //if (ShouldClearTextureCacheAtEndOfFrame) { + // gfx_texture_cache_clear(); + // LUS::SkeletonPatcher::UpdateSkeletons(); + // ShouldClearTextureCacheAtEndOfFrame = false; + //} + + // OTRTODO: FIGURE OUT END FRAME POINT + /* if (OTRGlobals::Instance->context->lastScancode != -1) + OTRGlobals::Instance->context->lastScancode = -1;*/ +} + +float divisor_num = 0.0f; + +extern "C" void OTRGetPixelDepthPrepare(float x, float y) { + OTRGlobals::Instance->context->GetWindow()->GetPixelDepthPrepare(x, y); +} + +extern "C" uint16_t OTRGetPixelDepth(float x, float y) { + return OTRGlobals::Instance->context->GetWindow()->GetPixelDepth(x, y); +} + +extern "C" uint32_t ResourceMgr_GetNumGameVersions() { + return LUS::Context::GetInstance()->GetResourceManager()->GetArchive()->GetGameVersions().size(); +} + +extern "C" uint32_t ResourceMgr_GetGameVersion(int index) { + return LUS::Context::GetInstance()->GetResourceManager()->GetArchive()->GetGameVersions()[index]; +} + +extern "C" uint32_t ResourceMgr_GetGamePlatform(int index) { + uint32_t version = LUS::Context::GetInstance()->GetResourceManager()->GetArchive()->GetGameVersions()[index]; + + switch (version) { + case OOT_NTSC_US_10: + case OOT_NTSC_US_11: + case OOT_NTSC_US_12: + case OOT_PAL_10: + case OOT_PAL_11: + return GAME_PLATFORM_N64; + case OOT_NTSC_JP_GC: + case OOT_NTSC_US_GC: + case OOT_PAL_GC: + case OOT_NTSC_JP_MQ: + case OOT_NTSC_US_MQ: + case OOT_PAL_MQ: + case OOT_PAL_GC_DBG1: + case OOT_PAL_GC_DBG2: + case OOT_PAL_GC_MQ_DBG: + return GAME_PLATFORM_GC; + } +} + +extern "C" uint32_t ResourceMgr_GetGameRegion(int index) { + uint32_t version = LUS::Context::GetInstance()->GetResourceManager()->GetArchive()->GetGameVersions()[index]; + + switch (version) { + case OOT_NTSC_US_10: + case OOT_NTSC_US_11: + case OOT_NTSC_US_12: + case OOT_NTSC_JP_GC: + case OOT_NTSC_US_GC: + case OOT_NTSC_JP_MQ: + case OOT_NTSC_US_MQ: + return GAME_REGION_NTSC; + case OOT_PAL_10: + case OOT_PAL_11: + case OOT_PAL_GC: + case OOT_PAL_MQ: + case OOT_PAL_GC_DBG1: + case OOT_PAL_GC_DBG2: + case OOT_PAL_GC_MQ_DBG: + return GAME_REGION_PAL; + } +} + +uint32_t IsSceneMasterQuest(s16 sceneNum) { + return false; + uint32_t value = 0; + //uint8_t mqMode = CVarGetInteger("gBetterDebugWarpScreenMQMode", WARP_MODE_OVERRIDE_OFF); + //if (mqMode == WARP_MODE_OVERRIDE_MQ_AS_VANILLA) { + // return 1; + //} else if (mqMode == WARP_MODE_OVERRIDE_VANILLA_AS_MQ) { + // return 0; + //} else { + // if (OTRGlobals::Instance->HasMasterQuest()) { + // if (!OTRGlobals::Instance->HasOriginal()) { + // value = 1; + // } else if (IS_MASTER_QUEST) { + // value = 1; + // } else { + // value = 0; + // if (IS_RANDO && !OTRGlobals::Instance->gRandomizer->masterQuestDungeons.empty() && + // OTRGlobals::Instance->gRandomizer->masterQuestDungeons.contains(sceneNum)) { + // value = 1; + // } + // } + // } + //} + return value; +} + +uint32_t IsGameMasterQuest() { + return false; + //return gPlayState != NULL ? IsSceneMasterQuest(gPlayState->sceneNum) : 0; +} + +extern "C" uint32_t ResourceMgr_GameHasMasterQuest() { + return OTRGlobals::Instance->HasMasterQuest(); +} + +extern "C" uint32_t ResourceMgr_GameHasOriginal() { + return OTRGlobals::Instance->HasOriginal(); +} + +extern "C" uint32_t ResourceMgr_IsSceneMasterQuest(s16 sceneNum) { + return IsSceneMasterQuest(sceneNum); +} + +extern "C" uint32_t ResourceMgr_IsGameMasterQuest() { + return IsGameMasterQuest(); +} + +extern "C" void ResourceMgr_LoadDirectory(const char* resName) { + LUS::Context::GetInstance()->GetResourceManager()->LoadDirectory(resName); +} +extern "C" void ResourceMgr_DirtyDirectory(const char* resName) { + LUS::Context::GetInstance()->GetResourceManager()->DirtyDirectory(resName); +} + +// OTRTODO: There is probably a more elegant way to go about this... +// Kenix: This is definitely leaking memory when it's called. +extern "C" char** ResourceMgr_ListFiles(const char* searchMask, int* resultSize) { + auto lst = LUS::Context::GetInstance()->GetResourceManager()->GetArchive()->ListFiles(searchMask); + char** result = (char**)malloc(lst->size() * sizeof(char*)); + + for (size_t i = 0; i < lst->size(); i++) { + char* str = (char*)malloc(lst.get()[0][i].size() + 1); + memcpy(str, lst.get()[0][i].data(), lst.get()[0][i].size()); + str[lst.get()[0][i].size()] = '\0'; + result[i] = str; + } + *resultSize = lst->size(); + + return result; +} + +extern "C" uint8_t ResourceMgr_FileExists(const char* filePath) { + std::string path = filePath; + if (path.substr(0, 7) == "__OTR__") { + path = path.substr(7); + } + + return ExtensionCache.contains(path); +} + +extern "C" void ResourceMgr_LoadFile(const char* resName) { + LUS::Context::GetInstance()->GetResourceManager()->LoadResource(resName); +} + +std::shared_ptr<LUS::IResource> GetResourceByNameHandlingMQ(const char* path) { + std::string Path = path; + if (ResourceMgr_IsGameMasterQuest()) { + size_t pos = 0; + if ((pos = Path.find("/nonmq/", 0)) != std::string::npos) { + Path.replace(pos, 7, "/mq/"); + } + } + return LUS::Context::GetInstance()->GetResourceManager()->LoadResource(Path.c_str()); +} + +extern "C" char* GetResourceDataByNameHandlingMQ(const char* path) { + auto res = GetResourceByNameHandlingMQ(path); + + if (res == nullptr) { + return nullptr; + } + + return (char*)res->GetRawPointer(); +} + +extern "C" char* ResourceMgr_LoadFileFromDisk(const char* filePath) { + FILE* file = fopen(filePath, "r"); + fseek(file, 0, SEEK_END); + int fSize = ftell(file); + fseek(file, 0, SEEK_SET); + + char* data = (char*)malloc(fSize); + fread(data, 1, fSize, file); + + fclose(file); + + return data; +} + +extern "C" uint8_t ResourceMgr_ResourceIsBackground(char* texPath) { + auto res = GetResourceByNameHandlingMQ(texPath); + return res->GetInitData()->Type == LUS::ResourceType::SOH_Background; +} + +extern "C" char* ResourceMgr_LoadJPEG(char* data, size_t dataSize) { + static char* finalBuffer = 0; + + if (finalBuffer == 0) + finalBuffer = (char*)malloc(dataSize); + + int w; + int h; + int comp; + + unsigned char* pixels = + stbi_load_from_memory((const unsigned char*)data, 320 * 240 * 2, &w, &h, &comp, STBI_rgb_alpha); + // unsigned char* pixels = stbi_load_from_memory((const unsigned char*)data, 480 * 240 * 2, &w, &h, &comp, + // STBI_rgb_alpha); + int idx = 0; + + for (int y = 0; y < h; y++) { + for (int x = 0; x < w; x++) { + uint16_t* bufferTest = (uint16_t*)finalBuffer; + int pixelIdx = ((y * w) + x) * 4; + + uint8_t r = pixels[pixelIdx + 0] / 8; + uint8_t g = pixels[pixelIdx + 1] / 8; + uint8_t b = pixels[pixelIdx + 2] / 8; + + uint8_t alphaBit = pixels[pixelIdx + 3] != 0; + + uint16_t data = (r << 11) + (g << 6) + (b << 1) + alphaBit; + + finalBuffer[idx++] = (data & 0xFF00) >> 8; + finalBuffer[idx++] = (data & 0x00FF); + } + } + + return (char*)finalBuffer; +} + +extern "C" uint16_t ResourceMgr_LoadTexWidthByName(char* texPath); + +extern "C" uint16_t ResourceMgr_LoadTexHeightByName(char* texPath); + +extern "C" char* ResourceMgr_LoadTexOrDListByName(const char* filePath) { + auto res = GetResourceByNameHandlingMQ(filePath); + + if (res->GetInitData()->Type == LUS::ResourceType::DisplayList) + return (char*)&((std::static_pointer_cast<LUS::DisplayList>(res))->Instructions[0]); + else if (res->GetInitData()->Type == LUS::ResourceType::Array) + return (char*)(std::static_pointer_cast<LUS::Array>(res))->Vertices.data(); + else { + return (char*)GetResourceDataByNameHandlingMQ(filePath); + } +} + +extern "C" char* ResourceMgr_LoadIfDListByName(const char* filePath) { + auto res = GetResourceByNameHandlingMQ(filePath); + + if (res->GetInitData()->Type == LUS::ResourceType::DisplayList) + return (char*)&((std::static_pointer_cast<LUS::DisplayList>(res))->Instructions[0]); + + return nullptr; +} + +//extern "C" Sprite* GetSeedTexture(uint8_t index) { +// return OTRGlobals::Instance->gRandomizer->GetSeedTexture(index); +//} + +extern "C" char* ResourceMgr_LoadPlayerAnimByName(const char* animPath) { + auto anim = std::static_pointer_cast<LUS::PlayerAnimation>(GetResourceByNameHandlingMQ(animPath)); + + return (char*)&anim->limbRotData[0]; +} + +extern "C" void ResourceMgr_PushCurrentDirectory(char* path) { + gfx_push_current_dir(path); +} + +extern "C" Gfx* ResourceMgr_LoadGfxByName(const char* path) { + auto res = std::static_pointer_cast<LUS::DisplayList>(GetResourceByNameHandlingMQ(path)); + return (Gfx*)&res->Instructions[0]; +} + +typedef struct { + int index; + Gfx instruction; +} GfxPatch; + +std::unordered_map<std::string, std::unordered_map<std::string, GfxPatch>> originalGfx; + +// Attention! This is primarily for cosmetics & bug fixes. For things like mods and model replacement you should be +// using OTRs instead (When that is available). Index can be found using the commented out section below. +extern "C" void ResourceMgr_PatchGfxByName(const char* path, const char* patchName, int index, Gfx instruction) { + auto res = std::static_pointer_cast<LUS::DisplayList>( + LUS::Context::GetInstance()->GetResourceManager()->LoadResource(path)); + + // Leaving this here for people attempting to find the correct Dlist index to patch + /*if (strcmp("__OTR__objects/object_gi_longsword/gGiBiggoronSwordDL", path) == 0) { + for (int i = 0; i < res->instructions.size(); i++) { + Gfx* gfx = (Gfx*)&res->instructions[i]; + // Log all commands + // SPDLOG_INFO("index:{} command:{}", i, gfx->words.w0 >> 24); + // Log only SetPrimColors + if (gfx->words.w0 >> 24 == 250) { + SPDLOG_INFO("index:{} r:{} g:{} b:{} a:{}", i, _SHIFTR(gfx->words.w1, 24, 8), _SHIFTR(gfx->words.w1, 16, + 8), _SHIFTR(gfx->words.w1, 8, 8), _SHIFTR(gfx->words.w1, 0, 8)); + } + } + }*/ + + // Index refers to individual gfx words, which are half the size on 32-bit + // if (sizeof(uintptr_t) < 8) { + // index /= 2; + // } + + Gfx* gfx = (Gfx*)&res->Instructions[index]; + + if (!originalGfx.contains(path) || !originalGfx[path].contains(patchName)) { + originalGfx[path][patchName] = { index, *gfx }; + } + + *gfx = instruction; +} + +extern "C" void ResourceMgr_PatchGfxCopyCommandByName(const char* path, const char* patchName, int destinationIndex, + int sourceIndex) { + auto res = std::static_pointer_cast<LUS::DisplayList>( + LUS::Context::GetInstance()->GetResourceManager()->LoadResource(path)); + + Gfx* destinationGfx = (Gfx*)&res->Instructions[destinationIndex]; + Gfx sourceGfx = res->Instructions[sourceIndex]; + + if (!originalGfx.contains(path) || !originalGfx[path].contains(patchName)) { + originalGfx[path][patchName] = { destinationIndex, *destinationGfx }; + } + + *destinationGfx = sourceGfx; +} + +extern "C" void ResourceMgr_UnpatchGfxByName(const char* path, const char* patchName) { + if (originalGfx.contains(path) && originalGfx[path].contains(patchName)) { + auto res = std::static_pointer_cast<LUS::DisplayList>( + LUS::Context::GetInstance()->GetResourceManager()->LoadResource(path)); + + Gfx* gfx = (Gfx*)&res->Instructions[originalGfx[path][patchName].index]; + *gfx = originalGfx[path][patchName].instruction; + + originalGfx[path].erase(patchName); + } +} + +extern "C" char* ResourceMgr_LoadVtxArrayByName(const char* path) { + auto res = std::static_pointer_cast<LUS::Array>(GetResourceByNameHandlingMQ(path)); + + return (char*)res->Vertices.data(); +} + +extern "C" size_t ResourceMgr_GetVtxArraySizeByName(const char* path) { + auto res = std::static_pointer_cast<LUS::Array>(GetResourceByNameHandlingMQ(path)); + + return res->Vertices.size(); + // } +} + +extern "C" char* ResourceMgr_LoadArrayByName(const char* path) { + auto res = std::static_pointer_cast<LUS::Array>(GetResourceByNameHandlingMQ(path)); + + return (char*)res->Scalars.data(); +} + +extern "C" size_t ResourceMgr_GetArraySizeByName(const char* path) { + auto res = std::static_pointer_cast<LUS::Array>(GetResourceByNameHandlingMQ(path)); + + return res->Scalars.size(); + // } +} +extern "C" char* ResourceMgr_LoadArrayByNameAsVec3s(const char* path) { + auto res = std::static_pointer_cast<LUS::Array>(GetResourceByNameHandlingMQ(path)); + + // if (res->CachedGameAsset != nullptr) + // return (char*)res->CachedGameAsset; + // else + // { + Vec3s* data = (Vec3s*)malloc(sizeof(Vec3s) * res->Scalars.size()); + + for (size_t i = 0; i < res->Scalars.size(); i += 3) { + data[(i / 3)].x = res->Scalars[i + 0].s16; + data[(i / 3)].y = res->Scalars[i + 1].s16; + data[(i / 3)].z = res->Scalars[i + 2].s16; + } + + // res->CachedGameAsset = data; + + return (char*)data; + // } +} + +extern "C" AnimatedMaterial* ResourceMgr_LoadAnimatedMatByName(const char* path) { + return (AnimatedMaterial*)ResourceGetDataByName(path); +} + +extern "C" CollisionHeader* ResourceMgr_LoadColByName(const char* path) { + return (CollisionHeader*)ResourceGetDataByName(path); +} + +extern "C" Vtx* ResourceMgr_LoadVtxByName(char* path) { + return (Vtx*)ResourceGetDataByName(path); +} + +//extern "C" SequenceData ResourceMgr_LoadSeqByName(const char* path) { +// SequenceData* sequence = (SequenceData*)ResourceGetDataByName(path); +// return *sequence; +//} +// +//std::map<std::string, SoundFontSample*> cachedCustomSFs; +#if 0 +extern "C" SoundFontSample* ReadCustomSample(const char* path) { + return nullptr; + /* + if (!ExtensionCache.contains(path)) + return nullptr; + + ExtensionEntry entry = ExtensionCache[path]; + + auto sampleRaw = LUS::Context::GetInstance()->GetResourceManager()->LoadFile(entry.path); + uint32_t* strem = (uint32_t*)sampleRaw->Buffer.get(); + uint8_t* strem2 = (uint8_t*)strem; + + SoundFontSample* sampleC = new SoundFontSample; + + if (entry.ext == "wav") { + drwav_uint32 channels; + drwav_uint32 sampleRate; + drwav_uint64 totalPcm; + drmp3_int16* pcmData = + drwav_open_memory_and_read_pcm_frames_s16(strem2, sampleRaw->BufferSize, &channels, &sampleRate, + &totalPcm, NULL); sampleC->size = totalPcm; sampleC->sampleAddr = (uint8_t*)pcmData; sampleC->codec = CODEC_S16; + + sampleC->loop = new AdpcmLoop; + sampleC->loop->start = 0; + sampleC->loop->end = sampleC->size - 1; + sampleC->loop->count = 0; + sampleC->sampleRateMagicValue = 'RIFF'; + sampleC->sampleRate = sampleRate; + + cachedCustomSFs[path] = sampleC; + return sampleC; + } else if (entry.ext == "mp3") { + drmp3_config mp3Info; + drmp3_uint64 totalPcm; + drmp3_int16* pcmData = + drmp3_open_memory_and_read_pcm_frames_s16(strem2, sampleRaw->BufferSize, &mp3Info, &totalPcm, NULL); + + sampleC->size = totalPcm * mp3Info.channels * sizeof(short); + sampleC->sampleAddr = (uint8_t*)pcmData; + sampleC->codec = CODEC_S16; + + sampleC->loop = new AdpcmLoop; + sampleC->loop->start = 0; + sampleC->loop->end = sampleC->size; + sampleC->loop->count = 0; + sampleC->sampleRateMagicValue = 'RIFF'; + sampleC->sampleRate = mp3Info.sampleRate; + + cachedCustomSFs[path] = sampleC; + return sampleC; + } + + return nullptr; + */ +} + +extern "C" SoundFontSample* ResourceMgr_LoadAudioSample(const char* path) { + return (SoundFontSample*)ResourceGetDataByName(path); +} + +extern "C" SoundFont* ResourceMgr_LoadAudioSoundFont(const char* path) { + return (SoundFont*)ResourceGetDataByName(path); +} +#endif +extern "C" int ResourceMgr_OTRSigCheck(char* imgData) { + uintptr_t i = (uintptr_t)(imgData); + + // if (i == 0xD9000000 || i == 0xE7000000 || (i & 1) == 1) + if ((i & 1) == 1) + return 0; + + // if ((i & 0xFF000000) != 0xAB000000 && (i & 0xFF000000) != 0xCD000000 && i != 0) { + if (i != 0) { + if (imgData[0] == '_' && imgData[1] == '_' && imgData[2] == 'O' && imgData[3] == 'T' && imgData[4] == 'R' && + imgData[5] == '_' && imgData[6] == '_') + return 1; + } + + return 0; +} + +extern "C" AnimationHeaderCommon* ResourceMgr_LoadAnimByName(const char* path) { + return (AnimationHeaderCommon*)ResourceGetDataByName(path); +} + +extern "C" SkeletonHeader* ResourceMgr_LoadSkeletonByName(const char* path, SkelAnime* skelAnime) { + std::string pathStr = std::string(path); + static const std::string sOtr = "__OTR__"; + + if (pathStr.starts_with(sOtr)) { + pathStr = pathStr.substr(sOtr.length()); + } + + bool isAlt = CVarGetInteger("gAltAssets", 0); + + if (isAlt) { + pathStr = LUS::IResource::gAltAssetPrefix + pathStr; + } + + SkeletonHeader* skelHeader = (SkeletonHeader*)ResourceGetDataByName(pathStr.c_str()); + + // If there isn't an alternate model, load the regular one + if (isAlt && skelHeader == NULL) { + skelHeader = (SkeletonHeader*)ResourceGetDataByName(path); + } + + // This function is only called when a skeleton is initialized. + // Therefore we can take this oppurtunity to take note of the Skeleton that is created... + if (skelAnime != nullptr) { + auto stringPath = std::string(path); + //LUS::SkeletonPatcher::RegisterSkeleton(stringPath, skelAnime); + } + + return skelHeader; +} + +extern "C" void ResourceMgr_UnregisterSkeleton(SkelAnime* skelAnime) { + if (skelAnime != nullptr) + LUS::SkeletonPatcher::UnregisterSkeleton(skelAnime); +} + +extern "C" void ResourceMgr_ClearSkeletons(SkelAnime* skelAnime) { + if (skelAnime != nullptr) + LUS::SkeletonPatcher::ClearSkeletons(); +} + +extern "C" s32* ResourceMgr_LoadCSByName(const char* path) { + return (s32*)GetResourceDataByNameHandlingMQ(path); +} + +std::filesystem::path GetSaveFile(std::shared_ptr<LUS::Config> Conf) { + const std::string fileName = + Conf->GetString("Game.SaveName", LUS::Context::GetPathRelativeToAppDirectory("oot_save.sav")); + std::filesystem::path saveFile = std::filesystem::absolute(fileName); + + if (!exists(saveFile.parent_path())) { + create_directories(saveFile.parent_path()); + } + + return saveFile; +} + +std::filesystem::path GetSaveFile() { + const std::shared_ptr<LUS::Config> pConf = OTRGlobals::Instance->context->GetConfig(); + + return GetSaveFile(pConf); +} + +void OTRGlobals::CheckSaveFile(size_t sramSize) const { + const std::shared_ptr<LUS::Config> pConf = Instance->context->GetConfig(); + + std::filesystem::path savePath = GetSaveFile(pConf); + std::fstream saveFile(savePath, std::fstream::in | std::fstream::out | std::fstream::binary); + if (saveFile.fail()) { + saveFile.open(savePath, std::fstream::in | std::fstream::out | std::fstream::binary | std::fstream::app); + for (int i = 0; i < sramSize; ++i) { + saveFile.write("\0", 1); + } + } + saveFile.close(); +} + +//extern "C" void Ctx_ReadSaveFile(uintptr_t addr, void* dramAddr, size_t size) { +// SaveManager::ReadSaveFile(GetSaveFile(), addr, dramAddr, size); +//} + +//extern "C" void Ctx_WriteSaveFile(uintptr_t addr, void* dramAddr, size_t size) { +// SaveManager::WriteSaveFile(GetSaveFile(), addr, dramAddr, size); +//} + +std::wstring StringToU16(const std::string& s) { + std::vector<unsigned long> result; + size_t i = 0; + while (i < s.size()) { + unsigned long uni; + size_t nbytes; + bool error = false; + unsigned char c = s[i++]; + if (c < 0x80) { // ascii + uni = c; + nbytes = 0; + } else if (c <= 0xBF) { // assuming kata/hiragana delimiter + nbytes = 0; + uni = '\1'; + } else if (c <= 0xDF) { + uni = c & 0x1F; + nbytes = 1; + } else if (c <= 0xEF) { + uni = c & 0x0F; + nbytes = 2; + } else if (c <= 0xF7) { + uni = c & 0x07; + nbytes = 3; + } + for (size_t j = 0; j < nbytes; ++j) { + unsigned char c = s[i++]; + uni <<= 6; + uni += c & 0x3F; + } + if (uni != '\1') + result.push_back(uni); + } + std::wstring utf16; + for (size_t i = 0; i < result.size(); ++i) { + unsigned long uni = result[i]; + if (uni <= 0xFFFF) { + utf16 += (wchar_t)uni; + } else { + uni -= 0x10000; + utf16 += (wchar_t)((uni >> 10) + 0xD800); + utf16 += (wchar_t)((uni & 0x3FF) + 0xDC00); + } + } + return utf16; +} + +int CopyStringToCharBuffer(const std::string& inputStr, char* buffer, const int maxBufferSize) { + if (!inputStr.empty()) { + // Prevent potential horrible overflow due to implicit conversion of maxBufferSize to an unsigned. Prevents + // negatives. + memset(buffer, 0, std::max<int>(0, maxBufferSize)); + // Gaurentee that this value will be greater than 0, regardless of passed variables. + const int copiedCharLen = std::min<int>(std::max<int>(0, maxBufferSize - 1), inputStr.length()); + memcpy(buffer, inputStr.c_str(), copiedCharLen); + return copiedCharLen; + } + + return 0; +} + +extern "C" void OTRGfxPrint(const char* str, void* printer, void (*printImpl)(void*, char)) { + const std::vector<uint32_t> hira1 = { + u'を', u'ぁ', u'ぃ', u'ぅ', u'ぇ', u'ぉ', u'ゃ', u'ゅ', u'ょ', u'っ', u'-', u'あ', u'い', + u'う', u'え', u'お', u'か', u'き', u'く', u'け', u'こ', u'さ', u'し', u'す', u'せ', u'そ', + }; + + const std::vector<uint32_t> hira2 = { + u'た', u'ち', u'つ', u'て', u'と', u'な', u'に', u'ぬ', u'ね', u'の', u'は', u'ひ', u'ふ', u'へ', u'ほ', u'ま', + u'み', u'む', u'め', u'も', u'や', u'ゆ', u'よ', u'ら', u'り', u'る', u'れ', u'ろ', u'わ', u'ん', u'゛', u'゜', + }; + + std::wstring wstr = StringToU16(str); + + for (const auto& c : wstr) { + unsigned char convt = ' '; + if (c < 0x80) { + printImpl(printer, c); + } else if (c >= u'。' && c <= u'゚') { // katakana + printImpl(printer, c - 0xFEC0); + } else { + auto it = std::find(hira1.begin(), hira1.end(), c); + if (it != hira1.end()) { // hiragana block 1 + printImpl(printer, 0x88 + std::distance(hira1.begin(), it)); + } + + auto it2 = std::find(hira2.begin(), hira2.end(), c); + if (it2 != hira2.end()) { // hiragana block 2 + printImpl(printer, 0xe0 + std::distance(hira2.begin(), it2)); + } + } + } +} + +extern "C" uint32_t OTRGetCurrentWidth() { + return OTRGlobals::Instance->context->GetWindow()->GetWidth(); +} + +extern "C" uint32_t OTRGetCurrentHeight() { + return OTRGlobals::Instance->context->GetWindow()->GetHeight(); +} + +Color_RGB8 GetColorForControllerLED() { + #if 0 + auto brightness = CVarGetFloat("gLedBrightness", 1.0f) / 1.0f; + Color_RGB8 color = { 0, 0, 0 }; + if (brightness > 0.0f) { + LEDColorSource source = + static_cast<LEDColorSource>(CVarGetInteger("gLedColorSource", LED_SOURCE_TUNIC_ORIGINAL)); + bool criticalOverride = CVarGetInteger("gLedCriticalOverride", 1); + if (gPlayState && (source == LED_SOURCE_TUNIC_ORIGINAL || source == LED_SOURCE_TUNIC_COSMETICS)) { + switch (CUR_EQUIP_VALUE(EQUIP_TUNIC) - 1) { + case PLAYER_TUNIC_KOKIRI: + color = source == LED_SOURCE_TUNIC_COSMETICS + ? CVarGetColor24("gCosmetics.Link_KokiriTunic.Value", kokiriColor) + : kokiriColor; + break; + case PLAYER_TUNIC_GORON: + color = source == LED_SOURCE_TUNIC_COSMETICS + ? CVarGetColor24("gCosmetics.Link_GoronTunic.Value", goronColor) + : goronColor; + break; + case PLAYER_TUNIC_ZORA: + color = source == LED_SOURCE_TUNIC_COSMETICS + ? CVarGetColor24("gCosmetics.Link_ZoraTunic.Value", zoraColor) + : zoraColor; + break; + } + } + if (source == LED_SOURCE_CUSTOM) { + color = CVarGetColor24("gLedPort1Color", { 255, 255, 255 }); + } + if (criticalOverride || source == LED_SOURCE_HEALTH) { + if (HealthMeter_IsCritical()) { + color = { 0xFF, 0, 0 }; + } else if (source == LED_SOURCE_HEALTH) { + if (gSaveContext.health / gSaveContext.healthCapacity <= 0.4f) { + color = { 0xFF, 0xFF, 0 }; + } else { + color = { 0, 0xFF, 0 }; + } + } + } + color.r = color.r * brightness; + color.g = color.g * brightness; + color.b = color.b * brightness; + } + #endif + return { 0, 0, 0 }; +} + +extern "C" void OTRControllerCallback(uint8_t rumble) { + auto physicalDevice = LUS::Context::GetInstance()->GetControlDeck()->GetDeviceFromPortIndex(0); + + if (physicalDevice->CanSetLed()) { + // We call this every tick, SDL accounts for this use and prevents driver spam + // https://github.com/libsdl-org/SDL/blob/f17058b562c8a1090c0c996b42982721ace90903/src/joystick/SDL_joystick.c#L1114-L1144 + physicalDevice->SetLedColor(0, GetColorForControllerLED()); + } + + physicalDevice->SetRumble(0, rumble); +} + +extern "C" float OTRGetAspectRatio() { + return gfx_current_dimensions.aspect_ratio; +} + +extern "C" float OTRGetDimensionFromLeftEdge(float v) { + return (SCREEN_WIDTH / 2 - SCREEN_HEIGHT / 2 * OTRGetAspectRatio() + (v)); +} + +extern "C" float OTRGetDimensionFromRightEdge(float v) { + return (SCREEN_WIDTH / 2 + SCREEN_HEIGHT / 2 * OTRGetAspectRatio() - (SCREEN_WIDTH - v)); +} + +f32 floorf(f32 x); +f32 ceilf(f32 x); + +extern "C" int16_t OTRGetRectDimensionFromLeftEdge(float v) { + return ((int)floorf(OTRGetDimensionFromLeftEdge(v))); +} + +extern "C" int16_t OTRGetRectDimensionFromRightEdge(float v) { + return ((int)ceilf(OTRGetDimensionFromRightEdge(v))); +} + +extern "C" int AudioPlayer_Buffered(void) { + return AudioPlayerBuffered(); +} + +extern "C" int AudioPlayer_GetDesiredBuffered(void) { + return AudioPlayerGetDesiredBuffered(); +} + +extern "C" void AudioPlayer_Play(const uint8_t* buf, uint32_t len) { + AudioPlayerPlayFrame(buf, len); +} + +extern "C" int Controller_ShouldRumble(size_t slot) { + auto controlDeck = LUS::Context::GetInstance()->GetControlDeck(); + + if (slot < controlDeck->GetNumConnectedPorts()) { + auto physicalDevice = controlDeck->GetDeviceFromPortIndex(slot); + + if (physicalDevice->GetProfile(slot)->UseRumble && physicalDevice->CanRumble()) { + return 1; + } + } + + return 0; +} diff --git a/mm/2s2h/BenPort.h b/mm/2s2h/BenPort.h new file mode 100644 index 000000000..fbdd93bcf --- /dev/null +++ b/mm/2s2h/BenPort.h @@ -0,0 +1,137 @@ +#ifndef OTR_GLOBALS_H +#define OTR_GLOBALS_H + +#pragma once + + +#define GAME_REGION_NTSC 0 +#define GAME_REGION_PAL 1 + +#define GAME_PLATFORM_N64 0 +#define GAME_PLATFORM_GC 1 + +#ifdef __cplusplus +#include <Context.h> + +#include <vector> + +const std::string customMessageTableID = "BaseGameOverrides"; +const std::string appShortName = "soh"; + +class OTRGlobals { + public: + static OTRGlobals* Instance; + + std::shared_ptr<LUS::Context> context; + + OTRGlobals(); + ~OTRGlobals(); + + bool HasMasterQuest(); + bool HasOriginal(); + uint32_t GetInterpolationFPS(); + std::shared_ptr<std::vector<std::string>> ListFiles(std::string path); + + private: + void CheckSaveFile(size_t sramSize) const; + bool hasMasterQuest; + bool hasOriginal; +}; + +uint32_t IsGameMasterQuest(); +#endif + +#ifndef __cplusplus +void InitOTR(void); +void DeinitOTR(void); +void VanillaItemTable_Init(); +void OTRAudio_Init(); +void OTRMessage_Init(); +void InitAudio(); +void Graph_StartFrame(); +void Graph_ProcessGfxCommands(Gfx* commands); +void Graph_ProcessFrame(void (*run_one_game_iter)(void)); +void OTRLogString(const char* src); +void OTRGfxPrint(const char* str, void* printer, void (*printImpl)(void*, char)); +void OTRGetPixelDepthPrepare(float x, float y); +uint16_t OTRGetPixelDepth(float x, float y); +int32_t OTRGetLastScancode(); +uint32_t ResourceMgr_IsGameMasterQuest(); +uint32_t ResourceMgr_IsSceneMasterQuest(s16 sceneNum); +uint32_t ResourceMgr_GameHasMasterQuest(); +uint32_t ResourceMgr_GameHasOriginal(); +uint32_t ResourceMgr_GetNumGameVersions(); +uint32_t ResourceMgr_GetGameVersion(int index); +uint32_t ResourceMgr_GetGamePlatform(int index); +uint32_t ResourceMgr_GetGameRegion(int index); +void ResourceMgr_LoadDirectory(const char* resName); +char** ResourceMgr_ListFiles(const char* searchMask, int* resultSize); +uint8_t ResourceMgr_FileExists(const char* resName); +char* GetResourceDataByNameHandlingMQ(const char* path); +void ResourceMgr_LoadFile(const char* resName); +char* ResourceMgr_LoadFileFromDisk(const char* filePath); +uint8_t ResourceMgr_ResourceIsBackground(char* texPath); +char* ResourceMgr_LoadJPEG(char* data, size_t dataSize); +uint16_t ResourceMgr_LoadTexWidthByName(char* texPath); +uint16_t ResourceMgr_LoadTexHeightByName(char* texPath); +CollisionHeader* ResourceMgr_LoadColByName(const char* path); +AnimatedMaterial* ResourceMgr_LoadAnimatedMatByName(const char* path); +char* ResourceMgr_LoadTexOrDListByName(const char* filePath); +char* ResourceMgr_LoadPlayerAnimByName(const char* animPath); +AnimationHeaderCommon* ResourceMgr_LoadAnimByName(const char* path); +char* ResourceMgr_GetNameByCRC(uint64_t crc, char* alloc); +Gfx* ResourceMgr_LoadGfxByCRC(uint64_t crc); +Gfx* ResourceMgr_LoadGfxByName(const char* path); +void ResourceMgr_PatchGfxByName(const char* path, const char* patchName, int index, Gfx instruction); +void ResourceMgr_UnpatchGfxByName(const char* path, const char* patchName); +char* ResourceMgr_LoadArrayByNameAsVec3s(const char* path); +char* ResourceMgr_LoadArrayByName(const char* path); +size_t ResourceMgr_GetArraySizeByName(const char* path); +Vtx* ResourceMgr_LoadVtxByCRC(uint64_t crc); +char* ResourceMgr_LoadVtxArrayByName(const char* path); +size_t ResourceMgr_GetVtxArraySizeByName(const char* path); +Vtx* ResourceMgr_LoadVtxByName(char* path); + +void Ctx_ReadSaveFile(uintptr_t addr, void* dramAddr, size_t size); +void Ctx_WriteSaveFile(uintptr_t addr, void* dramAddr, size_t size); + +uint64_t GetPerfCounter(); +struct SkeletonHeader* ResourceMgr_LoadSkeletonByName(const char* path, SkelAnime* skelAnime); +void ResourceMgr_UnregisterSkeleton(SkelAnime* skelAnime); +void ResourceMgr_ClearSkeletons(); +s32* ResourceMgr_LoadCSByName(const char* path); +int ResourceMgr_OTRSigCheck(char* imgData); +uint64_t osGetTime(void); +uint32_t osGetCount(void); +uint32_t OTRGetCurrentWidth(void); +uint32_t OTRGetCurrentHeight(void); +float OTRGetAspectRatio(void); +float OTRGetDimensionFromLeftEdge(float v); +float OTRGetDimensionFromRightEdge(float v); +int16_t OTRGetRectDimensionFromLeftEdge(float v); +int16_t OTRGetRectDimensionFromRightEdge(float v); +int AudioPlayer_Buffered(void); +int AudioPlayer_GetDesiredBuffered(void); +void AudioPlayer_Play(const uint8_t* buf, uint32_t len); +void AudioMgr_CreateNextAudioBuffer(s16* samples, u32 num_samples); +int Controller_ShouldRumble(size_t slot); +void Controller_BlockGameInput(); +void Controller_UnblockGameInput(); +void Overlay_DisplayText(float duration, const char* text); +void Overlay_DisplayText_Seconds(int seconds, const char* text); + +void Gfx_RegisterBlendedTexture(const char* name, u8* mask, u8* replacement); +void CheckTracker_OnMessageClose(); + +int32_t GetGIID(uint32_t itemID); +#endif + +#ifdef __cplusplus +extern "C" { +#endif +uint64_t GetUnixTimestamp(); +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/mm/2s2h/Extractor/EndianCvt.o b/mm/2s2h/Extractor/EndianCvt.o Binary files differnew file mode 100644 index 000000000..23c9daa88 --- /dev/null +++ b/mm/2s2h/Extractor/EndianCvt.o diff --git a/mm/2s2h/Extractor/Extract.cpp b/mm/2s2h/Extractor/Extract.cpp new file mode 100644 index 000000000..ae3e325fb --- /dev/null +++ b/mm/2s2h/Extractor/Extract.cpp @@ -0,0 +1,603 @@ +#ifdef _WIN32 +#include <Windows.h> +#include <winuser.h> +#include <shlwapi.h> +#pragma comment(lib, "Shlwapi.lib") +#endif +#include "Extract.h" +#include "portable-file-dialogs.h" +#include <Utils/BitConverter.h> + +#ifdef unix +#include <dirent.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#endif + +#ifdef _MSC_VER +#define BSWAP32 _byteswap_ulong +#define BSWAP16 _byteswap_ushort +#elif __has_include(<byteswap.h>) +#include <byteswap.h> +#define BSWAP32 bswap_32 +#define BSWAP16 bswap_16 +#else +#define BSWAP16(value) ((((value)&0xff) << 8) | ((value) >> 8)) + +#define BSWAP32(value) \ + (((uint32_t)BSWAP16((uint16_t)((value)&0xffff)) << 16) | (uint32_t)BSWAP16((uint16_t)((value) >> 16))) +#endif + +#if defined(_MSC_VER) +#define UNREACHABLE __assume(0) +#elif __llvm__ +#define UNREACHABLE __builtin_assume(0) +#else +#define UNREACHABLE __builtin_unreachable(); +#endif + +#include <stdlib.h> + +#include <SDL2/SDL_messagebox.h> + +#include <array> +#include <fstream> +#include <filesystem> +#include <unordered_map> +#include <random> +#include <string> + +extern "C" uint32_t CRC32C(unsigned char* data, size_t dataSize); + +static constexpr uint32_t OOT_PAL_GC = 0x09465AC3; +static constexpr uint32_t OOT_PAL_MQ = 0x1D4136F3; +static constexpr uint32_t OOT_PAL_GC_DBG1 = 0x871E1C92; // 03-21-2002 build +static constexpr uint32_t OOT_PAL_GC_DBG2 = 0x87121EFE; // 03-13-2002 build +static constexpr uint32_t OOT_PAL_GC_MQ_DBG = 0x917D18F6; +static constexpr uint32_t OOT_PAL_10 = 0xB044B569; +static constexpr uint32_t OOT_PAL_11 = 0xB2055FBD; +static constexpr uint32_t MM_US_10 = 0x5354631C; + +static const std::unordered_map<uint32_t, const char*> verMap = { + { MM_US_10, "U.S 1.0" }, + //{ OOT_PAL_GC, "PAL Gamecube" }, + //{ OOT_PAL_MQ, "PAL MQ" }, + //{ OOT_PAL_GC_DBG1, "PAL Debug 1" }, + //{ OOT_PAL_GC_DBG2, "PAL Debug 2" }, + //{ OOT_PAL_GC_MQ_DBG, "PAL MQ Debug" }, + //{ OOT_PAL_10, "PAL N64 1.0" }, + //{ OOT_PAL_11, "PAL N64 1.1" }, +}; + +// TODO only check the first 54MB of the rom. +static constexpr std::array<const uint32_t, 10> goodCrcs = { + + //0xfa8c0555, // MQ DBG 64MB (Original overdump) + //0x8652ac4c, // MQ DBG 64MB + //0x5B8A1EB7, // MQ DBG 64MB (Empty overdump) + //0x1f731ffe, // MQ DBG 54MB + //0x044b3982, // NMQ DBG 54MB + //0xEB15D7B9, // NMQ DBG 64MB + //0xDA8E61BF, // GC PAL + //0x7A2FAE68, // GC MQ PAL + //0xFD9913B1, // N64 PAL 1.0 + //0xE033FBBA, // N64 PAL 1.1 +}; + +enum class ButtonId : int { + YES, + NO, + FIND, +}; + + +void Extractor::ShowErrorBox(const char* title, const char* text) { +#ifdef _WIN32 + MessageBoxA(nullptr, text, title, MB_OK | MB_ICONERROR); +#else + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, title, text, nullptr); +#endif +} + +void Extractor::ShowSizeErrorBox() const { + std::unique_ptr<char[]> boxBuffer = std::make_unique<char[]>(mCurrentRomPath.size() + 100); + snprintf(boxBuffer.get(), mCurrentRomPath.size() + 100, + "The rom file %s was not a valid size. Was %zu MB, expecting 32, 54, or 64MB.", mCurrentRomPath.c_str(), + mCurRomSize / MB_BASE); + ShowErrorBox("Invalid Rom Size", boxBuffer.get()); +} + +void Extractor::ShowCrcErrorBox() const { + ShowErrorBox("Rom CRC invalid", "Rom CRC did not match the list of known good roms. Please find another."); +} + +int Extractor::ShowRomPickBox(uint32_t verCrc) const { + std::unique_ptr<char[]> boxBuffer = std::make_unique<char[]>(mCurrentRomPath.size() + 100); + SDL_MessageBoxData boxData = { 0 }; + SDL_MessageBoxButtonData buttons[3] = { { 0 } }; + int ret; + + buttons[0].buttonid = 0; + buttons[0].text = "Yes"; + buttons[0].flags = SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT; + buttons[1].buttonid = 1; + buttons[1].text = "No"; + buttons[1].flags = SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT; + buttons[2].buttonid = 2; + buttons[2].text = "Find ROM"; + boxData.numbuttons = 3; + boxData.flags = SDL_MESSAGEBOX_INFORMATION; + boxData.message = boxBuffer.get(); + boxData.title = "Rom Detected"; + boxData.window = nullptr; + + boxData.buttons = buttons; + snprintf(boxBuffer.get(), mCurrentRomPath.size() + 100, + "Rom detected: %s, Header CRC32: %8X. It appears to be: %s. Use this rom?", mCurrentRomPath.c_str(), + verCrc, verMap.at(verCrc)); + + SDL_ShowMessageBox(&boxData, &ret); + return ret; +} + +int Extractor::ShowYesNoBox(const char* title, const char* box) { + int ret; +#ifdef _WIN32 + ret = MessageBoxA(nullptr, box, title, MB_YESNO | MB_ICONQUESTION); +#else + SDL_MessageBoxData boxData = { 0 }; + SDL_MessageBoxButtonData buttons[2] = { { 0 } }; + + buttons[0].buttonid = IDYES; + buttons[0].text = "Yes"; + buttons[0].flags = SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT; + buttons[1].buttonid = IDNO; + buttons[1].text = "No"; + buttons[1].flags = SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT; + boxData.numbuttons = 2; + boxData.flags = SDL_MESSAGEBOX_INFORMATION; + boxData.message = box; + boxData.title = title; + boxData.buttons = buttons; + SDL_ShowMessageBox(&boxData, &ret); +#endif + return ret; +} + +void Extractor::SetRomInfo(const std::string& path) { + mCurrentRomPath = path; + mCurRomSize = GetCurRomSize(); +} + +void Extractor::FilterRoms(std::vector<std::string>& roms, RomSearchMode searchMode) { + std::ifstream inFile; + std::vector<std::string>::iterator it = roms.begin(); + + while (it != roms.end()) { + std::string rom = *it; + SetRomInfo(rom); + + // Skip. We will handle rom size errors later on after filtering + if (!ValidateRomSize()) { + it++; + continue; + } + + inFile.open(rom, std::ios::in | std::ios::binary); + inFile.read((char*)mRomData.get(), mCurRomSize); + inFile.clear(); + inFile.close(); + + BitConverter::RomToBigEndian(mRomData.get(), mCurRomSize); + + // Rom doesn't claim to be valid + // Game type doesn't match search mode + if (!verMap.contains(GetRomVerCrc()) || + (searchMode == RomSearchMode::Vanilla && IsMasterQuest()) || + (searchMode == RomSearchMode::MQ && !IsMasterQuest())) { + it = roms.erase(it); + continue; + } + + it++; + } +} + +void Extractor::GetRoms(std::vector<std::string>& roms) { +#ifdef _WIN32 + WIN32_FIND_DATAA ffd; + HANDLE h = FindFirstFileA(".\\*", &ffd); + + do { + if (!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { + char* ext = PathFindExtensionA(ffd.cFileName); + + // Check for any standard N64 rom file extensions. + if ((strcmp(ext, ".z64") == 0) || (strcmp(ext, ".n64") == 0) || (strcmp(ext, ".v64") == 0)) + roms.push_back(ffd.cFileName); + } + } while (FindNextFileA(h, &ffd) != 0); + // if (h != nullptr) { + // CloseHandle(h); + //} +#elif unix + // Open the directory of the app. + DIR* d = opendir("."); + struct dirent* dir; + + if (d != NULL) { + // Go through each file in the directory + while ((dir = readdir(d)) != NULL) { + struct stat path; + + // Check if current entry is not folder + stat(dir->d_name, &path); + if (S_ISREG(path.st_mode)) { + + // Get the position of the extension character. + char* ext = strrchr(dir->d_name, '.'); + if (ext != NULL && (strcmp(ext, ".z64") == 0 || strcmp(ext, ".n64") == 0 || + strcmp(ext, ".v64") == 0)) { + roms.push_back(dir->d_name); + } + } + } + } + closedir(d); +#else + for (const auto& file : std::filesystem::directory_iterator("./")) { + if (file.is_directory()) + continue; + if ((file.path().extension() == ".n64") || (file.path().extension() == ".z64") || + (file.path().extension() == ".v64")) { + roms.push_back((file.path())); + } + } +#endif +} + +bool Extractor::GetRomPathFromBox() { +#ifdef _WIN32 + OPENFILENAMEA box = { 0 }; + char nameBuffer[512]; + nameBuffer[0] = 0; + + box.lStructSize = sizeof(box); + box.lpstrFile = nameBuffer; + box.nMaxFile = sizeof(nameBuffer) / sizeof(nameBuffer[0]); + box.lpstrTitle = "Open Rom"; + box.Flags = OFN_NOCHANGEDIR | OFN_ENABLESIZING | OFN_FILEMUSTEXIST | OFN_LONGNAMES | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY; + box.lpstrFilter = "N64 Roms\0*.z64;*.v64;*.n64\0\0"; + if (!GetOpenFileNameA(&box)) { + DWORD err = CommDlgExtendedError(); + // GetOpenFileName will return 0 but no error is set if the user just closes the box. + if (err != 0) { + const char* errStr = nullptr; + switch (err) { + case FNERR_BUFFERTOOSMALL: + errStr = "Path buffer too small. Move file closer to root of your drive"; + break; + case FNERR_INVALIDFILENAME: + errStr = "File name for rom provided is invalid."; + break; + case FNERR_SUBCLASSFAILURE: + errStr = "Failed to open a filebox because there is not enough RAM to do so."; + break; + } + MessageBoxA(nullptr, "Box Error", errStr, MB_OK | MB_ICONERROR); + return false; + } + } + // The box was closed without something being selected. + if (nameBuffer[0] == 0) { + return false; + } + mCurrentRomPath = nameBuffer; + #else + auto selection = pfd::open_file("Select a file", ".", { "N64 Roms", "*.z64 *.n64 *.v64" }).result(); + + if (selection.empty()) { + return false; + } + + mCurrentRomPath = selection[0]; + #endif + mCurRomSize = GetCurRomSize(); + return true; +} + +uint32_t Extractor::GetRomVerCrc() const { + return BSWAP32(((uint32_t*)mRomData.get())[4]); +} + +size_t Extractor::GetCurRomSize() const { + return std::filesystem::file_size(mCurrentRomPath); +} + +bool Extractor::ValidateAndFixRom() { + // The MQ debug rom sometimes has the header patched to look like a US rom. Change it back + if (GetRomVerCrc() == OOT_PAL_GC_MQ_DBG) { + mRomData[0x3E] = 'P'; + } + + const uint32_t actualCrc = CRC32C(mRomData.get(), mCurRomSize); + + for (const uint32_t crc : goodCrcs) { + if (actualCrc == crc) { + return true; + } + } + return false; +} + +bool Extractor::ValidateRomSize() const { + if (mCurRomSize != MB32 && mCurRomSize != MB54 && mCurRomSize != MB64) { + return false; + } + return true; +} + +bool Extractor::ValidateRom(bool skipCrcTextBox) { + if (!ValidateRomSize()) { + ShowSizeErrorBox(); + return false; + } + if (!ValidateAndFixRom()) { + if (!skipCrcTextBox) { + ShowCrcErrorBox(); + } + return false; + } + return true; +} + +bool Extractor::ManuallySearchForRom() { + std::ifstream inFile; + + if (!GetRomPathFromBox()) { + ShowErrorBox("No rom selected", "No Rom selected. Exiting"); + return false; + } + + inFile.open(mCurrentRomPath, std::ios::in | std::ios::binary); + + if (!inFile.is_open()) { + return false; // TODO Handle error + } + + inFile.read((char*)mRomData.get(), mCurRomSize); + inFile.close(); + BitConverter::RomToBigEndian(mRomData.get(), mCurRomSize); + + if (!ValidateRom()) { + return false; + } + + return true; +} + +bool Extractor::ManuallySearchForRomMatchingType(RomSearchMode searchMode) { + if (!ManuallySearchForRom()) { + return false; + } + + char msgBuf[150]; + snprintf(msgBuf, 150, "The selected rom does not match the expected game type\nExpected type: %s.\n\nDo you want to search again?", + searchMode == RomSearchMode::MQ ? "Master Quest" : "Vanilla"); + + while ((searchMode == RomSearchMode::Vanilla && IsMasterQuest()) || + (searchMode == RomSearchMode::MQ && !IsMasterQuest())) { + int ret = ShowYesNoBox("Wrong Game Type", msgBuf); + switch (ret) { + case IDYES: + if (!ManuallySearchForRom()) { + return false; + } + continue; + case IDNO: + return false; + default: + UNREACHABLE; + break; + } + } + + return true; +} + +bool Extractor::Run(RomSearchMode searchMode) { + std::vector<std::string> roms; + std::ifstream inFile; + + GetRoms(roms); + FilterRoms(roms, searchMode); + + if (roms.empty()) { + int ret = ShowYesNoBox("No roms found", "No roms found. Look for one?"); + + switch (ret) { + case IDYES: + if (!ManuallySearchForRomMatchingType(searchMode)) { + return false; + } + break; + case IDNO: + ShowErrorBox("No rom selected", "No rom selected. Exiting"); + return false; + default: + UNREACHABLE; + break; + } + } + + for (const auto& rom : roms) { + SetRomInfo(rom); + + if (!ValidateRomSize()) { + ShowSizeErrorBox(); + continue; + } + + inFile.open(rom, std::ios::in | std::ios::binary); + inFile.read((char*)mRomData.get(), mCurRomSize); + inFile.clear(); + inFile.close(); + BitConverter::RomToBigEndian(mRomData.get(), mCurRomSize); + + int option = ShowRomPickBox(GetRomVerCrc()); + + if (option == (int)ButtonId::YES) { + if (!ValidateRom(true)) { + if (rom == roms.back()) { + ShowCrcErrorBox(); + } else { + ShowErrorBox("Rom CRC invalid", + "Rom CRC did not match the list of known good roms. Trying the next one..."); + } + continue; + } + break; + } else if (option == (int)ButtonId::FIND) { + if (!ManuallySearchForRomMatchingType(searchMode)) { + return false; + } + break; + } else if (option == (int)ButtonId::NO) { + if (rom == roms.back()) { + ShowErrorBox("No rom provided", "No rom provided. Exiting"); + return false; + } + continue; + } + break; + } + return true; +} + +bool Extractor::IsMasterQuest() const { + switch (GetRomVerCrc()) { + case OOT_PAL_MQ: + case OOT_PAL_GC_MQ_DBG: + return true; + case OOT_PAL_10: + case OOT_PAL_11: + case OOT_PAL_GC: + case OOT_PAL_GC_DBG1: + return false; + default: + UNREACHABLE; + } +} + +const char* Extractor::GetZapdVerStr() const { + switch (GetRomVerCrc()) { + case OOT_PAL_GC: + return "GC_NMQ_PAL_F"; + case OOT_PAL_MQ: + return "GC_MQ_PAL_F"; + case OOT_PAL_GC_DBG1: + return "GC_NMQ_D"; + case OOT_PAL_GC_MQ_DBG: + return "GC_MQ_D"; + case OOT_PAL_10: + return "N64_PAL_10"; + case OOT_PAL_11: + return "N64_PAL_11"; + default: + // We should never be in a state where this path happens. + UNREACHABLE; + break; + } +} + +std::string Extractor::Mkdtemp() { + std::string temp_dir = std::filesystem::temp_directory_path().string(); + + // create 6 random alphanumeric characters + static const char charset[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_int_distribution<> dist(0, sizeof(charset) - 1); + + char randchr[7]; + for (int i = 0; i < 6; i++) { + randchr[i] = charset[dist(gen)]; + } + randchr[6] = '\0'; + + std::string tmppath = temp_dir + "/extractor-" + randchr; + std::filesystem::create_directory(tmppath); + return tmppath; +} + +extern "C" int zapd_main(int argc, char** argv); + +bool Extractor::CallZapd(std::string installPath, std::string exportdir) { + constexpr int argc = 16; + char xmlPath[1024]; + char confPath[1024]; + std::array<const char*, argc> argv; + const char* version = GetZapdVerStr(); + const char* otrFile = IsMasterQuest() ? "oot-mq.otr" : "oot.otr"; + + std::string romPath = std::filesystem::absolute(mCurrentRomPath).string(); + installPath = std::filesystem::absolute(installPath).string(); + exportdir = std::filesystem::absolute(exportdir).string(); + // Work this out in the temporary folder + std::string tempdir = Mkdtemp(); + std::string curdir = std::filesystem::current_path().string(); +#ifdef _WIN32 + std::filesystem::copy(installPath + "/assets", tempdir + "/assets", + std::filesystem::copy_options::recursive | std::filesystem::copy_options::update_existing); +#else + std::filesystem::create_symlink(installPath + "/assets", tempdir + "/assets"); +#endif + + std::filesystem::current_path(tempdir); + + snprintf(xmlPath, 1024, "assets/extractor/xmls/%s", version); + snprintf(confPath, 1024, "assets/extractor/Config_%s.xml", version); + + argv[0] = "ZAPD"; + argv[1] = "ed"; + argv[2] = "-i"; + argv[3] = xmlPath; + argv[4] = "-b"; + argv[5] = romPath.c_str(); + argv[6] = "-fl"; + argv[7] = "assets/extractor/filelists"; + argv[8] = "-gsf"; + argv[9] = "1"; + argv[10] = "-rconf"; + argv[11] = confPath; + argv[12] = "-se"; + argv[13] = "OTR"; + argv[14] = "--otrfile"; + argv[15] = otrFile; + +#ifdef _WIN32 + // Grab a handle to the command window. + HWND cmdWindow = GetConsoleWindow(); + + // Normally the command window is hidden. We want the window to be shown here so the user can see the progess of the extraction. + ShowWindow(cmdWindow, SW_SHOW); + SetWindowPos(cmdWindow, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); +#endif + + zapd_main(argc, (char**)argv.data()); + +#ifdef _WIN32 + // Hide the command window again. + ShowWindow(cmdWindow, SW_HIDE); +#endif + + std::filesystem::copy(otrFile, exportdir + "/" + otrFile, std::filesystem::copy_options::overwrite_existing); + + // Go back to where this game was executed from + std::filesystem::current_path(curdir); + std::filesystem::remove_all(tempdir); + + return 0; +} + diff --git a/mm/2s2h/Extractor/Extract.h b/mm/2s2h/Extractor/Extract.h new file mode 100644 index 000000000..6c9b4a078 --- /dev/null +++ b/mm/2s2h/Extractor/Extract.h @@ -0,0 +1,64 @@ +#ifndef EXTRACT_H +#define EXTRACT_H + +#include <stdint.h> +#include <string> +#include <memory> +#include <vector> + +// Values come from windows.h +#ifndef IDYES +#define IDYES 6 +#endif +#ifndef IDNO +#define IDNO 7 +#endif + +static constexpr size_t MB_BASE = 1024 * 1024; +static constexpr size_t MB32 = 32 * MB_BASE; +static constexpr size_t MB54 = 54 * MB_BASE; +static constexpr size_t MB64 = 64 * MB_BASE; + +enum class RomSearchMode { + Both = 0, + Vanilla = 1, + MQ = 2, +}; + +class Extractor { + std::unique_ptr<unsigned char[]> mRomData = std::make_unique<unsigned char[]>(MB64); + std::string mCurrentRomPath; + size_t mCurRomSize = 0; + + bool GetRomPathFromBox(); + + uint32_t GetRomVerCrc() const; + size_t GetCurRomSize() const; + bool ValidateAndFixRom(); + bool ValidateRomSize() const; + + bool ValidateRom(bool skipCrcBox = false); + const char* GetZapdVerStr() const; + + void SetRomInfo(const std::string& path); + + void FilterRoms(std::vector<std::string>& roms, RomSearchMode searchMode); + void GetRoms(std::vector<std::string>& roms); + void ShowSizeErrorBox() const; + void ShowCrcErrorBox() const; + int ShowRomPickBox(uint32_t verCrc) const; + bool ManuallySearchForRom(); + bool ManuallySearchForRomMatchingType(RomSearchMode searchMode); + + public: + //TODO create some kind of abstraction for message boxes. + static int ShowYesNoBox(const char* title, const char* text); + static void ShowErrorBox(const char* title, const char* text); + bool IsMasterQuest() const; + + bool Run(RomSearchMode searchMode = RomSearchMode::Both); + bool CallZapd(std::string installPath, std::string exportdir); + const char* GetZapdStr(); + std::string Mkdtemp(); +}; +#endif diff --git a/mm/2s2h/Extractor/FastCrc32C.c b/mm/2s2h/Extractor/FastCrc32C.c new file mode 100644 index 000000000..d88b04beb --- /dev/null +++ b/mm/2s2h/Extractor/FastCrc32C.c @@ -0,0 +1,144 @@ +#include <stdint.h> +#include <stddef.h> + +// Force the compiler to assume we have support for the CRC32 intrinsic. We will check for our selves later. +// Clang will define both __llvm__ and __GNUC__ but GCC will only define __GNUC__. So we need to check for __llvm__ first. +#if ((defined(__llvm__) && (defined(__x86_64__) || defined(__i386__)))) +#pragma clang attribute push(__attribute__((target("crc32"))), apply_to = function) +#elif ((defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__)))) +// GCC Only lets you enable all of sse4.2 so we will for just this file and reset it at the end. +#pragma GCC push_options +#pragma GCC target("sse4.2") +#endif + +// Include headers for the CRC32 intrinsic and cpuid instruction on windows. No need to do any other checks because it assumes the target will support CRC32 +#ifdef _WIN32 +#include <immintrin.h> +#include <intrin.h> +// Same as above but these platforms use slightly different headers +#elif ((defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__)))) +#include <nmmintrin.h> +#include <cpuid.h> +#elif defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) +// Nothing cause its a compiler builtin +#else +#define NO_CRC_INTRIN +#endif + +#if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) +#define INTRIN_CRC32_64(crc, value) __asm__("crc32cx %w[c], %w[c], %x[v]" : [c] "+r"(crc) : [v] "r"(value)) +#define INTRIN_CRC32_32(crc, value) __asm__("crc32cw %w[c], %w[c], %w[v]" : [c] "+r"(crc) : [v] "r"(value)) +#define INTRIN_CRC32_16(crc, value) __asm__("crc32ch %w[c], %w[c], %w[v]" : [c] "+r"(crc) : [v] "r"(value)) +#define INTRIN_CRC32_8(crc, value) __asm__("crc32cb %w[c], %w[c], %w[v]" : [c] "+r"(crc) : [v] "r"(value)) +#elif defined(__GNUC__) || defined(_MSC_VER) +#define INTRIN_CRC32_64(crc, data) crc = _mm_crc32_u64(crc, data) +#define INTRIN_CRC32_32(crc, data) crc = _mm_crc32_u32(crc, data) +#define INTRIN_CRC32_16(crc, data) crc = _mm_crc32_u16(crc, data) +#define INTRIN_CRC32_8(crc, data) crc = _mm_crc32_u8(crc, data) +#endif + +static const uint32_t crc32Table[256] = { + 0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L, 0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL, 0x8AD958CFL, + 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL, 0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L, 0x105EC76FL, 0xE235446CL, + 0xF165B798L, 0x030E349BL, 0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L, 0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, + 0x89D76C54L, 0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL, 0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL, + 0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L, 0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L, 0x6DFE410EL, + 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL, 0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L, 0xF779DEAEL, 0x05125DADL, + 0x1642AE59L, 0xE4292D5AL, 0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL, 0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, + 0x6EF07595L, 0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L, 0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L, + 0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L, 0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L, 0x5125DAD3L, + 0xA34E59D0L, 0xB01EAA24L, 0x42752927L, 0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L, 0xDBFC821CL, 0x2997011FL, + 0x3AC7F2EBL, 0xC8AC71E8L, 0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L, 0x61C69362L, 0x93AD1061L, 0x80FDE395L, + 0x72966096L, 0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L, 0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L, + 0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L, 0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L, 0xB602C312L, + 0x44694011L, 0x5739B3E5L, 0xA55230E6L, 0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L, 0x3CDB9BDDL, 0xCEB018DEL, + 0xDDE0EB2AL, 0x2F8B6829L, 0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL, 0x456CAC67L, 0xB7072F64L, 0xA457DC90L, + 0x563C5F93L, 0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L, 0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL, + 0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L, 0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL, 0x1871A4D8L, + 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL, 0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L, 0xA24BB5A6L, 0x502036A5L, + 0x4370C551L, 0xB11B4652L, 0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL, 0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, + 0x3BC21E9DL, 0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L, 0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL, + 0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L, 0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L, 0xFF56BD19L, + 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL, 0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L, 0x0417B1DBL, 0xF67C32D8L, + 0xE52CC12CL, 0x1747422FL, 0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL, 0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, + 0x9D9E1AE0L, 0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL, 0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L, + 0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L, 0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL, 0xE330A81AL, + 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL, 0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L, 0x69E9F0D5L, 0x9B8273D6L, + 0x88D28022L, 0x7AB90321L, 0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL, 0xF36E6F75L, 0x0105EC76L, 0x12551F82L, + 0xE03E9C81L, 0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL, 0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL, + 0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L +}; +// On platforms that we know will never support a crc32 instruction (such as the WiiU) we will skip compiling this function in. +#ifndef NO_CRC_INTRIN + +static uint32_t CRC32IntrinImpl(unsigned char* data, size_t dataSize) { + uint32_t ret = 0xFFFFFFFF; + int64_t sizeSigned = dataSize; +// Only 64bit platforms support doing a CRC32 operation on a 64bit value +#if defined(_M_X64) || defined(__x86_64__) || defined(__aarch64__) + while ((sizeSigned -= sizeof(uint64_t)) >= 0) { + INTRIN_CRC32_64(ret, *(uint64_t*)data); + data += sizeof(uint64_t); + } + + if (sizeSigned & sizeof(uint32_t)) { + INTRIN_CRC32_32(ret, *(uint32_t*)data); + + data += sizeof(uint32_t); + } +// On 32 bit we can only do 32bit operations +#elif defined(_M_IX86) || defined(__i386__) + while ((sizeSigned -= sizeof(uint32_t)) >= 0) { + INTRIN_CRC32_32(ret, *(uint32_t*)data); + data += sizeof(uint32_t); + } +#endif + if (sizeSigned & sizeof(uint16_t)) { + INTRIN_CRC32_16(ret, *(uint16_t*)data); + data += sizeof(uint16_t); + } + + if (sizeSigned & sizeof(uint8_t)) { + INTRIN_CRC32_8(ret, *data); + } + + return ~ret; +} +#endif + +static uint32_t CRC32TableImpl(unsigned char* data, size_t dataSize) { + const uint8_t* p = data; + uint32_t crc = 0xFFFFFFFF; + + while (dataSize--) + crc = crc32Table[(crc ^ *p++) & 0xff] ^ (crc >> 8); + + return ~crc; +} + +uint32_t CRC32C(unsigned char* data, size_t dataSize) { +#ifndef NO_CRC_INTRIN + // Test to make sure the CPU supports the CRC32 intrinsic + unsigned int cpuidData[4]; +#ifdef _WIN32 + __cpuid(cpuidData, 1); +#elif __APPLE__ || (defined(__aarch64__) && defined(__ARM_FEATURE_CRC32)) +// Every Mac that supports SoH should support this instruction. Also check for ARM64 at the same time + return CRC32IntrinImpl(data, dataSize); +#else + __get_cpuid(1, &cpuidData[0], &cpuidData[1], &cpuidData[2], &cpuidData[3]); +#endif + + if (cpuidData[2] & (1 << 20)) { // bit_SSE4_2 + return CRC32IntrinImpl(data, dataSize); + } +#endif // NO_CRC_INTRIN + return CRC32TableImpl(data, dataSize); +} + +#if ((defined(__llvm__) && (defined(__x86_64__) || defined(__i386__)))) +#pragma clang attribute pop +#elif ((defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__)))) +#pragma GCC pop_options +#else +#endif diff --git a/mm/2s2h/Extractor/portable-file-dialogs.h b/mm/2s2h/Extractor/portable-file-dialogs.h new file mode 100644 index 000000000..1fc79a291 --- /dev/null +++ b/mm/2s2h/Extractor/portable-file-dialogs.h @@ -0,0 +1,1887 @@ +// +// Portable File Dialogs +// +// Copyright © 2018–2022 Sam Hocevar <sam@hocevar.net> +// +// This library is free software. It comes without any warranty, to +// the extent permitted by applicable law. You can redistribute it +// and/or modify it under the terms of the Do What the Fuck You Want +// to Public License, Version 2, as published by the WTFPL Task Force. +// See http://www.wtfpl.net/ for more details. +// + +#pragma once + +#if _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN 1 +#endif +#include <windows.h> +#include <commdlg.h> +#include <shlobj.h> +#include <shobjidl.h> // IFileDialog +#include <shellapi.h> +#include <strsafe.h> +#include <future> // std::async +#include <userenv.h> // GetUserProfileDirectory() + +#elif __EMSCRIPTEN__ +#include <emscripten.h> + +#else +#ifndef _POSIX_C_SOURCE +# define _POSIX_C_SOURCE 2 // for popen() +#endif +#ifdef __APPLE__ +# ifndef _DARWIN_C_SOURCE +# define _DARWIN_C_SOURCE +# endif +#endif +#include <cstdio> // popen() +#include <cstdlib> // std::getenv() +#include <fcntl.h> // fcntl() +#include <unistd.h> // read(), pipe(), dup2(), getuid() +#include <csignal> // ::kill, std::signal +#include <sys/stat.h> // stat() +#include <sys/wait.h> // waitpid() +#include <pwd.h> // getpwnam() +#endif + +#include <string> // std::string +#include <memory> // std::shared_ptr +#include <iostream> // std::ostream +#include <map> // std::map +#include <set> // std::set +#include <regex> // std::regex +#include <thread> // std::mutex, std::this_thread +#include <chrono> // std::chrono + +// Versions of mingw64 g++ up to 9.3.0 do not have a complete IFileDialog +#ifndef PFD_HAS_IFILEDIALOG +# define PFD_HAS_IFILEDIALOG 1 +# if (defined __MINGW64__ || defined __MINGW32__) && defined __GXX_ABI_VERSION +# if __GXX_ABI_VERSION <= 1013 +# undef PFD_HAS_IFILEDIALOG +# define PFD_HAS_IFILEDIALOG 0 +# endif +# endif +#endif + +namespace pfd +{ + +enum class button +{ + cancel = -1, + ok, + yes, + no, + abort, + retry, + ignore, +}; + +enum class choice +{ + ok = 0, + ok_cancel, + yes_no, + yes_no_cancel, + retry_cancel, + abort_retry_ignore, +}; + +enum class icon +{ + info = 0, + warning, + error, + question, +}; + +// Additional option flags for various dialog constructors +enum class opt : uint8_t +{ + none = 0, + // For file open, allow multiselect. + multiselect = 0x1, + // For file save, force overwrite and disable the confirmation dialog. + force_overwrite = 0x2, + // For folder select, force path to be the provided argument instead + // of the last opened directory, which is the Microsoft-recommended, + // user-friendly behaviour. + force_path = 0x4, +}; + +inline opt operator |(opt a, opt b) { return opt(uint8_t(a) | uint8_t(b)); } +inline bool operator &(opt a, opt b) { return bool(uint8_t(a) & uint8_t(b)); } + +// The settings class, only exposing to the user a way to set verbose mode +// and to force a rescan of installed desktop helpers (zenity, kdialog…). +class settings +{ +public: + static bool available(); + + static void verbose(bool value); + static void rescan(); + +protected: + explicit settings(bool resync = false); + + bool check_program(std::string const &program); + + inline bool is_osascript() const; + inline bool is_zenity() const; + inline bool is_kdialog() const; + + enum class flag + { + is_scanned = 0, + is_verbose, + + has_zenity, + has_matedialog, + has_qarma, + has_kdialog, + is_vista, + + max_flag, + }; + + // Static array of flags for internal state + bool const &flags(flag in_flag) const; + + // Non-const getter for the static array of flags + bool &flags(flag in_flag); +}; + +// Internal classes, not to be used by client applications +namespace internal +{ + +// Process wait timeout, in milliseconds +static int const default_wait_timeout = 20; + +class executor +{ + friend class dialog; + +public: + // High level function to get the result of a command + std::string result(int *exit_code = nullptr); + + // High level function to abort + bool kill(); + +#if _WIN32 + void start_func(std::function<std::string(int *)> const &fun); + static BOOL CALLBACK enum_windows_callback(HWND hwnd, LPARAM lParam); +#elif __EMSCRIPTEN__ + void start(int exit_code); +#else + void start_process(std::vector<std::string> const &command); +#endif + + ~executor(); + +protected: + bool ready(int timeout = default_wait_timeout); + void stop(); + +private: + bool m_running = false; + std::string m_stdout; + int m_exit_code = -1; +#if _WIN32 + std::future<std::string> m_future; + std::set<HWND> m_windows; + std::condition_variable m_cond; + std::mutex m_mutex; + DWORD m_tid; +#elif __EMSCRIPTEN__ || __NX__ + // FIXME: do something +#else + pid_t m_pid = 0; + int m_fd = -1; +#endif +}; + +class platform +{ +protected: +#if _WIN32 + // Helper class around LoadLibraryA() and GetProcAddress() with some safety + class dll + { + public: + dll(std::string const &name); + ~dll(); + + template<typename T> class proc + { + public: + proc(dll const &lib, std::string const &sym) + : m_proc(reinterpret_cast<T *>((void *)::GetProcAddress(lib.handle, sym.c_str()))) + {} + + operator bool() const { return m_proc != nullptr; } + operator T *() const { return m_proc; } + + private: + T *m_proc; + }; + + private: + HMODULE handle; + }; + + // Helper class around CoInitialize() and CoUnInitialize() + class ole32_dll : public dll + { + public: + ole32_dll(); + ~ole32_dll(); + bool is_initialized(); + + private: + HRESULT m_state; + }; + + // Helper class around CreateActCtx() and ActivateActCtx() + class new_style_context + { + public: + new_style_context(); + ~new_style_context(); + + private: + HANDLE create(); + ULONG_PTR m_cookie = 0; + }; +#endif +}; + +class dialog : protected settings, protected platform +{ +public: + bool ready(int timeout = default_wait_timeout) const; + bool kill() const; + +protected: + explicit dialog(); + + std::vector<std::string> desktop_helper() const; + static std::string buttons_to_name(choice _choice); + static std::string get_icon_name(icon _icon); + + std::string powershell_quote(std::string const &str) const; + std::string osascript_quote(std::string const &str) const; + std::string shell_quote(std::string const &str) const; + + // Keep handle to executing command + std::shared_ptr<executor> m_async; +}; + +class file_dialog : public dialog +{ +protected: + enum type + { + open, + save, + folder, + }; + + file_dialog(type in_type, + std::string const &title, + std::string const &default_path = "", + std::vector<std::string> const &filters = {}, + opt options = opt::none); + +protected: + std::string string_result(); + std::vector<std::string> vector_result(); + +#if _WIN32 + static int CALLBACK bffcallback(HWND hwnd, UINT uMsg, LPARAM, LPARAM pData); +#if PFD_HAS_IFILEDIALOG + std::string select_folder_vista(IFileDialog *ifd, bool force_path); +#endif + + std::wstring m_wtitle; + std::wstring m_wdefault_path; + + std::vector<std::string> m_vector_result; +#endif +}; + +} // namespace internal + +// +// The path class provides some platform-specific path constants +// + +class path : protected internal::platform +{ +public: + static std::string home(); + static std::string separator(); +}; + +// +// The notify widget +// + +class notify : public internal::dialog +{ +public: + notify(std::string const &title, + std::string const &message, + icon _icon = icon::info); +}; + +// +// The message widget +// + +class message : public internal::dialog +{ +public: + message(std::string const &title, + std::string const &text, + choice _choice = choice::ok_cancel, + icon _icon = icon::info); + + button result(); + +private: + // Some extra logic to map the exit code to button number + std::map<int, button> m_mappings; +}; + +// +// The open_file, save_file, and open_folder widgets +// + +class open_file : public internal::file_dialog +{ +public: + open_file(std::string const &title, + std::string const &default_path = "", + std::vector<std::string> const &filters = { "All Files", "*" }, + opt options = opt::none); + +#if defined(__has_cpp_attribute) +#if __has_cpp_attribute(deprecated) + // Backwards compatibility + [[deprecated("Use pfd::opt::multiselect instead of allow_multiselect")]] +#endif +#endif + open_file(std::string const &title, + std::string const &default_path, + std::vector<std::string> const &filters, + bool allow_multiselect); + + std::vector<std::string> result(); +}; + +class save_file : public internal::file_dialog +{ +public: + save_file(std::string const &title, + std::string const &default_path = "", + std::vector<std::string> const &filters = { "All Files", "*" }, + opt options = opt::none); + +#if defined(__has_cpp_attribute) +#if __has_cpp_attribute(deprecated) + // Backwards compatibility + [[deprecated("Use pfd::opt::force_overwrite instead of confirm_overwrite")]] +#endif +#endif + save_file(std::string const &title, + std::string const &default_path, + std::vector<std::string> const &filters, + bool confirm_overwrite); + + std::string result(); +}; + +class select_folder : public internal::file_dialog +{ +public: + select_folder(std::string const &title, + std::string const &default_path = "", + opt options = opt::none); + + std::string result(); +}; + +// +// Below this are all the method implementations. You may choose to define the +// macro PFD_SKIP_IMPLEMENTATION everywhere before including this header except +// in one place. This may reduce compilation times. +// + +#if !defined PFD_SKIP_IMPLEMENTATION + +// internal free functions implementations + +namespace internal +{ + +#if _WIN32 +static inline std::wstring str2wstr(std::string const &str) +{ + int len = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), (int)str.size(), nullptr, 0); + std::wstring ret(len, '\0'); + MultiByteToWideChar(CP_UTF8, 0, str.c_str(), (int)str.size(), (LPWSTR)ret.data(), (int)ret.size()); + return ret; +} + +static inline std::string wstr2str(std::wstring const &str) +{ + int len = WideCharToMultiByte(CP_UTF8, 0, str.c_str(), (int)str.size(), nullptr, 0, nullptr, nullptr); + std::string ret(len, '\0'); + WideCharToMultiByte(CP_UTF8, 0, str.c_str(), (int)str.size(), (LPSTR)ret.data(), (int)ret.size(), nullptr, nullptr); + return ret; +} + +static inline bool is_vista() +{ + OSVERSIONINFOEXW osvi; + memset(&osvi, 0, sizeof(osvi)); + DWORDLONG const mask = VerSetConditionMask( + VerSetConditionMask( + VerSetConditionMask( + 0, VER_MAJORVERSION, VER_GREATER_EQUAL), + VER_MINORVERSION, VER_GREATER_EQUAL), + VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); + osvi.dwOSVersionInfoSize = sizeof(osvi); + osvi.dwMajorVersion = HIBYTE(_WIN32_WINNT_VISTA); + osvi.dwMinorVersion = LOBYTE(_WIN32_WINNT_VISTA); + osvi.wServicePackMajor = 0; + + return VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, mask) != FALSE; +} +#endif + +// This is necessary until C++20 which will have std::string::ends_with() etc. + +static inline bool ends_with(std::string const &str, std::string const &suffix) +{ + return suffix.size() <= str.size() && + str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0; +} + +static inline bool starts_with(std::string const &str, std::string const &prefix) +{ + return prefix.size() <= str.size() && + str.compare(0, prefix.size(), prefix) == 0; +} + +// This is necessary until C++17 which will have std::filesystem::is_directory + +static inline bool is_directory(std::string const &path) +{ +#if _WIN32 + auto attr = GetFileAttributesA(path.c_str()); + return attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY); +#elif __EMSCRIPTEN__ + // TODO + return false; +#else + struct stat s; + return stat(path.c_str(), &s) == 0 && S_ISDIR(s.st_mode); +#endif +} + +// This is necessary because getenv is not thread-safe + +static inline std::string getenv(std::string const &str) +{ +#if _MSC_VER + char *buf = nullptr; + size_t size = 0; + if (_dupenv_s(&buf, &size, str.c_str()) == 0 && buf) + { + std::string ret(buf); + free(buf); + return ret; + } + return ""; +#else + auto buf = std::getenv(str.c_str()); + return buf ? buf : ""; +#endif +} + +} // namespace internal + +// settings implementation + +inline settings::settings(bool resync) +{ + flags(flag::is_scanned) &= !resync; + + if (flags(flag::is_scanned)) + return; + + auto pfd_verbose = internal::getenv("PFD_VERBOSE"); + auto match_no = std::regex("(|0|no|false)", std::regex_constants::icase); + if (!std::regex_match(pfd_verbose, match_no)) + flags(flag::is_verbose) = true; + +#if _WIN32 + flags(flag::is_vista) = internal::is_vista(); +#elif !__APPLE__ + flags(flag::has_zenity) = check_program("zenity"); + flags(flag::has_matedialog) = check_program("matedialog"); + flags(flag::has_qarma) = check_program("qarma"); + flags(flag::has_kdialog) = check_program("kdialog"); + + // If multiple helpers are available, try to default to the best one + if (flags(flag::has_zenity) && flags(flag::has_kdialog)) + { + auto desktop_name = internal::getenv("XDG_SESSION_DESKTOP"); + if (desktop_name == std::string("gnome")) + flags(flag::has_kdialog) = false; + else if (desktop_name == std::string("KDE")) + flags(flag::has_zenity) = false; + } +#endif + + flags(flag::is_scanned) = true; +} + +inline bool settings::available() +{ +#if _WIN32 + return true; +#elif __APPLE__ + return true; +#elif __EMSCRIPTEN__ + // FIXME: Return true after implementation is complete. + return false; +#else + settings tmp; + return tmp.flags(flag::has_zenity) || + tmp.flags(flag::has_matedialog) || + tmp.flags(flag::has_qarma) || + tmp.flags(flag::has_kdialog); +#endif +} + +inline void settings::verbose(bool value) +{ + settings().flags(flag::is_verbose) = value; +} + +inline void settings::rescan() +{ + settings(/* resync = */ true); +} + +// Check whether a program is present using “which”. +inline bool settings::check_program(std::string const &program) +{ +#if _WIN32 + (void)program; + return false; +#elif __EMSCRIPTEN__ + (void)program; + return false; +#else + int exit_code = -1; + internal::executor async; + async.start_process({"/bin/sh", "-c", "which " + program}); + async.result(&exit_code); + return exit_code == 0; +#endif +} + +inline bool settings::is_osascript() const +{ +#if __APPLE__ + return true; +#else + return false; +#endif +} + +inline bool settings::is_zenity() const +{ + return flags(flag::has_zenity) || + flags(flag::has_matedialog) || + flags(flag::has_qarma); +} + +inline bool settings::is_kdialog() const +{ + return flags(flag::has_kdialog); +} + +inline bool const &settings::flags(flag in_flag) const +{ + static bool flags[size_t(flag::max_flag)]; + return flags[size_t(in_flag)]; +} + +inline bool &settings::flags(flag in_flag) +{ + return const_cast<bool &>(static_cast<settings const *>(this)->flags(in_flag)); +} + +// path implementation +inline std::string path::home() +{ +#if _WIN32 + // First try the USERPROFILE environment variable + auto user_profile = internal::getenv("USERPROFILE"); + if (user_profile.size() > 0) + return user_profile; + // Otherwise, try GetUserProfileDirectory() + HANDLE token = nullptr; + DWORD len = MAX_PATH; + char buf[MAX_PATH] = { '\0' }; + if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) + { + dll userenv("userenv.dll"); + dll::proc<BOOL WINAPI (HANDLE, LPSTR, LPDWORD)> get_user_profile_directory(userenv, "GetUserProfileDirectoryA"); + get_user_profile_directory(token, buf, &len); + CloseHandle(token); + if (*buf) + return buf; + } +#elif __EMSCRIPTEN__ + return "/"; +#else + // First try the HOME environment variable + auto home = internal::getenv("HOME"); + if (home.size() > 0) + return home; + // Otherwise, try getpwuid_r() + size_t len = 4096; +#if defined(_SC_GETPW_R_SIZE_MAX) + auto size_max = sysconf(_SC_GETPW_R_SIZE_MAX); + if (size_max != -1) + len = size_t(size_max); +#endif + std::vector<char> buf(len); + struct passwd pwd, *result; + if (getpwuid_r(getuid(), &pwd, buf.data(), buf.size(), &result) == 0) + return result->pw_dir; +#endif + return "/"; +} + +inline std::string path::separator() +{ +#if _WIN32 + return "\\"; +#else + return "/"; +#endif +} + +// executor implementation + +inline std::string internal::executor::result(int *exit_code /* = nullptr */) +{ + stop(); + if (exit_code) + *exit_code = m_exit_code; + return m_stdout; +} + +inline bool internal::executor::kill() +{ +#if _WIN32 + if (m_future.valid()) + { + // Close all windows that weren’t open when we started the future + auto previous_windows = m_windows; + EnumWindows(&enum_windows_callback, (LPARAM)this); + for (auto hwnd : m_windows) + if (previous_windows.find(hwnd) == previous_windows.end()) + { + SendMessage(hwnd, WM_CLOSE, 0, 0); + // Also send IDNO in case of a Yes/No or Abort/Retry/Ignore messagebox + SendMessage(hwnd, WM_COMMAND, IDNO, 0); + } + } +#elif __EMSCRIPTEN__ || __NX__ + // FIXME: do something + return false; // cannot kill +#else + ::kill(m_pid, SIGKILL); +#endif + stop(); + return true; +} + +#if _WIN32 +inline BOOL CALLBACK internal::executor::enum_windows_callback(HWND hwnd, LPARAM lParam) +{ + auto that = (executor *)lParam; + + DWORD pid; + auto tid = GetWindowThreadProcessId(hwnd, &pid); + if (tid == that->m_tid) + that->m_windows.insert(hwnd); + return TRUE; +} +#endif + +#if _WIN32 +inline void internal::executor::start_func(std::function<std::string(int *)> const &fun) +{ + stop(); + + auto trampoline = [fun, this]() + { + // Save our thread id so that the caller can cancel us + m_tid = GetCurrentThreadId(); + EnumWindows(&enum_windows_callback, (LPARAM)this); + m_cond.notify_all(); + return fun(&m_exit_code); + }; + + std::unique_lock<std::mutex> lock(m_mutex); + m_future = std::async(std::launch::async, trampoline); + m_cond.wait(lock); + m_running = true; +} + +#elif __EMSCRIPTEN__ +inline void internal::executor::start(int exit_code) +{ + m_exit_code = exit_code; +} + +#else +inline void internal::executor::start_process(std::vector<std::string> const &command) +{ + stop(); + m_stdout.clear(); + m_exit_code = -1; + + int in[2], out[2]; + if (pipe(in) != 0 || pipe(out) != 0) + return; + + m_pid = fork(); + if (m_pid < 0) + return; + + close(in[m_pid ? 0 : 1]); + close(out[m_pid ? 1 : 0]); + + if (m_pid == 0) + { + dup2(in[0], STDIN_FILENO); + dup2(out[1], STDOUT_FILENO); + + // Ignore stderr so that it doesn’t pollute the console (e.g. GTK+ errors from zenity) + int fd = open("/dev/null", O_WRONLY); + dup2(fd, STDERR_FILENO); + close(fd); + + std::vector<char *> args; + std::transform(command.cbegin(), command.cend(), std::back_inserter(args), + [](std::string const &s) { return const_cast<char *>(s.c_str()); }); + args.push_back(nullptr); // null-terminate argv[] + + execvp(args[0], args.data()); + exit(1); + } + + close(in[1]); + m_fd = out[0]; + auto flags = fcntl(m_fd, F_GETFL); + fcntl(m_fd, F_SETFL, flags | O_NONBLOCK); + + m_running = true; +} +#endif + +inline internal::executor::~executor() +{ + stop(); +} + +inline bool internal::executor::ready(int timeout /* = default_wait_timeout */) +{ + if (!m_running) + return true; + +#if _WIN32 + if (m_future.valid()) + { + auto status = m_future.wait_for(std::chrono::milliseconds(timeout)); + if (status != std::future_status::ready) + { + // On Windows, we need to run the message pump. If the async + // thread uses a Windows API dialog, it may be attached to the + // main thread and waiting for messages that only we can dispatch. + MSG msg; + while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + return false; + } + + m_stdout = m_future.get(); + } +#elif __EMSCRIPTEN__ || __NX__ + // FIXME: do something + (void)timeout; +#else + char buf[BUFSIZ]; + ssize_t received = read(m_fd, buf, BUFSIZ); // Flawfinder: ignore + if (received > 0) + { + m_stdout += std::string(buf, received); + return false; + } + + // Reap child process if it is dead. It is possible that the system has already reaped it + // (this happens when the calling application handles or ignores SIG_CHLD) and results in + // waitpid() failing with ECHILD. Otherwise we assume the child is running and we sleep for + // a little while. + int status; + pid_t child = waitpid(m_pid, &status, WNOHANG); + if (child != m_pid && (child >= 0 || errno != ECHILD)) + { + // FIXME: this happens almost always at first iteration + std::this_thread::sleep_for(std::chrono::milliseconds(timeout)); + return false; + } + + close(m_fd); + m_exit_code = WEXITSTATUS(status); +#endif + + m_running = false; + return true; +} + +inline void internal::executor::stop() +{ + // Loop until the user closes the dialog + while (!ready()) + ; +} + +// dll implementation + +#if _WIN32 +inline internal::platform::dll::dll(std::string const &name) + : handle(::LoadLibraryA(name.c_str())) +{} + +inline internal::platform::dll::~dll() +{ + if (handle) + ::FreeLibrary(handle); +} +#endif // _WIN32 + +// ole32_dll implementation + +#if _WIN32 +inline internal::platform::ole32_dll::ole32_dll() + : dll("ole32.dll") +{ + // Use COINIT_MULTITHREADED because COINIT_APARTMENTTHREADED causes crashes. + // See https://github.com/samhocevar/portable-file-dialogs/issues/51 + auto coinit = proc<HRESULT WINAPI (LPVOID, DWORD)>(*this, "CoInitializeEx"); + m_state = coinit(nullptr, COINIT_MULTITHREADED); +} + +inline internal::platform::ole32_dll::~ole32_dll() +{ + if (is_initialized()) + proc<void WINAPI ()>(*this, "CoUninitialize")(); +} + +inline bool internal::platform::ole32_dll::is_initialized() +{ + return m_state == S_OK || m_state == S_FALSE; +} +#endif + +// new_style_context implementation + +#if _WIN32 +inline internal::platform::new_style_context::new_style_context() +{ + // Only create one activation context for the whole app lifetime. + static HANDLE hctx = create(); + + if (hctx != INVALID_HANDLE_VALUE) + ActivateActCtx(hctx, &m_cookie); +} + +inline internal::platform::new_style_context::~new_style_context() +{ + DeactivateActCtx(0, m_cookie); +} + +inline HANDLE internal::platform::new_style_context::create() +{ + // This “hack” seems to be necessary for this code to work on windows XP. + // Without it, dialogs do not show and close immediately. GetError() + // returns 0 so I don’t know what causes this. I was not able to reproduce + // this behavior on Windows 7 and 10 but just in case, let it be here for + // those versions too. + // This hack is not required if other dialogs are used (they load comdlg32 + // automatically), only if message boxes are used. + dll comdlg32("comdlg32.dll"); + + // Using approach as shown here: https://stackoverflow.com/a/10444161 + UINT len = ::GetSystemDirectoryA(nullptr, 0); + std::string sys_dir(len, '\0'); + ::GetSystemDirectoryA(&sys_dir[0], len); + + ACTCTXA act_ctx = + { + // Do not set flag ACTCTX_FLAG_SET_PROCESS_DEFAULT, since it causes a + // crash with error “default context is already set”. + sizeof(act_ctx), + ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID, + "shell32.dll", 0, 0, sys_dir.c_str(), (LPCSTR)124, nullptr, 0, + }; + + return ::CreateActCtxA(&act_ctx); +} +#endif // _WIN32 + +// dialog implementation + +inline bool internal::dialog::ready(int timeout /* = default_wait_timeout */) const +{ + return m_async->ready(timeout); +} + +inline bool internal::dialog::kill() const +{ + return m_async->kill(); +} + +inline internal::dialog::dialog() + : m_async(std::make_shared<executor>()) +{ +} + +inline std::vector<std::string> internal::dialog::desktop_helper() const +{ +#if __APPLE__ + return { "osascript" }; +#else + return { flags(flag::has_zenity) ? "zenity" + : flags(flag::has_matedialog) ? "matedialog" + : flags(flag::has_qarma) ? "qarma" + : flags(flag::has_kdialog) ? "kdialog" + : "echo" }; +#endif +} + +inline std::string internal::dialog::buttons_to_name(choice _choice) +{ + switch (_choice) + { + case choice::ok_cancel: return "okcancel"; + case choice::yes_no: return "yesno"; + case choice::yes_no_cancel: return "yesnocancel"; + case choice::retry_cancel: return "retrycancel"; + case choice::abort_retry_ignore: return "abortretryignore"; + /* case choice::ok: */ default: return "ok"; + } +} + +inline std::string internal::dialog::get_icon_name(icon _icon) +{ + switch (_icon) + { + case icon::warning: return "warning"; + case icon::error: return "error"; + case icon::question: return "question"; + // Zenity wants "information" but WinForms wants "info" + /* case icon::info: */ default: +#if _WIN32 + return "info"; +#else + return "information"; +#endif + } +} + +// This is only used for debugging purposes +inline std::ostream& operator <<(std::ostream &s, std::vector<std::string> const &v) +{ + int not_first = 0; + for (auto &e : v) + s << (not_first++ ? " " : "") << e; + return s; +} + +// Properly quote a string for Powershell: replace ' or " with '' or "" +// FIXME: we should probably get rid of newlines! +// FIXME: the \" sequence seems unsafe, too! +// XXX: this is no longer used but I would like to keep it around just in case +inline std::string internal::dialog::powershell_quote(std::string const &str) const +{ + return "'" + std::regex_replace(str, std::regex("['\"]"), "$&$&") + "'"; +} + +// Properly quote a string for osascript: replace \ or " with \\ or \" +// XXX: this also used to replace ' with \' when popen was used, but it would be +// smarter to do shell_quote(osascript_quote(...)) if this is needed again. +inline std::string internal::dialog::osascript_quote(std::string const &str) const +{ + return "\"" + std::regex_replace(str, std::regex("[\\\\\"]"), "\\$&") + "\""; +} + +// Properly quote a string for the shell: just replace ' with '\'' +// XXX: this is no longer used but I would like to keep it around just in case +inline std::string internal::dialog::shell_quote(std::string const &str) const +{ + return "'" + std::regex_replace(str, std::regex("'"), "'\\''") + "'"; +} + +// file_dialog implementation + +inline internal::file_dialog::file_dialog(type in_type, + std::string const &title, + std::string const &default_path /* = "" */, + std::vector<std::string> const &filters /* = {} */, + opt options /* = opt::none */) +{ +#if _WIN32 + std::string filter_list; + std::regex whitespace(" *"); + for (size_t i = 0; i + 1 < filters.size(); i += 2) + { + filter_list += filters[i] + '\0'; + filter_list += std::regex_replace(filters[i + 1], whitespace, ";") + '\0'; + } + filter_list += '\0'; + + m_async->start_func([this, in_type, title, default_path, filter_list, + options](int *exit_code) -> std::string + { + (void)exit_code; + m_wtitle = internal::str2wstr(title); + m_wdefault_path = internal::str2wstr(default_path); + auto wfilter_list = internal::str2wstr(filter_list); + + // Initialise COM. This is required for the new folder selection window, + // (see https://github.com/samhocevar/portable-file-dialogs/pull/21) + // and to avoid random crashes with GetOpenFileNameW() (see + // https://github.com/samhocevar/portable-file-dialogs/issues/51) + ole32_dll ole32; + + // Folder selection uses a different method + if (in_type == type::folder) + { +#if PFD_HAS_IFILEDIALOG + if (flags(flag::is_vista)) + { + // On Vista and higher we should be able to use IFileDialog for folder selection + IFileDialog *ifd; + HRESULT hr = dll::proc<HRESULT WINAPI (REFCLSID, LPUNKNOWN, DWORD, REFIID, LPVOID *)>(ole32, "CoCreateInstance") + (CLSID_FileOpenDialog, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&ifd)); + + // In case CoCreateInstance fails (which it should not), try legacy approach + if (SUCCEEDED(hr)) + return select_folder_vista(ifd, options & opt::force_path); + } +#endif + + BROWSEINFOW bi; + memset(&bi, 0, sizeof(bi)); + + bi.lpfn = &bffcallback; + bi.lParam = (LPARAM)this; + + if (flags(flag::is_vista)) + { + if (ole32.is_initialized()) + bi.ulFlags |= BIF_NEWDIALOGSTYLE; + bi.ulFlags |= BIF_EDITBOX; + bi.ulFlags |= BIF_STATUSTEXT; + } + + auto *list = SHBrowseForFolderW(&bi); + std::string ret; + if (list) + { + auto buffer = new wchar_t[MAX_PATH]; + SHGetPathFromIDListW(list, buffer); + dll::proc<void WINAPI (LPVOID)>(ole32, "CoTaskMemFree")(list); + ret = internal::wstr2str(buffer); + delete[] buffer; + } + return ret; + } + + OPENFILENAMEW ofn; + memset(&ofn, 0, sizeof(ofn)); + ofn.lStructSize = sizeof(OPENFILENAMEW); + ofn.hwndOwner = GetActiveWindow(); + + ofn.lpstrFilter = wfilter_list.c_str(); + + auto woutput = std::wstring(MAX_PATH * 256, L'\0'); + ofn.lpstrFile = (LPWSTR)woutput.data(); + ofn.nMaxFile = (DWORD)woutput.size(); + if (!m_wdefault_path.empty()) + { + // If a directory was provided, use it as the initial directory. If + // a valid path was provided, use it as the initial file. Otherwise, + // let the Windows API decide. + auto path_attr = GetFileAttributesW(m_wdefault_path.c_str()); + if (path_attr != INVALID_FILE_ATTRIBUTES && (path_attr & FILE_ATTRIBUTE_DIRECTORY)) + ofn.lpstrInitialDir = m_wdefault_path.c_str(); + else if (m_wdefault_path.size() <= woutput.size()) + //second argument is size of buffer, not length of string + StringCchCopyW(ofn.lpstrFile, MAX_PATH*256+1, m_wdefault_path.c_str()); + else + { + ofn.lpstrFileTitle = (LPWSTR)m_wdefault_path.data(); + ofn.nMaxFileTitle = (DWORD)m_wdefault_path.size(); + } + } + ofn.lpstrTitle = m_wtitle.c_str(); + ofn.Flags = OFN_NOCHANGEDIR | OFN_EXPLORER; + + dll comdlg32("comdlg32.dll"); + + // Apply new visual style (required for windows XP) + new_style_context ctx; + + if (in_type == type::save) + { + if (!(options & opt::force_overwrite)) + ofn.Flags |= OFN_OVERWRITEPROMPT; + + dll::proc<BOOL WINAPI (LPOPENFILENAMEW)> get_save_file_name(comdlg32, "GetSaveFileNameW"); + if (get_save_file_name(&ofn) == 0) + return ""; + return internal::wstr2str(woutput.c_str()); + } + else + { + if (options & opt::multiselect) + ofn.Flags |= OFN_ALLOWMULTISELECT; + ofn.Flags |= OFN_PATHMUSTEXIST; + + dll::proc<BOOL WINAPI (LPOPENFILENAMEW)> get_open_file_name(comdlg32, "GetOpenFileNameW"); + if (get_open_file_name(&ofn) == 0) + return ""; + } + + std::string prefix; + for (wchar_t const *p = woutput.c_str(); *p; ) + { + auto filename = internal::wstr2str(p); + p += wcslen(p); + // In multiselect mode, we advance p one wchar further and + // check for another filename. If there is one and the + // prefix is empty, it means we just read the prefix. + if ((options & opt::multiselect) && *++p && prefix.empty()) + { + prefix = filename + "/"; + continue; + } + + m_vector_result.push_back(prefix + filename); + } + + return ""; + }); +#elif __EMSCRIPTEN__ + // FIXME: do something + (void)in_type; + (void)title; + (void)default_path; + (void)filters; + (void)options; +#else + auto command = desktop_helper(); + + if (is_osascript()) + { + std::string script = "set ret to choose"; + switch (in_type) + { + case type::save: + script += " file name"; + break; + case type::open: default: + script += " file"; + if (options & opt::multiselect) + script += " with multiple selections allowed"; + break; + case type::folder: + script += " folder"; + break; + } + + if (default_path.size()) + { + if (in_type == type::folder || is_directory(default_path)) + script += " default location "; + else + script += " default name "; + script += osascript_quote(default_path); + } + + script += " with prompt " + osascript_quote(title); + + if (in_type == type::open) + { + // Concatenate all user-provided filter patterns + std::string patterns; + for (size_t i = 0; i < filters.size() / 2; ++i) + patterns += " " + filters[2 * i + 1]; + + // Split the pattern list to check whether "*" is in there; if it + // is, we have to disable filters because there is no mechanism in + // OS X for the user to override the filter. + std::regex sep("\\s+"); + std::string filter_list; + bool has_filter = true; + std::sregex_token_iterator iter(patterns.begin(), patterns.end(), sep, -1); + std::sregex_token_iterator end; + for ( ; iter != end; ++iter) + { + auto pat = iter->str(); + if (pat == "*" || pat == "*.*") + has_filter = false; + else if (internal::starts_with(pat, "*.")) + filter_list += "," + osascript_quote(pat.substr(2, pat.size() - 2)); + } + + if (has_filter && filter_list.size() > 0) + { + // There is a weird AppleScript bug where file extensions of length != 3 are + // ignored, e.g. type{"txt"} works, but type{"json"} does not. Fortunately if + // the whole list starts with a 3-character extension, everything works again. + // We use "///" for such an extension because we are sure it cannot appear in + // an actual filename. + script += " of type {\"///\"" + filter_list + "}"; + } + } + + if (in_type == type::open && (options & opt::multiselect)) + { + script += "\nset s to \"\""; + script += "\nrepeat with i in ret"; + script += "\n set s to s & (POSIX path of i) & \"\\n\""; + script += "\nend repeat"; + script += "\ncopy s to stdout"; + } + else + { + script += "\nPOSIX path of ret"; + } + + command.push_back("-e"); + command.push_back(script); + } + else if (is_zenity()) + { + command.push_back("--file-selection"); + + // If the default path is a directory, make sure it ends with "/" otherwise zenity will + // open the file dialog in the parent directory. + auto filename_arg = "--filename=" + default_path; + if (in_type != type::folder && !ends_with(default_path, "/") && internal::is_directory(default_path)) + filename_arg += "/"; + command.push_back(filename_arg); + + command.push_back("--title"); + command.push_back(title); + command.push_back("--separator=\n"); + + for (size_t i = 0; i < filters.size() / 2; ++i) + { + command.push_back("--file-filter"); + command.push_back(filters[2 * i] + "|" + filters[2 * i + 1]); + } + + if (in_type == type::save) + command.push_back("--save"); + if (in_type == type::folder) + command.push_back("--directory"); + if (!(options & opt::force_overwrite)) + command.push_back("--confirm-overwrite"); + if (options & opt::multiselect) + command.push_back("--multiple"); + } + else if (is_kdialog()) + { + switch (in_type) + { + case type::save: command.push_back("--getsavefilename"); break; + case type::open: command.push_back("--getopenfilename"); break; + case type::folder: command.push_back("--getexistingdirectory"); break; + } + if (options & opt::multiselect) + { + command.push_back("--multiple"); + command.push_back("--separate-output"); + } + + command.push_back(default_path); + + std::string filter; + for (size_t i = 0; i < filters.size() / 2; ++i) + filter += (i == 0 ? "" : " | ") + filters[2 * i] + "(" + filters[2 * i + 1] + ")"; + command.push_back(filter); + + command.push_back("--title"); + command.push_back(title); + } + + if (flags(flag::is_verbose)) + std::cerr << "pfd: " << command << std::endl; + + m_async->start_process(command); +#endif +} + +inline std::string internal::file_dialog::string_result() +{ +#if _WIN32 + return m_async->result(); +#else + auto ret = m_async->result(); + // Strip potential trailing newline (zenity). Also strip trailing slash + // added by osascript for consistency with other backends. + while (!ret.empty() && (ret.back() == '\n' || ret.back() == '/')) + ret.pop_back(); + return ret; +#endif +} + +inline std::vector<std::string> internal::file_dialog::vector_result() +{ +#if _WIN32 + m_async->result(); + return m_vector_result; +#else + std::vector<std::string> ret; + auto result = m_async->result(); + for (;;) + { + // Split result along newline characters + auto i = result.find('\n'); + if (i == 0 || i == std::string::npos) + break; + ret.push_back(result.substr(0, i)); + result = result.substr(i + 1, result.size()); + } + return ret; +#endif +} + +#if _WIN32 +// Use a static function to pass as BFFCALLBACK for legacy folder select +inline int CALLBACK internal::file_dialog::bffcallback(HWND hwnd, UINT uMsg, + LPARAM, LPARAM pData) +{ + auto inst = (file_dialog *)pData; + switch (uMsg) + { + case BFFM_INITIALIZED: + SendMessage(hwnd, BFFM_SETSELECTIONW, TRUE, (LPARAM)inst->m_wdefault_path.c_str()); + break; + } + return 0; +} + +#if PFD_HAS_IFILEDIALOG +inline std::string internal::file_dialog::select_folder_vista(IFileDialog *ifd, bool force_path) +{ + std::string result; + + IShellItem *folder; + + // Load library at runtime so app doesn't link it at load time (which will fail on windows XP) + dll shell32("shell32.dll"); + dll::proc<HRESULT WINAPI (PCWSTR, IBindCtx*, REFIID, void**)> + create_item(shell32, "SHCreateItemFromParsingName"); + + if (!create_item) + return ""; + + auto hr = create_item(m_wdefault_path.c_str(), + nullptr, + IID_PPV_ARGS(&folder)); + + // Set default folder if found. This only sets the default folder. If + // Windows has any info about the most recently selected folder, it + // will display it instead. Generally, calling SetFolder() to set the + // current directory “is not a good or expected user experience and + // should therefore be avoided”: + // https://docs.microsoft.com/windows/win32/api/shobjidl_core/nf-shobjidl_core-ifiledialog-setfolder + if (SUCCEEDED(hr)) + { + if (force_path) + ifd->SetFolder(folder); + else + ifd->SetDefaultFolder(folder); + folder->Release(); + } + + // Set the dialog title and option to select folders + ifd->SetOptions(FOS_PICKFOLDERS | FOS_FORCEFILESYSTEM); + ifd->SetTitle(m_wtitle.c_str()); + + hr = ifd->Show(GetActiveWindow()); + if (SUCCEEDED(hr)) + { + IShellItem* item; + hr = ifd->GetResult(&item); + if (SUCCEEDED(hr)) + { + wchar_t* wname = nullptr; + // This is unlikely to fail because we use FOS_FORCEFILESYSTEM, but try + // to output a debug message just in case. + if (SUCCEEDED(item->GetDisplayName(SIGDN_FILESYSPATH, &wname))) + { + result = internal::wstr2str(std::wstring(wname)); + dll::proc<void WINAPI (LPVOID)>(ole32_dll(), "CoTaskMemFree")(wname); + } + else + { + if (SUCCEEDED(item->GetDisplayName(SIGDN_NORMALDISPLAY, &wname))) + { + auto name = internal::wstr2str(std::wstring(wname)); + dll::proc<void WINAPI (LPVOID)>(ole32_dll(), "CoTaskMemFree")(wname); + std::cerr << "pfd: failed to get path for " << name << std::endl; + } + else + std::cerr << "pfd: item of unknown type selected" << std::endl; + } + + item->Release(); + } + } + + ifd->Release(); + + return result; +} +#endif +#endif + +// notify implementation + +inline notify::notify(std::string const &title, + std::string const &message, + icon _icon /* = icon::info */) +{ + if (_icon == icon::question) // Not supported by notifications + _icon = icon::info; + +#if _WIN32 + // Use a static shared pointer for notify_icon so that we can delete + // it whenever we need to display a new one, and we can also wait + // until the program has finished running. + struct notify_icon_data : public NOTIFYICONDATAW + { + ~notify_icon_data() { Shell_NotifyIconW(NIM_DELETE, this); } + }; + + static std::shared_ptr<notify_icon_data> nid; + + // Release the previous notification icon, if any, and allocate a new + // one. Note that std::make_shared() does value initialization, so there + // is no need to memset the structure. + nid = nullptr; + nid = std::make_shared<notify_icon_data>(); + + // For XP support + nid->cbSize = NOTIFYICONDATAW_V2_SIZE; + nid->hWnd = nullptr; + nid->uID = 0; + + // Flag Description: + // - NIF_ICON The hIcon member is valid. + // - NIF_MESSAGE The uCallbackMessage member is valid. + // - NIF_TIP The szTip member is valid. + // - NIF_STATE The dwState and dwStateMask members are valid. + // - NIF_INFO Use a balloon ToolTip instead of a standard ToolTip. The szInfo, uTimeout, szInfoTitle, and dwInfoFlags members are valid. + // - NIF_GUID Reserved. + nid->uFlags = NIF_MESSAGE | NIF_ICON | NIF_INFO; + + // Flag Description + // - NIIF_ERROR An error icon. + // - NIIF_INFO An information icon. + // - NIIF_NONE No icon. + // - NIIF_WARNING A warning icon. + // - NIIF_ICON_MASK Version 6.0. Reserved. + // - NIIF_NOSOUND Version 6.0. Do not play the associated sound. Applies only to balloon ToolTips + switch (_icon) + { + case icon::warning: nid->dwInfoFlags = NIIF_WARNING; break; + case icon::error: nid->dwInfoFlags = NIIF_ERROR; break; + /* case icon::info: */ default: nid->dwInfoFlags = NIIF_INFO; break; + } + + ENUMRESNAMEPROC icon_enum_callback = [](HMODULE, LPCTSTR, LPTSTR lpName, LONG_PTR lParam) -> BOOL + { + ((NOTIFYICONDATAW *)lParam)->hIcon = ::LoadIcon(GetModuleHandle(nullptr), lpName); + return false; + }; + + nid->hIcon = ::LoadIcon(nullptr, IDI_APPLICATION); + ::EnumResourceNames(nullptr, RT_GROUP_ICON, icon_enum_callback, (LONG_PTR)nid.get()); + + nid->uTimeout = 5000; + + StringCchCopyW(nid->szInfoTitle, ARRAYSIZE(nid->szInfoTitle), internal::str2wstr(title).c_str()); + StringCchCopyW(nid->szInfo, ARRAYSIZE(nid->szInfo), internal::str2wstr(message).c_str()); + + // Display the new icon + Shell_NotifyIconW(NIM_ADD, nid.get()); +#elif __EMSCRIPTEN__ + // FIXME: do something + (void)title; + (void)message; +#else + auto command = desktop_helper(); + + if (is_osascript()) + { + command.push_back("-e"); + command.push_back("display notification " + osascript_quote(message) + + " with title " + osascript_quote(title)); + } + else if (is_zenity()) + { + command.push_back("--notification"); + command.push_back("--window-icon"); + command.push_back(get_icon_name(_icon)); + command.push_back("--text"); + command.push_back(title + "\n" + message); + } + else if (is_kdialog()) + { + command.push_back("--icon"); + command.push_back(get_icon_name(_icon)); + command.push_back("--title"); + command.push_back(title); + command.push_back("--passivepopup"); + command.push_back(message); + command.push_back("5"); + } + + if (flags(flag::is_verbose)) + std::cerr << "pfd: " << command << std::endl; + + m_async->start_process(command); +#endif +} + +// message implementation + +inline message::message(std::string const &title, + std::string const &text, + choice _choice /* = choice::ok_cancel */, + icon _icon /* = icon::info */) +{ +#if _WIN32 + // Use MB_SYSTEMMODAL rather than MB_TOPMOST to ensure the message window is brought + // to front. See https://github.com/samhocevar/portable-file-dialogs/issues/52 + UINT style = MB_SYSTEMMODAL; + switch (_icon) + { + case icon::warning: style |= MB_ICONWARNING; break; + case icon::error: style |= MB_ICONERROR; break; + case icon::question: style |= MB_ICONQUESTION; break; + /* case icon::info: */ default: style |= MB_ICONINFORMATION; break; + } + + switch (_choice) + { + case choice::ok_cancel: style |= MB_OKCANCEL; break; + case choice::yes_no: style |= MB_YESNO; break; + case choice::yes_no_cancel: style |= MB_YESNOCANCEL; break; + case choice::retry_cancel: style |= MB_RETRYCANCEL; break; + case choice::abort_retry_ignore: style |= MB_ABORTRETRYIGNORE; break; + /* case choice::ok: */ default: style |= MB_OK; break; + } + + m_mappings[IDCANCEL] = button::cancel; + m_mappings[IDOK] = button::ok; + m_mappings[IDYES] = button::yes; + m_mappings[IDNO] = button::no; + m_mappings[IDABORT] = button::abort; + m_mappings[IDRETRY] = button::retry; + m_mappings[IDIGNORE] = button::ignore; + + m_async->start_func([text, title, style](int* exit_code) -> std::string + { + auto wtext = internal::str2wstr(text); + auto wtitle = internal::str2wstr(title); + // Apply new visual style (required for all Windows versions) + new_style_context ctx; + *exit_code = MessageBoxW(GetActiveWindow(), wtext.c_str(), wtitle.c_str(), style); + return ""; + }); + +#elif __EMSCRIPTEN__ + std::string full_message; + switch (_icon) + { + case icon::warning: full_message = "⚠️"; break; + case icon::error: full_message = "⛔"; break; + case icon::question: full_message = "❓"; break; + /* case icon::info: */ default: full_message = "ℹ"; break; + } + + full_message += ' ' + title + "\n\n" + text; + + // This does not really start an async task; it just passes the + // EM_ASM_INT return value to a fake start() function. + m_async->start(EM_ASM_INT( + { + if ($1) + return window.confirm(UTF8ToString($0)) ? 0 : -1; + alert(UTF8ToString($0)); + return 0; + }, full_message.c_str(), _choice == choice::ok_cancel)); +#else + auto command = desktop_helper(); + + if (is_osascript()) + { + std::string script = "display dialog " + osascript_quote(text) + + " with title " + osascript_quote(title); + auto if_cancel = button::cancel; + switch (_choice) + { + case choice::ok_cancel: + script += "buttons {\"OK\", \"Cancel\"}" + " default button \"OK\"" + " cancel button \"Cancel\""; + break; + case choice::yes_no: + script += "buttons {\"Yes\", \"No\"}" + " default button \"Yes\"" + " cancel button \"No\""; + if_cancel = button::no; + break; + case choice::yes_no_cancel: + script += "buttons {\"Yes\", \"No\", \"Cancel\"}" + " default button \"Yes\"" + " cancel button \"Cancel\""; + break; + case choice::retry_cancel: + script += "buttons {\"Retry\", \"Cancel\"}" + " default button \"Retry\"" + " cancel button \"Cancel\""; + break; + case choice::abort_retry_ignore: + script += "buttons {\"Abort\", \"Retry\", \"Ignore\"}" + " default button \"Abort\"" + " cancel button \"Retry\""; + if_cancel = button::retry; + break; + case choice::ok: default: + script += "buttons {\"OK\"}" + " default button \"OK\"" + " cancel button \"OK\""; + if_cancel = button::ok; + break; + } + m_mappings[1] = if_cancel; + m_mappings[256] = if_cancel; // XXX: I think this was never correct + script += " with icon "; + switch (_icon) + { + #define PFD_OSX_ICON(n) "alias ((path to library folder from system domain) as text " \ + "& \"CoreServices:CoreTypes.bundle:Contents:Resources:" n ".icns\")" + case icon::info: default: script += PFD_OSX_ICON("ToolBarInfo"); break; + case icon::warning: script += "caution"; break; + case icon::error: script += "stop"; break; + case icon::question: script += PFD_OSX_ICON("GenericQuestionMarkIcon"); break; + #undef PFD_OSX_ICON + } + + command.push_back("-e"); + command.push_back(script); + } + else if (is_zenity()) + { + switch (_choice) + { + case choice::ok_cancel: + command.insert(command.end(), { "--question", "--cancel-label=Cancel", "--ok-label=OK" }); break; + case choice::yes_no: + // Do not use standard --question because it causes “No” to return -1, + // which is inconsistent with the “Yes/No/Cancel” mode below. + command.insert(command.end(), { "--question", "--switch", "--extra-button=No", "--extra-button=Yes" }); break; + case choice::yes_no_cancel: + command.insert(command.end(), { "--question", "--switch", "--extra-button=Cancel", "--extra-button=No", "--extra-button=Yes" }); break; + case choice::retry_cancel: + command.insert(command.end(), { "--question", "--switch", "--extra-button=Cancel", "--extra-button=Retry" }); break; + case choice::abort_retry_ignore: + command.insert(command.end(), { "--question", "--switch", "--extra-button=Ignore", "--extra-button=Abort", "--extra-button=Retry" }); break; + case choice::ok: + default: + switch (_icon) + { + case icon::error: command.push_back("--error"); break; + case icon::warning: command.push_back("--warning"); break; + default: command.push_back("--info"); break; + } + } + + command.insert(command.end(), { "--title", title, + "--width=300", "--height=0", // sensible defaults + "--no-markup", // do not interpret text as Pango markup + "--text", text, + "--icon-name=dialog-" + get_icon_name(_icon) }); + } + else if (is_kdialog()) + { + if (_choice == choice::ok) + { + switch (_icon) + { + case icon::error: command.push_back("--error"); break; + case icon::warning: command.push_back("--sorry"); break; + default: command.push_back("--msgbox"); break; + } + } + else + { + std::string flag = "--"; + if (_icon == icon::warning || _icon == icon::error) + flag += "warning"; + flag += "yesno"; + if (_choice == choice::yes_no_cancel) + flag += "cancel"; + command.push_back(flag); + if (_choice == choice::yes_no || _choice == choice::yes_no_cancel) + { + m_mappings[0] = button::yes; + m_mappings[256] = button::no; + } + } + + command.push_back(text); + command.push_back("--title"); + command.push_back(title); + + // Must be after the above part + if (_choice == choice::ok_cancel) + command.insert(command.end(), { "--yes-label", "OK", "--no-label", "Cancel" }); + } + + if (flags(flag::is_verbose)) + std::cerr << "pfd: " << command << std::endl; + + m_async->start_process(command); +#endif +} + +inline button message::result() +{ + int exit_code; + auto ret = m_async->result(&exit_code); + // osascript will say "button returned:Cancel\n" + // and others will just say "Cancel\n" + if (internal::ends_with(ret, "Cancel\n")) + return button::cancel; + if (internal::ends_with(ret, "OK\n")) + return button::ok; + if (internal::ends_with(ret, "Yes\n")) + return button::yes; + if (internal::ends_with(ret, "No\n")) + return button::no; + if (internal::ends_with(ret, "Abort\n")) + return button::abort; + if (internal::ends_with(ret, "Retry\n")) + return button::retry; + if (internal::ends_with(ret, "Ignore\n")) + return button::ignore; + if (m_mappings.count(exit_code) != 0) + return m_mappings[exit_code]; + return exit_code == 0 ? button::ok : button::cancel; +} + +// open_file implementation + +inline open_file::open_file(std::string const &title, + std::string const &default_path /* = "" */, + std::vector<std::string> const &filters /* = { "All Files", "*" } */, + opt options /* = opt::none */) + : file_dialog(type::open, title, default_path, filters, options) +{ +} + +inline open_file::open_file(std::string const &title, + std::string const &default_path, + std::vector<std::string> const &filters, + bool allow_multiselect) + : open_file(title, default_path, filters, + (allow_multiselect ? opt::multiselect : opt::none)) +{ +} + +inline std::vector<std::string> open_file::result() +{ + return vector_result(); +} + +// save_file implementation + +inline save_file::save_file(std::string const &title, + std::string const &default_path /* = "" */, + std::vector<std::string> const &filters /* = { "All Files", "*" } */, + opt options /* = opt::none */) + : file_dialog(type::save, title, default_path, filters, options) +{ +} + +inline save_file::save_file(std::string const &title, + std::string const &default_path, + std::vector<std::string> const &filters, + bool confirm_overwrite) + : save_file(title, default_path, filters, + (confirm_overwrite ? opt::none : opt::force_overwrite)) +{ +} + +inline std::string save_file::result() +{ + return string_result(); +} + +// select_folder implementation + +inline select_folder::select_folder(std::string const &title, + std::string const &default_path /* = "" */, + opt options /* = opt::none */) + : file_dialog(type::folder, title, default_path, {}, options) +{ +} + +inline std::string select_folder::result() +{ + return string_result(); +} + +#endif // PFD_SKIP_IMPLEMENTATION + +} // namespace pfd diff --git a/mm/2s2h/SohGui.cpp b/mm/2s2h/SohGui.cpp new file mode 100644 index 000000000..3f7b792f2 --- /dev/null +++ b/mm/2s2h/SohGui.cpp @@ -0,0 +1,210 @@ +// +// SohGui.cpp +// soh +// +// Created by David Chavez on 24.08.22. +// + +#include "SohGui.hpp" + +#include <spdlog/spdlog.h> +#include <ImGui/imgui.h> +#define IMGUI_DEFINE_MATH_OPERATORS +#include <ImGui/imgui_internal.h> +#include <libultraship/libultraship.h> +#include <Fast3D/gfx_pc.h> + +#ifdef __APPLE__ +#include "graphic/Fast3D/gfx_metal.h" +#endif + +#ifdef __SWITCH__ +#include <port/switch/SwitchImpl.h> +#endif + +//#include "UIWidgets.hpp" +#include "include/global.h" +#include "include/z64audio.h" +//#include "soh/SaveManager.h" +//#include "OTRGlobals.h" +//#include "soh/Enhancements/presets.h" +//#include "2s2h/resource/type/Skeleton.h" +#include "libultraship/libultraship.h" + +//#ifdef ENABLE_CROWD_CONTROL +//#include "Enhancements/crowd-control/CrowdControl.h" +//#endif + +//#include "Enhancements/game-interactor/GameInteractor.h" +//#include "Enhancements/cosmetics/authenticGfxPatches.h" + +bool ShouldClearTextureCacheAtEndOfFrame = false; +bool isBetaQuestEnabled = false; + +extern "C" { + void enableBetaQuest() { isBetaQuestEnabled = true; } + void disableBetaQuest() { isBetaQuestEnabled = false; } +} + + +namespace SohGui { + + // MARK: - Properties + + static const char* chestSizeAndTextureMatchesContentsOptions[4] = { "Disabled", "Both", "Texture Only", "Size Only" }; + static const char* bunnyHoodOptions[3] = { "Disabled", "Faster Run & Longer Jump", "Faster Run" }; + static const char* allPowers[9] = { + "Vanilla (1x)", + "Double (2x)", + "Quadruple (4x)", + "Octuple (8x)", + "Foolish (16x)", + "Ridiculous (32x)", + "Merciless (64x)", + "Pure Torture (128x)", + "OHKO (256x)" }; + static const char* subPowers[8] = { allPowers[0], allPowers[1], allPowers[2], allPowers[3], allPowers[4], allPowers[5], allPowers[6], allPowers[7] }; + static const char* subSubPowers[7] = { allPowers[0], allPowers[1], allPowers[2], allPowers[3], allPowers[4], allPowers[5], allPowers[6] }; + static const char* zFightingOptions[3] = { "Disabled", "Consistent Vanish", "No Vanish" }; + static const char* autosaveLabels[6] = { "Off", "New Location + Major Item", "New Location + Any Item", "New Location", "Major Item", "Any Item" }; + static const char* FastFileSelect[5] = { "File N.1", "File N.2", "File N.3", "Zelda Map Select (require OoT Debug Mode)", "File select" }; + static const char* bonkDamageValues[8] = { + "No Damage", + "0.25 Heart", + "0.5 Heart", + "1 Heart", + "2 Hearts", + "4 Hearts", + "8 Hearts", + "OHKO" + }; + + static const inline std::vector<std::pair<const char*, const char*>> audioBackends = { +#ifdef _WIN32 + { "wasapi", "Windows Audio Session API" }, +#endif +#if defined(__linux) + { "pulse", "PulseAudio" }, +#endif + { "sdl", "SDL Audio" } + }; + + + // MARK: - Helpers + + std::string GetWindowButtonText(const char* text, bool menuOpen) { + char buttonText[100] = ""; + if (menuOpen) { + strcat(buttonText, ICON_FA_CHEVRON_RIGHT " "); + } + strcat(buttonText, text); + if (!menuOpen) { strcat(buttonText, " "); } + return buttonText; + } + + + // MARK: - Delegates + + std::shared_ptr<SohMenuBar> mSohMenuBar; + + std::shared_ptr<LUS::GuiWindow> mConsoleWindow; + std::shared_ptr<LUS::GuiWindow> mStatsWindow; + std::shared_ptr<LUS::GuiWindow> mInputEditorWindow; + + //std::shared_ptr<AudioEditor> mAudioEditorWindow; + //std::shared_ptr<GameControlEditor::GameControlEditorWindow> mGameControlEditorWindow; + //std::shared_ptr<CosmeticsEditorWindow> mCosmeticsEditorWindow; + //std::shared_ptr<ActorViewerWindow> mActorViewerWindow; + //std::shared_ptr<ColViewerWindow> mColViewerWindow; + //std::shared_ptr<SaveEditorWindow> mSaveEditorWindow; + //std::shared_ptr<DLViewerWindow> mDLViewerWindow; + //std::shared_ptr<GameplayStatsWindow> mGameplayStatsWindow; + //std::shared_ptr<CheckTracker::CheckTrackerSettingsWindow> mCheckTrackerSettingsWindow; + //std::shared_ptr<CheckTracker::CheckTrackerWindow> mCheckTrackerWindow; + //std::shared_ptr<EntranceTrackerWindow> mEntranceTrackerWindow; + //std::shared_ptr<ItemTrackerSettingsWindow> mItemTrackerSettingsWindow; + //std::shared_ptr<ItemTrackerWindow> mItemTrackerWindow; + //std::shared_ptr<RandomizerSettingsWindow> mRandomizerSettingsWindow; + + void SetupGuiElements() { + auto gui = LUS::Context::GetInstance()->GetWindow()->GetGui(); + + mSohMenuBar = std::make_shared<SohMenuBar>("gOpenMenuBar", CVarGetInteger("gOpenMenuBar", 0)); + gui->SetMenuBar(std::reinterpret_pointer_cast<LUS::GuiMenuBar>(mSohMenuBar)); + + if (gui->GetMenuBar() && !gui->GetMenuBar()->IsVisible()) { +#if defined(__SWITCH__) || defined(__WIIU__) + gui->GetGameOverlay()->TextDrawNotification(30.0f, true, "Press - to access enhancements menu"); +#else + gui->GetGameOverlay()->TextDrawNotification(30.0f, true, "Press F1 to access enhancements menu"); +#endif + } + + mStatsWindow = gui->GetGuiWindow("Stats"); + if (mStatsWindow == nullptr) { + SPDLOG_ERROR("Could not find stats window"); + } + + mConsoleWindow = gui->GetGuiWindow("Console"); + if (mConsoleWindow == nullptr) { + SPDLOG_ERROR("Could not find console window"); + } + + mInputEditorWindow = gui->GetGuiWindow("Input Editor"); + if (mInputEditorWindow == nullptr) { + SPDLOG_ERROR("Could not find input editor window"); + } + + /* + mAudioEditorWindow = std::make_shared<AudioEditor>("gAudioEditor.WindowOpen", "Audio Editor"); + gui->AddGuiWindow(mAudioEditorWindow); + mGameControlEditorWindow = std::make_shared<GameControlEditor::GameControlEditorWindow>("gGameControlEditorEnabled", "Game Control Editor"); + gui->AddGuiWindow(mGameControlEditorWindow); + mCosmeticsEditorWindow = std::make_shared<CosmeticsEditorWindow>("gCosmeticsEditorEnabled", "Cosmetics Editor"); + gui->AddGuiWindow(mCosmeticsEditorWindow); + mActorViewerWindow = std::make_shared<ActorViewerWindow>("gActorViewerEnabled", "Actor Viewer"); + gui->AddGuiWindow(mActorViewerWindow); + mColViewerWindow = std::make_shared<ColViewerWindow>("gCollisionViewerEnabled", "Collision Viewer"); + gui->AddGuiWindow(mColViewerWindow); + mSaveEditorWindow = std::make_shared<SaveEditorWindow>("gSaveEditorEnabled", "Save Editor"); + gui->AddGuiWindow(mSaveEditorWindow); + mDLViewerWindow = std::make_shared<DLViewerWindow>("gDLViewerEnabled", "Display List Viewer"); + gui->AddGuiWindow(mDLViewerWindow); + mGameplayStatsWindow = std::make_shared<GameplayStatsWindow>("gGameplayStatsEnabled", "Gameplay Stats"); + gui->AddGuiWindow(mGameplayStatsWindow); + mCheckTrackerWindow = std::make_shared<CheckTracker::CheckTrackerWindow>("gCheckTrackerEnabled", "Check Tracker"); + gui->AddGuiWindow(mCheckTrackerWindow); + mCheckTrackerSettingsWindow = std::make_shared<CheckTracker::CheckTrackerSettingsWindow>("gCheckTrackerSettingsEnabled", "Check Tracker Settings"); + gui->AddGuiWindow(mCheckTrackerSettingsWindow); + mEntranceTrackerWindow = std::make_shared<EntranceTrackerWindow>("gEntranceTrackerEnabled","Entrance Tracker"); + gui->AddGuiWindow(mEntranceTrackerWindow); + mItemTrackerWindow = std::make_shared<ItemTrackerWindow>("gItemTrackerEnabled", "Item Tracker"); + gui->AddGuiWindow(mItemTrackerWindow); + mItemTrackerSettingsWindow = std::make_shared<ItemTrackerSettingsWindow>("gItemTrackerSettingsEnabled", "Item Tracker Settings"); + gui->AddGuiWindow(mItemTrackerSettingsWindow); + mRandomizerSettingsWindow = std::make_shared<RandomizerSettingsWindow>("gRandomizerSettingsEnabled", "Randomizer Settings"); + gui->AddGuiWindow(mRandomizerSettingsWindow); + */ + } + + void Destroy() { + //mRandomizerSettingsWindow = nullptr; + //mItemTrackerWindow = nullptr; + //mItemTrackerSettingsWindow = nullptr; + //mEntranceTrackerWindow = nullptr; + //mCheckTrackerWindow = nullptr; + //mCheckTrackerSettingsWindow = nullptr; + //mGameplayStatsWindow = nullptr; + //mDLViewerWindow = nullptr; + //mSaveEditorWindow = nullptr; + //mColViewerWindow = nullptr; + //mActorViewerWindow = nullptr; + //mCosmeticsEditorWindow = nullptr; + //mGameControlEditorWindow = nullptr; + //mAudioEditorWindow = nullptr; + //mInputEditorWindow = nullptr; + mStatsWindow = nullptr; + mConsoleWindow = nullptr; + mSohMenuBar = nullptr; + } +} diff --git a/mm/2s2h/SohGui.hpp b/mm/2s2h/SohGui.hpp new file mode 100644 index 000000000..8e5fc9447 --- /dev/null +++ b/mm/2s2h/SohGui.hpp @@ -0,0 +1,42 @@ +// +// SohGui.hpp +// soh +// +// Created by David Chavez on 24.08.22. +// + +#ifndef SohGui_hpp +#define SohGui_hpp + +#include <stdio.h> +#include "SohMenuBar.h" +//#include "Enhancements/audio/AudioEditor.h" +//#include "Enhancements/controls/GameControlEditor.h" +//#include "Enhancements/cosmetics/CosmeticsEditor.h" +//#include "Enhancements/debugger/actorViewer.h" +//#include "Enhancements/debugger/colViewer.h" +//#include "Enhancements/debugger/debugSaveEditor.h" +//#include "Enhancements/debugger/dlViewer.h" +//#include "Enhancements/gameplaystatswindow.h" +//#include "Enhancements/randomizer/randomizer_check_tracker.h" +//#include "Enhancements/randomizer/randomizer_entrance_tracker.h" +//#include "Enhancements/randomizer/randomizer_item_tracker.h" +//#include "Enhancements/randomizer/randomizer_settings_window.h" + +#ifdef __cplusplus +extern "C" { +#endif + void enableBetaQuest(); + void disableBetaQuest(); +#ifdef __cplusplus +} +#endif + +namespace SohGui { + void SetupHooks(); + void SetupGuiElements(); + void Draw(); + void Destroy(); +} + +#endif /* SohGui_hpp */ diff --git a/mm/2s2h/SohMenuBar.cpp b/mm/2s2h/SohMenuBar.cpp new file mode 100644 index 000000000..1192cd2bf --- /dev/null +++ b/mm/2s2h/SohMenuBar.cpp @@ -0,0 +1,563 @@ +#include "SohMenuBar.h" +#include "ImGui/imgui.h" +#include "public/bridge/consolevariablebridge.h" +#include <libultraship/libultraship.h> +#include "UIWidgets.hpp" +//#include "include/z64audio.h" +//#include "OTRGlobals.h" +#include "z64.h" +//#include "Enhancements/game-interactor/GameInteractor.h" +//#include "soh/Enhancements/presets.h" +//#include "soh/Enhancements/mods.h" +//#include "Enhancements/cosmetics/authenticGfxPatches.h" +#ifdef ENABLE_CROWD_CONTROL +#include "Enhancements/crowd-control/CrowdControl.h" +#endif + + +//#include "Enhancements/audio/AudioEditor.h" +//#include "Enhancements/controls/GameControlEditor.h" +//#include "Enhancements/cosmetics/CosmeticsEditor.h" +//#include "Enhancements/debugger/actorViewer.h" +//#include "Enhancements/debugger/colViewer.h" +//#include "Enhancements/debugger/debugSaveEditor.h" +//#include "Enhancements/debugger/dlViewer.h" +//#include "Enhancements/gameplaystatswindow.h" +//#include "Enhancements/randomizer/randomizer_check_tracker.h" +//#include "Enhancements/randomizer/randomizer_entrance_tracker.h" +//#include "Enhancements/randomizer/randomizer_item_tracker.h" +//#include "Enhancements/randomizer/randomizer_settings_window.h" + +extern bool ShouldClearTextureCacheAtEndOfFrame; +extern bool isBetaQuestEnabled; + +extern "C" PlayState* gPlayState; + +enum SeqPlayers { + /* 0 */ SEQ_BGM_MAIN, + /* 1 */ SEQ_FANFARE, + /* 2 */ SEQ_SFX, + /* 3 */ SEQ_BGM_SUB, + /* 4 */ SEQ_MAX +}; + +std::string GetWindowButtonText(const char* text, bool menuOpen) { + char buttonText[100] = ""; + if (menuOpen) { + strcat(buttonText, ICON_FA_CHEVRON_RIGHT " "); + } + strcat(buttonText, text); + if (!menuOpen) { strcat(buttonText, " "); } + return buttonText; +} + + static const char* filters[3] = { +#ifdef __WIIU__ + "", +#else + "Three-Point", +#endif + "Linear", "None" + }; + + static const char* chestStyleMatchesContentsOptions[4] = { "Disabled", "Both", "Texture Only", "Size Only" }; + static const char* bunnyHoodOptions[3] = { "Disabled", "Faster Run & Longer Jump", "Faster Run" }; + static const char* mirroredWorldModes[9] = { + "Disabled", "Always", "Random", "Random (Seeded)", "Dungeons", + "Dungeons (Vanilla)", "Dungeons (MQ)", "Dungeons Random", "Dungeons Random (Seeded)", + }; + static const char* enemyRandomizerModes[3] = { "Disabled", "Random", "Random (Seeded)" }; + static const char* allPowers[9] = { + "Vanilla (1x)", + "Double (2x)", + "Quadruple (4x)", + "Octuple (8x)", + "Foolish (16x)", + "Ridiculous (32x)", + "Merciless (64x)", + "Pure Torture (128x)", + "OHKO (256x)" }; + static const char* subPowers[8] = { allPowers[0], allPowers[1], allPowers[2], allPowers[3], allPowers[4], allPowers[5], allPowers[6], allPowers[7] }; + static const char* subSubPowers[7] = { allPowers[0], allPowers[1], allPowers[2], allPowers[3], allPowers[4], allPowers[5], allPowers[6] }; + static const char* zFightingOptions[3] = { "Disabled", "Consistent Vanish", "No Vanish" }; + static const char* autosaveLabels[6] = { "Off", "New Location + Major Item", "New Location + Any Item", "New Location", "Major Item", "Any Item" }; + static const char* DebugSaveFileModes[3] = { "Off", "Vanilla", "Maxed" }; + static const char* FastFileSelect[5] = { "File N.1", "File N.2", "File N.3", "Zelda Map Select (require OoT Debug Mode)", "File select" }; + static const char* DekuStickCheat[3] = { "Normal", "Unbreakable", "Unbreakable + Always on Fire" }; + static const char* bonkDamageValues[8] = { + "No Damage", + "0.25 Heart", + "0.5 Heart", + "1 Heart", + "2 Hearts", + "4 Hearts", + "8 Hearts", + "OHKO" + }; + static const char* timeTravelOptions[3] = { "Disabled", "Ocarina of Time", "Any Ocarina" }; + +extern "C" SaveContext gSaveContext; + +namespace SohGui { + +void DrawMenuBarIcon() { + static bool gameIconLoaded = false; + if (!gameIconLoaded) { + LUS::Context::GetInstance()->GetWindow()->GetGui()->LoadTexture("Game_Icon", "textures/icons/gIcon.png"); + gameIconLoaded = true; + } + + if (LUS::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName("Game_Icon")) { +#ifdef __SWITCH__ + ImVec2 iconSize = ImVec2(20.0f, 20.0f); + float posScale = 1.0f; +#elif defined(__WIIU__) + ImVec2 iconSize = ImVec2(16.0f * 2, 16.0f * 2); + float posScale = 2.0f; +#else + ImVec2 iconSize = ImVec2(16.0f, 16.0f); + float posScale = 1.0f; +#endif + ImGui::SetCursorPos(ImVec2(5, 2.5f) * posScale); + ImGui::Image(LUS::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName("Game_Icon"), iconSize); + ImGui::SameLine(); + ImGui::SetCursorPos(ImVec2(25, 0) * posScale); + } +} + +void DrawShipMenu() { + if (ImGui::BeginMenu("Ship")) { + if (ImGui::MenuItem("Hide Menu Bar", +#if !defined(__SWITCH__) && !defined(__WIIU__) + "F1" +#else + "[-]" +#endif + )) { + LUS::Context::GetInstance()->GetWindow()->GetGui()->GetMenuBar()->ToggleVisibility(); + } + UIWidgets::Spacer(0); +#if !defined(__SWITCH__) && !defined(__WIIU__) + if (ImGui::MenuItem("Toggle Fullscreen", "F11")) { + LUS::Context::GetInstance()->GetWindow()->ToggleFullscreen(); + } + UIWidgets::Spacer(0); +#endif + if (ImGui::MenuItem("Reset", +#ifdef __APPLE__ + "Command-R" +#elif !defined(__SWITCH__) && !defined(__WIIU__) + "Ctrl+R" +#else + "" +#endif + )) { + std::reinterpret_pointer_cast<LUS::ConsoleWindow>( + LUS::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Console")) + ->Dispatch("reset"); + } +#if !defined(__SWITCH__) && !defined(__WIIU__) + UIWidgets::Spacer(0); + if (ImGui::MenuItem("Open App Files Folder")) { + std::string filesPath = LUS::Context::GetInstance()->GetAppDirectoryPath(); + SDL_OpenURL(std::string("file:///" + std::filesystem::absolute(filesPath).string()).c_str()); + } + UIWidgets::Spacer(0); + + if (ImGui::MenuItem("Quit")) { + LUS::Context::GetInstance()->GetWindow()->Close(); + } +#endif + ImGui::EndMenu(); + } +} + +extern std::shared_ptr<LUS::GuiWindow> mInputEditorWindow; +// extern std::shared_ptr<GameControlEditor::GameControlEditorWindow> mGameControlEditorWindow; + +void DrawSettingsMenu() { + if (ImGui::BeginMenu("Settings")) { + if (ImGui::BeginMenu("Audio")) { + UIWidgets::PaddedEnhancementSliderFloat("Master Volume: %d %%", "##Master_Vol", "gGameMasterVolume", 0.0f, + 1.0f, "", 1.0f, true, true, false, true); + if (UIWidgets::PaddedEnhancementSliderFloat("Main Music Volume: %d %%", "##Main_Music_Vol", + "gMainMusicVolume", 0.0f, 1.0f, "", 1.0f, true, true, false, + true)) { + // Audio_SetGameVolume(SEQ_BGM_MAIN, CVarGetFloat("gMainMusicVolume", 1.0f)); + } + if (UIWidgets::PaddedEnhancementSliderFloat("Sub Music Volume: %d %%", "##Sub_Music_Vol", "gSubMusicVolume", + 0.0f, 1.0f, "", 1.0f, true, true, false, true)) { + // Audio_SetGameVolume(SEQ_BGM_SUB, CVarGetFloat("gSubMusicVolume", 1.0f)); + } + if (UIWidgets::PaddedEnhancementSliderFloat("Sound Effects Volume: %d %%", "##Sound_Effect_Vol", + "gSFXMusicVolume", 0.0f, 1.0f, "", 1.0f, true, true, false, + true)) { + // Audio_SetGameVolume(SEQ_SFX, CVarGetFloat("gSFXMusicVolume", 1.0f)); + } + if (UIWidgets::PaddedEnhancementSliderFloat("Fanfare Volume: %d %%", "##Fanfare_Vol", "gFanfareVolume", + 0.0f, 1.0f, "", 1.0f, true, true, false, true)) { + // Audio_SetGameVolume(SEQ_FANFARE, CVarGetFloat("gFanfareVolume", 1.0f)); + } + + static std::unordered_map<LUS::AudioBackend, const char*> audioBackendNames = { + { LUS::AudioBackend::WASAPI, "Windows Audio Session API" }, + { LUS::AudioBackend::PULSE, "PulseAudio" }, + { LUS::AudioBackend::SDL, "SDL" }, + }; + + ImGui::Text("Audio API (Needs reload)"); + auto currentAudioBackend = LUS::Context::GetInstance()->GetAudio()->GetAudioBackend(); + + if (LUS::Context::GetInstance()->GetAudio()->GetAvailableAudioBackends()->size() <= 1) { + UIWidgets::DisableComponent(ImGui::GetStyle().Alpha * 0.5f); + } + if (ImGui::BeginCombo("##AApi", audioBackendNames[currentAudioBackend])) { + for (uint8_t i = 0; i < LUS::Context::GetInstance()->GetAudio()->GetAvailableAudioBackends()->size(); + i++) { + auto backend = LUS::Context::GetInstance()->GetAudio()->GetAvailableAudioBackends()->data()[i]; + if (ImGui::Selectable(audioBackendNames[backend], backend == currentAudioBackend)) { + LUS::Context::GetInstance()->GetAudio()->SetAudioBackend(backend); + } + } + ImGui::EndCombo(); + } + if (LUS::Context::GetInstance()->GetAudio()->GetAvailableAudioBackends()->size() <= 1) { + UIWidgets::ReEnableComponent(""); + } + + ImGui::EndMenu(); + } + + UIWidgets::Spacer(0); + + if (ImGui::BeginMenu("Controller")) { + //ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(12.0f, 6.0f)); + //ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.0f, 0.0f)); + //ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f); + //ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.22f, 0.38f, 0.56f, 1.0f)); + if (mInputEditorWindow) { + if (ImGui::Button( + GetWindowButtonText("Controller Mapping", CVarGetInteger("gControllerConfigurationEnabled", 0)) + .c_str(), + ImVec2(-1.0f, 0.0f))) { + mInputEditorWindow->ToggleVisibility(); + } + } + // if (mGameControlEditorWindow) { + // if (ImGui::Button(GetWindowButtonText("Additional Controller Options", + // CVarGetInteger("gGameControlEditorEnabled", 0)).c_str(), ImVec2(-1.0f, 0.0f))) { + // mGameControlEditorWindow->ToggleVisibility(); + //} + + ImGui::EndMenu(); + + } + UIWidgets::PaddedSeparator(); + //ImGui::PopStyleColor(1); + //ImGui::PopStyleVar(3); +#ifndef __SWITCH__ + UIWidgets::EnhancementCheckbox("Menubar Controller Navigation", "gControlNav"); + UIWidgets::Tooltip("Allows controller navigation of the SOH menu bar (Settings, Enhancements,...)\nCAUTION: " + "This will disable game inputs while the menubar is visible.\n\nD-pad to move between " + "items, A to select, and X to grab focus on the menu bar"); +#endif + UIWidgets::PaddedEnhancementCheckbox("Show Inputs", "gInputEnabled", true, false); + UIWidgets::Tooltip("Shows currently pressed inputs on the bottom right of the screen"); + UIWidgets::PaddedEnhancementSliderFloat("Input Scale: %.1f", "##Input", "gInputScale", 1.0f, 3.0f, "", 1.0f, + false, true, true, false); + UIWidgets::Tooltip("Sets the on screen size of the displayed inputs from the Show Inputs setting"); + UIWidgets::PaddedEnhancementSliderInt("Simulated Input Lag: %d frames", "##SimulatedInputLag", + "gSimulatedInputLag", 0, 6, "", 0, true, true, false); + UIWidgets::Tooltip("Buffers your inputs to be executed a specified amount of frames later"); + + ImGui::EndMenu(); + } + + UIWidgets::Spacer(0); + + if (ImGui::BeginMenu("Graphics")) { +#ifndef __APPLE__ + if (UIWidgets::EnhancementSliderFloat("Internal Resolution: %d %%", "##IMul", "gInternalResolution", 0.5f, 2.0f, + "", 1.0f, true)) { + LUS::Context::GetInstance()->GetWindow()->SetResolutionMultiplier(CVarGetFloat("gInternalResolution", 1)); + }; + UIWidgets::Tooltip("Multiplies your output resolution by the value inputted, as a more intensive but effective " + "form of anti-aliasing"); +#endif +#ifndef __WIIU__ + if (UIWidgets::PaddedEnhancementSliderInt("MSAA: %d", "##IMSAA", "gMSAAValue", 1, 8, "", 1, true, true, + false)) { + LUS::Context::GetInstance()->GetWindow()->SetMsaaLevel(CVarGetInteger("gMSAAValue", 1)); + }; + UIWidgets::Tooltip("Activates multi-sample anti-aliasing when above 1x up to 8x for 8 samples for every pixel"); +#endif + + { // FPS Slider + const int minFps = 20; + static int maxFps; + if (LUS::Context::GetInstance()->GetWindow()->GetWindowBackend() == LUS::WindowBackend::DX11) { + maxFps = 360; + } else { + maxFps = LUS::Context::GetInstance()->GetWindow()->GetCurrentRefreshRate(); + } + // int currentFps = fmax(fmin(OTRGlobals::Instance->GetInterpolationFPS(), maxFps), minFps); + int currentFps = 20; + bool matchingRefreshRate = + CVarGetInteger("gMatchRefreshRate", 0) && + LUS::Context::GetInstance()->GetWindow()->GetWindowBackend() != LUS::WindowBackend::DX11; + UIWidgets::PaddedEnhancementSliderInt((currentFps == 20) ? "FPS: Original (20)" : "FPS: %d", + "##FPSInterpolation", "gInterpolationFPS", minFps, maxFps, "", 20, + true, true, false, matchingRefreshRate); + if (LUS::Context::GetInstance()->GetWindow()->GetWindowBackend() == LUS::WindowBackend::DX11) { + UIWidgets::Tooltip( + "Uses Matrix Interpolation to create extra frames, resulting in smoother graphics. This is purely " + "visual and does not impact game logic, execution of glitches etc.\n\n" + "A higher target FPS than your monitor's refresh rate will waste resources, and might give a worse " + "result."); + } else { + UIWidgets::Tooltip( + "Uses Matrix Interpolation to create extra frames, resulting in smoother graphics. This is purely " + "visual and does not impact game logic, execution of glitches etc."); + } + } // END FPS Slider + + if (LUS::Context::GetInstance()->GetWindow()->GetWindowBackend() == LUS::WindowBackend::DX11) { + UIWidgets::Spacer(0); + if (ImGui::Button("Match Refresh Rate")) { + int hz = LUS::Context::GetInstance()->GetWindow()->GetCurrentRefreshRate(); + if (hz >= 20 && hz <= 360) { + CVarSetInteger("gInterpolationFPS", hz); + LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); + } + } + } else { + UIWidgets::PaddedEnhancementCheckbox("Match Refresh Rate", "gMatchRefreshRate", true, false); + } + UIWidgets::Tooltip("Matches interpolation value to the current game's window refresh rate"); + + if (LUS::Context::GetInstance()->GetWindow()->GetWindowBackend() == LUS::WindowBackend::DX11) { + UIWidgets::PaddedEnhancementSliderInt( + CVarGetInteger("gExtraLatencyThreshold", 80) == 0 ? "Jitter fix: Off" : "Jitter fix: >= %d FPS", + "##ExtraLatencyThreshold", "gExtraLatencyThreshold", 0, 360, "", 80, true, true, false); + UIWidgets::Tooltip("When Interpolation FPS setting is at least this threshold, add one frame of input lag " + "(e.g. 16.6 ms for 60 FPS) in order to avoid jitter. This setting allows the CPU to " + "work on one frame while GPU works on the previous frame.\nThis setting should be used " + "when your computer is too slow to do CPU + GPU work in time."); + } + + UIWidgets::PaddedSeparator(true, true, 3.0f, 3.0f); + + static std::unordered_map<LUS::WindowBackend, const char*> windowBackendNames = { + { LUS::WindowBackend::DX11, "DirectX" }, + { LUS::WindowBackend::SDL_OPENGL, "OpenGL" }, + { LUS::WindowBackend::SDL_METAL, "Metal" }, + { LUS::WindowBackend::GX2, "GX2" } + }; + + ImGui::Text("Renderer API (Needs reload)"); + LUS::WindowBackend runningWindowBackend = LUS::Context::GetInstance()->GetWindow()->GetWindowBackend(); + LUS::WindowBackend configWindowBackend; + int configWindowBackendId = LUS::Context::GetInstance()->GetConfig()->GetInt("Window.Backend.Id", -1); + if (configWindowBackendId != -1 && + configWindowBackendId < static_cast<int>(LUS::WindowBackend::BACKEND_COUNT)) { + configWindowBackend = static_cast<LUS::WindowBackend>(configWindowBackendId); + } else { + configWindowBackend = runningWindowBackend; + } + + if (LUS::Context::GetInstance()->GetWindow()->GetAvailableWindowBackends()->size() <= 1) { + UIWidgets::DisableComponent(ImGui::GetStyle().Alpha * 0.5f); + } + if (ImGui::BeginCombo("##RApi", windowBackendNames[configWindowBackend])) { + for (size_t i = 0; i < LUS::Context::GetInstance()->GetWindow()->GetAvailableWindowBackends()->size(); + i++) { + auto backend = LUS::Context::GetInstance()->GetWindow()->GetAvailableWindowBackends()->data()[i]; + if (ImGui::Selectable(windowBackendNames[backend], backend == configWindowBackend)) { + LUS::Context::GetInstance()->GetConfig()->SetInt("Window.Backend.Id", static_cast<int>(backend)); + LUS::Context::GetInstance()->GetConfig()->SetString("Window.Backend.Name", + windowBackendNames[backend]); + LUS::Context::GetInstance()->GetConfig()->Save(); + } + } + ImGui::EndCombo(); + } + if (LUS::Context::GetInstance()->GetWindow()->GetAvailableWindowBackends()->size() <= 1) { + UIWidgets::ReEnableComponent(""); + } + + if (LUS::Context::GetInstance()->GetWindow()->CanDisableVerticalSync()) { + UIWidgets::PaddedEnhancementCheckbox("Enable Vsync", "gVsyncEnabled", true, false); + } + + if (LUS::Context::GetInstance()->GetWindow()->SupportsWindowedFullscreen()) { + UIWidgets::PaddedEnhancementCheckbox("Windowed fullscreen", "gSdlWindowedFullscreen", true, false); + } + + if (LUS::Context::GetInstance()->GetWindow()->GetGui()->SupportsViewports()) { + UIWidgets::PaddedEnhancementCheckbox("Allow multi-windows", "gEnableMultiViewports", true, false, false, "", + UIWidgets::CheckboxGraphics::Cross, true); + UIWidgets::Tooltip("Allows windows to be able to be dragged off of the main game window. Requires a reload " + "to take effect."); + } + + // If more filters are added to LUS, make sure to add them to the filters list here + ImGui::Text("Texture Filter (Needs reload)"); + + UIWidgets::EnhancementCombobox("gTextureFilter", filters, FILTER_THREE_POINT); + + UIWidgets::Spacer(0); + + LUS::Context::GetInstance()->GetWindow()->GetGui()->GetGameOverlay()->DrawSettings(); + + ImGui::EndMenu(); + } + + UIWidgets::Spacer(0); + + if (ImGui::BeginMenu("Languages")) { + UIWidgets::PaddedEnhancementCheckbox("Translate Title Screen", "gTitleScreenTranslation"); + if (UIWidgets::EnhancementRadioButton("English", "gLanguages", LANGUAGE_ENG)) { + // GameInteractor::Instance->ExecuteHooks<GameInteractor::OnSetGameLanguage>(); + } + if (UIWidgets::EnhancementRadioButton("German", "gLanguages", LANGUAGE_GER)) { + // GameInteractor::Instance->ExecuteHooks<GameInteractor::OnSetGameLanguage>(); + } + // if (UIWidgets::EnhancementRadioButton("French", "gLanguages", LANGUAGE_FRA)) { + // GameInteractor::Instance->ExecuteHooks<GameInteractor::OnSetGameLanguage>(); + //} + ImGui::EndMenu(); + } + + UIWidgets::Spacer(0); + + if (ImGui::BeginMenu("Accessibility")) { +#if defined(_WIN32) || defined(__APPLE__) + UIWidgets::PaddedEnhancementCheckbox("Text to Speech", "gA11yTTS"); + UIWidgets::Tooltip("Enables text to speech for in game dialog"); +#endif + UIWidgets::PaddedEnhancementCheckbox("Disable Idle Camera Re-Centering", "gA11yDisableIdleCam"); + UIWidgets::Tooltip("Disables the automatic re-centering of the camera when idle."); + + ImGui::EndMenu(); + } + + //ImGui::EndMenu(); +} + +extern std::shared_ptr<LUS::GuiWindow> mStatsWindow; +extern std::shared_ptr<LUS::GuiWindow> mConsoleWindow; +// extern std::shared_ptr<SaveEditorWindow> mSaveEditorWindow; +// extern std::shared_ptr<ColViewerWindow> mColViewerWindow; +// extern std::shared_ptr<ActorViewerWindow> mActorViewerWindow; +// extern std::shared_ptr<DLViewerWindow> mDLViewerWindow; + +void DrawDeveloperToolsMenu() { + if (ImGui::BeginMenu("Developer Tools")) { + UIWidgets::EnhancementCheckbox("OoT Debug Mode", "gDebugEnabled"); + UIWidgets::Tooltip("Enables Debug Mode, allowing you to select maps with L + R + Z, noclip with L + D-pad " + "Right, and open the debug menu with L on the pause screen"); + if (CVarGetInteger("gDebugEnabled", 0)) { + ImGui::Text("Debug Save File Mode:"); + UIWidgets::EnhancementCombobox("gDebugSaveFileMode", DebugSaveFileModes, 1); + UIWidgets::Tooltip("Changes the behaviour of debug file select creation (creating a save file on slot 1 " + "with debug mode on)\n" + "- Off: The debug save file will be a normal savefile\n" + "- Vanilla: The debug save file will be the debug save file from the original game\n" + "- Maxed: The debug save file will be a save file with all of the items & upgrades"); + } + UIWidgets::PaddedEnhancementCheckbox("OoT Skulltula Debug", "gSkulltulaDebugEnabled", true, false); + UIWidgets::Tooltip("Enables Skulltula Debug, when moving the cursor in the menu above various map icons (boss " + "key, compass, map screen locations, etc) will set the GS bits in that area.\nUSE WITH " + "CAUTION AS IT DOES NOT UPDATE THE GS COUNT."); + UIWidgets::PaddedEnhancementCheckbox("Fast File Select", "gSkipLogoTitle", true, false); + UIWidgets::Tooltip( + "Load the game to the selected menu or file\n\"Zelda Map Select\" require debug mode else you will " + "fallback to File choose menu\nUsing a file number that don't have save will create a save file only if " + "you toggle on \"Create a new save if none ?\" else it will bring you to the File choose menu"); + if (CVarGetInteger("gSkipLogoTitle", 0)) { + ImGui::Text("Loading:"); + UIWidgets::EnhancementCombobox("gSaveFileID", FastFileSelect, 0); + }; + UIWidgets::PaddedEnhancementCheckbox("Better Debug Warp Screen", "gBetterDebugWarpScreen", true, false); + UIWidgets::Tooltip("Optimized debug warp screen, with the added ability to chose entrances and time of day"); + UIWidgets::PaddedEnhancementCheckbox("Debug Warp Screen Translation", "gDebugWarpScreenTranslation", true, + false, false, "", UIWidgets::CheckboxGraphics::Cross, true); + UIWidgets::Tooltip("Translate the Debug Warp Screen based on the game language"); + UIWidgets::PaddedSeparator(); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(12.0f, 6.0f)); + ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0, 0)); + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f); + ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.22f, 0.38f, 0.56f, 1.0f)); + if (mStatsWindow) { + if (ImGui::Button(GetWindowButtonText("Stats", CVarGetInteger("gStatsEnabled", 0)).c_str(), + ImVec2(-1.0f, 0.0f))) { + mStatsWindow->ToggleVisibility(); + } + UIWidgets::Tooltip("Shows the stats window, with your FPS and frametimes, and the OS you're playing on"); + } + UIWidgets::Spacer(0); + if (mConsoleWindow) { + if (ImGui::Button(GetWindowButtonText("Console", CVarGetInteger("gConsoleEnabled", 0)).c_str(), + ImVec2(-1.0f, 0.0f))) { + mConsoleWindow->ToggleVisibility(); + } + UIWidgets::Tooltip( + "Enables the console window, allowing you to input commands, type help for some examples"); + } + UIWidgets::Spacer(0); + // if (mSaveEditorWindow) { + // if (ImGui::Button(GetWindowButtonText("Save Editor", CVarGetInteger("gSaveEditorEnabled", 0)).c_str(), + // ImVec2(-1.0f, 0.0f))) { + // //mSaveEditorWindow->ToggleVisibility(); + // } + // } + // UIWidgets::Spacer(0); + // if (mColViewerWindow) { + // if (ImGui::Button(GetWindowButtonText("Collision Viewer", CVarGetInteger("gCollisionViewerEnabled", + // 0)).c_str(), ImVec2(-1.0f, 0.0f))) { + // //mColViewerWindow->ToggleVisibility(); + // } + // } + // UIWidgets::Spacer(0); + // if (mActorViewerWindow) { + // if (ImGui::Button(GetWindowButtonText("Actor Viewer", CVarGetInteger("gActorViewerEnabled", 0)).c_str(), + // ImVec2(-1.0f, 0.0f))) { + // //mActorViewerWindow->ToggleVisibility(); + // } + // } + // UIWidgets::Spacer(0); + // if (mDLViewerWindow) { + // if (ImGui::Button(GetWindowButtonText("Display List Viewer", CVarGetInteger("gDLViewerEnabled", + // 0)).c_str(), ImVec2(-1.0f, 0.0f))) { + // //mDLViewerWindow->ToggleVisibility(); + // } + // } + + ImGui::PopStyleVar(3); + ImGui::PopStyleColor(1); + + ImGui::EndMenu(); + } +} + +void SohMenuBar::DrawElement() { + if (ImGui::BeginMenuBar()) { + static ImVec2 sWindowPadding(8.0f, 8.0f); + + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, sWindowPadding); + + ImGui::SetCursorPosY(0.0f); + DrawSettingsMenu(); + + ImGui::SetCursorPosY(0.0f); + + DrawDeveloperToolsMenu(); + + ImGui::SetCursorPosY(0.0f); + + ImGui::PopStyleVar(1); + ImGui::EndMenuBar(); + } +} +} + // namespace SohGui
\ No newline at end of file diff --git a/mm/2s2h/SohMenuBar.h b/mm/2s2h/SohMenuBar.h new file mode 100644 index 000000000..ecfb2764e --- /dev/null +++ b/mm/2s2h/SohMenuBar.h @@ -0,0 +1,16 @@ +#pragma once + +//#include <libultraship/libultraship.h> +#include "window/gui/GuiMenuBar.h" +#include "window/gui/GuiElement.h" + +namespace SohGui { +class SohMenuBar : public LUS::GuiMenuBar { + public: + using LUS::GuiMenuBar::GuiMenuBar; + protected: + void DrawElement() override; + void InitElement() override {}; + void UpdateElement() override {}; +}; +} // namespace SohGui
\ No newline at end of file diff --git a/mm/2s2h/UIWidgets.cpp b/mm/2s2h/UIWidgets.cpp new file mode 100644 index 000000000..3086f32ad --- /dev/null +++ b/mm/2s2h/UIWidgets.cpp @@ -0,0 +1,716 @@ +// +// UIWidgets.cpp +// soh +// +// Created by David Chavez on 25.08.22. +// + +#include "UIWidgets.hpp" + +#define IMGUI_DEFINE_MATH_OPERATORS +#include <ImGui/imgui_internal.h> +#include <libultraship/libultraship.h> + +#include <libultraship/libultra/types.h> +//#include "soh/Enhancements/cosmetics/CosmeticsEditor.h" + +namespace UIWidgets { + + // MARK: - Layout Helper + + // Automatically adds newlines to break up text longer than a specified number of characters + // Manually included newlines will still be respected and reset the line length + // If line is midword when it hits the limit, text should break at the last encountered space + char* WrappedText(const char* text, unsigned int charactersPerLine) { + std::string newText(text); + const size_t tipLength = newText.length(); + int lastSpace = -1; + int currentLineLength = 0; + for (unsigned int currentCharacter = 0; currentCharacter < tipLength; currentCharacter++) { + if (newText[currentCharacter] == '\n') { + currentLineLength = 0; + lastSpace = -1; + continue; + } else if (newText[currentCharacter] == ' ') { + lastSpace = currentCharacter; + } + + if ((currentLineLength >= charactersPerLine) && (lastSpace >= 0)) { + newText[lastSpace] = '\n'; + currentLineLength = currentCharacter - lastSpace - 1; + lastSpace = -1; + } + currentLineLength++; + } + + return strdup(newText.c_str()); + } + + char* WrappedText(const std::string& text, unsigned int charactersPerLine) { + return WrappedText(text.c_str(), charactersPerLine); + } + + void SetLastItemHoverText(const std::string& text) { + if (ImGui::IsItemHovered()) { + ImGui::BeginTooltip(); + ImGui::Text("%s", WrappedText(text, 60)); + ImGui::EndTooltip(); + } + } + + void SetLastItemHoverText(const char* text) { + if (ImGui::IsItemHovered()) { + ImGui::BeginTooltip(); + ImGui::Text("%s", WrappedText(text, 60)); + ImGui::EndTooltip(); + } + } + + // Adds a "?" next to the previous ImGui item with a custom tooltip + void InsertHelpHoverText(const std::string& text) { + ImGui::SameLine(); + ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "?"); + if (ImGui::IsItemHovered()) { + ImGui::BeginTooltip(); + ImGui::Text("%s", WrappedText(text, 60)); + ImGui::EndTooltip(); + } + } + + void InsertHelpHoverText(const char* text) { + ImGui::SameLine(); + ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "?"); + if (ImGui::IsItemHovered()) { + ImGui::BeginTooltip(); + ImGui::Text("%s", WrappedText(text, 60)); + ImGui::EndTooltip(); + } + } + + + // MARK: - UI Elements + + void Tooltip(const char* text) { + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("%s", WrappedText(text)); + } + } + + void Spacer(float height) { + ImGui::Dummy(ImVec2(0.0f, height)); + } + + void PaddedSeparator(bool padTop, bool padBottom, float extraVerticalTopPadding, float extraVerticalBottomPadding) { + if (padTop) { + Spacer(extraVerticalTopPadding); + } + ImGui::Separator(); + if (padBottom) { + Spacer(extraVerticalBottomPadding); + } + } + + void RenderCross(ImDrawList* draw_list, ImVec2 pos, ImU32 col, float sz) { + float thickness = ImMax(sz / 5.0f, 1.0f); + sz -= thickness * 0.5f; + pos += ImVec2(thickness * 0.25f, thickness * 0.25f); + + draw_list->PathLineTo(ImVec2(pos.x, pos.y)); + draw_list->PathLineTo(ImVec2(pos.x + sz, pos.y + sz)); + draw_list->PathStroke(col, 0, thickness); + + draw_list->PathLineTo(ImVec2(pos.x + sz, pos.y)); + draw_list->PathLineTo(ImVec2(pos.x, pos.y + sz)); + draw_list->PathStroke(col, 0, thickness); + } + + bool CustomCheckbox(const char* label, bool* v, bool disabled, CheckboxGraphics disabledGraphic) { + ImGuiWindow* window = ImGui::GetCurrentWindow(); + if (window->SkipItems) { + return false; + } + + ImGuiContext& g = *GImGui; + const ImGuiStyle& style = g.Style; + const ImGuiID id = window->GetID(label); + const ImVec2 label_size = ImGui::CalcTextSize(label, NULL, true); + + const float square_sz = ImGui::GetFrameHeight(); + const ImVec2 pos = window->DC.CursorPos; + const ImRect total_bb(pos, pos + ImVec2(square_sz + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), label_size.y + style.FramePadding.y * 2.0f)); + ImGui::ItemSize(total_bb, style.FramePadding.y); + if (!ImGui::ItemAdd(total_bb, id)) { + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0)); + return false; + } + + bool hovered, held; + bool pressed = ImGui::ButtonBehavior(total_bb, id, &hovered, &held); + if (pressed) { + *v = !(*v); + ImGui::MarkItemEdited(id); + } + + const ImRect check_bb(pos, pos + ImVec2(square_sz, square_sz)); + ImGui::RenderNavHighlight(total_bb, id); + ImGui::RenderFrame(check_bb.Min, check_bb.Max, ImGui::GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), true, style.FrameRounding); + ImU32 check_col = ImGui::GetColorU32(ImGuiCol_CheckMark); + ImU32 cross_col = ImGui::GetColorU32(ImVec4(0.50f, 0.50f, 0.50f, 1.00f)); + bool mixed_value = (g.LastItemData.InFlags & ImGuiItemFlags_MixedValue) != 0; + if (mixed_value) { + // Undocumented tristate/mixed/indeterminate checkbox (#2644) + // This may seem awkwardly designed because the aim is to make ImGuiItemFlags_MixedValue supported by all widgets (not just checkbox) + ImVec2 pad(ImMax(1.0f, IM_FLOOR(square_sz / 3.6f)), ImMax(1.0f, IM_FLOOR(square_sz / 3.6f))); + window->DrawList->AddRectFilled(check_bb.Min + pad, check_bb.Max - pad, check_col, style.FrameRounding); + } else if ((!disabled && *v) || (disabled && disabledGraphic == CheckboxGraphics::Checkmark)) { + const float pad = ImMax(1.0f, IM_FLOOR(square_sz / 6.0f)); + ImGui::RenderCheckMark(window->DrawList, check_bb.Min + ImVec2(pad, pad), check_col, square_sz - pad * 2.0f); + } else if (disabled && disabledGraphic == CheckboxGraphics::Cross) { + const float pad = ImMax(1.0f, IM_FLOOR(square_sz / 6.0f)); + RenderCross(window->DrawList, check_bb.Min + ImVec2(pad, pad), cross_col, square_sz - pad * 2.0f); + } + + ImVec2 label_pos = ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y); + if (g.LogEnabled) { + ImGui::LogRenderedText(&label_pos, mixed_value ? "[~]" : *v ? "[x]" : "[ ]"); + } + if (label_size.x > 0.0f) { + ImGui::RenderText(label_pos, label); + } + + IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0)); + return pressed; + } + + void ReEnableComponent(const char* disabledTooltipText) { + // End of disable region of previous component + ImGui::PopStyleVar(1); + if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && strcmp(disabledTooltipText, "") != 0) { + ImGui::SetTooltip("%s", disabledTooltipText); + } + ImGui::PopItemFlag(); + } + + void DisableComponent(const float alpha) { + ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); + ImGui::PushStyleVar(ImGuiStyleVar_Alpha, alpha); + } + + bool EnhancementCheckbox(const char* text, const char* cvarName, bool disabled, const char* disabledTooltipText, CheckboxGraphics disabledGraphic, bool defaultValue) { + bool changed = false; + if (disabled) { + DisableComponent(ImGui::GetStyle().Alpha * 0.5f); + } + + bool val = (bool)CVarGetInteger(cvarName, defaultValue); + if (CustomCheckbox(text, &val, disabled, disabledGraphic)) { + CVarSetInteger(cvarName, val); + LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); + changed = true; + } + + if (disabled) { + ReEnableComponent(disabledTooltipText); + } + return changed; + } + + bool PaddedEnhancementCheckbox(const char* text, const char* cvarName, bool padTop, bool padBottom, bool disabled, const char* disabledTooltipText, CheckboxGraphics disabledGraphic, bool defaultValue) { + ImGui::BeginGroup(); + if (padTop) Spacer(0); + + bool changed = EnhancementCheckbox(text, cvarName, disabled, disabledTooltipText, disabledGraphic, defaultValue); + + if (padBottom) Spacer(0); + ImGui::EndGroup(); + return changed; + } + + bool EnhancementCombobox(const char* cvarName, std::span<const char*, std::dynamic_extent> comboArray, uint8_t defaultIndex, bool disabled, const char* disabledTooltipText, uint8_t disabledValue) { + bool changed = false; + if (defaultIndex <= 0) { + defaultIndex = 0; + } + + if (disabled) { + DisableComponent(ImGui::GetStyle().Alpha * 0.5f); + } + + uint8_t selected = CVarGetInteger(cvarName, defaultIndex); + std::string comboName = std::string("##") + std::string(cvarName); + if (ImGui::BeginCombo(comboName.c_str(), comboArray[selected])) { + for (uint8_t i = 0; i < comboArray.size(); i++) { + if (strlen(comboArray[i]) > 0) { + if (ImGui::Selectable(comboArray[i], i == selected)) { + CVarSetInteger(cvarName, i); + selected = i; + changed = true; + LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); + } + } + } + ImGui::EndCombo(); + } + + if (disabled) { + ReEnableComponent(disabledTooltipText); + + if (disabledValue >= 0 && selected != disabledValue) { + CVarSetInteger(cvarName, disabledValue); + changed = true; + LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); + } + } + + return changed; + } + + bool LabeledRightAlignedEnhancementCombobox(const char* label, const char* cvarName, std::span<const char*, std::dynamic_extent> comboArray, uint8_t defaultIndex, bool disabled, const char* disabledTooltipText, uint8_t disabledValue) { + ImGui::Text("%s", label); + s32 currentValue = CVarGetInteger(cvarName, defaultIndex); + +#ifdef __WIIU__ + ImGui::SameLine(ImGui::GetContentRegionAvail().x - (ImGui::CalcTextSize(comboArray[currentValue]).x + 40.0f)); + ImGui::PushItemWidth(ImGui::CalcTextSize(comboArray[currentValue]).x + 60.0f); +#else + ImGui::SameLine(ImGui::GetContentRegionAvail().x - (ImGui::CalcTextSize(comboArray[currentValue]).x + 20.0f)); + ImGui::PushItemWidth(ImGui::CalcTextSize(comboArray[currentValue]).x + 30.0f); +#endif + + bool changed = EnhancementCombobox(cvarName, comboArray, defaultIndex, disabled, disabledTooltipText, disabledValue); + + ImGui::PopItemWidth(); + return changed; + } + + void PaddedText(const char* text, bool padTop, bool padBottom) { + if (padTop) Spacer(0); + + ImGui::Text("%s", text); + + if (padBottom) Spacer(0); + } + + bool EnhancementSliderInt(const char* text, const char* id, const char* cvarName, int min, int max, const char* format, int defaultValue, bool PlusMinusButton, bool disabled, const char* disabledTooltipText) { + bool changed = false; + int val = CVarGetInteger(cvarName, defaultValue); + + if (disabled) { + DisableComponent(ImGui::GetStyle().Alpha * 0.5f); + } + + ImGui::Text(text, val); + Spacer(0); + + ImGui::BeginGroup(); + if (PlusMinusButton) { + std::string MinusBTNName = " - ##" + std::string(cvarName); + if (ImGui::Button(MinusBTNName.c_str())) { + val--; + changed = true; + } + ImGui::SameLine(); + ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 7.0f); + } + + ImGui::PushItemWidth(std::min((ImGui::GetContentRegionAvail().x - (PlusMinusButton ? sliderButtonWidth : 0.0f)), maxSliderWidth)); + if (ImGui::SliderInt(id, &val, min, max, format, ImGuiSliderFlags_AlwaysClamp)) + { + changed = true; + } + ImGui::PopItemWidth(); + + if (PlusMinusButton) { + std::string PlusBTNName = " + ##" + std::string(cvarName); + ImGui::SameLine(); + ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 7.0f); + if (ImGui::Button(PlusBTNName.c_str())) { + val++; + changed = true; + } + } + ImGui::EndGroup(); + + if (disabled) { + ReEnableComponent(disabledTooltipText); + } + + if (val < min) { + val = min; + changed = true; + } + + if (val > max) { + val = max; + changed = true; + } + + if (changed) { + CVarSetInteger(cvarName, val); + LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); + } + + return changed; + } + + bool EnhancementSliderFloat(const char* text, const char* id, const char* cvarName, float min, float max, const char* format, float defaultValue, bool isPercentage, bool PlusMinusButton, bool disabled, const char* disabledTooltipText) { + bool changed = false; + float val = CVarGetFloat(cvarName, defaultValue); + + if (disabled) { + DisableComponent(ImGui::GetStyle().Alpha * 0.5f); + } + + if (!isPercentage) { + ImGui::Text(text, val); + } else { + ImGui::Text(text, static_cast<int>(100 * val)); + } + Spacer(0); + + ImGui::BeginGroup(); + if (PlusMinusButton) { + std::string MinusBTNName = " - ##" + std::string(cvarName); + if (ImGui::Button(MinusBTNName.c_str())) { + if (isPercentage) { + val -= 0.01f; + } else { + val -= 0.1f; + } + changed = true; + } + ImGui::SameLine(); + ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 7.0f); + } + + ImGui::PushItemWidth(std::min((ImGui::GetContentRegionAvail().x - (PlusMinusButton ? sliderButtonWidth : 0.0f)), maxSliderWidth)); + if (ImGui::SliderFloat(id, &val, min, max, format, ImGuiSliderFlags_AlwaysClamp)) { + if (isPercentage) { + val = roundf(val * 100) / 100; + } + changed = true; + } + ImGui::PopItemWidth(); + + if (PlusMinusButton) { + std::string PlusBTNName = " + ##" + std::string(cvarName); + ImGui::SameLine(); + ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 7.0f); + if (ImGui::Button(PlusBTNName.c_str())) { + if (isPercentage) { + val += 0.01f; + } else { + val += 0.1f; + } + changed = true; + } + } + ImGui::EndGroup(); + + if (disabled) { + ReEnableComponent(disabledTooltipText); + } + + if (val < min) { + val = min; + changed = true; + } + + if (val > max) { + val = max; + changed = true; + } + + if (changed) { + CVarSetFloat(cvarName, val); + LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); + } + + return changed; + } + + bool PaddedEnhancementSliderInt(const char* text, const char* id, const char* cvarName, int min, int max, const char* format, int defaultValue, bool PlusMinusButton, bool padTop, bool padBottom, bool disabled, const char* disabledTooltipText) { + bool changed = false; + ImGui::BeginGroup(); + if (padTop) Spacer(0); + + changed = EnhancementSliderInt(text, id, cvarName, min, max, format, defaultValue, PlusMinusButton, disabled, disabledTooltipText); + + if (padBottom) Spacer(0); + ImGui::EndGroup(); + return changed; + } + + bool PaddedEnhancementSliderFloat(const char* text, const char* id, const char* cvarName, float min, float max, const char* format, float defaultValue, bool isPercentage, bool PlusMinusButton, bool padTop, bool padBottom, bool disabled, const char* disabledTooltipText) { + bool changed = false; + ImGui::BeginGroup(); + if (padTop) Spacer(0); + + changed = EnhancementSliderFloat(text, id, cvarName, min, max, format, defaultValue, isPercentage, PlusMinusButton, disabled, disabledTooltipText); + + if (padBottom) Spacer(0); + ImGui::EndGroup(); + return changed; + } + + bool EnhancementRadioButton(const char* text, const char* cvarName, int id) { + /*Usage : + EnhancementRadioButton("My Visible Name","gMyCVarName", MyID); + First arg is the visible name of the Radio button + Second is the cvar name where MyID will be saved. + Note: the CVar name should be the same to each Buddies. + Example : + EnhancementRadioButton("English", "gLanguages", LANGUAGE_ENG); + EnhancementRadioButton("German", "gLanguages", LANGUAGE_GER); + EnhancementRadioButton("French", "gLanguages", LANGUAGE_FRA); + */ + std::string make_invisible = "##" + std::string(text) + std::string(cvarName); + + bool ret = false; + int val = CVarGetInteger(cvarName, 0); + if (ImGui::RadioButton(make_invisible.c_str(), id == val)) { + CVarSetInteger(cvarName, id); + LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); + ret = true; + } + ImGui::SameLine(); + ImGui::Text("%s", text); + + return ret; + } + + bool DrawResetColorButton(const char* cvarName, ImVec4* colors, ImVec4 defaultcolors, bool has_alpha) { + bool changed = false; + std::string Cvar_RBM = std::string(cvarName) + "RBM"; + std::string MakeInvisible = "Reset##" + std::string(cvarName) + "Reset"; + if (ImGui::Button(MakeInvisible.c_str())) { + colors->x = defaultcolors.x; + colors->y = defaultcolors.y; + colors->z = defaultcolors.z; + colors->w = has_alpha ? defaultcolors.w : 255.0f; + + Color_RGBA8 colorsRGBA; + colorsRGBA.r = defaultcolors.x; + colorsRGBA.g = defaultcolors.y; + colorsRGBA.b = defaultcolors.z; + colorsRGBA.a = has_alpha ? defaultcolors.w : 255.0f; + + CVarSetColor(cvarName, colorsRGBA); + CVarSetInteger(Cvar_RBM.c_str(), 0); //On click disable rainbow mode. + LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); + changed = true; + } + Tooltip("Revert colors to the game's original colors (GameCube version)\nOverwrites previously chosen color"); + return changed; + } + + bool DrawRandomizeColorButton(const char* cvarName, ImVec4* colors) { + return false; + } + + void DrawLockColorCheckbox(const char* cvarName) { + std::string Cvar_Lock = std::string(cvarName) + "Lock"; + s32 lock = CVarGetInteger(Cvar_Lock.c_str(), 0); + std::string FullName = "Lock##" + Cvar_Lock; + EnhancementCheckbox(FullName.c_str(), Cvar_Lock.c_str()); + Tooltip("Prevents this color from being changed upon selecting \"Randomize all\""); + } + + void RainbowColor(const char* cvarName, ImVec4* colors) { + std::string Cvar_RBM = std::string(cvarName) + "RBM"; + std::string MakeInvisible = "Rainbow##" + std::string(cvarName) + "Rainbow"; + + EnhancementCheckbox(MakeInvisible.c_str(), Cvar_RBM.c_str()); + Tooltip("Cycles through colors on a timer\nOverwrites previously chosen color"); + } + + void LoadPickersColors(ImVec4& ColorArray, const char* cvarname, const ImVec4& default_colors, bool has_alpha) { + Color_RGBA8 defaultColors; + defaultColors.r = default_colors.x; + defaultColors.g = default_colors.y; + defaultColors.b = default_colors.z; + defaultColors.a = default_colors.w; + + Color_RGBA8 cvarColor = CVarGetColor(cvarname, defaultColors); + + ColorArray.x = cvarColor.r / 255.0; + ColorArray.y = cvarColor.g / 255.0; + ColorArray.z = cvarColor.b / 255.0; + ColorArray.w = cvarColor.a / 255.0; + } + + bool EnhancementColor(const char* text, const char* cvarName, ImVec4 ColorRGBA, ImVec4 default_colors, bool allow_rainbow, bool has_alpha, bool TitleSameLine) { + bool changed = false; + LoadPickersColors(ColorRGBA, cvarName, default_colors, has_alpha); + + ImGuiColorEditFlags flags = ImGuiColorEditFlags_None; + + if (!TitleSameLine) { + ImGui::Text("%s", text); + flags = ImGuiColorEditFlags_NoLabel; + } + + ImGui::PushID(cvarName); + + if (!has_alpha) { + if (ImGui::ColorEdit3(text, (float*)&ColorRGBA, flags)) + { + Color_RGBA8 colors; + colors.r = ColorRGBA.x * 255.0; + colors.g = ColorRGBA.y * 255.0; + colors.b = ColorRGBA.z * 255.0; + colors.a = 255.0; + + CVarSetColor(cvarName, colors); + LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); + changed = true; + } + } + else + { + flags |= ImGuiColorEditFlags_AlphaBar | ImGuiColorEditFlags_AlphaPreview; + if (ImGui::ColorEdit4(text, (float*)&ColorRGBA, flags)) + { + Color_RGBA8 colors; + colors.r = ColorRGBA.x * 255.0; + colors.g = ColorRGBA.y * 255.0; + colors.b = ColorRGBA.z * 255.0; + colors.a = ColorRGBA.w * 255.0; + + CVarSetColor(cvarName, colors); + LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); + changed = true; + } + } + + ImGui::PopID(); + + //ImGui::SameLine(); // Removing that one to gain some width spacing on the HUD editor + ImGui::PushItemWidth(-FLT_MIN); + if (DrawResetColorButton(cvarName, &ColorRGBA, default_colors, has_alpha)) { + changed = true; + } + ImGui::SameLine(); + if (DrawRandomizeColorButton(cvarName, &ColorRGBA)) { + changed = true; + } + if (allow_rainbow) { + if (ImGui::GetContentRegionAvail().x > 185) { + ImGui::SameLine(); + } + RainbowColor(cvarName, &ColorRGBA); + } + DrawLockColorCheckbox(cvarName); + ImGui::NewLine(); + ImGui::PopItemWidth(); + + return changed; + } + + void DrawFlagArray32(const std::string& name, uint32_t& flags) { + ImGui::PushID(name.c_str()); + for (int32_t flagIndex = 0; flagIndex < 32; flagIndex++) { + if ((flagIndex % 8) != 0) { + ImGui::SameLine(); + } + ImGui::PushID(flagIndex); + uint32_t bitMask = 1 << flagIndex; + bool flag = (flags & bitMask) != 0; + if (ImGui::Checkbox("##check", &flag)) { + if (flag) { + flags |= bitMask; + } else { + flags &= ~bitMask; + } + } + ImGui::PopID(); + } + ImGui::PopID(); + } + + void DrawFlagArray16(const std::string& name, uint16_t& flags) { + ImGui::PushID(name.c_str()); + for (int16_t flagIndex = 0; flagIndex < 16; flagIndex++) { + if ((flagIndex % 8) != 0) { + ImGui::SameLine(); + } + ImGui::PushID(flagIndex); + uint16_t bitMask = 1 << flagIndex; + bool flag = (flags & bitMask) != 0; + if (ImGui::Checkbox("##check", &flag)) { + if (flag) { + flags |= bitMask; + } else { + flags &= ~bitMask; + } + } + ImGui::PopID(); + } + ImGui::PopID(); + } + + void DrawFlagArray8(const std::string& name, uint8_t& flags) { + ImGui::PushID(name.c_str()); + for (int8_t flagIndex = 0; flagIndex < 8; flagIndex++) { + if ((flagIndex % 8) != 0) { + ImGui::SameLine(); + } + ImGui::PushID(flagIndex); + uint8_t bitMask = 1 << flagIndex; + bool flag = (flags & bitMask) != 0; + if (ImGui::Checkbox("##check", &flag)) { + if (flag) { + flags |= bitMask; + } else { + flags &= ~bitMask; + } + } + ImGui::PopID(); + } + ImGui::PopID(); + } + + bool StateButtonEx(const char* str_id, const char* label, ImVec2 size, ImGuiButtonFlags flags) { + ImGuiContext& g = *GImGui; + ImGuiWindow* window = ImGui::GetCurrentWindow(); + if (window->SkipItems) + return false; + + const ImGuiStyle& style = g.Style; + const ImVec2 label_size = ImGui::CalcTextSize(label, NULL, true); + + const ImGuiID id = window->GetID(str_id); + const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size); + const float default_size = ImGui::GetFrameHeight(); + ImGui::ItemSize(size, (size.y >= default_size) ? g.Style.FramePadding.y : -1.0f); + if (!ImGui::ItemAdd(bb, id)) + return false; + + if (g.LastItemData.InFlags & ImGuiItemFlags_ButtonRepeat) + flags |= ImGuiButtonFlags_Repeat; + + bool hovered, held; + bool pressed = ImGui::ButtonBehavior(bb, id, &hovered, &held, flags); + + // Render + const ImU32 bg_col = ImGui::GetColorU32((held && hovered) ? ImGuiCol_ButtonActive + : hovered ? ImGuiCol_ButtonHovered + : ImGuiCol_Button); + //const ImU32 text_col = ImGui::GetColorU32(ImGuiCol_Text); + ImGui::RenderNavHighlight(bb, id); + ImGui::RenderFrame(bb.Min, bb.Max, bg_col, true, g.Style.FrameRounding); + ImGui::RenderTextClipped(bb.Min + style.FramePadding, bb.Max - style.FramePadding, label, NULL, &label_size, {0.55f, 0.45f}, &bb); + /*ImGui::RenderArrow(window->DrawList, + bb.Min + + ImVec2(ImMax(0.0f, (size.x - g.FontSize) * 0.5f), ImMax(0.0f, (size.y - g.FontSize) * 0.5f)), + text_col, dir);*/ + + IMGUI_TEST_ENGINE_ITEM_INFO(id, str_id, g.LastItemData.StatusFlags); + return pressed; + } + + bool StateButton(const char* str_id, const char* label) { + float sz = ImGui::GetFrameHeight(); + return StateButtonEx(str_id, label, ImVec2(sz, sz), ImGuiButtonFlags_None); + } +} diff --git a/mm/2s2h/UIWidgets.hpp b/mm/2s2h/UIWidgets.hpp new file mode 100644 index 000000000..b18487977 --- /dev/null +++ b/mm/2s2h/UIWidgets.hpp @@ -0,0 +1,101 @@ +// +// UIWidgets.hpp +// soh +// +// Created by David Chavez on 25.08.22. +// + +#ifndef UIWidgets_hpp +#define UIWidgets_hpp + +#include <string> +#include <vector> +#include <span> +#include <stdint.h> +#include <ImGui/imgui.h> + +namespace UIWidgets { + + struct TextFilters { + static int FilterNumbers(ImGuiInputTextCallbackData* data) { + if (data->EventChar < 256 && strchr("1234567890", (char)data->EventChar)) { + return 0; + } + return 1; + } + + static int FilterAlphaNum(ImGuiInputTextCallbackData* data) { + const char* alphanum = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWYZ0123456789"; + if (data->EventChar < 256 && strchr(alphanum, (char)data->EventChar)) { + return 0; + } + return 1; + } + + }; + + // MARK: - Enums + + enum class CheckboxGraphics { + Cross, + Checkmark, + None + }; + constexpr float maxSliderWidth = 260.0f; +#ifdef __SWITCH__ + constexpr float sliderButtonWidth = 42.0f; +#elif defined(__WIIU__) + constexpr float sliderButtonWidth = 60.0f; +#else + constexpr float sliderButtonWidth = 30.0f; +#endif + + char* WrappedText(const char* text, unsigned int charactersPerLine = 60); + char* WrappedText(const std::string& text, unsigned int charactersPerLine); + + void SetLastItemHoverText(const std::string& text); + void SetLastItemHoverText(const char* text); + + void InsertHelpHoverText(const std::string& text); + void InsertHelpHoverText(const char* text); + + void Tooltip(const char* text); + void Spacer(float height); + void PaddedSeparator(bool padTop = true, bool padBottom = true, float extraVerticalTopPadding = 0.0f, float extraVerticalBottomPadding = 0.0f); + + void RenderCross(ImDrawList* draw_list, ImVec2 pos, ImU32 col, float sz); + bool CustomCheckbox(const char* label, bool* v, bool disabled, CheckboxGraphics disabledGraphic); + + void ReEnableComponent(const char* disabledTooltipText); + void DisableComponent(const float alpha); + + bool EnhancementCheckbox(const char* text, const char* cvarName, bool disabled = false, const char* disabledTooltipText = "", CheckboxGraphics disabledGraphic = CheckboxGraphics::Cross, bool defaultValue = false); + bool PaddedEnhancementCheckbox(const char* text, const char* cvarName, bool padTop = true, bool padBottom = true, bool disabled = false, const char* disabledTooltipText = "", CheckboxGraphics disabledGraphic = CheckboxGraphics::Cross, bool defaultValue = false); + + bool EnhancementCombobox(const char* cvarName, std::span<const char*, std::dynamic_extent> comboArray, uint8_t defaultIndex, bool disabled = false, const char* disabledTooltipText = "", uint8_t disabledValue = -1); + bool LabeledRightAlignedEnhancementCombobox(const char* label, const char* cvarName, std::span<const char*, std::dynamic_extent> comboArray, uint8_t defaultIndex, bool disabled = false, const char* disabledTooltipText = "", uint8_t disabledValue = -1); + + void PaddedText(const char* text, bool padTop = true, bool padBottom = true); + + bool EnhancementSliderInt(const char* text, const char* id, const char* cvarName, int min, int max, const char* format, int defaultValue = 0, bool PlusMinusButton = true, bool disabled = false, const char* disabledTooltipText = ""); + bool PaddedEnhancementSliderInt(const char* text, const char* id, const char* cvarName, int min, int max, const char* format, int defaultValue = 0, bool PlusMinusButton = true, bool padTop = true, bool padBottom = true, bool disabled = false, const char* disabledTooltipText = ""); + bool EnhancementSliderFloat(const char* text, const char* id, const char* cvarName, float min, float max, const char* format, float defaultValue, bool isPercentage, bool PlusMinusButton = true, bool disabled = false, const char* disabledTooltipText = ""); + bool PaddedEnhancementSliderFloat(const char* text, const char* id, const char* cvarName, float min, float max, const char* format, float defaultValue, bool isPercentage, bool PlusMinusButton = true, bool padTop = true, bool padBottom = true, bool disabled = false, const char* disabledTooltipText = ""); + + bool EnhancementRadioButton(const char* text, const char* cvarName, int id); + + bool DrawResetColorButton(const char* cvarName, ImVec4* colors, ImVec4 defaultcolors, bool has_alpha); + bool DrawRandomizeColorButton(const char* cvarName, ImVec4* colors); + void DrawLockColorCheckbox(const char* cvarName); + void RainbowColor(const char* cvarName, ImVec4* colors); + + void LoadPickersColors(ImVec4& ColorArray, const char* cvarname, const ImVec4& default_colors, bool has_alpha); + bool EnhancementColor(const char* text, const char* cvarName, ImVec4 ColorRGBA, ImVec4 default_colors, bool allow_rainbow = true, bool has_alpha = false, bool TitleSameLine = false); + + void DrawFlagArray32(const std::string& name, uint32_t& flags); + void DrawFlagArray16(const std::string& name, uint16_t& flags); + void DrawFlagArray8(const std::string& name, uint8_t& flags); + bool StateButton(const char* str_id, const char* label); +} + +#endif /* UIWidgets_hpp */ diff --git a/mm/2s2h/gu_pc.c b/mm/2s2h/gu_pc.c new file mode 100644 index 000000000..be1954a5d --- /dev/null +++ b/mm/2s2h/gu_pc.c @@ -0,0 +1,88 @@ +#include <math.h> +#include "z64.h" + +void guMtxF2L(float mf[4][4], Mtx* m) { + unsigned int r, c; + s32 tmp1; + s32 tmp2; + s32* m1 = &m->m[0][0]; + s32* m2 = &m->m[2][0]; + for (r = 0; r < 4; r++) { + for (c = 0; c < 2; c++) { + tmp1 = mf[r][2 * c] * 65536.0f; + tmp2 = mf[r][2 * c + 1] * 65536.0f; + *m1++ = (tmp1 & 0xffff0000) | ((tmp2 >> 0x10) & 0xffff); + *m2++ = ((tmp1 << 0x10) & 0xffff0000) | (tmp2 & 0xffff); + } + } +} + +void guMtxL2F(float mf[4][4], Mtx* m) { + unsigned int r, c; + u32 tmp1; + u32 tmp2; + u32* m1; + u32* m2; + s32 stmp1, stmp2; + m1 = (u32*)&m->m[0][0]; + m2 = (u32*)&m->m[2][0]; + for (r = 0; r < 4; r++) { + for (c = 0; c < 2; c++) { + tmp1 = (*m1 & 0xffff0000) | ((*m2 >> 0x10) & 0xffff); + tmp2 = ((*m1++ << 0x10) & 0xffff0000) | (*m2++ & 0xffff); + stmp1 = *(s32*)&tmp1; + stmp2 = *(s32*)&tmp2; + mf[r][c * 2 + 0] = stmp1 / 65536.0f; + mf[r][c * 2 + 1] = stmp2 / 65536.0f; + } + } +} + +void guMtxIdentF(f32 mf[4][4]) { + unsigned int r, c; + for (r = 0; r < 4; r++) { + for (c = 0; c < 4; c++) { + if (r == c) { + mf[r][c] = 1.0f; + } else { + mf[r][c] = 0.0f; + } + } + } +} + +void guMtxIdent(Mtx* m) { + guMtxIdentF(m->m); +} + +void guTranslateF(float m[4][4], float x, float y, float z) { + guMtxIdentF(m); + m[3][0] = x; + m[3][1] = y; + m[3][2] = z; +} +void guTranslate(Mtx* m, float x, float y, float z) { + float mf[4][4]; + guTranslateF(mf, x, y, z); + guMtxF2L(mf, m); +} + +void guScaleF(float mf[4][4], float x, float y, float z) { + guMtxIdentF(mf); + mf[0][0] = x; + mf[1][1] = y; + mf[2][2] = z; + mf[3][3] = 1.0; +} +void guScale(Mtx* m, float x, float y, float z) { + float mf[4][4]; + guScaleF(mf, x, y, z); + guMtxF2L(mf, m); +} + +void guNormalize(f32* x, f32* y, f32* z) { + f32 tmp = 1.0f / sqrtf(*x * *x + *y * *y + *z * *z); + *x = *x * tmp; + *y = *y * tmp; + *z = *z * tmp; +} diff --git a/mm/2s2h/resource/importer/AnimationFactory.cpp b/mm/2s2h/resource/importer/AnimationFactory.cpp new file mode 100644 index 000000000..c177c8ea9 --- /dev/null +++ b/mm/2s2h/resource/importer/AnimationFactory.cpp @@ -0,0 +1,108 @@ +#include "2s2h/resource/importer/AnimationFactory.h" +#include "2s2h/resource/type/Animation.h" +#include "2s2h/resource/importer/PlayerAnimationFactory.h" +#include <libultraship/libultraship.h> +#include "spdlog/spdlog.h" + +namespace LUS { +std::shared_ptr<IResource> +AnimationFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) { + auto resource = std::make_shared<Animation>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 0: + factory = std::make_shared<AnimationFactoryV0>(); + break; + } + + if (factory == nullptr) { + SPDLOG_ERROR("Failed to load Animation with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileBinary(reader, resource); + + return resource; +} + +void LUS::AnimationFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) { + std::shared_ptr<Animation> animation = std::static_pointer_cast<Animation>(resource); + + ResourceVersionFactory::ParseFileBinary(reader, animation); + + AnimationType animType = (AnimationType)reader->ReadUInt32(); + animation->type = animType; + + if (animType == AnimationType::Normal) { + // Set frame count + animation->animationData.animationHeader.common.frameCount = reader->ReadInt16(); + + // Populate frame data + uint32_t rotValuesCnt = reader->ReadUInt32(); + animation->rotationValues.reserve(rotValuesCnt); + for (uint32_t i = 0; i < rotValuesCnt; i++) { + animation->rotationValues.push_back(reader->ReadUInt16()); + } + animation->animationData.animationHeader.frameData = (int16_t*)animation->rotationValues.data(); + + // Populate joint indices + uint32_t rotIndCnt = reader->ReadUInt32(); + animation->rotationIndices.reserve(rotIndCnt); + for (size_t i = 0; i < rotIndCnt; i++) { + uint16_t x = reader->ReadUInt16(); + uint16_t y = reader->ReadUInt16(); + uint16_t z = reader->ReadUInt16(); + animation->rotationIndices.push_back(RotationIndex(x, y, z)); + } + animation->animationData.animationHeader.jointIndices = (JointIndex*)animation->rotationIndices.data(); + + // Set static index max + animation->animationData.animationHeader.staticIndexMax = reader->ReadInt16(); + } else if (animType == AnimationType::Curve) { + // Read frame count (unused in this animation type) + reader->ReadInt16(); + + // Set refIndex + uint32_t refArrCnt = reader->ReadUInt32(); + animation->refIndexArr.reserve(refArrCnt); + for (uint32_t i = 0; i < refArrCnt; i++) { + animation->refIndexArr.push_back(reader->ReadUByte()); + } + animation->animationData.transformUpdateIndex.refIndex = animation->refIndexArr.data(); + + // Populate transform data + uint32_t transformDataCnt = reader->ReadUInt32(); + animation->transformDataArr.reserve(transformDataCnt); + for (uint32_t i = 0; i < transformDataCnt; i++) { + TransformData data; + data.unk_00 = reader->ReadUInt16(); + data.unk_02 = reader->ReadInt16(); + data.unk_04 = reader->ReadInt16(); + data.unk_06 = reader->ReadInt16(); + data.unk_08 = reader->ReadFloat(); + + animation->transformDataArr.push_back(data); + } + animation->animationData.transformUpdateIndex.transformData = animation->transformDataArr.data(); + + // Populate copy values + uint32_t copyValuesCnt = reader->ReadUInt32(); + animation->copyValuesArr.reserve(copyValuesCnt); + for (uint32_t i = 0; i < copyValuesCnt; i++) { + animation->copyValuesArr.push_back(reader->ReadInt16()); + } + animation->animationData.transformUpdateIndex.copyValues = animation->copyValuesArr.data(); + } else if (animType == AnimationType::Link) { + // Read the frame count + animation->animationData.linkAnimationHeader.common.frameCount = reader->ReadInt16(); + + // Read the segment pointer (always 32 bit, doesn't adjust for system pointer size) + std::string path = reader->ReadString(); + + animation->animationData.linkAnimationHeader.segment = ResourceGetDataByName(path.c_str()); + } else if (animType == AnimationType::Legacy) { + SPDLOG_DEBUG("BEYTAH ANIMATION?!"); + } +} +} // namespace LUS diff --git a/mm/2s2h/resource/importer/AnimationFactory.h b/mm/2s2h/resource/importer/AnimationFactory.h new file mode 100644 index 000000000..dee2026f9 --- /dev/null +++ b/mm/2s2h/resource/importer/AnimationFactory.h @@ -0,0 +1,17 @@ +#pragma once + +#include "Resource.h" +#include "ResourceFactory.h" + +namespace LUS { +class AnimationFactory : public ResourceFactory { + public: + std::shared_ptr<IResource> + ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) override; +}; + +class AnimationFactoryV0 : public ResourceVersionFactory { + public: + void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/importer/AudioSampleFactory.cpp b/mm/2s2h/resource/importer/AudioSampleFactory.cpp new file mode 100644 index 000000000..73c5af484 --- /dev/null +++ b/mm/2s2h/resource/importer/AudioSampleFactory.cpp @@ -0,0 +1,141 @@ +#include "2s2h/resource/importer/AudioSampleFactory.h" +#include "2s2h/resource/type/AudioSample.h" +#include "spdlog/spdlog.h" + +namespace LUS { +std::shared_ptr<IResource> +AudioSampleFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) { + auto resource = std::make_shared<AudioSample>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 2: + factory = std::make_shared<AudioSampleFactoryV0>(); + break; + } + + if (factory == nullptr) { + SPDLOG_ERROR("Failed to load AudioSample with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileBinary(reader, resource); + + return resource; +} + +void LUS::AudioSampleFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader, + std::shared_ptr<IResource> resource) +{ + std::shared_ptr<AudioSample> audioSample = std::static_pointer_cast<AudioSample>(resource); + ResourceVersionFactory::ParseFileBinary(reader, audioSample); + + audioSample->sample.codec = reader->ReadUByte(); + audioSample->sample.medium = reader->ReadUByte(); + audioSample->sample.unk_bit26 = reader->ReadUByte(); + audioSample->sample.unk_bit25 = reader->ReadUByte(); + audioSample->sample.size = reader->ReadUInt32(); + + audioSample->audioSampleData.reserve(audioSample->sample.size); + for (uint32_t i = 0; i < audioSample->sample.size; i++) { + audioSample->audioSampleData.push_back(reader->ReadUByte()); + } + audioSample->sample.sampleAddr = audioSample->audioSampleData.data(); + + audioSample->loop.start = reader->ReadUInt32(); + audioSample->loop.end = reader->ReadUInt32(); + audioSample->loop.count = reader->ReadUInt32(); + + audioSample->loopStateCount = reader->ReadUInt32(); + for (int i = 0; i < 16; i++) { + audioSample->loop.state[i] = 0; + } + for (uint32_t i = 0; i < audioSample->loopStateCount; i++) { + audioSample->loop.state[i] = reader->ReadInt16(); + } + audioSample->sample.loop = &audioSample->loop; + + audioSample->book.order = reader->ReadInt32(); + audioSample->book.npredictors = reader->ReadInt32(); + audioSample->bookDataCount = reader->ReadUInt32(); + + audioSample->bookData.reserve(audioSample->bookDataCount); + for (uint32_t i = 0; i < audioSample->bookDataCount; i++) { + audioSample->bookData.push_back(reader->ReadInt16()); + } + audioSample->book.book = audioSample->bookData.data(); + audioSample->sample.book = &audioSample->book; +} +} // namespace LUS + + +/* +in ResourceMgr_LoadAudioSample we used to have +-------------- + if (cachedCustomSFs.find(path) != cachedCustomSFs.end()) + return cachedCustomSFs[path]; + + SoundFontSample* cSample = ReadCustomSample(path); + + if (cSample != nullptr) + return cSample; +-------------- +before the rest of the standard sample reading, this is the ReadCustomSample code we used to have + +extern "C" SoundFontSample* ReadCustomSample(const char* path) { + + if (!ExtensionCache.contains(path)) + return nullptr; + + ExtensionEntry entry = ExtensionCache[path]; + + auto sampleRaw = LUS::Context::GetInstance()->GetResourceManager()->LoadFile(entry.path); + uint32_t* strem = (uint32_t*)sampleRaw->Buffer.get(); + uint8_t* strem2 = (uint8_t*)strem; + + SoundFontSample* sampleC = new SoundFontSample; + + if (entry.ext == "wav") { + drwav_uint32 channels; + drwav_uint32 sampleRate; + drwav_uint64 totalPcm; + drmp3_int16* pcmData = + drwav_open_memory_and_read_pcm_frames_s16(strem2, sampleRaw->BufferSize, &channels, &sampleRate, &totalPcm, NULL); + sampleC->size = totalPcm; + sampleC->sampleAddr = (uint8_t*)pcmData; + sampleC->codec = CODEC_S16; + + sampleC->loop = new AdpcmLoop; + sampleC->loop->start = 0; + sampleC->loop->end = sampleC->size - 1; + sampleC->loop->count = 0; + sampleC->sampleRateMagicValue = 'RIFF'; + sampleC->sampleRate = sampleRate; + + cachedCustomSFs[path] = sampleC; + return sampleC; + } else if (entry.ext == "mp3") { + drmp3_config mp3Info; + drmp3_uint64 totalPcm; + drmp3_int16* pcmData = + drmp3_open_memory_and_read_pcm_frames_s16(strem2, sampleRaw->BufferSize, &mp3Info, &totalPcm, NULL); + + sampleC->size = totalPcm * mp3Info.channels * sizeof(short); + sampleC->sampleAddr = (uint8_t*)pcmData; + sampleC->codec = CODEC_S16; + + sampleC->loop = new AdpcmLoop; + sampleC->loop->start = 0; + sampleC->loop->end = sampleC->size; + sampleC->loop->count = 0; + sampleC->sampleRateMagicValue = 'RIFF'; + sampleC->sampleRate = mp3Info.sampleRate; + + cachedCustomSFs[path] = sampleC; + return sampleC; + } + + return nullptr; +} + +*/ diff --git a/mm/2s2h/resource/importer/AudioSampleFactory.h b/mm/2s2h/resource/importer/AudioSampleFactory.h new file mode 100644 index 000000000..6e9ddc17c --- /dev/null +++ b/mm/2s2h/resource/importer/AudioSampleFactory.h @@ -0,0 +1,19 @@ +#pragma once + +#include "Resource.h" +#include "ResourceFactory.h" + +namespace LUS { +class AudioSampleFactory : public ResourceFactory +{ + public: + std::shared_ptr<IResource> + ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) override; +}; + +class AudioSampleFactoryV0 : public ResourceVersionFactory +{ + public: + void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/importer/AudioSequenceFactory.cpp b/mm/2s2h/resource/importer/AudioSequenceFactory.cpp new file mode 100644 index 000000000..20c5df8a3 --- /dev/null +++ b/mm/2s2h/resource/importer/AudioSequenceFactory.cpp @@ -0,0 +1,52 @@ +#include "2s2h/resource/importer/AudioSequenceFactory.h" +#include "2s2h/resource/type/AudioSequence.h" +#include "spdlog/spdlog.h" + +namespace LUS { +std::shared_ptr<IResource> +AudioSequenceFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) { + auto resource = std::make_shared<AudioSequence>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 2: + factory = std::make_shared<AudioSequenceFactoryV0>(); + break; + } + + if (factory == nullptr) + { + SPDLOG_ERROR("Failed to load AudioSequence with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileBinary(reader, resource); + + return resource; +} + +void LUS::AudioSequenceFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader, + std::shared_ptr<IResource> resource) { + std::shared_ptr<AudioSequence> audioSequence = std::static_pointer_cast<AudioSequence>(resource); + ResourceVersionFactory::ParseFileBinary(reader, audioSequence); + + audioSequence->sequence.seqDataSize = reader->ReadInt32(); + audioSequence->sequenceData.reserve(audioSequence->sequence.seqDataSize); + for (uint32_t i = 0; i < audioSequence->sequence.seqDataSize; i++) { + audioSequence->sequenceData.push_back(reader->ReadChar()); + } + audioSequence->sequence.seqData = audioSequence->sequenceData.data(); + + audioSequence->sequence.seqNumber = reader->ReadUByte(); + audioSequence->sequence.medium = reader->ReadUByte(); + audioSequence->sequence.cachePolicy = reader->ReadUByte(); + + audioSequence->sequence.numFonts = reader->ReadUInt32(); + for (uint32_t i = 0; i < 16; i++) { + audioSequence->sequence.fonts[i] = 0; + } + for (uint32_t i = 0; i < audioSequence->sequence.numFonts; i++) { + audioSequence->sequence.fonts[i] = reader->ReadUByte(); + } +} +} // namespace LUS diff --git a/mm/2s2h/resource/importer/AudioSequenceFactory.h b/mm/2s2h/resource/importer/AudioSequenceFactory.h new file mode 100644 index 000000000..12b3809aa --- /dev/null +++ b/mm/2s2h/resource/importer/AudioSequenceFactory.h @@ -0,0 +1,19 @@ +#pragma once + +#include "Resource.h" +#include "ResourceFactory.h" + +namespace LUS { +class AudioSequenceFactory : public ResourceFactory +{ + public: + std::shared_ptr<IResource> + ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) override; +}; + +class AudioSequenceFactoryV0 : public ResourceVersionFactory +{ + public: + void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/importer/AudioSoundFontFactory.cpp b/mm/2s2h/resource/importer/AudioSoundFontFactory.cpp new file mode 100644 index 000000000..4ccb7edad --- /dev/null +++ b/mm/2s2h/resource/importer/AudioSoundFontFactory.cpp @@ -0,0 +1,190 @@ +#include "2s2h/resource/importer/AudioSoundFontFactory.h" +#include "2s2h/resource/type/AudioSoundFont.h" +#include "spdlog/spdlog.h" +#include "libultraship/libultraship.h" + +namespace LUS { +std::shared_ptr<IResource> +AudioSoundFontFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) { + auto resource = std::make_shared<AudioSoundFont>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 2: + factory = std::make_shared<AudioSoundFontFactoryV0>(); + break; + } + + if (factory == nullptr) + { + SPDLOG_ERROR("Failed to load AudioSoundFont with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileBinary(reader, resource); + + return resource; +} + +void LUS::AudioSoundFontFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader, + std::shared_ptr<IResource> resource) { + std::shared_ptr<AudioSoundFont> audioSoundFont = std::static_pointer_cast<AudioSoundFont>(resource); + ResourceVersionFactory::ParseFileBinary(reader, audioSoundFont); + + audioSoundFont->soundFont.fntIndex = reader->ReadInt32(); + audioSoundFont->medium = reader->ReadInt8(); + audioSoundFont->cachePolicy = reader->ReadInt8(); + + audioSoundFont->data1 = reader->ReadUInt16(); + audioSoundFont->soundFont.sampleBankId1 = audioSoundFont->data1 >> 8; + audioSoundFont->soundFont.sampleBankId2 = audioSoundFont->data1 & 0xFF; + + audioSoundFont->data2 = reader->ReadUInt16(); + audioSoundFont->data3 = reader->ReadUInt16(); + + uint32_t drumCount = reader->ReadUInt32(); + audioSoundFont->soundFont.numDrums = drumCount; + + uint32_t instrumentCount = reader->ReadUInt32(); + audioSoundFont->soundFont.numInstruments = instrumentCount; + + uint32_t soundEffectCount = reader->ReadUInt32(); + audioSoundFont->soundFont.numSfx = soundEffectCount; + + // 🥁 DRUMS 🥁 + audioSoundFont->drums.reserve(audioSoundFont->soundFont.numDrums); + audioSoundFont->drumAddresses.reserve(audioSoundFont->soundFont.numDrums); + for (uint32_t i = 0; i < audioSoundFont->soundFont.numDrums; i++) { + Drum drum; + drum.releaseRate = reader->ReadUByte(); + drum.pan = reader->ReadUByte(); + drum.loaded = reader->ReadUByte(); + drum.loaded = 0; // this was always getting set to zero in ResourceMgr_LoadAudioSoundFont + + uint32_t envelopeCount = reader->ReadUInt32(); + audioSoundFont->drumEnvelopeCounts.push_back(envelopeCount); + std::vector<AdsrEnvelope> drumEnvelopes; + drumEnvelopes.reserve(audioSoundFont->drumEnvelopeCounts[i]); + for (uint32_t j = 0; j < audioSoundFont->drumEnvelopeCounts.back(); j++) { + AdsrEnvelope env; + + int16_t delay = reader->ReadInt16(); + int16_t arg = reader->ReadInt16(); + + env.delay = BE16SWAP(delay); + env.arg = BE16SWAP(arg); + + drumEnvelopes.push_back(env); + } + audioSoundFont->drumEnvelopeArrays.push_back(drumEnvelopes); + drum.envelope = audioSoundFont->drumEnvelopeArrays.back().data(); + + bool hasSample = reader->ReadInt8(); + std::string sampleFileName = reader->ReadString(); + drum.sound.tuning = reader->ReadFloat(); + + if (sampleFileName.empty()) { + drum.sound.sample = nullptr; + } else { + auto res = LUS::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(sampleFileName.c_str()); + drum.sound.sample = static_cast<Sample*>(res ? res->GetRawPointer() : nullptr); + } + + audioSoundFont->drums.push_back(drum); + audioSoundFont->drumAddresses.push_back(&audioSoundFont->drums.back()); + } + audioSoundFont->soundFont.drums = audioSoundFont->drumAddresses.data(); + + // 🎺🎻🎷🎸🎹 INSTRUMENTS 🎹🎸🎷🎻🎺 + audioSoundFont->instruments.reserve(audioSoundFont->soundFont.numInstruments); + for (uint32_t i = 0; i < audioSoundFont->soundFont.numInstruments; i++) { + Instrument instrument; + + uint8_t isValidEntry = reader->ReadUByte(); + instrument.loaded = reader->ReadUByte(); + instrument.loaded = 0; // this was always getting set to zero in ResourceMgr_LoadAudioSoundFont + + instrument.normalRangeLo = reader->ReadUByte(); + instrument.normalRangeHi = reader->ReadUByte(); + instrument.releaseRate = reader->ReadUByte(); + + uint32_t envelopeCount = reader->ReadInt32(); + audioSoundFont->instrumentEnvelopeCounts.push_back(envelopeCount); + std::vector<AdsrEnvelope> instrumentEnvelopes; + for (uint32_t j = 0; j < audioSoundFont->instrumentEnvelopeCounts.back(); j++) { + AdsrEnvelope env; + + int16_t delay = reader->ReadInt16(); + int16_t arg = reader->ReadInt16(); + + env.delay = BE16SWAP(delay); + env.arg = BE16SWAP(arg); + + instrumentEnvelopes.push_back(env); + } + audioSoundFont->instrumentEnvelopeArrays.push_back(instrumentEnvelopes); + instrument.envelope = audioSoundFont->instrumentEnvelopeArrays.back().data(); + + bool hasLowNoteSoundFontEntry = reader->ReadInt8(); + if (hasLowNoteSoundFontEntry) { + bool hasSampleRef = reader->ReadInt8(); + std::string sampleFileName = reader->ReadString(); + instrument.lowNotesSound.tuning = reader->ReadFloat(); + auto res = LUS::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(sampleFileName.c_str()); + instrument.lowNotesSound.sample = static_cast<Sample*>(res ? res->GetRawPointer() : nullptr); + } else { + instrument.lowNotesSound.sample = nullptr; + instrument.lowNotesSound.tuning = 0; + } + + bool hasNormalNoteSoundFontEntry = reader->ReadInt8(); + if (hasNormalNoteSoundFontEntry) { + bool hasSampleRef = reader->ReadInt8(); + std::string sampleFileName = reader->ReadString(); + instrument.normalNotesSound.tuning = reader->ReadFloat(); + auto res = LUS::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(sampleFileName.c_str()); + instrument.normalNotesSound.sample = static_cast<Sample*>(res ? res->GetRawPointer() : nullptr); + } else { + instrument.normalNotesSound.sample = nullptr; + instrument.normalNotesSound.tuning = 0; + } + + bool hasHighNoteSoundFontEntry = reader->ReadInt8(); + if (hasHighNoteSoundFontEntry) { + bool hasSampleRef = reader->ReadInt8(); + std::string sampleFileName = reader->ReadString(); + instrument.highNotesSound.tuning = reader->ReadFloat(); + auto res = LUS::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(sampleFileName.c_str()); + instrument.highNotesSound.sample = static_cast<Sample*>(res ? res->GetRawPointer() : nullptr); + } else { + instrument.highNotesSound.sample = nullptr; + instrument.highNotesSound.tuning = 0; + } + + + audioSoundFont->instruments.push_back(instrument); + audioSoundFont->instrumentAddresses.push_back(isValidEntry ? + &audioSoundFont->instruments.back() : + nullptr); + } + audioSoundFont->soundFont.instruments = audioSoundFont->instrumentAddresses.data(); + + // 🔊 SOUND EFFECTS 🔊 + audioSoundFont->soundEffects.reserve(audioSoundFont->soundFont.numSfx); + for (uint32_t i = 0; i < audioSoundFont->soundFont.numSfx; i++) { + SoundFontSound soundEffect; + + bool hasSFEntry = reader->ReadInt8(); + if (hasSFEntry) { + bool hasSampleRef = reader->ReadInt8(); + std::string sampleFileName = reader->ReadString(); + soundEffect.tuning = reader->ReadFloat(); + auto res = LUS::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(sampleFileName.c_str()); + soundEffect.sample = static_cast<Sample*>(res ? res->GetRawPointer() : nullptr); + } + + audioSoundFont->soundEffects.push_back(soundEffect); + } + audioSoundFont->soundFont.soundEffects = audioSoundFont->soundEffects.data(); +} +} // namespace LUS diff --git a/mm/2s2h/resource/importer/AudioSoundFontFactory.h b/mm/2s2h/resource/importer/AudioSoundFontFactory.h new file mode 100644 index 000000000..7dd5bc0d5 --- /dev/null +++ b/mm/2s2h/resource/importer/AudioSoundFontFactory.h @@ -0,0 +1,19 @@ +#pragma once + +#include "Resource.h" +#include "ResourceFactory.h" + +namespace LUS { +class AudioSoundFontFactory : public ResourceFactory +{ + public: + std::shared_ptr<IResource> + ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) override; +}; + +class AudioSoundFontFactoryV0 : public ResourceVersionFactory +{ + public: + void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/importer/BackgroundFactory.cpp b/mm/2s2h/resource/importer/BackgroundFactory.cpp new file mode 100644 index 000000000..6acc7737c --- /dev/null +++ b/mm/2s2h/resource/importer/BackgroundFactory.cpp @@ -0,0 +1,39 @@ +#include "2s2h/resource/importer/BackgroundFactory.h" +#include "2s2h/resource/type/Background.h" +#include "spdlog/spdlog.h" + +namespace LUS { +std::shared_ptr<IResource> +BackgroundFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) { + auto resource = std::make_shared<Background>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 0: + factory = std::make_shared<BackgroundFactoryV0>(); + break; + } + + if (factory == nullptr) { + SPDLOG_ERROR("Failed to load Background with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileBinary(reader, resource); + + return resource; +} + +void BackgroundFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) { + std::shared_ptr<Background> background = std::static_pointer_cast<Background>(resource); + ResourceVersionFactory::ParseFileBinary(reader, background); + + uint32_t dataSize = reader->ReadUInt32(); + + background->Data.reserve(dataSize); + + for (uint32_t i = 0; i < dataSize; i++) { + background->Data.push_back(reader->ReadUByte()); + } +} +} // namespace LUS diff --git a/mm/2s2h/resource/importer/BackgroundFactory.h b/mm/2s2h/resource/importer/BackgroundFactory.h new file mode 100644 index 000000000..9767fdf8b --- /dev/null +++ b/mm/2s2h/resource/importer/BackgroundFactory.h @@ -0,0 +1,17 @@ +#pragma once + +#include "resource/Resource.h" +#include "resource/ResourceFactory.h" + +namespace LUS { +class BackgroundFactory : public ResourceFactory { + public: + std::shared_ptr<IResource> + ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) override; +}; + +class BackgroundFactoryV0 : public ResourceVersionFactory { + public: + void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/importer/CollisionHeaderFactory.cpp b/mm/2s2h/resource/importer/CollisionHeaderFactory.cpp new file mode 100644 index 000000000..4b5b45f0d --- /dev/null +++ b/mm/2s2h/resource/importer/CollisionHeaderFactory.cpp @@ -0,0 +1,142 @@ +#include "2s2h/resource/importer/CollisionHeaderFactory.h" +#include "2s2h/resource/type/CollisionHeader.h" +#include "spdlog/spdlog.h" + +namespace LUS { +std::shared_ptr<IResource> +CollisionHeaderFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) { + auto resource = std::make_shared<CollisionHeader>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 0: + factory = std::make_shared<CollisionHeaderFactoryV0>(); + break; + } + + if (factory == nullptr) { + SPDLOG_ERROR("Failed to load Collision Header with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileBinary(reader, resource); + + return resource; +} + +void LUS::CollisionHeaderFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader, + std::shared_ptr<IResource> resource) +{ + std::shared_ptr<CollisionHeader> collisionHeader = std::static_pointer_cast<CollisionHeader>(resource); + ResourceVersionFactory::ParseFileBinary(reader, collisionHeader); + + collisionHeader->collisionHeaderData.minBounds.x = reader->ReadInt16(); + collisionHeader->collisionHeaderData.minBounds.y = reader->ReadInt16(); + collisionHeader->collisionHeaderData.minBounds.z = reader->ReadInt16(); + + collisionHeader->collisionHeaderData.maxBounds.x = reader->ReadInt16(); + collisionHeader->collisionHeaderData.maxBounds.y = reader->ReadInt16(); + collisionHeader->collisionHeaderData.maxBounds.z = reader->ReadInt16(); + + collisionHeader->collisionHeaderData.numVertices = reader->ReadInt32(); + collisionHeader->vertices.reserve(collisionHeader->collisionHeaderData.numVertices); + for (int32_t i = 0; i < collisionHeader->collisionHeaderData.numVertices; i++) { + Vec3s vtx; + vtx.x = reader->ReadInt16(); + vtx.y = reader->ReadInt16(); + vtx.z = reader->ReadInt16(); + collisionHeader->vertices.push_back(vtx); + } + collisionHeader->collisionHeaderData.vtxList = collisionHeader->vertices.data(); + + collisionHeader->collisionHeaderData.numPolygons = reader->ReadUInt32(); + collisionHeader->polygons.reserve(collisionHeader->collisionHeaderData.numPolygons); + for (uint32_t i = 0; i < collisionHeader->collisionHeaderData.numPolygons; i++) { + CollisionPoly polygon; + + polygon.type = reader->ReadUInt16(); + + polygon.flags_vIA = reader->ReadUInt16(); + polygon.flags_vIB = reader->ReadUInt16(); + polygon.vIC = reader->ReadUInt16(); + + polygon.normal.x = reader->ReadUInt16(); + polygon.normal.y = reader->ReadUInt16(); + polygon.normal.z = reader->ReadUInt16(); + + polygon.dist = reader->ReadUInt16(); + + collisionHeader->polygons.push_back(polygon); + + } + collisionHeader->collisionHeaderData.polyList = collisionHeader->polygons.data(); + + collisionHeader->surfaceTypesCount = reader->ReadUInt32(); + collisionHeader->surfaceTypes.reserve(collisionHeader->surfaceTypesCount); + for (uint32_t i = 0; i < collisionHeader->surfaceTypesCount; i++) { + SurfaceType surfaceType; + + surfaceType.data[1] = reader->ReadUInt32(); + surfaceType.data[0] = reader->ReadUInt32(); + + collisionHeader->surfaceTypes.push_back(surfaceType); + } + collisionHeader->collisionHeaderData.surfaceTypeList = collisionHeader->surfaceTypes.data(); + + collisionHeader->camDataCount = reader->ReadUInt32(); + collisionHeader->camData.reserve(collisionHeader->camDataCount); + collisionHeader->camPosDataIndices.reserve(collisionHeader->camDataCount); + for (uint32_t i = 0; i < collisionHeader->camDataCount; i++) { + CamData camDataEntry; + camDataEntry.cameraSType = reader->ReadUInt16(); + camDataEntry.numCameras = reader->ReadInt16(); + collisionHeader->camData.push_back(camDataEntry); + + int32_t camPosDataIdx = reader->ReadInt32(); + collisionHeader->camPosDataIndices.push_back(camPosDataIdx); + } + + collisionHeader->camPosCount = reader->ReadInt32(); + collisionHeader->camPosData.reserve(collisionHeader->camPosCount); + for (int32_t i = 0; i < collisionHeader->camPosCount; i++) { + Vec3s pos; + pos.x = reader->ReadInt16(); + pos.y = reader->ReadInt16(); + pos.z = reader->ReadInt16(); + collisionHeader->camPosData.push_back(pos); + } + + Vec3s zero; + zero.x = 0; + zero.y = 0; + zero.z = 0; + collisionHeader->camPosDataZero = zero; + + for (size_t i = 0; i < collisionHeader->camDataCount; i++) { + int32_t idx = collisionHeader->camPosDataIndices[i]; + + if (collisionHeader->camPosCount > 0) { + collisionHeader->camData[i].camPosData = &collisionHeader->camPosData[idx]; + } else { + collisionHeader->camData[i].camPosData = &collisionHeader->camPosDataZero; + } + } + collisionHeader->collisionHeaderData.cameraDataList = collisionHeader->camData.data(); + collisionHeader->collisionHeaderData.cameraDataListLen = collisionHeader->camDataCount; + + collisionHeader->collisionHeaderData.numWaterBoxes = reader->ReadInt32(); + collisionHeader->waterBoxes.reserve(collisionHeader->collisionHeaderData.numWaterBoxes); + for (int32_t i = 0; i < collisionHeader->collisionHeaderData.numWaterBoxes; i++) { + WaterBox waterBox; + waterBox.xMin = reader->ReadInt16(); + waterBox.ySurface = reader->ReadInt16(); + waterBox.zMin = reader->ReadInt16(); + waterBox.xLength = reader->ReadInt16(); + waterBox.zLength = reader->ReadInt16(); + waterBox.properties = reader->ReadInt32(); + + collisionHeader->waterBoxes.push_back(waterBox); + } + collisionHeader->collisionHeaderData.waterBoxes = collisionHeader->waterBoxes.data(); +} +} diff --git a/mm/2s2h/resource/importer/CollisionHeaderFactory.h b/mm/2s2h/resource/importer/CollisionHeaderFactory.h new file mode 100644 index 000000000..09d6ba4c5 --- /dev/null +++ b/mm/2s2h/resource/importer/CollisionHeaderFactory.h @@ -0,0 +1,17 @@ +#pragma once + +#include "Resource.h" +#include "ResourceFactory.h" + +namespace LUS { +class CollisionHeaderFactory : public ResourceFactory { + public: + std::shared_ptr<IResource> + ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) override; +}; + +class CollisionHeaderFactoryV0 : public ResourceVersionFactory { + public: + void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/importer/CutsceneFactory.cpp b/mm/2s2h/resource/importer/CutsceneFactory.cpp new file mode 100644 index 000000000..34c12ccc0 --- /dev/null +++ b/mm/2s2h/resource/importer/CutsceneFactory.cpp @@ -0,0 +1,918 @@ +#include "2s2h/resource/importer/CutsceneFactory.h" +#include "2s2h/resource/type/Cutscene.h" +#include "spdlog/spdlog.h" +// TODO headers +//extern "C" { +//#include "z64cutscene.h" +//} +typedef enum { + /* 0x00A */ CS_CMD_TEXT = 10, + /* 0x05A */ CS_CMD_CAMERA_SPLINE = 90, + /* 0x064 */ CS_CMD_ACTOR_CUE_100 = 100, + /* 0x065 */ CS_CMD_ACTOR_CUE_101, + /* 0x066 */ CS_CMD_ACTOR_CUE_102, + /* 0x067 */ CS_CMD_ACTOR_CUE_103, + /* 0x068 */ CS_CMD_ACTOR_CUE_104, + /* 0x069 */ CS_CMD_ACTOR_CUE_105, + /* 0x06A */ CS_CMD_ACTOR_CUE_106, + /* 0x06B */ CS_CMD_ACTOR_CUE_107, + /* 0x06C */ CS_CMD_ACTOR_CUE_108, + /* 0x06D */ CS_CMD_ACTOR_CUE_109, + /* 0x06E */ CS_CMD_ACTOR_CUE_110, + /* 0x06F */ CS_CMD_ACTOR_CUE_111, + /* 0x070 */ CS_CMD_ACTOR_CUE_112, + /* 0x071 */ CS_CMD_ACTOR_CUE_113, + /* 0x072 */ CS_CMD_ACTOR_CUE_114, + /* 0x073 */ CS_CMD_ACTOR_CUE_115, + /* 0x074 */ CS_CMD_ACTOR_CUE_116, + /* 0x075 */ CS_CMD_ACTOR_CUE_117, + /* 0x076 */ CS_CMD_ACTOR_CUE_118, + /* 0x077 */ CS_CMD_ACTOR_CUE_119, + /* 0x078 */ CS_CMD_ACTOR_CUE_120, + /* 0x079 */ CS_CMD_ACTOR_CUE_121, + /* 0x07A */ CS_CMD_ACTOR_CUE_122, + /* 0x07B */ CS_CMD_ACTOR_CUE_123, + /* 0x07C */ CS_CMD_ACTOR_CUE_124, + /* 0x07D */ CS_CMD_ACTOR_CUE_125, + /* 0x07E */ CS_CMD_ACTOR_CUE_126, + /* 0x07F */ CS_CMD_ACTOR_CUE_127, + /* 0x080 */ CS_CMD_ACTOR_CUE_128, + /* 0x081 */ CS_CMD_ACTOR_CUE_129, + /* 0x082 */ CS_CMD_ACTOR_CUE_130, + /* 0x083 */ CS_CMD_ACTOR_CUE_131, + /* 0x084 */ CS_CMD_ACTOR_CUE_132, + /* 0x085 */ CS_CMD_ACTOR_CUE_133, + /* 0x086 */ CS_CMD_ACTOR_CUE_134, + /* 0x087 */ CS_CMD_ACTOR_CUE_135, + /* 0x088 */ CS_CMD_ACTOR_CUE_136, + /* 0x089 */ CS_CMD_ACTOR_CUE_137, + /* 0x08A */ CS_CMD_ACTOR_CUE_138, + /* 0x08B */ CS_CMD_ACTOR_CUE_139, + /* 0x08C */ CS_CMD_ACTOR_CUE_140, + /* 0x08D */ CS_CMD_ACTOR_CUE_141, + /* 0x08E */ CS_CMD_ACTOR_CUE_142, + /* 0x08F */ CS_CMD_ACTOR_CUE_143, + /* 0x090 */ CS_CMD_ACTOR_CUE_144, + /* 0x091 */ CS_CMD_ACTOR_CUE_145, + /* 0x092 */ CS_CMD_ACTOR_CUE_146, + /* 0x093 */ CS_CMD_ACTOR_CUE_147, + /* 0x094 */ CS_CMD_ACTOR_CUE_148, + /* 0x095 */ CS_CMD_ACTOR_CUE_149, + /* 0x096 */ CS_CMD_MISC, + /* 0x097 */ CS_CMD_LIGHT_SETTING, + /* 0x098 */ CS_CMD_TRANSITION, + /* 0x099 */ CS_CMD_MOTION_BLUR, + /* 0x09A */ CS_CMD_GIVE_TATL, + /* 0x09B */ CS_CMD_TRANSITION_GENERAL, + /* 0x09C */ CS_CMD_FADE_OUT_SEQ, + /* 0x09D */ CS_CMD_TIME, + /* 0x0C8 */ CS_CMD_PLAYER_CUE = 200, + /* 0x0C9 */ CS_CMD_ACTOR_CUE_201, + /* 0x0FA */ CS_CMD_UNK_DATA_FA = 0xFA, + /* 0x0FE */ CS_CMD_UNK_DATA_FE = 0xFE, + /* 0x0FF */ CS_CMD_UNK_DATA_FF, + /* 0x100 */ CS_CMD_UNK_DATA_100, + /* 0x101 */ CS_CMD_UNK_DATA_101, + /* 0x102 */ CS_CMD_UNK_DATA_102, + /* 0x103 */ CS_CMD_UNK_DATA_103, + /* 0x104 */ CS_CMD_UNK_DATA_104, + /* 0x105 */ CS_CMD_UNK_DATA_105, + /* 0x108 */ CS_CMD_UNK_DATA_108 = 0x108, + /* 0x109 */ CS_CMD_UNK_DATA_109, + /* 0x12C */ CS_CMD_START_SEQ = 300, + /* 0x12D */ CS_CMD_STOP_SEQ, + /* 0x12E */ CS_CMD_START_AMBIENCE, + /* 0x12F */ CS_CMD_FADE_OUT_AMBIENCE, + /* 0x130 */ CS_CMD_SFX_REVERB_INDEX_2, + /* 0x131 */ CS_CMD_SFX_REVERB_INDEX_1, + /* 0x132 */ CS_CMD_MODIFY_SEQ, + /* 0x15E */ CS_CMD_DESTINATION = 350, + /* 0x15F */ CS_CMD_CHOOSE_CREDITS_SCENES, + /* 0x190 */ CS_CMD_RUMBLE = 400, + /* 0x1C2 */ CS_CMD_ACTOR_CUE_450 = 450, + /* 0x1C3 */ CS_CMD_ACTOR_CUE_451, + /* 0x1C4 */ CS_CMD_ACTOR_CUE_452, + /* 0x1C5 */ CS_CMD_ACTOR_CUE_453, + /* 0x1C6 */ CS_CMD_ACTOR_CUE_454, + /* 0x1C7 */ CS_CMD_ACTOR_CUE_455, + /* 0x1C8 */ CS_CMD_ACTOR_CUE_456, + /* 0x1C9 */ CS_CMD_ACTOR_CUE_457, + /* 0x1CA */ CS_CMD_ACTOR_CUE_458, + /* 0x1CB */ CS_CMD_ACTOR_CUE_459, + /* 0x1CC */ CS_CMD_ACTOR_CUE_460, + /* 0x1CD */ CS_CMD_ACTOR_CUE_461, + /* 0x1CE */ CS_CMD_ACTOR_CUE_462, + /* 0x1CF */ CS_CMD_ACTOR_CUE_463, + /* 0x1D0 */ CS_CMD_ACTOR_CUE_464, + /* 0x1D1 */ CS_CMD_ACTOR_CUE_465, + /* 0x1D2 */ CS_CMD_ACTOR_CUE_466, + /* 0x1D3 */ CS_CMD_ACTOR_CUE_467, + /* 0x1D4 */ CS_CMD_ACTOR_CUE_468, + /* 0x1D5 */ CS_CMD_ACTOR_CUE_469, + /* 0x1D6 */ CS_CMD_ACTOR_CUE_470, + /* 0x1D7 */ CS_CMD_ACTOR_CUE_471, + /* 0x1D8 */ CS_CMD_ACTOR_CUE_472, + /* 0x1D9 */ CS_CMD_ACTOR_CUE_473, + /* 0x1DA */ CS_CMD_ACTOR_CUE_474, + /* 0x1DB */ CS_CMD_ACTOR_CUE_475, + /* 0x1DC */ CS_CMD_ACTOR_CUE_476, + /* 0x1DD */ CS_CMD_ACTOR_CUE_477, + /* 0x1DE */ CS_CMD_ACTOR_CUE_478, + /* 0x1DF */ CS_CMD_ACTOR_CUE_479, + /* 0x1E0 */ CS_CMD_ACTOR_CUE_480, + /* 0x1E1 */ CS_CMD_ACTOR_CUE_481, + /* 0x1E2 */ CS_CMD_ACTOR_CUE_482, + /* 0x1E3 */ CS_CMD_ACTOR_CUE_483, + /* 0x1E4 */ CS_CMD_ACTOR_CUE_484, + /* 0x1E5 */ CS_CMD_ACTOR_CUE_485, + /* 0x1E6 */ CS_CMD_ACTOR_CUE_486, + /* 0x1E7 */ CS_CMD_ACTOR_CUE_487, + /* 0x1E8 */ CS_CMD_ACTOR_CUE_488, + /* 0x1E9 */ CS_CMD_ACTOR_CUE_489, + /* 0x1EA */ CS_CMD_ACTOR_CUE_490, + /* 0x1EB */ CS_CMD_ACTOR_CUE_491, + /* 0x1EC */ CS_CMD_ACTOR_CUE_492, + /* 0x1ED */ CS_CMD_ACTOR_CUE_493, + /* 0x1EE */ CS_CMD_ACTOR_CUE_494, + /* 0x1EF */ CS_CMD_ACTOR_CUE_495, + /* 0x1F0 */ CS_CMD_ACTOR_CUE_496, + /* 0x1F1 */ CS_CMD_ACTOR_CUE_497, + /* 0x1F2 */ CS_CMD_ACTOR_CUE_498, + /* 0x1F3 */ CS_CMD_ACTOR_CUE_499, + /* 0x1F4 */ CS_CMD_ACTOR_CUE_500, + /* 0x1F5 */ CS_CMD_ACTOR_CUE_501, + /* 0x1F6 */ CS_CMD_ACTOR_CUE_502, + /* 0x1F7 */ CS_CMD_ACTOR_CUE_503, + /* 0x1F8 */ CS_CMD_ACTOR_CUE_504, + /* 0x1F9 */ CS_CMD_ACTOR_CUE_SOTCS, // Song of Time Cutscenes (Double SoT, Three-Day Reset SoT) + /* 0x1FA */ CS_CMD_ACTOR_CUE_506, + /* 0x1FB */ CS_CMD_ACTOR_CUE_507, + /* 0x1FC */ CS_CMD_ACTOR_CUE_508, + /* 0x1FD */ CS_CMD_ACTOR_CUE_509, + /* 0x1FE */ CS_CMD_ACTOR_CUE_510, + /* 0x1FF */ CS_CMD_ACTOR_CUE_511, + /* 0x200 */ CS_CMD_ACTOR_CUE_512, + /* 0x201 */ CS_CMD_ACTOR_CUE_513, + /* 0x202 */ CS_CMD_ACTOR_CUE_514, + /* 0x203 */ CS_CMD_ACTOR_CUE_515, + /* 0x204 */ CS_CMD_ACTOR_CUE_516, + /* 0x205 */ CS_CMD_ACTOR_CUE_517, + /* 0x206 */ CS_CMD_ACTOR_CUE_518, + /* 0x207 */ CS_CMD_ACTOR_CUE_519, + /* 0x208 */ CS_CMD_ACTOR_CUE_520, + /* 0x209 */ CS_CMD_ACTOR_CUE_521, + /* 0x20A */ CS_CMD_ACTOR_CUE_522, + /* 0x20B */ CS_CMD_ACTOR_CUE_523, + /* 0x20C */ CS_CMD_ACTOR_CUE_524, + /* 0x20D */ CS_CMD_ACTOR_CUE_525, + /* 0x20E */ CS_CMD_ACTOR_CUE_526, + /* 0x20F */ CS_CMD_ACTOR_CUE_527, + /* 0x210 */ CS_CMD_ACTOR_CUE_528, + /* 0x211 */ CS_CMD_ACTOR_CUE_529, + /* 0x212 */ CS_CMD_ACTOR_CUE_530, + /* 0x213 */ CS_CMD_ACTOR_CUE_531, + /* 0x214 */ CS_CMD_ACTOR_CUE_532, + /* 0x215 */ CS_CMD_ACTOR_CUE_533, + /* 0x216 */ CS_CMD_ACTOR_CUE_534, + /* 0x217 */ CS_CMD_ACTOR_CUE_535, + /* 0x218 */ CS_CMD_ACTOR_CUE_536, + /* 0x219 */ CS_CMD_ACTOR_CUE_537, + /* 0x21A */ CS_CMD_ACTOR_CUE_538, + /* 0x21B */ CS_CMD_ACTOR_CUE_539, + /* 0x21C */ CS_CMD_ACTOR_CUE_540, + /* 0x21D */ CS_CMD_ACTOR_CUE_541, + /* 0x21E */ CS_CMD_ACTOR_CUE_542, + /* 0x21F */ CS_CMD_ACTOR_CUE_543, + /* 0x220 */ CS_CMD_ACTOR_CUE_544, + /* 0x221 */ CS_CMD_ACTOR_CUE_545, + /* 0x222 */ CS_CMD_ACTOR_CUE_546, + /* 0x223 */ CS_CMD_ACTOR_CUE_547, + /* 0x224 */ CS_CMD_ACTOR_CUE_548, + /* 0x225 */ CS_CMD_ACTOR_CUE_549, + /* 0x226 */ CS_CMD_ACTOR_CUE_550, + /* 0x227 */ CS_CMD_ACTOR_CUE_551, + /* 0x228 */ CS_CMD_ACTOR_CUE_552, + /* 0x229 */ CS_CMD_ACTOR_CUE_553, + /* 0x22A */ CS_CMD_ACTOR_CUE_554, + /* 0x22B */ CS_CMD_ACTOR_CUE_555, + /* 0x22C */ CS_CMD_ACTOR_CUE_556, + /* 0x22D */ CS_CMD_ACTOR_CUE_557, + /* 0x22E */ CS_CMD_ACTOR_CUE_558, + /* 0x22F */ CS_CMD_ACTOR_CUE_559, + /* 0x230 */ CS_CMD_ACTOR_CUE_560, + /* 0x231 */ CS_CMD_ACTOR_CUE_561, + /* 0x232 */ CS_CMD_ACTOR_CUE_562, + /* 0x233 */ CS_CMD_ACTOR_CUE_563, + /* 0x234 */ CS_CMD_ACTOR_CUE_564, + /* 0x235 */ CS_CMD_ACTOR_CUE_565, + /* 0x236 */ CS_CMD_ACTOR_CUE_566, + /* 0x237 */ CS_CMD_ACTOR_CUE_567, + /* 0x238 */ CS_CMD_ACTOR_CUE_568, + /* 0x239 */ CS_CMD_ACTOR_CUE_569, + /* 0x23A */ CS_CMD_ACTOR_CUE_570, + /* 0x23B */ CS_CMD_ACTOR_CUE_571, + /* 0x23C */ CS_CMD_ACTOR_CUE_572, + /* 0x23D */ CS_CMD_ACTOR_CUE_573, + /* 0x23E */ CS_CMD_ACTOR_CUE_574, + /* 0x23F */ CS_CMD_ACTOR_CUE_575, + /* 0x240 */ CS_CMD_ACTOR_CUE_576, + /* 0x241 */ CS_CMD_ACTOR_CUE_577, + /* 0x242 */ CS_CMD_ACTOR_CUE_578, + /* 0x243 */ CS_CMD_ACTOR_CUE_579, + /* 0x244 */ CS_CMD_ACTOR_CUE_580, + /* 0x245 */ CS_CMD_ACTOR_CUE_581, + /* 0x246 */ CS_CMD_ACTOR_CUE_582, + /* 0x247 */ CS_CMD_ACTOR_CUE_583, + /* 0x248 */ CS_CMD_ACTOR_CUE_584, + /* 0x249 */ CS_CMD_ACTOR_CUE_585, + /* 0x24A */ CS_CMD_ACTOR_CUE_586, + /* 0x24B */ CS_CMD_ACTOR_CUE_587, + /* 0x24C */ CS_CMD_ACTOR_CUE_588, + /* 0x24D */ CS_CMD_ACTOR_CUE_589, + /* 0x24E */ CS_CMD_ACTOR_CUE_590, + /* 0x24F */ CS_CMD_ACTOR_CUE_591, + /* 0x250 */ CS_CMD_ACTOR_CUE_592, + /* 0x251 */ CS_CMD_ACTOR_CUE_593, + /* 0x252 */ CS_CMD_ACTOR_CUE_594, + /* 0x253 */ CS_CMD_ACTOR_CUE_595, + /* 0x254 */ CS_CMD_ACTOR_CUE_596, + /* 0x255 */ CS_CMD_ACTOR_CUE_597, + /* 0x256 */ CS_CMD_ACTOR_CUE_598, + /* 0x257 */ CS_CMD_ACTOR_CUE_599, + /* -2 */ CS_CMD_ACTOR_CUE_POST_PROCESS = 0xFFFFFFFE, + /* -1 */ CS_CAM_STOP // OoT Remnant +} CutsceneCmd; + +namespace LUS { +std::shared_ptr<IResource> +CutsceneFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) { + auto resource = std::make_shared<Cutscene>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 0: + factory = std::make_shared<CutsceneFactoryV0>(); + break; + } + + if (factory == nullptr) { + SPDLOG_ERROR("Failed to load Cutscene with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileBinary(reader, resource); + + return resource; +} + +static inline uint32_t read_CMD_BBBB(std::shared_ptr<BinaryReader> reader) { + uint32_t v; + reader->Read((char*)&v, sizeof(uint32_t)); + + return v; +} + +static inline uint32_t read_CMD_BBH(std::shared_ptr<BinaryReader> reader) { + uint32_t v; + reader->Read((char*)&v, sizeof(uint32_t)); + + // swap the half word to match endianness + if (reader->GetEndianness() != LUS::Endianness::Native) { + uint8_t* b = (uint8_t*)&v; + uint8_t tmp = b[2]; + b[2] = b[3]; + b[3] = tmp; + } + + return v; +} + +static inline uint32_t read_CMD_HBB(std::shared_ptr<BinaryReader> reader) { + uint32_t v; + reader->Read((char*)&v, sizeof(uint32_t)); + + // swap the half word to match endianness + if (reader->GetEndianness() != LUS::Endianness::Native) { + uint8_t* b = (uint8_t*)&v; + uint8_t tmp = b[0]; + b[0] = b[1]; + b[1] = tmp; + } + + return v; +} + +static inline uint32_t read_CMD_HH(std::shared_ptr<BinaryReader> reader) { + uint32_t v; + reader->Read((char*)&v, sizeof(uint32_t)); + + // swap the half words to match endianness + if (reader->GetEndianness() != LUS::Endianness::Native) { + uint8_t* b = (uint8_t*)&v; + uint8_t tmp = b[0]; + b[0] = b[1]; + b[1] = tmp; + tmp = b[2]; + b[2] = b[3]; + b[3] = tmp; + } + + return v; +} + +void LUS::CutsceneFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader, + std::shared_ptr<IResource> resource) +{ + std::shared_ptr<Cutscene> cutscene = std::static_pointer_cast<Cutscene>(resource); + ResourceVersionFactory::ParseFileBinary(reader, cutscene); + + uint32_t numEntries = reader->ReadUInt32(); + cutscene->commands.reserve(numEntries); + + cutscene->numCommands = reader->ReadUInt32(); + cutscene->commands.push_back(cutscene->numCommands); + + cutscene->endFrame = reader->ReadUInt32(); + cutscene->commands.push_back(cutscene->endFrame); + + // BENTODO detect the game + ParseFileBinaryMM(reader, cutscene); +} + +void LUS::CutsceneFactoryV0::ParseFileBinaryOoT(std::shared_ptr<BinaryReader> reader, std::shared_ptr<Cutscene> cutscene) { + while (true) { + uint32_t commandId = reader->ReadUInt32(); + cutscene->commands.push_back(commandId); + + switch (commandId) { + case (uint32_t)CutsceneCommands::SetCameraPos: { + cutscene->commands.push_back(read_CMD_HH(reader)); + cutscene->commands.push_back(read_CMD_HH(reader)); + + while (true) { + uint32_t val = read_CMD_BBH(reader); + int8_t continueFlag = ((int8_t*)&val)[0]; + + cutscene->commands.push_back(val); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(read_CMD_HH(reader)); + cutscene->commands.push_back(read_CMD_HH(reader)); + + if (continueFlag == -1) { + break; + } + } + } break; + case (uint32_t)CutsceneCommands::SetCameraFocus: { + cutscene->commands.push_back(read_CMD_HH(reader)); + cutscene->commands.push_back(read_CMD_HH(reader)); + + while (true) { + uint32_t val = read_CMD_BBH(reader); + int8_t continueFlag = ((int8_t*)&val)[0]; + + cutscene->commands.push_back(val); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(read_CMD_HH(reader)); + cutscene->commands.push_back(read_CMD_HH(reader)); + + if (continueFlag == -1) { + break; + } + } + break; + } + case (uint32_t)CutsceneCommands::SpecialAction: { + uint32_t size = reader->ReadUInt32(); + cutscene->commands.push_back(size); + + for (uint32_t i = 0; i < size; i++) { + cutscene->commands.push_back(read_CMD_HH(reader)); + cutscene->commands.push_back(read_CMD_HH(reader)); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + } + break; + } + case (uint32_t)CutsceneCommands::SetLighting: { + uint32_t size = reader->ReadUInt32(); + cutscene->commands.push_back(size); + + for (uint32_t i = 0; i < size; i++) { + cutscene->commands.push_back(read_CMD_HH(reader)); + cutscene->commands.push_back(read_CMD_HH(reader)); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + } + break; + } + case (uint32_t)CutsceneCommands::SetCameraPosLink: { + cutscene->commands.push_back(read_CMD_HH(reader)); + cutscene->commands.push_back(read_CMD_HH(reader)); + + while (true) { + uint32_t val = read_CMD_BBH(reader); + int8_t continueFlag = ((int8_t*)&val)[0]; + + cutscene->commands.push_back(val); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(read_CMD_HH(reader)); + cutscene->commands.push_back(read_CMD_HH(reader)); + + if (continueFlag == -1) { + break; + } + } + break; + } + case (uint32_t)CutsceneCommands::SetCameraFocusLink: { + cutscene->commands.push_back(read_CMD_HH(reader)); + cutscene->commands.push_back(read_CMD_HH(reader)); + + while (true) { + uint32_t val = read_CMD_BBH(reader); + int8_t continueFlag = ((int8_t*)&val)[0]; + + cutscene->commands.push_back(val); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(read_CMD_HH(reader)); + cutscene->commands.push_back(read_CMD_HH(reader)); + + if (continueFlag == -1) { + break; + } + } + break; + } + case (uint32_t)CutsceneCommands::Cmd09: { + uint32_t size = reader->ReadUInt32(); + cutscene->commands.push_back(size); + + for (uint32_t i = 0; i < size; i++) { + cutscene->commands.push_back(read_CMD_HH(reader)); + cutscene->commands.push_back(read_CMD_HBB(reader)); + cutscene->commands.push_back(read_CMD_BBH(reader)); + } + break; + } + case 0x15: + case (uint32_t)CutsceneCommands::Unknown: { + uint32_t size = reader->ReadUInt32(); + cutscene->commands.push_back(size); + + for (uint32_t i = 0; i < size; i++) { + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + } + } break; + case (uint32_t)CutsceneCommands::Textbox: { + uint32_t size = reader->ReadUInt32(); + cutscene->commands.push_back(size); + + for (uint32_t i = 0; i < size; i++) { + cutscene->commands.push_back(read_CMD_HH(reader)); + cutscene->commands.push_back(read_CMD_HH(reader)); + cutscene->commands.push_back(read_CMD_HH(reader)); + } + break; + } + case (uint32_t)CutsceneCommands::SetActorAction0: + case (uint32_t)CutsceneCommands::SetActorAction1: + case 17: + case 18: + case 23: + case 34: + case 39: + case 46: + case 76: + case 85: + case 93: + case 105: + case 107: + case 110: + case 119: + case 123: + case 138: + case 139: + case 144: + case (uint32_t)CutsceneCommands::SetActorAction2: + case 16: + case 24: + case 35: + case 40: + case 48: + case 64: + case 68: + case 70: + case 78: + case 80: + case 94: + case 116: + case 118: + case 120: + case 125: + case 131: + case 141: + case (uint32_t)CutsceneCommands::SetActorAction3: + case 36: + case 41: + case 50: + case 67: + case 69: + case 72: + case 74: + case 81: + case 106: + case 117: + case 121: + case 126: + case 132: + case (uint32_t)CutsceneCommands::SetActorAction4: + case 37: + case 42: + case 51: + case 53: + case 63: + case 65: + case 66: + case 75: + case 82: + case 108: + case 127: + case 133: + case (uint32_t)CutsceneCommands::SetActorAction5: + case 38: + case 43: + case 47: + case 54: + case 79: + case 83: + case 128: + case 135: + case (uint32_t)CutsceneCommands::SetActorAction6: + case 55: + case 77: + case 84: + case 90: + case 129: + case 136: + case (uint32_t)CutsceneCommands::SetActorAction7: + case 52: + case 57: + case 58: + case 88: + case 115: + case 130: + case 137: + case (uint32_t)CutsceneCommands::SetActorAction8: + case 60: + case 89: + case 111: + case 114: + case 134: + case 142: + case (uint32_t)CutsceneCommands::SetActorAction9: + case (uint32_t)CutsceneCommands::SetActorAction10: { + uint32_t size = reader->ReadUInt32(); + cutscene->commands.push_back(size); + + for (uint32_t i = 0; i < size; i++) { + cutscene->commands.push_back(read_CMD_HH(reader)); + cutscene->commands.push_back(read_CMD_HH(reader)); + cutscene->commands.push_back(read_CMD_HH(reader)); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + } + + break; + } + case (uint32_t)CutsceneCommands::SetSceneTransFX: { + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(read_CMD_HH(reader)); + cutscene->commands.push_back(read_CMD_HH(reader)); + break; + } + case (uint32_t)CutsceneCommands::PlayBGM: { + uint32_t size = reader->ReadUInt32(); + cutscene->commands.push_back(size); + + for (uint32_t i = 0; i < size; i++) { + cutscene->commands.push_back(read_CMD_HH(reader)); + cutscene->commands.push_back(read_CMD_HH(reader)); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + } + break; + } + case (uint32_t)CutsceneCommands::StopBGM: { + uint32_t size = reader->ReadUInt32(); + cutscene->commands.push_back(size); + + for (uint32_t i = 0; i < size; i++) { + cutscene->commands.push_back(read_CMD_HH(reader)); + cutscene->commands.push_back(read_CMD_HH(reader)); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + } + break; + } + case (uint32_t)CutsceneCommands::FadeBGM: { + uint32_t size = reader->ReadUInt32(); + cutscene->commands.push_back(size); + + for (uint32_t i = 0; i < size; i++) { + cutscene->commands.push_back(read_CMD_HH(reader)); + cutscene->commands.push_back(read_CMD_HH(reader)); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + } + break; + } + case (uint32_t)CutsceneCommands::SetTime: { + uint32_t size = reader->ReadUInt32(); + cutscene->commands.push_back(size); + + for (uint32_t i = 0; i < size; i++) { + cutscene->commands.push_back(read_CMD_HH(reader)); + cutscene->commands.push_back(read_CMD_HBB(reader)); + cutscene->commands.push_back(reader->ReadUInt32()); + } + break; + } + case (uint32_t)CutsceneCommands::Terminator: { + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(read_CMD_HH(reader)); + cutscene->commands.push_back(read_CMD_HH(reader)); + break; + } + case 0xFFFFFFFF: // CS_END + { + cutscene->commands.push_back(reader->ReadUInt32()); + return; + } + default: + SPDLOG_TRACE("CutsceneV0: Unknown command {}\n", commandId); + // error? + break; + } + } +} + +void LUS::CutsceneFactoryV0::ParseFileBinaryMM(std::shared_ptr<BinaryReader> reader, std::shared_ptr<Cutscene> cutscene) { + while (true) { + uint32_t command = reader->ReadUInt32(); + cutscene->commands.push_back(command); + + if (((command >= CS_CMD_ACTOR_CUE_100) && + (command <= CS_CMD_ACTOR_CUE_149)) || + (command == CS_CMD_ACTOR_CUE_201) || + ((command >= CS_CMD_ACTOR_CUE_450) && + (command <= CS_CMD_ACTOR_CUE_599))) { + goto actorCue; + } + + switch (command) { + case CS_CMD_TEXT: { + uint32_t size = reader->ReadUInt32(); + //uint8_t type = reader->ReadInt8(); + cutscene->commands.push_back(size); + // BENTODO do we need to read the type? + + for (uint32_t i = 0; i < size; i++) { + cutscene->commands.push_back(read_CMD_HH(reader)); + cutscene->commands.push_back(read_CMD_HH(reader)); + cutscene->commands.push_back(read_CMD_HH(reader)); + } + break; + } + case CS_CMD_CAMERA_SPLINE: { + uint32_t size = reader->ReadUInt32(); + cutscene->commands.push_back(size); + + for (uint32_t i = 0; i < (size / 4); i++) { + cutscene->commands.push_back(read_CMD_HH(reader)); + } + break; + } + case CS_CMD_MISC: { + uint32_t size = reader->ReadUInt32(); + cutscene->commands.push_back(size); + + for (uint32_t i = 0; i < size; i++) { + cutscene->commands.push_back(read_CMD_HH(reader)); + cutscene->commands.push_back(read_CMD_HH(reader)); + } + break; + } + case CS_CMD_LIGHT_SETTING: { + uint32_t size = reader->ReadUInt32(); + cutscene->commands.push_back(size); + + for (uint32_t i = 0; i < size; i++) { + cutscene->commands.push_back(read_CMD_BBH(reader)); + cutscene->commands.push_back(read_CMD_HH(reader)); + } + break; + } + case CS_CMD_TRANSITION: { + uint32_t size = reader->ReadUInt32(); + cutscene->commands.push_back(size); + + for (uint32_t i = 0; i < size; i++) { + cutscene->commands.push_back(read_CMD_HH(reader)); + cutscene->commands.push_back(read_CMD_HH(reader)); + } + break; + } + case CS_CMD_MOTION_BLUR: { + uint32_t size = reader->ReadUInt32(); + cutscene->commands.push_back(size); + + for (uint32_t i = 0; i < size; i++) { + cutscene->commands.push_back(read_CMD_HH(reader)); + cutscene->commands.push_back(read_CMD_HH(reader)); + } + break; + } + case CS_CMD_GIVE_TATL: { + uint32_t size = reader->ReadUInt32(); + cutscene->commands.push_back(size); + + for (uint32_t i = 0; i < size; i++) { + cutscene->commands.push_back(read_CMD_HH(reader)); + cutscene->commands.push_back(read_CMD_HH(reader)); + } + break; + } + case CS_CMD_START_SEQ: + case CS_CMD_STOP_SEQ: { + uint32_t size = reader->ReadUInt32(); + cutscene->commands.push_back(size); + + for (uint32_t i = 0; i < size; i++) { + cutscene->commands.push_back(read_CMD_BBH(reader)); + cutscene->commands.push_back(read_CMD_HH(reader)); + } + break; + } + case CS_CMD_SFX_REVERB_INDEX_2: + case CS_CMD_SFX_REVERB_INDEX_1: + case CS_CMD_MODIFY_SEQ: + + case CS_CMD_START_AMBIENCE: + case CS_CMD_FADE_OUT_AMBIENCE: + case CS_CMD_DESTINATION: + case CS_CMD_CHOOSE_CREDITS_SCENES: + + case CS_CMD_UNK_DATA_FA: + case CS_CMD_UNK_DATA_FE: + case CS_CMD_UNK_DATA_FF: + case CS_CMD_UNK_DATA_100: + case CS_CMD_UNK_DATA_101: + case CS_CMD_UNK_DATA_102: + case CS_CMD_UNK_DATA_103: + case CS_CMD_UNK_DATA_104: + case CS_CMD_UNK_DATA_105: + case CS_CMD_UNK_DATA_108: + case CS_CMD_UNK_DATA_109: { + uint32_t size = reader->ReadUInt32(); + cutscene->commands.push_back(size); + + for (uint32_t i = 0; i < size; i++) { + cutscene->commands.push_back(read_CMD_BBH(reader)); + cutscene->commands.push_back(read_CMD_HH(reader)); + } + break; + } + case CS_CMD_TRANSITION_GENERAL: { + uint32_t size = reader->ReadUInt32(); + cutscene->commands.push_back(size); + + for (uint32_t i = 0; i < size; i++) { + cutscene->commands.push_back(read_CMD_HH(reader)); + cutscene->commands.push_back(read_CMD_HBB(reader)); + cutscene->commands.push_back(read_CMD_BBBB(reader)); + } + break; + } + case CS_CMD_FADE_OUT_SEQ: { + uint32_t size = reader->ReadUInt32(); + cutscene->commands.push_back(size); + + for (uint32_t i = 0; i < size; i++) { + cutscene->commands.push_back(read_CMD_HH(reader)); + cutscene->commands.push_back(read_CMD_HH(reader)); + } + break; + } + case CS_CMD_TIME: { + uint32_t size = reader->ReadUInt32(); + cutscene->commands.push_back(size); + + for (uint32_t i = 0; i < size; i++) { + cutscene->commands.push_back(read_CMD_HH(reader)); + cutscene->commands.push_back(read_CMD_HBB(reader)); + } + break; + } + case CS_CMD_PLAYER_CUE: { + actorCue: + uint32_t size = reader->ReadUInt32(); + cutscene->commands.push_back(size); + for (uint32_t i = 0; i < size; i++) { + cutscene->commands.push_back(read_CMD_HH(reader)); + cutscene->commands.push_back(read_CMD_HH(reader)); + cutscene->commands.push_back(read_CMD_HH(reader)); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + cutscene->commands.push_back(reader->ReadUInt32()); + } + break; + } + case CS_CMD_RUMBLE: { + uint32_t size = reader->ReadUInt32(); + cutscene->commands.push_back(size); + + for (uint32_t i = 0; i < size; i++) { + cutscene->commands.push_back(read_CMD_HH(reader)); + cutscene->commands.push_back(read_CMD_HBB(reader)); + cutscene->commands.push_back(read_CMD_BBBB(reader)); + } + break; + } + case 0xFFFFFFFF: { + cutscene->commands.push_back(reader->ReadUInt32()); + return; + } + default: + SPDLOG_TRACE("CutsceneV0: Unknown command {}\n", command); + // error? + break; + } + } +} + +} // namespace LUS diff --git a/mm/2s2h/resource/importer/CutsceneFactory.h b/mm/2s2h/resource/importer/CutsceneFactory.h new file mode 100644 index 000000000..729041ce3 --- /dev/null +++ b/mm/2s2h/resource/importer/CutsceneFactory.h @@ -0,0 +1,25 @@ +#pragma once + +#include "Resource.h" +#include "ResourceFactory.h" + + +namespace LUS { +class Cutscene; +class CutsceneFactory : public ResourceFactory +{ + public: + std::shared_ptr<IResource> + ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) override; +}; + +class CutsceneFactoryV0 : public ResourceVersionFactory +{ + public: + void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override; + + private: + void ParseFileBinaryOoT(std::shared_ptr<BinaryReader> reader,std::shared_ptr<Cutscene> cutscene); + void ParseFileBinaryMM(std::shared_ptr<BinaryReader> reader, std::shared_ptr<Cutscene> cutscene); +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/importer/PathFactory.cpp b/mm/2s2h/resource/importer/PathFactory.cpp new file mode 100644 index 000000000..07e5b6e7b --- /dev/null +++ b/mm/2s2h/resource/importer/PathFactory.cpp @@ -0,0 +1,113 @@ +#include "2s2h/resource/importer/PathFactory.h" +#include "2s2h/resource/type/Path.h" +#include "spdlog/spdlog.h" + +namespace LUS { +std::shared_ptr<IResource> +PathFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) { + auto resource = std::make_shared<Path>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 0: + factory = std::make_shared<PathFactoryV0>(); + break; + } + + if (factory == nullptr) { + SPDLOG_ERROR("Failed to load Path with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileBinary(reader, resource); + + return resource; +} + +void LUS::PathFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader, + std::shared_ptr<IResource> resource) { + std::shared_ptr<Path> path = std::static_pointer_cast<Path>(resource); + ResourceVersionFactory::ParseFileBinary(reader, path); + + path->numPaths = reader->ReadUInt32(); + path->paths.reserve(path->numPaths); + for (uint32_t k = 0; k < path->numPaths; k++) { + std::vector<Vec3s> points; + uint32_t pointCount = reader->ReadUInt32(); + points.reserve(pointCount); + for (uint32_t i = 0; i < pointCount; i++) { + Vec3s point; + point.x = reader->ReadInt16(); + point.y = reader->ReadInt16(); + point.z = reader->ReadInt16(); + + points.push_back(point); + } + + PathData pathDataEntry; + pathDataEntry.count = pointCount; + + path->paths.push_back(points); + pathDataEntry.points = path->paths.back().data(); + + path->pathData.push_back(pathDataEntry); + } +} + +std::shared_ptr<IResource> PathFactoryMM::ReadResource(std::shared_ptr<ResourceInitData> initData, + std::shared_ptr<BinaryReader> reader) { + auto resource = std::make_shared<Path>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 0: + factory = std::make_shared<PathFactoryMMV0>(); + break; + } + + if (factory == nullptr) { + SPDLOG_ERROR("Failed to load Path with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileBinary(reader, resource); + + return resource; +} + +void LUS::PathFactoryMMV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) { + std::shared_ptr<PathMM> path = std::static_pointer_cast<PathMM>(resource); + ResourceVersionFactory::ParseFileBinary(reader, path); + + path->numPaths = reader->ReadUInt32(); + path->paths.reserve(path->numPaths); + for (uint32_t k = 0; k < path->numPaths; k++) { + std::vector<Vec3s> points; + uint32_t pointCount = reader->ReadUInt32(); + + uint8_t additionalPathIndex = reader->ReadUByte(); + int16_t customValue = reader->ReadInt16(); + + for (uint32_t i = 0; i < pointCount; i++) { + Vec3s point; + point.x = reader->ReadInt16(); + point.y = reader->ReadInt16(); + point.z = reader->ReadInt16(); + + points.push_back(point); + } + + PathDataMM pathDataEntry; + pathDataEntry.count = pointCount; + pathDataEntry.additionalPathIndex = additionalPathIndex; + pathDataEntry.customValue = customValue; + + path->paths.push_back(points); + pathDataEntry.points = path->paths.back().data(); + + path->pathData.push_back(pathDataEntry); + } +} + + +} // namespace LUS diff --git a/mm/2s2h/resource/importer/PathFactory.h b/mm/2s2h/resource/importer/PathFactory.h new file mode 100644 index 000000000..08f9e26cf --- /dev/null +++ b/mm/2s2h/resource/importer/PathFactory.h @@ -0,0 +1,31 @@ +#pragma once + +#include "Resource.h" +#include "ResourceFactory.h" + +namespace LUS { +class PathFactory : public ResourceFactory +{ + public: + std::shared_ptr<IResource> + ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) override; +}; + +class PathFactoryV0 : public ResourceVersionFactory +{ + public: + void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override; +}; + +class PathFactoryMM : public ResourceFactory { + public: + std::shared_ptr<IResource> ReadResource(std::shared_ptr<ResourceInitData> initData, + std::shared_ptr<BinaryReader> reader) override; +}; + +class PathFactoryMMV0 : public ResourceVersionFactory { + public: + void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override; +}; + +}; // namespace LUS diff --git a/mm/2s2h/resource/importer/PlayerAnimationFactory.cpp b/mm/2s2h/resource/importer/PlayerAnimationFactory.cpp new file mode 100644 index 000000000..7e6aba360 --- /dev/null +++ b/mm/2s2h/resource/importer/PlayerAnimationFactory.cpp @@ -0,0 +1,41 @@ +#include "2s2h/resource/importer/PlayerAnimationFactory.h" +#include "2s2h/resource/type/PlayerAnimation.h" +#include "spdlog/spdlog.h" + +namespace LUS { +std::shared_ptr<IResource> +PlayerAnimationFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) { + auto resource = std::make_shared<PlayerAnimation>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 0: + factory = std::make_shared<PlayerAnimationFactoryV0>(); + break; + } + + if (factory == nullptr) + { + SPDLOG_ERROR("Failed to load PlayerAnimation with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileBinary(reader, resource); + + return resource; +} + +void LUS::PlayerAnimationFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader, + std::shared_ptr<IResource> resource) +{ + std::shared_ptr<PlayerAnimation> playerAnimation = std::static_pointer_cast<PlayerAnimation>(resource); + ResourceVersionFactory::ParseFileBinary(reader, playerAnimation); + + uint32_t numEntries = reader->ReadUInt32(); + playerAnimation->limbRotData.reserve(numEntries); + + for (uint32_t i = 0; i < numEntries; i++) { + playerAnimation->limbRotData.push_back(reader->ReadInt16()); + } +} +} // namespace LUS diff --git a/mm/2s2h/resource/importer/PlayerAnimationFactory.h b/mm/2s2h/resource/importer/PlayerAnimationFactory.h new file mode 100644 index 000000000..b4981f7c6 --- /dev/null +++ b/mm/2s2h/resource/importer/PlayerAnimationFactory.h @@ -0,0 +1,17 @@ +#pragma once + +#include "Resource.h" +#include "ResourceFactory.h" + +namespace LUS { +class PlayerAnimationFactory : public ResourceFactory { + public: + std::shared_ptr<IResource> + ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) override; +}; + +class PlayerAnimationFactoryV0 : public ResourceVersionFactory { + public: + void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/importer/SceneFactory.cpp b/mm/2s2h/resource/importer/SceneFactory.cpp new file mode 100644 index 000000000..0e93da4f6 --- /dev/null +++ b/mm/2s2h/resource/importer/SceneFactory.cpp @@ -0,0 +1,140 @@ +#include "spdlog/spdlog.h" +#include "2s2h/resource/importer/SceneFactory.h" +#include "2s2h/resource/type/Scene.h" +#include "2s2h/resource/type/scenecommand/SceneCommand.h" +#include "2s2h/resource/importer/scenecommand/SetLightingSettingsFactory.h" +#include "2s2h/resource/importer/scenecommand/SetWindSettingsFactory.h" +#include "2s2h/resource/importer/scenecommand/SetExitListFactory.h" +#include "2s2h/resource/importer/scenecommand/SetTimeSettingsFactory.h" +#include "2s2h/resource/importer/scenecommand/SetSkyboxModifierFactory.h" +#include "2s2h/resource/importer/scenecommand/SetEchoSettingsFactory.h" +#include "2s2h/resource/importer/scenecommand/SetSoundSettingsFactory.h" +#include "2s2h/resource/importer/scenecommand/SetSkyboxSettingsFactory.h" +#include "2s2h/resource/importer/scenecommand/SetRoomBehaviorFactory.h" +#include "2s2h/resource/importer/scenecommand/SetCsCameraFactory.h" +#include "2s2h/resource/importer/scenecommand/SetCameraSettingsFactory.h" +#include "2s2h/resource/importer/scenecommand/SetRoomListFactory.h" +#include "2s2h/resource/importer/scenecommand/SetCollisionHeaderFactory.h" +#include "2s2h/resource/importer/scenecommand/SetEntranceListFactory.h" +#include "2s2h/resource/importer/scenecommand/SetSpecialObjectsFactory.h" +#include "2s2h/resource/importer/scenecommand/SetObjectListFactory.h" +#include "2s2h/resource/importer/scenecommand/SetStartPositionListFactory.h" +#include "2s2h/resource/importer/scenecommand/SetActorListFactory.h" +#include "2s2h/resource/importer/scenecommand/SetTransitionActorListFactory.h" +#include "2s2h/resource/importer/scenecommand/EndMarkerFactory.h" +#include "2s2h/resource/importer/scenecommand/SetAlternateHeadersFactory.h" +#include "2s2h/resource/importer/scenecommand/SetPathwaysFactory.h" +#include "2s2h/resource/importer/scenecommand/SetCutscenesFactory.h" +#include "2s2h/resource/importer/scenecommand/SetLightListFactory.h" +#include "2s2h/resource/importer/scenecommand/SetMeshFactory.h" +#include "2s2h/resource/importer/scenecommand/SetAnimatedMaterialListFactory.h" +#include "2s2h/resource/importer/scenecommand/SetMinimapListFactory.h" +#include "2s2h/resource/importer/scenecommand/SetMinimapChestsFactory.h" +#include "2s2h/resource/importer/scenecommand/SetActorCutsceneListFactory.h" + +namespace LUS { + +std::shared_ptr<IResource> +SceneFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) { + if (SceneFactory::sceneCommandFactories.empty()) { + SceneFactory::sceneCommandFactories[LUS::SceneCommandID::SetLightingSettings] = std::make_shared<SetLightingSettingsFactory>(); + SceneFactory::sceneCommandFactories[LUS::SceneCommandID::SetWind] = std::make_shared<SetWindSettingsFactory>(); + SceneFactory::sceneCommandFactories[LUS::SceneCommandID::SetExitList] = std::make_shared<SetExitListFactory>(); + SceneFactory::sceneCommandFactories[LUS::SceneCommandID::SetTimeSettings] = std::make_shared<SetTimeSettingsFactory>(); + SceneFactory::sceneCommandFactories[LUS::SceneCommandID::SetSkyboxModifier] = std::make_shared<SetSkyboxModifierFactory>(); + SceneFactory::sceneCommandFactories[LUS::SceneCommandID::SetEchoSettings] = std::make_shared<SetEchoSettingsFactory>(); + SceneFactory::sceneCommandFactories[LUS::SceneCommandID::SetSoundSettings] = std::make_shared<SetSoundSettingsFactory>(); + SceneFactory::sceneCommandFactories[LUS::SceneCommandID::SetSkyboxSettings] = std::make_shared<SetSkyboxSettingsFactory>(); + SceneFactory::sceneCommandFactories[LUS::SceneCommandID::SetRoomBehavior] = std::make_shared<SetRoomBehaviorFactory>(); + SceneFactory::sceneCommandFactories[LUS::SceneCommandID::SetCsCamera] = std::make_shared<SetCsCameraFactory>(); + SceneFactory::sceneCommandFactories[LUS::SceneCommandID::SetCameraSettings] = std::make_shared<SetCameraSettingsFactory>(); + SceneFactory::sceneCommandFactories[LUS::SceneCommandID::SetRoomList] = std::make_shared<SetRoomListFactory>(); + SceneFactory::sceneCommandFactories[LUS::SceneCommandID::SetCollisionHeader] = std::make_shared<SetCollisionHeaderFactory>(); + SceneFactory::sceneCommandFactories[LUS::SceneCommandID::SetEntranceList] = std::make_shared<SetEntranceListFactory>(); + SceneFactory::sceneCommandFactories[LUS::SceneCommandID::SetSpecialObjects] = std::make_shared<SetSpecialObjectsFactory>(); + SceneFactory::sceneCommandFactories[LUS::SceneCommandID::SetObjectList] = std::make_shared<SetObjectListFactory>(); + SceneFactory::sceneCommandFactories[LUS::SceneCommandID::SetStartPositionList] = std::make_shared<SetStartPositionListFactory>(); + SceneFactory::sceneCommandFactories[LUS::SceneCommandID::SetActorList] = std::make_shared<SetActorListFactory>(); + SceneFactory::sceneCommandFactories[LUS::SceneCommandID::SetTransitionActorList] = std::make_shared<SetTransitionActorListFactory>(); + SceneFactory::sceneCommandFactories[LUS::SceneCommandID::EndMarker] = std::make_shared<EndMarkerFactory>(); + SceneFactory::sceneCommandFactories[LUS::SceneCommandID::SetAlternateHeaders] = std::make_shared<SetAlternateHeadersFactory>(); + // TODO should we use a different custom scene command like cutscenes? + SceneFactory::sceneCommandFactories[LUS::SceneCommandID::SetPathways] = std::make_shared<SetPathwaysMMFactory>(); + SceneFactory::sceneCommandFactories[LUS::SceneCommandID::SetCutscenes] = std::make_shared<SetCutscenesFactory>(); + SceneFactory::sceneCommandFactories[LUS::SceneCommandID::SetLightList] = std::make_shared<SetLightListFactory>(); + SceneFactory::sceneCommandFactories[LUS::SceneCommandID::SetMesh] = std::make_shared<SetMeshFactory>(); + SceneFactory::sceneCommandFactories[LUS::SceneCommandID::SetCutscenesMM] = std::make_shared<SetCutsceneFactoryMM>(); + SceneFactory::sceneCommandFactories[LUS::SceneCommandID::SetAnimatedMaterialList] = + std::make_shared<SetAnimatedMaterialListFactory>(); + SceneFactory::sceneCommandFactories[LUS::SceneCommandID::SetMinimapList] = + std::make_shared<SetMinimapListFactory>(); + SceneFactory::sceneCommandFactories[LUS::SceneCommandID::SetMinimapChests] = + std::make_shared<SetMinimapChestsFactory>(); + SceneFactory::sceneCommandFactories[LUS::SceneCommandID::SetActorCutsceneList] = + std::make_shared<SetActorCutsceneListFactory>(); + } + + auto resource = std::make_shared<Scene>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 0: + factory = std::make_shared<SceneFactoryV0>(); + break; + } + + if (factory == nullptr) { + SPDLOG_ERROR("Failed to load Scene with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileBinary(reader, resource); + + return resource; +} + +void SceneFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader, + std::shared_ptr<IResource> resource) +{ + std::shared_ptr<Scene> scene = std::static_pointer_cast<Scene>(resource); + ResourceVersionFactory::ParseFileBinary(reader, scene); + + ParseSceneCommands(scene, reader); +} + +void SceneFactoryV0::ParseSceneCommands(std::shared_ptr<Scene> scene, std::shared_ptr<BinaryReader> reader) { + uint32_t commandCount = reader->ReadUInt32(); + scene->commands.reserve(commandCount); + + for (uint32_t i = 0; i < commandCount; i++) { + scene->commands.push_back(ParseSceneCommand(scene, reader, i)); + } +} + +std::shared_ptr<ISceneCommand> SceneFactoryV0::ParseSceneCommand(std::shared_ptr<Scene> scene, + std::shared_ptr<BinaryReader> reader, uint32_t index) { + SceneCommandID cmdID = (SceneCommandID)reader->ReadInt32(); + + reader->Seek(-sizeof(int32_t), SeekOffsetType::Current); + + std::shared_ptr<ISceneCommand> result = nullptr; + std::shared_ptr<SceneCommandFactory> commandFactory = SceneFactory::sceneCommandFactories[cmdID]; + + if (commandFactory != nullptr) { + auto initData = std::make_shared<ResourceInitData>(); + initData->Id = scene->GetInitData()->Id; + initData->Type = ResourceType::SOH_SceneCommand; + initData->Path = scene->GetInitData()->Path + "/SceneCommand" + std::to_string(index); + initData->ResourceVersion = scene->GetInitData()->ResourceVersion; + result = std::static_pointer_cast<ISceneCommand>(commandFactory->ReadResource(initData, reader)); + // Cache the resource? + } + + if (result == nullptr) { + SPDLOG_ERROR("Failed to load scene command of type {} in scene {}", (uint32_t)cmdID, scene->GetInitData()->Path); + } + + return result; +} + +} // namespace LUS diff --git a/mm/2s2h/resource/importer/SceneFactory.h b/mm/2s2h/resource/importer/SceneFactory.h new file mode 100644 index 000000000..40887983d --- /dev/null +++ b/mm/2s2h/resource/importer/SceneFactory.h @@ -0,0 +1,29 @@ +#pragma once + +#include "2s2h/resource/type/Scene.h" +#include "2s2h/resource/type/scenecommand/SceneCommand.h" +#include "2s2h/resource/importer/scenecommand/SceneCommandFactory.h" +#include "Resource.h" +#include "ResourceFactory.h" + +namespace LUS { +class SceneFactory : public ResourceFactory { + public: + std::shared_ptr<IResource> + ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) override; + + // Doing something very similar to what we do on the ResourceLoader. + // Eventually, scene commands should be moved up to the ResourceLoader as well. + // They can not right now because the exporter does not give them a proper resource type enum value, + // and the exporter does not export the commands with a proper OTR header. + static inline std::unordered_map<SceneCommandID, std::shared_ptr<SceneCommandFactory>> sceneCommandFactories; +}; + +class SceneFactoryV0 : public ResourceVersionFactory { + public: + void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override; + void ParseSceneCommands(std::shared_ptr<Scene> scene, std::shared_ptr<BinaryReader> reader); +protected: + std::shared_ptr<ISceneCommand> ParseSceneCommand(std::shared_ptr<Scene> scene, std::shared_ptr<BinaryReader> reader, uint32_t index); +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/importer/SkeletonFactory.cpp b/mm/2s2h/resource/importer/SkeletonFactory.cpp new file mode 100644 index 000000000..aa4c814bd --- /dev/null +++ b/mm/2s2h/resource/importer/SkeletonFactory.cpp @@ -0,0 +1,158 @@ +#include "2s2h/resource/importer/SkeletonFactory.h" +#include "2s2h/resource/type/Skeleton.h" +#include <spdlog/spdlog.h> +#include <libultraship/libultraship.h> + +namespace LUS { +std::shared_ptr<IResource> +SkeletonFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) { + auto resource = std::make_shared<Skeleton>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 0: + factory = std::make_shared<SkeletonFactoryV0>(); + break; + } + + if (factory == nullptr) { + SPDLOG_ERROR("Failed to load Skeleton with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileBinary(reader, resource); + + return resource; +} + +std::shared_ptr<IResource> +SkeletonFactory::ReadResourceXML(std::shared_ptr<ResourceInitData> initData, tinyxml2::XMLElement *reader) { + auto resource = std::make_shared<Skeleton>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 0: + factory = std::make_shared<SkeletonFactoryV0>(); + break; + } + + if (factory == nullptr) { + SPDLOG_ERROR("Failed to load Skeleton with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileXML(reader, resource); + + return resource; +} + +void SkeletonFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader, + std::shared_ptr<IResource> resource) +{ + std::shared_ptr<Skeleton> skeleton = std::static_pointer_cast<Skeleton>(resource); + ResourceVersionFactory::ParseFileBinary(reader, skeleton); + + skeleton->type = (SkeletonType)reader->ReadInt8(); + skeleton->limbType = (LimbType)reader->ReadInt8(); + skeleton->limbCount = reader->ReadUInt32(); + skeleton->dListCount = reader->ReadUInt32(); + skeleton->limbTableType = (LimbType)reader->ReadInt8(); + skeleton->limbTableCount = reader->ReadUInt32(); + + skeleton->limbTable.reserve(skeleton->limbTableCount); + for (uint32_t i = 0; i < skeleton->limbTableCount; i++) { + std::string limbPath = reader->ReadString(); + + skeleton->limbTable.push_back(limbPath); + } + + if (skeleton->type == LUS::SkeletonType::Curve) { + skeleton->skeletonData.skelCurveLimbList.limbCount = skeleton->limbCount; + skeleton->curveLimbArray.reserve(skeleton->skeletonData.skelCurveLimbList.limbCount); + } else if (skeleton->type == LUS::SkeletonType::Flex) { + skeleton->skeletonData.flexSkeletonHeader.dListCount = skeleton->dListCount; + } + + if (skeleton->type == LUS::SkeletonType::Normal) { + skeleton->skeletonData.skeletonHeader.limbCount = skeleton->limbCount; + skeleton->standardLimbArray.reserve(skeleton->skeletonData.skeletonHeader.limbCount); + } else if (skeleton->type == LUS::SkeletonType::Flex) { + skeleton->skeletonData.flexSkeletonHeader.sh.limbCount = skeleton->limbCount; + skeleton->standardLimbArray.reserve(skeleton->skeletonData.flexSkeletonHeader.sh.limbCount); + } + + for (size_t i = 0; i < skeleton->limbTable.size(); i++) { + std::string limbStr = skeleton->limbTable[i]; + auto limb = LUS::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(limbStr.c_str()); + skeleton->skeletonHeaderSegments.push_back(limb ? limb->GetRawPointer() : nullptr); + } + + if (skeleton->type == LUS::SkeletonType::Normal) { + skeleton->skeletonData.skeletonHeader.segment = (void**)skeleton->skeletonHeaderSegments.data(); + } else if (skeleton->type == LUS::SkeletonType::Flex) { + skeleton->skeletonData.flexSkeletonHeader.sh.segment = (void**)skeleton->skeletonHeaderSegments.data(); + } else if (skeleton->type == LUS::SkeletonType::Curve) { + skeleton->skeletonData.skelCurveLimbList.limbs = (SkelCurveLimb**)skeleton->skeletonHeaderSegments.data(); + } else { + SPDLOG_ERROR("unknown skeleton type {}", (uint32_t)skeleton->type); + } + + skeleton->skeletonData.skeletonHeader.skeletonType = (uint8_t)skeleton->type; +} +void SkeletonFactoryV0::ParseFileXML(tinyxml2::XMLElement* reader, std::shared_ptr<IResource> resource) +{ + std::shared_ptr<Skeleton> skel = std::static_pointer_cast<Skeleton>(resource); + + std::string skeletonType = reader->Attribute("Type"); + // std::string skeletonLimbType = reader->Attribute("LimbType"); + int numLimbs = reader->IntAttribute("LimbCount"); + int numDLs = reader->IntAttribute("DisplayListCount"); + + if (skeletonType == "Flex") { + skel->type = SkeletonType::Flex; + } else if (skeletonType == "Curve") { + skel->type = SkeletonType::Curve; + } else if (skeletonType == "Normal") { + skel->type = SkeletonType::Normal; + } + + skel->type = SkeletonType::Flex; + skel->limbType = LimbType::LOD; + + // if (skeletonLimbType == "Standard") + // skel->limbType = LimbType::Standard; + // else if (skeletonLimbType == "LOD") + // skel->limbType = LimbType::LOD; + // else if (skeletonLimbType == "Curve") + // skel->limbType = LimbType::Curve; + // else if (skeletonLimbType == "Skin") + // skel->limbType = LimbType::Skin; + // else if (skeletonLimbType == "Legacy") + // Sskel->limbType = LimbType::Legacy; + + auto child = reader->FirstChildElement(); + + skel->limbCount = numLimbs; + skel->dListCount = numDLs; + + while (child != nullptr) { + std::string childName = child->Name(); + + if (childName == "SkeletonLimb") { + std::string limbName = child->Attribute("Path"); + skel->limbTable.push_back(limbName); + + auto limb = LUS::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(limbName.c_str()); + skel->skeletonHeaderSegments.push_back(limb ? limb->GetRawPointer() : nullptr); + } + + child = child->NextSiblingElement(); + } + + skel->skeletonData.flexSkeletonHeader.sh.limbCount = skel->limbCount; + skel->skeletonData.flexSkeletonHeader.sh.segment = (void**)skel->skeletonHeaderSegments.data(); + skel->skeletonData.flexSkeletonHeader.dListCount = skel->dListCount; + skel->skeletonData.skeletonHeader.skeletonType = (uint8_t)skel->type; +} + +} // namespace LUS diff --git a/mm/2s2h/resource/importer/SkeletonFactory.h b/mm/2s2h/resource/importer/SkeletonFactory.h new file mode 100644 index 000000000..d64449393 --- /dev/null +++ b/mm/2s2h/resource/importer/SkeletonFactory.h @@ -0,0 +1,23 @@ +#pragma once + +#include "Resource.h" +#include "ResourceFactory.h" + +namespace LUS { +class SkeletonFactory : public ResourceFactory +{ + public: + std::shared_ptr<IResource> + ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) override; + std::shared_ptr<IResource> + ReadResourceXML(std::shared_ptr<ResourceInitData> initData, tinyxml2::XMLElement *reader) override; +}; + +class SkeletonFactoryV0 : public ResourceVersionFactory +{ + public: + void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override; + void ParseFileXML(tinyxml2::XMLElement* reader, std::shared_ptr<IResource> resource) override; +}; +}; // namespace LUS + diff --git a/mm/2s2h/resource/importer/SkeletonLimbFactory.cpp b/mm/2s2h/resource/importer/SkeletonLimbFactory.cpp new file mode 100644 index 000000000..ad2fec085 --- /dev/null +++ b/mm/2s2h/resource/importer/SkeletonLimbFactory.cpp @@ -0,0 +1,271 @@ +#include "2s2h/resource/importer/SkeletonLimbFactory.h" +#include "2s2h/resource/type/SkeletonLimb.h" +#include "spdlog/spdlog.h" +#include "libultraship/libultraship.h" + +namespace LUS { +std::shared_ptr<IResource> +SkeletonLimbFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) { + auto resource = std::make_shared<SkeletonLimb>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 0: + factory = std::make_shared<SkeletonLimbFactoryV0>(); + break; + } + + if (factory == nullptr) { + SPDLOG_ERROR("Failed to load Skeleton Limb with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileBinary(reader, resource); + + return resource; +} + +std::shared_ptr<IResource> +SkeletonLimbFactory::ReadResourceXML(std::shared_ptr<ResourceInitData> initData, tinyxml2::XMLElement *reader) { + auto resource = std::make_shared<SkeletonLimb>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 0: + factory = std::make_shared<SkeletonLimbFactoryV0>(); + break; + } + + if (factory == nullptr) { + SPDLOG_ERROR("Failed to load Skeleton Limb with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileXML(reader, resource); + + return resource; +} + +void LUS::SkeletonLimbFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader, + std::shared_ptr<IResource> resource) +{ + std::shared_ptr<SkeletonLimb> skeletonLimb = std::static_pointer_cast<SkeletonLimb>(resource); + ResourceVersionFactory::ParseFileBinary(reader, skeletonLimb); + + skeletonLimb->limbType = (LimbType)reader->ReadInt8(); + skeletonLimb->skinSegmentType = (ZLimbSkinType)reader->ReadInt8(); + skeletonLimb->skinDList = reader->ReadString(); + + skeletonLimb->skinVtxCnt = reader->ReadUInt16(); + + skeletonLimb->skinLimbModifCount = reader->ReadUInt32(); + skeletonLimb->skinLimbModifArray.reserve(skeletonLimb->skinLimbModifCount); + skeletonLimb->skinLimbModifVertexArrays.reserve(skeletonLimb->skinLimbModifCount); + skeletonLimb->skinLimbModifTransformationArrays.reserve(skeletonLimb->skinLimbModifCount); + for (size_t i = 0; i < skeletonLimb->skinLimbModifCount; i++) { + SkinLimbModif skinLimbModif; + skinLimbModif.unk_4 = reader->ReadUInt16(); + skeletonLimb->skinLimbModifArray.push_back(skinLimbModif); + + std::vector<SkinVertex> skinVertexArray; + int32_t skinVertexCount = reader->ReadInt32(); + skinVertexArray.reserve(skinVertexCount); + for (int32_t k = 0; k < skinVertexCount; k++) { + SkinVertex skinVertex; + + skinVertex.index = reader->ReadInt16(); + skinVertex.s = reader->ReadInt16(); + skinVertex.t = reader->ReadInt16(); + skinVertex.normX = reader->ReadInt8(); + skinVertex.normY = reader->ReadInt8(); + skinVertex.normZ = reader->ReadInt8(); + skinVertex.alpha = reader->ReadUByte(); + + skinVertexArray.push_back(skinVertex); + } + skeletonLimb->skinLimbModifVertexArrays.push_back(skinVertexArray); + + std::vector<SkinTransformation> skinTransformationArray; + int32_t skinTransformationCount = reader->ReadInt32(); + skinTransformationArray.reserve(skinTransformationCount); + for (int32_t k = 0; k < skinTransformationCount; k++) { + SkinTransformation skinTransformation; + + skinTransformation.limbIndex = reader->ReadUByte(); + skinTransformation.x = reader->ReadInt16(); + skinTransformation.y = reader->ReadInt16(); + skinTransformation.z = reader->ReadInt16(); + skinTransformation.scale = reader->ReadUByte(); + + skinTransformationArray.push_back(skinTransformation); + } + skeletonLimb->skinLimbModifTransformationArrays.push_back(skinTransformationArray); + } + + skeletonLimb->skinDList2 = reader->ReadString(); + + skeletonLimb->legTransX = reader->ReadFloat(); + skeletonLimb->legTransY = reader->ReadFloat(); + skeletonLimb->legTransZ = reader->ReadFloat(); + + skeletonLimb->rotX = reader->ReadUInt16(); + skeletonLimb->rotY = reader->ReadUInt16(); + skeletonLimb->rotZ = reader->ReadUInt16(); + + skeletonLimb->childPtr = reader->ReadString(); + skeletonLimb->siblingPtr = reader->ReadString(); + skeletonLimb->dListPtr = reader->ReadString(); + skeletonLimb->dList2Ptr = reader->ReadString(); + + skeletonLimb->transX = reader->ReadInt16(); + skeletonLimb->transY = reader->ReadInt16(); + skeletonLimb->transZ = reader->ReadInt16(); + + skeletonLimb->childIndex = reader->ReadUByte(); + skeletonLimb->siblingIndex = reader->ReadUByte(); + + if (skeletonLimb->limbType == LUS::LimbType::LOD) { + skeletonLimb->limbData.lodLimb.jointPos.x = skeletonLimb->transX; + skeletonLimb->limbData.lodLimb.jointPos.y = skeletonLimb->transY; + skeletonLimb->limbData.lodLimb.jointPos.z = skeletonLimb->transZ; + skeletonLimb->limbData.lodLimb.child = skeletonLimb->childIndex; + skeletonLimb->limbData.lodLimb.sibling = skeletonLimb->siblingIndex; + + if (skeletonLimb->dListPtr != "") { + auto dList = LUS::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(skeletonLimb->dListPtr.c_str()); + skeletonLimb->limbData.lodLimb.dLists[0] = (Gfx*)(dList ? dList->GetRawPointer() : nullptr); + } else { + skeletonLimb->limbData.lodLimb.dLists[0] = nullptr; + } + + if (skeletonLimb->dList2Ptr != "") { + auto dList = LUS::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(skeletonLimb->dList2Ptr.c_str()); + skeletonLimb->limbData.lodLimb.dLists[1] = (Gfx*)(dList ? dList->GetRawPointer() : nullptr); + } else { + skeletonLimb->limbData.lodLimb.dLists[1] = nullptr; + } + } else if (skeletonLimb->limbType == LUS::LimbType::Standard) { + skeletonLimb->limbData.standardLimb.jointPos.x = skeletonLimb->transX; + skeletonLimb->limbData.standardLimb.jointPos.y = skeletonLimb->transY; + skeletonLimb->limbData.standardLimb.jointPos.z = skeletonLimb->transZ; + skeletonLimb->limbData.standardLimb.child = skeletonLimb->childIndex; + skeletonLimb->limbData.standardLimb.sibling = skeletonLimb->siblingIndex; + skeletonLimb->limbData.standardLimb.dList = nullptr; + + if (!skeletonLimb->dListPtr.empty()) { + const auto dList = LUS::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(skeletonLimb->dListPtr.c_str()); + skeletonLimb->limbData.standardLimb.dList = (Gfx*)(dList ? dList->GetRawPointer() : nullptr); + } + } else if (skeletonLimb->limbType == LUS::LimbType::Curve) { + skeletonLimb->limbData.skelCurveLimb.firstChildIdx = skeletonLimb->childIndex; + skeletonLimb->limbData.skelCurveLimb.nextLimbIdx = skeletonLimb->siblingIndex; + skeletonLimb->limbData.skelCurveLimb.dList[0] = nullptr; + skeletonLimb->limbData.skelCurveLimb.dList[1] = nullptr; + + if (!skeletonLimb->dListPtr.empty()) { + const auto dList = LUS::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(skeletonLimb->dListPtr.c_str()); + skeletonLimb->limbData.skelCurveLimb.dList[0] = (Gfx*)(dList ? dList->GetRawPointer() : nullptr); + } + + if (!skeletonLimb->dList2Ptr.empty()) { + const auto dList = LUS::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(skeletonLimb->dList2Ptr.c_str()); + skeletonLimb->limbData.skelCurveLimb.dList[1] = (Gfx*)(dList ? dList->GetRawPointer() : nullptr); + } + } else if (skeletonLimb->limbType == LUS::LimbType::Skin) { + skeletonLimb->limbData.skinLimb.jointPos.x = skeletonLimb->transX; + skeletonLimb->limbData.skinLimb.jointPos.y = skeletonLimb->transY; + skeletonLimb->limbData.skinLimb.jointPos.z = skeletonLimb->transZ; + skeletonLimb->limbData.skinLimb.child = skeletonLimb->childIndex; + skeletonLimb->limbData.skinLimb.sibling = skeletonLimb->siblingIndex; + + if (skeletonLimb->skinSegmentType == LUS::ZLimbSkinType::SkinType_DList) { + skeletonLimb->limbData.skinLimb.segmentType = static_cast<int32_t>(skeletonLimb->skinSegmentType); + } else if (skeletonLimb->skinSegmentType == LUS::ZLimbSkinType::SkinType_4) { + skeletonLimb->limbData.skinLimb.segmentType = 4; + } else if (skeletonLimb->skinSegmentType == LUS::ZLimbSkinType::SkinType_5) { + skeletonLimb->limbData.skinLimb.segmentType = 5; + } else { + skeletonLimb->limbData.skinLimb.segmentType = 0; + } + + if (skeletonLimb->skinSegmentType == LUS::ZLimbSkinType::SkinType_DList) { + auto res = LUS::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(skeletonLimb->skinDList.c_str()); + skeletonLimb->limbData.skinLimb.segment = res ? res->GetRawPointer() : nullptr; + } else if (skeletonLimb->skinSegmentType == LUS::ZLimbSkinType::SkinType_4) { + skeletonLimb->skinAnimLimbData.totalVtxCount = skeletonLimb->skinVtxCnt; + skeletonLimb->skinAnimLimbData.limbModifCount = skeletonLimb->skinLimbModifCount; + skeletonLimb->skinAnimLimbData.limbModifications = skeletonLimb->skinLimbModifArray.data(); + auto res = LUS::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(skeletonLimb->skinDList2.c_str()); + skeletonLimb->skinAnimLimbData.dlist = (Gfx*)(res ? res->GetRawPointer() : nullptr); + + for (size_t i = 0; i < skeletonLimb->skinLimbModifArray.size(); i++) { + skeletonLimb->skinAnimLimbData.limbModifications[i].vtxCount = skeletonLimb->skinLimbModifVertexArrays[i].size(); + skeletonLimb->skinAnimLimbData.limbModifications[i].skinVertices = skeletonLimb->skinLimbModifVertexArrays[i].data(); + + skeletonLimb->skinAnimLimbData.limbModifications[i].transformCount = skeletonLimb->skinLimbModifTransformationArrays[i].size(); + skeletonLimb->skinAnimLimbData.limbModifications[i].limbTransformations = skeletonLimb->skinLimbModifTransformationArrays[i].data(); + + skeletonLimb->skinAnimLimbData.limbModifications[i].unk_4 = skeletonLimb->skinLimbModifArray[i].unk_4; + } + + skeletonLimb->limbData.skinLimb.segment = &skeletonLimb->skinAnimLimbData; + } + } +} +void SkeletonLimbFactoryV0::ParseFileXML(tinyxml2::XMLElement* reader, std::shared_ptr<IResource> resource) +{ + std::shared_ptr<SkeletonLimb> skelLimb = std::static_pointer_cast<SkeletonLimb>(resource); + + std::string limbType = reader->Attribute("Type"); + + // OTRTODO + skelLimb->limbType = LimbType::LOD; + + // skelLimb->legTransX = reader->FloatAttribute("LegTransX"); + // skelLimb->legTransY = reader->FloatAttribute("LegTransY"); + // skelLimb->legTransZ = reader->FloatAttribute("LegTransZ"); + skelLimb->rotX = reader->IntAttribute("RotX"); + skelLimb->rotY = reader->IntAttribute("RotY"); + skelLimb->rotZ = reader->IntAttribute("RotZ"); + + // skelLimb->transX = reader->IntAttribute("TransX"); + // skelLimb->transY = reader->IntAttribute("TransY"); + // skelLimb->transZ = reader->IntAttribute("TransZ"); + + skelLimb->transX = (int)reader->FloatAttribute("LegTransX"); + skelLimb->transY = (int)reader->FloatAttribute("LegTransY"); + skelLimb->transZ = (int)reader->FloatAttribute("LegTransZ"); + + skelLimb->childIndex = reader->IntAttribute("ChildIndex"); + skelLimb->siblingIndex = reader->IntAttribute("SiblingIndex"); + + // skelLimb->childPtr = reader->Attribute("ChildLimb"); + // skelLimb->siblingPtr = reader->Attribute("SiblingLimb"); + skelLimb->dListPtr = reader->Attribute("DisplayList1"); + + if (std::string(reader->Attribute("DisplayList1")) == "gEmptyDL") { + skelLimb->dListPtr = ""; + } + + auto& limbData = skelLimb->limbData; + + limbData.lodLimb.jointPos.x = skelLimb->transX; + limbData.lodLimb.jointPos.y = skelLimb->transY; + limbData.lodLimb.jointPos.z = skelLimb->transZ; + + if (skelLimb->dListPtr != "") { + auto res = LUS::Context::GetInstance()->GetResourceManager()->LoadResourceProcess((const char*)skelLimb->dListPtr.c_str()); + limbData.lodLimb.dLists[0] = (Gfx*)(res ? res->GetRawPointer() : nullptr); + } else { + limbData.lodLimb.dLists[0] = nullptr; + } + + limbData.lodLimb.dLists[1] = nullptr; + + limbData.lodLimb.child = skelLimb->childIndex; + limbData.lodLimb.sibling = skelLimb->siblingIndex; + + // skelLimb->dList2Ptr = reader->Attribute("DisplayList2"); +} + +} // namespace LUS diff --git a/mm/2s2h/resource/importer/SkeletonLimbFactory.h b/mm/2s2h/resource/importer/SkeletonLimbFactory.h new file mode 100644 index 000000000..8480a0126 --- /dev/null +++ b/mm/2s2h/resource/importer/SkeletonLimbFactory.h @@ -0,0 +1,23 @@ +#pragma once + +#include "Resource.h" +#include "ResourceFactory.h" + +namespace LUS { +class SkeletonLimbFactory : public ResourceFactory +{ + public: + std::shared_ptr<IResource> + ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) override; + std::shared_ptr<IResource> + ReadResourceXML(std::shared_ptr<ResourceInitData> initData, tinyxml2::XMLElement *reader) override; +}; + +class SkeletonLimbFactoryV0 : public ResourceVersionFactory +{ + public: + void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override; + void ParseFileXML(tinyxml2::XMLElement* reader, std::shared_ptr<IResource> resource) override; +}; +}; // namespace LUS + diff --git a/mm/2s2h/resource/importer/TextFactory.cpp b/mm/2s2h/resource/importer/TextFactory.cpp new file mode 100644 index 000000000..7d7ffb4f3 --- /dev/null +++ b/mm/2s2h/resource/importer/TextFactory.cpp @@ -0,0 +1,93 @@ +#include "2s2h/resource/importer/TextFactory.h" +#include "2s2h/resource/type/Text.h" +#include "spdlog/spdlog.h" + +namespace LUS { +std::shared_ptr<IResource> +TextFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) { + auto resource = std::make_shared<Text>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 0: + factory = std::make_shared<TextFactoryV0>(); + break; + default: + // VERSION NOT SUPPORTED + break; + } + + if (factory == nullptr) { + SPDLOG_ERROR("Failed to load Text with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileBinary(reader, resource); + + return resource; +} + +std::shared_ptr<IResource> +TextFactory::ReadResourceXML(std::shared_ptr<ResourceInitData> initData, tinyxml2::XMLElement *reader) { + auto resource = std::make_shared<Text>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 0: + factory = std::make_shared<TextFactoryV0>(); + break; + } + + if (factory == nullptr) { + SPDLOG_ERROR("Failed to load Text with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileXML(reader, resource); + + return resource; +} + +void LUS::TextFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader, + std::shared_ptr<IResource> resource) { + std::shared_ptr<Text> text = std::static_pointer_cast<Text>(resource); + ResourceVersionFactory::ParseFileBinary(reader, text); + + uint32_t msgCount = reader->ReadUInt32(); + text->messages.reserve(msgCount); + + for (uint32_t i = 0; i < msgCount; i++) { + MessageEntry entry; + entry.id = reader->ReadUInt16(); + entry.textboxType = reader->ReadUByte(); + entry.textboxYPos = reader->ReadUByte(); + entry.msg = reader->ReadString(); + + text->messages.push_back(entry); + } +} +void TextFactoryV0::ParseFileXML(tinyxml2::XMLElement* reader, std::shared_ptr<IResource> resource) { + std::shared_ptr<Text> txt = std::static_pointer_cast<Text>(resource); + + auto child = reader->FirstChildElement(); + + while (child != nullptr) { + std::string childName = child->Name(); + + if (childName == "TextEntry") { + MessageEntry entry; + entry.id = child->IntAttribute("ID"); + entry.textboxType = child->IntAttribute("TextboxType"); + entry.textboxYPos = child->IntAttribute("TextboxYPos"); + entry.msg = child->Attribute("Message"); + entry.msg += "\x2"; + + txt->messages.push_back(entry); + int bp = 0; + } + + child = child->NextSiblingElement(); + } +} + +} // namespace LUS diff --git a/mm/2s2h/resource/importer/TextFactory.h b/mm/2s2h/resource/importer/TextFactory.h new file mode 100644 index 000000000..7a6ae2841 --- /dev/null +++ b/mm/2s2h/resource/importer/TextFactory.h @@ -0,0 +1,23 @@ +#pragma once + +#include "Resource.h" +#include "ResourceFactory.h" + +namespace LUS { +class TextFactory : public ResourceFactory +{ + public: + std::shared_ptr<IResource> + ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) override; + std::shared_ptr<IResource> + ReadResourceXML(std::shared_ptr<ResourceInitData> initData, tinyxml2::XMLElement *reader) override; +}; + +class TextFactoryV0 : public ResourceVersionFactory +{ + public: + void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override; + void ParseFileXML(tinyxml2::XMLElement* reader, std::shared_ptr<IResource> resource) override; +}; +}; // namespace LUS + diff --git a/mm/2s2h/resource/importer/TextMMFactory.cpp b/mm/2s2h/resource/importer/TextMMFactory.cpp new file mode 100644 index 000000000..3c2892001 --- /dev/null +++ b/mm/2s2h/resource/importer/TextMMFactory.cpp @@ -0,0 +1,100 @@ +#include "2s2h/resource/importer/TextMMFactory.h" +#include "2s2h/resource/type/TextMM.h" +#include "spdlog/spdlog.h" + +namespace LUS { +std::shared_ptr<IResource> +TextMMFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) { + auto resource = std::make_shared<TextMM>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 0: + factory = std::make_shared<TextMMFactoryV0>(); + break; + default: + // VERSION NOT SUPPORTED + break; + } + + if (factory == nullptr) { + SPDLOG_ERROR("Failed to load Text with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileBinary(reader, resource); + + return resource; +} + +std::shared_ptr<IResource> TextMMFactory::ReadResourceXML(std::shared_ptr<ResourceInitData> initData, + tinyxml2::XMLElement* reader) { + auto resource = std::make_shared<TextMM>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 0: + factory = std::make_shared<TextMMFactoryV0>(); + break; + } + + if (factory == nullptr) { + SPDLOG_ERROR("Failed to load Text with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileXML(reader, resource); + + return resource; +} + +void LUS::TextMMFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) { + std::shared_ptr<TextMM> text = std::static_pointer_cast<TextMM>(resource); + ResourceVersionFactory::ParseFileBinary(reader, text); + + uint32_t msgCount = reader->ReadUInt32(); + text->messages.reserve(msgCount); + + for (uint32_t i = 0; i < msgCount; i++) { + MessageEntryMM entry; + entry.id = reader->ReadUInt16(); + entry.textboxType = reader->ReadUByte(); + entry.textboxYPos = reader->ReadUByte(); + entry.icon = reader->ReadUByte(); + entry.nextMessageID = reader->ReadUInt16(); + entry.firstItemCost = reader->ReadUInt16(); + entry.secondItemCost = reader->ReadUInt16(); + entry.msg = reader->ReadString(); + + text->messages.push_back(entry); + } +} +void TextMMFactoryV0::ParseFileXML(tinyxml2::XMLElement* reader, std::shared_ptr<IResource> resource) { + std::shared_ptr<TextMM> txt = std::static_pointer_cast<TextMM>(resource); + + auto child = reader->FirstChildElement(); + + while (child != nullptr) { + std::string childName = child->Name(); + + if (childName == "TextEntry") { + MessageEntryMM entry; + entry.id = child->IntAttribute("ID"); + entry.textboxType = child->IntAttribute("TextboxType"); + entry.textboxYPos = child->IntAttribute("TextboxYPos"); + + // BENTODO: MM Unique Fields + + + entry.msg = child->Attribute("Message"); + entry.msg += "\x2"; + + txt->messages.push_back(entry); + int bp = 0; + } + + child = child->NextSiblingElement(); + } +} + +} // namespace LUS diff --git a/mm/2s2h/resource/importer/TextMMFactory.h b/mm/2s2h/resource/importer/TextMMFactory.h new file mode 100644 index 000000000..0322a3762 --- /dev/null +++ b/mm/2s2h/resource/importer/TextMMFactory.h @@ -0,0 +1,23 @@ +#pragma once + +#include "Resource.h" +#include "ResourceFactory.h" + +namespace LUS { +class TextMMFactory : public ResourceFactory +{ + public: + std::shared_ptr<IResource> + ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) override; + std::shared_ptr<IResource> + ReadResourceXML(std::shared_ptr<ResourceInitData> initData, tinyxml2::XMLElement *reader) override; +}; + +class TextMMFactoryV0 : public ResourceVersionFactory +{ + public: + void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override; + void ParseFileXML(tinyxml2::XMLElement* reader, std::shared_ptr<IResource> resource) override; +}; +}; // namespace LUS + diff --git a/mm/2s2h/resource/importer/TextureAnimationFactory.cpp b/mm/2s2h/resource/importer/TextureAnimationFactory.cpp new file mode 100644 index 000000000..cc33beecf --- /dev/null +++ b/mm/2s2h/resource/importer/TextureAnimationFactory.cpp @@ -0,0 +1,124 @@ +#include "2s2h/resource/importer/TextureAnimationFactory.h" +#include "2s2h/resource/type/TextureAnimation.h" +#include <libultraship/libultraship.h> +#include "spdlog/spdlog.h" + +namespace LUS { + +std::shared_ptr<IResource> TextureAnimationFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, + std::shared_ptr<BinaryReader> reader) { + auto resource = std::make_shared<TextureAnimation>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 0: + factory = std::make_shared<TextureAnimationFactoryV0>(); + break; + } + + if (factory == nullptr) { + SPDLOG_ERROR("Failed to load Texture Animation with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileBinary(reader, resource); + + return resource; +} + +void LUS::TextureAnimationFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader, + std::shared_ptr<IResource> resource) { + std::shared_ptr<TextureAnimation> tAnim = std::static_pointer_cast<TextureAnimation>(resource); + ResourceVersionFactory::ParseFileBinary(reader, tAnim); + + size_t numEntries = reader->ReadUInt32(); + + for (size_t i = 0; i < numEntries; i++) { + AnimatedMaterial anim; + anim.segment = reader->ReadInt8(); + anim.type = reader->ReadInt8(); + + switch ((TextureAnimationParamsType)anim.type) { + case TextureAnimationParamsType::SingleScroll: { + auto* e = new AnimatedMatTexScrollParams; + e->xStep = reader->ReadInt8(); + e->yStep = reader->ReadInt8(); + e->width = reader->ReadUByte(); + e->height = reader->ReadUByte(); + anim.params = e; + break; + } + case TextureAnimationParamsType::DualScroll: { + auto* e = new AnimatedMatTexScrollParams[2]; + e[0].xStep = reader->ReadInt8(); + e[0].yStep = reader->ReadInt8(); + e[0].width = reader->ReadUByte(); + e[0].height = reader->ReadUByte(); + e[1].xStep = reader->ReadInt8(); + e[1].yStep = reader->ReadInt8(); + e[1].width = reader->ReadUByte(); + e[1].height = reader->ReadUByte(); + anim.params = e; + break; + } + case TextureAnimationParamsType::ColorChange: + case TextureAnimationParamsType::ColorChangeLERP: + case TextureAnimationParamsType::ColorChangeLagrange: { + auto* e = new AnimatedMatColorParams; + e->keyFrameLength = reader->ReadUInt16(); + e->keyFrameCount = reader->ReadUInt16(); + + size_t frames = reader->ReadUInt32(); + + e->keyFrames = new uint16_t[frames]; + for (size_t i = 0; i < frames; i++) { + e->keyFrames[i] = reader->ReadUInt16(); + } + size_t primColorSize = reader->ReadUInt32(); + e->primColors = new F3DPrimColor[primColorSize]; + + for (size_t i = 0; i < primColorSize; i++) { + e->primColors[i].r = reader->ReadUByte(); + e->primColors[i].g = reader->ReadUByte(); + e->primColors[i].b = reader->ReadUByte(); + e->primColors[i].a = reader->ReadUByte(); + e->primColors[i].lodFrac = reader->ReadUByte(); + } + + size_t envColorSize = reader->ReadUInt16(); + e->envColors = new F3DEnvColor[envColorSize]; + for (size_t i = 0; i < envColorSize; i++) { + e->envColors[i].r = reader->ReadUByte(); + e->envColors[i].g = reader->ReadUByte(); + e->envColors[i].b = reader->ReadUByte(); + e->envColors[i].a = reader->ReadUByte(); + } + anim.params = e; + break; + } + case TextureAnimationParamsType::TextureCycle: { + auto* e = new AnimatedMatTexCycleParams; + + e->keyFrameLength = reader->ReadUInt16(); + e->textureList = new void*[e->keyFrameLength]; + e->textureIndexList = new uint8_t[e->keyFrameLength]; + + for (size_t i = 0; i < e->keyFrameLength; i++) { + e->textureList[i] = ResourceGetDataByName(reader->ReadString().c_str()); + } + for (size_t i = 0; i < e->keyFrameLength; i++) { + e->textureIndexList[i] = reader->ReadUByte(); + } + anim.params = e; + break; + } + case TextureAnimationParamsType::Empty: { + anim.params = nullptr; + break; + } + } + tAnim->anims.emplace_back(anim); + } +} + +} // namespace LUS
\ No newline at end of file diff --git a/mm/2s2h/resource/importer/TextureAnimationFactory.h b/mm/2s2h/resource/importer/TextureAnimationFactory.h new file mode 100644 index 000000000..1bc52e246 --- /dev/null +++ b/mm/2s2h/resource/importer/TextureAnimationFactory.h @@ -0,0 +1,18 @@ +#pragma once + +#include "Resource.h" +#include "ResourceFactory.h" + +namespace LUS { +class TextureAnimationFactory : public ResourceFactory { + public: + std::shared_ptr<IResource> ReadResource(std::shared_ptr<ResourceInitData> initData, + std::shared_ptr<BinaryReader> reader) override; + +}; + +class TextureAnimationFactoryV0 : public ResourceVersionFactory { + public: + void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override; +}; +}; // namespace LUS
\ No newline at end of file diff --git a/mm/2s2h/resource/importer/scenecommand/EndMarkerFactory.cpp b/mm/2s2h/resource/importer/scenecommand/EndMarkerFactory.cpp new file mode 100644 index 000000000..61dba4ca3 --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/EndMarkerFactory.cpp @@ -0,0 +1,38 @@ +#include "2s2h/resource/importer/scenecommand/EndMarkerFactory.h" +#include "2s2h/resource/type/scenecommand/EndMarker.h" +#include "spdlog/spdlog.h" + +namespace LUS { +std::shared_ptr<IResource> +EndMarkerFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) { + auto resource = std::make_shared<EndMarker>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 0: + factory = std::make_shared<EndMarkerFactoryV0>(); + break; + } + + if (factory == nullptr) { + SPDLOG_ERROR("Failed to load EndMarker with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileBinary(reader, resource); + + return resource; +} + +void LUS::EndMarkerFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader, + std::shared_ptr<IResource> resource) +{ + std::shared_ptr<EndMarker> endMarker = std::static_pointer_cast<EndMarker>(resource); + ResourceVersionFactory::ParseFileBinary(reader, endMarker); + + ReadCommandId(endMarker, reader); + + // This has no data. +} + +} // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/EndMarkerFactory.h b/mm/2s2h/resource/importer/scenecommand/EndMarkerFactory.h new file mode 100644 index 000000000..a2580c077 --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/EndMarkerFactory.h @@ -0,0 +1,16 @@ +#pragma once + +#include "2s2h/resource/importer/scenecommand/SceneCommandFactory.h" + +namespace LUS { +class EndMarkerFactory : public SceneCommandFactory { + public: + std::shared_ptr<IResource> + ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) override; +}; + +class EndMarkerFactoryV0 : public SceneCommandVersionFactory { + public: + void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SceneCommandFactory.cpp b/mm/2s2h/resource/importer/scenecommand/SceneCommandFactory.cpp new file mode 100644 index 000000000..a2ed3c829 --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SceneCommandFactory.cpp @@ -0,0 +1,10 @@ +#include "2s2h/resource/importer/scenecommand/SceneCommandFactory.h" +#include "2s2h/resource/type/scenecommand/SceneCommand.h" +#include "spdlog/spdlog.h" + +namespace LUS { +void SceneCommandVersionFactory::ReadCommandId(std::shared_ptr<ISceneCommand> command, std::shared_ptr<BinaryReader> reader) { + command->cmdId = (SceneCommandID)reader->ReadInt32(); +} +} +
\ No newline at end of file diff --git a/mm/2s2h/resource/importer/scenecommand/SceneCommandFactory.h b/mm/2s2h/resource/importer/scenecommand/SceneCommandFactory.h new file mode 100644 index 000000000..b1449fad4 --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SceneCommandFactory.h @@ -0,0 +1,15 @@ +#pragma once + +#include <memory> +#include "Resource.h" +#include "ResourceFactory.h" +#include "2s2h/resource/type/scenecommand/SceneCommand.h" + +namespace LUS { +class SceneCommandFactory : public ResourceFactory {}; + +class SceneCommandVersionFactory : public ResourceVersionFactory { +protected: + void ReadCommandId(std::shared_ptr<ISceneCommand> command, std::shared_ptr<BinaryReader> reader); +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SetActorCutsceneListFactory.cpp b/mm/2s2h/resource/importer/scenecommand/SetActorCutsceneListFactory.cpp new file mode 100644 index 000000000..4ad852fb1 --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetActorCutsceneListFactory.cpp @@ -0,0 +1,55 @@ +#include "2s2h/resource/importer/scenecommand/SetActorCutsceneListFactory.h" +#include "2s2h/resource/type/scenecommand/SetActorCutsceneList.h" +#include "spdlog/spdlog.h" + +namespace LUS { +std::shared_ptr<IResource> SetActorCutsceneListFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, + std::shared_ptr<BinaryReader> reader) { + auto resource = std::make_shared<SetActorCutsceneList>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 0: + factory = std::make_shared<SetActorCutsceneListFactoryV0>(); + break; + } + + if (factory == nullptr) { + SPDLOG_ERROR("Failed to load SetActorList with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileBinary(reader, resource); + + return resource; +} + + +void SetActorCutsceneListFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader, + std::shared_ptr<IResource> resource) { + std::shared_ptr<SetActorCutsceneList> setActorCsList = std::static_pointer_cast<SetActorCutsceneList>(resource); + ResourceVersionFactory::ParseFileBinary(reader, setActorCsList); + + ReadCommandId(setActorCsList, reader); + + setActorCsList->numEntries = reader->ReadUInt32(); + setActorCsList->entries.reserve(setActorCsList->numEntries); + + for (uint32_t i = 0; i < setActorCsList->numEntries; i++) { + CutsceneEntry e; + e.priority = reader->ReadInt16(); + e.length = reader->ReadInt16(); + e.csCamId = reader->ReadInt16(); + e.scriptIndex = reader->ReadInt16(); + e.additionalCsId = reader->ReadInt16(); + e.endSfx = reader->ReadUByte(); + e.customValue = reader->ReadUByte(); + e.hudVisibility = reader->ReadInt16(); + e.endCam = reader->ReadUByte(); + e.letterboxSize = reader->ReadUByte(); + setActorCsList->entries.emplace_back(e); + } + +} + +} // namespace LUS
\ No newline at end of file diff --git a/mm/2s2h/resource/importer/scenecommand/SetActorCutsceneListFactory.h b/mm/2s2h/resource/importer/scenecommand/SetActorCutsceneListFactory.h new file mode 100644 index 000000000..23314c129 --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetActorCutsceneListFactory.h @@ -0,0 +1,17 @@ +#pragma once + +#include "2s2h/resource/importer/scenecommand/SceneCommandFactory.h" + +namespace LUS { +class SetActorCutsceneListFactory : public SceneCommandFactory { + std::shared_ptr<IResource> ReadResource(std::shared_ptr<ResourceInitData> initData, + std::shared_ptr<BinaryReader> reader) override; +}; + +class SetActorCutsceneListFactoryV0 : public SceneCommandVersionFactory { + public: + void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override; + +}; + +} diff --git a/mm/2s2h/resource/importer/scenecommand/SetActorListFactory.cpp b/mm/2s2h/resource/importer/scenecommand/SetActorListFactory.cpp new file mode 100644 index 000000000..32aa3db5f --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetActorListFactory.cpp @@ -0,0 +1,53 @@ +#include "2s2h/resource/importer/scenecommand/SetActorListFactory.h" +#include "2s2h/resource/type/scenecommand/SetActorList.h" +#include "spdlog/spdlog.h" + +namespace LUS { +std::shared_ptr<IResource> +SetActorListFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) { + auto resource = std::make_shared<SetActorList>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 0: + factory = std::make_shared<SetActorListFactoryV0>(); + break; + } + + if (factory == nullptr) + { + SPDLOG_ERROR("Failed to load SetActorList with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileBinary(reader, resource); + + return resource; +} + +void LUS::SetActorListFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader, + std::shared_ptr<IResource> resource) { + std::shared_ptr<SetActorList> setActorList = std::static_pointer_cast<SetActorList>(resource); + ResourceVersionFactory::ParseFileBinary(reader, setActorList); + + ReadCommandId(setActorList, reader); + + setActorList->numActors = reader->ReadUInt32(); + setActorList->actorList.reserve(setActorList->numActors); + for (uint32_t i = 0; i < setActorList->numActors; i++) { + ActorEntry entry; + + entry.id = reader->ReadUInt16(); + entry.pos.x = reader->ReadInt16(); + entry.pos.y = reader->ReadInt16(); + entry.pos.z = reader->ReadInt16(); + entry.rot.x = reader->ReadInt16(); + entry.rot.y = reader->ReadInt16(); + entry.rot.z = reader->ReadInt16(); + entry.params = reader->ReadUInt16(); + + setActorList->actorList.push_back(entry); + } +} + +} // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SetActorListFactory.h b/mm/2s2h/resource/importer/scenecommand/SetActorListFactory.h new file mode 100644 index 000000000..5958ac576 --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetActorListFactory.h @@ -0,0 +1,16 @@ +#pragma once + +#include "2s2h/resource/importer/scenecommand/SceneCommandFactory.h" + +namespace LUS { +class SetActorListFactory : public SceneCommandFactory { + public: + std::shared_ptr<IResource> + ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) override; +}; + +class SetActorListFactoryV0 : public SceneCommandVersionFactory { + public: + void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SetAlternateHeadersFactory.cpp b/mm/2s2h/resource/importer/scenecommand/SetAlternateHeadersFactory.cpp new file mode 100644 index 000000000..d68d65c34 --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetAlternateHeadersFactory.cpp @@ -0,0 +1,49 @@ +#include "2s2h/resource/importer/scenecommand/SetAlternateHeadersFactory.h" +#include "2s2h/resource/type/scenecommand/SetAlternateHeaders.h" +#include "spdlog/spdlog.h" +#include "libultraship/libultraship.h" + +namespace LUS { +std::shared_ptr<IResource> SetAlternateHeadersFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, + std::shared_ptr<BinaryReader> reader) { + auto resource = std::make_shared<SetAlternateHeaders>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 0: + factory = std::make_shared<SetAlternateHeadersFactoryV0>(); + break; + } + + if (factory == nullptr) + { + SPDLOG_ERROR("Failed to load SetAlternateHeaders with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileBinary(reader, resource); + + return resource; +} + +void LUS::SetAlternateHeadersFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader, + std::shared_ptr<IResource> resource) +{ + std::shared_ptr<SetAlternateHeaders> setAlternateHeaders = std::static_pointer_cast<SetAlternateHeaders>(resource); + ResourceVersionFactory::ParseFileBinary(reader, setAlternateHeaders); + + ReadCommandId(setAlternateHeaders, reader); + + setAlternateHeaders->numHeaders = reader->ReadUInt32(); + setAlternateHeaders->headers.reserve(setAlternateHeaders->numHeaders); + for (uint32_t i = 0; i < setAlternateHeaders->numHeaders; i++) { + auto headerName = reader->ReadString(); + if (!headerName.empty()) { + setAlternateHeaders->headers.push_back(std::static_pointer_cast<LUS::Scene>(LUS::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(headerName.c_str()))); + } else { + setAlternateHeaders->headers.push_back(nullptr); + } + } +} + +} // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SetAlternateHeadersFactory.h b/mm/2s2h/resource/importer/scenecommand/SetAlternateHeadersFactory.h new file mode 100644 index 000000000..efa96f68f --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetAlternateHeadersFactory.h @@ -0,0 +1,16 @@ +#pragma once + +#include "2s2h/resource/importer/scenecommand/SceneCommandFactory.h" + +namespace LUS { +class SetAlternateHeadersFactory : public SceneCommandFactory { + public: + std::shared_ptr<IResource> + ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) override; +}; + +class SetAlternateHeadersFactoryV0 : public SceneCommandVersionFactory { + public: + void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SetAnimatedMaterialListFactory.cpp b/mm/2s2h/resource/importer/scenecommand/SetAnimatedMaterialListFactory.cpp new file mode 100644 index 000000000..e6e9865ec --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetAnimatedMaterialListFactory.cpp @@ -0,0 +1,41 @@ +#include "2s2h/resource/importer/scenecommand/SetAnimatedMaterialListFactory.h" +#include "2s2h/resource/type/scenecommand/SetAnimatedMaterialList.h" +#include "2s2h/resource/type/TextureAnimation.h" +#include "spdlog/spdlog.h" +#include <libultraship/libultraship.h> + +namespace LUS { + +std::shared_ptr<IResource> LUS::SetAnimatedMaterialListFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, + std::shared_ptr<BinaryReader> reader) { + auto resource = std::make_shared<SetAnimatedMaterialList>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 0: + factory = std::make_shared<SetAnimatedMaterialListFactoryV0>(); + break; + } + + if (factory == nullptr) { + SPDLOG_ERROR("Failed to load SetAnimatedMaterialList with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileBinary(reader, resource); + + return resource; +} + +void LUS::SetAnimatedMaterialListFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader, + std::shared_ptr<IResource> resource) { + std::shared_ptr<SetAnimatedMaterialList> setAnimatedMat = + std::static_pointer_cast<SetAnimatedMaterialList>(resource); + ResourceVersionFactory::ParseFileBinary(reader, setAnimatedMat); + + ReadCommandId(setAnimatedMat, reader); + AnimatedMaterialData* res = (AnimatedMaterialData*)ResourceGetDataByName(reader->ReadString().c_str()); + setAnimatedMat->mat = res; +} + +} // namespace LUS
\ No newline at end of file diff --git a/mm/2s2h/resource/importer/scenecommand/SetAnimatedMaterialListFactory.h b/mm/2s2h/resource/importer/scenecommand/SetAnimatedMaterialListFactory.h new file mode 100644 index 000000000..22e3fff69 --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetAnimatedMaterialListFactory.h @@ -0,0 +1,17 @@ +#pragma once + +#include "2s2h/resource/importer/scenecommand/SceneCommandFactory.h" + +namespace LUS { +class SetAnimatedMaterialListFactory : public SceneCommandFactory { + public: + std::shared_ptr<IResource> ReadResource(std::shared_ptr<ResourceInitData> initData, + std::shared_ptr<BinaryReader> reader) override; +}; + +class SetAnimatedMaterialListFactoryV0 : public SceneCommandVersionFactory { + public: + void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override; +}; + +} diff --git a/mm/2s2h/resource/importer/scenecommand/SetCameraSettingsFactory.cpp b/mm/2s2h/resource/importer/scenecommand/SetCameraSettingsFactory.cpp new file mode 100644 index 000000000..d36d412e9 --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetCameraSettingsFactory.cpp @@ -0,0 +1,39 @@ +#include "2s2h/resource/importer/scenecommand/SetCameraSettingsFactory.h" +#include "2s2h/resource/type/scenecommand/SetCameraSettings.h" +#include "spdlog/spdlog.h" + +namespace LUS { +std::shared_ptr<IResource> SetCameraSettingsFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, + std::shared_ptr<BinaryReader> reader) { + auto resource = std::make_shared<SetCameraSettings>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 0: + factory = std::make_shared<SetCameraSettingsFactoryV0>(); + break; + } + + if (factory == nullptr) { + SPDLOG_ERROR("Failed to load SetCameraSettings with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileBinary(reader, resource); + + return resource; +} + +void LUS::SetCameraSettingsFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader, + std::shared_ptr<IResource> resource) +{ + std::shared_ptr<SetCameraSettings> setCameraSettings = std::static_pointer_cast<SetCameraSettings>(resource); + ResourceVersionFactory::ParseFileBinary(reader, setCameraSettings); + + ReadCommandId(setCameraSettings, reader); + + setCameraSettings->settings.cameraMovement = reader->ReadInt8(); + setCameraSettings->settings.worldMapArea = reader->ReadInt32(); +} + +} // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SetCameraSettingsFactory.h b/mm/2s2h/resource/importer/scenecommand/SetCameraSettingsFactory.h new file mode 100644 index 000000000..e17150807 --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetCameraSettingsFactory.h @@ -0,0 +1,16 @@ +#pragma once + +#include "2s2h/resource/importer/scenecommand/SceneCommandFactory.h" + +namespace LUS { +class SetCameraSettingsFactory : public SceneCommandFactory { + public: + std::shared_ptr<IResource> + ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) override; +}; + +class SetCameraSettingsFactoryV0 : public SceneCommandVersionFactory { + public: + void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SetCollisionHeaderFactory.cpp b/mm/2s2h/resource/importer/scenecommand/SetCollisionHeaderFactory.cpp new file mode 100644 index 000000000..4badbb055 --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetCollisionHeaderFactory.cpp @@ -0,0 +1,39 @@ +#include "2s2h/resource/importer/scenecommand/SetCollisionHeaderFactory.h" +#include "2s2h/resource/type/scenecommand/SetCollisionHeader.h" +#include "libultraship/libultraship.h" +#include "spdlog/spdlog.h" + +namespace LUS { +std::shared_ptr<IResource> SetCollisionHeaderFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, + std::shared_ptr<BinaryReader> reader) { + auto resource = std::make_shared<SetCollisionHeader>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 0: + factory = std::make_shared<SetCollisionHeaderFactoryV0>(); + break; + } + + if (factory == nullptr) { + SPDLOG_ERROR("Failed to load SetCollisionHeader with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileBinary(reader, resource); + + return resource; +} + +void LUS::SetCollisionHeaderFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader, + std::shared_ptr<IResource> resource) { + std::shared_ptr<SetCollisionHeader> setCollisionHeader = std::static_pointer_cast<SetCollisionHeader>(resource); + ResourceVersionFactory::ParseFileBinary(reader, setCollisionHeader); + + ReadCommandId(setCollisionHeader, reader); + + setCollisionHeader->fileName = reader->ReadString(); + setCollisionHeader->collisionHeader = std::static_pointer_cast<CollisionHeader>(LUS::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(setCollisionHeader->fileName.c_str())); +} + +} // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SetCollisionHeaderFactory.h b/mm/2s2h/resource/importer/scenecommand/SetCollisionHeaderFactory.h new file mode 100644 index 000000000..76655015d --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetCollisionHeaderFactory.h @@ -0,0 +1,16 @@ +#pragma once + +#include "2s2h/resource/importer/scenecommand/SceneCommandFactory.h" + +namespace LUS { +class SetCollisionHeaderFactory : public SceneCommandFactory { + public: + std::shared_ptr<IResource> + ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) override; +}; + +class SetCollisionHeaderFactoryV0 : public SceneCommandVersionFactory { + public: + void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SetCsCameraFactory.cpp b/mm/2s2h/resource/importer/scenecommand/SetCsCameraFactory.cpp new file mode 100644 index 000000000..4e7c74067 --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetCsCameraFactory.cpp @@ -0,0 +1,55 @@ +#include "2s2h/resource/importer/scenecommand/SetCsCameraFactory.h" +#include "2s2h/resource/type/scenecommand/SetCsCamera.h" +#include "spdlog/spdlog.h" + +namespace LUS { +std::shared_ptr<IResource> +SetCsCameraFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) { + auto resource = std::make_shared<SetCsCamera>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 0: + factory = std::make_shared<SetCsCameraFactoryV0>(); + break; + } + + if (factory == nullptr) { + SPDLOG_ERROR("Failed to load SetCsCamera with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileBinary(reader, resource); + + return resource; +} + +void LUS::SetCsCameraFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader, + std::shared_ptr<IResource> resource) { + std::shared_ptr<SetCsCamera> setCsCamera = std::static_pointer_cast<SetCsCamera>(resource); + ResourceVersionFactory::ParseFileBinary(reader, setCsCamera); + + ReadCommandId(setCsCamera, reader); + + size_t camSize = reader->ReadUInt32(); + + for (size_t i = 0; i < camSize; i++) { + ActorCsCamInfoData data; + data.setting = reader->ReadUInt16(); + data.count = reader->ReadUInt16(); + if (data.count == 0) { + data.actorCsCamFuncData = nullptr; + continue; + } + data.actorCsCamFuncData = new z64Vec3s[data.count]; + for (size_t j = 0; j < data.count; j++) { + data.actorCsCamFuncData->x = reader->ReadInt16(); + data.actorCsCamFuncData->y = reader->ReadInt16(); + data.actorCsCamFuncData->z = reader->ReadInt16(); + } + setCsCamera->csCamera.emplace_back(data); + } + +} + +} // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SetCsCameraFactory.h b/mm/2s2h/resource/importer/scenecommand/SetCsCameraFactory.h new file mode 100644 index 000000000..4be361364 --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetCsCameraFactory.h @@ -0,0 +1,16 @@ +#pragma once + +#include "2s2h/resource/importer/scenecommand/SceneCommandFactory.h" + +namespace LUS { +class SetCsCameraFactory : public SceneCommandFactory { + public: + std::shared_ptr<IResource> + ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) override; +}; + +class SetCsCameraFactoryV0 : public SceneCommandVersionFactory { + public: + void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SetCutscenesFactory.cpp b/mm/2s2h/resource/importer/scenecommand/SetCutscenesFactory.cpp new file mode 100644 index 000000000..ce429d8c1 --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetCutscenesFactory.cpp @@ -0,0 +1,81 @@ +#include "2s2h/resource/importer/scenecommand/SetCutscenesFactory.h" +#include "2s2h/resource/type/scenecommand/SetCutscenes.h" +#include <libultraship/libultraship.h> +#include "spdlog/spdlog.h" + +namespace LUS { +std::shared_ptr<IResource> +SetCutscenesFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) { + auto resource = std::make_shared<SetCutscenes>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 0: + factory = std::make_shared<SetCutscenesFactoryV0>(); + break; + } + + if (factory == nullptr) + { + SPDLOG_ERROR("Failed to load SetCutscenes with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileBinary(reader, resource); + + return resource; +} + +void LUS::SetCutscenesFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader, + std::shared_ptr<IResource> resource) { + std::shared_ptr<SetCutscenes> setCutscenes = std::static_pointer_cast<SetCutscenes>(resource); + ResourceVersionFactory::ParseFileBinary(reader, setCutscenes); + + ReadCommandId(setCutscenes, reader); + + setCutscenes->fileName = reader->ReadString(); + setCutscenes->cutscene = std::static_pointer_cast<Cutscene>(LUS::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(setCutscenes->fileName.c_str())); +} + +std::shared_ptr<IResource> SetCutsceneFactoryMM::ReadResource(std::shared_ptr<ResourceInitData> initData, + std::shared_ptr<BinaryReader> reader) { + auto resource = std::make_shared<SetCutscenesMM>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 0: + factory = std::make_shared<SetCutscenesFactoryMMV0>(); + break; + } + + if (factory == nullptr) { + SPDLOG_ERROR("Failed to load SetCutscenes with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileBinary(reader, resource); + + return resource; +} + +void LUS::SetCutscenesFactoryMMV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader, + std::shared_ptr<IResource> resource) { + std::shared_ptr<SetCutscenesMM> setCutscenes = std::static_pointer_cast<SetCutscenesMM>(resource); + ResourceVersionFactory::ParseFileBinary(reader, setCutscenes); + + ReadCommandId(setCutscenes, reader); + + size_t numCs = reader->ReadUByte(); + + for (size_t i = 0; i < numCs; i++) { + CutsceneScriptEntry entry; + std::string path = reader->ReadString(); + entry.exit = reader->ReadUInt16(); + entry.entrance = reader->ReadUByte(); + entry.flag = reader->ReadUByte(); + entry.data = ResourceGetDataByName(path.c_str()); + setCutscenes->entries.emplace_back(entry); + } +} + +} // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SetCutscenesFactory.h b/mm/2s2h/resource/importer/scenecommand/SetCutscenesFactory.h new file mode 100644 index 000000000..905eab39a --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetCutscenesFactory.h @@ -0,0 +1,28 @@ +#pragma once + +#include "2s2h/resource/importer/scenecommand/SceneCommandFactory.h" + +namespace LUS { +class SetCutscenesFactory : public SceneCommandFactory { + public: + std::shared_ptr<IResource> + ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) override; +}; + +class SetCutscenesFactoryV0 : public SceneCommandVersionFactory { + public: + void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override; +}; + +class SetCutsceneFactoryMM : public SceneCommandFactory { + public: + std::shared_ptr<IResource> ReadResource(std::shared_ptr<ResourceInitData> initData, + std::shared_ptr<BinaryReader> reader) override; +}; + +class SetCutscenesFactoryMMV0 : public SceneCommandVersionFactory { + public: + void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override; +}; + +}; // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SetEchoSettingsFactory.cpp b/mm/2s2h/resource/importer/scenecommand/SetEchoSettingsFactory.cpp new file mode 100644 index 000000000..c9bdfef54 --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetEchoSettingsFactory.cpp @@ -0,0 +1,38 @@ +#include "2s2h/resource/importer/scenecommand/SetEchoSettingsFactory.h" +#include "2s2h/resource/type/scenecommand/SetEchoSettings.h" +#include "spdlog/spdlog.h" + +namespace LUS { +std::shared_ptr<IResource> +SetEchoSettingsFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) { + auto resource = std::make_shared<SetEchoSettings>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 0: + factory = std::make_shared<SetEchoSettingsFactoryV0>(); + break; + } + + if (factory == nullptr) { + SPDLOG_ERROR("Failed to load SetEchoSettings with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileBinary(reader, resource); + + return resource; +} + +void LUS::SetEchoSettingsFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader, + std::shared_ptr<IResource> resource) +{ + std::shared_ptr<SetEchoSettings> setEchoSettings = std::static_pointer_cast<SetEchoSettings>(resource); + ResourceVersionFactory::ParseFileBinary(reader, setEchoSettings); + + ReadCommandId(setEchoSettings, reader); + + setEchoSettings->settings.echo = reader->ReadInt8(); +} + +} // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SetEchoSettingsFactory.h b/mm/2s2h/resource/importer/scenecommand/SetEchoSettingsFactory.h new file mode 100644 index 000000000..20673aa57 --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetEchoSettingsFactory.h @@ -0,0 +1,16 @@ +#pragma once + +#include "2s2h/resource/importer/scenecommand/SceneCommandFactory.h" + +namespace LUS { +class SetEchoSettingsFactory : public SceneCommandFactory { + public: + std::shared_ptr<IResource> + ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) override; +}; + +class SetEchoSettingsFactoryV0 : public SceneCommandVersionFactory { + public: + void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SetEntranceListFactory.cpp b/mm/2s2h/resource/importer/scenecommand/SetEntranceListFactory.cpp new file mode 100644 index 000000000..34a50248a --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetEntranceListFactory.cpp @@ -0,0 +1,46 @@ +#include "2s2h/resource/importer/scenecommand/SetEntranceListFactory.h" +#include "2s2h/resource/type/scenecommand/SetEntranceList.h" +#include "spdlog/spdlog.h" + +namespace LUS { +std::shared_ptr<IResource> +SetEntranceListFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) { + auto resource = std::make_shared<SetEntranceList>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 0: + factory = std::make_shared<SetEntranceListFactoryV0>(); + break; + } + + if (factory == nullptr) { + SPDLOG_ERROR("Failed to load SetEntranceListList with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileBinary(reader, resource); + + return resource; +} + +void LUS::SetEntranceListFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader, + std::shared_ptr<IResource> resource) { + std::shared_ptr<SetEntranceList> setEntranceList = std::static_pointer_cast<SetEntranceList>(resource); + ResourceVersionFactory::ParseFileBinary(reader, setEntranceList); + + ReadCommandId(setEntranceList, reader); + + setEntranceList->numEntrances = reader->ReadUInt32(); + setEntranceList->entrances.reserve(setEntranceList->numEntrances); + for (uint32_t i = 0; i < setEntranceList->numEntrances; i++) { + EntranceEntry entranceEntry; + + entranceEntry.spawn = reader->ReadInt8(); + entranceEntry.room = reader->ReadInt8(); + + setEntranceList->entrances.push_back(entranceEntry); + } +} + +} // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SetEntranceListFactory.h b/mm/2s2h/resource/importer/scenecommand/SetEntranceListFactory.h new file mode 100644 index 000000000..2bb1186ba --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetEntranceListFactory.h @@ -0,0 +1,16 @@ +#pragma once + +#include "2s2h/resource/importer/scenecommand/SceneCommandFactory.h" + +namespace LUS { +class SetEntranceListFactory : public SceneCommandFactory { + public: + std::shared_ptr<IResource> + ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) override; +}; + +class SetEntranceListFactoryV0 : public SceneCommandVersionFactory { + public: + void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SetExitListFactory.cpp b/mm/2s2h/resource/importer/scenecommand/SetExitListFactory.cpp new file mode 100644 index 000000000..4c5ddcb88 --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetExitListFactory.cpp @@ -0,0 +1,41 @@ +#include "2s2h/resource/importer/scenecommand/SetExitListFactory.h" +#include "2s2h/resource/type/scenecommand/SetExitList.h" +#include "spdlog/spdlog.h" + +namespace LUS { +std::shared_ptr<IResource> +SetExitListFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) { + auto resource = std::make_shared<SetExitList>( initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 0: + factory = std::make_shared<SetExitListFactoryV0>(); + break; + } + + if (factory == nullptr) { + SPDLOG_ERROR("Failed to load SetExitList with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileBinary(reader, resource); + + return resource; +} + +void LUS::SetExitListFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader, + std::shared_ptr<IResource> resource) { + std::shared_ptr<SetExitList> setExitList = std::static_pointer_cast<SetExitList>(resource); + ResourceVersionFactory::ParseFileBinary(reader, setExitList); + + ReadCommandId(setExitList, reader); + + setExitList->numExits = reader->ReadUInt32(); + setExitList->exits.reserve(setExitList->numExits); + for (uint32_t i = 0; i < setExitList->numExits; i++) { + setExitList->exits.push_back(reader->ReadUInt16()); + } +} + +} // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SetExitListFactory.h b/mm/2s2h/resource/importer/scenecommand/SetExitListFactory.h new file mode 100644 index 000000000..e04ab4ba0 --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetExitListFactory.h @@ -0,0 +1,16 @@ +#pragma once + +#include "2s2h/resource/importer/scenecommand/SceneCommandFactory.h" + +namespace LUS { +class SetExitListFactory : public SceneCommandFactory { + public: + std::shared_ptr<IResource> + ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) override; +}; + +class SetExitListFactoryV0 : public SceneCommandVersionFactory { + public: + void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SetLightListFactory.cpp b/mm/2s2h/resource/importer/scenecommand/SetLightListFactory.cpp new file mode 100644 index 000000000..ab83635bf --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetLightListFactory.cpp @@ -0,0 +1,58 @@ +#include "2s2h/resource/importer/scenecommand/SetLightListFactory.h" +#include "2s2h/resource/type/scenecommand/SetLightList.h" +#include "spdlog/spdlog.h" + +namespace LUS { +std::shared_ptr<IResource> +SetLightListFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) { + auto resource = std::make_shared<SetLightList>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 0: + factory = std::make_shared<SetLightListFactoryV0>(); + break; + } + + if (factory == nullptr) + { + SPDLOG_ERROR("Failed to load SetLightList with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileBinary(reader, resource); + + return resource; +} + +void LUS::SetLightListFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader, + std::shared_ptr<IResource> resource) +{ + std::shared_ptr<SetLightList> setLightList = std::static_pointer_cast<SetLightList>(resource); + ResourceVersionFactory::ParseFileBinary(reader, setLightList); + + ReadCommandId(setLightList, reader); + + setLightList->numLights = reader->ReadUInt32(); + setLightList->lightList.reserve(setLightList->numLights); + for (uint32_t i = 0; i < setLightList->numLights; i++) { + LightInfo light; + + light.type = reader->ReadUByte(); + + light.params.point.x = reader->ReadInt16(); + light.params.point.y = reader->ReadInt16(); + light.params.point.z = reader->ReadInt16(); + + light.params.point.color[0] = reader->ReadUByte(); // r + light.params.point.color[1] = reader->ReadUByte(); // g + light.params.point.color[2] = reader->ReadUByte(); // b + + light.params.point.drawGlow = reader->ReadUByte(); + light.params.point.radius = reader->ReadInt16(); + + setLightList->lightList.push_back(light); + } +} + +} // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SetLightListFactory.h b/mm/2s2h/resource/importer/scenecommand/SetLightListFactory.h new file mode 100644 index 000000000..c099b82c5 --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetLightListFactory.h @@ -0,0 +1,16 @@ +#pragma once + +#include "2s2h/resource/importer/scenecommand/SceneCommandFactory.h" + +namespace LUS { +class SetLightListFactory : public SceneCommandFactory { + public: + std::shared_ptr<IResource> + ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) override; +}; + +class SetLightListFactoryV0 : public SceneCommandVersionFactory { + public: + void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SetLightingSettingsFactory.cpp b/mm/2s2h/resource/importer/scenecommand/SetLightingSettingsFactory.cpp new file mode 100644 index 000000000..c13aeffec --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetLightingSettingsFactory.cpp @@ -0,0 +1,70 @@ +#include "2s2h/resource/importer/scenecommand/SetLightingSettingsFactory.h" +#include "2s2h/resource/type/scenecommand/SetLightingSettings.h" +#include "spdlog/spdlog.h" + +namespace LUS { +std::shared_ptr<IResource> SetLightingSettingsFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, + std::shared_ptr<BinaryReader> reader) { + auto resource = std::make_shared<SetLightingSettings>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 0: + factory = std::make_shared<SetLightingSettingsFactoryV0>(); + break; + } + + if (factory == nullptr) { + SPDLOG_ERROR("Failed to load SetLightingSettings with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileBinary(reader, resource); + + return resource; +} + +void LUS::SetLightingSettingsFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader, + std::shared_ptr<IResource> resource) +{ + std::shared_ptr<SetLightingSettings> setLightingSettings = std::static_pointer_cast<SetLightingSettings>(resource); + ResourceVersionFactory::ParseFileBinary(reader, setLightingSettings); + + ReadCommandId(setLightingSettings, reader); + + uint32_t count = reader->ReadInt32(); + setLightingSettings->settings.reserve(count); + + for (uint32_t i = 0; i < count; i++) { + EnvLightSettings lightSettings; + lightSettings.ambientColor[0] = reader->ReadInt8(); + lightSettings.ambientColor[1] = reader->ReadInt8(); + lightSettings.ambientColor[2] = reader->ReadInt8(); + + lightSettings.light1Dir[0] = reader->ReadInt8(); + lightSettings.light1Dir[1] = reader->ReadInt8(); + lightSettings.light1Dir[2] = reader->ReadInt8(); + + lightSettings.light1Color[0] = reader->ReadInt8(); + lightSettings.light1Color[1] = reader->ReadInt8(); + lightSettings.light1Color[2] = reader->ReadInt8(); + + lightSettings.light2Dir[0] = reader->ReadInt8(); + lightSettings.light2Dir[1] = reader->ReadInt8(); + lightSettings.light2Dir[2] = reader->ReadInt8(); + + lightSettings.light2Color[0] = reader->ReadInt8(); + lightSettings.light2Color[1] = reader->ReadInt8(); + lightSettings.light2Color[2] = reader->ReadInt8(); + + lightSettings.fogColor[0] = reader->ReadInt8(); + lightSettings.fogColor[1] = reader->ReadInt8(); + lightSettings.fogColor[2] = reader->ReadInt8(); + + lightSettings.fogNear = reader->ReadInt16(); + lightSettings.fogFar = reader->ReadUInt16(); + setLightingSettings->settings.push_back(lightSettings); + } +} + +} // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SetLightingSettingsFactory.h b/mm/2s2h/resource/importer/scenecommand/SetLightingSettingsFactory.h new file mode 100644 index 000000000..b25f85a97 --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetLightingSettingsFactory.h @@ -0,0 +1,16 @@ +#pragma once + +#include "2s2h/resource/importer/scenecommand/SceneCommandFactory.h" + +namespace LUS { +class SetLightingSettingsFactory : public SceneCommandFactory { + public: + std::shared_ptr<IResource> + ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) override; +}; + +class SetLightingSettingsFactoryV0 : public SceneCommandVersionFactory { + public: + void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SetMeshFactory.cpp b/mm/2s2h/resource/importer/scenecommand/SetMeshFactory.cpp new file mode 100644 index 000000000..dcb3f4c10 --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetMeshFactory.cpp @@ -0,0 +1,169 @@ +#include "2s2h/resource/importer/scenecommand/SetMeshFactory.h" +#include "2s2h/resource/type/scenecommand/SetMesh.h" +#include "spdlog/spdlog.h" +#include "libultraship/libultraship.h" + +namespace LUS { +std::shared_ptr<IResource> +SetMeshFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) { + auto resource = std::make_shared<SetMesh>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 0: + factory = std::make_shared<SetMeshFactoryV0>(); + break; + } + + if (factory == nullptr) + { + SPDLOG_ERROR("Failed to load SetMesh with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileBinary(reader, resource); + + return resource; +} + +void LUS::SetMeshFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader, + std::shared_ptr<IResource> resource) +{ + std::shared_ptr<SetMesh> setMesh = std::static_pointer_cast<SetMesh>(resource); + ResourceVersionFactory::ParseFileBinary(reader, setMesh); + + ReadCommandId(setMesh, reader); + + setMesh->data = reader->ReadInt8(); + + setMesh->meshHeader.base.type = reader->ReadInt8(); + int32_t polyNum = 1; + + if (setMesh->meshHeader.base.type != 1) { + polyNum = reader->ReadInt8(); + if (setMesh->meshHeader.base.type == 0) { + setMesh->meshHeader.polygon0.num = polyNum; + } else if (setMesh->meshHeader.base.type == 2) { + setMesh->meshHeader.polygon2.num = polyNum; + } else { + SPDLOG_ERROR("Tried to load mesh in SetMesh scene header with type that doesn't exist: {}", setMesh->meshHeader.base.type); + } + } + + if (setMesh->meshHeader.base.type == 2) { + setMesh->dlists2.reserve(polyNum); + } else { + setMesh->dlists.reserve(setMesh->meshHeader.polygon0.num); + } + + for (int32_t i = 0; i < polyNum; i++) { + if (setMesh->meshHeader.base.type == 0) { + PolygonDlist dlist; + + int32_t polyType = reader->ReadInt8(); // Unused + std::string meshOpa = reader->ReadString(); + std::string meshXlu = reader->ReadString(); + + auto opaRes = LUS::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(meshOpa.c_str()); + auto xluRes = LUS::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(meshXlu.c_str()); + dlist.opa = meshOpa != "" ? (Gfx*)(opaRes ? opaRes->GetRawPointer() : nullptr) : 0; + dlist.xlu = meshXlu != "" ? (Gfx*)(xluRes ? xluRes->GetRawPointer() : nullptr) : 0; + + setMesh->dlists.push_back(dlist); + } else if (setMesh->meshHeader.base.type == 1) { + PolygonDlist pType; + + setMesh->meshHeader.polygon1.format = reader->ReadUByte(); + std::string imgOpa = reader->ReadString(); + std::string imgXlu = reader->ReadString(); + + auto opaRes = LUS::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(imgOpa.c_str()); + auto xluRes = LUS::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(imgXlu.c_str()); + pType.opa = imgOpa != "" ? (Gfx*)(opaRes ? opaRes->GetRawPointer() : nullptr) : 0; + pType.xlu = imgXlu != "" ? (Gfx*)(xluRes ? xluRes->GetRawPointer() : nullptr) : 0; + + int32_t bgImageCount = reader->ReadUInt32(); + setMesh->images.reserve(bgImageCount); + + for (int32_t i = 0; i < bgImageCount; i++) { + BgImage image; + image.unk_00 = reader->ReadUInt16(); + image.id = reader->ReadUByte(); + std::string imagePath = "__OTR__" + reader->ReadString(); + setMesh->imagePaths.push_back(imagePath); + image.source = (void*)setMesh->imagePaths.back().c_str(); + image.unk_0C = reader->ReadUInt32(); + image.tlut = reader->ReadUInt32(); + image.width = reader->ReadUInt16(); + image.height = reader->ReadUInt16(); + image.fmt = reader->ReadUByte(); + image.siz = reader->ReadUByte(); + image.mode0 = reader->ReadUInt16(); + image.tlutCount = reader->ReadUInt16(); + + if (setMesh->meshHeader.polygon1.format == 1) { + setMesh->meshHeader.polygon1.single.source = image.source; + setMesh->meshHeader.polygon1.single.unk_0C = image.unk_0C; + setMesh->meshHeader.polygon1.single.tlut = (void*)image.tlut; // OTRTODO: type of bgimage.tlut should be uintptr_t + setMesh->meshHeader.polygon1.single.width = image.width; + setMesh->meshHeader.polygon1.single.height = image.height; + setMesh->meshHeader.polygon1.single.fmt = image.fmt; + setMesh->meshHeader.polygon1.single.siz = image.siz; + setMesh->meshHeader.polygon1.single.mode0 = image.mode0; + setMesh->meshHeader.polygon1.single.tlutCount = image.tlutCount; + } else { + setMesh->images.push_back(image); + } + } + + if (setMesh->meshHeader.polygon1.format != 1) { + setMesh->meshHeader.polygon1.multi.count = bgImageCount; + } + + int32_t polyType = reader->ReadInt8(); // Unused?? + + std::string meshOpa = reader->ReadString(); + std::string meshXlu = reader->ReadString(); + + opaRes = LUS::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(meshOpa.c_str()); + xluRes = LUS::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(meshXlu.c_str()); + pType.opa = meshOpa != "" ? (Gfx*)(opaRes ? opaRes->GetRawPointer() : nullptr) : 0; + pType.xlu = meshXlu != "" ? (Gfx*)(xluRes ? xluRes->GetRawPointer() : nullptr) : 0; + + setMesh->dlists.push_back(pType); + } else if (setMesh->meshHeader.base.type == 2) { + PolygonDlist2 dlist; + + int32_t polyType = reader->ReadInt8(); // Unused + dlist.pos.x = reader->ReadInt16(); + dlist.pos.y = reader->ReadInt16(); + dlist.pos.z = reader->ReadInt16(); + dlist.unk_06 = reader->ReadInt16(); + + std::string meshOpa = reader->ReadString(); + std::string meshXlu = reader->ReadString(); + + auto opaRes = LUS::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(meshOpa.c_str()); + auto xluRes = LUS::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(meshXlu.c_str()); + dlist.opa = meshOpa != "" ? (Gfx*)(opaRes ? opaRes->GetRawPointer() : nullptr) : 0; + dlist.xlu = meshXlu != "" ? (Gfx*)(xluRes ? xluRes->GetRawPointer() : nullptr) : 0; + + setMesh->dlists2.push_back(dlist); + } else { + SPDLOG_ERROR("Tried to load mesh in SetMesh scene header with type that doesn't exist: {}", setMesh->meshHeader.base.type); + } + } + + if (setMesh->meshHeader.base.type == 2) { + setMesh->meshHeader.polygon2.start = setMesh->dlists2.data(); + } else if (setMesh->meshHeader.base.type == 0) { + setMesh->meshHeader.polygon0.start = setMesh->dlists.data(); + } else if (setMesh->meshHeader.base.type == 1) { + setMesh->meshHeader.polygon1.multi.list = setMesh->images.data(); + setMesh->meshHeader.polygon1.dlist = (Gfx*)setMesh->dlists.data(); + } else { + SPDLOG_ERROR("Tried to load mesh in SetMesh scene header with type that doesn't exist: {}", setMesh->meshHeader.base.type); + } +} + +} // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SetMeshFactory.h b/mm/2s2h/resource/importer/scenecommand/SetMeshFactory.h new file mode 100644 index 000000000..3ae72fdbc --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetMeshFactory.h @@ -0,0 +1,16 @@ +#pragma once + +#include "2s2h/resource/importer/scenecommand/SceneCommandFactory.h" + +namespace LUS { +class SetMeshFactory : public SceneCommandFactory { + public: + std::shared_ptr<IResource> + ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) override; +}; + +class SetMeshFactoryV0 : public SceneCommandVersionFactory { + public: + void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SetMinimapChestsFactory.cpp b/mm/2s2h/resource/importer/scenecommand/SetMinimapChestsFactory.cpp new file mode 100644 index 000000000..dae215ab1 --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetMinimapChestsFactory.cpp @@ -0,0 +1,50 @@ +#include "2s2h/resource/importer/scenecommand/SetMinimapChestsFactory.h" +#include "2s2h/resource/type/scenecommand/SetMinimapChests.h" +#include "spdlog/spdlog.h" + +namespace LUS { + +std::shared_ptr<IResource> SetMinimapChestsFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, + std::shared_ptr<BinaryReader> reader) { + auto resource = std::make_shared<SetMinimapChests>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 0: + factory = std::make_shared<SetMinimapChestsFactoryV0>(); + break; + } + + if (factory == nullptr) { + SPDLOG_ERROR("Failed to load SetMinimapChestsFactory with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileBinary(reader, resource); + + return resource; +} + +void SetMinimapChestsFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader, + std::shared_ptr<IResource> resource) { + std::shared_ptr<SetMinimapChests> chests = std::static_pointer_cast<SetMinimapChests>(resource); + ResourceVersionFactory::ParseFileBinary(reader, chests); + + ReadCommandId(chests, reader); + + size_t size = reader->ReadUInt32(); + + chests->chests.reserve(size); + + for (size_t i = 0; i < size; i++) { + MinimapChestData d; + d.unk_0 = reader->ReadUInt16(); + d.unk_2 = reader->ReadUInt16(); + d.unk_4 = reader->ReadUInt16(); + d.unk_6 = reader->ReadUInt16(); + d.unk_8 = reader->ReadUInt16(); + chests->chests.emplace_back(d); + } +} + +} // namespace LUS
\ No newline at end of file diff --git a/mm/2s2h/resource/importer/scenecommand/SetMinimapChestsFactory.h b/mm/2s2h/resource/importer/scenecommand/SetMinimapChestsFactory.h new file mode 100644 index 000000000..941405c40 --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetMinimapChestsFactory.h @@ -0,0 +1,16 @@ +#pragma once + +#include "2s2h/resource/importer/scenecommand/SceneCommandFactory.h" + +namespace LUS { +class SetMinimapChestsFactory : public SceneCommandFactory { + public: + std::shared_ptr<IResource> ReadResource(std::shared_ptr<ResourceInitData> initData, + std::shared_ptr<BinaryReader> reader) override; +}; + +class SetMinimapChestsFactoryV0 : public SceneCommandVersionFactory { + public: + void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override; +}; +}
\ No newline at end of file diff --git a/mm/2s2h/resource/importer/scenecommand/SetMinimapListFactory.cpp b/mm/2s2h/resource/importer/scenecommand/SetMinimapListFactory.cpp new file mode 100644 index 000000000..43eb4b496 --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetMinimapListFactory.cpp @@ -0,0 +1,50 @@ +#include "2s2h/resource/importer/scenecommand/SetMinimapListFactory.h" +#include "2s2h/resource/type/scenecommand/SetMinimapList.h" +#include "spdlog/spdlog.h" + +namespace LUS { +std::shared_ptr<IResource> SetMinimapListFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, + std::shared_ptr<BinaryReader> reader) { + auto resource = std::make_shared<SetMinimapList>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 0: + factory = std::make_shared<SetMinimapListFactoryV0>(); + break; + } + + if (factory == nullptr) { + SPDLOG_ERROR("Failed to load SetMinimapListFactory with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileBinary(reader, resource); + + return resource; +} +void SetMinimapListFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader, + std::shared_ptr<IResource> resource) { + std::shared_ptr<SetMinimapList> mapList = std::static_pointer_cast<SetMinimapList>(resource); + + ResourceVersionFactory::ParseFileBinary(reader, mapList); + + ReadCommandId(mapList, reader); + + size_t size = reader->ReadUInt32(); + + mapList->list.scale = reader->ReadUInt16(); + mapList->entries.reserve(size); + + for (size_t i = 0; i < size; i++) { + MinimapEntryData data; + data.mapId = reader->ReadUInt16(); + data.unk2 = reader->ReadUInt16(); + data.unk4 = reader->ReadUInt16(); + data.unk6 = reader->ReadUInt16(); + data.unk8 = reader->ReadUInt16(); + mapList->entries.emplace_back(data); + } + mapList->list.entry = mapList->entries.data(); +} +} // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SetMinimapListFactory.h b/mm/2s2h/resource/importer/scenecommand/SetMinimapListFactory.h new file mode 100644 index 000000000..d8a5fd643 --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetMinimapListFactory.h @@ -0,0 +1,16 @@ +#pragma once + +#include "2s2h/resource/importer/scenecommand/SceneCommandFactory.h" + +namespace LUS { +class SetMinimapListFactory : public SceneCommandFactory { + public: + std::shared_ptr<IResource> ReadResource(std::shared_ptr<ResourceInitData> initData, + std::shared_ptr<BinaryReader> reader) override; +}; + +class SetMinimapListFactoryV0 : public SceneCommandVersionFactory { + public: + void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override; +}; +}; // namespace LUS
\ No newline at end of file diff --git a/mm/2s2h/resource/importer/scenecommand/SetObjectListFactory.cpp b/mm/2s2h/resource/importer/scenecommand/SetObjectListFactory.cpp new file mode 100644 index 000000000..274407c00 --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetObjectListFactory.cpp @@ -0,0 +1,42 @@ +#include "2s2h/resource/importer/scenecommand/SetObjectListFactory.h" +#include "2s2h/resource/type/scenecommand/SetObjectList.h" +#include "spdlog/spdlog.h" + +namespace LUS { +std::shared_ptr<IResource> +SetObjectListFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) { + auto resource = std::make_shared<SetObjectList>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 0: + factory = std::make_shared<SetObjectListFactoryV0>(); + break; + } + + if (factory == nullptr) { + SPDLOG_ERROR("Failed to load SetObjectList with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileBinary(reader, resource); + + return resource; +} + +void LUS::SetObjectListFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader, + std::shared_ptr<IResource> resource) +{ + std::shared_ptr<SetObjectList> setObjectList = std::static_pointer_cast<SetObjectList>(resource); + ResourceVersionFactory::ParseFileBinary(reader, setObjectList); + + ReadCommandId(setObjectList, reader); + + setObjectList->numObjects = reader->ReadUInt32(); + setObjectList->objects.reserve(setObjectList->numObjects); + for (uint32_t i = 0; i < setObjectList->numObjects; i++) { + setObjectList->objects.push_back(reader->ReadUInt16()); + } +} + +} // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SetObjectListFactory.h b/mm/2s2h/resource/importer/scenecommand/SetObjectListFactory.h new file mode 100644 index 000000000..b977576d3 --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetObjectListFactory.h @@ -0,0 +1,16 @@ +#pragma once + +#include "2s2h/resource/importer/scenecommand/SceneCommandFactory.h" + +namespace LUS { +class SetObjectListFactory : public SceneCommandFactory { + public: + std::shared_ptr<IResource> + ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) override; +}; + +class SetObjectListFactoryV0 : public SceneCommandVersionFactory { + public: + void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SetPathwaysFactory.cpp b/mm/2s2h/resource/importer/scenecommand/SetPathwaysFactory.cpp new file mode 100644 index 000000000..a361a0915 --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetPathwaysFactory.cpp @@ -0,0 +1,82 @@ +#include "2s2h/resource/importer/scenecommand/SetPathwaysFactory.h" +#include "2s2h/resource/type/scenecommand/SetPathways.h" +#include "spdlog/spdlog.h" +#include <libultraship/libultraship.h> + +namespace LUS { +std::shared_ptr<IResource> +SetPathwaysFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) { + auto resource = std::make_shared<SetPathways>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 0: + factory = std::make_shared<SetPathwaysFactoryV0>(); + break; + } + + if (factory == nullptr) { + SPDLOG_ERROR("Failed to load SetPathways with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileBinary(reader, resource); + + return resource; +} + +void LUS::SetPathwaysFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader, + std::shared_ptr<IResource> resource) { + std::shared_ptr<SetPathways> setPathways = std::static_pointer_cast<SetPathways>(resource); + ResourceVersionFactory::ParseFileBinary(reader, setPathways); + + ReadCommandId(setPathways, reader); + + setPathways->numPaths = reader->ReadUInt32(); + setPathways->paths.reserve(setPathways->numPaths); + for (uint32_t i = 0; i < setPathways->numPaths; i++) { + std::string pathFileName = reader->ReadString(); + auto path = std::static_pointer_cast<Path>(LUS::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(pathFileName.c_str())); + setPathways->paths.push_back(path->GetPointer()); + } +} + +std::shared_ptr<IResource> SetPathwaysMMFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, + std::shared_ptr<BinaryReader> reader) { + auto resource = std::make_shared<SetPathwaysMM>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 0: + factory = std::make_shared<SetPathwaysMMFactoryV0>(); + break; + } + + if (factory == nullptr) { + SPDLOG_ERROR("Failed to load SetPathwaysMM with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileBinary(reader, resource); + + return resource; +} + +void LUS::SetPathwaysMMFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader, + std::shared_ptr<IResource> resource) { + std::shared_ptr<SetPathwaysMM> setPathways = std::static_pointer_cast<SetPathwaysMM>(resource); + ResourceVersionFactory::ParseFileBinary(reader, setPathways); + + ReadCommandId(setPathways, reader); + + setPathways->numPaths = reader->ReadUInt32(); + setPathways->paths.reserve(setPathways->numPaths); + for (uint32_t i = 0; i < setPathways->numPaths; i++) { + std::string pathFileName = reader->ReadString(); + auto path = std::static_pointer_cast<PathMM>( + LUS::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(pathFileName.c_str())); + setPathways->paths.push_back(path->GetPointer()); + } +} + +} // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SetPathwaysFactory.h b/mm/2s2h/resource/importer/scenecommand/SetPathwaysFactory.h new file mode 100644 index 000000000..544ef02dc --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetPathwaysFactory.h @@ -0,0 +1,28 @@ +#pragma once + +#include "2s2h/resource/importer/scenecommand/SceneCommandFactory.h" + +namespace LUS { +class SetPathwaysFactory : public SceneCommandFactory { + public: + std::shared_ptr<IResource> + ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) override; +}; + +class SetPathwaysFactoryV0 : public SceneCommandVersionFactory { + public: + void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override; +}; + +class SetPathwaysMMFactory : public SceneCommandFactory { + public: + std::shared_ptr<IResource> ReadResource(std::shared_ptr<ResourceInitData> initData, + std::shared_ptr<BinaryReader> reader) override; +}; + +class SetPathwaysMMFactoryV0 : public SceneCommandVersionFactory { + public: + void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override; +}; + +}; // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SetRoomBehaviorFactory.cpp b/mm/2s2h/resource/importer/scenecommand/SetRoomBehaviorFactory.cpp new file mode 100644 index 000000000..6222eb3b6 --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetRoomBehaviorFactory.cpp @@ -0,0 +1,38 @@ +#include "2s2h/resource/importer/scenecommand/SetRoomBehaviorFactory.h" +#include "2s2h/resource/type/scenecommand/SetRoomBehavior.h" +#include "spdlog/spdlog.h" + +namespace LUS { +std::shared_ptr<IResource> +SetRoomBehaviorFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) { + auto resource = std::make_shared<SetRoomBehavior>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 0: + factory = std::make_shared<SetRoomBehaviorFactoryV0>(); + break; + } + + if (factory == nullptr) { + SPDLOG_ERROR("Failed to load SetRoomBehavior with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileBinary(reader, resource); + + return resource; +} + +void LUS::SetRoomBehaviorFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader, + std::shared_ptr<IResource> resource) { + std::shared_ptr<SetRoomBehavior> setRoomBehavior = std::static_pointer_cast<SetRoomBehavior>(resource); + ResourceVersionFactory::ParseFileBinary(reader, setRoomBehavior); + + ReadCommandId(setRoomBehavior, reader); + + setRoomBehavior->roomBehavior.gameplayFlags = reader->ReadInt8(); + setRoomBehavior->roomBehavior.gameplayFlags2 = reader->ReadInt32(); +} + +} // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SetRoomBehaviorFactory.h b/mm/2s2h/resource/importer/scenecommand/SetRoomBehaviorFactory.h new file mode 100644 index 000000000..de812249d --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetRoomBehaviorFactory.h @@ -0,0 +1,16 @@ +#pragma once + +#include "2s2h/resource/importer/scenecommand/SceneCommandFactory.h" + +namespace LUS { +class SetRoomBehaviorFactory : public SceneCommandFactory { + public: + std::shared_ptr<IResource> + ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) override; +}; + +class SetRoomBehaviorFactoryV0 : public SceneCommandVersionFactory { + public: + void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SetRoomListFactory.cpp b/mm/2s2h/resource/importer/scenecommand/SetRoomListFactory.cpp new file mode 100644 index 000000000..ac4040afa --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetRoomListFactory.cpp @@ -0,0 +1,50 @@ +#include "2s2h/resource/importer/scenecommand/SetRoomListFactory.h" +#include "2s2h/resource/type/scenecommand/SetRoomList.h" +#include "spdlog/spdlog.h" + +namespace LUS { +std::shared_ptr<IResource> +SetRoomListFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) { + auto resource = std::make_shared<SetRoomList>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 0: + factory = std::make_shared<SetRoomListFactoryV0>(); + break; + } + + if (factory == nullptr) + { + SPDLOG_ERROR("Failed to load SetRoomList with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileBinary(reader, resource); + + return resource; +} + +void LUS::SetRoomListFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader, + std::shared_ptr<IResource> resource) { + std::shared_ptr<SetRoomList> setRoomList = std::static_pointer_cast<SetRoomList>(resource); + ResourceVersionFactory::ParseFileBinary(reader, setRoomList); + + ReadCommandId(setRoomList, reader); + + setRoomList->numRooms = reader->ReadInt32(); + setRoomList->rooms.reserve(setRoomList->numRooms); + for (uint32_t i = 0; i < setRoomList->numRooms; i++) { + RomFile room; + + setRoomList->fileNames.push_back(reader->ReadString()); + + room.fileName = (char*)setRoomList->fileNames.back().c_str(); + room.vromStart = reader->ReadInt32(); + room.vromEnd = reader->ReadInt32(); + + setRoomList->rooms.push_back(room); + } +} + +} // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SetRoomListFactory.h b/mm/2s2h/resource/importer/scenecommand/SetRoomListFactory.h new file mode 100644 index 000000000..eeb099aa8 --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetRoomListFactory.h @@ -0,0 +1,16 @@ +#pragma once + +#include "2s2h/resource/importer/scenecommand/SceneCommandFactory.h" + +namespace LUS { +class SetRoomListFactory : public SceneCommandFactory { + public: + std::shared_ptr<IResource> + ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) override; +}; + +class SetRoomListFactoryV0 : public SceneCommandVersionFactory { + public: + void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SetSkyboxModifierFactory.cpp b/mm/2s2h/resource/importer/scenecommand/SetSkyboxModifierFactory.cpp new file mode 100644 index 000000000..c2670e0fd --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetSkyboxModifierFactory.cpp @@ -0,0 +1,38 @@ +#include "2s2h/resource/importer/scenecommand/SetSkyboxModifierFactory.h" +#include "2s2h/resource/type/scenecommand/SetSkyboxModifier.h" +#include "spdlog/spdlog.h" + +namespace LUS { +std::shared_ptr<IResource> SetSkyboxModifierFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, + std::shared_ptr<BinaryReader> reader) { + auto resource = std::make_shared<SetSkyboxModifier>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 0: + factory = std::make_shared<SetSkyboxModifierFactoryV0>(); + break; + } + + if (factory == nullptr) { + SPDLOG_ERROR("Failed to load SetSkyboxModifier with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileBinary(reader, resource); + + return resource; +} + +void LUS::SetSkyboxModifierFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader, + std::shared_ptr<IResource> resource) { + std::shared_ptr<SetSkyboxModifier> setSkyboxModifier = std::static_pointer_cast<SetSkyboxModifier>(resource); + ResourceVersionFactory::ParseFileBinary(reader, setSkyboxModifier); + + ReadCommandId(setSkyboxModifier, reader); + + setSkyboxModifier->modifier.skyboxDisabled = reader->ReadInt8(); + setSkyboxModifier->modifier.sunMoonDisabled = reader->ReadInt8(); +} + +} // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SetSkyboxModifierFactory.h b/mm/2s2h/resource/importer/scenecommand/SetSkyboxModifierFactory.h new file mode 100644 index 000000000..3880751fe --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetSkyboxModifierFactory.h @@ -0,0 +1,16 @@ +#pragma once + +#include "2s2h/resource/importer/scenecommand/SceneCommandFactory.h" + +namespace LUS { +class SetSkyboxModifierFactory : public SceneCommandFactory { + public: + std::shared_ptr<IResource> + ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) override; +}; + +class SetSkyboxModifierFactoryV0 : public SceneCommandVersionFactory { + public: + void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SetSkyboxSettingsFactory.cpp b/mm/2s2h/resource/importer/scenecommand/SetSkyboxSettingsFactory.cpp new file mode 100644 index 000000000..8ac3b91a4 --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetSkyboxSettingsFactory.cpp @@ -0,0 +1,40 @@ +#include "2s2h/resource/importer/scenecommand/SetSkyboxSettingsFactory.h" +#include "2s2h/resource/type/scenecommand/SetSkyboxSettings.h" +#include "spdlog/spdlog.h" + +namespace LUS { +std::shared_ptr<IResource> SetSkyboxSettingsFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, + std::shared_ptr<BinaryReader> reader) { + auto resource = std::make_shared<SetSkyboxSettings>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 0: + factory = std::make_shared<SetSkyboxSettingsFactoryV0>(); + break; + } + + if (factory == nullptr) { + SPDLOG_ERROR("Failed to load SetSkyboxSettings with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileBinary(reader, resource); + + return resource; +} + +void SetSkyboxSettingsFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader, + std::shared_ptr<IResource> resource) { + std::shared_ptr<SetSkyboxSettings> setSkyboxSettings = std::static_pointer_cast<SetSkyboxSettings>(resource); + ResourceVersionFactory::ParseFileBinary(reader, setSkyboxSettings); + + ReadCommandId(setSkyboxSettings, reader); + + setSkyboxSettings->settings.unk = reader->ReadInt8(); + setSkyboxSettings->settings.skyboxId = reader->ReadInt8(); + setSkyboxSettings->settings.weather = reader->ReadInt8(); + setSkyboxSettings->settings.indoors = reader->ReadInt8(); +} + +} // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SetSkyboxSettingsFactory.h b/mm/2s2h/resource/importer/scenecommand/SetSkyboxSettingsFactory.h new file mode 100644 index 000000000..c75c86673 --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetSkyboxSettingsFactory.h @@ -0,0 +1,16 @@ +#pragma once + +#include "2s2h/resource/importer/scenecommand/SceneCommandFactory.h" + +namespace LUS { +class SetSkyboxSettingsFactory : public SceneCommandFactory { + public: + std::shared_ptr<IResource> + ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) override; +}; + +class SetSkyboxSettingsFactoryV0 : public SceneCommandVersionFactory { + public: + void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SetSoundSettingsFactory.cpp b/mm/2s2h/resource/importer/scenecommand/SetSoundSettingsFactory.cpp new file mode 100644 index 000000000..98ee97f03 --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetSoundSettingsFactory.cpp @@ -0,0 +1,39 @@ +#include "2s2h/resource/importer/scenecommand/SetSoundSettingsFactory.h" +#include "2s2h/resource/type/scenecommand/SetSoundSettings.h" +#include "spdlog/spdlog.h" + +namespace LUS { +std::shared_ptr<IResource> SetSoundSettingsFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, + std::shared_ptr<BinaryReader> reader) { + auto resource = std::make_shared<SetSoundSettings>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 0: + factory = std::make_shared<SetSoundSettingsFactoryV0>(); + break; + } + + if (factory == nullptr) { + SPDLOG_ERROR("Failed to load SetSoundSettings with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileBinary(reader, resource); + + return resource; +} + +void LUS::SetSoundSettingsFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader, + std::shared_ptr<IResource> resource) { + std::shared_ptr<SetSoundSettings> setSoundSettings = std::static_pointer_cast<SetSoundSettings>(resource); + ResourceVersionFactory::ParseFileBinary(reader, setSoundSettings); + + ReadCommandId(setSoundSettings, reader); + + setSoundSettings->settings.reverb = reader->ReadInt8(); + setSoundSettings->settings.natureAmbienceId = reader->ReadInt8(); + setSoundSettings->settings.seqId = reader->ReadInt8(); +} + +} // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SetSoundSettingsFactory.h b/mm/2s2h/resource/importer/scenecommand/SetSoundSettingsFactory.h new file mode 100644 index 000000000..235c617a2 --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetSoundSettingsFactory.h @@ -0,0 +1,16 @@ +#pragma once + +#include "2s2h/resource/importer/scenecommand/SceneCommandFactory.h" + +namespace LUS { +class SetSoundSettingsFactory : public SceneCommandFactory { + public: + std::shared_ptr<IResource> + ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) override; +}; + +class SetSoundSettingsFactoryV0 : public SceneCommandVersionFactory { + public: + void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SetSpecialObjectsFactory.cpp b/mm/2s2h/resource/importer/scenecommand/SetSpecialObjectsFactory.cpp new file mode 100644 index 000000000..35fc6614e --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetSpecialObjectsFactory.cpp @@ -0,0 +1,38 @@ +#include "2s2h/resource/importer/scenecommand/SetSpecialObjectsFactory.h" +#include "2s2h/resource/type/scenecommand/SetSpecialObjects.h" +#include "spdlog/spdlog.h" + +namespace LUS { +std::shared_ptr<IResource> SetSpecialObjectsFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, + std::shared_ptr<BinaryReader> reader) { + auto resource = std::make_shared<SetSpecialObjects>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 0: + factory = std::make_shared<SetSpecialObjectsFactoryV0>(); + break; + } + + if (factory == nullptr){ + SPDLOG_ERROR("Failed to load SetSpecialObjects with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileBinary(reader, resource); + + return resource; +} + +void LUS::SetSpecialObjectsFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader, + std::shared_ptr<IResource> resource) { + std::shared_ptr<SetSpecialObjects> setSpecialObjects = std::static_pointer_cast<SetSpecialObjects>(resource); + ResourceVersionFactory::ParseFileBinary(reader, setSpecialObjects); + + ReadCommandId(setSpecialObjects, reader); + + setSpecialObjects->specialObjects.elfMessage = reader->ReadInt8(); + setSpecialObjects->specialObjects.globalObject = reader->ReadInt16(); +} + +} // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SetSpecialObjectsFactory.h b/mm/2s2h/resource/importer/scenecommand/SetSpecialObjectsFactory.h new file mode 100644 index 000000000..b62180a45 --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetSpecialObjectsFactory.h @@ -0,0 +1,16 @@ +#pragma once + +#include "2s2h/resource/importer/scenecommand/SceneCommandFactory.h" + +namespace LUS { +class SetSpecialObjectsFactory : public SceneCommandFactory { + public: + std::shared_ptr<IResource> + ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) override; +}; + +class SetSpecialObjectsFactoryV0 : public SceneCommandVersionFactory { + public: + void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SetStartPositionListFactory.cpp b/mm/2s2h/resource/importer/scenecommand/SetStartPositionListFactory.cpp new file mode 100644 index 000000000..9d95a01ce --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetStartPositionListFactory.cpp @@ -0,0 +1,55 @@ +#include "2s2h/resource/importer/scenecommand/SetStartPositionListFactory.h" +#include "2s2h/resource/type/scenecommand/SetStartPositionList.h" +#include "spdlog/spdlog.h" + +namespace LUS { +std::shared_ptr<IResource> SetStartPositionListFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, + std::shared_ptr<BinaryReader> reader) { + auto resource = std::make_shared<SetStartPositionList>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) + { + case 0: + factory = std::make_shared<SetStartPositionListFactoryV0>(); + break; + } + + if (factory == nullptr) + { + SPDLOG_ERROR("Failed to load SetStartPositionList with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileBinary(reader, resource); + + return resource; +} + +void LUS::SetStartPositionListFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader, + std::shared_ptr<IResource> resource) +{ + std::shared_ptr<SetStartPositionList> setStartPositionList = std::static_pointer_cast<SetStartPositionList>(resource); + ResourceVersionFactory::ParseFileBinary(reader, setStartPositionList); + + ReadCommandId(setStartPositionList, reader); + + setStartPositionList->numStartPositions = reader->ReadUInt32(); + setStartPositionList->startPositions.reserve(setStartPositionList->numStartPositions); + for (uint32_t i = 0; i < setStartPositionList->numStartPositions; i++) { + ActorEntry entry; + + entry.id = reader->ReadUInt16(); + entry.pos.x = reader->ReadInt16(); + entry.pos.y = reader->ReadInt16(); + entry.pos.z = reader->ReadInt16(); + entry.rot.x = reader->ReadInt16(); + entry.rot.y = reader->ReadInt16(); + entry.rot.z = reader->ReadInt16(); + entry.params = reader->ReadUInt16(); + + setStartPositionList->startPositions.push_back(entry); + } +} + +} // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SetStartPositionListFactory.h b/mm/2s2h/resource/importer/scenecommand/SetStartPositionListFactory.h new file mode 100644 index 000000000..b029f3a1e --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetStartPositionListFactory.h @@ -0,0 +1,16 @@ +#pragma once + +#include "2s2h/resource/importer/scenecommand/SceneCommandFactory.h" + +namespace LUS { +class SetStartPositionListFactory : public SceneCommandFactory { + public: + std::shared_ptr<IResource> + ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) override; +}; + +class SetStartPositionListFactoryV0 : public SceneCommandVersionFactory { + public: + void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SetTimeSettingsFactory.cpp b/mm/2s2h/resource/importer/scenecommand/SetTimeSettingsFactory.cpp new file mode 100644 index 000000000..e3f2d77e5 --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetTimeSettingsFactory.cpp @@ -0,0 +1,39 @@ +#include "2s2h/resource/importer/scenecommand/SetTimeSettingsFactory.h" +#include "2s2h/resource/type/scenecommand/SetTimeSettings.h" +#include "spdlog/spdlog.h" + +namespace LUS { +std::shared_ptr<IResource> +SetTimeSettingsFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) { + auto resource = std::make_shared<SetTimeSettings>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 0: + factory = std::make_shared<SetTimeSettingsFactoryV0>(); + break; + } + + if (factory == nullptr) { + SPDLOG_ERROR("Failed to load SetTimeSettings with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileBinary(reader, resource); + + return resource; +} + +void LUS::SetTimeSettingsFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader, + std::shared_ptr<IResource> resource) { + std::shared_ptr<SetTimeSettings> setTimeSettings = std::static_pointer_cast<SetTimeSettings>(resource); + ResourceVersionFactory::ParseFileBinary(reader, setTimeSettings); + + ReadCommandId(setTimeSettings, reader); + + setTimeSettings->settings.hour = reader->ReadInt8(); + setTimeSettings->settings.minute = reader->ReadInt8(); + setTimeSettings->settings.timeIncrement = reader->ReadInt8(); +} + +} // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SetTimeSettingsFactory.h b/mm/2s2h/resource/importer/scenecommand/SetTimeSettingsFactory.h new file mode 100644 index 000000000..1482c2892 --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetTimeSettingsFactory.h @@ -0,0 +1,16 @@ +#pragma once + +#include "2s2h/resource/importer/scenecommand/SceneCommandFactory.h" + +namespace LUS { +class SetTimeSettingsFactory : public SceneCommandFactory { + public: + std::shared_ptr<IResource> + ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) override; +}; + +class SetTimeSettingsFactoryV0 : public SceneCommandVersionFactory { + public: + void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SetTransitionActorListFactory.cpp b/mm/2s2h/resource/importer/scenecommand/SetTransitionActorListFactory.cpp new file mode 100644 index 000000000..611897fbe --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetTransitionActorListFactory.cpp @@ -0,0 +1,54 @@ +#include "2s2h/resource/importer/scenecommand/SetTransitionActorListFactory.h" +#include "2s2h/resource/type/scenecommand/SetTransitionActorList.h" +#include "spdlog/spdlog.h" + +namespace LUS { +std::shared_ptr<IResource> SetTransitionActorListFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, + std::shared_ptr<BinaryReader> reader) { + auto resource = std::make_shared<SetTransitionActorList>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 0: + factory = std::make_shared<SetTransitionActorListFactoryV0>(); + break; + } + + if (factory == nullptr) { + SPDLOG_ERROR("Failed to load SetTransitionActorList with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileBinary(reader, resource); + + return resource; +} + +void LUS::SetTransitionActorListFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader, + std::shared_ptr<IResource> resource) { + std::shared_ptr<SetTransitionActorList> setTransitionActorList = std::static_pointer_cast<SetTransitionActorList>(resource); + ResourceVersionFactory::ParseFileBinary(reader, setTransitionActorList); + + ReadCommandId(setTransitionActorList, reader); + + setTransitionActorList->numTransitionActors = reader->ReadUInt32(); + setTransitionActorList->transitionActorList.reserve(setTransitionActorList->numTransitionActors); + for (uint32_t i = 0; i < setTransitionActorList->numTransitionActors; i++) { + TransitionActorEntry entry; + + entry.sides[0].room = reader->ReadUByte(); + entry.sides[0].effects = reader->ReadUByte(); + entry.sides[1].room = reader->ReadUByte(); + entry.sides[1].effects = reader->ReadUByte(); + entry.id = reader->ReadInt16(); + entry.pos.x = reader->ReadInt16(); + entry.pos.y = reader->ReadInt16(); + entry.pos.z = reader->ReadInt16(); + entry.rotY = reader->ReadInt16(); + entry.params = reader->ReadUInt16(); + + setTransitionActorList->transitionActorList.push_back(entry); + } +} + +} // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SetTransitionActorListFactory.h b/mm/2s2h/resource/importer/scenecommand/SetTransitionActorListFactory.h new file mode 100644 index 000000000..d300fdf3c --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetTransitionActorListFactory.h @@ -0,0 +1,16 @@ +#pragma once + +#include "2s2h/resource/importer/scenecommand/SceneCommandFactory.h" + +namespace LUS { +class SetTransitionActorListFactory : public SceneCommandFactory { + public: + std::shared_ptr<IResource> + ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) override; +}; + +class SetTransitionActorListFactoryV0 : public SceneCommandVersionFactory { + public: + void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SetWindSettingsFactory.cpp b/mm/2s2h/resource/importer/scenecommand/SetWindSettingsFactory.cpp new file mode 100644 index 000000000..74b3e78ab --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetWindSettingsFactory.cpp @@ -0,0 +1,40 @@ +#include "2s2h/resource/importer/scenecommand/SetWindSettingsFactory.h" +#include "2s2h/resource/type/scenecommand/SetWindSettings.h" +#include "spdlog/spdlog.h" + +namespace LUS { +std::shared_ptr<IResource> +SetWindSettingsFactory::ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) { + auto resource = std::make_shared<SetWindSettings>(initData); + std::shared_ptr<ResourceVersionFactory> factory = nullptr; + + switch (resource->GetInitData()->ResourceVersion) { + case 0: + factory = std::make_shared<SetWindSettingsFactoryV0>(); + break; + } + + if (factory == nullptr) { + SPDLOG_ERROR("Failed to load SetWindSettings with version {}", resource->GetInitData()->ResourceVersion); + return nullptr; + } + + factory->ParseFileBinary(reader, resource); + + return resource; +} + +void LUS::SetWindSettingsFactoryV0::ParseFileBinary(std::shared_ptr<BinaryReader> reader, + std::shared_ptr<IResource> resource) { + std::shared_ptr<SetWindSettings> setWind = std::static_pointer_cast<SetWindSettings>(resource); + ResourceVersionFactory::ParseFileBinary(reader, setWind); + + ReadCommandId(setWind, reader); + + setWind->settings.windWest = reader->ReadInt8(); + setWind->settings.windVertical = reader->ReadInt8(); + setWind->settings.windSouth = reader->ReadInt8(); + setWind->settings.windSpeed = reader->ReadUByte(); +} + +} // namespace LUS diff --git a/mm/2s2h/resource/importer/scenecommand/SetWindSettingsFactory.h b/mm/2s2h/resource/importer/scenecommand/SetWindSettingsFactory.h new file mode 100644 index 000000000..b4fb4d615 --- /dev/null +++ b/mm/2s2h/resource/importer/scenecommand/SetWindSettingsFactory.h @@ -0,0 +1,16 @@ +#pragma once + +#include "2s2h/resource/importer/scenecommand/SceneCommandFactory.h" + +namespace LUS { +class SetWindSettingsFactory : public SceneCommandFactory { + public: + std::shared_ptr<IResource> + ReadResource(std::shared_ptr<ResourceInitData> initData, std::shared_ptr<BinaryReader> reader) override; +}; + +class SetWindSettingsFactoryV0 : public SceneCommandVersionFactory { + public: + void ParseFileBinary(std::shared_ptr<BinaryReader> reader, std::shared_ptr<IResource> resource) override; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/type/Animation.cpp b/mm/2s2h/resource/type/Animation.cpp new file mode 100644 index 000000000..46327c732 --- /dev/null +++ b/mm/2s2h/resource/type/Animation.cpp @@ -0,0 +1,21 @@ +#include "Animation.h" + +namespace LUS { +AnimationData* Animation::GetPointer() { + return &animationData; +} + +size_t Animation::GetPointerSize() { + switch(type) { + case AnimationType::Normal: + return sizeof(animationData.animationHeader); + case AnimationType::Link: + return sizeof(animationData.linkAnimationHeader); + case AnimationType::Curve: + return sizeof(animationData.transformUpdateIndex); + case AnimationType::Legacy: + default: + return 0; + } +} +} // namespace LUS
\ No newline at end of file diff --git a/mm/2s2h/resource/type/Animation.h b/mm/2s2h/resource/type/Animation.h new file mode 100644 index 000000000..3d6b810bf --- /dev/null +++ b/mm/2s2h/resource/type/Animation.h @@ -0,0 +1,87 @@ +#pragma once + +#include "Resource.h" +#include <libultraship/libultra/types.h> + +namespace LUS { + enum class AnimationType { + Normal = 0, + Link = 1, + Curve = 2, + Legacy = 3, + }; + + struct RotationIndex { + uint16_t x, y, z; + + RotationIndex(uint16_t nX, uint16_t nY, uint16_t nZ) : x(nX), y(nY), z(nZ) { + } + }; + + typedef struct { + /* 0x0000 */ u16 unk_00; // appears to be flags + /* 0x0002 */ s16 unk_02; + /* 0x0004 */ s16 unk_04; + /* 0x0006 */ s16 unk_06; + /* 0x0008 */ f32 unk_08; + } TransformData; // size = 0xC + + typedef struct { + /* 0x0000 */ u8* refIndex; + /* 0x0004 */ TransformData* transformData; + /* 0x0008 */ s16* copyValues; + /* 0x000C */ s16 unk_0C; + /* 0x000E */ s16 unk_0E; + } TransformUpdateIndex; // size = 0x10 + + typedef struct { + /* 0x00 */ s16 frameCount; + } AnimationHeaderCommon; + + // Index into the frame data table. + typedef struct { + /* 0x00 */ u16 x; + /* 0x02 */ u16 y; + /* 0x04 */ u16 z; + } JointIndex; // size = 0x06 + + typedef struct { + /* 0x00 */ AnimationHeaderCommon common; + /* 0x04 */ s16* frameData; // "tbl" + /* 0x08 */ JointIndex* jointIndices; // "ref_tbl" + /* 0x0C */ u16 staticIndexMax; + } AnimationHeader; // size = 0x10 + + typedef struct { + /* 0x00 */ AnimationHeaderCommon common; + /* 0x04 */ void* segment; + } LinkAnimationHeader; // size = 0x8 + + union AnimationData { + AnimationHeader animationHeader; + LinkAnimationHeader linkAnimationHeader; + TransformUpdateIndex transformUpdateIndex; + }; + + class Animation : public Resource<AnimationData> { + public: + using Resource::Resource; + + Animation() : Resource(std::shared_ptr<ResourceInitData>()) {} + + AnimationData* GetPointer(); + size_t GetPointerSize(); + + AnimationType type; + AnimationData animationData; + + // NORMAL + std::vector<uint16_t> rotationValues; + std::vector<RotationIndex> rotationIndices; + + // CURVE + std::vector<uint8_t> refIndexArr; + std::vector<TransformData> transformDataArr; + std::vector<int16_t> copyValuesArr; + }; +}; // namespace LUS
\ No newline at end of file diff --git a/mm/2s2h/resource/type/AudioSample.cpp b/mm/2s2h/resource/type/AudioSample.cpp new file mode 100644 index 000000000..951aae6c1 --- /dev/null +++ b/mm/2s2h/resource/type/AudioSample.cpp @@ -0,0 +1,11 @@ +#include "AudioSample.h" + +namespace LUS { +Sample* AudioSample::GetPointer() { + return &sample; +} + +size_t AudioSample::GetPointerSize() { + return sizeof(Sample); +} +} // namespace LUS
\ No newline at end of file diff --git a/mm/2s2h/resource/type/AudioSample.h b/mm/2s2h/resource/type/AudioSample.h new file mode 100644 index 000000000..eda8aa456 --- /dev/null +++ b/mm/2s2h/resource/type/AudioSample.h @@ -0,0 +1,61 @@ +#pragma once + +#include <cstdint> +#include <vector> +#include "Resource.h" +#include <libultraship/libultra/types.h> + +namespace LUS { + typedef struct { + /* 0x00 */ uintptr_t start; + /* 0x04 */ uintptr_t end; + /* 0x08 */ u32 count; + /* 0x0C */ char unk_0C[0x4]; + /* 0x10 */ s16 state[16]; // only exists if count != 0. 8-byte aligned + } AdpcmLoop; // size = 0x30 (or 0x10) + + typedef struct { + /* 0x00 */ s32 order; + /* 0x04 */ s32 npredictors; + /* 0x08 */ s16* book; // size 8 * order * npredictors. 8-byte aligned + } AdpcmBook; // s + + typedef struct { + union { + struct { + /* 0x00 */ u32 codec : 4; + /* 0x00 */ u32 medium : 2; + /* 0x00 */ u32 unk_bit26 : 1; + /* 0x00 */ u32 unk_bit25 : 1; // this has been named isRelocated in zret + /* 0x01 */ u32 size : 24; + }; + u32 asU32; + }; + + /* 0x04 */ u8* sampleAddr; + /* 0x08 */ AdpcmLoop* loop; + /* 0x0C */ AdpcmBook* book; + u32 sampleRateMagicValue; // For wav samples only... + s32 sampleRate; // For wav samples only... + } Sample; // size = 0x10 + + class AudioSample : public Resource<Sample> { + public: + using Resource::Resource; + + AudioSample() : Resource(std::shared_ptr<ResourceInitData>()) {} + + Sample* GetPointer(); + size_t GetPointerSize(); + + Sample sample; + std::vector<uint8_t> audioSampleData; + + AdpcmLoop loop; + uint32_t loopStateCount; + + AdpcmBook book; + uint32_t bookDataCount; + std::vector<int16_t> bookData; + }; +}; // namespace LUS diff --git a/mm/2s2h/resource/type/AudioSequence.cpp b/mm/2s2h/resource/type/AudioSequence.cpp new file mode 100644 index 000000000..c09514a67 --- /dev/null +++ b/mm/2s2h/resource/type/AudioSequence.cpp @@ -0,0 +1,12 @@ +#include "AudioSequence.h" + +namespace LUS { + +Sequence* AudioSequence::GetPointer() { + return &sequence; +} + +size_t AudioSequence::GetPointerSize() { + return sizeof(Sequence); +} +} // namespace LUS diff --git a/mm/2s2h/resource/type/AudioSequence.h b/mm/2s2h/resource/type/AudioSequence.h new file mode 100644 index 000000000..2b2bb8be9 --- /dev/null +++ b/mm/2s2h/resource/type/AudioSequence.h @@ -0,0 +1,32 @@ +#pragma once + +#include <cstdint> +#include <vector> +#include "Resource.h" +#include <libultraship/libultra/types.h> + +namespace LUS { + +typedef struct { + char* seqData; + int32_t seqDataSize; + uint16_t seqNumber; + uint8_t medium; + uint8_t cachePolicy; + int32_t numFonts; + uint8_t fonts[16]; +} Sequence; + +class AudioSequence : public Resource<Sequence> { +public: + using Resource::Resource; + + AudioSequence() : Resource(std::shared_ptr<ResourceInitData>()) {} + + Sequence* GetPointer(); + size_t GetPointerSize(); + + Sequence sequence; + std::vector<char> sequenceData; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/type/AudioSoundFont.cpp b/mm/2s2h/resource/type/AudioSoundFont.cpp new file mode 100644 index 000000000..43ac40abf --- /dev/null +++ b/mm/2s2h/resource/type/AudioSoundFont.cpp @@ -0,0 +1,11 @@ +#include "AudioSoundFont.h" + +namespace LUS { +SoundFont* AudioSoundFont::GetPointer() { + return &soundFont; +} + +size_t AudioSoundFont::GetPointerSize() { + return sizeof(SoundFont); +} +} // namespace LUS diff --git a/mm/2s2h/resource/type/AudioSoundFont.h b/mm/2s2h/resource/type/AudioSoundFont.h new file mode 100644 index 000000000..99b18b401 --- /dev/null +++ b/mm/2s2h/resource/type/AudioSoundFont.h @@ -0,0 +1,84 @@ +#pragma once + +#include <cstdint> +#include <vector> +#include "Resource.h" +#include "2s2h/resource/type/AudioSample.h" +#include <libultraship/libultra/types.h> + +namespace LUS { + +typedef struct { + /* 0x0 */ s16 delay; + /* 0x2 */ s16 arg; +} AdsrEnvelope; // size = 0x4 + +typedef struct { + /* 0x00 */ Sample* sample; + /* 0x04 */ union { + u32 tuningAsU32; + f32 tuning;// frequency scale factor + }; +} SoundFontSound; // size = 0x8 + +typedef struct { + /* 0x00 */ u8 loaded; + /* 0x01 */ u8 normalRangeLo; + /* 0x02 */ u8 normalRangeHi; + /* 0x03 */ u8 releaseRate; + /* 0x04 */ AdsrEnvelope* envelope; + /* 0x08 */ SoundFontSound lowNotesSound; + /* 0x10 */ SoundFontSound normalNotesSound; + /* 0x18 */ SoundFontSound highNotesSound; +} Instrument; // size = 0x20 + +typedef struct { + /* 0x00 */ u8 releaseRate; + /* 0x01 */ u8 pan; + /* 0x02 */ u8 loaded; + /* 0x04 */ SoundFontSound sound; + /* 0x14 */ AdsrEnvelope* envelope; +} Drum; // size = 0x14 + +typedef struct { + /* 0x00 */ u8 numInstruments; + /* 0x01 */ u8 numDrums; + /* 0x02 */ u8 sampleBankId1; + /* 0x03 */ u8 sampleBankId2; + /* 0x04 */ u16 numSfx; + /* 0x08 */ Instrument** instruments; + /* 0x0C */ Drum** drums; + /* 0x10 */ SoundFontSound* soundEffects; + s32 fntIndex; +} SoundFont; // size = 0x14 + +class AudioSoundFont : public Resource<SoundFont> { +public: + using Resource::Resource; + + AudioSoundFont() : Resource(std::shared_ptr<ResourceInitData>()) {} + + SoundFont* GetPointer(); + size_t GetPointerSize(); + + int8_t medium; + int8_t cachePolicy; + uint16_t data1; + uint16_t data2; + uint16_t data3; + + std::vector<Drum> drums; + std::vector<Drum*> drumAddresses; + std::vector<uint32_t> drumEnvelopeCounts; + std::vector<std::vector<AdsrEnvelope>> drumEnvelopeArrays; + + std::vector<Instrument> instruments; + std::vector<Instrument*> instrumentAddresses; + std::vector<uint32_t> instrumentEnvelopeCounts; + std::vector<std::vector<AdsrEnvelope>> instrumentEnvelopeArrays; + + std::vector<SoundFontSound> soundEffects; + + SoundFont soundFont; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/type/Background.cpp b/mm/2s2h/resource/type/Background.cpp new file mode 100644 index 000000000..bc1047b5c --- /dev/null +++ b/mm/2s2h/resource/type/Background.cpp @@ -0,0 +1,11 @@ +#include "Background.h" + +namespace LUS { +uint8_t* Background::GetPointer() { + return Data.data(); +} + +size_t Background::GetPointerSize() { + return Data.size() * sizeof(uint8_t); +} +} // namespace LUS diff --git a/mm/2s2h/resource/type/Background.h b/mm/2s2h/resource/type/Background.h new file mode 100644 index 000000000..7f22658e0 --- /dev/null +++ b/mm/2s2h/resource/type/Background.h @@ -0,0 +1,17 @@ +#pragma once + +#include "resource/Resource.h" + +namespace LUS { +class Background : public Resource<uint8_t> { + public: + using Resource::Resource; + + Background() : Resource(std::shared_ptr<ResourceInitData>()) {} + + uint8_t* GetPointer(); + size_t GetPointerSize(); + + std::vector<uint8_t> Data; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/type/CollisionHeader.cpp b/mm/2s2h/resource/type/CollisionHeader.cpp new file mode 100644 index 000000000..5625d2b59 --- /dev/null +++ b/mm/2s2h/resource/type/CollisionHeader.cpp @@ -0,0 +1,11 @@ +#include "CollisionHeader.h" + +namespace LUS { +CollisionHeaderData* CollisionHeader::GetPointer() { + return &collisionHeaderData; +} + +size_t CollisionHeader::GetPointerSize() { + return sizeof(collisionHeaderData); +} +} // namespace LUS
\ No newline at end of file diff --git a/mm/2s2h/resource/type/CollisionHeader.h b/mm/2s2h/resource/type/CollisionHeader.h new file mode 100644 index 000000000..e401aa7f5 --- /dev/null +++ b/mm/2s2h/resource/type/CollisionHeader.h @@ -0,0 +1,98 @@ +#pragma once + +#include <cstdint> +#include <vector> +#include "Resource.h" +#include <libultraship/libultra.h> +#include "z64math.h" + +namespace LUS { + +typedef struct { + /* 0x00 */ u16 type; + union { + u16 vtxData[3]; + struct { + /* 0x02 */ u16 flags_vIA; // 0xE000 is poly exclusion flags (xpFlags), 0x1FFF is vtxId + /* 0x04 */ u16 flags_vIB; // 0xE000 is flags, 0x1FFF is vtxId + // 0x2000 = poly IsConveyor surface + /* 0x06 */ u16 vIC; + }; + }; + /* 0x08 */ Vec3s normal; // Unit normal vector + // Value ranges from -0x7FFF to 0x7FFF, representing -1.0 to 1.0; 0x8000 is invalid + + /* 0x0E */ s16 dist; // Plane distance from origin along the normal +} CollisionPoly; // size = 0x10 + +typedef struct { + /* 0x00 */ s16 xMin; + /* 0x02 */ s16 ySurface; + /* 0x04 */ s16 zMin; + /* 0x06 */ s16 xLength; + /* 0x08 */ s16 zLength; + /* 0x0C */ u32 properties; + + // 0x0008_0000 = ? + // 0x0007_E000 = Room Index, 0x3F = all rooms + // 0x0000_1F00 = Lighting Settings Index + // 0x0000_00FF = CamData index +} WaterBox; // size = 0x10 + +typedef struct { + /* 0x00 */ u16 cameraSType; + /* 0x02 */ s16 numCameras; + /* 0x04 */ Vec3s* camPosData; +} CamData; + +typedef struct { + u32 data[2]; + + // Type 1 + // 0x0800_0000 = wall damage +} SurfaceType; + + +typedef struct { + /* 0x00 */ Vec3s minBounds; // minimum coordinates of poly bounding box + /* 0x06 */ Vec3s maxBounds; // maximum coordinates of poly bounding box + /* 0x0C */ u16 numVertices; + /* 0x10 */ Vec3s* vtxList; + /* 0x14 */ u16 numPolygons; + /* 0x18 */ CollisionPoly* polyList; + /* 0x1C */ SurfaceType* surfaceTypeList; + /* 0x20 */ CamData* cameraDataList; + /* 0x24 */ u16 numWaterBoxes; + /* 0x28 */ WaterBox* waterBoxes; + size_t cameraDataListLen; // OTRTODO: Added to allow for bounds checking the cameraDataList. +} CollisionHeaderData; // original name: BGDataInfo + +class CollisionHeader : public Resource<CollisionHeaderData> { +public: + using Resource::Resource; + + CollisionHeader() : Resource(std::shared_ptr<ResourceInitData>()) {} + + CollisionHeaderData* GetPointer(); + size_t GetPointerSize(); + + CollisionHeaderData collisionHeaderData; + + std::vector<Vec3s> vertices; + + std::vector<CollisionPoly> polygons; + + uint32_t surfaceTypesCount; + std::vector<SurfaceType> surfaceTypes; + + uint32_t camDataCount; + std::vector<CamData> camData; + std::vector<int32_t> camPosDataIndices; + + int32_t camPosCount; + Vec3s camPosDataZero; + std::vector<Vec3s> camPosData; + + std::vector<WaterBox> waterBoxes; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/type/Cutscene.cpp b/mm/2s2h/resource/type/Cutscene.cpp new file mode 100644 index 000000000..c7e98062a --- /dev/null +++ b/mm/2s2h/resource/type/Cutscene.cpp @@ -0,0 +1,12 @@ +#include "Cutscene.h" +#include <libultraship/libultra/gbi.h> + +namespace LUS { +uint32_t* Cutscene::GetPointer() { + return commands.data(); +} + +size_t Cutscene::GetPointerSize() { + return commands.size() * sizeof(uint32_t); +} +} // namespace LUS
\ No newline at end of file diff --git a/mm/2s2h/resource/type/Cutscene.h b/mm/2s2h/resource/type/Cutscene.h new file mode 100644 index 000000000..5bd268e61 --- /dev/null +++ b/mm/2s2h/resource/type/Cutscene.h @@ -0,0 +1,71 @@ +#pragma once + +#include <vector> +#include <string> +#include "Resource.h" +#include "Vec2f.h" +#include "Vec3f.h" +#include "Color3b.h" + +namespace LUS { + +enum class CutsceneCommands { + Cmd00 = 0x0000, + SetCameraPos = 0x0001, + SetCameraFocus = 0x0002, + SpecialAction = 0x0003, + SetLighting = 0x0004, + SetCameraPosLink = 0x0005, + SetCameraFocusLink = 0x0006, + Cmd07 = 0x0007, + Cmd08 = 0x0008, + Cmd09 = 0x0009, + Unknown = 0x001A, + Textbox = 0x0013, + SetActorAction0 = 0x000A, + SetActorAction1 = 0x000F, + SetActorAction2 = 0x000E, + SetActorAction3 = 0x0019, + SetActorAction4 = 0x001D, + SetActorAction5 = 0x001E, + SetActorAction6 = 0x002C, + SetActorAction7 = 0x001F, + SetActorAction8 = 0x0031, + SetActorAction9 = 0x003E, + SetActorAction10 = 0x008F, + SetSceneTransFX = 0x002D, + Nop = 0x000B, + PlayBGM = 0x0056, + StopBGM = 0x0057, + FadeBGM = 0x007C, + SetTime = 0x008C, + Terminator = 0x03E8, + End = 0xFFFF, + Error = 0xFEAF, +}; + +class Cutscene : public Resource<uint32_t> { + public: + using Resource::Resource; + + Cutscene() : Resource(std::shared_ptr<ResourceInitData>()) {} + + uint32_t* GetPointer(); + size_t GetPointerSize(); + + uint32_t numCommands; + uint32_t endFrame; + std::vector<uint32_t> commands; +}; +} // namespace LUS + + +///////////// + +// class CutsceneCommand { +// public: +// uint32_t commandID; +// uint32_t commandIndex; + +// CutsceneCommand(){}; +// }; diff --git a/mm/2s2h/resource/type/Path.cpp b/mm/2s2h/resource/type/Path.cpp new file mode 100644 index 000000000..8ca2ac78d --- /dev/null +++ b/mm/2s2h/resource/type/Path.cpp @@ -0,0 +1,19 @@ +#include "Path.h" + +namespace LUS { +PathData* Path::GetPointer() { + return pathData.data(); +} + +size_t Path::GetPointerSize() { + return pathData.size() * sizeof(PathData); +} + +PathDataMM* PathMM::GetPointer() { + return pathData.data(); +} +size_t PathMM::GetPointerSize() { + return pathData.size() * sizeof(PathData); +} + +} // namespace LUS diff --git a/mm/2s2h/resource/type/Path.h b/mm/2s2h/resource/type/Path.h new file mode 100644 index 000000000..045764cc8 --- /dev/null +++ b/mm/2s2h/resource/type/Path.h @@ -0,0 +1,52 @@ +#pragma once + +#include <cstdint> +#include <vector> +#include "Resource.h" +#include <libultraship/libultra/types.h> +#include "z64math.h" + +namespace LUS { + +typedef struct { + /* 0x00 */ u8 count; // number of points in the path + /* 0x04 */ Vec3s* points; // Segment Address to the array of points +} PathData; // size = 0x8 + +typedef struct { + /* 0x0 */ u8 count; // Number of points in the path + /* 0x1 */ u8 additionalPathIndex; + /* 0x2 */ s16 customValue; // Path specific to help distinguish different paths + /* 0x4 */ Vec3s* points; // Segment Address to the array of points +} PathDataMM; // size = 0x8 + +class Path : public Resource<PathData> { +public: + using Resource::Resource; + + Path() : Resource(std::shared_ptr<ResourceInitData>()) {} + + PathData* GetPointer(); + size_t GetPointerSize(); + + uint32_t numPaths; + std::vector<PathData> pathData; + std::vector<std::vector<Vec3s>> paths; +}; + +class PathMM : public Resource<PathDataMM> { + public: + using Resource::Resource; + + PathMM() : Resource(std::shared_ptr<ResourceInitData>()) { + } + + PathDataMM* GetPointer(); + size_t GetPointerSize(); + + uint32_t numPaths; + std::vector<PathDataMM> pathData; + std::vector<std::vector<Vec3s>> paths; +}; + +}; // namespace LUS diff --git a/mm/2s2h/resource/type/PlayerAnimation.cpp b/mm/2s2h/resource/type/PlayerAnimation.cpp new file mode 100644 index 000000000..55925f49c --- /dev/null +++ b/mm/2s2h/resource/type/PlayerAnimation.cpp @@ -0,0 +1,12 @@ +#include "PlayerAnimation.h" +#include <libultraship/libultra/gbi.h> + +namespace LUS { +int16_t* PlayerAnimation::GetPointer() { + return limbRotData.data(); +} + +size_t PlayerAnimation::GetPointerSize() { + return limbRotData.size() * sizeof(int16_t); +} +} // namespace LUS
\ No newline at end of file diff --git a/mm/2s2h/resource/type/PlayerAnimation.h b/mm/2s2h/resource/type/PlayerAnimation.h new file mode 100644 index 000000000..4eb51b139 --- /dev/null +++ b/mm/2s2h/resource/type/PlayerAnimation.h @@ -0,0 +1,23 @@ +#pragma once + +#include <vector> +#include <string> +#include "Resource.h" +#include "Vec2f.h" +#include "Vec3f.h" +#include "Color3b.h" + +namespace LUS { + +class PlayerAnimation : public Resource<int16_t> { + public: + using Resource::Resource; + + PlayerAnimation() : Resource(std::shared_ptr<ResourceInitData>()) {} + + int16_t* GetPointer(); + size_t GetPointerSize(); + + std::vector<int16_t> limbRotData; +}; +} // namespace LUS
\ No newline at end of file diff --git a/mm/2s2h/resource/type/Scene.cpp b/mm/2s2h/resource/type/Scene.cpp new file mode 100644 index 000000000..bfe219e54 --- /dev/null +++ b/mm/2s2h/resource/type/Scene.cpp @@ -0,0 +1,12 @@ +#include "Scene.h" + +namespace LUS { +void* Scene::GetPointer() { + // Scene is a special type that requries C++ processing. As such, we return nothing. + return nullptr; +} + +size_t Scene::GetPointerSize() { + return 0; +} +} // namespace LUS diff --git a/mm/2s2h/resource/type/Scene.h b/mm/2s2h/resource/type/Scene.h new file mode 100644 index 000000000..f726da359 --- /dev/null +++ b/mm/2s2h/resource/type/Scene.h @@ -0,0 +1,23 @@ +#pragma once + +#include <cstdint> +#include <vector> +#include <memory> +#include "Resource.h" +#include "scenecommand/SceneCommand.h" +#include <libultraship/libultra/types.h> + +namespace LUS { + +class Scene : public Resource<void> { +public: + using Resource::Resource; + + Scene() : Resource(std::shared_ptr<ResourceInitData>()) {} + + void* GetPointer(); + size_t GetPointerSize(); + + std::vector<std::shared_ptr<ISceneCommand>> commands; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/type/Skeleton.cpp b/mm/2s2h/resource/type/Skeleton.cpp new file mode 100644 index 000000000..7b9003bab --- /dev/null +++ b/mm/2s2h/resource/type/Skeleton.cpp @@ -0,0 +1,82 @@ +#include "resource/ResourceManager.h" +#include "Skeleton.h" +#include "2s2h/BenPort.h" +#include "libultraship/libultraship.h" + +namespace LUS { +SkeletonData* Skeleton::GetPointer() { + return &skeletonData; +} + +size_t Skeleton::GetPointerSize() { + switch(type) { + case SkeletonType::Normal: + return sizeof(skeletonData.skeletonHeader); + case SkeletonType::Flex: + return sizeof(skeletonData.flexSkeletonHeader); + case SkeletonType::Curve: + return sizeof(skeletonData.skelCurveLimbList); + default: + return 0; + } +} + +std::vector<SkeletonPatchInfo> SkeletonPatcher::skeletons; + + +void SkeletonPatcher::RegisterSkeleton(std::string& path, SkelAnime* skelAnime) { + SkeletonPatchInfo info; + + info.skelAnime = skelAnime; + + static const std::string sOtr = "__OTR__"; + + if (path.starts_with(sOtr)) { + path = path.substr(sOtr.length()); + } + + // Determine if we're using an alternate skeleton + if (path.starts_with(LUS::IResource::gAltAssetPrefix)) { + info.vanillaSkeletonPath = path.substr(LUS::IResource::gAltAssetPrefix.length(), + path.size() - LUS::IResource::gAltAssetPrefix.length()); + } else { + info.vanillaSkeletonPath = path; + } + + skeletons.push_back(info); +} + +void SkeletonPatcher::UnregisterSkeleton(SkelAnime* skelAnime) { + + // TODO: Should probably just use a dictionary here... + for (int i = 0; i < skeletons.size(); i++) + { + auto skel = skeletons[i]; + + if (skel.skelAnime == skelAnime) { + skeletons.erase(skeletons.begin() + i); + break; + } + } +} +void SkeletonPatcher::ClearSkeletons() +{ + skeletons.clear(); +} + +void SkeletonPatcher::UpdateSkeletons() { + bool isHD = CVarGetInteger("gAltAssets", 0); + for (auto skel : skeletons) { + Skeleton* newSkel = + (Skeleton*)LUS::Context::GetInstance()->GetResourceManager() + ->LoadResource((isHD ? LUS::IResource::gAltAssetPrefix : "") + skel.vanillaSkeletonPath, true) + .get(); + + if (newSkel != nullptr) { + skel.skelAnime->skeleton = newSkel->skeletonData.skeletonHeader.segment; + uintptr_t skelPtr = (uintptr_t)newSkel->GetPointer(); + memcpy(&skel.skelAnime->skeleton, &skelPtr, sizeof(uintptr_t)); // Dumb thing that needs to be done because cast is not cooperating + } + } +} +} // namespace LUS diff --git a/mm/2s2h/resource/type/Skeleton.h b/mm/2s2h/resource/type/Skeleton.h new file mode 100644 index 000000000..490614a44 --- /dev/null +++ b/mm/2s2h/resource/type/Skeleton.h @@ -0,0 +1,94 @@ +#pragma once + +#include <cstdint> +#include "Resource.h" +#include "SkeletonLimb.h" +#include <z64animation.h> + +namespace LUS { + +enum class SkeletonType { + Normal, + Flex, + Curve, +}; + +// typedef struct { +// /* 0x00 */ Vec3s jointPos; // Root is position in model space, children are relative to parent +// /* 0x06 */ u8 child; +// /* 0x07 */ u8 sibling; +// /* 0x08 */ Gfx* dList; +// } StandardLimb; // size = 0xC + +// Model has limbs with only rigid meshes +typedef struct { + /* 0x00 */ void** segment; + /* 0x04 */ uint8_t limbCount; + uint8_t skeletonType; +} SkeletonHeader; // size = 0x8 + +// Model has limbs with flexible meshes +typedef struct { + /* 0x00 */ SkeletonHeader sh; + /* 0x08 */ uint8_t dListCount; +} FlexSkeletonHeader; // size = 0xC + +// typedef struct { +// /* 0x0000 */ u8 firstChildIdx; +// /* 0x0001 */ u8 nextLimbIdx; +// /* 0x0004 */ Gfx* dList[2]; +// } SkelCurveLimb; // size = 0xC + +typedef struct { + /* 0x0000 */ SkelCurveLimb** limbs; + /* 0x0004 */ uint8_t limbCount; +} SkelCurveLimbList; // size = 0x8 + +union SkeletonData { + SkeletonHeader skeletonHeader; + FlexSkeletonHeader flexSkeletonHeader; + SkelCurveLimbList skelCurveLimbList; +}; + +class Skeleton : public Resource<SkeletonData> { + public: + using Resource::Resource; + + Skeleton() : Resource(std::shared_ptr<ResourceInitData>()) {} + + SkeletonData* GetPointer(); + size_t GetPointerSize(); + + SkeletonType type; + SkeletonData skeletonData; + + LimbType limbType; + int limbCount; + int dListCount; + LimbType limbTableType; + int limbTableCount; + std::vector<StandardLimb> standardLimbArray; + std::vector<SkelCurveLimb> curveLimbArray; + std::vector<std::string> limbTable; + std::vector<void*> skeletonHeaderSegments; +}; + +// TODO: CLEAN THIS UP LATER +struct SkeletonPatchInfo +{ + SkelAnime* skelAnime; + std::string vanillaSkeletonPath; +}; + +class SkeletonPatcher { + public: + static void RegisterSkeleton(std::string& path, SkelAnime* skelAnime); + static void UnregisterSkeleton(SkelAnime* skelAnime); + static void ClearSkeletons(); + static void UpdateSkeletons(); + + static std::vector<SkeletonPatchInfo> skeletons; +}; + + +} // namespace LUS
\ No newline at end of file diff --git a/mm/2s2h/resource/type/SkeletonLimb.cpp b/mm/2s2h/resource/type/SkeletonLimb.cpp new file mode 100644 index 000000000..8e5a8ef6d --- /dev/null +++ b/mm/2s2h/resource/type/SkeletonLimb.cpp @@ -0,0 +1,24 @@ +#include "SkeletonLimb.h" + +namespace LUS { +SkeletonLimbData* SkeletonLimb::GetPointer() { + return &limbData; +} + +size_t SkeletonLimb::GetPointerSize() { + switch(limbType) { + case LimbType::Standard: + return sizeof(limbData.standardLimb); + case LimbType::LOD: + return sizeof(limbData.lodLimb); + case LimbType::Skin: + return sizeof(limbData.skinLimb); + case LimbType::Curve: + return sizeof(limbData.skelCurveLimb); + case LimbType::Invalid: + case LimbType::Legacy: + default: + return 0; + } +} +} // namespace LUS diff --git a/mm/2s2h/resource/type/SkeletonLimb.h b/mm/2s2h/resource/type/SkeletonLimb.h new file mode 100644 index 000000000..2110b3484 --- /dev/null +++ b/mm/2s2h/resource/type/SkeletonLimb.h @@ -0,0 +1,134 @@ +#pragma once + +#include "Resource.h" +#include "libultraship/libultra.h" +#include "z64math.h" + +namespace LUS { +enum class LimbType { + Invalid, + Standard, + LOD, + Skin, + Curve, + Legacy, +}; + +enum class ZLimbSkinType +{ + SkinType_0, // Segment = 0 + SkinType_4 = 4, // Segment = segmented address // Struct_800A5E28 + SkinType_5 = 5, // Segment = 0 + SkinType_DList = 11, // Segment = DList address +}; + +/** + * Holds a compact version of a vertex used in the Skin system + * It is used to initialise the Vtx used by an animated limb + */ +typedef struct { + /* 0x00 */ u16 index; + /* 0x02 */ s16 s; // s and t are texture coordinates (also known as u and v) + /* 0x04 */ s16 t; + /* 0x06 */ s8 normX; + /* 0x07 */ s8 normY; + /* 0x08 */ s8 normZ; + /* 0x09 */ u8 alpha; +} SkinVertex; // size = 0xA + +/** + * Describes a position displacement and a scale to be applied to a limb at index `limbIndex` + */ +typedef struct { + /* 0x00 */ u8 limbIndex; + /* 0x02 */ s16 x; + /* 0x04 */ s16 y; + /* 0x06 */ s16 z; + /* 0x08 */ u8 scale; +} SkinTransformation; // size = 0xA + +typedef struct { + /* 0x00 */ u16 vtxCount; // number of vertices in this modif entry + /* 0x02 */ u16 transformCount; + /* 0x04 */ u16 unk_4; // index of limbTransformations? + /* 0x08 */ SkinVertex* skinVertices; + /* 0x0C */ SkinTransformation* limbTransformations; +} SkinLimbModif; // size = 0x10 + +typedef struct { + /* 0x00 */ Vec3s jointPos; // Root is position in model space, children are relative to parent + /* 0x06 */ u8 child; + /* 0x07 */ u8 sibling; + /* 0x08 */ Gfx* dLists[2]; // Near and far +} LodLimb; // size = 0x10 + +typedef struct { + /* 0x00 */ Vec3s jointPos; // Root is position in model space, children are relative to parent + /* 0x06 */ u8 child; + /* 0x07 */ u8 sibling; + /* 0x08 */ Gfx* dList; +} StandardLimb; // size = 0xC + +typedef struct { + /* 0x0000 */ u8 firstChildIdx; + /* 0x0001 */ u8 nextLimbIdx; + /* 0x0004 */ Gfx* dList[2]; +} SkelCurveLimb; // size = 0xC + +typedef struct { + /* 0x00 */ Vec3s jointPos; // Root is position in model space, children are relative to parent + /* 0x06 */ u8 child; + /* 0x07 */ u8 sibling; + /* 0x08 */ s32 segmentType; // Type of data contained in segment + /* 0x0C */ void* segment; // Gfx* if segmentType is SKIN_LIMB_TYPE_NORMAL, SkinAnimatedLimbData* if segmentType is SKIN_LIMB_TYPE_ANIMATED, NULL otherwise +} SkinLimb; // size = 0x10 + +typedef struct { + /* 0x00 */ u16 totalVtxCount; // total vertex count for all modif entries + /* 0x02 */ u16 limbModifCount; + /* 0x04 */ SkinLimbModif* limbModifications; + /* 0x08 */ Gfx* dlist; +} SkinAnimatedLimbData; // size = 0xC + +union SkeletonLimbData { + LodLimb lodLimb; + StandardLimb standardLimb; + SkelCurveLimb skelCurveLimb; + SkinLimb skinLimb; +}; + +class SkeletonLimb : public Resource<SkeletonLimbData> { +public: + using Resource::Resource; + + SkeletonLimb() : Resource(std::shared_ptr<ResourceInitData>()) {} + + SkeletonLimbData* GetPointer(); + size_t GetPointerSize(); + + LimbType limbType; + SkeletonLimbData limbData; + + ZLimbSkinType skinSegmentType; + uint16_t skinVtxCnt; + SkinAnimatedLimbData skinAnimLimbData; + + std::string skinDataDList; + std::string skinDList; + std::string skinDList2; + + float legTransX, legTransY, legTransZ; // Vec3f + uint16_t rotX, rotY, rotZ; // Vec3s + + std::string childPtr, siblingPtr, dListPtr, dList2Ptr; + + int16_t transX, transY, transZ; + uint8_t childIndex, siblingIndex; + + uint32_t skinLimbModifCount; + std::vector<SkinLimbModif> skinLimbModifArray; + + std::vector<std::vector<SkinVertex>> skinLimbModifVertexArrays; + std::vector<std::vector<SkinTransformation>> skinLimbModifTransformationArrays; +}; +} // namespace LUS
\ No newline at end of file diff --git a/mm/2s2h/resource/type/Text.cpp b/mm/2s2h/resource/type/Text.cpp new file mode 100644 index 000000000..eee289f8a --- /dev/null +++ b/mm/2s2h/resource/type/Text.cpp @@ -0,0 +1,11 @@ +#include "Text.h" + +namespace LUS { +MessageEntry* Text::GetPointer() { + return messages.data(); +} + +size_t Text::GetPointerSize() { + return messages.size() * sizeof(MessageEntry); +} +} // namespace LUS diff --git a/mm/2s2h/resource/type/Text.h b/mm/2s2h/resource/type/Text.h new file mode 100644 index 000000000..db0cb36a0 --- /dev/null +++ b/mm/2s2h/resource/type/Text.h @@ -0,0 +1,30 @@ +#pragma once + +#include <cstdint> +#include <vector> +#include "Resource.h" +#include <libultraship/libultra/types.h> + +namespace LUS { +// TODO: we've moved away from using classes for this stuff +class MessageEntry +{ +public: + uint16_t id; + uint8_t textboxType; + uint8_t textboxYPos; + std::string msg; +}; + +class Text : public Resource<MessageEntry> { +public: + using Resource::Resource; + + Text() : Resource(std::shared_ptr<ResourceInitData>()) {} + + MessageEntry* GetPointer(); + size_t GetPointerSize(); + + std::vector<MessageEntry> messages; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/type/TextMM.cpp b/mm/2s2h/resource/type/TextMM.cpp new file mode 100644 index 000000000..b4acc8d18 --- /dev/null +++ b/mm/2s2h/resource/type/TextMM.cpp @@ -0,0 +1,11 @@ +#include "TextMM.h" + +namespace LUS { +MessageEntryMM* TextMM::GetPointer() { + return messages.data(); +} + +size_t TextMM::GetPointerSize() { + return messages.size() * sizeof(MessageEntryMM); +} +} // namespace LUS diff --git a/mm/2s2h/resource/type/TextMM.h b/mm/2s2h/resource/type/TextMM.h new file mode 100644 index 000000000..7a6e2d1ab --- /dev/null +++ b/mm/2s2h/resource/type/TextMM.h @@ -0,0 +1,37 @@ +#pragma once + +#include <cstdint> +#include <vector> +#include "Resource.h" +#include <libultraship/libultra/types.h> + +namespace LUS { +// TODO: we've moved away from using classes for this stuff + +class MessageEntryMM { + public: + uint16_t id; + uint8_t textboxType; + uint8_t textboxYPos; + uint8_t icon; + uint16_t nextMessageID; + uint16_t firstItemCost; + uint16_t secondItemCost; + uint32_t segmentId; + uint32_t msgOffset; + std::string msg; +}; + +class TextMM : public Resource<MessageEntryMM> { +public: + using Resource::Resource; + + TextMM() : Resource(std::shared_ptr<ResourceInitData>()) { + } + + MessageEntryMM* GetPointer(); + size_t GetPointerSize(); + + std::vector<MessageEntryMM> messages; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/type/TextureAnimation.cpp b/mm/2s2h/resource/type/TextureAnimation.cpp new file mode 100644 index 000000000..0d49d0e5b --- /dev/null +++ b/mm/2s2h/resource/type/TextureAnimation.cpp @@ -0,0 +1,36 @@ +#include "TextureAnimation.h" + +namespace LUS { +TextureAnimation::~TextureAnimation() { + for (auto& a : anims) { + switch ((TextureAnimationParamsType)a.type) { + case TextureAnimationParamsType::SingleScroll: + delete a.params; + break; + case TextureAnimationParamsType::DualScroll: + delete[] a.params; + break; + case TextureAnimationParamsType::ColorChange: + case TextureAnimationParamsType::ColorChangeLERP: + case TextureAnimationParamsType::ColorChangeLagrange: + delete[] ((AnimatedMatColorParams*)a.params)->keyFrames; + delete[] ((AnimatedMatColorParams*)a.params)->primColors; + delete[] ((AnimatedMatColorParams*)a.params)->envColors; + delete a.params; + break; + case TextureAnimationParamsType::TextureCycle: + // BENTODO free the textures + delete[] ((AnimatedMatTexCycleParams*)a.params)->textureIndexList; + delete[] ((AnimatedMatTexCycleParams*)a.params)->textureList; + delete a.params; + break; + } + } +} +AnimatedMaterial* TextureAnimation::GetPointer() { + return anims.data(); +} +size_t TextureAnimation::GetPointerSize() { + return anims.size() * sizeof(AnimatedMaterial); +} +} // namespace LUS
\ No newline at end of file diff --git a/mm/2s2h/resource/type/TextureAnimation.h b/mm/2s2h/resource/type/TextureAnimation.h new file mode 100644 index 000000000..5538547c6 --- /dev/null +++ b/mm/2s2h/resource/type/TextureAnimation.h @@ -0,0 +1,104 @@ +#pragma once +#include "Resource.h" + +namespace LUS { +enum class TextureAnimationParamsType { + /* 0 */ SingleScroll, + /* 1 */ DualScroll, + /* 2 */ ColorChange, + /* 3 */ ColorChangeLERP, + /* 4 */ ColorChangeLagrange, + /* 5 */ TextureCycle, + /* 6 */ Empty // An empty TextureAnimation has the form 00 00 00 06 00000000 +}; + +class ZTextureAnimationParams { + public: + TextureAnimationParamsType type; +}; + +struct TextureScrollingParamsEntry { + int8_t xStep; + int8_t yStep; + uint8_t width; + uint8_t height; +}; + +class TextureScrollingParams : public ZTextureAnimationParams { + public: + int count; // 1 for Single, 2 for Dual + TextureScrollingParamsEntry rows[2]; // Too small to make a vector worth it +}; + +struct F3DPrimColor { + uint8_t r; + uint8_t g; + uint8_t b; + uint8_t a; + uint8_t lodFrac; +}; + +struct F3DEnvColor { + uint8_t r; + uint8_t g; + uint8_t b; + uint8_t a; +}; + +class TextureColorChangingParams : public ZTextureAnimationParams { + public: + uint16_t animLength; // size of list for type 2 + uint16_t colorListCount; + std::vector<F3DPrimColor> primColorList; + std::vector<F3DEnvColor> envColorList; + std::vector<uint16_t> frameDataList; +}; + +class TextureCyclingParams : public ZTextureAnimationParams { + public: + uint16_t cycleLength; + std::vector<void*> textureList; + std::vector<uint8_t> textureIndexList; +}; + +typedef struct { + /* 0x0 */ uint16_t keyFrameLength; + /* 0x2 */ uint16_t keyFrameCount; + /* 0x4 */ F3DPrimColor* primColors; + /* 0x8 */ F3DEnvColor* envColors; + /* 0xC */ uint16_t* keyFrames; +} AnimatedMatColorParams; // size = 0x10 + +typedef struct { + /* 0x0 */ int8_t xStep; + /* 0x1 */ int8_t yStep; + /* 0x2 */ uint8_t width; + /* 0x3 */ uint8_t height; +} AnimatedMatTexScrollParams; // size = 0x4 + +typedef struct { + /* 0x0 */ uint16_t keyFrameLength; + /* 0x4 */ void** textureList; + /* 0x8 */ uint8_t* textureIndexList; +} AnimatedMatTexCycleParams; // size = 0xC + +typedef struct { + /* 0x0 */ int8_t segment; + /* 0x2 */ int16_t type; + /* 0x4 */ void* params; +} AnimatedMaterial; // size = 0x8 + +class TextureAnimation : public Resource<AnimatedMaterial> { + public: + using Resource::Resource; + ~TextureAnimation(); + + TextureAnimation() : Resource(std::shared_ptr<ResourceInitData>()) { + } + + AnimatedMaterial* GetPointer(); + size_t GetPointerSize(); + + std::vector<AnimatedMaterial> anims; +}; +} // namespace LUS
\ No newline at end of file diff --git a/mm/2s2h/resource/type/scenecommand/EndMarker.cpp b/mm/2s2h/resource/type/scenecommand/EndMarker.cpp new file mode 100644 index 000000000..9d12c1518 --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/EndMarker.cpp @@ -0,0 +1,11 @@ +#include "EndMarker.h" + +namespace LUS { +Marker* EndMarker::GetPointer() { + return &endMarker; +} + +size_t EndMarker::GetPointerSize() { + return sizeof(Marker); +} +} // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/EndMarker.h b/mm/2s2h/resource/type/scenecommand/EndMarker.h new file mode 100644 index 000000000..9f981f1f9 --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/EndMarker.h @@ -0,0 +1,24 @@ +#pragma once + +#include <cstdint> +#include <vector> +#include <memory> +#include "Resource.h" +#include "SceneCommand.h" +#include <libultraship/libultra/types.h> + +namespace LUS { +typedef struct { + +} Marker; + +class EndMarker : public SceneCommand<Marker> { + public: + using SceneCommand::SceneCommand; + + Marker* GetPointer(); + size_t GetPointerSize(); + + Marker endMarker; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/RomFile.h b/mm/2s2h/resource/type/scenecommand/RomFile.h new file mode 100644 index 000000000..ebdc3dc3b --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/RomFile.h @@ -0,0 +1,11 @@ +#pragma once + +#include <cstdint> + +namespace LUS { + typedef struct { + /* 0x00 */ uintptr_t vromStart; + /* 0x04 */ uintptr_t vromEnd; + char* fileName; + } RomFile; // size = 0x8 +}
\ No newline at end of file diff --git a/mm/2s2h/resource/type/scenecommand/SceneCommand.h b/mm/2s2h/resource/type/scenecommand/SceneCommand.h new file mode 100644 index 000000000..ea99e066e --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SceneCommand.h @@ -0,0 +1,67 @@ +#pragma once + +#include <cstdint> +#include <vector> +#include <memory> +#include "Resource.h" +#include <libultraship/libultra/types.h> + +namespace LUS { + +enum class SceneCommandID : uint8_t { + SetStartPositionList = 0x00, + SetActorList = 0x01, + SetCsCamera = 0x02, + SetCollisionHeader = 0x03, + SetRoomList = 0x04, + SetWind = 0x05, + SetEntranceList = 0x06, + SetSpecialObjects = 0x07, + SetRoomBehavior = 0x08, + Unused09 = 0x09, + SetMesh = 0x0A, + SetObjectList = 0x0B, + SetLightList = 0x0C, + SetPathways = 0x0D, + SetTransitionActorList = 0x0E, + SetLightingSettings = 0x0F, + SetTimeSettings = 0x10, + SetSkyboxSettings = 0x11, + SetSkyboxModifier = 0x12, + SetExitList = 0x13, + EndMarker = 0x14, + SetSoundSettings = 0x15, + SetEchoSettings = 0x16, + SetCutscenes = 0x17, + SetAlternateHeaders = 0x18, + SetCameraSettings = 0x19, + + // MM Commands + SetWorldMapVisited = 0x19, + SetAnimatedMaterialList = 0x1A, + SetActorCutsceneList = 0x1B, + SetMinimapList = 0x1C, + Unused1D = 0x1D, + SetMinimapChests = 0x1E, + SetCutscenesMM = 0x1F, // This opcode is not in the original game. Its a special command for OTRs. + + Error = 0xFF +}; + +class ISceneCommand : public IResource { +public: + using IResource::IResource; + ISceneCommand() : IResource(std::shared_ptr<ResourceInitData>()) {} + SceneCommandID cmdId; +}; + +template <class T> class SceneCommand : public ISceneCommand { + public: + using ISceneCommand::ISceneCommand; + virtual T* GetPointer() = 0; + void* GetRawPointer() override { + return static_cast<void*>(GetPointer()); + } +}; + +}; // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/SetActorCutsceneList.cpp b/mm/2s2h/resource/type/scenecommand/SetActorCutsceneList.cpp new file mode 100644 index 000000000..79d5253ac --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetActorCutsceneList.cpp @@ -0,0 +1,13 @@ +#include "SetActorCutsceneList.h" +#include "2s2h/resource/type/scenecommand/SetActorCutsceneList.h" + +namespace LUS { +CutsceneEntry* SetActorCutsceneList::GetPointer() { + return entries.data(); +} + +size_t SetActorCutsceneList::GetPointerSize() { + return entries.size() * sizeof(CutsceneEntry); +} + +} // namespace LUS
\ No newline at end of file diff --git a/mm/2s2h/resource/type/scenecommand/SetActorCutsceneList.h b/mm/2s2h/resource/type/scenecommand/SetActorCutsceneList.h new file mode 100644 index 000000000..5b93d1a5b --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetActorCutsceneList.h @@ -0,0 +1,31 @@ +#pragma once + +#include "Resource.h" +#include "SceneCommand.h" + +namespace LUS { +typedef struct CutsceneEntry { + int16_t priority; + int16_t length; + int16_t csCamId; + int16_t scriptIndex; + int16_t additionalCsId; + uint8_t endSfx; + uint8_t customValue; + int16_t hudVisibility; + uint8_t endCam; + uint8_t letterboxSize; +} CutsceneEntry; + +class SetActorCutsceneList : public SceneCommand<CutsceneEntry> { + public: + using SceneCommand::SceneCommand; + + CutsceneEntry* GetPointer(); + size_t GetPointerSize(); + + uint32_t numEntries; + std::vector<CutsceneEntry> entries; +}; + +}
\ No newline at end of file diff --git a/mm/2s2h/resource/type/scenecommand/SetActorList.cpp b/mm/2s2h/resource/type/scenecommand/SetActorList.cpp new file mode 100644 index 000000000..d37ebb148 --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetActorList.cpp @@ -0,0 +1,11 @@ +#include "SetActorList.h" + +namespace LUS { +ActorEntry* SetActorList::GetPointer() { + return actorList.data(); +} + +size_t SetActorList::GetPointerSize() { + return actorList.size() * sizeof(ActorEntry); +} +} // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/SetActorList.h b/mm/2s2h/resource/type/scenecommand/SetActorList.h new file mode 100644 index 000000000..117175d7d --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetActorList.h @@ -0,0 +1,30 @@ +#pragma once + +#include <cstdint> +#include <vector> +#include <memory> +#include <string> +#include "Resource.h" +#include "SceneCommand.h" +// #include <libultraship/libultra/types.h> +#include "z64math.h" + +namespace LUS { +typedef struct { + /* 0x00 */ s16 id; + /* 0x02 */ Vec3s pos; + /* 0x08 */ Vec3s rot; + /* 0x0E */ s16 params; +} ActorEntry; // size = 0x10 + +class SetActorList : public SceneCommand<ActorEntry> { + public: + using SceneCommand::SceneCommand; + + ActorEntry* GetPointer(); + size_t GetPointerSize(); + + uint32_t numActors; + std::vector<ActorEntry> actorList; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/SetAlternateHeaders.cpp b/mm/2s2h/resource/type/scenecommand/SetAlternateHeaders.cpp new file mode 100644 index 000000000..15b3c97d4 --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetAlternateHeaders.cpp @@ -0,0 +1,12 @@ +#include "SetAlternateHeaders.h" + +namespace LUS { +void* SetAlternateHeaders::GetPointer() { + // Like Scene, SetAlternateHeader is a special type that is only acted upon in C++. + return nullptr; +} + +size_t SetAlternateHeaders::GetPointerSize() { + return 0; +} +} // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/SetAlternateHeaders.h b/mm/2s2h/resource/type/scenecommand/SetAlternateHeaders.h new file mode 100644 index 000000000..ebc571e3d --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetAlternateHeaders.h @@ -0,0 +1,26 @@ +#pragma once + +#include <cstdint> +#include <vector> +#include <memory> +#include <string> +#include "Resource.h" +#include "SceneCommand.h" +#include "2s2h/resource/type/Scene.h" +#include "RomFile.h" +#include <libultraship/libultra/types.h> + + +namespace LUS { + +class SetAlternateHeaders : public SceneCommand<void> { + public: + using SceneCommand::SceneCommand; + + void* GetPointer(); + size_t GetPointerSize(); + + uint32_t numHeaders; + std::vector<std::shared_ptr<Scene>> headers; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/SetAnimatedMaterialList.cpp b/mm/2s2h/resource/type/scenecommand/SetAnimatedMaterialList.cpp new file mode 100644 index 000000000..ef3adc543 --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetAnimatedMaterialList.cpp @@ -0,0 +1,13 @@ +#include "SetAnimatedMaterialList.h" + +namespace LUS { + +AnimatedMaterialData* LUS::SetAnimatedMaterialList::GetPointer() { + return mat; +} + +size_t LUS::SetAnimatedMaterialList::GetPointerSize() { + return sizeof(AnimatedMaterialData); +} + +} // namespace LUS
\ No newline at end of file diff --git a/mm/2s2h/resource/type/scenecommand/SetAnimatedMaterialList.h b/mm/2s2h/resource/type/scenecommand/SetAnimatedMaterialList.h new file mode 100644 index 000000000..02a8c7c38 --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetAnimatedMaterialList.h @@ -0,0 +1,23 @@ +#pragma once + +#include "Resource.h" +#include "SceneCommand.h" +#include <libultraship/libultra/types.h> + +namespace LUS { +typedef struct { + /* 0x0 */ int8_t segment; + /* 0x2 */ int16_t type; + /* 0x4 */ void* params; +} AnimatedMaterialData; // size = 0x8 + +class SetAnimatedMaterialList : public SceneCommand<AnimatedMaterialData> { + public: + using SceneCommand::SceneCommand; + + AnimatedMaterialData* GetPointer(); + size_t GetPointerSize(); + + AnimatedMaterialData* mat; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/SetCameraSettings.cpp b/mm/2s2h/resource/type/scenecommand/SetCameraSettings.cpp new file mode 100644 index 000000000..e1d2967e7 --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetCameraSettings.cpp @@ -0,0 +1,11 @@ +#include "SetCameraSettings.h" + +namespace LUS { +CameraSettings* SetCameraSettings::GetPointer() { + return &settings; +} + +size_t SetCameraSettings::GetPointerSize() { + return sizeof(CameraSettings); +} +} // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/SetCameraSettings.h b/mm/2s2h/resource/type/scenecommand/SetCameraSettings.h new file mode 100644 index 000000000..adbde2e02 --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetCameraSettings.h @@ -0,0 +1,25 @@ +#pragma once + +#include <cstdint> +#include <vector> +#include <memory> +#include "Resource.h" +#include "SceneCommand.h" +#include <libultraship/libultra/types.h> + +namespace LUS { +typedef struct { + int8_t cameraMovement; + int32_t worldMapArea; +} CameraSettings; + +class SetCameraSettings : public SceneCommand<CameraSettings> { + public: + using SceneCommand::SceneCommand; + + CameraSettings* GetPointer(); + size_t GetPointerSize(); + + CameraSettings settings; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/SetCollisionHeader.cpp b/mm/2s2h/resource/type/scenecommand/SetCollisionHeader.cpp new file mode 100644 index 000000000..db8cdcb32 --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetCollisionHeader.cpp @@ -0,0 +1,17 @@ +#include "SetCollisionHeader.h" + +namespace LUS { +CollisionHeaderData* SetCollisionHeader::GetPointer() { + if (collisionHeader == nullptr) { + return nullptr; + } + return collisionHeader->GetPointer(); +} + +size_t SetCollisionHeader::GetPointerSize() { + if (collisionHeader == nullptr) { + return 0; + } + return collisionHeader->GetPointerSize(); +} +} // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/SetCollisionHeader.h b/mm/2s2h/resource/type/scenecommand/SetCollisionHeader.h new file mode 100644 index 000000000..c615eedad --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetCollisionHeader.h @@ -0,0 +1,24 @@ +#pragma once + +#include <cstdint> +#include <vector> +#include <memory> +#include <string> +#include "Resource.h" +#include "2s2h/resource/type/scenecommand/SceneCommand.h" +#include "2s2h/resource/type/CollisionHeader.h" +// #include <libultraship/libultra/types.h> + +namespace LUS { +class SetCollisionHeader : public SceneCommand<CollisionHeaderData> { + public: + using SceneCommand::SceneCommand; + + CollisionHeaderData* GetPointer(); + size_t GetPointerSize(); + + std::string fileName; + + std::shared_ptr<CollisionHeader> collisionHeader; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/SetCsCamera.cpp b/mm/2s2h/resource/type/scenecommand/SetCsCamera.cpp new file mode 100644 index 000000000..186ffcae6 --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetCsCamera.cpp @@ -0,0 +1,18 @@ +#include "SetCsCamera.h" + +namespace LUS { +SetCsCamera::~SetCsCamera() { + for (auto c : csCamera) { + if (c.actorCsCamFuncData != nullptr) { + delete c.actorCsCamFuncData; + } + } +} +ActorCsCamInfoData* SetCsCamera::GetPointer() { + return csCamera.data(); +} + +size_t SetCsCamera::GetPointerSize() { + return sizeof(ActorCsCamInfoData); +} +} // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/SetCsCamera.h b/mm/2s2h/resource/type/scenecommand/SetCsCamera.h new file mode 100644 index 000000000..fa5d9a500 --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetCsCamera.h @@ -0,0 +1,37 @@ +#pragma once + +#include <cstdint> +#include <vector> +#include <memory> +#include "Resource.h" +#include "SceneCommand.h" +#include <libultraship/libultra/types.h> + +namespace LUS { +typedef struct { + +} CsCamera; + +typedef struct { + /* 0x0 */ s16 x; + /* 0x2 */ s16 y; + /* 0x4 */ s16 z; +} z64Vec3s; // size = 0x6 + +typedef struct { + /* 0x0 */ s16 setting; // camera setting described by CameraSettingType enum + /* 0x2 */ s16 count; + /* 0x4 */ z64Vec3s* actorCsCamFuncData; // s16 data grouped in threes +} ActorCsCamInfoData; // size = 0x8 + +class SetCsCamera : public SceneCommand<ActorCsCamInfoData> { + public: + using SceneCommand::SceneCommand; + ~SetCsCamera(); + + ActorCsCamInfoData* GetPointer(); + size_t GetPointerSize(); + + std::vector<ActorCsCamInfoData> csCamera; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/SetCutscenes.cpp b/mm/2s2h/resource/type/scenecommand/SetCutscenes.cpp new file mode 100644 index 000000000..01c88751b --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetCutscenes.cpp @@ -0,0 +1,35 @@ +#include "SetCutscenes.h" + +namespace LUS { +uint32_t* SetCutscenes::GetPointer() { + if (cutscene == nullptr) { + return nullptr; + } + return cutscene->GetPointer(); +} + +size_t SetCutscenes::GetPointerSize() { + if (cutscene == nullptr) { + return 0; + } + return cutscene->GetPointerSize(); +} + +CutsceneScriptEntry* SetCutscenesMM::GetPointer() { + // return nullptr; // BENTODO + if (entries.size() == 0) { + return nullptr; + } + return entries.data(); +} + +size_t SetCutscenesMM::GetPointerSize() { + //return 0; + // BENTODO + if (entries.size() == 0) { + return 0; + } + return entries.size() * sizeof(CutsceneScriptEntry); +} + +} // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/SetCutscenes.h b/mm/2s2h/resource/type/scenecommand/SetCutscenes.h new file mode 100644 index 000000000..900201522 --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetCutscenes.h @@ -0,0 +1,43 @@ +#pragma once + +#include <cstdint> +#include <vector> +#include <memory> +#include <string> +#include "Resource.h" +#include "2s2h/resource/type/scenecommand/SceneCommand.h" +#include "2s2h/resource/type/Cutscene.h" +// #include <libultraship/libultra.h> + +namespace LUS { +class SetCutscenes : public SceneCommand<uint32_t> { + public: + using SceneCommand::SceneCommand; + + uint32_t* GetPointer(); + size_t GetPointerSize(); + + std::string fileName; + std::shared_ptr<Cutscene> cutscene; +}; + +class CutsceneScriptEntry { + public: + void* data; + uint16_t exit; + uint8_t entrance; + uint8_t flag; +}; + + +class SetCutscenesMM : public SceneCommand<CutsceneScriptEntry> { + public: + using SceneCommand::SceneCommand; + + CutsceneScriptEntry* GetPointer(); + size_t GetPointerSize(); + + std::vector<CutsceneScriptEntry> entries; +}; + +}; // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/SetEchoSettings.cpp b/mm/2s2h/resource/type/scenecommand/SetEchoSettings.cpp new file mode 100644 index 000000000..47cfa85ad --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetEchoSettings.cpp @@ -0,0 +1,11 @@ +#include "SetEchoSettings.h" + +namespace LUS { +EchoSettings* SetEchoSettings::GetPointer() { + return &settings; +} + +size_t SetEchoSettings::GetPointerSize() { + return sizeof(EchoSettings); +} +} // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/SetEchoSettings.h b/mm/2s2h/resource/type/scenecommand/SetEchoSettings.h new file mode 100644 index 000000000..ea2f664d4 --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetEchoSettings.h @@ -0,0 +1,24 @@ +#pragma once + +#include <cstdint> +#include <vector> +#include <memory> +#include "Resource.h" +#include "SceneCommand.h" +#include <libultraship/libultra/types.h> + +namespace LUS { +typedef struct { + int8_t echo; +} EchoSettings; + +class SetEchoSettings : public SceneCommand<EchoSettings> { + public: + using SceneCommand::SceneCommand; + + EchoSettings* GetPointer(); + size_t GetPointerSize(); + + EchoSettings settings; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/SetEntranceList.cpp b/mm/2s2h/resource/type/scenecommand/SetEntranceList.cpp new file mode 100644 index 000000000..d33ac189b --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetEntranceList.cpp @@ -0,0 +1,11 @@ +#include "SetEntranceList.h" + +namespace LUS { +EntranceEntry* SetEntranceList::GetPointer() { + return entrances.data(); +} + +size_t SetEntranceList::GetPointerSize() { + return entrances.size() * sizeof(EntranceEntry); +} +} // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/SetEntranceList.h b/mm/2s2h/resource/type/scenecommand/SetEntranceList.h new file mode 100644 index 000000000..d31dda78c --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetEntranceList.h @@ -0,0 +1,28 @@ +#pragma once + +#include <cstdint> +#include <vector> +#include <memory> +#include <string> +#include "Resource.h" +#include "SceneCommand.h" +#include <libultraship/libultra/types.h> + +namespace LUS { +typedef struct { + /* 0x00 */ u8 spawn; + /* 0x01 */ u8 room; +} EntranceEntry; + +class SetEntranceList : public SceneCommand<EntranceEntry> { + public: + using SceneCommand::SceneCommand; + + EntranceEntry* GetPointer(); + size_t GetPointerSize(); + + uint32_t numEntrances; + + std::vector<EntranceEntry> entrances; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/SetExitList.cpp b/mm/2s2h/resource/type/scenecommand/SetExitList.cpp new file mode 100644 index 000000000..99966cdb4 --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetExitList.cpp @@ -0,0 +1,11 @@ +#include "SetExitList.h" + +namespace LUS { +uint16_t* SetExitList::GetPointer() { + return exits.data(); +} + +size_t SetExitList::GetPointerSize() { + return exits.size() * sizeof(int16_t); +} +} // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/SetExitList.h b/mm/2s2h/resource/type/scenecommand/SetExitList.h new file mode 100644 index 000000000..c6f0b3f42 --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetExitList.h @@ -0,0 +1,22 @@ +#pragma once + +#include <cstdint> +#include <vector> +#include <memory> +#include "Resource.h" +#include "SceneCommand.h" +#include <libultraship/libultra/types.h> + +namespace LUS { +class SetExitList : public SceneCommand<uint16_t> { + public: + using SceneCommand::SceneCommand; + + uint16_t* GetPointer(); + size_t GetPointerSize(); + + uint32_t numExits; + + std::vector<uint16_t> exits; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/SetLightList.cpp b/mm/2s2h/resource/type/scenecommand/SetLightList.cpp new file mode 100644 index 000000000..c59f75c20 --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetLightList.cpp @@ -0,0 +1,11 @@ +#include "SetLightList.h" + +namespace LUS { +LightInfo* SetLightList::GetPointer() { + return lightList.data(); +} + +size_t SetLightList::GetPointerSize() { + return lightList.size() * sizeof(LightInfo); +} +} // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/SetLightList.h b/mm/2s2h/resource/type/scenecommand/SetLightList.h new file mode 100644 index 000000000..bbc5aad3d --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetLightList.h @@ -0,0 +1,48 @@ +#pragma once + +#include <cstdint> +#include <vector> +#include <memory> +#include <string> +#include "Resource.h" +#include "SceneCommand.h" +#include <libultraship/libultra/types.h> + +namespace LUS { +typedef struct { + /* 0x0 */ s16 x; + /* 0x2 */ s16 y; + /* 0x4 */ s16 z; + /* 0x6 */ u8 color[3]; + /* 0x9 */ u8 drawGlow; + /* 0xA */ s16 radius; +} LightPoint; // size = 0xC + +typedef struct { + /* 0x0 */ s8 x; + /* 0x1 */ s8 y; + /* 0x2 */ s8 z; + /* 0x3 */ u8 color[3]; +} LightDirectional; // size = 0x6 + +typedef union { + LightPoint point; + LightDirectional dir; +} LightParams; // size = 0xC + +typedef struct { + /* 0x0 */ u8 type; + /* 0x2 */ LightParams params; +} LightInfo; // size = 0xE + +class SetLightList : public SceneCommand<LightInfo> { + public: + using SceneCommand::SceneCommand; + + LightInfo* GetPointer(); + size_t GetPointerSize(); + + uint32_t numLights; + std::vector<LightInfo> lightList; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/SetLightingSettings.cpp b/mm/2s2h/resource/type/scenecommand/SetLightingSettings.cpp new file mode 100644 index 000000000..69127f19c --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetLightingSettings.cpp @@ -0,0 +1,11 @@ +#include "SetLightingSettings.h" + +namespace LUS { +EnvLightSettings* SetLightingSettings::GetPointer() { + return settings.data(); +} + +size_t SetLightingSettings::GetPointerSize() { + return settings.size() * sizeof(EnvLightSettings); +} +} // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/SetLightingSettings.h b/mm/2s2h/resource/type/scenecommand/SetLightingSettings.h new file mode 100644 index 000000000..ca894fec3 --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetLightingSettings.h @@ -0,0 +1,31 @@ +#pragma once + +#include <cstdint> +#include <vector> +#include <memory> +#include "Resource.h" +#include "SceneCommand.h" +#include <libultraship/libultra/types.h> + +namespace LUS { +typedef struct { + /* 0x00 */ u8 ambientColor[3]; + /* 0x03 */ s8 light1Dir[3]; + /* 0x06 */ u8 light1Color[3]; + /* 0x09 */ s8 light2Dir[3]; + /* 0x0C */ u8 light2Color[3]; + /* 0x0F */ u8 fogColor[3]; + /* 0x12 */ s16 fogNear; + /* 0x14 */ s16 fogFar; +} EnvLightSettings; // size = 0x16 + +class SetLightingSettings : public SceneCommand<EnvLightSettings> { + public: + using SceneCommand::SceneCommand; + + EnvLightSettings* GetPointer(); + size_t GetPointerSize(); + + std::vector<EnvLightSettings> settings; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/SetMesh.cpp b/mm/2s2h/resource/type/scenecommand/SetMesh.cpp new file mode 100644 index 000000000..5ecd2cbfa --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetMesh.cpp @@ -0,0 +1,11 @@ +#include "SetMesh.h" + +namespace LUS { +MeshHeader* SetMesh::GetPointer() { + return &meshHeader; +} + +size_t SetMesh::GetPointerSize() { + return sizeof(MeshHeader); +} +} // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/SetMesh.h b/mm/2s2h/resource/type/scenecommand/SetMesh.h new file mode 100644 index 000000000..a3a6c9731 --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetMesh.h @@ -0,0 +1,103 @@ +#pragma once + +#include <cstdint> +#include <vector> +#include <memory> +#include "Resource.h" +#include "SceneCommand.h" +#include "libultraship/libultra.h" +#include "z64math.h" + +namespace LUS { +typedef struct { + /* 0x00 */ u8 type; +} PolygonBase; + +typedef struct { + /* 0x00 */ PolygonBase base; + /* 0x01 */ u8 num; // number of dlist entries + /* 0x04 */ void* start; + /* 0x08 */ void* end; +} PolygonType0; // size = 0xC + +typedef struct { + /* 0x00 */ u16 unk_00; + /* 0x02 */ u8 id; + /* 0x04 */ void* source; + /* 0x08 */ u32 unk_0C; + /* 0x0C */ u32 tlut; + /* 0x10 */ u16 width; + /* 0x12 */ u16 height; + /* 0x14 */ u8 fmt; + /* 0x15 */ u8 siz; + /* 0x16 */ u16 mode0; + /* 0x18 */ u16 tlutCount; +} BgImage; // size = 0x1C + +typedef struct { + /* 0x00 */ PolygonBase base; + /* 0x01 */ u8 format; // 1 = single, 2 = multi + /* 0x04 */ Gfx* dlist; + union { + struct { + /* 0x08 */ void* source; + /* 0x0C */ u32 unk_0C; + /* 0x10 */ void* tlut; + /* 0x14 */ u16 width; + /* 0x16 */ u16 height; + /* 0x18 */ u8 fmt; + /* 0x19 */ u8 siz; + /* 0x1A */ u16 mode0; + /* 0x1C */ u16 tlutCount; + } single; + struct { + /* 0x08 */ u8 count; + /* 0x0C */ BgImage* list; + } multi; + }; +} PolygonType1; + +typedef struct { + /* 0x00 */ PolygonBase base; + /* 0x01 */ u8 num; // number of dlist entries + /* 0x04 */ void* start; + /* 0x08 */ void* end; +} PolygonType2; // size = 0xC + +typedef union { + PolygonBase base; + PolygonType0 polygon0; + PolygonType1 polygon1; + PolygonType2 polygon2; +} MeshHeader; // "Ground Shape" + +typedef struct { + /* 0x00 */ Vec3s pos; + /* 0x06 */ s16 unk_06; + /* 0x08 */ Gfx* opa; + /* 0x0C */ Gfx* xlu; +} PolygonDlist2; // size = 0x8 + +typedef struct { + /* 0x00 */ Gfx* opa; + /* 0x04 */ Gfx* xlu; +} PolygonDlist; // size = 0x8 + +class SetMesh : public SceneCommand<MeshHeader> { + public: + using SceneCommand::SceneCommand; + + MeshHeader* GetPointer(); + size_t GetPointerSize(); + + uint32_t numPoly; + uint8_t data; + uint8_t meshHeaderType; + + std::vector<PolygonDlist> dlists; + std::vector<PolygonDlist2> dlists2; + std::vector<std::string> imagePaths; + std::vector<BgImage> images; + MeshHeader meshHeader; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/SetMinimapChests.cpp b/mm/2s2h/resource/type/scenecommand/SetMinimapChests.cpp new file mode 100644 index 000000000..dde6da61d --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetMinimapChests.cpp @@ -0,0 +1,13 @@ +#include "SetMinimapChests.h" + +namespace LUS { + +MinimapChestData* SetMinimapChests::GetPointer() { + return chests.data(); +} + +size_t SetMinimapChests::GetPointerSize() { + return sizeof(MinimapChestData); +} + +} // namespace LUS
\ No newline at end of file diff --git a/mm/2s2h/resource/type/scenecommand/SetMinimapChests.h b/mm/2s2h/resource/type/scenecommand/SetMinimapChests.h new file mode 100644 index 000000000..2877d4dc7 --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetMinimapChests.h @@ -0,0 +1,23 @@ +#pragma once +#include "Resource.h" +#include "SceneCommand.h" + +namespace LUS { +typedef struct { + int16_t unk_0; + int16_t unk_2; + int16_t unk_4; + int16_t unk_6; + int16_t unk_8; +} MinimapChestData; + +class SetMinimapChests : public SceneCommand<MinimapChestData> { + public: + using SceneCommand::SceneCommand; + + MinimapChestData* GetPointer(); + size_t GetPointerSize(); + std::vector<MinimapChestData> chests; +}; + +} diff --git a/mm/2s2h/resource/type/scenecommand/SetMinimapList.cpp b/mm/2s2h/resource/type/scenecommand/SetMinimapList.cpp new file mode 100644 index 000000000..e97a6eee0 --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetMinimapList.cpp @@ -0,0 +1,13 @@ +#include "SetMinimapList.h" + +namespace LUS { + +MinimapListData* LUS::SetMinimapList::GetPointer() { + return &list; +} + +size_t LUS::SetMinimapList::GetPointerSize() { + return sizeof(list); +} + +} // namespace LUS
\ No newline at end of file diff --git a/mm/2s2h/resource/type/scenecommand/SetMinimapList.h b/mm/2s2h/resource/type/scenecommand/SetMinimapList.h new file mode 100644 index 000000000..ecebbc323 --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetMinimapList.h @@ -0,0 +1,33 @@ +#pragma once + +#include "Resource.h" +#include "SceneCommand.h" +#include <libultraship/libultra/types.h> + + +namespace LUS { +typedef struct { + /* 0x00 */ u16 mapId; + /* 0x02 */ s16 unk2; + /* 0x04 */ s16 unk4; + /* 0x06 */ s16 unk6; + /* 0x08 */ u16 unk8; // flags; 1 = mirror x? 2 = mirror y? +} MinimapEntryData; // size = 0xA + +typedef struct { + /* 0x00 */ MinimapEntryData* entry; + /* 0x04 */ s16 scale; +} MinimapListData; // size = 0x8 + + +class SetMinimapList : public SceneCommand<MinimapListData> { + public: + using SceneCommand::SceneCommand; + MinimapListData* GetPointer(); + size_t GetPointerSize(); + + MinimapListData list; + std::vector<MinimapEntryData> entries; +}; + +} diff --git a/mm/2s2h/resource/type/scenecommand/SetObjectList.cpp b/mm/2s2h/resource/type/scenecommand/SetObjectList.cpp new file mode 100644 index 000000000..921166675 --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetObjectList.cpp @@ -0,0 +1,11 @@ +#include "SetObjectList.h" + +namespace LUS { +int16_t* SetObjectList::GetPointer() { + return objects.data(); +} + +size_t SetObjectList::GetPointerSize() { + return objects.size() * sizeof(int16_t); +} +} // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/SetObjectList.h b/mm/2s2h/resource/type/scenecommand/SetObjectList.h new file mode 100644 index 000000000..c6f786636 --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetObjectList.h @@ -0,0 +1,22 @@ +#pragma once + +#include <cstdint> +#include <vector> +#include <memory> +#include <string> +#include "Resource.h" +#include "SceneCommand.h" +#include <libultraship/libultra/types.h> + +namespace LUS { +class SetObjectList : public SceneCommand<int16_t> { + public: + using SceneCommand::SceneCommand; + + int16_t* GetPointer(); + size_t GetPointerSize(); + + uint32_t numObjects; + std::vector<int16_t> objects; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/SetPathways.cpp b/mm/2s2h/resource/type/scenecommand/SetPathways.cpp new file mode 100644 index 000000000..046543a5b --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetPathways.cpp @@ -0,0 +1,18 @@ +#include "SetPathways.h" + +namespace LUS { +PathData** SetPathways::GetPointer() { + return paths.data(); +} + +size_t SetPathways::GetPointerSize() { + return paths.size() * sizeof(PathData*); +} + +PathDataMM** SetPathwaysMM::GetPointer() { + return paths.data(); +} +size_t SetPathwaysMM::GetPointerSize() { + return paths.size() * sizeof(PathData*); +} +} // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/SetPathways.h b/mm/2s2h/resource/type/scenecommand/SetPathways.h new file mode 100644 index 000000000..e72cdcb29 --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetPathways.h @@ -0,0 +1,35 @@ +#pragma once + +#include <cstdint> +#include <vector> +#include <memory> +#include "Resource.h" +#include "SceneCommand.h" +// #include <libultraship/libultra/types.h> +#include "2s2h/resource/type/Path.h" + +namespace LUS { + +class SetPathways : public SceneCommand<PathData*> { + public: + using SceneCommand::SceneCommand; + + PathData** GetPointer(); + size_t GetPointerSize(); + + uint32_t numPaths; + std::vector<PathData*> paths; +}; + +class SetPathwaysMM : public SceneCommand<PathDataMM*> { + public: + using SceneCommand::SceneCommand; + + PathDataMM** GetPointer(); + size_t GetPointerSize(); + + uint32_t numPaths; + std::vector<PathDataMM*> paths; +}; + +}; // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/SetRoomBehavior.cpp b/mm/2s2h/resource/type/scenecommand/SetRoomBehavior.cpp new file mode 100644 index 000000000..deababc87 --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetRoomBehavior.cpp @@ -0,0 +1,11 @@ +#include "SetRoomBehavior.h" + +namespace LUS { +RoomBehavior* SetRoomBehavior::GetPointer() { + return &roomBehavior; +} + +size_t SetRoomBehavior::GetPointerSize() { + return sizeof(RoomBehavior); +} +} // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/SetRoomBehavior.h b/mm/2s2h/resource/type/scenecommand/SetRoomBehavior.h new file mode 100644 index 000000000..c2a28176e --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetRoomBehavior.h @@ -0,0 +1,25 @@ +#pragma once + +#include <cstdint> +#include <vector> +#include <memory> +#include "Resource.h" +#include "SceneCommand.h" +#include <libultraship/libultra/types.h> + +namespace LUS { +typedef struct { + int8_t gameplayFlags; + int32_t gameplayFlags2; +} RoomBehavior; + +class SetRoomBehavior : public SceneCommand<RoomBehavior> { + public: + using SceneCommand::SceneCommand; + + RoomBehavior* GetPointer(); + size_t GetPointerSize(); + + RoomBehavior roomBehavior; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/SetRoomList.cpp b/mm/2s2h/resource/type/scenecommand/SetRoomList.cpp new file mode 100644 index 000000000..cf8c1d61a --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetRoomList.cpp @@ -0,0 +1,11 @@ +#include "SetRoomList.h" + +namespace LUS { +RomFile* SetRoomList::GetPointer() { + return rooms.data(); +} + +size_t SetRoomList::GetPointerSize() { + return rooms.size() * sizeof(RomFile); +} +} // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/SetRoomList.h b/mm/2s2h/resource/type/scenecommand/SetRoomList.h new file mode 100644 index 000000000..9bd0e07bc --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetRoomList.h @@ -0,0 +1,35 @@ +#pragma once + +#include <cstdint> +#include <vector> +#include <memory> +#include <string> +#include "Resource.h" +#include "SceneCommand.h" +#include "RomFile.h" +#include <libultraship/libultra/types.h> +#include <spdlog/spdlog.h> + +namespace LUS { +// typedef struct { +// /* 0x00 */ uintptr_t vromStart; +// /* 0x04 */ uintptr_t vromEnd; +// char* fileName; +// } RomFile; // size = 0x8 + +class SetRoomList : public SceneCommand<RomFile> { + public: + using SceneCommand::SceneCommand; + + RomFile* GetPointer(); + size_t GetPointerSize(); + + uint32_t numRooms; + + std::vector<std::string> fileNames; + std::vector<RomFile> rooms; + ~SetRoomList() { + SPDLOG_TRACE("ROOM LIST DTOR"); + } +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/SetSkyboxModifier.cpp b/mm/2s2h/resource/type/scenecommand/SetSkyboxModifier.cpp new file mode 100644 index 000000000..9926ec01a --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetSkyboxModifier.cpp @@ -0,0 +1,11 @@ +#include "SetSkyboxModifier.h" + +namespace LUS { +SkyboxModifier* SetSkyboxModifier::GetPointer() { + return &modifier; +} + +size_t SetSkyboxModifier::GetPointerSize() { + return sizeof(SkyboxModifier); +} +} // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/SetSkyboxModifier.h b/mm/2s2h/resource/type/scenecommand/SetSkyboxModifier.h new file mode 100644 index 000000000..6a54879e6 --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetSkyboxModifier.h @@ -0,0 +1,25 @@ +#pragma once + +#include <cstdint> +#include <vector> +#include <memory> +#include "Resource.h" +#include "SceneCommand.h" +#include <libultraship/libultra/types.h> + +namespace LUS { +typedef struct { + uint8_t skyboxDisabled; + uint8_t sunMoonDisabled; +} SkyboxModifier; + +class SetSkyboxModifier : public SceneCommand<SkyboxModifier> { + public: + using SceneCommand::SceneCommand; + + SkyboxModifier* GetPointer(); + size_t GetPointerSize(); + + SkyboxModifier modifier; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/SetSkyboxSettings.cpp b/mm/2s2h/resource/type/scenecommand/SetSkyboxSettings.cpp new file mode 100644 index 000000000..7f12d4fa3 --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetSkyboxSettings.cpp @@ -0,0 +1,11 @@ +#include "SetSkyboxSettings.h" + +namespace LUS { +SkyboxSettings* SetSkyboxSettings::GetPointer() { + return &settings; +} + +size_t SetSkyboxSettings::GetPointerSize() { + return sizeof(SetSkyboxSettings); +} +} // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/SetSkyboxSettings.h b/mm/2s2h/resource/type/scenecommand/SetSkyboxSettings.h new file mode 100644 index 000000000..a2a9593b0 --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetSkyboxSettings.h @@ -0,0 +1,27 @@ +#pragma once + +#include <cstdint> +#include <vector> +#include <memory> +#include "Resource.h" +#include "SceneCommand.h" +#include <libultraship/libultra/types.h> + +namespace LUS { +typedef struct { + uint8_t unk; + uint8_t skyboxId; + uint8_t weather; + uint8_t indoors; +} SkyboxSettings; + +class SetSkyboxSettings : public SceneCommand<SkyboxSettings> { + public: + using SceneCommand::SceneCommand; + + SkyboxSettings* GetPointer(); + size_t GetPointerSize(); + + SkyboxSettings settings; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/SetSoundSettings.cpp b/mm/2s2h/resource/type/scenecommand/SetSoundSettings.cpp new file mode 100644 index 000000000..f6f1941d1 --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetSoundSettings.cpp @@ -0,0 +1,11 @@ +#include "SetSoundSettings.h" + +namespace LUS { +SoundSettings* SetSoundSettings::GetPointer() { + return &settings; +} + +size_t SetSoundSettings::GetPointerSize() { + return sizeof(SoundSettings); +} +} // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/SetSoundSettings.h b/mm/2s2h/resource/type/scenecommand/SetSoundSettings.h new file mode 100644 index 000000000..c4ee4668d --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetSoundSettings.h @@ -0,0 +1,26 @@ +#pragma once + +#include <cstdint> +#include <vector> +#include <memory> +#include "Resource.h" +#include "SceneCommand.h" +#include <libultraship/libultra/types.h> + +namespace LUS { +typedef struct { + uint8_t seqId; + uint8_t natureAmbienceId; + uint8_t reverb; +} SoundSettings; + +class SetSoundSettings : public SceneCommand<SoundSettings> { + public: + using SceneCommand::SceneCommand; + + SoundSettings* GetPointer(); + size_t GetPointerSize(); + + SoundSettings settings; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/SetSpecialObjects.cpp b/mm/2s2h/resource/type/scenecommand/SetSpecialObjects.cpp new file mode 100644 index 000000000..3887107da --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetSpecialObjects.cpp @@ -0,0 +1,11 @@ +#include "SetSpecialObjects.h" + +namespace LUS { +SpecialObjects* SetSpecialObjects::GetPointer() { + return &specialObjects; +} + +size_t SetSpecialObjects::GetPointerSize() { + return sizeof(SpecialObjects); +} +} // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/SetSpecialObjects.h b/mm/2s2h/resource/type/scenecommand/SetSpecialObjects.h new file mode 100644 index 000000000..78cfcd425 --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetSpecialObjects.h @@ -0,0 +1,25 @@ +#pragma once + +#include <cstdint> +#include <vector> +#include <memory> +#include "Resource.h" +#include "SceneCommand.h" +#include <libultraship/libultra/types.h> + +namespace LUS { +typedef struct { + int8_t elfMessage; + int16_t globalObject; +} SpecialObjects; + +class SetSpecialObjects : public SceneCommand<SpecialObjects> { + public: + using SceneCommand::SceneCommand; + + SpecialObjects* GetPointer(); + size_t GetPointerSize(); + + SpecialObjects specialObjects; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/SetStartPositionList.cpp b/mm/2s2h/resource/type/scenecommand/SetStartPositionList.cpp new file mode 100644 index 000000000..89fb40049 --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetStartPositionList.cpp @@ -0,0 +1,11 @@ +#include "SetStartPositionList.h" + +namespace LUS { +ActorEntry* SetStartPositionList::GetPointer() { + return startPositions.data(); +} + +size_t SetStartPositionList::GetPointerSize() { + return startPositions.size() * sizeof(ActorEntry); +} +} // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/SetStartPositionList.h b/mm/2s2h/resource/type/scenecommand/SetStartPositionList.h new file mode 100644 index 000000000..cc939aca0 --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetStartPositionList.h @@ -0,0 +1,30 @@ +#pragma once + +#include <cstdint> +#include <vector> +#include <memory> +#include <string> +#include "Resource.h" +#include "SceneCommand.h" +#include "2s2h/resource/type/scenecommand/SetActorList.h" +// #include <libultraship/libultra/types.h> + +namespace LUS { +// typedef struct { +// /* 0x00 */ s16 id; +// /* 0x02 */ Vec3s pos; +// /* 0x08 */ Vec3s rot; +// /* 0x0E */ s16 params; +// } ActorEntry; // size = 0x10 + +class SetStartPositionList : public SceneCommand<ActorEntry> { + public: + using SceneCommand::SceneCommand; + + ActorEntry* GetPointer(); + size_t GetPointerSize(); + + uint32_t numStartPositions; + std::vector<ActorEntry> startPositions; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/SetTimeSettings.cpp b/mm/2s2h/resource/type/scenecommand/SetTimeSettings.cpp new file mode 100644 index 000000000..9a10fb022 --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetTimeSettings.cpp @@ -0,0 +1,11 @@ +#include "SetTimeSettings.h" + +namespace LUS { +TimeSettings* SetTimeSettings::GetPointer() { + return &settings; +} + +size_t SetTimeSettings::GetPointerSize() { + return sizeof(TimeSettings); +} +} // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/SetTimeSettings.h b/mm/2s2h/resource/type/scenecommand/SetTimeSettings.h new file mode 100644 index 000000000..637398652 --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetTimeSettings.h @@ -0,0 +1,26 @@ +#pragma once + +#include <cstdint> +#include <vector> +#include <memory> +#include "Resource.h" +#include "SceneCommand.h" +#include <libultraship/libultra/types.h> + +namespace LUS { +typedef struct { + uint8_t hour; + uint8_t minute; + uint8_t timeIncrement; +} TimeSettings; + +class SetTimeSettings : public SceneCommand<TimeSettings> { + public: + using SceneCommand::SceneCommand; + + TimeSettings* GetPointer(); + size_t GetPointerSize(); + + TimeSettings settings; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/SetTransitionActorList.cpp b/mm/2s2h/resource/type/scenecommand/SetTransitionActorList.cpp new file mode 100644 index 000000000..86387e682 --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetTransitionActorList.cpp @@ -0,0 +1,11 @@ +#include "SetTransitionActorList.h" + +namespace LUS { +TransitionActorEntry* SetTransitionActorList::GetPointer() { + return transitionActorList.data(); +} + +size_t SetTransitionActorList::GetPointerSize() { + return transitionActorList.size() * sizeof(TransitionActorEntry); +} +} // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/SetTransitionActorList.h b/mm/2s2h/resource/type/scenecommand/SetTransitionActorList.h new file mode 100644 index 000000000..bb6fc2ac6 --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetTransitionActorList.h @@ -0,0 +1,34 @@ +#pragma once + +#include <cstdint> +#include <vector> +#include <memory> +#include <string> +#include "Resource.h" +#include "SceneCommand.h" +// #include <libultraship/libultra/types.h> +#include "z64math.h" + +namespace LUS { +typedef struct { + struct { + s8 room; // Room to switch to + s8 effects; // How the camera reacts during the transition + } /* 0x00 */ sides[2]; // 0 = front, 1 = back + /* 0x04 */ s16 id; + /* 0x06 */ Vec3s pos; + /* 0x0C */ s16 rotY; + /* 0x0E */ s16 params; +} TransitionActorEntry; // size = 0x10 + +class SetTransitionActorList : public SceneCommand<TransitionActorEntry> { + public: + using SceneCommand::SceneCommand; + + TransitionActorEntry* GetPointer(); + size_t GetPointerSize(); + + uint32_t numTransitionActors; + std::vector<TransitionActorEntry> transitionActorList; +}; +}; // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/SetWindSettings.cpp b/mm/2s2h/resource/type/scenecommand/SetWindSettings.cpp new file mode 100644 index 000000000..3aa9ce7a6 --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetWindSettings.cpp @@ -0,0 +1,11 @@ +#include "SetWindSettings.h" + +namespace LUS { +WindSettings* SetWindSettings::GetPointer() { + return &settings; +} + +size_t SetWindSettings::GetPointerSize() { + return sizeof(WindSettings); +} +} // namespace LUS diff --git a/mm/2s2h/resource/type/scenecommand/SetWindSettings.h b/mm/2s2h/resource/type/scenecommand/SetWindSettings.h new file mode 100644 index 000000000..e79b445ae --- /dev/null +++ b/mm/2s2h/resource/type/scenecommand/SetWindSettings.h @@ -0,0 +1,27 @@ +#pragma once + +#include <cstdint> +#include <vector> +#include <memory> +#include "Resource.h" +#include "SceneCommand.h" +#include <libultraship/libultra/types.h> + +namespace LUS { +typedef struct { + int8_t windWest; + int8_t windVertical; + int8_t windSouth; + uint8_t windSpeed; +} WindSettings; + +class SetWindSettings : public SceneCommand<WindSettings> { + public: + using SceneCommand::SceneCommand; + + WindSettings* GetPointer(); + size_t GetPointerSize(); + + WindSettings settings; +}; +}; // namespace LUS diff --git a/mm/2s2h/z_message_OTR.cpp b/mm/2s2h/z_message_OTR.cpp new file mode 100644 index 000000000..808d9b794 --- /dev/null +++ b/mm/2s2h/z_message_OTR.cpp @@ -0,0 +1,87 @@ +#include "BenPort.h" +#include <libultraship/libultraship.h> +#include "2s2h/resource/type/Scene.h" +#include <Utils/StringHelper.h> +#include "global.h" +#include "vt.h" +#include "2s2h/resource/type/TextMM.h" +#include <message_data_static.h> +#include <resource/type/Text.h> + +// BENTODO: This needs to be cleaned up. It can probably be implemented better. +struct MessageStruct +{ + uint8_t textboxType; + uint8_t textboxYPos; + uint8_t icon; + uint16_t nextMessageID; + uint16_t firstItemCost; + uint16_t secondItemCost; + uint16_t alwaysFFFF; +}; + +//extern "C" MessageTableEntry* sNesMessageEntryTablePtr; +//extern "C" MessageTableEntry* sStaffMessageEntryTablePtr; + +MessageTableEntry* OTRMessage_LoadTable(const char* filePath, bool isNES) { + auto file = std::static_pointer_cast<LUS::TextMM>(LUS::Context::GetInstance()->GetResourceManager()->LoadResource(filePath)); + + if (file == nullptr) + return nullptr; + + // Allocate room for an additional message + // OTRTODO: Should not be malloc'ing here. It's fine for now since we check elsewhere that the message table is + // already null. + MessageTableEntry* table = (MessageTableEntry*)malloc(sizeof(MessageTableEntry) * (file->messages.size() + 1)); + + for (size_t i = 0; i < file->messages.size(); i++) { + table[i].textId = file->messages[i].id; + table[i].typePos = (file->messages[i].textboxType << 4) | file->messages[i].textboxYPos; + table[i].segment = (const char*)malloc(file->messages[i].msg.size() + 11); + + MessageStruct* msgStruct = (MessageStruct*)table[i].segment; + msgStruct->textboxType = file->messages[i].textboxType; + msgStruct->textboxYPos = file->messages[i].textboxYPos; + msgStruct->icon = file->messages[i].icon; + msgStruct->nextMessageID = file->messages[i].nextMessageID; + msgStruct->firstItemCost = file->messages[i].firstItemCost; + msgStruct->secondItemCost = file->messages[i].secondItemCost; + msgStruct->alwaysFFFF = 0xFFFF; + + memcpy((void*)(&table[i].segment[11]), file->messages[i].msg.c_str(), file->messages[i].msg.size()); + + //table[i].segment = file->messages[i].msg.c_str(); + table[i].msgSize = file->messages[i].msg.size() + 11; + + //if (isNES && file->messages[i].id == 0xFFFC) + //_message_0xFFFC_nes = (char*)file->messages[i].msg.c_str(); + } + + return table; +} + +extern "C" void OTRMessage_Init(PlayState* play) { + // OTRTODO: Added a lot of null checks here so that we don't malloc the table multiple times causing a memory leak. + // We really ought to fix the implementation such that we aren't malloc'ing new tables. + // Once we fix the implementation, remove these NULL checks. + //if (play->msgCtx.messageEntryTableNes == NULL) { + play->msgCtx.messageEntryTableNes = OTRMessage_LoadTable("text/message_data_static/message_data_static", true); + play->msgCtx.messageEntryTable = play->msgCtx.messageEntryTableNes; + //} + + //if (play->msgCtx.messageTableStaff == NULL) { + auto file2 = + std::static_pointer_cast<LUS::TextMM>(LUS::Context::GetInstance()->GetResourceManager()->LoadResource( + "text/staff_message_data_static/staff_message_data_static")); + // OTRTODO: Should not be malloc'ing here. It's fine for now since we check that the message table is already null. + play->msgCtx.messageTableStaff = (MessageTableEntry*)malloc(sizeof(MessageTableEntry) * file2->messages.size()); + + for (size_t i = 0; i < file2->messages.size(); i++) { + play->msgCtx.messageTableStaff[i].textId = file2->messages[i].id; + play->msgCtx.messageTableStaff[i].typePos = + (file2->messages[i].textboxType << 4) | file2->messages[i].textboxYPos; + play->msgCtx.messageTableStaff[i].segment = file2->messages[i].msg.c_str(); + play->msgCtx.messageTableStaff[i].msgSize = file2->messages[i].msg.size(); + } + //} +} diff --git a/mm/2s2h/z_play_2SH.cpp b/mm/2s2h/z_play_2SH.cpp new file mode 100644 index 000000000..2350c4dbf --- /dev/null +++ b/mm/2s2h/z_play_2SH.cpp @@ -0,0 +1,80 @@ +#include "BenPort.h" +#include <libultraship/libultraship.h> +#include "2s2h/resource/type/Scene.h" +#include <Utils/StringHelper.h> +#include <Vertex.h> +extern "C" { +#include "global.h" +#include "vt.h" +#include <z64scene.h> +} +LUS::IResource* OTRPlay_LoadFile(PlayState* play, const char* fileName) { + auto res = LUS::Context::GetInstance()->GetResourceManager()->LoadResource(fileName); + return res.get(); +} + +s32 OTRScene_ExecuteCommands(PlayState* play, LUS::Scene* scene); + +extern "C" void OTRPlay_InitScene(PlayState* play, s32 spawn) { + play->curSpawn = spawn; + play->linkActorEntry = NULL; + play->actorCsCamList = NULL; + play->setupEntranceList = NULL; + play->setupExitList = NULL; + play->naviQuestHints = NULL; + play->setupPathList = NULL; + play->sceneMaterialAnims = NULL; + play->roomCtx.unk74 = NULL; + play->numSetupActors = 0; + Object_InitContext(&play->state, &play->objectCtx); + LightContext_Init(play, &play->lightCtx); + Scene_ResetTransiActorList(&play->state, &play->transitionActors); + Room_Init(play, &play->roomCtx); + gSaveContext.worldMapArea = 0; + OTRScene_ExecuteCommands(play, (LUS::Scene*)play->sceneSegment); + Play_InitEnvironment(play, play->skyboxId); +} + +extern "C" void OTRPlay_SpawnScene(PlayState* play, s32 sceneId, s32 spawn) { + s32 pad; + SceneTableEntry* scene = &gSceneTable[sceneId]; + + scene->unk_D = 0; + play->loadedScene = scene; + play->sceneId = sceneId; + play->sceneConfig = scene->drawConfig; + std::string scenePath = StringHelper::Sprintf("scenes/nonmq/%s/%s", scene->segment.fileName, scene->segment.fileName); + play->sceneSegment = OTRPlay_LoadFile(play, scenePath.c_str()); + scene->unk_D = 0; + gSegments[2] = (uintptr_t)VIRTUAL_TO_PHYSICAL(play->sceneSegment); + OTRPlay_InitScene(play, spawn); + Room_AllocateAndLoad(play, &play->roomCtx); +} + +extern "C" s32 OTRfunc_800973FC(PlayState* play, RoomContext* roomCtx) { + if (roomCtx->status == 1) { + // if (!osRecvMesg(&roomCtx->loadQueue, NULL, OS_MESG_NOBLOCK)) { + if (1) { + roomCtx->status = 0; + roomCtx->curRoom.segment = roomCtx->activeRoomVram; + gSegments[3] = (uintptr_t)VIRTUAL_TO_PHYSICAL(roomCtx->activeRoomVram); + + OTRScene_ExecuteCommands(play, (LUS::Scene*)roomCtx->curRoom.segment); + func_80123140(play, GET_PLAYER(play)); + Actor_SpawnTransitionActors(play, &play->actorCtx); + if (((play->sceneId != SCENE_IKANA) || (roomCtx->curRoom.num != 1)) && (play->sceneId != SCENE_IKNINSIDE)) { + play->envCtx.lightSettingOverride = LIGHT_SETTING_OVERRIDE_NONE; + play->envCtx.lightBlendOverride = LIGHT_BLEND_OVERRIDE_NONE; + } + func_800FEAB0(); + if (Environment_GetStormState(play) == STORM_STATE_OFF) { + Environment_StopStormNatureAmbience(play); + } + return 1; + } + + return 0; + } + + return 1; +}
\ No newline at end of file diff --git a/mm/2s2h/z_scene_2SH.cpp b/mm/2s2h/z_scene_2SH.cpp new file mode 100644 index 000000000..79945e9a8 --- /dev/null +++ b/mm/2s2h/z_scene_2SH.cpp @@ -0,0 +1,444 @@ +#include "BenPort.h" +extern "C" { +#include "z64.h" +#include "vt.h" +#include "global.h" +} +#include <libultraship/libultraship.h> +#include <Blob.h> +#include <memory> +#include <cassert> +#include <Utils/StringHelper.h> +#include <DisplayList.h> +#include "2s2h/resource/type/Scene.h" +#include "2s2h/resource/type/CollisionHeader.h" +#include "2s2h/resource/type/Cutscene.h" +#include "2s2h/resource/type/Path.h" +#include "2s2h/resource/type/Text.h" +#include "2s2h/resource/type/scenecommand/SetCameraSettings.h" +#include "2s2h/resource/type/scenecommand/SetCutscenes.h" +#include "2s2h/resource/type/scenecommand/SetStartPositionList.h" +#include "2s2h/resource/type/scenecommand/SetActorList.h" +#include "2s2h/resource/type/scenecommand/SetCollisionHeader.h" +#include "2s2h/resource/type/scenecommand/SetRoomList.h" +#include "2s2h/resource/type/scenecommand/SetEntranceList.h" +#include "2s2h/resource/type/scenecommand/SetSpecialObjects.h" +#include "2s2h/resource/type/scenecommand/SetRoomBehavior.h" +#include "2s2h/resource/type/scenecommand/SetMesh.h" +#include "2s2h/resource/type/scenecommand/SetObjectList.h" +#include "2s2h/resource/type/scenecommand/SetLightList.h" +#include "2s2h/resource/type/scenecommand/SetPathways.h" +#include "2s2h/resource/type/scenecommand/SetTransitionActorList.h" +#include "2s2h/resource/type/scenecommand/SetSkyboxSettings.h" +#include "2s2h/resource/type/scenecommand/SetSkyboxModifier.h" +#include "2s2h/resource/type/scenecommand/SetTimeSettings.h" +#include "2s2h/resource/type/scenecommand/SetWindSettings.h" +#include "2s2h/resource/type/scenecommand/SetSoundSettings.h" +#include "2s2h/resource/type/scenecommand/SetEchoSettings.h" +#include "2s2h/resource/type/scenecommand/SetAlternateHeaders.h" +#include "2s2h/resource/type/scenecommand/SetActorCutsceneList.h" +#include "2s2h/resource/type/scenecommand/SetAnimatedMaterialList.h" +#include "2s2h/resource/type/scenecommand/SetMinimapList.h" +#include "2s2h/resource/type/scenecommand/SetMinimapChests.h" +#include "2s2h/resource/type/scenecommand/SetCsCamera.h" + +s32 OTRScene_ExecuteCommands(PlayState* play, LUS::Scene* scene); + + +void Scene_CommandSpawnList(PlayState* play, LUS::ISceneCommand* cmd) { + LUS::SetStartPositionList* list = (LUS::SetStartPositionList*)cmd; + ActorEntry* entries = (ActorEntry*)(list->GetRawPointer()); + s32 loadedCount; + s16 playerObjectId; + void* objectPtr; + + play->linkActorEntry = &entries[play->setupEntranceList[play->curSpawn].spawn]; + + if ((PLAYER_GET_INITMODE(play->linkActorEntry) == PLAYER_INITMODE_TELESCOPE) || + ((gSaveContext.respawnFlag == 2) && + (gSaveContext.respawn[RESPAWN_MODE_RETURN].playerParams == PLAYER_PARAMS(0xFF, PLAYER_INITMODE_TELESCOPE)))) { + // Skull Kid Object + Object_SpawnPersistent(&play->objectCtx, OBJECT_STK); + return; + } + + loadedCount = Object_SpawnPersistent(&play->objectCtx, OBJECT_LINK_CHILD); + objectPtr = play->objectCtx.slots[play->objectCtx.numEntries].segment; + play->objectCtx.numEntries = loadedCount; + play->objectCtx.numPersistentEntries = loadedCount; + playerObjectId = gPlayerFormObjectIds[GET_PLAYER_FORM]; + gActorOverlayTable[0].initInfo->objectId = playerObjectId; + Object_SpawnPersistent(&play->objectCtx, playerObjectId); + + play->objectCtx.slots[play->objectCtx.numEntries].segment = objectPtr; +} + +void Scene_CommandActorList(PlayState* play, LUS::ISceneCommand* cmd) { + LUS::SetActorList* list = (LUS::SetActorList*)cmd; + + play->numSetupActors = list->numActors; + play->actorCtx.halfDaysBit = 0; + play->setupActorList = (ActorEntry*)list->GetRawPointer(); +} + +void Scene_CommandActorCutsceneCamList(PlayState* play, LUS::ISceneCommand* cmd) { + LUS::SetCsCamera* cams = (LUS::SetCsCamera*)cmd; + + play->actorCsCamList = (ActorCsCamInfo*)cams->GetPointer(); +} + +void Scene_CommandCollisionHeader(PlayState* play, LUS::ISceneCommand* cmd) { + LUS::SetCollisionHeader* colHeader = (LUS::SetCollisionHeader*)cmd; + BgCheck_Allocate(&play->colCtx, play, (CollisionHeader*)colHeader->GetRawPointer()); +} + +void Scene_CommandRoomList(PlayState* play, LUS::ISceneCommand* cmd) { + LUS::SetRoomList* list = (LUS::SetRoomList*)cmd; + play->numRooms = list->numRooms; + play->roomList = (RomFile*)list->GetPointer(); +} + +void Scene_CommandWindSettings(PlayState* play, LUS::ISceneCommand* cmd) { + LUS::SetWindSettings* settings = (LUS::SetWindSettings*)cmd; + + play->envCtx.windDirection.x = settings->settings.windWest; + play->envCtx.windDirection.y = settings->settings.windVertical; + play->envCtx.windDirection.z = settings->settings.windSouth; + play->envCtx.windSpeed = settings->settings.windSpeed; +} + +void Scene_CommandEntranceList(PlayState* play, LUS::ISceneCommand* cmd) { + LUS::SetEntranceList* list = (LUS::SetEntranceList*)cmd; + + play->setupEntranceList = (EntranceEntry*)list->GetRawPointer(); +} + +void Scene_CommandSpecialFiles(PlayState* play, LUS::ISceneCommand* cmd) { + printf("Un-implemented command %02X\n", cmd->cmdId); + // Unused according to z_scene.c +} + +void Scene_CommandRoomBehavior(PlayState* play, LUS::ISceneCommand* cmd) { + LUS::SetRoomBehavior* behavior = (LUS::SetRoomBehavior*)cmd; + + play->roomCtx.curRoom.behaviorType1 = behavior->roomBehavior.gameplayFlags; + play->roomCtx.curRoom.behaviorType2 = behavior->roomBehavior.gameplayFlags2 & 0xFF; + play->roomCtx.curRoom.lensMode = (behavior->roomBehavior.gameplayFlags2 >> 8) & 1; + play->msgCtx.unk12044 = (behavior->roomBehavior.gameplayFlags2 >> 0xA) & 1; + play->roomCtx.curRoom.enablePosLights = (behavior->roomBehavior.gameplayFlags2 >> 0xB) & 1; + play->envCtx.stormState = (behavior->roomBehavior.gameplayFlags2 >> 0xC) & 1; +} + +void Scene_Command09(PlayState* play, LUS::ISceneCommand* cmd) { + // Empty in z_scene.c +} + +void Scene_CommandMesh(PlayState* play, LUS::ISceneCommand* cmd) { + LUS::SetMesh* mesh = (LUS::SetMesh*)cmd; + + play->roomCtx.curRoom.roomShape = (RoomShape*)mesh->GetRawPointer(); +} + +void Scene_CommandObjectList(PlayState* play, LUS::ISceneCommand* cmd) { + LUS::SetObjectList* objList = (LUS::SetObjectList*)cmd; + + s16* entry = (s16*)objList->GetRawPointer(); + + for (unsigned int i = 0; i < objList->objects.size(); i++) { + bool alreadyIncluded = true; + + for (unsigned int j = 0; j < play->objectCtx.numEntries; j++) { + if (play->objectCtx.slots[j].id == objList->objects[i]) { + alreadyIncluded = true; + break; + } + } + + if (!alreadyIncluded) { + play->objectCtx.slots[play->objectCtx.numEntries++].id = objList->objects[i]; + Actor_KillAllWithMissingObject(play, &play->actorCtx); + } + } +} + +void Scene_CommandLightList(PlayState* play, LUS::ISceneCommand* cmd) { + LUS::SetLightList* lightList = (LUS::SetLightList*)cmd; + + for (unsigned int i = 0; i < lightList->numLights; i++) { + LightContext_InsertLight(play, &play->lightCtx, (LightInfo*)&lightList->lightList[i]); + } +} + +void Scene_CommandPathList(PlayState* play, LUS::ISceneCommand* cmd) { + LUS::SetPathwaysMM* paths = (LUS::SetPathwaysMM*)cmd; + + play->setupPathList = (Path*)paths->GetPointer()[0]; +} + +void Scene_CommandTransiActorList(PlayState* play, LUS::ISceneCommand* cmd) { + LUS::SetTransitionActorList* list = (LUS::SetTransitionActorList*)cmd; + + play->transitionActors.count = list->numTransitionActors; + play->transitionActors.list = (TransitionActorEntry*)list->GetRawPointer(); +} + +void Scene_CommandEnvLightSettings(PlayState* play, LUS::ISceneCommand* cmd) { + play->envCtx.lightSettingsList = (EnvLightSettings*)cmd->GetRawPointer(); +} + +void Scene_CommandTimeSettings(PlayState* play, LUS::ISceneCommand* cmd) { + LUS::SetTimeSettings* settings = (LUS::SetTimeSettings*)cmd; + + if ((settings->settings.hour != 0xFF) && (settings->settings.minute != 0xFF)) { + gSaveContext.skyboxTime = gSaveContext.save.time = CLOCK_TIME_ALT2_F(settings->settings.hour, settings->settings.minute); + } + + if (settings->settings.timeIncrement != 0xFF) { + play->envCtx.sceneTimeSpeed = settings->settings.timeIncrement; + } else { + play->envCtx.sceneTimeSpeed = 0; + } + + // Increase time speed during first cycle + if ((gSaveContext.save.saveInfo.inventory.items[SLOT_OCARINA] == ITEM_NONE) && (play->envCtx.sceneTimeSpeed != 0)) { + play->envCtx.sceneTimeSpeed = 5; + } + + if (gSaveContext.sunsSongState == SUNSSONG_INACTIVE) { + R_TIME_SPEED = play->envCtx.sceneTimeSpeed; + } + + play->envCtx.sunPos.x = -(Math_SinS(((void)0, gSaveContext.save.time) - CLOCK_TIME(12, 0)) * 120.0f) * 25.0f; + play->envCtx.sunPos.y = (Math_CosS(((void)0, gSaveContext.save.time) - CLOCK_TIME(12, 0)) * 120.0f) * 25.0f; + play->envCtx.sunPos.z = (Math_CosS(((void)0, gSaveContext.save.time) - CLOCK_TIME(12, 0)) * 20.0f) * 25.0f; + + if ((play->envCtx.sceneTimeSpeed == 0) && (gSaveContext.save.cutsceneIndex < 0xFFF0)) { + gSaveContext.skyboxTime = gSaveContext.save.time; + + if ((gSaveContext.skyboxTime >= CLOCK_TIME(4, 0)) && (gSaveContext.skyboxTime < CLOCK_TIME(6, 30))) { + gSaveContext.skyboxTime = CLOCK_TIME(5, 0); + } else if ((gSaveContext.skyboxTime >= CLOCK_TIME(6, 30)) && (gSaveContext.skyboxTime < CLOCK_TIME(8, 0))) { + gSaveContext.skyboxTime = CLOCK_TIME(8, 0); + } else if ((gSaveContext.skyboxTime >= CLOCK_TIME(16, 0)) && (gSaveContext.skyboxTime < CLOCK_TIME(17, 0))) { + gSaveContext.skyboxTime = CLOCK_TIME(17, 0); + } else if ((gSaveContext.skyboxTime >= CLOCK_TIME(18, 0)) && (gSaveContext.skyboxTime < CLOCK_TIME(19, 0))) { + gSaveContext.skyboxTime = CLOCK_TIME(19, 0); + } + } +} + +void Scene_CommandSkyboxSettings(PlayState* play, LUS::ISceneCommand* cmd) { + LUS::SetSkyboxSettings* settings = (LUS::SetSkyboxSettings*)cmd; + + play->skyboxId = settings->settings.skyboxId & 3; + // BENTODO z_scene.c reads from skyboxSettings.skyboxConfig not weather + // Settings uses names from OOT + play->envCtx.skyboxConfig = play->envCtx.changeSkyboxNextConfig = settings->settings.weather; + play->envCtx.lightMode = settings->settings.indoors; + //Scene_LoadAreaTextures(play, settings->settings.) +} + +void Scene_CommandSkyboxDisables(PlayState* play, LUS::ISceneCommand* cmd) { + LUS::SetSkyboxModifier* mod = (LUS::SetSkyboxModifier*)cmd; + + play->envCtx.skyboxDisabled = mod->modifier.skyboxDisabled; + play->envCtx.sunDisabled = mod->modifier.sunMoonDisabled; +} + +void Scene_CommandExitList(PlayState* play, LUS::ISceneCommand* cmd) { + play->setupExitList = (u16*)cmd->GetRawPointer(); +} + +void Scene_CommandSoundSettings(PlayState* play, LUS::ISceneCommand* cmd) { + LUS::SetSoundSettings* settings = (LUS::SetSoundSettings*)cmd; + + play->sequenceCtx.seqId = settings->settings.seqId; + play->sequenceCtx.ambienceId = settings->settings.natureAmbienceId; + + if(gSaveContext.seqId == (u8)NA_BGM_DISABLED || AudioSeq_GetActiveSeqId(SEQ_PLAYER_BGM_MAIN) == NA_BGM_FINAL_HOURS) { + Audio_SetSpec(settings->settings.reverb); // BENTODO Verify if this should be reverb + } + } + +void Scene_CommandEchoSetting(PlayState* play, LUS::ISceneCommand* cmd) { + LUS::SetEchoSettings* echo = (LUS::SetEchoSettings*)cmd; + play->roomCtx.curRoom.echo = echo->settings.echo; +} + +void Scene_CommandCutsceneScriptList(PlayState* play, LUS::ISceneCommand* cmd) { + LUS::SetCutscenesMM* cs = (LUS::SetCutscenesMM*)cmd; + play->csCtx.scriptListCount = cs->entries.size(); + // BENTODO do this the right way with get pointer + play->csCtx.scriptList = (CutsceneScriptEntry*)cs->entries.data(); + +} + +void Scene_CommandAltHeaderList(PlayState* play, LUS::ISceneCommand* cmd) { + LUS::SetAlternateHeaders* headers = (LUS::SetAlternateHeaders*)cmd; + + if (gSaveContext.sceneLayer != 0) { + LUS::Scene* desiredHeader = + std::static_pointer_cast<LUS::Scene>(headers->headers[gSaveContext.sceneLayer - 1]).get(); + + if (desiredHeader != nullptr) { + OTRScene_ExecuteCommands(play, desiredHeader); + // z_scene does (cmd + 1)->base.code = 0x14; + } + } +} + +void Scene_CommandSetRegionVisitedFlag(PlayState* play, LUS::ISceneCommand* cmd) { + s16 j = 0; + s16 i = 0; + + while (true) { + if (gSceneIdsPerRegion[i][j] == 0xFFFF) { + i++; + j = 0; + + if (i == REGION_MAX) { + break; + } + } + + if (play->sceneId == gSceneIdsPerRegion[i][j]) { + break; + } + + j++; + } + + if (i < REGION_MAX) { + gSaveContext.save.saveInfo.regionsVisited = + (gBitFlags[i] | gSaveContext.save.saveInfo.regionsVisited) | gSaveContext.save.saveInfo.regionsVisited; + } +} + +void Scene_CommandAnimatedMaterials(PlayState* play, LUS::ISceneCommand* cmd) { + LUS::SetAnimatedMaterialList* list = (LUS::SetAnimatedMaterialList*)cmd; + play->sceneMaterialAnims = (AnimatedMaterial*)list->mat; +} + +void Scene_CommandCutsceneList(PlayState* play, LUS::ISceneCommand* cmd) { + LUS::SetActorCutsceneList* list = (LUS::SetActorCutsceneList*)cmd; + + CutsceneManager_Init(play, (ActorCutscene*)list->GetPointer(), list->numEntries); +} + +void Scene_CommandMiniMap(PlayState* play, LUS::ISceneCommand* cmd) { + LUS::SetMinimapList* list = (LUS::SetMinimapList*)cmd; + + MapDisp_Init(play); + + func_8010549C(play, list->GetPointer()); +} + +void Scene_Command1D(PlayState* play, LUS::ISceneCommand* cmd) { + +} + +void Scene_CommandMiniMapCompassInfo(PlayState* play, LUS::ISceneCommand* cmd) { + LUS::SetMinimapChests* chests = (LUS::SetMinimapChests*)cmd; + + func_8010565C(play, chests->chests.size(), chests->GetPointer()); +} + +void (*sSceneCmdHandlersOTR[SCENE_CMD_MAX])(PlayState*, LUS::ISceneCommand*) = { + Scene_CommandSpawnList, // SCENE_CMD_ID_SPAWN_LIST + Scene_CommandActorList, // SCENE_CMD_ID_ACTOR_LIST + Scene_CommandActorCutsceneCamList, // SCENE_CMD_ID_ACTOR_CUTSCENE_CAM_LIST + Scene_CommandCollisionHeader, // SCENE_CMD_ID_COL_HEADER + Scene_CommandRoomList, // SCENE_CMD_ID_ROOM_LIST + Scene_CommandWindSettings, // SCENE_CMD_ID_WIND_SETTINGS + Scene_CommandEntranceList, // SCENE_CMD_ID_ENTRANCE_LIST + Scene_CommandSpecialFiles, // SCENE_CMD_ID_SPECIAL_FILES + Scene_CommandRoomBehavior, // SCENE_CMD_ID_ROOM_BEHAVIOR + Scene_Command09, // SCENE_CMD_ID_UNK_09 + Scene_CommandMesh, // SCENE_CMD_ID_ROOM_SHAPE + Scene_CommandObjectList, // SCENE_CMD_ID_OBJECT_LIST + Scene_CommandLightList, // SCENE_CMD_ID_LIGHT_LIST + Scene_CommandPathList, // SCENE_CMD_ID_PATH_LIST + Scene_CommandTransiActorList, // SCENE_CMD_ID_TRANSI_ACTOR_LIST + Scene_CommandEnvLightSettings, // SCENE_CMD_ID_ENV_LIGHT_SETTINGS + Scene_CommandTimeSettings, // SCENE_CMD_ID_TIME_SETTINGS + Scene_CommandSkyboxSettings, // SCENE_CMD_ID_SKYBOX_SETTINGS + Scene_CommandSkyboxDisables, // SCENE_CMD_ID_SKYBOX_DISABLES + Scene_CommandExitList, // SCENE_CMD_ID_EXIT_LIST + NULL, // SCENE_CMD_ID_END + Scene_CommandSoundSettings, // SCENE_CMD_ID_SOUND_SETTINGS + Scene_CommandEchoSetting, // SCENE_CMD_ID_ECHO_SETTINGS + Scene_CommandCutsceneScriptList, // SCENE_CMD_ID_CUTSCENE_SCRIPT_LIST + Scene_CommandAltHeaderList, // SCENE_CMD_ID_ALTERNATE_HEADER_LIST + Scene_CommandSetRegionVisitedFlag, // SCENE_CMD_ID_SET_REGION_VISITED + Scene_CommandAnimatedMaterials, // SCENE_CMD_ID_ANIMATED_MATERIAL_LIST + Scene_CommandCutsceneList, // SCENE_CMD_ID_ACTOR_CUTSCENE_LIST + Scene_CommandMiniMap, // SCENE_CMD_ID_MINIMAP_INFO + Scene_Command1D, // SCENE_CMD_ID_UNUSED_1D + Scene_CommandMiniMapCompassInfo, // SCENE_CMD_ID_MINIMAP_COMPASS_ICON_INFO +}; + +s32 OTRScene_ExecuteCommands(PlayState* play, LUS::Scene* scene) { + LUS::SceneCommandID cmdCode; + + for (int i = 0; i < scene->commands.size(); i++) { + auto sceneCmd = scene->commands[i]; + + if (sceneCmd == nullptr) // UH OH + continue; + + cmdCode = sceneCmd->cmdId; + // osSyncPrintf("*** Scene_Word = { code=%d, data1=%02x, data2=%04x } ***\n", cmdCode, sceneCmd->base.data1, sceneCmd->base.data2); + //SPDLOG_TRACE("CMD {:X}", cmdCode); + if ((int)cmdCode == SCENE_CMD_ID_END) { + break; + } else if (cmdCode == LUS::SceneCommandID::SetCutscenesMM) + cmdCode = LUS::SceneCommandID::SetCutscenes; + + //if ((int)cmdCode <= 0x19) + sSceneCmdHandlersOTR[(int)cmdCode](play, sceneCmd.get()); + + + // sceneCmd++; + } + return 0; +} + + +std::shared_ptr<LUS::IResource> GetResourceByNameHandlingMQ(const char* path); + +extern "C" s32 OTRfunc_8009728C(PlayState* play, RoomContext* roomCtx, s32 roomNum) { + + u32 size; + + if (roomCtx->status == 0) { + roomCtx->prevRoom = roomCtx->curRoom; + roomCtx->curRoom.num = roomNum; + roomCtx->curRoom.segment = NULL; + roomCtx->status = 1; + + //assert(roomNum < play->numRooms); + + if (roomNum >= play->numRooms) + return 0; // UH OH + + size = play->roomList[roomNum].vromEnd - play->roomList[roomNum].vromStart; + //roomCtx->activeRoomVram = + // (void*)((uintptr_t)roomCtx->roomMemPages[roomCtx->activeMemPage] - ((size + 8) * roomCtx->activeMemPage + 7)); + + // DmaMgr_SendRequest2(&roomCtx->dmaRequest, roomCtx->unk_34, play->roomList[roomNum].vromStart, size, 0, + //&roomCtx->loadQueue, NULL, __FILE__, __LINE__); + printf("File Name %s\n", play->roomList[roomNum].fileName); + auto roomData = + std::static_pointer_cast<LUS::Scene>(GetResourceByNameHandlingMQ(play->roomList[roomNum].fileName)); + roomCtx->status = 1; + roomCtx->activeRoomVram = roomData.get(); + + roomCtx->activeMemPage ^= 1; + + //SPDLOG_INFO("Room Init - curRoom.num: {0:#x}", roomCtx->curRoom.num); + + return 1; + } + + return 0; +}
\ No newline at end of file diff --git a/mm/CMakeLists.txt b/mm/CMakeLists.txt new file mode 100644 index 000000000..0a2e1a0e0 --- /dev/null +++ b/mm/CMakeLists.txt @@ -0,0 +1,822 @@ +cmake_minimum_required(VERSION 3.16.0 FATAL_ERROR) + +set(CMAKE_SYSTEM_VERSION 10.0 CACHE STRING "" FORCE) + +project(mm LANGUAGES C CXX) +set(CMAKE_CXX_STANDARD 20 CACHE STRING "The C++ standard to use") + +if (CMAKE_SYSTEM_NAME STREQUAL "Darwin") + enable_language(OBJCXX) + set(CMAKE_OBJC_FLAGS "${CMAKE_OBJC_FLAGS} -fobjc-arc") + set(CMAKE_OBJCXX_FLAGS "${CMAKE_OBJCXX_FLAGS} -fobjc-arc") +endif() + +set (BUILD_UTILS OFF CACHE STRING "no utilities") +set (BUILD_SHARED_LIBS OFF CACHE STRING "install/link shared instead of static libs") + +################################################################################ +# Set target arch type if empty. Visual studio solution generator provides it. +################################################################################ +if (CMAKE_SYSTEM_NAME STREQUAL "Windows") + if(NOT CMAKE_VS_PLATFORM_NAME) + set(CMAKE_VS_PLATFORM_NAME "x64") + endif() + message("${CMAKE_VS_PLATFORM_NAME} architecture in use") + + if(NOT ("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "x64" + OR "${CMAKE_VS_PLATFORM_NAME}" STREQUAL "Win32")) + message(FATAL_ERROR "${CMAKE_VS_PLATFORM_NAME} arch is not supported!") + endif() +endif() + +################################################################################ +# Global configuration types +################################################################################ +set(CMAKE_CONFIGURATION_TYPES + "Debug" + "Release" + CACHE STRING "" FORCE +) + +################################################################################ +# Global compiler options +################################################################################ +if(MSVC) + # remove default flags provided with CMake for MSVC + set(CMAKE_C_FLAGS "") + set(CMAKE_C_FLAGS_DEBUG "") + set(CMAKE_C_FLAGS_RELEASE "") + set(CMAKE_CXX_FLAGS "") + set(CMAKE_CXX_FLAGS_DEBUG "") + set(CMAKE_CXX_FLAGS_RELEASE "") +endif() + +################################################################################ +# Global linker options +################################################################################ +if(MSVC) + # remove default flags provided with CMake for MSVC + set(CMAKE_EXE_LINKER_FLAGS "") + set(CMAKE_MODULE_LINKER_FLAGS "") + set(CMAKE_SHARED_LINKER_FLAGS "") + set(CMAKE_STATIC_LINKER_FLAGS "") + set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS}") + set(CMAKE_MODULE_LINKER_FLAGS_DEBUG "${CMAKE_MODULE_LINKER_FLAGS}") + set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS}") + set(CMAKE_STATIC_LINKER_FLAGS_DEBUG "${CMAKE_STATIC_LINKER_FLAGS}") + set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS}") + set(CMAKE_MODULE_LINKER_FLAGS_RELEASE "${CMAKE_MODULE_LINKER_FLAGS}") + set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS}") + set(CMAKE_STATIC_LINKER_FLAGS_RELEASE "${CMAKE_STATIC_LINKER_FLAGS}") +endif() + +################################################################################ +# Common utils +################################################################################ +include(CMake/Utils.cmake) + +################################################################################ +# Additional Global Settings(add specific info there) +################################################################################ +include(CMake/GlobalSettingsInclude.cmake OPTIONAL) + +################################################################################ +# Use solution folders feature +################################################################################ +set_property(GLOBAL PROPERTY USE_FOLDERS ON) + +################################################################################ +# Sub-projects +################################################################################ +if (NOT TARGET libultraship) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../libultraship ${CMAKE_BINARY_DIR}/libultraship) +endif() + +if (NOT TARGET ZAPDUtils) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../ZAPDTR/ZAPDUtils ${CMAKE_BINARY_DIR}/ZAPDUtils) +endif() + +if (NOT TARGET ZAPDLib) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../ZAPDTR/ZAPD ${CMAKE_BINARY_DIR}/ZAPD) +endif() + +set(PROJECT_NAME mm) + +################################################################################ +# Sources +################################################################################ +configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/src/boot/build.c.in ${CMAKE_BINARY_DIR}/build.c @ONLY) +#configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/src/boot/properties.h.in ${CMAKE_CURRENT_SOURCE_DIR}/properties.h @ONLY) + +#set(Header_Files "resource.h") +source_group("headers" FILES ${Header_Files}) + +# include {{{ +file(GLOB Header_Files__include "include/*.h" "include/*.inc") +list(APPEND Header_Files__include ${CMAKE_CURRENT_SOURCE_DIR}/include/libc/stdarg.h) +list(REMOVE_ITEM Header_Files__include ${CMAKE_CURRENT_SOURCE_DIR}/include/bgm.h) +list(REMOVE_ITEM Header_Files__include ${CMAKE_CURRENT_SOURCE_DIR}/include/math_n64.h) +list(REMOVE_ITEM Header_Files__include ${CMAKE_CURRENT_SOURCE_DIR}/include/stdbool_n64.h) +list(REMOVE_ITEM Header_Files__include ${CMAKE_CURRENT_SOURCE_DIR}/include/stddef_n64.h) +list(REMOVE_ITEM Header_Files__include ${CMAKE_CURRENT_SOURCE_DIR}/include/stdlib_n64.h) +list(REMOVE_ITEM Header_Files__include ${CMAKE_CURRENT_SOURCE_DIR}/include/ultra64.h) +source_group("include" FILES ${Header_Files__include}) +# }}} + +# m (root) +file(GLOB soh__ RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "2s2h/*.c" "2s2h/*.cpp" "2s2h/*.h") +source_group("2s2h" FILES ${soh__}) + +file(GLOB_RECURSE libultra_headers RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + "include/PR/*.h" +) + +if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + set_source_files_properties(2s2h/BenPort.cpp PROPERTIES COMPILE_FLAGS "/utf-8") +endif() + +# soh/config {{{ +#file(GLOB_RECURSE soh__config RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} +# "soh/config/*.h" +# "soh/config/*.cpp" +#) +# }}} + +# soh/enhancements {{{ +#file(GLOB_RECURSE soh__Enhancements RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} +# "soh/Enhancements/*.c" +# "soh/Enhancements/*.cpp" +# "soh/Enhancements/*.h" +# "soh/Enhancements/*.hpp" +# "soh/Enhancements/*_extern.inc" +# "soh/Enhancements/*.mm" +#) + +#list(REMOVE_ITEM soh__Enhancements "soh/Enhancements/gamecommand.h") +#list(FILTER soh__Enhancements EXCLUDE REGEX "soh/Enhancements/gfx.*") + +# handle crowd control removals +#list(REMOVE_ITEM soh__Enhancements "soh/Enhancements/crowd-control/soh.cs") +#list(REMOVE_ITEM soh__Enhancements "soh/Enhancements/crowd-control/soh.ccpak") +#if (!BUILD_CROWD_CONTROL) +# list(FILTER soh__Enhancements EXCLUDE REGEX "soh/Enhancements/crowd-control/*") +#endif() + +# handle speechsynthesizer removals +#if (CMAKE_SYSTEM_NAME STREQUAL "Windows") +# list(FILTER soh__Enhancements EXCLUDE REGEX "soh/Enhancements/speechsynthesizer/Darwin*") +#elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin") +# list(FILTER soh__Enhancements EXCLUDE REGEX "soh/Enhancements/speechsynthesizer/SAPI*") +#else() +# list(FILTER soh__Enhancements EXCLUDE REGEX "soh/Enhancements/speechsynthesizer/(Darwin|SAPI).*") +#endif() + +#source_group("soh\\Enhancements" REGULAR_EXPRESSION "soh/Enhancements/*") +#source_group("soh\\Enhancements\\audio" REGULAR_EXPRESSION "soh/Enhancements/audio/*") +#source_group("soh\\Enhancements\\controls" REGULAR_EXPRESSION "soh/Enhancements/controls/*") +#source_group("soh\\Enhancements\\cosmetics" REGULAR_EXPRESSION "soh/Enhancements/cosmetics/*") +#source_group("soh\\Enhancements\\crowd-control" REGULAR_EXPRESSION "soh/Enhancements/crowd-control/*") +#source_group("soh\\Enhancements\\custom-message" REGULAR_EXPRESSION "soh/Enhancements/custom-message/*") +#source_group("soh\\Enhancements\\debugger" REGULAR_EXPRESSION "soh/Enhancements/debugger/*") +#source_group("soh\\Enhancements\\game-interactor" REGULAR_EXPRESSION "soh/Enhancements/game-interactor/*") +#source_group("soh\\Enhancements\\item-tables" REGULAR_EXPRESSION "soh/Enhancements/item-tables/*") +#source_group("soh\\Enhancements\\randomizer" REGULAR_EXPRESSION "soh/Enhancements/randomizer/*") +#source_group("soh\\Enhancements\\randomizer\\3drando" REGULAR_EXPRESSION "soh/Enhancements/randomizer/3drando/*") +#source_group("soh\\Enhancements\\randomizer\\3drando\\hint_list" REGULAR_EXPRESSION "soh/Enhancements/randomizer/3drando/hint_list/*") +#source_group("soh\\Enhancements\\randomizer\\3drando\\location_access" REGULAR_EXPRESSION "soh/Enhancements/randomizer/3drando/location_access/*") +#source_group("soh\\Enhancements\\speechsynthesizer" REGULAR_EXPRESSION "soh/Enhancements/speechsynthesizer/*") +#source_group("soh\\Enhancements\\tts" REGULAR_EXPRESSION "soh/Enhancements/tts/*") + +#if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") +# set_source_files_properties(soh/Enhancements/tts/tts.cpp PROPERTIES COMPILE_FLAGS "/utf-8") +#endif() +# }}} + +if(NOT CMAKE_SYSTEM_NAME MATCHES "NintendoSwitch|CafeOS") + # 2s2h/Extractor {{{ + file(GLOB_RECURSE soh__Extractor RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + "2s2h/Extractor/*.c" + "2s2h/Extractor/*.cpp" + "2s2h/Extractor/*.h" + "2s2h/Extractor/*.hpp" + ) + # }}} +else() + file(GLOB_RECURSE soh__Extractor RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + "2s2h/Extractor/*.h" + "2s2h/Extractor/*.hpp" + ) +# }}} +endif() + +# 2s2h/resource {{{ +file(GLOB_RECURSE soh__Resource RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "2s2h/resource/*.cpp" "2s2h/resource/*.h") + +source_group("2s2h\\resource\\type" REGULAR_EXPRESSION "2s2h/resource/type/*") +source_group("2s2h\\resource\\type\\scenecommand" REGULAR_EXPRESSION "2s2h/resource/type/scenecommand/*") +source_group("2s2h\\resource\\importer" REGULAR_EXPRESSION "2s2h/resource/importer/*") +source_group("2s2h\\resource\\importer\\scenecommand" REGULAR_EXPRESSION "2s2h/resource/importer/scenecommand/*") +# }}} + +# src (decomp) {{{ +file(GLOB_RECURSE src__ RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.c" "src/*.h") + +list(APPEND src__ ${CMAKE_BINARY_DIR}/build.c) +#list(APPEND src__ ${CMAKE_CURRENT_SOURCE_DIR}/properties.h) +#list(APPEND src__ ${CMAKE_CURRENT_SOURCE_DIR}/Resource.rc) +list(FILTER src__ EXCLUDE REGEX "src/dmadata/*") +list(FILTER src__ EXCLUDE REGEX "src/elf_message/*") +list(FILTER src__ EXCLUDE REGEX "src/libultra/io/*") +list(FILTER src__ EXCLUDE REGEX "src/libultra/libc/*") +list(FILTER src__ EXCLUDE REGEX "src/libultra/os/*") +list(FILTER src__ EXCLUDE REGEX "src/libultra/rmon/*") +list(FILTER src__ EXCLUDE REGEX "src/libultra/*") +#list(APPEND src__ "src/libultra/libc/sprintf.c") +#list(REMOVE_ITEM src__ "src/libultra/gu/cosf.c") +#list(REMOVE_ITEM src__ "src/libultra/gu/lookat.c") +#list(REMOVE_ITEM src__ "src/libultra/gu/lookathil.c") +#list(REMOVE_ITEM src__ "src/libultra/gu/perspective.c") +#list(REMOVE_ITEM src__ "src/libultra/gu/position.c") +#list(REMOVE_ITEM src__ "src/libultra/gu/sinf.c") +#list(REMOVE_ITEM src__ "src/libultra/gu/sinf.c") +#list(REMOVE_ITEM src__ "src/libultra/gu/sqrtf.c") +#list(REMOVE_ITEM src__ "src/libultra/gu/us2dex.c") + +source_group("src" REGULAR_EXPRESSION "src/*") +source_group("src\\build" FILES ${CMAKE_BINARY_DIR}/build.c) +source_group("src\\boot" REGULAR_EXPRESSION "src/boot/*") +source_group("src\\buffers" REGULAR_EXPRESSION "src/buffers/*") +source_group("src\\code" REGULAR_EXPRESSION "src/code/*") +#source_group("src\\libultra" REGULAR_EXPRESSION "src/libultra/*") +source_group("src\\overlays\\actors" REGULAR_EXPRESSION "src/overlays/actors/*") +source_group("src\\overlays\\effects" REGULAR_EXPRESSION "src/overlays/effects/*") +source_group("src\\overlays\\fbdemos" REGULAR_EXPRESSION "src/overlays/fbdemos/*") +source_group("src\\overlays\\gamestates" REGULAR_EXPRESSION "src/overlays/gamestates/*") +source_group("src\\overlays\\misc" REGULAR_EXPRESSION "src/overlays/misc/*") +# }}} + +set(ALL_FILES + ${Header_Files} + ${Header_Files__include} + ${soh__} + ${libultra_headers} +# ${soh__config} +# ${soh__Enhancements} + ${soh__Extractor} + ${soh__Resource} + ${src__} +) + +################################################################################ +# Target +################################################################################ +add_executable(${PROJECT_NAME} ${ALL_FILES}) + +if (CMAKE_SYSTEM_NAME STREQUAL "Windows") +use_props(${PROJECT_NAME} "${CMAKE_CONFIGURATION_TYPES}" "${DEFAULT_CXX_PROPS}") +endif() + +set(ROOT_NAMESPACE 2s2h) + +if (CMAKE_SYSTEM_NAME STREQUAL "Windows") + set_target_properties(${PROJECT_NAME} PROPERTIES + VS_GLOBAL_KEYWORD "Win32Proj" + ) + if("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "x64") + set_target_properties(${PROJECT_NAME} PROPERTIES + INTERPROCEDURAL_OPTIMIZATION_RELEASE "TRUE" + ) + elseif("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "Win32") + set_target_properties(${PROJECT_NAME} PROPERTIES + INTERPROCEDURAL_OPTIMIZATION_RELEASE "TRUE" + ) + endif() +elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + set_target_properties(${PROJECT_NAME} PROPERTIES + XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC YES + OUTPUT_NAME "2s2h-macos" + ) +elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux") + set_target_properties(${PROJECT_NAME} PROPERTIES + OUTPUT_NAME "2s2h.elf" + ) +endif() +################################################################################ +# MSVC runtime library +################################################################################ +if (CMAKE_SYSTEM_NAME STREQUAL "Windows") + get_property(MSVC_RUNTIME_LIBRARY_DEFAULT TARGET ${PROJECT_NAME} PROPERTY MSVC_RUNTIME_LIBRARY) + if("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "x64") + string(CONCAT "MSVC_RUNTIME_LIBRARY_STR" + $<$<CONFIG:Debug>: + MultiThreadedDebug + > + $<$<CONFIG:Release>: + MultiThreaded + > + $<$<NOT:$<OR:$<CONFIG:Debug>,$<CONFIG:Release>>>:${MSVC_RUNTIME_LIBRARY_DEFAULT}> + ) + elseif("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "Win32") + string(CONCAT "MSVC_RUNTIME_LIBRARY_STR" + $<$<CONFIG:Debug>: + MultiThreadedDebug + > + $<$<CONFIG:Release>: + MultiThreaded + > + $<$<NOT:$<OR:$<CONFIG:Debug>,$<CONFIG:Release>>>:${MSVC_RUNTIME_LIBRARY_DEFAULT}> + ) + endif() + set_target_properties(${PROJECT_NAME} PROPERTIES MSVC_RUNTIME_LIBRARY ${MSVC_RUNTIME_LIBRARY_STR}) +endif() +################################################################################ +# Find/download Boost +################################################################################ +include(FetchContent) +FetchContent_Declare( + Boost + URL https://boostorg.jfrog.io/artifactory/main/release/1.81.0/source/boost_1_81_0.tar.gz + URL_HASH SHA256=205666dea9f6a7cfed87c7a6dfbeb52a2c1b9de55712c9c1a87735d7181452b6 + SOURCE_SUBDIR "null" # Set to a nonexistent directory so boost is not built (we don't need to build it) + DOWNLOAD_EXTRACT_TIMESTAMP false # supress timestamp warning, not needed since the url wont change +) + +set(Boost_NO_BOOST_CMAKE false) +set(BOOST_INCLUDEDIR ${FETCHCONTENT_BASE_DIR}/boost-src) # Location where FetchContent stores the source +message("Searching for Boost installation") +find_package(Boost) + +if (NOT ${Boost_FOUND}) + message("Boost not found. Downloading now...") + FetchContent_MakeAvailable(Boost) + message("Boost downloaded to " ${FETCHCONTENT_BASE_DIR}/boost-src) + set(BOOST-INCLUDE ${FETCHCONTENT_BASE_DIR}/boost-src) +else() + message("Boost found in " ${Boost_INCLUDE_DIRS}) + set(BOOST-INCLUDE ${Boost_INCLUDE_DIRS}) +endif() +################################################################################ +# Compile definitions +################################################################################ +find_package(SDL2) +set(SDL2-INCLUDE ${SDL2_INCLUDE_DIRS}) + +if (BUILD_CROWD_CONTROL) + find_package(SDL2_net) + set(SDL2-NET-INCLUDE ${SDL_NET_INCLUDE_DIRS}) +endif() + +target_include_directories(${PROJECT_NAME} PRIVATE assets + ${CMAKE_CURRENT_SOURCE_DIR}/include/ + ${CMAKE_CURRENT_SOURCE_DIR}/include/PR + ${CMAKE_CURRENT_SOURCE_DIR}/src/ + ${CMAKE_CURRENT_SOURCE_DIR}/../libultraship + ${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/include + ${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/src + ${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/src/log + ${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/src/debug + ${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/src/menu + ${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/src/utils + ${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/src/utils/binarytools + ${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/src/config + ${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/src/resource + ${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/src/resource/type + ${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/src/resource/factory + ${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/src/audio + ${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/src/window + ${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/src/window/gui + ${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/src/config + ${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/src/public + ${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/src/public/libultra + ${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/src/public/bridge + ${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/extern + ${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/extern/tinyxml2 + ${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/libultraship/Lib/ + ${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/libultraship/Lib/libjpeg/include/ + ${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/libultraship/Lib/spdlog/include/ + ${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/src/graphic/Fast3D/U64/PR + ${CMAKE_CURRENT_SOURCE_DIR}/../libultraship/src/graphic + ${CMAKE_CURRENT_SOURCE_DIR}/../ZAPDTR/ZAPDUtils + ${CMAKE_CURRENT_SOURCE_DIR}/../ZAPDTR/ZAPD/resource/type + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/2s2h/ + ${SDL2-INCLUDE} + ${SDL2-NET-INCLUDE} + ${BOOST-INCLUDE} + ${CMAKE_CURRENT_SOURCE_DIR}/assets/ + . +) + +if (CMAKE_SYSTEM_NAME STREQUAL "Windows") + if("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "x64") + target_compile_definitions(${PROJECT_NAME} PRIVATE + "$<$<CONFIG:Debug>:" + "_DEBUG;" + "_CRT_SECURE_NO_WARNINGS;" + "ENABLE_DX11;" + ">" + "$<$<CONFIG:Release>:" + "NDEBUG" + ">" + "$<$<BOOL:${BUILD_CROWD_CONTROL}>:ENABLE_CROWD_CONTROL>" + "INCLUDE_GAME_PRINTF;" + "ENABLE_CROWD_CONTROL;" + "UNICODE;" + "_UNICODE" + STORMLIB_NO_AUTO_LINK + "_CRT_SECURE_NO_WARNINGS;" + ) + elseif("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "Win32") + target_compile_definitions(${PROJECT_NAME} PRIVATE + "$<$<CONFIG:Debug>:" + "NOINCLUDE_GAME_PRINTF;" + "_DEBUG;" + "_CRT_SECURE_NO_WARNINGS;" + "ENABLE_OPENGL" + ">" + "$<$<CONFIG:Release>:" + "NDEBUG;" + ">" + "INCLUDE_GAME_PRINTF;" + "NON_EQUIVALENT;" + "NON_MATCHING;" + "WIN32;" + "UNICODE;" + "_UNICODE" + STORMLIB_NO_AUTO_LINK + ) + endif() +elseif (CMAKE_SYSTEM_NAME STREQUAL "CafeOS") + target_compile_definitions(${PROJECT_NAME} PRIVATE + "$<$<CONFIG:Debug>:" + "_DEBUG" + ">" + "$<$<CONFIG:Release>:" + "NDEBUG" + ">" + "SPDLOG_ACTIVE_LEVEL=3;" + "SPDLOG_NO_THREAD_ID;" + "SPDLOG_NO_TLS;" + "STBI_NO_THREAD_LOCALS;" + ) +elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU|Clang|AppleClang") + target_compile_definitions(${PROJECT_NAME} PRIVATE + "$<$<CONFIG:Debug>:" + "_DEBUG" + ">" + "$<$<CONFIG:Release>:" + "NDEBUG" + ">" + "$<$<BOOL:${BUILD_CROWD_CONTROL}>:ENABLE_CROWD_CONTROL>" + "SPDLOG_ACTIVE_LEVEL=0;" + "_CONSOLE;" + "_CRT_SECURE_NO_WARNINGS;" + "ENABLE_OPENGL;" + "UNICODE;" + "_UNICODE" + "NON_MATCHING;" + "NON_EQUIVALENT;" + ) +endif() +################################################################################ +# Compile and link options +################################################################################ +if(MSVC) + if("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "x64") + target_compile_options(${PROJECT_NAME} PRIVATE + $<$<CONFIG:Debug>: + /w; + /Od + > + $<$<CONFIG:Release>: + /Oi; + /Gy; + /W3 + > + /sdl-; + /permissive-; + /MP; + ${DEFAULT_CXX_DEBUG_INFORMATION_FORMAT}; + ${DEFAULT_CXX_EXCEPTION_HANDLING} + ) + target_compile_options(${PROJECT_NAME} PRIVATE $<$<CONFIG:Debug>:/ZI;>) + elseif("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "Win32") + target_compile_options(${PROJECT_NAME} PRIVATE + $<$<CONFIG:Debug>: + /RTCs + > + $<$<CONFIG:Release>: + /O2; + /Oi; + /Gy + > + /permissive-; + /MP; + /sdl-; + /w; + ${DEFAULT_CXX_DEBUG_INFORMATION_FORMAT}; + ${DEFAULT_CXX_EXCEPTION_HANDLING} + ) + endif() + if("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "x64") + target_link_options(${PROJECT_NAME} PRIVATE + $<$<CONFIG:Debug>: + /INCREMENTAL + > + $<$<CONFIG:Release>: + /OPT:REF; + /OPT:ICF; + /INCREMENTAL:NO; + /FORCE:MULTIPLE + > + /MANIFEST:NO; + /DEBUG; + /SUBSYSTEM:WINDOWS + ) + elseif("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "Win32") + target_link_options(${PROJECT_NAME} PRIVATE + $<$<CONFIG:Debug>: + /STACK:8777216 + > + $<$<CONFIG:Release>: + /OPT:REF; + /OPT:ICF; + /INCREMENTAL:NO; + /FORCE:MULTIPLE + > + /MANIFEST:NO; + /DEBUG; + /SUBSYSTEM:WINDOWS + ) + endif() +endif() + +if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang|AppleClang") + if (CMAKE_SYSTEM_NAME STREQUAL "Darwin") + target_compile_options(${PROJECT_NAME} PRIVATE + -Wall -Wextra -Wno-error + -Wno-return-type + -Wno-unused-parameter + -Wno-unused-function + -Wno-unused-variable + -Wno-missing-field-initializers + -Wno-parentheses + -Wno-narrowing + -Wno-missing-braces + $<$<COMPILE_LANGUAGE:C>: + #-Werror-implicit-function-declaration + -Wno-incompatible-pointer-types + > + $<$<COMPILE_LANGUAGE:CXX>:-fpermissive> + $<$<COMPILE_LANGUAGE:CXX>: + -Wno-c++11-narrowing + -Wno-deprecated-enum-enum-conversion + > + -pthread + ) + + target_link_options(${PROJECT_NAME} PRIVATE + -pthread + ) + elseif (CMAKE_SYSTEM_NAME STREQUAL "NintendoSwitch") + target_compile_options(${PROJECT_NAME} PRIVATE + -Wall -Wextra -Wno-error + -Wno-return-type + -Wno-unused-parameter + -Wno-unused-function + -Wno-unused-variable + -Wno-missing-field-initializers + -Wno-parentheses + -Wno-narrowing + -Wno-missing-braces + $<$<COMPILE_LANGUAGE:C>: + -Werror-implicit-function-declaration + -Wno-incompatible-pointer-types + > + $<$<COMPILE_LANGUAGE:CXX>:-fpermissive> + $<$<COMPILE_LANGUAGE:CXX>: + -Wno-c++11-narrowing + -Wno-deprecated-enum-enum-conversion + > + -pthread + ) + + target_link_options(${PROJECT_NAME} PRIVATE + -pthread + ) + elseif (CMAKE_SYSTEM_NAME STREQUAL "CafeOS") + target_compile_options(${PROJECT_NAME} PRIVATE + -O2 + + # disable some warnings to not clutter output + -Wno-multichar + -Wno-return-type + -Wno-narrowing + -Wno-switch-outside-range + $<$<COMPILE_LANGUAGE:C>: + -Werror-implicit-function-declaration + -Wno-incompatible-pointer-types + -Wno-discarded-array-qualifiers + -Wno-discarded-qualifiers + -Wno-int-conversion + -Wno-builtin-declaration-mismatch + -Wno-switch-unreachable + -Wno-stringop-overflow + > + ) + else() + if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64") + set(CPU_OPTION -msse2 -mfpmath=sse) + endif() + + target_compile_options(${PROJECT_NAME} PRIVATE + -Wall -Wextra -Wno-error + -Wno-unused-parameter + -Wno-unused-function + -Wno-unused-variable + -Wno-missing-field-initializers + -Wno-parentheses + -Wno-narrowing + -Wno-missing-braces + $<$<COMPILE_LANGUAGE:C>: + #-Werror-implicit-function-declaration + -Wno-incompatible-pointer-types + > + $<$<COMPILE_LANGUAGE:CXX>:-fpermissive> + $<$<COMPILE_LANGUAGE:CXX>:-Wno-deprecated-enum-enum-conversion> + -pthread + ${CPU_OPTION} + ) + + target_link_options(${PROJECT_NAME} PRIVATE + -pthread + -Wl,-export-dynamic + ) + endif() +endif() +################################################################################ +# Pre build events +################################################################################ +if (CMAKE_SYSTEM_NAME STREQUAL "Windows") + add_custom_command_if( + TARGET ${PROJECT_NAME} + PRE_BUILD + COMMANDS + COMMAND $<CONFIG:Debug> copy /b $<SHELL_PATH:${CMAKE_BINARY_DIR}/>build.c +,, + ) +endif() + +if(NOT CMAKE_SYSTEM_NAME MATCHES "NintendoSwitch|CafeOS") + add_custom_command( + TARGET ${PROJECT_NAME} + POST_BUILD + COMMENT "Copying asset xmls..." + #COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/mm/assets/extractor $<TARGET_FILE_DIR:mm>/assets/extractor + #COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/mm/assets/xml $<TARGET_FILE_DIR:mm>/assets/extractor/xmls + #COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/OTRExporter/CFG/filelists $<TARGET_FILE_DIR:mm>/assets/extractor/filelists + #COMMAND ${CMAKE_COMMAND} -E make_directory $<TARGET_FILE_DIR:mm>/assets/extractor/symbols + #COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/OTRExporter/CFG/ActorList_MM.txt $<TARGET_FILE_DIR:mm>/assets/extractor/symbols + #COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/OTRExporter/CFG/ObjectList_MM.txt $<TARGET_FILE_DIR:mm>/assets/extractor/symbols + #COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/OTRExporter/CFG/SymbolMap_MM.txt $<TARGET_FILE_DIR:mm>/assets/extractor/symbols + ) +endif() +################################################################################ +# Dependencies +################################################################################ +add_dependencies(${PROJECT_NAME} + ZAPDUtils + libultraship +) +if(NOT CMAKE_SYSTEM_NAME MATCHES "NintendoSwitch|CafeOS") +add_dependencies(${PROJECT_NAME} + ZAPDLib +) +endif() + +if (CMAKE_SYSTEM_NAME STREQUAL "Windows") + find_package(glfw3 REQUIRED) + if("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "x64") + set(ADDITIONAL_LIBRARY_DEPENDENCIES + "libultraship;" + "ZAPDUtils;" + "ZAPDLib;" + "glu32;" + "SDL2::SDL2;" + "SDL2::SDL2main;" + "$<$<BOOL:${BUILD_CROWD_CONTROL}>:SDL2_net::SDL2_net-static>" + "glfw;" + "winmm;" + "imm32;" + "version;" + "setupapi" + ) + elseif("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "Win32") + set(ADDITIONAL_LIBRARY_DEPENDENCIES + "libultraship;" + "ZAPDUtils;" + "ZAPDLib;" + "glu32;" + "SDL2::SDL2;" + "SDL2::SDL2main;" + "glfw;" + "winmm;" + "imm32;" + "version;" + "setupapi" + ) + endif() +elseif(CMAKE_SYSTEM_NAME STREQUAL "NintendoSwitch") + find_package(SDL2) + set(THREADS_PREFER_PTHREAD_FLAG ON) + find_package(Threads REQUIRED) + set(ADDITIONAL_LIBRARY_DEPENDENCIES + "libultraship;" + "ZAPDUtils;" + SDL2::SDL2 + -lglad + Threads::Threads + ) +elseif(CMAKE_SYSTEM_NAME STREQUAL "CafeOS") + find_package(SDL2 REQUIRED) + set(ADDITIONAL_LIBRARY_DEPENDENCIES + "libultraship;" + SDL2::SDL2-static + + "$<$<CONFIG:Debug>:-Wl,--wrap=abort>" + ) + target_include_directories(${PROJECT_NAME} PRIVATE + ${DEVKITPRO}/portlibs/wiiu/include/ + ) +else() + find_package(SDL2) + set(THREADS_PREFER_PTHREAD_FLAG ON) + find_package(Threads REQUIRED) + set(ADDITIONAL_LIBRARY_DEPENDENCIES + "libultraship;" + "ZAPDUtils;" + "ZAPDLib;" + SDL2::SDL2 + "$<$<BOOL:${BUILD_CROWD_CONTROL}>:SDL2_net::SDL2_net>" + ${CMAKE_DL_LIBS} + Threads::Threads + ) +endif() + +if(NOT CMAKE_SYSTEM_NAME MATCHES "NintendoSwitch|CafeOS") +INSTALL(TARGETS mm DESTINATION . COMPONENT 2s2h) +endif() + +if (CMAKE_SYSTEM_NAME STREQUAL "Windows") +INSTALL(FILES $<TARGET_PDB_FILE:mm> DESTINATION ./debug COMPONENT 2s2h) +INSTALL(FILES ${CMAKE_BINARY_DIR}/mm/soh.otr DESTINATION . COMPONENT 2s2h) +endif() + +find_program(CURL NAMES curl DOC "Path to the curl program. Used to download files.") +execute_process(COMMAND ${CURL} -sSfL https://raw.githubusercontent.com/gabomdq/SDL_GameControllerDB/master/gamecontrollerdb.txt -o ${CMAKE_BINARY_DIR}/gamecontrollerdb.txt OUTPUT_VARIABLE RESULT) + +if("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin") +configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/macosx/Info.plist.in ${CMAKE_BINARY_DIR}/macosx/Info.plist @ONLY) +INSTALL(FILES ${CMAKE_BINARY_DIR}/gamecontrollerdb.txt DESTINATION ../MacOS COMPONENT 2s2h) +INSTALL(FILES ${CMAKE_BINARY_DIR}/mm/soh.otr DESTINATION ../Resources COMPONENT 2s2h) +elseif(NOT "${CMAKE_SYSTEM_NAME}" MATCHES "NintendoSwitch|CafeOS") +INSTALL(FILES ${CMAKE_BINARY_DIR}/gamecontrollerdb.txt DESTINATION . COMPONENT 2s2h) +endif() + +if(CMAKE_SYSTEM_NAME MATCHES "NintendoSwitch|CafeOS") + if (NOT TARGET pathconf) + add_library(pathconf OBJECT platform/pathconf.c) + endif() + target_link_libraries(${PROJECT_NAME} PRIVATE "${ADDITIONAL_LIBRARY_DEPENDENCIES}" $<TARGET_OBJECTS:pathconf> ) +else() + target_link_libraries(${PROJECT_NAME} PRIVATE "${ADDITIONAL_LIBRARY_DEPENDENCIES}") +endif() + +if(CMAKE_SYSTEM_NAME MATCHES "NintendoSwitch") + +nx_generate_nacp(2s2h.nacp + NAME "2s2h of Harkinian" + AUTHOR "${PROJECT_TEAM}" + VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}" +) + +nx_create_nro(2s2h + NACP 2s2h.nacp + ICON ${CMAKE_CURRENT_SOURCE_DIR}/icon.jpg +) + +INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/2s2h.nro DESTINATION . COMPONENT 2s2h) + +elseif(CMAKE_SYSTEM_NAME MATCHES "CafeOS") + +wut_create_rpx(${PROJECT_NAME}) + +wut_create_wuhb(${PROJECT_NAME} + NAME "Two Ship Two Harkinian" + SHORTNAME "2S2H" + AUTHOR "${PROJECT_TEAM}" + ICON ${CMAKE_CURRENT_SOURCE_DIR}/icon.jpg +) + +INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/2s2h.rpx ${CMAKE_CURRENT_BINARY_DIR}/2s2h.wuhb DESTINATION . COMPONENT 2s2h) + +endif() diff --git a/mm/assets/xml/archives/icon_item_24_static.xml b/mm/assets/xml/archives/icon_item_24_static.xml index 2997b546b..6bf637534 100644 --- a/mm/assets/xml/archives/icon_item_24_static.xml +++ b/mm/assets/xml/archives/icon_item_24_static.xml @@ -1,5 +1,5 @@ <Root> - <File Name="icon_item_24_static_yar.unarchive" Segment="9"> + <File Name="icon_item_24_static_yar" Segment="9"> <Texture Name="gQuestIconGoldSkulltulaTex" OutName="gold_skulltula_icon" Format="rgba32" Width="24" Height="24" Offset="0x0" /> <Texture Name="gQuestIconHeartContainerTex" OutName="heart_container_icon" Format="rgba32" Width="24" Height="24" Offset="0x900" /> <Texture Name="gQuestIconPieceOfHeartTex" OutName="piece_of_heart_icon" Format="rgba32" Width="24" Height="24" Offset="0x1200" /> diff --git a/mm/assets/xml/archives/icon_item_static.xml b/mm/assets/xml/archives/icon_item_static.xml index 3480d704a..52cf6a3a9 100644 --- a/mm/assets/xml/archives/icon_item_static.xml +++ b/mm/assets/xml/archives/icon_item_static.xml @@ -1,5 +1,5 @@ <Root> - <File Name="icon_item_static_yar.unarchive" Segment="8"> + <File Name="icon_item_static_yar" Segment="8"> <!-- Item icons --> <Texture Name="gItemIconOcarinaOfTimeTex" OutName="ocarina_of_time_icon" Format="rgba32" Width="32" Height="32" Offset="0x0000"/> <Texture Name="gItemIconBowTex" OutName="bow_icon" Format="rgba32" Width="32" Height="32" Offset="0x1000"/> diff --git a/mm/assets/xml/archives/item_name_static.xml b/mm/assets/xml/archives/item_name_static.xml index da0b903a0..b9ff2a5ee 100644 --- a/mm/assets/xml/archives/item_name_static.xml +++ b/mm/assets/xml/archives/item_name_static.xml @@ -1,6 +1,6 @@ <Root> <!-- Item Names. Must be ia4 128x16 and ordered following `ItemId` --> - <File Name="item_name_static.unarchive"> + <File Name="item_name_static"> <!-- Main items --> <Texture Name="gItemNameOcarinaOfTimeENGTex" OutName="item_name_ocarina_of_time_eng" Format="ia4" Width="128" Height="16" Offset="0x0" /> <!-- ITEM_OCARINA_OF_TIME --> <Texture Name="gItemNameHerosBowENGTex" OutName="item_name_heros_bow_eng" Format="ia4" Width="128" Height="16" Offset="0x400" /> <!-- ITEM_BOW --> diff --git a/mm/assets/xml/archives/map_grand_static.xml b/mm/assets/xml/archives/map_grand_static.xml index 05e5893c1..94e51b350 100644 --- a/mm/assets/xml/archives/map_grand_static.xml +++ b/mm/assets/xml/archives/map_grand_static.xml @@ -1,102 +1,102 @@ <Root> - <File Name="map_grand_static.unarchive"> - <Texture Name="gMapGrandStatic100Tex" OutName="map_100" Format="i4" Width="96" Height="85" Offset="0x0" /> - <Texture Name="gMapGrandStatic101Tex" OutName="map_101" Format="i4" Width="96" Height="85" Offset="0xFF0" /> - <Texture Name="gMapGrandStatic102Tex" OutName="map_102" Format="i4" Width="96" Height="85" Offset="0x1FE0" /> - <Texture Name="gMapGrandStatic103Tex" OutName="map_103" Format="i4" Width="96" Height="85" Offset="0x2FD0" /> - <Texture Name="gMapGrandStatic104Tex" OutName="map_104" Format="i4" Width="96" Height="85" Offset="0x3FC0" /> - <Texture Name="gMapGrandStatic105Tex" OutName="map_105" Format="i4" Width="80" Height="72" Offset="0x4FB0" /> - <Texture Name="gMapGrandStatic106Tex" OutName="map_106" Format="i4" Width="96" Height="85" Offset="0x5AF0" /> - <Texture Name="gMapGrandStatic107Tex" OutName="map_107" Format="i4" Width="96" Height="85" Offset="0x6AE0" /> - <Texture Name="gMapGrandStatic108Tex" OutName="map_108" Format="i4" Width="96" Height="85" Offset="0x7AD0" /> - <Texture Name="gMapGrandStatic109Tex" OutName="map_109" Format="i4" Width="96" Height="85" Offset="0x8AC0" /> - <Texture Name="gMapGrandStatic10ATex" OutName="map_10A" Format="i4" Width="48" Height="44" Offset="0x9AB0" /> - <Texture Name="gMapGrandStatic10BTex" OutName="map_10B" Format="i4" Width="96" Height="85" Offset="0x9ED0" /> - <Texture Name="gMapGrandStatic10CTex" OutName="map_10C" Format="i4" Width="48" Height="46" Offset="0xAEC0" /> - <Texture Name="gMapGrandStatic10DTex" OutName="map_10D" Format="i4" Width="64" Height="61" Offset="0xB310" /> - <Texture Name="gMapGrandStatic10ETex" OutName="map_10E" Format="i4" Width="96" Height="85" Offset="0xBAB0" /> - <Texture Name="gMapGrandStatic10FTex" OutName="map_10F" Format="i4" Width="96" Height="85" Offset="0xCAA0" /> - <Texture Name="gMapGrandStatic110Tex" OutName="map_110" Format="i4" Width="96" Height="85" Offset="0xDA90" /> - <Texture Name="gMapGrandStatic111Tex" OutName="map_111" Format="i4" Width="48" Height="80" Offset="0xEA80" /> - <Texture Name="gMapGrandStatic112Tex" OutName="map_112" Format="i4" Width="32" Height="128" Offset="0xF200" /> - <Texture Name="gMapGrandStatic113Tex" OutName="map_113" Format="i4" Width="80" Height="53" Offset="0xFA00" /> - <Texture Name="gMapGrandStatic114Tex" OutName="map_114" Format="i4" Width="32" Height="81" Offset="0x10250" /> - <Texture Name="gMapGrandStatic115Tex" OutName="map_115" Format="i4" Width="80" Height="45" Offset="0x10760" /> - <Texture Name="gMapGrandStatic116Tex" OutName="map_116" Format="i4" Width="64" Height="87" Offset="0x10E70" /> - <Texture Name="gMapGrandStatic117Tex" OutName="map_117" Format="i4" Width="64" Height="51" Offset="0x11950" /> - <Texture Name="gMapGrandStatic118Tex" OutName="map_118" Format="i4" Width="80" Height="79" Offset="0x11FB0" /> - <Texture Name="gMapGrandStatic119Tex" OutName="map_119" Format="i4" Width="96" Height="75" Offset="0x12C10" /> - <Texture Name="gMapGrandStatic11ATex" OutName="map_11A" Format="i4" Width="48" Height="41" Offset="0x13A20" /> - <Texture Name="gMapGrandStatic11BTex" OutName="map_11B" Format="i4" Width="64" Height="45" Offset="0x13E00" /> - <Texture Name="gMapGrandStatic11CTex" OutName="map_11C" Format="i4" Width="80" Height="52" Offset="0x143A0" /> - <Texture Name="gMapGrandStatic11DTex" OutName="map_11D" Format="i4" Width="48" Height="45" Offset="0x14BC0" /> - <Texture Name="gMapGrandStatic11ETex" OutName="map_11E" Format="i4" Width="48" Height="59" Offset="0x15000" /> - <Texture Name="gMapGrandStatic11FTex" OutName="map_11F" Format="i4" Width="48" Height="60" Offset="0x15590" /> - <Texture Name="gMapGrandStatic120Tex" OutName="map_120" Format="i4" Width="48" Height="81" Offset="0x15B30" /> - <Texture Name="gMapGrandStatic121Tex" OutName="map_121" Format="i4" Width="48" Height="81" Offset="0x162D0" /> - <Texture Name="gMapGrandStatic122Tex" OutName="map_122" Format="i4" Width="80" Height="89" Offset="0x16A70" /> - <Texture Name="gMapGrandStatic123Tex" OutName="map_123" Format="i4" Width="80" Height="53" Offset="0x17860" /> - <Texture Name="gMapGrandStatic124Tex" OutName="map_124" Format="i4" Width="64" Height="78" Offset="0x180B0" /> - <Texture Name="gMapGrandStatic125Tex" OutName="map_125" Format="i4" Width="64" Height="68" Offset="0x18A70" /> - <Texture Name="gMapGrandStatic126Tex" OutName="map_126" Format="i4" Width="48" Height="68" Offset="0x192F0" /> - <Texture Name="gMapGrandStatic127Tex" OutName="map_127" Format="i4" Width="48" Height="36" Offset="0x19950" /> - <Texture Name="gMapGrandStatic128Tex" OutName="map_128" Format="i4" Width="48" Height="25" Offset="0x19CB0" /> - <Texture Name="gMapGrandStatic129Tex" OutName="map_129" Format="i4" Width="64" Height="75" Offset="0x19F10" /> - <Texture Name="gMapGrandStatic12ATex" OutName="map_12A" Format="i4" Width="32" Height="53" Offset="0x1A870" /> - <Texture Name="gMapGrandStatic12BTex" OutName="map_12B" Format="i4" Width="80" Height="62" Offset="0x1ABC0" /> - <Texture Name="gMapGrandStatic12CTex" OutName="map_12C" Format="i4" Width="64" Height="76" Offset="0x1B570" /> - <Texture Name="gMapGrandStatic12DTex" OutName="map_12D" Format="i4" Width="96" Height="85" Offset="0x1BEF0" /> - <Texture Name="gMapGrandStatic12ETex" OutName="map_12E" Format="i4" Width="80" Height="71" Offset="0x1CEE0" /> - <Texture Name="gMapGrandStatic12FTex" OutName="map_12F" Format="i4" Width="80" Height="87" Offset="0x1DA00" /> - <Texture Name="gMapGrandStatic130Tex" OutName="map_130" Format="i4" Width="64" Height="65" Offset="0x1E7A0" /> - <Texture Name="gMapGrandStatic131Tex" OutName="map_131" Format="i4" Width="48" Height="41" Offset="0x1EFC0" /> - <Texture Name="gMapGrandStatic132Tex" OutName="map_132" Format="i4" Width="64" Height="76" Offset="0x1F3A0" /> - <Texture Name="gMapGrandStatic133Tex" OutName="map_133" Format="i4" Width="80" Height="60" Offset="0x1FD20" /> - <Texture Name="gMapGrandStatic134Tex" OutName="map_134" Format="i4" Width="80" Height="47" Offset="0x20680" /> - <Texture Name="gMapGrandStatic135Tex" OutName="map_135" Format="i4" Width="80" Height="60" Offset="0x20DE0" /> - <Texture Name="gMapGrandStatic136Tex" OutName="map_136" Format="i4" Width="48" Height="19" Offset="0x21740" /> - <Texture Name="gMapGrandStatic137Tex" OutName="map_137" Format="i4" Width="32" Height="99" Offset="0x21910" /> - <Texture Name="gMapGrandStatic138Tex" OutName="map_138" Format="i4" Width="48" Height="69" Offset="0x21F40" /> - <Texture Name="gMapGrandStatic139Tex" OutName="map_139" Format="i4" Width="48" Height="83" Offset="0x225C0" /> - <Texture Name="gMapGrandStatic13ATex" OutName="map_13A" Format="i4" Width="80" Height="54" Offset="0x22D90" /> - <Texture Name="gMapGrandStatic13BTex" OutName="map_13B" Format="i4" Width="80" Height="92" Offset="0x23600" /> - <Texture Name="gMapGrandStatic13CTex" OutName="map_13C" Format="i4" Width="48" Height="75" Offset="0x24460" /> - <Texture Name="gMapGrandStatic13DTex" OutName="map_13D" Format="i4" Width="64" Height="49" Offset="0x24B70" /> - <Texture Name="gMapGrandStatic13ETex" OutName="map_13E" Format="i4" Width="64" Height="49" Offset="0x25190" /> - <Texture Name="gMapGrandStatic13FTex" OutName="map_13F" Format="i4" Width="64" Height="52" Offset="0x257B0" /> - <Texture Name="gMapGrandStatic140Tex" OutName="map_140" Format="i4" Width="64" Height="49" Offset="0x25E30" /> - <Texture Name="gMapGrandStatic141Tex" OutName="map_141" Format="i4" Width="32" Height="33" Offset="0x26450" /> - <Texture Name="gMapGrandStatic142Tex" OutName="map_142" Format="i4" Width="48" Height="50" Offset="0x26660" /> - <Texture Name="gMapGrandStatic143Tex" OutName="map_143" Format="i4" Width="64" Height="52" Offset="0x26B10" /> - <Texture Name="gMapGrandStatic144Tex" OutName="map_144" Format="i4" Width="48" Height="35" Offset="0x27190" /> - <Texture Name="gMapGrandStatic145Tex" OutName="map_145" Format="i4" Width="64" Height="51" Offset="0x274E0" /> - <Texture Name="gMapGrandStatic146Tex" OutName="map_146" Format="i4" Width="48" Height="35" Offset="0x27B40" /> - <Texture Name="gMapGrandStatic147Tex" OutName="map_147" Format="i4" Width="48" Height="53" Offset="0x27E90" /> - <Texture Name="gMapGrandStatic148Tex" OutName="map_148" Format="i4" Width="64" Height="53" Offset="0x28390" /> - <Texture Name="gMapGrandStatic149Tex" OutName="map_149" Format="i4" Width="64" Height="47" Offset="0x28A30" /> - <Texture Name="gMapGrandStatic14ATex" OutName="map_14A" Format="i4" Width="64" Height="52" Offset="0x29010" /> - <Texture Name="gMapGrandStatic14BTex" OutName="map_14B" Format="i4" Width="48" Height="48" Offset="0x29690" /> - <Texture Name="gMapGrandStatic14CTex" OutName="map_14C" Format="i4" Width="64" Height="87" Offset="0x29B10" /> - <Texture Name="gMapGrandStatic14DTex" OutName="map_14D" Format="i4" Width="48" Height="30" Offset="0x2A5F0" /> - <Texture Name="gMapGrandStatic14ETex" OutName="map_14E" Format="i4" Width="80" Height="74" Offset="0x2A8C0" /> - <Texture Name="gMapGrandStatic14FTex" OutName="map_14F" Format="i4" Width="80" Height="87" Offset="0x2B450" /> - <Texture Name="gMapGrandStatic150Tex" OutName="map_150" Format="i4" Width="80" Height="56" Offset="0x2C1F0" /> - <Texture Name="gMapGrandStatic151Tex" OutName="map_151" Format="i4" Width="80" Height="65" Offset="0x2CAB0" /> - <Texture Name="gMapGrandStatic152Tex" OutName="map_152" Format="i4" Width="16" Height="38" Offset="0x2D4E0" /> - <Texture Name="gMapGrandStatic153Tex" OutName="map_153" Format="i4" Width="80" Height="78" Offset="0x2D610" /> - <Texture Name="gMapGrandStatic154Tex" OutName="map_154" Format="i4" Width="80" Height="55" Offset="0x2E240" /> - <Texture Name="gMapGrandStatic155Tex" OutName="map_155" Format="i4" Width="80" Height="98" Offset="0x2EAE0" /> - <Texture Name="gMapGrandStatic156Tex" OutName="map_156" Format="i4" Width="80" Height="62" Offset="0x2FA30" /> - <Texture Name="gMapGrandStatic157Tex" OutName="map_157" Format="i4" Width="32" Height="123" Offset="0x303E0" /> - <Texture Name="gMapGrandStatic158Tex" OutName="map_158" Format="i4" Width="80" Height="60" Offset="0x30B90" /> - <Texture Name="gMapGrandStatic159Tex" OutName="map_159" Format="i4" Width="48" Height="77" Offset="0x314F0" /> - <Texture Name="gMapGrandStatic15ATex" OutName="map_15A" Format="i4" Width="80" Height="64" Offset="0x31C30" /> - <Texture Name="gMapGrandStatic15BTex" OutName="map_15B" Format="i4" Width="64" Height="50" Offset="0x32630" /> - <Texture Name="gMapGrandStatic15CTex" OutName="map_15C" Format="i4" Width="80" Height="65" Offset="0x32C70" /> - <Texture Name="gMapGrandStatic15DTex" OutName="map_15D" Format="i4" Width="32" Height="61" Offset="0x336A0" /> - <Texture Name="gMapGrandStatic15ETex" OutName="map_15E" Format="i4" Width="80" Height="83" Offset="0x33A70" /> - <Texture Name="gMapGrandStatic15FTex" OutName="map_15F" Format="i4" Width="80" Height="27" Offset="0x34770" /> - <Texture Name="gMapGrandStatic160Tex" OutName="map_160" Format="i4" Width="80" Height="23" Offset="0x34BB0" /> - <Texture Name="gMapGrandStatic161Tex" OutName="map_161" Format="i4" Width="80" Height="60" Offset="0x34F50" /> + <File Name="map_grand_static"> + <Blob Name="map_grand_static_Blob_000000" Size="0x0FF0" Offset="0x0" /> + <Blob Name="map_grand_static_Blob_000FF0" Size="0x0FF0" Offset="0xFF0" /> + <Blob Name="map_grand_static_Blob_001FE0" Size="0x0FF0" Offset="0x1FE0" /> + <Blob Name="map_grand_static_Blob_002FD0" Size="0x0FF0" Offset="0x2FD0" /> + <Blob Name="map_grand_static_Blob_003FC0" Size="0x0FF0" Offset="0x3FC0" /> + <Blob Name="map_grand_static_Blob_004FB0" Size="0x0B40" Offset="0x4FB0" /> + <Blob Name="map_grand_static_Blob_005AF0" Size="0x0FF0" Offset="0x5AF0" /> + <Blob Name="map_grand_static_Blob_006AE0" Size="0x0FF0" Offset="0x6AE0" /> + <Blob Name="map_grand_static_Blob_007AD0" Size="0x0FF0" Offset="0x7AD0" /> + <Blob Name="map_grand_static_Blob_008AC0" Size="0x0FF0" Offset="0x8AC0" /> + <Blob Name="map_grand_static_Blob_009AB0" Size="0x0420" Offset="0x9AB0" /> + <Blob Name="map_grand_static_Blob_009ED0" Size="0x0FF0" Offset="0x9ED0" /> + <Blob Name="map_grand_static_Blob_00AEC0" Size="0x0450" Offset="0xAEC0" /> + <Blob Name="map_grand_static_Blob_00B310" Size="0x07A0" Offset="0xB310" /> + <Blob Name="map_grand_static_Blob_00BAB0" Size="0x0FF0" Offset="0xBAB0" /> + <Blob Name="map_grand_static_Blob_00CAA0" Size="0x0FF0" Offset="0xCAA0" /> + <Blob Name="map_grand_static_Blob_00DA90" Size="0x0FF0" Offset="0xDA90" /> + <Blob Name="map_grand_static_Blob_00EA80" Size="0x0780" Offset="0xEA80" /> + <Blob Name="map_grand_static_Blob_00F200" Size="0x0800" Offset="0xF200" /> + <Blob Name="map_grand_static_Blob_00FA00" Size="0x0850" Offset="0xFA00" /> + <Blob Name="map_grand_static_Blob_010250" Size="0x0510" Offset="0x10250" /> + <Blob Name="map_grand_static_Blob_010760" Size="0x0710" Offset="0x10760" /> + <Blob Name="map_grand_static_Blob_010E70" Size="0x0AE0" Offset="0x10E70" /> + <Blob Name="map_grand_static_Blob_011950" Size="0x0660" Offset="0x11950" /> + <Blob Name="map_grand_static_Blob_011FB0" Size="0x0C60" Offset="0x11FB0" /> + <Blob Name="map_grand_static_Blob_012C10" Size="0x0E10" Offset="0x12C10" /> + <Blob Name="map_grand_static_Blob_013A20" Size="0x03E0" Offset="0x13A20" /> + <Blob Name="map_grand_static_Blob_013E00" Size="0x05A0" Offset="0x13E00" /> + <Blob Name="map_grand_static_Blob_0143A0" Size="0x0820" Offset="0x143A0" /> + <Blob Name="map_grand_static_Blob_014BC0" Size="0x0440" Offset="0x14BC0" /> + <Blob Name="map_grand_static_Blob_015000" Size="0x0590" Offset="0x15000" /> + <Blob Name="map_grand_static_Blob_015590" Size="0x05A0" Offset="0x15590" /> + <Blob Name="map_grand_static_Blob_015B30" Size="0x07A0" Offset="0x15B30" /> + <Blob Name="map_grand_static_Blob_0162D0" Size="0x07A0" Offset="0x162D0" /> + <Blob Name="map_grand_static_Blob_016A70" Size="0x0DF0" Offset="0x16A70" /> + <Blob Name="map_grand_static_Blob_017860" Size="0x0850" Offset="0x17860" /> + <Blob Name="map_grand_static_Blob_0180B0" Size="0x09C0" Offset="0x180B0" /> + <Blob Name="map_grand_static_Blob_018A70" Size="0x0880" Offset="0x18A70" /> + <Blob Name="map_grand_static_Blob_0192F0" Size="0x0660" Offset="0x192F0" /> + <Blob Name="map_grand_static_Blob_019950" Size="0x0360" Offset="0x19950" /> + <Blob Name="map_grand_static_Blob_019CB0" Size="0x0260" Offset="0x19CB0" /> + <Blob Name="map_grand_static_Blob_019F10" Size="0x0960" Offset="0x19F10" /> + <Blob Name="map_grand_static_Blob_01A870" Size="0x0350" Offset="0x1A870" /> + <Blob Name="map_grand_static_Blob_01ABC0" Size="0x09B0" Offset="0x1ABC0" /> + <Blob Name="map_grand_static_Blob_01B570" Size="0x0980" Offset="0x1B570" /> + <Blob Name="map_grand_static_Blob_01BEF0" Size="0x0FF0" Offset="0x1BEF0" /> + <Blob Name="map_grand_static_Blob_01CEE0" Size="0x0B20" Offset="0x1CEE0" /> + <Blob Name="map_grand_static_Blob_01DA00" Size="0x0DA0" Offset="0x1DA00" /> + <Blob Name="map_grand_static_Blob_01E7A0" Size="0x0820" Offset="0x1E7A0" /> + <Blob Name="map_grand_static_Blob_01EFC0" Size="0x03E0" Offset="0x1EFC0" /> + <Blob Name="map_grand_static_Blob_01F3A0" Size="0x0980" Offset="0x1F3A0" /> + <Blob Name="map_grand_static_Blob_01FD20" Size="0x0960" Offset="0x1FD20" /> + <Blob Name="map_grand_static_Blob_020680" Size="0x0760" Offset="0x20680" /> + <Blob Name="map_grand_static_Blob_020DE0" Size="0x0960" Offset="0x20DE0" /> + <Blob Name="map_grand_static_Blob_021740" Size="0x01D0" Offset="0x21740" /> + <Blob Name="map_grand_static_Blob_021910" Size="0x0630" Offset="0x21910" /> + <Blob Name="map_grand_static_Blob_021F40" Size="0x0680" Offset="0x21F40" /> + <Blob Name="map_grand_static_Blob_0225C0" Size="0x07D0" Offset="0x225C0" /> + <Blob Name="map_grand_static_Blob_022D90" Size="0x0870" Offset="0x22D90" /> + <Blob Name="map_grand_static_Blob_023600" Size="0x0E60" Offset="0x23600" /> + <Blob Name="map_grand_static_Blob_024460" Size="0x0710" Offset="0x24460" /> + <Blob Name="map_grand_static_Blob_024B70" Size="0x0620" Offset="0x24B70" /> + <Blob Name="map_grand_static_Blob_025190" Size="0x0620" Offset="0x25190" /> + <Blob Name="map_grand_static_Blob_0257B0" Size="0x0680" Offset="0x257B0" /> + <Blob Name="map_grand_static_Blob_025E30" Size="0x0620" Offset="0x25E30" /> + <Blob Name="map_grand_static_Blob_026450" Size="0x0210" Offset="0x26450" /> + <Blob Name="map_grand_static_Blob_026660" Size="0x04B0" Offset="0x26660" /> + <Blob Name="map_grand_static_Blob_026B10" Size="0x0680" Offset="0x26B10" /> + <Blob Name="map_grand_static_Blob_027190" Size="0x0350" Offset="0x27190" /> + <Blob Name="map_grand_static_Blob_0274E0" Size="0x0660" Offset="0x274E0" /> + <Blob Name="map_grand_static_Blob_027B40" Size="0x0350" Offset="0x27B40" /> + <Blob Name="map_grand_static_Blob_027E90" Size="0x0500" Offset="0x27E90" /> + <Blob Name="map_grand_static_Blob_028390" Size="0x06A0" Offset="0x28390" /> + <Blob Name="map_grand_static_Blob_028A30" Size="0x05E0" Offset="0x28A30" /> + <Blob Name="map_grand_static_Blob_029010" Size="0x0680" Offset="0x29010" /> + <Blob Name="map_grand_static_Blob_029690" Size="0x0480" Offset="0x29690" /> + <Blob Name="map_grand_static_Blob_029B10" Size="0x0AE0" Offset="0x29B10" /> + <Blob Name="map_grand_static_Blob_02A5F0" Size="0x02D0" Offset="0x2A5F0" /> + <Blob Name="map_grand_static_Blob_02A8C0" Size="0x0B90" Offset="0x2A8C0" /> + <Blob Name="map_grand_static_Blob_02B450" Size="0x0DA0" Offset="0x2B450" /> + <Blob Name="map_grand_static_Blob_02C1F0" Size="0x08C0" Offset="0x2C1F0" /> + <Blob Name="map_grand_static_Blob_02CAB0" Size="0x0A30" Offset="0x2CAB0" /> + <Blob Name="map_grand_static_Blob_02D4E0" Size="0x0130" Offset="0x2D4E0" /> + <Blob Name="map_grand_static_Blob_02D610" Size="0x0C30" Offset="0x2D610" /> + <Blob Name="map_grand_static_Blob_02E240" Size="0x08A0" Offset="0x2E240" /> + <Blob Name="map_grand_static_Blob_02EAE0" Size="0x0F50" Offset="0x2EAE0" /> + <Blob Name="map_grand_static_Blob_02FA30" Size="0x09B0" Offset="0x2FA30" /> + <Blob Name="map_grand_static_Blob_0303E0" Size="0x07B0" Offset="0x303E0" /> + <Blob Name="map_grand_static_Blob_030B90" Size="0x0960" Offset="0x30B90" /> + <Blob Name="map_grand_static_Blob_0314F0" Size="0x0740" Offset="0x314F0" /> + <Blob Name="map_grand_static_Blob_031C30" Size="0x0A00" Offset="0x31C30" /> + <Blob Name="map_grand_static_Blob_032630" Size="0x0640" Offset="0x32630" /> + <Blob Name="map_grand_static_Blob_032C70" Size="0x0A30" Offset="0x32C70" /> + <Blob Name="map_grand_static_Blob_0336A0" Size="0x03D0" Offset="0x336A0" /> + <Blob Name="map_grand_static_Blob_033A70" Size="0x0D00" Offset="0x33A70" /> + <Blob Name="map_grand_static_Blob_034770" Size="0x0440" Offset="0x34770" /> + <Blob Name="map_grand_static_Blob_034BB0" Size="0x03A0" Offset="0x34BB0" /> + <Blob Name="map_grand_static_Blob_034F50" Size="0x0960" Offset="0x34F50" /> </File> </Root> diff --git a/mm/assets/xml/archives/map_i_static.xml b/mm/assets/xml/archives/map_i_static.xml index fce2cc437..15e1a4348 100644 --- a/mm/assets/xml/archives/map_i_static.xml +++ b/mm/assets/xml/archives/map_i_static.xml @@ -1,62 +1,62 @@ <Root> - <File Name="map_i_static.unarchive"> - <Texture Name="gMapIStatic00Tex" OutName="map_00" Format="i4" Width="96" Height="85" Offset="0x0" /> - <Texture Name="gMapIStatic01Tex" OutName="map_01" Format="i4" Width="96" Height="85" Offset="0xFF0" /> - <Texture Name="gMapIStatic02Tex" OutName="map_02" Format="i4" Width="96" Height="85" Offset="0x1FE0" /> - <Texture Name="gMapIStatic03Tex" OutName="map_03" Format="i4" Width="96" Height="85" Offset="0x2FD0" /> - <Texture Name="gMapIStatic04Tex" OutName="map_04" Format="i4" Width="96" Height="85" Offset="0x3FC0" /> - <Texture Name="gMapIStatic05Tex" OutName="map_05" Format="i4" Width="32" Height="29" Offset="0x4FB0" /> - <Texture Name="gMapIStatic06Tex" OutName="map_06" Format="i4" Width="32" Height="27" Offset="0x5180" /> - <Texture Name="gMapIStatic07Tex" OutName="map_07" Format="i4" Width="32" Height="30" Offset="0x5330" /> - <Texture Name="gMapIStatic08Tex" OutName="map_08" Format="i4" Width="16" Height="32" Offset="0x5510" /> - <Texture Name="gMapIStatic09Tex" OutName="map_09" Format="i4" Width="16" Height="12" Offset="0x5610" /> - <Texture Name="gMapIStatic0ATex" OutName="map_0A" Format="i4" Width="32" Height="27" Offset="0x5670" /> - <Texture Name="gMapIStatic0BTex" OutName="map_0B" Format="i4" Width="16" Height="14" Offset="0x5820" /> - <Texture Name="gMapIStatic0CTex" OutName="map_0C" Format="i4" Width="32" Height="19" Offset="0x5890" /> - <Texture Name="gMapIStatic0DTex" OutName="map_0D" Format="i4" Width="32" Height="26" Offset="0x59C0" /> - <Texture Name="gMapIStatic0ETex" OutName="map_0E" Format="i4" Width="16" Height="32" Offset="0x5B60" /> - <Texture Name="gMapIStatic0FTex" OutName="map_0F" Format="i4" Width="32" Height="27" Offset="0x5C60" /> - <Texture Name="gMapIStatic10Tex" OutName="map_10" Format="i4" Width="16" Height="35" Offset="0x5E10" /> - <Texture Name="gMapIStatic11Tex" OutName="map_11" Format="i4" Width="32" Height="18" Offset="0x5F30" /> - <Texture Name="gMapIStatic12Tex" OutName="map_12" Format="i4" Width="32" Height="38" Offset="0x6050" /> - <Texture Name="gMapIStatic13Tex" OutName="map_13" Format="i4" Width="32" Height="21" Offset="0x62B0" /> - <Texture Name="gMapIStatic14Tex" OutName="map_14" Format="i4" Width="32" Height="34" Offset="0x6400" /> - <Texture Name="gMapIStatic15Tex" OutName="map_15" Format="i4" Width="48" Height="32" Offset="0x6620" /> - <Texture Name="gMapIStatic16Tex" OutName="map_16" Format="i4" Width="32" Height="17" Offset="0x6920" /> - <Texture Name="gMapIStatic17Tex" OutName="map_17" Format="i4" Width="32" Height="17" Offset="0x6A30" /> - <Texture Name="gMapIStatic18Tex" OutName="map_18" Format="i4" Width="32" Height="21" Offset="0x6B40" /> - <Texture Name="gMapIStatic19Tex" OutName="map_19" Format="i4" Width="32" Height="18" Offset="0x6C90" /> - <Texture Name="gMapIStatic1ATex" OutName="map_1A" Format="i4" Width="16" Height="24" Offset="0x6DB0" /> - <Texture Name="gMapIStatic1BTex" OutName="map_1B" Format="i4" Width="16" Height="25" Offset="0x6E70" /> - <Texture Name="gMapIStatic1CTex" OutName="map_1C" Format="i4" Width="32" Height="35" Offset="0x6F40" /> - <Texture Name="gMapIStatic1DTex" OutName="map_1D" Format="i4" Width="16" Height="19" Offset="0x7170" /> - <Texture Name="gMapIStatic1ETex" OutName="map_1E" Format="i4" Width="32" Height="28" Offset="0x7210" /> - <Texture Name="gMapIStatic1FTex" OutName="map_1F" Format="i4" Width="32" Height="16" Offset="0x73D0" /> - <Texture Name="gMapIStatic20Tex" OutName="map_20" Format="i4" Width="32" Height="24" Offset="0x74D0" /> - <Texture Name="gMapIStatic21Tex" OutName="map_21" Format="i4" Width="32" Height="21" Offset="0x7650" /> - <Texture Name="gMapIStatic22Tex" OutName="map_22" Format="i4" Width="16" Height="21" Offset="0x77A0" /> - <Texture Name="gMapIStatic23Tex" OutName="map_23" Format="i4" Width="16" Height="10" Offset="0x7850" /> - <Texture Name="gMapIStatic24Tex" OutName="map_24" Format="i4" Width="16" Height="7" Offset="0x78A0" /> - <Texture Name="gMapIStatic25Tex" OutName="map_25" Format="i4" Width="32" Height="23" Offset="0x78E0" /> - <Texture Name="gMapIStatic26Tex" OutName="map_26" Format="i4" Width="16" Height="16" Offset="0x7A50" /> - <Texture Name="gMapIStatic27Tex" OutName="map_27" Format="i4" Width="16" Height="17" Offset="0x7AD0" /> - <Texture Name="gMapIStatic28Tex" OutName="map_28" Format="i4" Width="16" Height="23" Offset="0x7B60" /> - <Texture Name="gMapIStatic29Tex" OutName="map_29" Format="i4" Width="16" Height="15" Offset="0x7C20" /> - <Texture Name="gMapIStatic2ATex" OutName="map_2A" Format="i4" Width="32" Height="15" Offset="0x7CA0" /> - <Texture Name="gMapIStatic2BTex" OutName="map_2B" Format="i4" Width="32" Height="17" Offset="0x7D90" /> - <Texture Name="gMapIStatic2CTex" OutName="map_2C" Format="i4" Width="32" Height="16" Offset="0x7EA0" /> - <Texture Name="gMapIStatic2DTex" OutName="map_2D" Format="i4" Width="16" Height="10" Offset="0x7FA0" /> - <Texture Name="gMapIStatic2ETex" OutName="map_2E" Format="i4" Width="16" Height="17" Offset="0x7FF0" /> - <Texture Name="gMapIStatic2FTex" OutName="map_2F" Format="i4" Width="32" Height="17" Offset="0x8080" /> - <Texture Name="gMapIStatic30Tex" OutName="map_30" Format="i4" Width="16" Height="11" Offset="0x8190" /> - <Texture Name="gMapIStatic31Tex" OutName="map_31" Format="i4" Width="32" Height="17" Offset="0x81F0" /> - <Texture Name="gMapIStatic32Tex" OutName="map_32" Format="i4" Width="16" Height="12" Offset="0x8300" /> - <Texture Name="gMapIStatic33Tex" OutName="map_33" Format="i4" Width="16" Height="18" Offset="0x8360" /> - <Texture Name="gMapIStatic34Tex" OutName="map_34" Format="i4" Width="32" Height="17" Offset="0x83F0" /> - <Texture Name="gMapIStatic35Tex" OutName="map_35" Format="i4" Width="32" Height="15" Offset="0x8500" /> - <Texture Name="gMapIStatic36Tex" OutName="map_36" Format="i4" Width="16" Height="18" Offset="0x85F0" /> - <Texture Name="gMapIStatic37Tex" OutName="map_37" Format="i4" Width="16" Height="16" Offset="0x8680" /> - <Texture Name="gMapIStatic38Tex" OutName="map_38" Format="i4" Width="16" Height="30" Offset="0x8700" /> - <Texture Name="gMapIStatic39Tex" OutName="map_39" Format="i4" Width="16" Height="9" Offset="0x87F0" /> + <File Name="map_i_static"> + <Blob Name="map_i_static_Blob_000000" Size="0x0FF0" Offset="0x0" /> + <Blob Name="map_i_static_Blob_000FF0" Size="0x0FF0" Offset="0xFF0" /> + <Blob Name="map_i_static_Blob_001FE0" Size="0x0FF0" Offset="0x1FE0" /> + <Blob Name="map_i_static_Blob_002FD0" Size="0x0FF0" Offset="0x2FD0" /> + <Blob Name="map_i_static_Blob_003FC0" Size="0x0FF0" Offset="0x3FC0" /> + <Blob Name="map_i_static_Blob_004FB0" Size="0x01D0" Offset="0x4FB0" /> + <Blob Name="map_i_static_Blob_005180" Size="0x01B0" Offset="0x5180" /> + <Blob Name="map_i_static_Blob_005330" Size="0x01E0" Offset="0x5330" /> + <Blob Name="map_i_static_Blob_005510" Size="0x0100" Offset="0x5510" /> + <Blob Name="map_i_static_Blob_005610" Size="0x0060" Offset="0x5610" /> + <Blob Name="map_i_static_Blob_005670" Size="0x01B0" Offset="0x5670" /> + <Blob Name="map_i_static_Blob_005820" Size="0x0070" Offset="0x5820" /> + <Blob Name="map_i_static_Blob_005890" Size="0x0130" Offset="0x5890" /> + <Blob Name="map_i_static_Blob_0059C0" Size="0x01A0" Offset="0x59C0" /> + <Blob Name="map_i_static_Blob_005B60" Size="0x0100" Offset="0x5B60" /> + <Blob Name="map_i_static_Blob_005C60" Size="0x01B0" Offset="0x5C60" /> + <Blob Name="map_i_static_Blob_005E10" Size="0x0120" Offset="0x5E10" /> + <Blob Name="map_i_static_Blob_005F30" Size="0x0120" Offset="0x5F30" /> + <Blob Name="map_i_static_Blob_006050" Size="0x0260" Offset="0x6050" /> + <Blob Name="map_i_static_Blob_0062B0" Size="0x0150" Offset="0x62B0" /> + <Blob Name="map_i_static_Blob_006400" Size="0x0220" Offset="0x6400" /> + <Blob Name="map_i_static_Blob_006620" Size="0x0300" Offset="0x6620" /> + <Blob Name="map_i_static_Blob_006920" Size="0x0110" Offset="0x6920" /> + <Blob Name="map_i_static_Blob_006A30" Size="0x0110" Offset="0x6A30" /> + <Blob Name="map_i_static_Blob_006B40" Size="0x0150" Offset="0x6B40" /> + <Blob Name="map_i_static_Blob_006C90" Size="0x0120" Offset="0x6C90" /> + <Blob Name="map_i_static_Blob_006DB0" Size="0x00C0" Offset="0x6DB0" /> + <Blob Name="map_i_static_Blob_006E70" Size="0x00D0" Offset="0x6E70" /> + <Blob Name="map_i_static_Blob_006F40" Size="0x0230" Offset="0x6F40" /> + <Blob Name="map_i_static_Blob_007170" Size="0x00A0" Offset="0x7170" /> + <Blob Name="map_i_static_Blob_007210" Size="0x01C0" Offset="0x7210" /> + <Blob Name="map_i_static_Blob_0073D0" Size="0x0100" Offset="0x73D0" /> + <Blob Name="map_i_static_Blob_0074D0" Size="0x0180" Offset="0x74D0" /> + <Blob Name="map_i_static_Blob_007650" Size="0x0150" Offset="0x7650" /> + <Blob Name="map_i_static_Blob_0077A0" Size="0x00B0" Offset="0x77A0" /> + <Blob Name="map_i_static_Blob_007850" Size="0x0050" Offset="0x7850" /> + <Blob Name="map_i_static_Blob_0078A0" Size="0x0040" Offset="0x78A0" /> + <Blob Name="map_i_static_Blob_0078E0" Size="0x0170" Offset="0x78E0" /> + <Blob Name="map_i_static_Blob_007A50" Size="0x0080" Offset="0x7A50" /> + <Blob Name="map_i_static_Blob_007AD0" Size="0x0090" Offset="0x7AD0" /> + <Blob Name="map_i_static_Blob_007B60" Size="0x00C0" Offset="0x7B60" /> + <Blob Name="map_i_static_Blob_007C20" Size="0x0080" Offset="0x7C20" /> + <Blob Name="map_i_static_Blob_007CA0" Size="0x00F0" Offset="0x7CA0" /> + <Blob Name="map_i_static_Blob_007D90" Size="0x0110" Offset="0x7D90" /> + <Blob Name="map_i_static_Blob_007EA0" Size="0x0100" Offset="0x7EA0" /> + <Blob Name="map_i_static_Blob_007FA0" Size="0x0050" Offset="0x7FA0" /> + <Blob Name="map_i_static_Blob_007FF0" Size="0x0090" Offset="0x7FF0" /> + <Blob Name="map_i_static_Blob_008080" Size="0x0110" Offset="0x8080" /> + <Blob Name="map_i_static_Blob_008190" Size="0x0060" Offset="0x8190" /> + <Blob Name="map_i_static_Blob_0081F0" Size="0x0110" Offset="0x81F0" /> + <Blob Name="map_i_static_Blob_008300" Size="0x0060" Offset="0x8300" /> + <Blob Name="map_i_static_Blob_008360" Size="0x0090" Offset="0x8360" /> + <Blob Name="map_i_static_Blob_0083F0" Size="0x0110" Offset="0x83F0" /> + <Blob Name="map_i_static_Blob_008500" Size="0x00F0" Offset="0x8500" /> + <Blob Name="map_i_static_Blob_0085F0" Size="0x0090" Offset="0x85F0" /> + <Blob Name="map_i_static_Blob_008680" Size="0x0080" Offset="0x8680" /> + <Blob Name="map_i_static_Blob_008700" Size="0x00F0" Offset="0x8700" /> + <Blob Name="map_i_static_Blob_0087F0" Size="0x0050" Offset="0x87F0" /> </File> </Root> diff --git a/mm/assets/xml/archives/map_name_static.xml b/mm/assets/xml/archives/map_name_static.xml index fe392eb03..d672cdc39 100644 --- a/mm/assets/xml/archives/map_name_static.xml +++ b/mm/assets/xml/archives/map_name_static.xml @@ -1,6 +1,6 @@ <Root> <!-- Map Point Names. Must be ia4 128x16 and continguous with `ItemId` starting from `ITEM_MAP_POINT_GREAT_BAY` --> - <File Name="map_name_static.unarchive"> + <File Name="map_name_static"> <!-- First entries must be continguous with `RegionId` --> <Texture Name="gMapPointGreatBayENGTex" OutName="map_point_great_bay_eng" Format="ia4" Width="128" Height="16" Offset="0x0" /> <!-- ITEM_MAP_POINT_GREAT_BAY --> <Texture Name="gMapPointZoraHallENGTex" OutName="map_point_zora_hall_eng" Format="ia4" Width="128" Height="16" Offset="0x400" /> <!-- ITEM_MAP_POINT_ZORA_HALL --> diff --git a/mm/assets/xml/archives/schedule_dma_static.xml b/mm/assets/xml/archives/schedule_dma_static.xml index c71bdb413..42f75f6d9 100644 --- a/mm/assets/xml/archives/schedule_dma_static.xml +++ b/mm/assets/xml/archives/schedule_dma_static.xml @@ -1,5 +1,5 @@ <Root> - <File Name="schedule_dma_static_yar.unarchive" Segment="7"> + <File Name="schedule_dma_static_yar" Segment="7"> <Texture Name="gBombersNotebookPhotoAnjuTex" OutName="bombers_notebook_photo_anju" Format="rgba16" Width="32" Height="32" Offset="0x0" /> <Texture Name="gBombersNotebookPhotoKafeiTex" OutName="bombers_notebook_photo_kafei" Format="rgba16" Width="32" Height="32" Offset="0x800" /> <Texture Name="gBombersNotebookPhotoCuriosityShopManTex" OutName="bombers_notebook_photo_curiosity_shop_man" Format="rgba16" Width="32" Height="32" Offset="0x1000" /> |
