2024-03-24 02:01:28 -06:00
|
|
|
#include "Engine.h"
|
|
|
|
#include "ui/ImguiUI.h"
|
2024-05-20 22:29:07 -06:00
|
|
|
#include "StringHelper.h"
|
2024-12-31 05:27:37 -03:00
|
|
|
|
2025-01-15 15:50:57 -06:00
|
|
|
#include "extractor/GameExtractor.h"
|
2024-03-24 02:01:28 -06:00
|
|
|
#include "libultraship/src/Context.h"
|
2025-01-28 12:06:15 -05:00
|
|
|
#include "libultraship/src/controller/controldevice/controller/mapping/ControllerDefaultMappings.h"
|
2024-04-06 04:25:11 -06:00
|
|
|
#include "resource/type/ResourceType.h"
|
|
|
|
#include "resource/importers/AnimFactory.h"
|
2024-04-07 00:41:12 +01:00
|
|
|
#include "resource/importers/ColPolyFactory.h"
|
2024-04-06 14:25:40 -06:00
|
|
|
#include "resource/importers/EnvSettingsFactory.h"
|
2024-04-07 02:01:49 +01:00
|
|
|
#include "resource/importers/GenericArrayFactory.h"
|
2024-04-06 14:25:40 -06:00
|
|
|
#include "resource/importers/HitboxFactory.h"
|
2024-04-06 04:25:11 -06:00
|
|
|
#include "resource/importers/LimbFactory.h"
|
|
|
|
#include "resource/importers/MessageFactory.h"
|
|
|
|
#include "resource/importers/MessageLookupFactory.h"
|
2024-04-06 14:25:40 -06:00
|
|
|
#include "resource/importers/ObjectInitFactory.h"
|
|
|
|
#include "resource/importers/ScriptCommandFactory.h"
|
|
|
|
#include "resource/importers/ScriptFactory.h"
|
2024-04-06 04:25:11 -06:00
|
|
|
#include "resource/importers/SkeletonFactory.h"
|
2024-04-07 00:41:12 +01:00
|
|
|
#include "resource/importers/Vec3fFactory.h"
|
|
|
|
#include "resource/importers/Vec3sFactory.h"
|
2024-11-20 02:01:16 -06:00
|
|
|
|
|
|
|
#include "resource/importers/audio/AudioTableFactory.h"
|
|
|
|
#include "resource/importers/audio/BookFactory.h"
|
|
|
|
#include "resource/importers/audio/DrumFactory.h"
|
|
|
|
#include "resource/importers/audio/EnvelopeFactory.h"
|
|
|
|
#include "resource/importers/audio/InstrumentFactory.h"
|
|
|
|
#include "resource/importers/audio/LoopFactory.h"
|
|
|
|
#include "resource/importers/audio/SampleFactory.h"
|
|
|
|
#include "resource/importers/audio/SoundFontFactory.h"
|
|
|
|
|
2024-10-16 11:53:41 -06:00
|
|
|
#include "port/interpolation/FrameInterpolation.h"
|
2024-05-20 22:29:07 -06:00
|
|
|
#include <Fast3D/Fast3dWindow.h>
|
|
|
|
#include <DisplayListFactory.h>
|
|
|
|
#include <TextureFactory.h>
|
|
|
|
#include <MatrixFactory.h>
|
|
|
|
#include <BlobFactory.h>
|
|
|
|
#include <VertexFactory.h>
|
2024-10-25 22:39:32 -06:00
|
|
|
#include "audio/GameAudio.h"
|
2024-11-20 02:01:16 -06:00
|
|
|
#include "port/patches/DisplayListPatch.h"
|
2024-12-27 17:46:16 -06:00
|
|
|
#include "port/mods/PortEnhancements.h"
|
2024-03-24 02:01:28 -06:00
|
|
|
|
|
|
|
#include <Fast3D/gfx_pc.h>
|
2024-11-15 14:48:47 -06:00
|
|
|
#include <filesystem>
|
|
|
|
|
2025-03-05 18:31:53 -06:00
|
|
|
#ifdef __SWITCH__
|
|
|
|
#include <port/switch/SwitchImpl.h>
|
|
|
|
#endif
|
|
|
|
|
2024-11-15 14:48:47 -06:00
|
|
|
namespace fs = std::filesystem;
|
2024-03-24 02:01:28 -06:00
|
|
|
|
|
|
|
extern "C" {
|
2024-12-27 23:07:06 -06:00
|
|
|
bool prevAltAssets = false;
|
2025-01-16 11:28:47 -06:00
|
|
|
bool gEnableGammaBoost = true;
|
2024-04-01 23:13:52 -06:00
|
|
|
#include <sf64thread.h>
|
|
|
|
#include <macros.h>
|
2024-12-31 05:27:37 -03:00
|
|
|
#include "sf64audio_provisional.h"
|
2024-11-14 20:23:27 -03:00
|
|
|
void AudioThread_CreateNextAudioBuffer(int16_t* samples, uint32_t num_samples);
|
2024-03-24 02:01:28 -06:00
|
|
|
}
|
|
|
|
|
2025-01-31 01:02:33 -06:00
|
|
|
std::vector<uint8_t*> MemoryPool;
|
2024-03-24 02:01:28 -06:00
|
|
|
GameEngine* GameEngine::Instance;
|
|
|
|
|
|
|
|
GameEngine::GameEngine() {
|
2025-03-05 18:31:53 -06:00
|
|
|
#ifdef __SWITCH__
|
|
|
|
Ship::Switch::Init(Ship::PreInitPhase);
|
|
|
|
Ship::Switch::Init(Ship::PostInitPhase);
|
|
|
|
#endif
|
|
|
|
|
2025-01-09 10:17:46 +00:00
|
|
|
std::vector<std::string> archiveFiles;
|
2025-01-15 15:50:57 -06:00
|
|
|
const std::string main_path = Ship::Context::GetPathRelativeToAppDirectory("sf64.o2r");
|
|
|
|
const std::string assets_path = Ship::Context::GetPathRelativeToAppDirectory("starship.o2r");
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
2025-04-02 22:57:44 -03:00
|
|
|
// AllocConsole();
|
2025-01-15 15:50:57 -06:00
|
|
|
#endif
|
|
|
|
|
2025-01-16 02:17:12 -06:00
|
|
|
if (!fs::exists("mods")) {
|
|
|
|
fs::create_directories("mods");
|
|
|
|
}
|
|
|
|
|
2025-01-15 15:50:57 -06:00
|
|
|
if (std::filesystem::exists(main_path)) {
|
|
|
|
archiveFiles.push_back(main_path);
|
|
|
|
} else {
|
2025-01-15 19:29:43 -06:00
|
|
|
if (ShowYesNoBox("No O2R Files", "No O2R files found. Generate one now?") == IDYES) {
|
|
|
|
if(!GenAssetFile()){
|
|
|
|
ShowMessage("Error", "An error occured, no O2R file was generated.\n\nExiting...");
|
|
|
|
exit(1);
|
|
|
|
} else {
|
|
|
|
archiveFiles.push_back(main_path);
|
|
|
|
}
|
2025-01-16 01:31:33 -06:00
|
|
|
|
|
|
|
if (ShowYesNoBox("Extraction Complete", "ROM Extracted. Extract another?") == IDYES) {
|
|
|
|
if(!GenAssetFile()){
|
|
|
|
ShowMessage("Error", "An error occured, no O2R file was generated.");
|
|
|
|
}
|
|
|
|
}
|
2025-01-15 19:29:43 -06:00
|
|
|
} else {
|
|
|
|
exit(1);
|
|
|
|
}
|
2024-04-06 04:25:11 -06:00
|
|
|
}
|
2025-01-15 15:50:57 -06:00
|
|
|
|
|
|
|
if (std::filesystem::exists(assets_path)) {
|
|
|
|
archiveFiles.push_back(assets_path);
|
2024-03-24 02:01:28 -06:00
|
|
|
}
|
2025-01-15 15:50:57 -06:00
|
|
|
|
2024-11-14 20:23:27 -03:00
|
|
|
if (const std::string patches_path = Ship::Context::GetPathRelativeToAppDirectory("mods");
|
|
|
|
!patches_path.empty() && std::filesystem::exists(patches_path)) {
|
2024-03-24 02:01:28 -06:00
|
|
|
if (std::filesystem::is_directory(patches_path)) {
|
2024-11-14 20:23:27 -03:00
|
|
|
for (const auto& p : std::filesystem::recursive_directory_iterator(patches_path)) {
|
2024-11-16 16:19:14 -06:00
|
|
|
const auto ext = p.path().extension().string();
|
|
|
|
if (StringHelper::IEquals(ext, ".otr") || StringHelper::IEquals(ext, ".o2r")) {
|
2025-01-09 10:17:46 +00:00
|
|
|
archiveFiles.push_back(p.path().generic_string());
|
2024-03-24 02:01:28 -06:00
|
|
|
}
|
2025-01-07 13:20:37 -06:00
|
|
|
|
|
|
|
if (StringHelper::IEquals(ext, ".zip")) {
|
|
|
|
SPDLOG_WARN("Zip files should be only used for development purposes, not for distribution");
|
2025-01-09 10:17:46 +00:00
|
|
|
archiveFiles.push_back(p.path().generic_string());
|
2025-01-07 13:20:37 -06:00
|
|
|
}
|
2024-03-24 02:01:28 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-04-06 04:25:11 -06:00
|
|
|
|
2024-12-31 05:27:37 -03:00
|
|
|
this->context = Ship::Context::CreateUninitializedInstance("Starship", "ship", "starship.cfg.json");
|
2024-12-26 14:12:42 -05:00
|
|
|
|
2024-12-31 05:27:37 -03:00
|
|
|
this->context->InitConfiguration(); // without this line InitConsoleVariables fails at Config::Reload()
|
|
|
|
this->context->InitConsoleVariables(); // without this line the controldeck constructor failes in
|
|
|
|
// ShipDeviceIndexMappingManager::UpdateControllerNamesFromConfig()
|
2024-12-26 13:59:26 -05:00
|
|
|
|
2025-01-28 12:06:15 -05:00
|
|
|
auto defaultMappings = std::make_shared<Ship::ControllerDefaultMappings>(
|
|
|
|
// KeyboardKeyToButtonMappings - use built-in LUS defaults
|
|
|
|
std::unordered_map<CONTROLLERBUTTONS_T, std::unordered_set<Ship::KbScancode>>(),
|
|
|
|
// KeyboardKeyToAxisDirectionMappings - use built-in LUS defaults
|
|
|
|
std::unordered_map<Ship::StickIndex, std::vector<std::pair<Ship::Direction, Ship::KbScancode>>>(),
|
|
|
|
// SDLButtonToButtonMappings
|
|
|
|
std::unordered_map<CONTROLLERBUTTONS_T, std::unordered_set<SDL_GameControllerButton>>{
|
|
|
|
{ BTN_A, { SDL_CONTROLLER_BUTTON_A } },
|
|
|
|
{ BTN_B, { SDL_CONTROLLER_BUTTON_X } },
|
|
|
|
{ BTN_START, { SDL_CONTROLLER_BUTTON_START } },
|
|
|
|
{ BTN_CLEFT, { SDL_CONTROLLER_BUTTON_Y } },
|
|
|
|
{ BTN_CDOWN, { SDL_CONTROLLER_BUTTON_B } },
|
|
|
|
{ BTN_DUP, { SDL_CONTROLLER_BUTTON_DPAD_UP } },
|
|
|
|
{ BTN_DDOWN, { SDL_CONTROLLER_BUTTON_DPAD_DOWN } },
|
|
|
|
{ BTN_DLEFT, { SDL_CONTROLLER_BUTTON_DPAD_LEFT } },
|
|
|
|
{ BTN_DRIGHT, { SDL_CONTROLLER_BUTTON_DPAD_RIGHT } },
|
|
|
|
{ BTN_R, { SDL_CONTROLLER_BUTTON_RIGHTSHOULDER } },
|
|
|
|
{ BTN_Z, { SDL_CONTROLLER_BUTTON_LEFTSHOULDER } }
|
|
|
|
},
|
|
|
|
// SDLButtonToAxisDirectionMappings - use built-in LUS defaults
|
|
|
|
std::unordered_map<Ship::StickIndex, std::vector<std::pair<Ship::Direction, SDL_GameControllerButton>>>(),
|
|
|
|
// SDLAxisDirectionToButtonMappings
|
|
|
|
std::unordered_map<CONTROLLERBUTTONS_T, std::vector<std::pair<SDL_GameControllerAxis, int32_t>>>{
|
2025-04-06 01:53:11 -03:00
|
|
|
{ BTN_CLEFT, { { SDL_CONTROLLER_AXIS_TRIGGERRIGHT, 1 } } },
|
|
|
|
{ BTN_CDOWN, { { SDL_CONTROLLER_AXIS_TRIGGERLEFT, 1 } } },
|
2025-01-28 18:32:06 -05:00
|
|
|
{ BTN_CUP, { { SDL_CONTROLLER_AXIS_RIGHTY, -1 } } },
|
|
|
|
{ BTN_CRIGHT, { { SDL_CONTROLLER_AXIS_RIGHTX, 1 } } }
|
2025-01-28 12:06:15 -05:00
|
|
|
},
|
|
|
|
// SDLAxisDirectionToAxisDirectionMappings - use built-in LUS defaults
|
|
|
|
std::unordered_map<Ship::StickIndex, std::vector<std::pair<Ship::Direction, std::pair<SDL_GameControllerAxis, int32_t>>>>()
|
|
|
|
);
|
|
|
|
auto controlDeck = std::make_shared<LUS::ControlDeck>(std::vector<CONTROLLERBUTTONS_T>(), defaultMappings);
|
2024-12-26 13:59:26 -05:00
|
|
|
|
2025-01-09 10:17:46 +00:00
|
|
|
this->context->InitResourceManager(archiveFiles, {}, 3); // without this line InitWindow fails in Gui::Init()
|
2024-12-26 14:12:42 -05:00
|
|
|
this->context->InitConsole(); // without this line the GuiWindow constructor fails in ConsoleWindow::InitElement()
|
2024-12-26 13:59:26 -05:00
|
|
|
|
2024-12-26 12:25:50 -06:00
|
|
|
auto window = std::make_shared<Fast::Fast3dWindow>(std::vector<std::shared_ptr<Ship::GuiWindow>>({}));
|
|
|
|
|
2025-03-17 14:32:57 +01:00
|
|
|
auto audioChannelsSetting = Ship::Context::GetInstance()->GetConfig()->GetCurrentAudioChannelsSetting();
|
|
|
|
this->context->Init(archiveFiles, {}, 3, { 32000, 1024, 1680, audioChannelsSetting }, window, controlDeck);
|
2024-04-06 04:25:11 -06:00
|
|
|
|
2025-03-05 18:31:53 -06:00
|
|
|
#ifndef __SWITCH__
|
2024-12-31 05:27:37 -03:00
|
|
|
Ship::Context::GetInstance()->GetLogger()->set_level(
|
|
|
|
(spdlog::level::level_enum) CVarGetInteger("gDeveloperTools.LogLevel", 1));
|
2024-11-28 17:38:48 -06:00
|
|
|
Ship::Context::GetInstance()->GetLogger()->set_pattern("[%H:%M:%S.%e] [%s:%#] [%l] %v");
|
2025-03-05 18:31:53 -06:00
|
|
|
#endif
|
2024-11-28 17:38:48 -06:00
|
|
|
|
2024-04-06 04:25:11 -06:00
|
|
|
auto loader = context->GetResourceManager()->GetResourceLoader();
|
2024-11-14 20:23:27 -03:00
|
|
|
loader->RegisterResourceFactory(std::make_shared<SF64::ResourceFactoryBinaryAnimV0>(), RESOURCE_FORMAT_BINARY,
|
|
|
|
"Animation", static_cast<uint32_t>(SF64::ResourceType::AnimData), 0);
|
|
|
|
loader->RegisterResourceFactory(std::make_shared<SF64::ResourceFactoryBinarySkeletonV0>(), RESOURCE_FORMAT_BINARY,
|
|
|
|
"Skeleton", static_cast<uint32_t>(SF64::ResourceType::Skeleton), 0);
|
|
|
|
loader->RegisterResourceFactory(std::make_shared<SF64::ResourceFactoryBinaryLimbV0>(), RESOURCE_FORMAT_BINARY,
|
|
|
|
"Limb", static_cast<uint32_t>(SF64::ResourceType::Limb), 0);
|
|
|
|
loader->RegisterResourceFactory(std::make_shared<SF64::ResourceFactoryBinaryMessageV0>(), RESOURCE_FORMAT_BINARY,
|
|
|
|
"Message", static_cast<uint32_t>(SF64::ResourceType::Message), 0);
|
|
|
|
loader->RegisterResourceFactory(std::make_shared<SF64::ResourceFactoryBinaryMessageLookupV0>(),
|
|
|
|
RESOURCE_FORMAT_BINARY, "MessageTable",
|
|
|
|
static_cast<uint32_t>(SF64::ResourceType::MessageTable), 0);
|
|
|
|
loader->RegisterResourceFactory(std::make_shared<SF64::ResourceFactoryBinaryEnvSettingsV0>(),
|
|
|
|
RESOURCE_FORMAT_BINARY, "EnvSettings",
|
|
|
|
static_cast<uint32_t>(SF64::ResourceType::Environment), 0);
|
|
|
|
loader->RegisterResourceFactory(std::make_shared<SF64::ResourceFactoryBinaryObjectInitV0>(), RESOURCE_FORMAT_BINARY,
|
|
|
|
"ObjectInit", static_cast<uint32_t>(SF64::ResourceType::ObjectInit), 0);
|
|
|
|
loader->RegisterResourceFactory(std::make_shared<SF64::ResourceFactoryBinaryHitboxV0>(), RESOURCE_FORMAT_BINARY,
|
|
|
|
"Hitbox", static_cast<uint32_t>(SF64::ResourceType::Hitbox), 0);
|
|
|
|
loader->RegisterResourceFactory(std::make_shared<SF64::ResourceFactoryBinaryScriptV0>(), RESOURCE_FORMAT_BINARY,
|
|
|
|
"Script", static_cast<uint32_t>(SF64::ResourceType::Script), 0);
|
|
|
|
loader->RegisterResourceFactory(std::make_shared<SF64::ResourceFactoryBinaryScriptCMDV0>(), RESOURCE_FORMAT_BINARY,
|
|
|
|
"ScriptCMD", static_cast<uint32_t>(SF64::ResourceType::ScriptCmd), 0);
|
|
|
|
loader->RegisterResourceFactory(std::make_shared<SF64::ResourceFactoryBinaryColPolyV0>(), RESOURCE_FORMAT_BINARY,
|
|
|
|
"ColPoly", static_cast<uint32_t>(SF64::ResourceType::ColPoly), 0);
|
|
|
|
loader->RegisterResourceFactory(std::make_shared<SF64::ResourceFactoryBinaryVec3fV0>(), RESOURCE_FORMAT_BINARY,
|
|
|
|
"Vec3f", static_cast<uint32_t>(SF64::ResourceType::Vec3f), 0);
|
|
|
|
loader->RegisterResourceFactory(std::make_shared<SF64::ResourceFactoryBinaryVec3sV0>(), RESOURCE_FORMAT_BINARY,
|
|
|
|
"Vec3s", static_cast<uint32_t>(SF64::ResourceType::Vec3s), 0);
|
|
|
|
loader->RegisterResourceFactory(std::make_shared<SF64::ResourceFactoryBinaryGenericArrayV0>(),
|
|
|
|
RESOURCE_FORMAT_BINARY, "GenericArray",
|
|
|
|
static_cast<uint32_t>(SF64::ResourceType::GenericArray), 0);
|
2024-12-26 12:25:50 -06:00
|
|
|
loader->RegisterResourceFactory(std::make_shared<Fast::ResourceFactoryBinaryTextureV0>(), RESOURCE_FORMAT_BINARY,
|
|
|
|
"Texture", static_cast<uint32_t>(Fast::ResourceType::Texture), 0);
|
|
|
|
loader->RegisterResourceFactory(std::make_shared<Fast::ResourceFactoryBinaryTextureV1>(), RESOURCE_FORMAT_BINARY,
|
|
|
|
"Texture", static_cast<uint32_t>(Fast::ResourceType::Texture), 1);
|
|
|
|
|
|
|
|
loader->RegisterResourceFactory(std::make_shared<Fast::ResourceFactoryBinaryVertexV0>(), RESOURCE_FORMAT_BINARY,
|
|
|
|
"Vertex", static_cast<uint32_t>(Fast::ResourceType::Vertex), 0);
|
2024-12-31 05:27:37 -03:00
|
|
|
loader->RegisterResourceFactory(std::make_shared<Fast::ResourceFactoryXMLVertexV0>(), RESOURCE_FORMAT_XML, "Vertex",
|
|
|
|
static_cast<uint32_t>(Fast::ResourceType::Vertex), 0);
|
2024-12-26 12:25:50 -06:00
|
|
|
|
2024-12-31 05:27:37 -03:00
|
|
|
loader->RegisterResourceFactory(std::make_shared<Fast::ResourceFactoryBinaryDisplayListV0>(),
|
|
|
|
RESOURCE_FORMAT_BINARY, "DisplayList",
|
|
|
|
static_cast<uint32_t>(Fast::ResourceType::DisplayList), 0);
|
2024-12-26 12:25:50 -06:00
|
|
|
loader->RegisterResourceFactory(std::make_shared<Fast::ResourceFactoryXMLDisplayListV0>(), RESOURCE_FORMAT_XML,
|
|
|
|
"DisplayList", static_cast<uint32_t>(Fast::ResourceType::DisplayList), 0);
|
|
|
|
|
|
|
|
loader->RegisterResourceFactory(std::make_shared<Fast::ResourceFactoryBinaryMatrixV0>(), RESOURCE_FORMAT_BINARY,
|
|
|
|
"Matrix", static_cast<uint32_t>(Fast::ResourceType::Matrix), 0);
|
|
|
|
|
|
|
|
loader->RegisterResourceFactory(std::make_shared<Ship::ResourceFactoryBinaryBlobV0>(), RESOURCE_FORMAT_BINARY,
|
|
|
|
"Blob", static_cast<uint32_t>(Ship::ResourceType::Blob), 0);
|
2024-11-20 02:01:16 -06:00
|
|
|
|
|
|
|
loader->RegisterResourceFactory(std::make_shared<SF64::ResourceFactoryBinaryAudioTableV0>(), RESOURCE_FORMAT_BINARY,
|
|
|
|
"AudioTable", static_cast<uint32_t>(SF64::ResourceType::AudioTable), 0);
|
|
|
|
|
|
|
|
loader->RegisterResourceFactory(std::make_shared<SF64::ResourceFactoryBinaryAdpcmBookV0>(), RESOURCE_FORMAT_BINARY,
|
|
|
|
"AdpcmBook", static_cast<uint32_t>(SF64::ResourceType::AdpcmBook), 0);
|
|
|
|
|
|
|
|
loader->RegisterResourceFactory(std::make_shared<SF64::ResourceFactoryBinaryDrumV0>(), RESOURCE_FORMAT_BINARY,
|
|
|
|
"Drum", static_cast<uint32_t>(SF64::ResourceType::Drum), 0);
|
|
|
|
|
|
|
|
loader->RegisterResourceFactory(std::make_shared<SF64::ResourceFactoryBinaryEnvelopeV0>(), RESOURCE_FORMAT_BINARY,
|
|
|
|
"Envelope", static_cast<uint32_t>(SF64::ResourceType::Envelope), 0);
|
|
|
|
|
|
|
|
loader->RegisterResourceFactory(std::make_shared<SF64::ResourceFactoryBinaryInstrumentV0>(), RESOURCE_FORMAT_BINARY,
|
|
|
|
"Instrument", static_cast<uint32_t>(SF64::ResourceType::Instrument), 0);
|
|
|
|
|
|
|
|
loader->RegisterResourceFactory(std::make_shared<SF64::ResourceFactoryBinaryAdpcmLoopV0>(), RESOURCE_FORMAT_BINARY,
|
|
|
|
"AdpcmLoop", static_cast<uint32_t>(SF64::ResourceType::AdpcmLoop), 0);
|
|
|
|
|
|
|
|
loader->RegisterResourceFactory(std::make_shared<SF64::ResourceFactoryBinarySampleV1>(), RESOURCE_FORMAT_BINARY,
|
|
|
|
"Sample", static_cast<uint32_t>(SF64::ResourceType::Sample), 1);
|
2025-02-02 23:34:11 -06:00
|
|
|
|
|
|
|
loader->RegisterResourceFactory(std::make_shared<SF64::ResourceFactoryXMLSampleV0>(), RESOURCE_FORMAT_XML,
|
|
|
|
"Sample", static_cast<uint32_t>(SF64::ResourceType::Sample), 0);
|
2024-11-20 02:01:16 -06:00
|
|
|
|
|
|
|
loader->RegisterResourceFactory(std::make_shared<SF64::ResourceFactoryBinarySoundFontV0>(), RESOURCE_FORMAT_BINARY,
|
|
|
|
"SoundFont", static_cast<uint32_t>(SF64::ResourceType::SoundFont), 0);
|
2024-12-27 23:07:06 -06:00
|
|
|
|
2025-02-03 03:12:20 -06:00
|
|
|
loader->RegisterResourceFactory(std::make_shared<SF64::ResourceFactoryXMLSoundFontV0>(), RESOURCE_FORMAT_XML,
|
|
|
|
"SoundFont", static_cast<uint32_t>(SF64::ResourceType::SoundFont), 0);
|
|
|
|
|
2024-12-27 23:07:06 -06:00
|
|
|
prevAltAssets = CVarGetInteger("gEnhancements.Mods.AlternateAssets", 0);
|
2025-02-01 04:23:51 -03:00
|
|
|
gEnableGammaBoost = CVarGetInteger("gGraphics.GammaMode", 0) == 0;
|
2024-12-27 23:07:06 -06:00
|
|
|
context->GetResourceManager()->SetAltAssetsEnabled(prevAltAssets);
|
2024-11-14 20:23:27 -03:00
|
|
|
}
|
|
|
|
|
2025-03-08 18:36:42 -06:00
|
|
|
bool GameEngine::GenAssetFile(bool exitOnFail) {
|
2025-01-15 15:50:57 -06:00
|
|
|
auto extractor = new GameExtractor();
|
|
|
|
|
|
|
|
if (!extractor->SelectGameFromUI()) {
|
2025-01-15 19:29:43 -06:00
|
|
|
ShowMessage("Error", "No ROM selected.\n\nExiting...");
|
2025-03-08 18:36:42 -06:00
|
|
|
if (exitOnFail) {
|
|
|
|
exit(1);
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
2025-01-15 15:50:57 -06:00
|
|
|
}
|
|
|
|
|
2025-01-15 19:29:43 -06:00
|
|
|
auto game = extractor->ValidateChecksum();
|
|
|
|
if (!game.has_value()) {
|
|
|
|
ShowMessage("Unsupported ROM", "The provided ROM is not supported.\n\nCheck the readme for a list of supported versions.");
|
2025-03-08 18:36:42 -06:00
|
|
|
if (exitOnFail) {
|
|
|
|
exit(1);
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
2025-01-15 15:50:57 -06:00
|
|
|
}
|
2025-01-15 19:29:43 -06:00
|
|
|
|
2025-01-15 19:36:12 -06:00
|
|
|
ShowMessage(("Found " + game.value()).c_str(), "The extraction process will now begin.\n\nThis may take a few minutes.", SDL_MESSAGEBOX_INFORMATION);
|
2025-01-15 19:29:43 -06:00
|
|
|
|
|
|
|
return extractor->GenerateOTR();
|
2025-01-15 15:50:57 -06:00
|
|
|
}
|
|
|
|
|
2024-11-14 20:23:27 -03:00
|
|
|
void GameEngine::Create() {
|
2024-03-24 02:01:28 -06:00
|
|
|
const auto instance = Instance = new GameEngine();
|
2024-10-25 22:39:32 -06:00
|
|
|
instance->AudioInit();
|
2024-11-20 02:01:16 -06:00
|
|
|
DisplayListPatch::Run();
|
2024-03-24 02:01:28 -06:00
|
|
|
GameUI::SetupGuiElements();
|
2024-04-10 17:01:29 -06:00
|
|
|
#if defined(__SWITCH__) || defined(__WIIU__)
|
|
|
|
CVarRegisterInteger("gControlNav", 1); // always enable controller nav on switch/wii u
|
2025-03-05 19:03:20 -06:00
|
|
|
osSetTime(0);
|
2024-04-10 17:01:29 -06:00
|
|
|
#endif
|
2024-12-27 17:46:16 -06:00
|
|
|
PortEnhancements_Init();
|
2024-03-24 02:01:28 -06:00
|
|
|
}
|
|
|
|
|
2024-11-14 20:23:27 -03:00
|
|
|
void GameEngine::Destroy() {
|
2024-12-27 17:46:16 -06:00
|
|
|
PortEnhancements_Exit();
|
2024-11-15 14:48:47 -06:00
|
|
|
AudioExit();
|
2025-01-31 01:02:33 -06:00
|
|
|
for (auto ptr : MemoryPool) {
|
|
|
|
free(ptr);
|
|
|
|
}
|
|
|
|
MemoryPool.clear();
|
2025-03-05 18:31:53 -06:00
|
|
|
#ifdef __SWITCH__
|
|
|
|
Ship::Switch::Exit();
|
|
|
|
#endif
|
2024-03-24 02:01:28 -06:00
|
|
|
}
|
|
|
|
|
2024-11-14 20:23:27 -03:00
|
|
|
void GameEngine::StartFrame() const {
|
2024-05-20 22:29:07 -06:00
|
|
|
using Ship::KbScancode;
|
2024-03-24 02:01:28 -06:00
|
|
|
const int32_t dwScancode = this->context->GetWindow()->GetLastScancode();
|
|
|
|
this->context->GetWindow()->SetLastScancode(-1);
|
|
|
|
|
|
|
|
switch (dwScancode) {
|
|
|
|
case KbScancode::LUS_KB_TAB: {
|
|
|
|
// Toggle HD Assets
|
2024-12-27 23:07:06 -06:00
|
|
|
CVarSetInteger("gEnhancements.Mods.AlternateAssets", !CVarGetInteger("gEnhancements.Mods.AlternateAssets", 0));
|
2024-03-24 02:01:28 -06:00
|
|
|
break;
|
|
|
|
}
|
2025-04-09 23:39:03 -04:00
|
|
|
case KbScancode::LUS_KB_F4: {
|
|
|
|
gNextGameState = GSTATE_BOOT;
|
|
|
|
break;
|
|
|
|
}
|
2024-11-14 20:23:27 -03:00
|
|
|
default:
|
|
|
|
break;
|
2024-03-24 02:01:28 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-31 05:27:37 -03:00
|
|
|
#if 0
|
2024-12-02 15:40:52 -03:00
|
|
|
// Values for 44100 hz
|
2024-11-15 14:48:47 -06:00
|
|
|
#define SAMPLES_HIGH 752
|
|
|
|
#define SAMPLES_LOW 720
|
2024-12-02 15:40:52 -03:00
|
|
|
#else
|
|
|
|
// Values for 32000 hz
|
|
|
|
#define SAMPLES_HIGH 560
|
2024-12-31 05:27:37 -03:00
|
|
|
#define SAMPLES_LOW 528
|
2024-12-02 15:40:52 -03:00
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2025-03-12 14:20:15 +01:00
|
|
|
#define MAX_NUM_AUDIO_CHANNELS 6
|
2024-11-12 20:48:19 -03:00
|
|
|
|
2024-11-15 19:32:24 -03:00
|
|
|
extern "C" u16 audBuffer = 0;
|
2024-11-12 20:48:19 -03:00
|
|
|
#include <sf64audio_provisional.h>
|
|
|
|
|
|
|
|
extern "C" volatile s32 gAudioTaskCountQ;
|
2024-11-14 20:23:27 -03:00
|
|
|
int frames = 0;
|
|
|
|
extern "C" int countermin = 0;
|
2024-11-15 19:32:24 -03:00
|
|
|
|
|
|
|
extern "C" unsigned short samples_high = SAMPLES_HIGH;
|
|
|
|
extern "C" unsigned short samples_low = SAMPLES_LOW;
|
|
|
|
|
2024-11-12 20:48:19 -03:00
|
|
|
void GameEngine::HandleAudioThread() {
|
2024-11-15 14:48:47 -06:00
|
|
|
#ifdef PIPE_DEBUG
|
|
|
|
std::ofstream outfile("audio.bin", std::ios::binary | std::ios::app);
|
|
|
|
#endif
|
2024-10-25 22:39:32 -06:00
|
|
|
while (audio.running) {
|
|
|
|
{
|
|
|
|
std::unique_lock<std::mutex> Lock(audio.mutex);
|
|
|
|
while (!audio.processing && audio.running) {
|
|
|
|
audio.cv_to_thread.wait(Lock);
|
|
|
|
}
|
|
|
|
if (!audio.running) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2024-11-09 20:45:31 -06:00
|
|
|
|
2024-11-15 19:32:24 -03:00
|
|
|
// gVIsPerFrame = 2;
|
2024-11-14 23:53:56 -05:00
|
|
|
|
2024-11-15 14:48:47 -06:00
|
|
|
#define AUDIO_FRAMES_PER_UPDATE (gVIsPerFrame > 0 ? gVIsPerFrame : 1)
|
2025-03-12 14:20:15 +01:00
|
|
|
#define MAX_AUDIO_FRAMES_PER_UPDATE 3 // Compile-time constant with max value of gVIsPerFrame
|
2024-11-14 23:53:56 -05:00
|
|
|
|
2024-10-25 22:39:32 -06:00
|
|
|
std::unique_lock<std::mutex> Lock(audio.mutex);
|
|
|
|
int samples_left = AudioPlayerBuffered();
|
2024-12-31 05:27:37 -03:00
|
|
|
u32 num_audio_samples = samples_left < AudioPlayerGetDesiredBuffered() ? (((samples_high))) : (((samples_low)));
|
2024-11-14 20:23:27 -03:00
|
|
|
|
|
|
|
frames++;
|
|
|
|
|
|
|
|
if (frames > 60) {
|
|
|
|
countermin++;
|
|
|
|
}
|
|
|
|
|
2025-03-12 14:20:15 +01:00
|
|
|
const int32_t num_audio_channels = GetNumAudioChannels();
|
|
|
|
|
|
|
|
s16 audio_buffer[SAMPLES_HIGH * MAX_NUM_AUDIO_CHANNELS * MAX_AUDIO_FRAMES_PER_UPDATE] = { 0 };
|
2024-11-14 23:53:56 -05:00
|
|
|
for (int i = 0; i < AUDIO_FRAMES_PER_UPDATE; i++) {
|
2025-03-12 14:20:15 +01:00
|
|
|
AudioThread_CreateNextAudioBuffer(audio_buffer + i * (num_audio_samples * num_audio_channels),
|
2024-11-14 20:23:27 -03:00
|
|
|
num_audio_samples);
|
2024-10-25 22:39:32 -06:00
|
|
|
}
|
2024-11-15 14:48:47 -06:00
|
|
|
#ifdef PIPE_DEBUG
|
2024-11-15 19:32:24 -03:00
|
|
|
if (outfile.is_open()) {
|
|
|
|
outfile.write(reinterpret_cast<char*>(audio_buffer),
|
2025-03-12 14:20:15 +01:00
|
|
|
num_audio_samples * (sizeof(int16_t) * num_audio_channels * AUDIO_FRAMES_PER_UPDATE));
|
2024-11-15 14:48:47 -06:00
|
|
|
}
|
|
|
|
#endif
|
2024-11-14 20:23:27 -03:00
|
|
|
AudioPlayerPlayFrame((u8*) audio_buffer,
|
2025-03-12 14:20:15 +01:00
|
|
|
num_audio_samples * (sizeof(int16_t) * num_audio_channels * AUDIO_FRAMES_PER_UPDATE));
|
|
|
|
|
2024-10-25 22:39:32 -06:00
|
|
|
audio.processing = false;
|
|
|
|
audio.cv_from_thread.notify_one();
|
|
|
|
}
|
2024-11-15 14:48:47 -06:00
|
|
|
#ifdef PIPE_DEBUG
|
|
|
|
outfile.close();
|
|
|
|
#endif
|
2024-10-25 22:39:32 -06:00
|
|
|
}
|
|
|
|
|
2024-11-14 20:23:27 -03:00
|
|
|
void GameEngine::StartAudioFrame() {
|
2024-10-25 22:39:32 -06:00
|
|
|
{
|
|
|
|
std::unique_lock<std::mutex> Lock(audio.mutex);
|
|
|
|
audio.processing = true;
|
|
|
|
}
|
|
|
|
audio.cv_to_thread.notify_one();
|
|
|
|
}
|
|
|
|
|
2024-11-14 20:23:27 -03:00
|
|
|
void GameEngine::EndAudioFrame() {
|
2024-10-25 22:39:32 -06:00
|
|
|
{
|
|
|
|
std::unique_lock<std::mutex> Lock(audio.mutex);
|
|
|
|
while (audio.processing) {
|
|
|
|
audio.cv_from_thread.wait(Lock);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void GameEngine::AudioInit() {
|
|
|
|
if (!audio.running) {
|
|
|
|
audio.running = true;
|
|
|
|
audio.thread = std::thread(HandleAudioThread);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void GameEngine::AudioExit() {
|
|
|
|
{
|
|
|
|
std::unique_lock lock(audio.mutex);
|
|
|
|
audio.running = false;
|
|
|
|
}
|
|
|
|
audio.cv_to_thread.notify_all();
|
|
|
|
// Wait until the audio thread quit
|
|
|
|
audio.thread.join();
|
|
|
|
}
|
|
|
|
|
2024-10-16 11:53:41 -06:00
|
|
|
void GameEngine::RunCommands(Gfx* Commands, const std::vector<std::unordered_map<Mtx*, MtxF>>& mtx_replacements) {
|
2025-01-15 13:12:00 -06:00
|
|
|
auto wnd = std::dynamic_pointer_cast<Fast::Fast3dWindow>(Ship::Context::GetInstance()->GetWindow());
|
|
|
|
|
|
|
|
if (wnd == nullptr) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Process window events for resize, mouse, keyboard events
|
|
|
|
wnd->HandleEvents();
|
|
|
|
|
2025-03-28 03:25:11 -04:00
|
|
|
gInterpolationIndex = 0;
|
|
|
|
|
2024-10-16 11:53:41 -06:00
|
|
|
for (const auto& m : mtx_replacements) {
|
2025-01-15 13:12:00 -06:00
|
|
|
wnd->DrawAndRunGraphicsCommands(Commands, m);
|
2025-03-28 03:25:11 -04:00
|
|
|
gInterpolationIndex++;
|
2024-10-16 11:53:41 -06:00
|
|
|
}
|
2024-03-24 02:01:28 -06:00
|
|
|
|
2024-12-27 23:07:06 -06:00
|
|
|
bool curAltAssets = CVarGetInteger("gEnhancements.Mods.AlternateAssets", 0);
|
|
|
|
if (prevAltAssets != curAltAssets) {
|
|
|
|
prevAltAssets = curAltAssets;
|
|
|
|
Ship::Context::GetInstance()->GetResourceManager()->SetAltAssetsEnabled(curAltAssets);
|
2024-03-24 02:01:28 -06:00
|
|
|
gfx_texture_cache_clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void GameEngine::ProcessGfxCommands(Gfx* commands) {
|
2024-05-20 22:29:07 -06:00
|
|
|
auto wnd = std::dynamic_pointer_cast<Fast::Fast3dWindow>(Ship::Context::GetInstance()->GetWindow());
|
|
|
|
|
|
|
|
if (wnd == nullptr) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2025-01-16 11:28:47 -06:00
|
|
|
if(gEnableGammaBoost) {
|
|
|
|
wnd->EnableSRGBMode();
|
|
|
|
}
|
2024-05-20 22:29:07 -06:00
|
|
|
wnd->SetRendererUCode(UcodeHandlers::ucode_f3dex);
|
|
|
|
|
2024-10-16 11:53:41 -06:00
|
|
|
std::vector<std::unordered_map<Mtx*, MtxF>> mtx_replacements;
|
2025-04-01 04:38:57 +02:00
|
|
|
int target_fps = GameEngine::Instance->GetInterpolationFPS();
|
2024-10-16 11:53:41 -06:00
|
|
|
static int last_fps;
|
|
|
|
static int last_update_rate;
|
|
|
|
static int time;
|
|
|
|
int fps = target_fps;
|
2024-11-27 04:36:13 -03:00
|
|
|
int original_fps = 60 / gVIsPerFrame;
|
2024-10-16 11:53:41 -06:00
|
|
|
|
|
|
|
if (target_fps == 20 || original_fps > target_fps) {
|
|
|
|
fps = original_fps;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (last_fps != fps || last_update_rate != gVIsPerFrame) {
|
|
|
|
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) {
|
2024-11-14 20:23:27 -03:00
|
|
|
mtx_replacements.push_back(FrameInterpolation_Interpolate((float) time / next_original_frame));
|
2024-10-16 11:53:41 -06:00
|
|
|
} else {
|
|
|
|
mtx_replacements.emplace_back();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
time -= fps;
|
|
|
|
|
|
|
|
if (wnd != nullptr) {
|
|
|
|
wnd->SetTargetFps(fps);
|
2025-04-01 04:38:57 +02:00
|
|
|
wnd->SetMaximumFrameLatency(CVarGetInteger("gRenderParallelization", 0) ? 2 : 1);
|
2024-10-16 11:53:41 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// When the gfx debugger is active, only run with the final mtx
|
|
|
|
if (GfxDebuggerIsDebugging()) {
|
|
|
|
mtx_replacements.clear();
|
|
|
|
mtx_replacements.emplace_back();
|
|
|
|
}
|
|
|
|
|
|
|
|
RunCommands(commands, mtx_replacements);
|
|
|
|
|
|
|
|
last_fps = fps;
|
|
|
|
last_update_rate = gVIsPerFrame;
|
|
|
|
}
|
|
|
|
|
2024-11-14 20:23:27 -03:00
|
|
|
uint32_t GameEngine::GetInterpolationFPS() {
|
2024-10-16 11:53:41 -06:00
|
|
|
if (CVarGetInteger("gMatchRefreshRate", 0)) {
|
|
|
|
return Ship::Context::GetInstance()->GetWindow()->GetCurrentRefreshRate();
|
2025-04-01 04:38:57 +02:00
|
|
|
|
|
|
|
} else if (CVarGetInteger("gVsyncEnabled", 1) ||
|
|
|
|
!Ship::Context::GetInstance()->GetWindow()->CanDisableVerticalSync()) {
|
|
|
|
return std::min<uint32_t>(Ship::Context::GetInstance()->GetWindow()->GetCurrentRefreshRate(),
|
|
|
|
CVarGetInteger("gInterpolationFPS", 60));
|
2024-10-16 11:53:41 -06:00
|
|
|
}
|
|
|
|
|
2025-04-01 04:38:57 +02:00
|
|
|
return CVarGetInteger("gInterpolationFPS", 60);
|
2024-03-24 02:01:28 -06:00
|
|
|
}
|
|
|
|
|
2025-03-28 03:25:11 -04:00
|
|
|
uint32_t GameEngine::GetInterpolationFrameCount()
|
|
|
|
{
|
2025-04-05 23:53:25 -04:00
|
|
|
return ceil((float)GetInterpolationFPS() / (60.0f / gVIsPerFrame));
|
2025-03-28 03:25:11 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" uint32_t GameEngine_GetInterpolationFrameCount() {
|
|
|
|
return GameEngine::GetInterpolationFrameCount();
|
|
|
|
}
|
|
|
|
|
2025-01-15 19:36:12 -06:00
|
|
|
void GameEngine::ShowMessage(const char* title, const char* message, SDL_MessageBoxFlags type) {
|
2025-01-15 15:50:57 -06:00
|
|
|
#if defined(__SWITCH__)
|
|
|
|
SPDLOG_ERROR(message);
|
|
|
|
#else
|
2025-01-15 19:36:12 -06:00
|
|
|
SDL_ShowSimpleMessageBox(type, title, message, nullptr);
|
2025-01-15 15:50:57 -06:00
|
|
|
SPDLOG_ERROR(message);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2025-01-15 19:29:43 -06:00
|
|
|
int GameEngine::ShowYesNoBox(const char* title, const char* box) {
|
|
|
|
int ret;
|
|
|
|
#ifdef _WIN32
|
|
|
|
ret = MessageBoxA(nullptr, box, title, MB_YESNO | MB_ICONQUESTION);
|
2025-03-07 18:13:03 -06:00
|
|
|
#elif defined(__SWITCH__)
|
|
|
|
SPDLOG_ERROR(box);
|
|
|
|
return IDYES;
|
2025-01-15 19:29:43 -06:00
|
|
|
#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;
|
|
|
|
}
|
|
|
|
|
2025-01-31 18:20:12 -06:00
|
|
|
bool GameEngine::HasVersion(SF64Version ver){
|
|
|
|
auto versions = Ship::Context::GetInstance()->GetResourceManager()->GetArchiveManager()->GetGameVersions();
|
|
|
|
return std::find(versions.begin(), versions.end(), ver) != versions.end();
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" bool GameEngine_HasVersion(SF64Version ver) {
|
|
|
|
return GameEngine::HasVersion(ver);
|
|
|
|
}
|
|
|
|
|
2024-03-24 02:01:28 -06:00
|
|
|
extern "C" uint32_t GameEngine_GetSampleRate() {
|
2024-05-20 22:29:07 -06:00
|
|
|
auto player = Ship::Context::GetInstance()->GetAudio()->GetAudioPlayer();
|
2024-03-24 02:01:28 -06:00
|
|
|
if (player == nullptr) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!player->IsInitialized()) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return player->GetSampleRate();
|
|
|
|
}
|
|
|
|
|
2024-11-14 20:23:27 -03:00
|
|
|
extern "C" uint32_t GameEngine_GetSamplesPerFrame() {
|
2024-03-24 02:01:28 -06:00
|
|
|
return SAMPLES_PER_FRAME;
|
|
|
|
}
|
|
|
|
|
|
|
|
// End
|
|
|
|
|
|
|
|
extern "C" float GameEngine_GetAspectRatio() {
|
|
|
|
return gfx_current_dimensions.aspect_ratio;
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" uint32_t GameEngine_GetGameVersion() {
|
|
|
|
return 0x00000001;
|
|
|
|
}
|
|
|
|
|
2024-04-07 18:01:42 -06:00
|
|
|
static const char* sOtrSignature = "__OTR__";
|
|
|
|
|
|
|
|
extern "C" uint8_t GameEngine_OTRSigCheck(const char* data) {
|
2024-11-14 20:23:27 -03:00
|
|
|
if (data == nullptr) {
|
2024-04-07 18:01:42 -06:00
|
|
|
return 0;
|
|
|
|
}
|
2024-03-24 02:01:28 -06:00
|
|
|
return strncmp(data, sOtrSignature, strlen(sOtrSignature)) == 0;
|
2024-04-01 23:13:52 -06:00
|
|
|
}
|
|
|
|
|
2025-02-02 01:05:35 -06:00
|
|
|
extern "C" void GameEngine_GetTextureInfo(const char* path, int32_t* width, int32_t* height, float* scale, bool* custom) {
|
|
|
|
if(GameEngine_OTRSigCheck(path) != 1){
|
|
|
|
*custom = false;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
std::shared_ptr<Fast::Texture> tex = std::static_pointer_cast<Fast::Texture>(
|
|
|
|
Ship::Context::GetInstance()->GetResourceManager()->LoadResourceProcess(path));
|
|
|
|
*width = tex->Width;
|
|
|
|
*height = tex->Height;
|
|
|
|
*scale = tex->VPixelScale;
|
|
|
|
*custom = tex->Flags & (1 << 0);
|
|
|
|
}
|
|
|
|
|
2024-12-21 23:49:14 +01:00
|
|
|
extern "C" float __cosf(float angle) throw() {
|
2024-04-09 12:49:20 -06:00
|
|
|
return cosf(angle);
|
2024-04-03 09:57:24 -06:00
|
|
|
}
|
|
|
|
|
2024-12-21 23:49:14 +01:00
|
|
|
extern "C" float __sinf(float angle) throw() {
|
2024-04-09 12:49:20 -06:00
|
|
|
return sinf(angle);
|
2024-04-03 09:57:24 -06:00
|
|
|
}
|
|
|
|
|
2024-04-01 23:13:52 -06:00
|
|
|
extern "C" float SIN_DEG(float angle) {
|
2024-04-03 09:58:56 -06:00
|
|
|
return __sinf(M_DTOR * angle);
|
2024-04-01 23:13:52 -06:00
|
|
|
}
|
|
|
|
extern "C" float COS_DEG(float angle) {
|
2024-04-03 09:58:56 -06:00
|
|
|
return __cosf(M_DTOR * angle);
|
2024-04-01 23:13:52 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
struct TimedEntry {
|
|
|
|
uint64_t duration;
|
|
|
|
TimerAction action;
|
|
|
|
int32_t* address;
|
|
|
|
int32_t value;
|
|
|
|
bool active;
|
|
|
|
};
|
|
|
|
|
|
|
|
std::vector<TimedEntry> gTimerTasks;
|
|
|
|
|
|
|
|
uint64_t Timer_GetCurrentMillis() {
|
|
|
|
return SDL_GetTicks();
|
|
|
|
}
|
|
|
|
|
2024-04-09 12:49:20 -06:00
|
|
|
extern "C" s32 Timer_CreateTask(u64 time, TimerAction action, s32* address, s32 value) {
|
2024-04-01 23:13:52 -06:00
|
|
|
const auto millis = Timer_GetCurrentMillis();
|
|
|
|
TimedEntry entry = {
|
|
|
|
.duration = millis + CYCLES_TO_MSEC_PC(time),
|
|
|
|
.action = action,
|
|
|
|
.address = address,
|
|
|
|
.value = value,
|
|
|
|
.active = true,
|
|
|
|
};
|
|
|
|
|
|
|
|
gTimerTasks.push_back(entry);
|
|
|
|
|
|
|
|
return gTimerTasks.size() - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" void Timer_Increment(int32_t* address, int32_t value) {
|
|
|
|
*address += value;
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" void Timer_SetValue(int32_t* address, int32_t value) {
|
|
|
|
*address = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Timer_CompleteTask(TimedEntry& task) {
|
|
|
|
if (task.action != nullptr) {
|
|
|
|
task.action(task.address, task.value);
|
|
|
|
}
|
|
|
|
task.active = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" void Timer_Update() {
|
|
|
|
|
2024-11-14 20:23:27 -03:00
|
|
|
if (gTimerTasks.empty()) {
|
2024-04-01 23:13:52 -06:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const auto millis = Timer_GetCurrentMillis();
|
|
|
|
|
|
|
|
for (auto& task : gTimerTasks) {
|
|
|
|
if (task.active && millis >= task.duration) {
|
|
|
|
Timer_CompleteTask(task);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-05-27 15:27:19 -06:00
|
|
|
|
|
|
|
// Gets the width of the main ImGui window
|
|
|
|
extern "C" uint32_t OTRGetCurrentWidth() {
|
|
|
|
return GameEngine::Instance->context->GetWindow()->GetWidth();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Gets the height of the main ImGui window
|
|
|
|
extern "C" uint32_t OTRGetCurrentHeight() {
|
|
|
|
return GameEngine::Instance->context->GetWindow()->GetHeight();
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" float OTRGetAspectRatio() {
|
|
|
|
return gfx_current_dimensions.aspect_ratio;
|
|
|
|
}
|
|
|
|
|
2025-01-12 20:15:37 -03:00
|
|
|
extern "C" float OTRGetHUDAspectRatio() {
|
|
|
|
if (CVarGetInteger("gHUDAspectRatio.Enabled", 0) == 0 || CVarGetInteger("gHUDAspectRatio.X", 0) == 0 || CVarGetInteger("gHUDAspectRatio.Y", 0) == 0)
|
|
|
|
{
|
|
|
|
return OTRGetAspectRatio();
|
|
|
|
}
|
|
|
|
return ((float)CVarGetInteger("gHUDAspectRatio.X", 1) / (float)CVarGetInteger("gHUDAspectRatio.Y", 1));
|
|
|
|
}
|
|
|
|
|
2024-05-27 15:27:19 -06:00
|
|
|
extern "C" float OTRGetDimensionFromLeftEdge(float v) {
|
|
|
|
return (gfx_native_dimensions.width / 2 - gfx_native_dimensions.height / 2 * OTRGetAspectRatio() + (v));
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" float OTRGetDimensionFromRightEdge(float v) {
|
|
|
|
return (gfx_native_dimensions.width / 2 + gfx_native_dimensions.height / 2 * OTRGetAspectRatio() -
|
|
|
|
(gfx_native_dimensions.width - v));
|
|
|
|
}
|
|
|
|
|
2025-01-11 11:17:45 -03:00
|
|
|
extern "C" float OTRGetDimensionFromLeftEdgeForcedAspect(float v, float aspectRatio) {
|
|
|
|
return (gfx_native_dimensions.width / 2 - gfx_native_dimensions.height / 2 * (aspectRatio > 0 ? aspectRatio : OTRGetAspectRatio()) + (v));
|
2025-01-11 10:40:25 -03:00
|
|
|
}
|
|
|
|
|
2025-01-11 11:17:45 -03:00
|
|
|
extern "C" float OTRGetDimensionFromRightEdgeForcedAspect(float v, float aspectRatio) {
|
|
|
|
return (gfx_native_dimensions.width / 2 + gfx_native_dimensions.height / 2 * (aspectRatio > 0 ? aspectRatio : OTRGetAspectRatio()) -
|
2025-01-11 10:40:25 -03:00
|
|
|
(gfx_native_dimensions.width - v));
|
|
|
|
}
|
2025-01-12 20:15:37 -03:00
|
|
|
|
|
|
|
extern "C" float OTRGetDimensionFromLeftEdgeOverride(float v) {
|
|
|
|
return OTRGetDimensionFromLeftEdgeForcedAspect(v, OTRGetHUDAspectRatio());
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" float OTRGetDimensionFromRightEdgeOverride(float v) {
|
|
|
|
return OTRGetDimensionFromRightEdgeForcedAspect(v, OTRGetHUDAspectRatio());
|
|
|
|
}
|
|
|
|
|
2024-05-27 15:27:19 -06:00
|
|
|
// Gets the width of the current render target area
|
|
|
|
extern "C" uint32_t OTRGetGameRenderWidth() {
|
|
|
|
return gfx_current_dimensions.width;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Gets the height of the current render target area
|
|
|
|
extern "C" uint32_t OTRGetGameRenderHeight() {
|
|
|
|
return gfx_current_dimensions.height;
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" int16_t OTRGetRectDimensionFromLeftEdge(float v) {
|
2024-11-14 20:23:27 -03:00
|
|
|
return ((int) floorf(OTRGetDimensionFromLeftEdge(v)));
|
2024-05-27 15:27:19 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" int16_t OTRGetRectDimensionFromRightEdge(float v) {
|
2024-11-14 20:23:27 -03:00
|
|
|
return ((int) ceilf(OTRGetDimensionFromRightEdge(v)));
|
2024-10-23 11:21:03 -03:00
|
|
|
}
|
|
|
|
|
2025-01-11 11:17:45 -03:00
|
|
|
extern "C" int16_t OTRGetRectDimensionFromLeftEdgeForcedAspect(float v, float aspectRatio) {
|
|
|
|
return ((int) floorf(OTRGetDimensionFromLeftEdgeForcedAspect(v, aspectRatio)));
|
2025-01-11 10:40:25 -03:00
|
|
|
}
|
|
|
|
|
2025-01-11 11:17:45 -03:00
|
|
|
extern "C" int16_t OTRGetRectDimensionFromRightEdgeForcedAspect(float v, float aspectRatio) {
|
|
|
|
return ((int) ceilf(OTRGetDimensionFromRightEdgeForcedAspect(v, aspectRatio)));
|
2025-01-11 10:40:25 -03:00
|
|
|
}
|
|
|
|
|
2025-01-12 20:15:37 -03:00
|
|
|
extern "C" int16_t OTRGetRectDimensionFromLeftEdgeOverride(float v) {
|
|
|
|
return OTRGetRectDimensionFromLeftEdgeForcedAspect(v, OTRGetHUDAspectRatio());
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" int16_t OTRGetRectDimensionFromRightEdgeOverride(float v) {
|
|
|
|
return OTRGetRectDimensionFromRightEdgeForcedAspect(v, OTRGetHUDAspectRatio());
|
|
|
|
}
|
|
|
|
|
2024-10-23 11:21:03 -03:00
|
|
|
extern "C" int32_t OTRConvertHUDXToScreenX(int32_t v) {
|
|
|
|
float gameAspectRatio = gfx_current_dimensions.aspect_ratio;
|
|
|
|
int32_t gameHeight = gfx_current_dimensions.height;
|
|
|
|
int32_t gameWidth = gfx_current_dimensions.width;
|
|
|
|
float hudAspectRatio = 4.0f / 3.0f;
|
|
|
|
int32_t hudHeight = gameHeight;
|
|
|
|
int32_t hudWidth = hudHeight * hudAspectRatio;
|
|
|
|
float hudScreenRatio = (hudWidth / 320.0f);
|
|
|
|
float hudCoord = v * hudScreenRatio;
|
|
|
|
float gameOffset = (gameWidth - hudWidth) / 2;
|
|
|
|
float gameCoord = hudCoord + gameOffset;
|
|
|
|
float gameScreenRatio = (320.0f / gameWidth);
|
|
|
|
float screenScaledCoord = gameCoord * gameScreenRatio;
|
|
|
|
int32_t screenScaledCoordInt = screenScaledCoord;
|
|
|
|
return screenScaledCoordInt;
|
2024-10-29 02:06:14 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" void* GameEngine_Malloc(size_t size) {
|
2025-01-31 01:02:33 -06:00
|
|
|
MemoryPool.push_back(new uint8_t[size]);
|
|
|
|
return (void*) MemoryPool.back();
|
|
|
|
}
|
2024-10-29 02:06:14 -06:00
|
|
|
|
2025-01-31 01:02:33 -06:00
|
|
|
extern "C" void GameEngine_Free(void* ptr) {
|
|
|
|
for (auto it = MemoryPool.begin(); it != MemoryPool.end(); ++it) {
|
|
|
|
if (*it == ptr) {
|
|
|
|
free(ptr);
|
|
|
|
MemoryPool.erase(it);
|
|
|
|
break;
|
|
|
|
}
|
2024-10-29 02:06:14 -06:00
|
|
|
}
|
2024-05-27 15:27:19 -06:00
|
|
|
}
|