OPENGL4_变换
阅读原文时间:2023年07月15日阅读:2

几种变换的几何意义说明

http://blog.csdn.net/onafioo/article/details/22094247

变换的执行顺序问题

1 视图(观察)变换

2 模型变换

3 投影变换

4 视口变换

glViewport(GLint x,GLint y,GLsizei width,GLsizei height)

设置视口

glMatrixMode (GLenum mode)

指定哪一个矩阵堆栈是下一个矩阵操作的目标

可选值

GL_MODELVIEW,对模型视景矩阵堆栈应用随后的矩阵操作.

GL_PROJECTION,对投影矩阵应用随后的矩阵操作.

GL_TEXTURE,对纹理矩阵堆栈应用随后的矩阵操作.

glLoadIdentity();

清空glMatrixMode 指定的类型的矩阵(变成单位矩阵),相当于复位

gluPerspective(GLdouble fovy,GLdouble aspect,GLdouble zNear,GLdouble zFar)

设置视景体,在glMatrixMode(GL_PROJECTION)下使用

fovy:视角

aspect:屏幕纵宽比

zNear:近裁剪面z值

zFar:远裁剪面z值

gluLookAt(GLdoble eyex,GLdouble eyey,GLdouble eyez,GLdouble centerx,GLdouble centery,GLdouble centerz,GLdouble upx,GLdouble upy,GLdouble upz);

设置摄像机朝向

9个参数分别代表,摄像机位置xyz,摄像机看向的目标位置xyz,摄像机朝向xyz(摄像机和这个向量的关系类似人眼和人站立的方向),一般设置为(0,1,0),代表人正常站立,眼睛朝前看

glTranslatef (GLfloat x, GLfloat y, GLfloat z);

平移

glScalef (GLfloat x, GLfloat y, GLfloat z);

缩放

glRotatef (GLfloat angle, GLfloat x, GLfloat y, GLfloat z)

angle:旋转角度

xyz:旋转轴

//视口变换

glViewport(0,0,width,height);

//投影变换

glMatrixMode(GL_PROJECTION);

glLoadIdentity();

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

//模型视图变换

glMatrixMode(GL_MODELVIEW);

glLoadIdentity();

//摄像机位置,观察点,摄像机方位

gluLookAt();

后面跟模型变换的平移,旋转,缩放

Opengl让矩阵和顶点做左乘操作

例如C*B*A*v,实际是先乘A矩阵,然后B,然后C,所以变换顺序上,代码出现的顺序是反序。

所以下面代码意思为,先缩放,在旋转,然后再移动(下面代码在执行前已经)

glLoadIdentity();//清空模型观察矩阵(之前已经执行了glMatrixMode(GL_MODELVIEW)切换到了模型观察矩阵,并且已经对矩阵做过平移旋转等操作,所以要清空)

glTranslatef(8.0f,0.0f,-18.9f);//移动
glRotatef(rotateAngle,0.0f,1.0f,0.0f);//旋转
glScalef(1.5f,1.5f,1.5f);//缩放

glBegin(GL_TRIANGLES);
glColor3f(1.0f,0.0f,1.0f);// 设置当前色为紫色
glVertex3f( 0.0f, 1.0f, 0.0f);//对象绕自身的轴旋转,必须让对象的中心坐标总是(0.0f,0,0f,0,0f)
glVertex3f(-1.0f,-1.0f, 0.0f);
glVertex3f( 1.0f,-1.0f, 0.0f);
rotateAngle+=0.1;
glEnd();

完整代码及效果

#include "stdafx.h"
#include "Nehe_Base.h"

#include "GL.H" // Header File For The OpenGL32 Library
#include "GLU.H" // Header File For The GLu32 Library
#include "GLAUX.H" // Header File For The Glaux Library

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; // Fullscreen Flag Set To Fullscreen Mode By Default

GLfloat rotateAngle;

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

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);  
glLoadIdentity();  
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
return TRUE; // Initialization Went OK
}

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

gluLookAt(0.0f,0.0f,10.0f,0.0f,0.0f,0.0f,0.0f,1.0f,0.0f);  
//移动是相对当前位置移动(第一次移动相对与屏幕中心0,0,0下一次再移动时相对的就是本次移动后的位置了)  
//向屏幕内移动18.9个单位,这样1个单位(1米)对应480/(2\*tan(22.5)\*(18.9+0.1)= 30像素  
glTranslatef(0.0f,0.0f,-18.9f);

// 绘制不连续线段,把屏幕分成9部分  
glBegin(GL\_LINES);  
glColor3f(1.0f,1.0f,1.0f);// 设置当前色为红色  
// 横线  
glVertex3f( -21.0f, 3.0f, 0.0f);  
glVertex3f(21.0f, 3.0f, 0.0f);  
glVertex3f( -21.0f, -3.0f, 0.0f);  
glVertex3f( 21.0f, -3.0f, 0.0f);  
// 竖线  
glVertex3f( -3.0f, 8.0f, 0.0f);  
glVertex3f(-3.0f, -8.0f, 0.0f);  
glVertex3f( 3.0f, 8.0f, 0.0f);  
glVertex3f( 3.0f, -8.0f, 0.0f);  
glEnd();

