internal Texture(BinaryReaderEx br, FLVERHeader header) { int pathOffset = br.ReadInt32(); int typeOffset = br.ReadInt32(); Scale = br.ReadVector2(); Unk10 = br.AssertByte(0, 1, 2); Unk11 = br.ReadBoolean(); br.AssertByte(0); br.AssertByte(0); Unk14 = br.ReadSingle(); Unk18 = br.ReadSingle(); Unk1C = br.ReadSingle(); if (header.Unicode) { Type = br.GetUTF16(typeOffset); Path = br.GetUTF16(pathOffset); } else { Type = br.GetShiftJIS(typeOffset); Path = br.GetShiftJIS(pathOffset); } }
internal Bone(BinaryReaderEx br, FLVERHeader header) { Position = br.ReadVector3(); int nameOffset = br.ReadInt32(); Rotation = br.ReadVector3(); ParentIndex = br.ReadInt16(); ChildIndex = br.ReadInt16(); Scale = br.ReadVector3(); NextSiblingIndex = br.ReadInt16(); PreviousSiblingIndex = br.ReadInt16(); BoundingBoxMin = br.ReadVector3(); Unk3C = br.ReadInt32(); BoundingBoxMax = br.ReadVector3(); br.AssertPattern(0x34, 0x00); if (header.Unicode) { Name = br.GetUTF16(nameOffset); } else { Name = br.GetShiftJIS(nameOffset); } }
internal Mesh(BinaryReaderEx br, FLVERHeader header) { Dynamic = br.ReadBoolean(); br.AssertByte(0); br.AssertByte(0); br.AssertByte(0); MaterialIndex = br.ReadInt32(); br.AssertInt32(0); br.AssertInt32(0); DefaultBoneIndex = br.ReadInt32(); int boneCount = br.ReadInt32(); int boundingBoxOffset = br.ReadInt32(); int boneOffset = br.ReadInt32(); int faceSetCount = br.ReadInt32(); int faceSetOffset = br.ReadInt32(); int vertexBufferCount = br.AssertInt32(1, 2, 3); int vertexBufferOffset = br.ReadInt32(); if (boundingBoxOffset != 0) { br.StepIn(boundingBoxOffset); { BoundingBox = new BoundingBoxes(br, header); } br.StepOut(); } BoneIndices = new List <int>(br.GetInt32s(boneOffset, boneCount)); faceSetIndices = br.GetInt32s(faceSetOffset, faceSetCount); vertexBufferIndices = br.GetInt32s(vertexBufferOffset, vertexBufferCount); }
internal BoundingBoxes(BinaryReaderEx br, FLVERHeader header) { Min = br.ReadVector3(); Max = br.ReadVector3(); if (header.Version >= 0x2001A) { Unk = br.ReadVector3(); } }
internal void Write(BinaryWriterEx bw, FLVERHeader header) { bw.WriteVector3(Min); bw.WriteVector3(Max); if (header.Version >= 0x2001A) { bw.WriteVector3(Unk); } }
/// <summary> /// Creates a FLVER with a default header and empty lists. /// </summary> public FLVER2() { Header = new FLVERHeader(); Dummies = new List <FLVER.Dummy>(); Materials = new List <Material>(); GXLists = new List <GXList>(); Bones = new List <FLVER.Bone>(); Meshes = new List <Mesh>(); BufferLayouts = new List <BufferLayout>(); }
internal FaceSet(BinaryReaderEx br, FLVERHeader header, int headerIndexSize, int dataOffset) { Flags = (FSFlags)br.ReadUInt32(); TriangleStrip = br.ReadBoolean(); CullBackfaces = br.ReadBoolean(); Unk06 = br.ReadInt16(); int indexCount = br.ReadInt32(); int indicesOffset = br.ReadInt32(); int indexSize = 0; if (header.Version > 0x20005) { br.ReadInt32(); // Indices length br.AssertInt32(0); indexSize = br.AssertInt32(0, 16, 32); br.AssertInt32(0); } if (indexSize == 0) { indexSize = headerIndexSize; } if (indexSize == 8 ^ Flags.HasFlag(FSFlags.EdgeCompressed)) { throw new InvalidDataException("FSFlags.EdgeCompressed probably doesn't mean edge compression after all. Please investigate this."); } if (indexSize == 8) { br.StepIn(dataOffset + indicesOffset); { Indices = EdgeIndexCompression.ReadEdgeIndexGroup(br, indexCount); } br.StepOut(); } else if (indexSize == 16) { Indices = new List <int>(indexCount); foreach (ushort index in br.GetUInt16s(dataOffset + indicesOffset, indexCount)) { Indices.Add(index); } } else if (indexSize == 32) { Indices = new List <int>(br.GetInt32s(dataOffset + indicesOffset, indexCount)); } else { throw new NotImplementedException($"Unsupported index size: {indexSize}"); } }
internal void Write(BinaryWriterEx bw, FLVERHeader header) { foreach (GXItem item in this) { item.Write(bw, header); } bw.WriteInt32(int.MaxValue); bw.WriteInt32(100); bw.WriteInt32(TerminatorLength + 0xC); bw.WritePattern(TerminatorLength, 0x00); }
internal GXList(BinaryReaderEx br, FLVERHeader header) : base() { while (br.GetInt32(br.Position) != int.MaxValue) { Add(new GXItem(br, header)); } br.AssertInt32(int.MaxValue); br.AssertInt32(100); TerminatorLength = br.ReadInt32() - 0xC; br.AssertPattern(TerminatorLength, 0x00); }
internal void WriteBoundingBox(BinaryWriterEx bw, int index, FLVERHeader header) { if (BoundingBox == null) { bw.FillInt32($"MeshBoundingBox{index}", 0); } else { bw.FillInt32($"MeshBoundingBox{index}", (int)bw.Position); BoundingBox.Write(bw, header); } }
internal void WriteStrings(BinaryWriterEx bw, FLVERHeader header, int index) { bw.FillInt32($"BoneName{index}", (int)bw.Position); if (header.Unicode) { bw.WriteUTF16(Name, true); } else { bw.WriteShiftJIS(Name, true); } }
internal void Write(BinaryWriterEx bw, FLVERHeader header, int index, int bufferIndex, List <BufferLayout> layouts, int vertexCount) { BufferLayout layout = layouts[LayoutIndex]; bw.WriteInt32(bufferIndex); bw.WriteInt32(LayoutIndex); bw.WriteInt32(layout.Size); bw.WriteInt32(vertexCount); bw.WriteInt32(0); bw.WriteInt32(0); bw.WriteInt32(header.Version > 0x20005 ? layout.Size * vertexCount : 0); bw.ReserveInt32($"VertexBufferOffset{index}"); }
internal GXItem(BinaryReaderEx br, FLVERHeader header) { if (header.Version <= 0x20010) { ID = br.ReadInt32().ToString(); } else { ID = br.ReadFixStr(4); } Unk04 = br.ReadInt32(); int length = br.ReadInt32(); Data = br.ReadBytes(length - 0xC); }
internal FaceSet(BinaryReaderEx br, FLVERHeader header, FlverCache cache, int headerIndexSize, int dataOffset) { Flags = (FSFlags)br.ReadUInt32(); TriangleStrip = br.ReadBoolean(); CullBackfaces = br.ReadBoolean(); Unk06 = br.ReadByte(); Unk07 = br.ReadByte(); int indexCount = br.ReadInt32(); int indicesOffset = br.ReadInt32(); int indexSize = 0; if (header.Version > 0x20005) { br.ReadInt32(); // Indices length br.AssertInt32(0); indexSize = br.AssertInt32(0, 16, 32); br.AssertInt32(0); } if (indexSize == 0) { indexSize = headerIndexSize; } if (indexSize == 16) { //Indices = new int[indexCount]; IndicesCount = indexCount; Indices = cache.GetCachedIndices(indexCount); int i = 0; foreach (ushort index in br.GetUInt16s(dataOffset + indicesOffset, indexCount)) { Indices[i] = index; i++; } } else if (indexSize == 32) { IndicesCount = indexCount; Indices = br.GetInt32s(dataOffset + indicesOffset, indexCount); } else { throw new NotImplementedException($"Unsupported index size: {indexSize}"); } }
internal void Write(BinaryWriterEx bw, FLVERHeader header, int indexSize, int index) { bw.WriteUInt32((uint)Flags); bw.WriteBoolean(TriangleStrip); bw.WriteBoolean(CullBackfaces); bw.WriteInt16(Unk06); bw.WriteInt32(Indices.Count); bw.ReserveInt32($"FaceSetVertices{index}"); if (header.Version > 0x20005) { bw.WriteInt32(Indices.Count * (indexSize / 8)); bw.WriteInt32(0); bw.WriteInt32(header.Version >= 0x20013 ? indexSize : 0); bw.WriteInt32(0); } }
internal void Write(BinaryWriterEx bw, FLVERHeader header) { if (header.Version < 0x20010) { this[0].Write(bw, header); } else { foreach (GXItem item in this) { item.Write(bw, header); } bw.WriteInt32(TerminatorID); bw.WriteInt32(100); bw.WriteInt32(TerminatorLength + 0xC); bw.WritePattern(TerminatorLength, 0x00); } }
internal Material(BinaryReaderEx br, FLVERHeader header, List <GXList> gxLists, Dictionary <int, int> gxListIndices) { int nameOffset = br.ReadInt32(); int mtdOffset = br.ReadInt32(); textureCount = br.ReadInt32(); textureIndex = br.ReadInt32(); Flags = br.ReadInt32(); int gxOffset = br.ReadInt32(); Unk18 = br.ReadInt32(); br.AssertInt32(0); if (header.Unicode) { Name = br.GetUTF16(nameOffset); MTD = br.GetUTF16(mtdOffset); } else { Name = br.GetShiftJIS(nameOffset); MTD = br.GetShiftJIS(mtdOffset); } if (gxOffset == 0) { GXIndex = -1; } else { if (!gxListIndices.ContainsKey(gxOffset)) { br.StepIn(gxOffset); { gxListIndices[gxOffset] = gxLists.Count; gxLists.Add(new GXList(br, header)); } br.StepOut(); } GXIndex = gxListIndices[gxOffset]; } }
internal GXList(BinaryReaderEx br, FLVERHeader header) : base() { if (header.Version < 0x20010) { Add(new GXItem(br, header)); } else { int id; while ((id = br.GetInt32(br.Position)) != int.MaxValue && id != -1) { Add(new GXItem(br, header)); } TerminatorID = br.AssertInt32(id); br.AssertInt32(100); TerminatorLength = br.ReadInt32() - 0xC; br.AssertPattern(TerminatorLength, 0x00); } }
internal void Write(BinaryWriterEx bw, FLVERHeader header) { if (header.Version <= 0x20010) { if (int.TryParse(ID, out int id)) { bw.WriteInt32(id); } else { throw new FormatException("For Dark Souls 2, GX IDs must be convertible to int."); } } else { bw.WriteFixStr(ID, 4); } bw.WriteInt32(Unk04); bw.WriteInt32(Data.Length + 0xC); bw.WriteBytes(Data); }
internal void WriteStrings(BinaryWriterEx bw, FLVERHeader header, int index) { bw.FillInt32($"TexturePath{index}", (int)bw.Position); if (header.Unicode) { bw.WriteUTF16(Path, true); } else { bw.WriteShiftJIS(Path, true); } bw.FillInt32($"TextureType{index}", (int)bw.Position); if (header.Unicode) { bw.WriteUTF16(Type, true); } else { bw.WriteShiftJIS(Type, true); } }
internal void Write(BinaryWriterEx bw, FLVERHeader header) { bw.WriteVector3(Position); if (header.Version == 0x20010) { bw.WriteBGRA(Color); } else { bw.WriteARGB(Color); } bw.WriteVector3(Forward); bw.WriteInt16(ReferenceID); bw.WriteInt16(DummyBoneIndex); bw.WriteVector3(Upward); bw.WriteInt16(AttachBoneIndex); bw.WriteBoolean(Flag1); bw.WriteBoolean(UseUpwardVector); bw.WriteInt32(Unk30); bw.WriteInt32(Unk34); bw.WriteInt32(0); bw.WriteInt32(0); }
internal Dummy(BinaryReaderEx br, FLVERHeader header) { Position = br.ReadVector3(); // Not certain about the ordering of RGB here if (header.Version == 0x20010) { Color = br.ReadBGRA(); } else { Color = br.ReadARGB(); } Forward = br.ReadVector3(); ReferenceID = br.ReadInt16(); DummyBoneIndex = br.ReadInt16(); Upward = br.ReadVector3(); AttachBoneIndex = br.ReadInt16(); Flag1 = br.ReadBoolean(); UseUpwardVector = br.ReadBoolean(); Unk30 = br.ReadInt32(); Unk34 = br.ReadInt32(); br.AssertInt32(0); br.AssertInt32(0); }
/// <summary> /// Reads FLVER data from a BinaryReaderEx. /// </summary> protected override void Read(BinaryReaderEx br) { if (Cache == null) { Cache = new FlverCache(); } br.BigEndian = false; Header = new FLVERHeader(); br.AssertASCII("FLVER\0"); Header.BigEndian = br.AssertASCII("L\0", "B\0") == "B\0"; br.BigEndian = Header.BigEndian; // Gundam Unicorn: 0x20005, 0x2000E // DS1: 2000C, 2000D // DS2 NT: 2000F, 20010 // DS2: 20010, 20009 (armor 9320) // SFS: 20010 // BB: 20013, 20014 // DS3: 20013, 20014 // SDT: 2001A, 20016 (test chr) Header.Version = br.AssertInt32(0x20005, 0x20009, 0x2000C, 0x2000D, 0x2000E, 0x2000F, 0x20010, 0x20013, 0x20014, 0x20016, 0x2001A); int dataOffset = br.ReadInt32(); br.ReadInt32(); // Data length int dummyCount = br.ReadInt32(); int materialCount = br.ReadInt32(); int boneCount = br.ReadInt32(); int meshCount = br.ReadInt32(); int vertexBufferCount = br.ReadInt32(); Header.BoundingBoxMin = br.ReadVector3(); Header.BoundingBoxMax = br.ReadVector3(); br.ReadInt32(); // Face count not including motion blur meshes or degenerate faces br.ReadInt32(); // Total face count int vertexIndicesSize = br.AssertByte(0, 16, 32); Header.Unicode = br.ReadBoolean(); Header.Unk4A = br.ReadBoolean(); br.AssertByte(0); Header.Unk4C = br.ReadInt32(); int faceSetCount = br.ReadInt32(); int bufferLayoutCount = br.ReadInt32(); int textureCount = br.ReadInt32(); Header.Unk5C = br.ReadByte(); Header.Unk5D = br.ReadByte(); br.AssertByte(0); br.AssertByte(0); br.AssertInt32(0); br.AssertInt32(0); Header.Unk68 = br.AssertInt32(0, 1, 2, 3, 4); br.AssertInt32(0); br.AssertInt32(0); br.AssertInt32(0); br.AssertInt32(0); br.AssertInt32(0); Dummies = new List <FLVER.Dummy>(dummyCount); for (int i = 0; i < dummyCount; i++) { Dummies.Add(new FLVER.Dummy(br, Header.Version)); } Materials = new List <Material>(materialCount); var gxListIndices = new Dictionary <int, int>(); GXLists = new List <GXList>(); for (int i = 0; i < materialCount; i++) { Materials.Add(new Material(br, Header, GXLists, gxListIndices)); } Bones = new List <FLVER.Bone>(boneCount); for (int i = 0; i < boneCount; i++) { Bones.Add(new FLVER.Bone(br, Header.Unicode)); } Meshes = new List <Mesh>(meshCount); for (int i = 0; i < meshCount; i++) { Meshes.Add(new Mesh(br, Header)); } var faceSets = new List <FaceSet>(faceSetCount); for (int i = 0; i < faceSetCount; i++) { faceSets.Add(new FaceSet(br, Header, Cache, vertexIndicesSize, dataOffset)); } var vertexBuffers = new List <VertexBuffer>(vertexBufferCount); for (int i = 0; i < vertexBufferCount; i++) { vertexBuffers.Add(new VertexBuffer(br)); } BufferLayouts = new List <BufferLayout>(bufferLayoutCount); for (int i = 0; i < bufferLayoutCount; i++) { BufferLayouts.Add(new BufferLayout(br)); } var textures = new List <Texture>(textureCount); for (int i = 0; i < textureCount; i++) { textures.Add(new Texture(br, Header)); } if (Header.Version >= 0x2001A) { SekiroUnk = new SekiroUnkStruct(br); } Dictionary <int, Texture> textureDict = SFUtil.Dictionize(textures); foreach (Material material in Materials) { material.TakeTextures(textureDict); } if (textureDict.Count != 0) { throw new NotSupportedException("Orphaned textures found."); } Dictionary <int, FaceSet> faceSetDict = SFUtil.Dictionize(faceSets); Dictionary <int, VertexBuffer> vertexBufferDict = SFUtil.Dictionize(vertexBuffers); foreach (Mesh mesh in Meshes) { mesh.TakeFaceSets(faceSetDict); mesh.TakeVertexBuffers(vertexBufferDict, BufferLayouts); mesh.ReadVertices(br, dataOffset, BufferLayouts, Header, Cache); } if (faceSetDict.Count != 0) { throw new NotSupportedException("Orphaned face sets found."); } if (vertexBufferDict.Count != 0) { throw new NotSupportedException("Orphaned vertex buffers found."); } }
internal void ReadVertices(BinaryReaderEx br, int dataOffset, List <BufferLayout> layouts, FLVERHeader header, FlverCache cache) { var layoutMembers = layouts.SelectMany(l => l); int uvCap = layoutMembers.Where(m => m.Semantic == FLVER.LayoutSemantic.UV).Count(); int tanCap = layoutMembers.Where(m => m.Semantic == FLVER.LayoutSemantic.Tangent).Count(); int colorCap = layoutMembers.Where(m => m.Semantic == FLVER.LayoutSemantic.VertexColor).Count(); VertexCount = VertexBuffers[0].VertexCount; Vertices = cache.GetCachedVertexArray(VertexCount); if (Vertices == null) { Vertices = new FLVER.Vertex[VertexCount]; for (int i = 0; i < VertexCount; i++) { Vertices[i] = new FLVER.Vertex(uvCap, tanCap, colorCap); } cache.CacheVertexArray(Vertices); } else { for (int i = 0; i < Vertices.Length; i++) { Vertices[i].UVCount = 0; Vertices[i].TangentCount = 0; } } foreach (VertexBuffer buffer in VertexBuffers) { buffer.ReadBuffer(br, layouts, Vertices, VertexCount, dataOffset, header); } }
internal void ReadVertices(BinaryReaderEx br, int dataOffset, List <BufferLayout> layouts, FLVERHeader header) { var layoutMembers = layouts.SelectMany(l => l); int uvCap = layoutMembers.Where(m => m.Semantic == FLVER.LayoutSemantic.UV).Count(); int tanCap = layoutMembers.Where(m => m.Semantic == FLVER.LayoutSemantic.Tangent).Count(); int colorCap = layoutMembers.Where(m => m.Semantic == FLVER.LayoutSemantic.VertexColor).Count(); int vertexCount = VertexBuffers[0].VertexCount; Vertices = new List <FLVER.Vertex>(vertexCount); for (int i = 0; i < vertexCount; i++) { Vertices.Add(new FLVER.Vertex(uvCap, tanCap, colorCap)); } foreach (VertexBuffer buffer in VertexBuffers) { buffer.ReadBuffer(br, layouts, Vertices, dataOffset, header); } }
internal void ReadBuffer(BinaryReaderEx br, List <BufferLayout> layouts, FLVER.Vertex[] vertices, int count, int dataOffset, FLVERHeader header) { BufferLayout layout = layouts[LayoutIndex]; if (VertexSize != layout.Size) { throw new InvalidDataException($"Mismatched vertex buffer and buffer layout sizes."); } br.StepIn(dataOffset + BufferOffset); { float uvFactor = 1024; if (header.Version >= 0x2000F) { uvFactor = 2048; } for (int i = 0; i < count; i++) { vertices[i].Read(br, layout, uvFactor); } } br.StepOut(); VertexSize = -1; BufferIndex = -1; VertexCount = -1; BufferOffset = -1; }
internal void WriteBuffer(BinaryWriterEx bw, int index, List <BufferLayout> layouts, FLVER.Vertex[] Vertices, int dataStart, FLVERHeader header) { BufferLayout layout = layouts[LayoutIndex]; bw.FillInt32($"VertexBufferOffset{index}", (int)bw.Position - dataStart); float uvFactor = 1024; if (header.Version >= 0x2000F) { uvFactor = 2048; } foreach (FLVER.Vertex vertex in Vertices) { vertex.Write(bw, layout, uvFactor); } }