Click here to Skip to main content
15,881,715 members
Articles / Multimedia / OpenGL

Win32 OpenGL Framework - Star Wars scrolling Text

Rate me:
Please Sign up or sign in to vote.
4.38/5 (6 votes)
6 Aug 20024 min read 147.3K   5.6K   39  
An article detailing a project which contains StarWars-esque scrolling text. It is done completely using OpenGL and shows some advanced OpenGL topics. Also included is a framework for using OpenGL windows in your Win32 programs.
#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);
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
United States United States
I have a Masters degree in Computer Science from the School of Engineering at Lehigh University.

When I got to school I bought a book on MFC and VC++ 5.0, and I thoroughly taught myself. Been loving it ever since. I tend to use pure Win32 now as I'm a big fan of small, quick code.

Comments and Discussions