GLUT教程 - glutPostRedisplay函數

http://www.cnblogs.com/live41/p/3395899.html


[譯]GLUT教程 - glutPostRedisplay函數

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(100,100);
    glutInitWindowSize(800,800);
    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(100,100);
    glutInitWindowSize(800,800);
    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 >= 0) {

        // 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 >= 0) {

        // 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 = 0;break;
    }
}
複製代碼

 

下一節會給出完整代碼.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章