Files
pico-launcher/arm9/source/App.cpp
2025-11-25 17:41:31 +01:00

520 lines
16 KiB
C++

#include "common.h"
#include <algorithm>
#include <libtwl/mem/memVram.h>
#include <libtwl/gfx/gfx.h>
#include <libtwl/gfx/gfxOam.h>
#include <libtwl/gfx/gfxPalette.h>
#include <libtwl/gfx/gfxBackground.h>
#include <libtwl/gfx/gfxStatus.h>
#include <libtwl/gfx/gfx3d.h>
#include <libtwl/gfx/gfx3dCmd.h>
#include <libtwl/sys/sysPower.h>
#include "animation/Animator.h"
#include "gui/materialDesign.h"
#include "themes/material/MaterialColorSchemeFactory.h"
#include "core/math/ColorConverter.h"
#include "core/math/RgbMixer.h"
#include "gui/GraphicsContext.h"
#include "romBrowser/views/ChipView.h"
#include "picoLoaderBootstrap.h"
#include "romBrowser/DisplayMode/RomBrowserDisplayModeFactory.h"
#include "romBrowser/Theme/Material/MaterialThemeFileIconFactory.h"
#include "romBrowser/views/NdsGameDetailsBottomSheetView.h"
#include "romBrowser/views/DisplaySettingsBottomSheetView.h"
#include "bgm/AudioStreamPlayer.h"
#include "bgm/BgmService.h"
#include "themes/ThemeInfoFactory.h"
#include "themes/ThemeFactory.h"
#include "gui/Gx.h"
#include "splashTop.h"
#include "App.h"
#define SPLASH_FRAMES 44
App::App(IAppSettingsService& appSettingsService, IBgmService& bgmService)
: _mainObjPltt(GFX_PLTT_OBJ_MAIN)
, _mainObjVram(GFX_OBJ_MAIN)
, _mainObjDialogVram(GFX_OBJ_MAIN, 128 * 1024)
, _subObjVram(GFX_OBJ_SUB)
, _textureVram((vu16*)0x06860000)
, _texturePaletteVram((vu16*)0x6880000)
, _mainVramContext(nullptr, &_mainObjVram, &_textureVram, &_texturePaletteVram)
, _subVramContext(nullptr, &_subObjVram, nullptr, nullptr)
, _appSettingsService(appSettingsService)
, _bgmService(bgmService)
, _inputProvider(&_inputSource)
, _inputRepeater(&_inputProvider,
InputKey::DpadLeft | InputKey::DpadRight | InputKey::DpadUp | InputKey::DpadDown,
25, 8)
, _romBrowserController(&appSettingsService, &_ioTaskQueue, &_bgTaskQueue)
, _displaySettingsBottomSheetViewModel(&_romBrowserController)
, _romBrowserBottomScreenViewModel(&_romBrowserController)
, _dialogPresenter(&_focusManager, &_mainObjDialogVram) { }
void App::InitVramMapping() const
{
mem_setVramAMapping(MEM_VRAM_AB_TEX_SLOT_1);
mem_setVramBMapping(MEM_VRAM_AB_MAIN_OBJ_00000);
mem_setVramCMapping(MEM_VRAM_C_SUB_BG_00000);
mem_setVramDMapping(MEM_VRAM_D_TEX_SLOT_0);
mem_setVramEMapping(MEM_VRAM_E_TEX_PLTT_SLOT_0123);
mem_setVramFMapping(MEM_VRAM_FG_MAIN_BG_00000);
mem_setVramGMapping(MEM_VRAM_FG_MAIN_BG_04000);
mem_setVramHMapping(MEM_VRAM_H_SUB_BG_EXT_PLTT_SLOT_0123);
mem_setVramIMapping(MEM_VRAM_I_SUB_OBJ_00000);
}
void App::DisplaySplashScreen() const
{
dma_ntrCopy32(3, splashTopTiles, GFX_BG_SUB, splashTopTilesLen);
dma_ntrCopy32(3, splashTopMap, (u8*)GFX_BG_SUB + 0x3000, splashTopMapLen);
mem_setVramHMapping(MEM_VRAM_H_LCDC);
dma_ntrCopy32(3, splashTopPal, (void*)0x0689A000, splashTopPalLen);
mem_setVramHMapping(MEM_VRAM_H_SUB_BG_EXT_PLTT_SLOT_0123);
VBlank::Wait();
sys_setMainEngineToBottomScreen();
REG_DISPCNT_SUB = 0x40211015;
REG_BG1HOFS_SUB = 0;
REG_BG1VOFS_SUB = 0;
REG_BG1CNT_SUB = 0x0680;
REG_DISPCNT_SUB |= 1 << 9;
REG_BLDCNT_SUB = 0x3D42;
REG_BLDALPHA_SUB = 0x10;
REG_MASTER_BRIGHT_SUB = 0;
}
void App::LoadTheme()
{
ThemeInfoFactory themeInfoFactory;
auto themeInfo = themeInfoFactory.CreateFromThemeFolder(_appSettingsService.GetAppSettings().theme);
if (!themeInfo)
{
LOG_DEBUG("Failed to load theme '%s'. Using fallback theme.\n", _appSettingsService.GetAppSettings().theme.GetString());
themeInfo = themeInfoFactory.CreateFallbackTheme();
}
_theme = ThemeFactory().CreateFromThemeInfo(themeInfo.get());
themeInfo.reset();
_theme->LoadRomBrowserResources(_mainVramContext, _subVramContext);
_topBackground = _theme->CreateRomBrowserTopBackground();
_topBackground->LoadResources(*_theme, _subVramContext);
_bottomBackground = _theme->CreateRomBrowserBottomBackground();
_bottomBackground->LoadResources(*_theme, _mainVramContext);
_materialThemeFileIconFactory = std::make_unique<MaterialThemeFileIconFactory>(
&_theme->GetMaterialColorScheme(), _theme->GetFontRepository());
}
void App::VCountIrq()
{
_mainObjPltt.VCount();
}
void App::Run()
{
InitVramMapping();
DisplaySplashScreen();
gx_init();
_chipViewVram = ChipView::UploadGraphics(_mainObjVram);
_iconButtonViewVram = IconButton2DView::UploadGraphics(_mainObjVram);
mem_setVramEMapping(MEM_VRAM_E_LCDC);
_rgb6Palette.UploadGraphics(_mainVramContext);
mem_setVramEMapping(MEM_VRAM_E_TEX_PLTT_SLOT_0123);
_dialogPresenter.InitVram();
LoadTheme();
_ioTaskQueue.StartThread(1, _ioTaskThreadStack, sizeof(_ioTaskThreadStack));
_bgTaskQueue.StartThread(2, _bgTaskThreadStack, sizeof(_bgTaskThreadStack));
StoreVramState(_vramStateBeforeMakeBottomScreenView);
_romBrowserBottomScreenView = std::make_unique<RomBrowserBottomScreenView>(
&_romBrowserBottomScreenViewModel,
RomBrowserDisplayModeFactory().GetRomBrowserDisplayMode(
_romBrowserController.GetRomBrowserDisplaySettings().layout),
_materialThemeFileIconFactory.get(),
_theme->GetRomBrowserViewFactory(),
&_vblankTextureLoader);
_romBrowserBottomScreenView->InitVram(_mainVramContext);
StoreVramState(_vramStateAfterMakeBottomScreenView);
const auto& materialColorScheme = _theme->GetMaterialColorScheme();
auto scrimBlendColor = Rgb<8, 8, 8>(
materialColorScheme.inverseOnSurface.r + (materialColorScheme.scrim.r - materialColorScheme.inverseOnSurface.r) * 5 / 16,
materialColorScheme.inverseOnSurface.g + (materialColorScheme.scrim.g - materialColorScheme.inverseOnSurface.g) * 5 / 16,
materialColorScheme.inverseOnSurface.b + (materialColorScheme.scrim.b - materialColorScheme.inverseOnSurface.b) * 5 / 16);
RgbMixer::MakeGradientPalette((u16*)GFX_PLTT_BG_MAIN, scrimBlendColor, materialColorScheme.GetColor(md::sys::color::surfaceContainerLow));
GFX_PLTT_BG_MAIN[0] = ColorConverter::ToGBGR565(materialColorScheme.inverseOnSurface);
GFX_PLTT_BG_MAIN[31] = ColorConverter::ToGBGR565(materialColorScheme.scrim);
REG_DISPCNT = 0x211F1B;
REG_BG0HOFS = 0;
REG_BG0VOFS = 0;
REG_BG0CNT = 3;
Gx::MtxMode(GX_MTX_MODE_PROJECTION);
mtx43_t orthoMtx =
{
2048, 0, 0,
0, -21845, 0,
0, 0, 4096 >> 5,
-4096, 4096, 0
};
Gx::MtxLoad43(&orthoMtx);
_vcountIrqStarted = false;
rtos_disableIrqMask(RTOS_IRQ_VCOUNT);
rtos_setIrqFunc(RTOS_IRQ_VCOUNT, [] (u32 mask) { ((App*)gProcessManager.GetRunningProcess())->VCountIrq(); });
LOG_DEBUG("Amount of main obj vram used: %d\n", _mainObjVram.GetState());
_ioTaskQueue.Enqueue([this] (const vu8& cancelRequested)
{
_bgmService.StartBgmFromConfig();
return TaskResult<void>::Completed();
});
_fadeAnimator = Animator(16, 0, 16, &md::sys::motion::easing::linear);
MainLoop();
_bgmService.StopBgm();
rtos_disableIrqMask(RTOS_IRQ_VCOUNT);
rtos_setIrqFunc(RTOS_IRQ_VCOUNT, nullptr);
}
void App::MainLoop()
{
bool fadeIn = true;
int fadeWaitFrames = SPLASH_FRAMES;
while (true)
{
Update();
Draw();
VBlank::Wait();
VBlank();
if (_exit)
{
bool fadeComplete = _fadeAnimator.Update();
REG_MASTER_BRIGHT = 0x4000 | _fadeAnimator.GetValue();
REG_MASTER_BRIGHT_SUB = 0x4000 | _fadeAnimator.GetValue();
if (fadeComplete)
{
break;
}
}
else if (fadeIn)
{
if (fadeWaitFrames)
{
fadeWaitFrames--;
REG_BLDALPHA_SUB = 16;
REG_MASTER_BRIGHT = 0x4010;
}
else
{
bool fadeComplete = _fadeAnimator.Update();
if (fadeComplete)
{
fadeIn = false;
REG_BLDCNT_SUB = 0;
REG_DISPCNT_SUB &= ~(1 << 9);
REG_MASTER_BRIGHT = 0;
}
else
{
int fade = _fadeAnimator.GetValue();
REG_BLDALPHA_SUB = ((16 - fade) << 8) | fade;
REG_MASTER_BRIGHT = 0x4000 | fade;
}
}
}
}
}
void App::Exit()
{
_fadeAnimator.Goto(16, 16, &md::sys::motion::easing::linear);
_exit = true;
}
void App::HandleTrigger(RomBrowserStateTrigger trigger, RomBrowserState newState)
{
switch (trigger)
{
case RomBrowserStateTrigger::None:
case RomBrowserStateTrigger::Launch:
{
break;
}
case RomBrowserStateTrigger::ShowGameInfo:
{
HandleShowGameInfoTrigger();
break;
}
case RomBrowserStateTrigger::HideGameInfo:
{
HandleHideGameInfoTrigger();
break;
}
case RomBrowserStateTrigger::ShowDisplaySettings:
{
HandleShowDisplaySettingsTrigger();
break;
}
case RomBrowserStateTrigger::HideDisplaySettings:
{
HandleHideDisplaySettingsTrigger();
break;
}
case RomBrowserStateTrigger::Navigate:
{
HandleNavigateTrigger();
break;
}
case RomBrowserStateTrigger::FolderLoadDone:
{
HandleFolderLoadDoneTrigger();
break;
}
case RomBrowserStateTrigger::ChangeDisplayMode:
{
_changeDisplayMode = true;
break;
}
}
}
void App::HandleShowGameInfoTrigger()
{
auto gameInfoDialog = std::make_unique<NdsGameDetailsBottomSheetView>(
&_romBrowserController, &_theme->GetMaterialColorScheme(), _theme->GetFontRepository());
gameInfoDialog->SetGraphics(_chipViewVram);
_dialogPresenter.ShowDialog(std::move(gameInfoDialog));
}
void App::HandleHideGameInfoTrigger()
{
_dialogPresenter.CloseDialog();
if (!_dialogPresenter.GetOldFocus())
_romBrowserBottomScreenView->Focus(_focusManager);
}
void App::HandleShowDisplaySettingsTrigger()
{
auto displaySettingsDialog = std::make_unique<DisplaySettingsBottomSheetView>(
&_displaySettingsBottomSheetViewModel, &_theme->GetMaterialColorScheme(), _theme->GetFontRepository());
displaySettingsDialog->SetGraphics(_iconButtonViewVram);
_dialogPresenter.ShowDialog(std::move(displaySettingsDialog));
}
void App::HandleHideDisplaySettingsTrigger()
{
_dialogPresenter.CloseDialog();
if (!_dialogPresenter.GetOldFocus())
_romBrowserBottomScreenView->Focus(_focusManager);
}
void App::HandleNavigateTrigger()
{
if (!_romBrowserBottomScreenView->IsAppBarFocused(_focusManager))
_focusManager.Unfocus();
}
void App::HandleFolderLoadDoneTrigger()
{
_romBrowserTopScreenView.reset();
RestoreVramState(_vramStateAfterMakeBottomScreenView);
auto displayMode = RomBrowserDisplayModeFactory().GetRomBrowserDisplayMode(
_romBrowserController.GetRomBrowserDisplaySettings().layout);
_romBrowserTopScreenView = std::make_unique<RomBrowserTopScreenView>(
_romBrowserController.GetRomBrowserViewModel(),
displayMode,
_materialThemeFileIconFactory.get(),
_theme->GetRomBrowserViewFactory());
_romBrowserTopScreenView->InitVram(_subVramContext);
_romBrowserBottomScreenView->RomBrowserViewModelInvalidated(_mainVramContext);
if (!_focusManager.GetCurrentFocus())
_romBrowserBottomScreenView->Focus(_focusManager);
}
void App::HandleChangeDisplayModeTrigger(RomBrowserState newState)
{
_dialogPresenter.ClearOldFocus();
RestoreVramState(_vramStateBeforeMakeBottomScreenView);
auto displayMode = RomBrowserDisplayModeFactory().GetRomBrowserDisplayMode(
_romBrowserController.GetRomBrowserDisplaySettings().layout);
_romBrowserBottomScreenView = std::make_unique<RomBrowserBottomScreenView>(
&_romBrowserBottomScreenViewModel,
displayMode,
_materialThemeFileIconFactory.get(),
_theme->GetRomBrowserViewFactory(),
&_vblankTextureLoader);
_romBrowserBottomScreenView->InitVram(_mainVramContext);
StoreVramState(_vramStateAfterMakeBottomScreenView);
_romBrowserTopScreenView = std::make_unique<RomBrowserTopScreenView>(
_romBrowserController.GetRomBrowserViewModel(),
displayMode,
_materialThemeFileIconFactory.get(),
_theme->GetRomBrowserViewFactory());
_romBrowserTopScreenView->InitVram(_subVramContext);
_romBrowserBottomScreenView->RomBrowserViewModelInvalidated(_mainVramContext);
if (newState == RomBrowserState::Browser)
_romBrowserBottomScreenView->Focus(_focusManager);
}
bool App::IsRomBrowserVisible() const
{
const auto& stateMachine = _romBrowserController.GetStateMachine();
auto curState = stateMachine.GetCurrentState();
return curState == RomBrowserState::Browser
|| curState == RomBrowserState::GameInfo
|| curState == RomBrowserState::DisplaySettings
|| curState == RomBrowserState::Launching;
}
void App::Update()
{
const auto& stateMachine = _romBrowserController.GetStateMachine();
_romBrowserController.Update();
auto curState = stateMachine.GetCurrentState();
if (_changeDisplayMode)
{
HandleChangeDisplayModeTrigger(curState);
_changeDisplayMode = false;
}
if (stateMachine.HasStateChanged())
{
HandleTrigger(stateMachine.GetLastTrigger(), curState);
}
bool isRomBrowserVisible = IsRomBrowserVisible();
if (isRomBrowserVisible && !_exit && curState != RomBrowserState::Launching)
{
_focusManager.Update(_inputRepeater);
}
if (_topBackground)
_topBackground->Update();
if (_bottomBackground)
_bottomBackground->Update();
_dialogPresenter.Update();
_romBrowserBottomScreenView->Update();
if (isRomBrowserVisible)
{
_romBrowserTopScreenView->Update();
_romBrowserController.GetRomBrowserViewModel()->SetIconFrameCounter(
_romBrowserController.GetRomBrowserViewModel()->GetIconFrameCounter() + 1);
}
}
void App::Draw()
{
gx_reset();
Gx::Viewport(0, 0, 255, 191);
Gx::MtxMode(GX_MTX_MODE_POSITION_VECTOR);
Gx::MtxIdentity();
GraphicsContext mainGraphicsContext
{
&_mainOam,
&_mainObjPltt,
&_rgb6Palette
};
GraphicsContext subGraphicsContext
{
&_subOam,
&_subObjPltt,
nullptr
};
_mainOam.Clear();
_subOam.Clear();
_mainObjPltt.Reset();
_subObjPltt.Reset();
mainGraphicsContext.SetPriority(3);
subGraphicsContext.SetPriority(2);
if (_topBackground)
_topBackground->Draw(subGraphicsContext);
if (_bottomBackground)
_bottomBackground->Draw(mainGraphicsContext);
if (!_changeDisplayMode && IsRomBrowserVisible())
{
_romBrowserTopScreenView->Draw(subGraphicsContext);
}
_dialogPresenter.ApplyClipArea(mainGraphicsContext);
if (!_changeDisplayMode)
{
_romBrowserBottomScreenView->Draw(mainGraphicsContext);
}
mainGraphicsContext.ResetClipArea();
_dialogPresenter.Draw(mainGraphicsContext);
_mainObjPltt.EndOfFrame();
Gx::SwapBuffers(GX_XLU_SORT_MANUAL, GX_DEPTH_MODE_Z);
}
void App::VBlank()
{
dma_ntrStopDirect(0); // stop hblank dma
_inputProvider.Sample();
_inputRepeater.Update();
_mainOam.Apply(GFX_OAM_MAIN);
_subOam.Apply(GFX_OAM_SUB);
_subObjPltt.Apply(GFX_PLTT_OBJ_SUB);
if (!_vcountIrqStarted)
{
rtos_ackIrqMask(RTOS_IRQ_VCOUNT);
rtos_enableIrqMask(RTOS_IRQ_VCOUNT);
_vcountIrqStarted = true;
}
_mainObjPltt.VBlank();
if (_topBackground)
_topBackground->VBlank();
if (_bottomBackground)
_bottomBackground->VBlank();
_dialogPresenter.VBlank();
if (IsRomBrowserVisible())
{
_romBrowserTopScreenView->VBlank();
}
_romBrowserBottomScreenView->VBlank();
_vblankTextureLoader.VBlank();
}
void App::StoreVramState(VramState& vramState) const
{
vramState._mainObjVramState = _mainObjVram.GetState();
vramState._texVramState = _textureVram.GetState();
vramState._texPlttVramState = _texturePaletteVram.GetState();
vramState._subObjVramState = _subObjVram.GetState();
}
void App::RestoreVramState(const VramState& vramState)
{
_mainObjVram.SetState(vramState._mainObjVramState);
_textureVram.SetState(vramState._texVramState);
_texturePaletteVram.SetState(vramState._texPlttVramState);
_subObjVram.SetState(vramState._subObjVramState);
}