junky cam movements

This commit is contained in:
4sval 2022-10-31 01:56:29 +01:00
parent 4e321d74c9
commit b4df69fbeb
11 changed files with 361 additions and 213 deletions

View File

@ -232,25 +232,19 @@ outputColor = color * texture(in_fontTexture, texCoord);
private void UpdateImGuiInput(GameWindow wnd)
{
ImGuiIOPtr io = ImGui.GetIO();
var mState = wnd.MouseState;
var kState = wnd.KeyboardState;
MouseState MouseState = wnd.MouseState;
KeyboardState KeyboardState = wnd.KeyboardState;
io.AddMouseButtonEvent(0, mState[MouseButton.Left]);
io.AddMouseButtonEvent(1, mState[MouseButton.Right]);
io.AddMouseButtonEvent(2, mState[MouseButton.Middle]);
io.MouseDown[0] = MouseState[MouseButton.Left];
io.MouseDown[1] = MouseState[MouseButton.Right];
io.MouseDown[2] = MouseState[MouseButton.Middle];
var screenPoint = new Vector2i((int)MouseState.X, (int)MouseState.Y);
var point = screenPoint;//wnd.PointToClient(screenPoint);
io.MousePos = new System.Numerics.Vector2(point.X, point.Y);
io.AddMousePosEvent(mState.PreviousX, mState.PreviousY);
foreach (Keys key in Enum.GetValues(typeof(Keys)))
{
if (key == Keys.Unknown)
{
continue;
}
io.KeysDown[(int)key] = KeyboardState.IsKeyDown(key);
if (key == Keys.Unknown) continue;
io.AddKeyEvent((ImGuiKey) (int)key, kState.IsKeyDown(key));
}
foreach (var c in PressedChars)
@ -259,10 +253,10 @@ outputColor = color * texture(in_fontTexture, texCoord);
}
PressedChars.Clear();
io.KeyCtrl = KeyboardState.IsKeyDown(Keys.LeftControl) || KeyboardState.IsKeyDown(Keys.RightControl);
io.KeyAlt = KeyboardState.IsKeyDown(Keys.LeftAlt) || KeyboardState.IsKeyDown(Keys.RightAlt);
io.KeyShift = KeyboardState.IsKeyDown(Keys.LeftShift) || KeyboardState.IsKeyDown(Keys.RightShift);
io.KeySuper = KeyboardState.IsKeyDown(Keys.LeftSuper) || KeyboardState.IsKeyDown(Keys.RightSuper);
io.KeyCtrl = kState.IsKeyDown(Keys.LeftControl) || kState.IsKeyDown(Keys.RightControl);
io.KeyAlt = kState.IsKeyDown(Keys.LeftAlt) || kState.IsKeyDown(Keys.RightAlt);
io.KeyShift = kState.IsKeyDown(Keys.LeftShift) || kState.IsKeyDown(Keys.RightShift);
io.KeySuper = kState.IsKeyDown(Keys.LeftSuper) || kState.IsKeyDown(Keys.RightSuper);
}
internal void PressChar(char keyChar)
@ -273,7 +267,6 @@ outputColor = color * texture(in_fontTexture, texCoord);
internal void MouseScroll(Vector2 offset)
{
ImGuiIOPtr io = ImGui.GetIO();
io.MouseWheel = offset.Y;
io.MouseWheelH = offset.X;
}

View File

