《OpenGL v1.1》——(1)接入Win32窗口,并描绘基本图元

来源:互联网 发布:英雄联盟怎么玩 知乎 编辑:程序博客网 时间:2024/05/22 20:16

准备:

创建OpenGL窗口的通常步骤:

  1. 创建一个扩展的Windows窗口(注册类,创建窗口,取得句柄hwnd,取得设备场景hdc;
  2. 提供一个像素格式(结构),让Windows寻找匹配的格式,并给场景设置对应的像素格式;
  3. 取得场景的着色描述表hrc,并激活着色描述表;
  4. 显示窗口,调用调整窗口尺寸过程,调用GL初始化过程;
  5. 进入窗口的消息循环,调用绘制过程,调用交换缓存过程显示图形;

OpenGL库文件导入(VS):

  1. 在VS上使用外部库:包含路径及环境变量设置

  2. 链接lib

    • 方法1:直接按照上面链接中,在“右键项目—属性—配置属性—链接器—输入—附加依赖项”处加上相关的库;(本次用到的是opengl32.lib,和glu32.lib)。

    • 方法2:如我下方提供的代码Utility.h中采用#pragma comment(lib,”XXX.lib”)的方式加载lib文件。

OpenGL库介绍:

  1. GL.h图形库(核心库),提供最基本的函数,函数前缀都是gl;

  2. GLU.h实用库,包含多个诸如设置视点矩阵和投影矩阵、执行多边形网格化以及渲染曲面等任务的函数;

  3. GLAux.h辅助库,提供一些特殊的函数,包括简单的窗口管理、输入事件处理、某些复杂三维物体绘制等函数。前缀aux(现在更多采用glut库);

  4. glut.h实用工具库,这是一个独立于窗口系统的工具包,用于绕开窗口系统API的复杂性,简化打开窗口、检测输入等任务,提供了一些用于创建复杂三维物体(球形、圆环和茶壶)的函数,前缀是glut;

  5. glew.h工具函数,能够自动识别本平台所支持的全部OpenGL高级扩展函数(OpenGL1.1之后的扩展必须用到这个库),既只要包含一个glew.h,就能使用gl、glu、glext、glx的全部函数;

  6. glfw3.h开发框架(替代glut,freeglut替代glut,而freeglut的BUG太多,因而glfw应运而生);

  7. 窗口库glx、agl(ios)、wgl(windows);

glut或者freeglut主要是1.0的基本函数功能,GLEW是使用OPENGL2.0之后的一个工具函数;


本篇所用的API:

《win32 API》

  1. HGDIOBJ WINAPI GetStockObject(int fnObject);

    1. 参数:
      • fnObject :Specifies the type of stock object.
    2. 功能:
       The GetStockObject function retrieves a handle to one of the stock pens, brushes, fonts, or palettes.
       该函数检索预定义的备用笔、刷子、字体或者调色板的句柄。
  2. HCURSOR WINAPI LoadCursor(HINSTANCE hInstance, LPCWSTR lpCursorName);

    1. 参数:
      • hInstance:Handle to an instance of the module whose executable file contains the cursor to be loaded.
      • lpCursorName:Pointer to a null-terminated string that contains the name of the cursor resource to be loaded.
    2. 功能:
       The LoadCursor function loads the specified cursor resource from the executable (.EXE) file associated with an application instance.
       该函数从一个与应用事例相关的可执行文件(EXE文件)中载入指定的光标资源。该函数已被Loadlmage函数替代。
  3. HICON WINAPI LoadIcon(HINSTANCE hInstance,LPCWSTR lpIconName);

    1. 参数:
      • hInstance:Handle to an instance of the module whose executable file contains the icon to be loaded.
      • lpIconName:Pointer to a null-terminated string that contains the name of the icon resource to be loaded.
    2. 功能:
       The LoadIcon function loads the specified icon resource from the executable (.exe) file associated with an application instance.
       该函数从与hInstance模块相关联的可执行文件中装入lpIconName指定的图标资源,仅当图标资源还没有被装入时该函数才执行装入操作,否则只获取装入的资源句柄。该函数已被Loadlmage函数替代。
       
  4. ATOM WINAPI RegisterClass(CONST WNDCLASSW *lpWndClass);
    1. 参数:
      • lpWndClass: Pointer to a WNDCLASS structure.
    2. 功能:
        registers a window class for subsequent use in calls to the CreateWindow or CreateWindowEx function.
        RegisterClass注册在随后调用CreateWindow函数和CreateWindowEx函数中使用的窗口类。
       
  5. CreateWindow(lpClassName, lpWindowName, dwStyle, x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam);
    1. 参数:
      • lpClassName:registered class name
      • lpWindowName:window name
      • dwStyle:window style
      • x, y:horizontal & vertical position of window
      • nWidth, nHeight:window width & height
      • hWndParent:handle to parent or owner window
      • hMenu:menu handle or child identifier
      • hInstance:handle to application instance
      • lpParam:window-creation data
    2. 功能:
       creates an overlapped, pop-up, or child window.
       在注册完窗口类后就需要进行窗口的创建,该函数创建一个重叠式窗口、弹出式窗口或子窗口。
       
  6. BOOL WINAPI ShowWindow(HWND hWnd, int nCmdShow);
    1. 参数:
      • hWnd:handle to window.
      • nCmdShow:show state,Specifies how the window is to be shown.
    2. 功能:
       sets the specified window’s show state.
       该函数设置指定窗口的显示状态。
       
  7. BOOL WINAPI UpdateWindow(HWND hWnd);
    1. 参数:
      • hWnd:Handle to the window to be updated.
    2. 功能:
       updates the client area of the specified window by sending a WM_PAINT message to the window if the window’s update region is not empty.
       如果窗口的更新区域不是空的,则通过向窗口发送WM_PAINT消息来更新指定窗口的客户区域。
       
  8. BOOL WINAPI UnregisterClassW(LPCWSTR lpClassName, HINSTANCE hInstance);
    1. 参数:
      • lpClassName:class name,pointer to a null-terminated string or a class atom.
      • hInstance:handle to application instance.
    2. 功能:
       unregisters a window class, freeing the memory required for the class.
       取消一个窗口类,释放类所占用的内存;
       
  9. int WINAPI MessageBox(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType);
    1. 参数:
      • hWnd:Handle to the owner window of the message box to be created.
      • lpText:text in message box.
      • lpCaption:message box title.
      • uType:message box style.
    2. 功能:
       creates, displays, and operates a message box.
       创建、显示和操作一个消息框;
       
  10. VOID WINAPI PostQuitMessage(int nExitCode);
    1. 参数:
      • nExitCode:Specifies an application exit code. This value is used as the wParam parameter of the WM_QUIT message.
    2. 功能:
       Indicates to the system that a thread has made a request to terminate (quit). It is typically used in response to a WM_DESTROY message.
       向系统表明一个线程已经发出终止(退出)请求。它通常用于对WM_DESTROY消息的响应;
       
  11. BOOL WINAPI DestroyWindow(HWND hWnd);
    1. 参数:
      • hWnd:Handle to the window to be destroyed.
    2. 功能:
       destroys the specified window. The function sends WM_DESTROY and WM_NCDESTROY messages to the window to deactivate it and remove the keyboard focus from it.
       销毁指定的窗口。该函数发送WM_DESTROY和WM_NCDESTROY消息到窗口以禁用它,和将键盘的焦点移除;
       
  12. LRESULT WINAPI DefWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
    1. 参数:
      • hWnd:handle to window;
      • Msg:message identifier;
      • wParam:first message parameter;
      • lParam:second message parameter;
    2. 功能:
       Calls the default window procedure to provide default processing for any window messages that an application does not process.
       该函数调用缺省的窗口过程来为应用程序没有处理的任何窗口消息提供缺省的处理,该函数确保每一个消息得到处理;
       
  13. BOOL WINAPI PeekMessage(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg);
    1. 参数:
      • lpMsg:Pointer to an MSG structure that receives message information.
      • hWnd:Handle to the window whose messages are to be examined.
      • wMsgFilterMin:Specifies the value of the first message in the range of messages to be examined.
      • wMsgFilterMax:Specifies the value of the last message in the range of messages to be examined.
      • wRemoveMsg:Specifies how messages are handled.
    2. 功能:
       The PeekMessage function dispatches incoming sent messages, checks the thread message queue for a posted message, and retrieves the message (if any exist).
       分派传入的消息,检查已发布消息的线程消息队列,并检索消息(如果存在的话)
       
  14. BOOL WINAPI TranslateMessage(CONST MSG *lpMsg);
    1. 参数:
      • lpMsg:Pointer to an MSG structure that contains message information retrieved from the calling thread’s message queue by using the GetMessage or PeekMessage function.
    2. 功能:
       translates virtual-key messages into character messages. The character messages are posted to the calling thread’s message queue, to be read the next time the thread calls the GetMessage or PeekMessage function.
       将虚拟键消息转换为字符消息。字符消息再被派送到调用线程的消息队列中,待到下次线程调用的GetMessage或PeekMessage函数读取。
       
  15. LRESULT WINAPI DispatchMessage(CONST MSG *lpMsg);
    1. 参数:
      • lpMsg:Pointer to an MSG structure that contains the message.
    2. 功能:
       dispatches a message to a window procedure. It is typically used to dispatch a message retrieved by the GetMessage function.
       向“窗口过程”发送一条消息,它通常用于分派由GetMessage函数检索的消息。
       
  16. DWORD WINAPI timeGetTime(void);
    1. 参数:
      • none:
    2. 功能:
       retrieves the system time, in milliseconds. The system time is the time elapsed since Windows was started.
       以毫秒为单位检索系统时间。系统时间是自Windows启动以来开始计算的时间。
       
  17. HGLRC WINAPI wglCreateContext(HDC hdc);
    1. 参数:
      • hdc:Handle to a device context for which the function creates a suitable OpenGL rendering context.
    2. 功能:
       creates a new OpenGL rendering context, which is suitable for drawing on the device referenced by hdc. The rendering context has the same pixel format as the device context.
       创建一个新的OpenGL着色正文(rendering context),适合于在hdc引用的设备上绘制。着色正文与设备描述表具有相同的像素格式。
       
  18. BOOL WINAPI wglMakeCurrent(HDC hdc, HGLRC hglrc);
    1. 参数:
      • hdc:Handle to a device context. Subsequent OpenGL calls made by the calling thread are drawn on the device identified by hdc.
      • hglrc:Handle to an OpenGL rendering context that the function sets as the calling thread’s rendering context.
    2. 功能:
       makes a specified OpenGL rendering context the calling thread’s current rendering context. All subsequent OpenGL calls made by the thread are drawn on the device identified by hdc. You can also use wglMakeCurrent to change the calling thread’s current rendering context so it’s no longer current.
       设定指定的OpenGL着色正文为当前调用线程的着色正文(渲染环境)。以后这个线程所有的OpenGL调用都是在这个hdc标识的设备上绘制。你也可以使用wglMakeCurrent 函数来改变调用线程的当前着色正文(渲染环境),使之不再是当前的渲染环境。
       
  19. BOOL WINAPI SwapBuffers(HDC hdc);
    1. 参数:
      • hdc:Specifies a device context whose buffers get swapped.
    2. 功能:
       The SwapBuffers function exchanges the front and back buffers if the current pixel format for the window referenced by the specified device context includes a back buffer.
       如果指定的设备描述表所引用的窗口的当前像素格式包含一个后缓冲区,那么该函数将交换前缓冲区和后缓冲区。
       
  20. int ChoosePixelFormat(HDC hdc, CONST PIXELFORMATDESCRIPTOR* ppfd );

    1. 参数:
      • hdc:device context to search for a best pixel format match;
      • ppfd:pixel format for which a best match is sought;
    2. 功能:
       The ChoosePixelFormat function attempts to match an appropriate pixel format supported by a device context to a given pixel format specification.
       该函数尝试由指定的像素格式匹配出一个支持设备描述表的适合的像素格式索引;
  21. BOOL SetPixelFormat(HDC hdc, int iPixelFormat, CONST PIXELFORMATDESCRIPTOR* ppfd);

    1. 参数:
      • hdc: device context whose pixel format the function attempts to set;
      • iPixelFormat:pixel format index (one-based);
      • ppfd:pointer to logical pixel format specification;
    2. 功能:
       The SetPixelFormat function sets the pixel format of the specified device context to the format specified by the iPixelFormat index.
       通过指定iPixelFormat索引以设置指定设备描述表(DC)的像素格式。
  22. HDC WINAPI GetDC(HWND hWnd);

    1. 参数:
      • hWnd:Handle to the window whose DC is to be retrieved. If this value is NULL, GetDC retrieves the DC for the entire screen.
    2. 功能:
       The GetDC function retrieves a handle to a display device context (DC) for the client area of a specified window or for the entire screen. You can use the returned handle in subsequent GDI functions to draw in the DC.
       该函数检索指定窗口的客户区域或整个屏幕的显示设备描述表(DC)的句柄。你可以在随后设备描述表的GDI函数绘制中使用返回的句柄。
  23. BOOL WINAPI wglDeleteContext(HGLRC hglrc);

    1. 参数:
      • hglrc:Handle to an OpenGL rendering context that the function will delete.
    2. 功能:
       The wglDeleteContext function deletes a specified OpenGL rendering context.
       该函数删除指定的OpenGL着色正文(渲染环境);

《OpenGL API》

  1. void APIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height);
    1. 参数:
      • x,y:Specify the lower left corner of the viewport rectangle, in pixels. The default is (0, 0).
      • width,height:Specify the width and height, respectively, of the viewport. When a GL context is first attached to a window, width and height are set to the dimensions of that window.
    2. 功能:
       glViewport specifies the affine transformation of x and y from normalized device coordinates to window coordinates. Let (xnd, ynd) be normalized device coordinates.
       该函数指定从标准化设备坐标到窗口坐标的x和y坐标的仿射变换。令(xnd,ynd)为标准化设备坐标。
       
  2. void glMatrixMode(GLenum mode);

    1. 参数:
      • mode:Specifies which matrix stack is the target for subsequent matrix operations;
    2. 功能:
       Specify which matrix is the current matrix;
       指定一个矩阵堆栈为后续矩阵操作的目标,分别有这4种:GL_MODELVIEW、GL_PROJECTION、GL_TEXTURE、GL_COLOR;
  3. void APIENTRY glLoadIdentity(void);

    1. 参数:
      • none:
    2. 功能:
       replaces the current matrix with the identity matrix.
       用单位矩阵代替当前矩阵;
       
  4. void APIENTRY gluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar);

    1. 参数:
      • fovy:Specifies the field of view angle, in degrees, in the y direction.
      • aspect:Specifies the aspect ratio that determines the field of view in the x direction.(width / height)
      • zNear:Specifies the distance from the viewer to the near clipping plane (always positive).
      • zFar:Specifies the distance from the viewer to the far clipping plane (always positive).
    2. 功能:
       specifies a viewing frustum into the world coordinate system. In general, the aspect ratio in gluPerspective should match the aspect ratio of the associated viewport.
       指定一个截头视椎体到世界坐标系统。一般来说,gluPersPective中的横纵比应该与相关联的视口的横纵比相匹配;
  5. void APIENTRY glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);

    1. 参数:
      • red、green、blue、alpha: Values specified by glClearColor are clamped to the range [0, 1].
    2. 功能:
       specifies the red, green, blue, and alpha values used by glClear to clear the color buffers.
       指定通过glClear来清空颜色缓冲区的红、绿、蓝 和 alpha值;
  6. void APIENTRY glClear(GLbitfield mask);

    1. 参数:
      • mask:Bitwise OR of masks that indicate the buffers to be cleared.
    2. 功能:
       takes a single argument that is the bitwise OR of several values indicating which buffer is to be cleared.
       接受一个参数,即位值或多个值,指示要清楚哪个缓冲区。
  7. void APIENTRY glFlush(void);

    1. 参数:
      • none:
    2. 功能:
       glFlush empties all of these buffers, causing all issued commands to be executed as quickly as they are accepted by the actual rendering engine.
       清空缓冲区,将指令送往缓硬件立即执行,但是它是将命令传送完毕之后立即返回,不会等待指令执行完毕。这些指令会在有限时间内执行完毕。
      如果直接绘制到前缓冲,那么OpenGL的绘制将不会有任何延迟。
  8. void APIENTRY glPushMatrix(void);

    1. 参数:
      • can:
    2. 功能:
       pushes the current matrix stack down by one, duplicating the current matrix. That is, after a glPushMatrix call, the matrix on the top of the stack is identical to the one below it.
       将当前的矩阵栈逐个压栈入栈中,留待之后取出使用。
  9. void APIENTRY glPointSize(GLfloat size);

    1. 参数:
      • size:Specifies the diameter of rasterized points. The default is 1.0.
    2. 功能:
       specifies the rasterized diameter of both aliased and antialiased points.
       函数指定栅格化点的直径;
  10. void APIENTRY glLineWidth(GLfloat width);

    1. 参数:
      • width:Specifies the width of rasterized lines. The default is 1.0.
    2. 功能:
       specifies the rasterized width of both aliased and antialiased lines.
       指定线段的栅格化宽度,初始值为1;
       
  11. void APIENTRY glTranslatef(GLfloat x, GLfloat y, GLfloat z);

    1. 参数:
      • x,y,z:Specify the x, y, and z coordinates of a translation vector.
    2. 功能:
       moves the coordinate system origin to the point specified by (x, y, z).
       将坐标系原点移动到指定的点(x,y,z);
  12. void APIENTRY glColor3f(GLfloat red, GLfloat green, GLfloat blue);

    1. 参数:
      • red, green, blue:Specify new red, green, and blue values for the current color.
    2. 功能:
       set the current color.
       设置当前颜色;
  13. void APIENTRY glRotatef (GLfloat angle, GLfloat x, GLfloat y, GLfloat z);

    1. 参数:
      • angle:Specifies the angle of rotation, in degrees.
      • x,y,z:Specify the x, y, and z coordinates of a vector, respectively.
    2. 功能:
       computes a matrix that performs a counterclockwise rotation of angle degrees about the vector from the origin through the point (x, y, z).
       计算一个矩阵,它对从原点到点(x,y,z)的矢量进行逆时针旋转一个角度;旋转轴经过原点,方向为(x,y,z),旋转角度为angle,方向满足右手定则。
  14. void APIENTRY glPopMatrix (void);

    1. 参数:
      • none:
    2. 功能:
       pops the current matrix stack, replacing the current matrix with the one below it on the stack.
       弹出当前矩阵堆栈,将当前矩阵替换为堆栈下的当前矩阵;
  15. void APIENTRY glBegin (GLenum mode);

    1. 参数:
      • mode:Specifies the primitive or primitives that will be created from vertices presented between glBegin and the subsequent glEnd.
    2. 功能:
       accepts a single argument that specifies which of ten ways the vertices are interpreted.
       接受一个参数,其指定的10种方式中的1种进行顶点解释。
  16. void APIENTRY glVertex3f (GLfloat x, GLfloat y, GLfloat z);

    1. 参数:
      • x,y,z:Specify x, y, z coordinates of a vertex.
    2. 功能:
       glVertex commands are used within glBegin / glEnd pairs to specify point, line, and polygon vertices.
       glVertex指令用在glBegin和glEnd函数对之间,用于指定点、线和多边形顶点;
  17. void APIENTRY glEnd (void);

    1. 参数:
      • none:
    2. 功能:
       Specifies the primitive or primitives that will be created from vertices presented between glBegin and the subsequent glEnd.
       指定了从glBegin和glEnd之间显示的从提供的顶点创建的图元;

