Exemplo n.º 1
0
    public void RecreateQuadBatch()
    {
        if (font == null)
        {
            return;
        }

        //
        // first, cut into lines
        //

        // the line list is a list of pair <first char index, line text>
        lineList.Clear();
        {
            int lineStartIndex = 0;
            int lineBreakIndex = 0;
            int length         = text.Length;
            while (lineBreakIndex < length)
            {
                char c          = text[lineBreakIndex];
                bool antiSlashN = (c == '\n');
                bool antiSlashR = (c == '\r');
                if (antiSlashN || antiSlashR)
                {
                    lineList.Add(new LineDescriptor(lineStartIndex, (lineBreakIndex - lineStartIndex), false));

                    if (antiSlashR &&                                                           // if \r is found
                        (lineBreakIndex < length - 1) &&
                        (text[lineBreakIndex + 1] == '\n'))                                     // skip possible \n following it
                    {
                        lineBreakIndex++;
                    }

                    lineStartIndex = lineBreakIndex + 1;                     // start index of next line
                }
                lineBreakIndex++;
            }
            lineList.Add(new LineDescriptor(lineStartIndex, (text.Length - lineStartIndex), false));

//          int startIndex = 0;
//          int lineBreakIndex = -1;
//          while ( ( lineBreakIndex = text.IndexOf ( '\n', startIndex ) ) != -1 )
//          {
//              lineList.Add ( new LineDescriptor ( startIndex, lineBreakIndex - startIndex, false ) );
//              startIndex = lineBreakIndex + 1; // start index of next line
//          }
//          lineList.Add ( new LineDescriptor ( startIndex, text.Length - startIndex, false ) );
        }

#if UNITY_EDITOR
        errorMessage = null;
#endif

        //
        // new create lines geometry
        //

        quadBatch.setSize(text.Length);

        int     lineIndex      = 0;
        Vector3 linePosition   = new Vector3(position.x, position.y, position.z);
        int     quadStartIndex = 0;
        while (lineIndex < lineList.Count)
        {
            // TODO : optim : "lineList.get( lineIndex )" as local ?
            int  startIndex        = lineList[lineIndex].charStartIndexInText;
            int  length            = lineList[lineIndex].charCount;
            bool issuedFromLineCut = lineList[lineIndex].issuedFromLineCut;

            CreateTextGeometryResult result = createTextGeometry(linePosition, text, startIndex, length, quadStartIndex, issuedFromLineCut, scale, lineMaxWidth, preserveWords);

            if ((result.processedCharCount > 0) && (result.processedCharCount != length))                   // line not fully processed ? (see line break near end of
            // createTextGeometry method)
            {
                // insert remaining of the line
                lineList.Insert(lineIndex + 1, new LineDescriptor(startIndex + result.processedCharCount, length - result.processedCharCount, true));
            }

            // updates line description
            lineList[lineIndex] = new LineDescriptor(startIndex + result.spaceRemovedAtBeginning, result.processedCharCount - result.spaceRemovedAtBeginning, quadStartIndex, result.renderedCharCount, issuedFromLineCut);

            quadStartIndex += result.renderedCharCount;             // moves into the quad buffer

            if (fontData != null)
            {
                if (letterSpacingMode == LetterSpacingMode.Add)
                {
                    linePosition.y -= ((fontData.LineHeight + letterSpacing.y) * scale);
                }
                else
                {
                    linePosition.y -= (letterSpacing.y * scale);
                }
            }
            // TODO : might be an option instead of lineHeight : result.boundingRectMax.Y

            // result.boundingRectMin.Y;
            lineIndex++;
        }

#if UNITY_EDITOR
        if (errorMessage != null)
        {
            Debug.LogError("Invalid char found in text to render :\n" + errorMessage);
        }
#endif

        quadBatch.setSize(quadStartIndex);

        //
        // align each line's geometry
        //

        bounds = new Rect(0, 0, -1, -1);

        if (lineList.Count > 1)
        {
            float lineWidth = lineMaxWidth;

            if (
                (lineMaxWidth == float.MaxValue) ||
                (alignment == TextAlignment.Center)                     // we also want real width when centering
                )
            {
                bounds    = quadBatch.getBounds();
                lineWidth = bounds.width;
            }

            switch (alignment)
            {
            case TextAlignment.Left:
                // default alignment
                break;

            case TextAlignment.Center:
                for (int i = 0; i < lineList.Count; i++)
                {
                    LineDescriptor lineDesc     = lineList[i];
                    Rect           boundingRect = quadBatch.getBounds(lineDesc.quadStartIndexInBatch, lineDesc.quadCount);
                    quadBatch.translate(lineDesc.quadStartIndexInBatch, lineDesc.quadCount, new Vector3((lineWidth - boundingRect.width) / 2, 0, 0));
                }
                break;

            case TextAlignment.Right:
                for (int i = 0; i < lineList.Count; i++)
                {
                    LineDescriptor lineDesc     = lineList[i];
                    Rect           boundingRect = quadBatch.getBounds(lineDesc.quadStartIndexInBatch, lineDesc.quadCount);
                    quadBatch.translate(lineDesc.quadStartIndexInBatch, lineDesc.quadCount, new Vector3(lineWidth - boundingRect.width, 0, 0));
                }
                break;

            case TextAlignment.Justify:
                for (int i = 0; i < lineList.Count; i++)
                {
                    LineDescriptor lineDesc = lineList[i];

                    // line is cut if next line is issued from the cut
                    bool lineWasCut = (i < lineList.Count - 1) && (lineList[i + 1].issuedFromLineCut);

                    // TODO : add right/centered aligned justify as Photoshop do ?
                    if (lineWasCut)                               // only align line that are cut, others are already left aligned
                    {
                        // get space count in that line
                        List <int> charCountsToProcess = new List <int> ();
                        int        noSpaceCharCount    = 0;
                        for (int j = 0; j < lineDesc.charCount; j++)
                        {
                            char charToRender = text[lineDesc.charStartIndexInText + j];
                            if (charToRender == 0xA0)
                            {
                                charToRender = (char)0x20;                                         // convert unbreakable space into space
                            }
                            if (charToRender == 0x20)
                            {
                                charCountsToProcess.Add(noSpaceCharCount);
                                noSpaceCharCount = 0;
                            }
                            else
                            {
                                noSpaceCharCount++;
                            }
                        }
                        charCountsToProcess.Add(noSpaceCharCount);
                        if (charCountsToProcess.Count > 1)
                        {
                            Rect  boundingRect = quadBatch.getBounds(lineDesc.quadStartIndexInBatch, lineDesc.quadCount);
                            float spaceToAdd   = (lineWidth - boundingRect.width) / (charCountsToProcess.Count - 1);

                            if (spaceToAdd > 0)
                            {
                                // distribute translation to each spacing
                                int quadIndex = lineDesc.quadStartIndexInBatch;
                                int quadCount = 0;
                                for (int j = 0; j < charCountsToProcess.Count; j++)
                                {
                                    quadCount = charCountsToProcess[j];
                                    if (quadCount > 0)
                                    {
                                        // don't process first word, that stay left aligned
                                        if (j > 0)
                                        {
                                            // quadBatch.colorize ( quadIndex, 1, Color.RED ); // DEBUG : colorize first letter in red
                                            quadBatch.translate(quadIndex, quadCount, new Vector3(spaceToAdd * j, 0, 0));
                                        }
                                        quadIndex += charCountsToProcess[j];
                                    }

                                    quadIndex++;                                             // skip space char, that have not to be processed
                                }
                            }
                        }
                    }
                }
                break;
            }
        }

        if (bounds.width == -1 || bounds.height == -1)           // might have been already computed above, don't do it twice
        {
            bounds = quadBatch.getBounds();
        }

//      if ( trimTopLeftSpace ) // remove empty top left space created by glyph xoffset/yoffset
//      {
//          position.x = quadBounds.x;
//          position.y = quadBounds.y;
//          bounds.x = quadBounds.x;
//          bounds.y = quadBounds.y;
//      }

        float dx = 0;
        switch (anchor)
        {
        case TextAnchor.UpperLeft:
        case TextAnchor.MiddleLeft:
        case TextAnchor.LowerLeft:
            // dx = - bounds.width / 2;
            dx = -bounds.xMin;
            break;

        case TextAnchor.UpperCenter:
        case TextAnchor.MiddleCenter:
        case TextAnchor.LowerCenter:
            // dx = - bounds.width / 2;
            dx = -bounds.center.x;
            break;

        case TextAnchor.UpperRight:
        case TextAnchor.MiddleRight:
        case TextAnchor.LowerRight:
            // dx = - bounds.width;
            dx = -bounds.xMax;
            break;
        }

        // float dy = -( bounds.y + bounds.height );
        float dy = 0;
        switch (anchor)
        {
        case TextAnchor.UpperCenter:
        case TextAnchor.UpperLeft:
        case TextAnchor.UpperRight:
            // dy += bounds.height / 2;
            dy = -bounds.yMax;
            break;

        case TextAnchor.MiddleCenter:
        case TextAnchor.MiddleLeft:
        case TextAnchor.MiddleRight:
            // dy += bounds.height / 2;
            dy = -bounds.center.y;
            break;

        case TextAnchor.LowerCenter:
        case TextAnchor.LowerLeft:
        case TextAnchor.LowerRight:
            // dy += bounds.height;
            dy = -bounds.yMin;
            break;
        }

        quadBatch.translate(new Vector3(dx, dy, 0));
    }
