Shadow Blade
Morrowland Presents Apron Tutorials
game - design - multimedia - web - programming - tutorials - There are currently viewers visiting Apron Tutorials.
   
 
TECHNICAL
GRAPHICAL
SOUND
GAME
WEB
ARTICLE
TOOL
PROJECT
 
 NEWS

  news

  history


 TECHNICAL TUTORIALS

  opengl

  direct3d

  c/c++

  visual basic

  java

  c#


 WEB TUTORIALS

  html

  dhtml

  asp

  php


 IMAGE EDITING

  photoshop

  draw sketch


 3D MODELING

  3d studio


 PROJECTS

  shadow blade

  game environment

  virtual 3d guide

  billy blue flame


 DEMOS

  win32 api


 ARTICLES

  general

  opengl


 COMMUNITY

  about us

  credit

  contact







OPENGL WINDOW TUTORIAL

In this tutorial you will learn how to create an empty OpenGL window, or at least see how it is done : ) I will use highlighted C++ syntax in this tutorial. If you are unfamiliar with C++, but familiar with an other programming language donít worry about that.. The OpenGL syntax, it is pretty much the same for all programming languages. Before we start I will mention a couple of more things.. First, you don't have to know how to create the window to be able to use the window.. So donít give up if you donít understand this fairly advanced code, you will find it a lot easier to understand the next tutorial.. You should however study the InitGL and DrawGLScene functions we will use them in the next tutorials. Most of this window code is originally created by Neon Helium, and is mostly the same code that you will find in NeHeís Lesson 5 for most programming languages. I use this window code because it is a nice piece of work, and also the most popular OpenGL window code to be found on the Internet. By using this window code, it may become easier for you to compare your own work with other OpenGL programming examples from different websites, it sure was for me..


1# Ok let's rock! In order for OpenGL to be compiled on your computer you must first include the necessary header and library files. If you don't have these files, then click this link.
Click to download OpenGL SDK!

In Microsoft Visual Studio you can include the needed lib files in Project->Settings menu under the Link tab. Or you can include them by code, as you can see below. I have already done this for you in the source code, but since this may be the first time you include a lib file Iíll tell you a little about it. Lib files are library files that can give us programming access to a dll file. For a programmer dll files can be much like a precompiled class with a lot of useful functions.. A lib file can be included like you see below by using a pragma call.

#pragma comment(lib, "opengl32.lib")
#pragma comment(lib, "glu32.lib")
#pragma comment(lib, "glaux.lib")

#include "windows.h"       // Header File For Windows
#include "gl\gl.h"         // Header File For The OpenGL32 Library
#include "gl\glu.h"        // Header File For The GLu32 Library
#include "gl\glaux.h"      // Header File For The Glaux Library

2# Next we need to declare some variables. Our window needs a window handle, a device context and an OpenGL rendering context. The OpenGL Rendering Context is defined as hRC. Every OpenGL program needs a Rendering Context. A Rendering Context is what links OpenGL calls to the Device Context. In order for your program to draw to the window you need to create a Device Context from the window handler. The Windows Device Context is defined as hDC. The DC connects the window to the GDI (Graphics Device Interface). The RC connects OpenGL to the DC. We also declare an array for our keyboard routine, a boolean called active (set to true if the application is running) and a fullscreen flag.

HDC	   hDC=NULL;   // Private GDI Device Context
HGLRC	   hRC=NULL;   // Permanent Rendering Context
HWND	   hWnd=NULL;  // Holds Our Window Handle
HINSTANCE   hInstance;  // Holds The Instance Of The Application

bool	keys[256];          // Array Used For The Keyboard Routine
bool	active=TRUE;        // Window Active Flag Set To TRUE By Default
bool	fullscreen=TRUE;    // Set To Fullscreen Mode By Default

3# The next thing we are going to declare is our window procedure function. This function handles all the messages that are being sent to our window. If we press a key or move the mouse we want our window to know how to respond to it..

LRESULT	CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);	// Declaration For WndProc

4# The ReSizeGLScene function is used to resize our OpenGL scene. This function also makes sure we donít ďdo a divide by zeroĒ and crash the application. To reset and define our new view port we first pass in our wanted scene width and height into the glViewport function. We then want to create a nice perspective roughly meaning that things get smaller in a distance.

glMatrixMode(GL_PROJECTION) indicates that the next lines of code will affect the projection matrix. The projection matrix is responsible for adding perspective to our scene. glLoadIdentity is similar to a reset, it restores the selected matrix to it's original state. After glLoadIdentity has been called we set up our perspective view for the scene with gluPerspective (read more in the OpenGL camera article).

