using System;
using System.Linq;
using Avalonia.Platform;
using SharpDX;
using SharpDX.Direct2D1;
using SharpDX.Mathematics.Interop;
using DWrite = SharpDX.DirectWrite;
namespace Avalonia.Direct2D1
{
internal static class PrimitiveExtensions
{
///
/// The value for which all absolute numbers smaller than are considered equal to zero.
///
public const float ZeroTolerance = 1e-6f; // Value a 8x higher than 1.19209290E-07F
public static readonly RawRectangleF RectangleInfinite;
///
/// Gets the identity matrix.
///
/// The identity matrix.
public readonly static RawMatrix3x2 Matrix3x2Identity = new RawMatrix3x2 { M11 = 1, M12 = 0, M21 = 0, M22 = 1, M31 = 0, M32 = 0 };
static PrimitiveExtensions()
{
RectangleInfinite = new RawRectangleF
{
Left = float.NegativeInfinity,
Top = float.NegativeInfinity,
Right = float.PositiveInfinity,
Bottom = float.PositiveInfinity
};
}
public static Rect ToAvalonia(this RawRectangleF r)
{
return new Rect(new Point(r.Left, r.Top), new Point(r.Right, r.Bottom));
}
public static PixelSize ToAvalonia(this Size2 p) => new PixelSize(p.Width, p.Height);
public static Vector ToAvaloniaVector(this Size2F p) => new Vector(p.Width, p.Height);
public static RawRectangleF ToSharpDX(this Rect r)
{
return new RawRectangleF((float)r.X, (float)r.Y, (float)r.Right, (float)r.Bottom);
}
public static RawVector2 ToSharpDX(this Point p)
{
return new RawVector2 { X = (float)p.X, Y = (float)p.Y };
}
public static Size2F ToSharpDX(this Size p)
{
return new Size2F((float)p.Width, (float)p.Height);
}
public static ExtendMode ToDirect2D(this Avalonia.Media.GradientSpreadMethod spreadMethod)
{
if (spreadMethod == Avalonia.Media.GradientSpreadMethod.Pad)
return ExtendMode.Clamp;
else if (spreadMethod == Avalonia.Media.GradientSpreadMethod.Reflect)
return ExtendMode.Mirror;
else
return ExtendMode.Wrap;
}
public static SharpDX.Direct2D1.LineJoin ToDirect2D(this Avalonia.Media.PenLineJoin lineJoin)
{
if (lineJoin == Avalonia.Media.PenLineJoin.Round)
return LineJoin.Round;
else if (lineJoin == Avalonia.Media.PenLineJoin.Miter)
return LineJoin.Miter;
else
return LineJoin.Bevel;
}
public static SharpDX.Direct2D1.CapStyle ToDirect2D(this Avalonia.Media.PenLineCap lineCap)
{
if (lineCap == Avalonia.Media.PenLineCap.Flat)
return CapStyle.Flat;
else if (lineCap == Avalonia.Media.PenLineCap.Round)
return CapStyle.Round;
else if (lineCap == Avalonia.Media.PenLineCap.Square)
return CapStyle.Square;
else
return CapStyle.Triangle;
}
public static Guid ToWic(this Platform.PixelFormat format, Platform.AlphaFormat alphaFormat)
{
bool isPremul = alphaFormat == AlphaFormat.Premul;
if (format == Platform.PixelFormat.Rgb565)
return SharpDX.WIC.PixelFormat.Format16bppBGR565;
if (format == Platform.PixelFormat.Bgra8888)
return isPremul ? SharpDX.WIC.PixelFormat.Format32bppPBGRA : SharpDX.WIC.PixelFormat.Format32bppBGRA;
if (format == Platform.PixelFormat.Rgba8888)
return isPremul ? SharpDX.WIC.PixelFormat.Format32bppPRGBA : SharpDX.WIC.PixelFormat.Format32bppRGBA;
throw new ArgumentException("Unknown pixel format");
}
///
/// Converts a pen to a Direct2D stroke style.
///
/// The pen to convert.
/// The render target.
/// The Direct2D brush.
public static StrokeStyle ToDirect2DStrokeStyle(this Avalonia.Media.IPen pen, SharpDX.Direct2D1.RenderTarget renderTarget)
{
return pen.ToDirect2DStrokeStyle(Direct2D1Platform.Direct2D1Factory);
}
///
/// Converts a pen to a Direct2D stroke style.
///
/// The pen to convert.
/// The factory associated with this resource.
/// The Direct2D brush.
public static StrokeStyle ToDirect2DStrokeStyle(this Avalonia.Media.IPen pen, Factory factory)
{
var d2dLineCap = pen.LineCap.ToDirect2D();
var properties = new StrokeStyleProperties
{
DashStyle = DashStyle.Solid,
MiterLimit = (float)pen.MiterLimit,
LineJoin = pen.LineJoin.ToDirect2D(),
StartCap = d2dLineCap,
EndCap = d2dLineCap,
DashCap = d2dLineCap
};
float[] dashes = null;
if (pen.DashStyle?.Dashes != null && pen.DashStyle.Dashes.Count > 0)
{
properties.DashStyle = DashStyle.Custom;
properties.DashOffset = (float)pen.DashStyle.Offset;
dashes = pen.DashStyle.Dashes.Select(x => (float)x).ToArray();
}
dashes = dashes ?? Array.Empty();
return new StrokeStyle(factory, properties, dashes);
}
///
/// Converts a Avalonia to Direct2D.
///
/// The color to convert.
/// The Direct2D color.
public static RawColor4 ToDirect2D(this Avalonia.Media.Color color)
{
return new RawColor4(
(float)(color.R / 255.0),
(float)(color.G / 255.0),
(float)(color.B / 255.0),
(float)(color.A / 255.0));
}
///
/// Converts a Avalonia to a Direct2D
///
/// The .
/// The .
public static RawMatrix3x2 ToDirect2D(this Matrix matrix)
{
return new RawMatrix3x2
{
M11 = (float)matrix.M11,
M12 = (float)matrix.M12,
M21 = (float)matrix.M21,
M22 = (float)matrix.M22,
M31 = (float)matrix.M31,
M32 = (float)matrix.M32
};
}
///
/// Converts a Direct2D to a Avalonia .
///
/// The matrix
/// a .
public static Matrix ToAvalonia(this RawMatrix3x2 matrix)
{
return new Matrix(
matrix.M11,
matrix.M12,
matrix.M21,
matrix.M22,
matrix.M31,
matrix.M32);
}
///
/// Converts a Avalonia to a Direct2D
///
/// The .
/// The .
public static RawRectangleF ToDirect2D(this Rect rect)
{
return new RawRectangleF(
(float)rect.X,
(float)rect.Y,
(float)rect.Right,
(float)rect.Bottom);
}
public static DWrite.TextAlignment ToDirect2D(this Avalonia.Media.TextAlignment alignment)
{
switch (alignment)
{
case Avalonia.Media.TextAlignment.Left:
return DWrite.TextAlignment.Leading;
case Avalonia.Media.TextAlignment.Center:
return DWrite.TextAlignment.Center;
case Avalonia.Media.TextAlignment.Right:
return DWrite.TextAlignment.Trailing;
default:
throw new InvalidOperationException("Invalid TextAlignment");
}
}
}
}