// GfxOpenGL.cpp
//
// Implements all the OpenGL graphics functionality for the "NewView" demo
// as declared in Gfx.h.
//
// Copyright (C) 2009 John Hilton
//
// Implements the CGfxOpenGL class which implements the IGfx interface for
// graphics transformations and drawing.
//
// CGfxOpenGL
// (is a): IGfx - general graphics interface
// (has a) m_pImpl-> CGfxOpenGLImpl - helper class for CGfxDirect3D
#include "stdafx.h"
#include "wingdi.h"
#include "gl/gl.h"
#pragma comment( lib, "opengl32.lib" )
#include "Gfx.h"
#include "GfxSubclass.h"
#include "GeneralView.h"
template< typename T >
class CGfxOpenGLImpl
: public CGfxSubclass<T>
{
public:
typename IGfx<T>::ICallbacks* m_pCallbacks;
IGfx<T>* m_pGfx;
HDC m_hDC;
HGLRC m_hRC;
CGfxOpenGLImpl(typename IGfx<T>::ICallbacks& Callbacks, IGfx<T>& Gfx)
: m_pCallbacks(&Callbacks)
, m_pGfx(&Gfx)
, m_hRC(NULL)
{
}
~CGfxOpenGLImpl()
{
if (m_hWnd)
{
DestroyRC();
UnsubclassWindow();
}
}
virtual void /*CWindowImpl*/ OnFinalMessage( HWND hWnd )
{
m_pCallbacks->OnFinalMessage( hWnd ); // may delete this
}
void Attach( HWND hWnd )
{
if (!m_hWnd && hWnd)
{
// Create
ATLVERIFY(SubclassWindow(hWnd));
m_hDC = GetDC();
ASSERT(m_hDC);
CreateRC(m_hDC);
}
else if (m_hWnd && !hWnd)
{
// Destroy
DestroyRC();
ReleaseDC(m_hDC);
m_hDC = NULL;
UnsubclassWindow();
}
else if (m_hWnd)
{
// Change
UnsubclassWindow();
SubclassWindow( hWnd );
}
}
// create the OpenGL rendering context
void CreateRC( HDC hDC )
{
int nPixelFormat;
static PIXELFORMATDESCRIPTOR pfd = {
sizeof(PIXELFORMATDESCRIPTOR),
1, // structure version
PFD_DRAW_TO_WINDOW |
PFD_SUPPORT_OPENGL |
PFD_DOUBLEBUFFER,
PFD_TYPE_RGBA,
24, // 24 bit
0,0,0,0,0,0,
0,0,
0,0,0,0,0,
32, // depth buffer bits
0,
0,
PFD_MAIN_PLANE,
0,
0,0,0 };
// Choose and set the pixel format
nPixelFormat = ChoosePixelFormat(hDC, &pfd);
ATLVERIFY(SetPixelFormat(hDC, nPixelFormat, &pfd));
// Create the rendering context, make it current, initialize and deselect it
m_hRC = wglCreateContext(hDC);
ATLVERIFY(wglMakeCurrent(hDC,m_hRC));
ConfigureRC();
wglMakeCurrent(NULL,NULL);
// Ensure a non-palette mode is selected
DescribePixelFormat(hDC, nPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
if(pfd.dwFlags & PFD_NEED_PALETTE)
{
MessageBox( _T("Cannot run with a palette graphics mode."), _T(__FILE__), MB_OK );
exit(1);
}
}
void DestroyRC()
{
if (m_hRC)
{
// Destroy the OpenGL rendering context
wglDeleteContext(m_hRC);
m_hRC = NULL;
}
}
void ConfigureRC()
{
// Light values and coordinates
GLfloat ambientLight[] = { 0.4f, 0.4f, 0.4f, 1.0f };
GLfloat diffuseLight[] = { 0.7f, 0.7f, 0.7f, 1.0f };
GLfloat specular[] = { 0.9f, 0.9f, 0.9f, 1.0f };
GLfloat lightPos[] = { -50.0f, 200.0f, 200.0f, 1.0f };
GLfloat specref[] = { 0.6f, 0.6f, 0.6f, 1.0f };
glEnable(GL_DEPTH_TEST); // Hidden surface removal
// Enable lighting
glEnable(GL_LIGHTING);
// Setup light 0
glLightModelfv(GL_LIGHT_MODEL_AMBIENT,ambientLight);
glLightfv(GL_LIGHT0,GL_AMBIENT,ambientLight);
glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuseLight);
glLightfv(GL_LIGHT0,GL_SPECULAR,specular);
// Position and turn on the light
glLightfv(GL_LIGHT0,GL_POSITION,lightPos);
glEnable(GL_LIGHT0);
// Enable color tracking
glEnable(GL_COLOR_MATERIAL);
// Set Material properties to follow glColor values
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
// All materials hereafter have full specular reflectivity
// with a moderate shine
glMaterialfv(GL_FRONT, GL_SPECULAR,specref);
glMateriali(GL_FRONT,GL_SHININESS,64);
// Trigger a redraw
Invalidate();
}
void ClearBackground()
{
// background
glClearColor( 20.0f/255, 20.0f/255, 100.0f/255, 1.0f );
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
LRESULT OnSize(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
nMsg; wParam; bHandled;
int cx = LOWORD(lParam);
int cy = HIWORD(lParam);
if (!m_hWnd || !cy) return 0L;
HDC hDC = GetDC();
ASSERT(hDC);
VERIFY(wglMakeCurrent( hDC, m_hRC ));
glViewport( 0, 0, cx, cy );
VERIFY(ReleaseDC(hDC));
return 0L;
}
LRESULT OnPaint(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
nMsg; wParam; lParam; bHandled;
BOOL bRet = wglMakeCurrent( m_hDC, m_hRC );
ASSERT(bRet); bRet;
ClearBackground();
m_pCallbacks->OnPaint( *m_pGfx );
glFlush();
V(SwapBuffers( m_hDC ));
V(wglMakeCurrent( NULL, NULL ));
V(ValidateRect( NULL ));
return 0L;
}
void Draw( DWORD* pItem, int length )
{
int count;
while (length > 0)
switch (*pItem & 0xff000000)
{
case gfxColor:
glColor3f( ((*pItem>>16)&0xff)/255.0f,
((*pItem>> 8)&0xff)/255.0f,
((*pItem )&0xff)/255.0f );
pItem++;
length--;
break;
case gfxTriangleStrip:
count = *pItem & 0x00000fff;
ASSERT(count);
glDisable( GL_CULL_FACE );
GLboolean cullface;
glGetBooleanv( GL_CULL_FACE, &cullface );
glBegin( GL_TRIANGLE_STRIP );
for (int i=0; i<count+2; i++)
glVertex3f( *(GLfloat*) (pItem+1+3*i),
*(GLfloat*) (pItem+2+3*i),
*(GLfloat*) (pItem+3+3*i) );
glEnd();
pItem += 1+3*(count+2);
length -= 1+3*(count+2);
break;
default:
ASSERT(0);
return;
}
}
};
#pragma region CGfxOpenGL
template< typename T >
CGfxOpenGL<T>::CGfxOpenGL(IGfx<T>::ICallbacks& Callbacks)
{
m_pImpl = new CGfxOpenGLImpl<T>(Callbacks, *this);
ASSERT( m_pImpl );
}
template< typename T >
CGfxOpenGL<T>::~CGfxOpenGL(void)
{
if (m_pImpl) delete m_pImpl;
}
template< typename T >
HWND CGfxOpenGL<T>::Hwnd()
{
return m_pImpl ? m_pImpl->m_hWnd : NULL;
}
template< typename T >
void CGfxOpenGL<T>::Attach( HWND hWnd )
{
m_pImpl->Attach( hWnd );
}
template< typename T >
void CGfxOpenGL<T>::ConfigureView( T ViewVolume[7], T ViewToWorld[4][3] )
{
ConfigureView_OpenGL( ViewVolume, ViewToWorld );
}
template< typename T >
void CGfxOpenGL<T>::Push()
{
glMatrixMode( GL_MODELVIEW );
::glPushMatrix();
}
template< typename T >
void CGfxOpenGL<T>::Pop()
{
glMatrixMode( GL_MODELVIEW );
::glPopMatrix();
}
template< typename T >
void CGfxOpenGL<T>::Rotate( T Angle, T Axis[3] )
{
if (sizeof(T) == sizeof(float))
glRotatef( Angle, Axis[0], Axis[1], Axis[2] );
else
glRotated( Angle, Axis[0], Axis[1], Axis[2] );
}
template< typename T >
void CGfxOpenGL<T>::Rotate( T Matrix[3][3] )
{
if (sizeof(T) == sizeof(float))
{
GLfloat m[4][4] = {
{ Matrix[0][0], Matrix[0][1], Matrix[0][2], 0 },
{ Matrix[1][0], Matrix[1][1], Matrix[1][2], 0 },
{ Matrix[2][0], Matrix[2][1], Matrix[2][2], 0 },
{ 0, 0, 0, 1 }
};
glMultMatrixf( m[0] );
}
else
{
GLdouble m[4][4] = {
{ Matrix[0][0], Matrix[0][1], Matrix[0][2], 0 },
{ Matrix[1][0], Matrix[1][1], Matrix[1][2], 0 },
{ Matrix[2][0], Matrix[2][1], Matrix[2][2], 0 },
{ 0, 0, 0, 1 }
};
glMultMatrixd( m[0] );
}
}
template< typename T >
void CGfxOpenGL<T>::Translate( T x, T y, T z )
{
if (sizeof(T) == sizeof(float))
glTranslatef( x, y, z );
else
glTranslated( x, y, z );
}
template< typename T >
void CGfxOpenGL<T>::Scale( T factor )
{
if (sizeof(T) == sizeof(float))
glScalef( factor, factor, factor );
else
glScaled( factor, factor, factor );
}
template< typename T >
void CGfxOpenGL<T>::Scale( T xyz[3] )
{
if (sizeof(T) == sizeof(float))
glScalef( xyz[0], xyz[1], xyz[2] );
else
glScaled( xyz[0], xyz[1], xyz[2] );
}
template< typename T >
void CGfxOpenGL<T>::Render( DWORD* pItem, int length )
{
m_pImpl->Draw( pItem, length );
}
// Instantiate the class
template CGfxOpenGL<float>;
#pragma endregion