// 绘制点  
glBegin(GL\_POINTS);  
glColor3f(1.0f,0.0f,0.0f);// 设置当前色为红色  
glVertex3f( -8.0f, 5.5f, 0.0f);  
glVertex3f( -7.5f, 5.5f, 0.0f);  
glVertex3f( -7.0f, 5.5f, 0.0f);  
glEnd();

// 绘制不闭合折线  
glBegin(GL\_LINE\_STRIP);  
glColor3f(1.0f,1.0f,0.0f);// 设置当前色为黄色  
glVertex3f( -2.0f, 5.5f, 0.0f);  
glVertex3f( 2.0f, 5.5f, 0.0f);  
glVertex3f( -2.0f, 4.0f, 0.0f);  
glVertex3f( 2.0f, 4.0f, 0.0f);  
glEnd();

// 绘制闭合折线  
glBegin(GL\_LINE\_LOOP);  
glColor3f(0.0f,0.0f,1.0f);// 设置当前色为蓝色  
glVertex3f( 6.0f, 6.0f, 0.0f);  
glVertex3f( 4.0f, 4.0f, 0.0f);  
glVertex3f( 8.0f, 4.0f, 0.0f);  
glEnd();

// 绘制多组独立填充三角形(以下绘制2个三角形)  
glBegin(GL\_TRIANGLES);  
glColor3f(1.0f,0.0f,0.0f);// 设置当前色为红色  
glVertex3f( -9.0f, 1.0f, 0.0f);  
glVertex3f(-8.0f,-1.0f, 0.0f);  
glVertex3f( -10.0f,-1.0f, 0.0f);

glVertex3f( -6.0f, 1.0f, 0.0f);  
glVertex3f(-5.0f,-1.0f, 0.0f);  
glVertex3f( -7.0f,-1.0f, 0.0f);  
glEnd();

// 绘制三角形带  
glBegin(GL\_TRIANGLE\_STRIP);//(以下绘制3个连续三角形)  
//第一个三角形由点123逆时针构成  
//第二个三角形由点324逆时针构成  
//第三个三角形由点345逆时针构成  
glColor3f(1.0f,0.0f,0.0f);// 设置当前色为红色  
glVertex3f( -2.0f,-1.0f, 0.0f);//点1  
glVertex3f(0.0f,-1.0f, 0.0f);//点2  
glVertex3f( -1.0f, 1.0f, 0.0f);//点3  
glColor3f(0.0f,1.0f,0.0f);// 设置当前色为绿色  
glVertex3f( 1.0f,1.0f, 0.0f);//点4  
glColor3f(0.0f,0.0f,1.0f);// 设置当前色为蓝色  
glVertex3f(2.5f,2.5f, 0.0f);//点5  
glEnd();

//旋转  
//glLoadIdentity();  
glTranslatef(0.0f,0.0f,18.9f);  
glTranslatef(8.0f,0.0f,-18.9f);  
glRotatef(rotateAngle,0.0f,1.0f,0.0f);  
//glScalef(1.5f,1.5f,1.5f);  
glBegin(GL\_TRIANGLES);  
glColor3f(1.0f,0.0f,1.0f);// 设置当前色为紫色  
glVertex3f( 0.0f, 1.0f, 0.0f);  
glVertex3f(-1.0f,-1.0f, 0.0f);  
glVertex3f( 1.0f,-1.0f, 0.0f);  
rotateAngle+=0.1;  
glEnd();

return TRUE;                                        // Everything Went OK  

}

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  
}  

}

/* 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)
{
//当我们要求Windows为我们寻找相匹配的象素格式时,Windows寻找结束后将模式值保存在变量PixelFormat中。
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  
}

//像素格式明确了OpenGL绘制平面的特性,如象素缓冲区是单缓冲还是双缓冲,数据是 RGBA方式还是Color Index方式等。  
//每个OpenGL显示设备一般用名为PIXELFORMATDESCRIPTOR的结构来表示某个的像素格式  
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);  

}

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 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)                             // Program Active?  
        {  
            if (keys\[VK\_ESCAPE\])             // Was ESC Pressed?  
            {  
                done=TRUE;                      // ESC Signalled A Quit  
            }  
            else                                // Not Time To Quit, Update Screen  
            {  
                DrawGLScene();                  // Draw The Scene  
                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 OpenGL Framework",640,480,16,fullscreen))  
            {  
                return 0;                       // Quit If Window Was Not Created  
            }  
        }  
    }  
}

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

}