Browse Source

Merge branch 'master' into detachable-styles

pull/1887/head
Steven Kirk 8 years ago
committed by GitHub
parent
commit
2de646ddf8
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 26
      Avalonia.sln
  2. 1
      build.cake
  3. 2
      build/ReactiveUI.props
  4. 1
      packages.cake
  5. 9
      samples/ControlCatalog/App.xaml
  6. 61
      samples/ControlCatalog/Pages/MenuPage.xaml
  7. 97
      samples/ControlCatalog/Pages/MenuPage.xaml.cs
  8. 7
      samples/RenderDemo/Pages/AnimationsPage.xaml
  9. 16
      samples/RenderDemo/Pages/AnimationsPage.xaml.cs
  10. 26
      samples/RenderDemo/ViewModels/AnimationsPageViewModel.cs
  11. 1
      samples/VirtualizationDemo/ViewModels/MainWindowViewModel.cs
  12. 278
      samples/interop/Direct3DInteropSample/MainWindow.cs
  13. 3
      src/Android/Avalonia.Android/AndroidPlatform.cs
  14. 28
      src/Avalonia.Animation/Animatable.cs
  15. 15
      src/Avalonia.Animation/Animation.cs
  16. 61
      src/Avalonia.Animation/AnimationInstance`1.cs
  17. 118
      src/Avalonia.Animation/Animator`1.cs
  18. 30
      src/Avalonia.Animation/Clock.cs
  19. 72
      src/Avalonia.Animation/ClockBase.cs
  20. 65
      src/Avalonia.Animation/DisposeAnimationInstanceSubject.cs
  21. 5
      src/Avalonia.Animation/DoubleAnimator.cs
  22. 5
      src/Avalonia.Animation/FillMode.cs
  23. 11
      src/Avalonia.Animation/IAnimation.cs
  24. 3
      src/Avalonia.Animation/IAnimationSetter.cs
  25. 7
      src/Avalonia.Animation/IAnimator.cs
  26. 11
      src/Avalonia.Animation/IClock.cs
  27. 10
      src/Avalonia.Animation/IGlobalClock.cs
  28. 2
      src/Avalonia.Animation/ITransition.cs
  29. 5
      src/Avalonia.Animation/KeyFrame.cs
  30. 3
      src/Avalonia.Animation/KeyFramePair`1.cs
  31. 5
      src/Avalonia.Animation/PlayState.cs
  32. 5
      src/Avalonia.Animation/PlaybackDirection.cs
  33. 54
      src/Avalonia.Animation/Timing.cs
  34. 27
      src/Avalonia.Animation/TransitionInstance.cs
  35. 7
      src/Avalonia.Animation/Transition`1.cs
  36. 1
      src/Avalonia.Base/Avalonia.Base.csproj
  37. 18
      src/Avalonia.Base/Platform/Interop/IDynamicLibraryLoader.cs
  38. 4
      src/Avalonia.Base/Platform/Interop/Utf8Buffer.cs
  39. 7
      src/Avalonia.Base/PriorityBindingEntry.cs
  40. 14
      src/Avalonia.Base/PriorityLevel.cs
  41. 10
      src/Avalonia.Base/Reactive/LightweightObservableBase.cs
  42. 5
      src/Avalonia.Base/Reactive/ObservableEx.cs
  43. 2
      src/Avalonia.Controls/AppBuilderBase.cs
  44. 7
      src/Avalonia.Controls/Application.cs
  45. 6
      src/Avalonia.Controls/Border.cs
  46. 2
      src/Avalonia.Controls/DrawingPresenter.cs
  47. 4
      src/Avalonia.Controls/Generators/ItemContainerGenerator.cs
  48. 1
      src/Avalonia.Controls/Image.cs
  49. 38
      src/Avalonia.Controls/MenuItem.cs
  50. 1
      src/Avalonia.Controls/Panel.cs
  51. 2
      src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs
  52. 11
      src/Avalonia.Controls/Platform/InternalPlatformThreadingInterface.cs
  53. 8
      src/Avalonia.Controls/Presenters/ContentPresenter.cs
  54. 8
      src/Avalonia.Controls/Primitives/AdornerLayer.cs
  55. 8
      src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
  56. 7
      src/Avalonia.Controls/ProgressBar.cs
  57. 4
      src/Avalonia.Controls/TextBlock.cs
  58. 5
      src/Avalonia.Controls/TextBox.cs
  59. 1
      src/Avalonia.Controls/TopLevel.cs
  60. 156
      src/Avalonia.Controls/Utils/BorderRenderHelper.cs
  61. 3
      src/Avalonia.DesignerSupport/Remote/PreviewerWindowingPlatform.cs
  62. 8
      src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj
  63. 1
      src/Avalonia.Diagnostics/DevTools.xaml
  64. 23
      src/Avalonia.Diagnostics/DevTools.xaml.cs
  65. 38
      src/Avalonia.Diagnostics/Models/EventChainLink.cs
  66. 5
      src/Avalonia.Diagnostics/ViewModels/DevToolsViewModel.cs
  67. 61
      src/Avalonia.Diagnostics/ViewModels/EventOwnerTreeNode.cs
  68. 98
      src/Avalonia.Diagnostics/ViewModels/EventTreeNode.cs
  69. 78
      src/Avalonia.Diagnostics/ViewModels/EventTreeNodeBase.cs
  70. 60
      src/Avalonia.Diagnostics/ViewModels/EventsViewModel.cs
  71. 80
      src/Avalonia.Diagnostics/ViewModels/FiredEvent.cs
  72. 53
      src/Avalonia.Diagnostics/Views/EventsView.xaml
  73. 32
      src/Avalonia.Diagnostics/Views/EventsView.xaml.cs
  74. 12
      src/Avalonia.OpenGL/Avalonia.OpenGL.csproj
  75. 196
      src/Avalonia.OpenGL/EglConsts.cs
  76. 205
      src/Avalonia.OpenGL/EglDisplay.cs
  77. 39
      src/Avalonia.OpenGL/EglGlPlatformFeature.cs
  78. 80
      src/Avalonia.OpenGL/EglGlPlatformSurface.cs
  79. 93
      src/Avalonia.OpenGL/EglInterface.cs
  80. 16
      src/Avalonia.OpenGL/EntryPointAttribute.cs
  81. 789
      src/Avalonia.OpenGL/GlConsts.cs
  82. 8
      src/Avalonia.OpenGL/GlDisplayType.cs
  83. 48
      src/Avalonia.OpenGL/GlInterface.cs
  84. 28
      src/Avalonia.OpenGL/GlInterfaceBase.cs
  85. 8
      src/Avalonia.OpenGL/IGlContext.cs
  86. 11
      src/Avalonia.OpenGL/IGlDisplay.cs
  87. 7
      src/Avalonia.OpenGL/IGlPlatformSurface.cs
  88. 9
      src/Avalonia.OpenGL/IGlPlatformSurfaceRenderTarget.cs
  89. 12
      src/Avalonia.OpenGL/IGlPlatformSurfaceRenderingSession.cs
  90. 10
      src/Avalonia.OpenGL/IGlSurface.cs
  91. 7
      src/Avalonia.OpenGL/IWindowingPlatformGlFeature.cs
  92. 12
      src/Avalonia.OpenGL/OpenGlException.cs
  93. 4
      src/Avalonia.ReactiveUI/AppBuilderExtensions.cs
  94. 38
      src/Avalonia.ReactiveUI/AvaloniaActivationForViewFetcher.cs
  95. 19
      src/Avalonia.Styling/Styling/Style.cs
  96. 12
      src/Avalonia.Themes.Default/MenuItem.xaml
  97. 26
      src/Avalonia.Visuals/Animation/RenderLoopClock.cs
  98. 20
      src/Avalonia.Visuals/Animation/TransformAnimator.cs
  99. 1
      src/Avalonia.Visuals/Avalonia.Visuals.csproj
  100. 2
      src/Avalonia.Visuals/Matrix.cs

26
Avalonia.sln

