/// <summary> /// Create <see cref="FolderAsset"/>s as necessary to store this asset within a path and set the name of this asset to the last name in the path. /// </summary> /// <param name="path"></param> protected void MoveIntoPath(params string[] path) { int index = 0; if (path[0].Length == 0) { index = 1; } Asset target = Parent; for (; index < path.Length - 1; index++) { string name = path[index]; bool found = false; foreach (Asset child in target.Children) { if (child is FolderAsset && child.Name == name) { target = child; found = true; } } if (!found) { target = new FolderAsset((FolderAsset)target, name); } } Parent = target; Name = path[index]; }
/// <summary>Initialise the asset.</summary> /// <param name="folder"></param> /// <param name="name"></param> /// <param name="colors"></param> public PaletteAsset(FolderAsset folder, string name, IEnumerable <Color> colors) : base(folder, name) { if (colors != null) { ColorsMutable.AddRange(colors); } }
internal ModelBoneUnknown(FolderAsset bonesFolder, int index, AssetLoader loader) : base(bonesFolder, index, loader) { var reader = loader.Reader; Unknowns.ReadSingles(reader, 3); reader.Require(IsDS1 ? 0xFFFFFFFFu : 0xFF000000u); Unknowns.ReadSingles(reader, 3); Unknowns.ReadInt16s(reader, 2); Unknowns.ReadSingles(reader, 3); Unknowns.ReadInt16s(reader, 2); reader.RequireZeroes(4 * 4); }
internal ModelBone(FolderAsset folder, int index, AssetLoader loader) : base(folder, index, loader) { var reader = loader.Reader; Position = reader.ReadVector3f(); Name = reader.ReadStringzAtUInt32(Encoding); Angle = Angle3.Radians(reader.ReadVector3f()); parentIndex = reader.ReadInt16(); firstChildIndex = reader.ReadInt16(); Scale = reader.ReadVector3f(); nextSiblingIndex = reader.ReadInt16(); previousSiblingIndex = reader.ReadInt16(); var min = reader.ReadVector3f(); Unknowns.ReadInt32s(reader, 1); // 0 or 1 var max = reader.ReadVector3f(); Bounds = new Box3f(min, max); reader.RequireZeroes(4 * 13); }
internal ModelMesh(FolderAsset folder, int index, AssetLoader loader) : base(folder, index, loader) { var reader = loader.Reader; Unknowns.ReadInt32s(reader, 1); // 1? MaterialIndex = reader.ReadInt32(); reader.RequireZeroes(4 * 2); Unknowns.ReadInt32s(reader, 1); // 0 or 1, seems to be material-related but is not transparency; second seems bones-related int boneCount = reader.ReadInt32(); reader.RequireZeroes(4 * 1); int boneIndicesOffset = reader.ReadInt32(); PartCount = reader.ReadInt32(); int partIndicesOffset = reader.ReadInt32(); reader.Require(1); int indexOffset = reader.ReadInt32(); long reset = reader.BaseStream.Position; reader.BaseStream.Position = boneIndicesOffset; var bones = new Codex<ModelBone>(); Bones = bones; for (int i = 0; i < boneCount; i++) bones.Add(Model.Bones[reader.ReadInt32()]); // Read the part indices. reader.BaseStream.Position = partIndicesOffset; int partStart = PartStartIndex; for (int i = 0; i < PartCount; i++) reader.Require(i + partStart); reader.BaseStream.Position = indexOffset; reader.Require(Index); reader.BaseStream.Position = reset; }
internal ModelVertexDeclaration(FolderAsset folder, int index, AssetLoader loader) : base(folder, index, loader) { var reader = loader.Reader; int count = reader.ReadInt32(); reader.RequireZeroes(4 * 2); int offset = reader.ReadInt32(); long reset = reader.BaseStream.Position; reader.BaseStream.Position = offset; var blocks = new Codex<ModelVertexAttribute>(); Attributes = blocks; for (int blockIndex = 0; blockIndex < count; blockIndex++) blocks.Add(new ModelVertexAttribute(this, loader, blockIndex)); reader.BaseStream.Position = reset; }
/// <summary>Initialise the asset.</summary> /// <param name="folder"></param> /// <param name="name"></param> /// <param name="colors"></param> public PaletteAsset(FolderAsset folder, string name, params Color[] colors) : this(folder, name, (IEnumerable <Color>)colors) { }
internal Model(AssetLoader loader) : base(loader) { Asset context = loader.Context; string name = loader.Name; BinaryReader reader = loader.Reader; FolderAsset textureArchive = null; FolderAsset bonesFolder = new FolderAsset(this, "Bones"); FolderAsset materialsFolder = new FolderAsset(this, "Materials"); FolderAsset meshesFolder = new FolderAsset(this, "Meshes"); FolderAsset vertexDeclarationsFolder = new FolderAsset(this, "Vertex declarations"); ArrayBackedList<byte> bufferData = new ArrayBackedList<byte>(); if (context != null && context.Parent is FolderAsset) { // @"/map/m##_##_##_##/m*.flver.dcx" for DS1; textures are in the @"/map/m##/" folder. if (name.StartsWith(@"map/m")) { string folderName = name.Substring(4, 3); FolderAsset maps = (FolderAsset)context.Parent.Parent; foreach (FolderAsset child in maps.Children) { if (child.Name == folderName) { textureArchive = child; break; } } } else textureArchive = (FolderAsset)context.Parent; } #if Marking MarkingStream markingStream = loader.StartMarking(out reader); #endif loader.ExpectMagic(Magic); char endian = (char)reader.ReadByte(); switch (endian) { case 'L': ByteOrder = ByteOrder.LittleEndian; break; case 'B': reader = loader.MakeBigEndian(); ByteOrder = ByteOrder.BigEndian; break; default: throw new Exception(); } using (reader) { // Read header. loader.Expect((byte)0); Version = (ModelVersion)reader.ReadInt32(); if (Version != ModelVersion.DarkSouls && Version != ModelVersion.DarkSouls2) loader.AddError(loader.Position - 4, "Unknown model version " + VersionString + "; will try to load it anyway."); int dataOffset = reader.ReadInt32(); int dataSize = reader.ReadInt32(); if (((dataOffset + dataSize + 31) & ~31) != reader.BaseStream.Length) loader.AddError(loader.Position - 4, "Data size and offset aren't correct."); int boneUnknownCount = reader.ReadInt32(); int materialCount = reader.ReadInt32(); int boneCount = reader.ReadInt32(); int meshCount = reader.ReadInt32(); int meshCount2 = reader.ReadInt32(); if (meshCount != meshCount2) loader.AddError(loader.Position - 4, "Mesh count 1 and 2 aren't the same."); Bounds = new Box3f(reader.ReadVector3f(), reader.ReadVector3f()); Unknowns.ReadInt32s(reader, 1); // Possible the non-degenerate triangle count. Seems related. int triangleCount = reader.ReadInt32(); loader.Expect(IsDS1 ? 272 : 0x10010100); loader.Expect(IsDS1 ? 0 : 0xFFFF); int partCount = reader.ReadInt32(); int vertexDeclarationCount = reader.ReadInt32(); int materialParameterCount = reader.ReadInt32(); loader.Expect(IsDS1 ? 0 : 0x1000000); loader.ExpectZeroes(4, 8); // Calculate offsets. long boneUnknownsOffset = HeaderSize; long materialsOffset = boneUnknownsOffset + boneUnknownCount * ModelBoneUnknown.DataSize; long bonesOffset = materialsOffset + materialCount * ModelMaterial.DataSize; long meshesOffset = bonesOffset + boneCount * ModelBone.DataSize; long detailLevelsOffset = meshesOffset + meshCount * ModelMesh.DataSize; long meshVerticesOffset = detailLevelsOffset + partCount * ModelDetailLevel.DataSize; long vertexDeclarationsOffset = meshVerticesOffset + meshCount * ModelMesh.DataSizeVertexHeader; long materialParametersOffset = vertexDeclarationsOffset + vertexDeclarationCount * ModelVertexDeclaration.DataSize; long postHeaderOffset = materialParametersOffset + materialParameterCount * ModelMaterialParameter.DataSize; // BoneUnknowns ExpectedOffset(loader, boneUnknownsOffset, typeof(ModelBoneUnknown).Name); for (int index = 0; index < boneUnknownCount; index++) boneUnknowns.Add(new ModelBoneUnknown(bonesFolder, index, loader)); // Materials ExpectedOffset(loader, materialsOffset, typeof(ModelMaterial).Name); for (int index = 0; index < materialCount; index++) materials.Add(new ModelMaterial(materialsFolder, index, loader)); int expectedMaterialParameterCount = materialCount > 0 ? materials[materialCount - 1].ParameterEndIndex : 0; if (expectedMaterialParameterCount != materialParameterCount) loader.AddError(null, "Expected material parameter count {0} doesn't match actual count {1}.", expectedMaterialParameterCount, materialParameterCount); // Bones ExpectedOffset(loader, bonesOffset, typeof(ModelBone).Name); for (int index = 0; index < boneCount; index++) bones.Add(new ModelBone(bonesFolder, index, loader)); // Meshes ExpectedOffset(loader, meshesOffset, typeof(ModelMesh).Name); for (int index = 0; index < meshCount; index++) meshes.Add(new ModelMesh(meshesFolder, index, loader)); int expectedPartCount = meshCount > 0 ? meshes[meshCount - 1].PartEndIndex : 0; if (expectedPartCount != partCount) throw new InvalidDataException("Expected part count doesn't match actual count."); // Detail levels ExpectedOffset(loader, detailLevelsOffset, typeof(ModelDetailLevel).Name); foreach (ModelMesh mesh in meshes) { mesh.ReadDetailLevels(loader, dataOffset, bufferData); detailLevels.AddRange(mesh.DetailLevels); } // Mesh vertices ExpectedOffset(loader, meshVerticesOffset, typeof(ModelMesh).Name + " vertex header"); foreach (ModelMesh mesh in meshes) mesh.ReadVertexHeaders(reader, dataOffset, bufferData); // Vertex declarations ExpectedOffset(loader, vertexDeclarationsOffset, typeof(ModelVertexDeclaration).Name); for (int index = 0; index < vertexDeclarationCount; index++) vertexDeclarations.Add(new ModelVertexDeclaration(vertexDeclarationsFolder, index, loader)); // Material parameters ExpectedOffset(loader, materialParametersOffset, typeof(ModelMaterialParameter).Name); foreach (ModelMaterial material in materials) { material.ReadParameters(loader, textureArchive); materialParameters.AddRange(material.Parameters); } ExpectedOffset(loader, postHeaderOffset, "Post-header"); #if Marking if (markingStream != null) { markingStream.Report(loader); } #endif // Marking #if SkippedChecks /*int vertexDataSize = 0, indexCount = 0, indexSize = 0, vertexCount = 0, expectedTriangleCount = 0, nondegenerateTriangleCount = 0; foreach (var mesh in Meshes) { vertexDataSize += mesh.VertexCount * mesh.VertexSize; vertexCount += mesh.VertexCount; foreach (var part in mesh.Parts) { indexCount += part.Indices.Length; indexSize += part.Indices.Length * 2; expectedTriangleCount += part.Indices.Length - 2; for (int index = 0; index < part.Indices.Length - 2; index++) { if (part.Indices[index] != part.Indices[index + 1] && part.Indices[index + 1] != part.Indices[index + 2] && part.Indices[index] != part.Indices[index + 2]) nondegenerateTriangleCount++; } } } if (Math.Abs(expectedTriangleCount - triangleCount) > partCount) throw new InvalidDataException("Expected triangle count doesn't match the read value.");*/ #endif } Buffer = new GraphicsBuffer(bufferData.Count == 0 ? 1 : bufferData.Count); Buffer.Write(0, bufferData.Array, 0, bufferData.Count); }
internal void Sort(FolderAsset parent, string name, int fileNameBaseOffset, byte[] fileNames) { int fileNameOffset = FileNameOffset - fileNameBaseOffset; int fileIndex = FileIndex; if (Used) throw new InvalidDataException(); Used = true; Parent = parent; Name = name; while (true) { byte nameCode = fileNames[fileNameOffset++]; if (nameCode == 0) break; byte nameLength = (byte)(nameCode & 0x7F); bool isFolder = (nameCode & 0x80) != 0; string childName = Encoding.ASCII.GetString(fileNames, fileNameOffset, nameLength); fileNameOffset += nameLength; if (isFolder) { int folderIndex = fileNames[fileNameOffset++] + (fileNames[fileNameOffset++] << 8); RomFolder folder = Rom.Folders[folderIndex & 0xFFF]; folder.Unknown2 = (byte)(folderIndex >> 12); if (folder.Unknown2 != 15) { } folder.Sort(this, childName, fileNameBaseOffset, fileNames); } else { RomFile file = Rom.Files[fileIndex++]; file.Sort(this, childName); } } }
internal Rom(AssetLoader loader) : base(loader) { BinaryReader reader = Reader = loader.Reader; Codex<RomFile> files = new Codex<RomFile>(); Codex<RomFolder> folders = new Codex<RomFolder>(); Files = files; Folders = folders; GameTitle = Reader.ReadStringz(12, Encoding.ASCII); GameCode = Reader.ReadStringz(4, Encoding.ASCII); // Offset 0x10 MakerCode = Reader.ReadStringz(2, Encoding.ASCII); UnitCode = reader.ReadByte(); DeviceCode = reader.ReadByte(); CardSizeBase = reader.ReadByte(); loader.ExpectZeroes(1, 7); Unknowns.ReadInt32s(reader, 1); // Usually 0, Alice in Wonderland: 3 // Offset 0x20 PageSize = reader.ReadInt32(); // Usually (always?) 0x4000 Unknowns.ReadInt16s(reader, 2); // The Dark Spire: 0x800; Trauma Center: 0xF780 (-2176) loader.Expect(0x2000000); Unknowns.ReadInt32s(reader, 1); // The Dark Spire: 0x9BEF8; Trauma Center: 0x1DC518 // Offset 0x30 Unknowns.ReadInt32s(reader, 1); // Entry points? The Dark Spire: 0x152200; Trauma Center: 0x1E0600 loader.Expect(0x2380000); loader.Expect(0x2380000); Unknowns.ReadInt16s(reader, 1); // The Dark Spire: 0x6F28; Trauma Center: 0x6F24 loader.Expect((short)0x2); // Offset 0x40 int fileNameTableOffset = reader.ReadInt32(); int fileNameTableSize = reader.ReadInt32(); int fileSizeTableOffset = reader.ReadInt32(); int fileSizeTableSize = reader.ReadInt32(); // Offset 0x50 Unknowns.ReadInt32s(reader, 2, "Offset and size"); // Used in The Dark Spire, zeroes in Trauma Center. loader.ExpectZeroes(4, 2); // Offset 0x60 Unknowns.ReadInt32s(reader, 2); int iconAndTitleOffset = reader.ReadInt32(); Unknowns.ReadInt32s(reader, 1); // Offset 0x70 Unknowns.ReadInt32s(reader, 2); loader.ExpectZeroes(4, 2); // Offset 0x80 DataLength = reader.ReadInt32(); loader.Expect(PageSize); Unknowns.ReadInt32s(reader, 2); // The Dark Spire: 0x4B68; 0 in Trauma Center. ReadIconAndTitle(iconAndTitleOffset); if (fileNameTableOffset > 0) { int folderNamesOffset = reader.ReadInt32At(fileNameTableOffset); reader.BaseStream.Position = fileNameTableOffset; int folderCount = folderNamesOffset / 8; for (int index = 0; index < folderCount; index++) folders.Add(new RomFolder(this, index, reader)); byte[] folderNames = reader.ReadBytes(fileNameTableSize - folderNamesOffset); reader.BaseStream.Position = fileSizeTableOffset; int fileCount = fileSizeTableSize / 8; for (int index = 0; index < fileCount; index++) files.Add(new RomFile(this, index, reader)); folders[0].Sort(this, "Root", folderNamesOffset, folderNames); FolderAsset orphanedFolders = null, orphanedFiles = null; foreach (RomFolder folder in folders) { if (folder.Used) continue; if (orphanedFolders == null) orphanedFolders = new FolderAsset(this, "Orphaned folder[s]"); folder.Sort(this, folder.Name, folderNamesOffset, folderNames); } foreach (RomFile file in files) { if (file.Used) continue; if (orphanedFiles == null) orphanedFiles = new FolderAsset(this, "Orphaned file[s]"); file.Sort(orphanedFiles, file.Name); } } }
/// <summary>Initialise the asset.</summary> /// <param name="folder"></param> /// <param name="name"></param> /// <param name="colors"></param> public PaletteAsset(FolderAsset folder, string name, IEnumerable<Color> colors) : base(folder, name) { if (colors != null) ColorsMutable.AddRange(colors); }
/// <summary> /// Initialise the asset. /// </summary> /// <param name="parent"></param> /// <param name="name"></param> /// <param name="description"></param> public Asset(FolderAsset parent, string name, string description = null) : this(parent.Manager, name, description) { Parent = parent; }
/// <summary> /// Initialise the folder asset. /// </summary> /// <param name="parent"></param> /// <param name="loader"></param> public FolderAsset(FolderAsset parent, AssetLoader loader) : base(parent, loader) { }
/// <summary>Initialise the table asset.</summary> /// <param name="parent"></param> /// <param name="loader"></param> public TableAsset(FolderAsset parent, AssetLoader loader) : base(parent, loader) { }
internal static void LoadFileTable(FolderAsset parent, BinaryReader reader, NintendoOpticalDiscSystem system) { reader.BaseStream.Position = 0x424; long fileTableOffset = LoadOffset(reader, system); reader.BaseStream.Position = fileTableOffset + 8; int count = reader.ReadInt32(); for (int index = 1; index < count; ) LoadFile(parent, reader, ref index, system); foreach (Asset asset in parent.Children) LoadFileName(asset, reader, fileTableOffset + count * 12); }
internal NintendoOpticalDiscPartitionFile(FolderAsset parent, int index, int nameOffset, BinaryReader reader, NintendoOpticalDiscSystem system) : base(parent, "") { Index = index; NameOffset = nameOffset; DataOffset = NintendoOpticalDiscPartition.LoadOffset(reader, system); Size = reader.ReadUInt32(); }
internal static Asset LoadFile(FolderAsset parent, BinaryReader reader, ref int index, NintendoOpticalDiscSystem system) { int nameOffset = reader.ReadInt32(); bool isDirectory = (nameOffset & 0xFF000000) != 0; nameOffset &= 0xFFFFFF; if (isDirectory) return new NintendoOpticalDiscPartitionFolder(parent, ref index, nameOffset, reader, system); else return new NintendoOpticalDiscPartitionFile(parent, index++, nameOffset, reader, system); }
/// <summary>Initialise the texture.</summary> /// <param name="parent"></param> /// <param name="loader"></param> protected IndexedTextureAsset(FolderAsset parent, AssetLoader loader) : base(parent, loader, null) { }
/// <summary> /// Initialise the asset. /// </summary> /// <param name="parent"></param> /// <param name="loader"></param> public Asset(FolderAsset parent, AssetLoader loader) : this(loader) { Parent = parent; }
/// <summary> /// Initialise the object. /// </summary> /// <param name="parent"></param> /// <param name="index"></param> /// <param name="loader"></param> public ModelAsset(FolderAsset parent, int index, AssetLoader loader) : base(parent, "") { Name = GetType().Name + " " + index; Index = index; }
/// <summary>Initialise the asset.</summary> /// <param name="folder"></param> /// <param name="name"></param> /// <param name="colors"></param> public PaletteAsset(FolderAsset folder, string name, params Color[] colors) : this(folder, name, (IEnumerable<Color>)colors) { }
internal void Sort(FolderAsset parent, string name) { if (Used) throw new InvalidDataException(); Parent = parent; Name = name; Used = true; }
internal NintendoOpticalDiscPartitionFolder(FolderAsset parent, ref int index, int nameOffset, BinaryReader reader, NintendoOpticalDiscSystem system) : base(parent, "") { Index = index; NameOffset = nameOffset; int firstIndex = reader.ReadInt32(); /*if (firstIndex != index + 1) throw new InvalidDataException();*/ int endIndex = reader.ReadInt32(); index++; while (index < endIndex) NintendoOpticalDiscPartition.LoadFile(this, reader, ref index, system); }
/// <summary> /// Initialise the folder asset. /// </summary> /// <param name="parent"></param> /// <param name="name"></param> /// <param name="description"></param> public FolderAsset(FolderAsset parent, string name, string description = null) : base(parent, name, description) { }
/// <summary>Initialise the asset.</summary> /// <param name="parent"></param> /// <param name="loader"></param> /// <param name="texture"></param> public TextureAsset(FolderAsset parent, AssetLoader loader, Glare.Graphics.Texture texture) : base(parent, loader) { }
/// <summary> /// Initialise the data asset. /// </summary> /// <param name="parent"></param> /// <param name="name"></param> /// <param name="description"></param> public DataAsset(FolderAsset parent, string name, string description = null) : base(parent, name, description) { }
/// <summary> /// Initialise the resource. /// </summary> /// <param name="parent"></param> /// <param name="map"></param> /// <param name="id"></param> public Resource(FolderAsset parent, ResourceMap map, ResourceId id) : base(parent, id.ToString()) { Map = map; Id = id; }