public static WEP FromStream(EndianBinaryReader reader) { /*===================================================================== WEP HEADER (0x50) 80 bytes long =====================================================================*/ reader.Skip(0x04); // TODO: skip magic 0x04 (4 dec) "H01" check for file type? byte numJoints = reader.ReadByte(); byte numGroups = reader.ReadByte(); ushort numTriangles = reader.ReadUInt16(); ushort numQuads = reader.ReadUInt16(); ushort numPolygons = reader.ReadUInt16(); uint ptrTexture1 = (uint)(reader.ReadUInt32() + 0x10); // same as ptrTexture... why? reader.Skip(0x30); // header padding? uint ptrTexture = (uint)(reader.ReadUInt32() + 0x10); uint ptrGroups = (uint)(reader.ReadUInt32() + 0x10); uint ptrVertices = (uint)(reader.ReadUInt32() + 0x10); uint ptrPolygons = (uint)(reader.ReadUInt32() + 0x10); /*===================================================================== LOCALS =====================================================================*/ int numAllPolygons = numTriangles + numQuads + numPolygons; int numOfPalettes = 7; // palettes of 2/3 color count. /*===================================================================== STREAM READER =====================================================================*/ WEP wep = new WEP(); wep.joints = VSTools.GetJoints(reader, numJoints); wep.groups = VSTools.GetGroups(reader, numGroups); wep.vertices = VSTools.GetVertices(reader, wep.groups); wep.polygons = VSTools.GetPolygons(reader, numAllPolygons); wep.textures = VSTools.GetTextures(reader, numOfPalettes); return wep; }
public static List<Joint> GetJoints(EndianBinaryReader reader, int numJoints) { List<Joint> joints = new List<Joint>(); for (int i = 0; i < numJoints; i++) { Joint joint = new Joint(); joint.boneLength = -reader.ReadInt16(); reader.Skip(2); // no effect on length, just padding joint.parentID = reader.ReadSByte(); joint.x = reader.ReadSByte(); joint.y = reader.ReadSByte(); joint.z = reader.ReadSByte(); joint.mode = reader.ReadSByte(); // does this matter? reader.Skip(0x01); // unknown reader.Skip(0x06); // always 0? padding? joints.Add(joint); } return joints; }
public void Load(EndianBinaryReader stream) { if (stream == null || stream.BaseStream.Length == 0) throw new ArgumentException("Null or empty stream specified", "stream"); // Read the header byte entryCount = stream.ReadByte(); stream.Skip(3); // Unknown Constants (0x5E, 0, 0x61) // Offset to the first entry (realistically it's right after the header and always 0x8 int offsetToFirstEntry = stream.ReadInt32(); // Load categories and their entries. stream.BaseStream.Position = offsetToFirstEntry; for(int i = 0; i < entryCount; i++) { Category category = new Category(); category.Load(stream); Categories.Add(category); } }
public VirtualFilesystemDirectory ReadFile(EndianBinaryReader reader) { if (reader.ReadUInt32() != 0x52415243) // "RARC" throw new InvalidDataException("Invalid Magic, not a RARC File"); uint fileSize = reader.ReadUInt32(); reader.SkipUInt32(); // Unknown uint dataOffset = reader.ReadUInt32() + 0x20; reader.Skip(16); // Unknown - 4 unsigned ints uint numNodes = reader.ReadUInt32(); reader.Skip(8); // Unknown - 2 unsigned ints uint fileEntryOffset = reader.ReadUInt32() + 0x20; reader.SkipUInt32(); // Unknown uint stringTableOffset = reader.ReadUInt32() + 0x20; reader.Skip(8); // Unknown - 2 unsigned ints. // Read all of the node headers. Node[] nodes = new Node[numNodes]; for (int i = 0; i < numNodes; i++) { nodes[i] = new Node { Type = new string(reader.ReadChars(4)), Name = ReadStringAtOffset(reader, stringTableOffset, reader.ReadUInt32()), NameHashcode = reader.ReadUInt16(), Entries = new FileEntry[reader.ReadUInt16()], FirstFileOffset = reader.ReadUInt32() }; } // Create a virtual directory for every folder within the ARC before we process any of them. List<VirtualFilesystemDirectory> allDirs = new List<VirtualFilesystemDirectory>(nodes.Length); foreach (Node node in nodes) { VirtualFilesystemDirectory vfDir = new VirtualFilesystemDirectory(node.Name); allDirs.Add(vfDir); } for (int k = 0; k < nodes.Length; k++) { Node node = nodes[k]; VirtualFilesystemDirectory curDir = allDirs[k]; for (int i = 0; i < node.Entries.Length; i++) { // Jump to the entry's offset in the file. reader.BaseStream.Position = fileEntryOffset + ((node.FirstFileOffset + i) * 0x14); // 0x14 is the size of a File Entry in bytes node.Entries[i] = new FileEntry(); node.Entries[i].ID = reader.ReadUInt16(); node.Entries[i].NameHashcode = reader.ReadUInt16(); node.Entries[i].Type = reader.ReadByte(); reader.SkipByte(); // Padding node.Entries[i].Name = ReadStringAtOffset(reader, stringTableOffset, reader.ReadUInt16()); // Skip these ones cause I don't know how computers work. if (node.Entries[i].Name == "." || node.Entries[i].Name == "..") continue; uint entryDataOffset = reader.ReadUInt32(); uint dataSize = reader.ReadUInt32(); // If it's a directory, then entryDataOffset contains the index of the parent node if (node.Entries[i].IsDirectory) { node.Entries[i].SubDirIndex = entryDataOffset; var newSubDir = allDirs[(int)entryDataOffset]; curDir.Children.Add(newSubDir); } else { node.Entries[i].Data = reader.ReadBytesAt(dataOffset + entryDataOffset, (int)dataSize); string fileName = Path.GetFileNameWithoutExtension(node.Entries[i].Name); string extension = Path.GetExtension(node.Entries[i].Name); var vfFileContents = new VirtualFileContents(node.Entries[i].Data); VirtualFilesystemFile vfFile = new VirtualFilesystemFile(fileName, extension, vfFileContents); curDir.Children.Add(vfFile); } reader.SkipInt32(); // Padding } } // The ROOT directory should always be the first node. We don't have access to the node's TYPE anymore // so we're going to assume its always the first one listed. return allDirs.Count > 0 ? allDirs[0] : null; }
public static List<Vertex> GetVertices(EndianBinaryReader reader, List<Group> groups) { List<Vertex> vertices = new List<Vertex>(); for (int i = 0, g = 0; i < groups[groups.Count - 1].lastVertex; i++) { if (i >= groups[g].lastVertex) { g++; // next group } Vertex vertex = new Vertex(); vertex.x = reader.ReadInt16(); vertex.y = reader.ReadInt16(); vertex.z = reader.ReadInt16(); reader.Skip(0x02); // padding vertex.groupID = g; vertex.boneID = groups[g].boneID; vertices.Add(vertex); } return vertices; }
public void Load(EndianBinaryReader reader) { int numVerts = reader.ReadInt32(); int vertsOffset = reader.ReadInt32(); int numFaces = reader.ReadInt32(); int facesOffset = reader.ReadInt32(); reader.BaseStream.Position = vertsOffset; List<Vector3> vertsList = new List<Vector3>(); for (int i = 0; i < numVerts; i++) { vertsList.Add(new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle())); } Vertexes = vertsList.ToArray(); reader.BaseStream.Position = facesOffset; List<int> facesList = new List<int>(); for (int i = 0; i < numFaces; i++) { facesList.Add(reader.ReadInt16()); facesList.Add(reader.ReadInt16()); facesList.Add(reader.ReadInt16()); reader.Skip(4); } Meshes = facesList.ToArray(); //Generate a buffer on the GPU and get the ID to it GL.GenBuffers(1, out _glVbo); //This "binds" the buffer. Once a buffer is bound, all actions are relative to it until another buffer is bound. GL.BindBuffer(BufferTarget.ArrayBuffer, _glVbo); //This uploads data to the currently bound buffer from the CPU -> GPU. This only needs to be done with the data changes (ie: you edited a vertexes position on the cpu side) GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(Vertexes.Length * Vector3.SizeInBytes), Vertexes, BufferUsageHint.StaticDraw); //Now we're going to repeat the same process for the Element buffer, which is what OpenGL calls indicies. (Notice how it's basically identical?) GL.GenBuffers(1, out _glEbo); GL.BindBuffer(BufferTarget.ElementArrayBuffer, _glEbo); GL.BufferData(BufferTarget.ElementArrayBuffer, (IntPtr)(Meshes.Length * 4), Meshes, BufferUsageHint.StaticDraw); }
public static SHP FromStream(EndianBinaryReader reader) { /*===================================================================== WEP HEADER (0x50) 80 bytes long =====================================================================*/ reader.Skip(0x04); // TODO: skip magic 0x04 (4 dec) "H01" check for file type? byte numJoints = reader.ReadByte(); byte numGroups = reader.ReadByte(); ushort numTriangles = reader.ReadUInt16(); ushort numQuads = reader.ReadUInt16(); ushort numPolygons = reader.ReadUInt16(); // Overlay cords and size // First is Eyes, Second is Mouth, 3-8 are? special frames? byte[] overlayX = new byte[8]; byte[] overlayY = new byte[8]; byte[] width = new byte[8]; byte[] height = new byte[8]; for (int i = 0; i < 8; i++) { overlayX[i] = reader.ReadByte(); overlayY[i] = reader.ReadByte(); width[i] = reader.ReadByte(); height[i] = reader.ReadByte(); } reader.Skip(0x24); // unkown, skip padding assumed reader.Skip(0x06); // skip collision size and height (shape is a cylinder) reader.Skip(0x02); // skip menu position Y reader.Skip(0x0C); // skip Unknown reader.Skip(0x02); // skip Shadow radius reader.Skip(0x02); // skip Shadow size increase rate reader.Skip(0x02); // skip Shadow size decrease rate reader.Skip(0x04); // skip Unknown reader.Skip(0x02); // skip Menu scale reader.Skip(0x02); // skip Unknown reader.Skip(0x02); // skip Target sphere position Y reader.Skip(0x08); // skip Unknown uint[] animLBA = new uint[12]; for (int i = 0; i < 12; i++) { animLBA[i] = reader.ReadUInt32(); } ushort[] chainIDs = new ushort[13]; for (int i = 0; i < 12; i++) { chainIDs[i] = reader.ReadUInt16(); } uint[] specialLBAs = new uint[4]; for (int i = 0; i < 4; i++) { specialLBAs[i] = reader.ReadUInt32(); } reader.Skip(0x20); //unknown (probably more LBA tables, there are also special attack ids stored here.) uint ptrMagic = (uint)(reader.ReadUInt32() + 0xF8); // same as ptrTexture... why? reader.Skip(0x18 * 2); // unknown (noticeable effects when casting spells) uint ptrAkao = (uint)(reader.ReadUInt32() + 0xF8); uint ptrGroups = (uint)(reader.ReadUInt32() + 0xF8); uint ptrVertices = (uint)(reader.ReadUInt32() + 0xF8); uint ptrPolygons = (uint)(reader.ReadUInt32() + 0xF8); /*===================================================================== LOCALS =====================================================================*/ int numAllPolygons = numTriangles + numQuads + numPolygons; int numOfPalettes = 2; // Enemies have two palettes that add variation. No use on main characters /*===================================================================== STREAM READER =====================================================================*/ SHP shp = new SHP(); shp.joints = VSTools.GetJoints(reader, numJoints); shp.groups = VSTools.GetGroups(reader, numGroups); shp.vertices = VSTools.GetVertices(reader, shp.groups); shp.polygons = VSTools.GetPolygons(reader, numAllPolygons); // skip AKAO reader.Skip(ptrMagic - ptrAkao); // skip magic section reader.Skip(4); // unknown reader.Skip(reader.ReadUInt32()); // skip length of the magic section. shp.textures = VSTools.GetTextures(reader, numOfPalettes); return shp; }