private void IterateString(string text, STRVector position, bool draw, float scale, STRColor color, CoordinateType coordinateType, out StringMetrics metrics)
        {
            metrics = new StringMetrics();
            STRVector startPosition = position;
            float     scalY         = coordinateType == SpriteTextRenderer.CoordinateType.SNorm ? -1 : 1;

            string visualText = NBidi.NBidi.LogicalToVisual(text);

            int[] codePoints = Helpers.ConvertToCodePointArray(visualText);

            foreach (int c in codePoints)
            {
                var charDesc    = GetCharDescription(c);
                var charMetrics = charDesc.ToStringMetrics(position, scale, scale * scalY);
                if (draw)
                {
                    if (charMetrics.FullRectSize.X != 0 && charMetrics.FullRectSize.Y != 0)
                    {
                        float posY = position.Y - scalY * charMetrics.OverhangTop;
                        float posX = position.X - charMetrics.OverhangLeft;
                        Sprite.Draw(charDesc.TableDescription.SRV, new STRVector(posX, posY), charMetrics.FullRectSize, STRVector.Zero, 0, charDesc.TexCoordsStart, charDesc.TexCoordsSize, color, coordinateType);
                    }
                }

                metrics.Merge(charMetrics);

                position.X += charMetrics.Size.X;

                //Break newlines
                if (c == '\r')
                {
                    position.X = metrics.TopLeft.X;
                }

                if (c == '\n')
                {
                    position.Y = metrics.BottomRight.Y - charMetrics.Size.Y / 2;
                }
            }
        }
 /// <summary>
 /// Draws the string unscaled in absolute coordinate system aligned in the given rectangle. The text is not clipped or wrapped.
 /// </summary>
 /// <param name="text">Text to draw</param>
 /// <param name="rect">A position in absolute coordinates where the top left corner of the first character will be</param>
 /// <param name="align">Alignment in rectangle</param>
 /// <param name="color">Color in which to draw the text</param>
 /// <returns>The StringMetrics for the rendered text</returns>
 protected internal StringMetrics DrawString(string text, RectangleF rect, TextAlignment align, STRColor color)
 {
     return(DrawString(text, rect, align, FontSize, color, CoordinateType.Absolute));
 }
        private void IterateStringEm(string text, STRVector position, bool Draw, float realFontSize, STRColor color, CoordinateType coordinateType, out StringMetrics metrics)
        {
            float scale = realFontSize / _FontSize;

            IterateString(text, position, Draw, scale, color, coordinateType, out metrics);
        }
        /// <summary>
        /// Draws the string in the specified coordinate system aligned in the given rectangle. The text is not clipped or wrapped.
        /// </summary>
        /// <param name="text">The text to draw</param>
        /// <param name="rect">The rectangle in which to align the text</param>
        /// <param name="align">Alignment of text in rectangle</param>
        /// <param name="realFontSize">The real font size in the chosen coordinate system</param>
        /// <param name="color">The color in which to draw the text</param>
        /// <param name="coordinateType">The chosen coordinate system</param>
        /// <returns>The StringMetrics for the rendered text</returns>
        protected internal StringMetrics DrawString(string text, RectangleF rect, TextAlignment align, float realFontSize, STRColor color, CoordinateType coordinateType)
        {
            //If text is aligned top and left, no adjustment has to be made
            if (align.HasFlag(TextAlignment.Top) && align.HasFlag(TextAlignment.Left))
            {
                return(DrawString(text, new STRVector(rect.X, rect.Y), realFontSize, color, coordinateType));
            }

            text = text.Replace("\r", "");
            var   rawTextMetrics = MeasureString(text, realFontSize, coordinateType);
            var   mMetrics       = MeasureString("m", realFontSize, coordinateType);
            float startY;

            if (align.HasFlag(TextAlignment.Top))
            {
                startY = rect.Top;
            }
            else if (align.HasFlag(TextAlignment.VerticalCenter))
            {
                startY = rect.Top + rect.Height / 2 - rawTextMetrics.Size.Y / 2;
            }
            else //Bottom
            {
                startY = rect.Bottom - rawTextMetrics.Size.Y;
            }

            var totalMetrics = new StringMetrics();

            //break text into lines
            var lines = text.Split('\n');

            foreach (var line in lines)
            {
                float startX;
                if (align.HasFlag(TextAlignment.Left))
                {
                    startX = rect.X;
                }
                else
                {
                    var lineMetrics = MeasureString(line, realFontSize, coordinateType);
                    if (align.HasFlag(TextAlignment.HorizontalCenter))
                    {
                        startX = rect.X + rect.Width / 2 - lineMetrics.Size.X / 2;
                    }
                    else //Right
                    {
                        startX = rect.Right - lineMetrics.Size.X;
                    }
                }

                var   lineMetrics2 = DrawString(line, new STRVector(startX, startY), realFontSize, color, coordinateType);
                float lineHeight;
                if (mMetrics.Size.Y < 0)
                {
                    lineHeight = Math.Min(lineMetrics2.Size.Y, mMetrics.Size.Y);
                }
                else
                {
                    lineHeight = Math.Max(lineMetrics2.Size.Y, mMetrics.Size.Y);
                }
                startY += lineHeight;
                totalMetrics.Merge(lineMetrics2);
            }

            return(totalMetrics);
        }
 /// <summary>
 /// Draws the string untransformed in absolute coordinate system.
 /// </summary>
 /// <param name="text">The text to draw</param>
 /// <param name="position">A position in absolute coordinates where the top left corner of the first character will be</param>
 /// <param name="color">The color in which to draw the text</param>
 /// <returns>The StringMetrics for the rendered text</returns>
 protected internal StringMetrics DrawString(string text, STRVector position, STRColor color)
 {
     return(DrawString(text, position, FontSize, color, CoordinateType.Absolute));
 }
        /// <summary>
        /// Draws the string in the specified coordinate system.
        /// </summary>
        /// <param name="text">The text to draw</param>
        /// <param name="position">A position in the chosen coordinate system where the top left corner of the first character will be</param>
        /// <param name="realFontSize">The real font size in the chosen coordinate system</param>
        /// <param name="color">The color in which to draw the text</param>
        /// <param name="coordinateType">The chosen coordinate system</param>
        /// <returns>The StringMetrics for the rendered text</returns>
        protected internal StringMetrics DrawString(string text, STRVector position, float realFontSize, STRColor color, CoordinateType coordinateType)
        {
            StringMetrics sm;

            IterateStringEm(text, position, true, realFontSize, color, coordinateType, out sm);
            return(sm);
        }
        /// <summary>
        /// Draws a region of a texture on the screen.
        /// </summary>
        /// <param name="texture">The shader resource view of the texture to draw</param>
        /// <param name="position">Position of the center of the texture in the chosen coordinate system</param>
        /// <param name="size">Size of the texture in the chosen coordinate system. The size is specified in the screen's coordinate system.</param>
        /// <param name="center">Specify the texture's center in the chosen coordinate system. The center is specified in the texture's local coordinate system. E.g. for <paramref name="coordinateType"/>=CoordinateType.SNorm, the texture's center is defined by (0, 0).</param>
        /// <param name="rotationAngle">The angle in radians to rotate the texture. Positive values mean counter-clockwise rotation. Rotations can only be applied for relative or absolute coordinates. Consider using the Degrees or Radians helper structs.</param>
        /// <param name="coordinateType">A custom coordinate system in which to draw the texture</param>
        /// <param name="color">The color with which to multiply the texture</param>
        /// <param name="texCoords">Texture coordinates for the top left corner</param>
        /// <param name="texCoordsSize">Size of the region in texture coordinates</param>
        protected internal void Draw(object texture, STRVector position, STRVector size, STRVector center, double rotationAngle, STRVector texCoords, STRVector texCoordsSize, STRColor color, CoordinateType coordinateType)
        {
            if (texture == null)
            {
                return;
            }

            size.X = Math.Abs(size.X);
            size.Y = Math.Abs(size.Y);

            //Difference vectors from the center to the texture edges (in screen coordinates).
            STRVector left, up, right, down;

            if (coordinateType == CoordinateType.UNorm)
            {
                left  = new STRVector(0 - center.X * size.X, 0);
                up    = new STRVector(0, 0 - center.Y * size.Y);
                right = new STRVector((1 - center.X) * size.X, 0);
                down  = new STRVector(0, (1 - center.Y) * size.Y);
            }
            else if (coordinateType == CoordinateType.SNorm)
            {
                left  = new STRVector((-1 - center.X) * size.X / 2, 0);
                up    = new STRVector(0, (1 - center.Y) * size.Y / 2);
                right = new STRVector((1 - center.X) * size.X / 2, 0);
                down  = new STRVector(0, (-1 - center.Y) * size.Y / 2);
            }
            else
            {
                left  = new STRVector(-center.X, 0);
                up    = new STRVector(0, -center.Y);
                right = new STRVector(size.X - center.X, 0);
                down  = new STRVector(0, size.Y - center.Y);
            }

            if (rotationAngle != 0)
            {
                if (coordinateType != CoordinateType.Absolute && coordinateType != CoordinateType.Relative)
                {
                    //Normalized coordinates tend to be skewed when applying rotation
                    throw new ArgumentException("Rotation is only allowed for relative or absolute coordinates", "rotationAngle");
                }
                float sine   = (float)Math.Sin(rotationAngle);
                float cosine = (float)Math.Cos(rotationAngle);
                left  = Rotate(left, sine, cosine);
                right = Rotate(right, sine, cosine);
                up    = Rotate(up, sine, cosine);
                down  = Rotate(down, sine, cosine);
            }

            var data = new SpriteVertexLayout.Struct();

            data.TexCoord     = texCoords;
            data.TexCoordSize = texCoordsSize;
            data.Color        = color.ToArgb();
            data.TopLeft      = ConvertCoordinate(position + up + left, coordinateType);
            data.TopRight     = ConvertCoordinate(position + up + right, coordinateType);
            data.BottomLeft   = ConvertCoordinate(position + down + left, coordinateType);
            data.BottomRight  = ConvertCoordinate(position + down + right, coordinateType);

            if (AllowReorder)
            {
                //Is there already a sprite for this texture?
                if (textureSprites.ContainsKey(texture))
                {
                    //Add the sprite to the last segment for this texture
                    var Segment = textureSprites[texture].Last();
                    AddIn(Segment, data);
                }
                else
                {
                    //Add a new segment for this texture
                    AddNew(texture, data);
                }
            }
            else
            {
                //Add a new segment for this texture
                AddNew(texture, data);
            }
        }
 /// <summary>
 /// Draws a complete texture on the screen.
 /// </summary>
 /// <param name="texture">The shader resource view of the texture to draw</param>
 /// <param name="position">Position of the top left corner of the texture in the chosen coordinate system</param>
 /// <param name="size">Size of the texture in the chosen coordinate system. The size is specified in the screen's coordinate system.</param>
 /// <param name="center">Specify the texture's center in the chosen coordinate system. The center is specified in the texture's local coordinate system. E.g. for <paramref name="coordinateType"/>=CoordinateType.SNorm, the texture's center is defined by (0, 0).</param>
 /// <param name="rotationAngle">The angle in radians to rotate the texture. Positive values mean counter-clockwise rotation. Rotations can only be applied for relative or absolute coordinates. Consider using the Degrees or Radians helper structs.</param>
 /// <param name="coordinateType">A custom coordinate system in which to draw the texture</param>
 /// <param name="color">The color with which to multiply the texture</param>
 protected internal void Draw(object texture, STRVector position, STRVector size, STRVector center, double rotationAngle, STRColor color, CoordinateType coordinateType)
 {
     Draw(texture, position, size, center, rotationAngle, STRVector.Zero, new STRVector(1, 1), color, coordinateType);
 }