/// <summary>
        /// Obtains bounding rectangle.
        /// </summary>
        /// <param name="range"></param>
        /// <param name="min"></param>
        /// <param name="max"></param>
        public void GetBoundingRect(Vector2i range, out Vector2f min, out Vector2f max)
        {
            ValidateRange(range);

            min = new Vector2f(float.PositiveInfinity, float.PositiveInfinity);
            max = new Vector2f(float.NegativeInfinity, float.NegativeInfinity);

            for (int i = range.X; i <= range.Y; i++)
            {
                RenderGlyphInfo info = glyphs[i];
                Vector2f        lb = info.LeftBottom, rt = lb + info.MultiSize;

                if (lb.X < min.X)
                {
                    min.X = lb.X;
                }
                if (lb.Y < min.Y)
                {
                    min.Y = lb.Y;
                }
                if (rt.X > max.X)
                {
                    max.X = rt.X;
                }
                if (rt.Y > max.Y)
                {
                    max.Y = rt.Y;
                }
            }
        }
        /// <summary>
        /// Constructs render info from lines.
        /// </summary>
        /// <param name="lines"></param>
        public TextRenderInfo(ICanvas canvas, Font font,
                              float fontSize, params TextRenderLineInfo[] lines)
        {
            this.lines = lines;

            // We extract glyphs.
            List <RenderGlyphInfo> t = new List <RenderGlyphInfo>();

            for (int i = 0; i < lines.Length; i++)
            {
                TextRenderLineInfo info = lines[i];
                for (uint j = 0; j < info.GlyphCount; j++)
                {
                    RenderGlyphInfo g = info[j];
                    t.Add(info[j]);
                }
            }

            this.glyphs = t.ToArray();

            // May adjust.
            this.fullRange = new Vector2i(0, glyphs.Length - 1);
            this.canvas    = canvas;
            this.font      = font;
            this.fontSize  = fontSize;
        }
        /// <summary>
        /// Translates text render information by vector.
        /// </summary>
        /// <param name="translateVector"></param>
        public void Translate(Vector2f translateVector)
        {
            for (int i = 0; i < glyphs.Length; i++)
            {
                RenderGlyphInfo info = glyphs[i];
                info.Adjust(translateVector);
            }


            // Must adjust line spans.
            for (int i = 0; i < lines.Length; i++)
            {
                lines[i].AdjustSpan(translateVector.X);
            }
        }
        /// <summary>
        /// Render outlined characters.
        /// </summary>
        /// <param name="pen"></param>
        /// <param name="range"></param>
        public void Render(Pen pen, Vector2i range)
        {
            if (range.Y < range.X)
            {
                return;
            }
            ValidateRange(range);

            canvas.Begin(CanvasRenderFlags.SoftwarePositionTransform);
            try
            {
                for (int i = range.X; i <= range.Y; i++)
                {
                    RenderGlyphInfo info = glyphs[i];
                    if (glyphs[i].RenderingData == null)
                    {
                        continue;
                    }

                    // We set transform.
                    canvas.Transform =
                        new LinearTransform(
                            Matrix4x4f.CreateTranslate(info.LeftBottom.Vec3) *
                            Matrix4x4f.CreateScale(new Vector3f(fontSize, fontSize, fontSize))
                            );


                    // We finally render.
                    TriangleSoup2f soup =
                        info.RenderingData.AcquireOutline(canvas.CanvasInfo.TesselationResolution,
                                                          pen.ToOutlineTesselationOptions(canvas.CanvasInfo));
                    canvas.FillShape(pen.Fill, soup, info.AttachedMapper);
                }
            }
            finally
            {
                canvas.End();
            }
        }
