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};
-
+