private void WriteMtl(ThreeDModel m3d, string mtlfn) { var opts = Program.Options; var clr = opts.OverrideColor; var dn = this.fi.Directory.FullName; var p = Path.Combine(dn, string.Concat(mtlfn, ".mtl")); var mtlfi = new FileInfo(p); using (var fs = mtlfi.Create()) using (var sw = new StreamWriter(fs, new UTF8Encoding(false))) { sw.NewLine = "\n"; sw.WriteLine("# Generated using MSET Converter by John Cena of PTF"); sw.WriteLine("# mset Version: {0}", Program.GetAssemblyVersion()); sw.WriteLine("# mset-obj Version: {0}", this.VersionID); sw.WriteLine(); sw.WriteLine("# Default MSET material"); sw.WriteLine("newmtl JCMSet"); sw.WriteLine("Kd {0:0.000000} {1:0.000000} {2:0.000000}", clr.RFloat, clr.GFloat, clr.BFloat); sw.WriteLine("d {0:0.000000}", clr.AFloat); sw.WriteLine("Tr {0:0.000000}", 1F - clr.AFloat); sw.WriteLine(); sw.Flush(); } if (opts.VerboseMode) { ULogger.W("OBJMTL", "Written MTL: {0}", mtlfi.FullName); } }
private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) { var ex = e.ExceptionObject != null && e.ExceptionObject is Exception ? (Exception)e.ExceptionObject : null; ULogger.W("ERR", "An error has occured within the application"); if (ex != null) { ULogger.X("ERR", ex); } else { ULogger.W("ERR", "FATAL: No details are avaialble"); } }
internal static void PrintUse() { ULogger.W("APP", "Usage: mset2 <arguments...> <files>"); ULogger.N("APP"); ULogger.W("APP", "Extraction options:"); ULogger.W("APP", " -e:<encoder>"); ULogger.W("APP", " Specifies output encoder. <encoder> must be a valid encoder. For available encoders, see readme."); ULogger.W("APP", " Default value: OBJ"); ULogger.N("APP"); ULogger.W("APP", " -d:<path>"); ULogger.W("APP", " Specifies output directory. <path> must be a valid directory path."); ULogger.W("APP", " Default value: <null> (outputs to source files' directory)"); ULogger.N("APP"); ULogger.W("APP", " -l"); ULogger.W("APP", " Lists models in a file then exists."); ULogger.N("APP"); ULogger.W("APP", " -m:<model_name>"); ULogger.W("APP", " Specifies extracting a specific model from input file(s). <model_name> is a model to extract."); ULogger.W("APP", " Default value: <null> (extracts all models)"); ULogger.N("APP"); ULogger.W("APP", " -c:<color>"); ULogger.W("APP", " Overrides vertex colors on resulting mesh. <color> is an unsigned 32-bit integer containing ARGB information."); ULogger.W("APP", " Default value: <null> (does not override colors)"); ULogger.N("APP"); ULogger.W("APP", " -o:<options>"); ULogger.W("APP", " Specifies selected encoder's options. <options> is a string of comma-separated key-value pairs. For examples and available encoder options, see readme."); ULogger.W("APP", " Default value: <null> (use default options)"); ULogger.N("APP"); ULogger.W("APP", " -r"); ULogger.W("APP", " Creates raw mesh dumps alongside output files. These are UTF-8-encoded text files describing raw input data."); ULogger.N("APP"); ULogger.W("APP", "Program options:"); ULogger.W("APP", " -v"); ULogger.W("APP", " Enables verbose logging to console."); ULogger.N("APP"); ULogger.W("APP", " -v:<path>"); ULogger.W("APP", " Enables logging to file. Supersedes -v. <path> must be a valid file path."); ULogger.N("APP"); ULogger.W("APP", " -help"); ULogger.W("APP", " Prints this message and quits."); ULogger.N("APP"); }
/* * COMMANDLINE OPTIONS * * Extraction options: * -e:<encoder> * Specifies output encoder. <encoder> must be a valid encoder. For available encoders, see readme. * Default value: OBJ * * -d:<path> * Specifies output directory. <path> must be a valid directory path. * Default value: <null> (outputs to source files' directory) * * -l * Lists models in a file then exists. * * -m:<model_name> * Specifies extracting a specific model from input file(s). <model_name> is a model to extract. * Default value: <null> (extracts all models) * * -c:<color> * Overrides vertex colors on resulting mesh. <color> is an unsigned 32-bit integer containing ARGB information. * Default value: <null> (does not override colors) * * -o:<options> * Specifies selected encoder's options. <options> is a string of comma-separated key-value pairs. For examples and available encoder options, see readme. * Default value: <null> (use default options) * * -r * Creates raw mesh dumps alongside output files. These are UTF-8-encoded text files describing raw input data. * * Program options: * -v * Enables verbose logging to console. * * -v:<path> * Enables logging to file. Supersedes -v. <path> must be a valid file path. */ internal static void Main(string[] args) { ULogger.D(Debugger.IsAttached); ULogger.R(Console.Out); ULogger.W("MSET2", "Initializing"); AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; var cmdl = ParseCommandLine(args); Options = cmdl; if (cmdl.VerboseMode) { if (cmdl.VerboseModeLogFile != null) { var tw = new StreamWriter(cmdl.VerboseModeLogFile.Create(), new UTF8Encoding(false)); ULogger.R(tw); } ULogger.W("APP", "Commandline options:"); ULogger.W("APP", " Encoder: {0} (ver. {1})", cmdl.ModelWriter.WriterID, cmdl.ModelWriter.VersionID); ULogger.W("APP", " Output path: {0}", cmdl.OutputDirectory != null ? cmdl.OutputDirectory.FullName : "<null>"); ULogger.W("APP", " Just list models: {0}", cmdl.ListModels ? "Yes" : "No"); ULogger.W("APP", " Model name: {0}", cmdl.ModelName != null ? cmdl.ModelName : "<null>"); ULogger.W("APP", " Override color: {0}", cmdl.IsColorDefined ? string.Format("Yes (RGBA #{0:X2}{1:X2}{2:X2}{3:X2})", cmdl.OverrideColor.R, cmdl.OverrideColor.G, cmdl.OverrideColor.B, cmdl.OverrideColor.A) : "No"); ULogger.W("APP", " Encoder options specified: {0}", cmdl.ModelWriterOptions.Count); ULogger.W("APP", " Create raw meshes: {0}", cmdl.CreateRawMeshes ? "Yes" : "No"); ULogger.W("APP", " Verbose mode: {0}", cmdl.VerboseMode ? "Yes" : "No"); ULogger.W("APP", " Log file: {0}", cmdl.VerboseModeLogFile != null ? cmdl.VerboseModeLogFile.FullName : "<null>"); ULogger.N("APP"); ULogger.W("APP", "Invalid arguments specified: {0}", cmdl.HasInvalidArguments ? "Yes" : "No"); ULogger.N("APP"); ULogger.W("APP", "Input files ({0}):", cmdl.InputFiles.Count()); foreach (var infile in cmdl.InputFiles) { ULogger.W("APP", "'{0}'", infile.FullName); } ULogger.N("APP"); } if (cmdl.HasInvalidArguments && cmdl.ArgumentException != null) { ULogger.X("APP", cmdl.ArgumentException); ULogger.N("APP"); } if (cmdl.HelpMode || cmdl.HasInvalidArguments) { PrintUse(); ULogger.Q(); return; } var msetrdr = new MSetReader(); var msetdmp = new RawDumper(); foreach (var kvp in cmdl.ModelWriterOptions) { cmdl.ModelWriter.Options.Add(kvp.Key, kvp.Value); } var m3dw = cmdl.ModelWriter; var utf8 = new UTF8Encoding(false); try { foreach (var msetf in cmdl.InputFiles) { if (cmdl.VerboseMode) { ULogger.W("MSETLDR", "Loading '{0}'", msetf.FullName); } var mset = msetrdr.Load(msetf); var m3ds = msetrdr.Create3DModels(mset).ToList(); if (cmdl.VerboseMode) { ULogger.W("MSETLDR", "Loaded {0} models", m3ds.Count); } foreach (var m3d in m3ds) { ULogger.W("M3D", "Model '{0}' in file '{1}'", m3d.ModelName, msetf.FullName); if (cmdl.ListModels) { continue; } if (cmdl.ModelName != null && m3d.ModelName != cmdl.ModelName) { continue; } ULogger.W("M3DWRTR", "Extracting '{0}'", m3d.ModelName); var opath = cmdl.OutputDirectory != null ? cmdl.OutputDirectory.FullName : msetf.Directory.FullName; //var msetn = msetf.Name.Substring(0, msetf.Name.Length - msetf.Extension.Length); var msetn = m3d.ModelName; msetn = string.Concat(msetn, m3dw.FileExtension); opath = Path.Combine(opath, msetn); var m3df = new FileInfo(opath); m3dw.WriteModel(m3d, m3df); if (cmdl.CreateRawMeshes) { if (cmdl.VerboseMode) { ULogger.W("M3D RAW", "Creating raw dump"); } opath = string.Concat(opath, ".raw_3d"); var m3drf = new FileInfo(opath); msetdmp.WriteRawMesh(m3d, msetf, m3drf, utf8); } } } } catch (Exception ex) { ULogger.W("APP ERROR", "CRITICAL: ERROR WHILE UNPACKING MSET"); ULogger.X("APP ERROR", ex); } ULogger.W("MSET2", "Conversion completed"); ULogger.Q(); if (Debugger.IsAttached) { Console.ReadKey(); } }
private void WriteInternal(ThreeDModel m3d) { var opts = Program.Options; var usemtl = this.opts.ContainsKey("usemtl") && this.opts["usemtl"] == "true"; if (usemtl && !opts.IsColorDefined) { ULogger.W("OBJWRITE", "usemtl set to true but no override color defined; ignoring..."); } usemtl = usemtl && opts.IsColorDefined; if (!usemtl && opts.IsColorDefined && opts.OverrideColor.A != 255) { ULogger.W("OBJWRITE", "usemtl is not set to true, but override color has Alpha different from 255 -- it won't be written!"); } this.tw.WriteLine("# Converted using MSET Converter by John Cena of PTF"); this.tw.WriteLine("# mset Version: {0}", Program.GetAssemblyVersion()); this.tw.WriteLine("# mset-obj Version: {0}", this.VersionID); this.tw.WriteLine("# "); this.tw.WriteLine("# Model Summary: "); this.tw.WriteLine("# Name: {0}", m3d.ModelName); this.tw.WriteLine("# Vertex Count: {0:#,##0} ", m3d.VertexCount); this.tw.WriteLine("# Face Count: {0:#,##0} ", m3d.FaceCount); this.tw.WriteLine("# "); this.tw.WriteLine("# Writer options:"); foreach (var kvp in this.opts) { this.tw.WriteLine("# {0}={1}", kvp.Key, kvp.Value); } this.tw.WriteLine(); var hasclr = m3d.Colors != null; var hasnorm = m3d.Normals != null; var hastex = m3d.TextureCoordinates != null; var mtlfn = (string)null; if (this.fi != null && usemtl) { mtlfn = this.fi.Name.Substring(0, this.fi.Name.Length - this.fi.Extension.Length); this.tw.WriteLine("mtllib {0}.mtl", mtlfn); } this.tw.WriteLine("o Mset.1"); this.tw.WriteLine(); this.tw.WriteLine("# Vertices"); //foreach (var vert in m3d.Vertices) for (int i = 0; i < m3d.VertexCount; i++) { var vert = m3d.Vertices[i]; var clr = hasclr && !usemtl ? m3d.Colors[i] : default(ThreeDColor); if (hasclr && !usemtl) { this.tw.WriteLine("v {0:0.000000} {1:0.000000} {2:0.000000} {3:0.000000} {4:0.000000} {5:0.000000}", vert.X, vert.Y, vert.Z, clr.RFloat, clr.GFloat, clr.BFloat); } else { this.tw.WriteLine("v {0:0.000000} {1:0.000000} {2:0.000000}", vert.X, vert.Y, vert.Z); } } this.tw.WriteLine(""); if (hasnorm) { this.tw.WriteLine("# Normals"); foreach (var norm in m3d.Normals) { this.tw.WriteLine("vn {0:0.000000} {1:0.000000} {2:0.000000}", norm.X, norm.Y, norm.Z); } this.tw.WriteLine(""); } if (hastex) { this.tw.WriteLine("# Texture Coordinates"); foreach (var texcoord in m3d.TextureCoordinates) { this.tw.WriteLine("vt {0:0.000000} {1:0.000000}", texcoord.U, texcoord.V); } this.tw.WriteLine(""); } this.tw.WriteLine("# Faces"); if (this.fi != null && usemtl) { this.tw.WriteLine("usemtl JCMset"); } //foreach (var face in m3d.Faces) for (int i = 0; i < m3d.FaceCount; i++) { var face = m3d.Faces[i]; if (hastex && hasnorm) { this.tw.WriteLine("f {0:0}/{0:0}/{0:0} {1:0}/{1:0}/{1:0} {2:0}/{2:0}/{2:0}", face.Vertex1 + 1, face.Vertex2 + 1, face.Vertex3 + 1); } else if (hastex && !hasnorm) { this.tw.WriteLine("f {0:0}/{0:0} {1:0}/{1:0} {2:0}/{2:0}", face.Vertex1 + 1, face.Vertex2 + 1, face.Vertex3 + 1); } else if (!hastex && hasnorm) { this.tw.WriteLine("f {0:0}//{0:0} {1:0}//{1:0} {2:0}//{2:0}", face.Vertex1 + 1, face.Vertex2 + 1, face.Vertex3 + 1); } else { this.tw.WriteLine("f {0:0} {1:0} {2:0}", face.Vertex1 + 1, face.Vertex2 + 1, face.Vertex3 + 1); } } this.tw.WriteLine(""); this.tw.Flush(); if (usemtl) { this.WriteMtl(m3d, mtlfn); } }
public IEnumerable <ThreeDModel> Create3DModels(MSetFile file) { var opts = Program.Options; var mzs = file.Data; var mns = new HashSet <string>(); var ns = 0; foreach (var mz in mzs) { ns = Math.Max(ns, mz.Model); } var mzm = new MSetZlibStream[ns + 1, 12]; for (int i = 0; i < mzs.Length; i++) { if (opts.VerboseMode) { ULogger.W("3DMC", "Processing stream {0}", i); } var mz = mzs[i]; int fc = file.Models[mz.Model].FaceCount; var vc = file.Models[mz.Model].VertexCount; var mzdat = new byte[mz.DecompressedLength]; var y = 0; if (mz.CompressedLength == 0 && mz.DecompressedLength > 0) { while (y < mz.DecompressedLength) { y += mz.Data.Read(mzdat, y, mz.DecompressedLength - y); } } else { var mzlib = new ZlibStream(mz.Data, CompressionMode.Decompress); while (y < mz.DecompressedLength) { y += mzlib.Read(mzdat, y, mz.DecompressedLength - y); } } if (mz.IsEncoded) { if (mz.DataStream == 0) { mzdat = DataOperations.DeltaDecompress(mzdat, DataType.I32S, 3, fc); } else if (mz.DataStream <= 4 || mz.DataStream >= 10) { mzdat = DataOperations.DeltaDecompress(mzdat, DataType.F32, 3, vc); } else if (mz.DataStream == 5 || mz.DataStream == 6) { mzdat = DataOperations.DeltaDecompress(mzdat, DataType.F32, 2, vc); } } mz.DataProcessed = mzdat; mzm[mz.Model, mz.DataStream] = mz; } if (file.Models.Length <= 0) { yield break; } for (int i = 0; i < ns + 1; i++) { if (opts.VerboseMode) { ULogger.W("3DMC", "Processing model {0}", i); } var mz_tris = mzm[i, 0]; var mz_verts = mzm[i, 1]; var mz_norms = mzm[i, 2]; var mz_binorms = mzm[i, 3]; var mz_tangents = mzm[i, 4]; var mz_sts = mzm[i, 5]; var mz_sts3 = mzm[i, 6]; var mz_colors = mzm[i, 7]; //var mz_weights = mzm[i, 8]; //var mz_matidxs = mzm[i, 9]; var mz_verts2 = mzm[i, 10]; var mz_norms2 = mzm[i, 11]; int fc = file.Models[mz_tris.Model].FaceCount; var vc = file.Models[mz_tris.Model].VertexCount; // ... var l_tris = mz_tris.DataProcessed != null ? new ThreeDFace[fc] : null; var l_verts = mz_verts.DataProcessed != null ? new ThreeDVertex[vc] : null; var l_norms = mz_norms.DataProcessed != null ? new ThreeDNormal[vc] : null; var l_binorms = mz_binorms.DataProcessed != null ? new ThreeDBinormal[vc] : null; var l_tangents = mz_tangents.DataProcessed != null ? new ThreeDTangent[vc] : null; var l_sts = mz_sts.DataProcessed != null ? new ThreeDTextureCoordinate[vc] : null; var l_sts3 = mz_sts3.DataProcessed != null ? new ThreeDTextureCoordinate[vc] : null; var l_colors = mz_colors.DataProcessed != null ? new ThreeDColor[vc] : null; //var l_weights = mz_matidxs.DataProcessed != null ? new ThreeDBoneWeight[] : null; //var l_matidxs = mz_weights.DataProcessed != null ? new ThreeDBoneMaterials[] : null; var l_verts2 = mz_verts2.DataProcessed != null ? new ThreeDVertex[vc] : null; var l_norms2 = mz_norms2.DataProcessed != null ? new ThreeDNormal[vc] : null; if (l_tris != null) { for (int j = 0; j < fc; j++) { int index = j * 12; var f_v1 = BitConverter.ToInt32(mz_tris.DataProcessed, index + 0); var f_v2 = BitConverter.ToInt32(mz_tris.DataProcessed, index + 4); var f_v3 = BitConverter.ToInt32(mz_tris.DataProcessed, index + 8); //l_tris.Add(new ThreeDFace(f_v1, f_v2, f_v3)); l_tris[j] = new ThreeDFace(f_v1, f_v2, f_v3); } } for (int j = 0; j < vc; j++) { int index1 = j * 12; int index2 = j * 8; int index3 = j * 4; if (l_verts != null) { var v_x = BitConverter.ToSingle(mz_verts.DataProcessed, index1 + 0); var v_y = BitConverter.ToSingle(mz_verts.DataProcessed, index1 + 4); var v_z = BitConverter.ToSingle(mz_verts.DataProcessed, index1 + 8); //l_verts.Add(new ThreeDVertex(v_x, v_y, v_z)); l_verts[j] = new ThreeDVertex(v_x, v_y, v_z); } if (l_norms != null) { var n_x = BitConverter.ToSingle(mz_norms.DataProcessed, index1 + 0); var n_y = BitConverter.ToSingle(mz_norms.DataProcessed, index1 + 4); var n_z = BitConverter.ToSingle(mz_norms.DataProcessed, index1 + 8); //l_norms.Add(new ThreeDNormal(n_x, n_y, n_z)); l_norms[j] = new ThreeDNormal(n_x, n_y, n_z); } if (l_binorms != null) { var b_x = BitConverter.ToSingle(mz_binorms.DataProcessed, index1 + 0); var b_y = BitConverter.ToSingle(mz_binorms.DataProcessed, index1 + 4); var b_z = BitConverter.ToSingle(mz_binorms.DataProcessed, index1 + 8); //l_binorms.Add(new ThreeDBinormal(b_x, b_y, b_z)); l_binorms[j] = new ThreeDBinormal(b_x, b_y, b_z); } if (l_tangents != null) { var t_x = BitConverter.ToSingle(mz_tangents.DataProcessed, index1 + 0); var t_y = BitConverter.ToSingle(mz_tangents.DataProcessed, index1 + 4); var t_z = BitConverter.ToSingle(mz_tangents.DataProcessed, index1 + 8); //l_tangents.Add(new ThreeDTangent(t_x, t_y, t_z)); l_tangents[j] = new ThreeDTangent(t_x, t_y, t_z); } if (l_sts != null) { var t_u = BitConverter.ToSingle(mz_sts.DataProcessed, index2 + 0); var t_v = 1F - BitConverter.ToSingle(mz_sts.DataProcessed, index2 + 4); //l_sts.Add(new ThreeDTextureCoordinate(t_u, t_v)); l_sts[j] = new ThreeDTextureCoordinate(t_u, t_v); } if (l_sts3 != null) { var t_u = BitConverter.ToSingle(mz_sts3.DataProcessed, index2 + 0); var t_v = 1F - BitConverter.ToSingle(mz_sts3.DataProcessed, index2 + 4); //l_sts3.Add(new ThreeDTextureCoordinate(t_u, t_v)); l_sts3[j] = new ThreeDTextureCoordinate(t_u, t_v); } if (l_colors != null) { var c_r = mz_colors.DataProcessed[index3 + 0]; var c_g = mz_colors.DataProcessed[index3 + 1]; var c_b = mz_colors.DataProcessed[index3 + 2]; var c_a = mz_colors.DataProcessed[index3 + 3]; //l_colors.Add(new ThreeDColor(c_r, c_g, c_b, c_a)); l_colors[j] = new ThreeDColor(c_r, c_g, c_b, c_a); } if (l_verts2 != null) { var v_x = BitConverter.ToSingle(mz_verts2.DataProcessed, index1 + 0); var v_y = BitConverter.ToSingle(mz_verts2.DataProcessed, index1 + 4); var v_z = BitConverter.ToSingle(mz_verts2.DataProcessed, index1 + 8); //l_verts2.Add(new ThreeDVertex(v_x, v_y, v_z)); l_verts2[j] = new ThreeDVertex(v_x, v_y, v_z); } if (l_norms2 != null) { var n_x = BitConverter.ToSingle(mz_norms2.DataProcessed, index1 + 0); var n_y = BitConverter.ToSingle(mz_norms2.DataProcessed, index1 + 4); var n_z = BitConverter.ToSingle(mz_norms2.DataProcessed, index1 + 8); //l_norms2.Add(new ThreeDNormal(n_x, n_y, n_z)); l_norms2[j] = new ThreeDNormal(n_x, n_y, n_z); } } var mname = this.GenerateUniqueName(mns, mz_tris.ModelName); mns.Add(mname); var m3d = new ThreeDModel { ModelName = mname, VertexCount = vc, FaceCount = fc, Faces = l_tris != null?Array.AsReadOnly(l_tris) : null, Vertices = l_verts != null?Array.AsReadOnly(l_verts) : null, Normals = l_norms != null?Array.AsReadOnly(l_norms) : null, Binormals = l_binorms != null?Array.AsReadOnly(l_binorms) : null, Tangents = l_tangents != null?Array.AsReadOnly(l_tangents) : null, TextureCoordinates = l_sts != null?Array.AsReadOnly(l_sts) : null, TextureCoordinates3 = l_sts3 != null?Array.AsReadOnly(l_sts3) : null, Colors = l_colors != null?Array.AsReadOnly(l_colors) : null, // // Vertices2 = l_verts2 != null?Array.AsReadOnly(l_verts2) : null, Normals2 = l_norms2 != null?Array.AsReadOnly(l_norms2) : null }; yield return(m3d); } }