Skip to content

Commit

Permalink
Merge pull request #3 from wannkunstbeikor/master
Browse files Browse the repository at this point in the history
  • Loading branch information
SamboyCoding authored Feb 26, 2024
2 parents 2010270 + 41a222f commit 90efe72
Show file tree
Hide file tree
Showing 9 changed files with 45 additions and 76 deletions.
64 changes: 15 additions & 49 deletions OpenTKAvalonia/BaseTkOpenGlControl.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
using System.Reflection;
using Avalonia;
using Avalonia.Input;
using Avalonia.Input.Raw;
using Avalonia.OpenGL;
using Avalonia.OpenGL.Controls;
using Avalonia.Rendering;
using Avalonia.Threading;
using OpenTK.Graphics.OpenGL;

namespace OpenTKAvalonia;

public abstract class BaseTkOpenGlControl : OpenGlControlBase
public abstract class BaseTkOpenGlControl : OpenGlControlBase, ICustomHitTest
{
/// <summary>
/// KeyboardState provides an easy-to-use, stateful wrapper around Avalonia's Keyboard events, as OpenTK keyboard states are not handled.
Expand All @@ -17,23 +17,6 @@ public abstract class BaseTkOpenGlControl : OpenGlControlBase
public AvaloniaKeyboardState KeyboardState = new();

private AvaloniaTkContext? _avaloniaTkContext;
private FieldInfo _depthBufferField = typeof(OpenGlControlBase).GetField("_depthBuffer", BindingFlags.Instance | BindingFlags.NonPublic) ?? throw new("Unable to find _depthBuffer field");

public BaseTkOpenGlControl()
{
//Hook all Avalonia keyboard events to allow us to store Keyboard State
InputManager.Instance!.PreProcess.Subscribe(e =>
{
if (e is not RawKeyEventArgs keyEvent)
return;

if (keyEvent.Type == RawKeyEventType.KeyDown)
KeyPressed(keyEvent);
else
KeyReleased(keyEvent);
});
}


/// <summary>
/// OpenTkRender is called once a frame to draw to the control.
Expand Down Expand Up @@ -71,27 +54,20 @@ protected sealed override void OnOpenGlRender(GlInterface gl, int fb)
KeyboardState.OnFrame();

//Set up the aspect ratio so shapes aren't stretched.
//As avalonia is using this opengl instance internally to render the entire window, stuff gets messy, so we workaround that here
//to provide a good experience to the user.
var oldViewport = new int[4];
GL.GetInteger(GetPName.Viewport, oldViewport);
GL.Viewport(0, 0, (int) Bounds.Width, (int) Bounds.Height);

//Tell our subclass to render
OpenTkRender();

//Reset viewport after our fix above
GL.Viewport(oldViewport[0], oldViewport[1], oldViewport[2], oldViewport[3]);

//Workaround for avalonia issue #6488, set active texture back to 0
GL.ActiveTexture(TextureUnit.Texture0);
if (Bounds.Width != 0 && Bounds.Height != 0)
{
OpenTkRender();
}

//Schedule next UI update with avalonia
Dispatcher.UIThread.Post(InvalidateVisual, DispatcherPriority.Background);
Dispatcher.UIThread.Post(RequestNextFrameRendering, DispatcherPriority.Background);
}


protected sealed override void OnOpenGlInit(GlInterface gl, int fb)
protected sealed override void OnOpenGlInit(GlInterface gl)
{
//Initialize the OpenTK<->Avalonia Bridge
_avaloniaTkContext = new(gl);
Expand All @@ -102,36 +78,26 @@ protected sealed override void OnOpenGlInit(GlInterface gl, int fb)
}

//Simply call the subclass' teardown function
protected sealed override void OnOpenGlDeinit(GlInterface gl, int fb)
protected sealed override void OnOpenGlDeinit(GlInterface gl)
{
OpenTkTeardown();

//Workaround an avalonia issue where the depth buffer ID is not cleared
//which causes depth problems (see issue #1 on this repo)
_depthBufferField.SetValue(this, 0);
}

/// <summary>
/// Handles avalonia key down events, and sets the keyboard state
/// </summary>
/// <param name="e">The event</param>
private void KeyPressed(RawKeyEventArgs e)
protected override void OnKeyDown(KeyEventArgs e)
{
if (!IsEffectivelyVisible)
return;

KeyboardState.SetKey(e.Key, true);
}

/// <summary>
/// Handles avalonia key up events, and sets the keyboard state
/// </summary>
/// <param name="e">The event</param>
private void KeyReleased(RawKeyEventArgs e)

protected override void OnKeyUp(KeyEventArgs e)
{
if (!IsEffectivelyVisible)
return;

KeyboardState.SetKey(e.Key, false);
}

