00001
00002
00003
00004
00005
00006
00007
00009
00019 #include <cassert>
00020 #include <cstdarg>
00021 #include <math.h>
00022 #include "utils.h"
00023 #include "video.h"
00024 #include "gui.h"
00025
00026 using namespace std;
00027 using namespace hoa_utils;
00028 using namespace hoa_video::private_video;
00029
00030 namespace hoa_video {
00031
00032 bool GameVideo::LoadFont(const string &filename, const string &name, uint32 size) {
00033
00034 if (_font_map.find(filename) != _font_map.end()) {
00035 return true;
00036 }
00037
00038
00039 TTF_Font *font = TTF_OpenFont(filename.c_str(), size);
00040
00041 if (!font) {
00042 if (VIDEO_DEBUG)
00043 cerr << "VIDEO ERROR: TTF_OpenFont() failed for font file: " << filename.c_str() << endl;
00044 return false;
00045 }
00046
00047
00048 FontProperties *fp = new FontProperties;
00049 _font_map[name] = fp;
00050
00051
00052 fp->ttf_font = font;
00053 fp->height = TTF_FontHeight(font);
00054 fp->line_skip = TTF_FontLineSkip(font);
00055 fp->ascent = TTF_FontAscent(font);
00056 fp->descent = TTF_FontDescent(font);
00057
00058
00059 fp->shadow_x = max(fp->height / 8, 1);
00060 fp->shadow_y = -fp->shadow_x;
00061
00062
00063 fp->shadow_style = VIDEO_TEXT_SHADOW_DARK;
00064 fp->glyph_cache = new std::map<uint16, FontGlyph*>;
00065
00066 return true;
00067 }
00068
00069
00070
00071 FontProperties* GameVideo::GetFontProperties(const std::string &font_name) {
00072 if (!IsValidFont(font_name)) {
00073 if (VIDEO_DEBUG)
00074 cerr << "VIDEO ERROR: GetFontProperties() failed becase an invalid font name was passed: " << font_name << endl;
00075 return NULL;
00076 }
00077
00078 return _font_map[font_name];
00079 }
00080
00081
00082
00083 bool GameVideo::SetFont(const std::string &name) {
00084
00085 if ( _font_map.find(name) == _font_map.end())
00086 return false;
00087
00088 _current_font = name;
00089 return true;
00090 }
00091
00092
00093
00094
00095
00096
00097 std::string GameVideo::GetFont() const
00098 {
00099 return _current_font;
00100 }
00101
00102
00103
00104
00105
00106
00107 Color GameVideo::GetTextColor () const
00108 {
00109 return _current_text_color;
00110 }
00111
00112
00113
00114
00115 RenderedLine *GameVideo::_GenTexLine(uint16 *line, FontProperties *fp)
00116 {
00117 if (!fp)
00118 return NULL;
00119
00120
00121 GLuint texid[2] = { 0, 0 };
00122
00123 if (!*line)
00124 return new RenderedLine(texid, 0, 0, 0, 0, 0, 0);
00125
00126 static const SDL_Color color = { 0xFF, 0xFF, 0xFF, 0xFF };
00127
00128 TTF_Font * font = fp->ttf_font;
00129
00130 SDL_Surface *initial = NULL;
00131 SDL_Surface *intermediary = NULL;
00132
00133
00134
00135 uint8 *shadowPixels = NULL;
00136 int32 lineW, lineH;
00137 int32 textureW, textureH;
00138
00139
00140 uint8 numTextures = 0;
00141
00142
00143 int32 minY = 0;
00144
00145 int32 calcLineWidth = 0;
00146
00147 Color shadowColor;
00148
00149 uint16 *charPtr;
00150
00151 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
00152 static const int rmask = 0xff000000;
00153 static const int gmask = 0x00ff0000;
00154 static const int bmask = 0x0000ff00;
00155 static const int amask = 0x000000ff;
00156 #else
00157 static const int rmask = 0x000000ff;
00158 static const int gmask = 0x0000ff00;
00159 static const int bmask = 0x00ff0000;
00160 static const int amask = 0xff000000;
00161 #endif
00162
00163 if (TTF_SizeUNICODE(font, line, &lineW, &lineH) == -1)
00164 {
00165 if(VIDEO_DEBUG)
00166 cerr << "VIDEO ERROR: TTF_SizeUNICODE() returned NULL in _GenTexLine()!" << endl;
00167 return NULL;
00168 }
00169
00170 for (charPtr = line; *charPtr; ++charPtr)
00171 {
00172 FontGlyph * glyphinfo = (*fp->glyph_cache)[*charPtr];
00173 int curMinY = glyphinfo->top_y;
00174 if (curMinY < minY)
00175 minY = curMinY;
00176 calcLineWidth += glyphinfo->advance;
00177 }
00178
00179 lineH -= minY;
00180
00181
00182 if (calcLineWidth > lineW)
00183 lineW = calcLineWidth;
00184
00185 textureW = RoundUpPow2(lineW + 1);
00186 textureH = RoundUpPow2(lineH + 1);
00187
00188 intermediary = SDL_CreateRGBSurface(0, textureW, textureH, 32,
00189 rmask, gmask, bmask, amask);
00190
00191 if(!intermediary)
00192 {
00193 if(VIDEO_DEBUG)
00194 cerr << "VIDEO ERROR: SDL_CreateRGBSurface() returned NULL in _GenTexLine()!" << endl;
00195 return NULL;
00196 }
00197
00198 SDL_Rect surfTarget;
00199 int xpos = 0;
00200 int ypos = -minY;
00201 for (charPtr = line; *charPtr; ++charPtr)
00202 {
00203 FontGlyph * glyphinfo = (*fp->glyph_cache)[*charPtr];
00204
00205 initial = TTF_RenderGlyph_Blended(font, *charPtr, color);
00206
00207 if(!initial)
00208 {
00209 if(VIDEO_DEBUG)
00210 cerr << "VIDEO ERROR: TTF_RenderGlyph_Blended() returned NULL in _GenTexLine()!" << endl;
00211 return NULL;
00212 }
00213
00214 surfTarget.x = xpos + glyphinfo->min_x;
00215 surfTarget.y = ypos + glyphinfo->top_y;
00216
00217 if(SDL_BlitSurface(initial, NULL, intermediary, &surfTarget) < 0)
00218 {
00219 SDL_FreeSurface(initial);
00220 SDL_FreeSurface(intermediary);
00221 if(VIDEO_DEBUG)
00222 cerr << "VIDEO ERROR: SDL_BlitSurface() failed in _GenTexLine()! (" << SDL_GetError() << ")" << endl;
00223 return NULL;
00224 }
00225 SDL_FreeSurface(initial);
00226 xpos += glyphinfo->advance;
00227 }
00228
00229 if (_text_shadow)
00230 {
00231 shadowPixels = new uint8[intermediary->w * intermediary->h * 4];
00232 shadowColor = _GetTextShadowColor(fp);
00233 }
00234
00235 SDL_LockSurface(intermediary);
00236 for(int j = 0; j < intermediary->w * intermediary->h ; ++ j)
00237 {
00238 if (_text_shadow)
00239 {
00240 shadowPixels[j*4+3] = ((uint8*)intermediary->pixels)[j*4+2];
00241 shadowPixels[j*4+0] = (uint8) (shadowColor[0] * 0xFF);
00242 shadowPixels[j*4+1] = (uint8) (shadowColor[1] * 0xFF);
00243 shadowPixels[j*4+2] = (uint8) (shadowColor[2] * 0xFF);
00244 }
00245 ((uint8*)intermediary->pixels)[j*4+3] = ((uint8*)intermediary->pixels)[j*4+2];
00246 ((uint8*)intermediary->pixels)[j*4+0] = (uint8) (_current_text_color[0] * 0xFF);
00247 ((uint8*)intermediary->pixels)[j*4+1] = (uint8) (_current_text_color[1] * 0xFF);
00248 ((uint8*)intermediary->pixels)[j*4+2] = (uint8) (_current_text_color[2] * 0xFF);
00249 }
00250
00251 numTextures = _text_shadow ? 2 : 1;
00252
00253 glGenTextures(numTextures, texid);
00254
00255 uint8 *texturePointers[2] =
00256 {
00257 (uint8 *)intermediary->pixels,
00258 shadowPixels
00259 };
00260
00261 for (int j = 0; j < numTextures; ++j)
00262 {
00263 _BindTexture(texid[j]);
00264
00265 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00266 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00267
00268 glTexImage2D(GL_TEXTURE_2D, 0, 4, textureW, textureH, 0, GL_RGBA,
00269 GL_UNSIGNED_BYTE, texturePointers[j] );
00270
00271 GLenum err;
00272 if((err = glGetError()) != 0)
00273 {
00274 if(VIDEO_DEBUG)
00275 cerr << "VIDEO ERROR: _GenTexLine: glError found after glTexImage2D (" << gluErrorString(err) << ")" << endl;
00276
00277 SDL_FreeSurface(intermediary);
00278
00279 if (shadowPixels)
00280 delete shadowPixels;
00281
00282 return NULL;
00283 }
00284
00285 }
00286
00287 SDL_UnlockSurface(intermediary);
00288 SDL_FreeSurface(intermediary);
00289
00290 if (shadowPixels)
00291 delete shadowPixels;
00292
00293 return new RenderedLine(texid, lineW, textureW, lineH, textureH, 0, minY);
00294 }
00295
00296
00297
00298
00299
00300 bool GameVideo::_CacheGlyphs
00301 (
00302 const uint16 *uText,
00303 FontProperties *fp
00304 )
00305 {
00306 if (!fp)
00307 return false;
00308
00309 static const SDL_Color color = { 0xFF, 0xFF, 0xFF, 0xFF };
00310 static const uint16 fallbackglyph = '?';
00311
00312 TTF_Font * font = fp->ttf_font;
00313
00314 SDL_Surface *initial = NULL;
00315 SDL_Surface *intermediary = NULL;
00316 int32 w,h;
00317 GLuint texture;
00318
00319 for(const uint16 * character_ptr = uText; *character_ptr != 0; ++character_ptr)
00320 {
00321
00322 const uint16 &character = *character_ptr;
00323
00324
00325 if(fp->glyph_cache->find(character) != fp->glyph_cache->end())
00326 continue;
00327
00328 initial = TTF_RenderGlyph_Blended(font, character, color);
00329
00330 if(!initial)
00331 {
00332 if(VIDEO_DEBUG)
00333 cerr << "VIDEO ERROR: TTF_RenderUNICODE_Blended() returned NULL in CacheGlyphs(), resorting to fallback" << endl;
00334 initial = TTF_RenderGlyph_Blended(font, fallbackglyph, color);
00335 if (!fallbackglyph)
00336 {
00337 if (VIDEO_DEBUG)
00338 cerr << "VIDEO ERROR: TTF_RenderUNICODE_Blended() could not render fallback glyph, aborting!" << endl;
00339 return false;
00340 }
00341
00342
00343
00344 }
00345
00346 w = RoundUpPow2(initial->w + 1);
00347 h = RoundUpPow2(initial->h + 1);
00348
00349 uint32 rmask, gmask, bmask, amask;
00350
00351
00352
00353 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
00354 rmask = 0xff000000;
00355 gmask = 0x00ff0000;
00356 bmask = 0x0000ff00;
00357 amask = 0x000000ff;
00358 #else
00359 rmask = 0x000000ff;
00360 gmask = 0x0000ff00;
00361 bmask = 0x00ff0000;
00362 amask = 0xff000000;
00363 #endif
00364
00365 intermediary = SDL_CreateRGBSurface(0, w, h, 32,
00366 rmask, gmask, bmask, amask);
00367
00368 if(!intermediary)
00369 {
00370 SDL_FreeSurface(initial);
00371 SDL_FreeSurface(intermediary);
00372 if(VIDEO_DEBUG)
00373 cerr << "VIDEO ERROR: SDL_CreateRGBSurface() returned NULL in CacheGlyphs()!" << endl;
00374 return false;
00375 }
00376
00377
00378 if(SDL_BlitSurface(initial, 0, intermediary, 0) < 0)
00379 {
00380 SDL_FreeSurface(initial);
00381 SDL_FreeSurface(intermediary);
00382 if(VIDEO_DEBUG)
00383 cerr << "VIDEO ERROR: SDL_BlitSurface() failed in CacheGlyphs()!" << endl;
00384 return false;
00385 }
00386
00387 glGenTextures(1, &texture);
00388 if(glGetError())
00389 {
00390 SDL_FreeSurface(initial);
00391 SDL_FreeSurface(intermediary);
00392 if(VIDEO_DEBUG)
00393 cerr << "VIDEO ERROR: glGetError() true after glGenTextures() in CacheGlyphs()!" << endl;
00394 return false;
00395 }
00396
00397 _BindTexture(texture);
00398 if(glGetError())
00399 {
00400 SDL_FreeSurface(initial);
00401 SDL_FreeSurface(intermediary);
00402 if(VIDEO_DEBUG)
00403 cerr << "VIDEO ERROR: glGetError() true after glBindTexture() in CacheGlyphs()!" << endl;
00404 return false;
00405 }
00406
00407 SDL_LockSurface(intermediary);
00408 for(int j = 0; j < w * h ; ++ j)
00409 {
00410 ((uint8*)intermediary->pixels)[j*4+3] = ((uint8*)intermediary->pixels)[j*4+2];
00411
00412 ((uint8*)intermediary->pixels)[j*4+0] =
00413 ((uint8*)intermediary->pixels)[j*4+1] =
00414 ((uint8*)intermediary->pixels)[j*4+2] = 0xff;
00415 }
00416
00417 glTexImage2D(GL_TEXTURE_2D, 0, 4, w, h, 0, GL_RGBA,
00418 GL_UNSIGNED_BYTE, intermediary->pixels );
00419 SDL_UnlockSurface(intermediary);
00420
00421 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00422 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00423
00424
00425 if(glGetError())
00426 {
00427 SDL_FreeSurface(initial);
00428 SDL_FreeSurface(intermediary);
00429 if(VIDEO_DEBUG)
00430 cerr << "VIDEO ERROR: glGetError() true after glTexImage2D() in CacheGlyphs()!" << endl;
00431 return false;
00432 }
00433
00434 int minx, maxx;
00435 int miny, maxy;
00436 int advance;
00437
00438 if(TTF_GlyphMetrics(font, character, &minx, &maxx, &miny, &maxy, &advance))
00439 {
00440 SDL_FreeSurface(initial);
00441 SDL_FreeSurface(intermediary);
00442 if(VIDEO_DEBUG)
00443 cerr << "VIDEO ERROR: glGetError() true after glTexImage2D() in CacheGlyphs()!" << endl;
00444 return false;
00445 }
00446
00447 FontGlyph * glyph = new FontGlyph;
00448 glyph->texture = texture;
00449 glyph->min_x = minx;
00450 glyph->min_y = miny;
00451 glyph->top_y = fp->ascent - maxy;
00452 glyph->width = initial->w + 1;
00453 glyph->height = initial->h + 1;
00454 glyph->max_x = (float)(((double)initial->w + 1) / ((double)w));
00455 glyph->max_y = (float)(((double)initial->h + 1) / ((double)h));
00456 glyph->advance = advance;
00457
00458 fp->glyph_cache->insert(std::pair<uint16, FontGlyph *>(character, glyph));
00459
00460 SDL_FreeSurface(initial);
00461 SDL_FreeSurface(intermediary);
00462 }
00463 return true;
00464 }
00465
00466
00467
00468
00469
00470
00471
00472
00473 bool GameVideo::_DrawTextHelper
00474 (
00475 const uint16 *uText
00476 )
00477 {
00478
00479 if(_font_map.empty())
00480 return false;
00481
00482
00483 if(*uText == 0)
00484 return true;
00485
00486 if(_font_map.find(_current_font) == _font_map.end())
00487 return false;
00488
00489 FontProperties * fp = _font_map[_current_font];
00490
00491 glBlendFunc(GL_ONE, GL_ONE);
00492 glEnable(GL_BLEND);
00493
00494 CoordSys &cs = _coord_sys;
00495
00496 _CacheGlyphs(uText, fp);
00497
00498 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00499
00500 glEnable(GL_TEXTURE_2D);
00501 glDisable(GL_FOG);
00502
00503 glEnable(GL_ALPHA_TEST);
00504 glAlphaFunc(GL_GREATER, 0.1f);
00505
00506 glPushMatrix();
00507
00508 int fontwidth;
00509 int fontheight;
00510 if(TTF_SizeUNICODE(fp->ttf_font, uText, &fontwidth, &fontheight) != 0)
00511 {
00512 if(VIDEO_DEBUG)
00513 cerr << "VIDEO ERROR: TTF_SizeUNICODE() returned NULL in _DrawTextHelper()!" << endl;
00514 return false;
00515 }
00516
00517 float xoff = ((_x_align+1) * fontwidth) * .5f * -cs.GetHorizontalDirection();
00518 float yoff = ((_y_align+1) * fontheight) * .5f * -cs.GetVerticalDirection();
00519
00520 MoveRelative(xoff, yoff);
00521
00522 float modulation = _fader.GetFadeModulation();
00523 Color textColor = _current_text_color * modulation;
00524
00525 int xpos = 0;
00526
00527 GLfloat tex_coords[8];
00528 GLint vertices[8];
00529
00530 glEnableClientState ( GL_VERTEX_ARRAY );
00531 glEnableClientState ( GL_TEXTURE_COORD_ARRAY );
00532
00533 glVertexPointer ( 2, GL_INT, 0, vertices );
00534 glTexCoordPointer ( 2, GL_FLOAT, 0, tex_coords );
00535
00536 for(const uint16 * glyph = uText; *glyph != 0; glyph++)
00537 {
00538 FontGlyph * glyphinfo = (*fp->glyph_cache)[*glyph];
00539
00540 int xhi = glyphinfo->width;
00541 int yhi = glyphinfo->height;
00542
00543 if(cs.GetHorizontalDirection() < 0.0f)
00544 xhi = -xhi;
00545 if(cs.GetVerticalDirection() < 0.0f)
00546 yhi = -yhi;
00547
00548 float tx, ty;
00549 tx = glyphinfo->max_x;
00550 ty = glyphinfo->max_y;
00551
00552 int minx, miny;
00553 minx = glyphinfo->min_x * (int)cs.GetHorizontalDirection() + xpos;
00554 miny = glyphinfo->min_y * (int)cs.GetVerticalDirection();
00555
00556 _BindTexture(glyphinfo->texture);
00557
00558 if(glGetError())
00559 {
00560 if(VIDEO_DEBUG)
00561 cerr << "VIDEO ERROR: glGetError() true after 2nd call to glBindTexture() in _DrawTextHelper!" << endl;
00562 return false;
00563 }
00564
00565 vertices[0] = minx;
00566 vertices[1] = miny;
00567 vertices[2] = minx + xhi;
00568 vertices[3] = miny;
00569 vertices[4] = minx + xhi;
00570 vertices[5] = miny + yhi;
00571 vertices[6] = minx;
00572 vertices[7] = miny + yhi;
00573 tex_coords[0] = 0.0f;
00574 tex_coords[1] = ty;
00575 tex_coords[2] = tx;
00576 tex_coords[3] = ty;
00577 tex_coords[4] = tx;
00578 tex_coords[5] = 0.0f;
00579 tex_coords[6] = 0.0f;
00580 tex_coords[7] = 0.0f;
00581
00582 glColor4fv((GLfloat*)&textColor);
00583 glDrawArrays(GL_QUADS, 0, 4);
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601 xpos += glyphinfo->advance;
00602 }
00603
00604 glDisableClientState ( GL_VERTEX_ARRAY );
00605 glDisableClientState ( GL_TEXTURE_COORD_ARRAY );
00606
00607 glPopMatrix();
00608
00609 if(_fog_intensity > 0.0f)
00610 glEnable(GL_FOG);
00611
00612 glDisable(GL_ALPHA_TEST);
00613
00614
00615
00616 return true;
00617 }
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628 bool GameVideo::DrawText(const string &txt)
00629 {
00630 ustring wstr = MakeUnicodeString(txt);
00631 return DrawText(wstr);
00632 }
00633
00634
00635
00636
00637
00638
00639 bool GameVideo::DrawText(const ustring &txt)
00640 {
00641 if(txt.empty())
00642 {
00643
00644
00645
00646
00647 return true;
00648 }
00649
00650 if(_font_map.find(_current_font) == _font_map.end())
00651 {
00652 if(VIDEO_DEBUG)
00653 cerr << "GameVideo::DrawText() failed because font passed was either not loaded or improperly loaded!\n" <<
00654 " *fontname: " << _current_font << endl;
00655 return false;
00656 }
00657
00658 FontProperties * fp = _font_map[_current_font];
00659 TTF_Font * font = fp->ttf_font;
00660
00661 if(font)
00662 {
00663 _PushContext();
00664 int32 lineSkip = fp->line_skip;
00665
00666
00667 uint16 buffer[2048];
00668 uint16 newline('\n');
00669
00670 size_t lastline = 0;
00671
00672 do
00673 {
00674 size_t nextline;
00675 for(nextline = lastline; nextline < txt.length(); nextline++)
00676 {
00677 if(txt[nextline] == newline)
00678 break;
00679
00680 buffer[nextline - lastline] = txt[nextline];
00681 }
00682 buffer[nextline - lastline] = 0;
00683 lastline = nextline + 1;
00684
00685 glPushMatrix();
00686
00687 Color oldTextColor = _current_text_color;
00688
00689
00690 if(_text_shadow && fp->shadow_style != VIDEO_TEXT_SHADOW_NONE)
00691 {
00692 Color textColor;
00693
00694 switch(fp->shadow_style)
00695 {
00696 case VIDEO_TEXT_SHADOW_DARK:
00697 textColor = Color::black;
00698 textColor[3] = oldTextColor[3] * 0.5f;
00699 break;
00700 case VIDEO_TEXT_SHADOW_LIGHT:
00701 textColor = Color::white;
00702 textColor[3] = oldTextColor[3] * 0.5f;
00703 break;
00704 case VIDEO_TEXT_SHADOW_BLACK:
00705 textColor = Color::black;
00706 textColor[3] = oldTextColor[3];
00707 break;
00708 case VIDEO_TEXT_SHADOW_COLOR:
00709 textColor = oldTextColor;
00710 textColor[3] = oldTextColor[3] * 0.5f;
00711 break;
00712 case VIDEO_TEXT_SHADOW_INVCOLOR:
00713 textColor = Color(1.0f - oldTextColor[0], 1.0f - oldTextColor[1], 1.0f - oldTextColor[2], oldTextColor[3] * 0.5f);
00714 break;
00715 default:
00716 {
00717 if(VIDEO_DEBUG)
00718 cerr << "VIDEO ERROR: Unknown text shadow style (" << fp->shadow_style << ") found in GameVideo::DrawText()!" << endl;
00719 break;
00720 }
00721 };
00722 SetTextColor(textColor);
00723
00724
00725 glPushMatrix();
00726 MoveRelative(+_coord_sys.GetHorizontalDirection() * fp->shadow_x, 0.0f);
00727 MoveRelative(0.0f, _coord_sys.GetVerticalDirection() * fp->shadow_y);
00728
00729 if(!_DrawTextHelper(buffer))
00730 {
00731 _PopContext();
00732 return false;
00733 }
00734 glPopMatrix();
00735 }
00736
00737 SetTextColor(oldTextColor);
00738
00739
00740 if(!_DrawTextHelper(buffer))
00741 {
00742 _PopContext();
00743 return false;
00744 }
00745
00746 glPopMatrix();
00747
00748 MoveRelative(0, -lineSkip * _coord_sys.GetVerticalDirection());
00749
00750 } while(lastline < txt.length());
00751
00752 _PopContext();
00753 }
00754
00755 return true;
00756 }
00757
00758
00759
00760
00761 RenderedString *GameVideo::RenderText(const ustring &txt)
00762 {
00763 if(txt.empty())
00764 {
00765
00766
00767
00768
00769 return NULL;
00770 }
00771
00772 if(_font_map.find(_current_font) == _font_map.end())
00773 {
00774 if(VIDEO_DEBUG)
00775 cerr << "GameVideo::DrawText() failed because font passed was either not loaded or improperly loaded!\n" <<
00776 " *fontname: " << _current_font << endl;
00777 return NULL;
00778 }
00779
00780 FontProperties * fp = _font_map[_current_font];
00781 TTF_Font * font = fp->ttf_font;
00782
00783 if(!font)
00784 {
00785 return NULL;
00786 }
00787
00788 uint16 newline('\n');
00789 int32 lineSkip = fp->line_skip;
00790 std::vector<uint16 *> lineArray;
00791
00792 _CacheGlyphs(txt.c_str(), fp);
00793
00794 const uint16 *charIter;
00795
00796
00797 uint16 *reformattedText = new uint16[txt.size() + 1];
00798 uint16 *reformIter = reformattedText;
00799 uint16 *lastLine = reformattedText;
00800 for (charIter = txt.c_str(); *charIter; ++charIter)
00801 {
00802 if (*charIter == newline)
00803 {
00804 *reformIter++ = '\0';
00805 lineArray.push_back(lastLine);
00806 lastLine = reformIter;
00807 }
00808 else
00809 {
00810 *reformIter++ = *charIter;
00811 }
00812 }
00813 lineArray.push_back(lastLine);
00814 *reformIter = '\0';
00815
00816 std::vector<uint16 *>::iterator lineIter;
00817
00818
00819 Color oldColor = _current_text_color;
00820 int32 shadowOffsetX = 0;
00821 int32 shadowOffsetY = 0;
00822
00823 if(_text_shadow && fp->shadow_style != VIDEO_TEXT_SHADOW_NONE)
00824 {
00825 shadowOffsetX = static_cast<int32>(_coord_sys.GetHorizontalDirection()) * fp->shadow_x;
00826 shadowOffsetY = static_cast<int32>(_coord_sys.GetVerticalDirection()) * fp->shadow_y;
00827 }
00828
00829 RenderedString *rendStr = new RenderedString(lineSkip, shadowOffsetX, shadowOffsetY);
00830
00831 for (lineIter = lineArray.begin(); lineIter != lineArray.end(); ++lineIter)
00832 {
00833 RenderedLine *line = NULL;
00834 if ((line = _GenTexLine(*lineIter, fp)) == NULL)
00835 {
00836 if(VIDEO_DEBUG)
00837 cerr << "Failed to generate line texture for " << MakeStandardString(ustring(*lineIter)) << "." << endl;
00838 delete rendStr;
00839 return NULL;
00840 }
00841 rendStr->Add(line);
00842 }
00843 delete[] reformattedText;
00844
00845 return rendStr;
00846 }
00847
00848
00849
00850
00851
00852
00853 int32 GameVideo::CalculateTextWidth(const std::string &fontName, const hoa_utils::ustring &text)
00854 {
00855 if(!IsValidFont(fontName))
00856 return -1;
00857
00858 int32 w;
00859 if(-1 == TTF_SizeUNICODE(_font_map[fontName]->ttf_font, text.c_str(), &w, NULL))
00860 return -1;
00861
00862 return w;
00863 }
00864
00865
00866
00867
00868
00869
00870 int32 GameVideo::CalculateTextWidth(const std::string &fontName, const std::string &text)
00871 {
00872 if(!IsValidFont(fontName))
00873 return -1;
00874
00875 int32 w;
00876 if(-1 == TTF_SizeText(_font_map[fontName]->ttf_font, text.c_str(), &w, NULL))
00877 return -1;
00878
00879 return w;
00880 }
00881
00882
00883
00884
00885
00886
00887 void GameVideo::EnableTextShadow(bool enable)
00888 {
00889 _text_shadow = enable;
00890 }
00891
00892
00893
00894
00895
00896
00897 bool GameVideo::SetFontShadowXOffset(const std::string &fontName, int32 x)
00898 {
00899 if(_font_map.find(fontName) == _font_map.end())
00900 {
00901 if(VIDEO_DEBUG)
00902 cerr << "VIDEO ERROR: GameVideo::SetFontShadowXOffset() failed for font (" << fontName << ") because the font's properties could not be found!" << endl;
00903 return false;
00904 }
00905
00906 FontProperties *fp = _font_map[fontName];
00907
00908 if(!fp)
00909 {
00910 if(VIDEO_DEBUG)
00911 cerr << "VIDEO ERROR: GameVideo::SetFontShadowXOffset() failed for font (" << fontName << ") because the FontProperties pointer was NULL!" << endl;
00912 return false;
00913 }
00914
00915 fp->shadow_x = x;
00916 return true;
00917 }
00918
00919
00920
00921
00922
00923
00924 bool GameVideo::SetFontShadowYOffset(const std::string &fontName, int32 y)
00925 {
00926 if(_font_map.find(fontName) == _font_map.end())
00927 {
00928 if(VIDEO_DEBUG)
00929 cerr << "VIDEO ERROR: GameVideo::SetFontShadowYOffset() failed for font (" << fontName << ") because the font's properties could not be found!" << endl;
00930 return false;
00931 }
00932
00933 FontProperties *fp = _font_map[fontName];
00934
00935 if(!fp)
00936 {
00937 if(VIDEO_DEBUG)
00938 cerr << "VIDEO ERROR: GameVideo::SetFontShadowYOffset() failed for font (" << fontName << ") because the FontProperties pointer was NULL!" << endl;
00939 return false;
00940 }
00941
00942 fp->shadow_y = y;
00943 return true;
00944 }
00945
00946
00947
00948
00949
00950
00951 bool GameVideo::SetFontShadowStyle(const std::string &fontName, TEXT_SHADOW_STYLE style)
00952 {
00953 if(_font_map.find(fontName) == _font_map.end())
00954 {
00955 if(VIDEO_DEBUG)
00956 cerr << "VIDEO ERROR: GameVideo::SetFontShadowYOffset() failed for font (" << fontName << ") because the font's properties could not be found!" << endl;
00957 return false;
00958 }
00959
00960 FontProperties *fp = _font_map[fontName];
00961
00962 if(!fp)
00963 {
00964 if(VIDEO_DEBUG)
00965 cerr << "VIDEO ERROR: GameVideo::SetFontShadowYOffset() failed for font (" << fontName << ") because the FontProperties pointer was NULL!" << endl;
00966 return false;
00967 }
00968
00969 fp->shadow_style = style;
00970 return true;
00971 }
00972
00973
00974
00975
00976 Color GameVideo::_GetTextShadowColor(FontProperties *fp)
00977 {
00978 Color shadowColor;
00979 if(_text_shadow && fp->shadow_style != VIDEO_TEXT_SHADOW_NONE)
00980 {
00981 switch(fp->shadow_style)
00982 {
00983 case VIDEO_TEXT_SHADOW_DARK:
00984 shadowColor = Color::black;
00985 shadowColor[3] = _current_text_color[3] * 0.5f;
00986 break;
00987 case VIDEO_TEXT_SHADOW_LIGHT:
00988 shadowColor = Color::white;
00989 shadowColor[3] = _current_text_color[3] * 0.5f;
00990 break;
00991 case VIDEO_TEXT_SHADOW_BLACK:
00992 shadowColor = Color::black;
00993 shadowColor[3] = _current_text_color[3];
00994 break;
00995 case VIDEO_TEXT_SHADOW_COLOR:
00996 shadowColor = _current_text_color;
00997 shadowColor[3] = _current_text_color[3] * 0.5f;
00998 break;
00999 case VIDEO_TEXT_SHADOW_INVCOLOR:
01000 shadowColor = Color(1.0f - _current_text_color[0], 1.0f - _current_text_color[1], 1.0f - _current_text_color[2], _current_text_color[3] * 0.5f);
01001 break;
01002 default:
01003 {
01004 if(VIDEO_DEBUG)
01005 cerr << "VIDEO ERROR: Unknown text shadow style (" << fp->shadow_style << ") - GameVideo::_GetTextShadowColor()" << endl;
01006 break;
01007 }
01008 }
01009 }
01010 return shadowColor;
01011 }
01012
01013
01014
01015
01016
01017 RenderedLine::~RenderedLine()
01018 {
01019 }
01020
01021
01022
01023
01024
01025 RenderedLine::RenderedLine(GLuint *tex, int32 lineWidth, int32 texWidth, int32 lineHeight, int32 texHeight, int32 xOffset, int32 yOffset)
01026 : height(lineHeight), width(lineWidth),
01027 x_offset(xOffset), y_offset(yOffset)
01028 {
01029 u = ((float)lineWidth + 1.0f) / (float)texWidth;
01030 v = ((float)lineHeight + 1.0f) / (float)texHeight;
01031 if (tex)
01032 memcpy(texture, tex, sizeof(GLuint) * NUM_TEXTURES);
01033 else
01034 memset(texture, 0, sizeof(GLuint) * NUM_TEXTURES);
01035 }
01036
01037
01038
01039
01040 bool RenderedString::Draw() const
01041 {
01042 return VideoManager->Draw(*this);
01043 }
01044
01045
01046
01047
01048
01049 bool GameVideo::Draw(const RenderedLine &line, int32 texIndex)
01050 {
01051 if (texIndex >= RenderedLine::NUM_TEXTURES
01052 || texIndex < 0)
01053 return false;
01054
01055
01056 if (!line.texture[texIndex])
01057 return false;
01058
01059 if (!_BindTexture(line.texture[texIndex]))
01060 {
01061 if ( VIDEO_DEBUG )
01062 {
01063 cerr << "Failed to bind texture for line draw." << endl;
01064 }
01065 return false;
01066 }
01067
01068 float halfW = line.width * 0.5f;
01069 float halfH = line.height * 0.5f;
01070
01071 glBegin(GL_QUADS);
01072
01073 glTexCoord2f(0.0f, line.v);
01074 glVertex2f(- halfW, - halfH);
01075
01076 glTexCoord2f(line.u, line.v);
01077 glVertex2f(+ halfW, - halfH);
01078
01079 glTexCoord2f(line.u, 0.0f);
01080 glVertex2f(+ halfW, + halfH);
01081
01082 glTexCoord2f(0.0f, 0.0f);
01083 glVertex2f(- halfW, + halfH);
01084
01085 glEnd();
01086
01087 return true;
01088 }
01089
01090
01091
01092
01093
01094 bool RenderedString::Add(RenderedLine *str)
01095 {
01096 lines.push_back(str);
01097 if (str->width > _width)
01098 _width = str->width;
01099 return true;
01100 }
01101
01102
01103
01104
01105 RenderedString::RenderedString(int32 line_skip, int32 shadowX, int32 shadowY)
01106 : _width(0), _line_skip(line_skip),
01107 _shadow_xoff(shadowX), _shadow_yoff(shadowY)
01108 {}
01109
01110
01111
01112
01113 RenderedString::~RenderedString()
01114 {
01115 std::vector<RenderedLine *>::iterator line;
01116 for (line = lines.begin(); line != lines.end(); ++line)
01117 {
01118 VideoManager->_DeleteTexture((*line)->texture[RenderedLine::MAIN_TEXTURE]);
01119 VideoManager->_DeleteTexture((*line)->texture[RenderedLine::SHADOW_TEXTURE]);
01120 delete *line;
01121 }
01122 }
01123
01124
01125
01126
01127 bool GameVideo::Draw(const RenderedString &string)
01128 {
01129 glEnable(GL_BLEND);
01130 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
01131
01132 glEnable(GL_TEXTURE_2D);
01133 glDisable(GL_FOG);
01134
01135 glEnable(GL_ALPHA_TEST);
01136 glAlphaFunc(GL_GREATER, 0.1f);
01137
01138 float xoff = ((_x_align) * string.GetWidth()) * .5f * -_coord_sys.GetHorizontalDirection();
01139
01140 std::vector<RenderedLine*>::const_iterator it;
01141
01142 glPushMatrix();
01143 MoveRelative(xoff, 0.0f);
01144 for (it = string.lines.begin(); it != string.lines.end(); ++it)
01145 {
01146 const RenderedLine &line = *(*it);
01147 if (line.texture[RenderedLine::SHADOW_TEXTURE])
01148 {
01149 glPushMatrix();
01150 MoveRelative(string.GetShadowX(), string.GetShadowY());
01151 Draw(line, RenderedLine::SHADOW_TEXTURE);
01152 glPopMatrix();
01153 }
01154 Draw(line, RenderedLine::MAIN_TEXTURE);
01155 MoveRelative(0.0f, -_coord_sys.GetVerticalDirection() * string.GetLineSkip());
01156 }
01157 glPopMatrix();
01158 return true;
01159 }
01160
01161 }
01162