committed by
GitHub
125 changed files with 2400 additions and 639 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,61 @@ |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using Avalonia.Metadata; |
|||
|
|||
namespace Avalonia.Animation |
|||
{ |
|||
/// <summary>
|
|||
/// Defines a composite page transition that can be used to combine multiple transitions.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// <para>
|
|||
/// Instantiate the <see cref="CompositePageTransition" /> in XAML and initialize the
|
|||
/// <see cref="Transitions" /> property in order to have many animations triggered at once.
|
|||
/// For example, you can combine <see cref="CrossFade"/> and <see cref="PageSlide"/>.
|
|||
/// <code>
|
|||
/// <![CDATA[
|
|||
/// <reactiveUi:RoutedViewHost Router="{Binding Router}">
|
|||
/// <reactiveUi:RoutedViewHost.PageTransition>
|
|||
/// <CompositePageTransition>
|
|||
/// <PageSlide Duration="0.5" />
|
|||
/// <CrossFade Duration="0.5" />
|
|||
/// </CompositePageTransition>
|
|||
/// </reactiveUi:RoutedViewHost.PageTransition>
|
|||
/// </reactiveUi:RoutedViewHost>
|
|||
/// ]]>
|
|||
/// </code>
|
|||
/// </para>
|
|||
/// </remarks>
|
|||
public class CompositePageTransition : IPageTransition |
|||
{ |
|||
/// <summary>
|
|||
/// Gets or sets the transitions to be executed. Can be defined from XAML.
|
|||
/// </summary>
|
|||
[Content] |
|||
public List<IPageTransition> PageTransitions { get; set; } = new List<IPageTransition>(); |
|||
|
|||
/// <summary>
|
|||
/// Starts the animation.
|
|||
/// </summary>
|
|||
/// <param name="from">
|
|||
/// The control that is being transitioned away from. May be null.
|
|||
/// </param>
|
|||
/// <param name="to">
|
|||
/// The control that is being transitioned to. May be null.
|
|||
/// </param>
|
|||
/// <param name="forward">
|
|||
/// Defines the direction of the transition.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// A <see cref="Task"/> that tracks the progress of the animation.
|
|||
/// </returns>
|
|||
public Task Start(Visual from, Visual to, bool forward) |
|||
{ |
|||
var transitionTasks = PageTransitions |
|||
.Select(transition => transition.Start(from, to, forward)) |
|||
.ToList(); |
|||
return Task.WhenAll(transitionTasks); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,134 @@ |
|||
using System; |
|||
using Avalonia.OpenGL; |
|||
using SkiaSharp; |
|||
using static Avalonia.OpenGL.GlConsts; |
|||
namespace Avalonia.Skia |
|||
{ |
|||
public class FboSkiaSurface : ISkiaSurface |
|||
{ |
|||
private readonly GRContext _grContext; |
|||
private readonly IGlContext _glContext; |
|||
private readonly PixelSize _pixelSize; |
|||
private int _fbo; |
|||
private int _depthStencil; |
|||
private int _texture; |
|||
|
|||
private static readonly bool[] TrueFalse = new[] { true, false }; |
|||
public FboSkiaSurface(GRContext grContext, IGlContext glContext, PixelSize pixelSize) |
|||
{ |
|||
_grContext = grContext; |
|||
_glContext = glContext; |
|||
_pixelSize = pixelSize; |
|||
var InternalFormat = glContext.Version.Type == GlProfileType.OpenGLES ? GL_RGBA : GL_RGBA8; |
|||
var gl = glContext.GlInterface; |
|||
|
|||
// Save old bindings
|
|||
gl.GetIntegerv(GL_FRAMEBUFFER_BINDING, out var oldFbo); |
|||
gl.GetIntegerv(GL_RENDERBUFFER_BINDING, out var oldRenderbuffer); |
|||
gl.GetIntegerv(GL_TEXTURE_BINDING_2D, out var oldTexture); |
|||
|
|||
var arr = new int[2]; |
|||
|
|||
// Generate FBO
|
|||
gl.GenFramebuffers(1, arr); |
|||
_fbo = arr[0]; |
|||
gl.BindFramebuffer(GL_FRAMEBUFFER, _fbo); |
|||
|
|||
// Create a texture to render into
|
|||
gl.GenTextures(1, arr); |
|||
_texture = arr[0]; |
|||
gl.BindTexture(GL_TEXTURE_2D, _texture); |
|||
gl.TexImage2D(GL_TEXTURE_2D, 0, |
|||
InternalFormat, pixelSize.Width, pixelSize.Height, |
|||
0, GL_RGBA, GL_UNSIGNED_BYTE, IntPtr.Zero); |
|||
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
|||
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
|||
gl.FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _texture, 0); |
|||
|
|||
var success = false; |
|||
foreach (var useStencil8 in TrueFalse) |
|||
{ |
|||
gl.GenRenderbuffers(1, arr); |
|||
_depthStencil = arr[0]; |
|||
gl.BindRenderbuffer(GL_RENDERBUFFER, _depthStencil); |
|||
|
|||
if (useStencil8) |
|||
{ |
|||
gl.RenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, pixelSize.Width, pixelSize.Height); |
|||
gl.FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, _depthStencil); |
|||
} |
|||
else |
|||
{ |
|||
gl.RenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, pixelSize.Width, pixelSize.Height); |
|||
gl.FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _depthStencil); |
|||
gl.FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, _depthStencil); |
|||
} |
|||
|
|||
var status = gl.CheckFramebufferStatus(GL_FRAMEBUFFER); |
|||
if (status == GL_FRAMEBUFFER_COMPLETE) |
|||
{ |
|||
success = true; |
|||
break; |
|||
} |
|||
else |
|||
{ |
|||
gl.BindRenderbuffer(GL_RENDERBUFFER, oldRenderbuffer); |
|||
gl.DeleteRenderbuffers(1, arr); |
|||
} |
|||
} |
|||
|
|||
gl.BindRenderbuffer(GL_RENDERBUFFER, oldRenderbuffer); |
|||
gl.BindTexture(GL_TEXTURE_2D, oldTexture); |
|||
gl.BindFramebuffer(GL_FRAMEBUFFER, oldFbo); |
|||
|
|||
if (!success) |
|||
{ |
|||
arr[0] = _fbo; |
|||
gl.DeleteFramebuffers(1, arr); |
|||
arr[0] = _texture; |
|||
gl.DeleteTextures(1, arr); |
|||
throw new OpenGlException("Unable to create FBO with stencil"); |
|||
} |
|||
|
|||
var target = new GRBackendRenderTarget(pixelSize.Width, pixelSize.Height, 0, 8, |
|||
new GRGlFramebufferInfo((uint)_fbo, SKColorType.Rgba8888.ToGlSizedFormat())); |
|||
Surface = SKSurface.Create(_grContext, target, |
|||
GRSurfaceOrigin.BottomLeft, SKColorType.Rgba8888); |
|||
CanBlit = gl.BlitFramebuffer != null; |
|||
} |
|||
|
|||
public void Dispose() |
|||
{ |
|||
using (_glContext.EnsureCurrent()) |
|||
{ |
|||
Surface?.Dispose(); |
|||
Surface = null; |
|||
var gl = _glContext.GlInterface; |
|||
if (_fbo != 0) |
|||
{ |
|||
gl.DeleteFramebuffers(1, new[] { _fbo }); |
|||
gl.DeleteTextures(1, new[] { _texture }); |
|||
gl.DeleteRenderbuffers(1, new[] { _depthStencil }); |
|||
_fbo = _texture = _depthStencil = 0; |
|||
} |
|||
} |
|||
} |
|||
|
|||
public SKSurface Surface { get; private set; } |
|||
public bool CanBlit { get; } |
|||
public void Blit(SKCanvas canvas) |
|||
{ |
|||
// This should set the render target as the current FBO
|
|||
// which is definitely not the best method, but it works
|
|||
canvas.Clear(); |
|||
canvas.Flush(); |
|||
|
|||
var gl = _glContext.GlInterface; |
|||
gl.GetIntegerv(GL_READ_FRAMEBUFFER_BINDING, out var oldRead); |
|||
gl.BindFramebuffer(GL_READ_FRAMEBUFFER, _fbo); |
|||
gl.BlitFramebuffer(0, 0, _pixelSize.Width, _pixelSize.Height, 0, 0, _pixelSize.Width, _pixelSize.Height, |
|||
GL_COLOR_BUFFER_BIT, GL_LINEAR); |
|||
gl.BindFramebuffer(GL_READ_FRAMEBUFFER, oldRead); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,31 @@ |
|||
using Avalonia.Platform; |
|||
using Avalonia.Rendering; |
|||
using SkiaSharp; |
|||
|
|||
namespace Avalonia.Skia.Helpers |
|||
{ |
|||
public class DrawingContextHelper |
|||
{ |
|||
/// <summary>
|
|||
/// Wrap Skia canvas in drawing context so we can use Avalonia api to render to external skia canvas
|
|||
/// this is useful in scenarios where canvas is not controlled by application, but received from another non avalonia api
|
|||
/// like: SKCanvas canvas = SKDocument.BeginPage(...);
|
|||
/// </summary>
|
|||
/// <param name="canvas"></param>
|
|||
/// <param name="dpi"></param>
|
|||
/// <param name="visualBrushRenderer"></param>
|
|||
/// <returns>DrawingContext</returns>
|
|||
public static IDrawingContextImpl WrapSkiaCanvas(SKCanvas canvas, Vector dpi, IVisualBrushRenderer visualBrushRenderer = null) |
|||
{ |
|||
var createInfo = new DrawingContextImpl.CreateInfo |
|||
{ |
|||
Canvas = canvas, |
|||
Dpi = dpi, |
|||
VisualBrushRenderer = visualBrushRenderer, |
|||
DisableTextLcdRendering = true, |
|||
}; |
|||
|
|||
return new DrawingContextImpl(createInfo); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,62 @@ |
|||
namespace Avalonia.Win32.OpenGl |
|||
{ |
|||
internal class WglConsts |
|||
{ |
|||
public const int WGL_CONTEXT_MAJOR_VERSION_ARB = 0x2091; |
|||
public const int WGL_CONTEXT_MINOR_VERSION_ARB = 0x2092; |
|||
public const int WGL_CONTEXT_LAYER_PLANE_ARB = 0x2093; |
|||
public const int WGL_CONTEXT_FLAGS_ARB = 0x2094; |
|||
public const int WGL_CONTEXT_PROFILE_MASK_ARB = 0x9126; |
|||
public const int WGL_NUMBER_PIXEL_FORMATS_ARB = 0x2000; |
|||
|
|||
public const int WGL_DRAW_TO_WINDOW_ARB = 0x2001; |
|||
public const int WGL_DRAW_TO_BITMAP_ARB = 0x2002; |
|||
public const int WGL_ACCELERATION_ARB = 0x2003; |
|||
public const int WGL_NEED_PALETTE_ARB = 0x2004; |
|||
public const int WGL_NEED_SYSTEM_PALETTE_ARB = 0x2005; |
|||
public const int WGL_SWAP_LAYER_BUFFERS_ARB = 0x2006; |
|||
public const int WGL_SWAP_METHOD_ARB = 0x2007; |
|||
public const int WGL_NUMBER_OVERLAYS_ARB = 0x2008; |
|||
public const int WGL_NUMBER_UNDERLAYS_ARB = 0x2009; |
|||
public const int WGL_TRANSPARENT_ARB = 0x200A; |
|||
public const int WGL_TRANSPARENT_RED_VALUE_ARB = 0x2037; |
|||
public const int WGL_TRANSPARENT_GREEN_VALUE_ARB = 0x2038; |
|||
public const int WGL_TRANSPARENT_BLUE_VALUE_ARB = 0x2039; |
|||
public const int WGL_TRANSPARENT_ALPHA_VALUE_ARB = 0x203A; |
|||
public const int WGL_TRANSPARENT_INDEX_VALUE_ARB = 0x203B; |
|||
public const int WGL_SHARE_DEPTH_ARB = 0x200C; |
|||
public const int WGL_SHARE_STENCIL_ARB = 0x200D; |
|||
public const int WGL_SHARE_ACCUM_ARB = 0x200E; |
|||
public const int WGL_SUPPORT_GDI_ARB = 0x200F; |
|||
public const int WGL_SUPPORT_OPENGL_ARB = 0x2010; |
|||
public const int WGL_DOUBLE_BUFFER_ARB = 0x2011; |
|||
public const int WGL_STEREO_ARB = 0x2012; |
|||
public const int WGL_PIXEL_TYPE_ARB = 0x2013; |
|||
public const int WGL_COLOR_BITS_ARB = 0x2014; |
|||
public const int WGL_RED_BITS_ARB = 0x2015; |
|||
public const int WGL_RED_SHIFT_ARB = 0x2016; |
|||
public const int WGL_GREEN_BITS_ARB = 0x2017; |
|||
public const int WGL_GREEN_SHIFT_ARB = 0x2018; |
|||
public const int WGL_BLUE_BITS_ARB = 0x2019; |
|||
public const int WGL_BLUE_SHIFT_ARB = 0x201A; |
|||
public const int WGL_ALPHA_BITS_ARB = 0x201B; |
|||
public const int WGL_ALPHA_SHIFT_ARB = 0x201C; |
|||
public const int WGL_ACCUM_BITS_ARB = 0x201D; |
|||
public const int WGL_ACCUM_RED_BITS_ARB = 0x201E; |
|||
public const int WGL_ACCUM_GREEN_BITS_ARB = 0x201F; |
|||
public const int WGL_ACCUM_BLUE_BITS_ARB = 0x2020; |
|||
public const int WGL_ACCUM_ALPHA_BITS_ARB = 0x2021; |
|||
public const int WGL_DEPTH_BITS_ARB = 0x2022; |
|||
public const int WGL_STENCIL_BITS_ARB = 0x2023; |
|||
public const int WGL_AUX_BUFFERS_ARB = 0x2024; |
|||
public const int WGL_NO_ACCELERATION_ARB = 0x2025; |
|||
public const int WGL_GENERIC_ACCELERATION_ARB = 0x2026; |
|||
public const int WGL_FULL_ACCELERATION_ARB = 0x2027; |
|||
public const int WGL_SWAP_EXCHANGE_ARB = 0x2028; |
|||
public const int WGL_SWAP_COPY_ARB = 0x2029; |
|||
public const int WGL_SWAP_UNDEFINED_ARB = 0x202A; |
|||
public const int WGL_TYPE_RGBA_ARB = 0x202B; |
|||
public const int WGL_TYPE_COLORINDEX_ARB = 0x202C; |
|||
|
|||
} |
|||
} |
|||
@ -0,0 +1,85 @@ |
|||
using System; |
|||
using System.Reactive.Disposables; |
|||
using Avalonia.OpenGL; |
|||
using Avalonia.Win32.Interop; |
|||
using static Avalonia.Win32.Interop.UnmanagedMethods; |
|||
using static Avalonia.Win32.OpenGl.WglConsts; |
|||
|
|||
namespace Avalonia.Win32.OpenGl |
|||
{ |
|||
class WglContext : IGlContext |
|||
{ |
|||
private object _lock = new object(); |
|||
private readonly WglContext _sharedWith; |
|||
private readonly IntPtr _context; |
|||
private readonly IntPtr _hWnd; |
|||
private readonly IntPtr _dc; |
|||
private readonly int _pixelFormat; |
|||
private readonly PixelFormatDescriptor _formatDescriptor; |
|||
public IntPtr Handle => _context; |
|||
|
|||
public WglContext(WglContext sharedWith, GlVersion version, IntPtr context, IntPtr hWnd, IntPtr dc, int pixelFormat, |
|||
PixelFormatDescriptor formatDescriptor) |
|||
{ |
|||
Version = version; |
|||
_sharedWith = sharedWith; |
|||
_context = context; |
|||
_hWnd = hWnd; |
|||
_dc = dc; |
|||
_pixelFormat = pixelFormat; |
|||
_formatDescriptor = formatDescriptor; |
|||
StencilSize = formatDescriptor.StencilBits; |
|||
using (MakeCurrent()) |
|||
GlInterface = new GlInterface(version, proc => |
|||
{ |
|||
var ext = wglGetProcAddress(proc); |
|||
if (ext != IntPtr.Zero) |
|||
return ext; |
|||
return GetProcAddress(WglDisplay.OpenGl32Handle, proc); |
|||
}); |
|||
|
|||
} |
|||
|
|||
public void Dispose() |
|||
{ |
|||
wglDeleteContext(_context); |
|||
ReleaseDC(_hWnd, _dc); |
|||
DestroyWindow(_hWnd); |
|||
} |
|||
|
|||
public GlVersion Version { get; } |
|||
public GlInterface GlInterface { get; } |
|||
public int SampleCount { get; } |
|||
public int StencilSize { get; } |
|||
|
|||
private bool IsCurrent => wglGetCurrentContext() == _context && wglGetCurrentDC() == _dc; |
|||
public IDisposable MakeCurrent() |
|||
{ |
|||
if(IsCurrent) |
|||
return Disposable.Empty; |
|||
return new WglRestoreContext(_dc, _context, _lock); |
|||
} |
|||
|
|||
public IDisposable EnsureCurrent() => MakeCurrent(); |
|||
|
|||
|
|||
public IntPtr CreateConfiguredDeviceContext(IntPtr hWnd) |
|||
{ |
|||
var dc = GetDC(hWnd); |
|||
var fmt = _formatDescriptor; |
|||
SetPixelFormat(dc, _pixelFormat, ref fmt); |
|||
return dc; |
|||
} |
|||
|
|||
public IDisposable MakeCurrent(IntPtr hdc) => new WglRestoreContext(hdc, _context, _lock); |
|||
|
|||
public bool IsSharedWith(IGlContext context) |
|||
{ |
|||
var c = (WglContext)context; |
|||
return c == this |
|||
|| c._sharedWith == this |
|||
|| _sharedWith == context |
|||
|| _sharedWith != null && _sharedWith == c._sharedWith; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,183 @@ |
|||
using System; |
|||
using System.Runtime.InteropServices; |
|||
using Avalonia.OpenGL; |
|||
using Avalonia.Win32.Interop; |
|||
using static Avalonia.Win32.Interop.UnmanagedMethods; |
|||
using static Avalonia.Win32.OpenGl.WglConsts; |
|||
namespace Avalonia.Win32.OpenGl |
|||
{ |
|||
internal class WglDisplay |
|||
{ |
|||
private static bool? _initialized; |
|||
private static ushort _windowClass; |
|||
private static readonly WndProc _wndProcDelegate = WndProc; |
|||
private static readonly DebugCallbackDelegate _debugCallback = DebugCallback; |
|||
|
|||
private static IntPtr _bootstrapContext; |
|||
private static IntPtr _bootstrapWindow; |
|||
private static IntPtr _bootstrapDc; |
|||
private static PixelFormatDescriptor _defaultPfd; |
|||
private static int _defaultPixelFormat; |
|||
public static IntPtr OpenGl32Handle = LoadLibrary("opengl32"); |
|||
|
|||
private delegate bool WglChoosePixelFormatARBDelegate(IntPtr hdc, int[] piAttribIList, float[] pfAttribFList, |
|||
int nMaxFormats, int[] piFormats, out int nNumFormats); |
|||
|
|||
private static WglChoosePixelFormatARBDelegate WglChoosePixelFormatArb; |
|||
|
|||
private delegate IntPtr WglCreateContextAttribsARBDelegate(IntPtr hDC, IntPtr hShareContext, int[] attribList); |
|||
|
|||
private static WglCreateContextAttribsARBDelegate WglCreateContextAttribsArb; |
|||
|
|||
private delegate void GlDebugMessageCallbackDelegate(IntPtr callback, IntPtr userParam); |
|||
|
|||
private static GlDebugMessageCallbackDelegate GlDebugMessageCallback; |
|||
|
|||
private delegate void DebugCallbackDelegate(int source, int type, int id, int severity, int len, IntPtr message, |
|||
IntPtr userParam); |
|||
|
|||
static bool Initialize() |
|||
{ |
|||
if (!_initialized.HasValue) |
|||
_initialized = InitializeCore(); |
|||
return _initialized.Value; |
|||
} |
|||
static bool InitializeCore() |
|||
{ |
|||
var wndClassEx = new WNDCLASSEX |
|||
{ |
|||
cbSize = Marshal.SizeOf<WNDCLASSEX>(), |
|||
hInstance = GetModuleHandle(null), |
|||
lpfnWndProc = _wndProcDelegate, |
|||
lpszClassName = "AvaloniaGlWindow-" + Guid.NewGuid(), |
|||
style = (int)ClassStyles.CS_OWNDC |
|||
}; |
|||
|
|||
_windowClass = RegisterClassEx(ref wndClassEx); |
|||
_bootstrapWindow = CreateOffscreenWindow(); |
|||
_bootstrapDc = GetDC(_bootstrapWindow); |
|||
_defaultPfd = new PixelFormatDescriptor |
|||
{ |
|||
Size = (ushort)Marshal.SizeOf<PixelFormatDescriptor>(), |
|||
Version = 1, |
|||
Flags = PixelFormatDescriptorFlags.PFD_DRAW_TO_WINDOW | |
|||
PixelFormatDescriptorFlags.PFD_SUPPORT_OPENGL | PixelFormatDescriptorFlags.PFD_DOUBLEBUFFER, |
|||
DepthBits = 24, |
|||
StencilBits = 8, |
|||
ColorBits = 32 |
|||
}; |
|||
_defaultPixelFormat = ChoosePixelFormat(_bootstrapDc, ref _defaultPfd); |
|||
SetPixelFormat(_bootstrapDc, _defaultPixelFormat, ref _defaultPfd); |
|||
|
|||
_bootstrapContext = wglCreateContext(_bootstrapDc); |
|||
if (_bootstrapContext == IntPtr.Zero) |
|||
return false; |
|||
|
|||
wglMakeCurrent(_bootstrapDc, _bootstrapContext); |
|||
WglCreateContextAttribsArb = Marshal.GetDelegateForFunctionPointer<WglCreateContextAttribsARBDelegate>( |
|||
wglGetProcAddress("wglCreateContextAttribsARB")); |
|||
|
|||
WglChoosePixelFormatArb = |
|||
Marshal.GetDelegateForFunctionPointer<WglChoosePixelFormatARBDelegate>( |
|||
wglGetProcAddress("wglChoosePixelFormatARB")); |
|||
|
|||
GlDebugMessageCallback = |
|||
Marshal.GetDelegateForFunctionPointer<GlDebugMessageCallbackDelegate>( |
|||
wglGetProcAddress("glDebugMessageCallback")); |
|||
|
|||
|
|||
var formats = new int[1]; |
|||
WglChoosePixelFormatArb(_bootstrapDc, new int[] |
|||
{ |
|||
WGL_DRAW_TO_WINDOW_ARB, 1, |
|||
WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB, |
|||
WGL_SUPPORT_OPENGL_ARB, 1, |
|||
WGL_DOUBLE_BUFFER_ARB, 1, |
|||
WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB, |
|||
WGL_COLOR_BITS_ARB, 32, |
|||
WGL_DEPTH_BITS_ARB, 0, |
|||
WGL_STENCIL_BITS_ARB, 0, |
|||
0, // End
|
|||
}, null, 1, formats, out int numFormats); |
|||
if (numFormats != 0) |
|||
{ |
|||
DescribePixelFormat(_bootstrapDc, formats[0], Marshal.SizeOf<PixelFormatDescriptor>(), ref _defaultPfd); |
|||
_defaultPixelFormat = formats[0]; |
|||
} |
|||
|
|||
|
|||
wglMakeCurrent(IntPtr.Zero, IntPtr.Zero); |
|||
return true; |
|||
} |
|||
|
|||
static IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam) |
|||
{ |
|||
return DefWindowProc(hWnd, msg, wParam, lParam); |
|||
} |
|||
|
|||
private static void DebugCallback(int source, int type, int id, int severity, int len, IntPtr message, IntPtr userparam) |
|||
{ |
|||
var err = Marshal.PtrToStringAnsi(message, len); |
|||
Console.Error.WriteLine(err); |
|||
} |
|||
|
|||
public static WglContext CreateContext(GlVersion[] versions, IGlContext share) |
|||
{ |
|||
if (!Initialize()) |
|||
return null; |
|||
|
|||
var shareContext = (WglContext)share; |
|||
|
|||
using (new WglRestoreContext(_bootstrapDc, _bootstrapContext, null)) |
|||
{ |
|||
var window = CreateOffscreenWindow(); |
|||
var dc = GetDC(window); |
|||
SetPixelFormat(dc, _defaultPixelFormat, ref _defaultPfd); |
|||
foreach (var version in versions) |
|||
{ |
|||
if(version.Type != GlProfileType.OpenGL) |
|||
continue; |
|||
var context = WglCreateContextAttribsArb(dc, shareContext?.Handle ?? IntPtr.Zero, |
|||
new[] |
|||
{ |
|||
// major
|
|||
WGL_CONTEXT_MAJOR_VERSION_ARB, version.Major, |
|||
// minor
|
|||
WGL_CONTEXT_MINOR_VERSION_ARB, version.Minor, |
|||
// core profile
|
|||
WGL_CONTEXT_PROFILE_MASK_ARB, 1, |
|||
// debug
|
|||
// WGL_CONTEXT_FLAGS_ARB, 1,
|
|||
// end
|
|||
0, 0 |
|||
}); |
|||
using(new WglRestoreContext(dc, context, null)) |
|||
GlDebugMessageCallback(Marshal.GetFunctionPointerForDelegate(_debugCallback), IntPtr.Zero); |
|||
if (context != IntPtr.Zero) |
|||
return new WglContext(shareContext, version, context, window, dc, |
|||
_defaultPixelFormat, _defaultPfd); |
|||
} |
|||
|
|||
ReleaseDC(window, dc); |
|||
DestroyWindow(window); |
|||
return null; |
|||
} |
|||
} |
|||
|
|||
|
|||
static IntPtr CreateOffscreenWindow() => |
|||
CreateWindowEx( |
|||
0, |
|||
_windowClass, |
|||
null, |
|||
(int)WindowStyles.WS_OVERLAPPEDWINDOW, |
|||
0, |
|||
0, |
|||
640, |
|||
480, |
|||
IntPtr.Zero, |
|||
IntPtr.Zero, |
|||
IntPtr.Zero, |
|||
IntPtr.Zero); |
|||
} |
|||
} |
|||
@ -0,0 +1,85 @@ |
|||
using System; |
|||
using System.Diagnostics; |
|||
using Avalonia.OpenGL; |
|||
using Avalonia.OpenGL.Egl; |
|||
using Avalonia.OpenGL.Surfaces; |
|||
using Avalonia.Win32.Interop; |
|||
using static Avalonia.OpenGL.GlConsts; |
|||
using static Avalonia.Win32.Interop.UnmanagedMethods; |
|||
namespace Avalonia.Win32.OpenGl |
|||
{ |
|||
class WglGlPlatformSurface: IGlPlatformSurface |
|||
{ |
|||
|
|||
private readonly WglContext _context; |
|||
private readonly EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo _info; |
|||
|
|||
public WglGlPlatformSurface(WglContext context, EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo info) |
|||
{ |
|||
_context = context; |
|||
_info = info; |
|||
} |
|||
|
|||
public IGlPlatformSurfaceRenderTarget CreateGlRenderTarget() |
|||
{ |
|||
return new RenderTarget(_context, _info); |
|||
} |
|||
|
|||
class RenderTarget : IGlPlatformSurfaceRenderTarget |
|||
{ |
|||
private readonly WglContext _context; |
|||
private readonly EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo _info; |
|||
private IntPtr _hdc; |
|||
public RenderTarget(WglContext context, EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo info) |
|||
{ |
|||
_context = context; |
|||
_info = info; |
|||
_hdc = context.CreateConfiguredDeviceContext(info.Handle); |
|||
} |
|||
|
|||
public void Dispose() |
|||
{ |
|||
UnmanagedMethods.ReleaseDC(_hdc, _info.Handle); |
|||
} |
|||
|
|||
public IGlPlatformSurfaceRenderingSession BeginDraw() |
|||
{ |
|||
var oldContext = _context.MakeCurrent(_hdc); |
|||
|
|||
// Reset to default FBO first
|
|||
_context.GlInterface.BindFramebuffer(GL_FRAMEBUFFER, 0); |
|||
|
|||
return new Session(_context, _hdc, _info, oldContext); |
|||
} |
|||
|
|||
class Session : IGlPlatformSurfaceRenderingSession |
|||
{ |
|||
private readonly WglContext _context; |
|||
private readonly IntPtr _hdc; |
|||
private readonly EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo _info; |
|||
private readonly IDisposable _clearContext; |
|||
public IGlContext Context => _context; |
|||
|
|||
public Session(WglContext context, IntPtr hdc, EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo info, |
|||
IDisposable clearContext) |
|||
{ |
|||
_context = context; |
|||
_hdc = hdc; |
|||
_info = info; |
|||
_clearContext = clearContext; |
|||
} |
|||
|
|||
public void Dispose() |
|||
{ |
|||
_context.GlInterface.Flush(); |
|||
UnmanagedMethods.SwapBuffers(_hdc); |
|||
_clearContext.Dispose(); |
|||
} |
|||
|
|||
public PixelSize Size => _info.Size; |
|||
public double Scaling => _info.Scaling; |
|||
public bool IsYFlipped { get; } |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,39 @@ |
|||
using System; |
|||
using System.Linq; |
|||
using Avalonia.Logging; |
|||
using Avalonia.OpenGL; |
|||
|
|||
namespace Avalonia.Win32.OpenGl |
|||
{ |
|||
class WglPlatformOpenGlInterface : IPlatformOpenGlInterface |
|||
{ |
|||
public WglContext PrimaryContext { get; } |
|||
IGlContext IPlatformOpenGlInterface.PrimaryContext => PrimaryContext; |
|||
public IGlContext CreateSharedContext() => WglDisplay.CreateContext(new[] { PrimaryContext.Version }, PrimaryContext); |
|||
|
|||
public bool CanShareContexts => true; |
|||
public bool CanCreateContexts => true; |
|||
public IGlContext CreateContext() => WglDisplay.CreateContext(new[] { PrimaryContext.Version }, null); |
|||
|
|||
private WglPlatformOpenGlInterface(WglContext primary) |
|||
{ |
|||
PrimaryContext = primary; |
|||
} |
|||
|
|||
public static WglPlatformOpenGlInterface TryCreate() |
|||
{ |
|||
try |
|||
{ |
|||
var opts = AvaloniaLocator.Current.GetService<Win32PlatformOptions>() ?? new Win32PlatformOptions(); |
|||
var primary = WglDisplay.CreateContext(opts.WglProfiles.ToArray(), null); |
|||
return new WglPlatformOpenGlInterface(primary); |
|||
} |
|||
catch (Exception e) |
|||
{ |
|||
Logger.TryGet(LogEventLevel.Error, "OpenGL")?.Log("WGL", "Unable to initialize WGL: " + e); |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,39 @@ |
|||
using System; |
|||
using System.Threading; |
|||
using Avalonia.OpenGL; |
|||
using static Avalonia.Win32.Interop.UnmanagedMethods; |
|||
|
|||
namespace Avalonia.Win32.OpenGl |
|||
{ |
|||
internal class WglRestoreContext : IDisposable |
|||
{ |
|||
private readonly object _monitor; |
|||
private readonly IntPtr _oldDc; |
|||
private readonly IntPtr _oldContext; |
|||
|
|||
public WglRestoreContext(IntPtr gc, IntPtr context, object monitor, bool takeMonitor = true) |
|||
{ |
|||
_monitor = monitor; |
|||
_oldDc = wglGetCurrentDC(); |
|||
_oldContext = wglGetCurrentContext(); |
|||
|
|||
if (monitor != null && takeMonitor) |
|||
Monitor.Enter(monitor); |
|||
|
|||
if (!wglMakeCurrent(gc, context)) |
|||
{ |
|||
if(monitor != null && takeMonitor) |
|||
Monitor.Exit(monitor); |
|||
throw new OpenGlException("Unable to make the context current"); |
|||
} |
|||
} |
|||
|
|||
public void Dispose() |
|||
{ |
|||
if (!wglMakeCurrent(_oldDc, _oldContext)) |
|||
wglMakeCurrent(IntPtr.Zero, IntPtr.Zero); |
|||
if (_monitor != null) |
|||
Monitor.Exit(_monitor); |
|||
} |
|||
} |
|||
} |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue