Example #1
0
        private static void WriteTextureOffsets(Stream stream, BspTexture[] textures)
        {
            stream.Write(textures.Length);
            var offset = 4 + textures.Length * 4;

            foreach (var texture in textures)
            {
                stream.Write(offset);
                if (texture.IsEmbedded)
                {
                    offset += 40 + texture.ImageData.Sum(imageData => imageData.Length) + 2 + texture.Palette.Length * 3;
                    offset += StreamExtensions.RequiredPadding(2 + texture.Palette.Length * 3, 4);
                }
                else
                {
                    offset += 40;
                }
            }
        }
Example #2
0
        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)]);
            }
        }
Example #3
0
 private static uint GetTextureFileSize(Texture texture)
 {
     if (texture.Type == TextureType.MipmapTexture)
     {
         var size = 40;
         size += texture.ImageData.Length;
         size += texture.Mipmap1Data.Length;
         size += texture.Mipmap2Data.Length;
         size += texture.Mipmap3Data.Length;
         size += 2;
         size += texture.Palette.Length * 3;
         size += StreamExtensions.RequiredPadding(2 + texture.Palette.Length * 3, 4);
         return((uint)size);
     }
     else if (texture.Type == TextureType.Font)
     {
         var size = 16;
         size += texture.CharInfos.Length * 4;
         size += texture.ImageData.Length;
         size += 2;
         size += texture.Palette.Length * 3;
         size += StreamExtensions.RequiredPadding(2 + texture.Palette.Length * 3, 4);
         return((uint)size);
     }
     else if (texture.Type == TextureType.SimpleTexture)
     {
         var size = 8;
         size += texture.ImageData.Length;
         size += 2;
         size += texture.Palette.Length * 3;
         size += StreamExtensions.RequiredPadding(2 + texture.Palette.Length * 3, 4);
         return((uint)size);
     }
     else
     {
         throw new NotSupportedException($"Texture type {texture.Type} is not supported.");
     }
 }
Example #4
0
        /// <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);
        }
Example #5
0
        private static void WriteTexture(Stream stream, Texture texture)
        {
            if (texture.Type == TextureType.MipmapTexture)
            {
                stream.Write(texture.Name, 16);
                stream.Write((uint)texture.Width);
                stream.Write((uint)texture.Height);
                stream.Write((uint)40);
                stream.Write((uint)(40 + texture.ImageData.Length));
                stream.Write((uint)(40 + texture.ImageData.Length + texture.Mipmap1Data.Length));
                stream.Write((uint)(40 + texture.ImageData.Length + texture.Mipmap1Data.Length + texture.Mipmap2Data.Length));

                stream.Write(texture.ImageData);
                stream.Write(texture.Mipmap1Data);
                stream.Write(texture.Mipmap2Data);
                stream.Write(texture.Mipmap3Data);

                stream.Write((ushort)texture.Palette.Length);
                if (texture.Type == TextureType.MipmapTexture)
                {
                    foreach (var color in texture.Palette)
                    {
                        stream.Write(color);
                    }
                }
                stream.Write(new byte[StreamExtensions.RequiredPadding(2 + texture.Palette.Length * 3, 4)]);
            }
            else if (texture.Type == TextureType.Font)
            {
                stream.Write((uint)texture.Width);
                stream.Write((uint)texture.Height);

                stream.Write((uint)texture.RowCount);
                stream.Write((uint)texture.RowHeight);
                foreach (var charInfo in texture.CharInfos)
                {
                    stream.Write((ushort)charInfo.StartOffset);
                    stream.Write((ushort)charInfo.CharWidth);
                }
                stream.Write(texture.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)]);
            }
            else if (texture.Type == TextureType.SimpleTexture)
            {
                stream.Write((uint)texture.Width);
                stream.Write((uint)texture.Height);
                stream.Write(texture.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)]);
            }
            else
            {
                throw new InvalidDataException($"Unknown texture type: {texture.Type}.");
            }
        }