《补充》

其他可以包含在glBegine()和glEnd()中的函数:

函数
函数意义
glColor*() 设置当前颜色 glIndex*() 设置当前颜色表 glNormal*() 设置法向坐标 glEvalCoord*() 产生坐标 glCallList(),glCallLists() 显示列表 glTexCoord*() 设置纹理坐标 glEdgeFlag*() 控制边界绘制 glMaterial*() 设置材质

代码:

Utility.h

#pragma once#ifndef WINDOWS_PLATFORM#define WINDOWS_PLATFORM#include <windows.h>#include<math.h>#pragma comment(lib,"winmm.lib")#endif// !WINDOWS_PLATFORM#ifndef OPENGL_H#define OPENGL_H#include <gl/GL.h>//图形库,提供最基本的函数,函数前缀gl;#pragma comment(lib,"opengl32.lib")#include <gl/GLU.h>//使用库,包含多个完成诸如设置视点矩阵和投影矩阵、执行多边形网格化以及渲染曲面等任务的函数;#pragma comment(lib,"glu32.lib")#endif // !OPENGL_H

MyOpenGL.h

#pragma once#include "Utility.h"#include "BasePainter.h"class MyOpenGL{private:    HWND m_hWnd;//窗口句柄    HDC m_hDc;//DC将窗口连接到GDI(Graphics Device Interface图形设备接口)    HGLRC m_hRc;//RC将OpenGL连接到DC    BasePainter* m_basePainter;//自定义的图元绘制类    float m_angle = 0;public:    MyOpenGL(HWND hWnd);    ~MyOpenGL();    void Init(int width, int height);    void ReSize(int width,int height);    void Render();private:    void cleanUp();    bool setPixelFormat();    void drawBase();};

