diff --git a/source/ngc/mixer.cpp b/source/ngc/audio.cpp similarity index 76% rename from source/ngc/mixer.cpp rename to source/ngc/audio.cpp index 64e7868..39df56e 100644 --- a/source/ngc/mixer.cpp +++ b/source/ngc/audio.cpp @@ -16,6 +16,8 @@ static int tail = 0; static u8 mixerdata[MIXBUFFSIZE]; #define MIXERMASK ((MIXBUFFSIZE >> 2) - 1) +static u8 soundbuffer[3200] ATTRIBUTE_ALIGN(32); + /**************************************************************************** * MIXER_AddSamples * @@ -71,3 +73,29 @@ int MIXER_GetSamples( u8 *dstbuffer, int maxlen ) return 3200; } +static void AudioPlayer() +{ + AUDIO_StopDMA(); + MIXER_GetSamples(soundbuffer, 3200); + DCFlushRange(soundbuffer,3200); + AUDIO_InitDMA((u32)soundbuffer,3200); + AUDIO_StartDMA(); +} + +void InitialiseSound() +{ + AUDIO_Init(NULL); // Start audio subsystem + AUDIO_SetDSPSampleRate(AI_SAMPLERATE_48KHZ); + AUDIO_RegisterDMACallback(AudioPlayer); + memset(soundbuffer, 0, 3200); +} + +void StopAudio() +{ + AUDIO_StopDMA(); +} + +void StartAudio() +{ + AUDIO_StartDMA(); +} diff --git a/source/ngc/mixer.h b/source/ngc/audio.h similarity index 85% rename from source/ngc/mixer.h rename to source/ngc/audio.h index 227107e..9ffe14b 100644 --- a/source/ngc/mixer.h +++ b/source/ngc/audio.h @@ -8,6 +8,8 @@ void MIXER_AddSamples( u8 *sampledata, int len ); int MIXER_GetSamples( u8 *dstbuffer, int maxlen ); +void StopAudio(); +void StartAudio(); +void InitialiseSound(); #endif - diff --git a/source/ngc/button_mapping.c b/source/ngc/button_mapping.c new file mode 100644 index 0000000..83d097a --- /dev/null +++ b/source/ngc/button_mapping.c @@ -0,0 +1,117 @@ +/**************************************************************************** + * Snes9x 1.51 Nintendo Wii/Gamecube Port + * + * michniewski August 2008 + * + * button_mapping.c + * + * Controller button mapping + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#include "button_mapping.h" + +/**************************************************************************** + * Controller Button Descriptions: + * used for identifying which buttons have been pressed when configuring + * and for displaying the name of said button + ***************************************************************************/ + +CtrlrMap ctrlr_def[4] = { +// Nunchuk btn def +{ + CTRLR_NUNCHUK, + 13, + { + {WPAD_BUTTON_DOWN, "DOWN"}, + {WPAD_BUTTON_UP, "UP"}, + {WPAD_BUTTON_LEFT, "LEFT"}, + {WPAD_BUTTON_RIGHT, "RIGHT"}, + {WPAD_BUTTON_A, "A"}, + {WPAD_BUTTON_B, "B"}, + {WPAD_BUTTON_1, "1"}, + {WPAD_BUTTON_2, "2"}, + {WPAD_BUTTON_PLUS, "PLUS"}, + {WPAD_BUTTON_MINUS, "MINUS"}, + {WPAD_BUTTON_HOME, "HOME"}, + {WPAD_NUNCHUK_BUTTON_Z, "Z"}, + {WPAD_NUNCHUK_BUTTON_C, "C"}, + {0, ""}, + {0, ""} + } +}, +// Classic btn def +{ + CTRLR_CLASSIC, + 15, + { + {WPAD_CLASSIC_BUTTON_DOWN, "DOWN"}, + {WPAD_CLASSIC_BUTTON_UP, "UP"}, + {WPAD_CLASSIC_BUTTON_LEFT, "LEFT"}, + {WPAD_CLASSIC_BUTTON_RIGHT, "RIGHT"}, + {WPAD_CLASSIC_BUTTON_A, "A"}, + {WPAD_CLASSIC_BUTTON_B, "B"}, + {WPAD_CLASSIC_BUTTON_X, "X"}, + {WPAD_CLASSIC_BUTTON_Y, "Y"}, + {WPAD_CLASSIC_BUTTON_PLUS, "PLUS"}, + {WPAD_CLASSIC_BUTTON_MINUS, "MINUS"}, + {WPAD_CLASSIC_BUTTON_HOME, "HOME"}, + {WPAD_CLASSIC_BUTTON_FULL_L, "L TRIG"}, + {WPAD_CLASSIC_BUTTON_FULL_R, "R TRIG"}, + {WPAD_CLASSIC_BUTTON_ZL, "ZL"}, + {WPAD_CLASSIC_BUTTON_ZR, "ZR"} + } +}, +// Gamecube controller btn def +{ + CTRLR_GCPAD, + 13, + { + {PAD_BUTTON_DOWN, "DOWN"}, + {PAD_BUTTON_UP, "UP"}, + {PAD_BUTTON_LEFT, "LEFT"}, + {PAD_BUTTON_RIGHT, "RIGHT"}, + {PAD_BUTTON_A, "A"}, + {PAD_BUTTON_B, "B"}, + {PAD_BUTTON_X, "X"}, + {PAD_BUTTON_Y, "Y"}, + {PAD_BUTTON_MENU, "MENU"}, + {PAD_BUTTON_START, "START"}, + {PAD_TRIGGER_L, "L TRIG"}, + {PAD_TRIGGER_R, "R TRIG"}, + {PAD_TRIGGER_Z, "Z"}, + {0, ""}, + {0, ""} + } +}, +// Wiimote btn def +{ + CTRLR_WIIMOTE, + 11, + { + {WPAD_BUTTON_DOWN, "DOWN"}, + {WPAD_BUTTON_UP, "UP"}, + {WPAD_BUTTON_LEFT, "LEFT"}, + {WPAD_BUTTON_RIGHT, "RIGHT"}, + {WPAD_BUTTON_A, "A"}, + {WPAD_BUTTON_B, "B"}, + {WPAD_BUTTON_1, "1"}, + {WPAD_BUTTON_2, "2"}, + {WPAD_BUTTON_PLUS, "PLUS"}, + {WPAD_BUTTON_MINUS, "MINUS"}, + {WPAD_BUTTON_HOME, "HOME"}, + {0, ""}, + {0, ""}, + {0, ""}, + {0, ""} + } + } +}; + diff --git a/source/ngc/button_mapping.h b/source/ngc/button_mapping.h new file mode 100644 index 0000000..178dfc2 --- /dev/null +++ b/source/ngc/button_mapping.h @@ -0,0 +1,38 @@ +/**************************************************************************** + * Snes9x 1.51 Nintendo Wii/Gamecube Port + * + * michniewski August 2008 + * + * button_mapping.h + * + * Controller button mapping + ***************************************************************************/ + +#ifndef BTN_MAP_H +#define BTN_MAP_H + +enum { + CTRLR_NONE = -1, + CTRLR_NUNCHUK, + CTRLR_CLASSIC, + CTRLR_GCPAD, + CTRLR_WIIMOTE, + CTRLR_SNES = 7 // give some other value for the snes padmap +}; + +typedef struct _btn_map { + u32 btn; // button 'id' + char* name; // button name +} BtnMap; + +typedef struct _ctrlr_map { + u16 type; // controller type + int num_btns; // number of buttons on the controller + BtnMap map[15]; // controller button map +} CtrlrMap; + +// externs: + +extern CtrlrMap ctrlr_def[4]; + +#endif diff --git a/source/ngc/dvd.cpp b/source/ngc/dvd.cpp new file mode 100644 index 0000000..134817d --- /dev/null +++ b/source/ngc/dvd.cpp @@ -0,0 +1,573 @@ +/**************************************************************************** + * Snes9x 1.51 Nintendo Wii/Gamecube Port + * + * softdev July 2006 + * svpe & crunchy2 June 2007 + * Tantric September 2008 + * + * dvd.cpp + * + * DVD I/O functions + ***************************************************************************/ + +#include +#include +#include +#include +#include + +#ifdef WII_DVD +#ifdef __cplusplus +extern "C" { +#include +} +#endif +#endif + +#include "menudraw.h" +#include "gcunzip.h" + +extern int offset; +extern int selection; +extern FILEENTRIES filelist[MAXFILES]; +extern int maxfiles; +u64 dvddir = 0; +u64 dvdrootdir = 0; +int dvddirlength = 0; +bool isWii = false; + +#ifdef HW_DOL +/** DVD I/O Address base **/ +volatile unsigned long *dvd = (volatile unsigned long *) 0xCC006000; +#endif + + /** Due to lack of memory, we'll use this little 2k keyhole for all DVD operations **/ +unsigned char DVDreadbuffer[2048] ATTRIBUTE_ALIGN (32); +unsigned char dvdbuffer[2048]; + + +/**************************************************************************** + * dvd_read + * + * The only DVD function we need - you gotta luv gc-linux self-boots! + * returns: 1 - ok ; 0 - error + ***************************************************************************/ +int +dvd_read (void *dst, unsigned int len, u64 offset) +{ + + unsigned char *buffer = (unsigned char *) (unsigned int) DVDreadbuffer; + + if (len > 2048) + return 0; /*** We only allow 2k reads **/ + + DCInvalidateRange ((void *) buffer, len); + + // don't read past the end of the DVD (1.5 GB for GC DVD, 4.7 GB for DVD) + if(offset < 0x57057C00 || (isWii && offset < 0x118244F00LL)) + { + + #ifdef HW_DOL + + dvd[0] = 0x2E; + dvd[1] = 0; + dvd[2] = 0xA8000000; + dvd[3] = (u32)(offset >> 2); + dvd[4] = len; + dvd[5] = (u32) buffer; + dvd[6] = len; + dvd[7] = 3; /*** Enable reading with DMA ***/ + while (dvd[7] & 1); + memcpy (dst, buffer, len); + + if (dvd[0] & 0x4) /* Ensure it has completed */ + return 0; + + return 1; + + #elif WII_DVD + int ret = 1; + ret = DI_ReadDVD(dst, len >> 11, (u32)(offset >> 11)); + if (ret==0) + return 1; + else + return 0; + #endif + } + + return 0; +} + +/** Minimal ISO Directory Definition **/ +#define RECLEN 0 /* Record length */ +#define EXTENT 6 /* Extent */ +#define FILE_LENGTH 14 /* File length (BIG ENDIAN) */ +#define FILE_FLAGS 25 /* File flags */ +#define FILENAME_LENGTH 32 /* Filename length */ +#define FILENAME 33 /* ASCIIZ filename */ + +/** Minimal Primary Volume Descriptor **/ +#define PVDROOT 0x9c +static int IsJoliet = 0; + +/**************************************************************************** + * Primary Volume Descriptor + * + * The PVD should reside between sector 16 and 31. + * This is for single session DVD only. + ***************************************************************************/ +int +getpvd () +{ + int sector = 16; + u32 rootdir32; + + dvddir = dvddirlength = 0; + IsJoliet = -1; + + /** Look for Joliet PVD first **/ + while (sector < 32) + { + if (dvd_read (&dvdbuffer, 2048, (u64)(sector << 11))) + { + if (memcmp (&dvdbuffer, "\2CD001\1", 8) == 0) + { + memcpy(&rootdir32, &dvdbuffer[PVDROOT + EXTENT], 4); + dvddir = (u64)rootdir32; + dvddir <<= 11; + dvdrootdir = dvddir; + memcpy (&dvddirlength, &dvdbuffer[PVDROOT + FILE_LENGTH], 4); + IsJoliet = 1; + break; + } + } + else + return 0; /*** Can't read sector! ***/ + sector++; + } + + if (IsJoliet > 0) /*** Joliet PVD Found ? ***/ + return 1; + + sector = 16; + + /*** Look for standard ISO9660 PVD ***/ + while (sector < 32) + { + if (dvd_read (&dvdbuffer, 2048, sector << 11)) + { + if (memcmp (&dvdbuffer, "\1CD001\1", 8) == 0) + { + memcpy (&rootdir32, &dvdbuffer[PVDROOT + EXTENT], 4); + dvddir = (u64)rootdir32; + dvddir <<= 11; + dvdrootdir = dvddir; + memcpy (&dvddirlength, &dvdbuffer[PVDROOT + FILE_LENGTH], 4); + IsJoliet = 0; + break; + } + } + else + return 0; /*** Can't read sector! ***/ + sector++; + } + return (IsJoliet == 0); +} + +/**************************************************************************** + * TestDVD() + * + * Tests if a ISO9660 DVD is inserted and available + ***************************************************************************/ +bool TestDVD() +{ + + if (!getpvd()) + { + #ifdef HW_DOL + DVD_Mount(); + #elif WII_DVD + DI_Mount(); + while(DI_GetStatus() & DVD_INIT); + #endif + if (!getpvd()) + return false; + } + + return true; +} + +/**************************************************************************** + * getentry + * + * Support function to return the next file entry, if any + * Declared static to avoid accidental external entry. + ***************************************************************************/ +static int diroffset = 0; +static int +getentry (int entrycount) +{ + char fname[512]; /* Huge, but experience has determined this */ + char *ptr; + char *filename; + char *filenamelength; + char *rr; + int j; + u32 offset32; + + /* Basic checks */ + if (entrycount >= MAXFILES) + return 0; + + if (diroffset >= 2048) + return 0; + + /** Decode this entry **/ + if (dvdbuffer[diroffset]) /* Record length available */ + { + /* Update offsets into sector buffer */ + ptr = (char *) &dvdbuffer[0]; + ptr += diroffset; + filename = ptr + FILENAME; + filenamelength = ptr + FILENAME_LENGTH; + + /* Check for wrap round - illegal in ISO spec, + * but certain crap writers do it! */ + if ((diroffset + dvdbuffer[diroffset]) > 2048) + return 0; + + if (*filenamelength) + { + memset (&fname, 0, 512); + + if (!IsJoliet) /*** Do ISO 9660 first ***/ + strcpy (fname, filename); + else + { /*** The more tortuous unicode joliet entries ***/ + for (j = 0; j < (*filenamelength >> 1); j++) + { + fname[j] = filename[j * 2 + 1]; + } + + fname[j] = 0; + + if (strlen (fname) >= MAXJOLIET) + fname[MAXJOLIET - 1] = 0; + + if (strlen (fname) == 0) + fname[0] = filename[0]; + } + + if (strlen (fname) == 0) // root entry + { + fname[0] = 0; // we'll skip it by setting the filename to 0 length + } + else + { + if (fname[0] == 1) + { + if(dvddir == dvdrootdir) // at root already, don't show .. + fname[0] = 0; + else + strcpy (fname, ".."); + } + else + { + /* + * Move *filenamelength to t, + * Only to stop gcc warning for noobs :) + */ + int t = *filenamelength; + fname[t] = 0; + } + } + /** Rockridge Check **/ + rr = strstr (fname, ";"); + if (rr != NULL) + *rr = 0; + + strcpy (filelist[entrycount].filename, fname); + fname[MAXDISPLAY - 1] = 0; + strcpy (filelist[entrycount].displayname, fname); + + memcpy (&offset32, &dvdbuffer[diroffset + EXTENT], 4); + + filelist[entrycount].offset = (u64)offset32; + memcpy (&filelist[entrycount].length, &dvdbuffer[diroffset + FILE_LENGTH], 4); + memcpy (&filelist[entrycount].flags, &dvdbuffer[diroffset + FILE_FLAGS], 1); + + filelist[entrycount].offset <<= 11; + filelist[entrycount].flags = filelist[entrycount].flags & 2; + + /*** Prepare for next entry ***/ + + diroffset += dvdbuffer[diroffset]; + return 1; + } + } + return 0; +} + +/**************************************************************************** + * parseDVDdirectory + * + * This function will parse the directory tree. + * It relies on dvddir and dvddirlength being pre-populated by a call to + * getpvd, a previous parse or a menu selection. + * + * The return value is number of files collected, or 0 on failure. + ***************************************************************************/ +int +ParseDVDdirectory () +{ + int pdlength; + u64 pdoffset; + u64 rdoffset; + int len = 0; + int filecount = 0; + + // initialize selection + selection = offset = 0; + + pdoffset = rdoffset = dvddir; + pdlength = dvddirlength; + filecount = 0; + + // Clear any existing values + memset (&filelist, 0, sizeof (FILEENTRIES) * MAXFILES); + + /*** Get as many files as possible ***/ + while (len < pdlength) + { + if (dvd_read (&dvdbuffer, 2048, pdoffset) == 0) + return 0; + + diroffset = 0; + + while (getentry (filecount)) + { + if(strlen(filelist[filecount].filename) > 0 && filecount < MAXFILES) + filecount++; + } + + len += 2048; + pdoffset = rdoffset + len; + } + + // Sort the file list + qsort(filelist, filecount, sizeof(FILEENTRIES), FileSortCallback); + + return filecount; +} + +/**************************************************************************** + * DirectorySearch + * + * Searches for the directory name specified within the current directory + * Returns the index of the directory, or -1 if not found + ***************************************************************************/ +int DirectorySearch(char dir[512]) +{ + for (int i = 0; i < maxfiles; i++ ) + if (strcmp(filelist[i].filename, dir) == 0) + return i; + return -1; +} + +/**************************************************************************** + * SwitchDVDFolder + * + * Recursively searches for any directory path 'dir' specified + * Also loads the directory contents via ParseDVDdirectory() + * It relies on dvddir, dvddirlength, and filelist being pre-populated + ***************************************************************************/ +bool SwitchDVDFolder(char * dir, int maxDepth) +{ + if(maxDepth > 8) // only search to a max depth of 8 levels + return false; + + bool lastdir = false; + char * nextdir = NULL; + unsigned int t = strcspn(dir, "/"); + + if(t != strlen(dir)) + nextdir = dir + t + 1; // next directory path to find + else + lastdir = true; + + dir[t] = 0; + + int dirindex = DirectorySearch(dir); + + if(dirindex >= 0) + { + dvddir = filelist[dirindex].offset; + dvddirlength = filelist[dirindex].length; + maxfiles = ParseDVDdirectory(); + + if(lastdir) + return true; + else + return SwitchDVDFolder(nextdir, maxDepth++); + } + return false; +} + +bool SwitchDVDFolder(char origdir[]) +{ + // make a copy of origdir so we don't mess with original + char dir[200]; + strcpy(dir, origdir); + + char * dirptr = dir; + + // strip off leading/trailing slashes on the directory path + // we don't want to screw up our recursion! + if(dir[0] == '/') + dirptr = dirptr + 1; + if(dir[strlen(dir)-1] == '/') + dir[strlen(dir)-1] = 0; + + return SwitchDVDFolder(dirptr, 0); +} + +/**************************************************************************** + * LoadDVDFile + * This function will load a file from DVD, in BIN, SMD or ZIP format. + * The values for offset and length are inherited from dvddir and + * dvddirlength. + * + * The buffer parameter should re-use the initial ROM buffer. + ***************************************************************************/ + +int +LoadDVDFile (unsigned char *buffer) +{ + int offset; + int blocks; + int i; + u64 discoffset; + char readbuffer[2048]; + + // How many 2k blocks to read + blocks = dvddirlength / 2048; + offset = 0; + discoffset = dvddir; + ShowAction ((char*) "Loading..."); + dvd_read (readbuffer, 2048, discoffset); + + if (!IsZipFile (readbuffer)) + { + for (i = 0; i < blocks; i++) + { + dvd_read (readbuffer, 2048, discoffset); + memcpy (buffer + offset, readbuffer, 2048); + offset += 2048; + discoffset += 2048; + } + + /*** And final cleanup ***/ + if (dvddirlength % 2048) + { + i = dvddirlength % 2048; + dvd_read (readbuffer, 2048, discoffset); + memcpy (buffer + offset, readbuffer, i); + } + } + else + { + return UnZipFile (buffer, discoffset); // unzip from dvd + } + return dvddirlength; +} + +/**************************************************************************** + * uselessinquiry + * + * As the name suggests, this function is quite useless. + * It's only purpose is to stop any pending DVD interrupts while we use the + * memcard interface. + * + * libOGC tends to foul up if you don't, and sometimes does if you do! + ***************************************************************************/ +#ifdef HW_DOL +void uselessinquiry () +{ + dvd[0] = 0; + dvd[1] = 0; + dvd[2] = 0x12000000; + dvd[3] = 0; + dvd[4] = 0x20; + dvd[5] = 0x80000000; + dvd[6] = 0x20; + dvd[7] = 1; + + while (dvd[7] & 1); +} + +/**************************************************************************** + * dvd_motor_off( ) + * Turns off DVD drive motor so it doesn't make noise (Gamecube only) + ***************************************************************************/ +void dvd_motor_off( ) +{ + dvd[0] = 0x2e; + dvd[1] = 0; + dvd[2] = 0xe3000000; + dvd[3] = 0; + dvd[4] = 0; + dvd[5] = 0; + dvd[6] = 0; + dvd[7] = 1; // Do immediate + while (dvd[7] & 1); + + /*** PSO Stops blackscreen at reload ***/ + dvd[0] = 0x14; + dvd[1] = 0; +} + +/**************************************************************************** + * dvd_driveid + * + * Gets and returns the dvd driveid + ***************************************************************************/ + +int dvd_driveid() +{ + static unsigned char *inquiry=(unsigned char *)0x80000004; + + dvd[0] = 0x2e; + dvd[1] = 0; + dvd[2] = 0x12000000; + dvd[3] = 0; + dvd[4] = 0x20; + dvd[5] = 0x80000000; + dvd[6] = 0x20; + dvd[7] = 3; + + while( dvd[7] & 1 ) + ; + DCFlushRange((void *)0x80000000, 32); + + return (int)inquiry[2]; +} + +#endif + +/**************************************************************************** + * SetDVDDriveType() + * + * Sets the DVD drive ID for use to determine disc size (1.5 GB or 4.7 GB) + ***************************************************************************/ +void SetDVDDriveType() +{ + #ifdef HW_RVL + isWii = true; + #else + int drvid = dvd_driveid (); + if ( drvid == 4 || drvid == 6 || drvid == 8 ) + isWii = false; + else + isWii = true; + #endif +} diff --git a/source/ngc/dvd.h b/source/ngc/dvd.h new file mode 100644 index 0000000..6ec2a74 --- /dev/null +++ b/source/ngc/dvd.h @@ -0,0 +1,24 @@ +/**************************************************************************** + * Snes9x 1.51 Nintendo Wii/Gamecube Port + * + * softdev July 2006 + * svpe & crunchy2 June 2007 + * Tantric September 2008 + * + * dvd.h + * + * DVD I/O functions + ***************************************************************************/ + +#ifndef _NGCDVD_ +#define _NGCDVD_ + +int getpvd (); +int ParseDVDdirectory (); +int LoadDVDFile (unsigned char *buffer); +bool TestDVD(); +int dvd_read (void *dst, unsigned int len, u64 offset); +bool SwitchDVDFolder(char dir[]); +void SetDVDDriveType(); + +#endif diff --git a/source/ngc/fileop.cpp b/source/ngc/fileop.cpp new file mode 100644 index 0000000..a53a94b --- /dev/null +++ b/source/ngc/fileop.cpp @@ -0,0 +1,286 @@ +/**************************************************************************** + * Snes9x 1.51 Nintendo Wii/Gamecube Port + * + * softdev July 2006 + * crunchy2 May 2007 + * Tantric August 2008 + * + * fileop.cpp + * + * FAT File operations + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include "vba.h" +#include "vbasupport.h" +#include "fileop.h" +#include "gcunzip.h" +#include "video.h" +#include "menudraw.h" +#include "filesel.h" +#include "preferences.h" + +FILE * filehandle; + +extern unsigned char savebuffer[]; +extern char output[16384]; +extern int offset; +extern int selection; +extern char currentdir[MAXPATHLEN]; +extern FILEENTRIES filelist[MAXFILES]; + +/**************************************************************************** + * fat_is_mounted + * to check whether FAT media are detected. + ***************************************************************************/ + +bool FatIsMounted(PARTITION_INTERFACE partition) { + char prefix[] = "fatX:/"; + prefix[3] = partition + '0'; + DIR_ITER *dir = diropen(prefix); + if (dir) { + dirclose(dir); + return true; + } + return false; +} + +/**************************************************************************** + * changeFATInterface + * Checks if the device (method) specified is available, and + * sets libfat to use the device + ***************************************************************************/ +bool ChangeFATInterface(int method, bool silent) +{ + bool devFound = false; + + if(method == METHOD_SD) + { + // check which SD device is loaded + + #ifdef HW_RVL + if (FatIsMounted(PI_INTERNAL_SD)) + { + devFound = true; + fatSetDefaultInterface(PI_INTERNAL_SD); + } + #endif + + if (!devFound && FatIsMounted(PI_SDGECKO_A)) + { + devFound = true; + fatSetDefaultInterface(PI_SDGECKO_A); + } + if(!devFound && FatIsMounted(PI_SDGECKO_B)) + { + devFound = true; + fatSetDefaultInterface(PI_SDGECKO_B); + } + if(!devFound) + { + if(!silent) + WaitPrompt ((char *)"SD card not found!"); + } + } + else if(method == METHOD_USB) + { + #ifdef HW_RVL + if(FatIsMounted(PI_USBSTORAGE)) + { + devFound = true; + fatSetDefaultInterface(PI_USBSTORAGE); + } + else + { + if(!silent) + WaitPrompt ((char *)"USB flash drive not found!"); + } + #endif + } + + return devFound; +} + +/*************************************************************************** + * Browse FAT subdirectories + **************************************************************************/ +int +ParseFATdirectory(int method) +{ + int nbfiles = 0; + DIR_ITER *fatdir; + char filename[MAXPATHLEN]; + struct stat filestat; + char msg[128]; + + // initialize selection + selection = offset = 0; + + // Clear any existing values + memset (&filelist, 0, sizeof (FILEENTRIES) * MAXFILES); + + // open the directory + fatdir = diropen(currentdir); + if (fatdir == NULL) + { + sprintf(msg, "Couldn't open %s", currentdir); + WaitPrompt(msg); + + // if we can't open the dir, open root dir + sprintf(currentdir,"%s",ROOTFATDIR); + + fatdir = diropen(currentdir); + + if (fatdir == NULL) + { + sprintf(msg, "Error opening %s", currentdir); + WaitPrompt(msg); + return 0; + } + } + + // index files/folders + while(dirnext(fatdir,filename,&filestat) == 0) + { + if(strcmp(filename,".") != 0) + { + memset(&filelist[nbfiles], 0, sizeof(FILEENTRIES)); + strncpy(filelist[nbfiles].filename, filename, MAXPATHLEN); + strncpy(filelist[nbfiles].displayname, filename, MAXDISPLAY+1); // crop name for display + filelist[nbfiles].length = filestat.st_size; + filelist[nbfiles].flags = (filestat.st_mode & _IFDIR) == 0 ? 0 : 1; // flag this as a dir + nbfiles++; + } + } + + // close directory + dirclose(fatdir); + + // Sort the file list + qsort(filelist, nbfiles, sizeof(FILEENTRIES), FileSortCallback); + + return nbfiles; +} + +/**************************************************************************** + * LoadFATFile + ***************************************************************************/ +int +LoadFATFile (char *filename, int length) +{ + char zipbuffer[2048]; + char filepath[MAXPATHLEN]; + FILE *handle; + unsigned char *rbuffer; + u32 size; + + /* Check filename length */ + if ((strlen(currentdir)+1+strlen(filelist[selection].filename)) < MAXPATHLEN) + sprintf(filepath, "%s/%s",currentdir,filelist[selection].filename); + else + { + WaitPrompt((char*) "Maximum filepath length reached!"); + return -1; + } + return loadVBAROM(filepath); +/* + handle = fopen (filepath, "rb"); + if (handle > 0) + { + fread (zipbuffer, 1, 2048, handle); + + if (IsZipFile (zipbuffer)) + { + size = UnZipFile (rbuffer, handle); // unzip from FAT + } + else + { + // Just load the file up + fseek(handle, 0, SEEK_END); + length = ftell(handle); // get filesize + fseek(handle, 2048, SEEK_SET); // seek back to point where we left off + memcpy (rbuffer, zipbuffer, 2048); // copy what we already read + fread (rbuffer + 2048, 1, length - 2048, handle); + size = length; + } + fclose (handle); + return size; + } + else + { + WaitPrompt((char*) "Error opening file"); + return 0; + } + + return 0;*/ +} + +/**************************************************************************** + * Load savebuffer from FAT file + ***************************************************************************/ +int +LoadBufferFromFAT (char *filepath, bool silent) +{ + FILE *handle; + int boffset = 0; + int read = 0; + + ClearSaveBuffer (); + + handle = fopen (filepath, "rb"); + + if (handle <= 0) + { + if ( !silent ) + { + char msg[100]; + sprintf(msg, "Couldn't open %s", filepath); + WaitPrompt (msg); + } + return 0; + } + + /*** This is really nice, just load the file and decode it ***/ + while ((read = fread (savebuffer + boffset, 1, 1024, handle)) > 0) + { + boffset += read; + } + + fclose (handle); + + return boffset; +} + +/**************************************************************************** + * Write savebuffer to FAT card file + ***************************************************************************/ +int +SaveBufferToFAT (char *filepath, int datasize, bool silent) +{ + FILE *handle; + + if (datasize) + { + handle = fopen (filepath, "wb"); + + if (handle <= 0) + { + char msg[100]; + sprintf(msg, "Couldn't save %s", filepath); + WaitPrompt (msg); + return 0; + } + + fwrite (savebuffer, 1, datasize, handle); + fclose (handle); + } + + ClearSaveBuffer (); + return datasize; +} diff --git a/source/ngc/fileop.h b/source/ngc/fileop.h new file mode 100644 index 0000000..af651a7 --- /dev/null +++ b/source/ngc/fileop.h @@ -0,0 +1,34 @@ +/**************************************************************************** + * Snes9x 1.51 Nintendo Wii/Gamecube Port + * + * softdev July 2006 + * crunchy2 May 2007 + * Tantric August 2008 + * + * fileop.h + * + * FAT File operations + ****************************************************************************/ + +#ifndef _FATFILESC_ +#define _FATFILESC_ +#include +#include +#include +#include +#include +#include +#include +#include + +#define ROOTFATDIR "fat:/" + +bool ChangeFATInterface(int method, bool silent); +int ParseFATdirectory(int method); +int LoadFATFile (char *filename, int length); +int SaveBufferToFAT (char *filepath, int datasize, bool silent); +int LoadBufferFromFAT (char *filepath, bool silent); + +extern char currFATdir[MAXPATHLEN]; + +#endif diff --git a/source/ngc/filesel.cpp b/source/ngc/filesel.cpp new file mode 100644 index 0000000..cc78fed --- /dev/null +++ b/source/ngc/filesel.cpp @@ -0,0 +1,587 @@ +/**************************************************************************** + * Snes9x 1.51 Nintendo Wii/Gamecube Port + * + * softdev July 2006 + * svpe June 2007 + * crunchy2 May-July 2007 + * Tantric August 2008 + * + * filesel.cpp + * + * Generic file routines - reading, writing, browsing + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#ifdef WII_DVD +#ifdef __cplusplus +extern "C" { +#include +} +#endif +#endif + +#include "vba.h" +#include "vbasupport.h" +#include "vmmem.h" +#include "menudraw.h" +#include "video.h" +#include "filesel.h" +#include "fileop.h" +#include "memcardop.h" +#include "input.h" +#include "dvd.h" +#include "smbop.h" + +int offset; +int selection; +char currentdir[MAXPATHLEN]; +int maxfiles; +extern int screenheight; + +int havedir = -1; +extern u64 dvddir; +extern int dvddirlength; + +int hasloaded = 0; + +// Global file entry table +FILEENTRIES filelist[MAXFILES]; + +unsigned char savebuffer[SAVEBUFFERSIZE] ATTRIBUTE_ALIGN (32); + +char ROMFilename[512]; +int ROMSize = 0; + +/**************************************************************************** + * ClearSaveBuffer () + * Clear the savebuffer + ***************************************************************************/ +void +ClearSaveBuffer () +{ + memset (savebuffer, 0, SAVEBUFFERSIZE); +} + +/**************************************************************************** +* autoLoadMethod() +* Auto-determines and sets the load method +* Returns method set +****************************************************************************/ +int autoLoadMethod() +{ + ShowAction ((char*) "Attempting to determine load method..."); + + if(ChangeFATInterface(METHOD_SD, SILENT)) + return METHOD_SD; + else if(ChangeFATInterface(METHOD_USB, SILENT)) + return METHOD_USB; + else if(TestDVD()) + return METHOD_DVD; + else if(ConnectShare (SILENT)) + return METHOD_SMB; + else + { + WaitPrompt((char*) "Unable to auto-determine load method!"); + return 0; // no method found + } +} + +/**************************************************************************** +* autoSaveMethod() +* Auto-determines and sets the save method +* Returns method set +****************************************************************************/ +int autoSaveMethod() +{ + ShowAction ((char*) "Attempting to determine save method..."); + + if(ChangeFATInterface(METHOD_SD, SILENT)) + return METHOD_SD; + else if(ChangeFATInterface(METHOD_USB, SILENT)) + return METHOD_USB; + else if(TestCard(CARD_SLOTA, SILENT)) + return METHOD_MC_SLOTA; + else if(TestCard(CARD_SLOTB, SILENT)) + return METHOD_MC_SLOTB; + else if(ConnectShare (SILENT)) + return METHOD_SMB; + else + { + WaitPrompt((char*) "Unable to auto-determine save method!"); + return 0; // no method found + } +} + +/**************************************************************************** + * UpdateDirName() + * Update curent directory name for file browser + ***************************************************************************/ +int UpdateDirName(int method) +{ + int size=0; + char *test; + char temp[1024]; + + // update DVD directory (does not utilize 'currentdir') + if(method == METHOD_DVD) + { + dvddir = filelist[selection].offset; + dvddirlength = filelist[selection].length; + return 1; + } + + /* current directory doesn't change */ + if (strcmp(filelist[selection].filename,".") == 0) + { + return 0; + } + /* go up to parent directory */ + else if (strcmp(filelist[selection].filename,"..") == 0) + { + /* determine last subdirectory namelength */ + sprintf(temp,"%s",currentdir); + test = strtok(temp,"/"); + while (test != NULL) + { + size = strlen(test); + test = strtok(NULL,"/"); + } + + /* remove last subdirectory name */ + size = strlen(currentdir) - size - 1; + currentdir[size] = 0; + + return 1; + } + /* Open a directory */ + else + { + /* test new directory namelength */ + if ((strlen(currentdir)+1+strlen(filelist[selection].filename)) < MAXPATHLEN) + { + /* update current directory name */ + sprintf(currentdir, "%s/%s",currentdir, filelist[selection].filename); + return 1; + } + else + { + WaitPrompt((char*)"Directory name is too long !"); + return -1; + } + } +} + +/**************************************************************************** + * FileSortCallback + * + * Quick sort callback to sort file entries with the following order: + * . + * .. + * + * + ***************************************************************************/ +int FileSortCallback(const void *f1, const void *f2) +{ + /* Special case for implicit directories */ + if(((FILEENTRIES *)f1)->filename[0] == '.' || ((FILEENTRIES *)f2)->filename[0] == '.') + { + if(strcmp(((FILEENTRIES *)f1)->filename, ".") == 0) { return -1; } + if(strcmp(((FILEENTRIES *)f2)->filename, ".") == 0) { return 1; } + if(strcmp(((FILEENTRIES *)f1)->filename, "..") == 0) { return -1; } + if(strcmp(((FILEENTRIES *)f2)->filename, "..") == 0) { return 1; } + } + + /* If one is a file and one is a directory the directory is first. */ + if(((FILEENTRIES *)f1)->flags && !(((FILEENTRIES *)f2)->flags)) return -1; + if(!(((FILEENTRIES *)f1)->flags) && ((FILEENTRIES *)f2)->flags) return 1; + + return stricmp(((FILEENTRIES *)f1)->filename, ((FILEENTRIES *)f2)->filename); +} + +/**************************************************************************** + * StripExt + * + * Strips an extension from a filename + ***************************************************************************/ + +void StripExt(char* returnstring, char * inputstring) +{ + char* loc_dot; + + strcpy (returnstring, inputstring); + loc_dot = strrchr(returnstring,'.'); + if (loc_dot != NULL) + *loc_dot = '\0'; // strip file extension +} + +/**************************************************************************** + * FileSelector + * + * Let user select a file from the listing + ***************************************************************************/ +int FileSelector (int method) +{ + u32 p = 0; + u32 wp = 0; + u32 ph = 0; + u32 wh = 0; + signed char gc_ay = 0; + signed char gc_sx = 0; + signed char wm_ay = 0; + signed char wm_sx = 0; + + int haverom = 0; + int redraw = 1; + int selectit = 0; + + int scroll_delay = 0; + bool move_selection = 0; + #define SCROLL_INITIAL_DELAY 15 + #define SCROLL_LOOP_DELAY 2 + + while (haverom == 0) + { + if (redraw) + ShowFiles (filelist, maxfiles, offset, selection); + redraw = 0; + + VIDEO_WaitVSync(); // slow things down a bit so we don't overread the pads + + gc_ay = PAD_StickY (0); + gc_sx = PAD_SubStickX (0); + + p = PAD_ButtonsDown (0); + ph = PAD_ButtonsHeld (0); +#ifdef HW_RVL + wm_ay = WPAD_StickY (0, 0); + wm_sx = WPAD_StickX (0, 1); + + wp = WPAD_ButtonsDown (0); + wh = WPAD_ButtonsHeld (0); +#endif + + /*** Check for exit combo ***/ + if ( (gc_sx < -70) || (wm_sx < -70) || (wp & WPAD_BUTTON_HOME) || (wp & WPAD_CLASSIC_BUTTON_HOME) ) + return 0; + + /*** Check buttons, perform actions ***/ + if ( (p & PAD_BUTTON_A) || selectit || (wp & (WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A)) ) + { + if ( selectit ) + selectit = 0; + if (filelist[selection].flags) // This is directory + { + /* update current directory and set new entry list if directory has changed */ + int status = UpdateDirName(method); + if (status == 1) // ok, open directory + { + switch (method) + { + case METHOD_SD: + case METHOD_USB: + maxfiles = ParseFATdirectory(method); + break; + + case METHOD_DVD: + maxfiles = ParseDVDdirectory(); + break; + + case METHOD_SMB: + maxfiles = ParseSMBdirectory(); + break; + } + + if (!maxfiles) + { + WaitPrompt ((char*) "Error reading directory !"); + haverom = 1; // quit menu + } + } + else if (status == -1) // directory name too long + { + haverom = 1; // quit menu + } + } + else // this is a file + { + // store the filename (w/o ext) - used for sram/freeze naming + StripExt(ROMFilename, filelist[selection].filename); + + ShowAction ((char *)"Loading..."); + + switch (method) + { + case METHOD_SD: + case METHOD_USB: + ROMSize = LoadFATFile (filelist[selection].filename, filelist[selection].length); + break; + + case METHOD_DVD: + dvddir = filelist[selection].offset; + dvddirlength = filelist[selection].length; + //ROMSize = LoadDVDFile (Memory.ROM); + break; + + case METHOD_SMB: + //ROMSize = LoadSMBFile (filelist[selection].filename, filelist[selection].length); + break; + } + + if (ROMSize > 0) + { + + return 1; + } + else + { + WaitPrompt((char*) "Error loading ROM!"); + } + } + redraw = 1; + } // End of A + if ( (p & PAD_BUTTON_B) || (wp & (WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B)) ) + { + while ( (PAD_ButtonsDown(0) & PAD_BUTTON_B) +#ifdef HW_RVL + || (WPAD_ButtonsDown(0) & (WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B)) +#endif + ) + VIDEO_WaitVSync(); + if ( strcmp(filelist[0].filename,"..") == 0 ) + { + selection = 0; + selectit = 1; + } + else if ( strcmp(filelist[1].filename,"..") == 0 ) + { + selection = selectit = 1; + } else { + return 0; + } + } // End of B + 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) + { + selection++; + if (selection == maxfiles) + selection = offset = 0; + if ((selection - offset) >= PAGESIZE) + offset += PAGESIZE; + redraw = 1; + move_selection = 0; + } + } // End of down + 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) + { + selection--; + if (selection < 0) { + selection = maxfiles - 1; + offset = selection - PAGESIZE + 1; + } + if (selection < offset) + offset -= PAGESIZE; + if (offset < 0) + offset = 0; + redraw = 1; + move_selection = 0; + } + } // End of Up + if ( (p & PAD_BUTTON_LEFT) || (wp & (WPAD_BUTTON_LEFT | WPAD_CLASSIC_BUTTON_LEFT)) ) + { + /*** Go back a page ***/ + selection -= PAGESIZE; + if (selection < 0) + { + selection = maxfiles - 1; + offset = selection - PAGESIZE + 1; + } + if (selection < offset) + offset -= PAGESIZE; + if (offset < 0) + offset = 0; + redraw = 1; + } + if ( (p & PAD_BUTTON_RIGHT) || (wp & (WPAD_BUTTON_RIGHT | WPAD_CLASSIC_BUTTON_RIGHT)) ) + { + /*** Go forward a page ***/ + selection += PAGESIZE; + if (selection > maxfiles - 1) + selection = offset = 0; + if ((selection - offset) >= PAGESIZE) + offset += PAGESIZE; + redraw = 1; + } + } + return 0; +} + +/**************************************************************************** + * OpenDVD + * + * Function to load a DVD directory and display to user. + ***************************************************************************/ +int +OpenDVD (int method) +{ + if (!getpvd()) + { + ShowAction((char*) "Loading DVD..."); + #ifdef HW_DOL + DVD_Mount(); // mount the DVD unit again + #elif WII_DVD + u32 val; + DI_GetCoverRegister(&val); + if(val & 0x1) // True if no disc inside, use (val & 0x2) for true if disc inside. + { + WaitPrompt((char *)"No disc inserted!"); + return 0; + } + DI_Mount(); + while(DI_GetStatus() & DVD_INIT); + #endif + + if (!getpvd()) + { + WaitPrompt ((char *)"Invalid DVD."); + return 0; // not a ISO9660 DVD + } + } + + maxfiles = ParseDVDdirectory(); // load root folder + + // switch to rom folder + SwitchDVDFolder(GCSettings.LoadFolder); + + if (maxfiles > 0) + { + return FileSelector (method); + } + else + { + // no entries found + WaitPrompt ((char *)"No Files Found!"); + return 0; + } +} + +/**************************************************************************** + * OpenSMB + * + * Function to load from an SMB share + ***************************************************************************/ +int +OpenSMB (int method) +{ + // Connect to network share + if(ConnectShare (NOTSILENT)) + { + // change current dir to root dir + sprintf(currentdir, "/%s", GCSettings.LoadFolder); + + maxfiles = ParseSMBdirectory (); + if (maxfiles > 0) + { + return FileSelector (method); + } + else + { + // no entries found + WaitPrompt ((char *)"No Files Found!"); + return 0; + } + } + return 0; +} + +/**************************************************************************** + * OpenFAT + * + * Function to load from FAT + ***************************************************************************/ +int +OpenFAT (int method) +{ + if(ChangeFATInterface(method, NOTSILENT)) + { + // change current dir to snes roms directory + sprintf ( currentdir, "%s/%s", ROOTFATDIR, GCSettings.LoadFolder ); + + // Parse initial root directory and get entries list + maxfiles = ParseFATdirectory (method); + if (maxfiles > 0) + { + // Select an entry + return FileSelector (method); + } + else + { + // no entries found + WaitPrompt ((char *)"No Files Found!"); + return 0; + } + } + return 0; +} + +/**************************************************************************** + * OpenROM + * Opens device specified by method, displays a list of ROMS + ***************************************************************************/ + +int +OpenROM (int method) +{ + int loadROM = 0; + + if(method == METHOD_AUTO) + method = autoLoadMethod(); + + switch (method) + { + case METHOD_SD: + case METHOD_USB: + loadROM = OpenFAT (method); + break; + case METHOD_DVD: + // Load from DVD + loadROM = OpenDVD (method); + break; + case METHOD_SMB: + // Load from Network (SMB) + loadROM = OpenSMB (method); + break; + } + + return loadROM; +} diff --git a/source/ngc/filesel.h b/source/ngc/filesel.h new file mode 100644 index 0000000..bda1a04 --- /dev/null +++ b/source/ngc/filesel.h @@ -0,0 +1,39 @@ +/**************************************************************************** + * Snes9x 1.51 Nintendo Wii/Gamecube Port + * + * softdev July 2006 + * crunchy2 May 2007 + * Tantric August 2008 + * + * filesel.h + * + * Generic file routines - reading, writing, browsing + ****************************************************************************/ + +#ifndef _NGCFILESEL_ +#define _NGCFILESEL_ + +#define SAVEBUFFERSIZE ((512 * 1024) + 2048 + 64 + 4 + 4) +#define MAXJOLIET 255 +#define MAXDISPLAY 54 + +typedef struct +{ + u64 offset; + unsigned int length; + char flags; + char filename[MAXJOLIET + 1]; + char displayname[MAXDISPLAY + 1]; +} FILEENTRIES; + +#define MAXFILES 2000 // Restrict to 2000 files per dir +extern FILEENTRIES filelist[MAXFILES]; + +void ClearSaveBuffer (); +int OpenROM (int method); +int autoLoadMethod(); +int autoSaveMethod(); +int FileSortCallback(const void *f1, const void *f2); +void StripExt(char* returnstring, char * inputstring); + +#endif diff --git a/source/ngc/fontface.s b/source/ngc/fontface.s new file mode 100644 index 0000000..d0d88ed --- /dev/null +++ b/source/ngc/fontface.s @@ -0,0 +1,12 @@ +# Fonts + +.rodata +.globl fontface +.balign 32 +fontface: +.incbin "../source/ngc/ttf/font.ttf" + + +.globl fontsize +fontsize: .long 28736 + diff --git a/source/ngc/gcpad.cpp b/source/ngc/gcpad.cpp deleted file mode 100644 index 04fa67b..0000000 --- a/source/ngc/gcpad.cpp +++ /dev/null @@ -1,302 +0,0 @@ -/**************************************************************************** -* VisualBoyAdvance 1.7.2 -* -* Nintendo GameCube Joypad Wrapper -****************************************************************************/ - -#include -#include - - -#define VBA_BUTTON_A 1 -#define VBA_BUTTON_B 2 -#define VBA_BUTTON_SELECT 4 -#define VBA_BUTTON_START 8 -#define VBA_RIGHT 16 -#define VBA_LEFT 32 -#define VBA_UP 64 -#define VBA_DOWN 128 -#define VBA_BUTTON_R 256 -#define VBA_BUTTON_L 512 -#define VBA_SPEED 1024 -#define VBA_CAPTURE 2048 - -#ifdef WII_BUILD -#include -#include -int isClassicAvailable = 0; -int isWiimoteAvailable = 0; -/* -#ifndef PI -#define PI 3.14159f -#endif - -enum { STICK_X, STICK_Y }; -static int getStickValue(joystick_t* j, int axis, int maxAbsValue){ - double angle = PI * j->ang/180.0f; - double magnitude = (j->mag > 1.0f) ? 1.0f : - (j->mag < -1.0f) ? -1.0f : j->mag; - double value; - if(axis == STICK_X) - value = magnitude * sin( angle ); - else - value = magnitude * cos( angle ); - return (int)(value * maxAbsValue); -}*/ - -#endif -int menuCalled = 0; -u32 -NGCPad() -{ - u32 res = 0; - short p; - signed char x, - y; - int padcal = 90; - float t; - -#ifdef WII_BUILD - //wiimote - WPADData *wpad; - WPAD_ScanPads(); - wpad = WPAD_Data(0); - if (isWiimoteAvailable) - { - unsigned short b = wpad->btns_h; - - if (b & WPAD_BUTTON_2) - res |= VBA_BUTTON_A; - - if (b & WPAD_BUTTON_1) - res |= VBA_BUTTON_B; - - if (b & WPAD_BUTTON_MINUS) - res |= VBA_BUTTON_SELECT; - - if (b & WPAD_BUTTON_PLUS) - res |= VBA_BUTTON_START; - - if (b & WPAD_BUTTON_RIGHT) - res |= VBA_UP; - - if (b & WPAD_BUTTON_LEFT) - res |= VBA_DOWN; - - if (b & WPAD_BUTTON_UP) - res |= VBA_LEFT; - - if (b & WPAD_BUTTON_DOWN) - res |= VBA_RIGHT; - - if (b & WPAD_BUTTON_A) - res |= VBA_BUTTON_L; - - if (b & WPAD_BUTTON_B) - res |= VBA_BUTTON_R; - - if (b & WPAD_BUTTON_HOME) - menuCalled = 1; - } - //classic controller - if (isClassicAvailable) - { - float mag,ang; - int b = wpad->exp.classic.btns; - ang = wpad->exp.classic.ljs.ang; - mag = wpad->exp.classic.ljs.mag; - - if (mag > 0.4) { - if (ang > 292.5 | ang <= 67.5) - res |= VBA_UP; - if (ang > 22.5 & ang <= 157.5) - res |= VBA_RIGHT; - if (ang > 113.5 & ang <= 247.5) - res |= VBA_DOWN; - if (ang > 203.5 & ang <= 337.5) - res |= VBA_LEFT; - } - - int x_s = 0; //getStickValue(&wpad.exp.classic.ljs, STICK_X, 127); - int y_s = 0; //getStickValue(&wpad.exp.classic.ljs, STICK_Y, 127); - if (b & CLASSIC_CTRL_BUTTON_A) - res |= VBA_BUTTON_A; - - if (b & CLASSIC_CTRL_BUTTON_B) - res |= VBA_BUTTON_B; - - if (b & CLASSIC_CTRL_BUTTON_MINUS) - res |= VBA_BUTTON_SELECT; - - if (b & CLASSIC_CTRL_BUTTON_PLUS) - res |= VBA_BUTTON_START; - - if ((b & CLASSIC_CTRL_BUTTON_UP) || (y_s > 0)) - res |= VBA_UP; - - if ((b & CLASSIC_CTRL_BUTTON_DOWN) || (y_s < 0)) - res |= VBA_DOWN; - - if ((b & CLASSIC_CTRL_BUTTON_LEFT) || (x_s < 0)) - res |= VBA_LEFT; - - if ((b & CLASSIC_CTRL_BUTTON_RIGHT) || (x_s > 0)) - res |= VBA_RIGHT; - - if (b & CLASSIC_CTRL_BUTTON_FULL_L) - res |= VBA_BUTTON_L; - - if (b & CLASSIC_CTRL_BUTTON_FULL_R) - res |= VBA_BUTTON_R; - - if (b & CLASSIC_CTRL_BUTTON_HOME) - menuCalled = 1; - - } - //user needs a GC remote - PAD_ScanPads(); - p = PAD_ButtonsHeld(0); - x = PAD_StickX(0); - y = PAD_StickY(0); - if (x * x + y * y > padcal * padcal) - { - if (x > 0 && y == 0) - res |= VBA_RIGHT; - if (x < 0 && y == 0) - res |= VBA_LEFT; - if (x == 0 && y > 0) - res |= VBA_UP; - if (x == 0 && y < 0) - res |= VBA_DOWN; - - /*** Recalc left / right ***/ - t = (float) y / x; - if (t >= -2.41421356237 && t < 2.41421356237) - { - if (x >= 0) - res |= VBA_RIGHT; - else - res |= VBA_LEFT; - } - - /*** Recalc up / down ***/ - t = (float) x / y; - if (t >= -2.41421356237 && t < 2.41421356237) - { - if (y >= 0) - res |= VBA_UP; - else - res |= VBA_DOWN; - } - } - if (p & PAD_BUTTON_A) - res |= VBA_BUTTON_A; - - if (p & PAD_BUTTON_B) - res |= VBA_BUTTON_B; - - if (p & PAD_TRIGGER_Z) - res |= VBA_BUTTON_SELECT; - - if (p & PAD_BUTTON_START) - res |= VBA_BUTTON_START; - - if (p & PAD_BUTTON_UP) - res |= VBA_UP; - - if (p & PAD_BUTTON_DOWN) - res |= VBA_DOWN; - - if (p & PAD_BUTTON_LEFT) - res |= VBA_LEFT; - - if (p & PAD_BUTTON_RIGHT) - res |= VBA_RIGHT; - - if (p & PAD_TRIGGER_L) - res |= VBA_BUTTON_L; - - if (p & PAD_TRIGGER_R) - res |= VBA_BUTTON_R; - - if((p & PAD_BUTTON_X) && (p & PAD_BUTTON_Y)) - menuCalled = 1; - -#endif - -#ifdef GC_BUILD - p = PAD_ButtonsHeld(0); - x = PAD_StickX(0); - y = PAD_StickY(0); - if (x * x + y * y > padcal * padcal) - { - if (x > 0 && y == 0) - res |= VBA_RIGHT; - if (x < 0 && y == 0) - res |= VBA_LEFT; - if (x == 0 && y > 0) - res |= VBA_UP; - if (x == 0 && y < 0) - res |= VBA_DOWN; - - /*** Recalc left / right ***/ - t = (float) y / x; - if (t >= -2.41421356237 && t < 2.41421356237) - { - if (x >= 0) - res |= VBA_RIGHT; - else - res |= VBA_LEFT; - } - - /*** Recalc up / down ***/ - t = (float) x / y; - if (t >= -2.41421356237 && t < 2.41421356237) - { - if (y >= 0) - res |= VBA_UP; - else - res |= VBA_DOWN; - } - } - if (p & PAD_BUTTON_A) - res |= VBA_BUTTON_A; - - if (p & PAD_BUTTON_B) - res |= VBA_BUTTON_B; - - if (p & PAD_TRIGGER_Z) - res |= VBA_BUTTON_SELECT; - - if (p & PAD_BUTTON_START) - res |= VBA_BUTTON_START; - - if ((p & PAD_BUTTON_UP)) - res |= VBA_UP; - - if ((p & PAD_BUTTON_DOWN)) - res |= VBA_DOWN; - - if ((p & PAD_BUTTON_LEFT)) - res |= VBA_LEFT; - - if ((p & PAD_BUTTON_RIGHT)) - res |= VBA_RIGHT; - - if (p & PAD_TRIGGER_L) - res |= VBA_BUTTON_L; - - if (p & PAD_TRIGGER_R) - res |= VBA_BUTTON_R; - - if((p & PAD_BUTTON_X) && (p & PAD_BUTTON_Y)) - menuCalled = 1; -#endif - - if ((res & 48) == 48) - res &= ~16; - if ((res & 192) == 192) - res &= ~128; - - return res; -} diff --git a/source/ngc/gcpad.h b/source/ngc/gcpad.h deleted file mode 100644 index 174cfa7..0000000 --- a/source/ngc/gcpad.h +++ /dev/null @@ -1,11 +0,0 @@ -/**************************************************************************** -* VisualBoyAdvance 1.7.2 -* -* Nintendo GameCube Joypad Wrapper -****************************************************************************/ -#ifndef __NGCPADH__ -#define __NGCPADH__ - -u32 NGCPad(); - -#endif diff --git a/source/ngc/gcunzip.cpp b/source/ngc/gcunzip.cpp new file mode 100644 index 0000000..f159eb3 --- /dev/null +++ b/source/ngc/gcunzip.cpp @@ -0,0 +1,230 @@ +/**************************************************************************** + * Snes9x 1.51 Nintendo Wii/Gamecube Port + * + * softdev July 2006 + * Tantric September 2008 + * + * unzip.cpp + * + * File unzip routines + ***************************************************************************/ + +#include +#include +#include +#include +#include + +#include "dvd.h" +#include "smbop.h" +#include "video.h" +#include "menudraw.h" +#include "gcunzip.h" + +/* + * PKWare Zip Header - adopted into zip standard + */ +#define PKZIPID 0x504b0304 +#define MAXROM 0x500000 +#define ZIPCHUNK 2048 + +/* + * Zip files are stored little endian + * Support functions for short and int types + */ +u32 +FLIP32 (u32 b) +{ + unsigned int c; + + c = (b & 0xff000000) >> 24; + c |= (b & 0xff0000) >> 8; + c |= (b & 0xff00) << 8; + c |= (b & 0xff) << 24; + + return c; +} + +u16 +FLIP16 (u16 b) +{ + u16 c; + + c = (b & 0xff00) >> 8; + c |= (b & 0xff) << 8; + + return c; +} + +/**************************************************************************** + * IsZipFile + * + * Returns TRUE when PKZIPID is first four characters of buffer + ****************************************************************************/ +int +IsZipFile (char *buffer) +{ + unsigned int *check; + + check = (unsigned int *) buffer; + + if (check[0] == PKZIPID) + return 1; + + return 0; +} + + /***************************************************************************** + * unzip + * + * It should be noted that there is a limit of 5MB total size for any ROM + ******************************************************************************/ +FILE* fatfile; // FAT +u64 discoffset; // DVD +SMBFILE smbfile; // SMB + +int +UnZipBuffer (unsigned char *outbuffer, short where) +{ + PKZIPHEADER pkzip; + int zipoffset = 0; + int zipchunk = 0; + char out[ZIPCHUNK]; + z_stream zs; + int res; + int bufferoffset = 0; + int readoffset = 0; + int have = 0; + char readbuffer[ZIPCHUNK]; + char msg[128]; + + /*** Read Zip Header ***/ + switch (where) + { + case 0: // SD Card + fseek(fatfile, 0, SEEK_SET); + fread (readbuffer, 1, ZIPCHUNK, fatfile); + break; + + case 1: // DVD + dvd_read (readbuffer, ZIPCHUNK, discoffset); + break; + + case 2: // From SMB + SMB_ReadFile(readbuffer, ZIPCHUNK, 0, smbfile); + break; + } + + /*** Copy PKZip header to local, used as info ***/ + memcpy (&pkzip, readbuffer, sizeof (PKZIPHEADER)); + + pkzip.uncompressedSize = FLIP32 (pkzip.uncompressedSize); + + sprintf (msg, "Unzipping %d bytes ... Wait", + pkzip.uncompressedSize); + ShowAction (msg); + + /*** Prepare the zip stream ***/ + memset (&zs, 0, sizeof (z_stream)); + zs.zalloc = Z_NULL; + zs.zfree = Z_NULL; + zs.opaque = Z_NULL; + zs.avail_in = 0; + zs.next_in = Z_NULL; + res = inflateInit2 (&zs, -MAX_WBITS); + + if (res != Z_OK) + return 0; + + /*** Set ZipChunk for first pass ***/ + zipoffset = + (sizeof (PKZIPHEADER) + FLIP16 (pkzip.filenameLength) + + FLIP16 (pkzip.extraDataLength)); + zipchunk = ZIPCHUNK - zipoffset; + + /*** Now do it! ***/ + do + { + zs.avail_in = zipchunk; + zs.next_in = (Bytef *) & readbuffer[zipoffset]; + + /*** Now inflate until input buffer is exhausted ***/ + do + { + zs.avail_out = ZIPCHUNK; + zs.next_out = (Bytef *) & out; + + res = inflate (&zs, Z_NO_FLUSH); + + if (res == Z_MEM_ERROR) + { + inflateEnd (&zs); + return 0; + } + + have = ZIPCHUNK - zs.avail_out; + if (have) + { + /*** Copy to normal block buffer ***/ + memcpy (&outbuffer[bufferoffset], &out, have); + bufferoffset += have; + } + } + while (zs.avail_out == 0); + + /*** Readup the next 2k block ***/ + zipoffset = 0; + zipchunk = ZIPCHUNK; + + switch (where) + { + case 0: // SD Card + fread (readbuffer, 1, ZIPCHUNK, fatfile); + break; + + case 1: // DVD + readoffset += ZIPCHUNK; + dvd_read (readbuffer, ZIPCHUNK, discoffset+readoffset); + break; + + case 2: // From SMB + readoffset += ZIPCHUNK; + SMB_ReadFile(readbuffer, ZIPCHUNK, readoffset, smbfile); + break; + } + } + while (res != Z_STREAM_END); + + inflateEnd (&zs); + + if (res == Z_STREAM_END) + { + if (pkzip.uncompressedSize == (u32) bufferoffset) + return bufferoffset; + else + return pkzip.uncompressedSize; + } + + return 0; +} +// Reading from FAT +int +UnZipFile (unsigned char *outbuffer, FILE* infile) +{ + fatfile = infile; + return UnZipBuffer(outbuffer, 0); +} +// Reading from DVD +int +UnZipFile (unsigned char *outbuffer, u64 inoffset) +{ + discoffset = inoffset; + return UnZipBuffer(outbuffer, 1); +} +// Reading from SMB +int +UnZipFile (unsigned char *outbuffer, SMBFILE infile) +{ + smbfile = infile; + return UnZipBuffer(outbuffer, 2); +} diff --git a/source/ngc/gcunzip.h b/source/ngc/gcunzip.h new file mode 100644 index 0000000..ade862c --- /dev/null +++ b/source/ngc/gcunzip.h @@ -0,0 +1,44 @@ +/**************************************************************************** + * Snes9x 1.51 Nintendo Wii/Gamecube Port + * + * softdev July 2006 + * Tantric September 2008 + * + * unzip.h + * + * File unzip routines + ****************************************************************************/ +#ifndef _UNZIP_ +#define _UNZIP_ + +#include + +extern int IsZipFile (char *buffer); + +int UnZipFile (unsigned char *outbuffer, FILE* infile); // Reading from FAT +int UnZipFile (unsigned char *outbuffer, u64 inoffset); // Reading from DVD +int UnZipFile (unsigned char *outbuffer, SMBFILE infile); // Reading from SMB + +/* + * Zip file header definition + */ +typedef struct +{ + unsigned int zipid __attribute__ ((__packed__)); // 0x04034b50 + unsigned short zipversion __attribute__ ((__packed__)); + unsigned short zipflags __attribute__ ((__packed__)); + unsigned short compressionMethod __attribute__ ((__packed__)); + unsigned short lastmodtime __attribute__ ((__packed__)); + unsigned short lastmoddate __attribute__ ((__packed__)); + unsigned int crc32 __attribute__ ((__packed__)); + unsigned int compressedSize __attribute__ ((__packed__)); + unsigned int uncompressedSize __attribute__ ((__packed__)); + unsigned short filenameLength __attribute__ ((__packed__)); + unsigned short extraDataLength __attribute__ ((__packed__)); +} +PKZIPHEADER; + +u32 FLIP32 (u32 b); +u16 FLIP16 (u16 b); + +#endif diff --git a/source/ngc/gx_supp.c b/source/ngc/gx_supp.c deleted file mode 100644 index fd8217c..0000000 --- a/source/ngc/gx_supp.c +++ /dev/null @@ -1,264 +0,0 @@ -/**************************************************************************** -* Generic GX Support for Emulators -* softdev 2007 -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License along -* with this program; if not, write to the Free Software Foundation, Inc., -* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -* -* NGC GX Video Functions -* -* These are pretty standard functions to setup and use GX scaling. -****************************************************************************/ -#include -#include -#include -#include -#include - -/*** External 2D Video ***/ -extern u32 whichfb; -extern u32 *xfb[2]; -extern GXRModeObj *vmode; - -/*** 3D GX ***/ -#define DEFAULT_FIFO_SIZE ( 256 * 1024 ) -static u8 gp_fifo[DEFAULT_FIFO_SIZE] ATTRIBUTE_ALIGN(32); - -/*** Texture memory ***/ -static u8 *texturemem; -static int texturesize; - -GXTexObj texobj; -static Mtx view; -static int vwidth, vheight, oldvwidth, oldvheight; - -#define HASPECT 80 -#define VASPECT 45 - -/* New texture based scaler */ -typedef struct tagcamera - { - Vector pos; - Vector up; - Vector view; - } -camera; - -/*** Square Matrix - This structure controls the size of the image on the screen. - Think of the output as a -80 x 80 by -60 x 60 graph. -***/ -static s16 square[] ATTRIBUTE_ALIGN(32) = { - /* - * X, Y, Z - * Values set are for roughly 4:3 aspect - */ - -HASPECT, VASPECT, 0, // 0 - HASPECT, VASPECT, 0, // 1 - HASPECT, -VASPECT, 0, // 2 - -HASPECT, -VASPECT, 0, // 3 - }; - -static camera cam = { {0.0F, 0.0F, 0.0F}, - {0.0F, 0.5F, 0.0F}, - {0.0F, 0.0F, -0.5F} - }; - -/**************************************************************************** - * Scaler Support Functions - ****************************************************************************/ -static void draw_init(void) -{ - GX_ClearVtxDesc(); - GX_SetVtxDesc(GX_VA_POS, GX_INDEX8); - GX_SetVtxDesc(GX_VA_CLR0, GX_INDEX8); - GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT); - - GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_S16, 0); - GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0); - GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0); - - GX_SetArray(GX_VA_POS, square, 3 * sizeof(s16)); - - GX_SetNumTexGens(1); - GX_SetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY); - - GX_InvalidateTexAll(); - - GX_InitTexObj(&texobj, texturemem, vwidth, vheight, GX_TF_RGB565, - GX_CLAMP, GX_CLAMP, GX_FALSE); -} - -static void draw_vert(u8 pos, u8 c, f32 s, f32 t) -{ - GX_Position1x8(pos); - GX_Color1x8(c); - GX_TexCoord2f32(s, t); -} - -static void draw_square(Mtx v) -{ - Mtx m; // model matrix. - Mtx mv; // modelview matrix. - - guMtxIdentity(m); - guMtxTransApply(m, m, 0, 0, -100); - guMtxConcat(v, m, mv); - - GX_LoadPosMtxImm(mv, GX_PNMTX0); - GX_Begin(GX_QUADS, GX_VTXFMT0, 4); - draw_vert(0, 0, 0.0, 0.0); - draw_vert(1, 0, 1.0, 0.0); - draw_vert(2, 0, 1.0, 1.0); - draw_vert(3, 0, 0.0, 1.0); - GX_End(); -} - -/**************************************************************************** - * StartGX - ****************************************************************************/ -void GX_Start(int width, int height, int haspect, int vaspect) -{ - Mtx p; - - /*** Set new aspect (now with crap AR hack!) ***/ - square[0] = square[9] = (-haspect - 7); - square[3] = square[6] = (haspect + 7); - square[1] = square[4] = (vaspect + 7); - square[7] = square[10] = (-vaspect - 7); - - /*** Allocate 32byte aligned texture memory ***/ - texturesize = (width * height) * 2; - texturemem = (u8 *) memalign(32, texturesize); - - GXColor gxbackground = { 0, 0, 0, 0xff }; - - /*** Clear out FIFO area ***/ - memset(&gp_fifo, 0, DEFAULT_FIFO_SIZE); - - /*** Initialise GX ***/ - GX_Init(&gp_fifo, DEFAULT_FIFO_SIZE); - GX_SetCopyClear(gxbackground, 0x00ffffff); - - GX_SetViewport(0, 0, vmode->fbWidth, vmode->efbHeight, 0, 1); - GX_SetDispCopyYScale((f32) vmode->xfbHeight / (f32) vmode->efbHeight); - GX_SetScissor(0, 0, vmode->fbWidth, vmode->efbHeight); - GX_SetDispCopySrc(0, 0, vmode->fbWidth, vmode->efbHeight); - GX_SetDispCopyDst(vmode->fbWidth, vmode->xfbHeight); - GX_SetCopyFilter(vmode->aa, vmode->sample_pattern, GX_TRUE, - vmode->vfilter); - GX_SetFieldMode(vmode->field_rendering, - ((vmode->viHeight == - 2 * vmode->xfbHeight) ? GX_ENABLE : GX_DISABLE)); - GX_SetPixelFmt(GX_PF_RGB8_Z24, GX_ZC_LINEAR); - GX_SetCullMode(GX_CULL_NONE); - GX_CopyDisp(xfb[whichfb ^ 1], GX_TRUE); - GX_SetDispCopyGamma(GX_GM_1_0); - - guPerspective(p, 60, 1.33F, 10.0F, 1000.0F); - GX_LoadProjectionMtx(p, GX_PERSPECTIVE); - memset(texturemem, 0, texturesize); - - /*** Setup for first call to scaler ***/ - vwidth = vheight = -1; - -} - -/**************************************************************************** -* GX_Render -* -* Pass in a buffer, width and height to update as a tiled RGB565 texture -****************************************************************************/ -void GX_Render(int width, int height, u8 * buffer, int pitch) -{ - int h, w; - long long int *dst = (long long int *) texturemem; - long long int *src1 = (long long int *) buffer; - long long int *src2 = (long long int *) (buffer + pitch); - long long int *src3 = (long long int *) (buffer + (pitch * 2)); - long long int *src4 = (long long int *) (buffer + (pitch * 3)); - int rowpitch = (pitch >> 3) * 3; - int rowadjust = ( pitch % 8 ) * 4; - char *ra = NULL; - - vwidth = width; - vheight = height; - - whichfb ^= 1; - - if ((oldvheight != vheight) || (oldvwidth != vwidth)) - { - /** Update scaling **/ - oldvwidth = vwidth; - oldvheight = vheight; - draw_init(); - memset(&view, 0, sizeof(Mtx)); - guLookAt(view, &cam.pos, &cam.up, &cam.view); - GX_SetViewport(0, 0, vmode->fbWidth, vmode->efbHeight, 0, 1); - - } - - GX_InvVtxCache(); - GX_InvalidateTexAll(); - GX_SetTevOp(GX_TEVSTAGE0, GX_DECAL); - GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0); - - for (h = 0; h < vheight; h += 4) - { - - for (w = 0; w < (vwidth >> 2); w++) - { - *dst++ = *src1++; - *dst++ = *src2++; - *dst++ = *src3++; - *dst++ = *src4++; - } - - src1 += rowpitch; - src2 += rowpitch; - src3 += rowpitch; - src4 += rowpitch; - - if ( rowadjust ) - { - ra = (char *)src1; - src1 = (long long int *)(ra + rowadjust); - ra = (char *)src2; - src2 = (long long int *)(ra + rowadjust); - ra = (char *)src3; - src3 = (long long int *)(ra + rowadjust); - ra = (char *)src4; - src4 = (long long int *)(ra + rowadjust); - } - } - - DCFlushRange(texturemem, texturesize); - - GX_SetNumChans(1); - GX_LoadTexObj(&texobj, GX_TEXMAP0); - - draw_square(view); - - GX_DrawDone(); - - GX_SetZMode(GX_TRUE, GX_LEQUAL, GX_TRUE); - GX_SetColorUpdate(GX_TRUE); - GX_CopyDisp(xfb[whichfb], GX_TRUE); - GX_Flush(); - - VIDEO_SetNextFramebuffer(xfb[whichfb]); - VIDEO_Flush(); - //VIDEO_WaitVSync(); - -} diff --git a/source/ngc/input.cpp b/source/ngc/input.cpp new file mode 100644 index 0000000..6f70de4 --- /dev/null +++ b/source/ngc/input.cpp @@ -0,0 +1,354 @@ +/**************************************************************************** + * Snes9x 1.51 Nintendo Wii/Gamecube Port + * + * softdev July 2006 + * crunchy2 May-June 2007 + * Tantric September 2008 + * + * input.cpp + * + * Wii/Gamecube controller management + ***************************************************************************/ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "button_mapping.h" +#include "menu.h" +#include "video.h" +#include "input.h" +#include "tbtime.h" + +#define MAXJP 10 + +#define VBA_BUTTON_A 1 +#define VBA_BUTTON_B 2 +#define VBA_BUTTON_SELECT 4 +#define VBA_BUTTON_START 8 +#define VBA_RIGHT 16 +#define VBA_LEFT 32 +#define VBA_UP 64 +#define VBA_DOWN 128 +#define VBA_BUTTON_R 256 +#define VBA_BUTTON_L 512 +#define VBA_SPEED 1024 +#define VBA_CAPTURE 2048 + +// VBA controller buttons +// All other pads are mapped to this +unsigned int vbapadmap[] = { + VBA_BUTTON_A, VBA_BUTTON_B, + VBA_BUTTON_SELECT, VBA_BUTTON_START, + VBA_UP, VBA_DOWN, + VBA_LEFT, VBA_RIGHT, + VBA_BUTTON_L, VBA_BUTTON_R +}; + +/*** Gamecube controller Padmap ***/ +unsigned int gcpadmap[] = { + PAD_BUTTON_A, PAD_BUTTON_B, + PAD_TRIGGER_Z, PAD_BUTTON_START, + PAD_BUTTON_UP, PAD_BUTTON_DOWN, + PAD_BUTTON_LEFT, PAD_BUTTON_RIGHT, + PAD_TRIGGER_L, PAD_TRIGGER_R +}; +/*** Wiimote Padmap ***/ +unsigned int wmpadmap[] = { + WPAD_BUTTON_1, WPAD_BUTTON_2, + WPAD_BUTTON_MINUS, WPAD_BUTTON_PLUS, + WPAD_BUTTON_RIGHT, WPAD_BUTTON_LEFT, + WPAD_BUTTON_UP, WPAD_BUTTON_DOWN, + 0x0000, 0x0000 +}; +/*** Classic Controller Padmap ***/ +unsigned int ccpadmap[] = { + WPAD_CLASSIC_BUTTON_A, WPAD_CLASSIC_BUTTON_B, + WPAD_CLASSIC_BUTTON_MINUS, WPAD_CLASSIC_BUTTON_PLUS, + WPAD_CLASSIC_BUTTON_UP, WPAD_CLASSIC_BUTTON_DOWN, + WPAD_CLASSIC_BUTTON_LEFT, WPAD_CLASSIC_BUTTON_RIGHT, + WPAD_CLASSIC_BUTTON_FULL_L, WPAD_CLASSIC_BUTTON_FULL_R +}; +/*** Nunchuk + wiimote Padmap ***/ +unsigned int ncpadmap[] = { WPAD_BUTTON_A, WPAD_BUTTON_B, + WPAD_NUNCHUK_BUTTON_C, WPAD_NUNCHUK_BUTTON_Z, + WPAD_BUTTON_MINUS, WPAD_BUTTON_PLUS, + WPAD_BUTTON_2, WPAD_BUTTON_1, + WPAD_BUTTON_UP, WPAD_BUTTON_DOWN, + WPAD_BUTTON_LEFT, WPAD_BUTTON_RIGHT +}; + +#ifdef HW_RVL +/**************************************************************************** + * WPAD_StickX + * + * Get X value from Wii Joystick (classic, nunchuk) input + ***************************************************************************/ + +s8 WPAD_StickX(u8 chan,u8 right) +{ + float mag = 0.0; + float ang = 0.0; + WPADData *data = WPAD_Data(chan); + + switch (data->exp.type) + { + case WPAD_EXP_NUNCHUK: + case WPAD_EXP_GUITARHERO3: + if (right == 0) + { + mag = data->exp.nunchuk.js.mag; + ang = data->exp.nunchuk.js.ang; + } + break; + + case WPAD_EXP_CLASSIC: + if (right == 0) + { + mag = data->exp.classic.ljs.mag; + ang = data->exp.classic.ljs.ang; + } + else + { + mag = data->exp.classic.rjs.mag; + ang = data->exp.classic.rjs.ang; + } + break; + + default: + break; + } + + /* calculate X value (angle need to be converted into radian) */ + if (mag > 1.0) mag = 1.0; + else if (mag < -1.0) mag = -1.0; + double val = mag * sin((PI * ang)/180.0f); + + return (s8)(val * 128.0f); +} + +/**************************************************************************** + * WPAD_StickY + * + * Get Y value from Wii Joystick (classic, nunchuk) input + ***************************************************************************/ + +s8 WPAD_StickY(u8 chan, u8 right) +{ + float mag = 0.0; + float ang = 0.0; + WPADData *data = WPAD_Data(chan); + + switch (data->exp.type) + { + case WPAD_EXP_NUNCHUK: + case WPAD_EXP_GUITARHERO3: + if (right == 0) + { + mag = data->exp.nunchuk.js.mag; + ang = data->exp.nunchuk.js.ang; + } + break; + + case WPAD_EXP_CLASSIC: + if (right == 0) + { + mag = data->exp.classic.ljs.mag; + ang = data->exp.classic.ljs.ang; + } + else + { + mag = data->exp.classic.rjs.mag; + ang = data->exp.classic.rjs.ang; + } + break; + + default: + break; + } + + /* calculate X value (angle need to be converted into radian) */ + if (mag > 1.0) mag = 1.0; + else if (mag < -1.0) mag = -1.0; + double val = mag * cos((PI * ang)/180.0f); + + return (s8)(val * 128.0f); +} +#endif + +/**************************************************************************** + * DecodeJoy + * + * Reads the changes (buttons pressed, etc) from a controller and reports + * these changes to VBA + ****************************************************************************/ + +u32 DecodeJoy(unsigned short pad) +{ + signed char pad_x = PAD_StickX (pad); + signed char pad_y = PAD_StickY (pad); + u32 jp = PAD_ButtonsHeld (pad); + unsigned char J = 0; + + #ifdef HW_RVL + signed char wm_ax = 0; + signed char wm_ay = 0; + u32 wp = 0; + wm_ax = WPAD_StickX ((u8)pad, 0); + wm_ay = WPAD_StickY ((u8)pad, 0); + wp = WPAD_ButtonsHeld (pad); + + u32 exp_type; + if ( WPAD_Probe(pad, &exp_type) != 0 ) exp_type = WPAD_EXP_NONE; + #endif + + /*** + Gamecube Joystick input + ***/ + // Is XY inside the "zone"? + if (pad_x * pad_x + pad_y * pad_y > PADCAL * PADCAL) + { + if (pad_x > 0 && pad_y == 0) J |= VBA_RIGHT; + if (pad_x < 0 && pad_y == 0) J |= VBA_LEFT; + if (pad_x == 0 && pad_y > 0) J |= VBA_UP; + if (pad_x == 0 && pad_y < 0) J |= VBA_DOWN; + + if (pad_x != 0 && pad_y != 0) + { + if ((float)pad_y / pad_x >= -2.41421356237 && (float)pad_y / pad_x < 2.41421356237) + { + if (pad_x >= 0) + J |= VBA_RIGHT; + else + J |= VBA_LEFT; + } + + if ((float)pad_x / pad_y >= -2.41421356237 && (float)pad_x / pad_y < 2.41421356237) + { + if (pad_y >= 0) + J |= VBA_UP; + else + J |= VBA_DOWN; + } + } + } +#ifdef HW_RVL + /*** + Wii Joystick (classic, nunchuk) input + ***/ + // Is XY inside the "zone"? + if (wm_ax * wm_ax + wm_ay * wm_ay > PADCAL * PADCAL) + { + /*** we don't want division by zero ***/ + if (wm_ax > 0 && wm_ay == 0) + J |= VBA_RIGHT; + if (wm_ax < 0 && wm_ay == 0) + J |= VBA_LEFT; + if (wm_ax == 0 && wm_ay > 0) + J |= VBA_UP; + if (wm_ax == 0 && wm_ay < 0) + J |= VBA_DOWN; + + if (wm_ax != 0 && wm_ay != 0) + { + + /*** Recalc left / right ***/ + float t; + + t = (float) wm_ay / wm_ax; + if (t >= -2.41421356237 && t < 2.41421356237) + { + if (wm_ax >= 0) + J |= VBA_RIGHT; + else + J |= VBA_LEFT; + } + + /*** Recalc up / down ***/ + t = (float) wm_ax / wm_ay; + if (t >= -2.41421356237 && t < 2.41421356237) + { + if (wm_ay >= 0) + J |= VBA_UP; + else + J |= VBA_DOWN; + } + } + } +#endif + + /*** Report pressed buttons (gamepads) ***/ + int i; + + for (i = 0; i < MAXJP; i++) + { + if ( (jp & gcpadmap[i]) // gamecube controller + #ifdef HW_RVL + || ( (exp_type == WPAD_EXP_NONE) && (wp & wmpadmap[i]) ) // wiimote + || ( (exp_type == WPAD_EXP_CLASSIC) && (wp & ccpadmap[i]) ) // classic controller + || ( (exp_type == WPAD_EXP_NUNCHUK) && (wp & ncpadmap[i]) ) // nunchuk + wiimote + #endif + ) + J |= vbapadmap[i]; + } + + return J; +} +u32 GetJoy() +{ + short i; + int pad = 0; + u32 res = 0; + + s8 gc_px = PAD_SubStickX (0); + u32 jp = PAD_ButtonsHeld (0); // gamecube controller button info + + #ifdef HW_RVL + s8 wm_sx = WPAD_StickX (0,1); + u32 wm_pb = WPAD_ButtonsHeld (0); // wiimote / expansion button info + #endif + + // request to go back to menu + if ((gc_px < -70) || (jp & PAD_BUTTON_START) + #ifdef HW_RVL + || (wm_pb & WPAD_BUTTON_HOME) + || (wm_pb & WPAD_CLASSIC_BUTTON_HOME) + || (wm_sx < -70) + #endif + ) + { + /* + if (GCSettings.AutoSave == 1) + { + SaveRAM(GCSettings.SaveMethod, SILENT); + } + else if (GCSettings.AutoSave == 2) + { + SaveState(GCSettings.SaveMethod, SILENT); + } + else if(GCSettings.AutoSave == 3) + { + SaveRAM(GCSettings.SaveMethod, SILENT); + SaveState(GCSettings.SaveMethod, SILENT); + } + */ + mainmenu(3); + return 0; + } + else + { + res = DecodeJoy(pad); + if ((res & 48) == 48) + res &= ~16; + if ((res & 192) == 192) + res &= ~128; + + return res; + } +} diff --git a/source/ngc/input.h b/source/ngc/input.h new file mode 100644 index 0000000..4c755e6 --- /dev/null +++ b/source/ngc/input.h @@ -0,0 +1,31 @@ +/**************************************************************************** + * Snes9x 1.51 Nintendo Wii/Gamecube Port + * + * softdev July 2006 + * crunchy2 May-June 2007 + * Tantric September 2008 + * + * input.h + * + * Wii/Gamecube controller management + ***************************************************************************/ + +#ifndef _INPUT_H_ +#define _INPUT_H_ + +#include + +#define PI 3.14159265f +#define PADCAL 50 + +extern unsigned int gcpadmap[]; +extern unsigned int wmpadmap[]; +extern unsigned int ccpadmap[]; +extern unsigned int ncpadmap[]; + +s8 WPAD_StickX(u8 chan,u8 right); +s8 WPAD_StickY(u8 chan, u8 right); + +u32 GetJoy(); + +#endif diff --git a/source/ngc/main.c b/source/ngc/main.c deleted file mode 100644 index 8b13789..0000000 --- a/source/ngc/main.c +++ /dev/null @@ -1 +0,0 @@ - diff --git a/source/ngc/memcardop.cpp b/source/ngc/memcardop.cpp new file mode 100644 index 0000000..e42a302 --- /dev/null +++ b/source/ngc/memcardop.cpp @@ -0,0 +1,419 @@ +/**************************************************************************** + * Snes9x 1.51 Nintendo Wii/Gamecube Port + * + * softdev July 2006 + * crunchy2 May-June 2007 + * Tantric September 2008 + * + * memcardop.cpp + * + * Memory Card routines + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include "vba.h" +#include "video.h" +#include "menudraw.h" +#include "menu.h" +#include "preferences.h" +#include "memcardop.h" +#include "fileop.h" + +#define VERIFBUFFERSIZE 65536 +static u8 SysArea[CARD_WORKAREA] ATTRIBUTE_ALIGN (32); +extern unsigned char savebuffer[]; +unsigned char verifbuffer[VERIFBUFFERSIZE] ATTRIBUTE_ALIGN (32); +card_dir CardDir; +card_file CardFile; +card_stat CardStatus; + +/**************************************************************************** + * CardFileExists + * + * Wrapper to search through the files on the card. + * Returns TRUE if found. + ***************************************************************************/ +int +CardFileExists (char *filename, int slot) +{ + int CardError; + + CardError = CARD_FindFirst (slot, &CardDir, TRUE); + while (CardError != CARD_ERROR_NOFILE) + { + CardError = CARD_FindNext (&CardDir); + + if (strcmp ((char *) CardDir.filename, filename) == 0) + return 1; + } + + return 0; +} + +/**************************************************************************** + * TestCard + * + * Checks to see if a card is in the card slot specified + ***************************************************************************/ +bool TestCard(int slot, bool silent) +{ + // Memory Cards do not work in Wii mode - disable + #ifdef HW_RVL + return false; + #endif + + /*** Initialize Card System ***/ + memset (SysArea, 0, CARD_WORKAREA); + CARD_Init ("SNES", "00"); + + /*** Try to mount the card ***/ + if (MountCard(slot, silent) == 0) + { + // Mount successful! + if(!silent) + { + if (slot == CARD_SLOTA) + WaitPrompt((char*) "Mounted Slot A Memory Card!"); + else + WaitPrompt((char*) "Mounted Slot B Memory Card!"); + } + CARD_Unmount (slot); + return true; + } + else + { + if(!silent) + { + if (slot == CARD_SLOTA) + WaitPrompt((char*) "Unable to Mount Slot A Memory Card!"); + else + WaitPrompt((char*) "Unable to Mount Slot B Memory Card!"); + } + + return false; + } +} + +/**************************************************************************** + * MountCard + * + * Mounts the memory card in the given slot. + * Returns the result of the last attempted CARD_Mount command. + ***************************************************************************/ +int MountCard(int cslot, bool silent) +{ + int ret = -1; + int tries = 0; + + // Mount the card + while ( tries < 10 && ret != 0) + { + EXI_ProbeReset (); + ret = CARD_Mount (cslot, SysArea, NULL); + VIDEO_WaitVSync (); + tries++; + } + return ret; +} + + +/**************************************************************************** + * Verify Memory Card file against buffer + ***************************************************************************/ +int +VerifyMCFile (unsigned char *buf, int slot, char *filename, int datasize) +{ + int CardError; + unsigned int blocks; + unsigned int SectorSize; + char msg[80]; + int bytesleft = 0; + int bytesread = 0; + + /*** Initialize Card System ***/ + memset (SysArea, 0, CARD_WORKAREA); + CARD_Init ("SNES", "00"); + + /*** Try to mount the card ***/ + CardError = MountCard(slot, NOTSILENT); + + if (CardError == 0) + { + /*** Get Sector Size ***/ + CARD_GetSectorSize (slot, &SectorSize); + + if (!CardFileExists (filename, slot)) + { + CARD_Unmount (slot); + WaitPrompt((char*) "Unable to open file for verify!"); + return 0; + } + + memset (&CardFile, 0, sizeof (CardFile)); + CardError = CARD_Open (slot, filename, &CardFile); + + blocks = CardFile.len; + + if (blocks < SectorSize) + blocks = SectorSize; + + if (blocks % SectorSize) + blocks += SectorSize; + + if (blocks > (unsigned int)datasize) + blocks = datasize; + + memset (verifbuffer, 0, VERIFBUFFERSIZE); + bytesleft = blocks; + bytesread = 0; + while (bytesleft > 0) + { + CARD_Read (&CardFile, verifbuffer, SectorSize, bytesread); + if ( memcmp (buf + bytesread, verifbuffer, (unsigned int)bytesleft < SectorSize ? bytesleft : SectorSize) ) + { + CARD_Close (&CardFile); + CARD_Unmount (slot); + WaitPrompt((char*) "File did not verify!"); + return 0; + } + + bytesleft -= SectorSize; + bytesread += SectorSize; + + sprintf (msg, "Verified %d of %d bytes", bytesread, blocks); + ShowProgress (msg, bytesread, blocks); + } + CARD_Close (&CardFile); + CARD_Unmount (slot); + + return 1; + } + else + if (slot == CARD_SLOTA) + WaitPrompt((char*) "Unable to Mount Slot A Memory Card!"); + else + WaitPrompt((char*) "Unable to Mount Slot B Memory Card!"); + + return 0; +} + +/**************************************************************************** + * Load savebuffer from Memory Card file + ***************************************************************************/ +int +LoadBufferFromMC (unsigned char *buf, int slot, char *filename, bool silent) +{ + int CardError; + unsigned int blocks; + unsigned int SectorSize; + int bytesleft = 0; + int bytesread = 0; + + /*** Initialize Card System ***/ + memset (SysArea, 0, CARD_WORKAREA); + CARD_Init ("SNES", "00"); + + /*** Try to mount the card ***/ + CardError = MountCard(slot, NOTSILENT); + + if (CardError == 0) + { + /*** Get Sector Size ***/ + CARD_GetSectorSize (slot, &SectorSize); + + if (!CardFileExists (filename, slot)) + { + if (!silent) + WaitPrompt((char*) "Unable to open file"); + return 0; + } + + memset (&CardFile, 0, sizeof (CardFile)); + CardError = CARD_Open (slot, filename, &CardFile); + + blocks = CardFile.len; + + if (blocks < SectorSize) + blocks = SectorSize; + + if (blocks % SectorSize) + blocks += SectorSize; + + memset (buf, 0, 0x22000); + + bytesleft = blocks; + bytesread = 0; + while (bytesleft > 0) + { + CARD_Read (&CardFile, buf + bytesread, SectorSize, bytesread); + bytesleft -= SectorSize; + bytesread += SectorSize; + } + CARD_Close (&CardFile); + CARD_Unmount (slot); + } + else + if (slot == CARD_SLOTA) + WaitPrompt((char*) "Unable to Mount Slot A Memory Card!"); + else + WaitPrompt((char*) "Unable to Mount Slot B Memory Card!"); + + return bytesread; +} + + +/**************************************************************************** + * Write savebuffer to Memory Card file + ***************************************************************************/ +int +SaveBufferToMC (unsigned char *buf, int slot, char *filename, int datasize, bool silent) +{ + int CardError; + unsigned int blocks; + unsigned int SectorSize; + char msg[80]; + + /*** Initialize Card System ***/ + memset (SysArea, 0, CARD_WORKAREA); + CARD_Init ("SNES", "00"); + + /*** Try to mount the card ***/ + CardError = MountCard(slot, NOTSILENT); + + if (CardError == 0) + { + /*** Get Sector Size ***/ + CARD_GetSectorSize (slot, &SectorSize); + + if (datasize) + { + /*** Calculate number of blocks required ***/ + blocks = (datasize / SectorSize) * SectorSize; + if (datasize % SectorSize) + blocks += SectorSize; + + /*** Does this file exist ? ***/ + if (CardFileExists (filename, slot)) + { + /*** Try to open the file ***/ + CardError = CARD_Open (slot, filename, &CardFile); + if (CardError) + { + CARD_Unmount (slot); + WaitPrompt((char*) "Unable to open card file!"); + return 0; + } + + if ( (s32)blocks > CardFile.len ) /*** new data is longer ***/ + { + CARD_Close (&CardFile); + + /*** Try to create temp file to check available space ***/ + CardError = CARD_Create (slot, "TEMPFILESNES9XGX201", blocks, &CardFile); + if (CardError) + { + CARD_Unmount (slot); + WaitPrompt((char*) "Not enough space to update file!"); + return 0; + } + + /*** Delete the temporary file ***/ + CARD_Close (&CardFile); + CardError = CARD_Delete(slot, "TEMPFILESNES9XGX201"); + if (CardError) + { + CARD_Unmount (slot); + WaitPrompt((char*) "Unable to delete temporary file!"); + return 0; + } + + /*** Delete the existing shorter file ***/ + CardError = CARD_Delete(slot, filename); + if (CardError) + { + CARD_Unmount (slot); + WaitPrompt((char*) "Unable to delete existing file!"); + return 0; + } + + /*** Create new, longer file ***/ + CardError = CARD_Create (slot, filename, blocks, &CardFile); + if (CardError) + { + CARD_Unmount (slot); + WaitPrompt((char*) "Unable to create updated card file!"); + return 0; + } + } + } + else /*** no file existed, create new one ***/ + { + /*** Create new file ***/ + CardError = CARD_Create (slot, filename, blocks, &CardFile); + if (CardError) + { + CARD_Unmount (slot); + if ( CardError == CARD_ERROR_INSSPACE ) + WaitPrompt((char*) "Not enough space to create file!"); + else + WaitPrompt((char*) "Unable to create card file!"); + return 0; + } + } + + /*** Now, have an open file handle, ready to send out the data ***/ + CARD_GetStatus (slot, CardFile.filenum, &CardStatus); + CardStatus.icon_addr = 0x0; + CardStatus.icon_fmt = 2; + CardStatus.icon_speed = 1; + CardStatus.comment_addr = 2048; + CARD_SetStatus (slot, CardFile.filenum, &CardStatus); + + int byteswritten = 0; + int bytesleft = blocks; + while (bytesleft > 0) + { + CardError = + CARD_Write (&CardFile, buf + byteswritten, + SectorSize, byteswritten); + bytesleft -= SectorSize; + byteswritten += SectorSize; + + sprintf (msg, "Wrote %d of %d bytes", byteswritten, blocks); + ShowProgress (msg, byteswritten, blocks); + } + + CARD_Close (&CardFile); + CARD_Unmount (slot); + + if ( GCSettings.VerifySaves ) + { + /*** Verify the written file, but only up to the length we wrote + because the file could be longer due to past writes ***/ + if ( VerifyMCFile (buf, slot, filename, byteswritten) ) + return byteswritten; + else + return 0; + } + else + return byteswritten; + } + else + if ( !silent ) + WaitPrompt((char*) "This game does not appear to use SRAM"); + } + else + if (slot == CARD_SLOTA) + WaitPrompt((char*) "Unable to Mount Slot A Memory Card!"); + else + WaitPrompt((char*) "Unable to Mount Slot B Memory Card!"); + + return 0; + +} diff --git a/source/ngc/memcardop.h b/source/ngc/memcardop.h new file mode 100644 index 0000000..9cb2a91 --- /dev/null +++ b/source/ngc/memcardop.h @@ -0,0 +1,23 @@ +/**************************************************************************** + * Snes9x 1.51 Nintendo Wii/Gamecube Port + * + * softdev July 2006 + * crunchy2 May-June 2007 + * Tantric September 2008 + * + * memcardop.cpp + * + * Memory Card routines + ***************************************************************************/ + +#ifndef _NGCMCSAVE_ +#define _NGCMCSAVE_ + +int VerifyMCFile (unsigned char *buf, int slot, char *filename, int datasize); + +int LoadBufferFromMC (unsigned char *buf, int slot, char *filename, bool silent); +int SaveBufferToMC (unsigned char *buf, int slot, char *filename, int datasize, bool silent); +int MountCard(int cslot, bool silent); +bool TestCard(int slot, bool silent); + +#endif diff --git a/source/ngc/menu.cpp b/source/ngc/menu.cpp index ca99101..01cf18d 100644 --- a/source/ngc/menu.cpp +++ b/source/ngc/menu.cpp @@ -1,265 +1,731 @@ -/**************************************************************************** -* File Selection Menu -* -****************************************************************************/ -#include -#include -#include -#include -#include "sdfileio.h" - -extern GXRModeObj *vmode; /*** Graphics Mode Object ***/ -extern u32 *xfb[2]; /*** Framebuffers ***/ -extern int whichfb; /*** Frame buffer toggle ***/ - -/** Bits from SD lib **/ - -#define PAGE_SIZE 14 - -/*** Use OGC built in font ***/ -extern u8 console_font_8x16[]; - -static u32 forecolour = COLOR_WHITE; -static u32 backcolour = COLOR_BLACK; - -/**************************************************************************** -* MENU_DrawChar -****************************************************************************/ -void MENU_DrawChar( int x, int y, char c, int style ) -{ - u8 bits; - int offset; - int h,w; - u32 colour[2]; - u32 scroffs; - - offset = c << 4; - scroffs = ( y * 320 ) + ( x >> 1 ); - - for( h = 0; h < 16; h++ ) - { - bits = console_font_8x16[ offset++ ]; - - if ( style ) - { - for( w = 0; w < 8; w++ ) - { - xfb[whichfb][scroffs + w] = ( bits & 0x80 ) ? forecolour : backcolour; - bits <<= 1; - } - } - else - { - for( w = 0; w < 4; w++ ) - { - colour[0] = ( bits & 0x80 ) ? forecolour : backcolour; - colour[1] = ( bits & 0x40 ) ? forecolour : backcolour; - - xfb[whichfb][scroffs + w] = ( colour[0] & 0xFFFF00FF ) | ( colour[1] & 0x0000FF00 ); - bits <<= 2; - } - } - - scroffs += 320; - } -} - -/**************************************************************************** -* MENU_DrawString -****************************************************************************/ -void MENU_DrawString( int x, int y, char *msg, int style ) -{ - int i,len; - - /* Centred ? */ - if ( x == -1 ) - { - if ( style ) - x = strlen(msg) << 4; - else - x = strlen(msg) << 3; - - x = ( 640 - x ) >> 1; - } - if((int)strlen(msg) < 36) - len = (int)strlen(msg); - else - len = 36; - for ( i = 0; i < len; i++ ) - { - MENU_DrawChar(x,y,msg[i],style); - x += ( style ? 16 : 8 ); - } -} - -/**************************************************************************** -* MENU_Draw -****************************************************************************/ -int MENU_Draw( int max, int current, int offset ) -{ - int i; - int ypos = 30; - int xpos = 30; - - for ( i = offset; i < max && ( ( i - offset ) < PAGE_SIZE ); i++ ) - { - if ( i == current ) - { - forecolour = COLOR_BLACK; - backcolour = COLOR_WHITE; - } - else - { - forecolour = COLOR_WHITE; - backcolour = COLOR_BLACK; - } - MENU_DrawString( xpos, ypos, direntries[i], 1); - ypos += 16; - } -} -#ifdef WII_BUILD -#include -#include -extern int isClassicAvailable; -extern int isWiimoteAvailable; -extern void setup_controllers(); -#endif - -/**************************************************************************** -* MENU_GetLoadFile -* -* Returns the filename of the selected file -***************************************************************************/ -char *MENU_GetLoadFile( char *whichdir ) -{ - int count; - char *p = NULL; - int quit = 0; - int redraw = 1; - int current = 0; - int offset = 0; - u16 buttons; - int do_DOWN = 0; - int do_UP = 0; - int do_A = 0; - - count = gen_getdir( whichdir ); - - - if ( count == 0 ) - { - printf("No ROM files in %s\n", whichdir); - while(1); - } -#ifdef WII_BUILD - setup_controllers(); -#endif - if ( count == 1 ) - return (char*)direntries[0]; - - /* Do menu */ - while ( !quit ) - { - if ( redraw ) - { - whichfb ^= 1; - VIDEO_ClearFrameBuffer(vmode, xfb[whichfb], COLOR_BLACK); - MENU_Draw( count, current, offset ); - VIDEO_SetNextFramebuffer(xfb[whichfb]); - VIDEO_Flush(); - VIDEO_WaitVSync(); - redraw = 0; - } -#ifdef WII_BUILD - WPAD_ScanPads(); - WPADData *wpad; - wpad = WPAD_Data(0); - int b = wpad->exp.classic.btns; - unsigned short b1 = wpad->btns_d; - if (isClassicAvailable){ - if (b & CLASSIC_CTRL_BUTTON_DOWN){ - do_DOWN = 1; - do{WPAD_ScanPads(); wpad = WPAD_Data(0);} - while (WPAD_ButtonsHeld(0)); - } - else if (b & CLASSIC_CTRL_BUTTON_UP){ - do_UP = 1; - do{WPAD_ScanPads(); wpad = WPAD_Data(0);} - while (WPAD_ButtonsHeld(0)); - } - else if (b & CLASSIC_CTRL_BUTTON_A){ - do_A = 1; - do{WPAD_ScanPads(); wpad = WPAD_Data(0);} - while (WPAD_ButtonsHeld(0)); - } - } - if (isWiimoteAvailable){ - if (b1 & WPAD_BUTTON_LEFT){ - do_DOWN = 1; - do{WPAD_ScanPads(); wpad = WPAD_Data(0);} - while (WPAD_ButtonsHeld(0)); - } - else if (b1 & WPAD_BUTTON_RIGHT){ - do_UP = 1; - do{WPAD_ScanPads(); wpad = WPAD_Data(0);} - while (WPAD_ButtonsHeld(0)); - } - else if (b1 & WPAD_BUTTON_2){ - do_A = 1; - do{WPAD_ScanPads(); wpad = WPAD_Data(0);} - while (WPAD_ButtonsHeld(0)); - } - } -#endif - buttons = PAD_ButtonsDown(0); - if(buttons & PAD_BUTTON_DOWN) - do_DOWN = 1; - else if(buttons & PAD_BUTTON_UP) - do_UP = 1; - else if(buttons & PAD_BUTTON_A) - do_A = 1; - if (do_DOWN) - { - do_DOWN=0; - current++; - if ( current == count ) - current = 0; - - if ( ( current % PAGE_SIZE ) == 0 ) - offset = current; - - redraw = 1; - } - else - { - if ( do_UP ) - { - do_UP=0; - current--; - if ( current < 0 ) current = count - 1; - offset = ( current / PAGE_SIZE ) * PAGE_SIZE; - redraw = 1; - } - else - { - if ( do_A ) - { - do_A=0; - quit = 1; - p = (char*)direntries[current]; - } - } - } - } - - whichfb ^= 1; - VIDEO_ClearFrameBuffer(vmode, xfb[whichfb], COLOR_BLACK); - forecolour = COLOR_WHITE; - backcolour = COLOR_BLACK; - MENU_DrawString(-1, 240, "Loading ... Wait", 1); - VIDEO_SetNextFramebuffer(xfb[whichfb]); - VIDEO_Flush(); - VIDEO_WaitVSync(); - return p; -} - +/**************************************************************************** + * Snes9x 1.51 Nintendo Wii/Gamecube Port + * + * softdev July 2006 + * crunchy2 May-June 2007 + * Tantric August 2008 + * + * menu.cpp + * + * Menu flow routines - handles all menu logic + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#ifdef WII_DVD +extern "C" { +#include +} +#endif + +#include "vba.h" +#include "vbasupport.h" +#include "audio.h" +#include "video.h" +#include "filesel.h" +#include "gcunzip.h" +#include "smbop.h" +#include "memcardop.h" +#include "fileop.h" +#include "dvd.h" +#include "preferences.h" +#include "button_mapping.h" +#include "menudraw.h" +#include "input.h" + +extern "C" +{ +#include "tbtime.h" +} + +extern void DrawMenu (char items[][50], char *title, int maxitems, int selected, int fontsize); + +extern int menu; +extern int ROMSize; + +#define SOFTRESET_ADR ((volatile u32*)0xCC003024) + +/**************************************************************************** + * Reboot / Exit + ***************************************************************************/ + +#ifndef HW_RVL +#define PSOSDLOADID 0x7c6000a6 +int *psoid = (int *) 0x80001800; +void (*PSOReload) () = (void (*)()) 0x80001800; +#endif + +void Reboot() +{ +#ifdef HW_RVL + SYS_ResetSystem(SYS_RETURNTOMENU, 0, 0); +#else +#define SOFTRESET_ADR ((volatile u32*)0xCC003024) + *SOFTRESET_ADR = 0x00000000; +#endif +} + +/**************************************************************************** + * Load Manager + ***************************************************************************/ + +int +LoadManager () +{ + int loadROM = OpenROM(GCSettings.LoadMethod); + + /*** + * check for autoloadsram / freeze + ***/ + if ( loadROM == 1 ) // if ROM was loaded, load the SRAM & settings + { + //if ( GCSettings.AutoLoad == 1 ) + // LoadSRAM(GCSettings.SaveMethod, SILENT); + //else if ( GCSettings.AutoLoad == 2 ) + // NGCUnfreezeGame (GCSettings.SaveMethod, SILENT); + + // setup cheats + //SetupCheats(); + } + + return loadROM; +} + +/**************************************************************************** + * Preferences Menu + ***************************************************************************/ +static int prefmenuCount = 9; +static char prefmenu[][50] = { + + "Load Method", + "Load Folder", + "Save Method", + "Save Folder", + + "Auto Load", + "Auto Save", + "Verify MC Saves", + + "Save Preferences", + "Back to Main Menu" +}; + +void +PreferencesMenu () +{ + int ret = 0; + int quit = 0; + int oldmenu = menu; + menu = 0; + while (quit == 0) + { + // some load/save methods are not implemented - here's where we skip them + // they need to be skipped in the order they were enumerated in snes9xGX.h + + // no USB ports on GameCube + #ifndef HW_RVL + if(GCSettings.LoadMethod == METHOD_USB) + GCSettings.LoadMethod++; + if(GCSettings.SaveMethod == METHOD_USB) + GCSettings.SaveMethod++; + #endif + + // check if DVD access in Wii mode is disabled + #ifndef WII_DVD + if(GCSettings.LoadMethod == METHOD_DVD) + GCSettings.LoadMethod++; + #endif + + // saving to DVD is impossible + if(GCSettings.SaveMethod == METHOD_DVD) + GCSettings.SaveMethod++; + + // disable SMB in GC mode (stalls out) + #ifndef HW_RVL + if(GCSettings.LoadMethod == METHOD_SMB) + GCSettings.LoadMethod++; + if(GCSettings.SaveMethod == METHOD_SMB) + GCSettings.SaveMethod++; + #endif + + // disable MC saving in Wii mode - does not work for some reason! + #ifdef HW_RVL + if(GCSettings.SaveMethod == METHOD_MC_SLOTA) + GCSettings.SaveMethod++; + if(GCSettings.SaveMethod == METHOD_MC_SLOTB) + GCSettings.SaveMethod++; + #endif + + // correct load/save methods out of bounds + if(GCSettings.LoadMethod > 4) + GCSettings.LoadMethod = 0; + if(GCSettings.SaveMethod > 6) + GCSettings.SaveMethod = 0; + + if (GCSettings.LoadMethod == METHOD_AUTO) sprintf (prefmenu[0],"Load Method AUTO"); + else if (GCSettings.LoadMethod == METHOD_SD) sprintf (prefmenu[0],"Load Method SD"); + else if (GCSettings.LoadMethod == METHOD_USB) sprintf (prefmenu[0],"Load Method USB"); + else if (GCSettings.LoadMethod == METHOD_DVD) sprintf (prefmenu[0],"Load Method DVD"); + else if (GCSettings.LoadMethod == METHOD_SMB) sprintf (prefmenu[0],"Load Method Network"); + + sprintf (prefmenu[1], "Load Folder %s", GCSettings.LoadFolder); + + if (GCSettings.SaveMethod == METHOD_AUTO) sprintf (prefmenu[2],"Save Method AUTO"); + else if (GCSettings.SaveMethod == METHOD_SD) sprintf (prefmenu[2],"Save Method SD"); + else if (GCSettings.SaveMethod == METHOD_USB) sprintf (prefmenu[2],"Save Method USB"); + else if (GCSettings.SaveMethod == METHOD_SMB) sprintf (prefmenu[2],"Save Method Network"); + else if (GCSettings.SaveMethod == METHOD_MC_SLOTA) sprintf (prefmenu[2],"Save Method MC Slot A"); + else if (GCSettings.SaveMethod == METHOD_MC_SLOTB) sprintf (prefmenu[2],"Save Method MC Slot B"); + + sprintf (prefmenu[3], "Save Folder %s", GCSettings.SaveFolder); + + // disable changing load/save directories for now + prefmenu[1][0] = '\0'; + prefmenu[3][0] = '\0'; + + if (GCSettings.AutoLoad == 0) sprintf (prefmenu[4],"Auto Load OFF"); + else if (GCSettings.AutoLoad == 1) sprintf (prefmenu[4],"Auto Load SRAM"); + else if (GCSettings.AutoLoad == 2) sprintf (prefmenu[4],"Auto Load SNAPSHOT"); + + if (GCSettings.AutoSave == 0) sprintf (prefmenu[5],"Auto Save OFF"); + else if (GCSettings.AutoSave == 1) sprintf (prefmenu[5],"Auto Save SRAM"); + else if (GCSettings.AutoSave == 2) sprintf (prefmenu[5],"Auto Save SNAPSHOT"); + else if (GCSettings.AutoSave == 3) sprintf (prefmenu[5],"Auto Save BOTH"); + + sprintf (prefmenu[6], "Verify MC Saves %s", + GCSettings.VerifySaves == true ? " ON" : "OFF"); + + + ret = RunMenu (prefmenu, prefmenuCount, (char*)"Preferences", 16); + + switch (ret) + { + case 0: + GCSettings.LoadMethod ++; + break; + + case 1: + break; + + case 2: + GCSettings.SaveMethod ++; + break; + + case 3: + break; + + case 4: + GCSettings.AutoLoad ++; + if (GCSettings.AutoLoad > 2) + GCSettings.AutoLoad = 0; + break; + + case 5: + GCSettings.AutoSave ++; + if (GCSettings.AutoSave > 3) + GCSettings.AutoSave = 0; + break; + + case 6: + GCSettings.VerifySaves ^= 1; + break; + + case 7: + SavePrefs(GCSettings.SaveMethod, NOTSILENT); + break; + + case -1: /*** Button B ***/ + case 8: + quit = 1; + break; + + } + } + menu = oldmenu; +} + +/**************************************************************************** + * Game Options Menu + ***************************************************************************/ + +int +GameMenu () +{ + int gamemenuCount = 7; + char gamemenu[][50] = { + "Return to Game", + "Reset Game", + "Load SRAM", "Save SRAM", + "Load Game Snapshot", "Save Game Snapshot", + "Back to Main Menu" + }; + + int ret, retval = 0; + int quit = 0; + int oldmenu = menu; + menu = 0; + + while (quit == 0) + { + // disable SRAM/SNAPSHOT saving/loading if AUTO is on + + if (GCSettings.AutoLoad == 1) // Auto Load SRAM + gamemenu[2][0] = '\0'; + else if (GCSettings.AutoLoad == 2) // Auto Load SNAPSHOT + gamemenu[4][0] = '\0'; + + if (GCSettings.AutoSave == 1) // Auto Save SRAM + gamemenu[3][0] = '\0'; + else if (GCSettings.AutoSave == 2) // Auto Save SNAPSHOT + gamemenu[5][0] = '\0'; + else if (GCSettings.AutoSave == 3) // Auto Save BOTH + { + gamemenu[3][0] = '\0'; + gamemenu[5][0] = '\0'; + } + + ret = RunMenu (gamemenu, gamemenuCount, (char*)"Game Menu"); + + switch (ret) + { + case 0: // Return to Game + quit = retval = 1; + break; + + case 1: // Reset Game + emulator.emuReset(); + quit = retval = 1; + break; + + case 2: // Load SRAM + //quit = retval = LoadSRAM(GCSettings.SaveMethod, NOTSILENT); + break; + + case 3: // Save SRAM + //SaveSRAM(GCSettings.SaveMethod, NOTSILENT); + break; + + case 4: // Load Freeze + //quit = retval = NGCUnfreezeGame (GCSettings.SaveMethod, NOTSILENT); + break; + + case 5: // Save Freeze + //NGCFreezeGame (GCSettings.SaveMethod, NOTSILENT); + //emulator.emuWriteState(statename); + break; + + case -1: // Button B + case 6: // Return to previous menu + retval = 0; + quit = 1; + break; + } + } + + menu = oldmenu; + + return retval; +} + +/**************************************************************************** + * Controller Configuration + * + * Snes9x 1.51 uses a cmd system to work out which button has been pressed. + * Here, I simply move the designated value to the gcpadmaps array, which + * saves on updating the cmd sequences. + ***************************************************************************/ +u32 +GetInput (u16 ctrlr_type) +{ + //u32 exp_type; + u32 pressed; + pressed=0; + s8 gc_px = 0; + + while( PAD_ButtonsHeld(0) +#ifdef HW_RVL + | WPAD_ButtonsHeld(0) +#endif + ) VIDEO_WaitVSync(); // button 'debounce' + + while (pressed == 0) + { + VIDEO_WaitVSync(); + // get input based on controller type + if (ctrlr_type == CTRLR_GCPAD) + { + pressed = PAD_ButtonsHeld (0); + gc_px = PAD_SubStickX (0); + } +#ifdef HW_RVL + else + { + // if ( WPAD_Probe( 0, &exp_type) == 0) // check wiimote and expansion status (first if wiimote is connected & no errors) + // { + pressed = WPAD_ButtonsHeld (0); + + // if (ctrlr_type != CTRLR_WIIMOTE && exp_type != ctrlr_type+1) // if we need input from an expansion, and its not connected... + // pressed = 0; + // } + } +#endif + /*** check for exit sequence (c-stick left OR home button) ***/ + if ( (gc_px < -70) || (pressed & WPAD_BUTTON_HOME) || (pressed & WPAD_CLASSIC_BUTTON_HOME) ) + return 0; + } // end while + while( pressed == (PAD_ButtonsHeld(0) +#ifdef HW_RVL + | WPAD_ButtonsHeld(0) +#endif + ) ) VIDEO_WaitVSync(); + + return pressed; +} // end GetInput() + +int cfg_text_count = 7; +char cfg_text[][50] = { +"Remapping ", +"Press Any Button", +"on the", +" ", // identify controller +" ", +"Press C-Left or", +"Home to exit" +}; + +u32 +GetButtonMap(u16 ctrlr_type, char* btn_name) +{ + u32 pressed, previous; + char temp[50] = ""; + uint k; + pressed = 0; previous = 1; + + switch (ctrlr_type) { + case CTRLR_NUNCHUK: + strncpy (cfg_text[3], (char*)"NUNCHUK", 7); + break; + case CTRLR_CLASSIC: + strncpy (cfg_text[3], (char*)"CLASSIC", 7); + break; + case CTRLR_GCPAD: + strncpy (cfg_text[3], (char*)"GC PAD", 7); + break; + case CTRLR_WIIMOTE: + strncpy (cfg_text[3], (char*)"WIIMOTE", 7); + break; + }; + + /*** note which button we are remapping ***/ + sprintf (temp, (char*)"Remapping "); + for (k=0; k<9-strlen(btn_name); k++) strcat(temp, " "); // add whitespace padding to align text + strncat (temp, btn_name, 9); // snes button we are remapping + strncpy (cfg_text[0], temp, 19); // copy this all back to the text we wish to display + + DrawMenu(&cfg_text[0], NULL, cfg_text_count, 1); // display text + +// while (previous != pressed && pressed == 0); // get two consecutive button presses (which are the same) +// { +// previous = pressed; +// VIDEO_WaitVSync(); // slow things down a bit so we don't overread the pads + pressed = GetInput(ctrlr_type); +// } + return pressed; +} // end getButtonMap() + +int cfg_btns_count = 11; +char cfg_btns_menu[][50] = { + "A - ", + "B - ", + "L TRIG - ", + "R TRIG - ", + "SELECT - ", + "START - ", + "UP - ", + "DOWN - ", + "LEFT - ", + "RIGHT - ", + "Return to previous" +}; + +extern unsigned int gcpadmap[]; +extern unsigned int wmpadmap[]; +extern unsigned int ccpadmap[]; +extern unsigned int ncpadmap[]; + +void +ConfigureButtons (u16 ctrlr_type) +{ + int quit = 0; + int ret = 0; + int oldmenu = menu; + menu = 0; + char* menu_title = NULL; + u32 pressed; + + unsigned int* currentpadmap = 0; + char temp[50] = ""; + int i, j; + uint k; + + /*** Update Menu Title (based on controller we're configuring) ***/ + switch (ctrlr_type) { + case CTRLR_NUNCHUK: + menu_title = (char*)"VBA - NUNCHUK"; + currentpadmap = ncpadmap; + break; + case CTRLR_CLASSIC: + menu_title = (char*)"VBA - CLASSIC"; + currentpadmap = ccpadmap; + break; + case CTRLR_GCPAD: + menu_title = (char*)"VBA - GC PAD"; + currentpadmap = gcpadmap; + break; + case CTRLR_WIIMOTE: + menu_title = (char*)"VBA - WIIMOTE"; + currentpadmap = wmpadmap; + break; + }; + + while (quit == 0) + { + /*** Update Menu with Current ButtonMap ***/ + for (i=0; i<10; i++) // vba pad has 10 buttons to config (go thru them) + { + // get current padmap button name to display + for ( j=0; + j < ctrlr_def[ctrlr_type].num_btns && + currentpadmap[i] != ctrlr_def[ctrlr_type].map[j].btn // match padmap button press with button names + ; j++ ); + + memset (temp, 0, sizeof(temp)); + strncpy (temp, cfg_btns_menu[i], 12); // copy vba button information + if (currentpadmap[i] == ctrlr_def[ctrlr_type].map[j].btn) // check if a match was made + { + for (k=0; k<7-strlen(ctrlr_def[ctrlr_type].map[j].name) ;k++) strcat(temp, " "); // add whitespace padding to align text + strncat (temp, ctrlr_def[ctrlr_type].map[j].name, 6); // update button map display + } + else + strcat (temp, (char*)"---"); // otherwise, button is 'unmapped' + strncpy (cfg_btns_menu[i], temp, 19); // move back updated information + + } + + ret = RunMenu (cfg_btns_menu, cfg_btns_count, menu_title, 16); + + switch (ret) + { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + /*** Change button map ***/ + // wait for input + memset (temp, 0, sizeof(temp)); + strncpy(temp, cfg_btns_menu[ret], 6); // get the name of the vba button we're changing + pressed = GetButtonMap(ctrlr_type, temp); // get a button selection from user + // FIX: check if input is valid for this controller + if (pressed != 0) // check if a the button was configured, or if the user exited. + currentpadmap[ret] = pressed; // update mapping + break; + + case -1: /*** Button B ***/ + case 12: + /*** Return ***/ + quit = 1; + break; + } + } + menu = oldmenu; +} // end configurebuttons() + +int ctlrmenucount = 6; +char ctlrmenu[][50] = { + "Nunchuk", + "Classic Controller", + "Wiimote", + "Gamecube Pad", + "Save Preferences", + "Go Back" +}; + +void +ConfigureControllers () +{ + int quit = 0; + int ret = 0; + int oldmenu = menu; + menu = 0; + + // disable unavailable controller options if in GC mode + #ifndef HW_RVL + ctlrmenu[4][0] = '\0'; + ctlrmenu[5][0] = '\0'; + ctlrmenu[6][0] = '\0'; + #endif + + while (quit == 0) + { + + /*** Controller Config Menu ***/ + ret = RunMenu (ctlrmenu, ctlrmenucount, (char*)"Configure Controllers"); + + switch (ret) + { + + case 0: + /*** Configure Nunchuk ***/ + ConfigureButtons (CTRLR_NUNCHUK); + break; + + case 1: + /*** Configure Classic ***/ + ConfigureButtons (CTRLR_CLASSIC); + break; + + case 2: + /*** Configure Wiimote ***/ + ConfigureButtons (CTRLR_WIIMOTE); + break; + + case 3: + /*** Configure GC Pad ***/ + ConfigureButtons (CTRLR_GCPAD); + break; + + case 4: + /*** Save Preferences Now ***/ + SavePrefs(GCSettings.SaveMethod, NOTSILENT); + break; + + case -1: /*** Button B ***/ + case 5: + /*** Return ***/ + quit = 1; + break; + } + } + + menu = oldmenu; +} + +/**************************************************************************** + * Main Menu + ***************************************************************************/ +int menucount = 7; +char menuitems[][50] = { + "Choose Game", "Controller Configuration", "Preferences", + "Game Menu", + "Credits", "Reset System", "Return to Loader" +}; + +void +mainmenu (int selectedMenu) +{ + tb_t start,end; + mftb(&start); + StopAudio(); + + int quit = 0; + int ret; + + // disable game-specific menu items if a ROM isn't loaded + if (ROMSize == 0 ) + menuitems[3][0] = '\0'; + else + sprintf (menuitems[3], "Game Menu"); + + VIDEO_WaitVSync (); + + while (quit == 0) + { + if(selectedMenu >= 0) + { + ret = selectedMenu; + selectedMenu = -1; // default back to main menu + } + else + { + ret = RunMenu (menuitems, menucount, (char*)"Main Menu"); + } + + switch (ret) + { + case 0: + // Load ROM Menu + quit = LoadManager (); + break; + + case 1: + // Configure Controllers + ConfigureControllers (); + break; + + case 2: + // Preferences + PreferencesMenu (); + break; + + case 3: + // Game Options + quit = GameMenu (); + break; + + case 4: + // Credits + Credits (); + WaitButtonA (); + break; + + case 5: + // Reset the Gamecube/Wii + Reboot(); + break; + + case 6: + // Exit to Loader + #ifdef HW_RVL + #ifdef WII_DVD + DI_Close(); + #endif + exit(0); + #else // gamecube + if (psoid[0] == PSOSDLOADID) + PSOReload (); + #endif + break; + + case -1: // Button B + // Return to Game + quit = 1; + break; + } + } + + /*** Remove any still held buttons ***/ + #ifdef HW_RVL + while( PAD_ButtonsHeld(0) || WPAD_ButtonsHeld(0) ) + VIDEO_WaitVSync(); + #else + while( PAD_ButtonsHeld(0) ) + VIDEO_WaitVSync(); + #endif + + StartAudio(); + mftb(&end); + loadtimeradjust += tb_diff_msec(&end, &start); +} diff --git a/source/ngc/menu.h b/source/ngc/menu.h new file mode 100644 index 0000000..c7a02c2 --- /dev/null +++ b/source/ngc/menu.h @@ -0,0 +1,19 @@ +/**************************************************************************** + * Snes9x 1.51 Nintendo Wii/Gamecube Port + * + * softdev July 2006 + * crunchy2 May-June 2007 + * Tantric August 2008 + * + * menu.h + * + * Menu flow routines - handles all menu logic + ***************************************************************************/ + +#ifndef _NGCMENU_ + +#define _NGCMENU_ + +void mainmenu (int selectedMenu); + +#endif diff --git a/source/ngc/menudraw.cpp b/source/ngc/menudraw.cpp new file mode 100644 index 0000000..7efd6d2 --- /dev/null +++ b/source/ngc/menudraw.cpp @@ -0,0 +1,920 @@ +/**************************************************************************** + * Snes9x 1.51 Nintendo Wii/Gamecube Port + * + * softdev July 2006 + * crunchy2 June 2007 + * Tantric August 2008 + * + * menudraw.cpp + * + * Menu drawing routines + * + * Uses libfreetype 2.2.1 compiled for GC with TTF support only. + * TTF only reduces the library by some 900k bytes! + * + * **WARNING*** + * + * ONLY USE GUARANTEED PATENT FREE FONTS. + ***************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include FT_FREETYPE_H + +#include "video.h" +#include "menudraw.h" +#include "vba.h" +#include "filesel.h" +#include "dvd.h" +#include "input.h" + +/*** Globals ***/ +FT_Library ftlibrary; +FT_Face face; +FT_GlyphSlot slot; +FT_UInt glyph_index; +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; +#else +static u32 *backdrop; +#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, 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, (char*)"Credits"); + + int ypos = 25; + + if (screenheight == 480) + ypos += 52; + else + ypos += 32; + + setfontsize (18); + DrawText (-1, ypos += 30, (char*)"Technical"); + + setfontsize (14); + DrawText (-1, ypos += 22, (char*)"Snes9x v1.5.1 - Snes9x Team"); + DrawText (-1, ypos += 18, (char*)"GameCube Port 2.0 WIP6 and earlier - SoftDev"); + DrawText (-1, ypos += 18, (char*)"Additional improvements to 2.0 WIP6 - eke-eke"); + DrawText (-1, ypos += 18, (char*)"GameCube 2.0.1bx enhancements - crunchy2"); + DrawText (-1, ypos += 18, (char*)"v00x updates - michniewski & Tantric"); + DrawText (-1, ypos += 18, (char*)"GX - http://www.gc-linux.org"); + DrawText (-1, ypos += 18, (char*)"libogc - Shagkur & wintermute"); + + setfontsize (18); + DrawText (-1, ypos += 30, (char*)"Testing"); + + setfontsize (14); + DrawText (-1, ypos += 22, (char*)"crunchy2 / tehskeen users / others"); + + setfontsize (18); + DrawText (-1, ypos += 30, (char*)"Documentation"); + + setfontsize (14); + DrawText (-1, ypos += 22, (char*)"brakken, crunchy2, michniewski"); + + setfontsize (12); + DrawText (-1, ypos += 50, (char*)"Snes9x - Copyright (c) Snes9x Team 1996 - 2006"); + DrawText (-1, ypos += 15, (char*)"This software is open source and may be copied, distributed, or modified"); + DrawText (-1, ypos += 15, (char*)"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); +} + +/**************************************************************************** + * 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 (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, (char*)"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 (char *msg, char *bmsg, 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 (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], 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); + DrawText (510, screenheight - 20, VERSIONSTR); + + // 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, 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) + { + 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_StickY (0,0); + wp = WPAD_ButtonsDown (0); +#endif + + + 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) ) + { + 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) ) + { + redraw = 1; + 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 (FILEENTRIES filelist[], int maxfiles, int offset, int selection) +{ + int i, j; + char text[MAXPATHLEN]; + int ypos; + int w; + + clearscreen (); + + setfontsize (28); + DrawText (-1, 60, (char*)"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 (filelist[i].flags) // if a dir + { + strcpy (text, "["); + strcat (text, filelist[i].displayname); + strcat (text, "]"); + } + else + { + // hide file extension on listing (.7z, .fig, .smc) + StripExt(text, filelist[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, (char*)"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 (); +} + + +/**************************************************************************** + * 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 (char *msg, int done, int total) +{ + int ypos = (screenheight - 30) >> 1; + + if (screenheight == 480) + ypos += 52; + else + ypos += 32; + + int xpos; + int i; + + clearscreen (); + 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); + + 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 ); + +} diff --git a/source/ngc/menudraw.h b/source/ngc/menudraw.h new file mode 100644 index 0000000..81621f9 --- /dev/null +++ b/source/ngc/menudraw.h @@ -0,0 +1,46 @@ +/**************************************************************************** + * Snes9x 1.51 Nintendo Wii/Gamecube Port + * + * softdev July 2006 + * crunchy2 June 2007 + * Tantric August 2008 + * + * menudraw.h + * + * Menu drawing routines + * + * Uses libfreetype 2.2.1 compiled for GC with TTF support only. + * TTF only reduces the library by some 900k bytes! + * + * **WARNING*** + * + * ONLY USE GUARANTEED PATENT FREE FONTS. + ***************************************************************************/ +#ifndef _NGCMENUDRAW_ +#define _NGCMENUDRAW_ + +#include "filesel.h" + +#define PAGESIZE 17 // max item listing on a screen + +int FT_Init (); +void setfontsize (int pixelsize); +void setfontcolour (u8 r, u8 g, u8 b); +void DrawText (int x, int y, char *text); +void unpackbackdrop (); +void Credits (); +void RomInfo (); +void WaitButtonA (); +int RunMenu (char items[][50], int maxitems, char *title, int fontsize = 20, int x = -1); +void DrawMenu (char items[][50], char *title, int maxitems, int selected, int fontsize = 20, int x = -1); +void ShowCheats (char items[][50], char itemvalues[][50], int maxitems, int offset, int selection); +void ShowFiles (FILEENTRIES filelist[], int maxfiles, int offset, int selection); + +void WaitPrompt (char *msg); +int WaitPromptChoice (char *msg, char* bmsg, char* amsg); +void ShowAction (char *msg); +void ShowProgress (char *msg, int done, int total); +void DrawPolygon (int vertices, int *varray, u8 r, u8 g, u8 b); +void DrawLineFast( int startx, int endx, int y, u8 r, u8 g, u8 b ); + +#endif diff --git a/source/ngc/preferences.cpp b/source/ngc/preferences.cpp new file mode 100644 index 0000000..ec81a7b --- /dev/null +++ b/source/ngc/preferences.cpp @@ -0,0 +1,392 @@ +/**************************************************************************** + * Snes9x 1.51 Nintendo Wii/Gamecube Port + * + * Tantric September 2008 + * + * preferences.cpp + * + * Preferences save/load to XML file + ***************************************************************************/ + +#include +#include +#include +#include +#include + +#include "vba.h" +#include "images/saveicon.h" +#include "menudraw.h" +#include "memcardop.h" +#include "fileop.h" +#include "smbop.h" +#include "filesel.h" + +extern unsigned char savebuffer[]; +extern int currconfig[4]; + +// button map configurations +extern unsigned int gcpadmap[]; +extern unsigned int wmpadmap[]; +extern unsigned int ccpadmap[]; +extern unsigned int ncpadmap[]; + +#define PREFS_FILE_NAME "SNES9xGX.xml" + +char prefscomment[2][32]; + +/**************************************************************************** + * Prepare Preferences Data + * + * This sets up the save buffer for saving. + ***************************************************************************/ +mxml_node_t *xml; +mxml_node_t *data; +mxml_node_t *section; +mxml_node_t *item; +mxml_node_t *elem; + +char temp[200]; + +const char * toStr(int i) +{ + sprintf(temp, "%d", i); + return temp; +} + +void createXMLSection(const char * name, const char * description) +{ + section = mxmlNewElement(data, "section"); + mxmlElementSetAttr(section, "name", name); + mxmlElementSetAttr(section, "description", description); +} + +void createXMLSetting(const char * name, const char * description, const char * value) +{ + item = mxmlNewElement(section, "setting"); + mxmlElementSetAttr(item, "name", name); + mxmlElementSetAttr(item, "value", value); + mxmlElementSetAttr(item, "description", description); +} + +void createXMLController(unsigned int controller[], const char * name, const char * description) +{ + item = mxmlNewElement(section, "controller"); + mxmlElementSetAttr(item, "name", name); + mxmlElementSetAttr(item, "description", description); + + // create buttons + for(int i=0; i < 12; i++) + { + elem = mxmlNewElement(item, "button"); + mxmlElementSetAttr(elem, "number", toStr(i)); + mxmlElementSetAttr(elem, "assignment", toStr(controller[i])); + } +} + +const char * XMLSaveCallback(mxml_node_t *node, int where) +{ + const char *name; + + name = node->value.element.name; + + if(where == MXML_WS_BEFORE_CLOSE) + { + if(!strcmp(name, "file") || !strcmp(name, "section")) + return ("\n"); + else if(!strcmp(name, "controller")) + return ("\n\t"); + } + if (where == MXML_WS_BEFORE_OPEN) + { + if(!strcmp(name, "file")) + return ("\n"); + else if(!strcmp(name, "section")) + return ("\n\n"); + else if(!strcmp(name, "setting") || !strcmp(name, "controller")) + return ("\n\t"); + else if(!strcmp(name, "button")) + return ("\n\t\t"); + } + return (NULL); +} + + +int +preparePrefsData (int method) +{ + int offset = 0; + memset (savebuffer, 0, SAVEBUFFERSIZE); + + // add save icon and comments for Memory Card saves + if(method == METHOD_MC_SLOTA || method == METHOD_MC_SLOTB) + { + offset = sizeof (saveicon); + + // Copy in save icon + memcpy (savebuffer, saveicon, offset); + + // And the comments + sprintf (prefscomment[0], "%s Prefs", VERSIONSTR); + sprintf (prefscomment[1], "Preferences"); + memcpy (savebuffer + offset, prefscomment, 64); + offset += 64; + } + + xml = mxmlNewXML("1.0"); + mxmlSetWrapMargin(0); // disable line wrapping + + data = mxmlNewElement(xml, "file"); + mxmlElementSetAttr(data, "version",VERSIONSTR); + + createXMLSection("File", "File Settings"); + + createXMLSetting("AutoLoad", "Auto Load", toStr(GCSettings.AutoLoad)); + createXMLSetting("AutoSave", "Auto Save", toStr(GCSettings.AutoSave)); + createXMLSetting("LoadMethod", "Load Method", toStr(GCSettings.LoadMethod)); + createXMLSetting("SaveMethod", "Save Method", toStr(GCSettings.SaveMethod)); + createXMLSetting("LoadFolder", "Load Folder", GCSettings.LoadFolder); + createXMLSetting("SaveFolder", "Save Folder", GCSettings.SaveFolder); + createXMLSetting("CheatFolder", "Cheats Folder", GCSettings.CheatFolder); + createXMLSetting("VerifySaves", "Verify Memory Card Saves", toStr(GCSettings.VerifySaves)); + + createXMLSection("Network", "Network Settings"); + + createXMLSetting("smbip", "Share Computer IP", GCSettings.smbip); + createXMLSetting("smbshare", "Share Name", GCSettings.smbshare); + createXMLSetting("smbuser", "Share Username", GCSettings.smbuser); + createXMLSetting("smbpwd", "Share Password", GCSettings.smbpwd); + + createXMLSection("Emulation", "Emulation Settings"); + + createXMLSection("Controller", "Controller Settings"); + + createXMLController(gcpadmap, "gcpadmap", "GameCube Pad"); + createXMLController(wmpadmap, "wmpadmap", "Wiimote"); + createXMLController(ccpadmap, "ccpadmap", "Classic Controller"); + createXMLController(ncpadmap, "ncpadmap", "Nunchuk"); + + int datasize = mxmlSaveString(xml, (char *)savebuffer, SAVEBUFFERSIZE, XMLSaveCallback); + + mxmlDelete(xml); + + return datasize; +} + + +/**************************************************************************** + * loadXMLSetting + * + * Load XML elements into variables for an individual variable + ***************************************************************************/ + +void loadXMLSetting(char * var, const char * name) +{ + item = mxmlFindElement(xml, xml, "setting", "name", name, MXML_DESCEND); + if(item) + sprintf(var, "%s", mxmlElementGetAttr(item, "value")); +} +void loadXMLSetting(int * var, const char * name) +{ + item = mxmlFindElement(xml, xml, "setting", "name", name, MXML_DESCEND); + if(item) + *var = atoi(mxmlElementGetAttr(item, "value")); +} +void loadXMLSetting(bool * var, const char * name) +{ + item = mxmlFindElement(xml, xml, "setting", "name", name, MXML_DESCEND); + if(item) + *var = atoi(mxmlElementGetAttr(item, "value")); +} + +/**************************************************************************** + * loadXMLController + * + * Load XML elements into variables for a controller mapping + ***************************************************************************/ + +void loadXMLController(unsigned int controller[], const char * name) +{ + item = mxmlFindElement(xml, xml, "controller", "name", name, MXML_DESCEND); + + if(item) + { + // populate buttons + for(int i=0; i < 12; i++) + { + elem = mxmlFindElement(item, xml, "button", "number", toStr(i), MXML_DESCEND); + if(elem) + controller[i] = atoi(mxmlElementGetAttr(elem, "assignment")); + } + } +} + +/**************************************************************************** + * decodePrefsData + * + * Decodes preferences - parses XML and loads preferences into the variables + ***************************************************************************/ + +bool +decodePrefsData (int method) +{ + int offset = 0; + + // skip save icon and comments for Memory Card saves + if(method == METHOD_MC_SLOTA || method == METHOD_MC_SLOTB) + { + offset = sizeof (saveicon); + offset += 64; // sizeof prefscomment + } + + xml = mxmlLoadString(NULL, (char *)savebuffer+offset, MXML_TEXT_CALLBACK); + + // check settings version + // we don't do anything with the version #, but we'll store it anyway + char * version; + item = mxmlFindElement(xml, xml, "file", "version", NULL, MXML_DESCEND); + if(item) // a version entry exists + version = (char *)mxmlElementGetAttr(item, "version"); + else // version # not found, must be invalid + return false; + + // File Settings + + loadXMLSetting(&GCSettings.AutoLoad, "AutoLoad"); + loadXMLSetting(&GCSettings.AutoSave, "AutoSave"); + loadXMLSetting(&GCSettings.LoadMethod, "LoadMethod"); + loadXMLSetting(&GCSettings.SaveMethod, "SaveMethod"); + loadXMLSetting(GCSettings.LoadFolder, "LoadFolder"); + loadXMLSetting(GCSettings.SaveFolder, "SaveFolder"); + loadXMLSetting(GCSettings.CheatFolder, "CheatFolder"); + loadXMLSetting(&GCSettings.VerifySaves, "VerifySaves"); + + // Network Settings + + loadXMLSetting(GCSettings.smbip, "smbip"); + loadXMLSetting(GCSettings.smbshare, "smbshare"); + loadXMLSetting(GCSettings.smbuser, "smbuser"); + loadXMLSetting(GCSettings.smbpwd, "smbpwd"); + + // Emulation Settings + + // Controller Settings + + loadXMLController(gcpadmap, "gcpadmap"); + loadXMLController(wmpadmap, "wmpadmap"); + loadXMLController(ccpadmap, "ccpadmap"); + loadXMLController(ncpadmap, "ncpadmap"); + + mxmlDelete(xml); + + return true; +} + +/**************************************************************************** + * Save Preferences + ***************************************************************************/ +bool +SavePrefs (int method, bool silent) +{ + if(method == METHOD_AUTO) + method = autoSaveMethod(); + + char filepath[1024]; + int datasize; + int offset = 0; + + datasize = preparePrefsData (method); + + if (!silent) + ShowAction ((char*) "Saving preferences..."); + + if(method == METHOD_SD || method == METHOD_USB) + { + if(ChangeFATInterface(method, NOTSILENT)) + { + sprintf (filepath, "%s/%s/%s", ROOTFATDIR, GCSettings.SaveFolder, PREFS_FILE_NAME); + offset = SaveBufferToFAT (filepath, datasize, silent); + } + } + else if(method == METHOD_SMB) + { + sprintf (filepath, "%s/%s", GCSettings.SaveFolder, PREFS_FILE_NAME); + offset = SaveBufferToSMB (filepath, datasize, silent); + } + else if(method == METHOD_MC_SLOTA) + { + offset = SaveBufferToMC (savebuffer, CARD_SLOTA, (char *)PREFS_FILE_NAME, datasize, silent); + } + else if(method == METHOD_MC_SLOTB) + { + offset = SaveBufferToMC (savebuffer, CARD_SLOTB, (char *)PREFS_FILE_NAME, datasize, silent); + } + + if (offset > 0) + { + if (!silent) + WaitPrompt ((char *)"Preferences saved"); + return true; + } + return false; +} + +/**************************************************************************** + * Load Preferences from specified method + ***************************************************************************/ +bool +LoadPrefsFromMethod (int method) +{ + bool retval = false; + char filepath[1024]; + int offset = 0; + + if(method == METHOD_SD || method == METHOD_USB) + { + if(ChangeFATInterface(method, NOTSILENT)) + { + sprintf (filepath, "%s/%s/%s", ROOTFATDIR, GCSettings.SaveFolder, PREFS_FILE_NAME); + offset = LoadBufferFromFAT (filepath, SILENT); + } + } + else if(method == METHOD_SMB) + { + sprintf (filepath, "%s/%s", GCSettings.SaveFolder, PREFS_FILE_NAME); + offset = LoadBufferFromSMB (filepath, SILENT); + } + else if(method == METHOD_MC_SLOTA) + { + offset = LoadBufferFromMC (savebuffer, CARD_SLOTA, (char *)PREFS_FILE_NAME, SILENT); + } + else if(method == METHOD_MC_SLOTB) + { + offset = LoadBufferFromMC (savebuffer, CARD_SLOTB, (char *)PREFS_FILE_NAME, SILENT); + } + + if (offset > 0) + retval = decodePrefsData (method); + + return retval; +} + +/**************************************************************************** + * Load Preferences + * Checks sources consecutively until we find a preference file + ***************************************************************************/ +bool LoadPrefs() +{ + ShowAction ((char*) "Loading preferences..."); + bool prefFound = false; + if(ChangeFATInterface(METHOD_SD, SILENT)) + prefFound = LoadPrefsFromMethod(METHOD_SD); + if(!prefFound && ChangeFATInterface(METHOD_USB, SILENT)) + prefFound = LoadPrefsFromMethod(METHOD_USB); + if(!prefFound && TestCard(CARD_SLOTA, SILENT)) + prefFound = LoadPrefsFromMethod(METHOD_MC_SLOTA); + if(!prefFound && TestCard(CARD_SLOTB, SILENT)) + prefFound = LoadPrefsFromMethod(METHOD_MC_SLOTB); + if(!prefFound && ConnectShare (SILENT)) + prefFound = LoadPrefsFromMethod(METHOD_SMB); + + return prefFound; +} diff --git a/source/ngc/preferences.h b/source/ngc/preferences.h new file mode 100644 index 0000000..ff83c32 --- /dev/null +++ b/source/ngc/preferences.h @@ -0,0 +1,12 @@ +/**************************************************************************** + * Snes9x 1.51 Nintendo Wii/Gamecube Port + * + * Tantric September 2008 + * + * preferences.h + * + * Preferences save/load to XML file + ***************************************************************************/ + +bool SavePrefs (int method, bool silent); +bool LoadPrefs (); diff --git a/source/ngc/sdfileio.c b/source/ngc/sdfileio.c index 058467e..c474f53 100644 --- a/source/ngc/sdfileio.c +++ b/source/ngc/sdfileio.c @@ -50,7 +50,7 @@ int gen_fread( void *buffer, int len, int block, FILE* f ) * SD Card fclose */ void gen_fclose( FILE* f ) -{ +{ fclose(f); } @@ -73,7 +73,7 @@ int gen_fgetc( FILE* f ) return fgetc(f); } -static struct stat _fstat; +static struct stat _fstat; char filename[1024]; int fcount = 0; @@ -83,15 +83,15 @@ int fcount = 0; int gen_getdir( char *thisdir ) { memset(&direntries[0],0,MAXDIRENTRIES*255); - + DIR_ITER* dp = diropen( thisdir ); - + if ( dp ) { while ( dirnext(dp, filename, &_fstat) == 0 ) { - - // Skip any sub directories + + // Skip any sub directories if ( !(_fstat.st_mode & S_IFDIR) ) { memcpy(&direntries[fcount],&filename,strlen(filename)); @@ -100,9 +100,9 @@ int gen_getdir( char *thisdir ) } dirclose(dp); } - else + else return 0; - + return fcount; diff --git a/source/ngc/smbop.cpp b/source/ngc/smbop.cpp new file mode 100644 index 0000000..5cf7330 --- /dev/null +++ b/source/ngc/smbop.cpp @@ -0,0 +1,339 @@ +/**************************************************************************** + * Snes9x 1.51 Nintendo Wii/Gamecube Port + * + * softdev July 2006 + * crunchy2 May 2007 + * Tantric August 2008 + * + * smbload.cpp + * + * SMB support routines + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vba.h" +#include "smbop.h" +#include "gcunzip.h" +#include "video.h" +#include "menudraw.h" +#include "filesel.h" + +bool networkInit = false; +bool networkShareInit = false; +unsigned int SMBTimer = 0; +#define SMBTIMEOUT ( 3600 ) // Some implementations timeout in 10 minutes + +SMBCONN smbconn; +#define ZIPCHUNK 16384 + +extern unsigned char savebuffer[]; +extern char output[16384]; +extern int offset; +extern int selection; +extern char currentdir[MAXPATHLEN]; +extern FILEENTRIES filelist[MAXFILES]; + + +/**************************************************************************** + * InitializeNetwork + * Initializes the Wii/GameCube network interface + ****************************************************************************/ + +bool InitializeNetwork(bool silent) +{ + ShowAction ((char*) "Initializing network..."); + s32 result; + + while ((result = net_init()) == -EAGAIN); + + if (result >= 0) + { + char myIP[16]; + + if (if_config(myIP, NULL, NULL, true) < 0) + { + if(!silent) + WaitPrompt((char*) "Error reading IP address."); + return false; + } + else + { + return true; + } + } + + if(!silent) + WaitPrompt((char*) "Unable to initialize network."); + return false; +} + +/**************************************************************************** + * Mount SMB Share + ****************************************************************************/ + +bool +ConnectShare (bool silent) +{ + // Crashes or stalls system in GameCube mode - so disable + #ifndef HW_RVL + return false; + #endif + + // check that all parameter have been set + if(strlen(GCSettings.smbuser) == 0 || + strlen(GCSettings.smbpwd) == 0 || + strlen(GCSettings.smbshare) == 0 || + strlen(GCSettings.smbip) == 0) + { + if(!silent) + WaitPrompt((char*) "Invalid network settings. Check SNES9xGX.xml."); + return false; + } + + if(!networkInit) + networkInit = InitializeNetwork(silent); + + if(networkInit) + { + // connection may have expired + if (networkShareInit && SMBTimer > SMBTIMEOUT) + { + networkShareInit = false; + SMBTimer = 0; + SMB_Close(smbconn); + } + + if(!networkShareInit) + { + if(!silent) + ShowAction ((char*) "Connecting to network share..."); + + if(SMB_Connect(&smbconn, GCSettings.smbuser, GCSettings.smbpwd, + GCSettings.smbgcid, GCSettings.smbsvid, GCSettings.smbshare, GCSettings.smbip) == SMB_SUCCESS) + networkShareInit = true; + } + + if(!networkShareInit && !silent) + WaitPrompt ((char*) "Failed to connect to network share."); + } + + return networkShareInit; +} + +/**************************************************************************** + * SMBPath + * + * Returns a SMB-style path + *****************************************************************************/ + +char * SMBPath(char * path) +{ + // fix path - replace all '/' with '\' + for(uint i=0; i < strlen(path); i++) + if(path[i] == '/') + path[i] = '\\'; + + return path; +} + +/**************************************************************************** + * parseSMBDirectory + * + * Load the directory and put in the filelist array + *****************************************************************************/ +int +ParseSMBdirectory () +{ + if(!ConnectShare (NOTSILENT)) + return 0; + + int filecount = 0; + char searchpath[1024]; + SMBDIRENTRY smbdir; + + // initialize selection + selection = offset = 0; + + // Clear any existing values + memset (&filelist, 0, sizeof (FILEENTRIES) * MAXFILES); + + if(strlen(currentdir) <= 1) // root + sprintf(searchpath, "*"); + else + sprintf(searchpath, "%s/*", currentdir); + + if (SMB_FindFirst + (SMBPath(searchpath), SMB_SRCH_READONLY | SMB_SRCH_DIRECTORY, &smbdir, smbconn) != SMB_SUCCESS) + { + char msg[200]; + sprintf(msg, "Could not open %s", currentdir); + WaitPrompt (msg); + + // if we can't open the dir, open root dir + sprintf(searchpath, "/"); + sprintf(searchpath,"*"); + + if (SMB_FindFirst + (SMBPath(searchpath), SMB_SRCH_READONLY | SMB_SRCH_DIRECTORY, &smbdir, smbconn) != SMB_SUCCESS) + return 0; + } + + // index files/folders + do + { + if(strcmp(smbdir.name,".") != 0 && + !(strlen(currentdir) <= 1 && strcmp(smbdir.name,"..") == 0)) + { + memset (&filelist[filecount], 0, sizeof (FILEENTRIES)); + filelist[filecount].length = smbdir.size_low; + smbdir.name[MAXJOLIET] = 0; + + if(smbdir.attributes == SMB_SRCH_DIRECTORY) + filelist[filecount].flags = 1; // flag this as a dir + else + filelist[filecount].flags = 0; + + // Update display name + memcpy (&filelist[filecount].displayname, smbdir.name, MAXDISPLAY); + filelist[filecount].displayname[MAXDISPLAY] = 0; + + strcpy (filelist[filecount].filename, smbdir.name); + filecount++; + } + } while (SMB_FindNext (&smbdir, smbconn) == SMB_SUCCESS); + + // close directory + SMB_FindClose (smbconn); + + // Sort the file list + qsort(filelist, filecount, sizeof(FILEENTRIES), FileSortCallback); + + return filecount; +} + +/**************************************************************************** + * Load SMB file + ****************************************************************************/ +int +LoadSMBFile (char *filename, int length) +{ + char filepath[MAXPATHLEN]; + + /* Check filename length */ + if ((strlen(currentdir)+1+strlen(filelist[selection].filename)) < MAXPATHLEN) + sprintf(filepath, "%s/%s",currentdir,filelist[selection].filename); + else + { + WaitPrompt((char*) "Maximum filepath length reached!"); + return -1; + } + return 0; + //return LoadBufferFromSMB((char *)Memory.ROM, SMBPath(filepath), NOTSILENT); +} + +/**************************************************************************** + * Write savebuffer to SMB file + ****************************************************************************/ +int +SaveBufferToSMB (char *filepath, int datasize, bool silent) +{ + if(!ConnectShare (NOTSILENT)) + return 0; + + SMBFILE smbfile; + int dsize = datasize; + int wrote = 0; + int boffset = 0; + + smbfile = + SMB_OpenFile (SMBPath(filepath), SMB_OPEN_WRITING | SMB_DENY_NONE, + SMB_OF_CREATE | SMB_OF_TRUNCATE, smbconn); + + if (smbfile) + { + while (dsize > 0) + { + if (dsize > 1024) + wrote = + SMB_WriteFile ((char *) savebuffer + boffset, 1024, boffset, smbfile); + else + wrote = + SMB_WriteFile ((char *) savebuffer + boffset, dsize, boffset, smbfile); + + boffset += wrote; + dsize -= wrote; + } + SMB_CloseFile (smbfile); + } + else + { + char msg[100]; + sprintf(msg, "Couldn't save SMB: %s", SMBPath(filepath)); + WaitPrompt (msg); + } + + ClearSaveBuffer (); + return boffset; +} + +/**************************************************************************** + * Load up a buffer from SMB file + ****************************************************************************/ + +// no buffer is specified - so use savebuffer +int +LoadBufferFromSMB (char *filepath, bool silent) +{ + ClearSaveBuffer (); + return LoadBufferFromSMB((char *)savebuffer, filepath, silent); +} + +int +LoadBufferFromSMB (char * sbuffer, char *filepath, bool silent) +{ + if(!ConnectShare (NOTSILENT)) + return 0; + + SMBFILE smbfile; + int ret; + int boffset = 0; + + smbfile = + SMB_OpenFile (SMBPath(filepath), SMB_OPEN_READING, SMB_OF_OPEN, smbconn); + + if (!smbfile) + { + if(!silent) + { + char msg[100]; + sprintf(msg, "Couldn't open SMB: %s", SMBPath(filepath)); + WaitPrompt (msg); + } + return 0; + } + + ret = SMB_ReadFile (sbuffer, 1024, boffset, smbfile); + + if (IsZipFile (sbuffer)) + { + boffset = UnZipFile ((unsigned char *)sbuffer, smbfile); // unzip from SMB + } + else + { + // Just load the file up + while ((ret = SMB_ReadFile (sbuffer + boffset, 1024, boffset, smbfile)) > 0) + boffset += ret; + } + SMB_CloseFile (smbfile); + + return boffset; +} diff --git a/source/ngc/smbop.h b/source/ngc/smbop.h new file mode 100644 index 0000000..d23e7b0 --- /dev/null +++ b/source/ngc/smbop.h @@ -0,0 +1,27 @@ +/**************************************************************************** + * Snes9x 1.51 Nintendo Wii/Gamecube Port + * + * softdev July 2006 + * crunchy2 May 2007 + * Tantric August 2008 + * + * smbload.h + * + * SMB support routines + ****************************************************************************/ + +#ifndef _NGCSMB_ + +#define _NGCSMB_ + +bool InitializeNetwork(bool silent); +bool ConnectShare (bool silent); +char * SMBPath(char * path); +int UpdateSMBdirname(); +int ParseSMBdirectory (); +int LoadSMBFile (char *filename, int length); +int LoadBufferFromSMB (char *filepath, bool silent); +int LoadBufferFromSMB (char * sbuffer, char *filepath, bool silent); +int SaveBufferToSMB (char *filepath, int datasize, bool silent); + +#endif diff --git a/source/ngc/tbtime.h b/source/ngc/tbtime.h index fac67aa..779702e 100644 --- a/source/ngc/tbtime.h +++ b/source/ngc/tbtime.h @@ -3,10 +3,9 @@ ****************************************************************************/ #ifndef __TMBINCTIMER__ #define __TMBINCTIMER__ -#ifdef WII_BUILD +#ifdef HW_RVL #define TB_CLOCK 60750000 //WII -#endif -#ifdef GC_BUILD +#else #define TB_CLOCK 40500000 #endif #define mftb(rval) ({unsigned long u; do { \ diff --git a/source/ngc/vba.cpp b/source/ngc/vba.cpp new file mode 100644 index 0000000..370052c --- /dev/null +++ b/source/ngc/vba.cpp @@ -0,0 +1,107 @@ +/**************************************************************************** +* VisualBoyAdvance 1.7.2 +* Nintendo GameCube Wrapper +****************************************************************************/ + + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#ifdef WII_DVD +extern "C" { +#include +} +#endif + +#include "vbasupport.h" +#include "audio.h" +#include "dvd.h" +#include "smbop.h" +#include "menu.h" +#include "menudraw.h" +#include "input.h" +#include "video.h" +#include "vbaconfig.h" + +extern int ROMSize; +extern int emulating; + + +/**************************************************************************** +* main +* +* Program entry +****************************************************************************/ +int main() +{ +#ifdef WII_DVD + DI_Init(); // first +#endif + + int selectedMenu = -1; + + PAD_Init (); /*** Initialise pads for input ***/ + #ifdef HW_RVL + WPAD_Init(); + // read wiimote accelerometer and IR data + WPAD_SetDataFormat(WPAD_CHAN_ALL,WPAD_FMT_BTNS_ACC_IR); + WPAD_SetVRes(WPAD_CHAN_ALL,640,480); + #endif + + InitialiseVideo(); + + // Initialise freetype font system + if (FT_Init ()) + { + printf ("Cannot initialise font subsystem!\n"); + while (1); + } + + // Initialize libFAT for SD and USB + fatInitDefault(); + + // Initialize DVD subsystem (GameCube only) + #ifndef HW_RVL + DVD_Init (); + #endif + + // Check if DVD drive belongs to a Wii + SetDVDDriveType(); + + InitialiseSound(); + + InitialisePalette(); + + // Set defaults + DefaultSettings (); + + while (ROMSize == 0) + { + mainmenu (selectedMenu); + } + + //Main loop + while(1) + { + while (emulating) + { + emulator.emuMain(emulator.emuCount); + } + } + + // Never leaving here + while(1); + + return 0; +} + diff --git a/source/ngc/vba.h b/source/ngc/vba.h new file mode 100644 index 0000000..897b752 --- /dev/null +++ b/source/ngc/vba.h @@ -0,0 +1,56 @@ +/**************************************************************************** + * Snes9x 1.51 Nintendo Wii/Gamecube Port + * + * softdev July 2006 + * crunchy2 May 2007-July 2007 + * Tantric September 2008 + * + * snes9xGX.h + * + * This file controls overall program flow. Most things start and end here! + ***************************************************************************/ + +#ifndef _VBA_H_ +#define _VBA_H_ + +#include + +#define VERSIONNUM "1.0.0" +#define VERSIONSTR "VBA 1.0.0" + +#define NOTSILENT 0 +#define SILENT 1 + +enum { + METHOD_AUTO, + METHOD_SD, + METHOD_USB, + METHOD_DVD, + METHOD_SMB, + METHOD_MC_SLOTA, + METHOD_MC_SLOTB +}; + +struct SGCSettings{ + int AutoLoad; + int AutoSave; + int LoadMethod; // For ROMS: Auto, SD, DVD, USB, Network (SMB) + int SaveMethod; // For SRAM, Freeze, Prefs: Auto, SD, Memory Card Slot A, Memory Card Slot B, USB, SMB + char LoadFolder[200]; // Path to game files + char SaveFolder[200]; // Path to save files + char CheatFolder[200]; // Path to cheat files + char gcip[16]; + char gwip[16]; + char mask[16]; + char smbip[16]; + char smbuser[20]; + char smbpwd[20]; + char smbgcid[20]; + char smbsvid[20]; + char smbshare[20]; + int VerifySaves; +}; + +extern struct SGCSettings GCSettings; + +#endif diff --git a/source/ngc/vba172.cpp b/source/ngc/vba172.cpp deleted file mode 100644 index 01fbd02..0000000 --- a/source/ngc/vba172.cpp +++ /dev/null @@ -1,837 +0,0 @@ -/**************************************************************************** -* VisualBoyAdvance 1.7.2 -* Nintendo GameCube Wrapper -****************************************************************************/ -#include -#include -#include -#include -#include -#include - -#ifdef WII_BUILD - -extern "C" - { -#include -#include -#include -extern s32 CONF_Init(void); - } - -extern int isClassicAvailable; -extern int isWiimoteAvailable; - -void setup_controllers() -{ /* Doesn't work, either always returns - WiimoteAvailable only or apparently switches - REALLY fast between the two. WTF. - - WPAD_ScanPads(); - WPADData pad; - WPAD_ReadEvent(0, &pad); - // User can use just wiimote - if(pad.exp.type == WPAD_EXP_NONE) - { - isClassicAvailable = 0; - isWiimoteAvailable = 1; - return; - } - - // User can use a Classic controller - else if(pad.exp.type == WPAD_EXP_CLASSIC) - { - isClassicAvailable = 1; - WPAD_SetDataFormat(0, WPAD_FMT_BTNS); - return; - } - // User will have to use a GC controller - else - { - isClassicAvailable = 0; - isWiimoteAvailable = 0; - return; - } - */ - isClassicAvailable = 1; - isWiimoteAvailable = 1; - return; -} -#endif - -#include "mixer.h" -#include "gcpad.h" -#include "vmmem.h" -#include "pal60.h" - - -extern "C" - { -#include "gx_supp.h" -#include "tbtime.h" -#include "sdfileio.h" - } - -/** VBA **/ -#include "GBA.h" -#include "agbprint.h" -#include "Flash.h" -#include "Port.h" -#include "RTC.h" -#include "Sound.h" -#include "Text.h" -#include "unzip.h" -#include "Util.h" -#include "gb/GB.h" -#include "gb/gbGlobals.h" - -/** - * Globals - */ -int RGB_LOW_BITS_MASK=0x821; -int systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; -u16 systemGbPalette[24]; -int systemDebug = 0; -int emulating = 0; -int systemFrameSkip = 0; -int systemRedShift = 0; -int systemBlueShift = 0; -int systemGreenShift = 0; -int systemColorDepth = 0; -int sensorX = 2047; -int sensorY = 2047; -u16 systemColorMap16[0x10000]; -//u32 systemColorMap32[0x10000]; -u32 *systemColorMap32 = (u32 *)&systemColorMap16; -bool systemSoundOn = false; -int systemVerbose = 0; -int cartridgeType = 0; -int srcWidth = 0; -int srcHeight = 0; -int destWidth = 0; -int destHeight = 0; -int srcPitch = 0; -int saveExists = 0; -extern int menuCalled; -#define WITHGX 1 -#define DEBUGON 0 - - - -#if DEBUGON -const char *dbg_local_ip = "192.168.1.32"; -const char *dbg_netmask = "255.255.255.0"; -const char *dbg_gw = "192.168.1.100"; -#endif - -/*** 2D Video Globals ***/ -GXRModeObj *vmode; /*** Graphics Mode Object ***/ -u32 *xfb[2] = { NULL, NULL }; /*** Framebuffers ***/ -int whichfb = 0; /*** Frame buffer toggle ***/ - -void debuggerOutput(char *, u32) -{} - -void (*dbgOutput)(char *, u32) = debuggerOutput; - -/** - * Locals - */ - -extern char *MENU_GetLoadFile( char *whichdir ); -extern void MENU_DrawString( int x, int y, char *msg, int style ); - -struct EmulatedSystem emulator = - { - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - false, - 0 - }; - -static tb_t start, now; -static u8 soundbuffer[3200] ATTRIBUTE_ALIGN(32); - -u32 loadtimeradjust; - -void doScan(u32 blah) -{ - PAD_ScanPads(); -} - - -int throttle = 100; -u32 throttleLastTime = 0; - -char filename[1024]; //rom file name -char batfilename[1024]; //battery save file name -char statename[1024]; //savestate file name -/**************************************************************************** -* Initialise Video -* -* Before doing anything in libogc, it's recommended to configure a video -* output. -****************************************************************************/ -static void -Initialise (void) -{ - VIDEO_Init (); /*** ALWAYS CALL FIRST IN ANY LIBOGC PROJECT! - Not only does it initialise the video - subsystem, but also sets up the ogc os - ***/ -#if DEBUGON - DEBUG_Init(2424); - _break(); -#endif - - PAD_Init (); /*** Initialise pads for input ***/ -#ifdef WII_BUILD - CONF_Init(); - WPAD_Init(); - setup_controllers(); -#endif - vmode = VIDEO_GetPreferredMode(NULL); - - /*** Now configure the framebuffer. - Really a framebuffer is just a chunk of memory - to hold the display line by line. - ***/ - - xfb[0] = (u32 *) MEM_K0_TO_K1 (SYS_AllocateFramebuffer (vmode)); - /*** I prefer also to have a second buffer for double-buffering. - This is not needed for the console demo. - ***/ - xfb[1] = (u32 *) MEM_K0_TO_K1 (SYS_AllocateFramebuffer (vmode)); - - /*** Define a console ***/ - console_init (xfb[0], 20, 64, vmode->fbWidth, vmode->xfbHeight, - vmode->fbWidth * 2); - - /*** Let libogc configure the mode ***/ - VIDEO_Configure (vmode); - - /*** Clear framebuffer to black ***/ - VIDEO_ClearFrameBuffer (vmode, xfb[0], COLOR_BLACK); - VIDEO_ClearFrameBuffer (vmode, xfb[1], COLOR_BLACK); - - /*** Set the framebuffer to be displayed at next VBlank ***/ - VIDEO_SetNextFramebuffer (xfb[0]); - - /*** Get the PAD status updated by libogc ***/ - VIDEO_SetPreRetraceCallback (doScan); - VIDEO_SetBlack (0); -/* - int i; - u32 *vreg = (u32 *)0xCC002000; - for ( i = 0; i < 64; i++ ) - vreg[i] = vpal60[i]; */ - - /*** Update the video for next vblank ***/ - VIDEO_Flush (); - - VIDEO_WaitVSync (); /*** Wait for VBL ***/ - if (vmode->viTVMode & VI_NON_INTERLACE) - VIDEO_WaitVSync (); - -} - -void systemMessage(int num, const char *msg, ...) -{ - /*** For now ... do nothing ***/ -} - -void GC_Sleep(u32 dwMiliseconds) -{ - int nVBlanks = (dwMiliseconds / 16); - while (nVBlanks-- > 0) - { - VIDEO_WaitVSync(); - } -} - -void systemFrame() -{} - -void systemScreenCapture(int a) -{} - -void systemShowSpeed(int speed) -{} -static u32 autoFrameSkipLastTime = 0; -static int frameskipadjust = 0; - -void write_save() -{ -emulator.emuWriteBattery(batfilename); -} - -void system10Frames(int rate) -{ - if ( cartridgeType == 1 ) - return; - - u32 time = systemGetClock(); - u32 diff = time - autoFrameSkipLastTime; - int speed = 100; - - if(diff) - speed = (1000000/rate)/diff; - /* char temp[512]; - sprintf(temp,"Speed: %i",speed); - MENU_DrawString( -1, 450,temp , 1 ); */ - - if(speed >= 98) - { - frameskipadjust++; - - if(frameskipadjust >= 3) - { - frameskipadjust=0; - if(systemFrameSkip > 0) - systemFrameSkip--; - } - } - else - { - if(speed < 80) - frameskipadjust -= (90 - speed)/5; - else if(systemFrameSkip < 9) - frameskipadjust--; - - if(frameskipadjust <= -2) - { - frameskipadjust += 2; - if(systemFrameSkip < 9) - systemFrameSkip++; - } - } - -if ( cartridgeType == 1 ) - return; - - -/* -if(systemSaveUpdateCounter) { - char temp[512]; - sprintf(temp,"Writing Save To Disk"); - MENU_DrawString( -1, 450,temp , 1 ); -} */ - - if(systemSaveUpdateCounter) { - if(--systemSaveUpdateCounter <= SYSTEM_SAVE_NOT_UPDATED) { - write_save(); - systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; - } - } - - autoFrameSkipLastTime = time; -} - - - -void systemUpdateMotionSensor() -{} - -void systemGbBorderOn() -{} - -void systemWriteDataToSoundBuffer() -{ - MIXER_AddSamples((u8 *)soundFinalWave, (cartridgeType == 1)); -} - -void systemSoundPause() -{} - -void systemSoundResume() -{} - -void systemSoundReset() -{} - -void systemGbPrint(u8 *data,int pages,int feed,int palette, int contrast) -{} - -void systemSoundShutdown() -{} - -static void AudioPlayer( void ) -{ - AUDIO_StopDMA(); - MIXER_GetSamples(soundbuffer, 3200); - DCFlushRange(soundbuffer,3200); - AUDIO_InitDMA((u32)soundbuffer,3200); - AUDIO_StartDMA(); -} - -bool systemSoundInit() -{ - AUDIO_Init(NULL); - AUDIO_SetDSPSampleRate(AI_SAMPLERATE_48KHZ); - AUDIO_RegisterDMACallback(AudioPlayer); - memset(soundbuffer, 0, 3200); - - //printf("Audio Inited\n"); - return true; -} - -static void AudioDeInit() -{ - AUDIO_StopDMA(); -} - -bool systemPauseOnFrame() -{ - return false; -} - -int systemGetSensorX() -{ - return sensorX; -} - -int systemGetSensorY() -{ - return sensorY; -} - -bool systemCanChangeSoundQuality() -{ - return true; -} - -/**************************************************************************** -* systemReadJoypads -****************************************************************************/ -bool systemReadJoypads() -{ - return true; -} - -u32 systemReadJoypad(int which) -{ - return NGCPad(); -} - -/**************************************************************************** -* systemGetClock -* -* Returns number of milliseconds since program start -****************************************************************************/ -u32 systemGetClock( void ) -{ - mftb(&now); - return tb_diff_msec(&now, &start) - loadtimeradjust; -} - -/**************************************************************************** -* systemDrawScreen -****************************************************************************/ -void systemDrawScreen() -{ - /** GB / GBC Have oodles of time - so sync on VSync **/ -#if WITHGX - GX_Render( srcWidth, srcHeight, pix, srcPitch ); -#endif -#ifdef WII_BUILD - - VIDEO_WaitVSync (); - -#endif -#ifdef GC_BUILD - if ( cartridgeType == 1 ) - { - VIDEO_WaitVSync(); - } -#endif -} - -/**************************************************************************** -* Showdir -****************************************************************************/ -int ShowDir( char *whichdir ) -{ - int count; - int i; - count = gen_getdir( whichdir ); - printf("Found %d files\n",count); - - for ( i = 0; i < count; i++ ) - printf("%s\n", direntries[i]); - while(1); -} - -/* - Asks user to select a ROM -*/ -void chooseRom() { - //char *fname = "Sonic Advance 3.GBA"; - char *fname = NULL; - memset(filename,0,1024); - memset(batfilename,0,1024); - fname = MENU_GetLoadFile( "/VBA/ROMS" ); - sprintf(filename, "/VBA/ROMS/%s", fname); - - // construct battery save file name - strcpy(batfilename, "/VBA/SAVES/"); - strncat(batfilename,fname,strlen(fname)-4); - strcat(batfilename,".SAV"); - - // construct savestate name - strcpy(statename, "/VBA/SAVES/"); - strncat(statename,fname,strlen(fname)-4); - strcat(statename,".SGM"); -} - -/* - Checks to see if a previous SRAM/Flash save exists - If it does, it prompts the user to load it or not -*/ -void checkSave() { - FILE* f = gen_fopen(statename, "rb"); - if (f != NULL) { - gen_fclose(f); - whichfb^=1; - VIDEO_ClearFrameBuffer (vmode, xfb[whichfb], COLOR_BLACK); - MENU_DrawString( 140, 50,"Quick Save State Exists" , 1 ); - MENU_DrawString( 140, 80,"Do you wish to load it?" , 1 ); - MENU_DrawString( -1, 170,"(L) or (+) YES" , 1 ); - MENU_DrawString( -1, 200,"(R) or (-) NO" , 1 ); - VIDEO_WaitVSync (); - VIDEO_SetNextFramebuffer(xfb[whichfb]); - VIDEO_Flush(); - VIDEO_WaitVSync(); - while(1) { - WPADData *wpad; - WPAD_ScanPads(); - wpad = WPAD_Data(0); - if (isWiimoteAvailable) { - unsigned short b = wpad->btns_h; - if(b & WPAD_BUTTON_PLUS) { - saveExists = 1; - break; - } - if(b & WPAD_BUTTON_MINUS) break; - } - if (isClassicAvailable) { - unsigned short b = wpad->exp.classic.btns; - if(b & CLASSIC_CTRL_BUTTON_PLUS) { - saveExists = 1; - break; - } - if(b & CLASSIC_CTRL_BUTTON_MINUS) break; - } - u16 buttons = PAD_ButtonsHeld(0); - if(buttons & PAD_TRIGGER_R){ - break; - } - if(buttons & PAD_TRIGGER_L){ - saveExists = 1; - break; - } - } - VIDEO_ClearFrameBuffer (vmode, xfb[whichfb], COLOR_BLACK); - VIDEO_WaitVSync (); - VIDEO_SetNextFramebuffer(xfb[whichfb]); - VIDEO_Flush(); - VIDEO_WaitVSync(); - } -} - - -void askSound() { - soundOffFlag = false; - soundLowPass = true; -} - - -int ingameMenu() { - tb_t start,end; - mftb(&start); - char temp[512]; - u16 buttons; - AudioDeInit(); - whichfb^=1; - VIDEO_ClearFrameBuffer (vmode, xfb[whichfb], COLOR_BLACK); - MENU_DrawString( 140, 50,"VisualBoyAdvance 1.7.2" , 1 ); - -#ifdef GC_BUILD - MENU_DrawString( 140, 80,"Nintendo Gamecube Port" , 1 ); - MENU_DrawString( -1, 170,"(B) - Resume play" , 1 ); - MENU_DrawString( -1, 200,"(L) - Write Quicksave" , 1 ); - MENU_DrawString( -1, 230,"(R) - Reset game" , 1 ); - MENU_DrawString( -1, 320,"(Z) - Return to loader" , 1 ); -#endif -#ifdef WII_BUILD - MENU_DrawString( 140, 80,"Nintendo Wii Port" , 1 ); - MENU_DrawString( -1, 170,"(B) or (Home) - Resume play" , 1 ); - MENU_DrawString( -1, 200,"(L) or (+) - Write Quicksave" , 1 ); - MENU_DrawString( -1, 230,"(R) or (-) - Reset game" , 1 ); - MENU_DrawString( -1, 320,"(Z) or (A+B) - Return to loader" , 1 ); -#endif - - sprintf(temp,"Frameskip: Auto (Currently %i)",systemFrameSkip); - MENU_DrawString( -1, 450,temp , 1 ); - - VIDEO_WaitVSync (); - VIDEO_SetNextFramebuffer(xfb[whichfb]); - VIDEO_Flush(); - VIDEO_WaitVSync(); - - //wait for user to let go of menu calling button - do{buttons = PAD_ButtonsHeld(0);} - while((buttons & PAD_BUTTON_A)||(buttons & PAD_BUTTON_B)); - //wait for user to let go of home button -#ifdef WII_BUILD - WPADData *wpad; - int btn; - if(isWiimoteAvailable) - do{WPAD_ScanPads(); wpad = WPAD_Data(0); btn = wpad->btns_h;} - while(btn & WPAD_BUTTON_HOME); - if(isClassicAvailable) - do{WPAD_ScanPads(); wpad = WPAD_Data(0); btn = wpad->exp.classic.btns;} - while(btn & CLASSIC_CTRL_BUTTON_HOME); -#endif - - while(1){ - -#ifdef WII_BUILD - WPADData *wpad; - WPAD_ScanPads(); - wpad = WPAD_Data(0); - if (isWiimoteAvailable) - { - unsigned short b = wpad->btns_h; - if(b & WPAD_BUTTON_MINUS){ //Reset game - emulator.emuReset(); - break; - } - if(b & WPAD_BUTTON_PLUS) { //Write save - emulator.emuWriteState(statename); - GC_Sleep(1500); - break; - } - if((b & WPAD_BUTTON_A) && (b & WPAD_BUTTON_B)) { //Return to loader - void (*reload)() = (void(*)())0x80001800; - reload(); - } - if(b & WPAD_BUTTON_HOME) { //Resume play - do{WPAD_ScanPads(); wpad = WPAD_Data(0); b = wpad->btns_h;} - while(b & WPAD_BUTTON_HOME); //wait for home - break; - } - /* if(b & WPAD_BUTTON_2) { //back to menu - INSERT BACK-TO-MENU HERE - } */ - } - if (isClassicAvailable) - { - int b = wpad->exp.classic.btns; - if(b & CLASSIC_CTRL_BUTTON_MINUS){ //Reset game - emulator.emuReset(); - break; - } - if(b & CLASSIC_CTRL_BUTTON_PLUS) { //Write save - emulator.emuWriteState(statename); - break; - } - if((b & CLASSIC_CTRL_BUTTON_A) && (b & CLASSIC_CTRL_BUTTON_B)) { //Return to loader - void (*reload)() = (void(*)())0x80001800; - reload(); - } - if(b & CLASSIC_CTRL_BUTTON_HOME) { //Resume play - do{WPAD_ScanPads(); wpad = WPAD_Data(0); b = wpad->exp.classic.btns;} - while(b & CLASSIC_CTRL_BUTTON_HOME); //wait for home button - break; - } - } -#endif - - u16 buttons = PAD_ButtonsHeld(0); //grab pad buttons - - if(buttons & PAD_TRIGGER_R){ //Reset game - emulator.emuReset(); - break; - } - if(buttons & PAD_TRIGGER_L) { //Write save - emulator.emuWriteState(statename); - break; - } - if(buttons & PAD_TRIGGER_Z) { //Return to loader - void (*reload)() = (void(*)())0x80001800; - reload(); - } - if(buttons & PAD_BUTTON_B) { //Resume play - break; - } - } - AudioPlayer(); - mftb(&end); - loadtimeradjust += tb_diff_msec(&end, &start); - return 0; -} - - -/**************************************************************************** -* main -* -* Program entry -****************************************************************************/ -int main() -{ - int i; - int vAspect = 0; - int hAspect = 0; - - Initialise(); - - printf("\n\n\nVisualBoyAdvance 1.7.2\n"); - printf("Nintendo Wii Port\n"); - - - /** Kick off SD Lib **/ - SDInit(); - - - /** Build GBPalette **/ - for( i = 0; i < 24; ) - { - systemGbPalette[i++] = (0x1f) | (0x1f << 5) | (0x1f << 10); - systemGbPalette[i++] = (0x15) | (0x15 << 5) | (0x15 << 10); - systemGbPalette[i++] = (0x0c) | (0x0c << 5) | (0x0c << 10); - systemGbPalette[i++] = 0; - } - /** Set palette etc - Fixed to RGB565 **/ - systemColorDepth = 16; - systemRedShift = 11; - systemGreenShift = 6; - systemBlueShift = 0; - for(i = 0; i < 0x10000; i++) - { - systemColorMap16[i] = ((i & 0x1f) << systemRedShift) | - (((i & 0x3e0) >> 5) << systemGreenShift) | - (((i & 0x7c00) >> 10) << systemBlueShift); - } - - //Main loop - while(1) { - cartridgeType = 0; - srcWidth = 0; - srcHeight = 0; - destWidth = 0; - destHeight = 0; - srcPitch = 0; - - chooseRom(); - checkSave(); - - IMAGE_TYPE type = utilFindType(filename); - - switch( type ) - { - case IMAGE_GBA: - printf("GameBoy Advance Image\n"); - cartridgeType = 2; - emulator = GBASystem; - srcWidth = 240; - srcHeight = 160; - VMCPULoadROM(filename); - /* Actual Visual Aspect is 1.57 */ - hAspect = 70; - vAspect = 46; - srcPitch = 484; - soundQuality = 2; - soundBufferLen = 1470; - cpuSaveType = 0; - break; - - case IMAGE_GB: - printf("GameBoy Image\n"); - cartridgeType = 1; - emulator = GBSystem; - srcWidth = 160; - srcHeight = 144; - gbLoadRom(filename); - /* Actual physical aspect is 1.0 */ - hAspect = 60; - vAspect = 46; - srcPitch = 324; - soundQuality = 1; - soundBufferLen = 1470 * 2; - break; - - default: - printf("Unknown Image\n"); - while(1); - break; - - } - - /** Set defaults **/ - flashSetSize(0x10000); - rtcEnable(true); - agbPrintEnable(false); - askSound(); - - #if WITHGX - /** Set GX **/ - GX_Start( srcWidth, srcHeight, hAspect, vAspect ); - #endif - - - - if ( cartridgeType == 1 ) - { - gbSoundReset(); - gbSoundSetQuality(soundQuality); - } - else - { - soundSetQuality(soundQuality); - CPUInit("/VBA/BIOS/BIOS.GBA", 1); - CPUReset(); - } - - emulator.emuReadBattery(batfilename); - if (saveExists){ - emulator.emuReadState(statename); - saveExists = 0; - } - - soundVolume = 0; - systemSoundOn = true; - - soundInit(); - AudioPlayer(); - - emulating = 1; - /** Start system clock **/ - mftb(&start); - - while ( emulating ) - { - emulator.emuMain(emulator.emuCount); - if(menuCalled) { - if(ingameMenu()) - break; - menuCalled = 0; - } - } - } - - /** Never **/ - while(1); - return 0; - -} - diff --git a/source/ngc/vbaconfig.cpp b/source/ngc/vbaconfig.cpp new file mode 100644 index 0000000..a9be518 --- /dev/null +++ b/source/ngc/vbaconfig.cpp @@ -0,0 +1,53 @@ +/**************************************************************************** + * Snes9x 1.51 Nintendo Wii/Gamecube Port + * + * softdev July 2006 + * crunchy2 May 2007 + * Tantric September 2008 + * + * s9xconfig.cpp + * + * Configuration parameters are here for easy maintenance. + * Refer to Snes9x.h for all combinations. + * The defaults used here are taken directly from porting.html + ***************************************************************************/ + +#include +#include +#include +#include "vba.h" +#include "smbop.h" + +struct SGCSettings GCSettings; + +void +DefaultSettings () +{ + /************** GameCube/Wii Settings *********************/ + GCSettings.LoadMethod = METHOD_AUTO; // Auto, SD, DVD, USB, Network (SMB) + GCSettings.SaveMethod = METHOD_AUTO; // Auto, SD, Memory Card Slot A, Memory Card Slot B, USB, Network (SMB) + sprintf (GCSettings.LoadFolder,"vba/roms"); // Path to game files + sprintf (GCSettings.SaveFolder,"vba/saves"); // Path to save files + sprintf (GCSettings.CheatFolder,"vba/cheats"); // Path to cheat files + GCSettings.AutoLoad = 1; + GCSettings.AutoSave = 1; + + // custom SMB settings + strncpy (GCSettings.smbip, "", 15); // IP Address of share server + strncpy (GCSettings.smbuser, "", 19); // Your share user + strncpy (GCSettings.smbpwd, "", 19); // Your share user password + strncpy (GCSettings.smbshare, "", 19); // Share name on server + + GCSettings.smbip[15] = 0; + GCSettings.smbuser[19] = 0; + GCSettings.smbpwd[19] = 0; + GCSettings.smbshare[19] = 0; + + GCSettings.gcip[0] = 0; + GCSettings.gwip[0] = 0; + GCSettings.mask[0] = 0; + GCSettings.smbsvid[0] = 0; + GCSettings.smbgcid[0] = 0; + + GCSettings.VerifySaves = 0; +} diff --git a/source/ngc/vbaconfig.h b/source/ngc/vbaconfig.h new file mode 100644 index 0000000..57d2293 --- /dev/null +++ b/source/ngc/vbaconfig.h @@ -0,0 +1,21 @@ +/**************************************************************************** + * Snes9x 1.51 Nintendo Wii/Gamecube Port + * + * softdev July 2006 + * crunchy2 May 2007 + * Tantric September 2008 + * + * s9xconfig.h + * + * Configuration parameters are here for easy maintenance. + * Refer to Snes9x.h for all combinations. + * The defaults used here are taken directly from porting.html + ***************************************************************************/ + +#ifndef _VBACONFIG_ + +#define _VBACONFIG_ + +void DefaultSettings (); + +#endif diff --git a/source/ngc/vbasupport.cpp b/source/ngc/vbasupport.cpp new file mode 100644 index 0000000..d407545 --- /dev/null +++ b/source/ngc/vbasupport.cpp @@ -0,0 +1,474 @@ + + +#include +#include +#include +#include + + +#include "GBA.h" +#include "agbprint.h" +#include "Flash.h" +#include "Port.h" +#include "RTC.h" +#include "Sound.h" +#include "Text.h" +#include "unzip.h" +#include "Util.h" +#include "gb/GB.h" +#include "gb/gbGlobals.h" + + +#include "audio.h" +#include "vmmem.h" +#include "pal60.h" +#include "input.h" +#include "video.h" +#include "menudraw.h" + +extern "C" + { +#include "tbtime.h" +#include "sdfileio.h" + } + +/** + * Globals + */ +int RGB_LOW_BITS_MASK=0x821; +int systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; + +int systemDebug = 0; +int emulating = 0; + +int sensorX = 2047; +int sensorY = 2047; + +int systemFrameSkip = 0; +bool systemSoundOn = false; +int systemVerbose = 0; +int cartridgeType = 0; +int srcWidth = 0; +int srcHeight = 0; +int destWidth = 0; +int destHeight = 0; +int srcPitch = 0; +int saveExists = 0; + +int systemRedShift = 0; +int systemBlueShift = 0; +int systemGreenShift = 0; +int systemColorDepth = 0; +u16 systemGbPalette[24]; +u16 systemColorMap16[0x10000]; +//u32 systemColorMap32[0x10000]; +u32 *systemColorMap32 = (u32 *)&systemColorMap16; + +/*** 2D Video Globals ***/ +extern u32 whichfb; +extern u32 *xfb[2]; +extern GXRModeObj *vmode; + +struct EmulatedSystem emulator = + { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + false, + 0 + }; + +static tb_t start, now; + +u32 loadtimeradjust; + +int throttle = 100; +u32 throttleLastTime = 0; + +int vAspect = 0; +int hAspect = 0; + +//char filename[1024]; //rom file name +//char batfilename[1024]; //battery save file name +//char statename[1024]; //savestate file name + +void debuggerOutput(char *, u32) +{} + +void (*dbgOutput)(char *, u32) = debuggerOutput; + +void systemMessage(int num, const char *msg, ...) +{ + /*** For now ... do nothing ***/ +} + +void GC_Sleep(u32 dwMiliseconds) +{ + int nVBlanks = (dwMiliseconds / 16); + while (nVBlanks-- > 0) + { + VIDEO_WaitVSync(); + } +} + +void systemFrame() +{} + +void systemScreenCapture(int a) +{} + +void systemShowSpeed(int speed) +{} +static u32 autoFrameSkipLastTime = 0; +static int frameskipadjust = 0; + +void write_save() +{ +//emulator.emuWriteBattery(batfilename); +} + +void system10Frames(int rate) +{ + if ( cartridgeType == 1 ) + return; + + u32 time = systemGetClock(); + u32 diff = time - autoFrameSkipLastTime; + int speed = 100; + + if(diff) + speed = (1000000/rate)/diff; + /* char temp[512]; + sprintf(temp,"Speed: %i",speed); + MENU_DrawString( -1, 450,temp , 1 ); */ + + if(speed >= 98) + { + frameskipadjust++; + + if(frameskipadjust >= 3) + { + frameskipadjust=0; + if(systemFrameSkip > 0) + systemFrameSkip--; + } + } + else + { + if(speed < 80) + frameskipadjust -= (90 - speed)/5; + else if(systemFrameSkip < 9) + frameskipadjust--; + + if(frameskipadjust <= -2) + { + frameskipadjust += 2; + if(systemFrameSkip < 9) + systemFrameSkip++; + } + } + +if ( cartridgeType == 1 ) + return; + + +/* +if(systemSaveUpdateCounter) { + char temp[512]; + sprintf(temp,"Writing Save To Disk"); + MENU_DrawString( -1, 450,temp , 1 ); +} */ + + if(systemSaveUpdateCounter) { + if(--systemSaveUpdateCounter <= SYSTEM_SAVE_NOT_UPDATED) { + write_save(); + systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED; + } + } + + autoFrameSkipLastTime = time; +} + + + +void systemUpdateMotionSensor() +{} + +void systemGbBorderOn() +{} + +void systemWriteDataToSoundBuffer() +{ + MIXER_AddSamples((u8 *)soundFinalWave, (cartridgeType == 1)); +} + +void systemSoundPause() +{} + +void systemSoundResume() +{} + +void systemSoundReset() +{} + +void systemGbPrint(u8 *data,int pages,int feed,int palette, int contrast) +{} + +void systemSoundShutdown() +{} + +bool systemSoundInit() +{ + //memset(soundbuffer, 0, 3200); + return true; +} + +bool systemPauseOnFrame() +{ + return false; +} + +int systemGetSensorX() +{ + return sensorX; +} + +int systemGetSensorY() +{ + return sensorY; +} + +bool systemCanChangeSoundQuality() +{ + return true; +} + +/**************************************************************************** +* systemReadJoypads +****************************************************************************/ +bool systemReadJoypads() +{ + return true; +} + +u32 systemReadJoypad(int which) +{ + return GetJoy(); +} + +/**************************************************************************** +* systemGetClock +* +* Returns number of milliseconds since program start +****************************************************************************/ +u32 systemGetClock( void ) +{ + mftb(&now); + return tb_diff_msec(&now, &start) - loadtimeradjust; +} + +/**************************************************************************** +* systemDrawScreen +****************************************************************************/ +void systemDrawScreen() +{ + /** GB / GBC Have oodles of time - so sync on VSync **/ + GX_Render( srcWidth, srcHeight, pix, srcPitch ); + +#ifdef HW_RVL + VIDEO_WaitVSync (); +#else + if ( cartridgeType == 1 ) + { + VIDEO_WaitVSync(); + } +#endif +} + +/* + Checks to see if a previous SRAM/Flash save exists + If it does, it prompts the user to load it or not +*/ +void checkSave() { + /* FILE* f = gen_fopen(statename, "rb"); + if (f != NULL) { + gen_fclose(f); + whichfb^=1; + VIDEO_ClearFrameBuffer (vmode, xfb[whichfb], COLOR_BLACK); + //MENU_DrawString( 140, 50,"Quick Save State Exists" , 1 ); + //MENU_DrawString( 140, 80,"Do you wish to load it?" , 1 ); + //MENU_DrawString( -1, 170,"(L) or (+) YES" , 1 ); + //MENU_DrawString( -1, 200,"(R) or (-) NO" , 1 ); + VIDEO_WaitVSync (); + VIDEO_SetNextFramebuffer(xfb[whichfb]); + VIDEO_Flush(); + VIDEO_WaitVSync(); + while(1) { + WPADData *wpad; + WPAD_ScanPads(); + wpad = WPAD_Data(0); + if (isWiimoteAvailable) { + unsigned short b = wpad->btns_h; + if(b & WPAD_BUTTON_PLUS) { + saveExists = 1; + break; + } + if(b & WPAD_BUTTON_MINUS) break; + } + if (isClassicAvailable) { + unsigned short b = wpad->exp.classic.btns; + if(b & CLASSIC_CTRL_BUTTON_PLUS) { + saveExists = 1; + break; + } + if(b & CLASSIC_CTRL_BUTTON_MINUS) break; + } + u16 buttons = PAD_ButtonsHeld(0); + if(buttons & PAD_TRIGGER_R){ + break; + } + if(buttons & PAD_TRIGGER_L){ + saveExists = 1; + break; + } + } + VIDEO_ClearFrameBuffer (vmode, xfb[whichfb], COLOR_BLACK); + VIDEO_WaitVSync (); + VIDEO_SetNextFramebuffer(xfb[whichfb]); + VIDEO_Flush(); + VIDEO_WaitVSync(); + }*/ +} + + +void askSound() { + soundOffFlag = false; + soundLowPass = true; +} + +int loadVBAROM(char filename[]) +{ + cartridgeType = 0; + srcWidth = 0; + srcHeight = 0; + destWidth = 0; + destHeight = 0; + srcPitch = 0; + + IMAGE_TYPE type = utilFindType(filename); + + switch( type ) + { + case IMAGE_GBA: + //WaitPrompt("GameBoy Advance Image"); + cartridgeType = 2; + emulator = GBASystem; + srcWidth = 240; + srcHeight = 160; + VMCPULoadROM(filename); + /* Actual Visual Aspect is 1.57 */ + hAspect = 70; + vAspect = 46; + srcPitch = 484; + soundQuality = 2; + soundBufferLen = 1470; + cpuSaveType = 0; + break; + + case IMAGE_GB: + //WaitPrompt("GameBoy Image"); + cartridgeType = 1; + emulator = GBSystem; + srcWidth = 160; + srcHeight = 144; + gbLoadRom(filename); + /* Actual physical aspect is 1.0 */ + hAspect = 60; + vAspect = 46; + srcPitch = 324; + soundQuality = 1; + soundBufferLen = 1470 * 2; + break; + + default: + WaitPrompt((char *)"Unknown Image"); + return 0; + break; + } + + /** Set defaults **/ + flashSetSize(0x10000); + rtcEnable(true); + agbPrintEnable(false); + askSound(); + + /** Setup GX **/ + GX_Render_Init( srcWidth, srcHeight, hAspect, vAspect ); + + if ( cartridgeType == 1 ) + { + gbSoundReset(); + gbSoundSetQuality(soundQuality); + } + else + { + soundSetQuality(soundQuality); + CPUInit("/VBA/BIOS/BIOS.GBA", 1); + CPUReset(); + } + +// emulator.emuReadBattery(batfilename); + if (saveExists) + { + //emulator.emuReadState(statename); + saveExists = 0; + } + + soundVolume = 0; + systemSoundOn = true; + + soundInit(); + //AudioPlayer(); + + emulating = 1; + + /** Start system clock **/ + mftb(&start); + + //emulator.emuReset(); + return 1; +} + +void InitialisePalette() +{ + int i; + /** Build GBPalette **/ + for( i = 0; i < 24; ) + { + systemGbPalette[i++] = (0x1f) | (0x1f << 5) | (0x1f << 10); + systemGbPalette[i++] = (0x15) | (0x15 << 5) | (0x15 << 10); + systemGbPalette[i++] = (0x0c) | (0x0c << 5) | (0x0c << 10); + systemGbPalette[i++] = 0; + } + /** Set palette etc - Fixed to RGB565 **/ + systemColorDepth = 16; + systemRedShift = 11; + systemGreenShift = 6; + systemBlueShift = 0; + for(i = 0; i < 0x10000; i++) + { + systemColorMap16[i] = + ((i & 0x1f) << systemRedShift) | + (((i & 0x3e0) >> 5) << systemGreenShift) | + (((i & 0x7c00) >> 10) << systemBlueShift); + } +} diff --git a/source/ngc/vbasupport.h b/source/ngc/vbasupport.h new file mode 100644 index 0000000..ffb1965 --- /dev/null +++ b/source/ngc/vbasupport.h @@ -0,0 +1,6 @@ +#include "System.h" + +extern struct EmulatedSystem emulator; +extern u32 loadtimeradjust; +int loadVBAROM(char filename[]); +void InitialisePalette(); diff --git a/source/ngc/video.cpp b/source/ngc/video.cpp new file mode 100644 index 0000000..fba5e23 --- /dev/null +++ b/source/ngc/video.cpp @@ -0,0 +1,342 @@ +/**************************************************************************** +* Generic GX Support for Emulators +* softdev 2007 +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along +* with this program; if not, write to the Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +* +* NGC GX Video Functions +* +* These are pretty standard functions to setup and use GX scaling. +****************************************************************************/ +#include +#include +#include +#include +#include +#include + +/*** External 2D Video ***/ +/*** 2D Video Globals ***/ +GXRModeObj *vmode; /*** Graphics Mode Object ***/ +u32 *xfb[2] = { NULL, NULL }; /*** Framebuffers ***/ +int whichfb = 0; /*** Frame buffer toggle ***/ + +int screenheight; + +/*** 3D GX ***/ +#define DEFAULT_FIFO_SIZE ( 256 * 1024 ) +static u8 gp_fifo[DEFAULT_FIFO_SIZE] ATTRIBUTE_ALIGN(32); + +/*** Texture memory ***/ +static u8 *texturemem; +static int texturesize; + +GXTexObj texobj; +static Mtx view; +static int vwidth, vheight, oldvwidth, oldvheight; +unsigned int copynow = GX_FALSE; + +#define HASPECT 80 +#define VASPECT 45 + +/* New texture based scaler */ +typedef struct tagcamera + { + Vector pos; + Vector up; + Vector view; + } +camera; + +/*** Square Matrix + This structure controls the size of the image on the screen. + Think of the output as a -80 x 80 by -60 x 60 graph. +***/ +static s16 square[] ATTRIBUTE_ALIGN(32) = { + /* + * X, Y, Z + * Values set are for roughly 4:3 aspect + */ + -HASPECT, VASPECT, 0, // 0 + HASPECT, VASPECT, 0, // 1 + HASPECT, -VASPECT, 0, // 2 + -HASPECT, -VASPECT, 0, // 3 + }; + +static camera cam = { {0.0F, 0.0F, 0.0F}, + {0.0F, 0.5F, 0.0F}, + {0.0F, 0.0F, -0.5F} + }; + +/**************************************************************************** + * StartGX + ****************************************************************************/ +void GX_Start() +{ + Mtx p; + + GXColor gxbackground = { 0, 0, 0, 0xff }; + + /*** Clear out FIFO area ***/ + memset(&gp_fifo, 0, DEFAULT_FIFO_SIZE); + + /*** Initialise GX ***/ + GX_Init(&gp_fifo, DEFAULT_FIFO_SIZE); + GX_SetCopyClear(gxbackground, 0x00ffffff); + + GX_SetViewport(0, 0, vmode->fbWidth, vmode->efbHeight, 0, 1); + GX_SetDispCopyYScale((f32) vmode->xfbHeight / (f32) vmode->efbHeight); + GX_SetScissor(0, 0, vmode->fbWidth, vmode->efbHeight); + GX_SetDispCopySrc(0, 0, vmode->fbWidth, vmode->efbHeight); + GX_SetDispCopyDst(vmode->fbWidth, vmode->xfbHeight); + GX_SetCopyFilter(vmode->aa, vmode->sample_pattern, GX_TRUE, + vmode->vfilter); + GX_SetFieldMode(vmode->field_rendering, + ((vmode->viHeight == + 2 * vmode->xfbHeight) ? GX_ENABLE : GX_DISABLE)); + GX_SetPixelFmt(GX_PF_RGB8_Z24, GX_ZC_LINEAR); + GX_SetCullMode(GX_CULL_NONE); + GX_CopyDisp(xfb[whichfb ^ 1], GX_TRUE); + GX_SetDispCopyGamma(GX_GM_1_0); + + guPerspective(p, 60, 1.33F, 10.0F, 1000.0F); + GX_LoadProjectionMtx(p, GX_PERSPECTIVE); +} + +/**************************************************************************** + * UpdatePadsCB + * + * called by postRetraceCallback in InitGCVideo - scans gcpad and wpad + ***************************************************************************/ +void +UpdatePadsCB () +{ +#ifdef HW_RVL + WPAD_ScanPads(); +#endif + PAD_ScanPads(); +} + +/**************************************************************************** +* Initialise Video +* +* Before doing anything in libogc, it's recommended to configure a video +* output. +****************************************************************************/ +void InitialiseVideo () +{ + /*** Start VIDEO Subsystem ***/ + VIDEO_Init(); + + vmode = VIDEO_GetPreferredMode(NULL); + VIDEO_Configure(vmode); + + screenheight = vmode->xfbHeight; + + xfb[0] = (u32 *) MEM_K0_TO_K1 (SYS_AllocateFramebuffer (vmode)); + xfb[1] = (u32 *) MEM_K0_TO_K1 (SYS_AllocateFramebuffer (vmode)); + + VIDEO_SetNextFramebuffer(xfb[0]); + VIDEO_SetBlack(FALSE); + VIDEO_Flush(); + VIDEO_WaitVSync(); + + if(vmode->viTVMode&VI_NON_INTERLACE) VIDEO_WaitVSync(); + VIDEO_SetPostRetraceCallback((VIRetraceCallback)UpdatePadsCB); + VIDEO_SetNextFramebuffer(xfb[0]); + + GX_Start(); +} + +/**************************************************************************** + * Scaler Support Functions + ****************************************************************************/ +static void draw_init(void) +{ + GX_ClearVtxDesc(); + GX_SetVtxDesc(GX_VA_POS, GX_INDEX8); + GX_SetVtxDesc(GX_VA_CLR0, GX_INDEX8); + GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT); + + GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_S16, 0); + GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0); + GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0); + + GX_SetArray(GX_VA_POS, square, 3 * sizeof(s16)); + + GX_SetNumTexGens(1); + GX_SetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY); + + GX_InvalidateTexAll(); + + GX_InitTexObj(&texobj, texturemem, vwidth, vheight, GX_TF_RGB565, + GX_CLAMP, GX_CLAMP, GX_FALSE); +} + +static void draw_vert(u8 pos, u8 c, f32 s, f32 t) +{ + GX_Position1x8(pos); + GX_Color1x8(c); + GX_TexCoord2f32(s, t); +} + +static void draw_square(Mtx v) +{ + Mtx m; // model matrix. + Mtx mv; // modelview matrix. + + guMtxIdentity(m); + guMtxTransApply(m, m, 0, 0, -100); + guMtxConcat(v, m, mv); + + GX_LoadPosMtxImm(mv, GX_PNMTX0); + GX_Begin(GX_QUADS, GX_VTXFMT0, 4); + draw_vert(0, 0, 0.0, 0.0); + draw_vert(1, 0, 1.0, 0.0); + draw_vert(2, 0, 1.0, 1.0); + draw_vert(3, 0, 0.0, 1.0); + GX_End(); +} + +void GX_Render_Init(int width, int height, int haspect, int vaspect) +{ + /*** Set new aspect (now with crap AR hack!) ***/ + square[0] = square[9] = (-haspect - 7); + square[3] = square[6] = (haspect + 7); + square[1] = square[4] = (vaspect + 7); + square[7] = square[10] = (-vaspect - 7); + + /*** Allocate 32byte aligned texture memory ***/ + texturesize = (width * height) * 2; + texturemem = (u8 *) memalign(32, texturesize); + + memset(texturemem, 0, texturesize); + + /*** Setup for first call to scaler ***/ + vwidth = vheight = -1; +} +/**************************************************************************** +* GX_Render +* +* Pass in a buffer, width and height to update as a tiled RGB565 texture +****************************************************************************/ +void GX_Render(int width, int height, u8 * buffer, int pitch) +{ + int h, w; + long long int *dst = (long long int *) texturemem; + long long int *src1 = (long long int *) buffer; + long long int *src2 = (long long int *) (buffer + pitch); + long long int *src3 = (long long int *) (buffer + (pitch * 2)); + long long int *src4 = (long long int *) (buffer + (pitch * 3)); + int rowpitch = (pitch >> 3) * 3; + int rowadjust = ( pitch % 8 ) * 4; + char *ra = NULL; + + vwidth = width; + vheight = height; + + whichfb ^= 1; + + if ((oldvheight != vheight) || (oldvwidth != vwidth)) + { + /** Update scaling **/ + oldvwidth = vwidth; + oldvheight = vheight; + draw_init(); + memset(&view, 0, sizeof(Mtx)); + guLookAt(view, &cam.pos, &cam.up, &cam.view); + GX_SetViewport(0, 0, vmode->fbWidth, vmode->efbHeight, 0, 1); + } + + GX_InvVtxCache(); + GX_InvalidateTexAll(); + GX_SetTevOp(GX_TEVSTAGE0, GX_DECAL); + GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0); + + for (h = 0; h < vheight; h += 4) + { + for (w = 0; w < (vwidth >> 2); w++) + { + *dst++ = *src1++; + *dst++ = *src2++; + *dst++ = *src3++; + *dst++ = *src4++; + } + + src1 += rowpitch; + src2 += rowpitch; + src3 += rowpitch; + src4 += rowpitch; + + if ( rowadjust ) + { + ra = (char *)src1; + src1 = (long long int *)(ra + rowadjust); + ra = (char *)src2; + src2 = (long long int *)(ra + rowadjust); + ra = (char *)src3; + src3 = (long long int *)(ra + rowadjust); + ra = (char *)src4; + src4 = (long long int *)(ra + rowadjust); + } + } + + DCFlushRange(texturemem, texturesize); + + GX_SetNumChans(1); + GX_LoadTexObj(&texobj, GX_TEXMAP0); + + draw_square(view); + + GX_DrawDone(); + + GX_SetZMode(GX_TRUE, GX_LEQUAL, GX_TRUE); + GX_SetColorUpdate(GX_TRUE); + GX_CopyDisp(xfb[whichfb], GX_TRUE); + GX_Flush(); + + VIDEO_SetNextFramebuffer(xfb[whichfb]); + VIDEO_Flush(); + //VIDEO_WaitVSync(); +} + + +/**************************************************************************** + * Drawing screen + ***************************************************************************/ +void +clearscreen (int c) +{ + int colour = COLOR_WHITE; + + whichfb ^= 1; + VIDEO_ClearFrameBuffer (vmode, xfb[whichfb], colour); +#ifdef HW_RVL + // on wii copy from memory + //memcpy ((char *) xfb[whichfb], (char *) backdrop, 640 * screenheight * 2); +#else + // on gc copy from aram + //ARAMFetch ((char *) xfb[whichfb], (char *) AR_BACKDROP, 640 * screenheight * 2); +#endif +} + +void +showscreen () +{ + copynow = GX_FALSE; + VIDEO_SetNextFramebuffer (xfb[whichfb]); + VIDEO_Flush (); + VIDEO_WaitVSync (); +} diff --git a/source/ngc/gx_supp.h b/source/ngc/video.h similarity index 85% rename from source/ngc/gx_supp.h rename to source/ngc/video.h index 36c0cfb..c242127 100644 --- a/source/ngc/gx_supp.h +++ b/source/ngc/video.h @@ -1,5 +1,5 @@ /**************************************************************************** -* Generic GX Scaler +* Generic GX Scaler * softdev 2007 * * This program is free software; you can redistribute it and/or modify @@ -23,7 +23,10 @@ #ifndef __GXHDR__ #define __GXHDR__ -void GX_Start(int width, int height, int haspect, int vaspect); +void InitialiseVideo (); +void GX_Render_Init(int width, int height, int haspect, int vaspect); void GX_Render(int width, int height, u8 * buffer, int pitch); +void clearscreen (int colour = COLOR_BLACK); +void showscreen (); #endif diff --git a/source/ngc/vmmem.cpp b/source/ngc/vmmem.cpp index d991316..98661b0 100644 --- a/source/ngc/vmmem.cpp +++ b/source/ngc/vmmem.cpp @@ -1,4 +1,4 @@ -#ifdef WII_BUILD +#ifdef HW_RVL /**************************************************************************** * VisualBoyAdvance 1.7.2 * @@ -17,6 +17,8 @@ #include "Util.h" #include "Port.h" +#include "menudraw.h" + extern "C" { #include "tbtime.h" } @@ -33,7 +35,7 @@ static u32 GBAROMSize = 0; static char romfilename[1024]; /** - * GBA Memory + * GBA Memory */ #define WORKRAM 0x40000 #define BIOS 0x4000 @@ -47,7 +49,7 @@ static char romfilename[1024]; VRAM + OAM + PIX + IOMEM ) extern void CPUUpdateRenderBuffers(bool force); -extern void MENU_DrawString( int x, int y, char *msg, int style ); + /**************************************************************************** * VMAllocGBA * @@ -102,34 +104,34 @@ int VMCPULoadROM( char *filename ) VMAllocGBA(); GBAROMSize = 0; - - /*sprintf(temp,"Filename %s\n", filename); - MENU_DrawString( -1, 230,temp , 1 ); - */ + + sprintf(temp,"Filename %s\n", filename); + //WaitPrompt(temp); + romfile = gen_fopen(filename, "rb"); if ( romfile == NULL ) { - MENU_DrawString( -1, 400,"Error opening file!" , 1 ); - while(1); + WaitPrompt((char*) "Error opening file!"); + //while(1); VMClose(); return 0; } - + fseek(romfile, 0, SEEK_END); GBAROMSize = ftell(romfile); fseek(romfile, 0, SEEK_SET); - + sprintf(temp,"ROM Size %dMb (%dMBit)", GBAROMSize/1024/1024,(GBAROMSize*8)/1024/1024); - MENU_DrawString( -1, 150,temp , 1 ); - + //WaitPrompt(temp); + rom = (u8 *)MEM2Storage; - + /* Always use MEM2, regardless of ROM size */ res = gen_fread(rom, 1, GBAROMSize, romfile); if ( (u32)res != GBAROMSize ) { - MENU_DrawString( -1, 400,"Error reading file!" , 1 ); + WaitPrompt((char*) "Error reading file!"); while(1); } strcpy( romfilename, filename ); @@ -183,7 +185,7 @@ u16 VMRead16( u32 address ) ****************************************************************************/ u8 VMRead8( u32 address ) { - + if ( address >= GBAROMSize ) { return ( address >> 1 ) & 0xff; @@ -193,8 +195,7 @@ u8 VMRead8( u32 address ) return (u8)rom[address]; } -#endif -#ifdef GC_BUILD +#else /**************************************************************************** * VisualBoyAdvance 1.7.2 * @@ -211,6 +212,8 @@ u8 VMRead8( u32 address ) #include "Util.h" #include "Port.h" +#include "menudraw.h" + extern "C" { #include "tbtime.h" } @@ -248,7 +251,7 @@ static u32 GBAROMSize = 0; static char romfilename[1024]; /** - * GBA Memory + * GBA Memory */ #define WORKRAM 0x40000 #define BIOS 0x4000 @@ -376,6 +379,7 @@ static void VMClose( void ) int VMCPULoadROM( char *filename ) { int res; + char msg[512]; /** Fix VM **/ VMClose(); @@ -389,7 +393,7 @@ int VMCPULoadROM( char *filename ) romfile = gen_fopen(filename, "rb"); if ( romfile == NULL ) { - printf("Error opening file!\n"); + WaitPrompt((char*) "Error opening file!"); while(1); VMClose(); return 0; @@ -401,7 +405,8 @@ int VMCPULoadROM( char *filename ) res = gen_fread(rom, 1, (1 << VMSHIFTBITS), romfile); if ( res != (1 << VMSHIFTBITS ) ) { - printf("Error reading file! %i \n",res); + sprintf(msg, "Error reading file! %i \n",res); + WaitPrompt(msg); while(1); } @@ -431,13 +436,15 @@ static void VMNewPage( int pageid ) { int res; tb_t start,end; + char msg[512]; mftb(&start); res = gen_fseek( romfile, pageid << VMSHIFTBITS, SEEK_SET ); if ( ! res ) { - printf("Seek error! - Offset %08x %d\n", pageid << VMSHIFTBITS, res); + sprintf(msg, "Seek error! - Offset %08x %d\n", pageid << VMSHIFTBITS, res); + WaitPrompt(msg); while(1); } @@ -446,7 +453,8 @@ static void VMNewPage( int pageid ) res = gen_fread( vmpage[pageid].pageptr, 1, 1 << VMSHIFTBITS, romfile ); if ( res != ( 1 << VMSHIFTBITS ) ) { - printf("Error reading! %d bytes only\n", res); + sprintf(msg, "Error reading! %d bytes only\n", res); + WaitPrompt(msg); while(1); } @@ -481,6 +489,7 @@ u32 VMRead32( u32 address ) { int pageid; u32 badaddress; + char msg[512]; //printf("VM32 : Request %08x\n", address); if ( address >= GBAROMSize ) @@ -504,8 +513,9 @@ u32 VMRead32( u32 address ) return READ32LE( vmpage[pageid].pageptr + ( address & VMSHIFTMASK ) ); default: - printf("VM32 : Unknown page type! (%d) [%d]\n", vmpage[pageid].pagetype, pageid); - while(1); + sprintf(msg, "VM32 : Unknown page type! (%d) [%d]", vmpage[pageid].pagetype, pageid); + WaitPrompt(msg); + while(1); } /* Can never get here ... but stops gcc bitchin' */ @@ -543,7 +553,7 @@ u16 VMRead16( u32 address ) return READ16LE( vmpage[pageid].pageptr + ( address & VMSHIFTMASK ) ); default: - printf("VM16 : Unknown page type!\n"); + WaitPrompt((char*) "VM16 : Unknown page type!"); while(1); } @@ -582,7 +592,7 @@ u8 VMRead8( u32 address ) return (u8)vmpage[pageid].pageptr[ (address & VMSHIFTMASK) ]; default: - printf("VM8 : Unknown page type!\n"); + WaitPrompt((char*) "VM8 : Unknown page type!"); while(1); }