mirror of https://github.com/mgba-emu/mgba.git
Merge commit 'a21d773ae8dd52b6e2e1e7b34f8bca4ec3d5b457'
This commit is contained in:
commit
36daee6de3
|
@ -0,0 +1,121 @@
|
||||||
|
/* Copyright (c) 2013-2015 Jeffrey Pfau
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
#include "gl.h"
|
||||||
|
|
||||||
|
#include "gba/video.h"
|
||||||
|
|
||||||
|
static const GLint _glVertices[] = {
|
||||||
|
0, 0,
|
||||||
|
256, 0,
|
||||||
|
256, 256,
|
||||||
|
0, 256
|
||||||
|
};
|
||||||
|
|
||||||
|
static const GLint _glTexCoords[] = {
|
||||||
|
0, 0,
|
||||||
|
1, 0,
|
||||||
|
1, 1,
|
||||||
|
0, 1
|
||||||
|
};
|
||||||
|
|
||||||
|
static void GBAGLContextInit(struct VideoBackend* v, WHandle handle) {
|
||||||
|
UNUSED(handle);
|
||||||
|
struct GBAGLContext* context = (struct GBAGLContext*) v;
|
||||||
|
glGenTextures(1, &context->tex);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, context->tex);
|
||||||
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||||
|
#ifndef _WIN32
|
||||||
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef COLOR_16_BIT
|
||||||
|
#ifdef COLOR_5_6_5
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0);
|
||||||
|
#else
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, 0);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void GBAGLContextDeinit(struct VideoBackend* v) {
|
||||||
|
struct GBAGLContext* context = (struct GBAGLContext*) v;
|
||||||
|
glDeleteTextures(1, &context->tex);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void GBAGLContextResized(struct VideoBackend* v, int w, int h) {
|
||||||
|
int drawW = w;
|
||||||
|
int drawH = h;
|
||||||
|
if (v->lockAspectRatio) {
|
||||||
|
if (w * 2 > h * 3) {
|
||||||
|
drawW = h * 3 / 2;
|
||||||
|
} else if (w * 2 < h * 3) {
|
||||||
|
drawH = w * 2 / 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
glMatrixMode(GL_MODELVIEW);
|
||||||
|
glLoadIdentity();
|
||||||
|
glClearColor(0, 0, 0, 0);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
glViewport((w - drawW) / 2, (h - drawH) / 2, drawW, drawH);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void GBAGLContextClear(struct VideoBackend* v) {
|
||||||
|
UNUSED(v);
|
||||||
|
glClearColor(0, 0, 0, 0);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GBAGLContextDrawFrame(struct VideoBackend* v) {
|
||||||
|
struct GBAGLContext* context = (struct GBAGLContext*) v;
|
||||||
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
|
glVertexPointer(2, GL_INT, 0, _glVertices);
|
||||||
|
glTexCoordPointer(2, GL_INT, 0, _glTexCoords);
|
||||||
|
glMatrixMode (GL_PROJECTION);
|
||||||
|
glLoadIdentity();
|
||||||
|
glOrtho(0, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, 0, 0, 1);
|
||||||
|
glMatrixMode(GL_MODELVIEW);
|
||||||
|
glLoadIdentity();
|
||||||
|
glBindTexture(GL_TEXTURE_2D, context->tex);
|
||||||
|
if (v->filter) {
|
||||||
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
} else {
|
||||||
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
}
|
||||||
|
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GBAGLContextPostFrame(struct VideoBackend* v, const void* frame) {
|
||||||
|
struct GBAGLContext* context = (struct GBAGLContext*) v;
|
||||||
|
glBindTexture(GL_TEXTURE_2D, context->tex);
|
||||||
|
#ifdef COLOR_16_BIT
|
||||||
|
#ifdef COLOR_5_6_5
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, frame);
|
||||||
|
#else
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, frame);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, frame);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void GBAGLContextCreate(struct GBAGLContext* context) {
|
||||||
|
context->d.init = GBAGLContextInit;
|
||||||
|
context->d.deinit = GBAGLContextDeinit;
|
||||||
|
context->d.resized = GBAGLContextResized;
|
||||||
|
context->d.swap = 0;
|
||||||
|
context->d.clear = GBAGLContextClear;
|
||||||
|
context->d.postFrame = GBAGLContextPostFrame;
|
||||||
|
context->d.drawFrame = GBAGLContextDrawFrame;
|
||||||
|
context->d.setMessage = 0;
|
||||||
|
context->d.clearMessage = 0;
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
/* Copyright (c) 2013-2015 Jeffrey Pfau
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
#ifndef GL_H
|
||||||
|
#define GL_H
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include <OpenGL/gl.h>
|
||||||
|
#else
|
||||||
|
#include <GL/gl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "platform/video-backend.h"
|
||||||
|
|
||||||
|
struct GBAGLContext {
|
||||||
|
struct VideoBackend d;
|
||||||
|
|
||||||
|
GLuint tex;
|
||||||
|
};
|
||||||
|
|
||||||
|
void GBAGLContextCreate(struct GBAGLContext*);
|
||||||
|
|
||||||
|
#endif
|
|
@ -39,6 +39,8 @@ if(NOT Qt5OpenGL_FOUND OR NOT Qt5Widgets_FOUND OR NOT OPENGL_FOUND)
|
||||||
return()
|
return()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
list(APPEND PLATFORM_SRC ${PLATFORM_SRC} ${CMAKE_SOURCE_DIR}/src/platform/opengl/gl.c)
|
||||||
|
|
||||||
get_target_property(QT_TYPE Qt5::Core TYPE)
|
get_target_property(QT_TYPE Qt5::Core TYPE)
|
||||||
if(QT_TYPE STREQUAL STATIC_LIBRARY)
|
if(QT_TYPE STREQUAL STATIC_LIBRARY)
|
||||||
set(QT_STATIC ON)
|
set(QT_STATIC ON)
|
||||||
|
|
|
@ -14,20 +14,6 @@ extern "C" {
|
||||||
|
|
||||||
using namespace QGBA;
|
using namespace QGBA;
|
||||||
|
|
||||||
static const GLint _glVertices[] = {
|
|
||||||
0, 0,
|
|
||||||
256, 0,
|
|
||||||
256, 256,
|
|
||||||
0, 256
|
|
||||||
};
|
|
||||||
|
|
||||||
static const GLint _glTexCoords[] = {
|
|
||||||
0, 0,
|
|
||||||
1, 0,
|
|
||||||
1, 1,
|
|
||||||
0, 1
|
|
||||||
};
|
|
||||||
|
|
||||||
DisplayGL::DisplayGL(const QGLFormat& format, QWidget* parent)
|
DisplayGL::DisplayGL(const QGLFormat& format, QWidget* parent)
|
||||||
: Display(parent)
|
: Display(parent)
|
||||||
, m_gl(new EmptyGLWidget(format, this))
|
, m_gl(new EmptyGLWidget(format, this))
|
||||||
|
@ -154,10 +140,16 @@ PainterGL::PainterGL(QGLWidget* parent)
|
||||||
: m_gl(parent)
|
: m_gl(parent)
|
||||||
, m_drawTimer(nullptr)
|
, m_drawTimer(nullptr)
|
||||||
, m_messageTimer(this)
|
, m_messageTimer(this)
|
||||||
, m_lockAspectRatio(false)
|
|
||||||
, m_filter(false)
|
|
||||||
, m_context(nullptr)
|
, m_context(nullptr)
|
||||||
{
|
{
|
||||||
|
GBAGLContextCreate(&m_backend);
|
||||||
|
m_backend.d.swap = [](VideoBackend* v) {
|
||||||
|
PainterGL* painter = static_cast<PainterGL*>(v->user);
|
||||||
|
painter->m_gl->swapBuffers();
|
||||||
|
};
|
||||||
|
m_backend.d.user = this;
|
||||||
|
m_backend.d.filter = false;
|
||||||
|
m_backend.d.lockAspectRatio = false;
|
||||||
m_messageFont.setFamily("Source Code Pro");
|
m_messageFont.setFamily("Source Code Pro");
|
||||||
m_messageFont.setStyleHint(QFont::Monospace);
|
m_messageFont.setStyleHint(QFont::Monospace);
|
||||||
m_messageFont.setPixelSize(13);
|
m_messageFont.setPixelSize(13);
|
||||||
|
@ -174,16 +166,7 @@ void PainterGL::setContext(GBAThread* context) {
|
||||||
|
|
||||||
void PainterGL::setBacking(const uint32_t* backing) {
|
void PainterGL::setBacking(const uint32_t* backing) {
|
||||||
m_gl->makeCurrent();
|
m_gl->makeCurrent();
|
||||||
glBindTexture(GL_TEXTURE_2D, m_tex);
|
m_backend.d.postFrame(&m_backend.d, backing);
|
||||||
#ifdef COLOR_16_BIT
|
|
||||||
#ifdef COLOR_5_6_5
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, backing);
|
|
||||||
#else
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, backing);
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, backing);
|
|
||||||
#endif
|
|
||||||
m_gl->doneCurrent();
|
m_gl->doneCurrent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,43 +176,31 @@ void PainterGL::resize(const QSize& size) {
|
||||||
int h = m_size.height();
|
int h = m_size.height();
|
||||||
int drawW = w;
|
int drawW = w;
|
||||||
int drawH = h;
|
int drawH = h;
|
||||||
if (m_lockAspectRatio) {
|
if (m_backend.d.lockAspectRatio) {
|
||||||
if (w * 2 > h * 3) {
|
if (w * 2 > h * 3) {
|
||||||
drawW = h * 3 / 2;
|
drawW = h * 3 / 2;
|
||||||
} else if (w * 2 < h * 3) {
|
} else if (w * 2 < h * 3) {
|
||||||
drawH = w * 2 / 3;
|
drawH = w * 2 / 3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_viewport = QRect((w - drawW) / 2, (h - drawH) / 2, drawW, drawH);
|
|
||||||
m_painter.begin(m_gl->context()->device());
|
|
||||||
m_world.reset();
|
m_world.reset();
|
||||||
m_world.translate(m_viewport.x(), m_viewport.y());
|
m_world.translate((w - drawW) / 2, (h - drawH) / 2);
|
||||||
m_world.scale(qreal(drawW) / VIDEO_HORIZONTAL_PIXELS, qreal(drawH) / VIDEO_VERTICAL_PIXELS);
|
m_world.scale(qreal(drawW) / VIDEO_HORIZONTAL_PIXELS, qreal(drawH) / VIDEO_VERTICAL_PIXELS);
|
||||||
m_painter.setWorldTransform(m_world);
|
|
||||||
m_painter.setFont(m_messageFont);
|
|
||||||
m_message.prepare(m_world, m_messageFont);
|
m_message.prepare(m_world, m_messageFont);
|
||||||
m_painter.end();
|
|
||||||
if (m_drawTimer) {
|
if (m_drawTimer) {
|
||||||
forceDraw();
|
forceDraw();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PainterGL::lockAspectRatio(bool lock) {
|
void PainterGL::lockAspectRatio(bool lock) {
|
||||||
m_lockAspectRatio = lock;
|
m_backend.d.lockAspectRatio = lock;
|
||||||
if (m_drawTimer) {
|
if (m_drawTimer) {
|
||||||
forceDraw();
|
forceDraw();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PainterGL::filter(bool filter) {
|
void PainterGL::filter(bool filter) {
|
||||||
m_filter = filter;
|
m_backend.d.filter = filter;
|
||||||
m_gl->makeCurrent();
|
|
||||||
if (m_filter) {
|
|
||||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
||||||
} else {
|
|
||||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
||||||
}
|
|
||||||
m_gl->doneCurrent();
|
|
||||||
if (m_drawTimer) {
|
if (m_drawTimer) {
|
||||||
forceDraw();
|
forceDraw();
|
||||||
}
|
}
|
||||||
|
@ -237,24 +208,7 @@ void PainterGL::filter(bool filter) {
|
||||||
|
|
||||||
void PainterGL::start() {
|
void PainterGL::start() {
|
||||||
m_gl->makeCurrent();
|
m_gl->makeCurrent();
|
||||||
glEnable(GL_TEXTURE_2D);
|
m_backend.d.init(&m_backend.d, (void*) m_gl->winId());
|
||||||
glGenTextures(1, &m_tex);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, m_tex);
|
|
||||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
||||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
||||||
if (m_filter) {
|
|
||||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
||||||
} else {
|
|
||||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
||||||
}
|
|
||||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
||||||
glEnableClientState(GL_VERTEX_ARRAY);
|
|
||||||
glVertexPointer(2, GL_INT, 0, _glVertices);
|
|
||||||
glTexCoordPointer(2, GL_INT, 0, _glTexCoords);
|
|
||||||
glMatrixMode(GL_MODELVIEW);
|
|
||||||
glLoadIdentity();
|
|
||||||
glClearColor(0, 0, 0, 0);
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
|
||||||
m_gl->doneCurrent();
|
m_gl->doneCurrent();
|
||||||
|
|
||||||
m_drawTimer = new QTimer;
|
m_drawTimer = new QTimer;
|
||||||
|
@ -267,19 +221,17 @@ void PainterGL::start() {
|
||||||
void PainterGL::draw() {
|
void PainterGL::draw() {
|
||||||
GBASyncWaitFrameStart(&m_context->sync, m_context->frameskip);
|
GBASyncWaitFrameStart(&m_context->sync, m_context->frameskip);
|
||||||
m_painter.begin(m_gl->context()->device());
|
m_painter.begin(m_gl->context()->device());
|
||||||
m_painter.setWorldTransform(m_world);
|
|
||||||
performDraw();
|
performDraw();
|
||||||
m_painter.end();
|
m_painter.end();
|
||||||
GBASyncWaitFrameEnd(&m_context->sync);
|
GBASyncWaitFrameEnd(&m_context->sync);
|
||||||
m_gl->swapBuffers();
|
m_backend.d.swap(&m_backend.d);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PainterGL::forceDraw() {
|
void PainterGL::forceDraw() {
|
||||||
m_painter.begin(m_gl->context()->device());
|
m_painter.begin(m_gl->context()->device());
|
||||||
m_painter.setWorldTransform(m_world);
|
|
||||||
performDraw();
|
performDraw();
|
||||||
m_painter.end();
|
m_painter.end();
|
||||||
m_gl->swapBuffers();
|
m_backend.d.swap(&m_backend.d);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PainterGL::stop() {
|
void PainterGL::stop() {
|
||||||
|
@ -287,10 +239,9 @@ void PainterGL::stop() {
|
||||||
delete m_drawTimer;
|
delete m_drawTimer;
|
||||||
m_drawTimer = nullptr;
|
m_drawTimer = nullptr;
|
||||||
m_gl->makeCurrent();
|
m_gl->makeCurrent();
|
||||||
glDeleteTextures(1, &m_tex);
|
m_backend.d.clear(&m_backend.d);
|
||||||
glClearColor(0, 0, 0, 0);
|
m_backend.d.swap(&m_backend.d);
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
m_backend.d.deinit(&m_backend.d);
|
||||||
m_gl->swapBuffers();
|
|
||||||
m_gl->doneCurrent();
|
m_gl->doneCurrent();
|
||||||
m_gl->context()->moveToThread(m_gl->thread());
|
m_gl->context()->moveToThread(m_gl->thread());
|
||||||
moveToThread(m_gl->thread());
|
moveToThread(m_gl->thread());
|
||||||
|
@ -309,21 +260,11 @@ void PainterGL::unpause() {
|
||||||
|
|
||||||
void PainterGL::performDraw() {
|
void PainterGL::performDraw() {
|
||||||
m_painter.beginNativePainting();
|
m_painter.beginNativePainting();
|
||||||
glMatrixMode(GL_PROJECTION);
|
float r = m_gl->devicePixelRatio();
|
||||||
glLoadIdentity();
|
m_backend.d.resized(&m_backend.d, m_size.width() * r, m_size.height() * r);
|
||||||
glOrtho(0, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, 0, 0, 1);
|
m_backend.d.drawFrame(&m_backend.d);
|
||||||
glMatrixMode(GL_MODELVIEW);
|
|
||||||
glLoadIdentity();
|
|
||||||
glViewport(0, 0, m_size.width() * m_gl->devicePixelRatio(), m_size.height() * m_gl->devicePixelRatio());
|
|
||||||
glClearColor(0, 0, 0, 0);
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
|
||||||
QRect viewport(m_viewport.topLeft() * m_gl->devicePixelRatio(), m_viewport.size() * m_gl->devicePixelRatio());
|
|
||||||
glViewport(viewport.x(), viewport.y(), viewport.width(), viewport.height());
|
|
||||||
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
|
||||||
if (m_context->sync.videoFrameWait) {
|
|
||||||
glFlush();
|
|
||||||
}
|
|
||||||
m_painter.endNativePainting();
|
m_painter.endNativePainting();
|
||||||
|
m_painter.setWorldTransform(m_world);
|
||||||
m_painter.setRenderHint(QPainter::Antialiasing);
|
m_painter.setRenderHint(QPainter::Antialiasing);
|
||||||
m_painter.setFont(m_messageFont);
|
m_painter.setFont(m_messageFont);
|
||||||
m_painter.setPen(Qt::black);
|
m_painter.setPen(Qt::black);
|
||||||
|
|
|
@ -13,6 +13,10 @@
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "platform/opengl/gl.h"
|
||||||
|
}
|
||||||
|
|
||||||
struct GBAThread;
|
struct GBAThread;
|
||||||
|
|
||||||
namespace QGBA {
|
namespace QGBA {
|
||||||
|
@ -94,11 +98,8 @@ private:
|
||||||
QTimer* m_drawTimer;
|
QTimer* m_drawTimer;
|
||||||
QTimer m_messageTimer;
|
QTimer m_messageTimer;
|
||||||
GBAThread* m_context;
|
GBAThread* m_context;
|
||||||
GLuint m_tex;
|
GBAGLContext m_backend;
|
||||||
QSize m_size;
|
QSize m_size;
|
||||||
bool m_lockAspectRatio;
|
|
||||||
bool m_filter;
|
|
||||||
QRect m_viewport;
|
|
||||||
QTransform m_world;
|
QTransform m_world;
|
||||||
QFont m_messageFont;
|
QFont m_messageFont;
|
||||||
};
|
};
|
||||||
|
|
|
@ -67,6 +67,7 @@ else()
|
||||||
list(APPEND MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/sw-sdl.c)
|
list(APPEND MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/sw-sdl.c)
|
||||||
if(BUILD_GL)
|
if(BUILD_GL)
|
||||||
list(APPEND MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/gl-sdl.c)
|
list(APPEND MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/gl-sdl.c)
|
||||||
|
list(APPEND PLATFORM_SRC ${CMAKE_SOURCE_DIR}/src/platform/opengl/gl.c)
|
||||||
add_definitions(-DBUILD_GL)
|
add_definitions(-DBUILD_GL)
|
||||||
find_package(OpenGL REQUIRED)
|
find_package(OpenGL REQUIRED)
|
||||||
include_directories(${OPENGL_INCLUDE_DIR})
|
include_directories(${OPENGL_INCLUDE_DIR})
|
||||||
|
|
|
@ -6,47 +6,22 @@
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
|
||||||
#include "gba/supervisor/thread.h"
|
#include "gba/supervisor/thread.h"
|
||||||
|
#include "platform/opengl/gl.h"
|
||||||
|
|
||||||
#ifdef __APPLE__
|
static void _sdlSwap(struct VideoBackend* context) {
|
||||||
#include <OpenGL/gl.h>
|
struct SDLSoftwareRenderer* renderer = (struct SDLSoftwareRenderer*) context->user;
|
||||||
#else
|
|
||||||
#include <GL/gl.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef BUILD_GL
|
|
||||||
static const GLint _glVertices[] = {
|
|
||||||
0, 0,
|
|
||||||
256, 0,
|
|
||||||
256, 256,
|
|
||||||
0, 256
|
|
||||||
};
|
|
||||||
|
|
||||||
static const GLint _glTexCoords[] = {
|
|
||||||
0, 0,
|
|
||||||
1, 0,
|
|
||||||
1, 1,
|
|
||||||
0, 1
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void _doViewport(int w, int h, struct SDLSoftwareRenderer* renderer) {
|
|
||||||
int drawW = w;
|
|
||||||
int drawH = h;
|
|
||||||
if (renderer->lockAspectRatio) {
|
|
||||||
if (w * 2 > h * 3) {
|
|
||||||
drawW = h * 3 / 2;
|
|
||||||
} else if (w * 2 < h * 3) {
|
|
||||||
drawH = w * 2 / 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
glViewport((w - drawW) / 2, (h - drawH) / 2, drawW, drawH);
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
|
||||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
||||||
SDL_GL_SwapWindow(renderer->window);
|
SDL_GL_SwapWindow(renderer->window);
|
||||||
#else
|
#else
|
||||||
SDL_GL_SwapBuffers();
|
SDL_GL_SwapBuffers();
|
||||||
#endif
|
#endif
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
}
|
||||||
|
|
||||||
|
static void _doViewport(int w, int h, struct VideoBackend* v) {
|
||||||
|
v->resized(v, w, h);
|
||||||
|
v->clear(v);
|
||||||
|
v->swap(v);
|
||||||
|
v->clear(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool GBASDLGLInit(struct SDLSoftwareRenderer* renderer);
|
static bool GBASDLGLInit(struct SDLSoftwareRenderer* renderer);
|
||||||
|
@ -89,48 +64,24 @@ bool GBASDLGLInit(struct SDLSoftwareRenderer* renderer) {
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
renderer->d.outputBuffer = malloc(VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * BYTES_PER_PIXEL);
|
renderer->d.outputBuffer = malloc(256 * 256 * BYTES_PER_PIXEL);
|
||||||
renderer->d.outputBufferStride = VIDEO_HORIZONTAL_PIXELS;
|
renderer->d.outputBufferStride = 256;
|
||||||
glGenTextures(1, &renderer->tex);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, renderer->tex);
|
|
||||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
||||||
if (renderer->filter) {
|
|
||||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
||||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
||||||
} else {
|
|
||||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
||||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
||||||
}
|
|
||||||
#ifndef _WIN32
|
|
||||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
||||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef COLOR_16_BIT
|
GBAGLContextCreate(&renderer->gl);
|
||||||
#ifdef COLOR_5_6_5
|
renderer->gl.d.user = renderer;
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0);
|
renderer->gl.d.lockAspectRatio = renderer->lockAspectRatio;
|
||||||
#else
|
renderer->gl.d.filter = renderer->filter;
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, 0);
|
renderer->gl.d.swap = _sdlSwap;
|
||||||
#endif
|
renderer->gl.d.init(&renderer->gl.d, 0);
|
||||||
#else
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
_doViewport(renderer->viewportWidth, renderer->viewportHeight, renderer);
|
_doViewport(renderer->viewportWidth, renderer->viewportHeight, &renderer->gl.d);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GBASDLGLRunloop(struct GBAThread* context, struct SDLSoftwareRenderer* renderer) {
|
void GBASDLGLRunloop(struct GBAThread* context, struct SDLSoftwareRenderer* renderer) {
|
||||||
SDL_Event event;
|
SDL_Event event;
|
||||||
|
struct VideoBackend* v = &renderer->gl.d;
|
||||||
|
|
||||||
glEnable(GL_TEXTURE_2D);
|
|
||||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
||||||
glEnableClientState(GL_VERTEX_ARRAY);
|
|
||||||
glVertexPointer(2, GL_INT, 0, _glVertices);
|
|
||||||
glTexCoordPointer(2, GL_INT, 0, _glTexCoords);
|
|
||||||
glMatrixMode (GL_PROJECTION);
|
|
||||||
glLoadIdentity();
|
|
||||||
glOrtho(0, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, 0, 0, 1);
|
|
||||||
while (context->state < THREAD_EXITING) {
|
while (context->state < THREAD_EXITING) {
|
||||||
while (SDL_PollEvent(&event)) {
|
while (SDL_PollEvent(&event)) {
|
||||||
GBASDLHandleEvent(context, &renderer->player, &event);
|
GBASDLHandleEvent(context, &renderer->player, &event);
|
||||||
|
@ -138,37 +89,24 @@ void GBASDLGLRunloop(struct GBAThread* context, struct SDLSoftwareRenderer* rend
|
||||||
// Event handling can change the size of the screen
|
// Event handling can change the size of the screen
|
||||||
if (renderer->player.windowUpdated) {
|
if (renderer->player.windowUpdated) {
|
||||||
SDL_GetWindowSize(renderer->window, &renderer->viewportWidth, &renderer->viewportHeight);
|
SDL_GetWindowSize(renderer->window, &renderer->viewportWidth, &renderer->viewportHeight);
|
||||||
_doViewport(renderer->viewportWidth, renderer->viewportHeight, renderer);
|
_doViewport(renderer->viewportWidth, renderer->viewportHeight, v);
|
||||||
renderer->player.windowUpdated = 0;
|
renderer->player.windowUpdated = 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GBASyncWaitFrameStart(&context->sync, context->frameskip)) {
|
if (GBASyncWaitFrameStart(&context->sync, context->frameskip)) {
|
||||||
glBindTexture(GL_TEXTURE_2D, renderer->tex);
|
v->postFrame(v, renderer->d.outputBuffer);
|
||||||
#ifdef COLOR_16_BIT
|
|
||||||
#ifdef COLOR_5_6_5
|
|
||||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, renderer->d.outputBuffer);
|
|
||||||
#else
|
|
||||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, renderer->d.outputBuffer);
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, GL_RGBA, GL_UNSIGNED_BYTE, renderer->d.outputBuffer);
|
|
||||||
#endif
|
|
||||||
if (context->sync.videoFrameWait) {
|
|
||||||
glFlush();
|
|
||||||
}
|
}
|
||||||
}
|
v->drawFrame(v);
|
||||||
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
|
||||||
GBASyncWaitFrameEnd(&context->sync);
|
GBASyncWaitFrameEnd(&context->sync);
|
||||||
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
v->swap(v);
|
||||||
SDL_GL_SwapWindow(renderer->window);
|
|
||||||
#else
|
|
||||||
SDL_GL_SwapBuffers();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GBASDLGLDeinit(struct SDLSoftwareRenderer* renderer) {
|
void GBASDLGLDeinit(struct SDLSoftwareRenderer* renderer) {
|
||||||
|
if (renderer->gl.d.deinit) {
|
||||||
|
renderer->gl.d.deinit(&renderer->gl.d);
|
||||||
|
}
|
||||||
free(renderer->d.outputBuffer);
|
free(renderer->d.outputBuffer);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,11 +12,7 @@
|
||||||
#include "sdl-events.h"
|
#include "sdl-events.h"
|
||||||
|
|
||||||
#ifdef BUILD_GL
|
#ifdef BUILD_GL
|
||||||
#ifdef __APPLE__
|
#include "platform/opengl/gl.h"
|
||||||
#include <OpenGL/gl.h>
|
|
||||||
#else
|
|
||||||
#include <GL/gl.h>
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef BUILD_RASPI
|
#ifdef BUILD_RASPI
|
||||||
|
@ -59,7 +55,7 @@ struct SDLSoftwareRenderer {
|
||||||
bool filter;
|
bool filter;
|
||||||
|
|
||||||
#ifdef BUILD_GL
|
#ifdef BUILD_GL
|
||||||
GLuint tex;
|
struct GBAGLContext gl;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_PIXMAN
|
#ifdef USE_PIXMAN
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
/* Copyright (c) 2013-2015 Jeffrey Pfau
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
#ifndef VIDEO_BACKEND_H
|
||||||
|
#define VIDEO_BACKEND_H
|
||||||
|
|
||||||
|
#include "util/common.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
typedef HWND WHandle;
|
||||||
|
#else
|
||||||
|
typedef void* WHandle;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct VideoBackend {
|
||||||
|
void (*init)(struct VideoBackend*, WHandle handle);
|
||||||
|
void (*deinit)(struct VideoBackend*);
|
||||||
|
void (*swap)(struct VideoBackend*);
|
||||||
|
void (*clear)(struct VideoBackend*);
|
||||||
|
void (*resized)(struct VideoBackend*, int w, int h);
|
||||||
|
void (*postFrame)(struct VideoBackend*, const void* frame);
|
||||||
|
void (*drawFrame)(struct VideoBackend*);
|
||||||
|
void (*setMessage)(struct VideoBackend*, const char* message);
|
||||||
|
void (*clearMessage)(struct VideoBackend*);
|
||||||
|
|
||||||
|
void* user;
|
||||||
|
|
||||||
|
bool filter;
|
||||||
|
bool lockAspectRatio;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue