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

直到所有源代码都使用显示函数作为空闲函数.这意味着当没有任何事件要处理的时候GLUT会调用显示函数,也就是说,它会尽可能频繁的调用显示函数.

这个一个建立交互程序的简单方法.当你的回调函数处理完键盘事件后,显示函数会自动被调用,屏幕会被重绘.

我们要做的只是把显示函数和空闲函数注册到同一个回调函数.

如果我们的程序打算以独占的方式运行,或者想要获取测试分数,这是可行的.然而,当我们的程序只是操作系统进程之一时,计算机的资源就会变得不充足.

问题就在于我们的GLUT程序,它过于频繁的调用显示函数,即使已经没有新对象需要渲染.你可以去看下任务管理器中进程的选项卡,你会发现即使帧与帧之间没有渲染更改,我们的GLUT程序仍然会快速消耗CPU资源.GPU资源毫无疑问的也会被消耗.

当我们需要CPU或GPU资源来做其它事的时候我们就会想节省这些资源,保持我们的GLUT程序的占用行为不生效.

要达到这个目的,我们必须选择性的告诉GLUT去调用显示函数.glutPostRedisplay函数就是为了这个用途而设计的.

glutPostRedisplay函数会标记当前窗体来重新显示,它会促使主循环尽快的调用完显示函数.注意它只影响当前窗体(获得焦点的窗体),不是所有窗体.上一个例子有子窗体,我们必须做一些扩展测量来确保工作正常.

首先我们将会为主窗体更改显示函数,改成它可以调用所有子窗体定义的渲染函数.然后我们只需要在主窗体中调用glutPostRedisplay函数,所有的窗体都会被重新渲染.

在主函数中添加:

