zoukankan      html  css  js  c++  java
  • win32下的OpenGL绘图环境框架

    Win32OpenGL入门

    主要的步骤包括:添加opengl头文件,库文件,键盘鼠标响应,像素格式设置,opengl环境初始化,绘图变量设置,创建窗口,窗口大小改变时响应,绘制场景,源文件

    1, 新建一个win32项目(注意,不是console程序),在添加过程中,创建一个空的项目,然后,在解决方案资源管理器的源文件树目录下,添加一个cpp文件,文件可以命名为mian.cpp

    2, 添加绘图相关的头文件和库文件,在新建的main.cpp中,加入如下头文件:

    #include <windows.h>                                         // Windows的头文件

    #include <gl\gl.h>                                                 // Header File For The OpenGL32 Library

    #include <gl\glu.h>                                               // Header File For The GLu32 Library

    #include <gl\glaux.h>                      // Header File For The Glaux Library

    #include <math.h>                                               // 引入数学函数库中的Sin

    #include <stdio.h>                                                // Header File For Standard Input/Output

    在项目,配置属性-连接器-输入的附加依赖项里,加入opengl32.libglu32.libglaux.lib

    glut.lib,如图所示。

    3,为创建绘图窗口,定义基本的相关变量,这些变量在opengl绘图中,都必须用到。

    HGLRC           hRC=NULL;   // 窗口着色描述表句柄
    HDC             hDC=NULL;    // OpenGL渲染描述表句柄
    HWND            hWnd=NULL;                    // 保存我们的窗口句柄
    HINSTANCE       hInstance;     // 保存程序的实例

    第一行设置的变量是Rendering Context(着色描述表)。每一个OpenGL都被连接到一个着色描述表上。着色描述表将所有的OpenGL调用命令连接到Device Context(设备描述表)上。我将OpenGL的着色描述表定义为 hRC 。要让您的程序能够绘制窗口的话,还需要创建一个设备描述表,也就是第二行的内容。Windows的设备描述表被定义为 hDC 。DC将窗口连接到GDI(Graphics Device Interface图形设备接口)。而RC将OpenGL连接到DC。第三行的变量 hWnd 将保存由Windows给我们的窗口指派的句柄。最后,第四行为我们的程序创建了一个Instance(实例)。

    4,为响应键盘,鼠标等操作,以及窗口活动情况,是否全屏等

    bool            keys[256];                     // 保存键盘按键的数组
    bool            active=TRUE;                // 窗口的活动标志,缺省为TRUE
    bool            fullscreen=TRUE;         // 全屏标志缺省,缺省设定成全屏模式
    GLfloat             rtri;     // 用于几何体旋转的角度

    active 变量用来告知程序窗口是否处于最小化的状态。如果窗口已经最小化的话,我们可以做从暂停代码执行到退出程序的任何事情。我喜欢暂停程序。这样可以使得程序不用在后台保持运行。

    fullscreen 变量的作用相当明显。如果我们的程序在全屏状态下运行, fullscreen 的值为TRUE,否则为FALSE。这个全局变量的设置十分重要,它让每个过程都知道程序是否运行在全屏状态下。

    5我们需要先定义WndProc()。必须这么做的原因是CreateGLWindow()有对WndProc()的引用,但WndProc()CreateGLWindow()之后才出现。在C语言中,如果我们想要访问一个当前程序段之后的过程和程序段的话,必须在程序开始处先申明所要访问的程序段。所以下面的一行代码先行定义了WndProc(),使得CreateGLWindow()能够引用WndProc()

    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);   // WndProc的定义

    6,绘图视口的尺寸以及在窗口大小改变时的响应函数。不管窗口的大小是否已经改变(假定您没有使用全屏模式)。甚至您无法改变窗口的大小时(例如您在全屏模式下),它至少仍将运行一次--在程序开始时设置我们的透视图。OpenGL场景的尺寸将被设置成它显示时所在窗口的大小。

    GLvoid ReSizeGLScene(GLsizei width, GLsizei height)   // 重置OpenGL窗口大小
    {
                        if (height==0)                                                         // 防止被零除
                        {
                                             height=1;                                            // Height设为1
                        }
     
                        glViewport(0, 0, width, height);                           // 重置当前的视口glMatrixMode(GL_PROJECTION);                            // 选择投影矩阵
                        glLoadIdentity();                                                    // 重置投影矩阵
     
                        // 设置投影模式为透视投影
                        gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);
     
                        glMatrixMode(GL_MODELVIEW);                     // 选择模型观察矩阵
                        glLoadIdentity();                                                    // 重置模型观察矩阵
    }

    透视图设置屏幕。意味着越远的东西看起来越小。这么做创建了一个现实外观的场景。此处透视按照基于窗口宽度和高度的45度视角来计算。0.1f,100.0f是我们在场景中所能绘制深度的起点和终点。 glMatrixMode(GL_PROJECTION)指明接下来的两行代码将影响projection matrix(投影矩阵)。投影矩阵负责为我们的场景增加透视。 glLoadIdentity()近似于重置。它将所选的矩阵状态恢复成其原始状态。调用 glLoadIdentity()之后我们为场景设置透视图。

    glMatrixMode(GL_MODELVIEW)指明任何新的变换将会影响 modelview matrix(模型观察矩阵)。模型观察矩阵中存放了我们的物体讯息。最后我们重置模型观察矩阵。如果您还不能理解这些术语的含义,请别着急。在以后的教程里,我会向大家解释。只要知道如果您想获得一个精彩的透视场景的话,必须这么做。

    7接下的代码段中,我们将对OpenGL进行所有的设置。我们将设置清除屏幕所用的颜色,打开深度缓存,启用smooth shading(阴影平滑),等等。这个例程直到OpenGL窗口创建之后才会被调用。此过程将有返回值。但我们此处的初始化没那么复杂,现在还用不着担心这个返回值

    int InitGL(GLvoid)                             // 此处开始对OpenGL进行所有设置
    {
    glShadeModel(GL_SMOOTH);                 // 启用阴影平滑
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);           // 黑色背景
    glClearDepth(1.0f);                                     // 设置深度缓存
    glEnable(GL_DEPTH_TEST);                  // 启用深度测试
    glDepthFunc(GL_LEQUAL); // 所作深度测试的类型
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);// 告诉系统对透视进行修正
    return TRUE;                                                 // 初始化 OK
    }

    GL_SMOOTH阴影平滑通过多边形精细的混合色彩,并对外部光进行平滑。我将在另一个教程中更详细的解释阴影平滑。

    深度缓存:将深度缓存设想为屏幕后面的层。深度缓存不断的对物体进入屏幕内部有多深进行跟踪。几乎所有在屏幕上显示3D场景OpenGL程序都使用深度缓存。它的排序决定那个物体先画。这样您就不会将一个圆形后面的正方形画到圆形上来。深度缓存是OpenGL十分重要的部分。

    8,绘图部分。下一段包括了所有的绘图代码。任何您所想在屏幕上显示的东东都将在此段代码中出现。 这里,绘制了一个简单的金字塔,每个顶点采用不用的颜色

    int DrawGLScene(GLvoid)                                  // 从这里开始进行所有的绘制
    {
                        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);      // 清除屏幕和深度缓存
                        glLoadIdentity();                                                    // 重置当前的模型观察矩阵
                        glTranslatef(-1.5f,0.0f,-6.0f);                              // 左移 1.5 单位,并移入屏幕 6.0
                        glRotatef(rtri,0.0f,1.0f,0.0f);            // Y轴旋转金字塔
     
                        glBegin(GL_TRIANGLES);                                  // 开始绘制金字塔的各个面
                                             glColor3f(1.0f,0.0f,0.0f);                                                          // 红色
                                             glVertex3f( 0.0f, 1.0f, 0.0f);             // 三角形的上顶点 (前侧面)
                                             glColor3f(0.0f,1.0f,0.0f);                                      // 绿色
                                             glVertex3f(-1.0f,-1.0f, 1.0f);                                // 三角形的左下顶点 (前侧面)
                                             glColor3f(0.0f,0.0f,1.0f);                                      // 蓝色
                                             glVertex3f( 1.0f,-1.0f, 1.0f);                                 // 三角形的右下顶点 (前侧面)
                                             glColor3f(1.0f,0.0f,0.0f);                                      // 红色
                                             glVertex3f( 0.0f, 1.0f, 0.0f);                                 // 三角形的上顶点 (右侧面)
                                             glColor3f(0.0f,0.0f,1.0f);                                      // 蓝色
                                             glVertex3f( 1.0f,-1.0f, 1.0f);                                 // 三角形的左下顶点 (右侧面)
                                             glColor3f(0.0f,1.0f,0.0f);                 // 绿色
                                             glVertex3f( 1.0f,-1.0f, -1.0f);                               // 三角形的右下顶点 (右侧面)
                                             glColor3f(1.0f,0.0f,0.0f);                                      // 红色
                                             glVertex3f( 0.0f, 1.0f, 0.0f);                                 // 三角形的上顶点 (后侧面)
                                             glColor3f(0.0f,1.0f,0.0f);                                                          // 绿色
                                             glVertex3f( 1.0f,-1.0f, -1.0f);                               // 三角形的左下顶点 (后侧面)
                                             glColor3f(0.0f,0.0f,1.0f);                                                          // 蓝色
                                             glVertex3f(-1.0f,-1.0f, -1.0f);                               // 三角形的右下顶点 (后侧面)
                                             glColor3f(1.0f,0.0f,0.0f);                                                          // 红色
                                             glVertex3f( 0.0f, 1.0f, 0.0f);                                 // 三角形的上顶点 (左侧面)
                                             glColor3f(0.0f,0.0f,1.0f);                                                          // 蓝色
                                             glVertex3f(-1.0f,-1.0f,-1.0f);                                // 三角形的左下顶点 (左侧面)
                                             glColor3f(0.0f,1.0f,0.0f);                                                          // 绿色
                                             glVertex3f(-1.0f,-1.0f, 1.0f);                                // 三角形的右下顶点 (左侧面)
                        glEnd();      
                        rtri+=0.2f;                       // 增加三角形的旋转变量
                                                                                     
                        return TRUE;                                                                              
    }

    关于绘图:在opengl里面绘图,首先要了解的就是坐标原点,OpenGL的坐标原点默认情况下,在屏幕中心。OpenGL的坐标系统是右手坐标系统,默认情况下,屏幕朝上为y,朝左为x,朝外为z。

    9,释放程序的绘图指针。在程序退出之前调用。KillGLWindow() 的作用是依次释放着色描述表,设备描述表和窗口句柄。

    GLvoid KillGLWindow(GLvoid)      // 正常销毁窗口
    {
                        if (fullscreen)                 // 我们处于全屏模式吗?
                        {
                                             ChangeDisplaySettings(NULL,0);                     // 是的话,切换回桌面,因为全屏模式直接关闭窗口,可能引发错误
                                             ShowCursor(TRUE);                                            // 显示鼠标指针
                        }
                        if (hRC)                                                                   // 我们拥有OpenGL渲染描述表吗?
                        {
                                             if (!wglMakeCurrent(NULL,NULL))                   // 我们能否释放DCRC描述表?
                                             {
                                                                 MessageBox(NULL,"释放DCRC失败。","关闭错误",MB_OK | MB_ICONINFORMATION);
                                             }
                                             if (!wglDeleteContext(hRC))           // 我们能否删除RC?
                                             {
                                                                 MessageBox(NULL,"释放RC失败。","关闭错误",MB_OK | MB_ICONINFORMATION);
                                             }
                                             hRC=NULL;                                                           // RC设为 NULL
                        }
                        if (hDC && !ReleaseDC(hWnd,hDC))                                   // 我们能否释放 DC?
                        {
                                             MessageBox(NULL,"释放DC失败。","关闭错误",MB_OK | MB_ICONINFORMATION);
                                             hDC=NULL;                                                           //  DC 设为 NULL
                        }
                        if (hWnd && !DestroyWindow(hWnd))                                   // 能否销毁窗口?
                        {
                                             MessageBox(NULL,"释放窗口句柄失败。","关闭错误",MB_OK | MB_ICONINFORMATION);
                                             hWnd=NULL;                                                        //  hWnd 设为 NULL
                        }
                        if (!UnregisterClass("OpenG",hInstance))                            // 能否注销类?
                        {
                                             MessageBox(NULL,"不能注销窗口类。","关闭错误",MB_OK | MB_ICONINFORMATION);
                                             hInstance=NULL;                                                 //  hInstance 设为 NULL
                        }
    }

    10,创建窗口。此过程返回布尔变量(TRUE FALSE)。他还带有5个参数:窗口的标题栏,窗口的宽度,窗口的高度,色彩位数(16/24/32),和全屏标志(TRUE --全屏模式, FALSE--窗口模式 )。返回的布尔值告诉我们窗口是否成功创建。

    BOOL CreateGLWindow(char* title, int width, int height, int bits, bool fullscreenflag)
    {
    //我们要求Windows为我们寻找相匹配的象素格式时,Windows寻找结束后将模式值保存在变量PixelFormat
                        GLuint                             PixelFormat;                  // 保存查找匹配的结果
                        WNDCLASS                  wc;                                   // 窗口类结构
                        DWORD                         dwExStyle;                                         // 扩展窗口风格
                        DWORD                         dwStyle;                         // 窗口风格
                        RECT WindowRect;                                              // 取得矩形的左上角和右下角的坐标值
                        WindowRect.left=(long)0;               // Left   设为 0
                        WindowRect.right=(long)width;                          // Right 设为要求的宽度
                        WindowRect.top=(long)0;                                    // Top    设为 0
                        WindowRect.bottom=(long)height;                                        // Bottom 设为要求的高度
                        fullscreen=fullscreenflag;                                   // 设置全局全屏标志
                        hInstance                       = GetModuleHandle(NULL);          // 取得我们窗口的实例
                        wc.style                          = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;// 移动时重画,并为窗口取得DCCS_OWNDC为窗口创建一个私有的DC。这意味着DC不能在程序间共享。
                        wc.lpfnWndProc                               = (WNDPROC) WndProc;               // WndProc处理消息
                        wc.cbClsExtra                                   = 0;                                  // 无额外窗口数据
                        wc.cbWndExtra                                 = 0;                                  // 无额外窗口数据
                        wc.hInstance                                     = hInstance;                   // 设置实例
                        wc.hIcon                         = LoadIcon(NULL, IDI_WINLOGO);// 装入缺省图标
                        wc.hCursor                                        = LoadCursor(NULL, IDC_ARROW);// 装入默认鼠标指针
                        wc.hbrBackground       = NULL;                                              // GL不需要背景
                        wc.lpszMenuName                          = NULL;                          // 不需要菜单
                        wc.lpszClassName      = "OpenG";                                                             // 设定类名字
     
                        if (!RegisterClass(&wc))                                       // 尝试注册窗口类
                        {
                                             MessageBox(NULL,"注册窗口失败","错误",MB_OK|MB_ICONEXCLAMATION);
                                             return FALSE;                                                        // 退出并返回FALSE
                        }
                        if (fullscreen)                                     // 要尝试全屏模式吗?
                        {
                                             DEVMODE dmScreenSettings;                         // 设备模式
                                             memset(&dmScreenSettings,0,sizeof(dmScreenSettings));// 确保内存清空为零
                                             dmScreenSettings.dmSize=sizeof(dmScreenSettings);                       // Devmode 结构的大小
                                             dmScreenSettings.dmPelsWidth = width;                           // 所选屏幕宽度
                                             dmScreenSettings.dmPelsHeight                     = height;                          // 所选屏幕高度
                                             dmScreenSettings.dmBitsPerPel = bits;          // 每象素所选的色彩深度                    dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
                                             // 尝试设置显示模式并返回结果。注: CDS_FULLSCREEN 移去了状态条。
                                             if (ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)
                                             {
                                                                 // 若模式失败,提供两个选项:退出或在窗口内运行。
                                                                 if (MessageBox(NULL,"全屏模式在当前显卡上设置失败!\n使用窗口模式?","NeHe G",MB_YESNO|MB_ICONEXCLAMATION)==IDYES)
                                                                 {
                                                                                     fullscreen=FALSE;// 选择窗口模式(Fullscreen=FALSE)
                                                                 }
                                                                 else
                                                                 {
                                                                                     // 弹出一个对话框,告诉用户程序结束
                                                                                     MessageBox(NULL,"程序将被关闭","错误",MB_OK|MB_ICONSTOP);
                                                                                     return FALSE;               // 退出并返回 FALSE
                                                                 }
                                             }
                        }
                        if (fullscreen)                                     // 仍处于全屏模式吗?
                        {
                                             dwExStyle=WS_EX_APPWINDOW;                 // 扩展窗体风格
                                             dwStyle=WS_POPUP;                                         // 窗体风格
                                             ShowCursor(FALSE);                      // 隐藏鼠标指针
                        }
                        else
                        {
                                             dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;// 扩展窗体风格
                                             dwStyle=WS_OVERLAPPEDWINDOW;                               // 窗体风格
                        }
                        AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle); // 调整窗口大小
                        if (!(hWnd=CreateWindowEx(        dwExStyle,                                         // 扩展窗体风格
                                                                                                          "OpenGL",                     // 类名字
                                                                                                          title,                                                      // 窗口标题
                                                                                                          WS_CLIPSIBLINGS |   // 必须的窗体风格属性
                                                                                                          WS_CLIPCHILDREN |                     // 必须的窗体风格属性
                                                                                                          dwStyle,                         // 选择的窗体属性
                                                                                                         0, 0,                                                      // 窗口位置
                                                                                                          WindowRect.right-WindowRect.left,// 
                                                                                                          WindowRect.bottom-WindowRect.top,//高度
                                                                                                          NULL,                                                  // 无父窗口
                                                                                                          NULL,                                                  // 无菜单
                                                                                                          hInstance,                                           // 实例
                                                                                                          NULL)))    // 不向WM_CREATE传递任何东东
                        {
                                             KillGLWindow();                                                                        // 重置显示区
                                             MessageBox(NULL,"不能创建一个窗口设备描述表","错误",MB_OK|MB_ICONEXCLAMATION);
                                             return FALSE;                                                        // 返回 FALSE
                        }
                        static           PIXELFORMATDESCRIPTOR pfd=// /pfd 告诉窗使用的像素格式
                        {
                                             sizeof(PIXELFORMATDESCRIPTOR),             // 上述格式描述符的大小
                                             1,                                                                              // 版本号
                                             PFD_DRAW_TO_WINDOW |                              // 格式支持窗口
                                             PFD_SUPPORT_OPENGL |           // 格式必须支持OpenGL
                                             PFD_DOUBLEBUFFER,                 // 必须支持双缓冲
                                             PFD_TYPE_RGBA,                          // 申请 RGBA 格式
                                             bits,                                                      // 选定色彩深度
                                             0, 0, 0, 0, 0, 0,                                    // 忽略的色彩位
                                             0,                                                          // Alpha缓存
                                             0,                                                          // 忽略Shift Bit
                                             0,                                                          // 无累加缓存
                                             0, 0, 0, 0,                                             // 忽略聚集位
                                             16,                                                       // 16 Z-缓存 (深度缓存)
                                             0,                                                          // 无蒙板缓存
                                             0,                                                          // 无辅助缓存
                                             PFD_MAIN_PLANE,                        // 主绘图层
                                             0,                                                          // Reserved
                                             0, 0, 0                                                  // 忽略层遮罩
                        };
                        if (!(hDC=GetDC(hWnd)))                                                        // 取得设备描述表了么?
                        {
                                             KillGLWindow();                                                                        // 重置显示区
                                             MessageBox(NULL,"不能创建一种相匹配的像素格式","错误",MB_OK|MB_ICONEXCLAMATION);
                                             return FALSE;                                                                            // 返回 FALSE
                        }
                        if (!(PixelFormat=ChoosePixelFormat(hDC,&pfd)))// Windows 找到相应的象素格式了吗?
                        {
                                             KillGLWindow();                                                    // 重置显示区
                                             MessageBox(NULL,"不能设置像素格式","错误",MB_OK|MB_ICONEXCLAMATION);
                                             return FALSE;                                                        // 返回 FALSE
                        }
                        if(!SetPixelFormat(hDC,PixelFormat,&pfd))    // 能够设置象素格式么?
                        {
                                             KillGLWindow();                                                                        // 重置显示区
                                             MessageBox(NULL,"不能设置像素格式","错误",MB_OK|MB_ICONEXCLAMATION);
                                             return FALSE;                                                                            // 返回 FALSE
                        }
                        if (!(hRC=wglCreateContext(hDC)))                                      // 能否取得着色描述表?
                        {
                                             KillGLWindow();                                // 重置显示区
                                             MessageBox(NULL,"不能创建OpenGL渲染描述表","错误",MB_OK|MB_ICONEXCLAMATION);
                                             return FALSE;                                                                            // 返回 FALSE
                        }
                        if(!wglMakeCurrent(hDC,hRC))                         // 尝试激活着色描述表
                        {
                                             KillGLWindow();                                // 重置显示区
                                             MessageBox(NULL,"不能激活当前的OpenGL渲然描述表","错误",MB_OK|MB_ICONEXCLAMATION);
                                             return FALSE;                                    // 返回 FALSE
                        }
                        ShowWindow(hWnd,SW_SHOW);                                        // 显示窗口
                        SetForegroundWindow(hWnd);                         // 略略提高优先级
                        SetFocus(hWnd);                                                  // 设置键盘的焦点至此窗口
                        ReSizeGLScene(width, height);                         // 设置透视 GL 屏幕
                        if (!InitGL())                                                             // 初始化新建的GL窗口
                        {
                                             KillGLWindow();           // 重置显示区
                                             MessageBox(NULL,"Initialization Failed.","ERROR",MB_OK|MB_ICONEXCLAMATION);
                                             return FALSE;                                    // 返回 FALSE
                        }
                        return TRUE;                                                          // 成功
    }

    11,建立了窗口类之后,我们接下来完成窗口消息处理函数。

    LRESULT CALLBACK WndProc( HWND        hWnd,                             // 窗口的句柄
                                                                                     UINT           uMsg,                              // 窗口的消息
                                                                                     WPARAM   wParam,                        // 附加的消息内容
                                                                                     LPARAM    lParam)                          // 附加的消息内容
    {
                        switch (uMsg)                                                        // 检查Windows消息
                        {
                                             case WM_ACTIVATE:                      // 监视窗口激活消息
                                             {
                                                                 if (!HIWORD(wParam))                    // 检查最小化状态
                                                                 {
                                                                                     active=TRUE;                // 程序处于激活状态
                                                                 }
                                                                 else
                                                                 {
                                                                                     active=FALSE;              // 程序不再激活
                                                                 }
     
                                                                 return 0;                          // 返回消息循环
                                             }
                                             case WM_SYSCOMMAND:                                // 系统中断命令
                                             {
                                                                 switch (wParam)                               // 检查系统调用
                                                                 {
                                                                                     case SC_SCREENSAVE:               // 屏保要运行?
                                                                                     case SC_MONITORPOWER:// 显示器要进入节电模式?
                                                                                     return 0;                          // 阻止发生
                                                                 }
                                                                 break;                                                                      // 退出
                                             }
                                             case WM_CLOSE:                                                // 收到Close消息?
                                             {
                                                                 PostQuitMessage(0);                                           // 发出退出消息
                                                                 return 0;                                                                                       // 返回
                                             }
                                             case WM_KEYDOWN:                                                             // 有键按下么?
                                             {
                                                                 keys[wParam] = TRUE;                                        // 如果是,设为TRUE
                                                                 return 0;                                                                  // 返回
                                             }
                                             case WM_KEYUP:                                                                    // 有键放开么?
                                             {
                                                                 keys[wParam] = FALSE;                                      // 如果是,设为FALSE
                                                                 return 0;                                              // 返回
                                             }
                                             case WM_SIZE:                                                     // 调整OpenGL窗口大小
                                             {
                                                                 ReSizeGLScene(LOWORD(lParam),HIWORD(lParam));                      // LoWord=Width,HiWord=Height
                                                                 return 0;                                              // 返回
                                             }
                        }
                        //  DefWindowProc传递所有未处理的默认消息。
                        return DefWindowProc(hWnd,uMsg,wParam,lParam);
    }

    12,好了,南西北风都准备好了,现在只差东风。接下来我们来定义东风——程序的入口。调用窗口创建例程,处理窗口消息,并监视人机交互。

    int  WINAPI WinMain(                    HINSTANCE                 hInstance,                      // 当前窗口实例
                                                                 HINSTANCE                 hPrevInstance,              // 前一个窗口实例
                                                                 LPSTR                            lpCmdLine,                                        // 命令行参数
                                                                 int                                    nCmdShow)                  // 窗口显示状态
    {
                        MSG           msg;                                                                        // Windowsx消息结构
                        BOOL         done=FALSE;                                                        // 用来退出循环的Bool 变量
                        // 提示用户选择运行模式
                        if (MessageBox(NULL,"你想在全屏模式下运行么?", "设置全屏模式",MB_YESNO|MB_ICONQUESTION)==IDNO)
                        {
                                             fullscreen=FALSE;                                               // FALSE为窗口模式
                        }
                        // 创建OpenGL窗口
    /*CreateGLWindow函数的参数依次为标题、宽度、高度、色彩深度,以及全屏标志。就这么简单!我很欣赏这段代码的简洁。如果未能创建成功,函数返回FALSE。程序立即退出。*/
                        if (!CreateGLWindow("win32下的OpenGL程序学习入门 ",640,480,16,fullscreen))
                        {
                                             return 0;                                              // 失败退出
                        }
                        while(!done)                                                          // 保持循环直到 done=TRUE
                        {
                                             if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))          // 有消息在等待吗?
                                             {
                                                                 if (msg.message==WM_QUIT)      // 收到退出消息?
                                                                 {
                                                                                     done=TRUE;                 // 是,则done=TRUE
                                                                 }
                                                                 else                                                                         // 不是,处理窗口消息
                                                                 {
                                                                                     TranslateMessage(&msg);                                  // 翻译消息
                                                                                     DispatchMessage(&msg);                                   // 发送消息
                                                                 }
                                             }
                                             else                                                                          // 如果没有消息
                                             {
                                                                 // 绘制场景。监视ESC键和来自DrawGLScene()的退出消息
                                                                 if (active)                        // 程序激活的么?
                                                                 {
                                                                                     if (keys[VK_ESCAPE])                                         // ESC 按下了么?
                                                                                     {
                                                                                                          done=TRUE;                 // ESC 发出退出信号
                                                                                     }
                                                                                     else                                 // 不是退出的时候,刷新屏幕
                                                                                     {
                                                                                                          DrawGLScene();          // 绘制场景
                                                                                                          SwapBuffers(hDC);     // 交换缓存 (双缓存)
                                                                                     }
                                                                 }
    //下面代码的用于进行全屏跟普通窗口之间的切换
                                                                 if (keys[VK_F1])                                // F1键按下了么?
                                                                 {
                                                                                     keys[VK_F1]=FALSE; // Key数组中的值为 FALSE
                                                                                     KillGLWindow();                                // 销毁当前的窗口
                                                                                     fullscreen=!fullscreen;                     // 切换 全屏 / 窗口 模式
                                                                                     // 重建 OpenGL 窗口
                                                                                     if (!CreateGLWindow("NeHe's OpenGL 程序框架",640,480,16,fullscreen))
                                                                                     {
                                                                                                          return 0;     // 如果窗口未能创建,程序退出
                                                                                     }
                                                                 }
                                             }
                        }
                        // 关闭程序
                        KillGLWindow();                                                                                                                                                          // 销毁窗口
                        return (msg.wParam);                                                                                                                           // 退出程序
    }

    双缓冲绘图:使用双缓存可以实现无闪烁的动画,绘图领域一个经常用到的技术,特别是大规模场景的绘图。我们实际上在另一个看不见的"屏幕"上绘图。当我们交换缓存后,我们当前的屏幕被隐藏,现在看到的是刚才看不到的屏幕。这也是我们看不到场景绘制过程的原因。场景只是即时显示。

    13,好了,运行程序

     

    附:

    常见错误列表:

    1新建的工程如果出现error C2664: MessageBoxW: 不能将参数2 从const char [42]转换为LPCWSTR这种错误, 将项目->配置属性->常规->字符集改为支持多字节字符集

    2. error LNK2019: 无法解析的外部符号_main,该符号在函数___tmainCRTStartup 中被引用,找到项目->配置属性->连接器->系统,将子系统修改为Windows (/SUBSYSTEM:WINDOWS)

  • 相关阅读:
    activemq安装及使用
    匿名内部类的简单使用
    Struts2中动态方法调用
    重定向和转发的区别
    result转发到一个action
    在Android Studio中导入jar包
    架构文档类别
    Linux/Unix下pid文件的作用
    【8.21校内测试】【最大生成树】【树状数组】【数学】
    【BZOJ】2653: middle
  • 原文地址:https://www.cnblogs.com/yanhuiw/p/1794467.html
Copyright © 2011-2022 走看看