private void BuildNodeList() { NJS_OBJECT[] objs = editedHierarchy.GetObjects(); for (int i = 0; i < objs.Length; i++) { comboBoxNode.Items.Add(i.ToString() + ": " + objs[i].Name.ToString()); } }
private static string GetModel(byte[] fc, int address, uint key, string fn, List <string> nodenames, Dictionary <string, KeyValuePair <string, NJS_OBJECT> > modelfiles) { string name = null; int ptr3 = fc.GetPointer(address, key); if (ptr3 != 0) { name = $"object_{ptr3:X8}"; if (!nodenames.Contains(name)) { NJS_OBJECT obj = new NJS_OBJECT(fc, ptr3, key, ModelFormat.Chunk); name = obj.Name; List <string> names = new List <string>(obj.GetObjects().Select((o) => o.Name)); foreach (string s in names) { if (modelfiles.ContainsKey(s)) { modelfiles.Remove(s); } } nodenames.AddRange(names); modelfiles.Add(obj.Name, new KeyValuePair <string, NJS_OBJECT>(fn, obj)); } } return(name); }
public StartPosItem(NJS_OBJECT model, string textures, float offset, Vertex position, int yrot, Device dev, EditorItemSelection selectionManager, bool Weight = false) : base(selectionManager) { Model = model; hasWeight = Weight; model.ProcessVertexData(); if (hasWeight) { Meshes = model.ProcessWeightedModel().ToArray(); } else { NJS_OBJECT[] models = model.GetObjects(); Meshes = new Mesh[models.Length]; for (int i = 0; i < models.Length; i++) { if (models[i].Attach != null) { Meshes[i] = models[i].Attach.CreateD3DMesh(); } } } texture = textures; this.offset = offset; Position = position; YRotation = yrot; }
public static Mesh[] GetMeshes(NJS_OBJECT model, Device dev) { model.ProcessVertexData(); NJS_OBJECT[] models = model.GetObjects(); Mesh[] Meshes = new Mesh[models.Length]; for (int i = 0; i < models.Length; i++) if (models[i].Attach != null) Meshes[i] = models[i].Attach.CreateD3DMesh(dev); return Meshes; }
public static Mesh[] GetMeshes(NJS_OBJECT model) { model.ProcessVertexData(); NJS_OBJECT[] models = model.GetObjects(); Mesh[] Meshes = new Mesh[models.Length]; for (int i = 0; i < models.Length; i++) { if (models[i].Attach != null) { Meshes[i] = models[i].Attach.CreateD3DMesh(); } } return(Meshes); }
public StartPosItem(NJS_OBJECT model, string textures, float offset, Vertex position, int yrot, Device dev, EditorItemSelection selectionManager) : base(selectionManager) { Model = model; model.ProcessVertexData(); NJS_OBJECT[] models = model.GetObjects(); Meshes = new Mesh[models.Length]; for (int i = 0; i < models.Length; i++) if (models[i].Attach != null) Meshes[i] = models[i].Attach.CreateD3DMesh(dev); texture = textures; this.offset = offset; Position = position; YRotation = yrot; }
public static NJS_OBJECT GetModel(byte[] file, int address, uint imageBase, Dictionary <string, NJS_OBJECT> models) { NJS_OBJECT result = null; int ptr = file.GetPointer(address, imageBase); if (ptr != 0) { result = new NJS_OBJECT(file, ptr, imageBase, ModelFormat.Chunk); if (models.ContainsKey(result.Name)) { result = models[result.Name]; } else { foreach (NJS_OBJECT obj in result.GetObjects()) { models[obj.Name] = obj; } } } return(result); }
static void Main(string[] args) { string dir = Environment.CurrentDirectory; try { Queue <string> argq = new Queue <string>(args); if (argq.Count > 0 && argq.Peek().Equals("/be", StringComparison.OrdinalIgnoreCase)) { ByteConverter.BigEndian = true; argq.Dequeue(); } string mdlfilename; if (argq.Count > 0) { mdlfilename = argq.Dequeue(); Console.WriteLine("File: {0}", mdlfilename); } else { Console.Write("File: "); mdlfilename = Console.ReadLine(); } mdlfilename = Path.GetFullPath(mdlfilename); string[] anifilenames = new string[argq.Count]; for (int j = 0; j < anifilenames.Length; j++) { Console.WriteLine("Animations: {0}", argq.Peek()); anifilenames[j] = Path.GetFullPath(argq.Dequeue()); } Environment.CurrentDirectory = Path.GetDirectoryName(mdlfilename); byte[] mdlfile = File.ReadAllBytes(mdlfilename); if (Path.GetExtension(mdlfilename).Equals(".prs", StringComparison.OrdinalIgnoreCase)) { mdlfile = FraGag.Compression.Prs.Decompress(mdlfile); } Directory.CreateDirectory(Path.GetFileNameWithoutExtension(mdlfilename)); int address = 0; int i = ByteConverter.ToInt32(mdlfile, address); SortedDictionary <int, int> modeladdrs = new SortedDictionary <int, int>(); while (i != -1) { modeladdrs[i] = ByteConverter.ToInt32(mdlfile, address + 4); address += 8; i = ByteConverter.ToInt32(mdlfile, address); } Dictionary <int, NJS_OBJECT> models = new Dictionary <int, NJS_OBJECT>(); Dictionary <int, string> modelnames = new Dictionary <int, string>(); List <string> partnames = new List <string>(); foreach (KeyValuePair <int, int> item in modeladdrs) { NJS_OBJECT obj = new NJS_OBJECT(mdlfile, item.Value, 0, ModelFormat.Chunk); modelnames[item.Key] = obj.Name; if (!partnames.Contains(obj.Name)) { List <string> names = new List <string>(obj.GetObjects().Select((o) => o.Name)); foreach (int idx in modelnames.Where(a => names.Contains(a.Value)).Select(a => a.Key)) { models.Remove(idx); } models[item.Key] = obj; partnames.AddRange(names); } } Dictionary <int, string> animfns = new Dictionary <int, string>(); Dictionary <int, Animation> anims = new Dictionary <int, Animation>(); foreach (string anifilename in anifilenames) { byte[] anifile = File.ReadAllBytes(anifilename); if (Path.GetExtension(anifilename).Equals(".prs", StringComparison.OrdinalIgnoreCase)) { anifile = FraGag.Compression.Prs.Decompress(anifile); } Directory.CreateDirectory(Path.GetFileNameWithoutExtension(anifilename)); address = 0; i = ByteConverter.ToInt16(anifile, address); while (i != -1) { anims[i] = new Animation(anifile, ByteConverter.ToInt32(anifile, address + 4), 0, ByteConverter.ToInt16(anifile, address + 2)); animfns[i] = Path.Combine(Path.GetFileNameWithoutExtension(anifilename), i.ToString(NumberFormatInfo.InvariantInfo) + ".saanim"); address += 8; i = ByteConverter.ToInt16(anifile, address); } } foreach (KeyValuePair <int, NJS_OBJECT> model in models) { List <string> animlist = new List <string>(); foreach (KeyValuePair <int, Animation> anim in anims) { if (model.Value.CountAnimated() == anim.Value.ModelParts) { animlist.Add("../" + animfns[anim.Key]); } } ModelFile.CreateFile(Path.Combine(Path.GetFileNameWithoutExtension(mdlfilename), model.Key.ToString(NumberFormatInfo.InvariantInfo) + ".sa2mdl"), model.Value, animlist.ToArray(), null, null, null, "splitMDL", null, ModelFormat.Chunk); } IniSerializer.Serialize(modelnames, new IniCollectionSettings(IniCollectionMode.IndexOnly), Path.Combine(Path.GetFileNameWithoutExtension(mdlfilename), Path.GetFileNameWithoutExtension(mdlfilename) + ".ini")); foreach (KeyValuePair <int, Animation> anim in anims) { anim.Value.Save(animfns[anim.Key]); } } finally { Environment.CurrentDirectory = dir; } }
static byte[] GetSections(NJS_OBJECT mdl) { List <byte> result = new List <byte>(); NJS_OBJECT[] objs = mdl.GetObjects(); int[] modeladdr = new int[objs.Length]; int[] objaddr = new int[objs.Length]; int[] mataddr = new int[objs.Length]; int[] meshaddr = new int[objs.Length]; List <int>[] polyaddr = new List <int> [objs.Length]; List <int>[] uvaddr = new List <int> [objs.Length]; int[] vertaddr = new int[objs.Length]; int[] normaddr = new int[objs.Length]; int currentaddr = 0; // Write all polys int polysection = currentaddr; currentaddr += 8; short polycount = 0; for (int m = objs.Length - 1; m > -1; m--) { polyaddr[m] = new List <int>(); if (objs[m].Attach != null) { BasicAttach att = (BasicAttach)objs[m].Attach; if (att.Mesh != null) { foreach (NJS_MESHSET mesh in att.Mesh) { polyaddr[m].Add(result.Count); //Console.WriteLine("Polyaddr in model {0} : {1}", m, currentaddr.ToString("X")); foreach (Strip poly in mesh.Poly) { if (poly.Reversed) { result.AddRange(BitConverter.GetBytes((short)(0x8000 | (poly.Indexes.Length & 0x7FFF)))); } else { result.AddRange(BitConverter.GetBytes((short)(poly.Indexes.Length & 0x7FFF))); } polycount++; for (int ind = 0; ind < poly.Indexes.Length; ind++) { result.AddRange(BitConverter.GetBytes(poly.Indexes[ind])); polycount++; } } currentaddr = result.Count; } } } } if ((polycount * 2) % 4 != 0) { int res = polycount * 2; do { result.Add(0xCD); res++; }while (res % 4 != 0); } currentaddr = result.Count; result.InsertRange(polysection, BitConverter.GetBytes((uint)0)); result.InsertRange(polysection + 4, BitConverter.GetBytes((uint)polycount * 2)); // Write all vertices int vertsection = currentaddr; currentaddr += 8; short vertexcount = 0; for (int m = objs.Length - 1; m > -1; m--) { if (objs[m].Attach != null) { BasicAttach att = (BasicAttach)objs[m].Attach; vertaddr[m] = currentaddr; if (att.Vertex != null) { for (int v = 0; v < att.Vertex.Length; v++) { result.AddRange(BitConverter.GetBytes(att.Vertex[v].X)); result.AddRange(BitConverter.GetBytes(att.Vertex[v].Y)); result.AddRange(BitConverter.GetBytes(att.Vertex[v].Z)); vertexcount++; } } currentaddr = result.Count; } } result.InsertRange(vertsection + 8, BitConverter.GetBytes((uint)1)); result.InsertRange(vertsection + 4 + 8, BitConverter.GetBytes((uint)vertexcount * 12)); // Write all normals int normsection = currentaddr; currentaddr += 8; short normalcount = 0; for (int m = objs.Length - 1; m > -1; m--) { if (objs[m].Attach != null) { BasicAttach att = (BasicAttach)objs[m].Attach; normaddr[m] = currentaddr; if (att.Vertex != null) { for (int v = 0; v < att.Vertex.Length; v++) { result.AddRange(BitConverter.GetBytes(att.Normal[v].X)); result.AddRange(BitConverter.GetBytes(att.Normal[v].Y)); result.AddRange(BitConverter.GetBytes(att.Normal[v].Z)); normalcount++; } } currentaddr = result.Count; } } result.InsertRange(normsection + 8, BitConverter.GetBytes((uint)2)); result.InsertRange(normsection + 4 + 8, BitConverter.GetBytes((uint)normalcount * 12)); // Write all UVs int uvsection = currentaddr; currentaddr += 8; short uvcount = 0; for (int m = objs.Length - 1; m > -1; m--) { uvaddr[m] = new List <int>(); if (objs[m].Attach != null) { BasicAttach att = (BasicAttach)objs[m].Attach; foreach (NJS_MESHSET mesh in att.Mesh) { uvaddr[m].Add(currentaddr); if (mesh.UV != null) { for (int uv = 0; uv < mesh.UV.Length; uv++) { result.AddRange(BitConverter.GetBytes((short)(mesh.UV[uv].U * 255f))); result.AddRange(BitConverter.GetBytes((short)(mesh.UV[uv].V * 255f))); uvcount++; } } currentaddr = result.Count; } } } result.InsertRange(uvsection + 8, BitConverter.GetBytes((uint)3)); result.InsertRange(uvsection + 4 + 8, BitConverter.GetBytes((uint)uvcount * 4)); // Write materials int matsection = currentaddr; currentaddr += 8; short matcount = 0; for (int m = objs.Length - 1; m > -1; m--) { if (objs[m].Attach != null) { BasicAttach att = (BasicAttach)objs[m].Attach; if (att.Material != null && att.Material.Count > 0) { mataddr[m] = result.Count; foreach (NJS_MATERIAL mat in att.Material) { result.AddRange(BitConverter.GetBytes(mat.DiffuseColor.ToArgb())); result.AddRange(BitConverter.GetBytes(mat.SpecularColor.ToArgb())); result.AddRange(BitConverter.GetBytes(mat.Exponent)); result.AddRange(BitConverter.GetBytes(mat.TextureID)); result.AddRange(BitConverter.GetBytes(mat.Flags)); matcount++; currentaddr = result.Count; } } } } result.InsertRange(matsection + 8, BitConverter.GetBytes((short)4)); result.InsertRange(matsection + 2 + 8, BitConverter.GetBytes(matcount)); result.InsertRange(matsection + 4 + 8, BitConverter.GetBytes((uint)matcount * 20)); // Write meshsets short meshcount = 0; int meshsection = currentaddr; currentaddr += 8; for (int m = objs.Length - 1; m > -1; m--) { if (objs[m].Attach != null) { BasicAttach att = (BasicAttach)objs[m].Attach; if (att.Material != null && att.Material.Count > 0) { int[] polys = polyaddr[m].ToArray(); int[] uvs = uvaddr[m].ToArray(); meshaddr[m] = result.Count; NJS_MESHSET[] meshes = att.Mesh.ToArray(); for (int mesh = 0; mesh < meshes.Length; mesh++) { result.AddRange(BitConverter.GetBytes((ushort)((meshes[mesh].MaterialID & 0x3FFF) | ((int)meshes[mesh].PolyType << 0xE)))); result.AddRange(BitConverter.GetBytes((ushort)meshes[mesh].Poly.Count)); result.AddRange(BitConverter.GetBytes((uint)polys[mesh] + 8)); result.AddRange(BitConverter.GetBytes((uint)0)); //polyattr result.AddRange(BitConverter.GetBytes((uint)0)); //polynormal pointer result.AddRange(BitConverter.GetBytes((uint)0)); //vcolor pointer if (meshes[mesh].UV != null && meshes[mesh].UV.Length > 0) { result.AddRange(BitConverter.GetBytes((uint)uvs[mesh] + 8)); } else { result.AddRange(BitConverter.GetBytes((uint)0)); } meshcount++; } } currentaddr = result.Count; } } result.InsertRange(meshsection + 8, BitConverter.GetBytes((ushort)5)); result.InsertRange(meshsection + 2 + 8, BitConverter.GetBytes(meshcount)); result.InsertRange(meshsection + 4 + 8, BitConverter.GetBytes((uint)meshcount * 24)); // Write models short modelcount = 0; int modelsection = currentaddr; currentaddr += 8; for (int m = objs.Length - 1; m > -1; m--) { if (objs[m].Attach != null) { modeladdr[m] = currentaddr; BasicAttach att = (BasicAttach)objs[m].Attach; result.AddRange(BitConverter.GetBytes((uint)vertaddr[m] + 8)); result.AddRange(BitConverter.GetBytes((uint)normaddr[m] + 8)); result.AddRange(BitConverter.GetBytes((uint)att.Vertex.Length)); result.AddRange(BitConverter.GetBytes((uint)meshaddr[m] + 8)); result.AddRange(BitConverter.GetBytes((uint)mataddr[m] + 8)); result.AddRange(BitConverter.GetBytes((ushort)att.Mesh.Count)); result.AddRange(BitConverter.GetBytes((ushort)att.Material.Count)); result.AddRange(BitConverter.GetBytes(att.Bounds.Center.X)); result.AddRange(BitConverter.GetBytes(att.Bounds.Center.Y)); result.AddRange(BitConverter.GetBytes(att.Bounds.Center.Z)); result.AddRange(BitConverter.GetBytes(att.Bounds.Radius)); modelcount++; currentaddr = result.Count; } } result.InsertRange(modelsection + 8, BitConverter.GetBytes((ushort)6)); result.InsertRange(modelsection + 2 + 8, BitConverter.GetBytes((ushort)modelcount)); result.InsertRange(modelsection + 4 + 8, BitConverter.GetBytes((uint)(40 * modelcount))); // Write objects int objectsection = currentaddr; currentaddr += 8; for (int m = objs.Length - 1; m > -1; m--) { objaddr[m] = currentaddr; result.AddRange(BitConverter.GetBytes((int)objs[m].GetFlags())); if (objs[m].Attach != null) { result.AddRange(BitConverter.GetBytes((uint)modeladdr[m] + 8)); } else { result.AddRange(BitConverter.GetBytes((uint)0)); } result.AddRange(BitConverter.GetBytes(objs[m].Position.X)); result.AddRange(BitConverter.GetBytes(objs[m].Position.Y)); result.AddRange(BitConverter.GetBytes(objs[m].Position.Z)); result.AddRange(BitConverter.GetBytes(objs[m].Rotation.X)); result.AddRange(BitConverter.GetBytes(objs[m].Rotation.Y)); result.AddRange(BitConverter.GetBytes(objs[m].Rotation.Z)); result.AddRange(BitConverter.GetBytes(objs[m].Scale.X)); result.AddRange(BitConverter.GetBytes(objs[m].Scale.Y)); result.AddRange(BitConverter.GetBytes(objs[m].Scale.Z)); if (objs[m].Children != null && objs[m].Children.Count > 0) { result.AddRange(BitConverter.GetBytes((uint)(objaddr[FindModelIndex(objs[m].Children[0], objs)]) + 8)); //child } else { result.AddRange(BitConverter.GetBytes((uint)0)); } if (objs[m].Sibling != null) { result.AddRange(BitConverter.GetBytes((uint)(objaddr[FindModelIndex(objs[m].Sibling, objs)]) + 8)); //sibling } else { result.AddRange(BitConverter.GetBytes((uint)0)); } currentaddr = result.Count; } result.InsertRange(objectsection + 8, BitConverter.GetBytes((ushort)7)); result.InsertRange(objectsection + 2 + 8, BitConverter.GetBytes((ushort)objs.Length)); result.InsertRange(objectsection + 4 + 8, BitConverter.GetBytes((uint)objs.Length * 52)); return(result.ToArray()); }
static void Main(string[] args) { string basemdlname; if (args.Length > 0) { basemdlname = args[0]; } else { Console.Write("Base Model: "); basemdlname = Console.ReadLine().Trim('"'); } string fext = Path.GetExtension(basemdlname); ModelFile modelFile = new ModelFile(basemdlname); ModelFormat fmt = modelFile.Format; NJS_OBJECT basemdl = modelFile.Model; string mtnname; if (args.Length > 1) { mtnname = args[1]; } else { Console.Write("Motion: "); mtnname = Console.ReadLine().Trim('"'); } NJS_MOTION mtn = NJS_MOTION.Load(mtnname, basemdl.CountMorph()); string outdir; if (args.Length > 2) { outdir = args[2]; } else { outdir = Path.Combine(Path.GetDirectoryName(Path.GetFullPath(mtnname)), Path.GetFileNameWithoutExtension(mtnname)); } Directory.CreateDirectory(outdir); MTNInfo inf = new MTNInfo() { ModelFormat = fmt, Name = mtn.Name, Frames = mtn.Frames, InterpolationMode = mtn.InterpolationMode }; IniSerializer.Serialize(inf, Path.Combine(outdir, Path.ChangeExtension(Path.GetFileName(mtnname), ".ini"))); NJS_OBJECT[] objs = basemdl.GetObjects().Where(a => a.Morph).ToArray(); for (int frame = 0; frame < mtn.Frames; frame++) { if (!mtn.Models.Any(a => a.Value.Vertex.ContainsKey(frame))) { continue; } foreach ((int idx, AnimModelData amd) in mtn.Models) { if (amd.Vertex.ContainsKey(frame)) { Vertex[] verts = amd.Vertex[frame]; amd.Normal.TryGetValue(frame, out Vertex[] norms); switch (objs[idx].Attach) { case BasicAttach batt: for (int i = 0; i < Math.Min(verts.Length, batt.Vertex.Length); i++) { batt.Vertex[i] = verts[i]; if (norms != null && batt.Normal != null) { batt.Normal[i] = norms[i]; } } break; case ChunkAttach catt: if (catt.Vertex == null) { continue; } int vcnt = catt.Vertex.Sum(a => a.VertexCount); int ci = 0; int vi = 0; for (int i = 0; i < Math.Min(verts.Length, vcnt); i++) { catt.Vertex[ci].Vertices[vi] = verts[i]; if (norms != null && catt.Vertex[ci].Normals != null) { catt.Vertex[ci].Normals[vi] = norms[i]; } if (++vi >= catt.Vertex[ci].VertexCount) { ++ci; vi = 0; } } break; } } } ModelFile.CreateFile(Path.Combine(outdir, $"{frame}{fext}"), basemdl, null, null, null, null, fmt); } }
private void LoadFile(string filename) { loaded = false; Environment.CurrentDirectory = Path.GetDirectoryName(filename); timer1.Stop(); modelFile = null; animation = null; animations = null; animnum = -1; animframe = 0; if (ModelFile.CheckModelFile(filename)) { modelFile = new ModelFile(filename); outfmt = modelFile.Format; model = modelFile.Model; animations = new Animation[modelFile.Animations.Count]; modelFile.Animations.CopyTo(animations, 0); } else { byte[] file = File.ReadAllBytes(filename); if (Path.GetExtension(filename).Equals(".prs", StringComparison.OrdinalIgnoreCase)) { file = FraGag.Compression.Prs.Decompress(file); } SA_Tools.ByteConverter.BigEndian = false; uint?baseaddr = SA_Tools.HelperFunctions.SetupEXE(ref file); if (baseaddr.HasValue) { modelinfo.numericUpDown2.Value = baseaddr.Value; modelinfo.numericUpDown2.Enabled = false; modelinfo.ComboBox1.Enabled = false; modelinfo.checkBox2.Checked = modelinfo.checkBox2.Enabled = false; LoadBinFile(file); } else if (Path.GetExtension(filename).Equals(".rel", StringComparison.OrdinalIgnoreCase)) { SA_Tools.ByteConverter.BigEndian = true; SA_Tools.HelperFunctions.FixRELPointers(file); modelinfo.numericUpDown2.Value = 0; modelinfo.numericUpDown2.Enabled = false; modelinfo.ComboBox1.Enabled = false; modelinfo.checkBox2.Enabled = false; modelinfo.checkBox2.Checked = true; LoadBinFile(file); } else { using (FileTypeDialog ftd = new FileTypeDialog()) { if (ftd.ShowDialog(this) != DialogResult.OK) { return; } if (ftd.typBinary.Checked) { modelinfo.numericUpDown2.Enabled = true; modelinfo.ComboBox1.Enabled = true; modelinfo.checkBox2.Enabled = true; LoadBinFile(file); } else if (ftd.typSA2MDL.Checked | ftd.typSA2BMDL.Checked) { ModelFormat fmt = outfmt = ModelFormat.Chunk; ByteConverter.BigEndian = ftd.typSA2BMDL.Checked; using (SA2MDLDialog dlg = new SA2MDLDialog()) { int address = 0; SortedDictionary <int, NJS_OBJECT> sa2models = new SortedDictionary <int, NJS_OBJECT>(); int i = ByteConverter.ToInt32(file, address); while (i != -1) { sa2models.Add(i, new NJS_OBJECT(file, ByteConverter.ToInt32(file, address + 4), 0, fmt)); address += 8; i = ByteConverter.ToInt32(file, address); } foreach (KeyValuePair <int, NJS_OBJECT> item in sa2models) { dlg.modelChoice.Items.Add(item.Key + ": " + item.Value.Name); } dlg.ShowDialog(this); i = 0; foreach (KeyValuePair <int, NJS_OBJECT> item in sa2models) { if (i == dlg.modelChoice.SelectedIndex) { model = item.Value; break; } i++; } if (dlg.checkBox1.Checked) { using (OpenFileDialog anidlg = new OpenFileDialog() { DefaultExt = "bin", Filter = "Motion Files|*MTN.BIN;*MTN.PRS|All Files|*.*" }) { if (anidlg.ShowDialog(this) == DialogResult.OK) { byte[] anifile = File.ReadAllBytes(anidlg.FileName); if (Path.GetExtension(anidlg.FileName).Equals(".prs", StringComparison.OrdinalIgnoreCase)) { anifile = FraGag.Compression.Prs.Decompress(anifile); } address = 0; SortedDictionary <int, Animation> anis = new SortedDictionary <int, Animation>(); i = ByteConverter.ToInt32(file, address); while (i != -1) { anis.Add(i, new Animation(file, ByteConverter.ToInt32(file, address + 4), 0, model.CountAnimated())); address += 8; i = ByteConverter.ToInt32(file, address); } animations = new List <Animation>(anis.Values).ToArray(); } } } } } } } } model.ProcessVertexData(); NJS_OBJECT[] models = model.GetObjects(); meshes = new Mesh[models.Length]; for (int i = 0; i < models.Length; i++) { if (models[i].Attach != null) { try { meshes[i] = models[i].Attach.CreateD3DMesh(d3ddevice); } catch { } } } treeView1.Nodes.Clear(); nodeDict = new Dictionary <NJS_OBJECT, TreeNode>(); AddTreeNode(model, treeView1.Nodes); loaded = saveToolStripMenuItem.Enabled = exportToolStripMenuItem.Enabled = findToolStripMenuItem.Enabled = true; selectedObject = model; SelectedItemChanged(); }
static void Main(string[] args) { string path; if (args.Length > 0) { path = args[0]; } else { Console.Write("Path: "); path = Console.ReadLine().Trim('"'); } path = Path.GetFullPath(path); if (path.EndsWith(".ini")) { path = Path.GetDirectoryName(path); } string mtnfn = new DirectoryInfo(path).Name; MTNInfo info = IniSerializer.Deserialize <MTNInfo>(Path.Combine(path, mtnfn + ".ini")); string fext = null; switch (info.ModelFormat) { case ModelFormat.Basic: case ModelFormat.BasicDX: fext = "*.sa1mdl"; break; case ModelFormat.Chunk: fext = "*.sa2mdl"; break; case ModelFormat.GC: fext = "*.sa2bmdl"; break; } SortedDictionary <int, NJS_OBJECT> mdls = new SortedDictionary <int, NJS_OBJECT>(); foreach (string fn in Directory.EnumerateFiles(path, fext)) { if (int.TryParse(Path.GetFileNameWithoutExtension(fn), out int i) && i >= 0 && i < info.Frames) { mdls[i] = new ModelFile(fn).Model; } } NJS_OBJECT first = mdls.First().Value; int nodecnt = first.CountMorph(); int[] vcnt = new int[nodecnt]; ushort[][] polys = new ushort[nodecnt][]; NJS_OBJECT[] nodes = first.GetObjects().Where(a => a.Morph).ToArray(); for (int i = 0; i < nodecnt; i++) { switch (nodes[i].Attach) { case BasicAttach batt: vcnt[i] = batt.Vertex.Length; List <ushort> plist = new List <ushort>(); foreach (NJS_MESHSET mesh in batt.Mesh) { foreach (Poly p in mesh.Poly) { plist.AddRange(p.Indexes); } } polys[i] = plist.ToArray(); break; case ChunkAttach catt: if (catt.Vertex != null) { vcnt[i] = catt.Vertex.Sum(a => a.VertexCount); } plist = new List <ushort>(); foreach (PolyChunkStrip pcs in catt.Poly.OfType <PolyChunkStrip>()) { foreach (PolyChunkStrip.Strip s in pcs.Strips) { plist.AddRange(s.Indexes); } } polys[i] = plist.ToArray(); break; } } NJS_MOTION mtn = new NJS_MOTION() { Name = info.Name, Frames = info.Frames, InterpolationMode = info.InterpolationMode, ModelParts = nodecnt }; foreach ((int frame, NJS_OBJECT mdl) in mdls) { NJS_OBJECT[] nodes2 = mdl.GetObjects().Where(a => a.Morph).ToArray(); if (nodes2.Length != nodecnt) { Console.WriteLine("Warning: Model {0} skeleton does not match first file!", frame); if (nodes2.Length > mtn.ModelParts) { mtn.ModelParts = nodes2.Length; } } for (int i = 0; i < nodes2.Length; i++) { switch (nodes2[i].Attach) { case BasicAttach batt: if (batt.Vertex.Length != vcnt[i]) { Console.WriteLine("Warning: Model {0} node {1} vertex count does not match first file!", frame, i); } AnimModelData amd; if (!mtn.Models.TryGetValue(i, out amd)) { amd = new AnimModelData() { VertexName = mtn.MdataName + "_vtx_" + i, NormalName = mtn.MdataName + "_nor_" + i }; mtn.Models[i] = amd; } amd.Vertex[frame] = batt.Vertex; if (batt.Normal != null) { amd.Normal[frame] = batt.Normal; } List <ushort> plist = new List <ushort>(); foreach (NJS_MESHSET mesh in batt.Mesh) { foreach (Poly p in mesh.Poly) { plist.AddRange(p.Indexes); } } if (!polys[i].SequenceEqual(plist)) { Console.WriteLine("Warning: Model {0} node {1} poly data does not match first file!", frame, i); } break; case ChunkAttach catt: if (catt.Vertex != null) { if (catt.Vertex.Sum(a => a.VertexCount) != vcnt[i]) { Console.WriteLine("Warning: Model {0} node {1} vertex count does not match first file!", frame, i); } if (!mtn.Models.TryGetValue(i, out amd)) { amd = new AnimModelData() { VertexName = mtn.MdataName + "_vtx_" + i, NormalName = mtn.MdataName + "_nor_" + i }; mtn.Models[i] = amd; } amd.Vertex[frame] = catt.Vertex.SelectMany(a => a.Vertices).ToArray(); if (catt.Vertex.All(a => a.Normals != null)) { amd.Normal[frame] = catt.Vertex.SelectMany(a => a.Normals).ToArray(); } } plist = new List <ushort>(); foreach (PolyChunkStrip pcs in catt.Poly.OfType <PolyChunkStrip>()) { foreach (PolyChunkStrip.Strip s in pcs.Strips) { plist.AddRange(s.Indexes); } } polys[i] = plist.ToArray(); break; } } } foreach ((int _, AnimModelData amd) in mtn.Models) { amd.VertexItemName = Enumerable.Range(0, amd.Vertex.Count).Select(a => amd.VertexName + "_" + a).ToArray(); if (amd.Normal.Count > 0) { amd.NormalItemName = Enumerable.Range(0, amd.Normal.Count).Select(a => amd.NormalName + "_" + a).ToArray(); } } mtn.Save(Path.Combine(path, $"{mtnfn}.saanim")); }
public static void Split(bool isBigEndian, string filePath, string outputFolder, string[] animationPaths) { string dir = Environment.CurrentDirectory; try { if (outputFolder[outputFolder.Length - 1] != '/') { outputFolder = string.Concat(outputFolder, "/"); } ByteConverter.BigEndian = isBigEndian; // get file name, read it from the console if nothing string mdlfilename = filePath; mdlfilename = Path.GetFullPath(mdlfilename); // look through the argumetns for animationfiles string[] anifilenames = animationPaths; // load model file Environment.CurrentDirectory = (outputFolder.Length != 0) ? outputFolder : Path.GetDirectoryName(mdlfilename); byte[] mdlfile = File.ReadAllBytes(mdlfilename); if (Path.GetExtension(mdlfilename).Equals(".prs", StringComparison.OrdinalIgnoreCase)) { mdlfile = FraGag.Compression.Prs.Decompress(mdlfile); } Directory.CreateDirectory(Path.GetFileNameWithoutExtension(mdlfilename)); // getting model pointers int address = 0; int i = ByteConverter.ToInt32(mdlfile, address); SortedDictionary <int, int> modeladdrs = new SortedDictionary <int, int>(); while (i != -1) { modeladdrs[i] = ByteConverter.ToInt32(mdlfile, address + 4); address += 8; i = ByteConverter.ToInt32(mdlfile, address); } // load models from pointer list Dictionary <int, NJS_OBJECT> models = new Dictionary <int, NJS_OBJECT>(); Dictionary <int, string> modelnames = new Dictionary <int, string>(); List <string> partnames = new List <string>(); foreach (KeyValuePair <int, int> item in modeladdrs) { NJS_OBJECT obj = new NJS_OBJECT(mdlfile, item.Value, 0, ModelFormat.Chunk); modelnames[item.Key] = obj.Name; if (!partnames.Contains(obj.Name)) { List <string> names = new List <string>(obj.GetObjects().Select((o) => o.Name)); foreach (int idx in modelnames.Where(a => names.Contains(a.Value)).Select(a => a.Key)) { models.Remove(idx); } models[item.Key] = obj; partnames.AddRange(names); } } // load animations Dictionary <int, string> animfns = new Dictionary <int, string>(); Dictionary <int, NJS_MOTION> anims = new Dictionary <int, NJS_MOTION>(); foreach (string anifilename in anifilenames) { Dictionary <int, int> processedanims = new Dictionary <int, int>(); Dictionary <int, string> ini = new Dictionary <int, string>(); byte[] anifile = File.ReadAllBytes(anifilename); if (Path.GetExtension(anifilename).Equals(".prs", StringComparison.OrdinalIgnoreCase)) { anifile = FraGag.Compression.Prs.Decompress(anifile); } Directory.CreateDirectory(Path.GetFileNameWithoutExtension(anifilename)); address = 0; i = ByteConverter.ToInt16(anifile, address); while (i != -1) { int aniaddr = ByteConverter.ToInt32(anifile, address + 4); if (!processedanims.ContainsKey(aniaddr)) { anims[i] = new NJS_MOTION(anifile, ByteConverter.ToInt32(anifile, address + 4), 0, ByteConverter.ToInt16(anifile, address + 2)); animfns[i] = Path.Combine(Path.GetFileNameWithoutExtension(anifilename), i.ToString(NumberFormatInfo.InvariantInfo) + ".saanim"); anims[i].Save(animfns[i]); processedanims[aniaddr] = i; } ini[i] = "animation_" + aniaddr.ToString("X8"); address += 8; i = ByteConverter.ToInt16(anifile, address); } IniSerializer.Serialize(ini, new IniCollectionSettings(IniCollectionMode.IndexOnly), Path.Combine(Path.GetFileNameWithoutExtension(anifilename), Path.GetFileNameWithoutExtension(anifilename) + ".ini")); } // save output model files foreach (KeyValuePair <int, NJS_OBJECT> model in models) { List <string> animlist = new List <string>(); foreach (KeyValuePair <int, NJS_MOTION> anim in anims) { if (model.Value.CountAnimated() == anim.Value.ModelParts) { string rel = animfns[anim.Key].Replace(outputFolder, string.Empty); if (rel.Length > 1 && rel[1] != ':') { rel = "../" + rel; } animlist.Add(rel); } } ModelFile.CreateFile(Path.Combine(Path.GetFileNameWithoutExtension(mdlfilename), model.Key.ToString(NumberFormatInfo.InvariantInfo) + ".sa2mdl"), model.Value, animlist.ToArray(), null, null, null, null, ModelFormat.Chunk); } // save ini file IniSerializer.Serialize(modelnames, new IniCollectionSettings(IniCollectionMode.IndexOnly), Path.Combine(Path.GetFileNameWithoutExtension(mdlfilename), Path.GetFileNameWithoutExtension(mdlfilename) + ".ini")); } finally { Environment.CurrentDirectory = dir; } }