Programming - Games - using OpenGL and C++

This toturial was written for me by Imran Khan (imranahmedkhan82@hotmail.com, iak1982@yahoo.com).
Copyright (c) 2004 is owned by Martin Baker

My First OpenGL Program:

In this section you will learn how to start programming with OpenGL and how to display a basic openGL window of any resolution,size.

  • Go to Project >> Settings >> on the LINK tab.Under "Object/Library Modules" at the beginning of
    the line add : OpenGL32.lib GLu32.lib GLaux.lib.

Now you can use OpenGL libraries in your Program.

  • Now Open a New "C++ Source file"

  • From now on we start coding . Add these Header file
#include <windows.h>
#include <gl\gl.h>
#include <gl\glu.h>
#include <gl\glaux.h>

Windows programmers are familiar with first headerfile ' window.h ' use for windows programming. Next 3 header files are for openGL Libraries.

  • Now we define some important variable.

HGLRC hRC=NULL;// Rendering Context
HDC hDC=NULL; //Device Context
HWND hWnd=NULL;
HINSTANCE hInstance;

bool active=TRUE;
bool fullscreen=TRUE;

First 2 variables are related 2 openGL and last 2 are related to windows programming. First we declare a Rendering Context 'hRC' which will links OpenGL to device context. To Draw anything on a window you have to create Device context ( 2nd line).so 'hRC' is rendering context and 'hDC' is device context. Next variable holds the Window handle and next varible holds the instance of the window we will create. Last 2 variables are boolean type ,first variable tells that whether the window is active or not, second variable tells us that whether the window is fullscreen or not. By default these values are set to TRUE.

  • Declare WndProc (Windows programmer are familiar with this method)
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

Now we will Initialize OpenGL. This method will be called after the creation of window.

int InitGL(GLvoid)
{
glShadeModel(GL_SMOOTH);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
return TRUE;
}

In the first line we enables the smooth shading.Smooth shading blends colors nicely across a polygon, and smoothes out lighting. Next we describe the background color of the window.g1ClearColor method got 4 arguments. First is red,2nd is green and 3rd is blue,4th one is a alpha value.You can create different colors by mixing up these values But the range of these values are from 0.0f to 1.0f. More the value more brighter will be the color.Then we set the prespective view. Next we return true , i.e opengl initializse correctly. If any error occur u can return false too.

We have initialize OpenGL.Now we will write a function which will draw to the screen.

int DrawGLScene(GLvoid)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
return TRUE;
}

First line clearing the screen to the color we made in the previous method and clear the depth buffer.Second line reset the scene. Then we return True that our method deosn't got any error.

Now we will define an method which is use to resize the scene according to the width and height of the Window.This method is not compulsory but it is better to use it.

GLvoid ReSizeGLScene(GLsizei width, GLsizei height)
{

glViewport(0,0,width,height);

glMatrixMode(GL_PROJECTION);
glLoadIdentity();

gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}

First we reset the viewport according to width and height of the window.glMatrixMode(GL_PROJECTION) Select The Projection Matrix. The perspective matrix isresponsible for adding perspective to our scene. glLoadIdentity() is use to reset the Projection Matrix. glMatrixMode(GL_MODELVIEW) select the modelview matrix. The modelview matrix is where our object information is stored. Then we reset the modelview matrix.

Now we will define a method which will be called whenever u want to kill this openGL window.It will release the

Rendering Context, Device Context and Window Handle.

GLvoid KillGLWindow(GLvoid) // Properly Kill The Window
{
if (fullscreen)
{
ChangeDisplaySettings(NULL,0);
ShowCursor(TRUE);
}

if (hRC)
{
if (!wglMakeCurrent(NULL,NULL))
{
MessageBox(NULL,"Release Of DC And RC Failed.","Shutdown Error",MB_OK | MB_ICONINFORMATION);
}

if (!wglDeleteContext(hRC))
{
MessageBox(NULL,"Release Rendering Context Failed.","Shutdown Error",MB_OK | MB_ICONINFORMATION);
}
hRC=NULL;
}

if (hDC && !ReleaseDC(hWnd,hDC))
{
MessageBox(NULL,"Release Device Context Failed.","Shutdown Error",MB_OK | MB_ICONINFORMATION);
hDC=NULL;
}

if (hWnd && !DestroyWindow(hWnd))
{
MessageBox(NULL,"Could Not Release hWnd.","Shutdown Error",MB_OK | MB_ICONINFORMATION);
hWnd=NULL;
}

if (!UnregisterClass("OpenGL",hInstance))
{
MessageBox(NULL,"Could Not Unregister Class.","Shutdown Error",MB_OK | MB_ICONINFORMATION);
hInstance=NULL;
}
}

First we check the ' fullscreen' flag whether it is True or not. If it is true , it means that the window is fullscreen. We then switch to window screen so that we can destroy it.Then we try to destroy the Rendering Object , first we check whether rendering object exist or not .If it exist it will try to detach the hRC from the hDC.If it fails to destroy it will show a message. Then we try to destroy Rendering Context.If it fails it will show a error message.In the same manner we try to destroy Device Context,Window,Unregistered the window class.

