From 6e6ade730f4bb139bdeda9e099e6e773735ff454 Mon Sep 17 00:00:00 2001 From: wincent Date: Sun, 2 Feb 2020 20:58:12 +0100 Subject: [PATCH] Migrated some nif blocks from my other repository: * Can read some basic nif files * Writing can be buggy --- .../Extensions/BitReaderExtensions.cs | 19 +- .../Extensions/BitWriterExtensions.cs | 14 ++ .../Concepts/Generic/LwoObjectExtensions.cs | 25 +++ InfectedRose.Database/Concepts/LwoObject.cs | 5 +- InfectedRose.Database/FdbRowInfo.cs | 30 +-- InfectedRose.Database/Table.cs | 54 ++--- .../AccessDatabaseCommand.cs | 45 +++++ InfectedRose.Examples/AccessEditor.cs | 142 +++++++++++++ .../Controllers/NiTimeController.cs | 17 ++ .../Data/AbstractAdditionalGeometryData.cs | 17 ++ InfectedRose.Nif/Data/NiGeometryData.cs | 186 ++++++++++++++++++ InfectedRose.Nif/Data/NiLODData.cs | 15 ++ InfectedRose.Nif/Data/NiRangeLODData.cs | 40 ++++ InfectedRose.Nif/Data/NiScreenLODData.cs | 54 +++++ InfectedRose.Nif/Data/NiSkinInstance.cs | 17 ++ InfectedRose.Nif/Data/NiTriBasedGeomData.cs | 23 +++ InfectedRose.Nif/Data/NiTriShapeData.cs | 53 +++++ InfectedRose.Nif/Effects/NiAmbientLight.cs | 7 + InfectedRose.Nif/Effects/NiDynamicEffect.cs | 40 ++++ InfectedRose.Nif/Effects/NiLight.cs | 41 ++++ InfectedRose.Nif/Enums/NifVersion.cs | 2 +- .../Extensions/BitReaderExtensions.cs | 19 ++ InfectedRose.Nif/Extra/NiExtraData.cs | 20 ++ InfectedRose.Nif/Extra/NiStringExtraData.cs | 24 +++ InfectedRose.Nif/NiFile.cs | 154 +++++++++++++++ .../{NifHeader.cs => NiHeader.cs} | 42 +++- InfectedRose.Nif/NiObject.cs | 14 ++ InfectedRose.Nif/NiRef.cs | 48 +++++ InfectedRose.Nif/NiStringRef.cs | 38 ++++ InfectedRose.Nif/NifFile.cs | 22 --- InfectedRose.Nif/NifString.cs | 40 ---- InfectedRose.Nif/Nodes/NiAvObject.cs | 65 ++++++ InfectedRose.Nif/Nodes/NiCollisionObject.cs | 20 ++ InfectedRose.Nif/Nodes/NiGeometry.cs | 66 +++++++ InfectedRose.Nif/Nodes/NiLODNode.cs | 24 +++ InfectedRose.Nif/Nodes/NiNode.cs | 50 +++++ InfectedRose.Nif/Nodes/NiObjectNet.cs | 43 ++++ InfectedRose.Nif/Nodes/NiSwitchNode.cs | 29 +++ InfectedRose.Nif/Nodes/NiTriBasedGeom.cs | 7 + InfectedRose.Nif/Nodes/NiTriShape.cs | 7 + InfectedRose.Nif/Nodes/NiTriStrips.cs | 7 + .../Properties/NiMaterialProperty.cs | 59 ++++++ InfectedRose.Nif/Properties/NiProperty.cs | 7 + .../Properties/NiShadeProperty.cs | 23 +++ .../Properties/NiSpecularProperty.cs | 23 +++ .../Properties/NiVertexColorProperty.cs | 23 +++ .../Properties/NiZBufferProperty.cs | 23 +++ InfectedRose.Nif/Structs/Color3.cs | 11 ++ InfectedRose.Nif/Structs/Color4.cs | 13 ++ InfectedRose.Nif/Structs/LODRange.cs | 9 + InfectedRose.Nif/Structs/MatchGroup.cs | 9 + InfectedRose.Nif/Structs/Matrix3X3.cs | 23 +++ InfectedRose.Nif/Structs/Triangle.cs | 11 ++ 53 files changed, 1703 insertions(+), 116 deletions(-) create mode 100644 InfectedRose.Database/Concepts/Generic/LwoObjectExtensions.cs create mode 100644 InfectedRose.Examples/AccessDatabaseCommand.cs create mode 100644 InfectedRose.Examples/AccessEditor.cs create mode 100644 InfectedRose.Nif/Controllers/NiTimeController.cs create mode 100644 InfectedRose.Nif/Data/AbstractAdditionalGeometryData.cs create mode 100644 InfectedRose.Nif/Data/NiGeometryData.cs create mode 100644 InfectedRose.Nif/Data/NiLODData.cs create mode 100644 InfectedRose.Nif/Data/NiRangeLODData.cs create mode 100644 InfectedRose.Nif/Data/NiScreenLODData.cs create mode 100644 InfectedRose.Nif/Data/NiSkinInstance.cs create mode 100644 InfectedRose.Nif/Data/NiTriBasedGeomData.cs create mode 100644 InfectedRose.Nif/Data/NiTriShapeData.cs create mode 100644 InfectedRose.Nif/Effects/NiAmbientLight.cs create mode 100644 InfectedRose.Nif/Effects/NiDynamicEffect.cs create mode 100644 InfectedRose.Nif/Effects/NiLight.cs create mode 100644 InfectedRose.Nif/Extensions/BitReaderExtensions.cs create mode 100644 InfectedRose.Nif/Extra/NiExtraData.cs create mode 100644 InfectedRose.Nif/Extra/NiStringExtraData.cs create mode 100644 InfectedRose.Nif/NiFile.cs rename InfectedRose.Nif/{NifHeader.cs => NiHeader.cs} (72%) create mode 100644 InfectedRose.Nif/NiObject.cs create mode 100644 InfectedRose.Nif/NiRef.cs create mode 100644 InfectedRose.Nif/NiStringRef.cs delete mode 100644 InfectedRose.Nif/NifFile.cs delete mode 100644 InfectedRose.Nif/NifString.cs create mode 100644 InfectedRose.Nif/Nodes/NiAvObject.cs create mode 100644 InfectedRose.Nif/Nodes/NiCollisionObject.cs create mode 100644 InfectedRose.Nif/Nodes/NiGeometry.cs create mode 100644 InfectedRose.Nif/Nodes/NiLODNode.cs create mode 100644 InfectedRose.Nif/Nodes/NiNode.cs create mode 100644 InfectedRose.Nif/Nodes/NiObjectNet.cs create mode 100644 InfectedRose.Nif/Nodes/NiSwitchNode.cs create mode 100644 InfectedRose.Nif/Nodes/NiTriBasedGeom.cs create mode 100644 InfectedRose.Nif/Nodes/NiTriShape.cs create mode 100644 InfectedRose.Nif/Nodes/NiTriStrips.cs create mode 100644 InfectedRose.Nif/Properties/NiMaterialProperty.cs create mode 100644 InfectedRose.Nif/Properties/NiProperty.cs create mode 100644 InfectedRose.Nif/Properties/NiShadeProperty.cs create mode 100644 InfectedRose.Nif/Properties/NiSpecularProperty.cs create mode 100644 InfectedRose.Nif/Properties/NiVertexColorProperty.cs create mode 100644 InfectedRose.Nif/Properties/NiZBufferProperty.cs create mode 100644 InfectedRose.Nif/Structs/Color3.cs create mode 100644 InfectedRose.Nif/Structs/Color4.cs create mode 100644 InfectedRose.Nif/Structs/LODRange.cs create mode 100644 InfectedRose.Nif/Structs/MatchGroup.cs create mode 100644 InfectedRose.Nif/Structs/Matrix3X3.cs create mode 100644 InfectedRose.Nif/Structs/Triangle.cs diff --git a/InfectedRose.Core/Extensions/BitReaderExtensions.cs b/InfectedRose.Core/Extensions/BitReaderExtensions.cs index 64d60a9..fd66a19 100644 --- a/InfectedRose.Core/Extensions/BitReaderExtensions.cs +++ b/InfectedRose.Core/Extensions/BitReaderExtensions.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System; using System.Numerics; using RakDotNet.IO; @@ -20,14 +20,6 @@ public static string ReadNiString(this BitReader @this, bool wide = false, bool return new string(str); } - public static void Write(this BitWriter @this, ICollection collection) where T : struct - { - foreach (var value in collection) - { - @this.Write(value); - } - } - public static Quaternion ReadNiQuaternion(this BitReader @this) { return new Quaternion @@ -50,5 +42,14 @@ public static byte[] ReadBuffer(this BitReader @this, uint length) return buffer; } + + public static T Read(this BitReader @this) where T : IDeserializable + { + var instance = Activator.CreateInstance(); + + instance.Deserialize(@this); + + return instance; + } } } \ No newline at end of file diff --git a/InfectedRose.Core/Extensions/BitWriterExtensions.cs b/InfectedRose.Core/Extensions/BitWriterExtensions.cs index fe1eeda..751fc08 100644 --- a/InfectedRose.Core/Extensions/BitWriterExtensions.cs +++ b/InfectedRose.Core/Extensions/BitWriterExtensions.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using System.Numerics; using RakDotNet.IO; @@ -43,5 +44,18 @@ public static void Write(this BitWriter @this, byte[] buffer) @this.Write(value); } } + + public static void Write(this BitWriter @this, ICollection collection) where T : struct + { + foreach (var value in collection) + { + @this.Write(value); + } + } + + public static void Write(this BitWriter @this, ISerializable serializable) + { + serializable.Serialize(@this); + } } } \ No newline at end of file diff --git a/InfectedRose.Database/Concepts/Generic/LwoObjectExtensions.cs b/InfectedRose.Database/Concepts/Generic/LwoObjectExtensions.cs new file mode 100644 index 0000000..0a10822 --- /dev/null +++ b/InfectedRose.Database/Concepts/Generic/LwoObjectExtensions.cs @@ -0,0 +1,25 @@ +using System; + +namespace InfectedRose.Database.Concepts.Generic +{ + public static class LwoObjectExtensions + { + public static T GetComponent(this LwoObject @this) where T : class + { + var name = typeof(T).Name; + + foreach (var component in @this) + { + if (component.Row?.Table?.Name == default) continue; + + if ($"{component.Row.Table.Name}Table" != name) continue; + + var instance = Activator.CreateInstance(typeof(T), component.Row) as T; + + return instance; + } + + return default; + } + } +} \ No newline at end of file diff --git a/InfectedRose.Database/Concepts/LwoObject.cs b/InfectedRose.Database/Concepts/LwoObject.cs index 8cadd4b..2842cc5 100644 --- a/InfectedRose.Database/Concepts/LwoObject.cs +++ b/InfectedRose.Database/Concepts/LwoObject.cs @@ -2,7 +2,6 @@ using System.Collections; using System.Collections.Generic; using System.Linq; -using InfectedRose.Database.Generic; namespace InfectedRose.Database.Concepts { @@ -27,7 +26,7 @@ private List Components foreach (var entry in Database["ComponentsRegistry"].Where(r => r.Key == Row.Key)) { - var type = (ComponentId) entry.Value("component_type"); + var type = (ComponentId) entry["component_type"].Value; var component = new LwoComponent { @@ -40,7 +39,7 @@ private List Components var componentTable = Database[$"{type}"]; - var id = entry.Value("component_id"); + var id = (int) entry["component_id"].Value; if (id == 0 || componentTable == default) continue; diff --git a/InfectedRose.Database/FdbRowInfo.cs b/InfectedRose.Database/FdbRowInfo.cs index 4e726f9..272cb09 100644 --- a/InfectedRose.Database/FdbRowInfo.cs +++ b/InfectedRose.Database/FdbRowInfo.cs @@ -12,24 +12,30 @@ internal class FdbRowInfo : DatabaseData public override void Deserialize(BitReader reader) { - using (var s = new DatabaseScope(reader, true)) + // Super hacky way of getting around stackoverflow + Task.Run(() => { - if (s) + lock (reader) { - DataHeader = new FdbRowDataHeader(); - - DataHeader.Deserialize(reader); + using var s = new DatabaseScope(reader, true); + + if (s) + { + DataHeader = new FdbRowDataHeader(); + + DataHeader.Deserialize(reader); + } } - } - using (var s = new DatabaseScope(reader, true)) - { - if (!s) return; + using (var s = new DatabaseScope(reader, true)) + { + if (!s) return; - Linked = new FdbRowInfo(); + Linked = new FdbRowInfo(); - Linked.Deserialize(reader); - } + Linked.Deserialize(reader); + } + }).Wait(); } public override void Compile(HashMap map) diff --git a/InfectedRose.Database/Table.cs b/InfectedRose.Database/Table.cs index 50e60a1..1c7bf0a 100644 --- a/InfectedRose.Database/Table.cs +++ b/InfectedRose.Database/Table.cs @@ -23,6 +23,8 @@ internal Table(FdbColumnHeader info, FdbRowBucket data, AccessDatabase database) internal AccessDatabase Database { get; } + public uint Buckets => (uint) Data.RowHeader.RowInfos.Length; + public string Name { get => Info.TableName; @@ -278,10 +280,7 @@ public Column Create(object key, object values) return new Column(column, this); } - public void Recalculate() - { - Recalculate(1); - } + public void Recalculate() => Recalculate(1); public void Recalculate(int bucketSize) { @@ -300,9 +299,9 @@ public void Recalculate(int bucketSize) taken.Add(row.Key); } - var buckets = FdbRowBucket.NextPowerOf2(bucketSize == -1 ? taken.Count : bucketSize); + var buckets = FdbRowBucket.NextPowerOf2(bucketSize == default ? taken.Count : bucketSize); - var final = new FdbRowInfo[buckets]; + var hierarchy = new Dictionary>(); var data = this.ToArray(); @@ -314,36 +313,39 @@ public void Recalculate(int bucketSize) var key = index % buckets; - FdbRowInfo bucket; - - try + if (hierarchy.TryGetValue(key, out var list)) { - bucket = final[key]; + list.Add(column.Data); } - catch (Exception e) + else { - Console.WriteLine( - $"\n\"[{column[0].Type}] {column[0].Value}\" [{index}] -> {key} / {buckets}\n{e}\n"); - - Console.ReadLine(); - - throw; + hierarchy[key] = new List + { + column.Data + }; } + } + + var final = new FdbRowInfo[buckets]; - if (bucket != default) - { - var linked = bucket; + foreach (var (key, values) in hierarchy) + { + var root = values[0]; - while (linked.Linked != default) linked = linked.Linked; + var current = root; - linked.Linked = column.Data; - } - else + values.RemoveAt(0); + + foreach (var value in values) { - final[index % buckets] = column.Data; + current.Linked = value; + + current = value; } - } + final[key] = root; + } + Data.RowHeader.RowInfos = final.ToArray(); } diff --git a/InfectedRose.Examples/AccessDatabaseCommand.cs b/InfectedRose.Examples/AccessDatabaseCommand.cs new file mode 100644 index 0000000..1eefc24 --- /dev/null +++ b/InfectedRose.Examples/AccessDatabaseCommand.cs @@ -0,0 +1,45 @@ +using System; +using System.IO; +using Eto.Forms; + +namespace InfectedRose.Examples +{ + public class AccessDatabaseCommand : Command + { + public string Macro = $"{Application.Instance.CommonModifier} + {Keys.O}"; + + private AccessEditor Editor { get; } + + public AccessDatabaseCommand(AccessEditor editor) + { + Editor = editor; + + MenuText = "Open..."; + + ToolBarText = "Open a Database"; + + ToolTip = "Open a Database of Access type"; + + Shortcut = Application.Instance.CommonModifier | Keys.O; + } + + protected override void OnExecuted(EventArgs e) + { + base.OnExecuted(e); + + var dialog = new OpenFileDialog(); + + dialog.Filters.Add(new FileFilter("*.fdb", ".fdb")); + dialog.Filters.Add(new FileFilter("*")); + + dialog.ShowDialog(Editor); + + Console.WriteLine(dialog.FileName); + + if (File.Exists(dialog.FileName)) + { + Editor.OpenDatabase(dialog.FileName); + } + } + } +} \ No newline at end of file diff --git a/InfectedRose.Examples/AccessEditor.cs b/InfectedRose.Examples/AccessEditor.cs new file mode 100644 index 0000000..5e152ea --- /dev/null +++ b/InfectedRose.Examples/AccessEditor.cs @@ -0,0 +1,142 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Threading.Tasks; +using Eto.Drawing; +using Eto.Forms; +using InfectedRose.Database; + +namespace InfectedRose.Examples +{ + public sealed class AccessEditor : Form + { + public AccessDatabase Database { get; set; } + + public TableLayout MainTable { get; set; } + + public List> Bindings { get; } + + public string Status { get; set; } + + public AccessEditor() + { + Bindings = new List>(); + + Title = "Access Editor"; + + ClientSize = new Size + { + Height = 400, + Width = 640 + }; + + Resizable = true; + + var accessCommand = new AccessDatabaseCommand(this); + + var menu = new MenuBar + { + Items = + { + new ButtonMenuItem + { + Text = "File", + Items = + { + accessCommand + } + } + } + }; + + Menu = menu; + + Status = $"Open a database by using Open/File or {accessCommand.Macro}"; + + MainTable = new TableLayout + { + Spacing = new Size(1, 3), // space between each cell + Padding = new Padding(10, 10, 10, 10), // space around the table's sides + Rows = + { + new TableRow( + new TableCell(StatusBinding(), true) + ), + new TableRow( + + ), + new TableRow { ScaleHeight = true } + } + }; + + Content = MainTable; + } + + private Label StatusBinding() + { + var label = new Label(); + + var binding = label.TextBinding.Bind(() => Status); + + Bindings.Add(binding); + + return label; + } + + public void Update() + { + foreach (var binding in Bindings) + { + binding.Update(); + } + } + + public void OpenDatabase(string path) + { + Status = "Opening database..."; + + Console.WriteLine("Opening db"); + + Task.Run(async () => + { + try + { + Database = await AccessDatabase.OpenAsync(path); + + ShowDatabase(); + } + catch (Exception e) + { + Console.WriteLine(e); + + Status = "Failed to load database."; + + return; + } + + Status = "Database loaded..."; + }); + } + + public void ShowDatabase() + { + /* + Editor = new TableLayout + { + Spacing = new Size(2, Database.Count), // space between each cell + Padding = new Padding(10, 10, 10, 10), // space around the table's sides + }; + + foreach (var table in Database) + { + var editor = (TableLayout) Editor; + + editor.Rows.Add(new TableRow + ( + new TableCell(new Label {Text = table.Name}) + )); + } + */ + } + } +} \ No newline at end of file diff --git a/InfectedRose.Nif/Controllers/NiTimeController.cs b/InfectedRose.Nif/Controllers/NiTimeController.cs new file mode 100644 index 0000000..679188d --- /dev/null +++ b/InfectedRose.Nif/Controllers/NiTimeController.cs @@ -0,0 +1,17 @@ +using RakDotNet.IO; + +namespace InfectedRose.Nif.Controllers +{ + public class NiTimeController : NiObject + { + public override void Serialize(BitWriter writer) + { + throw new System.NotImplementedException(); + } + + public override void Deserialize(BitReader reader) + { + throw new System.NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/InfectedRose.Nif/Data/AbstractAdditionalGeometryData.cs b/InfectedRose.Nif/Data/AbstractAdditionalGeometryData.cs new file mode 100644 index 0000000..575de3b --- /dev/null +++ b/InfectedRose.Nif/Data/AbstractAdditionalGeometryData.cs @@ -0,0 +1,17 @@ +using RakDotNet.IO; + +namespace InfectedRose.Nif +{ + public class AbstractAdditionalGeometryData : NiObject + { + public override void Serialize(BitWriter writer) + { + throw new System.NotImplementedException(); + } + + public override void Deserialize(BitReader reader) + { + throw new System.NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/InfectedRose.Nif/Data/NiGeometryData.cs b/InfectedRose.Nif/Data/NiGeometryData.cs new file mode 100644 index 0000000..83f314f --- /dev/null +++ b/InfectedRose.Nif/Data/NiGeometryData.cs @@ -0,0 +1,186 @@ +using System.Numerics; +using InfectedRose.Core; +using RakDotNet.IO; + +namespace InfectedRose.Nif +{ + public class NiGeometryData : NiObject + { + public int GroupId { get; set; } + + public byte KeepFlags { get; set; } + + public byte CompressFlags { get; set; } + + public Vector3[] Vertices { get; set; } + + public Vector3[] Normals { get; set; } + + public Vector3 Center { get; set; } + + public float Radius { get; set; } + + public Color4[] VertexColors { get; set; } + + public ushort ConsistencyFlags { get; set; } + + public NiRef AdditionData { get; set; } + + public ushort NumUvSets { get; set; } + + public Vector2[][] Uv { get; set; } + + public Vector3[] Tangents { get; set; } + + public Vector3[] BitTangents { get; set; } + + public override void Serialize(BitWriter writer) + { + var verticesCount = (ushort) Vertices.Length; + + writer.Write(GroupId); + + writer.Write(verticesCount); + + writer.Write(KeepFlags); + + writer.Write(CompressFlags); + + writer.Write((byte) (verticesCount > 0 ? 1 : 0)); + + foreach (var vertex in Vertices) + { + writer.Write(vertex); + } + + writer.Write(NumUvSets); + + writer.Write((byte) (Normals.Length > 0 ? 1 : 0)); + + foreach (var normal in Normals) + { + writer.Write(normal); + } + + if (Normals.Length > 0 & (NumUvSets & 61440) != 0) + { + foreach (var tangent in Tangents) + { + writer.Write(tangent); + } + + foreach (var bitTangent in BitTangents) + { + writer.Write(bitTangent); + } + } + + writer.Write(Center); + + writer.Write(Radius); + + writer.Write((byte) (VertexColors.Length > 0 ? 1 : 0)); + + foreach (var vertexColor in VertexColors) + { + writer.Write(vertexColor); + } + + foreach (var layer in Uv) + { + foreach (var vector2 in layer) + { + writer.Write(vector2); + } + } + + writer.Write(ConsistencyFlags); + + writer.Write(AdditionData); + } + + public override void Deserialize(BitReader reader) + { + GroupId = reader.Read(); + + var verticesCount = reader.Read(); + + KeepFlags = reader.Read(); + + CompressFlags = reader.Read(); + + var hasVertices = reader.Read() != 0; + + if (hasVertices) + { + Vertices = new Vector3[verticesCount]; + + for (var i = 0; i < Vertices.Length; i++) + { + Vertices[i] = reader.Read(); + } + } + + NumUvSets = reader.Read(); + + var hasNormals = reader.Read() != 0; + + if (hasNormals) + { + Normals = new Vector3[verticesCount]; + + for (var i = 0; i < Normals.Length; i++) + { + Normals[i] = reader.Read(); + } + } + + if (hasNormals && (NumUvSets & 61440) != 0) + { + Tangents = new Vector3[verticesCount]; + for (var i = 0; i < verticesCount; i++) + { + Tangents[i] = reader.Read(); + } + + BitTangents = new Vector3[verticesCount]; + for (var i = 0; i < verticesCount; i++) + { + BitTangents[i] = reader.Read(); + } + } + + Center = reader.Read(); + + Radius = reader.Read(); + + var hasVertexColors = reader.Read() != 0; + + if (hasVertexColors) + { + VertexColors = new Color4[verticesCount]; + + for (var i = 0; i < verticesCount; i++) + { + VertexColors[i] = reader.Read(); + } + } + + Uv = new Vector2[NumUvSets & 63][]; + + for (var i = 0; i < Uv.Length; i++) + { + Uv[i] = new Vector2[verticesCount]; + + for (var j = 0; j < verticesCount; j++) + { + Uv[i][j] = reader.Read(); + } + } + + ConsistencyFlags = reader.Read(); + + AdditionData = reader.Read>(File); + } + } +} \ No newline at end of file diff --git a/InfectedRose.Nif/Data/NiLODData.cs b/InfectedRose.Nif/Data/NiLODData.cs new file mode 100644 index 0000000..bc13b3d --- /dev/null +++ b/InfectedRose.Nif/Data/NiLODData.cs @@ -0,0 +1,15 @@ +using RakDotNet.IO; + +namespace InfectedRose.Nif +{ + public class NiLODData : NiObject + { + public override void Serialize(BitWriter writer) + { + } + + public override void Deserialize(BitReader reader) + { + } + } +} \ No newline at end of file diff --git a/InfectedRose.Nif/Data/NiRangeLODData.cs b/InfectedRose.Nif/Data/NiRangeLODData.cs new file mode 100644 index 0000000..26cd149 --- /dev/null +++ b/InfectedRose.Nif/Data/NiRangeLODData.cs @@ -0,0 +1,40 @@ +using System.Numerics; +using RakDotNet.IO; + +namespace InfectedRose.Nif +{ + public class NiRangeLODData : NiLODData + { + public Vector3 Center { get; set; } + + public LODRange[] Ranges { get; set; } + + public override void Serialize(BitWriter writer) + { + base.Serialize(writer); + + writer.Write(Center); + + writer.Write((uint) Ranges.Length); + + foreach (var range in Ranges) + { + writer.Write(range); + } + } + + public override void Deserialize(BitReader reader) + { + base.Deserialize(reader); + + Center = reader.Read(); + + Ranges = new LODRange[reader.Read()]; + + for (var i = 0; i < Ranges.Length; i++) + { + Ranges[i] = reader.Read(); + } + } + } +} \ No newline at end of file diff --git a/InfectedRose.Nif/Data/NiScreenLODData.cs b/InfectedRose.Nif/Data/NiScreenLODData.cs new file mode 100644 index 0000000..0b04ef5 --- /dev/null +++ b/InfectedRose.Nif/Data/NiScreenLODData.cs @@ -0,0 +1,54 @@ +using System.Numerics; +using RakDotNet.IO; + +namespace InfectedRose.Nif +{ + public class NiScreenLODData : NiLODData + { + public Vector3 BoundCenter { get; set; } + + public float BoundRadius { get; set; } + + public Vector3 WorldCenter { get; set; } + + public float WorldRadius { get; set; } + + public float[] Proportions { get; set; } + + public override void Serialize(BitWriter writer) + { + writer.Write(BoundCenter); + + writer.Write(BoundRadius); + + writer.Write(WorldCenter); + + writer.Write(WorldRadius); + + writer.Write((uint) Proportions.Length); + + foreach (var proportion in Proportions) + { + writer.Write(proportion); + } + } + + public override void Deserialize(BitReader reader) + { + BoundCenter = reader.Read(); + + BoundRadius = reader.Read(); + + WorldCenter = reader.Read(); + + WorldRadius = reader.Read(); + + Proportions = new float[reader.Read()]; + + for (var i = 0; i < Proportions.Length; i++) + { + Proportions[i] = reader.Read(); + } + } + } +} \ No newline at end of file diff --git a/InfectedRose.Nif/Data/NiSkinInstance.cs b/InfectedRose.Nif/Data/NiSkinInstance.cs new file mode 100644 index 0000000..a36be41 --- /dev/null +++ b/InfectedRose.Nif/Data/NiSkinInstance.cs @@ -0,0 +1,17 @@ +using RakDotNet.IO; + +namespace InfectedRose.Nif +{ + public class NiSkinInstance : NiObject + { + public override void Serialize(BitWriter writer) + { + throw new System.NotImplementedException(); + } + + public override void Deserialize(BitReader reader) + { + throw new System.NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/InfectedRose.Nif/Data/NiTriBasedGeomData.cs b/InfectedRose.Nif/Data/NiTriBasedGeomData.cs new file mode 100644 index 0000000..fd58f53 --- /dev/null +++ b/InfectedRose.Nif/Data/NiTriBasedGeomData.cs @@ -0,0 +1,23 @@ +using RakDotNet.IO; + +namespace InfectedRose.Nif +{ + public class NiTriBasedGeomData : NiGeometryData + { + public ushort TriangleCount { get; set; } + + public override void Deserialize(BitReader reader) + { + base.Deserialize(reader); + + TriangleCount = reader.Read(); + } + + public override void Serialize(BitWriter writer) + { + base.Serialize(writer); + + writer.Write(TriangleCount); + } + } +} \ No newline at end of file diff --git a/InfectedRose.Nif/Data/NiTriShapeData.cs b/InfectedRose.Nif/Data/NiTriShapeData.cs new file mode 100644 index 0000000..e6cccea --- /dev/null +++ b/InfectedRose.Nif/Data/NiTriShapeData.cs @@ -0,0 +1,53 @@ +using RakDotNet.IO; + +namespace InfectedRose.Nif +{ + public class NiTriShapeData : NiTriBasedGeomData + { + public Triangle[] Triangles { get; set; } + + public MatchGroup[] Groups { get; set; } + + public override void Deserialize(BitReader reader) + { + base.Deserialize(reader); + + var points = reader.Read(); + + Triangles = new Triangle[TriangleCount]; + + for (var i = 0; i < TriangleCount; i++) + { + Triangles[i] = reader.Read(); + } + + Groups = new MatchGroup[reader.Read()]; + + for (var i = 0; i < Groups.Length; i++) + { + Groups[i] = reader.Read(); + } + } + + public override void Serialize(BitWriter writer) + { + TriangleCount = (ushort) Triangles.Length; + + base.Serialize(writer); + + writer.Write((uint) (TriangleCount * 3)); + + foreach (var triangle in Triangles) + { + writer.Write(triangle); + } + + writer.Write((ushort) Groups.Length); + + foreach (var group in Groups) + { + writer.Write(group); + } + } + } +} \ No newline at end of file diff --git a/InfectedRose.Nif/Effects/NiAmbientLight.cs b/InfectedRose.Nif/Effects/NiAmbientLight.cs new file mode 100644 index 0000000..c2bed06 --- /dev/null +++ b/InfectedRose.Nif/Effects/NiAmbientLight.cs @@ -0,0 +1,7 @@ +namespace InfectedRose.Nif +{ + public class NiAmbientLight : NiLight + { + + } +} \ No newline at end of file diff --git a/InfectedRose.Nif/Effects/NiDynamicEffect.cs b/InfectedRose.Nif/Effects/NiDynamicEffect.cs new file mode 100644 index 0000000..f967db0 --- /dev/null +++ b/InfectedRose.Nif/Effects/NiDynamicEffect.cs @@ -0,0 +1,40 @@ +using InfectedRose.Core; +using RakDotNet.IO; + +namespace InfectedRose.Nif +{ + public class NiDynamicEffect : NiAvObject + { + public bool SwitchState { get; set; } + + public NiRef[] Affected { get; set; } + + public override void Deserialize(BitReader reader) + { + base.Deserialize(reader); + + SwitchState = reader.Read() != 0; + + Affected = new NiRef[reader.Read()]; + + for (var i = 0; i < Affected.Length; i++) + { + Affected[i] = reader.Read>(File); + } + } + + public override void Serialize(BitWriter writer) + { + base.Serialize(writer); + + writer.Write((byte) (SwitchState ? 1 : 0)); + + writer.Write((uint) Affected.Length); + + foreach (var node in Affected) + { + writer.Write(node); + } + } + } +} \ No newline at end of file diff --git a/InfectedRose.Nif/Effects/NiLight.cs b/InfectedRose.Nif/Effects/NiLight.cs new file mode 100644 index 0000000..f15aaa6 --- /dev/null +++ b/InfectedRose.Nif/Effects/NiLight.cs @@ -0,0 +1,41 @@ +using RakDotNet.IO; + +namespace InfectedRose.Nif +{ + public class NiLight : NiDynamicEffect + { + public float Dimmer { get; set; } + + public Color3 Ambient { get; set; } + + public Color3 Diffuse { get; set; } + + public Color3 Specular { get; set; } + + public override void Deserialize(BitReader reader) + { + base.Deserialize(reader); + + Dimmer = reader.Read(); + + Ambient = reader.Read(); + + Diffuse = reader.Read(); + + Specular = reader.Read(); + } + + public override void Serialize(BitWriter writer) + { + base.Serialize(writer); + + writer.Write(Dimmer); + + writer.Write(Ambient); + + writer.Write(Diffuse); + + writer.Write(Specular); + } + } +} \ No newline at end of file diff --git a/InfectedRose.Nif/Enums/NifVersion.cs b/InfectedRose.Nif/Enums/NifVersion.cs index 178d66c..50d8e67 100644 --- a/InfectedRose.Nif/Enums/NifVersion.cs +++ b/InfectedRose.Nif/Enums/NifVersion.cs @@ -155,7 +155,7 @@ public enum NifVersion : uint /// /// The ve R_20_3_0_9 /// - Ver20309 = 335740937u, // LEGO Universe + Ver20309 = 0x14030009u, // LEGO Universe /// /// The ve r_ unsupported diff --git a/InfectedRose.Nif/Extensions/BitReaderExtensions.cs b/InfectedRose.Nif/Extensions/BitReaderExtensions.cs new file mode 100644 index 0000000..612c4de --- /dev/null +++ b/InfectedRose.Nif/Extensions/BitReaderExtensions.cs @@ -0,0 +1,19 @@ +using System; +using RakDotNet.IO; + +namespace InfectedRose.Nif +{ + public static class BitReaderExtensions + { + public static T Read(this BitReader @this, NiFile file) where T : NiObject + { + var instance = Activator.CreateInstance(); + + instance.File = file; + + instance.Deserialize(@this); + + return instance; + } + } +} \ No newline at end of file diff --git a/InfectedRose.Nif/Extra/NiExtraData.cs b/InfectedRose.Nif/Extra/NiExtraData.cs new file mode 100644 index 0000000..6b2dbea --- /dev/null +++ b/InfectedRose.Nif/Extra/NiExtraData.cs @@ -0,0 +1,20 @@ +using InfectedRose.Core; +using RakDotNet.IO; + +namespace InfectedRose.Nif +{ + public class NiExtraData : NiObject + { + public NiStringRef Name { get; set; } + + public override void Serialize(BitWriter writer) + { + writer.Write(Name); + } + + public override void Deserialize(BitReader reader) + { + Name = reader.Read(File); + } + } +} \ No newline at end of file diff --git a/InfectedRose.Nif/Extra/NiStringExtraData.cs b/InfectedRose.Nif/Extra/NiStringExtraData.cs new file mode 100644 index 0000000..bd83ccf --- /dev/null +++ b/InfectedRose.Nif/Extra/NiStringExtraData.cs @@ -0,0 +1,24 @@ +using InfectedRose.Core; +using RakDotNet.IO; + +namespace InfectedRose.Nif +{ + public class NiStringExtraData : NiExtraData + { + public NiStringRef StringData { get; set; } + + public override void Deserialize(BitReader reader) + { + base.Deserialize(reader); + + StringData = reader.Read(File); + } + + public override void Serialize(BitWriter writer) + { + base.Serialize(writer); + + writer.Write(StringData); + } + } +} \ No newline at end of file diff --git a/InfectedRose.Nif/NiFile.cs b/InfectedRose.Nif/NiFile.cs new file mode 100644 index 0000000..4369da5 --- /dev/null +++ b/InfectedRose.Nif/NiFile.cs @@ -0,0 +1,154 @@ +using System; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using InfectedRose.Core; +using RakDotNet.IO; + +namespace InfectedRose.Nif +{ + public class NiFile : IConstruct + { + public NiHeader Header { get; set; } + + public NiObject[] Blocks { get; set; } + + public void Serialize(BitWriter writer) + { + writer.Write(Header); + + for (var index = 0; index < Blocks.Length; index++) + { + var info = Header.NodeInfo[index]; + + var current = writer.BaseStream.Position; + + var block = Blocks[index]; + writer.Write(block); + + var now = writer.BaseStream.Position; + + var size = now - current; + + if (size != info.Size) + { + throw new Exception($"Failed to write {block}, {size}/{info.Size} bytes"); + } + } + } + + public void Deserialize(BitReader reader) + { + Header = reader.Read(); + } + + public Task ReadBlocksAsync(BitReader reader) + { + var type = typeof(NiObject); + + var blockTypes = type.Assembly.GetTypes().Where( + t => t.IsSubclassOf(type) + ).ToArray(); + + var blocks = Header.NodeInfo.Length; + + var readingTasks = new Task[blocks]; + + Blocks = new NiObject[blocks]; + + for (var i = 0; i < blocks; i++) + { + var blockInfo = Header.NodeInfo[i]; + var typeName = Header.NodeTypes[blockInfo.TypeIndex]; + + var data = reader.ReadBuffer(blockInfo.Size); + + var index = i; + + readingTasks[i] = Task.Run(async () => + { + await using var stream = new MemoryStream(data); + + using var blockReader = new BitReader(stream); + + var blockType = blockTypes.FirstOrDefault( + t => t.Name == typeName + ); + + if (blockType == default) + { + throw new NotImplementedException($"Block \"{typeName}\" is not implemented"); + } + + var instance = (NiObject) Activator.CreateInstance(blockType); + + instance.File = this; + + instance.Deserialize(blockReader); + + Blocks[index] = instance; + + if (stream.Position != stream.Length) + { + throw new Exception( + $"Failed to read {typeName}, read {stream.Position}/{stream.Length} bytes" + ); + } + }); + } + + return Task.WhenAll(readingTasks); + } + + public void ReadBlocks(BitReader reader) + { + var type = typeof(NiObject); + + var blockTypes = type.Assembly.GetTypes().Where( + t => t.IsSubclassOf(type) + ).ToArray(); + + var blocks = Header.NodeInfo.Length; + + Blocks = new NiObject[blocks]; + + for (var i = 0; i < blocks; i++) + { + var blockInfo = Header.NodeInfo[i]; + var typeName = Header.NodeTypes[blockInfo.TypeIndex]; + + var data = reader.ReadBuffer(blockInfo.Size); + + var index = i; + + using var stream = new MemoryStream(data); + + using var blockReader = new BitReader(stream); + + var blockType = blockTypes.FirstOrDefault( + t => t.Name == typeName + ); + + if (blockType == default) + { + throw new NotImplementedException($"Block \"{typeName}\" is not implemented"); + } + + var instance = (NiObject) Activator.CreateInstance(blockType); + + instance.File = this; + + instance.Deserialize(blockReader); + + Blocks[index] = instance; + + if (stream.Position != stream.Length) + { + throw new Exception( + $"Failed to read {typeName}, read {stream.Position}/{stream.Length} bytes" + ); + } + } + } + } +} \ No newline at end of file diff --git a/InfectedRose.Nif/NifHeader.cs b/InfectedRose.Nif/NiHeader.cs similarity index 72% rename from InfectedRose.Nif/NifHeader.cs rename to InfectedRose.Nif/NiHeader.cs index 01f4b77..3bfbd44 100644 --- a/InfectedRose.Nif/NifHeader.cs +++ b/InfectedRose.Nif/NiHeader.cs @@ -5,7 +5,7 @@ namespace InfectedRose.Nif { - public class NifHeader : IConstruct + public class NiHeader : IConstruct { public NifVersion Version { get; set; } @@ -19,6 +19,8 @@ public class NifHeader : IConstruct public string[] NodeTypes { get; set; } + public string[] Strings { get; set; } + public uint MaxStringLength { get; set; } public uint[] Groups { get; set; } @@ -32,8 +34,6 @@ public void Serialize(BitWriter writer) writer.Write(0xA); - writer.Write(0); - writer.Write((uint) Version); writer.Write((byte) Endian); @@ -57,12 +57,32 @@ public void Serialize(BitWriter writer) { writer.Write(blockInfo.Size); } + + writer.Write((uint) Strings.Length); + + writer.Write(MaxStringLength); + + foreach (var str in Strings) + { + writer.WriteNiString(str); + } + + writer.Write((uint) Groups.Length); + + foreach (var group in Groups) + { + writer.Write(group); + } } public void Deserialize(BitReader reader) { var versionStringBuilder = new StringBuilder(); + // + // Version + // + var character = reader.Read(); while (character != 0xA) { @@ -100,6 +120,22 @@ public void Deserialize(BitReader reader) { info.Size = reader.Read(); } + + Strings = new string[reader.Read()]; + + MaxStringLength = reader.Read(); + + for (var i = 0; i < Strings.Length; i++) + { + Strings[i] = reader.ReadNiString(); + } + + Groups = new uint[reader.Read()]; + + for (var i = 0; i < Groups.Length; i++) + { + Groups[i] = reader.Read(); + } } } } \ No newline at end of file diff --git a/InfectedRose.Nif/NiObject.cs b/InfectedRose.Nif/NiObject.cs new file mode 100644 index 0000000..6bc0985 --- /dev/null +++ b/InfectedRose.Nif/NiObject.cs @@ -0,0 +1,14 @@ +using InfectedRose.Core; +using RakDotNet.IO; + +namespace InfectedRose.Nif +{ + public abstract class NiObject : IConstruct + { + public NiFile File { get; set; } + + public abstract void Serialize(BitWriter writer); + + public abstract void Deserialize(BitReader reader); + } +} \ No newline at end of file diff --git a/InfectedRose.Nif/NiRef.cs b/InfectedRose.Nif/NiRef.cs new file mode 100644 index 0000000..dd8d134 --- /dev/null +++ b/InfectedRose.Nif/NiRef.cs @@ -0,0 +1,48 @@ +using System.Linq; +using RakDotNet.IO; + +namespace InfectedRose.Nif +{ + public class NiRef : NiRef + { + + } + + public class NiRef : NiObject where T : NiObject + { + public int Key { get; set; } + + public T Value + { + get + { + if (Key == -1) return default; + + return File.Blocks[Key] as T; + } + set + { + if (value == default) + { + Key = -1; + + return; + } + + Key = File.Blocks.ToList().IndexOf(value); + } + } + + public override void Serialize(BitWriter writer) + { + writer.Write(Key); + } + + public override void Deserialize(BitReader reader) + { + Key = reader.Read(); + } + + public static implicit operator T(NiRef @ref) => @ref.Value; + } +} \ No newline at end of file diff --git a/InfectedRose.Nif/NiStringRef.cs b/InfectedRose.Nif/NiStringRef.cs new file mode 100644 index 0000000..45c38ae --- /dev/null +++ b/InfectedRose.Nif/NiStringRef.cs @@ -0,0 +1,38 @@ +using System.Linq; +using RakDotNet.IO; + +namespace InfectedRose.Nif +{ + public class NiStringRef : NiObject + { + public int Key { get; set; } + + public string Value + { + get => Key == -1 ? default : File.Header.Strings[Key]; + set + { + if (value == default) + { + Key = -1; + + return; + } + + Key = File.Header.Strings.ToList().IndexOf(value); + } + } + + public override void Serialize(BitWriter writer) + { + writer.Write(Key); + } + + public override void Deserialize(BitReader reader) + { + Key = reader.Read(); + } + + public static implicit operator string(NiStringRef @ref) => @ref.Value; + } +} \ No newline at end of file diff --git a/InfectedRose.Nif/NifFile.cs b/InfectedRose.Nif/NifFile.cs deleted file mode 100644 index 89d5af6..0000000 --- a/InfectedRose.Nif/NifFile.cs +++ /dev/null @@ -1,22 +0,0 @@ -using InfectedRose.Core; -using RakDotNet.IO; - -namespace InfectedRose.Nif -{ - public class NifFile : IConstruct - { - public NifHeader Header { get; set; } - - public void Serialize(BitWriter writer) - { - Header.Serialize(writer); - } - - public void Deserialize(BitReader reader) - { - Header = new NifHeader(); - - Header.Deserialize(reader); - } - } -} \ No newline at end of file diff --git a/InfectedRose.Nif/NifString.cs b/InfectedRose.Nif/NifString.cs deleted file mode 100644 index 64711ce..0000000 --- a/InfectedRose.Nif/NifString.cs +++ /dev/null @@ -1,40 +0,0 @@ -using InfectedRose.Core; -using RakDotNet.IO; - -namespace InfectedRose.Nif -{ - public class NifString : IConstruct - { - public string Value { get; set; } - - public bool Wide { get; set; } - - public bool Small { get; set; } - - public void Serialize(BitWriter writer) - { - if (Small) writer.Write((byte) Value.Length); - else writer.Write((uint) Value.Length); - - foreach (var character in Value) - { - if (Wide) writer.Write((ushort) character); - else writer.Write((byte) character); - } - } - - public void Deserialize(BitReader reader) - { - var length = Small ? reader.Read() : reader.Read(); - - var chars = new char[length]; - - for (var i = 0; i < length; i++) - { - chars[i] = (char) (Wide ? reader.Read() : reader.Read()); - } - - Value = new string(chars); - } - } -} \ No newline at end of file diff --git a/InfectedRose.Nif/Nodes/NiAvObject.cs b/InfectedRose.Nif/Nodes/NiAvObject.cs new file mode 100644 index 0000000..0e38330 --- /dev/null +++ b/InfectedRose.Nif/Nodes/NiAvObject.cs @@ -0,0 +1,65 @@ +using System.Numerics; +using InfectedRose.Core; +using RakDotNet.IO; + +namespace InfectedRose.Nif +{ + public class NiAvObject : NiObjectNet + { + public ushort Flags { get; set; } + + public Vector3 Position { get; set; } + + public Matrix3X3 Rotation { get; set; } + + public float Scale { get; set; } + + public NiRef[] Properties { get; set; } + + public NiRef CollisionObject { get; set; } + + public override void Serialize(BitWriter writer) + { + base.Serialize(writer); + + writer.Write(Flags); + + writer.Write(Position); + + writer.Write(Rotation); + + writer.Write(Scale); + + writer.Write((uint) Properties.Length); + + foreach (var property in Properties) + { + writer.Write(property); + } + + writer.Write(CollisionObject); + } + + public override void Deserialize(BitReader reader) + { + base.Deserialize(reader); + + Flags = reader.Read(); + + Position = reader.Read(); + + Rotation = reader.Read(); + + Scale = reader.Read(); + + Properties = new NiRef[reader.Read()]; + + for (var i = 0; i < Properties.Length; i++) + { + Properties[i] = reader.Read>(File); + } + + CollisionObject = reader.Read>(File); + } + } +} \ No newline at end of file diff --git a/InfectedRose.Nif/Nodes/NiCollisionObject.cs b/InfectedRose.Nif/Nodes/NiCollisionObject.cs new file mode 100644 index 0000000..8321f6a --- /dev/null +++ b/InfectedRose.Nif/Nodes/NiCollisionObject.cs @@ -0,0 +1,20 @@ +using InfectedRose.Core; +using RakDotNet.IO; + +namespace InfectedRose.Nif +{ + public class NiCollisionObject : NiObject + { + public NiRef Target { get; set; } + + public override void Serialize(BitWriter writer) + { + writer.Write(Target); + } + + public override void Deserialize(BitReader reader) + { + Target = reader.Read>(File); + } + } +} \ No newline at end of file diff --git a/InfectedRose.Nif/Nodes/NiGeometry.cs b/InfectedRose.Nif/Nodes/NiGeometry.cs new file mode 100644 index 0000000..bd220ab --- /dev/null +++ b/InfectedRose.Nif/Nodes/NiGeometry.cs @@ -0,0 +1,66 @@ +using InfectedRose.Core; +using RakDotNet.IO; + +namespace InfectedRose.Nif +{ + public class NiGeometry : NiAvObject + { + public NiRef Data { get; set; } + + public NiRef Skin { get; set; } + + public string[] Materials { get; set; } + + public NiRef[] MaterialExtraData { get; set; } + + public int ActiveMaterial { get; set; } + + public bool Dirty { get; set; } + + public override void Deserialize(BitReader reader) + { + base.Deserialize(reader); + + Data = reader.Read>(File); + + Skin = reader.Read>(File); + + Materials = new string[reader.Read()]; + + MaterialExtraData = new NiRef[Materials.Length]; + + for (var i = 0; i < Materials.Length; i++) + { + Materials[i] = reader.ReadNiString(); + + MaterialExtraData[i] = reader.Read>(File); + } + + ActiveMaterial = reader.Read(); + + Dirty = reader.Read() != 0; + } + + public override void Serialize(BitWriter writer) + { + base.Serialize(writer); + + writer.Write(Data); + + writer.Write(Skin); + + writer.Write((uint) Materials.Length); + + for (var i = 0; i < Materials.Length; i++) + { + writer.WriteNiString(Materials[i]); + + writer.Write(MaterialExtraData[i]); + } + + writer.Write(ActiveMaterial); + + writer.Write((byte) (Dirty ? 1 : 0)); + } + } +} \ No newline at end of file diff --git a/InfectedRose.Nif/Nodes/NiLODNode.cs b/InfectedRose.Nif/Nodes/NiLODNode.cs new file mode 100644 index 0000000..3e69e15 --- /dev/null +++ b/InfectedRose.Nif/Nodes/NiLODNode.cs @@ -0,0 +1,24 @@ +using InfectedRose.Core; +using RakDotNet.IO; + +namespace InfectedRose.Nif +{ + public class NiLODNode : NiSwitchNode + { + public NiRef Data { get; set; } + + public override void Deserialize(BitReader reader) + { + base.Deserialize(reader); + + Data = reader.Read>(File); + } + + public override void Serialize(BitWriter writer) + { + base.Serialize(writer); + + writer.Write(Data); + } + } +} \ No newline at end of file diff --git a/InfectedRose.Nif/Nodes/NiNode.cs b/InfectedRose.Nif/Nodes/NiNode.cs new file mode 100644 index 0000000..f1ae9ed --- /dev/null +++ b/InfectedRose.Nif/Nodes/NiNode.cs @@ -0,0 +1,50 @@ +using InfectedRose.Core; +using RakDotNet.IO; + +namespace InfectedRose.Nif +{ + public class NiNode : NiAvObject + { + public NiRef[] Children { get; set; } + + public NiRef[] Effects { get; set; } + + public override void Deserialize(BitReader reader) + { + base.Deserialize(reader); + + Children = new NiRef[reader.Read()]; + + for (var i = 0; i < Children.Length; i++) + { + Children[i] = reader.Read>(File); + } + + Effects = new NiRef[reader.Read()]; + + for (var i = 0; i < Effects.Length; i++) + { + Effects[i] = reader.Read>(File); + } + } + + public override void Serialize(BitWriter writer) + { + base.Serialize(writer); + + writer.Write((uint) Children.Length); + + foreach (var child in Children) + { + writer.Write(child); + } + + writer.Write((uint) Effects.Length); + + foreach (var effect in Effects) + { + writer.Write(effect); + } + } + } +} \ No newline at end of file diff --git a/InfectedRose.Nif/Nodes/NiObjectNet.cs b/InfectedRose.Nif/Nodes/NiObjectNet.cs new file mode 100644 index 0000000..49c1f54 --- /dev/null +++ b/InfectedRose.Nif/Nodes/NiObjectNet.cs @@ -0,0 +1,43 @@ +using InfectedRose.Nif.Controllers; +using InfectedRose.Core; +using RakDotNet.IO; + +namespace InfectedRose.Nif +{ + public class NiObjectNet : NiObject + { + public NiStringRef Name { get; set; } + + public NiRef[] ExtraData { get; set; } + + public NiRef Controller { get; set; } + + public override void Serialize(BitWriter writer) + { + writer.Write(Name); + + writer.Write((uint) ExtraData.Length); + + foreach (var extra in ExtraData) + { + writer.Write(extra); + } + + writer.Write(Controller); + } + + public override void Deserialize(BitReader reader) + { + Name = reader.Read(File); + + ExtraData = new NiRef[reader.Read()]; + + for (var i = 0; i < ExtraData.Length; i++) + { + ExtraData[i] = reader.Read>(File); + } + + Controller = reader.Read>(File); + } + } +} \ No newline at end of file diff --git a/InfectedRose.Nif/Nodes/NiSwitchNode.cs b/InfectedRose.Nif/Nodes/NiSwitchNode.cs new file mode 100644 index 0000000..63969ad --- /dev/null +++ b/InfectedRose.Nif/Nodes/NiSwitchNode.cs @@ -0,0 +1,29 @@ +using RakDotNet.IO; + +namespace InfectedRose.Nif +{ + public class NiSwitchNode : NiNode + { + public ushort SwitchFlags { get; set; } + + public int Index { get; set; } + + public override void Deserialize(BitReader reader) + { + base.Deserialize(reader); + + SwitchFlags = reader.Read(); + + Index = reader.Read(); + } + + public override void Serialize(BitWriter writer) + { + base.Serialize(writer); + + writer.Write(SwitchFlags); + + writer.Write(Index); + } + } +} \ No newline at end of file diff --git a/InfectedRose.Nif/Nodes/NiTriBasedGeom.cs b/InfectedRose.Nif/Nodes/NiTriBasedGeom.cs new file mode 100644 index 0000000..b6fc2f6 --- /dev/null +++ b/InfectedRose.Nif/Nodes/NiTriBasedGeom.cs @@ -0,0 +1,7 @@ +namespace InfectedRose.Nif +{ + public class NiTriBasedGeom : NiGeometry + { + + } +} \ No newline at end of file diff --git a/InfectedRose.Nif/Nodes/NiTriShape.cs b/InfectedRose.Nif/Nodes/NiTriShape.cs new file mode 100644 index 0000000..87b81e9 --- /dev/null +++ b/InfectedRose.Nif/Nodes/NiTriShape.cs @@ -0,0 +1,7 @@ +namespace InfectedRose.Nif +{ + public class NiTriShape : NiTriBasedGeom + { + + } +} \ No newline at end of file diff --git a/InfectedRose.Nif/Nodes/NiTriStrips.cs b/InfectedRose.Nif/Nodes/NiTriStrips.cs new file mode 100644 index 0000000..81dc504 --- /dev/null +++ b/InfectedRose.Nif/Nodes/NiTriStrips.cs @@ -0,0 +1,7 @@ +namespace InfectedRose.Nif +{ + public class NiTriStrips : NiTriBasedGeom + { + + } +} \ No newline at end of file diff --git a/InfectedRose.Nif/Properties/NiMaterialProperty.cs b/InfectedRose.Nif/Properties/NiMaterialProperty.cs new file mode 100644 index 0000000..a24ba3b --- /dev/null +++ b/InfectedRose.Nif/Properties/NiMaterialProperty.cs @@ -0,0 +1,59 @@ +using RakDotNet.IO; + +namespace InfectedRose.Nif +{ + public class NiMaterialProperty : NiProperty + { + public Color3 AmbientColor { get; set; } + + public Color3 DiffuseColor { get; set; } + + public Color3 SpecularColor { get; set; } + + public Color3 EmissiveColor { get; set; } + + public float Glossiness { get; set; } + + public float Alpha { get; set; } + + public float EmitMultiplier { get; set; } + + public override void Deserialize(BitReader reader) + { + base.Deserialize(reader); + + AmbientColor = reader.Read(); + + DiffuseColor = reader.Read(); + + SpecularColor = reader.Read(); + + EmissiveColor = reader.Read(); + + Glossiness = reader.Read(); + + Alpha = reader.Read(); + + EmitMultiplier = reader.Read(); + } + + public override void Serialize(BitWriter writer) + { + base.Serialize(writer); + + writer.Write(AmbientColor); + + writer.Write(DiffuseColor); + + writer.Write(SpecularColor); + + writer.Write(EmissiveColor); + + writer.Write(Glossiness); + + writer.Write(Alpha); + + writer.Write(EmitMultiplier); + } + } +} \ No newline at end of file diff --git a/InfectedRose.Nif/Properties/NiProperty.cs b/InfectedRose.Nif/Properties/NiProperty.cs new file mode 100644 index 0000000..79c785c --- /dev/null +++ b/InfectedRose.Nif/Properties/NiProperty.cs @@ -0,0 +1,7 @@ +namespace InfectedRose.Nif +{ + public class NiProperty : NiObjectNet + { + + } +} \ No newline at end of file diff --git a/InfectedRose.Nif/Properties/NiShadeProperty.cs b/InfectedRose.Nif/Properties/NiShadeProperty.cs new file mode 100644 index 0000000..2150f73 --- /dev/null +++ b/InfectedRose.Nif/Properties/NiShadeProperty.cs @@ -0,0 +1,23 @@ +using RakDotNet.IO; + +namespace InfectedRose.Nif +{ + public class NiShadeProperty : NiProperty + { + public ushort Flags { get; set; } + + public override void Deserialize(BitReader reader) + { + base.Deserialize(reader); + + Flags = reader.Read(); + } + + public override void Serialize(BitWriter writer) + { + base.Serialize(writer); + + writer.Write(Flags); + } + } +} \ No newline at end of file diff --git a/InfectedRose.Nif/Properties/NiSpecularProperty.cs b/InfectedRose.Nif/Properties/NiSpecularProperty.cs new file mode 100644 index 0000000..c773e41 --- /dev/null +++ b/InfectedRose.Nif/Properties/NiSpecularProperty.cs @@ -0,0 +1,23 @@ +using RakDotNet.IO; + +namespace InfectedRose.Nif +{ + public class NiSpecularProperty : NiProperty + { + public ushort Flags { get; set; } + + public override void Serialize(BitWriter writer) + { + base.Serialize(writer); + + writer.Write(Flags); + } + + public override void Deserialize(BitReader reader) + { + base.Deserialize(reader); + + Flags = reader.Read(); + } + } +} \ No newline at end of file diff --git a/InfectedRose.Nif/Properties/NiVertexColorProperty.cs b/InfectedRose.Nif/Properties/NiVertexColorProperty.cs new file mode 100644 index 0000000..1e2c86a --- /dev/null +++ b/InfectedRose.Nif/Properties/NiVertexColorProperty.cs @@ -0,0 +1,23 @@ +using RakDotNet.IO; + +namespace InfectedRose.Nif +{ + public class NiVertexColorProperty : NiProperty + { + public ushort Flags { get; set; } + + public override void Deserialize(BitReader reader) + { + base.Deserialize(reader); + + Flags = reader.Read(); + } + + public override void Serialize(BitWriter writer) + { + base.Serialize(writer); + + writer.Write(Flags); + } + } +} \ No newline at end of file diff --git a/InfectedRose.Nif/Properties/NiZBufferProperty.cs b/InfectedRose.Nif/Properties/NiZBufferProperty.cs new file mode 100644 index 0000000..865bdac --- /dev/null +++ b/InfectedRose.Nif/Properties/NiZBufferProperty.cs @@ -0,0 +1,23 @@ +using RakDotNet.IO; + +namespace InfectedRose.Nif +{ + public class NiZBufferProperty : NiProperty + { + public ushort Flags { get; set; } + + public override void Deserialize(BitReader reader) + { + base.Deserialize(reader); + + Flags = reader.Read(); + } + + public override void Serialize(BitWriter writer) + { + base.Serialize(writer); + + writer.Write(Flags); + } + } +} \ No newline at end of file diff --git a/InfectedRose.Nif/Structs/Color3.cs b/InfectedRose.Nif/Structs/Color3.cs new file mode 100644 index 0000000..e794e8a --- /dev/null +++ b/InfectedRose.Nif/Structs/Color3.cs @@ -0,0 +1,11 @@ +namespace InfectedRose.Nif +{ + public struct Color3 + { + public float R { get; set; } + + public float G { get; set; } + + public float B { get; set; } + } +} \ No newline at end of file diff --git a/InfectedRose.Nif/Structs/Color4.cs b/InfectedRose.Nif/Structs/Color4.cs new file mode 100644 index 0000000..d849349 --- /dev/null +++ b/InfectedRose.Nif/Structs/Color4.cs @@ -0,0 +1,13 @@ +namespace InfectedRose.Nif +{ + public struct Color4 + { + public float R { get; set; } + + public float G { get; set; } + + public float B { get; set; } + + public float A { get; set; } + } +} \ No newline at end of file diff --git a/InfectedRose.Nif/Structs/LODRange.cs b/InfectedRose.Nif/Structs/LODRange.cs new file mode 100644 index 0000000..c9f0c85 --- /dev/null +++ b/InfectedRose.Nif/Structs/LODRange.cs @@ -0,0 +1,9 @@ +namespace InfectedRose.Nif +{ + public struct LODRange + { + public float Near { get; set; } + + public float Far { get; set; } + } +} \ No newline at end of file diff --git a/InfectedRose.Nif/Structs/MatchGroup.cs b/InfectedRose.Nif/Structs/MatchGroup.cs new file mode 100644 index 0000000..59509d0 --- /dev/null +++ b/InfectedRose.Nif/Structs/MatchGroup.cs @@ -0,0 +1,9 @@ +namespace InfectedRose.Nif +{ + public struct MatchGroup + { + public ushort Vertices { get; set; } + + public ushort Indices { get; set; } + } +} \ No newline at end of file diff --git a/InfectedRose.Nif/Structs/Matrix3X3.cs b/InfectedRose.Nif/Structs/Matrix3X3.cs new file mode 100644 index 0000000..e80d33d --- /dev/null +++ b/InfectedRose.Nif/Structs/Matrix3X3.cs @@ -0,0 +1,23 @@ +namespace InfectedRose.Nif +{ + public struct Matrix3X3 + { + public float M11 { get; set; } + + public float M21 { get; set; } + + public float M31 { get; set; } + + public float M12 { get; set; } + + public float M22 { get; set; } + + public float M32 { get; set; } + + public float M13 { get; set; } + + public float M23 { get; set; } + + public float M33 { get; set; } + } +} \ No newline at end of file diff --git a/InfectedRose.Nif/Structs/Triangle.cs b/InfectedRose.Nif/Structs/Triangle.cs new file mode 100644 index 0000000..75a98f2 --- /dev/null +++ b/InfectedRose.Nif/Structs/Triangle.cs @@ -0,0 +1,11 @@ +namespace InfectedRose.Nif +{ + public struct Triangle + { + public ushort V1; + + public ushort V2; + + public ushort V3; + } +} \ No newline at end of file