Lighthouse3d.com >> GLUT Tutorial >> Extras >> Game Mode

根据GLUT官网的说明,GLUT的游戏模式是为开启高性能全屏渲染而设计的.有些GLUT功能像弹出菜单和子窗体会因为增强性能而关闭.本节介绍GLUT的游戏模式.关于这个主题的教程和代码是可用的.由于我找不到官方文档,也没有其它教程关于这个主题,所以我不保证这节所有的内容都是对的.我建了一堆测试例子来尝试分析游戏模式的工作原理,但毕竟不同硬件的测试有限,所以会存在一些偏差和误差状况.如果你在运行本节代码时遇到问题,可以留言给我.如果你已经找到问题所在,希望留言告诉我去修复,感谢.

首先要定义游戏模式的设置,例如全屏.该设置包括屏幕分辨率,像素深度和刷新频率.换句话说,我们可以设置任意分辨率,也就是说,我们并不局限于设置当前分辨率下的全屏模式.
全屏模式的设置是用一个字符串来指定.格式如下:

“WxH:Bpp@Rr”

W - 屏幕宽度的像素

H - 屏幕高度的像素

Bpp - 每个像素的比特数

Rr - 垂直刷新的速率,单位是赫兹(hz)

在进行下一步之前,注意这些设置只是请求到硬件.如果指定的模式是不可用,设置会被忽略.

例如:

"800x600:32@100" - 屏幕大小800x600; 32位真色彩; 100赫兹 垂直刷新

"640x480:16@75" - 屏幕大小640x480; 16位真色彩; 75赫兹

设置好所有组件会有点紧张.虽然我们通常会有清晰的想法关于屏幕分辨率,但有时又会需要一个特别的颜色模型,刷新率是微妙的.幸运的是我们不用设置完所有项.我们留空一些项让GLUT填满它们.下面这字符串模板用来设置需要的全屏设置是允许的:

“WxH”

“WxH:Bpp”

“WxH@Rr”

“@Rr”

“:Bpp”

“Bpp:@Rr”

基本上GLUT可以控制所有组合,只要保持好它们的顺序.所以把每个像素的比特数移到刷新率前面是不允许的.

考虑如果我们只想设置屏幕分辨率但不想关心像素深度和刷新率,这时我们可以写"800x600".

如果我们只想在当前分辨率设置到全屏模式,但不想用32位的像素深度,我们可以写":32".

这些例子不能表达完全屏设置字符串的全部功能.我们可以使用上面演示的任意字符串模板.

首先我们告诉GLUT全屏模式的设置.GLUT的函数glutGameModeString原型如下:

void glutGameModeString(const char *string);

string - 跟以上例子类似的设置字符串

GLUT会验证glutGameModeString的变量.虽然该函数不会返回错误码,但是我们可以检查模式是否ok.GLUT提供了一个函数来检查,在其它可能性中,允许我们检查指定模式的可行性.原型如下:

int glutGameModeGet(GLenum info);

info - 请求的信息

为了检查提供的模式是否有效,info参数会提供一个常量值: GLUT_GAME_MODE_POSSIBLE.

在这个例子中,返回值表示了指定模式的可行性,非零值表示ok.注意GLUT的官网上警告说,即使检查是有效,但也不保证屏幕会成功更新.

假定我们得到一个非零的返回值,我们可以利用glutEnterGameMode函数进入或至少可以尝试进入游戏模式.函数会准确的设置屏幕到指定配置,只要是可行的.原型如下:

void glutEnterGameMode(void);

在main函数中初始化一个GLUT应用程序进入800乘600的游戏模式的话,可以这样设置:

  1. int main(int argc, char **argv)
  2. {
  3. glutInit(&argc, argv);
  4. glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
  5.  
  6. /* glutInitWindowPosition(100,100);
  7. glutInitWindowSize(640,360);
  8. glutCreateWindow("SnowMen from Lighthouse3D");
  9. */
  10. // setting the game mode replaces the above
  11. // calls to set the window size and position.
  12. glutGameModeString("800x600:32");
  13. // enter full screen
  14. if (glutGameModeGet(GLUT_GAME_MODE_POSSIBLE))
  15. glutEnterGameMode();
  16. else {
  17. printf("The select mode is not available\n");
  18. exit();
  19. }
  20.  
  21. // register all callbacks
  22. init();
  23.  
  24. glutMainLoop();
  25.  
  26. return ;
  27. }}

