From 49b5243c1a7634937b39db4b69524cd06501b233 Mon Sep 17 00:00:00 2001 From: riccardom Date: Sat, 16 Apr 2011 15:27:39 +0000 Subject: [PATCH] cocoa: Update cocoa frontend From Roger Manual, #3259154: BUGFIXES: - Fixed the bug tracker website link used by the "Submit a Bug Report" command in the Help menu. - Fixed issue where if one of the text files used for the About window was missing from the DeSmuME/Contents/Resources folder, then the entire panel didn't show. CHANGES: - Frame skipping options have been removed in this release. The way it works now, drawing a frame in Cocoa takes an insignificant amount of time. In other words, skipping Cocoa frames does NOT yield any significant speed improvement. It may be possible to gain speed by skipping frames in the actual NDS GPU rendering, but this is an emulation engine issue, not a Cocoa frontend issue. - Added OBJ layer toggling in the View/Layers menu. - Files are now saved in more logical locations. Save states slot files are now saved in "~/Library/Application Support/DeSmuME/(DeSmuME version number)/States". All other files (like battery files) are now saved in the same directory as the ROM. DEVELOPER: - Added Application Creator Code for DeSmuME. Registered 'DSmM' with Apple. - Reworked the execution loop for better maintainability. - Preliminary code refactoring for better DS controller function. Cocoa DeSmuME now uses the NDS_beginProcessingInput() and NDS_endProcessingInput() functions, which helps input support for some games. Note that this change probably breaks support for PowerPC Macs, but I don't know if we should be supporting PowerPC Macs anyways... xrmx: I'm not able to build this with xcode because 10.4 SDK does not like gcc4.2 but the cocoa stuff builds fine in cocoa so applying it. --- .../cocoa/DeSmuME.xcodeproj/project.pbxproj | 2 + desmume/src/cocoa/DeSmuME_Prefix.pch | 26 + desmume/src/cocoa/Info.plist | 24 +- desmume/src/cocoa/about.m | 166 ++- desmume/src/cocoa/cocoa_input.h | 185 ++++ desmume/src/cocoa/cocoa_input.mm | 596 +++++++++++ desmume/src/cocoa/cocoa_util.m | 107 ++ desmume/src/cocoa/globals.h | 12 +- desmume/src/cocoa/input.h | 2 + desmume/src/cocoa/input.mm | 60 +- desmume/src/cocoa/main.mm | 31 +- desmume/src/cocoa/main_window.h | 7 + desmume/src/cocoa/main_window.mm | 309 ++++-- desmume/src/cocoa/nds_control.h | 93 +- desmume/src/cocoa/nds_control.mm | 998 ++++++------------ desmume/src/cocoa/sndOSX.h | 2 - desmume/src/cocoa/sndOSX.mm | 2 - 17 files changed, 1683 insertions(+), 939 deletions(-) create mode 100644 desmume/src/cocoa/DeSmuME_Prefix.pch create mode 100644 desmume/src/cocoa/cocoa_input.h create mode 100644 desmume/src/cocoa/cocoa_input.mm diff --git a/desmume/src/cocoa/DeSmuME.xcodeproj/project.pbxproj b/desmume/src/cocoa/DeSmuME.xcodeproj/project.pbxproj index 304f95ad8..c0dd0d0a4 100644 --- a/desmume/src/cocoa/DeSmuME.xcodeproj/project.pbxproj +++ b/desmume/src/cocoa/DeSmuME.xcodeproj/project.pbxproj @@ -587,6 +587,7 @@ isa = PBXProject; buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "DeSmuME" */; compatibilityVersion = "Xcode 2.4"; + developmentRegion = English; hasScannedForEncodings = 1; knownRegions = ( English, @@ -894,6 +895,7 @@ GCC_UNROLL_LOOPS = YES; INFOPLIST_FILE = Info.plist; INSTALL_PATH = "$(HOME)/Applications"; + ONLY_ACTIVE_ARCH = NO; PRODUCT_NAME = DeSmuME; }; name = Debug; diff --git a/desmume/src/cocoa/DeSmuME_Prefix.pch b/desmume/src/cocoa/DeSmuME_Prefix.pch new file mode 100644 index 000000000..f204dcbd4 --- /dev/null +++ b/desmume/src/cocoa/DeSmuME_Prefix.pch @@ -0,0 +1,26 @@ +/* Copyright (C) 2011 Roger Manuel + + 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 + */ + +#ifdef __OBJC__ + #define OBJ_C +#endif + +#define DESMUME_COCOA +#define HAVE_OPENGL +#define HAVE_LIBZ \ No newline at end of file diff --git a/desmume/src/cocoa/Info.plist b/desmume/src/cocoa/Info.plist index f0d50cfde..89be8a740 100644 --- a/desmume/src/cocoa/Info.plist +++ b/desmume/src/cocoa/Info.plist @@ -14,10 +14,26 @@ CFBundleTypeIconFile DeSmuME CFBundleTypeName - Nintendo DS Software + Nintendo DS ROM CFBundleTypeRole Viewer + + CFBundleTypeExtensions + + dst + + CFBundleTypeIconFile + DeSmuME + CFBundleTypeName + DeSmuME Save State + CFBundleTypeRole + Viewer + LSTypeIsPackage + + NSPersistentStoreTypeKey + Binary + CFBundleExecutable DeSmuME @@ -32,11 +48,11 @@ CFBundlePackageType APPL CFBundleShortVersionString - 0.9.3 + 0.9.7 CFBundleSignature - ???? + DSmM CFBundleVersion - 0.9.3 + 0.9.7 NSMainNibFile MainMenu NSPrincipalClass diff --git a/desmume/src/cocoa/about.m b/desmume/src/cocoa/about.m index 865dc35d4..bbaa08d54 100644 --- a/desmume/src/cocoa/about.m +++ b/desmume/src/cocoa/about.m @@ -19,6 +19,20 @@ #import "globals.h" +#define STRING_DESMUME_WEBSITE "http://www.desmume.org" +#define STRING_DESMUME_FORUM_SITE "http://forums.desmume.org/index.php" +#define STRING_DESMUME_BUG_SITE "http://sourceforge.net/tracker/?group_id=164579&atid=832291" + +#define STRING_FILENAME_README "README" +#define STRING_FILENAME_COPYING "COPYING" +#define STRING_FILENAME_AUTHORS "AUTHORS" +#define STRING_FILENAME_CHANGELOG "ChangeLog" + +#define STRING_TABLABEL_README "Read Me" +#define STRING_TABLABEL_LICENSE "License" +#define STRING_TABLABEL_AUTHORS "Authors" +#define STRING_TABLABEL_CHANGELOG "Change Log" + const CGFloat inner_padding = 3; const CGFloat outer_padding = 3; const CGFloat tab_view_height = 240; @@ -36,6 +50,8 @@ NSTextField *about_website; } - (void)windowDidResize:(NSNotification*)notification; - (void)windowWillClose:(NSNotification*)notification; + ++ (void) readTextFile:(NSString *)dataPath label:(NSString *)labelName tab:(NSTabView *)tabView; @end @implementation AboutDelegate @@ -77,23 +93,52 @@ NSTextField *about_website; //end our modal session if the about window closses [NSApp stopModal]; } + ++ (void) readTextFile:(NSString *)dataPath label:(NSString *)labelName tab:(NSTabView *)tabView +{ + NSRect rect; + rect.origin.x = rect.origin.y = 0; + + NSTabViewItem *tab_view_item = [[NSTabViewItem alloc] initWithIdentifier:nil]; + [tab_view_item setLabel:labelName]; + [tabView addTabViewItem:tab_view_item]; + + NSScrollView *scroll_view = [[NSScrollView alloc] initWithFrame:NSMakeRect(0,0,0,0)]; + [scroll_view setDrawsBackground:NO]; + [scroll_view setHasVerticalScroller:YES]; + [scroll_view setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable]; + [tab_view_item setView:scroll_view]; + + rect.size = [[scroll_view contentView] frame].size; + NSTextView *text_view = [[NSTextView alloc] initWithFrame:rect]; + [text_view insertText:[NSString stringWithContentsOfFile:dataPath encoding:NSASCIIStringEncoding error:NULL]]; + [text_view setDrawsBackground:NO]; + [text_view setEditable:NO]; + [text_view setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable]; + [scroll_view setDocumentView:text_view]; + [text_view release]; + + [scroll_view release]; + + [tab_view_item release]; +} @end @implementation NSApplication (helpmenu) - (void)launchWebsite { - [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://desmume.sourceforge.net"]]; + [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@STRING_DESMUME_WEBSITE]]; } - (void)launchForums { - [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://forums.desmume.org/index.php"]]; + [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@STRING_DESMUME_FORUM_SITE]]; } - (void)bugReport { - [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://sourceforge.net/tracker/?func=add&group_id=164579&atid=832291"]]; + [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@STRING_DESMUME_BUG_SITE]]; } @end @@ -201,7 +246,7 @@ NSTextField *about_website; // about_website = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 8 + tab_view_height + inner_padding, width, 17)]; - [about_website setStringValue:@"http://www.desmume.org"];//fixme linkize + [about_website setStringValue:@STRING_DESMUME_WEBSITE];//fixme linkize [about_website setEditable:NO]; [about_website setDrawsBackground:NO]; [about_website setBordered:NO]; @@ -221,126 +266,33 @@ NSTextField *about_website; NSTabView *tab_view = [[NSTabView alloc] initWithFrame:NSMakeRect(outer_padding, outer_padding, window_width - outer_padding*2, tab_view_height)]; [tab_view setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable]; [[about_window contentView] addSubview:tab_view]; - - NSRect rect; - rect.origin.x = rect.origin.y = 0; - - //fixme if one of the files we read from is missing the entire panel doesn't show - - NSTabViewItem *tab_view_item; - NSScrollView *scroll_view; - NSTextView *text_view; //README - NSString *datapath = [main_bundle pathForResource:@"README" ofType:@""]; + NSString *datapath = [main_bundle pathForResource:@STRING_FILENAME_README ofType:@""]; if(datapath != nil) { - tab_view_item = [[NSTabViewItem alloc] initWithIdentifier:nil]; - [tab_view_item setLabel:NSLocalizedString(@"Readme", nil)]; - [tab_view addTabViewItem:tab_view_item]; - - scroll_view = [[NSScrollView alloc] initWithFrame:NSMakeRect(0,0,0,0)]; - [scroll_view setDrawsBackground:NO]; - [scroll_view setHasVerticalScroller:YES]; - [scroll_view setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable]; - [tab_view_item setView:scroll_view]; - - rect.size = [[scroll_view contentView] frame].size; - text_view = [[NSTextView alloc] initWithFrame:rect]; - [text_view insertText:[NSString stringWithContentsOfFile:datapath]]; - [text_view setDrawsBackground:NO]; - [text_view setEditable:NO]; - [text_view setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable]; - [scroll_view setDocumentView:text_view]; - [text_view release]; - - [scroll_view release]; - - [tab_view_item release]; + [AboutDelegate readTextFile:datapath label:NSLocalizedString(@STRING_TABLABEL_README, nil) tab:tab_view]; } //LICENSE - datapath = [main_bundle pathForResource:@"COPYING" ofType:@""]; + datapath = [main_bundle pathForResource:@STRING_FILENAME_COPYING ofType:@""]; if(datapath != nil) { - tab_view_item = [[NSTabViewItem alloc] initWithIdentifier:nil]; - [tab_view_item setLabel:NSLocalizedString(@"License", nil)]; - [tab_view addTabViewItem:tab_view_item]; - - scroll_view = [[NSScrollView alloc] initWithFrame:NSMakeRect(0,0,0,0)]; - [scroll_view setDrawsBackground:NO]; - [scroll_view setHasVerticalScroller:YES]; - [scroll_view setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable]; - [tab_view_item setView:scroll_view]; - - rect.size = [[scroll_view contentView] frame].size; - text_view = [[NSTextView alloc] initWithFrame:rect]; - [text_view insertText:[NSString stringWithContentsOfFile:datapath]]; - [text_view setDrawsBackground:NO]; - [text_view setEditable:NO]; - [text_view setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable]; - [scroll_view setDocumentView:text_view]; - [text_view release]; - - [scroll_view release]; - - [tab_view_item release]; + [AboutDelegate readTextFile:datapath label:NSLocalizedString(@STRING_TABLABEL_LICENSE, nil) tab:tab_view]; } //AUTHORS - datapath = [main_bundle pathForResource:@"AUTHORS" ofType:@""]; + datapath = [main_bundle pathForResource:@STRING_FILENAME_AUTHORS ofType:@""]; if(datapath != nil) { - tab_view_item = [[NSTabViewItem alloc] initWithIdentifier:nil]; - [tab_view_item setLabel:NSLocalizedString(@"Authors", nil)]; - [tab_view addTabViewItem:tab_view_item]; - - scroll_view = [[NSScrollView alloc] initWithFrame:NSMakeRect(0,0,0,0)]; - [scroll_view setDrawsBackground:NO]; - [scroll_view setHasVerticalScroller:YES]; - [scroll_view setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable]; - [tab_view_item setView:scroll_view]; - - rect.size = [[scroll_view contentView] frame].size; - text_view = [[NSTextView alloc] initWithFrame:rect]; - [text_view insertText:[NSString stringWithContentsOfFile:datapath]]; - [text_view setDrawsBackground:NO]; - [text_view setEditable:NO]; - [text_view setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable]; - [scroll_view setDocumentView:text_view]; - [text_view release]; - - [scroll_view release]; - - [tab_view_item release]; + [AboutDelegate readTextFile:datapath label:NSLocalizedString(@STRING_TABLABEL_AUTHORS, nil) tab:tab_view]; } //CHANGE LOG - datapath = [main_bundle pathForResource:@"ChangeLog" ofType:@""]; + datapath = [main_bundle pathForResource:@STRING_FILENAME_CHANGELOG ofType:@""]; if(datapath != nil) { - tab_view_item = [[NSTabViewItem alloc] initWithIdentifier:nil]; - [tab_view_item setLabel:NSLocalizedString(@"Change Log", nil)]; - [tab_view addTabViewItem:tab_view_item]; - - scroll_view = [[NSScrollView alloc] initWithFrame:NSMakeRect(0,0,0,0)]; - [scroll_view setDrawsBackground:NO]; - [scroll_view setHasVerticalScroller:YES]; - [scroll_view setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable]; - [tab_view_item setView:scroll_view]; - - rect.size = [[scroll_view contentView] frame].size; - text_view = [[NSTextView alloc] initWithFrame:rect]; - [text_view insertText:[NSString stringWithContentsOfFile:datapath]]; - [text_view setDrawsBackground:NO]; - [text_view setEditable:NO]; - [text_view setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable]; - [scroll_view setDocumentView:text_view]; - [text_view release]; - - [scroll_view release]; - - [tab_view_item release]; + [AboutDelegate readTextFile:datapath label:NSLocalizedString(@STRING_TABLABEL_CHANGELOG, nil) tab:tab_view]; } // @@ -348,9 +300,9 @@ NSTextField *about_website; content_min_width = [tab_view minimumSize].width; [tab_view release]; - + //show the window - rect = [about_window frame]; + NSRect rect = [about_window frame]; if(rect.size.width < content_min_width + outer_padding*2) rect.size.width = content_min_width + outer_padding*2; [about_window setFrame:rect display:NO]; diff --git a/desmume/src/cocoa/cocoa_input.h b/desmume/src/cocoa/cocoa_input.h new file mode 100644 index 000000000..1a153ce75 --- /dev/null +++ b/desmume/src/cocoa/cocoa_input.h @@ -0,0 +1,185 @@ +/* Copyright (C) 2011 Roger Manuel + + 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 + + +@interface CocoaDSInput : NSObject +{ + bool isStateChanged; + NSMutableDictionary *property; +} + +- (id) init; +- (void) dealloc; +- (void) setIsStateChanged:(bool)state; +- (bool) isStateChanged; +- (void) setInputTime:(NSDate*)inputTime; +- (NSDate*) getInputTime; + +@end + +@interface CocoaDSButton : CocoaDSInput +{ + +} + +- (id) init; +- (void) dealloc; +- (void) setPressed:(bool)inputValue; +- (bool) getPressed; + +@end + +@interface CocoaDSTouch : CocoaDSInput +{ + +} + +- (id) init; +- (void) dealloc; + +- (void) setTouching:(bool)inputValue; +- (bool) getTouching; + +- (void) setX:(float)inputValue; +- (float) getX; + +- (void) setY:(float)inputValue; +- (float) getY; + +- (void) setPoint:(NSPoint)inputValue; +- (NSPoint) getPoint; + +- (void) setTouchingWithCoords:(bool)isTouching x:(float)xValue y:(float)yValue; +- (void) setTouchingWithPoint:(bool)isTouching point:(NSPoint)inputPoint; + +@end + +@interface CocoaDSMic : CocoaDSInput +{ + +} + +- (id) init; +- (void) dealloc; +- (void) setPressed:(bool)inputValue; +- (bool) getPressed; + +@end + + +@interface CocoaDSController : NSObject +{ + CocoaDSButton *ndsButton_Up; + CocoaDSButton *ndsButton_Down; + CocoaDSButton *ndsButton_Left; + CocoaDSButton *ndsButton_Right; + CocoaDSButton *ndsButton_A; + CocoaDSButton *ndsButton_B; + CocoaDSButton *ndsButton_X; + CocoaDSButton *ndsButton_Y; + CocoaDSButton *ndsButton_Select; + CocoaDSButton *ndsButton_Start; + CocoaDSButton *ndsButton_R; + CocoaDSButton *ndsButton_L; + CocoaDSButton *ndsButton_Debug; + CocoaDSButton *ndsButton_Lid; + + CocoaDSTouch *ndsTouch; + + CocoaDSMic *ndsMic; +} + +- (id) init; +- (void) dealloc; + +- (void) setupAllDSInputs; + +//touch screen +- (void)touch:(NSPoint)point; +- (void)releaseTouch; +- (bool) getTouching; +- (NSPoint) getTouchPoint; +- (float) getTouchXCoord; +- (float) getTouchYCoord; + +//button input +- (void)pressStart; +- (void)liftStart; +- (bool) getStartPressed; + +- (void)pressSelect; +- (void)liftSelect; +- (bool) getSelectPressed; + +- (void)pressLeft; +- (void)liftLeft; +- (bool) getLeftPressed; + +- (void)pressRight; +- (void)liftRight; +- (bool) getRightPressed; + +- (void)pressUp; +- (void)liftUp; +- (bool) getUpPressed; + +- (void)pressDown; +- (void)liftDown; +- (bool) getDownPressed; + +- (void)pressA; +- (void)liftA; +- (bool) getAPressed; + +- (void)pressB; +- (void)liftB; +- (bool) getBPressed; + +- (void)pressX; +- (void)liftX; +- (bool) getXPressed; + +- (void)pressY; +- (void)liftY; +- (bool) getYPressed; + +- (void)pressL; +- (void)liftL; +- (bool) getLPressed; + +- (void)pressR; +- (void)liftR; +- (bool) getRPressed; + +- (void) pressDebug; +- (void) liftDebug; +- (bool) getDebugPressed; + +- (void) pressLid; +- (void) liftLid; +- (bool) getLidPressed; + +// Nintendo DS Mic +- (void) pressMic; +- (void) liftMic; +- (bool) getMicPressed; + +@end \ No newline at end of file diff --git a/desmume/src/cocoa/cocoa_input.mm b/desmume/src/cocoa/cocoa_input.mm new file mode 100644 index 000000000..3f463cc33 --- /dev/null +++ b/desmume/src/cocoa/cocoa_input.mm @@ -0,0 +1,596 @@ +/* Copyright (C) 2011 Roger Manuel + + 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 "cocoa_input.h" +#include "../NDSSystem.h" + + +@implementation CocoaDSInput + +- (id) init +{ + isStateChanged = false; + + property = [[NSMutableDictionary alloc] init]; + [property setValue:[NSDate date] forKey:@"inputTime"]; + + return self; +} + +- (void) dealloc +{ + [property release]; + + [super dealloc]; +} + +- (void) setIsStateChanged:(bool)state +{ + isStateChanged = state; +} + +- (bool) isStateChanged +{ + return isStateChanged; +} + +- (void) setInputTime:(NSDate*)inputTime +{ + [property setValue:inputTime forKey:@"inputTime"]; +} + +- (NSDate*) getInputTime +{ + return [property objectForKey:@"inputTime"]; +} + +@end + +@implementation CocoaDSButton + +- (id) init +{ + [super init]; + [property setValue:[NSNumber numberWithBool:false] forKey:@"press"]; + + return self; +} + +- (void) dealloc +{ + [super dealloc]; +} + +- (void) setPressed:(bool)inputValue +{ + // Check for state change and set the flag appropriately. + if (inputValue != [self getPressed]) + { + isStateChanged = true; + } + else + { + isStateChanged = false; + } + + [property setValue:[NSDate date] forKey:@"inputTime"]; + [property setValue:[NSNumber numberWithBool:inputValue] forKey:@"press"]; +} + +- (bool) getPressed +{ + return [[property objectForKey:@"press"] boolValue]; +} + +@end + +@implementation CocoaDSTouch + +- (id) init +{ + [super init]; + [property setValue:[NSNumber numberWithBool:false] forKey:@"touch"]; + [property setValue:[NSNumber numberWithFloat:0.0] forKey:@"x"]; + [property setValue:[NSNumber numberWithFloat:0.0] forKey:@"y"]; + + return self; +} + +- (void) dealloc +{ + [super dealloc]; +} + +- (void) setTouching:(bool)inputValue +{ + // Check for state change and set the flag appropriately. + if (inputValue != [self getTouching]) + { + isStateChanged = true; + } + else + { + isStateChanged = false; + } + + [property setValue:[NSDate date] forKey:@"inputTime"]; + [property setValue:[NSNumber numberWithBool:inputValue] forKey:@"touch"]; +} + +- (bool) getTouching +{ + return [[property objectForKey:@"touch"] boolValue]; +} + +- (void) setX:(float)inputValue +{ + // Check for state change and set the flag appropriately. + if (inputValue != [self getX]) + { + isStateChanged = true; + } + else + { + isStateChanged = false; + } + + [property setValue:[NSDate date] forKey:@"inputTime"]; + [property setValue:[NSNumber numberWithFloat:inputValue] forKey:@"x"]; +} + +- (float) getX +{ + return [[property objectForKey:@"x"] floatValue]; +} + +- (void) setY:(float)inputValue +{ + // Check for state change and set the flag appropriately. + if (inputValue != [self getY]) + { + isStateChanged = true; + } + else + { + isStateChanged = false; + } + + [property setValue:[NSDate date] forKey:@"inputTime"]; + [property setValue:[NSNumber numberWithFloat:inputValue] forKey:@"y"]; +} + +- (float) getY +{ + return [[property objectForKey:@"y"] floatValue]; +} + +- (void) setPoint:(NSPoint)inputValue +{ + // Check for state change and set the flag appropriately. + if (inputValue.x != [self getX] || inputValue.y != [self getY]) + { + isStateChanged = true; + } + else + { + isStateChanged = false; + } + + [self setX:inputValue.x]; + [self setY:inputValue.y]; +} + +- (NSPoint) getPoint +{ + NSPoint outPoint = {[self getX], [self getY]}; + return outPoint; +} + +- (void) setTouchingWithCoords:(bool)isTouching x:(float)xValue y:(float)yValue +{ + // Check for state change and set the flag appropriately. + if (isTouching != [self getTouching] || + xValue != [self getX] || + yValue != [self getY]) + { + isStateChanged = true; + } + else + { + isStateChanged = false; + } + + [property setValue:[NSDate date] forKey:@"inputTime"]; + [property setValue:[NSNumber numberWithBool:isTouching] forKey:@"touch"]; + [property setValue:[NSNumber numberWithFloat:xValue] forKey:@"x"]; + [property setValue:[NSNumber numberWithFloat:yValue] forKey:@"y"]; +} + +- (void) setTouchingWithPoint:(bool)isTouching point:(NSPoint)inputPoint +{ + [self setTouchingWithCoords:isTouching x:inputPoint.x y:inputPoint.y]; +} + +@end + +@implementation CocoaDSMic + +- (id) init +{ + [super init]; + [property setValue:[NSNumber numberWithBool:false] forKey:@"press"]; + + return self; +} + +- (void) dealloc +{ + [super dealloc]; +} + +- (void) setPressed:(bool)inputValue +{ + [property setValue:[NSDate date] forKey:@"inputTime"]; + [property setValue:[NSNumber numberWithBool:inputValue] forKey:@"press"]; +} + +- (bool) getPressed +{ + return [[property objectForKey:@"press"] boolValue]; +} + +@end + + +@implementation CocoaDSController + +- (id) init +{ + ndsButton_Up = [[CocoaDSButton alloc] init]; + ndsButton_Down = [[CocoaDSButton alloc] init]; + ndsButton_Left = [[CocoaDSButton alloc] init]; + ndsButton_Right = [[CocoaDSButton alloc] init]; + ndsButton_A = [[CocoaDSButton alloc] init]; + ndsButton_B = [[CocoaDSButton alloc] init]; + ndsButton_X = [[CocoaDSButton alloc] init]; + ndsButton_Y = [[CocoaDSButton alloc] init]; + ndsButton_Select = [[CocoaDSButton alloc] init]; + ndsButton_Start = [[CocoaDSButton alloc] init]; + ndsButton_R = [[CocoaDSButton alloc] init]; + ndsButton_L = [[CocoaDSButton alloc] init]; + ndsButton_Debug = [[CocoaDSButton alloc] init]; + ndsButton_Lid = [[CocoaDSButton alloc] init]; + + ndsTouch = [[CocoaDSTouch alloc] init]; + + ndsMic = [[CocoaDSMic alloc] init]; + + return self; +} + +- (void) dealloc +{ + [ndsButton_Up release]; + [ndsButton_Down release]; + [ndsButton_Left release]; + [ndsButton_Right release]; + [ndsButton_A release]; + [ndsButton_B release]; + [ndsButton_X release]; + [ndsButton_Y release]; + [ndsButton_Select release]; + [ndsButton_Start release]; + [ndsButton_R release]; + [ndsButton_L release]; + [ndsButton_Debug release]; + [ndsButton_Lid release]; + [ndsTouch release]; + [ndsMic release]; + + [super dealloc]; +} + +- (void) setupAllDSInputs +{ + // Setup the DS pad. + NDS_setPad([self getRightPressed], + [self getLeftPressed], + [self getDownPressed], + [self getUpPressed], + [self getSelectPressed], + [self getStartPressed], + [self getBPressed], + [self getAPressed], + [self getYPressed], + [self getXPressed], + [self getLPressed], + [self getRPressed], + [self getDebugPressed], + [self getLidPressed]); + + // Setup the DS touch pad. + if ([self getTouching]) + { + NDS_setTouchPos([self getTouchXCoord], [self getTouchYCoord]); + } + else + { + NDS_releaseTouch(); + } + + // Setup the DS mic. + NDS_setMic([self getMicPressed]); +} + +- (void)touch:(NSPoint)point +{ + [ndsTouch setTouchingWithPoint:true point:point]; +} + +- (void)releaseTouch +{ + [ndsTouch setTouching:false]; +} + +- (bool) getTouching +{ + return [ndsTouch getTouching]; +} + +- (NSPoint) getTouchPoint +{ + return [ndsTouch getPoint]; +} + +- (float) getTouchXCoord +{ + return [ndsTouch getX]; +} + +- (float) getTouchYCoord +{ + return [ndsTouch getY]; +} + +- (void)pressStart +{ + [ndsButton_Start setPressed:true]; +} + +- (void)liftStart +{ + [ndsButton_Start setPressed:false]; +} + +- (bool) getStartPressed +{ + return [ndsButton_Start getPressed]; +} + +- (void)pressSelect +{ + [ndsButton_Select setPressed:true]; +} + +- (void)liftSelect +{ + [ndsButton_Select setPressed:false]; +} + +- (bool) getSelectPressed +{ + return [ndsButton_Select getPressed]; +} + +- (void)pressLeft +{ + [ndsButton_Left setPressed:true]; +} + +- (void)liftLeft +{ + [ndsButton_Left setPressed:false]; +} + +- (bool) getLeftPressed +{ + return [ndsButton_Left getPressed]; +} + +- (void)pressRight +{ + [ndsButton_Right setPressed:true]; +} + +- (void)liftRight +{ + [ndsButton_Right setPressed:false]; +} + +- (bool) getRightPressed +{ + return [ndsButton_Right getPressed]; +} + +- (void)pressUp +{ + [ndsButton_Up setPressed:true]; +} + +- (void)liftUp +{ + [ndsButton_Up setPressed:false]; +} + +- (bool) getUpPressed +{ + return [ndsButton_Up getPressed]; +} + +- (void)pressDown +{ + [ndsButton_Down setPressed:true]; +} + +- (void)liftDown +{ + [ndsButton_Down setPressed:false]; +} + +- (bool) getDownPressed +{ + return [ndsButton_Down getPressed]; +} + +- (void)pressA +{ + [ndsButton_A setPressed:true]; +} + +- (void)liftA +{ + [ndsButton_A setPressed:false]; +} + +- (bool) getAPressed +{ + return [ndsButton_A getPressed]; +} + +- (void)pressB +{ + [ndsButton_B setPressed:true]; +} + +- (void)liftB +{ + [ndsButton_B setPressed:false]; +} + +- (bool) getBPressed +{ + return [ndsButton_B getPressed]; +} + +- (void)pressX +{ + [ndsButton_X setPressed:true]; +} + +- (void)liftX +{ + [ndsButton_X setPressed:false]; +} + +- (bool) getXPressed +{ + return [ndsButton_X getPressed]; +} + +- (void)pressY +{ + [ndsButton_Y setPressed:true]; +} + +- (void)liftY +{ + [ndsButton_Y setPressed:false]; +} + +- (bool) getYPressed +{ + return [ndsButton_Y getPressed]; +} + +- (void)pressL +{ + [ndsButton_L setPressed:true]; +} + +- (void)liftL +{ + [ndsButton_L setPressed:false]; +} + +- (bool) getLPressed +{ + return [ndsButton_L getPressed]; +} + +- (void)pressR +{ + [ndsButton_R setPressed:true]; +} + +- (void)liftR +{ + [ndsButton_R setPressed:false]; +} + +- (bool) getRPressed +{ + return [ndsButton_R getPressed]; +} + +- (void) pressDebug +{ + [ndsButton_Debug setPressed:true]; +} + +- (void) liftDebug +{ + [ndsButton_Debug setPressed:false]; +} + +- (bool) getDebugPressed +{ + return [ndsButton_Debug getPressed]; +} + +- (void) pressLid +{ + [ndsButton_Lid setPressed:true]; +} + +- (void) liftLid +{ + [ndsButton_Lid setPressed:false]; +} + +- (bool) getLidPressed +{ + return [ndsButton_Lid getPressed]; +} + +- (void) pressMic +{ + [ndsMic setPressed:true]; +} + +- (void) liftMic +{ + [ndsMic setPressed:false]; +} + +- (bool) getMicPressed +{ + return [ndsMic getPressed]; +} + +@end \ No newline at end of file diff --git a/desmume/src/cocoa/cocoa_util.m b/desmume/src/cocoa/cocoa_util.m index 27452e408..fd8447e47 100644 --- a/desmume/src/cocoa/cocoa_util.m +++ b/desmume/src/cocoa/cocoa_util.m @@ -58,3 +58,110 @@ NSString* openDialog(NSArray *file_types) return NULL; } +BOOL CreateAppDirectory(NSString *directoryName) +{ + BOOL result = NO; + BOOL isDir = YES; + + NSString *tempPath = nil; + NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"]; + NSString *appVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"]; + + NSArray *savePaths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES); + if ([savePaths count] > 0) + { + tempPath = [savePaths objectAtIndex:0]; + } + else + { + return result; + } + + NSFileManager *fileManager = [[NSFileManager alloc] init]; + + /* + Mac OS X v10.4 only + + Code for creating new directories based on NSString paths. + */ + tempPath = [[tempPath stringByAppendingString:@"/"] stringByAppendingString:appName]; + result = [fileManager createDirectoryAtPath:tempPath attributes:nil]; + if (result == NO) + { + if([fileManager fileExistsAtPath:tempPath isDirectory:&isDir] == NO) + { + [fileManager release]; + return result; + } + } + + tempPath = [[tempPath stringByAppendingString:@"/"] stringByAppendingString:appVersion]; + result = [fileManager createDirectoryAtPath:tempPath attributes:nil]; + if (result == NO) + { + if([fileManager fileExistsAtPath:tempPath isDirectory:&isDir] == NO) + { + [fileManager release]; + return result; + } + } + + if (directoryName != nil) + { + tempPath = [[tempPath stringByAppendingString:@"/"] stringByAppendingString:directoryName]; + result = [fileManager createDirectoryAtPath:tempPath attributes:nil]; + if (result == NO) + { + if([fileManager fileExistsAtPath:tempPath isDirectory:&isDir] == NO) + { + [fileManager release]; + return result; + } + } + } + + /* + In Mac OS X v10.4, having the File Manager create new directories where they already exist + returns NO. Note that this behavior is not per Apple's own documentation. Therefore, we manually + set result=YES at the end to make sure the function returns the right result. + */ + result = YES; + + /* + Mac OS X v10.5 and later + + Yes, it's that simple... + */ + //result = [fileManager createDirectoryAtPath:savePath createIntermediates:YES attributes:nil error:NULL]; + + [fileManager release]; + return result; +} + +NSString* GetPathUserAppSupport(NSString *directoryName) +{ + NSString *userAppSupportPath = nil; + NSString *appName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"]; + NSString *appVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"]; + + NSArray *savePaths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES); + if ([savePaths count] > 0) + { + userAppSupportPath = [savePaths objectAtIndex:0]; + } + else + { + return userAppSupportPath; + } + + if (directoryName == nil) + { + userAppSupportPath = [[[[userAppSupportPath stringByAppendingString:@"/"] stringByAppendingString:appName] stringByAppendingString:@"/"] stringByAppendingString:appVersion]; + } + else + { + userAppSupportPath = [[[[[[userAppSupportPath stringByAppendingString:@"/"] stringByAppendingString:appName] stringByAppendingString:@"/"] stringByAppendingString:appVersion] stringByAppendingString:@"/"] stringByAppendingString:directoryName]; + } + + return userAppSupportPath; +} \ No newline at end of file diff --git a/desmume/src/cocoa/globals.h b/desmume/src/cocoa/globals.h index 3bffd38c3..e4b8c82a1 100644 --- a/desmume/src/cocoa/globals.h +++ b/desmume/src/cocoa/globals.h @@ -27,6 +27,8 @@ extern "C" void messageDialog(NSString *title, NSString *text); BOOL messageDialogYN(NSString *title, NSString *text); NSString* openDialog(NSArray *file_types); +BOOL CreateAppDirectory(NSString *directoryName); +NSString* GetPathUserAppSupport(NSString *directoryName); // #if !defined(__LP64__) && !defined(NS_BUILD_32_LIKE_64) @@ -34,7 +36,15 @@ typedef int NSInteger; typedef unsigned int NSUInteger; #endif -typedef float CGFloat; +// Taken from CIVector.h of the Mac OS X 10.5 SDK. +// Defines CGFloat for Mac OS X 10.4 and earlier. +#ifndef CGFLOAT_DEFINED + typedef float CGFloat; +# define CGFLOAT_MIN FLT_MIN +# define CGFLOAT_MAX FLT_MAX +# define CGFLOAT_IS_DOUBLE 0 +# define CGFLOAT_DEFINED 1 +#endif #ifdef __cplusplus } diff --git a/desmume/src/cocoa/input.h b/desmume/src/cocoa/input.h index 968934f16..9399c623b 100644 --- a/desmume/src/cocoa/input.h +++ b/desmume/src/cocoa/input.h @@ -25,11 +25,13 @@ */ @class VideoOutputWindow; +@class CocoaDSController; @interface InputHandler : NSResponder { @private VideoOutputWindow *my_ds; + CocoaDSController *dsController; } //preferences + (NSView*)createPreferencesView:(float)width; diff --git a/desmume/src/cocoa/input.mm b/desmume/src/cocoa/input.mm index 0994724e6..eb5af23f3 100644 --- a/desmume/src/cocoa/input.mm +++ b/desmume/src/cocoa/input.mm @@ -166,12 +166,14 @@ inline int testKey(NSString *chars_pressed, NSString *chars_for_key) my_ds = nds; [my_ds retain]; + dsController = [nds getDSController]; + [dsController retain]; + return self; } - (void)dealloc { - [my_ds release]; [super dealloc]; } @@ -182,18 +184,18 @@ inline int testKey(NSString *chars_pressed, NSString *chars_for_key) NSUserDefaults *settings = [NSUserDefaults standardUserDefaults]; NSString *chars = [event characters]; - if(testKey(chars, [settings stringForKey:PREF_KEY_A ]))[my_ds pressA]; - else if(testKey(chars, [settings stringForKey:PREF_KEY_B ]))[my_ds pressB]; - else if(testKey(chars, [settings stringForKey:PREF_KEY_SELECT]))[my_ds pressSelect]; - else if(testKey(chars, [settings stringForKey:PREF_KEY_START ]))[my_ds pressStart]; - else if(testKey(chars, [settings stringForKey:PREF_KEY_RIGHT ]))[my_ds pressRight]; - else if(testKey(chars, [settings stringForKey:PREF_KEY_LEFT ]))[my_ds pressLeft]; - else if(testKey(chars, [settings stringForKey:PREF_KEY_UP ]))[my_ds pressUp]; - else if(testKey(chars, [settings stringForKey:PREF_KEY_DOWN ]))[my_ds pressDown]; - else if(testKey(chars, [settings stringForKey:PREF_KEY_R ]))[my_ds pressR]; - else if(testKey(chars, [settings stringForKey:PREF_KEY_L ]))[my_ds pressL]; - else if(testKey(chars, [settings stringForKey:PREF_KEY_X ]))[my_ds pressX]; - else if(testKey(chars, [settings stringForKey:PREF_KEY_Y ]))[my_ds pressY]; + if(testKey(chars, [settings stringForKey:PREF_KEY_A ]))[dsController pressA]; + else if(testKey(chars, [settings stringForKey:PREF_KEY_B ]))[dsController pressB]; + else if(testKey(chars, [settings stringForKey:PREF_KEY_SELECT]))[dsController pressSelect]; + else if(testKey(chars, [settings stringForKey:PREF_KEY_START ]))[dsController pressStart]; + else if(testKey(chars, [settings stringForKey:PREF_KEY_RIGHT ]))[dsController pressRight]; + else if(testKey(chars, [settings stringForKey:PREF_KEY_LEFT ]))[dsController pressLeft]; + else if(testKey(chars, [settings stringForKey:PREF_KEY_UP ]))[dsController pressUp]; + else if(testKey(chars, [settings stringForKey:PREF_KEY_DOWN ]))[dsController pressDown]; + else if(testKey(chars, [settings stringForKey:PREF_KEY_R ]))[dsController pressR]; + else if(testKey(chars, [settings stringForKey:PREF_KEY_L ]))[dsController pressL]; + else if(testKey(chars, [settings stringForKey:PREF_KEY_X ]))[dsController pressX]; + else if(testKey(chars, [settings stringForKey:PREF_KEY_Y ]))[dsController pressY]; } - (void)keyUp:(NSEvent*)event @@ -201,24 +203,28 @@ inline int testKey(NSString *chars_pressed, NSString *chars_for_key) NSUserDefaults *settings = [NSUserDefaults standardUserDefaults]; NSString *chars = [event characters]; - if(testKey(chars, [settings stringForKey:PREF_KEY_A ]))[my_ds liftA]; - else if(testKey(chars, [settings stringForKey:PREF_KEY_B ]))[my_ds liftB]; - else if(testKey(chars, [settings stringForKey:PREF_KEY_SELECT]))[my_ds liftSelect]; - else if(testKey(chars, [settings stringForKey:PREF_KEY_START ]))[my_ds liftStart]; - else if(testKey(chars, [settings stringForKey:PREF_KEY_RIGHT ]))[my_ds liftRight]; - else if(testKey(chars, [settings stringForKey:PREF_KEY_LEFT ]))[my_ds liftLeft]; - else if(testKey(chars, [settings stringForKey:PREF_KEY_UP ]))[my_ds liftUp]; - else if(testKey(chars, [settings stringForKey:PREF_KEY_DOWN ]))[my_ds liftDown]; - else if(testKey(chars, [settings stringForKey:PREF_KEY_R ]))[my_ds liftR]; - else if(testKey(chars, [settings stringForKey:PREF_KEY_L ]))[my_ds liftL]; - else if(testKey(chars, [settings stringForKey:PREF_KEY_X ]))[my_ds liftX]; - else if(testKey(chars, [settings stringForKey:PREF_KEY_Y ]))[my_ds liftY]; + if(testKey(chars, [settings stringForKey:PREF_KEY_A ]))[dsController liftA]; + else if(testKey(chars, [settings stringForKey:PREF_KEY_B ]))[dsController liftB]; + else if(testKey(chars, [settings stringForKey:PREF_KEY_SELECT]))[dsController liftSelect]; + else if(testKey(chars, [settings stringForKey:PREF_KEY_START ]))[dsController liftStart]; + else if(testKey(chars, [settings stringForKey:PREF_KEY_RIGHT ]))[dsController liftRight]; + else if(testKey(chars, [settings stringForKey:PREF_KEY_LEFT ]))[dsController liftLeft]; + else if(testKey(chars, [settings stringForKey:PREF_KEY_UP ]))[dsController liftUp]; + else if(testKey(chars, [settings stringForKey:PREF_KEY_DOWN ]))[dsController liftDown]; + else if(testKey(chars, [settings stringForKey:PREF_KEY_R ]))[dsController liftR]; + else if(testKey(chars, [settings stringForKey:PREF_KEY_L ]))[dsController liftL]; + else if(testKey(chars, [settings stringForKey:PREF_KEY_X ]))[dsController liftX]; + else if(testKey(chars, [settings stringForKey:PREF_KEY_Y ]))[dsController liftY]; } - (void)mouseDown:(NSEvent*)event { NSPoint temp = [my_ds windowPointToDSCoords:[event locationInWindow]]; - if(temp.x >= 0 && temp.y>=0)[my_ds touch:temp]; + + if(temp.x >= 0 && temp.y>=0) + { + [dsController touch:temp]; + } } - (void)mouseDragged:(NSEvent*)event @@ -228,7 +234,7 @@ inline int testKey(NSString *chars_pressed, NSString *chars_for_key) - (void)mouseUp:(NSEvent*)event { - [my_ds releaseTouch]; + [dsController releaseTouch]; } @end diff --git a/desmume/src/cocoa/main.mm b/desmume/src/cocoa/main.mm index f9a19f321..90475001b 100644 --- a/desmume/src/cocoa/main.mm +++ b/desmume/src/cocoa/main.mm @@ -56,10 +56,12 @@ extern NSMenuItem *topBG0_item; extern NSMenuItem *topBG1_item; extern NSMenuItem *topBG2_item; extern NSMenuItem *topBG3_item; +extern NSMenuItem *topOBJ_item; extern NSMenuItem *subBG0_item; extern NSMenuItem *subBG1_item; extern NSMenuItem *subBG2_item; extern NSMenuItem *subBG3_item; +extern NSMenuItem *subOBJ_item; extern NSMenuItem *screenshot_to_file_item; extern NSMenuItem *screenshot_to_window_item; @@ -235,7 +237,8 @@ void CreateMenu(AppDelegate *delegate) [emulation_menu addItem:[NSMenuItem separatorItem]]; //Frake skip menu - + // Disabling frame skipping for now since it doesn't yield any significant speed improvements. -rogerman 03/28/2011 + /* temp = [emulation_menu addItemWithTitle:NSLocalizedString(@"Frame Skip", nil) action:nil keyEquivalent:@""]; NSMenu *frame_skip_menu = [[NSMenu alloc] initWithTitle:NSLocalizedString(@"Frame Skip", nil)]; @@ -256,7 +259,7 @@ void CreateMenu(AppDelegate *delegate) [frame_skip_menu release]; } - + */ //Speed limit menu temp = [emulation_menu addItemWithTitle:NSLocalizedString(@"Speed Limit", nil) action:nil keyEquivalent:@""]; @@ -366,6 +369,7 @@ void CreateMenu(AppDelegate *delegate) topBG1_item = [layer_menu addItemWithTitle:NSLocalizedString(@"Top BG1", nil) action:@selector(toggleTopBackground1) keyEquivalent:@""]; topBG2_item = [layer_menu addItemWithTitle:NSLocalizedString(@"Top BG2", nil) action:@selector(toggleTopBackground2) keyEquivalent:@""]; topBG3_item = [layer_menu addItemWithTitle:NSLocalizedString(@"Top BG3", nil) action:@selector(toggleTopBackground3) keyEquivalent:@""]; + topOBJ_item = [layer_menu addItemWithTitle:NSLocalizedString(@"Top OBJ", nil) action:@selector(toggleTopObject) keyEquivalent:@""]; [layer_menu addItem:[NSMenuItem separatorItem]]; @@ -373,6 +377,7 @@ void CreateMenu(AppDelegate *delegate) subBG1_item = [layer_menu addItemWithTitle:NSLocalizedString(@"Sub BG1", nil) action:@selector(toggleSubBackground1) keyEquivalent:@""]; subBG2_item = [layer_menu addItemWithTitle:NSLocalizedString(@"Sub BG2", nil) action:@selector(toggleSubBackground2) keyEquivalent:@""]; subBG3_item = [layer_menu addItemWithTitle:NSLocalizedString(@"Sub BG3", nil) action:@selector(toggleSubBackground3) keyEquivalent:@""]; + subOBJ_item = [layer_menu addItemWithTitle:NSLocalizedString(@"Sub OBJ", nil) action:@selector(toggleSubObject) keyEquivalent:@""]; [layer_menu release]; } @@ -496,6 +501,7 @@ int main(int argc, char *argv[]) [panel setCanChooseDirectories:NO]; [panel setCanChooseFiles:YES]; + [panel setResolvesAliases:YES]; [panel setAllowsMultipleSelection:NO]; [panel setTitle:NSLocalizedString(@"Open ROM...", nil)]; @@ -545,12 +551,20 @@ int main(int argc, char *argv[]) - (void)application:(NSApplication*)sender openFiles:(NSArray*)filenames { //verify everything - if(sender != NSApp)goto fail; - if(!filenames)goto fail; - if([filenames count] == 0)goto fail; + if(sender != NSApp || + filenames == nil || + [filenames count] == 0) + { + [sender replyToOpenOrPrint:NSApplicationDelegateReplySuccess]; + return; + } + NSString *filename = [filenames lastObject]; - if(!filename)goto fail; - if([filename length] == 0)goto fail; + if(!filename || [filename length] == 0) + { + [sender replyToOpenOrPrint:NSApplicationDelegateReplySuccess]; + return; + } if([main_window loadROM:filename]) { @@ -558,9 +572,6 @@ int main(int argc, char *argv[]) [sender replyToOpenOrPrint:NSApplicationDelegateReplySuccess]; return; } - -fail: - [sender replyToOpenOrPrint:NSApplicationDelegateReplySuccess]; } - (void)applicationWillFinishLaunching:(NSNotification*)notification diff --git a/desmume/src/cocoa/main_window.h b/desmume/src/cocoa/main_window.h index 10b453e7d..3f37ca70c 100644 --- a/desmume/src/cocoa/main_window.h +++ b/desmume/src/cocoa/main_window.h @@ -44,6 +44,8 @@ bool no_smaller_than_ds; bool keep_proportions; + + NSString *pathLoadedRom; } //initialization @@ -102,10 +104,12 @@ - (void)toggleTopBackground1; - (void)toggleTopBackground2; - (void)toggleTopBackground3; +- (void)toggleTopObject; - (void)toggleSubBackground0; - (void)toggleSubBackground1; - (void)toggleSubBackground2; - (void)toggleSubBackground3; +- (void)toggleSubObject; //screenshots - (void)saveScreenshot; @@ -113,4 +117,7 @@ //delegate - (void)windowDidBecomeMain:(NSNotification*)notification; +- (BOOL)saveStateExistsInSlot:(int)slot; +- (NSString*) getSaveSlotFileName:(unsigned int)slotNumber; + @end diff --git a/desmume/src/cocoa/main_window.mm b/desmume/src/cocoa/main_window.mm index 69d35e1b2..11313e681 100644 --- a/desmume/src/cocoa/main_window.mm +++ b/desmume/src/cocoa/main_window.mm @@ -88,10 +88,12 @@ NSMenuItem *topBG0_item = nil; NSMenuItem *topBG1_item = nil; NSMenuItem *topBG2_item = nil; NSMenuItem *topBG3_item = nil; +NSMenuItem *topOBJ_item = nil; NSMenuItem *subBG0_item = nil; NSMenuItem *subBG1_item = nil; NSMenuItem *subBG2_item = nil; NSMenuItem *subBG3_item = nil; +NSMenuItem *subOBJ_item = nil; NSMenuItem *screenshot_to_file_item = nil; @implementation VideoOutputWindow @@ -232,6 +234,8 @@ NSMenuItem *screenshot_to_file_item = nil; NSResponder *temp = [window nextResponder]; [window setNextResponder:input]; [input setNextResponder:temp]; + + pathLoadedRom = nil; return self; } @@ -244,6 +248,7 @@ NSMenuItem *screenshot_to_file_item = nil; [status_view release]; [status_bar_text release]; [input release]; + [pathLoadedRom release]; [super dealloc]; } @@ -275,6 +280,9 @@ NSMenuItem *screenshot_to_file_item = nil; //update the rom info window, if needed [ROMInfo changeDS:self]; + + pathLoadedRom = filename; + [pathLoadedRom retain]; } //reset menu items @@ -283,7 +291,7 @@ NSMenuItem *screenshot_to_file_item = nil; int i; for(i = 0; i < MAX_SLOTS; i++) if([saveSlot_item[i] target] == self) - if([self saveStateExists:i] == YES) + if([self saveStateExistsInSlot:i] == YES) [saveSlot_item[i] setState:NSOnState]; else [saveSlot_item[i] setState:NSOffState]; @@ -301,12 +309,12 @@ NSMenuItem *screenshot_to_file_item = nil; - (void)execute { [super execute]; - + if([pause_item target] == self) [pause_item setState:NSOffState]; if([execute_item target] == self) [execute_item setState:NSOnState]; - + [self setStatusText:NSLocalizedString(@"Emulation Executing", nil)]; } @@ -343,7 +351,7 @@ NSMenuItem *screenshot_to_file_item = nil; - (void)setFrameSkip:(int)frameskip { [super setFrameSkip:frameskip]; - frameskip = [super frameSkip]; + frameskip = dsStateBuffer->frame_skip; if([frame_skip_auto_item target] == self) if(frameskip < 0) @@ -385,7 +393,8 @@ NSMenuItem *screenshot_to_file_item = nil; [super setSpeedLimit:speedLimit]; //Set the correct menu states - speedLimit = [super speedLimit]; + speedLimit = dsStateBuffer->speed_limit; + int standard_size = 0; if([speed_limit_25_item target] == self) @@ -511,23 +520,65 @@ NSMenuItem *screenshot_to_file_item = nil; - (BOOL)saveStateToSlot:(int)slot { - if([super saveStateToSlot:slot] == YES) + BOOL result = NO; + int i = slot; + + NSString *savePath = GetPathUserAppSupport(@"States"); + if (savePath == nil) { - if([saveSlot_item[slot] target] == self); - [saveSlot_item[slot] setState:NSOnState]; + // Throw an error message here... + return result; + } + + result = CreateAppDirectory(@"States"); + if (result == NO) + { + // Should throw an error message here... + return result; + } + + NSString *fileName = [self getSaveSlotFileName:slot]; + if (fileName == nil) + { + return result; + } + + NSString *fullFilePath = [[savePath stringByAppendingString:@"/"] stringByAppendingString:fileName]; + result = [self saveState:fullFilePath]; + if(result) + { + if([saveSlot_item[i] target] == self); + { + [saveSlot_item[i] setState:NSOnState]; + } - //if([clear_all_saves_item target] == self); - //[clear_all_saves_item setEnabled:YES]; - - return YES; + result = YES; } - return NO; + return result; } - (BOOL)loadStateFromSlot:(int)slot { - return [super loadStateFromSlot:slot]; + BOOL result = NO; + + NSString *savePath = GetPathUserAppSupport(@"States"); + if (savePath == nil) + { + // Should throw an error message here... + return result; + } + + NSString *fileName = [self getSaveSlotFileName:slot]; + if (fileName == nil) + { + return result; + } + + NSString *fullFilePath = [[savePath stringByAppendingString:@"/"] stringByAppendingString:fileName]; + result = [self loadState:fullFilePath]; + + return result; } - (BOOL)saveStateAs @@ -666,60 +717,103 @@ NSMenuItem *screenshot_to_file_item = nil; - (NSPoint)windowPointToDSCoords:(NSPoint)location { - if(video_output_view == nil)return NSMakePoint(-1, -1); - - NSSize temp = [[window contentView] frame].size; + CGFloat rotation; + NSSize temp; + float statusBarHeight; + + if(video_output_view == nil) + { + return NSMakePoint(-1, -1); + } + + rotation = [video_output_view boundsRotation]; + statusBarHeight = [self statusBarHeight]; + + temp = [[window contentView] frame].size; CGFloat x_size = temp.width - WINDOW_BORDER_PADDING*2; - CGFloat y_size = temp.height - [self statusBarHeight]; + CGFloat y_size = temp.height - statusBarHeight; //If the click was to the left or under the opengl view, exit - if((location.x < WINDOW_BORDER_PADDING) || (location.y < [self statusBarHeight])) + if((location.x < WINDOW_BORDER_PADDING) || (location.y < statusBarHeight)) + { return NSMakePoint(-1, -1); + } location.x -= WINDOW_BORDER_PADDING; - location.y -= [self statusBarHeight]; + location.y -= statusBarHeight; //If the click was top or right of the view... - if(location.x >= x_size)return NSMakePoint(-1, -1); - if(location.y >= y_size)return NSMakePoint(-1, -1); - - if([video_output_view boundsRotation] == 0 || [video_output_view boundsRotation] == -180) + if(location.x >= x_size) { - if([video_output_view boundsRotation] == -180) + return NSMakePoint(-1, -1); + } + if(location.y >= y_size) + { + return NSMakePoint(-1, -1); + } + + if(rotation == 0) + { + if(location.y >= y_size / 2) { - if(location.y < y_size / 2)return NSMakePoint(-1, -1); - location.x = x_size - location.x; - location.y = y_size - location.y; - } else - if(location.y >= y_size / 2)return NSMakePoint(-1, -1); - + return NSMakePoint(-1, -1); + } + //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 + } + else if(rotation = -90) { - - if([video_output_view boundsRotation] == -270) + if(location.x >= x_size / 2) { - if(location.x < x_size / 2)return NSMakePoint(-1, -1); - location.x = x_size - location.x; - - } else - { - if(location.x >= x_size / 2)return NSMakePoint(-1, -1); - location.y = y_size - location.y; + return NSMakePoint(-1, -1); } - + location.y = y_size - location.y; + location.x *= ((float)DS_SCREEN_HEIGHT_COMBINED) / ((float)x_size); location.y *= ((float)DS_SCREEN_WIDTH) / ((float)y_size); - + //invert the y location.x = DS_SCREEN_HEIGHT - location.x - 1; - + + float temp = location.x; + location.x = location.y; + location.y = temp; + } + else if(rotation = -180) + { + if(location.y < y_size / 2) + { + return NSMakePoint(-1, -1); + } + location.x = x_size - location.x; + location.y = y_size - location.y; + + //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 if(rotation = -270) + { + if(location.x < x_size / 2) + { + return NSMakePoint(-1, -1); + } + location.x = x_size - location.x; + + location.x *= ((float)DS_SCREEN_HEIGHT_COMBINED) / ((float)x_size); + location.y *= ((float)DS_SCREEN_WIDTH) / ((float)y_size); + + //invert the y + location.x = DS_SCREEN_HEIGHT - location.x - 1; + float temp = location.x; location.x = location.y; location.y = temp; @@ -874,10 +968,10 @@ NSMenuItem *screenshot_to_file_item = nil; - (void)toggleTopBackground0 { - [super toggleTopBackground0]; + [self toggleSubScreenLayer:0]; if([topBG0_item target] == self) - if([super showingTopBackground0] == NO) + if([self isSubScreenLayerDisplayed:0] == NO) [topBG0_item setState:NSOffState]; else [topBG0_item setState:NSOnState]; @@ -885,10 +979,10 @@ NSMenuItem *screenshot_to_file_item = nil; - (void)toggleTopBackground1 { - [super toggleTopBackground1]; + [self toggleSubScreenLayer:1]; if([topBG1_item target] == self) - if([super showingTopBackground1] == NO) + if([self isSubScreenLayerDisplayed:1] == NO) [topBG1_item setState:NSOffState]; else [topBG1_item setState:NSOnState]; @@ -896,10 +990,10 @@ NSMenuItem *screenshot_to_file_item = nil; - (void)toggleTopBackground2 { - [super toggleTopBackground2]; + [self toggleSubScreenLayer:2]; if([topBG2_item target] == self) - if([super showingTopBackground2] == NO) + if([self isSubScreenLayerDisplayed:2] == NO) [topBG2_item setState:NSOffState]; else [topBG2_item setState:NSOnState]; @@ -907,21 +1001,32 @@ NSMenuItem *screenshot_to_file_item = nil; - (void)toggleTopBackground3 { - [super toggleTopBackground3]; + [self toggleSubScreenLayer:3]; if([topBG3_item target] == self) - if([super showingTopBackground3] == NO) + if([self isSubScreenLayerDisplayed:3] == NO) [topBG3_item setState:NSOffState]; else [topBG3_item setState:NSOnState]; } +- (void)toggleTopObject +{ + [self toggleSubScreenLayer:4]; + + if([topOBJ_item target] == self) + if([self isSubScreenLayerDisplayed:4] == NO) + [topOBJ_item setState:NSOffState]; + else + [topOBJ_item setState:NSOnState]; +} + - (void)toggleSubBackground0 { - [super toggleSubBackground0]; + [self toggleMainScreenLayer:0]; if([subBG0_item target] == self) - if([super showingSubBackground0] == NO) + if([self isMainScreenLayerDisplayed:0] == NO) [subBG0_item setState:NSOffState]; else [subBG0_item setState:NSOnState]; @@ -929,10 +1034,10 @@ NSMenuItem *screenshot_to_file_item = nil; - (void)toggleSubBackground1 { - [super toggleSubBackground1]; + [self toggleMainScreenLayer:1]; if([subBG1_item target] == self) - if([super showingSubBackground1] == NO) + if([self isMainScreenLayerDisplayed:1] == NO) [subBG1_item setState:NSOffState]; else [subBG1_item setState:NSOnState]; @@ -940,10 +1045,10 @@ NSMenuItem *screenshot_to_file_item = nil; - (void)toggleSubBackground2 { - [super toggleSubBackground2]; + [self toggleMainScreenLayer:2]; if([subBG2_item target] == self) - if([super showingSubBackground2] == NO) + if([self isMainScreenLayerDisplayed:2] == NO) [subBG2_item setState:NSOffState]; else [subBG2_item setState:NSOnState]; @@ -951,15 +1056,26 @@ NSMenuItem *screenshot_to_file_item = nil; - (void)toggleSubBackground3 { - [super toggleSubBackground3]; + [self toggleMainScreenLayer:3]; if([subBG3_item target] == self) - if([super showingSubBackground3] == NO) + if([self isMainScreenLayerDisplayed:3] == NO) [subBG3_item setState:NSOffState]; else [subBG3_item setState:NSOnState]; } +- (void)toggleSubObject +{ + [self toggleMainScreenLayer:4]; + + if([subOBJ_item target] == self) + if([self isMainScreenLayerDisplayed:4] == NO) + [subOBJ_item setState:NSOffState]; + else + [subOBJ_item setState:NSOnState]; +} + - (void)saveScreenshot {//todo: this should work even if video_output_view doesn't exist BOOL executing = [self executing]; @@ -1145,7 +1261,7 @@ NSMenuItem *screenshot_to_file_item = nil; [saveSlot_item[i] setTarget:self]; [loadSlot_item[i] setTarget:self]; - if([self saveStateExists:i] == YES) + if([self saveStateExistsInSlot:i] == YES) { [saveSlot_item[i] setState:NSOnState]; } else @@ -1211,10 +1327,12 @@ NSMenuItem *screenshot_to_file_item = nil; [topBG1_item setTarget:self]; [topBG2_item setTarget:self]; [topBG3_item setTarget:self]; + [topOBJ_item setTarget:self]; [subBG0_item setTarget:self]; [subBG1_item setTarget:self]; [subBG2_item setTarget:self]; [subBG3_item setTarget:self]; + [subOBJ_item setTarget:self]; [screenshot_to_file_item setTarget:self]; //set checks for view window based on the options of this window @@ -1222,38 +1340,56 @@ NSMenuItem *screenshot_to_file_item = nil; [constrain_item setState:keep_proportions?NSOnState:NSOffState]; [min_size_item setState:no_smaller_than_ds?NSOnState:NSOffState]; [toggle_status_bar_item setState:(status_view!=nil)?NSOnState:NSOffState]; - if([self showingTopBackground0]) + + if([self isSubScreenLayerDisplayed:0] == YES) [topBG0_item setState:NSOnState]; else [topBG0_item setState:NSOffState]; - if([self showingTopBackground1]) + + if([self isSubScreenLayerDisplayed:1] == YES) [topBG1_item setState:NSOnState]; else [topBG1_item setState:NSOffState]; - if([self showingTopBackground2]) + + if([self isSubScreenLayerDisplayed:2] == YES) [topBG2_item setState:NSOnState]; else [topBG2_item setState:NSOffState]; - if([self showingTopBackground3]) + + if([self isSubScreenLayerDisplayed:3] == YES) [topBG3_item setState:NSOnState]; else [topBG3_item setState:NSOffState]; - if([self showingSubBackground0]) + + if([self isSubScreenLayerDisplayed:4] == YES) + [topOBJ_item setState:NSOnState]; + else + [topOBJ_item setState:NSOffState]; + + if([self isMainScreenLayerDisplayed:0] == YES) [subBG0_item setState:NSOnState]; else [subBG0_item setState:NSOffState]; - if([self showingSubBackground1]) + + if([self isMainScreenLayerDisplayed:1] == YES) [subBG1_item setState:NSOnState]; else [subBG1_item setState:NSOffState]; - if([self showingSubBackground2]) + + if([self isMainScreenLayerDisplayed:2] == YES) [subBG2_item setState:NSOnState]; else [subBG2_item setState:NSOffState]; - if([self showingSubBackground3]) + + if([self isMainScreenLayerDisplayed:3] == YES) [subBG3_item setState:NSOnState]; else [subBG3_item setState:NSOffState]; + + if([self isMainScreenLayerDisplayed:4] == YES) + [subOBJ_item setState:NSOnState]; + else + [subOBJ_item setState:NSOffState]; [self setRotation:[self rotation]]; @@ -1315,7 +1451,7 @@ NSMenuItem *screenshot_to_file_item = nil; else for(i = 0; i < MAX_SLOTS; i++) if(item == loadSlot_item[i]) - if([self saveStateExists:i]==NO)return NO; + if([self saveStateExistsInSlot:i] == NO)return NO; if(video_output_view == nil) { @@ -1340,4 +1476,33 @@ NSMenuItem *screenshot_to_file_item = nil; return YES; } +- (BOOL)saveStateExistsInSlot:(int)slot +{ + BOOL exists = false; + + NSString *searchPath = GetPathUserAppSupport(@"States"); + NSString *searchFileName = [self getSaveSlotFileName:slot]; + + if (searchPath == nil || searchFileName == nil) + { + return exists; + } + + NSFileManager *fileManager = [[NSFileManager alloc] init]; + NSString *searchFullPath = [[searchPath stringByAppendingString:@"/"] stringByAppendingString:searchFileName]; + + exists = [fileManager isReadableFileAtPath:searchFullPath]; + + [fileManager release]; + + return exists; +} + +- (NSString*) getSaveSlotFileName:(unsigned int)slotNumber +{ + NSString *fileExtension = [NSString stringWithFormat:@".ds%d", slotNumber]; + + return [[[pathLoadedRom lastPathComponent] stringByDeletingPathExtension] stringByAppendingString:fileExtension]; +} + @end diff --git a/desmume/src/cocoa/nds_control.h b/desmume/src/cocoa/nds_control.h index 59eab8ec5..7ef4d89d4 100644 --- a/desmume/src/cocoa/nds_control.h +++ b/desmume/src/cocoa/nds_control.h @@ -18,6 +18,7 @@ */ #import "globals.h" +#import "cocoa_input.h" @class ScreenState; @@ -29,6 +30,17 @@ #define MAX_SLOTS 10 #define MAX_FRAME_SKIP 10 +@interface CocoaDSStateBuffer : NSObject +{ + @public + int frame_skip; + int speed_limit; +} + +- (id) init; + +@end + //This class is a compelte objective-c wrapper for //the core emulation features, other objective-c code inherit //upon or instanciate this to add interfaces for these features @@ -65,6 +77,11 @@ NSString *current_file; NSString *flash_file; + + bool doesConfigNeedUpdate; + NSTimeInterval calcTimeBudget; + + CocoaDSController *dsController; #ifdef GDB_STUB NSInteger arm9_gdb_port; @@ -74,6 +91,9 @@ #endif unsigned char gpu_buff[256 * 256 * 5]; //this is where the 3D rendering of the NDS is stored + + @public + CocoaDSStateBuffer *dsStateBuffer; } //Instanciating, setup, and deconstruction @@ -82,6 +102,9 @@ - (void)setErrorCallback:(SEL)callback withObject:(id)object; - (void)dealloc; +// Data accessors +- (CocoaDSController*) getDSController; + //Firmware control - (void)setPlayerName:(NSString*)player_name; @@ -116,73 +139,19 @@ - (int)speedLimit; - (void)setSaveType:(int)savetype; // see save_types in src/mmu.h - (int)saveType; // default is 0, which is autodetect - -//touch screen -- (void)touch:(NSPoint)point; -- (void)releaseTouch; - -//button input -- (void)pressStart; -- (void)liftStart; -- (BOOL)start; -- (void)pressSelect; -- (void)liftSelect; -- (BOOL)select; -- (void)pressLeft; -- (void)liftLeft; -- (BOOL)left; -- (void)pressRight; -- (void)liftRight; -- (BOOL)right; -- (void)pressUp; -- (void)liftUp; -- (BOOL)up; -- (void)pressDown; -- (void)liftDown; -- (BOOL)down; -- (void)pressA; -- (void)liftA; -- (BOOL)A; -- (void)pressB; -- (void)liftB; -- (BOOL)B; -- (void)pressX; -- (void)liftX; -- (BOOL)X; -- (void)pressY; -- (void)liftY; -- (BOOL)Y; -- (void)pressL; -- (void)liftL; -- (BOOL)L; -- (void)pressR; -- (void)liftR; -- (BOOL)R; +- (void) updateConfig; +- (void) emulateDS; +- (void) drawFrame; +- (void) padTime:(NSTimeInterval)timePad; //save states - (BOOL)saveState:(NSString*)file; - (BOOL)loadState:(NSString*)file; -- (BOOL)saveStateToSlot:(int)slot; //0 to MAX_SLOTS-1, anything else is ignored -- (BOOL)loadStateFromSlot:(int)slot; -- (BOOL)saveStateExists:(int)slot; -//layers -- (void)toggleTopBackground0; -- (BOOL)showingTopBackground0; -- (void)toggleTopBackground1; -- (BOOL)showingTopBackground1; -- (void)toggleTopBackground2; -- (BOOL)showingTopBackground2; -- (void)toggleTopBackground3; -- (BOOL)showingTopBackground3; -- (void)toggleSubBackground0; -- (BOOL)showingSubBackground0; -- (void)toggleSubBackground1; -- (BOOL)showingSubBackground1; -- (void)toggleSubBackground2; -- (BOOL)showingSubBackground2; -- (void)toggleSubBackground3; -- (BOOL)showingSubBackground3; +- (BOOL) isSubScreenLayerDisplayed:(int)i; +- (BOOL) isMainScreenLayerDisplayed:(int)i; +- (void) toggleMainScreenLayer:(int)i; +- (void) toggleSubScreenLayer:(int)i; //Sound - (BOOL)hasSound; diff --git a/desmume/src/cocoa/nds_control.mm b/desmume/src/cocoa/nds_control.mm index 8e848d405..bf7728718 100644 --- a/desmume/src/cocoa/nds_control.mm +++ b/desmume/src/cocoa/nds_control.mm @@ -20,6 +20,7 @@ #import "nds_control.h" #import "preferences.h" #import "screen_state.h" +#import "main_window.h" #ifdef DESMUME_COCOA #import "sndOSX.h" @@ -31,7 +32,6 @@ #endif //DeSmuME general includes -#define OBJ_C #include "../NDSSystem.h" #include "../saves.h" #include "../render3D.h" @@ -50,7 +50,7 @@ bool timer_based; #define DS_MICROSECONDS_PER_FRAME (1.0 / 59.8) * 1000000.0 //accessed from other files -volatile desmume_BOOL execute = true; +volatile bool execute = true; GPU3DInterface *core3DList[] = { &gpu3DNull, @@ -61,6 +61,13 @@ GPU3DInterface *core3DList[] = { NULL }; +enum +{ + CORE3DLIST_NULL = 0, + CORE3DLIST_RASTERIZE, + CORE3DLIST_OPENGL +}; + SoundInterface_struct *SNDCoreList[] = { &SNDDummy, #ifdef DESMUME_COCOA @@ -69,15 +76,27 @@ SoundInterface_struct *SNDCoreList[] = { NULL }; -struct NDS_fw_config_data firmware; +struct NDS_fw_config_data macDS_firmware; bool opengl_init() { return true; } +@implementation CocoaDSStateBuffer + +- (id) init +{ + frame_skip = -1; //default to auto frame skip + speed_limit = 100; //default to max speed = normal speed + + return self; +} + +@end + @implementation NintendoDS -- (id)init; +- (id)init { // self = [super init]; @@ -87,6 +106,7 @@ bool opengl_init() error_object = nil; frame_skip = -1; //default to auto frame skip speed_limit = 100; //default to max speed = normal speed + calcTimeBudget = (NSTimeInterval)(DS_SECONDS_PER_FRAME / ((float)speed_limit / 100.0)); gui_thread = [NSThread currentThread]; current_file = nil; flash_file = nil; @@ -161,8 +181,8 @@ bool opengl_init() #endif //use default firmware - NDS_FillDefaultFirmwareConfigData(&firmware); - NDS_CreateDummyFirmware(&firmware); + NDS_FillDefaultFirmwareConfigData(&macDS_firmware); + NDS_CreateDummyFirmware(&macDS_firmware); /* * Activate the GDB stubs @@ -256,7 +276,7 @@ bool opengl_init() [context makeCurrentContext]; oglrender_init = &opengl_init; - NDS_3D_SetDriver(1); + NDS_3D_SetDriver(CORE3DLIST_RASTERIZE); if(!gpu3D->NDS_3D_Init()) messageDialog(NSLocalizedString(@"Error", nil), @"Unable to initialize OpenGL components"); } @@ -290,8 +310,11 @@ bool opengl_init() if(timer_based) { video_update_lock = [[NSLock alloc] init]; - [NSTimer scheduledTimerWithTimeInterval:1.0f/60.0f target:self selector:@selector(videoUpdateTimerHelper) userInfo:nil repeats:YES]; + [NSTimer scheduledTimerWithTimeInterval:DS_SECONDS_PER_FRAME target:self selector:@selector(videoUpdateTimerHelper) userInfo:nil repeats:YES]; } + + dsStateBuffer = [[CocoaDSStateBuffer alloc] init]; + dsController = [[CocoaDSController alloc] init]; return self; } @@ -324,7 +347,10 @@ bool opengl_init() //end the other thread finish = true; while(!finished){} - + + [dsStateBuffer release]; + [dsController release]; + [display_object release]; [error_object release]; [context release]; @@ -350,18 +376,23 @@ bool opengl_init() [super dealloc]; } +- (CocoaDSController*) getDSController +{ + return dsController; +} + - (void)setPlayerName:(NSString*)player_name { //first we convert to UTF-16 which the DS uses to store the nickname NSData *string_chars = [player_name dataUsingEncoding:NSUnicodeStringEncoding]; //copy the bytes - firmware.nickname_len = MIN([string_chars length],MAX_FW_NICKNAME_LENGTH); - [string_chars getBytes:firmware.nickname length:firmware.nickname_len]; - firmware.nickname[firmware.nickname_len / 2] = 0; + macDS_firmware.nickname_len = MIN([string_chars length],MAX_FW_NICKNAME_LENGTH); + [string_chars getBytes:macDS_firmware.nickname length:macDS_firmware.nickname_len]; + macDS_firmware.nickname[macDS_firmware.nickname_len / 2] = 0; //set the firmware - //NDS_CreateDummyFirmware(&firmware); + //NDS_CreateDummyFirmware(&macDS_firmware); } - (BOOL)loadROM:(NSString*)filename @@ -604,8 +635,14 @@ bool opengl_init() - (void)setFrameSkip:(int)frameskip { - if(frameskip < 0)frame_skip = -1; - else frame_skip = frameskip; + dsStateBuffer->frame_skip = frameskip; + + if(frameskip < 0) + { + dsStateBuffer->frame_skip = -1; + } + + doesConfigNeedUpdate = true; } - (int)frameSkip @@ -615,10 +652,14 @@ bool opengl_init() - (void)setSpeedLimit:(int)speedLimit { - if(speedLimit < 0)return; - if(speedLimit > 1000)return; + if(speedLimit < 0 || speedLimit > 1000) + { + return; + } - speed_limit = speedLimit; + dsStateBuffer->speed_limit = speedLimit; + + doesConfigNeedUpdate = true; } - (int)speedLimit @@ -639,602 +680,152 @@ bool opengl_init() return CommonSettings.manualBackupType; } - -- (void)touch:(NSPoint)point -{ - NDS_setTouchPos((unsigned short)point.x, (unsigned short)point.y); -} - -- (void)releaseTouch -{ - NDS_releaseTouch(); -} - -- (void)pressStart -{ -#ifndef __BIG_ENDIAN__ - ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] &= 0xFFF7; - ((u16 *)MMU.ARM7_REG)[0x130>>1] &= 0xFFF7; -#else - ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] &= 0xF7FF; - ((u16 *)MMU.ARM7_REG)[0x130>>1] &= 0xF7FF; -#endif -} - -- (void)liftStart -{ -#ifndef __BIG_ENDIAN__ - ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] |= 0x0008; - ((u16 *)MMU.ARM7_REG)[0x130>>1] |= 0x0008; -#else - ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] |= 0x0800; - ((u16 *)MMU.ARM7_REG)[0x130>>1] |= 0x0800; -#endif -} - -- (BOOL)start -{ -#ifndef __BIG_ENDIAN__ - if((((u16 *)MMU.ARM7_REG)[0x130>>1] & 0x0008) == 0) -#else - if((((u16 *)MMU.ARM7_REG)[0x130>>1] & 0x0800) == 0) -#endif - return YES; - return NO; -} - -- (void)pressSelect -{ -#ifndef __BIG_ENDIAN__ - ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] &= 0xFFFB; - ((u16 *)MMU.ARM7_REG)[0x130>>1] &= 0xFFFB; -#else - ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] &= 0xFBFF; - ((u16 *)MMU.ARM7_REG)[0x130>>1] &= 0xFBFF; -#endif -} - -- (void)liftSelect -{ -#ifndef __BIG_ENDIAN__ - ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] |= 0x0004; - ((u16 *)MMU.ARM7_REG)[0x130>>1] |= 0x0004; -#else - ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] |= 0x0400; - ((u16 *)MMU.ARM7_REG)[0x130>>1] |= 0x0400; -#endif -} - -- (BOOL)select -{ -#ifndef __BIG_ENDIAN__ - if((((u16 *)MMU.ARM7_REG)[0x130>>1] & 0x0004) == 0) -#else - if((((u16 *)MMU.ARM7_REG)[0x130>>1] & 0x0400) == 0) -#endif - return YES; - return NO; -} - -- (void)pressLeft -{ -#ifndef __BIG_ENDIAN__ - ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] &= 0xFFDF; - ((u16 *)MMU.ARM7_REG)[0x130>>1] &= 0xFFDF; -#else - ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] &= 0xDFFF; - ((u16 *)MMU.ARM7_REG)[0x130>>1] &= 0xDFFF; -#endif -} - -- (void)liftLeft -{ -#ifndef __BIG_ENDIAN__ - ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] |= 0x0020; - ((u16 *)MMU.ARM7_REG)[0x130>>1] |= 0x0020; -#else - ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] |= 0x2000; - ((u16 *)MMU.ARM7_REG)[0x130>>1] |= 0x2000; -#endif -} - -- (BOOL)left -{ -#ifndef __BIG_ENDIAN__ - if((((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] & 0x0020) == 0) -#else - if((((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] & 0x2000) == 0) -#endif - return YES; - return NO; -} - -- (void)pressRight -{ -#ifndef __BIG_ENDIAN__ - ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] &= 0xFFEF; - ((u16 *)MMU.ARM7_REG)[0x130>>1] &= 0xFFEF; -#else - ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] &= 0xEFFF; - ((u16 *)MMU.ARM7_REG)[0x130>>1] &= 0xEFFF; -#endif -} - -- (void)liftRight -{ -#ifndef __BIG_ENDIAN__ - ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] |= 0x0010; - ((u16 *)MMU.ARM7_REG)[0x130>>1] |= 0x0010; -#else - ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] |= 0x1000; - ((u16 *)MMU.ARM7_REG)[0x130>>1] |= 0x1000; -#endif -} - -- (BOOL)right -{ -#ifndef __BIG_ENDIAN__ - if((((u16*)ARM9Mem.ARM9_REG)[0x130>>1] & 0x0010) == 0) -#else - if((((u16*)ARM9Mem.ARM9_REG)[0x130>>1] & 0x1000) == 0) -#endif - return YES; - return NO; -} - -- (void)pressUp -{ -#ifndef __BIG_ENDIAN__ - ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] &= 0xFFBF; - ((u16 *)MMU.ARM7_REG)[0x130>>1] &= 0xFFBF; -#else - ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] &= 0xBFFF; - ((u16 *)MMU.ARM7_REG)[0x130>>1] &= 0xBFFF; -#endif -} - -- (void)liftUp -{ -#ifndef __BIG_ENDIAN__ - ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] |= 0x0040; - ((u16 *)MMU.ARM7_REG)[0x130>>1] |= 0x0040; -#else - ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] |= 0x4000; - ((u16 *)MMU.ARM7_REG)[0x130>>1] |= 0x4000; -#endif -} - -- (BOOL)up -{ -#ifndef __BIG_ENDIAN__ - if((((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] & 0x0040) == 0) -#else - if((((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] & 0x4000) == 0) -#endif - return YES; - return NO; -} - -- (void)pressDown -{ -#ifndef __BIG_ENDIAN__ - ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] &= 0xFF7F; - ((u16 *)MMU.ARM7_REG)[0x130>>1] &= 0xFF7F; -#else - ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] &= 0x7FFF; - ((u16 *)MMU.ARM7_REG)[0x130>>1] &= 0x7FFF; -#endif -} - -- (void)liftDown -{ -#ifndef __BIG_ENDIAN__ - ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] |= 0x0080; - ((u16 *)MMU.ARM7_REG)[0x130>>1] |= 0x0080; -#else - ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] |= 0x8000; - ((u16 *)MMU.ARM7_REG)[0x130>>1] |= 0x8000; -#endif -} - -- (BOOL)down -{ -#ifndef __BIG_ENDIAN__ - if((((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] & 0x0080) == 0) -#else - if((((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] & 0x8000) == 0) -#endif - return YES; - return NO; -} - -- (void)pressA -{ -#ifndef __BIG_ENDIAN__ - ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] &= 0xFFFE; - ((u16 *)MMU.ARM7_REG)[0x130>>1] &= 0xFFFE; -#else - ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] &= 0xFEFF; - ((u16 *)MMU.ARM7_REG)[0x130>>1] &= 0xFEFF; -#endif -} - -- (void)liftA -{ -#ifndef __BIG_ENDIAN__ - ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] |= 0x0001; - ((u16 *)MMU.ARM7_REG)[0x130>>1] |= 0x0001; -#else - ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] |= 0x0100; - ((u16 *)MMU.ARM7_REG)[0x130>>1] |= 0x0100; -#endif -} - -- (BOOL)A -{ -#ifndef __BIG_ENDIAN__ - if((((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] & 0x0001) == 0) -#else - if((((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] & 0x0100) == 0) -#endif - return YES; - return NO; -} - -- (void)pressB -{ -#ifndef __BIG_ENDIAN__ - ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] &= 0xFFFD; - ((u16 *)MMU.ARM7_REG)[0x130>>1] &= 0xFFFD; -#else - ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] &= 0xFDFF; - ((u16 *)MMU.ARM7_REG)[0x130>>1] &= 0xFDFF; -#endif -} - -- (void)liftB -{ -#ifndef __BIG_ENDIAN__ - ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] |= 0x0002; - ((u16 *)MMU.ARM7_REG)[0x130>>1] |= 0x0002; -#else - ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] |= 0x0200; - ((u16 *)MMU.ARM7_REG)[0x130>>1] |= 0x0200; -#endif -} - -- (BOOL)B -{ -#ifndef __BIG_ENDIAN__ - if((((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] & 0x0002) == 0) -#else - if((((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] & 0x0200) == 0) -#endif - return YES; - return NO; -} - -- (void)pressX -{ -#ifndef __BIG_ENDIAN__ - ((u16 *)MMU.ARM7_REG)[0x136>>1] &= 0xFFFE; -#else - ((u16 *)MMU.ARM7_REG)[0x136>>1] &= 0xFEFF; -#endif -} - -- (void)liftX -{ -#ifndef __BIG_ENDIAN__ - ((u16 *)MMU.ARM7_REG)[0x136>>1] |= 0x0001; -#else - ((u16 *)MMU.ARM7_REG)[0x136>>1] |= 0x0100; -#endif -} - -- (BOOL)X -{ -#ifndef __BIG_ENDIAN__ - if((((u16 *)MMU.ARM7_REG)[0x136>>1] & 0x0001) == 0) - if((((u16 *)MMU.ARM7_REG)[0x136>>1] & 0x0001) == 0) -#else - if((((u16 *)MMU.ARM7_REG)[0x136>>1] & 0x0100) == 0) - if((((u16 *)MMU.ARM7_REG)[0x136>>1] & 0x0100) == 0) -#endif - return YES; - return NO; -} - -- (void)pressY -{ -#ifndef __BIG_ENDIAN__ - ((u16 *)MMU.ARM7_REG)[0x136>>1] &= 0xFFFD; -#else - ((u16 *)MMU.ARM7_REG)[0x136>>1] &= 0xFDFF; -#endif -} - -- (void)liftY -{ -#ifndef __BIG_ENDIAN__ - ((u16 *)MMU.ARM7_REG)[0x136>>1] |= 0x0002; -#else - ((u16 *)MMU.ARM7_REG)[0x136>>1] |= 0x0200; -#endif -} - -- (BOOL)Y -{ -#ifndef __BIG_ENDIAN__ - if((((u16 *)MMU.ARM7_REG)[0x136>>1] & 0x0002) == 0) - if((((u16 *)MMU.ARM7_REG)[0x136>>1] & 0x0002) == 0) -#else - if((((u16 *)MMU.ARM7_REG)[0x136>>1] & 0x0200) == 0) - if((((u16 *)MMU.ARM7_REG)[0x136>>1] & 0x0200) == 0) -#endif - return YES; - return NO; -} - -- (void)pressL -{ -#ifndef __BIG_ENDIAN__ - ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] &= 0xFDFF; - ((u16 *)MMU.ARM7_REG)[0x130>>1] &= 0xFDFF; -#else - ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] &= 0xFFFD; - ((u16 *)MMU.ARM7_REG)[0x130>>1] &= 0xFFFD; -#endif -} - -- (void)liftL -{ -#ifndef __BIG_ENDIAN__ - ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] |= 0x0200; - ((u16 *)MMU.ARM7_REG)[0x130>>1] |= 0x0200; -#else - ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] |= 0x0002; - ((u16 *)MMU.ARM7_REG)[0x130>>1] |= 0x0002; -#endif -} - -- (BOOL)L -{ -#ifndef __BIG_ENDIAN__ - if((((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] & 0x0200) == 0) -#else - if((((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] & 0x0002) == 0) -#endif - return YES; - return NO; -} - -- (void)pressR -{ -#ifndef __BIG_ENDIAN__ - ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] &= 0xFEFF; - ((u16 *)MMU.ARM7_REG)[0x130>>1] &= 0xFEFF; -#else - ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] &= 0xFFFE; - ((u16 *)MMU.ARM7_REG)[0x130>>1] &= 0xFFFE; -#endif -} - -- (void)liftR -{ -#ifndef __BIG_ENDIAN__ - ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] |= 0x0100; - ((u16 *)MMU.ARM7_REG)[0x130>>1] |= 0x0100; -#else - ((u16 *)ARM9Mem.ARM9_REG)[0x130>>1] |= 0x0001; - ((u16 *)MMU.ARM7_REG)[0x130>>1] |= 0x0001; -#endif -} - -- (BOOL)R -{ -#ifndef __BIG_ENDIAN__ - if((((u16 *)MMU.ARM7_REG)[0x130>>1] & 0x0100) == 0) -#else - if((((u16 *)MMU.ARM7_REG)[0x130>>1] & 0x0001) == 0) -#endif - return YES; - return NO; -} - - (BOOL)saveState:(NSString*)file { [execution_lock lock]; - + BOOL result = NO; if(savestate_save([file cStringUsingEncoding:NSUTF8StringEncoding])) result = YES; - + [execution_lock unlock]; - + return result; } - (BOOL)loadState:(NSString*)file { [execution_lock lock]; - + //Set the GPU context (if it exists) incase the core needs to load anything into opengl during state load NSOpenGLContext *prev_context = [NSOpenGLContext currentContext]; [prev_context retain]; [context makeCurrentContext]; - + BOOL result = NO; if(savestate_load([file cStringUsingEncoding:NSUTF8StringEncoding])) result = YES; - + [execution_lock unlock]; - + if(prev_context != nil) { [prev_context makeCurrentContext]; [prev_context release]; } else [NSOpenGLContext clearCurrentContext]; - + return result; } -- (BOOL)saveStateToSlot:(int)slot +- (BOOL) isSubScreenLayerDisplayed:(int)i { - if(slot >= MAX_SLOTS)return NO; - if(slot < 0)return NO; - - [execution_lock lock]; - - BOOL result = NO; - - savestate_slot(slot + 1);//no execption handling? - result = YES; - - [execution_lock unlock]; - - return result; -} - -- (BOOL)loadStateFromSlot:(int)slot -{ - if(slot >= MAX_SLOTS)return NO; - if(slot < 0)return NO; - - BOOL result = NO; - [execution_lock lock]; - - //Set the GPU context (if it exists) incase the core needs to load anything into opengl during state load - NSOpenGLContext *prev_context = [NSOpenGLContext currentContext]; - [prev_context retain]; - [context makeCurrentContext]; - - loadstate_slot(slot + 1); //no exection handling? - result = YES; - - [execution_lock unlock]; - - if(prev_context != nil) + GPU *theGPU = SubScreen.gpu; + BOOL isLayerDisplayed = NO; + + // Check bounds on the layer index. + if(i < 0 || i > 4) { - [prev_context makeCurrentContext]; - [prev_context release]; - } else - [NSOpenGLContext clearCurrentContext]; - - return result; + return isLayerDisplayed; + } + + // Check if theGPU exists. + if(theGPU == nil) + { + return isLayerDisplayed; + } + + // CommonSettings.dispLayers is returned as a bool, so we convert + // to BOOL here. + if (CommonSettings.dispLayers[theGPU->core][i]) + { + isLayerDisplayed = YES; + } + + return isLayerDisplayed; } -- (BOOL)saveStateExists:(int)slot +- (BOOL) isMainScreenLayerDisplayed:(int)i { - scan_savestates(); - if(savestates[slot].exists) - return YES; - return NO; + GPU *theGPU = MainScreen.gpu; + BOOL isLayerDisplayed = NO; + + // Check bounds on the layer index. + if(i < 0 || i > 4) + { + return isLayerDisplayed; + } + + // Check if theGPU exists. + if(theGPU == nil) + { + return isLayerDisplayed; + } + + // CommonSettings.dispLayers is returned as a bool, so we convert + // to BOOL here. + if (CommonSettings.dispLayers[theGPU->core][i]) + { + isLayerDisplayed = YES; + } + + return isLayerDisplayed; } -- (void)toggleTopBackground0 +- (void) toggleSubScreenLayer:(int)i { - if(SubScreen.gpu->dispBG[0]) - GPU_remove(SubScreen.gpu, 0); + GPU *theGPU = SubScreen.gpu; + BOOL isLayerDisplayed; + + // Check bounds on the layer index. + if(i < 0 || i > 4) + { + return; + } + + // Check if theGPU exists. + if(theGPU == nil) + { + return; + } + + isLayerDisplayed = [self isSubScreenLayerDisplayed:i]; + if(isLayerDisplayed == YES) + { + GPU_remove(theGPU, i); + } else - GPU_addBack(SubScreen.gpu, 0); + { + GPU_addBack(theGPU, i); + } } -- (BOOL)showingTopBackground0 +- (void) toggleMainScreenLayer:(int)i { - return SubScreen.gpu->dispBG[0]; -} - -- (void)toggleTopBackground1 -{ - if(SubScreen.gpu->dispBG[1]) - GPU_remove(SubScreen.gpu, 1); + GPU *theGPU = MainScreen.gpu; + BOOL isLayerDisplayed; + + // Check bounds on the layer index. + if(i < 0 || i > 4) + { + return; + } + + // Check if theGPU exists. + if(theGPU == nil) + { + return; + } + + isLayerDisplayed = [self isMainScreenLayerDisplayed:i]; + if(isLayerDisplayed == YES) + { + GPU_remove(theGPU, i); + } else - GPU_addBack(SubScreen.gpu, 1); -} - -- (BOOL)showingTopBackground1 -{ - return SubScreen.gpu->dispBG[1]; -} - -- (void)toggleTopBackground2 -{ - if(SubScreen.gpu->dispBG[2]) - GPU_remove(SubScreen.gpu, 2); - else - GPU_addBack(SubScreen.gpu, 2); -} - -- (BOOL)showingTopBackground2 -{ - return SubScreen.gpu->dispBG[2]; -} - -- (void)toggleTopBackground3 -{ - if(SubScreen.gpu->dispBG[3]) - GPU_remove(SubScreen.gpu, 3); - else - GPU_addBack(SubScreen.gpu, 3); -} - -- (BOOL)showingTopBackground3 -{ - return SubScreen.gpu->dispBG[3]; -} - -- (void)toggleSubBackground0 -{ - if(MainScreen.gpu->dispBG[0]) - GPU_remove(MainScreen.gpu, 0); - else - GPU_addBack(MainScreen.gpu, 0); -} - -- (BOOL)showingSubBackground0 -{ - return MainScreen.gpu->dispBG[0]; -} - -- (void)toggleSubBackground1 -{ - if(MainScreen.gpu->dispBG[1]) - GPU_remove(MainScreen.gpu, 1); - else - GPU_addBack(MainScreen.gpu, 1); -} - -- (BOOL)showingSubBackground1 -{ - return MainScreen.gpu->dispBG[1]; -} - -- (void)toggleSubBackground2 -{ - if(MainScreen.gpu->dispBG[2]) - GPU_remove(MainScreen.gpu, 2); - else - GPU_addBack(MainScreen.gpu, 2); -} - -- (BOOL)showingSubBackground2 -{ - return MainScreen.gpu->dispBG[2]; -} - -- (void)toggleSubBackground3 -{ - if(MainScreen.gpu->dispBG[3]) - GPU_remove(MainScreen.gpu, 3); - else - GPU_addBack(MainScreen.gpu, 3); -} - -- (BOOL)showingSubBackground3 -{ - return MainScreen.gpu->dispBG[3]; + { + GPU_addBack(theGPU, i); + } } - (BOOL)hasSound @@ -1333,114 +924,217 @@ bool opengl_init() - (void)run:(NSOpenGLContext*)gl_context { NSAutoreleasePool *autorelease = [[NSAutoreleasePool alloc] init]; - + + NSDate *loopStartDate; + NSDate *emulation_start_date; + NSDate *frame_start_date; + + NSTimeInterval timeBudget; + NSTimeInterval timePad; + #ifdef HAVE_OPENGL [gl_context retain]; [gl_context makeCurrentContext]; CGLLockContext((CGLContextObj)[gl_context CGLContextObj]); #endif - - NSDate *frame_start_date, *frame_end_date, *ideal_frame_end_date; - - int frames_to_skip = 0; - + //program main loop while(!finish) { - if(!run)paused = true; - + if(!run) + { + paused = true; + } + //run the emulator while(run && execute) //run controls when the emulator runs, execute prevents it from continuing execution if there are errors { - - paused = false; - - int speed_limit_this_frame = speed_limit; //dont let speed limit change midframe - if(speed_limit_this_frame)ideal_frame_end_date = [NSDate dateWithTimeIntervalSinceNow: DS_SECONDS_PER_FRAME / ((float)speed_limit_this_frame / 100.0)]; - - frame_start_date = [NSDate dateWithTimeIntervalSinceNow:0]; - - [execution_lock lock]; - - NDS_exec(); - - [sound_lock lock]; - int x; - for(x = 0; x <= frames_to_skip; x++) + /* + Get the start time for the loop. This will be needed when it comes + time to determine the total time spent, and then calculating what + timePad should be. + */ + loopStartDate = [NSDate date]; + + /* + Some controls may affect how the loop runs. + + Instead of checking and modifying the NDS config every time through + the loop, only change the config on an as-needed basis. + */ + if(doesConfigNeedUpdate == true) { - SPU_Emulate_user(); - SPU_Emulate_core(); + [self updateConfig]; + doesConfigNeedUpdate = false; + } + + // Force paused state. + paused = false; + + /* + Set up our time budget, which is equal to calcTimeBudget, which + is the relationship between DS_SECONDS_PER_FRAME and speed_limit. + timeBudget represents how much time we have to spend doing the + various functions of making a new frame. + + The major parts we spend our time on is: + - Emulation + - Drawing the frame + - Pad time + + The priorities for spending time are the same as the order listed + above. + + timePad represents any excess time that can be released back + to the OS. + */ + timeBudget = calcTimeBudget; + timePad = timeBudget; + + /* + Set up the inputs for the emulator. + + The time taken up by this step should be insignificant, so we + won't bother calculating this in the time budget. + */ + [dsController setupAllDSInputs]; + NDS_beginProcessingInput(); + /* + Shouldn't need to do any special processing steps in between. + We'll just jump directly to ending the input processing. + */ + NDS_endProcessingInput(); + + emulation_start_date = [NSDate date]; + [self emulateDS]; + + /* + Subtract the emulation time from our time budget. + + For some reason, [NSDate timeIntervalSinceNow] returns a + negative interval if the receiver is an earlier date than now. + So to subtract from timeBudget, we add the interval. + + Go figure. + */ + timeBudget += [emulation_start_date timeIntervalSinceNow]; + + /* + If we have time left in our time budget, draw the frame. + + But if we don't have time left in our time budget, then we need + to make a decision on whether to simply drop the frame, or just + draw the frame. + + Currently, the decision is to just draw everything because + frame drawing time is very negligible. Dropping a whole bunch of + frames will NOT yield any significant speed increase. + */ + if(timeBudget > 0) + { + frame_start_date = [NSDate date]; + [self drawFrame]; + + // Subtract the drawing time from our time budget. + timeBudget += [frame_start_date timeIntervalSinceNow]; } - [sound_lock unlock]; - - [execution_lock unlock]; - - frame_end_date = [NSDate dateWithTimeIntervalSinceNow:0]; - - //speed limit - if(speed_limit_this_frame) - [NSThread sleepUntilDate:ideal_frame_end_date]; - - if(frames_to_skip > 0) - frames_to_skip--; - else { - 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 = [frame_end_date timeIntervalSinceDate:frame_start_date] / (float)DS_SECONDS_PER_FRAME; - if(frames_to_skip > 10)frames_to_skip = 10; - - } else - { - - frames_to_skip = frame_skip; - - } - - //update the screen - ScreenState *new_screen_data = [[ScreenState alloc] initWithColorData:GPU_screen]; - - if(timer_based) - { //for tiger compatibility - [video_update_lock lock]; - [current_screen release]; - current_screen = new_screen_data; - [video_update_lock unlock]; - } else - { //for leopard and later - - //this will generate a warning when compiling on tiger or earlier, but it should - //be ok since the purpose of the if statement is to check if this will work - [self performSelector:@selector(videoUpdateHelper:) onThread:gui_thread withObject:new_screen_data waitUntilDone:NO]; - [new_screen_data release]; //performSelector will auto retain the screen data while the other thread displays - } + // Don't even bother calculating timeBudget. We've already + // gone over at this point. + [self drawFrame]; + } + + // If there is any time left in the loop, go ahead and pad it. + timePad += [loopStartDate timeIntervalSinceNow]; + if(timePad > 0) + { + [self padTime:timePad]; } - - //execute is set to false sometimes by the emulation core - //when there is an error, if this happens notify the other thread that emulation has stopped. - if(!execute) - if(!timer_based) //wont display an error on tiger or earlier - [error_object performSelector:error_func onThread:gui_thread withObject:nil waitUntilDone:YES]; - } - + //when emulation is paused, return CPU time to the OS [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:.1]]; } - + #ifdef HAVE_OPENGL CGLUnlockContext((CGLContextObj)[gl_context CGLContextObj]); [gl_context release]; #endif - + [autorelease release]; - + paused = true; finished = true; } +- (void) emulateDS +{ + [execution_lock lock]; + + NDS_exec(); + + [sound_lock lock]; + + SPU_Emulate_user(); + + [sound_lock unlock]; + + [execution_lock unlock]; +} + +- (void) drawFrame +{ + ScreenState *new_screen_data = [[ScreenState alloc] initWithColorData:GPU_screen]; + + if(timer_based) + { //for tiger compatibility + [video_update_lock lock]; + [current_screen release]; + current_screen = new_screen_data; + [video_update_lock unlock]; + } + else + { //for leopard and later + + //this will generate a warning when compiling on tiger or earlier, but it should + //be ok since the purpose of the if statement is to check if this will work + [self performSelector:@selector(videoUpdateHelper:) onThread:gui_thread withObject:new_screen_data waitUntilDone:NO]; + [new_screen_data release]; //performSelector will auto retain the screen data while the other thread displays + } +} + +- (void) padTime:(NSTimeInterval)timePad +{ +#if (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4) // Code for Mac OS X 10.4 and earlier + + [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:timePad]]; + +#else // Code for Mac OS X 10.5 and later + + [NSThread sleepForTimeInterval:timePad]; + +#endif +} + +- (void) updateConfig +{ + // Update the Nintendo DS config + frame_skip = dsStateBuffer->frame_skip; + speed_limit = dsStateBuffer->speed_limit; + + if(speed_limit <= 0) + { + calcTimeBudget = 0; + } + else if(speed_limit > 0 && speed_limit < 1000) + { + calcTimeBudget = (NSTimeInterval)(DS_SECONDS_PER_FRAME / ((float)speed_limit / 100.0)); + } + else + { + calcTimeBudget = (NSTimeInterval)(DS_SECONDS_PER_FRAME / ((float)1000.0 / 100.0)); + } +} + @end diff --git a/desmume/src/cocoa/sndOSX.h b/desmume/src/cocoa/sndOSX.h index 432175347..ac1a207fe 100644 --- a/desmume/src/cocoa/sndOSX.h +++ b/desmume/src/cocoa/sndOSX.h @@ -17,9 +17,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#define OBJ_C #include "../SPU.h" -#undef OBJ_C #ifdef __cplusplus extern "C" diff --git a/desmume/src/cocoa/sndOSX.mm b/desmume/src/cocoa/sndOSX.mm index 43beb47a9..e81ef0779 100644 --- a/desmume/src/cocoa/sndOSX.mm +++ b/desmume/src/cocoa/sndOSX.mm @@ -29,9 +29,7 @@ #include //desmume includes -#define OBJ_C #include "sndOSX.h" -#undef BOOL //globals AudioUnit output_unit = NULL; //pointer to our audio device