This commit is contained in:
4sval
2022-10-14 23:13:28 +02:00
parent e3e5689fce
commit c8f0d9f014
6 changed files with 78 additions and 652 deletions

View File

@@ -141,6 +141,7 @@
<PackageReference Include="RestSharp" Version="108.0.1" />
<PackageReference Include="Serilog" Version="2.11.0" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="SixLabors.ImageSharp" Version="2.1.3" />
<PackageReference Include="SkiaSharp.HarfBuzz" Version="2.88.0" />
<PackageReference Include="SkiaSharp.Svg" Version="1.60.0" />
</ItemGroup>

View File

@@ -757,7 +757,10 @@ 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.Run(cancellationToken, export);
Application.Current.Dispatcher.Invoke(delegate
{
SnooperViewer.Run(cancellationToken, export);
});
return true;
}
case UMaterialInstance m when ModelIsOverwritingMaterial:

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Threading;
using CUE4Parse.UE4.Assets.Exports;
using CUE4Parse.UE4.Assets.Exports.Material;
@@ -13,7 +14,6 @@ using CUE4Parse.UE4.Objects.Engine;
using CUE4Parse.UE4.Objects.UObject;
using CUE4Parse_Conversion.Meshes;
using OpenTK.Graphics.OpenGL4;
using OpenTK.Mathematics;
using OpenTK.Windowing.Common;
using OpenTK.Windowing.Desktop;
using OpenTK.Windowing.GraphicsLibraryFramework;
@@ -22,13 +22,11 @@ namespace FModel.Views.Snooper;
public class FWindow : GameWindow
{
private SnimGui _imGui;
private Camera _camera;
private IMouse _mouse;
private Image _icon;
private Options _options;
private readonly FramebufferObject _framebuffer;
// private readonly FramebufferObject _framebuffer;
private readonly Skybox _skybox;
private readonly Grid _grid;
@@ -43,7 +41,7 @@ public class FWindow : GameWindow
public FWindow(GameWindowSettings gameWindowSettings, NativeWindowSettings nativeWindowSettings) : base(gameWindowSettings, nativeWindowSettings)
{
_options = new Options();
_framebuffer = new FramebufferObject(Size);
// _framebuffer = new FramebufferObject(Size);
_skybox = new Skybox();
_grid = new Grid();
_models = new Dictionary<FGuid, Model>();
@@ -161,7 +159,7 @@ public class FWindow : GameWindow
throw new ArgumentOutOfRangeException(nameof(export));
}
DoLoop();
Run();
}
public void SwapMaterial(UMaterialInstance mi)
@@ -171,13 +169,12 @@ public class FWindow : GameWindow
section.SwapMaterial(mi);
_options.SwapMaterial(false);
DoLoop();
Run();
}
private void DoLoop()
{
if (_options.Append) _options.Append = false;
_window.Run();
// if (_window.IsInitialized)
// {
// if (!_window.GLContext.IsCurrent)
@@ -223,24 +220,15 @@ public class FWindow : GameWindow
protected override void OnLoad()
{
base.OnLoad();
CenterWindow();
_window.SetWindowIcon(ref _icon);
_window.Center();
GL.Enable(EnableCap.Blend);
GL.Enable(EnableCap.DepthTest);
GL.Enable(EnableCap.Multisample);
GL.StencilOp(StencilOp.Keep, StencilOp.Replace, StencilOp.Replace);
GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
var input = _window.CreateInput();
_keyboard = input.Keyboards[0];
_mouse = input.Mice[0];
_gl = GL.GetApi(_window);
_gl.Enable(EnableCap.Blend);
_gl.Enable(EnableCap.DepthTest);
_gl.Enable(EnableCap.Multisample);
_gl.StencilOp(StencilOp.Keep, StencilOp.Replace, StencilOp.Replace);
_gl.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
_imGui = new SnimGui(_gl, _window, input);
_framebuffer.Setup();
// _framebuffer.Setup();
_skybox.Setup();
_grid.Setup();
@@ -258,12 +246,10 @@ public class FWindow : GameWindow
{
base.OnRenderFrame(args);
_imGui.Update((float) args.Time);
ClearWhatHasBeenDrawn(); // in main window
_framebuffer.Bind(); // switch to dedicated window
ClearWhatHasBeenDrawn(); // in dedicated window
// _framebuffer.Bind(); // switch to dedicated window
// ClearWhatHasBeenDrawn(); // in dedicated window
_skybox.Bind(_camera);
_grid.Bind(_camera);
@@ -300,20 +286,16 @@ public class FWindow : GameWindow
model.Outline(_outline);
}
_imGui.Construct(ref _options, _size, _framebuffer, _camera, _mouse, _models);
_framebuffer.BindMsaa();
_framebuffer.Bind(0); // switch back to main window
_framebuffer.BindStuff();
_imGui.Render(); // render ImGui in main window
// _framebuffer.BindMsaa();
// _framebuffer.Bind(0); // switch back to main window
// _framebuffer.BindStuff();
SwapBuffers();
}
private void ClearWhatHasBeenDrawn()
{
GL.ClearColor(1.0f, 0.102f, 0.129f, 1.0f);
GL.ClearColor(1.0f, 0f, 0f, 1.0f);
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit | ClearBufferMask.StencilBufferBit);
GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill);
}
@@ -321,28 +303,32 @@ public class FWindow : GameWindow
protected override void OnUpdateFrame(FrameEventArgs e)
{
base.OnUpdateFrame(e);
if (!IsFocused || ImGui.GetIO().WantTextInput)
if (!IsFocused)
return;
var multiplier = KeyboardState.IsKeyPressed(Keys.LeftShift) ? 2f : 1f;
var multiplier = KeyboardState.IsKeyDown(Keys.LeftShift) ? 2f : 1f;
var moveSpeed = _camera.Speed * multiplier * (float) e.Time;
if (KeyboardState.IsKeyPressed(Keys.W))
if (KeyboardState.IsKeyDown(Keys.W))
_camera.Position += moveSpeed * _camera.Direction;
if (KeyboardState.IsKeyPressed(Keys.S))
if (KeyboardState.IsKeyDown(Keys.S))
_camera.Position -= moveSpeed * _camera.Direction;
if (KeyboardState.IsKeyPressed(Keys.A))
if (KeyboardState.IsKeyDown(Keys.A))
_camera.Position -= Vector3.Normalize(Vector3.Cross(_camera.Direction, _camera.Up)) * moveSpeed;
if (KeyboardState.IsKeyPressed(Keys.D))
if (KeyboardState.IsKeyDown(Keys.D))
_camera.Position += Vector3.Normalize(Vector3.Cross(_camera.Direction, _camera.Up)) * moveSpeed;
if (KeyboardState.IsKeyPressed(Keys.E))
if (KeyboardState.IsKeyDown(Keys.E))
_camera.Position += moveSpeed * _camera.Up;
if (KeyboardState.IsKeyPressed(Keys.Q))
if (KeyboardState.IsKeyDown(Keys.Q))
_camera.Position -= moveSpeed * _camera.Up;
if (KeyboardState.IsKeyPressed(Keys.X))
if (KeyboardState.IsKeyDown(Keys.X))
_camera.ModifyZoom(-.5f);
if (KeyboardState.IsKeyPressed(Keys.C))
if (KeyboardState.IsKeyDown(Keys.C))
_camera.ModifyZoom(+.5f);
const float lookSensitivity = 0.1f;
var delta = MouseState.Delta * lookSensitivity;
_camera.ModifyDirection(delta.X, delta.Y);
if (KeyboardState.IsKeyPressed(Keys.H))
IsVisible = false;
if (KeyboardState.IsKeyPressed(Keys.Escape))
@@ -351,7 +337,7 @@ public class FWindow : GameWindow
private void OnClose()
{
_framebuffer.Dispose();
// _framebuffer.Dispose();
_grid.Dispose();
_skybox.Dispose();
_shader.Dispose();
@@ -366,9 +352,6 @@ public class FWindow : GameWindow
_options.Reset();
_previousSpeed = 0f;
}
_imGui.Dispose();
_window.Dispose();
_gl.Dispose();
}
protected override void OnResize(ResizeEventArgs e)
@@ -376,6 +359,6 @@ public class FWindow : GameWindow
base.OnResize(e);
GL.Viewport(0, 0, Size.X, Size.Y);
_camera.AspectRatio = Size.X / (float)Size.Y;
// _camera.AspectRatio = Size.X / (float)Size.Y;
}
}

