/* video.wgl authors: byuu, krom license: public domain last updated: 2008-08-20 */ #include #include #include 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