int main(int argc, char **argv) {

    // init GLUT and create main window
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(,);
glutInitWindowSize(,);
mainWindow = glutCreateWindow("Lighthouse3D - GLUT Tutorial"); // callbacks for main window
glutDisplayFunc(renderScene);
glutReshapeFunc(changeSize);
glutIdleFunc(renderSceneAll);
...

我们打算更改主窗体的显示函数为renderSceneAll,就是上一个空闲函数,我们会先取消空闲函数的原有绑定回调.于是新的main函数如下:

int main(int argc, char **argv) {

    // init GLUT and create main window
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(,);
glutInitWindowSize(,);
mainWindow = glutCreateWindow("Lighthouse3D - GLUT Tutorial"); // callbacks for main window
glutDisplayFunc(renderSceneAll);
glutReshapeFunc(changeSize); // Removing the idle function to save CPU and GPU
//glutIdleFunc(renderSceneAll);
...

现在来看我们要把glutPostRedisplay函数的调用放在哪里.我们只想要在渲染图像有更改的时候调用显示函数.当所有场景处于静止状态,渲染差异化的唯一时刻就是当我们移动镜头的时候.

镜头移动一般是用鼠标键盘,所以我们必须添加glutPostRedisplay的调用到这些事件的回调函数中.

现在就先来改鼠标回调函数.鼠标移动时镜头跟着移动.所以我们会将来的下面这段代码:

void mouseMove(int x, int y) {

    // this will only be true when the left button is down
if (xOrigin >= ) { // update deltaAngle
deltaAngle = (x - xOrigin) * 0.001f; // update camera's direction
lx = sin(angle + deltaAngle);
lz = -cos(angle + deltaAngle);
}
}

改成下面这样:

void mouseMove(int x, int y) {

    // this will only be true when the left button is down
if (xOrigin >= ) { // update deltaAngle
deltaAngle = (x - xOrigin) * 0.001f; // update camera's direction
lx = sin(angle + deltaAngle);
lz = -cos(angle + deltaAngle); // setting the main window as active
//and marking it for redraw
glutSetWindow(mainWindow);
glutPostRedisplay();
}
}

现在轮到键盘回调函数.处理键盘事件的函数叫pressKey.我们会将原来的下面这段代码:

void pressKey(int key, int xx, int yy) {

    switch (key) {
case GLUT_KEY_UP : deltaMove = 0.5f; break;
case GLUT_KEY_DOWN : deltaMove = -0.5f; break;
}
}

改成下面这样:

void pressKey(int key, int xx, int yy) {

    switch (key) {
case GLUT_KEY_UP : deltaMove = 0.5f; break;
case GLUT_KEY_DOWN : deltaMove = -0.5f; break;
} // setting the main window as active
//and marking it for redraw
glutSetWindow(mainWindow);
glutPostRedisplay(); }

不幸的是,我们关闭了键盘重复输入的键盘回调函数,因此以上代码的修改是不够的.pressKey函数只会被调用一次,不是你预期中的按压多久就调用多少次.

幸运的是有一个方法可以解决这个问题.当我们按下键时设置一个非零值的状态变量.稍后我们检查该变量来确定镜头位置是否需要更新.该检查是放在renderSceneAll函数中,所以我们的测试将会放在用户初始按下键的任何地方.

下面是之前例子中renderSceneAll的代码:

// Global render func
void renderSceneAll() { // check for keyboard movement
if (deltaMove) {
computePos(deltaMove);
} renderScene();
renderScenesw1();
renderScenesw2();
renderScenesw3();
}

变量deltaMode在一个键最初被按下的时候会被置非零值.因此我们可以在if条件语句中调用glutPostRedisplay函数,实现如下:

// Global render func
void renderSceneAll() { // check for keyboard movement
if (deltaMove) {
computePos(deltaMove); // set the main window as active and
// ask for a redraw
glutSetWindow(mainWindow);
glutPostRedisplay();
} renderScene();
renderScenesw1();
renderScenesw2();
renderScenesw3();
}

做完以上更改后,我们的显示函数会被重复调用直至deltaMove变量归零.只有当用户松开按键的时候发生,releaseKey函数实现如下:

void releaseKey(int key, int x, int y) {

    switch (key) {
case GLUT_KEY_UP :
case GLUT_KEY_DOWN : deltaMove = ;break;
}
}

下一节会给出完整代码.

[译]GLUT教程 - glutPostRedisplay函数的更多相关文章

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

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

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

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

  3. [译]GLUT教程 - 每秒帧数

    Lighthouse3d.com >> GLUT Tutorial >> Extras >> Frames per Second 你的程序实际上跑得多快? 有时我们 ...

  4. [译]GLUT教程 - 笔划字体

    Lighthouse3d.com >> GLUT Tutorial >> Fonts >> Stroke Fonts 笔划字体是用线条生成的.跟位图字体相反,笔划字 ...

  5. [译]GLUT教程 - 弹出菜单基础

    Lighthouse3d.com >> GLUT Tutorial >> Pop-up Menus >> Popup Menus 弹出菜单也是GLUT的一部分.虽然 ...

  6. [译]GLUT教程 - 鼠标

    Lighthouse3d.com >> GLUT Tutorial >> Input >> The Mouse 上一节我们讨论了怎么用GLUT的键盘函数跟OpenG ...

  7. [译]GLUT教程 - 键盘

    Lighthouse3d.com >> GLUT Tutorial >> Input >> Keyboard GLUT可以让应用程序自动监测键盘输入,包括普通按键和 ...

  8. [译]GLUT教程 - 动画

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

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

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

随机推荐

  1. Android UI 绘制过程浅析(二)onMeasure过程

    前言 View的绘制过程分为 measure.layout.draw三个步骤,接下来对这三个步骤逐一进行研究. measure方法的签名 public final void measure(int w ...

  2. window下乌龟git安装和使用

    一.安装git for windows 首先下载git for windows客户端http://msysgit.github.io/ 安装过程没什么特别的,不停next就ok了 图太多就不继续了~~ ...

  3. python代码中指定时区获取时间方法

    os.environ['TZ'] = 'Asia/Shanghai' os.environ['TZ'] = 'Europe/London' hour_cur = time.strftime('%H')

  4. Fastcgi介绍和php中fastcgi的应用

    先看下FastCgi的一些解释: CGI全称是“通用网关接口”(Common Gateway Interface), 它可以让一个客户端,从网页浏览器向执行在Web服务器上的程序请求数据. CGI描述 ...

  5. MySQL_杭州北仓 12.3-12.7需求活动期间累计下单达到3天及以上的客户_20161212

    #C025_02杭州北仓 12.3-12.7需求活动期间累计下单达到3天及以上的客户明细 SELECT d.*,CASE WHEN 下单天次>=3 THEN "下单超过3天" ...

  6. smarty模板的安装配置

    第一步:下载Smarty模版源码包了    百度一下“Smarty下载”,下载最新版本的Smarty模版第二部:解压缩,将下载好的Smarty包解压缩    右键->解压到当前文件夹...你懂的 ...

  7. CSS BOX模型

    对于box模型概念的理解以及它与决定元素最终尺寸的方式有何关系,是理解如何设定网 页上的元素位置的基础.box模型应用到块级元素.一个随之而来的概念,内联布局模型 定义了如何设定内联元素的位置. 对于 ...

  8. VirtualBox 内的 Ubuntu Server 虚拟机网络配置

    环境: 宿主机:Windows 7,单网卡: 虚拟机:ubuntu-14.04.1-server-amd64: 宿主机上网是连接的路由器,IP 地址是通过 DHCP 服务自动获取的: 基本情况: Ub ...

  9. codevs4919 线段树练习4

    4919 线段树练习4  时间限制: 1 s  空间限制: 128000 KB       题目描述 Description 给你N个数,有两种操作 1:给区间[a,b]内的所有数都增加X 2:询问区 ...

  10. 7.Mybatis关联表查询(这里主要讲的是一对一和一对多的关联查询)

    在Mybatis中的管理表查询这里主要介绍的是一对一和一对多的关联查询的resultMap的管理配置查询,当然你也可以用包装类来实现.不过这里不说,做关联查询的步骤可以简单的总结为以下的几步: 1.分 ...