This commit is contained in:
4sval
2022-11-17 23:53:40 +01:00
parent 38b6371a81
commit ce529c41ec
14 changed files with 96 additions and 83 deletions

View File

@@ -159,6 +159,15 @@
</MenuItem>
</MenuItem>
<MenuItem Header="Views">
<MenuItem Header="3D Viewer" Command="{Binding MenuCommand}" CommandParameter="Views_3dViewer">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">
<Canvas Width="24" Height="24">
<Path Fill="{DynamicResource {x:Static adonisUi:Brushes.AccentForegroundBrush}}" Data="{StaticResource MeshIcon}" />
</Canvas>
</Viewbox>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Audio Player" Command="{Binding MenuCommand}" CommandParameter="Views_AudioPlayer">
<MenuItem.Icon>
<Viewbox Width="16" Height="16">

View File

@@ -635,6 +635,13 @@ namespace FModel.Settings
set => SetProperty(ref _showGrid, value);
}
private bool _previewWorlds = true;
public bool PreviewWorlds
{
get => _previewWorlds;
set => SetProperty(ref _previewWorlds, value);
}
private bool _previewStaticMeshes = true;
public bool PreviewStaticMeshes
{

View File

@@ -94,6 +94,8 @@ public class CUE4ParseViewModel : ViewModel
Convert.ToInt32(SystemParameters.MaximizedPrimaryScreenHeight * .85)),
NumberOfSamples = Constants.SAMPLES_COUNT,
WindowBorder = WindowBorder.Resizable,
Flags = ContextFlags.ForwardCompatible,
Profile = ContextProfile.Core,
StartVisible = false,
StartFocused = false,
Title = "3D Viewer"
@@ -779,7 +781,7 @@ public class CUE4ParseViewModel : ViewModel
SaveAndPlaySound(Path.Combine(TabControl.SelectedTab.Directory, TabControl.SelectedTab.Header.SubstringBeforeLast('.')).Replace('\\', '/'), audioFormat, data);
return false;
}
case UWorld:
case UWorld when UserSettings.Default.PreviewWorlds:
case UStaticMesh when UserSettings.Default.PreviewStaticMeshes:
case USkeletalMesh when UserSettings.Default.PreviewSkeletalMeshes:
case UMaterialInstance when UserSettings.Default.PreviewMaterials && !ModelIsOverwritingMaterial &&
@@ -787,8 +789,8 @@ public class CUE4ParseViewModel : ViewModel
export.Owner.Name.EndsWith($"/RenderSwitch_Materials/{export.Name}", StringComparison.OrdinalIgnoreCase) ||
export.Owner.Name.EndsWith($"/MI_BPTile/{export.Name}", StringComparison.OrdinalIgnoreCase))):
{
SnooperViewer.LoadExport(cancellationToken, export);
SnooperViewer.Run();
if (SnooperViewer.TryLoadExport(cancellationToken, export))
SnooperViewer.Run();
return true;
}
case UMaterialInstance m when ModelIsOverwritingMaterial:

View File

@@ -35,6 +35,9 @@ public class MenuCommand : ViewModelCommand<ApplicationViewModel>
contextViewModel.CUE4Parse.TabControl.SelectedTab.Highlighter = AvalonExtensions.HighlighterSelector("json");
contextViewModel.CUE4Parse.TabControl.SelectedTab.SetDocumentText(JsonConvert.SerializeObject(contextViewModel.CUE4Parse.GameDirectory.DirectoryFiles, Formatting.Indented), false);
break;
case "Views_3dViewer":
contextViewModel.CUE4Parse.SnooperViewer.Run();
break;
case "Views_AudioPlayer":
Helper.OpenWindow<AdonisWindow>("Audio Player", () => new AudioPlayer().Show());
break;
@@ -109,4 +112,4 @@ public class MenuCommand : ViewModelCommand<ApplicationViewModel>
cancellationToken.ThrowIfCancellationRequested();
foreach (var f in parent.Folders) LoopFolders(cancellationToken, f, isExpanded);
}
}
}

View File