View File

@@ -1,559 +0,0 @@
using System;
using System.Collections.Generic;
using System.Numerics;
using System.Windows;
using CUE4Parse.UE4.Objects.Core.Misc;
using FModel.Creator;
using ImGuiNET;
using Silk.NET.Input;
using Silk.NET.Maths;
using Silk.NET.OpenGL;
using Silk.NET.OpenGL.Extensions.ImGui;
using Silk.NET.Windowing;
namespace FModel.Views.Snooper;
public class SnimGui : IDisposable
{
private readonly ImGuiController _controller;
private readonly GraphicsAPI _api;
private readonly string _renderer;
private readonly Vector4 _xAxis = new (1.0f, 0.102f, 0.129f, 1.0f);
private readonly Vector4 _yAxis = new (0.102f, 0.102f, 1.0f, 1.0f);
private readonly Vector4 _zAxis = new (0.102f, 0.102f, 0.129f, 1.0f);
private readonly Vector2 _outlinerSize;
private readonly Vector2 _outlinerPosition;
private readonly Vector2 _propertiesSize;
private readonly Vector2 _propertiesPosition;
private readonly Vector2 _viewportSize;
private readonly Vector2 _viewportPosition;
private readonly Vector2 _textureSize;
private readonly Vector2 _texturePosition;
private bool _viewportFocus;
private const ImGuiWindowFlags _noResize = ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoMove; // delete once we have a proper docking branch
private const ImGuiCond _firstUse = ImGuiCond.Appearing; // switch to FirstUseEver once the docking branch will not be useful anymore...
private const uint _dockspaceId = 1337;
public SnimGui(GL gl, IWindow window, IInputContext input)
{
var fontConfig = new ImGuiFontConfig("C:\\Windows\\Fonts\\segoeui.ttf", 16);
_controller = new ImGuiController(gl, window, input, fontConfig);
_api = window.API;
_renderer = gl.GetStringS(StringName.Renderer);
var style = ImGui.GetStyle();
var viewport = ImGui.GetMainViewport();
var titleBarHeight = ImGui.GetFontSize() + style.FramePadding.Y * 2;
_outlinerSize = new Vector2(400, 300);
_outlinerPosition = new Vector2(viewport.WorkSize.X - _outlinerSize.X, titleBarHeight);
_propertiesSize = _outlinerSize with { Y = viewport.WorkSize.Y - _outlinerSize.Y - titleBarHeight };
_propertiesPosition = new Vector2(viewport.WorkSize.X - _propertiesSize.X, _outlinerPosition.Y + _outlinerSize.Y);
_viewportSize = _outlinerPosition with { Y = viewport.WorkSize.Y - titleBarHeight - 150 };
_viewportPosition = new Vector2(0, titleBarHeight);
_textureSize = _viewportSize with { Y = viewport.WorkSize.Y - _viewportSize.Y - titleBarHeight };
_texturePosition = new Vector2(0, _viewportPosition.Y + _viewportSize.Y);
Theme(style);
}
public void Construct(ref Options options, Vector2D<int> size, FramebufferObject framebuffer, Camera camera, IMouse mouse, IDictionary<FGuid, Model> models)
{
DrawDockSpace(size);
DrawNavbar();
DrawOuliner(ref options, camera, models);
DrawProperties(ref options, camera, models);
DrawTextures(ref options, models);
Draw3DViewport(framebuffer, camera, mouse);
}
/// <summary>
/// absolutely useless at the moment since ImGui.NET lacks DockerBuilder bindinds
/// </summary>
private void DrawDockSpace(Vector2D<int> size)
{
const ImGuiWindowFlags flags =
ImGuiWindowFlags.MenuBar | ImGuiWindowFlags.NoDocking |
ImGuiWindowFlags.NoTitleBar | ImGuiWindowFlags.NoResize |
ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.NoMove |
ImGuiWindowFlags.NoBringToFrontOnFocus | ImGuiWindowFlags.NoNavFocus;
ImGui.SetNextWindowPos(new Vector2(0, 0));
ImGui.SetNextWindowSize(new Vector2(size.X, size.Y));
ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, Vector2.Zero);
ImGui.Begin("Snooper", flags);
ImGui.PopStyleVar();
ImGui.DockSpace(_dockspaceId);
}
private void DrawNavbar()
{
if (!ImGui.BeginMainMenuBar()) return;
if (ImGui.BeginMenu("Window"))
{
ImGui.MenuItem("Append", "H");
ImGui.MenuItem("Close", "ESC");
ImGui.EndMenu();
}
if (ImGui.BeginMenu("Edit"))
{
if (ImGui.MenuItem("Undo", "CTRL+Z")) {}
if (ImGui.MenuItem("Redo", "CTRL+Y", false, false)) {} // Disabled item
ImGui.Separator();
if (ImGui.MenuItem("Cut", "CTRL+X")) {}
if (ImGui.MenuItem("Copy", "CTRL+C")) {}
if (ImGui.MenuItem("Paste", "CTRL+V")) {}
ImGui.EndMenu();
}
const string text = "Press ESC to Exit...";
ImGui.SetCursorPosX(ImGui.GetWindowViewport().WorkSize.X - ImGui.CalcTextSize(text).X - 5);
ImGui.TextColored(new Vector4(0.36f, 0.42f, 0.47f, 1.00f), text); // ImGuiCol.TextDisabled
ImGui.EndMainMenuBar();
}
private void DrawOuliner(ref Options options, Camera camera, IDictionary<FGuid, Model> models)
{
ImGui.SetNextWindowSize(_outlinerSize, _firstUse);
ImGui.SetNextWindowPos(_outlinerPosition, _firstUse);
ImGui.Begin("Scene Hierarchy", _noResize | ImGuiWindowFlags.NoCollapse);
ImGui.Text("hello world!");
ImGui.Spacing();
ImGui.SetNextItemOpen(true, ImGuiCond.Appearing);
if (ImGui.CollapsingHeader("Collection"))
{
if (ImGui.BeginListBox("", new Vector2(ImGui.GetContentRegionAvail().X, _outlinerSize.Y / 2)))
{
var i = 0;
foreach (var (guid, model) in models)
{
ImGui.PushID(i);
model.IsSelected = options.SelectedModel == guid;
if (ImGui.Selectable(model.Name, model.IsSelected))
{
options.SelectModel(guid);
}
if (ImGui.BeginPopupContextItem())
{
options.SelectModel(guid);
if (ImGui.Selectable("Deselect"))
options.SelectModel(Guid.Empty);
if (ImGui.Selectable("Delete"))
models.Remove(guid);
if (ImGui.Selectable("Copy Name to Clipboard"))
Application.Current.Dispatcher.Invoke(delegate
{
Clipboard.SetText(model.Name);
});
ImGui.EndPopup();
}
ImGui.PopID();
i++;
}
ImGui.EndListBox();
}
}
if (ImGui.CollapsingHeader("Camera"))
{
PushStyleCompact();
string[] modes = { "free cam", "orbital cam" };
int selectedMode = 0;
ImGui.Combo("Projection", ref selectedMode, modes, modes.Length);
ImGui.DragFloat3("Position", ref camera.Position);
ImGui.DragFloat3("Direction", ref camera.Direction);
ImGui.DragFloat("Speed", ref camera.Speed, 0.01f);
ImGui.DragFloat("Zoom", ref camera.Zoom);
PopStyleCompact();
}
ImGui.End();
}
private void DrawProperties(ref Options options, Camera camera, IDictionary<FGuid, Model> models)
{
ImGui.SetNextWindowSize(_propertiesSize, _firstUse);
ImGui.SetNextWindowPos(_propertiesPosition, _firstUse);
ImGui.Begin("Properties", _noResize | ImGuiWindowFlags.NoCollapse);
if (!models.TryGetValue(options.SelectedModel, out var model))
return;
ImGui.Text($"Entity: ({model.Type}) {model.Name}");
ImGui.Text($"Guid: {options.SelectedModel.ToString(EGuidFormats.UniqueObjectGuid)}");
PushStyleCompact();
ImGui.Columns(4, "Actions", false);
if (ImGui.Button("Go To")) camera.Position = model.Transforms[options.SelectedModelInstance].Position;
ImGui.NextColumn(); ImGui.Checkbox("Show", ref model.Show);
ImGui.NextColumn(); ImGui.BeginDisabled(!model.HasVertexColors); ImGui.Checkbox("Colors", ref model.DisplayVertexColors); ImGui.EndDisabled();
ImGui.NextColumn(); ImGui.BeginDisabled(!model.HasBones); ImGui.Checkbox("Bones", ref model.DisplayBones); ImGui.EndDisabled();
ImGui.Columns(1);
PopStyleCompact();
ImGui.Separator();
ImGui.SetNextItemOpen(true, ImGuiCond.Appearing);
if (ImGui.BeginTabBar("properties_tab_bar", ImGuiTabBarFlags.None))
{
if (ImGui.BeginTabItem("Transform"))
{
const int width = 100;
var speed = camera.Speed / 100;
PushStyleCompact();
ImGui.PushID(0); ImGui.BeginDisabled(model.TransformsCount < 2);
ImGui.SetNextItemWidth(ImGui.GetContentRegionAvail().X);
ImGui.SliderInt("", ref options.SelectedModelInstance, 0, model.TransformsCount - 1, "Instance %i", ImGuiSliderFlags.AlwaysClamp);
ImGui.EndDisabled(); ImGui.PopID();
ImGui.SetNextItemOpen(true, ImGuiCond.Appearing);
if (ImGui.TreeNode("Location"))
{
ImGui.PushID(1);
ImGui.SetNextItemWidth(width);
ImGui.DragFloat("X", ref model.Transforms[options.SelectedModelInstance].Position.X, speed, 0f, 0f, "%.2f m");
ImGui.SetNextItemWidth(width);
ImGui.DragFloat("Y", ref model.Transforms[options.SelectedModelInstance].Position.Y, speed, 0f, 0f, "%.2f m");
ImGui.SetNextItemWidth(width);
ImGui.DragFloat("Z", ref model.Transforms[options.SelectedModelInstance].Position.Z, speed, 0f, 0f, "%.2f m");
ImGui.PopID();
ImGui.TreePop();
}
ImGui.SetNextItemOpen(true, ImGuiCond.Appearing);
if (ImGui.TreeNode("Rotation"))
{
ImGui.PushID(2);
ImGui.SetNextItemWidth(width);
ImGui.DragFloat("X", ref model.Transforms[options.SelectedModelInstance].Rotation.Pitch, .5f, 0f, 0f, "%.1f°");
ImGui.SetNextItemWidth(width);
ImGui.DragFloat("Y", ref model.Transforms[options.SelectedModelInstance].Rotation.Roll, .5f, 0f, 0f, "%.1f°");
ImGui.SetNextItemWidth(width);
ImGui.DragFloat("Z", ref model.Transforms[options.SelectedModelInstance].Rotation.Yaw, .5f, 0f, 0f, "%.1f°");
ImGui.PopID();
ImGui.TreePop();
}
ImGui.SetNextItemOpen(true, ImGuiCond.Appearing);
if (ImGui.TreeNode("Scale"))
{
ImGui.PushID(3);
ImGui.SetNextItemWidth(width);
ImGui.DragFloat("X", ref model.Transforms[options.SelectedModelInstance].Scale.X, speed, 0f, 0f, "%.3f");
ImGui.SetNextItemWidth(width);
ImGui.DragFloat("Y", ref model.Transforms[options.SelectedModelInstance].Scale.Y, speed, 0f, 0f, "%.3f");
ImGui.SetNextItemWidth(width);
ImGui.DragFloat("Z", ref model.Transforms[options.SelectedModelInstance].Scale.Z, speed, 0f, 0f, "%.3f");
ImGui.PopID();
ImGui.TreePop();
}
model.UpdateMatrix(options.SelectedModelInstance);
PopStyleCompact();
ImGui.EndTabItem();
}
if (ImGui.BeginTabItem("Materials"))
{
PushStyleCompact();
ImGui.BeginTable("Sections", 2, ImGuiTableFlags.Borders | ImGuiTableFlags.Resizable);
ImGui.TableSetupColumn("Index", ImGuiTableColumnFlags.NoHeaderWidth | ImGuiTableColumnFlags.WidthFixed);
ImGui.TableSetupColumn("Name");
ImGui.TableHeadersRow();
for (var i = 0; i < model.Sections.Length; i++)
{
var section = model.Sections[i];
ImGui.PushID(i);
ImGui.TableNextRow();
ImGui.TableNextColumn();
if (!section.Show)
ImGui.TableSetBgColor(ImGuiTableBgTarget.RowBg0, ImGui.GetColorU32(new Vector4(1, 0, 0, .5f)));
ImGui.Text(section.Index.ToString("D"));
ImGui.TableNextColumn();
if (ImGui.Selectable(section.Name, options.SelectedSection == i, ImGuiSelectableFlags.SpanAllColumns))
options.SelectSection(i);
if (ImGui.BeginPopupContextItem())
{
options.SelectSection(i);
if (ImGui.Selectable("Swap"))
options.SwapMaterial(true);
if (ImGui.Selectable("Copy Name to Clipboard"))
Application.Current.Dispatcher.Invoke(delegate
{
Clipboard.SetText(section.Name);
});
ImGui.EndPopup();
}
ImGui.PopID();
}
ImGui.EndTable();
PopStyleCompact();
ImGui.EndTabItem();
}
if (model.HasMorphTargets && ImGui.BeginTabItem("Morph Targets"))
{
PushStyleCompact();
if (ImGui.BeginListBox("", new Vector2(ImGui.GetContentRegionAvail().X, _propertiesSize.Y / 2)))
{
for (int i = 0; i < model.Morphs.Length; i++)
{
ImGui.PushID(i);
if (ImGui.Selectable(model.Morphs[i].Name, options.SelectedMorph == i))
options.SelectMorph(i, model);
ImGui.PopID();
}
ImGui.EndListBox();
ImGui.Separator();
ImGui.DragFloat("Value", ref model.MorphTime, 0.01f, 0.0f, 1.0f, "%.2f", ImGuiSliderFlags.AlwaysClamp);
}
PopStyleCompact();
ImGui.EndTabItem();
}
}
ImGui.End();
}
private void DrawTextures(ref Options options, IDictionary<FGuid, Model> models)
{
ImGui.SetNextWindowSize(_textureSize, _firstUse);
ImGui.SetNextWindowPos(_texturePosition, _firstUse);
ImGui.Begin("Textures", _noResize | ImGuiWindowFlags.NoCollapse);
if (!models.TryGetValue(options.SelectedModel, out var model) ||
!options.TryGetSection(model, out var section))
return;
PushStyleCompact(); ImGui.BeginGroup();
ImGui.Checkbox("Show", ref section.Show);
ImGui.Checkbox("Wireframe", ref section.Wireframe);
ImGui.SetNextItemWidth(50); ImGui.DragFloat("Metallic", ref section.Parameters.MetallicValue, 0.01f, 0.0f, 1.0f, "%.2f");
ImGui.SetNextItemWidth(50); ImGui.DragFloat("Roughness", ref section.Parameters.RoughnessValue, 0.01f, 0.0f, 1.0f, "%.2f");
ImGui.EndGroup(); PopStyleCompact(); ImGui.SameLine(); ImGui.BeginGroup();
if (section.HasDiffuseColor)
{
ImGui.SetNextItemWidth(300);
ImGui.ColorEdit4(section.TexturesLabels[0], ref section.DiffuseColor, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar);
if (section.Textures[1] is { } normalMap) DrawTexture(normalMap, "Normal");
}
else
{
for (var i = 0;i < section.Textures.Length; i++)
{
if (section.Textures[i] is not {} texture)
continue;
DrawTexture(texture, section.TexturesLabels[i]);
if (i == 3) // emissive, show color
{
ImGui.SameLine();
ImGui.SetNextItemWidth(300);
ImGui.ColorEdit4($"{section.TexturesLabels[i]} Color", ref section.EmissionColor, ImGuiColorEditFlags.NoAlpha);
}
}
}
ImGui.EndGroup();
ImGui.End();
}
private void DrawTexture(Texture texture, string label)
{
ImGui.SameLine();
ImGui.BeginGroup();
ImGui.Image(texture.GetPointer(), new Vector2(88), Vector2.Zero, Vector2.One, Vector4.One, new Vector4(1, 1, 1, .5f));
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())
{
Application.Current.Dispatcher.Invoke(delegate
{
Clipboard.SetText(Utils.FixPath(texture.Path));
texture.Label = "(?) Path Copied to Clipboard";
});
}
var width = ImGui.GetCursorPos().X;
ImGui.SetCursorPosX(width + ImGui.CalcTextSize(label).X * 0.5f);
ImGui.Text(label);
ImGui.EndGroup();
}
private void Draw3DViewport(FramebufferObject framebuffer, Camera camera, IMouse mouse)
{
const float lookSensitivity = 0.1f;
const ImGuiWindowFlags flags =
ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse |
ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.AlwaysUseWindowPadding;
ImGui.SetNextWindowSize(_viewportSize, _firstUse);
ImGui.SetNextWindowPos(_viewportPosition, _firstUse);
ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, Vector2.Zero);
ImGui.Begin($"Viewport ({_api.API} {_api.Version.MajorVersion}.{_api.Version.MinorVersion}) ({_renderer})", _noResize | flags);
ImGui.PopStyleVar();
var largest = ImGui.GetContentRegionAvail();
largest.X -= ImGui.GetScrollX();
largest.Y -= ImGui.GetScrollY();
var width = largest.X;
var height = width / camera.AspectRatio;
if (height > largest.Y)
{
height = largest.Y;
width = height * camera.AspectRatio;
}
var pos = new Vector2(largest.X / 2f - width / 2f + ImGui.GetCursorPosX(), largest.Y / 2f - height / 2f + ImGui.GetCursorPosY());
var size = new Vector2(width, height);
ImGui.SetCursorPos(pos);
ImGui.ImageButton(framebuffer.GetPointer(), size, new Vector2(0, 1), new Vector2(1, 0), 0);
// it took me 5 hours to make it work, don't change any of the following code
// basically the Raw cursor doesn't actually freeze the mouse position
// so for ImGui, the IsItemHovered will be false if mouse leave, even in Raw mode
var io = ImGui.GetIO();
if (ImGui.IsItemHovered())
{
// if right button down while mouse is hover viewport
if (ImGui.IsMouseDown(ImGuiMouseButton.Right) && !_viewportFocus)
_viewportFocus = true;
}
// this can't be inside IsItemHovered! read it as
// if right mouse button was pressed while hovering the viewport
// move camera until right mouse button is released
// no matter where mouse position end up
if (ImGui.IsMouseDragging(ImGuiMouseButton.Right, lookSensitivity) && _viewportFocus)
{
var delta = io.MouseDelta * lookSensitivity;
camera.ModifyDirection(delta.X, delta.Y);
mouse.Cursor.CursorMode = CursorMode.Raw;
}
// if left button up and mouse was in viewport
if (ImGui.IsMouseReleased(ImGuiMouseButton.Right) && _viewportFocus)
{
_viewportFocus = false;
mouse.Cursor.CursorMode = CursorMode.Normal;
}
const float padding = 5f;
float framerate = ImGui.GetIO().Framerate;
var text = $"FPS: {framerate:0} ({1000.0f / framerate:0.##} ms)";
ImGui.SetCursorPos(new Vector2(pos.X + padding, pos.Y + size.Y - ImGui.CalcTextSize(text).Y - padding));
ImGui.Text(text);
ImGui.End();
}
private void PushStyleCompact()
{
var style = ImGui.GetStyle();
ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, style.FramePadding with { Y = style.FramePadding.Y * 0.6f });
ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, style.ItemSpacing with { Y = style.ItemSpacing.Y * 0.6f });
}
private void PopStyleCompact() => ImGui.PopStyleVar(2);
private void Theme(ImGuiStylePtr style)
{
var io = ImGui.GetIO();
io.ConfigFlags |= ImGuiConfigFlags.DockingEnable;
io.ConfigFlags |= ImGuiConfigFlags.ViewportsEnable;
io.ConfigWindowsMoveFromTitleBarOnly = true;
io.ConfigDockingWithShift = true;
style.WindowMenuButtonPosition = ImGuiDir.Right;
style.ScrollbarSize = 10f;
style.FrameRounding = 3.0f;
style.Colors[(int) ImGuiCol.Text] = new Vector4(1.00f, 1.00f, 1.00f, 1.00f);
style.Colors[(int) ImGuiCol.TextDisabled] = new Vector4(0.50f, 0.50f, 0.50f, 1.00f);
style.Colors[(int) ImGuiCol.WindowBg] = new Vector4(0.11f, 0.11f, 0.12f, 1.00f);
style.Colors[(int) ImGuiCol.ChildBg] = new Vector4(0.15f, 0.15f, 0.19f, 1.00f);
style.Colors[(int) ImGuiCol.PopupBg] = new Vector4(0.08f, 0.08f, 0.08f, 0.94f);
style.Colors[(int) ImGuiCol.Border] = new Vector4(0.25f, 0.26f, 0.33f, 1.00f);
style.Colors[(int) ImGuiCol.BorderShadow] = new Vector4(0.00f, 0.00f, 0.00f, 0.00f);
style.Colors[(int) ImGuiCol.FrameBg] = new Vector4(0.05f, 0.05f, 0.05f, 0.54f);
style.Colors[(int) ImGuiCol.FrameBgHovered] = new Vector4(0.69f, 0.69f, 1.00f, 0.20f);
style.Colors[(int) ImGuiCol.FrameBgActive] = new Vector4(0.69f, 0.69f, 1.00f, 0.39f);
style.Colors[(int) ImGuiCol.TitleBg] = new Vector4(0.09f, 0.09f, 0.09f, 1.00f);
style.Colors[(int) ImGuiCol.TitleBgActive] = new Vector4(0.09f, 0.09f, 0.09f, 1.00f);
style.Colors[(int) ImGuiCol.TitleBgCollapsed] = new Vector4(0.05f, 0.05f, 0.05f, 0.51f);
style.Colors[(int) ImGuiCol.MenuBarBg] = new Vector4(0.14f, 0.14f, 0.14f, 1.00f);
style.Colors[(int) ImGuiCol.ScrollbarBg] = new Vector4(0.02f, 0.02f, 0.02f, 0.53f);
style.Colors[(int) ImGuiCol.ScrollbarGrab] = new Vector4(0.31f, 0.31f, 0.31f, 1.00f);
style.Colors[(int) ImGuiCol.ScrollbarGrabHovered] = new Vector4(0.41f, 0.41f, 0.41f, 1.00f);
style.Colors[(int) ImGuiCol.ScrollbarGrabActive] = new Vector4(0.51f, 0.51f, 0.51f, 1.00f);
style.Colors[(int) ImGuiCol.CheckMark] = new Vector4(0.13f, 0.42f, 0.83f, 1.00f);
style.Colors[(int) ImGuiCol.SliderGrab] = new Vector4(0.13f, 0.42f, 0.83f, 0.78f);
style.Colors[(int) ImGuiCol.SliderGrabActive] = new Vector4(0.13f, 0.42f, 0.83f, 1.00f);
style.Colors[(int) ImGuiCol.Button] = new Vector4(0.05f, 0.05f, 0.05f, 0.54f);
style.Colors[(int) ImGuiCol.ButtonHovered] = new Vector4(0.69f, 0.69f, 1.00f, 0.20f);
style.Colors[(int) ImGuiCol.ButtonActive] = new Vector4(0.69f, 0.69f, 1.00f, 0.39f);
style.Colors[(int) ImGuiCol.Header] = new Vector4(0.16f, 0.16f, 0.21f, 1.00f);
style.Colors[(int) ImGuiCol.HeaderHovered] = new Vector4(0.69f, 0.69f, 1.00f, 0.20f);
style.Colors[(int) ImGuiCol.HeaderActive] = new Vector4(0.69f, 0.69f, 1.00f, 0.39f);
style.Colors[(int) ImGuiCol.Separator] = new Vector4(0.43f, 0.43f, 0.50f, 0.50f);
style.Colors[(int) ImGuiCol.SeparatorHovered] = new Vector4(0.10f, 0.40f, 0.75f, 0.78f);
style.Colors[(int) ImGuiCol.SeparatorActive] = new Vector4(0.10f, 0.40f, 0.75f, 1.00f);
style.Colors[(int) ImGuiCol.ResizeGrip] = new Vector4(0.13f, 0.42f, 0.83f, 0.39f);
style.Colors[(int) ImGuiCol.ResizeGripHovered] = new Vector4(0.12f, 0.41f, 0.81f, 0.78f);
style.Colors[(int) ImGuiCol.ResizeGripActive] = new Vector4(0.12f, 0.41f, 0.81f, 1.00f);
style.Colors[(int) ImGuiCol.Tab] = new Vector4(0.15f, 0.15f, 0.19f, 1.00f);
style.Colors[(int) ImGuiCol.TabHovered] = new Vector4(0.35f, 0.35f, 0.41f, 0.80f);
style.Colors[(int) ImGuiCol.TabActive] = new Vector4(0.23f, 0.24f, 0.29f, 1.00f);
style.Colors[(int) ImGuiCol.TabUnfocused] = new Vector4(0.15f, 0.15f, 0.15f, 1.00f);
style.Colors[(int) ImGuiCol.TabUnfocusedActive] = new Vector4(0.14f, 0.26f, 0.42f, 1.00f);
style.Colors[(int) ImGuiCol.DockingPreview] = new Vector4(0.26f, 0.59f, 0.98f, 0.70f);
style.Colors[(int) ImGuiCol.DockingEmptyBg] = new Vector4(0.20f, 0.20f, 0.20f, 1.00f);
style.Colors[(int) ImGuiCol.PlotLines] = new Vector4(0.61f, 0.61f, 0.61f, 1.00f);
style.Colors[(int) ImGuiCol.PlotLinesHovered] = new Vector4(1.00f, 0.43f, 0.35f, 1.00f);
style.Colors[(int) ImGuiCol.PlotHistogram] = new Vector4(0.90f, 0.70f, 0.00f, 1.00f);
style.Colors[(int) ImGuiCol.PlotHistogramHovered] = new Vector4(1.00f, 0.60f, 0.00f, 1.00f);
style.Colors[(int) ImGuiCol.TableHeaderBg] = new Vector4(0.09f, 0.09f, 0.09f, 1.00f);
style.Colors[(int) ImGuiCol.TableBorderStrong] = new Vector4(0.69f, 0.69f, 1.00f, 0.20f);
style.Colors[(int) ImGuiCol.TableBorderLight] = new Vector4(0.69f, 0.69f, 1.00f, 0.20f);
style.Colors[(int) ImGuiCol.TableRowBg] = new Vector4(0.00f, 0.00f, 0.00f, 0.00f);
style.Colors[(int) ImGuiCol.TableRowBgAlt] = new Vector4(1.00f, 1.00f, 1.00f, 0.06f);
style.Colors[(int) ImGuiCol.TextSelectedBg] = new Vector4(0.26f, 0.59f, 0.98f, 0.35f);
style.Colors[(int) ImGuiCol.DragDropTarget] = new Vector4(1.00f, 1.00f, 0.00f, 0.90f);
style.Colors[(int) ImGuiCol.NavHighlight] = new Vector4(0.26f, 0.59f, 0.98f, 1.00f);
style.Colors[(int) ImGuiCol.NavWindowingHighlight] = new Vector4(1.00f, 1.00f, 1.00f, 0.70f);
style.Colors[(int) ImGuiCol.NavWindowingDimBg] = new Vector4(0.80f, 0.80f, 0.80f, 0.20f);
style.Colors[(int) ImGuiCol.ModalWindowDimBg] = new Vector4(0.80f, 0.80f, 0.80f, 0.35f);
}
public void Update(float deltaTime) => _controller.Update(deltaTime);
public void Render() => _controller.Render();
public void Dispose() => _controller.Dispose();
}

