Browse Source

Use double for compositor types

pull/11768/head
Nikita Tsukanov 3 years ago
parent
commit
700b199602
  1. 10
      samples/ControlCatalog/Pages/CompositionPage.axaml.cs
  2. 16
      samples/ControlCatalog/Pages/GesturePage.cs
  3. 4
      samples/GpuInterop/DrawingSurfaceDemoBase.cs
  4. 7
      samples/Sandbox/MainWindow.axaml
  5. 25
      src/Avalonia.Base/Rendering/Composition/Animations/Interpolators.cs
  6. 6
      src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs
  7. 2
      src/Avalonia.Base/Rendering/Composition/CompositionCustomVisualHandler.cs
  8. 2
      src/Avalonia.Base/Rendering/Composition/CompositionTarget.cs
  9. 59
      src/Avalonia.Base/Rendering/Composition/Expressions/BuiltInExpressionFfi.cs
  10. 43
      src/Avalonia.Base/Rendering/Composition/Expressions/DelegateExpressionFfi.cs
  11. 178
      src/Avalonia.Base/Rendering/Composition/Expressions/ExpressionVariant.cs
  12. 33
      src/Avalonia.Base/Rendering/Composition/MatrixUtils.cs
  13. 7
      src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionContainerVisual.cs
  14. 20
      src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionVisual.cs
  15. 2
      src/Avalonia.Base/Rendering/Composition/Visual.cs
  16. 48
      src/Avalonia.Base/Vector.cs
  17. 145
      src/Avalonia.Base/Vector3D.cs
  18. 15
      src/Avalonia.Base/composition-schema.xml
  19. 36
      src/Avalonia.Controls/PullToRefresh/RefreshVisualizer.cs
  20. 4
      src/Avalonia.OpenGL/Controls/OpenGlControlBase.cs

10
samples/ControlCatalog/Pages/CompositionPage.axaml.cs

