00001
00002
00003 #include "SDL.h"
00004 #include "SDL_ttf.h"
00005 #include "SDL_opengl.h"
00006
00007 #include "log.h"
00008 #include "font_ttf.h"
00009
00010
00011
00012 inline Uint32 getpixel(SDL_Surface *surface, int x, int y)
00013 {
00014 int bpp = surface->format->BytesPerPixel;
00015
00016 Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
00017
00018 switch(bpp) {
00019 case 1:
00020 return *p;
00021
00022 case 2:
00023 return *(Uint16 *)p;
00024
00025 case 3:
00026 if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
00027 return p[0] << 16 | p[1] << 8 | p[2];
00028 else
00029 return p[0] | p[1] << 8 | p[2] << 16;
00030
00031 case 4:
00032 return *(Uint32 *)p;
00033
00034 default:
00035 return 0;
00036 }
00037 }
00038
00039 inline void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel)
00040 {
00041 int bpp = surface->format->BytesPerPixel;
00042
00043 Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
00044
00045 switch(bpp) {
00046 case 1:
00047 *p = pixel;
00048 break;
00049
00050 case 2:
00051 *(Uint16 *)p = pixel;
00052 break;
00053
00054 case 3:
00055 if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
00056 p[0] = (pixel >> 16) & 0xff;
00057 p[1] = (pixel >> 8) & 0xff;
00058 p[2] = pixel & 0xff;
00059 } else {
00060 p[0] = pixel & 0xff;
00061 p[1] = (pixel >> 8) & 0xff;
00062 p[2] = (pixel >> 16) & 0xff;
00063 }
00064 break;
00065
00066 case 4:
00067 *(Uint32 *)p = pixel;
00068 break;
00069 }
00070 }
00071
00072
00073
00074 FontTTF::FontTTF(const char* file, int ptsize)
00075 {
00076
00077 if (!TTF_WasInit() && TTF_Init() == -1)
00078 {
00079 LOGE << "Unable to init TTF: " << TTF_GetError() << endl;
00080 DIE();
00081 }
00082
00083
00084 mFont = TTF_OpenFont(file, ptsize);
00085 if (!mFont)
00086 {
00087 LOGE << "TTF_OpenFont: " << TTF_GetError() << endl;
00088 DIE();
00089 }
00090
00091 mWwidth = -1;
00092 }
00093
00094 FontTTF::~FontTTF()
00095 {
00096 if (mFont)
00097 {
00098 TTF_CloseFont(mFont);
00099 mFont = 0;
00100 }
00101
00102
00103 cleanCache();
00104 cleanCache();
00105 cleanCache();
00106 }
00107
00108 SDL_Surface * ConvertToRGBA(SDL_Surface *surf)
00109 {
00110 TIN;
00111
00112 SDL_PixelFormat rgba;
00113 rgba.palette = 0;
00114 rgba.BitsPerPixel = 32;
00115 rgba.BytesPerPixel = 4;
00116 rgba.Rloss = 0;
00117 rgba.Gloss = 0;
00118 rgba.Bloss = 0;
00119 rgba.Aloss = 0;
00120 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
00121 rgba.Rmask = 0x000000FF;
00122 rgba.Gmask = 0x0000FF00;
00123 rgba.Bmask = 0x00FF0000;
00124 rgba.Amask = 0xFF000000;
00125 rgba.Rshift = 0;
00126 rgba.Gshift = 8;
00127 rgba.Bshift = 16;
00128 rgba.Ashift = 24;
00129 #else
00130 rgba.Rmask = 0xFF000000;
00131 rgba.Gmask = 0x00FF0000;
00132 rgba.Bmask = 0x0000FF00;
00133 rgba.Amask = 0x000000FF;
00134 rgba.Rshift = 24;
00135 rgba.Gshift = 16;
00136 rgba.Bshift = 8;
00137 rgba.Ashift = 0;
00138 #endif
00139 rgba.colorkey = 0;
00140 rgba.alpha = 0;
00141
00142
00143 SDL_Surface *tmp = SDL_ConvertSurface(surf, &rgba, SDL_SWSURFACE);
00144
00145
00146 SDL_LockSurface(surf);
00147 SDL_LockSurface(tmp);
00148
00149 for (int x = 0; x < tmp->w; x++)
00150 for (int y = 0; y < tmp->h; y++)
00151 {
00152 Uint32 col = getpixel(surf, x, y);
00153 if (col == surf->format->colorkey || col == 0)
00154 {
00155 col = SDL_MapRGBA(tmp->format, 250, 0, 0, 0);
00156 putpixel(tmp, x, y, col);
00157 }
00158
00159 }
00160
00161 SDL_UnlockSurface(surf);
00162 SDL_UnlockSurface(tmp);
00163
00164
00165 return tmp;
00166 }
00167
00168 void SwapRows(SDL_Surface *surf)
00169 {
00170 TIN;
00171
00172 Uint8 *hi_row, *lo_row, *tmp_row;
00173
00174 tmp_row = new Uint8[surf->pitch];
00175
00176 if (SDL_LockSurface(surf) == -1)
00177 {
00178 LOGE << "Unable to lock surface" << endl;
00179 DIE();
00180 }
00181
00182 hi_row = (Uint8 *)surf->pixels;
00183 lo_row = hi_row + (surf->h*surf->pitch) - surf->pitch;
00184
00185
00186 for(int i = 0; i < surf->h / 2; i++)
00187 {
00188 memcpy(tmp_row, hi_row, surf->pitch);
00189 memcpy(hi_row, lo_row, surf->pitch);
00190 memcpy(lo_row, tmp_row, surf->pitch);
00191
00192 hi_row += surf->pitch;
00193 lo_row -= surf->pitch;
00194 }
00195
00196 SDL_UnlockSurface(surf);
00197
00198 delete [] tmp_row;
00199 }
00200
00201 void FontTTF::RenderUTF8(const std::string &utf8str, float x, float y)
00202 {
00203 TIN;
00204
00205
00206 SCacheMember *scm;
00207
00208
00209 TStringHash::iterator it = mRenderedCache.find(utf8str);
00210
00211
00212 if (it == mRenderedCache.end())
00213 {
00214 LOGT << "creating new text" << endl;
00215
00216
00217 if (utf8str.empty()) return;
00218
00219
00220 SDL_Color col = {255,255,255};
00221
00222
00223 SDL_Surface *surf = TTF_RenderUTF8_Solid(mFont, utf8str.c_str(), col);
00224 if (!surf)
00225 {
00226 LOGE << "Unable to render '" << utf8str << "': " << TTF_GetError() << endl;
00227 return;
00228
00229 }
00230
00231
00232 SwapRows(surf);
00233
00234
00235 scm = new SCacheMember;
00236 if (!scm)
00237 {
00238 DIE("new failed");
00239 }
00240 scm->usages = 0;
00241 scm->w = surf->w;
00242 scm->h = surf->h;
00243 scm->surface = ConvertToRGBA(surf);
00244
00245
00246 SDL_FreeSurface(surf);
00247
00248 mRenderedCache.insert(make_pair(utf8str, scm));
00249 }
00250 else
00251 {
00252 scm = it->second;
00253 }
00254
00255
00256
00257 glEnable(GL_BLEND);
00258 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00259
00260 glRasterPos2f(x, y);
00261
00262 SDL_LockSurface(scm->surface);
00263 glDrawPixels( scm->w, scm->h, GL_RGBA, GL_UNSIGNED_BYTE, scm->surface->pixels);
00264 SDL_UnlockSurface(scm->surface);
00265
00266 glDisable(GL_BLEND);
00267
00268 scm->usages++;
00269 }
00270
00271 void FontTTF::cleanCache()
00272 {
00273 LOGT << "Cleaning TTF chache. Size before: " << mRenderedCache.size() << endl;
00274
00275 TStringHash::iterator it = mRenderedCache.begin();
00276
00277 while(it != mRenderedCache.end())
00278 {
00279 if (it->second->usages == 0)
00280 {
00281
00282
00283
00284 if (it->second->surface)
00285 {
00286 SDL_FreeSurface(it->second->surface);
00287 it->second->surface = 0;
00288 }
00289
00290
00291 if (it == mRenderedCache.begin())
00292 {
00293 mRenderedCache.erase(it);
00294 it = mRenderedCache.begin();
00295 }
00296 else
00297 {
00298 TStringHash::iterator it2 = it;
00299 ++it2;
00300 mRenderedCache.erase(it);
00301 it = it2;
00302 }
00303
00304 }
00305 else
00306 {
00307
00308 it->second->usages = 0;
00309 ++it;
00310 }
00311 }
00312
00313 LOGT << "Cleaning TTF chache. Size after: " << mRenderedCache.size() << endl;
00314 }
00315
00316
00317 int FontTTF::Ascent()
00318 {
00319 assertL(mFont);
00320
00321 return TTF_FontAscent(mFont);
00322 }
00323
00324 int FontTTF::getWwidth()
00325 {
00326 assertL(mFont);
00327
00328 if (mWwidth == -1)
00329 {
00330 TTF_SizeText(mFont, "W", &mWwidth, 0);
00331 }
00332
00333 return mWwidth;
00334 }
00335
00336 int FontTTF::getTextWidth(const std::string &utf8str)
00337 {
00338 assertL(mFont);
00339
00340 if (utf8str.empty()) return 0;
00341
00342 int w;
00343 TTF_SizeUTF8(mFont, utf8str.c_str(), &w, 0);
00344
00345 return w;
00346 }