Changeset 5343 in orxonox.OLD for trunk/src/lib/graphics/text_engine/font.cc
- Timestamp:
- Oct 10, 2005, 12:16:19 AM (19 years ago)
- File:
-
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/lib/graphics/text_engine/font.cc
r5330 r5343 10 10 11 11 ### File Specific: 12 main-programmer: ...12 main-programmer: Benjamin Grauer 13 13 co-programmer: ... 14 14 */ 15 15 16 //#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_ 17 18 #include "proto_class.h" 16 #define DEBUG_SPECIAL_MODULE DEBUG_MODULE_FONT 17 18 #include "font.h" 19 #include "text.h" 20 21 #ifdef HAVE_SDL_IMAGE_H 22 #include <SDL_image.h> 23 #else 24 #include <SDL/SDL_image.h> 25 #endif 26 #include "font.xpm" 27 28 #include "debug.h" 29 #include "compiler.h" 19 30 20 31 using namespace std; 21 32 22 23 /** 24 * standard constructor 25 * @todo this constructor is not jet implemented - do it 26 */ 27 ProtoClass::ProtoClass () 28 { 29 this->setClassID(CL_PROTO_ID, "ProtoClass"); 30 31 /* If you make a new class, what is most probably the case when you write this file 32 don't forget to: 33 1. Add the new file new_class.cc to the ./src/Makefile.am 34 2. Add the class identifier to ./src/class_id.h eg. CL_NEW_CLASS 35 36 Advanced Topics: 37 - if you want to let your object be managed via the ObjectManager make sure to read 38 the object_manager.h header comments. You will use this most certanly only if you 39 make many objects of your class, like a weapon bullet. 40 */ 41 } 42 43 44 /** 45 * standard deconstructor 46 */ 47 ProtoClass::~ProtoClass () 48 { 49 // delete what has to be deleted here 50 } 33 /** 34 * constructs a Font 35 * @param fontFile the File to load the font from 36 * @param fontSize the Size of the Font in Pixels 37 */ 38 Font::Font(const char* fontFile, unsigned int fontSize) 39 { 40 this->init(); 41 42 this->setSize(fontSize); 43 44 if (fontFile != NULL) 45 this->loadFont(fontFile); 46 47 this->setStyle("c");//TTF_STYLE_NORMAL); 48 49 this->fastTextureID = this->createFastTexture(); 50 51 52 // this->createAsciiImage("test.bmp"); 53 } 54 55 /** 56 * constructs a Font 57 * @param fontFile the File to load the font from 58 * @param fontSize the Size of the Font in Pixels 59 */ 60 Font::Font(char** xpmArray) 61 { 62 this->init(); 63 64 // this->setSize(fontSize); 65 SDL_Surface* image = NULL; 66 if (xpmArray != NULL) 67 image = IMG_ReadXPMFromArray(xpmArray); 68 if (image != NULL) 69 { 70 this->loadFontFromSDL_Surface(image); 71 SDL_FreeSurface(image); 72 } 73 else 74 PRINTF(1)("loading from surface failed: %s\n", IMG_GetError()); 75 76 } 77 78 79 /** 80 * destructs a font 81 * this releases the memory a font uses to be opened. 82 * deletes the glLists, and the TTF-handler, if present. 83 */ 84 Font::~Font() 85 { 86 // deleting all Glyphs 87 if (this->glyphArray != NULL) 88 { 89 for (int i = 0; i < FONT_HIGHEST_KNOWN_CHAR; i++) 90 { 91 if (this->glyphArray[i] != NULL) 92 { 93 glDeleteLists(this->glyphArray[i]->displayList, 1); 94 delete this->glyphArray[i]; 95 } 96 } 97 delete[] this->glyphArray; 98 } 99 100 // erease this font out of the memory. 101 if (likely(this->font != NULL)) 102 TTF_CloseFont(this->font); 103 } 104 105 /** 106 * initializes a Font (with default values) 107 */ 108 void Font::init() 109 { 110 this->setClassID(CL_FONT, "Font"); 111 // setting default values. 112 this->font = NULL; 113 this->glyphArray = NULL; 114 this->fastTextureID = 0; 115 } 116 117 118 /** 119 * sets The Font. 120 * @param fontFile The file containing the font. 121 * @returns true if loaded, false if something went wrong, or if a font was loaded before. 122 */ 123 bool Font::loadFont(const char* fontFile) 124 { 125 if (!this->getName()) 126 { 127 this->setName(fontFile); 128 129 this->font = TTF_OpenFont(this->getName(), this->fontSize); 130 if(!this->font) 131 { 132 PRINTF(1)("TTF_OpenFont: %s\n", TTF_GetError()); 133 return false; 134 } 135 else 136 return true; 137 } 138 else 139 { 140 PRINTF(2)("Font already initialized, unable to change it now.\n"); 141 return false; 142 } 143 } 144 145 /** 146 * loads a font From an XPM-array. 147 * @param xpmArray the array of the XPM to load the font from. 148 */ 149 bool Font::loadFontFromSDL_Surface(SDL_Surface* surface) 150 { 151 // loading to a texture. 152 if(surface == NULL) 153 return false; 154 this->fastTextureID = Text::loadTexture(surface, NULL); 155 156 // initializing the Glyphs. 157 if (this->glyphArray == NULL) 158 { 159 float cx,cy; 160 Glyph* glyph; 161 this->glyphArray = new Glyph*[FONT_HIGHEST_KNOWN_CHAR]; 162 for (int i = 0; i < FONT_HIGHEST_KNOWN_CHAR; i++) 163 { 164 glyph = this->glyphArray[i] = new Glyph; 165 glyph->displayList = glGenLists(1); 166 if (!glIsList(glyph->displayList)) 167 { 168 PRINTF(2)("Error creating glList for Font character %c\n", i); 169 this->glyphArray[i] = NULL; 170 delete glyph; 171 continue; 172 } 173 cx=(float)(i%16)/16.0f; // X Position Of Current Character 174 cy=(float)(i/16)/16.0f; // Y Position Of Current Character 175 glNewList(glyph->displayList, GL_COMPILE); // Start Building A List 176 glBegin(GL_QUADS); // Use A Quad For Each Character 177 glTexCoord2f(cx, cy+0.001f); // Texture Coord (Bottom Left) 178 glVertex2d(0,-16); // Vertex Coord (Bottom Left) 179 glTexCoord2f(cx+0.0625f, cy+0.001f); // Texture Coord (Bottom Right) 180 glVertex2i(16,-16); // Vertex Coord (Bottom Right) 181 glTexCoord2f(cx+0.0625f, cy+0.0625f); // Texture Coord (Top Right) 182 glVertex2i(16,0); // Vertex Coord (Top Right) 183 glTexCoord2f(cx, cy+0.0625f); // Texture Coord (Top Left) 184 glVertex2i(0,0); // Vertex Coord (Top Left) 185 glEnd(); // Done Building Our Quad (Character) 186 // glTranslated(12,0,0); // Move To The Right Of The Character 187 glEndList(); // Done Building The Display List 188 this->glyphArray[i]->width = 12; 189 } 190 } 191 return true; 192 } 193 194 195 /** 196 * sets a specific renderStyle 197 * @param renderStyle the Style to render: a char-array containing: 198 i: italic, b: bold, u, underline 199 */ 200 void Font::setStyle(const char* renderStyle) 201 { 202 this->renderStyle = TTF_STYLE_NORMAL; 203 204 for (int i = 0; i < strlen(renderStyle); i++) 205 if (strncmp(renderStyle+i, "b", 1) == 0) 206 this->renderStyle |= TTF_STYLE_BOLD; 207 else if (strncmp(renderStyle+i, "i", 1) == 0) 208 this->renderStyle |= TTF_STYLE_ITALIC; 209 else if (strncmp(renderStyle+i, "u", 1) == 0) 210 this->renderStyle |= TTF_STYLE_UNDERLINE; 211 212 if (likely(this->font != NULL)) 213 TTF_SetFontStyle(this->font, this->renderStyle); 214 else 215 PRINTF(2)("Font was not initialized, please do so before setting the Font-Style.\n"); 216 } 217 218 /** 219 * Sets a new Size to the font 220 * @param fontSize The new Size in pixels. 221 */ 222 void Font::setSize(unsigned int fontSize) 223 { 224 this->fontSize = fontSize; 225 } 226 227 Font* Font::defaultFont = NULL; 228 229 void Font::createAsciiImage(const char* fileName) 230 { 231 if (this->font == NULL) 232 return; 233 int height = this->getMaxHeight(); 234 235 // 236 SDL_Color tmpColor = {0, 0, 0}; 237 // Surface definition. 238 SDL_Rect tmpRect; // this represents a Rectangle for blitting. 239 SDL_Surface* tmpSurf = SDL_CreateRGBSurface(SDL_SWSURFACE, 240 height*16, height*16, 241 32, 242 #if SDL_BYTEORDER == SDL_LIL_ENDIAN /* OpenGL RGBA masks */ 243 0x000000FF, 244 0x0000FF00, 245 0x00FF0000, 246 0xFF000000 247 #else 248 0xFF000000, 249 0x00FF0000, 250 0x0000FF00, 251 0x000000FF 252 #endif 253 ); 254 tmpRect.x = 0; tmpRect.y = 0; tmpRect.w = tmpSurf->w; tmpRect.h = tmpSurf->h; 255 SDL_SetClipRect(tmpSurf, &tmpRect); 256 int maxLineHeight = 0; 257 258 int posX, posY; 259 // all the interessting Glyphs 260 for (posY = 0; posY < 16; posY++) 261 { 262 for (posX = 0; posX < 16; posX++) 263 { 264 SDL_Surface* glyphSurf = NULL; 265 if (likely(this->font != NULL)) 266 { 267 SDL_Color white = {255, 255, 255}; 268 glyphSurf = TTF_RenderGlyph_Blended(this->font, posX+16*posY, white); 269 } 270 if( glyphSurf != NULL ) 271 { 272 tmpRect.x = height*posX; 273 tmpRect.y = height*posY; 274 SDL_SetAlpha(glyphSurf, 0, 0); 275 276 SDL_BlitSurface(glyphSurf, NULL, tmpSurf, &tmpRect); 277 SDL_FreeSurface(glyphSurf); 278 // Outputting Glyphs to BMP-files. 279 /* 280 char outname[512]; 281 if (i < 10) 282 sprintf( outname, "%s-glyph-00%d.bmp", this->getName(), i ); 283 else if (i <100) 284 sprintf( outname, "%s-glyph-0%d.bmp", this->getName(), i ); 285 else 286 sprintf( outname, "%s-glyph-%d.bmp", this->getName(), i ); 287 SDL_SaveBMP(tmpSurf, outname);*/ 288 289 } 290 } 291 } 292 SDL_SaveBMP(tmpSurf, fileName); 293 SDL_FreeSurface(tmpSurf); 294 } 295 296 /** 297 * initializes the default font 298 */ 299 void Font::initDefaultFont() 300 { 301 if (Font::defaultFont == NULL) 302 Font::defaultFont = new Font(font_xpm); 303 } 304 305 /** 306 * deletes the default font 307 */ 308 void Font::removeDefaultFont() 309 { 310 if (Font::defaultFont != NULL) 311 delete Font::defaultFont; 312 Font::defaultFont = NULL; 313 } 314 315 316 /** 317 * @returns the maximum height of the Font, if the font was initialized, 0 otherwise 318 */ 319 int Font::getMaxHeight() 320 { 321 if (likely (this->font != NULL)) 322 return TTF_FontHeight(this->font); 323 else 324 return 0; 325 } 326 327 /** 328 * @returns the maximum ascent of the Font, if the font was initialized, 0 otherwise 329 330 the ascent is the pixels of the font above the baseline 331 */ 332 int Font::getMaxAscent() 333 { 334 if (likely(this->font != NULL)) 335 return TTF_FontAscent(this->font); 336 else 337 return 0; 338 } 339 340 /** 341 * @returns the maximum descent of the Font, if the font was initialized, 0 otherwise 342 343 the descent is the pixels of the font below the baseline 344 */ 345 int Font::getMaxDescent() 346 { 347 if (likely(this->font != NULL)) 348 return TTF_FontDescent(this->font); 349 else 350 return 0; 351 } 352 353 /** 354 * @param character The character to get info about. 355 * @returns a Glyph struct of a character. This Glyph is a pointer, 356 and MUST be deleted by the user.. 357 358 This only works for horizontal fonts. see 359 http://freetype.sourceforge.net/freetype2/docs/tutorial/step2.html 360 for more info about vertical Fonts 361 */ 362 Glyph* Font::getGlyphMetrics(Uint16 character) 363 { 364 Glyph* rg = new Glyph; 365 rg->character = character; 366 if (likely (this->font!= NULL)) 367 TTF_GlyphMetrics(this->font, rg->character, 368 &rg->minX, &rg->maxX, 369 &rg->minY, &rg->maxY, 370 &rg->advance); 371 rg->height = rg->maxY - rg->minY; 372 rg->width = rg->maxX - rg->minX; 373 rg->bearingX = (rg->advance - rg->width) / 2; 374 rg->bearingY = rg->maxY; 375 return rg; 376 } 377 378 /** 379 * creates a Fast-Texture of this Font 380 */ 381 GLuint Font::createFastTexture() 382 { 383 /* interesting GLYPHS: 384 * 32: space 385 * 33-47: Special Characters. 386 * 48-57: 0-9 387 * 58-63: some more special chars (minor) 388 * 65-90: A-Z 389 * 97-122: a-z 390 */ 391 int numberOfGlyphs = 91; 392 393 this->initGlyphs(32, numberOfGlyphs); 394 this->glyphArray[32]->width = fontSize/2; //!< @todo find out the real size of a Space 395 396 int rectSize = this->findOptimalFastTextureSize(); 397 398 // setting default values. (maybe not needed afterwards) 399 SDL_Color tmpColor; tmpColor.r = tmpColor.g = tmpColor.b = 0; 400 // Surface definition. 401 SDL_Rect tmpRect; // this represents a Rectangle for blitting. 402 SDL_Surface* tmpSurf = SDL_CreateRGBSurface(SDL_SWSURFACE, 403 rectSize, rectSize, 404 32, 405 #if SDL_BYTEORDER == SDL_LIL_ENDIAN /* OpenGL RGBA masks */ 406 0x000000FF, 407 0x0000FF00, 408 0x00FF0000, 409 0xFF000000 410 #else 411 0xFF000000, 412 0x00FF0000, 413 0x0000FF00, 414 0x000000FF 415 #endif 416 ); 417 tmpRect.x = 0; tmpRect.y = 0; tmpRect.w = tmpSurf->w; tmpRect.h = tmpSurf->h; 418 SDL_SetClipRect(tmpSurf, &tmpRect); 419 int maxLineHeight = 0; 420 421 // all the interessting Glyphs 422 for (int i = 0; i < 128; i++) 423 { 424 SDL_Surface* glyphSurf = NULL; 425 Glyph* tmpGlyph; 426 427 if (tmpGlyph = this->glyphArray[i]) 428 { 429 if (tmpGlyph->height > maxLineHeight) 430 maxLineHeight = tmpGlyph->height; 431 432 if (tmpRect.x+tmpGlyph->advance > tmpSurf->w) 433 { 434 tmpRect.x = 0; 435 tmpRect.y = tmpRect.y + maxLineHeight + 1; 436 maxLineHeight = 0; 437 } 438 if (tmpRect.y + maxLineHeight > tmpSurf->h) 439 { 440 PRINTF(1)("Protection, so font cannot write over the boundraries error (this should not heappen\n"); 441 break; 442 } 443 // reading in the new Glyph 444 if (likely(this->font != NULL)) 445 { 446 SDL_Color white = {255, 255, 255}; 447 glyphSurf = TTF_RenderGlyph_Blended(this->font, i, white); 448 } 449 if( glyphSurf != NULL ) 450 { 451 SDL_SetAlpha(glyphSurf, 0, 0); 452 453 SDL_BlitSurface(glyphSurf, NULL, tmpSurf, &tmpRect); 454 TexCoord tmpTexCoord; 455 tmpTexCoord.minU = (float)tmpRect.x/(float)tmpSurf->w; 456 tmpTexCoord.maxU = (float)(tmpRect.x + tmpGlyph->advance)/(float)tmpSurf->w; 457 tmpTexCoord.minV = (float)(tmpRect.y)/(float)tmpSurf->w; 458 tmpTexCoord.maxV = (float)(tmpRect.y+tmpGlyph->height)/(float)tmpSurf->w; 459 tmpGlyph->displayList = glGenLists(1); 460 461 glNewList(tmpGlyph->displayList, GL_COMPILE); 462 glBegin(GL_QUADS); 463 glTexCoord2f(tmpTexCoord.minU, tmpTexCoord.minV); 464 glVertex2d(0, - tmpGlyph->bearingY); 465 glTexCoord2f(tmpTexCoord.minU, tmpTexCoord.maxV); 466 glVertex2d(0, tmpGlyph->height - tmpGlyph->bearingY); 467 glTexCoord2f(tmpTexCoord.maxU, tmpTexCoord.maxV); 468 glVertex2d(tmpGlyph->width, tmpGlyph->height - tmpGlyph->bearingY); 469 glTexCoord2f(tmpTexCoord.maxU, tmpTexCoord.minV); 470 glVertex2d(tmpGlyph->width, - tmpGlyph->bearingY); 471 glEnd(); 472 glEndList(); 473 SDL_FreeSurface(glyphSurf); 474 475 tmpRect.x += tmpGlyph->advance; 476 477 // Outputting Glyphs to BMP-files. 478 /* 479 char outname[512]; 480 if (i < 10) 481 sprintf( outname, "%s-glyph-00%d.bmp", this->getName(), i ); 482 else if (i <100) 483 sprintf( outname, "%s-glyph-0%d.bmp", this->getName(), i ); 484 else 485 sprintf( outname, "%s-glyph-%d.bmp", this->getName(), i ); 486 SDL_SaveBMP(tmpSurf, outname);*/ 487 488 } 489 } 490 } 491 492 GLuint texture; 493 glGenTextures(1, &texture); 494 glBindTexture(GL_TEXTURE_2D, texture); 495 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 496 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 497 glTexImage2D(GL_TEXTURE_2D, 498 0, 499 GL_RGBA, 500 tmpSurf->w, tmpSurf->h, 501 0, 502 GL_RGBA, 503 GL_UNSIGNED_BYTE, 504 tmpSurf->pixels); 505 SDL_FreeSurface(tmpSurf); 506 return texture; 507 } 508 509 /** 510 * stores Glyph Metrics in an Array. 511 * @param from The Glyph to start from. 512 * @param count The number of Glyphs to start From. 513 */ 514 void Font::initGlyphs(Uint16 from, Uint16 count) 515 { 516 /* initialize the Array, and set all its entries to NULL 517 * only if the Glyph-array has not been initialized 518 */ 519 if (!this->glyphArray) 520 { 521 this->glyphArray = new Glyph*[FONT_HIGHEST_KNOWN_CHAR]; 522 for (int i = 0; i < FONT_HIGHEST_KNOWN_CHAR; i++) 523 this->glyphArray[i] = NULL; 524 } 525 526 Uint16 lastGlyph = from + count; 527 528 for (int i = from; i <= lastGlyph; i++) 529 { 530 // setting up all the Glyphs we like. 531 glyphArray[i] = getGlyphMetrics(i); 532 } 533 return; 534 } 535 536 /** 537 * @returns the optimal size to use as the texture size 538 539 @todo: this algorithm can be a lot more faster, althought it does 540 not really matter within the init-context, and 128 glyphs. 541 542 This function searches for a 2^n sizes texture-size, this is for 543 openGL-version < 1.2 compatibility ( and because it is realy easy like this :)) 544 */ 545 int Font::findOptimalFastTextureSize() 546 { 547 int i; 548 int x,y; // the counters 549 int maxLineHeight = this->getMaxHeight(); 550 unsigned int size = 32; // starting Value, we have to start somewhere 32 seems reasonable. (take any small enough 2^i number) 551 bool sizeOK = false; 552 Glyph* tmpGlyph; 553 554 while (!sizeOK) 555 { 556 x = 0; y = 0; 557 for (i = 0; i <= FONT_HIGHEST_KNOWN_CHAR; i++) 558 { 559 if((tmpGlyph = this->glyphArray[i]) != NULL) 560 { 561 // getting the height of the highest Glyph in the Line. 562 if (tmpGlyph->height > maxLineHeight) 563 maxLineHeight = tmpGlyph->height; 564 565 if (x + tmpGlyph->advance > size) 566 { 567 x = 0; 568 y = y + maxLineHeight; 569 //maxLineHeight = 0; 570 } 571 if (y + maxLineHeight + 1 > size) 572 break; 573 x += tmpGlyph->advance; 574 575 } 576 } 577 if (i >= FONT_HIGHEST_KNOWN_CHAR-1 || size > 8192) 578 sizeOK = true; 579 else 580 size *= 2; 581 } 582 return size; 583 } 584 585 586 /** 587 * a simple function to get some interesting information about this class 588 */ 589 void Font::debug() 590 { 591 // print the loaded font's style 592 int style; 593 if (likely(this->font != NULL)) 594 style = TTF_GetFontStyle(this->font); 595 PRINTF(0)("The font style is:"); 596 if(style==TTF_STYLE_NORMAL) 597 PRINTF(0)(" normal"); 598 else { 599 if(style&TTF_STYLE_BOLD) 600 PRINTF(0)(" bold"); 601 if(style&TTF_STYLE_ITALIC) 602 PRINTF(0)(" italic"); 603 if(style&TTF_STYLE_UNDERLINE) 604 PRINTF(0)(" underline"); 605 } 606 PRINTF(0)("\n"); 607 }
Note: See TracChangeset
for help on using the changeset viewer.