public static BspTexture[] ReadBspTexturesLumpData(this BinaryReader br, BspLump lump) { br.BaseStream.Position = lump.offset; var count = br.ReadInt32(); var result = new BspTexture[count]; for (int i = 0, j = lump.offset + 4; i < count; i++, j += 4) { br.BaseStream.Position = j; result[i] = new HlBspMap.BspTexture(br, lump.offset, br.ReadInt32()); } return(result); }
private static void WriteTexture(Stream stream, BspTexture texture) { stream.Write(texture.Name, 16); stream.Write(texture.Width); stream.Write(texture.Height); if (!texture.IsEmbedded) { for (int i = 0; i < 4; i++) { stream.Write(0u); } return; } else { var offset = 40u; foreach (var imageData in texture.ImageData) { stream.Write(offset); offset += (uint)imageData.Length; } foreach (var imageData in texture.ImageData) { if (imageData != null) { stream.Write(imageData); } } stream.Write((ushort)texture.Palette.Length); foreach (var color in texture.Palette) { stream.Write(color); } stream.Write(new byte[StreamExtensions.RequiredPadding(2 + texture.Palette.Length * 3, 4)]); } }
private static BspTexture ReadTexture(Stream stream) { var textureOffset = stream.Position; var texture = new BspTexture(); texture.Name = stream.ReadString(16); texture.Width = stream.ReadUint(); texture.Height = stream.ReadUint(); var imageDataOffsets = Enumerable.Range(0, 4) .Select(i => stream.ReadUint()) .ToArray(); // Is this an embedded texture? if (imageDataOffsets[0] == 0) { return(texture); } texture.ImageData = new byte[4][]; for (int j = 0; j < 4; j++) { if (imageDataOffsets[j] == 0) { continue; } stream.Seek(textureOffset + imageDataOffsets[j], SeekOrigin.Begin); texture.ImageData[j] = stream.ReadBytes((int)(texture.Width * texture.Height) >> (j * 2)); } var paletteSize = stream.ReadUshort(); texture.Palette = Enumerable.Range(0, paletteSize) .Select(i => stream.ReadColor()) .ToArray(); return(texture); }
/// <summary> /// Removes embedded textures from the specified bsp file. /// If no output path is provided, then the input bsp file is overwritten. /// </summary> public static int RemoveEmbeddedTextures(string path, string outputPath = null) { // Read all bsp lump contents: var lumps = new List <Lump>(); var lumpsData = new List <byte[]>(); using (var inputStream = File.OpenRead(path)) { var bspHeader = ReadBspHeader(inputStream); lumps.AddRange(bspHeader.Lumps); lumpsData.AddRange(bspHeader.Lumps.Select(lump => ReadLumpData(inputStream, lump))); } // Remove image and palette data from embedded textures: var removedTextureCount = 0; BspTexture[] bspTextures; using (var texturesLumpstream = new MemoryStream(lumpsData[TexturesLumpIndex])) { var textureOffsets = ReadTextureOffsets(texturesLumpstream); bspTextures = new BspTexture[textureOffsets.Length]; for (int i = 0; i < textureOffsets.Length; i++) { texturesLumpstream.Seek(textureOffsets[i], SeekOrigin.Begin); var bspTexture = ReadTexture(texturesLumpstream); if (bspTexture.IsEmbedded) { bspTexture.ImageData = null; bspTexture.Palette = null; removedTextureCount += 1; } bspTextures[i] = bspTexture; } } // Create new texture lump data: using (var stream = new MemoryStream()) { WriteTextureOffsets(stream, bspTextures); foreach (var bspTexture in bspTextures) { WriteTexture(stream, bspTexture); } lumpsData[TexturesLumpIndex] = stream.ToArray(); } // Recalculate lump offsets/lengths: var lumpIndexes = lumps .Select((lump, i) => (lump, i)) .OrderBy(pair => pair.lump.Offset) .Select(pair => pair.i) .ToArray(); var offset = 4 + lumps.Count * 8; // 124, BSP header size (15 lumps) for (int i = 0; i < lumpIndexes.Length; i++) { var lumpIndex = lumpIndexes[i]; lumps[lumpIndex] = new Lump { Offset = offset, Length = lumpsData[lumpIndex].Length }; offset += lumpsData[lumpIndex].Length; offset += StreamExtensions.RequiredPadding(lumpsData[lumpIndex].Length, 4); } // Save the bsp file: using (var outputStream = File.OpenWrite(outputPath ?? path)) { WriteBspHeader(outputStream, new BspHeader { Version = 30, Lumps = lumps.ToArray() }); foreach (var lumpIndex in lumpIndexes) { WriteLumpData(outputStream, lumpsData[lumpIndex]); } } return(removedTextureCount); }