diff --git a/CUE4Parse b/CUE4Parse index cebbff90..35f6d437 160000 --- a/CUE4Parse +++ b/CUE4Parse @@ -1 +1 @@ -Subproject commit cebbff9035b292e81493f8b94c19d39394be2618 +Subproject commit 35f6d437eb0f03855d30265a6214794810868e6a diff --git a/FModel/FModel.csproj b/FModel/FModel.csproj index c311a842..ef487add 100644 --- a/FModel/FModel.csproj +++ b/FModel/FModel.csproj @@ -101,8 +101,8 @@ - - + + @@ -120,8 +120,8 @@ - - + + @@ -132,7 +132,6 @@ - @@ -238,4 +237,10 @@ + + + Always + + + diff --git a/FModel/Resources/imgui.frag b/FModel/Resources/imgui.frag deleted file mode 100644 index 5a705b23..00000000 --- a/FModel/Resources/imgui.frag +++ /dev/null @@ -1,13 +0,0 @@ -#version 330 - -layout (location = 0) out vec4 Out_Color; - -in vec2 Frag_UV; -in vec4 Frag_Color; - -uniform sampler2D Texture; - -void main() -{ - Out_Color = Frag_Color * texture(Texture, Frag_UV.st); -} diff --git a/FModel/Resources/imgui.vert b/FModel/Resources/imgui.vert deleted file mode 100644 index 284ed1a5..00000000 --- a/FModel/Resources/imgui.vert +++ /dev/null @@ -1,17 +0,0 @@ -#version 330 - -layout (location = 0) in vec2 Position; -layout (location = 1) in vec2 UV; -layout (location = 2) in vec4 Color; - -uniform mat4 ProjMtx; - -out vec2 Frag_UV; -out vec4 Frag_Color; - -void main() -{ - Frag_UV = UV; - Frag_Color = Color; - gl_Position = ProjMtx * vec4(Position.xy,0,1); -} diff --git a/FModel/Resources/outline.frag b/FModel/Resources/outline.frag new file mode 100644 index 00000000..26817aa5 --- /dev/null +++ b/FModel/Resources/outline.frag @@ -0,0 +1,8 @@ +#version 330 + +out vec4 FragColor; + +void main() +{ + FragColor = vec4(0.929, 0.588, 0.196, 0.2); +} diff --git a/FModel/Resources/outline.vert b/FModel/Resources/outline.vert new file mode 100644 index 00000000..0d2d8acc --- /dev/null +++ b/FModel/Resources/outline.vert @@ -0,0 +1,15 @@ +#version 330 core + +layout (location = 0) in vec3 vPos; +layout (location = 1) in vec3 vNormal; +layout (location = 6) in mat4 vInstanceMatrix; + +uniform mat4 uView; +uniform mat4 uProjection; + +void main() +{ + float scaleFactor = 0.005; + vec3 scaleVertex = vPos + vNormal * scaleFactor; + gl_Position = uProjection * uView * vInstanceMatrix * vec4(scaleVertex, 1.0); +} diff --git a/FModel/ViewModels/ApplicationViewModel.cs b/FModel/ViewModels/ApplicationViewModel.cs index 9564f56c..7438c6a6 100644 --- a/FModel/ViewModels/ApplicationViewModel.cs +++ b/FModel/ViewModels/ApplicationViewModel.cs @@ -72,7 +72,6 @@ public class ApplicationViewModel : ViewModel public AesManagerViewModel AesManager { get; } public AudioPlayerViewModel AudioPlayer { get; } public MapViewerViewModel MapViewer { get; } - public ModelViewerViewModel ModelViewer { get; } private OodleCompressor _oodle; public ApplicationViewModel() @@ -94,7 +93,6 @@ public class ApplicationViewModel : ViewModel AesManager = new AesManagerViewModel(CUE4Parse); MapViewer = new MapViewerViewModel(CUE4Parse); AudioPlayer = new AudioPlayerViewModel(); - ModelViewer = new ModelViewerViewModel(CUE4Parse.Game); Status = EStatusKind.Ready; } diff --git a/FModel/ViewModels/CUE4ParseViewModel.cs b/FModel/ViewModels/CUE4ParseViewModel.cs index 1e2dc2f9..7586ab9f 100644 --- a/FModel/ViewModels/CUE4ParseViewModel.cs +++ b/FModel/ViewModels/CUE4ParseViewModel.cs @@ -763,12 +763,7 @@ public class CUE4ParseViewModel : ViewModel } case UMaterialInstance m when ModelIsOverwritingMaterial: { - Application.Current.Dispatcher.Invoke(delegate - { - var modelViewer = Helper.GetWindow("Model Viewer", () => new ModelViewer().Show()); - modelViewer.Overwrite(m); - }); - return true; + throw new NotImplementedException(); } case UStaticMesh when UserSettings.Default.SaveStaticMeshes: case USkeletalMesh when UserSettings.Default.SaveSkeletalMeshes: diff --git a/FModel/ViewModels/ModelViewerViewModel.cs b/FModel/ViewModels/ModelViewerViewModel.cs deleted file mode 100644 index 34018f77..00000000 --- a/FModel/ViewModels/ModelViewerViewModel.cs +++ /dev/null @@ -1,767 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.ComponentModel; -using System.IO; -using System.Linq; -using System.Numerics; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Data; -using System.Windows.Media.Media3D; -using CUE4Parse_Conversion; -using CUE4Parse.UE4.Assets; -using CUE4Parse.UE4.Assets.Exports; -using CUE4Parse.UE4.Assets.Exports.Material; -using CUE4Parse.UE4.Assets.Exports.SkeletalMesh; -using CUE4Parse.UE4.Assets.Exports.StaticMesh; -using CUE4Parse.UE4.Assets.Exports.Texture; -using CUE4Parse.UE4.Objects.Core.Math; -using CUE4Parse.Utils; -using CUE4Parse_Conversion.Materials; -using CUE4Parse_Conversion.Meshes; -using CUE4Parse_Conversion.Meshes.glTF; -using CUE4Parse_Conversion.Meshes.PSK; -using CUE4Parse_Conversion.Textures; -using FModel.Framework; -using FModel.Services; -using FModel.Settings; -using FModel.Views.Resources.Controls; -using HelixToolkit.SharpDX.Core; -using HelixToolkit.Wpf.SharpDX; -using Ookii.Dialogs.Wpf; -using Serilog; -using SharpDX; -using SharpGLTF.Geometry; -using SharpGLTF.Geometry.VertexTypes; -using SharpGLTF.Scenes; -using SharpGLTF.Schema2; -using SharpGLTF.Transforms; -using SkiaSharp; -using Camera = HelixToolkit.Wpf.SharpDX.Camera; -using Exporter = CUE4Parse_Conversion.Exporter; -using Geometry3D = HelixToolkit.SharpDX.Core.Geometry3D; -using PerspectiveCamera = HelixToolkit.Wpf.SharpDX.PerspectiveCamera; -using Vector2 = SharpDX.Vector2; -using Vector3 = SharpDX.Vector3; -using VERTEX = SharpGLTF.Geometry.VertexTypes.VertexPositionNormalTangent; - -namespace FModel.ViewModels; - -public class ModelViewerViewModel : ViewModel -{ - private ThreadWorkerViewModel _threadWorkerView => ApplicationService.ThreadWorkerView; - - private EffectsManager _effectManager; - public EffectsManager EffectManager - { - get => _effectManager; - set => SetProperty(ref _effectManager, value); - } - - private Camera _cam; - public Camera Cam - { - get => _cam; - set => SetProperty(ref _cam, value); - } - - private ModelAndCam _selectedModel; // selected mesh - public ModelAndCam SelectedModel - { - get => _selectedModel; - set => SetProperty(ref _selectedModel, value); - } - - private readonly ObservableCollection _loadedModels; // mesh list - public ICollectionView LoadedModelsView { get; } - - private bool _appendMode; - public bool AppendMode - { - get => _appendMode; - set => SetProperty(ref _appendMode, value); - } - - public bool CanAppend => SelectedModel != null; - - public TextureModel HDRi { get; private set; } - - private readonly FGame _game; - private readonly int[] _facesIndex = { 1, 0, 2 }; - - public ModelViewerViewModel(FGame game) - { - _game = game; - _loadedModels = new ObservableCollection(); - - EffectManager = new DefaultEffectsManager(); - LoadedModelsView = new ListCollectionView(_loadedModels); - Cam = new PerspectiveCamera { NearPlaneDistance = 0.1, FarPlaneDistance = double.PositiveInfinity, FieldOfView = 90 }; - LoadHDRi(); - } - - private void LoadHDRi() - { - var cubeMap = Application.GetResourceStream(new Uri("/FModel;component/Resources/approaching_storm_cubemap.dds", UriKind.Relative)); - HDRi = TextureModel.Create(cubeMap?.Stream); - } - - public void LoadExport(UObject export) - { -#if DEBUG - LoadHDRi(); -#endif - - ModelAndCam p; - if (AppendMode && CanAppend) - { - p = SelectedModel; - _loadedModels.Add(new ModelAndCam(export) { IsVisible = false }); - } - else - { - p = new ModelAndCam(export); - _loadedModels.Add(p); - } - - switch (export) - { - case UStaticMesh st: - LoadStaticMesh(st, p); - break; - case USkeletalMesh sk: - LoadSkeletalMesh(sk, p); - break; - case UMaterialInstance mi: - LoadMaterialInstance(mi, p); - break; - default: - throw new ArgumentOutOfRangeException(nameof(export)); - } - - if (AppendMode && CanAppend) return; - SelectedModel = p; - Cam.UpDirection = new Vector3D(0, 1, 0); - Cam.Position = p.Position; - Cam.LookDirection = p.LookDirection; - } - - #region PUBLIC METHODS - - public void RenderingToggle() - { - if (SelectedModel == null) return; - SelectedModel.RenderingToggle = !SelectedModel.RenderingToggle; - } - - public void WirefreameToggle() - { - if (SelectedModel == null) return; - SelectedModel.WireframeToggle = !SelectedModel.WireframeToggle; - } - - public void MaterialColorToggle() - { - if (SelectedModel == null) return; - SelectedModel.ShowMaterialColor = !SelectedModel.ShowMaterialColor; - } - - public void DiffuseOnlyToggle() - { - if (SelectedModel == null) return; - SelectedModel.DiffuseOnlyToggle = !SelectedModel.DiffuseOnlyToggle; - } - - public void FocusOnSelectedMesh() - { - Cam.AnimateTo(SelectedModel.Position, SelectedModel.LookDirection, new Vector3D(0, 1, 0), 500); - } - - public async Task SaveLoadedModels() - { - if (_loadedModels.Count < 1) return; - - var folderBrowser = new VistaFolderBrowserDialog { ShowNewFolderButton = true }; - if (folderBrowser.ShowDialog() == false) return; - - await _threadWorkerView.Begin(_ => - { - var exportOptions = new ExporterOptions - { - TextureFormat = UserSettings.Default.TextureExportFormat, - LodFormat = UserSettings.Default.LodExportFormat, - MeshFormat = UserSettings.Default.MeshExportFormat, - Platform = UserSettings.Default.OverridedPlatform, - ExportMorphTargets = UserSettings.Default.SaveMorphTargets - }; - foreach (var model in _loadedModels) - { - var toSave = new Exporter(model.Export, exportOptions); - if (toSave.TryWriteToDir(new DirectoryInfo(folderBrowser.SelectedPath), out var savedFileName)) - { - Log.Information("Successfully saved {FileName}", savedFileName); - FLogger.AppendInformation(); - FLogger.AppendText($"Successfully saved {savedFileName}", Constants.WHITE, true); - } - else - { - Log.Error("{FileName} could not be saved", savedFileName); - FLogger.AppendError(); - FLogger.AppendText($"Could not save '{savedFileName}'", Constants.WHITE, true); - } - } - }); - } - - public void SaveAsScene() - { - if (_loadedModels.Count < 1) return; - - var fileBrowser = new VistaSaveFileDialog - { - Title = "Save Loaded Models As...", - DefaultExt = ".glb", - Filter = "glTF Binary File (*.glb)|*.glb|glTF ASCII File (*.gltf)|*.gltf|All Files(*.*)|*.*", - AddExtension = true, - OverwritePrompt = true, - CheckPathExists = true - }; - - if (fileBrowser.ShowDialog() == false || string.IsNullOrEmpty(fileBrowser.FileName)) return; - - var sceneBuilder = new SceneBuilder(); - var materialExports = new List(); - foreach (var model in _loadedModels) - { - switch (model.Export) - { - case UStaticMesh sm: - { - var mesh = new MeshBuilder(sm.Name); - if (sm.TryConvert(out var convertedMesh) && convertedMesh.LODs.Count > 0) - { - var lod = convertedMesh.LODs.First(); - for (var i = 0; i < lod.Sections.Value.Length; i++) - { - Gltf.ExportStaticMeshSections(i, lod, lod.Sections.Value[i], materialExports, mesh); - } - - sceneBuilder.AddRigidMesh(mesh, AffineTransform.Identity); - } - - break; - } - case USkeletalMesh sk: - { - var mesh = new MeshBuilder(sk.Name); - - if (sk.TryConvert(out var convertedMesh) && convertedMesh.LODs.Count > 0) - { - var lod = convertedMesh.LODs.First(); - for (var i = 0; i < lod.Sections.Value.Length; i++) - { - Gltf.ExportSkelMeshSections(i, lod, lod.Sections.Value[i], materialExports, mesh); - } - - var armatureNodeBuilder = new NodeBuilder(sk.Name + ".ao"); - var armature = Gltf.CreateGltfSkeleton(convertedMesh.RefSkeleton, armatureNodeBuilder); - sceneBuilder.AddSkinnedMesh(mesh, Matrix4x4.Identity, armature); - } - - break; - } - } - } - - var scene = sceneBuilder.ToGltf2(); - var fileName = fileBrowser.FileName; - if (fileName.EndsWith(".glb", StringComparison.OrdinalIgnoreCase)) - scene.SaveGLB(fileName); - else if (fileName.EndsWith(".gltf", StringComparison.OrdinalIgnoreCase)) - scene.SaveGLTF(fileName); - else if (fileName.EndsWith(".obj", StringComparison.OrdinalIgnoreCase)) - scene.SaveAsWavefront(fileName); - else - throw new ArgumentOutOfRangeException(nameof(fileName), $@"Unknown file format {fileName.SubstringAfterWithLast('.')}"); - - if (!CheckIfSaved(fileName)) return; - foreach (var materialExport in materialExports) - { - materialExport.TryWriteToDir(new DirectoryInfo(StringUtils.SubstringBeforeWithLast(fileName, '\\')), out _); - } - } - - public void CopySelectedMaterialName() - { - if (SelectedModel is not { } m || m.SelectedGeometry is null) - return; - - Clipboard.SetText(m.SelectedGeometry.DisplayName.TrimEnd()); - } - - #endregion - - public bool TryOverwriteMaterial(UMaterialInstance materialInstance) - { - if (SelectedModel?.SelectedGeometry == null || _loadedModels.Count < 1) return false; - - var (m, _, _) = LoadMaterial(materialInstance); - - var obj = new ResolvedLoadedObject(materialInstance); - switch (_loadedModels[SelectedModel.SelectedGeometry.ExportIndex].Export) - { - case UStaticMesh { Materials: { } } st: - st.Materials[SelectedModel.SelectedGeometry.MaterialIndex] = obj; - break; - case USkeletalMesh sk: - sk.Materials[SelectedModel.SelectedGeometry.MaterialIndex].Material = obj; - break; - case UMaterialInstance: - SelectedModel.SwapExport(materialInstance); - break; - } - - SelectedModel.SelectedGeometry.Material = m; - return m != null; - } - - private void LoadMaterialInstance(UMaterialInstance materialInstance, ModelAndCam cam) - { - var builder = new MeshBuilder(); - builder.AddBox(Vector3.Zero, 10, 10, 10); - cam.TriangleCount = 12; // no need to count - - SetupCameraAndAxis(new FBox(new FVector(-8), new FVector(8)), cam); - var (m, isRendering, isTransparent) = LoadMaterial(materialInstance); - - cam.Group3d.Add(new CustomMeshGeometryModel3D - { - Transform = new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 1, 0), -45)), - DisplayName = materialInstance.Name, Geometry = builder.ToMeshGeometry3D(), MaterialIndex = 0, - Material = m, IsTransparent = isTransparent, IsRendering = isRendering, ExportIndex = _loadedModels.Count - 1 - }); - } - - private void LoadStaticMesh(UStaticMesh mesh, ModelAndCam cam) - { - if (!mesh.TryConvert(out var convertedMesh) || convertedMesh.LODs.Count <= 0) - { - return; - } - - SetupCameraAndAxis(convertedMesh.BoundingBox, cam); - foreach (var lod in convertedMesh.LODs.Where(lod => !lod.SkipLod)) - { - PushLod(lod.Sections.Value, lod.Verts, lod.Indices.Value, cam); - break; - } - } - - private void LoadSkeletalMesh(USkeletalMesh mesh, ModelAndCam cam) - { - if (!mesh.TryConvert(out var convertedMesh) || convertedMesh.LODs.Count <= 0) - { - return; - } - - SetupCameraAndAxis(convertedMesh.BoundingBox, cam); - foreach (var lod in convertedMesh.LODs.Where(lod => !lod.SkipLod)) - { - PushLod(lod.Sections.Value, lod.Verts, lod.Indices.Value, cam); - break; - } - } - - private void PushLod(CMeshSection[] sections, CMeshVertex[] verts, FRawStaticIndexBuffer indices, ModelAndCam cam) - { - for (var i = 0; i < sections.Length; i++) // each section is a mesh part with its own material - { - var section = sections[i]; - var builder = new MeshBuilder(); - cam.TriangleCount += section.NumFaces; // NumFaces * 3 (triangle) = next section FirstIndex - - for (var j = 0; j < section.NumFaces; j++) // draw a triangle for each face - { - foreach (var t in _facesIndex) // triangle face 1 then 0 then 2 - { - var id = section.FirstIndex + j * 3 + t; - var vert = verts[indices[id]]; - var p = new Vector3(vert.Position.X, vert.Position.Z, vert.Position.Y); // up direction is Y - var n = new Vector3(vert.Normal.X, vert.Normal.Z, vert.Normal.Y); - n.Normalize(); - - builder.AddNode(p, n, new Vector2(vert.UV.U, vert.UV.V)); - builder.TriangleIndices.Add(j * 3 + t); // one mesh part is "j * 3 + t" use "id" if you're building the full mesh - } - } - - if (section.Material == null || !section.Material.TryLoad(out var o) || o is not UMaterialInterface material) - { - cam.Group3d.Add(new CustomMeshGeometryModel3D - { - DisplayName = section.Material?.Name.ToString() ?? $"material_{section.MaterialIndex}", MaterialIndex = section.MaterialIndex, - Geometry = builder.ToMeshGeometry3D(), Material = new PBRMaterial(), IsTransparent = false, - IsRendering = true, ExportIndex = _loadedModels.Count - 1 - }); - } - else - { - var (m, isRendering, isTransparent) = LoadMaterial(material); - cam.Group3d.Add(new CustomMeshGeometryModel3D - { - DisplayName = material.Name, MaterialIndex = section.MaterialIndex, - Geometry = builder.ToMeshGeometry3D(), Material = m, IsTransparent = isTransparent, - IsRendering = isRendering, ExportIndex = _loadedModels.Count - 1 - }); - } - } - } - - private (PBRMaterial material, bool isRendering, bool isTransparent) LoadMaterial(UMaterialInterface unrealMaterial) - { - var m = new PBRMaterial { RenderShadowMap = true, EnableAutoTangent = true, RenderEnvironmentMap = true }; - var parameters = new CMaterialParams(); - unrealMaterial.GetParams(parameters); - - var isRendering = !parameters.IsNull; - if (isRendering) - { - if (!parameters.HasTopDiffuseTexture && parameters.DiffuseColor is { A: > 0 } diffuseColor) - { - m.AlbedoColor = new Color4(diffuseColor.R, diffuseColor.G, diffuseColor.B, diffuseColor.A); - } - else if (parameters.Diffuse is UTexture2D diffuse) - { - m.AlbedoMap = new TextureModel(diffuse.Decode(UserSettings.Default.OverridedPlatform)?.Encode(SKEncodedImageFormat.Png, 100).AsStream()); - } - - if (parameters.Normal is UTexture2D normal) - { - m.NormalMap = new TextureModel(normal.Decode(UserSettings.Default.OverridedPlatform)?.Encode(SKEncodedImageFormat.Png, 100).AsStream()); - } - - if (parameters.Specular is UTexture2D specular) - { - var mip = specular.GetFirstMip(); - var platform = UserSettings.Default.OverridedPlatform; - TextureDecoder.DecodeTexture(mip, specular.Format, specular.isNormalMap, platform, out var data, out var colorType); - - switch (_game) - { - case FGame.FortniteGame: - { - // Fortnite's Specular Texture Channels - // R Specular - // G Metallic - // B Roughness - unsafe - { - var offset = 0; - fixed (byte* d = data) - { - for (var i = 0; i < mip.SizeX * mip.SizeY; i++) - { - d[offset] = 0; - (d[offset + 1], d[offset + 2]) = (d[offset + 2], d[offset + 1]); // swap G and B - offset += 4; - } - } - } - - parameters.RoughnessValue = 1; - parameters.MetallicValue = 1; - break; - } - case FGame.ShooterGame: - { - var packedPBRType = specular.Name[(specular.Name.LastIndexOf('_') + 1)..]; - switch (packedPBRType) - { - case "MRAE": // R: Metallic, G: AO (0-127) & Emissive (128-255), B: Roughness (Character PBR) - unsafe - { - var offset = 0; - fixed (byte* d = data) - { - for (var i = 0; i < mip.SizeX * mip.SizeY; i++) - { - (d[offset], d[offset + 2]) = (d[offset + 2], d[offset]); // swap R and B - (d[offset], d[offset + 1]) = (d[offset + 1], d[offset]); // swap R and G - offset += 4; - } - } - } - - break; - case "MRAS": // R: Metallic, B: Roughness, B: AO, A: Specular (Legacy PBR) - case "MRA": // R: Metallic, B: Roughness, B: AO (Environment PBR) - case "MRS": // R: Metallic, G: Roughness, B: Specular (Weapon PBR) - unsafe - { - var offset = 0; - fixed (byte* d = data) - { - for (var i = 0; i < mip.SizeX * mip.SizeY; i++) - { - (d[offset], d[offset + 2]) = (d[offset + 2], d[offset]); // swap R and B - offset += 4; - } - } - } - - break; - } - - parameters.RoughnessValue = 1; - parameters.MetallicValue = 1; - break; - } - case FGame.Gameface: - { - // GTA's Specular Texture Channels - // R Metallic - // G Roughness - // B Specular - unsafe - { - var offset = 0; - fixed (byte* d = data) - { - for (var i = 0; i < mip.SizeX * mip.SizeY; i++) - { - (d[offset], d[offset + 2]) = (d[offset + 2], d[offset]); // swap R and B - offset += 4; - } - } - } - - break; - } - } - - using var bitmap = new SKBitmap(new SKImageInfo(mip.SizeX, mip.SizeY, colorType, SKAlphaType.Unpremul)); - unsafe - { - fixed (byte* p = data) - { - bitmap.SetPixels(new IntPtr(p)); - } - } - - // R -> AO G -> Roughness B -> Metallic - m.RoughnessMetallicMap = new TextureModel(bitmap.Encode(SKEncodedImageFormat.Png, 100).AsStream()); - m.RoughnessFactor = parameters.RoughnessValue; - m.MetallicFactor = parameters.MetallicValue; - m.RenderAmbientOcclusionMap = parameters.SpecularValue > 0; - } - - if (parameters.HasTopEmissiveTexture && parameters.Emissive is UTexture2D emissive && parameters.EmissiveColor is { A: > 0 } emissiveColor) - { - m.EmissiveColor = new Color4(emissiveColor.R, emissiveColor.G, emissiveColor.B, emissiveColor.A); - m.EmissiveMap = new TextureModel(emissive.Decode(UserSettings.Default.OverridedPlatform)?.Encode(SKEncodedImageFormat.Png, 100).AsStream()); - } - } - else - { - m.AlbedoColor = new Color4(1, 0, 0, 1); - } - - return (m, isRendering, parameters.IsTransparent); - } - - private void SetupCameraAndAxis(FBox box, ModelAndCam cam) - { - if (AppendMode && CanAppend) return; - var center = box.GetCenter(); - - var lineBuilder = new LineBuilder(); - lineBuilder.AddLine(new Vector3(box.Min.X, center.Z, center.Y), new Vector3(box.Max.X, center.Z, center.Y)); - cam.XAxis = lineBuilder.ToLineGeometry3D(); - lineBuilder = new LineBuilder(); - lineBuilder.AddLine(new Vector3(center.X, box.Min.Z, center.Y), new Vector3(center.X, box.Max.Z, center.Y)); - cam.YAxis = lineBuilder.ToLineGeometry3D(); - lineBuilder = new LineBuilder(); - lineBuilder.AddLine(new Vector3(center.X, center.Z, box.Min.Y), new Vector3(center.X, center.Z, box.Max.Y)); - cam.ZAxis = lineBuilder.ToLineGeometry3D(); - - cam.Position = new Point3D(box.Max.X + center.X * 2, center.Z, box.Min.Y + center.Y * 2); - cam.LookDirection = new Vector3D(-cam.Position.X + center.X, 0, -cam.Position.Z + center.Y); - } - - private bool CheckIfSaved(string path) - { - if (File.Exists(path)) - { - Log.Information("Successfully saved {FileName}", path); - FLogger.AppendInformation(); - FLogger.AppendText($"Successfully saved {path}", Constants.WHITE, true); - return true; - } - - Log.Error("{FileName} could not be saved", path); - FLogger.AppendError(); - FLogger.AppendText($"Could not save '{path}'", Constants.WHITE, true); - return false; - } - - public void Clear() - { - foreach (var g in _loadedModels.ToList()) - { - g.Dispose(); - _loadedModels.Remove(g); - } - } -} - -public class ModelAndCam : ViewModel -{ - public UObject Export { get; private set; } - public Point3D Position { get; set; } - public Vector3D LookDirection { get; set; } - public Geometry3D XAxis { get; set; } - public Geometry3D YAxis { get; set; } - public Geometry3D ZAxis { get; set; } - public int TriangleCount { get; set; } - - private bool _isVisible = true; - public bool IsVisible - { - get => _isVisible; - set => SetProperty(ref _isVisible, value); - } - - private bool _renderingToggle; - public bool RenderingToggle - { - get => _renderingToggle; - set - { - SetProperty(ref _renderingToggle, value); - foreach (var g in Group3d) - { - if (g is not CustomMeshGeometryModel3D geometryModel) - continue; - - geometryModel.IsRendering = !geometryModel.IsRendering; - } - } - } - - private bool _wireframeToggle; - public bool WireframeToggle - { - get => _wireframeToggle; - set - { - SetProperty(ref _wireframeToggle, value); - foreach (var g in Group3d) - { - if (g is not CustomMeshGeometryModel3D geometryModel) - continue; - - geometryModel.RenderWireframe = !geometryModel.RenderWireframe; - } - } - } - - private bool _showMaterialColor; - public bool ShowMaterialColor - { - get => _showMaterialColor; - set - { - SetProperty(ref _showMaterialColor, value); - for (var i = 0; i < Group3d.Count; i++) - { - if (Group3d[i] is not CustomMeshGeometryModel3D { Material: PBRMaterial material } m) - continue; - - var index = B(i); - material.RenderAlbedoMap = !_showMaterialColor; - - if (_showMaterialColor) - { - m.Tag = material.AlbedoColor; - material.AlbedoColor = new Color4(_table[C(index)] / 255, _table[C(index >> 1)] / 255, _table[C(index >> 2)] / 255, 1); - } - else material.AlbedoColor = (Color4) m.Tag; - } - } - } - - private bool _diffuseOnlyToggle; - public bool DiffuseOnlyToggle - { - get => _diffuseOnlyToggle; - set - { - SetProperty(ref _diffuseOnlyToggle, value); - foreach (var g in Group3d) - { - if (g is not CustomMeshGeometryModel3D { Material: PBRMaterial material }) - continue; - - material.RenderAmbientOcclusionMap = !material.RenderAmbientOcclusionMap; - material.RenderDisplacementMap = !material.RenderDisplacementMap; - // material.RenderEmissiveMap = !material.RenderEmissiveMap; - // material.RenderEnvironmentMap = !material.RenderEnvironmentMap; - material.RenderIrradianceMap = !material.RenderIrradianceMap; - material.RenderRoughnessMetallicMap = !material.RenderRoughnessMetallicMap; - material.RenderShadowMap = !material.RenderShadowMap; - material.RenderNormalMap = !material.RenderNormalMap; - } - } - } - - private CustomMeshGeometryModel3D _selectedGeometry; // selected material - public CustomMeshGeometryModel3D SelectedGeometry - { - get => _selectedGeometry; - set => SetProperty(ref _selectedGeometry, value); - } - - private ObservableElement3DCollection _group3d; // material list - public ObservableElement3DCollection Group3d - { - get => _group3d; - set => SetProperty(ref _group3d, value); - } - - private readonly float[] _table = { 255 * 0.9f, 25 * 3.0f, 255 * 0.6f, 255 * 0.0f }; - private readonly int[] _table2 = { 0, 1, 2, 4, 7, 3, 5, 6 }; - - public ModelAndCam(UObject export) - { - Export = export; - TriangleCount = 0; - Group3d = new ObservableElement3DCollection(); - } - - private int B(int x) => (x & 0xFFF8) | _table2[x & 7] ^ 7; - private int C(int x) => (x & 1) | ((x >> 2) & 2); - - public void SwapExport(UObject e) - { - Export = e; - } - - public void Dispose() - { - TriangleCount = 0; - SelectedGeometry = null; - foreach (var g in Group3d.ToList()) - { - g.Dispose(); - Group3d.Remove(g); - } - } -} - -public class CustomMeshGeometryModel3D : MeshGeometryModel3D -{ - public string DisplayName { get; set; } - public int MaterialIndex { get; set; } - public int ExportIndex { get; set; } -} diff --git a/FModel/Views/ModelViewer.xaml b/FModel/Views/ModelViewer.xaml deleted file mode 100644 index 66edcd2a..00000000 --- a/FModel/Views/ModelViewer.xaml +++ /dev/null @@ -1,135 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/FModel/Views/ModelViewer.xaml.cs b/FModel/Views/ModelViewer.xaml.cs deleted file mode 100644 index 07d6a2bd..00000000 --- a/FModel/Views/ModelViewer.xaml.cs +++ /dev/null @@ -1,115 +0,0 @@ -using System.ComponentModel; -using System.Windows; -using System.Windows.Input; -using AdonisUI.Controls; -using CUE4Parse.UE4.Assets.Exports; -using CUE4Parse.UE4.Assets.Exports.Material; -using FModel.Services; -using FModel.ViewModels; -using HelixToolkit.Wpf.SharpDX; -using MessageBox = AdonisUI.Controls.MessageBox; -using MessageBoxImage = AdonisUI.Controls.MessageBoxImage; - -namespace FModel.Views; - -public partial class ModelViewer -{ - private bool _messageShown; - private ApplicationViewModel _applicationView => ApplicationService.ApplicationView; - - public ModelViewer() - { - DataContext = _applicationView; - InitializeComponent(); - } - - public void Load(UObject export) => _applicationView.ModelViewer.LoadExport(export); - public void Overwrite(UMaterialInstance materialInstance) - { - if (_applicationView.ModelViewer.TryOverwriteMaterial(materialInstance)) - { - _applicationView.CUE4Parse.ModelIsOverwritingMaterial = false; - } - else - { - MessageBox.Show(new MessageBoxModel - { - Text = "An attempt to load a material failed.", - Caption = "Error", - Icon = MessageBoxImage.Error, - Buttons = MessageBoxButtons.OkCancel(), - IsSoundEnabled = false - }); - } - } - - private void OnClosing(object sender, CancelEventArgs e) - { - _applicationView.ModelViewer.Clear(); - _applicationView.ModelViewer.AppendMode = false; - _applicationView.CUE4Parse.ModelIsOverwritingMaterial = false; - MyAntiCrashGroup.ItemsSource = null; // <3 - } - - private async void OnWindowKeyDown(object sender, KeyEventArgs e) - { - switch (e.Key) - { - case Key.W: - _applicationView.ModelViewer.WirefreameToggle(); - break; - case Key.H: - _applicationView.ModelViewer.RenderingToggle(); - break; - case Key.D: - _applicationView.ModelViewer.DiffuseOnlyToggle(); - break; - case Key.M: - _applicationView.ModelViewer.MaterialColorToggle(); - break; - case Key.Decimal: - _applicationView.ModelViewer.FocusOnSelectedMesh(); - break; - case Key.S when Keyboard.Modifiers.HasFlag(ModifierKeys.Control) && Keyboard.Modifiers.HasFlag(ModifierKeys.Shift): - _applicationView.ModelViewer.SaveAsScene(); - break; - case Key.S when Keyboard.Modifiers.HasFlag(ModifierKeys.Control): - await _applicationView.ModelViewer.SaveLoadedModels(); - break; - } - } - - private void OnMouse3DDown(object sender, MouseDown3DEventArgs e) - { - if (!Keyboard.Modifiers.HasFlag(ModifierKeys.Shift) || e.HitTestResult.ModelHit is not CustomMeshGeometryModel3D m) return; - _applicationView.ModelViewer.SelectedModel.SelectedGeometry = m; - MaterialsListName.ScrollIntoView(m); - } - - private void OnFocusClick(object sender, RoutedEventArgs e) - => _applicationView.ModelViewer.FocusOnSelectedMesh(); - - private void OnCopyClick(object sender, RoutedEventArgs e) - => _applicationView.ModelViewer.CopySelectedMaterialName(); - - private async void Save(object sender, RoutedEventArgs e) - => await _applicationView.ModelViewer.SaveLoadedModels(); - - private void OnOverwriteMaterialClick(object sender, RoutedEventArgs e) - { - _applicationView.CUE4Parse.ModelIsOverwritingMaterial = true; - if (!_messageShown) - { - MessageBox.Show(new MessageBoxModel - { - Text = "Simply extract a material once FModel will be brought to the foreground. This message will be shown once per Model Viewer's lifetime, close it to begin.", - Caption = "How To Overwrite Material?", - Icon = MessageBoxImage.Information, - IsSoundEnabled = false - }); - _messageShown = true; - } - - MainWindow.YesWeCats.Activate(); - } -} \ No newline at end of file diff --git a/FModel/Views/Resources/Converters/BoolToFillModeConverter.cs b/FModel/Views/Resources/Converters/BoolToFillModeConverter.cs deleted file mode 100644 index 3a85a8c7..00000000 --- a/FModel/Views/Resources/Converters/BoolToFillModeConverter.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; -using System.Globalization; -using System.Windows.Data; -using SharpDX.Direct3D11; - -namespace FModel.Views.Resources.Converters; - -public class BoolToFillModeConverter : IValueConverter -{ - public static readonly BoolToFillModeConverter Instance = new(); - - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - return value switch - { - FillMode.Solid => true, - _ => false - }; - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - return value switch - { - true => FillMode.Solid, - _ => FillMode.Wireframe - }; - } -} \ No newline at end of file diff --git a/FModel/Views/Resources/Converters/DateTimeToStringConverter.cs b/FModel/Views/Resources/Converters/DateTimeToStringConverter.cs deleted file mode 100644 index 1d525940..00000000 --- a/FModel/Views/Resources/Converters/DateTimeToStringConverter.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Globalization; -using System.Windows.Data; - -namespace FModel.Views.Resources.Converters; - -public class DateTimeToStringConverter : IValueConverter -{ - public static readonly DateTimeToStringConverter Instance = new(); - - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - return value is not DateTime dateTime ? value : $"{dateTime.ToLongDateString()}, {dateTime.ToShortTimeString()}"; - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - throw new NotImplementedException(); - } -} \ No newline at end of file diff --git a/FModel/Views/Resources/Converters/TagToColorConverter.cs b/FModel/Views/Resources/Converters/TagToColorConverter.cs deleted file mode 100644 index ae0d4cfd..00000000 --- a/FModel/Views/Resources/Converters/TagToColorConverter.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using System.Globalization; -using System.Windows.Data; -using System.Windows.Media; -using HelixToolkit.Wpf.SharpDX; - -namespace FModel.Views.Resources.Converters; - -public class TagToColorConverter : IValueConverter -{ - public static readonly TagToColorConverter Instance = new(); - - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - if (value is not PBRMaterial material) - return new SolidColorBrush(Colors.Red); - - return new SolidColorBrush(Color.FromScRgb( - material.AlbedoColor.Alpha, material.AlbedoColor.Red, - material.AlbedoColor.Green, material.AlbedoColor.Blue)); - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - throw new NotImplementedException(); - } -} \ No newline at end of file diff --git a/FModel/Views/Resources/Resources.xaml b/FModel/Views/Resources/Resources.xaml index 984f2454..3dd838e2 100644 --- a/FModel/Views/Resources/Resources.xaml +++ b/FModel/Views/Resources/Resources.xaml @@ -4,7 +4,6 @@ xmlns:system="clr-namespace:System;assembly=mscorlib" xmlns:controls="clr-namespace:FModel.Views.Resources.Controls" xmlns:soundOut="clr-namespace:CSCore.SoundOut;assembly=CSCore" - xmlns:sharpDx="clr-namespace:SharpDX.Direct3D11;assembly=SharpDX.Direct3D11" xmlns:audioControls="clr-namespace:FModel.Views.Resources.Controls.Aup" xmlns:converters="clr-namespace:FModel.Views.Resources.Converters" xmlns:avalonedit="http://icsharpcode.net/sharpdevelop/avalonedit" @@ -638,91 +637,6 @@ - - - - - - - - - - - - - - - - - -