Suggestion from "mgh".
[open-ps2-loader.git] / src / gui.c
blob2b5ebd689beba8bbb27299ab3d2eb5dc48826641
1 /*
2 Copyright 2010, Volca
3 Licenced under Academic Free License version 3.0
4 Review OpenUsbLd README & LICENSE files for further details.
5 */
7 #include "include/usbld.h"
8 #include "include/gui.h"
9 #include "include/renderman.h"
10 #include "include/menusys.h"
11 #include "include/fntsys.h"
12 #include "include/ioman.h"
13 #include "include/lang.h"
14 #include "include/themes.h"
15 #include "include/pad.h"
16 #include "include/util.h"
17 #include "include/config.h"
18 #include "include/system.h"
19 #include "include/ethsupport.h"
21 #include <stdlib.h>
22 #include <libvux.h>
24 static int gScheduledOps;
25 static int gCompletedOps;
26 static int gTerminate;
27 static int gInitComplete;
29 static gui_callback_t gFrameHook;
31 static s32 gSemaId;
32 static s32 gGUILockSemaId;
33 static ee_sema_t gQueueSema;
35 static int screenWidth;
36 static float wideScreenScale;
37 static int screenHeight;
39 // forward decl.
40 static void guiShow();
42 #ifdef __DEBUG
44 #include <timer.h>
46 #define CLOCKS_PER_MILISEC 147456
48 // debug version displays an FPS meter
49 static u32 curtime = 0;
50 static u32 time_since_last = 0;
51 static u32 time_render = 0;
53 #endif
55 struct gui_update_list_t {
56 struct gui_update_t* item;
57 struct gui_update_list_t* next;
60 struct gui_update_list_t *gUpdateList;
61 struct gui_update_list_t *gUpdateEnd;
63 typedef struct {
64 void (*handleInput)(void);
65 void (*renderScreen)(void);
66 short inMenu;
67 } gui_screen_handler_t;
69 static gui_screen_handler_t screenHandlers[] = {{ &menuHandleInputMain, &menuRenderMain, 0 },
70 { &menuHandleInputMenu, &menuRenderMenu, 1 },
71 { &menuHandleInputInfo, &menuRenderInfo, 1 } };
73 // default screen handler (menu screen)
74 static gui_screen_handler_t *screenHandler = &screenHandlers[GUI_SCREEN_MENU];
76 // screen transition handling
77 static gui_screen_handler_t *screenHandlerTarget = NULL;
78 static int transIndex, transMax, transitionX, transitionY;
80 // Helper perlin noise data
81 #define PLASMA_H 32
82 #define PLASMA_W 32
83 #define PLASMA_ROWS_PER_FRAME 6
84 #define FADE_SIZE 256
86 static GSTEXTURE gBackgroundTex;
87 static int pperm[512];
88 static float fadetbl[FADE_SIZE + 1];
90 static VU_VECTOR pgrad3[12] = {{ 1, 1, 0, 1 }, { -1, 1, 0, 1 }, { 1, -1, 0, 1 }, { -1, -1, 0, 1 },
91 { 1, 0, 1, 1 }, { -1, 0, 1, 1 }, { 1, 0, -1, 1 }, { -1, 0, -1, 1 },
92 { 0, 1, 1, 1 }, { 0, -1, 1, 1 }, { 0, 1, -1, 1 }, { 0, -1, -1, 1 } };
94 void guiReloadScreenExtents() {
95 rmGetScreenExtents(&screenWidth, &screenHeight);
98 void guiInit(void) {
99 guiFrameId = 0;
100 guiInactiveFrames = 0;
102 gFrameHook = NULL;
103 gTerminate = 0;
104 gInitComplete = 0;
105 gScheduledOps = 0;
106 gCompletedOps = 0;
108 gUpdateList = NULL;
109 gUpdateEnd = NULL;
111 gQueueSema.init_count = 1;
112 gQueueSema.max_count = 1;
113 gQueueSema.option = 0;
115 gSemaId = CreateSema(&gQueueSema);
116 gGUILockSemaId = CreateSema(&gQueueSema);
118 guiReloadScreenExtents();
120 // background texture - for perlin
121 gBackgroundTex.Width = PLASMA_W;
122 gBackgroundTex.Height = PLASMA_H;
123 gBackgroundTex.Mem = memalign(128, PLASMA_W * PLASMA_H * 4);
124 gBackgroundTex.PSM = GS_PSM_CT32;
125 gBackgroundTex.Filter = GS_FILTER_LINEAR;
126 gBackgroundTex.Vram = 0;
127 gBackgroundTex.VramClut = 0;
128 gBackgroundTex.Clut = NULL;
130 wideScreenScale = 1.0f;
132 // Precalculate the values for the perlin noise plasma
133 int i;
134 for (i = 0; i < 256; ++i) {
135 pperm[i] = rand() % 256;
136 pperm[i + 256] = pperm[i];
139 for (i = 0; i <= FADE_SIZE; ++i) {
140 float t = (float) (i) / FADE_SIZE;
142 fadetbl[i] = t * t * t * (t * (t * 6.0 - 15.0) + 10.0);
146 void guiEnd() {
147 if (gBackgroundTex.Mem)
148 free(gBackgroundTex.Mem);
150 DeleteSema(gSemaId);
151 DeleteSema(gGUILockSemaId);
154 void guiLock(void) {
155 WaitSema(gGUILockSemaId);
158 void guiUnlock(void) {
159 SignalSema(gGUILockSemaId);
162 void guiStartFrame(void) {
163 #ifdef __DEBUG
164 u32 newtime = cpu_ticks() / CLOCKS_PER_MILISEC;
165 time_since_last = newtime - curtime;
166 curtime = newtime;
167 #endif
169 guiLock();
170 rmStartFrame();
171 guiFrameId++;
174 void guiEndFrame(void) {
175 guiUnlock();
176 rmFlush();
178 #ifdef __DEBUG
179 u32 newtime = cpu_ticks() / CLOCKS_PER_MILISEC;
180 time_render = newtime - curtime;
181 #endif
183 rmEndFrame();
186 void guiShowAbout() {
187 char OPLVersion[64];
188 snprintf(OPLVersion, 64, _l(_STR_OUL_VER), USBLD_VERSION);
190 #ifdef VMC
191 strcat(OPLVersion, " VMC");
192 #endif
193 #ifdef __RTL
194 strcat(OPLVersion, " RTL");
195 #endif
196 #ifdef __CHILDPROOF
197 strcat(OPLVersion, " CHILDPROOF");
198 #endif
200 diaSetLabel(diaAbout, 1, OPLVersion);
202 diaExecuteDialog(diaAbout, -1, 1, NULL);
205 void guiShowConfig() {
206 // configure the enumerations
207 const char* deviceNames[] = { _l(_STR_USB_GAMES), _l(_STR_NET_GAMES), _l(_STR_HDD_GAMES), NULL };
208 const char* deviceModes[] = { _l(_STR_OFF), _l(_STR_MANUAL), _l(_STR_AUTO), NULL };
210 diaSetEnum(diaConfig, CFG_DEFDEVICE, deviceNames);
211 diaSetEnum(diaConfig, CFG_USBMODE, deviceModes);
212 diaSetEnum(diaConfig, CFG_HDDMODE, deviceModes);
213 diaSetEnum(diaConfig, CFG_ETHMODE, deviceModes);
214 diaSetEnum(diaConfig, CFG_APPMODE, deviceModes);
216 diaSetInt(diaConfig, CFG_DEBUG, gDisableDebug);
217 diaSetString(diaConfig, CFG_EXITTO, gExitPath);
218 diaSetInt(diaConfig, CFG_DANDROP, gEnableDandR);
219 diaSetInt(diaConfig, CFG_HDDSPINDOWN, gHDDSpindown);
220 diaSetInt(diaConfig, CFG_CHECKUSBFRAG, gCheckUSBFragmentation);
221 diaSetInt(diaConfig, CFG_USBDELAY, gUSBDelay);
222 diaSetString(diaConfig, CFG_USBPREFIX, gUSBPrefix);
223 diaSetString(diaConfig, CFG_ETHPREFIX, gETHPrefix);
224 diaSetInt(diaConfig, CFG_LASTPLAYED, gRememberLastPlayed);
225 diaSetInt(diaConfig, CFG_DEFDEVICE, gDefaultDevice);
226 diaSetInt(diaConfig, CFG_USBMODE, gUSBStartMode);
227 diaSetInt(diaConfig, CFG_HDDMODE, gHDDStartMode);
228 diaSetInt(diaConfig, CFG_ETHMODE, gETHStartMode);
229 diaSetInt(diaConfig, CFG_APPMODE, gAPPStartMode);
231 int ret = diaExecuteDialog(diaConfig, -1, 1, NULL);
232 if (ret) {
233 diaGetString(diaConfig, CFG_EXITTO, gExitPath);
234 diaGetInt(diaConfig, CFG_DEBUG, &gDisableDebug);
235 diaGetInt(diaConfig, CFG_DANDROP, &gEnableDandR);
236 diaGetInt(diaConfig, CFG_HDDSPINDOWN, &gHDDSpindown);
237 diaGetInt(diaConfig, CFG_CHECKUSBFRAG, &gCheckUSBFragmentation);
238 diaGetInt(diaConfig, CFG_USBDELAY, &gUSBDelay);
239 diaGetString(diaConfig, CFG_USBPREFIX, gUSBPrefix);
240 diaGetString(diaConfig, CFG_ETHPREFIX, gETHPrefix);
241 diaGetInt(diaConfig, CFG_LASTPLAYED, &gRememberLastPlayed);
242 diaGetInt(diaConfig, CFG_DEFDEVICE, &gDefaultDevice);
243 diaGetInt(diaConfig, CFG_USBMODE, &gUSBStartMode);
244 diaGetInt(diaConfig, CFG_HDDMODE, &gHDDStartMode);
245 diaGetInt(diaConfig, CFG_ETHMODE, &gETHStartMode);
246 diaGetInt(diaConfig, CFG_APPMODE, &gAPPStartMode);
248 applyConfig(-1, -1);
252 static int curTheme = -1;
254 static int guiUIUpdater(int modified) {
255 if (modified) {
256 int temp;
257 diaGetInt(diaUIConfig, UICFG_THEME, &temp);
258 if (temp != curTheme) {
259 curTheme = temp;
260 if (temp == 0) {
261 diaUIConfig[32].type = UI_COLOUR; // Must be correctly set before doing the diaS/GetColor !!
262 diaUIConfig[36].type = UI_COLOUR;
263 diaUIConfig[40].type = UI_COLOUR;
264 diaUIConfig[44].type = UI_COLOUR;
265 diaSetColor(diaUIConfig, UICFG_BGCOL, gDefaultBgColor);
266 diaSetColor(diaUIConfig, UICFG_UICOL, gDefaultUITextColor);
267 diaSetColor(diaUIConfig, UICFG_TXTCOL, gDefaultTextColor);
268 diaSetColor(diaUIConfig, UICFG_SELCOL, gDefaultSelTextColor);
269 } else if (temp == thmGetGuiValue()) {
270 diaUIConfig[32].type = UI_COLOUR;
271 diaUIConfig[36].type = UI_COLOUR;
272 diaUIConfig[40].type = UI_COLOUR;
273 diaUIConfig[44].type = UI_COLOUR;
274 diaSetColor(diaUIConfig, UICFG_BGCOL, gTheme->bgColor);
275 diaSetU64Color(diaUIConfig, UICFG_UICOL, gTheme->uiTextColor);
276 diaSetU64Color(diaUIConfig, UICFG_TXTCOL, gTheme->textColor);
277 diaSetU64Color(diaUIConfig, UICFG_SELCOL, gTheme->selTextColor);
278 } else {
279 diaUIConfig[32].type = UI_SPACER;
280 diaUIConfig[36].type = UI_SPACER;
281 diaUIConfig[40].type = UI_SPACER;
282 diaUIConfig[44].type = UI_SPACER;
285 temp = !temp;
286 diaSetEnabled(diaUIConfig, UICFG_BGCOL, temp);
287 diaSetEnabled(diaUIConfig, UICFG_UICOL, temp);
288 diaSetEnabled(diaUIConfig, UICFG_TXTCOL, temp);
289 diaSetEnabled(diaUIConfig, UICFG_SELCOL, temp);
293 return 0;
296 void guiShowUIConfig() {
297 curTheme = -1;
299 // configure the enumerations
300 const char* scrollSpeeds[] = { _l(_STR_SLOW), _l(_STR_MEDIUM), _l(_STR_FAST), NULL };
301 const char* vmodeNames[] = { _l(_STR_AUTO), "PAL", "NTSC", NULL };
302 diaSetEnum(diaUIConfig, UICFG_SCROLL, scrollSpeeds);
303 diaSetEnum(diaUIConfig, UICFG_THEME, (const char **) thmGetGuiList());
304 diaSetEnum(diaUIConfig, UICFG_LANG, (const char **) lngGetGuiList());
305 diaSetEnum(diaUIConfig, UICFG_VMODE, vmodeNames);
307 diaSetInt(diaUIConfig, UICFG_SCROLL, gScrollSpeed);
308 diaSetInt(diaUIConfig, UICFG_THEME, thmGetGuiValue());
309 diaSetInt(diaUIConfig, UICFG_LANG, lngGetGuiValue());
310 guiUIUpdater(1);
311 diaSetInt(diaUIConfig, UICFG_AUTOSORT, gAutosort);
312 diaSetInt(diaUIConfig, UICFG_AUTOREFRESH, gAutoRefresh);
313 diaSetInt(diaUIConfig, UICFG_INFOPAGE, gUseInfoScreen);
314 diaSetInt(diaUIConfig, UICFG_COVERART, gEnableArt);
315 diaSetInt(diaUIConfig, UICFG_WIDESCREEN, gWideScreen);
316 diaSetInt(diaUIConfig, UICFG_VMODE, gVMode);
317 diaSetInt(diaUIConfig, UICFG_VSYNC, gVSync);
319 int ret = diaExecuteDialog(diaUIConfig, -1, 1, guiUIUpdater);
320 if (ret) {
321 int themeID = -1, langID = -1;
322 diaGetInt(diaUIConfig, UICFG_SCROLL, &gScrollSpeed);
323 diaGetInt(diaUIConfig, UICFG_LANG, &langID);
324 diaGetInt(diaUIConfig, UICFG_THEME, &themeID);
325 if (themeID == 0) {
326 diaGetColor(diaUIConfig, UICFG_BGCOL, gDefaultBgColor);
327 diaGetColor(diaUIConfig, UICFG_UICOL, gDefaultUITextColor);
328 diaGetColor(diaUIConfig, UICFG_TXTCOL, gDefaultTextColor);
329 diaGetColor(diaUIConfig, UICFG_SELCOL, gDefaultSelTextColor);
331 diaGetInt(diaUIConfig, UICFG_AUTOSORT, &gAutosort);
332 diaGetInt(diaUIConfig, UICFG_AUTOREFRESH, &gAutoRefresh);
333 diaGetInt(diaUIConfig, UICFG_INFOPAGE, &gUseInfoScreen);
334 diaGetInt(diaUIConfig, UICFG_COVERART, &gEnableArt);
335 diaGetInt(diaUIConfig, UICFG_WIDESCREEN, &gWideScreen);
336 diaGetInt(diaUIConfig, UICFG_VMODE, &gVMode);
337 diaGetInt(diaUIConfig, UICFG_VSYNC, &gVSync);
339 applyConfig(themeID, langID);
343 void guiShowIPConfig() {
344 size_t i;
345 // upload current values
346 for (i = 0; i < 4; ++i) {
347 if (gNetworkStartup != ERROR_ETH_NOT_STARTED) {
348 diaSetEnabled(diaIPConfig, 2 + i, 0);
349 diaSetEnabled(diaIPConfig, 6 + i, 0);
350 diaSetEnabled(diaIPConfig, 10 + i, 0);
351 } else {
352 diaSetEnabled(diaIPConfig, 2 + i, 1);
353 diaSetEnabled(diaIPConfig, 6 + i, 1);
354 diaSetEnabled(diaIPConfig, 10 + i, 1);
356 diaSetInt(diaIPConfig, 2 + i, ps2_ip[i]);
357 diaSetInt(diaIPConfig, 6 + i, ps2_netmask[i]);
358 diaSetInt(diaIPConfig, 10 + i, ps2_gateway[i]);
359 diaSetInt(diaIPConfig, 14 + i, pc_ip[i]);
362 diaSetInt(diaIPConfig, 18, gPCPort);
363 diaSetString(diaIPConfig, 19, gPCShareName);
364 diaSetString(diaIPConfig, 20, gPCUserName);
365 diaSetString(diaIPConfig, 21, gPCPassword);
367 if (gNetworkStartup == 0) {
368 diaSetLabel(diaIPConfig, NETCFG_OK, _l(_STR_OK));
369 diaIPConfig[64].type = UI_SPACER;
370 } else if (gNetworkStartup >= ERROR_ETH_SMB_LOGON) {
371 diaSetLabel(diaIPConfig, NETCFG_OK, _l(_STR_RECONNECT));
372 diaIPConfig[64].type = UI_TERMINATOR;
373 } else {
374 diaSetLabel(diaIPConfig, NETCFG_OK, _l(_STR_OK));
375 diaIPConfig[64].type = UI_TERMINATOR;
379 int result = diaExecuteDialog(diaIPConfig, -1, 1, NULL);
380 if (result) {
381 // Store values
382 for (i = 0; i < 4; ++i) {
383 diaGetInt(diaIPConfig, 2 + i, &ps2_ip[i]);
384 diaGetInt(diaIPConfig, 6 + i, &ps2_netmask[i]);
385 diaGetInt(diaIPConfig, 10 + i, &ps2_gateway[i]);
386 diaGetInt(diaIPConfig, 14 + i, &pc_ip[i]);
389 diaGetInt(diaIPConfig, 18, &gPCPort);
390 diaGetString(diaIPConfig, 19, gPCShareName);
391 diaGetString(diaIPConfig, 20, gPCUserName);
392 diaGetString(diaIPConfig, 21, gPCPassword);
393 gIPConfigChanged = 1;
395 if (result == NETCFG_RECONNECT)
396 gNetworkStartup = ERROR_ETH_SMB_LOGON;
398 applyConfig(-1, -1);
402 int guiShowKeyboard(char* value, int maxLength) {
403 char tmp[maxLength];
404 strncpy(tmp, value, maxLength);
406 int result = diaShowKeyb(tmp, maxLength);
407 if (result) {
408 strncpy(value, tmp, maxLength);
409 value[maxLength - 1] = '\0';
412 return result;
415 #ifdef VMC
416 typedef struct { // size = 76
417 int VMC_status; // 0=available, 1=busy
418 int VMC_error;
419 int VMC_progress;
420 char VMC_msg[64];
421 } statusVMCparam_t;
423 #define OPERATION_CREATE 0
424 #define OPERATION_CREATING 1
425 #define OPERATION_ABORTING 2
426 #define OPERATION_ENDING 3
427 #define OPERATION_END 4
429 static short vmc_refresh;
430 static int vmc_operation;
431 static statusVMCparam_t vmc_status;
433 int guiVmcNameHandler(char* text, int maxLen) {
434 int result = diaShowKeyb(text, maxLen);
436 if (result)
437 vmc_refresh = 1;
439 return result;
442 static int guiRefreshVMCConfig(item_list_t *support, char* name) {
443 int size = support->itemCheckVMC(name, 0);
445 if (size != -1) {
446 diaSetLabel(diaVMC, VMC_BUTTON_CREATE, _l(_STR_MODIFY));
447 diaSetLabel(diaVMC, VMC_STATUS, _l(_STR_VMC_FILE_EXISTS));
449 if (size == 8)
450 diaSetInt(diaVMC, VMC_SIZE, 0);
451 else if (size == 16)
452 diaSetInt(diaVMC, VMC_SIZE, 1);
453 else if (size == 32)
454 diaSetInt(diaVMC, VMC_SIZE, 2);
455 else if (size == 64)
456 diaSetInt(diaVMC, VMC_SIZE, 3);
457 else {
458 diaSetInt(diaVMC, VMC_SIZE, 0);
459 diaSetLabel(diaVMC, VMC_STATUS, _l(_STR_VMC_FILE_ERROR));
462 if (gEnableDandR) {
463 diaSetEnabled(diaVMC, VMC_SIZE, 1);
464 diaVMC[20].type = UI_SPLITTER;
466 else {
467 diaSetEnabled(diaVMC, VMC_SIZE, 0);
468 diaVMC[20].type = UI_TERMINATOR;
471 else {
472 diaSetLabel(diaVMC, VMC_BUTTON_CREATE, _l(_STR_CREATE));
473 diaSetLabel(diaVMC, VMC_STATUS, _l(_STR_VMC_FILE_NEW));
475 diaSetInt(diaVMC, VMC_SIZE, 0);
476 diaSetEnabled(diaVMC, VMC_SIZE, 1);
477 diaVMC[20].type = UI_TERMINATOR;
480 return size;
483 static int guiVMCUpdater(int modified) {
484 if (vmc_refresh) {
485 vmc_refresh = 0;
486 return VMC_REFRESH;
489 if ((vmc_operation == OPERATION_CREATING) || (vmc_operation == OPERATION_ABORTING)) {
490 int result = fileXioDevctl("genvmc:", 0xC0DE0003, NULL, 0, (void*) &vmc_status, sizeof(vmc_status));
491 if (result == 0) {
492 diaSetLabel(diaVMC, VMC_STATUS, vmc_status.VMC_msg);
493 diaSetInt(diaVMC, VMC_PROGRESS, vmc_status.VMC_progress);
495 if (vmc_status.VMC_error != 0)
496 LOG("GUI VMCUpdater: %d\n", vmc_status.VMC_error);
498 if (vmc_status.VMC_status == 0x00) {
499 diaSetLabel(diaVMC, VMC_BUTTON_CREATE, _l(_STR_OK));
500 vmc_operation = OPERATION_ENDING;
501 return VMC_BUTTON_CREATE;
504 else
505 LOG("GUI Status result: %d\n", result);
508 return 0;
511 static int guiShowVMCConfig(int id, item_list_t *support, char *VMCName, int slot, int validate) {
512 int result = validate ? VMC_BUTTON_CREATE : 0;
513 char vmc[32];
515 if (strlen(VMCName))
516 strncpy(vmc, VMCName, 32);
517 else {
518 if (validate)
519 return 1; // nothing to validate if no user input
521 char* startup = support->itemGetStartup(id);
522 snprintf(vmc, 32, "%s_%d", startup, slot);
525 vmc_refresh = 0;
526 vmc_operation = OPERATION_CREATE;
527 diaSetEnabled(diaVMC, VMC_NAME, 1);
528 diaSetEnabled(diaVMC, VMC_SIZE, 1);
529 diaSetInt(diaVMC, VMC_PROGRESS, 0);
531 const char* VMCSizes[] = {"8 Mb", "16 Mb", "32 Mb", "64 Mb", NULL};
532 diaSetEnum(diaVMC, VMC_SIZE, VMCSizes);
533 int size = guiRefreshVMCConfig(support, vmc);
534 diaSetString(diaVMC, VMC_NAME, vmc);
536 do {
537 if (result == VMC_BUTTON_CREATE) {
538 if (vmc_operation == OPERATION_CREATE) { // User start creation of VMC
539 int sizeUI;
540 diaGetInt(diaVMC, VMC_SIZE, &sizeUI);
541 if (sizeUI == 1)
542 sizeUI = 16;
543 else if (sizeUI == 2)
544 sizeUI = 32;
545 else if (sizeUI == 3)
546 sizeUI = 64;
547 else
548 sizeUI = 8;
550 if (sizeUI != size) {
551 support->itemCheckVMC(vmc, sizeUI);
553 diaSetEnabled(diaVMC, VMC_NAME, 0);
554 diaSetEnabled(diaVMC, VMC_SIZE, 0);
555 diaSetLabel(diaVMC, VMC_BUTTON_CREATE, _l(_STR_ABORT));
556 vmc_operation = OPERATION_CREATING;
558 else
559 break;
561 else if (vmc_operation == OPERATION_ENDING) {
562 if (validate)
563 break; // directly close VMC config dialog
565 vmc_operation = OPERATION_END;
567 else if (vmc_operation == OPERATION_END) { // User closed creation dialog of VMC
568 break;
570 else if (vmc_operation == OPERATION_CREATING) { // User canceled creation of VMC
571 fileXioDevctl("genvmc:", 0xC0DE0002, NULL, 0, NULL, 0);
572 vmc_operation = OPERATION_ABORTING;
575 else if (result == VMC_BUTTON_DELETE) {
576 if (guiMsgBox(_l(_STR_DELETE_WARNING), 1, diaVMC)) {
577 support->itemCheckVMC(vmc, -1);
578 diaSetString(diaVMC, VMC_NAME, "");
579 break;
582 else if (result == VMC_REFRESH) { // User changed the VMC name
583 diaGetString(diaVMC, VMC_NAME, vmc);
584 size = guiRefreshVMCConfig(support, vmc);
587 result = diaExecuteDialog(diaVMC, result, 1, &guiVMCUpdater);
589 if ((result == 0) && (vmc_operation == OPERATION_CREATE))
590 break;
591 } while (1);
593 return result;
595 #endif
597 int guiAltStartupNameHandler(char* text, int maxLen) {
598 int i;
600 int result = diaShowKeyb(text, maxLen);
601 if (result) {
602 for (i = 0; text[i]; i++) {
603 if (text[i] > 96 && text[i] < 123)
604 text[i] -= 32;
608 return result;
611 int guiShowCompatConfig(int id, item_list_t *support, config_set_t* configSet) {
612 int dmaMode = 7; // defaulting to UDMA 4
613 if (support->haveCompatibilityMode == COMPAT_FULL) {
614 configGetInt(configSet, CONFIG_ITEM_DMA, &dmaMode);
615 const char* dmaModes[] = { "MDMA 0", "MDMA 1", "MDMA 2", "UDMA 0", "UDMA 1", "UDMA 2", "UDMA 3", "UDMA 4", "UDMA 5", "UDMA 6", NULL };
616 diaSetEnum(diaCompatConfig, COMPAT_DMA, dmaModes);
617 diaSetInt(diaCompatConfig, COMPAT_DMA, dmaMode);
618 } else {
619 const char* dmaModes[] = { NULL };
620 diaSetEnum(diaCompatConfig, COMPAT_DMA, dmaModes);
621 diaSetInt(diaCompatConfig, COMPAT_DMA, 0);
624 diaSetLabel(diaCompatConfig, COMPAT_GAME, support->itemGetName(id));
626 int compatMode = 0;
627 configGetInt(configSet, CONFIG_ITEM_COMPAT, &compatMode);
628 int i, result = -1;
629 for (i = 0; i < COMPAT_MODE_COUNT; ++i)
630 diaSetInt(diaCompatConfig, COMPAT_MODE_BASE + i, (compatMode & (1 << i)) > 0 ? 1 : 0);
632 int timer = 0;
633 configGetInt(configSet, CONFIG_ITEM_CDVDMAN_TIMER, &timer);
634 diaSetInt(diaCompatConfig, COMPAT_CDVDMAN_TIMER, timer);
636 // Find out the current game ID
637 char hexid[32];
638 configGetStrCopy(configSet, CONFIG_ITEM_DNAS, hexid);
639 diaSetString(diaCompatConfig, COMPAT_GAMEID, hexid);
641 char altStartup[32];
642 configGetStrCopy(configSet, CONFIG_ITEM_ALTSTARTUP, altStartup);
643 diaSetString(diaCompatConfig, COMPAT_ALTSTARTUP, altStartup);
645 #ifdef VMC
646 char vmc1[32];
647 configGetVMC(configSet, vmc1, 0);
648 diaSetLabel(diaCompatConfig, COMPAT_VMC1_DEFINE, vmc1);
650 char vmc2[32]; // required as diaSetLabel use pointer to value
651 configGetVMC(configSet, vmc2, 1);
652 diaSetLabel(diaCompatConfig, COMPAT_VMC2_DEFINE, vmc2);
653 #endif
655 // show dialog
656 do {
657 #ifdef VMC
658 if (strlen(vmc1))
659 diaSetLabel(diaCompatConfig, COMPAT_VMC1_ACTION, _l(_STR_RESET));
660 else
661 diaSetLabel(diaCompatConfig, COMPAT_VMC1_ACTION, _l(_STR_USE_GENERIC));
662 if (strlen(vmc2))
663 diaSetLabel(diaCompatConfig, COMPAT_VMC2_ACTION, _l(_STR_RESET));
664 else
665 diaSetLabel(diaCompatConfig, COMPAT_VMC2_ACTION, _l(_STR_USE_GENERIC));
666 #endif
668 result = diaExecuteDialog(diaCompatConfig, result, 1, NULL);
670 if (result == COMPAT_LOADFROMDISC) {
671 char hexDiscID[15];
672 if (sysGetDiscID(hexDiscID) >= 0)
673 diaSetString(diaCompatConfig, COMPAT_GAMEID, hexDiscID);
674 else
675 guiMsgBox(_l(_STR_ERROR_LOADING_ID), 0, NULL);
677 #ifdef VMC
678 else if (result == COMPAT_VMC1_DEFINE) {
679 if(guiShowVMCConfig(id, support, vmc1, 0, 0))
680 diaGetString(diaVMC, VMC_NAME, vmc1);
681 } else if (result == COMPAT_VMC2_DEFINE) {
682 if(guiShowVMCConfig(id, support, vmc2, 1, 0))
683 diaGetString(diaVMC, VMC_NAME, vmc2);
684 } else if (result == COMPAT_VMC1_ACTION) {
685 if (strlen(vmc1))
686 vmc1[0] = '\0';
687 else
688 snprintf(vmc1, 32, "generic_%d", 0);
689 } else if (result == COMPAT_VMC2_ACTION) {
690 if (strlen(vmc2))
691 vmc2[0] = '\0';
692 else
693 snprintf(vmc2, 32, "generic_%d", 1);
695 #endif
696 } while (result >= COMPAT_NOEXIT);
698 if (result == COMPAT_REMOVE) {
699 configRemoveKey(configSet, CONFIG_ITEM_DMA);
700 configRemoveKey(configSet, CONFIG_ITEM_COMPAT);
701 configRemoveKey(configSet, CONFIG_ITEM_DNAS);
702 configRemoveKey(configSet, CONFIG_ITEM_ALTSTARTUP);
703 #ifdef VMC
704 configRemoveVMC(configSet, 0);
705 configRemoveVMC(configSet, 1);
706 #endif
707 menuSaveConfig();
708 } else if (result > 0) { // test button pressed or save button
709 compatMode = 0;
710 for (i = 0; i < COMPAT_MODE_COUNT; ++i) {
711 int mdpart;
712 diaGetInt(diaCompatConfig, COMPAT_MODE_BASE + i, &mdpart);
713 compatMode |= (mdpart ? 1 : 0) << i;
716 if (support->haveCompatibilityMode == COMPAT_FULL) {
717 diaGetInt(diaCompatConfig, COMPAT_DMA, &dmaMode);
718 if (dmaMode != 7)
719 configSetInt(configSet, CONFIG_ITEM_DMA, dmaMode);
720 else
721 configRemoveKey(configSet, CONFIG_ITEM_DMA);
724 if (compatMode != 0)
725 configSetInt(configSet, CONFIG_ITEM_COMPAT, compatMode);
726 else
727 configRemoveKey(configSet, CONFIG_ITEM_COMPAT);
729 diaGetInt(diaCompatConfig, COMPAT_CDVDMAN_TIMER, &timer);
730 if (timer != 0)
731 configSetInt(configSet, CONFIG_ITEM_CDVDMAN_TIMER, timer);
732 else
733 configRemoveKey(configSet, CONFIG_ITEM_CDVDMAN_TIMER);
735 diaGetString(diaCompatConfig, COMPAT_GAMEID, hexid);
736 if (hexid[0] != '\0')
737 configSetStr(configSet, CONFIG_ITEM_DNAS, hexid);
739 diaGetString(diaCompatConfig, COMPAT_ALTSTARTUP, altStartup);
740 if (altStartup[0] != '\0')
741 configSetStr(configSet, CONFIG_ITEM_ALTSTARTUP, altStartup);
742 else
743 configRemoveKey(configSet, CONFIG_ITEM_ALTSTARTUP);
745 #ifdef VMC
746 configSetVMC(configSet, vmc1, 0);
747 configSetVMC(configSet, vmc2, 1);
748 guiShowVMCConfig(id, support, vmc1, 0, 1);
749 guiShowVMCConfig(id, support, vmc2, 1, 1);
750 #endif
752 if (result == COMPAT_SAVE)
753 menuSaveConfig();
756 return result;
759 int guiGetOpCompleted(int opid) {
760 return gCompletedOps > opid;
763 int guiDeferUpdate(struct gui_update_t *op) {
764 WaitSema(gSemaId);
766 struct gui_update_list_t* up = (struct gui_update_list_t*) malloc(sizeof(struct gui_update_list_t));
767 up->item = op;
768 up->next = NULL;
770 if (!gUpdateList) {
771 gUpdateList = up;
772 gUpdateEnd = gUpdateList;
773 } else {
774 gUpdateEnd->next = up;
775 gUpdateEnd = up;
778 SignalSema(gSemaId);
780 return gScheduledOps++;
783 static void guiHandleOp(struct gui_update_t* item) {
784 submenu_list_t* result = NULL;
786 switch (item->type) {
787 case GUI_INIT_DONE:
788 gInitComplete = 1;
789 break;
791 case GUI_OP_ADD_MENU:
792 menuAppendItem(item->menu.menu);
793 break;
795 case GUI_OP_APPEND_MENU:
796 result = submenuAppendItem(item->menu.subMenu, item->submenu.icon_id,
797 item->submenu.text, item->submenu.id, item->submenu.text_id);
799 if (!item->menu.menu->submenu) { // first subitem in list
800 item->menu.menu->submenu = result;
801 item->menu.menu->current = result;
802 item->menu.menu->pagestart = result;
803 } else if (item->submenu.selected) { // remember last game feat.
804 item->menu.menu->current = result;
805 item->menu.menu->pagestart = result;
806 item->menu.menu->remindLast = 1;
809 break;
811 case GUI_OP_SELECT_MENU:
812 menuSetSelectedItem(item->menu.menu);
813 screenHandler = &screenHandlers[GUI_SCREEN_MAIN];
814 break;
816 case GUI_OP_CLEAR_SUBMENU:
817 submenuDestroy(item->menu.subMenu);
818 item->menu.menu->submenu = NULL;
819 item->menu.menu->current = NULL;
820 item->menu.menu->pagestart = NULL;
821 break;
823 case GUI_OP_SORT:
824 submenuSort(item->menu.subMenu);
825 item->menu.menu->submenu = *item->menu.subMenu;
827 if (!item->menu.menu->remindLast)
828 item->menu.menu->current = item->menu.menu->submenu;
830 item->menu.menu->pagestart = item->menu.menu->current;
831 break;
833 case GUI_OP_ADD_HINT:
834 // append the hint list in the menu item
835 menuAddHint(item->menu.menu, item->hint.text_id, item->hint.icon_id);
836 break;
838 default:
839 LOG("GUI: ??? (%d)\n", item->type);
843 static void guiHandleDeferredOps(void) {
844 // TODO: Fit into the given time interval, skip rest of operations of over limit
846 while (gUpdateList) {
847 WaitSema(gSemaId);
849 guiHandleOp(gUpdateList->item);
851 struct gui_update_list_t* td = gUpdateList;
852 gUpdateList = gUpdateList->next;
854 free(td);
856 gCompletedOps++;
858 SignalSema(gSemaId);
861 gUpdateEnd = NULL;
864 static int bfadeout = 0x0;
865 static void guiDrawBusy() {
866 if (gTheme->loadingIcon) {
867 GSTEXTURE* texture = thmGetTexture(LOAD0_ICON + (guiFrameId >> 1) % gTheme->loadingIconCount);
868 if (texture && texture->Mem) {
869 u64 mycolor = GS_SETREG_RGBA(0x080, 0x080, 0x080, bfadeout);
870 rmDrawPixmap(texture, gTheme->loadingIcon->posX, gTheme->loadingIcon->posY, gTheme->loadingIcon->aligned, gTheme->loadingIcon->width, gTheme->loadingIcon->height, gTheme->loadingIcon->scaled, mycolor);
875 static int wfadeout = 0x0150;
876 static void guiRenderGreeting() {
877 int fade = wfadeout > 0xFF ? 0xFF : wfadeout;
878 u64 mycolor = GS_SETREG_RGBA(0x10, 0x10, 0x10, fade >> 1);
879 rmDrawRect(0, 0, screenWidth, screenHeight, mycolor);
881 GSTEXTURE* logo = thmGetTexture(LOGO_PICTURE);
882 if (logo) {
883 mycolor = GS_SETREG_RGBA(0x080, 0x080, 0x080, fade >> 1);
884 rmDrawPixmap(logo, screenWidth >> 1, gTheme->usedHeight >> 1, ALIGN_CENTER, logo->Width, logo->Height, SCALING_RATIO, mycolor);
887 return;
890 static float mix(float a, float b, float t) {
891 return (1.0 - t) * a + t * b;
894 static float fade(float t) {
895 return fadetbl[(int) (t * FADE_SIZE)];
898 // The same as mix, but with 8 (2*4) values mixed at once
899 static void VU0MixVec(VU_VECTOR *a, VU_VECTOR *b, float mix, VU_VECTOR* res) {
900 asm (
901 "lqc2 vf1, 0(%0)\n" // load the first vector
902 "lqc2 vf2, 0(%1)\n" // load the second vector
903 "lw $2, 0(%2)\n" // load value from ptr to reg
904 "qmtc2 $2, vf3\n" // load the mix value from reg to VU
905 "vaddw.x vf5, vf00, vf00\n" // vf5.x = 1
906 "vsub.x vf4x, vf5x, vf3x\n" // subtract 1 - vf3,x, store the result in vf4.x
907 "vmulax.xyzw ACC, vf1, vf3x\n" // multiply vf1 by vf3.x, store the result in ACC
908 "vmaddx.xyzw vf1, vf2, vf4x\n" // multiply vf2 by vf4.x add ACC, store the result in vf1
909 "sqc2 vf1, 0(%3)\n" // transfer the result in acc to the ee
910 : : "r" (a), "r" (b), "r" (&mix), "r" (res)
914 static float guiCalcPerlin(float x, float y, float z) {
915 // Taken from: http://people.opera.com/patrickl/experiments/canvas/plasma/perlin-noise-classical.js
916 // By Sean McCullough
918 // Find unit grid cell containing point
919 int X = floor(x);
920 int Y = floor(y);
921 int Z = floor(z);
923 // Get relative xyz coordinates of point within that cell
924 x = x - X;
925 y = y - Y;
926 z = z - Z;
928 // Wrap the integer cells at 255 (smaller integer period can be introduced here)
929 X = X & 255;
930 Y = Y & 255;
931 Z = Z & 255;
933 // Calculate a set of eight hashed gradient indices
934 int gi000 = pperm[X + pperm[Y + pperm[Z]]] % 12;
935 int gi001 = pperm[X + pperm[Y + pperm[Z + 1]]] % 12;
936 int gi010 = pperm[X + pperm[Y + 1 + pperm[Z]]] % 12;
937 int gi011 = pperm[X + pperm[Y + 1 + pperm[Z + 1]]] % 12;
938 int gi100 = pperm[X + 1 + pperm[Y + pperm[Z]]] % 12;
939 int gi101 = pperm[X + 1 + pperm[Y + pperm[Z + 1]]] % 12;
940 int gi110 = pperm[X + 1 + pperm[Y + 1 + pperm[Z]]] % 12;
941 int gi111 = pperm[X + 1 + pperm[Y + 1 + pperm[Z + 1]]] % 12;
943 // The gradients of each corner are now:
944 // g000 = grad3[gi000];
945 // g001 = grad3[gi001];
946 // g010 = grad3[gi010];
947 // g011 = grad3[gi011];
948 // g100 = grad3[gi100];
949 // g101 = grad3[gi101];
950 // g110 = grad3[gi110];
951 // g111 = grad3[gi111];
952 // Calculate noise contributions from each of the eight corners
953 VU_VECTOR vec;
954 vec.x = x;
955 vec.y = y;
956 vec.z = z;
957 vec.w = 1;
959 VU_VECTOR a, b;
961 // float n000
962 a.x = Vu0DotProduct(&pgrad3[gi000], &vec);
964 vec.y -= 1;
966 // float n010
967 a.z = Vu0DotProduct(&pgrad3[gi010], &vec);
969 vec.x -= 1;
971 //float n110
972 b.z = Vu0DotProduct(&pgrad3[gi110], &vec);
974 vec.y += 1;
976 // float n100
977 b.x = Vu0DotProduct(&pgrad3[gi100], &vec);
979 vec.z -= 1;
981 // float n101
982 b.y = Vu0DotProduct(&pgrad3[gi101], &vec);
984 vec.y -= 1;
986 // float n111
987 b.w = Vu0DotProduct(&pgrad3[gi111], &vec);
989 vec.x += 1;
991 // float n011
992 a.w = Vu0DotProduct(&pgrad3[gi011], &vec);
994 vec.y += 1;
996 // float n001
997 a.y = Vu0DotProduct(&pgrad3[gi001], &vec);
999 // Compute the fade curve value for each of x, y, z
1000 float u = fade(x);
1001 float v = fade(y);
1002 float w = fade(z);
1004 // TODO: Low priority... This could be done on VU0 (xyzw for the first 4 mixes)
1005 // The result in sw
1006 // Interpolate along x the contributions from each of the corners
1007 VU_VECTOR rv;
1008 VU0MixVec(&b, &a, u, &rv);
1010 // TODO: The VU0MixVec could as well mix the results (as follows) - might improve performance...
1011 // Interpolate the four results along y
1012 float nxy0 = mix(rv.x, rv.z, v);
1013 float nxy1 = mix(rv.y, rv.w, v);
1014 // Interpolate the two last results along z
1015 float nxyz = mix(nxy0, nxy1, w);
1017 return nxyz;
1020 static float dir = 0.02;
1021 static float perz = -100;
1022 static int pery = 0;
1023 static unsigned char curbgColor[3] = { 0, 0, 0 };
1025 static int cdirection(unsigned char a, unsigned char b) {
1026 if (a == b)
1027 return 0;
1028 else if (a > b)
1029 return -1;
1030 else
1031 return 1;
1034 void guiDrawBGPlasma() {
1035 int x, y;
1037 // transition the colors
1038 curbgColor[0] += cdirection(curbgColor[0], gTheme->bgColor[0]);
1039 curbgColor[1] += cdirection(curbgColor[1], gTheme->bgColor[1]);
1040 curbgColor[2] += cdirection(curbgColor[2], gTheme->bgColor[2]);
1042 // it's PLASMA_ROWS_PER_FRAME rows a frame to stop being a resource hog
1043 if (pery >= PLASMA_H) {
1044 pery = 0;
1045 perz += dir;
1047 if (perz > 100.0f || perz < -100.0f)
1048 dir = -dir;
1051 u32 *buf = gBackgroundTex.Mem + PLASMA_W * pery;
1052 int ymax = pery + PLASMA_ROWS_PER_FRAME;
1054 if (ymax > PLASMA_H)
1055 ymax = PLASMA_H;
1057 for (y = pery; y < ymax; y++) {
1058 for (x = 0; x < PLASMA_W; x++) {
1059 u32 fper = guiCalcPerlin((float) (2 * x) / PLASMA_W, (float) (2 * y) / PLASMA_H, perz) * 0x080 + 0x080;
1061 *buf = GS_SETREG_RGBA(
1062 (u32)(fper * curbgColor[0]) >> 8,
1063 (u32)(fper * curbgColor[1]) >> 8,
1064 (u32)(fper * curbgColor[2]) >> 8,
1065 0x080);
1067 ++buf;
1072 pery = ymax;
1073 rmDrawPixmap(&gBackgroundTex, 0, 0, ALIGN_NONE, screenWidth, screenHeight, SCALING_NONE, gDefaultCol);
1076 int guiDrawIconAndText(int iconId, int textId, int font, int x, int y, u64 color) {
1077 GSTEXTURE* iconTex = thmGetTexture(iconId);
1078 if (iconTex && iconTex->Mem) {
1079 rmDrawPixmap(iconTex, x, y, ALIGN_NONE, iconTex->Width, iconTex->Height, SCALING_RATIO, gDefaultCol);
1080 x += iconTex->Width + 2;
1083 x = fntRenderString(font, x, y, ALIGN_NONE, 0, 0, _l(textId), color);
1085 return x;
1088 static void guiDrawOverlays() {
1089 // are there any pending operations?
1090 int pending = ioHasPendingRequests();
1092 if (!pending) {
1093 if (bfadeout > 0x0)
1094 bfadeout -= 0x08;
1095 else
1096 bfadeout = 0x0;
1097 } else {
1098 if (bfadeout < 0x080)
1099 bfadeout += 0x20;
1102 if (bfadeout > 0)
1103 guiDrawBusy();
1105 #ifdef __DEBUG
1106 // fps meter
1107 char fps[20];
1109 if (time_since_last != 0)
1110 snprintf(fps, 20, "%3d ms %3.1f FPS", time_render, 1000.0f / (float) time_since_last);
1111 else
1112 snprintf(fps, 20, "%3d ms ----- FPS", time_render);
1114 fntRenderString(gTheme->fonts[0], screenWidth - 90, 30, ALIGN_CENTER, 0, 0, fps, GS_SETREG_RGBA(0x060, 0x060, 0x060, 0x060));
1115 #endif
1118 static void guiReadPads() {
1119 if (readPads())
1120 guiInactiveFrames = 0;
1121 else
1122 guiInactiveFrames++;
1125 // renders the screen and handles inputs. Also handles screen transitions between numerous
1126 // screen handlers. For now we only have left-to right screen transition
1127 static void guiShow() {
1128 // is there a transmission effect going on or are
1129 // we in a normal rendering state?
1130 if (screenHandlerTarget) {
1131 // advance the effect
1133 // render the old screen, transposed
1134 rmSetTransposition(transIndex * transitionX, transIndex * transitionY);
1135 screenHandler->renderScreen();
1137 // render new screen transposed again
1138 rmSetTransposition((transIndex - transMax) * transitionX, (transIndex - transMax) * transitionY);
1139 screenHandlerTarget->renderScreen();
1141 // reset transposition to zero
1142 rmSetTransposition(0, 0);
1144 // move the transition indicator forward
1145 transIndex += (min(transIndex, transMax - transIndex) >> 1) + 1;
1147 if (transIndex > transMax) {
1148 transitionX = 0;
1149 transitionY = 0;
1150 screenHandler = screenHandlerTarget;
1151 screenHandlerTarget = NULL;
1153 } else
1154 // render with the set screen handler
1155 screenHandler->renderScreen();
1158 void guiIntroLoop(void) {
1159 int endIntro = 0;
1160 while (!endIntro) {
1161 guiStartFrame();
1163 guiReadPads();
1165 if (wfadeout < 0x0FF)
1166 guiShow();
1168 if (gInitComplete)
1169 wfadeout--;
1171 if (wfadeout > 0)
1172 guiRenderGreeting();
1173 else
1174 endIntro = 1;
1176 guiHandleDeferredOps();
1178 guiEndFrame();
1180 if (!screenHandlerTarget && screenHandler)
1181 screenHandler->handleInput();
1185 void guiMainLoop(void) {
1186 while (!gTerminate) {
1187 guiStartFrame();
1189 // Read the pad states to prepare for input processing in the screen handler
1190 guiReadPads();
1192 // handle inputs and render screen
1193 guiShow();
1195 // Render overlaying gui thingies :)
1196 guiDrawOverlays();
1198 // handle deferred operations
1199 guiHandleDeferredOps();
1201 guiEndFrame();
1203 // if not transiting, handle input
1204 // done here so we can use renderman if needed
1205 if (!screenHandlerTarget && screenHandler)
1206 screenHandler->handleInput();
1208 if (gFrameHook)
1209 gFrameHook();
1213 void guiSetFrameHook(gui_callback_t cback) {
1214 gFrameHook = cback;
1217 void guiSwitchScreen(int target, int transition) {
1218 if (transition == TRANSITION_LEFT) {
1219 transitionX = 1;
1220 transMax = screenWidth;
1221 } else if (transition == TRANSITION_RIGHT) {
1222 transitionX = -1;
1223 transMax = screenWidth;
1224 } else if (transition == TRANSITION_UP) {
1225 transitionY = 1;
1226 transMax = screenHeight;
1227 } else if (transition == TRANSITION_DOWN) {
1228 transitionY = -1;
1229 transMax = screenHeight;
1231 transIndex = 0;
1233 screenHandlerTarget = &screenHandlers[target];
1236 struct gui_update_t *guiOpCreate(gui_op_type_t type) {
1237 struct gui_update_t *op = (struct gui_update_t *) malloc(sizeof(struct gui_update_t));
1238 memset(op, 0, sizeof(struct gui_update_t));
1239 op->type = type;
1240 return op;
1243 void guiUpdateScrollSpeed(void) {
1244 // sanitize the settings
1245 if ((gScrollSpeed < 0) || (gScrollSpeed > 2))
1246 gScrollSpeed = 1;
1248 // update the pad delays for KEY_UP and KEY_DOWN
1249 // default delay is 7
1250 // fast - 100 ms
1251 // medium - 300 ms
1252 // slow - 500 ms
1253 setButtonDelay(KEY_UP, 500 - gScrollSpeed * 200); // 0,1,2 -> 500, 300, 100
1254 setButtonDelay(KEY_DOWN, 500 - gScrollSpeed * 200);
1257 void guiUpdateScreenScale(void) {
1258 if (gWideScreen)
1259 wideScreenScale = 0.75f;
1260 else
1261 wideScreenScale = 1.0f;
1263 // apply the scaling to renderman and font rendering
1264 rmSetAspectRatio(wideScreenScale, 1.0f);
1265 fntSetAspectRatio(wideScreenScale, 1.0f);
1268 int guiMsgBox(const char* text, int addAccept, struct UIItem *ui) {
1269 int terminate = 0;
1270 while (!terminate) {
1271 guiStartFrame();
1273 readPads();
1275 if (getKeyOn(KEY_CIRCLE))
1276 terminate = 1;
1277 else if (getKeyOn(KEY_CROSS))
1278 terminate = 2;
1280 if (ui)
1281 diaRenderUI(ui, screenHandler->inMenu, NULL, 0);
1282 else
1283 guiShow();
1285 rmDrawRect(0, 0, screenWidth, screenHeight, gColDarker);
1287 rmDrawLine(50, 75, screenWidth - 50, 75, gColWhite);
1288 rmDrawLine(50, 410, screenWidth - 50, 410, gColWhite);
1290 fntRenderString(gTheme->fonts[0], screenWidth >> 1, gTheme->usedHeight >> 1, ALIGN_CENTER, 0, 0, text, gTheme->textColor);
1291 guiDrawIconAndText(CIRCLE_ICON, _STR_O_BACK, gTheme->fonts[0], 500, 417, gTheme->selTextColor);
1292 if (addAccept)
1293 guiDrawIconAndText(CROSS_ICON, _STR_X_ACCEPT, gTheme->fonts[0], 70, 417, gTheme->selTextColor);
1295 guiEndFrame();
1298 return terminate - 1;
1301 void guiHandleDeferedIO(int *ptr, const unsigned char* message, int type, void *data) {
1302 ioPutRequest(type, data);
1304 while (*ptr)
1305 guiRenderTextScreen(message);
1308 void guiRenderTextScreen(const unsigned char* message) {
1309 guiStartFrame();
1311 guiShow();
1313 rmDrawRect(0, 0, screenWidth, screenHeight, gColDarker);
1315 fntRenderString(gTheme->fonts[0], screenWidth >> 1, gTheme->usedHeight >> 1, ALIGN_CENTER, 0, 0, message, gTheme->textColor);
1317 guiDrawOverlays();
1319 guiEndFrame();