TTFont.cpp

Go to the documentation of this file.
00001 /*
00002 Copyright (C) 2004-2006 The Pentagram team
00003 
00004 This program is free software; you can redistribute it and/or
00005 modify it under the terms of the GNU General Public License
00006 as published by the Free Software Foundation; either version 2
00007 of the License, or (at your option) any later version.
00008 
00009 This program is distributed in the hope that it will be useful,
00010 but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 GNU General Public License for more details.
00013 
00014 You should have received a copy of the GNU General Public License
00015 along with this program; if not, write to the Free Software
00016 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00017 */
00018 
00019 #include "pent_include.h"
00020 
00021 #if defined(HAVE_SDL_SDL_TTF_H)
00022 #include <SDL/SDL_ttf.h>
00023 #else
00024 #include "SDL_ttf.h"
00025 #endif
00026 
00027 #include "RenderSurface.h"
00028 #include "TTFont.h"
00029 #include "TTFRenderedText.h"
00030 #include "Texture.h"
00031 #include "IDataSource.h"
00032 #include "encoding.h"
00033 
00034 #include <iomanip>
00035 
00036 DEFINE_RUNTIME_CLASSTYPE_CODE(TTFont,Pentagram::Font);
00037 
00038 // various unicode characters which look like small black circles
00039 static const Uint16 bullets[] = { 0x2022, 0x30FB, 0x25CF, 0 };
00040 
00041 
00042 TTFont::TTFont(TTF_Font* font, uint32 rgb_, int bordersize_,
00043                            bool antiAliased_, bool SJIS_)
00044         : ttf_font(font), antiAliased(antiAliased_), SJIS(SJIS_)
00045 {
00046 //      rgb = PACK_RGB8( (rgb_>>16)&0xFF , (rgb_>>8)&0xFF , rgb_&0xFF );
00047         // This should be performed by PACK_RGB8, but it is not initialized at this point.
00048         rgb = (rgb_>>16)&0xFF | ((rgb_>>8)&0xFF)<<8 | (rgb_&0xFF)<<16;
00049         bordersize = bordersize_;
00050 
00051         bullet = 0;
00052         // scan for a character to use as a conversation option bullet
00053         for (int i = 0; bullets[i]; ++i) {
00054                 int minx, maxx, miny, maxy;
00055                 if (TTF_GlyphMetrics(font, bullets[i], &minx, &maxx,
00056                                                          &miny, &maxy, 0) == 0) {
00057                         if ((minx != 0 || maxx != 0) && (miny != 0 || maxy != 0)) {
00058                                 bullet = bullets[i];
00059                                 break;
00060                         }
00061                 }
00062         }
00063         if (bullet == 0) {
00064                 bullet = '*';
00065         }
00066 }
00067 
00068 TTFont::~TTFont()
00069 {
00070 
00071 }
00072 
00073 int TTFont::getHeight()
00074 {
00075         return TTF_FontHeight(ttf_font) + 2*bordersize; // constant (border)
00076 }
00077 
00078 int TTFont::getBaseline()
00079 {
00080         return TTF_FontAscent(ttf_font);
00081 }
00082 
00083 int TTFont::getBaselineSkip()
00084 {
00085         return TTF_FontLineSkip(ttf_font);
00086 }
00087 
00088 
00089 template<class T>
00090 static uint16* toUnicode(const std::string& text, uint16 bullet)
00091 {
00092         std::string::size_type l = T::length(text);
00093         uint16* unicodetext = new uint16[l+1];
00094         std::string::const_iterator iter = text.begin();
00095         for (unsigned int i = 0; i < l; ++i) {
00096                 uint32 u = T::unicode(iter);
00097                 if (u > 0xFFFF) {
00098                         perr.printf("Warning: unicode character out of range for SDL_ttf: %x\n", u);
00099                         unicodetext[i] = '?';
00100                 } else if (u == 64) {
00101                         unicodetext[i] = bullet;
00102                 } else {
00103                         unicodetext[i] = u;
00104                 }
00105         }
00106         unicodetext[l] = 0;
00107         return unicodetext;
00108 }
00109 
00110 
00111 void TTFont::getStringSize(const std::string& text, int& width, int& height)
00112 {
00113         // convert to unicode
00114         uint16* unicodetext;
00115         if (!SJIS)
00116                 unicodetext = toUnicode<Traits>(text, bullet);
00117         else
00118                 unicodetext = toUnicode<SJISTraits>(text, bullet);
00119 
00120         TTF_SizeUNICODE(ttf_font, unicodetext, &width, &height);
00121         delete[] unicodetext;
00122 #if 0
00123         pout << "StringSize: " << width << "," << height << ": " << text << std::endl;
00124         pout << "height: " << TTF_FontHeight(ttf_font) << std::endl;
00125         pout << "lineskip: " << TTF_FontLineSkip(ttf_font) << std::endl;
00126         pout << "ascent: " << TTF_FontAscent(ttf_font) << std::endl;
00127         pout << "descent: " << TTF_FontDescent(ttf_font) << std::endl;
00128 #endif
00129 
00130         width += 2*bordersize;
00131         height += 2*bordersize;
00132 }
00133 
00134 void TTFont::getTextSize(const std::string& text,
00135                                                  int& resultwidth, int& resultheight,
00136                                                  unsigned int& remaining,
00137                                                  int width, int height, TextAlign align,
00138                                                  bool u8specials)
00139 {
00140         std::list<PositionedText> tmp;
00141         if (!SJIS)
00142                 tmp = typesetText<Traits>(this, text, remaining,
00143                                                                   width, height, align, u8specials,
00144                                                                   resultwidth, resultheight);           
00145         else
00146                 tmp = typesetText<SJISTraits>(this, text, remaining,
00147                                                                           width, height, align, u8specials,
00148                                                                           resultwidth, resultheight);           
00149 }
00150 
00151 
00152 RenderedText* TTFont::renderText(const std::string& text,
00153                                                                  unsigned int& remaining,
00154                                                                  int width, int height,
00155                                                                  TextAlign align, bool u8specials,
00156                                                                  std::string::size_type cursor)
00157 {
00158         int resultwidth, resultheight;
00159         std::list<PositionedText> lines;
00160         if (!SJIS)
00161                 lines = typesetText<Traits>(this, text, remaining,
00162                                                                         width, height, align, u8specials,
00163                                                                         resultwidth, resultheight, cursor);
00164         else
00165                 lines = typesetText<SJISTraits>(this, text, remaining,
00166                                                                                 width, height, align, u8specials,
00167                                                                                 resultwidth, resultheight, cursor);
00168 
00169         // create 32bit RGBA texture buffer
00170         uint32* buf = new uint32[resultwidth*resultheight];
00171         memset(buf, 0, 4*resultwidth*resultheight);
00172 
00173         Texture* texture = new Texture;
00174         texture->buffer = buf;
00175         texture->width = resultwidth;
00176         texture->height = resultheight;
00177 
00178 #if 0
00179         pout << "Total size: " << resultwidth << "," << resultheight << std::endl;
00180 #endif
00181 
00182         std::list<PositionedText>::iterator iter;
00183         for (iter = lines.begin(); iter != lines.end(); ++iter)
00184         {
00185                 // convert to unicode
00186                 uint16* unicodetext;
00187                 if (!SJIS)
00188                         unicodetext = toUnicode<Traits>(iter->text, bullet);
00189                 else
00190                         unicodetext = toUnicode<SJISTraits>(iter->text, bullet);
00191 
00192                 // let SDL_ttf render the text
00193                 SDL_Surface* textsurf;
00194 
00195                 if (!antiAliased)
00196                 {
00197                         SDL_Color white = { 0xFF , 0xFF , 0xFF, 0 };
00198                         textsurf = TTF_RenderUNICODE_Solid(ttf_font, unicodetext, white);
00199                 }
00200                 else 
00201                 {
00202                         SDL_Color colour = { TEX32_R(rgb) , TEX32_G(rgb), TEX32_B(rgb), 0 };
00203                         SDL_Color black = { 0x00 , 0x00 , 0x00, 0 };
00204                         textsurf = TTF_RenderUNICODE_Shaded(ttf_font, unicodetext, colour, black);
00205                 }
00206 
00207                 if (textsurf) { 
00208                         SDL_LockSurface(textsurf);
00209 
00210 #if 0
00211                         pout << iter->dims.w << "," << iter->dims.h << " vs. "
00212                                  << textsurf->w << "," << textsurf->h << ": " << iter->text
00213                                  << std::endl;
00214 #endif
00215                         SDL_Palette *pal = textsurf->format->palette;
00216 
00217                         // render the text surface into our texture buffer
00218                         for (int y = 0; y < textsurf->h; y++) {
00219                                 uint8* surfrow = static_cast<uint8*>(textsurf->pixels) + y * textsurf->pitch;
00220                                 // CHECKME: bordersize!
00221                                 uint32* bufrow = buf + (iter->dims.y+y+bordersize)*resultwidth;
00222                                 for (int x = 0; x < textsurf->w; x++) {
00223 
00224                                         if (!antiAliased && surfrow[x] == 1) {
00225 
00226                                                 bufrow[iter->dims.x+x+bordersize] = rgb | 0xFF000000;
00227                                                 if (bordersize <= 0) continue;
00228                                                 if (bordersize == 1) {
00229                                                         // optimize common case
00230                                                         for (int dx = -1; dx <= 1; dx++) {
00231                                                                 for (int dy = -1; dy <= 1; dy++) {
00232                                                                         if (x + 1 + iter->dims.x + dx >= 0 &&
00233                                                                                 x + 1 + iter->dims.x + dx < resultwidth &&
00234                                                                                 y + 1 + dy >= 0 && y + 1 + dy < resultheight)
00235                                                                         {
00236                                                                                 if (buf[(y+iter->dims.y+dy+1)*resultwidth + x+1+iter->dims.x+dx] == 0) {
00237                                                                                         buf[(y+iter->dims.y+dy+1)*resultwidth + x+1+iter->dims.x+dx] = 0xFF000000;
00238                                                                                 }
00239                                                                         }
00240                                                                 }
00241                                                         }
00242                                                         continue;
00243                                                 }
00244                                                 for (int dx = -bordersize; dx <= bordersize; dx++) {
00245                                                         for (int dy = -bordersize; dy <= bordersize; dy++) {
00246                                                                 if (x + bordersize + iter->dims.x + dx >= 0 &&
00247                                                                         x + bordersize + iter->dims.x + dx < resultwidth &&
00248                                                                         y + bordersize + dy >= 0 && y + bordersize + dy < resultheight)
00249                                                                 {
00250                                                                         if (buf[(y+iter->dims.y+dy+bordersize)*resultwidth + x+bordersize+iter->dims.x+dx] == 0) {
00251                                                                                 buf[(y+iter->dims.y+dy+bordersize)*resultwidth + x+bordersize+iter->dims.x+dx] = 0xFF000000;
00252                                                                         }
00253                                                                 }
00254                                                         }
00255                                                 }
00256                                         }
00257                                         else if (antiAliased)
00258                                         {
00259                                                 uint32 idx = surfrow[x];
00260 
00261                                                 if (idx == 0) continue;
00262                                                 SDL_Color pe = pal->colors[idx];
00263 
00264                                                 if (bordersize <= 0) {
00265                                                         bufrow[iter->dims.x+x+bordersize] = TEX32_PACK_RGBA(pe.r, pe.g, pe.b, idx);
00266                                                 }
00267                                                 else {
00268                                                         bufrow[iter->dims.x+x+bordersize] = TEX32_PACK_RGBA(pe.r, pe.g, pe.b, 0xFF);
00269                                                         
00270                                                         // optimize common case
00271                                                         if (bordersize == 1) for (int dx = -1; dx <= 1; dx++) {
00272                                                                 for (int dy = -1; dy <= 1; dy++) {
00273                                                                         if (x + 1 + iter->dims.x + dx >= 0 &&
00274                                                                                 x + 1 + iter->dims.x + dx < resultwidth &&
00275                                                                                 y + 1 + dy >= 0 && y + 1 + dy < resultheight)
00276                                                                         {
00277                                                                                 uint32 alpha = TEX32_A(buf[(y+iter->dims.y+dy+1)*resultwidth + x+1+iter->dims.x+dx]);
00278                                                                                 if (alpha != 0xFF) {
00279                                                                                         alpha = 255-(((255-alpha) * (255-idx))>>8);
00280                                                                                         buf[(y+iter->dims.y+dy+1)*resultwidth + x+1+iter->dims.x+dx] = alpha<<TEX32_A_SHIFT;
00281                                                                                 }
00282                                                                         }
00283                                                                 }
00284                                                         }
00285                                                         else for (int dx = -bordersize; dx <= bordersize; dx++) {
00286                                                                 for (int dy = -bordersize; dy <= bordersize; dy++) {
00287                                                                         if (x + bordersize + iter->dims.x + dx >= 0 &&
00288                                                                                 x + bordersize + iter->dims.x + dx < resultwidth &&
00289                                                                                 y + bordersize + dy >= 0 && y + bordersize + dy < resultheight)
00290                                                                         {
00291                                                                                 uint32 alpha = TEX32_A(buf[(y+iter->dims.y+dy+bordersize)*resultwidth + x+bordersize+iter->dims.x+dx]);
00292                                                                                 if (alpha != 0xFF) {
00293                                                                                         alpha = 255-(((255-alpha) * (255-idx))>>8);
00294                                                                                         buf[(y+iter->dims.y+dy+bordersize)*resultwidth + x+bordersize+iter->dims.x+dx] = alpha<<TEX32_A_SHIFT;
00295                                                                                 }
00296                                                                         }
00297                                                                 }
00298                                                         }
00299                                                 }
00300                                         }
00301                                 }
00302                         }
00303 
00304                         SDL_UnlockSurface(textsurf);
00305                         SDL_FreeSurface(textsurf);
00306                 }
00307 
00308                 if (iter->cursor != std::string::npos) {
00309                         int w, h;
00310                         assert(iter->cursor <= iter->text.size());
00311                         unicodetext[iter->cursor] = 0;
00312                         TTF_SizeUNICODE(ttf_font, unicodetext,&w,&h);
00313                         for (int y = 0; y < iter->dims.h; y++) {
00314                                 uint32* bufrow = buf + (iter->dims.y+y)*resultwidth;
00315                                 bufrow[iter->dims.x+w+bordersize] = 0xFF000000;
00316 //                              if (bordersize > 0)
00317 //                                      bufrow[iter->dims.x+w+bordersize-1] = 0xFF000000;
00318                         }
00319                 }
00320 
00321                 delete[] unicodetext;
00322 
00323         }
00324 
00325         return new TTFRenderedText(texture, resultwidth, resultheight,
00326                                                            getBaselineSkip() - getHeight(), this);
00327 }

Generated on Fri Jul 27 22:27:45 2007 for pentagram by  doxygen 1.4.7