50 个 OpenGL Win32 项目合集






4.91/5 (28投票s)
前 NeHe OpenGL 课程改编为 MSVS-15 pro Win32 的 INICODE 和操纵杆实现示例
引言
本文是上个月发表的一篇文章的续篇,名称几乎相同,只是替换了一个关键词。但这是一个具有根本重要性的替换。将 MFC 替换为 Win32 意味着代码发生了巨大变化。许多人更喜欢 Win32 代码。
本文旨在展示一些古老的、20年前的项目在现代 MSVS-15 Win32 和 Windows-10 环境中运行的示例。
背景
提供的示例项目基于 NeHe 的旧版48课项目。三年前,我已经完成了将上述课程改编到 MSVS-10 pro Win32 的工作。我逐一将代码“原样”翻译成 MBCS 编码。目前,建议使用 UNICODE 编码,这项工作似乎并未完全执行。而且没有必要为每节课都开发一个项目。流程图方案对所有OpenGL项目都是通用的,因此,值得为所有课程开发一个通用项目用于演示目的。
现在,我有时间介绍这个针对 MSVS-15 pro Win32 的 UNICODE 编码解决方案,其中包含一些 操纵杆 实现的示例以及我之前 CodeProject 文章的使用示例。
在开始构建提供的项目之前,强烈建议您查看随附的 演示文稿,以了解预期的输出。
1. 演示说明
1.1. 可执行文件处理
WIN_GLdemo 目录中的可执行文件 WIN_GL.exe 是使用 MSVS-2015 pro 和 MSVS-2010 工具构建的。因此,WIN_GL.exe 甚至适用于 Windows-XP。与上一篇文章不同,演示性能不需要特殊的 *.dll 文件。
WIN_GL.exe 可以不带任何参数启动。在这种情况下,将显示上次调用的课程演示。
WIN_GL.exe XX 可以在命令行中以以下两个符号参数启动:01-48、X4、X5。在这种情况下,将显示相应的课程演示。
此处及其他地方,XX 表示两个符号字符串:(01-48)- NeHe 教程中课程的顺序号,(X4,X5)- 作者在 俄罗斯NeHe 网站上发布的课程号。
WIN_GL.exe 的控制如下:
- 菜单 文件->课程... - 调用 选择课程对话框(也可通过键盘 Ctrl+O)
- 菜单 文件->播放 - 播放/停止当前课程演示(也可通过键盘 Ctrl+P)
- 最近文件 - 调用 选择课程对话框,其中列表框行选中了相应的最近调用课程。
- 菜单 文件->退出 - 退出应用程序(也可通过键盘 Alt+F4(立即退出)或键盘 Esc(需要确认))
- 菜单 视图->全屏 - 安装/卸载当前课程的全屏性能(也可通过键盘 Ctrl+Enter)
- 菜单 视图->语言->俄语 - 将课程标题调整为俄语
- 菜单 视图->语言->英语 - 将课程标题调整为英语
- 菜单 视图->工具栏 - 显示/隐藏工具栏(也可通过键盘 Ctrl+T)
- 菜单 视图->状态栏 - 显示/隐藏状态栏(也可通过键盘 Ctrl+S)
- 菜单 视图->下一场景 - 如果停止,则为当前课程演示的下一场景(也可通过键盘 Ctrl+N)
- 菜单 视图->操纵杆测试 - 如果适用,则调用 操纵杆测试对话框(课程 09, 10, 32, 40, X4, X5)(也可通过键盘 Ctrl+J)
- 菜单 帮助->关于... - 调用 关于对话框(也可通过键盘 Ctrl+A)
- 菜单 帮助->帮助对话框... - 调用 帮助对话框(也可通过键盘 F1)
- 菜单 帮助->操纵杆帮助.. - 如果适用,则调用 操纵杆帮助对话框(课程 09, 10, 32, 40, X4, X5)(也可通过键盘 Ctrl + Y)
一旦 WIN_GL.exe 启动,您可以从通过菜单命令 文件->打开...(或键盘 Ctrl + O)弹出的 对话框 中的 课程列表 中选择任何其他课程演示开始。
请注意,最近文件系统 是标准 MS VS 的替代方案,基于我的 CodeProject 文章“你自己的最近文件列表”。目前,本项目的特殊类 ClassWinResent
已为 Win32 平台开发。
1.2. 课程选择对话框
通过 菜单 文件->课程... 命令(也可通过键盘 Ctrl+O)调用 课程选择对话框。
课程选择对话框 的控件如下:
- 列表框控件:显示可用课程名称列表
- 确定按钮:启动在 列表框控件 中选定的课程(也可通过双击鼠标左键在相应的 列表框控件 行上)
- 新窗口复选框:如果选中,新课程演示在新窗口中启动(当前课程保持不变);否则,新课程在与当前课程相同的窗口中启动。
- 英语单选按钮:将课程标题调整为英语
- 俄语单选按钮:将课程标题调整为俄语
- 取消按钮:仅关闭对话框
1.3. 帮助使用
通过 菜单 帮助->帮助对话框 命令(或键盘 F1)调用 帮助对话框。大多数键盘和鼠标命令与 NeHe 网站上原始课程的相应命令保持相同。
帮助对话框 的控件如下:
- 列表框控件:显示当前课程演示可用的键盘和/或鼠标命令列表
- 确定按钮:执行在 列表框控件 的控制列中选定的命令(也可双击鼠标左键在相应的 列表框控件 行上)
- 操纵杆帮助按钮:如果适用,则调用 操纵杆帮助对话框(课程 09, 10, 32, 40, X4, X5)
帮助对话框 是非模态的,因此既可以使用列出的键盘命令,也可以从 列表控件 中选择命令并按下 确定按钮(或双击鼠标左键)。
1.4. 关于对话框
为了尊重原始代码的作者,关于对话框(菜单 帮助->关于...)包含 原始NeHe的ReadMe 文本。
1.5. 操纵杆使用
操纵杆在课程 09, 10, 32, 40, X4, X5 中可用。您可以根据随附的 操纵杆 实现说明,自行将 操纵杆 调整到任何其他课程(或您自己的某些项目中)。
操纵杆功能可以通过 菜单 视图->操纵杆测试 命令(或键盘 Ctrl+J 或 操纵杆本身上的按钮8)与 操纵杆测试对话框(如果适用)进行测试。
操纵杆测试对话框 的控件如下:
- 1-12 复选框:检查相应的 操纵杆 按钮是否按下
- 未编号复选框:检查相应的 操纵杆 帽子 按钮是否按下
- 左侧图片控件:显示用于左右弯曲 操纵杆 手柄和前后弯曲的十字位置坐标。
- 右侧图片控件:显示用于左右转动 操纵杆 手柄和前后切换 操纵杆 加速的十字位置坐标。
- 开关单选按钮:显示 操纵杆 连接状态
当 操纵杆测试对话框 可见时,所有 操纵杆命令 仅对该对话框有效,对应用程序本身,操纵杆命令 不可用。
请注意,操纵杆测试对话框 是基于我的 CodeProject 文章“操纵杆Win32和MFC项目”,只是移除了 图片控件。
受影响课程的 操纵杆 帮助可通过 菜单 帮助->操纵杆帮助对话框 命令(或键盘 Ctrl+Y 或 帮助对话框 中的 操纵杆帮助按钮)与 操纵杆帮助对话框(如果适用)获取。
操纵杆帮助对话框 是非模态的,因此既可以使用列出的 操纵杆 命令,也可以从列表中选择命令并按下 确定按钮(或双击鼠标左键在相应的行上)。
2. 重要的构建注意事项。
在您使用文件 WIN_GLproj\WIN_GLproj\WIN_GLproj.sln 通过菜单 项目->构建解决方案 开始构建所有项目之前,请考虑一些重要的注意事项。
解决方案配置必须设置为 Release,平台为 X86。
默认编码属性为 UNICODE;尽管 MBCS 编码也可用,只需更改属性即可。
请注意,解决方案 WIN_GLproj\WIN_GLproj\WIN_GLproj.sln 由三个类似的项目组成,它们仅在构建复杂性程度上有所不同。
WIN_GL0
- 最简单的项目,可由没有任何 MSVS 编码经验的人构建;此项目不包含 操纵杆 和课程 43 和 47。WIN_GL1
- 此解决方案在构建前需要进行一些 属性框 设置;此解决方案包含 操纵杆,但不包含课程 43 和 47。WIN_GL
- 完整的解决方案在构建前需要安装一些 外部库;此解决方案的 WIN_GL.exe 结果在提供的 WIN_GLdemo 目录中。
即使您是第一次使用 MSVS,只需将 WIN_GL0
项目指定为 启动项目(右键单击鼠标 -> 菜单 设为启动项目),然后选择菜单 调试->启动不调试,程序 WIN_GL0.exe 应该会开始构建并运行。
2.1. 操纵杆构建注意事项(项目 WIN_GL1 和 WIN_GL)
所提供的项目是使用 MSVS-2015 pro 和 MSVS-2010 工具开发的。因此,生成的可执行文件甚至适用于 Windows-XP。
如果您不再需要在 Windows-XP 中运行应用程序,只需将工具更改为 MSVS-2015,就不会出现 操纵杆 程序构建问题。
使用 MSVS-2010 工具实现 操纵杆 可能会出现问题。问题在于使用了外部库 hid.lib。
在您使用 MSVS-2010 工具开始构建 WIN_GL1
项目之前,必须确保相关项目中的三件事:
- 在 项目属性框 的 配置属性->VC++目录->包含目录中,选择 更改 命令并将目录设置为 ..\Windows Kits\8.1\Include\shared(仅用于
#include <hidsdi.h>
命令) - 在 项目属性框 的 配置属性->VC++目录->库目录中,选择 更改 命令并将目录设置为 ..\Windows Kits\8.1\Lib\winv6.3\um\x86
- 在 项目属性框 的 链接器->输入->附加依赖项中,选择 更改 命令并安装 hid.lib(或者您可以通过菜单 项目->添加现有项 直接从目录 ..\Windows Kits\8.1\Lib\winv6.3\um\x86\hid.lib 插入库 hid.lib)。
2.2. 课程43和47构建注意事项(项目 WIN_GL)
第43课 需要外部库 freetype.lib,这需要从 http://gnuwin32.sourceforge.net/packages/freetype.htm 链接安装 Program Files\GnuWin32 目录(17.8 Mb)。
在您开始构建包含课程 43 的 WIN_GL
项目之前,必须确保相关项目中的四件事:
- 在 项目属性框 的 配置属性->VC++目录->包含目录中,选择 更改 命令并将目录设置为 ..\GnuWin32\include\freetype2
- 在 项目属性框 的 配置属性->VC++目录->库目录中,选择 更改 命令并将目录设置为 ..\GnuWin32\lib
- 在 项目属性框 的 链接器->输入->附加依赖项中,选择 更改 命令并安装 freetype.lib。
- 在应用程序的根目录中,需要插入 FreeType6.dll 和 zlib.dll 文件。
第47课 需要外部库 cg.dll 和 cgGL.dll,这需要从 https://developer.nvidia.com/cg-toolkit-download 链接安装 Program Files\NVIDIA Corporation 目录(596 Mb)。
在您开始构建包含课程 47 的 WIN_GL
项目之前,必须确保相关项目中的三件事:
- 在 项目属性框 的 配置属性->VC++目录->包含目录中,选择 更改 命令并将目录设置为 ..\NVIDIA Corporation\Cg\include
- 在 项目属性框 的 配置属性->VC++目录->库目录中,选择 更改 命令并将目录设置为 ..\NVIDIA Corporation\Cg\lib
- 在应用程序的根目录中,需要插入 Cg.dll 和 CgGL.dll 文件。
3. 项目源、数据和信息存储
MS Studio .NET(Grant James, 2002)的原始项目位于 NeHe GameDev 网站上,但未适配到现代 Win32 和最新版本的 MSVS。我逐一适配了所有课程的代码,并将其集成到一个通用项目 WIN_GLproj\WIN_GL\WIN_GL.sln 中。在适配代码时,我发现项目从一个 MS Visual Studio 版本修改到另一个版本时,出现了许多冲突。最后,为了演示目的,我在 Win32 MSVS-15 pro 环境中,使用 MSVS-10 的工具,以 UNICODE 编码开发了该项目。
您可以在 解决方案资源管理器 窗口中选择任何 *.h 或 *.cpp 文件,然后查看和编辑它。乍一看,似乎包含的文件太多了,但进一步考虑表明一切并非过于复杂。该项目由通用过程和每个课程实现的特殊过程组成。
所有三个项目 WIN_GL0
、WIN_GL1
、WIN_GL
都具有相似的结构,仅 属性框 设置有所不同。因此,源代码、数据和信息存储几乎相同。
3.1. WIN_GLproj\WIN_GL\WIN_GL
WIN_GLproj\WIN_GL\WIN_GL 路径中的源代码是使用标准 Win32应用程序向导 创建的。
- WIN_GL.cpp - 定义应用程序的标准 Win32 过程;
HanldleCmdLine, InitGLWindow
过程和WndGLProc
修改 - 由作者插入;
3.2. WIN_GLproj\NeHeDrawInit
WIN_GLproj\NeHeDrawInit 路径中的源 XX_*DrawInit.cpp
代码(XX 范围 01-48)是从原始 NeHe 网站借用并由作者为 Win32 MSVS-15 专业环境中的 UNICODE 编码修改的。我已尽量不修改这些代码。
X4_UFOGameDrawInit.cpp 是由作者从原始课程 07、11、30、32、34 中组合而成,用于演示目的。
X5_BoxmanDrawInit.cpp 是由作者为演示目的开发的。
由于平台从 MFC 更改为 Win32,XX_*DrawInit.cpp 代码相对于上一篇文章只做了一些更改。
3.3. WIN_GLproj\NeHeProgs
WIN_GLproj\NeHeProgs\XX_Spec 路径(XX 范围 01-48)中各个课程的 特殊源代码 从原始 NeHe 网站借用,并由作者为 Win32 MSVS-15 pro 环境中的 UNICODE 编码进行了修改。我已尽量不修改这些代码。
课程 X4 和 X5 的 特殊源代码 位于 WIN_GLproj\NeHeProgs\X4_Spec 和 WIN_GLproj\NeHeProgs\X5_Spec 中,由作者开发。
由于平台从 MFC 更改为 Win32,上一篇文章中的 特殊源代码文件 只做了一些更改;
3.4. WIN_GLproj\GlobUse
WIN_GLproj\GlobUse 路径中的 源代码 是作者基于标准 Win32应用程序向导 技术开发的。
- GLRoutine.cpp - 必须在项目中使用
- GlobTexture.cpp - 用于GL纹理过程(代替原始项目中使用的
Glaux.lib
库) - DlgAbout.cpp, DlgHelp.cpp, DlgLesson.cpp, DlgTitle.cpp - 仅由作者为演示目的附加,并非主要项目实现所必需
- JoystickWin32Dlg.cpp, JoystickHelpDlg.cpp, ClassWinResent - 由作者为演示操纵杆使用目的而附加,并非主要项目实现所必需
- GlobDrawGL.cpp - 仅由作者为演示项目与单独课程之间的外部链接而创建,并非主要项目实现所必需
由于平台从 MFC 更改为 Win32,GlobDrawGL.cpp 相对于上一篇文章只做了一些更改;所有其他文件都是为 Win32 平台新开发的(没什么特别的,只是常规操作)。
3.5. WIN_GLproj\Data
WIN_GLproj\Data\XX_Data 路径中各个课程的数据文件(XX 范围 06-47)是从原始 NeHe 网站借用的。
课程 X4 和 X5 的数据文件分别位于 WIN_GLproj\Data\X4_Data 和 WIN_GLproj\Data\X5_data,由作者创建。
数据文件相对于上一篇文章没有变化。
3.6. WIN_GLproj\HelpText
作者创建了 WIN_GLproj\HelpText\XX_GLhelp.txt 和 WIN_GLproj\HelpText\XX_JoystickHelp.txt 文件中的各个课程的 帮助文本,用于 DlgHelp.cpp、JoystickMFCHelpDlg.cpp 中的 DlgHelp
对话框和 DlgJoystickHelp
对话框。
WIN_GLproj\HelpText\ReadMe\ReadMe_XX.txt 和 WIN_GLproj\HelpText\XX_JoystickHelp.txt 文件中的各个课程的 ReadMe 文本 从原始 NeHe 网站借用,用于 DlgAbout
对话框。
ReadMe文本相对于上一篇文章没有变化。
3.7. WIN_GLproj
资源文件 WIN_GLproj 路径是从上一篇文章借用并创建的,仅对应用程序名称做了一些更改。
- WIN_GL.rc 和 resource.h - 菜单、对话框、加速器资源由作者使用标准 资源向导 过程创建;
4. 代码说明
标准 OpenGL 应用程序的控制流程图,步骤按这些部分的相应项目编号。
4.1. Win32平台中的Windows初始化
标准 MFC应用程序向导 同时提供 CMainFrame
和 CChildWindow
窗口。标准 Win32应用程序向导 只提供一个窗口模板。
因此,InitGLWindow
过程已由作者插入到标准 Initinstance
过程中。
BOOL InitGLWindow(void) //initialization of the Child GL Window
{
_tgetcwd(m_rootDir, _MAX_PATH); //Get root path of the application
SummaryListLessons(); //Create List of Lessons available
InitClassUseResent(); //Initialization of the MRU lessons handling
InitMRU(m_hMainWnd); //Search for recently called lessons
while (hTool == NULL) //Tool Bar and Status bar initialization
CreateToolBar(m_hMainWnd);
ShowToolStatus();
RECT rect;
GetWindowRect(m_hMainWnd, &rect); //Initial sizes od the Main Frame
m_boxWidth = rect.right - rect.left;
m_boxHeight = rect.bottom - rect.top;
//Create Child window handle m_hGLwnd:
if (!CreateChildWindow(_T(""), m_boxWidth, m_boxHeight, m_bits, fullscreen))
return FALSE;
//GL window creation(borrowed from NeHe samples);
if (!CreateGLWindow(m_bits, m_boxWidth, m_boxHeight))
return FALSE; // Quit If Window Was Not Created
return TRUE;
}
在 MFC 平台中,调整 主框架、子窗口、工具栏、状态栏 的过程嵌入在构建过程中。
在 Win32 平台中,需要特殊的程序来调整 主框架、子窗口、工具栏、状态栏,通过 WndProc
中的 WM_SIZE
消息进行。
case WM_SIZE:
WndGLProc(hWnd, message, wParam, lParam);
AdjustChildToRect(); //Adjusting Child GL window sizes to the Main Frame
break;
4.2. 创建GL窗口
CreateGLwindow
过程对所有课程都是通用的,位于公共 GlobUse 目录中的 GLRoutine.cpp 文件中。
CreateGLWindow
过程将在初始化过程 InitGLWindow
中调用。CreateGLWindow
过程几乎完全是从原始 NeHe 课程中借用的,我已尽量不修改作者的代码。
4.3. 初始化应用程序
将在 CreateGLWindow
过程中调用的初始化过程。
if (!InitGL()) // Initialize Our Newly Created GL Window
{
KillGLWindow(); // Reset The Display
MessageBox(NULL, _T("Initialization Failed."), _T("ERROR"),MB_OK|MB_ICONEXCLAMATION);
exit(0);
}
InitGL
OpenGL 窗口过程的初始化(位于 GlobUse\GlobDrawGL.cpp)指的是当前课程的初始化过程 InitGL_XX(GLvoid)
,该过程位于 NeHeDrawInit\XX_*DrawInit.cpp。这些初始化过程是从 NeHe 网站借用的。我已尽量不修改这些代码。
唯一的巨大差异是我擅自将 Glaux.lib 库从所有用于 纹理 初始化的课程中排除。尽管如此,我希望原始代码的作者不会抱怨。当然,他们可能没想到 MS VS 开发人员会从第 10 版开始将 Glaux.lib 库排除。如果仍然可以在 MS VS 10 版中包含 Glaux.lib,但在 11 版中它将无法工作。
代替 Glaux.lib 的 纹理 初始化过程位于 Globuse\GlobTexture.cpp 中。纹理初始化的说明可以从我之前的 CodeProject 文章“使用CImage类在OpenGL中进行纹理映射”和“使用CImage类在OpenGL中进行纹理遮罩”中获取。
4.4. 调整GL窗口大小
ResizeGLScene
过程对所有课程都是通用的,将在 WndGLProc
中通过 WM_SIZE
消息调用。
case WM_SIZE: // Resize The OpenGL Window
{
ReSizeGLScene(LOWORD(lParam), HIWORD(lParam)); // LoWord=Width, HiWord=Height
return 0; // Jump Back
}
与 NeHe 原始基础不同,插入了一些全局变量。
GLfloat fNearPlane = 0.1f, //Frustum Near Plane
fFarPlane = 100.f, //Frustum Far Plane
fViewAngle = 45.f, //Frustum View Angle
fAspect; //Frustum Width/Height ratio
int m_boxWidth = 800; //GL window width
int m_boxHeight = 600; //GL window height
在某些课程(30,31,34,36,44,45,46,X4)中,视锥体 值设置与 InitGL_XX
过程中的默认值不同。
在课程21和24中,使用了 glOrtho
演示。
if(m_bOrtho)
glOrtho(0.0f,width,height,0.0f,-1.0f,1.0f); // Create Ortho (0,0 At Top Left)
else // Calculate The Aspect Ratio Of The Window
gluPerspective(fViewAngle,(GLfloat)width/(GLfloat)height,fNearPlane,fFarPlane);
4.5. 绘制GL场景
OpenGL 绘图过程将在 WndGLProc
中通过 WM_PAINT
消息调用。
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(m_hGLwnd, &ps);
DrawGLScene();
EndPaint(m_hGLwnd, &ps);
}
break;
DrawGLScene
OpenGL 窗口绘图过程(位于 GlobUse\GlobDrawGL.cpp)指的是当前课程的绘图过程 DrawGLScene_XX(GLvoid)
,该过程位于 NeHeDrawInit\XX_*DrawInit.cpp。这些绘图过程是从 NeHe 网站借用的。我已尽量不修改这些代码。
4.6. 消息处理
键盘过程 处理将在 WndGLProc
中通过 WM_KEYDOWN
和 WM_KEYUP
消息调用。
case WM_KEYDOWN: // Is A Key Being Held Down?
{
HandleKeyboard(int(wParam)); //Key code handling
return 0; // Jump Back
}
case WM_KEYUP: // Has A Key Been Released?
{
ProcessKeyUpN(int(wParam));
return 0; // Jump Back
}
ProcessKeyboard
和 VkKeyUpN
键盘命令处理过程(位于 GlobUse\GlobDrawGL.cpp)指的是当前课程的键盘过程 ProcessKeyboard_XX(int idKey)
和 VkKeyUp_XX
,该过程位于 NeHeDrawInit\XX_*DrawInit.cpp
。这些键盘命令是从 NeHe 网站借用的。我已尽量不修改这些命令。我只更改了 F1 命令用于 帮助 功能,并将 Ctrl+Enter 命令更改为全屏模式处理。
鼠标过程 处理将在 WndGLProc
中通过 WM_MOUSEMOVE, WM_LBUTTONDOWN
和 WM_RBUTTONDOWN
消息调用。
case WM_MOUSEMOVE:
{
POINT point = { LOWORD(lParam), HIWORD(lParam) };
mouse_x = point.x;
mouse_y = point.y;
isClicked = (LOWORD(wParam) & MK_LBUTTON) ? true : false;
isRClicked = (LOWORD(wParam) & MK_RBUTTON) ? true : false;
MouseMoveN(LOWORD(wParam), point);
}
break;
case WM_LBUTTONDOWN:
{
POINT point = { LOWORD(lParam), HIWORD(lParam) };
mouse_x = point.x;
mouse_y = point.y;
LButtonDown(mouse_x, mouse_y);
isClicked = TRUE;
}
break;
case WM_RBUTTONDOWN: isRClicked = TRUE; break;
MouseMoveN
, LButtonDown
鼠标命令处理过程(位于 GlobUse\GlobDrawGL.cpp)指的是当前课程的鼠标处理过程 MouseMove_XX
, LButtonDown_XX
,该过程位于 NeHeDrawInit\XX_*DrawInit.cpp。这些鼠标命令是从 NeHe 网站借用的。我已尽量不修改这些命令。
计时器过程 处理将在 WndGLProc
中通过 WM_TIMER
消息调用。
case WM_TIMER:
if (m_bPlay)
switch (LOWORD(wParam))
{
case ID_TIMER:
::UpdateScene();
DrawGLScene();
break;
}
break;
UpdateScene
过程用于一步图像更改(位于 GlobUse\GlobDrawGL.cpp),指的是当前课程的 Update_XX
过程,该过程位于 NeHeDrawInit\XX_*DrawInit.cpp。这些更新过程是从 NeHe 网站借用的。我已尽量不修改这些过程。
4.7. 销毁GL窗口
如果在 课程对话框 中选择在新窗口中启动新课程,则必须释放内存并关闭 OpenGL 窗口。同样,在应用程序退出之前,必须释放内存并关闭 OpenGL 窗口。
case ID_APP_EXIT:
Deinitialize();
KillGLWindow();
DestroyWindow(hWnd);
break;
DeinitializeN
清理内存的过程(位于 GlobUse\GlobDrawGL.cpp)指的是当前课程的 Deinitialize_XX
过程,该过程位于 NeHeDrawInit\XX_*DrawInit.cpp。这些清理内存过程是从 NeHe 网站借用的。我已尽量不修改这些过程。
KillGLwindow
过程对所有课程都是通用的,位于公共 GlobUse 目录中的 GLRoutine.cpp 文件中。KillGLWindow
过程几乎完全是从原始 NeHe 课程中借用的,我已尽量不修改作者的代码。
5. 操纵杆实现
操纵杆 处理在项目 WIN_GL
和 WIN_GL1
的课程 09, 10, 32, 40, X4, X5 中可用。在 WIN_GL0
项目中,操纵杆 功能不可用。接下来的两个步骤需要使 WIN_GL0
像 WIN_GL1 一样使用 操纵杆:
- 选择菜单 项目->添加现有项... 并将 GlobUse\JoystickWin32Dlg.cpp 和 GlobUse\JoystickHelpDlg.cpp 插入到 解决方案资源管理器窗口 中;
- 打开 WIN_GL0\WIN_GL0\SetName.cpp 并注释掉(或直接删除)空过程
void InitJoystickDlg(void){}
。
就是这样(文章 2.1 点的条件已理解)。现在项目应该可以与 操纵杆 一起工作了。
操纵杆程序 处理将在 JoystickWin32Dlg.cpp 中通过 WM_INPUT
消息调用。
HandleJoystickN
操纵杆控制处理过程(位于 GlobUse\GlobDrawGL.cpp)指的是当前课程的 HandleJoystick_XX
过程,该过程位于 NeHeDrawInit\XX_*DrawInit.cpp。这些过程由作者为演示目的开发。例如,课程 40 操纵杆 处理。
void HandleJoystick_40(int nx, int ny, int nz, int nzr, int nh,
BOOL bButtonStates[], BOOL bButtonPrev[])
{
ropeConnectionVel = Vector3D(-0.003f*nzr, 0.003f*nx, 0.003f*ny);
}
您可以更改这个现有的 HandleJoystick_XX
代码,或者根据您的喜好创建自己的代码。
6. 异常(课程43和47)
课程 43 和 47 需要安装一些 外部库(本文 2.2 点),并且在项目 WIN_GL0
和 WIN_GL1
中不可用。
接下来的两个步骤需要使它们在项目 WIN_GL1
中像在 WIN_GL
中一样可用:
- 选择菜单 项目->添加现有项... 并将 NeHeDrawInit\43_FreeTypeFontsDrawInit.cpp、NeHeDrawInit\47_CGVertexShaderDrawInit.cpp 和 NeheProgs\43_Spec\freetype.cpp 插入到 解决方案资源管理器窗口 中;
- 打开 WIN_GL1\WIN_GL1\SetName.cpp 并注释掉(或直接删除)所有包含字符串 43 和/或 47 的行。
就是这样(文章 2.2 点的条件已理解)。现在,课程 43 和 47 在项目中可用了。
7. 使用提供的项目开发您自己的应用程序
提供的一系列课程为开发一些有效的应用程序演示提供了激动人心的机会。这些可能性已通过本项目的课程 X4 UFOGame(由作者从原始课程 07、11、30、32、34 组合)和 X5 Boxman(演示了仅通过由原始文本文件管理的绘图实体创建性能的可能性)进行了说明。
您可以拾取所有这些项目,使用我之前的 CodeProject 文章“一键从现有代码创建MFC项目”的技术重命名,并根据您的喜好组合和改进代码(如果您引用我的代码,将不胜感激)。
当前提供的解决方案的三个项目是仅仅通过上述技术重命名而彼此开发出来的。
兴趣点和致谢
上述项目是在俄罗斯NeHe网站编辑谢尔盖·阿尼西莫夫的巨大帮助下开发的,我非常感谢他的善意帮助。
同时非常感谢原始代码的尊敬作者以及他们在 NeHe 网站课程文章中的完美说明。他们在二十多年前完成了他们的工作,他们的程序在 Windows 10 和 Win32 MSVS 2015 的现代环境中仍然活跃,他们的说明仍然有效,只需进行很少的修正。
与上一篇文章中的 MFC 项目相比,Win32 项目的优势:
- 应用程序体积更小
- 程序运行更快
- Windows XP 应用程序不需要特殊的 *.dll 文件;
- Win32 平台代码几乎与 移动 应用程序代码兼容
上一篇文章中的 MFC 项目相对于当前 Win32 项目的优势在于,对话框、消息和工具处理更省力。
历史
本文的前身于2014年在 CodeProject 上发表:“所有课程集中于一个通用Win32项目”。此后,我在 CodeProject 上发表了五六篇文章,其中大部分也成为本文的前身。
我认为本文和代码对于程序开发来说更为委婉。