Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

pgfont.cpp

Go to the documentation of this file.
00001 /*
00002     ParaGUI - crossplatform widgetset
00003     Copyright (C) 2000,2001,2002  Alexander Pipelka
00004  
00005     This library is free software; you can redistribute it and/or
00006     modify it under the terms of the GNU Library General Public
00007     License as published by the Free Software Foundation; either
00008     version 2 of the License, or (at your option) any later version.
00009  
00010     This library is distributed in the hope that it will be useful,
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013     Library General Public License for more details.
00014  
00015     You should have received a copy of the GNU Library General Public
00016     License along with this library; if not, write to the Free
00017     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018  
00019     Alexander Pipelka
00020     pipelka@teleweb.at
00021  
00022     Last Update:      $Author: mbickel $
00023     Update Date:      $Date: 2007-04-13 16:16:01 $
00024     Source File:      $Source: /home/cvspsrv/cvsroot/games/asc/source/libs/paragui/src/font/pgfont.cpp,v $
00025     CVS/RCS Revision: $Revision: 1.2 $
00026     Status:           $State: Exp $
00027 */
00028 
00029 #include "pgfont.h"
00030 #include "pglog.h"
00031 #include "pgfilearchive.h"
00032 #include "facecache.h"
00033 #include "pgstring.h"
00034 
00035 //#define OLD_TEXTRENDERING
00036 
00037 //SDL_Surface* PG_FontEngine::my_charSurface = NULL;
00038 PG_FontEngine::MAP_FONTS PG_FontEngine::my_fontcache;
00039 FT_Library PG_FontEngine::my_library;
00040 
00041 PG_FontEngine::PG_FontEngine() {
00042         FT_Init_FreeType(&my_library);
00043 }
00044 
00045 PG_FontEngine::~PG_FontEngine() {
00046 
00047         // clean fontcache
00048         for(MAP_FONTS::iterator i = my_fontcache.begin(); i != my_fontcache.end(); i++) {
00049                 delete (*i).second;
00050         }
00051         my_fontcache.clear();
00052 
00053         FT_Done_FreeType(my_library);
00054 
00055         /*if (my_charSurface != NULL) {
00056                 SDL_FreeSurface(my_charSurface);
00057         }*/
00058 }
00059 
00060 void PG_FontEngine::FontEngineError(FT_Error error) {
00061 #undef __FTERRORS_H__
00062 #define FT_ERRORDEF( e, v, s )  { e, s },
00063 #define FT_ERROR_START_LIST  {
00064 #define FT_ERROR_END_LIST    { -1, NULL } };
00065         const struct {
00066                 int             err_code;
00067                 const char      *err_msg;
00068         }
00069         ft_errors[] =
00070 #include FT_ERRORS_H
00071 
00072             int i = 0;
00073         while (ft_errors[i].err_code != -1) {
00074                 if (ft_errors[i].err_code == error) {
00075                         PG_LogWRN("FreeType error %d : %s",error,ft_errors[i].err_msg);
00076                         return;
00077                 }
00078                 i++;
00079         }
00080 
00081         PG_LogWRN("FreeType : Unknown error : %d", error);
00082         return;
00083 }
00084 
00085 /*bool PG_FontEngine::PG_GetFontFace(PG_Font* Param) {
00086         PG_FontFaceCacheItem* CacheItem = LoadFontFace(
00087                                               Param->GetName(),
00088                                               Param->GetSize());
00089  
00090         Param->SetFaceCache(CacheItem);
00091  
00092         return (Param->GetFaceCache() != NULL);
00093 }*/
00094 
00095 PG_GlyphCacheItem* PG_FontEngine::GetGlyph(PG_Font *Param, int glyph_index) {
00096 
00097         PG_FontFaceCacheItem* facecache = Param->GetFaceCache();
00098         PG_GlyphCacheItem *GlyphCacheItem = facecache->GlyphCache[glyph_index];
00099 
00100         if(GlyphCacheItem != NULL) {
00101                 return GlyphCacheItem;
00102         }
00103 
00104         FT_Face face = facecache->Face;
00105 
00106         if (FT_Load_Glyph(face, glyph_index, FT_LOAD_RENDER ))
00107                 return NULL;
00108 
00109         Uint32 bitmapsize = face->glyph->bitmap.pitch * face->glyph->bitmap.rows;
00110         GlyphCacheItem = new PG_GlyphCacheItem(bitmapsize);
00111 
00112         GlyphCacheItem->Glyph_Index = glyph_index;
00113         GlyphCacheItem->Bitmap = face->glyph->bitmap;
00114         GlyphCacheItem->Bitmap_left = face->glyph->bitmap_left;
00115         GlyphCacheItem->Bitmap_top = face->glyph->bitmap_top;
00116         GlyphCacheItem->Advance_x = FT_CEIL(face->glyph->metrics.horiAdvance);
00117         memcpy(GlyphCacheItem->data(), face->glyph->bitmap.buffer, bitmapsize);
00118         GlyphCacheItem->Bitmap.buffer = (unsigned char*)GlyphCacheItem->data();
00119 
00120         facecache->GlyphCache[glyph_index] = GlyphCacheItem;
00121         return GlyphCacheItem;
00122 }
00123 
00124 #ifndef OLD_TEXTRENDERING
00125 
00126 template < class DT >
00127 inline void BlitTemplate(DT pixels, SDL_Surface* Surface, FT_Bitmap *Bitmap, int PosX, int PosY, int x0, int x1, int y0, int y1, PG_Font *Param) {
00128         int xw = x1-x0;
00129 
00130         SDL_PixelFormat* format = Surface->format;
00131         Uint8 Rloss = format->Rloss;
00132         Uint8 Gloss = format->Gloss;
00133         Uint8 Bloss = format->Bloss;
00134         Uint8 Aloss = format->Aloss;
00135         Uint8 Rloss8 = 8-Rloss;
00136         Uint8 Gloss8 = 8-Gloss;
00137         Uint8 Bloss8 = 8-Bloss;
00138         Uint8 Aloss8 = 8-Aloss;
00139         Uint8 Rshift = format->Rshift;
00140         Uint8 Gshift = format->Gshift;
00141         Uint8 Bshift = format->Bshift;
00142         Uint8 Ashift = format->Ashift;
00143         Uint32 Rmask = format->Rmask;
00144         Uint32 Gmask = format->Gmask;
00145         Uint32 Bmask = format->Bmask;
00146         Uint32 Amask = format->Amask;
00147 
00148         Uint8 bpp = format->BytesPerPixel;
00149         Uint32 pitch = Surface->pitch;
00150         Uint32 src_pitch = Bitmap->pitch;
00151         register Uint8* src_pixels = Bitmap->buffer + x0 + y0*Bitmap->pitch;
00152         register Uint8* dst_pixels = (Uint8*)pixels + (PosX+x0)*bpp + (PosY+y0)*pitch /*+ Surface->offset*/;
00153         Uint8* line;
00154 
00155         Uint8 r,g,b,a;
00156         unsigned rv,gv,bv,av;
00157         Sint32 cr,cg,cb;
00158         Uint32 color = 0;
00159         Sint32 v;
00160 
00161         PG_Color fc = Param->GetColor();
00162         cr = fc.r;
00163         cg = fc.g;
00164         cb = fc.b;
00165 
00166         int alpha = Param->GetAlpha();
00167 
00168         line = dst_pixels;
00169         for (register int y = y0; y <y1; y++, src_pixels += src_pitch) {
00170 
00171                 dst_pixels = line;
00172 
00173                 for (register int x = x0; x < x1; x++, dst_pixels += bpp) {
00174 
00175                         // get source pixel value
00176                         v = *(Uint8 *)(src_pixels++);
00177 
00178                         // don't do anything if the pixel is fully transparent
00179                         if(v == 0) {
00180                                 continue;
00181                         }
00182 
00183                         if(alpha != 255) {
00184                                 v = (v * alpha) >> 8;
00185                         }
00186 
00187                         // Get the pixel
00188                         color = *((DT) (dst_pixels));
00189                         switch(Surface->format->BytesPerPixel) {
00190                                 default:
00191                                         // get the RGBA values
00192                                         rv = (color & Rmask) >> Rshift;
00193                                         r = (rv << Rloss) + (rv >> Rloss8);
00194                                         gv = (color & Gmask) >> Gshift;
00195                                         g = (gv << Gloss) + (gv >> Gloss8);
00196                                         bv = (color & Bmask) >> Bshift;
00197                                         b = (bv << Bloss) + (bv >> Bloss8);
00198                                         if(Amask) {
00199                                                 av = (color & Amask) >> Ashift;
00200                                                 a = (av << Aloss) + (av >> Aloss8);
00201                                         } else
00202                                                 a = SDL_ALPHA_OPAQUE;
00203 
00204                                         //SDL_GetRGBA(color, format, &r, &g, &b, &a);
00205 
00206                                         // calculate new RGBA values
00207                                         if(v == 255) {
00208                                                 r = cr;
00209                                                 g = cg;
00210                                                 b = cb;
00211                                         } else {
00212                                                 //r += ((cr - r) * v) / 255;
00213                                                 //g += ((cg - g) * v) / 255;
00214                                                 //b += ((cb - b) * v) / 255;
00215                                                 r += ((cr - r) * v) >> 8;
00216                                                 g += ((cg - g) * v) >> 8;
00217                                                 b += ((cb - b) * v) >> 8;
00218                                         }
00219 
00220                                         // if the destination pixel is full transparent
00221                                         // use the pixel shading as alpha
00222                                         if(a == 0) {
00223                                                 a = v;
00224                                         }
00225 
00226                                         // get the destination color
00227                                         color = (r >> Rloss) << Rshift
00228                                                 | (g >> Gloss) << Gshift
00229                                                 | (b >> Bloss) << Bshift
00230                                                 | ((a >> Aloss) << Ashift & Amask);
00231                                         // Set the pixel
00232                                         *((DT) (dst_pixels)) = color;
00233                                         break;
00234 
00235                                 case 3:
00236                                         cr = (fc.r << format->Rshift) >> 16 & 0xff;
00237                                         cg = (fc.g << format->Gshift) >> 8 & 0xff;
00238                                         cb = fc.b << format->Bshift & 0xff;
00239 
00240                                         if (v == 255) {
00241                                                 r = cr;
00242                                                 g = cg;
00243                                                 b = cb;
00244                                         }
00245                                         // calculate new RGB values
00246                                         else {
00247                                                 b = *(dst_pixels);
00248                                                 g = *(dst_pixels+1);
00249                                                 r = *(dst_pixels+2);
00250                                                 r += ((cr - r) * v) >> 8;
00251                                                 g += ((cg - g) * v) >> 8;
00252                                                 b += ((cb - b) * v) >> 8;
00253                                         }
00254 
00255                                         *dst_pixels = b;
00256                                         *(dst_pixels + 1) = g;
00257                                         *(dst_pixels + 2) = r;
00258                                         break;
00259 
00260                                 case 1:
00261                                         SDL_GetRGBA(color, format, &r, &g, &b, &a);
00262 
00263                                         // calculate new RGBA values
00264                                         if(v == 255) {
00265                                                 r = cr;
00266                                                 g = cg;
00267                                                 b = cb;
00268                                         } else {
00269                                                 //r += ((cr - r) * v) / 255;
00270                                                 //g += ((cg - g) * v) / 255;
00271                                                 //b += ((cb - b) * v) / 255;
00272                                                 r += ((cr - r) * v) >> 8;
00273                                                 g += ((cg - g) * v) >> 8;
00274                                                 b += ((cb - b) * v) >> 8;
00275                                         }
00276 
00277                                         // if the destination pixel is full transparent
00278                                         // use the pixel shading as alpha
00279                                         if(a == 0) {
00280                                                 a = v;
00281                                         }
00282                                         color = SDL_MapRGBA(format, r,g,b, a);
00283                                         *((DT) (dst_pixels)) = color;
00284                                         break;
00285                         }
00286 
00287                 }
00288                 src_pixels -= xw;
00289                 line += pitch;
00290         }
00291 }
00292 
00293 bool PG_FontEngine::BlitFTBitmap(SDL_Surface *Surface, FT_Bitmap *Bitmap, int PosX, int PosY, PG_Font *Param, const PG_Rect* ClipRect) {
00294         int BitmapRealWidth;
00295 
00296         // i think we can skip that test
00297         /*if(Bitmap->pixel_mode != ft_pixel_mode_grays) {
00298                 return false;
00299         }*/
00300 
00301         // do nothing if we're fully transparent
00302         if (Param->GetAlpha() == 0)
00303                 return true;
00304 
00305         BitmapRealWidth = Bitmap->width;
00306 
00307         // get the cliprectangle of the surface
00308         static PG_Rect srfclip;
00309         SDL_GetClipRect(Surface, &srfclip);
00310 
00311         // the real clipping rectangle = surfaceclip  / ClipRect
00312         static PG_Rect clip;
00313         clip = *ClipRect / srfclip;
00314 
00315         //Italic font is widther than normal
00316         //if (Param->Style & PG_FSTYLE_ITALIC) {
00317         //      BitmapRealWidth += (int)(Bitmap->rows * PG_FITALIC_ANGLE);
00318         //}
00319 
00320         int x0 = 0;
00321         int x1 = BitmapRealWidth;
00322         int y0 = 0;
00323         int y1 = Bitmap->rows;
00324 
00325         if(PosX < clip.x) {
00326                 x0 = clip.x - PosX;
00327         }
00328 
00329         if(PosX+BitmapRealWidth > clip.x + clip.w) {
00330                 x1 = (clip.x + clip.w) - PosX;
00331         }
00332 
00333         if(PosY < clip.y) {
00334                 y0 = clip.y - PosY;
00335         }
00336 
00337         if(PosY+Bitmap->rows > clip.y + clip.h) {
00338                 y1 = (clip.y + clip.h) - PosY;
00339         }
00340 
00341         if((x1 <= x0) || (y1 <= y0)) {
00342                 return false;
00343         }
00344 
00345         switch(Surface->format->BytesPerPixel) {
00346                 case 1:
00347                 case 3:
00348                         BlitTemplate((Uint8*)Surface->pixels, Surface, Bitmap, PosX, PosY, x0, x1, y0, y1, Param);
00349                         break;
00350                 case 2:
00351                         BlitTemplate((Uint16*)Surface->pixels, Surface, Bitmap, PosX, PosY, x0, x1, y0, y1, Param);
00352                         break;
00353                 case 4:
00354                         BlitTemplate((Uint32*)Surface->pixels, Surface, Bitmap, PosX, PosY, x0, x1, y0, y1, Param);
00355                         break;
00356                 default:
00357                         PG_LogWRN("Unable to draw font: unsupported bit depth!");
00358                         break;
00359         }
00360 
00361         return true;
00362 }
00363 
00364 #else
00365 
00366 bool PG_FontEngine::BlitFTBitmap(SDL_Surface *Surface, FT_Bitmap *Bitmap, int PosX, int PosY, PG_Font *Param, PG_Rect *ClipRect) {
00367         int             x,y;
00368         Uint32          *raw_pixels;
00369         SDL_Rect        TargetPos;
00370         SDL_Rect        SourcePos;
00371         int             BitmapRealWidth;
00372 
00373         if (Param->Alpha == 0)
00374                 return true;
00375 
00376         TargetPos.x = PosX;
00377         TargetPos.y = PosY;
00378 
00379         //Italic font is widther than normal
00380         BitmapRealWidth = Bitmap->width;
00381         if (Param->Style & PG_FSTYLE_ITALIC) {
00382                 BitmapRealWidth += (int)(Bitmap->rows * PG_FITALIC_ANGLE);
00383         }
00384 
00385         //There is no need to draw
00386         if ((TargetPos.x > (ClipRect->x + ClipRect->w)) || (TargetPos.y > (ClipRect->y +ClipRect->h )) || ((TargetPos.y+Bitmap->rows) < ClipRect->y) || ((TargetPos.x+BitmapRealWidth) < ClipRect->x))
00387                 return true;
00388 
00389         //Is my_charSurface big enough ??
00390         if (my_charSurface != NULL) {
00391                 if ((my_charSurface->w < BitmapRealWidth)||(my_charSurface->h < Bitmap->rows)) {
00392                         SDL_FreeSurface(my_charSurface);
00393                         my_charSurface = NULL;
00394                 }
00395         }
00396 
00397         if (my_charSurface == NULL) {
00398                 my_charSurface = SDL_CreateRGBSurface(SDL_SRCALPHA , BitmapRealWidth, Bitmap->rows, 32, 0xff0000, 0xff00, 0xff, 0xff000000);
00399                 if (my_charSurface == NULL) {
00400                         PG_LogWRN("Can`t get char surface : %s",SDL_GetError());
00401                         return false;
00402                 }
00403         }
00404 
00405         if (Param->Style & PG_FSTYLE_ITALIC) {
00406                 SDL_FillRect(my_charSurface, NULL, 0);
00407         }
00408 
00409         SourcePos.x = 0; // = my_charSurface->clip_rect;
00410         SourcePos.y = 0;
00411         SourcePos.w = BitmapRealWidth;
00412         SourcePos.h = Bitmap->rows;
00413 
00414         //Clipping
00415         if ((TargetPos.x + SourcePos.w) > (ClipRect->x + ClipRect->w))
00416                 SourcePos.w = ClipRect->w - (TargetPos.x - ClipRect->x);
00417         if ((TargetPos.y + SourcePos.h) > (ClipRect->y + ClipRect->h))
00418                 SourcePos.h = ClipRect->h - (TargetPos.y - ClipRect->y);
00419         if (TargetPos.x < ClipRect->x) {
00420                 int     delta;
00421 
00422                 delta = ClipRect->x - TargetPos.x;
00423                 SourcePos.w -= delta;
00424                 TargetPos.x += delta;
00425                 SourcePos.x += delta;
00426         }
00427 
00428         if (TargetPos.y < ClipRect->y) {
00429                 int     delta;
00430 
00431                 delta = ClipRect->y - TargetPos.y;
00432                 SourcePos.h -= delta;
00433                 TargetPos.y += delta;
00434                 SourcePos.y += delta;
00435         }
00436 
00437         raw_pixels = (Uint32 *) my_charSurface->pixels;
00438         Uint32 pitch_diff = 0;
00439 
00440         switch (Bitmap->pixel_mode) {
00441                 case ft_pixel_mode_grays: {
00442                                 Uint8   *SrcPix = Bitmap->buffer;
00443                                 int     a;
00444 
00445 
00446                                 if (Param->Style & PG_FSTYLE_ITALIC) {
00447                                         double ioffset = Bitmap->rows * PG_FITALIC_ANGLE;
00448 
00449                                         for (y = 0; y < Bitmap->rows; y++, SrcPix += Bitmap->pitch, ioffset -= PG_FITALIC_ANGLE) {
00450                                                 for (x = 0; x <  Bitmap->width; x++) {
00451                                                         a = *(Uint8 *)(SrcPix++);
00452 
00453                                                         // What the hell should do this ?
00454                                                         //if (Param->Alpha != 255)
00455                                                         //      a = (a * Param->Alpha) / 255;
00456 
00457                                                         raw_pixels[int(ioffset) + x + (my_charSurface->pitch/4)*(y)] = Param->Color.MapRGBA(my_charSurface->format, a);
00458                                                 }
00459                                                 SrcPix -= x;
00460                                         }
00461                                 } else
00462                                         pitch_diff = (my_charSurface->pitch/4);
00463 
00464                                 for (y = 0; y < Bitmap->rows; y++, SrcPix += Bitmap->pitch) {
00465                                         for (x = 0; x <  Bitmap->width; x++) {
00466                                                 a = *(Uint8 *)(SrcPix++);
00467 
00468                                                 // Q: What the hell should do this ?
00469                                                 // A: This allows for alpha
00470                                                 // rendering of text. // Neo
00471 
00472                                                 if (Param->Alpha != 255)
00473                                                         a = (a * Param->Alpha) / 255;
00474 
00475                                                 *raw_pixels = Param->Color.MapRGBA(my_charSurface->format, a);
00476                                                 raw_pixels++;
00477                                         }
00478                                         SrcPix -= x;
00479                                         raw_pixels -= x;
00480                                         raw_pixels += pitch_diff;
00481                                 }
00482                                 break;
00483                         }
00484 
00485                 default:
00486                         PG_LogWRN("Unknown pixel type in font !");
00487                         return false;
00488         }
00489 
00490         // Final blit
00491         SDL_Rect BoldTarget = TargetPos;
00492         SDL_BlitSurface(my_charSurface, &SourcePos, Surface, &TargetPos);
00493 
00494         //BOLD
00495         if (Param->Style & PG_FSTYLE_BOLD) {
00496                 BoldTarget.x += Param->FaceCache->Bold_Offset;
00497                 SDL_BlitSurface(my_charSurface, &SourcePos, Surface, &BoldTarget);
00498         }
00499 
00500         return true;
00501 }
00502 
00503 #endif
00504 
00505 
00506 bool PG_FontEngine::RenderText(SDL_Surface *Surface, const PG_Rect& ClipRect, int BaseLineX, int BaseLineY, const PG_String& Text, PG_Font *ParamIn) {
00507         return RenderText(Surface, (PG_Rect*)&ClipRect, BaseLineX, BaseLineY, Text, ParamIn);
00508 }
00509 
00510 bool PG_FontEngine::RenderText(SDL_Surface *Surface, const PG_Rect *ClipRect, int BaseLineX, int BaseLineY, const PG_String& Text, PG_Font* font) {
00511         static bool bRecursion = false;
00512         int OriBaseX = BaseLineX;
00513         FT_UInt previous = 0;
00514 
00515         PG_FontFaceCacheItem* FaceCache = font->GetFaceCache();
00516 
00517         // invalid font ?
00518         if (FaceCache == NULL) {
00519                 return false;
00520         }
00521 
00522         FT_Face Face = FaceCache->Face;
00523         FT_Vector  delta;
00524 
00525         if(SDL_MUSTLOCK(Surface)) {
00526                 SDL_LockSurface(Surface);
00527         }
00528 
00529         Uint32 c0;
00530 
00531         //Go thu text and draw characters
00532         int len = Text.size();
00533         for(int i = 0; i < len; i++) {
00534                 int glyph_index;
00535                 PG_GlyphCacheItem* Glyph;
00536                 int OldBaseLineX = BaseLineX;
00537 
00538       c0 = (PG_Char)(Text[i]);
00539 
00540                 //Skip drawing we go non-printable char
00541                 if (c0 < 32) {
00542                         continue;
00543                 }
00544 
00545                 //Get glyph index
00546                 glyph_index = FT_Get_Char_Index(Face, c0);
00547 
00548                 //Make space between characters == kerneling
00549                 if ( FaceCache->Use_Kerning && previous && glyph_index ) {
00550                         FT_Get_Kerning(Face, previous, glyph_index, ft_kerning_default, &delta );
00551                         BaseLineX += delta.x >> 6;
00552                 }
00553                 previous = glyph_index;
00554 
00555                 //Get glyph bitmap
00556                 Glyph = GetGlyph(font, glyph_index);
00557 
00558                 //Blit glyph bitmap into the surface
00559                 if (c0 != ' ') {
00560                         BlitFTBitmap(Surface, &Glyph->Bitmap, BaseLineX + Glyph->Bitmap_left, BaseLineY - Glyph->Bitmap_top, font, ClipRect);
00561                 }
00562 
00563                 BaseLineX += Glyph->Advance_x;
00564                 if (font->GetStyle() & PG_Font::BOLD) {
00565                         BaseLineX += FaceCache->Bold_Offset;
00566                 }
00567 
00568                 //UNDERLINE
00569                 //TO-DO : Underline is not transparent !!!! (Fill must be replaced by Blit)
00570                 if (font->GetStyle() & PG_Font::UNDERLINE) {
00571                         SDL_Rect        und_rect;
00572 
00573                         und_rect.x = OldBaseLineX;
00574                         und_rect.y = BaseLineY;
00575                         und_rect.h = FaceCache->Underline_Height;
00576                         und_rect.w = BaseLineX - OldBaseLineX;
00577 
00578                         SDL_FillRect(
00579                             Surface,
00580                             &und_rect,
00581                             font->GetColor().MapRGB(Surface->format)
00582                         );
00583                 }
00584         }
00585 
00586         //BOLD
00587         if (font->GetStyle() & PG_Font::BOLD && !bRecursion) {
00588                 bRecursion = true;
00589                 RenderText(Surface, ClipRect, OriBaseX+1, BaseLineY, Text, font);
00590                 bRecursion = false;
00591         }
00592 
00593         if(SDL_MUSTLOCK(Surface)) {
00594                 SDL_UnlockSurface(Surface);
00595         }
00596 
00597         return true;
00598 }
00599 
00600 bool PG_FontEngine::GetTextSize(const PG_String& Text, PG_Font* font, Uint16 *Width, Uint16 *Height, int *BaselineY, int *FontLineSkip, Uint16 *FontHeight, int *Ascent, int *Descent) {
00601         FT_UInt                 previous = 0;
00602         int                             BaseLineX = 0;
00603         int                             preBaseLineY = 0;
00604         int                             MaxY = 0;
00605 
00606         Uint16                  preFontHeight = 0;
00607         int                             preLineSkip = 0;
00608         int                             preAscent = 0;
00609         int                             preDescent = 0;
00610 
00611         PG_FontFaceCacheItem* FaceCache = font->GetFaceCache();
00612 
00613         // invalid font ?
00614         if (FaceCache == NULL) {
00615                 return false;
00616         }
00617 
00618         FT_Face Face = FaceCache->Face;
00619 
00620         //Initial parametrs check
00621         if (FaceCache != NULL) {
00622                 if (preFontHeight < FaceCache->Height)
00623                         preFontHeight = FaceCache->Height;
00624                 if (preLineSkip < FaceCache->LineSkip)
00625                         preLineSkip = FaceCache->LineSkip;
00626                 if (preAscent < FaceCache->Ascent)
00627                         preAscent = FaceCache->Ascent;
00628                 if (preDescent > FaceCache->Descent)
00629                         preDescent = FaceCache->Descent;
00630         }
00631 
00632         //Go thu text and get sizes of the characters
00633 
00634         Uint32 c0;
00635 
00636         int len = Text.size();
00637         for(int i = 0; i < len; i++) {
00638                 int glyph_index;
00639                 PG_GlyphCacheItem       *Glyph;
00640 
00641                 c0 = Text[i];
00642 
00643                 //Skip non-printable char
00644                 if (c0 < 32) {
00645                         continue;
00646                 }
00647 
00648                 //Get glyph index
00649                 glyph_index = FT_Get_Char_Index(Face, c0);
00650 
00651                 //Make space between characters == kerneling
00652                 if ( FaceCache->Use_Kerning && previous && glyph_index ) {
00653                         FT_Vector  delta;
00654 
00655                         FT_Get_Kerning(Face, previous, glyph_index, ft_kerning_default, &delta );
00656                         BaseLineX += delta.x >> 6;
00657                 }
00658                 previous = glyph_index;
00659 
00660                 //Get glyph bitmap
00661                 Glyph = GetGlyph(font, glyph_index);
00662 
00663                 if (preBaseLineY < Glyph->Bitmap_top) {
00664                         preBaseLineY = Glyph->Bitmap_top;
00665                 }
00666 
00667                 if (MaxY < Glyph->Bitmap.rows) {
00668                         MaxY = Glyph->Bitmap.rows;
00669                 }
00670 
00671                 BaseLineX += Glyph->Advance_x;
00672                 if (font->GetStyle() & PG_Font::BOLD) {
00673                         BaseLineX += FaceCache->Bold_Offset;
00674                 }
00675 
00676         }
00677 
00678         if (Height != NULL)
00679                 *Height = MaxY;
00680         if (Width != NULL)
00681                 *Width = BaseLineX;
00682         if (BaselineY!= NULL)
00683                 *BaselineY = preBaseLineY;
00684         if (FontLineSkip!= NULL)
00685                 *FontLineSkip = preLineSkip;
00686         if (FontHeight != NULL)
00687                 *FontHeight = preFontHeight;
00688         if (Ascent != NULL)
00689                 *Ascent = preAscent;
00690         if (Descent != NULL)
00691                 *Descent = preDescent;
00692 
00693         return true;
00694 }
00695 
00696 PG_FontFaceCacheItem* PG_FontEngine::LoadFontFace(const std::string&  filename, FT_F26Dot6 fontsize, int index) {
00697 
00698         // lets see if the file is already in the cache
00699         FONT_ITEM* item = my_fontcache[filename];
00700 
00701         // NO -> Load the face from the file
00702         if(item == NULL) {
00703 
00704                 // open the fontfile
00705                 PG_DataContainer* data = PG_FileArchive::ReadFile(filename);
00706                 if(!data) {
00707                         return NULL;
00708                 }
00709 
00710                 // create new font item
00711                 item = new FONT_ITEM;
00712                 item->name = filename;
00713                 item->memdata = data;
00714 
00715                 // add the face to the cache
00716                 my_fontcache[filename] = item;
00717         }
00718 
00719         // let's see if we already have a face for the given size
00720         PG_FontFaceCacheItem* subitem = item->subitems[fontsize];
00721 
00722         // NO -> create new face for the size
00723         if(subitem == NULL) {
00724                 subitem = new PG_FontFaceCacheItem;
00725                 subitem->fontsize = fontsize;
00726 
00727                 // create the freetype face
00728                 FT_New_Memory_Face(my_library, (FT_Byte*)item->memdata->data(),
00729                                    item->memdata->size(), 0,
00730                                    &(subitem->Face));
00731 
00732                 // check if the font is scaleable
00733                 if (!FT_IS_SCALABLE(subitem->Face) ) {
00734                         PG_LogWRN("Font %s is not scalable !", filename.c_str());
00735                         delete subitem;
00736                         return NULL;
00737                 }
00738 
00739                 // set font size
00740                 FT_Set_Char_Size(subitem->Face, 0, fontsize*64, 0, 0);
00741 
00742                 // set subitem params
00743                 subitem->Bold_Offset = 1 + fontsize / 20;
00744                 subitem->Underline_Height = FT_FLOOR(FT_MulFix(subitem->Face->underline_thickness, subitem->Face->size->metrics.y_scale));
00745                 if ( subitem->Underline_Height < 1 ) {
00746                         subitem->Underline_Height = 1;
00747                 }
00748 
00749                 subitem->Ascent = FT_CEIL(FT_MulFix(subitem->Face->bbox.yMax, subitem->Face->size->metrics.y_scale));
00750                 subitem->Descent  = FT_CEIL(FT_MulFix(subitem->Face->bbox.yMin, subitem->Face->size->metrics.y_scale));
00751                 subitem->Height = subitem->Ascent - subitem->Descent + 1;
00752                 subitem->LineSkip = FT_CEIL(FT_MulFix(subitem->Face->height, subitem->Face->size->metrics.y_scale));
00753                 subitem->Use_Kerning = FT_HAS_KERNING(subitem->Face);
00754 
00755                 // add to subitem list
00756                 item->subitems[fontsize] = subitem;
00757         }
00758 
00759         return subitem;
00760 }
00761 
00762 PG_FontEngine::FONT_ITEM::~FONT_ITEM() {
00763         for(MAP_SUBITEMS::iterator i = subitems.begin(); i != subitems.end(); i++) {
00764                 delete (*i).second;
00765         }
00766         delete memdata;
00767 }
00768 
00769 
00770 /*
00771  * Local Variables:
00772  * c-basic-offset: 8
00773  * End:
00774  */
00775 
00776 

Generated on Tue Jun 24 01:27:48 2008 for Advanced Strategic Command by  doxygen 1.4.2