home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OpenGL Superbible
/
OpenGL_Superbible_Waite_Group_Press_1996.iso
/
book
/
chapt10
/
slstbolt
/
slstbolt.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-07-06
|
29KB
|
1,075 lines
// Slstbolt Spin the bolt with display lists.c
// Continously spins the bolt and reports the time
#include <windows.h> // Window defines
#include <gl\gl.h> // OpenGL
#include <gl\glu.h> // GLU library
#include <math.h> // Define for trig funcs.
#include <time.h>
#include <stdio.h>
#include "resource.h" // About box resource identifiers.
HPALETTE hPalette = NULL;
// Application name and instance storeage
static LPCTSTR lpszAppName = "Spinning Display List Bolt";
static HINSTANCE hInstance;
// Declaration for Window procedure
LRESULT CALLBACK WndProc( HWND hWnd,
UINT message,
WPARAM wParam,
LPARAM lParam);
// Dialog procedure for about box
BOOL APIENTRY AboutDlgProc (HWND hDlg, UINT message, UINT wParam, LONG lParam);
// Set Pixel Format function - forward declaration
void SetDCPixelFormat(HDC hDC);
#define HEAD_LIST 1
#define SHAFT_LIST 2
#define THREAD_LIST 3
#define BOLT_LIST 4
// Get and return the time as 1000 times the number of seconds passed
unsigned long ulGetProfileTime(void)
{
time_t now;
double seconds;
// Get the current time
now = clock();
// Convert to seconds
seconds = ((double)now /(double)CLOCKS_PER_SEC );
// Store in thousands of seconds and return
seconds *= 1000.0;
return (unsigned long) seconds;
}
// Reduces a normal vector specified as a set of three coordinates,
// to a unit normal vector of length one.
void ReduceToUnit(float vector[3])
{
float length;
// Calculate the length of the vector
length = (float)sqrt((vector[0]*vector[0]) +
(vector[1]*vector[1]) +
(vector[2]*vector[2]));
// Keep the program from blowing up by providing an exceptable
// value for vectors that may calculated too close to zero.
if(length == 0.0f)
length = 1.0f;
// Dividing each element by the length will result in a
// unit normal vector.
vector[0] /= length;
vector[1] /= length;
vector[2] /= length;
}
// Points p1, p2, & p3 specified in counter clock-wise order
void calcNormal(float v[3][3], float out[3])
{
float v1[3],v2[3];
static const int x = 0;
static const int y = 1;
static const int z = 2;
// Calculate two vectors from the three points
v1[x] = v[0][x] - v[1][x];
v1[y] = v[0][y] - v[1][y];
v1[z] = v[0][z] - v[1][z];
v2[x] = v[1][x] - v[2][x];
v2[y] = v[1][y] - v[2][y];
v2[z] = v[1][z] - v[2][z];
// Take the cross product of the two vectors to get
// the normal vector which will be stored in out
out[x] = v1[y]*v2[z] - v1[z]*v2[y];
out[y] = v1[z]*v2[x] - v1[x]*v2[z];
out[z] = v1[x]*v2[y] - v1[y]*v2[x];
// Normalize the vector (shorten length to one)
ReduceToUnit(out);
}
// Change viewing volume and viewport. Called when window is resized
void ChangeSize(GLsizei w, GLsizei h)
{
GLfloat nRange = 100.0f;
// Prevent a divide by zero
if(h == 0)
h = 1;
// Set Viewport to window dimensions
glViewport(0, 0, w, h);
// Reset coordinate system
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// Establish clipping volume (left, right, bottom, top, near, far)
if (w <= h)
glOrtho (-nRange, nRange, -nRange*h/w, nRange*h/w, -nRange*2.0f, nRange*2.0f);
else
glOrtho (-nRange*w/h, nRange*w/h, -nRange, nRange, -nRange*2.0f, nRange*2.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
// Creates the head of the bolt
void RenderHead(void)
{
float x,y,angle; // Calculated positions
float height = 25.0f; // Thickness of the head
float diameter = 30.0f; // Diameter of the head
float normal[3],corners[4][3]; // Storeage of vertices and normals
float step = (3.1415f/3.0f); // step = 1/6th of a circle = hexagon
// Set material color for head of screw
glColor3f(0.0f, 0.0f, 0.7f);
// clock-wise polygons face out, set for fans
glFrontFace(GL_CW);
// Begin a new triangle fan to cover the top
glBegin(GL_TRIANGLE_FAN);
// All the normals for the top of the bolt point straight up
// the z axis.
glNormal3f(0.0f, 0.0f, 1.0f);
// Center of fan is at the origin
glVertex3f(0.0f, 0.0f, 0.0f);
// Divide the circle up into 6 sections and start dropping
// points to specify the fan
for(angle = 0.0f; angle < (2.0f*3.1415f); angle += step)
{
// Calculate x and y position of the next vertex
x = diameter*(float)sin(angle);
y = diameter*(float)cos(angle);
// Specify the next vertex for the triangle fan
glVertex3f(x, y, 0.0f);
}
// Last vertex closes the fan
glVertex3f(0.0f, diameter, 0.0f);
// Done drawing the fan that covers the bottom
glEnd();
// Now draw the bottom of the bolt head. Now switch to
// clock-wise polygons faceing out.
glFrontFace(GL_CCW);
// Begin a new triangle fan to cover the bottom
glBegin(GL_TRIANGLE_FAN);
// Normal for bottom points straight down the negative z axis
glNormal3f(0.0f, 0.0f, -1.0f);
// Center of fan is at the origin
glVertex3f(0.0f, 0.0f, -height);
// Divide the circle up into 6 sections and start dropping
// points to specify the fan
for(angle = 0.0f; angle < (2.0f*3.1415f); angle += step)
{
// Calculate x and y position of the next vertex
x = diameter*(float)sin(angle);
y = diameter*(float)cos(angle);
// Specify the next vertex for the triangle fan
glVertex3f(x, y, -height);
}
// Last vertex, used to close the fan
glVertex3f(0.0f, diameter, -height);
// Done drawing the fan that covers the bottom
glEnd();
// Build the sides out of triangles (two each). Each face
// will consist of two triangles arranged to form a
// quadralateral
glBegin(GL_TRIANGLES);
// Go around and draw the sides
for(angle = 0.0f; angle < (2.0f*3.1415f); angle += step)
{
// Calculate x and y position of the next hex point
x = diameter*(float)sin(angle);
y = diameter*(float)cos(angle);
// start at bottom of head
corners[0][0] = x;
corners[0][1] = y;
corners[0][2] = -height;
// extrude to top of head
corners[1][0] = x;
corners[1][1] = y;
corners[1][2] = 0.0f;
// Calculate the next hex point
x = diameter*(float)sin(angle+step);
y = diameter*(float)cos(angle+step);
// Make sure we aren't done before proceeding
if(angle+step < 3.1415*2.0)
{
// If we are done, just close the fan at a
// known coordinate.
corners[2][0] = x;
corners[2][1] = y;
corners[2][2] = 0.0f;
corners[3][0] = x;
corners[3][1] = y;
corners[3][2] = -height;
}
else
{
// We aren't done, the points at the top and bottom
// of the head.
corners[2][0] = 0.0f;
corners[2][1] = diameter;
corners[2][2] = 0.0f;
corners[3][0] = 0.0f;
corners[3][1] = diameter;
corners[3][2] = -height;
}
// The normal vectors for the entire face will
// all point the same direction
calcNormal(corners, normal);
glNormal3fv(normal);
// Specify each triangle seperately to lie next
// to each other.
glVertex3fv(corners[0]);
glVertex3fv(corners[1]);
glVertex3fv(corners[2]);
glVertex3fv(corners[0]);
glVertex3fv(corners[2]);
glVertex3fv(corners[3]);
}
glEnd();
}
// Creates the shaft of the bolt as a cylinder with one end
// closed.
void RenderShaft(void)
{
float x,y,angle; // Used to calculate cylinder wall
float height = 75.0f; // Height of the cylinder
float diameter = 20.0f; // Diameter of the cylinder
float normal[3],corners[4][3]; // Storeage for vertices calculations
float step = (3.1415f/50.0f); // Approximate the cylinder wall with
// 100 flat segments.
// Set material color for head of screw
glColor3f(0.0f, 0.0f, 0.7f);
// counter clock-wise polygons face out (the default for triangles)
glFrontFace(GL_CCW);
// First assemble the wall as 100 quadrilaterals formed by
// placing adjoining triangles together
glBegin(GL_TRIANGLES);
// Go around and draw the sides
for(angle = 0.0f; angle < (2.0f*3.1415f); angle += step)
{
// Calculate x and y position of the next vertex
x = diameter*(float)sin(angle);
y = diameter*(float)cos(angle);
// Get the coordinate for this point and extrude the
// length of the cylinder.
corners[0][0] = x;
corners[0][1] = y;
corners[0][2] = -height;
corners[1][0] = x;
corners[1][1] = y;
corners[1][2] = 0.0f;
// Get the next point and do the same
x = diameter*(float)sin(angle+step);
y = diameter*(float)cos(angle+step);
// If finished, use know starting point to close the surface
if(angle+step < 3.1415*2.0) // Not Finished
{
corners[2][0] = x;
corners[2][1] = y;
corners[2][2] = 0.0f;
corners[3][0] = x;
corners[3][1] = y;
corners[3][2] = -height;
}
else
{
// Finished, use the staring point
corners[2][0] = 0.0f;
corners[2][1] = diameter;
corners[2][2] = 0.0f;
corners[3][0] = 0.0f;
corners[3][1] = diameter;
corners[3][2] = -height;
}
// Instead of using real normal to actual flat section
// Use what the normal would be if the surface was really
// curved. Since the cylinder goes up the Z axis, the normal
// points from the Z axis out directly through each vertex.
// Therefore we can use the vertex as the normal, as long as
// we reduce it to unit length first.
// First Triangle ////////////////////////////////////////
// Fill the normal vector with the coordinate points
normal[0] = corners[0][0];
normal[1] = corners[0][1];
normal[2] = corners[0][2];
// Reduce to length of one and specify for this point
ReduceToUnit(normal);
glNormal3fv(normal);
glVertex3fv(corners[0]);
// Get vertex, caluclate unit normal and go
normal[0] = corners[1][0];
normal[1] = corners[1][1];
normal[2] = corners[1][2];
ReduceToUnit(normal);
glNormal3fv(normal);
glVertex3fv(corners[1]);
// Get vertex, caluclate unit normal and go
normal[0] = corners[2][0];
normal[1] = corners[2][1];
normal[2] = corners[2][2];
ReduceToUnit(normal);
glNormal3fv(normal);
glVertex3fv(corners[2]);
// Second Triangle ////////////////////////////////////////
// Get vertex, caluclate unit normal and go
normal[0] = corners[2][0];
normal[1] = corners[2][1];
normal[2] = corners[2][2];
ReduceToUnit(normal);
glNormal3fv(normal);
glVertex3fv(corners[2]);
// Get vertex, caluclate unit normal and go
normal[0] = corners[3][0];
normal[1] = corners[3][1];
normal[2] = corners[3][2];
ReduceToUnit(normal);
glNormal3fv(normal);
glVertex3fv(corners[3]);
// Get vertex, caluclate unit normal and go
normal[0] = corners[0][0];
normal[1] = corners[0][1];
normal[2] = corners[0][2];
ReduceToUnit(normal);
glNormal3fv(normal);
glVertex3fv(corners[0]);
}
glEnd(); // Done with cylinder sides
// Begin a new triangle fan to cover the bottom
glBegin(GL_TRIANGLE_FAN);
// Normal points down the Z axis
glNormal3f(0.0f, 0.0f, -1.0f);
// Center of fan is at the origin
glVertex3f(0.0f, 0.0f, -height);
// Spin around matching step size of cylinder wall
for(angle = 0.0f; angle < (2.0f*3.1415f); angle += step)
{
// Calculate x and y position of the next vertex
x = diameter*(float)sin(angle);
y = diameter*(float)cos(angle);
// Specify the next vertex for the triangle fan
glVertex3f(x, y, -height);
}
// Close the fan
glVertex3f(0.0f, diameter, -height);
glEnd();
}
// Creates the head of the bolt
void RenderThread(void)
{
float x,y,z,angle; // Calculate coordinates and step angle
float height = 75.0f; // Height of the threading
float diameter = 20.0f; // Diameter of the threading
float normal[3],corners[4][3]; // Storeage for calculate normal and corners
float step = (3.1415f/32.0f); // one revolution
float revolutions = 7.0f; // How many time around the shaft
float threadWidth = 2.0f; // How wide is the thread
float threadThick = 3.0f; // How thick is the thread
float zstep = .125f; // How much does the thread move up
// the Z axis each time a new segment
// is drawn.
// 360 degrees in radians
#define PI2 (2.0f*3.1415f)
// Set material color for head of screw
glColor3f(0.0f, 0.0f, 0.4f);
z = -height+2; // Starting spot almost to the end
// Go around and draw the sides until finished spinning up
for(angle = 0.0f; angle < PI2*revolutions; angle += step)
{
// Calculate x and y position of the next vertex
x = diameter*(float)sin(angle);
y = diameter*(float)cos(angle);
// Store the next vertex next to the shaft
corners[0][0] = x;
corners[0][1] = y;
corners[0][2] = z;
// Calculate the position away from the shaft
x = (diameter+threadWidth)*(float)sin(angle);
y = (diameter+threadWidth)*(float)cos(angle);
corners[1][0] = x;
corners[1][1] = y;
corners[1][2] = z;
// Calculate the next position away from the shaft
x = (diameter+threadWidth)*(float)sin(angle+step);
y = (diameter+threadWidth)*(float)cos(angle+step);
corners[2][0] = x;
corners[2][1] = y;
corners[2][2] = z + zstep;
// Calculate the next position along the shaft
x = (diameter)*(float)sin(angle+step);
y = (diameter)*(float)cos(angle+step);
corners[3][0] = x;
corners[3][1] = y;
corners[3][2] = z+ zstep;
// We'll be using triangels, so make
// counter clock-wise polygons face out
glFrontFace(GL_CCW);
glBegin(GL_TRIANGLES); // Start the top section of thread
// Calculate the normal for this segment
calcNormal(corners, normal);
glNormal3fv(normal);
// Draw two triangles to cover area
glVertex3fv(corners[0]);
glVertex3fv(corners[1]);
glVertex3fv(corners[2]);
glVertex3fv(corners[2]);
glVertex3fv(corners[3]);
glVertex3fv(corners[0]);
glEnd();
// Move the edge along the shaft slightly up the z axis
// to represent the bottom of the thread
corners[0][2] += threadThick;
corners[3][2] += threadThick;
// Recalculate the normal since points have changed, this
// time it points in the opposite direction, so reverse it
calcNormal(corners, normal);
normal[0] = -normal[0];
normal[1] = -normal[1];
normal[2] = -normal[2];
// Switch to clock-wise facing out for underside of the
// thread.
glFrontFace(GL_CW);
// Draw the two triangles
glBegin(GL_TRIANGLES);
glNormal3fv(normal);
glVertex3fv(corners[0]);
glVertex3fv(corners[1]);
glVertex3fv(corners[2]);
glVertex3fv(corners[2]);
glVertex3fv(corners[3]);
glVertex3fv(corners[0]);
glEnd();
// Creep up the Z axis
z += zstep;
}
}
// This function does any needed initialization on the rendering
// context. Here it sets up and initializes the lighting for
// the scene.
void SetupRC()
{
// Light values and coordinates
GLfloat ambientLight[] = {0.4f, 0.4f, 0.4f, 1.0f };
GLfloat diffuseLight[] = {0.7f, 0.7f, 0.7f, 1.0f };
GLfloat specular[] = { 0.9f, 0.9f, 0.9f, 1.0f};
GLfloat lightPos[] = { -50.0f, 200.0f, 200.0f, 1.0f };
GLfloat specref[] = { 0.6f, 0.6f, 0.6f, 1.0f };
glEnable(GL_DEPTH_TEST); // Hidden surface removal
glEnable(GL_CULL_FACE); // Do not calculate inside of solid object
// Enable lighting
glEnable(GL_LIGHTING);
// Setup light 0
glLightModelfv(GL_LIGHT_MODEL_AMBIENT,ambientLight);
glLightfv(GL_LIGHT0,GL_AMBIENT,ambientLight);
glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuseLight);
glLightfv(GL_LIGHT0,GL_SPECULAR,specular);
// Position and turn on the light
glLightfv(GL_LIGHT0,GL_POSITION,lightPos);
glEnable(GL_LIGHT0);
// Enable color tracking
glEnable(GL_COLOR_MATERIAL);
// Set Material properties to follow glColor values
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
// All materials hereafter have full specular reflectivity
// with a moderate shine
glMaterialfv(GL_FRONT, GL_SPECULAR,specref);
glMateriali(GL_FRONT,GL_SHININESS,64);
// Black background
glClearColor(0.0f, 0.0f, 0.0f, 1.0f );
// Create display list for Bolt head
glNewList(HEAD_LIST,GL_COMPILE);
RenderHead();
glEndList();
// Create display list for shaft
glNewList(SHAFT_LIST,GL_COMPILE);
RenderShaft();
glEndList();
// Create display list for thread
glNewList(THREAD_LIST,GL_COMPILE);
RenderThread();
glEndList();
// Create nested display list for entire bolt
glNewList(BOLT_LIST,GL_COMPILE);
// Clear the window with current clearing color
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Make sure we have the correct matrix mode
glMatrixMode(GL_MODELVIEW);
// Rotate and translate the coordinate system
// Note this will be cumulative
glRotatef(5.0f, 0.0f, 1.0f, 0.0f);
// Translate and render the head
glTranslatef(0.0f, 0.0f, 55.0f);
glCallList(HEAD_LIST);
// Translate back some and render the shaft and thread together
glTranslatef(0.0f, 0.0f, -15.0f);
glCallList(SHAFT_LIST);
glCallList(THREAD_LIST);
// Translate back again for next pass
glTranslatef(0.0f, 0.0f, -40.0f);
// End Bolt list
glEndList();
}
// Called to draw the entire bolt
void RenderScene(void)
{
glCallList(BOLT_LIST);
// Flush drawing commands
glFlush();
}
// Select the pixel format for a given device context
void SetDCPixelFormat(HDC hDC)
{
int nPixelFormat;
static PIXELFORMATDESCRIPTOR pfd = {
sizeof(PIXELFORMATDESCRIPTOR), // Size of this structure
1, // Version of this structure
PFD_DRAW_TO_WINDOW | // Draw to Window (not to bitmap)
PFD_SUPPORT_OPENGL | // Support OpenGL calls in window
PFD_DOUBLEBUFFER, // Double buffered
PFD_TYPE_RGBA, // RGBA Color mode
24, // Want 24bit color
0,0,0,0,0,0, // Not used to select mode
0,0, // Not used to select mode
0,0,0,0,0, // Not used to select mode
16, // Size of depth buffer
0, // Not used to select mode
0, // Not used to select mode
PFD_MAIN_PLANE, // Draw in main plane
0, // Not used to select mode
0,0,0 }; // Not used to select mode
// Choose a pixel format that best matches that described in pfd
nPixelFormat = ChoosePixelFormat(hDC, &pfd);
// Set the pixel format for the device context
SetPixelFormat(hDC, nPixelFormat, &pfd);
}
// If necessary, creates a 3-3-2 palette for the device context listed.
HPALETTE GetOpenGLPalette(HDC hDC)
{
HPALETTE hRetPal = NULL; // Handle to palette to be created
PIXELFORMATDESCRIPTOR pfd; // Pixel Format Descriptor
LOGPALETTE *pPal; // Pointer to memory for logical palette
int nPixelFormat; // Pixel format index
int nColors; // Number of entries in palette
int i; // Counting variable
BYTE RedRange,GreenRange,BlueRange;
// Range for each color entry (7,7,and 3)
// Get the pixel format index and retrieve the pixel format description
nPixelFormat = GetPixelFormat(hDC);
DescribePixelFormat(hDC, nPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
// Does this pixel format require a palette? If not, do not create a
// palette and just return NULL
if(!(pfd.dwFlags & PFD_NEED_PALETTE))
return NULL;
// Number of entries in palette. 8 bits yeilds 256 entries
nColors = 1 << pfd.cColorBits;
// Allocate space for a logical palette structure plus all the palette entries
pPal = (LOGPALETTE*)malloc(sizeof(LOGPALETTE) +nColors*sizeof(PALETTEENTRY));
// Fill in palette header
pPal->palVersion = 0x300; // Windows 3.0
pPal->palNumEntries = nColors; // table size
// Build mask of all 1's. This creates a number represented by having
// the low order x bits set, where x = pfd.cRedBits, pfd.cGreenBits, and
// pfd.cBlueBits.
RedRange = (1 << pfd.cRedBits) -1;
GreenRange = (1 << pfd.cGreenBits) - 1;
BlueRange = (1 << pfd.cBlueBits) -1;
// Loop through all the palette entries
for(i = 0; i < nColors; i++)
{
// Fill in the 8-bit equivalents for each component
pPal->palPalEntry[i].peRed = (i >> pfd.cRedShift) & RedRange;
pPal->palPalEntry[i].peRed = (unsigned char)(
(double) pPal->palPalEntry[i].peRed * 255.0 / RedRange);
pPal->palPalEntry[i].peGreen = (i >> pfd.cGreenShift) & GreenRange;
pPal->palPalEntry[i].peGreen = (unsigned char)(
(double)pPal->palPalEntry[i].peGreen * 255.0 / GreenRange);
pPal->palPalEntry[i].peBlue = (i >> pfd.cBlueShift) & BlueRange;
pPal->palPalEntry[i].peBlue = (unsigned char)(
(double)pPal->palPalEntry[i].peBlue * 255.0 / BlueRange);
pPal->palPalEntry[i].peFlags = (unsigned char) NULL;
}
// Create the palette
hRetPal = CreatePalette(pPal);
// Go ahead and select and realize the palette for this device context
SelectPalette(hDC,hRetPal,FALSE);
RealizePalette(hDC);
// Free the memory used for the logical palette structure
free(pPal);
// Return the handle to the new palette
return hRetPal;
}
// Entry point of all Windows programs
int APIENTRY WinMain( HINSTANCE hInst,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
MSG msg; // Windows message structure
WNDCLASS wc; // Windows class structure
HWND hWnd; // Storeage for window handle
hInstance = hInst;
// Register Window style
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC) WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
// No need for background brush for OpenGL window
wc.hbrBackground = NULL;
wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU);
wc.lpszClassName = lpszAppName;
// Register the window class
if(RegisterClass(&wc) == 0)
return FALSE;
// Create the main application window
hWnd = CreateWindow(
lpszAppName,
lpszAppName,
// OpenGL requires WS_CLIPCHILDREN and WS_CLIPSIBLINGS
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
// Window position and size
50, 50,
400, 400,
NULL,
NULL,
hInstance,
NULL);
// If window was not created, quit
if(hWnd == NULL)
return FALSE;
// Display the window
ShowWindow(hWnd,SW_SHOW);
UpdateWindow(hWnd);
// Process application messages until the application closes
while( GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
// Window procedure, handles all messages for this program
LRESULT CALLBACK WndProc( HWND hWnd,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
static HGLRC hRC; // Permenant Rendering context
static HDC hDC; // Private GDI Device context
// Storeage for timing values
static unsigned long ulStart = 0L;
static unsigned long ulFinish = 0L;
static double dTime = 0.0;
// Storage for performance statistics
char cBuffer[80];
RECT cRect;
switch (message)
{
// Window creation, setup for OpenGL
case WM_CREATE:
// Store the device context
hDC = GetDC(hWnd);
// Select the pixel format
SetDCPixelFormat(hDC);
hPalette = GetOpenGLPalette(hDC);
// Create the rendering context and make it current
hRC = wglCreateContext(hDC);
wglMakeCurrent(hDC, hRC);
SetupRC();
break;
// Window is being destroyed, cleanup
case WM_DESTROY:
// Deselect the current rendering context and delete it
wglMakeCurrent(hDC,NULL);
wglDeleteContext(hRC);
if(hPalette != NULL)
DeleteObject(hPalette);
// Tell the application to terminate after the window
// is gone.
PostQuitMessage(0);
break;
// Window is resized.
case WM_SIZE:
// Call our function which modifies the clipping
// volume and viewport
ChangeSize(LOWORD(lParam), HIWORD(lParam));
break;
// The painting function. This message sent by Windows
// whenever the screen needs updating.
case WM_PAINT:
{
// Count how many times rendered
static iRenderCount = 0;
// Get time at beginning of spin
if(iRenderCount == 0)
ulStart = ulGetProfileTime();
// Call OpenGL drawing code
RenderScene();
// Bring image to front
SwapBuffers(hDC);
// Increment count. If 71 or over get the finish time,
iRenderCount++;
if(iRenderCount > 71)
{
iRenderCount = 0;
ulFinish = ulGetProfileTime();
// Calculate the time in seconds
dTime = ulFinish - ulStart;
dTime /= 1000.0;
}
// Display time (be sure and set background colors)
sprintf(cBuffer,"%3.1f Seconds for 360 degrees.",dTime);
GetClientRect(hWnd,&cRect);
SetBkColor(hDC,RGB(0,0,255));
SetTextColor(hDC,RGB(255,255,0));
TextOut(hDC,0,cRect.bottom-20,cBuffer,strlen(cBuffer));
// Do not validate, forcing a continuous repaint
}
break;
// Windows is telling the application that it may modify
// the system palette. This message in essance asks the
// application for a new palette.
case WM_QUERYNEWPALETTE:
// If the palette was created.
if(hPalette)
{
int nRet;
// Selects the palette into the current device context
SelectPalette(hDC, hPalette, FALSE);
// Map entries from the currently selected palette to
// the system palette. The return value is the number
// of palette entries modified.
nRet = RealizePalette(hDC);
// Repaint, forces remap of palette in current window
InvalidateRect(hWnd,NULL,FALSE);
return nRet;
}
break;
// This window may set the palette, even though it is not the
// currently active window.
case WM_PALETTECHANGED:
// Don't do anything if the palette does not exist, or if
// this is the window that changed the palette.
if((hPalette != NULL) && ((HWND)wParam != hWnd))
{
// Select the palette into the device context
SelectPalette(hDC,hPalette,FALSE);
// Map entries to system palette
RealizePalette(hDC);
// Remap the current colors to the newly realized palette
UpdateColors(hDC);
return 0;
}
break;
// A menu command
case WM_COMMAND:
{
switch(LOWORD(wParam))
{
// Exit the program
case ID_FILE_EXIT:
DestroyWindow(hWnd);
break;
// Display the about box
case ID_HELP_ABOUT:
DialogBox (hInstance,
MAKEINTRESOURCE(IDD_DIALOG_ABOUT),
hWnd,
AboutDlgProc);
break;
}
}
break;
default: // Passes it on if unproccessed
return (DefWindowProc(hWnd, message, wParam, lParam));
}
return (0L);
}
// Dialog procedure.
BOOL APIENTRY AboutDlgProc (HWND hDlg, UINT message, UINT wParam, LONG lParam)
{
switch (message)
{
// Initialize the dialog box
case WM_INITDIALOG:
{
int i;
GLenum glError;
// glGetString demo
SetDlgItemText(hDlg,IDC_OPENGL_VENDOR,glGetString(GL_VENDOR));
SetDlgItemText(hDlg,IDC_OPENGL_RENDERER,glGetString(GL_RENDERER));
SetDlgItemText(hDlg,IDC_OPENGL_VERSION,glGetString(GL_VERSION));
SetDlgItemText(hDlg,IDC_OPENGL_EXTENSIONS,glGetString(GL_EXTENSIONS));
// gluGetString demo
SetDlgItemText(hDlg,IDC_GLU_VERSION,gluGetString(GLU_VERSION));
SetDlgItemText(hDlg,IDC_GLU_EXTENSIONS,gluGetString(GLU_EXTENSIONS));
// Display any recent error messages
i = 0;
do {
glError = glGetError();
SetDlgItemText(hDlg,IDC_ERROR1+i,gluErrorString(glError));
i++;
}
while(i < 6 && glError != GL_NO_ERROR);
return (TRUE);
}
break;
// Process command messages
case WM_COMMAND:
{
// Validate and Make the changes
if(LOWORD(wParam) == IDOK)
EndDialog(hDlg,TRUE);
}
break;
// Closed from sysbox
case WM_CLOSE:
EndDialog(hDlg,TRUE);
break;
}
return FALSE;
}