JKSV/Source/JKSV.cpp

182 lines
5.5 KiB
C++

#include "JKSV.hpp"
#include "AppStates/MainMenuState.hpp"
#include "Colors.hpp"
#include "Config.hpp"
#include "Data/Data.hpp"
#include "FsLib.hpp"
#include "Input.hpp"
#include "Logger.hpp"
#include "SDL.hpp"
#include "Strings.hpp"
#include <switch.h>
#define ABORT_ON_FAILURE(x) \
if (!x) \
{ \
return; \
}
namespace
{
constexpr uint8_t BUILD_MON = 12;
constexpr uint8_t BUILD_DAY = 9;
constexpr uint16_t BUILD_YEAR = 2024;
} // namespace
template <typename... Args>
static bool InitializeService(Result (*Function)(Args...), const char *ServiceName, Args... Arguments)
{
Result Error = (*Function)(Arguments...);
if (R_FAILED(Error))
{
Logger::Log("Error initializing %s: 0x%X.", Error);
return false;
}
return true;
}
JKSV::JKSV(void)
{
// FsLib
ABORT_ON_FAILURE(FsLib::Initialize());
// This doesn't really on stdio or anything.
Logger::Initialize();
// Need to init RomFS here for now until I update FsLib to take care of this.
ABORT_ON_FAILURE(InitializeService(romfsInit, "RomFS"));
// Let FsLib take care of calls to SDMC instead of fs_dev
ABORT_ON_FAILURE(FsLib::Dev::InitializeSDMC());
// SDL
ABORT_ON_FAILURE(SDL::Initialize("JKSV", 1280, 720));
ABORT_ON_FAILURE(SDL::Text::Initialize());
// Services.
// Using administrator so JKSV can still run in Applet mode.
ABORT_ON_FAILURE(InitializeService(accountInitialize, "Account", AccountServiceType_Administrator));
ABORT_ON_FAILURE(InitializeService(nsInitialize, "NS"));
ABORT_ON_FAILURE(InitializeService(pdmqryInitialize, "PDMQry"));
ABORT_ON_FAILURE(InitializeService(plInitialize, "PL", PlServiceType_User));
ABORT_ON_FAILURE(InitializeService(pmshellInitialize, "PMShell"));
ABORT_ON_FAILURE(InitializeService(setInitialize, "Set"));
ABORT_ON_FAILURE(InitializeService(setsysInitialize, "SetSys"));
ABORT_ON_FAILURE(InitializeService(socketInitializeDefault, "Socket"));
// Input doesn't have anything to return.
Input::Initialize();
// Neither does config.
Config::Initialize();
// JKSV also has no internal strings anymore. This is FATAL now.
ABORT_ON_FAILURE(Strings::Initialize());
if (!Data::Initialize())
{
return;
}
// Install/setup our color changing characters.
SDL::Text::AddColorCharacter(L'#', Colors::Blue);
SDL::Text::AddColorCharacter(L'*', Colors::Red);
SDL::Text::AddColorCharacter(L'<', Colors::Yellow);
SDL::Text::AddColorCharacter(L'>', Colors::Green);
// This is to check whether the author wanted credit for their work.
m_ShowTranslationInfo = std::char_traits<char>::compare(Strings::GetByName(Strings::Names::TranslationInfo, 1), "NULL", 4) != 0;
// This can't be in an initializer list because it needs SDL initialized.
m_HeaderIcon = SDL::TextureManager::CreateLoadTexture("HeaderIcon", "romfs:/Textures/HeaderIcon.png");
// Push initial main menu state.
JKSV::PushState(std::make_shared<MainMenuState>());
m_IsRunning = true;
}
JKSV::~JKSV()
{
socketExit();
setsysExit();
setExit();
pmshellExit();
plExit();
pdmqryExit();
nsExit();
accountExit();
SDL::Text::Exit();
SDL::Exit();
FsLib::Exit();
}
bool JKSV::IsRunning(void) const
{
return m_IsRunning;
}
void JKSV::Update(void)
{
Input::Update();
if (Input::ButtonPressed(HidNpadButton_Plus))
{
m_IsRunning = false;
}
if (!m_StateVector.empty())
{
while (!m_StateVector.back()->IsActive())
{
m_StateVector.back()->TakeFocus();
m_StateVector.pop_back();
m_StateVector.back()->GiveFocus();
}
m_StateVector.back()->Update();
}
}
void JKSV::Render(void)
{
SDL::FrameBegin(Colors::ClearColor);
// Top and bottom divider lines.
SDL::RenderLine(NULL, 30, 88, 1250, 88, Colors::White);
SDL::RenderLine(NULL, 30, 648, 1250, 648, Colors::White);
// Icon
m_HeaderIcon->Render(NULL, 66, 27);
// "JKSV"
SDL::Text::Render(NULL, 130, 32, 34, SDL::Text::NO_TEXT_WRAP, Colors::White, "JKSV");
// Translation info in bottom left.
if (m_ShowTranslationInfo)
{
SDL::Text::Render(NULL,
8,
680,
14,
SDL::Text::NO_TEXT_WRAP,
Colors::White,
Strings::GetByName(Strings::Names::TranslationInfo, 0),
Strings::GetByName(Strings::Names::TranslationInfo, 1));
}
if (!m_StateVector.empty())
{
for (auto &CurrentState : m_StateVector)
{
CurrentState->Render();
}
}
SDL::Text::Render(NULL, 8, 700, 14, SDL::Text::NO_TEXT_WRAP, Colors::White, "v. %02d.%02d.%04d", BUILD_MON, BUILD_DAY, BUILD_YEAR);
SDL::FrameEnd();
}
void JKSV::PushState(std::shared_ptr<AppState> NewState)
{
if (!m_StateVector.empty())
{
m_StateVector.back()->TakeFocus();
}
NewState->GiveFocus();
m_StateVector.push_back(NewState);
}