Exemple #5
0
        /// <summary>
        /// Prepares text for rendering, with rectange where data should be rendered.
        /// </summary>
        public TextRenderInfo Prepare(ICanvas canvas, string text, float fontSize,
                                      TextOptions options, float lineSpacing, Vector2f leftBottom, Vector2f size)
        {
            // We extract information and convert them.
            bool newLineOrdinary = HasFlag(options, TextOptions.NewLineOrdinary);
            bool groupWords      = HasFlag(options, TextOptions.NotGroupWords);
            bool allowMulti      = HasFlag(options, TextOptions.AllowMulticharacters);

            if (!HasFlag(options, TextOptions.UseCanvasUnits))
            {
                // We use Y dimension, since it is primary axis for text (we want it properly aligned).
                fontSize *= canvas.CanvasInfo.CanvasUnitSize.Y / canvas.CanvasInfo.CanvasPixelSize.Y;
            }
            lineSpacing *= fontSize;

            // We go for each character.
            float lineY = leftBottom.Y + size.Y - fontSize;
            float lineX = leftBottom.X;

            // Return data.
            List <TextRenderLineInfo> lines       = new List <TextRenderLineInfo>();
            TextRenderLineInfo        currentLine = new TextRenderLineInfo(
                new Vector2f(leftBottom.X, leftBottom.X + size.X));

            for (int i = 0; i < text.Length; i++)
            {
                // We first check for out of range.
                if (lineY < leftBottom.Y)
                {
                    break;
                }

                // We select next character.
                int   advIndex = 1;
                Glyph obj      = null;

                // We find next glyph.
                if (text[i] != '\n' || newLineOrdinary)
                {
                    obj = SelectGlyph(text, i, out advIndex, allowMulti);
                }

                // We have it multiplied.
                float adv = obj.Advance;
                adv *= fontSize;

                // We check for line fit.
                if ((!newLineOrdinary && text[i] == '\n') || (lineX + adv >= leftBottom.X + size.X))
                {
                    // We go to new line.
                    lines.Add(currentLine);
                    lineY -= lineSpacing;
                    lineX  = leftBottom.X;
                    if (lineY < leftBottom.Y)
                    {
                        currentLine = null;
                        break;
                    }
                    else
                    {
                        i--;
                        currentLine = new TextRenderLineInfo(
                            new Vector2f(leftBottom.X, leftBottom.X + size.X));
                        continue;
                    }
                }

                // We advance and add it. We must carefully handle multi-char glyphs.
                for (int j = 0; j < advIndex; j++)
                {
                    // We create information.
                    RenderGlyphInfo info2 = new RenderGlyphInfo(
                        text[i + j], j == 0 ? text.Substring(i, advIndex) : string.Empty,
                        new Vector2f(lineX + j * (adv / advIndex), lineY), new Vector2f(adv / advIndex, fontSize),
                        j == 0 ? new Vector2f(adv, fontSize) : Vector2f.Zero, j == 0 ? obj : null, i + j);

                    currentLine.Append(info2);
                }

                // We advance.
                lineX += adv;
            }

            if (currentLine != null)
            {
                lines.Add(currentLine);
            }

            TextRenderInfo info = new TextRenderInfo(canvas, this, fontSize, lines.ToArray());

            // We now post-transform using flags.
            if (HasFlag(options, TextOptions.Top))
            {
                // Already positioned.
            }
            else if (HasFlag(options, TextOptions.Bottom))
            {
                float disp = lines[lines.Count - 1].Bottom - leftBottom.Y;

                info.Translate(new Vector2f(0, -disp));
            }
            else
            {
                // Center positioning.
                float disp = (lines[lines.Count - 1].Bottom - leftBottom.Y) / 2.0f;

                info.Translate(new Vector2f(0, -disp));
            }

            // We also align.
            if (HasFlag(options, TextOptions.Left))
            {
                // Already aligned.
                //info.LeftAlignLines();
            }
            else if (HasFlag(options, TextOptions.Right))
            {
                info.RightAlignLines();
            }
            else
            {
                info.CenterAlignLines();
            }

            return(info);
        }
 /// <summary>
 /// Appends a glyph.
 /// </summary>
 /// <param name="info"></param>
 public void Append(RenderGlyphInfo info)
 {
     glyphs.Add(info);
 }