mirror of https://github.com/bsnes-emu/bsnes.git
175 lines
4.6 KiB
C++
175 lines
4.6 KiB
C++
|
#ifdef __APPLE__
|
||
|
#include <OpenGL/OpenGL.h>
|
||
|
#endif
|
||
|
|
||
|
namespace ruby {
|
||
|
|
||
|
class pVideoQtOpenGL {
|
||
|
public:
|
||
|
QWidget *parent;
|
||
|
QVBoxLayout *layout;
|
||
|
|
||
|
class RubyGLWidget : public QGLWidget {
|
||
|
public:
|
||
|
GLuint texture;
|
||
|
unsigned textureWidth, textureHeight;
|
||
|
|
||
|
uint32_t *buffer;
|
||
|
unsigned rasterWidth, rasterHeight;
|
||
|
|
||
|
bool synchronize;
|
||
|
unsigned filter;
|
||
|
|
||
|
void resize(unsigned width, unsigned height) {
|
||
|
if(width > textureWidth || height > textureHeight) {
|
||
|
textureWidth = max(width, textureWidth);
|
||
|
textureHeight = max(height, textureHeight);
|
||
|
|
||
|
if(buffer) {
|
||
|
delete[] buffer;
|
||
|
glDeleteTextures(1, &texture);
|
||
|
}
|
||
|
|
||
|
buffer = new uint32_t[textureWidth * textureHeight];
|
||
|
glGenTextures(1, &texture);
|
||
|
glBindTexture(GL_TEXTURE_2D, texture);
|
||
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, textureWidth);
|
||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
|
||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, textureWidth, textureHeight, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, buffer);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void updateSynchronization() {
|
||
|
#ifdef __APPLE__
|
||
|
makeCurrent();
|
||
|
CGLContextObj context = CGLGetCurrentContext();
|
||
|
GLint value = synchronize; //0 = draw immediately (no vsync), 1 = draw once per frame (vsync)
|
||
|
CGLSetParameter(context, kCGLCPSwapInterval, &value);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void paintGL() {
|
||
|
unsigned outputWidth = width();
|
||
|
unsigned outputHeight = height();
|
||
|
|
||
|
glMatrixMode(GL_PROJECTION);
|
||
|
glLoadIdentity();
|
||
|
glOrtho(0, outputWidth, 0, outputHeight, -1.0, 1.0);
|
||
|
glViewport(0, 0, outputWidth, outputHeight);
|
||
|
|
||
|
glMatrixMode(GL_MODELVIEW);
|
||
|
glLoadIdentity();
|
||
|
|
||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (filter == Video::FilterPoint) ? GL_NEAREST : GL_LINEAR);
|
||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (filter == Video::FilterPoint) ? GL_NEAREST : GL_LINEAR);
|
||
|
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, rasterWidth, rasterHeight, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, buffer);
|
||
|
|
||
|
double w = (double)rasterWidth / (double)textureWidth;
|
||
|
double h = (double)rasterHeight / (double)textureHeight;
|
||
|
unsigned u = outputWidth;
|
||
|
unsigned v = outputHeight;
|
||
|
|
||
|
glBegin(GL_TRIANGLE_STRIP);
|
||
|
glTexCoord2f(0, 0); glVertex3i(0, v, 0);
|
||
|
glTexCoord2f(w, 0); glVertex3i(u, v, 0);
|
||
|
glTexCoord2f(0, h); glVertex3i(0, 0, 0);
|
||
|
glTexCoord2f(w, h); glVertex3i(u, 0, 0);
|
||
|
glEnd();
|
||
|
}
|
||
|
|
||
|
void initializeGL() {
|
||
|
format().setDoubleBuffer(true);
|
||
|
|
||
|
texture = 0;
|
||
|
textureWidth = 0;
|
||
|
textureHeight = 0;
|
||
|
buffer = 0;
|
||
|
resize(rasterWidth = 256, rasterHeight = 256);
|
||
|
|
||
|
glDisable(GL_ALPHA_TEST);
|
||
|
glDisable(GL_BLEND);
|
||
|
glDisable(GL_DEPTH_TEST);
|
||
|
glDisable(GL_POLYGON_SMOOTH);
|
||
|
glDisable(GL_STENCIL_TEST);
|
||
|
glEnable(GL_DITHER);
|
||
|
glEnable(GL_TEXTURE_2D);
|
||
|
glClearColor(0.0, 0.0, 0.0, 0.0);
|
||
|
}
|
||
|
} *widget;
|
||
|
|
||
|
bool cap(const string& name) {
|
||
|
if(name == Video::Synchronize) return true;
|
||
|
if(name == Video::Filter) return true;
|
||
|
if(name == "QWidget") return true;
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
any get(const string& name) {
|
||
|
if(name == Video::Synchronize) return widget->synchronize;
|
||
|
if(name == Video::Filter) return widget->filter;
|
||
|
if(name == "QWidget") return parent;
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool set(const string& name, const any& value) {
|
||
|
if(name == Video::Synchronize) {
|
||
|
widget->synchronize = any_cast<bool>(value);
|
||
|
widget->updateSynchronization();
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
if(name == Video::Filter) {
|
||
|
widget->filter = any_cast<unsigned>(value);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
if(name == "QWidget") {
|
||
|
parent = any_cast<QWidget*>(value);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool lock(uint32_t *&data, unsigned &pitch, unsigned width, unsigned height) {
|
||
|
widget->resize(width, height);
|
||
|
widget->rasterWidth = width;
|
||
|
widget->rasterHeight = height;
|
||
|
|
||
|
pitch = widget->textureWidth * sizeof(uint32_t);
|
||
|
return data = widget->buffer;
|
||
|
}
|
||
|
|
||
|
void unlock() {
|
||
|
}
|
||
|
|
||
|
void clear() {
|
||
|
memset(widget->buffer, 0, widget->textureWidth * widget->textureHeight * sizeof(uint32_t));
|
||
|
widget->updateGL();
|
||
|
}
|
||
|
|
||
|
void refresh() {
|
||
|
widget->updateGL();
|
||
|
}
|
||
|
|
||
|
bool init() {
|
||
|
layout = new QVBoxLayout;
|
||
|
layout->setMargin(0);
|
||
|
|
||
|
widget = new RubyGLWidget;
|
||
|
widget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||
|
layout->addWidget(widget);
|
||
|
parent->setLayout(layout);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
void term() {
|
||
|
}
|
||
|
};
|
||
|
|
||
|
DeclareVideo(QtOpenGL)
|
||
|
|
||
|
};
|