/*
* This Code Was Created By Jeff Molofee 2000
* Modified by Shawn T. to handle (%3.2f, num)
parameters.
* A HUGE Thanks To Fredric Echols For Cleaning Up
* And Optimizing The Base Code, Making It More Flexible!
* If You've Found This Code Useful, Please Let Me Know.
* Visit My Site At nehe.gamedev.net
*/
#include
<windows.h>
// Header File For Windows
#include <cmath>
// Header File For Windows Math
Library
#include <iostream>
// Header File For Standard
Input/Output
#include <stdarg.h>
// Header File For Variable
Argument Routines
#include <gl\glut.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
using
namespace
std;
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
GLuint base;
// Base Display List For The
Font Set
GLfloat cnt1;
// 1st Counter Used To Move
Text & For Coloring
GLfloat cnt2;
// 2nd Counter Used To Move
Text & For Coloring
bool keys[256];
// Array Used For The Keyboard
Routine
bool
active=TRUE;
// Window Active Flag Set To
TRUE By Default
bool fullscreen=TRUE;
// Fullscreen Flag Set To
Fullscreen Mode By Default
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
// Declaration For WndProc
/*
The following section of code builds the actual font.
This was the most difficult part
of the code to write. 'HFONT font' in simple english
tells Windows we are going to be
manipulating a Windows font. oldfont is used for good
house keeping.
Next we define base. We do this by creating a group of
96 display lists using glGenLists(96).
After the display lists are created, the variable base
will hold the number of the first list.
*/
GLvoid BuildFont(GLvoid)
// Build Our Bitmap Font
{
HFONT font;
// Windows Font ID
HFONT oldfont;
// Used For Good House Keeping
base = glGenLists(96);
// Storage For 96 Characters
/* Now for the fun stuff. We're
going to create our font. We start off by specifying the
size of the font. You'll notice
it's a negative number. By putting a minus, we're
telling
windows to find us a font based
on the CHARACTER height. If we use a positive number we
match the font based on the
CELL height.
Then we specify the cell width.
You'll notice I have it set to 0. By setting values to
0,
windows will use the default
value. You can play around with this value if you want.
Make the font wide, etc. Angle
of Escapement will rotate the font. Unfortunately this
isn't a very useful feature.
Unless your at 0, 90, 180, and 270 degrees, the font
usually
gets cropped to fit inside it's
invisible square border. Orientation Angle quoted from
MSDN
help Specifies the angle, in
tenths of degrees, between each character's base line
and
the x-axis of the device.
Unfortunately I have no idea what that means :(
Font weight is a great
parameter. You can put a number from 0 - 1000 or you can
use one
of the predefined values.
FW_DONTCARE is 0, FW_NORMAL is 400, FW_BOLD is 700 and
FW_BLACK
is 900. There are alot more
predefined values, but those 4 give some good variety.
The higher the value,
the thicker the font (more bold).
Character set Identifier
describes the type of Character set you wish to use.
There are
too many types to
explain. CHINESEBIG5_CHARSET, GREEK_CHARSET,
RUSSIAN_CHARSET,
DEFAULT_CHARSET, etc.
ANSI is the one I use, although DEFAULT would probably
work just
as well.
If you're interested in
using a font such as Webdings or Wingdings, you need to
use
SYMBOL_CHARSET instead
of ANSI_CHARSET.
Output Precision is very
important. It tells Windows what type of character set
to use
if there is more than
one type available. OUT_TT_PRECIS tells Windows that if
there is
more than one type of
font to choose from with the same name, select the
TRUETYPE version
of the font. Truetype
fonts always look better, especially when you make them
large.
You can also use
OUT_TT_ONLY_PRECIS, which ALWAYS trys to use a TRUETYPE
Font.
Clipping Precision is
the type of clipping to do on the font if it goes
outside the clipping
region. Not much to say
about this, just leave it set to default.
Output Quality is very
important. You can have PROOF, DRAFT, NONANTIALIASED,
DEFAULT or
ANTIALIASED. We all know
that ANTIALIASED fonts look good :) Antialiasing a font
is the
same effect you get when
you turn on font smoothing in Windows. It makes
everything look
less jagged.
Next we have the Family
and Pitch settings. For pitch you can have DEFAULT_PITCH,
FIXED_PITCH
and VARIABLE_PITCH, and
for family you can have FF_DECORATIVE, FF_MODERN,
FF_ROMAN, FF_SCRIPT,
FF_SWISS, FF_DONTCARE.
Play around with them to find out what they do. I just
set them both
to default.
Finally... We have the
actual name of the font. Boot up Microsoft Word or some
other text
editor. Click on the
font drop down menu, and find a font you like. To use
the font,
replace 'Courier New'
with the name of the font you'd rather use. */
font = CreateFont( -24,
// Height Of Font
0,
// Width Of Font
0,
// Angle Of Escapement
0,
// Orientation Angle
FW_BOLD,
// Font Weight
FALSE,
// Italic
FALSE,
// Underline
FALSE,
// Strikeout
ANSI_CHARSET,
// Character Set Identifier
OUT_TT_PRECIS,
// Output Precision
CLIP_DEFAULT_PRECIS,
// Clipping Precision
ANTIALIASED_QUALITY,
// Output Quality
FF_DONTCARE|DEFAULT_PITCH,
// Family And Pitch
"Comic Sans MS");
// Font Name
/* oldFont stores the
previously used font. SelectObject will return the font
(or pen,
or filler, or whatever GDI
objects) that was previously set when it switches to the
new font.
The way that GDI works is such
that the use of the return value of SelectObject is not
very
apparent. At first glance it
looks as if the code is selecting the new font and
returning
a pointer and storing it within
oldFont. */
oldfont = (HFONT)SelectObject(hDC,
font);
// Selects the font we want
wglUseFontBitmaps(hDC, 32, 96, base);
// Builds 96 characters starting at character 32
SelectObject(hDC, oldfont);
// Selects the font we want
DeleteObject(font);
// Delete the font
}
// The following code is
pretty simple. It deletes the 96 display lists from
memory
// starting at the first
list specified by 'base'. I'm not sure if windows would
do this
// for you, but it's better to be safe than sorry :)
GLvoid
KillFont(GLvoid)
// Delete The Font List
{
glDeleteLists(base, 96);
// Delete All 96 Characters
}
// Now for my handy dandy GL
text routine. You call this section of code with the
// command
glPrint("message goes here"). The text is stored in the
char string *fmt.
// I don't understand
the ellipsis here?
GLvoid glPrint( const
char
*fmt, ...)
// Custom GL "Print" Routine
{
// The
first line below creates storage space for a 256
character string --
// the
string we will be printing to the screen.
// The
second line below creates a pointer that points to the
list of arguments
// we
pass along with the string. If we send any variables
along with the text,
//
this will point to them.
char
text[256];
// Holds Our String
va_list ap;
// Pointer To List Of Arguments
// The
next two lines of code check to see if there's anything
to display?
// If
there's no text, fmt will be NULL, and nothing will be
drawn to the screen.
if
(fmt == NULL)
// If There's No Text
return;
// Do Nothing
// The
following three lines of code convert any symbols in the
text to the actual
//
numbers the symbols represent. The final text and any
converted symbols are then
//
stored in the character string called "text". I'll
explain symbols in more detail
//
down below.
va_start(ap, fmt);
// Parses The String For
Variables
vsprintf(text, fmt, ap);
// And Converts Symbols To Actual Numbers
va_end(ap);
// Results Are Stored In Text
/* We then push the GL_LIST_BIT,
this prevents glListBase from affecting any other
display lists we may be using
in our program.
The command glListBase(base-32)
is a little hard to explain. Say we draw the letter
'A', it's represented by the
number 65. Without glListBase(base-32) OpenGL wouldn't
know where to find this letter.
It would look for it at display list 65, but if base
was equal to 1000, 'A' would
actually be stored at display list 1065. So by setting
a base starting point, OpenGL
knows where to get the proper display list from.
The reason we subtract 32 is
because we never made the first 32 display lists.
We skipped them. So we have to
let OpenGL know this by subtracting 32 from the
base value. I hope that makes
sense. */
glPushAttrib(GL_LIST_BIT);
// Pushes The Display List Bits
glListBase(base - 32);
// Sets The Base Character to
32
glCallLists(strlen(text), GL_UNSIGNED_BYTE, text);
// Draws The Display List Text
glPopAttrib();
// Pops The Display List Bits
}
/* Now that OpenGL knows
where the Letters are located, we can tell it to write
the
text to the screen.
glCallLists is a very interesting command. It's capable
of
putting more than one
display list on the screen at a time.
The line below does the
following. First it tells OpenGL we're going to be
displaying lists to the
screen. strlen(text) finds out how many letters we're
going
to send to the screen.
Next it needs to know what the largest list number were
sending
to it is going to be.
We're not sending any more than 255 characters. The
lists
parameter is treated as
an array of unsigned bytes, each in the range 0 through
255.
Finally we tell it what
to display by passing text (pointer to our string).
In case you're wondering
why the letters don't pile on top of eachother. Each
display
list for each character
knows where the right side of the letter is. After the
letter
is drawn, OpenGL
translates to the right side of the drawn letter. The
next letter
or object drawn will be
drawn starting at the last location GL translated to,
which
is to the right of the
last letter.
Finally we pop the
GL_LIST_BIT setting GL back to how it was before we set
our base
setting using
glListBase(base-32). */
GLvoid ReSizeGLScene(GLsizei
width, GLsizei height)
// Resize And Initialize The GL Window
{
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
}
// The only thing different
in the Init code is the line BuildFont(). This jumps to
the
// code above that
builds the font so OpenGL can use it later on.
int
InitGL(GLvoid)
// All Setup For OpenGL Goes
Here
{
glShadeModel(GL_SMOOTH);
// Enable Smooth Shading
glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
// 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
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
// Really Nice Perspective Calculations
BuildFont();
// Build The Font
return
TRUE;
// Initialization Went OK
}
/* Now for the drawing code.
We start off by clearing the screen and the depth
buffer.
We call glLoadIdentity() to reset everything. Then we
translate one unit into the screen.
If we don't translate, the text wont show up. Bitmap
fonts work better when you use an
ortho projection rather than a perspective projection,
but ortho looks bad, so to make
it work in projection, translate.
You'll notice that if you
translate even deeper into the screen the size of the
font
does not shrink like you'd expect it to. What actually
happens when you translate deeper
is that you have more control over where the text is on
the screen. If you translate
1 unit into the screen, you can place the text anywhere
from -0.5 to +0.5 on the X axis.
If you translate 10 units into the screen, you place the
text from -5 to +5. It just
gives you more control instead of using decimal places
to position the text at exact
locations. Nothing will change the size of the text. Not
even glScalef(x,y,z).
If you want the font bigger or smaller, make it bigger
or smaller when you create it! */
int
DrawGLScene(GLvoid)
// Here's Where We Do All The Drawing
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Clear Screen And Depth Buffer
glLoadIdentity();
// Reset The Current Modelview
Matrix
glTranslatef(0.0f,0.0f,-1.0f);
// Move One Unit Into The Screen
/* Now we use trig functions to
make the colors pulse. I like to take advantage of as
many variables and stupid
tricks as I can to achieve results :)
In this case I'm using the two
counters we made to move the text around the screen
to change the red, green and
blue colors. Red will go from -1.0 to 1.0 using COS and
counter 1. Green will also go
from -1.0 to 1.0 using SIN and counter 2. Blue will go
from 0.5 to 1.5 using COS and
counter 1 and 2. That way blue will never be 0, and
the text should never
completely fade out. Stupid, but it works :) */
//
Pulsing Colors Based On Text Position
glColor3f(1.0f*float(cos(cnt1)),1.0f*float(sin(cnt2)),1.0f-0.5f*float(cos(cnt1+cnt2)));
/* Now for a new command.
glRasterPos2f(x,y) will position the Bitmapped Font on
the
screen. The center of the
screen is still 0,0. Notice there's no Z position.
Bitmap
Fonts only use the X axis
(left/right) and Y axis (up/down). Because we translate
one unit into the screen, the
far left is -0.5, and the far right is +0.5. You'll
notice that I move 0.45 pixels
to the left on the X axis. This moves the text into
the center of the screen.
Otherwise it would be more to the right of the screen
because it would be drawn from
the center to the right.
The fancy(?) math does pretty
much the same thing as the color setting math does.
It moves the text on the x axis
from -0.50 to -0.40 (remember, we subtract 0.45
right off the start). This
keeps the text on the screen at all times. It swings
left and right using COS and
counter 1. It moves from -0.35 to +0.35 on the Y axis
using SIN and counter 2. */
//
Position The Text On The Screen
glRasterPos2f(-0.45f+0.05f*float(cos(cnt1)),
0.32f*float(sin(2.*cnt2)));
/* Now for my favorite part...
Writing the actual text to the screen. I tried to make
it super easy, and very user
friendly. You'll notice it looks alot like an OpenGL
call, combined with the good
old fashioned Print statement :) All you do to write
the text to the screen is
glPrint("{any text you want}"). It's that easy. The
text will be drawn onto the
screen at the exact spot you positioned it.
Shawn T. sent me
modified code that allows glPrint to pass variables to
the screen.
This means that you can
increase a counter and display the results on the
screen!
It works like this... In
the line below you see our normal text. Then there's a
space, a dash, a space,
then a "symbol" (%7.2f). Now you may look at %7.2f and
say
what the heck does that
mean. It's very simple. % is like a marker saying don't
print 7.2f to the
screen, because it represents a variable. The 7 means a
maximum of
7 digits will be
displayed to the left of the decimal place. Then the
decimal place,
and right after the
decimal place is a 2. The 2 means that only two digits
will be
displayed to the right
of the decimal place. Finally, the f. The f means that
the
number we want to
display is a floating point number. We want to display
the value
of cnt1 on the screen.
As an example, if cnt1 was equal to 300.12345f the
number we
would end up seeing on
the screen would be 300.12. The 3, 4, and 5 after the
decimal
place would be cut off
because we only want 2 digits to appear after the
decimal
place.
I know if you're an
experienced C programmer, this is absolute basic stuff,
but there
may be people out there
that have never used printf. If you're interested in
learning
more about symbols, buy
a book, or read through the MSDN. */
glPrint("COD Active Bitmap Text: counter is %7.2f", cnt1);
// Print GL Text To The Screen
// The
last thing to do is increase both the counters by
different amounts so the colors
//
pulse and the text moves.
cnt1+=0.051f;
// Increase The First Counter
cnt2+=0.005f;
// Increase The First Counter
return
TRUE;
// Everything Went OK
}
// The last thing to do is add KillFont() to the end of
KillGLWindow() just like I'm showing
// below. It's important to add
this line. It cleans things up before we exit our
program.
GLvoid KillGLWindow(GLvoid)
// Properly Kill The Window
{
if
(fullscreen)
// Are We In Fullscreen Mode?
{
ChangeDisplaySettings(NULL,0);
// If So Switch Back To The Desktop
ShowCursor(TRUE);
// Show Mouse Pointer
}
if
(hRC)
// Do We Have A Rendering
Context?
{
if
(!wglMakeCurrent(NULL,NULL))
// Are We Able To Release The DC And RC Contexts?
{
MessageBox(NULL,"Release Of DC And RC Failed.","SHUTDOWN
ERROR",MB_OK | MB_ICONINFORMATION);
}
if
(!wglDeleteContext(hRC))
// Are We 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))
// Are We 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))
// Are We Able To Unregister Class
{
MessageBox(NULL,"Could Not Unregister Class.","SHUTDOWN
ERROR",MB_OK | MB_ICONINFORMATION);
hInstance=NULL;
// Set hInstance To NULL
}
KillFont();
}
/* This Code Creates Our OpenGL
Window. Parameters Are: *
* title - Title To Appear At
The Top Of The Window *
* width - Width Of The GL
Window Or Fullscreen Mode *
* height - Height Of The GL
Window Or Fullscreen Mode *
* bits
- Number Of Bits To Use For Color (8/16/24/32) *
* fullscreenflag - Use Fullscreen Mode (TRUE) Or
Windowed Mode (FALSE) */
BOOL CreateGLWindow( char*
title, int
width, int
height, int
bits, bool
fullscreenflag)
{
GLuint PixelFormat;
// Holds The Results After
Searching For A Match
WNDCLASS wc;
// Windows Class Structure
DWORD dwExStyle;
// Window Extended Style
DWORD dwStyle;
// Window Style
RECT WindowRect;
// Grabs Rectangle Upper Left /
Lower Right Values
WindowRect.left=(long)0;
// Set Left Value To 0
WindowRect.right=(long)width;
// Set Right Value To Requested
Width
WindowRect.top=(long)0;
// Set Top Value To 0
WindowRect.bottom=(long)height;
// Set Bottom Value To
Requested Height
fullscreen=fullscreenflag;
// Set The Global Fullscreen
Flag
hInstance =
GetModuleHandle(NULL);
// Grab An Instance For Our Window
wc.style =
CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
// Redraw On Size, And Own DC For Window.
wc.lpfnWndProc = (WNDPROC) WndProc;
// WndProc Handles Messages
wc.cbClsExtra = 0;
// No Extra Window Data
wc.cbWndExtra = 0;
// No Extra Window Data
wc.hInstance = hInstance;
// Set The Instance
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
// Load The Default Icon
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
// Load The Arrow Pointer
wc.hbrBackground = NULL;
// No Background Required For GL
wc.lpszMenuName = NULL;
// We Don't Want A Menu
wc.lpszClassName = "OpenGL";
// Set The Class Name
if
(!RegisterClass(&wc))
// Attempt To Register The Window Class
{
MessageBox(NULL,"Failed To Register The Window Class.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return
FALSE;
// Return FALSE
}
if
(fullscreen)
// Attempt Fullscreen Mode?
{
DEVMODE dmScreenSettings;
// Device Mode
memset(&dmScreenSettings,0,sizeof(dmScreenSettings));
// Makes Sure Memory's Cleared
dmScreenSettings.dmSize=sizeof(dmScreenSettings);
// Size Of The Devmode
Structure
dmScreenSettings.dmPelsWidth = width;
// Selected Screen Width
dmScreenSettings.dmPelsHeight = height;
// Selected Screen Height
dmScreenSettings.dmBitsPerPel = bits;
// Selected Bits Per Pixel
dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
// Try
To Set Selected Mode And Get Results. NOTE:
CDS_FULLSCREEN Gets Rid Of Start Bar.
if
(ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)
{
// If
The Mode Fails, Offer Two Options. Quit Or Use Windowed
Mode.
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;
// Windowed Mode Selected.
Fullscreen = FALSE
}
else
{
// Pop
Up A Message Box Letting User Know The Program Is
Closing.
MessageBox(NULL,"Program Will Now Close.","ERROR",MB_OK|MB_ICONSTOP);
return
FALSE;
// Return FALSE
}
}
}
if
(fullscreen)
// Are We Still In Fullscreen Mode?
{
dwExStyle=WS_EX_APPWINDOW;
// Window Extended Style
dwStyle=WS_POPUP;
// Windows Style
ShowCursor(FALSE);
// Hide Mouse Pointer
}
else
{
dwExStyle=WS_EX_APPWINDOW |
WS_EX_WINDOWEDGE;
// Window Extended Style
dwStyle=WS_OVERLAPPEDWINDOW;
// Windows Style
}
AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);
// Adjust Window To True
Requested Size
//
Create The Window
if
(!(hWnd=CreateWindowEx( dwExStyle,
// Extended Style For The Window
"OpenGL",
// Class Name
title,
// Window Title
dwStyle |
// Defined Window Style
WS_CLIPSIBLINGS |
// Required Window Style
WS_CLIPCHILDREN,
// Required Window Style
0, 0,
// Window Position
WindowRect.right-WindowRect.left,
// Calculate Window Width
WindowRect.bottom-WindowRect.top,
// Calculate Window Height
NULL,
// No Parent Window
NULL,
// No Menu
hInstance,
// Instance
NULL)))
// Dont Pass Anything To
WM_CREATE
{
KillGLWindow();
// Reset The Display
MessageBox(NULL,"Window Creation Error.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return
FALSE;
// Return FALSE
}
static
PIXELFORMATDESCRIPTOR pfd=
// pfd Tells Windows How We Want Things To Be
{
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
};
if
(!(hDC=GetDC(hWnd)))
// Did We Get A Device Context?
{
KillGLWindow();
// Reset The Display
MessageBox(NULL,"Can't Create A GL Device
Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return
FALSE;
// Return FALSE
}
if
(!(PixelFormat=ChoosePixelFormat(hDC,&pfd)))
// Did Windows Find A Matching
Pixel Format?
{
KillGLWindow();
// Reset The Display
MessageBox(NULL,"Can't Find A Suitable PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return
FALSE;
// Return FALSE
}
if(!SetPixelFormat(hDC,PixelFormat,&pfd))
// Are We Able To Set The Pixel
Format?
{
KillGLWindow();
// Reset The Display
MessageBox(NULL,"Can't Set The PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return
FALSE;
// Return FALSE
}
if
(!(hRC=wglCreateContext(hDC)))
// Are We Able To Get A Rendering Context?
{
KillGLWindow();
// Reset The Display
MessageBox(NULL,"Can't Create A GL Rendering
Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return
FALSE;
// Return FALSE
}
if(!wglMakeCurrent(hDC,hRC))
// Try To Activate The
Rendering Context
{
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 Keyboard Focus To The
Window
ReSizeGLScene(width,
height);
// Set Up Our Perspective GL
Screen
if
(!InitGL())
// Initialize Our Newly Created GL Window
{
KillGLWindow();
// Reset The Display
MessageBox(NULL,"Initialization Failed.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return
FALSE;
// Return FALSE
}
return
TRUE;
// Success
}
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
{
case
SC_SCREENSAVE:
// Screensaver Trying To Start?
case
SC_MONITORPOWER:
// Monitor Trying To Enter Powersave?
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
{
ReSizeGLScene(LOWORD(lParam),HIWORD(lParam));
// LoWord=Width, HiWord=Height
return
0;
// Jump Back
}
}
//
Pass All Unhandled Messages To DefWindowProc
return
DefWindowProc(hWnd,uMsg,wParam,lParam);
}
//*********************************************************************//
// HERE COME DA MAIN
//*********************************************************************//
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("NeHe's Bitmap Font
Tutorial",640,480,16,fullscreen))
{
return
0;
// Quit If Window Was Not
Created
}
while(!done)
// Loop That Runs While
done=FALSE
{
if
(PeekMessage(&msg,NULL,0,0,PM_REMOVE))
// Is There A Message Waiting?
{
if
(msg.message==WM_QUIT)
// Have We Received A Quit Message?
{
done=TRUE;
// If So done=TRUE
}
else
// If Not, Deal With Window
Messages
{
TranslateMessage(&msg);
// Translate The Message
DispatchMessage(&msg);
// Dispatch The Message
}
}
else
// If There Are No Messages
{
//
Draw The Scene. Watch For ESC Key And Quit Messages From
DrawGLScene()
if
((active && !DrawGLScene()) || keys[VK_ESCAPE])
// Active? Was There A Quit
Received?
{
done=TRUE;
// ESC or DrawGLScene Signalled
A Quit
}
else
// Not Time To Quit, Update
Screen
{
SwapBuffers(hDC);
// Swap Buffers (Double
Buffering)
}
if
(keys[VK_F1])
// Is F1 Being Pressed?
{
keys[VK_F1]=FALSE;
// If So Make Key FALSE
KillGLWindow();
// Kill Our Current Window
fullscreen=!fullscreen;
// Toggle Fullscreen / Windowed Mode
//
Recreate Our OpenGL Window
if
(!CreateGLWindow("NeHe's Bitmap Font
Tutorial",640,480,16,fullscreen))
{
return
0;
// Quit If Window Was Not
Created
}
}
}
}
//
Shutdown
KillGLWindow();
// Kill The Window
return
(msg.wParam);
// Exit The Program
} |