@ -3,7 +3,7 @@
in vec3 fPos;
in vec3 fNormal;
in vec2 fTexCoords;
in float fTexIndex;
in float fTexLayer;
in vec4 fColor;
struct Material {
@ -37,33 +37,24 @@ uniform bool display_vertex_colors;
out vec4 FragColor;
vec4 getValueFromSamplerArray(sampler2D array[8]) {
if (fTexIndex < 1.0) {
return texture(array[0], fTexCoords);
} if (fTexIndex < 2.0) {
return texture(array[1], fTexCoords);
} if (fTexIndex < 3.0) {
return texture(array[2], fTexCoords);
} else {
return texture(array[3], fTexCoords);
}
int LayerToIndex(int max)
{
return min(int(fTexLayer), max);
}
vec3 getValueFromVec4Array(vec4 array[8]) {
if (fTexIndex < 1.0) {
return array[0].rgb;
} if (fTexIndex < 2.0) {
return array[1].rgb;
} if (fTexIndex < 3.0) {
return array[2].rgb;
} else {
return array[3].rgb;
}
vec4 SamplerSelector(sampler2D array[8])
{
return texture(array[LayerToIndex(7)], fTexCoords);
}
vec4 VectorSelector(vec4 array[8])
{
return array[LayerToIndex(7)];
}
vec3 getNormalFromMap()
{
vec3 tangentNormal = getValueFromSamplerArray(material.normalMap).xyz * 2.0 - 1.0;
vec3 tangentNormal = SamplerSelector(material.normalMap).xyz * 2.0 - 1.0;
vec3 q1 = dFdx(fPos);
vec3 q2 = dFdy(fPos);
@ -98,7 +89,7 @@ void main()
}
else
{
vec4 diffuse_map = getValueFromSamplerArray(material.diffuseMap);
vec4 diffuse_map = SamplerSelector(material.diffuseMap);
vec3 diffuse_no_alpha = vec3(diffuse_map);
vec3 result = light.ambient * diffuse_no_alpha;
@ -111,14 +102,14 @@ void main()
vec3 n_view_direction = normalize(viewPos - fPos);
vec3 reflect_direction = reflect(-n_light_direction, n_normal_map);
float metallic = pow(max(dot(n_view_direction, reflect_direction), 0.0f), material.metallic_value);
vec3 specular_map = vec3(getValueFromSamplerArray(material.specularMap));
vec3 specular_map = vec3(SamplerSelector(material.specularMap));
result += specular_map.r * light.specular * (metallic * specular_map.g);
result += material.roughness_value * specular_map.b;
}
// emission
vec3 emission_map = vec3(getValueFromSamplerArray(material.emissionMap));
result += getValueFromVec4Array(material.emissionColor) * emission_map;
vec3 emission_map = vec3(SamplerSelector(material.emissionMap));
result += VectorSelector(material.emissionColor).rgb * emission_map;
FragColor = vec4(result, 1.0);
}

View File

@ -3,7 +3,7 @@
layout (location = 1) in vec3 vPos;
layout (location = 2) in vec3 vNormal;
layout (location = 3) in vec2 vTexCoords;
layout (location = 4) in float vTexIndex;
layout (location = 4) in float vTexLayer;
layout (location = 5) in vec4 vColor;
layout (location = 6) in ivec4 vBoneIds;
layout (location = 7) in vec4 vWeights;
@ -17,7 +17,7 @@ uniform float uMorphTime;
out vec3 fPos;
out vec3 fNormal;
out vec2 fTexCoords;
out float fTexIndex;
out float fTexLayer;
out vec4 fColor;
void main()
@ -28,6 +28,6 @@ void main()
fPos = vec3(vInstanceMatrix * vec4(pos, 1.0));
fNormal = mat3(transpose(inverse(vInstanceMatrix))) * vNormal;
fTexCoords = vTexCoords;
fTexIndex = vTexIndex;
fTexLayer = vTexLayer;
fColor = vColor;
}

View File

@ -83,8 +83,8 @@ public class CUE4ParseViewModel : ViewModel
new NativeWindowSettings
{
Size = new Vector2i(
Convert.ToInt32(SystemParameters.MaximizedPrimaryScreenWidth * .7),
Convert.ToInt32(SystemParameters.MaximizedPrimaryScreenHeight * .7)),
Convert.ToInt32(SystemParameters.MaximizedPrimaryScreenWidth * .75),
Convert.ToInt32(SystemParameters.MaximizedPrimaryScreenHeight * .85)),
NumberOfSamples = Constants.SAMPLES_COUNT,
WindowBorder = WindowBorder.Resizable,
StartVisible = false,
@ -786,7 +786,7 @@ public class CUE4ParseViewModel : ViewModel
}
case UMaterialInstance m when ModelIsOverwritingMaterial:
{
SnooperViewer.SwapMaterial(m);
SnooperViewer.Renderer.Swap(m);
SnooperViewer.Run();
return true;
}

View File