@@ -337,22 +337,14 @@ public class GameSelectorViewModel : ViewModel
dic[key] = val;
}
if (dic.Keys.Count <= 0) return null;
AppInfo appInfo = new();
var appId = dic["appid"];
var name = dic["name"];
var installDir = dic["installDir"];
if (!dic.TryGetValue("appid", out var appId) ||
!dic.TryGetValue("name", out var name) ||
!dic.TryGetValue("installDir", out var installDir)) return null;
var path = Path.GetDirectoryName(appMetaFile);
var libGameRoot = Path.Combine(path, "common", installDir);
if (!Directory.Exists(libGameRoot)) return null;
appInfo.Id = appId;
appInfo.Name = name;
appInfo.GameRoot = libGameRoot;
return appInfo;
return !Directory.Exists(libGameRoot) ? null : new AppInfo { Id = appId, Name = name, GameRoot = libGameRoot };
}
private static List<string> GetSteamLibs()

View File

@@ -64,7 +64,7 @@
<Geometry x:Key="FoldIcon">M8.12 19.3c.39.39 1.02.39 1.41 0L12 16.83l2.47 2.47c.39.39 1.02.39 1.41 0 .39-.39.39-1.02 0-1.41l-3.17-3.17c-.39-.39-1.02-.39-1.41 0l-3.17 3.17c-.4.38-.4 1.02-.01 1.41zm7.76-14.6c-.39-.39-1.02-.39-1.41 0L12 7.17 9.53 4.7c-.39-.39-1.02-.39-1.41 0-.39.39-.39 1.03 0 1.42l3.17 3.17c.39.39 1.02.39 1.41 0l3.17-3.17c.4-.39.4-1.03.01-1.42z</Geometry>
<Geometry x:Key="UnfoldIcon">M12 5.83l2.46 2.46c.39.39 1.02.39 1.41 0 .39-.39.39-1.02 0-1.41L12.7 3.7c-.39-.39-1.02-.39-1.41 0L8.12 6.88c-.39.39-.39 1.02 0 1.41.39.39 1.02.39 1.41 0L12 5.83zm0 12.34l-2.46-2.46c-.39-.39-1.02-.39-1.41 0-.39.39-.39 1.02 0 1.41l3.17 3.18c.39.39 1.02.39 1.41 0l3.17-3.17c.39-.39.39-1.02 0-1.41-.39-.39-1.02-.39-1.41 0L12 18.17z</Geometry>
<Geometry x:Key="LocateMeIcon">M11.71,17.99C8.53,17.84,6,15.22,6,12c0-3.31,2.69-6,6-6c3.22,0,5.84,2.53,5.99,5.71l-2.1-0.63C15.48,9.31,13.89,8,12,8 c-2.21,0-4,1.79-4,4c0,1.89,1.31,3.48,3.08,3.89L11.71,17.99z M22,12c0,0.3-0.01,0.6-0.04,0.9l-1.97-0.59C20,12.21,20,12.1,20,12 c0-4.42-3.58-8-8-8s-8,3.58-8,8s3.58,8,8,8c0.1,0,0.21,0,0.31-0.01l0.59,1.97C12.6,21.99,12.3,22,12,22C6.48,22,2,17.52,2,12 C2,6.48,6.48,2,12,2S22,6.48,22,12z M18.23,16.26l2.27-0.76c0.46-0.15,0.45-0.81-0.01-0.95l-7.6-2.28 c-0.38-0.11-0.74,0.24-0.62,0.62l2.28,7.6c0.14,0.47,0.8,0.48,0.95,0.01l0.76-2.27l3.91,3.91c0.2,0.2,0.51,0.2,0.71,0l1.27-1.27 c0.2-0.2,0.2-0.51,0-0.71L18.23,16.26z</Geometry>
<Geometry x:Key="MeshIcon">M12 2c1.1 0 2 .9 2 2s-.9 2-2 2-2-.9-2-2 .9-2 2-2zm8 7h-5v12c0 .55-.45 1-1 1s-1-.45-1-1v-5h-2v5c0 .55-.45 1-1 1s-1-.45-1-1V9H4c-.55 0-1-.45-1-1s.45-1 1-1h16c.55 0 1 .45 1 1s-.45 1-1 1z</Geometry>
<Geometry x:Key="MeshIcon">M1.8 6q-.525 0-.887-.35Q.55 5.3.55 4.8V4q0-1.425 1.012-2.438Q2.575.55 4 .55h.8q.5 0 .85.362.35.363.35.888 0 .5-.35.85T4.8 3H4q-.425 0-.712.287Q3 3.575 3 4v.8q0 .5-.35.85T1.8 6ZM4 23.45q-1.425 0-2.438-1.012Q.55 21.425.55 20v-.8q0-.5.363-.85.362-.35.887-.35.5 0 .85.35t.35.85v.8q0 .425.288.712Q3.575 21 4 21h.8q.5 0 .85.35t.35.85q0 .525-.35.887-.35.363-.85.363Zm15.2 0q-.5 0-.85-.363-.35-.362-.35-.887 0-.5.35-.85t.85-.35h.8q.425 0 .712-.288Q21 20.425 21 20v-.8q0-.5.35-.85t.85-.35q.525 0 .888.35.362.35.362.85v.8q0 1.425-1.012 2.438Q21.425 23.45 20 23.45ZM22.2 6q-.5 0-.85-.35T21 4.8V4q0-.425-.288-.713Q20.425 3 20 3h-.8q-.5 0-.85-.35T18 1.8q0-.525.35-.888.35-.362.85-.362h.8q1.425 0 2.438 1.012Q23.45 2.575 23.45 4v.8q0 .5-.362.85-.363.35-.888.35ZM12 17.35l1-.575v-4.1l3.55-2.075V9.425l-1-.575L12 10.925 8.45 8.85l-1 .575V10.6L11 12.675v4.1Zm-1.325 2.325-4.55-2.65q-.625-.35-.975-.963-.35-.612-.35-1.337V9.45q0-.725.35-1.337.35-.613.975-.963l4.55-2.65Q11.3 4.15 12 4.15t1.325.35l4.55 2.65q.625.35.975.963.35.612.35 1.337v5.275q0 .725-.35 1.337-.35.613-.975.963l-4.55 2.65q-.625.35-1.325.35t-1.325-.35Z</Geometry>
<Geometry x:Key="MaterialIcon">M11 9h2v2h-2V9zm-2 2h2v2H9v-2zm4 0h2v2h-2v-2zm2-2h2v2h-2V9zM7 9h2v2H7V9zm12-6H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 18H7v-2h2v2zm4 0h-2v-2h2v2zm4 0h-2v-2h2v2zm2-7h-2v2h2v2h-2v-2h-2v2h-2v-2h-2v2H9v-2H7v2H5v-2h2v-2H5V6c0-.55.45-1 1-1h12c.55 0 1 .45 1 1v5z</Geometry>
<Geometry x:Key="VisibleIcon">M12 4C7 4 2.73 7.11 1 11.5 2.73 15.89 7 19 12 19s9.27-3.11 11-7.5C21.27 7.11 17 4 12 4zm0 12.5c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z</Geometry>
<Geometry x:Key="NotVisibleIcon">M12 6.5c2.76 0 5 2.24 5 5 0 .51-.1 1-.24 1.46l3.06 3.06c1.39-1.23 2.49-2.77 3.18-4.53C21.27 7.11 17 4 12 4c-1.27 0-2.49.2-3.64.57l2.17 2.17c.47-.14.96-.24 1.47-.24zM2.71 3.16c-.39.39-.39 1.02 0 1.41l1.97 1.97C3.06 7.83 1.77 9.53 1 11.5 2.73 15.89 7 19 12 19c1.52 0 2.97-.3 4.31-.82l2.72 2.72c.39.39 1.02.39 1.41 0 .39-.39.39-1.02 0-1.41L4.13 3.16c-.39-.39-1.03-.39-1.42 0zM12 16.5c-2.76 0-5-2.24-5-5 0-.77.18-1.5.49-2.14l1.57 1.57c-.03.18-.06.37-.06.57 0 1.66 1.34 3 3 3 .2 0 .38-.03.57-.07L14.14 16c-.65.32-1.37.5-2.14.5zm2.97-5.33c-.15-1.4-1.25-2.49-2.64-2.64l2.64 2.64z</Geometry>

