Cocoa Port (OpenEmu Plug-in): Remove [OEGameCore changeDisplayMode] deprecation in favor of the latest display mode API. (Related to commit 452c3340.)

- Also sets things up for adding new display modes in the future.
This commit is contained in:
rogerman 2022-04-22 04:03:43 -07:00
parent 452c33405c
commit cd0cc31505
3 changed files with 465 additions and 69 deletions

View File

@ -2,6 +2,8 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSMicrophoneUsageDescription</key>
<string>DeSmuME requires your host microphone to emulate the NDS microphone.</string>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
@ -27,7 +29,7 @@
<key>CSResourcesFileMapped</key>
<string>yes</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2012-2017 DeSmuME Team. All rights reserved.</string>
<string>Copyright © 2012-2022 DeSmuME Team. All rights reserved.</string>
<key>NSPrincipalClass</key>
<string>OEGameCoreController</string>
<key>OEGameCoreClass</key>
@ -38,6 +40,8 @@
<dict>
<key>OEGameCoreSupportsCheatCode</key>
<true/>
<key>OEGameCoreSupportsDisplayModeChange</key>
<true/>
</dict>
</dict>
<key>OEGameCorePlayerCount</key>

View File

@ -26,29 +26,162 @@
@class CocoaDSController;
@class CocoaDSGPU;
@class CocoaDSFirmware;
// NDS Display Mode Keys for OpenEmu Display Mode Options
//
// Things to be aware of in OpenEmu's API:
// 1. All options are searched with a single OEGameCoreDisplayModeNameKey, and therefore must be unique.
// 2. Because all options are searched with a single OEGameCoreDisplayModeNameKey, the search list best
// takes the form of a 1-dimensional list (no nested stuff).
// 2. OEGameCoreDisplayModeNameKey is also used for the presented name in the "Display Modes" GUI menu.
// This implies that all presented menu item names are forced to be unique.
// 3. The actual generated menu uses an NSArray of NSDictionary objects, in which the position of the
// menu items is dependent on the order of the NSDictionary objects in the NSArray.
#define NDSDISPLAYMODE_NAMEKEY_MODE_DUALSCREEN "Dual Screen"
#define NDSDISPLAYMODE_NAMEKEY_MODE_MAIN "Main"
#define NDSDISPLAYMODE_NAMEKEY_MODE_TOUCH "Touch"
#define NDSDISPLAYMODE_NAMEKEY_LAYOUT_VERTICAL "Vertical"
#define NDSDISPLAYMODE_NAMEKEY_LAYOUT_HORIZONTAL "Horizontal"
#define NDSDISPLAYMODE_NAMEKEY_LAYOUT_HYBRID_2_1 "Hybrid (2:1)"
#define NDSDISPLAYMODE_NAMEKEY_LAYOUT_HYBRID_16_9 "Hybrid (16:9)"
#define NDSDISPLAYMODE_NAMEKEY_LAYOUT_HYBRID_16_10 "Hybrid (16:10)"
#define NDSDISPLAYMODE_NAMEKEY_DISPLAYORDER_MAIN "Main First"
#define NDSDISPLAYMODE_NAMEKEY_DISPLAYORDER_TOUCH "Touch First"
#define NDSDISPLAYMODE_NAMEKEY_ROTATION_0 "0°"
#define NDSDISPLAYMODE_NAMEKEY_ROTATION_90 "90°"
#define NDSDISPLAYMODE_NAMEKEY_ROTATION_180 "180°"
#define NDSDISPLAYMODE_NAMEKEY_ROTATION_270 "270°"
#define NDSDISPLAYMODE_NAMEKEY_SEPARATION_0 "0%"
#define NDSDISPLAYMODE_NAMEKEY_SEPARATION_50 "50%"
#define NDSDISPLAYMODE_NAMEKEY_SEPARATION_100 "100%"
#define NDSDISPLAYMODE_NAMEKEY_SEPARATION_150 "150%"
#define NDSDISPLAYMODE_NAMEKEY_SEPARATION_200 "200%"
#define NDSDISPLAYMODE_NAMEKEY_VIDEOSOURCEMAIN_NONE "Main Display - None"
#define NDSDISPLAYMODE_NAMEKEY_VIDEOSOURCEMAIN_NDS "Main Display - Let NDS Decide"
#define NDSDISPLAYMODE_NAMEKEY_VIDEOSOURCEMAIN_FORCEMAIN "Main Display - Force Main Engine"
#define NDSDISPLAYMODE_NAMEKEY_VIDEOSOURCEMAIN_FORCETOUCH "Main Display - Force Touch Engine"
#define NDSDISPLAYMODE_NAMEKEY_VIDEOSOURCETOUCH_NONE "Touch Display - None"
#define NDSDISPLAYMODE_NAMEKEY_VIDEOSOURCETOUCH_NDS "Touch Display - Let NDS Decide"
#define NDSDISPLAYMODE_NAMEKEY_VIDEOSOURCETOUCH_FORCEMAIN "Touch Display - Force Main Engine"
#define NDSDISPLAYMODE_NAMEKEY_VIDEOSOURCETOUCH_FORCETOUCH "Touch Display - Force Touch Engine"
#define NDSDISPLAYMODE_PREFKEY_DISPLAYMODE "displayMode"
#define NDSDISPLAYMODE_PREFKEY_LAYOUT "layout"
#define NDSDISPLAYMODE_PREFKEY_ORDER "dualOrder"
#define NDSDISPLAYMODE_PREFKEY_ROTATION "rotation"
#define NDSDISPLAYMODE_PREFKEY_SEPARATION "gap"
#define NDSDISPLAYMODE_PREFKEY_VIDEOSOURCE_MAIN "videosource_main"
#define NDSDISPLAYMODE_PREFKEY_VIDEOSOURCE_TOUCH "videosource_touch"
// These IDs are used to maintain the data associations for all of
// the display mode menu items.
enum NDSDisplayOptionID
{
NDSDisplayOptionID_Mode_DualScreen = 0,
NDSDisplayOptionID_Mode_Main,
NDSDisplayOptionID_Mode_Touch,
NDSDisplayOptionID_Rotation_0,
NDSDisplayOptionID_Rotation_90,
NDSDisplayOptionID_Rotation_180,
NDSDisplayOptionID_Rotation_270,
NDSDisplayOptionID_Layout_Vertical,
NDSDisplayOptionID_Layout_Horizontal,
NDSDisplayOptionID_Layout_Hybrid_2_1,
NDSDisplayOptionID_Layout_Hybrid_16_9,
NDSDisplayOptionID_Layout_Hybrid_16_10,
NDSDisplayOptionID_Order_MainFirst,
NDSDisplayOptionID_Order_TouchFirst,
NDSDisplayOptionID_Separation_0,
NDSDisplayOptionID_Separation_50,
NDSDisplayOptionID_Separation_100,
NDSDisplayOptionID_Separation_150,
NDSDisplayOptionID_Separation_200,
NDSDisplayOptionID_VideoSourceMain_None,
NDSDisplayOptionID_VideoSourceMain_NDS,
NDSDisplayOptionID_VideoSourceMain_ForceMain,
NDSDisplayOptionID_VideoSourceMain_ForceTouch,
NDSDisplayOptionID_VideoSourceTouch_None,
NDSDisplayOptionID_VideoSourceTouch_NDS,
NDSDisplayOptionID_VideoSourceTouch_ForceMain,
NDSDisplayOptionID_VideoSourceTouch_ForceTouch,
NDSDisplayOptionID_Count
};
// Used to track the bits that each option group uses, useful for clearing the
// entire group of bits prior to setting a single bit for that particular group.
enum NDSDisplayOptionStateBitmask
{
NDSDisplayOptionStateBitmask_DisplayMode = (1 << NDSDisplayOptionID_Mode_DualScreen) | (1 << NDSDisplayOptionID_Mode_Main) | (1 << NDSDisplayOptionID_Mode_Touch),
NDSDisplayOptionStateBitmask_Rotation = (1 << NDSDisplayOptionID_Rotation_0) | (1 << NDSDisplayOptionID_Rotation_90) | (1 << NDSDisplayOptionID_Rotation_180) | (1 << NDSDisplayOptionID_Rotation_270),
NDSDisplayOptionStateBitmask_Layout = (1 << NDSDisplayOptionID_Layout_Vertical) | (1 << NDSDisplayOptionID_Layout_Horizontal) | (1 << NDSDisplayOptionID_Layout_Hybrid_2_1) | (1 << NDSDisplayOptionID_Layout_Hybrid_16_9) | (1 << NDSDisplayOptionID_Layout_Hybrid_16_10),
NDSDisplayOptionStateBitmask_Order = (1 << NDSDisplayOptionID_Order_MainFirst) | (1 << NDSDisplayOptionID_Order_TouchFirst),
NDSDisplayOptionStateBitmask_Separation = (1 << NDSDisplayOptionID_Separation_0) | (1 << NDSDisplayOptionID_Separation_50) | (1 << NDSDisplayOptionID_Separation_100) | (1 << NDSDisplayOptionID_Separation_150) | (1 << NDSDisplayOptionID_Separation_200),
NDSDisplayOptionStateBitmask_VideoSourceMain = (1 << NDSDisplayOptionID_VideoSourceMain_None) | (1 << NDSDisplayOptionID_VideoSourceMain_NDS) | (1 << NDSDisplayOptionID_VideoSourceMain_ForceMain) | (1 << NDSDisplayOptionID_VideoSourceMain_ForceTouch),
NDSDisplayOptionStateBitmask_VideoSourceTouch = (1 << NDSDisplayOptionID_VideoSourceTouch_None) | (1 << NDSDisplayOptionID_VideoSourceTouch_NDS) | (1 << NDSDisplayOptionID_VideoSourceTouch_ForceMain) | (1 << NDSDisplayOptionID_VideoSourceTouch_ForceTouch)
};
// Describes the data associations for a single display mode menu item, used for generating
// the NSDictionary items that are part of the display mode menu descriptor. This struct
// represents the immutable portions of the data. The mutable parts, such as the menu item
// states, are handled elsewhere.
struct NDSDisplayMenuItem
{
NSString *nameKey;
NSString *prefKey;
};
typedef NDSDisplayMenuItem NDSDisplayMenuItem;
@interface NDSGameCore : OEGameCore
{
apple_unfairlock_t unfairlockDisplayMode;
pthread_rwlock_t rwlockCoreExecute;
NSPoint touchLocation;
NSMutableDictionary *addedCheatsDict;
CocoaDSCheatManager *cdsCheats;
CocoaDSController *cdsController;
CocoaDSGPU *cdsGPU;
CocoaDSFirmware *cdsFirmware;
NSInteger displayMode;
OEIntRect displayRect;
OEIntSize displayAspectRatio;
NSUInteger inputID[OENDSButtonCount]; // Key = OpenEmu's input ID, Value = DeSmuME's input ID
apple_unfairlock_t unfairlockDisplayMode;
pthread_rwlock_t rwlockCoreExecute;
NSUInteger inputID[OENDSButtonCount]; // Key = OpenEmu's input ID, Value = DeSmuME's input ID
OEIntRect _displayRect;
OEIntSize _displayAspectRatio;
// Records the display mode menu states on a per-bit basis. This only works because OpenEmu
// tracks only binary states for the menu items. Currently, there are 27 different states
// to keep track of, which leaves us another 37 states for future use.
uint64_t ndsDisplayMode;
// For simplicity's sake, we use NDSDisplayOptionID numbers to maintain all of the internal data
// associations for display mode menu items. However, OpenEmu uses OEGameCoreDisplayModeNameKey
// to request display mode changes. Therefore, we need to use an NSDictionary to translate
// between OEGameCoreDisplayModeNameKey and NDSDisplayOptionID.
//
// Using NSDictionary has a hidden bonus here over simply using std::map. The
// [NSDictionary objectForKey:] method will return nil if the passed in key is not present in
// the NSDictionary, which is a useful feature for key validation.
NSDictionary<NSString *, NSNumber *> *_displayModeIDFromString;
}
@property (retain) CocoaDSCheatManager *cdsCheats;
@property (retain) CocoaDSController *cdsController;
@property (retain) CocoaDSGPU *cdsGPU;
@property (retain) CocoaDSFirmware *cdsFirmware;
@property (assign) NSInteger displayMode;
@property (assign) uint64_t ndsDisplayMode;
- (NSDictionary<NSString *, id> *) generateDisplayModeItemByID:(NDSDisplayOptionID)optionID states:(const uint64_t)states;
@end

