00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "rFont.h"
00029 #include "rScreen.h"
00030 #include "tConfiguration.h"
00031 #include "tDirectories.h"
00032 #include "tCoord.h"
00033 #include "rTexture.h"
00034 #include <ctype.h>
00035
00036 #ifndef DEDICATED
00037 #include "rRender.h"
00038 #include <FTGLPixmapFont.h>
00039 #include <FTGLBitmapFont.h>
00040 #include <FTGLTextureFont.h>
00041 #include <FTGLPolygonFont.h>
00042 #include <FTGLOutlineFont.h>
00043 #include <FTGLExtrdFont.h>
00044
00045
00046 #endif
00047
00048 static REAL sr_bigFontThresholdWidth = 12;
00049 static REAL sr_bigFontThresholdHeight = 24;
00050
00051 static tSettingItem< REAL > sr_bigFontThresholdWidthConf( "FONT_BIG_THRESHOLD_WIDTH", sr_bigFontThresholdWidth );
00052 static tSettingItem< REAL > sr_bigFontThresholdHeightConf( "FONT_BIG_THRESHOLD_HEIGHT", sr_bigFontThresholdHeight );
00053
00054 class rFont:public rFileTexture{
00055 int offset;
00056 REAL cwidth;
00057 REAL cheight;
00058 REAL onepixel;
00059 rFont *lowerPart;
00060 public:
00061 rFont(const char *fileName,int Offset=0,REAL CWidth=(1/16.0),
00062 REAL CHeight=(1/8.0),REAL onepixel=1/256.0, rFont *lower=NULL);
00063 rFont(const char *fileName, rFont *lower);
00064 virtual ~rFont();
00065
00066 #ifndef DEDICATED
00067
00068 void Render(unsigned char c,REAL left,REAL top,REAL right,REAL bot);
00069 #endif
00070 static rFont s_defaultFont,s_defaultFontSmall;
00071
00072 protected:
00073 virtual void ProcessImage(SDL_Surface *);
00074 virtual void OnSelect( bool enforce );
00075 };
00076 rFont::rFont(const char *fileName,int Offset,REAL CWidth,REAL CHeight,REAL op, rFont *lower):
00077 rFileTexture(rTextureGroups::TEX_FONT,fileName,0,0),
00078 offset(Offset),cwidth(CWidth),cheight(CHeight),
00079 onepixel(op),lowerPart(lower)
00080 {
00081 StoreAlpha();
00082 }
00083
00084 rFont::rFont(const char *fileName, rFont *lower):
00085 rFileTexture(rTextureGroups::TEX_FONT,fileName,0,0),
00086 offset(0),cwidth(1/16.0),cheight(1/8.0),
00087 onepixel(1/256.0),lowerPart(lower)
00088 {
00089 StoreAlpha();
00090 }
00091
00092 rFont::~rFont(){}
00093
00094
00095
00096
00097
00098
00102
00103
00104 void rFont::ProcessImage( SDL_Surface * surface )
00105 {
00106 #ifndef DEDICATED
00107 if ( sr_alphaBlend )
00108 return;
00109
00110
00111 GLubyte *pixels =reinterpret_cast<GLubyte *>(surface->pixels);
00112
00113 if (surface->format->BytesPerPixel == 4)
00114 {
00115 for (int i=surface->w*surface->h-1;i>=0;i--){
00116 GLubyte alpha=pixels[4*i+3];
00117 pixels[4*i ] = (alpha * pixels[4*i ]) >> 8;
00118 pixels[4*i+1] = (alpha * pixels[4*i+1]) >> 8;
00119 pixels[4*i+2] = (alpha * pixels[4*i+2]) >> 8;
00120 }
00121 }
00122 else if (surface->format->BytesPerPixel == 2)
00123 {
00124 for (int i=surface->w*surface->h-1;i>=0;i--){
00125 GLubyte alpha=pixels[2*i+1];
00126 pixels[2*i ] = (alpha * pixels[2*i ]) >> 8;
00127 }
00128 }
00129 #endif
00130 }
00131
00132 void rFont::OnSelect( bool enforce )
00133 {
00134 rISurfaceTexture::OnSelect( enforce );
00135 if ( !Loaded() && sr_glOut )
00136 {
00137
00138 tERR_ERROR( "Font file " << this->GetFileName() << " could not be loaded.");
00139 }
00140 }
00141
00142
00143 #ifndef DEDICATED
00144 void rFont::Render(unsigned char c,REAL left,REAL top,REAL right,REAL bot){
00145
00146
00147
00148
00149 {
00150 c-=offset;
00151
00152 int x=c%16;
00153 int y=c/16;
00154
00155 REAL pix = onepixel *.1;
00156 if (rTextureGroups::TextureMode[rTextureGroups::TEX_FONT] != GL_NEAREST && rTextureGroups::TextureMode[rTextureGroups::TEX_FONT] != GL_NEAREST_MIPMAP_NEAREST)
00157 pix = onepixel * .5;
00158
00159
00160 REAL ttop=y*cheight+pix;
00161 REAL tbot=(y+1)*cheight-pix;
00162 REAL tleft=x*cwidth+pix;
00163 REAL tright=(x+1)*cwidth-pix;
00164
00165 rFont* select = this;
00166 while (ttop > .999 && select->lowerPart)
00167 {
00168 tbot -= 1;
00169 ttop -= 1;
00170 select = select->lowerPart;
00171 }
00172 select->Select(true);
00173
00174 BeginQuads();
00175 glTexCoord2f(tright,tbot);
00176 glVertex2f( right, bot);
00177
00178 glTexCoord2f(tright,ttop);
00179 glVertex2f( right ,top);
00180
00181 glTexCoord2f(tleft,ttop);
00182 glVertex2f( left, top);
00183
00184 glTexCoord2f(tleft,tbot);
00185 glVertex2f( left, bot);
00186 RenderEnd();
00187 }
00188 }
00189 #endif
00190
00191 static rFont sr_lowerPartFont("textures/font_extra.png");
00192 rFont rFont::s_defaultFont("textures/font.png", &sr_lowerPartFont);
00193 rFont rFont::s_defaultFontSmall("textures/font_s.png",32,5/128.0,9/128.0,1/128.0);
00194
00195 #ifndef DEDICATED
00196
00197 int sr_fontType = sr_fontTexture;
00198 static tConfItem< int > sr_fontTypeConf( "FONT_TYPE", sr_fontType, &sr_ReloadFont);
00199
00200 static float sr_fontSizeFactor = .9;
00201 static tConfItem< float > sr_fontSizeFactorConf( "FONT_SIZE_FACTOR", sr_fontSizeFactor, &sr_ReloadFont );
00202
00203 class rFontContainer : std::map<int, FTFont *> {
00204 FTFont &New(int size);
00205 FTFont *Load(tString const &path);
00206 public:
00207 void clear() {
00208 for(iterator i = begin(); i != end(); ++i) {
00209 delete i->second;
00210 }
00211 std::map<int, FTFont *>::clear();
00212 }
00213 float GetWidth(tString const &str, float height) {
00214 if(sr_fontType == sr_fontPixmap) {
00215 return height*(height*sr_screenHeight < sr_bigFontThresholdHeight ? .41 : .5)*str.size();
00216 }
00217 return GetFont(height).Advance(str.c_str())/sr_screenWidth*2.;
00218 }
00219 void Render(tString const &str, float height, tCoord const &where) {
00220 if (sr_fontType != sr_fontOld) {
00221 if(sr_fontType >= sr_fontTexture) {
00222 glPushMatrix();
00223 glTranslatef(where.x, where.y, 0.);
00224 glScalef(2./sr_screenWidth, 2./sr_screenHeight, 1.);
00225 if(sr_fontType == sr_fontTexture) {
00226 glEnable(GL_TEXTURE_2D);
00227 glEnable(GL_BLEND);
00228 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00229 }
00230 if(sr_fontType == sr_fontExtruded) {
00231 glEnable( GL_DEPTH_TEST);
00232 glDisable( GL_BLEND);
00233 glEnable(GL_TEXTURE_2D);
00234 static rFileTexture sg_RimWallNoWrap(rTextureGroups::TEX_WALL,"textures/dir_wall.png",1,0);
00235 sg_RimWallNoWrap.Select();
00236 glRotatef(45,1.,0.,0.);
00237 }
00238 } else {
00239 glRasterPos2f(where.x, where.y);
00240 }
00241 GetFont(height).Render(str.c_str());
00242 if(sr_fontType >= sr_fontTexture) {
00243 glPopMatrix();
00244 }
00245 } else {
00246 rFont *font;
00247 float widthFactor;
00248 if (height*sr_screenHeight < sr_bigFontThresholdHeight) {
00249 font = &rFont::s_defaultFontSmall;
00250 widthFactor = .41;
00251 } else {
00252 font = &rFont::s_defaultFont;
00253 widthFactor = .5;
00254 }
00255 float left = where.x;
00256 for(tString::const_iterator i = str.begin(); i < str.end(); ++i, left += height*widthFactor) {
00257
00258 font->Render(*i, left, where.y+height, left+widthFactor*height, where.y);
00259
00260 }
00261 }
00262 }
00263 FTFont &GetFont(float height) {
00264 int size = int(height*sr_fontSizeFactor*sr_screenHeight/2.+.5);
00265 if(count(size)) {
00266 return *((*this)[size]);
00267 } else {
00268 return New(size);
00269 }
00270 }
00271 void BBox(tString const &str, float height, tCoord where, float &l, float &b, float &r, float &t) {
00272 if(sr_fontType != sr_fontOld) {
00273 float rubbish;
00274 GetFont(height).BBox(str.c_str(), l, b, rubbish, r, t, rubbish);
00275 l/=sr_screenWidth/2.;
00276 r/=sr_screenWidth/2.;
00277 t/=sr_screenHeight/2.;
00278 b/=sr_screenHeight/2.;
00279 l+=where.x-0.005;
00280 r+=where.x+0.005;
00281 t+=where.y+0.005;
00282 b+=where.y-0.005;
00283 return;
00284 } else {
00285 l=where.x;
00286 r=where.x+GetWidth(str, height);
00287 b=where.y;
00288 t=where.y+height;
00289 }
00290 }
00291 ~rFontContainer() {
00292 clear();
00293 }
00294 };
00295
00296
00297
00298 tString fontFile("Armagetronad.ttf");
00299 static tConfItemLine ff("FONT_FILE", fontFile, &sr_ReloadFont);
00300
00301 static tString customFont("");
00302 static tConfItemLine ffc("FONT_FILE_CUSTOM", customFont, &sr_ReloadFont);
00303
00304 static int useCustomFont = 0;
00305 static tConfItem<int> ufc("USE_CUSTOM_FONT", useCustomFont, &sr_ReloadFont);
00306
00307 static rCallbackBeforeScreenModeChange reloadft(&sr_ReloadFont);
00308
00309 FTFont *rFontContainer::Load(tString const &path) {
00310 FTFont *font;
00311 switch (sr_fontType) {
00312 case sr_fontPixmap:
00313 font = new FTGLPixmapFont(path);
00314 break;
00315 case sr_fontBitmap:
00316 font = new FTGLBitmapFont(path);
00317 break;
00318 case sr_fontPolygon:
00319 font = new FTGLPolygonFont(path);
00320 break;
00321 case sr_fontOutline:
00322 font = new FTGLOutlineFont(path);
00323 break;
00324 case sr_fontExtruded:
00325 font = new FTGLExtrdFont(path);
00326 reinterpret_cast<FTGLExtrdFont *>(font)->Depth(10.);
00327 break;
00328 default:
00329 font = new FTGLTextureFont(path);
00330 }
00331 return font;
00332 }
00333 FTFont &rFontContainer::New(int size) {
00334 FTFont *font;
00335 tString theFontFile("");
00336
00337 if(useCustomFont == 1) {
00338 theFontFile = customFont;
00339 } else {
00340 theFontFile = "textures/" + fontFile;
00341 theFontFile = tDirectories::Data().GetReadPath(theFontFile);
00342 }
00343 font = Load(theFontFile);
00344
00345
00346 if(font->Error()) {
00347 std::cerr << "Error while loading font from path '" << theFontFile << "'. Error code: " << font->Error() << std::endl;
00348
00349 std::cerr << "Loading default font instead. Sorry." << std::endl;
00350 font = Load(tDirectories::Data().GetReadPath("textures/Armagetronad.ttf"));
00351
00352 }
00353 font->FaceSize(size);
00354 (*this)[size] = font;
00355 return *font;
00356 }
00357 rFontContainer sr_Font;
00358
00359 void sr_ReloadFont(void) {
00360 sr_Font.clear();
00361 }
00362 #endif
00363
00364 rTextField::rTextField(REAL Left,REAL Top,
00365 REAL Cheight, sr_fontClass Type)
00366 :parIndent(0),
00367 left(Left),top(Top),cheight(Cheight),x(0),y(0),realx(0),nextx(Left),currentWidth(0),multiline(false),type(Type),cursor(0),cursorPos(0){
00368 if (cheight*sr_screenHeight<18)
00369 {
00370 cheight=18/REAL(sr_screenHeight);
00371 }
00372
00373 color_ = defaultColor_;
00374
00375 width = 1.-Left;
00376
00377
00378
00379
00380
00381
00382 cursor_x = -100;
00383 cursor_y = -100;
00384 }
00385
00386
00387 rTextField::~rTextField(){
00388 FlushLine();
00389
00390 #ifndef DEDICATED
00391 if (cursor && sr_glOut){
00392 if (cursor==2)
00393 glColor4f(1,1,1,.5);
00394 else
00395 glColor3f(1,1,0);
00396
00397
00398 glDisable(GL_TEXTURE_2D);
00399
00400 BeginLines();
00401 glVertex2f(cursor_x,cursor_y);
00402 glVertex2f(cursor_x,cursor_y-cheight);
00403 RenderEnd();
00404 }
00405 #endif
00406 }
00407
00408
00409 static REAL sr_minR = .5, sr_minG = .5, sr_minB =.5, sr_minTotal = .7;
00410 tSettingItem< REAL > sr_minRConf( "FONT_MIN_R", sr_minR );
00411 tSettingItem< REAL > sr_minGConf( "FONT_MIN_G", sr_minG );
00412 tSettingItem< REAL > sr_minBConf( "FONT_MIN_B", sr_minB );
00413 tSettingItem< REAL > sr_minTotalConf( "FONT_MIN_TOTAL", sr_minTotal );
00414
00415 void rTextField::FlushLine(int len,bool newline){
00416 #ifndef DEDICATED
00417 float realTop = top-y*cheight;
00418 tString str(buffer.SubStr(realx, len));
00419 realx += len;
00420 if (len >= cursorPos && cursorPos >= 0) {
00421 cursor_y=realTop;
00422 cursor_x=nextx+sr_Font.GetWidth(str.SubStr(0, cursorPos), cheight);
00423 }
00424 cursorPos -= len+1;
00425 float thisx = nextx+sr_Font.GetWidth(str, cheight);
00426
00427 REAL r = color_.r_;
00428 REAL g = color_.g_;
00429 REAL b = color_.b_;
00430 REAL a = color_.a_;
00431
00432 if (sr_glOut)
00433 {
00434
00435 if ( r < sr_minR && g < sr_minG && b < sr_minG || r+g+b < sr_minTotal )
00436 {
00437 if ( sr_alphaBlend && !str.empty() )
00438 {
00439
00440 glDisable(GL_TEXTURE_2D);
00441
00442 glColor4f( blendColor_.r_, blendColor_.g_, blendColor_.b_, a * blendColor_.a_ );
00443
00444 float l,t,r,b;
00445
00446 sr_Font.BBox(str, cheight, tCoord(nextx, realTop-cheight), l, b, r, t);
00447
00448
00449
00450 BeginQuads();
00451
00452 glVertex2f( l, b);
00453
00454 glVertex2f( r, b);
00455
00456 glVertex2f( r ,t);
00457
00458 glVertex2f( l, t);
00459 RenderEnd();
00460 }
00461 else
00462 {
00463 if ( r < .5 ) r = .5;
00464 if ( g < .5 ) g = .5;
00465 if ( b < .5 ) b = .5;
00466 }
00467 }
00468
00469 glColor4f(r * blendColor_.r_,g * blendColor_.g_,b * blendColor_.b_,a * blendColor_.a_);
00470 }
00471
00472
00473 glRasterPos2f(nextx, realTop-cheight);
00474 sr_Font.Render(str, cheight, tCoord(nextx, realTop-cheight));
00475 nextx = thisx;
00476
00477 #endif
00478
00479
00480
00481
00482
00483
00484
00485 if (newline){
00486 y++;
00487 realx=x=0;
00488 nextx=left;
00489 }
00490 else
00491 {
00492
00493
00494 }
00495
00496 }
00497
00498 void rTextField::FlushLine(bool newline){
00499 FlushLine(buffer.Size()-realx,newline);
00500 }
00501
00502 inline void rTextField::WriteChar(unsigned char c)
00503 {
00504 switch (c){
00505 case('\n'):
00506 FlushLine();
00507 buffer.Clear();
00508 break;
00509 default:
00510 buffer += c;
00511 x++;
00512 break;
00513 }
00514 }
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553 #ifndef DEDICATED
00554 static REAL CTR(int x){
00555 return x/255.0;
00556 }
00557 #endif
00558
00559 static char hex_array[]="0123456789abcdef";
00560
00561 char int_to_hex(int i){
00562 if (i<0 || i >15)
00563 return 'Q';
00564 else
00565 return hex_array[i];
00566 }
00567
00568 int hex_to_int(char c){
00569 int ret=0;
00570 for (int i=15;i>=0;i--)
00571 if (hex_array[i]==c)
00572 ret=i;
00573 return ret;
00574 }
00575
00576 rTextField & rTextField::StringOutput(const char * c, ColorMode colorMode )
00577 {
00578 #ifndef DEDICATED
00579
00580 float const &maxWidth = width;
00581 bool lastIsNewline = true;
00582 bool trouble = false;
00583 static tString spaces;
00584
00585 while (*c!='\0')
00586 {
00587 if (trouble && !(*c=='0' && strlen(c)>=8 && c[1]=='x' && colorMode != COLOR_IGNORE)) {
00588 tString str;
00589 str << *c;
00590 currentWidth += sr_Font.GetWidth(str, cheight);
00591 if(isspace(*c)) {
00592 trouble = false;
00593 } else if ( currentWidth >= maxWidth) {
00594 WriteChar('\n');
00595 spaces.clear();
00596 for ( int i = parIndent-1; i >= 0; --i )
00597 {
00598 WriteChar(' ');
00599 spaces << ' ';
00600 cursorPos++;
00601 }
00602 currentWidth = sr_Font.GetWidth(spaces, cheight);
00603 }
00604 }
00605
00606 if ( !trouble && multiline && (isblank(*c) || lastIsNewline) )
00607 {
00608 lastIsNewline = false;
00609
00610 char const * nextSpace = c+1;
00611 int wordLen = 0;
00612 while ( *nextSpace != '\0' && *nextSpace != '\n' && !isblank(*nextSpace) )
00613 {
00614 if (*nextSpace=='0' && strlen(nextSpace)>=8 && nextSpace[1]=='x' && colorMode != COLOR_IGNORE )
00615 {
00616
00617 nextSpace += 8;
00618 }
00619 else
00620 {
00621
00622 nextSpace++;
00623 wordLen++;
00624 }
00625 }
00626 tString str(c, nextSpace);
00627 str = tColoredString::RemoveColors(str.c_str());
00628 float wordWidth = sr_Font.GetWidth(str, cheight);
00629
00630 currentWidth += wordWidth;
00631 if ( currentWidth >= maxWidth)
00632 {
00633 WriteChar('\n');
00634 c++;
00635
00636 spaces.clear();
00637 for ( int i = parIndent-1; i >= 0; --i )
00638 {
00639 WriteChar(' ');
00640 spaces << ' ';
00641 cursorPos++;
00642 }
00643 float spaceWidth = sr_Font.GetWidth(spaces, cheight);
00644
00645 if (wordWidth >= maxWidth) {
00646 trouble = true;
00647 currentWidth = spaceWidth;
00648 } else {
00649 currentWidth = wordWidth + spaceWidth;
00650 }
00651 continue;
00652 }
00653 }
00654 if ( *c == '\n' ) {
00655 lastIsNewline = true;
00656 currentWidth = 0.;
00657 cursorPos += 1;
00658 }
00659
00661
00662
00663
00664
00665
00666
00667
00668 if (*c=='0' && strlen(c)>=8 && c[1]=='x' && colorMode != COLOR_IGNORE )
00669 {
00670 tColor color;
00671 bool use = false;
00672
00673 if ( 0 ==strncmp(c,"0xRESETT",8) )
00674 {
00675
00676 color = defaultColor_;
00677 use = true;
00678 }
00679 else
00680 {
00681
00682 cursorPos-=8;
00683 color.r_=CTR(hex_to_int(c[2])*16+hex_to_int(c[3]));
00684 color.g_=CTR(hex_to_int(c[4])*16+hex_to_int(c[5]));
00685 color.b_=CTR(hex_to_int(c[6])*16+hex_to_int(c[7]));
00686 use = true;
00687 }
00688
00689
00690 if ( colorMode == COLOR_USE )
00691 {
00692 c+=8;
00693 }
00694 else
00695 {
00696
00697 cursorPos+=8;
00698 for(int i=7; i>=0;--i)
00699 WriteChar(*(c++));
00700 }
00701
00702
00703 if ( use )
00704 {
00705 FlushLine(false);
00706 cursorPos++;
00707 color_ = color;
00708 }
00709 }
00710 else
00711
00712 WriteChar(*(c++));
00713 }
00714 #endif
00715 return *this;
00716 }
00717
00718 void DisplayText(REAL x,REAL y,REAL h,const char *text,sr_fontClass type,int center,int cursor,int cursorPos, rTextField::ColorMode colorMode){
00719 #ifndef DEDICATED
00720 float height;
00721 float width = rTextField::GetTextLength(tString(text), h, true, true, &height);
00722
00723
00724 REAL maxw = 1.95 - x;
00725 if ( width > maxw )
00726 {
00727 h *= maxw/(width);
00728 width=maxw;
00729 }
00730
00731 rTextField c(x-(center+1)*width*.5,y+h*.5,h,type);
00732 if (center==-1)
00733 c.SetWidth(1.-x);
00734 else
00735 c.SetWidth(10000);
00736
00737 c.SetIndent(5);
00738 if (cursor)
00739 c.SetCursor(cursor,cursorPos);
00740 c.StringOutput(text, colorMode );
00741 #endif
00742 }
00743
00744
00745
00746
00747
00751
00752
00753 tColor const & rTextField::GetDefaultColor( void )
00754 {
00755 return defaultColor_;
00756 }
00757
00758
00759
00760
00761
00762
00766
00767
00768 void rTextField::GetDefaultColor( tColor & defaultColor )
00769 {
00770 defaultColor = defaultColor_;
00771 }
00772
00773
00774
00775
00776
00777
00781
00782
00783 void rTextField::SetDefaultColor( tColor const & defaultColor )
00784 {
00785 defaultColor_ = defaultColor;
00786 blendColor_ = tColor();
00787 }
00788
00789
00790
00791
00792
00793
00797
00798
00799 tColor const & rTextField::GetBlendColor( void )
00800 {
00801 return blendColor_;
00802 }
00803
00804
00805
00806
00807
00808
00812
00813
00814 void rTextField::GetBlendColor( tColor & blendColor )
00815 {
00816 blendColor = blendColor_;
00817 }
00818
00819
00820
00821
00822
00823
00827
00828
00829 void rTextField::SetBlendColor( tColor const & blendColor )
00830 {
00831 blendColor_ = blendColor;
00832 }
00833
00834 tColor rTextField::defaultColor_;
00835 tColor rTextField::blendColor_;
00836
00837 #ifndef DEDICATED
00844 float rTextField::GetTextLength (tString const &str, float height, bool stripColors, bool useNewline, float *resultingHeight) {
00845 if(stripColors) {
00846 return sr_Font.GetWidth(tColoredString::RemoveColors(str.c_str()), height);
00847 }
00848 return sr_Font.GetWidth(str, height);
00849 }
00850 #endif