예제 #1
0
        /// <summary>
        /// Creates a new rectangle shaped sub-path.
        /// </summary>
        public static void Rect(this Nvg nvg, Rectangle <float> rect)
        {
            InstructionQueue queue = nvg.instructionQueue;

            queue.AddMoveTo(rect.Origin);
            queue.AddLineTo(new(rect.Origin.X, rect.Max.Y));
            queue.AddLineTo(rect.Max);
            queue.AddLineTo(new(rect.Max.X, rect.Origin.Y));
            queue.AddClose();
        }
예제 #2
0
        private Nvg(INvgRenderer renderer)
        {
            this.renderer = renderer;

            instructionQueue = new InstructionQueue(this);
            pathCache        = new PathCache(this);
            stateStack       = new StateStack();
            pixelRatio       = new PixelRatio();

            if (!this.renderer.Create())
            {
                Dispose();
                throw new InvalidOperationException("Failed to initialize the renderer!");
            }

            fontManager = new FontManager(this);
        }
예제 #3
0
        /// <summary>
        /// Creates a new rounded rectangle shaped sub-path with varying radii for each corner.
        /// </summary>
        public static void RoundedRectVarying(this Nvg nvg, Rectangle <float> rect, float radTopLeft, float radTopRight, float radBottomRight, float radBottomLeft)
        {
            if (radTopLeft < 0.1f && radTopRight < 0.1f && radBottomRight < 0.1f && radBottomLeft < 0.1f)
            {
                Rect(nvg, rect);
            }
            else
            {
                InstructionQueue queue = nvg.instructionQueue;

                float            factor = 1 - KAPPA90;
                Vector2D <float> half   = Vector2D.Abs(rect.Size) * 0.5f;
                Vector2D <float> rBL    = new(MathF.Min(radBottomLeft, half.X) * Maths.Sign(rect.Size.X), MathF.Min(radBottomLeft, half.Y) * Maths.Sign(rect.Size.Y));
                Vector2D <float> rBR    = new(MathF.Min(radBottomRight, half.X) * Maths.Sign(rect.Size.X), MathF.Min(radBottomRight, half.Y) * Maths.Sign(rect.Size.Y));
                Vector2D <float> rTR    = new(MathF.Min(radTopRight, half.X) * Maths.Sign(rect.Size.X), MathF.Min(radTopRight, half.Y) * Maths.Sign(rect.Size.Y));
                Vector2D <float> rTL    = new(MathF.Min(radTopLeft, half.X) * Maths.Sign(rect.Size.X), MathF.Min(radTopLeft, half.Y) * Maths.Sign(rect.Size.Y));
                queue.AddMoveTo(new(rect.Origin.X, rect.Origin.Y + rTL.Y));
                queue.AddLineTo(new(rect.Origin.X, rect.Origin.Y + rect.Size.Y - rBL.Y));
                queue.AddBezierTo(
                    new(rect.Origin.X, rect.Origin.Y + rect.Size.Y - rBL.Y * factor),
                    new(rect.Origin.X + rBL.X * factor, rect.Origin.Y + rect.Size.Y),
                    new(rect.Origin.X + rBL.X, rect.Origin.Y + rect.Size.Y)
                    );
                queue.AddLineTo(new(rect.Origin.X + rect.Size.X - rBR.X, rect.Origin.Y + rect.Size.Y));
                queue.AddBezierTo(
                    new(rect.Origin.X + rect.Size.X - rBR.X * factor, rect.Origin.Y + rect.Size.Y),
                    new(rect.Origin.X + rect.Size.X, rect.Origin.Y + rect.Size.Y - rBR.Y * factor),
                    new(rect.Origin.X + rect.Size.X, rect.Origin.Y + rect.Size.Y - rBR.Y)
                    );
                queue.AddLineTo(new(rect.Origin.X + rect.Size.X, rect.Origin.Y + rTR.Y));
                queue.AddBezierTo(
                    new(rect.Origin.X + rect.Size.X, rect.Origin.Y + rTR.Y * factor),
                    new(rect.Origin.X + rect.Size.X - rTR.X * factor, rect.Origin.Y),
                    new(rect.Origin.X + rect.Size.X - rTR.X, rect.Origin.Y)
                    );
                queue.AddLineTo(new(rect.Origin.X + rTL.X, rect.Origin.Y));
                queue.AddBezierTo(
                    new(rect.Origin.X + rTL.X * factor, rect.Origin.Y),
                    new(rect.Origin.X, rect.Origin.Y + rTL.Y * factor),
                    new(rect.Origin.X, rect.Origin.Y + rTL.Y)
                    );
                queue.AddClose();
            }
        }
