mirror of
https://github.com/4sval/FModel.git
synced 2026-04-19 08:07:43 -05:00
248 lines
7.3 KiB
C#
248 lines
7.3 KiB
C#
using System;
|
|
using System.ComponentModel;
|
|
using System.Runtime.InteropServices;
|
|
using System.Threading;
|
|
using System.Windows.Forms;
|
|
using CUE4Parse.UE4.Assets.Exports;
|
|
using FModel.Views.Snooper.Buffers;
|
|
using ImGuiNET;
|
|
using OpenTK.Graphics.OpenGL4;
|
|
using OpenTK.Windowing.Common;
|
|
using OpenTK.Windowing.Common.Input;
|
|
using OpenTK.Windowing.Desktop;
|
|
using OpenTK.Windowing.GraphicsLibraryFramework;
|
|
using SixLabors.ImageSharp.Advanced;
|
|
using SixLabors.ImageSharp.PixelFormats;
|
|
using Application = System.Windows.Application;
|
|
using Keys = OpenTK.Windowing.GraphicsLibraryFramework.Keys;
|
|
|
|
namespace FModel.Views.Snooper;
|
|
|
|
public class Snooper : GameWindow
|
|
{
|
|
public readonly FramebufferObject Framebuffer;
|
|
public readonly Renderer Renderer;
|
|
|
|
private readonly SnimGui _gui;
|
|
|
|
private bool _init;
|
|
|
|
public Snooper(GameWindowSettings gwSettings, NativeWindowSettings nwSettings) : base(gwSettings, nwSettings)
|
|
{
|
|
Framebuffer = new FramebufferObject(ClientSize);
|
|
Renderer = new Renderer(ClientSize.X, ClientSize.Y);
|
|
|
|
_gui = new SnimGui(ClientSize.X, ClientSize.Y);
|
|
_init = false;
|
|
}
|
|
|
|
public bool TryLoadExport(CancellationToken cancellationToken, UObject export)
|
|
{
|
|
Renderer.Load(cancellationToken, export);
|
|
return Renderer.Options.Models.Count > 0;
|
|
}
|
|
|
|
public unsafe void WindowShouldClose(bool value, bool clear)
|
|
{
|
|
if (clear)
|
|
{
|
|
Renderer.CameraOp.Speed = 0;
|
|
Renderer.Save();
|
|
}
|
|
|
|
GLFW.SetWindowShouldClose(WindowPtr, value); // start / stop game loop
|
|
IsVisible = !value;
|
|
}
|
|
|
|
public unsafe void WindowShouldFreeze(bool value)
|
|
{
|
|
GLFW.SetWindowShouldClose(WindowPtr, value); // start / stop game loop
|
|
IsVisible = true;
|
|
}
|
|
|
|
public override void Run()
|
|
{
|
|
Renderer.Options.SwapMaterial(false);
|
|
Renderer.Options.AnimateMesh(false);
|
|
Application.Current.Dispatcher.Invoke(delegate
|
|
{
|
|
WindowShouldClose(false, false);
|
|
base.Run();
|
|
});
|
|
}
|
|
|
|
private unsafe void LoadWindowIcon()
|
|
{
|
|
var info = Application.GetResourceStream(new Uri("/FModel;component/Resources/engine.png", UriKind.Relative));
|
|
using var img = SixLabors.ImageSharp.Image.Load<Rgba32>(info.Stream);
|
|
var memoryGroup = img.GetPixelMemoryGroup();
|
|
Memory<byte> array = new byte[memoryGroup.TotalLength * sizeof(Rgba32)];
|
|
var block = MemoryMarshal.Cast<byte, Rgba32>(array.Span);
|
|
foreach (var memory in memoryGroup)
|
|
{
|
|
memory.Span.CopyTo(block);
|
|
block = block[memory.Length..];
|
|
}
|
|
|
|
Icon = new WindowIcon(new OpenTK.Windowing.Common.Input.Image(img.Width, img.Height, array.ToArray()));
|
|
}
|
|
|
|
protected override void OnLoad()
|
|
{
|
|
if (_init)
|
|
{
|
|
Renderer.Options.SetupModelsAndLights();
|
|
return;
|
|
}
|
|
|
|
base.OnLoad();
|
|
CenterWindow();
|
|
LoadWindowIcon();
|
|
|
|
GL.ClearColor(OpenTK.Mathematics.Color4.Black);
|
|
GL.Enable(EnableCap.Blend);
|
|
GL.Enable(EnableCap.CullFace);
|
|
GL.Enable(EnableCap.DepthTest);
|
|
GL.Enable(EnableCap.Multisample);
|
|
GL.StencilOp(StencilOp.Keep, StencilOp.Replace, StencilOp.Replace);
|
|
GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
|
|
|
|
Framebuffer.Setup();
|
|
Renderer.Setup();
|
|
_init = true;
|
|
}
|
|
|
|
protected override void OnRenderFrame(FrameEventArgs args)
|
|
{
|
|
base.OnRenderFrame(args);
|
|
if (!IsVisible)
|
|
return;
|
|
|
|
var delta = (float) args.Time;
|
|
|
|
ClearWhatHasBeenDrawn(); // clear window background
|
|
_gui.Controller.Update(this, delta);
|
|
_gui.Render(this);
|
|
|
|
Framebuffer.Bind(); // switch to viewport background
|
|
ClearWhatHasBeenDrawn(); // clear viewport background
|
|
|
|
Renderer.Render(delta);
|
|
|
|
Framebuffer.BindMsaa();
|
|
Framebuffer.Bind(0); // switch to window background
|
|
|
|
SwapBuffers();
|
|
}
|
|
|
|
private void ClearWhatHasBeenDrawn()
|
|
{
|
|
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit | ClearBufferMask.StencilBufferBit);
|
|
GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill);
|
|
}
|
|
|
|
protected override void OnTextInput(TextInputEventArgs e)
|
|
{
|
|
base.OnTextInput(e);
|
|
if (!IsVisible)
|
|
return;
|
|
|
|
_gui.Controller.PressChar((char) e.Unicode);
|
|
}
|
|
|
|
protected override void OnUpdateFrame(FrameEventArgs e)
|
|
{
|
|
base.OnUpdateFrame(e);
|
|
if (!IsVisible || ImGui.GetIO().WantTextInput)
|
|
return;
|
|
|
|
var delta = (float) e.Time;
|
|
Renderer.CameraOp.Modify(KeyboardState, delta);
|
|
|
|
if (KeyboardState.IsKeyPressed(Keys.Space))
|
|
Renderer.Options.Tracker.IsPaused = !Renderer.Options.Tracker.IsPaused;
|
|
if (KeyboardState.IsKeyPressed(Keys.Delete))
|
|
Renderer.Options.RemoveModel(Renderer.Options.SelectedModel);
|
|
if (KeyboardState.IsKeyPressed(Keys.H))
|
|
WindowShouldClose(true, false);
|
|
if (KeyboardState.IsKeyPressed(Keys.Escape))
|
|
WindowShouldClose(true, true);
|
|
}
|
|
|
|
protected override void OnResize(ResizeEventArgs e)
|
|
{
|
|
base.OnResize(e);
|
|
|
|
GL.Viewport(0, 0, e.Width, e.Height);
|
|
|
|
Framebuffer.WindowResized(e.Width, e.Height);
|
|
Renderer.WindowResized(e.Width, e.Height);
|
|
|
|
_gui.Controller.WindowResized(e.Width, e.Height);
|
|
}
|
|
|
|
protected override void OnClosing(CancelEventArgs e)
|
|
{
|
|
base.OnClosing(e);
|
|
WindowShouldClose(true, true);
|
|
}
|
|
|
|
[DllImport("user32.dll")]
|
|
private static extern bool EnumDisplaySettings(
|
|
string deviceName, int modeNum, ref DEVMODE devMode);
|
|
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
private struct DEVMODE
|
|
{
|
|
private const int CCHDEVICENAME = 0x20;
|
|
private const int CCHFORMNAME = 0x20;
|
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x20)]
|
|
public string dmDeviceName;
|
|
public short dmSpecVersion;
|
|
public short dmDriverVersion;
|
|
public short dmSize;
|
|
public short dmDriverExtra;
|
|
public int dmFields;
|
|
public int dmPositionX;
|
|
public int dmPositionY;
|
|
public ScreenOrientation dmDisplayOrientation;
|
|
public int dmDisplayFixedOutput;
|
|
public short dmColor;
|
|
public short dmDuplex;
|
|
public short dmYResolution;
|
|
public short dmTTOption;
|
|
public short dmCollate;
|
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x20)]
|
|
public string dmFormName;
|
|
public short dmLogPixels;
|
|
public int dmBitsPerPel;
|
|
public int dmPelsWidth;
|
|
public int dmPelsHeight;
|
|
public int dmDisplayFlags;
|
|
public int dmDisplayFrequency;
|
|
public int dmICMMethod;
|
|
public int dmICMIntent;
|
|
public int dmMediaType;
|
|
public int dmDitherType;
|
|
public int dmReserved1;
|
|
public int dmReserved2;
|
|
public int dmPanningWidth;
|
|
public int dmPanningHeight;
|
|
|
|
}
|
|
|
|
public static int GetMaxRefreshFrequency()
|
|
{
|
|
var rf = 60;
|
|
var vDevMode = new DEVMODE();
|
|
var i = 0;
|
|
while (EnumDisplaySettings(null, i, ref vDevMode))
|
|
{
|
|
i++;
|
|
rf = Math.Max(rf, vDevMode.dmDisplayFrequency);
|
|
}
|
|
|
|
return rf;
|
|
}
|
|
}
|