View File

@@ -31,7 +31,7 @@ public class Snooper
public void Run(CancellationToken cancellationToken, UObject export)
{
_window.Run();
_window.Run(cancellationToken, export);
}
public void SwapMaterial(UMaterialInstance mi)

View File

@@ -2,6 +2,8 @@
using System.Windows;
using CUE4Parse.UE4.Assets.Exports.Texture;
using OpenTK.Graphics.OpenGL4;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using SkiaSharp;
namespace FModel.Views.Snooper;
@@ -30,16 +32,16 @@ public class Texture : IDisposable
public Texture(uint width, uint height) : this(TextureType.MsaaFramebuffer)
{
Width = width;
Height = height;
Width = (int) width;
Height = (int) height;
Bind(TextureUnit.Texture0);
GL.TexImage2DMultisample(TextureTargetMultisample.Texture2DMultisample, Constants.SAMPLES_COUNT, PixelInternalFormat.Rgb, Width, Height, true);
GL.TexParameter(TextureTarget.Texture2DMultisample, TextureParameterName.TextureMinFilter, (int) GLEnum.Nearest);
GL.TexParameter(TextureTarget.Texture2DMultisample, TextureParameterName.TextureMagFilter, (int) GLEnum.Nearest);
GL.TexParameter(TextureTarget.Texture2DMultisample, TextureParameterName.TextureWrapS, (int) GLEnum.ClampToEdge);
GL.TexParameter(TextureTarget.Texture2DMultisample, TextureParameterName.TextureWrapT, (int) GLEnum.ClampToEdge);
GL.TexParameter(TextureTarget.Texture2DMultisample, TextureParameterName.TextureMinFilter, (int) TextureMinFilter.Nearest);
GL.TexParameter(TextureTarget.Texture2DMultisample, TextureParameterName.TextureMagFilter, (int) TextureMinFilter.Nearest);
GL.TexParameter(TextureTarget.Texture2DMultisample, TextureParameterName.TextureWrapS, (int) TextureWrapMode.ClampToEdge);
GL.TexParameter(TextureTarget.Texture2DMultisample, TextureParameterName.TextureWrapT, (int) TextureWrapMode.ClampToEdge);
GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, TextureTarget.Texture2DMultisample, _handle, 0);
}
@@ -50,12 +52,12 @@ public class Texture : IDisposable
Height = height;
Bind(TextureUnit.Texture0);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgb, Width, Height, 0, PixelFormat.Rgb, PixelType.UnsignedByte, null);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgb, Width, Height, 0, PixelFormat.Rgb, PixelType.UnsignedByte, IntPtr.Zero);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int) GLEnum.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int) GLEnum.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int) GLEnum.ClampToEdge);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int) GLEnum.ClampToEdge);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int) TextureMinFilter.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int) TextureMinFilter.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int) TextureWrapMode.ClampToEdge);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int) TextureWrapMode.ClampToEdge);
GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, TextureTarget.Texture2D, _handle, 0);
}
@@ -68,20 +70,17 @@ public class Texture : IDisposable
Format = texture2D.Format;
ImportedWidth = texture2D.ImportedSize.X;
ImportedHeight = texture2D.ImportedSize.Y;
Width = width;
Height = height;
Width = (int) width;
Height = (int) height;
Bind(TextureUnit.Texture0);
fixed (void* d = &data[0])
{
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgb, Width, Height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, d);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int) GLEnum.LinearMipmapLinear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int) GLEnum.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureBaseLevel, 0);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMaxLevel, 8);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgb, Width, Height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, data);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int) TextureMinFilter.LinearMipmapLinear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int) TextureMinFilter.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureBaseLevel, 0);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMaxLevel, 8);
GL.GenerateMipmap(GenerateMipmapTarget.Texture2D);
}
GL.GenerateMipmap(GenerateMipmapTarget.Texture2D);
}
public unsafe Texture(string[] textures) : this(TextureType.Cubemap)
@@ -92,42 +91,41 @@ public class Texture : IDisposable
{
var info = Application.GetResourceStream(new Uri($"/FModel;component/Resources/{textures[t]}.png", UriKind.Relative));
using var img = Image.Load<Rgba32>(info.Stream);
Width = (uint) img.Width; // we don't care anyway
Height = (uint) img.Height; // we don't care anyway
GL.TexImage2D(TextureTarget.TextureCubeMapPositiveX + t, 0, PixelInternalFormat.Rgba8, Width, Height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, null);
Width = img.Width; // we don't care anyway
Height = img.Height; // we don't care anyway
GL.TexImage2D(TextureTarget.TextureCubeMapPositiveX + t, 0, PixelInternalFormat.Rgba8, Width, Height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, IntPtr.Zero);
img.ProcessPixelRows(accessor =>
{
for (int y = 0; y < accessor.Height; y++)
{
fixed (void* data = accessor.GetRowSpan(y))
{
GL.TexSubImage2D(TextureTarget.TextureCubeMapPositiveX + t, 0, 0, y, (uint) accessor.Width, 1, PixelFormat.Rgba, PixelType.UnsignedByte, data);
}
GL.TexSubImage2D(TextureTarget.TextureCubeMapPositiveX + t, 0, 0, y, accessor.Width, 1, PixelFormat.Rgba, PixelType.UnsignedByte, accessor.GetRowSpan(y).ToArray());
}
});
}
GL.TexParameter(TextureTarget.TextureCubeMap, TextureParameterName.TextureMinFilter, (int) GLEnum.Linear);
GL.TexParameter(TextureTarget.TextureCubeMap, TextureParameterName.TextureMagFilter, (int) GLEnum.Linear);
GL.TexParameter(TextureTarget.TextureCubeMap, TextureParameterName.TextureWrapR, (int) GLEnum.ClampToEdge);
GL.TexParameter(TextureTarget.TextureCubeMap, TextureParameterName.TextureWrapS, (int) GLEnum.ClampToEdge);
GL.TexParameter(TextureTarget.TextureCubeMap, TextureParameterName.TextureWrapT, (int) GLEnum.ClampToEdge);
GL.TexParameter(TextureTarget.TextureCubeMap, TextureParameterName.TextureMinFilter, (int) TextureMinFilter.Linear);
GL.TexParameter(TextureTarget.TextureCubeMap, TextureParameterName.TextureMagFilter, (int) TextureMinFilter.Linear);
GL.TexParameter(TextureTarget.TextureCubeMap, TextureParameterName.TextureWrapR, (int) TextureWrapMode.ClampToEdge);
GL.TexParameter(TextureTarget.TextureCubeMap, TextureParameterName.TextureWrapS, (int) TextureWrapMode.ClampToEdge);
GL.TexParameter(TextureTarget.TextureCubeMap, TextureParameterName.TextureWrapT, (int) TextureWrapMode.ClampToEdge);
}
public unsafe Texture(uint width, uint height, IntPtr data) : this(TextureType.Normal)
{
Width = width;
Height = height;
Width = (int) width;
Height = (int) height;
Bind(TextureTarget.Texture2D);
GL.TexStorage2D(TextureTarget2d.Texture2D, 1, SizedInternalFormat.Rgba8, Width, Height);
GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, Width, Height, PixelFormat.Bgra, PixelType.UnsignedByte, (void*) data);
GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, Width, Height, PixelFormat.Bgra, PixelType.UnsignedByte, data);
GL.TexParameterI(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat);
GL.TexParameterI(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat);
var repeat = (int) TextureWrapMode.Repeat;
GL.TexParameterI(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, ref repeat);
GL.TexParameterI(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, ref repeat);
GL.TexParameterI(TextureTarget.Texture2D, TextureParameterName.TextureMaxLevel, 1 - 1);
var zero = 1 - 1;
GL.TexParameterI(TextureTarget.Texture2D, TextureParameterName.TextureMaxLevel, ref zero);
}
public void Bind(TextureUnit textureSlot)