View File

@@ -307,6 +307,7 @@
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
@@ -371,25 +372,30 @@
IsChecked="{Binding SaveMaterials, Source={x:Static local:Settings.UserSettings.Default}, Mode=TwoWay}"/>
</UniformGrid>
<TextBlock Grid.Row="6" Grid.Column="0" Text="Auto-Export Morph Targets" VerticalAlignment="Center" Margin="0 0 0 5" />
<TextBlock Grid.Row="6" Grid.Column="0" Text="Preview Static Meshes From Worlds (.umap)" VerticalAlignment="Center" Margin="0 0 0 5" />
<CheckBox Grid.Row="6" Grid.Column="2" Grid.ColumnSpan="3" Content="{Binding IsChecked, RelativeSource={RelativeSource Self}, Converter={x:Static converters:BoolToToggleConverter.Instance}}"
IsChecked="{Binding PreviewWorlds, Source={x:Static local:Settings.UserSettings.Default}, Mode=TwoWay}"
Style="{DynamicResource {x:Static adonisUi:Styles.ToggleSwitch}}" Margin="0 5 0 5"/>
<TextBlock Grid.Row="7" Grid.Column="0" Text="Auto-Export Morph Targets" VerticalAlignment="Center" Margin="0 0 0 5" />
<CheckBox Grid.Row="7" Grid.Column="2" Grid.ColumnSpan="3" Content="{Binding IsChecked, RelativeSource={RelativeSource Self}, Converter={x:Static converters:BoolToToggleConverter.Instance}}"
IsChecked="{Binding SaveMorphTargets, Source={x:Static local:Settings.UserSettings.Default}, Mode=TwoWay}"
Style="{DynamicResource {x:Static adonisUi:Styles.ToggleSwitch}}" Margin="0 5 0 5"/>
<TextBlock Grid.Row="7" Grid.Column="0" Text="Auto-Export Animations" VerticalAlignment="Center" Margin="0 0 0 5" />
<CheckBox Grid.Row="7" Grid.Column="2" Grid.ColumnSpan="3" Content="{Binding IsChecked, RelativeSource={RelativeSource Self}, Converter={x:Static converters:BoolToToggleConverter.Instance}}"
<TextBlock Grid.Row="8" Grid.Column="0" Text="Auto-Export Animations" VerticalAlignment="Center" Margin="0 0 0 5" />
<CheckBox Grid.Row="8" Grid.Column="2" Grid.ColumnSpan="3" Content="{Binding IsChecked, RelativeSource={RelativeSource Self}, Converter={x:Static converters:BoolToToggleConverter.Instance}}"
IsChecked="{Binding SaveAnimations, Source={x:Static local:Settings.UserSettings.Default}, Mode=TwoWay}"
Style="{DynamicResource {x:Static adonisUi:Styles.ToggleSwitch}}" Margin="0 5 0 5"/>
<TextBlock Grid.Row="8" Grid.Column="0" Text="Export Skeletons as Empty Meshes" VerticalAlignment="Center" />
<CheckBox Grid.Row="8" Grid.Column="2" Grid.ColumnSpan="3" Content="{Binding IsChecked, RelativeSource={RelativeSource Self}, Converter={x:Static converters:BoolToToggleConverter.Instance}}"
<TextBlock Grid.Row="9" Grid.Column="0" Text="Export Skeletons as Empty Meshes" VerticalAlignment="Center" />
<CheckBox Grid.Row="9" Grid.Column="2" Grid.ColumnSpan="3" Content="{Binding IsChecked, RelativeSource={RelativeSource Self}, Converter={x:Static converters:BoolToToggleConverter.Instance}}"
IsChecked="{Binding SaveSkeletonAsMesh, Source={x:Static local:Settings.UserSettings.Default}, Mode=TwoWay}"
Style="{DynamicResource {x:Static adonisUi:Styles.ToggleSwitch}}" Margin="0 5 0 0"/>
<Separator Grid.Row="9" Grid.Column="0" Grid.ColumnSpan="5" Style="{StaticResource CustomSeparator}" />
<Separator Grid.Row="10" Grid.Column="0" Grid.ColumnSpan="5" Style="{StaticResource CustomSeparator}" />
<TextBlock Grid.Row="10" Grid.Column="0" Text="Texture Format" VerticalAlignment="Center" Margin="0 0 0 5" />
<ComboBox Grid.Row="10" Grid.Column="2" Grid.ColumnSpan="3" ItemsSource="{Binding SettingsView.TextureExportFormats}" SelectedItem="{Binding SettingsView.SelectedTextureExportFormat, Mode=TwoWay}"
<TextBlock Grid.Row="11" Grid.Column="0" Text="Texture Format" VerticalAlignment="Center" Margin="0 0 0 5" />
<ComboBox Grid.Row="11" Grid.Column="2" Grid.ColumnSpan="3" ItemsSource="{Binding SettingsView.TextureExportFormats}" SelectedItem="{Binding SettingsView.SelectedTextureExportFormat, Mode=TwoWay}"
DataContext="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:Views.SettingsView}}}" Margin="0 0 0 5">
<ComboBox.ItemTemplate>
<DataTemplate>