@ -186,6 +186,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Designer.HostApp.N
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Skia.UnitTests", "tests\Avalonia.Skia.UnitTests\Avalonia.Skia.UnitTests.csproj", "{E1240B49-7B4B-4371-A00E-068778C5CF0B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.OpenGL", "src\Avalonia.OpenGL\Avalonia.OpenGL.csproj", "{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}"
EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
src\Shared\RenderHelpers\RenderHelpers.projitems*{3c4c0cb4-0c0f-4450-a37b-148c84ff905f}*SharedItemsImports = 13
@ -1663,6 +1665,30 @@ Global
{E1240B49-7B4B-4371-A00E-068778C5CF0B}.Release|iPhone.Build.0 = Release|Any CPU
{E1240B49-7B4B-4371-A00E-068778C5CF0B}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{E1240B49-7B4B-4371-A00E-068778C5CF0B}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.AppStore|Any CPU.Build.0 = Debug|Any CPU
{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.AppStore|iPhone.Build.0 = Debug|Any CPU
{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Debug|iPhone.Build.0 = Debug|Any CPU
{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Release|Any CPU.Build.0 = Release|Any CPU
{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Release|iPhone.ActiveCfg = Release|Any CPU
{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Release|iPhone.Build.0 = Release|Any CPU
{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{7CCAEFC4-135D-401D-BDDD-896B9B7D3569}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

1
build.cake

@ -170,6 +170,7 @@ Task("Run-Unit-Tests-Impl")
RunCoreTest("./tests/Avalonia.Styling.UnitTests", data.Parameters, false);
RunCoreTest("./tests/Avalonia.Visuals.UnitTests", data.Parameters, false);
RunCoreTest("./tests/Avalonia.Skia.UnitTests", data.Parameters, false);
RunCoreTest("./tests/Avalonia.ReactiveUI.UnitTests", data.Parameters, false);
if (data.Parameters.IsRunningOnWindows)
{
RunCoreTest("./tests/Avalonia.Direct2D1.UnitTests", data.Parameters, false);

2
build/ReactiveUI.props

@ -1,5 +1,5 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<PackageReference Include="reactiveui" Version="8.7.1" />
<PackageReference Include="reactiveui" Version="9.0.1" />
</ItemGroup>
</Project>

1
packages.cake

@ -167,6 +167,7 @@ public class Packages
new [] { "./src/", "Avalonia.Logging.Serilog"},
new [] { "./src/", "Avalonia.Visuals"},
new [] { "./src/", "Avalonia.Styling"},
new [] { "./src/", "Avalonia.OpenGL"},
new [] { "./src/", "Avalonia.Themes.Default"},
new [] { "./src/Markup/", "Avalonia.Markup"},
new [] { "./src/Markup/", "Avalonia.Markup.Xaml"},

9
samples/ControlCatalog/App.xaml

@ -14,6 +14,11 @@
<Setter Property="FontSize" Value="13"/>
</Style>
<StyleInclude Source="resm:ControlCatalog.SideBar.xaml"/>
<Style Selector="TextBlock.h3">
<Setter Property="Foreground" Value="#a2a2a2"/>
<Setter Property="FontSize" Value="13"/>
</Style>
<StyleInclude Source="resm:ControlCatalog.SideBar.xaml"/>
</Application.Styles>
</Application>
</Application>

61
samples/ControlCatalog/Pages/MenuPage.xaml

@ -7,29 +7,46 @@
Margin="0,16,0,0"
HorizontalAlignment="Center"
Spacing="16">
<Menu>
<MenuItem Header="_First">
<MenuItem Header="Standard _Menu Item"/>
<Separator/>
<MenuItem Header="Menu with _Submenu">
<MenuItem Header="Submenu _1"/>
<MenuItem Header="Submenu _2"/>
<StackPanel>
<TextBlock Classes="h3" Margin="4 8">Defined in XAML</TextBlock>
<Menu>
<MenuItem Header="_First">
<MenuItem Header="Standard _Menu Item"/>
<Separator/>
<MenuItem Header="Menu with _Submenu">
<MenuItem Header="Submenu _1"/>
<MenuItem Header="Submenu _2"/>
</MenuItem>
<MenuItem Header="Menu Item with _Icon">
<MenuItem.Icon>
<Image Source="resm:ControlCatalog.Assets.github_icon.png"/>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Menu Item with _Checkbox">
<MenuItem.Icon>
<CheckBox BorderThickness="0" IsHitTestVisible="False" IsChecked="True"/>
</MenuItem.Icon>
</MenuItem>
</MenuItem>
<MenuItem Header="Menu Item with _Icon">
<MenuItem.Icon>
<Image Source="resm:ControlCatalog.Assets.github_icon.png"/>
</MenuItem.Icon>
<MenuItem Header="_Second">
<MenuItem Header="Second _Menu Item"/>
</MenuItem>
<MenuItem Header="Menu Item with _Checkbox">
<MenuItem.Icon>
<CheckBox BorderThickness="0" IsHitTestVisible="False" IsChecked="True"/>
</MenuItem.Icon>
</MenuItem>
</MenuItem>
<MenuItem Header="_Second">
<MenuItem Header="Second _Menu Item"/>
</MenuItem>
</Menu>
</Menu>
</StackPanel>
<StackPanel>
<TextBlock Classes="h3" Margin="4 8">Dyanamically generated</TextBlock>
<Menu Items="{Binding MenuItems}">
<Menu.Styles>
<Style Selector="MenuItem">
<Setter Property="Header" Value="{Binding Header}"/>
<Setter Property="Items" Value="{Binding Items}"/>
<Setter Property="Command" Value="{Binding Command}"/>
<Setter Property="CommandParameter" Value="{Binding CommandParameter}"/>
</Style>
</Menu.Styles>
</Menu>
</StackPanel>
</StackPanel>
</StackPanel>
</UserControl>
</UserControl>

97
samples/ControlCatalog/Pages/MenuPage.xaml.cs

@ -1,5 +1,10 @@
using System.Collections.Generic;
using System.Reactive;
using System.Threading.Tasks;
using System.Windows.Input;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using ReactiveUI;
namespace ControlCatalog.Pages
{
@ -8,6 +13,51 @@ namespace ControlCatalog.Pages
public MenuPage()
{
this.InitializeComponent();
var vm = new MenuPageViewModel();
vm.MenuItems = new[]
{
new MenuItemViewModel
{
Header = "_File",
Items = new[]
{
new MenuItemViewModel { Header = "_Open...", Command = vm.OpenCommand },
new MenuItemViewModel { Header = "Save", Command = vm.SaveCommand },
new MenuItemViewModel { Header = "-" },
new MenuItemViewModel
{
Header = "Recent",
Items = new[]
{
new MenuItemViewModel
{
Header = "File1.txt",
Command = vm.OpenRecentCommand,
CommandParameter = @"c:\foo\File1.txt"
},
new MenuItemViewModel
{
Header = "File2.txt",
Command = vm.OpenRecentCommand,
CommandParameter = @"c:\foo\File2.txt"
},
}
},
}
},
new MenuItemViewModel
{
Header = "_Edit",
Items = new[]
{
new MenuItemViewModel { Header = "_Copy" },
new MenuItemViewModel { Header = "_Paste" },
}
}
};
DataContext = vm;
}
private void InitializeComponent()
@ -15,4 +65,51 @@ namespace ControlCatalog.Pages
AvaloniaXamlLoader.Load(this);
}
}
public class MenuPageViewModel
{
public MenuPageViewModel()
{
OpenCommand = ReactiveCommand.CreateFromTask(Open);
SaveCommand = ReactiveCommand.Create(Save);
OpenRecentCommand = ReactiveCommand.Create<string>(OpenRecent);
}
public IReadOnlyList<MenuItemViewModel> MenuItems { get; set; }
public ReactiveCommand<Unit, Unit> OpenCommand { get; }
public ReactiveCommand<Unit, Unit> SaveCommand { get; }
public ReactiveCommand<string, Unit> OpenRecentCommand { get; }
public async Task Open()
{
var dialog = new OpenFileDialog();
var result = await dialog.ShowAsync();
if (result != null)
{
foreach (var path in result)
{
System.Diagnostics.Debug.WriteLine($"Opened: {path}");
}
}
}
public void Save()
{
System.Diagnostics.Debug.WriteLine("Save");
}
public void OpenRecent(string path)
{
System.Diagnostics.Debug.WriteLine($"Open recent: {path}");
}
}
public class MenuItemViewModel
{
public string Header { get; set; }
public ICommand Command { get; set; }
public object CommandParameter { get; set; }
public IList<MenuItemViewModel> Items { get; set; }
}
}

7
samples/RenderDemo/Pages/AnimationsPage.xaml

@ -107,9 +107,12 @@
</UserControl.Styles>
<Grid>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" ClipToBounds="False">
<StackPanel.Clock>
<Clock />
</StackPanel.Clock>
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
<TextBlock VerticalAlignment="Center">Hover to activate Transform Keyframe Animations.</TextBlock>
<Button Content="{Binding PlayStateText}" Command="{Binding ToggleGlobalPlayState}"/>
<Button Content="{Binding PlayStateText}" Command="{Binding TogglePlayState}" Click="ToggleClock" />
</StackPanel>
<WrapPanel ClipToBounds="False">
<Border Classes="Test Rect1" Background="DarkRed"/>
@ -120,4 +123,4 @@
</WrapPanel>
</StackPanel>
</Grid>
</UserControl>
</UserControl>

16
samples/RenderDemo/Pages/AnimationsPage.xaml.cs

@ -5,6 +5,7 @@ using Avalonia.Controls;
using Avalonia.Controls.Shapes;
using Avalonia.Data;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
using Avalonia.Media;
using RenderDemo.ViewModels;
@ -23,5 +24,20 @@ namespace RenderDemo.Pages
{
AvaloniaXamlLoader.Load(this);
}
private void ToggleClock(object sender, RoutedEventArgs args)
{
var button = sender as Button;
var clock = button.Clock;
if (clock.PlayState == PlayState.Run)
{
clock.PlayState = PlayState.Pause;
}
else if (clock.PlayState == PlayState.Pause)
{
clock.PlayState = PlayState.Run;
}
}
}
}

26
samples/RenderDemo/ViewModels/AnimationsPageViewModel.cs

@ -6,27 +6,15 @@ namespace RenderDemo.ViewModels
{
public class AnimationsPageViewModel : ReactiveObject
{
private string _playStateText = "Pause all animations";
private bool _isPlaying = true;
public AnimationsPageViewModel()
{
ToggleGlobalPlayState = ReactiveCommand.Create(() => TogglePlayState());
}
private string _playStateText = "Pause animations on this page";
void TogglePlayState()
public void TogglePlayState()
{
switch (Animation.GlobalPlayState)
{
case PlayState.Run:
PlayStateText = "Resume all animations";
Animation.GlobalPlayState = PlayState.Pause;
break;
case PlayState.Pause:
PlayStateText = "Pause all animations";
Animation.GlobalPlayState = PlayState.Run;
break;
}
PlayStateText = _isPlaying
? "Resume animations on this page" : "Pause animations on this page";
_isPlaying = !_isPlaying;
}
public string PlayStateText
@ -34,7 +22,5 @@ namespace RenderDemo.ViewModels
get { return _playStateText; }
set { this.RaiseAndSetIfChanged(ref _playStateText, value); }
}
public ReactiveCommand ToggleGlobalPlayState { get; }
}
}

1
samples/VirtualizationDemo/ViewModels/MainWindowViewModel.cs

@ -7,6 +7,7 @@ using System.Linq;
using Avalonia.Collections;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using ReactiveUI.Legacy;
using ReactiveUI;
namespace VirtualizationDemo.ViewModels

278
samples/interop/Direct3DInteropSample/MainWindow.cs

@ -1,81 +1,83 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Direct2D1;
using Avalonia.Direct2D1.Media;
using Avalonia.Markup.Xaml;
using Avalonia.Platform;
using Avalonia.Rendering;
using SharpDX;
using SharpDX.D3DCompiler;
using SharpDX.Direct2D1;
using SharpDX.Direct3D;
using SharpDX.Direct3D11;
using SharpDX.DXGI;
using SharpDX.WIC;
using SharpDX.Mathematics;
using AlphaMode = SharpDX.Direct2D1.AlphaMode;
using Buffer = SharpDX.Direct3D11.Buffer;
using DeviceContext = SharpDX.Direct3D11.DeviceContext;
using Factory1 = SharpDX.DXGI.Factory1;
using DeviceContext = SharpDX.Direct2D1.DeviceContext;
using Factory2 = SharpDX.DXGI.Factory2;
using InputElement = SharpDX.Direct3D11.InputElement;
using Matrix = SharpDX.Matrix;
using PixelFormat = SharpDX.Direct2D1.PixelFormat;
using Resource = SharpDX.Direct3D11.Resource;
namespace Direct3DInteropSample
{
class MainWindow : Window
public class MainWindow : Window
{
private SharpDX.Direct3D11.Device _d3dDevice;
private SharpDX.DXGI.Device _dxgiDevice;
Texture2D backBuffer = null;
RenderTargetView renderView = null;
Texture2D depthBuffer = null;
DepthStencilView depthView = null;
Texture2D _backBuffer;
RenderTargetView _renderView;
Texture2D _depthBuffer;
DepthStencilView _depthView;
private readonly SwapChain _swapChain;
private SwapChainDescription _desc;
private SwapChainDescription1 _desc;
private Matrix _proj = Matrix.Identity;
private Matrix _view;
private readonly Matrix _view;
private Buffer _contantBuffer;
private SharpDX.Direct2D1.Device _d2dDevice;
private SharpDX.Direct2D1.DeviceContext _d2dContext;
private RenderTarget _d2dRenderTarget;
private MainWindowViewModel _model;
private DeviceContext _deviceContext;
private readonly MainWindowViewModel _model;
public MainWindow()
{
_dxgiDevice = AvaloniaLocator.Current.GetService<SharpDX.DXGI.Device>();
_d3dDevice = _dxgiDevice.QueryInterface<SharpDX.Direct3D11.Device>();
_d2dDevice = AvaloniaLocator.Current.GetService<SharpDX.Direct2D1.Device>();
DataContext = _model = new MainWindowViewModel();
_desc = new SwapChainDescription()
_desc = new SwapChainDescription1()
{
BufferCount = 1,
ModeDescription =
new ModeDescription((int)ClientSize.Width, (int)ClientSize.Height,
new Rational(60, 1), Format.R8G8B8A8_UNorm),
IsWindowed = true,
OutputHandle = PlatformImpl?.Handle.Handle ?? IntPtr.Zero,
Width = (int)ClientSize.Width,
Height = (int)ClientSize.Height,
Format = Format.R8G8B8A8_UNorm,
SampleDescription = new SampleDescription(1, 0),
SwapEffect = SwapEffect.Discard,
Usage = Usage.RenderTargetOutput
};
_swapChain = new SwapChain(new Factory1(), _d3dDevice, _desc);
using (var factory = Direct2D1Platform.DxgiDevice.Adapter.GetParent<Factory2>())
{
_swapChain = new SwapChain1(factory, Direct2D1Platform.DxgiDevice, PlatformImpl?.Handle.Handle ?? IntPtr.Zero, ref _desc);
}
_d2dContext = new SharpDX.Direct2D1.DeviceContext(_d2dDevice, DeviceContextOptions.None)
_deviceContext = new DeviceContext(Direct2D1Platform.Direct2D1Device, DeviceContextOptions.None)
{
DotsPerInch = new Size2F(96, 96)
};
CreateMesh();
_view = Matrix.LookAtLH(new Vector3(0, 0, -5), new Vector3(0, 0, 0), Vector3.UnitY);
this.GetObservable(ClientSizeProperty).Subscribe(Resize);
Resize(ClientSize);
AvaloniaXamlLoader.Load(this);
Background = Avalonia.Media.Brushes.Transparent;
}
@ -83,29 +85,32 @@ namespace Direct3DInteropSample
protected override void HandlePaint(Rect rect)
{
var viewProj = Matrix.Multiply(_view, _proj);
var context = _d3dDevice.ImmediateContext;
var context = Direct2D1Platform.Direct3D11Device.ImmediateContext;
// Clear views
context.ClearDepthStencilView(depthView, DepthStencilClearFlags.Depth, 1.0f, 0);
context.ClearRenderTargetView(renderView, Color.White);
context.ClearDepthStencilView(_depthView, DepthStencilClearFlags.Depth, 1.0f, 0);
context.ClearRenderTargetView(_renderView, Color.White);
// Update WorldViewProj Matrix
var worldViewProj = Matrix.RotationX((float) _model.RotationX) * Matrix.RotationY((float) _model.RotationY) *
Matrix.RotationZ((float) _model.RotationZ)
* Matrix.Scaling((float) _model.Zoom) * viewProj;
var worldViewProj = Matrix.RotationX((float)_model.RotationX) * Matrix.RotationY((float)_model.RotationY)
* Matrix.RotationZ((float)_model.RotationZ)
* Matrix.Scaling((float)_model.Zoom)
* viewProj;
worldViewProj.Transpose();
context.UpdateSubresource(ref worldViewProj, _contantBuffer);
// Draw the cube
context.Draw(36, 0);
base.HandlePaint(rect);
// Present!
_swapChain.Present(0, PresentFlags.None);
}
void CreateMesh()
private void CreateMesh()
{
var device = _d3dDevice;
var device = Direct2D1Platform.Direct3D11Device;
// Compile Vertex and Pixel shaders
var vertexShaderByteCode = ShaderBytecode.CompileFromFile("MiniCube.fx", "VS", "vs_4_0");
var vertexShader = new VertexShader(device, vertexShaderByteCode);
@ -114,63 +119,72 @@ namespace Direct3DInteropSample
var pixelShader = new PixelShader(device, pixelShaderByteCode);
var signature = ShaderSignature.GetInputSignature(vertexShaderByteCode);
var inputElements = new[]
{
new InputElement("POSITION", 0, Format.R32G32B32A32_Float, 0, 0),
new InputElement("COLOR", 0, Format.R32G32B32A32_Float, 16, 0)
};
// Layout from VertexShader input signature
var layout = new InputLayout(device, signature, new[]
{
new InputElement("POSITION", 0, Format.R32G32B32A32_Float, 0, 0),
new InputElement("COLOR", 0, Format.R32G32B32A32_Float, 16, 0)
});
// Instantiate Vertex buiffer from vertex data
var vertices = Buffer.Create(device, BindFlags.VertexBuffer, new[]
{
new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f), // Front
new Vector4(-1.0f, 1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
new Vector4( 1.0f, 1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
new Vector4( 1.0f, 1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
new Vector4( 1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
new Vector4(-1.0f, -1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f), // BACK
new Vector4( 1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
new Vector4(-1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
new Vector4(-1.0f, -1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
new Vector4( 1.0f, -1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
new Vector4( 1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
new Vector4(-1.0f, 1.0f, -1.0f, 1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f), // Top
new Vector4(-1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
new Vector4( 1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
new Vector4(-1.0f, 1.0f, -1.0f, 1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
new Vector4( 1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
new Vector4( 1.0f, 1.0f, -1.0f, 1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
new Vector4(-1.0f,-1.0f, -1.0f, 1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f), // Bottom
new Vector4( 1.0f,-1.0f, 1.0f, 1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
new Vector4(-1.0f,-1.0f, 1.0f, 1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
new Vector4(-1.0f,-1.0f, -1.0f, 1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
new Vector4( 1.0f,-1.0f, -1.0f, 1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
new Vector4( 1.0f,-1.0f, 1.0f, 1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f), // Left
new Vector4(-1.0f, -1.0f, 1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
new Vector4(-1.0f, 1.0f, 1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
new Vector4(-1.0f, 1.0f, 1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
new Vector4(-1.0f, 1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
new Vector4( 1.0f, -1.0f, -1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f), // Right
new Vector4( 1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
new Vector4( 1.0f, -1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
new Vector4( 1.0f, -1.0f, -1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
new Vector4( 1.0f, 1.0f, -1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
new Vector4( 1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
});
var layout = new InputLayout(
device,
signature,
inputElements);
// Instantiate Vertex buffer from vertex data
var vertices = Buffer.Create(
device,
BindFlags.VertexBuffer,
new[]
{
new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f), // Front
new Vector4(-1.0f, 1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
new Vector4( 1.0f, 1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
new Vector4( 1.0f, 1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
new Vector4( 1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 0.0f, 1.0f),
new Vector4(-1.0f, -1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f), // BACK
new Vector4( 1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
new Vector4(-1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
new Vector4(-1.0f, -1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
new Vector4( 1.0f, -1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
new Vector4( 1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 0.0f, 1.0f),
new Vector4(-1.0f, 1.0f, -1.0f, 1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f), // Top
new Vector4(-1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
new Vector4( 1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
new Vector4(-1.0f, 1.0f, -1.0f, 1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
new Vector4( 1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
new Vector4( 1.0f, 1.0f, -1.0f, 1.0f), new Vector4(0.0f, 0.0f, 1.0f, 1.0f),
new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f), // Bottom
new Vector4( 1.0f, -1.0f, 1.0f, 1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
new Vector4(-1.0f, -1.0f, 1.0f, 1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
new Vector4( 1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
new Vector4( 1.0f, -1.0f, 1.0f, 1.0f), new Vector4(1.0f, 1.0f, 0.0f, 1.0f),
new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f), // Left
new Vector4(-1.0f, -1.0f, 1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
new Vector4(-1.0f, 1.0f, 1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
new Vector4(-1.0f, -1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
new Vector4(-1.0f, 1.0f, 1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
new Vector4(-1.0f, 1.0f, -1.0f, 1.0f), new Vector4(1.0f, 0.0f, 1.0f, 1.0f),
new Vector4( 1.0f, -1.0f, -1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f), // Right
new Vector4( 1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
new Vector4( 1.0f, -1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
new Vector4( 1.0f, -1.0f, -1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
new Vector4( 1.0f, 1.0f, -1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
new Vector4( 1.0f, 1.0f, 1.0f, 1.0f), new Vector4(0.0f, 1.0f, 1.0f, 1.0f),
});
// Create Constant Buffer
_contantBuffer = new Buffer(device, Utilities.SizeOf<Matrix>(), ResourceUsage.Default, BindFlags.ConstantBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 0);
var context = _d3dDevice.ImmediateContext;
var context = Direct2D1Platform.Direct3D11Device.ImmediateContext;
// Prepare All the stages
context.InputAssembler.InputLayout = layout;
@ -181,63 +195,73 @@ namespace Direct3DInteropSample
context.PixelShader.Set(pixelShader);
}
void Resize(Size size)
private void Resize(Size size)
{
Utilities.Dispose(ref _d2dRenderTarget);
Utilities.Dispose(ref backBuffer);
Utilities.Dispose(ref renderView);
Utilities.Dispose(ref depthBuffer);
Utilities.Dispose(ref depthView);
var context = _d3dDevice.ImmediateContext;
Utilities.Dispose(ref _deviceContext);
Utilities.Dispose(ref _backBuffer);
Utilities.Dispose(ref _renderView);
Utilities.Dispose(ref _depthBuffer);
Utilities.Dispose(ref _depthView);
var context = Direct2D1Platform.Direct3D11Device.ImmediateContext;
// Resize the backbuffer
_swapChain.ResizeBuffers(_desc.BufferCount, (int)size.Width, (int)size.Height, Format.Unknown, SwapChainFlags.None);
_swapChain.ResizeBuffers(0, 0, 0, Format.Unknown, SwapChainFlags.None);
// Get the backbuffer from the swapchain
backBuffer = Texture2D.FromSwapChain<Texture2D>(_swapChain, 0);
_backBuffer = Resource.FromSwapChain<Texture2D>(_swapChain, 0);
// Renderview on the backbuffer
renderView = new RenderTargetView(_d3dDevice, backBuffer);
_renderView = new RenderTargetView(Direct2D1Platform.Direct3D11Device, _backBuffer);
// Create the depth buffer
depthBuffer = new Texture2D(_d3dDevice, new Texture2DDescription()
{
Format = Format.D32_Float_S8X24_UInt,
ArraySize = 1,
MipLevels = 1,
Width = (int)size.Width,
Height = (int)size.Height,
SampleDescription = new SampleDescription(1, 0),
Usage = ResourceUsage.Default,
BindFlags = BindFlags.DepthStencil,
CpuAccessFlags = CpuAccessFlags.None,
OptionFlags = ResourceOptionFlags.None
});
_depthBuffer = new Texture2D(
Direct2D1Platform.Direct3D11Device,
new Texture2DDescription()
{
Format = Format.D32_Float_S8X24_UInt,
ArraySize = 1,
MipLevels = 1,
Width = (int)size.Width,
Height = (int)size.Height,
SampleDescription = new SampleDescription(1, 0),
Usage = ResourceUsage.Default,
BindFlags = BindFlags.DepthStencil,
CpuAccessFlags = CpuAccessFlags.None,
OptionFlags = ResourceOptionFlags.None
});
// Create the depth buffer view
depthView = new DepthStencilView(_d3dDevice, depthBuffer);
_depthView = new DepthStencilView(Direct2D1Platform.Direct3D11Device, _depthBuffer);
// Setup targets and viewport for rendering
context.Rasterizer.SetViewport(new Viewport(0, 0, (int)size.Width, (int)size.Height, 0.0f, 1.0f));
context.OutputMerger.SetTargets(depthView, renderView);
context.OutputMerger.SetTargets(_depthView, _renderView);
// Setup new projection matrix with correct aspect ratio
_proj = Matrix.PerspectiveFovLH((float)Math.PI / 4.0f, (float)(size.Width / size.Height), 0.1f, 100.0f);
using (var dxgiBackBuffer = _swapChain.GetBackBuffer<Surface>(0))
{
_d2dRenderTarget = new RenderTarget(AvaloniaLocator.Current.GetService<SharpDX.Direct2D1.Factory>()
, dxgiBackBuffer, new RenderTargetProperties
var renderTarget = new SharpDX.Direct2D1.RenderTarget(
Direct2D1Platform.Direct2D1Factory,
dxgiBackBuffer,
new RenderTargetProperties
{
DpiX = 96,
DpiY = 96,
Type = RenderTargetType.Default,
PixelFormat = new PixelFormat(Format.Unknown, AlphaMode.Premultiplied)
PixelFormat = new PixelFormat(
Format.Unknown,
AlphaMode.Premultiplied)
});
}
_deviceContext = renderTarget.QueryInterface<DeviceContext>();
renderTarget.Dispose();
}
}
class D3DRenderTarget: IRenderTarget
private class D3DRenderTarget : IRenderTarget
{
private readonly MainWindow _window;
@ -245,16 +269,14 @@ namespace Direct3DInteropSample
{
_window = window;
}
public void Dispose()
{
}
public IDrawingContextImpl CreateDrawingContext(IVisualBrushRenderer visualBrushRenderer)
{
return new DrawingContextImpl(visualBrushRenderer, null, _window._d2dRenderTarget,
AvaloniaLocator.Current.GetService<SharpDX.DirectWrite.Factory>(),
AvaloniaLocator.Current.GetService<ImagingFactory>());
return new DrawingContextImpl(visualBrushRenderer, null, _window._deviceContext);
}
}

3
src/Android/Avalonia.Android/AndroidPlatform.cs

@ -52,7 +52,8 @@ namespace Avalonia.Android
.Bind<ISystemDialogImpl>().ToTransient<SystemDialogImpl>()
.Bind<IWindowingPlatform>().ToConstant(Instance)
.Bind<IPlatformIconLoader>().ToSingleton<PlatformIconLoader>()
.Bind<IRenderLoop>().ToConstant(new DefaultRenderLoop(60))
.Bind<IRenderTimer>().ToConstant(new DefaultRenderTimer(60))
.Bind<IRenderLoop>().ToConstant(new RenderLoop())
.Bind<IAssetLoader>().ToConstant(new AssetLoader(app.GetType().Assembly));
SkiaPlatform.Initialize();

28
src/Avalonia.Animation/Animatable.cs

@ -14,26 +14,14 @@ namespace Avalonia.Animation
/// Base class for all animatable objects.
/// </summary>
public class Animatable : AvaloniaObject
{
/// <summary>
/// Defines the <see cref="PlayState"/> property.
/// </summary>
public static readonly DirectProperty<Animatable, PlayState> PlayStateProperty =
AvaloniaProperty.RegisterDirect<Animatable, PlayState>(
nameof(PlayState),
o => o.PlayState,
(o, v) => o.PlayState = v);
private PlayState _playState = PlayState.Run;
{
public static readonly StyledProperty<IClock> ClockProperty =
AvaloniaProperty.Register<Animatable, IClock>(nameof(Clock), inherits: true);
/// <summary>
/// Gets or sets the state of the animation for this
/// control.
/// </summary>
public PlayState PlayState
public IClock Clock
{
get { return _playState; }
set { SetAndRaise(PlayStateProperty, ref _playState, value); }
get => GetValue(ClockProperty);
set => SetValue(ClockProperty, value);
}
/// <summary>
@ -69,9 +57,9 @@ namespace Avalonia.Animation
if (match != null)
{
match.Apply(this, e.OldValue, e.NewValue);
match.Apply(this, Clock ?? Avalonia.Animation.Clock.GlobalClock, e.OldValue, e.NewValue);
}
}
}
}
}
}

15
src/Avalonia.Animation/Animation.cs

@ -17,11 +17,6 @@ namespace Avalonia.Animation
/// </summary>
public class Animation : AvaloniaList<KeyFrame>, IAnimation
{
/// <summary>
/// Gets or sets the animation play state for all animations
/// </summary>
public static PlayState GlobalPlayState { get; set; } = PlayState.Run;
/// <summary>
/// Gets or sets the active time of this animation.
/// </summary>
@ -149,12 +144,12 @@ namespace Avalonia.Animation
}
/// <inheritdocs/>
public IDisposable Apply(Animatable control, IObservable<bool> match, Action onComplete)
public IDisposable Apply(Animatable control, IClock clock, IObservable<bool> match, Action onComplete)
{
var (animators, subscriptions) = InterpretKeyframes(control);
if (animators.Count == 1)
{
subscriptions.Add(animators[0].Apply(this, control, match, onComplete));
subscriptions.Add(animators[0].Apply(this, control, clock, match, onComplete));
}
else
{
@ -168,7 +163,7 @@ namespace Avalonia.Animation
animatorOnComplete = () => tcs.SetResult(null);
completionTasks.Add(tcs.Task);
}
subscriptions.Add(animator.Apply(this, control, match, animatorOnComplete));
subscriptions.Add(animator.Apply(this, control, clock, match, animatorOnComplete));
}
if (onComplete != null)
@ -180,7 +175,7 @@ namespace Avalonia.Animation
}
/// <inheritdocs/>
public Task RunAsync(Animatable control)
public Task RunAsync(Animatable control, IClock clock = null)
{
var run = new TaskCompletionSource<object>();
@ -188,7 +183,7 @@ namespace Avalonia.Animation
run.SetException(new InvalidOperationException("Looping animations must not use the Run method."));
IDisposable subscriptions = null;
subscriptions = this.Apply(control, Observable.Return(true), () =>
subscriptions = this.Apply(control, clock, Observable.Return(true), () =>
{
run.SetResult(null);
subscriptions?.Dispose();

61
src/Avalonia.Animation/AnimationInstance`1.cs

@ -8,7 +8,7 @@ using Avalonia.Reactive;
namespace Avalonia.Animation
{
/// <summary>
/// Handles interpolatoin and time-related functions
/// Handles interpolation and time-related functions
/// for keyframe animations.
/// </summary>
internal class AnimationInstance<T> : SingleSubscriberObservableBase<T>
@ -19,7 +19,6 @@ namespace Avalonia.Animation
private double _currentIteration;
private bool _isLooping;
private bool _gotFirstKFValue;
private bool _gotFirstFrameCount;
private bool _iterationDelay;
private FillMode _fillMode;
private PlaybackDirection _animationDirection;
@ -29,15 +28,14 @@ namespace Avalonia.Animation
private double _speedRatio;
private TimeSpan _delay;
private TimeSpan _duration;
private TimeSpan _firstFrameCount;
private TimeSpan _internalClock;
private TimeSpan? _previousClock;
private Easings.Easing _easeFunc;
private Action _onCompleteAction;
private Func<double, T, T> _interpolator;
private IDisposable _timerSubscription;
private readonly IClock _baseClock;
private IClock _clock;
public AnimationInstance(Animation animation, Animatable control, Animator<T> animator, Action OnComplete, Func<double, T, T> Interpolator)
public AnimationInstance(Animation animation, Animatable control, Animator<T> animator, IClock baseClock, Action OnComplete, Func<double, T, T> Interpolator)
{
if (animation.SpeedRatio <= 0)
throw new InvalidOperationException("Speed ratio cannot be negative or zero.");
@ -73,17 +71,19 @@ namespace Avalonia.Animation
_fillMode = animation.FillMode;
_onCompleteAction = OnComplete;
_interpolator = Interpolator;
_baseClock = baseClock;
}
protected override void Unsubscribed()
{
_timerSubscription?.Dispose();
_clock.PlayState = PlayState.Stop;
}
protected override void Subscribed()
{
_timerSubscription = Timing.AnimationsTimer
.Subscribe(p => this.Step(p));
_clock = new Clock(_baseClock);
_timerSubscription = _clock.Subscribe(Step);
}
public void Step(TimeSpan frameTick)
@ -116,46 +116,21 @@ namespace Avalonia.Animation
PublishNext(_lastInterpValue);
}
private void DoPlayStatesAndTime(TimeSpan systemTime)
private void DoPlayStates()
{
if (Animation.GlobalPlayState == PlayState.Stop || _targetControl.PlayState == PlayState.Stop)
if (_clock.PlayState == PlayState.Stop || _baseClock.PlayState == PlayState.Stop)
DoComplete();
if (!_previousClock.HasValue)
{
_previousClock = systemTime;
_internalClock = TimeSpan.Zero;
}
else
{
if (Animation.GlobalPlayState == PlayState.Pause || _targetControl.PlayState == PlayState.Pause)
{
_previousClock = systemTime;
return;
}
var delta = systemTime - _previousClock;
_internalClock += delta.Value;
_previousClock = systemTime;
}
if (!_gotFirstKFValue)
{
_firstKFValue = (T)_parent.First().Value;
_gotFirstKFValue = true;
}
if (!_gotFirstFrameCount)
{
_firstFrameCount = _internalClock;
_gotFirstFrameCount = true;
}
}
private void InternalStep(TimeSpan systemTime)
private void InternalStep(TimeSpan time)
{
DoPlayStatesAndTime(systemTime);
var time = _internalClock - _firstFrameCount;
DoPlayStates();
var delayEndpoint = _delay;
var iterationEndpoint = delayEndpoint + _duration;
@ -176,22 +151,18 @@ namespace Avalonia.Animation
}
//Calculate the current iteration number
_currentIteration = (int)Math.Floor((double)time.Ticks / iterationEndpoint.Ticks) + 2;
_currentIteration = (int)Math.Floor((double)((double)time.Ticks / iterationEndpoint.Ticks)) + 2;
}
else
{
_previousClock = systemTime;
return;
}
time = TimeSpan.FromTicks(time.Ticks % iterationEndpoint.Ticks);
time = TimeSpan.FromTicks((long)(time.Ticks % iterationEndpoint.Ticks));
if (!_isLooping)
{
if (_currentIteration > _repeatCount)
DoComplete();
if (time > iterationEndpoint)
if ((_currentIteration > _repeatCount) || (time > iterationEndpoint))
DoComplete();
}
@ -225,4 +196,4 @@ namespace Avalonia.Animation
}
}
}
}
}

118
src/Avalonia.Animation/Animator`1.cs

@ -1,10 +1,14 @@
using System;
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using Avalonia.Animation.Utils;
using Avalonia.Collections;
using Avalonia.Data;
using Avalonia.Reactive;
namespace Avalonia.Animation
{
@ -17,7 +21,7 @@ namespace Avalonia.Animation
/// List of type-converted keyframes.
/// </summary>
private readonly List<AnimatorKeyFrame> _convertedKeyframes = new List<AnimatorKeyFrame>();
private bool _isVerifiedAndConverted;
/// <summary>
@ -28,21 +32,17 @@ namespace Avalonia.Animation
public Animator()
{
// Invalidate keyframes when changed.
this.CollectionChanged += delegate { _isVerifiedAndConverted = false; };
this.CollectionChanged += delegate { _isVerifiedAndConverted = false; };
}
/// <inheritdoc/>
public virtual IDisposable Apply(Animation animation, Animatable control, IObservable<bool> match, Action onComplete)
public virtual IDisposable Apply(Animation animation, Animatable control, IClock clock, IObservable<bool> match, Action onComplete)
{
if (!_isVerifiedAndConverted)
if (!_isVerifiedAndConverted)
VerifyConvertKeyFrames();
return match
.Where(p => p)
.Subscribe(_ =>
{
var timerObs = RunKeyFrames(animation, control, onComplete);
});
var subject = new DisposeAnimationInstanceSubject<T>(this, animation, control, clock, onComplete);
return match.Subscribe(subject);
}
/// <summary>
@ -52,58 +52,84 @@ namespace Avalonia.Animation
/// (i.e., the normalized time between the selected keyframes, relative to the
/// time parameter).
/// </summary>
/// <param name="t">The time parameter, relative to the total animation time</param>
protected (double IntraKFTime, KeyFramePair<T> KFPair) GetKFPairAndIntraKFTime(double t)
/// <param name="animationTime">The time parameter, relative to the total animation time</param>
protected (double IntraKFTime, KeyFramePair<T> KFPair) GetKFPairAndIntraKFTime(double animationTime)
{
AnimatorKeyFrame firstCue, lastCue ;
AnimatorKeyFrame firstKeyframe, lastKeyframe;
int kvCount = _convertedKeyframes.Count;
if (kvCount > 2)
{
if (t <= 0.0)
if (animationTime <= 0.0)
{
firstCue = _convertedKeyframes[0];
lastCue = _convertedKeyframes[1];
firstKeyframe = _convertedKeyframes[0];
lastKeyframe = _convertedKeyframes[1];
}
else if (t >= 1.0)
else if (animationTime >= 1.0)
{
firstCue = _convertedKeyframes[_convertedKeyframes.Count - 2];
lastCue = _convertedKeyframes[_convertedKeyframes.Count - 1];
firstKeyframe = _convertedKeyframes[_convertedKeyframes.Count - 2];
lastKeyframe = _convertedKeyframes[_convertedKeyframes.Count - 1];
}
else
{
(double time, int index) maxval = (0.0d, 0);
for (int i = 0; i < _convertedKeyframes.Count; i++)
{
var comp = _convertedKeyframes[i].Cue.CueValue;
if (t >= comp)
{
maxval = (comp, i);
}
}
firstCue = _convertedKeyframes[maxval.index];
lastCue = _convertedKeyframes[maxval.index + 1];
int index = FindClosestBeforeKeyFrame(animationTime);
firstKeyframe = _convertedKeyframes[index];
lastKeyframe = _convertedKeyframes[index + 1];
}
}
else
{
firstCue = _convertedKeyframes[0];
lastCue = _convertedKeyframes[1];
firstKeyframe = _convertedKeyframes[0];
lastKeyframe = _convertedKeyframes[1];
}
double t0 = firstCue.Cue.CueValue;
double t1 = lastCue.Cue.CueValue;
var intraframeTime = (t - t0) / (t1 - t0);
var firstFrameData = (firstCue.GetTypedValue<T>(), firstCue.isNeutral);
var lastFrameData = (lastCue.GetTypedValue<T>(), lastCue.isNeutral);
double t0 = firstKeyframe.Cue.CueValue;
double t1 = lastKeyframe.Cue.CueValue;
var intraframeTime = (animationTime - t0) / (t1 - t0);
var firstFrameData = (firstKeyframe.GetTypedValue<T>(), firstKeyframe.isNeutral);
var lastFrameData = (lastKeyframe.GetTypedValue<T>(), lastKeyframe.isNeutral);
return (intraframeTime, new KeyFramePair<T>(firstFrameData, lastFrameData));
}
private int FindClosestBeforeKeyFrame(double time)
{
int FindClosestBeforeKeyFrame(int startIndex, int length)
{
if (length == 0 || length == 1)
{
return startIndex;
}
int middle = startIndex + (length / 2);
if (_convertedKeyframes[middle].Cue.CueValue < time)
{
return FindClosestBeforeKeyFrame(middle, length - middle);
}
else if (_convertedKeyframes[middle].Cue.CueValue > time)
{
return FindClosestBeforeKeyFrame(startIndex, middle - startIndex);
}
else
{
return middle;
}
}
return FindClosestBeforeKeyFrame(0, _convertedKeyframes.Count);
}
/// <summary>
/// Runs the KeyFrames Animation.
/// </summary>
private IDisposable RunKeyFrames(Animation animation, Animatable control, Action onComplete)
internal IDisposable Run(Animation animation, Animatable control, IClock clock, Action onComplete)
{
var instance = new AnimationInstance<T>(animation, control, this, onComplete, DoInterpolation);
var instance = new AnimationInstance<T>(
animation,
control,
this,
clock ?? control.Clock ?? Clock.GlobalClock,
onComplete,
DoInterpolation);
return control.Bind<T>((AvaloniaProperty<T>)Property, instance, BindingPriority.Animation);
}
@ -124,14 +150,6 @@ namespace Avalonia.Animation
AddNeutralKeyFramesIfNeeded();
var copy = _convertedKeyframes.ToList().OrderBy(p => p.Cue.CueValue);
_convertedKeyframes.Clear();
foreach (AnimatorKeyFrame keyframe in copy)
{
_convertedKeyframes.Add(keyframe);
}
_isVerifiedAndConverted = true;
}
@ -161,7 +179,7 @@ namespace Avalonia.Animation
{
if (!hasStartKey)
{
_convertedKeyframes.Add(new AnimatorKeyFrame(null, new Cue(0.0d)) { Value = default(T), isNeutral = true });
_convertedKeyframes.Insert(0, new AnimatorKeyFrame(null, new Cue(0.0d)) { Value = default(T), isNeutral = true });
}
if (!hasEndKey)
@ -170,4 +188,4 @@ namespace Avalonia.Animation
}
}
}
}
}

30
src/Avalonia.Animation/Clock.cs

@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Reactive.Linq;
using System.Text;
using Avalonia.Reactive;
namespace Avalonia.Animation
{
public class Clock : ClockBase
{
public static IClock GlobalClock => AvaloniaLocator.Current.GetService<IGlobalClock>();
private IDisposable _parentSubscription;
public Clock()
:this(GlobalClock)
{
}
public Clock(IClock parent)
{
_parentSubscription = parent.Subscribe(Pulse);
}
protected override void Stop()
{
_parentSubscription?.Dispose();
}
}
}

72
src/Avalonia.Animation/ClockBase.cs

@ -0,0 +1,72 @@
using System;
using System.Collections.Generic;
using System.Reactive.Linq;
using System.Text;
using Avalonia.Reactive;
namespace Avalonia.Animation
{
public class ClockBase : IClock
{
private ClockObservable _observable;
private IObservable<TimeSpan> _connectedObservable;
private TimeSpan? _previousTime;
private TimeSpan _internalTime;
protected ClockBase()
{
_observable = new ClockObservable();
_connectedObservable = _observable.Publish().RefCount();
}
protected bool HasSubscriptions => _observable.HasSubscriptions;
public PlayState PlayState { get; set; }
protected void Pulse(TimeSpan systemTime)
{
if (!_previousTime.HasValue)
{
_previousTime = systemTime;
_internalTime = TimeSpan.Zero;
}
else
{
if (PlayState == PlayState.Pause)
{
_previousTime = systemTime;
return;
}
var delta = systemTime - _previousTime;
_internalTime += delta.Value;
_previousTime = systemTime;
}
_observable.Pulse(_internalTime);
if (PlayState == PlayState.Stop)
{
Stop();
}
}
protected virtual void Stop()
{
}
public IDisposable Subscribe(IObserver<TimeSpan> observer)
{
return _connectedObservable.Subscribe(observer);
}
private class ClockObservable : LightweightObservableBase<TimeSpan>
{
public bool HasSubscriptions { get; private set; }
public void Pulse(TimeSpan time) => PublishNext(time);
protected override void Initialize() => HasSubscriptions = true;
protected override void Deinitialize() => HasSubscriptions = false;
}
}
}

65
src/Avalonia.Animation/DisposeAnimationInstanceSubject.cs

@ -0,0 +1,65 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using Avalonia.Animation.Utils;
using Avalonia.Collections;
using Avalonia.Data;
using Avalonia.Reactive;
namespace Avalonia.Animation
{
/// <summary>
/// Manages the lifetime of animation instances as determined by its selector state.
/// </summary>
internal class DisposeAnimationInstanceSubject<T> : IObserver<bool>, IDisposable
{
private IDisposable _lastInstance;
private bool _lastMatch;
private Animator<T> _animator;
private Animation _animation;
private Animatable _control;
private Action _onComplete;
private IClock _clock;
public DisposeAnimationInstanceSubject(Animator<T> animator, Animation animation, Animatable control, IClock clock, Action onComplete)
{
this._animator = animator;
this._animation = animation;
this._control = control;
this._onComplete = onComplete;
this._clock = clock;
}
public void Dispose()
{
_lastInstance?.Dispose();
}
public void OnCompleted()
{
}
public void OnError(Exception error)
{
_lastInstance?.Dispose();
}
void IObserver<bool>.OnNext(bool matchVal)
{
if (matchVal != _lastMatch)
{
_lastInstance?.Dispose();
if (matchVal)
{
_lastInstance = _animator.Run(_animation, _control, _clock, _onComplete);
}
_lastMatch = matchVal;
}
}
}
}

5
src/Avalonia.Animation/DoubleAnimator.cs

@ -1,4 +1,7 @@
namespace Avalonia.Animation
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
namespace Avalonia.Animation
{
/// <summary>
/// Animator that handles <see cref="double"/> properties.

5
src/Avalonia.Animation/FillMode.cs

@ -1,4 +1,7 @@
namespace Avalonia.Animation
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
namespace Avalonia.Animation
{
public enum FillMode
{

11
src/Avalonia.Animation/IAnimation.cs

@ -1,3 +1,6 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Threading.Tasks;
@ -9,13 +12,13 @@ namespace Avalonia.Animation
public interface IAnimation
{
/// <summary>
/// Apply the animation to the specified control
/// Apply the animation to the specified control and run it when <paramref name="match" /> produces <c>true</c>.
/// </summary>
IDisposable Apply(Animatable control, IObservable<bool> match, Action onComplete = null);
IDisposable Apply(Animatable control, IClock clock, IObservable<bool> match, Action onComplete = null);
/// <summary>
/// Run the animation to the specified control
/// Run the animation on the specified control.
/// </summary>
Task RunAsync(Animatable control);
Task RunAsync(Animatable control, IClock clock);
}
}

3
src/Avalonia.Animation/IAnimationSetter.cs

@ -1,3 +1,6 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
namespace Avalonia.Animation
{
public interface IAnimationSetter

7
src/Avalonia.Animation/IAnimator.cs

@ -1,4 +1,7 @@
using System;
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Collections.Generic;
namespace Avalonia.Animation
@ -16,6 +19,6 @@ namespace Avalonia.Animation
/// <summary>
/// Applies the current KeyFrame group to the specified control.
/// </summary>
IDisposable Apply(Animation animation, Animatable control, IObservable<bool> obsMatch, Action onComplete);
IDisposable Apply(Animation animation, Animatable control, IClock clock, IObservable<bool> match, Action onComplete);
}
}

11
src/Avalonia.Animation/IClock.cs

@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Avalonia.Animation
{
public interface IClock : IObservable<TimeSpan>
{
PlayState PlayState { get; set; }
}
}

10
src/Avalonia.Animation/IGlobalClock.cs

@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Avalonia.Animation
{
public interface IGlobalClock : IClock
{
}
}

2
src/Avalonia.Animation/ITransition.cs

@ -13,7 +13,7 @@ namespace Avalonia.Animation
/// <summary>
/// Applies the transition to the specified <see cref="Animatable"/>.
/// </summary>
IDisposable Apply(Animatable control, object oldValue, object newValue);
IDisposable Apply(Animatable control, IClock clock, object oldValue, object newValue);
/// <summary>
/// Gets the property to be animated.

5
src/Avalonia.Animation/KeyFrame.cs

@ -1,4 +1,7 @@
using System;
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Collections.Generic;
using Avalonia.Collections;

3
src/Avalonia.Animation/KeyFramePair`1.cs

@ -1,3 +1,6 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
namespace Avalonia.Animation
{
/// <summary>

5
src/Avalonia.Animation/PlayState.cs

@ -1,4 +1,7 @@
namespace Avalonia.Animation
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
namespace Avalonia.Animation
{
/// <summary>
/// Determines the playback state of an animation.

5
src/Avalonia.Animation/PlaybackDirection.cs

@ -1,4 +1,7 @@
namespace Avalonia.Animation
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
namespace Avalonia.Animation
{
/// <summary>
/// Determines the playback direction of an animation.

54
src/Avalonia.Animation/Timing.cs

@ -1,54 +0,0 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Linq;
using System.Reactive.Linq;
using Avalonia.Threading;
namespace Avalonia.Animation
{
/// <summary>
/// Provides global timing functions for animations.
/// </summary>
public static class Timing
{
/// <summary>
/// The number of frames per second.
/// </summary>
public const int FramesPerSecond = 60;
/// <summary>
/// The time span of each frame.
/// </summary>
internal static readonly TimeSpan FrameTick = TimeSpan.FromSeconds(1.0 / FramesPerSecond);
/// <summary>
/// Initializes static members of the <see cref="Timing"/> class.
/// </summary>
static Timing()
{
var globalTimer = Observable.Interval(FrameTick, AvaloniaScheduler.Instance);
AnimationsTimer = globalTimer
.Select(_ => GetTickCount())
.Publish()
.RefCount();
}
internal static TimeSpan GetTickCount() => TimeSpan.FromMilliseconds(Environment.TickCount);
/// <summary>
/// Gets the animation timer.
/// </summary>
/// <remarks>
/// The animation timer triggers usually at 60 times per second or as
/// defined in <see cref="FramesPerSecond"/>.
/// The parameter passed to a subsciber is the current playstate of the animation.
/// </remarks>
internal static IObservable<TimeSpan> AnimationsTimer
{
get;
}
}
}

27
src/Avalonia.Animation/TransitionInstance.cs

@ -15,21 +15,22 @@ namespace Avalonia.Animation
/// </summary>
internal class TransitionInstance : SingleSubscriberObservableBase<double>
{
private IDisposable timerSubscription;
private TimeSpan startTime;
private TimeSpan duration;
private IDisposable _timerSubscription;
private TimeSpan _duration;
private readonly IClock _baseClock;
private IClock _clock;
public TransitionInstance(TimeSpan Duration)
public TransitionInstance(IClock clock, TimeSpan Duration)
{
duration = Duration;
_duration = Duration;
_baseClock = clock;
}
private void TimerTick(TimeSpan t)
{
var interpVal = (double)(t.Ticks - startTime.Ticks) / duration.Ticks;
var interpVal = (double)t.Ticks / _duration.Ticks;
if (interpVal > 1d
|| interpVal < 0d)
if (interpVal > 1d || interpVal < 0d)
{
PublishCompleted();
return;
@ -40,15 +41,15 @@ namespace Avalonia.Animation
protected override void Unsubscribed()
{
timerSubscription?.Dispose();
_timerSubscription?.Dispose();
_clock.PlayState = PlayState.Stop;
}
protected override void Subscribed()
{
startTime = Timing.GetTickCount();
timerSubscription = Timing.AnimationsTimer
.Subscribe(t => TimerTick(t));
_clock = new Clock(_baseClock);
_timerSubscription = _clock.Subscribe(TimerTick);
PublishNext(0.0d);
}
}
}
}

7
src/Avalonia.Animation/Transition`1.cs

@ -14,7 +14,6 @@ namespace Avalonia.Animation
public abstract class Transition<T> : AvaloniaObject, ITransition
{
private AvaloniaProperty _prop;
private Easing _easing;
/// <summary>
/// Gets the duration of the animation.
@ -49,12 +48,10 @@ namespace Avalonia.Animation
public abstract IObservable<T> DoTransition(IObservable<double> progress, T oldValue, T newValue);
/// <inheritdocs/>
public virtual IDisposable Apply(Animatable control, object oldValue, object newValue)
public virtual IDisposable Apply(Animatable control, IClock clock, object oldValue, object newValue)
{
var transition = DoTransition(new TransitionInstance(Duration), (T)oldValue, (T)newValue);
var transition = DoTransition(new TransitionInstance(clock, Duration), (T)oldValue, (T)newValue);
return control.Bind<T>((AvaloniaProperty<T>)Property, transition, Data.BindingPriority.Animation);
}
}
}

1
src/Avalonia.Base/Avalonia.Base.csproj

@ -3,6 +3,7 @@
<TargetFramework>netstandard2.0</TargetFramework>
<AssemblyName>Avalonia.Base</AssemblyName>
<RootNamespace>Avalonia</RootNamespace>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
</PropertyGroup>
<Import Project="..\..\build\Base.props" />
<Import Project="..\..\build\Binding.props" />

18
src/Avalonia.Base/Platform/Interop/IDynamicLibraryLoader.cs

@ -0,0 +1,18 @@
using System;
namespace Avalonia.Platform.Interop
{
public interface IDynamicLibraryLoader
{
IntPtr LoadLibrary(string dll);
IntPtr GetProcAddress(IntPtr dll, string proc, bool optional);
}
public class DynamicLibraryLoaderException : Exception
{
public DynamicLibraryLoaderException(string message) : base(message)
{
}
}
}

4
src/Gtk/Avalonia.Gtk3/Interop/Utf8Buffer.cs → src/Avalonia.Base/Platform/Interop/Utf8Buffer.cs

@ -2,9 +2,9 @@
using System.Runtime.InteropServices;
using System.Text;
namespace Avalonia.Gtk3.Interop
namespace Avalonia.Platform.Interop
{
class Utf8Buffer : SafeHandle
public class Utf8Buffer : SafeHandle
{
private GCHandle _gchandle;
private byte[] _data;

7
src/Avalonia.Base/PriorityBindingEntry.cs

@ -50,6 +50,11 @@ namespace Avalonia
get;
}
/// <summary>
/// Gets a value indicating whether the binding has completed.
/// </summary>
public bool HasCompleted { get; private set; }
/// <summary>
/// The current value of the binding.
/// </summary>
@ -129,6 +134,8 @@ namespace Avalonia
private void Completed()
{
HasCompleted = true;
if (Dispatcher.UIThread.CheckAccess())
{
_owner.Completed(this);

14
src/Avalonia.Base/PriorityLevel.cs

@ -112,12 +112,16 @@ namespace Avalonia
return Disposable.Create(() =>
{
Bindings.Remove(node);
entry.Dispose();
if (entry.Index >= ActiveBindingIndex)
if (!entry.HasCompleted)
{
ActivateFirstBinding();
Bindings.Remove(node);
entry.Dispose();
if (entry.Index >= ActiveBindingIndex)
{
ActivateFirstBinding();
}
}
});
}

10
src/Avalonia.Base/Reactive/LightweightObservableBase.cs

@ -82,18 +82,10 @@ namespace Avalonia.Reactive
if (observers.Count == 0)
{
observers.TrimExcess();
Deinitialize();
}
else
{
return;
}
} else
{
return;
}
}
Deinitialize();
}
}

5
src/Avalonia.Base/Reactive/ObservableEx.cs

@ -21,7 +21,7 @@ namespace Avalonia.Reactive
{
return new SingleValueImpl<T>(value);
}
private class SingleValueImpl<T> : IObservable<T>
{
private T _value;
@ -30,7 +30,6 @@ namespace Avalonia.Reactive
{
_value = value;
}
public IDisposable Subscribe(IObserver<T> observer)
{
observer.OnNext(_value);
@ -38,4 +37,4 @@ namespace Avalonia.Reactive
}
}
}
}
}

2
src/Avalonia.Controls/AppBuilderBase.cs

@ -272,10 +272,10 @@ namespace Avalonia.Controls
s_setupWasAlreadyCalled = true;
Instance.RegisterServices();
RuntimePlatformServicesInitializer();
WindowingSubsystemInitializer();
RenderingSubsystemInitializer();
Instance.RegisterServices();
Instance.Initialize();
AfterSetupCallback(Self);
}

7
src/Avalonia.Controls/Application.cs

@ -4,12 +4,14 @@
using System;
using System.Reactive.Concurrency;
using System.Threading;
using Avalonia.Animation;
using Avalonia.Controls;
using Avalonia.Controls.Templates;
using Avalonia.Input;
using Avalonia.Input.Platform;
using Avalonia.Input.Raw;
using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.Styling;
using Avalonia.Threading;
@ -335,6 +337,11 @@ namespace Avalonia
.Bind<IScheduler>().ToConstant(AvaloniaScheduler.Instance)
.Bind<IDragDropDevice>().ToConstant(DragDropDevice.Instance)
.Bind<IPlatformDragSource>().ToTransient<InProcessDragSource>();
var clock = new RenderLoopClock();
AvaloniaLocator.CurrentMutable
.Bind<IGlobalClock>().ToConstant(clock)
.GetService<IRenderLoop>()?.Add(clock);
}
}
}

6
src/Avalonia.Controls/Border.cs

@ -43,7 +43,11 @@ namespace Avalonia.Controls
/// </summary>
static Border()
{
AffectsRender<Border>(BackgroundProperty, BorderBrushProperty, BorderThicknessProperty, CornerRadiusProperty);
AffectsRender<Border>(
BackgroundProperty,
BorderBrushProperty,
BorderThicknessProperty,
CornerRadiusProperty);
AffectsMeasure<Border>(BorderThicknessProperty);
}

2
src/Avalonia.Controls/DrawingPresenter.cs

@ -49,7 +49,7 @@ namespace Avalonia.Controls
if (Drawing != null)
{
using (context.PushPreTransform(_transform))
using (context.PushClip(Bounds))
using (context.PushClip(new Rect(Bounds.Size)))
{
Drawing.Draw(context);
}

4
src/Avalonia.Controls/Generators/ItemContainerGenerator.cs

@ -15,7 +15,7 @@ namespace Avalonia.Controls.Generators
/// </summary>
public class ItemContainerGenerator : IItemContainerGenerator
{
private Dictionary<int, ItemContainerInfo> _containers = new Dictionary<int, ItemContainerInfo>();
private SortedDictionary<int, ItemContainerInfo> _containers = new SortedDictionary<int, ItemContainerInfo>();
/// <summary>
/// Initializes a new instance of the <see cref="ItemContainerGenerator"/> class.
@ -246,4 +246,4 @@ namespace Avalonia.Controls.Generators
Recycled?.Invoke(this, e);
}
}
}
}

1
src/Avalonia.Controls/Image.cs

@ -26,6 +26,7 @@ namespace Avalonia.Controls
static Image()
{
AffectsRender<Image>(SourceProperty, StretchProperty);
AffectsMeasure<Image>(SourceProperty, StretchProperty);
}
/// <summary>

38
src/Avalonia.Controls/MenuItem.cs

@ -99,6 +99,7 @@ namespace Avalonia.Controls
SelectableMixin.Attach<MenuItem>(IsSelectedProperty);
CommandProperty.Changed.Subscribe(CommandChanged);
FocusableProperty.OverrideDefaultValue<MenuItem>(true);
HeaderProperty.Changed.AddClassHandler<MenuItem>(x => x.HeaderChanged);
IconProperty.Changed.AddClassHandler<MenuItem>(x => x.IconChanged);
IsSelectedProperty.Changed.AddClassHandler<MenuItem>(x => x.IsSelectedChanged);
ItemsPanelProperty.OverrideDefaultValue<MenuItem>(DefaultPanel);
@ -357,10 +358,21 @@ namespace Avalonia.Controls
{
base.OnTemplateApplied(e);
_popup = e.NameScope.Get<Popup>("PART_Popup");
_popup.DependencyResolver = DependencyResolver.Instance;
_popup.Opened += PopupOpened;
_popup.Closed += PopupClosed;
if (_popup != null)
{
_popup.Opened -= PopupOpened;
_popup.Closed -= PopupClosed;
_popup.DependencyResolver = null;
}
_popup = e.NameScope.Find<Popup>("PART_Popup");
if (_popup != null)
{
_popup.DependencyResolver = DependencyResolver.Instance;
_popup.Opened += PopupOpened;
_popup.Closed += PopupClosed;
}
}
/// <summary>
@ -408,6 +420,24 @@ namespace Avalonia.Controls
IsEnabled = Command == null || Command.CanExecute(CommandParameter);
}
/// <summary>
/// Called when the <see cref="Header"/> property changes.
/// </summary>
/// <param name="e">The property change event.</param>
private void HeaderChanged(AvaloniaPropertyChangedEventArgs e)
{
if (e.NewValue is string newValue && newValue == "-")
{
PseudoClasses.Add(":separator");
Focusable = false;
}
else if (e.OldValue is string oldValue && oldValue == "-")
{
PseudoClasses.Remove(":separator");
Focusable = true;
}
}
/// <summary>
/// Called when the <see cref="Icon"/> property changes.
/// </summary>

1
src/Avalonia.Controls/Panel.cs

@ -30,6 +30,7 @@ namespace Avalonia.Controls
/// </summary>
static Panel()
{
AffectsRender<Panel>(BackgroundProperty);
ClipToBoundsProperty.OverrideDefaultValue<Panel>(true);
}

2
src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs

@ -331,7 +331,7 @@ namespace Avalonia.Controls.Platform
{
var item = GetMenuItem(e.Source as IControl);
if (e.MouseButton == MouseButton.Left && item.HasSubMenu == false)
if (e.MouseButton == MouseButton.Left && item?.HasSubMenu == false)
{
Click(item);
e.Handled = true;

11
src/Avalonia.Controls/Platform/InternalPlatformThreadingInterface.cs

@ -9,12 +9,15 @@ using Avalonia.Threading;
namespace Avalonia.Controls.Platform
{
public class InternalPlatformThreadingInterface : IPlatformThreadingInterface, IRenderLoop
public class InternalPlatformThreadingInterface : IPlatformThreadingInterface, IRenderTimer
{
public InternalPlatformThreadingInterface()
{
TlsCurrentThreadIsLoopThread = true;
StartTimer(DispatcherPriority.Render, new TimeSpan(0, 0, 0, 0, 66), () => Tick?.Invoke(this, new EventArgs()));
StartTimer(
DispatcherPriority.Render,
new TimeSpan(0, 0, 0, 0, 66),
() => Tick?.Invoke(TimeSpan.FromMilliseconds(Environment.TickCount)));
}
private readonly AutoResetEvent _signaled = new AutoResetEvent(false);
@ -105,7 +108,7 @@ namespace Avalonia.Controls.Platform
public bool CurrentThreadIsLoopThread => TlsCurrentThreadIsLoopThread;
public event Action<DispatcherPriority?> Signaled;
public event EventHandler<EventArgs> Tick;
public event Action<TimeSpan> Tick;
}
}
}

8
src/Avalonia.Controls/Presenters/ContentPresenter.cs

@ -197,13 +197,6 @@ namespace Avalonia.Controls.Presenters
}
}
/// <inheritdoc/>
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnAttachedToVisualTree(e);
_dataTemplate = null;
}
/// <summary>
/// Updates the <see cref="Child"/> control based on the control's <see cref="Content"/>.
/// </summary>
@ -268,6 +261,7 @@ namespace Avalonia.Controls.Presenters
protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e)
{
base.OnAttachedToLogicalTree(e);
_dataTemplate = null;
_createdChild = false;
InvalidateMeasure();
}

8
src/Avalonia.Controls/Primitives/AdornerLayer.cs

@ -6,11 +6,12 @@ using System.Collections.Specialized;
using System.Linq;
using Avalonia.VisualTree;
using Avalonia.Media;
using Avalonia.Rendering;
namespace Avalonia.Controls.Primitives
{
// TODO: Need to track position of adorned elements and move the adorner if they move.
public class AdornerLayer : Panel
public class AdornerLayer : Panel, ICustomSimpleHitTest
{
public static AttachedProperty<Visual> AdornedElementProperty =
AvaloniaProperty.RegisterAttached<AdornerLayer, Visual, Visual>("AdornedElement");
@ -137,6 +138,11 @@ namespace Avalonia.Controls.Primitives
}
}
public bool HitTest(Point point)
{
return Children.Any(ctrl => ctrl.TransformedBounds?.Contains(point) == true);
}
private class AdornedElementInfo
{
public IDisposable Subscription { get; set; }

8
src/Avalonia.Controls/Primitives/SelectingItemsControl.cs

@ -289,12 +289,12 @@ namespace Avalonia.Controls.Primitives
/// <inheritdoc/>
public override void EndInit()
{
base.EndInit();
if (--_updateCount == 0)
{
UpdateFinished();
}
base.EndInit();
}
/// <summary>
@ -871,8 +871,8 @@ namespace Avalonia.Controls.Primitives
RaisePropertyChanged(SelectedItemProperty, oldItem, item, BindingPriority.LocalValue);
}
added = e.OldItems;
removed = e.NewItems;
added = e.NewItems;
removed = e.OldItems;
break;
}

7
src/Avalonia.Controls/ProgressBar.cs

@ -37,7 +37,8 @@ namespace Avalonia.Controls
PseudoClass<ProgressBar, Orientation>(OrientationProperty, o => o == Avalonia.Controls.Orientation.Horizontal, ":horizontal");
PseudoClass<ProgressBar>(IsIndeterminateProperty, ":indeterminate");
ValueProperty.Changed.AddClassHandler<ProgressBar>(x => x.ValueChanged);
ValueProperty.Changed.AddClassHandler<ProgressBar>(x => x.UpdateIndicatorWhenPropChanged);
IsIndeterminateProperty.Changed.AddClassHandler<ProgressBar>(x => x.UpdateIndicatorWhenPropChanged);
}
public bool IsIndeterminate
@ -114,9 +115,9 @@ namespace Avalonia.Controls
}
}
private void ValueChanged(AvaloniaPropertyChangedEventArgs e)
private void UpdateIndicatorWhenPropChanged(AvaloniaPropertyChangedEventArgs e)
{
UpdateIndicator(Bounds.Size);
}
}
}
}

4
src/Avalonia.Controls/TextBlock.cs

@ -6,6 +6,7 @@ using System.Reactive;
using System.Reactive.Linq;
using Avalonia.LogicalTree;
using Avalonia.Media;
using Avalonia.Media.Immutable;
using Avalonia.Metadata;
namespace Avalonia.Controls
@ -65,7 +66,7 @@ namespace Avalonia.Controls
public static readonly AttachedProperty<IBrush> ForegroundProperty =
AvaloniaProperty.RegisterAttached<TextBlock, Control, IBrush>(
nameof(Foreground),
new SolidColorBrush(0xff000000),
Brushes.Black,
inherits: true);
/// <summary>
@ -100,6 +101,7 @@ namespace Avalonia.Controls
{
ClipToBoundsProperty.OverrideDefaultValue<TextBlock>(true);
AffectsRender<TextBlock>(
BackgroundProperty,
ForegroundProperty,
FontWeightProperty,
FontSizeProperty,

5
src/Avalonia.Controls/TextBox.cs

@ -212,7 +212,10 @@ namespace Avalonia.Controls
{
if (!_ignoreTextChanges)
{
CaretIndex = CoerceCaretIndex(CaretIndex, value?.Length ?? 0);
var caretIndex = CaretIndex;
SelectionStart = CoerceCaretIndex(SelectionStart, value?.Length ?? 0);
SelectionEnd = CoerceCaretIndex(SelectionEnd, value?.Length ?? 0);
CaretIndex = CoerceCaretIndex(caretIndex, value?.Length ?? 0);
if (SetAndRaise(TextProperty, ref _text, value) && !_isUndoingRedoing)
{

1
src/Avalonia.Controls/TopLevel.cs

@ -96,7 +96,6 @@ namespace Avalonia.Controls
_applicationLifecycle = TryGetService<IApplicationLifecycle>(dependencyResolver);
_renderInterface = TryGetService<IPlatformRenderInterface>(dependencyResolver);
var renderLoop = TryGetService<IRenderLoop>(dependencyResolver);
Renderer = impl.CreateRenderer(this);
impl.SetInputRoot(this);

156
src/Avalonia.Controls/Utils/BorderRenderHelper.cs

@ -88,24 +88,82 @@ namespace Avalonia.Controls.Utils
}
else
{
var borderThickness = borders.Left;
var cornerRadius = (float)radii.TopLeft;
var rect = new Rect(size);
var borderThickness = borders.Top;
var top = borderThickness * 0.5;
var cornerRadius = (float)Math.Max(0, radii.TopLeft - borderThickness - top);
if (background != null)
{
context.FillRectangle(background, rect.Deflate(borders), cornerRadius);
var topLeft = new Point(borders.Left, borders.Top);
var bottomRight = new Point(size.Width - borders.Right, size.Height - borders.Bottom);
var innerRect = new Rect(topLeft, bottomRight);
context.FillRectangle(background, innerRect, cornerRadius);
}
if (borderBrush != null && borderThickness > 0)
{
context.DrawRectangle(new Pen(borderBrush, borderThickness), rect.Deflate(borderThickness), cornerRadius);
var topLeft = new Point(top, top);
var bottomRight = new Point(size.Width - top, size.Height - top);
var outerRect = new Rect(topLeft, bottomRight);
context.DrawRectangle(new Pen(borderBrush, borderThickness), outerRect, (float)radii.TopLeft);
}
}
}
private static void CreateGeometry(StreamGeometryContext context, Rect boundRect, BorderGeometryKeypoints keypoints)
{
context.BeginFigure(keypoints.TopLeft, true);
// Top
context.LineTo(keypoints.TopRight);
// TopRight corner
var radiusX = boundRect.TopRight.X - keypoints.TopRight.X;
var radiusY = keypoints.RightTop.Y - boundRect.TopRight.Y;
if (radiusX != 0 || radiusY != 0)
{
context.ArcTo(keypoints.RightTop, new Size(radiusY, radiusY), 0, false, SweepDirection.Clockwise);
}
// Right
context.LineTo(keypoints.RightBottom);
// BottomRight corner
radiusX = boundRect.BottomRight.X - keypoints.BottomRight.X;
radiusY = boundRect.BottomRight.Y - keypoints.RightBottom.Y;
if (radiusX != 0 || radiusY != 0)
{
context.ArcTo(keypoints.BottomRight, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise);
}
// Bottom
context.LineTo(keypoints.BottomLeft);
// BottomLeft corner
radiusX = keypoints.BottomLeft.X - boundRect.BottomLeft.X;
radiusY = boundRect.BottomLeft.Y - keypoints.LeftBottom.Y;
if (radiusX != 0 || radiusY != 0)
{
context.ArcTo(keypoints.LeftBottom, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise);
}
// Left
context.LineTo(keypoints.LeftTop);
// TopLeft corner
radiusX = keypoints.TopLeft.X - boundRect.TopLeft.X;
radiusY = keypoints.LeftTop.Y - boundRect.TopLeft.Y;
if (radiusX != 0 || radiusY != 0)
{
context.ArcTo(keypoints.TopLeft, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise);
}
context.EndFigure(true);
}
private class BorderGeometryKeypoints
{
{
internal BorderGeometryKeypoints(Rect boundRect, Thickness borderThickness, CornerRadius cornerRadius, bool inner)
{
var left = 0.5 * borderThickness.Left;
@ -135,25 +193,24 @@ namespace Avalonia.Controls.Utils
}
else
{
leftTopY = cornerRadius.TopLeft + top + boundRect.TopLeft.Y;
topLeftX = cornerRadius.TopLeft + left + boundRect.TopLeft.X;
topLeftX = cornerRadius.TopLeft + left + boundRect.TopLeft.X;
topRightX = boundRect.Width - (cornerRadius.TopRight + right) + boundRect.TopLeft.X;
rightTopY = cornerRadius.TopRight + top + boundRect.TopLeft.Y;
rightTopY = cornerRadius.TopRight + top + boundRect.TopLeft.Y;
rightBottomY = boundRect.Height - (cornerRadius.BottomRight + bottom) + boundRect.TopLeft.Y;
bottomRightX = boundRect.Width - (cornerRadius.BottomRight + right) + boundRect.TopLeft.X;
bottomLeftX = cornerRadius.BottomLeft + left + boundRect.TopLeft.X;
bottomRightX = boundRect.Width - (cornerRadius.BottomRight + right) + boundRect.TopLeft.X;
bottomLeftX = cornerRadius.BottomLeft + left + boundRect.TopLeft.X;
leftBottomY = boundRect.Height - (cornerRadius.BottomLeft + bottom) + boundRect.TopLeft.Y;
}
}
var leftTopX = boundRect.TopLeft.X;
var topLeftY = boundRect.TopLeft.Y;
var leftTopX = boundRect.TopLeft.X;
var topLeftY = boundRect.TopLeft.Y;
var topRightY = boundRect.TopLeft.Y;
var rightTopX = boundRect.Width + boundRect.TopLeft.X;
var rightBottomX = boundRect.Width + boundRect.TopLeft.X;
var bottomRightY = boundRect.Height + boundRect.TopLeft.Y;
var rightTopX = boundRect.Width + boundRect.TopLeft.X;
var rightBottomX = boundRect.Width + boundRect.TopLeft.X;
var bottomRightY = boundRect.Height + boundRect.TopLeft.Y;
var bottomLeftY = boundRect.Height + boundRect.TopLeft.Y;
var leftBottomX = boundRect.TopLeft.X;
var leftBottomX = boundRect.TopLeft.X;
LeftTop = new Point(leftTopX, leftTopY);
TopLeft = new Point(topLeftX, topLeftY);
@ -164,7 +221,7 @@ namespace Avalonia.Controls.Utils
BottomLeft = new Point(bottomLeftX, bottomLeftY);
LeftBottom = new Point(leftBottomX, leftBottomY);
//Fix overlap
// Fix overlap
if (TopLeft.X > TopRight.X)
{
var scaledX = topLeftX / (topLeftX + topRightX) * boundRect.Width;
@ -194,66 +251,21 @@ namespace Avalonia.Controls.Utils
}
}
internal Point LeftTop { get; private set; }
internal Point TopLeft { get; private set; }
internal Point TopRight { get; private set; }
internal Point RightTop { get; private set; }
internal Point RightBottom { get; private set; }
internal Point BottomRight { get; private set; }
internal Point BottomLeft { get; private set; }
internal Point LeftBottom { get; private set; }
}
internal Point LeftTop { get; }
private static void CreateGeometry(StreamGeometryContext context, Rect boundRect, BorderGeometryKeypoints keypoints)
{
context.BeginFigure(keypoints.TopLeft, true);
internal Point TopLeft { get; }
//Top
context.LineTo(keypoints.TopRight);
internal Point TopRight { get; }
//TopRight corner
var radiusX = boundRect.TopRight.X - keypoints.TopRight.X;
var radiusY = keypoints.RightTop.Y - boundRect.TopRight.Y;
if (radiusX != 0 || radiusY != 0)
{
context.ArcTo(keypoints.RightTop, new Size(radiusY, radiusY), 0, false, SweepDirection.Clockwise);
}
internal Point RightTop { get; }
//Right
context.LineTo(keypoints.RightBottom);
internal Point RightBottom { get; }
//BottomRight corner
radiusX = boundRect.BottomRight.X - keypoints.BottomRight.X;
radiusY = boundRect.BottomRight.Y - keypoints.RightBottom.Y;
if (radiusX != 0 || radiusY != 0)
{
context.ArcTo(keypoints.BottomRight, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise);
}
//Bottom
context.LineTo(keypoints.BottomLeft);
//BottomLeft corner
radiusX = keypoints.BottomLeft.X - boundRect.BottomLeft.X;
radiusY = boundRect.BottomLeft.Y - keypoints.LeftBottom.Y;
if (radiusX != 0 || radiusY != 0)
{
context.ArcTo(keypoints.LeftBottom, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise);
}
internal Point BottomRight { get; }
//Left
context.LineTo(keypoints.LeftTop);
//TopLeft corner
radiusX = keypoints.TopLeft.X - boundRect.TopLeft.X;
radiusY = keypoints.LeftTop.Y - boundRect.TopLeft.Y;
if (radiusX != 0 || radiusY != 0)
{
context.ArcTo(keypoints.TopLeft, new Size(radiusX, radiusY), 0, false, SweepDirection.Clockwise);
}
internal Point BottomLeft { get; }
context.EndFigure(true);
internal Point LeftBottom { get; }
}
}
}

3
src/Avalonia.DesignerSupport/Remote/PreviewerWindowingPlatform.cs

@ -53,7 +53,8 @@ namespace Avalonia.DesignerSupport.Remote
.Bind<IKeyboardDevice>().ToConstant(Keyboard)
.Bind<IPlatformSettings>().ToConstant(instance)
.Bind<IPlatformThreadingInterface>().ToConstant(threading)
.Bind<IRenderLoop>().ToConstant(threading)
.Bind<IRenderLoop>().ToConstant(new RenderLoop())
.Bind<IRenderTimer>().ToConstant(threading)
.Bind<ISystemDialogImpl>().ToSingleton<SystemDialogsStub>()
.Bind<IWindowingPlatform>().ToConstant(instance)
.Bind<IPlatformIconLoader>().ToSingleton<IconLoaderStub>();

8
src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj

@ -2,6 +2,9 @@
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<None Remove="Views\EventsView.xaml" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Markup\Avalonia.Markup.Xaml\Avalonia.Markup.Xaml.csproj" />
<ProjectReference Include="..\Markup\Avalonia.Markup\Avalonia.Markup.csproj" />
@ -17,4 +20,9 @@
</ItemGroup>
<Import Project="..\..\build\EmbedXaml.props" />
<Import Project="..\..\build\Rx.props" />
<ItemGroup>
<EmbeddedResource Update="Views\EventsView.xaml">
<Generator>MSBuild:Compile</Generator>
</EmbeddedResource>
</ItemGroup>
</Project>

1
src/Avalonia.Diagnostics/DevTools.xaml

@ -3,6 +3,7 @@
<TabStrip SelectedIndex="{Binding SelectedTab, Mode=TwoWay}">
<TabStripItem Content="Logical Tree"/>
<TabStripItem Content="Visual Tree"/>
<TabStripItem Content="Events"/>
</TabStrip>
<ContentControl Content="{Binding Content}" Grid.Row="1"/>

23
src/Avalonia.Diagnostics/DevTools.xaml.cs

@ -10,6 +10,7 @@ using Avalonia.Input;
using Avalonia.Input.Raw;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
using Avalonia.Rendering;
using Avalonia.VisualTree;
namespace Avalonia
@ -28,6 +29,7 @@ namespace Avalonia.Diagnostics
public class DevTools : UserControl
{
private static Dictionary<TopLevel, Window> s_open = new Dictionary<TopLevel, Window>();
private static HashSet<IRenderRoot> s_visualTreeRoots = new HashSet<IRenderRoot>();
private IDisposable _keySubscription;
public DevTools(IControl root)
@ -79,6 +81,7 @@ namespace Avalonia.Diagnostics
devToolsWindow.Closed += devTools.DevToolsClosed;
s_open.Add(control, devToolsWindow);
MarkAsDevTool(devToolsWindow);
devToolsWindow.Show();
}
}
@ -89,6 +92,7 @@ namespace Avalonia.Diagnostics
var devToolsWindow = (Window)sender;
var devTools = (DevTools)devToolsWindow.Content;
s_open.Remove((TopLevel)devTools.Root);
RemoveDevTool(devToolsWindow);
_keySubscription.Dispose();
devToolsWindow.Closed -= DevToolsClosed;
}
@ -116,5 +120,24 @@ namespace Avalonia.Diagnostics
}
}
}
/// <summary>
/// Marks a visual as part of the DevTools, so it can be excluded from event tracking.
/// </summary>
/// <param name="visual">The visual whose root is to be marked.</param>
public static void MarkAsDevTool(IVisual visual)
{
s_visualTreeRoots.Add(visual.GetVisualRoot());
}
public static void RemoveDevTool(IVisual visual)
{
s_visualTreeRoots.Remove(visual.GetVisualRoot());
}
public static bool BelongsToDevTool(IVisual visual)
{
return s_visualTreeRoots.Contains(visual.GetVisualRoot());
}
}
}

38
src/Avalonia.Diagnostics/Models/EventChainLink.cs

@ -0,0 +1,38 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using Avalonia.Interactivity;
namespace Avalonia.Diagnostics.Models
{
internal class EventChainLink
{
public EventChainLink(object handler, bool handled, RoutingStrategies route)
{
Contract.Requires<ArgumentNullException>(handler != null);
this.Handler = handler;
this.Handled = handled;
this.Route = route;
}
public object Handler { get; }
public string HandlerName
{
get
{
if (Handler is INamed named && !string.IsNullOrEmpty(named.Name))
{
return named.Name + " (" + Handler.GetType().Name + ")";
}
return Handler.GetType().Name;
}
}
public bool Handled { get; }
public RoutingStrategies Route { get; }
}
}

5
src/Avalonia.Diagnostics/ViewModels/DevToolsViewModel.cs

@ -14,6 +14,7 @@ namespace Avalonia.Diagnostics.ViewModels
private int _selectedTab;
private TreePageViewModel _logicalTree;
private TreePageViewModel _visualTree;
private EventsViewModel _eventsView;
private string _focusedControl;
private string _pointerOverElement;
@ -21,6 +22,7 @@ namespace Avalonia.Diagnostics.ViewModels
{
_logicalTree = new TreePageViewModel(LogicalTreeNode.Create(root));
_visualTree = new TreePageViewModel(VisualTreeNode.Create(root));
_eventsView = new EventsViewModel(root);
UpdateFocusedControl();
KeyboardDevice.Instance.PropertyChanged += (s, e) =>
@ -57,6 +59,9 @@ namespace Avalonia.Diagnostics.ViewModels
case 1:
Content = _visualTree;
break;
case 2:
Content = _eventsView;
break;
}
RaisePropertyChanged();

61
src/Avalonia.Diagnostics/ViewModels/EventOwnerTreeNode.cs

@ -0,0 +1,61 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.Linq;
using Avalonia.Collections;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Interactivity;
namespace Avalonia.Diagnostics.ViewModels
{
internal class EventOwnerTreeNode : EventTreeNodeBase
{
private static readonly RoutedEvent[] s_defaultEvents = new RoutedEvent[]
{
Button.ClickEvent,
InputElement.KeyDownEvent,
InputElement.KeyUpEvent,
InputElement.TextInputEvent,
InputElement.PointerReleasedEvent,
InputElement.PointerPressedEvent,
};
public EventOwnerTreeNode(Type type, IEnumerable<RoutedEvent> events, EventsViewModel vm)
: base(null, type.Name)
{
this.Children = new AvaloniaList<EventTreeNodeBase>(events.OrderBy(e => e.Name)
.Select(e => new EventTreeNode(this, e, vm) { IsEnabled = s_defaultEvents.Contains(e) }));
this.IsExpanded = true;
}
public override bool? IsEnabled
{
get => base.IsEnabled;
set
{
if (base.IsEnabled != value)
{
base.IsEnabled = value;
if (_updateChildren && value != null)
{
foreach (var child in Children)
{
try
{
child._updateParent = false;
child.IsEnabled = value;
}
finally
{
child._updateParent = true;
}
}
}
}
}
}
}
}

98
src/Avalonia.Diagnostics/ViewModels/EventTreeNode.cs

@ -0,0 +1,98 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using Avalonia.Diagnostics.Models;
using Avalonia.Interactivity;
using Avalonia.Threading;
using Avalonia.VisualTree;
namespace Avalonia.Diagnostics.ViewModels
{
internal class EventTreeNode : EventTreeNodeBase
{
private RoutedEvent _event;
private EventsViewModel _parentViewModel;
private bool _isRegistered;
private FiredEvent _currentEvent;
public EventTreeNode(EventOwnerTreeNode parent, RoutedEvent @event, EventsViewModel vm)
: base(parent, @event.Name)
{
Contract.Requires<ArgumentNullException>(@event != null);
Contract.Requires<ArgumentNullException>(vm != null);
this._event = @event;
this._parentViewModel = vm;
}
public override bool? IsEnabled
{
get => base.IsEnabled;
set
{
if (base.IsEnabled != value)
{
base.IsEnabled = value;
UpdateTracker();
if (Parent != null && _updateParent)
{
try
{
Parent._updateChildren = false;
Parent.UpdateChecked();
}
finally
{
Parent._updateChildren = true;
}
}
}
}
}
private void UpdateTracker()
{
if (IsEnabled.GetValueOrDefault() && !_isRegistered)
{
_event.AddClassHandler(typeof(object), HandleEvent, (RoutingStrategies)7, handledEventsToo: true);
_isRegistered = true;
}
}
private void HandleEvent(object sender, RoutedEventArgs e)
{
if (!_isRegistered || IsEnabled == false)
return;
if (sender is IVisual v && DevTools.BelongsToDevTool(v))
return;
var s = sender;
var handled = e.Handled;
var route = e.Route;
Action handler = delegate
{
if (_currentEvent == null || !_currentEvent.IsPartOfSameEventChain(e))
{
_currentEvent = new FiredEvent(e, new EventChainLink(s, handled, route));
_parentViewModel.RecordedEvents.Add(_currentEvent);
while (_parentViewModel.RecordedEvents.Count > 100)
_parentViewModel.RecordedEvents.RemoveAt(0);
}
else
{
_currentEvent.AddToChain(new EventChainLink(s, handled, route));
}
};
if (!Dispatcher.UIThread.CheckAccess())
Dispatcher.UIThread.Post(handler);
else
handler();
}
}
}

78
src/Avalonia.Diagnostics/ViewModels/EventTreeNodeBase.cs

@ -0,0 +1,78 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using Avalonia.Collections;
namespace Avalonia.Diagnostics.ViewModels
{
internal abstract class EventTreeNodeBase : ViewModelBase
{
internal bool _updateChildren = true;
internal bool _updateParent = true;
private bool _isExpanded;
private bool? _isEnabled = false;
public EventTreeNodeBase(EventTreeNodeBase parent, string text)
{
this.Parent = parent;
this.Text = text;
}
public IAvaloniaReadOnlyList<EventTreeNodeBase> Children
{
get;
protected set;
}
public bool IsExpanded
{
get { return _isExpanded; }
set { RaiseAndSetIfChanged(ref _isExpanded, value); }
}
public virtual bool? IsEnabled
{
get { return _isEnabled; }
set { RaiseAndSetIfChanged(ref _isEnabled, value); }
}
public EventTreeNodeBase Parent
{
get;
}
public string Text
{
get;
private set;
}
internal void UpdateChecked()
{
IsEnabled = GetValue();
bool? GetValue()
{
if (Children == null)
return false;
bool? value = false;
for (int i = 0; i < Children.Count; i++)
{
if (i == 0)
{
value = Children[i].IsEnabled;
continue;
}
if (value != Children[i].IsEnabled)
{
value = null;
break;
}
}
return value;
}
}
}
}

60
src/Avalonia.Diagnostics/ViewModels/EventsViewModel.cs

@ -0,0 +1,60 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Linq;
using System.Windows.Input;
using Avalonia.Controls;
using Avalonia.Data.Converters;
using Avalonia.Interactivity;
using Avalonia.Media;
namespace Avalonia.Diagnostics.ViewModels
{
internal class EventsViewModel : ViewModelBase
{
private readonly IControl _root;
private FiredEvent _selectedEvent;
public EventsViewModel(IControl root)
{
this._root = root;
this.Nodes = RoutedEventRegistry.Instance.GetAllRegistered()
.GroupBy(e => e.OwnerType)
.OrderBy(e => e.Key.Name)
.Select(g => new EventOwnerTreeNode(g.Key, g, this))
.ToArray();
}
public EventTreeNodeBase[] Nodes { get; }
public ObservableCollection<FiredEvent> RecordedEvents { get; } = new ObservableCollection<FiredEvent>();
public FiredEvent SelectedEvent
{
get => _selectedEvent;
set => RaiseAndSetIfChanged(ref _selectedEvent, value);
}
private void Clear()
{
RecordedEvents.Clear();
}
}
internal class BoolToBrushConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (bool)value ? Brushes.LightGreen : Brushes.Transparent;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

80
src/Avalonia.Diagnostics/ViewModels/FiredEvent.cs

@ -0,0 +1,80 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Collections.ObjectModel;
using Avalonia.Diagnostics.Models;
using Avalonia.Interactivity;
namespace Avalonia.Diagnostics.ViewModels
{
internal class FiredEvent : ViewModelBase
{
private RoutedEventArgs _eventArgs;
private EventChainLink _handledBy;
public FiredEvent(RoutedEventArgs eventArgs, EventChainLink originator)
{
Contract.Requires<ArgumentNullException>(eventArgs != null);
Contract.Requires<ArgumentNullException>(originator != null);
this._eventArgs = eventArgs;
this.Originator = originator;
AddToChain(originator);
}
public bool IsPartOfSameEventChain(RoutedEventArgs e)
{
return e == _eventArgs;
}
public RoutedEvent Event => _eventArgs.RoutedEvent;
public bool IsHandled => HandledBy?.Handled == true;
public ObservableCollection<EventChainLink> EventChain { get; } = new ObservableCollection<EventChainLink>();
public string DisplayText
{
get
{
if (IsHandled)
{
return $"{Event.Name} on {Originator.HandlerName};" + Environment.NewLine +
$"strategies: {Event.RoutingStrategies}; handled by: {HandledBy.HandlerName}";
}
return $"{Event.Name} on {Originator.HandlerName}; strategies: {Event.RoutingStrategies}";
}
}
public EventChainLink Originator { get; }
public EventChainLink HandledBy
{
get { return _handledBy; }
set
{
if (_handledBy != value)
{
_handledBy = value;
RaisePropertyChanged();
RaisePropertyChanged(nameof(IsHandled));
RaisePropertyChanged(nameof(DisplayText));
}
}
}
public void AddToChain(object handler, bool handled, RoutingStrategies route)
{
AddToChain(new EventChainLink(handler, handled, route));
}
public void AddToChain(EventChainLink link)
{
EventChain.Add(link);
if (HandledBy == null && link.Handled)
HandledBy = link;
}
}
}

53
src/Avalonia.Diagnostics/Views/EventsView.xaml

@ -0,0 +1,53 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:Avalonia.Diagnostics.ViewModels">
<UserControl.Resources>
<vm:BoolToBrushConverter x:Key="boolToBrush" />
</UserControl.Resources>
<Grid ColumnDefinitions="*,4,3*">
<TreeView Name="tree" Items="{Binding Nodes}" SelectedItem="{Binding SelectedNode, Mode=TwoWay}" Grid.RowSpan="2">
<TreeView.DataTemplates>
<TreeDataTemplate DataType="vm:EventTreeNodeBase"
ItemsSource="{Binding Children}">
<CheckBox Content="{Binding Text}" IsChecked="{Binding IsEnabled, Mode=TwoWay}" />
</TreeDataTemplate>
</TreeView.DataTemplates>
<TreeView.Styles>
<Style Selector="TreeViewItem">
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}"/>
</Style>
</TreeView.Styles>
</TreeView>
<GridSplitter Width="4" Grid.Column="1" />
<Grid RowDefinitions="*,4,2*,Auto" Grid.Column="2">
<ListBox Name="eventsList" Items="{Binding RecordedEvents}" SelectedItem="{Binding SelectedEvent, Mode=TwoWay}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Background="{Binding IsHandled, Converter={StaticResource boolToBrush}}" Text="{Binding DisplayText}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<GridSplitter Height="4" Grid.Row="1" />
<DockPanel Grid.Row="2" LastChildFill="True">
<TextBlock DockPanel.Dock="Top" FontSize="16" Text="Event chain:" />
<ListBox Items="{Binding SelectedEvent.EventChain}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Background="{Binding Handled, Converter={StaticResource boolToBrush}}">
<TextBlock Text="{Binding Route}" />
<TextBlock Text=": " />
<TextBlock Text="{Binding HandlerName}" />
<TextBlock Text=" handled: " />
<TextBlock Text="{Binding Handled}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DockPanel>
<StackPanel Orientation="Horizontal" Grid.Row="3">
<Button Content="Clear" Margin="3" Command="{Binding Clear}" />
</StackPanel>
</Grid>
</Grid>
</UserControl>

32
src/Avalonia.Diagnostics/Views/EventsView.xaml.cs

@ -0,0 +1,32 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System.Linq;
using Avalonia.Controls;
using Avalonia.Diagnostics.ViewModels;
using Avalonia.Markup.Xaml;
namespace Avalonia.Diagnostics.Views
{
public class EventsView : UserControl
{
private ListBox _events;
public EventsView()
{
this.InitializeComponent();
_events = this.FindControl<ListBox>("events");
}
private void RecordedEvents_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
_events.ScrollIntoView(_events.Items.OfType<FiredEvent>().LastOrDefault());
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
}

12
src/Avalonia.OpenGL/Avalonia.OpenGL.csproj

@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Avalonia.Base\Avalonia.Base.csproj" />
<ProjectReference Include="..\Avalonia.Visuals\Avalonia.Visuals.csproj" />
</ItemGroup>
</Project>

196
src/Avalonia.OpenGL/EglConsts.cs

@ -0,0 +1,196 @@
// ReSharper disable UnusedMember.Global
// ReSharper disable IdentifierTypo
namespace Avalonia.OpenGL
{
public static class EglConsts
{
public const int EGL_ALPHA_SIZE = 0x3021;
public const int EGL_BAD_ACCESS = 0x3002;
public const int EGL_BAD_ALLOC = 0x3003;
public const int EGL_BAD_ATTRIBUTE = 0x3004;
public const int EGL_BAD_CONFIG = 0x3005;
public const int EGL_BAD_CONTEXT = 0x3006;
public const int EGL_BAD_CURRENT_SURFACE = 0x3007;
public const int EGL_BAD_DISPLAY = 0x3008;
public const int EGL_BAD_MATCH = 0x3009;
public const int EGL_BAD_NATIVE_PIXMAP = 0x300A;
public const int EGL_BAD_NATIVE_WINDOW = 0x300B;
public const int EGL_BAD_PARAMETER = 0x300C;
public const int EGL_BAD_SURFACE = 0x300D;
public const int EGL_BLUE_SIZE = 0x3022;
public const int EGL_BUFFER_SIZE = 0x3020;
public const int EGL_CONFIG_CAVEAT = 0x3027;
public const int EGL_CONFIG_ID = 0x3028;
public const int EGL_CORE_NATIVE_ENGINE = 0x305B;
public const int EGL_DEPTH_SIZE = 0x3025;
public const int EGL_DONT_CARE = -1;
public const int EGL_DRAW = 0x3059;
public const int EGL_EXTENSIONS = 0x3055;
public const int EGL_FALSE = 0;
public const int EGL_GREEN_SIZE = 0x3023;
public const int EGL_HEIGHT = 0x3056;
public const int EGL_LARGEST_PBUFFER = 0x3058;
public const int EGL_LEVEL = 0x3029;
public const int EGL_MAX_PBUFFER_HEIGHT = 0x302A;
public const int EGL_MAX_PBUFFER_PIXELS = 0x302B;
public const int EGL_MAX_PBUFFER_WIDTH = 0x302C;
public const int EGL_NATIVE_RENDERABLE = 0x302D;
public const int EGL_NATIVE_VISUAL_ID = 0x302E;
public const int EGL_NATIVE_VISUAL_TYPE = 0x302F;
public const int EGL_NONE = 0x3038;
public const int EGL_NON_CONFORMANT_CONFIG = 0x3051;
public const int EGL_NOT_INITIALIZED = 0x3001;
public const int EGL_NO_CONTEXT = 0;
public const int EGL_NO_DISPLAY = 0;
public const int EGL_NO_SURFACE = 0;
public const int EGL_PBUFFER_BIT = 0x0001;
public const int EGL_PIXMAP_BIT = 0x0002;
public const int EGL_READ = 0x305A;
public const int EGL_RED_SIZE = 0x3024;
public const int EGL_SAMPLES = 0x3031;
public const int EGL_SAMPLE_BUFFERS = 0x3032;
public const int EGL_SLOW_CONFIG = 0x3050;
public const int EGL_STENCIL_SIZE = 0x3026;
public const int EGL_SUCCESS = 0x3000;
public const int EGL_SURFACE_TYPE = 0x3033;
public const int EGL_TRANSPARENT_BLUE_VALUE = 0x3035;
public const int EGL_TRANSPARENT_GREEN_VALUE = 0x3036;
public const int EGL_TRANSPARENT_RED_VALUE = 0x3037;
public const int EGL_TRANSPARENT_RGB = 0x3052;
public const int EGL_TRANSPARENT_TYPE = 0x3034;
public const int EGL_TRUE = 1;
public const int EGL_VENDOR = 0x3053;
public const int EGL_VERSION = 0x3054;
public const int EGL_WIDTH = 0x3057;
public const int EGL_WINDOW_BIT = 0x0004;
public const int EGL_BACK_BUFFER = 0x3084;
public const int EGL_BIND_TO_TEXTURE_RGB = 0x3039;
public const int EGL_BIND_TO_TEXTURE_RGBA = 0x303A;
public const int EGL_CONTEXT_LOST = 0x300E;
public const int EGL_MIN_SWAP_INTERVAL = 0x303B;
public const int EGL_MAX_SWAP_INTERVAL = 0x303C;
public const int EGL_MIPMAP_TEXTURE = 0x3082;
public const int EGL_MIPMAP_LEVEL = 0x3083;
public const int EGL_NO_TEXTURE = 0x305C;
public const int EGL_TEXTURE_2D = 0x305F;
public const int EGL_TEXTURE_FORMAT = 0x3080;
public const int EGL_TEXTURE_RGB = 0x305D;
public const int EGL_TEXTURE_RGBA = 0x305E;
public const int EGL_TEXTURE_TARGET = 0x3081;
public const int EGL_ALPHA_FORMAT = 0x3088;
public const int EGL_ALPHA_FORMAT_NONPRE = 0x308B;
public const int EGL_ALPHA_FORMAT_PRE = 0x308C;
public const int EGL_ALPHA_MASK_SIZE = 0x303E;
public const int EGL_BUFFER_PRESERVED = 0x3094;
public const int EGL_BUFFER_DESTROYED = 0x3095;
public const int EGL_CLIENT_APIS = 0x308D;
public const int EGL_COLORSPACE = 0x3087;
public const int EGL_COLORSPACE_sRGB = 0x3089;
public const int EGL_COLORSPACE_LINEAR = 0x308A;
public const int EGL_COLOR_BUFFER_TYPE = 0x303F;
public const int EGL_CONTEXT_CLIENT_TYPE = 0x3097;
public const int EGL_DISPLAY_SCALING = 10000;
public const int EGL_HORIZONTAL_RESOLUTION = 0x3090;
public const int EGL_LUMINANCE_BUFFER = 0x308F;
public const int EGL_LUMINANCE_SIZE = 0x303D;
public const int EGL_OPENGL_ES_BIT = 0x0001;
public const int EGL_OPENVG_BIT = 0x0002;
public const int EGL_OPENGL_ES_API = 0x30A0;
public const int EGL_OPENVG_API = 0x30A1;
public const int EGL_OPENVG_IMAGE = 0x3096;
public const int EGL_PIXEL_ASPECT_RATIO = 0x3092;
public const int EGL_RENDERABLE_TYPE = 0x3040;
public const int EGL_RENDER_BUFFER = 0x3086;
public const int EGL_RGB_BUFFER = 0x308E;
public const int EGL_SINGLE_BUFFER = 0x3085;
public const int EGL_SWAP_BEHAVIOR = 0x3093;
public const int EGL_UNKNOWN = -1;
public const int EGL_VERTICAL_RESOLUTION = 0x3091;
public const int EGL_CONFORMANT = 0x3042;
public const int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
public const int EGL_MATCH_NATIVE_PIXMAP = 0x3041;
public const int EGL_OPENGL_ES2_BIT = 0x0004;
public const int EGL_VG_ALPHA_FORMAT = 0x3088;
public const int EGL_VG_ALPHA_FORMAT_NONPRE = 0x308B;
public const int EGL_VG_ALPHA_FORMAT_PRE = 0x308C;
public const int EGL_VG_ALPHA_FORMAT_PRE_BIT = 0x0040;
public const int EGL_VG_COLORSPACE = 0x3087;
public const int EGL_VG_COLORSPACE_sRGB = 0x3089;
public const int EGL_VG_COLORSPACE_LINEAR = 0x308A;
public const int EGL_VG_COLORSPACE_LINEAR_BIT = 0x0020;
public const int EGL_DEFAULT_DISPLAY = 0;
public const int EGL_MULTISAMPLE_RESOLVE_BOX_BIT = 0x0200;
public const int EGL_MULTISAMPLE_RESOLVE = 0x3099;
public const int EGL_MULTISAMPLE_RESOLVE_DEFAULT = 0x309A;
public const int EGL_MULTISAMPLE_RESOLVE_BOX = 0x309B;
public const int EGL_OPENGL_API = 0x30A2;
public const int EGL_OPENGL_BIT = 0x0008;
public const int EGL_SWAP_BEHAVIOR_PRESERVED_BIT = 0x0400;
public const int EGL_CONTEXT_MAJOR_VERSION = 0x3098;
public const int EGL_CONTEXT_MINOR_VERSION = 0x30FB;
public const int EGL_CONTEXT_OPENGL_PROFILE_MASK = 0x30FD;
public const int EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY = 0x31BD;
public const int EGL_NO_RESET_NOTIFICATION = 0x31BE;
public const int EGL_LOSE_CONTEXT_ON_RESET = 0x31BF;
public const int EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT = 0x00000001;
public const int EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT = 0x00000002;
public const int EGL_CONTEXT_OPENGL_DEBUG = 0x31B0;
public const int EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE = 0x31B1;
public const int EGL_CONTEXT_OPENGL_ROBUST_ACCESS = 0x31B2;
public const int EGL_OPENGL_ES3_BIT = 0x00000040;
public const int EGL_CL_EVENT_HANDLE = 0x309C;
public const int EGL_SYNC_CL_EVENT = 0x30FE;
public const int EGL_SYNC_CL_EVENT_COMPLETE = 0x30FF;
public const int EGL_SYNC_PRIOR_COMMANDS_COMPLETE = 0x30F0;
public const int EGL_SYNC_TYPE = 0x30F7;
public const int EGL_SYNC_STATUS = 0x30F1;
public const int EGL_SYNC_CONDITION = 0x30F8;
public const int EGL_SIGNALED = 0x30F2;
public const int EGL_UNSIGNALED = 0x30F3;
public const int EGL_SYNC_FLUSH_COMMANDS_BIT = 0x0001;
public const int EGL_TIMEOUT_EXPIRED = 0x30F5;
public const int EGL_CONDITION_SATISFIED = 0x30F6;
public const int EGL_NO_SYNC = 0;
public const int EGL_SYNC_FENCE = 0x30F9;
public const int EGL_GL_COLORSPACE = 0x309D;
public const int EGL_GL_COLORSPACE_SRGB = 0x3089;
public const int EGL_GL_COLORSPACE_LINEAR = 0x308A;
public const int EGL_GL_RENDERBUFFER = 0x30B9;
public const int EGL_GL_TEXTURE_2D = 0x30B1;
public const int EGL_GL_TEXTURE_LEVEL = 0x30BC;
public const int EGL_GL_TEXTURE_3D = 0x30B2;
public const int EGL_GL_TEXTURE_ZOFFSET = 0x30BD;
public const int EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X = 0x30B3;
public const int EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X = 0x30B4;
public const int EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y = 0x30B5;
public const int EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y = 0x30B6;
public const int EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z = 0x30B7;
public const int EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z = 0x30B8;
public const int EGL_IMAGE_PRESERVED = 0x30D2;
public const int EGL_NO_IMAGE = 0;
public const int EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE = 0x3207;
public const int EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE = 0x3208;
//EGL_ANGLE_platform_angle
public const int EGL_PLATFORM_ANGLE_ANGLE = 0x3202;
public const int EGL_PLATFORM_ANGLE_TYPE_ANGLE = 0x3203;
public const int EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE = 0x3204;
public const int EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE = 0x3205;
public const int EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED = 0x3451;
public const int EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE = 0x3206;
public const int EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE = 0x320A;
public const int EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE = 0x345E;
//EGL_ANGLE_platform_angle_d3d
public const int EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE = 0x3209;
public const int EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE = 0x320F;
public const int EGL_PLATFORM_ANGLE_DEVICE_TYPE_D3D_WARP_ANGLE = 0x320B;
public const int EGL_PLATFORM_ANGLE_DEVICE_TYPE_D3D_REFERENCE_ANGLE = 0x320C;
}
}

205
src/Avalonia.OpenGL/EglDisplay.cs

@ -0,0 +1,205 @@
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using Avalonia.Platform.Interop;
using static Avalonia.OpenGL.EglConsts;
namespace Avalonia.OpenGL
{
public class EglDisplay : IGlDisplay
{
private readonly EglInterface _egl;
private readonly IntPtr _display;
private readonly IntPtr _config;
private readonly int[] _contextAttributes;
public EglDisplay(EglInterface egl)
{
_egl = egl;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && _egl.GetPlatformDisplayEXT != null)
{
foreach (var dapi in new[] {EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE})
{
_display = _egl.GetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, IntPtr.Zero, new[]
{
EGL_PLATFORM_ANGLE_TYPE_ANGLE, dapi, EGL_NONE
});
if(_display != IntPtr.Zero)
break;
}
}
if (_display == IntPtr.Zero)
_display = _egl.GetDisplay(IntPtr.Zero);
if(_display == IntPtr.Zero)
throw new OpenGlException("eglGetDisplay failed");
if (!_egl.Initialize(_display, out var major, out var minor))
throw new OpenGlException("eglInitialize failed");
foreach (var cfg in new[]
{
new
{
Attributes = new[] {EGL_NONE},
Api = EGL_OPENGL_API,
RenderableTypeBit = EGL_OPENGL_BIT,
Type = GlDisplayType.OpenGL2
},
new
{
Attributes = new[]
{
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
},
Api = EGL_OPENGL_ES_API,
RenderableTypeBit = EGL_OPENGL_ES2_BIT,
Type = GlDisplayType.OpenGLES2
}
})
{
if (!_egl.BindApi(cfg.Api))
continue;
var attribs = new[]
{
EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
EGL_RENDERABLE_TYPE, cfg.RenderableTypeBit,
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, 8,
EGL_STENCIL_SIZE, 8,
EGL_DEPTH_SIZE, 8,
EGL_NONE
};
if (!_egl.ChooseConfig(_display, attribs, out _config, 1, out int numConfigs))
continue;
if (numConfigs == 0)
continue;
_contextAttributes = cfg.Attributes;
Type = cfg.Type;
}
if (_contextAttributes == null)
throw new OpenGlException("No suitable EGL config was found");
GlInterface = new GlInterface((proc, optional) =>
{
using (var u = new Utf8Buffer(proc))
{
var rv = _egl.GetProcAddress(u);
if (rv == IntPtr.Zero && !optional)
throw new OpenGlException("Missing function " + proc);
return rv;
}
});
}
public EglDisplay() : this(new EglInterface())
{
}
public GlDisplayType Type { get; }
public GlInterface GlInterface { get; }
public IGlContext CreateContext(IGlContext share)
{
var shareCtx = (EglContext)share;
var ctx = _egl.CreateContext(_display, _config, shareCtx?.Context ?? IntPtr.Zero, _contextAttributes);
if (ctx == IntPtr.Zero)
throw new OpenGlException("eglCreateContext failed");
var surf = _egl.CreatePBufferSurface(_display, _config, new[]
{
EGL_WIDTH, 1,
EGL_HEIGHT, 1,
EGL_NONE
});
if (surf == IntPtr.Zero)
throw new OpenGlException("eglCreatePbufferSurface failed");
var rv = new EglContext(this, ctx, surf);
rv.MakeCurrent(null);
return rv;
}
public void ClearContext()
{
if (!_egl.MakeCurrent(_display, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero))
throw new OpenGlException("eglMakeCurrent failed");
}
public IGlSurface CreateWindowSurface(IntPtr window)
{
var s = _egl.CreateWindowSurface(_display, _config, window, new[] {EGL_NONE, EGL_NONE});
if (s == IntPtr.Zero)
throw new OpenGlException("eglCreateWindowSurface failed");
return new EglSurface(this, s);
}
public int SampleCount
{
get
{
_egl.GetConfigAttrib(_display, _config, EGL_SAMPLES, out var rv);
return rv;
}
}
public int StencilSize
{
get
{
_egl.GetConfigAttrib(_display, _config, EGL_STENCIL_SIZE, out var rv);
return rv;
}
}
class EglSurface : SafeHandle, IGlSurface
{
private readonly EglDisplay _display;
public EglSurface(EglDisplay display, IntPtr surface) : base(surface, true)
{
_display = display;
}
protected override bool ReleaseHandle()
{
_display._egl.DestroySurface(_display._display, handle);
return true;
}
public override bool IsInvalid => handle == IntPtr.Zero;
public IGlDisplay Display => _display;
public void SwapBuffers() => _display._egl.SwapBuffers(_display._display, handle);
}
class EglContext : IGlContext
{
private readonly EglDisplay _disp;
public EglContext(EglDisplay display, IntPtr ctx, IntPtr offscreenSurface)
{
_disp = display;
Context = ctx;
OffscreenSurface = offscreenSurface;
}
public IntPtr Context { get; }
public IntPtr OffscreenSurface { get; }
public IGlDisplay Display => _disp;
public void MakeCurrent(IGlSurface surface)
{
var surf = ((EglSurface)surface)?.DangerousGetHandle() ?? OffscreenSurface;
if (!_disp._egl.MakeCurrent(_disp._display, surf, surf, Context))
throw new OpenGlException("eglMakeCurrent failed");
}
}
}
}

39
src/Avalonia.OpenGL/EglGlPlatformFeature.cs

@ -0,0 +1,39 @@
using System;
using Avalonia.Logging;
namespace Avalonia.OpenGL
{
public class EglGlPlatformFeature : IWindowingPlatformGlFeature
{
public IGlDisplay Display { get; set; }
public IGlContext ImmediateContext { get; set; }
public IGlContext DeferredContext { get; set; }
public static void TryInitialize()
{
var feature = TryCreate();
if (feature != null)
AvaloniaLocator.CurrentMutable.Bind<IWindowingPlatformGlFeature>().ToConstant(feature);
}
public static EglGlPlatformFeature TryCreate()
{
try
{
var disp = new EglDisplay();
var ctx = disp.CreateContext(null);
return new EglGlPlatformFeature
{
Display = disp,
ImmediateContext = ctx,
DeferredContext = disp.CreateContext(ctx)
};
}
catch(Exception e)
{
Logger.Error("OpenGL", null, "Unable to initialize EGL-based rendering: {0}", e);
return null;
}
}
}
}

80
src/Avalonia.OpenGL/EglGlPlatformSurface.cs

@ -0,0 +1,80 @@
using System;
namespace Avalonia.OpenGL
{
public class EglGlPlatformSurface : IGlPlatformSurface
{
public interface IEglWindowGlPlatformSurfaceInfo
{
IntPtr Handle { get; }
// TODO: Change to PixelSize struct once https://github.com/AvaloniaUI/Avalonia/pull/1889 is merged
System.Drawing.Size PixelSize { get; }
double Scaling { get; }
}
private readonly EglDisplay _display;
private readonly IGlContext _context;
private readonly IEglWindowGlPlatformSurfaceInfo _info;
public EglGlPlatformSurface(EglDisplay display, IGlContext context, IEglWindowGlPlatformSurfaceInfo info)
{
_display = display;
_context = context;
_info = info;
}
public IGlPlatformSurfaceRenderTarget CreateGlRenderTarget()
{
var glSurface = _display.CreateWindowSurface(_info.Handle);
return new RenderTarget(_context, glSurface, _info);
}
class RenderTarget : IGlPlatformSurfaceRenderTarget
{
private readonly IGlContext _context;
private readonly IGlSurface _glSurface;
private readonly IEglWindowGlPlatformSurfaceInfo _info;
public RenderTarget(IGlContext context, IGlSurface glSurface, IEglWindowGlPlatformSurfaceInfo info)
{
_context = context;
_glSurface = glSurface;
_info = info;
}
public void Dispose() => _glSurface.Dispose();
public IGlPlatformSurfaceRenderingSession BeginDraw()
{
_context.MakeCurrent(_glSurface);
return new Session(_context, _glSurface, _info);
}
class Session : IGlPlatformSurfaceRenderingSession
{
private readonly IGlContext _context;
private readonly IGlSurface _glSurface;
private readonly IEglWindowGlPlatformSurfaceInfo _info;
public Session(IGlContext context, IGlSurface glSurface, IEglWindowGlPlatformSurfaceInfo info)
{
_context = context;
_glSurface = glSurface;
_info = info;
}
public void Dispose()
{
_context.Display.GlInterface.Flush();
_glSurface.SwapBuffers();
_context.Display.ClearContext();
}
public IGlDisplay Display => _context.Display;
public System.Drawing.Size PixelSize => _info.PixelSize;
public double Scaling => _info.Scaling;
}
}
}
}

93
src/Avalonia.OpenGL/EglInterface.cs

@ -0,0 +1,93 @@
using System;
using Avalonia.Platform;
using Avalonia.Platform.Interop;
using static Avalonia.OpenGL.EglConsts;
namespace Avalonia.OpenGL
{
public class EglInterface : GlInterfaceBase
{
public EglInterface() : base(Load())
{
}
public EglInterface(string library) : base(Load(library))
{
}
static Func<string, bool, IntPtr> Load()
{
var os = AvaloniaLocator.Current.GetService<IRuntimePlatform>().GetRuntimeInfo().OperatingSystem;
if(os == OperatingSystemType.Linux || os == OperatingSystemType.Android)
return Load("libEGL.so.1");
if (os == OperatingSystemType.WinNT)
return Load(@"libegl.dll");
throw new PlatformNotSupportedException();
}
static Func<string, bool, IntPtr> Load(string library)
{
var dyn = AvaloniaLocator.Current.GetService<IDynamicLibraryLoader>();
var lib = dyn.LoadLibrary(library);
return (s, o) => dyn.GetProcAddress(lib, s, o);
}
// ReSharper disable UnassignedGetOnlyAutoProperty
public delegate IntPtr EglGetDisplay(IntPtr nativeDisplay);
[EntryPoint("eglGetDisplay")]
public EglGetDisplay GetDisplay { get; }
public delegate IntPtr EglGetPlatformDisplayEXT(int platform, IntPtr nativeDisplay, int[] attrs);
[EntryPoint("eglGetPlatformDisplayEXT", true)]
public EglGetPlatformDisplayEXT GetPlatformDisplayEXT { get; }
public delegate bool EglInitialize(IntPtr display, out int major, out int minor);
[EntryPoint("eglInitialize")]
public EglInitialize Initialize { get; }
public delegate IntPtr EglGetProcAddress(Utf8Buffer proc);
[EntryPoint("eglGetProcAddress")]
public EglGetProcAddress GetProcAddress { get; }
public delegate bool EglBindApi(int api);
[EntryPoint("eglBindAPI")]
public EglBindApi BindApi { get; }
public delegate bool EglChooseConfig(IntPtr display, int[] attribs,
out IntPtr surfaceConfig, int numConfigs, out int choosenConfig);
[EntryPoint("eglChooseConfig")]
public EglChooseConfig ChooseConfig { get; }
public delegate IntPtr EglCreateContext(IntPtr display, IntPtr config,
IntPtr share, int[] attrs);
[EntryPoint("eglCreateContext")]
public EglCreateContext CreateContext { get; }
public delegate IntPtr EglCreatePBufferSurface(IntPtr display, IntPtr config, int[] attrs);
[EntryPoint("eglCreatePbufferSurface")]
public EglCreatePBufferSurface CreatePBufferSurface { get; }
public delegate bool EglMakeCurrent(IntPtr display, IntPtr draw, IntPtr read, IntPtr context);
[EntryPoint("eglMakeCurrent")]
public EglMakeCurrent MakeCurrent { get; }
public delegate void EglDisplaySurfaceVoidDelegate(IntPtr display, IntPtr surface);
[EntryPoint("eglDestroySurface")]
public EglDisplaySurfaceVoidDelegate DestroySurface { get; }
[EntryPoint("eglSwapBuffers")]
public EglDisplaySurfaceVoidDelegate SwapBuffers { get; }
public delegate IntPtr
EglCreateWindowSurface(IntPtr display, IntPtr config, IntPtr window, int[] attrs);
[EntryPoint("eglCreateWindowSurface")]
public EglCreateWindowSurface CreateWindowSurface { get; }
public delegate bool EglGetConfigAttrib(IntPtr display, IntPtr config, int attr, out int rv);
[EntryPoint("eglGetConfigAttrib")]
public EglGetConfigAttrib GetConfigAttrib { get; }
// ReSharper restore UnassignedGetOnlyAutoProperty
}
}

16
src/Avalonia.OpenGL/EntryPointAttribute.cs

@ -0,0 +1,16 @@
using System;
namespace Avalonia.OpenGL
{
class EntryPointAttribute : Attribute
{
public string EntryPoint { get; }
public bool Optional { get; }
public EntryPointAttribute(string entryPoint, bool optional = false)
{
EntryPoint = entryPoint;
Optional = optional;
}
}
}

789
src/Avalonia.OpenGL/GlConsts.cs

@ -0,0 +1,789 @@
// ReSharper disable UnusedMember.Global
// ReSharper disable IdentifierTypo
namespace Avalonia.OpenGL
{
public static class GlConsts
{
public const int GL_BYTE = 0x1400;
public const int GL_UNSIGNED_BYTE = 0x1401;
public const int GL_SHORT = 0x1402;
public const int GL_UNSIGNED_SHORT = 0x1403;
public const int GL_INT = 0x1404;
public const int GL_UNSIGNED_INT = 0x1405;
public const int GL_FLOAT = 0x1406;
public const int GL_2_BYTES = 0x1407;
public const int GL_3_BYTES = 0x1408;
public const int GL_4_BYTES = 0x1409;
public const int GL_DOUBLE = 0x140A;
public const int GL_POINTS = 0x0000;
public const int GL_LINES = 0x0001;
public const int GL_LINE_LOOP = 0x0002;
public const int GL_LINE_STRIP = 0x0003;
public const int GL_TRIANGLES = 0x0004;
public const int GL_TRIANGLE_STRIP = 0x0005;
public const int GL_TRIANGLE_FAN = 0x0006;
public const int GL_QUADS = 0x0007;
public const int GL_QUAD_STRIP = 0x0008;
public const int GL_POLYGON = 0x0009;
public const int GL_VERTEX_ARRAY = 0x8074;
public const int GL_NORMAL_ARRAY = 0x8075;
public const int GL_COLOR_ARRAY = 0x8076;
public const int GL_INDEX_ARRAY = 0x8077;
public const int GL_TEXTURE_COORD_ARRAY = 0x8078;
public const int GL_EDGE_FLAG_ARRAY = 0x8079;
public const int GL_VERTEX_ARRAY_SIZE = 0x807A;
public const int GL_VERTEX_ARRAY_TYPE = 0x807B;
public const int GL_VERTEX_ARRAY_STRIDE = 0x807C;
public const int GL_NORMAL_ARRAY_TYPE = 0x807E;
public const int GL_NORMAL_ARRAY_STRIDE = 0x807F;
public const int GL_COLOR_ARRAY_SIZE = 0x8081;
public const int GL_COLOR_ARRAY_TYPE = 0x8082;
public const int GL_COLOR_ARRAY_STRIDE = 0x8083;
public const int GL_INDEX_ARRAY_TYPE = 0x8085;
public const int GL_INDEX_ARRAY_STRIDE = 0x8086;
public const int GL_TEXTURE_COORD_ARRAY_SIZE = 0x8088;
public const int GL_TEXTURE_COORD_ARRAY_TYPE = 0x8089;
public const int GL_TEXTURE_COORD_ARRAY_STRIDE = 0x808A;
public const int GL_EDGE_FLAG_ARRAY_STRIDE = 0x808C;
public const int GL_VERTEX_ARRAY_POINTER = 0x808E;
public const int GL_NORMAL_ARRAY_POINTER = 0x808F;
public const int GL_COLOR_ARRAY_POINTER = 0x8090;
public const int GL_INDEX_ARRAY_POINTER = 0x8091;
public const int GL_TEXTURE_COORD_ARRAY_POINTER = 0x8092;
public const int GL_EDGE_FLAG_ARRAY_POINTER = 0x8093;
public const int GL_V2F = 0x2A20;
public const int GL_V3F = 0x2A21;
public const int GL_C4UB_V2F = 0x2A22;
public const int GL_C4UB_V3F = 0x2A23;
public const int GL_C3F_V3F = 0x2A24;
public const int GL_N3F_V3F = 0x2A25;
public const int GL_C4F_N3F_V3F = 0x2A26;
public const int GL_T2F_V3F = 0x2A27;
public const int GL_T4F_V4F = 0x2A28;
public const int GL_T2F_C4UB_V3F = 0x2A29;
public const int GL_T2F_C3F_V3F = 0x2A2A;
public const int GL_T2F_N3F_V3F = 0x2A2B;
public const int GL_T2F_C4F_N3F_V3F = 0x2A2C;
public const int GL_T4F_C4F_N3F_V4F = 0x2A2D;
public const int GL_MATRIX_MODE = 0x0BA0;
public const int GL_MODELVIEW = 0x1700;
public const int GL_PROJECTION = 0x1701;
public const int GL_TEXTURE = 0x1702;
public const int GL_POINT_SMOOTH = 0x0B10;
public const int GL_POINT_SIZE = 0x0B11;
public const int GL_POINT_SIZE_GRANULARITY = 0x0B13;
public const int GL_POINT_SIZE_RANGE = 0x0B12;
public const int GL_LINE_SMOOTH = 0x0B20;
public const int GL_LINE_STIPPLE = 0x0B24;
public const int GL_LINE_STIPPLE_PATTERN = 0x0B25;
public const int GL_LINE_STIPPLE_REPEAT = 0x0B26;
public const int GL_LINE_WIDTH = 0x0B21;
public const int GL_LINE_WIDTH_GRANULARITY = 0x0B23;
public const int GL_LINE_WIDTH_RANGE = 0x0B22;
public const int GL_POINT = 0x1B00;
public const int GL_LINE = 0x1B01;
public const int GL_FILL = 0x1B02;
public const int GL_CW = 0x0900;
public const int GL_CCW = 0x0901;
public const int GL_FRONT = 0x0404;
public const int GL_BACK = 0x0405;
public const int GL_POLYGON_MODE = 0x0B40;
public const int GL_POLYGON_SMOOTH = 0x0B41;
public const int GL_POLYGON_STIPPLE = 0x0B42;
public const int GL_EDGE_FLAG = 0x0B43;
public const int GL_CULL_FACE = 0x0B44;
public const int GL_CULL_FACE_MODE = 0x0B45;
public const int GL_FRONT_FACE = 0x0B46;
public const int GL_POLYGON_OFFSET_FACTOR = 0x8038;
public const int GL_POLYGON_OFFSET_UNITS = 0x2A00;
public const int GL_POLYGON_OFFSET_POINT = 0x2A01;
public const int GL_POLYGON_OFFSET_LINE = 0x2A02;
public const int GL_POLYGON_OFFSET_FILL = 0x8037;
public const int GL_COMPILE = 0x1300;
public const int GL_COMPILE_AND_EXECUTE = 0x1301;
public const int GL_LIST_BASE = 0x0B32;
public const int GL_LIST_INDEX = 0x0B33;
public const int GL_LIST_MODE = 0x0B30;
public const int GL_NEVER = 0x0200;
public const int GL_LESS = 0x0201;
public const int GL_EQUAL = 0x0202;
public const int GL_LEQUAL = 0x0203;
public const int GL_GREATER = 0x0204;
public const int GL_NOTEQUAL = 0x0205;
public const int GL_GEQUAL = 0x0206;
public const int GL_ALWAYS = 0x0207;
public const int GL_DEPTH_TEST = 0x0B71;
public const int GL_DEPTH_BITS = 0x0D56;
public const int GL_DEPTH_CLEAR_VALUE = 0x0B73;
public const int GL_DEPTH_FUNC = 0x0B74;
public const int GL_DEPTH_RANGE = 0x0B70;
public const int GL_DEPTH_WRITEMASK = 0x0B72;
public const int GL_DEPTH_COMPONENT = 0x1902;
public const int GL_LIGHTING = 0x0B50;
public const int GL_LIGHT0 = 0x4000;
public const int GL_LIGHT1 = 0x4001;
public const int GL_LIGHT2 = 0x4002;
public const int GL_LIGHT3 = 0x4003;
public const int GL_LIGHT4 = 0x4004;
public const int GL_LIGHT5 = 0x4005;
public const int GL_LIGHT6 = 0x4006;
public const int GL_LIGHT7 = 0x4007;
public const int GL_SPOT_EXPONENT = 0x1205;
public const int GL_SPOT_CUTOFF = 0x1206;
public const int GL_CONSTANT_ATTENUATION = 0x1207;
public const int GL_LINEAR_ATTENUATION = 0x1208;
public const int GL_QUADRATIC_ATTENUATION = 0x1209;
public const int GL_AMBIENT = 0x1200;
public const int GL_DIFFUSE = 0x1201;
public const int GL_SPECULAR = 0x1202;
public const int GL_SHININESS = 0x1601;
public const int GL_EMISSION = 0x1600;
public const int GL_POSITION = 0x1203;
public const int GL_SPOT_DIRECTION = 0x1204;
public const int GL_AMBIENT_AND_DIFFUSE = 0x1602;
public const int GL_COLOR_INDEXES = 0x1603;
public const int GL_LIGHT_MODEL_TWO_SIDE = 0x0B52;
public const int GL_LIGHT_MODEL_LOCAL_VIEWER = 0x0B51;
public const int GL_LIGHT_MODEL_AMBIENT = 0x0B53;
public const int GL_FRONT_AND_BACK = 0x0408;
public const int GL_SHADE_MODEL = 0x0B54;
public const int GL_FLAT = 0x1D00;
public const int GL_SMOOTH = 0x1D01;
public const int GL_COLOR_MATERIAL = 0x0B57;
public const int GL_COLOR_MATERIAL_FACE = 0x0B55;
public const int GL_COLOR_MATERIAL_PARAMETER = 0x0B56;
public const int GL_NORMALIZE = 0x0BA1;
public const int GL_CLIP_PLANE0 = 0x3000;
public const int GL_CLIP_PLANE1 = 0x3001;
public const int GL_CLIP_PLANE2 = 0x3002;
public const int GL_CLIP_PLANE3 = 0x3003;
public const int GL_CLIP_PLANE4 = 0x3004;
public const int GL_CLIP_PLANE5 = 0x3005;
public const int GL_ACCUM_RED_BITS = 0x0D58;
public const int GL_ACCUM_GREEN_BITS = 0x0D59;
public const int GL_ACCUM_BLUE_BITS = 0x0D5A;
public const int GL_ACCUM_ALPHA_BITS = 0x0D5B;
public const int GL_ACCUM_CLEAR_VALUE = 0x0B80;
public const int GL_ACCUM = 0x0100;
public const int GL_ADD = 0x0104;
public const int GL_LOAD = 0x0101;
public const int GL_MULT = 0x0103;
public const int GL_RETURN = 0x0102;
public const int GL_ALPHA_TEST = 0x0BC0;
public const int GL_ALPHA_TEST_REF = 0x0BC2;
public const int GL_ALPHA_TEST_FUNC = 0x0BC1;
public const int GL_BLEND = 0x0BE2;
public const int GL_BLEND_SRC = 0x0BE1;
public const int GL_BLEND_DST = 0x0BE0;
public const int GL_SRC_COLOR = 0x0300;
public const int GL_ONE_MINUS_SRC_COLOR = 0x0301;
public const int GL_SRC_ALPHA = 0x0302;
public const int GL_ONE_MINUS_SRC_ALPHA = 0x0303;
public const int GL_DST_ALPHA = 0x0304;
public const int GL_ONE_MINUS_DST_ALPHA = 0x0305;
public const int GL_DST_COLOR = 0x0306;
public const int GL_ONE_MINUS_DST_COLOR = 0x0307;
public const int GL_SRC_ALPHA_SATURATE = 0x0308;
public const int GL_FEEDBACK = 0x1C01;
public const int GL_RENDER = 0x1C00;
public const int GL_SELECT = 0x1C02;
public const int GL_2D = 0x0600;
public const int GL_3D = 0x0601;
public const int GL_3D_COLOR = 0x0602;
public const int GL_3D_COLOR_TEXTURE = 0x0603;
public const int GL_4D_COLOR_TEXTURE = 0x0604;
public const int GL_POINT_TOKEN = 0x0701;
public const int GL_LINE_TOKEN = 0x0702;
public const int GL_LINE_RESET_TOKEN = 0x0707;
public const int GL_POLYGON_TOKEN = 0x0703;
public const int GL_BITMAP_TOKEN = 0x0704;
public const int GL_DRAW_PIXEL_TOKEN = 0x0705;
public const int GL_COPY_PIXEL_TOKEN = 0x0706;
public const int GL_PASS_THROUGH_TOKEN = 0x0700;
public const int GL_FEEDBACK_BUFFER_POINTER = 0x0DF0;
public const int GL_FEEDBACK_BUFFER_SIZE = 0x0DF1;
public const int GL_FEEDBACK_BUFFER_TYPE = 0x0DF2;
public const int GL_SELECTION_BUFFER_POINTER = 0x0DF3;
public const int GL_SELECTION_BUFFER_SIZE = 0x0DF4;
public const int GL_FOG = 0x0B60;
public const int GL_FOG_MODE = 0x0B65;
public const int GL_FOG_DENSITY = 0x0B62;
public const int GL_FOG_COLOR = 0x0B66;
public const int GL_FOG_INDEX = 0x0B61;
public const int GL_FOG_START = 0x0B63;
public const int GL_FOG_END = 0x0B64;
public const int GL_LINEAR = 0x2601;
public const int GL_EXP = 0x0800;
public const int GL_EXP2 = 0x0801;
public const int GL_LOGIC_OP = 0x0BF1;
public const int GL_INDEX_LOGIC_OP = 0x0BF1;
public const int GL_COLOR_LOGIC_OP = 0x0BF2;
public const int GL_LOGIC_OP_MODE = 0x0BF0;
public const int GL_CLEAR = 0x1500;
public const int GL_SET = 0x150F;
public const int GL_COPY = 0x1503;
public const int GL_COPY_INVERTED = 0x150C;
public const int GL_NOOP = 0x1505;
public const int GL_INVERT = 0x150A;
public const int GL_AND = 0x1501;
public const int GL_NAND = 0x150E;
public const int GL_OR = 0x1507;
public const int GL_NOR = 0x1508;
public const int GL_XOR = 0x1506;
public const int GL_EQUIV = 0x1509;
public const int GL_AND_REVERSE = 0x1502;
public const int GL_AND_INVERTED = 0x1504;
public const int GL_OR_REVERSE = 0x150B;
public const int GL_OR_INVERTED = 0x150D;
public const int GL_STENCIL_BITS = 0x0D57;
public const int GL_STENCIL_TEST = 0x0B90;
public const int GL_STENCIL_CLEAR_VALUE = 0x0B91;
public const int GL_STENCIL_FUNC = 0x0B92;
public const int GL_STENCIL_VALUE_MASK = 0x0B93;
public const int GL_STENCIL_FAIL = 0x0B94;
public const int GL_STENCIL_PASS_DEPTH_FAIL = 0x0B95;
public const int GL_STENCIL_PASS_DEPTH_PASS = 0x0B96;
public const int GL_STENCIL_REF = 0x0B97;
public const int GL_STENCIL_WRITEMASK = 0x0B98;
public const int GL_STENCIL_INDEX = 0x1901;
public const int GL_KEEP = 0x1E00;
public const int GL_REPLACE = 0x1E01;
public const int GL_INCR = 0x1E02;
public const int GL_DECR = 0x1E03;
public const int GL_LEFT = 0x0406;
public const int GL_RIGHT = 0x0407;
public const int GL_FRONT_LEFT = 0x0400;
public const int GL_FRONT_RIGHT = 0x0401;
public const int GL_BACK_LEFT = 0x0402;
public const int GL_BACK_RIGHT = 0x0403;
public const int GL_AUX0 = 0x0409;
public const int GL_AUX1 = 0x040A;
public const int GL_AUX2 = 0x040B;
public const int GL_AUX3 = 0x040C;
public const int GL_COLOR_INDEX = 0x1900;
public const int GL_RED = 0x1903;
public const int GL_GREEN = 0x1904;
public const int GL_BLUE = 0x1905;
public const int GL_ALPHA = 0x1906;
public const int GL_LUMINANCE = 0x1909;
public const int GL_LUMINANCE_ALPHA = 0x190A;
public const int GL_ALPHA_BITS = 0x0D55;
public const int GL_RED_BITS = 0x0D52;
public const int GL_GREEN_BITS = 0x0D53;
public const int GL_BLUE_BITS = 0x0D54;
public const int GL_INDEX_BITS = 0x0D51;
public const int GL_SUBPIXEL_BITS = 0x0D50;
public const int GL_AUX_BUFFERS = 0x0C00;
public const int GL_READ_BUFFER = 0x0C02;
public const int GL_DRAW_BUFFER = 0x0C01;
public const int GL_DOUBLEBUFFER = 0x0C32;
public const int GL_STEREO = 0x0C33;
public const int GL_BITMAP = 0x1A00;
public const int GL_COLOR = 0x1800;
public const int GL_DEPTH = 0x1801;
public const int GL_STENCIL = 0x1802;
public const int GL_DITHER = 0x0BD0;
public const int GL_RGB = 0x1907;
public const int GL_RGBA = 0x1908;
public const int GL_MAX_LIST_NESTING = 0x0B31;
public const int GL_MAX_EVAL_ORDER = 0x0D30;
public const int GL_MAX_LIGHTS = 0x0D31;
public const int GL_MAX_CLIP_PLANES = 0x0D32;
public const int GL_MAX_TEXTURE_SIZE = 0x0D33;
public const int GL_MAX_PIXEL_MAP_TABLE = 0x0D34;
public const int GL_MAX_ATTRIB_STACK_DEPTH = 0x0D35;
public const int GL_MAX_MODELVIEW_STACK_DEPTH = 0x0D36;
public const int GL_MAX_NAME_STACK_DEPTH = 0x0D37;
public const int GL_MAX_PROJECTION_STACK_DEPTH = 0x0D38;
public const int GL_MAX_TEXTURE_STACK_DEPTH = 0x0D39;
public const int GL_MAX_VIEWPORT_DIMS = 0x0D3A;
public const int GL_MAX_CLIENT_ATTRIB_STACK_DEPTH = 0x0D3B;
public const int GL_ATTRIB_STACK_DEPTH = 0x0BB0;
public const int GL_CLIENT_ATTRIB_STACK_DEPTH = 0x0BB1;
public const int GL_COLOR_CLEAR_VALUE = 0x0C22;
public const int GL_COLOR_WRITEMASK = 0x0C23;
public const int GL_CURRENT_INDEX = 0x0B01;
public const int GL_CURRENT_COLOR = 0x0B00;
public const int GL_CURRENT_NORMAL = 0x0B02;
public const int GL_CURRENT_RASTER_COLOR = 0x0B04;
public const int GL_CURRENT_RASTER_DISTANCE = 0x0B09;
public const int GL_CURRENT_RASTER_INDEX = 0x0B05;
public const int GL_CURRENT_RASTER_POSITION = 0x0B07;
public const int GL_CURRENT_RASTER_TEXTURE_COORDS = 0x0B06;
public const int GL_CURRENT_RASTER_POSITION_VALID = 0x0B08;
public const int GL_CURRENT_TEXTURE_COORDS = 0x0B03;
public const int GL_INDEX_CLEAR_VALUE = 0x0C20;
public const int GL_INDEX_MODE = 0x0C30;
public const int GL_INDEX_WRITEMASK = 0x0C21;
public const int GL_MODELVIEW_MATRIX = 0x0BA6;
public const int GL_MODELVIEW_STACK_DEPTH = 0x0BA3;
public const int GL_NAME_STACK_DEPTH = 0x0D70;
public const int GL_PROJECTION_MATRIX = 0x0BA7;
public const int GL_PROJECTION_STACK_DEPTH = 0x0BA4;
public const int GL_RENDER_MODE = 0x0C40;
public const int GL_RGBA_MODE = 0x0C31;
public const int GL_TEXTURE_MATRIX = 0x0BA8;
public const int GL_TEXTURE_STACK_DEPTH = 0x0BA5;
public const int GL_VIEWPORT = 0x0BA2;
public const int GL_AUTO_NORMAL = 0x0D80;
public const int GL_MAP1_COLOR_4 = 0x0D90;
public const int GL_MAP1_INDEX = 0x0D91;
public const int GL_MAP1_NORMAL = 0x0D92;
public const int GL_MAP1_TEXTURE_COORD_1 = 0x0D93;
public const int GL_MAP1_TEXTURE_COORD_2 = 0x0D94;
public const int GL_MAP1_TEXTURE_COORD_3 = 0x0D95;
public const int GL_MAP1_TEXTURE_COORD_4 = 0x0D96;
public const int GL_MAP1_VERTEX_3 = 0x0D97;
public const int GL_MAP1_VERTEX_4 = 0x0D98;
public const int GL_MAP2_COLOR_4 = 0x0DB0;
public const int GL_MAP2_INDEX = 0x0DB1;
public const int GL_MAP2_NORMAL = 0x0DB2;
public const int GL_MAP2_TEXTURE_COORD_1 = 0x0DB3;
public const int GL_MAP2_TEXTURE_COORD_2 = 0x0DB4;
public const int GL_MAP2_TEXTURE_COORD_3 = 0x0DB5;
public const int GL_MAP2_TEXTURE_COORD_4 = 0x0DB6;
public const int GL_MAP2_VERTEX_3 = 0x0DB7;
public const int GL_MAP2_VERTEX_4 = 0x0DB8;
public const int GL_MAP1_GRID_DOMAIN = 0x0DD0;
public const int GL_MAP1_GRID_SEGMENTS = 0x0DD1;
public const int GL_MAP2_GRID_DOMAIN = 0x0DD2;
public const int GL_MAP2_GRID_SEGMENTS = 0x0DD3;
public const int GL_COEFF = 0x0A00;
public const int GL_ORDER = 0x0A01;
public const int GL_DOMAIN = 0x0A02;
public const int GL_PERSPECTIVE_CORRECTION_HINT = 0x0C50;
public const int GL_POINT_SMOOTH_HINT = 0x0C51;
public const int GL_LINE_SMOOTH_HINT = 0x0C52;
public const int GL_POLYGON_SMOOTH_HINT = 0x0C53;
public const int GL_FOG_HINT = 0x0C54;
public const int GL_DONT_CARE = 0x1100;
public const int GL_FASTEST = 0x1101;
public const int GL_NICEST = 0x1102;
public const int GL_SCISSOR_BOX = 0x0C10;
public const int GL_SCISSOR_TEST = 0x0C11;
public const int GL_MAP_COLOR = 0x0D10;
public const int GL_MAP_STENCIL = 0x0D11;
public const int GL_INDEX_SHIFT = 0x0D12;
public const int GL_INDEX_OFFSET = 0x0D13;
public const int GL_RED_SCALE = 0x0D14;
public const int GL_RED_BIAS = 0x0D15;
public const int GL_GREEN_SCALE = 0x0D18;
public const int GL_GREEN_BIAS = 0x0D19;
public const int GL_BLUE_SCALE = 0x0D1A;
public const int GL_BLUE_BIAS = 0x0D1B;
public const int GL_ALPHA_SCALE = 0x0D1C;
public const int GL_ALPHA_BIAS = 0x0D1D;
public const int GL_DEPTH_SCALE = 0x0D1E;
public const int GL_DEPTH_BIAS = 0x0D1F;
public const int GL_PIXEL_MAP_S_TO_S_SIZE = 0x0CB1;
public const int GL_PIXEL_MAP_I_TO_I_SIZE = 0x0CB0;
public const int GL_PIXEL_MAP_I_TO_R_SIZE = 0x0CB2;
public const int GL_PIXEL_MAP_I_TO_G_SIZE = 0x0CB3;
public const int GL_PIXEL_MAP_I_TO_B_SIZE = 0x0CB4;
public const int GL_PIXEL_MAP_I_TO_A_SIZE = 0x0CB5;
public const int GL_PIXEL_MAP_R_TO_R_SIZE = 0x0CB6;
public const int GL_PIXEL_MAP_G_TO_G_SIZE = 0x0CB7;
public const int GL_PIXEL_MAP_B_TO_B_SIZE = 0x0CB8;
public const int GL_PIXEL_MAP_A_TO_A_SIZE = 0x0CB9;
public const int GL_PIXEL_MAP_S_TO_S = 0x0C71;
public const int GL_PIXEL_MAP_I_TO_I = 0x0C70;
public const int GL_PIXEL_MAP_I_TO_R = 0x0C72;
public const int GL_PIXEL_MAP_I_TO_G = 0x0C73;
public const int GL_PIXEL_MAP_I_TO_B = 0x0C74;
public const int GL_PIXEL_MAP_I_TO_A = 0x0C75;
public const int GL_PIXEL_MAP_R_TO_R = 0x0C76;
public const int GL_PIXEL_MAP_G_TO_G = 0x0C77;
public const int GL_PIXEL_MAP_B_TO_B = 0x0C78;
public const int GL_PIXEL_MAP_A_TO_A = 0x0C79;
public const int GL_PACK_ALIGNMENT = 0x0D05;
public const int GL_PACK_LSB_FIRST = 0x0D01;
public const int GL_PACK_ROW_LENGTH = 0x0D02;
public const int GL_PACK_SKIP_PIXELS = 0x0D04;
public const int GL_PACK_SKIP_ROWS = 0x0D03;
public const int GL_PACK_SWAP_BYTES = 0x0D00;
public const int GL_UNPACK_ALIGNMENT = 0x0CF5;
public const int GL_UNPACK_LSB_FIRST = 0x0CF1;
public const int GL_UNPACK_ROW_LENGTH = 0x0CF2;
public const int GL_UNPACK_SKIP_PIXELS = 0x0CF4;
public const int GL_UNPACK_SKIP_ROWS = 0x0CF3;
public const int GL_UNPACK_SWAP_BYTES = 0x0CF0;
public const int GL_ZOOM_X = 0x0D16;
public const int GL_ZOOM_Y = 0x0D17;
public const int GL_TEXTURE_ENV = 0x2300;
public const int GL_TEXTURE_ENV_MODE = 0x2200;
public const int GL_TEXTURE_1D = 0x0DE0;
public const int GL_TEXTURE_2D = 0x0DE1;
public const int GL_TEXTURE_WRAP_S = 0x2802;
public const int GL_TEXTURE_WRAP_T = 0x2803;
public const int GL_TEXTURE_MAG_FILTER = 0x2800;
public const int GL_TEXTURE_MIN_FILTER = 0x2801;
public const int GL_TEXTURE_ENV_COLOR = 0x2201;
public const int GL_TEXTURE_GEN_S = 0x0C60;
public const int GL_TEXTURE_GEN_T = 0x0C61;
public const int GL_TEXTURE_GEN_R = 0x0C62;
public const int GL_TEXTURE_GEN_Q = 0x0C63;
public const int GL_TEXTURE_GEN_MODE = 0x2500;
public const int GL_TEXTURE_BORDER_COLOR = 0x1004;
public const int GL_TEXTURE_WIDTH = 0x1000;
public const int GL_TEXTURE_HEIGHT = 0x1001;
public const int GL_TEXTURE_BORDER = 0x1005;
public const int GL_TEXTURE_COMPONENTS = 0x1003;
public const int GL_TEXTURE_RED_SIZE = 0x805C;
public const int GL_TEXTURE_GREEN_SIZE = 0x805D;
public const int GL_TEXTURE_BLUE_SIZE = 0x805E;
public const int GL_TEXTURE_ALPHA_SIZE = 0x805F;
public const int GL_TEXTURE_LUMINANCE_SIZE = 0x8060;
public const int GL_TEXTURE_INTENSITY_SIZE = 0x8061;
public const int GL_NEAREST_MIPMAP_NEAREST = 0x2700;
public const int GL_NEAREST_MIPMAP_LINEAR = 0x2702;
public const int GL_LINEAR_MIPMAP_NEAREST = 0x2701;
public const int GL_LINEAR_MIPMAP_LINEAR = 0x2703;
public const int GL_OBJECT_LINEAR = 0x2401;
public const int GL_OBJECT_PLANE = 0x2501;
public const int GL_EYE_LINEAR = 0x2400;
public const int GL_EYE_PLANE = 0x2502;
public const int GL_SPHERE_MAP = 0x2402;
public const int GL_DECAL = 0x2101;
public const int GL_MODULATE = 0x2100;
public const int GL_NEAREST = 0x2600;
public const int GL_REPEAT = 0x2901;
public const int GL_CLAMP = 0x2900;
public const int GL_S = 0x2000;
public const int GL_T = 0x2001;
public const int GL_R = 0x2002;
public const int GL_Q = 0x2003;
public const int GL_VENDOR = 0x1F00;
public const int GL_RENDERER = 0x1F01;
public const int GL_VERSION = 0x1F02;
public const int GL_EXTENSIONS = 0x1F03;
public const int GL_INVALID_ENUM = 0x0500;
public const int GL_INVALID_VALUE = 0x0501;
public const int GL_INVALID_OPERATION = 0x0502;
public const int GL_STACK_OVERFLOW = 0x0503;
public const int GL_STACK_UNDERFLOW = 0x0504;
public const int GL_OUT_OF_MEMORY = 0x0505;
public const int GL_CURRENT_BIT = 0x00000001;
public const int GL_POINT_BIT = 0x00000002;
public const int GL_LINE_BIT = 0x00000004;
public const int GL_POLYGON_BIT = 0x00000008;
public const int GL_POLYGON_STIPPLE_BIT = 0x00000010;
public const int GL_PIXEL_MODE_BIT = 0x00000020;
public const int GL_LIGHTING_BIT = 0x00000040;
public const int GL_FOG_BIT = 0x00000080;
public const int GL_DEPTH_BUFFER_BIT = 0x00000100;
public const int GL_ACCUM_BUFFER_BIT = 0x00000200;
public const int GL_STENCIL_BUFFER_BIT = 0x00000400;
public const int GL_VIEWPORT_BIT = 0x00000800;
public const int GL_TRANSFORM_BIT = 0x00001000;
public const int GL_ENABLE_BIT = 0x00002000;
public const int GL_COLOR_BUFFER_BIT = 0x00004000;
public const int GL_HINT_BIT = 0x00008000;
public const int GL_EVAL_BIT = 0x00010000;
public const int GL_LIST_BIT = 0x00020000;
public const int GL_TEXTURE_BIT = 0x00040000;
public const int GL_SCISSOR_BIT = 0x00080000;
public const int GL_ALL_ATTRIB_BITS = -1;
public const int GL_PROXY_TEXTURE_1D = 0x8063;
public const int GL_PROXY_TEXTURE_2D = 0x8064;
public const int GL_TEXTURE_PRIORITY = 0x8066;
public const int GL_TEXTURE_RESIDENT = 0x8067;
public const int GL_TEXTURE_BINDING_1D = 0x8068;
public const int GL_TEXTURE_BINDING_2D = 0x8069;
public const int GL_TEXTURE_INTERNAL_FORMAT = 0x1003;
public const int GL_ALPHA4 = 0x803B;
public const int GL_ALPHA8 = 0x803C;
public const int GL_ALPHA12 = 0x803D;
public const int GL_ALPHA16 = 0x803E;
public const int GL_LUMINANCE4 = 0x803F;
public const int GL_LUMINANCE8 = 0x8040;
public const int GL_LUMINANCE12 = 0x8041;
public const int GL_LUMINANCE16 = 0x8042;
public const int GL_LUMINANCE4_ALPHA4 = 0x8043;
public const int GL_LUMINANCE6_ALPHA2 = 0x8044;
public const int GL_LUMINANCE8_ALPHA8 = 0x8045;
public const int GL_LUMINANCE12_ALPHA4 = 0x8046;
public const int GL_LUMINANCE12_ALPHA12 = 0x8047;
public const int GL_LUMINANCE16_ALPHA16 = 0x8048;
public const int GL_INTENSITY = 0x8049;
public const int GL_INTENSITY4 = 0x804A;
public const int GL_INTENSITY8 = 0x804B;
public const int GL_INTENSITY12 = 0x804C;
public const int GL_INTENSITY16 = 0x804D;
public const int GL_R3_G3_B2 = 0x2A10;
public const int GL_RGB4 = 0x804F;
public const int GL_RGB5 = 0x8050;
public const int GL_RGB8 = 0x8051;
public const int GL_RGB10 = 0x8052;
public const int GL_RGB12 = 0x8053;
public const int GL_RGB16 = 0x8054;
public const int GL_RGBA2 = 0x8055;
public const int GL_RGBA4 = 0x8056;
public const int GL_RGB5_A1 = 0x8057;
public const int GL_RGBA8 = 0x8058;
public const int GL_RGB10_A2 = 0x8059;
public const int GL_RGBA12 = 0x805A;
public const int GL_RGBA16 = 0x805B;
public const int GL_CLIENT_PIXEL_STORE_BIT = 0x00000001;
public const int GL_CLIENT_VERTEX_ARRAY_BIT = 0x00000002;
public const int GL_ALL_CLIENT_ATTRIB_BITS = -1;
public const int GL_CLIENT_ALL_ATTRIB_BITS = -1;
public const int GL_RESCALE_NORMAL = 0x803A;
public const int GL_CLAMP_TO_EDGE = 0x812F;
public const int GL_MAX_ELEMENTS_VERTICES = 0x80E8;
public const int GL_MAX_ELEMENTS_INDICES = 0x80E9;
public const int GL_BGR = 0x80E0;
public const int GL_BGRA = 0x80E1;
public const int GL_UNSIGNED_BYTE_3_3_2 = 0x8032;
public const int GL_UNSIGNED_BYTE_2_3_3_REV = 0x8362;
public const int GL_UNSIGNED_SHORT_5_6_5 = 0x8363;
public const int GL_UNSIGNED_SHORT_5_6_5_REV = 0x8364;
public const int GL_UNSIGNED_SHORT_4_4_4_4 = 0x8033;
public const int GL_UNSIGNED_SHORT_4_4_4_4_REV = 0x8365;
public const int GL_UNSIGNED_SHORT_5_5_5_1 = 0x8034;
public const int GL_UNSIGNED_SHORT_1_5_5_5_REV = 0x8366;
public const int GL_UNSIGNED_INT_8_8_8_8 = 0x8035;
public const int GL_UNSIGNED_INT_8_8_8_8_REV = 0x8367;
public const int GL_UNSIGNED_INT_10_10_10_2 = 0x8036;
public const int GL_UNSIGNED_INT_2_10_10_10_REV = 0x8368;
public const int GL_LIGHT_MODEL_COLOR_CONTROL = 0x81F8;
public const int GL_SINGLE_COLOR = 0x81F9;
public const int GL_SEPARATE_SPECULAR_COLOR = 0x81FA;
public const int GL_TEXTURE_MIN_LOD = 0x813A;
public const int GL_TEXTURE_MAX_LOD = 0x813B;
public const int GL_TEXTURE_BASE_LEVEL = 0x813C;
public const int GL_TEXTURE_MAX_LEVEL = 0x813D;
public const int GL_SMOOTH_POINT_SIZE_RANGE = 0x0B12;
public const int GL_SMOOTH_POINT_SIZE_GRANULARITY = 0x0B13;
public const int GL_SMOOTH_LINE_WIDTH_RANGE = 0x0B22;
public const int GL_SMOOTH_LINE_WIDTH_GRANULARITY = 0x0B23;
public const int GL_ALIASED_POINT_SIZE_RANGE = 0x846D;
public const int GL_ALIASED_LINE_WIDTH_RANGE = 0x846E;
public const int GL_PACK_SKIP_IMAGES = 0x806B;
public const int GL_PACK_IMAGE_HEIGHT = 0x806C;
public const int GL_UNPACK_SKIP_IMAGES = 0x806D;
public const int GL_UNPACK_IMAGE_HEIGHT = 0x806E;
public const int GL_TEXTURE_3D = 0x806F;
public const int GL_PROXY_TEXTURE_3D = 0x8070;
public const int GL_TEXTURE_DEPTH = 0x8071;
public const int GL_TEXTURE_WRAP_R = 0x8072;
public const int GL_MAX_3D_TEXTURE_SIZE = 0x8073;
public const int GL_TEXTURE_BINDING_3D = 0x806A;
public const int GL_CONSTANT_COLOR = 0x8001;
public const int GL_ONE_MINUS_CONSTANT_COLOR = 0x8002;
public const int GL_CONSTANT_ALPHA = 0x8003;
public const int GL_ONE_MINUS_CONSTANT_ALPHA = 0x8004;
public const int GL_COLOR_TABLE = 0x80D0;
public const int GL_POST_CONVOLUTION_COLOR_TABLE = 0x80D1;
public const int GL_POST_COLOR_MATRIX_COLOR_TABLE = 0x80D2;
public const int GL_PROXY_COLOR_TABLE = 0x80D3;
public const int GL_PROXY_POST_CONVOLUTION_COLOR_TABLE = 0x80D4;
public const int GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE = 0x80D5;
public const int GL_COLOR_TABLE_SCALE = 0x80D6;
public const int GL_COLOR_TABLE_BIAS = 0x80D7;
public const int GL_COLOR_TABLE_FORMAT = 0x80D8;
public const int GL_COLOR_TABLE_WIDTH = 0x80D9;
public const int GL_COLOR_TABLE_RED_SIZE = 0x80DA;
public const int GL_COLOR_TABLE_GREEN_SIZE = 0x80DB;
public const int GL_COLOR_TABLE_BLUE_SIZE = 0x80DC;
public const int GL_COLOR_TABLE_ALPHA_SIZE = 0x80DD;
public const int GL_COLOR_TABLE_LUMINANCE_SIZE = 0x80DE;
public const int GL_COLOR_TABLE_INTENSITY_SIZE = 0x80DF;
public const int GL_CONVOLUTION_1D = 0x8010;
public const int GL_CONVOLUTION_2D = 0x8011;
public const int GL_SEPARABLE_2D = 0x8012;
public const int GL_CONVOLUTION_BORDER_MODE = 0x8013;
public const int GL_CONVOLUTION_FILTER_SCALE = 0x8014;
public const int GL_CONVOLUTION_FILTER_BIAS = 0x8015;
public const int GL_REDUCE = 0x8016;
public const int GL_CONVOLUTION_FORMAT = 0x8017;
public const int GL_CONVOLUTION_WIDTH = 0x8018;
public const int GL_CONVOLUTION_HEIGHT = 0x8019;
public const int GL_MAX_CONVOLUTION_WIDTH = 0x801A;
public const int GL_MAX_CONVOLUTION_HEIGHT = 0x801B;
public const int GL_POST_CONVOLUTION_RED_SCALE = 0x801C;
public const int GL_POST_CONVOLUTION_GREEN_SCALE = 0x801D;
public const int GL_POST_CONVOLUTION_BLUE_SCALE = 0x801E;
public const int GL_POST_CONVOLUTION_ALPHA_SCALE = 0x801F;
public const int GL_POST_CONVOLUTION_RED_BIAS = 0x8020;
public const int GL_POST_CONVOLUTION_GREEN_BIAS = 0x8021;
public const int GL_POST_CONVOLUTION_BLUE_BIAS = 0x8022;
public const int GL_POST_CONVOLUTION_ALPHA_BIAS = 0x8023;
public const int GL_CONSTANT_BORDER = 0x8151;
public const int GL_REPLICATE_BORDER = 0x8153;
public const int GL_CONVOLUTION_BORDER_COLOR = 0x8154;
public const int GL_COLOR_MATRIX = 0x80B1;
public const int GL_COLOR_MATRIX_STACK_DEPTH = 0x80B2;
public const int GL_MAX_COLOR_MATRIX_STACK_DEPTH = 0x80B3;
public const int GL_POST_COLOR_MATRIX_RED_SCALE = 0x80B4;
public const int GL_POST_COLOR_MATRIX_GREEN_SCALE = 0x80B5;
public const int GL_POST_COLOR_MATRIX_BLUE_SCALE = 0x80B6;
public const int GL_POST_COLOR_MATRIX_ALPHA_SCALE = 0x80B7;
public const int GL_POST_COLOR_MATRIX_RED_BIAS = 0x80B8;
public const int GL_POST_COLOR_MATRIX_GREEN_BIAS = 0x80B9;
public const int GL_POST_COLOR_MATRIX_BLUE_BIAS = 0x80BA;
public const int GL_POST_COLOR_MATRIX_ALPHA_BIAS = 0x80BB;
public const int GL_HISTOGRAM = 0x8024;
public const int GL_PROXY_HISTOGRAM = 0x8025;
public const int GL_HISTOGRAM_WIDTH = 0x8026;
public const int GL_HISTOGRAM_FORMAT = 0x8027;
public const int GL_HISTOGRAM_RED_SIZE = 0x8028;
public const int GL_HISTOGRAM_GREEN_SIZE = 0x8029;
public const int GL_HISTOGRAM_BLUE_SIZE = 0x802A;
public const int GL_HISTOGRAM_ALPHA_SIZE = 0x802B;
public const int GL_HISTOGRAM_LUMINANCE_SIZE = 0x802C;
public const int GL_HISTOGRAM_SINK = 0x802D;
public const int GL_MINMAX = 0x802E;
public const int GL_MINMAX_FORMAT = 0x802F;
public const int GL_MINMAX_SINK = 0x8030;
public const int GL_TABLE_TOO_LARGE = 0x8031;
public const int GL_BLEND_EQUATION = 0x8009;
public const int GL_MIN = 0x8007;
public const int GL_MAX = 0x8008;
public const int GL_FUNC_ADD = 0x8006;
public const int GL_FUNC_SUBTRACT = 0x800A;
public const int GL_FUNC_REVERSE_SUBTRACT = 0x800B;
public const int GL_BLEND_COLOR = 0x8005;
public const int GL_TEXTURE0 = 0x84C0;
public const int GL_TEXTURE1 = 0x84C1;
public const int GL_TEXTURE2 = 0x84C2;
public const int GL_TEXTURE3 = 0x84C3;
public const int GL_TEXTURE4 = 0x84C4;
public const int GL_TEXTURE5 = 0x84C5;
public const int GL_TEXTURE6 = 0x84C6;
public const int GL_TEXTURE7 = 0x84C7;
public const int GL_TEXTURE8 = 0x84C8;
public const int GL_TEXTURE9 = 0x84C9;
public const int GL_TEXTURE10 = 0x84CA;
public const int GL_TEXTURE11 = 0x84CB;
public const int GL_TEXTURE12 = 0x84CC;
public const int GL_TEXTURE13 = 0x84CD;
public const int GL_TEXTURE14 = 0x84CE;
public const int GL_TEXTURE15 = 0x84CF;
public const int GL_TEXTURE16 = 0x84D0;
public const int GL_TEXTURE17 = 0x84D1;
public const int GL_TEXTURE18 = 0x84D2;
public const int GL_TEXTURE19 = 0x84D3;
public const int GL_TEXTURE20 = 0x84D4;
public const int GL_TEXTURE21 = 0x84D5;
public const int GL_TEXTURE22 = 0x84D6;
public const int GL_TEXTURE23 = 0x84D7;
public const int GL_TEXTURE24 = 0x84D8;
public const int GL_TEXTURE25 = 0x84D9;
public const int GL_TEXTURE26 = 0x84DA;
public const int GL_TEXTURE27 = 0x84DB;
public const int GL_TEXTURE28 = 0x84DC;
public const int GL_TEXTURE29 = 0x84DD;
public const int GL_TEXTURE30 = 0x84DE;
public const int GL_TEXTURE31 = 0x84DF;
public const int GL_ACTIVE_TEXTURE = 0x84E0;
public const int GL_CLIENT_ACTIVE_TEXTURE = 0x84E1;
public const int GL_MAX_TEXTURE_UNITS = 0x84E2;
public const int GL_NORMAL_MAP = 0x8511;
public const int GL_REFLECTION_MAP = 0x8512;
public const int GL_TEXTURE_CUBE_MAP = 0x8513;
public const int GL_TEXTURE_BINDING_CUBE_MAP = 0x8514;
public const int GL_TEXTURE_CUBE_MAP_POSITIVE_X = 0x8515;
public const int GL_TEXTURE_CUBE_MAP_NEGATIVE_X = 0x8516;
public const int GL_TEXTURE_CUBE_MAP_POSITIVE_Y = 0x8517;
public const int GL_TEXTURE_CUBE_MAP_NEGATIVE_Y = 0x8518;
public const int GL_TEXTURE_CUBE_MAP_POSITIVE_Z = 0x8519;
public const int GL_TEXTURE_CUBE_MAP_NEGATIVE_Z = 0x851A;
public const int GL_PROXY_TEXTURE_CUBE_MAP = 0x851B;
public const int GL_MAX_CUBE_MAP_TEXTURE_SIZE = 0x851C;
public const int GL_COMPRESSED_ALPHA = 0x84E9;
public const int GL_COMPRESSED_LUMINANCE = 0x84EA;
public const int GL_COMPRESSED_LUMINANCE_ALPHA = 0x84EB;
public const int GL_COMPRESSED_INTENSITY = 0x84EC;
public const int GL_COMPRESSED_RGB = 0x84ED;
public const int GL_COMPRESSED_RGBA = 0x84EE;
public const int GL_TEXTURE_COMPRESSION_HINT = 0x84EF;
public const int GL_TEXTURE_COMPRESSED_IMAGE_SIZE = 0x86A0;
public const int GL_TEXTURE_COMPRESSED = 0x86A1;
public const int GL_NUM_COMPRESSED_TEXTURE_FORMATS = 0x86A2;
public const int GL_COMPRESSED_TEXTURE_FORMATS = 0x86A3;
public const int GL_MULTISAMPLE = 0x809D;
public const int GL_SAMPLE_ALPHA_TO_COVERAGE = 0x809E;
public const int GL_SAMPLE_ALPHA_TO_ONE = 0x809F;
public const int GL_SAMPLE_COVERAGE = 0x80A0;
public const int GL_SAMPLE_BUFFERS = 0x80A8;
public const int GL_SAMPLES = 0x80A9;
public const int GL_SAMPLE_COVERAGE_VALUE = 0x80AA;
public const int GL_SAMPLE_COVERAGE_INVERT = 0x80AB;
public const int GL_MULTISAMPLE_BIT = 0x20000000;
public const int GL_TRANSPOSE_MODELVIEW_MATRIX = 0x84E3;
public const int GL_TRANSPOSE_PROJECTION_MATRIX = 0x84E4;
public const int GL_TRANSPOSE_TEXTURE_MATRIX = 0x84E5;
public const int GL_TRANSPOSE_COLOR_MATRIX = 0x84E6;
public const int GL_COMBINE = 0x8570;
public const int GL_COMBINE_RGB = 0x8571;
public const int GL_COMBINE_ALPHA = 0x8572;
public const int GL_SOURCE0_RGB = 0x8580;
public const int GL_SOURCE1_RGB = 0x8581;
public const int GL_SOURCE2_RGB = 0x8582;
public const int GL_SOURCE0_ALPHA = 0x8588;
public const int GL_SOURCE1_ALPHA = 0x8589;
public const int GL_SOURCE2_ALPHA = 0x858A;
public const int GL_OPERAND0_RGB = 0x8590;
public const int GL_OPERAND1_RGB = 0x8591;
public const int GL_OPERAND2_RGB = 0x8592;
public const int GL_OPERAND0_ALPHA = 0x8598;
public const int GL_OPERAND1_ALPHA = 0x8599;
public const int GL_OPERAND2_ALPHA = 0x859A;
public const int GL_RGB_SCALE = 0x8573;
public const int GL_ADD_SIGNED = 0x8574;
public const int GL_INTERPOLATE = 0x8575;
public const int GL_SUBTRACT = 0x84E7;
public const int GL_CONSTANT = 0x8576;
public const int GL_PRIMARY_COLOR = 0x8577;
public const int GL_PREVIOUS = 0x8578;
public const int GL_DOT3_RGB = 0x86AE;
public const int GL_DOT3_RGBA = 0x86AF;
public const int GL_CLAMP_TO_BORDER = 0x812D;
public const int GL_TEXTURE0_ARB = 0x84C0;
public const int GL_TEXTURE1_ARB = 0x84C1;
public const int GL_TEXTURE2_ARB = 0x84C2;
public const int GL_TEXTURE3_ARB = 0x84C3;
public const int GL_TEXTURE4_ARB = 0x84C4;
public const int GL_TEXTURE5_ARB = 0x84C5;
public const int GL_TEXTURE6_ARB = 0x84C6;
public const int GL_TEXTURE7_ARB = 0x84C7;
public const int GL_TEXTURE8_ARB = 0x84C8;
public const int GL_TEXTURE9_ARB = 0x84C9;
public const int GL_TEXTURE10_ARB = 0x84CA;
public const int GL_TEXTURE11_ARB = 0x84CB;
public const int GL_TEXTURE12_ARB = 0x84CC;
public const int GL_TEXTURE13_ARB = 0x84CD;
public const int GL_TEXTURE14_ARB = 0x84CE;
public const int GL_TEXTURE15_ARB = 0x84CF;
public const int GL_TEXTURE16_ARB = 0x84D0;
public const int GL_TEXTURE17_ARB = 0x84D1;
public const int GL_TEXTURE18_ARB = 0x84D2;
public const int GL_TEXTURE19_ARB = 0x84D3;
public const int GL_TEXTURE20_ARB = 0x84D4;
public const int GL_TEXTURE21_ARB = 0x84D5;
public const int GL_TEXTURE22_ARB = 0x84D6;
public const int GL_TEXTURE23_ARB = 0x84D7;
public const int GL_TEXTURE24_ARB = 0x84D8;
public const int GL_TEXTURE25_ARB = 0x84D9;
public const int GL_TEXTURE26_ARB = 0x84DA;
public const int GL_TEXTURE27_ARB = 0x84DB;
public const int GL_TEXTURE28_ARB = 0x84DC;
public const int GL_TEXTURE29_ARB = 0x84DD;
public const int GL_TEXTURE30_ARB = 0x84DE;
public const int GL_TEXTURE31_ARB = 0x84DF;
public const int GL_ACTIVE_TEXTURE_ARB = 0x84E0;
public const int GL_CLIENT_ACTIVE_TEXTURE_ARB = 0x84E1;
public const int GL_MAX_TEXTURE_UNITS_ARB = 0x84E2;
public const int GL_DEPTH_STENCIL_MESA = 0x8750;
public const int GL_UNSIGNED_INT_24_8_MESA = 0x8751;
public const int GL_UNSIGNED_INT_8_24_REV_MESA = 0x8752;
public const int GL_UNSIGNED_SHORT_15_1_MESA = 0x8753;
public const int GL_UNSIGNED_SHORT_1_15_REV_MESA = 0x8754;
public const int GL_ALPHA_BLEND_EQUATION_ATI = 0x883D;
// glext.h
public const int GL_FRAMEBUFFER_BINDING = 0x8CA6;
}
}

8
src/Avalonia.OpenGL/GlDisplayType.cs

@ -0,0 +1,8 @@
namespace Avalonia.OpenGL
{
public enum GlDisplayType
{
OpenGL2,
OpenGLES2
}
}

48
src/Avalonia.OpenGL/GlInterface.cs

@ -0,0 +1,48 @@
using System;
using System.Runtime.InteropServices;
namespace Avalonia.OpenGL
{
public delegate IntPtr GlGetProcAddressDelegate(string procName);
public class GlInterface : GlInterfaceBase
{
private readonly Func<string, bool, IntPtr> _getProcAddress;
public GlInterface(Func<string, bool, IntPtr> getProcAddress) : base(getProcAddress)
{
_getProcAddress = getProcAddress;
}
public IntPtr GetProcAddress(string proc) => _getProcAddress(proc, true);
public T GetProcAddress<T>(string proc) => Marshal.GetDelegateForFunctionPointer<T>(GetProcAddress(proc));
// ReSharper disable UnassignedGetOnlyAutoProperty
public delegate void GlClearStencil(int s);
[EntryPoint("glClearStencil")]
public GlClearStencil ClearStencil { get; }
public delegate void GlClearColor(int r, int g, int b, int a);
[EntryPoint("glClearColor")]
public GlClearColor ClearColor { get; }
public delegate void GlClear(int bits);
[EntryPoint("glClear")]
public GlClear Clear { get; }
public delegate void GlViewport(int x, int y, int width, int height);
[EntryPoint("glViewport")]
public GlViewport Viewport { get; }
[EntryPoint("glFlush")]
public Action Flush { get; }
public delegate void GlGetIntegerv(int name, out int rv);
[EntryPoint("glGetIntegerv")]
public GlGetIntegerv GetIntegerv { get; }
// ReSharper restore UnassignedGetOnlyAutoProperty
}
}

28
src/Avalonia.OpenGL/GlInterfaceBase.cs

@ -0,0 +1,28 @@
using System;
using System.Reflection;
using System.Runtime.InteropServices;
namespace Avalonia.OpenGL
{
public class GlInterfaceBase
{
public GlInterfaceBase(Func<string, bool, IntPtr> getProcAddress)
{
foreach (var prop in this.GetType().GetProperties())
{
var a = prop.GetCustomAttribute<EntryPointAttribute>();
if (a != null)
{
var fieldName = $"<{prop.Name}>k__BackingField";
var field = prop.DeclaringType.GetField(fieldName,
BindingFlags.Instance | BindingFlags.NonPublic);
if (field == null)
throw new InvalidProgramException($"Expected property {prop.Name} to have {fieldName}");
var proc = getProcAddress(a.EntryPoint, a.Optional);
if (proc != IntPtr.Zero)
field.SetValue(this, Marshal.GetDelegateForFunctionPointer(proc, prop.PropertyType));
}
}
}
}
}

8
src/Avalonia.OpenGL/IGlContext.cs

@ -0,0 +1,8 @@
namespace Avalonia.OpenGL
{
public interface IGlContext
{
IGlDisplay Display { get; }
void MakeCurrent(IGlSurface surface);
}
}

11
src/Avalonia.OpenGL/IGlDisplay.cs

@ -0,0 +1,11 @@
namespace Avalonia.OpenGL
{
public interface IGlDisplay
{
GlDisplayType Type { get; }
GlInterface GlInterface { get; }
void ClearContext();
int SampleCount { get; }
int StencilSize { get; }
}
}

7
src/Avalonia.OpenGL/IGlPlatformSurface.cs

@ -0,0 +1,7 @@
namespace Avalonia.OpenGL
{
public interface IGlPlatformSurface
{
IGlPlatformSurfaceRenderTarget CreateGlRenderTarget();
}
}

9
src/Avalonia.OpenGL/IGlPlatformSurfaceRenderTarget.cs

@ -0,0 +1,9 @@
using System;
namespace Avalonia.OpenGL
{
public interface IGlPlatformSurfaceRenderTarget : IDisposable
{
IGlPlatformSurfaceRenderingSession BeginDraw();
}
}

12
src/Avalonia.OpenGL/IGlPlatformSurfaceRenderingSession.cs

@ -0,0 +1,12 @@
using System;
namespace Avalonia.OpenGL
{
public interface IGlPlatformSurfaceRenderingSession : IDisposable
{
IGlDisplay Display { get; }
// TODO: Change to PixelSize struct once https://github.com/AvaloniaUI/Avalonia/pull/1889 is merged
System.Drawing.Size PixelSize { get; }
double Scaling { get; }
}
}

10
src/Avalonia.OpenGL/IGlSurface.cs

@ -0,0 +1,10 @@
using System;
namespace Avalonia.OpenGL
{
public interface IGlSurface : IDisposable
{
IGlDisplay Display { get; }
void SwapBuffers();
}
}

7
src/Avalonia.OpenGL/IWindowingPlatformGlFeature.cs

@ -0,0 +1,7 @@
namespace Avalonia.OpenGL
{
public interface IWindowingPlatformGlFeature
{
IGlContext ImmediateContext { get; }
}
}

12
src/Avalonia.OpenGL/OpenGlException.cs

@ -0,0 +1,12 @@
using System;
namespace Avalonia.OpenGL
{
public class OpenGlException : Exception
{
public OpenGlException(string message) : base(message)
{
}
}
}

4
src/Avalonia.ReactiveUI/AppBuilderExtensions.cs

@ -4,6 +4,7 @@
using Avalonia.Controls;
using Avalonia.Threading;
using ReactiveUI;
using Splat;
namespace Avalonia
{
@ -15,6 +16,9 @@ namespace Avalonia
return builder.AfterSetup(_ =>
{
RxApp.MainThreadScheduler = AvaloniaScheduler.Instance;
Locator.CurrentMutable.Register(
() => new AvaloniaActivationForViewFetcher(),
typeof(IActivationForViewFetcher));
});
}
}

38
src/Avalonia.ReactiveUI/AvaloniaActivationForViewFetcher.cs

@ -0,0 +1,38 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Reflection;
using System.Reactive.Linq;
using Avalonia;
using Avalonia.VisualTree;
using ReactiveUI;
namespace Avalonia
{
public class AvaloniaActivationForViewFetcher : IActivationForViewFetcher
{
public int GetAffinityForView(Type view)
{
return typeof(IVisual).GetTypeInfo().IsAssignableFrom(view.GetTypeInfo()) ? 10 : 0;
}
public IObservable<bool> GetActivationForView(IActivatable view)
{
if (!(view is IVisual visual)) return Observable.Return(false);
var viewLoaded = Observable
.FromEventPattern<VisualTreeAttachmentEventArgs>(
x => visual.AttachedToVisualTree += x,
x => visual.DetachedFromVisualTree -= x)
.Select(args => true);
var viewUnloaded = Observable
.FromEventPattern<VisualTreeAttachmentEventArgs>(
x => visual.DetachedFromVisualTree += x,
x => visual.DetachedFromVisualTree -= x)
.Select(args => false);
return viewLoaded
.Merge(viewUnloaded)
.DistinctUntilChanged();
}
}
}

19
src/Avalonia.Styling/Styling/Style.cs

@ -125,17 +125,20 @@ namespace Avalonia.Styling
var subs = new CompositeDisposable(Setters.Count + Animations.Count);
foreach (var animation in Animations)
if (control is Animatable animatable)
{
IObservable<bool> obsMatch = match.ObservableResult;
if (match.ImmediateResult == true)
foreach (var animation in Animations)
{
obsMatch = Observable.Return(true);
}
IObservable<bool> obsMatch = match.ObservableResult;
var sub = animation.Apply((Animatable)control, obsMatch);
subs.Add(sub);
if (match.ImmediateResult == true)
{
obsMatch = Observable.Return(true);
}
var sub = animation.Apply(animatable, null, obsMatch);
subs.Add(sub);
}
}
foreach (var setter in Setters)

12
src/Avalonia.Themes.Default/MenuItem.xaml

@ -73,7 +73,17 @@
</ControlTemplate>
</Setter>
</Style>
<Style Selector="MenuItem:separator">
<Setter Property="Template">
<ControlTemplate>
<Separator Background="{DynamicResource ThemeControlMidBrush}"
Margin="29,1,0,1"
Height="1"/>
</ControlTemplate>
</Setter>
</Style>
<Style Selector="Menu > MenuItem">
<Setter Property="Template">
<ControlTemplate>

26
src/Avalonia.Visuals/Animation/RenderLoopClock.cs

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Text;
using Avalonia.Rendering;
namespace Avalonia.Animation
{
public class RenderLoopClock : ClockBase, IRenderLoopTask, IGlobalClock
{
protected override void Stop()
{
AvaloniaLocator.Current.GetService<IRenderLoop>().Remove(this);
}
bool IRenderLoopTask.NeedsUpdate => HasSubscriptions;
void IRenderLoopTask.Render()
{
}
void IRenderLoopTask.Update(TimeSpan time)
{
Pulse(time);
}
}
}

20
src/Avalonia.Visuals/Animation/TransformAnimator.cs

@ -9,10 +9,10 @@ namespace Avalonia.Animation
/// </summary>
public class TransformAnimator : Animator<double>
{
DoubleAnimator childKeyFrames;
DoubleAnimator childAnimator;
/// <inheritdoc/>
public override IDisposable Apply(Animation animation, Animatable control, IObservable<bool> obsMatch, Action onComplete)
public override IDisposable Apply(Animation animation, Animatable control, IClock clock, IObservable<bool> obsMatch, Action onComplete)
{
var ctrl = (Visual)control;
@ -36,15 +36,15 @@ namespace Avalonia.Animation
var renderTransformType = ctrl.RenderTransform.GetType();
if (childKeyFrames == null)
if (childAnimator == null)
{
InitializeChildKeyFrames();
InitializeChildAnimator();
}
// It's a transform object so let's target that.
if (renderTransformType == Property.OwnerType)
{
return childKeyFrames.Apply(animation, ctrl.RenderTransform, obsMatch, onComplete);
return childAnimator.Apply(animation, ctrl.RenderTransform, clock ?? control.Clock, obsMatch, onComplete);
}
// It's a TransformGroup and try finding the target there.
else if (renderTransformType == typeof(TransformGroup))
@ -53,7 +53,7 @@ namespace Avalonia.Animation
{
if (transform.GetType() == Property.OwnerType)
{
return childKeyFrames.Apply(animation, transform, obsMatch, onComplete);
return childAnimator.Apply(animation, transform, clock ?? control.Clock, obsMatch, onComplete);
}
}
}
@ -73,16 +73,16 @@ namespace Avalonia.Animation
return null;
}
void InitializeChildKeyFrames()
void InitializeChildAnimator()
{
childKeyFrames = new DoubleAnimator();
childAnimator = new DoubleAnimator();
foreach (AnimatorKeyFrame keyframe in this)
{
childKeyFrames.Add(keyframe);
childAnimator.Add(keyframe);
}
childKeyFrames.Property = Property;
childAnimator.Property = Property;
}
/// <inheritdocs/>

1
src/Avalonia.Visuals/Avalonia.Visuals.csproj

@ -1,6 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace>Avalonia</RootNamespace>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Avalonia.Animation\Avalonia.Animation.csproj" />

2
src/Avalonia.Visuals/Matrix.cs

@ -47,7 +47,7 @@ namespace Avalonia
/// <summary>
/// Returns the multiplicative identity matrix.
/// </summary>
public static Matrix Identity => new Matrix(1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
public static Matrix Identity { get; } = new Matrix(1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
/// <summary>
/// Returns whether the matrix is the identity matrix.

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save