博客转自:http://www.lighthouse3d.com/tutorials/glut-tutorial/bitmap-fonts/
位图字体是一个2维的字体,虽然我们会将它放置在3维的世界内,但是这些字体没有厚度,不可以被旋转或者缩放;只可以被平移。而且,这种字体永远只朝向观测者的视野,就像看着宣传板一样。尽管这些特性是潜在的劣势,但是从另外一方面来看,我们不需要关心如何设置他的朝向使其朝向观测者的视野。
在这个小节,我们将呈现 GLUT 如何将位图字体显示在屏幕上。我们需要使用函数 glutBitmapCharacter 去写一个字符。
void glutBitmapCharacter(void *font, int character) Parameters: font – the name of the font to use (see bellow for a list of what’s available character – what to render, a letter, symbol, number, etc…
The font options available are:
- GLUT_BITMAP_8_BY_13
- GLUT_BITMAP_9_BY_15
- GLUT_BITMAP_TIMES_ROMAN_10
- GLUT_BITMAP_TIMES_ROMAN_24
- GLUT_BITMAP_HELVETICA_10
- GLUT_BITMAP_HELVETICA_12
- GLUT_BITMAP_HELVETICA_18
想要观测各种字体的显示效果,可以尝试将所有字体类型都显示在弹出菜单中。下面的函数输出一个字符到当前光栅位置。
glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,'3');
需要解释一下光栅位置,我们可以通过函数OpenGL库中的 glRasterPos 函数设置光栅位置。
void glRasterPos2f(float x, float y); void glRasterPos3f(float x, float y, float z); Parameters: x, y, z – local coordinates for the text to appear
函数 glutBitmapCharacter 依据字符的宽度在指定位置渲染字符。因此,如果想渲染字符串,需要连续调用 glutBitmapCharacter 函数,将会得到想要的显示效果。下面是渲染字符串的例子
void renderBitmapString( float x, float y, float z, void *font, char *string) { char *c; glRasterPos3f(x, y,z); for (c=string; *c != '\0'; c++) { glutBitmapCharacter(font, *c); } }
完整代码如下
#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 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; 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 != '\0'; c++) { glutBitmapCharacter(font, *c); } } void computePos(float deltaMove) { x += deltaMove * lx * 0.1f; z += deltaMove * lz * 0.1f; } 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(); } } 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; }
显示效果如下