@ -144,8 +144,8 @@ public partial class CompositionPage : UserControl
{
if(_solidVisual == null)
return;
_solidVisual.Size = new Vector2((float)v.Bounds.Width / 3, (float)v.Bounds.Height / 3);
_solidVisual.Offset = new Vector3((float)v.Bounds.Width / 3, (float)v.Bounds.Height / 3, 0);
_solidVisual.Size = new (v.Bounds.Width / 3, v.Bounds.Height / 3);
_solidVisual.Offset = new (v.Bounds.Width / 3, v.Bounds.Height / 3, 0);
}
v.AttachedToVisualTree += delegate
{
@ -164,7 +164,7 @@ public partial class CompositionPage : UserControl
animation.Direction = PlaybackDirection.Alternate;
_solidVisual.StartAnimation("Color", animation);
_solidVisual.AnchorPoint = new Vector2(0, 0);
_solidVisual.AnchorPoint = new (0, 0);
var scale = _solidVisual.Compositor.CreateVector3KeyFrameAnimation();
scale.Duration = TimeSpan.FromSeconds(5);
@ -195,8 +195,8 @@ public partial class CompositionPage : UserControl
if (_customVisual == null)
return;
var h = (float)Math.Min(v.Bounds.Height, v.Bounds.Width / 3);
_customVisual.Size = new Vector2((float)v.Bounds.Width, h);
_customVisual.Offset = new Vector3(0, (float)(v.Bounds.Height - h) / 2, 0);
_customVisual.Size = new (v.Bounds.Width, h);
_customVisual.Offset = new (0, (v.Bounds.Height - h) / 2, 0);
}
v.AttachedToVisualTree += delegate
{

16
samples/ControlCatalog/Pages/GesturePage.cs

@ -13,7 +13,7 @@ namespace ControlCatalog.Pages
public class GesturePage : UserControl
{
private bool _isInit;
private float _currentScale;
private double _currentScale;
public GesturePage()
{
@ -53,7 +53,7 @@ namespace ControlCatalog.Pages
if(compositionVisual!= null)
{
_currentScale = 1;
compositionVisual.Scale = new Vector3(1,1,1);
compositionVisual.Scale = new (1,1,1);
compositionVisual.Offset = default;
image.InvalidateMeasure();
}
@ -69,7 +69,7 @@ namespace ControlCatalog.Pages
}
_currentScale = 1;
Vector3 currentOffset = default;
Vector3D currentOffset = default;
CompositionVisual? compositionVisual = null;
@ -133,11 +133,11 @@ namespace ControlCatalog.Pages
if (compositionVisual != null && _currentScale != 1)
{
currentOffset += new Vector3((float)e.Delta.X, (float)e.Delta.Y, 0);
currentOffset += new Vector3D(e.Delta.X, e.Delta.Y, 0);
var currentSize = control.Bounds.Size * _currentScale;
currentOffset = new Vector3((float)MathUtilities.Clamp(currentOffset.X, 0, currentSize.Width - control.Bounds.Width),
currentOffset = new Vector3D(MathUtilities.Clamp(currentOffset.X, 0, currentSize.Width - control.Bounds.Width),
(float)MathUtilities.Clamp(currentOffset.Y, 0, currentSize.Height - control.Bounds.Height),
0);
@ -157,7 +157,7 @@ namespace ControlCatalog.Pages
var ball = control.FindLogicalDescendantOfType<Border>();
Vector3 defaultOffset = default;
Vector3D defaultOffset = default;
CompositionVisual? ballCompositionVisual = null;
@ -181,11 +181,11 @@ namespace ControlCatalog.Pages
control.AddHandler(Gestures.PullGestureEvent, (s, e) =>
{
Vector3 center = new((float)control.Bounds.Center.X, (float)control.Bounds.Center.Y, 0);
Vector3D center = new((float)control.Bounds.Center.X, (float)control.Bounds.Center.Y, 0);
InitComposition(ball!);
if (ballCompositionVisual != null)
{
ballCompositionVisual.Offset = defaultOffset + new System.Numerics.Vector3((float)e.Delta.X * 0.4f, (float)e.Delta.Y * 0.4f, 0) * (inverse ? -1 : 1);
ballCompositionVisual.Offset = defaultOffset + new Vector3D(e.Delta.X * 0.4f, e.Delta.Y * 0.4f, 0) * (inverse ? -1 : 1);
e.Handled = true;
}

4
samples/GpuInterop/DrawingSurfaceDemoBase.cs

@ -48,7 +48,7 @@ public abstract class DrawingSurfaceDemoBase : Control, IGpuDemo
Surface = _compositor.CreateDrawingSurface();
_visual = _compositor.CreateSurfaceVisual();
_visual.Size = new Vector2((float)Bounds.Width, (float)Bounds.Height);
_visual.Size = new (Bounds.Width, Bounds.Height);
_visual.Surface = Surface;
ElementComposition.SetElementChildVisual(this, _visual);
var (res, info) = await DoInitialize(_compositor, Surface);
@ -72,7 +72,7 @@ public abstract class DrawingSurfaceDemoBase : Control, IGpuDemo
if (root == null)
return;
_visual!.Size = new Vector2((float)Bounds.Width, (float)Bounds.Height);
_visual!.Size = new (Bounds.Width, Bounds.Height);
var size = PixelSize.FromSize(Bounds.Size, root.RenderScaling);
RenderFrame(size);
if (SupportsDisco && Disco > 0)

7
samples/Sandbox/MainWindow.axaml

@ -1,4 +1,11 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
x:Class="Sandbox.MainWindow">
<ScrollViewer>
<StackPanel>
<Button Margin="0 100000000000000000 0 0">0</Button>
<Button>1</Button>
</StackPanel>
</ScrollViewer>
</Window>

25
src/Avalonia.Base/Rendering/Composition/Animations/Interpolators.cs

@ -19,6 +19,12 @@ namespace Avalonia.Rendering.Composition.Animations
public static ScalarInterpolator Instance { get; } = new ScalarInterpolator();
}
class DoubleInterpolator : IInterpolator<double>
{
public double Interpolate(double @from, double to, float progress) => @from + (to - @from) * progress;
public static DoubleInterpolator Instance { get; } = new ();
}
class Vector2Interpolator : IInterpolator<Vector2>
{
@ -28,6 +34,15 @@ namespace Avalonia.Rendering.Composition.Animations
public static Vector2Interpolator Instance { get; } = new Vector2Interpolator();
}
class VectorInterpolator : IInterpolator<Vector>
{
public Vector Interpolate(Vector @from, Vector to, float progress)
=> new(DoubleInterpolator.Instance.Interpolate(from.X, to.X, progress),
DoubleInterpolator.Instance.Interpolate(from.Y, to.Y, progress));
public static VectorInterpolator Instance { get; } = new ();
}
class Vector3Interpolator : IInterpolator<Vector3>
{
public Vector3 Interpolate(Vector3 @from, Vector3 to, float progress)
@ -36,6 +51,16 @@ namespace Avalonia.Rendering.Composition.Animations
public static Vector3Interpolator Instance { get; } = new Vector3Interpolator();
}
class Vector3DInterpolator : IInterpolator<Vector3D>
{
public Vector3D Interpolate(Vector3D @from, Vector3D to, float progress)
=> new(DoubleInterpolator.Instance.Interpolate(from.X, to.X, progress),
DoubleInterpolator.Instance.Interpolate(from.Y, to.Y, progress),
DoubleInterpolator.Instance.Interpolate(from.Z, to.Z, progress));
public static Vector3DInterpolator Instance { get; } = new ();
}
class Vector4Interpolator : IInterpolator<Vector4>
{
public Vector4 Interpolate(Vector4 @from, Vector4 to, float progress)

6
src/Avalonia.Base/Rendering/Composition/CompositingRenderer.cs

@ -241,8 +241,8 @@ internal class CompositingRenderer : IRendererWithCompositor, IHitTester
continue;
// TODO: Optimize all of that by moving to the Visual itself, so we won't have to recalculate every time
comp.Offset = new Vector3((float)visual.Bounds.Left, (float)visual.Bounds.Top, 0);
comp.Size = new Vector2((float)visual.Bounds.Width, (float)visual.Bounds.Height);
comp.Offset = new (visual.Bounds.Left, visual.Bounds.Top, 0);
comp.Size = new (visual.Bounds.Width, visual.Bounds.Height);
comp.Visible = visual.IsVisible;
comp.Opacity = (float)visual.Opacity;
comp.ClipToBounds = visual.ClipToBounds;
@ -269,7 +269,7 @@ internal class CompositingRenderer : IRendererWithCompositor, IHitTester
renderTransform *= (-offset) * visual.RenderTransform.Value * (offset);
}
comp.TransformMatrix = MatrixUtils.ToMatrix4x4(renderTransform);
comp.TransformMatrix = renderTransform;
try
{

2
src/Avalonia.Base/Rendering/Composition/CompositionCustomVisualHandler.cs

@ -28,7 +28,7 @@ public abstract class CompositionCustomVisualHandler
_host.Compositor.VerifyAccess();
}
protected Vector2 EffectiveSize
protected Vector EffectiveSize
{
get
{

2
src/Avalonia.Base/Rendering/Composition/CompositionTarget.cs

@ -70,7 +70,7 @@ namespace Avalonia.Rendering.Composition
return false;
}
var m33 = MatrixUtils.ToMatrix(m.Value);
var m33 = m.Value;
return m33.TryInvert(out matrix);
}

59
src/Avalonia.Base/Rendering/Composition/Expressions/BuiltInExpressionFfi.cs

@ -16,6 +16,7 @@ namespace Avalonia.Rendering.Composition.Expressions
private readonly DelegateExpressionFfi _registry;
static float Lerp(float a, float b, float p) => p * (b - a) + a;
static double Lerp(double a, double b, double p) => p * (b - a) + a;
static Matrix3x2 Inverse(Matrix3x2 m)
{
@ -34,6 +35,13 @@ namespace Avalonia.Rendering.Composition.Expressions
var t = MathUtilities.Clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
return t * t * (3.0f - 2.0f * t);
}
static double SmoothStep(double edge0, double edge1, double x)
{
var t = MathUtilities.Clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
return t * t * (3.0f - 2.0f * t);
}
static Vector2 SmoothStep(Vector2 edge0, Vector2 edge1, Vector2 x)
{
@ -43,6 +51,15 @@ namespace Avalonia.Rendering.Composition.Expressions
);
}
static Vector SmoothStep(Vector edge0, Vector edge1, Vector x)
{
return new (
SmoothStep(edge0.X, edge1.X, x.X),
SmoothStep(edge0.Y, edge1.Y, x.Y)
);
}
static Vector3 SmoothStep(Vector3 edge0, Vector3 edge1, Vector3 x)
{
return new Vector3(
@ -52,6 +69,15 @@ namespace Avalonia.Rendering.Composition.Expressions
);
}
static Vector3D SmoothStep(Vector3D edge0, Vector3D edge1, Vector3D x)
{
return new (
SmoothStep(edge0.X, edge1.X, x.X),
SmoothStep(edge0.Y, edge1.Y, x.Y),
SmoothStep(edge0.Z, edge1.Z, x.Z)
);
}
static Vector4 SmoothStep(Vector4 edge0, Vector4 edge1, Vector4 x)
{
@ -69,7 +95,9 @@ namespace Avalonia.Rendering.Composition.Expressions
{
{"Abs", (float f) => Math.Abs(f)},
{"Abs", (Vector2 v) => Vector2.Abs(v)},
{"Abs", (Vector v) => v.Abs()},
{"Abs", (Vector3 v) => Vector3.Abs(v)},
{"Abs", (Vector3D v) => v.Abs()},
{"Abs", (Vector4 v) => Vector4.Abs(v)},
{"ACos", (float f) => (float) Math.Acos(f)},
@ -79,7 +107,9 @@ namespace Avalonia.Rendering.Composition.Expressions
{"Clamp", (float a1, float a2, float a3) => MathUtilities.Clamp(a1, a2, a3)},
{"Clamp", (Vector2 a1, Vector2 a2, Vector2 a3) => Vector2.Clamp(a1, a2, a3)},
{"Clamp", (Vector a1, Vector a2, Vector a3) => Vector.Clamp(a1, a2, a3)},
{"Clamp", (Vector3 a1, Vector3 a2, Vector3 a3) => Vector3.Clamp(a1, a2, a3)},
{"Clamp", (Vector3D a1, Vector3D a2, Vector3D a3) => Vector3D.Clamp(a1, a2, a3)},
{"Clamp", (Vector4 a1, Vector4 a2, Vector4 a3) => Vector4.Clamp(a1, a2, a3)},
{"Concatenate", (Quaternion a1, Quaternion a2) => Quaternion.Concatenate(a1, a2)},
@ -109,11 +139,15 @@ namespace Avalonia.Rendering.Composition.Expressions
},
{"Distance", (Vector2 a1, Vector2 a2) => Vector2.Distance(a1, a2)},
{"Distance", (Vector a1, Vector a2) => Vector.Distance(a1, a2)},
{"Distance", (Vector3 a1, Vector3 a2) => Vector3.Distance(a1, a2)},
{"Distance", (Vector3D a1, Vector3D a2) => Vector3D.Distance(a1, a2)},
{"Distance", (Vector4 a1, Vector4 a2) => Vector4.Distance(a1, a2)},
{"DistanceSquared", (Vector2 a1, Vector2 a2) => Vector2.DistanceSquared(a1, a2)},
{"DistanceSquared", (Vector a1, Vector a2) => Vector.DistanceSquared(a1, a2)},
{"DistanceSquared", (Vector3 a1, Vector3 a2) => Vector3.DistanceSquared(a1, a2)},
{"DistanceSquared", (Vector3D a1, Vector3D a2) => Vector3D.DistanceSquared(a1, a2)},
{"DistanceSquared", (Vector4 a1, Vector4 a2) => Vector4.DistanceSquared(a1, a2)},
{"Floor", (float v) => (float) Math.Floor(v)},
@ -123,18 +157,24 @@ namespace Avalonia.Rendering.Composition.Expressions
{"Length", (Vector2 a1) => a1.Length()},
{"Length", (Vector a1) => a1.Length},
{"Length", (Vector3 a1) => a1.Length()},
{"Length", (Vector3D a1) => a1.Length},
{"Length", (Vector4 a1) => a1.Length()},
{"Length", (Quaternion a1) => a1.Length()},
{"LengthSquared", (Vector2 a1) => a1.LengthSquared()},
{"LengthSquared", (Vector a1) => a1*a1},
{"LengthSquared", (Vector3 a1) => a1.LengthSquared()},
{"LengthSquared", (Vector3D a1) => Vector3D.Dot(a1, a1)},
{"LengthSquared", (Vector4 a1) => a1.LengthSquared()},
{"LengthSquared", (Quaternion a1) => a1.LengthSquared()},
{"Lerp", (float a1, float a2, float a3) => Lerp(a1, a2, a3)},
{"Lerp", (Vector2 a1, Vector2 a2, float a3) => Vector2.Lerp(a1, a2, a3)},
{"Lerp", (Vector a1, Vector a2, float a3) => new Vector(Lerp(a1.X, a2.X, a3), Lerp(a1.Y, a2.Y, a3))},
{"Lerp", (Vector3 a1, Vector3 a2, float a3) => Vector3.Lerp(a1, a2, a3)},
{"Lerp", (Vector3D a1, Vector3D a2, float a3) => new Vector3D(Lerp(a1.X, a2.X, a3), Lerp(a1.Y, a2.Y, a3), Lerp(a1.Z, a2.Z, a3))},
{"Lerp", (Vector4 a1, Vector4 a2, float a3) => Vector4.Lerp(a1, a2, a3)},
@ -173,24 +213,31 @@ namespace Avalonia.Rendering.Composition.Expressions
{"Max", (float a1, float a2) => Math.Max(a1, a2)},
{"Max", (Vector2 a1, Vector2 a2) => Vector2.Max(a1, a2)},
{"Max", (Vector a1, Vector a2) => Vector.Max(a1, a2)},
{"Max", (Vector3 a1, Vector3 a2) => Vector3.Max(a1, a2)},
{"Max", (Vector3D a1, Vector3D a2) => Vector3D.Max(a1, a2)},
{"Max", (Vector4 a1, Vector4 a2) => Vector4.Max(a1, a2)},
{"Min", (float a1, float a2) => Math.Min(a1, a2)},
{"Min", (Vector2 a1, Vector2 a2) => Vector2.Min(a1, a2)},
{"Min", (Vector a1, Vector a2) => Vector.Min(a1, a2)},
{"Min", (Vector3 a1, Vector3 a2) => Vector3.Min(a1, a2)},
{"Min", (Vector3D a1, Vector3D a2) => Vector3D.Min(a1, a2)},
{"Min", (Vector4 a1, Vector4 a2) => Vector4.Min(a1, a2)},
{"Mod", (float a, float b) => a % b},
{"Normalize", (Quaternion a) => Quaternion.Normalize(a)},
{"Normalize", (Vector2 a) => Vector2.Normalize(a)},
{"Normalize", (Vector a) => Vector.Normalize(a)},
{"Normalize", (Vector3 a) => Vector3.Normalize(a)},
{"Normalize", (Vector3D a) => Vector3D.Normalize(a)},
{"Normalize", (Vector4 a) => Vector4.Normalize(a)},
{"Pow", (float a, float b) => (float) Math.Pow(a, b)},
{"Quaternion.CreateFromAxisAngle", (Vector3 a, float b) => Quaternion.CreateFromAxisAngle(a, b)},
{"Quaternion.CreateFromAxisAngle", (Vector3D a, float b) => Quaternion.CreateFromAxisAngle(a.ToVector3(), b)},
{"Quaternion", (float a, float b, float c, float d) => new Quaternion(a, b, c, d)},
{"Round", (float a) => (float) Math.Round(a)},
@ -198,14 +245,18 @@ namespace Avalonia.Rendering.Composition.Expressions
{"Scale", (Matrix3x2 a, float b) => a * b},
{"Scale", (Matrix4x4 a, float b) => a * b},
{"Scale", (Vector2 a, float b) => a * b},
{"Scale", (Vector a, float b) => a * b},
{"Scale", (Vector3 a, float b) => a * b},
{"Scale", (Vector3D a, float b) => Vector3D.Multiply(a, b)},
{"Scale", (Vector4 a, float b) => a * b},
{"Sin", (float a) => (float) Math.Sin(a)},
{"SmoothStep", (float a1, float a2, float a3) => SmoothStep(a1, a2, a3)},
{"SmoothStep", (Vector2 a1, Vector2 a2, Vector2 a3) => SmoothStep(a1, a2, a3)},
{"SmoothStep", (Vector a1, Vector a2, Vector a3) => SmoothStep(a1, a2, a3)},
{"SmoothStep", (Vector3 a1, Vector3 a2, Vector3 a3) => SmoothStep(a1, a2, a3)},
{"SmoothStep", (Vector3D a1, Vector3D a2, Vector3D a3) => SmoothStep(a1, a2, a3)},
{"SmoothStep", (Vector4 a1, Vector4 a2, Vector4 a3) => SmoothStep(a1, a2, a3)},
// I have no idea how to do a spherical interpolation for a scalar value, so we are doing a linear one
@ -222,9 +273,13 @@ namespace Avalonia.Rendering.Composition.Expressions
{"Transform", (Vector2 a, Matrix3x2 b) => Vector2.Transform(a, b)},
{"Transform", (Vector3 a, Matrix4x4 b) => Vector3.Transform(a, b)},
{"Vector2", (float a, float b) => new Vector2(a, b)},
{"Vector3", (float a, float b, float c) => new Vector3(a, b, c)},
{"Vector2", (float a, float b) => new Vector(a, b)},
{"Vector2", (double a, double b) => new Vector(a, b)},
{"Vector3", (float a, float b, float c) => new Vector3D(a, b, c)},
{"Vector3", (double a, double b, double c) => new Vector3D(a, b, c)},
{"Vector3", (Vector2 v2, float z) => new Vector3(v2, z)},
{"Vector3", (Vector v2, float z) => new Vector3D(v2.X, v2.Y, z)},
{"Vector3", (Vector v2, double z) => new Vector3D(v2.X, v2.Y, z)},
{"Vector4", (float a, float b, float c, float d) => new Vector4(a, b, c, d)},
{"Vector4", (Vector2 v2, float z, float w) => new Vector4(v2, z, w)},
{"Vector4", (Vector3 v3, float w) => new Vector4(v3, w)},

43
src/Avalonia.Base/Rendering/Composition/Expressions/DelegateExpressionFfi.cs

@ -49,6 +49,46 @@ namespace Avalonia.Rendering.Composition.Expressions
}
}
return CallWithCast(countGroup, arguments, out result, false);
}
bool CallWithCast(List<FfiRecord> countGroup, IReadOnlyList<ExpressionVariant> arguments, out ExpressionVariant result, bool anyCast)
{
result = default;
foreach (var record in countGroup)
{
var match = true;
for (var c = 0; c < arguments.Count; c++)
{
var parameter = record.Types[c];
var arg = arguments[c].Type;
if (parameter != arg)
{
var canCast = (parameter == VariantType.Double && arg == VariantType.Scalar)
|| (parameter == VariantType.Vector3D && arg == VariantType.Vector3)
|| (parameter == VariantType.Vector && arg == VariantType.Vector2)
|| (anyCast && (
(arg == VariantType.Double && parameter == VariantType.Scalar)
|| (arg == VariantType.Vector3D && parameter == VariantType.Vector3)
|| (arg == VariantType.Vector && parameter == VariantType.Vector2)
));
if (!canCast)
{
match = false;
break;
}
}
}
if (match)
{
result = record.Delegate(arguments);
return true;
}
}
if (anyCast == false)
return CallWithCast(countGroup, arguments, out result, true);
return false;
}
@ -75,8 +115,11 @@ namespace Avalonia.Rendering.Composition.Expressions
{
[typeof(bool)] = VariantType.Boolean,
[typeof(float)] = VariantType.Scalar,
[typeof(double)] = VariantType.Double,
[typeof(Vector2)] = VariantType.Vector2,
[typeof(Vector)] = VariantType.Vector,
[typeof(Vector3)] = VariantType.Vector3,
[typeof(Vector3D)] = VariantType.Vector3D,
[typeof(Vector4)] = VariantType.Vector4,
[typeof(Matrix3x2)] = VariantType.Matrix3x2,
[typeof(Matrix4x4)] = VariantType.Matrix4x4,

178
src/Avalonia.Base/Rendering/Composition/Expressions/ExpressionVariant.cs

@ -17,6 +17,8 @@ namespace Avalonia.Rendering.Composition.Expressions
Vector2,
Vector3,
Vector4,
Vector,
Vector3D,
AvaloniaMatrix,
Matrix3x2,
Matrix4x4,
@ -38,6 +40,8 @@ namespace Avalonia.Rendering.Composition.Expressions
[FieldOffset(4)] public Vector2 Vector2;
[FieldOffset(4)] public Vector3 Vector3;
[FieldOffset(4)] public Vector4 Vector4;
[FieldOffset(4)] public Vector Vector;
[FieldOffset(4)] public Vector3D Vector3D;
[FieldOffset(4)] public Matrix AvaloniaMatrix;
[FieldOffset(4)] public Matrix3x2 Matrix3x2;
[FieldOffset(4)] public Matrix4x4 Matrix4x4;
@ -55,6 +59,15 @@ namespace Avalonia.Rendering.Composition.Expressions
return Vector2.Y;
return default;
}
if (Type == VariantType.Vector)
{
if (ReferenceEquals(property, "X"))
return Vector.X;
if (ReferenceEquals(property, "Y"))
return Vector.Y;
return default;
}
if (Type == VariantType.Vector3)
{
@ -78,6 +91,29 @@ namespace Avalonia.Rendering.Composition.Expressions
return new Vector2(Vector3.Z, Vector3.Y);
return default;
}
if (Type == VariantType.Vector3D)
{
if (ReferenceEquals(property, "X"))
return Vector3D.X;
if (ReferenceEquals(property, "Y"))
return Vector3D.Y;
if (ReferenceEquals(property, "Z"))
return Vector3D.Z;
if(ReferenceEquals(property, "XY"))
return new Vector(Vector3D.X, Vector3D.Y);
if(ReferenceEquals(property, "YX"))
return new Vector(Vector3D.Y, Vector3D.X);
if(ReferenceEquals(property, "XZ"))
return new Vector(Vector3D.X, Vector3D.Z);
if(ReferenceEquals(property, "ZX"))
return new Vector(Vector3D.Z, Vector3D.X);
if(ReferenceEquals(property, "YZ"))
return new Vector(Vector3D.Y, Vector3D.Z);
if(ReferenceEquals(property, "ZY"))
return new Vector(Vector3D.Z, Vector3D.Y);
return default;
}
if (Type == VariantType.Vector4)
{
@ -115,14 +151,20 @@ namespace Avalonia.Rendering.Composition.Expressions
return AvaloniaMatrix.M11;
if (ReferenceEquals(property, "M12"))
return AvaloniaMatrix.M12;
if (ReferenceEquals(property, "M13"))
return AvaloniaMatrix.M13;
if (ReferenceEquals(property, "M21"))
return AvaloniaMatrix.M21;
if (ReferenceEquals(property, "M22"))
return AvaloniaMatrix.M22;
if (ReferenceEquals(property, "M23"))
return AvaloniaMatrix.M23;
if (ReferenceEquals(property, "M31"))
return AvaloniaMatrix.M31;
if (ReferenceEquals(property, "M32"))
return AvaloniaMatrix.M32;
if (ReferenceEquals(property, "M33"))
return AvaloniaMatrix.M33;
return default;
}
@ -220,7 +262,13 @@ namespace Avalonia.Rendering.Composition.Expressions
Type = VariantType.Vector2,
Vector2 = value
};
public static implicit operator ExpressionVariant(Vector value) =>
new ExpressionVariant
{
Type = VariantType.Vector,
Vector = value
};
public static implicit operator ExpressionVariant(Vector3 value) =>
new ExpressionVariant
@ -228,6 +276,13 @@ namespace Avalonia.Rendering.Composition.Expressions
Type = VariantType.Vector3,
Vector3 = value
};
public static implicit operator ExpressionVariant(Vector3D value) =>
new ExpressionVariant
{
Type = VariantType.Vector3D,
Vector3D = value
};
public static implicit operator ExpressionVariant(Vector4 value) =>
@ -285,10 +340,16 @@ namespace Avalonia.Rendering.Composition.Expressions
if (left.Type == VariantType.Vector2)
return left.Vector2 + right.Vector2;
if (left.Type == VariantType.Vector)
return left.Vector + right.Vector;
if (left.Type == VariantType.Vector3)
return left.Vector3 + right.Vector3;
if (left.Type == VariantType.Vector3D)
return Avalonia.Vector3D.Add(left.Vector3D, right.Vector3D);
if (left.Type == VariantType.Vector4)
return left.Vector4 + right.Vector4;
@ -317,10 +378,16 @@ namespace Avalonia.Rendering.Composition.Expressions
if (left.Type == VariantType.Vector2)
return left.Vector2 - right.Vector2;
if (left.Type == VariantType.Vector)
return left.Vector - right.Vector;
if (left.Type == VariantType.Vector3)
return left.Vector3 - right.Vector3;
if (left.Type == VariantType.Vector3D)
return Vector3D.Add(left.Vector3D, -right.Vector3D);
if (left.Type == VariantType.Vector4)
return left.Vector4 - right.Vector4;
@ -347,9 +414,15 @@ namespace Avalonia.Rendering.Composition.Expressions
if (left.Type == VariantType.Vector2)
return -left.Vector2;
if (left.Type == VariantType.Vector)
return -left.Vector;
if (left.Type == VariantType.Vector3)
return -left.Vector3;
if (left.Type == VariantType.Vector3D)
return -left.Vector3D;
if (left.Type == VariantType.Vector4)
return -left.Vector4;
@ -383,14 +456,29 @@ namespace Avalonia.Rendering.Composition.Expressions
if (left.Type == VariantType.Vector2 && right.Type == VariantType.Vector2)
return left.Vector2 * right.Vector2;
if (left.Type == VariantType.Vector && right.Type == VariantType.Vector)
return Vector.Multiply(left.Vector, right.Vector);
if (left.Type == VariantType.Vector2 && right.Type == VariantType.Scalar)
return left.Vector2 * right.Scalar;
if (left.Type == VariantType.Vector && right.Type == VariantType.Scalar)
return left.Vector * right.Scalar;
if (left.Type == VariantType.Vector && right.Type == VariantType.Double)
return left.Vector * right.Double;
if (left.Type == VariantType.Vector3 && right.Type == VariantType.Vector3)
return left.Vector3 * right.Vector3;
if (left.Type == VariantType.Vector3D && right.Type == VariantType.Vector3D)
return Vector3D.Multiply(left.Vector3D, right.Vector3D);
if (left.Type == VariantType.Vector3 && right.Type == VariantType.Scalar)
return left.Vector3 * right.Scalar;
if (left.Type == VariantType.Vector3D && right.Type == VariantType.Scalar)
return Vector3D.Multiply(left.Vector3D, right.Scalar);
if (left.Type == VariantType.Vector4 && right.Type == VariantType.Vector4)
return left.Vector4 * right.Vector4;
@ -436,15 +524,33 @@ namespace Avalonia.Rendering.Composition.Expressions
if (left.Type == VariantType.Vector2 && right.Type == VariantType.Vector2)
return left.Vector2 / right.Vector2;
if (left.Type == VariantType.Vector && right.Type == VariantType.Vector)
return Vector.Divide(left.Vector, right.Vector);
if (left.Type == VariantType.Vector2 && right.Type == VariantType.Scalar)
return left.Vector2 / right.Scalar;
if (left.Type == VariantType.Vector && right.Type == VariantType.Scalar)
return left.Vector / right.Scalar;
if (left.Type == VariantType.Vector && right.Type == VariantType.Double)
return left.Vector / right.Scalar;
if (left.Type == VariantType.Vector3 && right.Type == VariantType.Vector3)
return left.Vector3 / right.Vector3;
if (left.Type == VariantType.Vector3D && right.Type == VariantType.Vector3D)
return Vector3D.Divide(left.Vector3D, right.Vector3D);
if (left.Type == VariantType.Vector3 && right.Type == VariantType.Scalar)
return left.Vector3 / right.Scalar;
if (left.Type == VariantType.Vector3D && right.Type == VariantType.Scalar)
return Avalonia.Vector3D.Divide(left.Vector3D, right.Scalar);
if (left.Type == VariantType.Vector3D && right.Type == VariantType.Double)
return Avalonia.Vector3D.Divide(left.Vector3D, right.Double);
if (left.Type == VariantType.Vector4 && right.Type == VariantType.Vector4)
return left.Vector4 / right.Vector4;
@ -471,9 +577,15 @@ namespace Avalonia.Rendering.Composition.Expressions
if (Type == VariantType.Vector2)
return Vector2 == right.Vector2;
if (Type == VariantType.Vector)
return Vector == right.Vector;
if (Type == VariantType.Vector3)
return Vector3 == right.Vector3;
if (Type == VariantType.Vector3D)
return Vector3D == right.Vector3D;
if (Type == VariantType.Vector4)
return Vector4 == right.Vector4;
@ -571,6 +683,11 @@ namespace Avalonia.Rendering.Composition.Expressions
res = (T) (object) Scalar;
return true;
}
if (Type == VariantType.Double)
{
res = (T)(object)Scalar;
return true;
}
}
if (typeof(T) == typeof(double))
@ -580,6 +697,12 @@ namespace Avalonia.Rendering.Composition.Expressions
res = (T) (object) Double;
return true;
}
if (Type == VariantType.Scalar)
{
res = (T)(object)(float)Double;
return true;
}
}
if (typeof(T) == typeof(Vector2))
@ -589,6 +712,27 @@ namespace Avalonia.Rendering.Composition.Expressions
res = (T) (object) Vector2;
return true;
}
if (Type == VariantType.Vector)
{
res = (T) (object) Vector.ToVector2();
return true;
}
}
if (typeof(T) == typeof(Vector))
{
if (Type == VariantType.Vector)
{
res = (T) (object) Vector;
return true;
}
if (Type == VariantType.Vector2)
{
res = (T)(object)new Vector(Vector2);
return true;
}
}
if (typeof(T) == typeof(Vector3))
@ -598,6 +742,26 @@ namespace Avalonia.Rendering.Composition.Expressions
res = (T) (object) Vector3;
return true;
}
if (Type == VariantType.Vector3D)
{
res = (T) (object) Vector3D.ToVector3();
return true;
}
}
if (typeof(T) == typeof(Vector3D))
{
if (Type == VariantType.Vector3D)
{
res = (T) (object) Vector3D;
return true;
}
if (Type == VariantType.Vector3)
{
res = (T)(object)new Vector3D(Vector3);
return true;
}
}
if (typeof(T) == typeof(Vector4))
@ -668,9 +832,15 @@ namespace Avalonia.Rendering.Composition.Expressions
if (typeof(T) == typeof(Vector2))
return (Vector2) (object) v;
if (typeof(T) == typeof(Vector))
return (Vector) (object) v;
if (typeof(T) == typeof(Vector3))
return (Vector3) (object) v;
if (typeof(T) == typeof(Vector3D))
return (Vector3D) (object) v;
if (typeof(T) == typeof(Vector4))
return (Vector4) (object) v;
@ -709,8 +879,12 @@ namespace Avalonia.Rendering.Composition.Expressions
return Double.ToString(CultureInfo.InvariantCulture);
if (Type == VariantType.Vector2)
return Vector2.ToString();
if (Type == VariantType.Vector)
return Vector.ToString();
if (Type == VariantType.Vector3)
return Vector3.ToString();
if (Type == VariantType.Vector3D)
return Vector3D.ToString();
if (Type == VariantType.Vector4)
return Vector4.ToString();
if (Type == VariantType.Quaternion)

