Bläddra i källkod

Adding scaling and right-to-left support to Font::drawText().

Adam Blake 14 år sedan
förälder
incheckning
f2709e25d4
2 ändrade filer med 79 tillägg och 67 borttagningar
  1. 65 59
      gameplay/src/Font.cpp
  2. 14 8
      gameplay/src/Font.h

+ 65 - 59
gameplay/src/Font.cpp

@@ -173,9 +173,16 @@ void Font::begin()
     _batch->begin();
 }
 
-void Font::drawText(const char* text, int x, int y, const Vector4& color)
+void Font::drawText(const char* text, int x, int y, const Vector4& color, float scale, bool rightToLeft)
 {
+    if (rightToLeft)
+    {
+        char* textCursor = const_cast<char*>(text);
+        reverseLines(textCursor);
+    }
+
     const int length = strlen(text);
+    const int size = (int)_size * scale;
     int xPos = x, yPos = y;
     for (int i = 0; i < length; ++i)
     {
@@ -185,34 +192,35 @@ void Font::drawText(const char* text, int x, int y, const Vector4& color)
         switch (c)
         {
         case ' ':
-            xPos += _size>>1;
+            xPos += size>>1;
             break;
         case '\r':
         case '\n':
-            yPos += _size;
+            yPos += size;
             xPos = x;
             break;
         case '\t':
-            xPos += (_size>>1)+4;
+            xPos += (size>>1)*4;
             break;
         default:
             unsigned int index = c - 32; // HACK for ASCII
             if (index >= 0 && index < _glyphCount)
             {
                 Glyph& g = _glyphs[index];
-                _batch->draw(xPos, yPos, g.width, _size, g.uvs[0], g.uvs[1], g.uvs[2], g.uvs[3], color);
-                xPos += g.width + (_size>>3);
+                _batch->draw(xPos, yPos, g.width * scale, size, g.uvs[0], g.uvs[1], g.uvs[2], g.uvs[3], color);
+                xPos += g.width * scale + (size>>3);
                 break;
             }
         }
     }
 }
 
