llfontgl.cpp

Go to the documentation of this file.
00001 
00032 #include "linden_common.h"
00033 
00034 #include <boost/tokenizer.hpp>
00035 
00036 #include "llfont.h"
00037 #include "llfontgl.h"
00038 #include "llgl.h"
00039 #include "llglimmediate.h"
00040 #include "v4color.h"
00041 #include "llstl.h"
00042 
00043 const S32 BOLD_OFFSET = 1;
00044 
00045 // static class members
00046 F32 LLFontGL::sVertDPI = 96.f;
00047 F32 LLFontGL::sHorizDPI = 96.f;
00048 F32 LLFontGL::sScaleX = 1.f;
00049 F32 LLFontGL::sScaleY = 1.f;
00050 BOOL LLFontGL::sDisplayFont = TRUE ;
00051 LLString LLFontGL::sAppDir;
00052 
00053 LLFontGL* LLFontGL::sMonospace = NULL;
00054 LLFontGL* LLFontGL::sSansSerifSmall = NULL;
00055 LLFontGL* LLFontGL::sSansSerif = NULL;
00056 LLFontGL* LLFontGL::sSansSerifBig = NULL;
00057 LLFontGL* LLFontGL::sSansSerifHuge = NULL;
00058 LLFontGL* LLFontGL::sSansSerifBold = NULL;
00059 LLFontList*     LLFontGL::sMonospaceFallback = NULL;
00060 LLFontList*     LLFontGL::sSSFallback = NULL;
00061 LLFontList*     LLFontGL::sSSSmallFallback = NULL;
00062 LLFontList*     LLFontGL::sSSBigFallback = NULL;
00063 LLFontList*     LLFontGL::sSSHugeFallback = NULL;
00064 LLFontList*     LLFontGL::sSSBoldFallback = NULL;
00065 LLColor4 LLFontGL::sShadowColor(0.f, 0.f, 0.f, 1.f);
00066 
00067 LLCoordFont LLFontGL::sCurOrigin;
00068 std::vector<LLCoordFont> LLFontGL::sOriginStack;
00069 
00070 LLFontGL*& gExtCharFont = LLFontGL::sSansSerif;
00071 
00072 const F32 EXT_X_BEARING = 1.f;
00073 const F32 EXT_Y_BEARING = 0.f;
00074 const F32 EXT_KERNING = 1.f;
00075 const F32 PIXEL_BORDER_THRESHOLD = 0.0001f;
00076 const F32 PIXEL_CORRECTION_DISTANCE = 0.01f;
00077 
00078 const F32 PAD_AMT = 0.5f;
00079 const F32 DROP_SHADOW_SOFT_STRENGTH = 0.3f;
00080 
00081 F32 llfont_round_x(F32 x)
00082 {
00083         //return llfloor((x-LLFontGL::sCurOrigin.mX)/LLFontGL::sScaleX+0.5f)*LLFontGL::sScaleX+LLFontGL::sCurOrigin.mX;
00084         //return llfloor(x/LLFontGL::sScaleX+0.5f)*LLFontGL::sScaleY;
00085         return x;
00086 }
00087 
00088 F32 llfont_round_y(F32 y)
00089 {
00090         //return llfloor((y-LLFontGL::sCurOrigin.mY)/LLFontGL::sScaleY+0.5f)*LLFontGL::sScaleY+LLFontGL::sCurOrigin.mY;
00091         //return llfloor(y+0.5f);
00092         return y;
00093 }
00094 
00095 // static
00096 U8 LLFontGL::getStyleFromString(const LLString &style)
00097 {
00098         S32 ret = 0;
00099         if (style.find("NORMAL") != style.npos)
00100         {
00101                 ret |= NORMAL;
00102         }
00103         if (style.find("BOLD") != style.npos)
00104         {
00105                 ret |= BOLD;
00106         }
00107         if (style.find("ITALIC") != style.npos)
00108         {
00109                 ret |= ITALIC;
00110         }
00111         if (style.find("UNDERLINE") != style.npos)
00112         {
00113                 ret |= UNDERLINE;
00114         }
00115         if (style.find("SHADOW") != style.npos)
00116         {
00117                 ret |= DROP_SHADOW;
00118         }
00119         if (style.find("SOFT_SHADOW") != style.npos)
00120         {
00121                 ret |= DROP_SHADOW_SOFT;
00122         }
00123         return ret;
00124 }
00125 
00126 LLFontGL::LLFontGL()
00127         : LLFont()
00128 {
00129         init();
00130         clearEmbeddedChars();
00131 }
00132 
00133 LLFontGL::LLFontGL(const LLFontGL &source)
00134 {
00135         llerrs << "Not implemented!" << llendl;
00136 }
00137 
00138 LLFontGL::~LLFontGL()
00139 {
00140         mImageGLp = NULL;
00141         mRawImageGLp = NULL;
00142         clearEmbeddedChars();
00143 }
00144 
00145 void LLFontGL::init()
00146 {
00147         if (mImageGLp.isNull())
00148         {
00149                 mImageGLp = new LLImageGL(FALSE);
00150                 //RN: use nearest mipmap filtering to obviate the need to do pixel-accurate positioning
00151                 mImageGLp->bind();
00152                 // we allow bilinear filtering to get sub-pixel positioning for drop shadows
00153                 //mImageGLp->setMipFilterNearest(TRUE, TRUE);
00154         }
00155         if (mRawImageGLp.isNull())
00156         {
00157                 mRawImageGLp = new LLImageRaw; // Note LLFontGL owns the image, not LLFont.
00158         }
00159         setRawImage( mRawImageGLp );  
00160 }
00161 
00162 void LLFontGL::reset()
00163 {
00164         init();
00165         resetBitmap();
00166 }
00167 
00168 // static 
00169 LLString LLFontGL::getFontPathSystem()
00170 {
00171         LLString system_path;
00172 
00173         // Try to figure out where the system's font files are stored.
00174         char *system_root = NULL;
00175 #if LL_WINDOWS
00176         system_root = getenv("SystemRoot");     /* Flawfinder: ignore */
00177         if (!system_root)
00178         {
00179                 llwarns << "SystemRoot not found, attempting to load fonts from default path." << llendl;
00180         }
00181 #endif
00182 
00183         if (system_root)
00184         {
00185                 system_path = llformat("%s/fonts/", system_root);
00186         }
00187         else
00188         {
00189 #if LL_WINDOWS
00190                 // HACK for windows 98/Me
00191                 system_path = "/WINDOWS/FONTS/";
00192 #elif LL_DARWIN
00193                 // HACK for Mac OS X
00194                 system_path = "/System/Library/Fonts/";
00195 #endif
00196         }
00197         return system_path;
00198 }
00199 
00200 
00201 // static 
00202 LLString LLFontGL::getFontPathLocal()
00203 {
00204         LLString local_path;
00205 
00206         // Backup files if we can't load from system fonts directory.
00207         // We could store this in an end-user writable directory to allow
00208         // end users to switch fonts.
00209         if (LLFontGL::sAppDir.length())
00210         {
00211                 // use specified application dir to look for fonts
00212                 local_path = LLFontGL::sAppDir + "/fonts/";
00213         }
00214         else
00215         {
00216                 // assume working directory is executable directory
00217                 local_path = "./fonts/";
00218         }
00219         return local_path;
00220 }
00221 
00222 //static
00223 bool LLFontGL::loadFaceFallback(LLFontList *fontlistp, const LLString& fontname, const F32 point_size)
00224 {
00225         LLString local_path = getFontPathLocal();
00226         LLString sys_path = getFontPathSystem();
00227         
00228         // The fontname string may contain multiple font file names separated by semicolons.
00229         // Break it apart and try loading each one, in order.
00230         typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
00231         boost::char_separator<char> sep(";");
00232         tokenizer tokens(fontname, sep);
00233         tokenizer::iterator token_iter;
00234 
00235         for(token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter)
00236         {
00237                 LLFont *fontp = new LLFont();
00238                 LLString font_path = local_path + *token_iter;
00239                 if (!fontp->loadFace(font_path, point_size, sVertDPI, sHorizDPI, 2, TRUE))
00240                 {
00241                         font_path = sys_path + *token_iter;
00242                         if (!fontp->loadFace(font_path, point_size, sVertDPI, sHorizDPI, 2, TRUE))
00243                         {
00244                                 LL_INFOS_ONCE("ViewerImages") << "Couldn't load font " << *token_iter << LL_ENDL;
00245                                 delete fontp;
00246                                 fontp = NULL;
00247                         }
00248                 }
00249                 
00250                 if(fontp)
00251                 {
00252                         fontlistp->addAtEnd(fontp);
00253                 }
00254         }
00255         
00256         // We want to return true if at least one fallback font loaded correctly.
00257         return (fontlistp->size() > 0);
00258 }
00259 
00260 //static
00261 bool LLFontGL::loadFace(LLFontGL *fontp, const LLString& fontname, const F32 point_size, LLFontList *fallback_fontp)
00262 {
00263         LLString local_path = getFontPathLocal();
00264         LLString font_path = local_path + fontname;
00265         if (!fontp->loadFace(font_path, point_size, sVertDPI, sHorizDPI, 2, FALSE))
00266         {
00267                 LLString sys_path = getFontPathSystem();
00268                 font_path = sys_path + fontname;
00269                 if (!fontp->loadFace(font_path, point_size, sVertDPI, sHorizDPI, 2, FALSE))
00270                 {
00271                         LL_WARNS("ViewerImages") << "Couldn't load font " << fontname << LL_ENDL;
00272                         return false;
00273                 }
00274         }
00275 
00276         fontp->setFallbackFont(fallback_fontp);
00277         return true;
00278 }
00279 
00280 
00281 // static
00282 BOOL LLFontGL::initDefaultFonts(F32 screen_dpi, F32 x_scale, F32 y_scale,
00283                                 const LLString& monospace_file, F32 monospace_size,
00284                                 const LLString& sansserif_file,
00285                                 const LLString& sanserif_fallback_file, F32 ss_fallback_scale,
00286                                 F32 small_size, F32 medium_size, F32 big_size, F32 huge_size,
00287                                 const LLString& sansserif_bold_file, F32 bold_size,
00288                                 const LLString& app_dir)
00289 {
00290         BOOL failed = FALSE;
00291         sVertDPI = (F32)llfloor(screen_dpi * y_scale);
00292         sHorizDPI = (F32)llfloor(screen_dpi * x_scale);
00293         sScaleX = x_scale;
00294         sScaleY = y_scale;
00295         sAppDir = app_dir;
00296 
00297         //
00298         // Monospace font
00299         //
00300 
00301         if (!sMonospace)
00302         {
00303                 sMonospace = new LLFontGL();
00304         }
00305         else
00306         {
00307                 sMonospace->reset();
00308         }
00309 
00310         if (sMonospaceFallback)
00311         {
00312                 delete sMonospaceFallback;
00313         }
00314         sMonospaceFallback = new LLFontList();
00315         if (!loadFaceFallback(
00316                         sMonospaceFallback,
00317                         sanserif_fallback_file,
00318                         monospace_size * ss_fallback_scale))
00319         {
00320                 delete sMonospaceFallback;
00321                 sMonospaceFallback = NULL;
00322         }
00323 
00324         failed |= !loadFace(sMonospace, monospace_file, monospace_size, sMonospaceFallback);
00325 
00326         //
00327         // Sans-serif fonts
00328         //
00329         if(!sSansSerifHuge)
00330         {
00331                 sSansSerifHuge = new LLFontGL();
00332         }
00333         else
00334         {
00335                 sSansSerifHuge->reset();
00336         }
00337 
00338         if (sSSHugeFallback)
00339         {
00340                 delete sSSHugeFallback;
00341         }
00342         sSSHugeFallback = new LLFontList();
00343         if (!loadFaceFallback(
00344                         sSSHugeFallback,
00345                         sanserif_fallback_file,
00346                         huge_size*ss_fallback_scale))
00347         {
00348                 delete sSSHugeFallback;
00349                 sSSHugeFallback = NULL;
00350         }
00351 
00352         failed |= !loadFace(sSansSerifHuge, sansserif_file, huge_size, sSSHugeFallback);
00353 
00354 
00355         if(!sSansSerifBig)
00356         {
00357                 sSansSerifBig = new LLFontGL();
00358         }
00359         else
00360         {
00361                 sSansSerifBig->reset();
00362         }
00363 
00364         if (sSSBigFallback)
00365         {
00366                 delete sSSBigFallback;
00367         }
00368         sSSBigFallback = new LLFontList();
00369         if (!loadFaceFallback(
00370                         sSSBigFallback,
00371                         sanserif_fallback_file,
00372                         big_size*ss_fallback_scale))
00373         {
00374                 delete sSSBigFallback;
00375                 sSSBigFallback = NULL;
00376         }
00377 
00378         failed |= !loadFace(sSansSerifBig, sansserif_file, big_size, sSSBigFallback);
00379 
00380 
00381         if(!sSansSerif)
00382         {
00383                 sSansSerif = new LLFontGL();
00384         }
00385         else
00386         {
00387                 sSansSerif->reset();
00388         }
00389 
00390         if (sSSFallback)
00391         {
00392                 delete sSSFallback;
00393         }
00394         sSSFallback = new LLFontList();
00395         if (!loadFaceFallback(
00396                         sSSFallback,
00397                         sanserif_fallback_file,
00398                         medium_size*ss_fallback_scale))
00399         {
00400                 delete sSSFallback;
00401                 sSSFallback = NULL;
00402         }
00403         failed |= !loadFace(sSansSerif, sansserif_file, medium_size, sSSFallback);
00404 
00405 
00406         if(!sSansSerifSmall)
00407         {
00408                 sSansSerifSmall = new LLFontGL();
00409         }
00410         else
00411         {
00412                 sSansSerifSmall->reset();
00413         }
00414 
00415         if(sSSSmallFallback)
00416         {
00417                 delete sSSSmallFallback;
00418         }
00419         sSSSmallFallback = new LLFontList();
00420         if (!loadFaceFallback(
00421                         sSSSmallFallback,
00422                         sanserif_fallback_file,
00423                         small_size*ss_fallback_scale))
00424         {
00425                 delete sSSSmallFallback;
00426                 sSSSmallFallback = NULL;
00427         }
00428         failed |= !loadFace(sSansSerifSmall, sansserif_file, small_size, sSSSmallFallback);
00429 
00430 
00431         //
00432         // Sans-serif bold
00433         //
00434         if(!sSansSerifBold)
00435         {
00436                 sSansSerifBold = new LLFontGL();
00437         }
00438         else
00439         {
00440                 sSansSerifBold->reset();
00441         }
00442 
00443         if (sSSBoldFallback)
00444         {
00445                 delete sSSBoldFallback;
00446         }
00447         sSSBoldFallback = new LLFontList();
00448         if (!loadFaceFallback(
00449                         sSSBoldFallback,
00450                         sanserif_fallback_file,
00451                         medium_size*ss_fallback_scale))
00452         {
00453                 delete sSSBoldFallback;
00454                 sSSBoldFallback = NULL;
00455         }
00456         failed |= !loadFace(sSansSerifBold, sansserif_bold_file, medium_size, sSSBoldFallback);
00457 
00458         return !failed;
00459 }
00460 
00461 
00462 
00463 // static
00464 void LLFontGL::destroyDefaultFonts()
00465 {
00466         delete sMonospace;
00467         sMonospace = NULL;
00468 
00469         delete sSansSerifHuge;
00470         sSansSerifHuge = NULL;
00471 
00472         delete sSansSerifBig;
00473         sSansSerifBig = NULL;
00474 
00475         delete sSansSerif;
00476         sSansSerif = NULL;
00477 
00478         delete sSansSerifSmall;
00479         sSansSerifSmall = NULL;
00480 
00481         delete sSansSerifBold;
00482         sSansSerifBold = NULL;
00483 
00484         delete sMonospaceFallback;
00485         sMonospaceFallback = NULL;
00486 
00487         delete sSSHugeFallback;
00488         sSSHugeFallback = NULL;
00489 
00490         delete sSSBigFallback;
00491         sSSBigFallback = NULL;
00492 
00493         delete sSSFallback;
00494         sSSFallback = NULL;
00495 
00496         delete sSSSmallFallback;
00497         sSSSmallFallback = NULL;
00498 
00499         delete sSSBoldFallback;
00500         sSSBoldFallback = NULL;
00501 }
00502 
00503 //static 
00504 void LLFontGL::destroyGL()
00505 {
00506         if (!sMonospace)
00507         {
00508                 // Already all destroyed.
00509                 return;
00510         }
00511         sMonospace->mImageGLp->destroyGLTexture();
00512         sSansSerifHuge->mImageGLp->destroyGLTexture();
00513         sSansSerifSmall->mImageGLp->destroyGLTexture();
00514         sSansSerif->mImageGLp->destroyGLTexture();
00515         sSansSerifBig->mImageGLp->destroyGLTexture();
00516         sSansSerifBold->mImageGLp->destroyGLTexture();
00517 }
00518 
00519 
00520 
00521 LLFontGL &LLFontGL::operator=(const LLFontGL &source)
00522 {
00523         llerrs << "Not implemented" << llendl;
00524         return *this;
00525 }
00526 
00527 BOOL LLFontGL::loadFace(const std::string& filename,
00528                                                 const F32 point_size, const F32 vert_dpi, const F32 horz_dpi,
00529                                                 const S32 components, BOOL is_fallback)
00530 {
00531         if (!LLFont::loadFace(filename, point_size, vert_dpi, horz_dpi, components, is_fallback))
00532         {
00533                 return FALSE;
00534         }
00535         mImageGLp->createGLTexture(0, mRawImageGLp);
00536         mImageGLp->bind();
00537         mImageGLp->setMipFilterNearest(TRUE, TRUE);
00538         return TRUE;
00539 }
00540 
00541 BOOL LLFontGL::addChar(const llwchar wch)
00542 {
00543         if (!LLFont::addChar(wch))
00544         {
00545                 return FALSE;
00546         }
00547 
00548         stop_glerror();
00549         mImageGLp->setSubImage(mRawImageGLp, 0, 0, mImageGLp->getWidth(), mImageGLp->getHeight());
00550         mImageGLp->bind();
00551         mImageGLp->setMipFilterNearest(TRUE, TRUE);
00552         stop_glerror();
00553         return TRUE;
00554 }
00555 
00556 
00557 S32 LLFontGL::renderUTF8(const LLString &text, const S32 offset, 
00558                                          const F32 x, const F32 y,
00559                                          const LLColor4 &color,
00560                                          const HAlign halign, const VAlign valign,
00561                                          U8 style,
00562                                          const S32 max_chars, const S32 max_pixels,
00563                                          F32* right_x,
00564                                          BOOL use_ellipses) const
00565 {
00566         LLWString wstr = utf8str_to_wstring(text);
00567         return render(wstr, offset, x, y, color, halign, valign, style, max_chars, max_pixels, right_x, use_ellipses);
00568 }
00569 
00570 S32 LLFontGL::render(const LLWString &wstr, 
00571                                          const S32 begin_offset,
00572                                          const F32 x, const F32 y,
00573                                          const LLColor4 &color,
00574                                          const HAlign halign, const VAlign valign,
00575                                          U8 style,
00576                                          const S32 max_chars, S32 max_pixels,
00577                                          F32* right_x,
00578                                          BOOL use_embedded,
00579                                          BOOL use_ellipses) const
00580 {
00581         if(!sDisplayFont) //do not display texts
00582         {
00583                 return wstr.length() ;
00584         }
00585 
00586         LLGLEnable tex(GL_TEXTURE_2D);
00587 
00588         if (wstr.empty())
00589         {
00590                 return 0;
00591         } 
00592 
00593         S32 scaled_max_pixels = max_pixels == S32_MAX ? S32_MAX : llceil((F32)max_pixels * sScaleX);
00594 
00595         // HACK for better bolding
00596         if (style & BOLD)
00597         {
00598                 if (this == LLFontGL::sSansSerif)
00599                 {
00600                         return LLFontGL::sSansSerifBold->render(
00601                                 wstr, begin_offset,
00602                                 x, y,
00603                                 color,
00604                                 halign, valign, 
00605                                 (style & ~BOLD),
00606                                 max_chars, max_pixels,
00607                                 right_x, use_embedded);
00608                 }
00609         }
00610 
00611         F32 drop_shadow_strength = 0.f;
00612         if (style & (DROP_SHADOW | DROP_SHADOW_SOFT))
00613         {
00614                 F32 luminance;
00615                 color.calcHSL(NULL, NULL, &luminance);
00616                 drop_shadow_strength = clamp_rescale(luminance, 0.35f, 0.6f, 0.f, 1.f);
00617                 if (luminance < 0.35f)
00618                 {
00619                         style = style & ~(DROP_SHADOW | DROP_SHADOW_SOFT);
00620                 }
00621         }
00622 
00623         gGL.pushMatrix();
00624         glLoadIdentity();
00625         gGL.translatef(floorf(sCurOrigin.mX*sScaleX), floorf(sCurOrigin.mY*sScaleY), sCurOrigin.mZ);
00626         //glScalef(sScaleX, sScaleY, 1.0f);
00627         
00628         // avoid half pixels
00629         // RN: if we're going to this trouble, might as well snap to nearest pixel all the time
00630         // but the plan is to get rid of this so that fonts "just work"
00631         //F32 half_pixel_distance = llabs(fmodf(sCurOrigin.mX * sScaleX, 1.f) - 0.5f);
00632         //if (half_pixel_distance < PIXEL_BORDER_THRESHOLD)
00633         //{
00634                 gGL.translatef(PIXEL_CORRECTION_DISTANCE*sScaleX, 0.f, 0.f);
00635         //}
00636 
00637         // this code would just snap to pixel grid, although it seems to introduce more jitter
00638         //F32 pixel_offset_x = llround(sCurOrigin.mX * sScaleX) - (sCurOrigin.mX * sScaleX);
00639         //F32 pixel_offset_y = llround(sCurOrigin.mY * sScaleY) - (sCurOrigin.mY * sScaleY);
00640         //gGL.translatef(-pixel_offset_x, -pixel_offset_y, 0.f);
00641 
00642         // scale back to native pixel size
00643         //glScalef(1.f / sScaleX, 1.f / sScaleY, 1.f);
00644         //glScaled(1.0 / (F64) sScaleX, 1.0 / (F64) sScaleY, 1.0f);
00645         LLFastTimer t(LLFastTimer::FTM_RENDER_FONTS);
00646 
00647         gGL.color4fv( color.mV );
00648 
00649         S32 chars_drawn = 0;
00650         S32 i;
00651         S32 length;
00652 
00653         if (-1 == max_chars)
00654         {
00655                 length = (S32)wstr.length() - begin_offset;
00656         }
00657         else
00658         {
00659                 length = llmin((S32)wstr.length() - begin_offset, max_chars );
00660         }
00661 
00662         F32 cur_x, cur_y, cur_render_x, cur_render_y;
00663 
00664         // Bind the font texture
00665         
00666         mImageGLp->bind(0);
00667         
00668         gGL.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Not guaranteed to be set correctly
00669         
00670         cur_x = ((F32)x * sScaleX);
00671         cur_y = ((F32)y * sScaleY);
00672 
00673         // Offset y by vertical alignment.
00674         switch (valign)
00675         {
00676         case TOP:
00677                 cur_y -= mAscender;
00678                 break;
00679         case BOTTOM:
00680                 cur_y += mDescender;
00681                 break;
00682         case VCENTER:
00683                 cur_y -= ((mAscender - mDescender)/2.f);
00684                 break;
00685         case BASELINE:
00686                 // Baseline, do nothing.
00687                 break;
00688         default:
00689                 break;
00690         }
00691 
00692         switch (halign)
00693         {
00694         case LEFT:
00695                 break;
00696         case RIGHT:
00697                 cur_x -= llmin(scaled_max_pixels, llround(getWidthF32(wstr.c_str(), 0, length) * sScaleX));
00698                 break;
00699         case HCENTER:
00700             cur_x -= llmin(scaled_max_pixels, llround(getWidthF32(wstr.c_str(), 0, length) * sScaleX)) / 2;
00701                 break;
00702         default:
00703                 break;
00704         }
00705 
00706         // Round properly.
00707         //cur_render_y = (F32)llfloor(cur_y/sScaleY + 0.5f)*sScaleY;
00708         //cur_render_x = (F32)llfloor(cur_x/sScaleX + 0.5f)*sScaleX;
00709         
00710         cur_render_y = cur_y;
00711         cur_render_x = cur_x;
00712 
00713         F32 start_x = cur_x;
00714 
00715         F32 inv_width = 1.f / mImageGLp->getWidth();
00716         F32 inv_height = 1.f / mImageGLp->getHeight();
00717 
00718         const S32 LAST_CHARACTER = LLFont::LAST_CHAR_FULL;
00719 
00720 
00721         BOOL draw_ellipses = FALSE;
00722         if (use_ellipses && halign == LEFT)
00723         {
00724                 // check for too long of a string
00725                 if (getWidthF32(wstr.c_str(), 0, max_chars) * sScaleX > scaled_max_pixels)
00726                 {
00727                         // use four dots for ellipsis width to generate padding
00728                         const LLWString dots(utf8str_to_wstring(LLString("....")));
00729                         scaled_max_pixels = llmax(0, scaled_max_pixels - llround(getWidthF32(dots.c_str())));
00730                         draw_ellipses = TRUE;
00731                 }
00732         }
00733 
00734 
00735         for (i = begin_offset; i < begin_offset + length; i++)
00736         {
00737                 llwchar wch = wstr[i];
00738 
00739                 // Handle embedded characters first, if they're enabled.
00740                 // Embedded characters are a hack for notecards
00741                 const embedded_data_t* ext_data = use_embedded ? getEmbeddedCharData(wch) : NULL;
00742                 if (ext_data)
00743                 {
00744                         LLImageGL* ext_image = ext_data->mImage;
00745                         const LLWString& label = ext_data->mLabel;
00746 
00747                         F32 ext_height = (F32)ext_image->getHeight() * sScaleY;
00748 
00749                         F32 ext_width = (F32)ext_image->getWidth() * sScaleX;
00750                         F32 ext_advance = (EXT_X_BEARING * sScaleX) + ext_width;
00751 
00752                         if (!label.empty())
00753                         {
00754                                 ext_advance += (EXT_X_BEARING + gExtCharFont->getWidthF32( label.c_str() )) * sScaleX;
00755                         }
00756 
00757                         if (start_x + scaled_max_pixels < cur_x + ext_advance)
00758                         {
00759                                 // Not enough room for this character.
00760                                 break;
00761                         }
00762 
00763                         ext_image->bind();
00764                         const F32 ext_x = cur_render_x + (EXT_X_BEARING * sScaleX);
00765                         const F32 ext_y = cur_render_y + (EXT_Y_BEARING * sScaleY + mAscender - mLineHeight);
00766 
00767                         LLRectf uv_rect(0.f, 1.f, 1.f, 0.f);
00768                         LLRectf screen_rect(ext_x, ext_y + ext_height, ext_x + ext_width, ext_y);
00769                         drawGlyph(screen_rect, uv_rect, LLColor4::white, style, drop_shadow_strength);
00770 
00771                         if (!label.empty())
00772                         {
00773                                 gGL.pushMatrix();
00774                                 //glLoadIdentity();
00775                                 //gGL.translatef(sCurOrigin.mX, sCurOrigin.mY, 0.0f);
00776                                 //glScalef(sScaleX, sScaleY, 1.f);
00777                                 gExtCharFont->render(label, 0,
00778                                                                          /*llfloor*/((ext_x + (F32)ext_image->getWidth() + EXT_X_BEARING) / sScaleX), 
00779                                                                          /*llfloor*/(cur_y / sScaleY),
00780                                                                          color,
00781                                                                          halign, BASELINE, NORMAL, S32_MAX, S32_MAX, NULL,
00782                                                                          TRUE );
00783                                 gGL.popMatrix();
00784                         }
00785 
00786                         gGL.color4fv(color.mV);
00787 
00788                         chars_drawn++;
00789                         cur_x += ext_advance;
00790                         if (((i + 1) < length) && wstr[i+1])
00791                         {
00792                                 cur_x += EXT_KERNING * sScaleX;
00793                         }
00794                         cur_render_x = cur_x;
00795 
00796                         // Bind the font texture
00797                         mImageGLp->bind();
00798                 }
00799                 else
00800                 {
00801                         if (!hasGlyph(wch))
00802                         {
00803                                 (const_cast<LLFontGL*>(this))->addChar(wch);
00804                         }
00805 
00806                         const LLFontGlyphInfo* fgi= getGlyphInfo(wch);
00807                         if (!fgi)
00808                         {
00809                                 llerrs << "Missing Glyph Info" << llendl;
00810                                 break;
00811                         }
00812                         if ((start_x + scaled_max_pixels) < (cur_x + fgi->mXBearing + fgi->mWidth))
00813                         {
00814                                 // Not enough room for this character.
00815                                 break;
00816                         }
00817 
00818                         // Draw the text at the appropriate location
00819                         //Specify vertices and texture coordinates
00820                         LLRectf uv_rect((fgi->mXBitmapOffset - PAD_AMT) * inv_width,
00821                                                         (fgi->mYBitmapOffset + fgi->mHeight + PAD_AMT) * inv_height,
00822                                                         (fgi->mXBitmapOffset + fgi->mWidth + PAD_AMT) * inv_width,
00823                                                         (fgi->mYBitmapOffset - PAD_AMT) * inv_height);
00824                         LLRectf screen_rect(cur_render_x + (F32)fgi->mXBearing - PAD_AMT,
00825                                                                 cur_render_y + (F32)fgi->mYBearing + PAD_AMT,
00826                                                                 cur_render_x + (F32)fgi->mXBearing + (F32)fgi->mWidth + PAD_AMT,
00827                                                                 cur_render_y + (F32)fgi->mYBearing - (F32)fgi->mHeight - PAD_AMT);
00828 
00829                         drawGlyph(screen_rect, uv_rect, color, style, drop_shadow_strength);
00830 
00831                         chars_drawn++;
00832                         cur_x += fgi->mXAdvance;
00833                         cur_y += fgi->mYAdvance;
00834 
00835                         llwchar next_char = wstr[i+1];
00836                         if (next_char && (next_char < LAST_CHARACTER))
00837                         {
00838                                 // Kern this puppy.
00839                                 if (!hasGlyph(next_char))
00840                                 {
00841                                         (const_cast<LLFontGL*>(this))->addChar(next_char);
00842                                 }
00843                                 cur_x += getXKerning(wch, next_char);
00844                         }
00845 
00846                         // Round after kerning.
00847                         // Must do this to cur_x, not just to cur_render_x, otherwise you
00848                         // will squish sub-pixel kerned characters too close together.
00849                         // For example, "CCCCC" looks bad.
00850                         cur_x = (F32)llfloor(cur_x + 0.5f);
00851                         //cur_y = (F32)llfloor(cur_y + 0.5f);
00852 
00853                         cur_render_x = cur_x;
00854                         cur_render_y = cur_y;
00855                 }
00856         }
00857 
00858         if (right_x)
00859         {
00860                 *right_x = cur_x / sScaleX;
00861         }
00862 
00863         if (style & UNDERLINE)
00864         {
00865                 LLGLSNoTexture no_texture;
00866                 gGL.begin(LLVertexBuffer::LINES);
00867                 gGL.vertex2f(start_x, cur_y - (mDescender));
00868                 gGL.vertex2f(cur_x, cur_y - (mDescender));
00869                 gGL.end();
00870         }
00871 
00872         // *FIX: get this working in all alignment cases, etc.
00873         if (draw_ellipses)
00874         {
00875                 // recursively render ellipses at end of string
00876                 // we've already reserved enough room
00877                 gGL.pushMatrix();
00878                 //glLoadIdentity();
00879                 //gGL.translatef(sCurOrigin.mX, sCurOrigin.mY, 0.0f);
00880                 //glScalef(sScaleX, sScaleY, 1.f);
00881                 renderUTF8("...", 
00882                                 0,
00883                                 cur_x / sScaleX, (F32)y,
00884                                 color,
00885                                 LEFT, valign,
00886                                 style,
00887                                 S32_MAX, max_pixels,
00888                                 right_x,
00889                                 FALSE); 
00890                 gGL.popMatrix();
00891         }
00892 
00893         gGL.popMatrix();
00894 
00895         return chars_drawn;
00896 }
00897 
00898  
00899 LLImageGL *LLFontGL::getImageGL() const
00900 {
00901         return mImageGLp;
00902 }
00903 
00904 S32 LLFontGL::getWidth(const LLString& utf8text) const
00905 {
00906         LLWString wtext = utf8str_to_wstring(utf8text);
00907         return getWidth(wtext.c_str(), 0, S32_MAX);
00908 }
00909 
00910 S32 LLFontGL::getWidth(const llwchar* wchars) const
00911 {
00912         return getWidth(wchars, 0, S32_MAX);
00913 }
00914 
00915 S32 LLFontGL::getWidth(const LLString& utf8text, const S32 begin_offset, const S32 max_chars) const
00916 {
00917         LLWString wtext = utf8str_to_wstring(utf8text);
00918         return getWidth(wtext.c_str(), begin_offset, max_chars);
00919 }
00920 
00921 S32 LLFontGL::getWidth(const llwchar* wchars, const S32 begin_offset, const S32 max_chars, BOOL use_embedded) const
00922 {
00923         F32 width = getWidthF32(wchars, begin_offset, max_chars, use_embedded);
00924         return llround(width);
00925 }
00926 
00927 F32 LLFontGL::getWidthF32(const LLString& utf8text) const
00928 {
00929         LLWString wtext = utf8str_to_wstring(utf8text);
00930         return getWidthF32(wtext.c_str(), 0, S32_MAX);
00931 }
00932 
00933 F32 LLFontGL::getWidthF32(const llwchar* wchars) const
00934 {
00935         return getWidthF32(wchars, 0, S32_MAX);
00936 }
00937 
00938 F32 LLFontGL::getWidthF32(const LLString& utf8text, const S32 begin_offset, const S32 max_chars ) const
00939 {
00940         LLWString wtext = utf8str_to_wstring(utf8text);
00941         return getWidthF32(wtext.c_str(), begin_offset, max_chars);
00942 }
00943 
00944 F32 LLFontGL::getWidthF32(const llwchar* wchars, const S32 begin_offset, const S32 max_chars, BOOL use_embedded) const
00945 {
00946         const S32 LAST_CHARACTER = LLFont::LAST_CHAR_FULL;
00947 
00948         F32 cur_x = 0;
00949         const S32 max_index = begin_offset + max_chars;
00950         for (S32 i = begin_offset; i < max_index; i++)
00951         {
00952                 const llwchar wch = wchars[i];
00953                 if (wch == 0)
00954                 {
00955                         break; // done
00956                 }
00957                 const embedded_data_t* ext_data = use_embedded ? getEmbeddedCharData(wch) : NULL;
00958                 if (ext_data)
00959                 {
00960                         // Handle crappy embedded hack
00961                         cur_x += getEmbeddedCharAdvance(ext_data);
00962 
00963                         if( ((i+1) < max_chars) && (i+1 < max_index))
00964                         {
00965                                 cur_x += EXT_KERNING * sScaleX;
00966                         }
00967                 }
00968                 else
00969                 {
00970                         cur_x += getXAdvance(wch);
00971                         llwchar next_char = wchars[i+1];
00972 
00973                         if (((i + 1) < max_chars) 
00974                                 && next_char 
00975                                 && (next_char < LAST_CHARACTER))
00976                         {
00977                                 // Kern this puppy.
00978                                 cur_x += getXKerning(wch, next_char);
00979                         }
00980                 }
00981                 // Round after kerning.
00982                 cur_x = (F32)llfloor(cur_x + 0.5f);
00983         }
00984 
00985         return cur_x / sScaleX;
00986 }
00987 
00988 
00989 
00990 // Returns the max number of complete characters from text (up to max_chars) that can be drawn in max_pixels
00991 S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_chars,
00992                                                            BOOL end_on_word_boundary, const BOOL use_embedded,
00993                                                            F32* drawn_pixels) const
00994 {
00995         if (!wchars || !wchars[0] || max_chars == 0)
00996         {
00997                 return 0;
00998         }
00999         
01000         llassert(max_pixels >= 0.f);
01001         llassert(max_chars >= 0);
01002         
01003         BOOL clip = FALSE;
01004         F32 cur_x = 0;
01005         F32 drawn_x = 0;
01006 
01007         S32 start_of_last_word = 0;
01008         BOOL in_word = FALSE;
01009 
01010         F32 scaled_max_pixels = (F32)llceil(max_pixels * sScaleX);
01011 
01012         S32 i;
01013         for (i=0; (i < max_chars); i++)
01014         {
01015                 llwchar wch = wchars[i];
01016 
01017                 if(wch == 0)
01018                 {
01019                         // Null terminator.  We're done.
01020                         break;
01021                 }
01022                         
01023                 const embedded_data_t* ext_data = use_embedded ? getEmbeddedCharData(wch) : NULL;
01024                 if (ext_data)
01025                 {
01026                         if (in_word)
01027                         {
01028                                 in_word = FALSE;
01029                         }
01030                         else
01031                         {
01032                                 start_of_last_word = i;
01033                         }
01034                         cur_x += getEmbeddedCharAdvance(ext_data);
01035                         
01036                         if (scaled_max_pixels < cur_x)
01037                         {
01038                                 clip = TRUE;
01039                                 break;
01040                         }
01041                         
01042                         if (((i+1) < max_chars) && wchars[i+1])
01043                         {
01044                                 cur_x += EXT_KERNING * sScaleX;
01045                         }
01046 
01047                         if( scaled_max_pixels < cur_x )
01048                         {
01049                                 clip = TRUE;
01050                                 break;
01051                         }
01052                 }
01053                 else
01054                 {
01055                         if (in_word)
01056                         {
01057                                 if (iswspace(wch))
01058                                 {
01059                                         in_word = FALSE;
01060                                 }
01061                         }
01062                         else
01063                         {
01064                                 start_of_last_word = i;
01065                                 if (!iswspace(wch))
01066                                 {
01067                                         in_word = TRUE;
01068                                 }
01069                         }
01070 
01071                         cur_x += getXAdvance(wch);
01072                         
01073                         if (scaled_max_pixels < cur_x)
01074                         {
01075                                 clip = TRUE;
01076                                 break;
01077                         }
01078 
01079                         if (((i+1) < max_chars) && wchars[i+1])
01080                         {
01081                                 // Kern this puppy.
01082                                 cur_x += getXKerning(wch, wchars[i+1]);
01083                         }
01084                 }
01085                 // Round after kerning.
01086                 cur_x = (F32)llfloor(cur_x + 0.5f);
01087                 drawn_x = cur_x;
01088         }
01089 
01090         if( clip && end_on_word_boundary && (start_of_last_word != 0) )
01091         {
01092                 i = start_of_last_word;
01093         }
01094         if (drawn_pixels)
01095         {
01096                 *drawn_pixels = drawn_x;
01097         }
01098         return i;
01099 }
01100 
01101 
01102 S32     LLFontGL::firstDrawableChar(const llwchar* wchars, F32 max_pixels, S32 text_len, S32 start_pos, S32 max_chars) const
01103 {
01104         if (!wchars || !wchars[0] || max_chars == 0)
01105         {
01106                 return 0;
01107         }
01108         
01109         F32 total_width = 0.0;
01110         S32 drawable_chars = 0;
01111 
01112         F32 scaled_max_pixels = max_pixels * sScaleX;
01113 
01114         S32 start = llmin(start_pos, text_len - 1);
01115         for (S32 i = start; i >= 0; i--)
01116         {
01117                 llwchar wch = wchars[i];
01118 
01119                 const embedded_data_t* ext_data = getEmbeddedCharData(wch);
01120                 if (ext_data)
01121                 {
01122                         F32 char_width = getEmbeddedCharAdvance(ext_data);
01123 
01124                         if( scaled_max_pixels < (total_width + char_width) )
01125                         {
01126                                 break;
01127                         }
01128 
01129                         total_width += char_width;
01130 
01131                         drawable_chars++;
01132                         if( max_chars >= 0 && drawable_chars >= max_chars )
01133                         {
01134                                 break;
01135                         }
01136 
01137                         if ( i > 0 )
01138                         {
01139                                 total_width += EXT_KERNING * sScaleX;
01140                         }
01141 
01142                         // Round after kerning.
01143                         total_width = (F32)llfloor(total_width + 0.5f);
01144                 }
01145                 else
01146                 {
01147                         F32 char_width = getXAdvance(wch);
01148                         if( scaled_max_pixels < (total_width + char_width) )
01149                         {
01150                                 break;
01151                         }
01152 
01153                         total_width += char_width;
01154 
01155                         drawable_chars++;
01156                         if( max_chars >= 0 && drawable_chars >= max_chars )
01157                         {
01158                                 break;
01159                         }
01160 
01161                         if ( i > 0 )
01162                         {
01163                                 // Kerning
01164                                 total_width += getXKerning(wchars[i-1], wch);
01165                         }
01166 
01167                         // Round after kerning.
01168                         total_width = (F32)llfloor(total_width + 0.5f);
01169                 }
01170         }
01171 
01172         return text_len - drawable_chars;
01173 }
01174 
01175 
01176 S32 LLFontGL::charFromPixelOffset(const llwchar* wchars, const S32 begin_offset, F32 target_x, F32 max_pixels, S32 max_chars, BOOL round, BOOL use_embedded) const
01177 {
01178         if (!wchars || !wchars[0] || max_chars == 0)
01179         {
01180                 return 0;
01181         }
01182         
01183         F32 cur_x = 0;
01184         S32 pos = 0;
01185 
01186         target_x *= sScaleX;
01187 
01188         // max_chars is S32_MAX by default, so make sure we don't get overflow
01189         const S32 max_index = begin_offset + llmin(S32_MAX - begin_offset, max_chars);
01190 
01191         F32 scaled_max_pixels = max_pixels * sScaleX;
01192 
01193         for (S32 i = begin_offset; (i < max_index); i++)
01194         {
01195                 llwchar wch = wchars[i];
01196                 if (!wch)
01197                 {
01198                         break; // done
01199                 }
01200                 const embedded_data_t* ext_data = use_embedded ? getEmbeddedCharData(wch) : NULL;
01201                 if (ext_data)
01202                 {
01203                         F32 ext_advance = getEmbeddedCharAdvance(ext_data);
01204 
01205                         if (round)
01206                         {
01207                                 // Note: if the mouse is on the left half of the character, the pick is to the character's left
01208                                 // If it's on the right half, the pick is to the right.
01209                                 if (target_x  < cur_x + ext_advance/2)
01210                                 {
01211                                         break;
01212                                 }
01213                         }
01214                         else
01215                         {
01216                                 if (target_x  < cur_x + ext_advance)
01217                                 {
01218                                         break;
01219                                 }
01220                         }
01221 
01222                         if (scaled_max_pixels < cur_x + ext_advance)
01223                         {
01224                                 break;
01225                         }
01226 
01227                         pos++;
01228                         cur_x += ext_advance;
01229 
01230                         if (((i + 1) < max_index)
01231                                 && (wchars[(i + 1)]))
01232                         {
01233                                 cur_x += EXT_KERNING * sScaleX;
01234                         }
01235                         // Round after kerning.
01236                         cur_x = (F32)llfloor(cur_x + 0.5f);
01237                 }
01238                 else
01239                 {
01240                         F32 char_width = getXAdvance(wch);
01241 
01242                         if (round)
01243                         {
01244                                 // Note: if the mouse is on the left half of the character, the pick is to the character's left
01245                                 // If it's on the right half, the pick is to the right.
01246                                 if (target_x  < cur_x + char_width*0.5f)
01247                                 {
01248                                         break;
01249                                 }
01250                         }
01251                         else if (target_x  < cur_x + char_width)
01252                         {
01253                                 break;
01254                         }
01255 
01256                         if (scaled_max_pixels < cur_x + char_width)
01257                         {
01258                                 break;
01259                         }
01260 
01261                         pos++;
01262                         cur_x += char_width;
01263 
01264                         if (((i + 1) < max_index)
01265                                 && (wchars[(i + 1)]))
01266                         {
01267                                 llwchar next_char = wchars[i + 1];
01268                                 // Kern this puppy.
01269                                 cur_x += getXKerning(wch, next_char);
01270                         }
01271 
01272                         // Round after kerning.
01273                         cur_x = (F32)llfloor(cur_x + 0.5f);
01274                 }
01275         }
01276 
01277         return pos;
01278 }
01279 
01280 
01281 const LLFontGL::embedded_data_t* LLFontGL::getEmbeddedCharData(const llwchar wch) const
01282 {
01283         // Handle crappy embedded hack
01284         embedded_map_t::const_iterator iter = mEmbeddedChars.find(wch);
01285         if (iter != mEmbeddedChars.end())
01286         {
01287                 return iter->second;
01288         }
01289         return NULL;
01290 }
01291 
01292 
01293 F32 LLFontGL::getEmbeddedCharAdvance(const embedded_data_t* ext_data) const
01294 {
01295         const LLWString& label = ext_data->mLabel;
01296         LLImageGL* ext_image = ext_data->mImage;
01297 
01298         F32 ext_width = (F32)ext_image->getWidth();
01299         if( !label.empty() )
01300         {
01301                 ext_width += (EXT_X_BEARING + gExtCharFont->getWidthF32(label.c_str())) * sScaleX;
01302         }
01303 
01304         return (EXT_X_BEARING * sScaleX) + ext_width;
01305 }
01306 
01307 
01308 void LLFontGL::clearEmbeddedChars()
01309 {
01310         for_each(mEmbeddedChars.begin(), mEmbeddedChars.end(), DeletePairedPointer());
01311         mEmbeddedChars.clear();
01312 }
01313 
01314 void LLFontGL::addEmbeddedChar( llwchar wc, LLImageGL* image, const LLString& label )
01315 {
01316         LLWString wlabel = utf8str_to_wstring(label);
01317         addEmbeddedChar(wc, image, wlabel);
01318 }
01319 
01320 void LLFontGL::addEmbeddedChar( llwchar wc, LLImageGL* image, const LLWString& wlabel )
01321 {
01322         embedded_data_t* ext_data = new embedded_data_t(image, wlabel);
01323         mEmbeddedChars[wc] = ext_data;
01324 }
01325 
01326 void LLFontGL::removeEmbeddedChar( llwchar wc )
01327 {
01328         embedded_map_t::iterator iter = mEmbeddedChars.find(wc);
01329         if (iter != mEmbeddedChars.end())
01330         {
01331                 delete iter->second;
01332                 mEmbeddedChars.erase(wc);
01333         }
01334 }
01335 
01336 
01337 void LLFontGL::renderQuad(const LLRectf& screen_rect, const LLRectf& uv_rect, F32 slant_amt) const
01338 {
01339         gGL.texCoord2f(uv_rect.mRight, uv_rect.mTop);
01340         gGL.vertex2f(llfont_round_x(screen_rect.mRight), 
01341                                 llfont_round_y(screen_rect.mTop));
01342 
01343         gGL.texCoord2f(uv_rect.mLeft, uv_rect.mTop);
01344         gGL.vertex2f(llfont_round_x(screen_rect.mLeft), 
01345                                 llfont_round_y(screen_rect.mTop));
01346 
01347         gGL.texCoord2f(uv_rect.mLeft, uv_rect.mBottom);
01348         gGL.vertex2f(llfont_round_x(screen_rect.mLeft + slant_amt), 
01349                                 llfont_round_y(screen_rect.mBottom));
01350 
01351         gGL.texCoord2f(uv_rect.mRight, uv_rect.mBottom);
01352         gGL.vertex2f(llfont_round_x(screen_rect.mRight + slant_amt), 
01353                                 llfont_round_y(screen_rect.mBottom));
01354 }
01355 
01356 void LLFontGL::drawGlyph(const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4& color, U8 style, F32 drop_shadow_strength) const
01357 {
01358         F32 slant_offset;
01359         slant_offset = ((style & ITALIC) ? ( -mAscender * 0.2f) : 0.f);
01360 
01361         gGL.begin(LLVertexBuffer::QUADS);
01362         {
01363                 //FIXME: bold and drop shadow are mutually exclusive only for convenience
01364                 //Allow both when we need them.
01365                 if (style & BOLD)
01366                 {
01367                         gGL.color4fv(color.mV);
01368                         for (S32 pass = 0; pass < 2; pass++)
01369                         {
01370                                 LLRectf screen_rect_offset = screen_rect;
01371 
01372                                 screen_rect_offset.translate((F32)(pass * BOLD_OFFSET), 0.f);
01373                                 renderQuad(screen_rect_offset, uv_rect, slant_offset);
01374                         }
01375                 }
01376                 else if (style & DROP_SHADOW_SOFT)
01377                 {
01378                         LLColor4 shadow_color = LLFontGL::sShadowColor;
01379                         shadow_color.mV[VALPHA] = color.mV[VALPHA] * drop_shadow_strength * DROP_SHADOW_SOFT_STRENGTH;
01380                         gGL.color4fv(shadow_color.mV);
01381                         for (S32 pass = 0; pass < 5; pass++)
01382                         {
01383                                 LLRectf screen_rect_offset = screen_rect;
01384 
01385                                 switch(pass)
01386                                 {
01387                                 case 0:
01388                                         screen_rect_offset.translate(-1.f, -1.f);
01389                                         break;
01390                                 case 1:
01391                                         screen_rect_offset.translate(1.f, -1.f);
01392                                         break;
01393                                 case 2:
01394                                         screen_rect_offset.translate(1.f, 1.f);
01395                                         break;
01396                                 case 3:
01397                                         screen_rect_offset.translate(-1.f, 1.f);
01398                                         break;
01399                                 case 4:
01400                                         screen_rect_offset.translate(0, -2.f);
01401                                         break;
01402                                 }
01403                         
01404                                 renderQuad(screen_rect_offset, uv_rect, slant_offset);
01405                         }
01406                         gGL.color4fv(color.mV);
01407                         renderQuad(screen_rect, uv_rect, slant_offset);
01408                 }
01409                 else if (style & DROP_SHADOW)
01410                 {
01411                         LLColor4 shadow_color = LLFontGL::sShadowColor;
01412                         shadow_color.mV[VALPHA] = color.mV[VALPHA] * drop_shadow_strength;
01413                         gGL.color4fv(shadow_color.mV);
01414                         LLRectf screen_rect_shadow = screen_rect;
01415                         screen_rect_shadow.translate(1.f, -1.f);
01416                         renderQuad(screen_rect_shadow, uv_rect, slant_offset);
01417                         gGL.color4fv(color.mV);
01418                         renderQuad(screen_rect, uv_rect, slant_offset);
01419                 }
01420                 else // normal rendering
01421                 {
01422                         gGL.color4fv(color.mV);
01423                         renderQuad(screen_rect, uv_rect, slant_offset);
01424                 }
01425 
01426         }
01427         gGL.end();
01428 }
01429 
01430 // static
01431 LLString LLFontGL::nameFromFont(const LLFontGL* fontp)
01432 {
01433         if (fontp == sSansSerifHuge)
01434         {
01435                 return LLString("SansSerifHuge");
01436         }
01437         else if (fontp == sSansSerifSmall)
01438         {
01439                 return LLString("SansSerifSmall");
01440         }
01441         else if (fontp == sSansSerif)
01442         {
01443                 return LLString("SansSerif");
01444         }
01445         else if (fontp == sSansSerifBig)
01446         {
01447                 return LLString("SansSerifBig");
01448         }
01449         else if (fontp == sSansSerifBold)
01450         {
01451                 return LLString("SansSerifBold");
01452         }
01453         else if (fontp == sMonospace)
01454         {
01455                 return LLString("Monospace");
01456         }
01457         else
01458         {
01459                 return LLString();
01460         }
01461 }
01462 
01463 // static
01464 LLFontGL* LLFontGL::fontFromName(const LLString& font_name)
01465 {
01466         LLFontGL* gl_font = NULL;
01467         if (font_name == "SansSerifHuge")
01468         {
01469                 gl_font = LLFontGL::sSansSerifHuge;
01470         }
01471         else if (font_name == "SansSerifSmall")
01472         {
01473                 gl_font = LLFontGL::sSansSerifSmall;
01474         }
01475         else if (font_name == "SansSerif")
01476         {
01477                 gl_font = LLFontGL::sSansSerif;
01478         }
01479         else if (font_name == "SansSerifBig")
01480         {
01481                 gl_font = LLFontGL::sSansSerifBig;
01482         }
01483         else if (font_name == "SansSerifBold")
01484         {
01485                 gl_font = LLFontGL::sSansSerifBold;
01486         }
01487         else if (font_name == "Monospace")
01488         {
01489                 gl_font = LLFontGL::sMonospace;
01490         }
01491         return gl_font;
01492 }
01493 
01494 // static
01495 LLString LLFontGL::nameFromHAlign(LLFontGL::HAlign align)
01496 {
01497         if (align == LEFT)                      return LLString("left");
01498         else if (align == RIGHT)        return LLString("right");
01499         else if (align == HCENTER)      return LLString("center");
01500         else return LLString();
01501 }
01502 
01503 // static
01504 LLFontGL::HAlign LLFontGL::hAlignFromName(const LLString& name)
01505 {
01506         LLFontGL::HAlign gl_hfont_align = LLFontGL::LEFT;
01507         if (name == "left")
01508         {
01509                 gl_hfont_align = LLFontGL::LEFT;
01510         }
01511         else if (name == "right")
01512         {
01513                 gl_hfont_align = LLFontGL::RIGHT;
01514         }
01515         else if (name == "center")
01516         {
01517                 gl_hfont_align = LLFontGL::HCENTER;
01518         }
01519         //else leave left
01520         return gl_hfont_align;
01521 }
01522 
01523 // static
01524 LLString LLFontGL::nameFromVAlign(LLFontGL::VAlign align)
01525 {
01526         if (align == TOP)                       return LLString("top");
01527         else if (align == VCENTER)      return LLString("center");
01528         else if (align == BASELINE)     return LLString("baseline");
01529         else if (align == BOTTOM)       return LLString("bottom");
01530         else return LLString();
01531 }
01532 
01533 // static
01534 LLFontGL::VAlign LLFontGL::vAlignFromName(const LLString& name)
01535 {
01536         LLFontGL::VAlign gl_vfont_align = LLFontGL::BASELINE;
01537         if (name == "top")
01538         {
01539                 gl_vfont_align = LLFontGL::TOP;
01540         }
01541         else if (name == "center")
01542         {
01543                 gl_vfont_align = LLFontGL::VCENTER;
01544         }
01545         else if (name == "baseline")
01546         {
01547                 gl_vfont_align = LLFontGL::BASELINE;
01548         }
01549         else if (name == "bottom")
01550         {
01551                 gl_vfont_align = LLFontGL::BOTTOM;
01552         }
01553         //else leave baseline
01554         return gl_vfont_align;
01555 }

Generated on Fri May 16 08:32:48 2008 for SecondLife by  doxygen 1.5.5