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