String.cpp
00001 00002 // 00003 // SFML - Simple and Fast Multimedia Library 00004 // Copyright (C) 2007-2009 Laurent Gomila ([email protected]) 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
:: Copyright © 2007-2008 Laurent Gomila, all rights reserved :: Documentation generated by doxygen 1.5.2 ::