Back to index

libsfml  1.6+dfsg2
String.cpp
Go to the documentation of this file.
00001 
00002 //
00003 // SFML - Simple and Fast Multimedia Library
00004 // Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
00005 //
00006 // This software is provided 'as-is', without any express or implied warranty.
00007 // In no event will the authors be held liable for any damages arising from the use of this software.
00008 //
00009 // Permission is granted to anyone to use this software for any purpose,
00010 // including commercial applications, and to alter it and redistribute it freely,
00011 // subject to the following restrictions:
00012 //
00013 // 1. The origin of this software must not be misrepresented;
00014 //    you must not claim that you wrote the original software.
00015 //    If you use this software in a product, an acknowledgment
00016 //    in the product documentation would be appreciated but is not required.
00017 //
00018 // 2. Altered source versions must be plainly marked as such,
00019 //    and must not be misrepresented as being the original software.
00020 //
00021 // 3. This notice may not be removed or altered from any source distribution.
00022 //
00024 
00026 // Headers
00028 #include <SFML/Graphics/String.hpp>
00029 #include <SFML/Graphics/Image.hpp>
00030 #include <SFML/Graphics/GraphicsContext.hpp>
00031 #include <locale>
00032 
00033 
00034 namespace sf
00035 {
00039 String::String() :
00040 myFont          (&Font::GetDefaultFont()),
00041 mySize          (30.f),
00042 myStyle         (Regular),
00043 myNeedRectUpdate(true)
00044 {
00045 
00046 }
00047 
00048 
00052 String::String(const Unicode::Text& Text, const Font& CharFont, float Size) :
00053 myFont          (&CharFont),
00054 mySize          (Size),
00055 myStyle         (Regular),
00056 myNeedRectUpdate(true)
00057 {
00058     SetText(Text);
00059 }
00060 
00061 
00065 void String::SetText(const Unicode::Text& Text)
00066 {
00067     myNeedRectUpdate = true;
00068     myText = Text;
00069 }
00070 
00071 
00075 void String::SetFont(const Font& CharFont)
00076 {
00077     if (myFont != &CharFont)
00078     {
00079         myNeedRectUpdate = true;
00080         myFont = &CharFont;
00081     }
00082 }
00083 
00084 
00088 void String::SetSize(float Size)
00089 {
00090     if (mySize != Size)
00091     {
00092         myNeedRectUpdate = true;
00093         mySize = Size;
00094     }
00095 }
00096 
00097 
00102 void String::SetStyle(unsigned long TextStyle)
00103 {
00104     if (myStyle != TextStyle)
00105     {
00106         myNeedRectUpdate = true;
00107         myStyle = TextStyle;
00108     }
00109 }
00110 
00111 
00115 const Unicode::Text& String::GetText() const
00116 {
00117     return myText;
00118 }
00119 
00120 
00124 const Font& String::GetFont() const
00125 {
00126     return *myFont;
00127 }
00128 
00129 
00133 float String::GetSize() const
00134 {
00135     return mySize;
00136 }
00137 
00138 
00142 unsigned long String::GetStyle() const
00143 {
00144     return myStyle;
00145 }
00146 
00147 
00153 sf::Vector2f String::GetCharacterPos(std::size_t Index) const
00154 {
00155     // First get the UTF32 representation of the text
00156     const Unicode::UTF32String& Text = myText;
00157 
00158     // Adjust the index if it's out of range
00159     if (Index > Text.length())
00160         Index = Text.length();
00161 
00162     // The final size is based on the text size
00163     float FactorX  = mySize / myFont->GetCharacterSize();
00164     float AdvanceY = mySize;
00165 
00166     // Compute the position
00167     sf::Vector2f Position;
00168     for (std::size_t i = 0; i < Index; ++i)
00169     {
00170         // Get the current character and its corresponding glyph
00171         Uint32       CurChar  = Text[i];
00172         const Glyph& CurGlyph = myFont->GetGlyph(CurChar);
00173         float        AdvanceX = CurGlyph.Advance * FactorX;
00174 
00175         switch (CurChar)
00176         {
00177             // Handle special characters
00178             case L' ' :  Position.x += AdvanceX;                 break;
00179             case L'\t' : Position.x += AdvanceX * 4;             break;
00180             case L'\v' : Position.y += AdvanceY * 4;             break;
00181             case L'\n' : Position.y += AdvanceY; Position.x = 0; break;
00182 
00183             // Regular character : just add its advance value
00184             default : Position.x += AdvanceX; break;
00185         }
00186     }
00187 
00188     return Position;
00189 }
00190 
00191 
00195 FloatRect String::GetRect() const
00196 {
00197     if (myNeedRectUpdate)
00198         const_cast<String*>(this)->RecomputeRect();
00199 
00200     FloatRect Rect;
00201     Rect.Left   = (myBaseRect.Left   - GetCenter().x) * GetScale().x + GetPosition().x;
00202     Rect.Top    = (myBaseRect.Top    - GetCenter().y) * GetScale().y + GetPosition().y;
00203     Rect.Right  = (myBaseRect.Right  - GetCenter().x) * GetScale().x + GetPosition().x;
00204     Rect.Bottom = (myBaseRect.Bottom - GetCenter().y) * GetScale().y + GetPosition().y;
00205 
00206     return Rect;
00207 }
00208 
00209 
00213 void String::Render(RenderTarget&) const
00214 {
00215     // First get the internal UTF-32 string of the text
00216     const Unicode::UTF32String& Text = myText;
00217 
00218     // No text, no rendering :)
00219     if (Text.empty())
00220         return;
00221 
00222     // Set the scaling factor to get the actual size
00223     float CharSize =  static_cast<float>(myFont->GetCharacterSize());
00224     float Factor   = mySize / CharSize;
00225     GLCheck(glScalef(Factor, Factor, 1.f));
00226 
00227     // Bind the font texture
00228     myFont->GetImage().Bind();
00229 
00230     // Initialize the rendering coordinates
00231     float X = 0.f;
00232     float Y = CharSize;
00233 
00234     // Holds the lines to draw later, for underlined style
00235     std::vector<float> UnderlineCoords;
00236     UnderlineCoords.reserve(16);
00237 
00238     // Compute the shearing to apply if we're using the italic style
00239     float ItalicCoeff = (myStyle & Italic) ? 0.208f : 0.f; // 12 degrees
00240 
00241     // Draw one quad for each character
00242     glBegin(GL_QUADS);
00243     for (std::size_t i = 0; i < Text.size(); ++i)
00244     {
00245         // Get the current character and its corresponding glyph
00246         Uint32           CurChar  = Text[i];
00247         const Glyph&     CurGlyph = myFont->GetGlyph(CurChar);
00248         int              Advance  = CurGlyph.Advance;
00249         const IntRect&   Rect     = CurGlyph.Rectangle;
00250         const FloatRect& Coord    = CurGlyph.TexCoords;
00251 
00252         // If we're using the underlined style and there's a new line,
00253         // we keep track of the previous line to draw it later
00254         if ((CurChar == L'\n') && (myStyle & Underlined))
00255         {
00256             UnderlineCoords.push_back(X);
00257             UnderlineCoords.push_back(Y + 2);
00258         }
00259 
00260         // Handle special characters
00261         switch (CurChar)
00262         {
00263             case L' ' :  X += Advance;         continue;
00264             case L'\n' : Y += CharSize; X = 0; continue;
00265             case L'\t' : X += Advance  * 4;    continue;
00266             case L'\v' : Y += CharSize * 4;    continue;
00267         }
00268 
00269         // Draw a textured quad for the current character
00270         glTexCoord2f(Coord.Left,  Coord.Top);    glVertex2f(X + Rect.Left  - ItalicCoeff * Rect.Top,    Y + Rect.Top);
00271         glTexCoord2f(Coord.Left,  Coord.Bottom); glVertex2f(X + Rect.Left  - ItalicCoeff * Rect.Bottom, Y + Rect.Bottom);
00272         glTexCoord2f(Coord.Right, Coord.Bottom); glVertex2f(X + Rect.Right - ItalicCoeff * Rect.Bottom, Y + Rect.Bottom);
00273         glTexCoord2f(Coord.Right, Coord.Top);    glVertex2f(X + Rect.Right - ItalicCoeff * Rect.Top,    Y + Rect.Top);
00274 
00275         // If we're using the bold style, we must render the character 4 more times,
00276         // slightly offseted, to simulate a higher weight
00277         if (myStyle & Bold)
00278         {
00279             static const float OffsetsX[] = {-0.5f, 0.5f, 0.f, 0.f};
00280             static const float OffsetsY[] = {0.f, 0.f, -0.5f, 0.5f};
00281 
00282             for (int j = 0; j < 4; ++j)
00283             {
00284                 glTexCoord2f(Coord.Left,  Coord.Top);    glVertex2f(X + OffsetsX[j] + Rect.Left  - ItalicCoeff * Rect.Top,    Y + OffsetsY[j] + Rect.Top);
00285                 glTexCoord2f(Coord.Left,  Coord.Bottom); glVertex2f(X + OffsetsX[j] + Rect.Left  - ItalicCoeff * Rect.Bottom, Y + OffsetsY[j] + Rect.Bottom);
00286                 glTexCoord2f(Coord.Right, Coord.Bottom); glVertex2f(X + OffsetsX[j] + Rect.Right - ItalicCoeff * Rect.Bottom, Y + OffsetsY[j] + Rect.Bottom);
00287                 glTexCoord2f(Coord.Right, Coord.Top);    glVertex2f(X + OffsetsX[j] + Rect.Right - ItalicCoeff * Rect.Top,    Y + OffsetsY[j] + Rect.Top);
00288             }
00289         }
00290 
00291         // Advance to the next character
00292         X += Advance;
00293     }
00294     glEnd();
00295 
00296     // Draw the underlines if needed
00297     if (myStyle & Underlined)
00298     {
00299         // Compute the line thickness
00300         float Thickness = (myStyle & Bold) ? 3.f : 2.f;
00301 
00302         // Add the last line (which was not finished with a \n)
00303         UnderlineCoords.push_back(X);
00304         UnderlineCoords.push_back(Y + 2);
00305 
00306         // Draw the underlines as quads
00307         GLCheck(glDisable(GL_TEXTURE_2D));
00308         glBegin(GL_QUADS);
00309         for (std::size_t i = 0; i < UnderlineCoords.size(); i += 2)
00310         {
00311             glVertex2f(0,                  UnderlineCoords[i + 1]);
00312             glVertex2f(0,                  UnderlineCoords[i + 1] + Thickness);
00313             glVertex2f(UnderlineCoords[i], UnderlineCoords[i + 1] + Thickness);
00314             glVertex2f(UnderlineCoords[i], UnderlineCoords[i + 1]);
00315         }
00316         glEnd();
00317     }
00318 }
00319 
00320 
00324 void String::RecomputeRect()
00325 {
00326     // First get the internal UTF-32 string of the text
00327     const Unicode::UTF32String& Text = myText;
00328 
00329     // Reset the "need update" state
00330     myNeedRectUpdate = false;
00331 
00332     // No text, empty box :)
00333     if (Text.empty())
00334     {
00335         myBaseRect = FloatRect(0, 0, 0, 0);
00336         return;
00337     }
00338 
00339     // Initial values
00340     float CurWidth  = 0;
00341     float CurHeight = 0;
00342     float Width     = 0;
00343     float Height    = 0;
00344     float Factor    = mySize / myFont->GetCharacterSize();
00345 
00346     // Go through each character
00347     for (std::size_t i = 0; i < Text.size(); ++i)
00348     {
00349         // Get the current character and its corresponding glyph
00350         Uint32         CurChar  = Text[i];
00351         const Glyph&   CurGlyph = myFont->GetGlyph(CurChar);
00352         float          Advance  = CurGlyph.Advance * Factor;
00353         const IntRect& Rect     = CurGlyph.Rectangle;
00354 
00355         // Handle special characters
00356         switch (CurChar)
00357         {
00358             case L' ' :  CurWidth += Advance;                    continue;
00359             case L'\t' : CurWidth += Advance * 4;                continue;
00360             case L'\v' : Height   += mySize  * 4; CurHeight = 0; continue;
00361 
00362             case L'\n' :
00363                 Height += mySize;
00364                 CurHeight = 0;
00365                 if (CurWidth > Width)
00366                     Width = CurWidth;
00367                 CurWidth = 0;
00368                 continue;
00369         }
00370 
00371         // Advance to the next character
00372         CurWidth += Advance;
00373 
00374         // Update the maximum height
00375         float CharHeight = (myFont->GetCharacterSize() + Rect.Bottom) * Factor;
00376         if (CharHeight > CurHeight)
00377             CurHeight = CharHeight;
00378     }
00379 
00380     // Update the last line
00381     if (CurWidth > Width)
00382         Width = CurWidth;
00383     Height += CurHeight;
00384 
00385     // Add a slight width / height if we're using the bold style
00386     if (myStyle & Bold)
00387     {
00388         Width  += 1 * Factor;
00389         Height += 1 * Factor;
00390     }
00391 
00392     // Add a slight width if we're using the italic style
00393     if (myStyle & Italic)
00394     {
00395         Width += 0.208f * mySize;
00396     }
00397 
00398     // Add a slight height if we're using the underlined style
00399     if (myStyle & Underlined)
00400     {
00401         if (CurHeight < mySize + 4 * Factor)
00402             Height += 4 * Factor;
00403     }
00404 
00405     // Finally update the rectangle
00406     myBaseRect.Left   = 0;
00407     myBaseRect.Top    = 0;
00408     myBaseRect.Right  = Width;
00409     myBaseRect.Bottom = Height;
00410 }
00411 
00412 } // namespace sf