internal override void ReadBody(EndianBinaryReader reader) { long nameOffset = reader.ReadOffset(); int count = reader.ReadInt32(); long boneIDsOffset = reader.ReadOffset(); long boneMatricesOffset = reader.ReadOffset(); BoneIDs.Capacity = BoneMatrices.Capacity = count; Name = reader.ReadStringAtOffset(nameOffset, StringBinaryFormat.NullTerminated); reader.ReadAtOffset(boneIDsOffset, () => { for (int i = 0; i < count; i++) { BoneIDs.Add(reader.ReadInt32()); } }); reader.ReadAtOffset(boneMatricesOffset, () => { for (int i = 0; i < count; i++) { BoneMatrices.Add(reader.ReadMatrix4x4()); } }); }
public static NUD LoadNud(byte[] fileBytes, int index, bool header) { int x = index; int headerSize = 0; int fileStart = index; int fileSize; int meshIndex = 0; int ndp3Size = fileBytes[x + 0x05] * 0x10000 + fileBytes[x + 0x06] * 0x100 + fileBytes[x + 0x07]; int sec1Index = x + 0x30; int groupCount = fileBytes[sec1Index + 0x2B]; int vertCount = 0; byte[] nudFile; List <Group> groupBytes = new List <Group>(); List <Polygon> poly = new List <Polygon>(); if (header) { if (fileBytes[x - 4] != 0x00) { headerSize = 0x40; fileStart = x - headerSize; } else { headerSize = 0x28; fileStart = x - headerSize; } fileSize = headerSize + ndp3Size + 0x02 + (groupCount * 0x04); nudFile = new byte[fileSize]; Array.Copy(fileBytes, fileStart, nudFile, 0, fileSize); x = headerSize; sec1Index = x + 0x30; meshIndex = nudFile[0x07]; } else { fileSize = ndp3Size + 0x02; nudFile = fileBytes; } for (int a = 0; a < groupCount; a++) { int matIndexp = x + BigBitConverter.ToInt16(nudFile, sec1Index + 0x42 + (a * 0x30)); string matNamep = BitConverter.ToString(nudFile, matIndexp + 1, 3).Replace('-', ' '); if (matNamep[1] == '0') { matNamep = matNamep.TrimStart('0', '0', ' '); } poly.Add(new Polygon { VertCount = BigBitConverter.ToInt16(nudFile, sec1Index + 0x3C + (a * 0x30)), FormatByte = nudFile[sec1Index + 0x3E + (a * 0x30)], MatName = matNamep, EndByte = 0 }); vertCount += poly[a].VertCount; if (header) { poly[a].EndByte = nudFile[(x - 1) + ndp3Size + 0x06 + (a * 4)]; groupBytes.Add(new Group { EndByte = poly[a].EndByte, Name = "" }); } } int sec1Size = BigBitConverter.ToInt32(nudFile, x + 0x10); int triSize = BigBitConverter.ToInt32(nudFile, x + 0x14); int triIndex = sec1Index + sec1Size; int uvSize = BigBitConverter.ToInt32(nudFile, x + 0x18); int uvIndex = triIndex + triSize; int vertSize = BigBitConverter.ToInt32(nudFile, x + 0x1C); int vertIndex = uvIndex + uvSize; int vertFormat = nudFile[sec1Index + 0x27]; // either 0x14 or 0x00, for stating if there are vertices or not int matIndex = x + BigBitConverter.ToInt16(nudFile, sec1Index + 0x42); bool mirrorState = false; int mirrorByte = BigBitConverter.ToInt16(nudFile, matIndex + 0x12); // mirrorState = CullMode if (mirrorByte == 0x00) { mirrorState = true; // true for ASB models with no bod1_f, else false } string matName = BitConverter.ToString(nudFile, matIndex + 1, 3).Replace('-', ' '); if (matName[1] == '0') { matName = matName.TrimStart('0', '0', ' '); } string meshName = Encoding.Default.GetString(nudFile.ToArray(), vertIndex + vertSize, 0x20); meshName = meshName.Remove(meshName.IndexOf("\0")); // Credit goes to the Smash Forge team for mesh formats string meshFormatName = ""; foreach (Polygon p in poly) { switch (p.FormatByte) { case 0x06: // Storm teeth/eyes // NormalsHalfFloat p.MeshFormat = 0x1C; break; case 0x20: // Storm effects (not ready) p.MeshFormat = 0x20; break; case 0x07: // JoJo teeth // NormalsTanBiTanHalfFloat p.MeshFormat = 0x2C; break; case 0x30: // JoJo teeth (not ready) p.MeshFormat = 0x30; break; case 0x11: // Storm most meshes + JoJo eyes // NormalsFloat p.MeshFormat = 0x40; p.BoneOffset = 0x20; break; case 0x13: // JoJo most meshes // NormalsTanBiTanFloat p.MeshFormat = 0x60; p.BoneOffset = 0x40; break; default: if (vertSize == 0) { p.MeshFormat = uvSize / vertCount; } else { p.MeshFormat = vertSize / vertCount; } break; } // Only last format for now meshFormatName = "0x" + BitConverter.ToString(BitConverter.GetBytes(p.MeshFormat)).Substring(0, 2); } int vertSum = 0; int maxBone = 0; List <BoneBytes> bones = new List <BoneBytes>(); for (int a = 0; a < poly.Count; a++) { if (poly[a].BoneOffset != 0) { for (int i = 0; i < poly[a].VertCount; i++) { BoneBytes bytes = new BoneBytes() { Id1 = nudFile[vertIndex + vertSum + poly[a].BoneOffset + 0x03 + (i * poly[a].MeshFormat)], Id2 = nudFile[vertIndex + vertSum + poly[a].BoneOffset + 0x07 + (i * poly[a].MeshFormat)], Id3 = nudFile[vertIndex + vertSum + poly[a].BoneOffset + 0x0B + (i * poly[a].MeshFormat)] }; int IdMax1 = Math.Max(bytes.Id1, bytes.Id2); int IdMax2 = Math.Max(bytes.Id3, IdMax1); if (IdMax2 > maxBone) { maxBone = IdMax2; } if (!BoneIDs.Contains(bytes.Id1)) { BoneIDs.Add(bytes.Id1); } if (!BoneIDs.Contains(bytes.Id2)) { BoneIDs.Add(bytes.Id2); } if (!BoneIDs.Contains(bytes.Id3)) { BoneIDs.Add(bytes.Id3); } bones.Add(bytes); } vertSum += poly[a].VertCount * poly[a].MeshFormat; } } BoneIDs = BoneIDs.OrderBy(l => l).ToList(); return(new NUD { MeshName = meshName, MeshFormat = meshFormatName, NudIndex = fileStart + headerSize, FileStart = fileStart, HeaderSize = headerSize, FileSize = fileSize, NDP3Size = ndp3Size, MeshIndex = meshIndex, TriIndex = triIndex, TriSize = triSize, UVIndex = uvIndex, UVSize = uvSize, VertIndex = vertIndex, VertSize = vertSize, VertFormat = vertFormat, GroupCount = groupCount, Material = matName, Mirror = mirrorState, NudFile = nudFile.ToList(), GroupBytes = groupBytes, Bones = bones, MaxBone = maxBone, Polygons = poly }); }