Example #1
0
		/// <summary> Creates a new header by reading it from the specified stream. </summary>
		/// <param name="reader"> The correctly positioned stream to read from. The caller is responsible for disposal. </param>
		public MathTable(BinaryReader reader)
		{
			Contract.Requires(reader != null);
			Contract.Requires(reader.BaseStream.CanSeek);

			long mathTableOffset = reader.BaseStream.Position;
			MainVersion = reader.ReadUInt16(); //section 4.3 of the specs says 16.16 bits for anything of type 'Fixed' (i.e. main version dot subversion)
			SubVersion = reader.ReadUInt16();

			uint offsetToConstantsTable = reader.ReadUInt16EvenThoughSpecsSays32();
			uint offsetToGlyphInfo = reader.ReadUInt16EvenThoughSpecsSays32();
			uint offsetToVariants = reader.ReadUInt16EvenThoughSpecsSays32();

			reader.BaseStream.Position = mathTableOffset + offsetToConstantsTable;
			Constants = new ConstantsTable(reader);

			reader.BaseStream.Position = mathTableOffset + offsetToGlyphInfo;
			Glyphs = new GlyphInfo(reader);

			reader.BaseStream.Position = mathTableOffset + offsetToVariants;
			Variants = new VariantsTable(reader);
		}
        GlyphInfo CreateGlyph(int index)
        {
            GlyphInfo glyph = new GlyphInfo();
            glyph.colors = ImageProcessing.GetProportionalGlyphColors(fntFile, index, backgroundColor, textColor, true);
            glyph.width = fntFile.GetGlyphWidth(index);

            return glyph;
        }
Example #3
0
        protected void SetTextMesh(int posX, int posY)
        {
            if (FontMap == null)
            {
                return;
            }

            // relative coordinates from -1 to +1
            var scaleX = (float)2 / RContext.ViewportWidth;
            var scaleY = (float)2 / RContext.ViewportHeight;

            var x = -1 + posX * scaleX;
            var y = +1 - posY * scaleY;

            // build complete structure
            var vertices = new float3[4 * Text.Length];
            var uvs      = new float2[4 * Text.Length];
            var indices  = new ushort[6 * Text.Length];

            // var charInfo = Font.CharInfo;
            var atlasWidth  = FontMap.Image.Width;
            var atlasHeight = FontMap.Image.Height;

            var    index  = 0;
            ushort vertex = 0;

            // now build the mesh
            foreach (var letter in Text)
            {
                GlyphOnMap glyphOnMap = FontMap.GetGlyphOnMap(letter);
                GlyphInfo  glyphInfo  = FontMap.Font.GetGlyphInfo(letter);

                var x2 = x + glyphOnMap.BitmapL * scaleX;
                var y2 = -y - glyphOnMap.BitmapT * scaleY;
                var w  = glyphOnMap.BitmapW * scaleX;
                var h  = glyphOnMap.BitmapH * scaleY;

                x += glyphInfo.AdvanceX * scaleX;
                y += glyphInfo.AdvanceY * scaleY;

                // skip glyphs that have no pixels
                if ((w <= M.EpsilonFloat) || (h <= M.EpsilonFloat))
                {
                    continue;
                }

                var bitmapW    = glyphOnMap.BitmapW;
                var bitmapH    = glyphOnMap.BitmapH;
                var texOffsetX = glyphOnMap.TexOffX;
                var texOffsetY = glyphOnMap.TexOffY;

                // vertices
                vertices[vertex]     = new float3(x2, -y2 - h, 0);
                vertices[vertex + 1] = new float3(x2, -y2, 0);
                vertices[vertex + 2] = new float3(x2 + w, -y2 - h, 0);
                vertices[vertex + 3] = new float3(x2 + w, -y2, 0);

                // uvs
                uvs[vertex]     = new float2(texOffsetX, texOffsetY + bitmapH / atlasHeight);
                uvs[vertex + 1] = new float2(texOffsetX, texOffsetY);
                uvs[vertex + 2] = new float2(texOffsetX + bitmapW / atlasWidth, texOffsetY + bitmapH / atlasHeight);
                uvs[vertex + 3] = new float2(texOffsetX + bitmapW / atlasWidth, texOffsetY);

                // indices
                indices[index++] = (ushort)(vertex + 1);
                indices[index++] = vertex;
                indices[index++] = (ushort)(vertex + 2);

                indices[index++] = (ushort)(vertex + 1);
                indices[index++] = (ushort)(vertex + 2);
                indices[index++] = (ushort)(vertex + 3);

                vertex += 4;
            }

            vertices = FontMap.FixTextKerning(vertices, Text, scaleX);

            // create final mesh
            CreateTextMesh(vertices, uvs, indices);
        }
Example #4
0
        internal bool GetGlyphMetrics(GlyphInfo array, uint size, GlyphType type, bool horizontal)
        {
            bool ret = NDalicManualPINVOKE.FontClient_GetGlyphMetrics__SWIG_0(swigCPtr, GlyphInfo.getCPtr(array), size, (int)type, horizontal);

            if (NDalicPINVOKE.SWIGPendingException.Pending)
            {
                throw NDalicPINVOKE.SWIGPendingException.Retrieve();
            }
            return(ret);
        }
Example #5
0
File: SymDef.cs Project: jonc/carto
        // Draw the glyphs along the path. "longPath" is the same as path unless shortening of the ends has occurred, in which case
        // path is the shortened path (used for all glyphs except start and end), and longPath is used for the start and end.
        private void DrawGlyphs(GraphicsTarget g, GlyphInfo glyphInfo, SymPath path, SymPath longPath, SymColor color, RenderOptions renderOpts)
        {
            float[] distances;
            PointF[] points;
            float[] perpAngles, subtendedAngles;
            float firstDistance;

            // Figure out the distances of the glyphs along the line.
            switch (glyphInfo.location) {
            case GlyphLocation.Corners:
                // Corner points are done somewhat differently. Only can have 1 symbol.
                // There is an interesting feature in OCAD where the dimensions of corner glyphs are stretched a certain amount at
                // very acute angles. This is so that power line crossbars always extend beyond the power lines themselves.
                // This is handled by stretching the glyph based on the subtended angle at the corner.
                points = path.FindCornerPoints(out perpAngles, out subtendedAngles);
                if (points != null) {
                    for (int i = 0; i < points.Length; ++i) {
                        float subtendedAngle = subtendedAngles[i];
                        float stretch;
                        if (subtendedAngle != 0)
                            stretch = Util.MiterFactor(subtendedAngle);
                        else
                            stretch = 1.0F;
                        stretch = Math.Min(stretch, CORNER_GLYPH_STRETCH_LIMIT);

                        Matrix stretchMatrix = new Matrix();
                        stretchMatrix.Scale(1.0F, stretch);

                        glyphInfo.glyph.Draw(g, points[i], perpAngles[i] + 90.0F, stretchMatrix, null, color, renderOpts);
                    }
                }
                return;

            case GlyphLocation.Spaced:
                distances = ComputeDashDistances(path, LocationKind.GapCenters, glyphInfo.distance, glyphInfo.firstDistance, glyphInfo.lastDistance, 0, glyphInfo.minimum, 0, 0, 0, 0, 0, 1.0F, false);
                break;
            case GlyphLocation.SpacedOffset:
                distances = ComputeDashDistances(path, LocationKind.GapCentersOffset, glyphInfo.distance, glyphInfo.firstDistance, glyphInfo.lastDistance, 0, glyphInfo.minimum, glyphInfo.offset, 0, 0, 0, 0, 1.0F, false);
                break;
            case GlyphLocation.SpacedDecrease:
                distances = ComputeDashDistances(path, LocationKind.GapCentersDecrease, glyphInfo.distance, glyphInfo.firstDistance, glyphInfo.lastDistance, 0, glyphInfo.minimum, 0, 0, 0, 0, 0, glyphInfo.decreaseLimit, glyphInfo.decreaseBothEnds);

                if (distances != null && distances.Length > 0) {
                    firstDistance = distances[0];

                    for (int n = 0; n < glyphInfo.number; ++n) {
                        distances[0] = Math.Max(0.0F, firstDistance - ((glyphInfo.number - 1 - n * 2) * (glyphInfo.spacing / 2.0F)));

                        points = path.FindPointsAlongLineBizzarro(distances, out perpAngles);

                        for (int i = 0; i < points.Length; ++i) {
                            float decreaseFactor;
                            if (glyphInfo.decreaseBothEnds) {
                                if (points.Length <= 2)
                                    decreaseFactor = glyphInfo.decreaseLimit;
                                else
                                    decreaseFactor = 1.0F - (Math.Abs(i - ((points.Length-1) / 2F)) * (1 - glyphInfo.decreaseLimit) / ((points.Length-1) / 2F));
                            }
                            else {
                                if (i == 0)
                                    decreaseFactor = 1.0F;
                                else
                                    decreaseFactor = 1.0F - (i * (1 - glyphInfo.decreaseLimit) / (points.Length - 1));
                            }
                            Matrix matrixTransform = new Matrix();
                            matrixTransform.Scale(decreaseFactor, decreaseFactor);
                            glyphInfo.glyph.Draw(g, points[i], perpAngles[i], matrixTransform, null, color, renderOpts);
                        }
                    }
                }

                return;
            case GlyphLocation.DashCenters:
                distances = ComputeDashDistances(path, LocationKind.DashCenters, dashInfo.dashLength, dashInfo.firstDashLength, dashInfo.lastDashLength, dashInfo.gapLength, dashInfo.minGaps, 0, 0, 0, 0, 0, 1.0F, false);
                break;
            case GlyphLocation.MiddleDashCenters:
                distances = ComputeDashDistances(path, LocationKind.MiddleDashCenters, dashInfo.dashLength, dashInfo.firstDashLength, dashInfo.lastDashLength, dashInfo.gapLength, dashInfo.minGaps, 0, 0, 0, 0, 0, 1.0F, false);
                break;
            case GlyphLocation.GapCenters:
                // OCAD doesn't respect the "0 minimum gaps" for the symbols, although it does for the gaps. Always have at least one symbol. This is handled on import by having glyphInfo.minimum be 1.
                distances = ComputeDashDistances(path, LocationKind.GapCenters, dashInfo.dashLength, dashInfo.firstDashLength, dashInfo.lastDashLength, dashInfo.gapLength, Math.Max(glyphInfo.minimum, dashInfo.minGaps), 0, 0, 0, 0, 0, 1.0F, false);
                break;
            case GlyphLocation.Start:
                distances = new float[1] { 0 };
                break;
            case GlyphLocation.End:
                distances = new float[1] { longPath.BizzarroLength };
                break;
            default:
                Debug.Fail("bad glyph location");
                return;
            }

            if (distances == null || distances.Length == 0)
                return;
            firstDistance = distances[0];

            for (int n = 0; n < glyphInfo.number; ++n) {
                distances[0] = Math.Max(0.0F, firstDistance - ((glyphInfo.number - 1 - n * 2) * (glyphInfo.spacing / 2.0F)));

                if (glyphInfo.location == GlyphLocation.Start || glyphInfo.location == GlyphLocation.End)
                    points = longPath.FindPointsAlongLineBizzarro(distances, out perpAngles);
                else
                    points = path.FindPointsAlongLineBizzarro(distances, out perpAngles);

                for (int i = 0; i < points.Length; ++i) {
                    glyphInfo.glyph.Draw(g, points[i], perpAngles[i], GraphicsUtil.IdentityMatrix, null, color, renderOpts);
                }
            }
        }
