00001
00002
00003
00004
00006
00007
00008 #include "TextTTF.h"
00009
00010 #include "OpenGL.h"
00011
00012 #include <iostream>
00013
00014 #ifdef HAVE_TTF
00015 #include <freetype.h>
00016
00017 #define MAXIMUM(a,b) ((a)>(b)?a:b)
00018 #define MINIMUM(a,b) ((a)<(b)?a:b)
00019
00020 class TextTTF_Internal {
00021 public:
00022 TT_Error loadTrueTypeChar(int);
00023 bool fOpened;
00024 TT_Face fFace;
00025 TT_CharMap fCharMap;
00026 TT_Instance fInstance;
00027 TT_Instance_Metrics fInstanceMetrics;
00028 TT_Glyph fGlyph;
00029 TT_Raster_Map fBitmap;
00030 int fNumGlyphs;
00031 bool fHinted;
00032 bool fNewLine;
00033 TT_UShort fWidth;
00034 TT_UShort fTextWidth;
00035 TT_UShort fTextHeight;
00036 float fXJustifyTranslation;
00037 float fYJustifyTranslation;
00038 };
00039
00040 static TT_Engine* fEngine = 0;
00041
00043 TT_Error TextTTF_Internal::loadTrueTypeChar(
00044 int aIndex
00045 )
00048 {
00049
00050
00051 int flags = TTLOAD_DEFAULT;
00052 return TT_Load_Glyph( fInstance, fGlyph, aIndex, flags );
00053 }
00054 #endif
00055
00057 hippodraw::TextTTF::TextTTF(
00058 )
00059 :fStatus(false)
00060 ,fInitFont(true)
00061 ,fPointSize(0)
00062 ,fViewportWidth(0)
00063 ,fViewportHeight(0)
00064 ,fRotated(false)
00067 {
00068 #ifdef HAVE_TTF
00069 if(!fEngine) {
00070 fEngine = new TT_Engine;
00071 TT_Error error = TT_Init_FreeType(fEngine);
00072 if(error) {
00073 std::cout << "TextTTF : could not initialise FreeType." << std::endl;
00074 return;
00075 }
00076
00077 }
00078 #else
00079 std::cout << "TextTTF : compiled without HAVE_TTF CPP macro" << std::endl;
00080 #endif
00081
00082
00083 m_fileName = "helvetica";
00084 m_size = 64;
00085 m_horizontalJustification = LEFT;
00086 m_verticalJustification = BOTTOM;
00087 m_viewportMapping = NONE;
00088 #ifdef HAVE_TTF
00089 fTTF = new TextTTF_Internal;
00090 fTTF->fOpened = false;
00091 fTTF->fBitmap.bitmap = 0;
00092 #else
00093 fTTF = 0;
00094 #endif
00095
00096 fPointSize = (int)m_size;
00097 initFont();
00098 fInitFont = false;
00099 }
00101 hippodraw::TextTTF::~TextTTF (
00102 )
00105 {
00106 fStatus = false;
00107 #ifdef HAVE_TTF
00108 if(fTTF->fOpened==true) {
00109 free(fTTF->fBitmap.bitmap);
00110 TT_Done_Glyph(fTTF->fGlyph);
00111 TT_Done_Instance(fTTF->fInstance);
00112 TT_Close_Face(fTTF->fFace);
00113 fTTF->fOpened = false;
00114 }
00115 delete fTTF;
00116 #endif
00117 }
00118 void hippodraw::TextTTF::setFileName(const std::string& aFileName){
00119 m_fileName = aFileName;
00120 fInitFont = true;
00121 }
00122 void hippodraw::TextTTF::setString(const std::string& aString) {
00123 m_strings.clear();
00124 m_strings.push_back(aString);
00125 fInitFont = true;
00126 }
00127 void hippodraw::TextTTF::setStrings(const std::vector<std::string>& aStrings) {
00128 m_strings = aStrings;
00129 fInitFont = true;
00130 }
00131 void hippodraw::TextTTF::setSize(float aSize){
00132 m_size = aSize;
00133 fInitFont = true;
00134 }
00135 void hippodraw::TextTTF::setJustification(Justification aH,Justification aV){
00136 m_horizontalJustification = aH;
00137 m_verticalJustification = aV;
00138 fInitFont = true;
00139 }
00140 void hippodraw::TextTTF::setRotated(bool aYesNo){
00141 fRotated = aYesNo;
00142 }
00144 void hippodraw::TextTTF::render (
00145 )
00148 {
00149 #ifdef HAVE_TTF
00150 if(m_viewportMapping==TextTTF::NONE) {
00151 if(fInitFont) {
00152 fPointSize = (int)m_size;
00153 initFont();
00154 fInitFont = false;
00155 }
00156 }
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204 if(fStatus==false) return;
00205
00206 float red = 0;
00207 float green = 0;
00208 float blue = 0;
00209 glPushAttrib( (GLbitfield)(GL_CURRENT_BIT | GL_ENABLE_BIT));
00210 #ifdef WIN32
00211
00212 glDisable(GL_DEPTH_TEST);
00213 #endif
00214 glDisable(GL_LIGHTING);
00215 glColor3f(red,green,blue);
00216 #endif
00217
00218 #ifdef HAVE_TTF
00219 fTTF->fXJustifyTranslation = 0;
00220 fTTF->fYJustifyTranslation = 0;
00221 short w,h;
00222 if(m_horizontalJustification==LEFT) {
00223 } else if(m_horizontalJustification==CENTER) {
00224 getTextSizePixels(w,h);
00225 fTTF->fXJustifyTranslation = 0.5F * w;
00226 } else if(m_horizontalJustification==RIGHT) {
00227 getTextSizePixels(w,h);
00228 fTTF->fXJustifyTranslation = w;
00229 }
00230
00231 if(m_verticalJustification==BOTTOM) {
00232 } else if(m_verticalJustification==MIDDLE) {
00233 getTextSizePixels(w,h);
00234 fTTF->fYJustifyTranslation = 0.5F * h;
00235 } else if(m_verticalJustification==TOP) {
00236 getTextSizePixels(w,h);
00237 fTTF->fYJustifyTranslation = h;
00238 }
00239 #endif
00240
00241
00242
00243
00244
00245
00246 glPixelStorei(GL_UNPACK_ALIGNMENT,1);
00247
00248
00249
00250
00251
00252
00253
00254 int linen = m_strings.size();
00255 for(int count=0;count<linen;count++) {
00256 renderString(m_strings[count]);
00257 }
00258
00259 glPopAttrib();
00260
00261 }
00264 void hippodraw::TextTTF::initFont(
00265 )
00268 {
00269 fStatus = false;
00270 #ifdef HAVE_TTF
00271 if(fPointSize<=0) return;
00272
00273 if(fTTF->fOpened==true) {
00274 free(fTTF->fBitmap.bitmap);
00275 TT_Done_Glyph(fTTF->fGlyph);
00276 TT_Done_Instance(fTTF->fInstance);
00277 TT_Close_Face(fTTF->fFace);
00278 fTTF->fOpened = false;
00279 }
00280
00281 char* ttf_path = ::getenv("TTFPATH");
00282 std::string ttfpath = (!ttf_path ? "" : ttf_path);
00283 if(ttfpath=="") {
00284 std::string fullName = m_fileName;
00285 if(m_fileName.find(".ttf")==std::string::npos) fullName += ".ttf";
00286 TT_Error error = TT_Open_Face(*fEngine,fullName.c_str(),&(fTTF->fFace));
00287 if(error) {
00288 std::cout << "TextTTF::initFont : could not find or open file "
00289 << m_fileName << std::endl;
00290 return;
00291 }
00292 } else {
00293
00294 char* path = (char*)ttfpath.c_str();
00295 std::vector<std::string> paths;
00296 char* token = strtok(path," ");
00297 do {
00298 paths.push_back(std::string(token));
00299 } while( (token = strtok(NULL," "))!=NULL);
00300
00301 bool found = false;
00302 unsigned int index;
00303 for(index=0;index<paths.size();index++) {
00304 std::string fullName = paths[index];
00305 #ifdef WIN32
00306 fullName += "\\";
00307 #else
00308 fullName += "/";
00309 #endif
00310 fullName += m_fileName;
00311 if(m_fileName.find(".ttf")==std::string::npos) fullName += ".ttf";
00312 TT_Error error =
00313 TT_Open_Face(*fEngine,fullName.c_str(),&(fTTF->fFace));
00314 if(error) continue;
00315 found = true;
00316 break;
00317 }
00318
00319 if(found==false) {
00320 std::cout << "TextTTF::initFont : could not find or open file "
00321 << m_fileName << std::endl;
00322 return;
00323 }
00324 }
00325
00326
00327 TT_Face_Properties properties;
00328 TT_Error error = TT_Get_Face_Properties(fTTF->fFace, &properties );
00329 if(error) {
00330 std::cout << "TextTTF::initFont : could not get face properties" << std::endl;
00331 return;
00332 }
00333
00334
00335 unsigned short n = properties.num_CharMaps;
00336 unsigned short i;
00337 for ( i = 0; i < n; i++ ) {
00338 unsigned short platform, encoding;
00339 TT_Get_CharMap_ID( fTTF->fFace, i, &platform, &encoding );
00340 if ( (platform == 3 && encoding == 1 ) ||
00341 (platform == 0 && encoding == 0 ) ) {
00342 TT_Get_CharMap( fTTF->fFace, i, &(fTTF->fCharMap) );
00343 i = n + 1;
00344 }
00345 }
00346 if ( i == n ) {
00347 std::cout << "TextTTF::initFont : this font doesn't contain any Unicode mapping table" << std::endl;
00348 return;
00349 }
00350
00351
00352 fTTF->fNumGlyphs = properties.num_Glyphs;
00353
00354 error = TT_New_Glyph( fTTF->fFace, &(fTTF->fGlyph) );
00355 if(error) {
00356 std::cout << "TextTTF::initFont : could not create glyph container" << std::endl;
00357 return;
00358 }
00359
00360 error = TT_New_Instance( fTTF->fFace, &(fTTF->fInstance) );
00361 if(error) {
00362 std::cout << "TextTTF::initFont : could not create instance" << std::endl;
00363 return;
00364 }
00365
00366
00367
00368
00369 error = TT_Set_Instance_Resolutions(fTTF->fInstance, 96, 96 );
00370 if (error) {
00371 std::cout << "TextTTF::initFont : Could not set instance resolution" << std::endl;
00372 return;
00373 }
00374
00375
00376
00377
00378
00379 error = TT_Set_Instance_PointSize(fTTF->fInstance,fPointSize);
00380
00381 if (error) {
00382 std::cout << "TextTTF::initFont : Could not set instance point size" << std::endl;
00383 return;
00384 }
00385
00386 error = TT_Get_Instance_Metrics(fTTF->fInstance,
00387 &(fTTF->fInstanceMetrics));
00388 if (error) {
00389 std::cout << "TextTTF::initFont : could not get instance metric" << std::endl;
00390 return;
00391 }
00392
00393
00394 fTTF->fBitmap.rows = fTTF->fInstanceMetrics.y_ppem;
00395 fTTF->fBitmap.width = fTTF->fInstanceMetrics.x_ppem;
00396
00397 fTTF->fBitmap.cols = (fTTF->fBitmap.width + 7)/8;
00398 fTTF->fBitmap.flow = TT_Flow_Up;
00399 fTTF->fBitmap.size = (long)(fTTF->fBitmap.rows * fTTF->fBitmap.cols);
00400 fTTF->fBitmap.bitmap = malloc( (int)fTTF->fBitmap.size );
00401 if(!fTTF->fBitmap.bitmap) return;
00402
00403 fTTF->fHinted = true;
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415 fTTF->fOpened = true;
00416
00417 fStatus = true;
00418 #endif
00419 }
00421 void hippodraw::TextTTF::renderString(
00422 const std::string& aString
00423 )
00426 {
00427 if(aString=="") return;
00428 #ifdef HAVE_TTF
00429 fTTF->fNewLine = false;
00430 fTTF->fWidth = 0;
00431 int l = aString.size();
00432 for(int count=0;count<l;count++) {
00433 if(count==l-1) fTTF->fNewLine = true;
00434 renderCharacter(aString[count]);
00435 }
00436 #endif
00437 }
00439 void hippodraw::TextTTF::renderCharacter(
00440 char aChar
00441 )
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458 {
00459 #ifdef HAVE_TTF
00460 short index = TT_Char_Index( fTTF->fCharMap, (short)aChar);
00461
00462 if((index<0)||(index>=fTTF->fNumGlyphs)) return;
00463
00464
00465
00466 TT_Error error = fTTF->loadTrueTypeChar(index);
00467 if (error) {
00468 std::cout << "TextTTF::renderCharacter." << std::endl;
00469 return;
00470 }
00471
00472
00473 TT_Big_Glyph_Metrics metrics;
00474 error = TT_Get_Glyph_Big_Metrics( fTTF->fGlyph, &metrics );
00475 if (error) {
00476 std::cout << "TextTTF::renderCharacter : could not get glyph metrics"
00477 << std::endl;
00478 return;
00479 }
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489 TT_F26Dot6 xmin, ymin;
00490 xmin = metrics.bbox.xMin & -64;
00491 ymin = metrics.bbox.yMin & -64;
00492
00493
00494
00495 memset( fTTF->fBitmap.bitmap, 0, fTTF->fBitmap.size );
00496 error = TT_Get_Glyph_Bitmap( fTTF->fGlyph,
00497 &(fTTF->fBitmap),
00498 -xmin, -ymin);
00499 if (error) {
00500 std::cout << "TextTTF::renderCharacter : could not get glyph bitmap"
00501 << std::endl;
00502 } else {
00503
00504 TT_F26Dot6 xmove,ymove;
00505 if(fTTF->fNewLine==true) {
00506 xmove = -fTTF->fWidth;
00507
00508 ymove = - (metrics.vertAdvance/64);
00509 fTTF->fNewLine = false;
00510 } else {
00511
00512 xmove = metrics.horiAdvance/64;
00513 ymove = 0;
00514 fTTF->fWidth += (TT_UShort)xmove;
00515 }
00516
00517 float xorig = fTTF->fXJustifyTranslation;
00518 float yorig = (float)(-ymin/64)+fTTF->fYJustifyTranslation;
00519
00520 if(fRotated) {
00521 GLubyte* pfrom = (GLubyte*)fTTF->fBitmap.bitmap;
00522 GLsizei bwidth = fTTF->fBitmap.rows;
00523 GLsizei bheight = fTTF->fBitmap.width;
00524 GLubyte* bptr = new GLubyte[bwidth * bheight];
00525 int irow;
00526 for(irow=0;irow<fTTF->fBitmap.rows;irow++) {
00527 int icol = 0;
00528 for(int ibyte=0;ibyte<fTTF->fBitmap.cols;ibyte++) {
00529 GLubyte byte = *pfrom;
00530 pfrom++;
00531 GLubyte pixel8 = (byte >> 0) & 0x1;
00532 GLubyte pixel7 = (byte >> 1) & 0x1;
00533 GLubyte pixel6 = (byte >> 2) & 0x1;
00534 GLubyte pixel5 = (byte >> 3) & 0x1;
00535 GLubyte pixel4 = (byte >> 4) & 0x1;
00536 GLubyte pixel3 = (byte >> 5) & 0x1;
00537 GLubyte pixel2 = (byte >> 6) & 0x1;
00538 GLubyte pixel1 = (byte >> 7) & 0x1;
00539
00540 int bicol = fTTF->fBitmap.rows-irow-1;
00541
00542 int birow = icol;
00543 if(icol<fTTF->fBitmap.width) *(bptr+birow*bwidth+bicol) = pixel1;
00544 icol++;
00545
00546 birow = icol;
00547 if(icol<fTTF->fBitmap.width) *(bptr+birow*bwidth+bicol) = pixel2;
00548 icol++;
00549
00550 birow = icol;
00551 if(icol<fTTF->fBitmap.width) *(bptr+birow*bwidth+bicol) = pixel3;
00552 icol++;
00553
00554 birow = icol;
00555 if(icol<fTTF->fBitmap.width) *(bptr+birow*bwidth+bicol) = pixel4;
00556 icol++;
00557
00558 birow = icol;
00559 if(icol<fTTF->fBitmap.width) *(bptr+birow*bwidth+bicol) = pixel5;
00560 icol++;
00561
00562 birow = icol;
00563 if(icol<fTTF->fBitmap.width) *(bptr+birow*bwidth+bicol) = pixel6;
00564 icol++;
00565
00566 birow = icol;
00567 if(icol<fTTF->fBitmap.width) *(bptr+birow*bwidth+bicol) = pixel7;
00568 icol++;
00569
00570 birow = icol;
00571 if(icol<fTTF->fBitmap.width) *(bptr+birow*bwidth+bicol) = pixel8;
00572 icol++;
00573 }
00574 }
00575 GLubyte* ptr = bptr;
00576 int bcols = (bwidth + 7)/8;
00577 GLubyte* bptr2 = new GLubyte[bheight * bcols];
00578 GLubyte* ptr2 = bptr2;
00579 for(irow=0;irow<bheight;irow++) {
00580 int icol = 0;
00581 for(int ibyte=0;ibyte<bcols;ibyte++) {
00582 GLubyte byte = 0;
00583 if(icol<bwidth) {
00584 byte = byte | ((*ptr) << 7);
00585 ptr++;icol++;
00586 }
00587 if(icol<bwidth) {
00588 byte = byte | ((*ptr) << 6);
00589 ptr++;icol++;
00590 }
00591 if(icol<bwidth) {
00592 byte = byte | ((*ptr) << 5);
00593 ptr++;icol++;
00594 }
00595 if(icol<bwidth) {
00596 byte = byte | ((*ptr) << 4);
00597 ptr++;icol++;
00598 }
00599 if(icol<bwidth) {
00600 byte = byte | ((*ptr) << 3);
00601 ptr++;icol++;
00602 }
00603 if(icol<bwidth) {
00604 byte = byte | ((*ptr) << 2);
00605 ptr++;icol++;
00606 }
00607 if(icol<bwidth) {
00608 byte = byte | ((*ptr) << 1);
00609 ptr++;icol++;
00610 }
00611 if(icol<bwidth) {
00612 byte = byte | ((*ptr) << 0);
00613 ptr++;icol++;
00614 }
00615 *ptr2 = byte;ptr2++;
00616 }
00617 }
00618 glBitmap(bwidth,bheight,xorig+bwidth,yorig,(float)ymove,(float)xmove,
00619 (GLubyte*)bptr2);
00620 delete [] bptr;
00621 delete [] bptr2;
00622 } else {
00623 glBitmap(fTTF->fBitmap.width,fTTF->fBitmap.rows,
00624 xorig,yorig,(float)xmove,(float)ymove,
00625 (GLubyte*)fTTF->fBitmap.bitmap);
00626 }
00627 }
00628 #else
00629 aChar = 0;
00630 #endif
00631 }
00633 bool hippodraw::TextTTF::getTextSizePixels(
00634 short& aWidth
00635 ,short& aHeight
00636 )
00639 {
00640 aWidth = 0;
00641 aHeight = 0;
00642 if(fStatus==false) return false;
00643 #ifdef HAVE_TTF
00644 int linen = m_strings.size();
00645 fTTF->fTextWidth = 0;
00646 fTTF->fTextHeight = 0;
00647 for(int count=0;count<linen;count++) {
00648 const std::string& s = m_strings[count];
00649 if(s=="") continue;
00650 fTTF->fNewLine = false;
00651 fTTF->fWidth = 0;
00652 int l = s.size();
00653 TT_F26Dot6 yMax = 0;
00654 TT_F26Dot6 yMin = 0;
00655 for(int i=0;i<l;i++) {
00656 if(i==l-1) fTTF->fNewLine = true;
00657 char c = s[i];
00658 short index = TT_Char_Index(fTTF->fCharMap,(short)c);
00659 if((index<0)||(index>=fTTF->fNumGlyphs)) continue;
00660 TT_Error error = fTTF->loadTrueTypeChar(index);
00661 if (error) {
00662 std::cout << "TextTTF::getTextSizePixels" << std::endl;
00663 continue;
00664 }
00665
00666 TT_Big_Glyph_Metrics metrics;
00667 error = TT_Get_Glyph_Big_Metrics( fTTF->fGlyph, &metrics );
00668 if (error) {
00669 std::cout << "TextTTF::getTextSizePixels : could not get glyph metrics"
00670 << std::endl;
00671 continue;
00672 }
00673
00674
00675
00676 TT_F26Dot6 xmove,ymove;
00677 if(fTTF->fNewLine==true) {
00678 fTTF->fWidth += (TT_UShort)metrics.horiAdvance/64;
00679 xmove = -fTTF->fWidth;
00680
00681 ymove = - (metrics.vertAdvance/64);
00682 fTTF->fNewLine = false;
00683
00684 fTTF->fTextWidth = MAXIMUM(fTTF->fTextWidth,fTTF->fWidth);
00685 if(count==0) fTTF->fTextHeight += yMax;
00686 if(count!=linen-1) fTTF->fTextHeight += (TT_UShort)-ymove;
00687 if(count==linen-1) fTTF->fTextHeight += -yMin;
00688 } else {
00689
00690 xmove = metrics.horiAdvance/64;
00691 ymove = 0;
00692 fTTF->fWidth += (TT_UShort)xmove;
00693 }
00694 yMax = MAXIMUM(yMax,(metrics.bbox.yMax & -64)/64);
00695 yMin = MINIMUM(yMin,(metrics.bbox.yMin & -64)/64);
00696 }
00697 }
00698 aWidth = fTTF->fTextWidth;
00699 aHeight = fTTF->fTextHeight;
00700 return true;
00701 #else
00702 return false;
00703 #endif
00704 }