2009-05-12 20:05:00 +02:00

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