View File

@@ -18,6 +18,14 @@ public class Camera
public float Far = 100f;
public float AspectRatio = 16f / 9f;
public Camera()
{
Position = new Vector3(0, 1, 1);
Direction = Vector3.Zero;
InitDirection();
}
public Camera(Vector3 position, Vector3 direction, float near, float far, float speed)
{
Position = position;
@@ -26,6 +34,11 @@ public class Camera
Far = far;
Speed = speed;
InitDirection();
}
private void InitDirection()
{
// trigonometric math to calculate the cam's yaw/pitch based on position and direction to look
var yaw = MathF.Atan((-Position.X - Direction.X) / (Position.Z - Direction.Z));
var pitch = MathF.Atan((Position.Y - Direction.Y) / (Position.Z - Direction.Z));

View File

@@ -115,11 +115,11 @@ public class FramebufferObject : IDisposable
public void Dispose()
{
_vao.Dispose();
_shader.Dispose();
_framebufferTexture.Dispose();
_postProcessingTexture.Dispose();
_renderbuffer.Dispose();
_vao?.Dispose();
_shader?.Dispose();
_framebufferTexture?.Dispose();
_postProcessingTexture?.Dispose();
_renderbuffer?.Dispose();
GL.DeleteFramebuffer(_framebufferHandle);
GL.DeleteFramebuffer(_postProcessingHandle);
}

View File

@@ -57,10 +57,10 @@ public class Grid : IDisposable
public void Dispose()
{
_ebo.Dispose();
_vbo.Dispose();
_vao.Dispose();
_shader.Dispose();
_ebo?.Dispose();
_vbo?.Dispose();
_vao?.Dispose();
_shader?.Dispose();
GL.DeleteProgram(_handle);
}
}

