[第一讲修正到一半,发现NeHe的教程太复杂了,如果基于glut,似乎要容易处理很多]
第一讲 设置OpenGL窗口
前言
欢迎使用我的 OpenGL 教程。我只是一个对 OpenGL 充满热情的普通人! 我第一次听说 OpenGL 还是 3Dfx 发布 Voodoo 1 卡的 OpenGL 硬件加速驱动的时候, 当时我就意识到 OpenGL 是我必须要学习的东西。 不幸的是当时很难从书本或者网络上找到关于 OpenGL 的信息。 我花 了 很多时间来调试代码、 在 email 和 IRC(在线聊天 系 统) 中恳求他人的帮助, 但我发现那些懂得 OpenGL 的人觉得自己是精英, 也没有兴趣共享他们的知识。 这实在令人灰心。
我创建这个网站是为 了 帮助那些有兴趣学习 OpenGL的人, 让他们在需要帮助时有个求助的地方。 在每一篇教程中我都会尽我个人所能,详细地解释每一行代码的作用。 我会保持代码的简洁(无需学习MFC代码)。 就算是Visual C++ 和 OpenGL 的绝对新手也应该能读懂代码并且清楚地知道发生 了 什 么 。 对于 OpenGL 的高级程序员来说这个站点可能太简单 了 。 但是如果你刚刚起步, 我想这个站点将会给你许多帮助!
准备工作
这篇教程已经在2000年一月份经过 了 彻底的重写。 这篇教程将会教给你如何设置一个 OpenGL 视窗, 它可以是窗口模式的或者全屏幕模式,并可以是 任何你想要的尺寸、 分辨率 和 色彩深度。 这个代码很灵活并且可以运用在你所有的 OpenGL 工程中, 它也是我所有教程的基础代码! 我把该代码写得灵活而强大。该程序将报告所有错误,也应该不会内存泄露。它易读且容易修改。 感谢 Fredric Echols 对代码所做的修改。
让我们直接跳到代码部分来开始这个教程。 首先, 我们需要在Visual C++ 中创建一个工程。 假如你不知道怎 么 做的话, 我想你应该先学习 Visual C++ 而不是 OpenGL。 可供下载的代码是用 Visual C++ 6.0 写成的。 在某些版本的 VC++ 中, 需要把 bool 改为 BOOL, true 改为 TRUE, false 改为 FALSE。 做 了 上述修改之后, 代码可以在 Visual C++ 4.0和5.0 中编译通过。
当你在Visual C++ 中创建 了 一个新的 Win32 程序(并非控 制 台 程序) 之后, 你还需要链接 OpenGL 的库文件。 操作步骤是: Project-> Settings, 点击 LINK 标签, 在 “Object/Library Modules” 下 面 ,在那一行的开始处(在kernel32.lib之前) 增添 OpenGL32.lib, GLu32.lib 和 GLaux.lib, 完成之后点击 OK 按钮。 现在你已经 准 备好来编写一个 OpenGL 视窗程序 了 。
注意 #1:许多编译器没有定义CDS_FULLSCREEN。如果得到关于CDS_FULLSCREEN的错误警告,必须在程序顶部添加下 面 一行: #define CDS_FULLSCREEN 4。
注意#2:写首批教程时,GLAUX是要遵循的途径。随着时间推移, 对 GLAUX的支持取消 了 。但该站的许多教程仍使用旧版的GLAUX代码。如果你的编译器不支持GLAUX,或者你不愿使用它,从主页(左边菜单)下载 GLAUX REPLACEMENT CODE。
代码的前4行包含了我们所需库的头文件, 如下:
#include <windows.h> // Header File For 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
然后我们需要初始化所有要用的变量。 因为这个程序仅仅创建一个空的 OpenGL 窗口, 所以需要初始化的变量并不多。 这为数不多的变量的初始化工作是十分重要的, 它们将在以后的每个 OpenGL 程序中被沿用。
下 面 第一行代码设置一个 Rendering Context (渲染描述表,着色描述表,渲染上下文), 每一个 OpenGL 程序都会连接一个 Rendering Context, Rendering Context 将 OpenGL调用 连接到 Device Context (设备描述表,设备上下文)。OpenGL Rendering Context 在这里被定义为 hRC。 要在窗口中进行绘 制 我们还需要创建一个 Device Context, 这是第二行代码所做的事情, Windows Device Context 在这里被定义为 hDC。 DC 将窗口连接到 GDI (Graphics Device Interface, 图形设备接口), 而 RC 将 OpenGL 连接到 DC。
第三行代码中的 hWnd 变量用于保存 Windows 分配给我们的窗口句柄, 而第四行创立应用程序的一个实例。
HGLRC hRC=NULL; // Permanent Rendering Context
HDC hDC=NULL; // Private GDI Device Context
HWND hWnd=NULL; // Holds Our Window Handle
HINSTANCE hInstance; // Holds The Instance Of The Application
下 面 第一行代码设置一个用于接收键盘输入的数组。 这只是接收键盘输入的多种方法中的其中一种, 但我 采 用这种方法。 它比较可靠, 而且支持同时按下多个键。
active 变量用于通知我们程序是否被最小化了。 如果窗口被最小化了, 我们可以做任何事情, 挂起程序或者退出程序。 我比较喜欢挂起程序, 当最小化的时候程序在后台不会保持运行状态。
变量fullscreen 意义相当明显,可以反映出我们的程序是否运行于全屏幕模式, 是的话它就为 TRUE; 如果运行于窗口模式, 它就为 FALSE。 将它设成全局变量是十分有用的, 好让每个程序知道其自身是否运行于全屏幕模式。
bool keys[256]; // Array Used For The Keyboard Routine
bool active=TRUE; // Window Active Flag Set To TRUE By Default
bool fullscreen=TRUE; // Fullscreen Flag Set To Fullscreen Mode By Default
下 面 我们需要声明窗口回调函数 WndProc()。 原因是 CreateGLWindow() 函数中有对其的引用, 但是 WndProc() 的函数体定义却又在 CreateGLWindow() 的后 面 。 我们知道在 C 语言中要使用一个函数的话,函数必须在之前已经声明 了 , 所以这里我们要先声明 WndProc(),好让CreateGLWindow()引用WndProc() 。