Here comes the main and the most important part of the code. It will Create OpenGL window.

BOOL CreateGLWindow(char* title, int width, int height, int bits, bool fullscreenflag)
{
GLuint PixelFormat;
WNDCLASS wc;
DWORD dwExStyle;
DWORD dwStyle;
RECT WindowRect;
WindowRect.left=(long)0;
WindowRect.right=(long)width;
WindowRect.top=(long)0;
WindowRect.bottom=(long)height;

fullscreen=fullscreenflag;

hInstance = GetModuleHandle(NULL);
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wc.lpfnWndProc = (WNDPROC) WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = "OpenGL";

if (!RegisterClass(&wc))
{
MessageBox(NULL,"Failed To Register The Window Class.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE;
}

// this function is continue...first we explain this part of the function

' CreateGLWindow ' has 5 arguments:

  • Title , Appears At The Top Of The Window.
  • Width Of The GL Window,
  • Height Of The GL Window,
  • Number Of Bits To Use For Color (8/16/24/32),
  • Fullscreen Mode or Windowed Mode.

First we define some variables. First define a variable to store the Pixel format .wc hold Window Class structure.dwExStyle and dwStyle will store the Window Style Information. dwExStyle for Extended Style and dwStyle for Normal Style. Next 5 variables are use to define the boundries of the window. Then we assign the value of fullscreenflag to fullscreen ( which we have define above). Next we grab an instance for our Window, then we define the Window Class ( windows programmer familiar with this ). Then we try to register the class .If we fail an error message will be shown.

Next part of the function...


if (fullscreen)
{
DEVMODE dmScreenSettings;
memset(&dmScreenSettings,0,sizeof(dmScreenSettings));
dmScreenSettings.dmSize=sizeof(dmScreenSettings);
dmScreenSettings.dmPelsWidth = width;
dmScreenSettings.dmPelsHeight = height;
dmScreenSettings.dmBitsPerPel = bits;
dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;


if (ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)
{

if (MessageBox(NULL,"The Requested Fullscreen Mode Is Not Supported By\nYour Video Card. Use Windowed Mode Instead?","NeHe GL",MB_YESNO|MB_ICONEXCLAMATION)==IDYES)
{
fullscreen=FALSE;
}
else
{
MessageBox(NULL,"Program Will Now Close.","ERROR",MB_OK|MB_ICONSTOP);
return FALSE;
}
}
}

if (fullscreen)
{
dwExStyle=WS_EX_APPWINDOW;
dwStyle=WS_POPUP;
ShowCursor(FALSE);
}
else
{
dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
dwStyle=WS_OVERLAPPEDWINDOW;
}

AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);

// this function is continue.... first we explain this part of function.

First we check whether the window is fullscreen or not.If it is then we set fullscreen mode.Then we define a Device mode( DEVMODE dmScreenSettings ) and then clear room to store our video (memset) .Then We set the width, height and bits that we want the screen to switch to.Then we check whether the fullmode is set successfully .If it is not it will show the error message "The Requested Fullscreen Mode Is Not Supported ...". with "Yes/NO" option. If you press No, Program will exit( in the else code ).If you press Yes. It will assign FLASE to FULLSCREEN flag , i.e now it will show Window.

Next we again check " if (fullscreen) ". Whether the mode is still fullscreen. If it is fullscreen then it will choose the extended window style,Hides the Cursor.If it is a window instead of fullscreen mode, we'll add WS_EX_WINDOWEDGE to the extended style. This gives the window a more 3D look. For style we'll use WS_OVERLAPPEDWINDOW instead of WS_POPUP. WS_OVERLAPPEDWINDOW creates a window with a title bar, sizing border, window menu, and minimize / maximize buttons.Last line adjust our window depending on what style of window we are creating.It is not usefull in Fullscreen Mode.

Next Part of the function...


if (!(hWnd=CreateWindowEx( dwExStyle,
"OpenGL",
title,
dwStyle |
WS_CLIPSIBLINGS |
WS_CLIPCHILDREN,
0, 0,
WindowRect.right-WindowRect.left,
WindowRect.bottom-WindowRect.top,
NULL,
NULL,
hInstance,
NULL)))
{
KillGLWindow();
MessageBox(NULL,"Window Creation Error.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE;
}

// this function is continue.... first we explain this part of function.

Now we will create a typical Window ( Windows programmers are familiar with this, so no explaination required for this code). Just one thing want to describe is this that we include the styles WS_CLIPSIBLINGS and WS_CLIPCHILDREN along with the style of window we've decided to use.WS_CLIPSIBLINGS and WS_CLIPCHILDREN are both REQUIRED for OpenGL to work properly. These styles prevent other windows from drawing over or into our OpenGL Window..In this section of code we check whether we create the window successfully or not. If not the we call out KillGLwindow method ( which we have define above ). Then we show a error Message and then return false.

Next Part of the function....

static PIXELFORMATDESCRIPTOR pfd=
{
sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor
1, // Version Number
PFD_DRAW_TO_WINDOW | // Format Must Support Window
PFD_SUPPORT_OPENGL | // Format Must Support OpenGL
PFD_DOUBLEBUFFER, // Must Support Double Buffering
PFD_TYPE_RGBA, // Request An RGBA Format
bits, // Select Our Color Depth
0, 0, 0, 0, 0, 0, // Color Bits Ignored
0, // No Alpha Buffer
0, // Shift Bit Ignored
0, // No Accumulation Buffer
0, 0, 0, 0, // Accumulation Bits Ignored
16, // 16Bit Z-Buffer (Depth Buffer)
0, // No Stencil Buffer
0, // No Auxiliary Buffer
PFD_MAIN_PLANE, // Main Drawing Layer
0, // Reserved
0, 0, 0 // Layer Masks Ignored
};

// this function is continue.... first we explain this part of function.

This part of code describes a Pixel Format. We choose a format that supports OpenGL and double buffering,RGBA (red, green, blue, alpha channel),Set Color Depth and set up a 16bit Z-Buffer other arguments are not important or not useful here.

Next Part of the Code...

if (!(hDC=GetDC(hWnd))) // getting Device Context
{
KillGLWindow();
MessageBox(NULL,"Can't Create A GL Device Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE;
}

if (!(PixelFormat=ChoosePixelFormat(hDC,&pfd))) //find a pixel format
{
KillGLWindow();
MessageBox(NULL,"Can't Find A Suitable PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE;
}

if(!SetPixelFormat(hDC,PixelFormat,&pfd)) //setting the pixel format
{
KillGLWindow();
MessageBox(NULL,"Can't Set The PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE;
}

if (!(hRC=wglCreateContext(hDC))) //get a Rendering Context.
{
KillGLWindow();
MessageBox(NULL,"Can't Create A GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE;
}

if(!wglMakeCurrent(hDC,hRC))
{
KillGLWindow();
MessageBox(NULL,"Can't Activate The GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE;
}

// this function is continue.... first we explain this part of function.

In this section of code we try to get Device Context,find a pixel format that matches the one we described above,setting the pixel format,get a Rendering Context.If we are succeed in all these things then we will make the Rendering Context active.

Next Part of the Code....

ShowWindow(hWnd,SW_SHOW);
SetForegroundWindow(hWnd);
SetFocus(hWnd);
ReSizeGLScene(width, height);

if (!InitGL())
{
KillGLWindow();
MessageBox(NULL,"Initialization Failed.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE;
}

return TRUE;
}

// end of the function

Now we will show the window, set it to be the foreground window (giving it more priority) and then set the focus to that window. Then we'll call ReSizeGLScene passing the screen width and height to set up our perspective OpenGL screen.

Now finally we will write Window Method which will deal with the message.

LRESULT CALLBACK WndProc( HWND hWnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
switch (uMsg)
{
case WM_ACTIVATE:
{
if (!HIWORD(wParam))
{
active=TRUE;
}
else
{
active=FALSE;
}

return 0;
}

case WM_SYSCOMMAND:
{
switch (wParam)
{
case SC_SCREENSAVE:
case SC_MONITORPOWER:
return 0;
}
break;
}

case WM_CLOSE:
{
PostQuitMessage(0);
return 0;
}

case WM_KEYDOWN:
{
keys[wParam] = TRUE;
return 0;
}

case WM_KEYUP:
{
keys[wParam] = FALSE;
return 0;
}

case WM_SIZE:
{
ReSizeGLScene(LOWORD(lParam),HIWORD(lParam));
return 0;
}
}

return DefWindowProc(hWnd,uMsg,wParam,lParam);
}

This Proc deals with the messages like, Is window active, Is keypressed,Is the windowsize changed by the user,Is the Window close.( Windows programmers already know this ).

Now we will describe the Main function From which our application start running.

int WINAPI WinMain( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
MSG msg;
BOOL done=FALSE;
if (MessageBox(NULL,"Would You Like To Run In Fullscreen Mode?", "Start FullScreen?",MB_YESNO|MB_ICONQUESTION)==IDNO)
{
fullscreen=FALSE;
}
if (!CreateGLWindow("Lesson 1",640,480,16,fullscreen))
{
return 0;
}

while(!done)
{
if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
{
if (msg.message==WM_QUIT)
{
done=TRUE;
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
else
{

if (active)
{
DrawGLScene();
SwapBuffers(hDC);
}
}
}
KillGLWindow();
return (msg.wParam);
}

In this Section of Code First we will show a message box so that user can choose whether he want windowed style or fullscreen.If it press 'No' , it will make the fullscreen flag to Flase. and call the CreateGLWindow method , which we have define above. Then we read Message By using PeekMessage().

Download the Source Code.

 

 

next: drawing shapes


metadata block
see also:
Correspondence about this page

This site may have errors. Don't use for critical systems.

Copyright (c) 1998-2023 Martin John Baker - All rights reserved - privacy policy.