BasePainter.h

#pragma once#include "Utility.h"class BasePainter{public:    BasePainter();    ~BasePainter();    void drawPoint();    void drawLine();    void drawTriangle();    void drawSqare();    void drawQube();    void drawCir(int rad);};

MyGame.cpp

#include "Utility.h"#include "MyOpenGL.h"//全局变量HWND g_hWnd; ///窗口句柄(可以理解为窗口id)HINSTANCE g_hInstance; ///窗口实例MyOpenGL* g_myOpenGL;///OpenGL//函数声明LRESULT CALLBACK WndProc(HWND _hWnd, UINT _uMsg, WPARAM _wParam, LPARAM _lParam);void GameLoop();//入口函数:hInstance 当前应用窗口实例句柄、hPrevInstance上一个应用程序窗口实例句柄、lpCmdLine命令行参数、nShowCmd显示方式int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nShowCmd) {    //生成窗口类的结构体对象    WNDCLASS* pWndClass = new WNDCLASS();    ZeroMemory(pWndClass, sizeof(WNDCLASS));///刷新内存    pWndClass->cbClsExtra = NULL;///窗口类附加信息    pWndClass->cbWndExtra = NULL;///窗口附加信息    pWndClass->hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);///窗口背景颜色画刷    pWndClass->hCursor = LoadCursor(hInstance,IDC_ARROW);///加载鼠标样式    pWndClass->hIcon = LoadIcon(hInstance,IDC_ICON);///加载窗口图标    pWndClass->hInstance = hInstance;///当前窗口实例句柄    pWndClass->lpfnWndProc = WndProc;//窗口过程函数(处理该窗口的所有信息)    pWndClass->lpszClassName = __TEXT("MyWndClass");///窗口类名,能够    pWndClass->lpszMenuName = NULL;///不要菜单    pWndClass->style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;///窗口风格    //注册窗口    RegisterClass(pWndClass);    //创建窗口    g_hInstance = hInstance;    int nWidth = 800; int nHeigh = 600;    g_hWnd = CreateWindow(pWndClass->lpszClassName, __TEXT("OpenGL学习记录 No.1"), WS_OVERLAPPEDWINDOW, 0, 0, nWidth, nHeigh, NULL, NULL, hInstance, NULL);    //连接OpenGL    g_myOpenGL = new MyOpenGL(g_hWnd);    g_myOpenGL->Init(nWidth, nHeigh);    //显示窗口,更新客户区内容    if (g_hWnd) {        ShowWindow(g_hWnd, SW_SHOWNORMAL);///展示窗口        UpdateWindow(g_hWnd);///更新(绘制)窗口    }    else        UnregisterClass(pWndClass->lpszClassName, g_hInstance);    //游戏循环    GameLoop();    return 0;}//窗口过程函数:_hWnd 窗口句柄,_uMsg 消息编号,_wParam 高位附加信息,_lParam低位附加信息LRESULT CALLBACK WndProc(HWND _hWnd, UINT _uMsg, WPARAM _wParam, LPARAM _lParam) {    switch (_uMsg)    {    case WM_CREATE:        MessageBox(NULL, __TEXT("是否测试OpenGL?"), __TEXT("提示"), MB_OK);        break;    case WM_PAINT://窗口绘制消息        break;    case WM_DESTROY:        //MessageBox(NULL, __TEXT("销毁?"), __TEXT("提示"), MB_OK);        PostQuitMessage(0);        break;    case WM_CLOSE:        //MessageBox(NULL, __TEXT("是否关闭?"), __TEXT("提示"), MB_OK);        DestroyWindow(_hWnd);        break;    case WM_LBUTTONDOWN:        OutputDebugString(__TEXT("单击\n"));        break;    case WM_ACTIVATE:        OutputDebugString(__TEXT("激活"));        break;    case WM_SIZE:    {        int nWidth = LOWORD(_lParam);        int nHeigh = HIWORD(_lParam);        g_myOpenGL->ReSize(nWidth, nHeigh);        break;    }    }    return DefWindowProc(_hWnd, _uMsg, _wParam, _lParam);}//游戏主循环void GameLoop() {    MSG msg;    ZeroMemory(&msg, sizeof(MSG));    while (msg.message != WM_QUIT)    {        //获取消息(peekMessage不等待,getMessage会等待)        if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))//**注意!!!这里peekMessage第二个参数如果为h_Wnd的话,会出现死循环。(原因暂时不明)        {            //翻译消息            TranslateMessage(&msg);            //分派消息            DispatchMessage(&msg);        }        else        {            //帧数控制            static float lastFlash = timeGetTime();            float currentFlash = timeGetTime();            float elapse = currentFlash - lastFlash;            if (elapse < 1000 / 100)                Sleep(1000 / 100 - elapse);            //游戏逻辑入口            g_myOpenGL->Render();            lastFlash = currentFlash;        }    }    return;}