-void Font::drawText(const char* text, const Rectangle& area, const Vector4& color, Justify justify, bool wrap)
+void Font::drawText(const char* text, const Rectangle& area, const Vector4& color, float scale, Justify justify, bool wrap, bool rightToLeft)
 {
+    char* token = const_cast<char*>(text);
     const int length = strlen(text);
+    const int fontSize = (int)(_size * scale);
     int yPos = area.y;
-    int fontSize = (int)_size;
 
     Justify vAlign = static_cast<Justify>(justify & 0xF0);
     if (vAlign == 0)
@@ -226,16 +234,20 @@ void Font::drawText(const char* text, const Rectangle& area, const Vector4& colo
         hAlign = ALIGN_LEFT;
     }
 
+    if (rightToLeft)
+    {
+        reverseLines(token);
+    }
+
     // For alignments other than top-left, need to calculate the y position to begin drawing from
     // and the starting x position of each line.
     std::vector<int> xPositions;
     if (vAlign != ALIGN_TOP || hAlign != ALIGN_LEFT)
     {
+        token = const_cast<char*>(text);
         int lineWidth = 0;
         int delimWidth = 0;
-        char* token;
 
-        token = const_cast<char*>(text);
         if (wrap)
         {
             // Go a word at a time.
@@ -250,7 +262,6 @@ void Font::drawText(const char* text, const Rectangle& area, const Vector4& colo
                        delimiter == '\t' ||
                        delimiter == '\r' ||
                        delimiter == '\n' ||
-                       //delimiter == '-' ||
                        delimiter == 0)
                 {
                     switch (delimiter)
@@ -279,19 +290,11 @@ void Font::drawText(const char* text, const Rectangle& area, const Vector4& colo
                             delimWidth = 0;
                             break;
                         case '\t':
-                            delimWidth += (fontSize>>1)+4;
+                            delimWidth += (fontSize>>1)*4;
                             break;
                         case 0:
                             reachedEOF = true;
                             break;
-                            /*
-                        case '-':
-                            unsigned int glyphIndex = delimiter - 32;
-                            Glyph& g = _glyphs[glyphIndex];
-                            tokenWidth += g.width + (_size>>3);
-                            //lineWidth += g.width + (_size>>3);
-                            //delimWidth += g.width + (_size>>3);
-                            break;*/
                     }
 
                     if (reachedEOF)
@@ -309,7 +312,7 @@ void Font::drawText(const char* text, const Rectangle& area, const Vector4& colo
                 }
 
                 unsigned int tokenLength = strcspn(token, " \r\n\t");
-                tokenWidth += getTokenWidth(token, tokenLength);
+                tokenWidth += getTokenWidth(token, tokenLength, scale);
 
                 // Wrap if necessary.
                 if (lineWidth + tokenWidth + delimWidth > area.width)
@@ -384,7 +387,7 @@ void Font::drawText(const char* text, const Rectangle& area, const Vector4& colo
                     tokenLength = strlen(token);
                 }
 
-                int lineWidth = getTokenWidth(token, tokenLength);
+                int lineWidth = getTokenWidth(token, tokenLength, scale);
                 int whitespace = area.width - lineWidth;
                 if (hAlign == ALIGN_HCENTER)
                 {
@@ -424,7 +427,7 @@ void Font::drawText(const char* text, const Rectangle& area, const Vector4& colo
         xPos = *xPositionsIt++;
     }
 
-    char* token = const_cast<char*>(text);
+    token = const_cast<char*>(text);
     while (token[0] != 0)
     {
         // Handle delimiters until next token.
@@ -435,7 +438,6 @@ void Font::drawText(const char* text, const Rectangle& area, const Vector4& colo
                delimiter == '\t' ||
                delimiter == '\r' ||
                delimiter == '\n' ||
-               //delimiter == '-' ||
                delimiter == 0)
         {
             switch (delimiter)
@@ -462,21 +464,11 @@ void Font::drawText(const char* text, const Rectangle& area, const Vector4& colo
                     }
                     break;
                 case '\t':
-                    xPos += (fontSize>>1)+4;
+                    xPos += (fontSize>>1)*4;
                     break;
                 case 0:
                     reachedEOF = true;
                     break;
-                /*case '-':
-                    // Dash is special -- a delimiter that isn't whitespace.
-                    unsigned int glyphIndex = delimiter - 32;
-                    Glyph& g = _glyphs[glyphIndex];
-                    _batch->draw(xPos, yPos, g.width, _size, g.uvs[0], g.uvs[1], g.uvs[2], g.uvs[3], color);
-                    xPos += g.width + (_size>>3);
-
-                    // Get next xPos again (in case of a substring such as "\n-\n").
-                    nextLine = true;
-                    break;*/
             }
 
             if (reachedEOF)
@@ -496,7 +488,7 @@ void Font::drawText(const char* text, const Rectangle& area, const Vector4& colo
         unsigned int tokenLength = strcspn(token, " \r\n\t");
         delimiter = token[tokenLength];
         bool truncated = false;
-        unsigned int tokenWidth = getTokenWidth(token, tokenLength);
+        unsigned int tokenWidth = getTokenWidth(token, tokenLength, scale);
 
         // Wrap if necessary.
         if (wrap &&
@@ -535,7 +527,7 @@ void Font::drawText(const char* text, const Rectangle& area, const Vector4& colo
             {
                 Glyph& g = _glyphs[glyphIndex];
 
-                if (xPos + (int)g.width >= area.x + area.width)
+                if (xPos + (int)(g.width*scale) >= area.x + area.width)
                 {
                     // Truncate this line and go on to the next one.
                     truncated = true;
@@ -546,10 +538,10 @@ void Font::drawText(const char* text, const Rectangle& area, const Vector4& colo
                     // Draw this character.
                     if (draw)
                     {
-                        _batch->draw(xPos, yPos, g.width, _size, g.uvs[0], g.uvs[1], g.uvs[2], g.uvs[3], color);
+                        _batch->draw(xPos, yPos, g.width * scale, fontSize, g.uvs[0], g.uvs[1], g.uvs[2], g.uvs[3], color);
                     }
                 }
-                xPos += g.width + (fontSize>>3);
+                xPos += g.width*scale + (fontSize>>3);
             }
         }
 
@@ -577,10 +569,11 @@ void Font::end()
     _batch->end();
 }
 
-void Font::measureText(const char* text, unsigned int* width, unsigned int* height)
+void Font::measureText(const char* text, unsigned int* width, unsigned int* height, float scale)
 {
     const int length = strlen(text);
     char* token = const_cast<char*>(text);
+    unsigned int fontSize = _size * scale;
 
     *width = 0;
     *height = 0;
@@ -590,12 +583,12 @@ void Font::measureText(const char* text, unsigned int* width, unsigned int* heig
     {
         while (token[0] == '\n')
         {
-            *height += _size;
+            *height += fontSize;
             ++token;
         }
 
         unsigned int tokenLength = strcspn(token, "\n");
-        unsigned int tokenWidth = getTokenWidth(token, tokenLength);
+        unsigned int tokenWidth = getTokenWidth(token, tokenLength, scale);
         if (tokenWidth > *width)
         {
             *width = tokenWidth;
@@ -605,7 +598,7 @@ void Font::measureText(const char* text, unsigned int* width, unsigned int* heig
     }
 }
 
-void Font::measureText(const char* text, const Rectangle& viewport, Justify justify, bool wrap, bool clipped, Rectangle* out)
+void Font::measureText(const char* text, Rectangle* out, const Rectangle& viewport, float scale, Justify justify, bool wrap, bool clipped)
 {
     Justify vAlign = static_cast<Justify>(justify & 0xF0);
     if (vAlign == 0)
@@ -619,7 +612,7 @@ void Font::measureText(const char* text, const Rectangle& viewport, Justify just
         hAlign = ALIGN_LEFT;
     }
 
-    int fontSize = (int)_size;
+    int fontSize = (int)(_size * scale);
     char* token = const_cast<char*>(text);
     std::vector<bool> emptyLines;
     std::vector<Vector2> lines;
@@ -639,7 +632,6 @@ void Font::measureText(const char* text, const Rectangle& viewport, Justify just
                     delimiter == '\t' ||
                     delimiter == '\r' ||
                     delimiter == '\n' ||
-                    //delimiter == '-' ||
                     delimiter == 0)
             {
                 switch (delimiter)
@@ -681,18 +673,11 @@ void Font::measureText(const char* text, const Rectangle& viewport, Justify just
                         delimWidth = 0;
                         break;
                     case '\t':
-                        delimWidth += (fontSize>>1)+4;
+                        delimWidth += (fontSize>>1)*4;
                         break;
                     case 0:
                         reachedEOF = true;
                         break;
-                        /*
-                    case '-':
-                        unsigned int glyphIndex = delimiter - 32;
-                        Glyph& g = _glyphs[glyphIndex];
-                        lineWidth += g.width + (fontSize>>3);
-                        break;
-                        */
                 }
 
                 if (reachedEOF)
@@ -711,7 +696,7 @@ void Font::measureText(const char* text, const Rectangle& viewport, Justify just
 
             // Measure the next token.
             unsigned int tokenLength = strcspn(token, " \r\n\t");
-            unsigned int tokenWidth = getTokenWidth(token, tokenLength);
+            unsigned int tokenWidth = getTokenWidth(token, tokenLength, scale);
 
             // Wrap if necessary.
             if (lineWidth + tokenWidth + delimWidth > viewport.width)
@@ -777,7 +762,7 @@ void Font::measureText(const char* text, const Rectangle& viewport, Justify just
 
             // Measure the next line.
             unsigned int tokenLength = strcspn(token, "\n");
-            lineWidth = getTokenWidth(token, tokenLength);
+            lineWidth = getTokenWidth(token, tokenLength, scale);
             
             // Determine horizontal position and width.
             int xPos = viewport.x;
@@ -933,27 +918,28 @@ void Font::measureText(const char* text, const Rectangle& viewport, Justify just
     }
 }
 
-unsigned int Font::getTokenWidth(const char* token, unsigned int length)
+unsigned int Font::getTokenWidth(const char* token, unsigned int length, float scale)
 {
     // Calculate width of word or line.
     unsigned int tokenWidth = 0;
+    const int size = (int)(_size * scale);
     for (unsigned int i = 0; i < length; ++i)
     {
         char c = token[i];
         switch (c)
         {
         case ' ':
-            tokenWidth += _size>>1;
+            tokenWidth += size>>1;
             break;
         case '\t':
-            tokenWidth += (_size>>1)+4;
+            tokenWidth += (size>>1)*4;
             break;
         default:
             unsigned int glyphIndex = c - 32;
             if (glyphIndex >= 0 && glyphIndex < _glyphCount)
             {
                 Glyph& g = _glyphs[glyphIndex];
-                tokenWidth += g.width + (_size>>3);
+                tokenWidth += g.width * scale + (size>>3);
             }
             break;
         }
@@ -962,4 +948,24 @@ unsigned int Font::getTokenWidth(const char* token, unsigned int length)
     return tokenWidth;
 }
 
+void Font::reverseLines(char* text)
+{
+    // Naive approach: reverse each line, then render left-to-right as usual.
+    while (text[0] != 0)
+    {
+        while (text[0] == '\n')
+        {
+            ++text;
+        }
+
+        unsigned int textLength = strcspn(text, "\n");
+
+        std::string line = std::string(text, textLength);
+        std::string reversedLine = std::string(line.rbegin(), line.rend());
+        memcpy(text, reversedLine.c_str(), textLength);
+
+        text += textLength;
+    }
+}
+
 }

+ 14 - 8
gameplay/src/Font.h

@@ -119,26 +119,29 @@ public:
     void begin();
 
     /**
-     * Draws the specified text.
+     * Draws the specified text in a solid color, with a scaling factor.
      *
      * @param text The text to draw.
      * @param x The viewport x position to draw text at.
      * @param y The viewport y position to draw text at.
      * @param color The color of text.
+     * @param scale The scaling factor.
      */
-    void drawText(const char* text, int x, int y, const Vector4& color);
+    void drawText(const char* text, int x, int y, const Vector4& color, float scale = 1.0f, bool rightToLeft = false);
 
     /**
-     * Draws the specified text within a rectangular area, with a specified alignment.
+     * Draws the specified text within a rectangular area, with a specified alignment and scale.
      * Clips text outside the viewport.  Optionally wraps text to fit within the width of the viewport.
      *
      * @param text The text to draw.
      * @param viewport The viewport area to draw within.  Text starts from the top-left of this rectangle.
      * @param color The color of text.
+     * @param scale The text's scaling factor.
      * @param justify Justification of text within the viewport.
      * @param wrap Wraps text to fit within the width of the viewport if true.
      */
-    void drawText(const char* text, const Rectangle& viewport, const Vector4& color, Justify justify = ALIGN_TOP_LEFT, bool wrap = true);
+    void drawText(const char* text, const Rectangle& viewport, const Vector4& color, float scale = 1.0f,
+                  Justify justify = ALIGN_TOP_LEFT, bool wrap = true, bool rightToLeft = false);
 
     /**
      * Ends text drawing for this font.
@@ -152,20 +155,22 @@ public:
      * @param width Destination for the text's width.
      * @param height Destination for the text's height.
      */
-    void measureText(const char* text, unsigned int* width, unsigned int* height);
+    void measureText(const char* text, unsigned int* width, unsigned int* height, float scale = 1.0f);
 
     /**
      * Measures a string's bounding box after alignment, wrapping and clipping within a viewport.
      *
      * @param text The text to measure.
+     * @param out Destination rectangle to store the bounds in.
      * @param viewport The viewport area to align, wrap and clip text within while measuring.
+     * @param scale The scaling factor to apply.
      * @param justify Justification of text within the viewport.
      * @param wrap Whether to measure text with wrapping applied.
      * @param clipped Whether to clip 'out' to the viewport.  Set true for the bounds of what would actually be drawn
      *                within the given viewport; false for bounds that are guaranteed to fit the entire string of text.
-     * @param out Destination rectangle to store the bounds in.
      */
-    void measureText(const char* text, const Rectangle& viewport, Justify justify, bool wrap, bool clipped, Rectangle* out);
+    void measureText(const char* text, Rectangle* out, const Rectangle& viewport,
+                     float scale = 1.0f, Justify justify = ALIGN_TOP_LEFT, bool wrap = true, bool clipped = true);
 
 
 private:
@@ -186,7 +191,8 @@ private:
     ~Font();
 
     // Utilities
-    unsigned int getTokenWidth(const char* token, unsigned int length);
+    unsigned int getTokenWidth(const char* token, unsigned int length, float scale);
+    void reverseLines(char* text);
 
     std::string _path;
     std::string _id;