1 /*
2  * OpenBOR - http://www.LavaLit.com
3  * -----------------------------------------------------------------------
4  * Licensed under the BSD license, see LICENSE in OpenBOR root for details.
5  *
6  * Copyright (c) 2004 - 2011 OpenBOR Team
7  */
8 // Adapted from sdl/menu.c.  Uses s_screen images instead of SDL surfaces.
9 
10 #include <dirent.h>
11 #include <unistd.h>
12 #include <ogcsys.h>
13 #include <wiiuse/wpad.h>
14 #include "wiiport.h"
15 #include "video.h"
16 #include "control.h"
17 #include "soundmix.h"
18 #include "packfile.h"
19 #include "hankaku.h"
20 #include "stristr.h"
21 
22 #include "pngdec.h"
23 #include "../resources/OpenBOR_Menu_480x272_png.h"
24 #include "../resources/OpenBOR_Menu_320x240_png.h"
25 
26 #undef MIN
27 #undef MAX
28 #include "openbor.h"
29 #undef time
30 #include <time.h>
31 
32 extern int videoMode;
33 
34 #define RGB32(R,G,B) ((R << 16) | ((G) << 8) | (B))
35 #define RGB16(R,G,B) ((B&0xF8)<<8) | ((G&0xFC)<<3) | (R>>3)
36 #define RGB(R,G,B)   (bpp==16?RGB16(R,G,B):RGB32(R,G,B))
37 
38 #define BLACK		RGB(  0,   0,   0)
39 #define WHITE		RGB(255, 255, 255)
40 #define RED			RGB(255,   0,   0)
41 #define	GREEN		RGB(  0, 255,   0)
42 #define BLUE		RGB(  0,   0, 255)
43 #define YELLOW		RGB(255, 255,   0)
44 #define PURPLE		RGB(255,   0, 255)
45 #define ORANGE		RGB(255, 128,   0)
46 #define GRAY		RGB(112, 128, 144)
47 #define LIGHT_GRAY  RGB(223, 223, 223)
48 #define DARK_RED	RGB(128,   0,   0)
49 #define DARK_GREEN	RGB(  0, 128,   0)
50 #define DARK_BLUE	RGB(  0,   0, 128)
51 
52 #define LOG_SCREEN_TOP 2
53 #define LOG_SCREEN_END (isWide ? 26 : 23)
54 
55 #define DIR_UP			0x00000001
56 #define DIR_RIGHT		0x00000002
57 #define DIR_DOWN		0x00000004
58 #define DIR_LEFT		0x00000008
59 #define WIIMOTE_A		0x00000010
60 #define WIIMOTE_B		0x00000020
61 #define WIIMOTE_1		0x00000040
62 #define WIIMOTE_2		0x00000080
63 #define WIIMOTE_PLUS	0x00000100
64 #define WIIMOTE_MINUS	0x00000200
65 #define WIIMOTE_HOME	0x00000400
66 #define NUNCHUK_C		0x00000800
67 #define NUNCHUK_Z		0x00001000
68 #define CC_A			0x00002000
69 #define CC_B			0x00004000
70 #define CC_X			0x00008000
71 #define CC_Y			0x00010000
72 #define CC_L			0x00020000
73 #define CC_R			0x00040000
74 #define CC_ZL			0x00080000
75 #define CC_ZR			0x00100000
76 #define CC_PLUS			0x00200000
77 #define CC_MINUS		0x00400000
78 #define CC_HOME			0x00800000
79 #define GC_A			0x01000000
80 #define GC_B			0x02000000
81 #define GC_X			0x04000000
82 #define GC_Y			0x08000000
83 #define GC_L			0x10000000
84 #define GC_R			0x20000000
85 #define GC_Z			0x40000000
86 #define GC_START		0x80000000
87 
88 s_screen *Source = NULL;
89 s_screen *Scaler = NULL;
90 s_screen *Screen = NULL;
91 int bpp = 32;
92 int factor = 1;
93 int isFull = 0;
94 int isWide = 0;
95 int flags;
96 int dListTotal;
97 int dListCurrentPosition;
98 int dListScrollPosition;
99 int which_logfile = OPENBOR_LOG;
100 int buttonsHeld = 0;
101 int buttonsPressed = 0;
102 FILE *bgmFile = NULL;
103 extern unsigned long bothkeys, bothnewkeys;
104 fileliststruct *filelist;
105 s_videomodes videomodes;
106 
107 typedef struct{
108 	stringptr *buf;
109 	int *pos;
110 	int line;
111 	int rows;
112 	char ready;
113 }s_logfile;
114 s_logfile logfile[2];
115 
116 typedef struct{
117 	int x;
118 	int y;
119 	int width;
120 	int height;
121 }Rect;
122 
123 typedef int (*ControlInput)();
124 
125 int ControlMenu();
126 int ControlBGM();
127 void PlayBGM();
128 void StopBGM();
129 void fillRect(s_screen* dest, Rect* rect, u32 color);
130 static ControlInput pControl;
131 
Control()132 int Control()
133 {
134 	return pControl();
135 }
136 
refreshInput()137 void refreshInput()
138 {
139 	unsigned long btns = 0;
140 	unsigned short gcbtns;
141 	WPADData *wpad;
142 
143 	PAD_Init();
144 	PAD_ScanPads();
145 	gcbtns = PAD_ButtonsDown(0) | PAD_ButtonsHeld(0);
146 	WPAD_ScanPads();
147 	wpad = WPAD_Data(0);
148 
149 	if(wpad->exp.type == WPAD_EXP_CLASSIC)
150 	{
151 		// Left thumb stick
152 		if(wpad->exp.classic.ljs.mag >= 0.3)
153 		{
154 			if (wpad->exp.classic.ljs.ang >= 310 || wpad->exp.classic.ljs.ang <= 50)   btns |= DIR_UP;
155 			if (wpad->exp.classic.ljs.ang >= 130 && wpad->exp.classic.ljs.ang <= 230)  btns |= DIR_DOWN;
156 			if (wpad->exp.classic.ljs.ang >= 220 && wpad->exp.classic.ljs.ang <= 320)  btns |= DIR_LEFT;
157 			if (wpad->exp.classic.ljs.ang >= 40 && wpad->exp.classic.ljs.ang <= 140)   btns |= DIR_RIGHT;
158 		}
159 		// D-pad
160 		if(wpad->btns_h & WPAD_CLASSIC_BUTTON_UP)         btns |= DIR_UP;
161 		if(wpad->btns_h & WPAD_CLASSIC_BUTTON_DOWN)       btns |= DIR_DOWN;
162 		if(wpad->btns_h & WPAD_CLASSIC_BUTTON_LEFT)       btns |= DIR_LEFT;
163 		if(wpad->btns_h & WPAD_CLASSIC_BUTTON_RIGHT)      btns |= DIR_RIGHT;
164 	}
165 	else if(wpad->exp.type == WPAD_EXP_NUNCHUK) // Wiimote + Nunchuk
166 	{
167 		if(wpad->exp.nunchuk.js.pos.y >= 0xB0)            btns |= DIR_UP;
168 		if(wpad->exp.nunchuk.js.pos.y <= 0x40)            btns |= DIR_DOWN;
169 		if(wpad->exp.nunchuk.js.pos.x <= 0x40)            btns |= DIR_LEFT;
170 		if(wpad->exp.nunchuk.js.pos.x >= 0xB0)            btns |= DIR_RIGHT;
171 		if(wpad->btns_h & WPAD_BUTTON_UP)                 btns |= DIR_UP;
172 		if(wpad->btns_h & WPAD_BUTTON_DOWN)               btns |= DIR_DOWN;
173 		if(wpad->btns_h & WPAD_BUTTON_LEFT)               btns |= DIR_LEFT;
174 		if(wpad->btns_h & WPAD_BUTTON_RIGHT)              btns |= DIR_RIGHT;
175 	}
176 	else // Wiimote held sideways
177 	{
178 		if(wpad->btns_h & WPAD_BUTTON_UP)                 btns |= DIR_LEFT;
179 		if(wpad->btns_h & WPAD_BUTTON_DOWN)               btns |= DIR_RIGHT;
180 		if(wpad->btns_h & WPAD_BUTTON_LEFT)               btns |= DIR_DOWN;
181 		if(wpad->btns_h & WPAD_BUTTON_RIGHT)              btns |= DIR_UP;
182 	}
183 
184 	// GameCube analog stick and D-pad
185 	if(PAD_StickY(0) > 18)                                btns |= DIR_UP;
186 	if(PAD_StickY(0) < -18)                               btns |= DIR_DOWN;
187 	if(PAD_StickX(0) < -18)                               btns |= DIR_LEFT;
188 	if(PAD_StickX(0) > 18)                                btns |= DIR_RIGHT;
189 	if(gcbtns & PAD_BUTTON_UP)                            btns |= DIR_UP;
190 	if(gcbtns & PAD_BUTTON_DOWN)                          btns |= DIR_DOWN;
191 	if(gcbtns & PAD_BUTTON_LEFT)                          btns |= DIR_LEFT;
192 	if(gcbtns & PAD_BUTTON_RIGHT)                         btns |= DIR_RIGHT;
193 
194 	// Controller buttons
195 	if(wpad->btns_h & WPAD_BUTTON_1)                      btns |= WIIMOTE_1;
196 	if(wpad->btns_h & WPAD_BUTTON_2)                      btns |= WIIMOTE_2;
197 	if(wpad->btns_h & WPAD_BUTTON_A)                      btns |= WIIMOTE_A;
198 	if(wpad->btns_h & WPAD_BUTTON_B)                      btns |= WIIMOTE_B;
199 	if(wpad->btns_h & WPAD_BUTTON_MINUS)                  btns |= WIIMOTE_MINUS;
200 	if(wpad->btns_h & WPAD_BUTTON_PLUS)                   btns |= WIIMOTE_PLUS;
201 	if(wpad->btns_h & WPAD_BUTTON_HOME)                   btns |= WIIMOTE_HOME;
202 	if(wpad->btns_h & WPAD_NUNCHUK_BUTTON_Z)              btns |= NUNCHUK_Z;
203 	if(wpad->btns_h & WPAD_NUNCHUK_BUTTON_C)              btns |= NUNCHUK_C;
204 	if(wpad->btns_h & WPAD_CLASSIC_BUTTON_A)              btns |= CC_A;
205 	if(wpad->btns_h & WPAD_CLASSIC_BUTTON_B)              btns |= CC_B;
206 	if(wpad->btns_h & WPAD_CLASSIC_BUTTON_Y)              btns |= CC_Y;
207 	if(wpad->btns_h & WPAD_CLASSIC_BUTTON_X)              btns |= CC_X;
208 	if(wpad->btns_h & WPAD_CLASSIC_BUTTON_MINUS)          btns |= CC_MINUS;
209 	if(wpad->btns_h & WPAD_CLASSIC_BUTTON_PLUS)           btns |= CC_PLUS;
210 	if(wpad->btns_h & WPAD_CLASSIC_BUTTON_HOME)           btns |= CC_HOME;
211 	if(wpad->btns_h & WPAD_CLASSIC_BUTTON_FULL_R)         btns |= CC_R;
212 	if(wpad->btns_h & WPAD_CLASSIC_BUTTON_FULL_L)         btns |= CC_L;
213 	if(wpad->btns_h & WPAD_CLASSIC_BUTTON_ZL)             btns |= CC_ZL;
214 	if(wpad->btns_h & WPAD_CLASSIC_BUTTON_ZR)             btns |= CC_ZR;
215 	if(gcbtns & PAD_BUTTON_X)                             btns |= GC_X;
216 	if(gcbtns & PAD_BUTTON_Y)                             btns |= GC_Y;
217 	if(gcbtns & PAD_BUTTON_A)                             btns |= GC_A;
218 	if(gcbtns & PAD_BUTTON_B)                             btns |= GC_B;
219 	if(gcbtns & PAD_TRIGGER_R)                            btns |= GC_R;
220 	if(gcbtns & PAD_TRIGGER_L)                            btns |= GC_L;
221 	if(gcbtns & PAD_TRIGGER_Z)                            btns |= GC_Z;
222 	if(gcbtns & PAD_BUTTON_START)                         btns |= GC_START;
223 
224 	// update buttons pressed (not held)
225 	buttonsPressed = btns & ~buttonsHeld;
226 	buttonsHeld = btns;
227 }
228 
getAllLogs()229 void getAllLogs()
230 {
231 	int i, j, k;
232 	for(i=0; i<2; i++)
233 	{
234 		logfile[i].buf = readFromLogFile(i);
235 		if(logfile[i].buf != NULL)
236 		{
237 			logfile[i].pos = malloc(++logfile[i].rows * sizeof(int));
238 			if(logfile[i].pos == NULL) return;
239 			memset(logfile[i].pos, 0, logfile[i].rows * sizeof(int));
240 
241 			for(k=0, j=0; j<logfile[i].buf->size; j++)
242 			{
243 				if(!k)
244 				{
245 					logfile[i].pos[logfile[i].rows - 1] = j;
246 					k = 1;
247 				}
248 				if(logfile[i].buf->ptr[j]=='\n')
249 				{
250 					int *_pos = malloc(++logfile[i].rows * sizeof(int));
251 					if(_pos == NULL) return;
252 					memcpy(_pos, logfile[i].pos, (logfile[i].rows - 1) * sizeof(int));
253 					_pos[logfile[i].rows - 1] = 0;
254 					free(logfile[i].pos);
255 					logfile[i].pos = NULL;
256 					logfile[i].pos = malloc(logfile[i].rows * sizeof(int));
257 					if(logfile[i].pos == NULL) return;
258 					memcpy(logfile[i].pos, _pos, logfile[i].rows * sizeof(int));
259 					free(_pos);
260 					_pos = NULL;
261 					logfile[i].buf->ptr[j] = 0;
262 					k = 0;
263 				}
264 				if(logfile[i].buf->ptr[j]=='\r') logfile[i].buf->ptr[j] = 0;
265 				if(logfile[i].rows>0xFFFFFFFE) break;
266 			}
267 			logfile[i].ready = 1;
268 		}
269 	}
270 }
271 
freeAllLogs()272 void freeAllLogs()
273 {
274 	int i;
275 	for(i=0; i<2; i++)
276 	{
277 		if(logfile[i].ready)
278 		{
279 			free(logfile[i].buf);
280 			logfile[i].buf = NULL;
281 			free(logfile[i].pos);
282 			logfile[i].pos = NULL;
283 		}
284 	}
285 }
286 
sortList()287 void sortList()
288 {
289 	int i, j;
290 	fileliststruct temp;
291 	if(dListTotal<2) return;
292 	for(j=dListTotal-1; j>0; j--)
293 	{
294 		for(i=0; i<j; i++)
295 		{
296 			if(stricmp(filelist[i].filename, filelist[i+1].filename)>0)
297 			{
298 				temp = filelist[i];
299 				filelist[i] = filelist[i+1];
300 				filelist[i+1] = temp;
301 			}
302 		}
303 	}
304 }
305 
findPaks(void)306 int findPaks(void)
307 {
308 	int i = 0;
309 	DIR* dp = NULL;
310 	struct dirent* ds;
311 
312 	dp = opendir(paksDir);
313 
314 	while((ds = readdir(dp)) != NULL)
315 	{
316 		if(packfile_supported(ds))
317 		{
318 			fileliststruct *copy = NULL;
319 			if(filelist == NULL) filelist = malloc(sizeof(fileliststruct));
320 			else
321 			{
322 				copy = malloc(i * sizeof(fileliststruct));
323 				memcpy(copy, filelist, i * sizeof(fileliststruct));
324 				free(filelist);
325 				filelist = malloc((i + 1) * sizeof(fileliststruct));
326 				memcpy(filelist, copy, i * sizeof(fileliststruct));
327 				free(copy); copy = NULL;
328 			}
329 			memset(&filelist[i], 0, sizeof(fileliststruct));
330 			strncpy(filelist[i].filename, ds->d_name, strlen(ds->d_name));
331 			i++;
332 		}
333 	}
334 	closedir(dp);
335 	return i;
336 }
337 
copyScreens(s_screen * Image)338 void copyScreens(s_screen *Image)
339 {
340 	// Copy Logo or Menu from Source to Scaler to give us a background
341 	// prior to printing to this s_screen.
342 	copyscreen_o(Scaler, Image, 0, 0);
343 }
344 
writeToScreen(s_screen * src)345 void writeToScreen(s_screen* src)
346 {
347 	copyscreen(Screen, src);
348 }
349 
drawScreens(s_screen * Image,int x,int y)350 void drawScreens(s_screen *Image, int x, int y)
351 {
352 	if(Image) copyscreen_o(Scaler, Image, x, y);
353 	writeToScreen(Scaler);
354 	video_copy_screen(Screen);
355 }
356 
printText(int x,int y,int col,int backcol,int fill,char * format,...)357 void printText(int x, int y, int col, int backcol, int fill, char *format, ...)
358 {
359 	int x1, y1, i;
360 	unsigned long data;
361 	unsigned short *line16 = NULL;
362 	unsigned long  *line32 = NULL;
363 	unsigned char *font;
364 	unsigned char ch = 0;
365 	char buf[128] = {""};
366 	va_list arglist;
367 		va_start(arglist, format);
368 		vsprintf(buf, format, arglist);
369 		va_end(arglist);
370 	if(factor > 1){ y += 5; }
371 
372 	for(i=0; i<sizeof(buf); i++)
373 	{
374 		ch = buf[i];
375 		// mapping
376 		if (ch<0x20) ch = 0;
377 		else if (ch<0x80) { ch -= 0x20; }
378 		else if (ch<0xa0) {	ch = 0;	}
379 		else ch -= 0x40;
380 		font = (u8 *)&hankaku_font10[ch*10];
381 		// draw
382 		if (bpp == 16) line16 = (unsigned short *)Scaler->data + x + y * Scaler->width;
383 		else           line32 = (unsigned long  *)Scaler->data + x + y * Scaler->width;
384 
385 		for (y1=0; y1<10; y1++)
386 		{
387 			data = *font++;
388 			for (x1=0; x1<5; x1++)
389 			{
390 				if (data & 1)
391 				{
392 					if (bpp == 16) *line16 = col;
393 				    else           *line32 = col;
394 				}
395 				else if (fill)
396 				{
397 					if (bpp == 16) *line16 = backcol;
398 					else           *line32 = backcol;
399 				}
400 
401 				if (bpp == 16) line16++;
402 				else           line32++;
403 
404 				data = data >> 1;
405 			}
406 			if (bpp == 16) line16 += Scaler->width-5;
407 			else           line32 += Scaler->width-5;
408 		}
409 		x+=5;
410 	}
411 }
412 
getPreview(char * filename)413 s_screen *getPreview(char *filename)
414 {
415 	int width = factor == 4 ? 640 : (factor == 2 ? 320 : 160);
416 	int height = factor == 4 ? 480 : (factor == 2 ? 240 : 120);
417 	s_screen *title = NULL;
418 	s_screen *scale = NULL;
419 
420 	// Grab current path and filename
421 	getBasePath(packfile, filename, 1);
422 
423 	// Create & Load & Scale Image
424 	return NULL; //if(!loadscreen("data/bgs/title.gif", packfile, realPal, PIXEL_8, &title)) return NULL;
425 	if((scale = allocscreen(width, height, title->pixelformat)) == NULL) return NULL;
426 
427 	scalescreen(scale, title);
428 
429 	// Free Images and Terminate FileCaching
430 	freescreen(&title);
431 
432 	// ScreenShots within Menu will be saved as "Menu"
433 	strncpy(packfile,"Menu.ext",128);
434 
435 	return scale;
436 }
437 
ControlMenu()438 int ControlMenu()
439 {
440 	int status = -1;
441 	int dListMaxDisplay = 17;
442 	//bothnewkeys = 0;
443 	//inputrefresh();
444 	refreshInput();
445 	switch(buttonsPressed)
446 	{
447 		case DIR_UP:
448 			dListScrollPosition--;
449 			if(dListScrollPosition < 0)
450 			{
451 				dListScrollPosition = 0;
452 				dListCurrentPosition--;
453 			}
454 			if(dListCurrentPosition < 0) dListCurrentPosition = 0;
455 			break;
456 
457 		case DIR_DOWN:
458 			dListCurrentPosition++;
459 			if(dListCurrentPosition > dListTotal - 1) dListCurrentPosition = dListTotal - 1;
460 			if(dListCurrentPosition > dListMaxDisplay)
461 	        {
462 		        if((dListCurrentPosition+dListScrollPosition) < dListTotal) dListScrollPosition++;
463 			    dListCurrentPosition = dListMaxDisplay;
464 			}
465 			break;
466 
467 		case DIR_LEFT:
468 			break;
469 
470 		case DIR_RIGHT:
471 			break;
472 
473 		case WIIMOTE_PLUS:
474 		case WIIMOTE_2:
475 		case CC_PLUS:
476 		case CC_A:
477 		case GC_START:
478 		case GC_A:
479 			// Start Engine!
480 			status = 1;
481 			break;
482 
483 		case WIIMOTE_HOME: // TODO? make a nice-looking Home menu
484 		case CC_HOME:
485 		case GC_Z:
486 			// Exit Engine!
487 			status = 2;
488 			break;
489 
490 		case WIIMOTE_1:
491 		case CC_X:
492 		case GC_X:
493 			status = 3;
494 			break;
495 
496 		default:
497 			// No Update Needed!
498 			status = 0;
499 			break;
500 	}
501 	return status;
502 }
503 
initMenu(int type)504 void initMenu(int type)
505 {
506 	// Read Logo or Menu from Array.
507 	if(type) {
508 
509 		Source = pngToScreen(isWide ? (void*) openbor_menu_480x272_png.data : (void*) openbor_menu_320x240_png.data);
510 
511 		// Depending on which mode we are in (WideScreen/FullScreen)
512 		// allocate proper size for final screen.
513 		Screen = allocscreen(Source->width, Source->height, PIXEL_32);
514 
515 		// Allocate Scaler.
516 		Scaler = allocscreen(Screen->width, Screen->height, PIXEL_32);
517 	}
518 
519 	control_init(2);
520 	apply_controls();
521 }
522 
termMenu()523 void termMenu()
524 {
525 	freescreen(&Source);
526 	Source = NULL;
527 	freescreen(&Scaler);
528 	Scaler = NULL;
529 	freescreen(&Screen);
530 	Screen = NULL;
531 	control_exit();
532 }
533 
drawMenu()534 void drawMenu()
535 {
536 	s_screen *Image = NULL;
537 	char listing[45] = {""};
538 	int list = 0;
539 	int shift = 0;
540 	int colors = 0;
541 	int clipX=0, clipY=0;
542 
543 	copyScreens(Source);
544 	if(dListTotal < 1) printText((isWide ? 30 : 8), (isWide ? 33 : 24), RED, 0, 0, "No Mods In Paks Folder!");
545 	for(list=0; list<dListTotal; list++)
546 	{
547 		if(list<18)
548 		{
549 			shift = 0;
550 			colors = GRAY;
551 			strncpy(listing, "", (isWide ? 44 : 28));
552 			if(strlen(filelist[list+dListScrollPosition].filename)-4 < (isWide ? 44 : 28))
553 				strncpy(listing, filelist[list+dListScrollPosition].filename, strlen(filelist[list+dListScrollPosition].filename)-4);
554 			if(strlen(filelist[list+dListScrollPosition].filename)-4 > (isWide ? 44 : 28))
555 				strncpy(listing, filelist[list+dListScrollPosition].filename, (isWide ? 44 : 28));
556 			if(list == dListCurrentPosition)
557 			{
558 				shift = 2;
559 				colors = RED;
560 				Image = NULL;
561 				if(Image)
562 				{
563 					clipX = factor * (isWide ? 286 : 155);
564 					clipY = factor * (isWide ? (factor == 4 ? (s16)32.5 : 32) : (factor == 4 ? (s16)21.5 : 21));
565 				}
566 				//else printText((isWide ? 288 : 157), (isWide ? 141 : 130), RED, 0, 0, "No Preview Available!");
567 			}
568 			printText((isWide ? 30 : 7) + shift, (isWide ? 33 : 22)+(11*list) , colors, 0, 0, "%s", listing);
569 		}
570 	}
571 
572 	printText((isWide ? 26 : 5), (isWide ? 11 : 4), WHITE, 0, 0, "OpenBoR %s", VERSION);
573 	printText((isWide ? 392 : 261),(isWide ? 11 : 4), WHITE, 0, 0, __DATE__);
574 	printText((isWide ? 23 : 4),(isWide ? 251 : 226), WHITE, 0, 0, "%s: Start Game", control_getkeyname(savedata.keys[0][SDID_ATTACK]));
575 	printText((isWide ? 150 : 84),(isWide ? 251 : 226), WHITE, 0, 0, "%s: BGM Player", control_getkeyname(savedata.keys[0][SDID_ATTACK2]));
576 	printText((isWide ? 270 : 164),(isWide ? 251 : 226), WHITE, 0, 0, "%s: View Logs", control_getkeyname(savedata.keys[0][SDID_JUMP]));
577 	printText((isWide ? 390 : 244),(isWide ? 251 : 226), WHITE, 0, 0, "%s: Quit Game", control_getkeyname(savedata.keys[0][SDID_SPECIAL]));
578    	printText((isWide ? 330 : 197),(isWide ? 170 : 155), BLACK, 0, 0, "www.LavaLit.com");
579 	printText((isWide ? 322 : 190),(isWide ? 180 : 165), BLACK, 0, 0, "www.SenileTeam.com");
580 
581 #ifdef SPK_SUPPORTED
582 	printText((isWide ? 324 : 192),(isWide ? 191 : 176), DARK_RED, 0, 0, "SecurePAK Edition");
583 #endif
584 
585 	drawScreens(Image, clipX, clipY);
586 
587 	if(Image)
588 	{
589 		freescreen(&Image);
590 		Image = NULL;
591 	}
592 }
593 
drawLogs()594 void drawLogs()
595 {
596 	int i=which_logfile, j, k, l, done=0;
597 	s_screen *Viewer = NULL;
598 
599 	bothkeys = bothnewkeys = 0;
600 	Viewer = allocscreen(Source->width, Source->height, Source->pixelformat);
601 	clearscreen(Viewer);
602 	bothkeys = bothnewkeys = 0;
603 
604 	while(!done)
605 	{
606 	    copyScreens(Viewer);
607 	    //inputrefresh();
608 	    refreshInput();
609 	    printText((isWide ? 410 : 250), 3, RED, 0, 0, "Quit : 1/B");
610 		if(buttonsPressed & (WIIMOTE_1|CC_B|GC_B)) done = 1;
611 
612 		if(logfile[i].ready)
613 		{
614 			printText(5, 3, RED, 0, 0, "OpenBorLog.txt");
615 			if(buttonsHeld & DIR_UP) --logfile[i].line;
616 	        if(buttonsHeld & DIR_DOWN) ++logfile[i].line;
617 			if(buttonsHeld & DIR_LEFT) logfile[i].line = 0;
618 			if(buttonsHeld & DIR_RIGHT) logfile[i].line = logfile[i].rows - (LOG_SCREEN_END - LOG_SCREEN_TOP);
619 			if(logfile[i].line > logfile[i].rows - (LOG_SCREEN_END - LOG_SCREEN_TOP) - 1) logfile[i].line = logfile[i].rows - (LOG_SCREEN_END - LOG_SCREEN_TOP) - 1;
620 			if(logfile[i].line < 0) logfile[i].line = 0;
621 			for(l=LOG_SCREEN_TOP, j=logfile[i].line; j<logfile[i].rows-1; l++, j++)
622 			{
623 				if(l<LOG_SCREEN_END)
624 				{
625 					char textpad[480] = {""};
626 					for(k=0; k<480; k++)
627 					{
628 						if(!logfile[i].buf->ptr[logfile[i].pos[j]+k]) break;
629 						textpad[k] = logfile[i].buf->ptr[logfile[i].pos[j]+k];
630 					}
631 					if(logfile[i].rows>0xFFFF)
632 						printText(5, l*10, WHITE, 0, 0, "0x%08x:  %s", j, textpad);
633 					else
634 						printText(5, l*10, WHITE, 0, 0, "0x%04x:  %s", j, textpad);
635 				}
636 				else break;
637 			}
638 		}
639 		else if(i == SCRIPT_LOG) printText(5, 3, RED, 0, 0, "Log NOT Found: ScriptLog.txt");
640 		else                     printText(5, 3, RED, 0, 0, "Log NOT Found: OpenBorLog.txt");
641 
642 	    drawScreens(NULL, 0, 0);
643 	}
644 	freescreen(&Viewer);
645 	Viewer = NULL;
646 	drawMenu();
647 }
648 
fillRect(s_screen * dest,Rect * rect,u32 color)649 void fillRect(s_screen *dest, Rect *rect, u32 color)
650 {
651 	u32 *data = (u32*)dest->data;
652 	int x, y, width=dest->width;
653 	for(y=rect->y; y<rect->y+rect->height; y++)
654 	{
655 		for(x=rect->x; x<rect->x+rect->width; x++)
656 		{
657 			data[x+y*width] = color;
658 		}
659 	}
660 }
661 
setVideoMode()662 void setVideoMode()
663 {
664 	if(isWide) // 480x272
665 	{
666 		videomodes.mode    = savedata.screen[videoMode][0];
667 		videomodes.filter  = savedata.screen[videoMode][1];
668 		videomodes.hRes    = 480;
669 		videomodes.vRes    = 272;
670 		videomodes.hScale  = (float)1.5;
671 		videomodes.vScale  = (float)1.13;
672 		videomodes.hShift  = 80;
673 		videomodes.vShift  = 20;
674 		videomodes.dOffset = 263;
675 		videomodes.pixel   = 4;
676 	}
677 	else // 320x240
678 	{
679 		videomodes.mode    = savedata.screen[videoMode][0];
680 		videomodes.filter  = savedata.screen[videoMode][1];
681 		videomodes.hRes    = 320;
682 		videomodes.vRes    = 240;
683 		videomodes.hScale  = 1;
684 		videomodes.vScale  = 1;
685 		videomodes.hShift  = 0;
686 		videomodes.vShift  = 0;
687 		videomodes.dOffset = 231;
688 		videomodes.pixel   = 4;
689 	}
690 
691 	video_set_mode(videomodes);
692 }
693 
Menu()694 void Menu()
695 {
696 	int done = 0;
697 	int ctrl = 0;
698 
699 	// Set video mode based on aspect ratio
700 	if(CONF_GetAspectRatio() == CONF_ASPECT_16_9) isWide = 1;
701 	setVideoMode();
702 	dListTotal = findPaks();
703 
704 	dListCurrentPosition = 0;
705 	if(dListTotal != 1)
706 	{
707 		sortList();
708 		getAllLogs();
709 		initMenu(1);
710 		drawMenu();
711 		pControl = ControlMenu;
712 
713 		while(!done)
714 		{
715 			ctrl = Control();
716 			switch(ctrl)
717 			{
718 				case 1:
719 				case 2:
720 					done = 1;
721 					break;
722 
723 				case 3:
724 					drawLogs();
725 					break;
726 
727 				case -1:
728 					drawMenu();
729 					break;
730 
731 				case -2:
732 					// BGM player isn't supported
733 					break;
734 			}
735 		}
736 		freeAllLogs();
737 		termMenu();
738 		if(ctrl == 2)
739 		{
740 			if (filelist)
741 			{
742 				free(filelist);
743 				filelist = NULL;
744 			}
745 			borExit(0);
746 		}
747 	}
748 	getBasePath(packfile, filelist[dListCurrentPosition+dListScrollPosition].filename, 1);
749 	free(filelist);
750 }
751 
752