MyOpenGL.cpp

#include "MyOpenGL.h"MyOpenGL::MyOpenGL(HWND hWnd){    m_hWnd = hWnd;    m_basePainter = new BasePainter();    m_hDc = GetDC(m_hWnd);    if (!m_hDc)        MessageBox(NULL, L"OpenGL获取DC失败", L"Error", 0);}MyOpenGL::~MyOpenGL(){    cleanUp();}//初始化摄像机void MyOpenGL::Init(int width, int height){    setPixelFormat();    ReSize(width,height);}//重置GL视口大小void MyOpenGL::ReSize(int width, int height){    if (height <= 1)//防止除0        height = 1;    glViewport(0, 0, width, height);//设置OpenGL视口大小    glMatrixMode(GL_PROJECTION);//设置当前矩阵为投影矩阵    glLoadIdentity();//矩阵单位化    gluPerspective(45.0f, (double)width / (double)height, 0.1f, 1000.0f);//透视投影(视口角度、宽高比、近截面、远截面)    //gluOrtho2D();//正交投影    glMatrixMode(GL_MODELVIEW);//设置当前矩阵为模型观察矩阵    glLoadIdentity();//矩阵单位化}//渲染图形void MyOpenGL::Render(){    glClearColor(1, 0, 0, 1);//清空背景用的底色    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//清空颜色和深度缓冲区    //各种图形的渲染    drawBase();    m_angle++;//用于旋转的角度    if (m_angle >= 360)        m_angle = 0.0f;    glFlush();    SwapBuffers(m_hDc);}//销除窗口void MyOpenGL::cleanUp(){    wglMakeCurrent(m_hDc, NULL);//    wglDeleteContext(m_hRc);}//给windows窗口设备设置像素格式bool MyOpenGL::setPixelFormat(){    int iPixelFormat = 0;    //描述绘图表面的像素格式    PIXELFORMATDESCRIPTOR pfd;    pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);//上述格式描述符的大小    pfd.nVersion = 1;//版本号    pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;    //格式支持:窗口、OpenGL、双缓冲    pfd.iPixelType = PFD_TYPE_RGBA;//申请RGBA格式    pfd.cColorBits = 16;//选定色彩深度    pfd.cRedBits = 0;//忽略色彩位    pfd.cRedShift = 0;    pfd.cGreenBits = 0;    pfd.cGreenShift = 0;    pfd.cBlueBits = 0;    pfd.cBlueShift = 0;    pfd.cAlphaBits = 0;//wuAlpha缓存    pfd.cAlphaShift = 0;//忽略Shift Bit    pfd.cAccumBits = 0;//无聚集缓存    pfd.cAccumRedBits = 0;//忽略聚集位    pfd.cAccumGreenBits = 0;    pfd.cAccumBlueBits = 0;    pfd.cAccumAlphaBits = 0;    pfd.cDepthBits = 16;//16位 深度缓存(z-缓存)    pfd.cStencilBits = 0;//无模板缓存    pfd.cAuxBuffers = 0;//无辅助缓存    pfd.iLayerType = PFD_MAIN_PLANE;//主绘图层    pfd.bReserved = 0;//保留    pfd.dwLayerMask = 0;//忽略遮罩层    pfd.dwVisibleMask = 0;    pfd.dwDamageMask = 0;    //让WINDOWS寻找与我们提供的pfd相匹配的像素格式,找到后保存在变量iPixelFormat中    if (!(iPixelFormat = ChoosePixelFormat(m_hDc, &pfd)))    {        MessageBox(NULL, L"OpenGL配置失败", L"Error", 0);        return false;    }    SetPixelFormat(m_hDc, iPixelFormat, &pfd);//给设备描述表设置像素格式    m_hRc = wglCreateContext(m_hDc);//取得着色描述表    wglMakeCurrent(m_hDc, m_hRc);//激活着色描述表,GL窗口创建工作完成    return true;}//绘制各种图元图形void MyOpenGL::drawBase(){    glPushMatrix();    glPointSize(4);    glTranslatef(-6, 4, -13);    glColor3f(0, 1, 0);    glRotatef(m_angle, 1, 1, 1);    m_basePainter->drawPoint();    glPopMatrix();    glPushMatrix();    glLineWidth(1);    glTranslatef(-3, 4, -13);    glColor3f(0, 1, 0);    glRotatef(m_angle, 1, 1, 1);    m_basePainter->drawLine();    glPopMatrix();    glPushMatrix();    glLineWidth(1);    glTranslatef(0, 4, -13);    glColor3f(0, 1, 0);    glRotatef(m_angle, 1, 1, 1);    m_basePainter->drawTriangle();    glPopMatrix();    glPushMatrix();    glLineWidth(1);    glTranslatef(3, 4, -13);    glColor3f(0, 0, 1);    glRotatef(m_angle, 1, 1, 1);    m_basePainter->drawSqare();    glPopMatrix();    glPushMatrix();    glLineWidth(1);    glTranslatef(6, 4, -13);    glColor3f(0.3, 0.3, 0.3);    glRotatef(m_angle, 1, 1, 1);    m_basePainter->drawQube();    glPopMatrix();    glPushMatrix();    glPointSize(4);    glTranslatef(-6, 0, -13);    glColor3f(0.3, 0.3, 0.3);    glRotatef(m_angle, 1, 1, 1);    m_basePainter->drawCir(4);    glPopMatrix();}

