/* * FTGLDemo - advanced demo for FTGL, the OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "config.h" #include #include #include #if defined HAVE_GL_GLUT_H # include #elif defined HAVE_GLUT_GLUT_H # include #else # error GLUT headers not present #endif #include #include "tb.h" // YOU'LL PROBABLY WANT TO CHANGE THESE #if defined FONT_FILE char const *defaultFonts[] = { FONT_FILE }; const int NumDefaultFonts = 1; #elif defined __APPLE_CC__ char const *defaultFonts[] = { "/System/Library/Fonts/Helvetica.dfont", "/System/Library/Fonts/Geneva.dfont" }; const int NumDefaultFonts = 2; #elif defined WIN32 char const *defaultFonts[] = { "C:\\WINNT\\Fonts\\arial.ttf" }; const int NumDefaultFonts = 1; #else // Put your font files here if configure did not find any. char const *defaultFonts[] = { }; const int NumDefaultFonts = 0; #endif /* Set this to 1 to build a Mac os app (ignore the command line args). */ #ifndef IGNORE_ARGV # define IGNORE_ARGV 0 #endif /* IGNORE_ARGV */ #define EDITING 1 #define INTERACTIVE 2 #define FTGL_BITMAP 0 #define FTGL_PIXMAP 1 #define FTGL_OUTLINE 2 #define FTGL_POLYGON 3 #define FTGL_EXTRUDE 4 #define FTGL_TEXTURE 5 const int NumStyles = 6; char const * const *fontfiles; int current_font = FTGL_EXTRUDE; GLint w_win = 640, h_win = 480; int mode = INTERACTIVE; int carat = 0; FTSimpleLayout simpleLayout; FTLayout *layouts[] = { &simpleLayout, NULL }; int currentLayout = 0; const int NumLayouts = 2; const float InitialLineLength = 300.0f; const float OX = -100; const float OY = 200; //wchar_t myString[16] = { 0x6FB3, 0x9580}; char myString[4096]; int totalFonts; static FTFont** fonts; static FTPixmapFont* infoFont; void SetCamera(void); inline int GetStyle() { return current_font % NumStyles; } inline int GetFace() { return current_font / NumStyles; } void setUpLighting() { // Set up lighting. float light1_ambient[4] = { 1.0, 1.0, 1.0, 1.0 }; float light1_diffuse[4] = { 1.0, 0.9, 0.9, 1.0 }; float light1_specular[4] = { 1.0, 0.7, 0.7, 1.0 }; float light1_position[4] = { -1.0, 1.0, 1.0, 0.0 }; glLightfv(GL_LIGHT1, GL_AMBIENT, light1_ambient); glLightfv(GL_LIGHT1, GL_DIFFUSE, light1_diffuse); glLightfv(GL_LIGHT1, GL_SPECULAR, light1_specular); glLightfv(GL_LIGHT1, GL_POSITION, light1_position); glEnable(GL_LIGHT1); float light2_ambient[4] = { 0.2, 0.2, 0.2, 1.0 }; float light2_diffuse[4] = { 0.9, 0.9, 0.9, 1.0 }; float light2_specular[4] = { 0.7, 0.7, 0.7, 1.0 }; float light2_position[4] = { 1.0, -1.0, -1.0, 0.0 }; glLightfv(GL_LIGHT2, GL_AMBIENT, light2_ambient); glLightfv(GL_LIGHT2, GL_DIFFUSE, light2_diffuse); glLightfv(GL_LIGHT2, GL_SPECULAR, light2_specular); glLightfv(GL_LIGHT2, GL_POSITION, light2_position); //glEnable(GL_LIGHT2); float front_emission[4] = { 0.3, 0.2, 0.1, 0.0 }; float front_ambient[4] = { 0.2, 0.2, 0.2, 0.0 }; float front_diffuse[4] = { 0.95, 0.95, 0.8, 0.0 }; float front_specular[4] = { 0.6, 0.6, 0.6, 0.0 }; glMaterialfv(GL_FRONT, GL_EMISSION, front_emission); glMaterialfv(GL_FRONT, GL_AMBIENT, front_ambient); glMaterialfv(GL_FRONT, GL_DIFFUSE, front_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, front_specular); glMaterialf(GL_FRONT, GL_SHININESS, 16.0); glColor4fv(front_diffuse); glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE); glEnable(GL_CULL_FACE); glColorMaterial(GL_FRONT, GL_DIFFUSE); glEnable(GL_COLOR_MATERIAL); glEnable(GL_LIGHTING); glShadeModel(GL_SMOOTH); } void setUpFonts(int numFontFiles) { // The total number of fonts is styles * faces totalFonts = numFontFiles*NumStyles; // Allocate an array to hold all fonts fonts = new FTFont *[totalFonts]; // Instantiate and configure named fonts for(int i = 0; i < numFontFiles; i++) { fonts[i*NumStyles + FTGL_BITMAP] = new FTBitmapFont(fontfiles[i]); fonts[i*NumStyles + FTGL_PIXMAP] = new FTPixmapFont(fontfiles[i]); fonts[i*NumStyles + FTGL_OUTLINE] = new FTOutlineFont(fontfiles[i]); fonts[i*NumStyles + FTGL_POLYGON] = new FTPolygonFont(fontfiles[i]); fonts[i*NumStyles + FTGL_EXTRUDE] = new FTExtrudeFont(fontfiles[i]); fonts[i*NumStyles + FTGL_TEXTURE] = new FTTextureFont(fontfiles[i]); for(int x = 0; x < NumStyles; ++x) { int j = i * NumStyles + x; if(fonts[j]->Error()) { fprintf(stderr, "Failed to open font %s\n", fontfiles[i]); exit(1); } if(!fonts[j]->FaceSize(24)) { fprintf(stderr, "Failed to set size\n"); exit(1); } fonts[j]->Depth(20); fonts[j]->CharMap(ft_encoding_unicode); } } infoFont = new FTPixmapFont(fontfiles[0]); if(infoFont->Error()) { fprintf(stderr, "Failed to open font %s\n", fontfiles[0]); exit(1); } infoFont->FaceSize(18); strcpy(myString, "OpenGL is a powerful software interface for graphics " "hardware that allows graphics programmers to produce high-quality " "color images of 3D objects. abcdefghijklmnopqrstuvwxyzABCDEFGHIJKL" "MNOPQRSTUVWXYZ0123456789"); } void renderFontmetrics() { FTBBox bbox; float x1, y1, z1, x2, y2, z2; // If there is a layout, use it to compute the bbox, otherwise query as // a string. if(layouts[currentLayout]) bbox = layouts[currentLayout]->BBox(myString); else bbox = fonts[current_font]->BBox(myString); x1 = bbox.Lower().Xf(); y1 = bbox.Lower().Yf(); z1 = bbox.Lower().Zf(); x2 = bbox.Upper().Xf(); y2 = bbox.Upper().Yf(); z2 = bbox.Upper().Zf(); // Draw the bounding box glDisable(GL_LIGHTING); glDisable(GL_TEXTURE_2D); glEnable(GL_LINE_SMOOTH); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE); // GL_ONE_MINUS_SRC_ALPHA glColor3f(0.0, 1.0, 0.0); // Draw the front face glBegin(GL_LINE_LOOP); glVertex3f(x1, y1, z1); glVertex3f(x1, y2, z1); glVertex3f(x2, y2, z1); glVertex3f(x2, y1, z1); glEnd(); // Draw the back face if((GetStyle() == FTGL_EXTRUDE) && (z1 != z2)) { glBegin(GL_LINE_LOOP); glVertex3f(x1, y1, z2); glVertex3f(x1, y2, z2); glVertex3f(x2, y2, z2); glVertex3f(x2, y1, z2); glEnd(); // Join the faces glBegin(GL_LINES); glVertex3f(x1, y1, z1); glVertex3f(x1, y1, z2); glVertex3f(x1, y2, z1); glVertex3f(x1, y2, z2); glVertex3f(x2, y2, z1); glVertex3f(x2, y2, z2); glVertex3f(x2, y1, z1); glVertex3f(x2, y1, z2); glEnd(); } // Render layout-specific metrics if(!layouts[currentLayout]) { // There is no layout. Draw the baseline, Ascender and Descender glBegin(GL_LINES); glColor3f(0.0, 0.0, 1.0); glVertex3f(0.0, 0.0, 0.0); glVertex3f(fonts[current_font]->Advance(myString), 0.0, 0.0); glVertex3f(0.0, fonts[current_font]->Ascender(), 0.0); glVertex3f(0.0, fonts[current_font]->Descender(), 0.0); glEnd(); } else if (layouts[currentLayout] && (dynamic_cast (layouts[currentLayout]))) { float lineWidth = ((FTSimpleLayout *)layouts[currentLayout])->GetLineLength(); // The layout is a SimpleLayout. Render guides that mark the edges // of the wrap region. glColor3f(0.5, 1.0, 1.0); glBegin(GL_LINES); glVertex3f(0, 10000, 0); glVertex3f(0, -10000, 0); glVertex3f(lineWidth, 10000, 0); glVertex3f(lineWidth, -10000, 0); glEnd(); } // Draw the origin glColor3f(1.0, 0.0, 0.0); glPointSize(5.0); glBegin(GL_POINTS); glVertex3f(0.0, 0.0, 0.0); glEnd(); } void renderFontInfo() { glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0, w_win, 0, h_win); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); // draw mode glColor3f(1.0, 1.0, 1.0); glRasterPos2f(20.0f , h_win - (20.0f + infoFont->Ascender())); switch(mode) { case EDITING: infoFont->Render("Edit Mode"); break; case INTERACTIVE: break; } // draw font type glRasterPos2i(20 , 20); switch(GetStyle()) { case FTGL_BITMAP: infoFont->Render("Bitmap Font"); break; case FTGL_PIXMAP: infoFont->Render("Pixmap Font"); break; case FTGL_OUTLINE: infoFont->Render("Outline Font"); break; case FTGL_POLYGON: infoFont->Render("Polygon Font"); break; case FTGL_EXTRUDE: infoFont->Render("Extruded Font"); break; case FTGL_TEXTURE: infoFont->Render("Texture Font"); break; } glRasterPos2f(20.0f , 20.0f + infoFont->Ascender() - infoFont->Descender()); infoFont->Render(fontfiles[GetFace()]); // If the current layout is a SimpleLayout, output the alignemnt mode if(layouts[currentLayout] && (dynamic_cast (layouts[currentLayout]))) { glRasterPos2f(20.0f , 20.0f + 2*(infoFont->Ascender() - infoFont->Descender())); // Output the alignment mode of the layout switch (((FTSimpleLayout *)layouts[currentLayout])->GetAlignment()) { case FTGL::ALIGN_LEFT: infoFont->Render("Align Left"); break; case FTGL::ALIGN_RIGHT: infoFont->Render("Align Right"); break; case FTGL::ALIGN_CENTER: infoFont->Render("Align Center"); break; case FTGL::ALIGN_JUSTIFY: infoFont->Render("Align Justified"); break; } } } void do_display (void) { switch(GetStyle()) { case FTGL_BITMAP: case FTGL_PIXMAP: case FTGL_OUTLINE: break; case FTGL_POLYGON: glDisable(GL_BLEND); setUpLighting(); break; case FTGL_EXTRUDE: glEnable(GL_DEPTH_TEST); glDisable(GL_BLEND); setUpLighting(); break; case FTGL_TEXTURE: glEnable(GL_TEXTURE_2D); glDisable(GL_DEPTH_TEST); setUpLighting(); glNormal3f(0.0, 0.0, 1.0); break; } glColor3f(1.0, 1.0, 1.0); // If you do want to switch the color of bitmaps rendered with glBitmap, // you will need to explicitly call glRasterPos (or its ilk) to lock // in a changed current color. // If there is an active layout use it to render the font if (layouts[currentLayout]) { layouts[currentLayout]->Render(myString); } else { fonts[current_font]->Render(myString); } renderFontmetrics(); renderFontInfo(); } void display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); SetCamera(); switch(GetStyle()) { case FTGL_BITMAP: case FTGL_PIXMAP: glRasterPos2i((long)(w_win / 2 + OX), (long)(h_win / 2 + OY)); glTranslatef(w_win / 2 + OX, h_win / 2 + OY, 0.0); break; case FTGL_OUTLINE: case FTGL_POLYGON: case FTGL_EXTRUDE: case FTGL_TEXTURE: glTranslatef(OX, OY, 0); tbMatrix(); break; } glPushMatrix(); do_display(); glPopMatrix(); glutSwapBuffers(); } void myinit(int numFontFiles) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClearColor(0.13, 0.17, 0.32, 0.0); glColor3f(1.0, 1.0, 1.0); glEnable(GL_CULL_FACE); glFrontFace(GL_CCW); glEnable(GL_DEPTH_TEST); glEnable(GL_POLYGON_OFFSET_LINE); glPolygonOffset(1.0, 1.0); // ???? SetCamera(); tbInit(GLUT_LEFT_BUTTON); tbAnimate(GL_FALSE); setUpFonts(numFontFiles); // Configure the SimpleLayout simpleLayout.SetLineLength(InitialLineLength); simpleLayout.SetFont(fonts[current_font]); } void parsekey(unsigned char key, int x, int y) { switch (key) { case 27: exit(0); break; case 13: if(mode == EDITING) { mode = INTERACTIVE; } else { mode = EDITING; carat = 0; } break; case '\t': // If current layout is a SimpleLayout, change its alignment properties if(layouts[currentLayout] && (dynamic_cast (layouts[currentLayout]))) { FTSimpleLayout *l = (FTSimpleLayout *)layouts[currentLayout]; // Decrement the layout switch (l->GetAlignment()) { case FTGL::ALIGN_LEFT: l->SetAlignment(FTGL::ALIGN_RIGHT); break; case FTGL::ALIGN_RIGHT: l->SetAlignment(FTGL::ALIGN_CENTER); break; case FTGL::ALIGN_CENTER: l->SetAlignment(FTGL::ALIGN_JUSTIFY); break; case FTGL::ALIGN_JUSTIFY: l->SetAlignment(FTGL::ALIGN_LEFT); break; } } break; default: if(mode == INTERACTIVE) { myString[0] = key; myString[1] = 0; } else { myString[carat] = key; myString[carat + 1] = 0; carat = carat > 2000 ? 2000 : carat + 1; } break; } glutPostRedisplay(); } void parseSpecialKey(int key, int x, int y) { FTSimpleLayout *l = NULL; // If the currentLayout is a SimpleLayout store a pointer in l if(layouts[currentLayout] && (dynamic_cast (layouts[currentLayout]))) { l = (FTSimpleLayout *)layouts[currentLayout]; } switch (key) { case GLUT_KEY_UP: current_font = (GetFace()*NumStyles + (current_font + 1)%NumStyles)%totalFonts; break; case GLUT_KEY_DOWN: current_font = (GetFace()*NumStyles + (current_font + NumStyles - 1)%NumStyles)%totalFonts; break; case GLUT_KEY_LEFT: fonts[current_font]->FaceSize(fonts[current_font]->FaceSize() - 1); break; case GLUT_KEY_RIGHT: fonts[current_font]->FaceSize(fonts[current_font]->FaceSize() + 1); break; case GLUT_KEY_PAGE_UP: current_font = (current_font + NumStyles)%totalFonts; break; case GLUT_KEY_PAGE_DOWN: current_font = (current_font + totalFonts - NumStyles)%totalFonts; break; case GLUT_KEY_HOME: currentLayout = (currentLayout + 1)%NumLayouts; break; case GLUT_KEY_END: currentLayout = (currentLayout + NumLayouts - 1)%NumLayouts; break; case GLUT_KEY_F1: case GLUT_KEY_F10: // If the current layout is simple decrement its line length if (l) l->SetLineLength(l->GetLineLength() - 10.0f); break; case GLUT_KEY_F2: case GLUT_KEY_F11: // If the current layout is simple increment its line length if (l) l->SetLineLength(l->GetLineLength() + 10.0f); break; } // If the current layout is a SimpleLayout, update its font. if(l) { l->SetFont(fonts[current_font]); } glutPostRedisplay(); } void motion(int x, int y) { tbMotion(x, y); } void mouse(int button, int state, int x, int y) { tbMouse(button, state, x, y); } void myReshape(int w, int h) { glMatrixMode (GL_MODELVIEW); glViewport (0, 0, w, h); glLoadIdentity(); w_win = w; h_win = h; SetCamera(); tbReshape(w_win, h_win); } void SetCamera(void) { switch(GetStyle()) { case FTGL_BITMAP: case FTGL_PIXMAP: glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0, w_win, 0, h_win); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); break; case FTGL_OUTLINE: case FTGL_POLYGON: case FTGL_EXTRUDE: case FTGL_TEXTURE: glMatrixMode (GL_PROJECTION); glLoadIdentity (); gluPerspective(90, (float)w_win / (float)h_win, 1, 1000); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(0.0, 0.0, (float)h_win / 2.0f, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); break; } } int main(int argc, char *argv[]) { int numFontFiles; if((argc >= 2) && !IGNORE_ARGV) { fontfiles = (char const * const *)argv + 1; numFontFiles = argc - 1; } else { fontfiles = defaultFonts; numFontFiles = NumDefaultFonts; } if(!fontfiles[0]) { fprintf(stderr, "At least one font file must be specified on the command line\n"); exit(1); } glutInit(&argc, argv); glutInitDisplayMode(GLUT_DEPTH | GLUT_RGB | GLUT_DOUBLE | GLUT_MULTISAMPLE); glutInitWindowPosition(50, 50); glutInitWindowSize(w_win, h_win); glutCreateWindow("FTGL TEST"); glutDisplayFunc(display); glutKeyboardFunc(parsekey); glutSpecialFunc(parseSpecialKey); glutMouseFunc(mouse); glutMotionFunc(motion); glutReshapeFunc(myReshape); glutIdleFunc(display); myinit(numFontFiles); glutMainLoop(); return 0; }