init函数会注册所有OpenGL用于初始化所需的回调函数,我们可以像这样写:

  1. void init() {
  2.  
  3. // register callbacks
  4. glutDisplayFunc(renderScene);
  5. glutReshapeFunc(changeSize);
  6. glutIdleFunc(renderScene);
  7.  
  8. glutIgnoreKeyRepeat();
  9. glutKeyboardFunc(processNormalKeys);
  10. glutSpecialFunc(pressKey);
  11. glutSpecialUpFunc(releaseKey);
  12. glutMouseFunc(mouseButton);
  13. glutMotionFunc(mouseMove);
  14.  
  15. // OpenGL init
  16. glEnable(GL_DEPTH_TEST);
  17. glEnable(GL_CULL_FACE);
  18. }

我们想要程序可以在游戏模式和窗体模式之间切换.下面代码声明了程序以窗体模式启动.用户可以按F1来切换到游戏模式,按F6再切换回窗体模式.这种情况下main函数必须定好窗体属性,注册回调和进入到主循环.

在我们执行代码前,先告知glut离开游戏模式.

void glutLeaveGameMode(void);

该函数会处理用来切换模式的特殊键.下面这个函数演示了需要的操作:

  1. void pressKey(int key, int x, int y) {
  2.  
  3. switch (key) {
  4. ...
  5. case GLUT_KEY_F1:
  6.  
  7. // define resolution, color depth
  8. glutGameModeString("640x480:32");
  9. // enter full screen
  10. if (glutGameModeGet(GLUT_GAME_MODE_POSSIBLE)) {
  11.  
  12. glutEnterGameMode();
  13.  
  14. // register callbacks again
  15. init();
  16. }
  17. break;
  18. case GLUT_KEY_F6:
  19. // return to default window
  20. glutLeaveGameMode();
  21. break;
  22. }
  23. }

在上面函数中有个非常重要的细节,就是当我们用glutEnterGameMode函数进入游戏模式时,我们必须再次注册回调函数,并且重定义OpenGL的上下文.游戏模式就像一个新窗体,拥有不同的OpenGL和GLUT上下文.这会导致窗体模式下的回调函数在游戏模式下失效.为了可以在游戏模式下使用必须重新注册回调函数.除此之外,OpenGL上下文需要重新定义.例如显示列表.

GLUT是一个非常厉害的API(接口库),例如它可以让程序员查询当前事务的属性.GLUT有一个特殊的函数来查询游戏模式的状态设置,glutGameModeGet.该函数的原型在上面已经介绍过,在我们提及适合的变量值GLUT_GAME_MODE_POSSIBLE的时候.

这里有几个会用到的变量提供给 glutGameModeGet,覆盖了所有正确游戏模式编程的需求.各种情况的返回值如下:

GLUT_GAME_MODE_ACTIVE - 如果程序正运行在游戏模式下,glutGameModeGet会返回非零值,如果在窗体模式下会返回0.

GLUT_GAME_MODE_POSSIBLE - 上面已经说过了,这个是用来测试游戏模式设置的配置字符串的.最好在进入游戏模式前调用glutGameModeGet获取该值.

GLUT_GAME_MODE_DISPLAY_CHANGED - 上面已经说过了,进入游戏模式时不能保证显示模式真的被改变了.该值可以用于测试是否真的进入了游戏模式.如果已经处于游戏模式下,我们也可以利用该值来检测设置是否被改变.

GLUT_GAME_MODE_WIDTH - 返回屏幕的宽度

GLUT_GAME_MODE_HEIGHT - 返回屏幕的高度

GLUT_GAME_MODE_PIXEL_DEPTH - 返回当前模式每个像素使用的比特数

GLUT_GAME_MODE_REFRESH - 实际刷新率,单位是赫兹(Hz)

最后4个选项只有在游戏模式下有意义.如果最后传入游戏模式设置的字符串无效,这些选项会引发glutGameModeGet返回-1,就算我们已经处于游戏模式下也是.例如如果我们已经以游戏模式运行程序且分辨率是640乘480,如果这是请求更改为1600乘1200,实际硬件配置不支持该模式,GLUT便不会更改分辨率,游戏模式会继续处于640乘480的分辨率下.然而这是如果查询当前高度,会得到-1而不是480,即使实际高度是480.

下面代码演示了glutGameModeGet函数的使用.

  1. if (glutGameModeGet(GLUT_GAME_MODE_ACTIVE) == )
  2. sprintf(currentMode,"Current Mode: Window");
  3. else
  4. sprintf(currentMode,
  5. "Current Mode: Game Mode %dx%d at %d hertz, %d bpp",
  6. glutGameModeGet(GLUT_GAME_MODE_WIDTH),
  7. glutGameModeGet(GLUT_GAME_MODE_HEIGHT),
  8. glutGameModeGet(GLUT_GAME_MODE_REFRESH_RATE),
  9. glutGameModeGet(GLUT_GAME_MODE_PIXEL_DEPTH));