BasePainter.cpp

#include "BasePainter.h"BasePainter::BasePainter(){}BasePainter::~BasePainter(){}//画点void BasePainter::drawPoint(){    glBegin(GL_POINTS);    glVertex3f(0, 1, 1);    glVertex3f(-1, 1, 0);    glVertex3f(1, -1, 0);    glEnd();}//画线void BasePainter::drawLine(){    //glBegin(GL_LINE_STRIP);    glBegin(GL_LINE_LOOP);    glVertex3f(0, 1, 1);    glVertex3f(-1, 1, 0);    glVertex3f(1, -1, 0);    glEnd();}//画三角形void BasePainter::drawTriangle(){    glBegin(GL_TRIANGLES);//画凸多边形的    glVertex3f(0, 1, 1);    glVertex3f(-1, 1, 0);    glVertex3f(1, -1, 0);    glEnd();}//画四边形void BasePainter::drawSqare(){    glBegin(GL_POLYGON);//画凸多边形的    glVertex3f(0, 0, 0);    glVertex3f(1, 0, 0);    glVertex3f(1, 1, 0);    glVertex3f(0, 1, 0);    glEnd();}//画方体void BasePainter::drawQube(){    glBegin(GL_TRIANGLE_STRIP);//画凸带    glVertex3f(0, 0, 0);    glVertex3f(0, 1, 0);    glVertex3f(1, 0, 0);    glVertex3f(1, 1, 0);    glVertex3f(1, 0, -1);    glVertex3f(1, 1, -1);    glVertex3f(0, 0, -1);    glVertex3f(0, 1, -1);    glVertex3f(0, 0, 0);    glVertex3f(0, 1, 0);    glEnd();    glBegin(GL_POLYGON);//画凸多边形的    glVertex3f(0, 0, 0);    glVertex3f(1, 0, 0);    glVertex3f(1, 0, -1);    glVertex3f(0, 0, -1);    glEnd();    glBegin(GL_POLYGON);//画凸多边形的    glVertex3f(0, 1, 0);    glVertex3f(1, 1, 0);    glVertex3f(1, 1, -1);    glVertex3f(0, 1, -1);    glEnd();}//画圆形void BasePainter::drawCir(int rad){    glBegin(GL_TRIANGLE_FAN);    glVertex3f(0, 0, 0);    for (int i = 0; i <= 365; i += 5)    {        float p = (i / 180.0f)*3.14;        glVertex3f(cos(p) * 2.0f, sin(p) * 2.0f, 0);    }    glEnd();}

