Example #1
0
        /// <summary>
        /// Load the data from the "kernpairs" node
        /// </summary>
        /// <param name="xnl">XML node list containing the "kernpairs" node's children</param>
        private void LoadFontXML_kernpairs(XmlNodeList xnl)
        {
            foreach (XmlNode xn in xnl)
            {
                if (xn.Name == "kernpair")
                {
                    var left   = GetXMLAttribute(xn, "left")[0];
                    var right  = GetXMLAttribute(xn, "right")[0];
                    var adjust = GetXMLAttribute(xn, "adjust");

                    var pair = new KernPair(left, right);

                    Debug.Assert(!m_kernByPair.ContainsKey(pair));
                    m_kernByPair[pair] = SByte.Parse(adjust);
                }
            }
        }
Example #2
0
        private static KerningSubTable ReadFormat0Table(int version, TrueTypeDataBytes data, KernCoverage coverage)
        {
            var numberOfPairs = data.ReadUnsignedShort();
            // ReSharper disable once UnusedVariable
            var searchRange = data.ReadUnsignedShort();
            // ReSharper disable once UnusedVariable
            var entrySelector = data.ReadUnsignedShort();
            // ReSharper disable once UnusedVariable
            var rangeShift = data.ReadUnsignedShort();

            var pairs = new KernPair[numberOfPairs];

            for (int i = 0; i < numberOfPairs; i++)
            {
                var leftGlyphIndex  = data.ReadUnsignedShort();
                var rightGlyphIndex = data.ReadUnsignedShort();

                var value = data.ReadSignedShort();

                pairs[i] = new KernPair(leftGlyphIndex, rightGlyphIndex, value);
            }

            return(new KerningSubTable(version, coverage, pairs));
        }