View File

@@ -296,16 +296,19 @@ public class Renderer : IDisposable
LoadWorld(cancellationToken, w, transform);
}
public void Dispose()
public void Save()
{
UserSettings.Default.ShowSkybox = ShowSkybox;
UserSettings.Default.ShowGrid = ShowGrid;
}
public void Dispose()
{
_skybox?.Dispose();
_grid?.Dispose();
_shader.Dispose();
_outline.Dispose();
Picking.Dispose();
Cache.Dispose();
_shader?.Dispose();
_outline?.Dispose();
Picking?.Dispose();
Cache?.Dispose();
}
}

View File

@@ -103,10 +103,10 @@ public class Skybox : IDisposable
public void Dispose()
{
_ebo.Dispose();
_vbo.Dispose();
_vao.Dispose();
_shader.Dispose();
_ebo?.Dispose();
_vbo?.Dispose();
_vao?.Dispose();
_shader?.Dispose();
GL.DeleteProgram(_handle);
}
}

View File

@@ -108,7 +108,7 @@ public class SnimGui
if (ImGui.BeginMenu("Window"))
{
ImGui.MenuItem("Append", "R");
ImGui.MenuItem("Hide", "H");
ImGui.MenuItem("Close", "ESC");
ImGui.EndMenu();
}
@@ -449,7 +449,7 @@ public class SnimGui
ImGui.DragInt("", ref material.SelectedChannel, 1, 0, model.NumTexCoords - 1, "UV %i", ImGuiSliderFlags.AlwaysClamp);
ImGui.EndDisabled();ImGui.PopID();Layout("Type");ImGui.PushID(2);
ImGui.Combo("texture_type", ref material.SelectedTexture,
"Diffuse\0Normals\0Specular\0Mask\0Emissive\0");
"Diffuse\0Normals\0Specular\0Ambient Occlusion\0Emissive\0");
ImGui.PopID();
ImGui.EndTable();
}
@@ -606,29 +606,6 @@ public class SnimGui
if (ImGui.IsItemClicked()) ImGui.SetClipboardText(name);
}
private void DrawSquareTexture(Texture texture, Vector2 size)
{
ImGui.Image(texture?.GetPointer() ?? IntPtr.Zero, size, Vector2.Zero, Vector2.One, Vector4.One, new Vector4(1, 1, 1, .5f));
if (texture == null) return;
if (ImGui.IsItemHovered())
{
ImGui.BeginTooltip();
ImGui.Text($"Type: ({texture.Format}) {texture.Type}:{texture.Name}");
ImGui.Text($"Texture: {texture.Path}");
ImGui.Text($"Imported: {texture.ImportedWidth}x{texture.ImportedHeight}");
ImGui.Text($"Mip Used: {texture.Width}x{texture.Height}");
ImGui.Spacing();
ImGui.TextDisabled(texture.Label);
ImGui.EndTooltip();
}
if (ImGui.IsItemClicked())
{
ImGui.SetClipboardText(Creator.Utils.FixPath(texture.Path));
texture.Label = "(?) Path Copied to Clipboard";
}
}
private void Theme()
{
var style = ImGui.GetStyle();

View File

@@ -1,3 +1,4 @@
using System.ComponentModel;
using System.Threading;
using System.Windows;
using CUE4Parse.UE4.Assets.Exports;
@@ -24,6 +25,7 @@ public class Snooper : GameWindow
public Snooper(GameWindowSettings gwSettings, NativeWindowSettings nwSettings) : base(gwSettings, nwSettings)
{
Camera = new Camera();
Framebuffer = new FramebufferObject(ClientSize);
Renderer = new Renderer(ClientSize.X, ClientSize.Y);
@@ -31,23 +33,26 @@ public class Snooper : GameWindow
_init = false;
}
public void LoadExport(CancellationToken cancellationToken, UObject export)
public bool TryLoadExport(CancellationToken cancellationToken, UObject export)
{
var newCamera = Renderer.Load(cancellationToken, export);
if (newCamera == null || !(newCamera.Speed > _previousSpeed)) return;
Camera = newCamera;
_previousSpeed = Camera.Speed;
var newCamera = Renderer.Load(cancellationToken, export) ?? new Camera();
if (newCamera.Speed > _previousSpeed)
{
Camera = newCamera;
_previousSpeed = Camera.Speed;
}
return Renderer.Cache.Models.Count > 0;
}
public unsafe void WindowShouldClose(bool value, bool clear)
{
if (clear)
{
_previousSpeed = 0f;
Renderer.Cache.DisposeModels();
Renderer.Cache.Models.Clear();
Renderer.Settings.Reset();
_previousSpeed = 0f;
Renderer.Save();
}
GLFW.SetWindowShouldClose(WindowPtr, value); // start / stop game loop
@@ -147,7 +152,7 @@ public class Snooper : GameWindow
if (KeyboardState.IsKeyDown(Keys.C))
Camera.ModifyZoom(+.5f);
if (KeyboardState.IsKeyPressed(Keys.R))
if (KeyboardState.IsKeyPressed(Keys.H))
WindowShouldClose(true, false);
if (KeyboardState.IsKeyPressed(Keys.Escape))
WindowShouldClose(true, true);
@@ -166,13 +171,9 @@ public class Snooper : GameWindow
_gui.Controller.WindowResized(e.Width, e.Height);
}
protected override void Dispose(bool disposing)
protected override void OnClosing(CancelEventArgs e)
{
base.Dispose(disposing);
Framebuffer?.Dispose();
Renderer?.Dispose();
_gui?.Controller.Dispose();
base.OnClosing(e);
WindowShouldClose(true, true);
}
}