Browse Source

Add MATE to YAML convert

ghorsington 4 years ago
parent
commit
850e5c7d38

+ 4 - 2
ArcToolkitCLI/ArcToolkitCLI.csproj

@@ -65,13 +65,15 @@
     <Reference Include="System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
       <HintPath>..\packages\System.ValueTuple.4.5.0\lib\net461\System.ValueTuple.dll</HintPath>
     </Reference>
-    <Reference Include="YamlDotNet, Version=6.0.0.0, Culture=neutral, PublicKeyToken=ec19458f3c15af5e, processorArchitecture=MSIL">
-      <HintPath>..\packages\YamlDotNet.6.1.2\lib\net45\YamlDotNet.dll</HintPath>
+    <Reference Include="YamlDotNet, Version=8.0.0.0, Culture=neutral, PublicKeyToken=ec19458f3c15af5e">
+      <HintPath>..\packages\YamlDotNet.8.1.0\lib\net45\YamlDotNet.dll</HintPath>
+      <Private>True</Private>
     </Reference>
   </ItemGroup>
   <ItemGroup>
     <Compile Include="Commands\ConvertCommand.cs" />
     <Compile Include="Commands\Converters\BaseConverter.cs" />
+    <Compile Include="Commands\Converters\MateConverter.cs" />
     <Compile Include="Commands\Converters\MenuConverter.cs" />
     <Compile Include="Commands\Converters\NeiConverter.cs" />
     <Compile Include="Commands\Converters\TexConverter.cs" />

+ 372 - 0
ArcToolkitCLI/Commands/Converters/MateConverter.cs

