215 lines
5.6 KiB
C++
Executable File
215 lines
5.6 KiB
C++
Executable File
/*
|
|
video.wgl
|
|
authors: byuu, krom
|
|
license: public domain
|
|
last updated: 2008-08-20
|
|
*/
|
|
|
|
#include <windows.h>
|
|
#include <GL/gl.h>
|
|
#include <GL/glext.h>
|
|
|
|
namespace ruby {
|
|
|
|
#include "wgl.hpp"
|
|
|
|
class pVideoWGL {
|
|
public:
|
|
VideoWGL &self;
|
|
uint32_t *buffer;
|
|
|
|
HDC display;
|
|
HGLRC wglcontext;
|
|
HWND window;
|
|
HINSTANCE glwindow;
|
|
GLuint gltexture;
|
|
|
|
struct {
|
|
HWND handle;
|
|
bool synchronize;
|
|
unsigned filter;
|
|
} settings;
|
|
|
|
bool cap(Video::Setting setting) {
|
|
if(setting == Video::Handle) return true;
|
|
if(setting == Video::Synchronize) return true;
|
|
if(setting == Video::Filter) return true;
|
|
return false;
|
|
}
|
|
|
|
uintptr_t get(Video::Setting setting) {
|
|
if(setting == Video::Handle) return (uintptr_t)settings.handle;
|
|
if(setting == Video::Synchronize) return settings.synchronize;
|
|
if(setting == Video::Filter) return settings.filter;
|
|
return false;
|
|
}
|
|
|
|
bool set(Video::Setting setting, uintptr_t param) {
|
|
if(setting == Video::Handle) {
|
|
settings.handle = (HWND)param;
|
|
return true;
|
|
}
|
|
|
|
if(setting == Video::Synchronize) {
|
|
if(settings.synchronize != param) {
|
|
settings.synchronize = param;
|
|
if(wglcontext) {
|
|
term();
|
|
init();
|
|
}
|
|
}
|
|
}
|
|
|
|
if(setting == Video::Filter) {
|
|
settings.filter = param;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool lock(uint32_t *&data, unsigned &pitch) {
|
|
pitch = 1024 * 4;
|
|
return data = buffer;
|
|
}
|
|
|
|
void unlock() {
|
|
}
|
|
|
|
void clear() {
|
|
memset(buffer, 0, 1024 * 1024 * sizeof(uint32_t));
|
|
glClearColor(0.0, 0.0, 0.0, 1.0);
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
glFlush();
|
|
SwapBuffers(display);
|
|
}
|
|
|
|
void refresh(unsigned width, unsigned height) {
|
|
RECT rc;
|
|
GetClientRect(settings.handle, &rc);
|
|
|
|
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_MAG_FILTER,
|
|
settings.filter == Video::FilterPoint ? GL_NEAREST : GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
|
|
settings.filter == Video::FilterPoint ? GL_NEAREST : GL_LINEAR);
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
glLoadIdentity();
|
|
glOrtho(0, width, 0, height, -1.0, 1.0);
|
|
glViewport(0, 0, rc.right, rc.bottom);
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glLoadIdentity();
|
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, 1024); //length of buffer in pixels
|
|
glTexSubImage2D(GL_TEXTURE_2D,
|
|
/* mip-map level = */ 0, /* x = */ 0, /* y = */ 0,
|
|
width, height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, buffer);
|
|
|
|
//OpenGL projection sets 0,0 as *bottom-left* of screen.
|
|
//therefore, below vertices flip image to support top-left source.
|
|
//texture range = x1:0.0, y1:0.0, x2:1.0, y2:1.0
|
|
//vertex range = x1:0, y1:0, x2:width, y2:height
|
|
double w = double(width) / 1024.0;
|
|
double h = double(height) / 1024.0;
|
|
int u = width;
|
|
int v = height;
|
|
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();
|
|
|
|
glFlush();
|
|
SwapBuffers(display);
|
|
}
|
|
|
|
bool init() {
|
|
buffer = new(zeromemory) uint32_t[1024 * 1024];
|
|
|
|
GLuint pixel_format;
|
|
PIXELFORMATDESCRIPTOR pfd;
|
|
memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
|
|
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
|
|
pfd.nVersion = 1;
|
|
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | (settings.synchronize ? PFD_DOUBLEBUFFER : 0);
|
|
pfd.iPixelType = PFD_TYPE_RGBA;
|
|
|
|
display = GetDC(settings.handle);
|
|
pixel_format = ChoosePixelFormat(display, &pfd);
|
|
SetPixelFormat(display, pixel_format, &pfd);
|
|
|
|
wglcontext = wglCreateContext(display);
|
|
wglMakeCurrent(display, wglcontext);
|
|
|
|
//disable unused features
|
|
glDisable(GL_ALPHA_TEST);
|
|
glDisable(GL_BLEND);
|
|
glDisable(GL_DEPTH_TEST);
|
|
glDisable(GL_POLYGON_SMOOTH);
|
|
glDisable(GL_STENCIL_TEST);
|
|
|
|
//enable useful and required features
|
|
glEnable(GL_DITHER);
|
|
glEnable(GL_TEXTURE_2D);
|
|
|
|
//create GL texture to copy buffer to
|
|
gltexture = 0;
|
|
glGenTextures(1, &gltexture);
|
|
glBindTexture(GL_TEXTURE_2D, gltexture);
|
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, 1024);
|
|
glTexImage2D(GL_TEXTURE_2D,
|
|
/* mip-map level = */ 0, /* internal format = */ GL_RGB,
|
|
/* width = */ 1024, /* height = */ 1024, /* border = */ 0,
|
|
/* format = */ GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, buffer);
|
|
|
|
return true;
|
|
}
|
|
|
|
void term() {
|
|
if(gltexture) {
|
|
glDeleteTextures(1, &gltexture);
|
|
gltexture = 0;
|
|
}
|
|
|
|
if(wglcontext) {
|
|
wglDeleteContext(wglcontext);
|
|
wglcontext = 0;
|
|
}
|
|
|
|
if(buffer) {
|
|
delete[] buffer;
|
|
buffer = 0;
|
|
}
|
|
}
|
|
|
|
pVideoWGL(VideoWGL &self_) : self(self_) {
|
|
settings.handle = 0;
|
|
settings.synchronize = false;
|
|
settings.filter = 0;
|
|
|
|
window = 0;
|
|
wglcontext = 0;
|
|
glwindow = 0;
|
|
gltexture = 0;
|
|
}
|
|
|
|
~pVideoWGL() { term(); }
|
|
};
|
|
|
|
bool VideoWGL::cap(Setting setting) { return p.cap(setting); }
|
|
uintptr_t VideoWGL::get(Setting setting) { return p.get(setting); }
|
|
bool VideoWGL::set(Setting setting, uintptr_t param) { return p.set(setting, param); }
|
|
bool VideoWGL::lock(uint32_t *&data, unsigned &pitch) { return p.lock(data, pitch); }
|
|
void VideoWGL::unlock() { p.unlock(); }
|
|
void VideoWGL::clear() { p.clear(); }
|
|
void VideoWGL::refresh(unsigned width, unsigned height) { p.refresh(width, height); }
|
|
bool VideoWGL::init() { return p.init(); }
|
|
void VideoWGL::term() { p.term(); }
|
|
VideoWGL::VideoWGL() : p(*new pVideoWGL(*this)) {}
|
|
VideoWGL::~VideoWGL() { delete &p; }
|
|
|
|
} //namespace ruby
|