Exemplo n.º 2
0
    private CreateTextGeometryResult createTextGeometry(Vector3 position, string text, int startIndex, int length, int quadStartIndex, bool lineIsIssuedFromLineCut, float scaleFactor, float lineMaxWidth, bool preserveWords)
    {
        CreateTextGeometryResult result = new CreateTextGeometryResult();

        if (lineIsIssuedFromLineCut)
        {
            // trim spaces at start
            while ((startIndex < startIndex + length) && ((text[startIndex] == 0x20) || (text[startIndex] == 0xA0)))
            {
                startIndex++;
                length--;
                result.processedCharCount++;
                result.spaceRemovedAtBeginning++;
            }
        }

        //      float pageWidth = font.getRegion ().getRegionWidth ();
        //      float pageHeight = font.getRegion ().getRegionHeight ();
        //      Glyph glyph = null;
        CharacterInfo glyph;
        // Font.fontChar letterStruct = null;
        Vector3 letterPosition      = new Vector3();
        Vector2 letterDimension     = new Vector2();
        Vector2 letterTopLeftUV     = new Vector2();
        Vector2 letterTopRightUV    = new Vector2();
        Vector2 letterBottomLeftUV  = new Vector2();
        Vector2 letterBottomRightUV = new Vector2();
        float   advance             = 0;
        int     lastSpaceIndex      = startIndex;

        for (int i = startIndex; i < startIndex + length; i++)
        {
            char charToRender = text[i];
            if (charToRender == 0xA0)
            {
                charToRender = (char)0x20;                 // convert unbreakable space into space
            }
            if (!font.GetCharacterInfo(charToRender, out glyph))
            {
#if UNITY_EDITOR
                if (charToRender != 0x0D)
                {
                    if (errorMessage == null)
                    {
                        errorMessage = "";
                    }

                    errorMessage += "Font character unknown : '" + charToRender + "' (0x" + ((int)charToRender).ToString("X2") + "), used in text \"" + text + "\"" + "\n";
                    // Debug.LogWarning ( "Font character unknown : '" + charToRender + "' (0x" + ( (int)charToRender ).ToString ( "X2" ) + "), used in text \"" + text + "\"" );
                    if (!font.GetCharacterInfo(' ', out glyph))
                    {
                        errorMessage += "Font default replacement character [space] not defined.";
                    }
                    // Debug.LogError ( "Font default replacement character [space] not defined." );
                }
#endif
            }

            //          glyph = font.getData ().getGlyph ( charToRender );
            //          if (glyph == null)
            //              // throw new RuntimeException ( "Character '" + charToRender + "' is not defined in font" );
            //              glyph = font.getData ().getGlyph ( ' ' );

            int kerning = 0;             // kerning to add
            // if (i > 0)
            // {
            // char previousCharToRender = text.charAt ( i - 1 );
            // if (previousCharToRender == 0xA0)
            // previousCharToRender = (char) 0x20; // convert unbreakable space into space
            //
            // font.kerningTable.TryGetValue ( new KeyValuePair<char, char> ( previousCharToRender, charToRender ), out kerning );
            // }

            if (charToRender == 0x20)
            {
                lastSpaceIndex = i;                 // keep index of last space
//
//              // space special case
//              letterPosition.x = advance + kerning + glyph.minX;
//              letterPosition.y = ( glyph.minY + glyph.maxY - glyph.minY );
//              letterDimension.x = (float)glyph.maxX - glyph.minX;
//              letterDimension.y = glyph.maxY - glyph.minY; // 0.0f;
//              letterTopLeftUV = glyph.uvTopLeft;
//              letterTopRightUV = glyph.uvTopRight;
//              letterBottomLeftUV = glyph.uvBottomLeft;
//              letterBottomRightUV = glyph.uvBottomRight;
            }
//          else
            {
                letterPosition.x    = advance + kerning + glyph.minX;
                letterPosition.y    = (glyph.minY + glyph.maxY - glyph.minY);
                letterDimension.x   = glyph.maxX - glyph.minX;
                letterDimension.y   = -(glyph.maxY - glyph.minY);
                letterTopLeftUV     = glyph.uvTopLeft;
                letterTopRightUV    = glyph.uvTopRight;
                letterBottomLeftUV  = glyph.uvBottomLeft;
                letterBottomRightUV = glyph.uvBottomRight;
            }

            letterPosition  *= scaleFactor;            // apply scaling
            letterDimension *= scaleFactor;

            // check if text is over the max line width
            if (letterPosition.x + letterDimension.x > lineMaxWidth)
            {
                // generation is not finished, return count of processed characters
                if (preserveWords && (lastSpaceIndex > startIndex))
                {
                    // cut where the last space char was found, will truncate and discard all chars after
                    result.processedCharCount -= (i - lastSpaceIndex);
                    result.renderedCharCount  -= (i - lastSpaceIndex);
                    break;
                }
                else
                {
                    break;                     // line break in the middle of a word
                }
            }

            letterPosition += position;             // then offset by position

            // if ( charToRender != 0x20 )
            quadBatch.setQuad(quadStartIndex + result.renderedCharCount, letterPosition, letterDimension, letterTopLeftUV, letterTopRightUV, letterBottomLeftUV, letterBottomRightUV, color);
//              if ( glyph.flipped )
//                  quadBatch.flipUvs ( quadStartIndex + result.renderedCharCount );

            if (letterSpacingMode == LetterSpacingMode.Add)
            {
                advance += (glyph.advance + letterSpacing.x);
            }
            else
            {
                advance += letterSpacing.x;
            }

            result.processedCharCount++;
            result.renderedCharCount++;
        }

        return(result);
    }