33
src/Avalonia.Base/Rendering/Composition/MatrixUtils.cs

@ -6,41 +6,46 @@ namespace Avalonia.Rendering.Composition
{
static class MatrixUtils
{
public static Matrix4x4 ComputeTransform(Vector2 size, Vector2 anchorPoint, Vector3 centerPoint,
Matrix4x4 transformMatrix, Vector3 scale, float rotationAngle, Quaternion orientation, Vector3 offset)
public static Matrix ComputeTransform(Vector size, Vector anchorPoint, Vector3D centerPoint,
Matrix transformMatrix, Vector3D scale, float rotationAngle, Quaternion orientation, Vector3D offset)
{
// The math here follows the *observed* UWP behavior since there are no docs on how it's supposed to work
var anchor = size * anchorPoint;
var mat = Matrix4x4.CreateTranslation(-anchor.X, -anchor.Y, 0);
var center = new Vector3(centerPoint.X, centerPoint.Y, centerPoint.Z);
var anchor = Vector.Multiply(size, anchorPoint);
var mat = Matrix.CreateTranslation(-anchor.X, -anchor.Y);
var center = new Vector3D(centerPoint.X, centerPoint.Y, centerPoint.Z);
if (!transformMatrix.IsIdentity)
mat = transformMatrix * mat;
if (scale != new Vector3(1, 1, 1))
mat *= Matrix4x4.CreateScale(scale, center);
if (scale != new Vector3D(1, 1, 1))
mat *= ToMatrix(Matrix4x4.CreateScale(scale.ToVector3(), center.ToVector3()));
//TODO: RotationAxis support
if (rotationAngle != 0)
mat *= Matrix4x4.CreateRotationZ(rotationAngle, center);
mat *= ToMatrix(Matrix4x4.CreateRotationZ(rotationAngle, center.ToVector3()));
if (orientation != Quaternion.Identity)
{
if (centerPoint != default)
{
mat *= Matrix4x4.CreateTranslation(-center)
* Matrix4x4.CreateFromQuaternion(orientation)
* Matrix4x4.CreateTranslation(center);
mat *= ToMatrix(Matrix4x4.CreateTranslation(-center.ToVector3())
* Matrix4x4.CreateFromQuaternion(orientation)
* Matrix4x4.CreateTranslation(center.ToVector3()));
}
else
mat *= Matrix4x4.CreateFromQuaternion(orientation);
mat *= ToMatrix(Matrix4x4.CreateFromQuaternion(orientation));
}
if (offset != default)
mat *= Matrix4x4.CreateTranslation(offset);
{
if (offset.Z == 0)
mat *= Matrix.CreateTranslation(offset.X, offset.Y);
else
mat *= ToMatrix(Matrix4x4.CreateTranslation(offset.ToVector3()));
}
return mat;
}

7
src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionContainerVisual.cs

@ -81,10 +81,9 @@ namespace Avalonia.Rendering.Composition.Server
// If we only have translation and scale, just scale the padding
if (CombinedTransformMatrix is
{
M12: 0, M13: 0, M14: 0,
M21: 0, M23: 0, M24: 0,
M31: 0, M32: 0, M34: 0,
M43: 0, M44: 1
M12: 0, M13: 0,
M21: 0, M23: 0,
M31: 0, M32: 0
})
padding = new Thickness(padding.Left * CombinedTransformMatrix.M11,
padding.Top * CombinedTransformMatrix.M22,

20
src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionVisual.cs

@ -51,7 +51,7 @@ namespace Avalonia.Rendering.Composition.Server
canvas.PushClip(AdornedVisual._combinedTransformedClipBounds);
}
var transform = GlobalTransformMatrix;
canvas.PostTransform = MatrixUtils.ToMatrix(transform);
canvas.PostTransform = transform;
canvas.Transform = Matrix.Identity;
if (Effect != null)
@ -71,7 +71,7 @@ namespace Avalonia.Rendering.Composition.Server
RenderCore(canvas, currentTransformedClip);
// Hack to force invalidation of SKMatrix
canvas.PostTransform = MatrixUtils.ToMatrix(transform);
canvas.PostTransform = transform;
canvas.Transform = Matrix.Identity;
if (OpacityMaskBrush != null)
@ -106,8 +106,8 @@ namespace Avalonia.Rendering.Composition.Server
return ref _readback2;
}
public Matrix4x4 CombinedTransformMatrix { get; private set; } = Matrix4x4.Identity;
public Matrix4x4 GlobalTransformMatrix { get; private set; }
public Matrix CombinedTransformMatrix { get; private set; } = Matrix.Identity;
public Matrix GlobalTransformMatrix { get; private set; }
public record struct UpdateResult(Rect? Bounds, bool InvalidatedOld, bool InvalidatedNew)
{
@ -134,12 +134,12 @@ namespace Avalonia.Rendering.Composition.Server
{
CombinedTransformMatrix = MatrixUtils.ComputeTransform(Size, AnchorPoint, CenterPoint,
// HACK: Ignore RenderTransform set by the adorner layer
AdornedVisual != null ? Matrix4x4.Identity : TransformMatrix,
AdornedVisual != null ? Matrix.Identity : TransformMatrix,
Scale, RotationAngle, Orientation, Offset);
_combinedTransformDirty = false;
}
var parentTransform = (AdornedVisual ?? Parent)?.GlobalTransformMatrix ?? Matrix4x4.Identity;
var parentTransform = (AdornedVisual ?? Parent)?.GlobalTransformMatrix ?? Matrix.Identity;
var newTransform = CombinedTransformMatrix * parentTransform;
@ -148,7 +148,7 @@ namespace Avalonia.Rendering.Composition.Server
if (GlobalTransformMatrix != newTransform)
{
_isBackface = Vector3.Transform(
new Vector3(0, 0, float.PositiveInfinity), GlobalTransformMatrix).Z <= 0;
new Vector3(0, 0, float.PositiveInfinity), MatrixUtils.ToMatrix4x4(GlobalTransformMatrix)).Z <= 0;
positionChanged = true;
}
@ -179,14 +179,14 @@ namespace Avalonia.Rendering.Composition.Server
TransformedOwnContentBounds = default;
else
TransformedOwnContentBounds =
ownBounds.TransformToAABB(MatrixUtils.ToMatrix(GlobalTransformMatrix));
ownBounds.TransformToAABB(GlobalTransformMatrix);
}
if (_clipSizeDirty || positionChanged)
{
_transformedClipBounds = ClipToBounds
? new Rect(new Size(Size.X, Size.Y))
.TransformToAABB(MatrixUtils.ToMatrix(GlobalTransformMatrix))
.TransformToAABB(GlobalTransformMatrix)
: null;
_clipSizeDirty = false;
@ -249,7 +249,7 @@ namespace Avalonia.Rendering.Composition.Server
/// </summary>
public struct ReadbackData
{
public Matrix4x4 Matrix;
public Matrix Matrix;
public ulong Revision;
public long TargetId;
public bool Visible;

2
src/Avalonia.Base/Rendering/Composition/Visual.cs

@ -33,7 +33,7 @@ namespace Avalonia.Rendering.Composition
}
}
internal Matrix4x4? TryGetServerGlobalTransform()
internal Matrix? TryGetServerGlobalTransform()
{
if (Root == null)
return null;

48
src/Avalonia.Base/Vector.cs

@ -1,5 +1,6 @@
using System;
using System.Globalization;
using System.Numerics;
#if !BUILDTASK
using Avalonia.Animation.Animators;
#endif
@ -353,5 +354,52 @@ namespace Avalonia
x = this._x;
y = this._y;
}
internal Vector2 ToVector2() => new Vector2((float)X, (float)Y);
internal Vector(Vector2 v) : this(v.X, v.Y)
{
}
/// <summary>
/// Returns a vector whose elements are the absolute values of each of the specified vector's elements.
/// </summary>
/// <returns></returns>
public Vector Abs() => new(Math.Abs(X), Math.Abs(Y));
/// <summary>
/// Restricts a vector between a minimum and a maximum value.
/// </summary>
public static Vector Clamp(Vector value, Vector min, Vector max) =>
Min(Max(value, min), max);
/// <summary>
/// Returns a vector whose elements are the maximum of each of the pairs of elements in two specified vectors
/// </summary>
public static Vector Max(Vector left, Vector right) =>
new(Math.Max(left.X, right.X), Math.Max(left.Y, right.Y));
/// <summary>
/// Returns a vector whose elements are the minimum of each of the pairs of elements in two specified vectors
/// </summary>
public static Vector Min(Vector left, Vector right) =>
new(Math.Min(left.X, right.X), Math.Min(left.Y, right.Y));
/// <summary>
/// Computes the Euclidean distance between the two given points.
/// </summary>
public static double Distance(Vector value1, Vector value2) => Math.Sqrt(DistanceSquared(value1, value2));
/// <summary>
/// Returns the Euclidean distance squared between two specified points
/// </summary>
public static double DistanceSquared(Vector value1, Vector value2)
{
var difference = value1 - value2;
return Dot(difference, difference);
}
public static implicit operator Vector(Vector2 v) => new(v);
}
}