@ -1,67 +1,89 @@
using System;
using System.Collections.Generic;
using CUE4Parse_Conversion.Meshes;
using CUE4Parse_Conversion.Textures;
using CUE4Parse.UE4.Assets.Exports.StaticMesh;
using CUE4Parse.UE4.Assets.Exports.Texture;
using CUE4Parse.UE4.Objects.Core.Misc;
using FModel.Settings;
namespace FModel.Views.Snooper;
public class Cache : IDisposable
{
private readonly Dictionary<FGuid, Model> _models;
private readonly Dictionary<FGuid, Texture> _textures;
public readonly Dictionary<FGuid, Model> Models;
public readonly Dictionary<FGuid, Texture> Textures;
private ETexturePlatform _platform;
public Cache()
{
_models = new Dictionary<FGuid, Model>();
_textures = new Dictionary<FGuid, Texture>();
Models = new Dictionary<FGuid, Model>();
Textures = new Dictionary<FGuid, Texture>();
_platform = UserSettings.Default.OverridedPlatform;
}
public void AddModel(FGuid guid, Model model) => _models.Add(guid, model);
public void AddTexture(FGuid guid, Texture texture) => _textures.Add(guid, texture);
public bool TryGetCachedModel(UStaticMesh o, out Model model)
{
var guid = o.LightingGuid;
if (!Models.TryGetValue(guid, out model) && o.TryConvert(out var mesh))
{
model = new Model(o.Name, o.ExportType, o.Materials, mesh);
Models[guid] = model;
}
return model != null;
}
public bool HasModel(FGuid guid) => _models.ContainsKey(guid);
public bool HasTexture(FGuid guid) => _textures.ContainsKey(guid);
public bool TryGetCachedTexture(UTexture2D o, out Texture texture)
{
var guid = o.LightingGuid;
if (!Textures.TryGetValue(guid, out texture) && o.GetFirstMip() is { } mip)
{
TextureDecoder.DecodeTexture(mip, o.Format, o.isNormalMap, _platform, out var data, out _);
public bool TryGetModel(FGuid guid, out Model model) => _models.TryGetValue(guid, out model);
public bool TryGetTexture(FGuid guid, out Texture texture) => _textures.TryGetValue(guid, out texture);
texture = new Texture(data, mip.SizeX, mip.SizeY, o);
Textures[guid] = texture;
}
return texture != null;
}
public void Setup()
{
foreach (var model in _models.Values)
foreach (var model in Models.Values)
{
if (model.IsSetup) continue;
model.Setup(this);
}
}
public void Render(Shader shader)
{
foreach (var model in _models.Values)
foreach (var model in Models.Values)
{
if (!model.Show) continue;
model.Render(shader);
}
}
public void Outline(Shader shader)
{
foreach (var model in _models.Values)
foreach (var model in Models.Values)
{
if (!model.IsSelected) continue;
if (!model.IsSelected || !model.Show) continue;
model.Outline(shader);
}
}
public void ClearModels() => _models.Clear();
public void ClearTextures() => _textures.Clear();
public void DisposeModels()
{
foreach (var model in _models.Values)
foreach (var model in Models.Values)
{
model.Dispose();
}
}
public void DisposeTextures()
{
foreach (var texture in _textures.Values)
foreach (var texture in Textures.Values)
{
texture.Dispose();
}
@ -70,9 +92,9 @@ public class Cache : IDisposable
public void Dispose()
{
DisposeModels();
ClearModels();
Models.Clear();
DisposeTextures();
ClearTextures();
Textures.Clear();
}
}

View File

@ -1,8 +1,5 @@
using System;
using CUE4Parse_Conversion.Textures;
using CUE4Parse.UE4.Assets.Exports.Material;
using CUE4Parse.UE4.Assets.Exports.Texture;
using FModel.Settings;
using OpenTK.Graphics.OpenGL4;
using OpenTK.Mathematics;
@ -67,43 +64,25 @@ public class Material : IDisposable
}
else
{
var platform = UserSettings.Default.OverridedPlatform;
bool TryGetCached(UTexture2D o, out Texture t)
{
var guid = o.LightingGuid;
if (!cache.TryGetTexture(guid, out t))
{
if (o.GetFirstMip() is { } mip)
{
TextureDecoder.DecodeTexture(mip, o.Format, o.isNormalMap, platform, out var data, out _);
t = new Texture(data, mip.SizeX, mip.SizeY, o);
cache.AddTexture(guid, t);
}
else t = null;
}
return t != null;
}
Diffuse = new Texture[UvNumber];
for (int i = 0; i < Diffuse.Length; i++)
if (Parameters.TryGetTexture2d(out var o, CMaterialParams2.Diffuse[i]) && TryGetCached(o, out var t))
if (Parameters.TryGetTexture2d(out var o, CMaterialParams2.Diffuse[i]) && cache.TryGetCachedTexture(o, out var t))
Diffuse[i] = t;
Normals = new Texture[UvNumber];
for (int i = 0; i < Normals.Length; i++)
if (Parameters.TryGetTexture2d(out var o, CMaterialParams2.Normals[i]) && TryGetCached(o, out var t))
if (Parameters.TryGetTexture2d(out var o, CMaterialParams2.Normals[i]) && cache.TryGetCachedTexture(o, out var t))
Normals[i] = t;
SpecularMasks = new Texture[UvNumber];
for (int i = 0; i < SpecularMasks.Length; i++)
if (Parameters.TryGetTexture2d(out var o, CMaterialParams2.SpecularMasks[i]) && TryGetCached(o, out var t))
if (Parameters.TryGetTexture2d(out var o, CMaterialParams2.SpecularMasks[i]) && cache.TryGetCachedTexture(o, out var t))
SpecularMasks[i] = t;
Emissive = new Texture[UvNumber];
EmissionColor = new Vector4[UvNumber];
for (int i = 0; i < Emissive.Length; i++)
if (Parameters.TryGetTexture2d(out var o, CMaterialParams2.Emissive[i]) && TryGetCached(o, out var t))
if (Parameters.TryGetTexture2d(out var o, CMaterialParams2.Emissive[i]) && cache.TryGetCachedTexture(o, out var t))
{
Emissive[i] = t;

View File

@ -46,6 +46,7 @@ public class Model : IDisposable
public bool IsSelected;
public bool DisplayVertexColors;
public bool DisplayBones;
public int SelectedInstance;
public float MorphTime;
protected Model(string name, string type)
@ -53,7 +54,6 @@ public class Model : IDisposable
Name = name;
Type = type;
Transforms = new List<Transform>();
Show = true;
}
public Model(string name, string type, ResolvedObject[] materials, CStaticMesh staticMesh) : this(name, type, materials, staticMesh, Transform.Identity) {}
@ -79,7 +79,7 @@ public class Model : IDisposable
for (int m = 0; m < Materials.Length; m++)
{
if ((materials[m]?.TryLoad(out var material) ?? false) && material is UMaterialInterface unrealMaterial)
Materials[m] = new Material(lod.NumTexCoords, unrealMaterial); // lod.NumTexCoords
Materials[m] = new Material(lod.NumTexCoords, unrealMaterial);
else Materials[m] = new Material(1);
}
@ -160,10 +160,10 @@ public class Model : IDisposable
public void AddInstance(Transform transform) => Transforms.Add(transform);
public void UpdateMatrix(int index)
public void UpdateMatrix(int instance)
{
_matrixVbo.Bind();
_matrixVbo.Update(index, Transforms[index].Matrix);
_matrixVbo.Update(instance, Transforms[instance].Matrix);
_matrixVbo.Unbind();
}
@ -223,6 +223,7 @@ public class Model : IDisposable
for (int section = 0; section < Sections.Length; section++)
{
if (Sections[section].Show) Show = true;
Sections[section].Setup();
}
@ -266,7 +267,7 @@ public class Model : IDisposable
for (int section = 0; section < Sections.Length; section++)
{
if (!Sections[section].Show) continue;
GL.DrawArraysInstanced(PrimitiveType.Triangles, Sections[section].FirstFaceIndex, Sections[section].FacesCount, TransformsCount);
GL.DrawArraysInstancedBaseInstance(PrimitiveType.Triangles, Sections[section].FirstFaceIndex, Sections[section].FacesCount, TransformsCount, SelectedInstance);
}
_vao.Unbind();

View File

@ -6,8 +6,6 @@ namespace FModel.Views.Snooper;
public class Options
{
public FGuid SelectedModel { get; private set; }
public int SelectedModelInstance;
public int SelectedSection { get; private set; }
public int SelectedMorph { get; private set; }
@ -19,7 +17,6 @@ public class Options
public void Reset()
{
SelectedModel = Guid.Empty;
SelectedModelInstance = 0;
SelectedSection = 0;
SelectedMorph = 0;
}
@ -27,7 +24,6 @@ public class Options
public void SelectModel(FGuid guid)
{
SelectedModel = guid;
SelectedModelInstance = 0;
SelectedSection = 0;
SelectedMorph = 0;
}

View File

@ -9,6 +9,7 @@ using CUE4Parse.UE4.Assets.Exports.Texture;
using CUE4Parse.UE4.Objects.Core.Math;
using CUE4Parse.UE4.Objects.Engine;
using CUE4Parse.UE4.Objects.UObject;
using OpenTK.Graphics.OpenGL4;
using OpenTK.Mathematics;
namespace FModel.Views.Snooper;
@ -16,7 +17,7 @@ namespace FModel.Views.Snooper;
public class Renderer : IDisposable
{
private Shader _shader;
// private Shader _outline; // fix stutter
private Shader _outline;
private Vector3 _diffuseLight;
private Vector3 _specularLight;
@ -43,7 +44,7 @@ public class Renderer : IDisposable
public void Swap(UMaterialInstance unrealMaterial)
{
if (!Cache.TryGetModel(Settings.SelectedModel, out var model) ||
if (!Cache.Models.TryGetValue(Settings.SelectedModel, out var model) ||
!Settings.TryGetSection(model, out var section)) return;
model.Materials[section.MaterialIndex].SwapMaterial(unrealMaterial);
@ -53,7 +54,7 @@ public class Renderer : IDisposable
public void Setup()
{
_shader = new Shader();
// _outline = new Shader("outline");
_outline = new Shader("outline");
_diffuseLight = new Vector3(0.75f);
_specularLight = new Vector3(0.5f);
@ -65,10 +66,10 @@ public class Renderer : IDisposable
var viewMatrix = cam.GetViewMatrix();
var projMatrix = cam.GetProjectionMatrix();
// _outline.Use();
// _outline.SetUniform("uView", viewMatrix);
// _outline.SetUniform("uProjection", projMatrix);
// _outline.SetUniform("viewPos", cam.Position);
_outline.Use();
_outline.SetUniform("uView", viewMatrix);
_outline.SetUniform("uProjection", projMatrix);
_outline.SetUniform("viewPos", cam.Position);
_shader.Use();
_shader.SetUniform("uView", viewMatrix);
@ -80,8 +81,8 @@ public class Renderer : IDisposable
_shader.SetUniform("light.specular", _specularLight);
Cache.Render(_shader);
// GL.Enable(EnableCap.StencilTest); // I don't get why this must be here but it works now so...
// Cache.Outline(_outline);
GL.Enable(EnableCap.StencilTest);
Cache.Outline(_outline);
}
private Camera SetupCamera(FBox box)
@ -97,7 +98,7 @@ public class Renderer : IDisposable
private Camera LoadStaticMesh(UStaticMesh original)
{
var guid = original.LightingGuid;
if (Cache.TryGetModel(guid, out var model))
if (Cache.Models.TryGetValue(guid, out var model))
{
model.AddInstance(Transform.Identity);
return null;
@ -106,7 +107,7 @@ public class Renderer : IDisposable
if (!original.TryConvert(out var mesh))
return null;
Cache.AddModel(guid, new Model(original.Name, original.ExportType, original.Materials, mesh));
Cache.Models[guid] = new Model(original.Name, original.ExportType, original.Materials, mesh);
Settings.SelectModel(guid);
return SetupCamera(mesh.BoundingBox *= Constants.SCALE_DOWN_RATIO);
}
@ -114,9 +115,9 @@ public class Renderer : IDisposable
private Camera LoadSkeletalMesh(USkeletalMesh original)
{
var guid = Guid.NewGuid();
if (Cache.HasModel(guid) || !original.TryConvert(out var mesh)) return null;
if (Cache.Models.ContainsKey(guid) || !original.TryConvert(out var mesh)) return null;
Cache.AddModel(guid, new Model(original.Name, original.ExportType, original.Materials, original.MorphTargets, mesh));
Cache.Models[guid] = new Model(original.Name, original.ExportType, original.Materials, original.MorphTargets, mesh);
Settings.SelectModel(guid);
return SetupCamera(mesh.BoundingBox *= Constants.SCALE_DOWN_RATIO);
}
@ -124,9 +125,9 @@ public class Renderer : IDisposable
private Camera LoadMaterialInstance(UMaterialInstance original)
{
var guid = Guid.NewGuid();
if (Cache.HasModel(guid)) return null;
if (Cache.Models.ContainsKey(guid)) return null;
Cache.AddModel(guid, new Cube(original));
Cache.Models[guid] = new Cube(original);
Settings.SelectModel(guid);
return SetupCamera(new FBox(new FVector(-.65f), new FVector(.65f)));
}
@ -164,7 +165,7 @@ public class Renderer : IDisposable
};
transform.Rotation.Yaw = -transform.Rotation.Yaw;
if (Cache.TryGetModel(guid, out var model))
if (Cache.Models.TryGetValue(guid, out var model))
{
model.AddInstance(transform);
}
@ -207,7 +208,7 @@ public class Renderer : IDisposable
}
}
Cache.AddModel(guid, model);
Cache.Models[guid] = model;
}
}
Services.ApplicationService.ApplicationView.Status.UpdateStatusLabel($"Actor {length}/{length}");
@ -217,7 +218,7 @@ public class Renderer : IDisposable
public void Dispose()
{
_shader.Dispose();
// _outline.Dispose();
_outline.Dispose();
Cache.Dispose();
}
}

