00001
00002
00003
00004
00005
00006
00007
00008
00009
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00030
00031
00032
00033
00034
00035 #include <stdio.h>
00036 #include <stdlib.h>
00037 #include <string.h>
00038
00039 #include "stratagus.h"
00040
00041 #include <string>
00042 #include <vector>
00043 #include <map>
00044
00045 #include "video.h"
00046 #include "font.h"
00047 #include "script.h"
00048
00049 #include "intern_video.h"
00050
00051
00052
00053
00054
00055 static std::vector<CFont *> AllFonts;
00056 static std::map<std::string, CFont *> Fonts;
00057
00058 static std::vector<CFontColor *> AllFontColors;
00059 std::map<std::string, CFontColor *> FontColors;
00060
00061 static CFontColor *FontColor;
00062
00063 static CFontColor *LastTextColor;
00064 static CFontColor *DefaultTextColor;
00065 static CFontColor *ReverseTextColor;
00066 static std::string DefaultNormalColorIndex;
00067 static std::string DefaultReverseColorIndex;
00068
00073 static std::map<CFont *, std::map<CFontColor *, CGraphic *> > FontColorGraphics;
00074
00075
00076 CFont *SmallFont;
00077 CFont *GameFont;
00078 CFont *LargeFont;
00079
00080
00081
00082
00083
00084
00085 int CFont::Height() const
00086 {
00087 return G->Height;
00088 }
00089
00090 bool CFont::IsLoaded() const
00091 {
00092 return G && G->IsLoaded();
00093 }
00094
00095 void CFont::drawString(gcn::Graphics *graphics, const std::string &txt,
00096 int x, int y)
00097 {
00098 const gcn::ClipRectangle &r = graphics->getCurrentClipArea();
00099 int right = std::min(r.x + r.width - 1, Video.Width - 1);
00100 int bottom = std::min(r.y + r.height - 1, Video.Height - 1);
00101
00102 if (r.x > right || r.y > bottom) {
00103 return;
00104 }
00105
00106 PushClipping();
00107 SetClipping(r.x, r.y, right, bottom);
00108 VideoDrawTextClip(x + r.xOffset, y + r.yOffset, this, txt);
00109 PopClipping();
00110 }
00111
00112
00113
00114
00115
00127 static void VideoDrawChar(const CGraphic *g,
00128 int gx, int gy, int w, int h, int x, int y)
00129 {
00130 if (!UseOpenGL) {
00131 SDL_Rect srect = {gx, gy, w, h};
00132 SDL_Rect drect = {x, y, 0, 0};
00133
00134 SDL_SetColors(g->Surface, FontColor->Colors, 0, MaxFontColors);
00135 SDL_BlitSurface(g->Surface, &srect, TheScreen, &drect);
00136 } else {
00137 g->DrawSub(gx, gy, w, h, x, y);
00138 }
00139 }
00140
00147 void SetDefaultTextColors(const std::string &normal, const std::string &reverse)
00148 {
00149 DefaultNormalColorIndex = normal;
00150 DefaultReverseColorIndex = reverse;
00151 LastTextColor = DefaultTextColor = FontColor = CFontColor::Get(normal);
00152 ReverseTextColor = CFontColor::Get(reverse);
00153 }
00154
00161 void GetDefaultTextColors(std::string &normalp, std::string &reversep)
00162 {
00163 normalp = DefaultNormalColorIndex;
00164 reversep = DefaultReverseColorIndex;
00165 }
00166
00170 static bool GetUTF8(const std::string &text, size_t &pos, int &utf8)
00171 {
00172
00173 if (pos >= text.size()) {
00174 return false;
00175 }
00176
00177 int count;
00178 char c = text[pos++];
00179
00180
00181 if (!(c & 0x80)) {
00182 utf8 = c;
00183 return true;
00184 }
00185
00186 if ((c & 0xE0) == 0xC0) {
00187 utf8 = (c & 0x1F);
00188 count = 1;
00189 } else if ((c & 0xF0) == 0xE0) {
00190 utf8 = (c & 0x0F);
00191 count = 2;
00192 } else if ((c & 0xF8) == 0xF0) {
00193 utf8 = (c & 0x07);
00194 count = 3;
00195 } else if ((c & 0xFC) == 0xF8) {
00196 utf8 = (c & 0x03);
00197 count = 4;
00198 } else if (( c & 0xFE) == 0xFC) {
00199 utf8 = (c & 0x01);
00200 count = 5;
00201 } else {
00202 DebugPrint("Invalid utf8\n");
00203 return false;
00204 }
00205
00206 while (count--) {
00207 c = text[pos++];
00208 if ((c & 0xC0) != 0x80) {
00209 DebugPrint("Invalid utf8\n");
00210 return false;
00211 }
00212 utf8 <<= 6;
00213 utf8 |= (c & 0x3F);
00214 }
00215
00216 return true;
00217 }
00218
00226 int CFont::Width(const std::string &text) const
00227 {
00228 int width = 0;
00229 bool isformat = false;
00230 int utf8;
00231 size_t pos = 0;
00232
00233 while (GetUTF8(text, pos, utf8)) {
00234 if (utf8 == '~') {
00235 if (pos >= text.size()) {
00236 break;
00237 }
00238 if (text[pos] == '<' || text[pos] == '>') {
00239 isformat = false;
00240 ++pos;
00241 continue;
00242 }
00243 if (text[pos] == '!') {
00244 ++pos;
00245 continue;
00246 }
00247 if (text[pos] != '~') {
00248 isformat = !isformat;
00249 continue;
00250 }
00251 }
00252 if (!isformat) {
00253 width += this->CharWidth[utf8 - 32] + 1;
00254 }
00255 }
00256 return width;
00257 }
00258
00259 extern int convertKey(const char *key);
00260
00264 int GetHotKey(const std::string &text)
00265 {
00266 int hotkey = 0;
00267 int utf8;
00268 size_t pos = 0;
00269
00270 while (GetUTF8(text, pos, utf8)) {
00271 if (utf8 == '~') {
00272 if (pos >= text.size()) {
00273 break;
00274 }
00275 if (text[pos] == '<') {
00276 ++pos;
00277 size_t endpos = pos;
00278 while (endpos < text.size()) {
00279 if (text[endpos] == '~') {
00280 break;
00281 }
00282 ++endpos;
00283 }
00284 std::string key = text.substr(pos, endpos - pos);
00285 hotkey = convertKey(key.c_str());
00286 break;
00287 }
00288 if (text[pos] == '!') {
00289 ++pos;
00290 if (pos >= text.size()) {
00291 break;
00292 }
00293 GetUTF8(text, pos, utf8);
00294 hotkey = utf8;
00295 break;
00296 }
00297 }
00298 }
00299
00300 return hotkey;
00301 }
00302
00303 CFont::~CFont()
00304 {
00305 if (G) {
00306 CGraphic::Free(G);
00307 }
00308 delete[] CharWidth;
00309 }
00310
00322 static void VideoDrawCharClip(const CGraphic *g, int gx, int gy, int w, int h,
00323 int x, int y)
00324 {
00325 int ox;
00326 int oy;
00327 int ex;
00328 CLIP_RECTANGLE_OFS(x, y, w, h, ox, oy, ex);
00329 VideoDrawChar(g, gx + ox, gy + oy, w, h, x, y);
00330 }
00331
00349 static int DoDrawText(int x, int y, CFont *font, const std::string &text,
00350 bool clip)
00351 {
00352 int w;
00353 int width;
00354 CFontColor *rev;
00355 char *color;
00356 const char *p;
00357 void (*DrawChar)(const CGraphic *, int, int, int, int, int, int);
00358 int ipr;
00359 int c;
00360 CGraphic *g;
00361 int utf8;
00362 size_t pos;
00363
00364 if (clip) {
00365 DrawChar = VideoDrawCharClip;
00366 } else {
00367 DrawChar = VideoDrawChar;
00368 }
00369
00370 if (!UseOpenGL) {
00371 g = font->G;
00372 } else {
00373 g = FontColorGraphics[font][FontColor];
00374 }
00375
00376 rev = NULL;
00377 width = 0;
00378 pos = 0;
00379 while (GetUTF8(text, pos, utf8)) {
00380 if (utf8 == '~') {
00381 switch (text[pos]) {
00382 case '\0':
00383 DebugPrint("oops, format your ~\n");
00384 return width;
00385 case '~':
00386 ++pos;
00387 break;
00388 case '!':
00389 rev = FontColor;
00390 FontColor = ReverseTextColor;
00391 if (UseOpenGL) {
00392 g = FontColorGraphics[font][FontColor];
00393 }
00394 ++pos;
00395 continue;
00396 case '<':
00397 LastTextColor = FontColor;
00398 FontColor = ReverseTextColor;
00399 if (UseOpenGL) {
00400 g = FontColorGraphics[font][FontColor];
00401 }
00402 ++pos;
00403 continue;
00404 case '>':
00405 rev = LastTextColor;
00406 LastTextColor = FontColor;
00407 FontColor = rev;
00408 if (UseOpenGL) {
00409 g = FontColorGraphics[font][FontColor];
00410 }
00411 ++pos;
00412 continue;
00413
00414 default:
00415 p = text.c_str() + pos;
00416 while (*p && *p !='~') {
00417 ++p;
00418 }
00419 if (!*p) {
00420 DebugPrint("oops, format your ~\n");
00421 return width;
00422 }
00423 color = new char[p - (text.c_str() + pos) + 1];
00424 memcpy(color, text.c_str() + pos, p - (text.c_str() + pos));
00425 color[p - (text.c_str() + pos)] = '\0';
00426 pos = p - text.c_str() + 1;
00427 LastTextColor = FontColor;
00428 CFontColor *fc = CFontColor::Get(color);
00429 if (fc) {
00430 FontColor = fc;
00431 if (UseOpenGL) {
00432 g = FontColorGraphics[font][fc];
00433 }
00434 }
00435 delete[] color;
00436 continue;
00437 }
00438 }
00439
00440 c = utf8 - 32;
00441 Assert(c >= 0);
00442
00443 ipr = font->G->GraphicWidth / font->G->Width;
00444 if (c >= 0 && c < ipr * font->G->GraphicHeight / font->G->Height) {
00445 w = font->CharWidth[c];
00446 DrawChar(g, (c % ipr) * font->G->Width, (c / ipr) * font->G->Height,
00447 w, font->G->Height, x + width, y);
00448 } else {
00449 w = font->CharWidth[0];
00450 DrawChar(g, 0, 0, w, font->G->Height, x + width, y);
00451 }
00452 width += w + 1;
00453 if (rev) {
00454 FontColor = rev;
00455 if (UseOpenGL) {
00456 g = FontColorGraphics[font][FontColor];
00457 }
00458 rev = NULL;
00459 }
00460 }
00461
00462 return width;
00463 }
00464
00477 int VideoDrawText(int x, int y, CFont *font, const std::string &text)
00478 {
00479 return DoDrawText(x, y, font, text, false);
00480 }
00481
00494 int VideoDrawTextClip(int x, int y, CFont *font, const std::string &text)
00495 {
00496 return DoDrawText(x, y, font, text, true);
00497 }
00498
00511 int VideoDrawReverseText(int x, int y, CFont *font, const std::string &text)
00512 {
00513 int width;
00514
00515 FontColor = ReverseTextColor;
00516 width = VideoDrawText(x, y, font, text);
00517 FontColor = DefaultTextColor;
00518
00519 return width;
00520 }
00521
00534 int VideoDrawReverseTextClip(int x, int y, CFont *font, const std::string &text)
00535 {
00536 int width;
00537
00538 FontColor = ReverseTextColor;
00539 width = VideoDrawTextClip(x, y, font, text);
00540 FontColor = DefaultTextColor;
00541
00542 return width;
00543 }
00544
00557 int VideoDrawTextCentered(int x, int y, CFont *font, const std::string &text)
00558 {
00559 int dx;
00560
00561 dx = font->Width(text);
00562 VideoDrawText(x - dx / 2, y, font, text);
00563
00564 return dx / 2;
00565 }
00566
00573 static void FormatNumber(int number, char *buf)
00574 {
00575 char bufs[sizeof(int) * 10 + 2];
00576 int sl;
00577 int s;
00578 int d;
00579
00580 sl = s = d = 0;
00581 sprintf_s(bufs, sizeof(bufs), "%d", number);
00582 sl = strlen(bufs);
00583 do {
00584 if (s > 0 && s < sl && (s - (sl % 3)) % 3 == 0) {
00585 buf[d++] = ',';
00586 }
00587 buf[d++] = bufs[s++];
00588 } while (s <= sl);
00589 }
00590
00601 int VideoDrawNumber(int x, int y, CFont *font, int number)
00602 {
00603 char buf[sizeof(int) * 10 + 2];
00604
00605 FormatNumber(number, buf);
00606 return VideoDrawText(x, y, font, buf);
00607 }
00608
00619 int VideoDrawNumberClip(int x, int y, CFont *font, int number)
00620 {
00621 char buf[sizeof(int) * 10 + 2];
00622
00623 FormatNumber(number, buf);
00624 return VideoDrawTextClip(x, y, font, buf);
00625 }
00626
00637 int VideoDrawReverseNumber(int x, int y, CFont *font, int number)
00638 {
00639 char buf[sizeof(int) * 10 + 2];
00640
00641 FormatNumber(number, buf);
00642 return VideoDrawReverseText(x, y, font, buf);
00643 }
00644
00655 int VideoDrawReverseNumberClip(int x, int y, CFont *font, int number)
00656 {
00657 char buf[sizeof(int) * 10 + 2];
00658
00659 FormatNumber(number, buf);
00660 return VideoDrawReverseTextClip(x, y, font, buf);
00661 }
00662
00666 void CFont::MeasureWidths()
00667 {
00668 const unsigned char *sp;
00669 const unsigned char *lp;
00670 const unsigned char *gp;
00671 Uint32 ckey;
00672 int ipr;
00673
00674 int maxy = G->GraphicWidth / G->Width * G->GraphicHeight / G->Height;
00675 delete[] CharWidth;
00676 CharWidth = new char[maxy];
00677 memset(CharWidth, 0, maxy);
00678 CharWidth[0] = G->Width / 2;
00679 ckey = G->Surface->format->colorkey;
00680 ipr = G->Surface->w / G->Width;
00681
00682 SDL_LockSurface(G->Surface);
00683 for (int y = 1; y < maxy; ++y) {
00684 sp = (const unsigned char *)G->Surface->pixels +
00685 (y / ipr) * G->Surface->pitch * G->Height +
00686 (y % ipr) * G->Width - 1;
00687 gp = sp + G->Surface->pitch * G->Height;
00688
00689 if (gp >= ((const unsigned char *)G->Surface->pixels +
00690 G->Surface->pitch * G->GraphicHeight)) {
00691 break;
00692 }
00693 while (sp < gp) {
00694 lp = sp + G->Width;
00695 for (; sp < lp; --lp) {
00696 if (*lp != ckey && *lp != 7) {
00697 if (lp - sp > CharWidth[y]) {
00698 CharWidth[y] = lp - sp;
00699 }
00700 }
00701 }
00702 sp += G->Surface->pitch;
00703 }
00704
00705 }
00706 SDL_UnlockSurface(G->Surface);
00707 }
00708
00714 void MakeFontColorTextures(CFont *font)
00715 {
00716 SDL_Surface *s;
00717 CGraphic *g;
00718 CGraphic *newg;
00719
00720 if (!FontColorGraphics[font].empty()) {
00721
00722 return;
00723 }
00724
00725 g = font->G;
00726 s = g->Surface;
00727 for (int i = 0; i < (int)AllFontColors.size(); ++i) {
00728 CFontColor *fc = AllFontColors[i];
00729 newg = FontColorGraphics[font][fc] = new CGraphic;
00730 newg->Width = g->Width;
00731 newg->Height = g->Height;
00732 newg->NumFrames = g->NumFrames;
00733 newg->GraphicWidth = g->GraphicWidth;
00734 newg->GraphicHeight = g->GraphicHeight;
00735 newg->Surface = g->Surface;
00736
00737 SDL_LockSurface(s);
00738 for (int j = 0; j < MaxFontColors; ++j) {
00739 s->format->palette->colors[j] = fc->Colors[j];
00740 }
00741 SDL_UnlockSurface(s);
00742
00743 MakeTexture(newg);
00744 }
00745 }
00746
00750 void LoadFonts()
00751 {
00752 CGraphic *g;
00753
00754 for (int i = 0; i < (int)AllFonts.size(); ++i) {
00755 if ((g = AllFonts[i]->G)) {
00756 ShowLoadProgress("Fonts %s", g->File.c_str());
00757 g->Load();
00758 AllFonts[i]->MeasureWidths();
00759 if (UseOpenGL) {
00760 MakeFontColorTextures(AllFonts[i]);
00761 }
00762 }
00763 }
00764
00765
00766 SmallFont = CFont::Get("small");
00767 GameFont = CFont::Get("game");
00768 LargeFont = CFont::Get("large");
00769 }
00770
00774 void FreeOpenGLFonts()
00775 {
00776 for (int i = 0; i < (int)AllFonts.size(); ++i) {
00777 CFont *font = AllFonts[i];
00778 if (font->G) {
00779 for (int j = 0; j < (int)AllFontColors.size(); ++j) {
00780 CGraphic *g = FontColorGraphics[font][AllFontColors[j]];
00781 glDeleteTextures(g->NumTextures, g->Textures);
00782 }
00783 }
00784 }
00785 }
00786
00790 void ReloadFonts()
00791 {
00792 for (int i = 0; i < (int)AllFonts.size(); ++i) {
00793 CFont *font = AllFonts[i];
00794 if (font->G) {
00795 for (int j = 0; j < (int)AllFontColors.size(); ++j) {
00796 CGraphic *g = FontColorGraphics[font][AllFontColors[j]];
00797 delete[] g->Textures;
00798 delete g;
00799 }
00800 FontColorGraphics[font].clear();
00801 MakeFontColorTextures(font);
00802 }
00803 }
00804 }
00805
00814 CFont *CFont::New(const std::string &ident, CGraphic *g)
00815 {
00816 CFont *font = Fonts[ident];
00817 if (font) {
00818 if (font->G != g) {
00819 CGraphic::Free(font->G);
00820 }
00821 font->G = g;
00822 } else {
00823 font = new CFont(ident);
00824 font->G = g;
00825 AllFonts.push_back(font);
00826 Fonts[ident] = font;
00827 }
00828 return font;
00829 }
00830
00838 CFont *CFont::Get(const std::string &ident)
00839 {
00840 CFont *font = Fonts[ident];
00841 if (!font) {
00842 DebugPrint("font not found: %s" _C_ ident.c_str());
00843 }
00844 return font;
00845 }
00846
00850 CFontColor::CFontColor(const std::string &ident)
00851 {
00852 Ident = ident;
00853 memset(Colors, 0, sizeof(Colors));
00854 }
00855
00859 CFontColor::~CFontColor()
00860 {
00861 }
00862
00870 CFontColor *CFontColor::New(const std::string &ident)
00871 {
00872 CFontColor *fc = FontColors[ident];
00873 if (fc) {
00874 return fc;
00875 } else {
00876 fc = new CFontColor(ident);
00877 FontColors[ident] = fc;
00878 AllFontColors.push_back(fc);
00879 return fc;
00880 }
00881 }
00882
00890 CFontColor *CFontColor::Get(const std::string &ident)
00891 {
00892 CFontColor *fc = FontColors[ident];
00893 if (!fc) {
00894 DebugPrint("font color not found: %s" _C_ ident.c_str());
00895 }
00896 return fc;
00897 }
00898
00902 void CleanFonts()
00903 {
00904 int i;
00905
00906 for (i = 0; i < (int)AllFonts.size(); ++i) {
00907 CFont *font = AllFonts[i];
00908
00909 if (UseOpenGL) {
00910 if (!FontColorGraphics[font].empty()) {
00911 for (int j = 0; j < (int)AllFontColors.size(); ++j) {
00912 CGraphic *g = FontColorGraphics[font][AllFontColors[j]];
00913 glDeleteTextures(g->NumTextures, g->Textures);
00914 delete[] g->Textures;
00915 delete g;
00916 }
00917 FontColorGraphics[font].clear();
00918 }
00919 }
00920
00921 delete font;
00922 }
00923 if (UseOpenGL) {
00924 FontColorGraphics.clear();
00925 }
00926 AllFonts.clear();
00927 Fonts.clear();
00928
00929 for (i = 0; i < (int)AllFontColors.size(); ++i) {
00930 delete AllFontColors[i];
00931 }
00932 AllFontColors.clear();
00933 FontColors.clear();
00934
00935 SmallFont = NULL;
00936 GameFont = NULL;
00937 LargeFont = NULL;
00938 }
00939