├── Lib ├── SharpDX.dll ├── SharpDX.DXGI.dll ├── SharpDX.XInput.dll ├── Lidgren.Network.dll ├── SharpDX.Direct2D1.dll ├── SharpDX.XAudio2.dll ├── MonoGame.Framework.dll ├── SharpDX.Direct3D11.dll ├── MonoGame.Framework.Net.dll ├── SharpDX.MediaFoundation.dll └── MonoGame.Framework.Net.xml ├── .gitmodules ├── ContentSource ├── MissingTexture.png ├── DarkSoulsModelViewerDX_Content.mgcb ├── CollisionShader.fx ├── DbgMenuFontSimple.spritefont └── NormalMapShader.fx ├── DarkSoulsModelViewerDX ├── Icon.ico ├── Content │ ├── DbgMenuFont.xnb │ ├── CollisionShader.xnb │ ├── MissingTexture.xnb │ ├── NormalMapShader.xnb │ ├── WP_A_0221.partsbnd │ ├── DbgMenuFontSimple.xnb │ └── DbgMenuFontSmall.xnb ├── GFXShaders │ ├── IGFXShader.cs │ ├── DbgPrimShader.cs │ ├── CollisionShader.cs │ └── FlverShader.cs ├── DebugPrimitives │ ├── IDbgPrim.cs │ ├── DbgPrimWireGrid.cs │ ├── DbgPrimWireBox.cs │ ├── DbgPrimWireCylinder.cs │ ├── DbgPrim.cs │ ├── DbgPrimWireSphere.cs │ └── DbgPrimWire.cs ├── Program.cs ├── DbgMenus │ ├── DbgMenuItemTextLabel.cs │ ├── DbgMenuItemBool.cs │ ├── DbgMenuItemTaskKiller.cs │ ├── DbgMenuItemResolutionChange.cs │ ├── DbgMenuItemGfxFlverShaderAdjust.cs │ ├── DbgMenuItemNumber.cs │ ├── DbgMenuPadRepeater.cs │ ├── DbgMenuItemEnum.cs │ ├── DbgMenuItemGfxDepthStencilStateAdjust.cs │ ├── DbgMenuItemGfxBlendStateAdjust.cs │ ├── DbgMenuItemSpawnChr.cs │ ├── DbgMenuItemSceneList.cs │ └── DbgMenuItemSpawnObj.cs ├── FrameCounter.cs ├── Properties │ └── AssemblyInfo.cs ├── StructExtensions.cs ├── Utils.cs ├── app.config ├── Transform.cs ├── packages.config ├── ModelInstance.cs ├── VertexPositionColorNormalTangentTexture.cs └── Tests.cs ├── README.md ├── SoulsFormats ├── SoulsFormats │ ├── SoulsFormats.nuspec │ ├── IBinder.cs │ ├── Formats │ │ ├── MSB64 │ │ │ ├── MSB64.PartsPoseSection.cs │ │ │ ├── MSB64.BoneNamesSection.cs │ │ │ ├── MSB64.LayerSection.cs │ │ │ └── MSB64.RouteSection.cs │ │ ├── MSB3 │ │ │ ├── MSB3.BoneNamesSection.cs │ │ │ ├── MSB3.PartsPoseSection.cs │ │ │ ├── MSB3.LayerSection.cs │ │ │ └── MSB3.RouteSection.cs │ │ ├── TPF.DDS.cs │ │ ├── DDS.cs │ │ ├── ENFL.cs │ │ ├── BND0.cs │ │ ├── MSB2 │ │ │ └── MSB2.ModelSection.cs │ │ ├── BTAB.cs │ │ ├── FMG.cs │ │ ├── MSBD │ │ │ └── MSBD.ModelSection.cs │ │ └── MSBN │ │ │ └── MSBN.ModelSection.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── SoulsFile.cs │ └── SoulsFormats.csproj └── SoulsFormats.sln ├── LICENSE └── DarkSoulsModelViewerDX.sln /Lib/SharpDX.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soulsmods/DarkSoulsModelViewerDX/HEAD/Lib/SharpDX.dll -------------------------------------------------------------------------------- /Lib/SharpDX.DXGI.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soulsmods/DarkSoulsModelViewerDX/HEAD/Lib/SharpDX.DXGI.dll -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "MeowDSIO"] 2 | path = MeowDSIO 3 | url = https://github.com/Meowmaritus/MeowDSIO 4 | -------------------------------------------------------------------------------- /Lib/SharpDX.XInput.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soulsmods/DarkSoulsModelViewerDX/HEAD/Lib/SharpDX.XInput.dll -------------------------------------------------------------------------------- /Lib/Lidgren.Network.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soulsmods/DarkSoulsModelViewerDX/HEAD/Lib/Lidgren.Network.dll -------------------------------------------------------------------------------- /Lib/SharpDX.Direct2D1.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soulsmods/DarkSoulsModelViewerDX/HEAD/Lib/SharpDX.Direct2D1.dll -------------------------------------------------------------------------------- /Lib/SharpDX.XAudio2.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soulsmods/DarkSoulsModelViewerDX/HEAD/Lib/SharpDX.XAudio2.dll -------------------------------------------------------------------------------- /Lib/MonoGame.Framework.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soulsmods/DarkSoulsModelViewerDX/HEAD/Lib/MonoGame.Framework.dll -------------------------------------------------------------------------------- /Lib/SharpDX.Direct3D11.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soulsmods/DarkSoulsModelViewerDX/HEAD/Lib/SharpDX.Direct3D11.dll -------------------------------------------------------------------------------- /Lib/MonoGame.Framework.Net.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soulsmods/DarkSoulsModelViewerDX/HEAD/Lib/MonoGame.Framework.Net.dll -------------------------------------------------------------------------------- /ContentSource/MissingTexture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soulsmods/DarkSoulsModelViewerDX/HEAD/ContentSource/MissingTexture.png -------------------------------------------------------------------------------- /DarkSoulsModelViewerDX/Icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soulsmods/DarkSoulsModelViewerDX/HEAD/DarkSoulsModelViewerDX/Icon.ico -------------------------------------------------------------------------------- /Lib/SharpDX.MediaFoundation.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soulsmods/DarkSoulsModelViewerDX/HEAD/Lib/SharpDX.MediaFoundation.dll -------------------------------------------------------------------------------- /DarkSoulsModelViewerDX/Content/DbgMenuFont.xnb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soulsmods/DarkSoulsModelViewerDX/HEAD/DarkSoulsModelViewerDX/Content/DbgMenuFont.xnb -------------------------------------------------------------------------------- /DarkSoulsModelViewerDX/Content/CollisionShader.xnb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soulsmods/DarkSoulsModelViewerDX/HEAD/DarkSoulsModelViewerDX/Content/CollisionShader.xnb -------------------------------------------------------------------------------- /DarkSoulsModelViewerDX/Content/MissingTexture.xnb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soulsmods/DarkSoulsModelViewerDX/HEAD/DarkSoulsModelViewerDX/Content/MissingTexture.xnb -------------------------------------------------------------------------------- /DarkSoulsModelViewerDX/Content/NormalMapShader.xnb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soulsmods/DarkSoulsModelViewerDX/HEAD/DarkSoulsModelViewerDX/Content/NormalMapShader.xnb -------------------------------------------------------------------------------- /DarkSoulsModelViewerDX/Content/WP_A_0221.partsbnd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soulsmods/DarkSoulsModelViewerDX/HEAD/DarkSoulsModelViewerDX/Content/WP_A_0221.partsbnd -------------------------------------------------------------------------------- /DarkSoulsModelViewerDX/Content/DbgMenuFontSimple.xnb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soulsmods/DarkSoulsModelViewerDX/HEAD/DarkSoulsModelViewerDX/Content/DbgMenuFontSimple.xnb -------------------------------------------------------------------------------- /DarkSoulsModelViewerDX/Content/DbgMenuFontSmall.xnb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soulsmods/DarkSoulsModelViewerDX/HEAD/DarkSoulsModelViewerDX/Content/DbgMenuFontSmall.xnb -------------------------------------------------------------------------------- /DarkSoulsModelViewerDX/GFXShaders/IGFXShader.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Xna.Framework; 2 | using Microsoft.Xna.Framework.Graphics; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace DarkSoulsModelViewerDX.GFXShaders 10 | { 11 | public interface IGFXShader 12 | where T : Effect 13 | { 14 | T Effect { get; } 15 | void ApplyWorldView(Matrix world, Matrix view, Matrix projection); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /DarkSoulsModelViewerDX/DebugPrimitives/IDbgPrim.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Xna.Framework; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace DarkSoulsModelViewerDX.DebugPrimitives 9 | { 10 | public interface IDbgPrim : IDisposable 11 | { 12 | Transform Transform { get; set; } 13 | string Name { get; set; } 14 | Color NameColor { get; set; } 15 | void Draw(); 16 | void LabelDraw(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /DarkSoulsModelViewerDX/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DarkSoulsModelViewerDX 4 | { 5 | 6 | /// 7 | /// The main class. 8 | /// 9 | public static class Program 10 | { 11 | /// 12 | /// The main entry point for the application. 13 | /// 14 | [STAThread] 15 | static void Main() 16 | { 17 | using (var game = new Main()) 18 | game.Run(Microsoft.Xna.Framework.GameRunBehavior.Synchronous); 19 | } 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Credits: 2 | * **Model Management/Rendering Engine**: Meowmaritus 3 | * **Menu System**: Meowmaritus 4 | * **Asset Loading From Games**: Katalash 5 | * **FLVER Model Parsing**: Meowmaritus & TKGP 6 | * **MSB Map Layout Parsing**: Meowmaritus & TKGP 7 | * **TPF/TPFBHD Texture Packs Parsing**: TKGP 8 | * **PS4 Texture Headerization**: Katalash 9 | * **DX11 Texture Support Patch To MonoGame**: Katalash 10 | * **Binder & DCX Container Parsing**: TKGP 11 | * **HKX Collision Parsing**: Katalash 12 | * **Post-Build Task**: TKGP 13 | * **OVERALL OPTIMIZATION / POLISHING**: Meowmaritus & Katalash 14 | 15 | 16 | ## Special Thanks 17 | * **River Nyxx** 18 | * **Wulf2k9** 19 | -------------------------------------------------------------------------------- /DarkSoulsModelViewerDX/DbgMenus/DbgMenuItemTextLabel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace DarkSoulsModelViewerDX.DbgMenus 8 | { 9 | public class DbgMenuItemTextLabel : DbgMenuItem 10 | { 11 | public readonly Func GetText; 12 | 13 | public DbgMenuItemTextLabel(Func getText) 14 | { 15 | GetText = getText; 16 | } 17 | 18 | public override void UpdateUI() 19 | { 20 | Text = GetText.Invoke(); 21 | base.UpdateUI(); 22 | } 23 | 24 | public override void OnRequestTextRefresh() 25 | { 26 | UpdateUI(); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /SoulsFormats/SoulsFormats/SoulsFormats.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $id$ 5 | $version$ 6 | $title$ 7 | $author$ 8 | $author$ 9 | 10 | https://github.com/JKAnderson/SoulsFormats 11 | 12 | false 13 | $description$ 14 | 15 | $copyright$ 16 | 17 | 18 | -------------------------------------------------------------------------------- /Lib/MonoGame.Framework.Net.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | MonoGame.Framework.Net 5 | 6 | 7 | 8 | 9 | Used to Simulate the delay between computers 10 | 11 | 12 | 13 | 14 | Used to simulate the number of packets you might expect to loose. 15 | 16 | 17 | 18 | 19 | Contacts the Master Server on the net and gets a list of available host games 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /SoulsFormats/SoulsFormats/IBinder.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace SoulsFormats 4 | { 5 | /// 6 | /// A read-only collection of files in a bnd or bxf format. 7 | /// 8 | public interface IBinder 9 | { 10 | /// 11 | /// Files in this binder. 12 | /// 13 | IReadOnlyList Files { get; } 14 | } 15 | 16 | /// 17 | /// A read-only file in a bnd or bxf format. 18 | /// 19 | public interface IBinderFile 20 | { 21 | /// 22 | /// The ID of this file. 23 | /// 24 | int ID { get; } 25 | 26 | /// 27 | /// The name of this file, typically a network path. 28 | /// 29 | string Name { get; } 30 | 31 | /// 32 | /// The raw data of this file. 33 | /// 34 | byte[] Bytes { get; } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /DarkSoulsModelViewerDX/DebugPrimitives/DbgPrimWireGrid.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Xna.Framework; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace DarkSoulsModelViewerDX.DebugPrimitives 9 | { 10 | public class DbgPrimWireGrid : DbgPrimWire 11 | { 12 | public DbgPrimWireGrid(Color originColor, Color color, int unitRange, float unitSize) 13 | { 14 | NameColor = color; 15 | for (int h = -unitRange; h <= unitRange; h++) 16 | { 17 | AddLine(new Vector3(h, 0, unitRange) * unitSize, 18 | new Vector3(h, 0, -unitRange) * unitSize, h == 0 ? originColor : color); 19 | } 20 | 21 | for (int v = -unitRange; v <= unitRange; v++) 22 | { 23 | AddLine(new Vector3(-unitRange, 0, v) * unitSize, 24 | new Vector3(unitRange, 0, v) * unitSize, v == 0 ? originColor : color); 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Meowmaritus 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /SoulsFormats/SoulsFormats.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27703.2042 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SoulsFormats", "SoulsFormats\SoulsFormats.csproj", "{22C664BD-877B-44DF-8ECF-2808522469A8}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {22C664BD-877B-44DF-8ECF-2808522469A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {22C664BD-877B-44DF-8ECF-2808522469A8}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {22C664BD-877B-44DF-8ECF-2808522469A8}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {22C664BD-877B-44DF-8ECF-2808522469A8}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {B89F4ACF-4B4B-4DD4-9805-824777798DBA} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /DarkSoulsModelViewerDX/GFXShaders/DbgPrimShader.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Xna.Framework; 2 | using Microsoft.Xna.Framework.Graphics; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace DarkSoulsModelViewerDX.GFXShaders 10 | { 11 | public class DbgPrimShader : BasicEffect, IGFXShader 12 | { 13 | public DbgPrimShader Effect => this; 14 | 15 | public DbgPrimShader(GraphicsDevice device) : base(device) 16 | { 17 | LightingEnabled = false; 18 | VertexColorEnabled = true; 19 | DiffuseColor = Main.SELECTED_MESH_WIREFRAME_COLOR.ToVector3(); 20 | TextureEnabled = false; 21 | } 22 | 23 | protected DbgPrimShader(BasicEffect cloneSource) : base(cloneSource) 24 | { 25 | LightingEnabled = false; 26 | VertexColorEnabled = true; 27 | DiffuseColor = Main.SELECTED_MESH_WIREFRAME_COLOR.ToVector3(); 28 | TextureEnabled = false; 29 | } 30 | 31 | public void ApplyWorldView(Matrix world, Matrix view, Matrix projection) 32 | { 33 | World = world; 34 | View = view; 35 | Projection = projection; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /SoulsFormats/SoulsFormats/Formats/MSB64/MSB64.PartsPoseSection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace SoulsFormats 8 | { 9 | public partial class MSB64 10 | { 11 | //public class PartsPoseSection : Section 12 | //{ 13 | // public override string Type => "MAPSTUDIO_PARTS_POSE_ST"; 14 | 15 | // public override List Entries => throw new NotImplementedException(); 16 | 17 | // internal PartsPoseSection(BinaryReaderEx br, int unk1, int offsets) : base(br, unk1, offsets) { } 18 | 19 | // internal override void Init() 20 | // { 21 | // throw new NotImplementedException(); 22 | // } 23 | 24 | // internal override void Read(BinaryReaderEx br) 25 | // { 26 | // throw new NotImplementedException(); 27 | // } 28 | 29 | // internal override void WriteOffsets(BinaryWriterEx bw) 30 | // { 31 | // throw new NotImplementedException(); 32 | // } 33 | 34 | // internal override void WriteData(BinaryWriterEx bw) 35 | // { 36 | // throw new NotImplementedException(); 37 | // } 38 | //} 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /DarkSoulsModelViewerDX/FrameCounter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace DarkSoulsModelViewerDX 8 | { 9 | public class FrameCounter 10 | { 11 | public FrameCounter() 12 | { 13 | } 14 | 15 | public long TotalFrames { get; private set; } 16 | public float TotalSeconds { get; private set; } 17 | public float AverageFramesPerSecond { get; private set; } 18 | public float CurrentFramesPerSecond { get; private set; } 19 | 20 | public const int MAXIMUM_SAMPLES = 8; 21 | 22 | private Queue _sampleBuffer = new Queue(); 23 | 24 | public bool Update(float deltaTime) 25 | { 26 | CurrentFramesPerSecond = 1.0f / deltaTime; 27 | 28 | _sampleBuffer.Enqueue(CurrentFramesPerSecond); 29 | 30 | if (_sampleBuffer.Count > MAXIMUM_SAMPLES) 31 | { 32 | _sampleBuffer.Dequeue(); 33 | AverageFramesPerSecond = _sampleBuffer.Average(i => i); 34 | } 35 | else 36 | { 37 | AverageFramesPerSecond = CurrentFramesPerSecond; 38 | } 39 | 40 | TotalFrames++; 41 | TotalSeconds += deltaTime; 42 | return true; 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /DarkSoulsModelViewerDX/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Dark Souls Model Viewer DX")] 9 | [assembly: AssemblyProduct("Dark Souls Model Viewer DX")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyDescription("")] 12 | [assembly: AssemblyCompany("")] 13 | [assembly: AssemblyCopyright("Copyright © 2018")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("830e7b6d-a061-4fca-be97-a2485f7ec87b")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /SoulsFormats/SoulsFormats/Formats/MSB3/MSB3.BoneNamesSection.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace SoulsFormats 4 | { 5 | public partial class MSB3 6 | { 7 | /// 8 | /// A section containing bone name strings. Purpose unknown. 9 | /// 10 | public class BoneNameSection : Section 11 | { 12 | internal override string Type => "MAPSTUDIO_BONE_NAME_STRING"; 13 | 14 | /// 15 | /// The bone names in this section. 16 | /// 17 | public List Names; 18 | 19 | internal BoneNameSection(BinaryReaderEx br, int unk1) : base(br, unk1) 20 | { 21 | Names = new List(); 22 | } 23 | 24 | /// 25 | /// Returns every bone name in the order they will be written. 26 | /// 27 | public override List GetEntries() 28 | { 29 | return Names; 30 | } 31 | 32 | internal override string ReadEntry(BinaryReaderEx br) 33 | { 34 | var name = br.ReadUTF16(); 35 | Names.Add(name); 36 | return name; 37 | } 38 | 39 | internal override void WriteEntries(BinaryWriterEx bw, List entries) 40 | { 41 | for (int i = 0; i < entries.Count; i++) 42 | { 43 | bw.FillInt64($"Offset{i}", bw.Position); 44 | bw.WriteUTF16(entries[i], true); 45 | } 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /SoulsFormats/SoulsFormats/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("SoulsFormats")] 9 | [assembly: AssemblyDescription("A .NET library for reading and writing FromSoftware file formats.")] 10 | #if DEBUG 11 | [assembly: AssemblyConfiguration("Debug")] 12 | #else 13 | [assembly: AssemblyConfiguration("Release")] 14 | #endif 15 | [assembly: AssemblyCompany("JKAnderson")] 16 | [assembly: AssemblyProduct("SoulsFormats")] 17 | [assembly: AssemblyCopyright("Copyright © Joseph Anderson 2018")] 18 | [assembly: AssemblyTrademark("")] 19 | [assembly: AssemblyCulture("")] 20 | 21 | // Setting ComVisible to false makes the types in this assembly not visible 22 | // to COM components. If you need to access a type in this assembly from 23 | // COM, set the ComVisible attribute to true on that type. 24 | [assembly: ComVisible(false)] 25 | 26 | // The following GUID is for the ID of the typelib if this project is exposed to COM 27 | [assembly: Guid("22c664bd-877b-44df-8ecf-2808522469a8")] 28 | 29 | // Version information for an assembly consists of the following four values: 30 | // 31 | // Major Version 32 | // Minor Version 33 | // Build Number 34 | // Revision 35 | // 36 | // You can specify all the values or you can default the Build and Revision Numbers 37 | // by using the '*' as shown below: 38 | // [assembly: AssemblyVersion("1.0.*")] 39 | [assembly: AssemblyVersion("1.0.0.0")] 40 | [assembly: AssemblyFileVersion("1.0.0.0")] 41 | -------------------------------------------------------------------------------- /SoulsFormats/SoulsFormats/Formats/MSB64/MSB64.BoneNamesSection.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace SoulsFormats 4 | { 5 | public partial class MSB64 6 | { 7 | /// 8 | /// A section containing bone name strings. Purpose unknown. 9 | /// 10 | public class BoneNameSection : Section 11 | { 12 | /// 13 | /// The MSB type string for this section. 14 | /// 15 | public override string Type => "MAPSTUDIO_BONE_NAME_STRING"; 16 | 17 | /// 18 | /// The bone names in this section. 19 | /// 20 | public List Names; 21 | 22 | internal BoneNameSection(BinaryReaderEx br, int unk1) : base(br, unk1) 23 | { 24 | Names = new List(); 25 | } 26 | 27 | public override List GetEntries() 28 | { 29 | return Names; 30 | } 31 | 32 | internal override string ReadEntry(BinaryReaderEx br) 33 | { 34 | var name = br.ReadUTF16(); 35 | Names.Add(name); 36 | return name; 37 | } 38 | 39 | internal override string ReadEntryBB(BinaryReaderEx br) 40 | { 41 | return null; 42 | } 43 | 44 | internal override void WriteEntries(BinaryWriterEx bw, List entries) 45 | { 46 | for (int i = 0; i < entries.Count; i++) 47 | { 48 | bw.FillInt64($"Offset{i}", bw.Position); 49 | bw.WriteUTF16(entries[i], true); 50 | } 51 | } 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /DarkSoulsModelViewerDX/DbgMenus/DbgMenuItemBool.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace DarkSoulsModelViewerDX.DbgMenus 8 | { 9 | public class DbgMenuItemBool : DbgMenuItem 10 | { 11 | public string OptionName = "?BoolName?"; 12 | public string YesText = "?YesText?"; 13 | public string NoText = "?NoText?"; 14 | public Action SetValue; 15 | public Func GetValue; 16 | 17 | private bool defaultValue; 18 | 19 | public DbgMenuItemBool(string optionName, string yesText, 20 | string noText, Action setValue, Func getValue) 21 | { 22 | OptionName = optionName; 23 | YesText = yesText; 24 | NoText = noText; 25 | SetValue = setValue; 26 | GetValue = getValue; 27 | defaultValue = GetValue.Invoke(); 28 | } 29 | 30 | public override void OnResetDefault() 31 | { 32 | SetValue.Invoke(defaultValue); 33 | base.OnResetDefault(); 34 | } 35 | 36 | public override void OnIncrease(bool isRepeat, int incrementAmount) 37 | { 38 | if (!isRepeat) 39 | SetValue.Invoke(!GetValue.Invoke()); 40 | } 41 | 42 | public override void OnDecrease(bool isRepeat, int incrementAmount) 43 | { 44 | if (!isRepeat) 45 | SetValue.Invoke(!GetValue.Invoke()); 46 | } 47 | 48 | public override void UpdateUI() 49 | { 50 | Text = $"{OptionName}: <{(GetValue.Invoke() ? YesText : NoText)}>"; 51 | 52 | base.UpdateUI(); 53 | } 54 | 55 | public override void OnRequestTextRefresh() 56 | { 57 | UpdateUI(); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /ContentSource/DarkSoulsModelViewerDX_Content.mgcb: -------------------------------------------------------------------------------- 1 | 2 | #----------------------------- Global Properties ----------------------------# 3 | 4 | /outputDir:..\DarkSoulsModelViewerDX\Content 5 | /intermediateDir:obj 6 | /platform:Windows 7 | /config: 8 | /profile:HiDef 9 | /compress:False 10 | 11 | #-------------------------------- References --------------------------------# 12 | 13 | 14 | #---------------------------------- Content ---------------------------------# 15 | 16 | #begin CollisionShader.fx 17 | /importer:EffectImporter 18 | /processor:EffectProcessor 19 | /processorParam:DebugMode=Auto 20 | /build:CollisionShader.fx 21 | 22 | #begin DbgMenuFont.spritefont 23 | /importer:FontDescriptionImporter 24 | /processor:FontDescriptionProcessor 25 | /processorParam:PremultiplyAlpha=True 26 | /processorParam:TextureFormat=Color 27 | /build:DbgMenuFont.spritefont 28 | 29 | #begin DbgMenuFontSimple.spritefont 30 | /importer:FontDescriptionImporter 31 | /processor:FontDescriptionProcessor 32 | /processorParam:PremultiplyAlpha=True 33 | /processorParam:TextureFormat=Compressed 34 | /build:DbgMenuFontSimple.spritefont 35 | 36 | #begin DbgMenuFontSmall.spritefont 37 | /importer:FontDescriptionImporter 38 | /processor:FontDescriptionProcessor 39 | /processorParam:PremultiplyAlpha=True 40 | /processorParam:TextureFormat=Compressed 41 | /build:DbgMenuFontSmall.spritefont 42 | 43 | #begin MissingTexture.png 44 | /importer:TextureImporter 45 | /processor:TextureProcessor 46 | /processorParam:ColorKeyColor=255,0,255,255 47 | /processorParam:ColorKeyEnabled=False 48 | /processorParam:GenerateMipmaps=False 49 | /processorParam:PremultiplyAlpha=True 50 | /processorParam:ResizeToPowerOfTwo=False 51 | /processorParam:MakeSquare=False 52 | /processorParam:TextureFormat=Color 53 | /build:MissingTexture.png 54 | 55 | #begin NormalMapShader.fx 56 | /importer:EffectImporter 57 | /processor:EffectProcessor 58 | /processorParam:DebugMode=Auto 59 | /build:NormalMapShader.fx 60 | 61 | -------------------------------------------------------------------------------- /SoulsFormats/SoulsFormats/Formats/MSB3/MSB3.PartsPoseSection.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace SoulsFormats 4 | { 5 | public partial class MSB3 6 | { 7 | /// 8 | /// Unknown. 9 | /// 10 | public class PartsPoseSection 11 | { 12 | internal string Type = "MAPSTUDIO_PARTS_POSE_ST"; 13 | 14 | /// 15 | /// Unknown. 16 | /// 17 | public int Unk1; 18 | 19 | /// 20 | /// Parts pose data in this section. 21 | /// 22 | public List Entries; 23 | 24 | internal PartsPoseSection(BinaryReaderEx br, int unk1, int offsets) 25 | { 26 | Unk1 = unk1; 27 | 28 | Entries = new List(); 29 | for (int i = 0; i < offsets; i++) 30 | { 31 | long offset = br.ReadInt64(); 32 | long next = br.GetInt64(br.Position); 33 | byte[] bytes = br.GetBytes(offset, (int)(next - offset)); 34 | Entries.Add(bytes); 35 | } 36 | } 37 | 38 | internal void Write(BinaryWriterEx bw) 39 | { 40 | bw.WriteInt32(Unk1); 41 | bw.WriteInt32(Entries.Count + 1); 42 | bw.ReserveInt64("TypeOffset"); 43 | 44 | for (int i = 0; i < Entries.Count; i++) 45 | bw.ReserveInt64($"Offset{i}"); 46 | 47 | bw.ReserveInt64("NextOffset"); 48 | 49 | bw.FillInt64("TypeOffset", bw.Position); 50 | bw.WriteUTF16(Type, true); 51 | bw.Pad(8); 52 | 53 | for (int i = 0; i < Entries.Count; i++) 54 | { 55 | bw.FillInt64($"Offset{i}", bw.Position); 56 | bw.WriteBytes(Entries[i]); 57 | } 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /ContentSource/CollisionShader.fx: -------------------------------------------------------------------------------- 1 | #if OPENGL 2 | #define SV_POSITION POSITION 3 | #define VS_SHADERMODEL vs_3_0 4 | #define PS_SHADERMODEL ps_3_0 5 | #else 6 | #define VS_SHADERMODEL vs_4_0_level_9_1 7 | #define PS_SHADERMODEL ps_4_0_level_9_1 8 | #endif 9 | 10 | // Matrix 11 | float4x4 World; 12 | float4x4 View; 13 | float4x4 Projection; 14 | 15 | // Light related 16 | float4 AmbientColor; 17 | 18 | float4 DiffuseColor; 19 | 20 | float3 EyePosition; 21 | 22 | //Default 2 23 | float DEBUG_ValueA; 24 | 25 | // The input for the VertexShader 26 | struct VertexShaderInput 27 | { 28 | float4 Position : POSITION0; 29 | float2 TexCoord : TEXCOORD0; 30 | float2 TexCoord2 : TEXCOORD1; 31 | float3 Normal : NORMAL0; 32 | float3 Binormal : BINORMAL0; 33 | float3 Tangent : TANGENT0; 34 | float4x4 InstanceWorld : TEXCOORD2; 35 | float2 AtlasScale : TEXCOORD6; 36 | float2 AtlasOffset : TEXCOORD7; 37 | }; 38 | 39 | // The output from the vertex shader, used for later processing 40 | struct VertexShaderOutput 41 | { 42 | float4 Position : POSITION0; 43 | float3 View : TEXCOORD0; 44 | float3 Normal : NORMAL0; 45 | }; 46 | 47 | VertexShaderOutput MainVS(in VertexShaderInput input) 48 | { 49 | VertexShaderOutput output; 50 | 51 | float4 worldPosition = mul(mul(input.Position, transpose(input.InstanceWorld)), World); 52 | float4 viewPosition = mul(worldPosition, View); 53 | output.Position = mul(viewPosition, Projection); 54 | 55 | output.View = normalize(float4(EyePosition,1.0) - worldPosition); 56 | 57 | output.Normal = input.Normal; 58 | 59 | return output; 60 | } 61 | 62 | float4 MainPS(VertexShaderOutput input) : COLOR 63 | { 64 | float4 diffuse = saturate(abs(dot(-input.View, input.Normal))); 65 | 66 | float4 outputColor = AmbientColor * 0.3 + 67 | DiffuseColor * diffuse * 0.7; 68 | 69 | outputColor = float4(outputColor.xyz, 1.0); 70 | return outputColor; 71 | } 72 | 73 | technique BasicColorDrawing 74 | { 75 | pass P0 76 | { 77 | VertexShader = compile VS_SHADERMODEL MainVS(); 78 | PixelShader = compile PS_SHADERMODEL MainPS(); 79 | } 80 | }; 81 | 82 | -------------------------------------------------------------------------------- /DarkSoulsModelViewerDX/DebugPrimitives/DbgPrimWireBox.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Xna.Framework; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace DarkSoulsModelViewerDX.DebugPrimitives 9 | { 10 | public class DbgPrimWireBox : DbgPrimWire 11 | { 12 | public DbgPrimWireBox(Transform location, Vector3 size, Color color) 13 | : this(location, size, color, color) 14 | { 15 | 16 | } 17 | 18 | public DbgPrimWireBox(Transform location, Vector3 size, Color topColor, Color bottomColor) 19 | { 20 | Transform = location; 21 | NameColor = new Color((topColor.ToVector4() + bottomColor.ToVector4()) / 2); 22 | 23 | Vector3 max = size / 2; 24 | Vector3 min = -max; 25 | 26 | // 3 Letters of below names: 27 | // [T]op/[B]ottom, [F]ront/[B]ack, [L]eft/[R]ight 28 | var tfl = new Vector3(min.X, max.Y, max.Z); 29 | var tfr = new Vector3(max.X, max.Y, max.Z); 30 | var bfr = new Vector3(max.X, min.Y, max.Z); 31 | var bfl = new Vector3(min.X, min.Y, max.Z); 32 | var tbl = new Vector3(min.X, max.Y, min.Z); 33 | var tbr = new Vector3(max.X, max.Y, min.Z); 34 | var bbr = new Vector3(max.X, min.Y, min.Z); 35 | var bbl = new Vector3(min.X, min.Y, min.Z); 36 | 37 | // Top Face 38 | AddLine(tfl, tfr, topColor); 39 | AddLine(tfr, tbr, topColor); 40 | AddLine(tbr, tbl, topColor); 41 | AddLine(tbl, tfl, topColor); 42 | 43 | // Bottom Face 44 | AddLine(bfl, bfr, bottomColor); 45 | AddLine(bfr, bbr, bottomColor); 46 | AddLine(bbr, bbl, bottomColor); 47 | AddLine(bbl, bfl, bottomColor); 48 | 49 | // Four Vertical Pillars 50 | AddLine(bfl, tfl, bottomColor, topColor); 51 | AddLine(bfr, tfr, bottomColor, topColor); 52 | AddLine(bbl, tbl, bottomColor, topColor); 53 | AddLine(bbr, tbr, bottomColor, topColor); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /ContentSource/DbgMenuFontSimple.spritefont: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 14 | Arial 15 | 16 | 20 | 12 21 | 22 | 26 | 0 27 | 28 | 32 | true 33 | 34 | 38 | 39 | 40 | 44 | ? 45 | 46 | 53 | 54 | 55 | 56 | ~ 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /DarkSoulsModelViewerDX/GFXShaders/CollisionShader.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Xna.Framework; 2 | using Microsoft.Xna.Framework.Graphics; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace DarkSoulsModelViewerDX.GFXShaders 10 | { 11 | public class CollisionShader : Effect, IGFXShader 12 | { 13 | public CollisionShader Effect => this; 14 | 15 | public Matrix World 16 | { 17 | get => Parameters["World"].GetValueMatrix(); 18 | set => Parameters["World"].SetValue(value); 19 | } 20 | 21 | public Matrix View 22 | { 23 | get => Parameters["View"].GetValueMatrix(); 24 | set => Parameters["View"].SetValue(value); 25 | } 26 | 27 | public Matrix Projection 28 | { 29 | get => Parameters["Projection"].GetValueMatrix(); 30 | set => Parameters["Projection"].SetValue(value); 31 | } 32 | 33 | public Vector4 AmbientColor 34 | { 35 | get => Parameters["AmbientColor"].GetValueVector4(); 36 | set => Parameters["AmbientColor"].SetValue(value); 37 | } 38 | 39 | public Vector4 DiffuseColor 40 | { 41 | get => Parameters["DiffuseColor"].GetValueVector4(); 42 | set => Parameters["DiffuseColor"].SetValue(value); 43 | } 44 | 45 | public Vector3 EyePosition 46 | { 47 | get => Parameters["EyePosition"].GetValueVector3(); 48 | set => Parameters["EyePosition"].SetValue(value); 49 | } 50 | 51 | public CollisionShader(GraphicsDevice graphicsDevice, byte[] effectCode) : base(graphicsDevice, effectCode) 52 | { 53 | } 54 | 55 | public CollisionShader(GraphicsDevice graphicsDevice, byte[] effectCode, int index, int count) : base(graphicsDevice, effectCode, index, count) 56 | { 57 | } 58 | 59 | public CollisionShader(Effect cloneSource) : base(cloneSource) 60 | { 61 | } 62 | 63 | public void ApplyWorldView(Matrix world, Matrix view, Matrix projection) 64 | { 65 | World = world; 66 | View = view; 67 | Projection = projection; 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /DarkSoulsModelViewerDX/DebugPrimitives/DbgPrimWireCylinder.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Xna.Framework; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace DarkSoulsModelViewerDX.DebugPrimitives 9 | { 10 | public class DbgPrimWireCylinder : DbgPrimWire 11 | { 12 | public DbgPrimWireCylinder(Transform location, float range, float height, int numSegments, Color color) 13 | { 14 | NameColor = color; 15 | Transform = location; 16 | 17 | float top = height / 2; 18 | float bottom = -top; 19 | 20 | for (int i = 0; i < numSegments; i++) 21 | { 22 | float angle = (1.0f * i / numSegments) * MathHelper.TwoPi; 23 | float x = (float)Math.Cos(angle); 24 | float z = (float)Math.Sin(angle); 25 | //Very last one wraps around to the first one 26 | if (i == numSegments - 1) 27 | { 28 | float x_next = (float)Math.Cos(0); 29 | float z_next = (float)Math.Sin(0); 30 | // Create line to wrap around to first point 31 | //---- Top 32 | AddLine(new Vector3(x, top, z), new Vector3(x_next, top, z_next), color); 33 | //---- Bottom 34 | AddLine(new Vector3(x, bottom, z), new Vector3(x_next, bottom, z_next), color); 35 | } 36 | else 37 | { 38 | float angle_next = (1.0f * (i + 1) / numSegments) * MathHelper.TwoPi; 39 | float x_next = (float)Math.Cos(angle_next); 40 | float z_next = (float)Math.Sin(angle_next); 41 | 42 | // Create line to next point in ring 43 | //---- Top 44 | AddLine(new Vector3(x, top, z), new Vector3(x_next, top, z_next), color); 45 | //---- Bottom 46 | AddLine(new Vector3(x, bottom, z), new Vector3(x_next, bottom, z_next), color); 47 | } 48 | 49 | // Make pillar from top to bottom 50 | AddLine(new Vector3(x, bottom, z), new Vector3(x, top, z), color); 51 | } 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /DarkSoulsModelViewerDX/StructExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Xna.Framework; 2 | using Microsoft.Xna.Framework.Graphics; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace DarkSoulsModelViewerDX 10 | { 11 | public static class StructExtensions 12 | { 13 | public static Vector3 GetCenter(this BoundingBox bb) 14 | { 15 | return (bb.Min + bb.Max) / 2; 16 | } 17 | 18 | public static RasterizerState GetCopyOfState(this RasterizerState rs) 19 | { 20 | return new RasterizerState() 21 | { 22 | CullMode = rs.CullMode, 23 | DepthBias = rs.DepthBias, 24 | DepthClipEnable = rs.DepthClipEnable, 25 | FillMode = rs.FillMode, 26 | MultiSampleAntiAlias = rs.MultiSampleAntiAlias, 27 | Name = rs.Name, 28 | ScissorTestEnable = rs.ScissorTestEnable, 29 | SlopeScaleDepthBias = rs.SlopeScaleDepthBias, 30 | }; 31 | } 32 | 33 | public static Vector2 TopLeftCorner(this Rectangle r) => new Vector2(r.Left, r.Top); 34 | public static Vector2 TopRightCorner(this Rectangle r) => new Vector2(r.Right, r.Top); 35 | public static Vector2 BottomLeftCorner(this Rectangle r) => new Vector2(r.Left, r.Bottom); 36 | public static Vector2 BottomRightCorner(this Rectangle r) => new Vector2(r.Right, r.Bottom); 37 | public static Vector2 Center(this Rectangle r) => new Vector2(r.Center.X, r.Center.Y); 38 | 39 | public static Rectangle GetUniformShrunkFromBorder(this Rectangle r, int shrinkAmount) 40 | { 41 | return new Rectangle(Math.Min(r.X + shrinkAmount, r.X + r.Width / 2), 42 | Math.Min(r.Y + shrinkAmount, r.Y + r.Height / 2), 43 | Math.Max(r.Width - shrinkAmount * 2, 0), 44 | Math.Max(r.Height - shrinkAmount * 2, 0)); 45 | } 46 | 47 | public static Vector3 Rad2Deg(this Vector3 v) 48 | { 49 | return new Vector3(MathHelper.ToDegrees(v.X), MathHelper.ToDegrees(v.Y), MathHelper.ToDegrees(v.Z)); 50 | } 51 | 52 | public static Vector3 Deg2Rad(this Vector3 v) 53 | { 54 | return new Vector3(MathHelper.ToRadians(v.X), MathHelper.ToRadians(v.Y), MathHelper.ToRadians(v.Z)); 55 | } 56 | 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /DarkSoulsModelViewerDX/DbgMenus/DbgMenuItemTaskKiller.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Xna.Framework; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace DarkSoulsModelViewerDX.DbgMenus 9 | { 10 | public class DbgMenuItemTaskKiller : DbgMenuItem 11 | { 12 | private Dictionary MapMenuEntriesToTaskKeys 13 | = new Dictionary(); 14 | 15 | public DbgMenuItemTaskKiller() 16 | { 17 | BuildSceneItems(); 18 | } 19 | 20 | private List baseMenuItems = new List 21 | { 22 | new DbgMenuItem() 23 | { 24 | Text = "Cyan = Task is running.", 25 | CustomColorFunction = () => Color.Cyan 26 | }, 27 | new DbgMenuItem() 28 | { 29 | Text = "Red = Task is marked to be killed when it gets to a stopping point.", 30 | CustomColorFunction = () => Color.Red 31 | }, 32 | new DbgMenuItem() 33 | { 34 | Text = @"<-- CLICK TASK BELOW TO KILL -->", 35 | }, 36 | }; 37 | 38 | private void BuildSceneItems() 39 | { 40 | lock (LoadingTaskMan._lock_TaskDictEdit) 41 | { 42 | MapMenuEntriesToTaskKeys.Clear(); 43 | Items.Clear(); 44 | 45 | foreach (var it in baseMenuItems) 46 | { 47 | Items.Add(it); 48 | } 49 | 50 | foreach (var kvp in LoadingTaskMan.TaskDict) 51 | { 52 | var menuItem = new DbgMenuItem() 53 | { 54 | ClickAction = (m) => LoadingTaskMan.KillTask(kvp.Key), 55 | RefreshTextFunction = () => $"{kvp.Key} [{kvp.Value.ProgressRatio:0.00}] [\"{kvp.Value.DisplayString}\"]", 56 | CustomColorFunction = () => kvp.Value.IsBeingKilledManually ? Color.Red : Color.Cyan 57 | }; 58 | 59 | Items.Add(menuItem); 60 | MapMenuEntriesToTaskKeys.Add(menuItem, kvp.Key); 61 | } 62 | 63 | RequestTextRefresh(); 64 | } 65 | } 66 | 67 | public override void UpdateUI() 68 | { 69 | if (CurrentMenu == this) 70 | { 71 | // If the amount of models changes, just rebuild the whole thing. 72 | if (Items.Count != (LoadingTaskMan.TaskDict.Count + baseMenuItems.Count)) 73 | { 74 | BuildSceneItems(); 75 | } 76 | 77 | RequestTextRefresh(); 78 | } 79 | 80 | base.UpdateUI(); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /DarkSoulsModelViewerDX/Utils.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Xna.Framework; 2 | using System; 3 | using System.Text; 4 | 5 | namespace DarkSoulsModelViewerDX 6 | { 7 | public static class Utils 8 | { 9 | private static double GetColorComponent(double temp1, double temp2, double temp3) 10 | { 11 | double num; 12 | temp3 = Utils.MoveIntoRange(temp3); 13 | if (temp3 < 0.166666666666667) 14 | { 15 | num = temp1 + (temp2 - temp1) * 6 * temp3; 16 | } 17 | else if (temp3 >= 0.5) 18 | { 19 | num = (temp3 >= 0.666666666666667 ? temp1 : temp1 + (temp2 - temp1) * (0.666666666666667 - temp3) * 6); 20 | } 21 | else 22 | { 23 | num = temp2; 24 | } 25 | return num; 26 | } 27 | 28 | private static double GetTemp2(float H, float S, float L) 29 | { 30 | double temp2; 31 | temp2 = ((double)L >= 0.5 ? (double)(L + S - L * S) : (double)L * (1 + (double)S)); 32 | return temp2; 33 | } 34 | 35 | public static Color HSLtoRGB(float H, float S, float L) 36 | { 37 | double r = 0; 38 | double g = 0; 39 | double b = 0; 40 | if (L != 0f) 41 | { 42 | if (S != 0f) 43 | { 44 | double temp2 = Utils.GetTemp2(H, S, L); 45 | double temp1 = 2 * (double)L - temp2; 46 | r = Utils.GetColorComponent(temp1, temp2, (double)H + 0.333333333333333); 47 | g = Utils.GetColorComponent(temp1, temp2, (double)H); 48 | b = Utils.GetColorComponent(temp1, temp2, (double)H - 0.333333333333333); 49 | } 50 | else 51 | { 52 | double l = (double)L; 53 | b = l; 54 | g = l; 55 | r = l; 56 | } 57 | } 58 | Color color = Color.FromNonPremultiplied(new Vector4((float)r, (float)g, (float)b, 1f)); 59 | return color; 60 | } 61 | 62 | private static double MoveIntoRange(double temp3) 63 | { 64 | if (temp3 < 0) 65 | { 66 | temp3 += 1; 67 | } 68 | else if (temp3 > 1) 69 | { 70 | temp3 -= 1; 71 | } 72 | return temp3; 73 | } 74 | 75 | public static string Frankenpath(params string[] pathParts) 76 | { 77 | StringBuilder sb = new StringBuilder(); 78 | 79 | for (int i = 0; i < pathParts.Length; i++) 80 | { 81 | sb.Append(pathParts[i].Trim('\\')); 82 | if (i < pathParts.Length - 1) 83 | sb.Append('\\'); 84 | } 85 | 86 | return sb.ToString(); 87 | } 88 | } 89 | } -------------------------------------------------------------------------------- /DarkSoulsModelViewerDX/DbgMenus/DbgMenuItemResolutionChange.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Xna.Framework.Graphics; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace DarkSoulsModelViewerDX.DbgMenus 9 | { 10 | public class DbgMenuItemResolutionChange : DbgMenuItem 11 | { 12 | private List supportedModes; 13 | private int modeIndex = 0; 14 | 15 | public DbgMenuItemResolutionChange() 16 | { 17 | supportedModes = Main.GetAllResolutions(); 18 | modeIndex = supportedModes.IndexOf(GraphicsAdapter.DefaultAdapter.CurrentDisplayMode); 19 | UpdateText(); 20 | } 21 | 22 | private void UpdateText() 23 | { 24 | Text = $"Display Mode: {supportedModes[modeIndex].Width}x{supportedModes[modeIndex].Height} " + 25 | $"({GetSurfaceFormatFriendlyName(supportedModes[modeIndex].Format)})"; 26 | } 27 | 28 | public override void OnIncrease(bool isRepeat, int incrementAmount) 29 | { 30 | int prevIndex = modeIndex; 31 | modeIndex += incrementAmount; 32 | 33 | //If upper bound reached 34 | if (modeIndex >= supportedModes.Count) 35 | { 36 | //If already at end and just tapped button 37 | if (prevIndex == supportedModes.Count - 1 && !isRepeat) 38 | modeIndex = 0; //Wrap Around 39 | else 40 | modeIndex = supportedModes.Count - 1; //Stop 41 | } 42 | 43 | GFX.Display.SetFromDisplayMode(supportedModes[modeIndex]); 44 | 45 | UpdateText(); 46 | } 47 | 48 | public override void OnDecrease(bool isRepeat, int incrementAmount) 49 | { 50 | int prevIndex = modeIndex; 51 | modeIndex -= incrementAmount; 52 | 53 | //If upper bound reached 54 | if (modeIndex < 0) 55 | { 56 | //If already at end and just tapped button 57 | if (prevIndex == 0 && !isRepeat) 58 | modeIndex = supportedModes.Count - 1; //Wrap Around 59 | else 60 | modeIndex = 0; //Stop 61 | } 62 | 63 | GFX.Display.SetFromDisplayMode(supportedModes[modeIndex]); 64 | 65 | UpdateText(); 66 | } 67 | 68 | public override void OnResetDefault() 69 | { 70 | base.OnResetDefault(); 71 | } 72 | 73 | private string GetSurfaceFormatFriendlyName(SurfaceFormat f) 74 | { 75 | switch(f) 76 | { 77 | case SurfaceFormat.Color: 78 | return "32-Bit"; 79 | default: 80 | return $"<{nameof(SurfaceFormat)}.{f.ToString()}>"; 81 | } 82 | } 83 | 84 | public override void OnRequestTextRefresh() 85 | { 86 | UpdateText(); 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /DarkSoulsModelViewerDX/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /DarkSoulsModelViewerDX/DbgMenus/DbgMenuItemGfxFlverShaderAdjust.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Xna.Framework; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace DarkSoulsModelViewerDX.DbgMenus 9 | { 10 | public class DbgMenuItemGfxFlverShaderAdjust : DbgMenuItem 11 | { 12 | private void AddVector4(string name) 13 | { 14 | Vector4 GetVector4() 15 | { 16 | return GFX.FlverShader.Effect.Parameters[name].GetValueVector4(); 17 | } 18 | 19 | void SetVector4(float x, float y, float z, float w) 20 | { 21 | GFX.FlverShader.Effect.Parameters[name].SetValue(new Vector4(x, y, z, w)); 22 | } 23 | 24 | Items.Add(new DbgMenuItemNumber($"{name}.X", 0, 1, 0.01f, 25 | f => 26 | { 27 | var v = GetVector4(); 28 | SetVector4(f, v.Y, v.Z, v.W); 29 | }, 30 | () => GetVector4().X)); 31 | Items.Add(new DbgMenuItemNumber($"{name}.Y", 0, 1, 0.01f, 32 | f => 33 | { 34 | var v = GetVector4(); 35 | SetVector4(v.X, f, v.Z, v.W); 36 | }, 37 | () => GetVector4().Y)); 38 | Items.Add(new DbgMenuItemNumber($"{name}.Z", 0, 1, 0.01f, 39 | f => 40 | { 41 | var v = GetVector4(); 42 | SetVector4(v.X, v.Y, f, v.W); 43 | }, 44 | () => GetVector4().Z)); 45 | Items.Add(new DbgMenuItemNumber($"{name}.W", 0, 1, 0.01f, 46 | f => 47 | { 48 | var v = GetVector4(); 49 | SetVector4(v.X, v.Y, v.Z, f); 50 | }, 51 | () => GetVector4().W)); 52 | } 53 | 54 | private void AddFloat(string name) 55 | { 56 | Items.Add(new DbgMenuItemNumber(name, 0, 10, 0.01f, 57 | (f) => GFX.FlverShader.Effect.Parameters[name].SetValue(f), 58 | () => GFX.FlverShader.Effect.Parameters[name].GetValueSingle())); 59 | } 60 | 61 | public DbgMenuItemGfxFlverShaderAdjust() 62 | { 63 | Text = "[GFX.FlverShader]"; 64 | 65 | AddVector4("AmbientColor"); 66 | AddFloat("AmbientIntensity"); 67 | 68 | AddVector4("DiffuseColor"); 69 | AddFloat("DiffuseIntensity"); 70 | 71 | AddVector4("SpecularColor"); 72 | AddFloat("SpecularPower"); 73 | 74 | //AddVector4("LightColor"); 75 | 76 | AddFloat("NormalMapCustomZ"); 77 | } 78 | 79 | public override void UpdateUI() 80 | { 81 | foreach (var item in Items) 82 | { 83 | if (item is DbgMenuItemNumber num) 84 | num.UpdateText(); 85 | } 86 | } 87 | 88 | public override void OnRequestTextRefresh() 89 | { 90 | UpdateUI(); 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /DarkSoulsModelViewerDX/DbgMenus/DbgMenuItemNumber.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace DarkSoulsModelViewerDX.DbgMenus 8 | { 9 | public class DbgMenuItemNumber : DbgMenuItem 10 | { 11 | public readonly string Name; 12 | public readonly float MinValue = 0; 13 | public readonly float MaxValue = 1; 14 | public readonly float BaseChangeAmount; 15 | public readonly Action SetValue; 16 | public readonly Func GetValue; 17 | public readonly Func GetValueString; 18 | public readonly float DefaultValue; 19 | 20 | public DbgMenuItemNumber(string name, float min, float max, float change, 21 | Action setValue, Func getValue, Func getValueString = null) 22 | { 23 | Name = name; 24 | MinValue = min; 25 | MaxValue = max; 26 | BaseChangeAmount = change; 27 | SetValue = setValue; 28 | GetValue = getValue; 29 | GetValueString = getValueString ?? new Func((f) => f.ToString()); 30 | 31 | DefaultValue = GetValue.Invoke(); 32 | 33 | UpdateText(); 34 | } 35 | 36 | public void UpdateText() 37 | { 38 | Text = $"{Name}: <{(GetValueString.Invoke(GetValue.Invoke()))}>"; 39 | } 40 | 41 | public override void OnIncrease(bool isRepeat, int incrementAmount) 42 | { 43 | float prevValue = GetValue.Invoke(); 44 | float newValue = prevValue + incrementAmount * BaseChangeAmount; 45 | 46 | //If upper bound reached 47 | if (newValue >= MaxValue) 48 | { 49 | //If already at end and just tapped button 50 | if (prevValue == MaxValue && !isRepeat) 51 | newValue = MinValue; //Wrap Around 52 | else 53 | newValue = MaxValue; //Stop 54 | } 55 | 56 | SetValue.Invoke(newValue); 57 | 58 | UpdateText(); 59 | } 60 | 61 | public override void OnDecrease(bool isRepeat, int incrementAmount) 62 | { 63 | float prevValue = GetValue.Invoke(); 64 | float newValue = prevValue - incrementAmount * BaseChangeAmount; 65 | 66 | //If lower bound reached 67 | if (newValue <= MinValue) 68 | { 69 | //If already at start and just tapped button 70 | if (prevValue == MinValue && !isRepeat) 71 | newValue = MaxValue; //Wrap Around 72 | else 73 | newValue = MinValue; //Stop 74 | } 75 | 76 | SetValue.Invoke(newValue); 77 | 78 | UpdateText(); 79 | } 80 | 81 | public override void OnResetDefault() 82 | { 83 | SetValue.Invoke(DefaultValue); 84 | UpdateText(); 85 | base.OnResetDefault(); 86 | } 87 | 88 | public override void OnRequestTextRefresh() 89 | { 90 | UpdateText(); 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /SoulsFormats/SoulsFormats/Formats/TPF.DDS.cs: -------------------------------------------------------------------------------- 1 | namespace SoulsFormats 2 | { 3 | public partial class TPF : SoulsFile 4 | { 5 | public class DDS 6 | { 7 | public int dwFlags; 8 | public int dwHeight; 9 | public int dwWidth; 10 | public int dwPitchOrLinearSize; 11 | public int dwDepth; 12 | public int dwMipMapCount; 13 | public PIXELFORMAT ddspf; 14 | public int dwCaps; 15 | public int dwCaps2; 16 | public HEADER_DXT10 header10; 17 | 18 | public long dataOffset; 19 | 20 | public DDS(byte[] bytes) 21 | { 22 | BinaryReaderEx br = new BinaryReaderEx(false, bytes); 23 | br.AssertASCII("DDS "); 24 | br.AssertInt32(124); 25 | dwFlags = br.ReadInt32(); 26 | dwHeight = br.ReadInt32(); 27 | dwWidth = br.ReadInt32(); 28 | dwPitchOrLinearSize = br.ReadInt32(); 29 | dwDepth = br.ReadInt32(); 30 | dwMipMapCount = br.ReadInt32(); 31 | 32 | // dwReserved1 33 | br.Skip(4 * 11); 34 | 35 | ddspf = new PIXELFORMAT(br); 36 | dwCaps = br.ReadInt32(); 37 | dwCaps2 = br.ReadInt32(); 38 | 39 | // dwCaps3, dwCaps4, dwReserved2 40 | br.Skip(4 * 3); 41 | 42 | if (ddspf.dwFourCC == "DX10") 43 | header10 = new HEADER_DXT10(br); 44 | else 45 | header10 = null; 46 | 47 | dataOffset = br.Position; 48 | } 49 | 50 | public class PIXELFORMAT 51 | { 52 | public uint dwFlags; 53 | public string dwFourCC; 54 | public int dwRGBBitCount; 55 | public uint dwRBitMask; 56 | public uint dwGBitMask; 57 | public uint dwBBitMask; 58 | public uint dwABitMask; 59 | 60 | public PIXELFORMAT(BinaryReaderEx br) 61 | { 62 | br.AssertInt32(32); 63 | dwFlags = br.ReadUInt32(); 64 | dwFourCC = br.ReadASCII(4); 65 | dwRGBBitCount = br.ReadInt32(); 66 | dwRBitMask = br.ReadUInt32(); 67 | dwGBitMask = br.ReadUInt32(); 68 | dwBBitMask = br.ReadUInt32(); 69 | dwABitMask = br.ReadUInt32(); 70 | } 71 | } 72 | 73 | public class HEADER_DXT10 74 | { 75 | public uint dxgiFormat; 76 | public uint resourceDimension; 77 | public uint miscFlag; 78 | public uint arraySize; 79 | public uint miscFlags2; 80 | 81 | public HEADER_DXT10(BinaryReaderEx br) 82 | { 83 | dxgiFormat = br.ReadUInt32(); 84 | resourceDimension = br.ReadUInt32(); 85 | miscFlag = br.ReadUInt32(); 86 | arraySize = br.ReadUInt32(); 87 | miscFlags2 = br.ReadUInt32(); 88 | } 89 | } 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /SoulsFormats/SoulsFormats/Formats/DDS.cs: -------------------------------------------------------------------------------- 1 | namespace SoulsFormats 2 | { 3 | /// 4 | /// Read-only parser for .dds texture file headers. 5 | /// 6 | public class DDS 7 | { 8 | #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member 9 | public int dwFlags; 10 | public int dwHeight; 11 | public int dwWidth; 12 | public int dwPitchOrLinearSize; 13 | public int dwDepth; 14 | public int dwMipMapCount; 15 | public PIXELFORMAT ddspf; 16 | public int dwCaps; 17 | public int dwCaps2; 18 | public HEADER_DXT10 header10; 19 | 20 | public long dataOffset; 21 | 22 | public DDS(byte[] bytes) 23 | { 24 | BinaryReaderEx br = new BinaryReaderEx(false, bytes); 25 | 26 | br.AssertASCII("DDS "); 27 | br.AssertInt32(124); 28 | dwFlags = br.ReadInt32(); 29 | dwHeight = br.ReadInt32(); 30 | dwWidth = br.ReadInt32(); 31 | dwPitchOrLinearSize = br.ReadInt32(); 32 | dwDepth = br.ReadInt32(); 33 | dwMipMapCount = br.ReadInt32(); 34 | 35 | // dwReserved1 36 | br.Skip(4 * 11); 37 | 38 | ddspf = new PIXELFORMAT(br); 39 | dwCaps = br.ReadInt32(); 40 | dwCaps2 = br.ReadInt32(); 41 | 42 | // dwCaps3, dwCaps4, dwReserved2 43 | br.Skip(4 * 3); 44 | 45 | if (ddspf.dwFourCC == "DX10") 46 | header10 = new HEADER_DXT10(br); 47 | else 48 | header10 = null; 49 | 50 | dataOffset = br.Position; 51 | 52 | } 53 | 54 | public class PIXELFORMAT 55 | { 56 | public uint dwFlags; 57 | public string dwFourCC; 58 | public int dwRGBBitCount; 59 | public uint dwRBitMask; 60 | public uint dwGBitMask; 61 | public uint dwBBitMask; 62 | public uint dwABitMask; 63 | 64 | public PIXELFORMAT(BinaryReaderEx br) 65 | { 66 | br.AssertInt32(32); 67 | dwFlags = br.ReadUInt32(); 68 | dwFourCC = br.ReadASCII(4); 69 | dwRGBBitCount = br.ReadInt32(); 70 | dwRBitMask = br.ReadUInt32(); 71 | dwGBitMask = br.ReadUInt32(); 72 | dwBBitMask = br.ReadUInt32(); 73 | dwABitMask = br.ReadUInt32(); 74 | } 75 | } 76 | 77 | public class HEADER_DXT10 78 | { 79 | public uint dxgiFormat; 80 | public uint resourceDimension; 81 | public uint miscFlag; 82 | public uint arraySize; 83 | public uint miscFlags2; 84 | 85 | public HEADER_DXT10(BinaryReaderEx br) 86 | { 87 | dxgiFormat = br.ReadUInt32(); 88 | resourceDimension = br.ReadUInt32(); 89 | miscFlag = br.ReadUInt32(); 90 | arraySize = br.ReadUInt32(); 91 | miscFlags2 = br.ReadUInt32(); 92 | } 93 | } 94 | #pragma warning restore CS1591 // Missing XML comment for publicly visible type or member 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /SoulsFormats/SoulsFormats/Formats/MSB3/MSB3.LayerSection.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace SoulsFormats 4 | { 5 | public partial class MSB3 6 | { 7 | /// 8 | /// A section containing layers, which probably don't actually do anything. 9 | /// 10 | public class LayerSection : Section 11 | { 12 | internal override string Type => "LAYER_PARAM_ST"; 13 | 14 | /// 15 | /// The layers in this section. 16 | /// 17 | public List Layers; 18 | 19 | internal LayerSection(BinaryReaderEx br, int unk1) : base(br, unk1) 20 | { 21 | Layers = new List(); 22 | } 23 | 24 | /// 25 | /// Returns every layer in the order they will be written. 26 | /// 27 | public override List GetEntries() 28 | { 29 | return Layers; 30 | } 31 | 32 | internal override Layer ReadEntry(BinaryReaderEx br) 33 | { 34 | var layer = new Layer(br); 35 | Layers.Add(layer); 36 | return layer; 37 | } 38 | 39 | internal override void WriteEntries(BinaryWriterEx bw, List entries) 40 | { 41 | for (int i = 0; i < entries.Count; i++) 42 | { 43 | bw.FillInt64($"Offset{i}", bw.Position); 44 | entries[i].Write(bw); 45 | } 46 | } 47 | } 48 | 49 | /// 50 | /// Unknown; seems to have been related to ceremonies but probably unused in release. 51 | /// 52 | public class Layer 53 | { 54 | /// 55 | /// The name of this layer. 56 | /// 57 | public string Name; 58 | 59 | /// 60 | /// Unknown. 61 | /// 62 | public int Unk1, Unk2, Unk3; 63 | 64 | internal Layer(BinaryReaderEx br) 65 | { 66 | long start = br.Position; 67 | 68 | long nameOffset = br.ReadInt64(); 69 | Unk1 = br.ReadInt32(); 70 | Unk2 = br.ReadInt32(); 71 | Unk3 = br.ReadInt32(); 72 | 73 | Name = br.GetUTF16(start + nameOffset); 74 | } 75 | 76 | internal void Write(BinaryWriterEx bw) 77 | { 78 | long start = bw.Position; 79 | 80 | bw.ReserveInt64("NameOffset"); 81 | bw.WriteInt32(Unk1); 82 | bw.WriteInt32(Unk2); 83 | bw.WriteInt32(Unk3); 84 | 85 | bw.FillInt64("NameOffset", bw.Position - start); 86 | bw.WriteUTF16(Name, true); 87 | bw.Pad(8); 88 | } 89 | 90 | /// 91 | /// Returns the name and three values of this layer. 92 | /// 93 | public override string ToString() 94 | { 95 | return $"{Name} ({Unk1}, {Unk2}, {Unk3})"; 96 | } 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /DarkSoulsModelViewerDX/DbgMenus/DbgMenuPadRepeater.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Xna.Framework.Input; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace DarkSoulsModelViewerDX.DbgMenus 9 | { 10 | public enum DbgMenuPadRepeatState 11 | { 12 | ButtonNotHeld, 13 | ButtonHeldInitialWait, 14 | ButtonRepeating 15 | } 16 | 17 | public class DbgMenuPadRepeater 18 | { 19 | public readonly Buttons Button; 20 | public readonly float InitialRepeatDelay; 21 | public readonly float RepeatInterval; 22 | 23 | public bool State = false; 24 | 25 | private bool prevHeldState = false; 26 | 27 | public bool IsInitalButtonTap { get; private set; } = false; 28 | 29 | private DbgMenuPadRepeatState RepeatState = DbgMenuPadRepeatState.ButtonNotHeld; 30 | private float timer = 0; 31 | 32 | 33 | public DbgMenuPadRepeater(Buttons b, float initialRepeatDelay, float repeatInterval) 34 | { 35 | Button = b; 36 | InitialRepeatDelay = initialRepeatDelay; 37 | RepeatInterval = repeatInterval; 38 | } 39 | 40 | public bool Update(GamePadState gamepad, float elapsedSeconds, bool alternateKeyboardInput) 41 | { 42 | bool curHeldState = gamepad.IsButtonDown(Button) || (Main.Active && alternateKeyboardInput); 43 | 44 | if (!curHeldState) 45 | { 46 | RepeatState = DbgMenuPadRepeatState.ButtonNotHeld; 47 | timer = InitialRepeatDelay; 48 | State = false; 49 | IsInitalButtonTap = false; 50 | } 51 | else 52 | { 53 | if (RepeatState == DbgMenuPadRepeatState.ButtonNotHeld) 54 | { 55 | //First frame of pressing button. 56 | if (!prevHeldState && curHeldState) 57 | { 58 | State = true; 59 | IsInitalButtonTap = true; 60 | //Start counting down the initial wait timer. 61 | RepeatState = DbgMenuPadRepeatState.ButtonHeldInitialWait; 62 | timer = InitialRepeatDelay; 63 | } 64 | } 65 | else if (RepeatState == DbgMenuPadRepeatState.ButtonHeldInitialWait) 66 | { 67 | State = false; 68 | IsInitalButtonTap = false; 69 | timer -= elapsedSeconds; 70 | if (timer <= 0) 71 | { 72 | State = true; 73 | RepeatState = DbgMenuPadRepeatState.ButtonRepeating; 74 | timer = RepeatInterval; 75 | } 76 | } 77 | else if (RepeatState == DbgMenuPadRepeatState.ButtonRepeating) 78 | { 79 | State = false; 80 | IsInitalButtonTap = false; 81 | timer -= elapsedSeconds; 82 | if (timer <= 0) 83 | { 84 | State = true; 85 | timer = RepeatInterval; 86 | } 87 | } 88 | } 89 | 90 | prevHeldState = curHeldState; 91 | 92 | 93 | return State; 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /SoulsFormats/SoulsFormats/Formats/MSB64/MSB64.LayerSection.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace SoulsFormats 4 | { 5 | public partial class MSB64 6 | { 7 | /// 8 | /// A section containing layers, which probably don't actually do anything. 9 | /// 10 | public class LayerSection : Section 11 | { 12 | /// 13 | /// The MSB type string for this section. 14 | /// 15 | public override string Type => "LAYER_PARAM_ST"; 16 | 17 | /// 18 | /// The layers in this section. 19 | /// 20 | public List Layers; 21 | 22 | internal LayerSection(BinaryReaderEx br, int unk1) : base(br, unk1) 23 | { 24 | Layers = new List(); 25 | } 26 | 27 | public override List GetEntries() 28 | { 29 | return Layers; 30 | } 31 | 32 | internal override Layer ReadEntry(BinaryReaderEx br) 33 | { 34 | var layer = new Layer(br); 35 | Layers.Add(layer); 36 | return layer; 37 | } 38 | 39 | internal override Layer ReadEntryBB(BinaryReaderEx br) 40 | { 41 | return null; 42 | } 43 | 44 | internal override void WriteEntries(BinaryWriterEx bw, List entries) 45 | { 46 | for (int i = 0; i < entries.Count; i++) 47 | { 48 | bw.FillInt64($"Offset{i}", bw.Position); 49 | entries[i].Write(bw); 50 | } 51 | } 52 | } 53 | 54 | /// 55 | /// Unknown; seems to have been related to ceremonies but probably unused in release. 56 | /// 57 | public class Layer 58 | { 59 | /// 60 | /// The name of this layer. 61 | /// 62 | public string Name; 63 | 64 | /// 65 | /// Unknown. 66 | /// 67 | public int Unk1, Unk2, Unk3; 68 | 69 | internal Layer(BinaryReaderEx br) 70 | { 71 | long start = br.Position; 72 | 73 | long nameOffset = br.ReadInt64(); 74 | Unk1 = br.ReadInt32(); 75 | Unk2 = br.ReadInt32(); 76 | Unk3 = br.ReadInt32(); 77 | 78 | Name = br.GetUTF16(start + nameOffset); 79 | } 80 | 81 | internal void Write(BinaryWriterEx bw) 82 | { 83 | long start = bw.Position; 84 | 85 | bw.ReserveInt64("NameOffset"); 86 | bw.WriteInt32(Unk1); 87 | bw.WriteInt32(Unk2); 88 | bw.WriteInt32(Unk3); 89 | 90 | bw.FillInt64("NameOffset", bw.Position - start); 91 | bw.WriteUTF16(Name, true); 92 | bw.Pad(8); 93 | } 94 | 95 | /// 96 | /// Returns the name and three values of this layer. 97 | /// 98 | public override string ToString() 99 | { 100 | return $"{Name} ({Unk1}, {Unk2}, {Unk3})"; 101 | } 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /SoulsFormats/SoulsFormats/Formats/MSB3/MSB3.RouteSection.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace SoulsFormats 4 | { 5 | public partial class MSB3 6 | { 7 | /// 8 | /// A section containing routes. Purpose unknown. 9 | /// 10 | public class RouteSection : Section 11 | { 12 | internal override string Type => "ROUTE_PARAM_ST"; 13 | 14 | /// 15 | /// The routes in this section. 16 | /// 17 | public List Routes; 18 | 19 | internal RouteSection(BinaryReaderEx br, int unk1) : base(br, unk1) 20 | { 21 | Routes = new List(); 22 | } 23 | 24 | /// 25 | /// Returns every route in the order they will be written. 26 | /// 27 | public override List GetEntries() 28 | { 29 | return Routes; 30 | } 31 | 32 | internal override Route ReadEntry(BinaryReaderEx br) 33 | { 34 | var route = new Route(br); 35 | Routes.Add(route); 36 | return route; 37 | } 38 | 39 | internal override void WriteEntries(BinaryWriterEx bw, List entries) 40 | { 41 | for (int i = 0; i < entries.Count; i++) 42 | { 43 | bw.FillInt64($"Offset{i}", bw.Position); 44 | entries[i].Write(bw); 45 | } 46 | } 47 | } 48 | 49 | /// 50 | /// Unknown. 51 | /// 52 | public class Route 53 | { 54 | /// 55 | /// The name of this route. 56 | /// 57 | public string Name; 58 | 59 | /// 60 | /// Unknown. 61 | /// 62 | public int Unk1, Unk2, Unk3, Unk4; 63 | 64 | internal Route(BinaryReaderEx br) 65 | { 66 | long start = br.Position; 67 | 68 | long nameOffset = br.ReadInt64(); 69 | Unk1 = br.ReadInt32(); 70 | Unk2 = br.ReadInt32(); 71 | Unk3 = br.ReadInt32(); 72 | Unk4 = br.ReadInt32(); 73 | 74 | for (int i = 0; i < 26; i++) 75 | br.AssertInt32(0); 76 | 77 | Name = br.GetUTF16(start + nameOffset); 78 | } 79 | 80 | internal void Write(BinaryWriterEx bw) 81 | { 82 | long start = bw.Position; 83 | 84 | bw.ReserveInt64("NameOffset"); 85 | bw.WriteInt32(Unk1); 86 | bw.WriteInt32(Unk2); 87 | bw.WriteInt32(Unk3); 88 | bw.WriteInt32(Unk4); 89 | 90 | for (int i = 0; i < 26; i++) 91 | bw.WriteInt32(0); 92 | 93 | bw.FillInt64("NameOffset", bw.Position - start); 94 | bw.WriteUTF16(Name, true); 95 | bw.Pad(8); 96 | } 97 | 98 | /// 99 | /// Returns the name and four values of this route. 100 | /// 101 | public override string ToString() 102 | { 103 | return $"{Name} ({Unk1}, {Unk2}, {Unk3}, {Unk4})"; 104 | } 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /DarkSoulsModelViewerDX/DebugPrimitives/DbgPrim.cs: -------------------------------------------------------------------------------- 1 | using DarkSoulsModelViewerDX.GFXShaders; 2 | using Microsoft.Xna.Framework; 3 | using Microsoft.Xna.Framework.Graphics; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace DarkSoulsModelViewerDX.DebugPrimitives 11 | { 12 | public class DbgLabel 13 | { 14 | public Vector3 Position = Vector3.Zero; 15 | public float Height = 0.5f; 16 | public string Text = "?LabelText?"; 17 | public Color Color; 18 | 19 | public DbgLabel(Vector3 position, float height, string text, Color color) 20 | { 21 | Position = position; 22 | Height = height; 23 | Text = text; 24 | Color = color; 25 | } 26 | } 27 | 28 | public abstract class DbgPrim : IDbgPrim 29 | where T : Effect 30 | { 31 | public Transform Transform { get; set; } = Transform.Default; 32 | public string Name { get; set; } 33 | public Color NameColor { get; set; } = Color.Yellow; 34 | 35 | private List DbgLabels = new List(); 36 | 37 | public void AddDbgLabel(Vector3 position, float height, string text, Color color) 38 | { 39 | DbgLabels.Add(new DbgLabel(position, height, text, color)); 40 | } 41 | 42 | public abstract IGFXShader Shader { get; } 43 | 44 | public abstract DbgPrim Instantiate(string newName, Transform newLocation, Color? newNameColor = null); 45 | 46 | /// 47 | /// Set this to choose specific technique(s). 48 | /// Null to just use the current technique. 49 | /// 50 | public virtual string[] ShaderTechniquesSelection => null; 51 | 52 | protected abstract void DrawPrimitive(); 53 | 54 | public void Draw() 55 | { 56 | var techniques = ShaderTechniquesSelection; 57 | 58 | var effect = Shader.Effect; 59 | 60 | if (techniques != null) 61 | { 62 | foreach (var techniqueName in techniques) 63 | { 64 | effect.CurrentTechnique = effect.Techniques[techniqueName]; 65 | foreach (var pass in effect.CurrentTechnique.Passes) 66 | { 67 | GFX.World.ApplyViewToShader(Shader, Transform); 68 | pass.Apply(); 69 | DrawPrimitive(); 70 | } 71 | } 72 | } 73 | else 74 | { 75 | foreach (var pass in effect.CurrentTechnique.Passes) 76 | { 77 | GFX.World.ApplyViewToShader(Shader, Transform); 78 | pass.Apply(); 79 | DrawPrimitive(); 80 | } 81 | } 82 | } 83 | 84 | public void LabelDraw() 85 | { 86 | if (DbgLabels.Count > 0) 87 | { 88 | foreach (var label in DbgLabels) 89 | { 90 | DBG.DrawTextOn3DLocation(Vector3.Transform(label.Position, Transform.WorldMatrix), 91 | label.Text, label.Color, label.Height, startAndEndSpriteBatchForMe: false); 92 | } 93 | } 94 | } 95 | 96 | protected abstract void DisposeBuffers(); 97 | 98 | public void Dispose() 99 | { 100 | DisposeBuffers(); 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /SoulsFormats/SoulsFormats/Formats/MSB64/MSB64.RouteSection.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace SoulsFormats 4 | { 5 | public partial class MSB64 6 | { 7 | /// 8 | /// A section containing routes. Purpose unknown. 9 | /// 10 | public class RouteSection : Section 11 | { 12 | /// 13 | /// The MSB type string for this section. 14 | /// 15 | public override string Type => "ROUTE_PARAM_ST"; 16 | 17 | /// 18 | /// The routes in this section. 19 | /// 20 | public List Routes; 21 | 22 | internal RouteSection(BinaryReaderEx br, int unk1) : base(br, unk1) 23 | { 24 | Routes = new List(); 25 | } 26 | 27 | public override List GetEntries() 28 | { 29 | return Routes; 30 | } 31 | 32 | internal override Route ReadEntry(BinaryReaderEx br) 33 | { 34 | var route = new Route(br); 35 | Routes.Add(route); 36 | return route; 37 | } 38 | 39 | internal override Route ReadEntryBB(BinaryReaderEx br) 40 | { 41 | return null; 42 | } 43 | 44 | internal override void WriteEntries(BinaryWriterEx bw, List entries) 45 | { 46 | for (int i = 0; i < entries.Count; i++) 47 | { 48 | bw.FillInt64($"Offset{i}", bw.Position); 49 | entries[i].Write(bw); 50 | } 51 | } 52 | } 53 | 54 | /// 55 | /// Unknown. 56 | /// 57 | public class Route 58 | { 59 | /// 60 | /// The name of this route. 61 | /// 62 | public string Name; 63 | 64 | /// 65 | /// Unknown. 66 | /// 67 | public int Unk1, Unk2, Unk3, Unk4; 68 | 69 | internal Route(BinaryReaderEx br) 70 | { 71 | long start = br.Position; 72 | 73 | long nameOffset = br.ReadInt64(); 74 | Unk1 = br.ReadInt32(); 75 | Unk2 = br.ReadInt32(); 76 | Unk3 = br.ReadInt32(); 77 | Unk4 = br.ReadInt32(); 78 | 79 | for (int i = 0; i < 26; i++) 80 | br.AssertInt32(0); 81 | 82 | Name = br.GetUTF16(start + nameOffset); 83 | } 84 | 85 | internal void Write(BinaryWriterEx bw) 86 | { 87 | long start = bw.Position; 88 | 89 | bw.ReserveInt64("NameOffset"); 90 | bw.WriteInt32(Unk1); 91 | bw.WriteInt32(Unk2); 92 | bw.WriteInt32(Unk3); 93 | bw.WriteInt32(Unk4); 94 | 95 | for (int i = 0; i < 26; i++) 96 | bw.WriteInt32(0); 97 | 98 | bw.FillInt64("NameOffset", bw.Position - start); 99 | bw.WriteUTF16(Name, true); 100 | bw.Pad(8); 101 | } 102 | 103 | /// 104 | /// Returns the name and four values of this route. 105 | /// 106 | public override string ToString() 107 | { 108 | return $"{Name} ({Unk1}, {Unk2}, {Unk3}, {Unk4})"; 109 | } 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /DarkSoulsModelViewerDX/DbgMenus/DbgMenuItemEnum.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace DarkSoulsModelViewerDX.DbgMenus 8 | { 9 | public class DbgMenuItemEnum : DbgMenuItem 10 | where T : Enum 11 | { 12 | public readonly string Name; 13 | public readonly Action SetValue; 14 | public readonly Func GetValue; 15 | public readonly T DefaultValue; 16 | public readonly T[] EnumValues; 17 | public readonly Dictionary NameOverrides = null; 18 | private int currentValueIndex; 19 | 20 | public DbgMenuItemEnum(string name, Action setValue, Func getValue, 21 | List enumItemsNotToShow = null, Dictionary nameOverrides = null) 22 | { 23 | Name = name; 24 | SetValue = setValue; 25 | GetValue = getValue; 26 | DefaultValue = GetValue.Invoke(); 27 | 28 | var enumValueList = ((T[])Enum.GetValues(typeof(T))).ToList(); 29 | 30 | if (enumItemsNotToShow != null) 31 | { 32 | foreach (var badEgg in enumItemsNotToShow) 33 | { 34 | enumValueList.Remove(badEgg); 35 | } 36 | } 37 | 38 | EnumValues = enumValueList.ToArray(); 39 | 40 | NameOverrides = nameOverrides; 41 | 42 | UpdateText(); 43 | } 44 | 45 | private string GetEnumValueName(T val) 46 | { 47 | if (NameOverrides != null && NameOverrides.ContainsKey(val)) 48 | return NameOverrides[val]; 49 | else 50 | return val.ToString(); 51 | } 52 | 53 | public void UpdateText() 54 | { 55 | var currentValue = GetValue.Invoke(); 56 | currentValueIndex = Array.IndexOf(EnumValues, currentValue); 57 | 58 | Text = $"{Name}: <{GetEnumValueName(currentValue)}>"; 59 | } 60 | 61 | public override void OnIncrease(bool isRepeat, int incrementAmount) 62 | { 63 | int prevIndex = currentValueIndex; 64 | currentValueIndex += incrementAmount; 65 | 66 | //If upper bound reached 67 | if (currentValueIndex >= EnumValues.Length) 68 | { 69 | //If already at end and just tapped button 70 | if (prevIndex == EnumValues.Length - 1 && !isRepeat) 71 | currentValueIndex = 0; //Wrap Around 72 | else 73 | currentValueIndex = EnumValues.Length - 1; //Stop 74 | } 75 | 76 | SetValue.Invoke(EnumValues[currentValueIndex]); 77 | 78 | UpdateText(); 79 | } 80 | 81 | 82 | public override void OnDecrease(bool isRepeat, int incrementAmount) 83 | { 84 | int prevIndex = currentValueIndex; 85 | currentValueIndex -= incrementAmount; 86 | 87 | //If upper bound reached 88 | if (currentValueIndex < 0) 89 | { 90 | //If already at end and just tapped button 91 | if (prevIndex == 0 && !isRepeat) 92 | currentValueIndex = EnumValues.Length - 1; //Wrap Around 93 | else 94 | currentValueIndex = 0; //Stop 95 | } 96 | 97 | SetValue.Invoke(EnumValues[currentValueIndex]); 98 | 99 | UpdateText(); 100 | } 101 | 102 | public override void OnRequestTextRefresh() 103 | { 104 | UpdateText(); 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /DarkSoulsModelViewerDX/DebugPrimitives/DbgPrimWireSphere.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Xna.Framework; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace DarkSoulsModelViewerDX.DebugPrimitives 9 | { 10 | public class DbgPrimWireSphere : DbgPrimWire 11 | { 12 | public DbgPrimWireSphere(Transform location, float radius, int numVerticalSegments, int numSidesPerSegment, Color color) 13 | { 14 | NameColor = color; 15 | Transform = location; 16 | 17 | if (!(numVerticalSegments >= 2)) 18 | throw new ArgumentException($"Number of vertical segments must be >= 2", nameof(numVerticalSegments)); 19 | if (!(numSidesPerSegment >= 3)) 20 | throw new ArgumentException($"Number of sides per vertical segment must be >= 3", nameof(numSidesPerSegment)); 21 | 22 | numVerticalSegments -= 1; 23 | 24 | var topPoint = Vector3.Up * radius; 25 | var bottomPoint = Vector3.Down * radius; 26 | var points = new Vector3[numVerticalSegments, numSidesPerSegment]; 27 | 28 | for (int i = 0; i < numVerticalSegments; i++) 29 | { 30 | for (int j = 0; j < numSidesPerSegment; j++) 31 | { 32 | float horizontalAngle = (1.0f * j / numSidesPerSegment) * MathHelper.TwoPi; 33 | float verticalAngle = ((1.0f * (i + 1) / (numVerticalSegments + 1)) * MathHelper.Pi) - MathHelper.PiOver2; 34 | float altitude = (float)Math.Sin(verticalAngle); 35 | float horizontalDist = (float)Math.Cos(verticalAngle); 36 | points[i, j] = new Vector3((float)Math.Cos(horizontalAngle) * horizontalDist, altitude, (float)Math.Sin(horizontalAngle) * horizontalDist) * radius; 37 | } 38 | } 39 | 40 | for (int i = 0; i < numVerticalSegments; i++) 41 | { 42 | for (int j = 0; j < numSidesPerSegment; j++) 43 | { 44 | // On the bottom, we must connect each to the bottom point 45 | if (i == 0) 46 | { 47 | AddLine(points[i, j], bottomPoint, color); 48 | } 49 | // On the top, we must connect each point to the top 50 | // Note: this isn't "else if" because with 2 segments, 51 | // these are both true for the only ring 52 | if (i == numVerticalSegments - 1) 53 | { 54 | AddLine(points[i, j], topPoint, color); 55 | } 56 | 57 | // Make vertical lines that connect from this 58 | // horizontal ring to the one above 59 | // Since we are connecting 60 | // (current) -> (the one above current) 61 | // we dont need to do this for the very last one. 62 | if (i < numVerticalSegments - 1) 63 | { 64 | AddLine(points[i, j], points[i + 1, j], color); 65 | } 66 | 67 | 68 | // Make lines that connect points horizontally 69 | //---- if we reach end, we must wrap around, 70 | //---- otherwise, simply make line to next one 71 | if (j == numSidesPerSegment - 1) 72 | { 73 | AddLine(points[i, j], points[i, 0], color); 74 | } 75 | else 76 | { 77 | AddLine(points[i, j], points[i, j + 1], color); 78 | } 79 | } 80 | } 81 | 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /DarkSoulsModelViewerDX/DbgMenus/DbgMenuItemGfxDepthStencilStateAdjust.cs: -------------------------------------------------------------------------------- 1 | //using Microsoft.Xna.Framework; 2 | //using Microsoft.Xna.Framework.Graphics; 3 | //using System; 4 | //using System.Collections.Generic; 5 | //using System.Linq; 6 | //using System.Text; 7 | //using System.Threading.Tasks; 8 | 9 | //namespace DarkSoulsModelViewerDX.DbgMenus 10 | //{ 11 | // public class DbgMenuItemGfxDepthStencilStateAdjust : DbgMenuItem 12 | // { 13 | 14 | // public DbgMenuItemGfxDepthStencilStateAdjust() 15 | // { 16 | // Text = "[GFX.DepthStencilStateConfig]"; 17 | 18 | // Items.Add(new DbgMenuItemEnum("StencilPass", 19 | // v => GFX.DepthStencilStateConfig.StencilPass = v, 20 | // () => GFX.DepthStencilStateConfig.StencilPass)); 21 | // // StencilMask 22 | // Items.Add(new DbgMenuItemEnum("StencilFunction", 23 | // v => GFX.DepthStencilStateConfig.StencilFunction = v, 24 | // () => GFX.DepthStencilStateConfig.StencilFunction)); 25 | // Items.Add(new DbgMenuItemEnum("StencilFail", 26 | // v => GFX.DepthStencilStateConfig.StencilFail = v, 27 | // () => GFX.DepthStencilStateConfig.StencilFail)); 28 | // Items.Add(new DbgMenuItemBool("StencilEnable", "True", "False", 29 | // v => GFX.DepthStencilStateConfig.StencilEnable = v, 30 | // () => GFX.DepthStencilStateConfig.StencilEnable)); 31 | // Items.Add(new DbgMenuItemEnum("StencilDepthBufferFail", 32 | // v => GFX.DepthStencilStateConfig.StencilDepthBufferFail = v, 33 | // () => GFX.DepthStencilStateConfig.StencilDepthBufferFail)); 34 | // // ReferenceStencil 35 | // Items.Add(new DbgMenuItemEnum("DepthBufferFunction", 36 | // v => GFX.DepthStencilStateConfig.DepthBufferFunction = v, 37 | // () => GFX.DepthStencilStateConfig.DepthBufferFunction)); 38 | // Items.Add(new DbgMenuItemEnum("CounterClockwiseStencilFunction", 39 | // v => GFX.DepthStencilStateConfig.CounterClockwiseStencilFunction = v, 40 | // () => GFX.DepthStencilStateConfig.CounterClockwiseStencilFunction)); 41 | // // StencilWriteMask 42 | // Items.Add(new DbgMenuItemEnum("CounterClockwiseStencilFail", 43 | // v => GFX.DepthStencilStateConfig.CounterClockwiseStencilFail = v, 44 | // () => GFX.DepthStencilStateConfig.CounterClockwiseStencilFail)); 45 | // Items.Add(new DbgMenuItemEnum("CounterClockwiseStencilDepthBufferFail", 46 | // v => GFX.DepthStencilStateConfig.CounterClockwiseStencilDepthBufferFail = v, 47 | // () => GFX.DepthStencilStateConfig.CounterClockwiseStencilDepthBufferFail)); 48 | // Items.Add(new DbgMenuItemBool("DepthBufferWriteEnable", "True", "False", 49 | // v => GFX.DepthStencilStateConfig.DepthBufferWriteEnable = v, 50 | // () => GFX.DepthStencilStateConfig.DepthBufferWriteEnable)); 51 | // Items.Add(new DbgMenuItemBool("DepthBufferEnable", "True", "False", 52 | // v => GFX.DepthStencilStateConfig.DepthBufferEnable = v, 53 | // () => GFX.DepthStencilStateConfig.DepthBufferEnable)); 54 | // Items.Add(new DbgMenuItemEnum("CounterClockwiseStencilPass", 55 | // v => GFX.DepthStencilStateConfig.CounterClockwiseStencilPass = v, 56 | // () => GFX.DepthStencilStateConfig.CounterClockwiseStencilPass)); 57 | // Items.Add(new DbgMenuItemBool("TwoSidedStencilMode", "True", "False", 58 | // v => GFX.DepthStencilStateConfig.TwoSidedStencilMode = v, 59 | // () => GFX.DepthStencilStateConfig.TwoSidedStencilMode)); 60 | // } 61 | // } 62 | //} 63 | -------------------------------------------------------------------------------- /DarkSoulsModelViewerDX/Transform.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Xna.Framework; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace DarkSoulsModelViewerDX 9 | { 10 | public struct Transform 11 | { 12 | public static readonly Transform Default 13 | = new Transform(Vector3.Zero, Vector3.Zero, Vector3.One); 14 | 15 | public Transform(Vector3 pos, Vector3 rot) 16 | { 17 | Position = pos; 18 | EulerRotation = rot; 19 | Scale = Vector3.One; 20 | } 21 | 22 | public Transform(Vector3 pos, Vector3 rot, Vector3 scale) 23 | { 24 | Position = pos; 25 | EulerRotation = rot; 26 | Scale = scale; 27 | } 28 | 29 | public Transform(float x, float y, float z, float rx, float ry, float rz) 30 | : this(new Vector3(x, y, z), new Vector3(rx, ry, rz)) 31 | { 32 | 33 | } 34 | 35 | public Transform(float x, float y, float z, float rx, float ry, float rz, float sx, float sy, float sz) 36 | : this(new Vector3(x, y, z), new Vector3(rx, ry, rz), new Vector3(sx, sy, sz)) 37 | { 38 | 39 | } 40 | 41 | public Vector3 Position; 42 | public Vector3 EulerRotation; 43 | public Vector3 Scale; 44 | 45 | public Matrix ScaleMatrix => Matrix.CreateScale(Scale); 46 | 47 | public Matrix TranslationMatrix => Matrix.CreateTranslation(Position.X, Position.Y, Position.Z); 48 | public Matrix RotationMatrix => Matrix.CreateRotationY(EulerRotation.Y) 49 | * Matrix.CreateRotationZ(EulerRotation.Z) 50 | * Matrix.CreateRotationX(EulerRotation.X); 51 | 52 | public Matrix RotationMatrixXYZ => Matrix.CreateRotationX(EulerRotation.X) 53 | * Matrix.CreateRotationY(EulerRotation.Y) 54 | * Matrix.CreateRotationZ(EulerRotation.Z); 55 | 56 | 57 | public Matrix WorldMatrix => ScaleMatrix * RotationMatrix * TranslationMatrix; 58 | 59 | public Matrix CameraViewMatrix => Matrix.CreateTranslation(-Position.X, -Position.Y, -Position.Z) 60 | * Matrix.CreateRotationY(EulerRotation.Y) 61 | * Matrix.CreateRotationZ(EulerRotation.Z) 62 | * Matrix.CreateRotationX(EulerRotation.X); 63 | 64 | private static Random rand = new Random(); 65 | public static Transform RandomUnit(bool randomRot = false) 66 | { 67 | float randFloat() => (float)((rand.NextDouble() * 2) - 1); 68 | return new Transform(randFloat(), randFloat(), randFloat(), 69 | randomRot ? (randFloat() * MathHelper.PiOver2) : 0, 70 | randomRot ? (randFloat() * MathHelper.PiOver2) : 0, 71 | randomRot ? (randFloat() * MathHelper.PiOver2) : 0); 72 | } 73 | 74 | public override string ToString() 75 | { 76 | return $"Pos: {Position.ToString()} Rot (deg): {EulerRotation.Rad2Deg().ToString()}"; 77 | } 78 | 79 | public static Transform operator *(Transform a, float b) 80 | { 81 | return new Transform(a.Position * b, a.EulerRotation); 82 | } 83 | 84 | public static Transform operator /(Transform a, float b) 85 | { 86 | return new Transform(a.Position / b, a.EulerRotation); 87 | } 88 | 89 | public static Transform operator +(Transform a, Vector3 b) 90 | { 91 | return new Transform(a.Position + b, a.EulerRotation); 92 | } 93 | 94 | public static Transform operator -(Transform a, Vector3 b) 95 | { 96 | return new Transform(a.Position - b, a.EulerRotation); 97 | } 98 | 99 | public static implicit operator Transform(Vector3 v) 100 | { 101 | return new Transform(v, Vector3.Zero); 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /DarkSoulsModelViewerDX/DbgMenus/DbgMenuItemGfxBlendStateAdjust.cs: -------------------------------------------------------------------------------- 1 | //using Microsoft.Xna.Framework; 2 | //using Microsoft.Xna.Framework.Graphics; 3 | //using System; 4 | //using System.Collections.Generic; 5 | //using System.Linq; 6 | //using System.Text; 7 | //using System.Threading.Tasks; 8 | 9 | //namespace DarkSoulsModelViewerDX.DbgMenus 10 | //{ 11 | // public class DbgMenuItemGfxBlendStateAdjust : DbgMenuItem 12 | // { 13 | 14 | // public DbgMenuItemGfxBlendStateAdjust() 15 | // { 16 | // Text = "[GFX.BlendStateConfig]"; 17 | 18 | // Items.Add(new DbgMenuItemEnum("AlphaBlendFunction", 19 | // v => GFX.BlendStateConfig.AlphaBlendFunction = v, 20 | // () => GFX.BlendStateConfig.AlphaBlendFunction)); 21 | // Items.Add(new DbgMenuItemEnum("AlphaDestinationBlend", 22 | // v => GFX.BlendStateConfig.AlphaDestinationBlend = v, 23 | // () => GFX.BlendStateConfig.AlphaDestinationBlend)); 24 | // Items.Add(new DbgMenuItemEnum("AlphaSourceBlend", 25 | // v => GFX.BlendStateConfig.AlphaSourceBlend = v, 26 | // () => GFX.BlendStateConfig.AlphaSourceBlend)); 27 | 28 | // Items.Add(new DbgMenuItemNumber("BlendFactor.R", 0, 255, 1, v => 29 | // { 30 | // GFX.BlendStateConfig.BlendFactor = new Color( 31 | // (byte)(int)v, 32 | // GFX.BlendStateConfig.BlendFactor.G, 33 | // GFX.BlendStateConfig.BlendFactor.B, 34 | // GFX.BlendStateConfig.BlendFactor.A); 35 | // }, () => GFX.BlendStateConfig.BlendFactor.R)); 36 | 37 | // Items.Add(new DbgMenuItemNumber("BlendFactor.G", 0, 255, 1, v => 38 | // { 39 | // GFX.BlendStateConfig.BlendFactor = new Color( 40 | // GFX.BlendStateConfig.BlendFactor.R, 41 | // (byte)(int)v, 42 | // GFX.BlendStateConfig.BlendFactor.B, 43 | // GFX.BlendStateConfig.BlendFactor.A); 44 | // }, () => GFX.BlendStateConfig.BlendFactor.G)); 45 | 46 | // Items.Add(new DbgMenuItemNumber("BlendFactor.B", 0, 255, 1, v => 47 | // { 48 | // GFX.BlendStateConfig.BlendFactor = new Color( 49 | // GFX.BlendStateConfig.BlendFactor.R, 50 | // GFX.BlendStateConfig.BlendFactor.G, 51 | // (byte)(int)v, 52 | // GFX.BlendStateConfig.BlendFactor.A); 53 | // }, () => GFX.BlendStateConfig.BlendFactor.B)); 54 | 55 | // Items.Add(new DbgMenuItemNumber("BlendFactor.A", 0, 255, 1, v => 56 | // { 57 | // GFX.BlendStateConfig.BlendFactor = new Color( 58 | // GFX.BlendStateConfig.BlendFactor.R, 59 | // GFX.BlendStateConfig.BlendFactor.G, 60 | // GFX.BlendStateConfig.BlendFactor.B, 61 | // (byte)(int)v); 62 | // }, () => GFX.BlendStateConfig.BlendFactor.A)); 63 | 64 | // Items.Add(new DbgMenuItemEnum("ColorBlendFunction", 65 | // v => GFX.BlendStateConfig.ColorBlendFunction = v, 66 | // () => GFX.BlendStateConfig.ColorBlendFunction)); 67 | // Items.Add(new DbgMenuItemEnum("ColorDestinationBlend", 68 | // v => GFX.BlendStateConfig.ColorDestinationBlend = v, 69 | // () => GFX.BlendStateConfig.ColorDestinationBlend)); 70 | // Items.Add(new DbgMenuItemEnum("ColorSourceBlend", 71 | // v => GFX.BlendStateConfig.ColorSourceBlend = v, 72 | // () => GFX.BlendStateConfig.ColorSourceBlend)); 73 | 74 | // Items.Add(new DbgMenuItemBool("IndependentBlendEnable", "True", "False", 75 | // v => GFX.BlendStateConfig.IndependentBlendEnable = v, 76 | // () => GFX.BlendStateConfig.IndependentBlendEnable)); 77 | // } 78 | // } 79 | //} 80 | -------------------------------------------------------------------------------- /DarkSoulsModelViewerDX/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /DarkSoulsModelViewerDX/ModelInstance.cs: -------------------------------------------------------------------------------- 1 | using MeowDSIO.DataFiles; 2 | using Microsoft.Xna.Framework; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using System.Runtime.InteropServices; 9 | 10 | namespace DarkSoulsModelViewerDX 11 | { 12 | public class ModelInstance 13 | { 14 | //[StructLayout(LayoutKind.Sequential, Pack = 1)] 15 | public struct InstanceData 16 | { 17 | public Matrix WorldMatrix; 18 | public Vector2 atlasScale; 19 | public Vector2 atlasOffset; 20 | }; 21 | 22 | public string Name; 23 | public readonly Model ModelReference; 24 | public InstanceData Data; 25 | public Transform Transform; 26 | 27 | //public bool IsVisible 28 | //{ 29 | // get => ModelReference.IsVisible; 30 | // set => ModelReference.IsVisible = value; 31 | //} 32 | public bool IsDummyMapPart = false; 33 | 34 | public int DrawGroup1 = -1; 35 | public int DrawGroup2 = -1; 36 | public int DrawGroup3 = -1; 37 | public int DrawGroup4 = -1; 38 | 39 | public bool DrawgroupMatch(ModelInstance other) 40 | { 41 | return ( 42 | ((DrawGroup1 & other.DrawGroup1) != 0) || 43 | ((DrawGroup2 & other.DrawGroup2) != 0) || 44 | ((DrawGroup3 & other.DrawGroup3) != 0) || 45 | ((DrawGroup4 & other.DrawGroup4) != 0) 46 | ); 47 | } 48 | 49 | public BoundingBox WorldBounds => new BoundingBox( 50 | Vector3.Transform(ModelReference.Bounds.Min, Transform.WorldMatrix), 51 | Vector3.Transform(ModelReference.Bounds.Max, Transform.WorldMatrix) 52 | ); 53 | 54 | public Vector3 GetCenterPoint() 55 | { 56 | return WorldBounds.GetCenter(); 57 | } 58 | 59 | public Vector3 GetTopCenterPoint(float verticalOffset = 0) 60 | { 61 | var absoluteCenter = GetCenterPoint(); 62 | return new Vector3(absoluteCenter.X, WorldBounds.Max.Y + verticalOffset, absoluteCenter.Z); 63 | } 64 | 65 | public Vector3 GetBottomCenterPoint(float verticalOffset = 0) 66 | { 67 | var absoluteCenter = GetCenterPoint(); 68 | return new Vector3(absoluteCenter.X, WorldBounds.Min.Y + verticalOffset, absoluteCenter.Z); 69 | } 70 | 71 | public float GetRoughBoundsDiameter() 72 | { 73 | return ModelReference.Bounds.Min.Length() + ModelReference.Bounds.Max.Length(); 74 | } 75 | 76 | public ModelInstance(string name, Model model, Transform transform, int drawGroup1, int drawGroup2, int drawGroup3, int drawGroup4) 77 | { 78 | Name = name; 79 | ModelReference = model; 80 | Data = new InstanceData(); 81 | Transform = transform; 82 | Data.WorldMatrix = transform.WorldMatrix; 83 | Data.atlasScale = new Vector2(1.0f, 1.0f); 84 | Data.atlasOffset = new Vector2(0.0f, 0.0f); 85 | DrawGroup1 = drawGroup1; 86 | DrawGroup2 = drawGroup2; 87 | DrawGroup3 = drawGroup3; 88 | DrawGroup4 = drawGroup4; 89 | } 90 | 91 | public void DrawDebugInfo() 92 | { 93 | // if (DBG.ShowModelBoundingBoxes) 94 | // DBG.DrawBoundingBox(Model.Bounds, Color.Yellow, Transform); 95 | 96 | // if (DBG.ShowModelSubmeshBoundingBoxes) 97 | // { 98 | // foreach (var sm in Model.Submeshes) 99 | // { 100 | // DBG.DrawBoundingBox(sm.Bounds, Color.Orange, Transform); 101 | // } 102 | // } 103 | 104 | if (DBG.ShowModelNames) 105 | DBG.DrawTextOn3DLocation(GetTopCenterPoint(verticalOffset: 0.25f), Name, Color.Yellow, 0.5f); 106 | } 107 | 108 | //public void TryToLoadTextures() 109 | //{ 110 | // Model.TryToLoadTextures(); 111 | //} 112 | 113 | //public void Dispose() 114 | //{ 115 | // Model.Dispose(); 116 | // Model = null; 117 | 118 | // Name = null; 119 | //} 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /DarkSoulsModelViewerDX.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 12.00 2 | # Visual Studio 15 3 | VisualStudioVersion = 15.0.28010.2048 4 | MinimumVisualStudioVersion = 10.0.40219.1 5 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DarkSoulsModelViewerDX", "DarkSoulsModelViewerDX\DarkSoulsModelViewerDX.csproj", "{D523836E-9BD1-4663-9A49-9F86EB480F2E}" 6 | EndProject 7 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MeowDSIO", "MeowDSIO\MeowDSIO\MeowDSIO.csproj", "{4AD69470-8146-4D20-94F0-DA9844EEE5A2}" 8 | EndProject 9 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SoulsFormats", "SoulsFormats\SoulsFormats\SoulsFormats.csproj", "{22C664BD-877B-44DF-8ECF-2808522469A8}" 10 | EndProject 11 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Dark Souls IO", "Dark Souls IO", "{D1BDEB2B-399D-497D-9D47-7F0C5967661B}" 12 | EndProject 13 | Global 14 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 15 | Debug|Any CPU = Debug|Any CPU 16 | Debug|x64 = Debug|x64 17 | Debug|x86 = Debug|x86 18 | Release|Any CPU = Release|Any CPU 19 | Release|x64 = Release|x64 20 | Release|x86 = Release|x86 21 | EndGlobalSection 22 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 23 | {D523836E-9BD1-4663-9A49-9F86EB480F2E}.Debug|Any CPU.ActiveCfg = Debug|x86 24 | {D523836E-9BD1-4663-9A49-9F86EB480F2E}.Debug|Any CPU.Build.0 = Debug|x86 25 | {D523836E-9BD1-4663-9A49-9F86EB480F2E}.Debug|x64.ActiveCfg = Debug|x64 26 | {D523836E-9BD1-4663-9A49-9F86EB480F2E}.Debug|x64.Build.0 = Debug|x64 27 | {D523836E-9BD1-4663-9A49-9F86EB480F2E}.Debug|x86.ActiveCfg = Debug|x86 28 | {D523836E-9BD1-4663-9A49-9F86EB480F2E}.Debug|x86.Build.0 = Debug|x86 29 | {D523836E-9BD1-4663-9A49-9F86EB480F2E}.Release|Any CPU.ActiveCfg = Release|x86 30 | {D523836E-9BD1-4663-9A49-9F86EB480F2E}.Release|Any CPU.Build.0 = Release|x86 31 | {D523836E-9BD1-4663-9A49-9F86EB480F2E}.Release|x64.ActiveCfg = Release|x64 32 | {D523836E-9BD1-4663-9A49-9F86EB480F2E}.Release|x64.Build.0 = Release|x64 33 | {D523836E-9BD1-4663-9A49-9F86EB480F2E}.Release|x86.ActiveCfg = Release|x86 34 | {D523836E-9BD1-4663-9A49-9F86EB480F2E}.Release|x86.Build.0 = Release|x86 35 | {4AD69470-8146-4D20-94F0-DA9844EEE5A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 36 | {4AD69470-8146-4D20-94F0-DA9844EEE5A2}.Debug|Any CPU.Build.0 = Debug|Any CPU 37 | {4AD69470-8146-4D20-94F0-DA9844EEE5A2}.Debug|x64.ActiveCfg = Debug|x64 38 | {4AD69470-8146-4D20-94F0-DA9844EEE5A2}.Debug|x64.Build.0 = Debug|x64 39 | {4AD69470-8146-4D20-94F0-DA9844EEE5A2}.Debug|x86.ActiveCfg = Debug|Any CPU 40 | {4AD69470-8146-4D20-94F0-DA9844EEE5A2}.Debug|x86.Build.0 = Debug|Any CPU 41 | {4AD69470-8146-4D20-94F0-DA9844EEE5A2}.Release|Any CPU.ActiveCfg = Release|Any CPU 42 | {4AD69470-8146-4D20-94F0-DA9844EEE5A2}.Release|Any CPU.Build.0 = Release|Any CPU 43 | {4AD69470-8146-4D20-94F0-DA9844EEE5A2}.Release|x64.ActiveCfg = Release|x64 44 | {4AD69470-8146-4D20-94F0-DA9844EEE5A2}.Release|x64.Build.0 = Release|x64 45 | {4AD69470-8146-4D20-94F0-DA9844EEE5A2}.Release|x86.ActiveCfg = Release|Any CPU 46 | {4AD69470-8146-4D20-94F0-DA9844EEE5A2}.Release|x86.Build.0 = Release|Any CPU 47 | {22C664BD-877B-44DF-8ECF-2808522469A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 48 | {22C664BD-877B-44DF-8ECF-2808522469A8}.Debug|Any CPU.Build.0 = Debug|Any CPU 49 | {22C664BD-877B-44DF-8ECF-2808522469A8}.Debug|x64.ActiveCfg = Debug|x64 50 | {22C664BD-877B-44DF-8ECF-2808522469A8}.Debug|x64.Build.0 = Debug|x64 51 | {22C664BD-877B-44DF-8ECF-2808522469A8}.Debug|x86.ActiveCfg = Debug|Any CPU 52 | {22C664BD-877B-44DF-8ECF-2808522469A8}.Debug|x86.Build.0 = Debug|Any CPU 53 | {22C664BD-877B-44DF-8ECF-2808522469A8}.Release|Any CPU.ActiveCfg = Release|Any CPU 54 | {22C664BD-877B-44DF-8ECF-2808522469A8}.Release|Any CPU.Build.0 = Release|Any CPU 55 | {22C664BD-877B-44DF-8ECF-2808522469A8}.Release|x64.ActiveCfg = Release|x64 56 | {22C664BD-877B-44DF-8ECF-2808522469A8}.Release|x64.Build.0 = Release|x64 57 | {22C664BD-877B-44DF-8ECF-2808522469A8}.Release|x86.ActiveCfg = Release|Any CPU 58 | {22C664BD-877B-44DF-8ECF-2808522469A8}.Release|x86.Build.0 = Release|Any CPU 59 | EndGlobalSection 60 | GlobalSection(SolutionProperties) = preSolution 61 | HideSolutionNode = FALSE 62 | EndGlobalSection 63 | GlobalSection(NestedProjects) = preSolution 64 | {4AD69470-8146-4D20-94F0-DA9844EEE5A2} = {D1BDEB2B-399D-497D-9D47-7F0C5967661B} 65 | {22C664BD-877B-44DF-8ECF-2808522469A8} = {D1BDEB2B-399D-497D-9D47-7F0C5967661B} 66 | EndGlobalSection 67 | GlobalSection(ExtensibilityGlobals) = postSolution 68 | SolutionGuid = {305964B1-6068-4920-804B-F6729C4A7AED} 69 | EndGlobalSection 70 | EndGlobal 71 | -------------------------------------------------------------------------------- /DarkSoulsModelViewerDX/GFXShaders/FlverShader.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Xna.Framework; 2 | using Microsoft.Xna.Framework.Graphics; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace DarkSoulsModelViewerDX.GFXShaders 10 | { 11 | public class FlverShader : Effect, IGFXShader 12 | { 13 | public FlverShader Effect => this; 14 | 15 | public Matrix World 16 | { 17 | get => Parameters["World"].GetValueMatrix(); 18 | set => Parameters["World"].SetValue(value); 19 | } 20 | 21 | public Matrix View 22 | { 23 | get => Parameters["View"].GetValueMatrix(); 24 | set => Parameters["View"].SetValue(value); 25 | } 26 | 27 | public Matrix Projection 28 | { 29 | get => Parameters["Projection"].GetValueMatrix(); 30 | set => Parameters["Projection"].SetValue(value); 31 | } 32 | 33 | public Vector4 AmbientColor 34 | { 35 | get => Parameters["AmbientColor"].GetValueVector4(); 36 | set => Parameters["AmbientColor"].SetValue(value); 37 | } 38 | 39 | public float AmbientIntensity 40 | { 41 | get => Parameters["AmbientIntensity"].GetValueSingle(); 42 | set => Parameters["AmbientIntensity"].SetValue(value); 43 | } 44 | 45 | public Vector3 LightDirection 46 | { 47 | get => Parameters["LightDirection"].GetValueVector3(); 48 | set => Parameters["LightDirection"].SetValue(value); 49 | } 50 | 51 | public Vector4 DiffuseColor 52 | { 53 | get => Parameters["DiffuseColor"].GetValueVector4(); 54 | set => Parameters["DiffuseColor"].SetValue(value); 55 | } 56 | 57 | public float DiffuseIntensity 58 | { 59 | get => Parameters["DiffuseIntensity"].GetValueSingle(); 60 | set => Parameters["DiffuseIntensity"].SetValue(value); 61 | } 62 | 63 | public Vector4 SpecularColor 64 | { 65 | get => Parameters["SpecularColor"].GetValueVector4(); 66 | set => Parameters["SpecularColor"].SetValue(value); 67 | } 68 | 69 | public float SpecularPower 70 | { 71 | get => Parameters["SpecularPower"].GetValueSingle(); 72 | set => Parameters["SpecularPower"].SetValue(value); 73 | } 74 | 75 | public Vector3 EyePosition 76 | { 77 | get => Parameters["EyePosition"].GetValueVector3(); 78 | set => Parameters["EyePosition"].SetValue(value); 79 | } 80 | 81 | public float NormalMapCustomZ 82 | { 83 | get => Parameters["NormalMapCustomZ"].GetValueSingle(); 84 | set => Parameters["NormalMapCustomZ"].SetValue(value); 85 | } 86 | 87 | public Texture2D ColorMap 88 | { 89 | get => Parameters["ColorMap"].GetValueTexture2D(); 90 | set => Parameters["ColorMap"].SetValue(value); 91 | } 92 | 93 | public Texture2D NormalMap 94 | { 95 | get => Parameters["NormalMap"].GetValueTexture2D(); 96 | set => Parameters["NormalMap"].SetValue(value); 97 | } 98 | 99 | public Texture2D SpecularMap 100 | { 101 | get => Parameters["SpecularMap"].GetValueTexture2D(); 102 | set => Parameters["SpecularMap"].SetValue(value); 103 | } 104 | 105 | public Texture2D LightMap1 106 | { 107 | get => Parameters["LightMap1"].GetValueTexture2D(); 108 | set => Parameters["LightMap1"].SetValue(value); 109 | } 110 | 111 | public Texture2D LightMap2 112 | { 113 | get => Parameters["LightMap2"].GetValueTexture2D(); 114 | set => Parameters["LightMap2"].SetValue(value); 115 | } 116 | 117 | public FlverShader(GraphicsDevice graphicsDevice, byte[] effectCode) : base(graphicsDevice, effectCode) 118 | { 119 | } 120 | 121 | public FlverShader(GraphicsDevice graphicsDevice, byte[] effectCode, int index, int count) : base(graphicsDevice, effectCode, index, count) 122 | { 123 | } 124 | 125 | public FlverShader(Effect cloneSource) : base(cloneSource) 126 | { 127 | } 128 | 129 | public void ApplyWorldView(Matrix world, Matrix view, Matrix projection) 130 | { 131 | World = world; 132 | View = view; 133 | Projection = projection; 134 | } 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /DarkSoulsModelViewerDX/DebugPrimitives/DbgPrimWire.cs: -------------------------------------------------------------------------------- 1 | using DarkSoulsModelViewerDX.GFXShaders; 2 | using Microsoft.Xna.Framework; 3 | using Microsoft.Xna.Framework.Graphics; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace DarkSoulsModelViewerDX.DebugPrimitives 11 | { 12 | public class DbgPrimWire : DbgPrim 13 | { 14 | public override IGFXShader Shader => GFX.DbgPrimShader; 15 | 16 | private int[] Indices = new int[0]; 17 | private VertexPositionColor[] Vertices = new VertexPositionColor[0]; 18 | private VertexBuffer VertBuffer; 19 | private IndexBuffer IndexBuffer; 20 | private bool NeedToRecreateVertBuffer = true; 21 | private bool NeedToRecreateIndexBuffer = true; 22 | 23 | public int VertexCount => Vertices.Length; 24 | public int LineCount => Indices.Length / 2; 25 | public int IndexCount => Indices.Length; 26 | 27 | private void AddVertex(Vector3 pos, Color color) 28 | { 29 | Array.Resize(ref Vertices, Vertices.Length + 1); 30 | Vertices[Vertices.Length - 1].Position = pos; 31 | Vertices[Vertices.Length - 1].Color = color; 32 | 33 | NeedToRecreateVertBuffer = true; 34 | } 35 | 36 | private void AddVertex(VertexPositionColor vert) 37 | { 38 | Array.Resize(ref Vertices, Vertices.Length + 1); 39 | Vertices[Vertices.Length - 1] = vert; 40 | 41 | NeedToRecreateVertBuffer = true; 42 | } 43 | 44 | private void AddIndex(int index) 45 | { 46 | Array.Resize(ref Indices, Indices.Length + 1); 47 | Indices[Indices.Length - 1] = index; 48 | NeedToRecreateIndexBuffer = true; 49 | } 50 | 51 | public void AddLine(Vector3 start, Vector3 end, Color color) 52 | { 53 | AddLine(start, end, color, color); 54 | } 55 | 56 | public void AddLine(Vector3 start, Vector3 end, Color startColor, Color endColor) 57 | { 58 | var startVert = new VertexPositionColor(start, startColor); 59 | var endVert = new VertexPositionColor(end, endColor); 60 | int startIndex = Array.IndexOf(Vertices, startVert); 61 | int endIndex = Array.IndexOf(Vertices, endVert); 62 | 63 | //If start vertex can't be recycled from an old one, make a new one. 64 | if (startIndex == -1) 65 | { 66 | AddVertex(startVert); 67 | startIndex = Vertices.Length - 1; 68 | } 69 | 70 | //If end vertex can't be recycled from an old one, make a new one. 71 | if (endIndex == -1) 72 | { 73 | AddVertex(endVert); 74 | endIndex = Vertices.Length - 1; 75 | } 76 | 77 | AddIndex(startIndex); 78 | AddIndex(endIndex); 79 | 80 | if (NeedToRecreateVertBuffer) 81 | { 82 | VertBuffer = new VertexBuffer(GFX.Device, 83 | typeof(VertexPositionColor), Vertices.Length, BufferUsage.WriteOnly); 84 | VertBuffer.SetData(Vertices); 85 | NeedToRecreateVertBuffer = false; 86 | } 87 | 88 | if (NeedToRecreateIndexBuffer) 89 | { 90 | IndexBuffer = new IndexBuffer(GFX.Device, IndexElementSize.ThirtyTwoBits, Indices.Length, BufferUsage.WriteOnly); 91 | IndexBuffer.SetData(Indices); 92 | NeedToRecreateIndexBuffer = false; 93 | } 94 | } 95 | 96 | protected override void DrawPrimitive() 97 | { 98 | GFX.Device.SetVertexBuffer(VertBuffer); 99 | GFX.Device.Indices = IndexBuffer; 100 | GFX.Device.DrawIndexedPrimitives(PrimitiveType.LineList, 0, 0, Indices.Length); 101 | } 102 | 103 | protected override void DisposeBuffers() 104 | { 105 | VertBuffer.Dispose(); 106 | } 107 | 108 | public override DbgPrim Instantiate(string newName, Transform newLocation, Color? newNameColor = null) 109 | { 110 | var newPrim = new DbgPrimWire(); 111 | newPrim.Indices = Indices; 112 | newPrim.VertBuffer = VertBuffer; 113 | newPrim.IndexBuffer = IndexBuffer; 114 | newPrim.Vertices = Vertices; 115 | newPrim.NeedToRecreateVertBuffer = NeedToRecreateVertBuffer; 116 | newPrim.NeedToRecreateIndexBuffer = NeedToRecreateIndexBuffer; 117 | 118 | newPrim.Transform = newLocation; 119 | 120 | newPrim.Name = newName; 121 | 122 | newPrim.NameColor = newNameColor ?? NameColor; 123 | 124 | return newPrim; 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /DarkSoulsModelViewerDX/VertexPositionColorNormalTangentTexture.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Xna.Framework; 2 | using Microsoft.Xna.Framework.Graphics; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Runtime.InteropServices; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace DarkSoulsModelViewerDX 11 | { 12 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 13 | public struct VertexPositionColorNormalTangentTexture : IVertexType 14 | { 15 | public Vector3 Position; 16 | public Vector2 TextureCoordinate; 17 | public Vector2 TextureCoordinate2; 18 | public Vector3 Normal; 19 | public Vector3 Binormal; 20 | public Vector3 Tangent; 21 | public Vector4 Color; 22 | 23 | /// 24 | /// Vertex declaration object. 25 | /// 26 | public static readonly VertexDeclaration VertexDeclaration; 27 | 28 | /// 29 | /// Vertex declaration. 30 | /// 31 | VertexDeclaration IVertexType.VertexDeclaration 32 | { 33 | get 34 | { 35 | return VertexDeclaration; 36 | } 37 | } 38 | 39 | 40 | 41 | /// 42 | /// Static constructor to init vertex declaration. 43 | /// 44 | static VertexPositionColorNormalTangentTexture() 45 | { 46 | VertexElement[] elements = new VertexElement[] { 47 | new VertexElement(sizeof(float) * (0), VertexElementFormat.Vector3, VertexElementUsage.Position, 0), 48 | new VertexElement(sizeof(float) * (0 + 3), VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 0), 49 | new VertexElement(sizeof(float) * (0 + 3 + 2), VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 0), 50 | new VertexElement(sizeof(float) * (0 + 3 + 2 + 2), VertexElementFormat.Vector3, VertexElementUsage.Normal, 0), 51 | new VertexElement(sizeof(float) * (0 + 3 + 2 + 2 + 3), VertexElementFormat.Vector3, VertexElementUsage.Binormal, 0), 52 | new VertexElement(sizeof(float) * (0 + 3 + 2 + 2 + 3 + 3), VertexElementFormat.Vector3, VertexElementUsage.Tangent, 0), 53 | new VertexElement(sizeof(float) * (0 + 3 + 2 + 2 + 3 + 3 + 3), VertexElementFormat.Vector4, VertexElementUsage.Color, 0), 54 | 55 | }; 56 | VertexDeclaration declaration = new VertexDeclaration(elements); 57 | VertexDeclaration = declaration; 58 | } 59 | 60 | /// 61 | /// Get if equals another object. 62 | /// 63 | /// Object to compare to. 64 | /// If objects are equal. 65 | public override bool Equals(object obj) 66 | { 67 | if (obj == null) 68 | { 69 | return false; 70 | } 71 | if (obj.GetType() != base.GetType()) 72 | { 73 | return false; 74 | } 75 | return (this == ((VertexPositionColorNormalTangentTexture)obj)); 76 | } 77 | 78 | /// 79 | /// Get the hash code of this vertex. 80 | /// 81 | /// 82 | public override int GetHashCode() 83 | { 84 | unchecked 85 | { 86 | var hashCode = Position.GetHashCode(); 87 | hashCode = (hashCode * 397) ^ Position.GetHashCode(); 88 | hashCode = (hashCode * 397) ^ Color.GetHashCode(); 89 | hashCode = (hashCode * 397) ^ Normal.GetHashCode(); 90 | hashCode = (hashCode * 397) ^ Binormal.GetHashCode(); 91 | hashCode = (hashCode * 397) ^ Tangent.GetHashCode(); 92 | return hashCode; 93 | } 94 | } 95 | 96 | /// 97 | /// Return if two vertices are equal. 98 | /// 99 | /// Left side to compare. 100 | /// Right side to compare. 101 | /// If equal. 102 | public static bool operator ==(VertexPositionColorNormalTangentTexture left, VertexPositionColorNormalTangentTexture right) 103 | { 104 | return ( 105 | (left.Position == right.Position) && 106 | (left.Color == right.Color) && 107 | (left.Normal == right.Normal) && 108 | (left.Binormal == right.Binormal) && 109 | (left.Tangent == right.Tangent) 110 | ); 111 | } 112 | 113 | /// 114 | /// Return if two vertices are not equal. 115 | /// 116 | /// Left side to compare. 117 | /// Right side to compare. 118 | /// If not equal. 119 | public static bool operator !=(VertexPositionColorNormalTangentTexture left, VertexPositionColorNormalTangentTexture right) 120 | { 121 | return !(left == right); 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /SoulsFormats/SoulsFormats/SoulsFile.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | 3 | namespace SoulsFormats 4 | { 5 | /// 6 | /// A generic From file supporting transparent DCX reading and writing. 7 | /// 8 | public abstract class SoulsFile where TFormat : SoulsFile, new() 9 | { 10 | /// 11 | /// The type of DCX compression to be used when writing. 12 | /// 13 | public DCX.Type Compression = DCX.Type.None; 14 | 15 | /// 16 | /// Returns true if the data appears to be a BND4. 17 | /// 18 | // This should really be a static method, but interfaces do not allow static inheritance; hence the dummy objects below. 19 | internal abstract bool Is(BinaryReaderEx br); 20 | 21 | /// 22 | /// Returns true if the bytes appear to be a file of this type. 23 | /// 24 | public static bool Is(byte[] bytes) 25 | { 26 | if (bytes.Length == 0) 27 | return false; 28 | 29 | BinaryReaderEx br = new BinaryReaderEx(false, bytes); 30 | var dummy = new TFormat(); 31 | return dummy.Is(Util.GetDecompressedBR(br, out _)); 32 | } 33 | 34 | /// 35 | /// Returns true if the file appears to be a file of this type. 36 | /// 37 | public static bool Is(string path) 38 | { 39 | using (FileStream stream = File.OpenRead(path)) 40 | { 41 | if (stream.Length == 0) 42 | return false; 43 | 44 | BinaryReaderEx br = new BinaryReaderEx(false, stream); 45 | var dummy = new TFormat(); 46 | return dummy.Is(Util.GetDecompressedBR(br, out _)); 47 | } 48 | } 49 | 50 | /// 51 | /// Loads file data from a BinaryReaderEx. 52 | /// 53 | internal abstract void Read(BinaryReaderEx br); 54 | 55 | /// 56 | /// Loads a file from a byte array, automatically decompressing it if necessary. 57 | /// 58 | public static TFormat Read(byte[] bytes) 59 | { 60 | BinaryReaderEx br = new BinaryReaderEx(false, bytes); 61 | TFormat file = new TFormat(); 62 | br = Util.GetDecompressedBR(br, out file.Compression); 63 | file.Read(br); 64 | return file; 65 | } 66 | 67 | /// 68 | /// Loads a file from the specified path, automatically decompressing it if necessary. 69 | /// 70 | public static TFormat Read(string path) 71 | { 72 | using (FileStream stream = File.OpenRead(path)) 73 | { 74 | BinaryReaderEx br = new BinaryReaderEx(false, stream); 75 | TFormat file = new TFormat(); 76 | br = Util.GetDecompressedBR(br, out file.Compression); 77 | file.Read(br); 78 | return file; 79 | } 80 | } 81 | 82 | /// 83 | /// Writes file data to a BinaryWriterEx. 84 | /// 85 | internal abstract void Write(BinaryWriterEx bw); 86 | 87 | /// 88 | /// Writes file data to a BinaryWriterEx, compressing it afterwards if specified. 89 | /// 90 | private void Write(BinaryWriterEx bw, DCX.Type compression) 91 | { 92 | if (compression == DCX.Type.None) 93 | { 94 | Write(bw); 95 | } 96 | else 97 | { 98 | BinaryWriterEx bwUncompressed = new BinaryWriterEx(false); 99 | Write(bwUncompressed); 100 | byte[] uncompressed = bwUncompressed.FinishBytes(); 101 | DCX.Compress(uncompressed, bw, compression); 102 | } 103 | } 104 | 105 | /// 106 | /// Writes the file to an array of bytes, automatically compressing it if necessary. 107 | /// 108 | public byte[] Write() 109 | { 110 | return Write(Compression); 111 | } 112 | 113 | /// 114 | /// Writes the file to an array of bytes, compressing it as specified. 115 | /// 116 | public byte[] Write(DCX.Type compression) 117 | { 118 | BinaryWriterEx bw = new BinaryWriterEx(false); 119 | Write(bw, compression); 120 | return bw.FinishBytes(); 121 | } 122 | 123 | /// 124 | /// Writes the file to the specified path, automatically compressing it if necessary. 125 | /// 126 | public void Write(string path) 127 | { 128 | Write(path, Compression); 129 | } 130 | 131 | /// 132 | /// Writes the file to the specified path, compressing it as specified. 133 | /// 134 | public void Write(string path, DCX.Type compression) 135 | { 136 | using (FileStream stream = File.Create(path)) 137 | { 138 | BinaryWriterEx bw = new BinaryWriterEx(false, stream); 139 | Write(bw, compression); 140 | bw.Finish(); 141 | } 142 | } 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /DarkSoulsModelViewerDX/DbgMenus/DbgMenuItemSpawnChr.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.IO; 3 | using System.Linq; 4 | using System.Windows.Forms; 5 | using System; 6 | 7 | namespace DarkSoulsModelViewerDX.DbgMenus 8 | { 9 | public class DbgMenuItemSpawnChr : DbgMenuItem 10 | { 11 | public static List IDList = new List(); 12 | private static bool NeedsTextUpdate = false; 13 | 14 | public int IDIndex = 0; 15 | 16 | public DbgMenuItemSpawnChr() 17 | { 18 | UpdateSpawnIDs(); 19 | UpdateText(); 20 | } 21 | 22 | public static void UpdateSpawnIDs() 23 | { 24 | try 25 | { 26 | var path = (InterrootLoader.Type == InterrootLoader.InterrootType.InterrootDS2) ? @"\model\chr\" : @"\chr\"; 27 | var extensionBase = (InterrootLoader.Type == InterrootLoader.InterrootType.InterrootDS2 || InterrootLoader.Type == InterrootLoader.InterrootType.InterrootNB) ? @"*.bnd" : @"*.chrbnd"; 28 | var chrFiles = Directory.GetFiles(InterrootLoader.GetInterrootPath(path), extensionBase) 29 | .Select(Path.GetFileNameWithoutExtension); 30 | if (InterrootLoader.Type == InterrootLoader.InterrootType.InterrootDeS) 31 | { 32 | chrFiles = Directory.GetFileSystemEntries(InterrootLoader.GetInterrootPath(path), "c*").Select(Path.GetFileNameWithoutExtension); 33 | } 34 | IDList = new List(); 35 | var IDSet = new HashSet(); 36 | foreach (var cf in chrFiles) 37 | { 38 | if (int.TryParse(cf.Substring(1, 4), out int id)) 39 | { 40 | IDList.Add(id); 41 | IDSet.Add(id); 42 | } 43 | } 44 | 45 | var chrFilesDCX = Directory.GetFiles(InterrootLoader.GetInterrootPath(path), extensionBase + ".dcx") 46 | .Select(Path.GetFileNameWithoutExtension).Select(Path.GetFileNameWithoutExtension); 47 | foreach (var cf in chrFilesDCX) 48 | { 49 | if (int.TryParse(cf.Substring(1, 4), out int id)) 50 | { 51 | if (!IDSet.Contains(id)) 52 | IDList.Add(id); 53 | } 54 | } 55 | NeedsTextUpdate = true; 56 | } 57 | catch (Exception e) 58 | { 59 | IDList = new List(); 60 | NeedsTextUpdate = true; 61 | MessageBox.Show("An error occured when populating the chr list: " + e.Message, e.StackTrace); 62 | } 63 | } 64 | 65 | private void UpdateText() 66 | { 67 | if (IDList.Count == 0) 68 | { 69 | IDIndex = 0; 70 | Text = $"Click to Spawn CHR [Invalid Data Root Selected]"; 71 | } 72 | else 73 | { 74 | if (IDIndex >= IDList.Count) 75 | IDIndex = IDList.Count - 1; 76 | 77 | Text = $"Click to Spawn CHR [ID: ]"; 78 | } 79 | } 80 | 81 | public override void OnIncrease(bool isRepeat, int incrementAmount) 82 | { 83 | int prevIndex = IDIndex; 84 | IDIndex += incrementAmount; 85 | 86 | //If upper bound reached 87 | if (IDIndex >= IDList.Count) 88 | { 89 | //If already at end and just tapped button 90 | if (prevIndex == IDList.Count - 1 && !isRepeat) 91 | IDIndex = 0; //Wrap Around 92 | else 93 | IDIndex = IDList.Count - 1; //Stop 94 | } 95 | 96 | UpdateText(); 97 | } 98 | 99 | public override void OnDecrease(bool isRepeat, int incrementAmount) 100 | { 101 | int prevIndex = IDIndex; 102 | IDIndex -= incrementAmount; 103 | 104 | //If upper bound reached 105 | if (IDIndex < 0) 106 | { 107 | //If already at end and just tapped button 108 | if (prevIndex == 0 && !isRepeat) 109 | IDIndex = IDList.Count - 1; //Wrap Around 110 | else 111 | IDIndex = 0; //Stop 112 | } 113 | 114 | UpdateText(); 115 | } 116 | 117 | public override void OnResetDefault() 118 | { 119 | IDIndex = 0; 120 | UpdateText(); 121 | } 122 | 123 | public override void OnClick() 124 | { 125 | if (IDList.Count == 0) 126 | return; 127 | GFX.ModelDrawer.AddChr(IDList[IDIndex], GFX.World.GetSpawnPointInFrontOfCamera(distance: 5, 128 | faceBackwards: false, lockPitch: true, alignToFloor: true)); 129 | } 130 | 131 | public override void UpdateUI() 132 | { 133 | if (NeedsTextUpdate) 134 | { 135 | UpdateText(); 136 | NeedsTextUpdate = false; 137 | } 138 | } 139 | 140 | public override void OnRequestTextRefresh() 141 | { 142 | UpdateSpawnIDs(); 143 | UpdateText(); 144 | } 145 | } 146 | 147 | } -------------------------------------------------------------------------------- /SoulsFormats/SoulsFormats/Formats/ENFL.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace SoulsFormats 4 | { 5 | /// 6 | /// A mysterious file format used in BB and DS3. Speculation: determines assets to load based on location in a map. Extension: .entryfilelist 7 | /// 8 | public class ENFL : SoulsFile 9 | { 10 | /// 11 | /// Unknown. 12 | /// 13 | public List Struct1s; 14 | 15 | /// 16 | /// Uknown. 17 | /// 18 | public List Struct2s; 19 | 20 | /// 21 | /// A list of file paths. 22 | /// 23 | public List Strings; 24 | 25 | internal override bool Is(BinaryReaderEx br) 26 | { 27 | string magic = br.GetASCII(0, 4); 28 | return magic == "ENFL"; 29 | } 30 | 31 | internal override void Read(BinaryReaderEx br) 32 | { 33 | br.BigEndian = false; 34 | 35 | br.AssertASCII("ENFL"); 36 | // Probably 4 bytes 37 | br.AssertInt32(0x10415); 38 | int compressedSize = br.ReadInt32(); 39 | int uncompressedSize = br.ReadInt32(); 40 | byte[] data = Util.ReadZlib(br, compressedSize); 41 | 42 | br = new BinaryReaderEx(false, data); 43 | br.AssertInt32(0); 44 | int unkCount1 = br.ReadInt32(); 45 | int unkCount2 = br.ReadInt32(); 46 | br.AssertInt32(0); 47 | 48 | Struct1s = new List(); 49 | for (int i = 0; i < unkCount1; i++) 50 | Struct1s.Add(new Struct1(br)); 51 | br.Pad(0x10); 52 | 53 | Struct2s = new List(); 54 | for (int i = 0; i < unkCount2; i++) 55 | Struct2s.Add(new Struct2(br)); 56 | br.Pad(0x10); 57 | 58 | br.AssertInt16(0); 59 | Strings = new List(); 60 | for (int i = 0; i < unkCount2; i++) 61 | Strings.Add(br.ReadUTF16()); 62 | } 63 | 64 | internal override void Write(BinaryWriterEx bw) 65 | { 66 | BinaryWriterEx bwData = new BinaryWriterEx(false); 67 | 68 | bwData.WriteInt32(0); 69 | bwData.WriteInt32(Struct1s.Count); 70 | bwData.WriteInt32(Struct2s.Count); 71 | bwData.WriteInt32(0); 72 | 73 | foreach (Struct1 struct1 in Struct1s) 74 | struct1.Write(bwData); 75 | bwData.Pad(0x10); 76 | 77 | foreach (Struct2 struct2 in Struct2s) 78 | struct2.Write(bwData); 79 | bwData.Pad(0x10); 80 | 81 | bwData.WriteInt16(0); 82 | foreach (string str in Strings) 83 | bwData.WriteUTF16(str, true); 84 | bwData.Pad(0x10); 85 | 86 | byte[] data = bwData.FinishBytes(); 87 | 88 | bw.WriteASCII("ENFL"); 89 | bw.WriteInt32(0x10415); 90 | bw.ReserveInt32("CompressedSize"); 91 | bw.WriteInt32(data.Length); 92 | int compressedSize = Util.WriteZlib(bw, 0xDA, data); 93 | bw.FillInt32("CompressedSize", compressedSize); 94 | } 95 | 96 | /// 97 | /// Some kind of weird iteration through the strings. 98 | /// 99 | public class Struct1 100 | { 101 | /// 102 | /// Increase of index to next Struct1. For instance, if Step is 0, the next Struct1 will have the same index. If Step is 2, the next Struct will have this Index + 2. 103 | /// 104 | public short Step; 105 | 106 | /// 107 | /// Almost certainly an index into the strings. 108 | /// 109 | public short Index; 110 | 111 | internal Struct1(BinaryReaderEx br) 112 | { 113 | Step = br.ReadInt16(); 114 | Index = br.ReadInt16(); 115 | } 116 | 117 | internal void Write(BinaryWriterEx bw) 118 | { 119 | bw.WriteInt16(Step); 120 | bw.WriteInt16(Index); 121 | } 122 | 123 | /// 124 | /// Returns the step and index. 125 | /// 126 | public override string ToString() 127 | { 128 | return $"0x{Step:X4} 0x{Index:X4}"; 129 | } 130 | } 131 | 132 | /// 133 | /// Some data corresponding to each string. Possibly a hash? 134 | /// 135 | public class Struct2 136 | { 137 | /// 138 | /// Almost definitely not a single field. Appears to be 6 bytes of hash and a short in range 0-2, but I don't know. 139 | /// 140 | public long Unk1; 141 | 142 | internal Struct2(BinaryReaderEx br) 143 | { 144 | Unk1 = br.ReadInt64(); 145 | } 146 | 147 | internal void Write(BinaryWriterEx bw) 148 | { 149 | bw.WriteInt64(Unk1); 150 | } 151 | 152 | /// 153 | /// Returns the entire struct as a number. 154 | /// 155 | public override string ToString() 156 | { 157 | return $"0x{Unk1:X16}"; 158 | } 159 | } 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /DarkSoulsModelViewerDX/Tests.cs: -------------------------------------------------------------------------------- 1 | using DarkSoulsModelViewerDX.DbgMenus; 2 | using DarkSoulsModelViewerDX.DebugPrimitives; 3 | using MeowDSIO; 4 | using MeowDSIO.DataFiles; 5 | using Microsoft.Xna.Framework; 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Linq; 9 | using System.Text; 10 | using System.Threading.Tasks; 11 | 12 | namespace DarkSoulsModelViewerDX 13 | { 14 | public static class Tests 15 | { 16 | static void TestMCP_MGC(string mapName) 17 | { 18 | if (InterrootLoader.Type != InterrootLoader.InterrootType.InterrootDS1) 19 | return; 20 | 21 | //GFX.ModelDrawer.AddMap(mapName, false); 22 | 23 | var box = new DbgPrimWireBox(Transform.Default, Vector3.One, Color.Red); 24 | var mcp = DataFile.LoadFromFile(InterrootLoader.GetInterrootPath($@"map\{mapName}\{mapName}.mcp")); 25 | int bi = 0; 26 | foreach (var mcpBox in mcp.Boxes) 27 | { 28 | var min = new Vector3(mcpBox.MinX, mcpBox.MinY, mcpBox.MinZ); 29 | var max = new Vector3(mcpBox.MaxX, mcpBox.MaxY, mcpBox.MaxZ); 30 | var size = max - min; 31 | var center = min + (size / 2f); 32 | DBG.AddPrimitive(box.Instantiate($"Box [{(bi++)}]", new Transform(center.X, center.Y, center.Z, 0, 0, 0, size.X, size.Y, size.Z))); 33 | } 34 | var sphere = new DbgPrimWireSphere(Transform.Default, 0.35f, 32, 32, Color.Cyan); 35 | var mcg = DataFile.LoadFromFile(InterrootLoader.GetInterrootPath($@"map\{mapName}\{mapName}.mcg")); 36 | var lines = new DbgPrimWire(); 37 | List startPoints = new List(); 38 | List endPoints = new List(); 39 | for (int i = 0; i < mcg.Paths.Count; i++) 40 | { 41 | var pointsThatReferenceThisShit = mcg.Points.Where(x => x.NearbyPathIndices.Contains(i)).ToList(); 42 | startPoints.Add(new Vector3(pointsThatReferenceThisShit[0].PosX, pointsThatReferenceThisShit[0].PosY, pointsThatReferenceThisShit[0].PosZ)); 43 | endPoints.Add(new Vector3(pointsThatReferenceThisShit[1].PosX, pointsThatReferenceThisShit[1].PosY, pointsThatReferenceThisShit[1].PosZ)); 44 | } 45 | void AddPath(int pathIndex, Color col) => 46 | lines.AddLine(startPoints[pathIndex], endPoints[pathIndex], col); 47 | void AddPathString(int pathIndex, string str, Color col) 48 | { 49 | var position = (startPoints[pathIndex] + endPoints[pathIndex]) / 2.0f; 50 | lines.AddDbgLabel(position, 5f, str, col); 51 | } 52 | 53 | //for (int i = 0; i < mcg.Paths.Count; i++) 54 | //{ 55 | // AddPath(i, Color.Cyan); 56 | // AddPathString(i, mcg.Paths[i].GetDebugReport(), Color.Cyan); 57 | 58 | // //foreach (var edgeIndex in mcg.Edges[i].OtherEdgeIndicesA) 59 | // //{ 60 | // // AddEdge(edgeIndex, Color.Cyan); 61 | // //} 62 | 63 | // //foreach (var edgeIndex in mcg.Edges[i].OtherEdgeIndicesB) 64 | // //{ 65 | // // AddEdge(edgeIndex, Color.Yellow); 66 | // //} 67 | 68 | // //break; 69 | //} 70 | 71 | float getPathLength(int pathIndex) 72 | { 73 | var start = startPoints[pathIndex]; 74 | var end = endPoints[pathIndex]; 75 | return (start - end).Length(); 76 | } 77 | 78 | void addPointDbg(int pointIndex) 79 | { 80 | DBG.AddPrimitive(sphere.Instantiate($"Point [{pointIndex}]", new Transform(new Vector3(mcg.Points[pointIndex].PosX, mcg.Points[pointIndex].PosY, mcg.Points[pointIndex].PosZ), Vector3.Zero))); 81 | 82 | int pidx = 0; 83 | foreach (var adjPointIndex in mcg.Points[pointIndex].NearbyPointIndices) 84 | { 85 | DBG.AddPrimitive(sphere.Instantiate($"INDEX IN POINT'S LIST:{pidx++}, Point Near [{adjPointIndex}]", new Transform(new Vector3(mcg.Points[adjPointIndex].PosX, mcg.Points[adjPointIndex].PosY, mcg.Points[adjPointIndex].PosZ), Vector3.Zero))); 86 | } 87 | 88 | pidx = 0; 89 | foreach (var path in mcg.Points[pointIndex].NearbyPathIndices) 90 | { 91 | AddPath(path, Color.Cyan); 92 | AddPathString(path, $"PATH INDEX IN POINT'S LIST:{pidx++}\n{mcg.Paths[path].GetDebugReport()}\nPATH LENGTH: {getPathLength(path)}", Color.Cyan); 93 | } 94 | } 95 | 96 | //addPointDbg(0); 97 | //addPointDbg(1); 98 | //addPointDbg(2); 99 | 100 | for (int i = 0; i < mcg.Points.Count; i++) 101 | { 102 | addPointDbg(i); 103 | } 104 | 105 | DBG.AddPrimitive(lines); 106 | 107 | Console.WriteLine("TEST"); 108 | } 109 | 110 | public static void SetupTests(List menu) 111 | { 112 | menu.Add(new DbgMenuItem() 113 | { 114 | Text = "Test MGC & MCP", 115 | Items = DbgMenuItemSpawnMap.IDList.Select(x => new DbgMenuItem() 116 | { 117 | Text = x, 118 | ClickAction = m => TestMCP_MGC(x) 119 | }).ToList() 120 | }); 121 | } 122 | 123 | 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /SoulsFormats/SoulsFormats/Formats/BND0.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace SoulsFormats 4 | { 5 | /// 6 | /// A file container used in A.C.E. 3. 7 | /// 8 | public class BND0 : SoulsFile 9 | { 10 | /// 11 | /// The files contained in this BND0. 12 | /// 13 | public List Files; 14 | 15 | /// 16 | /// Whether to use the small header format or not. 17 | /// 18 | public bool Lite; 19 | 20 | /// 21 | /// Unknown, non-lite format. 22 | /// 23 | public byte Flag1; 24 | 25 | /// 26 | /// Unknown, non-lite format. 27 | /// 28 | public byte Flag2; 29 | 30 | /// 31 | /// Creates an uninitialized BND0. Should not be used publicly; use BND0.Read instead. 32 | /// 33 | public BND0() { } 34 | 35 | /// 36 | /// Returns true if the data appears to be a BND0. 37 | /// 38 | internal override bool Is(BinaryReaderEx br) 39 | { 40 | string magic = br.GetASCII(0, 4); 41 | return magic == "BND\0"; 42 | } 43 | 44 | /// 45 | /// Reads BND0 data from a BinaryReaderEx. 46 | /// 47 | internal override void Read(BinaryReaderEx br) 48 | { 49 | br.BigEndian = false; 50 | br.AssertASCII("BND\0"); 51 | // File size in non-lite format 52 | Lite = br.GetInt32(0xC) == 0; 53 | int fileSize, fileCount; 54 | 55 | if (Lite) 56 | { 57 | fileSize = br.ReadInt32(); 58 | fileCount = br.ReadInt32(); 59 | br.AssertInt32(0); 60 | } 61 | else 62 | { 63 | br.AssertInt32(0xF7FF); 64 | br.AssertInt32(0xD3); 65 | fileSize = br.ReadInt32(); 66 | fileCount = br.ReadInt32(); 67 | br.AssertInt32(0); 68 | 69 | Flag1 = br.AssertByte(0, 0x20); 70 | Flag2 = br.AssertByte(0, 0x08); 71 | br.AssertByte(3); 72 | br.AssertByte(0); 73 | 74 | br.AssertInt32(0); 75 | br.AssertInt32(0); 76 | } 77 | 78 | Files = new List(); 79 | for (int i = 0; i < fileCount; i++) 80 | { 81 | Files.Add(new File(br, Lite)); 82 | } 83 | } 84 | 85 | /// 86 | /// Writes BND0 data to a BinaryWriterEx. 87 | /// 88 | internal override void Write(BinaryWriterEx bw) 89 | { 90 | bw.BigEndian = false; 91 | bw.WriteASCII("BND\0"); 92 | 93 | if (Lite) 94 | { 95 | bw.ReserveInt32("FileSize"); 96 | bw.WriteInt32(Files.Count); 97 | bw.WriteInt32(0); 98 | } 99 | else 100 | { 101 | bw.WriteInt32(0xF7FF); 102 | bw.WriteInt32(0xD3); 103 | bw.ReserveInt32("FileSize"); 104 | bw.WriteInt32(Files.Count); 105 | bw.WriteInt32(0); 106 | 107 | bw.WriteByte(Flag1); 108 | bw.WriteByte(Flag2); 109 | bw.WriteByte(3); 110 | bw.WriteByte(0); 111 | 112 | bw.WriteInt32(0); 113 | bw.WriteInt32(0); 114 | } 115 | 116 | for (int i = 0; i < Files.Count; i++) 117 | { 118 | Files[i].Write(bw, Lite, i); 119 | } 120 | 121 | for (int i = 0; i < Files.Count; i++) 122 | { 123 | File file = Files[i]; 124 | bw.Pad(0x20); 125 | 126 | bw.FillInt32($"FileOffset{i}", (int)bw.Position); 127 | if (Lite) 128 | { 129 | bw.WriteInt32(file.Bytes.Length + 4); 130 | bw.WriteBytes(file.Bytes); 131 | } 132 | else 133 | { 134 | bw.WriteBytes(file.Bytes); 135 | } 136 | } 137 | 138 | bw.FillInt32("FileSize", (int)bw.Position); 139 | } 140 | 141 | /// 142 | /// A file in a BND0 container. 143 | /// 144 | public class File 145 | { 146 | /// 147 | /// The ID number of this file. 148 | /// 149 | public int ID; 150 | 151 | /// 152 | /// The raw data of this file. 153 | /// 154 | public byte[] Bytes; 155 | 156 | internal File(BinaryReaderEx br, bool lite) 157 | { 158 | ID = br.ReadInt32(); 159 | int offset = br.ReadInt32(); 160 | 161 | int size; 162 | if (lite) 163 | { 164 | // Size int is included in size 165 | size = br.GetInt32(offset) - 4; 166 | offset += 4; 167 | } 168 | else 169 | { 170 | size = br.ReadInt32(); 171 | } 172 | 173 | Bytes = br.GetBytes(offset, size); 174 | } 175 | 176 | internal void Write(BinaryWriterEx bw, bool lite, int index) 177 | { 178 | bw.WriteInt32(ID); 179 | bw.ReserveInt32($"FileOffset{index}"); 180 | if (!lite) 181 | bw.WriteInt32(Bytes.Length); 182 | } 183 | } 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /SoulsFormats/SoulsFormats/Formats/MSB2/MSB2.ModelSection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace SoulsFormats 5 | { 6 | public partial class MSB2 7 | { 8 | /// 9 | /// A section containing all the models available to parts in this map. 10 | /// 11 | public class ModelSection : Section 12 | { 13 | internal override string Type => "MODEL_PARAM_ST"; 14 | 15 | /// 16 | /// Map piece models in this section. 17 | /// 18 | public List MapPieces; 19 | 20 | /// 21 | /// Object models in this section. 22 | /// 23 | public List Objects; 24 | 25 | /// 26 | /// Enemy models in this section. 27 | /// 28 | public List Enemies; 29 | 30 | /// 31 | /// Items in this section. 32 | /// 33 | public List Items; 34 | 35 | /// 36 | /// Player models in this section. 37 | /// 38 | public List Players; 39 | 40 | /// 41 | /// Collision models in this section. 42 | /// 43 | public List Collisions; 44 | 45 | /// 46 | /// Other models in this section. 47 | /// 48 | public List Others; 49 | 50 | internal ModelSection(BinaryReaderEx br, int unk1) : base(br, unk1) 51 | { 52 | MapPieces = new List(); 53 | Objects = new List(); 54 | Enemies = new List(); 55 | Items = new List(); 56 | Players = new List(); 57 | Collisions = new List(); 58 | Others = new List(); 59 | } 60 | 61 | /// 62 | /// Returns every model in the order they will be written. 63 | /// 64 | public override List GetEntries() 65 | { 66 | return Util.ConcatAll( 67 | MapPieces, Objects, Enemies, Items, Players, Collisions, Others); 68 | } 69 | 70 | internal override Model ReadEntry(BinaryReaderEx br) 71 | { 72 | ModelType type = br.GetEnum16(br.Position + 8); 73 | 74 | switch (type) 75 | { 76 | case ModelType.MapPiece: 77 | var mapPiece = new Model(br); 78 | MapPieces.Add(mapPiece); 79 | return mapPiece; 80 | 81 | case ModelType.Object: 82 | var obj = new Model(br); 83 | Objects.Add(obj); 84 | return obj; 85 | 86 | case ModelType.Enemy: 87 | var enemy = new Model(br); 88 | Enemies.Add(enemy); 89 | return enemy; 90 | 91 | case ModelType.Item: 92 | var item = new Model(br); 93 | Items.Add(item); 94 | return item; 95 | 96 | case ModelType.Player: 97 | var player = new Model(br); 98 | Players.Add(player); 99 | return player; 100 | 101 | case ModelType.Collision: 102 | var collision = new Model(br); 103 | Collisions.Add(collision); 104 | return collision; 105 | 106 | case ModelType.Other: 107 | var other = new Model(br); 108 | Others.Add(other); 109 | return other; 110 | 111 | default: 112 | throw new NotImplementedException($"Unsupported model type: {type}"); 113 | } 114 | } 115 | 116 | internal override void WriteEntries(BinaryWriterEx bw, List entries) 117 | { 118 | throw new NotImplementedException(); 119 | } 120 | } 121 | 122 | internal enum ModelType : ushort 123 | { 124 | MapPiece = 0, 125 | Object = 1, 126 | Enemy = 2, 127 | Item = 3, 128 | Player = 4, 129 | Collision = 5, 130 | Navmesh = 6, 131 | DummyObject = 7, 132 | DummyEnemy = 8, 133 | Other = 0xFFFF 134 | } 135 | 136 | /// 137 | /// A model available for use by parts in this map. 138 | /// 139 | public class Model : Entry 140 | { 141 | internal ModelType Type { get; private set; } 142 | 143 | /// 144 | /// The name of this model. 145 | /// 146 | public override string Name { get; set; } 147 | 148 | internal Model(BinaryReaderEx br) 149 | { 150 | long start = br.Position; 151 | 152 | long nameOffset = br.ReadInt64(); 153 | Type = br.ReadEnum16(); 154 | 155 | Name = br.GetUTF16(start + nameOffset); 156 | } 157 | 158 | /// 159 | /// Returns the model type and name of this model. 160 | /// 161 | public override string ToString() 162 | { 163 | return $"{Type} : {Name}"; 164 | } 165 | } 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /ContentSource/NormalMapShader.fx: -------------------------------------------------------------------------------- 1 | #if OPENGL 2 | #define SV_POSITION POSITION 3 | #define VS_SHADERMODEL vs_3_0 4 | #define PS_SHADERMODEL ps_3_0 5 | #else 6 | #define VS_SHADERMODEL vs_4_0_level_9_1 7 | #define PS_SHADERMODEL ps_4_0_level_9_1 8 | #endif 9 | 10 | // Matrix 11 | float4x4 World; 12 | float4x4 View; 13 | float4x4 Projection; 14 | 15 | // Light related 16 | float4 AmbientColor; 17 | float AmbientIntensity; 18 | 19 | float3 LightDirection; 20 | float4 DiffuseColor; 21 | float DiffuseIntensity; 22 | 23 | float4 SpecularColor; 24 | float SpecularPower; 25 | float3 EyePosition; 26 | // 27 | //float DebugBlend_Normal; 28 | //float DebugBlend_Normal_ColorStart; 29 | //float DebugBlend_Normal_ColorScale; 30 | // 31 | //float DebugBlend_NormalAsVertexColor; 32 | 33 | //Default 2 34 | float DEBUG_ValueA; 35 | 36 | float NormalMapCustomZ; 37 | 38 | texture2D ColorMap; 39 | sampler2D ColorMapSampler = sampler_state 40 | { 41 | Texture = ; 42 | MinFilter = linear; 43 | MagFilter = linear; 44 | MipFilter = linear; 45 | }; 46 | 47 | texture2D NormalMap; 48 | sampler2D NormalMapSampler = sampler_state 49 | { 50 | Texture = ; 51 | MinFilter = linear; 52 | MagFilter = linear; 53 | MipFilter = linear; 54 | }; 55 | 56 | texture2D SpecularMap; 57 | sampler2D SpecularMapSampler = sampler_state 58 | { 59 | Texture = ; 60 | MinFilter = linear; 61 | MagFilter = linear; 62 | MipFilter = linear; 63 | }; 64 | 65 | texture2D LightMap1; 66 | sampler2D LightMap1Sampler = sampler_state 67 | { 68 | Texture = ; 69 | MinFilter = linear; 70 | MagFilter = linear; 71 | MipFilter = linear; 72 | }; 73 | 74 | texture2D LightMap2; 75 | sampler2D LightMap2Sampler = sampler_state 76 | { 77 | Texture = ; 78 | MinFilter = linear; 79 | MagFilter = linear; 80 | MipFilter = linear; 81 | }; 82 | 83 | // The input for the VertexShader 84 | struct VertexShaderInput 85 | { 86 | float4 Position : POSITION0; 87 | float2 TexCoord : TEXCOORD0; 88 | float2 TexCoord2 : TEXCOORD1; 89 | float3 Normal : NORMAL0; 90 | float3 Binormal : BINORMAL0; 91 | float3 Tangent : TANGENT0; 92 | float4x4 InstanceWorld : TEXCOORD2; 93 | float2 AtlasScale : TEXCOORD6; 94 | float2 AtlasOffset : TEXCOORD7; 95 | }; 96 | 97 | // The output from the vertex shader, used for later processing 98 | struct VertexShaderOutput 99 | { 100 | float4 Position : POSITION0; 101 | float2 TexCoord : TEXCOORD0; 102 | float2 TexCoord2 : TEXCOORD1; 103 | float3 View : TEXCOORD2; 104 | float3x3 WorldToTangentSpace : TEXCOORD3; 105 | float3 Normal : NORMAL0; 106 | float4 DebugColor : TEXCOORD6; 107 | }; 108 | 109 | VertexShaderOutput MainVS(in VertexShaderInput input) 110 | { 111 | VertexShaderOutput output; 112 | 113 | float4 worldPosition = mul(mul(input.Position, transpose(input.InstanceWorld)), World); 114 | float4 viewPosition = mul(worldPosition, View); 115 | output.Position = mul(viewPosition, Projection); 116 | output.TexCoord = input.TexCoord; 117 | output.TexCoord2.xy = input.TexCoord2.xy * input.AtlasScale.xy + input.AtlasOffset.xy; 118 | 119 | output.WorldToTangentSpace[0] = mul(normalize(input.Tangent), World); 120 | output.WorldToTangentSpace[1] = mul(normalize(input.Binormal), World); 121 | output.WorldToTangentSpace[2] = mul(normalize(input.Normal), World); 122 | 123 | output.View = normalize(float4(EyePosition,1.0) - worldPosition); 124 | 125 | output.Normal = input.Normal; 126 | 127 | output.DebugColor.xy = input.AtlasScale.xy; 128 | output.DebugColor.zw = input.AtlasOffset.xy; 129 | 130 | return output; 131 | } 132 | 133 | float4 MainPS(VertexShaderOutput input) : COLOR 134 | { 135 | float4 color = tex2D(ColorMapSampler, input.TexCoord); 136 | 137 | //color = color * float4(color.w, color.w, color.w, 1); 138 | 139 | float3 nmapcol = tex2D(NormalMapSampler, input.TexCoord); 140 | 141 | //Ignore the Z of the normal map to be accurate to the game. 142 | nmapcol = float3(nmapcol.x, nmapcol.y, NormalMapCustomZ); 143 | 144 | //nmapcol.x = -nmapcol.x; 145 | 146 | float3 normalMap = 2.0 *(nmapcol)-1.0; 147 | 148 | normalMap = normalize(mul(normalMap, input.WorldToTangentSpace)); 149 | float4 normal = float4(normalMap,1.0); 150 | 151 | //float4 debugNormalColor = float4( 152 | // (normal.x * DebugBlend_Normal_ColorScale) + DebugBlend_Normal_ColorStart, 153 | // (normal.y * DebugBlend_Normal_ColorScale) + DebugBlend_Normal_ColorStart, 154 | // (normal.z * DebugBlend_Normal_ColorScale) + DebugBlend_Normal_ColorStart, 155 | // 1 156 | // ); 157 | 158 | float4 diffuse = saturate(dot(-LightDirection,normal)); 159 | float4 reflect = normalize(2*diffuse*normal-float4(LightDirection,1.0)); 160 | float4 specular = pow(saturate(dot(reflect,input.View)),SpecularPower); 161 | 162 | float4 lightmap = tex2D(LightMap1Sampler, input.TexCoord2); 163 | 164 | float4 outputColor = color * AmbientColor * AmbientIntensity * lightmap + 165 | color * DiffuseIntensity * DiffuseColor * diffuse * lightmap + 166 | color * tex2D(SpecularMapSampler, input.TexCoord) * specular; 167 | 168 | outputColor = float4(outputColor.xyz * color.w, color.w); 169 | outputColor = outputColor;// * 0.001; 170 | //outputColor += input.DebugColor; 171 | return outputColor; 172 | 173 | //float4 outputAndDbgNorm = lerp(outputColor, debugNormalColor, float4(DebugBlend_Normal, DebugBlend_Normal, DebugBlend_Normal, DebugBlend_Normal)); 174 | 175 | //float4 dbgNormAsVertColor = saturate(float4(input.Normal.x, input.Normal.y, input.Normal.z, 1)); 176 | 177 | //return lerp(outputAndDbgNorm, dbgNormAsVertColor, 178 | // float4(DebugBlend_NormalAsVertexColor, DebugBlend_NormalAsVertexColor, DebugBlend_NormalAsVertexColor, DebugBlend_NormalAsVertexColor) 179 | // ); 180 | } 181 | 182 | technique BasicColorDrawing 183 | { 184 | pass P0 185 | { 186 | VertexShader = compile VS_SHADERMODEL MainVS(); 187 | PixelShader = compile PS_SHADERMODEL MainPS(); 188 | } 189 | }; 190 | 191 | -------------------------------------------------------------------------------- /SoulsFormats/SoulsFormats/Formats/BTAB.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Numerics; 4 | 5 | namespace SoulsFormats 6 | { 7 | /// 8 | /// A DS2/DS3 and BB file that specifies coordinates into a lightmap atlas to apply certain light maps to map parts 9 | /// 10 | public class BTAB : SoulsFile 11 | { 12 | /// 13 | /// Entries in this BTAB. 14 | /// 15 | public List Entries; 16 | 17 | internal override bool Is(BinaryReaderEx br) 18 | { 19 | throw new NotImplementedException(); 20 | } 21 | 22 | internal override void Read(BinaryReaderEx br) 23 | { 24 | br.BigEndian = false; 25 | 26 | br.AssertInt32(1); 27 | br.AssertInt32(0); 28 | int entryCount = br.ReadInt32(); 29 | int nameSize = br.ReadInt32(); 30 | br.AssertInt32(0); 31 | // Entry size 32 | br.AssertInt32(0x28); 33 | br.AssertInt32(0); 34 | br.AssertInt32(0); 35 | br.AssertInt32(0); 36 | br.AssertInt32(0); 37 | br.AssertInt32(0); 38 | br.AssertInt32(0); 39 | br.AssertInt32(0); 40 | br.AssertInt32(0); 41 | br.AssertInt32(0); 42 | 43 | long nameStart = br.Position; 44 | br.Position = nameStart + nameSize; 45 | Entries = new List(); 46 | for (int i = 0; i < entryCount; i++) 47 | Entries.Add(new Entry(br, nameStart)); 48 | } 49 | 50 | internal override void Write(BinaryWriterEx bw) 51 | { 52 | bw.BigEndian = false; 53 | 54 | bw.WriteInt32(1); 55 | bw.WriteInt32(0); 56 | bw.WriteInt32(Entries.Count); 57 | bw.ReserveInt32("NameSize"); 58 | bw.WriteInt32(0); 59 | bw.WriteInt32(0x28); 60 | bw.WriteInt32(0); 61 | bw.WriteInt32(0); 62 | bw.WriteInt32(0); 63 | bw.WriteInt32(0); 64 | bw.WriteInt32(0); 65 | bw.WriteInt32(0); 66 | bw.WriteInt32(0); 67 | bw.WriteInt32(0); 68 | bw.WriteInt32(0); 69 | 70 | long nameStart = bw.Position; 71 | var nameOffsets = new List(); 72 | foreach (Entry entry in Entries) 73 | { 74 | int nameOffset = (int)(bw.Position - nameStart); 75 | nameOffsets.Add(nameOffset); 76 | bw.WriteUTF16(entry.MSBPartName, true); 77 | if (nameOffset % 0x10 != 0) 78 | { 79 | for (int i = 0; i < 0x10 - (nameOffset % 0x10); i++) 80 | bw.WriteByte(0); 81 | } 82 | 83 | int nameOffset2 = (int)(bw.Position - nameStart); 84 | nameOffsets.Add(nameOffset2); 85 | bw.WriteUTF16(entry.FLVERMaterialName, true); 86 | if (nameOffset2 % 0x10 != 0) 87 | { 88 | for (int i = 0; i < 0x10 - (nameOffset2 % 0x10); i++) 89 | bw.WriteByte(0); 90 | } 91 | } 92 | 93 | bw.FillInt32("NameSize", (int)(bw.Position - nameStart)); 94 | for (int i = 0; i < Entries.Count; i++) 95 | Entries[i].Write(bw, nameOffsets[i * 2], nameOffsets[i * 2 + 1]); 96 | } 97 | 98 | /// 99 | /// A BTAB entry. 100 | /// 101 | public class Entry 102 | { 103 | /// 104 | /// The name of the target part defined in the MSB file 105 | /// 106 | public string MSBPartName; 107 | 108 | /// 109 | /// The name of a material in the FLVER; not the name of the MTD file itself. 110 | /// 111 | public string FLVERMaterialName; 112 | 113 | /// 114 | /// Which atlas texture to use for lightmaps 115 | /// 116 | public int AtlasIndex; 117 | 118 | /// 119 | /// Used to scale and translate lightmap uvs to select a particular index for a map part 120 | /// 121 | public Vector2 AtlasOffset; 122 | public Vector2 AtlasScale; 123 | 124 | internal Entry(BinaryReaderEx br, long nameStart) 125 | { 126 | int nameOffset = br.ReadInt32(); 127 | MSBPartName = br.GetUTF16(nameStart + nameOffset); 128 | br.AssertInt32(0); 129 | 130 | int nameOffset2 = br.ReadInt32(); 131 | FLVERMaterialName = br.GetUTF16(nameStart + nameOffset2); 132 | br.AssertInt32(0); 133 | 134 | AtlasIndex = br.ReadInt32(); 135 | AtlasOffset = br.ReadVector2(); 136 | AtlasScale = br.ReadVector2(); 137 | br.AssertInt32(0); 138 | } 139 | 140 | internal void Write(BinaryWriterEx bw, int nameOffset, int nameOffset2) 141 | { 142 | bw.WriteInt32(nameOffset); 143 | bw.WriteInt32(0); 144 | bw.WriteInt32(nameOffset2); 145 | bw.WriteInt32(0); 146 | bw.WriteInt32(AtlasIndex); 147 | bw.WriteVector2(AtlasOffset); 148 | bw.WriteVector2(AtlasScale); 149 | bw.WriteInt32(0); 150 | } 151 | 152 | /// 153 | /// Returns the MSB part name and FLVER material name of the entry. 154 | /// 155 | public override string ToString() 156 | { 157 | return $"{MSBPartName} : {FLVERMaterialName}"; 158 | } 159 | } 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /DarkSoulsModelViewerDX/DbgMenus/DbgMenuItemSceneList.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace DarkSoulsModelViewerDX.DbgMenus 8 | { 9 | public class DbgMenuItemSceneList : DbgMenuItem 10 | { 11 | public readonly bool IsModelGroupingKind; 12 | 13 | private Dictionary MapMenuEntriesToModels 14 | = new Dictionary(); 15 | 16 | public DbgMenuItemSceneList(bool isModelGroupingKind) 17 | { 18 | IsModelGroupingKind = isModelGroupingKind; 19 | BuildSceneItems(); 20 | } 21 | 22 | private List baseMenuItems = new List 23 | { 24 | new DbgMenuItem() 25 | { 26 | Text = "[Click to Delete All]", 27 | ClickAction = (m) => GFX.ModelDrawer.ClearScene() 28 | }, 29 | new DbgMenuItem() 30 | { 31 | Text = "[Click to Hide All]", 32 | ClickAction = (m) => GFX.ModelDrawer.HideAll() 33 | }, 34 | new DbgMenuItem() 35 | { 36 | Text = "[Click to Show All]", 37 | ClickAction = (m) => GFX.ModelDrawer.ShowAll() 38 | }, 39 | new DbgMenuItem() 40 | { 41 | Text = "[Click to Toggle All]", 42 | ClickAction = (m) => GFX.ModelDrawer.InvertVisibility() 43 | } 44 | }; 45 | 46 | private static void SetModelPrefixVisibility(string prefix, bool visibility) 47 | { 48 | throw new NotImplementedException(); 49 | //lock (ModelDrawer._lock_ModelLoad_Draw) 50 | //{ 51 | // var modelsWithPrefix = GFX.ModelDrawer.ModelInstanceList.Where(x => x.Name.StartsWith(prefix)); 52 | // if (modelsWithPrefix.Any()) 53 | // { 54 | // foreach (var m in modelsWithPrefix) 55 | // { 56 | // m.IsVisible = visibility; 57 | // } 58 | // } 59 | //} 60 | 61 | } 62 | private static bool GetModelPrefixVisibility(string prefix) 63 | { 64 | throw new NotImplementedException(); 65 | //lock (ModelDrawer._lock_ModelLoad_Draw) 66 | //{ 67 | // var modelsWithPrefix = GFX.ModelDrawer.ModelInstanceList.Where(x => x.Name.StartsWith(prefix)); 68 | // if (modelsWithPrefix.Any()) 69 | // return modelsWithPrefix.First().IsVisible; 70 | //} 71 | 72 | //return false; 73 | } 74 | 75 | private void BuildSceneItems() 76 | { 77 | lock (ModelDrawer._lock_ModelLoad_Draw) 78 | { 79 | Items.Clear(); 80 | foreach (var it in baseMenuItems) 81 | { 82 | Items.Add(it); 83 | } 84 | 85 | if (IsModelGroupingKind) 86 | { 87 | Dictionary modelNamePrefixes = new Dictionary(); 88 | 89 | //foreach (var md in GFX.ModelDrawer.ModelInstanceList) 90 | //{ 91 | // var underscoreIndex = md.Name.IndexOf('_'); 92 | // string modelNamePrefix = null; 93 | // if (underscoreIndex >= 0) 94 | // modelNamePrefix = md.Name.Substring(0, underscoreIndex); 95 | // else 96 | // modelNamePrefix = md.Name; 97 | 98 | // if (!modelNamePrefixes.ContainsKey(modelNamePrefix)) 99 | // modelNamePrefixes.Add(modelNamePrefix, 1); 100 | // else 101 | // modelNamePrefixes[modelNamePrefix] = modelNamePrefixes[modelNamePrefix] + 1; 102 | //} 103 | 104 | foreach (var prefix in modelNamePrefixes) 105 | { 106 | Items.Add(new DbgMenuItemBool($"{prefix.Key} (x{prefix.Value.ToString()})", "SHOW", "HIDE", 107 | (b) => SetModelPrefixVisibility(prefix.Key, b), () => GetModelPrefixVisibility(prefix.Key))); 108 | } 109 | } 110 | else 111 | { 112 | MapMenuEntriesToModels.Clear(); 113 | 114 | //foreach (var md in GFX.ModelDrawer.ModelInstanceList) 115 | //{ 116 | // var menuItem = new DbgMenuItemBool($"{md.Name}", "SHOW", "HIDE", 117 | // (b) => md.IsVisible = b, () => md.IsVisible); 118 | 119 | // Items.Add(menuItem); 120 | // MapMenuEntriesToModels.Add(menuItem, md); 121 | //} 122 | } 123 | 124 | 125 | } 126 | 127 | } 128 | 129 | public override void UpdateUI() 130 | { 131 | if (CurrentMenu == this) 132 | { 133 | //// If the amount of models changes, just rebuild the whole thing. 134 | //if (Items.Count != (GFX.ModelDrawer.ModelInstanceList.Count + baseMenuItems.Count)) 135 | //{ 136 | // BuildSceneItems(); 137 | //} 138 | 139 | if (!IsModelGroupingKind) 140 | { 141 | if (SelectedIndex >= baseMenuItems.Count && SelectedIndex < Items.Count) 142 | { 143 | GFX.ModelDrawer.Selected = MapMenuEntriesToModels[Items[SelectedIndex]]; 144 | } 145 | else 146 | { 147 | GFX.ModelDrawer.Selected = null; 148 | } 149 | } 150 | } 151 | 152 | base.UpdateUI(); 153 | } 154 | 155 | public override void OnRequestTextRefresh() 156 | { 157 | UpdateUI(); 158 | } 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /DarkSoulsModelViewerDX/DbgMenus/DbgMenuItemSpawnObj.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.IO; 3 | using System.Linq; 4 | using System; 5 | using System.Windows.Forms; 6 | 7 | namespace DarkSoulsModelViewerDX.DbgMenus 8 | { 9 | public class DbgMenuItemSpawnObj : DbgMenuItem 10 | { 11 | public static List IDList = new List(); 12 | private static bool NeedsTextUpdate = false; 13 | 14 | public int IDIndex = 0; 15 | 16 | public static void UpdateSpawnIDs() 17 | { 18 | try 19 | { 20 | string[] objFiles = null; 21 | 22 | if (InterrootLoader.Type == InterrootLoader.InterrootType.InterrootDS1) 23 | { 24 | objFiles = Directory.GetFiles(InterrootLoader.GetInterrootPath(@"\obj\"), @"*.objbnd") 25 | .Select(Path.GetFileNameWithoutExtension) 26 | .ToArray(); 27 | } 28 | else if (InterrootLoader.Type == InterrootLoader.InterrootType.InterrootDS2) 29 | { 30 | objFiles = Directory.GetFiles(InterrootLoader.GetInterrootPath(@"\model\obj\"), @"*.bnd") 31 | .Select(Path.GetFileNameWithoutExtension) //Remove .dcx 32 | .Select(Path.GetFileNameWithoutExtension) //Remove .objbnd 33 | .ToArray(); 34 | } 35 | else if (InterrootLoader.Type == InterrootLoader.InterrootType.InterrootNB) 36 | { 37 | objFiles = Directory.GetFiles(InterrootLoader.GetInterrootPath(@"\obj\"), @"*.bnd") 38 | .Select(Path.GetFileNameWithoutExtension) 39 | .ToArray(); 40 | } 41 | else 42 | { 43 | objFiles = Directory.GetFiles(InterrootLoader.GetInterrootPath(@"\obj\"), @"*.objbnd.dcx") 44 | .Select(Path.GetFileNameWithoutExtension) //Remove .dcx 45 | .Select(Path.GetFileNameWithoutExtension) //Remove .objbnd 46 | .ToArray(); 47 | } 48 | 49 | IDList = new List(); 50 | var IDSet = new HashSet(); 51 | foreach (var cf in objFiles) 52 | { 53 | if (int.TryParse((InterrootLoader.Type == InterrootLoader.InterrootType.InterrootDS3 || InterrootLoader.Type == InterrootLoader.InterrootType.InterrootBloodborne) 54 | ? cf.Substring(1, 6) : (InterrootLoader.Type == InterrootLoader.InterrootType.InterrootDS2) ? cf.Substring(1, 7).Replace("_", "") : cf.Substring(1, 4), out int id)) 55 | { 56 | IDList.Add(id); 57 | IDSet.Add(id); 58 | } 59 | } 60 | 61 | NeedsTextUpdate = true; 62 | } 63 | catch (Exception e) 64 | { 65 | IDList = new List(); 66 | NeedsTextUpdate = true; 67 | MessageBox.Show("An error occured when populating the obj list: " + e.Message, e.StackTrace); 68 | } 69 | } 70 | 71 | public DbgMenuItemSpawnObj() 72 | { 73 | UpdateSpawnIDs(); 74 | UpdateText(); 75 | } 76 | 77 | private void UpdateText() 78 | { 79 | if (IDList.Count == 0) 80 | { 81 | IDIndex = 0; 82 | Text = $"Click to Spawn OBJ [Invalid Data Root Selected]"; 83 | } 84 | else 85 | { 86 | if (IDIndex >= IDList.Count) 87 | IDIndex = IDList.Count - 1; 88 | 89 | if (InterrootLoader.Type == InterrootLoader.InterrootType.InterrootDS3) 90 | Text = $"Click to Spawn OBJ [ID: ]"; 91 | else 92 | Text = $"Click to Spawn OBJ [ID: ]"; 93 | } 94 | } 95 | 96 | public override void OnIncrease(bool isRepeat, int incrementAmount) 97 | { 98 | int prevIndex = IDIndex; 99 | IDIndex += incrementAmount; 100 | 101 | //If upper bound reached 102 | if (IDIndex >= IDList.Count) 103 | { 104 | //If already at end and just tapped button 105 | if (prevIndex == IDList.Count - 1 && !isRepeat) 106 | IDIndex = 0; //Wrap Around 107 | else 108 | IDIndex = IDList.Count - 1; //Stop 109 | } 110 | 111 | UpdateText(); 112 | } 113 | 114 | public override void OnDecrease(bool isRepeat, int incrementAmount) 115 | { 116 | int prevIndex = IDIndex; 117 | IDIndex -= incrementAmount; 118 | 119 | //If upper bound reached 120 | if (IDIndex < 0) 121 | { 122 | //If already at end and just tapped button 123 | if (prevIndex == 0 && !isRepeat) 124 | IDIndex = IDList.Count - 1; //Wrap Around 125 | else 126 | IDIndex = 0; //Stop 127 | } 128 | 129 | UpdateText(); 130 | } 131 | 132 | public override void OnResetDefault() 133 | { 134 | IDIndex = 0; 135 | UpdateText(); 136 | } 137 | 138 | public override void OnClick() 139 | { 140 | if (IDList.Count == 0) 141 | return; 142 | 143 | GFX.ModelDrawer.AddObj(IDList[IDIndex], 144 | GFX.World.GetSpawnPointInFrontOfCamera(distance: 5, 145 | faceBackwards: false, lockPitch: true, alignToFloor: true)); 146 | } 147 | 148 | public override void UpdateUI() 149 | { 150 | if (NeedsTextUpdate) 151 | { 152 | UpdateText(); 153 | NeedsTextUpdate = false; 154 | } 155 | } 156 | 157 | public override void OnRequestTextRefresh() 158 | { 159 | UpdateSpawnIDs(); 160 | UpdateText(); 161 | } 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /SoulsFormats/SoulsFormats/Formats/FMG.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace SoulsFormats 5 | { 6 | /// 7 | /// A simple string container used throughout the series. 8 | /// 9 | public class FMG : SoulsFile 10 | { 11 | /// 12 | /// The strings contained in this FMG. 13 | /// 14 | public List Entries; 15 | 16 | /// 17 | /// If true, use DS3 format with 64-bit string offsets. 18 | /// 19 | public bool Long; 20 | 21 | /// 22 | /// Creates an uninitialized FMG. Should not be used publicly; use FMG.Read instead. 23 | /// 24 | public FMG() { } 25 | 26 | internal override bool Is(BinaryReaderEx br) 27 | { 28 | throw new NotImplementedException(); 29 | } 30 | 31 | internal override void Read(BinaryReaderEx br) 32 | { 33 | br.BigEndian = false; 34 | 35 | br.AssertByte(0); 36 | br.AssertByte(0); 37 | Long = br.AssertByte(1, 2) == 2; 38 | br.AssertByte(0); 39 | 40 | int fileSize = br.ReadInt32(); 41 | br.AssertInt32(1); 42 | int groupCount = br.ReadInt32(); 43 | int stringCount = br.ReadInt32(); 44 | 45 | if (Long) 46 | br.AssertInt32(0xFF); 47 | 48 | long stringOffsetsOffset; 49 | if (Long) 50 | stringOffsetsOffset = br.ReadInt64(); 51 | else 52 | stringOffsetsOffset = br.ReadInt32(); 53 | 54 | br.AssertInt32(0); 55 | br.AssertInt32(0); 56 | 57 | Entries = new List(); 58 | for (int i = 0; i < groupCount; i++) 59 | { 60 | int offsetIndex = br.ReadInt32(); 61 | int firstID = br.ReadInt32(); 62 | int lastID = br.ReadInt32(); 63 | 64 | if (Long) 65 | br.AssertInt32(0); 66 | 67 | br.StepIn(stringOffsetsOffset + offsetIndex * (Long ? 8 : 4)); 68 | for (int j = 0; j < lastID - firstID + 1; j++) 69 | { 70 | long stringOffset; 71 | if (Long) 72 | stringOffset = br.ReadInt64(); 73 | else 74 | stringOffset = br.ReadInt32(); 75 | 76 | int id = firstID + j; 77 | string text = stringOffset != 0 ? br.GetUTF16(stringOffset) : null; 78 | Entries.Add(new Entry(id, text)); 79 | } 80 | br.StepOut(); 81 | } 82 | } 83 | 84 | internal override void Write(BinaryWriterEx bw) 85 | { 86 | bw.BigEndian = false; 87 | 88 | bw.WriteByte(0); 89 | bw.WriteByte(0); 90 | bw.WriteByte((byte)(Long ? 2 : 1)); 91 | bw.WriteByte(0); 92 | 93 | bw.ReserveInt32("FileSize"); 94 | bw.WriteInt32(1); 95 | bw.ReserveInt32("GroupCount"); 96 | bw.WriteInt32(Entries.Count); 97 | 98 | if (Long) 99 | bw.WriteInt32(0xFF); 100 | 101 | if (Long) 102 | bw.ReserveInt64("StringOffsets"); 103 | else 104 | bw.ReserveInt32("StringOffsets"); 105 | 106 | bw.WriteInt32(0); 107 | bw.WriteInt32(0); 108 | 109 | int groupCount = 0; 110 | Entries.Sort((e1, e2) => e1.ID.CompareTo(e2.ID)); 111 | for (int i = 0; i < Entries.Count; i++) 112 | { 113 | bw.WriteInt32(i); 114 | bw.WriteInt32(Entries[i].ID); 115 | while (i < Entries.Count - 1 && Entries[i + 1].ID == Entries[i].ID + 1) 116 | i++; 117 | bw.WriteInt32(Entries[i].ID); 118 | 119 | if (Long) 120 | bw.WriteInt32(0); 121 | 122 | groupCount++; 123 | } 124 | bw.FillInt32("GroupCount", groupCount); 125 | 126 | if (Long) 127 | bw.FillInt64("StringOffsets", bw.Position); 128 | else 129 | bw.FillInt32("StringOffsets", (int)bw.Position); 130 | 131 | for (int i = 0; i < Entries.Count; i++) 132 | { 133 | if (Long) 134 | bw.ReserveInt64($"StringOffset{i}"); 135 | else 136 | bw.ReserveInt32($"StringOffset{i}"); 137 | } 138 | 139 | for (int i = 0; i < Entries.Count; i++) 140 | { 141 | string text = Entries[i].Text; 142 | 143 | if (Long) 144 | bw.FillInt64($"StringOffset{i}", text == null ? 0 : bw.Position); 145 | else 146 | bw.FillInt64($"StringOffset{i}", text == null ? 0 : (int)bw.Position); 147 | 148 | if (text != null) 149 | bw.WriteUTF16(Entries[i].Text, true); 150 | } 151 | 152 | bw.FillInt32("FileSize", (int)bw.Position); 153 | } 154 | 155 | /// 156 | /// Returns the string with the given ID, or null if not present. 157 | /// 158 | public string this[int id] 159 | { 160 | get 161 | { 162 | foreach (Entry entry in Entries) 163 | { 164 | if (entry.ID == id) 165 | return entry.Text; 166 | } 167 | return null; 168 | } 169 | } 170 | 171 | /// 172 | /// A string in an FMG identified with an ID number. 173 | /// 174 | public class Entry 175 | { 176 | /// 177 | /// The ID of this entry. 178 | /// 179 | public int ID; 180 | 181 | /// 182 | /// The text of this entry. 183 | /// 184 | public string Text; 185 | 186 | /// 187 | /// Creates a new entry with the specified ID and text. 188 | /// 189 | public Entry(int id, string text) 190 | { 191 | ID = id; 192 | Text = text; 193 | } 194 | 195 | /// 196 | /// Returns the ID and text of this entry. 197 | /// 198 | public override string ToString() 199 | { 200 | return $"{ID}: {Text ?? ""}"; 201 | } 202 | } 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /SoulsFormats/SoulsFormats/SoulsFormats.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {22C664BD-877B-44DF-8ECF-2808522469A8} 8 | Library 9 | Properties 10 | SoulsFormats 11 | SoulsFormats 12 | v4.6.1 13 | 512 14 | 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | false 25 | bin\Debug\SoulsFormats.xml 26 | 7.3 27 | IDE0017 28 | 29 | 30 | pdbonly 31 | true 32 | bin\Release\ 33 | TRACE 34 | prompt 35 | 4 36 | false 37 | bin\Release\SoulsFormats.xml 38 | 7.3 39 | IDE0017 40 | 41 | 42 | true 43 | bin\x64\Debug\ 44 | DEBUG;TRACE 45 | full 46 | x64 47 | prompt 48 | MinimumRecommendedRules.ruleset 49 | false 50 | bin\x64\Debug\SoulsFormats.xml 51 | 7.3 52 | IDE0017 53 | 54 | 55 | bin\x64\Release\ 56 | TRACE 57 | true 58 | pdbonly 59 | x64 60 | prompt 61 | MinimumRecommendedRules.ruleset 62 | false 63 | bin\x64\Release\SoulsFormats.xml 64 | 7.3 65 | IDE0017 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | -------------------------------------------------------------------------------- /SoulsFormats/SoulsFormats/Formats/MSBD/MSBD.ModelSection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace SoulsFormats 5 | { 6 | public partial class MSBD 7 | { 8 | /// 9 | /// A section containing all the models available to parts in this map. 10 | /// 11 | public class ModelSection : Section 12 | { 13 | internal override string Type => "MODEL_PARAM_ST"; 14 | 15 | /// 16 | /// Map piece models in this section. 17 | /// 18 | public List MapPieces; 19 | 20 | /// 21 | /// Object models in this section. 22 | /// 23 | public List Objects; 24 | 25 | /// 26 | /// Enemy models in this section. 27 | /// 28 | public List Enemies; 29 | 30 | /// 31 | /// Items in this section. 32 | /// 33 | public List Items; 34 | 35 | /// 36 | /// Player models in this section. 37 | /// 38 | public List Players; 39 | 40 | /// 41 | /// Collision models in this section. 42 | /// 43 | public List Collisions; 44 | 45 | /// 46 | /// Navmeshes in this section. 47 | /// 48 | public List Navmeshes; 49 | 50 | /// 51 | /// Dummy objects in this section. 52 | /// 53 | public List DummyObjects; 54 | 55 | /// 56 | /// Dummy enemies in this section. 57 | /// 58 | public List DummyEnemies; 59 | 60 | /// 61 | /// Other models in this section. 62 | /// 63 | public List Others; 64 | 65 | internal ModelSection(BinaryReaderEx br, int unk1) : base(br, unk1) 66 | { 67 | MapPieces = new List(); 68 | Objects = new List(); 69 | Enemies = new List(); 70 | Items = new List(); 71 | Players = new List(); 72 | Collisions = new List(); 73 | Navmeshes = new List(); 74 | DummyObjects = new List(); 75 | DummyEnemies = new List(); 76 | Others = new List(); 77 | } 78 | 79 | /// 80 | /// Returns every model in the order they will be written. 81 | /// 82 | public override List GetEntries() 83 | { 84 | return Util.ConcatAll( 85 | MapPieces, Objects, Enemies, Items, Players, Collisions, Navmeshes, DummyObjects, DummyEnemies, Others); 86 | } 87 | 88 | internal override Model ReadEntry(BinaryReaderEx br) 89 | { 90 | ModelType type = br.GetEnum32(br.Position + 4); 91 | 92 | switch (type) 93 | { 94 | case ModelType.MapPiece: 95 | var mapPiece = new Model(br); 96 | MapPieces.Add(mapPiece); 97 | return mapPiece; 98 | 99 | case ModelType.Object: 100 | var obj = new Model(br); 101 | Objects.Add(obj); 102 | return obj; 103 | 104 | case ModelType.Enemy: 105 | var enemy = new Model(br); 106 | Enemies.Add(enemy); 107 | return enemy; 108 | 109 | case ModelType.Item: 110 | var item = new Model(br); 111 | Items.Add(item); 112 | return item; 113 | 114 | case ModelType.Player: 115 | var player = new Model(br); 116 | Players.Add(player); 117 | return player; 118 | 119 | case ModelType.Collision: 120 | var collision = new Model(br); 121 | Collisions.Add(collision); 122 | return collision; 123 | 124 | case ModelType.Navmesh: 125 | var navmesh = new Model(br); 126 | Navmeshes.Add(navmesh); 127 | return navmesh; 128 | 129 | case ModelType.DummyObject: 130 | var dummyObj = new Model(br); 131 | DummyObjects.Add(dummyObj); 132 | return dummyObj; 133 | 134 | case ModelType.DummyEnemy: 135 | var dummyEne = new Model(br); 136 | DummyEnemies.Add(dummyEne); 137 | return dummyEne; 138 | 139 | case ModelType.Other: 140 | var other = new Model(br); 141 | Others.Add(other); 142 | return other; 143 | 144 | default: 145 | throw new NotImplementedException($"Unsupported model type: {type}"); 146 | } 147 | } 148 | 149 | internal override void WriteEntries(BinaryWriterEx bw, List entries) 150 | { 151 | throw new NotImplementedException(); 152 | } 153 | } 154 | 155 | internal enum ModelType : uint 156 | { 157 | MapPiece = 0, 158 | Object = 1, 159 | Enemy = 2, 160 | Item = 3, 161 | Player = 4, 162 | Collision = 5, 163 | Navmesh = 6, 164 | DummyObject = 7, 165 | DummyEnemy = 8, 166 | Other = 0xFFFF 167 | } 168 | 169 | /// 170 | /// A model available for use by parts in this map. 171 | /// 172 | public class Model : Entry 173 | { 174 | internal ModelType Type { get; private set; } 175 | 176 | /// 177 | /// The name of this model. 178 | /// 179 | public override string Name { get; set; } 180 | 181 | internal Model(BinaryReaderEx br) 182 | { 183 | long start = br.Position; 184 | 185 | int nameOffset = br.ReadInt32(); 186 | Type = br.ReadEnum32(); 187 | 188 | Name = br.GetShiftJIS(start + nameOffset); 189 | } 190 | 191 | /// 192 | /// Returns the model type and name of this model. 193 | /// 194 | public override string ToString() 195 | { 196 | return $"{Type} : {Name}"; 197 | } 198 | } 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /SoulsFormats/SoulsFormats/Formats/MSBN/MSBN.ModelSection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace SoulsFormats 5 | { 6 | public partial class MSBN 7 | { 8 | /// 9 | /// A section containing all the models available to parts in this map. 10 | /// 11 | public class ModelSection : Section 12 | { 13 | internal override string Type => "MODEL_PARAM_ST"; 14 | 15 | /// 16 | /// Map piece models in this section. 17 | /// 18 | public List MapPieces; 19 | 20 | /// 21 | /// Object models in this section. 22 | /// 23 | public List Objects; 24 | 25 | /// 26 | /// Enemy models in this section. 27 | /// 28 | public List Enemies; 29 | 30 | /// 31 | /// Items in this section. 32 | /// 33 | public List Items; 34 | 35 | /// 36 | /// Player models in this section. 37 | /// 38 | public List Players; 39 | 40 | /// 41 | /// Collision models in this section. 42 | /// 43 | public List Collisions; 44 | 45 | /// 46 | /// Navmeshes in this section. 47 | /// 48 | public List Navmeshes; 49 | 50 | /// 51 | /// Dummy objects in this section. 52 | /// 53 | public List DummyObjects; 54 | 55 | /// 56 | /// Dummy enemies in this section. 57 | /// 58 | public List DummyEnemies; 59 | 60 | /// 61 | /// Other models in this section. 62 | /// 63 | public List Others; 64 | 65 | internal ModelSection(BinaryReaderEx br, int unk1) : base(br, unk1) 66 | { 67 | MapPieces = new List(); 68 | Objects = new List(); 69 | Enemies = new List(); 70 | Items = new List(); 71 | Players = new List(); 72 | Collisions = new List(); 73 | Navmeshes = new List(); 74 | DummyObjects = new List(); 75 | DummyEnemies = new List(); 76 | Others = new List(); 77 | } 78 | 79 | /// 80 | /// Returns every model in the order they will be written. 81 | /// 82 | public override List GetEntries() 83 | { 84 | return Util.ConcatAll( 85 | MapPieces, Objects, Enemies, Items, Players, Collisions, Navmeshes, DummyObjects, DummyEnemies, Others); 86 | } 87 | 88 | internal override Model ReadEntry(BinaryReaderEx br) 89 | { 90 | ModelType type = br.GetEnum32(br.Position + 4); 91 | 92 | switch (type) 93 | { 94 | case ModelType.MapPiece: 95 | var mapPiece = new Model(br); 96 | MapPieces.Add(mapPiece); 97 | return mapPiece; 98 | 99 | case ModelType.Object: 100 | var obj = new Model(br); 101 | Objects.Add(obj); 102 | return obj; 103 | 104 | case ModelType.Enemy: 105 | var enemy = new Model(br); 106 | Enemies.Add(enemy); 107 | return enemy; 108 | 109 | case ModelType.Item: 110 | var item = new Model(br); 111 | Items.Add(item); 112 | return item; 113 | 114 | case ModelType.Player: 115 | var player = new Model(br); 116 | Players.Add(player); 117 | return player; 118 | 119 | case ModelType.Collision: 120 | var collision = new Model(br); 121 | Collisions.Add(collision); 122 | return collision; 123 | 124 | case ModelType.Navmesh: 125 | var navmesh = new Model(br); 126 | Navmeshes.Add(navmesh); 127 | return navmesh; 128 | 129 | case ModelType.DummyObject: 130 | var dummyObj = new Model(br); 131 | DummyObjects.Add(dummyObj); 132 | return dummyObj; 133 | 134 | case ModelType.DummyEnemy: 135 | var dummyEne = new Model(br); 136 | DummyEnemies.Add(dummyEne); 137 | return dummyEne; 138 | 139 | case ModelType.Other: 140 | var other = new Model(br); 141 | Others.Add(other); 142 | return other; 143 | 144 | default: 145 | throw new NotImplementedException($"Unsupported model type: {type}"); 146 | } 147 | } 148 | 149 | internal override void WriteEntries(BinaryWriterEx bw, List entries) 150 | { 151 | throw new NotImplementedException(); 152 | } 153 | } 154 | 155 | internal enum ModelType : uint 156 | { 157 | Collision = 0, 158 | MapPiece = 1, 159 | Object = 2, 160 | Enemy = 3, 161 | Item = 4, 162 | Player = 5, 163 | Navmesh = 6, 164 | DummyObject = 7, 165 | DummyEnemy = 8, 166 | Other = 0xFFFFFFFF 167 | } 168 | 169 | /// 170 | /// A model available for use by parts in this map. 171 | /// 172 | public class Model : Entry 173 | { 174 | internal ModelType Type { get; private set; } 175 | 176 | /// 177 | /// The name of this model. 178 | /// 179 | public override string Name { get; set; } 180 | 181 | internal Model(BinaryReaderEx br) 182 | { 183 | long start = br.Position; 184 | 185 | int nameOffset = br.ReadInt32(); 186 | Type = br.ReadEnum32(); 187 | 188 | Name = br.GetShiftJIS(start + nameOffset); 189 | } 190 | 191 | /// 192 | /// Returns the model type and name of this model. 193 | /// 194 | public override string ToString() 195 | { 196 | return $"{Type} : {Name}"; 197 | } 198 | } 199 | } 200 | } 201 | --------------------------------------------------------------------------------