Fixed flipped rendering

This commit is contained in:
Akop Karapetyan 2019-10-21 08:51:46 -07:00 committed by tmaul
parent 314d90dbd5
commit de30f6a28d
5 changed files with 152 additions and 146 deletions

View File

@ -11,7 +11,7 @@
// FIXME: errors during load
// FIXME: starting without ROM selected
// FIXME: dropping file into window
// FIXME: rotation (mimonkey)
// FIXME: sound when load fails
@interface AppDelegate ()
@property (weak) IBOutlet NSWindow *window;

View File

@ -14,7 +14,7 @@ int MainInit(const char *path, const char *setname)
return 0;
}
fprintf(stderr, "Initializing '%s' with path '%s'\n", setname, path);
fprintf(stderr, "Initializing '%s' in '%s'\n", setname, path);
SDL_Init(SDL_INIT_AUDIO);
BurnLibInit();

View File

@ -24,19 +24,20 @@
@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;
GLuint screenTextureId;
unsigned char *texture;
int imageWidth;
int imageHeight;
BOOL isRotated;
BOOL isFlipped;
int textureWidth;
int textureHeight;
int textureBytesPerPixel;
NSLock *renderLock;
NSSize screenSize;
CFAbsoluteTime _lastMouseAction;
NSPoint _lastCursorPosition;
NSTrackingArea *_trackingArea;
NSRect viewBounds; // Access from non-UI thread
}
@ -45,16 +46,16 @@
- (void) dealloc
{
glDeleteTextures(1, &screenTextureId);
free(self->texture);
free(texture);
}
- (void) awakeFromNib
{
self->renderLock = [[NSLock alloc] init];
_lastMouseAction = CFAbsoluteTimeGetCurrent();
_lastCursorPosition = NSMakePoint(-1, -1);
renderLock = [[NSLock alloc] init];
_lastMouseAction = CFAbsoluteTimeGetCurrent();
_lastCursorPosition = NSMakePoint(-1, -1);
[self resetTrackingArea];
[self resetTrackingArea];
}
#pragma mark - Cocoa Callbacks
@ -62,43 +63,43 @@
- (void) prepareOpenGL
{
[super prepareOpenGL];
NSLog(@"FBScreenView/prepareOpenGL");
[self->renderLock lock];
[renderLock lock];
// Synchronize buffer swaps with vertical refresh rate
GLint swapInt = 1;
[[self openGLContext] setValues:&swapInt
forParameter:NSOpenGLCPSwapInterval];
forParameter:NSOpenGLCPSwapInterval];
glClearColor(0, 0, 0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glGenTextures(1, &screenTextureId);
[self->renderLock unlock];
[renderLock unlock];
}
- (void) drawRect:(NSRect)dirtyRect
{
[self->renderLock lock];
[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;
GLfloat coordX = (GLfloat)imageWidth / textureWidth;
GLfloat coordY = (GLfloat)imageHeight / 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);
@ -110,109 +111,111 @@
glVertex3f(-offset, size.height, 0.0);
glEnd();
glDisable(GL_TEXTURE_2D);
[nsContext flushBuffer];
[self->renderLock unlock];
[renderLock unlock];
}
- (void) reshape
{
viewBounds = [self bounds];
[self->renderLock lock];
[renderLock lock];
[[self openGLContext] makeCurrentContext];
[[self openGLContext] update];
[self resetProjection];
glClear(GL_COLOR_BUFFER_BIT);
[self->renderLock unlock];
[renderLock unlock];
}
#pragma mark - FBVideoRenderDelegate
- (void)initTextureOfWidth:(int)width
height:(int)height
isRotated:(BOOL)rotated
bytesPerPixel:(int)bytesPerPixel
- (void)initTextureOfWidth:(int) width
height:(int) height
isRotated:(BOOL) rotated
isFlipped:(BOOL) flipped
bytesPerPixel:(int) bytesPerPixel
{
NSLog(@"FBScreenView/initTexture");
[self->renderLock lock];
[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);
free(texture);
imageWidth = width;
imageHeight = height;
isRotated = rotated;
isFlipped = flipped;
textureWidth = [FBScreenView powerOfTwoClosestTo:imageWidth];
textureHeight = [FBScreenView powerOfTwoClosestTo:imageHeight];
textureBytesPerPixel = bytesPerPixel;
screenSize = NSMakeSize((CGFloat)width, (CGFloat)height);
int texSize = textureWidth * textureHeight * bytesPerPixel;
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);
textureWidth, textureHeight,
0, GL_BGR, GL_UNSIGNED_BYTE, texture);
glDisable(GL_TEXTURE_2D);
[self resetProjection];
[self->renderLock unlock];
[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];
if (NSPointInRect(_lastCursorPosition, viewBounds)) {
CFAbsoluteTime interval = CFAbsoluteTimeGetCurrent() - _lastMouseAction;
if (interval > HIDE_CURSOR_TIMEOUT_SECONDS) {
if ([_delegate respondsToSelector:@selector(mouseDidIdle)]) {
[_delegate mouseDidIdle];
}
_lastCursorPosition.x = -1;
}
}
[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;
GLfloat coordX = (GLfloat)imageWidth / textureWidth;
GLfloat coordY = (GLfloat)imageHeight / 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,
for (int y = 0; y < imageHeight; y += 1) {
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, y, imageWidth, 1,
GL_BGR, GL_UNSIGNED_BYTE,
bitmap + y * self->imageWidth * self->textureBytesPerPixel);
bitmap + y * imageWidth * textureBytesPerPixel);
}
NSSize size = viewBounds.size;
CGFloat offset = 0;
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0);
glVertex3f(-offset, 0.0, 0.0);
@ -224,10 +227,10 @@
glVertex3f(-offset, size.height, 0.0);
glEnd();
glDisable(GL_TEXTURE_2D);
[nsContext flushBuffer];
[self->renderLock unlock];
[renderLock unlock];
}
#pragma mark - Keyboard
@ -259,80 +262,78 @@
- (void) mouseEntered:(NSEvent *) event
{
[self handleMouseChange:[event locationInWindow]];
[self handleMouseChange:[event locationInWindow]];
}
- (void) mouseMoved:(NSEvent *) event
{
[self handleMouseChange:[event locationInWindow]];
[self handleMouseChange:[event locationInWindow]];
}
- (void) mouseExited:(NSEvent *) event
{
[self handleMouseChange:NSMakePoint(-1, -1)];
[self handleMouseChange:NSMakePoint(-1, -1)];
}
- (void) mouseDown:(NSEvent *) event
{
[self handleMouseChange:[event locationInWindow]];
[self handleMouseChange:[event locationInWindow]];
}
- (void) rightMouseDown:(NSEvent *) event
{
[self handleMouseChange:[event locationInWindow]];
[self handleMouseChange:[event locationInWindow]];
}
#pragma mark - Public methods
- (NSSize) screenSize
{
return self->screenSize;
return screenSize;
}
#pragma mark - Private methods
- (void) resetTrackingArea
{
if (_trackingArea) {
[self removeTrackingArea:_trackingArea];
}
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];
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];
}
_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);
}
if (!isRotated) {
glOrtho(0, size.width, size.height, 0, -1, 1);
} else {
glRotatef(isFlipped ? 270 : 90.0, 0.0, 0.0, 1.0);
glOrtho(0, size.width, size.height, 0, -1, 5);
}
glMatrixMode(GL_MODELVIEW);
}

