#include "stdafx.h"
#include "openglwnd.h"
#include <gl/gl.h>
#include <gl/glu.h>
#define STUPID_OPENGL_CLASS _T("StupidOpenGL1.0")
#define OPENGL_CLASS _T("OpenGL1.0")
// This is the structure used in CreateOpenGLWindow
typedef struct _tagOPENGLWNDCREATESTRUCT
{
COpenGLWndController *pController;
LPPIXELFORMATDESCRIPTOR pfd;
int pixelFormat;
} OPENGLWNDCREATESTRUCT,*LPOPENGLWNDCREATESTRUCT;
#define GWL_GLDATA 0
// This is the structure the OpenGL window carries around with it. In GWL_GLDATA
typedef struct _tagOPENGLDATA
{
HDC hDC;
HGLRC hRC;
COpenGLWndController *pController;
} OPENGLDATA,*LPOPENGLDATA;
// CreateOpenGLWindow
// Pass it the controller to use and the requested pixel format, and it creates the
// window using the style given in dwStyle. Normally you would use WS_CHILD for a
// a child window.
// It uses a temporary window solution for querying special video card capabilities.
// A dummy window is first created, and an OpenGL rendering context is created for it
// Then the controllers ValidatePixelFormat is called, and within that function you
// can check for any extensions your card supports. The return value is the pixel
// format you want to use.
// In my star wars example, I use this method to turn on FSAA.
HWND CreateOpenGLWindow(HINSTANCE hInst,HWND hParent,DWORD dwStyle,UINT id,LPRECT rt,COpenGLWndController *pController,LPPIXELFORMATDESCRIPTOR pfd)
{
// ok first create the stupid temporary window
if (!pController || !pfd)
return NULL;
// create dummy window
HWND hStupid = CreateWindowEx(0L,STUPID_OPENGL_CLASS,_T(""),WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,0,0,1,1,hParent,0,hInst,NULL);
if (!hStupid)
return NULL;
// ok now setup the opengl for it
HDC hDC = GetDC(hStupid);
HGLRC hRC;
pfd->dwFlags |= (PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER);
int requestedFormat;
int format = ChoosePixelFormat( hDC, pfd );
if (format == 0 ||
(SetPixelFormat( hDC, format, pfd ) == FALSE) ||
((hRC = wglCreateContext(hDC)) == NULL)
)
{
ReleaseDC(hStupid,hDC);
DestroyWindow(hStupid);
return NULL;
}
// ok validate it now
wglMakeCurrent(hDC,hRC);
requestedFormat = pController->ValidatePixelFormat(hDC,format);
// destroy openGL resources
wglMakeCurrent(NULL,NULL);
ReleaseDC(hStupid,hDC);
wglDeleteContext(hRC);
// destroy temporary window
DestroyWindow(hStupid);
// now create real window
OPENGLWNDCREATESTRUCT ogwcs;
ogwcs.pController = pController;
ogwcs.pfd = pfd;
ogwcs.pixelFormat = requestedFormat;
return CreateWindowEx(0L,OPENGL_CLASS,_T(""),dwStyle | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,rt->left,rt->top,
rt->right - rt->left,rt->bottom - rt->top,hParent,(HMENU)id,hInst,&ogwcs);
}
// Base implementation. Use the suggested pixel format
int COpenGLWndController::ValidatePixelFormat(HDC hdc,int suggestedFormat)
{
return suggestedFormat;
}
// Stores away the parameters in the class.
void COpenGLWndController::SetParameters(HDC hdc,HGLRC hglrc)
{
m_hdc = hdc;
m_hglrc = hglrc;
}
// Draws - double buffering
void COpenGLWndController::Draw()
{
wglMakeCurrent(m_hdc,m_hglrc);
vDraw();
glFlush();
SwapBuffers(m_hdc);
}
static LRESULT OnOpenGLCreate(HWND hWnd,LPCREATESTRUCT lpcs)
{
// initialize opengl
HDC hDC;
HGLRC hRC;
LPOPENGLWNDCREATESTRUCT pogwcs = (LPOPENGLWNDCREATESTRUCT)lpcs->lpCreateParams;
// first ensure that we have the correct properties set
if ((GetWindowLong(hWnd,GWL_STYLE) & (WS_CLIPCHILDREN | WS_CLIPSIBLINGS)) !=
(WS_CLIPCHILDREN | WS_CLIPSIBLINGS))
{
return -1;
}
// get the device context (DC)
hDC = GetDC(hWnd);
if (!hDC)
return -1;
// set the pixel format for the DC
if (pogwcs->pixelFormat == 0 ||
(SetPixelFormat( hDC, pogwcs->pixelFormat, pogwcs->pfd ) == FALSE) ||
((hRC = wglCreateContext(hDC)) == NULL)
)
{
ReleaseDC(hWnd,hDC);
return -1;
}
// store the data in our window's memory
LPOPENGLDATA pData = new OPENGLDATA;
if (!pData)
{
wglDeleteContext(hRC);
ReleaseDC(hWnd,hDC);
return -1;
}
pData->hDC = hDC;
pData->hRC = hRC;
pData->pController = pogwcs->pController;
SetWindowLong(hWnd,GWL_GLDATA,(LONG)pData);
// ok now setup/initialize controller
wglMakeCurrent(hDC,hRC);
if (pData->pController)
{
RECT rt;
GetClientRect(hWnd,&rt);
pData->pController->SetParameters(pData->hDC,pData->hRC);
pData->pController->Init();
pData->pController->WindowSized(rt.right,rt.bottom);
}
return 0;
}
// Clean up any memory associated with the window, and destroy the controller
static LRESULT OnOpenGLDestroy(HWND hWnd)
{
LPOPENGLDATA pData = (LPOPENGLDATA)GetWindowLong(hWnd,GWL_GLDATA);
if (!pData)
return 0;
wglMakeCurrent(pData->hDC,pData->hRC);
if (pData->pController)
{
pData->pController->Close();
delete pData->pController;
}
wglMakeCurrent(NULL,NULL);
wglDeleteContext( pData->hRC );
ReleaseDC( hWnd,pData->hDC );
delete pData;
return 0;
}
// Paints the window using OpenGL
static LRESULT OnOpenGLPaint(HWND hWnd)
{
PAINTSTRUCT ps;
LPOPENGLDATA pData = (LPOPENGLDATA)GetWindowLong(hWnd,GWL_GLDATA);
HDC hDC = BeginPaint( hWnd, &ps );
if (pData->pController)
pData->pController->Draw();
EndPaint( hWnd, &ps );
return 0;
}
// Calls WindowSized in the controller
static LRESULT OnOpenGLSize(HWND hWnd,int cx,int cy)
{
LPOPENGLDATA pData = (LPOPENGLDATA)GetWindowLong(hWnd,GWL_GLDATA);
if (!pData)
return 0;
wglMakeCurrent(pData->hDC,pData->hRC);
if (pData->pController)
pData->pController->WindowSized(cx,cy);
return 0;
}
// Return the controller
static LRESULT OnOpenGLGetController(HWND hWnd)
{
LPOPENGLDATA pData = (LPOPENGLDATA)GetWindowLong(hWnd,GWL_GLDATA);
return (LRESULT)pData->pController;
}
// Sets the controller. We could be fancy and use RTTI for better type checking,
// but I didn't
static LRESULT OnOpenGLSetController(HWND hWnd,void *pController)
{
LPOPENGLDATA pData = (LPOPENGLDATA)GetWindowLong(hWnd,GWL_GLDATA);
wglMakeCurrent(pData->hDC,pData->hRC);
// destroy old controller if we have one
if (pData->pController)
{
pData->pController->Close();
delete pData->pController;
}
pData->pController = (COpenGLWndController*)pController;
if (pController)
{
RECT rt;
GetClientRect(hWnd,&rt);
pData->pController->SetParameters(pData->hDC,pData->hRC);
pData->pController->Init();
pData->pController->WindowSized(rt.right,rt.bottom);
pData->pController->Draw();
}
return 0;
}
static LRESULT CALLBACK OpenGLProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
switch (msg)
{
case WM_CREATE:
return OnOpenGLCreate(hWnd,(LPCREATESTRUCT)lParam);
case WM_DESTROY:
return OnOpenGLDestroy(hWnd);
case WM_SIZE:
return OnOpenGLSize(hWnd,LOWORD(lParam),HIWORD(lParam));
case WM_PAINT:
return OnOpenGLPaint(hWnd);
case WM_ERASEBKGND:
return TRUE;
case WM_SETCONTROLLER:
return OnOpenGLSetController(hWnd,(void*)lParam);
case WM_GETCONTROLLER:
return OnOpenGLGetController(hWnd);
default:
return DefWindowProc(hWnd,msg,wParam,lParam);
}
return 0;
}
// don't do anything
static LRESULT CALLBACK StupidOpenGLProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
return DefWindowProc(hWnd,msg,wParam,lParam);
}
// Registers the window classes
BOOL RegisterOpenGLWindow(HINSTANCE hInst)
{
WNDCLASSEX wcex;
// Initialize our Window class
if (GetClassInfoEx(hInst,OPENGL_CLASS,&wcex))
return TRUE;
// register main one
ZeroMemory(&wcex,sizeof(wcex));
wcex.cbSize = sizeof(wcex);
wcex.style = CS_VREDRAW | CS_HREDRAW | CS_OWNDC;
wcex.cbWndExtra = 4; /* space for our pointer */
wcex.lpfnWndProc = OpenGLProc;
wcex.hbrBackground = NULL;
wcex.hInstance = hInst;
wcex.hCursor = LoadCursor(NULL,IDC_ARROW);
wcex.lpszClassName = OPENGL_CLASS;
if (!RegisterClassEx(&wcex))
return FALSE;
// now the stupid one
wcex.cbSize = sizeof(wcex);
wcex.style = CS_OWNDC;
wcex.cbWndExtra = 0; /* space for our pointer */
wcex.lpfnWndProc = StupidOpenGLProc;
wcex.hbrBackground = NULL;
wcex.hInstance = hInst;
wcex.hCursor = LoadCursor(NULL,IDC_ARROW);
wcex.lpszClassName = STUPID_OPENGL_CLASS;
return RegisterClassEx(&wcex);
}