View File

@ -33,6 +33,53 @@
#include "../../GPU.h"
#undef BOOL
#define DISPLAYMODE_STATEBIT_CHECK(_STATEBITS_, _ID_) ((((_STATEBITS_) >> (_ID_)) & 1) != 0)
#define DISPLAYMODE_STATEBITGROUP_CLEAR(_STATEBITS_, _BITMASK_) _STATEBITS_ = (((_STATEBITS_) | (_BITMASK_)) ^ (_BITMASK_))
static const NDSDisplayMenuItem kDisplayModeItem[NDSDisplayOptionID_Count] = {
{ @NDSDISPLAYMODE_NAMEKEY_MODE_DUALSCREEN, @NDSDISPLAYMODE_PREFKEY_DISPLAYMODE },
{ @NDSDISPLAYMODE_NAMEKEY_MODE_MAIN, @NDSDISPLAYMODE_PREFKEY_DISPLAYMODE },
{ @NDSDISPLAYMODE_NAMEKEY_MODE_TOUCH, @NDSDISPLAYMODE_PREFKEY_DISPLAYMODE },
{ @NDSDISPLAYMODE_NAMEKEY_ROTATION_0, @NDSDISPLAYMODE_PREFKEY_ROTATION },
{ @NDSDISPLAYMODE_NAMEKEY_ROTATION_90, @NDSDISPLAYMODE_PREFKEY_ROTATION },
{ @NDSDISPLAYMODE_NAMEKEY_ROTATION_180, @NDSDISPLAYMODE_PREFKEY_ROTATION },
{ @NDSDISPLAYMODE_NAMEKEY_ROTATION_270, @NDSDISPLAYMODE_PREFKEY_ROTATION },
{ @NDSDISPLAYMODE_NAMEKEY_LAYOUT_VERTICAL, @NDSDISPLAYMODE_PREFKEY_LAYOUT },
{ @NDSDISPLAYMODE_NAMEKEY_LAYOUT_HORIZONTAL, @NDSDISPLAYMODE_PREFKEY_LAYOUT },
{ @NDSDISPLAYMODE_NAMEKEY_LAYOUT_HYBRID_2_1, @NDSDISPLAYMODE_PREFKEY_LAYOUT },
{ @NDSDISPLAYMODE_NAMEKEY_LAYOUT_HYBRID_16_9, @NDSDISPLAYMODE_PREFKEY_LAYOUT },
{ @NDSDISPLAYMODE_NAMEKEY_LAYOUT_HYBRID_16_10, @NDSDISPLAYMODE_PREFKEY_LAYOUT },
{ @NDSDISPLAYMODE_NAMEKEY_DISPLAYORDER_MAIN, @NDSDISPLAYMODE_PREFKEY_ORDER },
{ @NDSDISPLAYMODE_NAMEKEY_DISPLAYORDER_TOUCH, @NDSDISPLAYMODE_PREFKEY_ORDER },
{ @NDSDISPLAYMODE_NAMEKEY_SEPARATION_0, @NDSDISPLAYMODE_PREFKEY_SEPARATION },
{ @NDSDISPLAYMODE_NAMEKEY_SEPARATION_50, @NDSDISPLAYMODE_PREFKEY_SEPARATION },
{ @NDSDISPLAYMODE_NAMEKEY_SEPARATION_100, @NDSDISPLAYMODE_PREFKEY_SEPARATION },
{ @NDSDISPLAYMODE_NAMEKEY_SEPARATION_150, @NDSDISPLAYMODE_PREFKEY_SEPARATION },
{ @NDSDISPLAYMODE_NAMEKEY_SEPARATION_200, @NDSDISPLAYMODE_PREFKEY_SEPARATION },
{ @NDSDISPLAYMODE_NAMEKEY_VIDEOSOURCEMAIN_NONE, @NDSDISPLAYMODE_PREFKEY_VIDEOSOURCE_MAIN },
{ @NDSDISPLAYMODE_NAMEKEY_VIDEOSOURCEMAIN_NDS, @NDSDISPLAYMODE_PREFKEY_VIDEOSOURCE_MAIN },
{ @NDSDISPLAYMODE_NAMEKEY_VIDEOSOURCEMAIN_FORCEMAIN, @NDSDISPLAYMODE_PREFKEY_VIDEOSOURCE_MAIN },
{ @NDSDISPLAYMODE_NAMEKEY_VIDEOSOURCEMAIN_FORCETOUCH, @NDSDISPLAYMODE_PREFKEY_VIDEOSOURCE_MAIN },
{ @NDSDISPLAYMODE_NAMEKEY_VIDEOSOURCETOUCH_NONE, @NDSDISPLAYMODE_PREFKEY_VIDEOSOURCE_TOUCH },
{ @NDSDISPLAYMODE_NAMEKEY_VIDEOSOURCETOUCH_NDS, @NDSDISPLAYMODE_PREFKEY_VIDEOSOURCE_TOUCH },
{ @NDSDISPLAYMODE_NAMEKEY_VIDEOSOURCETOUCH_FORCEMAIN, @NDSDISPLAYMODE_PREFKEY_VIDEOSOURCE_TOUCH },
{ @NDSDISPLAYMODE_NAMEKEY_VIDEOSOURCETOUCH_FORCETOUCH, @NDSDISPLAYMODE_PREFKEY_VIDEOSOURCE_TOUCH }
};
static const uint64_t kDisplayModeStatesDefault = (1 << NDSDisplayOptionID_Mode_DualScreen) |
(1 << NDSDisplayOptionID_Rotation_0) |
(1 << NDSDisplayOptionID_Layout_Vertical) |
(1 << NDSDisplayOptionID_Order_MainFirst) |
(1 << NDSDisplayOptionID_Separation_0) |
(1 << NDSDisplayOptionID_VideoSourceMain_NDS) |
(1 << NDSDisplayOptionID_VideoSourceTouch_NDS);
volatile bool execute = true;
@ -42,7 +89,7 @@ volatile bool execute = true;
@synthesize cdsGPU;
@synthesize cdsFirmware;
@synthesize cdsCheats;
@dynamic displayMode;
@dynamic ndsDisplayMode;
- (id)init
{
@ -118,9 +165,45 @@ volatile bool execute = true;
SPU_SetVolume(100);
// Set up the DS display
displayMode = ClientDisplayMode_Dual;
displayRect = OEIntRectMake(0, 0, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT * 2);
displayAspectRatio = OEIntSizeMake(2, 3);
ndsDisplayMode = kDisplayModeStatesDefault;
_displayRect = OEIntRectMake(0, 0, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT * 2);
_displayAspectRatio = OEIntSizeMake(2, 3);
_displayModeIDFromString = [[NSDictionary alloc] initWithObjectsAndKeys:
[NSNumber numberWithInteger:NDSDisplayOptionID_Mode_DualScreen], kDisplayModeItem[NDSDisplayOptionID_Mode_DualScreen].nameKey,
[NSNumber numberWithInteger:NDSDisplayOptionID_Mode_Main], kDisplayModeItem[NDSDisplayOptionID_Mode_Main].nameKey,
[NSNumber numberWithInteger:NDSDisplayOptionID_Mode_Touch], kDisplayModeItem[NDSDisplayOptionID_Mode_Touch].nameKey,
[NSNumber numberWithInteger:NDSDisplayOptionID_Rotation_0], kDisplayModeItem[NDSDisplayOptionID_Rotation_0].nameKey,
[NSNumber numberWithInteger:NDSDisplayOptionID_Rotation_90], kDisplayModeItem[NDSDisplayOptionID_Rotation_90].nameKey,
[NSNumber numberWithInteger:NDSDisplayOptionID_Rotation_180], kDisplayModeItem[NDSDisplayOptionID_Rotation_180].nameKey,
[NSNumber numberWithInteger:NDSDisplayOptionID_Rotation_270], kDisplayModeItem[NDSDisplayOptionID_Rotation_270].nameKey,
[NSNumber numberWithInteger:NDSDisplayOptionID_Layout_Vertical], kDisplayModeItem[NDSDisplayOptionID_Layout_Vertical].nameKey,
[NSNumber numberWithInteger:NDSDisplayOptionID_Layout_Horizontal], kDisplayModeItem[NDSDisplayOptionID_Layout_Horizontal].nameKey,
[NSNumber numberWithInteger:NDSDisplayOptionID_Layout_Hybrid_2_1], kDisplayModeItem[NDSDisplayOptionID_Layout_Hybrid_2_1].nameKey,
[NSNumber numberWithInteger:NDSDisplayOptionID_Layout_Hybrid_16_9], kDisplayModeItem[NDSDisplayOptionID_Layout_Hybrid_16_9].nameKey,
[NSNumber numberWithInteger:NDSDisplayOptionID_Layout_Hybrid_16_10], kDisplayModeItem[NDSDisplayOptionID_Layout_Hybrid_16_10].nameKey,
[NSNumber numberWithInteger:NDSDisplayOptionID_Order_MainFirst], kDisplayModeItem[NDSDisplayOptionID_Order_MainFirst].nameKey,
[NSNumber numberWithInteger:NDSDisplayOptionID_Order_TouchFirst], kDisplayModeItem[NDSDisplayOptionID_Order_TouchFirst].nameKey,
[NSNumber numberWithInteger:NDSDisplayOptionID_Separation_0], kDisplayModeItem[NDSDisplayOptionID_Separation_0].nameKey,
[NSNumber numberWithInteger:NDSDisplayOptionID_Separation_50], kDisplayModeItem[NDSDisplayOptionID_Separation_50].nameKey,
[NSNumber numberWithInteger:NDSDisplayOptionID_Separation_100], kDisplayModeItem[NDSDisplayOptionID_Separation_100].nameKey,
[NSNumber numberWithInteger:NDSDisplayOptionID_Separation_150], kDisplayModeItem[NDSDisplayOptionID_Separation_150].nameKey,
[NSNumber numberWithInteger:NDSDisplayOptionID_Separation_200], kDisplayModeItem[NDSDisplayOptionID_Separation_200].nameKey,
[NSNumber numberWithInteger:NDSDisplayOptionID_VideoSourceMain_None], kDisplayModeItem[NDSDisplayOptionID_VideoSourceMain_None].nameKey,
[NSNumber numberWithInteger:NDSDisplayOptionID_VideoSourceMain_NDS], kDisplayModeItem[NDSDisplayOptionID_VideoSourceMain_NDS].nameKey,
[NSNumber numberWithInteger:NDSDisplayOptionID_VideoSourceMain_ForceMain], kDisplayModeItem[NDSDisplayOptionID_VideoSourceMain_ForceMain].nameKey,
[NSNumber numberWithInteger:NDSDisplayOptionID_VideoSourceMain_ForceTouch], kDisplayModeItem[NDSDisplayOptionID_VideoSourceMain_ForceTouch].nameKey,
[NSNumber numberWithInteger:NDSDisplayOptionID_VideoSourceTouch_None], kDisplayModeItem[NDSDisplayOptionID_VideoSourceTouch_None].nameKey,
[NSNumber numberWithInteger:NDSDisplayOptionID_VideoSourceTouch_NDS], kDisplayModeItem[NDSDisplayOptionID_VideoSourceTouch_NDS].nameKey,
[NSNumber numberWithInteger:NDSDisplayOptionID_VideoSourceTouch_ForceMain], kDisplayModeItem[NDSDisplayOptionID_VideoSourceTouch_ForceMain].nameKey,
[NSNumber numberWithInteger:NDSDisplayOptionID_VideoSourceTouch_ForceTouch], kDisplayModeItem[NDSDisplayOptionID_VideoSourceTouch_ForceTouch].nameKey,
nil];
return self;
}
@ -136,52 +219,52 @@ volatile bool execute = true;
[cdsGPU release];
[cdsFirmware release];
[_displayModeIDFromString release];
pthread_rwlock_destroy(&rwlockCoreExecute);
apple_unfairlock_destroy(unfairlockDisplayMode);
[super dealloc];
}
- (NSInteger) displayMode
- (uint64_t) ndsDisplayMode
{
apple_unfairlock_lock(unfairlockDisplayMode);
const NSInteger theMode = displayMode;
const uint64_t displayModeStates = ndsDisplayMode;
apple_unfairlock_unlock(unfairlockDisplayMode);
return theMode;
return displayModeStates;
}
- (void) setDisplayMode:(NSInteger)theMode
- (void) setNdsDisplayMode:(uint64_t)displayModeStates
{
OEIntRect newDisplayRect;
OEIntSize newDisplayAspectRatio;
switch (theMode)
if ( DISPLAYMODE_STATEBIT_CHECK(displayModeStates, NDSDisplayOptionID_Mode_DualScreen) )
{
case ClientDisplayMode_Main:
newDisplayRect = OEIntRectMake(0, 0, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT);
newDisplayAspectRatio = OEIntSizeMake(4, 3);
break;
case ClientDisplayMode_Touch:
newDisplayRect = OEIntRectMake(0, GPU_FRAMEBUFFER_NATIVE_HEIGHT + 1, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT);
newDisplayAspectRatio = OEIntSizeMake(4, 3);
break;
case ClientDisplayMode_Dual:
newDisplayRect = OEIntRectMake(0, 0, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT * 2);
newDisplayAspectRatio = OEIntSizeMake(2, 3);
break;
default:
return;
break;
newDisplayRect = OEIntRectMake(0, 0, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT * 2);
newDisplayAspectRatio = OEIntSizeMake(2, 3);
}
else if ( DISPLAYMODE_STATEBIT_CHECK(displayModeStates, NDSDisplayOptionID_Mode_Main) )
{
newDisplayRect = OEIntRectMake(0, 0, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT);
newDisplayAspectRatio = OEIntSizeMake(4, 3);
}
else if ( DISPLAYMODE_STATEBIT_CHECK(displayModeStates, NDSDisplayOptionID_Mode_Touch) )
{
newDisplayRect = OEIntRectMake(0, GPU_FRAMEBUFFER_NATIVE_HEIGHT + 1, GPU_FRAMEBUFFER_NATIVE_WIDTH, GPU_FRAMEBUFFER_NATIVE_HEIGHT);
newDisplayAspectRatio = OEIntSizeMake(4, 3);
}
else
{
return;
}
apple_unfairlock_lock(unfairlockDisplayMode);
displayMode = theMode;
displayRect = newDisplayRect;
displayAspectRatio = newDisplayAspectRatio;
ndsDisplayMode = displayModeStates;
_displayRect = newDisplayRect;
_displayAspectRatio = newDisplayAspectRatio;
apple_unfairlock_unlock(unfairlockDisplayMode);
}
@ -227,6 +310,30 @@ volatile bool execute = true;
[CocoaDSCheatManager setMasterCheatList:cdsCheats];
// Set the default options.
// Have to do it now because displayModeInfo is only available now -- not at this object's init.
NSDictionary<NSString *, id> *userDefaultsDisplayMode = nil;
if ([self respondsToSelector:@selector(displayModeInfo)])
{
userDefaultsDisplayMode = [self displayModeInfo];
}
#define GENDISPLAYMODESTATE(_PREFKEY_, _DEFAULTID_) \
( ([userDefaultsDisplayMode objectForKey:(_PREFKEY_)] == nil) || ([_displayModeIDFromString objectForKey:(NSString *)[userDefaultsDisplayMode objectForKey:(_PREFKEY_)]] == nil) ) ? \
(1 << (_DEFAULTID_)) : \
(1 << [(NSNumber *)[_displayModeIDFromString objectForKey:(NSString *)[userDefaultsDisplayMode objectForKey:(_PREFKEY_)]] integerValue])
uint64_t newDisplayModeStates = 0;
newDisplayModeStates |= GENDISPLAYMODESTATE( @NDSDISPLAYMODE_PREFKEY_DISPLAYMODE, NDSDisplayOptionID_Mode_DualScreen );
newDisplayModeStates |= GENDISPLAYMODESTATE( @NDSDISPLAYMODE_PREFKEY_ROTATION, NDSDisplayOptionID_Rotation_0 );
newDisplayModeStates |= GENDISPLAYMODESTATE( @NDSDISPLAYMODE_PREFKEY_LAYOUT, NDSDisplayOptionID_Layout_Vertical );
newDisplayModeStates |= GENDISPLAYMODESTATE( @NDSDISPLAYMODE_PREFKEY_ORDER, NDSDisplayOptionID_Order_MainFirst );
newDisplayModeStates |= GENDISPLAYMODESTATE( @NDSDISPLAYMODE_PREFKEY_SEPARATION, NDSDisplayOptionID_Separation_0 );
newDisplayModeStates |= GENDISPLAYMODESTATE( @NDSDISPLAYMODE_PREFKEY_VIDEOSOURCE_MAIN, NDSDisplayOptionID_VideoSourceMain_NDS );
newDisplayModeStates |= GENDISPLAYMODESTATE( @NDSDISPLAYMODE_PREFKEY_VIDEOSOURCE_TOUCH, NDSDisplayOptionID_VideoSourceTouch_NDS );
[self setNdsDisplayMode:newDisplayModeStates];
return isRomLoaded;
}
@ -405,7 +512,7 @@ volatile bool execute = true;
- (OEIntRect)screenRect
{
apple_unfairlock_lock(unfairlockDisplayMode);
const OEIntRect theRect = displayRect;
const OEIntRect theRect = _displayRect;
apple_unfairlock_unlock(unfairlockDisplayMode);
return theRect;
@ -421,7 +528,7 @@ volatile bool execute = true;
- (OEIntSize)aspectSize
{
apple_unfairlock_lock(unfairlockDisplayMode);
const OEIntSize theAspectRatio = displayAspectRatio;
const OEIntSize theAspectRatio = _displayAspectRatio;
apple_unfairlock_unlock(unfairlockDisplayMode);
return theAspectRatio;
@ -633,33 +740,187 @@ volatile bool execute = true;
* - A nested group of options (which appears as a submenu)
* See OEGameCoreController.h for a detailed discussion of the keys contained
* in each item dictionary. */
//@property(readonly) NSArray<NSDictionary<NSString *, id> *> *displayModes;
- (NSDictionary<NSString *, id> *) generateDisplayModeItemByID:(NDSDisplayOptionID)optionID states:(const uint64_t)states
{
if ( (optionID < 0) || (optionID >= NDSDisplayOptionID_Count) )
{
return nil;
}
return [NSDictionary dictionaryWithObjectsAndKeys:
kDisplayModeItem[optionID].nameKey, OEGameCoreDisplayModeNameKey,
kDisplayModeItem[optionID].prefKey, OEGameCoreDisplayModePrefKeyNameKey,
[NSNumber numberWithBool:DISPLAYMODE_STATEBIT_CHECK(states, optionID) ? YES : NO], OEGameCoreDisplayModeStateKey,
nil];
}
- (NSArray<NSDictionary<NSString *, id> *> *) displayModes
{
const uint64_t currentDisplayMode = [self ndsDisplayMode];
// Generate each display option submenu.
NSArray< NSDictionary<NSString *, id> *> *displayModeMenu =
[NSArray arrayWithObjects:
[self generateDisplayModeItemByID:NDSDisplayOptionID_Mode_DualScreen states:currentDisplayMode],
[self generateDisplayModeItemByID:NDSDisplayOptionID_Mode_Main states:currentDisplayMode],
[self generateDisplayModeItemByID:NDSDisplayOptionID_Mode_Touch states:currentDisplayMode],
nil];
NSArray< NSDictionary<NSString *, id> *> *displayRotationMenu =
[NSArray arrayWithObjects:
[self generateDisplayModeItemByID:NDSDisplayOptionID_Rotation_0 states:currentDisplayMode],
[self generateDisplayModeItemByID:NDSDisplayOptionID_Rotation_90 states:currentDisplayMode],
[self generateDisplayModeItemByID:NDSDisplayOptionID_Rotation_180 states:currentDisplayMode],
[self generateDisplayModeItemByID:NDSDisplayOptionID_Rotation_270 states:currentDisplayMode],
nil];
NSArray< NSDictionary<NSString *, id> *> *displayLayoutMenu =
[NSArray arrayWithObjects:
[self generateDisplayModeItemByID:NDSDisplayOptionID_Layout_Vertical states:currentDisplayMode],
[self generateDisplayModeItemByID:NDSDisplayOptionID_Layout_Horizontal states:currentDisplayMode],
[self generateDisplayModeItemByID:NDSDisplayOptionID_Layout_Hybrid_2_1 states:currentDisplayMode],
[self generateDisplayModeItemByID:NDSDisplayOptionID_Layout_Hybrid_16_9 states:currentDisplayMode],
[self generateDisplayModeItemByID:NDSDisplayOptionID_Layout_Hybrid_16_10 states:currentDisplayMode],
nil];
NSArray< NSDictionary<NSString *, id> *> *displayOrderMenu =
[NSArray arrayWithObjects:
[self generateDisplayModeItemByID:NDSDisplayOptionID_Order_MainFirst states:currentDisplayMode],
[self generateDisplayModeItemByID:NDSDisplayOptionID_Order_TouchFirst states:currentDisplayMode],
nil];
NSArray< NSDictionary<NSString *, id> *> *displaySeparationMenu =
[NSArray arrayWithObjects:
[self generateDisplayModeItemByID:NDSDisplayOptionID_Separation_0 states:currentDisplayMode],
[self generateDisplayModeItemByID:NDSDisplayOptionID_Separation_50 states:currentDisplayMode],
[self generateDisplayModeItemByID:NDSDisplayOptionID_Separation_100 states:currentDisplayMode],
[self generateDisplayModeItemByID:NDSDisplayOptionID_Separation_150 states:currentDisplayMode],
[self generateDisplayModeItemByID:NDSDisplayOptionID_Separation_200 states:currentDisplayMode],
nil];
NSArray< NSDictionary<NSString *, id> *> *displayVideoSourceMenu =
[NSArray arrayWithObjects:
[self generateDisplayModeItemByID:NDSDisplayOptionID_VideoSourceMain_None states:currentDisplayMode],
[self generateDisplayModeItemByID:NDSDisplayOptionID_VideoSourceMain_NDS states:currentDisplayMode],
[self generateDisplayModeItemByID:NDSDisplayOptionID_VideoSourceMain_ForceMain states:currentDisplayMode],
[self generateDisplayModeItemByID:NDSDisplayOptionID_VideoSourceMain_ForceTouch states:currentDisplayMode],
[NSDictionary dictionaryWithObjectsAndKeys:@"---", OEGameCoreDisplayModeSeparatorItemKey, nil],
[self generateDisplayModeItemByID:NDSDisplayOptionID_VideoSourceTouch_None states:currentDisplayMode],
[self generateDisplayModeItemByID:NDSDisplayOptionID_VideoSourceTouch_NDS states:currentDisplayMode],
[self generateDisplayModeItemByID:NDSDisplayOptionID_VideoSourceTouch_ForceMain states:currentDisplayMode],
[self generateDisplayModeItemByID:NDSDisplayOptionID_VideoSourceTouch_ForceTouch states:currentDisplayMode],
nil];
// Add each submenu to the menu descriptor.
//
// You may wonder why we're generating the menu from scratch every time. The reason is because
// OpenEmu wants to have a full immutable copy of the menu descriptor so that it can use it for
// its Next/Last Display Mode switching feature. Because of this, we can't just generate a
// single menu descriptor at init time, modify it as needed, and then send OpenEmu the pointer
// to our menu descriptor. as OpenEmu can modify it in some unpredictable ways. We would have
// to send a copy to keep our internal working menu descriptor from getting borked.
//
// Maintaining a mutable version of the menu descriptor for our internal usage is a pain, as
// it involves a bunch of hash table lookups and calls to [NSString isEqualToString:], among
// many other annoyances with dealing with NSMutableDictionary directly. Since we have to send
// OpenEmu a copy of the menu descriptor anyways, it ends up being easier to just use a single
// integer ID, NDSDisplayOptionID in our case, to keep track of all of the data associations
// and then use that ID to generate the menu.
/*
NSArray< NSDictionary<NSString *, id> *> *newDisplayModeMenuDescription =
[[NSArray alloc] initWithObjects:
[NSDictionary dictionaryWithObjectsAndKeys: @"Mode", OEGameCoreDisplayModeGroupNameKey, displayModeMenu, OEGameCoreDisplayModeGroupItemsKey, nil],
[NSDictionary dictionaryWithObjectsAndKeys: @"Rotation", OEGameCoreDisplayModeGroupNameKey, displayRotationMenu, OEGameCoreDisplayModeGroupItemsKey, nil],
[NSDictionary dictionaryWithObjectsAndKeys: @"Layout", OEGameCoreDisplayModeGroupNameKey, displayLayoutMenu, OEGameCoreDisplayModeGroupItemsKey, nil],
[NSDictionary dictionaryWithObjectsAndKeys: @"Order", OEGameCoreDisplayModeGroupNameKey, displayOrderMenu, OEGameCoreDisplayModeGroupItemsKey, nil],
[NSDictionary dictionaryWithObjectsAndKeys: @"Separation", OEGameCoreDisplayModeGroupNameKey, displaySeparationMenu, OEGameCoreDisplayModeGroupItemsKey, nil],
[NSDictionary dictionaryWithObjectsAndKeys: @"Video Source", OEGameCoreDisplayModeGroupNameKey, displayVideoSourceMenu, OEGameCoreDisplayModeGroupItemsKey, nil],
nil];
*/
// Still working on other display modes, so just support the original display modes for now.
NSArray< NSDictionary<NSString *, id> *> *newDisplayModeMenuDescription =
[[NSArray alloc] initWithObjects:
[self generateDisplayModeItemByID:NDSDisplayOptionID_Mode_DualScreen states:currentDisplayMode],
[self generateDisplayModeItemByID:NDSDisplayOptionID_Mode_Main states:currentDisplayMode],
[self generateDisplayModeItemByID:NDSDisplayOptionID_Mode_Touch states:currentDisplayMode],
nil];
return newDisplayModeMenuDescription;
}
/** Change display mode.
* @param displayMode The name of the display mode to enable or disable, as
* specified in its OEGameCoreDisplayModeNameKey key. */
//- (void)changeDisplayWithMode:(NSString *)displayMode;
- (void)changeDisplayMode
- (void)changeDisplayWithMode:(NSString *)displayMode
{
switch (displayMode)
NSNumber *optionIDNumber = [_displayModeIDFromString objectForKey:displayMode];
if ( (displayMode == nil) || (optionIDNumber == nil) )
{
case ClientDisplayMode_Main:
[self setDisplayMode:ClientDisplayMode_Touch];
return;
}
uint64_t displayModeStates = [self ndsDisplayMode];
const NDSDisplayOptionID optionID = (NDSDisplayOptionID)[optionIDNumber integerValue];
switch (optionID)
{
case NDSDisplayOptionID_Mode_DualScreen:
case NDSDisplayOptionID_Mode_Main:
case NDSDisplayOptionID_Mode_Touch:
DISPLAYMODE_STATEBITGROUP_CLEAR(displayModeStates, NDSDisplayOptionStateBitmask_DisplayMode);
break;
case ClientDisplayMode_Touch:
[self setDisplayMode:ClientDisplayMode_Dual];
case NDSDisplayOptionID_Rotation_0:
case NDSDisplayOptionID_Rotation_90:
case NDSDisplayOptionID_Rotation_180:
case NDSDisplayOptionID_Rotation_270:
DISPLAYMODE_STATEBITGROUP_CLEAR(displayModeStates, NDSDisplayOptionStateBitmask_Rotation);
break;
case ClientDisplayMode_Dual:
[self setDisplayMode:ClientDisplayMode_Main];
case NDSDisplayOptionID_Layout_Vertical:
case NDSDisplayOptionID_Layout_Horizontal:
case NDSDisplayOptionID_Layout_Hybrid_2_1:
case NDSDisplayOptionID_Layout_Hybrid_16_9:
case NDSDisplayOptionID_Layout_Hybrid_16_10:
DISPLAYMODE_STATEBITGROUP_CLEAR(displayModeStates, NDSDisplayOptionStateBitmask_Layout);
break;
case NDSDisplayOptionID_Order_MainFirst:
case NDSDisplayOptionID_Order_TouchFirst:
DISPLAYMODE_STATEBITGROUP_CLEAR(displayModeStates, NDSDisplayOptionStateBitmask_Order);
break;
case NDSDisplayOptionID_Separation_0:
case NDSDisplayOptionID_Separation_50:
case NDSDisplayOptionID_Separation_100:
case NDSDisplayOptionID_Separation_150:
case NDSDisplayOptionID_Separation_200:
DISPLAYMODE_STATEBITGROUP_CLEAR(displayModeStates, NDSDisplayOptionStateBitmask_Separation);
break;
case NDSDisplayOptionID_VideoSourceMain_None:
case NDSDisplayOptionID_VideoSourceMain_NDS:
case NDSDisplayOptionID_VideoSourceMain_ForceMain:
case NDSDisplayOptionID_VideoSourceMain_ForceTouch:
DISPLAYMODE_STATEBITGROUP_CLEAR(displayModeStates, NDSDisplayOptionStateBitmask_VideoSourceMain);
break;
case NDSDisplayOptionID_VideoSourceTouch_None:
case NDSDisplayOptionID_VideoSourceTouch_NDS:
case NDSDisplayOptionID_VideoSourceTouch_ForceMain:
case NDSDisplayOptionID_VideoSourceTouch_ForceTouch:
DISPLAYMODE_STATEBITGROUP_CLEAR(displayModeStates, NDSDisplayOptionStateBitmask_VideoSourceTouch);
break;
default:
return;
break;
}
displayModeStates |= (1 << optionID);
[self setNdsDisplayMode:displayModeStates];
}
#pragma mark - Internal
@ -768,26 +1029,24 @@ volatile bool execute = true;
- (oneway void)didTouchScreenPoint:(OEIntPoint)aPoint
{
BOOL isTouchPressed = NO;
NSInteger dispMode = [self displayMode];
uint64_t displayModeStates = [self ndsDisplayMode];
switch (dispMode)
if ( DISPLAYMODE_STATEBIT_CHECK(displayModeStates, NDSDisplayOptionID_Mode_DualScreen) )
{
case ClientDisplayMode_Main:
isTouchPressed = NO; // Reject touch input if showing only the main screen.
break;
case ClientDisplayMode_Touch:
isTouchPressed = YES;
break;
case ClientDisplayMode_Dual:
isTouchPressed = YES;
aPoint.y -= GPU_FRAMEBUFFER_NATIVE_HEIGHT; // Normalize the y-coordinate to the DS.
break;
default:
return;
break;
isTouchPressed = YES;
aPoint.y -= GPU_FRAMEBUFFER_NATIVE_HEIGHT; // Normalize the y-coordinate to the DS.
}
else if ( DISPLAYMODE_STATEBIT_CHECK(displayModeStates, NDSDisplayOptionID_Mode_Main) )
{
isTouchPressed = NO; // Reject touch input if showing only the main screen.
}
else if ( DISPLAYMODE_STATEBIT_CHECK(displayModeStates, NDSDisplayOptionID_Mode_Touch) )
{
isTouchPressed = YES;
}
else
{
return;
}
// Constrain the touch point to the DS dimensions.