145
src/Avalonia.Base/Vector3D.cs

@ -0,0 +1,145 @@
using System;
using System.Globalization;
using System.Numerics;
using Avalonia.Rendering.Composition.Expressions;
using Avalonia.Utilities;
namespace Avalonia;
public readonly record struct Vector3D(double X, double Y, double Z)
{
/// <summary>
/// Parses a <see cref="Vector"/> string.
/// </summary>
/// <param name="s">The string.</param>
/// <returns>The <see cref="Vector3D"/>.</returns>
public static Vector3D Parse(string s)
{
using (var tokenizer = new StringTokenizer(s, CultureInfo.InvariantCulture, exceptionMessage: "Invalid Vector."))
{
return new Vector3D(
tokenizer.ReadDouble(),
tokenizer.ReadDouble(),
tokenizer.ReadDouble()
);
}
}
internal Vector3 ToVector3() => new Vector3((float)X, (float)Y, (float)Z);
internal Vector3D(Vector3 v) : this(v.X, v.Y, v.Z)
{
}
public static implicit operator Vector3D(Vector3 vector) => new(vector);
/// <summary>
/// Calculates the dot product of two vectors.
/// </summary>
public static double Dot(Vector3D vector1, Vector3D vector2) =>
(vector1.X * vector2.X)
+ (vector1.Y * vector2.Y)
+ (vector1.Z * vector2.Z);
/// <summary>
/// Adds the second to the first vector
/// </summary>
public static Vector3D Add(Vector3D left, Vector3D right) =>
new Vector3D(left.X + right.X, left.Y + right.Y, left.Z + right.Z);
/// <summary>
/// Adds the second to the first vector
/// </summary>
public static Vector3D operator +(Vector3D left, Vector3D right) => Add(left, right);
/// <summary>
/// Subtracts the second from the first vector
/// </summary>
public static Vector3D Substract(Vector3D left, Vector3D right) =>
new Vector3D(left.X - right.X, left.Y - right.Y, left.Z - right.Z);
/// <summary>
/// Subtracts the second from the first vector
/// </summary>
public static Vector3D operator -(Vector3D left, Vector3D right) => Substract(left, right);
/// <summary>
/// Negates the vector
/// </summary>
public static Vector3D operator -(Vector3D v) => new(-v.X, -v.Y, -v.Z);
/// <summary>
/// Multiplies the first vector by the second.
/// </summary>
public static Vector3D Multiply(Vector3D left, Vector3D right) =>
new(left.X * right.X, left.Y * right.Y, left.Z * right.Z);
/// <summary>
/// Multiplies the vector by the given scalar.
/// </summary>
public static Vector3D Multiply(Vector3D left, double right) =>
new(left.X * right, left.Y * right, left.Z * right);
/// <summary>
/// Multiplies the vector by the given scalar.
/// </summary>
public static Vector3D operator *(Vector3D left, double right) => Multiply(left, right);
/// <summary>
/// Divides the first vector by the second.
/// </summary>
public static Vector3D Divide(Vector3D left, Vector3D right) =>
new(left.X / right.X, left.Y / right.Y, left.Z / right.Z);
/// <summary>
/// Divides the vector by the given scalar.
/// </summary>
public static Vector3D Divide(Vector3D left, double right) =>
new(left.X / right, left.Y / right, left.Z / right);
/// <summary>Returns a vector whose elements are the absolute values of each of the specified vector's elements.</summary>
public Vector3D Abs() => new(Math.Abs(X), Math.Abs(Y), Math.Abs(Z));
/// <summary>
/// Restricts a vector between a minimum and a maximum value.
/// </summary>
public static Vector3D Clamp(Vector3D value, Vector3D min, Vector3D max) =>
Min(Max(value, min), max);
/// <summary>
/// Returns a vector whose elements are the maximum of each of the pairs of elements in two specified vectors
/// </summary>
public static Vector3D Max(Vector3D left, Vector3D right) =>
new(Math.Max(left.X, right.X), Math.Max(left.Y, right.Y), Math.Max(left.Z, right.Z));
/// <summary>
/// Returns a vector whose elements are the minimum of each of the pairs of elements in two specified vectors
/// </summary>
public static Vector3D Min(Vector3D left, Vector3D right) =>
new(Math.Min(left.X, right.X), Math.Min(left.Y, right.Y), Math.Min(left.Z, right.Z));
/// <summary>
/// Length of the vector.
/// </summary>
public double Length => Math.Sqrt(Dot(this, this));
/// <summary>
/// Returns a normalized version of this vector.
/// </summary>
public static Vector3D Normalize(Vector3D value) => Divide(value, value.Length);
/// <summary>
/// Computes the squared Euclidean distance between the two given points.
/// </summary>
public static double DistanceSquared(Vector3D value1, Vector3D value2)
{
var difference = Vector3D.Substract(value1, value2);
return Dot(difference, difference);
}
/// <summary>
/// Computes the Euclidean distance between the two given points.
/// </summary>
public static double Distance(Vector3D value1, Vector3D value2) => Math.Sqrt(DistanceSquared(value1, value2));
}

