diff --git a/FModel/Extensions/ImGuiExtensions.cs b/FModel/Extensions/ImGuiExtensions.cs
index 88f749d6..0b293077 100644
--- a/FModel/Extensions/ImGuiExtensions.cs
+++ b/FModel/Extensions/ImGuiExtensions.cs
@@ -8,6 +8,29 @@ public static class ImGuiExtensions
public const float PADDING = 5.0f;
public static ImGuiStylePtr STYLE = ImGui.GetStyle();
+ public static void DrawNavbar()
+ {
+ if (ImGui.BeginMainMenuBar())
+ {
+ 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();
+ }
+ }
+
public static void DrawFPS()
{
const ImGuiWindowFlags flags =
diff --git a/FModel/FModel.csproj b/FModel/FModel.csproj
index c11e65eb..fd4883d0 100644
--- a/FModel/FModel.csproj
+++ b/FModel/FModel.csproj
@@ -137,7 +137,7 @@
-
+
diff --git a/FModel/MainWindow.xaml.cs b/FModel/MainWindow.xaml.cs
index 563c3b27..cb5099c6 100644
--- a/FModel/MainWindow.xaml.cs
+++ b/FModel/MainWindow.xaml.cs
@@ -79,7 +79,7 @@ public partial class MainWindow
#if DEBUG
await _threadWorkerView.Begin(_ =>
_applicationView.CUE4Parse.Extract(
- "FortniteGame/Content/Environments/Props/Winter/Meshes/SM_ChristmasTree_Llama.uasset"));
+ "/Game/Characters/Player/Female/Medium/Bodies/F_MED_Neon_Cat_Tech/Meshes/F_MED_Neon_Cat_Tech.uasset"));
#endif
}
diff --git a/FModel/Resources/shader.frag b/FModel/Resources/shader.frag
index be50fdcf..1fa18d57 100644
--- a/FModel/Resources/shader.frag
+++ b/FModel/Resources/shader.frag
@@ -5,12 +5,16 @@ in vec3 fNormal;
in vec2 fTexCoords;
struct Material {
- sampler2D diffuse;
- sampler2D normal;
- sampler2D specular;
- sampler2D metallic;
- sampler2D emission;
+ sampler2D diffuseMap;
+ sampler2D normalMap;
+ sampler2D specularMap;
+ sampler2D metallicMap;
+ sampler2D emissionMap;
+ bool swap;
+
+ vec4 diffuseColor;
+ vec4 emissionColor;
float shininess;
};
@@ -29,24 +33,34 @@ out vec4 FragColor;
void main()
{
+ if (material.swap)
+ {
+ FragColor = material.diffuseColor;
+ return;
+ }
+
// ambient
- vec3 ambient = light.ambient * vec3(texture(material.diffuse, fTexCoords));
+ vec3 ambient = light.ambient * vec3(texture(material.diffuseMap, fTexCoords));
// diffuse
- vec3 norm = texture(material.normal, fTexCoords).rgb;
+ vec3 norm = texture(material.normalMap, fTexCoords).rgb;
norm = normalize(norm * 2.0 - 1.0);
vec3 lightDir = normalize(light.position - fPos);
float diff = max(dot(norm, lightDir), 0.0f);
- vec3 diffuseMap = vec3(texture(material.diffuse, fTexCoords));
+ vec3 diffuseMap = vec3(texture(material.diffuseMap, fTexCoords));
vec3 diffuse = light.diffuse * diff * diffuseMap;
// specular
vec3 viewDir = normalize(viewPos - fPos);
vec3 reflectDir = reflect(-lightDir, norm);
float spec = pow(max(dot(viewDir, reflectDir), 0.0f), material.shininess);
- vec3 specularMap = vec3(texture(material.specular, fTexCoords));
+ vec3 specularMap = vec3(texture(material.specularMap, fTexCoords));
vec3 specular = light.specular * spec * specularMap;
- vec3 result = ambient + diffuse + specular;
+ // emission
+ vec3 emissionMap = vec3(texture(material.emissionMap, fTexCoords));
+ vec3 emission = material.emissionColor.rgb * emissionMap;
+
+ vec3 result = ambient + diffuse + specular + emission;
FragColor = vec4(result, 1.0);
}
diff --git a/FModel/ViewModels/CUE4ParseViewModel.cs b/FModel/ViewModels/CUE4ParseViewModel.cs
index 4b9ac9a6..e413dc4e 100644
--- a/FModel/ViewModels/CUE4ParseViewModel.cs
+++ b/FModel/ViewModels/CUE4ParseViewModel.cs
@@ -753,8 +753,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))):
{
- var snooper = new Snooper(export);
- snooper.Run();
+ var snooper = new Snooper();
+ snooper.Run(export);
return true;
}
case UMaterialInstance m when ModelIsOverwritingMaterial:
diff --git a/FModel/Views/Snooper/Model.cs b/FModel/Views/Snooper/Model.cs
index ffa32773..8a032683 100644
--- a/FModel/Views/Snooper/Model.cs
+++ b/FModel/Views/Snooper/Model.cs
@@ -20,8 +20,6 @@ public class Model : IDisposable
private const uint _faceSize = 3; // just so we don't have to do .Length
private readonly uint[] _facesIndex = { 1, 0, 2 };
- private Shader _shader;
-
public readonly string Name;
public readonly uint[] Indices;
public readonly float[] Vertices;
@@ -70,8 +68,6 @@ public class Model : IDisposable
_handle = _gl.CreateProgram();
- _shader = new Shader(_gl);
-
_ebo = new BufferObject(_gl, Indices, BufferTargetARB.ElementArrayBuffer);
_vbo = new BufferObject(_gl, Vertices, BufferTargetARB.ArrayBuffer);
_vao = new VertexArrayObject(_gl, _vbo, _ebo);
@@ -92,36 +88,13 @@ public class Model : IDisposable
_vao.Bind();
- _shader.Use();
-
- _shader.SetUniform("uModel", Matrix4x4.Identity);
- _shader.SetUniform("uView", camera.GetViewMatrix());
- _shader.SetUniform("uProjection", camera.GetProjectionMatrix());
- _shader.SetUniform("viewPos", camera.Position);
-
- _shader.SetUniform("material.diffuse", 0);
- _shader.SetUniform("material.normal", 1);
- _shader.SetUniform("material.specular", 2);
- // _shader.SetUniform("material.metallic", 3);
- // _shader.SetUniform("material.emission", 4);
- _shader.SetUniform("material.shininess", 32f);
-
- var lightColor = Vector3.One;
- var diffuseColor = lightColor * new Vector3(0.5f);
- var ambientColor = diffuseColor * new Vector3(0.2f);
-
- _shader.SetUniform("light.ambient", ambientColor);
- _shader.SetUniform("light.diffuse", diffuseColor); // darkened
- _shader.SetUniform("light.specular", Vector3.One);
- _shader.SetUniform("light.position", camera.Position);
-
ImGui.BeginTable("Sections", 2, ImGuiTableFlags.RowBg);
ImGui.TableSetupColumn("Index", ImGuiTableColumnFlags.WidthFixed);
ImGui.TableSetupColumn("Material", ImGuiTableColumnFlags.WidthStretch);
ImGui.TableHeadersRow();
for (int section = 0; section < Sections.Length; section++)
{
- Sections[section].Bind(Indices.Length);
+ Sections[section].Bind(camera, Indices.Length);
_gl.DrawArrays(PrimitiveType.Triangles, Sections[section].FirstFaceIndex, Sections[section].FacesCount);
}
ImGui.EndTable();
@@ -134,7 +107,6 @@ public class Model : IDisposable
_ebo.Dispose();
_vbo.Dispose();
_vao.Dispose();
- _shader.Dispose();
for (int section = 0; section < Sections.Length; section++)
{
Sections[section].Dispose();
diff --git a/FModel/Views/Snooper/Section.cs b/FModel/Views/Snooper/Section.cs
index 57991d88..a1097bf7 100644
--- a/FModel/Views/Snooper/Section.cs
+++ b/FModel/Views/Snooper/Section.cs
@@ -1,4 +1,5 @@
using System;
+using System.Numerics;
using CUE4Parse.UE4.Assets.Exports.Material;
using CUE4Parse.UE4.Assets.Exports.Texture;
using CUE4Parse_Conversion.Meshes.PSK;
@@ -20,6 +21,11 @@ public class Section : IDisposable
// private Texture _metallicMap;
private Texture _emissionMap;
+ private Vector4 _diffuseColor;
+ private Vector4 _emissionColor;
+
+ private Shader _shader;
+
public readonly string Name;
public readonly int Index;
public readonly uint FacesCount;
@@ -46,8 +52,20 @@ public class Section : IDisposable
_handle = _gl.CreateProgram();
+ _shader = new Shader(_gl);
+
+ if (Parameters.IsNull)
+ {
+ _diffuseColor = new Vector4(1, 0, 0, 1);
+ return;
+ }
+
var platform = UserSettings.Default.OverridedPlatform;
- if (Parameters.Diffuse is UTexture2D { IsVirtual: false } diffuse)
+ if (!Parameters.HasTopDiffuseTexture && Parameters.DiffuseColor is { A: > 0 } diffuseColor)
+ {
+ _diffuseColor = new Vector4(diffuseColor.R, diffuseColor.G, diffuseColor.B, diffuseColor.A);
+ }
+ else if (Parameters.Diffuse is UTexture2D { IsVirtual: false } diffuse)
{
var mip = diffuse.GetFirstMip();
TextureDecoder.DecodeTexture(mip, diffuse.Format, diffuse.isNormalMap, platform, out var data, out _);
@@ -75,10 +93,11 @@ public class Section : IDisposable
var mip = emissive.GetFirstMip();
TextureDecoder.DecodeTexture(mip, emissive.Format, emissive.isNormalMap, platform, out var data, out _);
_emissionMap = new Texture(_gl, data, (uint) mip.SizeX, (uint) mip.SizeY);
+ _emissionColor = new Vector4(emissiveColor.R, emissiveColor.G, emissiveColor.B, emissiveColor.A);
}
}
- public void Bind(float indices)
+ public void Bind(Camera camera, float indices)
{
ImGui.TableNextRow();
@@ -97,15 +116,42 @@ public class Section : IDisposable
ImGui.EndTooltip();
}
- if (Parameters.IsNull) return;
+ _shader.Use();
+
+ _shader.SetUniform("uModel", Matrix4x4.Identity);
+ _shader.SetUniform("uView", camera.GetViewMatrix());
+ _shader.SetUniform("uProjection", camera.GetProjectionMatrix());
+ _shader.SetUniform("viewPos", camera.Position);
+
+ _shader.SetUniform("material.diffuseMap", 0);
+ _shader.SetUniform("material.normalMap", 1);
+ _shader.SetUniform("material.specularMap", 2);
+ // _shader.SetUniform("material.metallicMap", 3);
+ _shader.SetUniform("material.emissionMap", 4);
+ _shader.SetUniform("material.shininess", 32f);
+
+ _shader.SetUniform("material.swap", Convert.ToUInt32(_diffuseColor != Vector4.Zero));
+ _shader.SetUniform("material.diffuseColor", _diffuseColor);
+ _shader.SetUniform("material.emissionColor", _emissionColor);
+
_diffuseMap?.Bind(TextureUnit.Texture0);
_normalMap?.Bind(TextureUnit.Texture1);
_specularMap?.Bind(TextureUnit.Texture2);
_emissionMap?.Bind(TextureUnit.Texture4);
+
+ var lightColor = Vector3.One;
+ var diffuseColor = lightColor * new Vector3(0.5f);
+ var ambientColor = diffuseColor * new Vector3(0.2f);
+
+ _shader.SetUniform("light.ambient", ambientColor);
+ _shader.SetUniform("light.diffuse", diffuseColor); // darkened
+ _shader.SetUniform("light.specular", Vector3.One);
+ _shader.SetUniform("light.position", camera.Position);
}
public void Dispose()
{
+ _shader.Dispose();
_diffuseMap?.Dispose();
_normalMap?.Dispose();
_specularMap?.Dispose();
diff --git a/FModel/Views/Snooper/Shader.cs b/FModel/Views/Snooper/Shader.cs
index 879b9eec..5ac485a2 100644
--- a/FModel/Views/Snooper/Shader.cs
+++ b/FModel/Views/Snooper/Shader.cs
@@ -61,6 +61,16 @@ public class Shader : IDisposable
_gl.UniformMatrix4(location, 1, false, (float*) &value);
}
+ public void SetUniform(string name, uint value)
+ {
+ int location = _gl.GetUniformLocation(_handle, name);
+ if (location == -1)
+ {
+ throw new Exception($"{name} uniform not found on shader.");
+ }
+ _gl.Uniform1(location, value);
+ }
+
public void SetUniform(string name, float value)
{
int location = _gl.GetUniformLocation(_handle, name);
@@ -81,6 +91,16 @@ public class Shader : IDisposable
_gl.Uniform3(location, value.X, value.Y, value.Z);
}
+ public void SetUniform(string name, Vector4 value)
+ {
+ int location = _gl.GetUniformLocation(_handle, name);
+ if (location == -1)
+ {
+ throw new Exception($"{name} uniform not found on shader.");
+ }
+ _gl.Uniform4(location, value.X, value.Y, value.Z, value.W);
+ }
+
public void Dispose()
{
_gl.DeleteProgram(_handle);
diff --git a/FModel/Views/Snooper/Snooper.cs b/FModel/Views/Snooper/Snooper.cs
index 6c4bd389..f9646acb 100644
--- a/FModel/Views/Snooper/Snooper.cs
+++ b/FModel/Views/Snooper/Snooper.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.Numerics;
using System.Runtime.InteropServices;
using System.Windows;
@@ -32,23 +33,23 @@ public class Snooper
private Vector2 _previousMousePosition;
private RawImage _icon;
- private Skybox _skybox;
- private Grid _grid;
- private Model[] _models;
+ private readonly Skybox _skybox;
+ private readonly Grid _grid;
+ private readonly List _models;
- public int Width { get; }
- public int Height { get; }
+ private readonly int _width;
+ private readonly int _height;
- public Snooper(UObject export)
+ public Snooper()
{
const double ratio = .7;
var x = SystemParameters.MaximizedPrimaryScreenWidth;
var y = SystemParameters.MaximizedPrimaryScreenHeight;
- Width = Convert.ToInt32(x * ratio);
- Height = Convert.ToInt32(y * ratio);
+ _width = Convert.ToInt32(x * ratio);
+ _height = Convert.ToInt32(y * ratio);
var options = WindowOptions.Default;
- options.Size = new Vector2D(Width, Height);
+ options.Size = new Vector2D(_width, _height);
options.WindowBorder = WindowBorder.Hidden;
options.Title = "Snooper";
options.Samples = 4;
@@ -77,28 +78,29 @@ public class Snooper
_skybox = new Skybox();
_grid = new Grid();
- _models = new Model[1];
+ _models = new List();
+ }
+
+ public void Run(UObject export)
+ {
switch (export)
{
case UStaticMesh st when st.TryConvert(out var mesh):
{
- _models[0] = new Model(st.Name, mesh.LODs[0], mesh.LODs[0].Verts);
+ _models.Add(new Model(st.Name, mesh.LODs[0], mesh.LODs[0].Verts));
SetupCamera(mesh.BoundingBox *= Constants.SCALE_DOWN_RATIO);
break;
}
case USkeletalMesh sk when sk.TryConvert(out var mesh):
{
- _models[0] = new Model(sk.Name, mesh.LODs[0], mesh.LODs[0].Verts);
+ _models.Add(new Model(sk.Name, mesh.LODs[0], mesh.LODs[0].Verts));
SetupCamera(mesh.BoundingBox *= Constants.SCALE_DOWN_RATIO);
break;
}
default:
throw new ArgumentOutOfRangeException(nameof(export));
}
- }
- public void Run()
- {
_window.Run();
}
@@ -132,6 +134,8 @@ public class Snooper
_controller = new ImGuiController(_gl, _window, input);
+ ImGuiExtensions.Theme();
+
_skybox.Setup(_gl);
_grid.Setup(_gl);
@@ -156,27 +160,7 @@ public class Snooper
_skybox.Bind(_camera);
_grid.Bind(_camera);
- ImGuiExtensions.Theme();
-
- if (ImGui.BeginMainMenuBar())
- {
- 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(ImGuiExtensions.STYLE.Colors[(int) ImGuiCol.TextDisabled], text);
-
- ImGui.EndMainMenuBar();
- }
+ ImGuiExtensions.DrawNavbar();
ImGui.Begin("ImGui.NET", ImGuiWindowFlags.NoTitleBar | ImGuiWindowFlags.NoBringToFrontOnFocus | ImGuiWindowFlags.NoSavedSettings);
foreach (var model in _models)
@@ -263,6 +247,7 @@ public class Snooper
{
model.Dispose();
}
+ _models.Clear();
_controller.Dispose();
_window.Dispose();
_gl.Dispose();