Skip to content

Commit

Permalink
Merge pull request #106 from softwareantics/feature/public-glwpf-sett…
Browse files Browse the repository at this point in the history
…ings

Added support to modify the GLWpfControlSettings within XAML front-end.
  • Loading branch information
NogginBops committed Apr 27, 2023
2 parents 6ea6871 + fb0d8ab commit 516bf69
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 25 deletions.
11 changes: 9 additions & 2 deletions src/Example/MainWindow.xaml
Expand Up @@ -12,7 +12,14 @@
<Grid>
<glWpfControl:GLWpfControl
x:Name="OpenTkControl"
Render="OpenTkControl_OnRender" />
Render="OpenTkControl_OnRender">

<glWpfControl:GLWpfControl.Settings>
<glWpfControl:GLWpfControlSettings MajorVersion="2"
MinorVersion="1"/>
</glWpfControl:GLWpfControl.Settings>

</glWpfControl:GLWpfControl>
<Border
HorizontalAlignment="Right"
VerticalAlignment="Top"
Expand All @@ -32,7 +39,7 @@
Height="128"
HorizontalAlignment="Left"
VerticalAlignment="Bottom"
Margin="10,0,0,60" />
Margin="10,0,0,60"/>
<Button
Content="Redraw Inset Control"
HorizontalAlignment="Left"
Expand Down
15 changes: 11 additions & 4 deletions src/Example/MainWindow.xaml.cs
Expand Up @@ -9,10 +9,17 @@ namespace Example {
public sealed partial class MainWindow {
public MainWindow() {
InitializeComponent();
var mainSettings = new GLWpfControlSettings {MajorVersion = 2, MinorVersion = 1};
OpenTkControl.Start(mainSettings);
var insetSettings = new GLWpfControlSettings {MajorVersion = 2, MinorVersion = 1, RenderContinuously = false};
InsetControl.Start(insetSettings);

// You can start and rely on the Settings property that may be set in XAML or elsewhere in the codebase.
OpenTkControl.Start();

// Or, you can suppy a settings object directly.
InsetControl.Start(new GLWpfControlSettings()
{
MajorVersion = 2,
MinorVersion = 1,
RenderContinuously = false,
});
}

private void OpenTkControl_OnRender(TimeSpan delta) {
Expand Down
6 changes: 3 additions & 3 deletions src/GLWpfControl/DXGLContext.cs
Expand Up @@ -87,9 +87,9 @@ internal sealed class DxGlContext : IDisposable {
if (_sharedContext != null) {
var isSameContext = GLWpfControlSettings.WouldResultInSameContext(settings, _sharedContextSettings);
if (!isSameContext) {
throw new ArgumentException($"The provided {nameof(GLWpfControlSettings)} would result" +
$"in a different context creation to one previously created. To fix this," +
$" either ensure all of your context settings are identical, or provide an " +
throw new ArgumentException($"The provided {nameof(GLWpfControlSettings)} would result " +
$"in a different context creation to one previously created. To fix this, " +
$"either ensure all of your context settings are identical, or provide an " +
$"external context via the '{nameof(GLWpfControlSettings.ContextToUse)}' field.");
}
}
Expand Down
76 changes: 60 additions & 16 deletions src/GLWpfControl/GLWpfControl.cs
Expand Up @@ -41,25 +41,46 @@ public class GLWpfControl : FrameworkElement
// -----------------------------------
// Fields
// -----------------------------------

[CanBeNull] private GLWpfControlSettings _settings;

/// <summary>
/// Represents the dependency property for <see cref="Settings"/>.
/// </summary>
public static readonly DependencyProperty SettingsProperty = DependencyProperty.Register(
"Settings", typeof(GLWpfControlSettings), typeof(GLWpfControl));

[CanBeNull] private GLWpfControlRenderer _renderer;

/// <summary>
/// Indicates whether the <see cref="Start"/> function has been invoked.
/// </summary>
private bool _isStarted;

// -----------------------------------
// Properties
// -----------------------------------

/// <summary>
/// Gets or sets the settings used when initializing the control.
/// </summary>
/// <value>
/// The settings used when initializing the control.
/// </value>
public GLWpfControlSettings Settings
{
get { return (GLWpfControlSettings)GetValue(SettingsProperty); }
set { SetValue(SettingsProperty, value); }
}

/// The OpenGL Framebuffer Object used internally by this component.
/// Bind to this instead of the default framebuffer when using this component along with other FrameBuffers for the final pass.
/// If no framebuffer is available (because this control is not visible, etc etc, then it should be 0).
public int Framebuffer => _renderer?.FrameBufferHandle ?? 0;


/// If this control is rendering continuously.
/// If this is false, then redrawing will only occur when <see cref="UIElement.InvalidateVisual"/> is called.
public bool RenderContinuously {
get => _settings.RenderContinuously;
set => _settings.RenderContinuously = value;
get => Settings.RenderContinuously;
set => Settings.RenderContinuously = value;
}

/// Pixel width of the underlying OpenGL framebuffer.
Expand All @@ -85,14 +106,36 @@ public GLWpfControl() : base()
{
}

/// <summary>
/// Starts the control and rendering, using the settings provided via the <see cref="Settings"/> property.
/// </summary>
public void Start()
{
// Start with default settings if none were provided.
Settings ??= new GLWpfControlSettings();

Start(Settings);
}

/// <summary>
/// Starts the control and rendering, using the settings provided.
/// </summary>
/// <param name="settings">
/// The settings used to construct the underlying graphics context.
/// </param>
/// <exception cref="InvalidOperationException">
/// The <see cref="Start"/> function must only be called once for a given <see cref="GLWpfControl"/>.
/// </exception>
public void Start(GLWpfControlSettings settings)
{
if (_settings != null) {
if (_isStarted) {
throw new InvalidOperationException($"{nameof(Start)} must only be called once for a given {nameof(GLWpfControl)}");
}
_settings = settings.Copy();
_renderer = new GLWpfControlRenderer(_settings);

_isStarted = true;

Settings = settings.Copy();
_renderer = new GLWpfControlRenderer(Settings);
_renderer.GLRender += timeDelta => Render?.Invoke(timeDelta);
_renderer.GLAsyncRender += () => AsyncRender?.Invoke();
IsVisibleChanged += (_, args) => {
Expand All @@ -106,10 +149,10 @@ public void Start(GLWpfControlSettings settings)

// Inheriting directly from a FrameworkElement has issues with receiving certain events -- register for these events directly
if (RegisterToEventsDirectly)
{
EventManager.RegisterClassHandler(typeof(Control), Keyboard.KeyDownEvent, new KeyEventHandler(OnKeyDown), CanInvokeOnHandledEvents);
EventManager.RegisterClassHandler(typeof(Control), Keyboard.KeyUpEvent, new KeyEventHandler(OnKeyUp), CanInvokeOnHandledEvents);
}
{
EventManager.RegisterClassHandler(typeof(Control), Keyboard.KeyDownEvent, new KeyEventHandler(OnKeyDown), CanInvokeOnHandledEvents);
EventManager.RegisterClassHandler(typeof(Control), Keyboard.KeyUpEvent, new KeyEventHandler(OnKeyUp), CanInvokeOnHandledEvents);
}

Loaded += (a, b) => {
InvalidateVisual();
Expand All @@ -119,14 +162,14 @@ public void Start(GLWpfControlSettings settings)
}

private void SetupRenderSize() {
if (_renderer == null || _settings == null) {
if (_renderer == null || Settings == null) {
return;
}

var dpiScaleX = 1.0;
var dpiScaleY = 1.0;

if (_settings.UseDeviceDpi) {
if (Settings.UseDeviceDpi) {
var presentationSource = PresentationSource.FromVisual(this);
// this can be null in the case of not having any visual on screen, such as a tabbed view.
if (presentationSource != null) {
Expand All @@ -137,7 +180,8 @@ public void Start(GLWpfControlSettings settings)
dpiScaleY = transformToDevice.M22;
}
}
var format = _settings.TransparentBackground ? Format.A8R8G8B8 : Format.X8R8G8B8;

var format = Settings.TransparentBackground ? Format.A8R8G8B8 : Format.X8R8G8B8;
_renderer?.SetSize((int) RenderSize.Width, (int) RenderSize.Height, dpiScaleX, dpiScaleY, format);
}

Expand Down Expand Up @@ -167,7 +211,6 @@ internal void OnKeyUp(object sender, KeyEventArgs e)
}
}


private void OnCompTargetRender(object sender, EventArgs e)
{
var currentRenderTime = (e as RenderingEventArgs)?.RenderingTime;
Expand Down Expand Up @@ -211,6 +254,7 @@ protected override void OnRenderSizeChanged(SizeChangedInfo info)
{
InvalidateVisual();
}

base.OnRenderSizeChanged(info);
}
}
Expand Down

0 comments on commit 516bf69

Please sign in to comment.