summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKiritoDv <kiritodev01@gmail.com>2024-03-24 02:01:28 -0600
committerKiritoDv <kiritodev01@gmail.com>2024-04-06 04:32:13 -0600
commit641a43cbf9b4f4c4f545218e201fb58bbe15fcd7 (patch)
tree50ecef61c66e171580ef1a09c2d3a9fc32591768 /src
parent126a55aa0eadaf8b2ed8f370cbba63368be7a964 (diff)
First compilation, we just need more stupid assets
Diffstat (limited to 'src')
-rw-r--r--src/audio/audio_general.c2
-rw-r--r--src/audio/audio_load.c33
-rw-r--r--src/audio/audio_synthesis.c8
-rw-r--r--src/audio/audio_thread.c36
-rw-r--r--src/buffers.c1
-rw-r--r--src/dmatable.c156
-rw-r--r--src/engine/fox_360.c6
-rw-r--r--src/engine/fox_load.c35
-rw-r--r--src/engine/fox_load_inits.c9
-rw-r--r--src/engine/fox_save.c12
-rw-r--r--src/engine/guPerspectiveF.c40
-rw-r--r--src/engine/lookat.c73
-rw-r--r--src/libc_sprintf.c46
-rw-r--r--src/libultra/gu/cosf.c2
-rw-r--r--src/libultra/gu/lookat.c2
-rw-r--r--src/libultra/gu/mtxutil.c3
-rw-r--r--src/libultra/gu/ortho.c3
-rw-r--r--src/libultra/gu/perspective.c2
-rw-r--r--src/libultra/gu/sinf.c2
-rw-r--r--src/libultra/gu/sqrtf.c4
-rw-r--r--src/libultra/io/ai.c2
-rw-r--r--src/libultra/io/aisetfreq.c2
-rw-r--r--src/libultra/libc/ldiv.c2
-rw-r--r--src/libultra/libc/string.c2
-rw-r--r--src/libultra/libc/xldtob.c4
-rw-r--r--src/libultra/libc/xlitob.c4
-rw-r--r--src/libultra/libc/xprintf.c4
-rw-r--r--src/overlays/ovl_i4/fox_bo.c2
-rw-r--r--src/overlays/ovl_menu/fox_title.h2
-rw-r--r--src/port/Engine.cpp119
-rw-r--r--src/port/Engine.h32
-rw-r--r--src/port/GBIMiddleware.cpp45
-rw-r--r--src/port/Game.cpp31
-rw-r--r--src/port/Variables.cpp6
-rw-r--r--src/port/ui/ImguiUI.cpp508
-rw-r--r--src/port/ui/ImguiUI.h16
-rw-r--r--src/port/ui/ResolutionEditor.cpp422
-rw-r--r--src/port/ui/ResolutionEditor.h19
-rw-r--r--src/port/ui/UIWidgets.cpp1033
-rw-r--r--src/port/ui/UIWidgets.h209
-rw-r--r--src/sys/sys_fault.c2
-rw-r--r--src/sys/sys_joybus.c24
-rw-r--r--src/sys/sys_lib.c13
-rw-r--r--src/sys/sys_main.c219
-rw-r--r--src/sys/sys_matrix.c44
-rw-r--r--src/sys/sys_timer.c4
46 files changed, 2891 insertions, 354 deletions
diff --git a/src/audio/audio_general.c b/src/audio/audio_general.c
index ff1247ba..1e4f5b00 100644
--- a/src/audio/audio_general.c
+++ b/src/audio/audio_general.c
@@ -1,6 +1,6 @@
#include "sys.h"
#include "sf64audio_provisional.h"
-#include "context.h"
+#include "sf64context.h"
#include "audiothread_cmd.h"
#include "audioseq_cmd.h"
diff --git a/src/audio/audio_load.c b/src/audio/audio_load.c
index 9a87a93b..e74e9ab3 100644
--- a/src/audio/audio_load.c
+++ b/src/audio/audio_load.c
@@ -296,7 +296,7 @@ s32 AudioLoad_SyncLoadInstrument(s32 fontId, s32 instId, s32 drumId) {
void AudioLoad_AsyncLoadSampleBank(s32 sampleBankId, s32 nChunks, s32 retData, OSMesgQueue* retQueue) {
if (AudioLoad_AsyncLoadInner(2, AudioLoad_GetLoadTableIndex(2, sampleBankId), nChunks, retData, retQueue) == NULL) {
- osSendMesg(retQueue, NULL, 0);
+ osSendMesg(retQueue, OS_MESG_PTR(NULL), 0);
}
}
@@ -742,7 +742,7 @@ void* AudioLoad_AsyncLoadInner(s32 tableType, s32 id, s32 nChunks, s32 retData,
ramAddr = AudioLoad_SearchCaches(tableType, id);
if (ramAddr != NULL) {
loadStatus = 2;
- osSendMesg(retQueue, (void*) (retData << 0x18), 0);
+ osSendMesg(retQueue, OS_MESG_32(retData << 0x18), 0);
} else {
table = AudioLoad_GetLoadTable(tableType);
size = table->entries[id].size;
@@ -842,21 +842,9 @@ void AudioLoad_Init(void) {
for (; dwordsLeft >= 0; dwordsLeft--) {
*clearContext++ = 0;
}
- switch (osTvType) {
- case OS_TV_PAL:
- gMaxTempoTvTypeFactors = 20.03042f;
- gRefreshRate = 50;
- break;
- case OS_TV_MPAL:
- gMaxTempoTvTypeFactors = 16.546f;
- gRefreshRate = 60;
- break;
- default:
- case OS_TV_NTSC:
- gMaxTempoTvTypeFactors = 16.713f;
- gRefreshRate = 60;
- break;
- }
+ // TODO: osTVType should be unnecessary
+ gMaxTempoTvTypeFactors = 16.713f;
+ gRefreshRate = 60;
AudioThread_Init();
for (i = 0; i < 3; i++) {
gAiBuffLengths[i] = 0xA0;
@@ -1084,7 +1072,7 @@ AudioAsyncLoad* AudioLoad_StartAsyncLoad(u32 devAddr, u8* ramAddr, u32 size, s32
asyncLoad->delay = 3;
asyncLoad->medium = medium;
- asyncLoad->retMsg = retMesg;
+ asyncLoad->retMsg = OS_MESG_32(retMesg);
osCreateMesgQueue(&asyncLoad->msgQueue, &asyncLoad->msg, 1);
return asyncLoad;
@@ -1128,7 +1116,7 @@ void AudioLoad_ProcessAsyncLoad(AudioAsyncLoad* asyncLoad, s32 resetStatus) {
}
}
if (asyncLoad->bytesRemaining == 0) {
- temp = asyncLoad->retMsg;
+ temp = asyncLoad->retMsg.data32;
pad1 = (temp >> 0x10) & 0xFF;
sp24 = (temp >> 8) & 0xFF;
pad2 = temp & 0xFF;
@@ -1352,17 +1340,18 @@ s32 AudioLoad_ProcessSamplePreloads(s32 resetStatus) {
s32 sampleAddr;
u32 size;
s32 nChunks;
+ OSMesg mesg;
if (gPreloadSampleStackTop > 0) {
if (resetStatus != 0) {
- if (osRecvMesg(&gPreloadSampleQueue, (OSMesg) &preloadIndex, 0)) {}
+ if (osRecvMesg(&gPreloadSampleQueue, &mesg, 0)) {}
gPreloadSampleStackTop = 0;
return false;
}
- if (osRecvMesg(&gPreloadSampleQueue, (OSMesg) &preloadIndex, 0) == -1) {
+ if (osRecvMesg(&gPreloadSampleQueue, &mesg, 0) == -1) {
return false;
}
- // "Receive %d\n"
+ preloadIndex = mesg.data32;
preloadIndex >>= 0x18;
if (gPreloadSampleStack[preloadIndex].isFree == 0) {
diff --git a/src/audio/audio_synthesis.c b/src/audio/audio_synthesis.c
index 44042134..128c342c 100644
--- a/src/audio/audio_synthesis.c
+++ b/src/audio/audio_synthesis.c
@@ -1215,22 +1215,22 @@ Acmd* func_8000B51C(Acmd* aList, NoteSubEu* noteSub, NoteSynthesisState* synthSt
switch (delaySide) {
case 1:
aEnvMixer(aList++, dmemSrc, aiBufLen, 0, 0, ((temp_a1 & 0x80) >> 7),
- noteSub->bitField0.stereoStrongRight, noteSub->bitField0.stereoStrongLeft, 0x65B1C9E1);
+ noteSub->bitField0.stereoStrongRight, noteSub->bitField0.stereoStrongLeft, 0x65B1C9E1, 0);
break;
case 2:
aEnvMixer(aList++, dmemSrc, aiBufLen, 0, 0, ((temp_a1 & 0x80) >> 7),
- noteSub->bitField0.stereoStrongRight, noteSub->bitField0.stereoStrongLeft, 0x9965C9E1);
+ noteSub->bitField0.stereoStrongRight, noteSub->bitField0.stereoStrongLeft, 0x9965C9E1, 0);
break;
default:
aEnvMixer(aList++, dmemSrc, aiBufLen, 0, 0, ((temp_a1 & 0x80) >> 7),
- noteSub->bitField0.stereoStrongRight, noteSub->bitField0.stereoStrongLeft, 0x99B1C9E1);
+ noteSub->bitField0.stereoStrongRight, noteSub->bitField0.stereoStrongLeft, 0x99B1C9E1, 0);
break;
}
} else {
aEnvSetup1(aList++, (temp_a1 & 0x7F), var_a2, var_t0, var_a3);
aEnvSetup2(aList++, temp_t1, temp_t2);
aEnvMixer(aList++, dmemSrc, aiBufLen, 0, 0, ((temp_a1 & 0x80) >> 7), noteSub->bitField0.stereoStrongRight,
- noteSub->bitField0.stereoStrongLeft, 0x99B1C9E1);
+ noteSub->bitField0.stereoStrongLeft, 0x99B1C9E1, 0);
}
return aList;
diff --git a/src/audio/audio_thread.c b/src/audio/audio_thread.c
index 8d383393..e1e3248e 100644
--- a/src/audio/audio_thread.c
+++ b/src/audio/audio_thread.c
@@ -49,15 +49,15 @@ SPTask* AudioThread_CreateTask(void) {
OSTask_t* task;
u16* sp40;
s32 pad3C;
- u32 sp38;
- u32 sp34;
+ OSMesg sp38;
+ OSMesg sp34;
s32 pad30;
gAudioTaskCountQ++;
if ((gAudioTaskCountQ % gAudioBufferParams.specUnk4) != 0) {
return gWaitingAudioTask;
}
- osSendMesg(gAudioTaskStartQueue, (OSMesg) gAudioTaskCountQ, 0);
+ osSendMesg(gAudioTaskStartQueue, OS_MESG_32(gAudioTaskCountQ), 0);
gAudioTaskIndexQ ^= 1;
gCurAiBuffIndex++;
gCurAiBuffIndex %= 3;
@@ -71,15 +71,15 @@ SPTask* AudioThread_CreateTask(void) {
gCurAudioFrameDmaCount = 0;
AudioLoad_DecreaseSampleDmaTtls();
AudioLoad_ProcessLoads(gResetStatus);
- if (osRecvMesg(gAudioUnkQueue, (OSMesg) &sp38, 0) != -1) {
+ if (osRecvMesg(gAudioUnkQueue, &sp38, 0) != -1) {
if (gResetStatus == 0) {
gResetStatus = 5;
}
- gAudioSpecId = sp38;
+ gAudioSpecId = sp38.data32;
}
if ((gResetStatus != 0) && (AudioHeap_ResetStep() == 0)) {
if (gResetStatus == 0) {
- osSendMesg(gAudioResetQueue, (OSMesg) (s32) gAudioSpecId, 0);
+ osSendMesg(gAudioResetQueue, OS_MESG_32((s32) gAudioSpecId), 0);
}
gWaitingAudioTask = NULL;
return NULL;
@@ -102,8 +102,8 @@ SPTask* AudioThread_CreateTask(void) {
if (gAiBuffLengths[sp4C] > gAudioBufferParams.maxAiBufferLength) {
gAiBuffLengths[sp4C] = gAudioBufferParams.maxAiBufferLength;
}
- while (osRecvMesg(gThreadCmdProcQueue, (OSMesg) &sp34, 0) != -1) {
- AudioThread_ProcessCmds(sp34);
+ while (osRecvMesg(gThreadCmdProcQueue, &sp34, 0) != -1) {
+ AudioThread_ProcessCmds(sp34.data32);
}
gCurAbiCmdBuffer = func_80009B64(gCurAbiCmdBuffer, &sp50, sp40, gAiBuffLengths[sp4C]);
gAudioRandom = osGetCount() * (gAudioRandom + gAudioTaskCountQ);
@@ -112,19 +112,19 @@ SPTask* AudioThread_CreateTask(void) {
sp4C = gAudioTaskIndexQ;
gAudioCurTask->msgQueue = NULL;
- gAudioCurTask->msg = NULL;
+ gAudioCurTask->msg = OS_MESG_PTR(NULL);
task = &gAudioCurTask->task.t;
task->type = 2;
task->flags = 0;
- task->ucode_boot = rspbootTextStart;
- task->ucode_boot_size = (uintptr_t) rspbootTextEnd - (uintptr_t) rspbootTextStart;
-
- task->ucode = aspMainTextStart;
- task->ucode_data = aspMainDataStart;
- task->ucode_size = SP_UCODE_SIZE;
- task->ucode_data_size = (aspMainDataEnd - aspMainDataStart) * 8;
+ // task->ucode_boot = rspbootTextStart;
+ // task->ucode_boot_size = (uintptr_t) rspbootTextEnd - (uintptr_t) rspbootTextStart;
+ //
+ // task->ucode = aspMainTextStart;
+ // task->ucode_data = aspMainDataStart;
+ // task->ucode_size = SP_UCODE_SIZE;
+ // task->ucode_data_size = (aspMainDataEnd - aspMainDataStart) * 8;
task->dram_stack = NULL;
task->dram_stack_size = 0;
@@ -282,7 +282,7 @@ void AudioThread_ScheduleProcessCmds(void) {
D_800C7C70 = (u8) (gThreadCmdWritePos - gThreadCmdReadPos + 0x100);
}
msg = (((gThreadCmdReadPos & 0xFF) << 8) | (gThreadCmdWritePos & 0xFF));
- osSendMesg(gThreadCmdProcQueue, (OSMesg) msg, 0);
+ osSendMesg(gThreadCmdProcQueue, OS_MESG_32(msg), 0);
gThreadCmdReadPos = gThreadCmdWritePos;
}
@@ -420,7 +420,7 @@ void AudioThread_ResetAudioHeap(s32 specId) {
// clang-format on
AudioThread_ResetCmdQueue();
- osSendMesg(gAudioUnkQueue, (OSMesg) specId, 0);
+ osSendMesg(gAudioUnkQueue, OS_MESG_32(specId), 0);
}
void AudioThread_PreNMIReset(void) {
diff --git a/src/buffers.c b/src/buffers.c
index 3ca949c8..50ac0cb0 100644
--- a/src/buffers.c
+++ b/src/buffers.c
@@ -1,6 +1,5 @@
#include "global.h"
-u64 gDramStack[SP_DRAM_STACK_SIZE64];
u8 gOSYieldData[OS_YIELD_DATA_SIZE];
FrameBuffer gZBuffer; // z buffer
u8 gTaskOutputBuffer[0x30000];
diff --git a/src/dmatable.c b/src/dmatable.c
index b2b4f77c..b8231e06 100644
--- a/src/dmatable.c
+++ b/src/dmatable.c
@@ -6,82 +6,82 @@
{ NULL, { NULL, NULL }, false }
DmaEntry gDmaTable[90] = {
- { SEGMENT_ROM_START(makerom), { SEGMENT_ROM_START(makerom), SEGMENT_ROM_END(makerom) }, false },
- { SEGMENT_ROM_START(main), { SEGMENT_ROM_START(main), SEGMENT_ROM_END(main) }, false },
- { SEGMENT_ROM_START(dma_table), { SEGMENT_ROM_START(dma_table), SEGMENT_ROM_END(dma_table) }, false },
- { SEGMENT_ROM_START(audio_seq), { SEGMENT_ROM_START(audio_seq), SEGMENT_ROM_END(audio_seq) }, false },
- { SEGMENT_ROM_START(audio_bank), { SEGMENT_ROM_START(audio_bank), SEGMENT_ROM_END(audio_bank) }, false },
- { SEGMENT_ROM_START(audio_table), { SEGMENT_ROM_START(audio_table), SEGMENT_ROM_END(audio_table) }, false },
- { SEGMENT_ROM_START(ast_common), { SEGMENT_ROM_START(ast_common), SEGMENT_ROM_END(ast_common) }, false },
- { SEGMENT_ROM_START(ast_bg_space), { SEGMENT_ROM_START(ast_bg_space), SEGMENT_ROM_END(ast_bg_space) }, false },
- { SEGMENT_ROM_START(ast_bg_planet), { SEGMENT_ROM_START(ast_bg_planet), SEGMENT_ROM_END(ast_bg_planet) }, false },
- { SEGMENT_ROM_START(ast_arwing), { SEGMENT_ROM_START(ast_arwing), SEGMENT_ROM_END(ast_arwing) }, false },
- { SEGMENT_ROM_START(ast_landmaster),
- { SEGMENT_ROM_START(ast_landmaster), SEGMENT_ROM_END(ast_landmaster) },
- false },
- { SEGMENT_ROM_START(ast_blue_marine),
- { SEGMENT_ROM_START(ast_blue_marine), SEGMENT_ROM_END(ast_blue_marine) },
- false },
- { SEGMENT_ROM_START(ast_versus), { SEGMENT_ROM_START(ast_versus), SEGMENT_ROM_END(ast_versus) }, false },
- { SEGMENT_ROM_START(ast_enmy_planet),
- { SEGMENT_ROM_START(ast_enmy_planet), SEGMENT_ROM_END(ast_enmy_planet) },
- false },
- { SEGMENT_ROM_START(ast_enmy_space),
- { SEGMENT_ROM_START(ast_enmy_space), SEGMENT_ROM_END(ast_enmy_space) },
- false },
- { SEGMENT_ROM_START(ast_great_fox), { SEGMENT_ROM_START(ast_great_fox), SEGMENT_ROM_END(ast_great_fox) }, false },
- { SEGMENT_ROM_START(ast_star_wolf), { SEGMENT_ROM_START(ast_star_wolf), SEGMENT_ROM_END(ast_star_wolf) }, false },
- { SEGMENT_ROM_START(ast_allies), { SEGMENT_ROM_START(ast_allies), SEGMENT_ROM_END(ast_allies) }, false },
- { SEGMENT_ROM_START(ast_corneria), { SEGMENT_ROM_START(ast_corneria), SEGMENT_ROM_END(ast_corneria) }, false },
- { SEGMENT_ROM_START(ast_meteo), { SEGMENT_ROM_START(ast_meteo), SEGMENT_ROM_END(ast_meteo) }, false },
- { SEGMENT_ROM_START(ast_titania), { SEGMENT_ROM_START(ast_titania), SEGMENT_ROM_END(ast_titania) }, false },
- { SEGMENT_ROM_START(ast_7_ti_2), { SEGMENT_ROM_START(ast_7_ti_2), SEGMENT_ROM_END(ast_7_ti_2) }, false },
- { SEGMENT_ROM_START(ast_8_ti), { SEGMENT_ROM_START(ast_8_ti), SEGMENT_ROM_END(ast_8_ti) }, false },
- { SEGMENT_ROM_START(ast_9_ti), { SEGMENT_ROM_START(ast_9_ti), SEGMENT_ROM_END(ast_9_ti) }, false },
- { SEGMENT_ROM_START(ast_A_ti), { SEGMENT_ROM_START(ast_A_ti), SEGMENT_ROM_END(ast_A_ti) }, false },
- { SEGMENT_ROM_START(ast_7_ti_1), { SEGMENT_ROM_START(ast_7_ti_1), SEGMENT_ROM_END(ast_7_ti_1) }, false },
- { SEGMENT_ROM_START(ast_sector_x), { SEGMENT_ROM_START(ast_sector_x), SEGMENT_ROM_END(ast_sector_x) }, false },
- { SEGMENT_ROM_START(ast_sector_z), { SEGMENT_ROM_START(ast_sector_z), SEGMENT_ROM_END(ast_sector_z) }, false },
- { SEGMENT_ROM_START(ast_aquas), { SEGMENT_ROM_START(ast_aquas), SEGMENT_ROM_END(ast_aquas) }, false },
- { SEGMENT_ROM_START(ast_area_6), { SEGMENT_ROM_START(ast_area_6), SEGMENT_ROM_END(ast_area_6) }, false },
- { SEGMENT_ROM_START(ast_venom_1), { SEGMENT_ROM_START(ast_venom_1), SEGMENT_ROM_END(ast_venom_1) }, false },
- { SEGMENT_ROM_START(ast_venom_2), { SEGMENT_ROM_START(ast_venom_2), SEGMENT_ROM_END(ast_venom_2) }, false },
- { SEGMENT_ROM_START(ast_ve1_boss), { SEGMENT_ROM_START(ast_ve1_boss), SEGMENT_ROM_END(ast_ve1_boss) }, false },
- { SEGMENT_ROM_START(ast_bolse), { SEGMENT_ROM_START(ast_bolse), SEGMENT_ROM_END(ast_bolse) }, false },
- { SEGMENT_ROM_START(ast_fortuna), { SEGMENT_ROM_START(ast_fortuna), SEGMENT_ROM_END(ast_fortuna) }, false },
- { SEGMENT_ROM_START(ast_sector_y), { SEGMENT_ROM_START(ast_sector_y), SEGMENT_ROM_END(ast_sector_y) }, false },
- { SEGMENT_ROM_START(ast_solar), { SEGMENT_ROM_START(ast_solar), SEGMENT_ROM_END(ast_solar) }, false },
- { SEGMENT_ROM_START(ast_zoness), { SEGMENT_ROM_START(ast_zoness), SEGMENT_ROM_END(ast_zoness) }, false },
- { SEGMENT_ROM_START(ast_katina), { SEGMENT_ROM_START(ast_katina), SEGMENT_ROM_END(ast_katina) }, false },
- { SEGMENT_ROM_START(ast_macbeth), { SEGMENT_ROM_START(ast_macbeth), SEGMENT_ROM_END(ast_macbeth) }, false },
- { SEGMENT_ROM_START(ast_warp_zone), { SEGMENT_ROM_START(ast_warp_zone), SEGMENT_ROM_END(ast_warp_zone) }, false },
- { SEGMENT_ROM_START(ast_title), { SEGMENT_ROM_START(ast_title), SEGMENT_ROM_END(ast_title) }, false },
- { SEGMENT_ROM_START(ast_map), { SEGMENT_ROM_START(ast_map), SEGMENT_ROM_END(ast_map) }, false },
- { SEGMENT_ROM_START(ast_option), { SEGMENT_ROM_START(ast_option), SEGMENT_ROM_END(ast_option) }, false },
- { SEGMENT_ROM_START(ast_vs_menu), { SEGMENT_ROM_START(ast_vs_menu), SEGMENT_ROM_END(ast_vs_menu) }, false },
- { SEGMENT_ROM_START(ast_font), { SEGMENT_ROM_START(ast_font), SEGMENT_ROM_END(ast_font) }, false },
- { SEGMENT_ROM_START(ast_font_3d), { SEGMENT_ROM_START(ast_font_3d), SEGMENT_ROM_END(ast_font_3d) }, false },
- { SEGMENT_ROM_START(ast_andross), { SEGMENT_ROM_START(ast_andross), SEGMENT_ROM_END(ast_andross) }, false },
- { SEGMENT_ROM_START(ast_logo), { SEGMENT_ROM_START(ast_logo), SEGMENT_ROM_END(ast_logo) }, false },
- { SEGMENT_ROM_START(ast_ending), { SEGMENT_ROM_START(ast_ending), SEGMENT_ROM_END(ast_ending) }, false },
- { SEGMENT_ROM_START(ast_ending_award_front),
- { SEGMENT_ROM_START(ast_ending_award_front), SEGMENT_ROM_END(ast_ending_award_front) },
- false },
- { SEGMENT_ROM_START(ast_ending_award_back),
- { SEGMENT_ROM_START(ast_ending_award_back), SEGMENT_ROM_END(ast_ending_award_back) },
- false },
- { SEGMENT_ROM_START(ast_ending_expert),
- { SEGMENT_ROM_START(ast_ending_expert), SEGMENT_ROM_END(ast_ending_expert) },
- false },
- { SEGMENT_ROM_START(ast_training), { SEGMENT_ROM_START(ast_training), SEGMENT_ROM_END(ast_training) }, false },
- { SEGMENT_ROM_START(ast_radio), { SEGMENT_ROM_START(ast_radio), SEGMENT_ROM_END(ast_radio) }, false },
- { SEGMENT_ROM_START(ovl_i1), { SEGMENT_ROM_START(ovl_i1), SEGMENT_ROM_END(ovl_i1) }, false },
- { SEGMENT_ROM_START(ovl_i2), { SEGMENT_ROM_START(ovl_i2), SEGMENT_ROM_END(ovl_i2) }, false },
- { SEGMENT_ROM_START(ovl_i3), { SEGMENT_ROM_START(ovl_i3), SEGMENT_ROM_END(ovl_i3) }, false },
- { SEGMENT_ROM_START(ovl_i4), { SEGMENT_ROM_START(ovl_i4), SEGMENT_ROM_END(ovl_i4) }, false },
- { SEGMENT_ROM_START(ovl_i5), { SEGMENT_ROM_START(ovl_i5), SEGMENT_ROM_END(ovl_i5) }, false },
- { SEGMENT_ROM_START(ovl_i6), { SEGMENT_ROM_START(ovl_i6), SEGMENT_ROM_END(ovl_i6) }, false },
- { SEGMENT_ROM_START(ovl_menu), { SEGMENT_ROM_START(ovl_menu), SEGMENT_ROM_END(ovl_menu) }, false },
- { SEGMENT_ROM_START(ovl_ending), { SEGMENT_ROM_START(ovl_ending), SEGMENT_ROM_END(ovl_ending) }, false },
- { SEGMENT_ROM_START(ovl_unused), { SEGMENT_ROM_START(ovl_unused), SEGMENT_ROM_END(ovl_unused) }, false },
+ // { SEGMENT_ROM_START(makerom), { SEGMENT_ROM_START(makerom), SEGMENT_ROM_END(makerom) }, false },
+ // { SEGMENT_ROM_START(main), { SEGMENT_ROM_START(main), SEGMENT_ROM_END(main) }, false },
+ // { SEGMENT_ROM_START(dma_table), { SEGMENT_ROM_START(dma_table), SEGMENT_ROM_END(dma_table) }, false },
+ // { SEGMENT_ROM_START(audio_seq), { SEGMENT_ROM_START(audio_seq), SEGMENT_ROM_END(audio_seq) }, false },
+ // { SEGMENT_ROM_START(audio_bank), { SEGMENT_ROM_START(audio_bank), SEGMENT_ROM_END(audio_bank) }, false },
+ // { SEGMENT_ROM_START(audio_table), { SEGMENT_ROM_START(audio_table), SEGMENT_ROM_END(audio_table) }, false },
+ // { SEGMENT_ROM_START(ast_common), { SEGMENT_ROM_START(ast_common), SEGMENT_ROM_END(ast_common) }, false },
+ // { SEGMENT_ROM_START(ast_bg_space), { SEGMENT_ROM_START(ast_bg_space), SEGMENT_ROM_END(ast_bg_space) }, false },
+ // { SEGMENT_ROM_START(ast_bg_planet), { SEGMENT_ROM_START(ast_bg_planet), SEGMENT_ROM_END(ast_bg_planet) }, false },
+ // { SEGMENT_ROM_START(ast_arwing), { SEGMENT_ROM_START(ast_arwing), SEGMENT_ROM_END(ast_arwing) }, false },
+ // { SEGMENT_ROM_START(ast_landmaster),
+ // { SEGMENT_ROM_START(ast_landmaster), SEGMENT_ROM_END(ast_landmaster) },
+ // false },
+ // { SEGMENT_ROM_START(ast_blue_marine),
+ // { SEGMENT_ROM_START(ast_blue_marine), SEGMENT_ROM_END(ast_blue_marine) },
+ // false },
+ // { SEGMENT_ROM_START(ast_vs_player), { SEGMENT_ROM_START(ast_vs_player), SEGMENT_ROM_END(ast_vs_player) }, false },
+ // { SEGMENT_ROM_START(ast_enmy_planet),
+ // { SEGMENT_ROM_START(ast_enmy_planet), SEGMENT_ROM_END(ast_enmy_planet) },
+ // false },
+ // { SEGMENT_ROM_START(ast_enmy_space),
+ // { SEGMENT_ROM_START(ast_enmy_space), SEGMENT_ROM_END(ast_enmy_space) },
+ // false },
+ // { SEGMENT_ROM_START(ast_great_fox), { SEGMENT_ROM_START(ast_great_fox), SEGMENT_ROM_END(ast_great_fox) }, false },
+ // { SEGMENT_ROM_START(ast_star_wolf), { SEGMENT_ROM_START(ast_star_wolf), SEGMENT_ROM_END(ast_star_wolf) }, false },
+ // { SEGMENT_ROM_START(ast_allies), { SEGMENT_ROM_START(ast_allies), SEGMENT_ROM_END(ast_allies) }, false },
+ // { SEGMENT_ROM_START(ast_corneria), { SEGMENT_ROM_START(ast_corneria), SEGMENT_ROM_END(ast_corneria) }, false },
+ // { SEGMENT_ROM_START(ast_meteo), { SEGMENT_ROM_START(ast_meteo), SEGMENT_ROM_END(ast_meteo) }, false },
+ // { SEGMENT_ROM_START(ast_titania), { SEGMENT_ROM_START(ast_titania), SEGMENT_ROM_END(ast_titania) }, false },
+ // { SEGMENT_ROM_START(ast_7_ti_2), { SEGMENT_ROM_START(ast_7_ti_2), SEGMENT_ROM_END(ast_7_ti_2) }, false },
+ // { SEGMENT_ROM_START(ast_8_ti), { SEGMENT_ROM_START(ast_8_ti), SEGMENT_ROM_END(ast_8_ti) }, false },
+ // { SEGMENT_ROM_START(ast_9_ti), { SEGMENT_ROM_START(ast_9_ti), SEGMENT_ROM_END(ast_9_ti) }, false },
+ // { SEGMENT_ROM_START(ast_A_ti), { SEGMENT_ROM_START(ast_A_ti), SEGMENT_ROM_END(ast_A_ti) }, false },
+ // { SEGMENT_ROM_START(ast_7_ti_1), { SEGMENT_ROM_START(ast_7_ti_1), SEGMENT_ROM_END(ast_7_ti_1) }, false },
+ // { SEGMENT_ROM_START(ast_sector_x), { SEGMENT_ROM_START(ast_sector_x), SEGMENT_ROM_END(ast_sector_x) }, false },
+ // { SEGMENT_ROM_START(ast_sector_z), { SEGMENT_ROM_START(ast_sector_z), SEGMENT_ROM_END(ast_sector_z) }, false },
+ // { SEGMENT_ROM_START(ast_aquas), { SEGMENT_ROM_START(ast_aquas), SEGMENT_ROM_END(ast_aquas) }, false },
+ // { SEGMENT_ROM_START(ast_area_6), { SEGMENT_ROM_START(ast_area_6), SEGMENT_ROM_END(ast_area_6) }, false },
+ // { SEGMENT_ROM_START(ast_venom_1), { SEGMENT_ROM_START(ast_venom_1), SEGMENT_ROM_END(ast_venom_1) }, false },
+ // { SEGMENT_ROM_START(ast_venom_2), { SEGMENT_ROM_START(ast_venom_2), SEGMENT_ROM_END(ast_venom_2) }, false },
+ // { SEGMENT_ROM_START(ast_ve1_boss), { SEGMENT_ROM_START(ast_ve1_boss), SEGMENT_ROM_END(ast_ve1_boss) }, false },
+ // { SEGMENT_ROM_START(ast_bolse), { SEGMENT_ROM_START(ast_bolse), SEGMENT_ROM_END(ast_bolse) }, false },
+ // { SEGMENT_ROM_START(ast_fortuna), { SEGMENT_ROM_START(ast_fortuna), SEGMENT_ROM_END(ast_fortuna) }, false },
+ // { SEGMENT_ROM_START(ast_sector_y), { SEGMENT_ROM_START(ast_sector_y), SEGMENT_ROM_END(ast_sector_y) }, false },
+ // { SEGMENT_ROM_START(ast_solar), { SEGMENT_ROM_START(ast_solar), SEGMENT_ROM_END(ast_solar) }, false },
+ // { SEGMENT_ROM_START(ast_zoness), { SEGMENT_ROM_START(ast_zoness), SEGMENT_ROM_END(ast_zoness) }, false },
+ // { SEGMENT_ROM_START(ast_katina), { SEGMENT_ROM_START(ast_katina), SEGMENT_ROM_END(ast_katina) }, false },
+ // { SEGMENT_ROM_START(ast_macbeth), { SEGMENT_ROM_START(ast_macbeth), SEGMENT_ROM_END(ast_macbeth) }, false },
+ // { SEGMENT_ROM_START(ast_warp_zone), { SEGMENT_ROM_START(ast_warp_zone), SEGMENT_ROM_END(ast_warp_zone) }, false },
+ // { SEGMENT_ROM_START(ast_title), { SEGMENT_ROM_START(ast_title), SEGMENT_ROM_END(ast_title) }, false },
+ // { SEGMENT_ROM_START(ast_map), { SEGMENT_ROM_START(ast_map), SEGMENT_ROM_END(ast_map) }, false },
+ // { SEGMENT_ROM_START(ast_option), { SEGMENT_ROM_START(ast_option), SEGMENT_ROM_END(ast_option) }, false },
+ // { SEGMENT_ROM_START(ast_versus), { SEGMENT_ROM_START(ast_versus), SEGMENT_ROM_END(ast_versus) }, false },
+ // { SEGMENT_ROM_START(ast_font), { SEGMENT_ROM_START(ast_font), SEGMENT_ROM_END(ast_font) }, false },
+ // { SEGMENT_ROM_START(ast_font_3d), { SEGMENT_ROM_START(ast_font_3d), SEGMENT_ROM_END(ast_font_3d) }, false },
+ // { SEGMENT_ROM_START(ast_andross), { SEGMENT_ROM_START(ast_andross), SEGMENT_ROM_END(ast_andross) }, false },
+ // { SEGMENT_ROM_START(ast_logo), { SEGMENT_ROM_START(ast_logo), SEGMENT_ROM_END(ast_logo) }, false },
+ // { SEGMENT_ROM_START(ast_ending), { SEGMENT_ROM_START(ast_ending), SEGMENT_ROM_END(ast_ending) }, false },
+ // { SEGMENT_ROM_START(ast_ending_award_front),
+ // { SEGMENT_ROM_START(ast_ending_award_front), SEGMENT_ROM_END(ast_ending_award_front) },
+ // false },
+ // { SEGMENT_ROM_START(ast_ending_award_back),
+ // { SEGMENT_ROM_START(ast_ending_award_back), SEGMENT_ROM_END(ast_ending_award_back) },
+ // false },
+ // { SEGMENT_ROM_START(ast_ending_expert),
+ // { SEGMENT_ROM_START(ast_ending_expert), SEGMENT_ROM_END(ast_ending_expert) },
+ // false },
+ // { SEGMENT_ROM_START(ast_training), { SEGMENT_ROM_START(ast_training), SEGMENT_ROM_END(ast_training) }, false },
+ // { SEGMENT_ROM_START(ast_radio), { SEGMENT_ROM_START(ast_radio), SEGMENT_ROM_END(ast_radio) }, false },
+ // { SEGMENT_ROM_START(ovl_i1), { SEGMENT_ROM_START(ovl_i1), SEGMENT_ROM_END(ovl_i1) }, false },
+ // { SEGMENT_ROM_START(ovl_i2), { SEGMENT_ROM_START(ovl_i2), SEGMENT_ROM_END(ovl_i2) }, false },
+ // { SEGMENT_ROM_START(ovl_i3), { SEGMENT_ROM_START(ovl_i3), SEGMENT_ROM_END(ovl_i3) }, false },
+ // { SEGMENT_ROM_START(ovl_i4), { SEGMENT_ROM_START(ovl_i4), SEGMENT_ROM_END(ovl_i4) }, false },
+ // { SEGMENT_ROM_START(ovl_i5), { SEGMENT_ROM_START(ovl_i5), SEGMENT_ROM_END(ovl_i5) }, false },
+ // { SEGMENT_ROM_START(ovl_i6), { SEGMENT_ROM_START(ovl_i6), SEGMENT_ROM_END(ovl_i6) }, false },
+ // { SEGMENT_ROM_START(ovl_menu), { SEGMENT_ROM_START(ovl_menu), SEGMENT_ROM_END(ovl_menu) }, false },
+ // { SEGMENT_ROM_START(ovl_ending), { SEGMENT_ROM_START(ovl_ending), SEGMENT_ROM_END(ovl_ending) }, false },
+ // { SEGMENT_ROM_START(ovl_unused), { SEGMENT_ROM_START(ovl_unused), SEGMENT_ROM_END(ovl_unused) }, false },
};
diff --git a/src/engine/fox_360.c b/src/engine/fox_360.c
index 9dbdfa93..2adec923 100644
--- a/src/engine/fox_360.c
+++ b/src/engine/fox_360.c
@@ -2272,10 +2272,12 @@ void ActorAllRange_Draw(Actor* actor) {
break;
}
} else if (gCurrentLevel == LEVEL_SECTOR_Z) {
- gSPDisplayList(gMasterDisp++, D_SZ_6004FE0) Matrix_Translate(gGfxMatrix, 0.0f, 0.0f, -60.0f, 1);
+ gSPDisplayList(gMasterDisp++, D_SZ_6004FE0);
+ Matrix_Translate(gGfxMatrix, 0.0f, 0.0f, -60.0f, 1);
func_edisplay_8005B1E8(actor, 2);
} else if (gCurrentLevel == LEVEL_BOLSE) {
- gSPDisplayList(gMasterDisp++, D_BO_6008770) Matrix_Push(&gGfxMatrix);
+ gSPDisplayList(gMasterDisp++, D_BO_6008770);
+ Matrix_Push(&gGfxMatrix);
Matrix_Translate(gGfxMatrix, 0.0f, 0.0f, -60.0f, 1);
func_edisplay_8005B1E8(actor, 2);
Matrix_Pop(&gGfxMatrix);
diff --git a/src/engine/fox_load.c b/src/engine/fox_load.c
index 556a6c50..5ad54e8c 100644
--- a/src/engine/fox_load.c
+++ b/src/engine/fox_load.c
@@ -27,22 +27,21 @@ OverlayInit sCurrentOverlay = {
};
void Overlay_LoadSegment(void* vRomAddress, void* dest, ptrdiff_t size) {
- s32 i;
-
- for (i = 0; gDmaTable[i].pRom.end != NULL; i++) {
- if (gDmaTable[i].vRomAddress == vRomAddress) {
- if (gDmaTable[i].compFlag == 0) {
- Lib_DmaRead(gDmaTable[i].pRom.start, dest, size);
- } else {
- Lib_FillScreen(true);
- sFillTimer = 3;
- D_game_80161A39 = true;
- Lib_DmaRead(gDmaTable[i].pRom.start, gFrameBuffers, SEGMENT_SIZE(gDmaTable[i].pRom));
- Mio0_Decompress(gFrameBuffers, dest);
- }
- break;
- }
- }
+ // s32 i;
+ // for (i = 0; gDmaTable[i].pRom.end != NULL; i++) {
+ // if (gDmaTable[i].vRomAddress == vRomAddress) {
+ // if (gDmaTable[i].compFlag == 0) {
+ // Lib_DmaRead(gDmaTable[i].pRom.start, dest, size);
+ // } else {
+ // Lib_FillScreen(true);
+ // sFillTimer = 3;
+ // D_80161A39 = true;
+ // Lib_DmaRead(gDmaTable[i].pRom.start, gFrameBuffers, SEGMENT_SIZE(gDmaTable[i].pRom));
+ // Mio0_Decompress(gFrameBuffers, dest);
+ // }
+ // break;
+ // }
+ // }
}
u8 Overlay_Init(OverlayInit* ovlInit) {
@@ -196,6 +195,6 @@ u8 Overlay_Load(u8 ovlSetup, u8 ovlStage) {
}
void Overlay_InitDma(void) {
- Lib_DmaRead(SEGMENT_ROM_START(dma_table), SEGMENT_VRAM_START(dma_table), SEGMENT_ROM_SIZE(dma_table));
- Overlay_LoadSegment(SEGMENT_ROM_START(ast_radio), SEGMENT_VRAM_START(ast_radio), SEGMENT_ROM_SIZE(ast_radio));
+ // Lib_DmaRead(SEGMENT_ROM_START(dma_table), SEGMENT_VRAM_START(dma_table), SEGMENT_ROM_SIZE(dma_table));
+ // Overlay_LoadSegment(SEGMENT_ROM_START(ast_radio), SEGMENT_VRAM_START(ast_radio), SEGMENT_ROM_SIZE(ast_radio));
}
diff --git a/src/engine/fox_load_inits.c b/src/engine/fox_load_inits.c
index 621f718b..580a27c8 100644
--- a/src/engine/fox_load_inits.c
+++ b/src/engine/fox_load_inits.c
@@ -4,12 +4,7 @@
{ NULL, NULL }
#define OVERLAY_OFFSETS(file) \
- { \
- { SEGMENT_ROM_START(file), SEGMENT_ROM_END(file) }, { SEGMENT_BSS_START(file), SEGMENT_BSS_END(file) }, \
- { SEGMENT_TEXT_START(file), SEGMENT_TEXT_END(file) }, { \
- SEGMENT_DATA_START(file), SEGMENT_RODATA_END(file) \
- } \
- }
+ NO_OVERLAY
#define NO_OVERLAY \
{ \
@@ -19,7 +14,7 @@
}
#define ROM_SEGMENT(file) \
- { SEGMENT_ROM_START(file), SEGMENT_ROM_END(file) }
+ NO_SEGMENT
OverlayInit sNoOvl_Logo[1] = {
{ NO_OVERLAY,
diff --git a/src/engine/fox_save.c b/src/engine/fox_save.c
index beb3357e..554ab310 100644
--- a/src/engine/fox_save.c
+++ b/src/engine/fox_save.c
@@ -39,26 +39,26 @@ u16 Save_Checksum(Save* arg0) {
}
s32 Save_Write(void) {
- void* sp1C;
+ OSMesg sp1C;
gSaveFile.save.checksum = Save_Checksum(&gSaveFile.save);
gSaveFile.backup = gSaveFile.save;
gSaveIOBuffer = gSaveFile;
- osSendMesg(&gSerialThreadMsgQueue, (OSMesg) SI_WRITE_SAVE, OS_MESG_PRI_NORMAL);
+ osSendMesg(&gSerialThreadMsgQueue, OS_MESG_32(SI_WRITE_SAVE), OS_MESG_PRI_NORMAL);
osRecvMesg(&gSaveMsgQueue, &sp1C, OS_MESG_BLOCK);
- if (sp1C != (OSMesg) SI_SAVE_SUCCESS) {
+ if (sp1C.data32 != SI_SAVE_SUCCESS) {
return -1;
}
return 0;
}
s32 Save_Read(void) {
- void* sp24;
+ OSMesg* sp24;
s32 i;
- osSendMesg(&gSerialThreadMsgQueue, (OSMesg) SI_READ_SAVE, OS_MESG_PRI_NORMAL);
+ osSendMesg(&gSerialThreadMsgQueue, OS_MESG_32(SI_READ_SAVE), OS_MESG_PRI_NORMAL);
osRecvMesg(&gSaveMsgQueue, &sp24, OS_MESG_BLOCK);
- if ((s32) sp24 != SI_SAVE_SUCCESS) {
+ if (sp24->data32 != SI_SAVE_SUCCESS) {
return -1;
}
diff --git a/src/engine/guPerspectiveF.c b/src/engine/guPerspectiveF.c
new file mode 100644
index 00000000..a7247534
--- /dev/null
+++ b/src/engine/guPerspectiveF.c
@@ -0,0 +1,40 @@
+#include <libultraship.h>
+#include <math.h>
+
+void guPerspectiveF(float mf[4][4], u16 *perspNorm, float fovy, float aspect, float near, float far,
+ float scale) {
+ float yscale;
+ int row;
+ int col;
+ guMtxIdentF(mf);
+ fovy *= GU_PI / 180.0;
+ yscale = cosf(fovy / 2) / sinf(fovy / 2);
+ mf[0][0] = yscale / aspect;
+ mf[1][1] = yscale;
+ mf[2][2] = (near + far) / (near - far);
+ mf[2][3] = -1;
+ mf[3][2] = 2 * near * far / (near - far);
+ mf[3][3] = 0.0f;
+ for (row = 0; row < 4; row++) {
+ for (col = 0; col < 4; col++) {
+ mf[row][col] *= scale;
+ }
+ }
+ if (perspNorm != NULL) {
+ if (near + far <= 2.0) {
+ *perspNorm = 65535;
+ } else {
+ *perspNorm = (double) (1 << 17) / (near + far);
+ if (*perspNorm <= 0) {
+ *perspNorm = 1;
+ }
+ }
+ }
+}
+
+void guPerspective(Mtx *m, u16 *perspNorm, float fovy, float aspect, float near, float far,
+ float scale) {
+ float mat[4][4];
+ guPerspectiveF(mat, perspNorm, fovy, aspect, near, far, scale);
+ guMtxF2L(mat, m);
+}
diff --git a/src/engine/lookat.c b/src/engine/lookat.c
new file mode 100644
index 00000000..e5060d24
--- /dev/null
+++ b/src/engine/lookat.c
@@ -0,0 +1,73 @@
+#include <libultraship.h>
+
+void guLookAtF(float mf[4][4], float xEye, float yEye, float zEye, float xAt, float yAt, float zAt, float xUp,
+ float yUp, float zUp) {
+ float len;
+ float xLook;
+ float yLook;
+ float zLook;
+ float xRight;
+ float yRight;
+ float zRight;
+
+ guMtxIdentF(mf);
+
+ xLook = xAt - xEye;
+ yLook = yAt - yEye;
+ zLook = zAt - zEye;
+
+ /* Negate because positive Z is behind us: */
+ len = -1.0 / guSqrtf(xLook * xLook + yLook * yLook + zLook * zLook);
+ xLook *= len;
+ yLook *= len;
+ zLook *= len;
+
+ /* Right = Up x Look */
+
+ xRight = yUp * zLook - zUp * yLook;
+ yRight = zUp * xLook - xUp * zLook;
+ zRight = xUp * yLook - yUp * xLook;
+ len = 1.0 / guSqrtf(xRight * xRight + yRight * yRight + zRight * zRight);
+ xRight *= len;
+ yRight *= len;
+ zRight *= len;
+
+ /* Up = Look x Right */
+
+ xUp = yLook * zRight - zLook * yRight;
+ yUp = zLook * xRight - xLook * zRight;
+ zUp = xLook * yRight - yLook * xRight;
+ len = 1.0 / guSqrtf(xUp * xUp + yUp * yUp + zUp * zUp);
+ xUp *= len;
+ yUp *= len;
+ zUp *= len;
+
+ mf[0][0] = xRight;
+ mf[1][0] = yRight;
+ mf[2][0] = zRight;
+ mf[3][0] = -(xEye * xRight + yEye * yRight + zEye * zRight);
+
+ mf[0][1] = xUp;
+ mf[1][1] = yUp;
+ mf[2][1] = zUp;
+ mf[3][1] = -(xEye * xUp + yEye * yUp + zEye * zUp);
+
+ mf[0][2] = xLook;
+ mf[1][2] = yLook;
+ mf[2][2] = zLook;
+ mf[3][2] = -(xEye * xLook + yEye * yLook + zEye * zLook);
+
+ mf[0][3] = 0;
+ mf[1][3] = 0;
+ mf[2][3] = 0;
+ mf[3][3] = 1;
+}
+
+void guLookAt(Mtx* m, float xEye, float yEye, float zEye, float xAt, float yAt, float zAt, float xUp, float yUp,
+ float zUp) {
+ float mf[4][4];
+
+ guLookAtF(mf, xEye, yEye, zEye, xAt, yAt, zAt, xUp, yUp, zUp);
+
+ guMtxF2L(mf, m);
+}
diff --git a/src/libc_sprintf.c b/src/libc_sprintf.c
index 0b2e506f..60af7d6e 100644
--- a/src/libc_sprintf.c
+++ b/src/libc_sprintf.c
@@ -6,26 +6,26 @@ void* proutSprintf(void* dst, const char* fmt, size_t size) {
return (void*) ((uintptr_t) memcpy(dst, fmt, size) + size);
}
-s32 vsprintf(char* dst, const char* fmt, va_list args) {
- s32 ret = _Printf((outfun*) proutSprintf, dst, fmt, args);
-
- if (ret > -1) {
- dst[ret] = 0;
- }
- return ret;
-}
-
-int sprintf(char* s, const char* fmt, ...) {
- s32 ret;
- va_list args;
- va_start(args, fmt);
-
- ret = _Printf((outfun*) proutSprintf, s, fmt, args);
-
- if (ret >= 0) {
- s[ret] = 0;
- }
- va_end(args);
-
- return ret;
-}
+// s32 vsprintf(char* dst, const char* fmt, va_list args) {
+// s32 ret = _Printf((outfun*) proutSprintf, dst, fmt, args);
+//
+// if (ret > -1) {
+// dst[ret] = 0;
+// }
+// return ret;
+// }
+//
+// int sprintf(char* s, const char* fmt, ...) {
+// s32 ret;
+// va_list args;
+// va_start(args, fmt);
+//
+// ret = _Printf((outfun*) proutSprintf, s, fmt, args);
+//
+// if (ret >= 0) {
+// s[ret] = 0;
+// }
+// va_end(args);
+//
+// return ret;
+// }
diff --git a/src/libultra/gu/cosf.c b/src/libultra/gu/cosf.c
index e67d5485..4e250569 100644
--- a/src/libultra/gu/cosf.c
+++ b/src/libultra/gu/cosf.c
@@ -10,7 +10,7 @@
* *
**************************************************************************/
-#include "PR/ultratypes.h"
+#include <libultra/types.h>
#include "PR/guint.h"
/* ====================================================================
diff --git a/src/libultra/gu/lookat.c b/src/libultra/gu/lookat.c
index df591319..9086aad8 100644
--- a/src/libultra/gu/lookat.c
+++ b/src/libultra/gu/lookat.c
@@ -1,4 +1,4 @@
-#include "PR/ultratypes.h"
+#include <libultra/types.h>
#include "PR/gbi.h"
#include "PR/gu.h"
diff --git a/src/libultra/gu/mtxutil.c b/src/libultra/gu/mtxutil.c
index 66dc44c3..e4521bb1 100644
--- a/src/libultra/gu/mtxutil.c
+++ b/src/libultra/gu/mtxutil.c
@@ -10,8 +10,7 @@
* *
**************************************************************************/
-#include "PR/ultratypes.h"
-#include "PR/guint.h"
+#include <libultraship.h>
void guMtxF2L(float mf[4][4], Mtx* m) {
int i, j;
diff --git a/src/libultra/gu/ortho.c b/src/libultra/gu/ortho.c
index f389ab26..3ce76557 100644
--- a/src/libultra/gu/ortho.c
+++ b/src/libultra/gu/ortho.c
@@ -1,5 +1,4 @@
-#include "PR/ultratypes.h"
-#include "PR/gu.h"
+#include <libultraship.h>
void guOrthoF(float mf[4][4], float l, float r, float b, float t, float n, float f, float scale) {
int i;
diff --git a/src/libultra/gu/perspective.c b/src/libultra/gu/perspective.c
index 9b54e888..850289d7 100644
--- a/src/libultra/gu/perspective.c
+++ b/src/libultra/gu/perspective.c
@@ -11,7 +11,7 @@
* *
**************************************************************************/
-#include "PR/ultratypes.h"
+#include <libultra/types.h>
#include "PR/guint.h"
extern f32 __cosf(f32);
diff --git a/src/libultra/gu/sinf.c b/src/libultra/gu/sinf.c
index b10dece6..f5264e7f 100644
--- a/src/libultra/gu/sinf.c
+++ b/src/libultra/gu/sinf.c
@@ -10,7 +10,7 @@
* *
**************************************************************************/
-#include "PR/ultratypes.h"
+#include <libultra/types.h>
#include "PR/guint.h"
/* ====================================================================
diff --git a/src/libultra/gu/sqrtf.c b/src/libultra/gu/sqrtf.c
index 57df68b3..fd51829c 100644
--- a/src/libultra/gu/sqrtf.c
+++ b/src/libultra/gu/sqrtf.c
@@ -1,5 +1,5 @@
-#include "PR/ultratypes.h"
-#include "libc/math.h"
+#include <libultra/types.h>
+#include "math.h"
f32 guSqrtf(f32 value) {
return sqrtf(value);
diff --git a/src/libultra/io/ai.c b/src/libultra/io/ai.c
index f297634f..b6c55165 100644
--- a/src/libultra/io/ai.c
+++ b/src/libultra/io/ai.c
@@ -1,4 +1,4 @@
-#include "libc/stdbool.h"
+#include "stdbool.h"
#include "PR/rcp.h"
s32 __osAiDeviceBusy(void) {
diff --git a/src/libultra/io/aisetfreq.c b/src/libultra/io/aisetfreq.c
index 6225e1ee..c1bc23db 100644
--- a/src/libultra/io/aisetfreq.c
+++ b/src/libultra/io/aisetfreq.c
@@ -1,4 +1,4 @@
-#include "PR/rcp.h"
+#include <libultraship.h>
extern s32 osViClock;
diff --git a/src/libultra/libc/ldiv.c b/src/libultra/libc/ldiv.c
index 2f6dace1..20be8d7a 100644
--- a/src/libultra/libc/ldiv.c
+++ b/src/libultra/libc/ldiv.c
@@ -1,4 +1,4 @@
-#include "libc/stdlib.h"
+#include "stdlib.h"
lldiv_t lldiv(long long numer, long long denom) {
lldiv_t val;
diff --git a/src/libultra/libc/string.c b/src/libultra/libc/string.c
index dc92907c..96aec169 100644
--- a/src/libultra/libc/string.c
+++ b/src/libultra/libc/string.c
@@ -1,4 +1,4 @@
-#include "PR/ultratypes.h"
+#include <libultra/types.h>
void* memcpy(void* s1, const void* s2, size_t n) {
unsigned char* su1 = (unsigned char*) s1;
diff --git a/src/libultra/libc/xldtob.c b/src/libultra/libc/xldtob.c
index 0327cc66..c5987284 100644
--- a/src/libultra/libc/xldtob.c
+++ b/src/libultra/libc/xldtob.c
@@ -1,5 +1,5 @@
-#include "libc/stdlib.h"
-#include "libc/string.h"
+#include "stdlib.h"
+#include "string.h"
#include "PR/xstdio.h"
// TODO: these come from headers
diff --git a/src/libultra/libc/xlitob.c b/src/libultra/libc/xlitob.c
index c74fd7ff..bbe26398 100644
--- a/src/libultra/libc/xlitob.c
+++ b/src/libultra/libc/xlitob.c
@@ -1,6 +1,6 @@
#include "PR/xstdio.h"
-#include "libc/string.h"
-#include "libc/stdlib.h"
+#include "string.h"
+#include "stdlib.h"
#define BUFF_LEN 0x18
diff --git a/src/libultra/libc/xprintf.c b/src/libultra/libc/xprintf.c
index f338f662..6fe74631 100644
--- a/src/libultra/libc/xprintf.c
+++ b/src/libultra/libc/xprintf.c
@@ -1,6 +1,6 @@
#include "macros.h"
-#include "libc/string.h"
-#include "libc/stdarg.h"
+#include "string.h"
+#include "stdarg.h"
#include "PR/xstdio.h"
// TODO: these come from headers
diff --git a/src/overlays/ovl_i4/fox_bo.c b/src/overlays/ovl_i4/fox_bo.c
index 73ea0119..c4211d01 100644
--- a/src/overlays/ovl_i4/fox_bo.c
+++ b/src/overlays/ovl_i4/fox_bo.c
@@ -2216,7 +2216,7 @@ void Bolse_80192264(void) {
gDPLoadTileTexture(gMasterDisp++, D_BO_600AD80, G_IM_FMT_RGBA, G_IM_SIZ_16b, 32, 32);
}
Matrix_SetGfxMtx(&gMasterDisp);
- gSPDisplayList(gMasterDisp++, D_BO_600BEC0)
+ gSPDisplayList(gMasterDisp++, D_BO_600BEC0);
}
Matrix_Pop(&gGfxMatrix);
}
diff --git a/src/overlays/ovl_menu/fox_title.h b/src/overlays/ovl_menu/fox_title.h
index f75cf80c..741224e1 100644
--- a/src/overlays/ovl_menu/fox_title.h
+++ b/src/overlays/ovl_menu/fox_title.h
@@ -219,7 +219,7 @@ void Title_8018DF0C(f32 arg0);
void Title_8018E058(void);
void Title_8018E200(void);
bool Title_8018EDC8(s32, Gfx **, Vec3f *, Vec3f *, void *);
-void Title_8018E67C(s32);
+void Title_8018E67C(s32);
void Title_8018F438(void);
void Title_80190144(void);
void Title_801903B8(void);
diff --git a/src/port/Engine.cpp b/src/port/Engine.cpp
new file mode 100644
index 00000000..b6a1f636
--- /dev/null
+++ b/src/port/Engine.cpp
@@ -0,0 +1,119 @@
+#include "Engine.h"
+#include "ui/ImguiUI.h"
+#include "ZAPDUtils/Utils/StringHelper.h"
+#include "libultraship/src/Context.h"
+
+#include <Fast3D/gfx_pc.h>
+#include <Fast3D/gfx_rendering_api.h>
+#include <SDL2/SDL_net.h>
+
+#include <utility>
+
+extern "C" {
+float gInterpolationStep = 0.0f;
+}
+
+GameEngine* GameEngine::Instance;
+
+GameEngine::GameEngine() {
+ std::vector<std::string> OTRFiles;
+ if (const std::string cube_path = LUS::Context::GetPathRelativeToAppDirectory("smcube.otr"); std::filesystem::exists(cube_path)) {
+ OTRFiles.push_back(cube_path);
+ }
+ if (const std::string sm64_otr_path = LUS::Context::GetPathRelativeToAppBundle("lylat.otr"); std::filesystem::exists(sm64_otr_path)) {
+ OTRFiles.push_back(sm64_otr_path);
+ }
+ if (const std::string patches_path = LUS::Context::GetPathRelativeToAppDirectory("mods"); !patches_path.empty() && std::filesystem::exists(patches_path)) {
+ if (std::filesystem::is_directory(patches_path)) {
+ for (const auto&p: std::filesystem::recursive_directory_iterator(patches_path)) {
+ if (StringHelper::IEquals(p.path().extension().string(), ".otr")) {
+ OTRFiles.push_back(p.path().generic_string());
+ }
+ }
+ }
+ }
+ this->context = LUS::Context::CreateInstance("Lylat64", "sf64", "lylat.cfg.json", OTRFiles,
+ {0xFF2B5A63, 0xE3DAA4E}, 3);
+ // this->context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(
+ // LUS::ResourceType::SAnim, "Animation", std::make_shared<CubeOS::AnimationFactory>());
+}
+
+void GameEngine::Create(){
+ const auto instance = Instance = new GameEngine();
+ GameUI::SetupGuiElements();
+}
+
+void GameEngine::Destroy(){
+
+}
+
+bool ShouldClearTextureCacheAtEndOfFrame = false;
+
+void GameEngine::StartFrame() const{
+ using LUS::KbScancode;
+ const int32_t dwScancode = this->context->GetWindow()->GetLastScancode();
+ this->context->GetWindow()->SetLastScancode(-1);
+
+ switch (dwScancode) {
+ case KbScancode::LUS_KB_TAB: {
+ // Toggle HD Assets
+ CVarSetInteger("gAltAssets", !CVarGetInteger("gAltAssets", 0));
+ ShouldClearTextureCacheAtEndOfFrame = true;
+ break;
+ }
+ default: break;
+ }
+ this->context->GetWindow()->StartFrame();
+}
+
+void GameEngine::ProcessFrame(void (*run_one_game_iter)()) const {
+ this->context->GetWindow()->MainLoop(run_one_game_iter);
+}
+
+void GameEngine::RunCommands(Gfx* Commands) {
+ gfx_run(Commands, {});
+ gfx_end_frame();
+
+ if (ShouldClearTextureCacheAtEndOfFrame) {
+ gfx_texture_cache_clear();
+ ShouldClearTextureCacheAtEndOfFrame = false;
+ }
+}
+
+void GameEngine::ProcessGfxCommands(Gfx* commands) {
+ RunCommands(commands);
+ Instance->context->GetWindow()->SetTargetFps(30);
+ Instance->context->GetWindow()->SetMaximumFrameLatency(1);
+}
+
+extern "C" uint32_t GameEngine_GetSampleRate() {
+ auto player = LUS::Context::GetInstance()->GetAudio()->GetAudioPlayer();
+ if (player == nullptr) {
+ return 0;
+ }
+
+ if (!player->IsInitialized()) {
+ return 0;
+ }
+
+ return player->GetSampleRate();
+}
+
+extern "C" uint32_t GameEngine_GetSamplesPerFrame(){
+ return SAMPLES_PER_FRAME;
+}
+
+// End
+
+extern "C" float GameEngine_GetAspectRatio() {
+ return gfx_current_dimensions.aspect_ratio;
+}
+
+extern "C" uint32_t GameEngine_GetGameVersion() {
+ return 0x00000001;
+}
+
+extern "C" int GameEngine_OTRSigCheck(const char* data) {
+ static const char* sOtrSignature = "__OTR__";
+ return strncmp(data, sOtrSignature, strlen(sOtrSignature)) == 0;
+} \ No newline at end of file
diff --git a/src/port/Engine.h b/src/port/Engine.h
new file mode 100644
index 00000000..85c8cd01
--- /dev/null
+++ b/src/port/Engine.h
@@ -0,0 +1,32 @@
+#pragma once
+#include "libultraship/src/Context.h"
+
+#ifdef __cplusplus
+#include <vector>
+#include <Fast3D/gfx_pc.h>
+
+#define SAMPLES_HIGH 544
+#define SAMPLES_LOW 528
+#define AUDIO_FRAMES_PER_UPDATE 2
+#define NUM_AUDIO_CHANNELS 2
+#define SAMPLES_PER_FRAME (SAMPLES_HIGH * NUM_AUDIO_CHANNELS * 2)
+
+class GameEngine {
+ public:
+ static GameEngine* Instance;
+
+ std::shared_ptr<LUS::Context> context;
+
+ GameEngine();
+ static void Create();
+ void StartFrame() const;
+ static void RunCommands(Gfx* Commands);
+ void ProcessFrame(void (*run_one_game_iter)()) const;
+ static void Destroy();
+ void ProcessGfxCommands(Gfx* commands);
+};
+#else
+void GameEngine_ProcessGfxCommands(Gfx* commands);
+float GameEngine_GetAspectRatio();
+int GameEngine_OTRSigCheck(char* imgData);
+#endif \ No newline at end of file
diff --git a/src/port/GBIMiddleware.cpp b/src/port/GBIMiddleware.cpp
new file mode 100644
index 00000000..ab8f0e0a
--- /dev/null
+++ b/src/port/GBIMiddleware.cpp
@@ -0,0 +1,45 @@
+#include <libultraship.h>
+
+#include "Engine.h"
+#include "DisplayList.h"
+#include "Array.h"
+
+extern "C" int GameEngine_OTRSigCheck(const char* data);
+
+extern "C" void gSPDisplayList(Gfx* pkt, Gfx* dl) {
+ char* imgData = (char*)dl;
+
+ if (GameEngine_OTRSigCheck(imgData) == 1) {
+ auto resource = LUS::Context::GetInstance()->GetResourceManager()->LoadResource(imgData);
+ auto res = std::static_pointer_cast<LUS::DisplayList>(resource);
+ dl = &res->Instructions[0];
+ }
+
+ __gSPDisplayList(pkt, dl);
+}
+
+extern "C" void gSPVertex(Gfx* pkt, uintptr_t v, int n, int v0) {
+
+ if (GameEngine_OTRSigCheck((char*)v) == 1) {
+ v = (uintptr_t) ResourceGetDataByName((char *) v);
+ }
+
+ __gSPVertex(pkt, v, n, v0);
+}
+
+extern "C" void gSPInvalidateTexCache(Gfx* pkt, uintptr_t texAddr) {
+ char* imgData = (char*)texAddr;
+
+ if (texAddr != 0 && GameEngine_OTRSigCheck(imgData)) {
+ auto res = LUS::Context::GetInstance()->GetResourceManager()->LoadResource(imgData);
+
+ if (res->GetInitData()->Type == LUS::ResourceType::DisplayList)
+ texAddr = (uintptr_t)&((std::static_pointer_cast<LUS::DisplayList>(res))->Instructions[0]);
+ else if (res->GetInitData()->Type == LUS::ResourceType::Array)
+ texAddr = (uintptr_t)(std::static_pointer_cast<LUS::Array>(res))->Vertices.data();
+ else {
+ texAddr = (uintptr_t) res->GetRawPointer();
+ }
+ }
+ __gSPInvalidateTexCache(pkt, texAddr);
+}
diff --git a/src/port/Game.cpp b/src/port/Game.cpp
new file mode 100644
index 00000000..ca47f686
--- /dev/null
+++ b/src/port/Game.cpp
@@ -0,0 +1,31 @@
+#include <libultraship.h>
+
+#include <Fast3D/gfx_pc.h>
+#include "Engine.h"
+
+extern "C"
+// void exec_display_list(SPTask *spTask) {
+// GameEngine::ProcessGfxCommands((Gfx *) spTask->task.t.data_ptr);
+// }
+
+void push_frame() {
+ // GameEngine::StartAudioFrame();
+ GameEngine::Instance->StartFrame();
+ // thread5_iteration();
+ // GameEngine::EndAudioFrame();
+}
+
+#ifdef _WIN32
+int SDL_main(int argc, char **argv) {
+#else
+int main(){
+#endif
+ GameEngine::Create();
+ // alloc_pool();
+ // audio_init();
+ // sound_init();
+ // thread5_game_loop();
+ GameEngine::Instance->ProcessFrame(push_frame);
+ GameEngine::Instance->Destroy();
+ return 0;
+} \ No newline at end of file
diff --git a/src/port/Variables.cpp b/src/port/Variables.cpp
new file mode 100644
index 00000000..f7ccf0eb
--- /dev/null
+++ b/src/port/Variables.cpp
@@ -0,0 +1,6 @@
+#include <libultraship.h>
+#include <Fast3D/gfx_pc.h>
+
+extern "C" {
+
+} \ No newline at end of file
diff --git a/src/port/ui/ImguiUI.cpp b/src/port/ui/ImguiUI.cpp
new file mode 100644
index 00000000..f4639cf4
--- /dev/null
+++ b/src/port/ui/ImguiUI.cpp
@@ -0,0 +1,508 @@
+#include "ImguiUI.h"
+#include "UIWidgets.h"
+#include "ResolutionEditor.h"
+
+#include <spdlog/spdlog.h>
+#include <ImGui/imgui.h>
+#define IMGUI_DEFINE_MATH_OPERATORS
+#include "libultraship/src/Context.h"
+
+#include <ImGui/imgui_internal.h>
+#include <libultraship/libultraship.h>
+#include <Fast3D/gfx_pc.h>
+#include "port/Engine.h"
+
+namespace GameUI {
+std::shared_ptr<GameMenuBar> mGameMenuBar;
+std::shared_ptr<LUS::GuiWindow> mConsoleWindow;
+std::shared_ptr<LUS::GuiWindow> mStatsWindow;
+std::shared_ptr<LUS::GuiWindow> mInputEditorWindow;
+std::shared_ptr<LUS::GuiWindow> mGfxDebuggerWindow;
+std::shared_ptr<AdvancedResolutionSettings::AdvancedResolutionSettingsWindow> mAdvancedResolutionSettingsWindow;
+
+void SetupGuiElements() {
+ auto gui = LUS::Context::GetInstance()->GetWindow()->GetGui();
+
+ auto& style = ImGui::GetStyle();
+ style.FramePadding = ImVec2(4.0f, 6.0f);
+ style.ItemSpacing = ImVec2(8.0f, 6.0f);
+ style.Colors[ImGuiCol_MenuBarBg] = UIWidgets::Colors::DarkGray;
+
+ mGameMenuBar = std::make_shared<GameMenuBar>("gOpenMenuBar", CVarGetInteger("gOpenMenuBar", 0));
+ gui->SetMenuBar(mGameMenuBar);
+ mStatsWindow = gui->GetGuiWindow("Stats");
+ if (mStatsWindow == nullptr) {
+ SPDLOG_ERROR("Could not find stats window");
+ }
+
+ mConsoleWindow = gui->GetGuiWindow("Console");
+ if (mConsoleWindow == nullptr) {
+ SPDLOG_ERROR("Could not find console window");
+ }
+
+ mInputEditorWindow = gui->GetGuiWindow("Input Editor");
+ if (mInputEditorWindow == nullptr) {
+ SPDLOG_ERROR("Could not find input editor window");
+ return;
+ }
+
+ mGfxDebuggerWindow = gui->GetGuiWindow("GfxDebuggerWindow");
+ if (mGfxDebuggerWindow == nullptr) {
+ SPDLOG_ERROR("Could not find input GfxDebuggerWindow");
+ }
+
+ mAdvancedResolutionSettingsWindow = std::make_shared<AdvancedResolutionSettings::AdvancedResolutionSettingsWindow>("gAdvancedResolutionEditorEnabled", "Advanced Resolution Settings");
+ gui->AddGuiWindow(mAdvancedResolutionSettingsWindow);
+}
+
+void Destroy() {
+ mAdvancedResolutionSettingsWindow = nullptr;
+ mConsoleWindow = nullptr;
+ mStatsWindow = nullptr;
+ mInputEditorWindow = nullptr;
+}
+
+std::string GetWindowButtonText(const char* text, bool menuOpen) {
+ char buttonText[100] = "";
+ if (menuOpen) {
+ strcat(buttonText, ICON_FA_CHEVRON_RIGHT " ");
+ }
+ strcat(buttonText, text);
+ if (!menuOpen) { strcat(buttonText, " "); }
+ return buttonText;
+}
+}
+
+static const char* filters[3] = {
+#ifdef __WIIU__
+ "",
+#else
+ "Three-Point",
+#endif
+ "Linear", "None"
+};
+
+void DrawSettingsMenu(){
+ if(UIWidgets::BeginMenu("Settings")){
+ // if (UIWidgets::BeginMenu("Audio")) {
+ // UIWidgets::CVarSliderFloat("Master Volume", "gGameMasterVolume", 0.0f, 1.0f, 1.0f, {
+ // .format = "%.0f%%",
+ // .isPercentage = true,
+ // });
+ // if (UIWidgets::CVarSliderFloat("Main Music Volume", "gMainMusicVolume", 0.0f, 1.0f, 1.0f, {
+ // .format = "%.0f%%",
+ // .isPercentage = true,
+ // })) {
+ // audio_set_player_volume(SEQ_PLAYER_LEVEL, CVarGetFloat("gMainMusicVolume", 1.0f));
+ // }
+ // if (UIWidgets::CVarSliderFloat("Sound Effects Volume", "gSFXMusicVolume", 0.0f, 1.0f, 1.0f, {
+ // .format = "%.0f%%",
+ // .isPercentage = true,
+ // })) {
+ // audio_set_player_volume(SEQ_PLAYER_SFX, CVarGetFloat("gSFXMusicVolume", 1.0f));
+ // }
+ // if (UIWidgets::CVarSliderFloat("Environment Volume", "gEnvironmentVolume", 0.0f, 1.0f, 1.0f, {
+ // .format = "%.0f%%",
+ // .isPercentage = true,
+ // })) {
+ // audio_set_player_volume(SEQ_PLAYER_ENV, CVarGetFloat("gEnvironmentVolume", 1.0f));
+ // }
+ //
+ // static std::unordered_map<LUS::AudioBackend, const char*> audioBackendNames = {
+ // { LUS::AudioBackend::WASAPI, "Windows Audio Session API" },
+ // { LUS::AudioBackend::PULSE, "PulseAudio" },
+ // { LUS::AudioBackend::SDL, "SDL" },
+ // };
+ //
+ // ImGui::Text("Audio API (Needs reload)");
+ // auto currentAudioBackend = LUS::Context::GetInstance()->GetAudio()->GetAudioBackend();
+ //
+ // if (LUS::Context::GetInstance()->GetAudio()->GetAvailableAudioBackends()->size() <= 1) {
+ // UIWidgets::DisableComponent(ImGui::GetStyle().Alpha * 0.5f);
+ // }
+ // if (ImGui::BeginCombo("##AApi", audioBackendNames[currentAudioBackend])) {
+ // for (uint8_t i = 0; i < LUS::Context::GetInstance()->GetAudio()->GetAvailableAudioBackends()->size(); i++) {
+ // auto backend = LUS::Context::GetInstance()->GetAudio()->GetAvailableAudioBackends()->data()[i];
+ // if (ImGui::Selectable(audioBackendNames[backend], backend == currentAudioBackend)) {
+ // LUS::Context::GetInstance()->GetAudio()->SetAudioBackend(backend);
+ // }
+ // }
+ // ImGui::EndCombo();
+ // }
+ // if (LUS::Context::GetInstance()->GetAudio()->GetAvailableAudioBackends()->size() <= 1) {
+ // UIWidgets::ReEnableComponent("");
+ // }
+ //
+ // ImGui::EndMenu();
+ // }
+
+ UIWidgets::Spacer(0);
+
+ if (UIWidgets::BeginMenu("Controller")) {
+ UIWidgets::WindowButton("Controller Mapping", "gInputEditorWindow", GameUI::mInputEditorWindow);
+
+ UIWidgets::Spacer(0);
+
+#ifndef __SWITCH__
+ UIWidgets::CVarCheckbox("Menubar Controller Navigation", "gControlNav", {
+ .tooltip = "Allows controller navigation of the SOH menu bar (Settings, Enhancements,...)\nCAUTION: This will disable game inputs while the menubar is visible.\n\nD-pad to move between items, A to select, and X to grab focus on the menu bar"
+ });
+#endif
+ UIWidgets::CVarCheckbox("Show Inputs", "gInputEnabled", {
+ .tooltip = "Shows currently pressed inputs on the bottom right of the screen"
+ });
+ if (CVarGetInteger("gInputEnabled", 0)) {
+ UIWidgets::CVarSliderFloat("Input Scale", "gInputScale", 1.0f, 3.0f, 1.0f, {
+ .tooltip = "Sets the on screen size of the displayed inputs from the Show Inputs setting",
+ .format = "%.1fx",
+ });
+ }
+
+ ImGui::EndMenu();
+ }
+
+ ImGui::EndMenu();
+ }
+
+ ImGui::SetCursorPosY(0.0f);
+ if (UIWidgets::BeginMenu("Graphics")) {
+ UIWidgets::WindowButton("Resolution Editor", "gAdvancedResolutionEditorEnabled", GameUI::mAdvancedResolutionSettingsWindow);
+
+ UIWidgets::Spacer(0);
+
+ // Previously was running every frame, and nothing was setting it? Maybe a bad copy/paste?
+ // LUS::Context::GetInstance()->GetWindow()->SetResolutionMultiplier(CVarGetFloat("gInternalResolution", 1));
+ // UIWidgets::Tooltip("Multiplies your output resolution by the value inputted, as a more intensive but effective form of anti-aliasing");
+#ifndef __WIIU__
+ if (UIWidgets::CVarSliderInt("MSAA: %d", "gMSAAValue", 1, 8, 1, {
+ .tooltip = "Activates multi-sample anti-aliasing when above 1x up to 8x for 8 samples for every pixel"
+ })) {
+ LUS::Context::GetInstance()->GetWindow()->SetMsaaLevel(CVarGetInteger("gMSAAValue", 1));
+ }
+#endif
+
+ { // FPS Slider
+ const int minFps = 30;
+ static int maxFps;
+ if (LUS::Context::GetInstance()->GetWindow()->GetWindowBackend() == LUS::WindowBackend::DX11) {
+ maxFps = 360;
+ } else {
+ maxFps = LUS::Context::GetInstance()->GetWindow()->GetCurrentRefreshRate();
+ }
+ int currentFps = 0;
+ #ifdef __WIIU__
+ UIWidgets::Spacer(0);
+ // only support divisors of 60 on the Wii U
+ if (currentFps > 60) {
+ currentFps = 60;
+ } else {
+ currentFps = 60 / (60 / currentFps);
+ }
+
+ int fpsSlider = 1;
+ if (currentFps == 30) {
+ ImGui::Text("FPS: Original (30)");
+ } else {
+ ImGui::Text("FPS: %d", currentFps);
+ if (currentFps == 30) {
+ fpsSlider = 2;
+ } else { // currentFps == 60
+ fpsSlider = 3;
+ }
+ }
+ if (CVarGetInteger("gMatchRefreshRate", 0)) {
+ UIWidgets::DisableComponent(ImGui::GetStyle().Alpha * 0.5f);
+ }
+
+ if (ImGui::Button(" - ##WiiUFPS")) {
+ fpsSlider--;
+ }
+ ImGui::SameLine();
+ ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 7.0f);
+
+ UIWidgets::Spacer(0);
+
+ ImGui::PushItemWidth(std::min((ImGui::GetContentRegionAvail().x - 60.0f), 260.0f));
+ ImGui::SliderInt("##WiiUFPSSlider", &fpsSlider, 1, 3, "", ImGuiSliderFlags_AlwaysClamp);
+ ImGui::PopItemWidth();
+
+ ImGui::SameLine();
+ ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 7.0f);
+ if (ImGui::Button(" + ##WiiUFPS")) {
+ fpsSlider++;
+ }
+
+ if (CVarGetInteger("gMatchRefreshRate", 0)) {
+ UIWidgets::ReEnableComponent("");
+ }
+ if (fpsSlider > 3) {
+ fpsSlider = 3;
+ } else if (fpsSlider < 1) {
+ fpsSlider = 1;
+ }
+
+ if (fpsSlider == 1) {
+ currentFps = 20;
+ } else if (fpsSlider == 2) {
+ currentFps = 30;
+ } else if (fpsSlider == 3) {
+ currentFps = 60;
+ }
+ CVarSetInteger("gInterpolationFPS", currentFps);
+ LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
+ #else
+ bool matchingRefreshRate =
+ CVarGetInteger("gMatchRefreshRate", 0) && LUS::Context::GetInstance()->GetWindow()->GetWindowBackend() != LUS::WindowBackend::DX11;
+ UIWidgets::CVarSliderInt((currentFps == 20) ? "FPS: Original (20)" : "FPS: %d", "gInterpolationFPS", minFps, maxFps, 1, {
+ .disabled = matchingRefreshRate
+ });
+ #endif
+ if (LUS::Context::GetInstance()->GetWindow()->GetWindowBackend() == LUS::WindowBackend::DX11) {
+ UIWidgets::Tooltip(
+ "Uses Matrix Interpolation to create extra frames, resulting in smoother graphics. This is purely "
+ "visual and does not impact game logic, execution of glitches etc.\n\n"
+ "A higher target FPS than your monitor's refresh rate will waste resources, and might give a worse result."
+ );
+ } else {
+ UIWidgets::Tooltip(
+ "Uses Matrix Interpolation to create extra frames, resulting in smoother graphics. This is purely "
+ "visual and does not impact game logic, execution of glitches etc."
+ );
+ }
+ } // END FPS Slider
+
+ if (LUS::Context::GetInstance()->GetWindow()->GetWindowBackend() == LUS::WindowBackend::DX11) {
+ UIWidgets::Spacer(0);
+ if (ImGui::Button("Match Refresh Rate")) {
+ int hz = LUS::Context::GetInstance()->GetWindow()->GetCurrentRefreshRate();
+ if (hz >= 30 && hz <= 360) {
+ CVarSetInteger("gInterpolationFPS", hz);
+ LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
+ }
+ }
+ } else {
+ UIWidgets::PaddedEnhancementCheckbox("Match Refresh Rate", "gMatchRefreshRate", true, false);
+ }
+
+ UIWidgets::Tooltip("Matches interpolation value to the current game's window refresh rate");
+
+ if (LUS::Context::GetInstance()->GetWindow()->GetWindowBackend() == LUS::WindowBackend::DX11) {
+ UIWidgets::PaddedEnhancementSliderInt(CVarGetInteger("gExtraLatencyThreshold", 80) == 0 ? "Jitter fix: Off" : "Jitter fix: >= %d FPS",
+ "##ExtraLatencyThreshold", "gExtraLatencyThreshold", 0, 360, "", 80, true, true, false);
+ UIWidgets::Tooltip("When Interpolation FPS setting is at least this threshold, add one frame of input lag (e.g. 16.6 ms for 60 FPS) in order to avoid jitter. This setting allows the CPU to work on one frame while GPU works on the previous frame.\nThis setting should be used when your computer is too slow to do CPU + GPU work in time.");
+ }
+
+ UIWidgets::PaddedSeparator(true, true, 3.0f, 3.0f);
+
+
+ static std::unordered_map<LUS::WindowBackend, const char*> windowBackendNames = {
+ { LUS::WindowBackend::DX11, "DirectX" },
+ { LUS::WindowBackend::SDL_OPENGL, "OpenGL"},
+ { LUS::WindowBackend::SDL_METAL, "Metal" },
+ { LUS::WindowBackend::GX2, "GX2"}
+ };
+
+ ImGui::Text("Renderer API (Needs reload)");
+ LUS::WindowBackend runningWindowBackend = LUS::Context::GetInstance()->GetWindow()->GetWindowBackend();
+ LUS::WindowBackend configWindowBackend;
+ int configWindowBackendId = LUS::Context::GetInstance()->GetConfig()->GetInt("Window.Backend.Id", -1);
+ if (configWindowBackendId != -1 && configWindowBackendId < static_cast<int>(LUS::WindowBackend::BACKEND_COUNT)) {
+ configWindowBackend = static_cast<LUS::WindowBackend>(configWindowBackendId);
+ } else {
+ configWindowBackend = runningWindowBackend;
+ }
+
+ if (LUS::Context::GetInstance()->GetWindow()->GetAvailableWindowBackends()->size() <= 1) {
+ UIWidgets::DisableComponent(ImGui::GetStyle().Alpha * 0.5f);
+ }
+ if (ImGui::BeginCombo("##RApi", windowBackendNames[configWindowBackend])) {
+ for (size_t i = 0; i < LUS::Context::GetInstance()->GetWindow()->GetAvailableWindowBackends()->size(); i++) {
+ auto backend = LUS::Context::GetInstance()->GetWindow()->GetAvailableWindowBackends()->data()[i];
+ if (ImGui::Selectable(windowBackendNames[backend], backend == configWindowBackend)) {
+ LUS::Context::GetInstance()->GetConfig()->SetInt("Window.Backend.Id", static_cast<int>(backend));
+ LUS::Context::GetInstance()->GetConfig()->SetString("Window.Backend.Name",
+ windowBackendNames[backend]);
+ LUS::Context::GetInstance()->GetConfig()->Save();
+ }
+ }
+ ImGui::EndCombo();
+ }
+ if (LUS::Context::GetInstance()->GetWindow()->GetAvailableWindowBackends()->size() <= 1) {
+ UIWidgets::ReEnableComponent("");
+ }
+
+ if (LUS::Context::GetInstance()->GetWindow()->CanDisableVerticalSync()) {
+ UIWidgets::PaddedEnhancementCheckbox("Enable Vsync", "gVsyncEnabled", true, false);
+ }
+
+ if (LUS::Context::GetInstance()->GetWindow()->SupportsWindowedFullscreen()) {
+ UIWidgets::PaddedEnhancementCheckbox("Windowed fullscreen", "gSdlWindowedFullscreen", true, false);
+ }
+
+ if (LUS::Context::GetInstance()->GetWindow()->GetGui()->SupportsViewports()) {
+ UIWidgets::PaddedEnhancementCheckbox("Allow multi-windows", "gEnableMultiViewports", true, false, false, "", UIWidgets::CheckboxGraphics::Cross, true);
+ UIWidgets::Tooltip("Allows windows to be able to be dragged off of the main game window. Requires a reload to take effect.");
+ }
+
+ // If more filters are added to LUS, make sure to add them to the filters list here
+ ImGui::Text("Texture Filter (Needs reload)");
+
+ UIWidgets::EnhancementCombobox("gTextureFilter", filters, 0);
+
+ UIWidgets::Spacer(0);
+
+ LUS::Context::GetInstance()->GetWindow()->GetGui()->GetGameOverlay()->DrawSettings();
+
+ ImGui::EndMenu();
+ }
+}
+
+void DrawMenuBarIcon() {
+ static bool gameIconLoaded = false;
+ if (!gameIconLoaded) {
+ // LUS::Context::GetInstance()->GetWindow()->GetGui()->LoadTexture("Game_Icon", "textures/icons/gIcon.png");
+ gameIconLoaded = false;
+ }
+
+ if (LUS::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName("Game_Icon")) {
+#ifdef __SWITCH__
+ ImVec2 iconSize = ImVec2(20.0f, 20.0f);
+ float posScale = 1.0f;
+#elif defined(__WIIU__)
+ ImVec2 iconSize = ImVec2(16.0f * 2, 16.0f * 2);
+ float posScale = 2.0f;
+#else
+ ImVec2 iconSize = ImVec2(20.0f, 20.0f);
+ float posScale = 1.5f;
+#endif
+ ImGui::SetCursorPos(ImVec2(5, 2.5f) * posScale);
+ ImGui::Image(LUS::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName("Game_Icon"), iconSize);
+ ImGui::SameLine();
+ ImGui::SetCursorPos(ImVec2(25, 0) * posScale);
+ }
+}
+
+void DrawGameMenu() {
+ if (UIWidgets::BeginMenu("Ghostship")) {
+ if (UIWidgets::MenuItem("Reset",
+#ifdef __APPLE__
+ "Command-R"
+#else
+ "Ctrl+R"
+#endif
+ )) {
+ std::reinterpret_pointer_cast<LUS::ConsoleWindow>(LUS::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Console"))->Dispatch("reset");
+ }
+#if !defined(__SWITCH__) && !defined(__WIIU__)
+
+ if (UIWidgets::MenuItem("Toggle Fullscreen", "F9")) {
+ LUS::Context::GetInstance()->GetWindow()->ToggleFullscreen();
+ }
+
+ if (UIWidgets::MenuItem("Quit")) {
+ LUS::Context::GetInstance()->GetWindow()->Close();
+ }
+#endif
+ ImGui::EndMenu();
+ }
+}
+
+void DrawEnhancementsMenu() {
+ if (UIWidgets::BeginMenu("Enhancements")) {
+
+ if (UIWidgets::BeginMenu("Gameplay")) {
+ UIWidgets::CVarCheckbox("No Level of Detail (LOD)", "gDisableLOD", {
+ .tooltip = "Disable Level of Detail (LOD) to avoid models using lower poly versions at a distance"
+ });
+ UIWidgets::CVarCheckbox("Select any star from menu", "gSelectAllStars", {
+ .tooltip = "Let's you select any star from the menu regardless of the courses completion status."
+ });
+ UIWidgets::CVarCheckbox("Collecting Stars Will Not Exit Level", "gStarNoExit", {
+ .tooltip = "Stars act like the 100 coin star and will not take you out of the level"
+ });
+ UIWidgets::CVarCheckbox("Avoid playing peach cutscene", "gDisablePeachCutscene", {
+ .tooltip = "Avoid playing the peach cutscene when starting a new game"
+ });
+ ImGui::EndMenu();
+ }
+
+ ImGui::EndMenu();
+ }
+}
+
+void DrawCheatsMenu() {
+ if (UIWidgets::BeginMenu("Cheats")) {
+ UIWidgets::CVarCheckbox("Infinite Health", "gInfiniteHealth");
+ UIWidgets::CVarCheckbox("Infinite Lives", "gInfiniteLives");
+
+ ImGui::EndMenu();
+ }
+}
+
+const char* debugInfoPages[6] = {
+ "Object",
+ "Check Surface",
+ "Map",
+ "Stage",
+ "Effect",
+ "Enemy",
+};
+
+void DrawDebugMenu() {
+ if (UIWidgets::BeginMenu("Developer")) {
+ UIWidgets::WindowButton("Gfx Debugger", "gGfxDebuggerEnabled", GameUI::mGfxDebuggerWindow, {
+ .tooltip = "Enables the Gfx Debugger window, allowing you to input commands, type help for some examples"
+ });
+
+ UIWidgets::CVarCheckbox("Debug mode", "gEnableDebugMode", {
+ .tooltip = "Various debug features, including a level selector from the main menu"
+ });
+
+ UIWidgets::CVarCheckbox("Better Level Select", "gDeveloper.BetterLevelSelect", {
+ .tooltip = "Tweaks to the level select screen, like naming and allowing C-buttons to be used"
+ });
+
+ UIWidgets::CVarCheckbox("Draw DebugInfo", "gDeveloper.DrawDebugInfo");
+ if (CVarGetInteger("gDeveloper.DrawDebugInfo", 0)) {
+ UIWidgets::CVarCombobox("DebugInfo mode", "gDeveloper.DebugInfoPage", debugInfoPages, {
+ .defaultIndex = 0,
+ });
+ }
+ UIWidgets::Spacer(0);
+
+ UIWidgets::WindowButton("Stats", "gStatsEnabled", GameUI::mStatsWindow, {
+ .tooltip = "Shows the stats window, with your FPS and frametimes, and the OS you're playing on"
+ });
+ UIWidgets::WindowButton("Console", "gConsoleEnabled", GameUI::mConsoleWindow, {
+ .tooltip = "Enables the console window, allowing you to input commands, type help for some examples"
+ });
+
+ ImGui::EndMenu();
+ }
+}
+
+void GameMenuBar::DrawElement() {
+ if(ImGui::BeginMenuBar()){
+ DrawMenuBarIcon();
+
+ DrawGameMenu();
+
+ ImGui::SetCursorPosY(0.0f);
+
+ DrawSettingsMenu();
+
+ ImGui::SetCursorPosY(0.0f);
+
+ DrawEnhancementsMenu();
+
+ ImGui::SetCursorPosY(0.0f);
+
+ DrawCheatsMenu();
+
+ ImGui::SetCursorPosY(0.0f);
+
+ DrawDebugMenu();
+
+ ImGui::EndMenuBar();
+ }
+} \ No newline at end of file
diff --git a/src/port/ui/ImguiUI.h b/src/port/ui/ImguiUI.h
new file mode 100644
index 00000000..2d233f4c
--- /dev/null
+++ b/src/port/ui/ImguiUI.h
@@ -0,0 +1,16 @@
+#pragma once
+#include <libultraship/libultraship.h>
+
+namespace GameUI {
+ void SetupGuiElements();
+ void Destroy();
+}
+
+class GameMenuBar : public LUS::GuiMenuBar {
+ public:
+ using LUS::GuiMenuBar::GuiMenuBar;
+ protected:
+ void DrawElement() override;
+ void InitElement() override {};
+ void UpdateElement() override {};
+}; \ No newline at end of file
diff --git a/src/port/ui/ResolutionEditor.cpp b/src/port/ui/ResolutionEditor.cpp
new file mode 100644
index 00000000..01995a3c
--- /dev/null
+++ b/src/port/ui/ResolutionEditor.cpp
@@ -0,0 +1,422 @@
+#include "ResolutionEditor.h"
+#include "UIWidgets.h"
+#include "libultraship/src/Context.h"
+
+#include <ImGui/imgui.h>
+#include <libultraship/libultraship.h>
+#include <graphic/Fast3D/gfx_pc.h>
+
+/* Console Variables are grouped under gAdvancedResolution. (e.g. "gAdvancedResolution.Enabled")
+
+ The following CVars are used in Libultraship and can be edited here:
+ - Enabled - Turns Advanced Resolution Mode on.
+ - AspectRatioX, AspectRatioY - Aspect ratio controls. To toggle off, set either to zero.
+ - VerticalPixelCount, VerticalResolutionToggle - Resolution controls.
+ - PixelPerfectMode, IntegerScale.Factor - Pixel Perfect Mode a.k.a. integer scaling controls.
+ (Waiting on a second PR merge on LUS for this to fully function.):
+ - IntegerScale.FitAutomatically - Automatic resizing for Pixel Perfect Mode.
+ - IntegerScale.NeverExceedBounds - Prevents manual resizing from exceeding screen bounds.
+
+ The following CVars are also implemented in LUS for niche use cases:
+ - IgnoreAspectCorrection - Stretch framebuffer to fill screen.
+ This is something of a power-user setting for niche setups that most people won't need or care about,
+ but may be useful if playing the Switch/Wii U ports on a 4:3 television.
+ - IntegerScale.ExceedBoundsBy - Offset the max screen bounds, usually by +1.
+ This isn't that useful at the moment.
+*/
+
+namespace AdvancedResolutionSettings {
+ enum setting { UPDATE_aspectRatioX, UPDATE_aspectRatioY, UPDATE_verticalPixelCount };
+
+ const char* aspectRatioPresetLabels[] = {
+ "Off", "Custom", "Original (4:3)", "Widescreen (16:9)", "Nintendo 3DS (5:3)", "16:10 (8:5)", "Ultrawide (21:9)"
+ };
+ const float aspectRatioPresetsX[] = { 0.0f, 12.0f, 4.0f, 16.0f, 5.0f, 16.0f, 21.0f };
+ const float aspectRatioPresetsY[] = { 0.0f, 9.0f, 3.0f, 9.0f, 3.0f, 10.0f, 9.0f };
+ const int default_aspectRatio = 1; // Default combo list option
+
+ const char* pixelCountPresetLabels[] = { "Custom", "Native N64 (240p)", "2x (480p)", "3x (720p)", "4x (960p)",
+ "5x (1200p)", "6x (1440p)", "Full HD (1080p)", "4K (2160p)" };
+ const int pixelCountPresets[] = { 480, 240, 480, 720, 960, 1200, 1440, 1080, 2160, 480 };
+ const int default_pixelCount = 0; // Default combo list option
+
+ const uint32_t minVerticalPixelCount = 240; // see: LUS::AdvancedResolution()
+ const uint32_t maxVerticalPixelCount = 4320;
+
+ const unsigned short default_maxIntegerScaleFactor = 6; // Default size of Integer scale factor slider.
+
+ const float enhancementSpacerHeight = 19.0f;
+// This will need to be determined more intelligently when Hi-DPI UI support is added.
+
+ void AdvancedResolutionSettingsWindow::InitElement() {
+ }
+
+ void AdvancedResolutionSettingsWindow::DrawElement() {
+ ImGui::SetNextWindowSize(ImVec2(497, 532), ImGuiCond_FirstUseEver);
+ if (ImGui::Begin("Advanced Resolution Settings", &mIsVisible)) {
+ // Initialise update flags.
+ bool update[sizeof(setting)];
+ for (unsigned short i = 0; i < sizeof(setting); i++)
+ update[i] = false;
+ static short updateCountdown = 0;
+ short countdownStartingValue = CVarGetInteger("gInterpolationFPS", 20) / 2; // half of a second, in frames.
+
+ // Initialise integer scale bounds.
+ short max_integerScaleFactor = default_maxIntegerScaleFactor; // default value, which may or may not get
+ // overridden depending on viewport res
+
+ short integerScale_maximumBounds = 1; // can change when window is resized
+ // This is mostly just for UX purposes, as Fit Automatically logic is part of LUS.
+ if (((float)gfx_current_game_window_viewport.width / gfx_current_game_window_viewport.height) >
+ ((float)gfx_current_dimensions.width / gfx_current_dimensions.height)) {
+ // Scale to window height
+ integerScale_maximumBounds = gfx_current_game_window_viewport.height / gfx_current_dimensions.height;
+ } else {
+ // Scale to window width
+ integerScale_maximumBounds = gfx_current_game_window_viewport.width / gfx_current_dimensions.width;
+ }
+ // Lower-clamping maximum bounds value to 1 is no-longer necessary as that's accounted for in LUS.
+ // Letting it go below 1 in this Editor will even allow for checking if screen bounds are being exceeded.
+ if (default_maxIntegerScaleFactor < integerScale_maximumBounds) {
+ max_integerScaleFactor =
+ integerScale_maximumBounds + CVarGetInteger("gAdvancedResolution.IntegerScale.ExceedBoundsBy", 0);
+ }
+
+ // Stored Values for non-UIWidgets elements
+ static float aspectRatioX = CVarGetFloat("gAdvancedResolution.AspectRatioX", 16.0f);
+ static float aspectRatioY = CVarGetFloat("gAdvancedResolution.AspectRatioY", 9.0f);
+ static int verticalPixelCount = CVarGetInteger("gAdvancedResolution.VerticalPixelCount", 480);
+ // Combo List defaults
+ static int item_aspectRatio = default_aspectRatio;
+ static int item_pixelCount = default_pixelCount;
+ // Additional settings
+ static bool showHorizontalResField = false;
+ static int horizontalPixelCount = (verticalPixelCount / aspectRatioY) * aspectRatioX;
+
+#ifdef __APPLE__
+ ImGui::Text("Note: these settings may behave incorrectly on Apple Retina Displays.");
+ UIWidgets::PaddedSeparator(true, true, 3.0f, 3.0f);
+#endif
+
+ // The original resolution slider (for convenience)
+ if (UIWidgets::EnhancementSliderFloat("Internal Resolution: %d %%", "##IMul", "gInternalResolution", 0.5f, 2.0f,
+ "", 1.0f, true, true,
+ (CVarGetInteger("gAdvancedResolution.VerticalResolutionToggle", 0) &&
+ CVarGetInteger("gAdvancedResolution.Enabled", 0)) ||
+ CVarGetInteger("gLowResMode", 0))) {
+ LUS::Context::GetInstance()->GetWindow()->SetResolutionMultiplier(CVarGetFloat("gInternalResolution", 1));
+ }
+ UIWidgets::Tooltip("Multiplies your output resolution by the value entered, as a more intensive but effective "
+ "form of anti-aliasing"); // Description pulled from SohMenuBar.cpp
+
+ // N64 Mode toggle (again for convenience)
+ // UIWidgets::PaddedEnhancementCheckbox("(Enhancements>Graphics) N64 Mode", "gLowResMode", false, false, false,
+ // "", UIWidgets::CheckboxGraphics::Cross, false);
+
+ UIWidgets::PaddedSeparator(true, true, 3.0f, 3.0f);
+ // Activator
+ UIWidgets::PaddedEnhancementCheckbox("Enable advanced settings.", "gAdvancedResolution.Enabled", false, false,
+ false, "", UIWidgets::CheckboxGraphics::Cross, false);
+ // Error/Warning display
+ if (!CVarGetInteger("gLowResMode", 0)) {
+ if (IsDroppingFrames()) { // Significant frame drop warning
+ ImGui::TextColored({ 0.85f, 0.85f, 0.0f, 1.0f },
+ ICON_FA_EXCLAMATION_TRIANGLE " Significant frame rate (FPS) drops may be occuring.");
+ UIWidgets::Spacer(2);
+ } else { // No warnings
+ UIWidgets::Spacer(enhancementSpacerHeight);
+ }
+ } else { // N64 Mode warning
+ ImGui::TextColored({ 0.0f, 0.85f, 0.85f, 1.0f },
+ ICON_FA_QUESTION_CIRCLE " \"N64 Mode\" is overriding these settings.");
+ ImGui::SameLine();
+ if (ImGui::Button("Click to disable")) {
+ CVarSetInteger("gLowResMode", (int)false);
+ CVarSave();
+ }
+ }
+ // Resolution visualiser
+ ImGui::Text("Viewport dimensions: %d x %d", gfx_current_game_window_viewport.width,
+ gfx_current_game_window_viewport.height);
+ ImGui::Text("Internal resolution: %d x %d", gfx_current_dimensions.width, gfx_current_dimensions.height);
+
+ UIWidgets::PaddedSeparator(true, true, 3.0f, 3.0f);
+
+ // Aspect Ratio
+ ImGui::Text("Force aspect ratio:");
+ ImGui::SameLine();
+ ImGui::TextColored({ 0.75f, 0.75f, 0.75f, 1.0f }, "(Select \"Off\" to disable.)");
+ if (ImGui::Combo(" ", &item_aspectRatio, aspectRatioPresetLabels,
+ IM_ARRAYSIZE(aspectRatioPresetLabels)) &&
+ item_aspectRatio != default_aspectRatio) { // don't change anything if "Custom" is selected.
+ aspectRatioX = aspectRatioPresetsX[item_aspectRatio];
+ aspectRatioY = aspectRatioPresetsY[item_aspectRatio];
+ update[UPDATE_aspectRatioX] = true;
+ update[UPDATE_aspectRatioY] = true;
+
+ if (showHorizontalResField) {
+ horizontalPixelCount = (verticalPixelCount / aspectRatioY) * aspectRatioX;
+ }
+ }
+ if (item_aspectRatio == default_aspectRatio && !showHorizontalResField) {
+ // Declaring the Y input interaction in particular as a variable beforehand
+ // will prevent a bug where the Y field would disappear when modifying X.
+ bool inputX = ImGui::InputFloat("X", &aspectRatioX, 0.1f, 1.0f, "%.3f");
+ bool inputY = ImGui::InputFloat("Y", &aspectRatioY, 0.1f, 1.0f, "%.3f");
+ if (inputX || inputY) {
+ item_aspectRatio = default_aspectRatio;
+ update[UPDATE_aspectRatioX] = true;
+ update[UPDATE_aspectRatioY] = true;
+ }
+ } else if (showHorizontalResField) { // Show calculated aspect ratio
+ if (item_aspectRatio) {
+ UIWidgets::Spacer(2);
+ float resolvedAspectRatio = (float)gfx_current_dimensions.height / gfx_current_dimensions.width;
+ ImGui::Text("Aspect ratio: %.4f", resolvedAspectRatio);
+ } else {
+ UIWidgets::Spacer(enhancementSpacerHeight);
+ }
+ }
+
+ UIWidgets::Spacer(0);
+ // Vertical Resolution
+ UIWidgets::PaddedEnhancementCheckbox("Set fixed vertical resolution (disables Resolution slider)",
+ "gAdvancedResolution.VerticalResolutionToggle", true, false, false, "",
+ UIWidgets::CheckboxGraphics::Cross, false);
+ UIWidgets::Tooltip(
+ "Override the resolution scale slider and use the settings below, irrespective of window size.");
+ if (ImGui::Combo("Pixel Count Presets", &item_pixelCount, pixelCountPresetLabels,
+ IM_ARRAYSIZE(pixelCountPresetLabels)) &&
+ item_pixelCount != default_pixelCount) { // don't change anything if "Custom" is selected.
+ verticalPixelCount = pixelCountPresets[item_pixelCount];
+ update[UPDATE_verticalPixelCount] = true;
+
+ if (showHorizontalResField) {
+ horizontalPixelCount = (verticalPixelCount / aspectRatioY) * aspectRatioX;
+ }
+ }
+ // Horizontal Resolution, if visibility is enabled for it.
+ if (showHorizontalResField) {
+ // Only show the field if Aspect Ratio is being enforced.
+ if ((aspectRatioX > 0.0f) && (aspectRatioY > 0.0f)) {
+ // So basically we're "faking" this one by setting aspectRatioX instead.
+ if (ImGui::InputInt("Horiz. Pixel Count", &horizontalPixelCount, 8, 320)) {
+ item_aspectRatio = default_aspectRatio;
+ if (horizontalPixelCount < (minVerticalPixelCount / 3.0f) * 4.0f) {
+ horizontalPixelCount = (minVerticalPixelCount / 3.0f) * 4.0f;
+ }
+ aspectRatioX = aspectRatioY * horizontalPixelCount / verticalPixelCount;
+ update[UPDATE_aspectRatioX] = true;
+ }
+ } else { // Display a notice instead.
+ ImGui::TextColored({ 0.0f, 0.85f, 0.85f, 1.0f },
+ ICON_FA_QUESTION_CIRCLE " \"Force aspect ratio\" required.");
+ // ImGui::Text(" ");
+ ImGui::SameLine();
+ if (ImGui::Button("Click to resolve")) {
+ item_aspectRatio = default_aspectRatio; // Set it to Custom
+ aspectRatioX = aspectRatioPresetsX[2]; // but use the 4:3 defaults
+ aspectRatioY = aspectRatioPresetsY[2];
+ update[UPDATE_aspectRatioX] = true;
+ update[UPDATE_aspectRatioY] = true;
+ horizontalPixelCount = (verticalPixelCount / aspectRatioY) * aspectRatioX;
+ }
+ }
+ }
+ // Vertical Resolution part 2
+ if (ImGui::InputInt("Vertical Pixel Count", &verticalPixelCount, 8, 240)) {
+ item_pixelCount = default_pixelCount;
+ update[UPDATE_verticalPixelCount] = true;
+
+ // Account for the natural instinct to enter horizontal first.
+ // Ignore vertical resolutions that are below the lower clamp constant.
+ if (showHorizontalResField && !(verticalPixelCount < minVerticalPixelCount)) {
+ aspectRatioX = aspectRatioY * horizontalPixelCount / verticalPixelCount;
+ update[UPDATE_aspectRatioX] = true;
+ }
+ }
+
+ UIWidgets::Spacer(0);
+ // UIWidgets::PaddedSeparator(true, true, 3.0f, 3.0f);
+
+ // Integer scaling settings group
+ if (ImGui::CollapsingHeader("Integer Scaling Settings")) {
+ // Pixel-perfect Mode
+ UIWidgets::PaddedEnhancementCheckbox("Pixel-perfect Mode", "gAdvancedResolution.PixelPerfectMode", true,
+ true,
+ !CVarGetInteger("gAdvancedResolution.VerticalResolutionToggle", 0), "",
+ UIWidgets::CheckboxGraphics::Cross, false);
+ UIWidgets::Tooltip("Don't scale image to fill window.");
+ if (!CVarGetInteger("gAdvancedResolution.VerticalResolutionToggle", 0)) {
+ CVarSetInteger("gAdvancedResolution.PixelPerfectMode", (int)false);
+ CVarSave();
+ }
+
+ // Integer Scaling
+ UIWidgets::EnhancementSliderInt("Integer scale factor: %d", "##ARSIntScale",
+ "gAdvancedResolution.IntegerScale.Factor", 1, max_integerScaleFactor, "%d",
+ 1, true,
+ !CVarGetInteger("gAdvancedResolution.PixelPerfectMode", 0) ||
+ CVarGetInteger("gAdvancedResolution.IntegerScale.FitAutomatically", 0));
+ UIWidgets::Tooltip("Integer scales the image. Only available in pixel-perfect mode.");
+ // Display warning if size is being clamped or if framebuffer is larger than viewport.
+ if (CVarGetInteger("gAdvancedResolution.PixelPerfectMode", 0) &&
+ (CVarGetInteger("gAdvancedResolution.IntegerScale.NeverExceedBounds", 1) &&
+ CVarGetInteger("gAdvancedResolution.IntegerScale.Factor", 1) > integerScale_maximumBounds)) {
+ ImGui::SameLine();
+ ImGui::TextColored({ 0.85f, 0.85f, 0.0f, 1.0f }, ICON_FA_EXCLAMATION_TRIANGLE " Window exceeded.");
+ }
+
+ UIWidgets::PaddedEnhancementCheckbox("Automatically scale image to fit viewport",
+ "gAdvancedResolution.IntegerScale.FitAutomatically", true, true,
+ !CVarGetInteger("gAdvancedResolution.PixelPerfectMode", 0), "",
+ UIWidgets::CheckboxGraphics::Cross, false);
+ UIWidgets::Tooltip("Automatically sets scale factor to fit window. Only available in pixel-perfect mode.");
+ if (CVarGetInteger("gAdvancedResolution.IntegerScale.FitAutomatically", 0)) {
+ // This is just here to update the value shown on the slider.
+ // The function in LUS to handle this setting will ignore IntegerScaleFactor while active.
+ CVarSetInteger("gAdvancedResolution.IntegerScale.Factor", integerScale_maximumBounds);
+ // CVarSave();
+ }
+ }
+
+ UIWidgets::PaddedSeparator(true, true, 3.0f, 3.0f);
+
+ // Collapsible panel for additional settings
+ if (ImGui::CollapsingHeader("Additional Settings")) {
+ UIWidgets::Spacer(0);
+#if defined(__SWITCH__) || defined(__WIIU__)
+ // Disable aspect correction, stretching the framebuffer to fill the viewport.
+ // This option is only really needed on systems limited to 16:9 TV resolutions, such as consoles.
+ // The associated CVar is still functional on PC platforms if you want to use it though.
+ UIWidgets::PaddedEnhancementCheckbox("Disable aspect correction and stretch the output image.\n"
+ "(Might be useful for 4:3 televisions!)\n"
+ "Not available in Pixel Perfect Mode.",
+ "gAdvancedResolution.IgnoreAspectCorrection", false, true,
+ CVarGetInteger("gAdvancedResolution.PixelPerfectMode", 0), "",
+ UIWidgets::CheckboxGraphics::Cross, false);
+#else
+ if (CVarGetInteger("gAdvancedResolution.IgnoreAspectCorrection", 0)) {
+ // This setting is intentionally not exposed on PC platforms,
+ // but may be accidentally activated for varying reasons.
+ // Having this button should hopefully prevent support headaches.
+ ImGui::TextColored({ 0.0f, 0.85f, 0.85f, 1.0f }, ICON_FA_QUESTION_CIRCLE
+ " If the image is stretched and you don't know why, click this.");
+ if (ImGui::Button("Click to reenable aspect correction.")) {
+ CVarSetInteger("gAdvancedResolution.IgnoreAspectCorrection", (int)false);
+ CVarSave();
+ }
+ UIWidgets::Spacer(2);
+ }
+#endif
+
+ if (ImGui::Checkbox("Show a horizontal resolution field.", &showHorizontalResField)) {
+ if (!showHorizontalResField && (aspectRatioX > 0.0f)) { // when turning this setting off
+ // Refresh relevant values
+ aspectRatioX = aspectRatioY * horizontalPixelCount / verticalPixelCount;
+ horizontalPixelCount = (verticalPixelCount / aspectRatioY) * aspectRatioX;
+ } else { // when turning this setting on
+ item_aspectRatio = default_aspectRatio;
+ if (aspectRatioX > 0.0f) {
+ // Refresh relevant values in the opposite order
+ horizontalPixelCount = (verticalPixelCount / aspectRatioY) * aspectRatioX;
+ aspectRatioX = aspectRatioY * horizontalPixelCount / verticalPixelCount;
+ }
+ }
+ update[UPDATE_aspectRatioX] = true;
+ }
+
+ UIWidgets::PaddedEnhancementCheckbox(
+ "Don't allow integer scaling to exceed screen bounds.\n"
+ "(Makes screen bounds take priority over specified factor.)",
+ "gAdvancedResolution.IntegerScale.NeverExceedBounds", true, false,
+ !CVarGetInteger("gAdvancedResolution.PixelPerfectMode", 0) ||
+ CVarGetInteger("gAdvancedResolution.IntegerScale.FitAutomatically", 0),
+ "", UIWidgets::CheckboxGraphics::Cross, true);
+
+ if (!CVarGetInteger("gAdvancedResolution.IntegerScale.NeverExceedBounds", 1) ||
+ CVarGetInteger("gAdvancedResolution.IntegerScale.ExceedBoundsBy", 0)) {
+ ImGui::TextColored({ 0.0f, 0.85f, 0.85f, 1.0f },
+ " " ICON_FA_QUESTION_CIRCLE
+ " A scroll bar may become visible if screen bounds are exceeded.");
+ // Another helpful button for an unused CVar.
+ if (CVarGetInteger("gAdvancedResolution.IntegerScale.ExceedBoundsBy", 0)) {
+ if (ImGui::Button("Click to reset an unused CVar that may be causing this.")) {
+ CVarSetInteger("gAdvancedResolution.IntegerScale.ExceedBoundsBy", 0);
+ CVarSave();
+ }
+ }
+ } else {
+ UIWidgets::Spacer(enhancementSpacerHeight);
+ }
+
+ // I've ended up dummying this one out because it doesn't function in a satisfactory way.
+ // Consider this idea on the table, but I don't deem it an important enough feature to push for.
+ /*
+ UIWidgets::PaddedEnhancementCheckbox("Allow integer scale factor to go 1x above maximum screen bounds.",
+ "gAdvancedResolution.IntegerScale.ExceedBoundsBy", false, false,
+ !CVarGetInteger("gAdvancedResolution.PixelPerfectMode", 0), "",
+ UIWidgets::CheckboxGraphics::Cross, false);
+ if (CVarGetInteger("gAdvancedResolution.IntegerScale.ExceedBoundsBy", 0)) {
+ ImGui::TextColored({ 0.0f, 0.85f, 0.85f, 1.0f },
+ " " ICON_FA_QUESTION_CIRCLE
+ " A scroll bar may become visible if screen bounds are exceeded.");
+ }*/
+
+ } // end of Additional Settings
+
+ // Clamp and update the CVars that don't use UIWidgets
+ if (IsBoolArrayTrue(update)) {
+ if (update[UPDATE_aspectRatioX]) {
+ if (aspectRatioX < 0.0f) {
+ aspectRatioX = 0.0f;
+ }
+ CVarSetFloat("gAdvancedResolution.AspectRatioX", aspectRatioX);
+ }
+ if (update[UPDATE_aspectRatioY]) {
+ if (aspectRatioY < 0.0f) {
+ aspectRatioY = 0.0f;
+ }
+ CVarSetFloat("gAdvancedResolution.AspectRatioY", aspectRatioY);
+ }
+ if (update[UPDATE_verticalPixelCount]) {
+ // There's a upper and lower clamp on the Libultraship side too,
+ // so clamping it here is purely visual, so the vertical resolution field reflects it.
+ if (verticalPixelCount < minVerticalPixelCount) {
+ verticalPixelCount = minVerticalPixelCount;
+ }
+ if (verticalPixelCount > maxVerticalPixelCount) {
+ verticalPixelCount = maxVerticalPixelCount;
+ }
+ CVarSetInteger("gAdvancedResolution.VerticalPixelCount", verticalPixelCount);
+ }
+ // Delay saving this set of CVars by a predetermined length of time, in frames.
+ updateCountdown = countdownStartingValue;
+ }
+ if (updateCountdown > 0) {
+ updateCountdown--;
+ } else {
+ CVarSave();
+ }
+ }
+ ImGui::End();
+ }
+
+ void AdvancedResolutionSettingsWindow::UpdateElement() {
+ }
+
+ bool AdvancedResolutionSettingsWindow::IsDroppingFrames() {
+ // a rather imprecise way of checking for frame drops.
+ // but it's mostly there to inform the player of large drops.
+ const short targetFPS = CVarGetInteger("gInterpolationFPS", 20);
+ const float threshold = targetFPS / 20.0f + 4.1f;
+ return ImGui::GetIO().Framerate < targetFPS - threshold;
+ }
+
+ bool AdvancedResolutionSettingsWindow::IsBoolArrayTrue(bool* foo) {
+ for (unsigned short i = 0; i < sizeof(&foo); i++)
+ if (&foo[i])
+ return true;
+ return false;
+ }
+} // namespace AdvancedResolutionSettings \ No newline at end of file
diff --git a/src/port/ui/ResolutionEditor.h b/src/port/ui/ResolutionEditor.h
new file mode 100644
index 00000000..38af5607
--- /dev/null
+++ b/src/port/ui/ResolutionEditor.h
@@ -0,0 +1,19 @@
+#pragma once
+#include <libultraship/libultraship.h>
+
+namespace AdvancedResolutionSettings {
+ class AdvancedResolutionSettingsWindow : public LUS::GuiWindow {
+ private:
+ bool IsDroppingFrames();
+
+ protected:
+ bool IsBoolArrayTrue(bool*);
+
+ public:
+ using LUS::GuiWindow::GuiWindow;
+
+ void InitElement() override;
+ void DrawElement() override;
+ void UpdateElement() override;
+ };
+} // namespace AdvancedResolutionSettings \ No newline at end of file
diff --git a/src/port/ui/UIWidgets.cpp b/src/port/ui/UIWidgets.cpp
new file mode 100644
index 00000000..3375e79a
--- /dev/null
+++ b/src/port/ui/UIWidgets.cpp
@@ -0,0 +1,1033 @@
+//
+// UIWidgets.cpp
+// soh
+//
+// Created by David Chavez on 25.08.22.
+//
+
+#include "UIWidgets.h"
+
+#define IMGUI_DEFINE_MATH_OPERATORS
+#include "libultraship/src/Context.h"
+
+#include <ImGui/imgui_internal.h>
+#include <libultraship/libultraship.h>
+#include <libultraship/libultra/types.h>
+
+namespace UIWidgets {
+
+ // MARK: - Layout Helper
+
+ // Automatically adds newlines to break up text longer than a specified number of characters
+ // Manually included newlines will still be respected and reset the line length
+ // If line is midword when it hits the limit, text should break at the last encountered space
+ char* WrappedText(const char* text, unsigned int charactersPerLine) {
+ std::string newText(text);
+ const size_t tipLength = newText.length();
+ int lastSpace = -1;
+ int currentLineLength = 0;
+ for (unsigned int currentCharacter = 0; currentCharacter < tipLength; currentCharacter++) {
+ if (newText[currentCharacter] == '\n') {
+ currentLineLength = 0;
+ lastSpace = -1;
+ continue;
+ } else if (newText[currentCharacter] == ' ') {
+ lastSpace = currentCharacter;
+ }
+
+ if ((currentLineLength >= charactersPerLine) && (lastSpace >= 0)) {
+ newText[lastSpace] = '\n';
+ currentLineLength = currentCharacter - lastSpace - 1;
+ lastSpace = -1;
+ }
+ currentLineLength++;
+ }
+
+ return strdup(newText.c_str());
+ }
+
+ char* WrappedText(const std::string& text, unsigned int charactersPerLine) {
+ return WrappedText(text.c_str(), charactersPerLine);
+ }
+
+ void SetLastItemHoverText(const std::string& text) {
+ if (ImGui::IsItemHovered()) {
+ ImGui::BeginTooltip();
+ ImGui::Text("%s", WrappedText(text, 60));
+ ImGui::EndTooltip();
+ }
+ }
+
+ void SetLastItemHoverText(const char* text) {
+ if (ImGui::IsItemHovered()) {
+ ImGui::BeginTooltip();
+ ImGui::Text("%s", WrappedText(text, 60));
+ ImGui::EndTooltip();
+ }
+ }
+
+ // Adds a "?" next to the previous ImGui item with a custom tooltip
+ void InsertHelpHoverText(const std::string& text) {
+ ImGui::SameLine();
+ ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "?");
+ if (ImGui::IsItemHovered()) {
+ ImGui::BeginTooltip();
+ ImGui::Text("%s", WrappedText(text, 60));
+ ImGui::EndTooltip();
+ }
+ }
+
+ void InsertHelpHoverText(const char* text) {
+ ImGui::SameLine();
+ ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "?");
+ if (ImGui::IsItemHovered()) {
+ ImGui::BeginTooltip();
+ ImGui::Text("%s", WrappedText(text, 60));
+ ImGui::EndTooltip();
+ }
+ }
+
+
+ // MARK: - UI Elements
+
+ void Tooltip(const char* text) {
+ if (ImGui::IsItemHovered()) {
+ ImGui::SetTooltip("%s", WrappedText(text));
+ }
+ }
+
+ void Spacer(float height) {
+ ImGui::Dummy(ImVec2(0.0f, height));
+ }
+
+ void PaddedSeparator(bool padTop, bool padBottom, float extraVerticalTopPadding, float extraVerticalBottomPadding) {
+ if (padTop) {
+ Spacer(extraVerticalTopPadding);
+ }
+ ImGui::Separator();
+ if (padBottom) {
+ Spacer(extraVerticalBottomPadding);
+ }
+ }
+
+ void RenderCross(ImDrawList* draw_list, ImVec2 pos, ImU32 col, float sz) {
+ float thickness = ImMax(sz / 5.0f, 1.0f);
+ sz -= thickness * 0.5f;
+ pos += ImVec2(thickness * 0.25f, thickness * 0.25f);
+
+ draw_list->PathLineTo(ImVec2(pos.x, pos.y));
+ draw_list->PathLineTo(ImVec2(pos.x + sz, pos.y + sz));
+ draw_list->PathStroke(col, 0, thickness);
+
+ draw_list->PathLineTo(ImVec2(pos.x + sz, pos.y));
+ draw_list->PathLineTo(ImVec2(pos.x, pos.y + sz));
+ draw_list->PathStroke(col, 0, thickness);
+ }
+
+ bool CustomCheckbox(const char* label, bool* v, bool disabled, CheckboxGraphics disabledGraphic) {
+ ImGuiWindow* window = ImGui::GetCurrentWindow();
+ if (window->SkipItems) {
+ return false;
+ }
+
+ ImGuiContext& g = *GImGui;
+ const ImGuiStyle& style = g.Style;
+ const ImGuiID id = window->GetID(label);
+ const ImVec2 label_size = ImGui::CalcTextSize(label, NULL, true);
+
+ const float square_sz = ImGui::GetFrameHeight();
+ const ImVec2 pos = window->DC.CursorPos;
+ const ImRect total_bb(pos, pos + ImVec2(square_sz + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), label_size.y + style.FramePadding.y * 2.0f));
+ ImGui::ItemSize(total_bb, style.FramePadding.y);
+ if (!ImGui::ItemAdd(total_bb, id)) {
+ IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0));
+ return false;
+ }
+
+ bool hovered, held;
+ bool pressed = ImGui::ButtonBehavior(total_bb, id, &hovered, &held);
+ if (pressed) {
+ *v = !(*v);
+ ImGui::MarkItemEdited(id);
+ }
+
+ const ImRect check_bb(pos, pos + ImVec2(square_sz, square_sz));
+ ImGui::RenderNavHighlight(total_bb, id);
+ ImGui::RenderFrame(check_bb.Min, check_bb.Max, ImGui::GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), true, style.FrameRounding);
+ ImU32 check_col = ImGui::GetColorU32(ImGuiCol_CheckMark);
+ ImU32 cross_col = ImGui::GetColorU32(ImVec4(0.50f, 0.50f, 0.50f, 1.00f));
+ bool mixed_value = (g.LastItemData.InFlags & ImGuiItemFlags_MixedValue) != 0;
+ if (mixed_value) {
+ // Undocumented tristate/mixed/indeterminate checkbox (#2644)
+ // This may seem awkwardly designed because the aim is to make ImGuiItemFlags_MixedValue supported by all widgets (not just checkbox)
+ ImVec2 pad(ImMax(1.0f, IM_FLOOR(square_sz / 3.6f)), ImMax(1.0f, IM_FLOOR(square_sz / 3.6f)));
+ window->DrawList->AddRectFilled(check_bb.Min + pad, check_bb.Max - pad, check_col, style.FrameRounding);
+ } else if ((!disabled && *v) || (disabled && disabledGraphic == CheckboxGraphics::Checkmark)) {
+ const float pad = ImMax(1.0f, IM_FLOOR(square_sz / 6.0f));
+ ImGui::RenderCheckMark(window->DrawList, check_bb.Min + ImVec2(pad, pad), check_col, square_sz - pad * 2.0f);
+ } else if (disabled && disabledGraphic == CheckboxGraphics::Cross) {
+ const float pad = ImMax(1.0f, IM_FLOOR(square_sz / 6.0f));
+ RenderCross(window->DrawList, check_bb.Min + ImVec2(pad, pad), cross_col, square_sz - pad * 2.0f);
+ }
+
+ ImVec2 label_pos = ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y);
+ if (g.LogEnabled) {
+ ImGui::LogRenderedText(&label_pos, mixed_value ? "[~]" : *v ? "[x]" : "[ ]");
+ }
+ if (label_size.x > 0.0f) {
+ ImGui::RenderText(label_pos, label);
+ }
+
+ IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0));
+ return pressed;
+ }
+
+ void ReEnableComponent(const char* disabledTooltipText) {
+ // End of disable region of previous component
+ ImGui::PopStyleVar(1);
+ if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && strcmp(disabledTooltipText, "") != 0) {
+ ImGui::SetTooltip("%s", disabledTooltipText);
+ }
+ ImGui::PopItemFlag();
+ }
+
+ void DisableComponent(const float alpha) {
+ ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true);
+ ImGui::PushStyleVar(ImGuiStyleVar_Alpha, alpha);
+ }
+
+ bool EnhancementCheckbox(const char* text, const char* cvarName, bool disabled, const char* disabledTooltipText, CheckboxGraphics disabledGraphic, bool defaultValue) {
+ bool changed = false;
+ if (disabled) {
+ DisableComponent(ImGui::GetStyle().Alpha * 0.5f);
+ }
+
+ bool val = (bool)CVarGetInteger(cvarName, defaultValue);
+ if (CustomCheckbox(text, &val, disabled, disabledGraphic)) {
+ CVarSetInteger(cvarName, val);
+ LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
+ changed = true;
+ }
+
+ if (disabled) {
+ ReEnableComponent(disabledTooltipText);
+ }
+ return changed;
+ }
+
+ bool PaddedEnhancementCheckbox(const char* text, const char* cvarName, bool padTop, bool padBottom, bool disabled, const char* disabledTooltipText, CheckboxGraphics disabledGraphic, bool defaultValue) {
+ ImGui::BeginGroup();
+ if (padTop) Spacer(0);
+
+ bool changed = EnhancementCheckbox(text, cvarName, disabled, disabledTooltipText, disabledGraphic, defaultValue);
+
+ if (padBottom) Spacer(0);
+ ImGui::EndGroup();
+ return changed;
+ }
+
+ bool EnhancementCombobox(const char* cvarName, std::span<const char*, std::dynamic_extent> comboArray, uint8_t defaultIndex, bool disabled, const char* disabledTooltipText, uint8_t disabledValue) {
+ bool changed = false;
+ if (defaultIndex <= 0) {
+ defaultIndex = 0;
+ }
+
+ if (disabled) {
+ DisableComponent(ImGui::GetStyle().Alpha * 0.5f);
+ }
+
+ uint8_t selected = CVarGetInteger(cvarName, defaultIndex);
+ std::string comboName = std::string("##") + std::string(cvarName);
+ if (ImGui::BeginCombo(comboName.c_str(), comboArray[selected])) {
+ for (uint8_t i = 0; i < comboArray.size(); i++) {
+ if (strlen(comboArray[i]) > 1) {
+ if (ImGui::Selectable(comboArray[i], i == selected)) {
+ CVarSetInteger(cvarName, i);
+ selected = i;
+ changed = true;
+ LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
+ }
+ }
+ }
+ ImGui::EndCombo();
+ }
+
+ if (disabled) {
+ ReEnableComponent(disabledTooltipText);
+
+ if (disabledValue >= 0 && selected != disabledValue) {
+ CVarSetInteger(cvarName, disabledValue);
+ changed = true;
+ LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
+ }
+ }
+
+ return changed;
+ }
+
+ bool LabeledRightAlignedEnhancementCombobox(const char* label, const char* cvarName, std::span<const char*, std::dynamic_extent> comboArray, uint8_t defaultIndex, bool disabled, const char* disabledTooltipText, uint8_t disabledValue) {
+ ImGui::Text(label);
+ s32 currentValue = CVarGetInteger(cvarName, defaultIndex);
+
+#ifdef __WIIU__
+ ImGui::SameLine(ImGui::GetContentRegionAvail().x - (ImGui::CalcTextSize(comboArray[currentValue]).x + 40.0f));
+ ImGui::PushItemWidth(ImGui::CalcTextSize(comboArray[currentValue]).x + 60.0f);
+#else
+ ImGui::SameLine(ImGui::GetContentRegionAvail().x - (ImGui::CalcTextSize(comboArray[currentValue]).x + 20.0f));
+ ImGui::PushItemWidth(ImGui::CalcTextSize(comboArray[currentValue]).x + 30.0f);
+#endif
+
+ bool changed = EnhancementCombobox(cvarName, comboArray, defaultIndex, disabled, disabledTooltipText, disabledValue);
+
+ ImGui::PopItemWidth();
+ return changed;
+ }
+
+ void PaddedText(const char* text, bool padTop, bool padBottom) {
+ if (padTop) Spacer(0);
+
+ ImGui::Text("%s", text);
+
+ if (padBottom) Spacer(0);
+ }
+
+ bool EnhancementSliderInt(const char* text, const char* id, const char* cvarName, int min, int max, const char* format, int defaultValue, bool PlusMinusButton, bool disabled, const char* disabledTooltipText) {
+ bool changed = false;
+ int val = CVarGetInteger(cvarName, defaultValue);
+
+ if (disabled) {
+ DisableComponent(ImGui::GetStyle().Alpha * 0.5f);
+ }
+
+ ImGui::Text(text, val);
+ Spacer(0);
+
+ ImGui::BeginGroup();
+ if (PlusMinusButton) {
+ std::string MinusBTNName = " - ##" + std::string(cvarName);
+ if (ImGui::Button(MinusBTNName.c_str())) {
+ val--;
+ changed = true;
+ }
+ ImGui::SameLine();
+ ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 7.0f);
+ }
+
+ ImGui::PushItemWidth(std::min((ImGui::GetContentRegionAvail().x - (PlusMinusButton ? sliderButtonWidth : 0.0f)), maxSliderWidth));
+ if (ImGui::SliderInt(id, &val, min, max, format, ImGuiSliderFlags_AlwaysClamp))
+ {
+ changed = true;
+ }
+ ImGui::PopItemWidth();
+
+ if (PlusMinusButton) {
+ std::string PlusBTNName = " + ##" + std::string(cvarName);
+ ImGui::SameLine();
+ ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 7.0f);
+ if (ImGui::Button(PlusBTNName.c_str())) {
+ val++;
+ changed = true;
+ }
+ }
+ ImGui::EndGroup();
+
+ if (disabled) {
+ ReEnableComponent(disabledTooltipText);
+ }
+
+ if (val < min) {
+ val = min;
+ changed = true;
+ }
+
+ if (val > max) {
+ val = max;
+ changed = true;
+ }
+
+ if (changed) {
+ CVarSetInteger(cvarName, val);
+ LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
+ }
+
+ return changed;
+ }
+
+ bool EnhancementSliderFloat(const char* text, const char* id, const char* cvarName, float min, float max, const char* format, float defaultValue, bool isPercentage, bool PlusMinusButton, bool disabled, const char* disabledTooltipText) {
+ bool changed = false;
+ float val = CVarGetFloat(cvarName, defaultValue);
+
+ if (disabled) {
+ DisableComponent(ImGui::GetStyle().Alpha * 0.5f);
+ }
+
+ if (!isPercentage) {
+ ImGui::Text(text, val);
+ } else {
+ ImGui::Text(text, static_cast<int>(100 * val));
+ }
+ Spacer(0);
+
+ ImGui::BeginGroup();
+ if (PlusMinusButton) {
+ std::string MinusBTNName = " - ##" + std::string(cvarName);
+ if (ImGui::Button(MinusBTNName.c_str())) {
+ if (isPercentage) {
+ val -= 0.01f;
+ } else {
+ val -= 0.1f;
+ }
+ changed = true;
+ }
+ ImGui::SameLine();
+ ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 7.0f);
+ }
+
+ ImGui::PushItemWidth(std::min((ImGui::GetContentRegionAvail().x - (PlusMinusButton ? sliderButtonWidth : 0.0f)), maxSliderWidth));
+ if (ImGui::SliderFloat(id, &val, min, max, format, ImGuiSliderFlags_AlwaysClamp)) {
+ if (isPercentage) {
+ val = roundf(val * 100) / 100;
+ }
+ changed = true;
+ }
+ ImGui::PopItemWidth();
+
+ if (PlusMinusButton) {
+ std::string PlusBTNName = " + ##" + std::string(cvarName);
+ ImGui::SameLine();
+ ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 7.0f);
+ if (ImGui::Button(PlusBTNName.c_str())) {
+ if (isPercentage) {
+ val += 0.01f;
+ } else {
+ val += 0.1f;
+ }
+ changed = true;
+ }
+ }
+ ImGui::EndGroup();
+
+ if (disabled) {
+ ReEnableComponent(disabledTooltipText);
+ }
+
+ if (val < min) {
+ val = min;
+ changed = true;
+ }
+
+ if (val > max) {
+ val = max;
+ changed = true;
+ }
+
+ if (changed) {
+ CVarSetFloat(cvarName, val);
+ LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
+ }
+
+ return changed;
+ }
+
+ bool PaddedEnhancementSliderInt(const char* text, const char* id, const char* cvarName, int min, int max, const char* format, int defaultValue, bool PlusMinusButton, bool padTop, bool padBottom, bool disabled, const char* disabledTooltipText) {
+ bool changed = false;
+ ImGui::BeginGroup();
+ if (padTop) Spacer(0);
+
+ changed = EnhancementSliderInt(text, id, cvarName, min, max, format, defaultValue, PlusMinusButton, disabled, disabledTooltipText);
+
+ if (padBottom) Spacer(0);
+ ImGui::EndGroup();
+ return changed;
+ }
+
+ bool PaddedEnhancementSliderFloat(const char* text, const char* id, const char* cvarName, float min, float max, const char* format, float defaultValue, bool isPercentage, bool PlusMinusButton, bool padTop, bool padBottom, bool disabled, const char* disabledTooltipText) {
+ bool changed = false;
+ ImGui::BeginGroup();
+ if (padTop) Spacer(0);
+
+ changed = EnhancementSliderFloat(text, id, cvarName, min, max, format, defaultValue, isPercentage, PlusMinusButton, disabled, disabledTooltipText);
+
+ if (padBottom) Spacer(0);
+ ImGui::EndGroup();
+ return changed;
+ }
+
+ bool EnhancementRadioButton(const char* text, const char* cvarName, int id) {
+ /*Usage :
+ EnhancementRadioButton("My Visible Name","gMyCVarName", MyID);
+ First arg is the visible name of the Radio button
+ Second is the cvar name where MyID will be saved.
+ Note: the CVar name should be the same to each Buddies.
+ Example :
+ EnhancementRadioButton("English", "gLanguages", LANGUAGE_ENG);
+ EnhancementRadioButton("German", "gLanguages", LANGUAGE_GER);
+ EnhancementRadioButton("French", "gLanguages", LANGUAGE_FRA);
+ */
+ std::string make_invisible = "##" + std::string(text) + std::string(cvarName);
+
+ bool ret = false;
+ int val = CVarGetInteger(cvarName, 0);
+ if (ImGui::RadioButton(make_invisible.c_str(), id == val)) {
+ CVarSetInteger(cvarName, id);
+ LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
+ ret = true;
+ }
+ ImGui::SameLine();
+ ImGui::Text("%s", text);
+
+ return ret;
+ }
+
+ bool DrawResetColorButton(const char* cvarName, ImVec4* colors, ImVec4 defaultcolors, bool has_alpha) {
+ bool changed = false;
+ std::string Cvar_RBM = std::string(cvarName) + "RBM";
+ std::string MakeInvisible = "Reset##" + std::string(cvarName) + "Reset";
+ if (ImGui::Button(MakeInvisible.c_str())) {
+ colors->x = defaultcolors.x;
+ colors->y = defaultcolors.y;
+ colors->z = defaultcolors.z;
+ colors->w = has_alpha ? defaultcolors.w : 255.0f;
+
+ Color_RGBA8 colorsRGBA;
+ colorsRGBA.r = defaultcolors.x;
+ colorsRGBA.g = defaultcolors.y;
+ colorsRGBA.b = defaultcolors.z;
+ colorsRGBA.a = has_alpha ? defaultcolors.w : 255.0f;
+
+ CVarSetColor(cvarName, colorsRGBA);
+ CVarSetInteger(Cvar_RBM.c_str(), 0); //On click disable rainbow mode.
+ LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
+ changed = true;
+ }
+ Tooltip("Revert colors to the game's original colors (GameCube version)\nOverwrites previously chosen color");
+ return changed;
+ }
+
+ void DrawLockColorCheckbox(const char* cvarName) {
+ std::string Cvar_Lock = std::string(cvarName) + "Lock";
+ s32 lock = CVarGetInteger(Cvar_Lock.c_str(), 0);
+ std::string FullName = "Lock##" + Cvar_Lock;
+ EnhancementCheckbox(FullName.c_str(), Cvar_Lock.c_str());
+ Tooltip("Prevents this color from being changed upon selecting \"Randomize all\"");
+ }
+
+ void RainbowColor(const char* cvarName, ImVec4* colors) {
+ std::string Cvar_RBM = std::string(cvarName) + "RBM";
+ std::string MakeInvisible = "Rainbow##" + std::string(cvarName) + "Rainbow";
+
+ EnhancementCheckbox(MakeInvisible.c_str(), Cvar_RBM.c_str());
+ Tooltip("Cycles through colors on a timer\nOverwrites previously chosen color");
+ }
+
+ void LoadPickersColors(ImVec4& ColorArray, const char* cvarname, const ImVec4& default_colors, bool has_alpha) {
+ Color_RGBA8 defaultColors;
+ defaultColors.r = default_colors.x;
+ defaultColors.g = default_colors.y;
+ defaultColors.b = default_colors.z;
+ defaultColors.a = default_colors.w;
+
+ Color_RGBA8 cvarColor = CVarGetColor(cvarname, defaultColors);
+
+ ColorArray.x = cvarColor.r / 255.0;
+ ColorArray.y = cvarColor.g / 255.0;
+ ColorArray.z = cvarColor.b / 255.0;
+ ColorArray.w = cvarColor.a / 255.0;
+ }
+
+ void DrawFlagArray32(const std::string& name, uint32_t& flags) {
+ ImGui::PushID(name.c_str());
+ for (int32_t flagIndex = 0; flagIndex < 32; flagIndex++) {
+ if ((flagIndex % 8) != 0) {
+ ImGui::SameLine();
+ }
+ ImGui::PushID(flagIndex);
+ uint32_t bitMask = 1 << flagIndex;
+ bool flag = (flags & bitMask) != 0;
+ if (ImGui::Checkbox("##check", &flag)) {
+ if (flag) {
+ flags |= bitMask;
+ } else {
+ flags &= ~bitMask;
+ }
+ }
+ ImGui::PopID();
+ }
+ ImGui::PopID();
+ }
+
+ void DrawFlagArray16(const std::string& name, uint16_t& flags) {
+ ImGui::PushID(name.c_str());
+ for (int16_t flagIndex = 0; flagIndex < 16; flagIndex++) {
+ if ((flagIndex % 8) != 0) {
+ ImGui::SameLine();
+ }
+ ImGui::PushID(flagIndex);
+ uint16_t bitMask = 1 << flagIndex;
+ bool flag = (flags & bitMask) != 0;
+ if (ImGui::Checkbox("##check", &flag)) {
+ if (flag) {
+ flags |= bitMask;
+ } else {
+ flags &= ~bitMask;
+ }
+ }
+ ImGui::PopID();
+ }
+ ImGui::PopID();
+ }
+
+ void DrawFlagArray8(const std::string& name, uint8_t& flags) {
+ ImGui::PushID(name.c_str());
+ for (int8_t flagIndex = 0; flagIndex < 8; flagIndex++) {
+ if ((flagIndex % 8) != 0) {
+ ImGui::SameLine();
+ }
+ ImGui::PushID(flagIndex);
+ uint8_t bitMask = 1 << flagIndex;
+ bool flag = (flags & bitMask) != 0;
+ if (ImGui::Checkbox("##check", &flag)) {
+ if (flag) {
+ flags |= bitMask;
+ } else {
+ flags &= ~bitMask;
+ }
+ }
+ ImGui::PopID();
+ }
+ ImGui::PopID();
+ }
+
+ // V2
+
+ void PushStyleMenu(const ImVec4& color) {
+ ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(color.x, color.y, color.z, 0.5f));
+ ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(color.x, color.y, color.z, 1.0f));
+ ImGui::PushStyleColor(ImGuiCol_PopupBg, UIWidgets::Colors::DarkGray);
+ ImGui::PushStyleColor(ImGuiCol_Border, UIWidgets::Colors::DarkGray);
+ ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(8.0f, 15.0f));
+ ImGui::PushStyleVar(ImGuiStyleVar_PopupBorderSize, 3.0f);
+ }
+
+ void PopStyleMenu() {
+ ImGui::PopStyleVar(2);
+ ImGui::PopStyleColor(4);
+ }
+
+ bool BeginMenu(const char* label, const ImVec4& color) {
+ bool dirty = false;
+ PushStyleMenu(color);
+ if (ImGui::BeginMenu(label)) {
+ dirty = true;
+ }
+ PopStyleMenu();
+ return dirty;
+ }
+
+ void PushStyleMenuItem(const ImVec4& color) {
+ ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(color.x, color.y, color.z, 1.0f));
+ ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(20.0f, 15.0f));
+ }
+
+ void PopStyleMenuItem() {
+ ImGui::PopStyleVar(1);
+ ImGui::PopStyleColor(1);
+ }
+
+ bool MenuItem(const char* label, const char* shortcut, const ImVec4& color) {
+ bool dirty = false;
+ PushStyleMenuItem(color);
+ if (ImGui::MenuItem(label, shortcut)) {
+ dirty = true;
+ }
+ PopStyleMenuItem();
+ return dirty;
+ }
+
+ void PushStyleButton(const ImVec4& color) {
+ ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(color.x, color.y, color.z, 1.0f));
+ ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(color.x, color.y, color.z, 0.8f));
+ ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(color.x, color.y, color.z, 0.6f));
+ ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.0f, 0.0f, 0.0f, 0.3f));
+ ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f);
+ ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10.0f, 8.0f));
+ ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 5.0f);
+ }
+
+ void PopStyleButton() {
+ ImGui::PopStyleVar(3);
+ ImGui::PopStyleColor(4);
+ }
+
+ bool Button(const char* label, const ButtonOptions& options) {
+ ImGui::BeginDisabled(options.disabled);
+ PushStyleButton(options.color);
+ bool dirty = ImGui::Button(label, options.size);
+ PopStyleButton();
+ ImGui::EndDisabled();
+ if (options.disabled && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && strcmp(options.disabledTooltip, "") != 0) {
+ ImGui::SetTooltip("%s", WrappedText(options.disabledTooltip));
+ } else if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && strcmp(options.tooltip, "") != 0) {
+ ImGui::SetTooltip("%s", WrappedText(options.tooltip));
+ }
+ return dirty;
+ }
+
+ bool WindowButton(const char* label, const char* cvarName, std::shared_ptr<LUS::GuiWindow> windowPtr, const ButtonOptions& options) {
+ ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0, 0));
+ std::string buttonText = label;
+ bool dirty = false;
+ if (CVarGetInteger(cvarName, 0)) {
+ buttonText = ICON_FA_WINDOW_CLOSE " " + buttonText;
+ } else {
+ buttonText = ICON_FA_EXTERNAL_LINK_SQUARE " " + buttonText;
+ }
+ if (Button(buttonText.c_str(), options)) {
+ windowPtr->ToggleVisibility();
+ dirty = true;
+ }
+ ImGui::PopStyleVar();
+ return dirty;
+ }
+
+ void PushStyleCheckbox(const ImVec4& color) {
+ ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(color.x, color.y, color.z, 1.0f));
+ ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(color.x, color.y, color.z, 0.8f));
+ ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(color.x, color.y, color.z, 0.6f));
+ ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.0f, 0.0f, 0.0f, 0.3f));
+ ImGui::PushStyleColor(ImGuiCol_CheckMark, ImVec4(1.0f, 1.0f, 1.0f, 0.7f));
+ ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f);
+ ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10.0f, 6.0f));
+ ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 5.0f);
+ }
+
+ void PopStyleCheckbox() {
+ ImGui::PopStyleVar(3);
+ ImGui::PopStyleColor(5);
+ }
+
+ bool Checkbox(const char* label, bool* value, const CheckboxOptions& options) {
+ ImGui::PushID(label);
+ bool dirty = false;
+ float startX = ImGui::GetCursorPosX();
+ std::string invisibleLabelStr = "##" + std::string(label);
+ const char* invisibleLabel = invisibleLabelStr.c_str();
+ ImGui::BeginDisabled(options.disabled);
+ PushStyleCheckbox(options.color);
+ if (options.alignment == ComponentAlignment::Right) {
+ if (options.labelPosition == LabelPosition::Near || options.labelPosition == LabelPosition::Far || options.labelPosition == LabelPosition::None) {
+ ImGui::SameLine(ImGui::GetContentRegionAvail().x - ImGui::GetStyle().FramePadding.x * 2 - ImGui::GetStyle().ItemSpacing.x);
+ } else if (options.labelPosition == LabelPosition::Above) {
+ ImGui::SameLine(ImGui::GetContentRegionAvail().x - ImGui::CalcTextSize(label).x);
+ ImGui::Text(label);
+ ImGui::NewLine();
+ ImGui::SameLine(ImGui::GetContentRegionAvail().x - ImGui::GetStyle().FramePadding.x * 2 - ImGui::GetStyle().ItemSpacing.x);
+ }
+ } else if (options.alignment == ComponentAlignment::Left) {
+ if (options.labelPosition == LabelPosition::Above) {
+ ImGui::Text(label);
+ }
+ }
+ dirty = ImGui::Checkbox(invisibleLabel, value);
+ if (options.alignment == ComponentAlignment::Right) {
+ if (options.labelPosition == LabelPosition::Near) {
+ ImGui::SameLine(ImGui::GetContentRegionAvail().x - ImGui::CalcTextSize(label).x - ImGui::GetStyle().FramePadding.x * 2 - ImGui::GetStyle().ItemSpacing.x * 2);
+ ImGui::Text(label);
+ } else if (options.labelPosition == LabelPosition::Far) {
+ ImGui::SameLine();
+ ImGui::SetCursorPosX(startX);
+ ImGui::Text(label);
+ }
+ } else if (options.alignment == ComponentAlignment::Left) {
+ if (options.labelPosition == LabelPosition::Near) {
+ ImGui::SameLine();
+ ImGui::Text(label);
+ } else if (options.labelPosition == LabelPosition::Far) {
+ ImGui::SameLine(ImGui::GetContentRegionAvail().x - ImGui::CalcTextSize(label).x);
+ ImGui::Text(label);
+ }
+ }
+ PopStyleCheckbox();
+ ImGui::EndDisabled();
+ if (options.disabled && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && strcmp(options.disabledTooltip, "") != 0) {
+ ImGui::SetTooltip("%s", WrappedText(options.disabledTooltip));
+ } else if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && strcmp(options.tooltip, "") != 0) {
+ ImGui::SetTooltip("%s", WrappedText(options.tooltip));
+ }
+ ImGui::PopID();
+ return dirty;
+ }
+
+ bool CVarCheckbox(const char* label, const char* cvarName, const CheckboxOptions& options) {
+ bool dirty = false;
+ bool value = (bool)CVarGetInteger(cvarName, options.defaultValue);
+ if (Checkbox(label, &value, options)) {
+ CVarSetInteger(cvarName, value);
+ LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
+ dirty = true;
+ }
+ return dirty;
+ }
+
+ void PushStyleCombobox(const ImVec4& color) {
+ ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(color.x, color.y, color.z, 0.8f));
+ ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(color.x, color.y, color.z, 0.6f));
+ ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(color.x, color.y, color.z, 0.6f));
+ ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(color.x, color.y, color.z, 1.0f));
+ ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(color.x, color.y, color.z, 0.8f));
+ ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(color.x, color.y, color.z, 1.0f));
+ ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(color.x, color.y, color.z, 0.5f));
+ ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(color.x, color.y, color.z, 0.6f));
+ ImGui::PushStyleColor(ImGuiCol_HeaderActive, ImVec4(color.x, color.y, color.z, 0.6f));
+ ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f);
+ ImGui::PushStyleVar(ImGuiStyleVar_PopupRounding, 3.0f);
+ ImGui::PushStyleVar(ImGuiStyleVar_PopupBorderSize, 0.0f);
+ ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10.0f, 6.0f));
+ }
+
+ void PopStyleCombobox() {
+ ImGui::PopStyleVar(4);
+ ImGui::PopStyleColor(9);
+ }
+
+ bool Combobox(const char* label, uint8_t* value, std::span<const char*, std::dynamic_extent> comboArray, const ComboboxOptions& options) {
+ bool dirty = false;
+ float startX = ImGui::GetCursorPosX();
+ std::string invisibleLabelStr = "##" + std::string(label);
+ const char* invisibleLabel = invisibleLabelStr.c_str();
+ ImGui::PushID(label);
+ ImGui::BeginGroup();
+ ImGui::BeginDisabled(options.disabled);
+ PushStyleCombobox(options.color);
+ if (options.alignment == ComponentAlignment::Left) {
+ if (options.labelPosition == LabelPosition::Above) {
+ ImGui::Text(label);
+ ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
+ } else if (options.labelPosition == LabelPosition::Near) {
+ ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - ImGui::CalcTextSize(label).x - ImGui::GetStyle().ItemSpacing.x * 2);
+ } else if (options.labelPosition == LabelPosition::Far || options.labelPosition == LabelPosition::None) {
+ ImGui::SetNextItemWidth(ImGui::CalcTextSize(comboArray[*value]).x + ImGui::GetStyle().FramePadding.x * 4 + ImGui::GetStyle().ItemSpacing.x);
+ }
+ } else if (options.alignment == ComponentAlignment::Right) {
+ if (options.labelPosition == LabelPosition::Above) {
+ ImGui::NewLine();
+ ImGui::SameLine(ImGui::GetContentRegionAvail().x - ImGui::CalcTextSize(label).x);
+ ImGui::Text(label);
+ ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
+ } else if (options.labelPosition == LabelPosition::Near) {
+ ImGui::SameLine(ImGui::CalcTextSize(label).x + ImGui::GetStyle().ItemSpacing.x * 2);
+ ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
+ } else if (options.labelPosition == LabelPosition::Far || options.labelPosition == LabelPosition::None) {
+ float width = ImGui::CalcTextSize(comboArray[*value]).x + ImGui::GetStyle().FramePadding.x * 4;
+ ImGui::SameLine(ImGui::GetContentRegionAvail().x - width);
+ ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
+ }
+ }
+ if (ImGui::BeginCombo(invisibleLabel, comboArray[*value], options.flags)) {
+ ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(10.0f, 10.0f));
+ for (uint8_t i = 0; i < comboArray.size(); i++) {
+ if (strlen(comboArray[i]) > 1) {
+ if (ImGui::Selectable(comboArray[i], i == *value)) {
+ *value = i;
+ dirty = true;
+ }
+ }
+ }
+ ImGui::PopStyleVar();
+ ImGui::EndCombo();
+ }
+ if (options.alignment == ComponentAlignment::Left) {
+ if (options.labelPosition == LabelPosition::Near) {
+ ImGui::SameLine();
+ ImGui::Text(label);
+ } else if (options.labelPosition == LabelPosition::Far) {
+ ImGui::SameLine(ImGui::GetContentRegionAvail().x - ImGui::CalcTextSize(label).x);
+ ImGui::Text(label);
+ }
+ } else if (options.alignment == ComponentAlignment::Right) {
+ if (options.labelPosition == LabelPosition::Near || options.labelPosition == LabelPosition::Far) {
+ ImGui::SameLine(startX);
+ ImGui::Text(label);
+ }
+ }
+ PopStyleCombobox();
+ ImGui::EndDisabled();
+ ImGui::EndGroup();
+ if (options.disabled && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && strcmp(options.disabledTooltip, "") != 0) {
+ ImGui::SetTooltip("%s", WrappedText(options.disabledTooltip));
+ } else if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && strcmp(options.tooltip, "") != 0) {
+ ImGui::SetTooltip("%s", WrappedText(options.tooltip));
+ }
+ ImGui::PopID();
+ return dirty;
+ }
+
+ bool CVarCombobox(const char* label, const char* cvarName, std::span<const char*, std::dynamic_extent> comboArray, const ComboboxOptions& options) {
+ bool dirty = false;
+ uint8_t value = (uint8_t)CVarGetInteger(cvarName, options.defaultIndex);
+ if (Combobox(label, &value, comboArray, options)) {
+ CVarSetInteger(cvarName, value);
+ LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
+ dirty = true;
+ }
+ return dirty;
+ }
+
+ void PushStyleSlider(const ImVec4& color) {
+ ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(color.x, color.y, color.z, 1.0f));
+ ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(color.x, color.y, color.z, 1.0f));
+ ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(color.x, color.y, color.z, 1.0f));
+ ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(color.x, color.y, color.z, 1.0f));
+ ImGui::PushStyleColor(ImGuiCol_SliderGrab, ImVec4(1.0, 1.0, 1.0, 0.4f));
+ ImGui::PushStyleColor(ImGuiCol_SliderGrabActive, ImVec4(1.0, 1.0, 1.0, 0.5f));
+ ImGui::PushStyleVar(ImGuiStyleVar_GrabRounding, 3.0f);
+ ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f);
+ ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10.0f, 8.0f));
+ ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f);
+ }
+
+ void PopStyleSlider() {
+ ImGui::PopStyleVar(4);
+ ImGui::PopStyleColor(6);
+ }
+
+ bool SliderInt(const char* label, int32_t* value, int32_t min, int32_t max, const IntSliderOptions& options) {
+ bool dirty = false;
+ std::string invisibleLabelStr = "##" + std::string(label);
+ const char* invisibleLabel = invisibleLabelStr.c_str();
+ ImGui::PushID(label);
+ ImGui::BeginGroup();
+ ImGui::BeginDisabled(options.disabled);
+ PushStyleSlider(options.color);
+ if (options.alignment == ComponentAlignment::Left) {
+ if (options.labelPosition == LabelPosition::Above) {
+ ImGui::Text(label, *value);
+ }
+ } else if (options.alignment == ComponentAlignment::Right) {
+ if (options.labelPosition == LabelPosition::Above) {
+ ImGui::NewLine();
+ ImGui::SameLine(ImGui::GetContentRegionAvail().x - ImGui::CalcTextSize(label).x);
+ ImGui::Text(label, *value);
+ }
+ }
+ if (options.showButtons) {
+ if (Button("-", { .color = options.color, .size = Sizes::Inline }) && *value > min) {
+ *value -= options.step;
+ if (*value < min) *value = min;
+ LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
+ dirty = true;
+ }
+ ImGui::SameLine(0, 3.0f);
+ ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - (ImGui::CalcTextSize("+").x + 20.0f + 3.0f));
+ } else {
+ ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
+ }
+ if (ImGui::SliderScalar(invisibleLabel, ImGuiDataType_S32, value, &min, &max, options.format, options.flags)) {
+ LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
+ dirty = true;
+ }
+ if (options.showButtons) {
+ ImGui::SameLine(0, 3.0f);
+ ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
+ if (Button("+", { .color = options.color, .size = Sizes::Inline }) && *value < max) {
+ *value += options.step;
+ if (*value > max) *value = max;
+ LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
+ dirty = true;
+ }
+ }
+ PopStyleSlider();
+ ImGui::EndDisabled();
+ ImGui::EndGroup();
+ if (options.disabled && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && strcmp(options.disabledTooltip, "") != 0) {
+ ImGui::SetTooltip("%s", WrappedText(options.disabledTooltip));
+ } else if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && strcmp(options.tooltip, "") != 0) {
+ ImGui::SetTooltip("%s", WrappedText(options.tooltip));
+ }
+ ImGui::PopID();
+ return dirty;
+ }
+
+ bool CVarSliderInt(const char* label, const char* cvarName, int32_t min, int32_t max, const int32_t defaultValue, const IntSliderOptions& options) {
+ bool dirty = false;
+ int32_t value = CVarGetInteger(cvarName, defaultValue);
+ if (SliderInt(label, &value, min, max, options)) {
+ CVarSetInteger(cvarName, value);
+ LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
+ dirty = true;
+ }
+ return dirty;
+ }
+
+ bool SliderFloat(const char* label, float* value, float min, float max, const FloatSliderOptions& options) {
+ bool dirty = false;
+ std::string invisibleLabelStr = "##" + std::string(label);
+ const char* invisibleLabel = invisibleLabelStr.c_str();
+ float valueToDisplay = options.isPercentage ? *value * 100.0f : *value;
+ float maxToDisplay = options.isPercentage ? max * 100.0f : max;
+ float minToDisplay = options.isPercentage ? min * 100.0f : min;
+ ImGui::PushID(label);
+ ImGui::BeginGroup();
+ ImGui::BeginDisabled(options.disabled);
+ PushStyleSlider(options.color);
+ if (options.alignment == ComponentAlignment::Left) {
+ if (options.labelPosition == LabelPosition::Above) {
+ ImGui::Text(label, valueToDisplay);
+ }
+ } else if (options.alignment == ComponentAlignment::Right) {
+ if (options.labelPosition == LabelPosition::Above) {
+ ImGui::NewLine();
+ ImGui::SameLine(ImGui::GetContentRegionAvail().x - ImGui::CalcTextSize(label).x);
+ ImGui::Text(label, valueToDisplay);
+ }
+ }
+ if (options.showButtons) {
+ if (Button("-", { .color = options.color, .size = Sizes::Inline }) && *value > min) {
+ *value -= options.step;
+ if (*value < min) *value = min;
+ LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
+ dirty = true;
+ }
+ ImGui::SameLine(0, 3.0f);
+ ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - (ImGui::CalcTextSize("+").x + 20.0f + 3.0f));
+ } else {
+ ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
+ }
+ if (ImGui::SliderScalar(invisibleLabel, ImGuiDataType_Float, &valueToDisplay, &minToDisplay, &maxToDisplay, options.format, options.flags)) {
+ *value = options.isPercentage ? valueToDisplay / 100.0f : valueToDisplay;
+ LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
+ dirty = true;
+ }
+ if (options.showButtons) {
+ ImGui::SameLine(0, 3.0f);
+ ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
+ if (Button("+", { .color = options.color, .size = Sizes::Inline }) && *value < max) {
+ *value += options.step;
+ if (*value > max) *value = max;
+ LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
+ dirty = true;
+ }
+ }
+ PopStyleSlider();
+ ImGui::EndDisabled();
+ ImGui::EndGroup();
+ if (options.disabled && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && strcmp(options.disabledTooltip, "") != 0) {
+ ImGui::SetTooltip("%s", WrappedText(options.disabledTooltip));
+ } else if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && strcmp(options.tooltip, "") != 0) {
+ ImGui::SetTooltip("%s", WrappedText(options.tooltip));
+ }
+ ImGui::PopID();
+ return dirty;
+ }
+
+ bool CVarSliderFloat(const char* label, const char* cvarName, float min, float max, const float defaultValue, const FloatSliderOptions& options) {
+ bool dirty = false;
+ float value = CVarGetFloat(cvarName, defaultValue);
+ if (SliderFloat(label, &value, min, max, options)) {
+ CVarSetFloat(cvarName, value);
+ LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick();
+ dirty = true;
+ }
+ return dirty;
+ }
+}
diff --git a/src/port/ui/UIWidgets.h b/src/port/ui/UIWidgets.h
new file mode 100644
index 00000000..2d398f61
--- /dev/null
+++ b/src/port/ui/UIWidgets.h
@@ -0,0 +1,209 @@
+#pragma once
+
+#include <string>
+#include <vector>
+#include <span>
+#include <stdint.h>
+#include <ImGui/imgui.h>
+#include <libultraship/libultraship.h>
+
+namespace UIWidgets {
+
+ struct TextFilters {
+ static int FilterNumbers(ImGuiInputTextCallbackData* data) {
+ if (data->EventChar < 256 && strchr("1234567890", (char)data->EventChar)) {
+ return 0;
+ }
+ return 1;
+ }
+
+ static int FilterAlphaNum(ImGuiInputTextCallbackData* data) {
+ const char* alphanum = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWYZ0123456789";
+ if (data->EventChar < 256 && strchr(alphanum, (char)data->EventChar)) {
+ return 0;
+ }
+ return 1;
+ }
+
+ };
+
+ // MARK: - Enums
+
+ enum class CheckboxGraphics {
+ Cross,
+ Checkmark,
+ None
+ };
+ constexpr float maxSliderWidth = 260.0f;
+#ifdef __SWITCH__
+ constexpr float sliderButtonWidth = 42.0f;
+#elif defined(__WIIU__)
+ constexpr float sliderButtonWidth = 60.0f;
+#else
+ constexpr float sliderButtonWidth = 30.0f;
+#endif
+
+ char* WrappedText(const char* text, unsigned int charactersPerLine = 60);
+ char* WrappedText(const std::string& text, unsigned int charactersPerLine);
+
+ void SetLastItemHoverText(const std::string& text);
+ void SetLastItemHoverText(const char* text);
+
+ void InsertHelpHoverText(const std::string& text);
+ void InsertHelpHoverText(const char* text);
+
+ void Tooltip(const char* text);
+ void Spacer(float height);
+ void PaddedSeparator(bool padTop = true, bool padBottom = true, float extraVerticalTopPadding = 0.0f, float extraVerticalBottomPadding = 0.0f);
+
+ void RenderCross(ImDrawList* draw_list, ImVec2 pos, ImU32 col, float sz);
+ bool CustomCheckbox(const char* label, bool* v, bool disabled, CheckboxGraphics disabledGraphic);
+
+ void ReEnableComponent(const char* disabledTooltipText);
+ void DisableComponent(const float alpha);
+
+ bool EnhancementCheckbox(const char* text, const char* cvarName, bool disabled = false, const char* disabledTooltipText = "", CheckboxGraphics disabledGraphic = CheckboxGraphics::Cross, bool defaultValue = false);
+ bool PaddedEnhancementCheckbox(const char* text, const char* cvarName, bool padTop = true, bool padBottom = true, bool disabled = false, const char* disabledTooltipText = "", CheckboxGraphics disabledGraphic = CheckboxGraphics::Cross, bool defaultValue = false);
+
+ bool EnhancementCombobox(const char* cvarName, std::span<const char*, std::dynamic_extent> comboArray, uint8_t defaultIndex, bool disabled = false, const char* disabledTooltipText = "", uint8_t disabledValue = -1);
+ bool LabeledRightAlignedEnhancementCombobox(const char* label, const char* cvarName, std::span<const char*, std::dynamic_extent> comboArray, uint8_t defaultIndex, bool disabled = false, const char* disabledTooltipText = "", uint8_t disabledValue = -1);
+
+ void PaddedText(const char* text, bool padTop = true, bool padBottom = true);
+
+ bool EnhancementSliderInt(const char* text, const char* id, const char* cvarName, int min, int max, const char* format, int defaultValue = 0, bool PlusMinusButton = true, bool disabled = false, const char* disabledTooltipText = "");
+ bool PaddedEnhancementSliderInt(const char* text, const char* id, const char* cvarName, int min, int max, const char* format, int defaultValue = 0, bool PlusMinusButton = true, bool padTop = true, bool padBottom = true, bool disabled = false, const char* disabledTooltipText = "");
+ bool EnhancementSliderFloat(const char* text, const char* id, const char* cvarName, float min, float max, const char* format, float defaultValue, bool isPercentage, bool PlusMinusButton = true, bool disabled = false, const char* disabledTooltipText = "");
+ bool PaddedEnhancementSliderFloat(const char* text, const char* id, const char* cvarName, float min, float max, const char* format, float defaultValue, bool isPercentage, bool PlusMinusButton = true, bool padTop = true, bool padBottom = true, bool disabled = false, const char* disabledTooltipText = "");
+
+ bool EnhancementRadioButton(const char* text, const char* cvarName, int id);
+
+ bool DrawResetColorButton(const char* cvarName, ImVec4* colors, ImVec4 defaultcolors, bool has_alpha);
+ bool DrawRandomizeColorButton(const char* cvarName, ImVec4* colors);
+ void DrawLockColorCheckbox(const char* cvarName);
+ void RainbowColor(const char* cvarName, ImVec4* colors);
+
+ void LoadPickersColors(ImVec4& ColorArray, const char* cvarname, const ImVec4& default_colors, bool has_alpha);
+ bool EnhancementColor(const char* text, const char* cvarName, ImVec4 ColorRGBA, ImVec4 default_colors, bool allow_rainbow = true, bool has_alpha = false, bool TitleSameLine = false);
+
+ void DrawFlagArray32(const std::string& name, uint32_t& flags);
+ void DrawFlagArray16(const std::string& name, uint16_t& flags);
+ void DrawFlagArray8(const std::string& name, uint8_t& flags);
+
+ // V2
+ namespace Colors {
+ const ImVec4 White = ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
+ const ImVec4 Gray = ImVec4(0.4f, 0.4f, 0.4f, 1.0f);
+ const ImVec4 DarkGray = ImVec4(0.1f, 0.1f, 0.1f, 1.0f);
+ const ImVec4 Indigo = ImVec4(0.24f, 0.31f, 0.71f, 1.0f);
+ const ImVec4 Red = ImVec4(0.5f, 0.0f, 0.0f, 1.0f);
+ const ImVec4 DarkRed = ImVec4(0.3f, 0.0f, 0.0f, 1.0f);
+ const ImVec4 LightGreen = ImVec4(0.0f, 0.7f, 0.0f, 1.0f);
+ const ImVec4 Green = ImVec4(0.0f, 0.5f, 0.0f, 1.0f);
+ const ImVec4 DarkGreen = ImVec4(0.0f, 0.3f, 0.0f, 1.0f);
+ const ImVec4 Yellow = ImVec4(1.0f, 0.627f, 0.0f, 1.0f);
+ };
+
+ namespace Sizes {
+ const ImVec2 Inline = ImVec2(0.0f, 0.0f);
+ const ImVec2 Fill = ImVec2(-1.0f, 0.0f);
+ }
+
+ enum LabelPosition {
+ Near,
+ Far,
+ Above,
+ None,
+ Within,
+ };
+
+ enum ComponentAlignment {
+ Left,
+ Right,
+ };
+
+ void PushStyleMenu(const ImVec4& color = Colors::Indigo);
+ void PopStyleMenu();
+ bool BeginMenu(const char* label, const ImVec4& color = Colors::Indigo);
+
+ void PushStyleMenuItem(const ImVec4& color = Colors::Indigo);
+ void PopStyleMenuItem();
+ bool MenuItem(const char* label, const char* shortcut = NULL, const ImVec4& color = Colors::Indigo);
+
+ struct ButtonOptions {
+ const ImVec4 color = Colors::Gray;
+ const ImVec2 size = Sizes::Fill;
+ const char* tooltip = "";
+ bool disabled = false;
+ const char* disabledTooltip = "";
+ };
+
+ void PushStyleButton(const ImVec4& color = Colors::Gray);
+ void PopStyleButton();
+ bool Button(const char* label, const ButtonOptions& options = {});
+ bool WindowButton(const char* label, const char* cvarName, std::shared_ptr<LUS::GuiWindow> windowPtr, const ButtonOptions& options = {});
+
+ struct CheckboxOptions {
+ const ImVec4 color = Colors::Indigo;
+ const char* tooltip = "";
+ bool disabled = false;
+ const char* disabledTooltip = "";
+ bool defaultValue = false; // Only applicable to CVarCheckbox
+ ComponentAlignment alignment = ComponentAlignment::Left;
+ LabelPosition labelPosition = LabelPosition::Near;
+ };
+
+ void PushStyleCheckbox(const ImVec4& color = Colors::Indigo);
+ void PopStyleCheckbox();
+ bool Checkbox(const char* label, bool* v, const CheckboxOptions& options = {});
+ bool CVarCheckbox(const char* label, const char* cvarName, const CheckboxOptions& options = {});
+
+ struct ComboboxOptions {
+ const ImVec4 color = Colors::Indigo;
+ const char* tooltip = "";
+ bool disabled = false;
+ const char* disabledTooltip = "";
+ uint32_t defaultIndex = 0; // Only applicable to CVarCombobox
+ ComponentAlignment alignment = ComponentAlignment::Left;
+ LabelPosition labelPosition = LabelPosition::Above;
+ ImGuiComboFlags flags = 0;
+ };
+
+ void PushStyleCombobox(const ImVec4& color = Colors::Indigo);
+ void PopStyleCombobox();
+ bool Combobox(const char* label, uint8_t* value, std::span<const char*, std::dynamic_extent> comboArray, const ComboboxOptions& options = {});
+ bool CVarCombobox(const char* label, const char* cvarName, std::span<const char*, std::dynamic_extent> comboArray, const ComboboxOptions& options = {});
+
+ struct IntSliderOptions {
+ const ImVec4 color = Colors::Gray;
+ const char* tooltip = "";
+ bool disabled = false;
+ const char* disabledTooltip = "";
+ bool showButtons = true;
+ ImGuiSliderFlags flags = 0;
+ const char* format = "%d";
+ const uint32_t step = 1;
+ ComponentAlignment alignment = ComponentAlignment::Left;
+ LabelPosition labelPosition = LabelPosition::Above;
+ };
+
+ struct FloatSliderOptions {
+ const ImVec4 color = Colors::Gray;
+ const char* tooltip = "";
+ bool disabled = false;
+ const char* disabledTooltip = "";
+ bool showButtons = true;
+ ImGuiSliderFlags flags = 0;
+ const char* format = "%f";
+ const float step = 0.01f;
+ bool isPercentage = false; // Multiplies visual value by 100
+ ComponentAlignment alignment = ComponentAlignment::Left;
+ LabelPosition labelPosition = LabelPosition::Above;
+ };
+
+ void PushStyleSlider(const ImVec4& color = Colors::Indigo);
+ void PopStyleSlider();
+ bool SliderInt(const char* label, int32_t* value, int32_t min, int32_t max, const IntSliderOptions& options = {});
+ bool CVarSliderInt(const char* label, const char* cvarName, int32_t min, int32_t max, const int32_t defaultValue, const IntSliderOptions& options = {});
+ bool SliderFloat(const char* label, float* value, float min, float max, const FloatSliderOptions& options = {});
+ bool CVarSliderFloat(const char* label, const char* cvarName, float min, float max, const float defaultValue, const FloatSliderOptions& options = {});
+} \ No newline at end of file
diff --git a/src/sys/sys_fault.c b/src/sys/sys_fault.c
index 14a322e2..f73e1396 100644
--- a/src/sys/sys_fault.c
+++ b/src/sys/sys_fault.c
@@ -242,7 +242,7 @@ void Fault_ThreadEntry(void* arg0) {
func_8000762C(300, 10, "-");
gControllerPlugged[0] = 1;
while (var_s5 == 0) {
- osSendMesg(&gSerialThreadMsgQueue, (OSMesg) SI_READ_CONTROLLER, OS_MESG_PRI_NORMAL);
+ osSendMesg(&gSerialThreadMsgQueue, OS_MESG_32(SI_READ_CONTROLLER), OS_MESG_PRI_NORMAL);
osRecvMesg(&gControllerMsgQueue, NULL, OS_MESG_BLOCK);
Controller_UpdateInput();
switch (var_s0) {
diff --git a/src/sys/sys_joybus.c b/src/sys/sys_joybus.c
index fb6ad5ac..890961ce 100644
--- a/src/sys/sys_joybus.c
+++ b/src/sys/sys_joybus.c
@@ -63,7 +63,7 @@ void Controller_UpdateInput(void) {
s32 i;
for (i = 0; i < 4; i++) {
- if (gControllerPlugged[i] == 1 && sNextController[i].errno == 0) {
+ if (gControllerPlugged[i] == 1 && sNextController[i].err_no == 0) {
sPrevController[i] = gControllerHold[i];
gControllerHold[i] = sNextController[i];
gControllerPress[i].button =
@@ -71,8 +71,8 @@ void Controller_UpdateInput(void) {
Controller_AddDeadZone(i);
} else {
gControllerHold[i].button = gControllerHold[i].stick_x = gControllerHold[i].stick_y =
- gControllerHold[i].errno = gControllerPress[i].button = gControllerPress[i].stick_x =
- gControllerPress[i].stick_y = gControllerPress[i].errno = 0;
+ gControllerHold[i].err_no = gControllerPress[i].button = gControllerPress[i].stick_x =
+ gControllerPress[i].stick_y = gControllerPress[i].err_no = 0;
}
}
}
@@ -84,41 +84,41 @@ void Controller_ReadData(void) {
gControllerLock--;
for (i = 0; i < 4; i++) {
sNextController[i].button = sNextController[i].stick_x = sNextController[i].stick_y =
- sNextController[i].errno = 0;
+ sNextController[i].err_no = 0;
}
} else {
osContStartReadData(&gSerialEventQueue);
osRecvMesg(&gSerialEventQueue, NULL, OS_MESG_BLOCK);
osContGetReadData(sNextController);
}
- osSendMesg(&gControllerMsgQueue, (OSMesg) SI_CONT_READ_DONE, OS_MESG_PRI_NORMAL);
+ osSendMesg(&gControllerMsgQueue, OS_MESG_32(SI_CONT_READ_DONE), OS_MESG_PRI_NORMAL);
}
void Save_ReadData(void) {
if ((gStartNMI == 0) && (Save_ReadEeprom(&gSaveIOBuffer) == 0)) {
- osSendMesg(&gSaveMsgQueue, (OSMesg) SI_SAVE_SUCCESS, OS_MESG_PRI_NORMAL);
+ osSendMesg(&gSaveMsgQueue, OS_MESG_32(SI_SAVE_SUCCESS), OS_MESG_PRI_NORMAL);
return;
}
- osSendMesg(&gSaveMsgQueue, (OSMesg) SI_SAVE_FAILED, OS_MESG_PRI_NORMAL);
+ osSendMesg(&gSaveMsgQueue, OS_MESG_32(SI_SAVE_FAILED), OS_MESG_PRI_NORMAL);
}
void Save_WriteData(void) {
if ((gStartNMI == 0) && (Save_WriteEeprom(&gSaveIOBuffer) == 0)) {
- osSendMesg(&gSaveMsgQueue, (OSMesg) SI_SAVE_SUCCESS, OS_MESG_PRI_NORMAL);
+ osSendMesg(&gSaveMsgQueue, OS_MESG_32(SI_SAVE_SUCCESS), OS_MESG_PRI_NORMAL);
return;
}
- osSendMesg(&gSaveMsgQueue, (OSMesg) SI_SAVE_FAILED, OS_MESG_PRI_NORMAL);
+ osSendMesg(&gSaveMsgQueue, OS_MESG_32(SI_SAVE_FAILED), OS_MESG_PRI_NORMAL);
}
void Controller_Rumble(void) {
s32 i;
- osContStartQuery(&gSerialEventQueue);
+ // osContStartQuery(&gSerialEventQueue);
osRecvMesg(&gSerialEventQueue, NULL, OS_MESG_BLOCK);
- osContGetQuery(sControllerStatus);
+ // osContGetQuery(sControllerStatus);
for (i = 0; i < 4; i++) {
- if ((gControllerPlugged[i] != 0) && (sControllerStatus[i].errno == 0)) {
+ if ((gControllerPlugged[i] != 0) && (sControllerStatus[i].err_no == 0)) {
if (sControllerStatus[i].status & 1) {
if (gControllerRumble[i] == 0) {
if (osMotorInit(&gSerialEventQueue, &sControllerMotor[i], i)) {
diff --git a/src/sys/sys_lib.c b/src/sys/sys_lib.c
index ffb3cb91..1f528aa0 100644
--- a/src/sys/sys_lib.c
+++ b/src/sys/sys_lib.c
@@ -120,24 +120,25 @@ void Lib_DmaRead(void* src, void* dst, ptrdiff_t size) {
void Lib_FillScreen(u8 setFill) {
s32 i;
+ // TODO: Implement fill screen
gFillScreenColor |= 1;
if (setFill == true) {
if (gFillScreen == false) {
if (gFillScreenColor == 1) {
- osViBlack(1);
+ // osViBlack(1);
} else {
for (i = 0; i < 3 * SCREEN_WIDTH; i++) {
gFillBuffer[i] = gFillScreenColor;
}
- osWritebackDCacheAll();
- osViSwapBuffer(&gFillBuffer[SCREEN_WIDTH]);
- osViRepeatLine(1);
+ // osWritebackDCacheAll();
+ // osViSwapBuffer(&gFillBuffer[SCREEN_WIDTH]);
+ // osViRepeatLine(1);
}
gFillScreen = true;
}
} else if (gFillScreen == true) {
- osViRepeatLine(0);
- osViBlack(0);
+ // osViRepeatLine(0);
+ // osViBlack(0);
gFillScreen = false;
}
}
diff --git a/src/sys/sys_main.c b/src/sys/sys_main.c
index da8e19bd..4b0d0147 100644
--- a/src/sys/sys_main.c
+++ b/src/sys/sys_main.c
@@ -108,46 +108,46 @@ void Audio_ThreadEntry(void* arg0) {
task = AudioThread_CreateTask();
if (task != NULL) {
task->msgQueue = &gAudioTaskMsgQueue;
- task->msg = (OSMesg) TASK_MESG_1;
+ task->msg = OS_MESG_32(TASK_MESG_1);
osWritebackDCacheAll();
- osSendMesg(&gTaskMsgQueue, task, OS_MESG_PRI_NORMAL);
+ osSendMesg(&gTaskMsgQueue, OS_MESG_PTR(task), OS_MESG_PRI_NORMAL);
}
while (1) {
task = AudioThread_CreateTask();
if (task != NULL) {
task->msgQueue = &gAudioTaskMsgQueue;
- task->msg = (OSMesg) TASK_MESG_1;
+ task->msg = OS_MESG_32(TASK_MESG_1);
osWritebackDCacheAll();
}
osRecvMesg(&gAudioTaskMsgQueue, NULL, OS_MESG_NOBLOCK);
if (task != NULL) {
- osSendMesg(&gTaskMsgQueue, task, OS_MESG_PRI_NORMAL);
+ osSendMesg(&gTaskMsgQueue, OS_MESG_PTR(task), OS_MESG_PRI_NORMAL);
}
osRecvMesg(&gAudioVImsgQueue, NULL, OS_MESG_BLOCK);
}
}
void Graphics_SetTask(void) {
- gGfxTask->msgQueue = &gGfxTaskMsgQueue;
- gGfxTask->msg = (OSMesg) TASK_MESG_2;
- gGfxTask->task.t.type = M_GFXTASK;
- gGfxTask->task.t.flags = 0;
- gGfxTask->task.t.ucode_boot = rspbootTextStart;
- gGfxTask->task.t.ucode_boot_size = (uintptr_t) rspbootTextEnd - (uintptr_t) rspbootTextStart;
- gGfxTask->task.t.ucode = gspF3DEX_fifoTextStart;
- gGfxTask->task.t.ucode_size = SP_UCODE_SIZE;
- gGfxTask->task.t.ucode_data = (u64*) &gspF3DEX_fifoDataStart;
- gGfxTask->task.t.ucode_data_size = SP_UCODE_DATA_SIZE;
- gGfxTask->task.t.dram_stack = gDramStack;
- gGfxTask->task.t.dram_stack_size = SP_DRAM_STACK_SIZE8;
- gGfxTask->task.t.output_buff = (u64*) gTaskOutputBuffer;
- gGfxTask->task.t.output_buff_size = (u64*) gAudioHeap;
- gGfxTask->task.t.data_ptr = (u64*) gGfxPool->masterDL;
- gGfxTask->task.t.data_size = (gMasterDisp - gGfxPool->masterDL) * sizeof(Gfx);
- gGfxTask->task.t.yield_data_ptr = (u64*) &gOSYieldData;
- gGfxTask->task.t.yield_data_size = OS_YIELD_DATA_SIZE;
- osWritebackDCacheAll();
- osSendMesg(&gTaskMsgQueue, gGfxTask, OS_MESG_PRI_NORMAL);
+ // gGfxTask->msgQueue = &gGfxTaskMsgQueue;
+ // gGfxTask->msg = (OSMesg) TASK_MESG_2;
+ // gGfxTask->task.t.type = M_GFXTASK;
+ // gGfxTask->task.t.flags = 0;
+ // gGfxTask->task.t.ucode_boot = rspbootTextStart;
+ // gGfxTask->task.t.ucode_boot_size = (uintptr_t) rspbootTextEnd - (uintptr_t) rspbootTextStart;
+ // gGfxTask->task.t.ucode = gspF3DEX_fifoTextStart;
+ // gGfxTask->task.t.ucode_size = SP_UCODE_SIZE;
+ // gGfxTask->task.t.ucode_data = (u64*) &gspF3DEX_fifoDataStart;
+ // gGfxTask->task.t.ucode_data_size = SP_UCODE_DATA_SIZE;
+ // gGfxTask->task.t.dram_stack = gDramStack;
+ // gGfxTask->task.t.dram_stack_size = SP_DRAM_STACK_SIZE8;
+ // gGfxTask->task.t.output_buff = (u64*) gTaskOutputBuffer;
+ // gGfxTask->task.t.output_buff_size = (u64*) gAudioHeap;
+ // gGfxTask->task.t.data_ptr = (u64*) gGfxPool->masterDL;
+ // gGfxTask->task.t.data_size = (gMasterDisp - gGfxPool->masterDL) * sizeof(Gfx);
+ // gGfxTask->task.t.yield_data_ptr = (u64*) &gOSYieldData;
+ // gGfxTask->task.t.yield_data_size = OS_YIELD_DATA_SIZE;
+ // osWritebackDCacheAll();
+ // osSendMesg(&gTaskMsgQueue, gGfxTask, OS_MESG_PRI_NORMAL);
}
void Graphics_InitializeTask(u32 frameCount) {
@@ -176,23 +176,23 @@ void Main_SetVIMode(void) {
(gControllerHold[3].button & R_TRIG) && (gControllerHold[3].button & Z_TRIG)) {
sGammaMode = 1 - sGammaMode;
}
- switch (osTvType) {
- case OS_TV_PAL:
- osViSetMode(&osViModePalLan1);
- break;
- case OS_TV_MPAL:
- osViSetMode(&osViModeMpalLan1);
- break;
- default:
- case OS_TV_NTSC:
- osViSetMode(&osViModeNtscLan1);
- break;
- }
- if (sGammaMode != 0) {
- osViSetSpecialFeatures(OS_VI_DITHER_FILTER_ON | OS_VI_DIVOT_OFF | OS_VI_GAMMA_ON | OS_VI_GAMMA_DITHER_ON);
- } else {
- osViSetSpecialFeatures(OS_VI_DITHER_FILTER_ON | OS_VI_DIVOT_OFF | OS_VI_GAMMA_OFF | OS_VI_GAMMA_DITHER_OFF);
- }
+ // switch (osTvType) {
+ // case OS_TV_PAL:
+ // osViSetMode(&osViModePalLan1);
+ // break;
+ // case OS_TV_MPAL:
+ // osViSetMode(&osViModeMpalLan1);
+ // break;
+ // default:
+ // case OS_TV_NTSC:
+ // osViSetMode(&osViModeNtscLan1);
+ // break;
+ // }
+ // if (sGammaMode != 0) {
+ // osViSetSpecialFeatures(OS_VI_DITHER_FILTER_ON | OS_VI_DIVOT_OFF | OS_VI_GAMMA_ON | OS_VI_GAMMA_DITHER_ON);
+ // } else {
+ // osViSetSpecialFeatures(OS_VI_DITHER_FILTER_ON | OS_VI_DIVOT_OFF | OS_VI_GAMMA_OFF | OS_VI_GAMMA_DITHER_OFF);
+ // }
}
void SerialInterface_ThreadEntry(void* arg0) {
@@ -202,7 +202,7 @@ void SerialInterface_ThreadEntry(void* arg0) {
while (1) {
osRecvMesg(&gSerialThreadMsgQueue, &sp34, OS_MESG_BLOCK);
- switch ((s32) sp34) {
+ switch (sp34.data32) {
case SI_READ_CONTROLLER:
Controller_ReadData();
break;
@@ -220,11 +220,11 @@ void SerialInterface_ThreadEntry(void* arg0) {
}
void Timer_ThreadEntry(void* arg0) {
- void* sp24;
+ OSMesg sp24;
while (1) {
osRecvMesg(&gTimerTaskMsgQueue, &sp24, OS_MESG_BLOCK);
- Timer_CompleteTask(sp24);
+ Timer_CompleteTask(sp24.ptr);
}
}
@@ -234,7 +234,7 @@ void Graphics_ThreadEntry(void* arg0) {
u8 var_v2;
Game_Initialize();
- osSendMesg(&gSerialThreadMsgQueue, (OSMesg) SI_READ_CONTROLLER, OS_MESG_PRI_NORMAL);
+ osSendMesg(&gSerialThreadMsgQueue, OS_MESG_32(SI_READ_CONTROLLER), OS_MESG_PRI_NORMAL);
Graphics_InitializeTask(gSysFrameCount);
{
gSPSegment(gUnkDisp1++, 0, 0);
@@ -251,9 +251,9 @@ void Graphics_ThreadEntry(void* arg0) {
gSysFrameCount++;
Graphics_InitializeTask(gSysFrameCount);
osRecvMesg(&gControllerMsgQueue, NULL, OS_MESG_BLOCK);
- osSendMesg(&gSerialThreadMsgQueue, (OSMesg) SI_RUMBLE, OS_MESG_PRI_NORMAL);
+ osSendMesg(&gSerialThreadMsgQueue, OS_MESG_32(SI_RUMBLE), OS_MESG_PRI_NORMAL);
Controller_UpdateInput();
- osSendMesg(&gSerialThreadMsgQueue, (OSMesg) SI_READ_CONTROLLER, OS_MESG_PRI_NORMAL);
+ osSendMesg(&gSerialThreadMsgQueue, OS_MESG_32(SI_READ_CONTROLLER), OS_MESG_PRI_NORMAL);
if (gControllerPress[3].button & U_JPAD) {
Main_SetVIMode();
}
@@ -275,7 +275,7 @@ void Graphics_ThreadEntry(void* arg0) {
if (gFillScreen == 0) {
osViSwapBuffer(&gFrameBuffers[(gSysFrameCount - 1) % 3]);
}
- func_80007FE4(&gFrameBuffers[(gSysFrameCount - 1) % 3], SCREEN_WIDTH, 16);
+ // func_80007FE4(&gFrameBuffers[(gSysFrameCount - 1) % 3], SCREEN_WIDTH, 16);
var_v1 = MIN(D_80137E78, 4);
var_v2 = MAX(var_v1, gGfxVImsgQueue.validCount + 1);
@@ -295,12 +295,12 @@ void Main_InitMesgQueues(void) {
osCreateMesgQueue(&gGfxVImsgQueue, sGfxVImsgBuff, ARRAY_COUNT(sGfxVImsgBuff));
osCreateMesgQueue(&gGfxTaskMsgQueue, sGfxTaskMsgBuff, ARRAY_COUNT(sGfxTaskMsgBuff));
osCreateMesgQueue(&gSerialEventQueue, sSerialEventBuff, ARRAY_COUNT(sSerialEventBuff));
- osSetEventMesg(OS_EVENT_SI, &gSerialEventQueue, NULL);
+ osSetEventMesg(OS_EVENT_SI, &gSerialEventQueue, OS_MESG_PTR(NULL));
osCreateMesgQueue(&gMainThreadMsgQueue, sMainThreadMsgBuff, ARRAY_COUNT(sMainThreadMsgBuff));
- osViSetEvent(&gMainThreadMsgQueue, (OSMesg) EVENT_MESG_VI, 1);
- osSetEventMesg(OS_EVENT_SP, &gMainThreadMsgQueue, (OSMesg) EVENT_MESG_SP);
- osSetEventMesg(OS_EVENT_DP, &gMainThreadMsgQueue, (OSMesg) EVENT_MESG_DP);
- osSetEventMesg(OS_EVENT_PRENMI, &gMainThreadMsgQueue, (OSMesg) EVENT_MESG_PRENMI);
+ osViSetEvent(&gMainThreadMsgQueue, OS_MESG_32(EVENT_MESG_VI), 1);
+ osSetEventMesg(OS_EVENT_SP, &gMainThreadMsgQueue, OS_MESG_32(EVENT_MESG_SP));
+ osSetEventMesg(OS_EVENT_DP, &gMainThreadMsgQueue, OS_MESG_32(EVENT_MESG_DP));
+ osSetEventMesg(OS_EVENT_PRENMI, &gMainThreadMsgQueue, OS_MESG_32(EVENT_MESG_PRENMI));
osCreateMesgQueue(&gTimerTaskMsgQueue, sTimerTaskMsgBuff, ARRAY_COUNT(sTimerTaskMsgBuff));
osCreateMesgQueue(&gTimerWaitMsgQueue, sTimerWaitMsgBuff, ARRAY_COUNT(sTimerWaitMsgBuff));
osCreateMesgQueue(&gSerialThreadMsgQueue, sSerialThreadMsgBuff, ARRAY_COUNT(sSerialThreadMsgBuff));
@@ -323,22 +323,22 @@ void Main_HandleRDP(void) {
}
void Main_HandleRSP(void) {
- SPTask* task = gCurrentTask;
-
- gCurrentTask = NULL;
- if (task->state == SPTASK_STATE_INTERRUPTED) {
- if (osSpTaskYielded(&task->task) == 0) {
- task->state = SPTASK_STATE_FINISHED;
- }
- } else {
- task->state = SPTASK_STATE_FINISHED;
- if (task->task.t.type == M_AUDTASK) {
- if (task->msgQueue != NULL) {
- osSendMesg(task->msgQueue, task->msg, OS_MESG_PRI_NORMAL);
- }
- sAudioTasks[0] = NULL;
- }
- }
+ // SPTask* task = gCurrentTask;
+ //
+ // gCurrentTask = NULL;
+ // if (task->state == SPTASK_STATE_INTERRUPTED) {
+ // if (osSpTaskYielded(&task->task) == 0) {
+ // task->state = SPTASK_STATE_FINISHED;
+ // }
+ // } else {
+ // task->state = SPTASK_STATE_FINISHED;
+ // if (task->task.t.type == M_AUDTASK) {
+ // if (task->msgQueue != NULL) {
+ // osSendMesg(task->msgQueue, task->msg, OS_MESG_PRI_NORMAL);
+ // }
+ // sAudioTasks[0] = NULL;
+ // }
+ // }
}
void Main_GetNewTasks(void) {
@@ -362,7 +362,7 @@ void Main_GetNewTasks(void) {
var_s0_2 = sNewAudioTasks;
var_s1_2 = sNewGfxTasks;
while (osRecvMesg(&gTaskMsgQueue, &sp40, OS_MESG_NOBLOCK) != MSG_QUEUE_EMPTY) {
- sp3C = (SPTask*) sp40;
+ sp3C = (SPTask*) sp40.ptr;
sp3C->state = SPTASK_STATE_NOT_STARTED;
switch (sp3C->task.t.type) {
@@ -403,50 +403,50 @@ void Main_StartNextTask(void) {
if (gCurrentTask != NULL) {
if (gCurrentTask->task.t.type == M_GFXTASK) {
gCurrentTask->state = SPTASK_STATE_INTERRUPTED;
- osSpTaskYield();
+ // osSpTaskYield();
}
} else {
gCurrentTask = sAudioTasks[0];
- osSpTaskLoad(&gCurrentTask->task);
- osSpTaskStartGo(&gCurrentTask->task);
+ // osSpTaskLoad(&gCurrentTask->task);
+ // osSpTaskStartGo(&gCurrentTask->task);
gCurrentTask->state = SPTASK_STATE_RUNNING;
}
} else if ((gCurrentTask == NULL) && (sGfxTasks[0] != NULL) && (sGfxTasks[0]->state != SPTASK_STATE_FINISHED)) {
gCurrentTask = sGfxTasks[0];
- osDpSetStatus(DPC_CLR_TMEM_CTR | DPC_CLR_PIPE_CTR | DPC_CLR_CMD_CTR | DPC_CLR_CLOCK_CTR);
- osSpTaskLoad(&gCurrentTask->task);
- osSpTaskStartGo(&gCurrentTask->task);
+ // osDpSetStatus(DPC_CLR_TMEM_CTR | DPC_CLR_PIPE_CTR | DPC_CLR_CMD_CTR | DPC_CLR_CLOCK_CTR);
+ // osSpTaskLoad(&gCurrentTask->task);
+ // osSpTaskStartGo(&gCurrentTask->task);
gCurrentTask->state = SPTASK_STATE_RUNNING;
}
}
void Main_ThreadEntry(void* arg0) {
OSMesg ogMsg;
- u8 mesg;
-
- osCreateThread(&gAudioThread, THREAD_ID_AUDIO, Audio_ThreadEntry, arg0,
- gAudioThreadStack + sizeof(gAudioThreadStack), 80);
- osStartThread(&gAudioThread);
- osCreateThread(&gGraphicsThread, THREAD_ID_GRAPHICS, Graphics_ThreadEntry, arg0,
- gGraphicsThreadStack + sizeof(gGraphicsThreadStack), 40);
- osStartThread(&gGraphicsThread);
- osCreateThread(&gTimerThread, THREAD_ID_TIMER, Timer_ThreadEntry, arg0,
- gTimerThreadStack + sizeof(gTimerThreadStack), 60);
- osStartThread(&gTimerThread);
- osCreateThread(&gSerialThread, THREAD_ID_SERIAL, SerialInterface_ThreadEntry, arg0,
- gSerialThreadStack + sizeof(gSerialThreadStack), 20);
- osStartThread(&gSerialThread);
+ u32 mesg;
+
+ // osCreateThread(&gAudioThread, THREAD_ID_AUDIO, Audio_ThreadEntry, arg0,
+ // gAudioThreadStack + sizeof(gAudioThreadStack), 80);
+ // osStartThread(&gAudioThread);
+ // osCreateThread(&gGraphicsThread, THREAD_ID_GRAPHICS, Graphics_ThreadEntry, arg0,
+ // gGraphicsThreadStack + sizeof(gGraphicsThreadStack), 40);
+ // osStartThread(&gGraphicsThread);
+ // osCreateThread(&gTimerThread, THREAD_ID_TIMER, Timer_ThreadEntry, arg0,
+ // gTimerThreadStack + sizeof(gTimerThreadStack), 60);
+ // osStartThread(&gTimerThread);
+ // osCreateThread(&gSerialThread, THREAD_ID_SERIAL, SerialInterface_ThreadEntry, arg0,
+ // gSerialThreadStack + sizeof(gSerialThreadStack), 20);
+ // osStartThread(&gSerialThread);
Main_InitMesgQueues();
while (true) {
osRecvMesg(&gMainThreadMsgQueue, &ogMsg, OS_MESG_BLOCK);
- mesg = (u32) ogMsg;
+ mesg = ogMsg.data32;
switch (mesg) {
case EVENT_MESG_VI:
- osSendMesg(&gAudioVImsgQueue, (OSMesg) EVENT_MESG_VI, OS_MESG_PRI_NORMAL);
- osSendMesg(&gGfxVImsgQueue, (OSMesg) EVENT_MESG_VI, OS_MESG_PRI_NORMAL);
+ osSendMesg(&gAudioVImsgQueue, OS_MESG_32(EVENT_MESG_VI), OS_MESG_PRI_NORMAL);
+ osSendMesg(&gGfxVImsgQueue, OS_MESG_32(EVENT_MESG_VI), OS_MESG_PRI_NORMAL);
Main_GetNewTasks();
break;
case EVENT_MESG_SP:
@@ -466,24 +466,25 @@ void Main_ThreadEntry(void* arg0) {
}
void Idle_ThreadEntry(void* arg0) {
- osCreateViManager(OS_PRIORITY_VIMGR);
- Main_SetVIMode();
- Lib_FillScreen(1);
- osCreatePiManager(OS_PRIORITY_PIMGR, &gPiMgrCmdQueue, sPiMgrCmdBuff, ARRAY_COUNT(sPiMgrCmdBuff));
- osCreateThread(&gMainThread, THREAD_ID_MAIN, &Main_ThreadEntry, arg0, sMainThreadStack + sizeof(sMainThreadStack),
- 100);
- osStartThread(&gMainThread);
- Fault_Init();
- osSetThreadPri(NULL, OS_PRIORITY_IDLE);
-loop_1:
- goto loop_1;
+ // TODO: Implement idle thread
+ // osCreateViManager(OS_PRIORITY_VIMGR);
+ // Main_SetVIMode();
+ // Lib_FillScreen(1);
+ // osCreatePiManager(OS_PRIORITY_PIMGR, &gPiMgrCmdQueue, sPiMgrCmdBuff, ARRAY_COUNT(sPiMgrCmdBuff));
+ // osCreateThread(&gMainThread, THREAD_ID_MAIN, &Main_ThreadEntry, arg0, sMainThreadStack + sizeof(sMainThreadStack),
+ // 100);
+ // osStartThread(&gMainThread);
+ // Fault_Init();
+ // osSetThreadPri(NULL, OS_PRIORITY_IDLE);
+// loop_1:
+// goto loop_1;
}
void bootproc(void) {
- RdRam_CheckIPL3();
- osInitialize();
+ // RdRam_CheckIPL3();
+ // osInitialize();
Main_Initialize();
- osCreateThread(&sIdleThread, THREAD_ID_IDLE, &Idle_ThreadEntry, NULL, sIdleThreadStack + sizeof(sIdleThreadStack),
- 255);
- osStartThread(&sIdleThread);
+ // osCreateThread(&sIdleThread, THREAD_ID_IDLE, &Idle_ThreadEntry, NULL, sIdleThreadStack + sizeof(sIdleThreadStack),
+ // 255);
+ // osStartThread(&sIdleThread);
}
diff --git a/src/sys/sys_matrix.c b/src/sys/sys_matrix.c
index f50cfb64..2722bfb5 100644
--- a/src/sys/sys_matrix.c
+++ b/src/sys/sys_matrix.c
@@ -1,19 +1,19 @@
#include "sys.h"
-Mtx gIdentityMtx = { {
- {
+Mtx gIdentityMtx = {
+ .intPart = {
{ 1, 0, 0, 0 },
{ 0, 1, 0, 0 },
{ 0, 0, 1, 0 },
{ 0, 0, 0, 1 },
},
- {
+ .fracPart = {
{ 0, 0, 0, 0 },
{ 0, 0, 0, 0 },
{ 0, 0, 0, 0 },
{ 0, 0, 0, 0 },
},
-} };
+};
Matrix gIdentityMatrix = { {
{ 1.0f, 0.0f, 0.0f, 0.0f },
@@ -332,8 +332,8 @@ void Matrix_RotateAxis(Matrix* mtx, f32 angle, f32 axisX, f32 axisY, f32 axisZ,
// Converts the current Gfx matrix to a Mtx
void Matrix_ToMtx(Mtx* dest) {
s32 intVal;
- u16(*iPart)[4] = dest->u.i;
- u16(*fPart)[4] = dest->u.f;
+ u16(*iPart)[4] = dest->intPart;
+ u16(*fPart)[4] = dest->fracPart;
Matrix* src = gGfxMatrix;
intVal = src->m[0][0] * 0x10000;
@@ -403,22 +403,22 @@ void Matrix_ToMtx(Mtx* dest) {
// Converts the Mtx src to a Matrix, putting the result in dest
void Matrix_FromMtx(Mtx* src, Matrix* dest) {
- dest->m[0][0] = ((src->u.i[0][0] << 0x10) | src->u.f[0][0]) * (1.0f / 0x10000);
- dest->m[0][1] = ((src->u.i[0][1] << 0x10) | src->u.f[0][1]) * (1.0f / 0x10000);
- dest->m[0][2] = ((src->u.i[0][2] << 0x10) | src->u.f[0][2]) * (1.0f / 0x10000);
- dest->m[0][3] = ((src->u.i[0][3] << 0x10) | src->u.f[0][3]) * (1.0f / 0x10000);
- dest->m[1][0] = ((src->u.i[1][0] << 0x10) | src->u.f[1][0]) * (1.0f / 0x10000);
- dest->m[1][1] = ((src->u.i[1][1] << 0x10) | src->u.f[1][1]) * (1.0f / 0x10000);
- dest->m[1][2] = ((src->u.i[1][2] << 0x10) | src->u.f[1][2]) * (1.0f / 0x10000);
- dest->m[1][3] = ((src->u.i[1][3] << 0x10) | src->u.f[1][3]) * (1.0f / 0x10000);
- dest->m[2][0] = ((src->u.i[2][0] << 0x10) | src->u.f[2][0]) * (1.0f / 0x10000);
- dest->m[2][1] = ((src->u.i[2][1] << 0x10) | src->u.f[2][1]) * (1.0f / 0x10000);
- dest->m[2][2] = ((src->u.i[2][2] << 0x10) | src->u.f[2][2]) * (1.0f / 0x10000);
- dest->m[2][3] = ((src->u.i[2][3] << 0x10) | src->u.f[2][3]) * (1.0f / 0x10000);
- dest->m[3][0] = ((src->u.i[3][0] << 0x10) | src->u.f[3][0]) * (1.0f / 0x10000);
- dest->m[3][1] = ((src->u.i[3][1] << 0x10) | src->u.f[3][1]) * (1.0f / 0x10000);
- dest->m[3][2] = ((src->u.i[3][2] << 0x10) | src->u.f[3][2]) * (1.0f / 0x10000);
- dest->m[3][3] = ((src->u.i[3][3] << 0x10) | src->u.f[3][3]) * (1.0f / 0x10000);
+ dest->m[0][0] = ((src->intPart[0][0] << 0x10) | src->fracPart[0][0]) * (1.0f / 0x10000);
+ dest->m[0][1] = ((src->intPart[0][1] << 0x10) | src->fracPart[0][1]) * (1.0f / 0x10000);
+ dest->m[0][2] = ((src->intPart[0][2] << 0x10) | src->fracPart[0][2]) * (1.0f / 0x10000);
+ dest->m[0][3] = ((src->intPart[0][3] << 0x10) | src->fracPart[0][3]) * (1.0f / 0x10000);
+ dest->m[1][0] = ((src->intPart[1][0] << 0x10) | src->fracPart[1][0]) * (1.0f / 0x10000);
+ dest->m[1][1] = ((src->intPart[1][1] << 0x10) | src->fracPart[1][1]) * (1.0f / 0x10000);
+ dest->m[1][2] = ((src->intPart[1][2] << 0x10) | src->fracPart[1][2]) * (1.0f / 0x10000);
+ dest->m[1][3] = ((src->intPart[1][3] << 0x10) | src->fracPart[1][3]) * (1.0f / 0x10000);
+ dest->m[2][0] = ((src->intPart[2][0] << 0x10) | src->fracPart[2][0]) * (1.0f / 0x10000);
+ dest->m[2][1] = ((src->intPart[2][1] << 0x10) | src->fracPart[2][1]) * (1.0f / 0x10000);
+ dest->m[2][2] = ((src->intPart[2][2] << 0x10) | src->fracPart[2][2]) * (1.0f / 0x10000);
+ dest->m[2][3] = ((src->intPart[2][3] << 0x10) | src->fracPart[2][3]) * (1.0f / 0x10000);
+ dest->m[3][0] = ((src->intPart[3][0] << 0x10) | src->fracPart[3][0]) * (1.0f / 0x10000);
+ dest->m[3][1] = ((src->intPart[3][1] << 0x10) | src->fracPart[3][1]) * (1.0f / 0x10000);
+ dest->m[3][2] = ((src->intPart[3][2] << 0x10) | src->fracPart[3][2]) * (1.0f / 0x10000);
+ dest->m[3][3] = ((src->intPart[3][3] << 0x10) | src->fracPart[3][3]) * (1.0f / 0x10000);
}
// Applies the transform matrix mtx to the vector src, putting the result in dest
diff --git a/src/sys/sys_timer.c b/src/sys/sys_timer.c
index 6e33932e..7b11b71d 100644
--- a/src/sys/sys_timer.c
+++ b/src/sys/sys_timer.c
@@ -23,7 +23,7 @@ s32 Timer_CreateTask(u64 time, TimerAction action, s32* address, s32 value) {
task->action = action;
task->address = address;
task->value = value;
- return osSetTimer(&task->timer, time, 0, &gTimerTaskMsgQueue, task);
+ return osSetTimer(&task->timer, time, 0, &gTimerTaskMsgQueue, OS_MESG_PTR(task));
}
void Timer_Increment(s32* address, s32 value) {
@@ -45,6 +45,6 @@ void Timer_Wait(u64 time) {
OSTimer timer;
OSMesg dummy;
- osSetTimer(&timer, time, 0, &gTimerWaitMsgQueue, NULL);
+ osSetTimer(&timer, time, 0, &gTimerWaitMsgQueue, OS_MESG_PTR(NULL));
osRecvMesg(&gTimerWaitMsgQueue, &dummy, OS_MESG_BLOCK);
}