Example #6
0
        internal GlyphInfo LoadGlyph(char codePoint)
        {
            if (!_pages.ContainsKey(codePoint))
            {
                // Load the glyph from the font face
                Glyph glyph = FontFace.GetGlyph(codePoint, FontSize);

                if (glyph == null)
                {
                    if (!_errorChars.Contains(codePoint))
                    {
                        Engine.Get.Debug.Warning($"Could not load character '{codePoint}' for font '{FontFace.FullName}'");
                        _errorChars.Add(codePoint);
                    }
                    return(GlyphInfo.Empty);
                }

                // Load the glyph into the texture
                Surface fontSurface = new Surface
                {
                    Bits   = Marshal.AllocHGlobal(glyph.RenderWidth * glyph.RenderHeight),
                    Width  = glyph.RenderWidth,
                    Height = glyph.RenderHeight,
                    Pitch  = glyph.RenderWidth
                };

                // Clear the memory region of the surface bits
                Marshal.Copy(new byte[glyph.RenderWidth * glyph.RenderHeight], 0,
                             fontSurface.Bits, glyph.RenderWidth * glyph.RenderHeight);

                // Render the glyph to the surface
                glyph.RenderTo(fontSurface);

                int    width  = fontSurface.Width;
                int    height = fontSurface.Height;
                int    len    = width * height;
                byte[] data   = new byte[len];

                // Copy the bits into the data bytes array
                Marshal.Copy(fontSurface.Bits, data, 0, len);

                // Free the memory of the surface bits
                Marshal.FreeHGlobal(fontSurface.Bits);

                // Create RGBA version of data bytes
                byte[] pixels = new byte[len * 4];
                int    index  = 0;

                // Fill the RGBA pixels with the data
                for (int i = 0; i < len; i++)
                {
                    byte c = data[i];
                    pixels[index++] = c;
                    pixels[index++] = c;
                    pixels[index++] = c;
                    pixels[index++] = c;
                }

                FaceMetrics faceMetrics = FontFace.GetFaceMetrics(FontSize);

                // padding between glyphs to avoid bleeding in rotated text
                const int padding = 3;

                // While the glyph does not fit on the x-axis, keep resizing the texture in the x-axis
                while (Texture.Size.X <= (_nextFreeColumnPosition + glyph.RenderWidth + padding + RowOffset))
                {
                    int newSizeX = Texture.Size.X * 2;

                    // Check if the glyph does not fit on the row
                    if (newSizeX >= Texture.MaxTextureSize)
                    {
                        AddTextureRow();

                        // Move row to the next available
                        _nextFreeRowPosition = RowOffset;

                        // Reset the column to the start of the line
                        _nextFreeColumnPosition = RowOffset;
                    }
                    else
                    {
                        // Make the texture wider
                        ResizeTexture(newSizeX, Texture.Size.Y);
                    }
                }

                // While the glyph does not fit on the y-axis, keep resizing the texture in the y-axis
                while (Texture.Size.Y <= (_nextFreeRowPosition + glyph.RenderHeight + padding))
                {
                    AddTextureRow();
                }

                // Update texture with the glyph
                Texture.Update(pixels, new IntRect((int)_nextFreeColumnPosition + RowOffset, (int)_nextFreeRowPosition, glyph.RenderWidth, glyph.RenderHeight));

                float sourceX = Math.Max(RowOffset, (_nextFreeColumnPosition + RowOffset) - ((float)padding / 2));


                // Create the rect representing the region for this glyph on the updated texture
                FloatRect sourceRect = new FloatRect(sourceX, _nextFreeRowPosition,
                                                     glyph.RenderWidth + padding, glyph.RenderHeight);

                // Move column to next available
                _nextFreeColumnPosition += glyph.RenderWidth + padding;

                // Create and add glyph info to the pages
                GlyphInfo glyphInfo = new GlyphInfo
                {
                    Advance    = glyph.HorizontalMetrics.Advance,
                    BearingX   = glyph.HorizontalMetrics.Bearing.X,
                    BearingY   = glyph.HorizontalMetrics.Bearing.Y,
                    SourceRect = sourceRect
                };

                _pages.Add(codePoint, glyphInfo);
            }

            return(_pages[codePoint]);
        }
Example #7
0
 public void AddGlyph(int ascii, GlyphInfo info)
 {
     glyphs.Add(ascii, info);
 }
Example #8
0
		public void SetGlyphTexCoords( CodePoint c, Real u1, Real v1, Real u2, Real v2, Real aspect )
		{
			var glyph = new GlyphInfo( c, new UVRect( v1, u1, v2, u2 ), aspect*( u2 - u1 )/( v2 - v1 ) );
			if ( this.codePoints.ContainsKey( c ) )
			{
				this.codePoints[ c ] = glyph;
			}
			else
			{
				this.codePoints.Add( c, glyph );
			}
		}
Example #9
0
 public GlyphContourInfo(GlyphInfo g)
 {
     BaseInfo = g;
 }
        /// <summary>
        /// Imports a generic pixel font from texture.
        /// Source atlas texture:
        ///  * Must be readable
        ///  * Must start from ASCII 0 character
        ///  * Must not have more than 256 characters total
        ///  * Must increment characters left to right, top to bottom (with 0 at top-left)
        /// </summary>
        /// <param name="texture">Source texture atlas.</param>
        /// <param name="glyphsWide">Number of glyphs packed horizontally.</param>
        /// <param name="glyphsHigh">Number of glyphs packed vertically.</param>
        /// <param name="dimension">Dimension of each glyph.</param>
        /// <param name="proportional">Discover proportional width of glyphs.</param>
        public void ImportBitmapFont(Texture2D texture, int glyphsWide, int glyphsHigh, int dimension, bool proportional = true)
        {
            // Validate count
            int count = glyphsWide * glyphsHigh;

            if (count > 256)
            {
                throw new Exception("ImportBitmapFont: Glyph count > 256.");
            }

            // Validate dimensions
            if (glyphsWide * dimension > texture.width ||
                glyphsHigh * dimension > texture.height)
            {
                throw new Exception("ImportBitmapFont: Invalid texture dimensions.");
            }

            // Get texture as Color32 array
            Color32[] colors = texture.GetPixels32();

            // Start new glyph dictionary
            ClearGlyphs();

            // Store settings
            atlasTexture = texture;
            GlyphHeight  = dimension;
            asciiStart   = 0;

            // Generate rects
            if (!proportional)
            {
                atlasRects = GenerateNonProportionalRects(texture.width, texture.height, glyphsWide, glyphsHigh, dimension, count);
            }
            else
            {
                atlasRects = GenerateProportionalRects(ref colors, texture.width, texture.height, glyphsWide, glyphsHigh, dimension, count);
            }

            // Add glyphs
            //int xpos = 0;
            //int ypos = 0;
            //DFSize srcSize = new DFSize(texture.width, texture.height);
            //DFSize dstSize = new DFSize(dimension, dimension);
            for (int i = 0; i < count; i++)
            {
                //Color32[] dst = new Color32[dimension * dimension];
                //ImageProcessing.CopyColors(ref colors, ref dst, srcSize, dstSize, new DFPosition(xpos, ypos), new DFPosition(0, 0), dstSize);

                GlyphInfo glyph = new GlyphInfo();
                //glyph.colors = dst;
                glyph.width = (int)(atlasRects[i].width * texture.width);
                AddGlyph(i, glyph);

                //xpos += dimension;
                //if (xpos > texture.width)
                //{
                //    xpos = 0;
                //    ypos += dimension;
                //}
            }
        }