예제 #4
0
        /// <summary>
        /// Creates a new ellipse shaped sub-path.
        /// </summary>
        public static void Ellipse(this Nvg nvg, Vector2D <float> c, float rx, float ry)
        {
            InstructionQueue queue = nvg.instructionQueue;

            queue.AddMoveTo(new(c.X - rx, c.Y));
            queue.AddBezierTo(
                new(c.X - rx, c.Y + ry * KAPPA90),
                new(c.X - rx * KAPPA90, c.Y + ry),
                new(c.X, c.Y + ry));
            queue.AddBezierTo(
                new(c.X + rx * KAPPA90, c.Y + ry),
                new(c.X + rx, c.Y + ry * KAPPA90),
                new(c.X + rx, c.Y));
            queue.AddBezierTo(
                new(c.X + rx, c.Y - ry * KAPPA90),
                new(c.X + rx * KAPPA90, c.Y - ry),
                new(c.X, c.Y - ry));
            queue.AddBezierTo(
                new(c.X - rx * KAPPA90, c.Y - ry),
                new(c.X - rx, c.Y - ry * KAPPA90),
                new(c.X - rx, c.Y));
            queue.AddClose();
        }
예제 #5
0
        /// <summary>
        /// Creates new circle arc shaped sub-path.
        /// The arc is drawn from angle a0 to a1.
        /// </summary>
        /// <param name="c">The arc center.</param>
        /// <param name="r">The arc radius.</param>
        /// <param name="dir">The direction the arc is swept in.</param>
        public static void Arc(this Nvg nvg, Vector2D <float> c, float r, float a0, float a1, Winding dir)
        {
            Vector2D <float> pPos = default;
            Vector2D <float> pTan = default;

            InstructionQueue queue = nvg.instructionQueue;

            bool line = queue.Count > 0;

            float da = a1 - a0;

            if (dir == Winding.Cw)
            {
                if (MathF.Abs(da) >= MathF.PI * 2.0f)
                {
                    da = MathF.PI * 2.0f;
                }
                else
                {
                    while (da < 0.0f)
                    {
                        da += MathF.PI * 2.0f;
                    }
                }
            }
            else
            {
                if (MathF.Abs(da) >= MathF.PI * 2.0f)
                {
                    da = -MathF.PI * 2.0f;
                }
                else
                {
                    while (da > 0.0f)
                    {
                        da -= MathF.PI * 2.0f;
                    }
                }
            }

            int   ndivs = Math.Max(1, Math.Min((int)(MathF.Abs(da) / (MathF.PI * 0.5f) + 0.5f), 5));
            float hda   = (da / (float)ndivs) / 2.0f;
            float kappa = MathF.Abs(4.0f / 3.0f * (1.0f - MathF.Cos(hda)) / MathF.Sin(hda));

            if (dir == Winding.Ccw)
            {
                kappa *= -1.0f;
            }

            for (int i = 0; i <= ndivs; i++)
            {
                float            alpha = a0 + da * ((float)i / (float)ndivs);
                Vector2D <float> d     = new(MathF.Cos(alpha), MathF.Sin(alpha));
                Vector2D <float> pos   = new(c.X + d.X * r, c.Y + d.Y * r);
                Vector2D <float> tan   = new(-d.Y * r * kappa, d.X *r *kappa);

                if (i == 0)
                {
                    if (line)
                    {
                        queue.AddLineTo(pos);
                    }
                    else
                    {
                        queue.AddMoveTo(pos);
                    }
                }
                else
                {
                    queue.AddBezierTo(pPos + pTan, pos - tan, pos);
                }

                pPos = pos;
                pTan = tan;
            }
        }