GLUT 窗口模板






4.86/5 (26投票s)
本文详细介绍了如何设置第一个 OpenGL FreeGLUT 窗口,并为您提供 OpenGL 应用程序的模板
Visual C++ 2015 文件
Visual C++ 6 文件(旧)
目录
引言
本程序使用 GLUT 库设置了一个平台无关的 OpenGL 窗口。它可以用于以下方面:
- 通过交互式程序学习 GLUT 和 OpenGL
- 交互式程序
- 文档
- 源代码
- 启动你的第一个 OpenGL 程序
- 将代码用作 OpenGL 应用程序的模板
在下载和运行程序之前,请务必阅读文档的“运行程序”部分。
什么是 OpenGL?
OpenGL 是用于开发可移植二维和三维图形应用程序的最广泛使用的 API 之一。它最初由 Silicon Graphics 于 1992 年开发,目前由 OpenGL ARB(架构审查委员会)控制和维护。ARB 的代表包括 SGI、Microsoft、Apple、nVidia、ATI、Intel、id Software(以创建 DOOM 和 QUAKE 而闻名)以及 3D Labs。
OpenGL 因其易用性、可移植性、稳定性和丰富的文档而成为行业标准和非常受欢迎的 API。根据 OpenGL.org 的说法,OpenGL 是唯一真正开放、厂商中立、跨平台图形标准。
本文最初基于 OpenGL 2.1 撰写,但应与最新的 OpenGL 4.5 版本兼容。我没有找到 4.5 的 dll,因此这里使用的 dll 仍然是 2.1 的。
为什么使用 GLUT?
OpenGL 是一个与窗口系统无关的图形库。这意味着它不处理特定于操作系统的窗口系统操作。这样做的目的是使 OpenGL 能够移植到新的平台。创建渲染窗口和处理事件的任务留给本机窗口系统定义。OpenGL 实用工具包 (GLUT) 旨在弥补这一差距,从而为 OpenGL 程序开发者提供了一个与窗口系统无关的 API。GLUT 支持以下功能:
- 窗口管理
- 事件处理
- 右键菜单
- 渲染字体
- 渲染各种实心和线框对象
- 从复杂的输入设备读取
需要注意的是,GLUT 不是一个功能齐全的窗口工具包。它主要用于学习 OpenGL 和开发简单的 OpenGL 程序。GLUT 简单、易用且小巧。GLUT 库提供 C、C++、FORTRAN 和 Ada 编程绑定。它可以移植到几乎所有 X Window 系统和 Windows 的 OpenGL 实现。
重要提示: GLUT 自 1998 年以来就未更新过。一个更好的替代方案是 FreeGLUT。本文最初基于 GLUT 3.6 版本撰写,现已过渡为与 FreeGLUT 兼容。
为什么需要 GLUT 窗口模板?
考虑到 OpenGL 是一个面向图形应用程序的 API,很明显,渲染图形对象总是需要一个窗口。为了避免每次创建使用 OpenGL 的图形应用程序时都要编写相同的代码,可以使用此程序代码作为模板,让您直接开始关注程序中真正重要的事情。OpenGL GLUT 窗口模板具有以下属性:
- 标题:“GLUT 窗口模板”
- 背景颜色:黑色 (R = 0, G = 0, B = 0)
- 尺寸:宽度 = 480,高度 = 480
- 位置:x = (屏幕宽度 - 窗口宽度) / 2,y = (屏幕高度 - 窗口高度) / 2。这意味着窗口将居中显示在屏幕上。
- 处理键盘、鼠标和显示事件
- 通过命令提示符显示事件发生及其含义
在 Windows 上使用
我强烈建议您查阅官方 OpenGL Wiki 上的说明,了解如何在 Windows、Linux 和 Mac 上开始使用 OpenGL: https://www.opengl.org/wiki/Getting_Started
Visual C++ 2015 (14.0)
如今,使用最新版本的 Visual Studio 启动 OpenGL GLUT 应用程序真是太方便了。您只需要安装 NupenGL.Core nuget 包即可。无需再处理 .h、.lib 和 .dll 文件。因此,请忽略下面的“Visual C++ 6”部分,因为它写于 9 年前,适用于 Visual C++ 6 版本(我们现在是 14 版本!)。
以下是从头开始的简单步骤:
- 打开 Visual Studio 2015 Community Edition
- 创建一个新的 Visual Studio C++ Windows 控制台应用程序
- 保持为空即可
- 安装 NupenGL.Core nuget 包。在 Visual Studio 中,转到“工具”>“NuGet 包管理器”>“管理此解决方案的 NuGet 程序包”。搜索“NupenGL”并安装该包。
- 将 *GLUT_Window_Template.c* 添加到您的项目中
- 当前的 NunpenGL.Core nuget 包 (0.0.0.1) 是为与 Visual Studio 2013 配合使用而设计的。需要更新才能在 Visual Studio 2015 中正常运行。如果构建,您会收到此错误:“LNK1104 无法打开文件 'freeglut.lib'”。要解决此问题,请转到“项目属性”,并将“平台工具集”设置为“Visual Studio 2013 (v120)”,这样您就可以在没有问题的情况下进行构建和运行。
Visual C++ 6 (忽略)
运行程序
为了运行程序,需要三个动态链接库 (DLL):*opengl32.dll*、*glu32.dll* 和 *glut32.dll*。*opengl32.dll* 和 *glu32.dll* 文件已随您的 Windows 操作系统一同提供,位于系统文件夹中。要运行可执行文件,您需要下载 *glut32.dll* 并将其复制到与您的 exe 相同的文件夹中,或者放在系统路径中的一个文件夹中。您可以在附加的 ZIP 文件 *GLUT_Window_Template_dll.zip* 的 *Visual C++\dll* 子文件夹中找到所有 DLL 文件。
使用 Microsoft Visual C++ 编译代码
为了在 Windows 平台上使用 Microsoft Visual Studio 编写 C OpenGL 应用程序,您需要以下文件:
- C 头文件:*GL.h*、*GLU.h* 和 *GLUT.h*
- C LIB 文件:*glui32.lib*、*opengl32.lib* 和 *glut32.lib*
您可以在附加的 ZIP 文件 *GLUT_Window_Template_dll.zip* 的 *Visual C++\include\GL* 和 *Visual C++\lib* 子文件夹中找到所有头文件和 LIB 文件。
Microsoft Visual C++ 6
要在 Visual C++ 6.0 环境中使用代码,请执行以下步骤:
- 打开 Microsoft Visual C++ 6.0
- 创建一个新的 Win32 控制台应用程序项目
- 将源文件 *GLUT_Window_Template.c* 复制到您的项目文件夹。在我们的例子中,这是 GLUT_Window_Template_src。您可能需要重命名该文件以满足您的程序需求。
- 使用菜单选项 Project\Add To Project\Files 将源文件添加到项目中
- 确保头文件在 include 文件夹中,LIB 文件在 lib 文件夹中,DLL 文件在系统文件夹中。
文件 描述 源文件夹(已附加) 目标文件夹 GL.H、GLU.H、GLUT.H 头文件 Visual C++\include\GL C:\Program Files\Microsoft Visual Studio\VC98\Include\GL OPENGL32.LIB、GLU32.LIB、GLUT32.LIB Lib 文件 Visual C++\lib C:\Program Files\Microsoft Visual Studio\VC98\Lib OPENGL32.DLL、GLU32.DLL、GLUT32.DLL DLL 文件 Visual C++\dll C:\WINDOWS\system32 - 将代码链接到库
为了避免在您创建的每个 Visual C++ 6.0 项目中都设置链接设置,您可以在代码中包含以下代码段,它基本上与上面的操作相同。
// Link the lib files to the program. This is not necessary // if you have added the lib names using Project/Settings/Link #pragma comment (lib, "opengl32.lib") #pragma comment (lib, "glut32.lib") #pragma comment (lib, "glu32.lib")
- 为了避免在您想要运行 OpenGL 窗口时出现控制台窗口,您可以在代码中包含此指令:
#pragma comment( linker,"/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
Using the Code
源代码旨在用作您 OpenGL 应用程序的模板。要在新应用程序中使用它,您可以简单地重命名 C 文件并将其添加到您的 Visual Studio 项目中。
代码解释
应使用以下 include 指令在 GLUT 程序中包含 GLUT 的头文件:
#include <GL/glut.h>
无需包含 `<GL/gl.h>` 或 `<GL/glu.h>`,因为 `<GL/glut.h>` 已经包含了它们。您也可以使用 `<GL/freeglut.h>`。
初始化
以 `glutInit` 开头的函数用于初始化 GLUT 状态。`glutInit` 函数是主要的初始化例程,在一个 GLUT 程序中只能调用一次。不允许在主 `glutInit` 函数调用之前调用不以 `glutInit` 开头的 OpenGL 或 GLUT 函数。但是,可以在主 `glutInit` 函数调用之前调用其他以 `glutInit` 开头的函数。这样做的目的是允许在命令行参数中指定窗口初始化状态,并在与窗口系统协商会话之前。
下面我将展示每个初始化函数的原型、其描述以及我在程序中的用法。
连接到窗口系统
void glutInit(int *argcp, char **argv);
`glutInit` 初始化 GLUT 库并与窗口系统协商会话。
glutInit(&argc, argv);
设置窗口大小
void glutInitWindowSize(int width, int height);
使用 `glutInitWindowSize` 设置将要创建的窗口的初始大小。`width` 和 `height` 参数的值必须大于零。如果未指定值(即未调用该函数),则默认窗口大小为 300 x 300。请注意,窗口系统不一定会遵循此信息。因此,GLUT 程序必须依赖 `glutReshapeFunc` 来确定窗口的实际大小。
// variables representing the window size
int window_width = 240;
int window_height = 240;
// Set the window size
glutInitWindowSize (window_width, window_height);
设置窗口位置
void glutInitWindowPosition(int x, int y);
使用 `glutInitWindowPosition` 设置窗口的初始位置。默认值为 -1 by -1,这意味着窗口系统将确定合适的位置。
// define the window position on screen
int window_x;
int window_y;
//-------------------------------------------------------------------------
// This function sets the window x and y coordinates
// such that the window becomes centered
//-------------------------------------------------------------------------
void centerOnScreen (void)
{
window_x = (glutGet (GLUT_SCREEN_WIDTH) - window_width)/2;
window_y = (glutGet (GLUT_SCREEN_HEIGHT) - window_height)/2;
}
// Set the window position
glutInitWindowPosition (window_x, window_y);
在上面的代码中,我只是简单地将窗口居中显示在屏幕上。`glutGet (GLUT_SCREEN_WIDTH)` 获取屏幕宽度(以像素为单位),`glutGet (GLUT_SCREEN_HEIGHT)` 获取屏幕高度。
设置显示模式
void glutInitDisplayMode(unsigned int mode);
显示模式指定了用于渲染 OpenGL 图形的缓冲区。可以使用逻辑 `OR` 运算符选择多个模式。以下是可选项,已从 GLUT API Version 3 Reference Manual 复制:
模式 | 描述 |
GLUT_INDEX |
位掩码,用于选择颜色索引模式窗口。如果也指定了 `GLUT_RGBA`,则此选项会覆盖它。 |
GLUT_SINGLE |
位掩码,用于选择单缓冲窗口。如果未指定 `GLUT_DOUBLE` 或 `GLUT_SINGLE`,则默认为此项。 |
GLUT_DOUBLE |
位掩码,用于选择双缓冲窗口。如果也指定了 `GLUT_SINGLE`,则此选项会覆盖它。 |
GLUT_ACCUM |
位掩码,用于选择带有累加缓冲区的窗口。 |
GLUT_ALPHA |
位掩码,用于选择带有 Alpha 分量(用于颜色缓冲区)的窗口。 |
GLUT_DEPTH |
位掩码,用于选择带有深度缓冲区的窗口。 |
GLUT_STENCIL |
位掩码,用于选择带有模板缓冲区的窗口。 |
GLUT_MULTISAMPLE |
位掩码,用于选择支持多重采样的窗口。如果多重采样不可用,则会自动选择一个不支持多重采样的窗口。注意:OpenGL 客户端和服务器端实现都必须支持 `GLX_SAMPLE_SGIS` 扩展才能使用多重采样。 |
GLUT_STEREO |
位掩码,用于选择立体窗口。 |
GLUT_LUMINANCE |
位掩码,用于选择具有“亮度”颜色模型的窗口。此模型提供了 OpenGL RGBA 颜色模型的功能,但帧缓冲区中不保留绿色和蓝色分量。相反,每个像素的红色分量会被转换为零到 `glutGet(GLUT_WINDOW_COLORMAP_SIZE)-1` 之间的索引,并在每个窗口的颜色映射表中查找,以确定窗口内像素的颜色。`GLUT_LUMINANCE` 窗口的初始颜色映射被初始化为线性灰度渐变,但可以使用 GLUT 的颜色映射例程进行修改。 |
glutInitDisplayMode (GLUT_RGBA | GLUT_DOUBLE);
要在窗口上显示图形内容,我们需要告诉 GLUT 使用单缓冲还是双缓冲。如果使用单缓冲,我们需要将 `mode` 设置为 `GLUT_SINGLE`(默认)。要显示 OpenGL 内容在窗口上,我们必须调用 `glFlush` OpenGL 函数,该函数将帧缓冲区的 Gopy 复制到窗口上可见的 Gopy。
然而,`GLUT_DOUBLE` 通常是更好的选择,因为它允许更快的图形渲染,并且由于使用了两个连续交换的帧缓冲区而不会出现闪烁。要交换这些缓冲区,我们调用 GLUT 函数 `glutSwapBuffers`。请注意,由于使用了 2 个帧缓冲区而不是 1 个,`GLUT_DOUBLE` 比 `GLUT_SINGLE` 占用更多内存。
创建窗口
int glutCreateWindow(char *name);
使用 `name` 作为标题创建 GLUT 窗口。返回的值是窗口的唯一小型整数标识符。在调用 `glutMainLoop` 函数之前,渲染到已创建的窗口无效,因为窗口尚无法显示。
// variable representing the window title
char *window_title = "GLUT Window Template";
// Create Window
glutCreateWindow (window_title);
创建窗口后,您可能希望将其全屏显示。
// Tells whether to display the window full screen or not
// Press Alt + Esc to exit a full screen.
int full_screen = 0;
// View in full screen if the fullscreen flag is on
if (full_screen)
glutFullScreen ();
设置程序初始状态
这里的目的是设置一些 OpenGL 属性并初始化程序中的任何数据结构。在我们的例子中,我们需要将帧缓冲区清除颜色设置为黑色。这意味着每当我们想要刷新图形时,我们都需要先用黑色画布清除旧的绘图,然后再重绘新的内容。否则,我们的图形将无法正确显示。
//-------------------------------------------------------------------------
// Set OpenGL program initial state.
//-------------------------------------------------------------------------
void init ()
{
// Set the frame buffer clear color to be black.
glClearColor (0.0, 0.0, 0.0, 0.0);
}
`glClearColor` 的参数是 `R`(红色)、`G`(绿色)、`B`(蓝色)和 `A`(Alpha)。Alpha 用于透明度。值范围在 0.0 到 1.0 之间。例如,如果您想将清除颜色设置为灰色(128, 128, 128),则需要将每个分量除以 255 才能获得 `glClearColor` 的正确参数。
设置回调函数
// Set the callback functions
glutDisplayFunc (display);
glutReshapeFunc (reshape);
glutMouseFunc (mouse);
glutMotionFunc (motion);
glutPassiveMotionFunc (pmotion);
glutKeyboardFunc (keyboard);
glutSpecialFunc (special);
这些是最常用的回调函数。要查看 GLUT 支持的其余回调函数,请参考 GLUT API Version 3 Reference Manual。
glutDisplayFunc
//-------------------------------------------------------------------------
// This function is passed to glutDisplayFunc in order to display
// OpenGL contents on the window.
//-------------------------------------------------------------------------
void display (void)
{
// Clear the window or more specifically the frame buffer...
// This happens by replacing all the contents of the frame
// buffer by the clear color (black in our case)
glClear (GL_COLOR_BUFFER_BIT);
// Draw scene
drawObject ();
// Swap contents of backward and forward frame buffers
glutSwapBuffers ();
}
`glClear (GL_COLOR_BUFFER_BIT)` 将清除帧缓冲区,以便可以清晰地重新绘制内容。`glutSwapBuffer` 将后缓冲区的 Gopy 放入窗口上可见的前缓冲区的 Gopy 中。
`drawObject` 函数简单地显示一个二十面体,并告诉我们 `display` 函数当前正在被调用。当 GLUT 确定窗口需要重绘时,将调用窗口的 `display` 回调。GLUT 中的 `display` 回调函数可以通过调用 `glutPostRedisplay` 来显式设置,也可以作为窗口系统报告的窗口损坏的结果隐式设置。GLUT 会将窗口的多个已发布重绘合并,以最大程度地减少调用 `display` 回调的次数。
//-------------------------------------------------------------------------
// Draws our object.
//-------------------------------------------------------------------------
void drawObject ()
{
// Show when are displaying an object
printf ("Displaying object...\n");
// Draw Icosahedron
glutWireIcosahedron ();
}
您将在以下情况下在命令提示符中看到“正在显示对象…”消息:
- `glutPostRedisplay` 在代码中显式调用
- 窗口调整大小后
- 窗口失去焦点然后重新获得焦点时
如果您在其他情况下看到这种情况,请告知我。
glutReshapeFunc
//-------------------------------------------------------------------------
// This function is passed to the glutReshapeFunc and is called
// whenever the window is resized.
//-------------------------------------------------------------------------
void reshape (int w, int h)
{
// Stay updated with the window width and height
window_width = w;
window_height = h;
// Reset viewport
glViewport(0, 0, window_width, window_height);
// Print current width and height on the screen
printf ("Window Width: %d, Window Height: %d.\n",
window_width, window_height);
}
`reshape` 函数将在每次窗口调整大小时以及窗口首次显示在屏幕上时被调用。回调的 `w` 和 `h` 参数以像素为单位指定了新的窗口大小。
我在这里使用 `glViewport` 函数来在窗口大小调整时将绘图区域重置为等于窗口大小。如果您尝试注释掉 `glViewport` 函数,您会注意到绘图内容会保持不变,无论您如何调整窗口大小。但是,调用 `glViewport` 函数将根据窗口大小的变化放大和缩小绘图区域。
glutMouseFunc
当用户按下和释放鼠标按钮时,会生成两个事件:一个用于按下,另一个用于释放。`state` 参数为 `GLUT_UP` 或 `GLUT_DOWN`,分别表示回调是由于释放还是按下引起的。`button` 参数为 `GLUT_LEFT_BUTTON`、`GLUT_MIDDLE_BUTTON` 或 `GLUT_RIGHT_BUTTON` 之一,表示哪个按钮被点击。`x` 和 `y` 参数表示鼠标坐标相对于 GLUT 窗口时鼠标按钮状态的变化。如果菜单附加到窗口的某个按钮,则不会为该按钮生成鼠标回调。将 `NULL` 传递给 `glutMouseFunc` 会禁用鼠标回调的生成。
//-------------------------------------------------------------------------
// This function is passed to the glutMouseFunc and is called
// whenever the mouse is clicked.
//-------------------------------------------------------------------------
void mouse (int button, int state, int x, int y)
{
switch (button)
{
// Left Button Clicked
case GLUT_LEFT_BUTTON:
switch (state)
{
// Pressed
case GLUT_DOWN:
printf ("Mouse Left Button Pressed (Down)...\n");
break;
// Released
case GLUT_UP:
printf ("Mouse Left Button Released (Up)...\n");
break;
}
break;
// Middle Button clicked
case GLUT_MIDDLE_BUTTON:
switch (state)
{
// Pressed
case GLUT_DOWN:
printf ("Mouse Middle Button Pressed (Down)...\n");
break;
// Released
case GLUT_UP:
printf ("Mouse Middle Button Released (Up)...\n");
break;
}
break;
// Right Button Clicked
case GLUT_RIGHT_BUTTON:
switch (state)
{
// Pressed
case GLUT_DOWN:
printf ("Mouse Right Button Pressed (Down)...\n");
break;
// Released
case GLUT_UP:
printf ("Mouse Right Button Released (Up)...\n");
break;
}
break;
}
}
为了在鼠标事件发生时检查 Shift、Ctrl 或 Alt 键是否被按下,我们可以使用 `glutGetModifiers` 函数。它返回输入事件(键盘、特殊键或鼠标回调)生成时修改键的状态。修饰键是 `GLUT_ACTIVE_SHIFT`(Shift 或 Caps Lock)、`GLUT_ACTIVE_CTRL`(Ctrl)和 `GLUT_ACTIVE_ALT`(Alt)。
glutMotionFunc
只要用户在按下按钮的同时移动鼠标(即拖动),此事件就会连续调用。
//-------------------------------------------------------------------------
// This function is passed to the glutMotionFunc and is called
// whenever the mouse is dragged.
//-------------------------------------------------------------------------
void motion (int x, int y)
{
// Print the mouse drag position
printf ("Mouse Drag Position: %d, %d.\n", x, y);
}
glutPassiveMotionFunc
只要用户在未按下按钮的情况下移动鼠标,此事件就会连续调用。
//-------------------------------------------------------------------------
// This function is passed to the glutPassiveMotionFunc and is called
// whenever the mouse is moved.
//-------------------------------------------------------------------------
void pmotion (int x, int y)
{
// Print mouse move position
printf ("Mouse Move Position: %d, %d.\n", x, y);
}
glutKeyboardFunc
每个生成 ASCII 字符的按键都会生成一个键盘回调。`key` 回调参数是生成的 ASCII 字符。`x` 和 `y` 回调参数表示按键时窗口相对坐标中的鼠标位置。将 `NULL` 传递给 `glutKeyboardFunc` 会禁用键盘回调的生成。
//-------------------------------------------------------------------------
// This function is passed to the glutKeyboardFunc and is called
// whenever the user hits a key.
//-------------------------------------------------------------------------
void keyboard (unsigned char key, int x, int y)
{
// Print what key the user is hitting
printf ("User is hitting the '%c' key.\n", key);
printf ("ASCII code is %d.\n", key);
switch (key)
{
// User hits A key
case 'a':
break;
// User hits Shift + A key
case 'A':
break;
// User hits Enter
case 13:
printf ("User is hitting the Return key.\n");
break;
// User hits Space
case 32:
printf ("User is hitting the Space key.\n");
break;
// User hits back space
case 8:
printf ("User is hitting the Back Space key.\n");
break;
// User hits ESC key
case 27:
exit (1);
break;
}
glutPostRedisplay ();
}
为了在按下 ASCII 键时检查 Shift、Ctrl 或 Alt 键是否被按下,我们可以使用 `glutGetModifiers` 函数。此外,修饰键也可能影响 ASCII 字符本身。例如,如果 Caps Lock 关闭,我们按下 Shift + A 键,`key` 参数的值将设置为 `A`。如果只按下 A 键,则 `key` 参数设置为 `a`。
glutSpecialFunc
//-------------------------------------------------------------------------
// This function is passed to the glutSpecialFunc and is called
// whenever the user hits a special key.
//-------------------------------------------------------------------------
void special (int key, int x, int y)
{
switch (key)
{
case GLUT_KEY_F1 :
printf ("F1 function key.\n");
break;
case GLUT_KEY_F2 :
printf ("F2 function key. \n");
break;
case GLUT_KEY_F3 :
printf ("F3 function key. \n");
break;
case GLUT_KEY_F4 :
printf ("F4 function key. \n");
break;
case GLUT_KEY_F5 :
printf ("F5 function key. \n");
break;
case GLUT_KEY_F6 :
printf ("F6 function key. \n");
break;
case GLUT_KEY_F7 :
printf ("F7 function key. \n");
break;
case GLUT_KEY_F8 :
printf ("F8 function key. \n");
break;
case GLUT_KEY_F9 :
printf ("F9 function key. \n");
break;
case GLUT_KEY_F10 :
printf ("F10 function key. \n");
break;
case GLUT_KEY_F11 :
printf ("F11 function key. \n");
break;
case GLUT_KEY_F12 :
printf ("F12 function key. \n");
break;
case GLUT_KEY_LEFT :
printf ("Left directional key. \n");
break;
case GLUT_KEY_UP :
printf ("Up directional key. \n");
break;
case GLUT_KEY_RIGHT :
printf ("Right directional key. \n");
break;
case GLUT_KEY_DOWN :
printf ("Down directional key. \n");
break;
case GLUT_KEY_PAGE_UP :
printf ("Page up directional key. \n");
break;
case GLUT_KEY_PAGE_DOWN :
printf ("Page down directional key. \n");
break;
case GLUT_KEY_HOME :
printf ("Home directional key. \n");
break;
case GLUT_KEY_END :
printf ("End directional key. \n");
break;
case GLUT_KEY_INSERT :
printf ("Inset directional key. \n");
break;
}
glutPostRedisplay ();
}
每个生成非 ASCII 字符的按键都会生成一个特殊回调。`x` 和 `y` 回调参数表示按键时窗口相对坐标中的鼠标位置。将 `NULL` 传递给 `glutSpecialFunc` 会禁用特殊回调的生成。以下是 GLUT API Version 3 Reference Manual 中指定的特殊键列表:
键 | 描述 |
GLUT_KEY_F1 |
F1 功能键。 |
GLUT_KEY_F2 |
F2 功能键。 |
GLUT_KEY_F3 |
F3 功能键。 |
GLUT_KEY_F4 |
F4 功能键。 |
GLUT_KEY_F5 |
F5 功能键。 |
GLUT_KEY_F6 |
F6 功能键。 |
GLUT_KEY_F7 |
F7 功能键。 |
GLUT_KEY_F8 |
F8 功能键。 |
GLUT_KEY_F9 |
F9 功能键。 |
GLUT_KEY_F10 |
F10 功能键。 |
GLUT_KEY_F11 |
F11 功能键。 |
GLUT_KEY_F12 |
F12 功能键。 |
GLUT_KEY_LEFT |
左方向键。 |
GLUT_KEY_UP |
上方向键。 |
GLUT_KEY_RIGHT |
右方向键。 |
GLUT_KEY_DOWN |
下方向键。 |
GLUT_KEY_PAGE_UP |
Page Up 方向键。 |
GLUT_KEY_PAGE_DOWN |
Page Down 方向键。 |
GLUT_KEY_HOME |
Home 方向键。 |
GLUT_KEY_END |
End 方向键。 |
GLUT_KEY_INSERT |
Insert 方向键。 |
开始事件处理
void glutMainLoop(void);
在 GLUT 程序完成初始设置(例如创建窗口和菜单)后,GLUT 程序通过调用 `glutMainLoop` 进入 GLUT 事件处理循环。此函数在一个 OpenGL 程序中最多只能调用一次。
结论
我认为这篇文章可以极大地帮助您开始使用 OpenGL。同时,该模板可用于节省大量从旧项目或互联网复制粘贴的时间。如果您觉得此模板有用或有任何建议,请告诉我。
参考文献
修订历史
8/10/2015
- 提高对 GLUT 应被 FreeGlut 取代的认识
- 展示如何轻松地在 Visual Studio 2015 Community Edition 和 Nupengl Nuget 包中进行设置
26/07/2007
- 应作者要求转载文章
2007 年 7 月中旬
- 应作者要求删除文章
02/07/2007
- 添加了参考文献部分
06/06/2007
- 修改文章以符合 Marc Clifton 在“A Guide To Writing Articles For Code Project”中指定的标准。
- 在代码模板中添加了常用回调函数
21/05/2005:
- 原始文章发布