技术文章 > NEHE OpenGL源代码(28)

NEHE OpenGL源代码(28)

2018-10-21 11:25

文档管理软件,文档管理系统,知识管理系统,档案管理系统的技术资料:
//---------------------------------------------------------------------------
#include <vcl.h>
#include <windows.h> // Header file for windows
#include <math.h> // Header file for math library routines
#include <stdio.h> // Header file for standard I/O routines
#include <stdlib.h> // Header file for standard library
#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
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma argsused
typedef struct point_3d // Structure for a 3-dimensional point ( NEW )
{
double x, y, z;
} POINT_3D;
typedef struct bpatch // Structure for a 3rd degree bezier patch ( NEW )
{
POINT_3D anchors[4][4]; // 4x4 grid of anchor points
GLuint dlBPatch; // Display list for bezier patch
GLuint texture; // Texture for the patch
} BEZIER_PATCH;
HGLRC hRC = NULL; // Permanent rendering context
HDC hDC = NULL; // Private GDI device context
HWND hWnd = NULL; // Holds our window handle
HINSTANCE hInstance = NULL; // Holds the instance of the application
DEVMODE DMsaved; // Saves the previous screen settings ( NEW )
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
GLfloat rotz = 0.0f; // Rotation about the Z axis
BEZIER_PATCH mybezier; // The bezier patch we“re going to use ( NEW )
BOOL showCPoints = true; // Toggles displaying the control point grid ( NEW )
int divs = 7; // Number of intrapolations (Controls poly resolution) ( NEW )
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // Declaration for WndProc
// Adds 2 points. Don“t just use “+“ ;)
POINT_3D pointAdd(POINT_3D p, POINT_3D q)
{
p.x += q.x; p.y += q.y; p.z += q.z;
return p;
}
// Multiplies a point and a constant. Don“t just use “*“
POINT_3D pointTimes(double c, POINT_3D p)
{
p.x *= c; p.y *= c; p.z *= c;
return p;
}
// Function for quick point creation
POINT_3D makePoint(double a, double b, double c)
{
POINT_3D p;
p.x = a; p.y = b; p.z = c;
return p;
}
// Calculates 3rd degree polynomial based on array of 4 points
// And a single variable (u) which is generally between 0 and 1
POINT_3D Bernstein(float u, POINT_3D *p)
{
POINT_3D a, b, c, d, r;
a = pointTimes(pow(u,3), p[0]);
b = pointTimes(3*pow(u,2)*(1-u), p[1]);
c = pointTimes(3*u*pow((1-u),2), p[2]);
d = pointTimes(pow((1-u),3), p[3]);
r = pointAdd(pointAdd(a, b), pointAdd(c, d));
return r;
}
// Generates a display list based on the data in the patch
// and the number of divisions
GLuint genBezier(BEZIER_PATCH patch, int divs)
{
int u = 0, v;
float py, px, pyold;
GLuint drawlist = glGenLists(1); // Make the display list
POINT_3D temp[4];
POINT_3D *last = (POINT_3D*)malloc(sizeof(POINT_3D)*(divs+1));
// Array of points to mark the first line of polys
if (patch.dlBPatch != NULL) // Get Rid Of Any Old Display Lists
glDeleteLists(patch.dlBPatch, 1);
temp[0] = patch.anchors[0][3]; // The first derived curve (Along X-axis)
temp[1] = patch.anchors[1][3];
temp[2] = patch.anchors[2][3];
temp[3] = patch.anchors[3][3];
for (v=0;v<=divs;v++) { // Create the first line of points
px = ((float)v)/((float)divs); // Percent slong Y-axis
// Use the 4 points from the derived curve to calculate the points along That Curve
last[v] = Bernstein(px, temp);
}
glNewList(drawlist, GL_COMPILE); // Start a new display list
glBindTexture(GL_TEXTURE_2D, patch.texture); // Bind the texture
for (u=1;u<=divs;u++) {
py = ((float)u)/((float)divs); // Percent along Y-axis
pyold = ((float)u-1.0f)/((float)divs); // Percent along old Y axis
temp[0] = Bernstein(py, patch.anchors[0]); // Calculate new bezier points
temp[1] = Bernstein(py, patch.anchors[1]);
temp[2] = Bernstein(py, patch.anchors[2]);
temp[3] = Bernstein(py, patch.anchors[3]);
glBegin(GL_TRIANGLE_STRIP); // Begin a new triangle strip
for (v=0;v<=divs;v++) {
px = ((float)v)/((float)divs); // Percent along the X-axis
glTexCoord2f(pyold, px); // Apply the old texture coords
glVertex3d(last[v].x, last[v].y, last[v].z); // Old point
last[v] = Bernstein(px, temp); // Generate new point
glTexCoord2f(py, px); // Apply the new texture coords
glVertex3d(last[v].x, last[v].y, last[v].z); // New point
}
glEnd(); // END the triangle strip
}
glEndList(); // END the list
free(last); // Free the old vertices array
return drawlist; // Return the display list
}
void initBezier(void)
{
mybezier.anchors[0][0] = makePoint(-0.75, -0.75, -0.50); // Set the bezier vertices
mybezier.anchors[0][1] = makePoint(-0.25, -0.75, 0.00);
mybezier.anchors[0][2] = makePoint( 0.25, -0.75, 0.00);
mybezier.anchors[0][3] = makePoint( 0.75, -0.75, -0.50);
mybezier.anchors[1][0] = makePoint(-0.75, -0.25, -0.75);
mybezier.anchors[1][1] = makePoint(-0.25, -0.25, 0.50);
mybezier.anchors[1][2] = makePoint( 0.25, -0.25, 0.50);
mybezier.anchors[1][3] = makePoint( 0.75, -0.25, -0.75);
mybezier.anchors[2][0] = makePoint(-0.75, 0.25, 0.00);
mybezier.anchors[2][1] = makePoint(-0.25, 0.25, -0.50);
mybezier.anchors[2][2] = makePoint( 0.25, 0.25, -0.50);
mybezier.anchors[2][3] = makePoint( 0.75, 0.25, 0.00);
mybezier.anchors[3][0] = makePoint(-0.75, 0.75, -0.50);
mybezier.anchors[3][1] = makePoint(-0.25, 0.75, -1.00);
mybezier.anchors[3][2] = makePoint( 0.25, 0.75, -1.00);
mybezier.anchors[3][3] = makePoint( 0.75, 0.75, -0.50);
mybezier.dlBPatch = NULL; // Go ahead and initialize this to NULL
}
// Load bitmaps and convert to textures
bool LoadGLTexture(GLuint *texPntr, char* name)
{
BOOL success = FALSE;
AUX_RGBImageRec *TextureImage = NULL;
glGenTextures(1, texPntr); // Generate 1 texture
FILE* test=NULL;
TextureImage = NULL;
test = fopen(name, “r“); // Test to see if the file exists
if (test != NULL) { // If it does
fclose(test); // Close the file
TextureImage = auxDIBImageLoad(name); // and load the texture
}
if (TextureImage != NULL) { // If it loaded
success = TRUE;
// Typical texture generation using data from the bitmap
glBindTexture(GL_TEXTURE_2D, *texPntr);
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage->sizeX, TextureImage->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage->data);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
}
if (TextureImage->data)
free(TextureImage->data);
return success;
}
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
}
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
initBezier(); // Initialize the bezier“s control grid ( NEW )
LoadGLTexture(&(mybezier.texture), “./Data/NeHe.bmp“); // Load the texture ( NEW )
mybezier.dlBPatch = genBezier(mybezier, divs); // Generate the patch ( NEW )
return true; // Initialization went OK
}
int DrawGLScene(GLvoid) // Here“s where we do all the drawing
{
int i, j;
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,-4.0f); // Move left 1.5 units and into the screen 6.0
glRotatef(-75.0f,1.0f,0.0f,0.0f);
glRotatef(rotz,0.0f,0.0f,1.0f); // Rotate the triangle on the Z-axis
glCallList(mybezier.dlBPatch); // Call the bezier“s display list
// This need only be updated when the patch changes
if (showCPoints) { // If drawing the grid is toggled on
glDisable(GL_TEXTURE_2D);
glColor3f(1.0f,0.0f,0.0f);
for(i=0;i<4;i++) { // Draw the horizontal lines
glBegin(GL_LINE_STRIP);
for(j=0;j<4;j++)
glVertex3d(mybezier.anchors[i][j].x, mybezier.anchors[i][j].y, mybezier.anchors[i][j].z);
glEnd();
}
for(i=0;i<4;i++) { // Draw the vertical lines
glBegin(GL_LINE_STRIP);
for(j=0;j<4;j++)
glVertex3d(mybezier.anchors[j][i].x, mybezier.anchors[j][i].y, mybezier.anchors[j][i].z);
glEnd();
}
glColor3f(1.0f,1.0f,1.0f);
glEnable(GL_TEXTURE_2D);
}
return true; // Everything went OK
}
GLvoid KillGLWindow(GLvoid) // Properly kill the window
{
if (fullscreen) // Are we in fullscreen mode?
{
if (!ChangeDisplaySettings(NULL,CDS_TEST)) { // If the shortcut doesn“t work ( NEW )
ChangeDisplaySettings(NULL,CDS_RESET); // Do it anyway (To get the values out of the registry) ( NEW )
ChangeDisplaySettings(&DMsaved,CDS_RESET); // Change it to the saved settings ( NEW )
} else {
ChangeDisplaySettings(NULL,CDS_RESET); // If it works, go right ahead ( NEW )
}
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
}
}
/* 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 rctangle 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
EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &DMsaved); // Save the current display state ( NEW )
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 (!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) // 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);
}
WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
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 OpenGL Framework“,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_LEFT]) rotz -= 0.8f; // Rotate left
if (keys[VK_RIGHT]) rotz += 0.8f; // Rotate right
if (keys[VK_UP]) { // Resolution up
divs++;
mybezier.dlBPatch = genBezier(mybezier, divs); // Update the patch
keys[VK_UP] = FALSE;
}
if (keys[VK_DOWN] && divs > 1) {
divs--;
mybezier.dlBPatch = genBezier(mybezier, divs); // Update the patch
keys[VK_DOWN] = FALSE;
}
if (keys[VK_SPACE]) { // SPACE toggles showCPoints
showCPoints = !showCPoints;
keys[VK_SPACE] = FALSE;
}
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(“David Nikdel & NeHe“s Bezier Tutorial“,640,480,16,fullscreen))
{
return 0; // Quit if window was not created
}
}
}
}
// Shutdown
KillGLWindow(); // Kill the window
return (msg.wParam); // Exit the program
}
//---------------------------------------------------------------------------