View File

@ -5,15 +5,15 @@ using CUE4Parse.UE4.Objects.Core.Misc;
using FModel.Framework;
using ImGuiNET;
using OpenTK.Mathematics;
using OpenTK.Windowing.Desktop;
using OpenTK.Windowing.Common;
using Vector2 = System.Numerics.Vector2;
using Vector4 = System.Numerics.Vector4;
namespace FModel.Views.Snooper;
public class SnimGui : IDisposable
public class SnimGui
{
private readonly ImGuiController _controller;
public readonly ImGuiController Controller;
private readonly Vector2 _outlinerSize;
private readonly Vector2 _outlinerPosition;
@ -31,7 +31,7 @@ public class SnimGui : IDisposable
public SnimGui(int width, int height)
{
_controller = new ImGuiController(width, height);
Controller = new ImGuiController(width, height);
var style = ImGui.GetStyle();
var viewport = ImGui.GetMainViewport();
@ -49,22 +49,32 @@ public class SnimGui : IDisposable
Theme(style);
}
public void Render(Vector2i size, FramebufferObject framebuffer, Camera camera)
public void Render(Snooper s)
{
DrawDockSpace(size);
DrawDockSpace(s.Size);
DrawNavbar();
ImGui.Begin("Outliner");
ImGui.Begin("Camera");
ImGui.End();
ImGui.Begin("Properties");
ImGui.Begin("World");
ImGui.End();
ImGui.Begin("UV Editor");
ImGui.Begin("UV Channels");
ImGui.End();
ImGui.Begin("Timeline");
ImGui.End();
Draw3DViewport(framebuffer, camera);
ImGui.Begin("Materials");
ImGui.End();
ImGui.Begin("Textures");
ImGui.End();
_controller.Render();
DrawTransform(s);
DrawDetails(s);
DrawOuliner(s);
Draw3DViewport(s);
// last render will always be on top
// order by decreasing importance
Controller.Render();
ImGuiController.CheckGLError("End of frame");
}
@ -113,7 +123,157 @@ public class SnimGui : IDisposable
ImGui.EndMainMenuBar();
}
private void Draw3DViewport(FramebufferObject framebuffer, Camera camera)
private void DrawOuliner(Snooper s)
{
ImGui.Begin("Outliner");
PushStyleCompact();
if (ImGui.BeginTable("Items", 2, ImGuiTableFlags.Borders | ImGuiTableFlags.Resizable))
{
ImGui.TableSetupColumn("Count", ImGuiTableColumnFlags.NoHeaderWidth | ImGuiTableColumnFlags.WidthFixed);
ImGui.TableSetupColumn("Name");
ImGui.TableHeadersRow();
var i = 0;
foreach ((FGuid guid, Model model) in s.Renderer.Cache.Models)
{
ImGui.PushID(i);
ImGui.TableNextRow();
ImGui.TableNextColumn();
if (!model.Show)
ImGui.TableSetBgColor(ImGuiTableBgTarget.RowBg0, ImGui.GetColorU32(new Vector4(1, 0, 0, .5f)));
ImGui.Text(model.TransformsCount.ToString("D"));
ImGui.TableNextColumn();
model.IsSelected = s.Renderer.Settings.SelectedModel == guid;
if (ImGui.Selectable(model.Name, model.IsSelected, ImGuiSelectableFlags.SpanAllColumns))
{
s.Renderer.Settings.SelectModel(guid);
}
if (ImGui.BeginPopupContextItem())
{
s.Renderer.Settings.SelectModel(guid);
if (ImGui.Selectable("Deselect"))
s.Renderer.Settings.SelectModel(Guid.Empty);
if (ImGui.Selectable("Delete"))
s.Renderer.Cache.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.EndTable();
}
PopStyleCompact();
ImGui.End();
}
private void DrawDetails(Snooper s)
{
if (ImGui.Begin("Details"))
{
var guid = s.Renderer.Settings.SelectedModel;
if (s.Renderer.Cache.Models.TryGetValue(guid, out var model))
{
ImGui.Text($"Entity: ({model.Type}) {model.Name}");
ImGui.Text($"Guid: {guid.ToString(EGuidFormats.UniqueObjectGuid)}");
PushStyleCompact();
ImGui.Columns(4, "Actions", false);
// if (ImGui.Button("Go To")) s.Camera.Position = model.Transforms[s.Renderer.Settings.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.End();
}
}
private void DrawTransform(Snooper s)
{
if (ImGui.Begin("Transform"))
{
if (s.Renderer.Cache.Models.TryGetValue(s.Renderer.Settings.SelectedModel, out var model))
{
const int width = 100;
var speed = s.Camera.Speed / 100;
PushStyleCompact();
ImGui.PushID(0); ImGui.BeginDisabled(model.TransformsCount < 2);
ImGui.SetNextItemWidth(ImGui.GetContentRegionAvail().X);
ImGui.SliderInt("", ref model.SelectedInstance, 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[model.SelectedInstance].Position.X, speed, 0f, 0f, "%.2f m");
ImGui.SetNextItemWidth(width);
ImGui.DragFloat("Y", ref model.Transforms[model.SelectedInstance].Position.Y, speed, 0f, 0f, "%.2f m");
ImGui.SetNextItemWidth(width);
ImGui.DragFloat("Z", ref model.Transforms[model.SelectedInstance].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[model.SelectedInstance].Rotation.Pitch, .5f, 0f, 0f, "%.1f°");
ImGui.SetNextItemWidth(width);
ImGui.DragFloat("Y", ref model.Transforms[model.SelectedInstance].Rotation.Roll, .5f, 0f, 0f, "%.1f°");
ImGui.SetNextItemWidth(width);
ImGui.DragFloat("Z", ref model.Transforms[model.SelectedInstance].Rotation.Yaw, .5f, 0f, 0f, "%.1f°");
ImGui.PopID();
ImGui.TreePop();
}
if (ImGui.TreeNode("Scale"))
{
ImGui.PushID(3);
ImGui.SetNextItemWidth(width);
ImGui.DragFloat("X", ref model.Transforms[model.SelectedInstance].Scale.X, speed, 0f, 0f, "%.3f");
ImGui.SetNextItemWidth(width);
ImGui.DragFloat("Y", ref model.Transforms[model.SelectedInstance].Scale.Y, speed, 0f, 0f, "%.3f");
ImGui.SetNextItemWidth(width);
ImGui.DragFloat("Z", ref model.Transforms[model.SelectedInstance].Scale.Z, speed, 0f, 0f, "%.3f");
ImGui.PopID();
ImGui.TreePop();
}
model.UpdateMatrix(model.SelectedInstance);
PopStyleCompact();
}
ImGui.End();
}
}
private void Draw3DViewport(Snooper s)
{
const float lookSensitivity = 0.1f;
const ImGuiWindowFlags flags =
@ -131,43 +291,45 @@ public class SnimGui : IDisposable
largest.Y -= ImGui.GetScrollY();
var size = new Vector2(largest.X, largest.Y);
camera.AspectRatio = size.X / size.Y;
ImGui.ImageButton(framebuffer.GetPointer(), size, new Vector2(0, 1), new Vector2(1, 0), 0);
s.Camera.AspectRatio = size.X / size.Y;
ImGui.ImageButton(s.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;
// }
if (ImGui.IsItemHovered())
{
// if left button down while mouse is hover viewport
if (ImGui.IsMouseDown(ImGuiMouseButton.Left) && !_viewportFocus)
{
_viewportFocus = true;
s.CursorState = CursorState.Grabbed;
}
}
// 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
// if left mouse button was pressed while hovering the viewport
// move camera until left 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;
// }
var io = ImGui.GetIO();
if (ImGui.IsMouseDragging(ImGuiMouseButton.Left, lookSensitivity) && _viewportFocus)
{
var delta = io.MouseDelta * lookSensitivity;
s.Camera.ModifyDirection(delta.X, delta.Y);
}
// if left button up and mouse was in viewport
// if (ImGui.IsMouseReleased(ImGuiMouseButton.Right) && _viewportFocus)
// {
// _viewportFocus = false;
// mouse.Cursor.CursorMode = CursorMode.Normal;
// }
if (ImGui.IsMouseReleased(ImGuiMouseButton.Left) && _viewportFocus)
{
_viewportFocus = false;
s.CursorState = CursorState.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);
const float padding = 7.5f;
float framerate = ImGui.GetIO().Framerate;
var text = $"FPS: {framerate:0} ({1000.0f / framerate:0.##} ms)";
ImGui.SetCursorPos(size with { X = padding });
ImGui.Text(text);
ImGui.End();
}
@ -249,8 +411,4 @@ public class SnimGui : IDisposable
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(GameWindow wnd, float deltaSeconds) => _controller.Update(wnd, deltaSeconds);
public void WindowResized(int width, int height) => _controller.WindowResized(width, height);
public void Dispose() => _controller.Dispose();
}

View File

@ -1,7 +1,6 @@
using System.Threading;
using System.Windows;
using CUE4Parse.UE4.Assets.Exports;
using CUE4Parse.UE4.Assets.Exports.Material;
using OpenTK.Graphics.OpenGL4;
using OpenTK.Mathematics;
using OpenTK.Windowing.Common;
@ -12,49 +11,50 @@ namespace FModel.Views.Snooper;
public class Snooper : GameWindow
{
private FramebufferObject _framebuffer;
public Camera Camera;
public FramebufferObject Framebuffer;
public readonly Renderer Renderer;
private readonly Skybox _skybox;
private readonly Grid _grid;
private readonly Renderer _renderer;
private readonly SnimGui _gui;
private Camera _camera;
private float _previousSpeed;
private bool _init;
public Snooper(GameWindowSettings gwSettings, NativeWindowSettings nwSettings) : base(gwSettings, nwSettings)
{
_framebuffer = new FramebufferObject(Size);
Framebuffer = new FramebufferObject(Size);
Renderer = new Renderer();
_skybox = new Skybox();
_grid = new Grid();
_renderer = new Renderer();
_gui = new SnimGui(ClientSize.X, ClientSize.Y);
_init = false;
}
public void SwapMaterial(UMaterialInstance mi) => _renderer.Swap(mi);
public void LoadExport(CancellationToken cancellationToken, UObject export)
{
var newCamera = _renderer.Load(cancellationToken, export);
var newCamera = Renderer.Load(cancellationToken, export);
if (newCamera == null || !(newCamera.Speed > _previousSpeed)) return;
_camera = newCamera;
_previousSpeed = _camera.Speed;
Camera = newCamera;
_previousSpeed = Camera.Speed;
}
private unsafe void WindowShouldClose(bool value, bool clear)
{
if (clear)
{
_renderer.Cache.DisposeModels();
_renderer.Cache.ClearModels();
_renderer.Settings.Reset();
Renderer.Cache.DisposeModels();
Renderer.Cache.Models.Clear();
Renderer.Settings.Reset();
_previousSpeed = 0f;
}
GLFW.SetWindowShouldClose(WindowPtr, value); // start / stop game loop
// CursorState = value ? CursorState.Normal : CursorState.Grabbed;
IsVisible = !value;
}
@ -71,7 +71,7 @@ public class Snooper : GameWindow
{
if (_init)
{
_renderer.Cache.Setup();
Renderer.Cache.Setup();
return;
}
@ -85,10 +85,10 @@ public class Snooper : GameWindow
GL.StencilOp(StencilOp.Keep, StencilOp.Replace, StencilOp.Replace);
GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
_framebuffer.Setup();
Framebuffer.Setup();
_skybox.Setup();
_grid.Setup();
_renderer.Setup();
Renderer.Setup();
_init = true;
}
@ -98,20 +98,20 @@ public class Snooper : GameWindow
if (!IsVisible)
return;
_gui.Update(this, (float)args.Time);
_gui.Controller.Update(this, (float)args.Time);
ClearWhatHasBeenDrawn();
_framebuffer.Bind();
Framebuffer.Bind();
ClearWhatHasBeenDrawn();
_skybox.Render(_camera);
_grid.Render(_camera);
_renderer.Render(_camera);
_skybox.Render(Camera);
_grid.Render(Camera);
Renderer.Render(Camera);
_framebuffer.BindMsaa();
_framebuffer.Bind(0);
Framebuffer.BindMsaa();
Framebuffer.Bind(0);
_gui.Render(Size, _framebuffer, _camera);
_gui.Render(this);
SwapBuffers();
}
@ -122,15 +122,22 @@ public class Snooper : GameWindow
GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill);
}
protected override void OnMouseMove(MouseMoveEventArgs e)
protected override void OnMouseWheel(MouseWheelEventArgs e)
{
base.OnMouseMove(e);
base.OnMouseWheel(e);
if (!IsVisible)
return;
// const float lookSensitivity = 0.1f;
// var delta = e.Delta * lookSensitivity;
// _camera.ModifyDirection(delta.X, delta.Y);
_gui.Controller.MouseScroll(e.Offset);
}
protected override void OnTextInput(TextInputEventArgs e)
{
base.OnTextInput(e);
if (!IsVisible)
return;
_gui.Controller.PressChar((char) e.Unicode);
}
protected override void OnUpdateFrame(FrameEventArgs e)
@ -140,23 +147,23 @@ public class Snooper : GameWindow
return;
var multiplier = KeyboardState.IsKeyDown(Keys.LeftShift) ? 2f : 1f;
var moveSpeed = _camera.Speed * multiplier * (float) e.Time;
var moveSpeed = Camera.Speed * multiplier * (float) e.Time;
if (KeyboardState.IsKeyDown(Keys.W))
_camera.Position += moveSpeed * _camera.Direction;
Camera.Position += moveSpeed * Camera.Direction;
if (KeyboardState.IsKeyDown(Keys.S))
_camera.Position -= moveSpeed * _camera.Direction;
Camera.Position -= moveSpeed * Camera.Direction;
if (KeyboardState.IsKeyDown(Keys.A))
_camera.Position -= Vector3.Normalize(Vector3.Cross(_camera.Direction, _camera.Up)) * moveSpeed;
Camera.Position -= Vector3.Normalize(Vector3.Cross(Camera.Direction, Camera.Up)) * moveSpeed;
if (KeyboardState.IsKeyDown(Keys.D))
_camera.Position += Vector3.Normalize(Vector3.Cross(_camera.Direction, _camera.Up)) * moveSpeed;
Camera.Position += Vector3.Normalize(Vector3.Cross(Camera.Direction, Camera.Up)) * moveSpeed;
if (KeyboardState.IsKeyDown(Keys.E))
_camera.Position += moveSpeed * _camera.Up;
Camera.Position += moveSpeed * Camera.Up;
if (KeyboardState.IsKeyDown(Keys.Q))
_camera.Position -= moveSpeed * _camera.Up;
Camera.Position -= moveSpeed * Camera.Up;
if (KeyboardState.IsKeyDown(Keys.X))
_camera.ModifyZoom(-.5f);
Camera.ModifyZoom(-.5f);
if (KeyboardState.IsKeyDown(Keys.C))
_camera.ModifyZoom(+.5f);
Camera.ModifyZoom(+.5f);
if (KeyboardState.IsKeyPressed(Keys.R))
WindowShouldClose(true, false);
@ -170,10 +177,10 @@ public class Snooper : GameWindow
GL.Viewport(0, 0, Size.X, Size.Y);
_framebuffer = new FramebufferObject(Size);
_framebuffer.Setup();
_camera.AspectRatio = Size.X / (float)Size.Y;
_gui.WindowResized(ClientSize.X, ClientSize.Y);
Framebuffer = new FramebufferObject(Size);
Framebuffer.Setup();
Camera.AspectRatio = Size.X / (float)Size.Y;
_gui.Controller.WindowResized(ClientSize.X, ClientSize.Y);
}
protected override void Dispose(bool disposing)
@ -182,7 +189,7 @@ public class Snooper : GameWindow
_skybox?.Dispose();
_grid?.Dispose();
_renderer?.Dispose();
_gui?.Dispose();
Renderer?.Dispose();
_gui?.Controller.Dispose();
}
}