private int ReadLumpValues <T>(LumpType type, int srcOffset, T[] dst, int dstOffset, int count) where T : struct { var info = GetLumpInfo(type); var tSize = Marshal.SizeOf <T>(); var length = info.Length / tSize; if (srcOffset > length) { srcOffset = length; } if (srcOffset + count > length) { count = length - srcOffset; } if (count <= 0) { return(0); } using (var stream = GetLumpStream(type)) { stream.Seek(tSize * srcOffset, SeekOrigin.Begin); LumpReader <T> .ReadLumpFromStream(stream, count, dst, dstOffset); } return(count); }
public ValveVertexFile(Stream stream) { using (var reader = new BinaryReader(stream)) { var id = reader.ReadInt32(); var version = reader.ReadInt32(); Debug.Assert(id == 0x56534449); Debug.Assert(version == 4); reader.ReadInt32(); NumLods = reader.ReadInt32(); _numVerts = new int[NumLods]; for (var i = 0; i < 8; ++i) { var count = reader.ReadInt32(); if (i < NumLods) { _numVerts[i] = count; } } var numFixups = reader.ReadInt32(); var fixupTableStart = reader.ReadInt32(); var vertexDataStart = reader.ReadInt32(); var tangentDataStart = reader.ReadInt32(); if (numFixups > 0) { reader.BaseStream.Seek(fixupTableStart, SeekOrigin.Begin); _fixups = LumpReader <VertexFixup> .ReadLumpFromStream(reader.BaseStream, numFixups); } HasTangents = tangentDataStart != 0; var vertLength = (int)(HasTangents ? tangentDataStart - vertexDataStart : stream.Length - vertexDataStart); reader.BaseStream.Seek(vertexDataStart, SeekOrigin.Begin); _vertices = LumpReader <StudioVertex> .ReadLumpFromStream(reader.BaseStream, vertLength / Marshal.SizeOf <StudioVertex>()); if (HasTangents) { var tangLength = (int)(stream.Length - tangentDataStart); reader.BaseStream.Seek(tangentDataStart, SeekOrigin.Begin); _tangents = LumpReader <Vector4> .ReadLumpFromStream(reader.BaseStream, tangLength / Marshal.SizeOf <Vector4>()); } } }
private void EnsureLoaded() { lock (this) { if (Loaded) { return; } using (var reader = new BinaryReader(_bspFile.GetLumpStream(LumpType))) { _numClusters = reader.ReadInt32(); _vpsList = new HashSet <int> [_numClusters]; _offsets = LumpReader <ByteOffset> .ReadLumpFromStream(reader.BaseStream, _numClusters); } } }
public ValveVertexLightingFile(Stream stream) { using (var reader = new BinaryReader(stream)) { var version = reader.ReadInt32(); Debug.Assert(version == 2); var checksum = reader.ReadInt32(); var vertFlags = reader.ReadUInt32(); var vertSize = reader.ReadUInt32(); var vertCount = reader.ReadUInt32(); var meshCount = reader.ReadInt32(); reader.ReadInt64(); // Unused reader.ReadInt64(); // Unused var meshHeaders = new List <VhvMeshHeader>(); LumpReader <VhvMeshHeader> .ReadLumpFromStream(stream, meshCount, meshHeaders); _samples = new VertexData4[meshHeaders.Max(x => x.Lod) + 1][][]; for (var i = 0; i < _samples.Length; ++i) { _samples[i] = new VertexData4[meshHeaders.Count(x => x.Lod == i)][]; } foreach (var meshHeader in meshHeaders) { stream.Seek(meshHeader.VertOffset, SeekOrigin.Begin); var samples = _samples[meshHeader.Lod]; var meshIndex = Array.IndexOf(samples, null); if (vertFlags == 2) { samples[meshIndex] = LumpReader <VertexData2> .ReadLumpFromStream(stream, meshHeader.VertCount, x => x.GetVertexColor()); } else { samples[meshIndex] = LumpReader <VertexData4> .ReadLumpFromStream(stream, meshHeader.VertCount, x => x.GetVertexColor()); } } } }
private void EnsureLoaded() { lock (this) { if (_items != null) { return; } _items = new Dictionary <string, Item>(); using (var reader = new BinaryReader(_bspFile.GetLumpStream(LumpType))) { var count = reader.ReadInt32(); LumpReader <Item> .ReadLumpFromStream(reader.BaseStream, count, item => _items.Add(GetIdString(item.Id), item)); } } }
public ValveTextureFile(Stream stream, bool onlyHeader = false) { Header = LumpReader <TextureHeader> .ReadSingleFromStream(stream); var readCount = Marshal.SizeOf <TextureHeader>(); ZSliceCount = 1; if (Header.MajorVersion > 7 || Header.MajorVersion == 7 && Header.MinorVersion >= 2) { ZSliceCount = stream.ReadByte() | (stream.ReadByte() << 8); readCount += 2; } MipmapCount = Header.MipMapCount; FrameCount = Header.Frames; FaceCount = (Header.Flags & TextureFlags.ENVMAP) != 0 ? 6 : 1; if (onlyHeader) { return; } var thumbSize = GetImageDataSize(Header.LowResWidth, Header.LowResHeight, 1, 1, Header.LowResFormat); VtfResource[] resources = null; var buffer = new byte[8]; if (Header.MajorVersion > 7 || Header.MajorVersion == 7 && Header.MinorVersion >= 3) { Skip(stream, 3); readCount += 3; stream.Read(buffer, 0, 4); readCount += 4; var resourceCount = BitConverter.ToInt32(buffer, 0); // Probably padding? stream.Read(buffer, 0, 8); readCount += 8; resources = LumpReader <VtfResource> .ReadLumpFromStream(stream, resourceCount); readCount += Marshal.SizeOf <VtfResource>() * resourceCount; } if (resources == null || resources.Length == 0) { resources = new VtfResource[2]; resources[0] = new VtfResource(VtfResourceType.LowResImage, Header.HeaderSize); resources[1] = new VtfResource(VtfResourceType.HiResImage, Header.HeaderSize + (uint)thumbSize); } Skip(stream, Header.HeaderSize - readCount); readCount = (int)Header.HeaderSize; switch (Header.HiResFormat) { case TextureFormat.DXT1: case TextureFormat.DXT3: case TextureFormat.DXT5: case TextureFormat.I8: case TextureFormat.IA88: case TextureFormat.BGR888: case TextureFormat.RGB888: case TextureFormat.RGB888_BLUESCREEN: case TextureFormat.ABGR8888: case TextureFormat.BGRA8888: case TextureFormat.RGBA8888: case TextureFormat.RGBA16161616F: break; default: throw new NotImplementedException($"VTF format: {Header.HiResFormat}"); } _imageData = new ImageData[MipmapCount * FrameCount * FaceCount * ZSliceCount]; var offset = 0; for (var mipmap = MipmapCount - 1; mipmap >= 0; --mipmap) { var length = GetImageDataSize(Header.Width >> mipmap, Header.Height >> mipmap, 1, 1, Header.HiResFormat); for (var frame = 0; frame < FrameCount; ++frame) { for (var face = 0; face < FaceCount; ++face) { for (var zslice = 0; zslice < ZSliceCount; ++zslice) { var index = GetImageDataIndex(mipmap, frame, face, zslice); _imageData[index] = new ImageData(offset, length); offset += length; } } } } var hiResEntry = resources.First(x => x.Type == VtfResourceType.HiResImage); Skip(stream, hiResEntry.Data - readCount); _hiResPixelData = new byte[offset]; stream.Read(_hiResPixelData, 0, offset); }
public ValveVertexLightingFile(Stream stream) { using (var reader = new BinaryReader(stream)) { var version = (int)reader.ReadByte(); var baseOffset = 0; if (version == 0) { // First 3 bytes are missing :( version = 2; baseOffset = -3; } else { version |= reader.ReadByte() << 8; version |= reader.ReadUInt16() << 16; } if (version != 2) { throw new NotSupportedException($"Vertex lighting file version {version:x} is not supported."); } var checksum = reader.ReadInt32(); var vertFlags = reader.ReadUInt32(); var vertSize = reader.ReadUInt32(); var vertCount = reader.ReadUInt32(); var meshCount = reader.ReadInt32(); var unused0 = reader.ReadInt64(); // Unused var unused1 = reader.ReadInt64(); // Unused var meshHeaders = new List <VhvMeshHeader>(); LumpReader <VhvMeshHeader> .ReadLumpFromStream(stream, meshCount, meshHeaders); _samples = new VertexData4[meshHeaders.Max(x => x.Lod) + 1][][]; for (var i = 0; i < _samples.Length; ++i) { _samples[i] = new VertexData4[meshHeaders.Count(x => x.Lod == i)][]; } foreach (var meshHeader in meshHeaders) { stream.Seek(meshHeader.VertOffset + baseOffset, SeekOrigin.Begin); var samples = _samples[meshHeader.Lod]; var meshIndex = Array.IndexOf(samples, null); if (vertFlags == 2) { samples[meshIndex] = LumpReader <VertexData2> .ReadLumpFromStream(stream, meshHeader.VertCount, x => x.GetVertexColor()); } else { samples[meshIndex] = LumpReader <VertexData4> .ReadLumpFromStream(stream, meshHeader.VertCount, x => x.GetVertexColor()); } } } }
private int ReadLumpValues <T>(LumpType type, int srcOffset, T[] dst, int dstOffset, int count) where T : struct { var info = GetLumpInfo(type); // 0 = no compression if (info.UncompressedSize == 0) { var tSize = Marshal.SizeOf <T>(); var length = info.Length / tSize; if (srcOffset > length) { srcOffset = length; } if (srcOffset + count > length) { count = length - srcOffset; } if (count <= 0) { return(0); } using (var stream = GetLumpStream(type)) { stream.Seek(tSize * srcOffset, SeekOrigin.Begin); LumpReader <T> .ReadLumpFromStream(stream, count, dst, dstOffset); } } else { // LZMA compressed lump if (type == LumpType.GAME_LUMP) { // game lumps are compressed individually // https://developer.valvesoftware.com/wiki/Source_BSP_File_Format#Lump_compression throw new NotImplementedException(); } using (var stream = GetSubStream(info.Offset, LzmaHeader.Size)) { var lzmaHeader = LzmaHeader.Read(stream); using (var compressedStream = GetSubStream(info.Offset + LzmaHeader.Size, lzmaHeader.LzmaSize)) { using (var uncompressedStream = new MemoryStream(info.UncompressedSize)) { Decoder decoder = new Decoder(); decoder.SetDecoderProperties(lzmaHeader.Properties); decoder.Code(compressedStream, uncompressedStream, lzmaHeader.LzmaSize, lzmaHeader.ActualSize, null); var tSize = Marshal.SizeOf <T>(); var length = info.UncompressedSize / tSize; if (srcOffset > length) { srcOffset = length; } if (srcOffset + count > length) { count = length - srcOffset; } if (count <= 0) { return(0); } uncompressedStream.Seek(tSize * srcOffset, SeekOrigin.Begin); LumpReader <T> .ReadLumpFromStream(uncompressedStream, count, dst, dstOffset); if (type == LumpType.PLANES) { return(count); } } } } } return(count); }
public StudioModelFile(Stream stream) { _header = LumpReader <Header> .ReadSingleFromStream(stream); if (_header.Id != 0x54534449) { throw new Exception("Not a MDL file."); } _materials = new StudioTexture[_header.NumTextures]; _materialNames = new string[_header.NumTextures]; _cachedFullMaterialPaths = new string[_header.NumTextures]; stream.Seek(_header.TextureIndex, SeekOrigin.Begin); LumpReader <StudioTexture> .ReadLumpFromStream(stream, _header.NumTextures, (index, tex) => { _materials[index] = tex; stream.Seek(tex.NameIndex, SeekOrigin.Current); _materialNames[index] = ReadNullTerminatedString(stream).Replace('\\', '/') + ".vmt"; }); _materialPaths = new string[_header.NumCdTextures]; stream.Seek(_header.CdTextureIndex, SeekOrigin.Begin); LumpReader <int> .ReadLumpFromStream(stream, _header.NumCdTextures, (index, cdTex) => { stream.Seek(cdTex, SeekOrigin.Begin); _materialPaths[index] = ReadNullTerminatedString(stream).Replace('\\', '/'); }); _bodyParts = new StudioBodyPart[_header.NumBodyParts]; _bodyPartNames = new string[_header.NumBodyParts]; var modelList = new List <StudioModel>(); var meshList = new List <StudioMesh>(); stream.Seek(_header.BodyPartIndex, SeekOrigin.Begin); LumpReader <StudioBodyPart> .ReadLumpFromStream(stream, _header.NumBodyParts, (partIndex, part) => { var partPos = stream.Position; stream.Seek(partPos + part.NameIndex, SeekOrigin.Begin); _bodyPartNames[partIndex] = ReadNullTerminatedString(stream); stream.Seek(partPos + part.ModelIndex, SeekOrigin.Begin); // Now indexes into array of models part.ModelIndex = modelList.Count; LumpReader <StudioModel> .ReadLumpFromStream(stream, part.NumModels, (modelIndex, model) => { var modelPos = stream.Position; stream.Seek(modelPos + model.MeshIndex, SeekOrigin.Begin); model.MeshIndex = meshList.Count; LumpReader <StudioMesh> .ReadLumpFromStream(stream, model.NumMeshes, (meshIndex, mesh) => { mesh.ModelIndex = modelIndex; meshList.Add(mesh); }); modelList.Add(model); }); _bodyParts[partIndex] = part; }); _models = modelList.ToArray(); _meshes = meshList.ToArray(); }
public ValveTriangleFile(Stream stream, StudioModelFile mdl, ValveVertexFile vvd) { var outIndices = new List <int>(); var outVertices = new List <StudioVertex>(); using (var reader = new BinaryReader(stream)) { var version = reader.ReadInt32(); Debug.Assert(version == 7); var vertCacheSize = reader.ReadInt32(); var maxBonesPerStrip = reader.ReadUInt16(); var maxBonesPerTri = reader.ReadUInt16(); var maxBonesPerVert = reader.ReadInt32(); var checksum = reader.ReadInt32(); var numLods = NumLods = reader.ReadInt32(); var matReplacementListOffset = reader.ReadInt32(); var origVerts = new StudioVertex[numLods][]; for (var i = 0; i < numLods; ++i) { origVerts[i] = new StudioVertex[vvd.GetVertexCount(i)]; vvd.GetVertices(i, origVerts[i]); } var numBodyParts = reader.ReadInt32(); var bodyPartOffset = reader.ReadInt32(); var verts = new List <OptimizedVertex>(); var indices = new List <ushort>(); _bodyParts = new BodyPartHeader[numBodyParts]; var modelList = new List <ModelHeader>(); var modelLodList = new List <ModelLodHeader>(); var meshList = new List <MeshData>(); reader.BaseStream.Seek(bodyPartOffset, SeekOrigin.Begin); LumpReader <BodyPartHeader> .ReadLumpFromStream(reader.BaseStream, numBodyParts, (bodyPartIndex, bodyPart) => { reader.BaseStream.Seek(bodyPart.ModelOffset, SeekOrigin.Current); bodyPart.ModelOffset = modelList.Count; LumpReader <ModelHeader> .ReadLumpFromStream(reader.BaseStream, bodyPart.NumModels, (modelIndex, model) => { reader.BaseStream.Seek(model.LodOffset, SeekOrigin.Current); model.LodOffset = modelLodList.Count; LumpReader <ModelLodHeader> .ReadLumpFromStream(reader.BaseStream, model.NumLods, (lodIndex, lod) => { // TODO if (lodIndex > 0) { return; } reader.BaseStream.Seek(lod.MeshOffset, SeekOrigin.Current); lod.MeshOffset = meshList.Count; var lodVerts = origVerts[lodIndex]; var firstLodIndex = outVertices.Count; var firstLodVertex = outVertices.Count; LumpReader <MeshHeader> .ReadLumpFromStream(reader.BaseStream, lod.NumMeshes, (meshIndex, mesh) => { var meshData = new MeshData { LodIndexOffset = firstLodIndex, LodVertexOffset = firstLodVertex, IndexOffset = outIndices.Count, VertexOffset = outVertices.Count }; var meshInfo = mdl.GetMesh(bodyPartIndex, modelIndex, meshIndex); var origVertOffset = meshInfo.VertexOffset; reader.BaseStream.Seek(mesh.StripGroupHeaderOffset, SeekOrigin.Current); LumpReader <StripGroupHeader> .ReadLumpFromStream(reader.BaseStream, mesh.NumStripGroups, stripGroup => { verts.Clear(); indices.Clear(); var start = reader.BaseStream.Position; reader.BaseStream.Seek(start + stripGroup.VertOffset, SeekOrigin.Begin); LumpReader <OptimizedVertex> .ReadLumpFromStream(reader.BaseStream, stripGroup.NumVerts, verts); var meshIndexOffset = outVertices.Count - firstLodVertex; for (var i = 0; i < verts.Count; ++i) { var vertIndex = origVertOffset + verts[i].OrigMeshVertId; if (vertIndex < 0 || vertIndex >= lodVerts.Length) { throw new IndexOutOfRangeException(); } outVertices.Add(lodVerts[vertIndex]); } reader.BaseStream.Seek(start + stripGroup.IndexOffset, SeekOrigin.Begin); LumpReader <ushort> .ReadLumpFromStream(reader.BaseStream, stripGroup.NumIndices, indices); reader.BaseStream.Seek(start + stripGroup.StripOffset, SeekOrigin.Begin); LumpReader <StripHeader> .ReadLumpFromStream(reader.BaseStream, stripGroup.NumStrips, strip => { Debug.Assert(strip.Flags != StripHeaderFlags.IsTriStrip); for (var i = 0; i < strip.NumIndices; ++i) { outIndices.Add(meshIndexOffset + indices[strip.IndexOffset + i]); } }); }); meshData.IndexCount = outIndices.Count - meshData.IndexOffset; meshData.VertexCount = outVertices.Count - meshData.VertexOffset; meshList.Add(meshData); }); modelLodList.Add(lod); }); modelList.Add(model); }); _bodyParts[bodyPartIndex] = bodyPart; }); _models = modelList.ToArray(); _modelLods = modelLodList.ToArray(); _meshes = meshList.ToArray(); _indices = outIndices.ToArray(); _vertices = outVertices.ToArray(); } }