Example #11
0
        internal bool GetGlyphMetrics(GlyphInfo array, uint size, GlyphType type)
        {
            bool ret = Interop.FontClient.FontClient_GetGlyphMetrics__SWIG_1(swigCPtr, GlyphInfo.getCPtr(array), size, (int)type);

            if (NDalicPINVOKE.SWIGPendingException.Pending)
            {
                throw NDalicPINVOKE.SWIGPendingException.Retrieve();
            }
            return(ret);
        }
		/// --------------------------------------------------------------------------------
		/// <summary>
		///
		/// </summary>
		/// <param name="x"></param>
		/// <param name="y"></param>
		/// <param name="cgi"></param>
		/// <param name="_rggi"></param>
		/// <returns></returns>
		/// --------------------------------------------------------------------------------
		public void DrawGlyphs(int x, int y, int cgi, GlyphInfo[] _rggi)
		{
			// TODO:  Add DummyGraphics.DrawGlyphs implementation
		}
Example #13
0
 public static extern GlyphFlags hb_glyph_info_get_glyph_flags(ref GlyphInfo info);
        /// <summary>
        /// Imports a generic pixel font from texture.
        /// Source atlas texture:
        ///  * Must be readable
        ///  * Must start from ASCII 0 character
        ///  * Must not have more than 256 characters total
        ///  * Must increment characters left to right, top to bottom (with 0 at top-left)
        /// </summary>
        /// <param name="texture">Source texture atlas.</param>
        /// <param name="glyphsWide">Number of glyphs packed horizontally.</param>
        /// <param name="glyphsHigh">Number of glyphs packed vertically.</param>
        /// <param name="dimension">Dimension of each glyph.</param>
        /// <param name="proportional">Discover proportional width of glyphs.</param>
        public void ImportBitmapFont(Texture2D texture, int glyphsWide, int glyphsHigh, int dimension, bool proportional = true)
        {
            // Validate count
            int count = glyphsWide * glyphsHigh;
            if (count > 256)
            {
                throw new Exception("ImportBitmapFont: Glyph count > 256.");
            }

            // Validate dimensions
            if (glyphsWide * dimension > texture.width ||
                glyphsHigh * dimension > texture.height)
            {
                throw new Exception("ImportBitmapFont: Invalid texture dimensions.");
            }

            // Get texture as Color32 array
            Color32[] colors = texture.GetPixels32();

            // Start new glyph dictionary
            ClearGlyphs();

            // Store settings
            atlasTexture = texture;
            GlyphHeight = dimension;
            asciiStart = 0;

            // Generate rects
            if (!proportional)
                atlasRects = GenerateNonProportionalRects(texture.width, texture.height, glyphsWide, glyphsHigh, dimension, count);
            else
                atlasRects = GenerateProportionalRects(ref colors, texture.width, texture.height, glyphsWide, glyphsHigh, dimension, count);

            // Add glyphs
            //int xpos = 0;
            //int ypos = 0;
            //DFSize srcSize = new DFSize(texture.width, texture.height);
            //DFSize dstSize = new DFSize(dimension, dimension);
            for (int i = 0; i < count; i++)
            {
                //Color32[] dst = new Color32[dimension * dimension];
                //ImageProcessing.CopyColors(ref colors, ref dst, srcSize, dstSize, new DFPosition(xpos, ypos), new DFPosition(0, 0), dstSize);

                GlyphInfo glyph = new GlyphInfo();
                //glyph.colors = dst;
                glyph.width = (int)(atlasRects[i].width * texture.width);
                AddGlyph(i, glyph);

                //xpos += dimension;
                //if (xpos > texture.width)
                //{
                //    xpos = 0;
                //    ypos += dimension;
                //}
            }
        }
        GlyphInfo CreateSpaceGlyph()
        {
            int width = fntFile.FixedWidth - 1;
            int height = fntFile.FixedHeight;
            Color32[] colors = new Color32[width * height];
            for (int i = 0; i < colors.Length; i++)
            {
                colors[i] = backgroundColor;
            }

            GlyphInfo glyph = new GlyphInfo();
            glyph.colors = colors;
            glyph.width = width;

            return glyph;
        }
        // Convert from FT_GlyphInfo[] to GlyphInfo[]
        GlyphInfo[] GetGlyphInfo(FT_GlyphInfo[] ft_glyphs, int scaleFactor)
        {
            GlyphInfo[] glyphs = new GlyphInfo[ft_glyphs.Length];
            m_kerningSet = new int[ft_glyphs.Length];

            for (int i = 0; i < ft_glyphs.Length; i++)
            {
                GlyphInfo g = new GlyphInfo();

                g.id = ft_glyphs[i].id;
                g.x = ft_glyphs[i].x / scaleFactor;
                g.y = ft_glyphs[i].y / scaleFactor;
                g.width = ft_glyphs[i].width / scaleFactor;
                g.height = ft_glyphs[i].height / scaleFactor;
                g.xOffset = ft_glyphs[i].xOffset / scaleFactor;
                g.yOffset = ft_glyphs[i].yOffset / scaleFactor;
                g.xAdvance = ft_glyphs[i].xAdvance / scaleFactor;

                glyphs[i] = g;
                m_kerningSet[i] = g.id;
            }

            return glyphs;
        }
Example #17
0
        private void CreateTextMesh()
        {
            if (_fontMap == null)
            {
                throw new ArgumentException("Can not create Text Mesh - FontMap not found!");
            }


            var verts   = new List <float3>();
            var uvs     = new List <float2>();
            var tris    = new List <ushort>();
            var normals = new List <float3>();

            // build complete structure

            // var charInfo = Font.CharInfo;
            var atlasWidth  = _fontMap.Image.Width;
            var atlasHeight = _fontMap.Image.Height;

            ushort vertex   = 0;
            var    advanceX = 0f;
            var    advanceY = 0f;

            var textMeshHeight = 0f;

            // now build the mesh
            foreach (var letter in _text)
            {
                GlyphOnMap glyphOnMap = _fontMap.GetGlyphOnMap(letter);
                GlyphInfo  glyphInfo  = _fontMap.Font.GetGlyphInfo(letter);

                var x = advanceX + glyphOnMap.BitmapL;
                var y = advanceY - glyphOnMap.BitmapT;
                var w = glyphOnMap.BitmapW;
                var h = glyphOnMap.BitmapH;

                if (-y > textMeshHeight)
                {
                    textMeshHeight = -y;
                }

                advanceX += glyphInfo.AdvanceX;
                advanceY += glyphInfo.AdvanceY;

                // skip glyphs that have no pixels
                if ((w <= M.EpsilonFloat) || (h <= M.EpsilonFloat))
                {
                    continue;
                }

                var bitmapW    = glyphOnMap.BitmapW;
                var bitmapH    = glyphOnMap.BitmapH;
                var texOffsetX = glyphOnMap.TexOffX;
                var texOffsetY = glyphOnMap.TexOffY;

                // vertices
                verts.Add(new float3(x, -y - h, 0));
                verts.Add(new float3(x, -y, 0));
                verts.Add(new float3(x + w, -y - h, 0));
                verts.Add(new float3(x + w, -y, 0));

                normals.Add(-float3.UnitZ);
                normals.Add(-float3.UnitZ);
                normals.Add(-float3.UnitZ);
                normals.Add(-float3.UnitZ);

                // uvs
                uvs.Add(new float2(texOffsetX, texOffsetY + bitmapH / atlasHeight));
                uvs.Add(new float2(texOffsetX, texOffsetY));
                uvs.Add(new float2(texOffsetX + bitmapW / atlasWidth, texOffsetY + bitmapH / atlasHeight));
                uvs.Add(new float2(texOffsetX + bitmapW / atlasWidth, texOffsetY));

                // indices
                tris.Add((ushort)(vertex + 1));
                tris.Add(vertex);
                tris.Add((ushort)(vertex + 2));

                tris.Add((ushort)(vertex + 1));
                tris.Add((ushort)(vertex + 2));
                tris.Add((ushort)(vertex + 3));

                vertex += 4;
            }

            Vertices  = verts.ToArray();
            Triangles = tris.ToArray();
            UVs       = uvs.ToArray();
            Normals   = normals.ToArray();

            Vertices = _fontMap.FixTextKerning(Vertices, _text, 1);

            var meshWidth       = Vertices[Vertices.Length - 1].x - Vertices[0].x;
            var translateToZero = Vertices[0].x;

            for (var i = 0; i < Vertices.Length; i++)
            {
                var translateVert = new float3(Vertices[i].x - translateToZero - meshWidth / 2, Vertices[i].y - textMeshHeight / 2, Vertices[i].z);
                var scaledVert    = translateVert / meshWidth;
                Vertices[i] = scaledVert;
            }
        }
