Site Contents

Home
Programming
OpenGL Demos
MFC OpenGL
Tutorial 1
Graphics Demos
Jonathan
Travel
Garden

Main Guestbook
Help!
Contact Us

Forum

ISP Referral

Page Validation

Valid XHTML 1.0!
Valid CSS!

tutorial 1 - simple project

using OpenGL

The first thing we have to do is write a small class to handle the OpenGL routines for getting a device context, etc. Because this tutorial is meant for people who have experience of Win32 programming, I won't explain what the code in this class does. The code is commented which should help those who may have a different way of using Win32 in their programmes. I used the ClassWizard to add the COpenGL class to my project in the files "OpenGL.cpp" and "OpenGL.h".

Don't forget to include the OpenGL headers in these files and to include your new class in the other source files!

// OpenGL.h: interface for the COpenGL class.
//
//////////////////////////////////////////////////////////////////////

class COpenGL  
{
public:
	COpenGL();
	virtual ~COpenGL();

	// member variables
	// windows stuff
	HDC		m_hDC;			// The device context for OpenGL
	HGLRC	m_hRC;			// Render Context for OpenGL
	// viewing
	int		m_view_width;
	int		m_view_height;
	float	m_view_aspect;
	float	m_view_fov;
	float	m_view_near_clip;
	float	m_view_far_clip;

	// member functions
	void Init(HDC the_device_context);
	void UnInit(void);
	void Setup(void);

	void Set_Viewport_Size(int width, int height);
	void Set_Viewport3D(void);
	void Set_Viewport2D(void);
	void Finish_Render(void);
};

// OpenGL.cpp: implementation of the COpenGL class.
//
//////////////////////////////////////////////////////////////////////

COpenGL::COpenGL()
{
	HDC		m_hDC = NULL;
	HGLRC	m_hRC = NULL;
	
	m_view_far_clip = 3000.0f;
	m_view_near_clip = 5.0f;
	m_view_fov = 50.0f;
}

COpenGL::~COpenGL()
{

}

void COpenGL::Init(HDC the_device_context)
{
	// Initialise OpenGL

	// Get a DC for the OpenGL render window
	m_hDC = the_device_context;

	// Set the pixel format for this DC
	static PIXELFORMATDESCRIPTOR pfd =
	{
		sizeof (PIXELFORMATDESCRIPTOR),	// strcut size 
		1,						// Version number
		PFD_DRAW_TO_WINDOW |    // Flags, draw to a window,
		PFD_SUPPORT_OPENGL |    // use OpenGL
		PFD_DOUBLEBUFFER,		// double buffered
		PFD_TYPE_RGBA,          // RGBA pixel values
		32,                     // 32-bit color
		0, 0, 0,                // RGB bits & shift sizes.
		0, 0, 0,                // Don't care about them
		0, 0,                   // No alpha buffer info
		0, 0, 0, 0, 0,          // No accumulation buffer
		32,                     // 32-bit depth buffer
		0,                      // No stencil buffer
		0,                      // No auxiliary buffers
		PFD_MAIN_PLANE,         // Layer type
		0,                      // Reserved (must be 0)
		0,                      // No layer mask
		0,                      // No visible mask
		0                       // No damage mask
	};

    int nMyPixelFormatID = ChoosePixelFormat( m_hDC, &pfd );

    SetPixelFormat( m_hDC, nMyPixelFormatID, &pfd );

	// get a render context for OpenGL
	m_hRC = wglCreateContext(m_hDC);
	wglMakeCurrent (m_hDC, m_hRC);
}

void COpenGL::UnInit()
{
	// Tell windows we don't want to use OpenGL anymore
	wglMakeCurrent(m_hDC, NULL);
	wglDeleteContext(m_hRC);
}

void COpenGL::Set_Viewport_Size(int width, int height)
{
	// update the window properties

	// prevent divide by zero
	if (height == 0) height = 1;

	m_view_width = width;
	m_view_height = height;

	m_view_aspect = width/height;
}

void COpenGL::Set_Viewport3D()
{
	// set up the viewing transforms for a 3D view
	glMatrixMode( GL_PROJECTION );
	glLoadIdentity();

	// a perspective-view matrix...
	gluPerspective(
		m_view_fov,			// Field-of-view angle
		m_view_aspect,		// Aspect ratio of view volume
		m_view_near_clip,	// Distance to near clipping plane
		m_view_far_clip );	// Distance to far clipping plane

	glViewport( 0, 0, m_view_width, m_view_height );

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}

void COpenGL::Set_Viewport2D()
{
	// Setup the viewing transformations for 2D
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	gluOrtho2D(0,m_view_width,m_view_height,0);
	glViewport(0, 0, m_view_width, m_view_height);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}

void COpenGL::Finish_Render()
{
	glFlush();
	SwapBuffers(m_hDC);
}

