public static staticMeshOffset ReadStaticMeshOffset(BufferedStreamReader streamReader, bool active) { var offset = new staticMeshOffset(); offset.offset = streamReader.ReadBE <uint>(active); offset.uint_04 = streamReader.ReadBE <uint>(active); offset.uint_08 = streamReader.ReadBE <uint>(active); offset.flags = streamReader.ReadBE <uint>(active); return(offset); }
public static stripInfo ReadStripInfo(BufferedStreamReader streamReader, bool active) { var sInfo = new stripInfo(); sInfo.materialPropertyListOffset = streamReader.ReadBE <uint>(active); sInfo.materialPropertyListSize = streamReader.ReadBE <uint>(active); sInfo.indexListOffset = streamReader.ReadBE <uint>(active); sInfo.indexCount = streamReader.ReadBE <uint>(active); sInfo.uint_10 = streamReader.ReadBE <uint>(active); return(sInfo); }
public static njVTXE ReadNjVtxe(BufferedStreamReader streamReader, bool active) { var vtxe = new njVTXE(); vtxe.vertexType = streamReader.ReadBE <ushort>(active); vtxe.ushort_02 = streamReader.ReadBE <ushort>(active); vtxe.vertexListOffset = streamReader.ReadBE <uint>(active); vtxe.vertexSize = streamReader.ReadBE <uint>(active); vtxe.vertexCount = streamReader.ReadBE <uint>(active); return(vtxe); }
public static njMesh ReadNjMesh(BufferedStreamReader streamReader, bool active) { var mesh = new njMesh(); mesh.flags = streamReader.ReadBE <uint>(active); mesh.vertexInfoListOffset = streamReader.ReadBE <uint>(active); mesh.vertexInfoCount = streamReader.ReadBE <uint>(active); mesh.triangleStripListAOffset = streamReader.ReadBE <uint>(active); mesh.triangleStripListACount = streamReader.ReadBE <uint>(active); mesh.triangleStripListBOffset = streamReader.ReadBE <uint>(active); mesh.triangleStripListBCount = streamReader.ReadBE <uint>(active); mesh.center = streamReader.ReadBEV3(active); mesh.radius = streamReader.ReadBE <float>(active); return(mesh); }
public static relHeader ReadRelHeader(BufferedStreamReader streamReader, bool active) { var header = new relHeader(); header.fmt2 = streamReader.ReadBE <uint>(active); header.uint_04 = streamReader.ReadBE <uint>(active); header.drawCount = streamReader.ReadBE <uint>(active); header.hd = streamReader.ReadBE <float>(active); header.drawOffset = streamReader.ReadBE <uint>(active); header.nameInfoOffset = streamReader.ReadBE <uint>(active); return(header); }
public static Vector4 ReadBEV4(this BufferedStreamReader streamReader, bool active) { return(new Vector4(streamReader.ReadBE <float>(active), streamReader.ReadBE <float>(active), streamReader.ReadBE <float>(active), streamReader.ReadBE <float>(active))); }
//Read njNode public void readNode(Matrix4x4 parentMatrix, int parentId) { njNode node = new njNode(); node.flags = streamReader.ReadBE <uint>(be); node.meshOffset = streamReader.ReadBE <uint>(be); node.pos = streamReader.ReadBEV3(be); var rotX = streamReader.ReadBE <int>(be); var rotY = streamReader.ReadBE <int>(be); var rotZ = streamReader.ReadBE <int>(be); node.rot = new Vector3((float)(rotX * BAMSvalue), (float)(rotY * BAMSvalue), (float)(rotZ * BAMSvalue)); node.scl = streamReader.ReadBEV3(be); node.childOffset = streamReader.ReadBE <uint>(be); node.siblingOffset = streamReader.ReadBE <uint>(be); Matrix4x4 mat = Matrix4x4.Identity; mat *= Matrix4x4.CreateScale(node.scl); var rotation = Matrix4x4.CreateRotationX(node.rot.X) * Matrix4x4.CreateRotationY(node.rot.Y) * Matrix4x4.CreateRotationZ(node.rot.Z); mat *= rotation; mat *= Matrix4x4.CreateTranslation(node.pos * rootScale); //If there's a parent, multiply by it if (parentMatrix != null) { mat = mat * parentMatrix; } //Create AQN node NODE aqNode = new NODE(); aqNode.animatedFlag = 1; aqNode.parentId = parentId; aqNode.unkNode = -1; aqNode.pos = node.pos; aqNode.eulRot = new Vector3((float)((rotX * BAMSvalue) * 180 / Math.PI), (float)((rotY * BAMSvalue) * 180 / Math.PI), (float)((rotZ * BAMSvalue) * 180 / Math.PI)); if (Math.Abs(aqNode.eulRot.Y) > 120) { aqNode.scale = new Vector3(-1, -1, -1); } else { aqNode.scale = new Vector3(1, 1, 1); } Matrix4x4.Invert(mat, out var invMat); aqNode.m1 = new Vector4(invMat.M11, invMat.M12, invMat.M13, invMat.M14); aqNode.m2 = new Vector4(invMat.M21, invMat.M22, invMat.M23, invMat.M24); aqNode.m3 = new Vector4(invMat.M31, invMat.M32, invMat.M33, invMat.M34); aqNode.m4 = new Vector4(invMat.M41, invMat.M42, invMat.M43, invMat.M44); aqNode.boneName.SetString("Node " + nodes.Count); nodes.Add(aqNode); //Not sure what it means when these happen, but sometimes they do. Maybe hardcoded logic? if (node.meshOffset > fileSize || node.siblingOffset > fileSize || node.childOffset > fileSize) { return; } //Read the attached Mesh if (node.meshOffset != 0) { streamReader.Seek(node.meshOffset, SeekOrigin.Begin); readMesh(mat); } //Read the child if (node.childOffset != 0) { streamReader.Seek(node.childOffset, SeekOrigin.Begin); readNode(mat, nodes.Count - 1); } //Read the sibling if (node.siblingOffset != 0) { streamReader.Seek(node.siblingOffset, SeekOrigin.Begin); readNode(parentMatrix, parentId); } }
//Takes in bytes of a *n.rel file from PSO //To convert to PSO2's units, we set the scale to 1/10th scale public PSONRelConvert(byte[] file, string fileName = null, float scale = 0.1f, string outFolder = null) { fileSize = file.Length; rootScale = scale; List <dSection> dSections = new List <dSection>(); streamReader = new BufferedStreamReader(new MemoryStream(file), 8192); //Get header offset streamReader.Seek(file.Length - 0x10, SeekOrigin.Begin); //Check Endianness. No offset should ever come close to half of the int max value. be = streamReader.PeekBigEndianPrimitiveUInt32() < streamReader.Peek <uint>(); if (be) { MessageBox.Show("Sorry, Gamecube n.rel files are not supported at this time."); } uint tableOfs = streamReader.ReadBE <uint>(be); //Read header streamReader.Seek(tableOfs, SeekOrigin.Begin); var header = ReadRelHeader(streamReader, be); //Read draw Sections streamReader.Seek(header.drawOffset, SeekOrigin.Begin); for (int i = 0; i < header.drawCount; i++) { dSection section = new dSection(); section.id = streamReader.ReadBE <int>(be); section.pos = streamReader.ReadBEV3(be); var rotX = streamReader.ReadBE <int>(be); var rotY = streamReader.ReadBE <int>(be); var rotZ = streamReader.ReadBE <int>(be); section.rot = new Vector3((float)(rotX * BAMSvalue), (float)(rotY * BAMSvalue), (float)(rotZ * BAMSvalue)); section.radius = streamReader.ReadBE <float>(be); section.staticOffset = streamReader.ReadBE <uint>(be); section.animatedOffset = streamReader.ReadBE <uint>(be); section.staticCount = streamReader.ReadBE <uint>(be); section.animatedCount = streamReader.ReadBE <uint>(be); section.end = streamReader.ReadBE <uint>(be); dSections.Add(section); } //Get texture names streamReader.Seek(header.nameInfoOffset, SeekOrigin.Begin); var nameOffset = streamReader.ReadBE <uint>(be); var nameCount = streamReader.ReadBE <uint>(be); streamReader.Seek(nameOffset, SeekOrigin.Begin); List <uint> nameOffsets = new List <uint>(); for (int i = 0; i < nameCount; i++) { nameOffsets.Add(streamReader.ReadBE <uint>(be)); var unk0 = streamReader.ReadBE <uint>(be); var unk1 = streamReader.ReadBE <uint>(be); if (unk0 != 0) { Console.WriteLine($"Iteration {i} unk0 == {unk0}"); } if (unk1 != 0) { Console.WriteLine($"Iteration {i} unk1 == {unk1}"); } } foreach (uint offset in nameOffsets) { streamReader.Seek(offset, SeekOrigin.Begin); texNames.Add(AquaObjectMethods.ReadCString(streamReader)); } //If there's an .xvm, dump that too with texture names from the .rel if (fileName != null) { //Naming patterns for *n.rel files are *_12n.rel for example or *n.rel vs *.xvm. We can determine which we have, edit, and proceed var basename = fileName.Substring(0, fileName.Length - 5); string xvmName = null; if (basename.ElementAt(basename.Length - 3) == '_') { xvmName = basename.Substring(0, basename.Length - 3) + ".xvm"; } else { xvmName = basename + ".xvm"; } ExtractXVM(xvmName, texNames, outFolder); } //Create root AQN node NODE aqNode = new NODE(); aqNode.animatedFlag = 1; aqNode.parentId = -1; aqNode.unkNode = -1; aqNode.pos = new Vector3(); aqNode.eulRot = new Vector3(); aqNode.scale = new Vector3(1, 1, 1); aqNode.m1 = new Vector4(1, 0, 0, 0); aqNode.m2 = new Vector4(0, 1, 0, 0); aqNode.m3 = new Vector4(0, 0, 1, 0); aqNode.m4 = new Vector4(0, 0, 0, 1); aqNode.boneName.SetString("RootNode"); nodes.Add(aqNode); //Loop through nodes and parse geometry for (int i = 0; i < dSections.Count; i++) { var matrix = Matrix4x4.Identity; matrix *= Matrix4x4.CreateScale(1, 1, 1); var rotation = Matrix4x4.CreateRotationX(dSections[i].rot.X) * Matrix4x4.CreateRotationY(dSections[i].rot.Y) * Matrix4x4.CreateRotationZ(dSections[i].rot.Z); matrix *= rotation; matrix *= Matrix4x4.CreateTranslation(dSections[i].pos * rootScale); //Read static meshes List <staticMeshOffset> staticMeshOffsets = new List <staticMeshOffset>(); streamReader.Seek(dSections[i].staticOffset, SeekOrigin.Begin); for (int st = 0; st < dSections[i].staticCount; st++) { staticMeshOffsets.Add(ReadStaticMeshOffset(streamReader, be)); } for (int ofs = 0; ofs < staticMeshOffsets.Count; ofs++) { streamReader.Seek(staticMeshOffsets[ofs].offset, SeekOrigin.Begin); readNode(matrix, 0); } //Read animated meshes List <animMeshOffset> animatedMeshOffsets = new List <animMeshOffset>(); streamReader.Seek(dSections[i].animatedOffset, SeekOrigin.Begin); for (int st = 0; st < dSections[i].animatedCount; st++) { animatedMeshOffsets.Add(ReadAnimMeshOffset(streamReader, be)); } for (int ofs = 0; ofs < animatedMeshOffsets.Count; ofs++) { streamReader.Seek(animatedMeshOffsets[ofs].offset, SeekOrigin.Begin); readNode(matrix, 0); } } //Set material names for (int i = 0; i < aqObj.tempMats.Count; i++) { aqObj.tempMats[i].matName = $"PSOMat {i}"; } }