15
src/Avalonia.Base/composition-schema.xml

@ -21,14 +21,14 @@
<Property Name="Clip" Type="Avalonia.Platform.IGeometryImpl?" Internal="true" />
<Property Name="ClipToBounds" Type="bool" Animated="true" DefaultValue="true"/>
<Property Name="Offset" Type="Vector3" Animated="true"/>
<Property Name="Size" Type="Vector2" Animated="true"/>
<Property Name="AnchorPoint" Type="Vector2" Animated="true"/>
<Property Name="CenterPoint" Type="Vector3" Animated="true"/>
<Property Name="Offset" Type="Vector3D" Animated="true"/>
<Property Name="Size" Type="Vector" Animated="true"/>
<Property Name="AnchorPoint" Type="Vector" Animated="true"/>
<Property Name="CenterPoint" Type="Vector3D" Animated="true"/>
<Property Name="RotationAngle" Type="float" Animated="true"/>
<Property Name="Orientation" Type="Quaternion" DefaultValue="Quaternion.Identity" Animated="true"/>
<Property Name="Scale" Type="Vector3" DefaultValue="new Vector3(1, 1, 1)" Animated="true"/>
<Property Name="TransformMatrix" Type="Matrix4x4" DefaultValue="Matrix4x4.Identity" Animated="true"/>
<Property Name="Scale" Type="Vector3D" DefaultValue="new Avalonia.Vector3D(1, 1, 1)" Animated="true"/>
<Property Name="TransformMatrix" Type="Avalonia.Matrix" DefaultValue="Avalonia.Matrix.Identity" Animated="true" Internal="true"/>
<Property Name="AdornedVisual" Type="CompositionVisual?" Internal="true" />
<Property Name="AdornerIsClipped" Type="bool" Internal="true" />
<Property Name="OpacityMaskBrush" Type="Avalonia.Media.IImmutableBrush?" Internal="true" />
@ -57,10 +57,13 @@
<Property Name="Size" Type="Size" />
</Object>
<KeyFrameAnimation Name="Scalar" Type="float"/>
<KeyFrameAnimation Name="Double" Type="double"/>
<KeyFrameAnimation Name="Boolean" Type="bool"/>
<KeyFrameAnimation Name="Color" Type="Avalonia.Media.Color"/>
<KeyFrameAnimation Type="Vector"/>
<KeyFrameAnimation Type="Vector2"/>
<KeyFrameAnimation Type="Vector3"/>
<KeyFrameAnimation Type="Vector3D"/>
<KeyFrameAnimation Type="Vector4"/>
<KeyFrameAnimation Type="Quaternion"/>
<Object Name="CompositionSimpleTransform" Internal="true" ServerOnly="true" ServerBase="SimpleServerRenderResource">

