原文:http://blog.csdn.net/lingang_/article/details/3347463
最近在看徐明亮的<<opengl游戏编程>>,发觉这本书在国人的著作中尚属不错,在此先要感谢作者。
这个框摘自<<opengl游戏编程>>,我修改了部分代码,使之能在VS2005中顺利运行。
代码清单:
- //========================================================
- /**
- * @file GLWindows.h
- *
- * 项目描述: OpenGL程序框架演示
- * 文件描述: 程序窗口类
- * 适用平台: Windows98/2000/NT/XP
- *
- *
- */
- //========================================================
- #ifndef __GLWINDOW_H__
- #define __GLWINDOW_H__
- #include <windows.h> /**< 包含windows.h头文件 */
- #pragma warning(disable: 4311) /**< 禁止编译器出现类型转换的警告 */
- #pragma warning(disable: 4312)
- #pragma warning(disable: 4244)
- /** windows窗口类 */
- class GLWindow
- {
- public:
- /** 重要的窗口函数 */
- /** 构造函数 */
- GLWindow();
- /** 创建windows窗口 */
- bool Create(const char * window_title, const char * class_name, bool fullscreen,HINSTANCE h_instance, LPVOID lpParam);
- /** 删除OpenGL窗口 */
- void Destroy();
- /** 改变窗口的显示设置 */
- bool ChangeScreenSetting();
- /** 当窗口大小改变时,通知OpenGL调整大小 */
- void ReshapeGL();
- /** Swap Buffers (Double Buffering) */
- void SwapBuffers() { ::SwapBuffers(m_hDC); }
- /** 下面函数为设置/返回窗口类的属性 */
- /** 设置窗口左上角的位置 */
- void SetPosX(int x);
- void SetPosX(unsigned short x) { SetPosX((signed short)x); }
- void SetPosY(int y);
- void SetPosY(unsigned short y) { SetPosY((signed short)y); }
- /** 返回窗口的大小 */
- int GetWidth();
- int GetHeight();
- /** 设置窗口的大小 */
- void SetWidth(int width);
- void SetHeight(int height);
- /** 返回窗口左上角的位置 */
- int GetPosX();
- int GetPosY();
- /** 设置窗口的颜色位深 */
- void SetHiColor() { m_BitsPerPixel = 16; }
- void SetTrueColor() { m_BitsPerPixel = 32; }
- //void SetFullScreen(bool mode) { m_IsFullScreen = mode; }
- //bool GetFullScreen() { return m_IsFullScreen; }
- /** 重载运算符,可以让GL_Window m_Window声明后的m_Window作为窗口句柄使用 */
- operator HWND() { return m_hWnd; }
- private:
- HWND m_hWnd; /**< 窗口句柄 */
- HDC m_hDC; /**< 设备描述表 */
- HGLRC m_hRC; /**< OpenGL渲染描述表 */
- int m_WindowPosX; /**< 窗口的左上角的X位置 */
- int m_WindowPosY; /**< 窗口的左上角的Y位置 */
- int m_WindowWidth; /**< 窗口的宽度 */
- int m_WindowHeight; /**< 窗口的高度 */
- int m_ScreenWidth; /**< 全屏的宽度 */
- int m_ScreenHeight; /**< 全屏的高度 */
- int m_BitsPerPixel; /**< 颜色位深 */
- bool m_IsFullScreen; /**< 是否全屏 */
- };
- #endif // __GLWINDOW_H__
- //========================================================
- /**
- * @file GLWindows.h
- *
- * 项目描述: OpenGL程序框架演示
- * 文件描述: 程序窗口类
- * 适用平台: Windows98/2000/NT/XP
- *
- *
- */
- //========================================================
- #include "GLWindow.h" /**< 包含GLwindows.h头文件 */
- #include <gl/gl.h> /**< 包含OpenGL头文件 */
- #include <gl/glu.h>
- /** 构造函数 */
- GLWindow::GLWindow()
- {
- m_WindowPosX = 0; /**< 窗口的左上角的X位置 */
- m_WindowPosY = 0; /**< 窗口的左上角的Y位置 */
- m_WindowWidth = 640; /**< 窗口的宽度 */
- m_WindowHeight = 480; /**< 窗口的高度 */
- m_ScreenWidth = 1024; /**< 全屏的宽度 */
- m_ScreenHeight = 768; /**< 全屏的高度 */
- m_BitsPerPixel = 16; /**< 颜色位深 */
- m_IsFullScreen = false; /**< 不使用全屏 */
- m_hWnd = 0;
- m_hDC = 0;
- m_hRC = 0;
- }
- /** 返回窗口的大小 */
- int GLWindow::GetWidth()
- {
- if (m_IsFullScreen == true)
- {
- return m_ScreenWidth;
- }
- else
- {
- return m_WindowWidth;
- }
- }
- int GLWindow::GetHeight()
- {
- if (m_IsFullScreen == true)
- {
- return m_ScreenHeight;
- }
- else
- {
- return m_WindowHeight;
- }
- }
- /** 设置窗口的大小 */
- void GLWindow::SetWidth(int width)
- {
- if (m_IsFullScreen == true)
- {
- m_ScreenWidth = width;
- }
- else
- {
- m_WindowWidth = width;
- }
- }
- void GLWindow::SetHeight(int height)
- {
- if (m_IsFullScreen == true)
- {
- m_ScreenHeight = height;
- }
- else
- {
- m_WindowHeight = height;
- }
- }
- /** 返回窗口左上角的位置 */
- int GLWindow::GetPosX()
- {
- if (m_IsFullScreen == false)
- {
- return m_WindowPosX;
- }
- return 0;
- }
- int GLWindow::GetPosY()
- {
- if (m_IsFullScreen == false)
- {
- return m_WindowPosY;
- }
- return 0;
- }
- /** 设置窗口左上角的位置 */
- void GLWindow::SetPosX(int x)
- {
- if (m_IsFullScreen == false)
- {
- m_WindowPosX = x;
- }
- }
- void GLWindow::SetPosY(int y)
- {
- if (m_IsFullScreen == false)
- {
- m_WindowPosY = y;
- }
- }
- /** 当窗口大小改变时,通知OpenGL调整大小 */
- void GLWindow::ReshapeGL()
- {
- GLsizei width = GetWidth();
- GLsizei height = GetHeight();
- glViewport(0, 0, width, height); /**< 重新设置视口 */
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- gluPerspective(45.0f, (GLfloat)width / (GLfloat)height, 1.0f, 100.0f);
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
- }
- /** 改变窗口的显示设置 */
- bool GLWindow::ChangeScreenSetting()
- {
- DEVMODE dmScreenSettings; /**< 设备模式 */
- ZeroMemory(&dmScreenSettings, sizeof(DEVMODE)); /**< 清零结构 */
- dmScreenSettings.dmSize = sizeof(DEVMODE); /**< 结构大小 */
- dmScreenSettings.dmPelsWidth = GetWidth(); /**< 设置宽度 */
- dmScreenSettings.dmPelsHeight = GetHeight(); /**< 设置高度 */
- dmScreenSettings.dmBitsPerPel = m_BitsPerPixel; /**< 设置位深度 */
- //dmScreenSettings.dmDisplayFrequency = 75; /**< 设置屏幕刷新率 */
- dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT ;//| DM_DISPLAYFREQUENCY;
- /// 改变显示模式
- if (ChangeDisplaySettings(&dmScreenSettings, 0) != DISP_CHANGE_SUCCESSFUL)
- {
- return false; /**< 如果失败,返回false */
- }
- return true; /**< 成功返回 */
- }
- /** 创建windows窗口 */
- bool GLWindow::Create(const char * window_title,const char * class_name,bool fullscreen, HINSTANCE h_instance, LPVOID lpParam)
- {
- m_IsFullScreen = fullscreen;
- int nX=0;
- int nY=0;
- PIXELFORMATDESCRIPTOR pfd = /**< 设置像素描述结构 */
- {
- sizeof(PIXELFORMATDESCRIPTOR), /**< 像素描述结构的大小 */
- 1, /**< 版本号 */
- PFD_DRAW_TO_WINDOW | /**< 缓存区的输出显示在一个窗口中 */
- PFD_SUPPORT_OPENGL | /**< 缓存区支持OpenGL绘图 */
- PFD_STEREO | /**< 颜色缓存区是立体缓存 */
- PFD_DOUBLEBUFFER, /**< 颜色缓存区是双缓存 */
- PFD_TYPE_RGBA, /**< 使用RGBA颜色格式 */
- m_BitsPerPixel, /**< 颜色缓存区中颜色值所占的位深 */
- 0, 0, 0, 0, 0, 0, /**< 使用默认的颜色设置 */
- 0, /**< 无Alpha缓存 */
- 0, /**< 颜色缓存区中alpha成分的移位计数 */
- 0, /**< 无累计缓存区 */
- 0, 0, 0, 0, /**< 累计缓存区无移位 */
- 32, /**< 32位深度缓存 */
- 0, /**< 无蒙版缓存 */
- 0, /**< 无辅助缓存区 */
- PFD_MAIN_PLANE, /**< 必须为PFD_MAIN_PLANE,设置为主绘图层 */
- 0, /**< 表示OpenGL实现所支持的上层或下层平面的数量 */
- 0, 0, 0 /**< 过时,已不再使用 */
- };
- DWORD windowStyle = WS_OVERLAPPEDWINDOW & ~WS_SIZEBOX & ~WS_MAXIMIZEBOX; /**< 定义我们窗口类型,使用常规设定,去掉最大化按钮,并不能改变窗体大小 */
- DWORD windowExtendedStyle = WS_EX_APPWINDOW;
- if (m_IsFullScreen == true) /**< 如果为全屏模式,尝试转化为全屏模式 */
- {
- if (ChangeScreenSetting() == false)
- { /**< 全屏模式转换失败,弹出对话框提示,并尝试窗口模式 */
- MessageBoxA(HWND_DESKTOP, "模式转换失败./n在窗口模式下运行.", "Error", MB_OK | MB_ICONEXCLAMATION);
- m_IsFullScreen = false; /**< 设置为窗口模式 */
- }
- else /**< 如果为窗口模式 */
- {
- ShowCursor(false); /**< 隐藏鼠标 */
- windowStyle = WS_POPUP; /**< 设置窗口模式为顶层窗口 */
- windowExtendedStyle |= WS_EX_TOPMOST;
- }
- }
- /// 调整我们窗口的大小,使其客户区的大小为我们设置的大小
- RECT windowRect = {GetPosX(), GetPosY(), GetPosX() + GetWidth(), GetPosY() + GetHeight()};
- if (m_IsFullScreen == false) /**< 在窗口模式下使用 */
- {
- windowExtendedStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; /**< 使窗口具有3D外观 */
- int wid = GetSystemMetrics(SM_CXSCREEN); /**< 获取当前屏幕宽 */
- int hei = GetSystemMetrics(SM_CYSCREEN); /**< 获取当前屏幕高 */
- nX = (wid - GetWidth()) / 2; /**< 计算窗口居中用 */
- nY = (hei - GetHeight()) / 2;
- /// 调整我们窗口的大小,使其客户区的大小为我们设置的大小
- AdjustWindowRectEx(&windowRect, windowStyle, 0, windowExtendedStyle);
- /// 判断窗口的左上角是否隐藏在桌面外
- if (windowRect.left < 0) /**< 如果窗口X坐标为负,移动坐标到0处,并调整窗口的位置 */
- {
- windowRect.right -= windowRect.left;
- windowRect.left = 0;
- }
- if (windowRect.top < 0) /**< 如果窗口Y坐标为负,移动坐标到0处,并调整窗口的位置 */
- {
- windowRect.bottom -= windowRect.top;
- windowRect.top = 0;
- }
- }
- /// 创建窗口
- m_hWnd = CreateWindowExA(windowExtendedStyle, /**< 窗口的扩展风格 */
- class_name, /**< 窗口的类名 */
- window_title, /**< 窗口标题 */
- windowStyle, /**< 窗口的风格 */
- nX,nY, /**< 窗口的左上角位置 */
- windowRect.right - windowRect.left, /**< 窗口的宽度 */
- windowRect.bottom - windowRect.top, /**< 窗口的高度 */
- HWND_DESKTOP, /**< 窗口的父窗口为桌面 */
- 0, /**< 无菜单 */
- h_instance, /**< 传入窗口的实例句柄 */
- lpParam); /**< 传入程序类参数 */
- while (m_hWnd != 0) /**< 窗口是否创建成功 */
- {
- m_hDC = GetDC(m_hWnd); /**< 返回窗口的设备描述表 */
- if (m_hDC == 0) /**< 如果为空 */
- { /**< 失败 */
- break;
- }
- GLuint PixelFormat = ChoosePixelFormat(m_hDC, &pfd); /**< 查找一个兼容的像素格式 */
- if (PixelFormat == 0) /**< 如果没找到 */
- { /**< 失败 */
- break;
- }
- if (SetPixelFormat(m_hDC, PixelFormat, &pfd) == false) /**< 设置像素格式 */
- { /**< 失败 */
- break;
- }
- m_hRC = wglCreateContext(m_hDC); /**< 创建OpenGL的渲染描述表 */
- if (m_hRC == 0) /**< 如果为空 */
- { /**< 失败 */
- break;
- }
- if (wglMakeCurrent(m_hDC, m_hRC) == false) /**< 设置当前的OpenGL的渲染对象为当前的窗口 */
- { /**< 失败 */
- break;
- }
- ShowWindow(m_hWnd, SW_NORMAL); /**< 显示窗口 */
- ReshapeGL(); /**< 告诉OpenGL调整窗口大小 */
- return true; /**< 成功返回 */
- }
- Destroy(); /**< 释放资源 */
- return false; /**< 返回失败 */
- }
- /** 删除OpenGL窗口 */
- void GLWindow::Destroy()
- {
- if (m_hWnd != 0) /**< 窗口句柄是否存在 */
- {
- if (m_hDC != 0) /**< 窗口设备描述表是否存在 */
- {
- wglMakeCurrent(m_hDC, 0); /**< 设置当前的OpenGL的渲染对象为空NULL */
- if (m_hRC != 0) /**< OpenGL的渲染描述表是否存在 */
- {
- wglDeleteContext(m_hRC); /**< 释放OpenGL的渲染描述表 */
- m_hRC = 0; /**< 设置OpenGL的渲染描述表为0 */
- }
- ReleaseDC(m_hWnd, m_hDC); /**< 释放窗口的设备描述表 */
- m_hDC = 0; /**< 设置窗口的设备描述表为0 */
- }
- DestroyWindow(m_hWnd); /**< 删除窗口 */
- m_hWnd = 0; /**< 设置窗口句柄为0 */
- }
- if (m_IsFullScreen) /**< 如果为全屏模式,在程序结束后,变换到窗口模式,并显示鼠标 */
- {
- ChangeDisplaySettings(NULL, 0); /**< 变换到窗口模式 */
- ShowCursor(true); /**< 显示鼠标 */
- }
- }
- //======================================================================
- /**
- * @file Framework.h
- *
- * 项目描述: OpenGL程序框架演示
- * 文件描述: 键盘类和程序框架类
- * 适用平台: Windows98/2000/NT/XP
- *
- * 你必须在你的继承类中完成以下函数的实现
- *
- * GLApplication * GLApplication::Create(const char * class_name)
- * 创建你的子类的一个实例
- *
- * bool Init();
- * 执行所有的初始化工作,如果成功函数返回true
- *
- * void Uninit();
- * 执行所有的卸载工作
- *
- * void Update(DWORD milliseconds);
- * 执行所有的更新操作,传入的参数为两次操作经过的时间,以毫秒为单位
- *
- * void Draw();
- * 执行所有的绘制操作
- */
- //======================================================================
- #ifndef __GLFRAME_H__
- #define __GLFRAME_H__
- #include "GLWindow.h" /**< 包含GLWindow.h头文件 */
- /** 定义键盘类 */
- class Keys
- {
- public:
- /** 构造函数 */
- Keys() { Clear(); }
- /** 清空所有的按键信息 */
- void Clear() { ZeroMemory(&m_KeyDown, sizeof(m_KeyDown)); }
- /** 判断某个键是否按下 */
- bool IsPressed(unsigned int key) { return (key < MAX_KEYS) ? (m_KeyDown[key] == true) : false; }
- /** 设置某个键被按下 */
- void SetPressed(unsigned int key) { if (key < MAX_KEYS) m_KeyDown[key] = true; }
- /** 设置某个键被释放 */
- void SetReleased(unsigned int key) { if (key < MAX_KEYS) m_KeyDown[key] = false; }
- private:
- static const unsigned int MAX_KEYS = 256;
- bool m_KeyDown[MAX_KEYS]; /**< 保存256个按键的状态 */
- };
- /** 基本的程序类,继承它用来创建OpenGL程序 */
- class GLApplication
- {
- public:
- /** 创建一个全局的Create函数,这个函数必须被继承类实现 */
- static GLApplication * Create(const char * class_name); /**< 创建你自己的子类 */
- /** 虚析构函数 */
- virtual ~GLApplication() {};
- protected:
- /** 下面的函数必须被继承类实现,完成基本的OpenGL渲染过程 */
- virtual bool Init() = 0; /**< OpenGL的初始化 */
- virtual void Uninit() = 0; /**< OpenGL的卸载 */
- virtual void Update(DWORD milliseconds) = 0; /**< 执行OpenGL程序的更新 */
- virtual void Draw() = 0; /**< 绘制OpenGL场景 */
- /** 通用的函数 */
- void ToggleFullscreen(); /**< 切换 全屏/窗口模式 */
- void TerminateApplication(); /**< 结束程序 */
- void ResizeDraw(bool enable) { m_ResizeDraw = enable; } /**< 设置在窗口改变大小的时候,可以绘制 */
- Keys m_Keys; /**< 按键类 */
- /** 构造函数 */
- GLApplication(const char * class_name);
- private:
- /** 程序的主循环 */
- friend int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow);
- int Main(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow);
- /** 消息处理回调函数 */
- friend LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
- LRESULT Message(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
- static const UINT WM_TOGGLEFULLSCREEN = (WM_USER + 1); /**< 自定义消息,在切换窗口模式的时候发送 */
- GLWindow m_Window; /**< Window类 */
- const char* m_ClassName; /**< 程序名 */
- bool m_IsProgramLooping; /**< 程序循环标记,如果为false,则退出程序 */
- bool m_CreateFullScreen; /**< 若为true,则创建全屏模式 */
- bool m_IsVisible; /**< 窗口是否可见 */
- bool m_ResizeDraw; /**< 是否在改变大小时,调用绘制函数 */
- DWORD m_LastTickCount; /**< 上一次计时器的值 */
- };
- #endif // __GLFRAMEWORK_H__
- //======================================================================
- /**
- * @file Framework.cpp
- *
- * 项目描述: OpenGL程序框架演示
- * 文件描述: 键盘类和程序框架类
- * 适用平台: Windows98/2000/NT/XP
- *
- *
- * 你必须在你的继承类中完成以下函数的实现
- *
- * GLApplication * GLApplication::Create(const char * class_name)
- * 创建你的子类的一个实例
- *
- * bool Init();
- * 执行所有的初始化工作,如果成功函数返回true
- *
- * void Uninit();
- * 执行所有的卸载工作
- *
- * void Update(DWORD milliseconds);
- * 执行所有的更新操作,传入的参数为两次操作经过的时间,以毫秒为单位
- *
- * void Draw();
- * 执行所有的绘制操作
- */
- //======================================================================
- #include "GLFrame.h" /**< 包含Framework.h头文件 */
- //#include "ScreenDlg.h" /**< 包含ScreenDlg.h头文件 */
- #include <gl/gl.h> /**< 包含OpenGL头文件 */
- #include <gl/glu.h>
- /** 主程序入口 */
- int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
- {
- int ret = -1;
- GLApplication * appl = GLApplication::Create("OpenGL"); /**< 创建程序类 */
- if (appl != 0)
- {
- ret = appl->Main(hInstance, hPrevInstance, lpCmdLine, nCmdShow);/**< 执行程序主循环 */
- delete appl; /**< 删除程序类(在继承类中,使用GL_Example * example = new GL_Example(class_name);分配了一块内存)*/
- }
- else
- { /**< 创建程序出错 */
- MessageBoxA(HWND_DESKTOP, "创建程序出错", "Error", MB_OK | MB_ICONEXCLAMATION);
- }
- return ret;
- }
- /** 处理窗口消息 */
- LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
- {
- LONG user_data = GetWindowLong(hWnd, GWL_USERDATA); /**< 返回用户自定义的32位的程序附加值 */
- if (user_data == 0)
- {
- /// 如果程序第一次运行
- if (uMsg == WM_CREATE) /**< 处理窗口创建消息 */
- {
- /// 返回窗口结构的指针,它保存刚创建的程序实例的类
- CREATESTRUCT * creation = reinterpret_cast<CREATESTRUCT *>(lParam);
- /// 获得程序实例的指针
- GLApplication * appl = reinterpret_cast<GLApplication *>(creation->lpCreateParams);
- /// 保存程序实例的指针为用户自定义的程序附加值
- SetWindowLong(hWnd, GWL_USERDATA, reinterpret_cast<LONG>(appl));
- appl->m_IsVisible = true; /**< 设置程序可见 */
- return 0; /**< 返回 */
- }
- }
- else
- { /// 如果不是第一次窗口,返回程序实例的指针
- GLApplication * appl = reinterpret_cast<GLApplication *>(user_data);
- return appl->Message(hWnd, uMsg, wParam, lParam); /**< 调用程序实例自己的消息处理函数 */
- }
- return DefWindowProc(hWnd, uMsg, wParam, lParam); /**< 调用默认的窗口消息处理函数 */
- }
- /** 构造函数 */
- GLApplication::GLApplication(const char * class_name)
- {
- m_ClassName = class_name; /**< 保存类名 */
- m_IsProgramLooping = true; /**< 设置程序循环为true */
- m_CreateFullScreen = true; /**< 使用全屏模式 */
- m_IsVisible = false; /**< 不可见 */
- m_ResizeDraw = false; /**< 在窗口改变大小的时候,不可绘制 */
- m_LastTickCount = 0;
- }
- void GLApplication::ToggleFullscreen() /**< 切换 全屏/窗口模式 */
- {
- PostMessage(m_Window, WM_TOGGLEFULLSCREEN, 0, 0); /**< 发送自定的切换消息 */
- }
- void GLApplication::TerminateApplication() /**< 结束程序 */
- {
- PostMessage(m_Window, WM_QUIT, 0, 0); /**< 发送退出消息 */
- m_IsProgramLooping = false; /**< 停止程序循环 */
- }
- /** 消息循环 */
- LRESULT GLApplication::Message(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
- {
- switch (uMsg) /**< 处理不同的Windows消息 */
- {
- case WM_SYSCOMMAND: /**< 截获系统命令 */
- switch (wParam)
- {
- case SC_SCREENSAVE: /**< 截获屏幕保护启动命令 */
- case SC_MONITORPOWER: /**< 截获显示其省电模式启动命令 */
- return 0; /**< 不启用这两个命令 */
- break;
- }
- break; /**< 退出 */
- case WM_CLOSE: /**< 关闭窗口 */
- TerminateApplication(); /**< 调用TerminateApplication函数 */
- return 0;
- break;
- case WM_EXITMENULOOP:
- case WM_EXITSIZEMOVE:
- m_LastTickCount = GetTickCount(); /**< 更新计数器的值 */
- return 0;
- break;
- case WM_MOVE:
- m_Window.SetPosX(LOWORD(lParam)); /**< 更新鼠标的坐标 */
- m_Window.SetPosY(HIWORD(lParam));
- return 0;
- break;
- case WM_PAINT:
- if (m_ResizeDraw == true) /**< 如果需要重绘 */
- {
- m_Window.ReshapeGL(); /**< 重新设置窗口的大小 */
- Draw(); /**< 重新绘制 */
- m_Window.SwapBuffers(); /**< 交换前后帧缓存 */
- }
- break;
- case WM_SIZING: /**< 窗口正在改变大小 */
- {
- RECT * rect = (RECT *)lParam;
- m_Window.SetWidth(rect->right - rect->left); /**< 设置窗口宽度 */
- m_Window.SetHeight(rect->bottom - rect->top); /**< 设置窗口高度 */
- return TRUE;
- }
- break;
- case WM_SIZE: /**< 窗口改变大小后 */
- switch (wParam) /**< 处理不同的窗口状态 */
- {
- case SIZE_MINIMIZED: /**< 是否最小化? */
- m_IsVisible = false; /**< 如果是,则设置不可见 */
- return 0;
- break;
- case SIZE_MAXIMIZED: /**< 窗口是否最大化? */
- case SIZE_RESTORED: /**< 窗口被还原? */
- m_IsVisible = true; /**< 设置为可见 */
- m_Window.SetWidth(LOWORD(lParam)); /**< 设置窗口宽度 */
- m_Window.SetHeight(HIWORD(lParam)); /**< 设置窗口高度 */
- m_Window.ReshapeGL(); /**< 改变窗口大小 */
- m_LastTickCount = GetTickCount(); /**< 更新计数器的值 */
- return 0;
- break;
- }
- break;
- case WM_KEYDOWN: /**< 更新按键信息 */
- m_Keys.SetPressed(wParam);
- return 0;
- break;
- case WM_KEYUP: /**< 更新释放键信息 */
- m_Keys.SetReleased(wParam);
- return 0;
- break;
- case WM_TOGGLEFULLSCREEN: /**< 切换 全屏/窗口模式 */
- /* m_Window.SetFullScreen(!m_Window.GetFullScreen());
- if(!m_Window.GetFullScreen())
- ShowCursor(true);
- else
- ShowCursor(false);*/
- m_CreateFullScreen = !m_CreateFullScreen;
- PostMessage(hWnd, WM_QUIT, 0, 0);
- break;
- }
- return DefWindowProc(hWnd, uMsg, wParam, lParam); /**< 调用默认的窗口消息处理函数 */
- }
- /** 程序的主循环 */
- int GLApplication::Main(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
- {
- /// 注册一个窗口
- WNDCLASSEX windowClass; /**< 窗口类 */
- ZeroMemory(&windowClass, sizeof(WNDCLASSEX)); /**< 清空结构为0 */
- windowClass.cbSize = sizeof(WNDCLASSEX); /**< 窗口结构的大小 */
- windowClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; /**< 设置窗口类型为,移动时重画,并为窗口取得DC */
- windowClass.lpfnWndProc = (WNDPROC)(WindowProc); /**< WndProc处理消息 */
- windowClass.hInstance = hInstance; /**< 设置实例 */
- windowClass.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE); /**< 设置背景 */
- windowClass.hCursor = LoadCursor(NULL, IDC_ARROW); /**< 载入光标 */
- windowClass.lpszClassName = m_ClassName; /**< 设置类名 */
- if (RegisterClassEx(&windowClass) == 0) /**< 尝试注册窗口类 */
- { /**< NOTE: Failure, Should Never Happen */
- MessageBoxA(HWND_DESKTOP, "注册窗口失败!", "Error", MB_OK | MB_ICONEXCLAMATION);
- return -1; /**< 退出并返回FALSE */
- }
- // 询问是否在全屏状态下运行?
- if (MessageBoxA(HWND_DESKTOP, "你想在全屏状态下运行么 ?", "是否全屏运行?", MB_YESNO | MB_ICONQUESTION) == IDNO)
- {
- m_CreateFullScreen = false; /**< m_CreateFullScreen记录当前的显示模式为窗口 */
- }
- //ScreenDlg sd;
- //sd.SetupWindow(&m_Window);
- //m_CreateFullScreen = m_Window.GetFullScreen();
- while (m_IsProgramLooping) /**< 循环直道WM_QUIT退出程序 */
- {
- /// 创建一个窗口
- if (m_Window.Create("OpenGL 3D游戏编程——框架", m_ClassName,m_CreateFullScreen, hInstance, this) == true)
- {
- /// 如果初始化失败,则退出
- if (Init() == false) /**< 调用自定义的初始化函数 */
- { /**< 失败 */
- TerminateApplication(); /**< 关闭窗口退出程序 */
- }
- else /**< 成功开始消息循环 */
- {
- MSG msg; /**< Window消息结构 */
- bool isMessagePumpActive = true; /**< 当消息不为空时,处理消息循环 */
- m_LastTickCount = GetTickCount(); /**< 返回当前的计时器的值 */
- m_Keys.Clear(); /**< 清空所有的按键信息 */
- while (isMessagePumpActive == true) /**< 当消息不为空时,处理消息循环 */
- { /**< 成功创建窗口,检测窗口消息 */
- if (PeekMessage(&msg, m_Window, 0, 0, PM_REMOVE) != 0)
- {
- /// 检测是否为WM_QUIT消息
- if (msg.message != WM_QUIT)
- {
- DispatchMessage(&msg); /**< 如果不是发送消息到消息回调函数中处理 */
- }
- else
- {
- isMessagePumpActive = false; /**< 如果是,则退出 */
- }
- }
- /// 如果没有消息
- else
- {
- if (m_IsVisible == false) /**< 如果窗口不可见 */
- {
- WaitMessage(); /**< 暂停程序,等待消息 */
- }
- else /**< 如果窗口可见 */
- { /**< 执行消息循环 */
- DWORD tickCount = GetTickCount(); /**< 返回计时器的当前值 */
- Update(tickCount - m_LastTickCount); /**< 调用用户自定义的更新函数 */
- m_LastTickCount = tickCount; /**< 重新设置上一次,计数器的值 */
- Draw(); /**< 调用用户自定义的绘制函数 */
- m_Window.SwapBuffers(); /**< 交换前后帧缓存 */
- }
- }
- } /**< 如果isMessagePumpActive == true,则循环 */
- }
- /**< 程序结束 */
- Uninit(); /**< 用户自定义的卸载函数 */
- m_Window.Destroy(); /**< 删除窗口 */
- }
- else /**< 如果创建窗口失败 */
- {
- MessageBoxA(HWND_DESKTOP, "创建OpenGL窗口错误", "Error", MB_OK | MB_ICONEXCLAMATION);
- m_IsProgramLooping = false; /**< 停止程序循环 */
- }
- }
- UnregisterClassA(m_ClassName, hInstance); /**< 取消注册的窗口 */
- return 0;
- }
附上实例程序:
- //=========================================================================
- /**
- * @file Example.h
- *
- * 项目描述: OpenGL程序框架演示
- * 文件描述: 具体实例类
- * 适用平台: Windows98/2000/NT/XP
- *
- *
- * 在这个类中您必须重载如下几个虚函数
- *
- * virtual bool Init();
- * 执行所有的初始化工作,如果成功函数返回true
- *
- * virtual void Uninit();
- * 执行所有的卸载工作
- *
- * virtual void Update(DWORD milliseconds);
- * 执行所有的更新操作,传入的参数为两次操作经过的时间,以毫秒为单位
- *
- * virtual void Draw();
- * 执行所有的绘制操作
- */
- //=========================================================================
- #ifndef __EXAMPLE_H__
- #define __EXAMPLE_H__
- #include "GLFrame.h" /**< 包含基本的框架类 */
- /** 从GL_Application派生出一个子类 */
- class Example : GLApplication
- {
- public:
- bool Init(); /**< 执行所有的初始化工作,如果成功函数返回true */
- void Uninit(); /**< 执行所有的卸载工作 */
- void Update(DWORD milliseconds); /**< 执行所有的更新操作,传入的参数为两次操作经过的时间,以毫秒为单位 */
- void Draw(); /**< 执行所有的绘制操作 */
- private:
- friend class GLApplication; /**< 父类为它的一个友元类,可以用来创建程序的实例,见函数GL_Application * GL_Application::Create(const char * class_name) */
- Example(const char * class_name); /**< 构造函数 */
- /** 用户自定义的程序变量 */
- float m_Angle; /**< 使用它来旋转三角形 */
- };
- #endif // __EXAMPLE_H__
- //=========================================================================
- /**
- * @file Example.cpp
- *
- * 项目描述: OpenGL程序框架演示
- * 文件描述: 具体实例类
- * 适用平台: Windows98/2000/NT/XP
- *
- *
- * 在这个类中您必须重载如下几个虚函数
- *
- * virtual bool Init();
- * 执行所有的初始化工作,如果成功函数返回true
- *
- * virtual void Uninit();
- * 执行所有的卸载工作
- *
- * virtual void Update(DWORD milliseconds);
- * 执行所有的更新操作,传入的参数为两次操作经过的时间,以毫秒为单位
- *
- * virtual void Draw();
- * 执行所有的绘制操作
- */
- //=========================================================================
- #include "Example.h" /**< 包含头文件 */
- #include <gl/gl.h> /**< 包含OpenGL头文件 */
- #include <gl/glu.h>
- #include <gl/glaux.h>
- #pragma comment(lib, "opengl32.lib") /**< 包含OpenGL链接库文件 */
- #pragma comment(lib, "glu32.lib")
- #pragma comment(lib, "glaux.lib")
- /** 创建一个程序的实例 */
- GLApplication * GLApplication::Create(const char * class_name)
- {
- Example * example = new Example(class_name);
- return reinterpret_cast<GLApplication *>(example);
- }
- /** 构造函数 */
- Example::Example(const char * class_name) : GLApplication(class_name)
- {
- /// 初始化用户自定义的程序变量
- m_Angle = 0.0f; /**< 设置初始角度为0 */
- }
- /** 初始化OpenGL */
- bool Example::Init()
- {
- /** 用户自定义的初始化过程 */
- glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
- glClearDepth(1.0f);
- glDepthFunc(GL_LEQUAL);
- glEnable(GL_DEPTH_TEST);
- glShadeModel(GL_SMOOTH);
- glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
- ResizeDraw(true); /**< 改变OpenGL窗口大小,直接调用子类的函数 */
- return true; /**< 成功返回 */
- }
- /** 用户自定义的卸载函数 */
- void Example::Uninit()
- {
- /** 用户自定义的卸载过程 */
- ///......
- ///......
- }
- /** 程序更新函数 */
- void Example::Update(DWORD milliseconds)
- {
- if (m_Keys.IsPressed(VK_ESCAPE) == true) /**< 按ESC退出 */
- {
- TerminateApplication();
- }
- if (m_Keys.IsPressed(VK_F1) == true) /**< 按F1切换窗口/全屏模式 */
- {
- ToggleFullscreen();
- }
- /** 用户自定义的更新过程 */
- m_Angle += (float)(milliseconds) / 15.0f; /**< 更新旋转的角度 */
- }
- /** 绘制函数 */
- void Example::Draw()
- {
- /** 用户自定义的绘制过程 */
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- glLoadIdentity();
- glTranslatef(0.0f, 0.0f, -6.0f);
- glRotatef(m_Angle, 0.0f, 1.0f, 0.0f);
- glRotatef(m_Angle * 0.7f, -1.0f, 0.0f, 0.0f);
- for (int rot1 = 0; rot1 < 2; rot1++) /**< 绘制四个交错的三角形(想的很巧妙啊)*/
- {
- glRotatef(90.0f, 0.0f, 1.0f, 0.0f);
- glRotatef(180.0f, 1.0f, 0.0f, 0.0f);
- for (int rot2 = 0; rot2 < 2; rot2++)
- {
- glRotatef(180.0f, 0.0f, 1.0f, 0.0f);
- glBegin(GL_TRIANGLES);
- glColor3f(1.f, 0.f, 0.f); glVertex3f( 0.0f, 1.0f, 0.0f);
- glColor3f(0.f, 1.f, 0.f); glVertex3f(-1.0f, -1.0f, 1.0f);
- glColor3f(0.f, 0.f, 1.f); glVertex3f( 1.0f, -1.0f, 1.0f);
- glEnd();
- }
- }
- glFlush(); /**< 强制执行所有的OpenGL命令 */
- }
注意的几点是:
1.在VS2005中建立项目时,须先建立控制台应用程序,再点选空项目,否则调试时会跑到 crt0.c 程序中。
2.需要将相应库文件放在源文件同一目录下。
3.配置属性->常规->字符集 中点选使用多字节字符集,否则若使用Unicode字符集,一些windows函数调用会出错。
4.配置属性->调试->生成调试信息 点选(是/Debug).
5.配置属性->清单工具->常规->使用FAT32解决办法 点选是。