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:
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.
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....
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
.
Part
1: Introduction
Part
2: Getting Started
Part
3: Creating a Window
Part
4: Using OpenGL
Go to Top