glMatrixMode(GL_MODELVIEW) indicates that any new transformations will affect the model view matrix. The model view matrix is where our object information is stored. Last we reset the model view matrix. Don't worry if you don't understand this stuff.. Just know that it has to be done if you want the window view in perspective.

GLvoid ReSizeGLScene(GLsizei width, GLsizei height)
{
    if (height==0)			// Prevent A Divide By Zero By
    {
	height=1;			// Making Height Equal One
    }

    glViewport(0,0,width,height);	// Reset The Current Viewport

    glMatrixMode(GL_PROJECTION);	// Select The Projection Matrix
    glLoadIdentity();		// Reset The Projection Matrix

    // Calculate The Aspect Ratio Of The Window
    gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);

    glMatrixMode(GL_MODELVIEW);	// Select The Modelview Matrix
    glLoadIdentity();		// Reset The Modelview Matrix
}

5# Now this function we will use a lot! Here we will do all of the initialisation for our OpenGL applications. We set the color of the screen, we turn on the depth buffer (Z-Buffer), enable smooth shading, etc. This function will not be called until the OpenGL Window has been successfully created.

The next line enables smooth shading. Smooth shading blends colors nicely across a polygon, and smoothes out lighting.

The following line sets the color of the screen. The color values range from 0.0f to 1.0f. 0.0f being the darkest and 1. 0f being the brightest. This function uses RGBA values. The first parameter is the Red Intensity, the second parameter is for Green and the third is for Blue. The closer the value of the number is to 1.0f, the brighter that specific color will be. The last number is an Alpha value. When it comes to clearing the screen, we wonít worry about the 4th number. For now just leave it at zero. You create different colors by mixing the three primary colors for light (red, green, blue).

The next tree functions is for the depth buffer. Think of the depth buffer as layers into the screen. The depth buffer keeps track of how deep objects are into the screen. It keeps track of which object to draw first so that a square you drew behind a triangle doesn't end up if front of the triangle on the screen. The depth buffer is a very important part of OpenGL, and of 3D programming in general. We don't need the depth buffer in this application, but as you start to explore more advanced OpenGL tutorials, try to disable the depth buffer and see what happens..

So what else can you use the setup function for in the future?! If you want to render a 3D model you need to load the model before you can render it.. It would be appropriate to call your model loading function here, but for now we are only dealing with a blank window..

int InitGL(GLvoid)				// All Setup For OpenGL Goes Here
{
    glShadeModel(GL_SMOOTH);		// Enable Smooth Shading
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);	// Black Background
    glClearDepth(1.0f);			// Depth Buffer Setup
    glEnable(GL_DEPTH_TEST);		// Enables Depth Testing
    glDepthFunc(GL_LEQUAL);			// The Type Of Depth Testing To Do

    // Really Nice Perspective Calculations
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
    return TRUE;			 	// Initialization Went OK
}

6# Ahh! Finally the render function.. This is my favourite OpenGL function. In this function you can call all the models you want to display on the screen. Anything from simple polygons to advanced game characters.. It works like this: You should first clear the color and depth buffer, then you render your scene using double buffering. Double buffering is a technique used by graphic systems to support smooth rendering by drawing with two color buffers often called: the front color buffer and back color buffer. With double buffering, you render your scene to the (off-screen) back buffer. After the scene is finished rendering, you swap the back buffer with the front buffer. This buffer swapping process happens so fast that it is hidden from the user. The double buffering technique eliminates the flickering effects that usually arise when scenes are rendered directly to the screen. You should always clear the screen first. This way you will prevent the frames you paint to the screen from overlapping. If you donít like the idea of the two ďlayers swappingĒ, you can just imagine that youíre drawing directly to the screen, like I do ; ) Now you know how it works, and donít worry the window code will handle this process for you. Just think of it as a simple flip book..

int DrawGLScene(GLvoid)		// Here's Where We Do All The Drawing
{
    // Clear Screen And Depth Buffer
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    // Reset The Current Modelview Matrix
    glLoadIdentity();
	
    // Place your code here!

    return TRUE;			// Keep Going
}

7# The next section of code is called just before we exit the application. The purpose of KillGLWindow is to release the Rendering Context, the Device Context and finally the window handler. NeHe have added a lot of useful error checking to this function. If the program is unable to destroy any part of the Window, a message box will appear with a describing error message, making it a lot easier to find errors, and do manual debugging.

