diff --git a/AppleCommon/GBViewBase.h b/AppleCommon/GBViewBase.h new file mode 100644 index 0000000..4257b71 --- /dev/null +++ b/AppleCommon/GBViewBase.h @@ -0,0 +1,35 @@ +#include +#include + +#if TARGET_OS_IPHONE +#define NSView UIView +#import +#else +#import +#endif + +typedef enum { + GB_FRAME_BLENDING_MODE_DISABLED, + GB_FRAME_BLENDING_MODE_SIMPLE, + GB_FRAME_BLENDING_MODE_ACCURATE, + GB_FRAME_BLENDING_MODE_ACCURATE_EVEN = GB_FRAME_BLENDING_MODE_ACCURATE, + GB_FRAME_BLENDING_MODE_ACCURATE_ODD, +} GB_frame_blending_mode_t; + +@interface GBViewBase : NSView +{ + @public + GB_gameboy_t *_gb; +} + +@property (nonatomic) GB_gameboy_t *gb; +@property (nonatomic) GB_frame_blending_mode_t frameBlendingMode; +@property (nonatomic, strong) NSView *internalView; +- (void) flip; +- (uint32_t *) pixels; +- (void)screenSizeChanged; +- (void) createInternalView; +- (uint32_t *)currentBuffer; +- (uint32_t *)previousBuffer; + +@end diff --git a/AppleCommon/GBViewBase.m b/AppleCommon/GBViewBase.m new file mode 100644 index 0000000..20af0a9 --- /dev/null +++ b/AppleCommon/GBViewBase.m @@ -0,0 +1,83 @@ +#import "GBViewBase.h" + +@implementation GBViewBase +{ + uint32_t *_imageBuffers[3]; + unsigned _currentBuffer; + GB_frame_blending_mode_t _frameBlendingMode; +} + +- (void)screenSizeChanged +{ + if (_imageBuffers[0]) free(_imageBuffers[0]); + if (_imageBuffers[1]) free(_imageBuffers[1]); + if (_imageBuffers[2]) free(_imageBuffers[2]); + + size_t buffer_size = sizeof(_imageBuffers[0][0]) * GB_get_screen_width(_gb) * GB_get_screen_height(_gb); + + _imageBuffers[0] = calloc(1, buffer_size); + _imageBuffers[1] = calloc(1, buffer_size); + _imageBuffers[2] = calloc(1, buffer_size); +} + +- (void)flip +{ + _currentBuffer = (_currentBuffer + 1) % self.numberOfBuffers; +} + +- (unsigned) numberOfBuffers +{ + return _frameBlendingMode? 3 : 2; +} + +- (void) createInternalView +{ + assert(false && "createInternalView must not be inherited"); +} + +- (uint32_t *)currentBuffer +{ + return _imageBuffers[_currentBuffer]; +} + +- (uint32_t *)previousBuffer +{ + return _imageBuffers[(_currentBuffer + 2) % self.numberOfBuffers]; +} + +- (uint32_t *) pixels +{ + return _imageBuffers[(_currentBuffer + 1) % self.numberOfBuffers]; +} + +- (void) setFrameBlendingMode:(GB_frame_blending_mode_t)frameBlendingMode +{ + _frameBlendingMode = frameBlendingMode; + [self setNeedsDisplay]; +} + +- (GB_frame_blending_mode_t)frameBlendingMode +{ + if (_frameBlendingMode == GB_FRAME_BLENDING_MODE_ACCURATE) { + if (!_gb || GB_is_sgb(_gb)) { + return GB_FRAME_BLENDING_MODE_SIMPLE; + } + return GB_is_odd_frame(_gb)? GB_FRAME_BLENDING_MODE_ACCURATE_ODD : GB_FRAME_BLENDING_MODE_ACCURATE_EVEN; + } + return _frameBlendingMode; +} + +- (void)dealloc +{ + free(_imageBuffers[0]); + free(_imageBuffers[1]); + free(_imageBuffers[2]); +} + +#if !TARGET_OS_IPHONE +- (void)setNeedsDisplay +{ + [self setNeedsDisplay:true]; +} +#endif +@end diff --git a/AppleCommon/GBViewMetal.h b/AppleCommon/GBViewMetal.h new file mode 100644 index 0000000..2081fc7 --- /dev/null +++ b/AppleCommon/GBViewMetal.h @@ -0,0 +1,11 @@ +#include +#import +#if TARGET_OS_IPHONE +#import "../iOS/GBView.h" +#else +#import "../Cocoa/GBView.h" +#endif + +@interface GBViewMetal : GBView ++ (bool) isSupported; +@end diff --git a/Cocoa/GBViewMetal.m b/AppleCommon/GBViewMetal.m similarity index 97% rename from Cocoa/GBViewMetal.m rename to AppleCommon/GBViewMetal.m index ae7443f..6a45dab 100644 --- a/Cocoa/GBViewMetal.m +++ b/AppleCommon/GBViewMetal.m @@ -25,10 +25,14 @@ static const vector_float2 rect[] = + (bool)isSupported { +#if TARGET_OS_IPHONE + return true; +#else if (MTLCopyAllDevices) { return [MTLCopyAllDevices() count]; } return false; +#endif } - (void) allocateTextures @@ -135,7 +139,9 @@ static const vector_float2 rect[] = - (void)drawInMTKView:(MTKView *)view { +#if !TARGET_OS_IPHONE if (!(view.window.occlusionState & NSWindowOcclusionStateVisible)) return; +#endif if (!self.gb) return; if (texture.width != GB_get_screen_width(self.gb) || texture.height != GB_get_screen_height(self.gb)) { @@ -161,7 +167,7 @@ static const vector_float2 rect[] = MTLRenderPassDescriptor *render_pass_descriptor = view.currentRenderPassDescriptor; id command_buffer = [command_queue commandBuffer]; - if (render_pass_descriptor != nil) { + if (render_pass_descriptor) { *(GB_frame_blending_mode_t *)[frame_blending_mode_buffer contents] = [self frameBlendingMode]; *(vector_float2 *)[output_resolution_buffer contents] = output_resolution; @@ -210,10 +216,15 @@ static const vector_float2 rect[] = { [super flip]; dispatch_async(dispatch_get_main_queue(), ^{ +#if TARGET_OS_IPHONE + [(MTKView *)self.internalView setNeedsDisplay]; +#else [(MTKView *)self.internalView setNeedsDisplay:true]; +#endif }); } +#if !TARGET_OS_IPHONE - (NSImage *)renderToImage { CIImage *ciImage = [CIImage imageWithMTLTexture:[[(MTKView *)self.internalView currentDrawable] texture] @@ -228,5 +239,6 @@ static const vector_float2 rect[] = CGImageRelease(cgImage); return ret; } +#endif @end diff --git a/Cocoa/GBView.h b/Cocoa/GBView.h index a264d29..eff3268 100644 --- a/Cocoa/GBView.h +++ b/Cocoa/GBView.h @@ -1,32 +1,16 @@ #import -#include #import #import "GBOSDView.h" +#import "GBViewBase.h" + @class Document; -typedef enum { - GB_FRAME_BLENDING_MODE_DISABLED, - GB_FRAME_BLENDING_MODE_SIMPLE, - GB_FRAME_BLENDING_MODE_ACCURATE, - GB_FRAME_BLENDING_MODE_ACCURATE_EVEN = GB_FRAME_BLENDING_MODE_ACCURATE, - GB_FRAME_BLENDING_MODE_ACCURATE_ODD, -} GB_frame_blending_mode_t; - -@interface GBView : NSView -- (void) flip; -- (uint32_t *) pixels; +@interface GBView : GBViewBase @property (nonatomic, weak) IBOutlet Document *document; -@property (nonatomic) GB_gameboy_t *gb; -@property (nonatomic) GB_frame_blending_mode_t frameBlendingMode; @property (nonatomic, getter=isMouseHidingEnabled) bool mouseHidingEnabled; @property (nonatomic) bool isRewinding; -@property (nonatomic, strong) NSView *internalView; @property (weak) GBOSDView *osdView; -- (void) createInternalView; -- (uint32_t *)currentBuffer; -- (uint32_t *)previousBuffer; -- (void)screenSizeChanged; -- (void)setRumble: (double)amp; - (NSImage *)renderToImage; +- (void)setRumble: (double)amp; @end diff --git a/Cocoa/GBView.m b/Cocoa/GBView.m index 65b807c..5ed5e10 100644 --- a/Cocoa/GBView.m +++ b/Cocoa/GBView.m @@ -104,8 +104,6 @@ static const uint8_t workboy_vk_to_key[] = { @implementation GBView { - uint32_t *image_buffers[3]; - unsigned char current_buffer; bool mouse_hidden; NSTrackingArea *tracking_area; bool _mouseHidingEnabled; @@ -116,7 +114,6 @@ static const uint8_t workboy_vk_to_key[] = { bool analogClockMultiplierValid; NSEventModifierFlags previousModifiers; JOYController *lastController; - GB_frame_blending_mode_t _frameBlendingMode; bool _turbo; bool _mouseControlEnabled; } @@ -137,11 +134,6 @@ static const uint8_t workboy_vk_to_key[] = { return [super allocWithZone:zone]; } -- (void) createInternalView -{ - assert(false && "createInternalView must not be inherited"); -} - - (void) _init { [self registerForDraggedTypes:[NSArray arrayWithObjects: NSFilenamesPboardType, nil]]; @@ -162,15 +154,7 @@ static const uint8_t workboy_vk_to_key[] = { - (void)screenSizeChanged { - if (image_buffers[0]) free(image_buffers[0]); - if (image_buffers[1]) free(image_buffers[1]); - if (image_buffers[2]) free(image_buffers[2]); - - size_t buffer_size = sizeof(image_buffers[0][0]) * GB_get_screen_width(_gb) * GB_get_screen_height(_gb); - - image_buffers[0] = calloc(1, buffer_size); - image_buffers[1] = calloc(1, buffer_size); - image_buffers[2] = calloc(1, buffer_size); + [super screenSizeChanged]; dispatch_async(dispatch_get_main_queue(), ^{ [self setFrame:self.superview.frame]; @@ -182,33 +166,8 @@ static const uint8_t workboy_vk_to_key[] = { [self setFrame:self.superview.frame]; } -- (void) setFrameBlendingMode:(GB_frame_blending_mode_t)frameBlendingMode -{ - _frameBlendingMode = frameBlendingMode; - [self setNeedsDisplay:true]; -} - - -- (GB_frame_blending_mode_t)frameBlendingMode -{ - if (_frameBlendingMode == GB_FRAME_BLENDING_MODE_ACCURATE) { - if (!_gb || GB_is_sgb(_gb)) { - return GB_FRAME_BLENDING_MODE_SIMPLE; - } - return GB_is_odd_frame(_gb)? GB_FRAME_BLENDING_MODE_ACCURATE_ODD : GB_FRAME_BLENDING_MODE_ACCURATE_EVEN; - } - return _frameBlendingMode; -} -- (unsigned char) numberOfBuffers -{ - return _frameBlendingMode? 3 : 2; -} - - (void)dealloc { - free(image_buffers[0]); - free(image_buffers[1]); - free(image_buffers[2]); if (mouse_hidden) { mouse_hidden = false; [NSCursor unhide]; @@ -217,6 +176,7 @@ static const uint8_t workboy_vk_to_key[] = { [self setRumble:0]; [JOYController unregisterListener:self]; } + - (instancetype)initWithCoder:(NSCoder *)coder { if (!(self = [super initWithCoder:coder])) { @@ -301,12 +261,7 @@ static const uint8_t workboy_vk_to_key[] = { (analogClockMultiplierValid && analogClockMultiplier < 1)) { [self.osdView displayText:@"Slow motion..."]; } - current_buffer = (current_buffer + 1) % self.numberOfBuffers; -} - -- (uint32_t *) pixels -{ - return image_buffers[(current_buffer + 1) % self.numberOfBuffers]; + [super flip]; } -(void)keyDown:(NSEvent *)theEvent @@ -760,16 +715,6 @@ static const uint8_t workboy_vk_to_key[] = { previousModifiers = event.modifierFlags; } -- (uint32_t *)currentBuffer -{ - return image_buffers[current_buffer]; -} - -- (uint32_t *)previousBuffer -{ - return image_buffers[(current_buffer + 2) % self.numberOfBuffers]; -} - -(NSDragOperation)draggingEntered:(id)sender { NSPasteboard *pboard = [sender draggingPasteboard]; diff --git a/Cocoa/GBViewMetal.h b/Cocoa/GBViewMetal.h deleted file mode 100644 index 521c3c7..0000000 --- a/Cocoa/GBViewMetal.h +++ /dev/null @@ -1,7 +0,0 @@ -#import -#import -#import "GBView.h" - -@interface GBViewMetal : GBView -+ (bool) isSupported; -@end diff --git a/iOS/GBView.h b/iOS/GBView.h new file mode 100644 index 0000000..f30cf5a --- /dev/null +++ b/iOS/GBView.h @@ -0,0 +1,5 @@ +#import "GBViewBase.h" + +@interface GBView : GBViewBase + +@end diff --git a/iOS/GBView.m b/iOS/GBView.m new file mode 100644 index 0000000..40e08b3 --- /dev/null +++ b/iOS/GBView.m @@ -0,0 +1,12 @@ +#import "GBView.h" + +@implementation GBView +- (instancetype)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + [self createInternalView]; + [self addSubview:self.internalView]; + self.internalView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + return self; +} +@end diff --git a/iOS/GBViewController.m b/iOS/GBViewController.m index 98b50c2..4933812 100644 --- a/iOS/GBViewController.m +++ b/iOS/GBViewController.m @@ -1,6 +1,8 @@ #import "GBViewController.h" #import "GBHorizontalLayout.h" #import "GBVerticalLayout.h" +#import "GBViewMetal.h" +#include static void positionView(UIImageView *view, CGPoint position) { @@ -26,6 +28,8 @@ static void positionView(UIImageView *view, CGPoint position) UIImageView *_bButtonView; UIImageView *_startButtonView; UIImageView *_selectButtonView; + GBView *_gbView; + GB_gameboy_t _gb; } - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions @@ -33,36 +37,42 @@ static void positionView(UIImageView *view, CGPoint position) _window = [[UIWindow alloc] init]; _window.rootViewController = self; [_window makeKeyAndVisible]; + + _window.backgroundColor = [UIColor colorWithRed:174 / 255.0 green:176 / 255.0 blue:180 / 255.0 alpha:1.0]; + _horizontalLayout = [[GBHorizontalLayout alloc] init]; _verticalLayout = [[GBVerticalLayout alloc] init]; _backgroundView = [[UIImageView alloc] initWithImage:nil]; [_window addSubview:_backgroundView]; + self.view = _backgroundView; _dpadView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"dpad"]]; _aButtonView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"button"]]; _bButtonView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"button"]]; _startButtonView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"button2"]]; _selectButtonView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"button2"]]; + _gbView = [[GBViewMetal alloc] initWithFrame:CGRectZero]; + + GB_init(&_gb, GB_MODEL_CGB_E); + _gbView.gb = &_gb; + [_gbView screenSizeChanged]; + + [self willRotateToInterfaceOrientation:[UIApplication sharedApplication].statusBarOrientation + duration:0]; [_backgroundView addSubview:_dpadView]; [_backgroundView addSubview:_aButtonView]; [_backgroundView addSubview:_bButtonView]; [_backgroundView addSubview:_startButtonView]; [_backgroundView addSubview:_selectButtonView]; + [_backgroundView addSubview:_gbView]; - [self orientationChange]; - - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(orientationChange) - name:UIApplicationDidChangeStatusBarOrientationNotification - object:nil]; return true; } -- (void)orientationChange +- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)orientation duration:(NSTimeInterval)duration { - UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation; if (orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown) { _currentLayout = _verticalLayout; } @@ -78,6 +88,16 @@ static void positionView(UIImageView *view, CGPoint position) positionView(_bButtonView, _currentLayout.bLocation); positionView(_startButtonView, _currentLayout.startLocation); positionView(_selectButtonView, _currentLayout.selectLocation); + + CGRect screenFrame = _currentLayout.screenRect; + screenFrame.origin.x /= [UIScreen mainScreen].scale; + screenFrame.origin.y /= [UIScreen mainScreen].scale; + screenFrame.size.width /= [UIScreen mainScreen].scale; + screenFrame.size.height /= [UIScreen mainScreen].scale; + + _gbView.frame = screenFrame; + memset(_gbView.pixels, rand(), 160 * 144 * 4); + [_gbView flip]; } - (BOOL)prefersHomeIndicatorAutoHidden