public bool HitTest(Point point) => Bounds.Contains(point);
}
10 changes: 5 additions & 5 deletions OpenTKAvalonia/OpenTKAvalonia.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Avalonia" Version="0.10.12" />
<PackageReference Include="Avalonia.Desktop" Version="0.10.12" />
<PackageReference Include="OpenTK.Graphics" Version="4.6.7" />
<PackageReference Include="OpenTK.Input" Version="4.6.7" />
<PackageReference Include="OpenTK.Windowing.Common" Version="4.6.7" />
<PackageReference Include="Avalonia" Version="11.0.9" />
<PackageReference Include="Avalonia.Desktop" Version="11.0.9" />
<PackageReference Include="OpenTK.Graphics" Version="4.8.2" />
<PackageReference Include="OpenTK.Input" Version="4.8.2" />
<PackageReference Include="OpenTK.Windowing.Common" Version="4.8.2" />
</ItemGroup>

</Project>
7 changes: 3 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
OpenTKAvalonia is a simple wrapper to provide OpenTK OpenGL bindings for Avalonia, and a control which handles some of
the heavy lifting for you.

This includes setting up the OpenGL bindings, setting up the aspect ratio so anything you draw looks as expected,
working around avalonia bug 6488 (where failing to reset the active texture causes all controls to become invisible),
This includes setting up the OpenGL bindings, setting up the aspect ratio so anything you draw looks as expected,
providing events for Initialization, Teardown, and Render, and providing a KeyboardState API for detecting keyboard input.

The library is somewhat work-in-progress but it currently functions for simple applications, and there is a sample included.
Expand All @@ -15,12 +14,12 @@ switching the default rendering mode, like so:
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.UsePlatformDetect()
.With(new Win32PlatformOptions() {UseWgl = true}) //This line is the important one.
.With(new Win32PlatformOptions { RenderingMode = new Collection<Win32RenderingMode> { Win32RenderingMode.Wgl } }) //This line is the important one.
.LogToTrace();
```
Without this, your control simply will never receive any of the OpenTK events (Initialization, Teardown, and Render).

The library itself is netstandard2.1, because that's what OpenTK requires, and the sample is net6.0.
The library itself is netstandard2.1, because that's what OpenTK requires, and the sample is net7.0.

## Demonstration

Expand Down
2 changes: 1 addition & 1 deletion Samples/BasicCubeSample/App.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="BasicCubeSample.App">
<Application.Styles>
<FluentTheme Mode="Light"/>
<FluentTheme/>
</Application.Styles>
</Application>
11 changes: 6 additions & 5 deletions Samples/BasicCubeSample/BasicCubeSample.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net7</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
Expand All @@ -17,11 +17,12 @@
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Avalonia" Version="0.10.12" />
<PackageReference Include="Avalonia.Desktop" Version="0.10.12" />
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="0.10.12" />
<PackageReference Include="OpenTK" Version="4.6.7" />
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.0.9" />
<PackageReference Include="Avalonia" Version="11.0.9" />
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.9" />
<PackageReference Include="OpenTK" Version="4.8.2" />
<PackageReference Include="OpenTK.Graphics" Version="4.8.2" />
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.4" />
</ItemGroup>
<ItemGroup>
Expand Down
6 changes: 3 additions & 3 deletions Samples/BasicCubeSample/Program.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System;
using System.Collections.ObjectModel;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;

namespace BasicCubeSample
{
Expand All @@ -18,7 +17,8 @@ public static void Main(string[] args) => BuildAvaloniaApp()
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.UsePlatformDetect()
.With(new Win32PlatformOptions() {UseWgl = true})
.With(new Win32PlatformOptions
{ RenderingMode = new Collection<Win32RenderingMode> { Win32RenderingMode.Wgl } })
.LogToTrace();
}
}
2 changes: 1 addition & 1 deletion Samples/ResizableAndHidableSample/App.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="NonFullScreenSample.App">
<Application.Styles>
<FluentTheme Mode="Light"/>
<FluentTheme />
</Application.Styles>
</Application>
6 changes: 3 additions & 3 deletions Samples/ResizableAndHidableSample/Program.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System;
using System.Collections.ObjectModel;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;

namespace NonFullScreenSample
{
Expand All @@ -18,7 +17,8 @@ public static void Main(string[] args) => BuildAvaloniaApp()
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.UsePlatformDetect()
.With(new Win32PlatformOptions() {UseWgl = true})
.With(new Win32PlatformOptions
{ RenderingMode = new Collection<Win32RenderingMode> { Win32RenderingMode.Wgl } })
.LogToTrace();
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net7</TargetFramework>
<Nullable>enable</Nullable>
<RootNamespace>NonFullScreenSample</RootNamespace>
</PropertyGroup>
Expand All @@ -18,11 +18,14 @@
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Avalonia" Version="0.10.12" />
<PackageReference Include="Avalonia.Desktop" Version="0.10.12" />
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="0.10.12" />
<PackageReference Include="OpenTK" Version="4.6.7" />
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.0.9" />
<PackageReference Include="Avalonia" Version="11.0.9" />
<PackageReference Include="Avalonia.Desktop" Version="11.0.9" />
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.9" />
<PackageReference Include="JetBrains.Annotations" Version="2023.3.0" />
<PackageReference Include="OpenTK" Version="4.8.2" />
<PackageReference Include="OpenTK.Graphics" Version="4.8.2" />
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.4" />
</ItemGroup>
<ItemGroup>
Expand Down

0 comments on commit 90efe72

Please sign in to comment.