all repos — mgba @ 342b02134db8e3cec36ea6db26be3296a4cd109e

mGBA Game Boy Advance Emulator

OpenEmu: Start the OpenEmu core
Jeffrey Pfau jeffrey@endrift.com
Fri, 01 Jan 2016 21:57:46 -0800
commit

342b02134db8e3cec36ea6db26be3296a4cd109e

parent

29556f45a4a1753c5cab239c26b5b8c1cd4e1d78

M CMakeLists.txtCMakeLists.txt

@@ -18,6 +18,7 @@ set(USE_LZMA ON CACHE BOOL "Whether or not to enable 7-Zip support")

set(BUILD_QT ON CACHE BOOL "Build Qt frontend") set(BUILD_SDL ON CACHE BOOL "Build SDL frontend") set(BUILD_LIBRETRO OFF CACHE BOOL "Build libretro core") +set(BUILD_OPENEMU OFF CACHE BOOL "Build OpenEmu core") set(BUILD_PERF OFF CACHE BOOL "Build performance profiling tool") set(BUILD_TEST OFF CACHE BOOL "Build testing harness") set(BUILD_STATIC OFF CACHE BOOL "Build a static library")

@@ -556,6 +557,21 @@ add_library(${BINARY_NAME}_libretro SHARED ${CORE_SRC} ${RETRO_SRC})

