From ce95b8539abb97f9646f1592b3b5d209bb5bc625 Mon Sep 17 00:00:00 2001 From: Gericom Date: Sat, 24 Aug 2019 20:44:46 +0200 Subject: [PATCH 1/8] Added settings menu and settings file --- arm9/Makefile | 7 + arm9/data/CheckboxMarked.nbfc | Bin 0 -> 128 bytes arm9/data/CheckboxOutline.nbfc | Bin 0 -> 128 bytes arm9/data/IconGamepad.nbfc | Bin 0 -> 128 bytes arm9/data/IconInformation.nbfc | Bin 0 -> 128 bytes arm9/data/IconPlayCircle.nbfc | Bin 0 -> 128 bytes arm9/data/RobotoRegular9.ntft | Bin 0 -> 17264 bytes arm9/source/INIReader.h | 10 ++ arm9/source/INIReader.vram.cpp | 31 ++++ arm9/source/INIWriter.h | 14 ++ arm9/source/INIWriter.vram.cpp | 30 ++++ arm9/source/bios.vram.cpp | 2 + arm9/source/fat/diskio.vram.cpp | 2 +- arm9/source/fat/ff.vram.c | 6 +- arm9/source/fat/ffconf.h | 2 +- arm9/source/gui/FileBrowser.h | 14 +- arm9/source/gui/FileBrowser.vram.cpp | 137 +++++---------- arm9/source/gui/FileBrowserListEntry.vram.cpp | 12 +- arm9/source/gui/SettingsCategoryListAdapter.h | 33 ++++ .../gui/SettingsCategoryListAdapter.vram.cpp | 21 +++ arm9/source/gui/SettingsCategoryListEntry.h | 47 +++++ .../gui/SettingsCategoryListEntry.vram.cpp | 126 ++++++++++++++ arm9/source/gui/SettingsItemListAdapter.h | 34 ++++ .../gui/SettingsItemListAdapter.vram.cpp | 21 +++ arm9/source/gui/SettingsItemListEntry.h | 68 ++++++++ .../source/gui/SettingsItemListEntry.vram.cpp | 134 ++++++++++++++ arm9/source/gui/SettingsScreen.h | 59 +++++++ arm9/source/gui/SettingsScreen.vram.cpp | 163 ++++++++++++++++++ arm9/source/gui/Toolbar.h | 15 +- arm9/source/gui/Toolbar.vram.cpp | 37 ++-- arm9/source/gui/UIContext.h | 49 ++++++ arm9/source/gui/UIContext.vram.cpp | 63 +++++++ arm9/source/gui/core/ListRecycler.vram.cpp | 8 +- arm9/source/math.h | 2 + arm9/source/math.vram.c | 19 ++ arm9/source/sd_access.cpp | 63 ++++++- arm9/source/settings.h | 10 ++ arm9/source/settings.vram.cpp | 83 +++++++++ arm9/source/setup.s | 26 ++- arm9/source/vram_code.s | 7 +- readme.md | 3 +- 41 files changed, 1223 insertions(+), 135 deletions(-) create mode 100644 arm9/data/CheckboxMarked.nbfc create mode 100644 arm9/data/CheckboxOutline.nbfc create mode 100644 arm9/data/IconGamepad.nbfc create mode 100644 arm9/data/IconInformation.nbfc create mode 100644 arm9/data/IconPlayCircle.nbfc create mode 100644 arm9/data/RobotoRegular9.ntft create mode 100644 arm9/source/INIReader.h create mode 100644 arm9/source/INIReader.vram.cpp create mode 100644 arm9/source/INIWriter.h create mode 100644 arm9/source/INIWriter.vram.cpp create mode 100644 arm9/source/gui/SettingsCategoryListAdapter.h create mode 100644 arm9/source/gui/SettingsCategoryListAdapter.vram.cpp create mode 100644 arm9/source/gui/SettingsCategoryListEntry.h create mode 100644 arm9/source/gui/SettingsCategoryListEntry.vram.cpp create mode 100644 arm9/source/gui/SettingsItemListAdapter.h create mode 100644 arm9/source/gui/SettingsItemListAdapter.vram.cpp create mode 100644 arm9/source/gui/SettingsItemListEntry.h create mode 100644 arm9/source/gui/SettingsItemListEntry.vram.cpp create mode 100644 arm9/source/gui/SettingsScreen.h create mode 100644 arm9/source/gui/SettingsScreen.vram.cpp create mode 100644 arm9/source/gui/UIContext.h create mode 100644 arm9/source/gui/UIContext.vram.cpp create mode 100644 arm9/source/settings.h create mode 100644 arm9/source/settings.vram.cpp diff --git a/arm9/Makefile b/arm9/Makefile index 430c452..8be112e 100644 --- a/arm9/Makefile +++ b/arm9/Makefile @@ -44,6 +44,13 @@ ifdef ENABLE_WRAM_ICACHE CFLAGS += -DENABLE_WRAM_ICACHE endif +GIT_HASH := $(shell git rev-parse HEAD) +GIT_DATE := $(shell git log -1 "--date=format:%d-%m-%Y %H:%M" --pretty=format:%cd) +GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD) + +CFLAGS += -DGIT_COMMIT_HASH="\"$(GIT_HASH)\"" -DGIT_COMMIT_DATE="\"$(GIT_DATE)\"" -DGIT_BRANCH="\"$(GIT_BRANCH)\"" + + CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -fnon-call-exceptions ASFLAGS := -g $(ARCH) -march=armv5te -mtune=arm946e-s $(INCLUDE) diff --git a/arm9/data/CheckboxMarked.nbfc b/arm9/data/CheckboxMarked.nbfc new file mode 100644 index 0000000000000000000000000000000000000000..1124c17cfbac13744a5bfb1aeb2fe9eaac54fd38 GIT binary patch literal 128 zcmZQzfP$a@|1CjbBd literal 0 HcmV?d00001 diff --git a/arm9/data/CheckboxOutline.nbfc b/arm9/data/CheckboxOutline.nbfc new file mode 100644 index 0000000000000000000000000000000000000000..79b1a00dd2bc811b356840de82d99d7b20d9beb2 GIT binary patch literal 128 zcmZQzfP$a@|1U SV<-Ts;rRZas~?*rPz(T#(j`Iw literal 0 HcmV?d00001 diff --git a/arm9/data/IconInformation.nbfc b/arm9/data/IconInformation.nbfc new file mode 100644 index 0000000000000000000000000000000000000000..c6495fcbeff97b1229f1426ab7a164b3c2eae47a GIT binary patch literal 128 zcmW-Zu?>JQ5Cct`C>;Y(WV5V5%M{Qt1~V`L(;%S;>3Czwm3=2Ub=TO@3F=%G+6-*4 odR>ylF$gBT9J(RJoF6Fh@wb^V`#bEiGZNnt&1THnVV9lG2fzkFi~s-t literal 0 HcmV?d00001 diff --git a/arm9/data/IconPlayCircle.nbfc b/arm9/data/IconPlayCircle.nbfc new file mode 100644 index 0000000000000000000000000000000000000000..7a6d7ffe9a3cb9faf30a5afe7069e122edd07622 GIT binary patch literal 128 zcmXAhu?>JQ3zL%_AceB}Jy ki$om+Yp&)fH;nNxnK5g}?$>b3O_!4~Yv*^fku5iUFYl#3e*gdg literal 0 HcmV?d00001 diff --git a/arm9/data/RobotoRegular9.ntft b/arm9/data/RobotoRegular9.ntft new file mode 100644 index 0000000000000000000000000000000000000000..b91919e3969683c721cca03737393351c07a603d GIT binary patch literal 17264 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 literal 0 HcmV?d00001 diff --git a/arm9/source/INIReader.h b/arm9/source/INIReader.h new file mode 100644 index 0000000..eca0b63 --- /dev/null +++ b/arm9/source/INIReader.h @@ -0,0 +1,10 @@ +#pragma once +#include "fat/ff.h" + +typedef void (*inir_callback_t)(void* arg, const char* section, const char* key, const char* value); + +class INIReader +{ +public: + static bool Parse(FIL* file, inir_callback_t callback, void* arg); +}; \ No newline at end of file diff --git a/arm9/source/INIReader.vram.cpp b/arm9/source/INIReader.vram.cpp new file mode 100644 index 0000000..19acba2 --- /dev/null +++ b/arm9/source/INIReader.vram.cpp @@ -0,0 +1,31 @@ +#include "vram.h" +#include "vramheap.h" +#include "string.h" +#include "fat/ff.h" +#include "INIReader.h" + +bool INIReader::Parse(FIL* file, inir_callback_t callback, void* arg) +{ + char line[128]; + char section[128]; + while (f_gets(line, sizeof(line), file)) + { + if(line[0] == ';') + continue; + char* newLine = strchr(line, '\n'); + *newLine = 0; + if(line[0] == '[') + { + int len = strlen(line) - 2; + for(int i = 0; i < len; i++) + section[i] = line[i + 1]; + section[len] = 0; + continue; + } + char* equals = strchr(line, '='); + if(!equals) + continue; + *equals = 0; + callback(arg, section, line, equals + 1); + } +} \ No newline at end of file diff --git a/arm9/source/INIWriter.h b/arm9/source/INIWriter.h new file mode 100644 index 0000000..80b87f0 --- /dev/null +++ b/arm9/source/INIWriter.h @@ -0,0 +1,14 @@ +#pragma once +#include "fat/ff.h" + +class INIWriter +{ + FIL* _file; +public: + explicit INIWriter(FIL* file); + + void WriteSection(const char* name); + void WriteProperty(const char* key, const char* value); + void WriteBooleanProperty(const char* key, bool value); + void WriteIntegerProperty(const char* key, int value); +}; \ No newline at end of file diff --git a/arm9/source/INIWriter.vram.cpp b/arm9/source/INIWriter.vram.cpp new file mode 100644 index 0000000..9d1db8f --- /dev/null +++ b/arm9/source/INIWriter.vram.cpp @@ -0,0 +1,30 @@ +#include "vram.h" +#include "vramheap.h" +#include "fat/ff.h" +#include "INIWriter.h" + +INIWriter::INIWriter(FIL* file) + : _file(file) +{ + +} + +void INIWriter::WriteSection(const char* name) +{ + f_printf(_file, "[%s]\n", name); +} + +void INIWriter::WriteProperty(const char* key, const char* value) +{ + f_printf(_file, "%s=%s\n", key, value); +} + +void INIWriter::WriteBooleanProperty(const char* key, bool value) +{ + WriteProperty(key, value ? "true" : "false"); +} + +void INIWriter::WriteIntegerProperty(const char* key, int value) +{ + f_printf(_file, "%s=%d\n", key, value); +} \ No newline at end of file diff --git a/arm9/source/bios.vram.cpp b/arm9/source/bios.vram.cpp index 019cd51..6af5ee0 100644 --- a/arm9/source/bios.vram.cpp +++ b/arm9/source/bios.vram.cpp @@ -122,6 +122,8 @@ BiosLoadResult bios_load() FRESULT result = f_open(&vram_cd->fil, "0:/bios.bin", FA_OPEN_EXISTING | FA_READ); if (result != FR_OK) result = f_open(&vram_cd->fil, "0:/gba/bios.bin", FA_OPEN_EXISTING | FA_READ); + if (result != FR_OK) + result = f_open(&vram_cd->fil, "0:/_gba/bios.bin", FA_OPEN_EXISTING | FA_READ); if (result != FR_OK) return BIOS_LOAD_RESULT_NOT_FOUND; if (vram_cd->fil.obj.objsize != BIOS_SIZE) diff --git a/arm9/source/fat/diskio.vram.cpp b/arm9/source/fat/diskio.vram.cpp index 5a735cd..118082f 100644 --- a/arm9/source/fat/diskio.vram.cpp +++ b/arm9/source/fat/diskio.vram.cpp @@ -228,6 +228,6 @@ extern "C" DRESULT disk_ioctl ( return res; }*/ - return RES_PARERR; + return RES_OK; } diff --git a/arm9/source/fat/ff.vram.c b/arm9/source/fat/ff.vram.c index b015592..3be263e 100644 --- a/arm9/source/fat/ff.vram.c +++ b/arm9/source/fat/ff.vram.c @@ -6530,7 +6530,11 @@ int f_printf ( } i = 0; do { - d = (TCHAR)(v % r); v /= r; + int mod; + v = math_divmod(v, r, &mod); + d = (TCHAR)mod; + //d = (TCHAR)(v % r); + //v = math_div(v, r); if (d > 9) d += (c == 'x') ? 0x27 : 0x07; str[i++] = d + '0'; } while (v && i < sizeof str / sizeof *str); diff --git a/arm9/source/fat/ffconf.h b/arm9/source/fat/ffconf.h index bb81ab9..e176440 100644 --- a/arm9/source/fat/ffconf.h +++ b/arm9/source/fat/ffconf.h @@ -25,7 +25,7 @@ / 3: f_lseek() function is removed in addition to 2. */ -#define FF_USE_STRFUNC 0 +#define FF_USE_STRFUNC 1 /* This option switches string functions, f_gets(), f_putc(), f_puts() and f_printf(). / / 0: Disable string functions. diff --git a/arm9/source/gui/FileBrowser.h b/arm9/source/gui/FileBrowser.h index 36b4e6b..d573f0e 100644 --- a/arm9/source/gui/FileBrowser.h +++ b/arm9/source/gui/FileBrowser.h @@ -5,6 +5,7 @@ #include "core/ListRecycler.h" #include "fat/ff.h" #include "save/Save.h" +#include "UIContext.h" class NtftFont; class FileBrowser @@ -13,11 +14,7 @@ class FileBrowser FILINFO _entries[64]; FILINFO* _sortedEntries[64]; - PaletteManager _bgPalMan; - UIManager _uiManager; - - NtftFont* _robotoMedium13; - NtftFont* _robotoRegular11; + UIContext* _uiContext; ListRecycler* _listRecycler; FileBrowserListAdapter* _adapter; @@ -32,10 +29,9 @@ class FileBrowser void LoadFolder(const char* path); void CreateLoadSave(const char* path, const save_type_t* saveType); void LoadGame(const char* path); - void FatalError(const char* error); public: - FileBrowser() - : _listRecycler(NULL), _adapter(NULL), _inputRepeater(0x3F3, 20, 8), _selectedEntry(0) + FileBrowser(UIContext* uiContext) + : _uiContext(uiContext), _listRecycler(NULL), _adapter(NULL), _inputRepeater(0x3F3, 20, 8), _selectedEntry(0) { } @@ -47,5 +43,5 @@ class FileBrowser delete _adapter; } - void Run(); + int Run(); }; diff --git a/arm9/source/gui/FileBrowser.vram.cpp b/arm9/source/gui/FileBrowser.vram.cpp index ce1c104..f4ec27d 100644 --- a/arm9/source/gui/FileBrowser.vram.cpp +++ b/arm9/source/gui/FileBrowser.vram.cpp @@ -32,34 +32,16 @@ static int compDirEntries(const FILINFO*& dir1, const FILINFO*& dir2) return strcasecmp(dir1->fname, dir2->fname); } -void FileBrowser::LoadBios() -{ - switch (bios_load()) - { - case BIOS_LOAD_RESULT_OK: - break; - case BIOS_LOAD_RESULT_ERROR: - FatalError("Error while loading bios!"); - break; - case BIOS_LOAD_RESULT_NOT_FOUND: - FatalError("Bios not found!"); - break; - case BIOS_LOAD_RESULT_INVALID: - FatalError("Bios invalid!"); - break; - } -} - void FileBrowser::LoadFolder(const char* path) { if (f_opendir(&vram_cd->dir, path) != FR_OK) - FatalError("Error while reading directory!"); + _uiContext->FatalError("Error while reading directory!"); int entryCount = 0; FILINFO info; while (true) { if (f_readdir(&vram_cd->dir, &info) != FR_OK) - FatalError("Error while reading directory!"); + _uiContext->FatalError("Error while reading directory!"); if (info.fattrib & (AM_SYS | AM_HID)) continue; if (info.fname[0] == 0) @@ -78,17 +60,25 @@ void FileBrowser::LoadFolder(const char* path) _entryCount = entryCount; if (_listRecycler) { - _uiManager.RemoveElement(_listRecycler); + _uiContext->GetUIManager().RemoveElement(_listRecycler); delete _listRecycler; } if (_adapter) delete _adapter; - _uiManager.GetSubObjManager().SetState(_vramState); - _adapter = new FileBrowserListAdapter(_robotoRegular11, _sortedEntries, _entryCount); + + //clear everything except the toolbar + _uiContext->GetUIManager().Update(); + _uiContext->GetUIManager().VBlank(); + + _uiContext->GetUIManager().GetSubObjManager().SetState(_vramState); + _adapter = new FileBrowserListAdapter(_uiContext->GetRobotoRegular11(), _sortedEntries, _entryCount); _listRecycler = new ListRecycler(0, 36, 256, 156, 5, _adapter); _selectedEntry = 0; _listRecycler->SetSelectedIdx(0); - _uiManager.AddElement(_listRecycler); + _uiContext->GetUIManager().AddElement(_listRecycler); + + //load the text graphics for next menu + _uiContext->GetUIManager().VBlank(); } void FileBrowser::CreateLoadSave(const char* path, const save_type_t* saveType) @@ -116,15 +106,15 @@ void FileBrowser::CreateLoadSave(const char* path, const save_type_t* saveType) return; #else if (f_open(&vram_cd->fil, path, FA_CREATE_NEW | FA_WRITE) != FR_OK) - FatalError("Error creating save file!"); + _uiContext->FatalError("Error creating save file!"); UINT bw; if (f_write(&vram_cd->fil, (void*)MAIN_MEMORY_ADDRESS_SAVE_DATA, vram_cd->save_work.saveSize, &bw) != FR_OK || bw != vram_cd->save_work.saveSize) - FatalError("Error creating save file!"); + _uiContext->FatalError("Error creating save file!"); f_close(&vram_cd->fil); if (f_open(&vram_cd->fil, path, FA_OPEN_EXISTING | FA_READ) != FR_OK) - FatalError("Error creating save file!"); + _uiContext->FatalError("Error creating save file!"); #endif } @@ -132,7 +122,7 @@ void FileBrowser::CreateLoadSave(const char* path, const save_type_t* saveType) vram_cd->save_work.saveSize = 512; if (vram_cd->fil.obj.objsize < vram_cd->save_work.saveSize) - FatalError("Save file too small!"); + _uiContext->FatalError("Save file too small!"); uint32_t* cluster_table = &vram_cd->save_work.save_fat_table[0]; uint32_t cur_cluster = vram_cd->fil.obj.sclust; @@ -147,7 +137,7 @@ void FileBrowser::CreateLoadSave(const char* path, const save_type_t* saveType) UINT br; if (f_read(&vram_cd->fil, (void*)MAIN_MEMORY_ADDRESS_SAVE_DATA, vram_cd->save_work.saveSize, &br) != FR_OK || br != vram_cd->save_work.saveSize) - FatalError("Error while reading save file!"); + _uiContext->FatalError("Error while reading save file!"); f_close(&vram_cd->fil); vram_cd->save_work.fat_table_crc = crc16(0xFFFF, vram_cd->save_work.save_fat_table, @@ -162,7 +152,7 @@ void FileBrowser::CreateLoadSave(const char* path, const save_type_t* saveType) void FileBrowser::LoadGame(const char* path) { if (f_open(&vram_cd->fil, path, FA_OPEN_EXISTING | FA_READ) != FR_OK) - FatalError("Error while opening rom!"); + _uiContext->FatalError("Error while opening rom!"); vram_cd->sd_info.gba_rom_size = vram_cd->fil.obj.objsize; uint32_t* cluster_table = &vram_cd->gba_rom_cluster_table[0]; uint32_t cur_cluster = vram_cd->fil.obj.sclust; @@ -174,7 +164,7 @@ void FileBrowser::LoadGame(const char* path) } UINT br; if (f_read(&vram_cd->fil, (void*)MAIN_MEMORY_ADDRESS_ROM_DATA, ROM_DATA_LENGTH, &br) != FR_OK) - FatalError("Error while reading rom!"); + _uiContext->FatalError("Error while reading rom!"); const save_type_t* saveType = save_findTag(); if (saveType != NULL) @@ -205,59 +195,19 @@ void FileBrowser::LoadGame(const char* path) CreateLoadSave(nameBuf, saveType); } -void FileBrowser::FatalError(const char* error) -{ - Dialog* dialog = new Dialog(_robotoMedium13, "Error", _robotoRegular11, error); - _uiManager.AddElement(dialog); - _uiManager.GetSubObjPalManager().DimRows(0x3FFF); - _bgPalMan.DimRows(0x7FFF); - while (1) - { - _uiManager.Update(); - while (*((vu16*)0x04000004) & 1); - while (!(*((vu16*)0x04000004) & 1)); - _bgPalMan.Apply(BG_PALETTE_SUB); - _uiManager.VBlank(); - } -} - -void FileBrowser::Run() +int FileBrowser::Run() { - REG_DISPCNT_SUB = DISPLAY_BG1_ACTIVE | DISPLAY_BG2_ACTIVE | DISPLAY_SPR_ACTIVE | DISPLAY_SPR_1D | - DISPLAY_SPR_1D_SIZE_32 | MODE_0_2D; - - //toolbar shadow - for (int i = 0; i < 16; i++) - _bgPalMan.palette[i].color = ((u16*)BarShadow_nbfp)[i]; - for (int i = 0; i < (64 >> 1); i++) - BG_GFX_SUB[i] = ((u16*)BarShadow_nbfc)[i]; - for (int i = 0; i < 2048 / 2; i++) - BG_GFX_SUB[(0x3800 >> 1) + i] = ((u16*)BarShadow_nbfs)[i]; - REG_BG1CNT_SUB = BG_32x32 | BG_PRIORITY_2 | BG_COLOR_16 | BG_MAP_BASE(7); - REG_BLDCNT_SUB = BLEND_ALPHA | BLEND_SRC_BG1 | BLEND_DST_BG0 | BLEND_DST_SPRITE | BLEND_DST_BACKDROP; - REG_BLDALPHA_SUB = 4 | (12 << 8); - _bgPalMan.palette[0].color = RGB5(31, 31, 31); + int next = 2; + _uiContext->GetToolbar().SetTitle("GBARunner2"); + _uiContext->GetToolbar().SetShowBackButton(false); + _uiContext->GetToolbar().SetShowSettingsButton(true); + _uiContext->GetUIManager().Update(); + while (*((vu16*)0x04000004) & 1); + while (!(*((vu16*)0x04000004) & 1)); + _uiContext->GetUIManager().VBlank(); + FileBrowserListEntry::LoadCommonData(_uiContext->GetUIManager()); + _vramState = _uiContext->GetUIManager().GetSubObjManager().GetState(); - //dialogue bg - BG_GFX_SUB[32] = 0x1112; - for (int i = 0; i < (64 >> 1) - 1; i++) - BG_GFX_SUB[33 + i] = 0x1111; - REG_BG2CNT_SUB = BG_32x32 | BG_PRIORITY_2 | BG_COLOR_16 | BG_MAP_BASE(8); - _bgPalMan.palette[15 * 16 + 1].color = RGB5(31, 31, 31); - _bgPalMan.palette[15 * 16 + 2].color = RGB5(157 >> 3, 157 >> 3, 157 >> 3); - - _robotoMedium13 = new NtftFont(RobotoMedium13_ntft); - _robotoRegular11 = new NtftFont(RobotoRegular11_ntft); - Toolbar::LoadCommonData(_uiManager); - Toolbar* toolbar = new Toolbar(RGB5(103 >> 3, 58 >> 3, 183 >> 3), 0x7FFF, _robotoMedium13, "GBARunner2", 0x7FFF); - FileBrowserListEntry::LoadCommonData(_uiManager); - _uiManager.AddElement(toolbar); - _vramState = _uiManager.GetSubObjManager().GetState(); - - if (f_mount(&vram_cd->fatFs, "", 1) != FR_OK) - FatalError("Couldn't mount sd card!"); - - LoadBios(); f_chdir("/"); if (f_stat("gba", NULL) == FR_OK) f_chdir("gba"); @@ -293,16 +243,23 @@ void FileBrowser::Run() f_chdir(".."); LoadFolder("."); } + else if (_inputRepeater.GetTriggeredKeys() & (1 << 8)) + { + next = 1; + break; + } _listRecycler->SetSelectedIdx(_selectedEntry); - _uiManager.Update(); + _uiContext->GetUIManager().Update(); while (*((vu16*)0x04000004) & 1); while (!(*((vu16*)0x04000004) & 1)); - _bgPalMan.Apply(BG_PALETTE_SUB); - _uiManager.VBlank(); + _uiContext->GetBGPalManager().Apply(BG_PALETTE_SUB); + _uiContext->GetUIManager().VBlank(); } - _uiManager.GetSubOamManager().Clear(); - _uiManager.GetSubOamManager().Apply(OAM_SUB); - REG_BLDCNT_SUB = 0; - REG_BLDALPHA_SUB = 0; - delete toolbar; + if (_listRecycler) + _uiContext->GetUIManager().RemoveElement(_listRecycler); + + //clear everything except the toolbar + _uiContext->GetUIManager().Update(); + _uiContext->GetUIManager().VBlank(); + return next; } diff --git a/arm9/source/gui/FileBrowserListEntry.vram.cpp b/arm9/source/gui/FileBrowserListEntry.vram.cpp index 1d7341b..d77bbb7 100644 --- a/arm9/source/gui/FileBrowserListEntry.vram.cpp +++ b/arm9/source/gui/FileBrowserListEntry.vram.cpp @@ -30,21 +30,21 @@ void FileBrowserListEntry::LoadCommonData(UIManager& uiManager) PaletteManager& palMan = uiManager.GetSubObjPalManager(); for (int i = 0; i < 16; i++) { - int gray = 31 + ((4 - 31) * i + 7) / 15; + int gray = 31 + ((4 - 31) * i) / 15; palMan.palette[i + (3 * 16)].color = RGB5(gray, gray, gray); - int gray2 = 28 + ((4 - 28) * i + 7) / 15; + int gray2 = 28 + ((4 - 28) * i) / 15; palMan.palette[i + (6 * 16)].color = RGB5(gray2, gray2, gray2); } for (int i = 0; i < 16; i++) { - int gray = 31 + ((19 - 31) * i + 7) / 15; + int gray = 31 + ((19 - 31) * i) / 15; palMan.palette[i + (4 * 16)].color = RGB5(gray, gray, gray); - int gray2 = 28 + ((19 - 28) * i + 7) / 15; + int gray2 = 28 + ((19 - 28) * i) / 15; palMan.palette[i + (7 * 16)].color = RGB5(gray2, gray2, gray2); } for (int i = 0; i < 16; i++) { - int gray = 19 + ((31 - 19) * i + 7) / 15; + int gray = 19 + ((31 - 19) * i) / 15; palMan.palette[i + (5 * 16)].color = RGB5(gray, gray, gray); } palMan.palette[1 + (8 * 16)].color = RGB5(28, 28, 28); @@ -101,7 +101,7 @@ void FileBrowserListEntry::Update(UIManager& uiManager) { nameOams[i].attribute[0] = ATTR0_NORMAL | ATTR0_TYPE_NORMAL | ATTR0_COLOR_16 | ATTR0_WIDE | OBJ_Y(_offsetY + 10); - nameOams[i].attribute[1] = ATTR1_SIZE_32 | OBJ_X(_offsetX + 46 + 32 * i); + nameOams[i].attribute[1] = ATTR1_SIZE_32 | OBJ_X(_offsetX + 47 + 32 * i); nameOams[i].attribute[2] = ATTR2_PRIORITY(3) | ATTR2_PALETTE(3 + palOffset) | ((_nameObjAddr >> 5) + 8 * i); } } diff --git a/arm9/source/gui/SettingsCategoryListAdapter.h b/arm9/source/gui/SettingsCategoryListAdapter.h new file mode 100644 index 0000000..5625079 --- /dev/null +++ b/arm9/source/gui/SettingsCategoryListAdapter.h @@ -0,0 +1,33 @@ +#pragma once +#include "SettingsCategoryListEntry.h" +#include "SettingsScreen.h" +#include "core/ListAdapter.h" + +class SettingsCategoryListAdapter : public ListAdapter +{ + const NtftFont* _font; + const settings_category_t* _items; + int _itemCount; +protected: + void OnBindElementHolder(ElementHolder* elementHolder, int position); + +public: + explicit SettingsCategoryListAdapter(const NtftFont* font, const settings_category_t* items, int itemCount) + : _font(font), _items(items), _itemCount(itemCount) + { + } + + ElementHolder* CreateElementHolder(); + + void DestroyElementHolder(ElementHolder* elementHolder); + + int GetItemCount() + { + return _itemCount; + } + + int GetElementHeight() + { + return 32; + } +}; diff --git a/arm9/source/gui/SettingsCategoryListAdapter.vram.cpp b/arm9/source/gui/SettingsCategoryListAdapter.vram.cpp new file mode 100644 index 0000000..91e5f85 --- /dev/null +++ b/arm9/source/gui/SettingsCategoryListAdapter.vram.cpp @@ -0,0 +1,21 @@ +#include "vram.h" +#include "vramheap.h" +#include "SettingsCategoryListAdapter.h" + +void SettingsCategoryListAdapter::OnBindElementHolder(ElementHolder* elementHolder, int position) +{ + SettingsCategoryListEntry* element = (SettingsCategoryListEntry*)elementHolder->GetItemElement(); + element->SetName(_items[position].name); + element->SetIcon(_items[position].icon); +} + +ElementHolder* SettingsCategoryListAdapter::CreateElementHolder() +{ + return new ElementHolder(new SettingsCategoryListEntry(_font)); +} + +void SettingsCategoryListAdapter::DestroyElementHolder(ElementHolder* elementHolder) +{ + delete (SettingsCategoryListEntry*)elementHolder->GetItemElement(); + delete elementHolder; +} \ No newline at end of file diff --git a/arm9/source/gui/SettingsCategoryListEntry.h b/arm9/source/gui/SettingsCategoryListEntry.h new file mode 100644 index 0000000..8cc4cd0 --- /dev/null +++ b/arm9/source/gui/SettingsCategoryListEntry.h @@ -0,0 +1,47 @@ +#pragma once + +#include "core/ListEntry.h" +#include "core/NtftFont.h" + +class SettingsCategoryListEntry : public ListEntry +{ + static u16 sPlayCircleObjAddr; + static u16 sGamepadObjAddr; + static u16 sInfoObjAddr; + +public: + enum CategoryIcon : u16 + { + SETTINGS_CATEGORY_ICON_PLAYCIRCLE, + SETTINGS_CATEGORY_ICON_GAMEPAD, + SETTINGS_CATEGORY_ICON_INFO + }; + +private: + const NtftFont* _font; + CategoryIcon _icon; + u16 _nameObjAddr; + char _name[128]; + u16 _nameInvalidated; +public: + static void LoadCommonData(UIManager& uiManager); + + explicit SettingsCategoryListEntry(const NtftFont* font) + : _font(font) + { + } + + void Initialize(UIManager& uiManager); + void Update(UIManager& uiManager); + void VBlank(UIManager& uiManager); + + void SetFont(const NtftFont* font) + { + _font = font; + _nameInvalidated = true; + } + + void SetName(const char* name); + + void SetIcon(CategoryIcon icon) { _icon = icon; } +}; \ No newline at end of file diff --git a/arm9/source/gui/SettingsCategoryListEntry.vram.cpp b/arm9/source/gui/SettingsCategoryListEntry.vram.cpp new file mode 100644 index 0000000..e82731d --- /dev/null +++ b/arm9/source/gui/SettingsCategoryListEntry.vram.cpp @@ -0,0 +1,126 @@ +#include "vram.h" +#include "vramheap.h" +#include "string.h" +#include "sd_access.h" +#include "core/UIManager.h" +#include "core/NtftFont.h" +#include "Toolbar.h" +#include "uiutil.h" +#include "IconPlayCircle_nbfc.h" +#include "IconGamepad_nbfc.h" +#include "IconInformation_nbfc.h" +#include "SettingsCategoryListEntry.h" + +u16 SettingsCategoryListEntry::sPlayCircleObjAddr; +u16 SettingsCategoryListEntry::sGamepadObjAddr; +u16 SettingsCategoryListEntry::sInfoObjAddr; + +void SettingsCategoryListEntry::LoadCommonData(UIManager& uiManager) +{ + sPlayCircleObjAddr = uiManager.GetSubObjManager().Alloc(IconPlayCircle_nbfc_size); + for (int i = 0; i < IconPlayCircle_nbfc_size / 2; i++) + SPRITE_GFX_SUB[(sPlayCircleObjAddr >> 1) + i] = ((u16*)IconPlayCircle_nbfc)[i]; + sGamepadObjAddr = uiManager.GetSubObjManager().Alloc(IconGamepad_nbfc_size); + for (int i = 0; i < IconGamepad_nbfc_size / 2; i++) + SPRITE_GFX_SUB[(sGamepadObjAddr >> 1) + i] = ((u16*)IconGamepad_nbfc)[i]; + sInfoObjAddr = uiManager.GetSubObjManager().Alloc(IconInformation_nbfc_size); + for (int i = 0; i < IconInformation_nbfc_size / 2; i++) + SPRITE_GFX_SUB[(sInfoObjAddr >> 1) + i] = ((u16*)IconInformation_nbfc)[i]; + + PaletteManager& palMan = uiManager.GetSubObjPalManager(); + for (int i = 0; i < 16; i++) + { + int gray = 31 + ((4 - 31) * i) / 15; + palMan.palette[i + (3 * 16)].color = RGB5(gray, gray, gray); + int gray2 = 28 + ((4 - 28) * i) / 15; + palMan.palette[i + (5 * 16)].color = RGB5(gray2, gray2, gray2); + } + for (int i = 0; i < 16; i++) + { + int gray = 31 + ((14 - 31) * i) / 15; + palMan.palette[i + (4 * 16)].color = RGB5(gray, gray, gray); + int gray2 = 28 + ((13 - 28) * i) / 15; + palMan.palette[i + (6 * 16)].color = RGB5(gray2, gray2, gray2); + } + palMan.palette[1 + (7 * 16)].color = RGB5(28, 28, 28); +} + +void SettingsCategoryListEntry::Initialize(UIManager& uiManager) +{ + _nameObjAddr = uiManager.GetSubObjManager().Alloc(192 * 16 / 2); +} + +void SettingsCategoryListEntry::Update(UIManager& uiManager) +{ + OamManager& oamMan = uiManager.GetSubOamManager(); + int palOffset = 0; + if (_selected) + { + int mtxId; + SpriteRotation* bgMtx = oamMan.AllocMtxs(1, mtxId); + bgMtx->hdx = 128; + bgMtx->vdx = 0; + bgMtx->hdy = 0; + bgMtx->vdy = 256; + SpriteEntry* bgOams = oamMan.AllocOams(2); + bgOams[0].attribute[0] = ATTR0_ROTSCALE_DOUBLE | ATTR0_TYPE_NORMAL | ATTR0_COLOR_16 | ATTR0_WIDE | OBJ_Y(_offsetY - 16); + bgOams[0].attribute[1] = ATTR1_SIZE_64 | OBJ_X(0) | ATTR1_ROTDATA(mtxId); + bgOams[0].attribute[2] = ATTR2_PRIORITY(3) | ATTR2_PALETTE(7) | (Toolbar::sBgObjAddr >> 5); + bgOams[1].attribute[0] = ATTR0_ROTSCALE_DOUBLE | ATTR0_TYPE_NORMAL | ATTR0_COLOR_16 | ATTR0_WIDE | OBJ_Y(_offsetY - 16); + bgOams[1].attribute[1] = ATTR1_SIZE_64 | OBJ_X(128) | ATTR1_ROTDATA(mtxId); + bgOams[1].attribute[2] = ATTR2_PRIORITY(3) | ATTR2_PALETTE(7) | (Toolbar::sBgObjAddr >> 5); + palOffset = 2; + } + + SpriteEntry* iconOam = oamMan.AllocOams(1); + iconOam->attribute[0] = ATTR0_NORMAL | ATTR0_TYPE_NORMAL | ATTR0_COLOR_16 | ATTR0_SQUARE | OBJ_Y(_offsetY + 8); + iconOam->attribute[1] = ATTR1_SIZE_16 | OBJ_X(_offsetX + 10); + u16 icon; + switch (_icon) + { + case SETTINGS_CATEGORY_ICON_PLAYCIRCLE: + icon = sPlayCircleObjAddr; + break; + case SETTINGS_CATEGORY_ICON_GAMEPAD: + icon = sGamepadObjAddr; + break; + case SETTINGS_CATEGORY_ICON_INFO: + icon = sInfoObjAddr; + break; + } + iconOam->attribute[2] = ATTR2_PRIORITY(3) | ATTR2_PALETTE(4 + palOffset) | (icon >> 5); + + SpriteEntry* nameOams = oamMan.AllocOams(6); + for (int i = 0; i < 6; i++) + { + nameOams[i].attribute[0] = ATTR0_NORMAL | ATTR0_TYPE_NORMAL | ATTR0_COLOR_16 | ATTR0_WIDE | + OBJ_Y(_offsetY + 8); + nameOams[i].attribute[1] = ATTR1_SIZE_32 | OBJ_X(_offsetX + 47 + 32 * i); + nameOams[i].attribute[2] = ATTR2_PRIORITY(3) | ATTR2_PALETTE(3 + palOffset) | ((_nameObjAddr >> 5) + 8 * i); + } +} + +void SettingsCategoryListEntry::VBlank(UIManager& uiManager) +{ + if (_nameInvalidated) + { + u8* tmp = new u8[192 * 16]; + for (int i = 0; i < 192 * 16; i += 2) + *((u16*)&tmp[i]) = 0; + _font->CreateStringData(_name, tmp + (8 - ((_font->GetFontHeight() + 1) >> 1)) * 192, 192); + for (int i = 0; i < 6; i++) + uiutil_convertToObj(tmp + i * 32, 32, 16, 192, &SPRITE_GFX_SUB[(_nameObjAddr >> 1) + i * 128]); + delete[] tmp; + _nameInvalidated = false; + } +} + +void SettingsCategoryListEntry::SetName(const char* name) +{ + int len = strlen(name); + if (len > 63) + len = 63; + arm9_memcpy16((u16*)_name, (u16*)name, (len + 1) >> 1); + MI_WriteByte(&_name[len], 0); + _nameInvalidated = true; +} diff --git a/arm9/source/gui/SettingsItemListAdapter.h b/arm9/source/gui/SettingsItemListAdapter.h new file mode 100644 index 0000000..f150587 --- /dev/null +++ b/arm9/source/gui/SettingsItemListAdapter.h @@ -0,0 +1,34 @@ +#pragma once +#include "core/ListAdapter.h" + +struct settings_item_t; + +class SettingsItemListAdapter : public ListAdapter +{ + const NtftFont* _titleFont; + const NtftFont* _subTitleFont; + const settings_item_t* _items; + int _itemCount; +protected: + void OnBindElementHolder(ElementHolder* elementHolder, int position); + +public: + explicit SettingsItemListAdapter(const NtftFont* titleFont, const NtftFont* subTitleFont, const settings_item_t* items, int itemCount) + : _titleFont(titleFont), _subTitleFont(subTitleFont), _items(items), _itemCount(itemCount) + { + } + + ElementHolder* CreateElementHolder(); + + void DestroyElementHolder(ElementHolder* elementHolder); + + int GetItemCount() + { + return _itemCount; + } + + int GetElementHeight() + { + return 42; + } +}; diff --git a/arm9/source/gui/SettingsItemListAdapter.vram.cpp b/arm9/source/gui/SettingsItemListAdapter.vram.cpp new file mode 100644 index 0000000..33cc6de --- /dev/null +++ b/arm9/source/gui/SettingsItemListAdapter.vram.cpp @@ -0,0 +1,21 @@ +#include "vram.h" +#include "vramheap.h" +#include "SettingsScreen.h" +#include "SettingsItemListAdapter.h" + +void SettingsItemListAdapter::OnBindElementHolder(ElementHolder* elementHolder, int position) +{ + SettingsItemListEntry* element = (SettingsItemListEntry*)elementHolder->GetItemElement(); + element->SetSettingsItem(&_items[position]); +} + +ElementHolder* SettingsItemListAdapter::CreateElementHolder() +{ + return new ElementHolder(new SettingsItemListEntry(_titleFont, _subTitleFont)); +} + +void SettingsItemListAdapter::DestroyElementHolder(ElementHolder* elementHolder) +{ + delete (SettingsItemListEntry*)elementHolder->GetItemElement(); + delete elementHolder; +} \ No newline at end of file diff --git a/arm9/source/gui/SettingsItemListEntry.h b/arm9/source/gui/SettingsItemListEntry.h new file mode 100644 index 0000000..8a20ab2 --- /dev/null +++ b/arm9/source/gui/SettingsItemListEntry.h @@ -0,0 +1,68 @@ +#pragma once + +#include "core/ListEntry.h" +#include "core/NtftFont.h" + +struct settings_item_t; + +enum SettingsItemMode : u16 +{ + SETTINGS_ITEM_MODE_SIMPLE, + SETTINGS_ITEM_MODE_SWITCH, + SETTINGS_ITEM_MODE_CHECK +}; + +class SettingsItemListEntry : public ListEntry +{ + static u16 sCheckboxOutlineObjAddr; + static u16 sCheckboxMarkedObjAddr; + + const NtftFont* _titleFont; + u16 _titleObjAddr; + u16 _titleInvalidated; + //char _title[64]; + const NtftFont* _subTitleFont; + u16 _subTitleObjAddr; + u16 _subTitleInvalidated; + //char _subTitle[64]; + //ItemMode _mode; + //u16 _checked; + const settings_item_t* _settingsItem; +public: + static void LoadCommonData(UIManager& uiManager); + + explicit SettingsItemListEntry(const NtftFont* titleFont, const NtftFont* subTitleFont) + : _titleFont(titleFont), _subTitleFont(subTitleFont) + { + } + + void Initialize(UIManager& uiManager); + void Update(UIManager& uiManager); + void VBlank(UIManager& uiManager); + + void SetTitleFont(const NtftFont* font) + { + _titleFont = font; + _titleInvalidated = true; + } + + //void SetTitle(const char* title); + + void SetSubTitleFont(const NtftFont* font) + { + _subTitleFont = font; + _subTitleInvalidated = true; + } + + void SetSettingsItem(const settings_item_t* settingsItem) + { + _settingsItem = settingsItem; + _titleInvalidated = true; + _subTitleInvalidated = true; + } + + //void SetSubTitle(const char* subTitle); + + //void SetMode(ItemMode mode) { _mode = mode; } + //void SetChecked(bool checked) { _checked = checked; } +}; \ No newline at end of file diff --git a/arm9/source/gui/SettingsItemListEntry.vram.cpp b/arm9/source/gui/SettingsItemListEntry.vram.cpp new file mode 100644 index 0000000..58f4def --- /dev/null +++ b/arm9/source/gui/SettingsItemListEntry.vram.cpp @@ -0,0 +1,134 @@ +#include "vram.h" +#include "vramheap.h" +#include "string.h" +#include "sd_access.h" +#include "core/UIManager.h" +#include "core/NtftFont.h" +#include "Toolbar.h" +#include "uiutil.h" +#include "CheckboxOutline_nbfc.h" +#include "CheckboxMarked_nbfc.h" +#include "SettingsScreen.h" +#include "SettingsItemListEntry.h" + +u16 SettingsItemListEntry::sCheckboxOutlineObjAddr; +u16 SettingsItemListEntry::sCheckboxMarkedObjAddr; + +void SettingsItemListEntry::LoadCommonData(UIManager& uiManager) +{ + sCheckboxOutlineObjAddr = uiManager.GetSubObjManager().Alloc(CheckboxOutline_nbfc_size); + for (int i = 0; i < CheckboxOutline_nbfc_size / 2; i++) + SPRITE_GFX_SUB[(sCheckboxOutlineObjAddr >> 1) + i] = ((u16*)CheckboxOutline_nbfc)[i]; + sCheckboxMarkedObjAddr = uiManager.GetSubObjManager().Alloc(CheckboxMarked_nbfc_size); + for (int i = 0; i < CheckboxMarked_nbfc_size / 2; i++) + SPRITE_GFX_SUB[(sCheckboxMarkedObjAddr >> 1) + i] = ((u16*)CheckboxMarked_nbfc)[i]; + + PaletteManager& palMan = uiManager.GetSubObjPalManager(); + for (int i = 0; i < 16; i++) + { + int gray = 31 + ((4 - 31) * i) / 15; + palMan.palette[i + (3 * 16)].color = RGB5(gray, gray, gray); + int gray2 = 28 + ((4 - 28) * i) / 15; + palMan.palette[i + (5 * 16)].color = RGB5(gray2, gray2, gray2); + } + for (int i = 0; i < 16; i++) + { + int gray = 31 + ((14 - 31) * i) / 15; + palMan.palette[i + (4 * 16)].color = RGB5(gray, gray, gray); + int gray2 = 28 + ((13 - 28) * i) / 15; + palMan.palette[i + (6 * 16)].color = RGB5(gray2, gray2, gray2); + } + + palMan.palette[1 + (7 * 16)].color = RGB5(28, 28, 28); +} + +void SettingsItemListEntry::Initialize(UIManager& uiManager) +{ + _titleObjAddr = uiManager.GetSubObjManager().Alloc(192 * 16 / 2); + _subTitleObjAddr = uiManager.GetSubObjManager().Alloc(224 * 16 / 2); +} + +void SettingsItemListEntry::Update(UIManager& uiManager) +{ + OamManager& oamMan = uiManager.GetSubOamManager(); + int palOffset = 0; + if (_selected) + { + int mtxId; + SpriteRotation* bgMtx = oamMan.AllocMtxs(1, mtxId); + bgMtx->hdx = 128; + bgMtx->vdx = 0; + bgMtx->hdy = 0; + bgMtx->vdy = 256; + SpriteEntry* bgOams = oamMan.AllocOams(4); + bgOams[0].attribute[0] = ATTR0_ROTSCALE_DOUBLE | ATTR0_TYPE_NORMAL | ATTR0_COLOR_16 | ATTR0_WIDE | OBJ_Y(_offsetY - 16); + bgOams[0].attribute[1] = ATTR1_SIZE_64 | OBJ_X(0) | ATTR1_ROTDATA(mtxId); + bgOams[0].attribute[2] = ATTR2_PRIORITY(3) | ATTR2_PALETTE(7) | (Toolbar::sBgObjAddr >> 5); + bgOams[1].attribute[0] = ATTR0_ROTSCALE_DOUBLE | ATTR0_TYPE_NORMAL | ATTR0_COLOR_16 | ATTR0_WIDE | OBJ_Y(_offsetY - 16); + bgOams[1].attribute[1] = ATTR1_SIZE_64 | OBJ_X(128) | ATTR1_ROTDATA(mtxId); + bgOams[1].attribute[2] = ATTR2_PRIORITY(3) | ATTR2_PALETTE(7) | (Toolbar::sBgObjAddr >> 5); + bgOams[2].attribute[0] = ATTR0_ROTSCALE_DOUBLE | ATTR0_TYPE_NORMAL | ATTR0_COLOR_16 | ATTR0_WIDE | OBJ_Y(_offsetY - 16 + 10); + bgOams[2].attribute[1] = ATTR1_SIZE_64 | OBJ_X(0) | ATTR1_ROTDATA(mtxId); + bgOams[2].attribute[2] = ATTR2_PRIORITY(3) | ATTR2_PALETTE(7) | (Toolbar::sBgObjAddr >> 5); + bgOams[3].attribute[0] = ATTR0_ROTSCALE_DOUBLE | ATTR0_TYPE_NORMAL | ATTR0_COLOR_16 | ATTR0_WIDE | OBJ_Y(_offsetY - 16 + 10); + bgOams[3].attribute[1] = ATTR1_SIZE_64 | OBJ_X(128) | ATTR1_ROTDATA(mtxId); + bgOams[3].attribute[2] = ATTR2_PRIORITY(3) | ATTR2_PALETTE(7) | (Toolbar::sBgObjAddr >> 5); + palOffset = 2; + } + + SpriteEntry* titleOams = oamMan.AllocOams(6); + for (int i = 0; i < 6; i++) + { + titleOams[i].attribute[0] = ATTR0_NORMAL | ATTR0_TYPE_NORMAL | ATTR0_COLOR_16 | ATTR0_WIDE | + OBJ_Y(_offsetY + (_settingsItem->subTitle[0] != 0 ? 7 : 13)); + titleOams[i].attribute[1] = ATTR1_SIZE_32 | OBJ_X(_offsetX + 10 + 32 * i); + titleOams[i].attribute[2] = ATTR2_PRIORITY(3) | ATTR2_PALETTE(3 + palOffset) | ((_titleObjAddr >> 5) + 8 * i); + } + + if(_settingsItem->subTitle[0] != 0) + { + SpriteEntry* subTitleOams = oamMan.AllocOams(7); + for (int i = 0; i < 7; i++) + { + subTitleOams[i].attribute[0] = ATTR0_NORMAL | ATTR0_TYPE_NORMAL | ATTR0_COLOR_16 | ATTR0_WIDE | + OBJ_Y(_offsetY + 20); + subTitleOams[i].attribute[1] = ATTR1_SIZE_32 | OBJ_X(_offsetX + 10 + 32 * i); + subTitleOams[i].attribute[2] = ATTR2_PRIORITY(3) | ATTR2_PALETTE(4 + palOffset) | ((_subTitleObjAddr >> 5) + 8 * i); + } + } + + if(_settingsItem->mode == SETTINGS_ITEM_MODE_CHECK) + { + SpriteEntry* checkboxOam = oamMan.AllocOams(1); + checkboxOam->attribute[0] = ATTR0_NORMAL | ATTR0_TYPE_NORMAL | ATTR0_COLOR_16 | ATTR0_SQUARE | OBJ_Y(_offsetY + 13); + checkboxOam->attribute[1] = ATTR1_SIZE_16 | OBJ_X(_offsetX + 228); + checkboxOam->attribute[2] = ATTR2_PRIORITY(3) | ATTR2_PALETTE(4 + palOffset) | + ((*_settingsItem->pValue ? sCheckboxMarkedObjAddr : sCheckboxOutlineObjAddr) >> 5); + } +} + +void SettingsItemListEntry::VBlank(UIManager& uiManager) +{ + if (_titleInvalidated) + { + u8* tmp = new u8[192 * 16]; + for (int i = 0; i < 192 * 16; i += 2) + *((u16*)&tmp[i]) = 0; + _titleFont->CreateStringData(_settingsItem->title, tmp + (8 - ((_titleFont->GetFontHeight() + 1) >> 1)) * 192, 192); + for (int i = 0; i < 6; i++) + uiutil_convertToObj(tmp + i * 32, 32, 16, 192, &SPRITE_GFX_SUB[(_titleObjAddr >> 1) + i * 128]); + delete[] tmp; + _titleInvalidated = false; + } + if (_subTitleInvalidated) + { + u8* tmp = new u8[224 * 16]; + for (int i = 0; i < 224 * 16; i += 2) + *((u16*)&tmp[i]) = 0; + _subTitleFont->CreateStringData(_settingsItem->subTitle, tmp + (8 - ((_subTitleFont->GetFontHeight() + 1) >> 1)) * 224, 224); + for (int i = 0; i < 7; i++) + uiutil_convertToObj(tmp + i * 32, 32, 16, 224, &SPRITE_GFX_SUB[(_subTitleObjAddr >> 1) + i * 128]); + delete[] tmp; + _subTitleInvalidated = false; + } +} \ No newline at end of file diff --git a/arm9/source/gui/SettingsScreen.h b/arm9/source/gui/SettingsScreen.h new file mode 100644 index 0000000..9579a9b --- /dev/null +++ b/arm9/source/gui/SettingsScreen.h @@ -0,0 +1,59 @@ +#pragma once +#include "core/UIManager.h" +#include "core/PaletteManager.h" +#include "core/ListAdapter.h" +#include "core/InputRepeater.h" +#include "core/ListRecycler.h" +#include "SettingsCategoryListEntry.h" +#include "SettingsItemListEntry.h" +#include "Toolbar.h" +#include "UIContext.h" + +struct settings_item_t +{ + SettingsItemMode mode; + const char* title; + const char* subTitle; + u32* pValue; +}; + +struct settings_category_t +{ + const char* name; + SettingsCategoryListEntry::CategoryIcon icon; + int itemCount; + settings_item_t* items; +}; + +class SettingsScreen +{ + UIContext* _uiContext; + + ListRecycler* _listRecycler; + ListAdapter* _adapter; + + InputRepeater _inputRepeater; + + int _selectedEntry; + + u16 _vramState; + + const settings_category_t* _selectedCategory; + + void GotoCategory(const settings_category_t* category); +public: + SettingsScreen(UIContext* uiContext) + : _uiContext(uiContext), _listRecycler(NULL), _adapter(NULL), _inputRepeater(0x3F3, 20, 8), _selectedEntry(0) + { + } + + ~SettingsScreen() + { + if (_listRecycler) + delete _listRecycler; + if (_adapter) + delete _adapter; + } + + void Run(); +}; \ No newline at end of file diff --git a/arm9/source/gui/SettingsScreen.vram.cpp b/arm9/source/gui/SettingsScreen.vram.cpp new file mode 100644 index 0000000..10c338e --- /dev/null +++ b/arm9/source/gui/SettingsScreen.vram.cpp @@ -0,0 +1,163 @@ +#include +#include +#include "vram.h" +#include "vramheap.h" +#include "vector.h" +#include "gui/core/UIManager.h" +#include "gui/Toolbar.h" +#include "Dialog.h" +#include "core/ListRecycler.h" +#include "core/InputRepeater.h" +#include "SettingsCategoryListAdapter.h" +#include "SettingsItemListAdapter.h" +#include "SettingsItemListEntry.h" +#include "SettingsCategoryListEntry.h" +#include "UIContext.h" +#include "settings.h" +#include "SettingsScreen.h" + +static settings_item_t sEmulationItems[] = +{ + { SETTINGS_ITEM_MODE_CHECK, "Display game on bottom screen", "", &gEmuSettingUseBottomScreen }, + //{ SETTINGS_ITEM_MODE_CHECK, "Enable autosaving", "Writes back the save to sd after a game saves", &gEmuSettingAutoSave }, + { SETTINGS_ITEM_MODE_CHECK, "Enable center and mask", "Centers the game with a border. Adds 1 frame delay", &gEmuSettingCenterMask }, + //{ SETTINGS_ITEM_MODE_CHECK, "Enable wram i-cache", "Boosts speed, but some games may crash", &gEmuSettingWramICache }, + { SETTINGS_ITEM_MODE_CHECK, "Skip bios intro", "Directly boot the game without playing the intro", &gEmuSettingSkipIntro } +}; + +static settings_item_t sInputItems[] = +{ + { SETTINGS_ITEM_MODE_SIMPLE, "GBA A button", "DS A button", NULL }, + { SETTINGS_ITEM_MODE_SIMPLE, "GBA B button", "DS B button", NULL }, + { SETTINGS_ITEM_MODE_SIMPLE, "GBA L button", "DS L button", NULL }, + { SETTINGS_ITEM_MODE_SIMPLE, "GBA R button", "DS R button", NULL }, + { SETTINGS_ITEM_MODE_SIMPLE, "GBA START button", "DS START button", NULL }, + { SETTINGS_ITEM_MODE_SIMPLE, "GBA SELECT button", "DS SELECT button", NULL } +}; + +static settings_item_t sInfoItems[] = +{ + { SETTINGS_ITEM_MODE_SIMPLE, "Commit date", GIT_COMMIT_DATE, NULL }, + { SETTINGS_ITEM_MODE_SIMPLE, "Commit hash", GIT_COMMIT_HASH, NULL }, + { SETTINGS_ITEM_MODE_SIMPLE, "Branch", GIT_BRANCH, NULL }, + { SETTINGS_ITEM_MODE_SIMPLE, "DLDI Cpu", +#ifdef ARM7_DLDI + "ARM 7" +#else + "ARM 9" +#endif + , NULL }, + { SETTINGS_ITEM_MODE_SIMPLE, "Wram i-cache", +#ifdef ENABLE_WRAM_ICACHE + "On" +#else + "Off" +#endif + , NULL } +}; + +static const settings_category_t sCategories[] = +{ + { "Emulation Settings", SettingsCategoryListEntry::SETTINGS_CATEGORY_ICON_PLAYCIRCLE, sizeof(sEmulationItems) / sizeof(settings_item_t), sEmulationItems }, + //{ "Input Settings", SettingsCategoryListEntry::SETTINGS_CATEGORY_ICON_GAMEPAD, sizeof(sInputItems) / sizeof(settings_item_t), sInputItems }, + { "About GBARunner2", SettingsCategoryListEntry::SETTINGS_CATEGORY_ICON_INFO, sizeof(sInfoItems) / sizeof(settings_item_t), sInfoItems } +}; + +void SettingsScreen::GotoCategory(const settings_category_t* category) +{ + if (_listRecycler) + { + _uiContext->GetUIManager().RemoveElement(_listRecycler); + delete _listRecycler; + } + if (_adapter) + delete _adapter; + _uiContext->GetUIManager().GetSubObjManager().SetState(_vramState); + + //clear everything except the toolbar + _uiContext->GetUIManager().Update(); + _uiContext->GetUIManager().VBlank(); + + _selectedCategory = category; + if(_selectedCategory) + { + _adapter = new SettingsItemListAdapter(_uiContext->GetRobotoRegular11(), _uiContext->GetRobotoRegular9(), _selectedCategory->items, _selectedCategory->itemCount); + _listRecycler = new ListRecycler(0, 36, 256, 156, 5, _adapter); + _selectedEntry = 0; + _listRecycler->SetSelectedIdx(0); + _uiContext->GetUIManager().AddElement(_listRecycler); + _uiContext->GetToolbar().SetTitle(_selectedCategory->name); + } + else + { + _adapter = new SettingsCategoryListAdapter(_uiContext->GetRobotoRegular11(), sCategories, sizeof(sCategories) / sizeof(settings_category_t)); + _listRecycler = new ListRecycler(0, 36, 256, 156, 5, _adapter); + _selectedEntry = 0; + _listRecycler->SetSelectedIdx(0); + _uiContext->GetUIManager().AddElement(_listRecycler); + _uiContext->GetToolbar().SetTitle("Settings"); + } + //load the text graphics for next menu + _uiContext->GetUIManager().VBlank(); +} + +void SettingsScreen::Run() +{ + _uiContext->GetToolbar().SetTitle("Settings"); + _uiContext->GetToolbar().SetShowBackButton(true); + _uiContext->GetToolbar().SetShowSettingsButton(false); + _uiContext->GetUIManager().Update(); + while (*((vu16*)0x04000004) & 1); + while (!(*((vu16*)0x04000004) & 1)); + _uiContext->GetUIManager().VBlank(); + SettingsItemListEntry::LoadCommonData(_uiContext->GetUIManager()); + SettingsCategoryListEntry::LoadCommonData(_uiContext->GetUIManager()); + _vramState = _uiContext->GetUIManager().GetSubObjManager().GetState(); + GotoCategory(NULL); + while (1) + { + _inputRepeater.Update(~*((vu16*)0x04000130)); + if (_inputRepeater.GetTriggeredKeys() & (1 << 6)) + { + if (_selectedEntry > 0) + _selectedEntry--; + } + else if (_inputRepeater.GetTriggeredKeys() & (1 << 7)) + { + if (_selectedEntry < _adapter->GetItemCount() - 1) + _selectedEntry++; + } + else if (_inputRepeater.GetTriggeredKeys() & 1) + { + if(_selectedCategory) + { + if(_selectedCategory->items[_selectedEntry].mode == SETTINGS_ITEM_MODE_CHECK) + *_selectedCategory->items[_selectedEntry].pValue = !*_selectedCategory->items[_selectedEntry].pValue; + } + else + GotoCategory(&sCategories[_selectedEntry]); + } + else if (_inputRepeater.GetTriggeredKeys() & 2) + { + if(_selectedCategory) + GotoCategory(NULL); + else + { + while(!(*((vu16*)0x04000130) & 2)); + break; + } + } + _listRecycler->SetSelectedIdx(_selectedEntry); + _uiContext->GetUIManager().Update(); + while (*((vu16*)0x04000004) & 1); + while (!(*((vu16*)0x04000004) & 1)); + _uiContext->GetBGPalManager().Apply(BG_PALETTE_SUB); + _uiContext->GetUIManager().VBlank(); + } + if (_listRecycler) + _uiContext->GetUIManager().RemoveElement(_listRecycler); + + //clear everything except the toolbar + _uiContext->GetUIManager().Update(); + _uiContext->GetUIManager().VBlank(); +} \ No newline at end of file diff --git a/arm9/source/gui/Toolbar.h b/arm9/source/gui/Toolbar.h index d17e7ea..e125b5d 100644 --- a/arm9/source/gui/Toolbar.h +++ b/arm9/source/gui/Toolbar.h @@ -14,6 +14,7 @@ class Toolbar : public UIElement XBGR1555 _iconColor; XBGR1555 _textColor; u16 _textObjAddr; + u16 _backArrowObjAddr; u16 _settingsObjAddr; union @@ -26,7 +27,7 @@ class Toolbar : public UIElement vu32 cursorInvalidated : 1; vu32 : 12; vu32 showBackButton : 1; - vu32 showClearButton : 1; + vu32 showSettingsButton : 1; vu32 showSearchButton : 1; vu32 showMenuButton : 1; vu32 showCursor : 1; @@ -50,6 +51,8 @@ class Toolbar : public UIElement SetIconColor(iconColor); SetTextColor(textColor); SetTitle(title); + SetShowBackButton(false); + SetShowSettingsButton(true); } void Initialize(UIManager& uiManager); @@ -80,5 +83,15 @@ class Toolbar : public UIElement _flags.titleInvalidated = true; } + void SetShowBackButton(bool showBackButton) + { + _flags.showBackButton = showBackButton; + } + + void SetShowSettingsButton(bool showSettingsButton) + { + _flags.showSettingsButton = showSettingsButton; + } + void SetTitle(const char* title); }; diff --git a/arm9/source/gui/Toolbar.vram.cpp b/arm9/source/gui/Toolbar.vram.cpp index 47583cc..b683847 100644 --- a/arm9/source/gui/Toolbar.vram.cpp +++ b/arm9/source/gui/Toolbar.vram.cpp @@ -20,9 +20,9 @@ void Toolbar::LoadCommonData(UIManager& uiManager) void Toolbar::Initialize(UIManager& uiManager) { - u16 backArrowAddr = uiManager.GetSubObjManager().Alloc(128); + _backArrowObjAddr = uiManager.GetSubObjManager().Alloc(128); for (int i = 0; i < 128 / 2; i++) - SPRITE_GFX_SUB[(backArrowAddr >> 1) + i] = ((u16*)IconArrowLeft_nbfc)[i]; + SPRITE_GFX_SUB[(_backArrowObjAddr >> 1) + i] = ((u16*)IconArrowLeft_nbfc)[i]; _settingsObjAddr = uiManager.GetSubObjManager().Alloc(128); for (int i = 0; i < 128 / 2; i++) SPRITE_GFX_SUB[(_settingsObjAddr >> 1) + i] = ((u16*)IconSettings_nbfc)[i]; @@ -47,8 +47,16 @@ void Toolbar::Update(UIManager& uiManager) bgOams[1].attribute[1] = ATTR1_SIZE_64 | OBJ_X(128) | ATTR1_ROTDATA(mtxId); bgOams[1].attribute[2] = ATTR2_PRIORITY(2) | ATTR2_PALETTE(0) | (sBgObjAddr >> 5); - SpriteEntry* titleOams = oamMan.AllocOams(5); int text_x = 10; + if (_flags.showBackButton) + { + SpriteEntry* backButtonOam = oamMan.AllocOams(1); + backButtonOam->attribute[0] = ATTR0_NORMAL | ATTR0_TYPE_NORMAL | ATTR0_COLOR_16 | ATTR0_SQUARE | OBJ_Y(10); + backButtonOam->attribute[1] = ATTR1_SIZE_16 | OBJ_X(10); + backButtonOam->attribute[2] = ATTR2_PRIORITY(2) | ATTR2_PALETTE(2) | (_backArrowObjAddr >> 5); + text_x = 47; + } + SpriteEntry* titleOams = oamMan.AllocOams(5); for (int i = 0; i < 5; i++) { titleOams[i].attribute[0] = ATTR0_NORMAL | ATTR0_TYPE_NORMAL | ATTR0_COLOR_16 | ATTR0_WIDE | OBJ_Y(11); @@ -56,10 +64,13 @@ void Toolbar::Update(UIManager& uiManager) titleOams[i].attribute[2] = ATTR2_PRIORITY(2) | ATTR2_PALETTE(1) | ((_textObjAddr >> 5) + 8 * i); } - SpriteEntry* settingsOam = oamMan.AllocOams(1); - settingsOam->attribute[0] = ATTR0_NORMAL | ATTR0_TYPE_NORMAL | ATTR0_COLOR_16 | ATTR0_SQUARE | OBJ_Y(10); - settingsOam->attribute[1] = ATTR1_SIZE_16 | OBJ_X(_flags.showMenuButton ? 204 : 230); - settingsOam->attribute[2] = ATTR2_PRIORITY(2) | ATTR2_PALETTE(2) | (_settingsObjAddr >> 5); + if(_flags.showSettingsButton) + { + SpriteEntry* settingsOam = oamMan.AllocOams(1); + settingsOam->attribute[0] = ATTR0_NORMAL | ATTR0_TYPE_NORMAL | ATTR0_COLOR_16 | ATTR0_SQUARE | OBJ_Y(10); + settingsOam->attribute[1] = ATTR1_SIZE_16 | OBJ_X(_flags.showMenuButton ? 204 : 230); + settingsOam->attribute[2] = ATTR2_PRIORITY(2) | ATTR2_PALETTE(2) | (_settingsObjAddr >> 5); + } if (_flags.colorInvalidated) { @@ -67,16 +78,16 @@ void Toolbar::Update(UIManager& uiManager) palMan.palette[1] = _bgColor; for (int i = 0; i < 16; i++) { - int rnew = _bgColor.r + ((_iconColor.r - _bgColor.r) * i + 7) / 15; - int gnew = _bgColor.g + ((_iconColor.g - _bgColor.g) * i + 7) / 15; - int bnew = _bgColor.b + ((_iconColor.b - _bgColor.b) * i + 7) / 15; + int rnew = _bgColor.r + ((_iconColor.r - _bgColor.r) * i) / 15; + int gnew = _bgColor.g + ((_iconColor.g - _bgColor.g) * i) / 15; + int bnew = _bgColor.b + ((_iconColor.b - _bgColor.b) * i) / 15; palMan.palette[i + 32].color = RGB5(rnew, gnew, bnew); } for (int i = 0; i < 16; i++) { - int rnew = _bgColor.r + ((_textColor.r - _bgColor.r) * i + 7) / 15; - int gnew = _bgColor.g + ((_textColor.g - _bgColor.g) * i + 7) / 15; - int bnew = _bgColor.b + ((_textColor.b - _bgColor.b) * i + 7) / 15; + int rnew = _bgColor.r + ((_textColor.r - _bgColor.r) * i) / 15; + int gnew = _bgColor.g + ((_textColor.g - _bgColor.g) * i) / 15; + int bnew = _bgColor.b + ((_textColor.b - _bgColor.b) * i) / 15; palMan.palette[i + 16].color = RGB5(rnew, gnew, bnew); } _flags.colorInvalidated = 0; diff --git a/arm9/source/gui/UIContext.h b/arm9/source/gui/UIContext.h new file mode 100644 index 0000000..d51ec2b --- /dev/null +++ b/arm9/source/gui/UIContext.h @@ -0,0 +1,49 @@ +#pragma once +#include "gui/core/NtftFont.h" +#include "core/PaletteManager.h" +#include "core/UIManager.h" +#include "Toolbar.h" + +class UIContext +{ + PaletteManager _bgPalMan; + UIManager _uiManager; + + u16 _initialVramState; + + NtftFont* _robotoMedium13; + NtftFont* _robotoRegular11; + NtftFont* _robotoRegular9; + + Toolbar _toolbar; + +public: + UIContext(); + + ~UIContext() + { + _uiManager.GetSubOamManager().Clear(); + _uiManager.GetSubOamManager().Apply(OAM_SUB); + REG_BLDCNT_SUB = 0; + REG_BLDALPHA_SUB = 0; + delete _robotoRegular9; + delete _robotoRegular11; + delete _robotoMedium13; + } + + void FatalError(const char* error); + + PaletteManager& GetBGPalManager() { return _bgPalMan; } + UIManager& GetUIManager() { return _uiManager; } + + Toolbar& GetToolbar() { return _toolbar; } + + const NtftFont* GetRobotoMedium13() const { return _robotoMedium13; } + const NtftFont* GetRobotoRegular11() const { return _robotoRegular11; } + const NtftFont* GetRobotoRegular9() const { return _robotoRegular9; } + + void ResetVram() + { + _uiManager.GetSubObjManager().SetState(_initialVramState); + } +}; \ No newline at end of file diff --git a/arm9/source/gui/UIContext.vram.cpp b/arm9/source/gui/UIContext.vram.cpp new file mode 100644 index 0000000..7d31c3f --- /dev/null +++ b/arm9/source/gui/UIContext.vram.cpp @@ -0,0 +1,63 @@ +#include +#include +#include "vram.h" +#include "vramheap.h" +#include "RobotoMedium13_ntft.h" +#include "RobotoRegular11_ntft.h" +#include "RobotoRegular9_ntft.h" +#include "BarShadow_nbfp.h" +#include "BarShadow_nbfc.h" +#include "BarShadow_nbfs.h" +#include "Dialog.h" +#include "UIContext.h" + +UIContext::UIContext() + : _robotoMedium13(new NtftFont(RobotoMedium13_ntft)), + _robotoRegular11(new NtftFont(RobotoRegular11_ntft)), + _robotoRegular9(new NtftFont(RobotoRegular9_ntft)), + _toolbar(RGB5(103 >> 3, 58 >> 3, 183 >> 3), 0x7FFF, _robotoMedium13, "GBARunner2", 0x7FFF) +{ + REG_DISPCNT_SUB = DISPLAY_BG1_ACTIVE | DISPLAY_BG2_ACTIVE | DISPLAY_SPR_ACTIVE | DISPLAY_SPR_1D | + DISPLAY_SPR_1D_SIZE_32 | MODE_0_2D; + + Toolbar::LoadCommonData(_uiManager); + _uiManager.AddElement(&_toolbar); + + //toolbar shadow + for (int i = 0; i < 16; i++) + _bgPalMan.palette[i].color = ((u16*)BarShadow_nbfp)[i]; + for (int i = 0; i < (64 >> 1); i++) + BG_GFX_SUB[i] = ((u16*)BarShadow_nbfc)[i]; + for (int i = 0; i < 2048 / 2; i++) + BG_GFX_SUB[(0x3800 >> 1) + i] = ((u16*)BarShadow_nbfs)[i]; + REG_BG1CNT_SUB = BG_32x32 | BG_PRIORITY_2 | BG_COLOR_16 | BG_MAP_BASE(7); + REG_BLDCNT_SUB = BLEND_ALPHA | BLEND_SRC_BG1 | BLEND_DST_BG0 | BLEND_DST_SPRITE | BLEND_DST_BACKDROP; + REG_BLDALPHA_SUB = 4 | (12 << 8); + _bgPalMan.palette[0].color = RGB5(31, 31, 31); + + //dialogue bg + BG_GFX_SUB[32] = 0x1112; + for (int i = 0; i < (64 >> 1) - 1; i++) + BG_GFX_SUB[33 + i] = 0x1111; + REG_BG2CNT_SUB = BG_32x32 | BG_PRIORITY_2 | BG_COLOR_16 | BG_MAP_BASE(8); + _bgPalMan.palette[15 * 16 + 1].color = RGB5(31, 31, 31); + _bgPalMan.palette[15 * 16 + 2].color = RGB5(157 >> 3, 157 >> 3, 157 >> 3); + + _initialVramState = _uiManager.GetSubObjManager().GetState(); +} + +void UIContext::FatalError(const char* error) +{ + Dialog* dialog = new Dialog(_robotoMedium13, "Error", _robotoRegular11, error); + _uiManager.AddElement(dialog); + _uiManager.GetSubObjPalManager().DimRows(0x3FFF); + _bgPalMan.DimRows(0x7FFF); + while (1) + { + _uiManager.Update(); + while (*((vu16*)0x04000004) & 1); + while (!(*((vu16*)0x04000004) & 1)); + _bgPalMan.Apply(BG_PALETTE_SUB); + _uiManager.VBlank(); + } +} \ No newline at end of file diff --git a/arm9/source/gui/core/ListRecycler.vram.cpp b/arm9/source/gui/core/ListRecycler.vram.cpp index 624721b..4ad7572 100644 --- a/arm9/source/gui/core/ListRecycler.vram.cpp +++ b/arm9/source/gui/core/ListRecycler.vram.cpp @@ -7,7 +7,7 @@ ListRecycler::ListRecycler(int x, int y, int width, int height, int paddingY, Li _selectedElement(-1) { _elementHeight = _adapter->GetElementHeight(); - _holderCount = 2 + math_div(_height, _elementHeight); + _holderCount = 3 + math_div(_height, _elementHeight); _holders = new ElementHolder*[_holderCount]; for (int i = 0; i < _holderCount; i++) _holders[i] = _adapter->CreateElementHolder(); @@ -75,7 +75,7 @@ void ListRecycler::UpdateElementPositions() if (!_holders[i]->GetIsBound()) continue; int newY = _paddingY + _holders[i]->GetItemPosition() * _elementHeight + _scrollY; - if (newY + _elementHeight < 0 || newY > _height) + if (newY + _elementHeight < -((_elementHeight + 1) >> 1) || newY > _height + ((_elementHeight + 1) >> 1)) { if (_holders[i]->GetItemPosition() == _firstElement) _firstElement++; @@ -88,13 +88,13 @@ void ListRecycler::UpdateElementPositions() _holders[i]->GetItemElement()->SetOffset(_x, _y + newY); } int firstY = _paddingY + _firstElement * _elementHeight + _scrollY; - while (_firstElement > 0 && firstY > 0) + while (_firstElement > 0 && firstY > -((_elementHeight + 1) >> 1)) { SetupListItem(--_firstElement); firstY = _paddingY + _firstElement * _elementHeight + _scrollY; } int lastY = _paddingY + _lastElement * _elementHeight + _scrollY; - while (_lastElement < _adapter->GetItemCount() - 1 && lastY + _elementHeight < _height) + while (_lastElement < _adapter->GetItemCount() - 1 && lastY + _elementHeight < _height + ((_elementHeight + 1) >> 1)) { SetupListItem(++_lastElement); lastY = _paddingY + _lastElement * _elementHeight + _scrollY; diff --git a/arm9/source/math.h b/arm9/source/math.h index 40b7e40..5bcef76 100644 --- a/arm9/source/math.h +++ b/arm9/source/math.h @@ -21,6 +21,8 @@ extern "C" { #endif int math_div(int a, int b); +int math_mod(int a, int b); +int math_divmod(int a, int b, int* rem); #ifdef __cplusplus } diff --git a/arm9/source/math.vram.c b/arm9/source/math.vram.c index 381ddf1..b32bdc4 100644 --- a/arm9/source/math.vram.c +++ b/arm9/source/math.vram.c @@ -8,4 +8,23 @@ int math_div(int a, int b) REG_DIV_DENOM = b; while (REG_DIV_CNT & DIV_CNT_BUSY); return REG_DIV_RESULT32; +} + +int math_mod(int a, int b) +{ + REG_DIV_CNT = DIV_CNT_MODE_32_32; + REG_DIV_NUMER32 = a; + REG_DIV_DENOM = b; + while (REG_DIV_CNT & DIV_CNT_BUSY); + return REG_DIV_REM_RESULT32; +} + +int math_divmod(int a, int b, int* rem) +{ + REG_DIV_CNT = DIV_CNT_MODE_32_32; + REG_DIV_NUMER32 = a; + REG_DIV_DENOM = b; + while (REG_DIV_CNT & DIV_CNT_BUSY); + *rem = REG_DIV_REM_RESULT32; + return REG_DIV_RESULT32; } \ No newline at end of file diff --git a/arm9/source/sd_access.cpp b/arm9/source/sd_access.cpp index 0407cad..d7540ed 100644 --- a/arm9/source/sd_access.cpp +++ b/arm9/source/sd_access.cpp @@ -7,8 +7,12 @@ #include "qsort.h" #include "fat.h" #include "consts.s" +#include "gui/UIContext.h" #include "gui/FileBrowser.h" +#include "gui/SettingsScreen.h" #include "sd_access.h" +#include "settings.h" +#include "bios.h" #include "crc16.h" #define REG_SEND_FIFO (*((vu32*)0x04000188)) @@ -190,13 +194,66 @@ extern "C" PUT_IN_VRAM void sd_write_save() extern "C" PUT_IN_VRAM void sd_init(uint8_t* bios_dst) { vramheap_init(); - FileBrowser* fileBrowser = new FileBrowser(); - fileBrowser->Run(); - delete fileBrowser; + *(vu8*)0x04000243 = 0x84; + *(vu8*)0x04000249 = 0x00; + UIContext* uiContext = new UIContext(); + uiContext->GetUIManager().Update(); + while (*((vu16*)0x04000004) & 1); + while (!(*((vu16*)0x04000004) & 1)); + uiContext->GetUIManager().VBlank(); + if (f_mount(&vram_cd->fatFs, "", 1) != FR_OK) + uiContext->FatalError("Couldn't mount sd card!"); +#ifndef ISNITRODEBUG + if (f_stat("0:/_gba", NULL) != FR_OK) + if(f_mkdir("0:/_gba") != FR_OK) + uiContext->FatalError("Couldn't create /_gba folder!"); +#endif + switch (bios_load()) + { + case BIOS_LOAD_RESULT_OK: + break; + case BIOS_LOAD_RESULT_ERROR: + uiContext->FatalError("Error while loading bios!"); + break; + case BIOS_LOAD_RESULT_NOT_FOUND: + uiContext->FatalError("Bios not found!"); + break; + case BIOS_LOAD_RESULT_INVALID: + uiContext->FatalError("Bios invalid!"); + break; + } + settings_initialize(); + + int next = 0; + while(true) + { + uiContext->ResetVram(); + if(next == 0) + { + FileBrowser* fileBrowser = new FileBrowser(uiContext); + next = fileBrowser->Run(); + delete fileBrowser; + } + else if(next == 1) + { + SettingsScreen* settings = new SettingsScreen(uiContext); + settings->Run(); + delete settings; +#ifndef ISNITRODEBUG + if(!settings_save()) + uiContext->FatalError("Couldn't save settings!"); +#endif + next = 0; + } + else if(next == 2) + break; + } + delete uiContext; MI_WriteByte(&vram_cd->sd_info.nr_sectors_per_cluster, vram_cd->fatFs.csize); vram_cd->sd_info.cluster_shift = 31 - __builtin_clz(vram_cd->sd_info.nr_sectors_per_cluster * 512); vram_cd->sd_info.cluster_mask = (1 << vram_cd->sd_info.cluster_shift) - 1; initialize_cache(); + *(vu8*)0x04000243 = 0x80; } //gets an empty one or wipes the oldest diff --git a/arm9/source/settings.h b/arm9/source/settings.h new file mode 100644 index 0000000..5566aa8 --- /dev/null +++ b/arm9/source/settings.h @@ -0,0 +1,10 @@ +#pragma once + +extern u32 gEmuSettingUseBottomScreen; +//extern u32 gEmuSettingAutoSave; +extern u32 gEmuSettingCenterMask; +//extern u32 gEmuSettingWramICache; +extern u32 gEmuSettingSkipIntro; + +void settings_initialize(); +bool settings_save(); \ No newline at end of file diff --git a/arm9/source/settings.vram.cpp b/arm9/source/settings.vram.cpp new file mode 100644 index 0000000..fa802d5 --- /dev/null +++ b/arm9/source/settings.vram.cpp @@ -0,0 +1,83 @@ +#include "vram.h" +#include "vramheap.h" +#include "sd_access.h" +#include "string.h" +#include "fat/ff.h" +#include "INIReader.h" +#include "INIWriter.h" +#include "settings.h" + +static const char* sSettingsFilePath = "0:/_gba/gbarunner2.ini"; + +static const char* sEmulationSectionName = "emulation"; + +//settings are globals such that they can be easily accessed from assembly +static const char* sEmuSettingUseBottomScreenName = "useBottomScreen"; +u32 gEmuSettingUseBottomScreen; +static const char* sEmuSettingAutoSaveName = "autoSave"; +u32 gEmuSettingAutoSave; +static const char* sEmuSettingCenterMaskName = "centerMask"; +u32 gEmuSettingCenterMask; +static const char* sEmuSettingWramICacheName = "wramICache"; +u32 gEmuSettingWramICache; +static const char* sEmuSettingSkipIntroName = "skipIntro"; +u32 gEmuSettingSkipIntro; + +static void loadDefaultSettings() +{ + gEmuSettingUseBottomScreen = false; + gEmuSettingAutoSave = true; + gEmuSettingCenterMask = true; + gEmuSettingWramICache = true; + gEmuSettingSkipIntro = false; +} + +static bool parseBoolean(const char* str, bool def = false) +{ + if(!strcmp(str, "true")) + return true; + else if(!strcmp(str, "false")) + return false; + return def; +} + +static void iniPropertyCallback(void* arg, const char* section, const char* key, const char* value) +{ + if(!strcmp(section, sEmulationSectionName)) + { + if(!strcmp(key, sEmuSettingUseBottomScreenName)) + gEmuSettingUseBottomScreen = parseBoolean(value, false); + else if(!strcmp(key, sEmuSettingAutoSaveName)) + gEmuSettingAutoSave = parseBoolean(value, true); + else if(!strcmp(key, sEmuSettingCenterMaskName)) + gEmuSettingCenterMask = parseBoolean(value, true); + else if(!strcmp(key, sEmuSettingWramICacheName)) + gEmuSettingWramICache = parseBoolean(value, true); + else if(!strcmp(key, sEmuSettingSkipIntroName)) + gEmuSettingSkipIntro = parseBoolean(value, false); + } +} + +void settings_initialize() +{ + loadDefaultSettings(); + if (f_open(&vram_cd->fil, sSettingsFilePath, FA_OPEN_EXISTING | FA_READ) != FR_OK) + return; + INIReader::Parse(&vram_cd->fil, iniPropertyCallback, NULL); + f_close(&vram_cd->fil); +} + +bool settings_save() +{ + if (f_open(&vram_cd->fil, sSettingsFilePath, FA_CREATE_ALWAYS | FA_WRITE) != FR_OK) + return false; + INIWriter writer = INIWriter(&vram_cd->fil); + writer.WriteSection(sEmulationSectionName); + writer.WriteBooleanProperty(sEmuSettingUseBottomScreenName, gEmuSettingUseBottomScreen); + //writer.WriteBooleanProperty(sEmuSettingAutoSaveName, gEmuSettingAutoSave); + writer.WriteBooleanProperty(sEmuSettingCenterMaskName, gEmuSettingCenterMask); + //writer.WriteBooleanProperty(sEmuSettingWramICacheName, gEmuSettingWramICache); + writer.WriteBooleanProperty(sEmuSettingSkipIntroName, gEmuSettingSkipIntro); + f_close(&vram_cd->fil); + return true; +} \ No newline at end of file diff --git a/arm9/source/setup.s b/arm9/source/setup.s index 170ccf5..28477b2 100644 --- a/arm9/source/setup.s +++ b/arm9/source/setup.s @@ -402,6 +402,12 @@ dldi_name_copy: str r1, [r0] ldr r1,= 0x4084 strh r1, [r0, #0xE] + + ldr r2,= gEmuSettingCenterMask + ldr r2, [r2] + cmp r2, #1 + bne skip_center_mask + //center ldr r1,= -(8 * 256) str r1, [r0, #0x38] @@ -420,6 +426,7 @@ dldi_name_copy: strh r1, [r0, #0x54] ldr r1,= 0x3FFF strh r1, [r0, #0x50] +skip_center_mask: ldr r2,= 0x05000400 mov r1, #0 @@ -461,11 +468,24 @@ dldi_name_copy: ldr r0,= 0x04000304 ldrh r1, [r0] bic r1, #0xC - eor r1, #0x8000 + + //set the screen swap setting + ldr r2,= gEmuSettingUseBottomScreen + ldr r2, [r2] + cmp r2, #1 + bicne r1, #0x8000 + orreq r1, #0x8000 + + ldr r2,= gEmuSettingCenterMask + ldr r2, [r2] + cmp r2, #1 + eorne r1, #0x8000 //reversed if no center+mask + strh r1, [r0] - //turn off the main engine display using masterbright - ldr r0,= 0x0400006C + //turn off the other engine display using masterbright + ldreq r0,= 0x0400006C + ldrne r0,= 0x0400106C ldr r1,= 0x801F strh r1, [r0] diff --git a/arm9/source/vram_code.s b/arm9/source/vram_code.s index 83aebda..09ddeec 100644 --- a/arm9/source/vram_code.s +++ b/arm9/source/vram_code.s @@ -358,6 +358,9 @@ gba_start_bkpt_vram: mcr p15, 0, r0, c7, c10, 4 - //to boot without intro set this to 0xB4 - ldr r0,= (gGbaBios + 0x68) + ldr r2,= gEmuSettingSkipIntro + ldr r2, [r2] + cmp r2, #1 + ldrne r0,= (gGbaBios + 0x68) //with intro + ldreq r0,= (gGbaBios + 0xB4) //without intro bx r0 \ No newline at end of file diff --git a/readme.md b/readme.md index 75e9bd3..d2c51fc 100644 --- a/readme.md +++ b/readme.md @@ -2,10 +2,11 @@ GBARunner2 =================== GBARunner2 is a hypervisor that runs GBA games on DS/DSi/3DS in DS mode. ## Usage Notes -- Place a GBA bios on your sd card. Either /bios.bin or /gba/bios.bin will work. +- Place a GBA bios on your sd card. Either /bios.bin, /gba/bios.bin or /_gba/bios.bin will work. - If you have a gba folder on the root of your sd, this folder will be opened by default - Make sure your games are SRAM patched if needed, this is most likely only the case for FLASH1M_V103 (use [gbata](http://www.no-intro.org/gbadat/tools/gbata7a-en.zip)) - If you are using GBARunner2 with TWiLightMenu on a DSi or 3DS with the SD card, make sure you use the dldi on ARM7 build +- The settings are accessed by pressing R on the rom selection menu. Settings are saved when leaving the settings menu ### Bios checksums A valid bios should have the following checksums: From 2dc841fa7ebe752d44b2622c25f29f04348b4f98 Mon Sep 17 00:00:00 2001 From: Gericom Date: Sat, 24 Aug 2019 23:49:42 +0200 Subject: [PATCH 2/8] Fix azure builds with git info in settings (#69) * Attempt to fix azure builds * Attempt 2 * Attempt 3 * Attempt 4 * Attempt 5 * Attempt 6 * Attempt 7 * Attempt 8 --- arm9/Makefile | 6 +++--- arm9/source/gui/SettingsScreen.vram.cpp | 19 ++++++++++++++++--- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/arm9/Makefile b/arm9/Makefile index 8be112e..10c46d3 100644 --- a/arm9/Makefile +++ b/arm9/Makefile @@ -45,10 +45,10 @@ ifdef ENABLE_WRAM_ICACHE endif GIT_HASH := $(shell git rev-parse HEAD) -GIT_DATE := $(shell git log -1 "--date=format:%d-%m-%Y %H:%M" --pretty=format:%cd) -GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD) +GIT_DATE := $(shell git log -1 "--date=format:%d-%m-%Y\ %H:%M" --pretty=format:%cd) +GIT_BRANCH := $(shell git describe --all --exact-match | sed 's/heads\///' | sed 's/remotes\/origin\///') -CFLAGS += -DGIT_COMMIT_HASH="\"$(GIT_HASH)\"" -DGIT_COMMIT_DATE="\"$(GIT_DATE)\"" -DGIT_BRANCH="\"$(GIT_BRANCH)\"" +CFLAGS += -DGIT_COMMIT_HASH=$(GIT_HASH) -DGIT_COMMIT_DATE=$(GIT_DATE) -DGIT_BRANCH=$(GIT_BRANCH) CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -fnon-call-exceptions diff --git a/arm9/source/gui/SettingsScreen.vram.cpp b/arm9/source/gui/SettingsScreen.vram.cpp index 10c338e..a8141bc 100644 --- a/arm9/source/gui/SettingsScreen.vram.cpp +++ b/arm9/source/gui/SettingsScreen.vram.cpp @@ -16,6 +16,9 @@ #include "settings.h" #include "SettingsScreen.h" +#define STRINGIFY2(x) #x +#define STRINGIFY(x) STRINGIFY2(x) + static settings_item_t sEmulationItems[] = { { SETTINGS_ITEM_MODE_CHECK, "Display game on bottom screen", "", &gEmuSettingUseBottomScreen }, @@ -35,11 +38,21 @@ static settings_item_t sInputItems[] = { SETTINGS_ITEM_MODE_SIMPLE, "GBA SELECT button", "DS SELECT button", NULL } }; +#ifndef GIT_COMMIT_DATE +#define GIT_COMMIT_DATE unavailable +#endif +#ifndef GIT_COMMIT_HASH +#define GIT_COMMIT_HASH unavailable +#endif +#ifndef GIT_BRANCH +#define GIT_BRANCH unavailable +#endif + static settings_item_t sInfoItems[] = { - { SETTINGS_ITEM_MODE_SIMPLE, "Commit date", GIT_COMMIT_DATE, NULL }, - { SETTINGS_ITEM_MODE_SIMPLE, "Commit hash", GIT_COMMIT_HASH, NULL }, - { SETTINGS_ITEM_MODE_SIMPLE, "Branch", GIT_BRANCH, NULL }, + { SETTINGS_ITEM_MODE_SIMPLE, "Commit date", STRINGIFY(GIT_COMMIT_DATE), NULL }, + { SETTINGS_ITEM_MODE_SIMPLE, "Commit hash", STRINGIFY(GIT_COMMIT_HASH), NULL }, + { SETTINGS_ITEM_MODE_SIMPLE, "Branch", STRINGIFY(GIT_BRANCH), NULL }, { SETTINGS_ITEM_MODE_SIMPLE, "DLDI Cpu", #ifdef ARM7_DLDI "ARM 7" From b82841ca1946d5b9dd1ea5fdb5088b577827a120 Mon Sep 17 00:00:00 2001 From: Gericom Date: Fri, 6 Sep 2019 12:35:23 +0200 Subject: [PATCH 3/8] Fixed sound dma in games that don't use repeat mode This fixes sound in 007 - James Bond - Nightfire for example --- arm7/source/sound.cpp | 2 ++ arm9/source/emu/irq.s | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/arm7/source/sound.cpp b/arm7/source/sound.cpp index 94a4bd5..1ee6af3 100644 --- a/arm7/source/sound.cpp +++ b/arm7/source/sound.cpp @@ -222,6 +222,8 @@ void gba_sound_fifo_write(uint32_t samps) void gba_sound_set_src(uint32_t address) { + if(srcAddress == address - 16 || srcAddress == address || srcAddress == address + 16) + return; srcAddress = address; REG_TM[3].CNT_H = 0; sampcnter = 0; diff --git a/arm9/source/emu/irq.s b/arm9/source/emu/irq.s index d5f219f..45c3345 100644 --- a/arm9/source/emu/irq.s +++ b/arm9/source/emu/irq.s @@ -290,10 +290,18 @@ irq_handler_arm7_irq: ldrh lr, [r0, #0x16] tst lr, #(1 << 14) orrne r1, #(1 << 9) //dma 1 + //if no repeat, stop dma + tst lr, #(1 << 9) + biceq lr, #0x8000 + streqh lr, [r0, #0x16] ldrh lr, [r0, #0x22] tst lr, #(1 << 14) orrne r1, #(1 << 10) //dma 2 + //if no repeat, stop dma + tst lr, #(1 << 9) + biceq lr, #0x8000 + streqh lr, [r0, #0x22] str r1, [r2] From 96cd77d27b7697fcc9a0994a0280cab6779316fb Mon Sep 17 00:00:00 2001 From: Gericom Date: Sat, 7 Sep 2019 12:02:49 +0200 Subject: [PATCH 4/8] Fixed gb noise frequency --- arm7/source/gbsound.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/arm7/source/gbsound.cpp b/arm7/source/gbsound.cpp index 85961b3..8c73f77 100644 --- a/arm7/source/gbsound.cpp +++ b/arm7/source/gbsound.cpp @@ -122,6 +122,7 @@ static void updateChannelFreq(int channel) div = 4; div *= 2 << sChannel4ShiftFreq; int freq = 4194304 / div; + freq *= 8; if (freq == 0) { REG_SOUND[GB_CHANNEL_4_HW_L].TMR = 0; From 5793bc42aeacd2f1b7e04c3c8278afc88ea569ef Mon Sep 17 00:00:00 2001 From: Gericom Date: Sat, 7 Sep 2019 19:00:03 +0200 Subject: [PATCH 5/8] Improved is-nitro debugging --- arm9/source/dtcm_data.s | 5 ++++- arm9/source/setup.s | 40 +++++++++++++++++++++++++++++++--------- 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/arm9/source/dtcm_data.s b/arm9/source/dtcm_data.s index 81f58eb..aecae75 100644 --- a/arm9/source/dtcm_data.s +++ b/arm9/source/dtcm_data.s @@ -14,7 +14,10 @@ cpu_mode_switch_dtcm: .word pu_data_permissions .word data_abort_handler_cont_finish .word 0x08088008 //arm low instruction mask -.rept 12 +.global dbgDatarightsTmp +dbgDatarightsTmp: + .word 0 +.rept 11 .word 0 .endr .word data_abort_handler_arm_usr_sys //usr diff --git a/arm9/source/setup.s b/arm9/source/setup.s index 28477b2..764591e 100644 --- a/arm9/source/setup.s +++ b/arm9/source/setup.s @@ -61,11 +61,10 @@ itcm_setup_copyloop: //map the gba cartridge to the arm7 and nds card too ldr r0,= 0x4000204 ldrh r1, [r0] + orr r1, #0x80 //gba slot to arm7 (for is-nitro-emulator) #ifdef ARM7_DLDI - orr r1, #0x80 orr r1, #0x800 //card to arm7 #else - bic r1, #0x80 bic r1, #0x800 //card to arm9 #endif bic r1, #0x8000 //set memory priority to arm9 @@ -781,8 +780,16 @@ nibble_to_char: .global undef_inst_handler undef_inst_handler: - //TODO: if this is an is-nitro breakpoint (arm 0xE7FFFFFF; thumb 0xEFFF), pass control to the debugger - + mrc p15, 0, sp, c5, c0, 2 + eor sp, #0x33 + eor sp, #0x3300 + eor sp, #0x330000 + eor sp, #0x33000000 + cmp sp, #0 + movne sp, #1 //0 = unlocked, 1 = locked + add sp, #address_dtcm + strb sp, [sp, #0x4C] + //make use of the backwards compatible version //of the data rights register, so we can use 0xFFFFFFFF instead of 0x33333333 mov sp, #0xFFFFFFFF @@ -819,9 +826,10 @@ no_bkpt: bic r0, #(1 << 12) //and cache mcr p15, 0, r0, c1, c0, 0 - ldr r0,= 0x06202000 - ldr r1,= 0x46444E55 - str r1, [r0] + //ldr r0,= 0x06202000 + //ldr r1,= 0x46444E55 + //str r1, [r0] + mov r0, lr /* mov r0, lr ldr r1,= nibble_to_char @@ -963,6 +971,16 @@ fiq_hook: MRS SP, CPSR ORR SP, SP, #0xC0 MSR CPSR_cxsf, SP + + mrc p15, 0, sp, c5, c0, 2 + eor sp, #0x33 + eor sp, #0x3300 + eor sp, #0x330000 + eor sp, #0x33000000 + cmp sp, #0 + movne sp, #1 //0 = unlocked, 1 = locked + add sp, #address_dtcm + strb sp, [sp, #0x4C] //make use of the backwards compatible version //of the data rights register, so we can use 0xFFFFFFFF instead of 0x33333333 @@ -988,8 +1006,12 @@ fiq_hook_cp15_done: MSR SPSR_cxsf, LR LDMFD SP!, {R12,LR} - ldr sp,= pu_data_permissions - mcr p15, 0, sp, c5, c0, 2 + mov sp, #address_dtcm + ldrb sp, [sp, #0x4C] + cmp sp, #1 + + ldreq sp,= pu_data_permissions + mcreq p15, 0, sp, c5, c0, 2 SUBS PC, LR, #4 From 285f93cc6c23694726fd26e016f6818e97acbebc Mon Sep 17 00:00:00 2001 From: Gericom Date: Sat, 7 Sep 2019 19:08:48 +0200 Subject: [PATCH 6/8] Added patch for Banjo Pilot race condition --- arm9/source/gamePatches.vram.cpp | 13 +++++++++++++ arm9/source/gamePatches_asm.s | 18 ++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 arm9/source/gamePatches_asm.s diff --git a/arm9/source/gamePatches.vram.cpp b/arm9/source/gamePatches.vram.cpp index 77faca0..a792a7a 100644 --- a/arm9/source/gamePatches.vram.cpp +++ b/arm9/source/gamePatches.vram.cpp @@ -5,6 +5,8 @@ static const u8 sSomeBuggedMixer[16] = {0xF0, 0x1F, 0x2D, 0xE9, 0x0F, 0x00, 0xB0, 0xE8, 0x03, 0x32, 0xA0, 0xE1, 0x01, 0x20, 0x82, 0xE0}; +extern "C" void gptc_banjoPilotFix(); + void gptc_patchRom() { //fix a soundmixer that has ldm with writeback and rb in rlist @@ -16,6 +18,17 @@ void gptc_patchRom() u32 gameTitle1 = *(u32*)(MAIN_MEMORY_ADDRESS_ROM_DATA + 0xA4); u32 gameTitle2 = *(u32*)(MAIN_MEMORY_ADDRESS_ROM_DATA + 0xA8); u32 gameCode = *(u32*)(MAIN_MEMORY_ADDRESS_ROM_DATA + 0xAC); + if(gameTitle0 == 0x4A4E4142 && gameTitle1 == 0x4950204F && gameTitle2 == 0x544F4C && (gameCode == 0x504A4142 || gameCode == 0x454A4142)) + { + //Banjo-Pilot (Europe) (En,Fr,De,Es,It) and Banjo-Pilot (USA) + //Prevent race condition from happening + if (*(u32*)(MAIN_MEMORY_ADDRESS_ROM_DATA + 0x2134) == 0x4861089B) + { + *(u16*)(MAIN_MEMORY_ADDRESS_ROM_DATA + 0x2134) = 0x4800; //ldr r0,= gptc_banjoPilotFix+1 + *(u16*)(MAIN_MEMORY_ADDRESS_ROM_DATA + 0x2136) = 0x4700; //bx r0 + *(u32*)(MAIN_MEMORY_ADDRESS_ROM_DATA + 0x2138) = (u32)&gptc_banjoPilotFix + 1; + } + } /*else if (gameTitle0 == 0x4C415256 && gameTitle1 == 0x3320594C && gameTitle2 == 0x00000000 && gameCode == 0x45525641) { //V-Rally 3 (USA) (En,Fr,Es) diff --git a/arm9/source/gamePatches_asm.s b/arm9/source/gamePatches_asm.s new file mode 100644 index 0000000..479e28c --- /dev/null +++ b/arm9/source/gamePatches_asm.s @@ -0,0 +1,18 @@ +.section .vram +#include "consts.s" + +.thumb +.global gptc_banjoPilotFix +gptc_banjoPilotFix: + lsr r3, r3, #2 + ldr r0,= 0x84000000 + orr r3, r0 + ldr r0,= 0x040000BC + stmia r0!, {r1-r3} + sub r0, #0xC + ldr r3,= 0x030075A4 + str r3, [r0] + ldr r3,= 0x040000A0 + str r3, [r0, #4] + ldr r0,= 0x0800213F + bx r0 \ No newline at end of file From 89c01e3527fba136805b8c33ab127ea18c8d0ac2 Mon Sep 17 00:00:00 2001 From: Gericom Date: Sun, 8 Sep 2019 19:15:45 +0200 Subject: [PATCH 7/8] Added setting for enabling/disabling main memory i-cache --- arm9/source/gui/SettingsScreen.vram.cpp | 3 ++- arm9/source/settings.h | 1 + arm9/source/settings.vram.cpp | 6 ++++++ arm9/source/vram_code.s | 10 ++++++++++ 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/arm9/source/gui/SettingsScreen.vram.cpp b/arm9/source/gui/SettingsScreen.vram.cpp index a8141bc..ac613cb 100644 --- a/arm9/source/gui/SettingsScreen.vram.cpp +++ b/arm9/source/gui/SettingsScreen.vram.cpp @@ -24,7 +24,8 @@ static settings_item_t sEmulationItems[] = { SETTINGS_ITEM_MODE_CHECK, "Display game on bottom screen", "", &gEmuSettingUseBottomScreen }, //{ SETTINGS_ITEM_MODE_CHECK, "Enable autosaving", "Writes back the save to sd after a game saves", &gEmuSettingAutoSave }, { SETTINGS_ITEM_MODE_CHECK, "Enable center and mask", "Centers the game with a border. Adds 1 frame delay", &gEmuSettingCenterMask }, - //{ SETTINGS_ITEM_MODE_CHECK, "Enable wram i-cache", "Boosts speed, but some games may crash", &gEmuSettingWramICache }, + { SETTINGS_ITEM_MODE_CHECK, "Enable DS main memory i-cache", "Boosts speed, but causes timing bugs in a few games", &gEmuSettingMainMemICache }, + //{ SETTINGS_ITEM_MODE_CHECK, "Enable wram i-cache", "Boosts speed, but some games may crash", &gEmuSettingWramICache }, { SETTINGS_ITEM_MODE_CHECK, "Skip bios intro", "Directly boot the game without playing the intro", &gEmuSettingSkipIntro } }; diff --git a/arm9/source/settings.h b/arm9/source/settings.h index 5566aa8..afa5e9f 100644 --- a/arm9/source/settings.h +++ b/arm9/source/settings.h @@ -3,6 +3,7 @@ extern u32 gEmuSettingUseBottomScreen; //extern u32 gEmuSettingAutoSave; extern u32 gEmuSettingCenterMask; +extern u32 gEmuSettingMainMemICache; //extern u32 gEmuSettingWramICache; extern u32 gEmuSettingSkipIntro; diff --git a/arm9/source/settings.vram.cpp b/arm9/source/settings.vram.cpp index fa802d5..f3e6e86 100644 --- a/arm9/source/settings.vram.cpp +++ b/arm9/source/settings.vram.cpp @@ -18,6 +18,8 @@ static const char* sEmuSettingAutoSaveName = "autoSave"; u32 gEmuSettingAutoSave; static const char* sEmuSettingCenterMaskName = "centerMask"; u32 gEmuSettingCenterMask; +static const char* sEmuSettingMainMemICacheName = "mainMemICache"; +u32 gEmuSettingMainMemICache; static const char* sEmuSettingWramICacheName = "wramICache"; u32 gEmuSettingWramICache; static const char* sEmuSettingSkipIntroName = "skipIntro"; @@ -28,6 +30,7 @@ static void loadDefaultSettings() gEmuSettingUseBottomScreen = false; gEmuSettingAutoSave = true; gEmuSettingCenterMask = true; + gEmuSettingMainMemICache = true; gEmuSettingWramICache = true; gEmuSettingSkipIntro = false; } @@ -51,6 +54,8 @@ static void iniPropertyCallback(void* arg, const char* section, const char* key, gEmuSettingAutoSave = parseBoolean(value, true); else if(!strcmp(key, sEmuSettingCenterMaskName)) gEmuSettingCenterMask = parseBoolean(value, true); + else if(!strcmp(key, sEmuSettingMainMemICacheName)) + gEmuSettingMainMemICache = parseBoolean(value, true); else if(!strcmp(key, sEmuSettingWramICacheName)) gEmuSettingWramICache = parseBoolean(value, true); else if(!strcmp(key, sEmuSettingSkipIntroName)) @@ -76,6 +81,7 @@ bool settings_save() writer.WriteBooleanProperty(sEmuSettingUseBottomScreenName, gEmuSettingUseBottomScreen); //writer.WriteBooleanProperty(sEmuSettingAutoSaveName, gEmuSettingAutoSave); writer.WriteBooleanProperty(sEmuSettingCenterMaskName, gEmuSettingCenterMask); + writer.WriteBooleanProperty(sEmuSettingMainMemICacheName, gEmuSettingMainMemICache); //writer.WriteBooleanProperty(sEmuSettingWramICacheName, gEmuSettingWramICache); writer.WriteBooleanProperty(sEmuSettingSkipIntroName, gEmuSettingSkipIntro); f_close(&vram_cd->fil); diff --git a/arm9/source/vram_code.s b/arm9/source/vram_code.s index 09ddeec..b54cc33 100644 --- a/arm9/source/vram_code.s +++ b/arm9/source/vram_code.s @@ -341,6 +341,16 @@ gba_start_bkpt_vram: ldr r0,= 0x05000000 ldr r1,= 0x7FFF strh r1, [r0] + + ldr r2,= gEmuSettingMainMemICache + ldr r2, [r2] + cmp r2, #1 + beq 1f + //disable main memory i-cache + mrc p15, 0, r0, c2, c0, 1 + bic r0, #(1 << 5) + mcr p15, 0, r0, c2, c0, 1 +1: mrc p15, 0, r0, c1, c0, 0 //orr r0, #(1<<15) orr r0, #(1 | (1 << 2)) //enable pu and data cache From ce32975f2a7b99cee2b2b0a2810ad9b59e074fc4 Mon Sep 17 00:00:00 2001 From: Gericom Date: Wed, 11 Sep 2019 20:09:12 +0200 Subject: [PATCH 8/8] Implemented rtc support --- arm7/source/main.cpp | 13 +- arm7/source/sound.cpp | 2 +- arm9/source/emu/handle_address_write.s | 17 ++- arm9/source/emu/romGpio.h | 15 +++ arm9/source/emu/romGpio.vram.cpp | 130 ++++++++++++++++++ arm9/source/emu/romGpioRtc.h | 4 + arm9/source/emu/romGpioRtc.vram.cpp | 177 +++++++++++++++++++++++++ arm9/source/sd_access.cpp | 6 +- {arm7/source => common}/fifo.h | 0 9 files changed, 358 insertions(+), 6 deletions(-) create mode 100644 arm9/source/emu/romGpio.h create mode 100644 arm9/source/emu/romGpio.vram.cpp create mode 100644 arm9/source/emu/romGpioRtc.h create mode 100644 arm9/source/emu/romGpioRtc.vram.cpp rename {arm7/source => common}/fifo.h (100%) diff --git a/arm7/source/main.cpp b/arm7/source/main.cpp index 428457b..fc40b8e 100644 --- a/arm7/source/main.cpp +++ b/arm7/source/main.cpp @@ -5,7 +5,7 @@ #include "gbsound.h" #include "save.h" #include "dldi_handler.h" -#include "fifo.h" +#include "../../common/fifo.h" #include "../../common/common_defs.s" static void vblank_handler() @@ -186,6 +186,17 @@ int main() } break; } + case 0xAA550100: //get rtc data + { + u8 dateTime[8]; + u8 cmd = READ_TIME_AND_DATE; + rtcTransaction(&cmd, 1, dateTime, 7); + cmd = READ_STATUS_REG1; + rtcTransaction(&cmd, 1, &dateTime[7], 1); + REG_SEND_FIFO = *(u32*)&dateTime[0]; + REG_SEND_FIFO = *(u32*)&dateTime[4]; + break; + } case 0x040000A0: while (REG_FIFO_CNT & FIFO_CNT_EMPTY); val = REG_RECV_FIFO; diff --git a/arm7/source/sound.cpp b/arm7/source/sound.cpp index 1ee6af3..0329558 100644 --- a/arm7/source/sound.cpp +++ b/arm7/source/sound.cpp @@ -1,7 +1,7 @@ #include #include #include "timer.h" -#include "fifo.h" +#include "../../common/fifo.h" #include "../../common/sd_vram.h" #include "lock.h" #include "sound.h" diff --git a/arm9/source/emu/handle_address_write.s b/arm9/source/emu/handle_address_write.s index 94259ca..d597750 100644 --- a/arm9/source/emu/handle_address_write.s +++ b/arm9/source/emu/handle_address_write.s @@ -99,7 +99,7 @@ write_address_from_handler_16bit: .word write_address_ignore .word write_address_from_handler_vram_16 .word write_address_ignore - .word write_address_ignore + .word write_address_from_handler_rom_gpio_16 .word write_address_ignore .word write_address_ignore .word write_address_ignore @@ -144,6 +144,21 @@ write_address_from_handler_vram_16: strh r11, [r10] bx lr +write_address_from_handler_rom_gpio_16: + ldr r13,= 0x080000C4 + subs r13, r9, r13 + bxlt lr + cmp r13, #0x4 + bxgt lr + ldr sp,= address_dtcm + (16 * 1024) + push {r0-r3,lr} + mov r0, r9 + mov r1, r11 + ldr r12,= rio_write + blx r12 + pop {r0-r3,lr} + bx lr + write_address_from_handler_sram_16: ldr r12,= 0x01FF0000 bic r10, r9, r12 diff --git a/arm9/source/emu/romGpio.h b/arm9/source/emu/romGpio.h new file mode 100644 index 0000000..667c061 --- /dev/null +++ b/arm9/source/emu/romGpio.h @@ -0,0 +1,15 @@ +#pragma once + +typedef u16 RomGpioHwMask; + +#define RIO_NONE 0 +#define RIO_RTC (1 << 0) +#define RIO_LIGHT (1 << 1) + +extern u16 gRioGpioData; +extern u16 gRioGpioDirection; +extern u16 gRioGpioControl; + +void rio_init(RomGpioHwMask forceHwMask); +extern "C" void rio_write(u32 addr, u16 val); +void rio_invalidate(); \ No newline at end of file diff --git a/arm9/source/emu/romGpio.vram.cpp b/arm9/source/emu/romGpio.vram.cpp new file mode 100644 index 0000000..a7c0c33 --- /dev/null +++ b/arm9/source/emu/romGpio.vram.cpp @@ -0,0 +1,130 @@ +#include "vram.h" +#include "consts.s" +#include "romGpioRtc.h" +#include "romGpio.h" + +struct game_hw_info_t +{ + u32 gameCode; + RomGpioHwMask hardware; +}; + +#define GAMECODE(x) ((((x) & 0xFF) << 24) | ((((x) >> 8) & 0xFF) << 16) | ((((x) >> 16) & 0xFF) << 8) | ((x) >> 24)) + +static game_hw_info_t sGameHardwareTable[] = +{ + // Boktai: The Sun is in Your Hand + { GAMECODE('U3IJ'), RIO_RTC | RIO_LIGHT }, + { GAMECODE('U3IE'), RIO_RTC | RIO_LIGHT }, + { GAMECODE('U3IP'), RIO_RTC | RIO_LIGHT }, + + // Boktai 2: Solar Boy Django + { GAMECODE('U32J'), RIO_RTC | RIO_LIGHT }, + { GAMECODE('U32E'), RIO_RTC | RIO_LIGHT }, + { GAMECODE('U32P'), RIO_RTC | RIO_LIGHT }, + + // Pokemon Ruby + { GAMECODE('AXVJ'), RIO_RTC }, + { GAMECODE('AXVE'), RIO_RTC }, + { GAMECODE('AXVP'), RIO_RTC }, + { GAMECODE('AXVI'), RIO_RTC }, + { GAMECODE('AXVS'), RIO_RTC }, + { GAMECODE('AXVD'), RIO_RTC }, + { GAMECODE('AXVF'), RIO_RTC }, + + // Pokemon Sapphire + { GAMECODE('AXPJ'), RIO_RTC }, + { GAMECODE('AXPE'), RIO_RTC }, + { GAMECODE('AXPP'), RIO_RTC }, + { GAMECODE('AXPI'), RIO_RTC }, + { GAMECODE('AXPS'), RIO_RTC }, + { GAMECODE('AXPD'), RIO_RTC }, + { GAMECODE('AXPF'), RIO_RTC }, + + // Pokemon Emerald + { GAMECODE('BPEJ'), RIO_RTC }, + { GAMECODE('BPEE'), RIO_RTC }, + { GAMECODE('BPEP'), RIO_RTC }, + { GAMECODE('BPEI'), RIO_RTC }, + { GAMECODE('BPES'), RIO_RTC }, + { GAMECODE('BPED'), RIO_RTC }, + { GAMECODE('BPEF'), RIO_RTC }, + + // RockMan EXE 4.5 - Real Operation + { GAMECODE('BR4J'), RIO_RTC }, + + // Sennen Kazoku + { GAMECODE('BKAJ'), RIO_RTC }, + + // Shin Bokura no Taiyou: Gyakushuu no Sabata + { GAMECODE('U33J'), RIO_RTC | RIO_LIGHT }, +}; + +#define RIO_REG_DATA 0xC4 +#define RIO_REG_DIRECTION 0xC6 +#define RIO_REG_CONTROL 0xC8 + +static RomGpioHwMask sGpioHwMask; + +u16 gRioGpioData; +u16 gRioGpioDirection; +u16 gRioGpioControl; + +void rio_init(RomGpioHwMask forceHwMask) +{ + sGpioHwMask = forceHwMask; + u32 gameCode = *(u32*)(MAIN_MEMORY_ADDRESS_ROM_DATA + 0xAC); + for(int i = 0; i < sizeof(sGameHardwareTable) / sizeof(sGameHardwareTable[0]); i++) + { + if(sGameHardwareTable[i].gameCode == gameCode) + { + sGpioHwMask = sGameHardwareTable[i].hardware | forceHwMask; + break; + } + } + gRioGpioData = 0; + gRioGpioDirection = 0; + gRioGpioControl = 0; + if(sGpioHwMask & RIO_RTC) + rio_rtcInit(); +} + +static void updateHardware() +{ + if(sGpioHwMask & RIO_RTC) + rio_rtcUpdate(); +} + +extern "C" void rio_write(u32 addr, u16 val) +{ + switch(addr - 0x08000000) + { + case RIO_REG_DATA: + gRioGpioData = (gRioGpioData & ~gRioGpioDirection) | (val & gRioGpioDirection); + updateHardware(); + break; + case RIO_REG_DIRECTION: + gRioGpioDirection = val & 0xF; + break; + case RIO_REG_CONTROL: + gRioGpioControl = val & 1; + break; + } + rio_invalidate(); +} + +void rio_invalidate() +{ + if(gRioGpioControl) + { + *(u16*)(MAIN_MEMORY_ADDRESS_ROM_DATA + RIO_REG_DATA) = gRioGpioData; + *(u16*)(MAIN_MEMORY_ADDRESS_ROM_DATA + RIO_REG_DIRECTION) = gRioGpioDirection; + *(u16*)(MAIN_MEMORY_ADDRESS_ROM_DATA + RIO_REG_CONTROL) = gRioGpioControl; + } + else + { + *(u16*)(MAIN_MEMORY_ADDRESS_ROM_DATA + RIO_REG_DATA) = 0; + *(u16*)(MAIN_MEMORY_ADDRESS_ROM_DATA + RIO_REG_DIRECTION) = 0; + *(u16*)(MAIN_MEMORY_ADDRESS_ROM_DATA + RIO_REG_CONTROL) = 0; + } +} \ No newline at end of file diff --git a/arm9/source/emu/romGpioRtc.h b/arm9/source/emu/romGpioRtc.h new file mode 100644 index 0000000..f249688 --- /dev/null +++ b/arm9/source/emu/romGpioRtc.h @@ -0,0 +1,4 @@ +#pragma once + +void rio_rtcInit(); +void rio_rtcUpdate(); \ No newline at end of file diff --git a/arm9/source/emu/romGpioRtc.vram.cpp b/arm9/source/emu/romGpioRtc.vram.cpp new file mode 100644 index 0000000..7eefe52 --- /dev/null +++ b/arm9/source/emu/romGpioRtc.vram.cpp @@ -0,0 +1,177 @@ +#include "sd_access.h" +#include "../../common/fifo.h" +#include "romGpio.h" +#include "romGpioRtc.h" + +//based on https://github.com/mgba-emu/mgba/blob/master/src/gba/hardware.c + +#define RTC_COMMAND_MAGIC 0x06 +#define RTC_COMMAND_MAGIC_MASK 0x0F +#define RTC_COMMAND_CMD_MASK 0x70 +#define RTC_COMMAND_CMD_SHIFT 4 +#define RTC_COMMAND_READ 0x80 + +#define RTC_CMD_RESET 0 +#define RTC_CMD_DATETIME 2 +#define RTC_CMD_FORCE_IRQ 3 +#define RTC_CMD_CONTROL 4 +#define RTC_CMD_TIME 6 + +static u16 sRtcTransferState; +static u16 sRtcBits; +static u16 sRtcBitCount; +static u16 sRtcCommand; +static u16 sRtcCommandActive; +static u16 sRtcBytesLeft; + +static u16 sRtcControl; + +static u8 sRtcDateTime[8]; + +void rio_rtcInit() +{ + sRtcTransferState = 0; + sRtcBits = 0; + sRtcBitCount = 0; + sRtcCommand = 0; + sRtcCommandActive = 0; + sRtcBytesLeft = 0; + + sRtcControl = 0x40; +} + +static void updateDateTime() +{ + REG_SEND_FIFO = 0xAA550100; + while (*((vu32*)0x04000184) & (1 << 8)); + *(u32*)&sRtcDateTime[0] = REG_RECV_FIFO; + while (*((vu32*)0x04000184) & (1 << 8)); + *(u32*)&sRtcDateTime[4] = REG_RECV_FIFO; + MI_WriteByte(&sRtcDateTime[4], sRtcDateTime[4] & 0x3F); +} + +static void processByte() +{ + sRtcBytesLeft--; + if(!sRtcCommandActive) + { + if((sRtcBits & RTC_COMMAND_MAGIC_MASK) == RTC_COMMAND_MAGIC) + { + sRtcCommand = sRtcBits; + switch ((sRtcCommand & RTC_COMMAND_CMD_MASK) >> RTC_COMMAND_CMD_SHIFT) + { + case RTC_CMD_RESET: + sRtcControl = 0; + sRtcBytesLeft = 0; + break; + case RTC_CMD_DATETIME: + updateDateTime(); + sRtcBytesLeft = 7; + break; + case RTC_CMD_FORCE_IRQ: + sRtcBytesLeft = 0; + break; + case RTC_CMD_CONTROL: + sRtcBytesLeft = 1; + break; + case RTC_CMD_TIME: + updateDateTime(); + sRtcBytesLeft = 3; + break; + default: + sRtcBytesLeft = 0; + break; + } + sRtcCommandActive = sRtcBytesLeft > 0; + } + } + else + { + switch ((sRtcCommand & RTC_COMMAND_CMD_MASK) >> RTC_COMMAND_CMD_SHIFT) + { + case RTC_CMD_FORCE_IRQ: + //todo + break; + case RTC_CMD_CONTROL: + sRtcControl = sRtcBits; + break; + } + } + + sRtcBits = 0; + sRtcBitCount = 0; + if(!sRtcBytesLeft) + { + sRtcCommandActive = 0; + sRtcCommand = 0; + } +} + +static u32 getOutputBit() +{ + if(!sRtcCommandActive) + return 0; + u8 outByte = 0; + switch ((sRtcCommand & RTC_COMMAND_CMD_MASK) >> RTC_COMMAND_CMD_SHIFT) + { + case RTC_CMD_DATETIME: + case RTC_CMD_TIME: + outByte = sRtcDateTime[7 - sRtcBytesLeft]; + break; + case RTC_CMD_CONTROL: + outByte = sRtcControl; + break; + } + return (outByte >> sRtcBitCount) & 1; +} + +void rio_rtcUpdate() +{ + switch(sRtcTransferState) + { + case 0: + if((gRioGpioData & 5) == 1) + sRtcTransferState = 1; + break; + case 1: + if((gRioGpioData & 5) == 5) + sRtcTransferState = 2; + else if((gRioGpioData & 5) != 1) + sRtcTransferState = 0; + break; + case 2: + if(!(gRioGpioData & 1)) + sRtcBits = (sRtcBits & ~(1 << sRtcBitCount)) | (((gRioGpioData >> 1) & 1) << sRtcBitCount); + else if(gRioGpioData & 4) + { + if(sRtcCommand & RTC_COMMAND_READ) + { + gRioGpioData = (gRioGpioData & gRioGpioDirection) | ((5 | (getOutputBit() << 1)) & ~gRioGpioDirection); + rio_invalidate(); + if(++sRtcBitCount == 8) + { + sRtcBitCount = 0; + if(--sRtcBytesLeft <= 0) + { + sRtcCommandActive = 0; + sRtcCommand = 0; + } + } + } + else if(++sRtcBitCount == 8) + processByte(); + } + else + { + sRtcBits = 0; + sRtcBitCount = 0; + sRtcCommandActive = 0; + sRtcCommand = 0; + sRtcBytesLeft = 0; + sRtcTransferState = gRioGpioData & 1; + gRioGpioData = (gRioGpioData & gRioGpioDirection) | (1 & ~gRioGpioDirection); + rio_invalidate(); + } + break; + } +} \ No newline at end of file diff --git a/arm9/source/sd_access.cpp b/arm9/source/sd_access.cpp index d7540ed..02bebe4 100644 --- a/arm9/source/sd_access.cpp +++ b/arm9/source/sd_access.cpp @@ -1,6 +1,7 @@ #include #include #include "vram.h" +#include "../../common/fifo.h" #include "vector.h" #include "string.h" #include "vramheap.h" @@ -14,9 +15,7 @@ #include "settings.h" #include "bios.h" #include "crc16.h" - -#define REG_SEND_FIFO (*((vu32*)0x04000188)) -#define REG_RECV_FIFO (*((vu32*)0x04100000)) +#include "emu/romGpio.h" typedef enum KEYPAD_BITS { @@ -253,6 +252,7 @@ extern "C" PUT_IN_VRAM void sd_init(uint8_t* bios_dst) vram_cd->sd_info.cluster_shift = 31 - __builtin_clz(vram_cd->sd_info.nr_sectors_per_cluster * 512); vram_cd->sd_info.cluster_mask = (1 << vram_cd->sd_info.cluster_shift) - 1; initialize_cache(); + rio_init(RIO_NONE); *(vu8*)0x04000243 = 0x80; } diff --git a/arm7/source/fifo.h b/common/fifo.h similarity index 100% rename from arm7/source/fifo.h rename to common/fifo.h