Example #18
0
        /// <summary>
        ///     Drawing all glyphs and return the drawn visual and char information.
        /// </summary>
        /// <param name="glyphs">The collection of all glyphs.</param>
        /// <returns>The drawn visual list and box information.</returns>
        private (IReadOnlyList <Visual> Visuals, IReadOnlyList <GlyphInfo> BoxInfo) DrawingGlyphs(
            IReadOnlyCollection <GlyphMappingInfo> glyphs)
        {
            DrawingVisual  currentVisual;
            DrawingContext drawingContext;

            var visualList   = new List <Visual>();
            var charInfoList = new List <GlyphInfo>();

            #region Help methods

            void CloseCurrentVisual()
            {
                drawingContext.Close();
                visualList.Add(currentVisual);
            }

            void OpenNewVisual()
            {
                currentVisual  = new DrawingVisual();
                drawingContext = currentVisual.RenderOpen();

                //  Background overlay
                drawingContext.DrawRectangle(Brushes.Black, null, new System.Windows.Rect(0, 0, Setting.TextureSize, Setting.TextureSize));
            }

            #endregion

            double atlasWidth  = Setting.TextureSize;
            double atlasHeight = Setting.TextureSize;

            double space = Setting.GlyphSpace;

            double currentX = space, currentY = space, lineHeight = 0;

            // Log
            Logger.Log(LogLevel.Debug, App.Current.FormatResString("BeginDrawingGlyphs"));

            // Initialize progress
            Logger.AdvanceProgressStage(0, 40);
            Logger.SetProgressLevel(1, App.Current.FormatResString("BeginDrawingGlyphsTitle"), glyphs.Count);

            // Open visual
            OpenNewVisual();

            foreach (var g in glyphs)
            {
                var index = g.Typeface.CharacterToGlyphMap[g.CodePrint];

                // Get alignment data
                var advancedWidth   = g.Typeface.AdvanceWidths[index];
                var leftSideBearing = g.Typeface.LeftSideBearings[index];

                // Calculate real size and baseline
                var emSize   = (Setting.GlyphSize * g.Setting.GlyphSizeRatio);
                var baseline = (emSize * (g.Typeface.Baseline + g.Setting.BaselineOffsetRatio * g.Typeface.Height));

                // Extract geometry and get outline size
                var geometry = g.Typeface.GetGlyphOutline(index, emSize, emSize);

                var totalWidth  = geometry.Bounds.Width;
                var totalHeight = geometry.Bounds.Height;

                // Handle empty (the size will be -inf by default)
                if (geometry.Bounds.IsEmpty)
                {
                    totalWidth  = 0;
                    totalHeight = 0;
                }

                if (totalWidth > atlasWidth || totalHeight > atlasHeight)
                {
                    throw new InvalidOperationException(App.Current.FormatResString("GlyphSizeTooLargeErrorMessage",
                                                                                    (char)g.CodePrint, g.Typeface.FamilyNames[CultureInfo.CurrentUICulture]));
                }

                if (currentX + space + totalWidth <= atlasWidth && currentY + space + totalHeight <= atlasHeight)
                {
                    // Current line, do nothing
                }
                else if (currentY + lineHeight + space + totalHeight <= atlasHeight)
                {
                    // New line
                    currentX   = space;
                    currentY  += lineHeight + space;
                    lineHeight = 0;
                }
                else
                {
                    // new Atlas
                    currentX   = space;
                    currentY   = space;
                    lineHeight = 0;

                    // Close and open visual
                    CloseCurrentVisual();
                    OpenNewVisual();
                }

                // Add char info for metadata
                var charInfo = new GlyphInfo
                {
                    Atlas = visualList.Count,

                    W = (float)totalWidth,
                    H = (float)totalHeight,

                    U = (float)(currentX / atlasWidth),
                    V = (float)(currentY / atlasHeight),

                    S = (float)((currentX + totalWidth) / atlasWidth),
                    T = (float)((currentY + totalHeight) / atlasHeight),

                    X0 = (float)(leftSideBearing * emSize),
                    Y0 = (float)(geometry.Bounds.Top + baseline),

                    HAdvance = (float)(advancedWidth * emSize),

                    CodePrint = (ushort)g.CodePrint
                };

                charInfoList.Add(charInfo);

                // Apply transform and drawing chars

                var transform = new TransformGroup();

                // Move to baseline
                transform.Children.Add(new TranslateTransform(-geometry.Bounds.Left, -geometry.Bounds.Top));
                // Move to start location
                transform.Children.Add(new TranslateTransform(currentX, currentY));

                geometry.Transform = transform;

                // Draw
                drawingContext.DrawGeometry(Brushes.White, new Pen(Brushes.Gray, 1.5)
                {
                }, geometry);

                // Advance the start location
                currentX += totalWidth + space;

                // Update line height if necessary
                if (totalHeight > lineHeight)
                {
                    lineHeight = totalHeight;
                }

                // Advance progress
                Logger.AdvanceCurrentStageProgress(1);
            }

            // Close the final visual
            CloseCurrentVisual();

            Logger.Log(LogLevel.Success,
                       App.Current.FormatResString("DrawingGlyphsFinished", visualList.Count, charInfoList.Count));
            return(visualList, charInfoList);
        }
