diff --git a/desmume/AUTHORS b/desmume/AUTHORS index 05b61f8c5..a7b61595d 100644 --- a/desmume/AUTHORS +++ b/desmume/AUTHORS @@ -18,6 +18,7 @@ Tim Seidel (Mighty Max) Damien Nozay (damdoum) Pascal Giard (evilynux) Ben Jaques (masscat) +Jeff Bland Contributors ------------ diff --git a/desmume/ChangeLog b/desmume/ChangeLog index a1d10c09b..68ebc7b53 100644 --- a/desmume/ChangeLog +++ b/desmume/ChangeLog @@ -3,6 +3,8 @@ - Full localization using intltool/gettext. [evilynux] general: - Added a README.TRANSLATION documenting the localization process. [evilynux] + MacOS X: + - Initial version of the Mac interface added. [Jeff B] 0.7.1 -> 0.7.2 spu: diff --git a/desmume/README.TRANSLATION b/desmume/README.TRANSLATION index 32aaa7a34..46118e890 100644 --- a/desmume/README.TRANSLATION +++ b/desmume/README.TRANSLATION @@ -14,7 +14,7 @@ Developpers: 1 Supported UIs ________________________________________________________________ -Although there are 4 UIs, only 2 currently support localization: +Although there are 4 UIs, only 3 currently support localization: windows and gtk-glade. To translate DeSmuME, see "Starting a new translation" below. @@ -32,6 +32,10 @@ To translate DeSmuME, see "Starting a new translation" below. Localization is located in one single file: src/windows/resources.rc . + 1.3 Mac OS X (Cocoa) UI +-------------------------------------------------------------- + + Localization is located within the application bundle (in Finder right click on DeSmuME and select "Show Package Contents"). Within the Contents/Resources folder there is a folder for each localization. 2 Starting a new translation ___________________________________________________ @@ -54,6 +58,13 @@ To translate DeSmuME, see "Starting a new translation" below. Translate the strings. Send us your translation by getting in touch with us: see "Contact Us" below. + 2.3 Max OS X UI +-------------------------------------------------------------- + + Copy one of the localization folders mentioned in section one, and paste it into the same folder. + Rename the part before ".lproj" to the language of the translation. + Within your newly created folder edit "Localizable.strings". + Send us your translation by getting in touch with us: see "Contact Us" below. 3 Editors ______________________________________________________________________ @@ -128,4 +139,4 @@ To update po/desmume.pot, move to the po/ folder and execute "make update-po". Add the new language to to the list in src/windows/resource.h . Rebuild. -$Id: README.TRANSLATION,v 1.7 2007-07-19 06:50:57 evilynux Exp $ +$Id: README.TRANSLATION,v 1.8 2007-08-11 19:23:44 gecko_reverse Exp $ diff --git a/desmume/src/GPU.h b/desmume/src/GPU.h index b2a0aa3df..22b1616b8 100644 --- a/desmume/src/GPU.h +++ b/desmume/src/GPU.h @@ -30,6 +30,7 @@ #include "mem.h" #include "registers.h" #include "FIFO.h" +#include "MMU.h" #ifdef __cplusplus extern "C" { @@ -44,7 +45,7 @@ extern "C" { #ifdef WORDS_BIGENDIAN struct _DISPCNT { -/* 7*/ u8 ForceBlank:1; // A+B: +/* 7*/ u8 ForceBlank:1; // A+B: /* 6*/ u8 OBJ_BMP_mapping:1; // A+B: 0=2D (128KB), 1=1D (128..256KB) /* 5*/ u8 OBJ_BMP_2D_dim:1; // A+B: 0=128x512, 1=256x256 pixels /* 4*/ u8 OBJ_Tile_1D:1; // A+B: 0=2D (32KB), 1=1D (32..256KB) @@ -59,8 +60,8 @@ struct _DISPCNT /* 9*/ u8 BG1_Enable:1; // A+B: 0=disable, 1=Enable /* 8*/ u8 BG0_Enable:1; // A+B: 0=disable, 1=Enable /*23*/ u8 OBJ_HBlank_process:1; // A+B: OBJ processed during HBlank (GBA bit5) -/*22*/ u8 OBJ_BMP_1D_Bound:1; // A : -/*20*/ u8 OBJ_Tile_1D_Bound:2; // A+B: +/*22*/ u8 OBJ_BMP_1D_Bound:1; // A : +/*20*/ u8 OBJ_Tile_1D_Bound:2; // A+B: /*18*/ u8 VRAM_Block:2; // A : VRAM block (0..3=A..D) /*16*/ u8 DisplayMode:2; // A+B: coreA(0..3) coreB(0..1) GBA(Green Swap) @@ -73,7 +74,7 @@ struct _DISPCNT /*30*/ u8 ExBGxPalette_Enable:1; // A+B: 0=disable, 1=Enable BG extended Palette /*27*/ u8 ScreenBase_Block:3; // A : Screen Base (64K step) /*24*/ u8 CharacBase_Block:3; // A : Character Base (64K step) -}; +}; #else struct _DISPCNT { @@ -84,7 +85,7 @@ struct _DISPCNT /* 6*/ u8 OBJ_BMP_mapping:1; // A+B: 0=2D (128KB), 1=1D (128..256KB) // 7-15 same as GBA -/* 7*/ u8 ForceBlank:1; // A+B: +/* 7*/ u8 ForceBlank:1; // A+B: /* 8*/ u8 BG0_Enable:1; // A+B: 0=disable, 1=Enable /* 9*/ u8 BG1_Enable:1; // A+B: 0=disable, 1=Enable /*10*/ u8 BG2_Enable:1; // A+B: 0=disable, 1=Enable @@ -99,23 +100,23 @@ struct _DISPCNT // 1=on (normal BG & OBJ layers) // 2=VRAM display (coreA only) // 3=RAM display (coreA only, DMA transfers) - + /*18*/ u8 VRAM_Block:2; // A : VRAM block (0..3=A..D) -/*20*/ u8 OBJ_Tile_1D_Bound:2; // A+B: -/*22*/ u8 OBJ_BMP_1D_Bound:1; // A : +/*20*/ u8 OBJ_Tile_1D_Bound:2; // A+B: +/*22*/ u8 OBJ_BMP_1D_Bound:1; // A : /*23*/ u8 OBJ_HBlank_process:1; // A+B: OBJ processed during HBlank (GBA bit5) /*24*/ u8 CharacBase_Block:3; // A : Character Base (64K step) /*27*/ u8 ScreenBase_Block:3; // A : Screen Base (64K step) /*30*/ u8 ExBGxPalette_Enable:1; // A+B: 0=disable, 1=Enable BG extended Palette /*31*/ u8 ExOBJPalette_Enable:1; // A+B: 0=disable, 1=Enable OBJ extended Palette -}; +}; #endif -typedef union +typedef union { struct _DISPCNT bits; u32 val; -} DISPCNT; +} DISPCNT; #define BGxENABLED(cnt,num) ((num<8)? ((cnt.val>>8) & num):0) @@ -129,7 +130,7 @@ typedef union *******************************************************************************/ #ifdef WORDS_BIGENDIAN -struct _BGxCNT +struct _BGxCNT { /* 7*/ u8 Palette_256:1; // 0=16x16, 1=1*256 palette /* 6*/ u8 Mosaic_Enable:1; // 0=disable, 1=Enable mosaic @@ -144,9 +145,9 @@ struct _BGxCNT // BG2 overflow area wraparound 0=off, 1=wrap // BG3 overflow area wraparound 0=off, 1=wrap /* 8*/ u8 ScreenBase_Block:5; // individual screen base offset (text n*2KB, BMP n*16KB) -}; +}; #else -struct _BGxCNT +struct _BGxCNT { /* 0*/ u8 Priority:2; // 0..3=high..low /* 2*/ u8 CharacBase_Block:4; // individual character base offset (n*16KB) @@ -161,15 +162,15 @@ struct _BGxCNT // x/rot/s : 128x128 256x256 512x512 1024x1024 // bmp : 128x128 256x256 512x256 512x512 // large : 512x1024 1024x512 - - -}; +}; #endif -typedef union +typedef union { struct _BGxCNT bits; u16 val; -} BGxCNT; +} BGxCNT; /******************************************************************************* this structure is for background offset @@ -178,7 +179,7 @@ typedef union typedef struct { u16 BGxHOFS; u16 BGxVOFS; -} BGxOFS; +} BGxOFS; /******************************************************************************* this structure is for rotoscale parameters @@ -191,7 +192,7 @@ typedef struct { s16 BGxPD; s32 BGxX; s32 BGxY; -} BGxPARMS; +} BGxPARMS; /******************************************************************************* @@ -282,7 +283,7 @@ typedef struct { WINxDIM WIN1V; WINxCNT WININ; WINxCNT WINOUT; -} WINCNT; +} WINCNT; */ /******************************************************************************* @@ -303,7 +304,7 @@ typedef struct { u16 unused8; u16 unused9; */ -} MISCCNT; +} MISCCNT; /******************************************************************************* @@ -319,20 +320,20 @@ struct _DISP3DCNT /* 4*/ u8 EnableAntiAliasing:1; // /* 5*/ u8 EnableEdgeMarking:1; // see EDGE_COLOR /* 6*/ u8 FogOnlyAlpha:1; // 0=Alpha and Color, 1=Only Alpha (see FOG_COLOR) -/* 7*/ u8 EnableFog:1; // Fog Master Enable +/* 7*/ u8 EnableFog:1; // Fog Master Enable /* 8*/ u8 FogShiftSHR:4; // 0..10 SHR-Divider (see FOG_OFFSET) /*12*/ u8 AckColorBufferUnderflow:1; // Color Buffer RDLINES Underflow (0=None, 1=Underflow/Acknowledge) /*13*/ u8 AckVertexRAMOverflow:1; // Polygon/Vertex RAM Overflow (0=None, 1=Overflow/Acknowledge) /*14*/ u8 RearPlaneMode:1; // 0=Blank, 1=Bitmap /*15*/ u8 :1; /*16*/ u16 :16; -}; +}; -typedef union +typedef union { struct _DISP3DCNT bits; u32 val; -} DISP3DCNT; +} DISP3DCNT; /******************************************************************************* this structure is for capture control (core A only) @@ -357,13 +358,13 @@ struct _DISPCAPCNT /*28*/ u8 :1; // /*29*/ u8 Capture_Source:2; // 0=Source A, 1=Source B, 2/3=Sources A+B blended /*31*/ u8 Capture_Enable:1; // 0=Disable/Ready, 1=Enable/Busy -}; +}; -typedef union +typedef union { struct _DISPCAPCNT bits; u32 val; -} DISPCAPCNT; +} DISPCAPCNT; /******************************************************************************* @@ -374,7 +375,7 @@ typedef union typedef struct _reg_dispx { DISPCNT dispx_DISPCNT; // 0x0400x000 - u16 dispA_DISPSTAT; // 0x04000004 + u16 dispA_DISPSTAT; // 0x04000004 u16 dispx_VCOUNT; // 0x0400x006 BGxCNT dispx_BGxCNT[4]; // 0x0400x008 BGxOFS dispx_BGxOFS[4]; // 0x0400x010 @@ -385,7 +386,7 @@ typedef struct _reg_dispx { DISP3DCNT dispA_DISP3DCNT; // 0x04000060 DISPCAPCNT dispA_DISPCAPCNT; // 0x04000064 u32 dispA_DISPMMEMFIFO; // 0x04000068 -} REG_DISPx ; +} REG_DISPx ; @@ -405,7 +406,7 @@ typedef struct _reg_dispx { typedef BOOL (*fun_gl_Begin) (int screen); typedef void (*fun_gl_End) (int screen); // the GUI should use this function prior to all gl calls -// if call to beg succeeds opengl draw +// if call to beg succeeds opengl draw void register_gl_fun(fun_gl_Begin beg,fun_gl_End end); #define GPU_MAIN 0 @@ -438,7 +439,7 @@ struct _TILEENTRY /*14*/ unsigned Palette:4; }; #endif -typedef union +typedef union { struct _TILEENTRY bits; u16 val; @@ -450,7 +451,7 @@ struct _ROTOCOORD /* 8*/ signed Integer:24; // /*28*/ unsigned :4; }; -typedef union +typedef union { struct _ROTOCOORD bits; s32 val; @@ -475,7 +476,7 @@ struct _COLORx { // abgr x555 unsigned alpha:1; // sometimes it is unused (pad) }; -typedef union +typedef union { struct _COLOR bits; struct _COLORx bitx; @@ -493,7 +494,7 @@ struct _COLOR32 { // ARGB unsigned alpha:1; // sometimes it is unused (pad) }; -typedef union +typedef union { struct _COLOR32 bits; u32 val; @@ -529,7 +530,7 @@ typedef struct /*14*/ unsigned Shape:2; // (00: Square, 01: Wide, 10: Tall, 11: Illegal) // attr1 /* 0*/ signed X:9; -/* 9*/ unsigned RotScalIndex:3; // Rot/scale matrix index +/* 9*/ unsigned RotScalIndex:3; // Rot/scale matrix index /*12*/ unsigned HFlip:1; /*13*/ unsigned VFlip:1; /*14*/ unsigned Size:2; @@ -567,7 +568,7 @@ typedef struct #define NB_PRIORITIES 4 #define NB_BG 4 -typedef struct +typedef struct { u8 BGs[NB_BG], nbBGs; u8 PixelsX[256]; @@ -583,7 +584,7 @@ struct _GPU // some structs are becoming redundant // some functions too (no need to recopy some vars as it is done by MMU) REG_DISPx * dispx_st; - + DISPCAPCNT dispCapCnt; BOOL LayersEnable[5]; itemsForPriority_t itemsForPriority[NB_PRIORITIES]; @@ -591,23 +592,23 @@ struct _GPU #define BGBmpBB BG_bmp_ram #define BGChBB BG_tile_ram - + u8 *(BG_bmp_ram[4]); u8 *(BG_tile_ram[4]); u8 *(BG_map_ram[4]); - + u8 BGExtPalSlot[4]; u32 BGSize[4][2]; - + u8 lcd; u8 core; - + u8 dispMode; u8 vramBlock; BOOL dispBG[4]; BOOL dispOBJ; - + OAM * oam; u8 * sprMem; u8 sprBoundary; @@ -651,7 +652,7 @@ struct _GPU void (*spriteRender) (GPU * gpu, u16 l, u8 * dst, u8 * prioTab); }; /* -// normally should have same addresses +// normally should have same addresses static void REG_DISPx_pack_test(GPU * gpu) { REG_DISPx * r = gpu->dispx_st; @@ -717,7 +718,7 @@ typedef struct int (*Init)(); // Initializes stuff related to core void (*DeInit)(); // Deinitializes stuff related to core void (*Resize)(int width, int height, BOOL fullscreen); // Resizes window or fullscreen - void (*OnScreenText)(char *string, ...); // For handling save state messages, etc. + void (*OnScreenText)(char *string, ...); // For handling save state messages, etc. } GraphicsInterface_struct; extern GraphicsInterface_struct GFXDummy; diff --git a/desmume/src/cocoa/DeSmuME.cbp b/desmume/src/cocoa/DeSmuME.cbp new file mode 100644 index 000000000..76b22267b --- /dev/null +++ b/desmume/src/cocoa/DeSmuME.cbp @@ -0,0 +1,173 @@ + + + + + + diff --git a/desmume/src/cocoa/cocoa_util.m b/desmume/src/cocoa/cocoa_util.m new file mode 100644 index 000000000..28c59e595 --- /dev/null +++ b/desmume/src/cocoa/cocoa_util.m @@ -0,0 +1,96 @@ +/* Copyright (C) 2007 Jeff Bland + + This file is part of DeSmuME + + DeSmuME 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. + + DeSmuME 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 DeSmuME; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#import "globals.h" + +//////////////////////////////////////////////////////////////// +//Menu Item implementation-------------------------------------- +//////////////////////////////////////////////////////////////// + +@implementation NSMenu (localization) + +- (id )addItemWithTitle:(NSString *)aString action:(SEL)aSelector keyEquivalent:(NSString *)keyEquiv +{ + NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:localizedString(aString, nil) action:aSelector keyEquivalent:keyEquiv]; + [self addItem:item]; + + return item; +} + +- (id )addItemWithTitle:(NSString *)aString withInt:(int)number action:(SEL)aSelector keyEquivalent:(NSString *)keyEquiv +{ + NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:[NSString stringWithFormat:localizedString(aString, nil),number] action:aSelector keyEquivalent:keyEquiv]; + [self addItem:item]; + + return item; +} + +@end + +//////////////////////////////////////////////////////////////// +//Dialog Boxes------------------------------------------------- +//////////////////////////////////////////////////////////////// + +void messageDialogBlank() +{ + NSRunAlertPanel(@"Click OK", @" ", nil/*OK*/, nil, nil); +} + +void messageDialog(NSString *title, NSString *text) +{ + NSRunAlertPanel(title, text, nil/*OK*/, nil, nil); +} + +BOOL messageDialogYN(NSString *title, NSString *text) +{ + return NSRunAlertPanel(title, text, @"Yes", @"No", nil) != 0; +} + +//does an open dialog to choose an NDS file +//returns the filename or NULL if the user selected cancel +NSOpenPanel* panel; +NSString* openDialog(NSArray *file_types) +{ + panel = [NSOpenPanel openPanel]; + + [panel setCanChooseDirectories:NO]; + [panel setCanChooseFiles:YES]; + [panel setAllowsMultipleSelection:NO]; + + if([panel runModalForDirectory:@"/Users/gecko/nds" file:nil types:file_types] == NSOKButton) + { + //a file was selected + + id selected_file = [[panel filenames] lastObject]; //hopefully also the first object + + return selected_file; + } + + //a file wasn't selected + return NULL; +} + +//////////////////////////////////////////////////////////////// +//Language Stuff----------------------------------------------- +//////////////////////////////////////////////////////////////// + +NSString *localizedString(NSString *string, NSString *comment) +{ + return NSLocalizedString(string,nil); +} diff --git a/desmume/src/cocoa/globals.h b/desmume/src/cocoa/globals.h new file mode 100644 index 000000000..2e3730266 --- /dev/null +++ b/desmume/src/cocoa/globals.h @@ -0,0 +1,145 @@ +/* Copyright (C) 2007 Jeff Bland + + This file is part of DeSmuME + + DeSmuME 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. + + DeSmuME 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 DeSmuME; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +//fixme headers conform to desmume? +#ifndef GLOBALS_H_INCLUDED +#define GLOBALS_H_INCLUDED + +#import + +//fixme +#define desmume_TRUE TRUE + +//Nintendo DS constants--------------------------------------------------------------------------- + +//This just improves legibility throughut the code +//by showing you names instead of numbers + +#define DS_SCREEN_WIDTH 256 +#define DS_SCREEN_HEIGHT 192 +#define DS_SCREEN_HEIGHT_COMBINED (192*2) /*height of the two screens*/ +#define DS_SCREEN_X_RATIO (256.0 / (192.0 * 2.0)) +#define DS_SCREEN_Y_RATIO ((192.0 * 2.0) / 256.0) + +//Cocoa Util------------------------------------------------------------------------------------ +//These are just useful little functions to help with stuff +//defined in cocoa_util.m + +//c string to NSString +#define NSSTRc(x) ([[NSString alloc] initWithCString:(x) encoding:NSASCIIStringEncoding]) + +//these class extensions do the localstring lookup so we dont have to type it over and over again +/* +@interface NSMenuItem (localization) +- (id)initWithTitle:(NSString *)not_localized_name action:(SEL)action keyEquivalent:(NSString*)key; +@end +*/ +@interface NSMenu (localization) +- (id )addItemWithTitle:(NSString *)aString action:(SEL)aSelector keyEquivalent:(NSString *)keyEquiv; +- (id )addItemWithTitle:(NSString *)aString withInt:(int)number action:(SEL)aSelector keyEquivalent:(NSString *)keyEquiv; +@end + +//dialogs + +void messageDialogBlank(); +void messageDialog(NSString *title, NSString *text); +BOOL messageDialogYN(NSString *title, NSString *text); +NSString* openDialog(NSArray *file_types); + +// + +NSString* localizedString(NSString *stuff, NSString *comment); + +//Menus ------------------------------------------------------------------------------------------- +//These are all the menu items that need checkmarks +//or their enabled status managed + +//global menu (defined in main.m) +extern NSMenu *menu; + +//view (defined/managed in main_window.m) +extern NSMenuItem *resize1x; +extern NSMenuItem *resize2x; +extern NSMenuItem *resize3x; +extern NSMenuItem *resize4x; + +extern NSMenuItem *allows_resize_item; +extern NSMenuItem *constrain_item; +extern NSMenuItem *min_size_item; + +extern NSMenuItem *rotation0_item; +extern NSMenuItem *rotation90_item; +extern NSMenuItem *rotation180_item; +extern NSMenuItem *rotation270_item; + +extern NSMenuItem *topBG0_item; +extern NSMenuItem *topBG1_item; +extern NSMenuItem *topBG2_item; +extern NSMenuItem *topBG3_item; +extern NSMenuItem *subBG0_item; +extern NSMenuItem *subBG1_item; +extern NSMenuItem *subBG2_item; +extern NSMenuItem *subBG3_item; + +//execution control (defined/managed in nds_control.m) +extern NSMenuItem *close_rom_item; + +extern NSMenuItem *execute_item; +extern NSMenuItem *pause_item; +extern NSMenuItem *reset_item; + +extern NSMenuItem *save_state_as_item; +extern NSMenuItem *load_state_from_item; + +#define SAVE_SLOTS 10 //this should never be more than NB_SAVES in saves.h +extern NSMenuItem *saveSlot_item[SAVE_SLOTS]; +extern NSMenuItem *loadSlot_item[SAVE_SLOTS]; + +#define MAX_FRAME_SKIP 10 //this is actually 1 more than the highest frame skip +extern NSMenuItem *frame_skip_auto_item; +extern NSMenuItem *frame_skip_item[SAVE_SLOTS]; + +//extern NSMenuItem *clear_all_saves_item; waiting for more functionality from saves.h + +extern NSMenuItem *rom_info_item; + +//Cocoa Port Stuff --------------------------------------------------------------------------------- + +//Enable this to multithread the program +//#define MULTITHREADED + +//prototype for our NintendoDS class (defined in nds_control.h) +// +@class NintendoDS; + +//Here's our global DS object +//which controls things like pausing and whatnot +extern NintendoDS *NDS; + +@class VideoOutputWindow; +extern VideoOutputWindow *main_window; + +//-------------------------------------------------------------------------------------------------- + +extern volatile int /*desmume_BOOL*/ execute; + +extern volatile BOOL finished; +extern volatile BOOL paused; + +#endif // GLOBALS_H_INCLUDED diff --git a/desmume/src/cocoa/main.m b/desmume/src/cocoa/main.m new file mode 100644 index 000000000..eda29b50f --- /dev/null +++ b/desmume/src/cocoa/main.m @@ -0,0 +1,620 @@ +/* Copyright (C) 2007 Jeff Bland + + This file is part of DeSmuME + + DeSmuME 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. + + DeSmuME 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 DeSmuME; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* +This file is part of the Cocoa (Mac OS X) port of DeSmuME emulator +By Jeff Bland (reversegecko@gmail.com) +Based on work by yopyop and the DeSmuME team! +*/ + +//DeSmuME Cocoa includes +#import "globals.h" +#import "main_window.h" +#import "nds_control.h" + +//DeSmuME general includes +#define OBJ_C +#include "../SPU.h" +#include "../render3D.h" +#include "../GPU.h" +#include "../Windows/OGLRender.h" +#include "../NDSSystem.h" +#undef BOOL + +/* +FIXME: Apple+Q during open dialog = badness +FIXME: Live resize needs to work without pausing emulator +FIXME: Hardware acceleration for openglrender.c ?? +FIXME: When cross-platform (core) components end emulation due to error - pause should be called (set the menu checkmark) +FIXME: Multi-threaded version needs to do some sleep()-ing when not running game +FIXME: Some bug where states get messed up and hitting execute does nothing...... +FIXME: single threaded version requires an additional event to quit (after you tell the program to exit you gotta click or press something) +FIXME: .nds.gba extensions don't work in open panels +FIXME: Traveling windows when constantly resizing with hotkey +*/ + +//Globals---------------------------------------------------------------------------------------- + +NSMenu *menu; + +//Interfaces-------------------------------------------------------------------------------------- + +@interface NSApplication(custom) + +//this prototype was removed from the mac os headers +- (void)setAppleMenu:(NSMenu*)menu; + +//here we extend NSApplication +- (void)about; +- (void)preferences; + +@end + +@interface NSApplication(delegate) + +//delegate methods +- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename; +- (void)application:(NSApplication *)sender openFiles:(NSArray *)filenames; +- (void)applicationDidFinishLaunching:(NSNotification *)aNotification; +- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender; + +@end + +//Global access gui constructs +VideoOutputWindow *main_window; + +//Desmume globals--------------------------------------------------------------------------------------- + +//accessed from other files +volatile desmume_BOOL execute = FALSE; + +// +volatile BOOL finished = FALSE; +volatile BOOL paused = TRUE; + +SoundInterface_struct *SNDCoreList[] = { +&SNDDummy, +//&SNDFile, +//&SNDDIRECTX, +NULL +}; + +GPU3DInterface *core3DList[] = { +&gpu3DNull, +&gpu3Dgl +}; + +//NDS/Emulator control----------------------------------------------------------------------------------------- +//These functions should be called by GUI handling mechanisms to change the state of the emulator or emulation + +NintendoDS *NDS; + +void Quit() +{ + //stop emulation if it's going + [NDS pause]; + + // + finished = true; + + // + [NSApp stop:NSApp]; +} + +void AskForQuit() +{ + BOOL was_paused = paused; + + //pause while we prompt the user + [NDS pause]; + + //ask the user if quitting is acceptable + if(messageDialogYN(localizedString(@"DeSmuME Emulator", nil), localizedString(@"Are you sure you want to quit?", nil))) + Quit(); + else + if(!was_paused)[NDS execute]; //unpaused if we weren't paused before +} + +NSEvent *current_event; + +//if wait is true then it will sit around waiting for an +//event for a short period of time taking up very little CPU +//(use when game is not running) +inline void clearEvents(bool wait) +{ + //wait for the next event + while((current_event = [NSApp nextEventMatchingMask:0 untilDate:wait?[NSDate dateWithTimeIntervalSinceNow:.2]:nil inMode:NSDefaultRunLoopMode dequeue:YES])) + [NSApp sendEvent: current_event]; +} + +/////////////////////////////// + +//This generates and sets the entire menubar (and sets defaults) +//call after objects (ie NDS main_window) are inited +void CreateMenu() +{ + NSMenuItem *temp; + + NSMenu* application_menu; + NSMenu* services_menu; + NSMenu* file; + NSMenu* emulation; + NSMenu* view; + //NSMenu* window; + NSMenu* help; + + NSMenu* frame_skip_menu; + + SEL action = nil;//@selector(method:); + + //Create the outermost menu that contains all the others + menu = [[NSMenu alloc] initWithTitle:@"DeSmuME"]; + + //Create the "DeSmuME" (application) menu + application_menu = [[NSMenu alloc] initWithTitle:@"DeSmuME"]; + + //Create the sevices menu + services_menu = [[NSMenu alloc] initWithTitle:@"Services"]; + [NSApp setServicesMenu:services_menu]; + + //Add the about menu + temp = [application_menu addItemWithTitle:@"About DeSmuME" action:@selector(about) keyEquivalent:@""]; + [temp setTarget:NSApp]; + + // + [application_menu addItem: [NSMenuItem separatorItem]]; + + //Add the preferences menu + //temp = [application_menu addItemWithTitle:@"Preferences..." action:@selector(preferences) keyEquivalent:@","]; + //[temp setTarget:NSApp]; + + // + [application_menu addItem: [NSMenuItem separatorItem]]; + + //add the services menu to the application menu (after preferences) + temp = [application_menu addItemWithTitle:@"Services" action:nil keyEquivalent:@""]; + [temp setSubmenu:services_menu]; + + // + [application_menu addItem: [NSMenuItem separatorItem]]; + + //standard hide option + temp = [application_menu addItemWithTitle:@"Hide DeSmuME" action:@selector(hide:) keyEquivalent:@""]; + [temp setTarget:NSApp]; + + //standard hide others option + temp = [application_menu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@""]; + [temp setTarget:NSApp]; + + //standard show all option + temp = [application_menu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; + [temp setTarget:NSApp]; + + // + [application_menu addItem: [NSMenuItem separatorItem]]; + + //standard quit option + temp = [application_menu addItemWithTitle:@"Quit DeSmuME" action:@selector(terminate:) keyEquivalent:@"q"]; + [temp setTarget: NSApp]; + + //finally call setAppleMenu to have all our stuff working + [NSApp setAppleMenu:application_menu]; + + temp = [menu addItemWithTitle:@"" action:nil keyEquivalent:@""]; + [temp setSubmenu:application_menu]; + [temp release]; + + NSMenuItem *file_item = [menu addItemWithTitle:@"File" action:action keyEquivalent:@""]; + NSMenuItem *emulation_item = [menu addItemWithTitle:@"Emulation" action:action keyEquivalent:@""]; + NSMenuItem *view_item = [menu addItemWithTitle:@"View" action:action keyEquivalent:@""]; + //NSMenuItem *window_item = [menu addItemWithTitle:@"Window" action:action keyEquivalent:@""]; + NSMenuItem *help_item = [menu addItemWithTitle:@"Help" action:action keyEquivalent:@""]; + + //Create the File Menu + file = [[NSMenu alloc] initWithTitle:@"File"]; + [file setAutoenablesItems:NO]; + [menu setSubmenu:file forItem:file_item]; + + temp = [file addItemWithTitle:@"Open ROM..." action:@selector(pickROM) keyEquivalent:@"o"]; + [temp setTarget:NDS]; + + //recent items menu + temp = [file addItemWithTitle:@"Open Recent" action:nil keyEquivalent:@""]; + + NSMenu *recent_menu = [[NSMenu alloc] initWithTitle:@""]; + [temp setSubmenu:recent_menu]; + + [recent_menu addItemWithTitle:@"Blar" action:nil keyEquivalent:@""]; + + [file addItem:[NSMenuItem separatorItem]]; + + rom_info_item = [file addItemWithTitle:@"ROM Info..." action:@selector(showRomInfo) keyEquivalent:@""]; + [rom_info_item setEnabled:NO]; + [rom_info_item setTarget:NDS]; + +#ifdef HAVE_LIBZ //internally, save states only work when zlib is there + + [file addItem:[NSMenuItem separatorItem]]; + + save_state_as_item = [file addItemWithTitle:@"Save State As..." action:@selector(saveStateAs) keyEquivalent:@""]; + [save_state_as_item setEnabled:NO]; + [save_state_as_item setTarget:NDS]; + + load_state_from_item = [file addItemWithTitle:@"Load State From..." action:@selector(loadStateFrom) keyEquivalent:@""]; + [load_state_from_item setEnabled:NO]; + [load_state_from_item setTarget:NDS]; + + [file addItem:[NSMenuItem separatorItem]]; + + temp = [file addItemWithTitle:@"Save State" action:@selector(saveTo:) keyEquivalent:@""]; + NSMenu *save_state_menu = [[NSMenu alloc] initWithTitle:@"Save State"]; + [save_state_menu setAutoenablesItems:NO]; + [temp setSubmenu:save_state_menu]; + + temp = [file addItemWithTitle:@"Load State" action:nil keyEquivalent:@""]; + NSMenu *load_state_menu = [[NSMenu alloc] initWithTitle:@"Load State"]; + [load_state_menu setAutoenablesItems:NO]; + [temp setSubmenu:load_state_menu]; + + int i; + for(i = 0; i < SAVE_SLOTS; i++) + { + saveSlot_item[i] = [save_state_menu addItemWithTitle:@"Slot %d" withInt:i action:@selector(saveToSlot:) keyEquivalent:@""]; + [saveSlot_item[i] setEnabled:NO]; + [saveSlot_item[i] setTarget:NDS]; + + loadSlot_item[i] = [load_state_menu addItemWithTitle:@"Slot %d" withInt:i action:@selector(loadFromSlot:) keyEquivalent:@""]; + [loadSlot_item[i] setEnabled:NO]; + [loadSlot_item[i] setTarget:NDS]; + } + +/* To be implemented when saves.h provides +a way to get the time of a save that's not string/human formatted... + + [save_state_menu addItem:[NSMenuItem separatorItem]]; + + temp = [save_state_menu addItemWithTitle:@"Save Over Oldest" action:nil keyEquivalent:@""]; + [temp setEnabled:NO]; + [temp setTarget:NDS]; + + temp = [save_state_menu addItemWithTitle:@"Save Over Latest" action:nil keyEquivalent:@""]; + [temp setEnabled:NO]; + [temp setTarget:NDS]; +*/ +/* to be implemented after saves.h provides a way to delete saves... + + [save_state_menu addItem:[NSMenuItem separatorItem]]; + + clear_all_saves_item = [save_state_menu addItemWithTitle:@"Clear All" action:@selector(askAndClearStates) keyEquivalent:@""]; + [clear_all_saves_item setEnabled:NO]; + [clear_all_saves_item setTarget:NDS]; +*/ +/* + [save_state_menu addItem:[NSMenuItem separatorItem]]; + + temp = [save_state_menu addItemWithTitle:@"View States" action:nil keyEquivalent:@""]; + [temp setEnabled:NO]; + [temp setTarget:NDS]; +*/ +/* To be implemented when saves.h provides +a way to get the time of a save that's not a string / human formatted... + + [load_state_menu addItem:[NSMenuItem separatorItem]]; + + temp = [load_state_menu addItemWithTitle:@"Load Oldest" action:nil keyEquivalent:@""]; + [temp setEnabled:NO]; + [temp setTarget:NDS]; + + temp = [load_state_menu addItemWithTitle:@"Load Latest" action:nil keyEquivalent:@""]; + [temp setEnabled:NO]; + [temp setTarget:NDS]; +*/ +/* + [load_state_menu addItem:[NSMenuItem separatorItem]]; + + temp = [load_state_menu addItemWithTitle:@"View States" action:nil keyEquivalent:@""]; + [temp setEnabled:NO]; + [temp setTarget:NDS]; +*/ +#endif + + [file addItem:[NSMenuItem separatorItem]]; + + close_rom_item = [file addItemWithTitle:@"Close ROM" action:@selector(askAndCloseROM) keyEquivalent:@"w"]; + [close_rom_item setEnabled:NO]; + [close_rom_item setTarget:NDS]; + + //Create the Emulation Menu + emulation = [[NSMenu alloc] initWithTitle:localizedString(@"Emulation", nil)]; + [emulation setAutoenablesItems:NO]; + [menu setSubmenu:emulation forItem:emulation_item]; + + execute_item = [emulation addItemWithTitle:@"Execute" action:@selector(execute) keyEquivalent:@""]; + [execute_item setTarget:NDS]; + [execute_item setEnabled:NO]; + + pause_item = [emulation addItemWithTitle:@"Pause" action:@selector(pause) keyEquivalent:@""]; + [pause_item setTarget:NDS]; + [pause_item setEnabled:NO]; + + reset_item = [emulation addItemWithTitle:@"Reset" action:@selector(reset) keyEquivalent:@""]; + [reset_item setTarget:NDS]; + [reset_item setEnabled:NO]; + + [emulation addItem:[NSMenuItem separatorItem]]; + + temp = [emulation addItemWithTitle:@"Frame Skip" action:nil keyEquivalent:@""]; + frame_skip_menu = [[NSMenu alloc] initWithTitle:localizedString(@"Frame Skip", nil)]; + [temp setSubmenu:frame_skip_menu]; + + frame_skip_auto_item = [frame_skip_menu addItemWithTitle:@"Auto" action:@selector(setFrameSkip:) keyEquivalent:@""]; + [frame_skip_auto_item setTarget:NDS]; + [frame_skip_auto_item setState:NSOnState]; + [frame_skip_auto_item setEnabled:YES]; + + [frame_skip_menu addItem:[NSMenuItem separatorItem]]; + + frame_skip_item[0] = [frame_skip_menu addItemWithTitle:@"Off" action:@selector(setFrameSkip:) keyEquivalent:@""]; + [frame_skip_item[0] setTarget:NDS]; + [frame_skip_item[0] setEnabled:YES]; + + int i2; + for(i2 = 1; i2 < MAX_FRAME_SKIP; i2++) + { + frame_skip_item[i2] = [frame_skip_menu addItemWithTitle:@"%d" withInt:i2 action:@selector(setFrameSkip:) keyEquivalent:@""]; + [frame_skip_item[i2] setTarget:NDS]; + [frame_skip_item[i2] setEnabled:YES]; + } + + //Create the screens menu + view = [[NSMenu alloc] initWithTitle:localizedString(@"View", nil)]; + [menu setSubmenu:view forItem:view_item]; + + resize1x = [view addItemWithTitle:@"Size 1x" action:@selector(resizeScreen1x) keyEquivalent:@"1"]; + [resize1x setState:NSOnState]; + [resize1x setTarget:main_window]; + + resize2x = [view addItemWithTitle:@"Size 2x" action:@selector(resizeScreen2x) keyEquivalent:@"2"]; + [resize2x setTarget:main_window]; + + resize3x = [view addItemWithTitle:@"Size 3x" action:@selector(resizeScreen3x) keyEquivalent:@"3"]; + [resize3x setTarget:main_window]; + + resize4x = [view addItemWithTitle:@"Size 4x" action:@selector(resizeScreen4x) keyEquivalent:@"4"]; + [resize4x setTarget:main_window]; +/* + [view addItem:[NSMenuItem separatorItem]]; + + [view addItemWithTitle:@"Full Screen" action:nil keyEquivalent:@"f"]; +*/ + [view addItem:[NSMenuItem separatorItem]]; + + allows_resize_item = [view addItemWithTitle:@"Allow Resize" action:@selector(toggleAllowsResize) keyEquivalent:@""]; + [allows_resize_item setState:NSOnState]; + [allows_resize_item setTarget:main_window]; + + constrain_item = [view addItemWithTitle:@"Constrain Proportions" action:@selector(toggleConstrainProportions) keyEquivalent:@""]; + [constrain_item setState:NSOnState]; + [constrain_item setTarget:main_window]; + + min_size_item = [view addItemWithTitle: @"No smaller than DS" action:@selector(toggleMinSize) keyEquivalent:@""]; + [min_size_item setState:NSOnState]; + [min_size_item setTarget:main_window]; + + [view addItem:[NSMenuItem separatorItem]]; + + temp = [view addItemWithTitle: @"Rotation" action:nil keyEquivalent:@""]; + + NSMenu *rotation_menu = [[NSMenu alloc] initWithTitle:@"Rotation"]; + [temp setSubmenu: rotation_menu]; + + rotation0_item = [rotation_menu addItemWithTitle:@"0" action:@selector(setRotation0) keyEquivalent:@""]; + [rotation0_item setState:NSOnState]; + [rotation0_item setTarget:main_window]; + + rotation90_item = [rotation_menu addItemWithTitle:@"90" action:@selector(setRotation90) keyEquivalent:@""]; + [rotation90_item setState:NSOffState]; + [rotation90_item setTarget:main_window]; + + rotation180_item = [rotation_menu addItemWithTitle:@"180" action:@selector(setRotation180) keyEquivalent:@""]; + [rotation180_item setState:NSOffState]; + [rotation180_item setTarget:main_window]; + + rotation270_item = [rotation_menu addItemWithTitle:@"270" action:@selector(setRotation270) keyEquivalent:@""]; + [rotation270_item setState:NSOffState]; + [rotation270_item setTarget:main_window]; + + [view addItem:[NSMenuItem separatorItem]]; + + temp = [view addItemWithTitle:@"Layers" action:nil keyEquivalent:@""]; + NSMenu *layer_menu = [[NSMenu alloc] initWithTitle:@"Layers"]; + [temp setSubmenu: layer_menu]; + + topBG0_item = [layer_menu addItemWithTitle:@"Top BG0" action:@selector(toggleTopBackground0) keyEquivalent:@""]; + [topBG0_item setState:NSOnState]; + [topBG0_item setTarget:main_window]; + + topBG1_item = [layer_menu addItemWithTitle:@"Top BG1" action:@selector(toggleTopBackground1) keyEquivalent:@""]; + [topBG1_item setState:NSOnState]; + [topBG1_item setTarget:main_window]; + + topBG2_item = [layer_menu addItemWithTitle:@"Top BG2" action:@selector(toggleTopBackground2) keyEquivalent:@""]; + [topBG2_item setState:NSOnState]; + [topBG2_item setTarget:main_window]; + + topBG3_item = [layer_menu addItemWithTitle:@"Top BG3" action:@selector(toggleTopBackground3) keyEquivalent:@""]; + [topBG3_item setState:NSOnState]; + [topBG3_item setTarget:main_window]; + + [layer_menu addItem:[NSMenuItem separatorItem]]; + + subBG0_item = [layer_menu addItemWithTitle:@"Sub BG0" action:@selector(toggleSubBackground0) keyEquivalent:@""]; + [subBG0_item setState:NSOnState]; + [subBG0_item setTarget:main_window]; + + subBG1_item = [layer_menu addItemWithTitle:@"Sub BG1" action:@selector(toggleSubBackground1) keyEquivalent:@""]; + [subBG1_item setState:NSOnState]; + [subBG1_item setTarget:main_window]; + + subBG2_item = [layer_menu addItemWithTitle:@"Sub BG2" action:@selector(toggleSubBackground2) keyEquivalent:@""]; + [subBG2_item setState:NSOnState]; + [subBG2_item setTarget:main_window]; + + subBG3_item = [layer_menu addItemWithTitle:@"Sub BG3" action:@selector(toggleSubBackground3) keyEquivalent:@""]; + [subBG3_item setState:NSOnState]; + [subBG3_item setTarget:main_window]; + + //Create the window menu +/* + window = [[NSMenu alloc] initWithTitle:localizedString(@"Window", nil)]; + [menu setSubmenu:window forItem:window_item]; + + [window addItemWithTitle:@"Minimize" action:nil keyEquivalent:@""]; + [window addItemWithTitle:@"Zoom" action:nil keyEquivalent:@""]; + [window addItem:[NSMenuItem separatorItem]]; + [window addItemWithTitle:@"Bring All to Front" action:nil keyEquivalent:@""]; + [window addItem:[NSMenuItem separatorItem]]; + [window addItemWithTitle:@"DS Display" action:nil keyEquivalent:@""]; + //[window addItemWithTitle:@"Save State Viewer" action:nil keyEquivalent:@""]; + //[window addItemWithTitle:@"Debugger" action:nil keyEquivalent:@""]; + //[window addItem:[NSMenuItem separatorItem]]; + //[window addItemWithTitle:@"(screenshots)" action:nil keyEquivalent:@""]; +*/ + + //Create the help menu + help = [[NSMenu alloc] initWithTitle:localizedString(@"Help", nil)]; + [menu setSubmenu:help forItem:help_item]; + + [help addItemWithTitle:@"Website" action:nil keyEquivalent: @""]; + [help addItemWithTitle:@"Forums" action:nil keyEquivalent: @""]; + [help addItemWithTitle:@"Submit A Bug Report" action:nil keyEquivalent: @""]; + + [NSApp setMainMenu: menu]; + + [menu update]; +} + +//Main Function-------------------------------------------------------------------------------------- + +int main(int argc, char *argv[]) +{ + + srand(time(NULL)); + + //Application Init Stuff---------------------------------------------------------------------- + + //Get the application instance (global variable called NSApp) + [NSApplication sharedApplication]; + + //Set the application delegate + [NSApp setDelegate:NSApp]; + + [NSApp run]; + + //Program Exit --------------------------------------------------------------------------------------- + + return 0; +} + +//gdb stuff-------------------------------------------------------------------------------- +//don't know and don't care + +void * +createThread_gdb( void (*thread_function)( void *data), + void *thread_data) { +return NULL; +} + +void +joinThread_gdb( void *thread_handle) { +} + +//Implementations------------------------------------------------------------------------- + +@implementation NSApplication(delegate) + +- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename +{ + if([NDS loadROM:filename]) + return YES; + + return NO; +} + +- (void)application:(NSApplication *)sender openFiles:(NSArray *)filenames +{ + //messageDialog(@"Openfiles",@""); +} + +- (void)applicationDidFinishLaunching:(NSNotification *)aNotification +{ + + //More app Init ------------------------------------------------------------------------------ + + //Bring the application to the front + [NSApp activateIgnoringOtherApps:TRUE]; + + //create the global ds object + NDS = [[NintendoDS alloc] init]; + + //create the video output window (the only window that opens with the app) + main_window = [[VideoOutputWindow alloc] init]; + + //start with a blank screen + [main_window clearScreen]; + + //create the menus + CreateMenu(); + + //init opengl 3d ness + NDS_3D_SetDriver (GPU3D_OPENGL); + if(!gpu3D->NDS_3D_Init()) + messageDialog(@"Error", @"Unable to initialize OpenGL components"); + + //[NDS LoadROM:@"/Users/gecko/nds/0004 - Feel the Magic - XY-XX (U) (Trashman).nds"]; + //^ above line breaks everything!? + + //Main program loop ---------------------------------------------------------------------------- + +#ifdef MULTITHREADED + + //Breakoff a thread to run + [NSApplication detachDrawingThread:@selector(run) toTarget:NDS withObject:nil]; + +#else + + [NDS run]; + + //it seems we need an event before it will quit + //(probably has something to do with calling run from applicationDidFinishLaunching?) + [NSEvent startPeriodicEventsAfterDelay:0 withPeriod:1]; + +#endif + +} + +- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender +{ + //Ask user if he wants to quit + AskForQuit(); + + //AskForQuit takes care of quitting, dont need cocoa to do it for us + return NSTerminateCancel; +} +@end diff --git a/desmume/src/cocoa/main_window.h b/desmume/src/cocoa/main_window.h new file mode 100644 index 000000000..b2ed2cf6e --- /dev/null +++ b/desmume/src/cocoa/main_window.h @@ -0,0 +1,87 @@ +/* Copyright (C) 2007 Jeff Bland + + This file is part of DeSmuME + + DeSmuME 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. + + DeSmuME 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 DeSmuME; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef MAIN_WINDOW_H +#define MAIN_WINDOW_H + +#import + +//This interface is to create and manaage the window +//that displays DS video output and takes keyboard/mouse input +//do not instanciate more than one of these +@interface VideoOutputWindow : NSWindow {} + +//initialization +- (id)init; + +//call this function to read the screen from the emulator and update the window +//this is the only method involving cocoa that should be called from the run() function +- (void)updateScreen; + +//makes the screen white +- (void)clearScreen; + +//resets the min size internalls (when rotation changes), shouldn't be used from outside +- (void)resetMinSize:(bool)resize; + +//toggles between allowing tiny sizes and only being as small as DS +- (void)toggleMinSize; + +//this method will contrain the size as well +//this is screen size not window size +- (void)resizeScreen:(NSSize)size; + + +//like resizeScreen but does a size in relation to DS pixels +- (void)resizeScreen1x; +- (void)resizeScreen2x; +- (void)resizeScreen3x; +- (void)resizeScreen4x; + +// +- (void)toggleAllowsResize; +- (void)toggleConstrainProportions; + +//rotation +- (void)setRotation0; +- (void)setRotation90; +- (void)setRotation180; +- (void)setRotation270; + +//layers +- (void)toggleTopBackground0; +- (void)toggleTopBackground1; +- (void)toggleTopBackground2; +- (void)toggleTopBackground3; +- (void)toggleSubBackground0; +- (void)toggleSubBackground1; +- (void)toggleSubBackground2; +- (void)toggleSubBackground3; + +//keyboard input +- (void)keyDown:(NSEvent*)event; +- (void)keyUp:(NSEvent*)event; + +//mouse input +- (void)mouseDown:(NSEvent*)event; +- (void)mouseDragged:(NSEvent*)event; +- (void)mouseUp:(NSEvent*)event; +@end + +#endif //MAIN_WINDOW_H diff --git a/desmume/src/cocoa/main_window.m b/desmume/src/cocoa/main_window.m new file mode 100644 index 000000000..6ad4cffeb --- /dev/null +++ b/desmume/src/cocoa/main_window.m @@ -0,0 +1,1336 @@ +/* Copyright (C) 2007 Jeff Bland + + This file is part of DeSmuME + + DeSmuME 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. + + DeSmuME 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 DeSmuME; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#import +#import + +//DeSmuME Cocoa includes +#import "globals.h" +#import "main_window.h" +#import "nds_control.h" + +//DeSmuME general includes +#define OBJ_C +#include "../MMU.h" +#include "../GPU.h" +#undef BOOL + +// +BOOL keep_proportions = YES; + +//Title bar size (calculated by VideoOuputWindow init) +//useful for window rect calculations +unsigned short title_bar_height; + +//How much padding to put around the video output +#define WINDOW_BORDER_PADDING 5 + +//data is copied here from the DS screen to flip it +volatile u8 correction_buffer[DS_SCREEN_WIDTH * DS_SCREEN_HEIGHT_COMBINED * 2 /*bits per pixel*/]; +volatile u8 temp_buffer[DS_SCREEN_WIDTH * DS_SCREEN_HEIGHT_COMBINED * 2 /*bits per pixel*/]; + +//this is th opengl view where we will display the video output +@class VideoOutputView; +VideoOutputView *video_output_view; + +//fast access to size of openglview (not size of window) +volatile unsigned short x_size = DS_SCREEN_WIDTH; +volatile unsigned short y_size = DS_SCREEN_HEIGHT_COMBINED; + +//screen menu items +NSMenuItem *resize1x; +NSMenuItem *resize2x; +NSMenuItem *resize3x; +NSMenuItem *resize4x; +NSMenuItem *allows_resize_item; +NSMenuItem *constrain_item; +NSMenuItem *min_size_item; +NSMenuItem *rotation0_item; +NSMenuItem *rotation90_item; +NSMenuItem *rotation180_item; +NSMenuItem *rotation270_item; +NSMenuItem *topBG0_item; +NSMenuItem *topBG1_item; +NSMenuItem *topBG2_item; +NSMenuItem *topBG3_item; +NSMenuItem *subBG0_item; +NSMenuItem *subBG1_item; +NSMenuItem *subBG2_item; +NSMenuItem *subBG3_item; + +//Default key config (based on the windows version) +unsigned short ds_up = 126; //up arrow +unsigned short ds_down = 125; //down arrow +unsigned short ds_left = 123; //left arrow +unsigned short ds_right = 124; //right arrrow +unsigned short ds_a = 9 ; //v +unsigned short ds_b = 11 ; //b +unsigned short ds_x = 5 ; //g +unsigned short ds_y = 4 ; //h +unsigned short ds_l = 8 ; //c +unsigned short ds_r = 45 ; //n +unsigned short ds_select = 49 ; //space bar +unsigned short ds_start = 36 ; //enter +unsigned short ds_debug = 999; + +// +unsigned short save_slot_1 = 122; //F1 +unsigned short save_slot_2 = 120; //F2 +unsigned short save_slot_3 = 99; //F3 +unsigned short save_slot_4 = 118; //F4 +unsigned short save_slot_5 = 96; //F5 +unsigned short save_slot_6 = 97; //F6 +unsigned short save_slot_7 = 98; //F7 +unsigned short save_slot_8 = 100; //F8 +unsigned short save_slot_9 = 101; //F9 +unsigned short save_slot_10 = 109; //F10 +//unsigned short save_slot_11 = 103; //F11 +//unsigned short save_slot_12 = 111; //F12 + +NSOpenGLContext *gpu_context; + +//rotation +#define ROTATION_0 0 +#define ROTATION_90 1 +#define ROTATION_180 2 +#define ROTATION_270 3 +u8 rotation = ROTATION_0; + +//extern unsigned char GPU_screen3D[256*256*4]; + +u8 gpu_buff[256 * 256 * 4]; +//#define gpu_buff GPU_screen3D + +//min sizes (window size, not ds screen size) +NSSize min_size; + +//Window delegate class --------------------------------------------------------- + +@interface WindowDelegate : NSObject {} +- (void)windowDidResize:(NSNotification *)aNotification; +- (BOOL)windowShouldClose:(id)sender; +- (NSSize)windowWillResize:(NSWindow *)sender toSize:(NSSize)proposedFrameSize; +@end + +@interface VideoOutputView : NSView +{ + @private + NSOpenGLContext* context; + NSOpenGLPixelFormat* format; +} +- (id)initWithFrame:(NSRect)frame; +- (void)draw; +- (void)drawRect:(NSRect)bounds; +- (void)setFrame:(NSRect)rect; +- (BOOL) isOpaque; +@end + +@implementation VideoOutputView + +- (id)initWithFrame:(NSRect)frame +{ + //Initialize the view------------------------------------------------------------------ + + self = [super initWithFrame:frame]; + + if(self==nil) + { + messageDialog(@"Error", @"Could not init frame for OpenGL display"); + return nil; + } + + //Initialize the OpenGL context for displaying the screen ----------------------------------- + + //Create the pixel format for our video output view + NSOpenGLPixelFormatAttribute attrs[] = + { + NSOpenGLPFAAccelerated, + NSOpenGLPFANoRecovery, + NSOpenGLPFAColorSize, 16, + NSOpenGLPFAAlphaSize, 0, + NSOpenGLPFADepthSize, 0, + NSOpenGLPFAWindow, + 0 + }; + + NSOpenGLPixelFormat* pixel_format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs]; + if(pixel_format == nil) + { + messageDialog(@"Error", @"Couldn't create OpenGL pixel format for video output"); + return self; + } + + context = [[NSOpenGLContext alloc] initWithFormat:pixel_format shareContext:nil]; + if(context == nil) + { + messageDialog(@"Error", @"Couldn't create OpenGL context for video output"); + return self; + } + + //Initialize the OpenGL context for 3D rendering --------------------------------------- + + //Create the pixel format for our gpu + NSOpenGLPixelFormatAttribute attrs2[] = + { + //NSOpenGLPFAAccelerated, + //NSOpenGLPFANoRecovery, + //NSOpenGLPFADoubleBuffer, + NSOpenGLPFAColorSize, 24, + NSOpenGLPFAAlphaSize, 8, + NSOpenGLPFADepthSize, 24, + //NSOpenGLPFAStencilSize, 8, + NSOpenGLPFAOffScreen, + 0 + }; + + NSOpenGLPixelFormat* pixel_format2 = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs2]; + if(pixel_format2 == nil) + { + messageDialog(@"Error", @"Couldn't create OpenGL pixel format for GPU"); + return self; + } + + gpu_context = [[NSOpenGLContext alloc] initWithFormat:pixel_format2 shareContext:nil]; + if(gpu_context == nil) + { + messageDialog(@"Error", @"Couldn't create OpenGL context for GPU"); + return self; + } + + //offscreen rendering + [gpu_context setOffScreen:(void*)&gpu_buff width:DS_SCREEN_WIDTH height:DS_SCREEN_HEIGHT rowbytes:DS_SCREEN_WIDTH * 4]; + + //this will init opengl for drawing + [self setFrame:frame]; + + // + return self; +} + +- (void) draw +{ + NSRect blar; + [self drawRect:blar]; +} + +- (void)drawRect:(NSRect)bounds +{ + [context setView:self]; //for some reason this doesnt work when called from the init function + + [context makeCurrentContext]; + + if(rotation == ROTATION_0 || rotation == ROTATION_180) + { + + //here we send our corrected video buffer off to OpenGL where it gets pretty much + //directly copied to the frame buffer (and converted to the devices color format) + glDrawPixels(DS_SCREEN_WIDTH, DS_SCREEN_HEIGHT_COMBINED, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, (GLvoid*)&correction_buffer); + + } else + { + glDrawPixels(DS_SCREEN_HEIGHT_COMBINED, DS_SCREEN_WIDTH, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, (GLvoid*)&correction_buffer); + } + + glFlush(); + + [gpu_context makeCurrentContext]; +} + +- (void)setFrame:(NSRect)rect +{ + BOOL was_paused = paused; + [NDS pause]; + + [super setFrame:rect]; + + [context update]; + +#ifndef MULTITHREADED + [context makeCurrentContext]; +#endif + + //set the viewport (so the raster pos will be correct) + glViewport(0, 0, rect.size.width, rect.size.height); + + if(rotation == ROTATION_0) + { + + //the raster pos controls where the bitmap where will be placed + glRasterPos2f(-1, 1); + + //set the pixel zoom so our bitmap streches to fit our new opengl size + glPixelZoom(((float)rect.size.width) / ((float)DS_SCREEN_WIDTH), -((float)rect.size.height) / ((float)DS_SCREEN_HEIGHT_COMBINED)); + + } else if (rotation == ROTATION_90) + { + + //the raster pos controls where the bitmap where will be placed + glRasterPos2f(1, 1); + + //set the pixel zoom so our bitmap streches to fit our new opengl size + glPixelZoom(-((float)rect.size.width) / ((float)DS_SCREEN_HEIGHT_COMBINED), -((float)rect.size.height) / ((float)DS_SCREEN_WIDTH)); + + } else if (rotation == ROTATION_180) + { + + //set the viewport (so the raster pos will be correct) + glViewport(0, 0, rect.size.width, rect.size.height); + + //the raster pos controls where the bitmap where will be placed + glRasterPos2f(1, -1); + + //set the pixel zoom so our bitmap streches to fit our new opengl size + glPixelZoom(-((float)rect.size.width) / ((float)DS_SCREEN_WIDTH), ((float)rect.size.height) / ((float)DS_SCREEN_HEIGHT_COMBINED)); + + } else if (rotation == ROTATION_270) + { + //the raster pos controls where the bitmap where will be placed + glRasterPos2f(-1, -1); + + //set the pixel zoom so our bitmap streches to fit our new opengl size + glPixelZoom(((float)rect.size.width) / ((float)DS_SCREEN_HEIGHT_COMBINED), ((float)rect.size.height) / ((float)DS_SCREEN_WIDTH)); + + } + +#ifndef MULTITHREADED + [gpu_context makeCurrentContext]; +#endif + + if(!was_paused)[NDS execute]; +} + +- (BOOL)isOpaque +{ + return YES; +} +@end + +/////////////////////////////////////////////////////////////////////////////////////// +//Video output window class ---------------------------------------------------------- +/////////////////////////////////////////////////////////////////////////////////////// + +@implementation VideoOutputWindow + +- (id)init +{ + + // + NSRect rect; + + //Create the window rect (content rect - title bar not included in size) + rect.size.width = DS_SCREEN_WIDTH + WINDOW_BORDER_PADDING * 2; + rect.size.height = DS_SCREEN_HEIGHT_COMBINED + WINDOW_BORDER_PADDING; + rect.origin.x = 200; + rect.origin.y = 200; + + //allocate the window + self = [super initWithContentRect:rect styleMask: + + NSTitledWindowMask|NSResizableWindowMask|/*NSClosableWindowMask|*/NSMiniaturizableWindowMask|NSTexturedBackgroundWindowMask + + backing:NSBackingStoreBuffered defer:NO screen:nil]; + + [self setTitle:@"DeSmuME Emulator"]; + + //set minimum window size (to the starting size, pixel-for-pixel to DS) + //this re-gets the window rect to include the title bar size + NSSize tempsize; + tempsize.width = 1; + tempsize.height = 1; + [self setMinSize:tempsize]; + min_size = rect.size; + + NSSize temp; + temp.width = WINDOW_BORDER_PADDING * 2 + 2; + temp.height = WINDOW_BORDER_PADDING + 2; + [self setContentMinSize:temp]; + + //set title_bar_height + title_bar_height = [super frame].size.height - rect.size.height; + + //Set the window delegate + [self setDelegate:[[WindowDelegate alloc] init]]; + + //Create the image view where we will display video output + rect.origin.x = WINDOW_BORDER_PADDING; + rect.origin.y = WINDOW_BORDER_PADDING; + rect.size.width = DS_SCREEN_WIDTH; + rect.size.height = DS_SCREEN_HEIGHT_COMBINED; + if((video_output_view = [[VideoOutputView alloc] initWithFrame:rect]) == nil) + messageDialog(@"Error", @"Couldn't create OpenGL view to display screens"); + else + { + [[self contentView] addSubview:video_output_view]; + + } + + //Show the window + [[[NSWindowController alloc] initWithWindow:self] showWindow:nil]; + + return self; +} + +- (void)updateScreen +{ + //here we copy gpu_screen to our own buffer + + if(rotation == ROTATION_0 || rotation == ROTATION_180) + memcpy(&correction_buffer, &GPU_screen, DS_SCREEN_WIDTH * DS_SCREEN_HEIGHT_COMBINED * 2); + else + { + //here is where we turn the screen sideways + + int x, y; + for(x = 0; x< DS_SCREEN_WIDTH; x++) + for(y = 0; y < DS_SCREEN_HEIGHT_COMBINED; y++) + { + correction_buffer[(x * DS_SCREEN_HEIGHT_COMBINED + y) * 2] = GPU_screen[(y * DS_SCREEN_WIDTH + x) * 2]; + correction_buffer[(x * DS_SCREEN_HEIGHT_COMBINED + y) * 2 + 1] = GPU_screen[(y * DS_SCREEN_WIDTH + x) * 2 + 1]; + } + + } + + //then video output view draws from that buffer + [video_output_view draw]; +} + +- (void)clearScreen +{ + //fill our buffer with pure white + memset(&correction_buffer, 255, DS_SCREEN_WIDTH * DS_SCREEN_HEIGHT_COMBINED * 2); + + [video_output_view draw]; +} + +- (void)resetMinSize:(bool)resize +{ + if(rotation == ROTATION_0 || rotation == ROTATION_180) + { + min_size.width = DS_SCREEN_WIDTH + WINDOW_BORDER_PADDING * 2; + min_size.height = DS_SCREEN_HEIGHT_COMBINED + WINDOW_BORDER_PADDING + title_bar_height; + + //resize if too small + if(resize) + { + NSSize temp = [video_output_view frame].size; + if(temp.width < DS_SCREEN_WIDTH || temp.height < DS_SCREEN_HEIGHT_COMBINED) + [self resizeScreen:NSMakeSize(DS_SCREEN_WIDTH, DS_SCREEN_HEIGHT_COMBINED)]; //this could be per axis? + } + + } else + { + min_size.width = DS_SCREEN_HEIGHT_COMBINED + WINDOW_BORDER_PADDING * 2; + min_size.height = DS_SCREEN_WIDTH + WINDOW_BORDER_PADDING + title_bar_height; + + //resize if too small + if(resize) + { + NSSize temp = [video_output_view frame].size; + if(temp.width < DS_SCREEN_HEIGHT_COMBINED || temp.height < DS_SCREEN_WIDTH) + [self resizeScreen:NSMakeSize(DS_SCREEN_HEIGHT_COMBINED, DS_SCREEN_WIDTH)]; + } + } +} + +- (void)toggleMinSize +{ + static bool state = false; + + if([min_size_item state] == NSOnState) + { + [min_size_item setState:NSOffState]; + min_size.width = 0; + min_size.height = 0; + } else + { + [min_size_item setState:NSOnState]; + [self resetMinSize:true]; + } +} + +- (void)resizeScreen:(NSSize)size +{ + //if(x_size == size.width && y_size == size.height)return; + + BOOL was_paused = paused; + [NDS pause]; + + //add the window borders + size.width += WINDOW_BORDER_PADDING * 2; + size.height += WINDOW_BORDER_PADDING + title_bar_height; + + //constrain + size = [[self delegate] windowWillResize:self toSize:size]; + + //set the position (keeping the center of the window the same) + NSRect current_window_rect = [super frame]; + current_window_rect.origin.x -= ((size.width + WINDOW_BORDER_PADDING * 2) - current_window_rect.size.width) / 2; + current_window_rect.origin.y -= ((size.height + WINDOW_BORDER_PADDING + title_bar_height) - current_window_rect.size.height) / 2; + + //and change the size + current_window_rect.size.width = size.width; + current_window_rect.size.height = size.height; + + //send it off to cocoa + [self setFrame:current_window_rect display:YES]; + + if(!was_paused)[NDS execute]; +} + +- (void)resizeScreen1x +{ + + if(rotation == ROTATION_0 || rotation == ROTATION_180) + [self resizeScreen:NSMakeSize(DS_SCREEN_WIDTH, DS_SCREEN_HEIGHT_COMBINED)]; + else + [self resizeScreen:NSMakeSize(DS_SCREEN_HEIGHT_COMBINED, DS_SCREEN_WIDTH)]; +} + +- (void)resizeScreen2x +{ + + if(rotation == ROTATION_0 || rotation == ROTATION_180) + [self resizeScreen:NSMakeSize(DS_SCREEN_WIDTH * 2, DS_SCREEN_HEIGHT_COMBINED * 2)]; + else + [self resizeScreen:NSMakeSize(DS_SCREEN_HEIGHT_COMBINED * 2, DS_SCREEN_WIDTH * 2)]; +} + +- (void)resizeScreen3x +{ + if(rotation == ROTATION_0 || rotation == ROTATION_180) + [self resizeScreen:NSMakeSize(DS_SCREEN_WIDTH * 3, DS_SCREEN_HEIGHT_COMBINED * 3)]; + else + [self resizeScreen:NSMakeSize(DS_SCREEN_HEIGHT_COMBINED * 3, DS_SCREEN_WIDTH * 3)]; +} + +- (void)resizeScreen4x +{ + if(rotation == ROTATION_0 || rotation == ROTATION_180) + [self resizeScreen:NSMakeSize(DS_SCREEN_WIDTH * 4, DS_SCREEN_HEIGHT_COMBINED * 4)]; + else + [self resizeScreen:NSMakeSize(DS_SCREEN_HEIGHT_COMBINED * 4, DS_SCREEN_WIDTH * 4)]; +} + +- (void)toggleAllowsResize +{ + //get the resize control state + BOOL resizes = [self showsResizeIndicator]; + + if(resizes == YES) + { + // + resizes = NO; + + //don't allow resize + //hack!!! fixme + NSSize temp; + temp.width = 9000; + temp.height = 9000; + [self setResizeIncrements:temp]; + + //don't show resize control + [self setShowsResizeIndicator:NO]; + + //unset the check + [allows_resize_item setState:NSOffState]; + + } else{ + resizes = YES; + + //allow resize + NSSize temp; + temp.width = 1; + temp.height = 1; + [self setResizeIncrements:temp]; + + //show resize control + [self setShowsResizeIndicator:YES]; + + //set the check + [allows_resize_item setState:NSOnState]; + } +} + +- (void)toggleConstrainProportions; +{ + //change the state + keep_proportions = !keep_proportions; + + //constrain + NSSize size; + size.width = x_size; + size.height = y_size; + if(keep_proportions) + [self resizeScreen:size]; + + //set the menu checks + if(keep_proportions) + [constrain_item setState:NSOnState]; + else + [constrain_item setState:NSOffState]; +} + +- (void)setRotation0 +{ + if(rotation == ROTATION_0)return; + + if(rotation == ROTATION_180) + { + rotation = ROTATION_0; + + [video_output_view setFrame:[video_output_view frame]]; + [self updateScreen]; + + } else + { + //set the global rotation state + rotation = ROTATION_0; + + //fix the buffer + memcpy(&temp_buffer, &correction_buffer, DS_SCREEN_WIDTH * DS_SCREEN_HEIGHT_COMBINED * 2); + int x, y; + for(x = 0; x< DS_SCREEN_WIDTH; x++) + for(y = 0; y < DS_SCREEN_HEIGHT_COMBINED; y++) + { + correction_buffer[(y * DS_SCREEN_WIDTH + x) * 2] = temp_buffer[(x * DS_SCREEN_HEIGHT_COMBINED + y) * 2]; + correction_buffer[(y * DS_SCREEN_WIDTH + x) * 2 + 1] = temp_buffer[(x * DS_SCREEN_HEIGHT_COMBINED + y) * 2 + 1]; + } + + //fix the min size + if([min_size_item state] == NSOnState) + [self resetMinSize:false]; + + //resize the window/view + NSSize video_size = [video_output_view frame].size; + float temp = video_size.width; + video_size.width = video_size.height; + video_size.height = temp; + [self resizeScreen:video_size]; + } + + //set the checkmarks + [rotation0_item setState:NSOnState ]; + [rotation90_item setState:NSOffState]; + [rotation180_item setState:NSOffState]; + [rotation270_item setState:NSOffState]; +} + +- (void)setRotation90 +{ + if(rotation == ROTATION_90)return; + + if(rotation == ROTATION_270) + { + + rotation = ROTATION_90; + + [video_output_view setFrame:[video_output_view frame]]; + [self updateScreen]; + + } else + { + //set the global rotation state + rotation = ROTATION_90; + + //fix the buffer + memcpy(&temp_buffer, &correction_buffer, DS_SCREEN_WIDTH * DS_SCREEN_HEIGHT_COMBINED * 2); + int x, y; + for(x = 0; x< DS_SCREEN_WIDTH; x++) + for(y = 0; y < DS_SCREEN_HEIGHT_COMBINED; y++) + { + correction_buffer[(x * DS_SCREEN_HEIGHT_COMBINED + y) * 2] = temp_buffer[(y * DS_SCREEN_WIDTH + x) * 2]; + correction_buffer[(x * DS_SCREEN_HEIGHT_COMBINED + y) * 2 + 1] = temp_buffer[(y * DS_SCREEN_WIDTH + x) * 2 + 1]; + } + + //fix min size + if([min_size_item state] == NSOnState) + [self resetMinSize:false]; + + //resize the window/screen + NSSize video_size = [video_output_view frame].size; + float temp = video_size.width; + video_size.width = video_size.height; + video_size.height = temp; + [self resizeScreen:video_size]; + } + + //set the checkmarks + [rotation0_item setState:NSOffState]; + [rotation90_item setState:NSOnState ]; + [rotation180_item setState:NSOffState]; + [rotation270_item setState:NSOffState]; +} + +- (void)setRotation180 +{ + if(rotation == ROTATION_180)return; + + if(rotation == ROTATION_0) + { + rotation = ROTATION_180; + + [video_output_view setFrame:[video_output_view frame]]; + [self updateScreen]; + + } else + { + //set the global rotation state + rotation = ROTATION_180; + + //fix the buffer + memcpy(&temp_buffer, &correction_buffer, DS_SCREEN_WIDTH * DS_SCREEN_HEIGHT_COMBINED * 2); + int x, y; + for(x = 0; x< DS_SCREEN_WIDTH; x++) + for(y = 0; y < DS_SCREEN_HEIGHT_COMBINED; y++) + { + correction_buffer[(y * DS_SCREEN_WIDTH + x) * 2] = temp_buffer[(x * DS_SCREEN_HEIGHT_COMBINED + y) * 2]; + correction_buffer[(y * DS_SCREEN_WIDTH + x) * 2 + 1] = temp_buffer[(x * DS_SCREEN_HEIGHT_COMBINED + y) * 2 + 1]; + } + + //fix the min size + if([min_size_item state] == NSOnState) + [self resetMinSize:false]; + + //resize the window/view + NSSize video_size = [video_output_view frame].size; + float temp = video_size.width; + video_size.width = video_size.height; + video_size.height = temp; + [self resizeScreen:video_size]; + + } + + //set the checkmarks + [rotation0_item setState:NSOffState]; + [rotation90_item setState:NSOffState]; + [rotation180_item setState:NSOnState ]; + [rotation270_item setState:NSOffState]; +} + +- (void)setRotation270 +{ + if(rotation == ROTATION_270)return; + + if(rotation == ROTATION_90) + { + rotation = ROTATION_270; + + [video_output_view setFrame:[video_output_view frame]]; + [self updateScreen]; + + } else + { + + //set the global rotation state + rotation = ROTATION_270; + + //fix the buffer + memcpy(&temp_buffer, &correction_buffer, DS_SCREEN_WIDTH * DS_SCREEN_HEIGHT_COMBINED * 2); + int x, y; + for(x = 0; x< DS_SCREEN_WIDTH; x++) + for(y = 0; y < DS_SCREEN_HEIGHT_COMBINED; y++) + { + correction_buffer[(x * DS_SCREEN_HEIGHT_COMBINED + y) * 2] = temp_buffer[(y * DS_SCREEN_WIDTH + x) * 2]; + correction_buffer[(x * DS_SCREEN_HEIGHT_COMBINED + y) * 2 + 1] = temp_buffer[(y * DS_SCREEN_WIDTH + x) * 2 + 1]; + } + + //fix the min size + if([min_size_item state] == NSOnState) + [self resetMinSize:false]; + + //resize the window/screen + NSSize video_size = [video_output_view frame].size; + float temp = video_size.width; + video_size.width = video_size.height; + video_size.height = temp; + [self resizeScreen:video_size]; + } + + //set the checkmarks + [rotation0_item setState:NSOffState]; + [rotation90_item setState:NSOffState]; + [rotation180_item setState:NSOffState]; + [rotation270_item setState:NSOnState]; +} + +- (void)toggleTopBackground0 +{ + if(SubScreen.gpu->dispBG[0]) + { + GPU_remove(SubScreen.gpu, 0); + [topBG0_item setState:NSOffState]; + } + else + { + GPU_addBack(SubScreen.gpu, 0); + [topBG0_item setState:NSOnState]; + } +} + +- (void)toggleTopBackground1 +{ + if(SubScreen.gpu->dispBG[1]) + { + GPU_remove(SubScreen.gpu, 1); + [topBG1_item setState:NSOffState]; + } + else + { + GPU_addBack(SubScreen.gpu, 1); + [topBG1_item setState:NSOnState]; + } +} + +- (void)toggleTopBackground2 +{ + if(SubScreen.gpu->dispBG[2]) + { + GPU_remove(SubScreen.gpu, 2); + [topBG2_item setState:NSOffState]; + } + else + { + GPU_addBack(SubScreen.gpu, 2); + [topBG2_item setState:NSOnState]; + } +} + +- (void)toggleTopBackground3 +{ + if(SubScreen.gpu->dispBG[3]) + { + GPU_remove(SubScreen.gpu, 3); + [topBG3_item setState:NSOffState]; + } + else + { + GPU_addBack(SubScreen.gpu, 3); + [topBG3_item setState:NSOnState]; + } +} + +- (void)toggleSubBackground0 +{ + if(MainScreen.gpu->dispBG[0]) + { + GPU_remove(MainScreen.gpu, 0); + [subBG0_item setState:NSOffState]; + } + else + { + GPU_addBack(MainScreen.gpu, 0); + [subBG0_item setState:NSOnState]; + } +} + +- (void)toggleSubBackground1 +{ + if(MainScreen.gpu->dispBG[1]) + { + GPU_remove(MainScreen.gpu, 1); + [subBG1_item setState:NSOffState]; + } + else + { + GPU_addBack(MainScreen.gpu, 1); + [subBG1_item setState:NSOnState]; + } +} + +- (void)toggleSubBackground2 +{ + if(MainScreen.gpu->dispBG[2]) + { + GPU_remove(MainScreen.gpu, 2); + [subBG2_item setState:NSOffState]; + } + else + { + GPU_addBack(MainScreen.gpu, 2); + [subBG2_item setState:NSOnState]; + } +} + +- (void)toggleSubBackground3 +{ + if(MainScreen.gpu->dispBG[3]) + { + GPU_remove(MainScreen.gpu, 3); + [subBG3_item setState:NSOffState]; + } + else + { + GPU_addBack(MainScreen.gpu, 3); + [subBG3_item setState:NSOnState]; + } +} + +- (void)keyDown:(NSEvent*)event +{ + if([event isARepeat])return; + + unsigned short keycode = [event keyCode]; + + if(keycode == ds_a) + { + ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] &= 0xFFFE; + ((u16 *)MMU.ARM7_REG)[0x130>>1] &= 0xFFFE; + } + + else if(keycode == ds_b) + { + ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] &= 0xFFFD; + ((u16 *)MMU.ARM7_REG)[0x130>>1] &= 0xFFFD; + } + + else if(keycode == ds_select) + { + ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] &= 0xFFFB; + ((u16 *)MMU.ARM7_REG)[0x130>>1] &= 0xFFFB; + } + + else if(keycode == ds_start) + { + ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] &= 0xFFF7; + ((u16 *)MMU.ARM7_REG)[0x130>>1] &= 0xFFF7; + } + + else if(keycode == ds_right) + { + ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] &= 0xFFEF; + ((u16 *)MMU.ARM7_REG)[0x130>>1] &= 0xFFEF; + } + + else if(keycode == ds_left) + { + ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] &= 0xFFDF; + ((u16 *)MMU.ARM7_REG)[0x130>>1] &= 0xFFDF; + } + + else if(keycode == ds_up) + { + ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] &= 0xFFBF; + ((u16 *)MMU.ARM7_REG)[0x130>>1] &= 0xFFBF; + } + + else if(keycode == ds_down) + { + ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] &= 0xFF7F; + ((u16 *)MMU.ARM7_REG)[0x130>>1] &= 0xFF7F; + } + + else if(keycode == ds_r) + { + ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] &= 0xFEFF; + ((u16 *)MMU.ARM7_REG)[0x130>>1] &= 0xFEFF; + } + + else if(keycode == ds_l) + { + ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] &= 0xFDFF; + ((u16 *)MMU.ARM7_REG)[0x130>>1] &= 0xFDFF; + } + + else if(keycode == ds_x) + { + ((u16 *)MMU.ARM7_REG)[0x136>>1] &= 0xFFFE; + } + + else if(keycode == ds_y) + { + ((u16 *)MMU.ARM7_REG)[0x136>>1] &= 0xFFFD; + } + + else if(keycode == ds_debug) + { + ((u16 *)MMU.ARM7_REG)[0x136>>1] &= 0xFFFB; + } +} + +- (void)keyUp:(NSEvent*)event +{ + unsigned short keycode = [event keyCode]; + + if(keycode == ds_a) + { + ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] |= 0x1; + ((u16 *)MMU.ARM7_REG)[0x130>>1] |= 0x1; + } + + else if(keycode == ds_b) + { + ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] |= 0x2; + ((u16 *)MMU.ARM7_REG)[0x130>>1] |= 0x2; + } + + else if(keycode == ds_select) + { + ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] |= 0x4; + ((u16 *)MMU.ARM7_REG)[0x130>>1] |= 0x4; + } + + else if(keycode == ds_start) + { + ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] |= 0x8; + ((u16 *)MMU.ARM7_REG)[0x130>>1] |= 0x8; + } + + else if(keycode == ds_right) + { + ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] |= 0x10; + ((u16 *)MMU.ARM7_REG)[0x130>>1] |= 0x10; + } + + if(keycode == ds_left) + { + ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] |= 0x20; + ((u16 *)MMU.ARM7_REG)[0x130>>1] |= 0x20; + } + + else if(keycode == ds_up) + { + ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] |= 0x40; + ((u16 *)MMU.ARM7_REG)[0x130>>1] |= 0x40; + } + + else if(keycode == ds_down) + { + ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] |= 0x80; + ((u16 *)MMU.ARM7_REG)[0x130>>1] |= 0x80; + } + + else if(keycode == ds_r) + { + ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] |= 0x100; + ((u16 *)MMU.ARM7_REG)[0x130>>1] |= 0x100; + } + + else if(keycode == ds_l) + { + ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] |= 0x200; + ((u16 *)MMU.ARM7_REG)[0x130>>1] |= 0x200; + } + + else if(keycode == ds_x) + { + ((u16 *)MMU.ARM7_REG)[0x136>>1] |= 0x1; + } + + else if(keycode == ds_y) + { + ((u16 *)MMU.ARM7_REG)[0x136>>1] |= 0x2; + } + + else if(keycode == ds_debug) + { + ((u16 *)MMU.ARM7_REG)[0x136>>1] |= 0x4; + } + + else if(keycode == save_slot_1) + { + bool was_paused = paused; + [NDS pause]; + + if([event modifierFlags] & NSShiftKeyMask) + savestate_slot(1); + else + loadstate_slot(1); + + if(!was_paused)[NDS execute]; + } + + else if(keycode == save_slot_2) + { + bool was_paused = paused; + [NDS pause]; + + if([event modifierFlags] & NSShiftKeyMask) + savestate_slot(2); + else + loadstate_slot(2); + + if(!was_paused)[NDS execute]; + } + + else if(keycode == save_slot_3) + { + bool was_paused = paused; + [NDS pause]; + + if([event modifierFlags] & NSShiftKeyMask) + savestate_slot(3); + else + loadstate_slot(3); + + if(!was_paused)[NDS execute]; + } + + else if(keycode == save_slot_4) + { + bool was_paused = paused; + [NDS pause]; + + if([event modifierFlags] & NSShiftKeyMask) + savestate_slot(4); + else + loadstate_slot(4); + + if(!was_paused)[NDS execute]; + } + + else if(keycode == save_slot_5) + { + bool was_paused = paused; + [NDS pause]; + + if([event modifierFlags] & NSShiftKeyMask) + savestate_slot(5); + else + loadstate_slot(5); + + if(!was_paused)[NDS execute]; + } + + else if(keycode == save_slot_6) + { + bool was_paused = paused; + [NDS pause]; + + if([event modifierFlags] & NSShiftKeyMask) + savestate_slot(6); + else + loadstate_slot(6); + + if(!was_paused)[NDS execute]; + } + + else if(keycode == save_slot_7) + { + bool was_paused = paused; + [NDS pause]; + + if([event modifierFlags] & NSShiftKeyMask) + savestate_slot(7); + else + loadstate_slot(7); + + if(!was_paused)[NDS execute]; + } + + else if(keycode == save_slot_8) + { + bool was_paused = paused; + [NDS pause]; + + if([event modifierFlags] & NSShiftKeyMask) + savestate_slot(8); + else + loadstate_slot(8); + + if(!was_paused)[NDS execute]; + } + + else if(keycode == save_slot_9) + { + bool was_paused = paused; + [NDS pause]; + + if([event modifierFlags] & NSShiftKeyMask) + savestate_slot(9); + else + loadstate_slot(9); + + if(!was_paused)[NDS execute]; + } + + else if(keycode == save_slot_10) + { + bool was_paused = paused; + [NDS pause]; + + if([event modifierFlags] & NSShiftKeyMask) + savestate_slot(10); + else + loadstate_slot(10); + + if(!was_paused)[NDS execute]; + } + +} + +- (void)mouseDown:(NSEvent*)event +{ + NSPoint location = [event locationInWindow]; + + if(rotation == ROTATION_0 || rotation == ROTATION_180) + { + if(rotation == ROTATION_180) + { + location.x = (x_size + WINDOW_BORDER_PADDING) - location.x; + location.y = (y_size + WINDOW_BORDER_PADDING) - location.y; + } + + //If the click was to the left or under the opengl view, exit + if((location.x < WINDOW_BORDER_PADDING) || (location.y < WINDOW_BORDER_PADDING)) + return; + + //If the click was top or right of the view... + location.x -= WINDOW_BORDER_PADDING; + location.y -= WINDOW_BORDER_PADDING; + if(location.x >= x_size)return; + if(location.y >= (y_size / 2))return; + + + //scale the coordinates + location.x *= ((float)DS_SCREEN_WIDTH) / ((float)x_size); + location.y *= ((float)DS_SCREEN_HEIGHT_COMBINED) / ((float)y_size); + + //invert the y + location.y = DS_SCREEN_HEIGHT - location.y - 1; + + } else + { + location.x = 0; + location.y = 0; + } +//[self setTitle:[NSString localizedStringWithFormat:@"%u %u", (unsigned int)location.x, (unsigned int)location.y]]; + + NDS_setTouchPos((unsigned short)location.x, (unsigned short)location.y); +} + +- (void)mouseDragged:(NSEvent*)event +{ + [self mouseDown:event]; +} + +- (void)mouseUp:(NSEvent*)event +{ +// [self setTitle:@""]; + + NDS_releasTouch(); +} +@end + +//Window Delegate ----------------------------------------------------------------------- + +@implementation WindowDelegate +- (BOOL)windowShouldClose:(id)sender +{ + [sender hide]; + return FALSE; +} + +- (void)windowDidResize:(NSNotification *)aNotification; +{ + BOOL was_paused = paused; //we need to pause here incase the other thread wants to draw to the view while its resizing + [NDS pause]; + + //this is called after the window frame resizes + //so we must recalculate the video output view + + NSRect rect; + rect.size.width = x_size; + rect.size.height = y_size; + rect.origin.x = WINDOW_BORDER_PADDING; + rect.origin.y = WINDOW_BORDER_PADDING; + [video_output_view setFrame:rect]; + + if(!was_paused)[NDS execute]; +} + +- (NSSize)windowWillResize:(NSWindow *)sender toSize:(NSSize)proposedFrameSize +{ + //constrain size + if(proposedFrameSize.width < min_size.width)proposedFrameSize.width = min_size.width; + if(proposedFrameSize.height < min_size.height)proposedFrameSize.height = min_size.height; + + //constrain proportions + if(keep_proportions) + { + //this is a simple algorithm to constrain to the smallest axis + unsigned short x_constrained; + unsigned short y_constrained; + + if(rotation == ROTATION_0 || rotation == ROTATION_180) + { + //this is a simple algorithm to constrain to the smallest axis + + x_constrained = ((float)(proposedFrameSize.height - WINDOW_BORDER_PADDING - title_bar_height)) * DS_SCREEN_X_RATIO; + x_constrained += WINDOW_BORDER_PADDING * 2; + + y_constrained = ((float)(proposedFrameSize.width - WINDOW_BORDER_PADDING * 2)) * DS_SCREEN_Y_RATIO; + y_constrained += WINDOW_BORDER_PADDING + title_bar_height; + + } else + { + + x_constrained = ((float)(proposedFrameSize.height - WINDOW_BORDER_PADDING - title_bar_height)) * DS_SCREEN_Y_RATIO; + x_constrained += WINDOW_BORDER_PADDING * 2; + + y_constrained = ((float)(proposedFrameSize.width - WINDOW_BORDER_PADDING * 2)) * DS_SCREEN_X_RATIO; + y_constrained += WINDOW_BORDER_PADDING + title_bar_height; + + } + + if(x_constrained < proposedFrameSize.width)proposedFrameSize.width = x_constrained; + if(y_constrained < proposedFrameSize.height)proposedFrameSize.height = y_constrained; + } + + //set global size variables + x_size = proposedFrameSize.width - WINDOW_BORDER_PADDING * 2; + y_size = proposedFrameSize.height - WINDOW_BORDER_PADDING - title_bar_height; + + //set the menu items + if((x_size == DS_SCREEN_WIDTH) && (y_size == DS_SCREEN_HEIGHT_COMBINED)) + { + [resize1x setState:NSOnState ]; + [resize2x setState:NSOffState]; + [resize3x setState:NSOffState]; + [resize4x setState:NSOffState]; + } else if((x_size == DS_SCREEN_WIDTH * 2) && (y_size == DS_SCREEN_HEIGHT_COMBINED * 2)) + { + [resize1x setState:NSOffState]; + [resize2x setState:NSOnState ]; + [resize3x setState:NSOffState]; + [resize4x setState:NSOffState]; + } else if((x_size == DS_SCREEN_WIDTH * 3) && (y_size == DS_SCREEN_HEIGHT_COMBINED * 3)) + { + [resize1x setState:NSOffState]; + [resize2x setState:NSOffState]; + [resize3x setState:NSOnState ]; + [resize4x setState:NSOffState]; + } else if((x_size == DS_SCREEN_WIDTH * 4) && (y_size == DS_SCREEN_HEIGHT_COMBINED * 4)) + { + [resize1x setState:NSOffState]; + [resize2x setState:NSOffState]; + [resize3x setState:NSOffState]; + [resize4x setState:NSOnState ]; + } else + { + [resize1x setState:NSOffState]; + [resize2x setState:NSOffState]; + [resize3x setState:NSOffState]; + [resize4x setState:NSOffState]; + } + + //return the [potentially modified] frame size to cocoa to actually resize the window + return proposedFrameSize; +} + +@end diff --git a/desmume/src/cocoa/nds_control.h b/desmume/src/cocoa/nds_control.h new file mode 100644 index 000000000..f186e7178 --- /dev/null +++ b/desmume/src/cocoa/nds_control.h @@ -0,0 +1,59 @@ +/* Copyright (C) 2007 Jeff Bland + + This file is part of DeSmuME + + DeSmuME 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. + + DeSmuME 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 DeSmuME; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef NDS_CONTROL_H_INCLUDED +#define NDS_CONTROL_H_INCLUDED + +#include + +//This class manages emulation +//dont instanciate more than once! +@interface NintendoDS : NSObject {} + +//creation +- (id)init; + +//ROM control +- (void)pickROM; +- (BOOL)loadROM:(NSString*)filename; +- (void)closeROM; +- (void)askAndCloseROM; + +//execution control +- (void)execute; +- (void)pause; +- (void)reset; +- (void)setFrameSkip:(id)sender; + +//run function (should be called at the start of the program) +- (void)run; + +//save states +- (void)saveStateAs; +- (void)loadStateFrom; +- (void)saveToSlot:(id)sender; +- (void)loadFromSlot:(id)sender; +//- (void)askAndClearStates; + +// +- (void)showRomInfo; +@end + + +#endif // NDS_CONTROL_H_INCLUDED diff --git a/desmume/src/cocoa/nds_control.m b/desmume/src/cocoa/nds_control.m new file mode 100644 index 000000000..4c592139b --- /dev/null +++ b/desmume/src/cocoa/nds_control.m @@ -0,0 +1,711 @@ +/* Copyright (C) 2007 Jeff Bland + + This file is part of DeSmuME + + DeSmuME 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. + + DeSmuME 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 DeSmuME; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +//DeSmuME Cocoa includes +#import "globals.h" +#import "nds_control.h" +#import "main_window.h" + +//DeSmuME general includes +#define OBJ_C +#include "../NDSSystem.h" +#include "../saves.h" +#undef BOOL + +//ds screens are 59.8 frames per sec, so 1/59.8 seconds per frame +//times one million for microseconds per frame +#define DS_MICROSECONDS_PER_FRAME (1.0 / 59.8) * 1000000.0 + +//fixme bug when hitting apple+Q during the open dialog + +@interface TableHelper : NSObject +{ + NSTableView *table; + NSTableColumn *type_column; + NSTableColumn *value_column; + NDS_header *header; +} +//init +- (id)initWithWindow:(NSWindow*)window; + +//table data protocol +- (int)numberOfRowsInTableView:(NSTableView *)aTableView; +- (BOOL)tableView:(NSTableView *)aTableView acceptDrop:(id )info row:(int)row dropOperation:(NSTableViewDropOperation)operation; +- (NSArray *)tableView:(NSTableView *)aTableView namesOfPromisedFilesDroppedAtDestination:(NSURL *)dropDestination forDraggedRowsWithIndexes:(NSIndexSet *)indexSet; +- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex; +- (void)tableView:(NSTableView *)aTableView setObjectValue:(id)anObject forTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex; +- (void)tableView:(NSTableView *)aTableView sortDescriptorsDidChange:(NSArray *)oldDescriptors; +- (NSDragOperation)tableView:(NSTableView *)aTableView validateDrop:(id )info proposedRow:(int)row proposedDropOperation:(NSTableViewDropOperation)operation; +- (BOOL)tableView:(NSTableView *)aTableView writeRowsWithIndexes:(NSIndexSet *)rowIndexes toPasteboard:(NSPasteboard*)pboard; + +//window delegate stuff +- (void)windowWillClose:(NSNotification *)aNotification; +- (void)windowDidResize:(NSNotification *)aNotification; +@end + +///////////////////////// + +NSMenuItem *close_rom_item; +NSMenuItem *execute_item; +NSMenuItem *pause_item; +NSMenuItem *reset_item; +NSMenuItem *save_state_as_item; +NSMenuItem *load_state_from_item; +NSMenuItem *saveSlot_item[SAVE_SLOTS]; +NSMenuItem *loadSlot_item[SAVE_SLOTS]; +//NSMenuItem *clear_all_saves_item; +NSMenuItem *rom_info_item; +NSMenuItem *frame_skip_auto_item; +NSMenuItem *frame_skip_item[MAX_FRAME_SKIP]; + +volatile u8 frame_skip = 0; //this is one more than the acutal frame skip, a value of 0 signifies auto frame skip + +static int backupmemorytype=MC_TYPE_AUTODETECT; +static u32 backupmemorysize=1; + +NSString *current_file; + +@implementation NintendoDS +- (id)init +{ + struct armcpu_memory_iface *arm9_memio = &arm9_base_memory_iface; + struct armcpu_memory_iface *arm7_memio = &arm7_base_memory_iface; + struct armcpu_ctrl_iface *arm9_ctrl_iface; + struct armcpu_ctrl_iface *arm7_ctrl_iface; + //struct configured_features my_config; + + NDS_Init( arm9_memio, &arm9_ctrl_iface, + arm7_memio, &arm7_ctrl_iface); + +typedef struct { + enum nds_fw_ds_type ds_type; + + u8 fav_colour; + u8 birth_month; + u8 birth_day; + + u16 nickname[MAX_FW_NICKNAME_LENGTH]; + u8 nickname_len; + + u16 message[MAX_FW_MESSAGE_LENGTH]; + u8 message_len; + + u8 language; + + /* touchscreen calibration */ + struct NDS_fw_touchscreen_cal touch_cal[2]; +} NDS_fw_config_data; + + NDS_fw_config_data firmware; + NDS_FillDefaultFirmwareConfigData(&firmware); + NDS_CreateDummyFirmware(&firmware); + + return self; +} + +- (void)pickROM +{ + BOOL was_paused = paused; + [self pause]; + + NSString *temp = openDialog([NSArray arrayWithObjects:@"NDS", @"ds.GBA", nil]); + + if(temp) + { + [self loadROM:temp]; + return; + } + + if(!was_paused)[self execute]; +} + +- (BOOL)loadROM:(NSString*)filename +{ + //pause if not already paused + bool was_paused = paused; + [self pause]; + + //load the rom + if(!NDS_LoadROM([filename cStringUsingEncoding:NSASCIIStringEncoding], backupmemorytype, backupmemorysize, "/Users/gecko/AAAA.sav") > 0) + { + //if it didn't work give an error and dont unpause + messageDialog(@"Error", @"Could not open file"); + + //continue playing if load didn't work + if(!was_paused)[self execute]; + + return FALSE; + } + + //set current file var + current_file = filename; + + //enable execution control menu + [execute_item setEnabled:YES]; + [pause_item setEnabled:YES]; + [reset_item setEnabled:YES]; + [close_rom_item setEnabled:YES]; + [rom_info_item setEnabled:YES]; + [save_state_as_item setEnabled:YES]; + [load_state_from_item setEnabled:YES]; + + // + bool atleast_one_save_exists = false; + scan_savestates(); + int i; + for(i = 0; i < SAVE_SLOTS; i++) + { + [saveSlot_item[i] setEnabled:YES]; + + if(savestates[i].exists == desmume_TRUE) + { + atleast_one_save_exists = true; + [saveSlot_item[i] setState:NSOnState]; + [loadSlot_item[i] setEnabled:YES]; + } else + { + [saveSlot_item[i] setState:NSOffState]; + [loadSlot_item[i] setEnabled:NO]; + } + } + + //if(atleast_one_save_exists) + //[clear_all_saves_item setEnabled:YES]; + + //layers apparently get reset on rom load? + //[set topBG2_item fixme + + //if it worked, unpause (start) + [self execute]; + + return true; +} + +- (void)closeROM +{ + [self pause]; + + NDS_FreeROM(); + + //set menu item states + [execute_item setEnabled:NO]; + [pause_item setEnabled:NO]; + [reset_item setEnabled:NO]; + [close_rom_item setEnabled:NO]; + [rom_info_item setEnabled:NO]; + [save_state_as_item setEnabled:NO]; + [load_state_from_item setEnabled:NO]; + + //disable all save slots + int i; + for(i = 0; i < SAVE_SLOTS; i++) + { + [saveSlot_item[i] setEnabled:NO]; + [saveSlot_item[i] setState:NSOffState]; + [loadSlot_item[i] setEnabled:NO]; + } + + //[clear_all_saves_item setEnabled:NO]; +} + +- (void)askAndCloseROM +{ + bool was_paused = paused; + [NDS pause]; + + if(messageDialogYN(localizedString(@"DeSmuME Emulator", nil), localizedString(@"Are you sure you want to close the ROM?", nil))) + { + [self closeROM]; + + [main_window clearScreen]; + } + else if(!was_paused)[NDS execute]; +} + +- (void)execute +{ + paused = FALSE; + execute = TRUE; + //SPU_Pause(0); + + [pause_item setState:NSOffState]; + [execute_item setState:NSOnState]; +} + +- (void)pause +{ + if(paused)return; + + execute = FALSE; + //SPU_Pause(1); + +#ifndef MULTITHREADED + paused = TRUE; +#else + //wait for the other thread to stop execution + while (!paused) {} +#endif + + [pause_item setState:NSOnState]; + [execute_item setState:NSOffState]; +} + +- (void)reset +{ + NDS_Reset(); + [self execute]; +} + +- (void)setFrameSkip:(id)sender +{ + int i; + + //see if this was sent from the autoskip menu item + if(sender == frame_skip_auto_item) + { + //set the frame skip to auto + frame_skip = 0; + + //check auto + [frame_skip_auto_item setState:NSOnState]; + + //uncheck the others + for(i = 0; i < MAX_FRAME_SKIP; i++)[frame_skip_item[i] setState:NSOffState]; + return; + } + + //search through the frame skip menu items to find out which one called this function + for(i = 0; i < MAX_FRAME_SKIP; i++) + if(sender == frame_skip_item[i])break; + + if(i == MAX_FRAME_SKIP)return; //not a known sender + + //set the frame skip value + frame_skip = i + 1; + + //check the selected frame skip value + [frame_skip_item[i] setState:NSOnState]; + + //uncheck the others + int i2; + for(i2 = 0; i2 < MAX_FRAME_SKIP; i2++) + if(i2 != i) + [frame_skip_item[i2] setState:NSOffState]; + [frame_skip_auto_item setState:NSOffState]; +} + +- (void)run +{ + u32 cycles = 0; + + //this flag is so we can set the pause state to true + //ONCE after the inner run loop breaks (ie when you pause) + //to avoid some slight chance that the other thread sets pause to false + //and this thread re + bool was_running = false; //initialized here to avoid a warning + + unsigned long long frame_start_time, frame_end_time; + unsigned long long microseconds_per_frame; + + int frames_to_skip = 0; + + //program main loop + while(!finished) + { + +#ifndef MULTITHREADED + //keep the GUI responsive even while not running a gme + if(!execute)clearEvents(true); +#endif + //run the emulator + while(execute && !finished) + { + was_running = true; + +//clear the event queue so the GUI elements are responsive when the game is running +//needs to happen before frame_start_time is recieved incase the user does a live resize +//or something that will pause everything +#ifndef MULTITHREADED + if(frames_to_skip == 0) + clearEvents(false); +#endif + + Microseconds((struct UnsignedWide*)&frame_start_time); + + cycles = NDS_exec((560190<<1)-cycles, FALSE); + + if(frames_to_skip != 0) + frames_to_skip--; + + else + { + + Microseconds((struct UnsignedWide*)&frame_end_time); + + if(frame_skip == 0) + { //automatic + + //i don't know if theres a standard strategy, but here we calculate + //how much longer the frame took than it should have, then set it to skip + //that many frames. + frames_to_skip = ((double)(frame_end_time - frame_start_time)) / ((double)DS_MICROSECONDS_PER_FRAME); + + } else + { + + frames_to_skip = frame_skip; + + } + +#ifndef MULTITHREADED + if(!paused) //so the screen doesnt update after being cleared to white (when closing rom) +#endif + [main_window updateScreen]; + + } + + } + + // + if(was_running) + { + paused = TRUE; //for the multithreaded version (avoid forever loop in the pause method) + was_running = false; // + + //set some kind of checkmarks or something? + } + + } +} + +- (void)saveStateAs +{ + messageDialog(@"LOAD",@"DDSA"); +} + +- (void)loadStateFrom +{ + NSString *file = openDialog([NSArray arrayWithObject:@"DST"]); + + if(file) + { + [NDS pause]; + + savestate_load([file cStringUsingEncoding:NSASCIIStringEncoding]); + + [NDS execute]; + } +} + +- (void)saveToSlot:(id)sender +{ + //get the save slot by detecting which menu item sent the message + int i; + for(i = 0; i < SAVE_SLOTS; i++) + if(sender == saveSlot_item[i])break; + + //quit if the message wasn't sent by a save state menu item + if(i == SAVE_SLOTS)return; + + bool was_paused = paused; + [NDS pause]; + + savestate_slot(i + 1); + + [saveSlot_item[i] setState:NSOnState]; + [loadSlot_item[i] setEnabled:YES]; + //[clear_all_saves_item setEnabled:YES]; + + if(!was_paused)[NDS execute]; + +} + +- (void)loadFromSlot:(id)sender +{ + //get the load slot + int i; + for(i = 0; i < SAVE_SLOTS; i++) + if(sender == loadSlot_item[i])break; + + //quit if the message wasn't sent by a save state menu item + if(i == SAVE_SLOTS)return; + + bool was_paused = paused; + [NDS pause]; + + loadstate_slot(i + 1); + + if(!was_paused)[NDS execute]; +} +/* +- (void)askAndClearStates +{ + BOOL was_paused = paused; + [NDS pause]; + + if(messageDialogYN(localizedString(@"DeSmuME Emulator", nil), + localizedString(@"Are you sure you want to clear all save slots?", nil))) + { + + + to be implemented after saves.h provides a way to delete saves... + + int i; + for(i = 0; i < SAVE_SLOTS; i++) + { + [saveSlot_item[i] setState:NSOffState]; + [loadSlot_item[i] setEnabled:NO]; + } + + [clear_all_saves_item setEnabled:NO]; + + } + + if(!was_paused)[NDS execute]; +} +*/ + +- (void)showRomInfo +{ + BOOL was_paused = paused; + [self pause]; + + //create a window + NSRect rect; + rect.size.width = 400; + rect.size.height = 200; //fixme; + rect.origin.x = 200; + rect.origin.y = 200; + NSWindow *rom_info_window = [[NSWindow alloc] initWithContentRect:rect styleMask: + NSTitledWindowMask|NSClosableWindowMask|NSResizableWindowMask backing:NSBackingStoreBuffered defer:NO screen:nil]; + + //set the window title + [rom_info_window setTitle:localizedString(@"ROM Info", nil)]; + + //create an NSTableView to display the stuff + TableHelper *helper = [[TableHelper alloc] initWithWindow:rom_info_window]; + + //set the window delegate + [rom_info_window setDelegate:helper]; + + //min size is starting size + [rom_info_window setMinSize:[rom_info_window frame].size]; + + //show the window + [[[NSWindowController alloc] initWithWindow:rom_info_window] showWindow:nil]; + + //run the window + [NSApp runModalForWindow:rom_info_window]; + + if(!was_paused)[self execute]; +} + +@end +#define ROM_INFO_ROWS 9 +#define ROM_INFO_WIDTH 400 +@implementation TableHelper +- (id)initWithWindow:(NSWindow*)window +{ + self = [super init]; + + type_column = [[NSTableColumn alloc] initWithIdentifier:@""]; + [type_column setEditable:NO]; + [value_column setResizable:YES]; + [[type_column headerCell] setStringValue:@"Attribute"]; + [type_column setMinWidth: 1]; + + value_column = [[NSTableColumn alloc] initWithIdentifier:@""]; + [value_column setEditable:NO]; + [value_column setResizable:YES]; + [[value_column headerCell] setStringValue:@"Value"]; + [value_column setMinWidth: 1]; + + NSRect rect; + rect.size.width = rect.size.height = rect.origin.x = rect.origin.y = 0; + table = [[NSTableView alloc] initWithFrame:rect]; + [table setDrawsGrid:NO]; + [table setAllowsColumnSelection:YES]; + [table setAllowsColumnReordering:YES]; + [table setAllowsEmptySelection:YES]; + [table setAllowsMultipleSelection:NO]; + [table addTableColumn:type_column]; + [table addTableColumn:value_column]; + [table setDataSource:self]; + //[table setDelegate:self]; + //[table setTarget: _parent]; + //[table setDoubleAction: @selector(editClicked:)]; + [table setUsesAlternatingRowBackgroundColors:YES]; + + // + //[table setHeaderView:[[NSTableHeaderView alloc] initWithFrame:NSMakeRect(0,0,0,0)]]; +if([table headerView] == nil)messageDialogBlank(); + + //resize the window to fit enough rows + rect.size.width = ROM_INFO_WIDTH; + rect.size.height = [table rowHeight] * ROM_INFO_ROWS + [table intercellSpacing].height * (ROM_INFO_ROWS - 1) + 2 /*dunno what the 2 is for*/; + [window setContentSize:rect.size]; + + //resize the left column to take up only as much space as needed + //[type_column sizeToFit]; + + //resize the right column to take up the rest of the window + [value_column setWidth:ROM_INFO_WIDTH - [type_column width]]; + + // + [window setContentView:table]; + + //grab the header to read data from + header = NDS_getROMHeader(); + + return self; +} +- (int)numberOfRowsInTableView:(NSTableView *)aTableView; +{ + return ROM_INFO_ROWS; +} + +- (BOOL)tableView:(NSTableView *)aTableView acceptDrop:(id )info row:(int)row dropOperation:(NSTableViewDropOperation)operation +{ + return NO; +} + +- (NSArray *)tableView:(NSTableView *)aTableView namesOfPromisedFilesDroppedAtDestination:(NSURL *)dropDestination forDraggedRowsWithIndexes:(NSIndexSet *)indexSet +{ + return [NSArray array]; +} + +- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex +{ + if(aTableColumn == type_column) + { + if(rowIndex == 0) + return localizedString(@"File on Disc", @" ROM Info "); + + if(rowIndex == 1) + return localizedString(@"ROM Title", @" ROM Info "); + + if(rowIndex == 2) + return localizedString(@"Maker Code", @" ROM Info "); + + if(rowIndex == 3) + return localizedString(@"Unit Code", @" ROM Info "); + + if(rowIndex == 4) + return localizedString(@"Card Size", @" ROM Info "); + + if(rowIndex == 5) + return localizedString(@"Flags", @" ROM Info "); + + if(rowIndex == 6) + return localizedString(@"Size of ARM9 Binary", @" ROM Info "); + + if(rowIndex == 7) + return localizedString(@"Size of ARM7 Size", @" ROM Info "); + + if(rowIndex == 8) + return localizedString(@"Size of Data", @" ROM Info "); + } else + { + if(rowIndex == 0)return current_file; + + if(rowIndex == 1) + return NSSTRc(header->gameTile); + + if(rowIndex == 2) + { + return [NSString localizedStringWithFormat:@"%u", header->makerCode]; + } + + if(rowIndex == 3) + { + return [NSString localizedStringWithFormat:@"%u", header->unitCode]; + } + + if(rowIndex == 4) + {//fixe: should show units? + return [NSString localizedStringWithFormat:@"%u", header->cardSize]; + } + + if(rowIndex == 5) + {//always seems to be empty? + return [NSString localizedStringWithFormat:@"%u%u%u%u%u%u%u%u", + ((header->flags) & 0x01) >> 0, + ((header->flags) & 0x02) >> 1, + ((header->flags) & 0x04) >> 2, + ((header->flags) & 0x08) >> 3, + ((header->flags) & 0x10) >> 4, + ((header->flags) & 0x20) >> 5, + ((header->flags) & 0x40) >> 6, + ((header->flags) & 0x80) >> 7]; + } + + if(rowIndex == 6) + {//fixe: should show units? + return [NSString localizedStringWithFormat:@"%u", header->ARM9binSize]; + } + + if(rowIndex == 7) + {//fixe: should show units? + return [NSString localizedStringWithFormat:@"%u", header->ARM7binSize]; + } + + if(rowIndex == 8) + {//fixe: should show units? + return [NSString localizedStringWithFormat:@"%u", header->ARM7binSize + header->ARM7src]; + } + + } + + return @"If you see this, there is a bug"; +} + +- (void)tableView:(NSTableView *)aTableView setObjectValue:(id)anObject forTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex; +{ +} + +- (void)tableView:(NSTableView *)aTableView sortDescriptorsDidChange:(NSArray *)oldDescriptors; +{ +} + +- (NSDragOperation)tableView:(NSTableView *)aTableView validateDrop:(id )info proposedRow:(int)row proposedDropOperation:(NSTableViewDropOperation)operation +{ + return NSDragOperationNone; +} + +- (BOOL)tableView:(NSTableView *)aTableView writeRowsWithIndexes:(NSIndexSet *)rowIndexes toPasteboard:(NSPasteboard*)pboard; +{ + return NO; +} + +- (void)windowWillClose:(NSNotification *)aNotification +{ + [NSApp stopModal]; +} + +- (void)windowDidResize:(NSNotification *)aNotification +{ + //we have this because the tableview doesn't change clipped text size + + int i; + for(i = 0; i < ROM_INFO_ROWS; i++) + { + [table drawRow:i clipRect:[table frame]]; + } +} +@end diff --git a/desmume/src/cocoa/preferences.m b/desmume/src/cocoa/preferences.m new file mode 100644 index 000000000..d45d29cc6 --- /dev/null +++ b/desmume/src/cocoa/preferences.m @@ -0,0 +1,174 @@ +#import "globals.h" +#import "nds_control.h" + +/////////////////////////////// + +NSWindow *preferences_window; + +NSFont *preferences_font; +NSDictionary *preferences_font_attribs; + +NSTabViewItem *interface_pane_tab; +NSTabViewItem *firmware_pane_tab; +NSTabViewItem *plugins_pane_tab; + +NSText *language_selection_text; +NSPopUpButton *language_selection; + +/////////////////////////////// + +@interface PreferencesDelegate : NSObject {} +- (void)windowWillClose:(NSNotification *)aNotification; +@end + +@implementation PreferencesDelegate +- (void)windowWillClose:(NSNotification *)aNotification +{ + [NSApp stopModal]; +} + +- (void)languageChange:(id)sender +{ + +} +@end + +//////////////////////////////////////////////////// + +@implementation NSApplication(custom_extensions) + +- (void)about +{ + bool was_paused = paused; + [NDS pause]; + + NSRunAlertPanel(localizedString(@"About DeSmuME", nil), + @"DeSmuME is an open source Nintendo DS emulator.\n\nBased off of YopYop's original work, and continued by the DeSmuME team.\n\ +\nhttp://www.desmume.org\n\n\n\ +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. \ +\n\n\ +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. \ +\n\n\ +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., 59 Temple Place, Suite 330, Boston, \ +MA 02111-1307 USA\ +\n\n\ +See the GNU General Public License details in COPYING.", nil/*OK*/, nil, nil); + + if(!was_paused)[NDS execute]; +} + +/////////////////////////////////////////////////// + +- (void)preferences +{ + bool was_paused = paused; + [NDS pause]; + + //---------------------------------------------------------------------------------------------- + + //get the applications main bundle + NSBundle* app_bundle = [NSBundle mainBundle]; + + //grab the list of languages + NSArray *languages = [app_bundle localizations]; + + //get a font for displaying text + preferences_font = [NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSRegularControlSize]]; + + preferences_font_attribs = [NSDictionary dictionaryWithObjectsAndKeys:preferences_font, NSFontAttributeName, nil]; + + //create our delegate + PreferencesDelegate *delegate = [[PreferencesDelegate alloc] init]; + // + int i; //general iterator + + //Create the window ------------------------------------------------------------------------------ + + //create a preferences window + NSRect rect; + rect.size.width = 400; + rect.size.height = 300; + rect.origin.x = 200; + rect.origin.y = 200; + preferences_window = [[NSWindow alloc] initWithContentRect:rect styleMask: + NSTitledWindowMask|NSClosableWindowMask backing:NSBackingStoreBuffered defer:NO screen:nil]; + + //set the window title + [preferences_window setTitle:localizedString(@"DeSmuME Preferences", nil)]; + + //set the window delegate + [preferences_window setDelegate:delegate]; + + //create a tab view + rect.size.width = 400 - 10; + rect.size.height = 300 - 10; + rect.origin.x = 5; + rect.origin.y = 5; + NSTabView *tab_view = [[NSTabView alloc] initWithFrame:rect]; + [[preferences_window contentView] addSubview:tab_view]; + + //Create the "Interface" pane + interface_pane_tab = [[NSTabViewItem alloc] initWithIdentifier:nil]; + [interface_pane_tab setLabel:localizedString(@"Interface", nil)]; + [tab_view addTabViewItem:interface_pane_tab]; + + //Create interface view + rect.size.width = 400 - 10; + rect.size.height = 300 - 10; + rect.origin.x = 0; + rect.origin.y = 0; + NSView *interface_view = [[NSView alloc] initWithFrame:rect]; + [interface_pane_tab setView:interface_view]; + + //Create language selection text + rect.size.width = 225; + rect.size.height = 29 - [localizedString(@"Language",nil) sizeWithAttributes:preferences_font_attribs].height / 2; + rect.origin.x = 0; + rect.origin.y = 200;// + [localizedString(@"Language",nil) sizeWithAttributes:preferences_font_attribs].height / 2; + language_selection_text = [[NSText alloc] initWithFrame:rect]; + [language_selection_text setFont: preferences_font]; + [language_selection_text setString:localizedString(@"Language",nil)]; + [language_selection_text setEditable:NO]; + [language_selection_text setDrawsBackground:NO]; + [interface_view addSubview:language_selection_text]; + + //Create language selection button + rect.size.width = 130; + rect.size.height = 26; + rect.origin.x = 230; + rect.origin.y = 200; + language_selection = [[NSPopUpButton alloc] initWithFrame:rect pullsDown:NO]; + [language_selection addItemWithTitle:@"Default"]; + for(i = 0; i < [languages count]; i++) + [language_selection addItemWithTitle:[languages objectAtIndex:i]]; + [language_selection setAction:@selector(languageChange:)]; + [language_selection setTarget:delegate]; + [interface_view addSubview:language_selection]; + + //Create the "DS Firmware" pane + firmware_pane_tab = [[NSTabViewItem alloc] initWithIdentifier:nil]; + [firmware_pane_tab setLabel:localizedString(@"DS Firmware", nil)]; + [tab_view addTabViewItem:firmware_pane_tab]; + + //Create the "Plugins" pane + plugins_pane_tab = [[NSTabViewItem alloc] initWithIdentifier:nil]; + [plugins_pane_tab setLabel:localizedString(@"Plugins", nil)]; + [tab_view addTabViewItem:plugins_pane_tab]; + + //show the window + [[[NSWindowController alloc] initWithWindow:preferences_window] showWindow:nil]; + + + [NSApp runModalForWindow:preferences_window]; + + if(!was_paused)[NDS execute]; +} +@end diff --git a/desmume/src/types.h b/desmume/src/types.h index 8a57c3d68..3f61d0311 100644 --- a/desmume/src/types.h +++ b/desmume/src/types.h @@ -105,7 +105,13 @@ typedef s16 v10; /*----------------------*/ +#ifndef OBJ_C typedef int BOOL; +#else +//apple defines BOOL so this is to avoid conflicts +typedef int desmume_BOOL; +#define BOOL desmume_BOOL +#endif #ifndef TRUE #define TRUE 1 diff --git a/desmume/src/windows/OGLRender.c b/desmume/src/windows/OGLRender.c index 4b6d99641..02ce98217 100644 --- a/desmume/src/windows/OGLRender.c +++ b/desmume/src/windows/OGLRender.c @@ -1,4 +1,4 @@ -/* +/* Copyright (C) 2006 yopyop Copyright (C) 2006-2007 shash @@ -19,6 +19,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef DESMUME_COCOA + #define WIN32_LEAN_AND_MEAN #include #include @@ -29,6 +31,19 @@ #include "..\MMU.h" #include "..\bits.h" #include "..\matrix.h" + +#else + + +#include +#include +#include "../debug.h" +#include "../MMU.h" +#include "../bits.h" +#include "../matrix.h" + +#endif + #include "OGLRender.h" @@ -99,13 +114,17 @@ static unsigned int vtxFormat; static unsigned int textureFormat=0, texturePalette=0; static unsigned int lastTextureFormat=0, lastTexturePalette=0; +#ifndef DESMUME_COCOA extern HWND hwnd; +#endif char NDS_glInit(void) { + int i; +#ifndef DESMUME_COCOA HDC oglDC = NULL; HGLRC hRC = NULL; - int pixelFormat, i; + int pixelFormat; PIXELFORMATDESCRIPTOR pfd; oglDC = GetDC (hwnd); @@ -121,18 +140,19 @@ char NDS_glInit(void) pfd.iLayerType = PFD_MAIN_PLANE ; pixelFormat = ChoosePixelFormat(oglDC, &pfd); - if (pixelFormat == 0) + if (pixelFormat == 0) return 0; - if(!SetPixelFormat(oglDC, pixelFormat, &pfd)) + if(!SetPixelFormat(oglDC, pixelFormat, &pfd)) return 0; hRC = wglCreateContext(oglDC); - if (!hRC) + if (!hRC) return 0; if(!wglMakeCurrent(oglDC, hRC)) return 0; +#endif glEnable(GL_DEPTH_TEST); glEnable(GL_TEXTURE_2D); @@ -194,8 +214,8 @@ void NDS_glViewPort(unsigned long v) void NDS_glClearColor(unsigned long v) { glClearColor( ((float)(v&0x1F))/31.0f, - ((float)((v>>5)&0x1F))/31.0f, - ((float)((v>>10)&0x1F))/31.0f, + ((float)((v>>5)&0x1F))/31.0f, + ((float)((v>>10)&0x1F))/31.0f, ((float)((v>>16)&0x1F))/31.0f); } @@ -346,7 +366,7 @@ void NDS_glScale(signed long v) ++scaleind; - if(scaleind<3) + if(scaleind<3) return; scaleind = 0; @@ -600,7 +620,7 @@ static __inline void SetupTexture (unsigned int format, unsigned int palette) u32 yAbs = ((y<<2) + sy); u32 currentPos = xAbs + yAbs*sizeX; - // Palette + // Palette u8 currRow = (u8)((currBlock >> (sy*8)) & 0xFF); #define RGB16TO32(col,alpha) (((alpha)<<24) | ((((col) & 0x7C00)>>7)<<16) | ((((col) & 0x3E0)>>2)<<8) | (((col) & 0x1F)<<3)) #define RGB32(r,g,b,a) (((a)<<24) | ((r)<<16) | ((g)<<8) | (b)) @@ -717,7 +737,7 @@ static __inline void SetupTexture (unsigned int format, unsigned int palette) } } } - + break; } case 6: @@ -749,9 +769,9 @@ static __inline void SetupTexture (unsigned int format, unsigned int palette) break; } - glBindTexture(GL_TEXTURE_2D, oglTextureID); + glBindTexture(GL_TEXTURE_2D, oglTextureID); + - switch ((format>>18)&3) { case 0: @@ -818,7 +838,7 @@ static __inline void SetupTexture (unsigned int format, unsigned int palette) invTexWidth = 1.f/((float)sizeX*(1<<4)); invTexHeight = 1.f/((float)sizeY*(1<<4)); - + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); @@ -877,7 +897,7 @@ void NDS_glBegin(unsigned long v) { glEnable(GL_CULL_FACE); glCullFace(map3d_cull[cullingMask>>6]); - } + } else { glDisable(GL_CULL_FACE); @@ -900,7 +920,7 @@ void NDS_glBegin(unsigned long v) else { glPolygonMode (GL_FRONT, GL_LINE); - glPolygonMode (GL_BACK, GL_LINE); + glPolygonMode (GL_BACK, GL_LINE); } if (textureFormat != lastTextureFormat || @@ -948,21 +968,21 @@ static __inline void SetVertex() { float coordTransformed[3] = { coord[0], coord[1], coord[2] }; - if (texCoordinateTransform == 3) + if (texCoordinateTransform == 3) { - int s2 = (int)(( coord[0]*mtxCurrent[3][0] + - coord[1]*mtxCurrent[3][4] + + int s2 = (int)(( coord[0]*mtxCurrent[3][0] + + coord[1]*mtxCurrent[3][4] + coord[2]*mtxCurrent[3][8]) + s); - int t2 = (int)(( coord[0]*mtxCurrent[3][1] + - coord[1]*mtxCurrent[3][5] + - coord[2]*mtxCurrent[3][9]) + t); + int t2 = (int)(( coord[0]*mtxCurrent[3][1] + + coord[1]*mtxCurrent[3][5] + + coord[2]*mtxCurrent[3][9]) + t); - glTexCoord2i (s2, t2); - } + glTexCoord2i (s2, t2); + } MatrixMultVec4x4 (mtxCurrent[1], coordTransformed); - glVertex3fv (coordTransformed); + glVertex3fv (coordTransformed); numVertex++; } @@ -972,7 +992,7 @@ void NDS_glVertex16b(unsigned int v) if(coordind==0) { coord[0] = float16table[v&0xFFFF]; - coord[1] = float16table[v>>16]; + coord[1] = float16table[v>>16]; ++coordind; return; @@ -997,7 +1017,7 @@ void NDS_glVertex3_cord(unsigned int one, unsigned int two, unsigned int v) { coord[one] = float16table[v&0xffff]; coord[two] = float16table[v>>16]; - + SetVertex (); } @@ -1184,9 +1204,9 @@ void NDS_glTexCoord(unsigned long val) if (texCoordinateTransform == 1) { - int s2 =(int)( s* mtxCurrent[3][0] + t* mtxCurrent[3][4] + + int s2 =(int)( s* mtxCurrent[3][0] + t* mtxCurrent[3][4] + (1.f/16.f)* mtxCurrent[3][8] + (1.f/16.f)* mtxCurrent[3][12]); - int t2 =(int)( s* mtxCurrent[3][1] + t* mtxCurrent[3][5] + + int t2 =(int)( s* mtxCurrent[3][1] + t* mtxCurrent[3][5] + (1.f/16.f)* mtxCurrent[3][9] + (1.f/16.f)* mtxCurrent[3][13]); glTexCoord2i (s2, t2); @@ -1243,9 +1263,9 @@ void NDS_glLightDirection (unsigned long v) void NDS_glLightColor (unsigned long v) { - int lightColor[4] = { ((v) &0x1F)<<26, - ((v>> 5)&0x1F)<<26, - ((v>>10)&0x1F)<<26, + int lightColor[4] = { ((v) &0x1F)<<26, + ((v>> 5)&0x1F)<<26, + ((v>>10)&0x1F)<<26, 0x7fffffff}; if (beginCalled) @@ -1335,9 +1355,9 @@ void NDS_glNormal(unsigned long v) if (texCoordinateTransform == 2) { - int s2 =(int)( (normal[0] *mtxCurrent[3][0] + normal[1] *mtxCurrent[3][4] + + int s2 =(int)( (normal[0] *mtxCurrent[3][0] + normal[1] *mtxCurrent[3][4] + normal[2] *mtxCurrent[3][8]) + s); - int t2 =(int)( (normal[0] *mtxCurrent[3][1] + normal[1] *mtxCurrent[3][5] + + int t2 =(int)( (normal[0] *mtxCurrent[3][1] + normal[1] *mtxCurrent[3][5] + normal[2] *mtxCurrent[3][9]) + t); glTexCoord2i (s2, t2); @@ -1394,7 +1414,7 @@ void NDS_glCallList(unsigned long v) case 0x41: { - NDS_glEnd(); + NDS_glEnd(); --clInd; clCmd>>=8; continue; @@ -1429,7 +1449,7 @@ void NDS_glCallList(unsigned long v) NDS_glPopMatrix(v); --clInd; clCmd>>=8; - break; + break; } case 0x13: @@ -1438,7 +1458,7 @@ void NDS_glCallList(unsigned long v) NDS_glStoreMatrix(v); --clInd; clCmd>>=8; - break; + break; } case 0x14: @@ -1583,7 +1603,7 @@ void NDS_glCallList(unsigned long v) if(clInd2==2) { --clInd; - clCmd>>=8; + clCmd>>=8; clInd2 = 0; } break; @@ -1610,7 +1630,7 @@ void NDS_glCallList(unsigned long v) case 0x26:// GFX_VERTEX_XZ { ((unsigned long *)ARM9Mem.ARM9_REG)[0x498>>2] = v; - NDS_glVertex3_cord(0,2,v); + NDS_glVertex3_cord(0,2,v); --clInd; clCmd>>=8; break; @@ -1619,7 +1639,7 @@ void NDS_glCallList(unsigned long v) case 0x27:// GFX_VERTEX_YZ { ((unsigned long *)ARM9Mem.ARM9_REG)[0x49C>>2] = v; - NDS_glVertex3_cord(1,2,v); + NDS_glVertex3_cord(1,2,v); --clInd; clCmd>>=8; break; @@ -1669,7 +1689,7 @@ void NDS_glCallList(unsigned long v) clCmd>>=8; break; } - + case 0x31: // GFX_SPECULAR_EMISSION { ((unsigned long *)ARM9Mem.ARM9_REG)[0x4C4>>2] = v; @@ -1711,7 +1731,7 @@ void NDS_glCallList(unsigned long v) break; } - case 0x40 : + case 0x40 : { ((unsigned long *)ARM9Mem.ARM9_REG)[0x500>>2] = v; NDS_glBegin(v); @@ -1761,7 +1781,7 @@ void NDS_glCallList(unsigned long v) } if((clCmd&0xFF)==0x41) { - glEnd(); + glEnd(); --clInd; clCmd>>=8; } @@ -1811,8 +1831,8 @@ GPU3DInterface gpu3Dgl = { NDS_glInit, NDS_glControl, NDS_glNormal, NDS_glCallList, - + NDS_glGetClipMatrix, NDS_glGetDirectionalMatrix, NDS_glGetLine}; - +