void COpenGL::Setup()
{
	// put generic OpenGL code here

	glClearColor(0.0, 0.0, 0.0, 0.0);

	// Set OpenGL state variables
	glPolygonMode(GL_FRONT, GL_FILL);
	glPolygonMode(GL_BACK, GL_LINE);

	glEnable(GL_CULL_FACE);
	glCullFace(GL_BACK);

	glFrontFace(GL_CCW);
}

You will also need to add an instance of the new class into your CDlg class declaration (COpenGL m_OpenGL;). Inside the CDlg::OnInitDialog() method you need to add this magical piece of code: m_OpenGL.Init( (GetDC())->m_hDC ) to get a valid device context.

We're nearly there now, I promise! You need to add a window resizing event for our dialog - use the ClassWizard to do this:

AppWizard Step 2 (click to enlarge)

You should then add the following line of code to the new event handler:

void CDlg::OnSize(UINT nType, int cx, int cy) 
{
	CDialog::OnSize(nType, cx, cy);
	
	// TODO: Add your message handler code here
	m_OpenGL.Set_Viewport_Size(cx,cy);
}

You'll notice that we have missed out an important call - freeing up the device context when our application closes. Using the ClassWizard, add a WM_DESTROY event handler to the dialog class. You need to call m_OpenGL.UnInit() inside that event handler.

Finally, we need somewhere to make our calls to OpenGL. As it is, our programme just draws a blank window. We can change this by using the ClassWizard to declare for us the OnIdle() method in our CApp class. You have to override this member function to perform idle-time processing. OnIdle is called in the default message loop when the application’s message queue is empty, in the same way that you would call a Draw_Frame() function in your Win32 programmes after a call to PeekMessage.

AppWizard Step 2 (click to enlarge)

To bring this tutorial to an end, let's do some OpenGL! All of the code below should not be new to you, it is just a simple routine to draw to spinning triangles in the window.

BOOL CApp::OnIdle(LONG lCount) 
{
	// "Pause" the application while our app is minimised
	if (m_pTheDialog->IsIconic()) return FALSE;

	static float rotation = 0;

	////////// CLEAR BUFFERS ////////////////////
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	////////// SET UP 3D VIEWPORT ///////////////
	m_pTheDialog->m_OpenGL.Set_Viewport3D();

	gluLookAt(0.0f, 0.0f, 50.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);

	// draw two spinning triangles, back to back
	glPushMatrix();
	{
		glRotatef(rotation,0,1,0);
		{
			glBegin(GL_TRIANGLES);
			{
				// first triangle
				glColor3f(  0.0f,  1.0f, 0.0f);
				glVertex3f( 0.0f, 15.0f, 0.0f);

				glColor3f(    0.0f,   1.0f, 0.0f);
				glVertex3f( -15.0f, -15.0f, 0.0f);

				glColor3f(   0.0f,   0.0f, 0.0f);
				glVertex3f( 15.0f, -15.0f, 0.0f);

				// second triangle
				glColor3f(  0.0f,  0.0f, 1.0f);
				glVertex3f( 0.0f, 15.0f, 0.0f);

				glColor3f(  0.0f,   0.0f, 0.0f);
				glVertex3f(15.0f, -15.0f, 0.0f);

				glColor3f(    0.0f,   0.0f, 1.0f);
				glVertex3f( -15.0f, -15.0f, 0.0f);
			}
			glEnd();
		}
	}
	glPopMatrix();

	////////// SET UP 2D VIEWPORT ///////////////
	m_pTheDialog->m_OpenGL.Set_Viewport2D();

	////////// RENDER 2D SCENE //////////////////

	////////// FINISH RENDERING /////////////////
	m_pTheDialog->m_OpenGL.Finish_Render();

	////////// NONE-GRAPHICS RELATED CODE ///////
	
	if (rotation >= 358)
		rotation = 0;
	else
		rotation+=2;

	// prevent our simple application from stealing too many CPU cycles
	// this is NOT the proper way to control the frame rate!!!
	Sleep(10);

	// request more idle time for our application
	return TRUE;
}

And if you compile all this code you end up with this....

AppWizard Step 2 (click to enlarge)

You will notice that you cannot resize the window. You can fix this by going into the Dialog Resource Editor and right-clicking on the dialog and selecting Properties|Styles|Border|Resizing. You will also see options for maximise and minimise buttons, plus many more options.

If you want the complete source code, including MSVC Workspace and Project files - click here

That brings this tutorial to an end. If you spot any mistakes, either in the source code or the tutorial itself, please do let us know by emailing hidden email address.

 

Part 1: Introduction Part 2: Getting Started

Part 3: Creating a Window Part 4: Using OpenGL

Go to Top

Page Stats

Page last updated: 19:21 GMT on Saturday 1 January 2005
This page has had 3841 hits since 27 March 2004. Last viewed on 6 September 2010.
It took the server 0.0623262 seconds to generate this page.

Site designed and maintained by Jonathan Copelin
Go to homepage