Example #19
0
    /// <summary>
    /// Print the specified text into the buffers.
    /// </summary>

    static public void Print(string text, BetterList <Vector3> verts, BetterList <Vector2> uvs, BetterList <Color32> cols)
    {
        if (string.IsNullOrEmpty(text))
        {
            return;
        }

        int indexOffset = verts.size;

        Prepare(text);

        // Start with the white tint
        mColors.Add(Color.white);

        int   ch = 0, prev = 0;
        float x = 0f, y = 0f, maxX = 0f;
        float sizeF = finalSize;

        Color   gb         = tint * gradientBottom;
        Color   gt         = tint * gradientTop;
        Color32 uc         = tint;
        int     textLength = text.Length;

        Rect  uvRect = new Rect();
        float invX = 0f, invY = 0f;
        float sizePD = sizeF * pixelDensity;

        // Advanced symbol support contributed by Rudy Pangestu.
        bool        subscript     = false;
        int         subscriptMode = 0;  // 0 = normal, 1 = subscript, 2 = superscript
        bool        bold          = false;
        bool        italic        = false;
        bool        underline     = false;
        bool        strikethrough = false;
        const float sizeShrinkage = 0.75f;

        float v0x;
        float v1x;
        float v1y;
        float v0y;
        float prevX = 0;

        if (bitmapFont != null)
        {
            uvRect = bitmapFont.uvRect;
            invX   = uvRect.width / bitmapFont.texWidth;
            invY   = uvRect.height / bitmapFont.texHeight;
        }

        for (int i = 0; i < textLength; ++i)
        {
            ch = text[i];

            prevX = x;

            if (ch == '\n')
            {
                if (x > maxX)
                {
                    maxX = x;
                }

                if (alignment != TextAlignment.Left)
                {
                    Align(verts, indexOffset, x - finalSpacingX);
                    indexOffset = verts.size;
                }

                x    = 0;
                y   += finalLineHeight;
                prev = 0;
                continue;
            }

            if (ch < ' ')
            {
                prev = ch;
                continue;
            }

            // Color changing symbol
            if (encoding && ParseSymbol(text, ref i, mColors, premultiply, ref subscriptMode, ref bold, ref italic, ref underline, ref strikethrough))
            {
                Color fc = tint * mColors[mColors.size - 1];
                uc = fc;

                if (gradient)
                {
                    gb = gradientBottom * fc;
                    gt = gradientTop * fc;
                }
                --i;
                continue;
            }

            // See if there is a symbol matching this text
            BMSymbol symbol = useSymbols ? GetSymbol(text, i, textLength) : null;

            if (symbol != null)
            {
                v0x = x + symbol.offsetX * fontScale;
                v1x = v0x + symbol.width * fontScale;
                v1y = -(y + symbol.offsetY * fontScale);
                v0y = v1y - symbol.height * fontScale;

                verts.Add(new Vector3(v0x, v0y));
                verts.Add(new Vector3(v0x, v1y));
                verts.Add(new Vector3(v1x, v1y));
                verts.Add(new Vector3(v1x, v0y));

                x   += finalSpacingX + symbol.advance * fontScale;
                i   += symbol.length - 1;
                prev = 0;

                if (uvs != null)
                {
                    Rect uv = symbol.uvRect;

                    float u0x = uv.xMin;
                    float u0y = uv.yMin;
                    float u1x = uv.xMax;
                    float u1y = uv.yMax;

                    uvs.Add(new Vector2(u0x, u0y));
                    uvs.Add(new Vector2(u0x, u1y));
                    uvs.Add(new Vector2(u1x, u1y));
                    uvs.Add(new Vector2(u1x, u0y));
                }

                if (cols != null)
                {
                    if (symbolStyle == SymbolStyle.Colored)
                    {
                        for (int b = 0; b < 4; ++b)
                        {
                            cols.Add(uc);
                        }
                    }
                    else
                    {
                        Color32 col = Color.white;
                        col.a = uc.a;
                        for (int b = 0; b < 4; ++b)
                        {
                            cols.Add(col);
                        }
                    }
                }
            }
            else             // No symbol present
            {
                GlyphInfo glyph = GetGlyph(ch, prev);
                if (glyph == null)
                {
                    continue;
                }
                prev = ch;

                if (ch == ' ')
                {
                    if (underline)
                    {
                        ch = '_';
                    }
                    else if (strikethrough)
                    {
                        ch = '-';
                    }
                    else
                    {
                        x += finalSpacingX + glyph.advance;
                        continue;
                    }
                }

                // Texture coordinates
                if (uvs != null)
                {
                    if (bitmapFont != null)
                    {
                        glyph.u0.x = uvRect.xMin + invX * glyph.u0.x;
                        glyph.u1.x = uvRect.xMin + invX * glyph.u1.x;
                        glyph.u0.y = uvRect.yMax - invY * glyph.u0.y;
                        glyph.u1.y = uvRect.yMax - invY * glyph.u1.y;
                    }

                    for (int j = 0, jmax = (bold ? 4 : 1); j < jmax; ++j)
                    {
                        if (glyph.rotatedUVs)
                        {
                            uvs.Add(glyph.u0);
                            uvs.Add(new Vector2(glyph.u1.x, glyph.u0.y));
                            uvs.Add(glyph.u1);
                            uvs.Add(new Vector2(glyph.u0.x, glyph.u1.y));
                        }
                        else
                        {
                            uvs.Add(glyph.u0);
                            uvs.Add(new Vector2(glyph.u0.x, glyph.u1.y));
                            uvs.Add(glyph.u1);
                            uvs.Add(new Vector2(glyph.u1.x, glyph.u0.y));
                        }
                    }
                }

                // Vertex colors
                if (cols != null)
                {
                    if (glyph.channel == 0 || glyph.channel == 15)
                    {
                        if (gradient)
                        {
                            float min = sizePD + glyph.v0.y;
                            float max = sizePD + glyph.v1.y;

                            min /= sizePD;
                            max /= sizePD;

                            s_c0 = Color.Lerp(gb, gt, min);
                            s_c1 = Color.Lerp(gb, gt, max);

                            for (int j = 0, jmax = (bold ? 4 : 1); j < jmax; ++j)
                            {
                                cols.Add(s_c0);
                                cols.Add(s_c1);
                                cols.Add(s_c1);
                                cols.Add(s_c0);
                            }
                        }
                        else
                        {
                            for (int j = 0, jmax = (bold ? 16 : 4); j < jmax; ++j)
                            {
                                cols.Add(uc);
                            }
                        }
                    }
                    else
                    {
                        // Packed fonts come as alpha masks in each of the RGBA channels.
                        // In order to use it we need to use a special shader.
                        //
                        // Limitations:
                        // - Effects (drop shadow, outline) will not work.
                        // - Should not be a part of the atlas (eastern fonts rarely are anyway).
                        // - Lower color precision

                        Color col = uc;

                        col *= 0.49f;

                        switch (glyph.channel)
                        {
                        case 1: col.b += 0.51f; break;

                        case 2: col.g += 0.51f; break;

                        case 4: col.r += 0.51f; break;

                        case 8: col.a += 0.51f; break;
                        }

                        for (int j = 0, jmax = (bold ? 16 : 4); j < jmax; ++j)
                        {
                            cols.Add(uc);
                        }
                    }
                }

                if (subscriptMode != 0)
                {
                    glyph.v0.x *= sizeShrinkage;
                    glyph.v0.y *= sizeShrinkage;
                    glyph.v1.x *= sizeShrinkage;
                    glyph.v1.y *= sizeShrinkage;

                    if (subscriptMode == 1)
                    {
                        glyph.v0.y -= fontScale * fontSize * 0.4f;
                        glyph.v1.y -= fontScale * fontSize * 0.4f;
                    }
                    else
                    {
                        glyph.v0.y += fontScale * fontSize * 0.05f;
                        glyph.v1.y += fontScale * fontSize * 0.05f;
                    }
                }

                glyph.v0.x += x;
                glyph.v1.x += x;
                glyph.v0.y -= y;
                glyph.v1.y -= y;

                if (subscriptMode == 0)
                {
                    x += finalSpacingX + glyph.advance;
                }
                else
                {
                    x += (finalSpacingX + glyph.advance) * sizeShrinkage;
                }

                v0x = glyph.v0.x;
                v0y = glyph.v0.y;
                v1x = glyph.v1.x;
                v1y = glyph.v1.y;

                // Bold and italic contributed by Rudy Pangestu.
                if (!bold)
                {
                    if (!italic)
                    {
                        verts.Add(new Vector3(v0x, v0y));
                        verts.Add(new Vector3(v0x, v1y));
                        verts.Add(new Vector3(v1x, v1y));
                        verts.Add(new Vector3(v1x, v0y));
                    }
                    else                     // Italic
                    {
                        verts.Add(new Vector3(v0x, v0y));
                        verts.Add(new Vector3(v0x + fontSize * 0.2f, v1y));
                        verts.Add(new Vector3(v1x + fontSize * 0.2f, v1y));
                        verts.Add(new Vector3(v1x, v0y));
                    }
                }
                else                 // Bold
                {
                    for (int j = 0; j < 4; ++j)
                    {
                        float a = mBoldOffset[j * 2];
                        float b = mBoldOffset[j * 2 + 1];

                        verts.Add(new Vector3(v0x + a, v0y + b));
                        verts.Add(new Vector3(v0x + (italic ? fontSize * 0.2f : 0) + a, v1y + b));
                        verts.Add(new Vector3(v1x + (italic ? fontSize * 0.2f : 0) + a, v1y + b));
                        verts.Add(new Vector3(v1x + a, v0y + b));
                    }
                }

                // Underline and strike-through contributed by Rudy Pangestu.
                if (underline || strikethrough)
                {
                    GlyphInfo dash = GetGlyph(strikethrough ? '-' : '_', prev);
                    if (dash == null)
                    {
                        continue;
                    }

                    if (uvs != null)
                    {
                        if (bitmapFont != null)
                        {
                            dash.u0.x = uvRect.xMin + invX * dash.u0.x;
                            dash.u1.x = uvRect.xMin + invX * dash.u1.x;
                            dash.u0.y = uvRect.yMax - invY * dash.u0.y;
                            dash.u1.y = uvRect.yMax - invY * dash.u1.y;
                        }

                        float cx = (dash.u0.x + dash.u1.x) * 0.5f;
                        float cy = (dash.u0.y + dash.u1.y) * 0.5f;

                        uvs.Add(new Vector2(cx, cy));
                        uvs.Add(new Vector2(cx, cy));
                        uvs.Add(new Vector2(cx, cy));
                        uvs.Add(new Vector2(cx, cy));
                    }

                    if (subscript && strikethrough)
                    {
                        v0y = (-y + dash.v0.y) * sizeShrinkage;
                        v1y = (-y + dash.v1.y) * sizeShrinkage;
                    }
                    else
                    {
                        v0y = (-y + dash.v0.y);
                        v1y = (-y + dash.v1.y);
                    }

                    verts.Add(new Vector3(prevX, v0y));
                    verts.Add(new Vector3(prevX, v1y));
                    verts.Add(new Vector3(x, v1y));
                    verts.Add(new Vector3(x, v0y));

                    Color tint2 = uc;

                    if (strikethrough)
                    {
                        tint2.r *= 0.5f;
                        tint2.g *= 0.5f;
                        tint2.b *= 0.5f;
                    }
                    tint2.a *= 0.75f;
                    Color32 uc2 = tint2;

                    cols.Add(uc2);
                    cols.Add(uc);
                    cols.Add(uc);
                    cols.Add(uc2);
                }
            }
        }

        if (alignment != TextAlignment.Left && indexOffset < verts.size)
        {
            Align(verts, indexOffset, x - finalSpacingX);
            indexOffset = verts.size;
        }
        mColors.Clear();
    }
 public void AddGlyph(int ascii, GlyphInfo info)
 {
     glyphs.Add(ascii, info);
 }
    static public bool Print(string text, List <Vector3> verts, List <Vector2> uvs, List <Color> cols, bool show_symbol)
    {
        if (string.IsNullOrEmpty(text))
        {
            return(true);
        }

        int indexOffset = verts.Count;

        Prepare(text);
        if (indexOffset != verts.Count)
        {
            //Prepare->dynamicFont.RequestCharactersInTexture->UILableSymbolCustom.OnFontChange->OnFill->Print 会引起递归重入
            //避免因递归重入弄脏vers,导致lable绘制时出现重影,偏移等问题.
            return(false);
        }
        // Start with the white tint
        mColors.Add(Color.white);
        mAlpha = 1f;

        int   ch = 0, prev = 0;
        float x = 0f, y = 0f, maxX = 0f;
        float sizeF = finalSize;

        Color   gb         = tint * gradientBottom;
        Color   gt         = tint * gradientTop;
        Color32 uc         = tint;
        int     textLength = text.Length;

        //Rect uvRect = new Rect();
        //float invX = 0f, invY = 0f;
        float sizePD = sizeF * pixelDensity;

        // Advanced symbol support contributed by Rudy Pangestu.
        bool        subscript     = false;
        int         subscriptMode = 0; // 0 = normal, 1 = subscript, 2 = superscript
        bool        bold          = false;
        bool        italic        = false;
        bool        underline     = false;
        bool        strikethrough = false;
        bool        ignoreColor   = false;
        const float sizeShrinkage = 0.75f;

        float v0x;
        float v1x;
        float v1y;
        float v0y;
        float prevX = 0;

        //if (bitmapFont != null)
        //{
        //    uvRect = bitmapFont.uvRect;
        //    invX = uvRect.width / bitmapFont.texWidth;
        //    invY = uvRect.height / bitmapFont.texHeight;
        //}

        for (int i = 0; i < textLength; ++i)
        {
            ch = text[i];

            prevX = x;

            // New line character -- skip to the next line
            if (ch == '\n')
            {
                if (x > maxX)
                {
                    maxX = x;
                }

                if (alignment != Alignment.Left)
                {
                    Align(verts, indexOffset, x - finalSpacingX);
                    indexOffset = verts.Count;
                }

                x    = 0;
                y   += finalLineHeight;
                prev = 0;
                continue;
            }

            // Invalid character -- skip it
            if (ch < ' ')
            {
                prev = ch;
                continue;
            }

            // Color changing symbol
            if (encoding && ParseSymbol(text, ref i, mColors, premultiply, ref subscriptMode, ref bold,
                                        ref italic, ref underline, ref strikethrough, ref ignoreColor))
            {
                Color fc;

                if (ignoreColor)
                {
                    fc    = mColors[mColors.size - 1];
                    fc.a *= mAlpha * tint.a;
                }
                else
                {
                    fc    = tint * mColors[mColors.size - 1];
                    fc.a *= mAlpha;
                }
                uc = fc;

                for (int b = 0, bmax = mColors.size - 2; b < bmax; ++b)
                {
                    fc.a *= mColors[b].a;
                }

                if (gradient)
                {
                    gb = gradientBottom * fc;
                    gt = gradientTop * fc;
                }
                --i;
                continue;
            }

            // See if there is a symbol matching this text
            BMSymbol symbol = useSymbols ? GetSymbol(text, i, textLength) : null;

            if (symbol != null)
            {
                v0x = x + symbol.offsetX * symbolFontScale;
                v1x = v0x + symbol.width * symbolFontScale;
                v1y = -(y + symbol.offsetY * symbolFontScale);
                v0y = v1y - symbol.height * symbolFontScale;

                // Doesn't fit? Move down to the next line
                if (Mathf.RoundToInt(x + symbol.advance * symbolFontScale) > regionWidth)
                {
                    if (x == 0f)
                    {
                        return(true);
                    }

                    if (alignment != Alignment.Left && indexOffset < verts.Count)
                    {
                        Align(verts, indexOffset, x - finalSpacingX);
                        indexOffset = verts.Count;
                    }

                    v0x -= x;
                    v1x -= x;
                    v0y -= finalLineHeight;
                    v1y -= finalLineHeight;

                    x     = 0;
                    y    += finalLineHeight;
                    prevX = 0;
                }

                if (show_symbol)
                {
                    verts.Add(new Vector3(v0x, v0y));
                    verts.Add(new Vector3(v0x, v1y));
                    verts.Add(new Vector3(v1x, v1y));
                    verts.Add(new Vector3(v1x, v0y));
                }

                x   += finalSpacingX + symbol.advance * symbolFontScale;
                i   += symbol.length - 1;
                prev = 0;

                if (show_symbol && uvs != null)
                {
                    Rect uv = symbol.uvRect;

                    float u0x = uv.xMin;
                    float u0y = uv.yMin;
                    float u1x = uv.xMax;
                    float u1y = uv.yMax;

                    uvs.Add(new Vector2(u0x, u0y));
                    uvs.Add(new Vector2(u0x, u1y));
                    uvs.Add(new Vector2(u1x, u1y));
                    uvs.Add(new Vector2(u1x, u0y));
                }

                if (show_symbol && cols != null)
                {
                    if (symbolStyle == SymbolStyle.Colored)
                    {
                        for (int b = 0; b < 4; ++b)
                        {
                            cols.Add(uc);
                        }
                    }
                    else
                    {
                        Color32 col = Color.white;
                        col.a = uc.a;
                        for (int b = 0; b < 4; ++b)
                        {
                            cols.Add(col);
                        }
                    }
                }
            }
            else // No symbol present
            {
                GlyphInfo glyph = GetGlyph(ch, prev);
                if (glyph == null)
                {
                    continue;
                }
                prev = ch;

                if (subscriptMode != 0)
                {
                    glyph.v0.x *= sizeShrinkage;
                    glyph.v0.y *= sizeShrinkage;
                    glyph.v1.x *= sizeShrinkage;
                    glyph.v1.y *= sizeShrinkage;

                    if (subscriptMode == 1)
                    {
                        glyph.v0.y -= fontScale * fontSize * 0.4f;
                        glyph.v1.y -= fontScale * fontSize * 0.4f;
                    }
                    else
                    {
                        glyph.v0.y += fontScale * fontSize * 0.05f;
                        glyph.v1.y += fontScale * fontSize * 0.05f;
                    }
                }

                v0x = glyph.v0.x + x;
                v0y = glyph.v0.y - y;
                v1x = glyph.v1.x + x;
                v1y = glyph.v1.y - y;

                float w = glyph.advance;
                if (finalSpacingX < 0f)
                {
                    w += finalSpacingX;
                }

                // Doesn't fit? Move down to the next line
                if (Mathf.RoundToInt(x + w) > regionWidth)
                {
                    if (x == 0f)
                    {
                        return(true);
                    }

                    if (alignment != Alignment.Left && indexOffset < verts.Count)
                    {
                        Align(verts, indexOffset, x - finalSpacingX);
                        indexOffset = verts.Count;
                    }

                    v0x -= x;
                    v1x -= x;
                    v0y -= finalLineHeight;
                    v1y -= finalLineHeight;

                    x     = 0;
                    y    += finalLineHeight;
                    prevX = 0;
                }

                if (IsSpace(ch))
                {
                    if (underline)
                    {
                        ch = '_';
                    }
                    else if (strikethrough)
                    {
                        ch = '-';
                    }
                }

                // Advance the position
                x += (subscriptMode == 0) ? finalSpacingX + glyph.advance :
                     (finalSpacingX + glyph.advance) * sizeShrinkage;

                // No need to continue if this is a space character
                if (IsSpace(ch))
                {
                    continue;
                }

                // Texture coordinates
                if (!show_symbol && uvs != null)
                {
                    //if (bitmapFont != null)
                    //{
                    //    glyph.u0.x = uvRect.xMin + invX * glyph.u0.x;
                    //    glyph.u2.x = uvRect.xMin + invX * glyph.u2.x;
                    //    glyph.u0.y = uvRect.yMax - invY * glyph.u0.y;
                    //    glyph.u2.y = uvRect.yMax - invY * glyph.u2.y;

                    //    glyph.u1.x = glyph.u0.x;
                    //    glyph.u1.y = glyph.u2.y;

                    //    glyph.u3.x = glyph.u2.x;
                    //    glyph.u3.y = glyph.u0.y;
                    //}

                    for (int j = 0, jmax = (bold ? 4 : 1); j < jmax; ++j)
                    {
                        uvs.Add(glyph.u0);
                        uvs.Add(glyph.u1);
                        uvs.Add(glyph.u2);
                        uvs.Add(glyph.u3);
                    }
                }

                // Vertex colors
                if (!show_symbol && cols != null)
                {
                    if (glyph.channel == 0 || glyph.channel == 15)
                    {
                        if (gradient)
                        {
                            float min = sizePD + glyph.v0.y / fontScale;
                            float max = sizePD + glyph.v1.y / fontScale;

                            min /= sizePD;
                            max /= sizePD;

                            s_c0 = Color.Lerp(gb, gt, min);
                            s_c1 = Color.Lerp(gb, gt, max);

                            for (int j = 0, jmax = (bold ? 4 : 1); j < jmax; ++j)
                            {
                                cols.Add(s_c0);
                                cols.Add(s_c1);
                                cols.Add(s_c1);
                                cols.Add(s_c0);
                            }
                        }
                        else
                        {
                            for (int j = 0, jmax = (bold ? 16 : 4); j < jmax; ++j)
                            {
                                cols.Add(uc);
                            }
                        }
                    }
                    else
                    {
                        // Packed fonts come as alpha masks in each of the RGBA channels.
                        // In order to use it we need to use a special shader.
                        //
                        // Limitations:
                        // - Effects (drop shadow, outline) will not work.
                        // - Should not be a part of the atlas (eastern fonts rarely are anyway).
                        // - Lower color precision

                        Color col = uc;

                        col *= 0.49f;

                        switch (glyph.channel)
                        {
                        case 1: col.b += 0.51f; break;

                        case 2: col.g += 0.51f; break;

                        case 4: col.r += 0.51f; break;

                        case 8: col.a += 0.51f; break;
                        }

                        Color32 c = col;
                        for (int j = 0, jmax = (bold ? 16 : 4); j < jmax; ++j)
                        {
                            cols.Add(c);
                        }
                    }
                }

                if (!show_symbol)
                {
                    // Bold and italic contributed by Rudy Pangestu.
                    if (!bold)
                    {
                        if (!italic)
                        {
                            verts.Add(new Vector3(v0x, v0y));
                            verts.Add(new Vector3(v0x, v1y));
                            verts.Add(new Vector3(v1x, v1y));
                            verts.Add(new Vector3(v1x, v0y));
                        }
                        else // Italic
                        {
                            float slant = fontSize * 0.1f * ((v1y - v0y) / fontSize);
                            verts.Add(new Vector3(v0x - slant, v0y));
                            verts.Add(new Vector3(v0x + slant, v1y));
                            verts.Add(new Vector3(v1x + slant, v1y));
                            verts.Add(new Vector3(v1x - slant, v0y));
                        }
                    }
                    else // Bold
                    {
                        for (int j = 0; j < 4; ++j)
                        {
                            float a = mBoldOffset[j * 2];
                            float b = mBoldOffset[j * 2 + 1];

                            float slant = (italic ? fontSize * 0.1f * ((v1y - v0y) / fontSize) : 0f);
                            verts.Add(new Vector3(v0x + a - slant, v0y + b));
                            verts.Add(new Vector3(v0x + a + slant, v1y + b));
                            verts.Add(new Vector3(v1x + a + slant, v1y + b));
                            verts.Add(new Vector3(v1x + a - slant, v0y + b));
                        }
                    }

                    // Underline and strike-through contributed by Rudy Pangestu.
                    if (underline || strikethrough)
                    {
                        GlyphInfo dash = GetGlyph(strikethrough ? '-' : '_', prev);
                        if (dash == null)
                        {
                            continue;
                        }

                        if (uvs != null)
                        {
                            //if (bitmapFont != null)
                            //{
                            //    dash.u0.x = uvRect.xMin + invX * dash.u0.x;
                            //    dash.u2.x = uvRect.xMin + invX * dash.u2.x;
                            //    dash.u0.y = uvRect.yMax - invY * dash.u0.y;
                            //    dash.u2.y = uvRect.yMax - invY * dash.u2.y;
                            //}

                            float cx = (dash.u0.x + dash.u2.x) * 0.5f;

                            for (int j = 0, jmax = (bold ? 4 : 1); j < jmax; ++j)
                            {
                                uvs.Add(new Vector2(cx, dash.u0.y));
                                uvs.Add(new Vector2(cx, dash.u2.y));
                                uvs.Add(new Vector2(cx, dash.u2.y));
                                uvs.Add(new Vector2(cx, dash.u0.y));
                            }
                        }

                        if (subscript && strikethrough)
                        {
                            v0y = (-y + dash.v0.y) * sizeShrinkage;
                            v1y = (-y + dash.v1.y) * sizeShrinkage;
                        }
                        else
                        {
                            v0y = (-y + dash.v0.y);
                            v1y = (-y + dash.v1.y);
                        }

                        if (bold)
                        {
                            for (int j = 0; j < 4; ++j)
                            {
                                float a = mBoldOffset[j * 2];
                                float b = mBoldOffset[j * 2 + 1];

                                verts.Add(new Vector3(prevX + a, v0y + b));
                                verts.Add(new Vector3(prevX + a, v1y + b));
                                verts.Add(new Vector3(x + a, v1y + b));
                                verts.Add(new Vector3(x + a, v0y + b));
                            }
                        }
                        else
                        {
                            verts.Add(new Vector3(prevX, v0y));
                            verts.Add(new Vector3(prevX, v1y));
                            verts.Add(new Vector3(x, v1y));
                            verts.Add(new Vector3(x, v0y));
                        }

                        if (gradient)
                        {
                            float min = sizePD + dash.v0.y / fontScale;
                            float max = sizePD + dash.v1.y / fontScale;

                            min /= sizePD;
                            max /= sizePD;

                            s_c0 = Color.Lerp(gb, gt, min);
                            s_c1 = Color.Lerp(gb, gt, max);

                            for (int j = 0, jmax = (bold ? 4 : 1); j < jmax; ++j)
                            {
                                cols.Add(s_c0);
                                cols.Add(s_c1);
                                cols.Add(s_c1);
                                cols.Add(s_c0);
                            }
                        }
                        else
                        {
                            for (int j = 0, jmax = (bold ? 16 : 4); j < jmax; ++j)
                            {
                                cols.Add(uc);
                            }
                        }
                    }
                }
            }
        }

        if (alignment != Alignment.Left && indexOffset < verts.Count)
        {
            Align(verts, indexOffset, x - finalSpacingX);
            indexOffset = verts.Count;
        }
        mColors.Clear();
        return(true);
    }