36
src/Avalonia.Controls/PullToRefresh/RefreshVisualizer.cs

@ -223,7 +223,7 @@ namespace Avalonia.Controls
var visualizerVisual = ElementComposition.GetElementVisual(this);
if (visual != null && contentVisual != null && visualizerVisual != null)
{
contentVisual.CenterPoint = new Vector3((float)(_content.Bounds.Width / 2), (float)(_content.Bounds.Height / 2), 0);
contentVisual.CenterPoint = new Vector3D((_content.Bounds.Width / 2), (_content.Bounds.Height / 2), 0);
switch (RefreshVisualizerState)
{
case RefreshVisualizerState.Idle:
@ -236,43 +236,43 @@ namespace Avalonia.Controls
contentVisual.Opacity = MinimumIndicatorOpacity;
contentVisual.RotationAngle = _startingRotationAngle;
visualizerVisual.Offset = IsPullDirectionVertical ?
new Vector3(visualizerVisual.Offset.X, 0, 0) :
new Vector3(0, visualizerVisual.Offset.Y, 0);
new Vector3D(visualizerVisual.Offset.X, 0, 0) :
new Vector3D(0, visualizerVisual.Offset.Y, 0);
_content.InvalidateMeasure();
break;
case RefreshVisualizerState.Interacting:
_played = false;
contentVisual.Opacity = MinimumIndicatorOpacity;
contentVisual.RotationAngle = (float)(_startingRotationAngle + _interactionRatio * 2 * Math.PI);
Vector3 offset = default;
Vector3D offset = default;
if (IsPullDirectionVertical)
{
offset = new Vector3(0, (float)(_interactionRatio * (IsPullDirectionFar ? -1 : 1) * root.Bounds.Height), 0);
offset = new Vector3D(0, (_interactionRatio * (IsPullDirectionFar ? -1 : 1) * root.Bounds.Height), 0);
}
else
{
offset = new Vector3((float)(_interactionRatio * (IsPullDirectionFar ? -1 : 1) * root.Bounds.Width), 0, 0);
offset = new Vector3D((_interactionRatio * (IsPullDirectionFar ? -1 : 1) * root.Bounds.Width), 0, 0);
}
visual.Offset = offset;
visualizerVisual.Offset = IsPullDirectionVertical ?
new Vector3(visualizerVisual.Offset.X, offset.Y, 0) :
new Vector3(offset.X, visualizerVisual.Offset.Y, 0);
new Vector3D(visualizerVisual.Offset.X, offset.Y, 0) :
new Vector3D(offset.X, visualizerVisual.Offset.Y, 0);
break;
case RefreshVisualizerState.Pending:
contentVisual.Opacity = 1;
contentVisual.RotationAngle = _startingRotationAngle + (float)(2 * Math.PI);
if (IsPullDirectionVertical)
{
offset = new Vector3(0, (float)(_interactionRatio * (IsPullDirectionFar ? -1 : 1) * root.Bounds.Height), 0);
offset = new Vector3D(0, (float)(_interactionRatio * (IsPullDirectionFar ? -1 : 1) * root.Bounds.Height), 0);
}
else
{
offset = new Vector3((float)(_interactionRatio * (IsPullDirectionFar ? -1 : 1) * root.Bounds.Width), 0, 0);
offset = new Vector3D((float)(_interactionRatio * (IsPullDirectionFar ? -1 : 1) * root.Bounds.Width), 0, 0);
}
visual.Offset = offset;
visualizerVisual.Offset = IsPullDirectionVertical ?
new Vector3(visualizerVisual.Offset.X, offset.Y, 0) :
new Vector3(offset.X, visualizerVisual.Offset.Y, 0);
new Vector3D(visualizerVisual.Offset.X, offset.Y, 0) :
new Vector3D(offset.X, visualizerVisual.Offset.Y, 0);
if (!_played)
{
@ -301,18 +301,18 @@ namespace Avalonia.Controls
* (IsPullDirectionFar ? -1f : 1f);
if (IsPullDirectionVertical)
{
offset = new Vector3(0, (float)(_executingRatio * (IsPullDirectionFar ? -1 : 1) * root.Bounds.Height), 0);
offset = new Vector3D(0, (_executingRatio * (IsPullDirectionFar ? -1 : 1) * root.Bounds.Height), 0);
}
else
{
offset = new Vector3((float)(_executingRatio * (IsPullDirectionFar ? -1 : 1) * root.Bounds.Width), 0, 0);
offset = new Vector3D((_executingRatio * (IsPullDirectionFar ? -1 : 1) * root.Bounds.Width), 0, 0);
}
visual.Offset = offset;
contentVisual.Offset += IsPullDirectionVertical ? new Vector3(0, (float)(translationRatio * root.Bounds.Height), 0) :
new Vector3((float)(translationRatio * root.Bounds.Width), 0, 0);
contentVisual.Offset += IsPullDirectionVertical ? new Vector3D(0, (translationRatio * root.Bounds.Height), 0) :
new Vector3D((translationRatio * root.Bounds.Width), 0, 0);
visualizerVisual.Offset = IsPullDirectionVertical ?
new Vector3(visualizerVisual.Offset.X, offset.Y, 0) :
new Vector3(offset.X, visualizerVisual.Offset.Y, 0);
new Vector3D(visualizerVisual.Offset.X, offset.Y, 0) :
new Vector3D(offset.X, visualizerVisual.Offset.Y, 0);
break;
case RefreshVisualizerState.Peeking:
contentVisual.Opacity = 1;

4
src/Avalonia.OpenGL/Controls/OpenGlControlBase.cs

@ -105,7 +105,7 @@ namespace Avalonia.OpenGL.Controls
}
_visual = _compositor.CreateSurfaceVisual();
_visual.Size = new Vector2((float)Bounds.Width, (float)Bounds.Height);
_visual.Size = new Vector(Bounds.Width, Bounds.Height);
_visual.Surface = _resources.Surface;
ElementComposition.SetElementChildVisual(this, _visual);
using (_resources.Context.MakeCurrent())
@ -118,7 +118,7 @@ namespace Avalonia.OpenGL.Controls
{
if (_visual != null && change.Property == BoundsProperty)
{
_visual.Size = new Vector2((float)Bounds.Width, (float)Bounds.Height);
_visual.Size = new Vector(Bounds.Width, Bounds.Height);
RequestNextFrameRendering();
}

Loading…
Cancel
Save