Esempio n. 1
0
        /// <summary>
        /// Compile input images into WAD texture file.
        /// </summary>
        /// <param name="outputFilename">Output wad file path.</param>
        /// <param name="images">Input image files.</param>
        /// <param name="names">Names of textures.</param>
        /// <param name="reserverLastPalColor">Reserve last color in palette if name starts with {.</param>
        public static void CreateWad(string outputFilename, string[] images, string[] names, Color alphaReplacementColor, bool reserverLastPalColor = false)
        {
            using (FileStream fs = new FileStream(outputFilename, FileMode.Create))
                using (BinaryWriter bw = new BinaryWriter(fs))
                {
                    //Convert bitmaps to 8bpp format
                    List <FreeImageBitmap> imgs = new List <FreeImageBitmap>();
                    for (int i = 0; i < images.Length; i++)
                    {
                        //Quantize images
                        FreeImageBitmap originalImage = new FreeImageBitmap(images[i]);

                        //If texture will be transparent, reserve last color if enabled
                        bool reserveLastClr     = (names[i].StartsWith("{") && reserverLastPalColor);
                        bool isTransparentImage = originalImage.IsTransparent;
                        bool is8Bpp             = originalImage.BitsPerPixel == 8;
                        int  r = reserveLastClr ? 1 : 0;

                        if (isTransparentImage)
                        {
                            originalImage.SwapColors(new RGBQUAD(Color.Transparent), new RGBQUAD(alphaReplacementColor), false);
                        }

                        originalImage.Quantize(FREE_IMAGE_QUANTIZE.FIQ_NNQUANT, MaxPaletteColors - r);
                        originalImage.ConvertColorDepth(FREE_IMAGE_COLOR_DEPTH.FICD_08_BPP);

                        if (reserveLastClr)
                        {
                            if (isTransparentImage)
                            {
                                bool foundReplacementColor = false;
                                for (int pindex = 0; pindex < originalImage.Palette.Length; pindex++)
                                {
                                    RGBQUAD rgb = originalImage.Palette.GetValue(pindex);
                                    if (rgb.rgbRed == alphaReplacementColor.R && rgb.rgbGreen == alphaReplacementColor.G && rgb.rgbBlue == alphaReplacementColor.B)
                                    {
                                        var lastColor = originalImage.Palette.GetValue(MaxPaletteColors - 1);
                                        originalImage.Palette[pindex] = lastColor;
                                        originalImage.Palette[MaxPaletteColors - 1] = new RGBQUAD(alphaReplacementColor);
                                        originalImage.SwapPaletteIndices((byte)pindex, MaxPaletteColors - 1);
                                        foundReplacementColor = true;
                                        break;
                                    }
                                }

                                // If didn't found replacement, set directly last alpha color
                                if (!foundReplacementColor)
                                {
                                    originalImage.Palette[MaxPaletteColors - 1] = new RGBQUAD(alphaReplacementColor);
                                }
                            }
                            else
                            {
                                originalImage.Palette[MaxPaletteColors - 1] = new RGBQUAD(alphaReplacementColor);
                            }
                        }

                        imgs.Add(originalImage);
                    }
                    uint[] offsets = new uint[images.Length];
                    uint[] sizes   = new uint[images.Length];

                    //WAD header
                    bw.Write(WadHeaderId);
                    bw.Write(images.Length);
                    bw.Write(0); //This will be changed later

                    //Write textures
                    for (int i = 0; i < images.Length; i++)
                    {
                        uint posTextureStart = (uint)bw.BaseStream.Position;
                        offsets[i] = posTextureStart;
                        //Texture name
                        byte[] name = CreateTextureName(names[i]);
                        bw.Write(name, 0, name.Length);

                        //Texture dimensions
                        bw.Write(imgs[i].Width);
                        bw.Write(imgs[i].Height);

                        //Offsets
                        uint posImage = (uint)(bw.BaseStream.Position - posTextureStart);
                        bw.Write(posImage + 16); //image
                        int pixelSize = ((imgs[i].Width) * (imgs[i].Height));
                        int m1        = ((imgs[i].Width / 2) * (imgs[i].Height / 2));
                        int m2        = ((imgs[i].Width / 4) * (imgs[i].Height / 4));
                        int m3        = ((imgs[i].Width / 8) * (imgs[i].Height / 8));
                        bw.Write((uint)(posImage + pixelSize + 16));           //mipmap1
                        bw.Write((uint)(posImage + pixelSize + m1 + 16));      //mipmap2
                        bw.Write((uint)(posImage + pixelSize + m1 + m2 + 16)); //mipmap3

                        //Write pixel data
                        imgs[i].RotateFlip(RotateFlipType.RotateNoneFlipX);
                        byte[] arr = new byte[imgs[i].Width * imgs[i].Height];
                        System.Runtime.InteropServices.Marshal.Copy(imgs[i].GetScanlinePointer(0), arr, 0, arr.Length);
                        Array.Reverse(arr);
                        bw.Write(arr);
                        //

                        //Mip map data
                        int factor = 2;
                        for (int a = 0; a < 3; a++)
                        {
                            int widthMM  = (imgs[i].Width / factor);
                            int heightMM = (imgs[i].Height / factor);

                            using (FreeImageBitmap clBmp = new FreeImageBitmap(imgs[i]))
                            {
                                //TODO: Transparent png
                                clBmp.Rescale(widthMM, heightMM, FREE_IMAGE_FILTER.FILTER_LANCZOS3);
                                clBmp.Quantize(FREE_IMAGE_QUANTIZE.FIQ_NNQUANT, MaxPaletteColors, imgs[i].Palette);

                                byte[] arrMM = new byte[widthMM * heightMM];
                                System.Runtime.InteropServices.Marshal.Copy(clBmp.GetScanlinePointer(0), arrMM, 0, arrMM.Length);
                                Array.Reverse(arrMM);
                                bw.Write(arrMM);
                            }
                            factor *= 2;
                        }

                        //Unknown 2 bytes
                        bw.Write(new byte[] { 0x00, 0x01 });

                        //Write color palette
                        for (int p = 0; p < imgs[i].Palette.Length; p++)
                        {
                            bw.Write(imgs[i].Palette[p].rgbRed);
                            bw.Write(imgs[i].Palette[p].rgbGreen);
                            bw.Write(imgs[i].Palette[p].rgbBlue);
                        }

                        //Padding
                        bw.Write(new byte[] { 0x00, 0x00 });
                        sizes[i] = (uint)bw.BaseStream.Position - posTextureStart;
                    }

                    long posLumps = bw.BaseStream.Position;
                    bw.Seek(8, SeekOrigin.Begin);
                    bw.Write((uint)posLumps);
                    bw.Seek((int)posLumps, SeekOrigin.Begin);
                    //Write Lumps infos
                    for (int i = 0; i < images.Length; i++)
                    {
                        bw.Write(offsets[i]);
                        bw.Write(sizes[i]);
                        bw.Write(sizes[i]);
                        bw.Write((byte)0x43);
                        bw.Write((byte)0);
                        bw.Write(new byte[] { 0x00, 0x00 });
                        byte[] name = CreateTextureName(names[i]);
                        bw.Write(name, 0, name.Length);
                    }

                    //Free resources
                    for (int i = 0; i < imgs.Count; i++)
                    {
                        imgs[i].Dispose();
                    }
                }
        }
        /// <summary>
        /// Create new sprite file from image files.
        /// </summary>
        /// <param name="outputPath">Output filename *.SPR</param>
        /// <param name="files">Input image paths.</param>
        /// <param name="spriteType">SprType</param>
        /// <param name="textFormat">SprTextFormat</param>
        /// <param name="palIndex">Which palette use from files</param>
        public static void CreateSpriteFile(string outputPath, string[] files, SprType spriteType, SprTextFormat textFormat, int palIndex, Color alphaReplacementColor)
        {
            List <FreeImageBitmap> images = files.Select(file => new FreeImageBitmap(file)).ToList();

            //Retrieve maximum width, height
            int prevSize = 0;
            int maxW = 0, maxH = 0;

            for (int i = 0; i < images.Count; i++)
            {
                FreeImageBitmap image = images[i];
                if ((image.Height + image.Width) > prevSize)
                {
                    prevSize = image.Height + image.Width;
                    maxW     = image.Width;
                    maxH     = image.Height;
                }

                if (image.IsTransparent)
                {
                    image.SwapColors(new RGBQUAD(Color.Transparent), new RGBQUAD(alphaReplacementColor), false);
                }
            }

            //Calc. bounding box
            float f = (float)Math.Sqrt((maxW >> 1) * (maxW >> 1) + (maxH >> 1) * (maxH >> 1));

            using (BinaryWriter bw = new BinaryWriter(new FileStream(outputPath, FileMode.Create)))
            {
                //Write header first
                bw.Write(SpriteHeaderId.ToCharArray());
                bw.Write(2);
                bw.Write((uint)spriteType);
                bw.Write((uint)textFormat);
                bw.Write(f);
                bw.Write(maxW);
                bw.Write(maxH);
                bw.Write(images.Count);
                bw.Write(0.0f);                     //Always 0 ?
                bw.Write(1);                        //Synch. type
                //Color palette
                bw.Write((ushort)MaxPaletteColors); //Always 256 ?

                if ((palIndex > (images.Count - 1)) || palIndex < images.Count)
                {
                    palIndex = 0;
                }

                if (!images[palIndex].HasPalette || images[palIndex].Palette.Length != 256)
                {
                    images[palIndex].ConvertColorDepth(FREE_IMAGE_COLOR_DEPTH.FICD_08_BPP);
                }

                Palette pal = images[palIndex].Palette;

                for (int i = 0; i < 256; i++)
                {
                    bw.Write(pal[i].rgbRed);
                    bw.Write(pal[i].rgbGreen);
                    bw.Write(pal[i].rgbBlue);
                }

                //Write images
                for (int i = 0; i < images.Count; i++)
                {
                    bw.Write(0);                      //group
                    bw.Write(-(images[i].Width / 2)); //origin x
                    bw.Write(images[i].Height / 2);   //origin y
                    bw.Write(images[i].Width);        //w
                    bw.Write(images[i].Height);       //h

                    byte[] arr = new byte[images[i].Width * images[i].Height];
                    images[i].RotateFlip(RotateFlipType.RotateNoneFlipX);
                    System.Runtime.InteropServices.Marshal.Copy(images[i].GetScanlinePointer(0), arr, 0, arr.Length);
                    Array.Reverse(arr);
                    bw.Write(arr);
                }
            }

            //Free resources
            images.ForEach(image => image.Dispose());
        }