50 个 OpenGL MFC 项目合集





5.00/5 (25投票s)
将 NeHe OpenGL 课程改编为 MSVS-15 pro MFC 的 INICODE,以及操纵杆实现的示例
引言
随着现代3D技术的不断发展,有时回顾一些基本要点是值得的。有时,现代3D图形导向系统的一些令人印象深刻的3D效果可以通过被视为已弃用的基本技术的纤薄手段来实现。
本文旨在演示一些旧的20年前的项目在现代 MSVS-15 MFC 和 Windows-10 环境中运行的示例。
背景
提供的示例项目基于 NeHe 旧的 48 课项目。大约三年前,我已经完成了将上述课程适应 MSVS-10 pro MFC 的工作。我逐一将代码“原样”翻译成 MBCS 编码。鉴于现在建议使用 UNICODE 编码,这项工作似乎没有完全执行。并且不需要为每节课单独开发项目。流程图方案对所有 OpenGL 项目都是通用的,因此,为了演示目的,开发一个所有课程通用的项目是值得的。
现在,我有一些时间来展示这个 MSVS-15 pro MFC 的 UNICODE 编码解决方案,其中包含一些 操纵杆 实现示例以及我以前的 CodeProject 文章的使用示例。
在开始构建提供的项目之前,强烈建议您查看随附的演示文稿,以了解预期的输出。
1. 演示说明
1.1. 可执行文件处理
MFC_GLdemo 目录中的可执行文件 MFC_GL.exe 已使用 MSVS-2015 pro 并通过 MSVS-2010 的工具构建。因此,MFC_GL.exe 甚至对 Windows-XP 也有效。如果您想在 Windows-XP 中启动,请不要忘记将 mfc100.dll、mfc100u.dll、msvcp100.dll、msvcr100.dll 文件插入到 MFC_GLdemo 目录中(或 ..windows\system32 目录中)。
MFC_GL.exe 可以不带任何参数启动。在这种情况下,将显示上次调用的课程。
MFC_GL.exe XX 可以在命令行中以两个符号参数启动,如下所示:01-48,X4,X5。在这种情况下,将显示相应课程的演示。
此处及其他地方,XX 表示两个符号的字符串
- (01-48)- NeHe教程中课程的序号
- (X4,X5)- 作者在俄罗斯NeHe网站上发布的课程编号
MFC_GL.exe 的控件如下
- 菜单 文件->课程... - 调用 选择课程对话框(也可按键盘 Ctrl+O)
- 菜单 文件->播放 - 播放/停止当前课程演示(也可按键盘 Ctrl+P)
- 最近文件 - 调用 选择课程对话框,其中列表框行选中了最近调用的相应课程
- 菜单 文件->退出 - 退出应用程序(也可按键盘 Alt+F4(立即退出)或按键盘 Esc(需要确认))
- 菜单 视图->全屏 - 安装/卸载当前课程全屏显示(也可按键盘 Ctrl+Enter)
- 菜单 视图->语言->俄语 - 将课程标题调整为俄语
- 菜单 视图->语言->英语 - 将课程标题调整为英语
- 菜单 视图->工具栏 - 显示/隐藏工具栏(也可按键盘 Alt+T)
- 菜单 视图->状态栏 - 显示/隐藏状态栏(也可按键盘 Alt+S)
- 菜单 视图->下一场景 - 如果停止,则当前课程演示的下一场景(也可按键盘 Ctrl+N)
- 菜单 视图->操纵杆测试 - 如果适用(课程 09, 10, 32, 40, X4, X5),则调用 操纵杆测试对话框(也可按键盘 Ctrl+J)
- 菜单 帮助->关于... - 调用 关于对话框(也可按键盘 Ctrl+A)
- 菜单 帮助->帮助对话框... - 调用 帮助对话框(也可按键盘 F1)
- 菜单 帮助->操纵杆帮助.. - 如果适用(课程 09, 10, 32, 40, X4, X5),则调用 操纵杆帮助对话框(也可按键盘 Ctrl + Y)
一旦启动 MFC_GL.exe,您可以通过菜单命令 文件->打开... (或键盘 Ctrl + O) 从弹出的对话框中的课程列表中选择任何其他课程演示开始。
请注意,最近文件系统是标准 MS VS 系统的替代方案,基于我的 CodeProject 文章“您自己的最近文件列表”。
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 复选框:检查相应的操纵杆按钮是否按下
- 未编号的复选框:检查相应的操纵杆 Hatch 按钮是否按下
- 左图片控件:显示用于弯曲操纵杆手柄左右和前后运动的十字位置坐标
- 右图片控件:显示用于左右转动操纵杆手柄和前后切换操纵杆加速的十字位置坐标
- 开/关单选按钮:显示操纵杆连接状态
当操纵杆测试对话框可见时,所有操纵杆命令仅对该对话框有效,对应用程序本身,操纵杆命令不可用。
请注意,操纵杆测试对话框基于我的 CodeProject 文章“操纵杆 Win32 和 MFC 项目”,只是移除了图片控件。
受影响课程的操纵杆帮助可通过菜单 帮助->操纵杆帮助对话框命令(或键盘 Ctrl+Y 或帮助对话框中的操纵杆帮助按钮)与操纵杆帮助对话框(如果适用)获得。
操纵杆帮助对话框是无模式的,因此既可以使用列出的操纵杆命令,也可以从列表中选择命令并按确定按钮(或双击相应行上的鼠标左键)。
2. 重要构建说明
在您使用 MFC_GLproj\MFC_GL\MFC_GLset.sln 文件,通过菜单 项目->构建解决方案来构建所有项目之前,请考虑一些重要的注意事项。
解决方案配置必须设置为 Release,平台必须为 X86。
默认编码属性为 UNICODE;尽管 MBCS 编码也可用,只需更改属性即可。
请注意,解决方案 MFC_GLproj\MFC_GL\MFC_GLset.sln 由三个相似的项目组成,它们仅在构建复杂性程度上有所不同
MFC_GL0
- 最简单的项目,可由没有任何 MSVS 编码经验的人构建;此项目没有 操纵杆 和课程 43 和 47;MFC_GL1
- 此解决方案在构建之前需要一些 属性框 安装;此解决方案包含 操纵杆 但不包含课程 43 和 47;MFC_GL
- 完整的解决方案在构建之前需要一些外部库安装;此解决方案的 MFC_GL.exe 结果显示在提供的 MFC_GLdemo 目录中。
即使您是首次使用 MSVS,只需将 MFC_GL0
项目指定为 启动项目(右键单击 -> 菜单 设置为启动项目),然后选择菜单 调试->不调试启动,程序 MFC_GL0.exe 应该开始构建并运行。
2.1. 操纵杆构建说明(项目 MFC_GL1 和 MFC_GL)
提供的项目是使用 MSVS-2015 pro 并通过 MSVS-2010 的工具开发的。因此,EXE 文件甚至对 Windows-XP 也有效。
如果您不需要在 Windows-XP 中运行应用程序,只需将工具更改为 MSVS-2015,则不会出现 操纵杆 过程构建问题。
使用 MSVS-2010 的工具在操纵杆实现中可能会出现问题。问题是使用了外部库 hid.lib。
在您使用 MSVS-2010 的工具构建项目 MFC_GL1
之前,您必须确保相关项目中的两件事
- 在项目属性框中,配置属性->VC++目录->包含目录,选择更改命令并将目录设置为 ..\Windows Kits\8.1\Include\shared(仅用于
#include <hidsdi.h>
命令) - 在项目属性框中,在配置属性->VC++目录->库目录中,选择更改命令并将目录设置为 ..\Windows Kits\8.1\Lib\winv6.3\um\x86(或者您可以通过菜单项目->添加现有项直接从目录 ..\Windows Kits\8.1\Lib\winv6.3\um\x86\hid.lib 插入库hid.lib)。
2.2. 课程 43 和 47 构建说明(项目 MFC_GL)
课程 43 需要外部库 freetype.lib,这需要从 http://gnuwin32.sourceforge.net/packages/freetype.htm 链接安装 Program Files\GnuWin32 目录(17.8 MB)。
在您开始构建包含课程 43 的项目 MFC_GL
之前,您必须确保相关项目中的两件事
- 在项目属性框中,在配置属性->VC++目录->包含目录中,选择更改命令并将目录设置为 ..\GnuWin32\include\freetype2
- 在项目属性框中,在配置属性->VC++目录->库目录中,选择更改命令并将目录设置为 ..\GnuWin32\lib
课程 47 需要外部库 cg.dll 和 cgGL.dll,这需要从 https://developer.nvidia.com/cg-toolkit-download 安装 Program Files\NVIDIA Corporation 目录 (596 MB)。
在您开始构建包含课程 47 的项目 MFC_GL
之前,您必须确保相关项目中的两件事
- 在项目属性框中,在配置属性->VC++目录->包含目录中,选择更改命令并将目录设置为 ..\NVIDIA Corporation\Cg\include
- 在项目属性框中,在配置属性->VC++目录->库目录中,选择更改命令并将目录设置为 ..\NVIDIA Corporation\Cg\lib
3. 项目源代码、数据和信息存储
MS Studio .NET (Grant James, 2002) 的原始项目位于 NeHe GameDev 网站上,但未适应 Microsoft Foundation Classes (MFC) 和最新版本的 MSVS。我逐一改编了所有课程代码,并将它们集成到一个公共项目 MFC_GLproj\MFC_GL\MFC_GL.sln 中。在代码改编过程中,我发现项目从一个 MS Visual Studio 版本修改到另一个版本时出现了很多冲突。最后,为了演示目的,我在 MFC MSVS-15 pro 环境中使用 MSVS-10 的工具开发了 UNICODE 编码的项目。
您可以在解决方案资源管理器窗口中选择任何*.h或*.cpp文件,并查看和编辑它。乍一看,似乎包含的文件太多,但进一步考虑表明一切并非过于复杂。项目由通用过程和每个课程实现的特殊过程组成。
所有三个项目,MFC_GL0
,MFC_GL1
,MFC_GL
具有相似的结构,只是 属性框 安装不同。因此,源代码、数据和信息存储几乎相同。
3.1. MFC_GLproj\MFC_GL
MFC_GLproj\MFC_GL\MFC_GL 路径中的源代码是使用标准 MFC 应用程序向导创建的
- MFC_GL.cpp - 定义应用程序的标准类行为;命令行参数处理 - 由作者插入
- MainFrm.cpp - 标准
CMainFrame 类
的实现;HideMenu
和ShowMenu
过程 - 由作者添加 - ChildView.cpp - 标准
CChildView 类
的实现;消息处理过程由作者使用标准 MFC 应用程序向导过程创建 - MFC_GL.rc 和 resource.h - 菜单、对话框、加速器资源由作者使用标准 资源向导 过程创建
3.2. MFC_GLproj\NeHeDrawInit
MFC_GLproj\NeHeDrawInit 路径中的源代码 XX_*DrawInit.cpp(XX 范围 01-48)借用自原始 NeHe 网站,并由作者修改为 MFC MSVS-15 pro 环境中的 UNICODE 编码。我已尽可能地不更改这些代码。
X4_UFOGameDrawInit.cpp 由作者根据原始课程 07、11、30、32、34 组合而成,用于演示。
X5_BoxmanDrawInit.cpp 由作者开发,用于演示。
3.3. MFC_GLproj\NeHeProgs
MFC_GLproj\NeHeProgs\XX_Spec 路径中(XX 范围 01-48)的各个课程的特殊源代码已从原始 NeHe 网站借用,并由作者修改为 MFC MSVS-15 pro 环境中的 UNICODE 编码。我已尽可能不更改这些代码。
课程 X4 和 X5 的特殊源代码位于 MFC_GLproj\NeHeProgs\X4_Spec 和 MFC_GLproj\NeHeProgs\X5_Spec,由作者开发。
3.4. MFC_GLproj\GlobUse
MFC_GLproj\GlobUse 路径中的源代码由作者基于标准 MFC 应用程序向导技术开发
- GlobMyProc.cpp, GLRoutine.cpp - 项目中强制使用
- GlobTexture.cpp - 用于 GL 纹理过程(取代原始项目中使用的 Glaux.lib 库)
- DlgAbout.cpp, DlgHelp.cpp, DlgLesson.cpp, DlgTitle.cpp - 由作者为演示目的添加,并非主项目实现所必需
- JoystickMFCDlg.cpp, JoystickMFCHelpDlg.cpp - 由作者为演示操纵杆使用目的而添加,并非主项目实现所必需
- GlobDrawGL.cpp - 仅由作者为项目与独立课程之间的外部链接而创建,并非主项目实现所必需
- MFC_GL.rc 和 resource.h - 菜单、对话框、加速器资源由作者使用标准 资源向导 过程创建
3.5. MFC_GLproj\Data
MFC_GLproj\Data\XX_Data 路径中(XX 范围 06-47)的各个课程的数据文件已从原始 NeHe 网站借用。
课程 X4 和 X5 的数据文件分别在 MFC_GLproj\Data\X4_Data 和 MFC_GLproj\Data\X5_data 中,由作者创建。
3.6. MFC_GLproj\HelpText
MFC_GLproj\HelpText\XX_GLhelp.txt 和 MFC_GLproj\HelpText\XX_JoystickHelp.txt 文件中的各个课程的帮助文本已由作者创建,用于 codeDlgHelp.cpp, JoystickMFCHelpDlg.cpp 中的 DlgHelp
对话框和 DlgJoystickHelp
对话框。
MFC_GLproj\HelpText\ReadMe\ReadMe_XX.txt 和 MFC_GLproj\HelpText\XX_JoystickHelp.txt 文件中的各个课程的自述文本已从原始 NeHe 网站借用,用于 DlgAbout
对话框。
4. 代码解释
标准 OpenGL 应用程序的控制流程图,步骤按相应章节的项编号。
4.1. 创建 GL 窗口
CreateGLwindow
过程对所有课程都是通用的,位于公共 GlobUse 目录中的 GLRoutine.cpp 文件中。
CreateGLWindow
过程由虚拟过程 OnCreate
调用
int CChildView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CWnd::OnCreate(lpCreateStruct) == -1)
return -1;
CreateGLWindow(this, 32); //borrowed from NeHe site;
//located in GlobUse\GLRoutine.cpp
_tgetcwd(m_rootDir, _MAX_PATH); //root directory identification
CreateListLessons(); //list box of DlgLesson dialog content;
//located in GlobUse\GLRoutine.cpp
m_bPlay = TRUE; //flag of autoplay
SetTimer(ID_TIMER_PLAY, 15, NULL); //timer of the scene to change in 15 milliseconds
return 0;
}
CreateGLWindow
过程几乎完全借用自原始 NeHe 课程,我已尽可能不更改原始代码。
4.2. 初始化应用程序
初始化过程由 CChildView::InitChildView
过程调用
void CChildView::InitChildView(void)
{
m_bInitGL = FALSE; //initialization flag
m_pView = this; //identification of the window
//to be called in global procedures
InitMRU(); //initialization of the resent lessons list
InitGLn(m_strNum); //initialization of the OpenGL window
//(located in GlobUse\GlobDrawGL.cpp)
//Main Frame Text:
GetMainFrameGlob->SetWindowText( CString(AfxGetApp()->m_pszAppName) +
_T(" : ") + (m_strLesson = GetLessonName(m_strNum)));
}
InitGLn
是 OpenGL 窗口的初始化过程(位于 GlobUse\GlobDrawGL.cpp),它引用了当前课程的初始化过程 InitGL_XX(GLvoid)
,该过程位于 NeHeDrawInit\XX_*DrawInit.cpp 中。这些初始化过程均借用自 NeHe 网站。我已尽可能地不更改这些代码。
唯一的重大区别是,我擅自将用于纹理初始化的 Glaux.lib 库从所有课程中排除。尽管如此,我希望原始代码的作者不会抱怨。当然,他们可能没想到 MS VS 开发者会将 Glaux.lib 库从 第10版 及以后版本中排除。如果仍有可能在 MS VS 第10版 中包含 Glaux.lib,那么在 第11版 中它将不起作用。
用于纹理初始化的过程,而不是 Glaux.lib,位于 Globuse\GlobTexture.cpp 中。纹理初始化的说明可以从我以前的 CodeProject 文章“使用 CImage 类在 OpenGL 中进行纹理映射”和“使用 CImage 类在 OpenGL 中遮蔽纹理”中获得。
4.3. 调整 GL 窗口大小
ResizeGLScene
过程对所有课程通用,由虚拟过程 OnSize
调用
void CChildView::OnSize(UINT nType, int cx, int cy)
{
CWnd::OnSize(nType, cx, cy);
ReSizeGLScene(cx, cy); //base borrowed from NeHe site;
//located in GlobUse\GLRoutine.cpp
SetTitlePos(); //title of the lesson in Main Frame and in Full Screen mode
}
与 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
RECT m_viewRect; //current View rect size in pixel
在某些课程中(30,31,34,36,44,45,46,X4),视锥体值设置与 InitGL_XX
过程中的默认值不同。
在第 21 课和第 24 课中,使用了 glOrtho
演示
if(m_strNum == _T("21")||m_strNum == _T("24"))
glOrtho(0.0f,width,height,0.0f,-1.0f,1.0f); // Create Ortho widthxheight View
// (0,0 At Top Left)
else // Calculate The Aspect Ratio Of The Window
gluPerspective(fViewAngle,(GLfloat)width/(GLfloat)height,fNearPlane,fFarPlane);
4.4. 绘制 GL 场景
OpenGL 绘图过程由虚拟过程 OnPaint
调用
void CChildView::OnPaint()
{
CPaintDC dc(this); // device context for painting
if (m_bInitGL)InitChildView(); //Initialization of the GL window if first call
DrawGLSceneN(); //Global drawing procedure
// Do not call CWnd::OnPaint() for painting messages
}
DrawGLSceneN
OpenGL 窗口的绘图过程(位于 GlobUse\GlobDrawGL.cpp)引用当前课程的绘图过程 DrawGLScene_XX(GLvoid)
,该过程位于 NeHeDrawInit\XX_*DrawInit.cpp
中。这些绘图过程均借用自 NeHe 网站。我已尽可能地不更改这些代码。
4.5. 消息处理
键盘过程处理由虚拟过程 OnKeyDown
和 OnKeyUp
调用
void CChildView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
ProcessKeyboardN(nChar); //Global procedure of nChar handling
CWnd::OnKeyDown(nChar, nRepCnt, 1nFlags);
}
void CChildView::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
{
VkKeyUpN(nChar, nRepCnt, nFlags); //Global procedure of nChar handling
CWnd::OnKeyUp(nChar, nRepCnt, nFlags);
}
ProcessKeyboardN
和 VkKeyUpN
键盘命令处理程序(位于 GlobUse\GlobDrawGL.cpp)引用当前课程的键盘程序 ProcessKeyboard_XX(int idKey)
和 VkKeyUp_XX
,这些程序位于 NeHeDrawInit\XX_*DrawInit.cpp 中。这些键盘命令均借用自 NeHe 网站。我已尽可能地不更改这些命令。我只将 F1 命令更改为 帮助 功能,并将 Ctrl+Enter 命令更改为全屏模式处理。
鼠标过程处理由虚拟过程 OnMouseMove
、OnLButtonDown
和 OnRButtonDown
调用
void CChildView::OnMouseMove(UINT nFlags, CPoint point)
{
mouse_x = point.x; mouse_y = point.y; //global mouse position
MouseMoveN(nFlags, point); //Global procedure of Mouse Move handling
CWnd::OnMouseMove(nFlags, point);
}
void CChildView::OnLButtonDown(UINT nFlags, CPoint point)
{
LButtonDownN(nFlags, point); //Global procedure of Mouse Left Button handling
CWnd::OnLButtonDown(nFlags, point);
}
void CChildView::OnRButtonDown(UINT nFlags, CPoint point)
{
RButtonDownN(nFlags, point); //Global procedure of Mouse Right Button handling
CWnd::OnRButtonDown(nFlags, point);
}
MouseMoveN
、LButtonDownN
和 RButtonDownN
鼠标命令处理程序(位于 GlobUse\GlobDrawGL.cpp)引用当前课程的鼠标处理程序 MouseMove_XX
、LButtonDown_XX
和 RButtonDown_XX
,这些程序位于 NeHeDrawInit\XX_*DrawInit.cpp 中。这些鼠标命令均借用自 NeHe 网站。我已尽可能地不更改这些命令。
定时器过程处理由虚拟过程 OnTimer
调用
void CChildView::OnTimer(UINT_PTR nIDEvent)
{
switch (nIDEvent)
{
case ID_TIMER_PLAY:
if (!m_bPlay) return; //if not play mode do nothing
UpdateGLScene(); //Global procedure for one step image change
DrawGLSceneN(); //Global drawing procedure
break;
}
CWnd::OnTimer(nIDEvent);
}
UpdateGLScene
过程用于一步图像更改(位于 GlobUse\GlobDrawGL.cpp),它引用当前课程的 Update_XX
过程,该过程位于 NeHeDrawInit\XX_*DrawInit.cpp 中。这些更新过程均借用自 NeHe 网站。我已尽可能地不更改这些过程。
4.6. 终止 GL 窗口
如果在 课程对话框 中选择在新窗口中开始新课程,则必须释放内存并关闭 OpenGL 窗口。同样,在应用程序退出之前,也必须释放内存并关闭 OpenGL 窗口
void CChildView::OnAppExit()
{
DeinitializeN(); //Clear memory
KillGLWindow(this); //Close OpenGL window
}
用于清除内存的 DeinitializeN
过程(位于 GlobUse\GlobDrawGL.cpp)引用当前课程的 Deinitialize_XX
过程,该过程位于 NeHeDrawInit\XX_*DrawInit.cpp 中。这些清除内存过程均借用自 NeHe 网站。我已尽可能地不更改此过程。
KillGLwindow
过程对所有课程都是通用的,位于公共 GlobUse 目录中的 GLRoutine.cpp 文件中。KillGLWindow
过程几乎完全借用自原始 NeHe 课程,我已尽可能不更改原始代码。
5. 操纵杆实现
操纵杆处理在项目 MFC_GL
和 MFC_GL1
的课程 09、10、32、40、X4、X5 中可用。在项目 MFC_GL0
中,操纵杆功能不可用。以下两步需要使 MFC_GL0
像 MFC_GL1
一样与操纵杆一起工作
- 选择菜单 项目->添加现有项... 并将 GlobUse\JoystickMFCDlg.cpp 和 GlobUse\JoystickHelpDlg.cpp 插入到解决方案资源管理器窗口中
- 打开 MFC_GL0\MFC_GL0\SetName0.cpp 并注释掉(或直接删除)空过程
void InitJoystickDlg(void){}
。
就这样(本文第 2.1 点的条件已理解)。现在项目应该可以与 操纵杆 配合使用了。
操纵杆过程处理由虚拟过程 CJoystickMFCDlg::OnRawInput
调用。
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 点),并且在项目 MFC_GL0
和 MFC_GL1
中不可用。
接下来两个步骤需要使它们在项目 MFC_GL1
中像 MFC_GL
中一样可用
- 选择菜单 项目->添加现有项... 并将 NeHeDrawInit\43_FreeTypeFontsDrawInit.cpp、NeHeDrawInit\47_CGVertexShaderDrawInit.cpp 和 NeheProgs\43_Spec\freetype.cpp 插入到解决方案资源管理器窗口中
- 打开 MFC_GL0\MFC_GL0\SetName1.cpp 并注释掉(或直接删除)所有包含字符串 43 和/或 47 的行。
就这样(本文第 2.2 点的条件已理解)。现在课程 43 和 47 已在项目中可用。
7. 使用提供的项目开发您自己的应用程序
所提供的一系列课程为开发一些有效的应用程序演示提供了令人兴奋的机会。这些可能性已在本项目中通过课程 X4 UFOGame(由作者根据原始课程 07、11、30、32、34 组合而成)和 X5 Boxman(演示了仅使用基本文本文件管理的绘图实体来创建性能的可能性)进行了说明。
您可以获取这个项目,使用我之前的 CodeProject 文章“一键从现有代码创建 MFC 项目”重命名它,然后根据您的喜好组合和改进代码(如果您引用我的代码,我将不胜感激)。
当前提供的解决方案的三个项目仅通过上述技术重命名而成。
兴趣点和致谢
上述项目是在俄罗斯NeHe网站的编辑Sergey Anisimov的鼎力帮助下开发的,我非常感谢他的友好协助。
此外,非常感谢原始代码的尊敬作者及其在 NeHe 网站课程文章中的完美说明。
他们二十多年前完成了他们的工作,他们的程序在 Windows 10 和 MFC MSVS 2015 的现代环境中仍然活跃。此外,所有这些庞大的现代图形系统都源自这些原始但有效的技术。谁知道呢,也许它们可以在某些将要开发的替代图形系统中得到更新,而 CodeProject 是实现这一目标的最佳平台。有时,回过头来看看最初是什么样子是值得的,也许还有其他程序开发方式。
历史
首先,我关于该主题的文章于2013年发表在 GameDev 上:“所有课程集中于 MFC 中的公共库 GLSummary”。不幸的是,GameDev 社区对 MFC 持怀疑态度,许多 GameDev 人在听到 MFC 字眼时会感到恐慌(甚至有人称之为厌恶)。
此后,我在 CodeProject 上发表了四五篇文章,其中大部分都是本文的前身。
工作将继续进行。
历史
- 2017年5月11日:初始版本