/// <summary> /// Reads a generic Pokémon container from a Stream. /// Those containers are the ones that starts with "GR", "MM", "AD" and so on... /// </summary> /// <param name="data">Stream with container data</param> /// <returns></returns> public static OContainer load(Stream data) { BinaryReader input = new BinaryReader(data); OContainer output = new OContainer(); IOUtils.readString(input, 0, 2); //Magic ushort sectionCount = input.ReadUInt16(); for (int i = 0; i < sectionCount; i++) { OContainer.fileEntry entry = new OContainer.fileEntry(); data.Seek(4 + (i * 4), SeekOrigin.Begin); uint startOffset = input.ReadUInt32(); uint endOffset = input.ReadUInt32(); uint length = endOffset - startOffset; data.Seek(startOffset, SeekOrigin.Begin); byte[] buffer = new byte[length]; input.Read(buffer, 0, (int)length); entry.data = buffer; output.content.Add(entry); } data.Close(); return output; }
/// <summary> /// Reads a DARC archive. /// </summary> /// <param name="data">Stream of the data</param> /// <returns>The container data</returns> public static OContainer load(Stream data) { OContainer output = new OContainer(); BinaryReader input = new BinaryReader(data); string darcMagic = IOUtils.readStringWithLength(input, 4); ushort endian = input.ReadUInt16(); ushort headerLength = input.ReadUInt16(); uint version = input.ReadUInt32(); uint fileSize = input.ReadUInt32(); uint tableOffset = input.ReadUInt32(); uint tableLength = input.ReadUInt32(); uint dataOffset = input.ReadUInt32(); data.Seek(tableOffset, SeekOrigin.Begin); fileEntry root = getEntry(input); int baseOffset = (int)data.Position; int namesOffset = (int)(tableOffset + root.length * 0xc); string currDir = null; for (int i = 0; i < root.length - 1; i++) { data.Seek(baseOffset + i * 0xc, SeekOrigin.Begin); fileEntry entry = getEntry(input); if ((entry.flags & 1) > 0) { //Folder int index = i; currDir = null; for (;;) { uint parentIndex = entry.offset; currDir = getName(input, entry.nameOffset + namesOffset) + "/" + currDir; if (parentIndex == 0 || parentIndex == index) break; data.Seek(baseOffset + parentIndex * 0xc, SeekOrigin.Begin); entry = getEntry(input); index = (int)parentIndex; } continue; } data.Seek(entry.offset, SeekOrigin.Begin); byte[] buffer = new byte[entry.length]; data.Read(buffer, 0, buffer.Length); OContainer.fileEntry file = new OContainer.fileEntry(); file.name = currDir + getName(input, entry.nameOffset + namesOffset); file.data = buffer; output.content.Add(file); } data.Close(); return output; }
/// <summary> /// Reads a GARC archive. /// </summary> /// <param name="data">Stream of the data</param> /// <returns>The container data</returns> public static OContainer load(Stream data) { OContainer output = new OContainer(); BinaryReader input = new BinaryReader(data); output.data = data; string garcMagic = IOUtils.readStringWithLength(input, 4); uint garcHeaderLength = input.ReadUInt32(); ushort endian = input.ReadUInt16(); input.ReadUInt16(); //0x400 uint sectionCount = input.ReadUInt32(); uint dataOffset = input.ReadUInt32(); uint decompressedLength = input.ReadUInt32(); uint compressedLength = input.ReadUInt32(); //File Allocation Table Offsets string fatoMagic = IOUtils.readStringWithLength(input, 4); uint fatoHeaderLength = input.ReadUInt32(); ushort fatoEntries = input.ReadUInt16(); input.ReadUInt16(); //0xffff = Padding? data.Seek(fatoEntries * 4, SeekOrigin.Current); //We don't need this string fatbMagic = IOUtils.readStringWithLength(input, 4); uint fatbHeaderLength = input.ReadUInt32(); uint entries = input.ReadUInt32(); long baseOffset = data.Position; for (int i = 0; i < entries; i++) { data.Seek(baseOffset + i * 0x10, SeekOrigin.Begin); uint flags = input.ReadUInt32(); uint startOffset = input.ReadUInt32(); uint endOffset = input.ReadUInt32(); uint length = input.ReadUInt32(); input.BaseStream.Seek(startOffset + dataOffset, SeekOrigin.Begin); byte[] buffer = new byte[Math.Min(0x10, length)]; input.Read(buffer, 0, buffer.Length); bool isCompressed = buffer.Length > 0 ? buffer[0] == 0x11 : false; string extension = FileIO.getExtension(buffer, isCompressed ? 5 : 0); string name = string.Format("file_{0:D5}{1}", i, extension); //And add the file to the container list OContainer.fileEntry entry = new OContainer.fileEntry(); entry.name = name; entry.loadFromDisk = true; entry.fileOffset = startOffset + dataOffset; entry.fileLength = length; output.content.Add(entry); } return output; }
/// <summary> /// Loads a PC monster model from Pokémon. /// </summary> /// <param name="data">The data</param> /// <returns>The Model group with the monster meshes</returns> public static RenderBase.OModelGroup load(Stream data) { RenderBase.OModelGroup models = new RenderBase.OModelGroup(); OContainer container = PkmnContainer.load(data); models = BCH.load(new MemoryStream(container.content[0].data)); return(models); }
/// <summary> /// Loads a CP overworld character model from Pokémon. /// </summary> /// <param name="data">The data</param> /// <returns>The Model group with the character meshes</returns> public static RenderBase.OModelGroup load(Stream data) { RenderBase.OModelGroup models = new RenderBase.OModelGroup(); OContainer container = PkmnContainer.load(data); models = CM.load(new MemoryStream(container.ElementAt(1).data)); return(models); }
/// <summary> /// Loads a BS animation file from Pokémon. /// </summary> /// <param name="data">The data</param> /// <returns>The Model group with the animations</returns> public static RenderBase.OModelGroup load(Stream data) { List <RenderBase.OModelGroup> models = new List <RenderBase.OModelGroup>(); OContainer naCont = PkmnContainer.load(data); //Get NA containers from BS for (int i = 1; i < naCont.content.Count; i++) { //Skip first entry because its not a NA (TODO: figure out this data) OContainer bchCont = PkmnContainer.load(new MemoryStream(naCont.content[1].data)); //Get BCH from NA containers models.Add(BCH.load(new System.IO.MemoryStream(bchCont.content[0].data))); } return(models[0]); //TODO: Figure out how to load all anim BCHs }
/// <summary> /// Loads a BS animation file from Pokémon. /// </summary> /// <param name="data">The data</param> /// <returns>The Model group with the animations</returns> public static RenderBase.OModelGroup load(Stream data) { List <RenderBase.OModelGroup> models = new List <RenderBase.OModelGroup>(); OContainer naCont = PkmnContainer.load(data); //Get NA containers from BS var naList = naCont.GetList(); foreach (var entry in naCont.Skip(1)) { OContainer bchCont = PkmnContainer.load(new MemoryStream(entry.data)); //Get BCH from NA containers models.Add(BCH.load(new MemoryStream(bchCont.First().data))); } return(models[0]); //TODO: Figure out how to load all anim BCHs }
public void launch(object data) { container = (OContainer)data; FileList.addColumn(new OList.columnHeader(384, "Name")); FileList.addColumn(new OList.columnHeader(128, "Size")); foreach (OContainer.fileEntry file in container.content) { OList.listItemGroup item = new OList.listItemGroup(); item.columns.Add(new OList.listItem(file.name)); uint length = file.loadFromDisk ? file.fileLength : (uint)file.data.Length; item.columns.Add(new OList.listItem(getLength(length))); FileList.addItem(item); } FileList.Refresh(); }
/// <summary> /// Loads all map textures (and other data) on a AD Pokémon container. /// </summary> /// <param name="data">The data</param> /// <returns>The Model group with textures and stuff</returns> public static RenderBase.OModelGroup load(Stream data) { RenderBase.OModelGroup models = new RenderBase.OModelGroup(); OContainer container = PkmnContainer.load(data); for (int i = 1; i < container.content.Count; i++) { FileIO.file file = FileIO.load(new MemoryStream(container.content[i].data)); if (file.type == FileIO.formatType.model) { models.merge((RenderBase.OModelGroup)file.data); } } return(models); }
/// <summary> /// Loads a CM overworld character model from Pokémon. /// </summary> /// <param name="data">The data</param> /// <returns>The Model group with the character meshes</returns> public static RenderBase.OModelGroup load(Stream data) { RenderBase.OModelGroup models = new RenderBase.OModelGroup(); OContainer container = PkmnContainer.load(data); models = GfModel.load(new MemoryStream(container.content[0].data)); List <RenderBase.OSkeletalAnimation> anms = GfMotion.load(new MemoryStream(container.content[1].data)); foreach (RenderBase.OSkeletalAnimation anm in anms) { models.skeletalAnimation.list.Add(anm); } return(models); }
/// <summary> /// Loads all map textures (and other data) on a AD Pokémon container. /// </summary> /// <param name="data">The data</param> /// <returns>The Model group with textures and stuff</returns> public static RenderBase.OModelGroup load(Stream data) { RenderBase.OModelGroup models = new RenderBase.OModelGroup(); OContainer container = PkmnContainer.load(data); foreach (var entry in container) { FileIO.file file = FileIO.load(new MemoryStream(entry.data)); if (file.type == FileIO.formatType.model) { models.merge((RenderBase.OModelGroup)file.data); } } return(models); }
/// <summary> /// Loads all monster textures on a PT Pokémon container. /// </summary> /// <param name="data">The data</param> /// <returns>The monster textures</returns> public static List <RenderBase.OTexture> load(Stream data) { List <RenderBase.OTexture> textures = new List <RenderBase.OTexture>(); RenderBase.OModelGroup models = new RenderBase.OModelGroup(); OContainer container = PkmnContainer.load(data); foreach (var entry in container) { FileIO.file file = FileIO.load(new MemoryStream(entry.data)); if (file.type == FileIO.formatType.model) { textures.AddRange(((RenderBase.OModelGroup)file.data).texture); } } return(textures); }
/// <summary> /// Loads all monster textures on a PT Pokémon container. /// </summary> /// <param name="data">The data</param> /// <returns>The monster textures</returns> public static List <RenderBase.OTexture> load(Stream data) { List <RenderBase.OTexture> textures = new List <RenderBase.OTexture>(); RenderBase.OModelGroup models = new RenderBase.OModelGroup(); OContainer container = PkmnContainer.load(data); for (int i = 0; i < container.content.Count; i++) { FileIO.file file = FileIO.load(new MemoryStream(container.content[i].data)); if (file.type == FileIO.formatType.model) { textures.AddRange(((RenderBase.OModelGroup)file.data).texture); } } return(textures); }
/// <summary> /// Reads FPT0 containers from Dragon Quest VII. /// </summary> /// <param name="data">Stream with container data</param> /// <returns></returns> public static OContainer load(Stream data) { BinaryReader input = new BinaryReader(data); OContainer output = new OContainer(); data.Seek(8, SeekOrigin.Begin); uint entries = input.ReadUInt32(); uint baseAddress = 0x10 + (entries * 0x20) + 0x80; input.ReadUInt32(); List<sectionEntry> files = new List<sectionEntry>(); for (int i = 0; i < entries; i++) { sectionEntry entry = new sectionEntry(); entry.name = IOUtils.readString(input, (uint)(0x10 + (i * 0x20))); data.Seek(0x20 + (i * 0x20), SeekOrigin.Begin); input.ReadUInt32(); //Memory address? entry.offset = input.ReadUInt32() + baseAddress; entry.length = input.ReadUInt32(); input.ReadUInt32(); //Padding? files.Add(entry); } foreach (sectionEntry file in files) { OContainer.fileEntry entry = new OContainer.fileEntry(); data.Seek(file.offset, SeekOrigin.Begin); byte[] buffer = new byte[file.length]; input.Read(buffer, 0, buffer.Length); entry.data = buffer; entry.name = file.name; output.content.Add(entry); } data.Close(); return output; }
/// <summary> /// Reads a SARC archive. /// </summary> /// <param name="data">Stream of the data</param> /// <returns>The container data</returns> public static OContainer load(Stream data) { OContainer output = new OContainer(); BinaryReader input = new BinaryReader(data); string sarcMagic = IOUtils.readStringWithLength(input, 4); ushort sarcHeaderLength = input.ReadUInt16(); ushort endian = input.ReadUInt16(); uint fileLength = input.ReadUInt32(); uint dataOffset = input.ReadUInt32(); uint dataPadding = input.ReadUInt32(); string sfatMagic = IOUtils.readStringWithLength(input, 4); ushort sfatHeaderLength = input.ReadUInt16(); ushort entries = input.ReadUInt16(); uint hashMultiplier = input.ReadUInt32(); int sfntOffset = 0x20 + entries * 0x10 + 8; for (int i = 0; i < entries; i++) { data.Seek(0x20 + i * 0x10, SeekOrigin.Begin); uint nameHash = input.ReadUInt32(); uint nameOffset = (input.ReadUInt32() & 0xffffff) << 2; uint offset = input.ReadUInt32(); uint length = input.ReadUInt32() - offset; string name = IOUtils.readString(input, (uint)(sfntOffset + nameOffset)); data.Seek(offset + dataOffset, SeekOrigin.Begin); byte[] buffer = new byte[length]; data.Read(buffer, 0, buffer.Length); if (name == "") name = string.Format("file_{0:D5}{1}", i, FileIO.getExtension(buffer)); OContainer.fileEntry entry = new OContainer.fileEntry(); entry.name = name; entry.data = buffer; output.content.Add(entry); } data.Close(); return output; }
/// <summary> /// Loads a PC monster model from Pokémon. /// </summary> /// <param name="data">The data</param> /// <returns>The Model group with the monster meshes</returns> public static RenderBase.OModelGroup load(Stream data) { RenderBase.OModelGroup models = new RenderBase.OModelGroup(); OContainer container = PkmnContainer.load(data); foreach (OContainer.FileEntry file in container) { FileIO.file loaded = new FileIO.file(); try { loaded = FileIO.load(new MemoryStream(file.data)); } catch (Exception e) { Debug.WriteLine(string.Format("Error opening file:\n{0}\n{1}", e.Message, e.StackTrace)); } if (loaded.data == null) { continue; } switch (loaded.type) { case FileIO.formatType.model: models.merge((RenderBase.OModelGroup)loaded.data); break; case FileIO.formatType.anims: models.skeletalAnimation.Add((RenderBase.OSkeletalAnimation)loaded.data); break; case FileIO.formatType.image: models.texture.Add((RenderBase.OTexture)loaded.data); break; } } return(models); }
public void finalize() { container.Dispose(); container = null; }
/// <summary> /// Reads the Model PACKage from Dragon Quest VII. /// </summary> /// <param name="data">Stream of the data</param> /// <returns></returns> public static OContainer load(Stream data) { BinaryReader input = new BinaryReader(data); OContainer output = new OContainer(); List<sectionEntry> mainSection = getSection(input); //World nodes section data.Seek(mainSection[0].offset, SeekOrigin.Begin); List<node> nodes = new List<node>(); List<sectionEntry> worldNodesSection = getSection(input); foreach (sectionEntry entry in worldNodesSection) { data.Seek(entry.offset, SeekOrigin.Begin); node n = new node(); //Geometry node input.ReadUInt32(); //GNOD magic number input.ReadUInt32(); input.ReadUInt32(); n.parentId = input.ReadInt32(); n.name = IOUtils.readString(input, (uint)data.Position); data.Seek(entry.offset + 0x20, SeekOrigin.Begin); n.transform = new RenderBase.OMatrix(); RenderBase.OVector4 t = new RenderBase.OVector4(input.ReadSingle(), input.ReadSingle(), input.ReadSingle(), input.ReadSingle()); RenderBase.OVector4 r = new RenderBase.OVector4(input.ReadSingle(), input.ReadSingle(), input.ReadSingle(), input.ReadSingle()); RenderBase.OVector4 s = new RenderBase.OVector4(input.ReadSingle(), input.ReadSingle(), input.ReadSingle(), input.ReadSingle()); n.transform *= RenderBase.OMatrix.scale(new RenderBase.OVector3(s.x, s.y, s.z)); n.transform *= RenderBase.OMatrix.rotateX(r.x); n.transform *= RenderBase.OMatrix.rotateY(r.y); n.transform *= RenderBase.OMatrix.rotateZ(r.z); n.transform *= RenderBase.OMatrix.translate(new RenderBase.OVector3(t.x, t.y, t.z)); nodes.Add(n); } RenderBase.OMatrix[] nodesTransform = new RenderBase.OMatrix[nodes.Count]; for (int i = 0; i < nodes.Count; i++) { RenderBase.OMatrix transform = new RenderBase.OMatrix(); transformNode(nodes, i, ref transform); nodesTransform[i] = transform; } //Models section data.Seek(mainSection[1].offset, SeekOrigin.Begin); List<sectionEntry> modelsSection = getSection(input); foreach (sectionEntry entry in modelsSection) { data.Seek(entry.offset, SeekOrigin.Begin); //Field Data section /* * Usually have 3 entries. * 1st entry: Model CGFX * 2nd entry: Unknow CGFX, possibly animations * 3rd entry: Another FieldData section, possibly child object */ List<sectionEntry> fieldDataSection = getSection(input); data.Seek(fieldDataSection[0].offset, SeekOrigin.Begin); uint length = fieldDataSection[0].length; while ((length & 0x7f) != 0) length++; //Align byte[] buffer = new byte[length]; input.Read(buffer, 0, buffer.Length); OContainer.fileEntry file = new OContainer.fileEntry(); file.name = CGFX.getName(new MemoryStream(buffer)) + ".bcmdl"; file.data = buffer; output.content.Add(file); } //FILE section data.Seek(mainSection[2].offset, SeekOrigin.Begin); //TODO //Collision section data.Seek(mainSection[3].offset, SeekOrigin.Begin); //TODO //PARM(???) section data.Seek(mainSection[4].offset, SeekOrigin.Begin); //TODO //Textures CGFX data.Seek(mainSection[5].offset, SeekOrigin.Begin); byte[] texBuffer = new byte[mainSection[5].length]; input.Read(texBuffer, 0, texBuffer.Length); OContainer.fileEntry texFile = new OContainer.fileEntry(); texFile.name = "textures.bctex"; texFile.data = texBuffer; output.content.Add(texFile); data.Close(); return output; }