mirror of
https://github.com/libretro/FBNeo.git
synced 2024-11-27 02:50:29 +00:00
Added video rendering
This commit is contained in:
parent
fdc1141f4c
commit
501d815a31
@ -975,7 +975,8 @@
|
||||
FE1B287B23561A7A0065200C /* sshot.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE1B239E23561A750065200C /* sshot.cpp */; };
|
||||
FE1B288F23562B360065200C /* m68kops.c in Sources */ = {isa = PBXBuildFile; fileRef = FE1B288E23562B360065200C /* m68kops.c */; };
|
||||
FEA5E79223563F5400DA2D9D /* misc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FEA5E79023563F5400DA2D9D /* misc.cpp */; };
|
||||
FEA5E79A2356472200DA2D9D /* vid_macos.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FEA5E7992356472200DA2D9D /* vid_macos.cpp */; };
|
||||
FEC5D3D6235C136F00ABA9FB /* FBVideo.mm in Sources */ = {isa = PBXBuildFile; fileRef = FEC5D3D5235C136F00ABA9FB /* FBVideo.mm */; };
|
||||
FEC5D3D9235C160600ABA9FB /* FBScreenView.mm in Sources */ = {isa = PBXBuildFile; fileRef = FEC5D3D8235C160600ABA9FB /* FBScreenView.mm */; };
|
||||
FEED9DCA2356EF5000B7AF83 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FEED9DC92356EF4F00B7AF83 /* OpenGL.framework */; };
|
||||
FEED9DD12356F0B900B7AF83 /* SDL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FEED9DCF2356F07500B7AF83 /* SDL.framework */; };
|
||||
FEED9DD22356F0B900B7AF83 /* SDL.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = FEED9DCF2356F07500B7AF83 /* SDL.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
@ -2465,7 +2466,6 @@
|
||||
FE1B288D23562B350065200C /* m68kops.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = m68kops.h; sourceTree = "<group>"; };
|
||||
FE1B288E23562B360065200C /* m68kops.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = m68kops.c; sourceTree = "<group>"; };
|
||||
FEA5E79023563F5400DA2D9D /* misc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = misc.cpp; sourceTree = "<group>"; };
|
||||
FEA5E7992356472200DA2D9D /* vid_macos.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = vid_macos.cpp; sourceTree = "<group>"; };
|
||||
FEA5E79C23564A3200DA2D9D /* cave_tile_func.pl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.perl; path = cave_tile_func.pl; sourceTree = "<group>"; };
|
||||
FEA5E7AE23564A6400DA2D9D /* cave_sprite_func.pl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.perl; path = cave_sprite_func.pl; sourceTree = "<group>"; };
|
||||
FEA5E7B623566E7600DA2D9D /* cave_tile_func_table.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cave_tile_func_table.h; sourceTree = "<group>"; };
|
||||
@ -2475,6 +2475,10 @@
|
||||
FEA5E7BD2356721800DA2D9D /* neo_sprite_func.pl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.perl; path = neo_sprite_func.pl; sourceTree = "<group>"; };
|
||||
FEA5E7BE2356721800DA2D9D /* psikyo_tile_func.pl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.perl; path = psikyo_tile_func.pl; sourceTree = "<group>"; };
|
||||
FEA5E7BF2356721900DA2D9D /* toa_gp9001_func.pl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.perl; path = toa_gp9001_func.pl; sourceTree = "<group>"; };
|
||||
FEC5D3D4235C136E00ABA9FB /* FBVideo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBVideo.h; sourceTree = "<group>"; };
|
||||
FEC5D3D5235C136F00ABA9FB /* FBVideo.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FBVideo.mm; sourceTree = "<group>"; };
|
||||
FEC5D3D7235C160600ABA9FB /* FBScreenView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBScreenView.h; sourceTree = "<group>"; };
|
||||
FEC5D3D8235C160600ABA9FB /* FBScreenView.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FBScreenView.mm; sourceTree = "<group>"; };
|
||||
FEED9DC22356DDA900B7AF83 /* gamelist.pl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.perl; path = gamelist.pl; sourceTree = "<group>"; };
|
||||
FEED9DC92356EF4F00B7AF83 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; };
|
||||
FEED9DCF2356F07500B7AF83 /* SDL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDL.framework; path = ../../../../../../Library/Frameworks/SDL.framework; sourceTree = "<group>"; };
|
||||
@ -4617,7 +4621,10 @@
|
||||
FEA5E7982356472200DA2D9D /* macos */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FEA5E7992356472200DA2D9D /* vid_macos.cpp */,
|
||||
FEC5D3D7235C160600ABA9FB /* FBScreenView.h */,
|
||||
FEC5D3D8235C160600ABA9FB /* FBScreenView.mm */,
|
||||
FEC5D3D4235C136E00ABA9FB /* FBVideo.h */,
|
||||
FEC5D3D5235C136F00ABA9FB /* FBVideo.mm */,
|
||||
);
|
||||
path = macos;
|
||||
sourceTree = "<group>";
|
||||
@ -4929,6 +4936,7 @@
|
||||
FEED9E0623576DD800B7AF83 /* ips_manager.cpp in Sources */,
|
||||
FE1B272123561A780065200C /* d_bogeyman.cpp in Sources */,
|
||||
FE1B24B323561A750065200C /* d_m72.cpp in Sources */,
|
||||
FEC5D3D6235C136F00ABA9FB /* FBVideo.mm in Sources */,
|
||||
FE1B268D23561A770065200C /* d_thief.cpp in Sources */,
|
||||
FE1B266A23561A770065200C /* tc0280grd.cpp in Sources */,
|
||||
FE1B254823561A760065200C /* d_dooyong.cpp in Sources */,
|
||||
@ -5327,6 +5335,7 @@
|
||||
FE1B26FF23561A780065200C /* d_seicross.cpp in Sources */,
|
||||
FE1B245B23561A750065200C /* gzwrite.c in Sources */,
|
||||
FE1B278223561A790065200C /* tms5110.cpp in Sources */,
|
||||
FEC5D3D9235C160600ABA9FB /* FBScreenView.mm in Sources */,
|
||||
FE1B26A223561A770065200C /* d_snk.cpp in Sources */,
|
||||
FE1B271723561A780065200C /* d_travrusa.cpp in Sources */,
|
||||
FE1B242523561A750065200C /* Lzma2Dec.c in Sources */,
|
||||
@ -5506,7 +5515,6 @@
|
||||
FE1B26B623561A770065200C /* d_mrdo.cpp in Sources */,
|
||||
FE1B27DD23561A790065200C /* mathbox.cpp in Sources */,
|
||||
FE1B268E23561A770065200C /* d_bionicc.cpp in Sources */,
|
||||
FEA5E79A2356472200DA2D9D /* vid_macos.cpp in Sources */,
|
||||
FE1B24BF23561A750065200C /* smssystem.cpp in Sources */,
|
||||
FE1B267623561A770065200C /* taito_ic.cpp in Sources */,
|
||||
FE1B26BF23561A770065200C /* d_wallc.cpp in Sources */,
|
||||
|
@ -8,7 +8,16 @@
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface AppDelegate : NSObject <NSApplicationDelegate>
|
||||
#import "FBScreenView.h"
|
||||
@class FBVideo;
|
||||
|
||||
@interface AppDelegate : NSObject <NSApplicationDelegate, FBScreenViewDelegate>
|
||||
{
|
||||
IBOutlet FBScreenView *screen;
|
||||
}
|
||||
|
||||
+ (AppDelegate *) sharedInstance;
|
||||
|
||||
@property (readonly) FBVideo *video;
|
||||
|
||||
@end
|
||||
|
@ -1,4 +1,4 @@
|
||||
//(
|
||||
//
|
||||
// AppDelegate.m
|
||||
// FinalBurnNeo
|
||||
//
|
||||
@ -9,21 +9,38 @@
|
||||
#import "AppDelegate.h"
|
||||
|
||||
#import "FBMainThread.h"
|
||||
#import "FBVideo.h"
|
||||
|
||||
@interface AppDelegate ()
|
||||
|
||||
@property (weak) IBOutlet NSWindow *window;
|
||||
|
||||
- (NSSize) gameScreenSize;
|
||||
|
||||
@end
|
||||
|
||||
static AppDelegate *sharedInstance = nil;
|
||||
|
||||
@implementation AppDelegate
|
||||
{
|
||||
FBMainThread *main;
|
||||
BOOL _cursorVisible;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
screen.delegate = nil;
|
||||
}
|
||||
|
||||
- (void) awakeFromNib
|
||||
{
|
||||
sharedInstance = self;
|
||||
_video = [FBVideo new];
|
||||
main = [FBMainThread new];
|
||||
|
||||
_cursorVisible = YES;
|
||||
screen.delegate = self;
|
||||
_video.delegate = screen;
|
||||
}
|
||||
|
||||
- (void) applicationDidFinishLaunching:(NSNotification *)aNotification {
|
||||
@ -42,6 +59,47 @@
|
||||
[main cancel];
|
||||
}
|
||||
|
||||
- (NSSize) windowWillResize:(NSWindow *) sender
|
||||
toSize:(NSSize) frameSize
|
||||
{
|
||||
NSSize screenSize = [self gameScreenSize];
|
||||
NSRect windowFrame = [[self window] frame];
|
||||
NSView *contentView = [[self window] contentView];
|
||||
NSRect viewRect = [contentView convertRect:[contentView bounds]
|
||||
toView:nil];
|
||||
NSRect contentRect = [[self window] contentRectForFrameRect:windowFrame];
|
||||
|
||||
CGFloat screenRatio = screenSize.width / screenSize.height;
|
||||
|
||||
float marginY = viewRect.origin.y + windowFrame.size.height - contentRect.size.height;
|
||||
float marginX = contentRect.size.width - viewRect.size.width;
|
||||
|
||||
// Clamp the minimum height
|
||||
if ((frameSize.height - marginY) < screenSize.height) {
|
||||
frameSize.height = screenSize.height + marginY;
|
||||
}
|
||||
|
||||
// Set the screen width as a percentage of the screen height
|
||||
frameSize.width = (frameSize.height - marginY) * screenRatio + marginX;
|
||||
|
||||
return frameSize;
|
||||
}
|
||||
|
||||
- (void) windowDidResize:(NSNotification *) notification
|
||||
{
|
||||
NSSize screenSize = [self gameScreenSize];
|
||||
if (screenSize.width != 0 && screenSize.height != 0) {
|
||||
NSRect windowFrame = [[self window] frame];
|
||||
NSRect contentRect = [[self window] contentRectForFrameRect:windowFrame];
|
||||
|
||||
NSString *screenSizeString = NSStringFromSize(screenSize);
|
||||
NSString *actualSizeString = NSStringFromSize(contentRect.size);
|
||||
|
||||
[[NSUserDefaults standardUserDefaults] setObject:actualSizeString
|
||||
forKey:[@"preferredSize-" stringByAppendingString:screenSizeString]];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL) applicationShouldTerminateAfterLastWindowClosed:(NSApplication *) sender
|
||||
{
|
||||
return YES;
|
||||
@ -54,4 +112,38 @@
|
||||
return YES;
|
||||
}
|
||||
|
||||
+ (AppDelegate *) sharedInstance
|
||||
{
|
||||
return sharedInstance;
|
||||
}
|
||||
|
||||
#pragma mark - FBScreenViewDelegate
|
||||
|
||||
- (void) mouseDidIdle
|
||||
{
|
||||
if (_cursorVisible) {
|
||||
_cursorVisible = NO;
|
||||
[NSCursor hide];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) mouseStateDidChange
|
||||
{
|
||||
if (!_cursorVisible) {
|
||||
_cursorVisible = YES;
|
||||
[NSCursor unhide];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
extern int BurnDrvGetVisibleSize(int* pnWidth, int* pnHeight);
|
||||
|
||||
- (NSSize) gameScreenSize
|
||||
{
|
||||
int w, h;
|
||||
BurnDrvGetVisibleSize(&w, &h);
|
||||
return NSMakeSize(w, h);
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -12,9 +12,10 @@
|
||||
</connections>
|
||||
</customObject>
|
||||
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||
<customObject id="-3" userLabel="Application"/>
|
||||
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
||||
<customObject id="Voe-Tx-rLC" customClass="AppDelegate">
|
||||
<connections>
|
||||
<outlet property="screen" destination="Jj9-3G-U07" id="7Fv-Ip-Vmf"/>
|
||||
<outlet property="window" destination="QvC-M9-y7g" id="gIp-Ho-8D9"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
@ -689,11 +690,17 @@
|
||||
<view key="contentView" id="EiT-Mj-1SZ">
|
||||
<rect key="frame" x="0.0" y="0.0" width="480" height="360"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<openGLView wantsLayer="YES" fixedFrame="YES" colorSize="5bit_RGB_8bit_Alpha" depthSize="32bit" rendererType="accelerated" useAuxiliaryDepthBufferStencil="NO" useDoubleBufferingEnabled="YES" allowOffline="YES" useRecovery="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Jj9-3G-U07" customClass="FBScreenView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="480" height="360"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
</openGLView>
|
||||
</subviews>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="Voe-Tx-rLC" id="suI-T0-B1U"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="140" y="-120"/>
|
||||
<point key="canvasLocation" x="131" y="-153"/>
|
||||
</window>
|
||||
</objects>
|
||||
</document>
|
||||
|
26
src/intf/video/macos/FBScreenView.h
Normal file
26
src/intf/video/macos/FBScreenView.h
Normal file
@ -0,0 +1,26 @@
|
||||
// Portions from FinalBurn X: Port of FinalBurn to OS X
|
||||
// https://github.com/0xe1f/FinalBurn-X
|
||||
//
|
||||
// Copyright (C) Akop Karapetyan
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#import "FBVideo.h"
|
||||
|
||||
@protocol FBScreenViewDelegate<NSObject>
|
||||
|
||||
@optional
|
||||
- (void) mouseDidIdle;
|
||||
- (void) mouseStateDidChange;
|
||||
|
||||
@end
|
||||
|
||||
@interface FBScreenView : NSOpenGLView<FBVideoDelegate>
|
||||
|
||||
- (NSSize) screenSize;
|
||||
|
||||
@property (nonatomic, weak) id<FBScreenViewDelegate> delegate;
|
||||
|
||||
@end
|
325
src/intf/video/macos/FBScreenView.mm
Normal file
325
src/intf/video/macos/FBScreenView.mm
Normal file
@ -0,0 +1,325 @@
|
||||
// Portions from FinalBurn X: Port of FinalBurn to OS X
|
||||
// https://github.com/0xe1f/FinalBurn-X
|
||||
//
|
||||
// Copyright (C) Akop Karapetyan
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
#include <OpenGL/gl.h>
|
||||
#include <time.h>
|
||||
|
||||
#import "FBScreenView.h"
|
||||
|
||||
#define HIDE_CURSOR_TIMEOUT_SECONDS 1.0f
|
||||
|
||||
@interface FBScreenView ()
|
||||
|
||||
+ (int) powerOfTwoClosestTo:(int) number;
|
||||
- (void) resetProjection;
|
||||
- (void) handleMouseChange:(NSPoint) position;
|
||||
- (void) resetTrackingArea;
|
||||
|
||||
@end
|
||||
|
||||
@implementation FBScreenView
|
||||
{
|
||||
GLuint screenTextureId;
|
||||
unsigned char *texture;
|
||||
int imageWidth;
|
||||
int imageHeight;
|
||||
BOOL isRotated;
|
||||
int textureWidth;
|
||||
int textureHeight;
|
||||
int textureBytesPerPixel;
|
||||
NSLock *renderLock;
|
||||
NSSize screenSize;
|
||||
CFAbsoluteTime _lastMouseAction;
|
||||
NSPoint _lastCursorPosition;
|
||||
NSTrackingArea *_trackingArea;
|
||||
NSRect viewBounds; // Access from non-UI thread
|
||||
}
|
||||
|
||||
#pragma mark - Initialize, Dealloc
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
glDeleteTextures(1, &screenTextureId);
|
||||
free(self->texture);
|
||||
}
|
||||
|
||||
- (void) awakeFromNib
|
||||
{
|
||||
self->renderLock = [[NSLock alloc] init];
|
||||
_lastMouseAction = CFAbsoluteTimeGetCurrent();
|
||||
_lastCursorPosition = NSMakePoint(-1, -1);
|
||||
|
||||
[self resetTrackingArea];
|
||||
}
|
||||
|
||||
#pragma mark - Cocoa Callbacks
|
||||
|
||||
- (void) prepareOpenGL
|
||||
{
|
||||
[super prepareOpenGL];
|
||||
|
||||
NSLog(@"FBScreenView/prepareOpenGL");
|
||||
|
||||
[self->renderLock lock];
|
||||
|
||||
// Synchronize buffer swaps with vertical refresh rate
|
||||
GLint swapInt = 1;
|
||||
[[self openGLContext] setValues:&swapInt
|
||||
forParameter:NSOpenGLCPSwapInterval];
|
||||
|
||||
glClearColor(0, 0, 0, 1.0);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
glGenTextures(1, &screenTextureId);
|
||||
|
||||
[self->renderLock unlock];
|
||||
}
|
||||
|
||||
- (BOOL) acceptsFirstResponder
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void) drawRect:(NSRect)dirtyRect
|
||||
{
|
||||
[self->renderLock lock];
|
||||
|
||||
NSOpenGLContext *nsContext = [self openGLContext];
|
||||
[nsContext makeCurrentContext];
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
GLfloat coordX = (GLfloat)self->imageWidth / self->textureWidth;
|
||||
GLfloat coordY = (GLfloat)self->imageHeight / self->textureHeight;
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, screenTextureId);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||
|
||||
NSSize size = [self bounds].size;
|
||||
CGFloat offset = 0;
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(0.0, 0.0);
|
||||
glVertex3f(-offset, 0.0, 0.0);
|
||||
glTexCoord2f(coordX, 0.0);
|
||||
glVertex3f(size.width + offset, 0.0, 0.0);
|
||||
glTexCoord2f(coordX, coordY);
|
||||
glVertex3f(size.width + offset, size.height, 0.0);
|
||||
glTexCoord2f(0.0, coordY);
|
||||
glVertex3f(-offset, size.height, 0.0);
|
||||
glEnd();
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
|
||||
[nsContext flushBuffer];
|
||||
|
||||
[self->renderLock unlock];
|
||||
}
|
||||
|
||||
- (void)reshape
|
||||
{
|
||||
viewBounds = [self bounds];
|
||||
[self->renderLock lock];
|
||||
|
||||
[[self openGLContext] makeCurrentContext];
|
||||
[[self openGLContext] update];
|
||||
|
||||
[self resetProjection];
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
[self->renderLock unlock];
|
||||
}
|
||||
|
||||
#pragma mark - FBVideoRenderDelegate
|
||||
|
||||
- (void)initTextureOfWidth:(int)width
|
||||
height:(int)height
|
||||
isRotated:(BOOL)rotated
|
||||
bytesPerPixel:(int)bytesPerPixel
|
||||
{
|
||||
NSLog(@"FBScreenView/initTexture");
|
||||
|
||||
[self->renderLock lock];
|
||||
|
||||
NSOpenGLContext *nsContext = [self openGLContext];
|
||||
[nsContext makeCurrentContext];
|
||||
|
||||
free(self->texture);
|
||||
|
||||
self->imageWidth = width;
|
||||
self->imageHeight = height;
|
||||
self->isRotated = rotated;
|
||||
self->textureWidth = [FBScreenView powerOfTwoClosestTo:self->imageWidth];
|
||||
self->textureHeight = [FBScreenView powerOfTwoClosestTo:self->imageHeight];
|
||||
self->textureBytesPerPixel = bytesPerPixel;
|
||||
self->screenSize = NSMakeSize((CGFloat)width, (CGFloat)height);
|
||||
|
||||
int texSize = self->textureWidth * self->textureHeight * bytesPerPixel;
|
||||
self->texture = (unsigned char *)malloc(texSize);
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, screenTextureId);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, bytesPerPixel,
|
||||
self->textureWidth, self->textureHeight,
|
||||
0, GL_BGR, GL_UNSIGNED_BYTE, self->texture);
|
||||
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
|
||||
[self resetProjection];
|
||||
|
||||
[self->renderLock unlock];
|
||||
}
|
||||
|
||||
- (void)renderFrame:(unsigned char *)bitmap
|
||||
{
|
||||
if (NSPointInRect(_lastCursorPosition, viewBounds)) {
|
||||
CFAbsoluteTime interval = CFAbsoluteTimeGetCurrent() - _lastMouseAction;
|
||||
if (interval > HIDE_CURSOR_TIMEOUT_SECONDS) {
|
||||
if ([_delegate respondsToSelector:@selector(mouseDidIdle)]) {
|
||||
[_delegate mouseDidIdle];
|
||||
}
|
||||
_lastCursorPosition.x = -1;
|
||||
}
|
||||
}
|
||||
|
||||
[self->renderLock lock];
|
||||
|
||||
NSOpenGLContext *nsContext = [self openGLContext];
|
||||
[nsContext makeCurrentContext];
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
GLfloat coordX = (GLfloat)self->imageWidth / self->textureWidth;
|
||||
GLfloat coordY = (GLfloat)self->imageHeight / self->textureHeight;
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, screenTextureId);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||
|
||||
for (int y = 0; y < self->imageHeight; y += 1) {
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, y, self->imageWidth, 1,
|
||||
GL_BGR, GL_UNSIGNED_BYTE,
|
||||
bitmap + y * self->imageWidth * self->textureBytesPerPixel);
|
||||
}
|
||||
|
||||
NSSize size = viewBounds.size;
|
||||
CGFloat offset = 0;
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(0.0, 0.0);
|
||||
glVertex3f(-offset, 0.0, 0.0);
|
||||
glTexCoord2f(coordX, 0.0);
|
||||
glVertex3f(size.width + offset, 0.0, 0.0);
|
||||
glTexCoord2f(coordX, coordY);
|
||||
glVertex3f(size.width + offset, size.height, 0.0);
|
||||
glTexCoord2f(0.0, coordY);
|
||||
glVertex3f(-offset, size.height, 0.0);
|
||||
glEnd();
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
|
||||
[nsContext flushBuffer];
|
||||
|
||||
[self->renderLock unlock];
|
||||
}
|
||||
|
||||
#pragma mark - Mouse tracking
|
||||
|
||||
- (void) mouseEntered:(NSEvent *) event
|
||||
{
|
||||
[self handleMouseChange:[event locationInWindow]];
|
||||
}
|
||||
|
||||
- (void) mouseMoved:(NSEvent *) event
|
||||
{
|
||||
[self handleMouseChange:[event locationInWindow]];
|
||||
}
|
||||
|
||||
- (void) mouseExited:(NSEvent *) event
|
||||
{
|
||||
[self handleMouseChange:NSMakePoint(-1, -1)];
|
||||
}
|
||||
|
||||
- (void) mouseDown:(NSEvent *) event
|
||||
{
|
||||
[self handleMouseChange:[event locationInWindow]];
|
||||
}
|
||||
|
||||
- (void) rightMouseDown:(NSEvent *) event
|
||||
{
|
||||
[self handleMouseChange:[event locationInWindow]];
|
||||
}
|
||||
|
||||
#pragma mark - Public methods
|
||||
|
||||
- (NSSize) screenSize
|
||||
{
|
||||
return self->screenSize;
|
||||
}
|
||||
|
||||
#pragma mark - Private methods
|
||||
|
||||
- (void) resetTrackingArea
|
||||
{
|
||||
if (_trackingArea) {
|
||||
[self removeTrackingArea:_trackingArea];
|
||||
}
|
||||
|
||||
NSTrackingAreaOptions opts = NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingActiveInKeyWindow | NSTrackingInVisibleRect;
|
||||
_trackingArea = [[NSTrackingArea alloc] initWithRect:NSZeroRect
|
||||
options:opts
|
||||
owner:self
|
||||
userInfo:nil];
|
||||
[self addTrackingArea:_trackingArea];
|
||||
}
|
||||
|
||||
- (void) handleMouseChange:(NSPoint) position
|
||||
{
|
||||
_lastMouseAction = CFAbsoluteTimeGetCurrent();
|
||||
_lastCursorPosition = [self convertPoint:position
|
||||
fromView:nil];
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(mouseStateDidChange)]) {
|
||||
[_delegate mouseStateDidChange];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)resetProjection
|
||||
{
|
||||
NSSize size = [self bounds].size;
|
||||
|
||||
glViewport(0, 0, size.width, size.height);
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
|
||||
if (!self->isRotated) {
|
||||
glOrtho(0, size.width, size.height, 0, -1, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
glRotatef(90.0, 0.0, 0.0, 1.0);
|
||||
glOrtho(0, size.width, size.height, 0, -1, 5);
|
||||
}
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
}
|
||||
|
||||
+ (int)powerOfTwoClosestTo:(int)number
|
||||
{
|
||||
int rv = 1;
|
||||
while (rv < number) rv *= 2;
|
||||
return rv;
|
||||
}
|
||||
|
||||
@end
|
26
src/intf/video/macos/FBVideo.h
Normal file
26
src/intf/video/macos/FBVideo.h
Normal file
@ -0,0 +1,26 @@
|
||||
// Portions from FinalBurn X: Port of FinalBurn to OS X
|
||||
// https://github.com/0xe1f/FinalBurn-X
|
||||
//
|
||||
// Copyright (C) Akop Karapetyan
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@protocol FBVideoDelegate<NSObject>
|
||||
|
||||
@optional
|
||||
- (void)screenSizeDidChange:(NSSize)newSize;
|
||||
- (void)initTextureOfWidth:(int)width
|
||||
height:(int)height
|
||||
isRotated:(BOOL)rotated
|
||||
bytesPerPixel:(int)bytesPerPixel;
|
||||
- (void)renderFrame:(unsigned char *)bitmap;
|
||||
|
||||
@end
|
||||
|
||||
@interface FBVideo : NSObject
|
||||
|
||||
@property (nonatomic, weak) id<FBVideoDelegate> delegate;
|
||||
|
||||
@end
|
186
src/intf/video/macos/FBVideo.mm
Normal file
186
src/intf/video/macos/FBVideo.mm
Normal file
@ -0,0 +1,186 @@
|
||||
// Portions from FinalBurn X: Port of FinalBurn to OS X
|
||||
// https://github.com/0xe1f/FinalBurn-X
|
||||
//
|
||||
// Copyright (C) Akop Karapetyan
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
#import "FBVideo.h"
|
||||
|
||||
#import "AppDelegate.h"
|
||||
|
||||
#include "burner.h"
|
||||
|
||||
@implementation FBVideo
|
||||
|
||||
#pragma mark - Init and dealloc
|
||||
|
||||
- (instancetype) init
|
||||
{
|
||||
if (self = [super init]) {
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
_delegate = nil;
|
||||
}
|
||||
|
||||
#pragma mark - Intermediaries
|
||||
|
||||
- (BOOL) renderToSurface:(unsigned char *) buffer
|
||||
{
|
||||
id<FBVideoDelegate> vd = [self delegate];
|
||||
if ([vd respondsToSelector:@selector(renderFrame:)])
|
||||
[vd renderFrame:buffer];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void) notifyTextureReadyOfWidth:(int) texWidth
|
||||
height:(int) texHeight
|
||||
isRotated:(BOOL) isRotated
|
||||
bytesPerPixel:(int) bpp
|
||||
screenSize:(NSSize) size
|
||||
{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
id<FBVideoDelegate> vd = [self delegate];
|
||||
if ([vd respondsToSelector:@selector(initTextureOfWidth:height:isRotated:bytesPerPixel:)])
|
||||
[vd initTextureOfWidth:texWidth
|
||||
height:texHeight
|
||||
isRotated:isRotated
|
||||
bytesPerPixel:bpp];
|
||||
|
||||
if ([vd respondsToSelector:@selector(screenSizeDidChange:)])
|
||||
[vd screenSizeDidChange:size];
|
||||
});
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - FinalBurn callbacks
|
||||
|
||||
static unsigned char *screenBuffer = NULL;
|
||||
static int bufferWidth = 0;
|
||||
static int bufferHeight = 0;
|
||||
static int bufferBytesPerPixel = 0;
|
||||
|
||||
static int MacOSVideoInit()
|
||||
{
|
||||
int gameWidth;
|
||||
int gameHeight;
|
||||
int rotationMode = 0;
|
||||
|
||||
BurnDrvGetVisibleSize(&gameWidth, &gameHeight);
|
||||
|
||||
if (BurnDrvGetFlags() & BDF_ORIENTATION_VERTICAL) {
|
||||
rotationMode |= 1;
|
||||
}
|
||||
|
||||
if (BurnDrvGetFlags() & BDF_ORIENTATION_FLIPPED) {
|
||||
rotationMode ^= 2;
|
||||
}
|
||||
|
||||
nVidImageWidth = gameWidth;
|
||||
nVidImageHeight = gameHeight;
|
||||
nVidImageDepth = 24;
|
||||
nVidImageBPP = 3;
|
||||
if (!rotationMode) {
|
||||
nVidImagePitch = nVidImageWidth * nVidImageBPP;
|
||||
} else {
|
||||
nVidImagePitch = nVidImageHeight * nVidImageBPP;
|
||||
}
|
||||
|
||||
SetBurnHighCol(nVidImageDepth);
|
||||
|
||||
bufferBytesPerPixel = nVidImageBPP;
|
||||
bufferWidth = gameWidth;
|
||||
bufferHeight = gameHeight;
|
||||
|
||||
int bufSize = bufferWidth * bufferHeight * nVidImageBPP;
|
||||
free(screenBuffer);
|
||||
screenBuffer = (unsigned char *) malloc(bufSize);
|
||||
|
||||
if (screenBuffer == NULL)
|
||||
return 1;
|
||||
|
||||
nBurnBpp = nVidImageBPP;
|
||||
nBurnPitch = nVidImagePitch;
|
||||
pVidImage = screenBuffer;
|
||||
|
||||
memset(screenBuffer, 0, bufSize);
|
||||
|
||||
int textureWidth;
|
||||
int textureHeight;
|
||||
BOOL isRotated = rotationMode & 1;
|
||||
|
||||
if (!isRotated) {
|
||||
textureWidth = bufferWidth;
|
||||
textureHeight = bufferHeight;
|
||||
} else {
|
||||
textureWidth = bufferHeight;
|
||||
textureHeight = bufferWidth;
|
||||
}
|
||||
|
||||
NSSize screenSize = NSMakeSize((CGFloat)bufferWidth,
|
||||
(CGFloat)bufferHeight);
|
||||
|
||||
[AppDelegate.sharedInstance.video notifyTextureReadyOfWidth:textureWidth
|
||||
height:textureHeight
|
||||
isRotated:isRotated
|
||||
bytesPerPixel:bufferBytesPerPixel
|
||||
screenSize:screenSize];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int MacOSVideoExit()
|
||||
{
|
||||
free(screenBuffer);
|
||||
screenBuffer = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int MacOSVideoFrame(bool redraw)
|
||||
{
|
||||
if (pVidImage == NULL)
|
||||
return NO;
|
||||
|
||||
if (redraw) {
|
||||
if (BurnDrvRedraw()) {
|
||||
BurnDrvFrame();
|
||||
}
|
||||
} else {
|
||||
BurnDrvFrame();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int MacOSVideoPaint(int validate)
|
||||
{
|
||||
return [AppDelegate.sharedInstance.video renderToSurface:screenBuffer] ? 0 : 1;
|
||||
}
|
||||
|
||||
static int MacOSVideoScale(RECT*, int, int)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int MacOSVideoGetSettings(InterfaceInfo *info)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct VidOut VidOutMacOS = {
|
||||
MacOSVideoInit,
|
||||
MacOSVideoExit,
|
||||
MacOSVideoFrame,
|
||||
MacOSVideoPaint,
|
||||
MacOSVideoScale,
|
||||
MacOSVideoGetSettings,
|
||||
_T("MacOS Video"),
|
||||
};
|
@ -1,56 +0,0 @@
|
||||
#include "burner.h"
|
||||
|
||||
static int Init()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int Exit()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Run one frame and render the screen
|
||||
static int Frame(bool bRedraw)
|
||||
{
|
||||
if (bDrvOkay) {
|
||||
if (bRedraw) { // Redraw current frame
|
||||
if (BurnDrvRedraw()) {
|
||||
BurnDrvFrame(); // No redraw function provided, advance one frame
|
||||
}
|
||||
} else {
|
||||
BurnDrvFrame(); // Run one frame and draw the screen
|
||||
}
|
||||
|
||||
if ((BurnDrvGetFlags() & BDF_16BIT_ONLY) && pVidTransCallback)
|
||||
pVidTransCallback();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Paint the BlitFX surface onto the primary surface
|
||||
static int Paint(int bValidate)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int Scale(RECT* , int, int)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int GetSettings(InterfaceInfo* pInfo)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct VidOut VidOutMacOS = {
|
||||
Init,
|
||||
Exit,
|
||||
Frame,
|
||||
Paint,
|
||||
Scale,
|
||||
GetSettings,
|
||||
_T("MacOS Video"),
|
||||
};
|
Loading…
Reference in New Issue
Block a user