View File

@ -10,12 +10,13 @@
@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;
- (void) screenSizeDidChange:(NSSize) newSize;
- (void) initTextureOfWidth:(int) width
height:(int) height
isRotated:(BOOL) rotated
isFlipped:(BOOL) flipped
bytesPerPixel:(int) bytesPerPixel;
- (void) renderFrame:(unsigned char *) bitmap;
@end

View File

@ -42,16 +42,18 @@
- (void) notifyTextureReadyOfWidth:(int) texWidth
height:(int) texHeight
isRotated:(BOOL) isRotated
isFlipped:(BOOL) isFlipped
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:)])
if ([vd respondsToSelector:@selector(initTextureOfWidth:height:isRotated:isFlipped:bytesPerPixel:)])
[vd initTextureOfWidth:texWidth
height:texHeight
isRotated:isRotated
bytesPerPixel:bpp];
height:texHeight
isRotated:isRotated
isFlipped:isFlipped
bytesPerPixel:bpp];
if ([vd respondsToSelector:@selector(screenSizeDidChange:)])
[vd screenSizeDidChange:size];
@ -82,14 +84,15 @@ static int MacOSVideoInit()
int gameWidth;
int gameHeight;
int rotationMode = 0;
int flags = BurnDrvGetFlags();
BurnDrvGetVisibleSize(&gameWidth, &gameHeight);
if (BurnDrvGetFlags() & BDF_ORIENTATION_VERTICAL) {
if (flags & BDF_ORIENTATION_VERTICAL) {
rotationMode |= 1;
}
if (BurnDrvGetFlags() & BDF_ORIENTATION_FLIPPED) {
if (flags & BDF_ORIENTATION_FLIPPED) {
rotationMode ^= 2;
}
@ -140,6 +143,7 @@ static int MacOSVideoInit()
[AppDelegate.sharedInstance.video notifyTextureReadyOfWidth:textureWidth
height:textureHeight
isRotated:isRotated
isFlipped:flags & BDF_ORIENTATION_FLIPPED
bytesPerPixel:bufferBytesPerPixel
screenSize:screenSize];