public GeoAnimData(byte[] file, int address, uint imageBase, LandTableFormat format, Dictionary <int, string> labels, Dictionary <int, Attach> attaches) { ModelFormat mfmt = 0; switch (format) { case LandTableFormat.SA1: mfmt = ModelFormat.Basic; break; case LandTableFormat.SADX: mfmt = ModelFormat.BasicDX; break; case LandTableFormat.SA2: mfmt = ModelFormat.Chunk; break; } AnimationFrame = ByteConverter.ToSingle(file, address); AnimationSpeed = ByteConverter.ToSingle(file, address + 4); MaxFrame = ByteConverter.ToSingle(file, address + 8); Model = new NJS_OBJECT(file, (int)(ByteConverter.ToUInt32(file, address + 0xC) - imageBase), imageBase, mfmt, labels, attaches); int actionaddr = (int)(ByteConverter.ToUInt32(file, address + 0x10) - imageBase); TexlistPointer = ByteConverter.ToUInt32(file, address + 0x14); NJS_ACTION action = new NJS_ACTION(file, actionaddr, imageBase, mfmt, labels, attaches); Animation = action.Animation; }
public NJS_OBJECT Clone() { NJS_OBJECT result = (NJS_OBJECT)MemberwiseClone(); if (Attach != null) { result.Attach = Attach.Clone(); } result.Position = Position.Clone(); result.Rotation = Rotation.Clone(); result.Scale = Scale.Clone(); result.children = new List <NJS_OBJECT>(children.Count); result.Children = new ReadOnlyCollection <NJS_OBJECT>(result.children); if (children.Count > 0) { NJS_OBJECT child = children[0].Clone(); while (child != null) { result.children.Add(child); child = child.Sibling; } } if (Sibling != null) { result.Sibling = Sibling.Clone(); } return(result); }
public void RemoveChildAt(int index) { NJS_OBJECT child = children[index]; children.RemoveAt(index); child.Parent = null; }
public void AddChild(NJS_OBJECT child) { children.Add(child); child.Parent = this; if (child.Sibling != null) { AddChild(child.Sibling); } }
public GeoAnimData(NJS_OBJECT model, NJS_MOTION animation) { Model = model; Animation = animation; MaxFrame = animation.Frames; AnimationSpeed = 1.0f; Animation.ActionName = "action_" + Extensions.GenerateIdentifier(); Animation.ObjectName = model.Name; }
public void ProcessShapeMotionVertexData(NJS_MOTION motion, float frame) { int animindex = -1; NJS_OBJECT obj = this; do { obj.ProcessShapeMotionVertexData(motion, frame, ref animindex); obj = obj.Sibling; } while (obj != null); }
public ModelFile(byte[] file, string filename = null) { int tmpaddr; bool be = ByteConverter.BigEndian; ByteConverter.BigEndian = false; ulong magic = ByteConverter.ToUInt64(file, 0) & FormatMask; byte version = file[7]; if (version > CurrentVersion) { throw new FormatException("Not a valid SA1MDL/SA2MDL file."); } Metadata = new Dictionary <uint, byte[]>(); Dictionary <int, string> labels = new Dictionary <int, string>(); Dictionary <int, Attach> attaches = new Dictionary <int, Attach>(); if (version < 2) { if (version == 1) { tmpaddr = ByteConverter.ToInt32(file, 0x14); if (tmpaddr != 0) { int addr = ByteConverter.ToInt32(file, tmpaddr); while (addr != -1) { labels.Add(addr, file.GetCString(ByteConverter.ToInt32(file, tmpaddr + 4))); tmpaddr += 8; addr = ByteConverter.ToInt32(file, tmpaddr); } } } switch (magic) { case SA1MDL: Format = ModelFormat.Basic; break; case SA2MDL: Format = ModelFormat.Chunk; break; default: throw new FormatException("Not a valid SA1MDL/SA2MDL file."); } Model = new NJS_OBJECT(file, ByteConverter.ToInt32(file, 8), 0, Format, labels, attaches); if (filename != null) { tmpaddr = ByteConverter.ToInt32(file, 0xC); if (tmpaddr != 0) { List <string> animfiles = new List <string>(); int addr = ByteConverter.ToInt32(file, tmpaddr); while (addr != -1) { animfiles.Add(file.GetCString(addr)); tmpaddr += 4; addr = ByteConverter.ToInt32(file, tmpaddr); } animationFiles = animfiles.ToArray(); } else { animationFiles = new string[0]; } string path = Path.GetDirectoryName(filename); List <NJS_MOTION> anims = new List <NJS_MOTION>(); try { foreach (string item in animationFiles) { anims.Add(NJS_MOTION.Load(Path.Combine(path, item), Model.CountAnimated())); } } catch { anims.Clear(); } Animations = anims.AsReadOnly(); } } else { animationFiles = new string[0]; tmpaddr = ByteConverter.ToInt32(file, 0xC); if (tmpaddr != 0) { bool finished = false; while (!finished) { ChunkTypes type = (ChunkTypes)ByteConverter.ToUInt32(file, tmpaddr); int chunksz = ByteConverter.ToInt32(file, tmpaddr + 4); int nextchunk = tmpaddr + 8 + chunksz; tmpaddr += 8; if (version == 2) { switch (type) { case ChunkTypes.Label: while (ByteConverter.ToInt64(file, tmpaddr) != -1) { labels.Add(ByteConverter.ToInt32(file, tmpaddr), file.GetCString(ByteConverter.ToInt32(file, tmpaddr + 4))); tmpaddr += 8; } break; case ChunkTypes.Animation: List <string> animfiles = new List <string>(); while (ByteConverter.ToInt32(file, tmpaddr) != -1) { animfiles.Add(file.GetCString(ByteConverter.ToInt32(file, tmpaddr))); tmpaddr += 4; } animationFiles = animfiles.ToArray(); break; case ChunkTypes.Morph: break; case ChunkTypes.Author: Author = file.GetCString(tmpaddr); break; case ChunkTypes.Tool: break; case ChunkTypes.Description: Description = file.GetCString(tmpaddr); break; case ChunkTypes.Texture: break; case ChunkTypes.End: finished = true; break; } } else { byte[] chunk = new byte[chunksz]; Array.Copy(file, tmpaddr, chunk, 0, chunksz); int chunkaddr = 0; switch (type) { case ChunkTypes.Label: while (ByteConverter.ToInt64(chunk, chunkaddr) != -1) { labels.Add(ByteConverter.ToInt32(chunk, chunkaddr), chunk.GetCString(ByteConverter.ToInt32(chunk, chunkaddr + 4))); chunkaddr += 8; } break; case ChunkTypes.Animation: List <string> animchunks = new List <string>(); while (ByteConverter.ToInt32(chunk, chunkaddr) != -1) { animchunks.Add(chunk.GetCString(ByteConverter.ToInt32(chunk, chunkaddr))); chunkaddr += 4; } animationFiles = animchunks.ToArray(); break; case ChunkTypes.Morph: break; case ChunkTypes.Author: Author = chunk.GetCString(chunkaddr); break; case ChunkTypes.Tool: break; case ChunkTypes.Description: Description = chunk.GetCString(chunkaddr); break; case ChunkTypes.End: finished = true; break; default: Metadata.Add((uint)type, chunk); break; } } tmpaddr = nextchunk; } } switch (magic) { case SA1MDL: Format = ModelFormat.Basic; break; case SA2MDL: Format = ModelFormat.Chunk; break; case SA2BMDL: Format = ModelFormat.GC; break; case XJMDL: Format = ModelFormat.XJ; break; default: throw new FormatException("Not a valid SA1MDL/SA2MDL file."); } Model = new NJS_OBJECT(file, ByteConverter.ToInt32(file, 8), 0, Format, labels, attaches); if (filename != null) { string path = Path.GetDirectoryName(filename); if (File.Exists(Path.GetFileNameWithoutExtension(filename) + ".action")) { using (TextReader tr = File.OpenText(Path.GetFileNameWithoutExtension(filename) + ".action")) { List <string> animlist = new List <string>(); int count = File.ReadLines(Path.GetFileNameWithoutExtension(filename) + ".action").Count(); for (int i = 0; i < count; i++) { string line = tr.ReadLine(); if (File.Exists(Path.Combine(path, line))) { animlist.Add(line); } } animationFiles = animlist.ToArray(); } } List <NJS_MOTION> anims = new List <NJS_MOTION>(); try { foreach (string item in animationFiles) { if (Path.GetExtension(item).ToLowerInvariant() == ".json") { JsonSerializer js = new JsonSerializer() { Culture = System.Globalization.CultureInfo.InvariantCulture }; using (TextReader tr = File.OpenText(Path.Combine(path, item))) { using (JsonTextReader jtr = new JsonTextReader(tr)) anims.Add(js.Deserialize <NJS_MOTION>(jtr)); } } else { anims.Add(NJS_MOTION.Load(Path.Combine(path, item), Model.CountAnimated())); } } } catch { anims.Clear(); } Animations = anims.AsReadOnly(); } } ByteConverter.BigEndian = be; }
public static void CreateFile(string filename, NJS_OBJECT model, string[] animationFiles, string author, string description, Dictionary <uint, byte[]> metadata, ModelFormat format, bool nometa = false, bool useNinjaMetaData = false) { uint ninjaMagic; uint imageBase = (uint)(useNinjaMetaData ? 0 : 0x10); bool be = ByteConverter.BigEndian; if (useNinjaMetaData == false) { ByteConverter.BigEndian = false; } if (format == ModelFormat.BasicDX) { format = ModelFormat.Basic; } List <byte> file = new List <byte>(); ulong magic; switch (format) { case ModelFormat.Basic: case ModelFormat.BasicDX: magic = SA1MDLVer; ninjaMagic = NJBMMagic; break; case ModelFormat.Chunk: magic = SA2MDLVer; ninjaMagic = NJCMMagic; break; case ModelFormat.GC: magic = SA2BMDLVer; ninjaMagic = GJCMMagic; break; case ModelFormat.XJ: magic = XJMDLVer; ninjaMagic = NJCMMagic; //XJ uses Chunk's magic break; default: throw new ArgumentException("Cannot save " + format.ToString() + " format models to file!", "format"); } Dictionary <string, uint> labels = new Dictionary <string, uint>(); List <uint> njOffsets = new List <uint>(); byte[] mdl; uint addr; if (useNinjaMetaData == true) { mdl = model.NJGetBytes(imageBase, false, labels, njOffsets, out addr); //***Ninja metadata should always be little endian!*** file.AddRange(BitConverter.GetBytes(ninjaMagic)); file.AddRange(BitConverter.GetBytes(mdl.Length)); //***Ninja metadata should always be little endian!*** } else { mdl = model.GetBytes(imageBase, false, labels, njOffsets, out addr); file.AddRange(ByteConverter.GetBytes(magic)); file.AddRange(ByteConverter.GetBytes(addr + 0x10)); file.AddRange(ByteConverter.GetBytes(mdl.Length + 0x10)); } file.AddRange(mdl); if (!nometa) { if (labels.Count > 0) { List <byte> chunk = new List <byte>((labels.Count * 8) + 8); int straddr = (labels.Count * 8) + 8; List <byte> strbytes = new List <byte>(); foreach (KeyValuePair <string, uint> label in labels) { chunk.AddRange(ByteConverter.GetBytes(label.Value)); chunk.AddRange(ByteConverter.GetBytes(straddr + strbytes.Count)); strbytes.AddRange(Encoding.UTF8.GetBytes(label.Key)); strbytes.Add(0); strbytes.Align(4); } chunk.AddRange(ByteConverter.GetBytes(-1L)); chunk.AddRange(strbytes); file.AddRange(ByteConverter.GetBytes((uint)ChunkTypes.Label)); file.AddRange(ByteConverter.GetBytes(chunk.Count)); file.AddRange(chunk); } if (animationFiles != null && animationFiles.Length > 0) { using (TextWriter tw = File.CreateText(Path.ChangeExtension(filename, ".action"))) { for (int a = 0; a < animationFiles.Count(); a++) { tw.WriteLine(animationFiles[a]); } tw.Flush(); tw.Close(); } /* * //Old animation code * List<byte> chunk = new List<byte>((animationFiles.Length + 1) * 4); * int straddr = (animationFiles.Length + 1) * 4; * List<byte> strbytes = new List<byte>(); * for (int i = 0; i < animationFiles.Length; i++) * { * chunk.AddRange(ByteConverter.GetBytes(straddr + strbytes.Count)); * strbytes.AddRange(Encoding.UTF8.GetBytes(animationFiles[i])); * strbytes.Add(0); * strbytes.Align(4); * } * chunk.AddRange(ByteConverter.GetBytes(-1)); * chunk.AddRange(strbytes); * file.AddRange(ByteConverter.GetBytes((uint)ChunkTypes.Animation)); * file.AddRange(ByteConverter.GetBytes(chunk.Count)); * file.AddRange(chunk); */ } if (!string.IsNullOrEmpty(author)) { List <byte> chunk = new List <byte>(author.Length + 1); chunk.AddRange(Encoding.UTF8.GetBytes(author)); chunk.Add(0); chunk.Align(4); file.AddRange(ByteConverter.GetBytes((uint)ChunkTypes.Author)); file.AddRange(ByteConverter.GetBytes(chunk.Count)); file.AddRange(chunk); } if (!string.IsNullOrEmpty(description)) { List <byte> chunk = new List <byte>(description.Length + 1); chunk.AddRange(Encoding.UTF8.GetBytes(description)); chunk.Add(0); chunk.Align(4); file.AddRange(ByteConverter.GetBytes((uint)ChunkTypes.Description)); file.AddRange(ByteConverter.GetBytes(chunk.Count)); file.AddRange(chunk); } if (metadata != null) { foreach (KeyValuePair <uint, byte[]> item in metadata) { file.AddRange(ByteConverter.GetBytes(item.Key)); file.AddRange(ByteConverter.GetBytes(item.Value.Length)); file.AddRange(item.Value); } } } if (useNinjaMetaData == true) { /* * List<uint> addresses = new List<uint>(); * foreach(var pair in labels) * { * if(pair.Value != 0) * { * addresses.Add(pair.Value); * } * } * addresses.Insert(0, 0x4); * addresses.Sort();*/ njOffsets = njOffsets.Distinct().ToList(); njOffsets.Sort(); List <byte> pof0 = new List <byte>(); pof0.Add(0x41); for (int i = 1; i < njOffsets.Count; i++) { pof0.AddRange(POF0Helper.calcPOF0Pointer(njOffsets[i - 1], njOffsets[i])); } POF0Helper.finalizePOF0(pof0); file.AddRange(pof0); if (metadata.Count != 0 && metadata.ContainsKey(uint.MaxValue)) { file.InsertRange(0, metadata[uint.MaxValue]); } } else { file.AddRange(ByteConverter.GetBytes((uint)ChunkTypes.End)); file.AddRange(new byte[4]); } File.WriteAllBytes(filename, file.ToArray()); ByteConverter.BigEndian = be; }
public COL(byte[] file, int address, uint imageBase, LandTableFormat format, Dictionary <int, string> labels, bool?forceBasic, Dictionary <int, Attach> attaches) { Bounds = new BoundingSphere(file, address); ModelFormat mfmt = 0; switch (format) { case LandTableFormat.SA1: mfmt = ModelFormat.Basic; break; case LandTableFormat.SADX: mfmt = ModelFormat.BasicDX; break; case LandTableFormat.SA2: if (forceBasic.HasValue && forceBasic.Value) { mfmt = ModelFormat.Basic; } else { mfmt = ModelFormat.Chunk; } break; case LandTableFormat.SA2B: if (forceBasic.HasValue && forceBasic.Value) { mfmt = ModelFormat.Basic; } else { mfmt = ModelFormat.GC; } break; } switch (format) { case LandTableFormat.SA1: case LandTableFormat.SADX: WidthY = ByteConverter.ToSingle(file, address + 0x10); WidthZ = ByteConverter.ToSingle(file, address + 0x14); uint tmpaddr = ByteConverter.ToUInt32(file, address + 0x18) - imageBase; Model = new NJS_OBJECT(file, (int)tmpaddr, imageBase, mfmt, labels, attaches); BlockBits = ByteConverter.ToUInt32(file, address + 0x1C); Flags = ByteConverter.ToInt32(file, address + 0x20); break; case LandTableFormat.SA2: case LandTableFormat.SA2B: Flags = ByteConverter.ToInt32(file, address + 0x1C); if (!forceBasic.HasValue && Flags >= 0) { mfmt = ModelFormat.Basic; } tmpaddr = ByteConverter.ToUInt32(file, address + 0x10) - imageBase; Model = new NJS_OBJECT(file, (int)tmpaddr, imageBase, mfmt, labels, attaches); WidthZ = ByteConverter.ToInt32(file, address + 0x14); BlockBits = ByteConverter.ToUInt32(file, address + 0x18); break; } }
public void RemoveChild(NJS_OBJECT child) { children.Remove(child); child.Parent = null; }
public void InsertChild(int index, NJS_OBJECT child) { children.Insert(index, child); child.Parent = this; }
private NJS_OBJECT(byte[] file, int address, uint imageBase, ModelFormat format, NJS_OBJECT parent, Dictionary <int, string> labels, Dictionary <int, Attach> attaches) { if (labels.ContainsKey(address)) { Name = labels[address]; } else { Name = "object_" + address.ToString("X8"); } if (address > file.Length - 52) { Position = new Vertex(); Rotation = new Rotation(); Scale = new Vertex(1, 1, 1); children = new List <NJS_OBJECT>(); Children = new ReadOnlyCollection <NJS_OBJECT>(children); return; } ObjectFlags flags = (ObjectFlags)ByteConverter.ToInt32(file, address); RotateZYX = (flags & ObjectFlags.RotateZYX) == ObjectFlags.RotateZYX; SkipDraw = (flags & ObjectFlags.NoDisplay) == ObjectFlags.NoDisplay; SkipChildren = (flags & ObjectFlags.NoChildren) == ObjectFlags.NoChildren; IgnorePosition = (flags & ObjectFlags.NoPosition) == ObjectFlags.NoPosition; IgnoreRotation = (flags & ObjectFlags.NoRotate) == ObjectFlags.NoRotate; IgnoreScale = (flags & ObjectFlags.NoScale) == ObjectFlags.NoScale; Animate = (flags & ObjectFlags.NoAnimate) == 0; Morph = (flags & ObjectFlags.NoMorph) == 0; int tmpaddr = ByteConverter.ToInt32(file, address + 4); if (tmpaddr != 0) { tmpaddr = (int)unchecked ((uint)tmpaddr - imageBase); if (attaches != null && attaches.ContainsKey(tmpaddr)) { Attach = attaches[tmpaddr]; } else { Attach = Attach.Load(file, tmpaddr, imageBase, format, labels); if (attaches != null) { attaches.Add(tmpaddr, Attach); } } } Position = new Vertex(file, address + 8); Rotation = new Rotation(file, address + 0x14); Scale = new Vertex(file, address + 0x20); Parent = parent; children = new List <NJS_OBJECT>(); Children = new ReadOnlyCollection <NJS_OBJECT>(children); NJS_OBJECT child = null; tmpaddr = ByteConverter.ToInt32(file, address + 0x2C); if (tmpaddr != 0) { tmpaddr = (int)unchecked ((uint)tmpaddr - imageBase); child = new NJS_OBJECT(file, tmpaddr, imageBase, format, this, labels, attaches); } while (child != null) { children.Add(child); child = child.Sibling; } tmpaddr = ByteConverter.ToInt32(file, address + 0x30); if (tmpaddr != 0) { tmpaddr = (int)unchecked ((uint)tmpaddr - imageBase); Sibling = new NJS_OBJECT(file, tmpaddr, imageBase, format, parent, labels, attaches); } //Assimp.AssimpContext context = new AssimpContext(); //Scene scene = context.ImportFile("F:\\untitled.obj", PostProcessSteps.Triangulate); //AssimpLoad(scene, scene.RootNode); }