snes9xgx/source/ngc/menudraw.cpp
2009-02-07 03:01:10 +00:00

1128 lines
26 KiB
C++

/****************************************************************************
* Snes9x 1.51 Nintendo Wii/Gamecube Port
*
* softdev July 2006
* crunchy2 June 2007
* Michniewski 2008
* Tantric August 2008
*
* menudraw.cpp
*
* Menu drawing routines
***************************************************************************/
#include <malloc.h>
#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 "memmap.h"
#include "video.h"
#include "menudraw.h"
#include "snes9xGX.h"
#include "filesel.h"
#include "dvd.h"
#include "aram.h"
#include "images/gfx_bg.h"
#include "input.h"
#include "networkop.h"
/*** Globals ***/
static FT_Library ftlibrary;
static FT_Face face;
static FT_GlyphSlot slot;
static unsigned int fonthi, fontlo;
extern char fontface[]; /*** From fontface.s ***/
extern int fontsize; /*** From fontface.s ***/
extern int screenheight;
extern unsigned int *xfb[2];
extern int whichfb;
/*** Permanent backdrop ***/
#ifdef HW_RVL
u32 *backdrop = NULL;
#endif
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 *) fontface, fontsize, 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;
}
/****************************************************************************
* Display credits, legal copyright and licence
*
* THIS MUST NOT BE REMOVED IN ANY DERIVATIVE WORK.
***************************************************************************/
void
Credits ()
{
clearscreen ();
setfontcolour (0x00, 0x00, 0x00);
setfontsize (28);
DrawText (-1, 60, "Credits");
int ypos = 25;
if (screenheight == 480)
ypos += 52;
else
ypos += 32;
setfontsize(16);
DrawText (-1, ypos += 30, "Official Site: http://code.google.com/p/snes9x-gx/");
ypos += 20;
setfontsize (20);
DrawText (-1, ypos += 30, "Technical");
setfontsize (16);
DrawText (75, ypos += 30, "Snes9x GX 00x");
DrawText (350, ypos, "michniewski & Tantric");
DrawText (75, ypos += 20, "Snes9X GX 2.0.1 GameCube");
DrawText (350, ypos, "crunchy2, eke-eke, others");
DrawText (75, ypos += 20, "Snes9x GX GameCube Port");
DrawText (350, ypos, "SoftDev");
DrawText (75, ypos += 20, "Snes9x 1.5.1");
DrawText (350, ypos, "Snes9x Team");
DrawText (75, ypos += 20, "GX");
DrawText (350, ypos, "http://www.gc-linux.org");
DrawText (75, ypos += 20, "libogc");
DrawText (350, ypos, "Shagkur & wintermute");
setfontsize (20);
DrawText (-1, ypos += 40, "Testing");
setfontsize (16);
DrawText (-1, ypos += 30, "TehSkeen users");
setfontsize (12);
DrawText (-1, ypos += 45, "Snes9x - Copyright (c) Snes9x Team 1996 - 2006");
DrawText (-1, ypos += 15, "This software is open source and may be copied, distributed, or modified");
DrawText (-1, ypos += 15, "under the terms of the GNU General Public License (GPL) Version 2.");
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);
}
/****************************************************************************
* Unpackbackdrop
*
* Decompress menu background and store it in ARAM or memory
***************************************************************************/
void
unpackbackdrop ()
{
unsigned long res, inbytes, outbytes;
unsigned int colour;
int offset;
int i;
int bgSize = (screenheight * 640 * 2);
u32 * bgtemp = (u32 *) memalign(32, bgSize);
colour = getcolour (0x00, 0x00, 0x00);
/*** Fill with black for now ***/
for (i = 0; i < (320 * screenheight); i++)
bgtemp[i] = colour;
/*** If it's PAL50, need to move down a few lines ***/
offset = ((screenheight - 480) >> 1) * 320;
inbytes = BG_COMPRESSED;
outbytes = BG_RAW;
res =
uncompress ((Bytef *) bgtemp + offset, &outbytes, (Bytef *) bg,
inbytes);
#ifdef HW_RVL
// On Wii - store backdrop in MEM2
unsigned int MEM2Storage = 0x91000000;
backdrop = (u32 *)MEM2Storage;
memcpy(backdrop, bgtemp, bgSize);
#else
// On GameCube - store the backdrop in ARAM
ARAMPut ((char *) bgtemp, (char *) AR_BACKDROP, bgSize);
#endif
free (bgtemp);
bgtemp = NULL;
clearscreen ();
showscreen ();
}
/****************************************************************************
* 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)) ) VIDEO_WaitVSync();
while (!(PAD_ButtonsDown (0) & PAD_BUTTON_A) && !(WPAD_ButtonsDown(0) & (WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A)) ) VIDEO_WaitVSync();
#else
while ( PAD_ButtonsDown (0) & PAD_BUTTON_A ) VIDEO_WaitVSync();
while (!(PAD_ButtonsDown (0) & PAD_BUTTON_A) ) 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))
) 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)) )
return 1;
else if ( (gc_btns & PAD_BUTTON_B) || (wm_btns & (WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B)) )
return 0;
}
#else
u32 gc_btns;
while ( (PAD_ButtonsDown (0) & (PAD_BUTTON_A | PAD_BUTTON_B)) ) 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 ();
DrawText (-1, ypos, msg);
ypos += 30;
DrawText (-1, ypos, "Press A to continue");
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 ();
DrawText (-1, ypos, msg);
ypos += 60;
char txt[80];
sprintf (txt, "B = %s : A = %s", bmsg, amsg);
DrawText (-1, ypos, txt);
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 ();
DrawText (-1, ypos, msg);
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 = 45;
if (screenheight == 480)
ypos += 52;
else
ypos += 32;
clearscreen ();
setfontcolour (0, 0, 0);
if (title != NULL)
{
setfontsize (28);
DrawText (-1, 60, title);
}
setfontsize (12);
char versionText[50];
sprintf(versionText, "%s %s", APPNAME, APPVERSION);
DrawText (510, screenheight - 20, versionText);
// 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( 30, 610, n * line_height + (ypos-line_height+6) + w, 0x80, 0x80, 0x80 );
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++;
}
}
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;
u32 ph = 0;
u32 wh = 0;
signed char gc_ay = 0;
signed char wm_ay = 0;
int scroll_delay = 0;
bool move_selection = 0;
#define SCROLL_INITIAL_DELAY 15
#define SCROLL_LOOP_DELAY 2
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);
ph = PAD_ButtonsHeld (0);
#ifdef HW_RVL
wm_ay = WPAD_Stick (0,0, 1);
wp = WPAD_ButtonsDown (0);
wh = WPAD_ButtonsHeld (0);
#endif
VIDEO_WaitVSync(); // slow things down a bit so we don't overread the pads
/*** Look for up ***/
if ( ((p | ph) & PAD_BUTTON_UP) || ((wp | wh) & (WPAD_BUTTON_UP | WPAD_CLASSIC_BUTTON_UP)) || (gc_ay > PADCAL) || (wm_ay > PADCAL) )
{
if ((p & PAD_BUTTON_UP) || (wp & (WPAD_BUTTON_UP
| WPAD_CLASSIC_BUTTON_UP)))
{ /*** Button just pressed***/
scroll_delay = SCROLL_INITIAL_DELAY; // reset scroll delay.
move_selection = 1; //continue (move selection)
}
else if (scroll_delay == 0)
{ /*** Button is held ***/
scroll_delay = SCROLL_LOOP_DELAY;
move_selection = 1; //continue (move selection)
}
else
{
scroll_delay--; // wait
}
if (move_selection)
{
redraw = 1;
menu = FindMenuItem(&items[0], maxitems, menu, -1);
move_selection = 0;
}
}
/*** Look for down ***/
if ( ((p | ph) & PAD_BUTTON_DOWN) || ((wp | wh) & (WPAD_BUTTON_DOWN | WPAD_CLASSIC_BUTTON_DOWN)) || (gc_ay < -PADCAL) || (wm_ay < -PADCAL) )
{
if ((p & PAD_BUTTON_DOWN) || (wp & (WPAD_BUTTON_DOWN
| WPAD_CLASSIC_BUTTON_DOWN)))
{ /*** Button just pressed ***/
scroll_delay = SCROLL_INITIAL_DELAY; // reset scroll delay.
move_selection = 1; //continue (move selection)
}
else if (scroll_delay == 0)
{ /*** Button is held ***/
scroll_delay = SCROLL_LOOP_DELAY;
move_selection = 1; //continue (move selection)
}
else
{
scroll_delay--; // wait
}
if (move_selection)
{
redraw = 1;
move_selection = 0;
menu = FindMenuItem(&items[0], maxitems, menu, +1);
}
}
if ((p & PAD_BUTTON_A) || (wp & (WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A)))
{
quit = 1;
ret = menu;
}
if ((p & PAD_BUTTON_B) || (wp & (WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B)))
{
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))
#endif
)
{
ret = -1;
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 (28);
DrawText (-1, 60, "Choose Game");
setfontsize(18);
ypos = (screenheight - ((PAGESIZE - 1) * 20)) >> 1;
if (screenheight == 480)
ypos += 24;
else
ypos += 10;
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( 30, 610, ( j * 20 ) + (ypos-16) + w, 0x80, 0x80, 0x80 );
setfontcolour (0x00, 0x00, 0xe0);
DrawText (50, (j * 20) + ypos, text);
setfontcolour (0x00, 0x00, 0x00);
}
else
{
/*** Normal entry ***/
DrawText (50, (j * 20) + ypos, text);
}
j++;
}
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 (28);
DrawText (-1, 60, "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++;
}
showscreen ();
}
/****************************************************************************
* ROM Information Screen
***************************************************************************/
void RomInfo()
{
clearscreen ();
int ypos = 65;
if (screenheight == 480)
ypos += 52;
else
ypos += 32;
setfontsize (28);
DrawText (-1, 60, "Rom Information");
setfontsize (16);
setfontcolour (0x00, 0x00, 0x00);
#define MENU_INFO_ROM "ROM"
#define MENU_INFO_ROMID "ROMID"
#define MENU_INFO_COMPANY "Company"
#define MENU_INFO_SIZE "Size"
#define MENU_INFO_SRAM "SRAM"
#define MENU_INFO_TYPE "Type"
#define MENU_INFO_CHECKSUM "Checksum"
#define MENU_INFO_TVTYPE "TV Type"
#define MENU_INFO_FRAMES "Frames"
#define MENU_INFO_CRC32 "CRC32"
char fmtString[1024];
ypos += 20;
DrawText (150, ypos, MENU_INFO_ROM);
DrawText (300, ypos, Memory.ROMName);
ypos += 20;
DrawText (150, ypos, MENU_INFO_ROMID);
DrawText (300, ypos, Memory.ROMId);
ypos += 20;
DrawText (150, ypos, MENU_INFO_COMPANY);
DrawText (300, ypos, Memory.CompanyId);
ypos += 20;
DrawText (150, ypos, MENU_INFO_SIZE);
sprintf(fmtString, "%d", Memory.ROMSize);
DrawText (300, ypos, fmtString);
ypos += 20;
DrawText (150, ypos, MENU_INFO_SRAM);
sprintf(fmtString, "%d", Memory.SRAMSize);
DrawText (300, ypos, fmtString);
ypos += 20;
DrawText (150, ypos, MENU_INFO_TYPE);
sprintf(fmtString, "%d", Memory.ROMType);
DrawText (300, ypos, fmtString);
ypos += 20;
DrawText (150, ypos, MENU_INFO_CHECKSUM);
sprintf(fmtString, "%04x / %04x", Memory.ROMChecksum, Memory.ROMComplementChecksum);
DrawText (300, ypos, fmtString);
ypos += 20;
DrawText (150, ypos, MENU_INFO_TVTYPE);
sprintf(fmtString, "%s", Settings.PAL ? "PAL" : "NTSC");
DrawText (300, ypos, fmtString);
ypos += 20;
DrawText (150, ypos, MENU_INFO_FRAMES);
sprintf(fmtString, "%d", Memory.ROMFramesPerSecond);
DrawText (300, ypos, fmtString);
ypos += 20;
DrawText (150, ypos, MENU_INFO_CRC32);
sprintf(fmtString, "%08X", Memory.ROMCRC32);
DrawText (300, ypos, fmtString);
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!
{
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 );
}