问题:

这个问题不属于OpenGL的,而是win32上的一个问题。在自定义GameLoop函数中有这么一句代码if( PeekMessage(&msg, 0, 0, 0, PM_REMOVE)){ … },在之前是使用if( PeekMessage(&msg, hWnd, 0, 0, PM_REMOVE)){ … },在退出窗口时,发现窗口关闭了,可是在后台进程中,却任然运行着。
而在窗口过程函数中,有对退出窗口进行处理,如下:

case WM_DESTROY:        PostQuitMessage(0);        break;case WM_CLOSE:        DestroyWindow(_hWnd);        break;

按道理来说,是能够正常退出的。于是我断点调试下,发现程序卡死在了循环的else里,而msg.message并没有获取到WM_QUIT这个消息,返回的是161(A1h)。

    while (msg.message != WM_QUIT)    {        //获取消息(peekMessage不等待,getMessage会等待)        if (PeekMessage(&msg, h_Wnd, 0, 0, PM_REMOVE))//**注意!!!这里peekMessage第二个参数如果为h_Wnd的话,会出现死循环。(原因暂时不明)        {            //翻译消息            TranslateMessage(&msg);            //分派消息            DispatchMessage(&msg);        }        else        {            //帧数控制            static float lastFlash = timeGetTime();            float currentFlash = timeGetTime();            float elapse = currentFlash - lastFlash;            if (elapse < 1000 / 100)                Sleep(1000 / 100 - elapse);            //游戏逻辑入口            g_myOpenGL->Render();            lastFlash = currentFlash;        }    }

但是改为这样if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))后,却发现问题解决了。但是原因不明,还望路过的老司机指点一二,感激不尽。