set_target_properties(${BINARY_NAME}_libretro PROPERTIES PREFIX "" COMPILE_DEFINITIONS "COLOR_16_BIT;COLOR_5_6_5;DISABLE_THREADING;${OS_DEFINES};${FUNCTION_DEFINES};MINIMAL_CORE=2") target_link_libraries(${BINARY_NAME}_libretro ${OS_LIB}) install(TARGETS ${BINARY_NAME}_libretro LIBRARY DESTINATION ${LIBDIR} COMPONENT ${BINARY_NAME}_libretro NAMELINK_SKIP) +endif() + +if(BUILD_OPENEMU) + find_library(FOUNDATION Foundation) + find_library(OPENEMUBASE OpenEmuBase) + file(GLOB OE_SRC ${CMAKE_SOURCE_DIR}/src/platform/openemu/*.m) + add_library(${BINARY_NAME}-openemu MODULE ${CORE_SRC} ${OE_SRC}) + set_target_properties(${BINARY_NAME}-openemu PROPERTIES + MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/src/platform/openemu/Info.plist.in + BUNDLE TRUE + BUNDLE_EXTENSION oecoreplugin + OUTPUT_NAME ${PROJECT_NAME}EmuCore + COMPILE_DEFINITIONS "DISABLE_THREADING;${OS_DEFINES};${FUNCTION_DEFINES};MINIMAL_CORE=2") + target_link_libraries(${BINARY_NAME}-openemu ${OS_LIB} ${FOUNDATION} ${OPENEMUBASE}) + install(TARGETS ${BINARY_NAME}-openemu LIBRARY DESTINATION ${LIBDIR} COMPONENT ${BINARY_NAME}.oecoreplugin NAMELINK_SKIP) endif() if(BUILD_SDL)
A src/platform/openemu/Info.plist.in

@@ -0,0 +1,42 @@

+<?xml version="1.0" encoding="UTF-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>CFBundleDevelopmentRegion</key> + <string>English</string> + <key>CFBundleExecutable</key> + <string>${EXECUTABLE_NAME}</string> + <key>CFBundleIconFile</key> + <string>mGBA</string> + <key>CFBundleIdentifier</key> + <string>com.endrift.mgba</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> + <key>CFBundlePackageType</key> + <string>BNDL</string> + <key>CFBundleSignature</key> + <string>????</string> + <key>CFBundleVersion</key> + <string>1.8.0.1232</string> + <key>NSPrincipalClass</key> + <string>OEGameCoreController</string> + <key>OEGameCoreClass</key> + <string>mGBAGameCore</string> + <key>OEGameCoreOptions</key> + <dict> + <key>openemu.system.gba</key> + </dict> + <key>OEGameCorePlayerCount</key> + <string>1</string> + <key>OEProjectURL</key> + <string>https://mgba.io/</string> + <key>OESystemIdentifiers</key> + <array> + <string>openemu.system.gba</string> + </array> + <key>SUEnableAutomaticChecks</key> + <string>1</string> + <key>SUFeedURL</key> + <string>https://raw.github.com/OpenEmu/OpenEmu-Update/master/mgba_appcast.xml</string> +</dict> +</plist>
A src/platform/openemu/OEGBASystemResponderClient.h

@@ -0,0 +1,51 @@

+/* + Copyright (c) 2011, OpenEmu Team + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the OpenEmu Team nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY OpenEmu Team ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL OpenEmu Team BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import <Cocoa/Cocoa.h> + +@protocol OESystemResponderClient; + +typedef enum _OEGBAButton +{ + OEGBAButtonUp, + OEGBAButtonDown, + OEGBAButtonLeft, + OEGBAButtonRight, + OEGBAButtonA, + OEGBAButtonB, + OEGBAButtonL, + OEGBAButtonR, + OEGBAButtonStart, + OEGBAButtonSelect, + OEGBAButtonCount +} OEGBAButton; + +@protocol OEGBASystemResponderClient <OESystemResponderClient, NSObject> + +- (oneway void)didPushGBAButton:(OEGBAButton)button forPlayer:(NSUInteger)player; +- (oneway void)didReleaseGBAButton:(OEGBAButton)button forPlayer:(NSUInteger)player; + +@end
A src/platform/openemu/mGBAGameCore.h

@@ -0,0 +1,6 @@

+#import <Cocoa/Cocoa.h> +#import <OpenEmuBase/OEGameCore.h> + +OE_EXPORTED_CLASS +@interface mGBAGameCore : OEGameCore +@end
A src/platform/openemu/mGBAGameCore.m

@@ -0,0 +1,251 @@

+/* + Copyright (c) 2016, Jeffrey Pfau + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ''AS IS'' + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + */ + +#import "mGBAGameCore.h" + +#include "util/common.h" + +#include "gba/cheats.h" +#include "gba/renderers/video-software.h" +#include "gba/serialize.h" +#include "gba/context/context.h" +#include "util/circle-buffer.h" +#include "util/memory.h" +#include "util/vfs.h" + +#import <OpenEmuBase/OERingBuffer.h> +#import "OEGBASystemResponderClient.h" +#import <OpenGL/gl.h> + +#define SAMPLES 1024 + +@interface mGBAGameCore () <OEGBASystemResponderClient> +{ + struct GBAContext context; + struct GBAVideoSoftwareRenderer renderer; + struct GBACheatDevice cheats; + struct GBACheatSet cheatSet; + uint16_t keys; +} +@end + +@implementation mGBAGameCore + +- (id)init +{ + if ((self = [super init])) + { + // TODO: Add a log handler + GBAContextInit(&context, 0); + struct GBAOptions opts = { + .useBios = true, + .idleOptimization = IDLE_LOOP_REMOVE + }; + GBAConfigLoadDefaults(&context.config, &opts); + GBAVideoSoftwareRendererCreate(&renderer); + renderer.outputBuffer = malloc(256 * VIDEO_VERTICAL_PIXELS * BYTES_PER_PIXEL); + renderer.outputBufferStride = 256; + context.renderer = &renderer.d; + GBAAudioResizeBuffer(&context.gba->audio, SAMPLES); + GBACheatDeviceCreate(&cheats); + GBACheatAttachDevice(context.gba, &cheats); + GBACheatSetInit(&cheatSet, "openemu"); + GBACheatAddSet(&cheats, &cheatSet); + keys = 0; + } + + return self; +} + +- (void)dealloc +{ + GBAContextDeinit(&context); + GBACheatRemoveSet(&cheats, &cheatSet); + GBACheatDeviceDestroy(&cheats); + GBACheatSetDeinit(&cheatSet); + free(renderer.outputBuffer); + + [super dealloc]; +} + +#pragma mark - Execution + +- (BOOL)loadFileAtPath:(NSString *)path error:(NSError **)error +{ + UNUSED(error); + if (!GBAContextLoadROM(&context, [path UTF8String], true)) { + return NO; + } + GBAContextStart(&context); + return YES; +} + +- (void)executeFrame +{ + GBAContextFrame(&context, keys); + + int16_t samples[SAMPLES * 2]; + size_t available = 0; +#if RESAMPLE_LIBRARY == RESAMPLE_BLIP_BUF + available = blip_samples_avail(context.gba->audio.left); + blip_read_samples(context.gba->audio.left, samples, available, true); + blip_read_samples(context.gba->audio.right, samples + 1, available, true); +#else +#error BLIP_BUF is required for now +#endif + [[self ringBufferAtIndex:0] write:samples maxLength:available * 4]; +} + +- (void)resetEmulation +{ + ARMReset(context.cpu); +} + +- (void)stopEmulation +{ + NSLog(@"Stopping"); + GBAContextStop(&context); + [super stopEmulation]; +} + +- (void)setupEmulation +{ +#if RESAMPLE_LIBRARY == RESAMPLE_BLIP_BUF + blip_set_rates(context.gba->audio.left, GBA_ARM7TDMI_FREQUENCY, 32768); + blip_set_rates(context.gba->audio.right, GBA_ARM7TDMI_FREQUENCY, 32768); +#endif +} + +#pragma mark - Video + +- (OEIntSize)aspectSize +{ + return OEIntSizeMake(3, 2); +} + +- (OEIntRect)screenRect +{ + return OEIntRectMake(0, 0, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS); +} + +- (OEIntSize)bufferSize +{ + return OEIntSizeMake(256, VIDEO_VERTICAL_PIXELS); +} + +- (const void *)videoBuffer +{ + return renderer.outputBuffer; +} + +- (GLenum)pixelFormat +{ + return GL_RGBA; +} + +- (GLenum)pixelType +{ + return GL_UNSIGNED_INT_8_8_8_8_REV; +} + +- (GLenum)internalPixelFormat +{ + return GL_RGB8; +} + +- (NSTimeInterval)frameInterval +{ + return GBA_ARM7TDMI_FREQUENCY / (double) VIDEO_TOTAL_LENGTH; +} + +#pragma mark - Audio + +- (NSUInteger)channelCount +{ + return 2; +} + +- (double)audioSampleRate +{ + return 32768; +} + +#pragma mark - Save State + +- (NSData *)serializeStateWithError:(NSError **)outError +{ + UNUSED(outError); + // TODO memory VFile that self-manages memory + return nil; +} + +- (BOOL)deserializeState:(NSData *)state withError:(NSError **)outError +{ + UNUSED(outError); + // TODO VFileFromConstMemory + struct VFile* vf = VFileFromMemory((void*) state.bytes, state.length); + return GBALoadStateNamed(context.gba, vf, 0); +} + +- (void)saveStateToFileAtPath:(NSString *)fileName completionHandler:(void (^)(BOOL, NSError *))block +{ + struct VFile* vf = VFileOpen([fileName UTF8String], O_CREAT | O_TRUNC | O_RDWR); + block(GBASaveStateNamed(context.gba, vf, 0), nil); +} + +- (void)loadStateFromFileAtPath:(NSString *)fileName completionHandler:(void (^)(BOOL, NSError *))block +{ + struct VFile* vf = VFileOpen([fileName UTF8String], O_RDONLY); + block(GBALoadStateNamed(context.gba, vf, 0), nil); +} + +#pragma mark - Input + +const int GBAMap[] = { + GBA_KEY_UP, + GBA_KEY_DOWN, + GBA_KEY_LEFT, + GBA_KEY_RIGHT, + GBA_KEY_A, + GBA_KEY_B, + GBA_KEY_L, + GBA_KEY_R, + GBA_KEY_START, + GBA_KEY_SELECT +}; + +- (oneway void)didPushGBAButton:(OEGBAButton)button forPlayer:(NSUInteger)player +{ + UNUSED(player); + keys |= 1 << GBAMap[button]; +} + +- (oneway void)didReleaseGBAButton:(OEGBAButton)button forPlayer:(NSUInteger)player +{ + UNUSED(player); + keys &= ~(1 << GBAMap[button]); +} + +@end +