@@ -0,0 +1,372 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using CommandLine;
+using YamlDotNet.Core;
+using YamlDotNet.Serialization;
+
+namespace ArcToolkitCLI.Commands.Converters
+{
+    [Verb("mate", HelpText = "Convert MATE files into YAML and back")]
+    public class MateConverter : BaseConverter
+    {
+        private const string MATE_TAG = "CM3D2_MATERIAL";
+
+        private readonly Dictionary<string, Type> mappingTypes;
+
+        public MateConverter()
+        {
+            Converters = new Dictionary<string, Func<string, int>>
+            {
+                [".mate"] = MateToYaml,
+                [".yaml"] = YamlToMate
+            };
+
+            mappingTypes = GetType().GetNestedTypes(BindingFlags.NonPublic).Select(t => new
+                {
+                    type = t,
+                    attrs = t.GetCustomAttributes(typeof(TagAttribute), true).Cast<TagAttribute>().ToArray()
+                })
+                .Where(d => d.attrs.Length != 0)
+                .ToDictionary(d => $"!{d.attrs.First().Tag}", d => d.type);
+        }
+
+        private int YamlToMate(string file)
+        {
+            var fileName = Path.GetFileNameWithoutExtension(file);
+
+            if (!fileName.ToLowerInvariant().EndsWith(".mate"))
+            {
+                Console.WriteLine($"Filename of {file} must have .mate.yaml extension! Skipping...");
+                return 0;
+            }
+
+            var db = new DeserializerBuilder();
+
+            foreach (var kv in mappingTypes)
+                db.WithTagMapping(kv.Key, kv.Value);
+
+            var deserializer = db.Build();
+
+            MateFile data;
+            try
+            {
+                data = deserializer.Deserialize<MateFile>(new StreamReader(file, Encoding.UTF8));
+            }
+            catch (YamlException e)
+            {
+                Console.WriteLine($"Failed to read YAML file because {e.Message}: {e.InnerException?.Message}");
+                return 1;
+            }
+
+            using var bw =
+                new BinaryWriter(File.Create(Path.Combine(Output, fileName)),
+                    Encoding.UTF8);
+
+            data.Serialize(bw);
+
+            return 0;
+        }
+
+        private int MateToYaml(string file)
+        {
+            using var br = new BinaryReader(File.OpenRead(file), Encoding.UTF8);
+            var tag = br.ReadString();
+            if (tag != MATE_TAG)
+            {
+                Console.WriteLine("Provided file is not a valid MATE file!");
+                return 1;
+            }
+
+            var mateFile = new MateFile
+            {
+                Version = br.ReadInt32(),
+                Path = br.ReadString(),
+                Name = br.ReadString(),
+                ShaderName = br.ReadString(),
+                DefMaterial = br.ReadString(),
+                ShaderProperties = new List<ShaderVariable>()
+            };
+
+            while (true)
+            {
+                var prop = br.ReadString();
+
+                if (prop == "end")
+                {
+                    mateFile.ShaderProperties.Add(new EndTag());
+                    break;
+                }
+                
+                // TODO: Clean up
+
+                var paramName = br.ReadString();
+                ShaderVariable sVar;
+                switch (prop)
+                {
+                    case "tex":
+                        var texType = br.ReadString();
+                        sVar = texType switch
+                        {
+                            "null" => new TexNullVar(),
+                            "tex2d" => new Tex2DVar
+                            {
+                                TextureName = br.ReadString(),
+                                Path = br.ReadString(),
+                                Offset = new Vec2
+                                {
+                                    X = br.ReadSingle(),
+                                    Y = br.ReadSingle()
+                                },
+                                Scale = new Vec2
+                                {
+                                    X = br.ReadSingle(),
+                                    Y = br.ReadSingle()
+                                }
+                            },
+                            "texRT" => new TexRTVar
+                            {
+                                TextureName = br.ReadString(),
+                                Path = br.ReadString()
+                            },
+                            _ => throw new Exception($"Invalid prop {texType} in file {file}")
+                        };
+                        break;
+                    case "col":
+                        sVar = new ColVar
+                        {
+                            Red = br.ReadSingle(),
+                            Green = br.ReadSingle(),
+                            Blue = br.ReadSingle(),
+                            Alpha = br.ReadSingle()
+                        };
+                        break;
+                    case "vec":
+                        sVar = new Vec4Var
+                        {
+                            X = br.ReadSingle(),
+                            Y = br.ReadSingle(),
+                            Z = br.ReadSingle(),
+                            W = br.ReadSingle()
+                        };
+                        break;
+                    case "f":
+                        sVar = new FloatVar
+                        {
+                            Value = br.ReadSingle()
+                        };
+                        break;
+                    default:
+                        Console.WriteLine($"Invalid prop {prop} in file {file}");
+                        return 1;
+                }
+
+                sVar.ShaderProperty = paramName;
+                mateFile.ShaderProperties.Add(sVar);
+            }
+
+            var sb = new SerializerBuilder();
+            sb.ConfigureDefaultValuesHandling(DefaultValuesHandling.OmitNull);
+            foreach (var kv in mappingTypes)
+                sb.WithTagMapping(kv.Key, kv.Value);
+            var serializer = sb.Build();
+
+            var yaml = serializer.Serialize(mateFile);
+            File.WriteAllText(Path.Combine(Output, $"{Path.GetFileName(file)}.yaml"), yaml);
+            return 0;
+        }
+
+        [AttributeUsage(AttributeTargets.Class, Inherited = false)]
+        private class TagAttribute : Attribute
+        {
+            public TagAttribute(string Tag)
+            {
+                this.Tag = Tag;
+            }
+
+            public string Tag { get; }
+
+            public bool WriteShaderProp { get; set; } = true;
+        }
+
+        private class ShaderVariable
+        {
+            [YamlMember(Alias = "property")] public string ShaderProperty { get; set; }
+
+            public virtual void Serialize(BinaryWriter bw)
+            {
+                var tagAttribute = GetType().GetCustomAttributes(typeof(TagAttribute), true).Cast<TagAttribute>()
+                    .FirstOrDefault();
+
+                if (tagAttribute == null)
+                    return;
+
+                bw.Write(tagAttribute.Tag);
+
+                if (tagAttribute.WriteShaderProp)
+                    bw.Write(ShaderProperty);
+            }
+        }
+
+        [Tag("end", WriteShaderProp = false)]
+        private class EndTag : ShaderVariable
+        {
+        }
+
+        private class TexVar : ShaderVariable
+        {
+            public override void Serialize(BinaryWriter bw)
+            {
+                var tagAttribute = GetType().GetCustomAttributes(typeof(TagAttribute), true).Cast<TagAttribute>()
+                    .FirstOrDefault();
+                if (tagAttribute == null)
+                    return;
+
+                bw.Write("tex");
+                bw.Write(ShaderProperty);
+                bw.Write(tagAttribute.Tag);
+            }
+        }
+
+        [Tag("tex_null")]
+        private class TexNullVar : TexVar
+        {
+            public override void Serialize(BinaryWriter bw)
+            {
+                bw.Write("tex");
+                bw.Write(ShaderProperty);
+                bw.Write("null");
+            }
+        }
+
+        [Tag("tex2d")]
+        private class Tex2DVar : TexVar
+        {
+            [YamlMember(Alias = "texname")] public string TextureName { get; set; }
+
+            [YamlMember(Alias = "path")] public string Path { get; set; }
+
+            [YamlMember(Alias = "offset")] public Vec2 Offset { get; set; }
+
+            [YamlMember(Alias = "scale")] public Vec2 Scale { get; set; }
+
+            public override void Serialize(BinaryWriter bw)
+            {
+                base.Serialize(bw);
+                bw.Write(TextureName);
+                bw.Write(Path);
+                bw.Write(Offset.X);
+                bw.Write(Offset.Y);
+                bw.Write(Scale.X);
+                bw.Write(Scale.Y);
+            }
+        }
+
+        [Tag("texRT")]
+        private class TexRTVar : TexVar
+        {
+            [YamlMember(Alias = "texname")] public string TextureName { get; set; }
+
+            [YamlMember(Alias = "path")] public string Path { get; set; }
+
+            public override void Serialize(BinaryWriter bw)
+            {
+                base.Serialize(bw);
+                bw.Write(Path);
+                bw.Write(TextureName);
+            }
+        }
+
+        [Tag("col")]
+        private class ColVar : ShaderVariable
+        {
+            [YamlMember(Alias = "r")] public float Red { get; set; }
+
+            [YamlMember(Alias = "g")] public float Green { get; set; }
+
+            [YamlMember(Alias = "b")] public float Blue { get; set; }
+
+            [YamlMember(Alias = "a")] public float Alpha { get; set; }
+
+            public override void Serialize(BinaryWriter bw)
+            {
+                base.Serialize(bw);
+                bw.Write(Red);
+                bw.Write(Green);
+                bw.Write(Blue);
+                bw.Write(Alpha);
+            }
+        }
+
+        [Tag("vec")]
+        private class Vec4Var : ShaderVariable
+        {
+            [YamlMember(Alias = "x")] public float X { get; set; }
+
+            [YamlMember(Alias = "y")] public float Y { get; set; }
+
+            [YamlMember(Alias = "z")] public float Z { get; set; }
+
+            [YamlMember(Alias = "w")] public float W { get; set; }
+
+            public override void Serialize(BinaryWriter bw)
+            {
+                base.Serialize(bw);
+                bw.Write(X);
+                bw.Write(Y);
+                bw.Write(Z);
+                bw.Write(W);
+            }
+        }
+
+        [Tag("f")]
+        private class FloatVar : ShaderVariable
+        {
+            [YamlMember(Alias = "value")] public float Value { get; set; }
+
+            public override void Serialize(BinaryWriter bw)
+            {
+                base.Serialize(bw);
+                bw.Write(Value);
+            }
+        }
+
+        private class Vec2
+        {
+            [YamlMember(Alias = "x")] public float X { get; set; }
+
+            [YamlMember(Alias = "y")] public float Y { get; set; }
+        }
+
+        private class MateFile
+        {
+            [YamlMember(Alias = "version")] public int Version { get; set; }
+
+            [YamlMember(Alias = "path")] public string Path { get; set; }
+
+            [YamlMember(Alias = "name")] public string Name { get; set; }
+
+            [YamlMember(Alias = "shader")] public string ShaderName { get; set; }
+
+            [YamlMember(Alias = "def_material")] public string DefMaterial { get; set; }
+
+            [YamlMember(Alias = "shader_props")] public List<ShaderVariable> ShaderProperties { get; set; }
+
+            public void Serialize(BinaryWriter bw)
+            {
+                bw.Write(MATE_TAG);
+                bw.Write(Version);
+                bw.Write(Path);
+                bw.Write(Name);
+                bw.Write(ShaderName);
+                bw.Write(DefMaterial);
+
+                foreach (var shaderProperty in ShaderProperties)
+                    shaderProperty.Serialize(bw);
+            }
+        }
+    }
+}