Example #22
0
 internal static global::System.Runtime.InteropServices.HandleRef getCPtr(GlyphInfo obj)
 {
     return((obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr);
 }
Example #23
0
        public void Convert(PlaygroundSoft.FontConverter.Glyph[] glyphs)
        {
            DirectoryInfo dirInfo = null;
            try
            {
                dirInfo = new DirectoryInfo(".");
            }
            catch (Exception err)
            {
                MessageBox.Show(err.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            Array.Sort(glyphs, new GlyphComparer());

            Bitmap output = new Bitmap(128, 128);
            Graphics g = Graphics.FromImage(output);
            uint x = 0, y = 0;
            uint maxHeight = 0;
            int fileNo = 0;
            List<GlyphInfo> lstGlyphInfo = new List<GlyphInfo>();

            foreach (Glyph glyph in glyphs)
            {
                if (x + glyph.Width > output.Width)
                {
                    x = 0;
                    y += maxHeight;

                    if (y + maxHeight > output.Height)
                    {
                        y = 0;
                        g.Dispose();

                        SaveImage(output, string.Format(dirInfo.FullName + "\\{0}", fileNo));
                        output.Dispose();
                        fileNo++;
                        output = new Bitmap(128, 128);
                        g = Graphics.FromImage(output);
                    }
                }

                if (x == 0)
                    maxHeight = glyph.Height;

                if (glyph.ImagePath != string.Empty)
                {
                    Bitmap bitmap = new Bitmap(glyph.ImagePath);
                    g.DrawImage(bitmap, x, y);
                    bitmap.Dispose();
                }
                GlyphInfo info = new GlyphInfo();
                info.Glyph = glyph;
                info.X = x;
                info.Y = y;
                info.ImageIndex = fileNo;
                lstGlyphInfo.Add(info);
                x += glyph.Width;
            }

            SaveImage(output, string.Format(dirInfo.FullName + "\\{0}", fileNo));
            g.Dispose();
            output.Dispose();
            UTF8Encoding utf8 = new UTF8Encoding();
            byte[] buffer = new byte[32];
            BinaryWriter writer = new BinaryWriter(new FileStream("output.bmfnt", FileMode.Create));
            writer.Write(utf8.GetBytes("BMFONT"));
            writer.Write(utf8.GetBytes("texture"));
            writer.Write(fileNo + 1);
            for (int i = 0; i < fileNo; i++)
            {
                string filename = string.Format("{0}.dds", i);
                utf8.GetBytes(filename, 0, filename.Length, buffer, 0);
                writer.Write(buffer);
            }
            writer.Write(utf8.GetBytes("characater"));
            writer.Write(glyphs.Count());
            foreach (GlyphInfo glyphInfo in lstGlyphInfo)
            {
                writer.Write(glyphInfo.Glyph.Code);
                writer.Write(glyphInfo.ImageIndex);
                writer.Write(glyphInfo.X);
                writer.Write(glyphInfo.Y);
                writer.Write(glyphInfo.Glyph.Width);
                writer.Write(glyphInfo.Glyph.Height);
                writer.Write(glyphInfo.Glyph.HorizontalAdvance);
                writer.Write(glyphInfo.Glyph.HorizontalBearingX);
                writer.Write(glyphInfo.Glyph.HorizontalBearingY);
            }
            writer.Close();
        }
Example #24
0
File: SymDef.cs Project: jonc/carto
 public void SetGlyphs(GlyphInfo[] glyphs)
 {
     CheckModifiable();
     this.glyphs = glyphs;
 }
Example #25
0
    /// <summary>
    /// Print the specified text into the buffers.
    /// </summary>

    static public void Print(string text, BetterList <Vector3> verts, BetterList <Vector2> uvs, BetterList <Color32> cols)
    {
        if (string.IsNullOrEmpty(text))
        {
            return;
        }

        int   indexOffset = verts.size;
        float lineHeight  = size + spacingY;

        Prepare(text);

        // Start with the white tint
        mColors.Add(Color.white);

        int   ch = 0, prev = 0;
        float x = 0f, y = 0f, maxX = 0f;
        float sizeF = size;

        Color   gb         = tint * gradientBottom;
        Color   gt         = tint * gradientTop;
        Color32 uc         = tint;
        int     textLength = text.Length;

        Rect  uvRect = new Rect();
        float invX = 0f, invY = 0f;

        if (bitmapFont != null)
        {
            uvRect = bitmapFont.uvRect;
            invX   = uvRect.width / bitmapFont.texWidth;
            invY   = uvRect.height / bitmapFont.texHeight;
        }

        for (int i = 0; i < textLength; ++i)
        {
            ch = text[i];

            if (ch == '\n')
            {
                if (x > maxX)
                {
                    maxX = x;
                }

                if (alignment != TextAlignment.Left)
                {
                    Align(verts, indexOffset, x - spacingX);
                    indexOffset = verts.size;
                }

                x    = 0;
                y   += lineHeight;
                prev = 0;
                continue;
            }

            if (ch < ' ')
            {
                prev = ch;
                continue;
            }

            // Color changing symbol
            if (encoding && ParseSymbol(text, ref i, mColors, premultiply))
            {
                Color fc = tint * mColors[mColors.size - 1];
                uc = fc;

                if (gradient)
                {
                    gb = gradientBottom * fc;
                    gt = gradientTop * fc;
                }
                --i;
                continue;
            }

            // See if there is a symbol matching this text
            BMSymbol symbol = useSymbols ? GetSymbol(text, i, textLength) : null;

            if (symbol == null)
            {
                GlyphInfo glyph = GetGlyph(ch, prev);
                if (glyph == null)
                {
                    continue;
                }
                prev = ch;

                if (ch == ' ')
                {
                    x += spacingX + glyph.advance;
                    continue;
                }

                // Texture coordinates
                if (uvs != null)
                {
                    if (bitmapFont != null)
                    {
                        glyph.u0.x = uvRect.xMin + invX * glyph.u0.x;
                        glyph.u1.x = uvRect.xMin + invX * glyph.u1.x;
                        glyph.u0.y = uvRect.yMax - invY * glyph.u0.y;
                        glyph.u1.y = uvRect.yMax - invY * glyph.u1.y;
                    }

                    if (glyph.rotatedUVs)
                    {
                        uvs.Add(glyph.u0);
                        uvs.Add(new Vector2(glyph.u1.x, glyph.u0.y));
                        uvs.Add(glyph.u1);
                        uvs.Add(new Vector2(glyph.u0.x, glyph.u1.y));
                    }
                    else
                    {
                        uvs.Add(glyph.u0);
                        uvs.Add(new Vector2(glyph.u0.x, glyph.u1.y));
                        uvs.Add(glyph.u1);
                        uvs.Add(new Vector2(glyph.u1.x, glyph.u0.y));
                    }
                }

                // Vertex colors
                if (cols != null)
                {
                    if (glyph.channel == 0 || glyph.channel == 15)
                    {
                        if (gradient)
                        {
                            float min = sizeF + glyph.v0.y;
                            float max = sizeF + glyph.v1.y;

                            min /= sizeF;
                            max /= sizeF;

                            s_c0 = Color.Lerp(gb, gt, min);
                            s_c1 = Color.Lerp(gb, gt, max);

                            cols.Add(s_c0);
                            cols.Add(s_c1);
                            cols.Add(s_c1);
                            cols.Add(s_c0);
                        }
                        else
                        {
                            for (int b = 0; b < 4; ++b)
                            {
                                cols.Add(uc);
                            }
                        }
                    }
                    else
                    {
                        // Packed fonts come as alpha masks in each of the RGBA channels.
                        // In order to use it we need to use a special shader.
                        //
                        // Limitations:
                        // - Effects (drop shadow, outline) will not work.
                        // - Should not be a part of the atlas (eastern fonts rarely are anyway).
                        // - Lower color precision

                        Color col = uc;

                        col *= 0.49f;

                        switch (glyph.channel)
                        {
                        case 1: col.b += 0.51f; break;

                        case 2: col.g += 0.51f; break;

                        case 4: col.r += 0.51f; break;

                        case 8: col.a += 0.51f; break;
                        }

                        for (int b = 0; b < 4; ++b)
                        {
                            cols.Add(col);
                        }
                    }
                }

                glyph.v0.x += x;
                glyph.v1.x += x;
                glyph.v0.y -= y;
                glyph.v1.y -= y;

                x += spacingX + glyph.advance;

                verts.Add(glyph.v0);
                verts.Add(new Vector3(glyph.v0.x, glyph.v1.y));
                verts.Add(glyph.v1);
                verts.Add(new Vector3(glyph.v1.x, glyph.v0.y));
            }
            else             // Symbol exists
            {
                float v0x = x + symbol.offsetX;
                float v1x = v0x + symbol.width;
                float v1y = -(y + symbol.offsetY);
                float v0y = v1y - symbol.height;

                verts.Add(new Vector3(v0x, v0y));
                verts.Add(new Vector3(v0x, v1y));
                verts.Add(new Vector3(v1x, v1y));
                verts.Add(new Vector3(v1x, v0y));

                x   += spacingX + symbol.advance;
                i   += symbol.length - 1;
                prev = 0;

                if (uvs != null)
                {
                    Rect uv = symbol.uvRect;

                    float u0x = uv.xMin;
                    float u0y = uv.yMin;
                    float u1x = uv.xMax;
                    float u1y = uv.yMax;

                    uvs.Add(new Vector2(u0x, u0y));
                    uvs.Add(new Vector2(u0x, u1y));
                    uvs.Add(new Vector2(u1x, u1y));
                    uvs.Add(new Vector2(u1x, u0y));
                }

                if (cols != null)
                {
                    if (symbolStyle == SymbolStyle.Colored)
                    {
                        for (int b = 0; b < 4; ++b)
                        {
                            cols.Add(uc);
                        }
                    }
                    else
                    {
                        Color32 col = Color.white;
                        col.a = uc.a;
                        for (int b = 0; b < 4; ++b)
                        {
                            cols.Add(col);
                        }
                    }
                }
            }
        }

        if (alignment != TextAlignment.Left && indexOffset < verts.size)
        {
            Align(verts, indexOffset, x - spacingX);
            indexOffset = verts.size;
        }
        mColors.Clear();
    }
        // Convert from FT_GlyphInfo[] to GlyphInfo[]
        GlyphInfo[] GetGlyphInfo(FT_GlyphInfo[] ft_glyphs, int scaleFactor)
        {
            List<GlyphInfo> glyphs = new List<GlyphInfo>();
            List<int> kerningSet = new List<int>();

            for (int i = 0; i < ft_glyphs.Length; i++)
            {
                GlyphInfo g = new GlyphInfo();

                g.id = ft_glyphs[i].id;
                g.x = ft_glyphs[i].x / scaleFactor;
                g.y = ft_glyphs[i].y / scaleFactor;
                g.width = ft_glyphs[i].width / scaleFactor;
                g.height = ft_glyphs[i].height / scaleFactor;
                g.xOffset = ft_glyphs[i].xOffset / scaleFactor;
                g.yOffset = ft_glyphs[i].yOffset / scaleFactor;
                g.xAdvance = ft_glyphs[i].xAdvance / scaleFactor;

                // Filter out characters with missing glyphs.
                if (g.x == -1)
                    continue;

                glyphs.Add(g);
                kerningSet.Add(g.id);
            }

            m_kerningSet = kerningSet.ToArray();

            return glyphs.ToArray();
        }
Example #27
0
        public void Add(byte[] ttf, float fontPixelHeight,
                        IEnumerable <CharacterRange> characterRanges)
        {
            if (ttf == null || ttf.Length == 0)
            {
                throw new ArgumentNullException(nameof(ttf));
            }

            if (fontPixelHeight <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(fontPixelHeight));
            }

            if (characterRanges == null)
            {
                throw new ArgumentNullException(nameof(characterRanges));
            }

            if (!characterRanges.Any())
                throw new ArgumentException("characterRanges must have a least one value.");

            fixed(byte *ttfPtr = ttf)
            {
                var fontInfo = new StbTrueType.stbtt_fontinfo();

                if (StbTrueType.stbtt_InitFont(fontInfo, ttfPtr, 0) == 0)
                {
                    throw new Exception("Failed to init font.");
                }

                var scaleFactor = StbTrueType.stbtt_ScaleForPixelHeight(fontInfo, fontPixelHeight);

                int ascent, descent, lineGap;

                StbTrueType.stbtt_GetFontVMetrics(fontInfo, &ascent, &descent, &lineGap);

                foreach (var range in characterRanges)
                {
                    if (range.Start > range.End)
                    {
                        continue;
                    }

                    var cd = new StbTrueType.stbtt_packedchar[range.End - range.Start + 1];
                    fixed(StbTrueType.stbtt_packedchar *chardataPtr = cd)
                    {
                        StbTrueType.stbtt_PackFontRange(_context, ttfPtr, 0, fontPixelHeight,
                                                        range.Start,
                                                        range.End - range.Start + 1,
                                                        chardataPtr);
                    }

                    for (var i = 0; i < cd.Length; ++i)
                    {
                        var yOff = cd[i].yoff;
                        yOff += ascent * scaleFactor;

                        var glyphInfo = new GlyphInfo
                        {
                            X        = cd[i].x0,
                            Y        = cd[i].y0,
                            Width    = cd[i].x1 - cd[i].x0,
                            Height   = cd[i].y1 - cd[i].y0,
                            XOffset  = (int)cd[i].xoff,
                            YOffset  = (int)Math.Round(yOff),
                            XAdvance = (int)Math.Round(cd[i].xadvance)
                        };

                        _glyphs[i + range.Start] = glyphInfo;
                    }
                }
            }
        }