diff --git a/dq8chr2glb/AppendAnimations.cs b/dq8chr2glb/AppendAnimations.cs new file mode 100644 index 0000000..f256d28 --- /dev/null +++ b/dq8chr2glb/AppendAnimations.cs @@ -0,0 +1,62 @@ +using System.Collections.Generic; +using System.IO; +using System.Text; +using dq8chr2glb.Converter; +using dq8chr2glb.Converter.GLTF; +using dq8chr2glb.Core.InfoCfg; +using dq8chr2glb.Core.MOTFormat; +using dq8chr2glb.Logger; +using SharpGLTF.Schema2; + +namespace dq8chr2glb; + +public class AppendAnimations +{ + public void Append(string glbPath, string extractedPath) + { + Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); + + var modelName = Path.GetFileNameWithoutExtension(glbPath); + var glbDir = Path.GetDirectoryName(glbPath); + var model = ModelRoot.Load(glbPath); + var mdsConverter = new MDSConverter(modelName, model); + + var ctx = new Context(); + Context.Current.MdsConverters = new List(); + Context.Current.MdsConverters.Add(mdsConverter); + + foreach (var dataFile in Directory.GetFiles(extractedPath)) + { + if (dataFile.ToLower().EndsWith(".cfg")) + { + var directory = Path.GetDirectoryName(dataFile); + ReadConfig(dataFile); + var motionFile = Path.Combine(directory, Context.Current.InfoCfg.motion); + ProcessMOTFile(motionFile); + } + } + + mdsConverter.Save(@"C:\Users\Boris\Desktop\yangus"); + } + + private void ReadConfig(string path) + { + Log.Line(path); + var bytes = File.ReadAllBytes(path); + var data = Encoding.GetEncoding("shift_jis").GetString(bytes).TrimEnd('\0'); + var configFile = new ConfigFile(data); + var info = configFile.ReadConfig(); + Context.Current.InfoCfg = info; + } + + private void ProcessMOTFile(string path) + { + Log.Line(path); + var bytes = File.ReadAllBytes(path); + var motImporter = new Importer(); + var animation = motImporter.Import(bytes); + + var converter = Context.Current.MdsConverters[0]; + converter.AddAnimation(animation, Context.Current.InfoCfg); + } +} diff --git a/dq8chr2glb/ChrFile.cs b/dq8chr2glb/ChrFile.cs index b8a12ef..8f646ee 100644 --- a/dq8chr2glb/ChrFile.cs +++ b/dq8chr2glb/ChrFile.cs @@ -16,29 +16,29 @@ namespace dq8chr2glb; public class ChrFile { - public bool extract; - public bool convert; - public bool textFormat; + public bool Extract; + public bool Convert; + public bool TextFormat; public void Process(string inputPath, string outputPath) { Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); var ctx = new Context(); - ctx.inputPath = inputPath; - ctx.modelName = Path.GetFileNameWithoutExtension(ctx.inputPath); - ctx.outputPath = Path.Combine(outputPath, ctx.modelName); + ctx.InputPath = inputPath; + ctx.ModelName = Path.GetFileNameWithoutExtension(ctx.InputPath); + ctx.OutputPath = Path.Combine(outputPath, ctx.ModelName); - var chrData = File.ReadAllBytes(ctx.inputPath); - var container = ChrContainer.FromBytes(chrData); + var chrData = File.ReadAllBytes(ctx.InputPath); + var container = Container.ChrFile.FromBytes(chrData); - EnsurePath(ctx.outputPath); + EnsurePath(ctx.OutputPath); foreach (var file in container) { PrintTask(file); - switch (file.extension) + switch (file.Extension) { case FileExtension.CFG: ProcessConfig(file); @@ -61,39 +61,39 @@ public class ChrFile } } - if (convert) + if (Convert) { - foreach (var converter in Context.current.mdsConverters) + foreach (var converter in Context.Current.MdsConverters) { - converter.Save(ctx.outputPath, textFormat); + converter.Save(ctx.OutputPath, TextFormat); } } - foreach (var err in Context.current.errors) + foreach (var err in Context.Current.Errors) { - Log.Line($"{err.name}, {err.text}", LogLevel.Error); - if (err.exception != null) + Log.Line($"{err.Name}, {err.Text}", LogLevel.Error); + if (err.Exception != null) { - Log.Error(err.exception); + Log.Error(err.Exception); } } - foreach (var err in Context.current.messages) + foreach (var err in Context.Current.Messages) { - Log.Line($"{err.name}, {err.text}"); + Log.Line($"{err.Name}, {err.Text}"); } } private void PrintTask(IncludedFile file) { - var spaces = 30 - file.name.Length; + var spaces = 30 - file.Name.Length; if (spaces <= 0) { spaces = 1; } var spacer = new string('.', spaces); - Log.Line($" Process: {file.name + spacer} {file.data.Length} bytes"); + Log.Line($" Process: {file.Name + spacer} {file.Data.Length} bytes"); } private void EnsurePath(string path) @@ -106,65 +106,65 @@ public class ChrFile private void ProcessMOTFile(IncludedFile file) { - if (extract) + if (Extract) { ProcessRawFile(file); } - if (convert) + if (Convert) { - foreach (var converter in Context.current.mdsConverters) + foreach (var converter in Context.Current.MdsConverters) { var motImporter = new Importer(); - var animation = motImporter.Import(file.data); - converter.CreateAnimation(animation, Context.current.infoCfg); + var animation = motImporter.Import(file.Data); + converter.AddAnimation(animation, Context.Current.InfoCfg); } } } private void ProcessMDSFile(IncludedFile file) { - if (extract) + if (Extract) { ProcessRawFile(file); } - var mdsScene = Reader.Read(file.data, file.name); + var mdsScene = Reader.Read(file.Data, file.Name); if (mdsScene == null) { - Context.current.errors.Add(new Error(file.name, "mdsScene is empty!")); + Context.Current.Errors.Add(new Error(file.Name, "mdsScene is empty!")); return; } - if (convert) + if (Convert) { - var converter = new MDSConverter(file.name); - var rootName = Path.GetFileNameWithoutExtension(file.name); - converter.Convert(mdsScene, Context.current.textures, rootName); - Context.current.mdsConverters.Add(converter); + var converter = new MDSConverter(file.Name); + var rootName = Path.GetFileNameWithoutExtension(file.Name); + converter.Convert(mdsScene, Context.Current.Textures, rootName); + Context.Current.MdsConverters.Add(converter); } } private void ProcessConfig(IncludedFile file) { - if (extract) + if (Extract) { - var isSecond = Context.current.infoCfg != null; + var isSecond = Context.Current.InfoCfg != null; if (isSecond) { - file.name = file.name.Replace(".cfg", "_2.cfg"); + file.Name = file.Name.Replace(".cfg", "_2.cfg"); } ProcessTextFile(file); } - var data = Encoding.GetEncoding("shift_jis").GetString(file.data).TrimEnd('\0'); + var data = Encoding.GetEncoding("shift_jis").GetString(file.Data).TrimEnd('\0'); var configFile = new ConfigFile(data); var info = configFile.ReadConfig(); - if (Context.current.infoCfg == null) + if (Context.Current.InfoCfg == null) { - Context.current.infoCfg = info; + Context.Current.InfoCfg = info; } } @@ -172,18 +172,18 @@ public class ChrFile { try { - var root = Path.GetDirectoryName(file.name); - var fileName = Path.GetFileName(file.name); - var outputPath = Path.Combine(Context.current.outputPath, root); - var text = Encoding.GetEncoding("shift_jis").GetString(file.data).TrimEnd('\0'); + var root = Path.GetDirectoryName(file.Name); + var fileName = Path.GetFileName(file.Name); + var outputPath = Path.Combine(Context.Current.OutputPath, root); + var text = Encoding.GetEncoding("shift_jis").GetString(file.Data).TrimEnd('\0'); if (string.IsNullOrEmpty(text)) { - Context.current.errors.Add(new Error(file.name, "Text data is empty!")); + Context.Current.Errors.Add(new Error(file.Name, "Text data is empty!")); return; } - if (extract) + if (Extract) { EnsurePath(outputPath); File.WriteAllText(Path.Combine(outputPath, fileName), text); @@ -191,7 +191,7 @@ public class ChrFile } catch (Exception e) { - Context.current.errors.Add(new Error(file.name, "Error while process text file", e)); + Context.Current.Errors.Add(new Error(file.Name, "Error while process text file", e)); } } @@ -199,35 +199,35 @@ public class ChrFile { try { - var root = Path.GetDirectoryName(file.name); - var fileName = Path.GetFileName(file.name); - var outputPath = Path.Combine(Context.current.outputPath, root); + var root = Path.GetDirectoryName(file.Name); + var fileName = Path.GetFileName(file.Name); + var outputPath = Path.Combine(Context.Current.OutputPath, root); - if (extract) + if (Extract) { EnsurePath(outputPath); - File.WriteAllBytes(Path.Combine(outputPath, fileName), file.data); + File.WriteAllBytes(Path.Combine(outputPath, fileName), file.Data); } } catch (Exception e) { - Context.current.errors.Add(new Error(file.name, $"File extraction failed", e)); + Context.Current.Errors.Add(new Error(file.Name, $"File extraction failed", e)); } } private void ProcessTextures(IncludedFile file) { - var root = Path.GetDirectoryName(file.name); - var fileName = Path.GetFileNameWithoutExtension(file.name); - var outputPath = Path.Combine(Context.current.outputPath, root); + var root = Path.GetDirectoryName(file.Name); + var fileName = Path.GetFileNameWithoutExtension(file.Name); + var outputPath = Path.Combine(Context.Current.OutputPath, root); var image = TM2Format.TM2Format.GetImage(file, fileName); - if (extract) + if (Extract && image != null && image.Data != null) { EnsurePath(outputPath); - image.data.SaveAsPng(Path.Combine(outputPath, fileName + ".png")); + image.Data.SaveAsPng(Path.Combine(outputPath, fileName + ".png")); } - Context.current.textures.Add(image); + Context.Current.Textures.Add(image); } } diff --git a/dq8chr2glb/Container/ChrContainer.cs b/dq8chr2glb/Container/ChrFile.cs similarity index 88% rename from dq8chr2glb/Container/ChrContainer.cs rename to dq8chr2glb/Container/ChrFile.cs index 1b087f6..7c11796 100644 --- a/dq8chr2glb/Container/ChrContainer.cs +++ b/dq8chr2glb/Container/ChrFile.cs @@ -6,7 +6,7 @@ using System.Text; namespace dq8chr2glb.Container; -public class ChrContainer +public class ChrFile { public static List FromBytes(byte[] chrFile) { @@ -52,15 +52,15 @@ public class ChrContainer else { var file = new IncludedFile(); - file.name = name; - file.data = data; + file.Name = name; + file.Data = data; subContainers.Add(file); } foreach (var file in subContainers) { - var extension = file.name.ToLower().Split(".")[^1]; - file.extension = extension switch + var extension = file.Name.ToLower().Split(".")[^1]; + file.Extension = extension switch { "mds" => FileExtension.MDS, "mot" => FileExtension.MOT, @@ -70,9 +70,9 @@ public class ChrContainer _ => FileExtension.TEXT }; - if (file.name == "info.cfg") + if (file.Name == "info.cfg") { - file.extension = FileExtension.CFG; + file.Extension = FileExtension.CFG; } } @@ -109,13 +109,13 @@ public class ChrContainer name = Path.Combine(rootFolderName, name); - file.extension = isTexture ? FileExtension.TM2 : FileExtension.TEXT; - file.name = name + (isTexture ? ".tm2" : ".cfg"); + file.Extension = isTexture ? FileExtension.TM2 : FileExtension.TEXT; + file.Name = name + (isTexture ? ".tm2" : ".cfg"); var fileData = new byte[imgFile.FileSize]; Array.Copy(imgData, imgFile.DataOffset, fileData, 0, imgFile.FileSize); - file.data = fileData; + file.Data = fileData; files.Add(file); diff --git a/dq8chr2glb/Container/IncludedFile.cs b/dq8chr2glb/Container/IncludedFile.cs index 062dc50..8884cee 100644 --- a/dq8chr2glb/Container/IncludedFile.cs +++ b/dq8chr2glb/Container/IncludedFile.cs @@ -4,7 +4,7 @@ namespace dq8chr2glb.Container; public class IncludedFile { - public string name; - public FileExtension extension; - public byte[] data = Array.Empty(); + public string Name; + public FileExtension Extension; + public byte[] Data = Array.Empty(); } diff --git a/dq8chr2glb/Container/Utils.cs b/dq8chr2glb/Container/Utils.cs index 5637e33..cc46086 100644 --- a/dq8chr2glb/Container/Utils.cs +++ b/dq8chr2glb/Container/Utils.cs @@ -14,7 +14,7 @@ public static class Utils foreach (var file in files) { - switch (file.extension) + switch (file.Extension) { case FileExtension.TEXT: configs.Add(file); diff --git a/dq8chr2glb/Converter/Context.cs b/dq8chr2glb/Converter/Context.cs index 198d2a9..39f58e0 100644 --- a/dq8chr2glb/Converter/Context.cs +++ b/dq8chr2glb/Converter/Context.cs @@ -7,45 +7,45 @@ namespace dq8chr2glb.Converter; public class Message { - public readonly string name; - public readonly string text; + public readonly string Name; + public readonly string Text; public Message(string name, string text) { - this.name = name; - this.text = text; + Name = name; + Text = text; } } public class Error { - public readonly string name; - public readonly string text; - public readonly Exception? exception; + public readonly string Name; + public readonly string Text; + public readonly Exception? Exception; public Error(string name, string text, Exception? exception = null) { - this.name = name; - this.text = text; - this.exception = exception; + Name = name; + Text = text; + Exception = exception; } } public class Context { - public static Context current; + public static Context Current; - public string modelName; - public string inputPath; - public string outputPath; - public ModelConfig infoCfg; - public List textures = new(); - public List mdsConverters = new(); - public List errors = new(); - public List messages = new(); + public string ModelName; + public string InputPath; + public string OutputPath; + public ModelConfig InfoCfg; + public List Textures = new(); + public List MdsConverters = new(); + public List Errors = new(); + public List Messages = new(); public Context() { - current = this; + Current = this; } } diff --git a/dq8chr2glb/Converter/GLTF/MDSConverter.cs b/dq8chr2glb/Converter/GLTF/MDSConverter.cs index 15f41af..f4746f2 100644 --- a/dq8chr2glb/Converter/GLTF/MDSConverter.cs +++ b/dq8chr2glb/Converter/GLTF/MDSConverter.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Numerics; +using System.Text.Json.Nodes; using dq8chr2glb.Core.InfoCfg; using dq8chr2glb.Core.MDSFormat; using dq8chr2glb.Core.MOTFormat; @@ -33,56 +34,96 @@ public class MDSConverter _gltfModel = ModelRoot.CreateModel(); } + public MDSConverter(string name, ModelRoot model) + { + _name = name; + _gltfModel = model; + + foreach (var scene in _gltfModel.LogicalScenes) + { + foreach (var node in scene.VisualChildren) + { + ProcessIndicesRecursive(node); + } + } + + + foreach (var item in _nodeMap) + { + Log.Line(item.Value.Name); + } + } + + private void ProcessIndicesRecursive(Node? node) + { + if (node == null) + { + return; + } + + _nodeMap.Add(node.Extras["mds_index"]!.GetValue(), node); + foreach (var child in node.VisualChildren) + { + ProcessIndicesRecursive(child); + } + } + public void Convert(MDSScene scene, List images, string name) { var gltfScene = _gltfModel.UseScene("DefaultScene"); var nodesWithParents = new HashSet(); - if (scene.nodes == null || scene.nodes.Length == 0) + if (scene.Nodes == null || scene.Nodes.Length == 0) { Log.Line($"There is nothing to convert in {name}", LogLevel.Info); return; } - foreach (var node in scene.nodes) + foreach (var node in scene.Nodes) { - if (node.parentIndex >= 0) + if (node.ParentIndex >= 0) { - nodesWithParents.Add(node.index); + nodesWithParents.Add(node.Index); } } - foreach (var node in scene.nodes) + foreach (var node in scene.Nodes) { - if (node.parentIndex < 0) + if (node.ParentIndex < 0) { - var gltfNode = gltfScene.CreateNode(node.name); - _nodeMap[node.index] = gltfNode; + var gltfNode = gltfScene.CreateNode(node.Name); + gltfNode.Extras = new JsonObject(); + gltfNode.Extras["mds_index"] = JsonValue.Create(node.Index); + + _nodeMap[node.Index] = gltfNode; if (node is MDSBone) { _boneNodes.Add(gltfNode); } - gltfNode.WithLocalTransform(ToNumericsMatrix4x4(node.transform)); + gltfNode.WithLocalTransform(ToNumericsMatrix4x4(node.Transform)); } } - foreach (var node in scene.nodes) + foreach (var node in scene.Nodes) { - if (node.parentIndex >= 0 && _nodeMap.ContainsKey(node.parentIndex)) + if (node.ParentIndex >= 0 && _nodeMap.ContainsKey(node.ParentIndex)) { - var parent = _nodeMap[node.parentIndex]; - var gltfNode = parent.CreateNode(node.name); - _nodeMap[node.index] = gltfNode; + var parent = _nodeMap[node.ParentIndex]; + var gltfNode = parent.CreateNode(node.Name); + gltfNode.Extras = new JsonObject(); + gltfNode.Extras["mds_index"] = JsonValue.Create(node.Index); + + _nodeMap[node.Index] = gltfNode; if (node is MDSBone) { _boneNodes.Add(gltfNode); } - gltfNode.WithLocalTransform(ToNumericsMatrix4x4(node.transform)); + gltfNode.WithLocalTransform(ToNumericsMatrix4x4(node.Transform)); } } @@ -90,22 +131,22 @@ public class MDSConverter for (int i = 0; i < _boneNodes.Count; i++) { var boneNode = _boneNodes[i]; - var mdsNode = Array.Find(scene.nodes, n => n.name == boneNode.Name); + var mdsNode = Array.Find(scene.Nodes, n => n.Name == boneNode.Name); if (mdsNode != null) { - nodesMapping[mdsNode.index] = i; + nodesMapping[mdsNode.Index] = i; } } - CreateMaterials(scene.materials, images); + CreateMaterials(scene.Materials, images); - var meshes = scene.nodes.Where(n => n is MDSMesh).Cast().ToArray(); + var meshes = scene.Nodes.Where(n => n is MDSMesh).Cast().ToArray(); foreach (var mdsMesh in meshes) { - if (mdsMesh?.vertices == null || mdsMesh.triangles == null) continue; + if (mdsMesh?.Vertices == null || mdsMesh.Triangles == null) continue; - var mesh = CreateGltfMesh(mdsMesh, scene.materials, nodesMapping); - if (_nodeMap.TryGetValue(mdsMesh.index, out var meshNode)) + var mesh = CreateGltfMesh(mdsMesh, scene.Materials, nodesMapping); + if (_nodeMap.TryGetValue(mdsMesh.Index, out var meshNode)) { meshNode.WithMesh(mesh); } @@ -113,11 +154,11 @@ public class MDSConverter if (_boneNodes.Count > 0) { - SetupSkeleton(scene.nodes, name); + SetupSkeleton(scene.Nodes, name); } } - public void CreateAnimation(List motionCurves, ModelConfig config) + public void AddAnimation(List motionCurves, ModelConfig config) { foreach (var clip in config.clips) { @@ -125,29 +166,29 @@ public class MDSConverter var translationCurves = new List<(Node node, Dictionary items)>(); foreach (var curve in motionCurves) { - if (_nodeMap.TryGetValue(curve.boneIndex, out var node)) + if (_nodeMap.TryGetValue(curve.BoneIndex, out var node)) { var rotationKeyframes = new Dictionary(); var translationKeyframes = new Dictionary(); - for (var i = clip.startFrame; i < clip.endFrame; i++) + for (var i = clip.StartFrame; i < clip.EndFrame; i++) { - if (i >= curve.keyframes.Count || curve.keyframes[i] == null) + if (i >= curve.Keyframes.Count || curve.Keyframes[i] == null) { continue; } - var keyframe = curve.keyframes[i]; + var keyframe = curve.Keyframes[i]; - if (curve.curveType == KeyframeType.Quaternion) + if (curve.CurveType == KeyframeType.Quaternion) { - var time = keyframe.frame / FRAMERATE / clip.speed; - rotationKeyframes[time] = keyframe.rotation; + var time = keyframe.Frame / FRAMERATE / clip.Speed; + rotationKeyframes[time] = keyframe.Rotation; } - else if (curve.curveType == KeyframeType.Translation) + else if (curve.CurveType == KeyframeType.Translation) { - var time = keyframe.frame / FRAMERATE / clip.speed; - translationKeyframes[time] = keyframe.translation; + var time = keyframe.Frame / FRAMERATE / clip.Speed; + translationKeyframes[time] = keyframe.Translation; } } @@ -165,7 +206,7 @@ public class MDSConverter if (rotationCurves.Count > 0 || translationCurves.Count > 0) { - var animation = _gltfModel.CreateAnimation(clip.name); + var animation = _gltfModel.CreateAnimation(clip.Name); foreach (var (node, items) in rotationCurves) { @@ -198,12 +239,12 @@ public class MDSConverter byte[] imageBytes; using (var ms = new MemoryStream()) { - tex.data.SaveAsPng(ms); + tex.Data.SaveAsPng(ms); imageBytes = ms.ToArray(); } - var imageBuilder = ImageBuilder.From(new MemoryImage(imageBytes), tex.name); - _textureBuilders[tex.name] = imageBuilder; + var imageBuilder = ImageBuilder.From(new MemoryImage(imageBytes), tex.Name); + _textureBuilders[tex.Name] = imageBuilder; } var defaultMat = new MaterialBuilder(); @@ -212,15 +253,15 @@ public class MDSConverter foreach (var mat in materials) { var materialBuilder = new MaterialBuilder(); - materialBuilder.Name = mat.name; + materialBuilder.Name = mat.Name; - if (!string.IsNullOrEmpty(mat.textureName) && _textureBuilders.ContainsKey(mat.textureName)) + if (!string.IsNullOrEmpty(mat.TextureName) && _textureBuilders.ContainsKey(mat.TextureName)) { - var textureImage = _textureBuilders[mat.textureName]; + var textureImage = _textureBuilders[mat.TextureName]; materialBuilder.WithBaseColor(textureImage); } - _materialCache[mat.name] = materialBuilder; + _materialCache[mat.Name] = materialBuilder; } } @@ -234,8 +275,8 @@ public class MDSConverter Node rootBone = null; foreach (var boneNode in _boneNodes) { - var mdsNode = Array.Find(nodes, n => n.name == boneNode.Name); - if (mdsNode is MDSBone bone && bone.parentIndex < 0) + var mdsNode = Array.Find(nodes, n => n.Name == boneNode.Name); + if (mdsNode is MDSBone bone && bone.ParentIndex < 0) { rootBone = boneNode; break; @@ -255,12 +296,12 @@ public class MDSConverter for (var i = 0; i < _boneNodes.Count; i++) { var boneNode = _boneNodes[i]; - var mdsNode = Array.Find(nodes, n => n.name == boneNode.Name); + var mdsNode = Array.Find(nodes, n => n.Name == boneNode.Name); Matrix4x4 bindMatrix; if (mdsNode is MDSBone b) { - var bindposeMatrix = ToNumericsMatrix4x4(b.bindpose); + var bindposeMatrix = ToNumericsMatrix4x4(b.Bindpose); if (Matrix4x4.Invert(bindposeMatrix, out var bindposeInverse)) { bindMatrix = Matrix4x4.Multiply(bindposeInverse, Matrix4x4.Identity); @@ -299,7 +340,7 @@ public class MDSConverter } catch (Exception e) { - Context.current.errors.Add(new Error(name, "Can't set Skin", e)); + Context.Current.Errors.Add(new Error(name, "Can't set Skin", e)); } } } @@ -317,16 +358,18 @@ public class MDSConverter private Matrix4x4 ToNumericsMatrix4x4(MDSMatrix m) { return new Matrix4x4( - m.m00, m.m01, m.m02, m.m03, - m.m10, m.m11, m.m12, m.m13, - m.m20, m.m21, m.m22, m.m23, - m.m30, m.m31, m.m32, m.m33 + m.M00, m.M01, m.M02, m.M03, + m.M10, m.M11, m.M12, m.M13, + m.M20, m.M21, m.M22, m.M23, + m.M30, m.M31, m.M32, m.M33 ); } - public void Save(string filePath, bool textFormat = true) + public void Save(string filePath, bool textFormat = false) { - var path = Path.Combine(filePath, _name + (textFormat ? ".gltf" : ".glb")); + var name = Path.GetFileNameWithoutExtension(_name); + var path = Path.Combine(filePath, name + (textFormat ? ".gltf" : ".glb")); + Log.Line(path); try { diff --git a/dq8chr2glb/Converter/GLTF/UniversalMeshBuilder.cs b/dq8chr2glb/Converter/GLTF/UniversalMeshBuilder.cs index f54c444..a1ef2f4 100644 --- a/dq8chr2glb/Converter/GLTF/UniversalMeshBuilder.cs +++ b/dq8chr2glb/Converter/GLTF/UniversalMeshBuilder.cs @@ -15,8 +15,8 @@ namespace dq8chr2glb.Converter.GLTF public static Mesh CreateMesh(ModelRoot _root, MDSMesh mdsMesh, MDSMaterial[] materials, Dictionary materialCache, Dictionary nodesMap) { - var hasUvs = (mdsMesh.features & MeshFeatures.UVs) != 0; - var hasSkinning = (mdsMesh.features & MeshFeatures.Weights) != 0; + var hasUvs = (mdsMesh.Features & MeshFeatures.UVs) != 0; + var hasSkinning = (mdsMesh.Features & MeshFeatures.Weights) != 0; if (hasSkinning) { @@ -48,10 +48,10 @@ namespace dq8chr2glb.Converter.GLTF private static (bool hasUvs, bool hasSkinning) AnalyzeMeshAttributes(MDSMesh mdsMesh) { - var hasUvs = mdsMesh.uv != null && mdsMesh.uv.Length > 0 && - Array.Exists(mdsMesh.uv, uv => uv != null && uv.Length >= 2); - var hasSkinning = mdsMesh.weights != null && mdsMesh.bones != null && - mdsMesh.bones.Length > 0; + var hasUvs = mdsMesh.Uv != null && mdsMesh.Uv.Length > 0 && + Array.Exists(mdsMesh.Uv, uv => uv != null && uv.Length >= 2); + var hasSkinning = mdsMesh.Weights != null && mdsMesh.Bones != null && + mdsMesh.Bones.Length > 0; return (hasUvs, hasSkinning); } @@ -66,37 +66,37 @@ namespace dq8chr2glb.Converter.GLTF where TvM : struct, IVertexMaterial where TvS : struct, IVertexSkinning { - var meshBuilder = new MeshBuilder(mdsMesh.name); + var meshBuilder = new MeshBuilder(mdsMesh.Name); var positions = new List(); var normals = new List(); var texCoords = new List(); var skinningData = new List<(int, float)[]>(); - var hasUvs = (mdsMesh.features & MeshFeatures.UVs) != 0; - var hasSkinning = (mdsMesh.features & MeshFeatures.Weights) != 0; + var hasUvs = (mdsMesh.Features & MeshFeatures.UVs) != 0; + var hasSkinning = (mdsMesh.Features & MeshFeatures.Weights) != 0; - for (var i = 0; i < mdsMesh.vertices.Length; i++) + for (var i = 0; i < mdsMesh.Vertices.Length; i++) { positions.Add(new Vector3( - mdsMesh.vertices[i][0], - mdsMesh.vertices[i][1], - mdsMesh.vertices[i][2])); + mdsMesh.Vertices[i][0], + mdsMesh.Vertices[i][1], + mdsMesh.Vertices[i][2])); normals.Add(Vector3.Zero); - if (hasUvs && i < mdsMesh.uv.Length && mdsMesh.uv[i] != null && mdsMesh.uv[i].Length >= 2) + if (hasUvs && i < mdsMesh.Uv.Length && mdsMesh.Uv[i] != null && mdsMesh.Uv[i].Length >= 2) { - texCoords.Add(new Vector2(mdsMesh.uv[i][0], mdsMesh.uv[i][1])); + texCoords.Add(new Vector2(mdsMesh.Uv[i][0], mdsMesh.Uv[i][1])); } else { texCoords.Add(Vector2.Zero); } - if (hasSkinning && i < mdsMesh.bones.Length) + if (hasSkinning && i < mdsMesh.Bones.Length) { - var boneIndices = mdsMesh.bones[i]; - var boneWeights = mdsMesh.weights[i]; + var boneIndices = mdsMesh.Bones[i]; + var boneWeights = mdsMesh.Weights[i]; var bindings = new (int JointIndex, float Weight)[Math.Min(4, boneIndices.Length)]; @@ -135,14 +135,14 @@ namespace dq8chr2glb.Converter.GLTF } } - MeshUtils.ComputeNormals(positions, mdsMesh.triangles, normals); + MeshUtils.ComputeNormals(positions, mdsMesh.Triangles, normals); - foreach (var submesh in mdsMesh.submeshes) + foreach (var submesh in mdsMesh.Submeshes) { var materialBuilder = materialCache.TryGetValue( - submesh.materialIndex >= 0 && - submesh.materialIndex < materials.Length - ? materials[submesh.materialIndex].name + submesh.MaterialIndex >= 0 && + submesh.MaterialIndex < materials.Length + ? materials[submesh.MaterialIndex].Name : "default", out var mat) ? mat @@ -151,15 +151,15 @@ namespace dq8chr2glb.Converter.GLTF var primitive = meshBuilder.UsePrimitive(materialBuilder); var indices = new List(); - for (var i = submesh.startIndex; i < submesh.startIndex + submesh.indexCount; i += 3) + for (var i = submesh.StartIndex; i < submesh.StartIndex + submesh.IndexCount; i += 3) { - indices.Add(mdsMesh.triangles[i]); - indices.Add(mdsMesh.triangles[i + 1]); - indices.Add(mdsMesh.triangles[i + 2]); + indices.Add(mdsMesh.Triangles[i]); + indices.Add(mdsMesh.Triangles[i + 1]); + indices.Add(mdsMesh.Triangles[i + 2]); } var maxBoneIndex = 0; - foreach (var bones in mdsMesh.bones) + foreach (var bones in mdsMesh.Bones) { foreach (var boneID in bones) { @@ -201,7 +201,7 @@ namespace dq8chr2glb.Converter.GLTF } catch (Exception e) { - Log.Line($"Create Mesh Error: {mdsMesh.name}", LogLevel.Error); + Log.Line($"Create Mesh Error: {mdsMesh.Name}", LogLevel.Error); Log.Error(e); return null; } diff --git a/dq8chr2glb/Core/InfoCfg/Clip.cs b/dq8chr2glb/Core/InfoCfg/Clip.cs index 158c1f4..4155b96 100644 --- a/dq8chr2glb/Core/InfoCfg/Clip.cs +++ b/dq8chr2glb/Core/InfoCfg/Clip.cs @@ -2,8 +2,8 @@ namespace dq8chr2glb.Core.InfoCfg; public class Clip { - public string name; - public int startFrame; - public int endFrame; - public float speed; + public string Name; + public int StartFrame; + public int EndFrame; + public float Speed; } diff --git a/dq8chr2glb/Core/InfoCfg/ConfigFile.cs b/dq8chr2glb/Core/InfoCfg/ConfigFile.cs index 5ad4857..a94adaf 100644 --- a/dq8chr2glb/Core/InfoCfg/ConfigFile.cs +++ b/dq8chr2glb/Core/InfoCfg/ConfigFile.cs @@ -6,43 +6,54 @@ namespace dq8chr2glb.Core.InfoCfg; public class ConfigFile { - public string text; + public string Text; + public ModelConfig Config; public ConfigFile(string text) { - this.text = text; + Text = text; } public ModelConfig ReadConfig() { - var config = new ModelConfig(); - config.model = GetModelFileName(); - config.clips = GetClips(); - return config; + Config = new ModelConfig(); + GetModelFileName(); + GetClips(); + return Config; } - public string GetModelFileName() + public void GetModelFileName() { - var lines = text.Split('\n'); + var lines = Text.Split('\n'); foreach (var line in lines) { if (line.StartsWith("MODEL")) { - var match = Regex.Match(line, @"MODEL\s+""([^""]+)"""); - return match.Groups[1].Value; + var match = Regex.Match(line, "\"([^\"]+)\""); + if (match.Success) + { + Config.model = match.Groups[1].Value; + } + } + + if (line.StartsWith("MOTION")) + { + var match = Regex.Match(line, "\"([^\"]+)\""); + if (match.Success) + { + Config.motion = match.Groups[1].Value; + } } } - - return null; } - public List GetClips() + public void GetClips() { CultureInfo.CurrentCulture = CultureInfo.InvariantCulture; var clips = new List(); - var lines = text.Split('\n'); + var lines = Text.Split('\n'); var insideKeyBlock = false; foreach (var line in lines) @@ -70,13 +81,13 @@ public class ConfigFile clips.Add(new Clip { - name = parts[0][1..^1], - startFrame = int.Parse(parts[1]), - endFrame = int.Parse(parts[2]), - speed = float.Parse(parts[3]) + Name = parts[0][1..^1], + StartFrame = int.Parse(parts[1]), + EndFrame = int.Parse(parts[2]), + Speed = float.Parse(parts[3]) }); } - return clips; + Config.clips = clips; } } \ No newline at end of file diff --git a/dq8chr2glb/Core/InfoCfg/ModelConfig.cs b/dq8chr2glb/Core/InfoCfg/ModelConfig.cs index b59b223..55417c1 100644 --- a/dq8chr2glb/Core/InfoCfg/ModelConfig.cs +++ b/dq8chr2glb/Core/InfoCfg/ModelConfig.cs @@ -6,6 +6,7 @@ public class ModelConfig { public string name; public string model; + public string motion; public string shadow; public List clips; } diff --git a/dq8chr2glb/Core/MDSFormat/Headers.cs b/dq8chr2glb/Core/MDSFormat/Headers.cs index a38b177..a79f87c 100644 --- a/dq8chr2glb/Core/MDSFormat/Headers.cs +++ b/dq8chr2glb/Core/MDSFormat/Headers.cs @@ -6,130 +6,85 @@ namespace dq8chr2glb.Core.MDSFormat; public struct MDSHeader { [FieldOffset(00)] public int MagicCode; - [FieldOffset(04)] public int version; - [FieldOffset(08)] public int headerSize; - [FieldOffset(12)] public int nodesCount; - [FieldOffset(20)] public int nodeSize; - [FieldOffset(24)] public int offsetToNodes; - [FieldOffset(32)] public int meshCount; - [FieldOffset(36)] public int offsetToMDT; - [FieldOffset(44)] public int materialsCount; - [FieldOffset(48)] public int materialSize; - [FieldOffset(52)] public int offsetToMaterials; - [FieldOffset(56)] public int offsetToNames; - [FieldOffset(60)] public int namesBlockSize; + [FieldOffset(04)] public int Version; + [FieldOffset(08)] public int HeaderSize; + [FieldOffset(12)] public int NodesCount; + [FieldOffset(20)] public int NodeSize; + [FieldOffset(24)] public int OffsetToNodes; + [FieldOffset(32)] public int MeshCount; + [FieldOffset(36)] public int OffsetToMDT; + [FieldOffset(44)] public int MaterialsCount; + [FieldOffset(48)] public int MaterialSize; + [FieldOffset(52)] public int OffsetToMaterials; + [FieldOffset(56)] public int OffsetToNames; + [FieldOffset(60)] public int NamesBlockSize; } [StructLayout(LayoutKind.Explicit, Size = 256)] public struct MDTHeader { [FieldOffset(00)] public int MagicCode; - [FieldOffset(08)] public int toVertexCount; - [FieldOffset(12)] public int totalSize; - - [FieldOffset(16)] public int value1; // always 2064? - [FieldOffset(20)] public int value2; // always 4104? - [FieldOffset(24)] public int value3; // always 4112? - - [FieldOffset(32)] public float scaleX; - [FieldOffset(36)] public float scaleY; - - [FieldOffset(40)] public float scaleZ; - - // [FieldOffset(64)] public Float3 someScale; // always 1.079? - [FieldOffset(80)] public float uvScaleX; - [FieldOffset(84)] public float uvScaleY; - - [FieldOffset(96)] public int value4; // always 144? - - [FieldOffset(112)] public int triangleGroupCount; - [FieldOffset(116)] public int vertexAttrSize; - - [FieldOffset(128)] public int value5; // some offset - - [FieldOffset(144)] public int vertsCount; - [FieldOffset(148)] public int bytesToFirstVertex; - [FieldOffset(152)] public int colorsCount; - [FieldOffset(156)] public int bytesToFirstColor; - [FieldOffset(160)] public int uvCount; - [FieldOffset(164)] public int uvOffset; - [FieldOffset(176)] public int bonesPerVertex; - [FieldOffset(180)] public int toWeightsOffset; - [FieldOffset(184)] public int toBoneIndicesOffset; - - [FieldOffset(188)] public int value6; // always 1? - [FieldOffset(192)] public AABB bounds; + [FieldOffset(08)] public int ToVertexCount; + [FieldOffset(12)] public int TotalSize; + [FieldOffset(32)] public float ScaleX; + [FieldOffset(36)] public float ScaleY; + [FieldOffset(40)] public float ScaleZ; + [FieldOffset(80)] public float UvScaleX; + [FieldOffset(84)] public float UvScaleY; + [FieldOffset(112)] public int TriangleGroupCount; + [FieldOffset(116)] public int VertexAttrSize; + [FieldOffset(144)] public int VertsCount; + [FieldOffset(148)] public int BytesToFirstVertex; + [FieldOffset(152)] public int ColorsCount; + [FieldOffset(156)] public int BytesToFirstColor; + [FieldOffset(160)] public int UvCount; + [FieldOffset(164)] public int UvOffset; + [FieldOffset(176)] public int BonesPerVertex; + [FieldOffset(180)] public int ToWeightsOffset; + [FieldOffset(184)] public int ToBoneIndicesOffset; + [FieldOffset(192)] public AABB Bounds; } [StructLayout(LayoutKind.Explicit, Size = 48)] public struct AABB { - [FieldOffset(00)] public float minX; - [FieldOffset(04)] public float minY; - [FieldOffset(08)] public float minZ; - [FieldOffset(12)] public int value1; // corner flag? - [FieldOffset(16)] public float maxX; - [FieldOffset(20)] public float maxY; - [FieldOffset(24)] public float maxZ; - [FieldOffset(28)] public int value2; // corner flag? - [FieldOffset(32)] public float centerX; - [FieldOffset(36)] public float centerY; - [FieldOffset(40)] public float centerZ; - [FieldOffset(44)] public float floatValue1; // ? + [FieldOffset(00)] public float MinX; + [FieldOffset(04)] public float MinY; + [FieldOffset(08)] public float MinZ; + [FieldOffset(16)] public float MaxX; + [FieldOffset(20)] public float MaxY; + [FieldOffset(24)] public float MaxZ; + [FieldOffset(32)] public float CenterX; + [FieldOffset(36)] public float CenterY; + [FieldOffset(40)] public float CenterZ; } [StructLayout(LayoutKind.Explicit, Size = 160)] public struct Node { - [FieldOffset(00)] public int nameOffset; - [FieldOffset(12)] public int meshIndex; - [FieldOffset(16)] public int parentIndex; - [FieldOffset(32)] public MDSMatrix matrix; - [FieldOffset(96)] public MDSMatrix bindpose; + [FieldOffset(00)] public int NameOffset; + [FieldOffset(12)] public int MeshIndex; + [FieldOffset(16)] public int ParentIndex; + [FieldOffset(32)] public MDSMatrix Matrix; + [FieldOffset(96)] public MDSMatrix Bindpose; } [StructLayout(LayoutKind.Explicit, Size = 96)] public struct Material { - [FieldOffset(00)] public float value1; - [FieldOffset(04)] public float value2; - [FieldOffset(08)] public float value3; - [FieldOffset(12)] public float value4; - - [FieldOffset(16)] public float value5; - [FieldOffset(20)] public float value6; - [FieldOffset(24)] public float value7; - [FieldOffset(28)] public float value8; - - [FieldOffset(32)] public float value9; - [FieldOffset(36)] public float value10; - [FieldOffset(40)] public float value11; - [FieldOffset(44)] public float value12; - - [FieldOffset(48)] public int nameOffset; - [FieldOffset(52)] public int textureNameOffset; - - [FieldOffset(64)] public int value13; // 0 для обычных материалов, 1 для материалов без имён - [FieldOffset(68)] public int value14; - [FieldOffset(72)] public int value15; - [FieldOffset(76)] public int value16; - - [FieldOffset(80)] public int value17; - [FieldOffset(84)] public int value18; - [FieldOffset(88)] public int value19; - [FieldOffset(92)] public int value20; + [FieldOffset(48)] public int NameOffset; + [FieldOffset(52)] public int TextureNameOffset; + [FieldOffset(64)] public int NoName; + [FieldOffset(80)] public int MaterialType; } [StructLayout(LayoutKind.Explicit, Size = 32)] public struct TriangleGroupHeader { - [FieldOffset(00)] public short toNext; - [FieldOffset(04)] public short readMode; + [FieldOffset(00)] public short ToNext; + [FieldOffset(04)] public short TriangleReadMode; + [FieldOffset(06)] public short IdsCount; + [FieldOffset(16)] public short HeaderSize; - [FieldOffset(06)] public short idsCount; - - // [FieldOffset(06)]public short dataSize; - [FieldOffset(16)] public short headerSize; - - public TriangleReadMode ReadMode => (TriangleReadMode)readMode; + public TriangleReadMode ReadMode => (TriangleReadMode)TriangleReadMode; } diff --git a/dq8chr2glb/Core/MDSFormat/Reader.cs b/dq8chr2glb/Core/MDSFormat/Reader.cs index 276701c..a9eddd0 100644 --- a/dq8chr2glb/Core/MDSFormat/Reader.cs +++ b/dq8chr2glb/Core/MDSFormat/Reader.cs @@ -8,16 +8,16 @@ namespace dq8chr2glb.Core.MDSFormat; public class Reader { - private const float gScale = 0.00003f; // Global Scale Constant + private const float GLOBAL_SCALE = 0.00003f; // Global Scale Constant public static MDSScene Read(byte[] data, string filename) { var offset = 0; var header = Utils.ReadStruct(data, ref offset, true); - if (header.version != 200) + if (header.Version != 200) { - Log.Line($"Unknown version: {header.version}."); + Log.Line($"Unknown version: {header.Version}."); return null; } @@ -27,32 +27,32 @@ public class Reader ReadNodes(scene, header, data, names); ReadMaterials(scene, header, data, names); - var mdtHeaders = new MDTHeader[header.meshCount]; - for (var meshIndex = 0; meshIndex < header.meshCount; meshIndex++) + var mdtHeaders = new MDTHeader[header.MeshCount]; + for (var meshIndex = 0; meshIndex < header.MeshCount; meshIndex++) { - offset = header.offsetToMDT + mdtHeaders.Sum(h => h.totalSize); + offset = header.OffsetToMDT + mdtHeaders.Sum(h => h.TotalSize); var mdtHeader = Utils.ReadStruct(data, ref offset); mdtHeaders[meshIndex] = mdtHeader; var mesh = Utils.GetMeshByIndex(scene, meshIndex); - var hasVertices = mdtHeader.vertsCount != 0; - var hasColors = mdtHeader.colorsCount != 0; - var hasUVs = mdtHeader.uvCount != 0; - var isSkinned = mdtHeader.bonesPerVertex != 0; + var hasVertices = mdtHeader.VertsCount != 0; + var hasColors = mdtHeader.ColorsCount != 0; + var hasUVs = mdtHeader.UvCount != 0; + var isSkinned = mdtHeader.BonesPerVertex != 0; var features = Utils.GetFeaturesFlags(hasVertices, hasColors, hasUVs, isSkinned); - mesh.features = features; - mesh.bounds = mdtHeader.bounds; + mesh.Features = features; + mesh.Bounds = mdtHeader.Bounds; var scale = new float[3] - { mdtHeader.scaleX * gScale, mdtHeader.scaleY * gScale, mdtHeader.scaleZ * gScale }; - var uvScale = new float[2] { mdtHeader.uvScaleX, mdtHeader.uvScaleY }; + { mdtHeader.ScaleX * GLOBAL_SCALE, mdtHeader.ScaleY * GLOBAL_SCALE, mdtHeader.ScaleZ * GLOBAL_SCALE }; + var uvScale = new float[2] { mdtHeader.UvScaleX, mdtHeader.UvScaleY }; // read vertices array - var vOffset = offset + mdtHeader.toVertexCount + mdtHeader.bytesToFirstVertex; - var vCount = mdtHeader.vertsCount; + var vOffset = offset + mdtHeader.ToVertexCount + mdtHeader.BytesToFirstVertex; + var vCount = mdtHeader.VertsCount; var vertices = Utils.ReadArray(data, vOffset, vCount, 3, s => new[] { @@ -60,11 +60,11 @@ public class Reader }); // read colors array - var colors = new float[mdtHeader.colorsCount][]; + var colors = new float[mdtHeader.ColorsCount][]; if ((features & MeshFeatures.Colors) == MeshFeatures.Colors) { - var cOffset = offset + mdtHeader.toVertexCount + mdtHeader.bytesToFirstColor; - var cCount = mdtHeader.colorsCount; + var cOffset = offset + mdtHeader.ToVertexCount + mdtHeader.BytesToFirstColor; + var cCount = mdtHeader.ColorsCount; var maxByte = (float)byte.MaxValue; colors = Utils.ReadArray(data, cOffset, cCount, 3, s => new[] @@ -74,8 +74,8 @@ public class Reader } // read texcoords array - var tOffset = offset + mdtHeader.toVertexCount + mdtHeader.uvOffset; - var tCount = mdtHeader.uvCount; + var tOffset = offset + mdtHeader.ToVertexCount + mdtHeader.UvOffset; + var tCount = mdtHeader.UvCount; var maxSByte = (float)sbyte.MaxValue; var uvs = Utils.ReadArray(data, tOffset, tCount, 2, s => new[] @@ -84,17 +84,17 @@ public class Reader }); // read weights array - var wOffset = offset + mdtHeader.toVertexCount + mdtHeader.toWeightsOffset; + var wOffset = offset + mdtHeader.ToVertexCount + mdtHeader.ToWeightsOffset; var weights = Utils.ReadArray(data, wOffset, vCount, 4, s => Array.ConvertAll(s, x => (float)x / short.MaxValue)); // read bones per vertex array - var bOffset = offset + mdtHeader.toVertexCount + mdtHeader.toBoneIndicesOffset; + var bOffset = offset + mdtHeader.ToVertexCount + mdtHeader.ToBoneIndicesOffset; var boneIndices = Utils.ReadArray(data, bOffset, vCount, 4, s => Array.ConvertAll(s, x => (int)x)); var submeshes = new List(); - var triangleGroupOffset = offset + mdtHeader.vertexAttrSize; + var triangleGroupOffset = offset + mdtHeader.VertexAttrSize; var lastEndIndex = 0; var verticesList = new List(); @@ -104,16 +104,16 @@ public class Reader var weightsList = new List(); var bonesList = new List(); - for (var submeshIndex = 0; submeshIndex < mdtHeader.triangleGroupCount; submeshIndex++) + for (var submeshIndex = 0; submeshIndex < mdtHeader.TriangleGroupCount; submeshIndex++) { var triangleGroupHeader = Utils.ReadStruct(data, ref triangleGroupOffset); - if (triangleGroupHeader.headerSize == 32 && triangleGroupHeader.toNext == 0) + if (triangleGroupHeader.HeaderSize == 32 && triangleGroupHeader.ToNext == 0) { // This is normal. Often, such blocks complete a sequence. continue; } - if (triangleGroupHeader.headerSize == 32 && triangleGroupHeader.toNext != 0) + if (triangleGroupHeader.HeaderSize == 32 && triangleGroupHeader.ToNext != 0) { // This might be weird. // Log.Line($"Skip 32-bit triangle group header on {triangleGroupOffset}"); @@ -122,7 +122,7 @@ public class Reader var submesh = new SubMesh(); - var triangleIndexOffset = triangleGroupOffset + triangleGroupHeader.headerSize; + var triangleIndexOffset = triangleGroupOffset + triangleGroupHeader.HeaderSize; var triangles = ReadTriangles(triangleGroupHeader, triangleIndexOffset, data); var cornerVerts = GetCornerAttribute(vertices, triangles, triangleIndexOffset, "vertices"); verticesList.AddRange(cornerVerts); @@ -136,9 +136,9 @@ public class Reader bonesList.AddRange(cornerBoneIndices); } - submesh.materialIndex = BitConverter.ToInt32(data, triangleGroupOffset + 32); - submesh.startIndex = lastEndIndex; - submesh.indexCount = triangles.Length; + submesh.MaterialIndex = BitConverter.ToInt32(data, triangleGroupOffset + 32); + submesh.StartIndex = lastEndIndex; + submesh.IndexCount = triangles.Length; lastEndIndex += cornerVerts.Length; submeshes.Add(submesh); @@ -168,16 +168,16 @@ public class Reader } } - triangleGroupOffset += triangleGroupHeader.toNext; + triangleGroupOffset += triangleGroupHeader.ToNext; } - mesh.vertices = verticesList.ToArray(); - mesh.triangles = trianglesList.ToArray(); - mesh.color = colorsList.ToArray(); - mesh.uv = uvList.ToArray(); - mesh.weights = weightsList.ToArray(); - mesh.bones = bonesList.ToArray(); - mesh.submeshes = submeshes.ToArray(); + mesh.Vertices = verticesList.ToArray(); + mesh.Triangles = trianglesList.ToArray(); + mesh.Color = colorsList.ToArray(); + mesh.Uv = uvList.ToArray(); + mesh.Weights = weightsList.ToArray(); + mesh.Bones = bonesList.ToArray(); + mesh.Submeshes = submeshes.ToArray(); } return scene; @@ -185,21 +185,21 @@ public class Reader private static string ReadNames(MDSHeader header, byte[] data) { - var offset = header.offsetToNames; - var decodedString = Encoding.UTF8.GetString(data, offset, header.namesBlockSize); + var offset = header.OffsetToNames; + var decodedString = Encoding.UTF8.GetString(data, offset, header.NamesBlockSize); return decodedString.Replace("\0", " "); } private static void ReadNodes(MDSScene scene, MDSHeader header, byte[] data, string names) { - scene.nodes = new MDSNode[header.nodesCount]; + scene.Nodes = new MDSNode[header.NodesCount]; - var offset = header.offsetToNodes; - for (var i = 0; i < header.nodesCount; i++) + var offset = header.OffsetToNodes; + for (var i = 0; i < header.NodesCount; i++) { var node = Utils.ReadStruct(data, ref offset, true); - var type = node.meshIndex < 0 ? NodeType.Bone : NodeType.Mesh; + var type = node.MeshIndex < 0 ? NodeType.Bone : NodeType.Mesh; MDSNode mdsNode; if (type == NodeType.Bone) @@ -212,42 +212,42 @@ public class Reader mdsNode = new MDSMesh(); } - mdsNode.bindpose = node.bindpose; - mdsNode.name = Utils.GetName(names, node.nameOffset); - mdsNode.transform = node.matrix; - mdsNode.index = i; - mdsNode.parentIndex = node.parentIndex; - mdsNode.type = type; - mdsNode.meshIndex = node.meshIndex; + mdsNode.Bindpose = node.Bindpose; + mdsNode.Name = Utils.GetName(names, node.NameOffset); + mdsNode.Transform = node.Matrix; + mdsNode.Index = i; + mdsNode.ParentIndex = node.ParentIndex; + mdsNode.Type = type; + mdsNode.MeshIndex = node.MeshIndex; - scene.nodes[i] = mdsNode; + scene.Nodes[i] = mdsNode; } } private static void ReadMaterials(MDSScene scene, MDSHeader header, byte[] data, string names) { - var offset = header.offsetToMaterials; + var offset = header.OffsetToMaterials; - scene.materials = new MDSMaterial[header.materialsCount]; + scene.Materials = new MDSMaterial[header.MaterialsCount]; - for (var i = 0; i < header.materialsCount; i++) + for (var i = 0; i < header.MaterialsCount; i++) { var rawMaterial = Utils.ReadStruct(data, ref offset, true); var mdsMaterial = new MDSMaterial(); - mdsMaterial.materialType = rawMaterial.value17; + mdsMaterial.MaterialType = rawMaterial.MaterialType; - if (rawMaterial.value13 == 1) + if (rawMaterial.NoName == 1) { - mdsMaterial.name = "NONE"; - mdsMaterial.textureName = "NONE"; + mdsMaterial.Name = "NONE"; + mdsMaterial.TextureName = "NONE"; } else { - mdsMaterial.name = Utils.GetName(names, rawMaterial.nameOffset); - mdsMaterial.textureName = Utils.GetName(names, rawMaterial.textureNameOffset); + mdsMaterial.Name = Utils.GetName(names, rawMaterial.NameOffset); + mdsMaterial.TextureName = Utils.GetName(names, rawMaterial.TextureNameOffset); } - scene.materials[i] = mdsMaterial; + scene.Materials[i] = mdsMaterial; } } @@ -256,7 +256,7 @@ public class Reader var triangles = new List(); if (header.ReadMode == TriangleReadMode.Triangle) { - for (var i = 0; i < header.idsCount; i += 3) + for (var i = 0; i < header.IdsCount; i += 3) { var triangle = Utils.ReadArray(data, offset, 3, 0, i => i); offset += 6; @@ -271,7 +271,7 @@ public class Reader if (header.ReadMode == TriangleReadMode.TriangleStrip) { var isDefaultOrder = true; - while (readCount < header.idsCount - 2) + while (readCount < header.IdsCount - 2) { var triangle = Utils.ReadArray(data, offset, 3, 0, i => i); readCount++; diff --git a/dq8chr2glb/Core/MDSFormat/Types.cs b/dq8chr2glb/Core/MDSFormat/Types.cs index 13397df..a907cb7 100644 --- a/dq8chr2glb/Core/MDSFormat/Types.cs +++ b/dq8chr2glb/Core/MDSFormat/Types.cs @@ -4,19 +4,19 @@ namespace dq8chr2glb.Core.MDSFormat; public class MDSScene { - public MDSNode[] nodes; - public MDSMaterial[] materials; + public MDSNode[] Nodes; + public MDSMaterial[] Materials; } public class MDSNode { - public string name; - public int index; - public int parentIndex; - public MDSMatrix transform; - public MDSMatrix bindpose; - public NodeType type; - public int meshIndex; + public string Name; + public int Index; + public int ParentIndex; + public MDSMatrix Transform; + public MDSMatrix Bindpose; + public NodeType Type; + public int MeshIndex; } public class MDSBone : MDSNode @@ -25,57 +25,57 @@ public class MDSBone : MDSNode public class MDSMesh : MDSNode { - public SubMesh[] submeshes; - public MeshFeatures features; - public AABB bounds; + public SubMesh[] Submeshes; + public MeshFeatures Features; + public AABB Bounds; // merged data - public float[][] vertices; - public float[][] color; - public float[][] uv; - public float[][] weights; - public int[][] bones; - public int[] triangles; + public float[][] Vertices; + public float[][] Color; + public float[][] Uv; + public float[][] Weights; + public int[][] Bones; + public int[] Triangles; } public class SubMesh { - public int materialIndex; - public int startIndex; - public int indexCount; + public int MaterialIndex; + public int StartIndex; + public int IndexCount; } public class MDSMaterial { - public string name; - public string textureName; - public int materialType; + public string Name; + public string TextureName; + public int MaterialType; } [StructLayout(LayoutKind.Explicit, Size=64)] public struct MDSMatrix { - [FieldOffset(00)]public float m00; - [FieldOffset(04)]public float m01; - [FieldOffset(08)]public float m02; - [FieldOffset(12)]public float m03; - [FieldOffset(16)]public float m10; - [FieldOffset(20)]public float m11; - [FieldOffset(24)]public float m12; - [FieldOffset(28)]public float m13; - [FieldOffset(32)]public float m20; - [FieldOffset(36)]public float m21; - [FieldOffset(40)]public float m22; - [FieldOffset(44)]public float m23; - [FieldOffset(48)]public float m30; - [FieldOffset(52)]public float m31; - [FieldOffset(56)]public float m32; - [FieldOffset(60)]public float m33; + [FieldOffset(00)]public float M00; + [FieldOffset(04)]public float M01; + [FieldOffset(08)]public float M02; + [FieldOffset(12)]public float M03; + [FieldOffset(16)]public float M10; + [FieldOffset(20)]public float M11; + [FieldOffset(24)]public float M12; + [FieldOffset(28)]public float M13; + [FieldOffset(32)]public float M20; + [FieldOffset(36)]public float M21; + [FieldOffset(40)]public float M22; + [FieldOffset(44)]public float M23; + [FieldOffset(48)]public float M30; + [FieldOffset(52)]public float M31; + [FieldOffset(56)]public float M32; + [FieldOffset(60)]public float M33; - public float[] elements => new[] + public float[] Elements => new[] { - m00, m01, m02, m03, - m10, m11, m12, m13, - m20, m21, m22, m23, - m30, m31, m32, m33 + M00, M01, M02, M03, + M10, M11, M12, M13, + M20, M21, M22, M23, + M30, M31, M32, M33 }; } \ No newline at end of file diff --git a/dq8chr2glb/Core/MOTFormat/Importer.cs b/dq8chr2glb/Core/MOTFormat/Importer.cs index 07fc154..a3a38d8 100644 --- a/dq8chr2glb/Core/MOTFormat/Importer.cs +++ b/dq8chr2glb/Core/MOTFormat/Importer.cs @@ -12,9 +12,9 @@ public class Importer { var offset = 0; var header = Utils.ReadStruct(data, ref offset); - offset += header.bonesOffset; + offset += header.BonesOffset; - var boneCount = header.boneCount; + var boneCount = header.BoneCount; var animation = new List(); for (var i = 0; i < boneCount; i++) { @@ -27,7 +27,7 @@ public class Importer private List GetTransformGroups(byte[] data, BoneHeader header, int offset, out int offsetAfter) { - var attribCount = TransformFlagsHelper.GetAttribCount(header.transformFlags); + var attribCount = TransformFlagsHelper.GetAttribCount(header.TransformFlags); var attribHeadersOffset = attribCount > 1 ? 32 : 16; var transformGroups = new List(); @@ -45,31 +45,31 @@ public class Importer private void ReadRotationKeyframes(byte[] data, MotionCurve curve, int offset) { - curve.curveType = KeyframeType.Quaternion; + curve.CurveType = KeyframeType.Quaternion; var headerOffset = offset; var header = Utils.ReadStruct(data, ref headerOffset); - var valuesOffset = headerOffset + header.valuesOffset; + var valuesOffset = headerOffset + header.ValuesOffset; - if (header.toFramesOffset == 0) + if (header.ToFramesOffset == 0) { - var count = header.framesCount; + var count = header.FramesCount; for (var i = 0; i < count; i++) { var keyframe = new KeyFrame(); - keyframe.frame = i; + keyframe.Frame = i; - var scale = new Vector4(header.scaleX, header.scaleY, - header.scaleZ, header.scaleW); + var scale = new Vector4(header.ScaleX, header.ScaleY, + header.ScaleZ, header.ScaleW); - keyframe.rotation = ReadQuaternion(data, valuesOffset, scale); - curve.keyframes.Add(keyframe); + keyframe.Rotation = ReadQuaternion(data, valuesOffset, scale); + curve.Keyframes.Add(keyframe); valuesOffset += 8; } } else { - var framesCount = header.framesCount; - var toFramesOffset = headerOffset + header.toFramesOffset; + var framesCount = header.FramesCount; + var toFramesOffset = headerOffset + header.ToFramesOffset; var frames = ReadFrames(data, toFramesOffset, framesCount); if (frames.Length == 0) { @@ -77,26 +77,26 @@ public class Importer } var maxFrame = frames.Max(); - curve.keyframes = new List(); + curve.Keyframes = new List(); for (var i = 0; i < maxFrame + 1; i++) { - curve.keyframes.Add(null); + curve.Keyframes.Add(null); } - var toValues = header.valuesOffset; + var toValues = header.ValuesOffset; foreach (var frame in frames) { - var scale = new Vector4(header.scaleX, header.scaleY, - header.scaleZ, header.scaleW); + var scale = new Vector4(header.ScaleX, header.ScaleY, + header.ScaleZ, header.ScaleW); var keyframe = new KeyFrame(); - keyframe.frame = frame; - keyframe.type = KeyframeType.Quaternion; - keyframe.rotation = ReadQuaternion(data, valuesOffset, scale); + keyframe.Frame = frame; + keyframe.Type = KeyframeType.Quaternion; + keyframe.Rotation = ReadQuaternion(data, valuesOffset, scale); try { - curve.keyframes[frame] = keyframe; + curve.Keyframes[frame] = keyframe; } catch (Exception e) { @@ -110,33 +110,33 @@ public class Importer private void ReadPositionKeyframes(byte[] data, MotionCurve curve, int offset) { - curve.curveType = KeyframeType.Translation; + curve.CurveType = KeyframeType.Translation; var headerOffset = offset; var header = Utils.ReadStruct(data, ref offset, false); - var valuesOffset = headerOffset + header.valuesOffset; + var valuesOffset = headerOffset + header.ValuesOffset; - if (header.toFramesOffset == 0) + if (header.ToFramesOffset == 0) { - var count = header.framesCount; + var count = header.FramesCount; for (var i = 0; i < count; i++) { var keyframe = new KeyFrame(); - keyframe.frame = i; + keyframe.Frame = i; - var scale = new Vector3(header.scaleX, header.scaleY, - header.scaleZ); + var scale = new Vector3(header.ScaleX, header.ScaleY, + header.ScaleZ); var translation = ReadVector3(data, valuesOffset, scale); - keyframe.translation = translation; - curve.keyframes.Add(keyframe); + keyframe.Translation = translation; + curve.Keyframes.Add(keyframe); valuesOffset += 6; } } else { - var framesCount = header.framesCount; - var toFramesOffset = headerOffset + header.toFramesOffset; + var framesCount = header.FramesCount; + var toFramesOffset = headerOffset + header.ToFramesOffset; var frames = ReadFrames(data, toFramesOffset, framesCount); if (frames.Length == 0) { @@ -144,13 +144,13 @@ public class Importer } var maxFrame = frames.Max(); - curve.keyframes = new List(); + curve.Keyframes = new List(); for (var i = 0; i < maxFrame + 1; i++) { - curve.keyframes.Add(null); + curve.Keyframes.Add(null); } - var toValues = header.valuesOffset; + var toValues = header.ValuesOffset; foreach (var frame in frames) { if (frame == null || frame < 0) @@ -158,15 +158,15 @@ public class Importer continue; } - var scale = new Vector3(header.scaleX, header.scaleY, - header.scaleZ); + var scale = new Vector3(header.ScaleX, header.ScaleY, + header.ScaleZ); var keyframe = new KeyFrame(); - keyframe.frame = frame; - keyframe.type = KeyframeType.Translation; - keyframe.translation = ReadVector3(data, valuesOffset, scale); + keyframe.Frame = frame; + keyframe.Type = KeyframeType.Translation; + keyframe.Translation = ReadVector3(data, valuesOffset, scale); - curve.keyframes[frame] = keyframe; + curve.Keyframes[frame] = keyframe; valuesOffset += 6; } } @@ -184,39 +184,39 @@ public class Importer foreach (var group in transformGroups) { var curve = new MotionCurve(); - curve.boneIndex = header.boneIndex; - curve.keyframes = new List(); + curve.BoneIndex = header.BoneIndex; + curve.Keyframes = new List(); - switch (group.keyframeType) + switch (group.KeyframeType) { case KeyframeType.Quaternion: - ReadRotationKeyframes(data, curve, headerPosition + group.offset); + ReadRotationKeyframes(data, curve, headerPosition + group.Offset); break; case KeyframeType.Translation: - ReadPositionKeyframes(data, curve, headerPosition + group.offset); + ReadPositionKeyframes(data, curve, headerPosition + group.Offset); break; default: - // Debug.Log($"[UNK KF TYPE]: {group.keyframeType}"); + Log.Line($"[UNKNOWN KF TYPE]: {group.KeyframeType}"); break; } boneCurves.Add(curve); } - switch (header.transformFlags) - { - case TransformFlags.Rotation: - // Debug.Log($"Rotation: {(int)header.transformFlags}."); - break; - case TransformFlags.TR: - // Debug.Log($"Rot/Pos: {(int)header.transformFlags}"); - break; - default: - // Debug.Log($"Unknown flag: {(int)header.transformFlags}, {header.transformFlags}"); - break; - } + // switch (header.transformFlags) + // { + // case TransformFlags.Rotation: + // // Debug.Log($"Rotation: {(int)header.transformFlags}."); + // break; + // case TransformFlags.TR: + // // Debug.Log($"Rot/Pos: {(int)header.transformFlags}"); + // break; + // default: + // // Debug.Log($"Unknown flag: {(int)header.transformFlags}, {header.transformFlags}"); + // break; + // } - offset = headerPosition + header.toNext; + offset = headerPosition + header.ToNext; return boneCurves; } diff --git a/dq8chr2glb/Core/MOTFormat/Types.cs b/dq8chr2glb/Core/MOTFormat/Types.cs index fedb6bb..3229ef8 100644 --- a/dq8chr2glb/Core/MOTFormat/Types.cs +++ b/dq8chr2glb/Core/MOTFormat/Types.cs @@ -9,39 +9,39 @@ namespace dq8chr2glb.Core.MOTFormat public struct MOTHeader { [FieldOffset(00)] public int MagicCode; - [FieldOffset(08)] public int headerSize; - [FieldOffset(28)] public int boneCount; - [FieldOffset(32)] public int bonesOffset; - [FieldOffset(48)] public int fileSizeClaim; + [FieldOffset(08)] public int HeaderSize; + [FieldOffset(28)] public int BoneCount; + [FieldOffset(32)] public int BonesOffset; + [FieldOffset(48)] public int FileSize; } [StructLayout(LayoutKind.Explicit, Size = 16)] public struct BoneHeader { - [FieldOffset(00)] public int toNext; - [FieldOffset(04)] public int boneIndex; - [FieldOffset(12)] public TransformFlags transformFlags; + [FieldOffset(00)] public int ToNext; + [FieldOffset(04)] public int BoneIndex; + [FieldOffset(12)] public TransformFlags TransformFlags; } [StructLayout(LayoutKind.Explicit, Size = 8)] public struct TransformGroup { - [FieldOffset(00)] public KeyframeType keyframeType; - [FieldOffset(04)] public int offset; + [FieldOffset(00)] public KeyframeType KeyframeType; + [FieldOffset(04)] public int Offset; } [StructLayout(LayoutKind.Explicit, Size = 32)] public struct KeyframesBlockHeader { - [FieldOffset(00)] public short flag0; - [FieldOffset(02)] public short flag1; - [FieldOffset(06)] public short framesCount; - [FieldOffset(08)] public short toFramesOffset; - [FieldOffset(12)] public short valuesOffset; - [FieldOffset(16)] public float scaleX; - [FieldOffset(20)] public float scaleY; - [FieldOffset(24)] public float scaleZ; - [FieldOffset(28)] public float scaleW; + [FieldOffset(00)] public short Flag0; + [FieldOffset(02)] public short Flag1; + [FieldOffset(06)] public short FramesCount; + [FieldOffset(08)] public short ToFramesOffset; + [FieldOffset(12)] public short ValuesOffset; + [FieldOffset(16)] public float ScaleX; + [FieldOffset(20)] public float ScaleY; + [FieldOffset(24)] public float ScaleZ; + [FieldOffset(28)] public float ScaleW; } [Flags] @@ -68,18 +68,18 @@ namespace dq8chr2glb.Core.MOTFormat public class MotionCurve { - public int boneIndex; - public KeyframeType curveType; - public List keyframes; + public int BoneIndex; + public KeyframeType CurveType; + public List Keyframes; } public class KeyFrame { - public int frame; - public KeyframeType type; - public Quaternion rotation; - public Vector3 translation; - public Vector3 scale; + public int Frame; + public KeyframeType Type; + public Quaternion Rotation; + public Vector3 Translation; + public Vector3 Scale; } public static class TransformFlagsHelper diff --git a/dq8chr2glb/Core/Types.cs b/dq8chr2glb/Core/Types.cs deleted file mode 100644 index 0bb9739..0000000 --- a/dq8chr2glb/Core/Types.cs +++ /dev/null @@ -1,2 +0,0 @@ -namespace dq8chr2glb.Core; - diff --git a/dq8chr2glb/Core/Utils.cs b/dq8chr2glb/Core/Utils.cs index aed10cd..d1f7a77 100644 --- a/dq8chr2glb/Core/Utils.cs +++ b/dq8chr2glb/Core/Utils.cs @@ -68,12 +68,12 @@ public static class Utils public static MDSMesh GetMeshByIndex(MDSScene scene, int index) { - foreach (var node in scene.nodes) + foreach (var node in scene.Nodes) { - if (node.type == NodeType.Mesh) + if (node.Type == NodeType.Mesh) { var mesh = node as MDSMesh; - if (mesh.meshIndex == index) + if (mesh.MeshIndex == index) { return mesh; } diff --git a/dq8chr2glb/Program.cs b/dq8chr2glb/Program.cs index 2033b64..d36c543 100644 --- a/dq8chr2glb/Program.cs +++ b/dq8chr2glb/Program.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.CommandLine; using System.IO; using dq8chr2glb.Converter; @@ -15,24 +14,34 @@ public class Program { new Option("-i", "--input") { Description = "Input path", HelpName = "input path"}, new Option("-o", "--output") { Description = "Output path", HelpName = "output path"}, + new Option("-d", "--data") { Description = "Data for append animations", HelpName = "Data"}, new Option("-f", "--format") {Description = "Output format", DefaultValueFactory = _ => OutputFormat.GLB}, new Option("-e", "--extract") {Description = "Extract only - unpack .chr without conversion"}, new Option("-b", "--batch") {Description = "Batch mode - process all .chr files in the input directory"}, - new Option("-l", "--log") { Description = "Log level", DefaultValueFactory = _ => LogMode.MINIMAL }, + // new Option("-a", "--append") { Description = "Append animations to input .glb/glTF file"}, }; var parser = rootCommand.Parse(args); var inputPath = parser.GetValue("-i"); var outputPath = parser.GetValue("-o"); + var dataPath = parser.GetValue("-d"); var extractOnly = parser.GetValue("-e"); var textFormat = parser.GetValue("-f") == OutputFormat.GLTF; var batchMode = parser.GetValue("-b"); + // var appendMode = parser.GetValue("-a"); + + // if (appendMode) + // { + // var appendAnimations = new AppendAnimations(); + // appendAnimations.Append(inputPath, dataPath); + // return; + // } var chrFile = new ChrFile(); - chrFile.convert = !extractOnly; - chrFile.extract = extractOnly; - chrFile.textFormat = textFormat; + chrFile.Convert = !extractOnly; + chrFile.Extract = extractOnly; + chrFile.TextFormat = textFormat; if (string.IsNullOrEmpty(inputPath)) { diff --git a/dq8chr2glb/TM2Format/TM2Format.cs b/dq8chr2glb/TM2Format/TM2Format.cs index 2057ca9..a9af217 100644 --- a/dq8chr2glb/TM2Format/TM2Format.cs +++ b/dq8chr2glb/TM2Format/TM2Format.cs @@ -10,12 +10,12 @@ namespace dq8chr2glb.TM2Format; // Взято из https://github.com/Souzooka/TM2Unswizzler public static class TM2Format { - public static IncludedFile currentFile; + public static IncludedFile CurrentFile; public static Texture GetImage(IncludedFile file, string name) { - currentFile = file; - var data = file.data; + CurrentFile = file; + var data = file.Data; var header = TM2Header.GetHeader(data); var image = GetImageBuffer(header, data); @@ -73,7 +73,7 @@ public static class TM2Format } catch (Exception e) { - Context.current.errors.Add(new Error(currentFile.name, "Error while import texture", e)); + Context.Current.Errors.Add(new Error(CurrentFile.Name, "Error while import texture", e)); palette = null; } diff --git a/dq8chr2glb/TM2Format/TM2Types.cs b/dq8chr2glb/TM2Format/TM2Types.cs index f36ca4e..ffc3dcf 100644 --- a/dq8chr2glb/TM2Format/TM2Types.cs +++ b/dq8chr2glb/TM2Format/TM2Types.cs @@ -8,8 +8,8 @@ public struct TM2Header public int Label; public byte Version; public byte Format; - public int padding0; - public int padding1; + public int Padding0; + public int Padding1; public uint TotalSize; public uint ClutSize; public uint ImageSize; diff --git a/dq8chr2glb/TM2Format/Texture.cs b/dq8chr2glb/TM2Format/Texture.cs index a5574de..67fb995 100644 --- a/dq8chr2glb/TM2Format/Texture.cs +++ b/dq8chr2glb/TM2Format/Texture.cs @@ -5,12 +5,12 @@ namespace dq8chr2glb.TM2Format; public class Texture { - public readonly string name; - public readonly Image data; + public readonly string Name; + public readonly Image Data; public Texture(string name, Image data) { - this.name = name; - this.data = data; + Name = name; + Data = data; } } \ No newline at end of file