More gradient improvements
This commit is contained in:
Родитель
140953b4e8
Коммит
31af9445d5
|
@ -129,6 +129,7 @@ namespace XGraphics.Renderer.Skia
|
|||
|
||||
return skiaPathFigures;
|
||||
}
|
||||
|
||||
private void AddPathSegmentToSkiaPath(SKPath skPath, IPathSegment pathSegment)
|
||||
{
|
||||
if (pathSegment is IBezierSegment bezierSegment)
|
||||
|
@ -136,6 +137,29 @@ namespace XGraphics.Renderer.Skia
|
|||
(float)bezierSegment.Point1.X, (float)bezierSegment.Point1.Y,
|
||||
(float)bezierSegment.Point2.X, (float)bezierSegment.Point2.Y,
|
||||
(float)bezierSegment.Point3.X, (float)bezierSegment.Point3.Y);
|
||||
else if (pathSegment is IPolyBezierSegment polyBezierSegment)
|
||||
{
|
||||
List<Point> points = new List<Point>();
|
||||
foreach (Point point in polyBezierSegment.Points)
|
||||
points.Add(point);
|
||||
|
||||
if (points.Count % 3 != 0)
|
||||
throw new InvalidOperationException($"IPolyBezerSegment contains {points.Count} points, which isn't a multiple of 3");
|
||||
|
||||
for (int i = 0; i < points.Count; )
|
||||
{
|
||||
var point1 = points[i + 0];
|
||||
var point2 = points[i + 1];
|
||||
var point3 = points[i + 2];
|
||||
|
||||
skPath.CubicTo(
|
||||
(float)point1.X, (float)point1.Y,
|
||||
(float)point2.X, (float)point2.Y,
|
||||
(float)point3.X, (float)point3.Y);
|
||||
|
||||
i += 3;
|
||||
}
|
||||
}
|
||||
else if (pathSegment is ILineSegment lineSegment)
|
||||
skPath.LineTo((float) lineSegment.Point.X, (float) lineSegment.Point.Y);
|
||||
else if (pathSegment is IQuadraticBezierSegment quadraticBezierSegment)
|
||||
|
@ -203,7 +227,7 @@ namespace XGraphics.Renderer.Skia
|
|||
if (fill != null && allowFill)
|
||||
{
|
||||
using SKPaint paint = new SKPaint { Style = SKPaintStyle.Fill, IsAntialias = true };
|
||||
InitSkiaPaintForBrush(paint, fill);
|
||||
InitSkiaPaintForBrush(paint, fill, shape);
|
||||
skCanvas.DrawPath(skiaPath, paint);
|
||||
}
|
||||
|
||||
|
@ -211,25 +235,66 @@ namespace XGraphics.Renderer.Skia
|
|||
if (stroke != null)
|
||||
{
|
||||
using SKPaint paint = new SKPaint { Style = SKPaintStyle.Stroke, IsAntialias = true };
|
||||
InitSkiaPaintForBrush(paint, stroke);
|
||||
InitSkiaPaintForBrush(paint, stroke, shape);
|
||||
paint.StrokeWidth = (int)shape.StrokeThickness;
|
||||
|
||||
skCanvas.DrawPath(skiaPath, paint);
|
||||
}
|
||||
}
|
||||
|
||||
public static void InitSkiaPaintForBrush(SKPaint paint, IBrush brush)
|
||||
public static void InitSkiaPaintForBrush(SKPaint paint, IBrush brush, IShape shape)
|
||||
{
|
||||
if (brush is ISolidColorBrush solidColorBrush)
|
||||
paint.Color = ToSkiaColor(solidColorBrush.Color);
|
||||
else if (brush is IGradientBrush gradientBrush)
|
||||
paint.Shader = ToSkiaShader(gradientBrush, shape);
|
||||
else throw new InvalidOperationException($"Brush type {brush.GetType()} isn't currently supported");
|
||||
}
|
||||
|
||||
public static SKColor ToSkiaColor(Color color) =>
|
||||
new SKColor(color.R, color.G, color.B, color.A);
|
||||
public static SKColor ToSkiaColor(Color color) => new SKColor(color.R, color.G, color.B, color.A);
|
||||
|
||||
public static SKPoint ToSkiaPoint(Point point) =>
|
||||
new SKPoint((float) point.X, (float) point.Y);
|
||||
public static SKShader ToSkiaShader(IGradientBrush gradientBrush, IShape shape)
|
||||
{
|
||||
SKShaderTileMode tileMode = gradientBrush.SpreadMethod switch
|
||||
{
|
||||
GradientSpreadMethod.Pad => SKShaderTileMode.Clamp,
|
||||
GradientSpreadMethod.Reflect => SKShaderTileMode.Mirror,
|
||||
GradientSpreadMethod.Repeat => SKShaderTileMode.Repeat,
|
||||
_ => throw new InvalidOperationException($"Unknown GradientSpreadmethod value {gradientBrush.SpreadMethod}")
|
||||
};
|
||||
|
||||
List<SKColor> skiaColors = new List<SKColor>();
|
||||
List<float> skiaColorPositions = new List<float>();
|
||||
foreach (IGradientStop gradientStop in gradientBrush.GradientStops)
|
||||
{
|
||||
skiaColors.Add(ToSkiaColor(gradientStop.Color));
|
||||
skiaColorPositions.Add((float)gradientStop.Offset);
|
||||
}
|
||||
|
||||
if (gradientBrush is ILinearGradientBrush linearGradientBrush)
|
||||
{
|
||||
SKPoint skiaStartPoint = new SKPoint(
|
||||
(float)(shape.Left + linearGradientBrush.StartPoint.X * shape.Width),
|
||||
(float)(shape.Top + linearGradientBrush.StartPoint.Y * shape.Height));
|
||||
SKPoint skiaEndPoint = new SKPoint(
|
||||
(float)(shape.Left + linearGradientBrush.EndPoint.X * shape.Width),
|
||||
(float)(shape.Top + linearGradientBrush.EndPoint.Y * shape.Height));
|
||||
|
||||
return SKShader.CreateLinearGradient(skiaStartPoint, skiaEndPoint, skiaColors.ToArray(), skiaColorPositions.ToArray(), tileMode);
|
||||
}
|
||||
else if (gradientBrush is IRadialGradientBrush radialGradientBrush)
|
||||
{
|
||||
SKPoint skiaCenterPoint = new SKPoint(
|
||||
(float)(shape.Left + radialGradientBrush.Center.X * shape.Width),
|
||||
(float)(shape.Top + radialGradientBrush.Center.Y * shape.Height));
|
||||
|
||||
float radius = (float)(radialGradientBrush.RadiusX * shape.Width);
|
||||
return SKShader.CreateRadialGradient(skiaCenterPoint, radius, skiaColors.ToArray(), skiaColorPositions.ToArray(), tileMode);
|
||||
}
|
||||
else throw new InvalidOperationException($"GradientBrush type {gradientBrush.GetType()} is unknown");
|
||||
}
|
||||
|
||||
public static SKPoint ToSkiaPoint(Point point) => new SKPoint((float) point.X, (float) point.Y);
|
||||
|
||||
public static void AddSkiaPoints(IEnumerable<Point> points, List<SKPoint> skiaPoints)
|
||||
{
|
||||
|
|
|
@ -495,7 +495,7 @@ namespace XGraphics.DataModelGenerator
|
|||
|
||||
private static bool IsEnumType(string typeName)
|
||||
{
|
||||
return typeName == "SweepDirection" || typeName == "FillRule";
|
||||
return typeName == "SweepDirection" || typeName == "FillRule" || typeName == "GradientSpreadMethod";
|
||||
}
|
||||
|
||||
private static bool IsPointType(TypeSyntax type)
|
||||
|
@ -536,7 +536,23 @@ namespace XGraphics.DataModelGenerator
|
|||
if (firstArgument == null)
|
||||
throw new UserViewableException($"Property {modelProperty.Identifier.Text} should have an argument for the [ModelDefaultValue] attribute");
|
||||
|
||||
return firstArgument.Expression;
|
||||
ExpressionSyntax defaultExpression = firstArgument.Expression;
|
||||
if (defaultExpression is LiteralExpressionSyntax literalExpression && literalExpression.Token.IsKind(SyntaxKind.StringLiteralToken))
|
||||
{
|
||||
string literalExpressionString = literalExpression.Token.ToString();
|
||||
if (literalExpressionString == "\"0.5,0.5\"")
|
||||
defaultExpression =
|
||||
MemberAccessExpression(
|
||||
SyntaxKind.SimpleMemberAccessExpression,
|
||||
MemberAccessExpression(
|
||||
SyntaxKind.SimpleMemberAccessExpression,
|
||||
IdentifierName("Wrapper"),
|
||||
IdentifierName("Point")),
|
||||
IdentifierName("CenterDefault"));
|
||||
else throw new UserViewableException($"Unknown string literal based default value: {literalExpressionString}");
|
||||
}
|
||||
|
||||
return defaultExpression;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,12 +6,10 @@ namespace XGraphics.WPF.Brushes
|
|||
{
|
||||
public class RadialGradientBrush : GradientBrush, IRadialGradientBrush
|
||||
{
|
||||
public static readonly DependencyProperty CenterProperty = PropertyUtils.Create(nameof(Center), typeof(Wrapper.Point), typeof(RadialGradientBrush), PropertyUtils.DefaultPoint);
|
||||
public static readonly DependencyProperty GraidentOriginProperty = PropertyUtils.Create(nameof(GraidentOrigin), typeof(Wrapper.Point), typeof(RadialGradientBrush), PropertyUtils.DefaultPoint);
|
||||
public static readonly DependencyProperty CenterProperty = PropertyUtils.Create(nameof(Center), typeof(Wrapper.Point), typeof(RadialGradientBrush), Wrapper.Point.CenterDefault);
|
||||
public static readonly DependencyProperty GraidentOriginProperty = PropertyUtils.Create(nameof(GraidentOrigin), typeof(Wrapper.Point), typeof(RadialGradientBrush), Wrapper.Point.CenterDefault);
|
||||
public static readonly DependencyProperty RadiusXProperty = PropertyUtils.Create(nameof(RadiusX), typeof(double), typeof(RadialGradientBrush), 0.5);
|
||||
public static readonly DependencyProperty RadiusYProperty = PropertyUtils.Create(nameof(RadiusY), typeof(double), typeof(RadialGradientBrush), 0.5);
|
||||
|
||||
// The default value is 0.5, 0.5
|
||||
Point IRadialGradientBrush.Center => Center.WrappedPoint;
|
||||
public Wrapper.Point Center
|
||||
{
|
||||
|
@ -19,7 +17,6 @@ namespace XGraphics.WPF.Brushes
|
|||
set => SetValue(CenterProperty, value);
|
||||
}
|
||||
|
||||
// The default value is 0.5, 0.5
|
||||
Point IRadialGradientBrush.GraidentOrigin => GraidentOrigin.WrappedPoint;
|
||||
public Wrapper.Point GraidentOrigin
|
||||
{
|
||||
|
@ -32,11 +29,5 @@ namespace XGraphics.WPF.Brushes
|
|||
get => (double)GetValue(RadiusXProperty);
|
||||
set => SetValue(RadiusXProperty, value);
|
||||
}
|
||||
|
||||
public double RadiusY
|
||||
{
|
||||
get => (double)GetValue(RadiusYProperty);
|
||||
set => SetValue(RadiusYProperty, value);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,8 +12,7 @@ namespace XGraphics.WPF.Converters
|
|||
return sourceType == typeof(string);
|
||||
}
|
||||
|
||||
public override object ConvertFrom(ITypeDescriptorContext context,
|
||||
CultureInfo culture, object valueObject)
|
||||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object valueObject)
|
||||
{
|
||||
if (!(valueObject is string value))
|
||||
throw new InvalidOperationException($"Cannot convert from type {valueObject.GetType()}");
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using XGraphics.Converters;
|
||||
|
||||
namespace XGraphics.WPF.Converters
|
||||
{
|
||||
public class PointTypeConverter : TypeConverter
|
||||
{
|
||||
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) => sourceType == typeof(string);
|
||||
|
||||
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object valueObject)
|
||||
{
|
||||
if (!(valueObject is string value))
|
||||
throw new InvalidOperationException($"Cannot convert from type {valueObject.GetType()}");
|
||||
|
||||
return new Wrapper.Point(PointConverter.ConvertFromString(value));
|
||||
}
|
||||
|
||||
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) => false;
|
||||
|
||||
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) =>
|
||||
throw new InvalidOperationException($"ConvertTo isn't currently supported");
|
||||
}
|
||||
}
|
|
@ -1,11 +1,15 @@
|
|||
using XGraphicsPoint = XGraphics.Point;
|
||||
using System.ComponentModel;
|
||||
using XGraphics.WPF.Converters;
|
||||
using XGraphicsPoint = XGraphics.Point;
|
||||
|
||||
|
||||
namespace XGraphics.WPF.Wrapper
|
||||
{
|
||||
[TypeConverter(typeof(PointTypeConverter))]
|
||||
public struct Point
|
||||
{
|
||||
public static readonly Point Default = new Point(XGraphicsPoint.Default);
|
||||
public static readonly Point CenterDefault = new Point(XGraphicsPoint.CenterDefault);
|
||||
|
||||
|
||||
public XGraphicsPoint WrappedPoint { get; }
|
||||
|
|
|
@ -5,12 +5,10 @@ namespace XGraphics.XamarinForms.Brushes
|
|||
{
|
||||
public class RadialGradientBrush : GradientBrush, IRadialGradientBrush
|
||||
{
|
||||
public static readonly BindableProperty CenterProperty = PropertyUtils.Create(nameof(Center), typeof(Wrapper.Point), typeof(RadialGradientBrush), PropertyUtils.DefaultPoint);
|
||||
public static readonly BindableProperty GraidentOriginProperty = PropertyUtils.Create(nameof(GraidentOrigin), typeof(Wrapper.Point), typeof(RadialGradientBrush), PropertyUtils.DefaultPoint);
|
||||
public static readonly BindableProperty CenterProperty = PropertyUtils.Create(nameof(Center), typeof(Wrapper.Point), typeof(RadialGradientBrush), Wrapper.Point.CenterDefault);
|
||||
public static readonly BindableProperty GraidentOriginProperty = PropertyUtils.Create(nameof(GraidentOrigin), typeof(Wrapper.Point), typeof(RadialGradientBrush), Wrapper.Point.CenterDefault);
|
||||
public static readonly BindableProperty RadiusXProperty = PropertyUtils.Create(nameof(RadiusX), typeof(double), typeof(RadialGradientBrush), 0.5);
|
||||
public static readonly BindableProperty RadiusYProperty = PropertyUtils.Create(nameof(RadiusY), typeof(double), typeof(RadialGradientBrush), 0.5);
|
||||
|
||||
// The default value is 0.5, 0.5
|
||||
Point IRadialGradientBrush.Center => Center.WrappedPoint;
|
||||
public Wrapper.Point Center
|
||||
{
|
||||
|
@ -18,7 +16,6 @@ namespace XGraphics.XamarinForms.Brushes
|
|||
set => SetValue(CenterProperty, value);
|
||||
}
|
||||
|
||||
// The default value is 0.5, 0.5
|
||||
Point IRadialGradientBrush.GraidentOrigin => GraidentOrigin.WrappedPoint;
|
||||
public Wrapper.Point GraidentOrigin
|
||||
{
|
||||
|
@ -31,11 +28,5 @@ namespace XGraphics.XamarinForms.Brushes
|
|||
get => (double)GetValue(RadiusXProperty);
|
||||
set => SetValue(RadiusXProperty, value);
|
||||
}
|
||||
|
||||
public double RadiusY
|
||||
{
|
||||
get => (double)GetValue(RadiusYProperty);
|
||||
set => SetValue(RadiusYProperty, value);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,16 +3,13 @@
|
|||
[GraphicsModelObject]
|
||||
public interface IRadialGradientBrush : IGradientBrush
|
||||
{
|
||||
// The default value is 0.5, 0.5
|
||||
[ModelDefaultValue("0.5,0.5")]
|
||||
Point Center { get; }
|
||||
|
||||
// The default value is 0.5, 0.5
|
||||
[ModelDefaultValue("0.5,0.5")]
|
||||
Point GraidentOrigin { get; }
|
||||
|
||||
[ModelDefaultValue(0.5)]
|
||||
double RadiusX { get; }
|
||||
|
||||
[ModelDefaultValue(0.5)]
|
||||
double RadiusY { get; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
namespace XGraphics.Converters
|
||||
{
|
||||
public static class PointConverter
|
||||
{
|
||||
public static Point ConvertFromString(string value)
|
||||
{
|
||||
|
||||
if (value != null)
|
||||
{
|
||||
double x, y;
|
||||
string[] xy = value.Split(',');
|
||||
if (xy.Length == 2 && double.TryParse(xy[0], NumberStyles.Number, CultureInfo.InvariantCulture, out x) && double.TryParse(xy[1], NumberStyles.Number, CultureInfo.InvariantCulture, out y))
|
||||
return new Point(x, y);
|
||||
}
|
||||
|
||||
throw new InvalidOperationException(string.Format("Cannot convert \"{0}\" into {1}", value, typeof(Point)));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
public struct Point
|
||||
{
|
||||
public static readonly Point Default = new Point(0, 0);
|
||||
public static readonly Point CenterDefault = new Point(0.5, 0.5);
|
||||
|
||||
|
||||
public Point(double x, double y)
|
||||
|
|
Загрузка…
Ссылка в новой задаче