• GLUT Tutorials 13:位图字体和正交投影


    博客转自:http://www.lighthouse3d.com/tutorials/glut-tutorial/bitmap-fonts-and-orthogonal-projections/

    位图字体的通常使用是在2维空间给用户提供信息。例如,一个简单的例子就是当我们想去显示应用程序的帧率的时候。显示信息应当出现在屏幕上的固定位置,即使在用户移动相机视野时候。利用正交投影很容易计算位图字体的位置,而不是依靠透视投影,因为我们可以阐明像素的位置。

    基本的概略流程就是在透视投影模式下去绘制世界,之后,切换到正交投影去绘制字体,之后在切换回透视投影模式即可。接下俩的模板就是一个渲染函数去实现这个效果。

    void renderScene() {
    
    // do everything we need to render the world as usual
        ...
    
        setOrthographicProjection();
    
        glPushMatrix();
        glLoadIdentity();
        renderBitmapString(5,30,GLUT_BITMAP_HELVETICA_18,"Lighthouse3D");
        glPopMatrix();
    
        restorePerspectiveProjection();
    
        glutSwapBuffers();
    }

    这两个函数 setOrthograpicProjection 和 restorePerspectiveProjection 在下面呈现。第一个函数 改变矩阵模式到 GL_PROJECTION,意味着我们正在相机上工作。之后,我们并保存先前的透视投影设置,方便绘制字体后可以恢复。之后设置 GL_PROJECTION 矩阵为单位矩阵,利用gluOrtho声明正交投影。

    这个函数的参数表明x和y的范围,围绕Y周反转之后平移操作。平移中的负值是向下,其实就是平移原点到左上角。这种方式使在屏幕坐标上写字符很容易。

    The variables w and h we’re computed elsewhere (see the changeSize function in the source code).

    void setOrthographicProjection() {
    
        // switch to projection mode
        glMatrixMode(GL_PROJECTION);
    
        // save previous matrix which contains the
        //settings for the perspective projection
        glPushMatrix();
    
        // reset matrix
        glLoadIdentity();
    
        // set a 2D orthographic projection
        gluOrtho2D(0, w, 0, h);
    
        // invert the y axis, down is positive
        glScalef(1, -1, 1);
    
        // mover the origin from the bottom left corner
        // to the upper left corner
        glTranslatef(0, -h, 0);
    
        // switch back to modelview mode
        glMatrixMode(GL_MODELVIEW);
    }

    A faster way to perform the ortho projection is as follows. The idea is to set the projection in such a way that no scale and translation are required.

    void setOrthographicProjection() {
    
        // switch to projection mode
        glMatrixMode(GL_PROJECTION);
    
        // save previous matrix which contains the
        //settings for the perspective projection
        glPushMatrix();
    
        // reset matrix
        glLoadIdentity();
    
        // set a 2D orthographic projection
        gluOrtho2D(0, w, h, 0);
    
        // switch back to modelview mode
        glMatrixMode(GL_MODELVIEW);
    }

    This function is very simple. Since we saved the settings of the perspective projection before we set the orthographic projection, all we have to do is to change the matrix mode to GL_PROJECTION, pop the matrix, i.e. restore the settings, and finally change the matrix mode again to GL_MODELVIEW.

    void restorePerspectiveProjection() {
    
        glMatrixMode(GL_PROJECTION);
        // restore previous projection matrix
        glPopMatrix();
    
        // get back to modelview mode
        glMatrixMode(GL_MODELVIEW);
    }

    The function above, renderBitmapString, as presented in the previous section will write the characters continuously, without extra spacing, except where a space character appears in the text. In order to add extra spacing we must keep track of where the current raster position is so that we can add the extra spacing to the x coordinate, for example. There are at least two different approaches to keep track of the raster position; one is to compute the current raster position after drawing a bitmap. The second option involves asking the OpenGL state machine what is the current raster position.

    The first approach requires that we know the dimensions of the character. While the maximum height is always constant for a particular font, the width may vary in some fonts. Fortunately GLUT provides a function that returns the width of a character. The function is glutBitmapWidth and the syntax is as follows:

    int glutBitmapWidth(void *font, int character);
    
    Parameters:
    
    font – one of the pre defined fonts in GLUT, see the previous section for the possible values.
    character – the character which we want to know the width

    So for instance if we want a function that writes a string with a certain amount of pixels between each character we can write:

    void renderSpacedBitmapString(
    
                float x,
                float y,
                int spacing,
                void *font,
                char *string) {
    
      char *c;
      int x1=x;
    
      for (c=string; *c != ''; c++) {
    
        glRasterPos2f(x1,y);
        glutBitmapCharacter(font, *c);
        x1 = x1 + glutBitmapWidth(font,*c) + spacing;
      }
    }

    If we want to draw vertical text we can do as follows:

    void renderVerticalBitmapString(
    
                float x,
                float y,
                int bitmapHeight,
                void *font,
                char *string) {
    
      char *c;
      int i;
    
      for (c=string,i=0; *c != ''; i++,c++) {
    
        glRasterPos2f(x, y+bitmapHeight*i);
        glutBitmapCharacter(font, *c);
      }
    }

    The variable bitmapHeight can be easily computed because we know the maximum height of each font, it is the last number in the font name. For instance, GLUT_BITMAP_TIMES_ROMAN_10 is 10 pixels tall.

    One last thing, GLUT has yet another function for bitmap fonts, its glutBitMapLength and it computes the length in pixels of a string. The return value of this function is the sum of the widths for every character in the string. Here goes the syntax:

    int glutBitmapLength(void *font, char *string);
    
    Parameters:
    
    font – one of the pre defined fonts in GLUT, see the previous section for the possible values.
    string – the string which we want to know the length in pixels

    全部代码如下

    #include <stdlib.h>
    #include <stdio.h>
    #include <math.h>
    
    #ifdef __APPLE__
    #include <GLUT/glut.h>
    #else
    #include <GL/glut.h>
    #endif
    
    // angle of rotation for the camera direction
    float angle = 0.0f;
    
    // actual vector representing the camera's direction
    float lx = 0.0f, lz = -1.0f;
    
    // XZ position of the camera
    float x = 0.0f, z = 5.0f;
    
    // the key states. These variables will be zero
    //when no key is being presses
    float deltaAngle = 0.0f;
    float deltaMove = 0;
    int xOrigin = -1;
    
    // Constant definitions for Menus
    #define RED 1
    #define GREEN 2
    #define BLUE 3
    #define ORANGE 4
    
    #define FILL 1
    #define LINE 2
    
    // Pop up menu identifiers
    int fillMenu, fontMenu, mainMenu, colorMenu;
    
    // color for the nose
    float red = 1.0f, blue = 0.5f, green = 0.5f;
    
    // scale of snowman
    float scale = 1.0f;
    
    // menu status
    int menuFlag = 0;
    
    // default font
    void *font = GLUT_BITMAP_TIMES_ROMAN_24;
    
    #define INT_GLUT_BITMAP_8_BY_13 1
    #define INT_GLUT_BITMAP_9_BY_15 2
    #define INT_GLUT_BITMAP_TIMES_ROMAN_10  3
    #define INT_GLUT_BITMAP_TIMES_ROMAN_24  4
    #define INT_GLUT_BITMAP_HELVETICA_10  5
    #define INT_GLUT_BITMAP_HELVETICA_12  6
    #define INT_GLUT_BITMAP_HELVETICA_18  7
    
    int width, height;
    void changeSize(int w, int h) {
    
        // Prevent a divide by zero, when window is too short
        // (you cant make a window of zero width).
        if (h == 0)
            h = 1;
    
        width = w;
        height = h;
    
        float ratio = w * 1.0 / h;
    
        // Use the Projection Matrix
        glMatrixMode(GL_PROJECTION);
    
        // Reset Matrix
        glLoadIdentity();
    
        // Set the viewport to be the entire window
        glViewport(0, 0, w, h);
    
        // Set the correct perspective.
        gluPerspective(45.0f, ratio, 0.1f, 100.0f);
    
        // Get Back to the Modelview
        glMatrixMode(GL_MODELVIEW);
    }
    
    void drawSnowMan() {
    
        glScalef(scale, scale, scale);
        glColor3f(1.0f, 1.0f, 1.0f);
    
        // Draw Body
        glTranslatef(0.0f, 0.75f, 0.0f);
        glutSolidSphere(0.75f, 20, 20);
    
        // Draw Head
        glTranslatef(0.0f, 1.0f, 0.0f);
        glutSolidSphere(0.25f, 20, 20);
    
        // Draw Eyes
        glPushMatrix();
        glColor3f(0.0f, 0.0f, 0.0f);
        glTranslatef(0.05f, 0.10f, 0.18f);
        glutSolidSphere(0.05f, 10, 10);
        glTranslatef(-0.1f, 0.0f, 0.0f);
        glutSolidSphere(0.05f, 10, 10);
        glPopMatrix();
    
        // Draw Nose
        glColor3f(red, green, blue);
        glRotatef(0.0f, 1.0f, 0.0f, 0.0f);
        glutSolidCone(0.08f, 0.5f, 10, 2);
    
        glColor3f(1.0f, 1.0f, 1.0f);
    
    }
    
    void renderBitmapString(
        float x,
        float y,
        float z,
        void *font,
        char *string) {
        char *c;
        glRasterPos3f(x, y, z);
        for (c = string; *c != ''; c++)
        {
            glutBitmapCharacter(font, *c);
        }
    }
    
    void renderSpacedBitmapString(
        float x,
        float y,
        int spacing,
        void *font,
        char *string) 
    {
    
        char *c;
        int x1 = x;
    
        for (c = string; *c != ''; c++)
        {
    
            glRasterPos2f(x1, y);
            glutBitmapCharacter(font, *c);
            x1 = x1 + glutBitmapWidth(font, *c) + spacing;
        }
    }
    
    void renderVerticalBitmapString(
        float x,
        float y,
        int bitmapHeight,
        void *font,
        char *string) 
    {
        char *c;
        int i;
    
        for (c = string, i = 0; *c != ''; i++, c++)
        {
            glRasterPos2f(x, y + bitmapHeight*i);
            glutBitmapCharacter(font, *c);
        }
    }
    
    void computePos(float deltaMove) {
    
        x += deltaMove * lx * 0.1f;
        z += deltaMove * lz * 0.1f;
    }
    
    void setOrthographicProjection()
    {
        // switch to projection mode
        glMatrixMode(GL_PROJECTION);
    
        // save previous matrix which contains the
        //settings for the perspective projection
        glPushMatrix();
    
        // reset matrix
        glLoadIdentity();
    
        // set a 2D orthographic projection
        gluOrtho2D(0, width, 0, height);
    
        // invert the y axis, down is positive
        glScalef(1, -1, 1);
    
        // mover the origin from the bottom left corner
        // to the upper left corner
        glTranslatef(0, -height, 0);
    
        // switch back to modelview mode
        glMatrixMode(GL_MODELVIEW);
    }
    
    void restorePerspectiveProjection() 
    {
        glMatrixMode(GL_PROJECTION);
        // restore previous projection matrix
        glPopMatrix();
    
        // get back to modelview mode
        glMatrixMode(GL_MODELVIEW);
    }
    
    void renderScene(void)
    {
        if (deltaMove)
            computePos(deltaMove);
    
        // Clear Color and Depth Buffers
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
        // Reset transformations
        glLoadIdentity();
        
        // Set the camera
        gluLookAt(x, 1.0f, z,
            x + lx, 1.0f, z + lz,
            0.0f, 1.0f, 0.0f);
    
        // Draw ground
        glColor3f(0.9f, 0.9f, 0.9f);
        glBegin(GL_QUADS);
        glVertex3f(-100.0f, 0.0f, -100.0f);
        glVertex3f(-100.0f, 0.0f, 100.0f);
        glVertex3f(100.0f, 0.0f, 100.0f);
        glVertex3f(100.0f, 0.0f, -100.0f);
        glEnd();
    
        // Draw 36 SnowMen
        char number[3];
        for (int i = -3; i < 3; i++)
        {
            for (int j = -3; j < 3; j++)
            {
                glPushMatrix();
                glTranslatef(i*10.0f, 0.0f, j * 10.0f);
                drawSnowMan();
                sprintf(number, "%d", (i + 3) * 6 + (j + 3));
                renderBitmapString(0.0f, 0.5f, 0.0f, (void *)font, number);
                glPopMatrix();
            }
        }
    
        setOrthographicProjection();
    
        glPushMatrix();
        glLoadIdentity();
        renderBitmapString(5.0, 30.0, 0.0, GLUT_BITMAP_HELVETICA_18, "Fixed Font");
        renderSpacedBitmapString(5.0, 130, 5.0, GLUT_BITMAP_HELVETICA_18, "Fixed Font");
        renderVerticalBitmapString(230.0, 50.0, 30, GLUT_BITMAP_HELVETICA_18, "Fixed Font");
    
        glPopMatrix();
    
        restorePerspectiveProjection();
            
        glutSwapBuffers();
    }
    
    // -----------------------------------
    //             KEYBOARD
    // -----------------------------------
    
    void processNormalKeys(unsigned char key, int xx, int yy)
    {
        switch (key) 
        {
        case 27:
            glutDestroyMenu(mainMenu);
            glutDestroyMenu(fillMenu);
            glutDestroyMenu(colorMenu);
            glutDestroyMenu(fontMenu);
            exit(0);
            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;
        }
    }
    
    void releaseKey(int key, int x, int y)
    {
        switch (key) 
        {
        case GLUT_KEY_UP:
        case GLUT_KEY_DOWN: deltaMove = 0; break;
        }
    }
    
    // -----------------------------------
    //             MOUSE
    // -----------------------------------
    
    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 mouseButton(int button, int state, int x, int y) 
    {
        // only start motion if the left button is pressed
        if (button == GLUT_LEFT_BUTTON) {
    
            // when the button is released
            if (state == GLUT_UP) {
                angle += deltaAngle;
                xOrigin = -1;
            }
            else  {// state = GLUT_DOWN
                xOrigin = x;
            }
        }
    }
    
    // -----------------------------------
    //             MENUS
    // -----------------------------------
    
    void processMenuStatus(int status, int x, int y) 
    {
        if (status == GLUT_MENU_IN_USE)
            menuFlag = 1;
        else
            menuFlag = 0;
    }
    
    void processMainMenu(int option)
    {
        // nothing to do in here
        // all actions are for submenus
    }
    
    void processFillMenu(int option) 
    {
        switch (option) 
        {
        case FILL: glPolygonMode(GL_FRONT, GL_FILL); break;
        case LINE: glPolygonMode(GL_FRONT, GL_LINE); break;
        }
    }
    
    void processFontMenu(int option)
    {
        switch (option)
        {
        case INT_GLUT_BITMAP_8_BY_13:
            font = GLUT_BITMAP_8_BY_13;
            break;
        case INT_GLUT_BITMAP_9_BY_15:
            font = GLUT_BITMAP_9_BY_15;
            break;
        case INT_GLUT_BITMAP_TIMES_ROMAN_10:
            font = GLUT_BITMAP_TIMES_ROMAN_10;
            break;
        case INT_GLUT_BITMAP_TIMES_ROMAN_24:
            font = GLUT_BITMAP_TIMES_ROMAN_24;
            break;
        case INT_GLUT_BITMAP_HELVETICA_10:
            font = GLUT_BITMAP_HELVETICA_10;
            break;
        case INT_GLUT_BITMAP_HELVETICA_12:
            font = GLUT_BITMAP_HELVETICA_12;
            break;
        case INT_GLUT_BITMAP_HELVETICA_18:
            font = GLUT_BITMAP_HELVETICA_18;
            break;
        }
    }
    
    void processColorMenu(int option)
    {
        switch (option) {
        case RED:
            red = 1.0f;
            green = 0.0f;
            blue = 0.0f; break;
        case GREEN:
            red = 0.0f;
            green = 1.0f;
            blue = 0.0f; break;
        case BLUE:
            red = 0.0f;
            green = 0.0f;
            blue = 1.0f; break;
        case ORANGE:
            red = 1.0f;
            green = 0.5f;
            blue = 0.5f; break;
        }
    }
    
    void createPopupMenus() 
    {
        fontMenu = glutCreateMenu(processFontMenu);
    
        glutAddMenuEntry("BITMAP_8_BY_13 ", INT_GLUT_BITMAP_8_BY_13);
        glutAddMenuEntry("BITMAP_9_BY_15", INT_GLUT_BITMAP_9_BY_15);
        glutAddMenuEntry("BITMAP_TIMES_ROMAN_10 ", INT_GLUT_BITMAP_TIMES_ROMAN_10);
        glutAddMenuEntry("BITMAP_TIMES_ROMAN_24", INT_GLUT_BITMAP_TIMES_ROMAN_24);
        glutAddMenuEntry("BITMAP_HELVETICA_10 ", INT_GLUT_BITMAP_HELVETICA_10);
        glutAddMenuEntry("BITMAP_HELVETICA_12", INT_GLUT_BITMAP_HELVETICA_12);
        glutAddMenuEntry("BITMAP_HELVETICA_18", INT_GLUT_BITMAP_HELVETICA_18);
    
        fillMenu = glutCreateMenu(processFillMenu);
    
        glutAddMenuEntry("Fill", FILL);
        glutAddMenuEntry("Line", LINE);
    
        colorMenu = glutCreateMenu(processColorMenu);
        glutAddMenuEntry("Red", RED);
        glutAddMenuEntry("Blue", BLUE);
        glutAddMenuEntry("Green", GREEN);
        glutAddMenuEntry("Orange", ORANGE);
    
        mainMenu = glutCreateMenu(processMainMenu);
    
        glutAddSubMenu("Polygon Mode", fillMenu);
        glutAddSubMenu("Color", colorMenu);
        glutAddSubMenu("Font", fontMenu);
        // attach the menu to the right button
        glutAttachMenu(GLUT_RIGHT_BUTTON);
    
        // this will allow us to know if the menu is active
        glutMenuStatusFunc(processMenuStatus);
    }
    
    // -----------------------------------
    //             MAIN
    // -----------------------------------
    
    int main(int argc, char **argv)
    {
        glutInit(&argc, argv);
        glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
        glutInitWindowPosition(100, 100);
        glutInitWindowSize(320, 320);
        glutCreateWindow("Lighthouse3D - GLUT Tutorial");
    
        // register callbacks
        glutDisplayFunc(renderScene);
        glutReshapeFunc(changeSize);
        glutIdleFunc(renderScene);
    
        glutIgnoreKeyRepeat(1);
        glutKeyboardFunc(processNormalKeys);
        glutSpecialFunc(pressKey);
        glutSpecialUpFunc(releaseKey);
    
        // here are the two new functions
        glutMouseFunc(mouseButton);
        glutMotionFunc(mouseMove);
    
        // OpenGL init
        glEnable(GL_DEPTH_TEST);
        glEnable(GL_CULL_FACE);
    
        // init Menus
        createPopupMenus();
    
        // enter GLUT event processing cycle
        glutMainLoop();
    
        return 1;
    }

    显示效果如下

  • 相关阅读:
    爬取淘宝商品信息
    eclipse 搭建Robotium环境--apk 环境搭建
    android studio2.0 搭建Robotium环境--有被测源代码的情况下
    mysql 特殊语句
    电脑浏览器访问文件夹
    mindmanager 15 停止工作
    yum被lock Existing lock /var/run/yum.pid: another copy is running as pid 1580. Another app is currently holding the yum lock; waiting for it to exi
    jenkins安装及部署
    ant+jmeter
    charles抓包及篡改
  • 原文地址:https://www.cnblogs.com/flyinggod/p/12941641.html
Copyright © 2020-2023  润新知