mirror of
https://github.com/dborth/vbagx.git
synced 2025-07-09 15:05:49 +02:00

* "Match Wii Game" controls option! Games that have a Wii equivalent can be played using the controls for that Wii game. For example all Zelda games can be played with Twilight Princess controls. See the Instructions section below for important details. * Rotation/Tilt sensor games all work * Solar sensors (Boktai 1/2/3) * Rumble (except for games that rely on Gameboy Player) * Keyboard * PAL support, finally! * New scaling options, choose how much stretching you want * Colourised games now partially work but still have distortion * "Corvette" no longer has a screwed up palette (but still crashes) * Triggers net reconnection on SMB failure * Source code refactored, and project file added * Instructions section added to this readme file
1001 lines
22 KiB
C++
1001 lines
22 KiB
C++
/****************************************************************************
|
|
* Visual Boy Advance GX
|
|
*
|
|
* Tantric September 2008
|
|
*
|
|
* menudraw.cpp
|
|
*
|
|
* Menu drawing routines
|
|
***************************************************************************/
|
|
|
|
#include <gccore.h>
|
|
#include <ogcsys.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
#include <wiiuse/wpad.h>
|
|
#include <ft2build.h>
|
|
#include <zlib.h>
|
|
#include FT_FREETYPE_H
|
|
|
|
#include "video.h"
|
|
#include "menudraw.h"
|
|
#include "vba.h"
|
|
#include "filesel.h"
|
|
#include "dvd.h"
|
|
#include "input.h"
|
|
#include "networkop.h"
|
|
#include "wiiusbsupport.h"
|
|
#include "filelist.h"
|
|
|
|
/*** Globals ***/
|
|
static FT_Library ftlibrary;
|
|
static FT_Face face;
|
|
static FT_GlyphSlot slot;
|
|
static unsigned int fonthi, fontlo;
|
|
|
|
extern int screenheight;
|
|
extern unsigned int *xfb[2];
|
|
extern int whichfb;
|
|
|
|
unsigned int getcolour (u8 r1, u8 g1, u8 b1);
|
|
void DrawLineFast( int startx, int endx, int y, u8 r, u8 g, u8 b );
|
|
u32 getrgb( u32 ycbr, u32 low );
|
|
|
|
/****************************************************************************
|
|
* Initialisation of libfreetype
|
|
***************************************************************************/
|
|
int
|
|
FT_Init ()
|
|
{
|
|
|
|
int err;
|
|
|
|
err = FT_Init_FreeType (&ftlibrary);
|
|
if (err)
|
|
return 1;
|
|
|
|
err =
|
|
FT_New_Memory_Face (ftlibrary, (FT_Byte *) font_ttf, font_ttf_size, 0, &face);
|
|
if (err)
|
|
return 1;
|
|
|
|
setfontsize (16);
|
|
setfontcolour (0xff, 0xff, 0xff);
|
|
|
|
slot = face->glyph;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/****************************************************************************
|
|
* setfontsize
|
|
*
|
|
* Set the screen font size in pixels
|
|
***************************************************************************/
|
|
void
|
|
setfontsize (int pixelsize)
|
|
{
|
|
int err;
|
|
|
|
err = FT_Set_Pixel_Sizes (face, 0, pixelsize);
|
|
|
|
if (err)
|
|
printf ("Error setting pixel sizes!");
|
|
}
|
|
|
|
/****************************************************************************
|
|
* DrawCharacter
|
|
* Draws a single character on the screen
|
|
***************************************************************************/
|
|
static void
|
|
DrawCharacter (FT_Bitmap * bmp, FT_Int x, FT_Int y)
|
|
{
|
|
FT_Int i, j, p, q;
|
|
FT_Int x_max = x + bmp->width;
|
|
FT_Int y_max = y + bmp->rows;
|
|
int spos;
|
|
unsigned int pixel;
|
|
int c;
|
|
|
|
for (i = x, p = 0; i < x_max; i++, p++)
|
|
{
|
|
for (j = y, q = 0; j < y_max; j++, q++)
|
|
{
|
|
if (i < 0 || j < 0 || i >= 640 || j >= screenheight)
|
|
continue;
|
|
|
|
/*** Convert pixel position to GC int sizes ***/
|
|
spos = (j * 320) + (i >> 1);
|
|
|
|
pixel = xfb[whichfb][spos];
|
|
c = bmp->buffer[q * bmp->width + p];
|
|
|
|
/*** Cool Anti-Aliasing doesn't work too well at hires on GC ***/
|
|
if (c > 128)
|
|
{
|
|
if (i & 1)
|
|
pixel = (pixel & 0xffff0000) | fontlo;
|
|
else
|
|
pixel = ((pixel & 0xffff) | fonthi);
|
|
|
|
xfb[whichfb][spos] = pixel;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
* DrawText
|
|
*
|
|
* Place the font bitmap on the screen
|
|
***************************************************************************/
|
|
void
|
|
DrawText (int x, int y, const char *text)
|
|
{
|
|
int px, n;
|
|
int i;
|
|
int err;
|
|
int value, count;
|
|
|
|
n = strlen (text);
|
|
if (n == 0)
|
|
return;
|
|
|
|
setfontcolour (0x00, 0x00, 0x00);
|
|
|
|
/*** x == -1, auto centre ***/
|
|
if (x == -1)
|
|
{
|
|
value = 0;
|
|
px = 0;
|
|
}
|
|
else
|
|
{
|
|
value = 1;
|
|
px = x;
|
|
}
|
|
|
|
for (count = value; count < 2; count++)
|
|
{
|
|
/*** Draw the string ***/
|
|
for (i = 0; i < n; i++)
|
|
{
|
|
err = FT_Load_Char (face, text[i], FT_LOAD_RENDER);
|
|
|
|
if (err)
|
|
{
|
|
printf ("Error %c %d\n", text[i], err);
|
|
continue; /*** Skip unprintable characters ***/
|
|
}
|
|
|
|
if (count)
|
|
DrawCharacter (&slot->bitmap, px + slot->bitmap_left,
|
|
y - slot->bitmap_top);
|
|
|
|
px += slot->advance.x >> 6;
|
|
}
|
|
|
|
px = (640 - px) >> 1;
|
|
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
* setfontcolour
|
|
*
|
|
* Uses RGB triple values.
|
|
***************************************************************************/
|
|
void
|
|
setfontcolour (u8 r, u8 g, u8 b)
|
|
{
|
|
u32 fontcolour;
|
|
|
|
fontcolour = getcolour (r, g, b);
|
|
fonthi = fontcolour & 0xffff0000;
|
|
fontlo = fontcolour & 0xffff;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Draws Version # on screen
|
|
***************************************************************************/
|
|
|
|
void DrawVersion()
|
|
{
|
|
setfontsize (12);
|
|
setfontcolour (0,0,0);
|
|
char versionText[50];
|
|
sprintf(versionText, "%s %s", APPNAME, APPVERSION);
|
|
DrawText (115, screenheight - 34, versionText);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Display credits, legal copyright and licence
|
|
*
|
|
* THIS MUST NOT BE REMOVED IN ANY DERIVATIVE WORK.
|
|
***************************************************************************/
|
|
void
|
|
Credits ()
|
|
{
|
|
clearscreen ();
|
|
|
|
setfontcolour (0x00, 0x00, 0x00);
|
|
|
|
setfontsize (26);
|
|
DrawText (-1, 150, "Credits");
|
|
|
|
int ypos = 110;
|
|
|
|
if (screenheight == 480)
|
|
ypos += 52;
|
|
else
|
|
ypos += 32;
|
|
|
|
setfontsize (14);
|
|
|
|
DrawText (-1, ypos += 18, "Official Site: http://code.google.com/p/vba-wii/");
|
|
|
|
DrawText (90, ypos += 36, "Visual Boy Advance GX");
|
|
DrawText (380, ypos, "Tantric, Carl Kenner");
|
|
DrawText (90, ypos += 18, "GameCube/Wii Port Improvements");
|
|
DrawText (380, ypos, "emukidid");
|
|
DrawText (90, ypos += 18, "Original GameCube Port");
|
|
DrawText (380, ypos, "SoftDev");
|
|
DrawText (90, ypos += 18, "Visual Boy Advance - M");
|
|
DrawText (380, ypos, "VBA-M Team");
|
|
DrawText (90, ypos += 18, "Visual Boy Advance 1.7.2");
|
|
DrawText (380, ypos, "Forgotten");
|
|
DrawText (90, ypos += 18, "libogc");
|
|
DrawText (380, ypos, "Shagkur & wintermute");
|
|
DrawText (90, ypos += 18, "Testing");
|
|
DrawText (380, ypos, "tehskeen users");
|
|
|
|
DrawText (-1, ypos += 36, "And many others who have contributed over the years!");
|
|
|
|
setfontsize (12);
|
|
DrawText (-1, ypos += 30, "This software is open source and may be copied,");
|
|
DrawText (-1, ypos += 15, "distributed, or modified under the terms of");
|
|
DrawText (-1, ypos += 15, "the GNU General Public License (GPL) Version 2.");
|
|
|
|
DrawVersion();
|
|
updateRumbleFrame();
|
|
showscreen ();
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
* getcolour
|
|
*
|
|
* Simply converts RGB to Y1CbY2Cr format
|
|
*
|
|
* I got this from a pastebin, so thanks to whoever originally wrote it!
|
|
***************************************************************************/
|
|
|
|
unsigned int
|
|
getcolour (u8 r1, u8 g1, u8 b1)
|
|
{
|
|
int y1, cb1, cr1, y2, cb2, cr2, cb, cr;
|
|
u8 r2, g2, b2;
|
|
|
|
r2 = r1;
|
|
g2 = g1;
|
|
b2 = b1;
|
|
|
|
y1 = (299 * r1 + 587 * g1 + 114 * b1) / 1000;
|
|
cb1 = (-16874 * r1 - 33126 * g1 + 50000 * b1 + 12800000) / 100000;
|
|
cr1 = (50000 * r1 - 41869 * g1 - 8131 * b1 + 12800000) / 100000;
|
|
|
|
y2 = (299 * r2 + 587 * g2 + 114 * b2) / 1000;
|
|
cb2 = (-16874 * r2 - 33126 * g2 + 50000 * b2 + 12800000) / 100000;
|
|
cr2 = (50000 * r2 - 41869 * g2 - 8131 * b2 + 12800000) / 100000;
|
|
|
|
cb = (cb1 + cb2) >> 1;
|
|
cr = (cr1 + cr2) >> 1;
|
|
|
|
return ((y1 << 24) | (cb << 16) | (y2 << 8) | cr);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Wait for user to press A
|
|
***************************************************************************/
|
|
void
|
|
WaitButtonA ()
|
|
{
|
|
#ifdef HW_RVL
|
|
while ( (PAD_ButtonsDown (0) & PAD_BUTTON_A)
|
|
|| (WPAD_ButtonsDown(0) & (WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A))
|
|
|| (DownUsbKeys[KB_ENTER])) {
|
|
updateRumbleFrame();
|
|
VIDEO_WaitVSync();
|
|
}
|
|
while (!(PAD_ButtonsDown (0) & PAD_BUTTON_A)
|
|
&& !(WPAD_ButtonsDown(0) & (WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A))
|
|
&& !(DownUsbKeys[KB_ENTER])) {
|
|
updateRumbleFrame();
|
|
VIDEO_WaitVSync();
|
|
}
|
|
#else
|
|
while ( PAD_ButtonsDown (0) & PAD_BUTTON_A ) {
|
|
updateRumbleFrame();
|
|
VIDEO_WaitVSync();
|
|
}
|
|
while (!(PAD_ButtonsDown (0) & PAD_BUTTON_A) ) {
|
|
updateRumbleFrame();
|
|
VIDEO_WaitVSync();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Wait for user to press A or B. Returns 0 = B; 1 = A
|
|
***************************************************************************/
|
|
|
|
int
|
|
WaitButtonAB ()
|
|
{
|
|
#ifdef HW_RVL
|
|
u32 gc_btns, wm_btns;
|
|
|
|
while ( (PAD_ButtonsDown (0) & (PAD_BUTTON_A | PAD_BUTTON_B))
|
|
|| (WPAD_ButtonsDown(0) & (WPAD_BUTTON_A | WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_A | WPAD_CLASSIC_BUTTON_B))
|
|
|| (DownUsbKeys[KB_ENTER]) || (DownUsbKeys[KB_ESC])
|
|
) {
|
|
updateRumbleFrame();
|
|
VIDEO_WaitVSync();
|
|
}
|
|
|
|
while ( TRUE )
|
|
{
|
|
gc_btns = PAD_ButtonsDown (0);
|
|
wm_btns = WPAD_ButtonsDown (0);
|
|
if ( (gc_btns & PAD_BUTTON_A) || (wm_btns & (WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A))
|
|
|| (DownUsbKeys[KB_ENTER])
|
|
)
|
|
return 1;
|
|
else if ( (gc_btns & PAD_BUTTON_B) || (wm_btns & (WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B))
|
|
|| (DownUsbKeys[KB_ESC])
|
|
)
|
|
return 0;
|
|
}
|
|
#else
|
|
u32 gc_btns;
|
|
|
|
while ( (PAD_ButtonsDown (0) & (PAD_BUTTON_A | PAD_BUTTON_B)) ) {
|
|
updateRumbleFrame();
|
|
VIDEO_WaitVSync();
|
|
}
|
|
|
|
while ( TRUE )
|
|
{
|
|
gc_btns = PAD_ButtonsDown (0);
|
|
if ( gc_btns & PAD_BUTTON_A )
|
|
return 1;
|
|
else if ( gc_btns & PAD_BUTTON_B )
|
|
return 0;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Show a prompt
|
|
***************************************************************************/
|
|
void
|
|
WaitPrompt (const char *msg)
|
|
{
|
|
int ypos = (screenheight - 64) >> 1;
|
|
|
|
if (screenheight == 480)
|
|
ypos += 52;
|
|
else
|
|
ypos += 32;
|
|
|
|
clearscreen ();
|
|
setfontsize(16);
|
|
DrawText (-1, ypos, msg);
|
|
ypos += 30;
|
|
DrawText (-1, ypos, "Press A to continue");
|
|
|
|
DrawVersion();
|
|
showscreen ();
|
|
WaitButtonA ();
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Show a prompt with choice of two options. Returns 1 if A button was pressed
|
|
and 0 if B button was pressed.
|
|
***************************************************************************/
|
|
int
|
|
WaitPromptChoice (const char *msg, const char *bmsg, const char *amsg)
|
|
{
|
|
int ypos = (screenheight - 64) >> 1;
|
|
|
|
if (screenheight == 480)
|
|
ypos += 37;
|
|
else
|
|
ypos += 17;
|
|
|
|
clearscreen ();
|
|
setfontsize(20);
|
|
DrawText (-1, ypos, msg);
|
|
ypos += 60;
|
|
char txt[80];
|
|
sprintf (txt, "B = %s : A = %s", bmsg, amsg);
|
|
DrawText (-1, ypos, txt);
|
|
|
|
DrawVersion();
|
|
showscreen ();
|
|
return WaitButtonAB ();
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Show an action in progress
|
|
***************************************************************************/
|
|
void
|
|
ShowAction (const char *msg)
|
|
{
|
|
int ypos = (screenheight - 30) >> 1;
|
|
|
|
if (screenheight == 480)
|
|
ypos += 52;
|
|
else
|
|
ypos += 32;
|
|
|
|
clearscreen ();
|
|
setfontsize(20);
|
|
DrawText (-1, ypos, msg);
|
|
|
|
DrawVersion();
|
|
showscreen ();
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Generic Menu Routines
|
|
***************************************************************************/
|
|
void
|
|
DrawMenu (char items[][50], const char *title, int maxitems, int selected, int fontsize, int x)
|
|
{
|
|
int i, w = 0;
|
|
int ypos = 0;
|
|
int n = 1;
|
|
int line_height;
|
|
|
|
ypos = 105;
|
|
|
|
if (screenheight == 480)
|
|
ypos += 52;
|
|
else
|
|
ypos += 42;
|
|
|
|
clearscreen ();
|
|
|
|
setfontcolour (0, 0, 0);
|
|
|
|
if (title != NULL)
|
|
{
|
|
setfontsize (26);
|
|
DrawText (-1, 150, title);
|
|
}
|
|
|
|
// Draw menu items
|
|
|
|
setfontsize (fontsize); // set font size
|
|
|
|
line_height = (fontsize + 8);
|
|
|
|
for (i = 0; i < maxitems; i++)
|
|
{
|
|
if(strlen(items[i]) > 0)
|
|
{
|
|
if ( items[i] == NULL )
|
|
ypos -= line_height;
|
|
else if (i == selected)
|
|
{
|
|
for( w = 0; w < line_height; w++ )
|
|
DrawLineFast( 77, 575, n * line_height + (ypos-line_height+6) + w, 0x00, 0x00, 0x00 );
|
|
|
|
//setfontcolour (0xff, 0xff, 0xff);
|
|
DrawText (x, n * line_height + ypos, items[i]);
|
|
//setfontcolour (0x00, 0x00, 0x00);
|
|
}
|
|
else
|
|
{
|
|
DrawText (x, n * line_height + ypos, items[i]);
|
|
}
|
|
n++;
|
|
}
|
|
}
|
|
|
|
DrawVersion();
|
|
showscreen ();
|
|
}
|
|
|
|
/****************************************************************************
|
|
* FindMenuItem
|
|
*
|
|
* Help function to find the next visible menu item on the list
|
|
* Supports menu wrap-around
|
|
***************************************************************************/
|
|
|
|
int FindMenuItem(char items[][50], int maxitems, int currentItem, int direction)
|
|
{
|
|
int nextItem = currentItem + direction;
|
|
|
|
if(nextItem < 0)
|
|
nextItem = maxitems-1;
|
|
else if(nextItem >= maxitems)
|
|
nextItem = 0;
|
|
|
|
if(strlen(items[nextItem]) > 0)
|
|
return nextItem;
|
|
else
|
|
return FindMenuItem(&items[0], maxitems, nextItem, direction);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* RunMenu
|
|
*
|
|
* Call this with the menu array defined in menu.cpp
|
|
* It's here to keep all the font / interface stuff together.
|
|
***************************************************************************/
|
|
int menu = 0;
|
|
|
|
int
|
|
RunMenu (char items[][50], int maxitems, const char *title, int fontsize, int x)
|
|
{
|
|
int redraw = 1;
|
|
int quit = 0;
|
|
int ret = 0;
|
|
|
|
u32 p = 0;
|
|
u32 wp = 0;
|
|
signed char gc_ay = 0;
|
|
signed char wm_ay = 0;
|
|
|
|
while (quit == 0)
|
|
{
|
|
#ifdef HW_RVL
|
|
if(updateFound)
|
|
{
|
|
updateFound = WaitPromptChoice("An update is available!", "Update later", "Update now");
|
|
if(updateFound)
|
|
if(DownloadUpdate())
|
|
ExitToLoader();
|
|
}
|
|
|
|
if(ShutdownRequested)
|
|
ShutdownWii();
|
|
#endif
|
|
|
|
if (redraw)
|
|
{
|
|
DrawMenu (&items[0], title, maxitems, menu, fontsize);
|
|
redraw = 0;
|
|
}
|
|
|
|
gc_ay = PAD_StickY (0);
|
|
p = PAD_ButtonsDown (0);
|
|
#ifdef HW_RVL
|
|
wm_ay = WPAD_Stick (0,0,1);
|
|
wp = WPAD_ButtonsDown (0);
|
|
#endif
|
|
|
|
updateRumbleFrame();
|
|
VIDEO_WaitVSync(); // slow things down a bit so we don't overread the pads
|
|
|
|
/*** Look for up ***/
|
|
if ( (p & PAD_BUTTON_UP) || (wp & (WPAD_BUTTON_UP | WPAD_CLASSIC_BUTTON_UP)) ||
|
|
(gc_ay > PADCAL) || (wm_ay > PADCAL)
|
|
#ifdef HW_RVL
|
|
|| DownUsbKeys[KB_UP]
|
|
#endif
|
|
)
|
|
{
|
|
redraw = 1;
|
|
menu = FindMenuItem(&items[0], maxitems, menu, -1);
|
|
}
|
|
|
|
/*** Look for down ***/
|
|
if ( (p & PAD_BUTTON_DOWN) || (wp & (WPAD_BUTTON_DOWN | WPAD_CLASSIC_BUTTON_DOWN)) ||
|
|
(gc_ay < -PADCAL) || (wm_ay < -PADCAL)
|
|
#ifdef HW_RVL
|
|
|| DownUsbKeys[KB_DOWN]
|
|
#endif
|
|
)
|
|
{
|
|
redraw = 1;
|
|
menu = FindMenuItem(&items[0], maxitems, menu, +1);
|
|
}
|
|
|
|
if ((p & PAD_BUTTON_A) || (wp & (WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A))
|
|
#ifdef HW_RVL
|
|
|| DownUsbKeys[KB_ENTER]
|
|
#endif
|
|
)
|
|
{
|
|
quit = 1;
|
|
ret = menu;
|
|
}
|
|
|
|
if ((p & PAD_BUTTON_B) || (wp & (WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B))
|
|
#ifdef HW_RVL
|
|
|| DownUsbKeys[KB_ESC]
|
|
#endif
|
|
)
|
|
{
|
|
quit = -1;
|
|
ret = -1;
|
|
}
|
|
}
|
|
|
|
/*** Wait for B button to be released before proceeding ***/
|
|
while ( (PAD_ButtonsDown(0) & PAD_BUTTON_B)
|
|
#ifdef HW_RVL
|
|
|| (WPAD_ButtonsDown(0) & (WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B))
|
|
|| DownUsbKeys[KB_ESC]
|
|
#endif
|
|
)
|
|
{
|
|
ret = -1;
|
|
updateRumbleFrame();
|
|
VIDEO_WaitVSync();
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Showfile screen
|
|
*
|
|
* Display the file selection to the user
|
|
***************************************************************************/
|
|
|
|
void
|
|
ShowFiles (BROWSERENTRY * browserList, int maxfiles, int offset, int selection)
|
|
{
|
|
int i, j;
|
|
char text[MAXPATHLEN];
|
|
int ypos;
|
|
int w;
|
|
|
|
clearscreen ();
|
|
|
|
setfontsize (26);
|
|
DrawText (-1, 150, "Choose Game");
|
|
|
|
setfontsize(18);
|
|
|
|
ypos = (screenheight - ((PAGESIZE - 1) * 20)) >> 1;
|
|
|
|
if (screenheight == 480)
|
|
ypos += 24;
|
|
else
|
|
ypos += 10;
|
|
|
|
ypos += 30;
|
|
|
|
j = 0;
|
|
for (i = offset; i < (offset + PAGESIZE) && (i < maxfiles); i++)
|
|
{
|
|
if (browserList[i].isdir) // if a dir
|
|
{
|
|
strcpy (text, "[");
|
|
strcat (text, browserList[i].displayname);
|
|
strcat (text, "]");
|
|
}
|
|
else
|
|
{
|
|
sprintf(text, browserList[i].displayname);
|
|
}
|
|
if (j == (selection - offset))
|
|
{
|
|
/*** Highlighted text entry ***/
|
|
for ( w = 0; w < 20; w++ )
|
|
DrawLineFast( 77, 575, ( j * 20 ) + (ypos-16) + w, 0x00, 0x00, 0x00 );
|
|
DrawText (100, (j * 20) + ypos, text);
|
|
}
|
|
else
|
|
{
|
|
/*** Normal entry ***/
|
|
DrawText (100, (j * 20) + ypos, text);
|
|
}
|
|
j++;
|
|
}
|
|
|
|
DrawVersion();
|
|
showscreen ();
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Cheats screen
|
|
*
|
|
* Displays a scrollable list of cheats to the user
|
|
***************************************************************************/
|
|
|
|
void
|
|
ShowCheats (char items[][50], char itemvalues[][50], int maxitems, int offset, int selection)
|
|
{
|
|
int i, j = 0;
|
|
int ypos;
|
|
int w;
|
|
|
|
clearscreen ();
|
|
|
|
setfontsize (26);
|
|
DrawText (-1, 150, "Cheats");
|
|
|
|
setfontsize(18);
|
|
|
|
ypos = (screenheight - ((PAGESIZE - 1) * 20)) >> 1;
|
|
|
|
if (screenheight == 480)
|
|
ypos += 24;
|
|
else
|
|
ypos += 10;
|
|
|
|
for (i = offset; i < (offset + PAGESIZE) && (i < maxitems); i++)
|
|
{
|
|
if (i == selection)
|
|
{
|
|
/*** Highlighted text entry ***/
|
|
for ( w = 0; w < 20; w++ )
|
|
DrawLineFast( 30, 610, ( j * 20 ) + (ypos-16) + w, 0x80, 0x80, 0x80 );
|
|
|
|
DrawText (150, (j * 20) + ypos, items[i]);
|
|
DrawText (400, (j * 20) + ypos, itemvalues[i]);
|
|
}
|
|
else
|
|
{
|
|
/*** Normal entry ***/
|
|
DrawText (150, (j * 20) + ypos, items[i]);
|
|
DrawText (400, (j * 20) + ypos, itemvalues[i]);
|
|
}
|
|
j++;
|
|
}
|
|
|
|
DrawVersion();
|
|
showscreen ();
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
* DrawLine
|
|
*
|
|
* Quick'n'Dirty Bresenham line drawing routine.
|
|
***************************************************************************/
|
|
#define SIGN(x) ((x<0)?-1:((x>0)?1:0))
|
|
|
|
void
|
|
DrawLine (int x1, int y1, int x2, int y2, u8 r, u8 g, u8 b)
|
|
{
|
|
u32 colour, pixel;
|
|
u32 colourhi, colourlo;
|
|
int i, dx, dy, sdx, sdy, dxabs, dyabs, x, y, px, py;
|
|
int sp;
|
|
|
|
colour = getcolour (r, g, b);
|
|
colourhi = colour & 0xffff0000;
|
|
colourlo = colour & 0xffff;
|
|
|
|
dx = x2 - x1; /*** Horizontal distance ***/
|
|
dy = y2 - y1; /*** Vertical distance ***/
|
|
|
|
dxabs = abs (dx);
|
|
dyabs = abs (dy);
|
|
sdx = SIGN (dx);
|
|
sdy = SIGN (dy);
|
|
x = dyabs >> 1;
|
|
y = dxabs >> 1;
|
|
px = x1;
|
|
py = y1;
|
|
|
|
sp = (py * 320) + (px >> 1);
|
|
pixel = xfb[whichfb][sp];
|
|
/*** Plot this pixel ***/
|
|
if (px & 1)
|
|
xfb[whichfb][sp] = (pixel & 0xffff0000) | colourlo;
|
|
else
|
|
xfb[whichfb][sp] = (pixel & 0xffff) | colourhi;
|
|
|
|
if (dxabs >= dyabs) /*** Mostly horizontal ***/
|
|
{
|
|
for (i = 0; i < dxabs; i++)
|
|
{
|
|
y += dyabs;
|
|
if (y >= dxabs)
|
|
{
|
|
y -= dxabs;
|
|
py += sdy;
|
|
}
|
|
|
|
px += sdx;
|
|
|
|
sp = (py * 320) + (px >> 1);
|
|
pixel = xfb[whichfb][sp];
|
|
|
|
if (px & 1)
|
|
xfb[whichfb][sp] = (pixel & 0xffff0000) | colourlo;
|
|
else
|
|
xfb[whichfb][sp] = (pixel & 0xffff) | colourhi;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < dyabs; i++)
|
|
{
|
|
x += dxabs;
|
|
if (x >= dyabs)
|
|
{
|
|
x -= dyabs;
|
|
px += sdx;
|
|
}
|
|
|
|
py += sdy;
|
|
|
|
sp = (py * 320) + (px >> 1);
|
|
pixel = xfb[whichfb][sp];
|
|
|
|
if (px & 1)
|
|
xfb[whichfb][sp] = (pixel & 0xffff0000) | colourlo;
|
|
else
|
|
xfb[whichfb][sp] = (pixel & 0xffff) | colourhi;
|
|
}
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Progress Bar
|
|
*
|
|
* Show the user what's happening
|
|
***************************************************************************/
|
|
void
|
|
ShowProgress (const char *msg, int done, int total)
|
|
{
|
|
if(total <= 0) // division by 0 is bad!
|
|
return;
|
|
else if(done > total) // this shouldn't happen
|
|
done = total;
|
|
else if(total < (256*1024)) // don't bother showing progress for small files
|
|
return;
|
|
|
|
int xpos, ypos;
|
|
int i;
|
|
|
|
if(done < 5000) // we just started!
|
|
{
|
|
ypos = (screenheight - 30) >> 1;
|
|
|
|
if (screenheight == 480)
|
|
ypos += 52;
|
|
else
|
|
ypos += 32;
|
|
|
|
clearscreen ();
|
|
setfontsize(20);
|
|
DrawText (-1, ypos, msg);
|
|
|
|
/*** Draw a white outline box ***/
|
|
for (i = 380; i < 401; i++)
|
|
DrawLine (100, i, 540, i, 0xff, 0xff, 0xff);
|
|
}
|
|
|
|
/*** Show progess ***/
|
|
xpos = (int) (((float) done / (float) total) * 438);
|
|
|
|
for (i = 381; i < 400; i++)
|
|
DrawLine (101, i, 101 + xpos, i, 0x00, 0x00, 0x80);
|
|
|
|
if(done < 5000) // we just started!
|
|
{
|
|
DrawVersion();
|
|
showscreen ();
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
* DrawPolygon
|
|
***************************************************************************/
|
|
void
|
|
DrawPolygon (int vertices, int varray[], u8 r, u8 g, u8 b)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < vertices - 1; i++)
|
|
{
|
|
DrawLine (varray[(i << 1)], varray[(i << 1) + 1], varray[(i << 1) + 2],
|
|
varray[(i << 1) + 3], r, g, b);
|
|
}
|
|
|
|
DrawLine (varray[0], varray[1], varray[(vertices << 1) - 2],
|
|
varray[(vertices << 1) - 1], r, g, b);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Draw Line Fast
|
|
*
|
|
* This routine requires that start and endx are 32bit aligned.
|
|
* It tries to perform a semi-transparency over the existing image.
|
|
***************************************************************************/
|
|
|
|
#define SRCWEIGHT 0.7f
|
|
#define DSTWEIGHT (1.0f - SRCWEIGHT)
|
|
|
|
static inline u8 c_adjust( u8 c , float weight )
|
|
{
|
|
return (u8)((float)c * weight);
|
|
}
|
|
|
|
void DrawLineFast( int startx, int endx, int y, u8 r, u8 g, u8 b )
|
|
{
|
|
int width;
|
|
u32 offset;
|
|
int i;
|
|
u32 colour, clo, chi;
|
|
u32 lo,hi;
|
|
u8 *s, *d;
|
|
|
|
//colour = getcolour(r, g, b);
|
|
colour = ( r << 16 | g << 8 | b );
|
|
d = (u8 *)&colour;
|
|
d[1] = c_adjust(d[1], DSTWEIGHT);
|
|
d[2] = c_adjust(d[2], DSTWEIGHT);
|
|
d[3] = c_adjust(d[3], DSTWEIGHT);
|
|
|
|
width = ( endx - startx ) >> 1;
|
|
offset = ( y << 8 ) + ( y << 6 ) + ( startx >> 1 );
|
|
|
|
for ( i = 0; i < width; i++ )
|
|
{
|
|
lo = getrgb(xfb[whichfb][offset], 0);
|
|
hi = getrgb(xfb[whichfb][offset], 1);
|
|
|
|
s = (u8 *)&hi;
|
|
s[1] = ( ( c_adjust(s[1],SRCWEIGHT) ) + d[1] );
|
|
s[2] = ( ( c_adjust(s[2],SRCWEIGHT) ) + d[2] );
|
|
s[3] = ( ( c_adjust(s[3],SRCWEIGHT) ) + d[3] );
|
|
|
|
s = (u8 *)&lo;
|
|
s[1] = ( ( c_adjust(s[1],SRCWEIGHT) ) + d[1] );
|
|
s[2] = ( ( c_adjust(s[2],SRCWEIGHT) ) + d[2] );
|
|
s[3] = ( ( c_adjust(s[3],SRCWEIGHT) ) + d[3] );
|
|
|
|
clo = getcolour( s[1], s[2], s[3] );
|
|
s = (u8 *)&hi;
|
|
chi = getcolour( s[1], s[2], s[3] );
|
|
|
|
xfb[whichfb][offset++] = (chi & 0xffff0000 ) | ( clo & 0xffff) ;
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Ok, I'm useless with Y1CBY2CR colour.
|
|
* So convert back to RGB so I can work with it -;)
|
|
***************************************************************************/
|
|
u32 getrgb( u32 ycbr, u32 low )
|
|
{
|
|
u8 r,g,b;
|
|
u32 y;
|
|
s8 cb,cr;
|
|
|
|
if ( low )
|
|
y = ( ycbr & 0xff00 ) >> 8;
|
|
else
|
|
y = ( ycbr & 0xff000000 ) >> 24;
|
|
|
|
cr = ycbr & 0xff;
|
|
cb = ( ycbr & 0xff0000 ) >> 16;
|
|
|
|
cr -= 128;
|
|
cb -= 128;
|
|
|
|
r = (u8)((float)y + 1.371 * (float)cr);
|
|
g = (u8)((float)y - 0.698 * (float)cr - 0.336 * (float)cb);
|
|
b = (u8)((float)y + 1.732 * (float)cb);
|
|
|
|
return (u32)( r << 16 | g << 8 | b );
|
|
|
|
}
|