9 Commits

Author SHA1 Message Date
clobber cd166c0561 Bump version for sparkle updater. Core is still 2.2.3 2018-11-25 16:15:16 -06:00
clobber dd9e1c3cee Cleanup 2018-11-25 16:14:41 -06:00
clobber 28ae039566 Add display mode change support 2018-11-23 00:54:14 -06:00
clobber 33026a6424 Cleanup 2018-11-22 21:11:38 -06:00
clobber 10e4d8fd38 Build fix for latest Clang.
cheat.cpp:219:30: error: ordered comparison between pointer and zero ('char *' and 'int')
2018-04-05 02:11:16 -05:00
clobber 2758d42404 Use -fileSystemRepresentation instead of -UTF8String for file names 2017-08-16 23:42:32 -05:00
Rudy Richter 0fa341d5c1 these should be uint32_t not uint8_t 2017-07-20 20:54:58 -04:00
Rudy Richter 5bfdfc26d4 Use spaces 2017-07-20 08:50:47 -04:00
mrvacbob 22d81842fa Enable direct-rendering 2017-07-20 01:35:09 -07:00
4 changed files with 394 additions and 77 deletions
+1
View File
@@ -1131,6 +1131,7 @@
);
name = VisualBoyAdvance;
sourceTree = "<group>";
usesTabs = 0;
};
089C1671FE841209C02AAC07 /* Frameworks and Libraries */ = {
isa = PBXGroup;
+389 -75
View File
@@ -1,5 +1,5 @@
/*
Copyright (c) 2015, OpenEmu Team
Copyright (c) 2018, OpenEmu Team
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -41,18 +41,37 @@
extern uint8 *XBuf;
static uint32_t palette[256];
#define OVERSCAN_VERTICAL 8
#define OVERSCAN_HORIZONTAL 8
#define OptionDefault(_NAME_, _PREFKEY_) @{ OEGameCoreDisplayModeNameKey : _NAME_, OEGameCoreDisplayModePrefKeyNameKey : _PREFKEY_, OEGameCoreDisplayModeStateKey : @YES, }
#define Option(_NAME_, _PREFKEY_) @{ OEGameCoreDisplayModeNameKey : _NAME_, OEGameCoreDisplayModePrefKeyNameKey : _PREFKEY_, OEGameCoreDisplayModeStateKey : @NO, }
#define OptionIndented(_NAME_, _PREFKEY_) @{ OEGameCoreDisplayModeNameKey : _NAME_, OEGameCoreDisplayModePrefKeyNameKey : _PREFKEY_, OEGameCoreDisplayModeStateKey : @NO, OEGameCoreDisplayModeIndentationLevelKey : @(1), }
#define OptionToggleable(_NAME_, _PREFKEY_) @{ OEGameCoreDisplayModeNameKey : _NAME_, OEGameCoreDisplayModePrefKeyNameKey : _PREFKEY_, OEGameCoreDisplayModeStateKey : @NO, OEGameCoreDisplayModeAllowsToggleKey : @YES, }
#define OptionToggleableNoSave(_NAME_, _PREFKEY_) @{ OEGameCoreDisplayModeNameKey : _NAME_, OEGameCoreDisplayModePrefKeyNameKey : _PREFKEY_, OEGameCoreDisplayModeStateKey : @NO, OEGameCoreDisplayModeAllowsToggleKey : @YES, OEGameCoreDisplayModeDisallowPrefSaveKey : @YES, }
#define Label(_NAME_) @{ OEGameCoreDisplayModeLabelKey : _NAME_, }
#define SeparatorItem() @{ OEGameCoreDisplayModeSeparatorItemKey : @"",}
@interface FCEUGameCore () <OENESSystemResponderClient>
{
uint32_t *videoBuffer;
uint8_t *pXBuf;
int32_t *soundBuffer;
int32_t soundSize;
uint32_t pad;
uint32_t arkanoid[3];
uint32_t zapper[3];
uint32_t hypershot[4];
uint32_t *_videoBuffer;
int32_t *_soundBuffer;
int32_t _soundSize;
uint32_t _pad;
uint32_t _arkanoid[3];
uint32_t _zapper[3];
uint32_t _hypershot[4];
int _videoWidth, _videoHeight;
int _videoOffsetX, _videoOffsetY;
int _aspectWidth, _aspectHeight;
BOOL _isHorzOverscanCropped;
BOOL _isVertOverscanCropped;
NSMutableDictionary<NSString *, NSNumber *> *_cheatList;
NSMutableArray <NSMutableDictionary <NSString *, id> *> *_availableDisplayModes;
}
- (void)loadDisplayModeOptions;
@end
@implementation FCEUGameCore
@@ -63,7 +82,7 @@ static __weak FCEUGameCore *_current;
{
if((self = [super init]))
{
videoBuffer = (uint32_t *)malloc(256 * 240 * 4);
_cheatList = [NSMutableDictionary dictionary];
}
_current = self;
@@ -73,51 +92,51 @@ static __weak FCEUGameCore *_current;
- (void)dealloc
{
free(videoBuffer);
free(_videoBuffer);
}
# pragma mark - Execution
- (BOOL)loadFileAtPath:(NSString *)path error:(NSError **)error
{
pad = 0;
memset(arkanoid, 0, sizeof(arkanoid));
memset(zapper, 0, sizeof(zapper));
memset(hypershot, 0, sizeof(hypershot));
_pad = 0;
memset(_arkanoid, 0, sizeof(_arkanoid));
memset(_zapper, 0, sizeof(_zapper));
memset(_hypershot, 0, sizeof(_hypershot));
//newppu = 0 default off, set 1 to enable
FCEUI_Initialize();
NSURL *batterySavesDirectory = [NSURL fileURLWithPath:[self batterySavesDirectoryPath]];
[[NSFileManager defaultManager] createDirectoryAtURL:batterySavesDirectory withIntermediateDirectories:YES attributes:nil error:nil];
//FCEUI_SetBaseDirectory([[self biosDirectoryPath] UTF8String]); unused for now
FCEUI_SetDirOverride(FCEUIOD_NV, strdup([[batterySavesDirectory path] UTF8String]));
NSURL *batterySavesDirectory = [NSURL fileURLWithPath:self.batterySavesDirectoryPath];
[NSFileManager.defaultManager createDirectoryAtURL:batterySavesDirectory withIntermediateDirectories:YES attributes:nil error:nil];
//FCEUI_SetBaseDirectory([[self biosDirectoryPath] fileSystemRepresentation]); unused for now
FCEUI_SetDirOverride(FCEUIOD_NV, strdup(batterySavesDirectory.fileSystemRepresentation));
FCEUI_SetSoundVolume(256);
FCEUI_Sound(48000);
FCEUGI *FCEUGameInfo;
FCEUGameInfo = FCEUI_LoadGame([path UTF8String], 1, false);
FCEUGameInfo = FCEUI_LoadGame(path.fileSystemRepresentation, 1, false);
if(!FCEUGameInfo)
return NO;
//NSLog(@"FPS: %d", FCEUI_GetDesiredFPS() >> 24); // Hz
FCEUI_SetInput(0, SI_GAMEPAD, &pad, 0); // Controllers 1 and 3
FCEUI_SetInput(0, SI_GAMEPAD, &_pad, 0); // Controllers 1 and 3
if(FCEUGameInfo->input[1] == SI_ZAPPER)
FCEUI_SetInput(1, SI_ZAPPER, &zapper, 0);
FCEUI_SetInput(1, SI_ZAPPER, &_zapper, 0);
else if(FCEUGameInfo->input[1] == SI_ARKANOID)
FCEUI_SetInput(1, SI_ARKANOID, &arkanoid, 0);
FCEUI_SetInput(1, SI_ARKANOID, &_arkanoid, 0);
else
FCEUI_SetInput(1, SI_GAMEPAD, &pad, 0); // Controllers 2 and 4
FCEUI_SetInput(1, SI_GAMEPAD, &_pad, 0); // Controllers 2 and 4
if(FCEUGameInfo->inputfc == SIFC_SHADOW)
FCEUI_SetInputFC(SIFC_SHADOW, &hypershot, 0);
FCEUI_SetInputFC(SIFC_SHADOW, &_hypershot, 0);
else if(FCEUGameInfo->inputfc == SIFC_ARKANOID)
FCEUI_SetInputFC(SIFC_ARKANOID, &arkanoid, 0);
FCEUI_SetInputFC(SIFC_ARKANOID, &_arkanoid, 0);
extern uint32_t iNESGameCRC32;
NSString *cartCRC32 = [NSString stringWithFormat:@"%08x", iNESGameCRC32];
@@ -192,29 +211,29 @@ static __weak FCEUGameCore *_current;
FCEUI_SetInputFourscore(true);
if([famicom4Player containsObject:cartCRC32])
FCEUI_SetInputFC(SIFC_4PLAYER, &pad, 0);
FCEUI_SetInputFC(SIFC_4PLAYER, &_pad, 0);
FCEU_ResetPalette();
// Only temporary, so core doesn't crash on an older OpenEmu version
if ([self respondsToSelector:@selector(displayModeInfo)]) {
[self loadDisplayModeOptions];
}
return YES;
}
- (void)executeFrame
{
pXBuf = 0;
soundSize = 0;
uint8_t *pXBuf;
_soundSize = 0;
FCEUI_Emulate(&pXBuf, &soundBuffer, &soundSize, 0);
FCEUI_Emulate(&pXBuf, &_soundBuffer, &_soundSize, 0);
pXBuf = XBuf;
for (unsigned y = 0; y < 240; y++)
for (unsigned x = 0; x < 256; x++, pXBuf++)
videoBuffer[y * 256 + x] = palette[*pXBuf];
for (int i = 0; i < _soundSize; i++)
_soundBuffer[i] = (_soundBuffer[i] << 16) | (_soundBuffer[i] & 0xffff);
for (int i = 0; i < soundSize; i++)
soundBuffer[i] = (soundBuffer[i] << 16) | (soundBuffer[i] & 0xffff);
[[self ringBufferAtIndex:0] write:soundBuffer maxLength:soundSize << 2];
[[self ringBufferAtIndex:0] write:_soundBuffer maxLength:_soundSize << 2];
}
- (void)resetEmulation
@@ -237,19 +256,39 @@ static __weak FCEUGameCore *_current;
# pragma mark - Video
- (const void *)videoBuffer
- (const void *)getVideoBufferWithHint:(void *)hint
{
return videoBuffer;
if (!hint) {
if (!_videoBuffer) _videoBuffer = (uint32_t *)malloc(256 * 240 * sizeof(uint32_t));
hint = _videoBuffer;
}
// TODO: support paletted video in OE
uint8_t *pXBuf = XBuf;
uint32_t *pOBuf = (uint32_t *)hint;
for (unsigned y = 0; y < 240; y++)
for (unsigned x = 0; x < 256; x++, pXBuf++)
pOBuf[y * 256 + x] = palette[*pXBuf];
return hint;
}
- (OEIntRect)screenRect
{
return OEIntRectMake(0, 0, 256, 240);
_videoOffsetX = _isHorzOverscanCropped ? OVERSCAN_HORIZONTAL : 0;
_videoOffsetY = _isVertOverscanCropped ? OVERSCAN_VERTICAL : 0;
_videoWidth = _isHorzOverscanCropped ? 256 - (OVERSCAN_HORIZONTAL * 2) : 256;
_videoHeight = _isVertOverscanCropped ? 240 - (OVERSCAN_VERTICAL * 2) : 240;
return OEIntRectMake(_videoOffsetX, _videoOffsetY, _videoWidth, _videoHeight);
}
- (OEIntSize)aspectSize
{
return OEIntSizeMake(256 * (8.0/7.0), 240);
_aspectWidth = _isHorzOverscanCropped ? (256 - (OVERSCAN_HORIZONTAL * 2)) * (8.0/7.0) : 256 * (8.0/7.0);
_aspectHeight = _isVertOverscanCropped ? 240 - (OVERSCAN_VERTICAL * 2) : 240;
return OEIntSizeMake(_aspectWidth, _aspectHeight);
}
- (OEIntSize)bufferSize
@@ -267,11 +306,6 @@ static __weak FCEUGameCore *_current;
return GL_UNSIGNED_INT_8_8_8_8_REV;
}
- (GLenum)internalPixelFormat
{
return GL_RGB8;
}
# pragma mark - Audio
- (double)audioSampleRate
@@ -316,8 +350,8 @@ static __weak FCEUGameCore *_current;
- (BOOL)deserializeState:(NSData *)state withError:(NSError **)outError
{
u8 *bytes = (u8 *)[state bytes];
size_t length = [state length];
u8 *bytes = (u8 *)state.bytes;
size_t length = state.length;
std::vector<u8> byteVector(bytes, bytes + length);
EMUFILE *emuFile = new EMUFILE_MEMORY(&byteVector);
@@ -349,7 +383,7 @@ const int NESMap[] = {JOY_UP, JOY_DOWN, JOY_LEFT, JOY_RIGHT, JOY_A, JOY_B, JOY_S
break;
}
pad |= NESMap[button] << playerShift;
_pad |= NESMap[button] << playerShift;
}
- (oneway void)didReleaseNESButton:(OENESButton)button forPlayer:(NSUInteger)player;
@@ -370,76 +404,77 @@ const int NESMap[] = {JOY_UP, JOY_DOWN, JOY_LEFT, JOY_RIGHT, JOY_A, JOY_B, JOY_S
break;
}
pad &= ~(NESMap[button] << playerShift);
_pad &= ~(NESMap[button] << playerShift);
}
- (oneway void)didTriggerGunAtPoint:(OEIntPoint)aPoint
{
[self mouseMovedAtPoint:aPoint];
arkanoid[2] = 1;
int xcoord = _isHorzOverscanCropped ? (aPoint.x + OVERSCAN_HORIZONTAL) * 0.876712 : aPoint.x * 0.876712;
int ycoord = _isVertOverscanCropped ? aPoint.y + OVERSCAN_VERTICAL : aPoint.y;
zapper[0] = aPoint.x * 0.876712;
zapper[1] = aPoint.y;
zapper[2] = 1;
_arkanoid[2] = 1;
hypershot[0] = aPoint.x * 0.876712;
hypershot[1] = aPoint.y;
hypershot[2] = 1;
_zapper[0] = xcoord;
_zapper[1] = ycoord;
_zapper[2] = 1;
_hypershot[0] = xcoord;
_hypershot[1] = ycoord;
_hypershot[2] = 1;
}
- (oneway void)didReleaseTrigger
{
arkanoid[2] = 0;
zapper[2] = 0;
hypershot[2] = 0;
_arkanoid[2] = 0;
_zapper[2] = 0;
_hypershot[2] = 0;
}
- (oneway void)mouseMovedAtPoint:(OEIntPoint)aPoint
{
arkanoid[0] = aPoint.x * 0.876712;
_arkanoid[0] = _isHorzOverscanCropped ? (aPoint.x + OVERSCAN_HORIZONTAL) * 0.876712 : aPoint.x * 0.876712;
}
- (oneway void)rightMouseDownAtPoint:(OEIntPoint)point
{
hypershot[3] = 1; // "move" button
_hypershot[3] = 1; // "move" button
}
- (oneway void)rightMouseUp;
{
hypershot[3] = 0;
_hypershot[3] = 0;
}
#pragma mark - Cheats
NSMutableDictionary *cheatList = [[NSMutableDictionary alloc] init];
- (void)setCheat:(NSString *)code setType:(NSString *)type setEnabled:(BOOL)enabled
{
// Sanitize
code = [code stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
code = [code stringByTrimmingCharactersInSet:NSCharacterSet.whitespaceAndNewlineCharacterSet];
// Remove any spaces
code = [code stringByReplacingOccurrencesOfString:@" " withString:@""];
if (enabled)
[cheatList setValue:@YES forKey:code];
_cheatList[code] = @YES;
else
[cheatList removeObjectForKey:code];
[_cheatList removeObjectForKey:code];
FCEU_FlushGameCheats(0, 1);
NSArray *multipleCodes = [[NSArray alloc] init];
NSArray<NSString *> *multipleCodes = [NSArray array];
// Apply enabled cheats found in dictionary
for (id key in cheatList)
for (NSString *key in _cheatList)
{
if ([[cheatList valueForKey:key] isEqual:@YES])
if ([_cheatList[key] boolValue])
{
// Handle multi-line cheats
multipleCodes = [key componentsSeparatedByString:@"+"];
for (NSString *singleCode in multipleCodes) {
const char *cCode = [singleCode UTF8String];
const char *cCode = singleCode.UTF8String;
int address, value, compare;
int type = 1;
@@ -451,6 +486,285 @@ NSMutableDictionary *cheatList = [[NSMutableDictionary alloc] init];
}
}
# pragma mark - Display Mode
- (NSArray <NSDictionary <NSString *, id> *> *)displayModes
{
if (_availableDisplayModes.count == 0)
{
_availableDisplayModes = [NSMutableArray array];
NSArray <NSDictionary <NSString *, id> *> *availableModesWithDefault =
@[
OptionToggleableNoSave(@"No Sprite Limit", @"noSpriteLimit"),
SeparatorItem(),
Label(@"Overscan"),
OptionToggleable(@"Crop Horizontal", @"cropHorizontalOverscan"),
OptionToggleable(@"Crop Vertical", @"cropVerticalOverscan"),
SeparatorItem(),
Label(@"Palette"),
OptionDefault(@"Default — FCEUX", @"palette"),
Option(@"RGB (PlayChoice-10)", @"palette"),
Option(@"NESCAP", @"palette"),
Option(@"Sony CXA2025AS", @"palette"),
Option(@"Smooth (FBX)", @"palette"),
Option(@"Wavebeam", @"palette"),
];
// Deep mutable copy
_availableDisplayModes = (NSMutableArray *)CFBridgingRelease(CFPropertyListCreateDeepCopy(kCFAllocatorDefault, (CFArrayRef)availableModesWithDefault, kCFPropertyListMutableContainers));
}
return [_availableDisplayModes copy];
}
- (void)changeDisplayWithMode:(NSString *)displayMode
{
if (_availableDisplayModes.count == 0)
[self displayModes];
// First check if 'displayMode' is valid
BOOL isDisplayModeToggleable = NO;
BOOL isValidDisplayMode = NO;
BOOL displayModeState = NO;
NSString *displayModePrefKey;
for (NSDictionary *modeDict in _availableDisplayModes) {
if ([modeDict[OEGameCoreDisplayModeNameKey] isEqualToString:displayMode]) {
displayModeState = [modeDict[OEGameCoreDisplayModeStateKey] boolValue];
displayModePrefKey = modeDict[OEGameCoreDisplayModePrefKeyNameKey];
isDisplayModeToggleable = [modeDict[OEGameCoreDisplayModeAllowsToggleKey] boolValue];
isValidDisplayMode = YES;
break;
}
}
// Disallow a 'displayMode' not found in _availableDisplayModes
if (!isValidDisplayMode)
return;
// Handle option state changes
for (NSMutableDictionary *optionDict in _availableDisplayModes) {
NSString *modeName = optionDict[OEGameCoreDisplayModeNameKey];
NSString *prefKey = optionDict[OEGameCoreDisplayModePrefKeyNameKey];
if (!modeName)
continue;
// Mutually exclusive option state change
else if ([modeName isEqualToString:displayMode] && !isDisplayModeToggleable)
optionDict[OEGameCoreDisplayModeStateKey] = @YES;
// Reset mutually exclusive options that are the same prefs group as 'displayMode'
else if (!isDisplayModeToggleable && [prefKey isEqualToString:displayModePrefKey])
optionDict[OEGameCoreDisplayModeStateKey] = @NO;
// Toggleable option state change
else if ([modeName isEqualToString:displayMode] && isDisplayModeToggleable)
optionDict[OEGameCoreDisplayModeStateKey] = @(!displayModeState);
}
if ([displayMode isEqualToString:@"Crop Horizontal"])
{
_isHorzOverscanCropped = !_isHorzOverscanCropped;
}
else if ([displayMode isEqualToString:@"Crop Vertical"])
{
_isVertOverscanCropped = !_isVertOverscanCropped;
}
else if ([displayMode isEqualToString:@"No Sprite Limit"])
{
FCEUI_DisableSpriteLimitation(!displayModeState);
}
else if ([displayMode isEqualToString:@"Default — FCEUX"])
{
FCEU_ResetPalette();
}
else if ([displayMode isEqualToString:@"RGB (PlayChoice-10)"])
{
unsigned int pc10_palette[64] =
{
0x6D6D6D, 0x002492, 0x0000DB, 0x6D49DB,
0x92006D, 0xB6006D, 0xB62400, 0x924900,
0x6D4900, 0x244900, 0x006D24, 0x009200,
0x004949, 0x000000, 0x000000, 0x000000,
0xB6B6B6, 0x006DDB, 0x0049FF, 0x9200FF,
0xB600FF, 0xFF0092, 0xFF0000, 0xDB6D00,
0x926D00, 0x249200, 0x009200, 0x00B66D,
0x009292, 0x242424, 0x000000, 0x000000,
0xFFFFFF, 0x6DB6FF, 0x9292FF, 0xDB6DFF,
0xFF00FF, 0xFF6DFF, 0xFF9200, 0xFFB600,
0xDBDB00, 0x6DDB00, 0x00FF00, 0x49FFDB,
0x00FFFF, 0x494949, 0x000000, 0x000000,
0xFFFFFF, 0xB6DBFF, 0xDBB6FF, 0xFFB6FF,
0xFF92FF, 0xFFB6B6, 0xFFDB92, 0xFFFF49,
0xFFFF6D, 0xB6FF49, 0x92FF6D, 0x49FFDB,
0x92DBFF, 0x929292, 0x000000, 0x000000
};
for (int i = 0; i < 64; i++)
{
int r = pc10_palette[i] >> 16;
int g = (pc10_palette[i] & 0xff00) >> 8;
int b = pc10_palette[i] & 0xff;
FCEUD_SetPalette(i, r, g, b);
FCEUD_SetPalette(i + 64, r, g, b);
FCEUD_SetPalette(i + 128, r, g, b);
FCEUD_SetPalette(i + 192, r, g, b);
}
}
else if ([displayMode isEqualToString:@"NESCAP"])
{
unsigned int nescap_palette[64] =
{
0x646365, 0x001580, 0x1D0090, 0x380082,
0x56005D, 0x5A001A, 0x4F0900, 0x381B00,
0x1E3100, 0x003D00, 0x004100, 0x003A1B,
0x002F55, 0x000000, 0x000000, 0x000000,
0xAFADAF, 0x164BCA, 0x472AE7, 0x6B1BDB,
0x9617B0, 0x9F185B, 0x963001, 0x7B4800,
0x5A6600, 0x237800, 0x017F00, 0x00783D,
0x006C8C, 0x000000, 0x000000, 0x000000,
0xFFFFFF, 0x60A6FF, 0x8F84FF, 0xB473FF,
0xE26CFF, 0xF268C3, 0xEF7E61, 0xD89527,
0xBAB307, 0x81C807, 0x57D43D, 0x47CF7E,
0x4BC5CD, 0x4C4B4D, 0x000000, 0x000000,
0xFFFFFF, 0xC2E0FF, 0xD5D2FF, 0xE3CBFF,
0xF7C8FF, 0xFEC6EE, 0xFECEC6, 0xF6D7AE,
0xE9E49F, 0xD3ED9D, 0xC0F2B2, 0xB9F1CC,
0xBAEDED, 0xBAB9BB, 0x000000, 0x000000
};
for (int i = 0; i < 64; i++)
{
int r = nescap_palette[i] >> 16;
int g = (nescap_palette[i] & 0xff00) >> 8;
int b = nescap_palette[i] & 0xff;
FCEUD_SetPalette(i, r, g, b);
FCEUD_SetPalette(i + 64, r, g, b);
FCEUD_SetPalette(i + 128, r, g, b);
FCEUD_SetPalette(i + 192, r, g, b);
}
}
else if ([displayMode isEqualToString:@"Sony CXA2025AS"])
{
unsigned int cxa2025as_palette[64] =
{
0x585858, 0x00238C, 0x00139B, 0x2D0585,
0x5D0052, 0x7A0017, 0x7A0800, 0x5F1800,
0x352A00, 0x093900, 0x003F00, 0x003C22,
0x00325D, 0x000000, 0x000000, 0x000000,
0xA1A1A1, 0x0053EE, 0x153CFE, 0x6028E4,
0xA91D98, 0xD41E41, 0xD22C00, 0xAA4400,
0x6C5E00, 0x2D7300, 0x007D06, 0x007852,
0x0069A9, 0x000000, 0x000000, 0x000000,
0xFFFFFF, 0x1FA5FE, 0x5E89FE, 0xB572FE,
0xFE65F6, 0xFE6790, 0xFE773C, 0xFE9308,
0xC4B200, 0x79CA10, 0x3AD54A, 0x11D1A4,
0x06BFFE, 0x424242, 0x000000, 0x000000,
0xFFFFFF, 0xA0D9FE, 0xBDCCFE, 0xE1C2FE,
0xFEBCFB, 0xFEBDD0, 0xFEC5A9, 0xFED18E,
0xE9DE86, 0xC7E992, 0xA8EEB0, 0x95ECD9,
0x91E4FE, 0xACACAC, 0x000000, 0x000000
};
for (int i = 0; i < 64; i++)
{
int r = cxa2025as_palette[i] >> 16;
int g = (cxa2025as_palette[i] & 0xff00) >> 8;
int b = cxa2025as_palette[i] & 0xff;
FCEUD_SetPalette(i, r, g, b);
FCEUD_SetPalette(i + 64, r, g, b);
FCEUD_SetPalette(i + 128, r, g, b);
FCEUD_SetPalette(i + 192, r, g, b);
}
}
else if ([displayMode isEqualToString:@"Smooth (FBX)"])
{
unsigned int smoothfbx_palette[64] =
{
0x6A6D6A, 0x001380, 0x1E008A, 0x39007A,
0x550056, 0x5A0018, 0x4F1000, 0x3D1C00,
0x253200, 0x003D00, 0x004000, 0x003924,
0x002E55, 0x000000, 0x000000, 0x000000,
0xB9BCB9, 0x1850C7, 0x4B30E3, 0x7322D6,
0x951FA9, 0x9D285C, 0x983700, 0x7F4C00,
0x5E6400, 0x227700, 0x027E02, 0x007645,
0x006E8A, 0x000000, 0x000000, 0x000000,
0xFFFFFF, 0x68A6FF, 0x8C9CFF, 0xB586FF,
0xD975FD, 0xE377B9, 0xE58D68, 0xD49D29,
0xB3AF0C, 0x7BC211, 0x55CA47, 0x46CB81,
0x47C1C5, 0x4A4D4A, 0x000000, 0x000000,
0xFFFFFF, 0xCCEAFF, 0xDDDEFF, 0xECDAFF,
0xF8D7FE, 0xFCD6F5, 0xFDDBCF, 0xF9E7B5,
0xF1F0AA, 0xDAFAA9, 0xC9FFBC, 0xC3FBD7,
0xC4F6F6, 0xBEC1BE, 0x000000, 0x000000
};
for (int i = 0; i < 64; i++)
{
int r = smoothfbx_palette[i] >> 16;
int g = (smoothfbx_palette[i] & 0xff00) >> 8;
int b = smoothfbx_palette[i] & 0xff;
FCEUD_SetPalette(i, r, g, b);
FCEUD_SetPalette(i + 64, r, g, b);
FCEUD_SetPalette(i + 128, r, g, b);
FCEUD_SetPalette(i + 192, r, g, b);
}
}
else if ([displayMode isEqualToString:@"Wavebeam"])
{
unsigned int wavebeam_palette[64] =
{
0x6B6B6B, 0x001B88, 0x21009A, 0x40008C,
0x600067, 0x64001E, 0x590800, 0x481600,
0x283600, 0x004500, 0x004908, 0x00421D,
0x003659, 0x000000, 0x000000, 0x000000,
0xB4B4B4, 0x1555D3, 0x4337EF, 0x7425DF,
0x9C19B9, 0xAC0F64, 0xAA2C00, 0x8A4B00,
0x666B00, 0x218300, 0x008A00, 0x008144,
0x007691, 0x000000, 0x000000, 0x000000,
0xFFFFFF, 0x63B2FF, 0x7C9CFF, 0xC07DFE,
0xE977FF, 0xF572CD, 0xF4886B, 0xDDA029,
0xBDBD0A, 0x89D20E, 0x5CDE3E, 0x4BD886,
0x4DCFD2, 0x525252, 0x000000, 0x000000,
0xFFFFFF, 0xBCDFFF, 0xD2D2FF, 0xE1C8FF,
0xEFC7FF, 0xFFC3E1, 0xFFCAC6, 0xF2DAAD,
0xEBE3A0, 0xD2EDA2, 0xBCF4B4, 0xB5F1CE,
0xB6ECF1, 0xBFBFBF, 0x000000, 0x000000
};
for (int i = 0; i < 64; i++)
{
int r = wavebeam_palette[i] >> 16;
int g = (wavebeam_palette[i] & 0xff00) >> 8;
int b = wavebeam_palette[i] & 0xff;
FCEUD_SetPalette(i, r, g, b);
FCEUD_SetPalette(i + 64, r, g, b);
FCEUD_SetPalette(i + 128, r, g, b);
FCEUD_SetPalette(i + 192, r, g, b);
}
}
}
- (void)loadDisplayModeOptions
{
// Restore palette
NSString *lastPalette = self.displayModeInfo[@"palette"];
if (lastPalette && ![lastPalette isEqualToString:@"Default — FCEUX"]) {
[self changeDisplayWithMode:lastPalette];
}
// Crop horizontal overscan
BOOL isHorizontalOverscanCropped = [self.displayModeInfo[@"cropHorizontalOverscan"] boolValue];
if (isHorizontalOverscanCropped) {
[self changeDisplayWithMode:@"Crop Horizontal"];
}
// Crop vertical overscan
BOOL isVerticalOverscanCropped = [self.displayModeInfo[@"cropVerticalOverscan"] boolValue];
if (isVerticalOverscanCropped) {
[self changeDisplayWithMode:@"Crop Vertical"];
}
}
// FCEUX internal functions and stubs
void FCEUD_SetPalette(unsigned char index, unsigned char r, unsigned char g, unsigned char b)
{
@@ -505,11 +819,11 @@ ArchiveScanRecord FCEUD_ScanArchive(std::string fname) { return ArchiveScanRecor
void GetMouseData(uint32 (&md)[3]) {}
void FCEUD_PrintError(const char *s)
{
NSLog(@"FCEUX error: %s", s);
NSLog(@"[FCEUX] error: %s", s);
}
void FCEUD_Message(const char *s)
{
NSLog(@"FCEUX message: %s", s);
NSLog(@"[FCEUX] message: %s", s);
}
@end
+3 -1
View File
@@ -17,7 +17,7 @@
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>2.2.3</string>
<string>2.2.3.1</string>
<key>NSPrincipalClass</key>
<string>OEGameCoreController</string>
<key>OEGameCoreClass</key>
@@ -32,6 +32,8 @@
<integer>0</integer>
<key>OEGameCoreSupportsCheatCode</key>
<true/>
<key>OEGameCoreSupportsDisplayModeChange</key>
<true/>
<key>OEGameCoreSupportsRewinding</key>
<true/>
</dict>
+1 -1
View File
@@ -216,7 +216,7 @@ void FCEU_LoadGameCheats(FILE *override)
}
FCEU_DispMessage("Cheats file loaded.",0); //Tells user a cheats file was loaded.
while(fgets(linebuf,2048,fp)>0)
while(fgets(linebuf,2048,fp) != nullptr)
{
char *tbuf=linebuf;
int doc=0;