下一节会提供完整代码.

[译]GLUT教程 - 游戏模式的更多相关文章

  1. [译]GLUT教程(目录)

    http://www.lighthouse3d.com/tutorials/glut-tutorial/ GLUT是OpenGL Utility Toolkit的意思.作者Mark J. Kilgar ...

  2. [译]GLUT教程 - 整合代码6

    Lighthouse3d.com >> GLUT Tutorial >> Extras >> The Code So Far VI 下面代码以窗体模式启动.你可以在 ...

  3. [译]GLUT教程 - 位图和正交投影视图

    Lighthouse3d.com >> GLUT Tutorial >> Fonts >> Bitmap Fonts and Orthogonal Projecti ...

  4. [译]GLUT教程 - 子菜单

    Lighthouse3d.com >> GLUT Tutorial >> Pop-up Menus >> Sub Menus 上一节我们介绍了如何创建普通菜单和如果 ...

  5. [译]GLUT教程 - 动画

    Lighthouse3d.com >> GLUT Tutorial >> Basics >> Animation 前面章节我们已经创建了一个白色三角形的窗体.还没到 ...

  6. [译]GLUT教程 - 初始化

    Lighthouse3d.com >> GLUT Tutorial >> Basics >> Initialization 这一节开始从main函数入手.第一步是线 ...

  7. [译]GLUT教程 - glutPostRedisplay函数

    Lighthouse3d.com >> GLUT Tutorial >> Avoiding the Idle Func >> glutPostRedisplay 直 ...

  8. [译]GLUT教程 - 安装

    Lighthouse3d.com >> GLUT Tutorial >> Basics >> Setup 你需要什么 要用GLUT库开发程序,你可以下载最新版本3. ...

  9. [译]GLUT教程 - 整合代码8

    Lighthouse3d.com >> GLUT Tutorial >> Avoiding the Idle Func >> The Code So Far VII ...

随机推荐

  1. 分层图【p4568】 [JLOI2011]飞行路线

    Description Alice和Bob现在要乘飞机旅行,他们选择了一家相对便宜的航空公司.该航空公司一共在nn个城市设有业务,设这些城市分别标记为\(0\)到\(n−1\),一共有\(m\)种航线 ...

  2. -------------》》》【Vim】vim的一些简单配置~

    在linux下使用   :vsp ~/.vimrc   来打开配置文件 一些命令[任何命令前加上   !    强制执行]: :w     保存 :wq    保存退出 :q     退出 ctrl ...

  3. 四. Java继承和多态6. 多态对象的类型转换

    这里所说的对象类型转换,是指存在继承关系的对象,不是任意类型的对象.当对不存在继承关系的对象进行强制类型转换时,java 运行时将抛出 java.lang.ClassCastException 异常. ...

  4. 用swift开发自己的MacOS锁屏软件(3)

    前两篇中实现了MacOS端的锁屏软件,现在需要再实现一个移动端的app用来实现和mac的通信,以后的文章可能就会两个项目来回穿插了. 写完MacOS的软件又回来接着写iOS真的是享受,看着堆积如山的各 ...

  5. Redis2.8.7配置文件说明

    Redis master配置文件说明 daemonize no 默认情况下,redis不是在后台运行的,如果需要在后台运行,把该项的值更改为yes daemonize yes # 当redis在后台运 ...

  6. Visio中插入公式

    也可以直接插入MathType公式,我原来的word不显示MathType,现在显示了,不过插入后太小,那是因为字体小,拖动托大就行. 在word中插入-对象-公式3.0对象(安装MathType后, ...

  7. JAVA常见算法题(十)

    package com.xiaowu.demo; /** * 一球从100米高度自由落下,每次落地后反跳回原高度的一半:再落下……求它在第10次落地时,共经过多少米?第10次反弹多高? * * @au ...

  8. [置顶] docker web-GUI DockerUI和Shipyard对比

    DockerUI和Shipyard对比 相似 基于Docker API,提供等同Docker命令行的大部分功能,支持container管理,image管理. web页面查看和管理容器和镜像,均能批量管 ...

  9. 用js怎么控制submit提交表单

    需求: 1. 要在点击submit按钮的时候,弹出一个询问框,"你确定要修改?".如果按了"确定"那么就提交表单,否则就保留在原页面,既不提交不跳转. 2. 要 ...

  10. ES6里关于字符串的拓展

    一.子串识别 自从 JS 引入了 indexOf() 方法,开发者们就使用它来识别字符串是否存在于其它字符串中.ES6 包含了以下三个方法来满足这类需求: 1.includes():该方法在给定文本存 ...