|
|
The OpenGlWin class
At the heart is the OpenGlWin class. It is an Abstract Base Class whose Draw Method must be overridden.
Download the project here.
OpenGlWin.h
#ifndef __OPEN_GL_H__
#define __OPEN_GL_H__
#include <windows.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include "ChildWindow.h"
class OpenGlWin : public ChildWindow {
public:
OpenGlWin(Wnd& parent, int x, int y, int width, int height, int bits=24);
virtual ~OpenGlWin();
virtual void Draw() = 0;
void MakeCurrent(bool b=true);
void SwapBuffers();
virtual void Move(int x, int y, int width, int height, bool repaint=true);
private:
void SetPixelFormat(int bits);
void Error();
HDC hdc_ ; // Private GDI Device Context
HGLRC hglrc_; // Permanent Rendering Context
};
#endif
OpenGlWin.cpp
#include "OpenGlWin.h"
/*
Performs hidden surface removal using the Depth Test:
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
*/
LRESULT CALLBACK OpenGlWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
OpenGlWin* glwin=reinterpret_cast<OpenGlWin*>(::GetWindowLong(hWnd, GWL_USERDATA));
switch (uMsg) {
case WM_PAINT: {
glwin->Draw();
break;
}
case WM_ERASEBKGND:
return 1; // Do not erase background between frames
break;
}
return DefWindowProc(hWnd,uMsg,wParam,lParam);
}
OpenGlWin::OpenGlWin(Wnd& parent, int x, int y, int width, int height, int bits) :
ChildWindow(parent), hdc_(0) , hglrc_(0) {
WNDCLASSEXW wc;
wc.cbSize = sizeof(wc);
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wc.lpfnWndProc = OpenGlWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = 0;
wc.hIcon = 0; // LoadIcon (0, IDI_WINLOGO);
wc.hCursor = LoadCursor(0, IDC_ARROW);
wc.hbrBackground = 0; // No Background Required For GL
wc.lpszMenuName = 0; // No Menu
wc.lpszClassName = L"OpenGlWnd";
wc.hIconSm = 0;
if (!RegisterClassExW(&wc)) {
MessageBoxA(0,"Failed To Register The Window Class.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return;
}
Create(L"OpenGlWnd", x, y, width, height, WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
Show();
hdc_ = GetDC(hwnd_);
SetPixelFormat(bits);
if (!(hglrc_= ::wglCreateContext(hdc_))) {
Error();
throw "wglCreateContext";
}
}
OpenGlWin::~OpenGlWin() {
::wglDeleteContext(hglrc_);
MakeCurrent(false);
}
void OpenGlWin::SetPixelFormat(int bits) {
PIXELFORMATDESCRIPTOR pfd;
::ZeroMemory(&pfd,sizeof(pfd));
pfd.nSize = sizeof(pfd);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = bits;
pfd.cDepthBits = 32;
pfd.iLayerType = PFD_MAIN_PLANE;
GLuint pixelFormat;
if (! (pixelFormat = ::ChoosePixelFormat(hdc_,&pfd))) {
throw "ChoosePixelFormat";
}
if (! ::SetPixelFormat(hdc_,pixelFormat,&pfd)) {
throw "SetPixelFormat";
}
}
void OpenGlWin::MakeCurrent(bool b) {
if (b) ::wglMakeCurrent(hdc_,hglrc_);
else ::wglMakeCurrent(0,0);
}
void OpenGlWin::Error() {
GLenum errorno = glGetError() ;
if (errorno != GL_NO_ERROR)
MessageBoxA(0,(const char*)gluErrorString(errorno),0,0) ;
}
/* A double buffered DC is used. anything drawn to the DC actually goes to
a non-visible space in memory. This behaviour is set with the PFD_DOUBLEBUFFER
flag (see SetPixelFormat) */
void OpenGlWin::SwapBuffers() {
::SwapBuffers(hdc_);
}
void OpenGlWin::Move(int x, int y, int width, int height, bool repaint) {
ChildWindow::Move(x, y, width, height, false);
MakeCurrent();
glViewport(0,0,width,height); // Reset The Current Viewport
glMatrixMode(GL_PROJECTION); // Select The Projection Matrix
glLoadIdentity(); // Reset The Projection Matrix
//glOrtho2f(-1,1,-1,1);
// Calculate The Aspect Ratio Of The Window
gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);
glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
glLoadIdentity();
MakeCurrent(false);
}
The Main Program
Main.cpp
#include "OverlappedWindow.h"
#include "WndApplication.h"
#include "OpenGlWin_1.h"
OpenGlWin_1* oglw = 0;
LRESULT CALLBACK WndProc(
HWND hWnd,
UINT msg,
WPARAM wParam,
LPARAM lParam ) {
switch( msg ) {
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_SIZE: {
int width = LOWORD(lParam);
int height= HIWORD(lParam);
oglw->Move(20,20,width-40,height-40);
break;
}
default:
return DefWindowProc( hWnd, msg, wParam, lParam);
}
return 0;
}
int WINAPI WinMain(
HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow) {
OverlappedWindow ow(WndProc, L"Open GL", 50, 100, 300, 300,
0);//WS_CLIPCHILDREN);// | WS_CLIPSIBLINGS);
oglw = new OpenGlWin_1(ow,20,20,200,200);
ow.Show();
return EnterMsgLoop();
delete oglw; // NEVER REACHED!
}
The derived class
>OpenGlWin_1.h
#ifndef __OPEN_GL_WIN_1__
#define __OPEN_GL_WIN_1__
#include "OpenGlWin.h"
class OpenGlWin_1 : public OpenGlWin {
public:
OpenGlWin_1(Wnd& parent, int x, int y, int width, int height);
virtual void Draw();
};
#endif
OpenGlWin_1.cpp
#include "OpenGlWin_1.h"
OpenGlWin_1::OpenGlWin_1(Wnd& parent, int x, int y, int width, int height) :
OpenGlWin(parent, x, y, width, height) {
}
void OpenGlWin_1::Draw() {
MakeCurrent();
glClearColor(0.0f, 0.0f, 0.0f, 0.0f) ;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer
glColor3f(1.0, 1.0, 1.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
glBegin(GL_POLYGON);
glVertex2f(-0.5, -0.5);
glVertex2f(-0.5, 0.5);
glVertex2f(0.5, 0.5);
glVertex2f(0.5, -0.5);
glEnd();
glFlush();
SwapBuffers();
MakeCurrent(false);
}
|