Example #3
0
    private static GameObject GetObject(string s, Material material, float size, float extrudeDepth, int resolution, float characterSpacing, float lineSpacing, bool prime, bool separate)
    {
        if (!_initialized)
        {
            Debug.LogError("No font information available");
            return(null);
        }
        if (s == null || s.Length < 1)
        {
            Debug.LogError("String can't be null");
            return(null);
        }
        if (material == null)
        {
            material = defaultMaterial;
        }
        if (resolution < 1)
        {
            resolution = 1;
        }
        if (size < 0.001f)
        {
            size = 0.001f;
        }
        if (extrudeDepth < 0.0f)
        {
            extrudeDepth = 0.0f;
        }
        if (characterSpacing < 0.0f)
        {
            characterSpacing = 0.0f;
        }
        defaultFont = Mathf.Clamp(defaultFont, 0, _fontInfo.Length - 1);

        List <CommandData> commandData;
        int commandIndex = 0;

        char[] chars          = ParseString(s, out commandData);
        int    charCount      = chars.Length;
        var    glyphIndices   = new int[charCount];
        int    totalVertCount = 0;
        int    totalTriCount  = 0;
        bool   extrude        = (extrudeDepth > 0.0f);
        float  spacePercent   = (characterSpacing < 1.0f)? characterSpacing : 1.0f;
        float  spaceAdd       = (characterSpacing > 1.0f)? characterSpacing - 1.0f : 0.0f;
        var    thisFont       = _fontInfo[defaultFont];
        int    fontNumber     = defaultFont;

        // Get total vertex and triangle count, initializing glyph data as necessary
        for (int i = 0; i < charCount; i++)
        {
            var thisCommand = commandData[commandIndex];
            while (thisCommand.index == i)
            {
                if (thisCommand.command == Command.Font)
                {
                    int thisFontNumber = (int)thisCommand.data;
                    if (thisFontNumber >= 0 && thisFontNumber < _fontInfo.Length)
                    {
                        fontNumber = thisFontNumber;
                        thisFont   = _fontInfo[fontNumber];
                    }
                }
                thisCommand = commandData[++commandIndex];
            }

            if (thisFont == null)
            {
                Debug.LogError("Font is null");
                return(null);
            }

            // Set up glyphs if they haven't been previously initialized
            var character = chars[i];
            if (!thisFont.glyphDictionary.ContainsKey(character))
            {
                if (!thisFont.SetGlyphData(character))
                {
                    return(null);
                }
            }

            var glyphData = thisFont.glyphDictionary[character];
            glyphIndices[i] = glyphData.glyphIndex;

            if (glyphData.isVisible)
            {
                if (glyphData.resolution != resolution)
                {
                    if (!glyphData.SetMeshData(resolution))
                    {
                        Debug.LogWarning("Triangulation failed for char code " + Convert.ToInt32(character) + " (" + character + ")");
                        continue;
                    }
                    if (!extrude)
                    {
                        glyphData.SetFrontData();
                    }
                    else
                    {
                        if (includeBackface)
                        {
                            glyphData.SetData();
                        }
                        else
                        {
                            glyphData.SetFrontAndEdgeData();
                        }
                    }
                }
                if (!separate)
                {
                    totalVertCount += glyphData.vertexCount;
                    totalTriCount  += glyphData.triCount;
                }
            }
        }

        if (totalVertCount > 65534)
        {
            Debug.LogError("Too many points...use fewer characters or reduce resolution");
            return(null);
        }
        if (!separate && totalVertCount == 0)
        {
            Debug.LogError("No usable characters in string");
            return(null);
        }

        if (prime)
        {
            return(null);
        }
        GameObject goParent = separate? new GameObject() : null;

        // Use vertex colors if anything other than Color.white is specified anywhere
        Color thisColor = defaultColor;
        var   useColors = false;

        if (thisColor == Color.white)
        {
            for (var i = 0; i < commandData.Count; i++)
            {
                if (commandData[i].command == Command.Color && (Color)commandData[i].data != Color.white)
                {
                    useColors = true;
                    break;
                }
            }
        }
        else
        {
            useColors = true;
        }

        var   totalVerts   = new Vector3[totalVertCount];
        var   totalTris    = new int[totalTriCount];
        var   meshUVs      = new Vector2[totalVertCount];
        var   meshColors   = new Color[totalVertCount];
        int   vertIndex    = 0;
        int   triIndex     = 0;
        float baseScale    = 1.0f / thisFont.unitsPerEm;
        bool  uvsPerLetter = separate? true : texturePerLetter;

        Vector3[]      thisVerts;
        int[]          thisTris;
        var            kernPair         = new KernPair();
        float          smallestX        = float.MaxValue;
        float          largestX         = -float.MaxValue;
        float          smallestY        = float.MaxValue;
        float          largestY         = -float.MaxValue;
        List <float>   lineLengths      = null;
        List <Justify> lineJustifies    = null;
        int            loopType         = BUILDMESH;
        bool           hasMultipleLines = false;
        int            lineCount        = 0;
        float          longestLength    = 0.0f;
        var            thisJustify      = defaultJustification;

        if (Array.IndexOf(chars, '\n') != -1)
        {
            lineLengths      = new List <float>();
            lineJustifies    = new List <Justify>();
            loopType         = PREPROCESS;
            hasMultipleLines = true;
        }

        while (loopType > 0)
        {
            float horizontalPosition = 0.0f;
            float verticalPosition   = 0.0f;
            float zPosition          = 0.0f;
            float thisSize           = size;
            thisFont     = _fontInfo[defaultFont];
            commandIndex = 0;
            if (hasMultipleLines && loopType == BUILDMESH)
            {
                thisJustify = lineJustifies[0];
            }
            var thisCommand = commandData[0];
            for (int i = 0; i < charCount; i++)
            {
                while (thisCommand.index == i)
                {
                    switch (thisCommand.command)
                    {
                    case Command.Size:
                        thisSize = (float)thisCommand.data;
                        if (thisSize < .001f)
                        {
                            thisSize = .001f;
                        }
                        break;

                    case Command.Color:
                        thisColor = (Color)thisCommand.data;
                        break;

                    case Command.Font:
                        fontNumber = (int)thisCommand.data;
                        if (fontNumber >= 0 && fontNumber < _fontInfo.Length)
                        {
                            thisFont  = _fontInfo[fontNumber];
                            baseScale = 1.0f / thisFont.unitsPerEm;
                        }
                        break;

                    case Command.Zpos:
                        zPosition = (float)thisCommand.data;
                        break;

                    case Command.Depth:
                        extrudeDepth = (float)thisCommand.data;
                        if (extrudeDepth < 0.0f)
                        {
                            extrudeDepth = 0.0f;
                        }
                        break;

                    case Command.Space:
                        horizontalPosition += (float)thisCommand.data * thisSize;
                        break;

                    case Command.Justify:
                        if (loopType == PREPROCESS)
                        {
                            thisJustify = ((Justify)thisCommand.data);
                        }
                        break;
                    }
                    thisCommand = commandData[++commandIndex];
                }

                float scaleFactor = baseScale * thisSize;
                var   character   = chars[i];
                if (character == '\0')
                {
                    continue;
                }
                if (character == '\n')
                {
                    if (loopType == PREPROCESS)
                    {
                        lineLengths.Add(horizontalPosition);
                        lineJustifies.Add(thisJustify);
                    }
                    else if (hasMultipleLines)
                    {
                        if (++lineCount < lineJustifies.Count)
                        {
                            thisJustify = lineJustifies[lineCount];
                        }
                    }
                    verticalPosition  -= thisFont.lineHeight * lineSpacing * scaleFactor;
                    horizontalPosition = 0.0f;
                    continue;
                }
                int thisGlyphIdx = glyphIndices[i];

                // Kerning
                if (thisFont.hasKerning && i > 0)
                {
                    kernPair.left  = glyphIndices[i - 1];
                    kernPair.right = thisGlyphIdx;
                    if (thisFont.kernDictionary.ContainsKey(kernPair))
                    {
                        horizontalPosition += thisFont.kernDictionary[kernPair] * scaleFactor;
                    }
                }
                var glyphData = thisFont.glyphDictionary[character];

                // Copy tris/verts to combined mesh
                int vertexCount = glyphData.vertexCount;
                if (vertexCount > 0 && loopType == BUILDMESH)
                {
                    if (glyphData.scaleFactor != scaleFactor)
                    {
                        glyphData.ScaleVertices(scaleFactor, extrude, includeBackface);
                    }

                    if (extrude && glyphData.extrudeDepth != extrudeDepth)
                    {
                        glyphData.SetExtrudeDepth(extrudeDepth, includeBackface);
                    }

                    thisVerts = glyphData.vertices;

                    if (separate)
                    {
                        totalVerts = new Vector3[vertexCount];
                        totalTris  = new int[glyphData.triCount];
                        meshUVs    = new Vector2[vertexCount];
                        if (useColors)
                        {
                            meshColors = new Color[vertexCount];
                        }
                        vertIndex = 0;
                        triIndex  = 0;
                    }

                    // Get min/max bounds (for UVs if not per-letter, plus anchor position)
                    float max = glyphData.xMax * scaleFactor + horizontalPosition;
                    float min = glyphData.xMin * scaleFactor + horizontalPosition;
                    if (max > largestX)
                    {
                        largestX = max;
                    }
                    if (min < smallestX)
                    {
                        smallestX = min;
                    }
                    max = glyphData.yMax * scaleFactor + verticalPosition;
                    min = glyphData.yMin * scaleFactor + verticalPosition;
                    if (max > largestY)
                    {
                        largestY = max;
                    }
                    if (min < smallestY)
                    {
                        smallestY = min;
                    }

                    if (uvsPerLetter)
                    {
                        float xMax   = glyphData.xMax * scaleFactor;
                        float xMin   = glyphData.xMin * scaleFactor;
                        float yMax   = glyphData.yMax * scaleFactor;
                        float yMin   = glyphData.yMin * scaleFactor;
                        float xRange = xMax - xMin;
                        float yRange = yMax - yMin;
                        for (int j = 0; j < vertexCount; j++)
                        {
                            meshUVs[j + vertIndex].x = (thisVerts[j].x - xMin) / xRange;
                            meshUVs[j + vertIndex].y = (thisVerts[j].y - yMin) / yRange;
                        }
                    }

                    if (useColors)
                    {
                        for (int j = 0; j < vertexCount; j++)
                        {
                            meshColors[j + vertIndex] = thisColor;
                        }
                    }

                    thisTris = glyphData.triangles;
                    int triCount = glyphData.triCount;
                    for (int j = 0; j < triCount; j += 3)
                    {
                        totalTris[triIndex]     = thisTris[j] + vertIndex;
                        totalTris[triIndex + 1] = thisTris[j + 1] + vertIndex;
                        totalTris[triIndex + 2] = thisTris[j + 2] + vertIndex;
                        triIndex += 3;
                    }

                    // Set vertices with appropriate line justification
                    if (hasMultipleLines && thisJustify != Justify.Left && longestLength != lineLengths[lineCount])
                    {
                        float addSpace = (thisJustify == Justify.Right)? longestLength - lineLengths[lineCount] :
                                         (longestLength - lineLengths[lineCount]) / 2;
                        if (!separate)
                        {
                            for (int j = 0; j < vertexCount; j++)
                            {
                                totalVerts[vertIndex].x   = thisVerts[j].x + horizontalPosition + addSpace;
                                totalVerts[vertIndex].y   = thisVerts[j].y + verticalPosition;
                                totalVerts[vertIndex++].z = thisVerts[j].z + zPosition;
                            }
                        }
                        else
                        {
                            for (int j = 0; j < vertexCount; j++)
                            {
                                totalVerts[vertIndex].x   = thisVerts[j].x + addSpace;
                                totalVerts[vertIndex].y   = thisVerts[j].y;
                                totalVerts[vertIndex++].z = thisVerts[j].z + zPosition;
                            }
                        }
                    }
                    else
                    {
                        if (!separate)
                        {
                            for (int j = 0; j < vertexCount; j++)
                            {
                                totalVerts[vertIndex].x   = thisVerts[j].x + horizontalPosition;
                                totalVerts[vertIndex].y   = thisVerts[j].y + verticalPosition;
                                totalVerts[vertIndex++].z = thisVerts[j].z + zPosition;
                            }
                        }
                        else
                        {
                            for (int j = 0; j < vertexCount; j++)
                            {
                                totalVerts[vertIndex].x   = thisVerts[j].x;
                                totalVerts[vertIndex].y   = thisVerts[j].y;
                                totalVerts[vertIndex++].z = thisVerts[j].z + zPosition;
                            }
                        }
                    }

                    // Create mesh and game object for individual letters
                    if (separate)
                    {
                        var charMesh = new Mesh();
                        charMesh.name     = character.ToString();
                        charMesh.vertices = totalVerts;
                        charMesh.uv       = meshUVs;
                        if (useColors)
                        {
                            charMesh.colors = meshColors;
                        }
                        charMesh.triangles = totalTris;
                        charMesh.RecalculateNormals();

                        var charGo = new GameObject(character.ToString(), typeof(MeshFilter), typeof(MeshRenderer));
                        charGo.GetComponent <MeshFilter>().mesh = charMesh;
                        if (colliderType == ColliderType.Mesh || colliderType == ColliderType.ConvexMesh)
                        {
                            var meshCollider = charGo.AddComponent <MeshCollider>();
                            meshCollider.sharedMesh     = charMesh;
                            meshCollider.convex         = (colliderType == ColliderType.ConvexMesh);
                            meshCollider.sharedMaterial = physicsMaterial;
                        }
                        else if (colliderType == ColliderType.Box)
                        {
                            var boxCollider = charGo.AddComponent <BoxCollider>();
                            boxCollider.sharedMaterial = physicsMaterial;
                        }
                        if (addRigidbodies)
                        {
                            charGo.AddComponent(typeof(Rigidbody));
                        }
                        charGo.renderer.sharedMaterial = material;
                        charGo.transform.parent        = goParent.transform;
                        charGo.transform.position      = new Vector3(horizontalPosition, verticalPosition, zPosition);
                    }
                }
                horizontalPosition += (thisFont.advanceArray[thisGlyphIdx] + spaceAdd / baseScale) * (scaleFactor * spacePercent);
            }

            if (loopType-- == PREPROCESS)
            {
                lineLengths.Add(horizontalPosition);
                lineJustifies.Add(thisJustify);
                longestLength = lineLengths[0];
                for (int i = 1; i < lineLengths.Count; i++)
                {
                    if (lineLengths[i] > longestLength)
                    {
                        longestLength = lineLengths[i];
                    }
                }
            }
        }

        // Set UVs for complete mesh, if not per-letter
        if (!uvsPerLetter)
        {
            float xRange = largestX - smallestX;
            float yRange = largestY - smallestY;
            for (int i = 0; i < totalVertCount; i++)
            {
                meshUVs[i].x = (totalVerts[i].x - smallestX) / xRange;
                meshUVs[i].y = (totalVerts[i].y - smallestY) / yRange;
            }
        }

        var add = Vector3.zero;

        switch (anchor)
        {
        case TextAnchor.UpperLeft:
            add.y = largestY;
            break;

        case TextAnchor.UpperCenter:
            add.x = (largestX - smallestX) * .5f;
            add.y = largestY;
            break;

        case TextAnchor.UpperRight:
            add.x = largestX - smallestX;
            add.y = largestY;
            break;

        case TextAnchor.MiddleLeft:
            add.y = (smallestY - largestY) * .5f + largestY;
            break;

        case TextAnchor.MiddleCenter:
            add.x = (largestX - smallestX) * .5f;
            add.y = (smallestY - largestY) * .5f + largestY;
            break;

        case TextAnchor.MiddleRight:
            add.x = largestX - smallestX;
            add.y = (smallestY - largestY) * .5f + largestY;
            break;

        case TextAnchor.LowerLeft:
            add.y = (smallestY - largestY) + largestY;
            break;

        case TextAnchor.LowerCenter:
            add.x = (largestX - smallestX) * .5f;
            add.y = (smallestY - largestY) + largestY;
            break;

        case TextAnchor.LowerRight:
            add.x = largestX - smallestX;
            add.y = (smallestY - largestY) + largestY;
            break;
        }
        if (extrude)
        {
            switch (zAnchor)
            {
            case ZAnchor.Middle:
                add.z = defaultDepth * .5f;
                break;

            case ZAnchor.Back:
                add.z = defaultDepth;
                break;
            }
        }
        if (!separate)
        {
            for (int i = 0; i < totalVertCount; i++)
            {
                totalVerts[i] -= add;
            }
        }
        else
        {
            var gos = goParent.GetComponentsInChildren <Transform>();
            for (int i = 0; i < gos.Length; i++)
            {
                if (gos[i].gameObject == goParent.gameObject)
                {
                    continue;
                }
                gos[i].position -= add;
            }
        }

        // Get gameobject name from string, and create mesh and game object if not separate
        var charString = new string(chars);
        var name       = charString.Substring(0, Mathf.Min(20, charString.Length));

        name = name.Replace("\n", " ");
        name = name.Replace("\0", "");

        if (separate)
        {
            goParent.name = "3DText " + name;
            return(goParent);
        }

        var mesh = new Mesh();

        mesh.name     = name;
        mesh.vertices = totalVerts;
        mesh.uv       = meshUVs;
        if (useColors)
        {
            mesh.colors = meshColors;
        }
        mesh.triangles = totalTris;
        mesh.RecalculateNormals();

        var textGo = new GameObject("3DText " + name, typeof(MeshFilter), typeof(MeshRenderer));

        textGo.GetComponent <MeshFilter>().mesh = mesh;
        textGo.renderer.sharedMaterial          = material;
        if (colliderType == ColliderType.Box)
        {
            var boxCollider = textGo.AddComponent <BoxCollider>();
            boxCollider.sharedMaterial = physicsMaterial;
        }
        if (addRigidbodies)
        {
            textGo.AddComponent <Rigidbody>();
        }
        return(textGo);
    }