GLvoid KillGLWindow(GLvoid)			// Properly Kill The Window
{
    if (fullscreen)			// Are We In Fullscreen Mode?
    {
	ChangeDisplaySettings(NULL,0);	// witch Back To Desktop
	ShowCursor(TRUE);			// Show Mouse Pointer
	
    if (hRC)				// Do We Have A Rendering Context?
    {
	if (!wglMakeCurrent(NULL,NULL))	// Able To Release DC And RC?
	{
		MessageBox(NULL,"Release Of DC And RC Failed.",
		"SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
	}

	if (!wglDeleteContext(hRC))		// Able To Delete The RC?
	{
		MessageBox(NULL,"Release Rendering Context Failed.",
		"SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
	}
	hRC=NULL;				// Set RC To NULL
    }

    if (hDC && !ReleaseDC(hWnd,hDC))		// Are We Able To Release The DC
    {
	MessageBox(NULL,"Release Device Context Failed.",
	"SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
	hDC=NULL;				// Set DC To NULL
    }

    if (hWnd && !DestroyWindow(hWnd))	// Able To Destroy The Window?
    {
	MessageBox(NULL,"Could Not Release hWnd.",
	"SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
	hWnd=NULL;			// Set hWnd To NULL
    }

    if (!UnregisterClass("OpenGL",hInstance))// Able To Unregister Class?
    {
	MessageBox(NULL,"Could Not Unregister Class.",
	"SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
	hInstance=NULL;			// Set hInstance To NULL
    }
}

8# This LONG function creates an OpenGL Win32 window. In general it starts by setting up a Win32 window , moves on to ask if we want fullscreen and then inserts the values we want for our OpenGL window. A last if everything was successful it calls InitGL our setup function.

The first variable you see is PixelFormat. Later in the function we will ďaskĒ Windows to find us a pixel format that matches the one we want, the number of the mode that Windows ends up finding for us will be stored in the variable PixelFormat.

The WNDCLASS wc object will be used to hold our Window Class structure. The Window Class structure holds information about our window. By changing different fields in the Class we can change how the window looks and behaves. Every window you see has itís own Window Class. Before you create your window, you must register a class for the window.

dwExStyle and dwStyle will store the Extended and normal Window Style Information. We can use variables to store the styles so that we can change the styles depending on what type of window we need to create (A popup window for fullscreen or a window with a border for windowed mode)

The following five lines of code holds the values of the upper left, and lower right values of a rectangle. We can use these values to adjust the window size so that the area we draw is the exact resolution we want to have for our window. If we create a 640x480 window, the borders of the window will take up some of our resolution tough.

Now we move on to insert the value of our fullscreen flag. Before we start to define some of the properties of our new window by using our wc window class object. We pass in values like which mouse cursor, application icon and our message handler. After this we register our window class with RegisterClass..

The next section of the function is about switching to fullscreen mode. There are a few very important things you should keep in mind when switching to fullscreen mode. Make sure the width and height that you use in fullscreen mode is the same as the width and height you plan to use for your window, and most importantly, set fullscreen mode before you create your window. In this code, you don't have to worry about the width and height, the fullscreen and the window size are both set to be the same size requested.

The function also need to store the value of your screen before you switch to fullscreen mode.. This way you will get the same resolution to your screen when you exit the application as you had before.. Some annoying application forget to do this, they switch your screen resolution, but you have to go and change it back manually afterwards..

After we have set our wanted display mode we use AdjustWindowRectEx to pass in our rectangle values and CreateWindowEx to create our window with our wanted size and properties. If the function should fail to create the window correctly, it will move to destroy the window and exit the program.

Coming up next is the code that describes a Pixel Format. We choose a format that supports OpenGL and double buffering, along with RGBA (red, green, blue, alpha channel). We try to find a pixel format that matches the bits we decided on (16bit, 24bit, 32bit). Finally we set up a 16bit Z-Buffer. The remaining parameters are either not used or are not important (aside from the stencil buffer and the (slow) accumulation buffer). After our window is created itís proper to do some error checking to see that everything went as planned.

We check if we:
- can't get a device context.
- canít find a correct pixel format.
- canít set the pixel format.
- canít get the rendering context
- canít activate the rendering context

If everything went as planned, and our OpenGL Win32 window was created correctly we need to show the new window, set it to be the foreground window (giving it higher priority) and then set the focus on that window. Then we can call ReSizeGLScene passing it the screen width and height to set up our new OpenGL screen with perspective. FINALLY itís time to call our OpenGL setup function InitGL..

BOOL CreateGLWindow(char* title, int width, int height,
		    int bits, bool fullscreenflag)
{
    // First some standard Win32 window creating
    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 variable
    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";	

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

    // If fullscreen flag is set
    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;

	// Try To Set Selected Mode And Get Results.
	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?",
		"OPENGL",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);

    // Create The Window
    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();		// Reset The Display
	MessageBox(NULL,"Window Creation Error.",
	"ERROR",MB_OK|MB_ICONEXCLAMATION);
	return FALSE;			
    }

    // Tell the window how we want things to be..
    static	PIXELFORMATDESCRIPTOR pfd=
    {
	sizeof(PIXELFORMATDESCRIPTOR),
	1,			// Version Number
	PFD_DRAW_TO_WINDOW |	// Format Must Support Window
	PFD_SUPPORT_OPENGL |	// Format Must Support OpenGL
	PFD_DOUBLEBUFFER,		// 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	
    };

    // Did We Get A Device Context?
    if (!(hDC=GetDC(hWnd)))	
    {
	KillGLWindow();		// Reset The Display
	MessageBox(NULL,"Can't Create A GL Device Context.",
	"ERROR",MB_OK|MB_ICONEXCLAMATION);
	return FALSE;		// Return FALSE
    }

    // Did Windows Find A Matching Pixel Format?
    if (!(PixelFormat=ChoosePixelFormat(hDC,&pfd)))	
    {
	KillGLWindow();		// Reset The Display
	MessageBox(NULL,"Can't Find A Suitable PixelFormat.",
	"ERROR",MB_OK|MB_ICONEXCLAMATION);
	return FALSE;		// Return FALSE
    }
    // Are We Able To Set The Pixel Format?
    if(!SetPixelFormat(hDC,PixelFormat,&pfd))		
    {
	KillGLWindow();		// Reset The Display
	MessageBox(NULL,"Can't Set The PixelFormat.",
	"ERROR",MB_OK|MB_ICONEXCLAMATION);
	return FALSE;		// Return FALSE
    }

    // Are We Able To Get A Rendering Context?
    if (!(hRC=wglCreateContext(hDC)))
    {
	KillGLWindow();		// Reset The Display
	MessageBox(NULL,"Can't Create A GL Rendering Context.",
	"ERROR",MB_OK|MB_ICONEXCLAMATION);
	return FALSE;		// Return FALSE
    }

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

    ShowWindow(hWnd,SW_SHOW);	// Show The Window
    SetForegroundWindow(hWnd);	// Slightly Higher Priority
    SetFocus(hWnd);		// Sets Focus To The Window
    ReSizeGLScene(width, height);	// Set Up Our Perspective GL Screen

    // Initialize Our Newly Created GL Window
    if (!InitGL())
    {
	KillGLWindow();		// Reset The Display
	MessageBox(NULL,"Initialization Failed.",
	"ERROR",MB_OK|MB_ICONEXCLAMATION);
	return FALSE;		// Return FALSE
    }

    return TRUE;			// Success
}

9# This our windows message handler WndProc (window procedure). It handles all the messages for our window like mouse move, key pressed, application closed .etc. The code below is how we set up a standard message loop:

These commands are being called
WM_ACTIVATE // if the window is activated
WM_SYSCOMMAND // on system command interrupts
WM_CLOSE // on close window command
WM_KEYDOWN // if a key is pressed
WM_KEYUP // if a key is released
WM_SIZE // if window is resized

LRESULT CALLBACK WndProc(	HWND hWnd,	// Handle For This Window
			UINT	uMsg,	// Message For This Window
			WPARAM	wParam,  // Additional Message Information
			LPARAM	lParam)	// Additional Message Information
{
	switch (uMsg)			// Check For Windows Messages
	{
		case WM_ACTIVATE:	// Watch For Window Activate Message
		{
			if (!HIWORD(wParam))// Check Minimization State
	
				active=TRUE;// Program Is Active
			}
			else
			{
				active=FALSE;// Program Is No Longer Active
			}

			return 0;	// Return To The Message Loop
		}

		case WM_SYSCOMMAND:	// Intercept System Commands
		{
			switch (wParam)	// Check System Calls
			{
				// Screensaver Trying To Start?
				case SC_SCREENSAVE:	
				// Monitor Trying To Enter Powersave?
				case SC_MONITORPOWER:
				return 0;	// Prevent From Happening
			}
			break;			// Exit
		}

		case WM_CLOSE:	// Did We Receive A Close Message?
		{
			PostQuitMessage(0);// Send A Quit Message
			return 0;		// Jump Back
		}

		case WM_KEYDOWN:		// Is A Key Being Held Down?
		{
			keys[wParam] = TRUE;// If So, Mark It As TRUE
			return 0;		// Jump Back
		}

		case WM_KEYUP:		// Has A Key Been Released?
		{
			keys[wParam] = FALSE;// If So, Mark It As FALSE
			return 0;			// Jump Back
		}

		case WM_SIZE:		// Resize The OpenGL Window
		{
 			// LoWord=Width, HiWord=Height
			ReSizeGLScene(LOWORD(lParam),HIWORD(lParam)); 
			return 0;			// Jump Back
		}
	}

	// Pass All Unhandled Messages To DefWindowProc
	return DefWindowProc(hWnd,uMsg,wParam,lParam);
}

10# Last we will look at the function that is called first by standard Win32 application the WinMain. As you can see this function starts with a declaring two variables. The first variable msg is for the message loop. The second is a boolean to see if we want to exit the message loop. Then it calls a message box that asks which screen mode we prefer. It will then call our function CreateGLWindow with the wanted screen resolution and our fullscreen variable. After the window is created this function will go into a loop. This message loop will go on until the Esc or exit window button is pressed. If you study the function for a while you will see that by pressing F1 you can toggle between fullscreen and window mode.

int WINAPI WinMain( HINSTANCE hInstance,	// Instance
		  HINSTANCE hPrevInstance,	// Previous Instance
		  LPSTR lpCmdLine,		// Command Line Parameters
		  int nCmdShow)		// Window Show State
{
	MSG	msg;			// Windows Message Structure
	BOOL	done=FALSE;		// Bool Variable To Exit Loop

	// Ask The User Which Screen Mode They Prefer
	if (MessageBox(NULL,"Would You Like To Run In Fullscreen Mode?",
	"Start FullScreen?",MB_YESNO|MB_ICONQUESTION)==IDNO)
	{
		fullscreen=FALSE;	// Windowed Mode
	}

	// Create Our OpenGL Window
	if (!CreateGLWindow("APRON TUTORIALS",640,480,16,fullscreen))
	{
		return 0;		// Quit If Window Was Not Created
	}

	while(!done)		// Loop That Runs While done=FALSE
	{
		// Is There A Message Waiting?
		if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
		{
			// Have We Received A Quit Message?
			if (msg.message==WM_QUIT)
			{
				done=TRUE;// If So done=TRUE
			}
			else	// If Not, Deal With Window Messages
			{
				// Translate The Message
				TranslateMessage(&msg);
				// Dispatch The Message
				DispatchMessage(&msg);
			}
		}
		else			// If There Are No Messages
		{
			// Draw The Scene.
			// Active?  Was There A Quit Received?
			if ((active && !DrawGLScene()) || keys[VK_ESCAPE])
			{
				// ESC or DrawGLScene Signalled A Quit
				done=TRUE;
			}
			else		// Not Time To Quit, Update Screen
			{
				// Swap Buffers (Double Buffering)
				SwapBuffers(hDC);
			}

			if (keys[VK_F1])	// Is F1 Being Pressed?
			{
				keys[VK_F1]=FALSE;// If So Make Key FALSE
				KillGLWindow();	// Kill Our Current Window
				// Toggle Fullscreen / Windowed Mode
				fullscreen=!fullscreen;
				// Recreate Our OpenGL Window
				if (!CreateGLWindow("APRON TUTORIALS",
				640,480,16,fullscreen))
				{
					// Quit If Window Was Not Created
					return 0;
				}
			}
		}
	}

	// Shutdown
	KillGLWindow();		// Kill The Window
	return (msg.wParam);	// Exit The Program
}

Thatís it! You can breath now ; )You might think that Itís a lot of code for only one window.. But you will get used to it after some practise. Try downloading the source code and compile it. If you want you can also shorten the code by removing all the error checking, but I donít recommend it! Most OpenGL programmers don't create there own window at first, but I do recommend that you read through the code a couple of times. Feel free to use this window in future OpenGL applications. Learn how to use this one, and then move on the next and much easier tutorial..

Please mention me in your references!

THE END!

Regards
Ronny Andrť Reierstad


Download Source Code! Visual Studio C++ Source Code

Download Source Code! Visual Basic Source Code

Download Source Code! GLUT C++ Source Code

Download Source Code! Java LWJGL Source Code


Credits & References:
-------------------------------------------------------------
This tutorial is built on a Jeff Molofee (aka NeHe) Lesson5.
COPYRIGHT AND DISCLAIMER: (c)2000 Jeff Molofee
http://nehe.gamedev.net

And to Fredric Echols For Cleaning Up
Thank you for a great tutorial site!
-------------------------------------------------------------
  All rights reserved Morrowland © 2011  
Ronny Andrť Reierstad