Ejemplo n.º 1
0
        /// <summary>
        /// Allocates and decodes all mipmap levels of a DDS texture.
        /// </summary>
        /// <param name="stream">The stream to read the texture data from.</param>
        /// <param name="width">The width of the texture at level 0.</param>
        /// <param name="height">The height of the texture at level 0.</param>
        /// <param name="count">The mipmap count.</param>
        /// <returns>The decoded mipmaps.</returns>
        private MipMap[] AllocateMipMaps <TBlock>(Stream stream, int width, int height, int count)
            where TBlock : struct, IBlock <TBlock>
        {
            var blockFormat = default(TBlock);

            var mipMaps = new MipMap <TBlock> [count];

            for (int i = 0; i < count; i++)
            {
                int widthBlocks  = blockFormat.Compressed ? Helper.CalcBlocks(width) : width;
                int heightBlocks = blockFormat.Compressed ? Helper.CalcBlocks(height) : height;
                int bytesToRead  = heightBlocks * widthBlocks * blockFormat.CompressedBytesPerBlock;

                // Special case for yuv formats with a single pixel.
                if (bytesToRead < blockFormat.BitsPerPixel / 8)
                {
                    bytesToRead = blockFormat.BitsPerPixel / 8;
                }

                byte[] mipData = new byte[bytesToRead];
                int    read    = stream.Read(mipData, 0, bytesToRead);
                if (read != bytesToRead)
                {
                    throw new TextureFormatException("could not read enough texture data from the stream");
                }

                mipMaps[i] = new MipMap <TBlock>(blockFormat, mipData, width, height);

                width  >>= 1;
                height >>= 1;
            }

            return(mipMaps);
        }
Ejemplo n.º 2
0
        public static MipMap Resize(MipMap mipMap, double xScale, double yScale)
        {
            Bitmap bmp    = mipMap.GetBitmap();
            int    width  = (int)(mipMap.Width * xScale);
            int    height = (int)(mipMap.Height * yScale);

            var destRect  = new Rectangle(0, 0, width, height);
            var destImage = new Bitmap(width, height);

            destImage.SetResolution(bmp.HorizontalResolution, bmp.VerticalResolution);

            using (var graphics = System.Drawing.Graphics.FromImage(destImage))
            {
                graphics.CompositingMode    = CompositingMode.SourceCopy;
                graphics.CompositingQuality = CompositingQuality.HighQuality;
                graphics.InterpolationMode  = InterpolationMode.HighQualityBicubic;
                graphics.SmoothingMode      = SmoothingMode.HighQuality;
                graphics.PixelOffsetMode    = PixelOffsetMode.HighQuality;

                using (var wrapMode = new ImageAttributes())
                {
                    wrapMode.SetWrapMode(WrapMode.TileFlipXY);
                    graphics.DrawImage(bmp, destRect, 0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel, wrapMode);
                }
            }

            MipMap result = new MipMap(width, height);

            result.SetPixels(destImage);
            return(result);
        }
Ejemplo n.º 3
0
        public static void importTexture(GpkExport export, string file)
        {
            var texture2d = export.Payload as Texture2D;

            var image  = new DdsFile();
            var config = new DdsSaveConfig(texture2d.GetFormat(), 0, 0, false, false);

            image.Load(file);

            if (image.MipMaps.Count == 0 || Settings.Default.GenerateMipMaps)
            {
                image.GenerateMipMaps();
            }


            texture2d.maps = new List <MipMap>();
            foreach (DdsMipMap mipMap in image.MipMaps.OrderByDescending(mip => mip.Width))
            {
                byte[] outputData = image.WriteMipMap(mipMap, config);

                var textureMipMap = new MipMap();
                textureMipMap.compFlag                     = (int)CompressionTypes.LZO;
                textureMipMap.uncompressedData             = outputData;
                textureMipMap.uncompressedSize             = outputData.Length;
                textureMipMap.uncompressedSize_chunkheader = outputData.Length;
                textureMipMap.sizeX = mipMap.Width;
                textureMipMap.sizeY = mipMap.Height;

                textureMipMap.generateBlocks();
                texture2d.maps.Add(textureMipMap);
            }
        }
Ejemplo n.º 4
0
        //private void AllocateMipMaps(Stream stream)
        //{
        //    if (this.DdsHeader.TextureCount() <= 1)
        //    {
        //        int width = (int)Math.Max(BlockInfo.DivSize, (int)this.DdsHeader.Width);
        //        int height = (int)Math.Max(BlockInfo.DivSize, this.DdsHeader.Height);
        //        int bytesPerPixel = (BlockInfo.BitsPerPixel + 7) / 8;
        //        int stride = CalcStride(width, BlockInfo.BitsPerPixel);
        //        int len = stride * height;

        //        var mipData = new byte[len];
        //        stream.Read(mipData, 0, len);

        //        var mipMap = new MipMap(BlockInfo, mipData, false, width, height, stride / bytesPerPixel);
        //        Swap(mipMap);
        //        this.mipMaps = new[] { mipMap };
        //        return;
        //    }

        //    mipMaps = new MipMap[this.DdsHeader.TextureCount() - 1];

        //    for (int i = 0; i < this.DdsHeader.TextureCount() - 1; i++)
        //    {
        //        int width = (int)Math.Max(BlockInfo.DivSize, (int)(this.DdsHeader.Width / Math.Pow(2, i + 1)));
        //        int height = (int)Math.Max(BlockInfo.DivSize, this.DdsHeader.Height / Math.Pow(2, i + 1));

        //        int bytesPerPixel = (BlockInfo.BitsPerPixel + 7) / 8;
        //        int stride = CalcStride(width, BlockInfo.BitsPerPixel);
        //        int len = stride * height;

        //        var mipData = new byte[len];
        //        stream.Read(mipData, 0, len);

        //        var mipMap = new MipMap(BlockInfo, mipData, false, width, height, stride / bytesPerPixel);
        //        Swap(mipMap);
        //        mipMaps[i] = mipMap;
        //    }
        //}

        private MipMap[] AllocateMipMaps <TBlock>(Stream stream, int width, int height, int count)
            where TBlock : struct, IBlock <TBlock>
        {
            var blockFormat = default(TBlock);

            var mipMaps = new MipMap <TBlock> [count];

            for (int i = 0; i < count; i++)
            {
                int widthBlocks  = blockFormat.Compressed ? Helper.CalcBlocks(width) : width;
                int heightBlocks = blockFormat.Compressed ? Helper.CalcBlocks(height) : height;
                int len          = heightBlocks * widthBlocks * blockFormat.CompressedBytesPerBlock;

                byte[] mipData = new byte[len];
                int    read    = stream.Read(mipData, 0, len);
                if (read != len)
                {
                    throw new InvalidDataException();
                }

                mipMaps[i] = new MipMap <TBlock>(blockFormat, mipData, width, height);

                width  >>= 1;
                height >>= 1;
            }

            return(mipMaps);
        }
Ejemplo n.º 5
0
        public Bitmap Decompress(int mipLevel = 0, bool suppressAlpha = false)
        {
            MipMap mip = MipMaps[mipLevel];

            Bitmap      b             = new Bitmap(mip.Width, mip.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
            SquishFlags flags         = 0;
            bool        notCompressed = false;

            switch (Format)
            {
            case D3DFormat.DXT1:
                flags = SquishFlags.kDxt1;
                break;

            case D3DFormat.DXT5:
                flags = SquishFlags.kDxt5;
                break;

            case D3DFormat.A8R8G8B8:
                notCompressed = true;
                break;

            default:
                throw new NotImplementedException($"Can't decompress: {Format}");
            }

            byte[] dest = new byte[mip.Width * mip.Height * 4];
            byte[] data = mip.Data;

            if (notCompressed)
            {
                for (uint i = 0; i < data.Length - 4; i += 4)
                {
                    uint colour = (uint)((data[i + 3] << 24) | (data[i + 2] << 16) | (data[i + 1] << 8) | (data[i + 0] << 0));

                    dest[i + 0] = (byte)((colour & PixelFormat.BBitMask) >> 0);
                    dest[i + 1] = (byte)((colour & PixelFormat.GBitMask) >> 8);
                    dest[i + 2] = (byte)((colour & PixelFormat.RBitMask) >> 16);
                    dest[i + 3] = (byte)((colour & PixelFormat.ABitMask) >> 24);
                }
            }
            else
            {
                Squish.Squish.DecompressImage(dest, mip.Width, mip.Height, ref data, flags);

                for (uint i = 0; i < dest.Length - 4; i += 4)
                {
                    byte r = dest[i + 0];
                    dest[i + 0] = dest[i + 2];
                    dest[i + 2] = r;
                }
            }

            BitmapData bmpdata = b.LockBits(new Rectangle(0, 0, mip.Width, mip.Height), ImageLockMode.ReadWrite, (suppressAlpha ? System.Drawing.Imaging.PixelFormat.Format32bppRgb : b.PixelFormat));

            Marshal.Copy(dest, 0, bmpdata.Scan0, dest.Length);
            b.UnlockBits(bmpdata);

            return(b);
        }
Ejemplo n.º 6
0
        private void LoadRawPixels(byte[] rawPixelData, int width, int height, int numSourceChannels)
        {
            if (numSourceChannels < 2)
            {
                throw new ArgumentException("Source rawPixelData must have at least 2 channels.");
            }

            Width   = width;
            Height  = height;
            MipMaps = new MipMap[1];
            MipMap mip = null;

            if (numSourceChannels == 2)
            {
                mip = new MipMap(rawPixelData, width, height);
            }
            else
            {
                List <byte> formattedPixelData = new List <byte>();
                int         ptr = 0;

                while (ptr < rawPixelData.Length)
                {
                    // KFreon: Read single pixel
                    formattedPixelData.Add(rawPixelData[ptr++]);
                    formattedPixelData.Add(rawPixelData[ptr++]);

                    // KFreon: Skip unneeded channels
                    ptr += numSourceChannels - 2;
                }
                mip = new MipMap(formattedPixelData.ToArray(), width, height);
            }

            MipMaps[0] = mip;
        }
Ejemplo n.º 7
0
 public override void Init()
 {
     Vector2 size = Engine.Map.GetSize();
     float mapWidth = size.X;
     float mapHeight = size.Y;
     visiblesMap = new MipMap<VisibleProperty>(mapWidth, mapHeight);
     smellablesMap = new MipMap<SmellableProperty>(mapWidth, mapHeight);
 }
Ejemplo n.º 8
0
        public override void Init()
        {
            Vector2 size      = Engine.Map.GetSize();
            float   mapWidth  = size.X;
            float   mapHeight = size.Y;

            visiblesMap   = new MipMap <VisibleProperty>(mapWidth, mapHeight);
            smellablesMap = new MipMap <SmellableProperty>(mapWidth, mapHeight);
        }
Ejemplo n.º 9
0
        public override void Init()
        {
            _cluster     = new Dictionary <int, PhysicsUnit>();
            _collidables = new HashSet <PhysicsUnit>();

            _map = Engine.Map;

            Vector2 size = _map.GetSize();

            _mipmap = new MipMap <PhysicsUnit>(size.X, size.Y);
        }
Ejemplo n.º 10
0
        private void LoadImage(Stream stream)
        {
            stream.Seek(0, SeekOrigin.Begin);
            BinaryReader r       = new BinaryReader(stream);
            int          dwMagic = r.ReadInt32();

            if (dwMagic != 0x20534444)
            {
                throw new Exception("This is not a DDS! Magic number wrong.");
            }

            DDS_HEADER header = new DDS_HEADER();

            Read_DDS_HEADER(header, r);

            if (((header.ddspf.dwFlags & 0x00000004) != 0) && (header.ddspf.dwFourCC == 0x30315844 /*DX10*/))
            {
                throw new Exception("DX10 not supported yet!");
            }

            if (header.ddspf.dwFourCC != 0)
            {
                throw new InvalidDataException("DDS not V8U8.");
            }

            int mipMapCount = 1;

            if ((header.dwFlags & 0x00020000) != 0)
            {
                mipMapCount = header.dwMipMapCount;
            }

            int w = 0;
            int h = 0;

            double bytePerPixel = 2;

            MipMaps = new MipMap[mipMapCount];

            // KFreon: Get mips
            for (int i = 0; i < mipMapCount; i++)
            {
                w = (int)(header.dwWidth / Math.Pow(2, i));
                h = (int)(header.dwHeight / Math.Pow(2, i));

                int mipMapBytes = (int)(w * h * bytePerPixel);
                MipMaps[i] = new MipMap(r.ReadBytes(mipMapBytes), w, h);
            }

            Width  = header.dwWidth;
            Height = header.dwHeight;
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Ensures all Mipmaps are generated in MipMaps.
        /// </summary>
        /// <param name="MipMaps">MipMaps to check.</param>
        /// <returns>Number of mipmaps present in MipMaps.</returns>
        internal static int BuildMipMaps(List <MipMap> MipMaps)
        {
            if (MipMaps?.Count == 0)
            {
                return(0);
            }

            MipMap currentMip = MipMaps[0];

            // KFreon: Check if mips required
            int estimatedMips = DDSGeneral.EstimateNumMipMaps(currentMip.Width, currentMip.Height);

            if (MipMaps.Count > 1)
            {
                return(estimatedMips);
            }

            // KFreon: Half dimensions until one == 1.
            MipMap[] newmips = new MipMap[estimatedMips];

            // TODO: Component size - pixels
            //var baseBMP = UsefulThings.WPF.Images.CreateWriteableBitmap(currentMip.Pixels, currentMip.Width, currentMip.Height);
            //baseBMP.Freeze();

            Action <int> action = new Action <int>(item =>
            {
                int index = item;
                MipMap newmip;
                var scale = 1d / (2 << (index - 1));  // Shifting is 2^index - Math.Pow seems extraordinarly slow.
                //newmip = ImageEngine.Resize(baseBMP, scale, scale, currentMip.Width, currentMip.Height, currentMip.LoadedFormatDetails);
                newmip             = ImageEngine.Resize(currentMip, scale, scale);
                newmips[index - 1] = newmip;
            });

            // Start at 1 to skip top mip
            if (ImageEngine.EnableThreading)
            {
                Parallel.For(1, estimatedMips + 1, new ParallelOptions {
                    MaxDegreeOfParallelism = ImageEngine.NumThreads
                }, action);
            }
            else
            {
                for (int item = 1; item < estimatedMips + 1; item++)
                {
                    action(item);
                }
            }

            MipMaps.AddRange(newmips);
            return(MipMaps.Count);
        }
Ejemplo n.º 12
0
        static int WriteCompressedMipMap(byte[] destination, int mipOffset, MipMap mipmap, int blockSize, Action <byte[], int, int, byte[], int, AlphaSettings, ImageFormats.ImageEngineFormatDetails> compressor,
                                         AlphaSettings alphaSetting)
        {
            if (mipmap.Width < 4 || mipmap.Height < 4)
            {
                return(-1);
            }

            int destinationTexelCount = mipmap.Width * mipmap.Height / 16;
            int sourceLineLength      = mipmap.Width * 4 * mipmap.LoadedFormatDetails.ComponentSize;
            int numTexelsInLine       = mipmap.Width / 4;

            var mipWriter = new Action <int>(texelIndex =>
            {
                // Since this is the top corner of the first texel in a line, skip 4 pixel rows (texel = 4x4 pixels) and the number of rows down the bitmap we are already.
                int sourceLineOffset = sourceLineLength * 4 * (texelIndex / numTexelsInLine);                                                  // Length in bytes x 3 lines x texel line index (how many texel sized lines down the image are we). Index / width will truncate, so for the first texel line, it'll be < 0. For the second texel line, it'll be < 1 and > 0.

                int sourceTopLeftCorner = ((texelIndex % numTexelsInLine) * 16) * mipmap.LoadedFormatDetails.ComponentSize + sourceLineOffset; // *16 since its 4 pixels with 4 channels each. Index % numTexels will effectively reset each line.
                compressor(mipmap.Pixels, sourceTopLeftCorner, sourceLineLength, destination, mipOffset + texelIndex * blockSize, alphaSetting, mipmap.LoadedFormatDetails);
            });

            // Choose an acceleration method.
            if (ImageEngine.EnableThreading)
            {
                Parallel.For(0, destinationTexelCount, new ParallelOptions {
                    MaxDegreeOfParallelism = ImageEngine.NumThreads
                }, (mip, loopState) =>
                {
                    if (ImageEngine.IsCancellationRequested)
                    {
                        loopState.Stop();
                    }

                    mipWriter(mip);
                });
            }
            else
            {
                for (int i = 0; i < destinationTexelCount; i++)
                {
                    if (ImageEngine.IsCancellationRequested)
                    {
                        break;
                    }

                    mipWriter(i);
                }
            }

            return(mipOffset + destinationTexelCount * blockSize);
        }
Ejemplo n.º 13
0
        public DDSImage(string ddsFileName)
        {
            using (FileStream ddsStream = File.OpenRead(ddsFileName))
            {
                using (BinaryReader r = new BinaryReader(ddsStream))
                {
                    dwMagic = r.ReadInt32();
                    if (dwMagic != 0x20534444)
                    {
                        throw new Exception("This is not a DDS!");
                    }

                    Read_DDS_HEADER(header, r);

                    if (((header.ddspf.dwFlags & DDPF_FOURCC) != 0) && (header.ddspf.dwFourCC == FOURCC_DX10 /*DX10*/))
                    {
                        throw new Exception("DX10 not supported yet!");
                    }

                    int mipMapCount = 1;
                    if ((header.dwFlags & DDSD_MIPMAPCOUNT) != 0)
                    {
                        mipMapCount = header.dwMipMapCount;
                    }

                    mipMaps = new MipMap[mipMapCount];

                    ddsFormat = getFormat();

                    double bytePerPixel = getBytesPerPixel(ddsFormat);

                    for (int i = 0; i < mipMapCount; i++)
                    {
                        int w = (int)(header.dwWidth / Math.Pow(2, i));
                        int h = (int)(header.dwHeight / Math.Pow(2, i));

                        if (ddsFormat == DDSFormat.DXT1 || ddsFormat == DDSFormat.DXT5)
                        {
                            w = (w < 4) ? 4 : w;
                            h = (h < 4) ? 4 : h;
                        }

                        int mipMapBytes = (int)(w * h * bytePerPixel);
                        mipMaps[i] = new MipMap(r.ReadBytes(mipMapBytes), ddsFormat, w, h);
                    }
                }
            }
        }
Ejemplo n.º 14
0
        public static void importTexture(GpkExport export, string file)
        {
            try
            {
                var texture2d = export.Payload as Texture2D;

                var image  = new DdsFile();
                var config = new DdsSaveConfig(texture2d.parsedImageFormat, 0, 0, false, false);
                image.Load(file);

                if (image.MipMaps.Count == 0 || CoreSettings.Default.GenerateMipMaps)
                {
                    image.GenerateMipMaps();
                }


                texture2d.maps = new List <MipMap>();
                foreach (DdsMipMap mipMap in image.MipMaps.OrderByDescending(mip => mip.Width))
                {
                    byte[] outputData = image.WriteMipMap(mipMap, config);

                    var textureMipMap = new MipMap();
                    textureMipMap.flags = (int)CompressionTypes.LZO;
                    //textureMipMap.flags = 0;
                    textureMipMap.uncompressedData             = outputData;
                    textureMipMap.uncompressedSize             = outputData.Length;
                    textureMipMap.uncompressedSize_chunkheader = outputData.Length;
                    textureMipMap.sizeX = mipMap.Width;
                    textureMipMap.sizeY = mipMap.Height;

                    if (textureMipMap.flags != 0)
                    {
                        textureMipMap.generateBlocks();
                    }
                    texture2d.maps.Add(textureMipMap);
                }

                int mipTailBaseIdx = (int)Math.Log(image.Width > image.Height ? image.Width : image.Height, 2);
                ((GpkIntProperty)export.GetProperty("MipTailBaseIdx")).SetValue(mipTailBaseIdx.ToString());

                logger.Info("Imported image from {0}, size {1}x{2}, target format {3}, mipTailBaseIdx {4}", file, image.Width, image.Height, config.FileFormat, mipTailBaseIdx);
            }
            catch (Exception ex)
            {
                logger.Error(ex, "Failed to import texture");
                logger.Error(ex);
            }
        }
Ejemplo n.º 15
0
        /// <summary>
        /// Ensures all Mipmaps are generated in MipMaps.
        /// </summary>
        /// <param name="MipMaps">MipMaps to check.</param>
        /// <returns>Number of mipmaps present in MipMaps.</returns>
        internal static int BuildMipMaps(List <MipMap> MipMaps)
        {
            if (MipMaps?.Count == 0)
            {
                return(0);
            }

            MipMap currentMip = MipMaps[0];

            // KFreon: Check if mips required
            int estimatedMips = DDSGeneral.EstimateNumMipMaps(currentMip.Width, currentMip.Height);

            if (MipMaps.Count > 1)
            {
                return(estimatedMips);
            }

            // KFreon: Half dimensions until one == 1.
            MipMap[] newmips = new MipMap[estimatedMips];

            Action <int> action = new Action <int>(item =>
            {
                int index = item;
                MipMap newmip;
                var scale          = 1d / (2 << (index - 1)); // Shifting is 2^index - Math.Pow seems extraordinarly slow.
                newmip             = Resize(currentMip, scale, scale);
                newmips[index - 1] = newmip;
            });

            // Start at 1 to skip top mip
            if (EnableThreading)
            {
                Parallel.For(1, estimatedMips + 1, new ParallelOptions {
                    MaxDegreeOfParallelism = ThreadCount
                }, action);
            }
            else
            {
                for (int item = 1; item < estimatedMips + 1; item++)
                {
                    action(item);
                }
            }

            MipMaps.AddRange(newmips);
            return(MipMaps.Count);
        }
Ejemplo n.º 16
0
        private void SaveDDS(List <string> paths, string outputPath)
        {
            ImageEngineImage outputImage = new ImageEngineImage(paths[0]);

            for (int i = 1; i < paths.Count; i++)
            {
                ImageEngineImage mipImage = new ImageEngineImage(paths[i]);
                MipMap           mip      = new MipMap(mipImage.MipMaps[0].Pixels, mipImage.Width, mipImage.Height, mipImage.FormatDetails);
                outputImage.MipMaps.Add(mip);
            }
            ImageFormats.ImageEngineFormatDetails outputFormat = new ImageFormats.ImageEngineFormatDetails(ImageEngineFormat.DDS_DXT1);
            byte[] data = outputImage.Save(outputFormat, MipHandling.KeepExisting);

            using (var file = File.Create(outputPath))
            {
                file.Write(data, 0, data.Length);
            }
        }
Ejemplo n.º 17
0
        public override bool BuildMipMaps(bool rebuild = false)
        {
            bool success = false;

            MipMap LastMip = MipMaps.Last();

            int width  = LastMip.width;
            int height = LastMip.height;

            Debug.WriteLine("Building V8U8 Mips with starting MIP size of {0} x {1}.", width, height);
            List <MipMap> newMips = new List <MipMap>();

            foreach (var mip in MipMaps)
            {
                newMips.Add(mip);
            }

            try
            {
                byte[] previousMipData = LastMip.data;
                while (width > 1 && height > 1)
                {
                    // KFreon: Need original height to resize. Original = previous, but initially it's the original height.
                    byte[] newMipData = BuildMip(previousMipData, width, height, 2);

                    // KFreon: Adjust to new dimensions for generating the new mipmap
                    height /= 2;
                    width  /= 2;

                    newMips.Add(new MipMap(newMipData, width, height));

                    previousMipData = newMipData;
                }

                MipMaps = newMips.ToArray();
                success = true;
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
            return(success);
        }
Ejemplo n.º 18
0
        public static TDX Load(Stream stream, string name = null)
        {
            TDX tdx = new TDX {
                Name = name
            };

            using (BinaryReader br = new BinaryReader(stream))
            {
                if (br.ReadByte() != 0x00 ||
                    br.ReadByte() != 0x02)
                {
                    Logger.LogToFile(Logger.LogLevel.Error, "This isn't a valid TDX");
                    return(null);
                }

                tdx.Width  = br.ReadUInt16();
                tdx.Height = br.ReadUInt16();
                int mipCount = br.ReadUInt16();
                tdx.Flags  = (TDXFlags)br.ReadUInt32();
                tdx.Format = (D3DFormat)br.ReadUInt32();

                if (tdx.Flags.HasFlag(TDXFlags.ExtraData))
                {
                    int extraDataLength = (int)br.ReadUInt32();
                    int extraDataType   = br.ReadUInt16();

                    switch (extraDataType)
                    {
                    case 0:
                        tdx.ExtraDataType = ExtraDataTypes.Font;
                        tdx.ExtraData     = new FontDefinition(br.ReadBytes(extraDataLength - 2));
                        break;

                    case 1:
                        tdx.ExtraDataType = ExtraDataTypes.Animation;
                        tdx.ExtraData     = new AnimationDefinition(br.ReadBytes(extraDataLength - 2));
                        break;

                    case 3:
                        tdx.ExtraDataType = ExtraDataTypes.VTMap;
                        tdx.ExtraData     = new VTMap(br.ReadBytes(extraDataLength - 2));
                        break;

                    default:
                        throw new NotImplementedException($"Unknown Extra Data flag: {extraDataType}");
                    }
                }

                for (int i = 0; i < mipCount; i++)
                {
                    MipMap mip = new MipMap()
                    {
                        Width  = tdx.Width >> i,
                        Height = tdx.Height >> i
                    };

                    switch (tdx.Format)
                    {
                    case D3DFormat.PVRTC4:
                        mip.Data = br.ReadBytes(mip.Width * mip.Height / 2);
                        break;

                    case D3DFormat.R4G4B4A4:
                    case D3DFormat.R5G5B6:
                    case D3DFormat.R5G6B5:
                        mip.Data = br.ReadBytes(mip.Width * mip.Height * 2);
                        break;

                    case D3DFormat.A8B8G8R8:
                        mip.Data = br.ReadBytes(mip.Width * mip.Height * 4);
                        break;

                    case D3DFormat.A8R8G8B8:
                        mip.Data = br.ReadBytes(mip.Width * mip.Height * (tdx.Flags.HasFlag(TDXFlags.AlphaNbit) ? 4 : 3));
                        break;

                    case D3DFormat.A8:
                        mip.Data = br.ReadBytes(mip.Width * mip.Height);
                        break;

                    case D3DFormat.DXT1:
                        mip.Data = br.ReadBytes((mip.Width + 3) / 4 * ((mip.Height + 3) / 4) * 8);
                        break;

                    case D3DFormat.ATI2:
                    case D3DFormat.DXT5:
                        mip.Data = br.ReadBytes((mip.Width + 3) / 4 * ((mip.Height + 3) / 4) * 16);
                        break;

                    default:
                        Logger.LogToFile(Logger.LogLevel.Error, "Unknown format: {0}", tdx.Format);
                        return(null);
                    }

                    tdx.MipMaps.Add(mip);
                }
            }

            return(tdx);
        }
Ejemplo n.º 19
0
 public void Initialize()
 {
     mipmap = new MipMap <int>(width, height);
 }
Ejemplo n.º 20
0
        public DDSImage(string ddsFileName)
        {
            using (FileStream ddsStream = File.OpenRead(ddsFileName))
            {
                using (BinaryReader r = new BinaryReader(ddsStream))
                {
                    dwMagic = r.ReadInt32();
                    if (dwMagic != 0x20534444)
                    {
                        throw new Exception("This is not a DDS!");
                    }

                    Read_DDS_HEADER(header, r);

                    if (((header.ddspf.dwFlags & DDPF_FOURCC) != 0) && (header.ddspf.dwFourCC == FOURCC_DX10 /*DX10*/))
                    {
                        throw new Exception("DX10 not supported yet!");
                    }

                    int mipMapCount = 1;
                    if ((header.dwFlags & DDSD_MIPMAPCOUNT) != 0)
                        mipMapCount = header.dwMipMapCount;

                    mipMaps = new MipMap[mipMapCount];

                    ddsFormat = getFormat();

                    double bytePerPixel = getBytesPerPixel(ddsFormat);

                    for (int i = 0; i < mipMapCount; i++)
                    {
                        int w = (int)(header.dwWidth / Math.Pow(2, i));
                        int h = (int)(header.dwHeight / Math.Pow(2, i));

                        if (ddsFormat == DDSFormat.DXT1 || ddsFormat == DDSFormat.DXT5)
                        {
                            w = (w < 4) ? 4 : w;
                            h = (h < 4) ? 4 : h;
                        }

                        int mipMapBytes = (int)(w * h * bytePerPixel);
                        mipMaps[i] = new MipMap(r.ReadBytes(mipMapBytes), ddsFormat, w, h);
                    }
                }
            }
        }
Ejemplo n.º 21
0
        public Bitmap GetBitmap(int mipLevel = 0)
        {
            MipMap mip = MipMaps[mipLevel];
            int    x, y;

            Bitmap bmp = new Bitmap(mip.Width, mip.Height, PixelFormat.Format32bppArgb);

            byte[] data;
            byte[] dest;

            switch (Format)
            {
            case D3DFormat.PVRTC4:
                data = mip.Data;
                dest = new byte[mip.Width * mip.Height * 4];

                PVTRC.Decompress(data, false, mip.Width, mip.Height, true, dest);

                for (y = 0; y < mip.Height; y++)
                {
                    for (x = 0; x < mip.Width; x++)
                    {
                        int offset = (x + y * mip.Width) * 4;

                        Color c = Color.FromArgb(dest[offset + 3], dest[offset + 0], dest[offset + 1], dest[offset + 2]);
                        bmp.SetPixel(x, y, c);
                    }
                }
                break;

            case D3DFormat.R4G4B4A4:
                data = mip.Data;

                for (y = 0; y < mip.Height; y++)
                {
                    for (x = 0; x < mip.Width; x++)
                    {
                        int offset = (x + y * mip.Width) * 2;
                        int pixel  = BitConverter.ToUInt16(data, offset);
                        bmp.SetPixel(x, y, ColorHelper.R4G4B4A4ToColor(pixel));
                    }
                }
                break;

            case D3DFormat.R5G5B6:
                data = mip.Data;

                for (y = 0; y < mip.Height; y++)
                {
                    for (x = 0; x < mip.Width; x++)
                    {
                        int offset = (x + y * mip.Width) * 2;
                        int pixel  = BitConverter.ToUInt16(data, offset);
                        bmp.SetPixel(x, y, ColorHelper.R5G5B6ToColor(pixel));
                    }
                }
                break;

            case D3DFormat.A8B8G8R8:
                data = mip.Data;

                for (y = 0; y < mip.Height; y++)
                {
                    for (x = 0; x < mip.Width; x++)
                    {
                        int  offset = (x + y * mip.Width) * 4;
                        uint pixel  = BitConverter.ToUInt32(data, offset);
                        bmp.SetPixel(x, y, ColorHelper.A8B8G8R8ToColor(pixel));
                    }
                }
                break;

            case D3DFormat.R5G6B5:
                data = mip.Data;

                for (y = 0; y < mip.Height; y++)
                {
                    for (x = 0; x < mip.Width; x++)
                    {
                        int offset = (x + y * mip.Width) * 2;
                        int pixel  = BitConverter.ToUInt16(data, offset);
                        bmp.SetPixel(x, y, ColorHelper.R5G6B5ToColor(pixel));
                    }
                }
                break;

            case D3DFormat.A8R8G8B8:
                data = mip.Data;

                int pixelSize = Flags.HasFlag(TDXFlags.AlphaNbit) ? 4 : 3;

                for (y = 0; y < mip.Height; y++)
                {
                    for (x = 0; x < mip.Width; x++)
                    {
                        int offset = (x + y * mip.Width) * pixelSize;
                        int a      = pixelSize == 4 ? data[offset + 3] : 255;

                        Color c = Color.FromArgb(a, data[offset + 0], data[offset + 1], data[offset + 2]);
                        bmp.SetPixel(x, y, c);
                    }
                }
                break;

            case D3DFormat.DXT1:
                data = mip.Data;
                dest = new byte[mip.Width * mip.Height * 4];

                Squish.Squish.DecompressImage(dest, mip.Width, mip.Height, ref data, SquishFlags.kDxt1);

                for (y = 0; y < mip.Height; y++)
                {
                    for (x = 0; x < mip.Width; x++)
                    {
                        int offset = (x + y * mip.Width) * 4;

                        Color c = Color.FromArgb(dest[offset + 3], dest[offset + 0], dest[offset + 1], dest[offset + 2]);
                        bmp.SetPixel(x, y, c);
                    }
                }
                break;

            case D3DFormat.DXT5:
                data = mip.Data;
                dest = new byte[mip.Width * mip.Height * 4];

                Squish.Squish.DecompressImage(dest, mip.Width, mip.Height, ref data, SquishFlags.kDxt5);

                for (y = 0; y < mip.Height; y++)
                {
                    for (x = 0; x < mip.Width; x++)
                    {
                        int offset = (x + y * mip.Width) * 4;

                        Color c = Color.FromArgb(dest[offset + 3], dest[offset + 0], dest[offset + 1], dest[offset + 2]);
                        bmp.SetPixel(x, y, c);
                    }
                }
                break;

            case D3DFormat.ATI2:
                data = mip.Data;

                dest = BC5Unorm.Decompress(data, (uint)mip.Width, (uint)mip.Height);

                for (y = 0; y < mip.Height; y++)
                {
                    for (x = 0; x < mip.Width; x++)
                    {
                        int offset = (x + y * mip.Width) * 4;

                        Color c = Color.FromArgb(dest[offset + 3], dest[offset + 2], dest[offset + 1], dest[offset + 0]);
                        bmp.SetPixel(x, y, c);
                    }
                }
                break;
            }

            return(bmp);
        }
Ejemplo n.º 22
0
        private void LoadImage(Stream stream)
        {
            stream.Seek(0, SeekOrigin.Begin);
            BinaryReader r = new BinaryReader(stream);
            int dwMagic = r.ReadInt32();
            if (dwMagic != 0x20534444)
                throw new Exception("This is not a DDS! Magic number wrong.");

            DDS_HEADER header = new DDS_HEADER();
            Read_DDS_HEADER(header, r);

            if (((header.ddspf.dwFlags & 0x00000004) != 0) && (header.ddspf.dwFourCC == 0x30315844 /*DX10*/))
            {
                throw new Exception("DX10 not supported yet!");
            }

            if (header.ddspf.dwFourCC != 0)
                throw new InvalidDataException("DDS not V8U8.");

            int mipMapCount = 1;
            if ((header.dwFlags & 0x00020000) != 0)
                mipMapCount = header.dwMipMapCount;

            int w = 0;
            int h = 0;

            double bytePerPixel = 2;
            MipMaps = new MipMap[mipMapCount];

            // KFreon: Get mips
            for (int i = 0; i < mipMapCount; i++)
            {
                w = (int)(header.dwWidth / Math.Pow(2, i));
                h = (int)(header.dwHeight / Math.Pow(2, i));

                int mipMapBytes = (int)(w * h * bytePerPixel);
                MipMaps[i] = new MipMap(r.ReadBytes(mipMapBytes), w, h);
            }

            Width = header.dwWidth;
            Height = header.dwHeight;
        }
Ejemplo n.º 23
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="loadMipmaps"></param>
        private Dds Parse(byte[] buffer, bool loadMipmaps = false)
        {
            var dds = new Dds();

            // Adapted from @toji's DDS utils
            //	https://github.com/toji/webgl-texture-utils/blob/master/texture-util/dds.js

            // All values and structures referenced from:
            // http://msdn.microsoft.com/en-us/library/bb943991.aspx/

            var DDS_MAGIC = 0x20534444;

            var DDSD_CAPS        = 0x1;
            var DDSD_HEIGHT      = 0x2;
            var DDSD_WIDTH       = 0x4;
            var DDSD_PITCH       = 0x8;
            var DDSD_PIXELFORMAT = 0x1000;
            var DDSD_MIPMAPCOUNT = 0x20000;
            var DDSD_LINEARSIZE  = 0x80000;
            var DDSD_DEPTH       = 0x800000;

            var DDSCAPS_COMPLEX = 0x8;
            var DDSCAPS_MIPMAP  = 0x400000;
            var DDSCAPS_TEXTURE = 0x1000;

            var DDSCAPS2_CUBEMAP           = 0x200;
            var DDSCAPS2_CUBEMAP_POSITIVEX = 0x400;
            var DDSCAPS2_CUBEMAP_NEGATIVEX = 0x800;
            var DDSCAPS2_CUBEMAP_POSITIVEY = 0x1000;
            var DDSCAPS2_CUBEMAP_NEGATIVEY = 0x2000;
            var DDSCAPS2_CUBEMAP_POSITIVEZ = 0x4000;
            var DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x8000;
            var DDSCAPS2_VOLUME            = 0x200000;

            var DDPF_ALPHAPIXELS = 0x1;
            var DDPF_ALPHA       = 0x2;
            var DDPF_FOURCC      = 0x4;
            var DDPF_RGB         = 0x40;
            var DDPF_YUV         = 0x200;
            var DDPF_LUMINANCE   = 0x20000;

            var FOURCC_DXT1 = FourCcToInt32("DXT1");
            var FOURCC_DXT3 = FourCcToInt32("DXT3");
            var FOURCC_DXT5 = FourCcToInt32("DXT5");

            var headerLengthInt = 31; // The header length in 32 bit ints

            // Offsets into the header array

            var off_magic = 0;

            var off_size   = 1;
            var off_flags  = 2;
            var off_height = 3;
            var off_width  = 4;

            var off_mipmapCount = 7;

            var off_pfFlags     = 20;
            var off_pfFourCC    = 21;
            var off_RGBBitCount = 22;
            var off_RBitMask    = 23;
            var off_GBitMask    = 24;
            var off_BBitMask    = 25;
            var off_ABitMask    = 26;

            var off_caps  = 27;
            var off_caps2 = 28;
            var off_caps3 = 29;
            var off_caps4 = 30;

            // Parse header

            var header = new Int32[headerLengthInt];

            Buffer.BlockCopy(buffer, 0, header, 0, headerLengthInt * sizeof(int));

            if (header[off_magic] != DDS_MAGIC)
            {
                Trace.TraceError("THREE.DDSLoader.parse: Invalid magic number in DDS header.");
                return(dds);
            }

            //if ((header[off_pfFlags] & DDPF_FOURCC) == 0)
            //{
            //    Trace.TraceError("THREE.DDSLoader.parse: Unsupported format, must contain a FourCC code.");
            //    return dds;
            //}

            var blockBytes = 0;

            var fourCC = header[off_pfFourCC];

            var isRGBAUncompressed = false;

            if (fourCC == FOURCC_DXT1)
            {
                blockBytes = 8;
                dds.Format = ThreeCs.Three.RGB_S3TC_DXT1_Format;
            }
            else if (fourCC == FOURCC_DXT3)
            {
                blockBytes = 16;
                dds.Format = ThreeCs.Three.RGBA_S3TC_DXT3_Format;
            }
            else if (fourCC == FOURCC_DXT5)
            {
                blockBytes = 16;
                dds.Format = ThreeCs.Three.RGBA_S3TC_DXT3_Format;
            }
            else
            {
                if (header[off_RGBBitCount] == 32 &&
                    (header[off_RBitMask] & 0xff0000) > 0 &&
                    (header[off_GBitMask] & 0xff00) > 0 &&
                    (header[off_BBitMask] & 0xff) > 0 &&
                    (header[off_ABitMask] & 0xff000000) > 0)
                {
                    isRGBAUncompressed = true;
                    blockBytes         = 64;
                    dds.Format         = ThreeCs.Three.RGBAFormat;
                }
                else
                {
                    Trace.TraceError("THREE.DDSLoader.parse: Unsupported FourCC code ");
                    return(dds);
                }
            }

            dds.MipmapCount = 1;

            if (((header[off_flags] & DDSD_MIPMAPCOUNT) > 0) && loadMipmaps != false)
            {
                dds.MipmapCount = Math.Max(1, header[off_mipmapCount]);
            }

            //TODO: Verify that all faces of the cubemap are present with DDSCAPS2_CUBEMAP_POSITIVEX, etc.

            dds.IsCubemap = ((header[off_caps2] & DDSCAPS2_CUBEMAP) > 0) ? true : false;

            dds.Width  = header[off_width];
            dds.Height = header[off_height];

            var dataOffset = header[off_size] + 4;

            // Extract mipmaps buffers

            var width  = dds.Width;
            var height = dds.Height;

            var faces = dds.IsCubemap ? 6 : 1;

            for (var face = 0; face < faces; face++)
            {
                for (var i = 0; i < dds.MipmapCount; i++)
                {
                    var    dataLength = 0;
                    byte[] byteArray  = null;

                    if (isRGBAUncompressed)
                    {
                        byteArray  = loadARGBMip(buffer, dataOffset, width, height);
                        dataLength = byteArray.Length;
                    }
                    else
                    {
                        dataLength = Math.Max(4, width) / 4 * Math.Max(4, height) / 4 * blockBytes;

                        byteArray = new byte[dataLength];
                        Buffer.BlockCopy(buffer, dataOffset, byteArray, 0, dataLength);
                        //var byteArray = new Uint8Array( buffer, dataOffset, dataLength );
                    }

                    var mipmap = new MipMap()
                    {
                        Data = byteArray, Width = width, Height = height
                    };
                    dds.Mipmaps.Add(mipmap);

                    dataOffset += dataLength;

                    width  = (int)Math.Max(width * 0.5, 1);
                    height = (int)Math.Max(height * 0.5, 1);
                }

                width  = dds.Width;
                height = dds.Height;
            }

            return(dds);
        }
Ejemplo n.º 24
0
 static void WriteUncompressedMipMap(byte[] destination, int mipOffset, MipMap mipmap, ImageFormats.ImageEngineFormatDetails destFormatDetails, DDS_Header.DDS_PIXELFORMAT ddspf)
 {
     DDS_Encoders.WriteUncompressed(mipmap.Pixels, destination, mipOffset, ddspf, mipmap.LoadedFormatDetails, destFormatDetails);
 }
Ejemplo n.º 25
0
        BitmapSource GetWPFBitmap(MipMap mip, int maxDimension, bool ShowAlpha)
        {
            BitmapSource bmp = null;

            if (maxDimension != 0)
            {
                // Choose a mip of the correct size, if available.
                var sizedMip = MipMaps.Where(m => (m.Height <= maxDimension && m.Width <= maxDimension) || (m.Width <= maxDimension && m.Height <= maxDimension));
                if (sizedMip.Any())
                {
                    var mip1 = sizedMip.First();
                    bmp = mip1.ToImage();
                }
                else
                {
                    double scale = (double)maxDimension / (Height > Width ? Height : Width);
                    mip = ImageEngine.Resize(mip, scale);
                    bmp = mip.ToImage();
                }         
            }
            else
                bmp = mip.ToImage();

            if (!ShowAlpha)
                bmp = new FormatConvertedBitmap(bmp, System.Windows.Media.PixelFormats.Bgr32, null, 0);

            bmp.Freeze();
            return bmp;
        }
Ejemplo n.º 26
0
        internal static List <MipMap> LoadDDS(MemoryStream compressed, DDS_Header header, int desiredMaxDimension, ImageFormats.ImageEngineFormatDetails formatDetails)
        {
            MipMap[] MipMaps = null;

            int mipWidth             = header.Width;
            int mipHeight            = header.Height;
            ImageEngineFormat format = header.Format;

            int estimatedMips  = header.dwMipMapCount;
            int mipOffset      = formatDetails.HeaderSize;
            int originalOffset = mipOffset;

            if (!EnsureMipInImage(compressed.Length, mipWidth, mipHeight, 4, formatDetails, out mipOffset))  // Update number of mips too
            {
                estimatedMips = 1;
            }

            if (estimatedMips == 0)
            {
                estimatedMips = EstimateNumMipMaps(mipWidth, mipHeight);
            }

            mipOffset = originalOffset;  // Needs resetting after checking there's mips in this image.

            // Ensure there's at least 1 mipmap
            if (estimatedMips == 0)
            {
                estimatedMips = 1;
            }

            int orig_estimatedMips = estimatedMips; // Store original count for later (uncompressed only I think)

            // KFreon: Decide which mip to start loading at - going to just load a few mipmaps if asked instead of loading all, then choosing later. That's slow.
            if (desiredMaxDimension != 0 && estimatedMips > 1)
            {
                if (!EnsureMipInImage(compressed.Length, mipWidth, mipHeight, desiredMaxDimension, formatDetails, out mipOffset))  // Update number of mips too
                {
                    throw new InvalidDataException($"Requested mipmap does not exist in this image. Top Image Size: {mipWidth}x{mipHeight}, requested mip max dimension: {desiredMaxDimension}.");
                }

                // Not the first mipmap.
                if (mipOffset > formatDetails.HeaderSize)
                {
                    double divisor = mipHeight > mipWidth ? mipHeight / desiredMaxDimension : mipWidth / desiredMaxDimension;
                    mipHeight = (int)(mipHeight / divisor);
                    mipWidth  = (int)(mipWidth / divisor);

                    if (mipWidth == 0 || mipHeight == 0)  // Reset as a dimension is too small to resize
                    {
                        mipHeight = header.Height;
                        mipWidth  = header.Width;
                        mipOffset = formatDetails.HeaderSize;
                    }
                    else
                    {
                        // Update estimated mips due to changing dimensions.
                        estimatedMips = EstimateNumMipMaps(mipWidth, mipHeight);
                    }
                }
                else  // The first mipmap
                {
                    mipOffset = formatDetails.HeaderSize;
                }
            }

            // Move to requested mipmap
            compressed.Position = mipOffset;

            // Block Compressed texture chooser.
            Action <byte[], int, byte[], int, int, bool> DecompressBCBlock = formatDetails.BlockDecoder;

            MipMaps = new MipMap[estimatedMips];
            int blockSize = formatDetails.BlockSize;

            // KFreon: Read mipmaps
            if (formatDetails.IsBlockCompressed)    // Threading done in the decompression, not here.
            {
                for (int m = 0; m < estimatedMips; m++)
                {
                    if (ImageEngine.IsCancellationRequested)
                    {
                        break;
                    }


                    // KFreon: If mip is too small, skip out. This happens most often with non-square textures. I think it's because the last mipmap is square instead of the same aspect.
                    // Don't do the mip size check here (<4) since we still need to have a MipMap object for those lower than this for an accurate count.
                    if (mipWidth <= 0 || mipHeight <= 0)  // Needed cos it doesn't throw when reading past the end for some reason.
                    {
                        break;
                    }

                    MipMap mipmap = ReadCompressedMipMap(compressed, mipWidth, mipHeight, mipOffset, formatDetails, DecompressBCBlock);
                    MipMaps[m] = mipmap;
                    mipOffset += (int)(mipWidth * mipHeight * (blockSize / 16d)); // Also put the division in brackets cos if the mip dimensions are high enough, the multiplications can exceed int.MaxValue)
                    mipWidth  /= 2;
                    mipHeight /= 2;
                }
            }
            else
            {
                int startMip = orig_estimatedMips - estimatedMips;

                // UNCOMPRESSED - Can't really do threading in "decompression" so do it for the mipmaps.
                var action = new Action <int>(mipIndex =>
                {
                    // Calculate mipOffset and dimensions
                    int offset, width, height;
                    offset = GetMipOffset(mipIndex, formatDetails, header.Width, header.Height);

                    double divisor = mipIndex == 0 ? 1d : 2 << (mipIndex - 1);   // Divisor represents 2^mipIndex - Math.Pow seems very slow.
                    width          = (int)(header.Width / divisor);
                    height         = (int)(header.Height / divisor);

                    MipMap mipmap = null;
                    try
                    {
                        mipmap = ReadUncompressedMipMap(compressed, offset, width, height, header.ddspf, formatDetails);
                    }
                    catch (Exception e)
                    {
                        Debug.WriteLine(e.ToString());
                    }

                    MipMaps[mipIndex] = mipmap;
                });

                if (ImageEngine.EnableThreading)
                {
                    Parallel.For(startMip, orig_estimatedMips, new ParallelOptions {
                        MaxDegreeOfParallelism = ImageEngine.NumThreads
                    }, (mip, loopState) =>
                    {
                        if (ImageEngine.IsCancellationRequested)
                        {
                            loopState.Stop();
                        }

                        action(mip);
                    });
                }
                else
                {
                    for (int i = startMip; i < orig_estimatedMips; i++)
                    {
                        if (ImageEngine.IsCancellationRequested)
                        {
                            break;
                        }

                        action(i);
                    }
                }
            }

            List <MipMap> mips = new List <MipMap>(MipMaps.Where(t => t != null));

            if (mips.Count == 0)
            {
                throw new InvalidOperationException($"No mipmaps loaded. Estimated mips: {estimatedMips}, mip dimensions: {mipWidth}x{mipHeight}");
            }
            return(mips);
        }
Ejemplo n.º 27
0
        public override void Deserialize(Stream input)
        {
            var encoding = this.Encoding;

            var basePosition = input.Position;

            base.Deserialize(input);
            var endian = this.Endian;

            var entryCount           = input.ReadValueS32(endian);
            var entryNameTableOffset = input.ReadValueS64(endian);

            var rawEntries = new RawEntry[entryCount];

            for (int i = 0; i < entryCount; i++)
            {
                rawEntries[i] = RawEntry.Read(input, endian);
            }

            var entryNames = new string[entryCount];

            if (entryCount > 0)
            {
                input.Position = basePosition + entryNameTableOffset;
                for (int i = 0; i < entryCount; i++)
                {
                    var nameLength = input.ReadValueU16(endian);
                    var name       = input.ReadString(nameLength, encoding);
                    entryNames[i] = name;
                }
            }

            // we're assuming the entry names match up in order with the entries
            var entries = new Entry[entryCount];

            for (int i = 0; i < entryCount; i++)
            {
                var rawEntry   = rawEntries[i];
                var rawMipMaps = rawEntry.MipMaps;

                var mipMaps = new MipMap[rawMipMaps.Length];
                for (int j = 0; j < rawMipMaps.Length; j++)
                {
                    var rawMipMap = rawMipMaps[j];
                    mipMaps[j] = new MipMap()
                    {
                        DataOffset           = rawMipMap.DataOffset,
                        DataCompressedSize   = rawMipMap.DataCompressedSize,
                        DataUncompressedSize = rawMipMap.DataUncompressedSize,
                        IndexStart           = rawMipMap.IndexStart,
                        IndexEnd             = rawMipMap.IndexEnd,
                    };
                }

                entries[i] = new Entry()
                {
                    Name              = entryNames[i],
                    NameHash          = rawEntry.NameHash,
                    Type              = rawEntry.Type,
                    DirectoryNameHash = rawEntry.DirectoryNameHash,
                    Unknown0C         = rawEntry.Unknown0C,
                    Height            = rawEntry.Height,
                    Width             = rawEntry.Width,
                    MipMapCount       = rawEntry.MipMapCount,
                    Format            = rawEntry.Format,
                    Unknown16         = rawEntry.Unknown16,
                    Unknown17         = rawEntry.Unknown17,
                    MipMaps           = mipMaps,
                };
            }

            this._Entries.Clear();
            this._Entries.AddRange(entries);
        }
Ejemplo n.º 28
0
        public static DDS Load(byte[] data)
        {
            DDS dds = new DDS();

            using (MemoryStream ms = new MemoryStream(data))
                using (BinaryReader br = new BinaryReader(ms))
                {
                    if (!IsDDS(br))
                    {
                        return(null);
                    }

                    br.ReadUInt32(); // header length
                    dds.Flags  = (HeaderFlags)br.ReadUInt32();
                    dds.Height = (int)br.ReadUInt32();
                    dds.Width  = (int)br.ReadUInt32();
                    dds.Pitch  = (int)br.ReadUInt32();
                    dds.Depth  = (int)br.ReadUInt32();
                    int mipCount = (int)br.ReadUInt32();
                    for (int i = 0; i < 11; i++)
                    {
                        br.ReadUInt32();
                    }
                    br.ReadUInt32(); // pixel format length
                    dds.PixelFormat = new DDSPixelFormat
                    {
                        Flags       = (PixelFormatFlags)br.ReadUInt32(),
                        FourCC      = (PixelFormatFourCC)br.ReadUInt32(),
                        RGBBitCount = (int)br.ReadUInt32(),
                        RBitMask    = br.ReadUInt32(),
                        GBitMask    = br.ReadUInt32(),
                        BBitMask    = br.ReadUInt32(),
                        ABitMask    = br.ReadUInt32()
                    };
                    dds.Caps  = (DDSCaps)br.ReadUInt32();
                    dds.Caps2 = (DDSCaps2)br.ReadUInt32();
                    br.ReadUInt32();
                    br.ReadUInt32();
                    br.ReadUInt32();

                    if (dds.PixelFormat.Flags.HasFlag(PixelFormatFlags.DDPF_FOURCC))
                    {
                        dds.Format = (D3DFormat)dds.PixelFormat.FourCC;
                    }
                    else if (dds.PixelFormat.Flags.HasFlag(PixelFormatFlags.DDPF_RGB) & dds.PixelFormat.Flags.HasFlag(PixelFormatFlags.DDPF_ALPHAPIXELS))
                    {
                        dds.Format = D3DFormat.A8R8G8B8;
                    }

                    for (int i = 0; i < Math.Max(1, mipCount); i++)
                    {
                        MipMap mip = new MipMap
                        {
                            Width  = dds.Width >> i,
                            Height = dds.Height >> i
                        };

                        switch (dds.Format)
                        {
                        case D3DFormat.A8R8G8B8:
                            mip.Data = br.ReadBytes(mip.Width * mip.Height * 4);
                            break;

                        case D3DFormat.DXT1:
                            mip.Data = br.ReadBytes((((mip.Width + 3) / 4) * ((mip.Height + 3) / 4)) * 8);
                            break;

                        case D3DFormat.DXT3:
                        case D3DFormat.DXT5:
                            mip.Data = br.ReadBytes((((mip.Width + 3) / 4) * ((mip.Height + 3) / 4)) * 16);
                            break;
                        }

                        dds.MipMaps.Add(mip);
                    }
                }

            return(dds);
        }
Ejemplo n.º 29
0
        private void readHeader(Stream stream)
        {
            byte[] buffer = new byte[HEADER_SIZE];
            stream.Read(buffer, 0, HEADER_SIZE);

            long dataSize   = BitConverter.ToUInt32(buffer, 0);
            bool compressed = dataSize != 0;

            float alphaTest = BitConverter.ToSingle(buffer, 4);

            int width  = BitConverter.ToUInt16(buffer, 8),
                height = BitConverter.ToUInt16(buffer, 10);

            encoding = (Encoding)buffer[12];
            //bool hasAlpha = ((int)encoding & 4) == 4;

            int mipMapCount = Math.Max(1, (int)buffer[13]);

            int minDataSize;

            switch (encoding)
            {
            case Encoding.Gray:
                Format      = TextureFormat.RGB24;
                minDataSize = 1;
                dataSize    = width * height * minDataSize;
                break;

            case Encoding.RGB:
                if (compressed)
                {
                    Format      = TextureFormat.DXT1;
                    minDataSize = 8;
                }
                else
                {
                    Format      = TextureFormat.RGB24;
                    minDataSize = 3;
                    dataSize    = width * height * minDataSize;
                }
                break;

            case Encoding.RGBA:
                if (compressed)
                {
                    Format      = TextureFormat.DXT5;
                    minDataSize = 16;
                }
                else
                {
                    Format      = TextureFormat.RGBA32;
                    minDataSize = 4;
                    dataSize    = width * height * minDataSize;
                }
                break;

            case Encoding.BGRA:
                Format      = TextureFormat.BGRA32;
                minDataSize = 4;
                dataSize    = width * height * minDataSize;
                break;

            default:
                Format      = TextureFormat.RGB24;
                minDataSize = 0;
                break;
            }

            // Calculate the complete data size for images with mipmaps
            long completeDataSize = dataSize;
            int  w = width, h = height;

            for (int i = 1; i < mipMapCount; ++i)
            {
                w = Math.Max(w >> 1, 1);
                h = Math.Max(h >> 1, 1);

                completeDataSize += getDataSize(Format, w, h);
            }
            completeDataSize *= _layerCount;

            stream.Position += completeDataSize;
            readTXIData(stream);

            bool isAnimated = false;

            //checkAnimated(width, height, dataSize);

            stream.Position = HEADER_SIZE;

            long fullImageSize = getDataSize(Format, width, height);
            long combinedSize  = 0;

            mipMaps = new MipMap[mipMapCount];
            for (int l = 0; l < _layerCount; l++)
            {
                int  layerWidth  = width;
                int  layerHeight = height;
                long layerSize   = (isAnimated) ? getDataSize(Format, layerWidth, layerHeight) : dataSize;

                for (int i = 0; i < mipMapCount; i++)
                {
                    mipMaps[i] = new MipMap();

                    mipMaps[i].width  = Math.Max(layerWidth, 1);
                    mipMaps[i].height = Math.Max(layerHeight, 1);

                    mipMaps[i].size = Math.Max(layerSize, minDataSize);

                    long mipMapDataSize = getDataSize(Format, mipMaps[i].width, mipMaps[i].height);

                    combinedSize += mipMaps[i].size;

                    layerWidth  >>= 1;
                    layerHeight >>= 1;
                    layerSize     = getDataSize(Format, layerWidth, layerHeight);

                    if ((layerWidth < 1) && (layerHeight < 1))
                    {
                        break;
                    }
                }
            }
        }
Ejemplo n.º 30
0
        public static XT2 Load(string path)
        {
            FileInfo fi = new FileInfo(path);

            Console.WriteLine("{0}", path);
            XT2 xt2 = new XT2()
            {
                Name = fi.Name.Replace(fi.Extension, "")
            };

            using (BEBinaryReader br = new BEBinaryReader(fi.OpenRead()))
            {
                Console.WriteLine("Always 0 : {0}", br.ReadUInt32());

                int magic = (int)br.ReadUInt32();

                br.ReadUInt32();    // datasize
                Console.WriteLine("Always 52 : {0}", br.ReadUInt32());
                Console.WriteLine("Always 0 : {0}", br.ReadUInt16());
                xt2.Width  = br.ReadUInt16();
                xt2.Height = br.ReadUInt16();
                Console.WriteLine("{0} {1}", br.ReadUInt16(), br.ReadUInt16());

                xt2.Header = new D3DBaseTexture(br);

                int W          = 0;
                int H          = 0;
                int TexelPitch = 0;
                int DataSize   = 0;
                int OutSize    = 0;
                int w          = xt2.Width;
                int h          = xt2.Height;

                switch (xt2.Header.DataFormat)
                {
                    //case D3DFormat.X360_A8R8G8B8:
                    //    W = w;
                    //    H = h;
                    //    TexelPitch = 4;
                    //    DataSize = w * h * 4;
                    //    break;

                    //case D3DFormat.X360_DXT1:
                    //    W = w / 4;
                    //    H = h / 4;
                    //    TexelPitch = 8;
                    //    DataSize = w * h / 2;
                    //    break;

                    //case D3DFormat.X360_DXT2:
                    //    W = w / 4;
                    //    H = h / 4;
                    //    TexelPitch = 16;
                    //    DataSize = W * H;
                    //    break;
                }

                if (H % 128 != 0)
                {
                    H += 128 - H % 128;
                }

                switch (xt2.Header.DataFormat)
                {
                    //case D3DFormat.X360_A8R8G8B8:
                    //    OutSize = W * H * TexelPitch;
                    //    break;

                    //case D3DFormat.X360_DXT1:
                    //    OutSize = W * H * TexelPitch;
                    //    break;

                    //case D3DFormat.X360_DXT2:
                    //    DataSize = w * H * 2;
                    //    OutSize = W * H * TexelPitch;
                    //    break;
                }

                byte[] data    = new byte[DataSize];
                byte[] outdata = new byte[OutSize];

                Array.Copy(br.ReadBytes(DataSize), data, DataSize);

                int step = xt2.Header.Endian == 1 ? 2 : 4;
                for (int i = 0; i < data.Length; i += step)
                {
                    for (int j = 0; j < step / 2; j++)
                    {
                        byte tmp = data[i + j];
                        data[i + j]            = data[i + step - j - 1];
                        data[i + step - j - 1] = tmp;
                    }
                }

                for (int y = 0; y < H; y++)
                {
                    for (int x = 0; x < W; x++)
                    {
                        int offset = Xbox360ConvertTextureAddress(x, y, W, TexelPitch);
                        if (offset * TexelPitch < data.Length)
                        {
                            Array.Copy(data, offset * TexelPitch, outdata, (x + y * W) * TexelPitch, TexelPitch);
                        }
                    }
                }

                MipMap mip = new MipMap
                {
                    Width  = xt2.Width,
                    Height = xt2.Height,
                    Data   = data
                };

                xt2.MipMaps.Add(mip);
            }

            return(xt2);
        }
Ejemplo n.º 31
0
        /// <summary>
        /// Ensures all Mipmaps are generated in MipMaps.
        /// </summary>
        /// <param name="MipMaps">MipMaps to check.</param>
        /// <returns>Number of mipmaps present in MipMaps.</returns>
        internal static int BuildMipMaps(List<MipMap> MipMaps)
        {
            if (MipMaps?.Count == 0)
                return 0;

            MipMap currentMip = MipMaps[0];

            // KFreon: Check if mips required
            int estimatedMips = DDSGeneral.EstimateNumMipMaps(currentMip.Width, currentMip.Height);
            if (MipMaps.Count > 1)
                return estimatedMips;

            // KFreon: Half dimensions until one == 1.
            MipMap[] newmips = new MipMap[estimatedMips];

            var baseBMP = UsefulThings.WPF.Images.CreateWriteableBitmap(currentMip.Pixels, currentMip.Width, currentMip.Height);
            baseBMP.Freeze();

            Action<int> action = new Action<int>(item =>
            {
                int index = item;
                MipMap newmip;
                var scale = 1d / (2 << (index - 1));  // Shifting is 2^index - Math.Pow seems extraordinarly slow.
                newmip = ImageEngine.Resize(baseBMP, scale, scale, currentMip.Width, currentMip.Height);
                newmips[index - 1] = newmip;
            });

            // Start at 1 to skip top mip
            if (ImageEngine.EnableThreading)
                Parallel.For(1, estimatedMips + 1, new ParallelOptions { MaxDegreeOfParallelism = ImageEngine.NumThreads }, action);
            else
                for (int item = 1; item < estimatedMips + 1; item++)
                    action(item);

            MipMaps.AddRange(newmips);
            return estimatedMips;
        }
Ejemplo n.º 32
0
 static int WriteUncompressedMipMap(byte[] destination, int mipOffset, MipMap mipmap, ImageEngineFormat saveFormat, DDS_Header.DDS_PIXELFORMAT ddspf)
 {
     return DDS_Encoders.WriteUncompressed(mipmap.Pixels, destination, mipOffset, ddspf);
 }
Ejemplo n.º 33
0
        public static (string, IDxt <IImage>) ReadDds(IFile ddsFile)
        {
            using var ddsStream = ddsFile.OpenRead();
            var er = new EndianBinaryReader(ddsStream, Endianness.LittleEndian);

            er.AssertString("DDS ");
            er.AssertInt32(124); // size
            var flags = er.ReadInt32();

            var width  = er.ReadInt32();
            var height = er.ReadInt32();

            var pitchOrLinearSize = er.ReadInt32();
            var depth             = er.ReadInt32();
            // TODO: Read others
            var mipmapCount = er.ReadInt32();
            var reserved1   = er.ReadInt32s(11);

            // DDS_PIXELFORMAT
            er.AssertInt32(32); // size
            var pfFlags       = er.ReadInt32();
            var pfFourCc      = er.ReadString(4);
            var pfRgbBitCount = er.ReadInt32();
            var pfRBitMask    = er.ReadInt32();
            var pfGBitMask    = er.ReadInt32();
            var pfBBitMask    = er.ReadInt32();
            var pfABitMask    = er.ReadInt32();

            var caps1 = er.ReadInt32();

            var caps2        = er.ReadInt32();
            var isCubeMap    = (caps2 & 0x200) != 0;
            var hasPositiveX = (caps2 & 0x400) != 0;
            var hasNegativeX = (caps2 & 0x800) != 0;
            var hasPositiveY = (caps2 & 0x1000) != 0;
            var hasNegativeY = (caps2 & 0x2000) != 0;
            var hasPositiveZ = (caps2 & 0x4000) != 0;
            var hasNegativeZ = (caps2 & 0x8000) != 0;
            var hasVolume    = (caps2 & 0x200000) != 0;

            var sideCount = new[] {
                hasPositiveX, hasNegativeX,
                hasPositiveY, hasNegativeY,
                hasPositiveZ, hasNegativeZ
            }.Count(b => b);

            sideCount = Math.Max(1, sideCount);

            var queue = new Queue <CubeMapSide>();

            if (hasPositiveX)
            {
                queue.Enqueue(CubeMapSide.POSITIVE_X);
            }
            if (hasNegativeX)
            {
                queue.Enqueue(CubeMapSide.NEGATIVE_X);
            }
            if (hasPositiveY)
            {
                queue.Enqueue(CubeMapSide.POSITIVE_Y);
            }
            if (hasNegativeY)
            {
                queue.Enqueue(CubeMapSide.NEGATIVE_Y);
            }
            if (hasPositiveZ)
            {
                queue.Enqueue(CubeMapSide.POSITIVE_Z);
            }
            if (hasNegativeZ)
            {
                queue.Enqueue(CubeMapSide.NEGATIVE_Z);
            }

            er.Position = 128;

            switch (pfFourCc)
            {
            case "q\0\0\0": {
                var q000Text = "a16b16g16r16";

                var hdrCubeMap = new CubeMapImpl <IList <float> >();

                for (var s = 0; s < sideCount; s++)
                {
                    var hdrMipMap = new MipMap <IList <float> >();

                    for (var i = 0; i < mipmapCount; ++i)
                    {
                        var mmWidth  = width >> i;
                        var mmHeight = height >> i;

                        var hdr = DecompressA16B16G16R16F(er, mmWidth, mmHeight);
                        hdrMipMap.AddLevel(
                            new MipMapLevel <IList <float> >(hdr, mmWidth, mmHeight));
                    }

                    if (!isCubeMap)
                    {
                        return(
                            q000Text,
                            new DxtImpl <IImage>(
                                ToneMapAndConvertHdrMipMapsToBitmap(hdrMipMap)));
                    }

                    var side = queue.Dequeue();
                    switch (side)
                    {
                    case CubeMapSide.POSITIVE_X: {
                        hdrCubeMap.PositiveX = hdrMipMap;
                        break;
                    }

                    case CubeMapSide.NEGATIVE_X: {
                        hdrCubeMap.NegativeX = hdrMipMap;
                        break;
                    }

                    case CubeMapSide.POSITIVE_Y: {
                        hdrCubeMap.PositiveY = hdrMipMap;
                        break;
                    }

                    case CubeMapSide.NEGATIVE_Y: {
                        hdrCubeMap.NegativeY = hdrMipMap;
                        break;
                    }

                    case CubeMapSide.POSITIVE_Z: {
                        hdrCubeMap.PositiveZ = hdrMipMap;
                        break;
                    }

                    case CubeMapSide.NEGATIVE_Z: {
                        hdrCubeMap.NegativeZ = hdrMipMap;
                        break;
                    }

                    default: throw new ArgumentOutOfRangeException();
                    }
                }

                return(q000Text,
                       new DxtImpl <IImage>(
                           ToneMapAndConvertHdrCubemapToBitmap(hdrCubeMap)));
            }

            default: {
                ddsStream.Position = 0;
                return(pfFourCc,
                       new DxtImpl <IImage>(new DdsReader().Read(ddsStream)));
            }
            }
        }
Ejemplo n.º 34
0
        static int WriteCompressedMipMap(byte[] destination, int mipOffset, MipMap mipmap, int blockSize, Action<byte[], int, int, byte[], int, AlphaSettings> compressor, AlphaSettings alphaSetting)
        {
            int destinationTexelCount = mipmap.Width * mipmap.Height / 16;
            int sourceLineLength = mipmap.Width * 4;
            int numTexelsInLine = mipmap.Width / 4;

            var mipWriter = new Action<int>(texelIndex =>
            {
                // Since this is the top corner of the first texel in a line, skip 4 pixel rows (texel = 4x4 pixels) and the number of rows down the bitmap we are already.
                int sourceLineOffset = sourceLineLength * 4 * (texelIndex / numTexelsInLine);  // Length in bytes x 3 lines x texel line index (how many texel sized lines down the image are we). Index / width will truncate, so for the first texel line, it'll be < 0. For the second texel line, it'll be < 1 and > 0.

                int sourceTopLeftCorner = ((texelIndex % numTexelsInLine) * 16) + sourceLineOffset; // *16 since its 4 pixels with 4 channels each. Index % numTexels will effectively reset each line.
                compressor(mipmap.Pixels, sourceTopLeftCorner, sourceLineLength, destination, mipOffset + texelIndex * blockSize, alphaSetting);
            });

            // Choose an acceleration method.
            if (ImageEngine.EnableGPUAcceleration)
                Debugger.Break();
            else if (ImageEngine.EnableThreading)
                Parallel.For(0, destinationTexelCount, new ParallelOptions { MaxDegreeOfParallelism = ImageEngine.NumThreads }, mipWriter);
            else
                for (int i = 0; i < destinationTexelCount; i++)
                    mipWriter(i);

            return mipOffset + destinationTexelCount * blockSize;
        }
Ejemplo n.º 35
0
 /// <summary>
 /// Creates image from mipmap.
 /// </summary>
 /// <param name="mip">Mipmap to use as source.</param>
 public ImageEngineImage(MipMap mip)
 {
     MipMaps.Add(mip);
 }
Ejemplo n.º 36
0
        internal static List<MipMap> LoadDDS(MemoryStream compressed, DDS_Header header, int desiredMaxDimension)
        {
            MipMap[] MipMaps = null;

            int mipWidth = header.Width;
            int mipHeight = header.Height;
            ImageEngineFormat format = header.Format;
            int blockSize = ImageFormats.GetBlockSize(format);

            int estimatedMips = header.dwMipMapCount;
            int mipOffset = 128;  // Includes header.
            // TODO: Incorrect mip offset for DX10

            if (!EnsureMipInImage(compressed.Length, mipWidth, mipHeight, 4, format, out mipOffset))  // Update number of mips too
                estimatedMips = 1;

            if (estimatedMips == 0)
                estimatedMips = EstimateNumMipMaps(mipWidth, mipHeight);

            mipOffset = 128;  // Needs resetting after checking there's mips in this image.

            // TESTUNIG
            if (estimatedMips == 0)
                estimatedMips = 1;

            int orig_estimatedMips = estimatedMips; // Store original count for later (uncompressed only I think)

            // KFreon: Decide which mip to start loading at - going to just load a few mipmaps if asked instead of loading all, then choosing later. That's slow.
            if (desiredMaxDimension != 0 && estimatedMips > 1)
            {
                if (!EnsureMipInImage(compressed.Length, mipWidth, mipHeight, desiredMaxDimension, format, out mipOffset))  // Update number of mips too
                    throw new InvalidDataException($"Requested mipmap does not exist in this image. Top Image Size: {mipWidth}x{mipHeight}, requested mip max dimension: {desiredMaxDimension}.");

                // Not the first mipmap.
                if (mipOffset > 128)
                {

                    double divisor = mipHeight > mipWidth ? mipHeight / desiredMaxDimension : mipWidth / desiredMaxDimension;
                    mipHeight = (int)(mipHeight / divisor);
                    mipWidth = (int)(mipWidth / divisor);

                    if (mipWidth == 0 || mipHeight == 0)  // Reset as a dimension is too small to resize
                    {
                        mipHeight = header.Height;
                        mipWidth = header.Width;
                        mipOffset = 128;
                    }
                    else
                    {
                        // Update estimated mips due to changing dimensions.
                        estimatedMips = EstimateNumMipMaps(mipWidth, mipHeight);
                    }
                }
                else  // The first mipmap
                    mipOffset = 128;

            }

            // Move to requested mipmap
            compressed.Position = mipOffset;

            // Block Compressed texture chooser.
            Action<byte[], int, byte[], int, int, bool> DecompressBCBlock = null;
            switch (format)
            {
                case ImageEngineFormat.DDS_DXT1:
                    DecompressBCBlock = DDS_Decoders.DecompressBC1Block;
                    break;
                case ImageEngineFormat.DDS_DXT2:
                case ImageEngineFormat.DDS_DXT3:
                    DecompressBCBlock = DDS_Decoders.DecompressBC2Block;
                    break;
                case ImageEngineFormat.DDS_DXT4:
                case ImageEngineFormat.DDS_DXT5:
                    DecompressBCBlock = DDS_Decoders.DecompressBC3Block;
                    break;
                case ImageEngineFormat.DDS_ATI1:
                    DecompressBCBlock = DDS_Decoders.DecompressATI1;
                    break;
                case ImageEngineFormat.DDS_ATI2_3Dc:
                    DecompressBCBlock = DDS_Decoders.DecompressATI2Block;
                    break;
            }

            MipMaps = new MipMap[estimatedMips];

            // KFreon: Read mipmaps
            if (ImageFormats.IsBlockCompressed(format))    // Threading done in the decompression, not here.
            {
                for (int m = 0; m < estimatedMips; m++)
                {
                    // KFreon: If mip is too small, skip out. This happens most often with non-square textures. I think it's because the last mipmap is square instead of the same aspect.
                    if (mipWidth <= 0 || mipHeight <= 0)  // Needed cos it doesn't throw when reading past the end for some reason.
                    {
                        break;
                    }
                    MipMap mipmap = ReadCompressedMipMap(compressed, mipWidth, mipHeight, blockSize, mipOffset, (format == ImageEngineFormat.DDS_DXT2 || format == ImageEngineFormat.DDS_DXT4), DecompressBCBlock);

                    MipMaps[m] = mipmap;
                    mipOffset += (int)(mipWidth * mipHeight * (blockSize / 16d)); // Also put the division in brackets cos if the mip dimensions are high enough, the multiplications can exceed int.MaxValue)
                    mipWidth /= 2;
                    mipHeight /= 2;
                }
            }
            else
            {
                int startMip = orig_estimatedMips - estimatedMips;

                // UNCOMPRESSED - Can't really do threading in "decompression" so do it for the mipmaps.
                var action = new Action<int>(mipIndex =>
                {
                    // Calculate mipOffset and dimensions
                    int offset, width, height;
                    offset = GetMipOffset(mipIndex, format, header.Width, header.Height);

                    double divisor = mipIndex == 0 ? 1d : 2 << (mipIndex - 1);   // Divisor represents 2^mipIndex - Math.Pow seems very slow.
                    width = (int)(header.Width / divisor);
                    height = (int)(header.Height / divisor);

                    MipMap mipmap = null;
                    try
                    {
                        mipmap = ReadUncompressedMipMap(compressed, offset, width, height, header.ddspf);
                    }
                    catch (Exception e)
                    {
                        Debug.WriteLine(e.ToString());
                    }

                    MipMaps[mipIndex] = mipmap;
                });

                if (ImageEngine.EnableThreading)
                    Parallel.For(startMip, orig_estimatedMips, new ParallelOptions { MaxDegreeOfParallelism = ImageEngine.NumThreads }, action);
                else
                    for (int i = startMip; i < orig_estimatedMips; i++)
                        action(i);
            }

            List<MipMap> mips = new List<MipMap>(MipMaps.Where(t => t != null));
            if (mips.Count == 0)
                throw new InvalidOperationException($"No mipmaps loaded. Estimated mips: {estimatedMips}, mip dimensions: {mipWidth}x{mipHeight}");
            return mips;
        }
Ejemplo n.º 37
0
        private void LoadRawPixels(byte[] rawPixelData, int width, int height, int numSourceChannels)
        {
            if (numSourceChannels < 2)
                throw new ArgumentException("Source rawPixelData must have at least 2 channels.");

            Width = width;
            Height = height;
            MipMaps = new MipMap[1];
            MipMap mip = null;

            if (numSourceChannels == 2)
                mip = new MipMap(rawPixelData, width, height);
            else
            {
                List<byte> formattedPixelData = new List<byte>();
                int ptr = 0;

                while (ptr < rawPixelData.Length)
                {
                    // KFreon: Read single pixel
                    formattedPixelData.Add(rawPixelData[ptr++]);
                    formattedPixelData.Add(rawPixelData[ptr++]);

                    // KFreon: Skip unneeded channels
                    ptr += numSourceChannels - 2;
                }
                mip = new MipMap(formattedPixelData.ToArray(), width, height);
            }

            MipMaps[0] = mip;
        }
Ejemplo n.º 38
0
        public static TDX LoadFromBitmap(Bitmap asset, string name, D3DFormat format)
        {
            TDX tdx = null;

            if (tdx == null)
            {
                tdx = new TDX();

                Bitmap      b     = asset;
                SquishFlags flags = SquishFlags.kDxt1;

                tdx.Name   = name;
                tdx.Format = format;

                switch (tdx.Format)
                {
                case D3DFormat.DXT1:
                    flags = SquishFlags.kDxt1;
                    break;

                case D3DFormat.DXT5:
                    flags = SquishFlags.kDxt5;
                    break;
                }

                List <Bitmap> mipBitmaps = GenerateMips(b, b.Width, b.Height);

                foreach (Bitmap mb in mipBitmaps)
                {
                    MipMap mip = new MipMap()
                    {
                        Width  = mb.Width,
                        Height = mb.Height
                    };

                    byte[] data = new byte[mb.Width * mb.Height * 4];
                    byte[] dest = new byte[Squish.Squish.GetStorageRequirements(mb.Width, mb.Height, flags | SquishFlags.kColourIterativeClusterFit | SquishFlags.kWeightColourByAlpha)];

                    int ii = 0;
                    for (int y = 0; y < mb.Height; y++)
                    {
                        for (int x = 0; x < mb.Width; x++)
                        {
                            Color p = mb.GetPixel(x, y);
                            data[ii + 0] = p.R;
                            data[ii + 1] = p.G;
                            data[ii + 2] = p.B;
                            data[ii + 3] = p.A;

                            ii += 4;
                        }
                    }

                    if (format == D3DFormat.ATI2)
                    {
                        dest = BC5Unorm.Compress(data, (ushort)mb.Width, (ushort)mb.Height, GetMipSize(format, (ushort)mb.Width, (ushort)mb.Height));
                    }
                    else
                    {
                        Squish.Squish.CompressImage(data, mb.Width, mb.Height, ref dest, flags | SquishFlags.kColourClusterFit);
                    }

                    mip.Data = dest;

                    tdx.MipMaps.Add(mip);
                }
            }

            return(tdx);
        }
Ejemplo n.º 39
0
        public static string Replace(this Texture2D t2d, Image image, PropertyCollection props, string fileSourcePath = null, string forcedTFCName = null)
        {
            string      errors       = "";
            var         textureCache = forcedTFCName ?? t2d.GetTopMip().TextureCacheName;
            string      fmt          = t2d.TextureFormat;
            PixelFormat pixelFormat  = Image.getPixelFormatType(fmt);

            t2d.RemoveEmptyMipsFromMipList();

            // Not sure what this does?
            // Remove all but one mip?
            //if (Export.Game == MEGame.ME1 && texture.mipMapsList.Count < 6)
            //{
            //    for (int i = texture.mipMapsList.Count - 1; i != 0; i--)
            //        texture.mipMapsList.RemoveAt(i);
            //}
            PixelFormat newPixelFormat = pixelFormat;

            //Changing Texture Type. Not sure what this is, exactly.
            //if (mod.markConvert)
            //    newPixelFormat = changeTextureType(pixelFormat, image.pixelFormat, ref package, ref texture);


            if (!image.checkDDSHaveAllMipmaps() || t2d.Mips.Count > 1 && image.mipMaps.Count() <= 1 || image.pixelFormat != newPixelFormat)
            //(!mod.markConvert && image.pixelFormat != pixelFormat))
            {
                bool dxt1HasAlpha  = false;
                byte dxt1Threshold = 128;
                if (pixelFormat == PixelFormat.DXT1 && props.GetProp <EnumProperty>("CompressionSettings") is EnumProperty compressionSettings && compressionSettings.Value.Name == "TC_OneBitAlpha")
                {
                    dxt1HasAlpha = true;
                    if (image.pixelFormat == PixelFormat.ARGB ||
                        image.pixelFormat == PixelFormat.DXT3 ||
                        image.pixelFormat == PixelFormat.DXT5)
                    {
                        errors += "Warning: Texture was converted from full alpha to binary alpha." + Environment.NewLine;
                    }
                }

                //Generate lower mips
                image.correctMips(newPixelFormat, dxt1HasAlpha, dxt1Threshold);
            }

            if (t2d.Mips.Count == 1)
            {
                var topMip = image.mipMaps[0];
                image.mipMaps.Clear();
                image.mipMaps.Add(topMip);
            }
            else
            {
                // remove lower mipmaps from source image which not exist in game data
                //Not sure what this does since we just generated most of these mips
                for (int t = 0; t < image.mipMaps.Count(); t++)
                {
                    if (image.mipMaps[t].origWidth <= t2d.Mips[0].width &&
                        image.mipMaps[t].origHeight <= t2d.Mips[0].height &&
                        t2d.Mips.Count > 1)
                    {
                        if (!t2d.Mips.Exists(m => m.width == image.mipMaps[t].origWidth && m.height == image.mipMaps[t].origHeight))
                        {
                            image.mipMaps.RemoveAt(t--);
                        }
                    }
                }

                // put empty mips if missing
                for (int t = 0; t < t2d.Mips.Count; t++)
                {
                    if (t2d.Mips[t].width <= image.mipMaps[0].origWidth &&
                        t2d.Mips[t].height <= image.mipMaps[0].origHeight)
                    {
                        if (!image.mipMaps.Exists(m => m.origWidth == t2d.Mips[t].width && m.origHeight == t2d.Mips[t].height))
                        {
                            MipMap mipmap = new MipMap(t2d.Mips[t].width, t2d.Mips[t].height, pixelFormat);
                            image.mipMaps.Add(mipmap);
                        }
                    }
                }
            }

            //if (!texture.properties.exists("LODGroup"))
            //    texture.properties.setByteValue("LODGroup", "TEXTUREGROUP_Character", "TextureGroup", 1025);
            List <byte[]> compressedMips = new List <byte[]>();

            for (int m = 0; m < image.mipMaps.Count(); m++)
            {
                if (t2d.Export.Game == MEGame.ME2)
                {
                    compressedMips.Add(TextureCompression.CompressTexture(image.mipMaps[m].data, StorageTypes.extLZO)); //LZO
                }
                else
                {
                    compressedMips.Add(TextureCompression.CompressTexture(image.mipMaps[m].data, StorageTypes.extZlib)); //ZLib
                }
            }

            List <Texture2DMipInfo> mipmaps = new List <Texture2DMipInfo>();

            for (int m = 0; m < image.mipMaps.Count(); m++)
            {
                Texture2DMipInfo mipmap = new Texture2DMipInfo();
                mipmap.Export           = t2d.Export;
                mipmap.width            = image.mipMaps[m].origWidth;
                mipmap.height           = image.mipMaps[m].origHeight;
                mipmap.TextureCacheName = textureCache;
                if (t2d.Mips.Exists(x => x.width == mipmap.width && x.height == mipmap.height))
                {
                    var oldMip = t2d.Mips.First(x => x.width == mipmap.width && x.height == mipmap.height);
                    mipmap.storageType = oldMip.storageType;
                }
                else
                {
                    mipmap.storageType = t2d.Mips[0].storageType;
                    if (t2d.Mips.Count() > 1)
                    {
                        //Will implement later. ME3Explorer won't support global relinking, that's MEM's job.
                        //if (Export.Game == MEGame.ME1 && matched.linkToMaster == -1)
                        //{
                        //    if (mipmap.storageType == StorageTypes.pccUnc)
                        //    {
                        //        mipmap.storageType = StorageTypes.pccLZO;
                        //    }
                        //}
                        //else if (Export.Game == MEGame.ME1 && matched.linkToMaster != -1)
                        //{
                        //    if (mipmap.storageType == StorageTypes.pccUnc ||
                        //        mipmap.storageType == StorageTypes.pccLZO ||
                        //        mipmap.storageType == StorageTypes.pccZlib)
                        //    {
                        //        mipmap.storageType = StorageTypes.extLZO;
                        //    }
                        //}
                        //else
                    }
                }

                //ME2,ME3: Force compression type (not implemented yet)
                if (t2d.Export.Game == MEGame.ME3)
                {
                    if (mipmap.storageType == StorageTypes.extLZO) //ME3 LZO -> ZLIB
                    {
                        mipmap.storageType = StorageTypes.extZlib;
                    }
                    if (mipmap.storageType == StorageTypes.pccLZO) //ME3 PCC LZO -> PCCZLIB
                    {
                        mipmap.storageType = StorageTypes.pccZlib;
                    }
                    if (mipmap.storageType == StorageTypes.extUnc) //ME3 Uncomp -> ZLib
                    {
                        mipmap.storageType = StorageTypes.extZlib;
                    }
                    //Leave here for future. WE might need this after dealing with double compression
                    //if (mipmap.storageType == StorageTypes.pccUnc && mipmap.width > 32) //ME3 Uncomp -> ZLib
                    //    mipmap.storageType = StorageTypes.pccZlib;
                    if (mipmap.storageType == StorageTypes.pccUnc && m < image.mipMaps.Count() - 6 && textureCache != null) //Moving texture to store externally.
                    {
                        mipmap.storageType = StorageTypes.extZlib;
                    }
                }
                else if (t2d.Export.Game == MEGame.ME2)
                {
                    if (mipmap.storageType == StorageTypes.extZlib) //ME2 ZLib -> LZO
                    {
                        mipmap.storageType = StorageTypes.extLZO;
                    }
                    if (mipmap.storageType == StorageTypes.pccZlib) //M2 ZLib -> LZO
                    {
                        mipmap.storageType = StorageTypes.pccLZO;
                    }
                    if (mipmap.storageType == StorageTypes.extUnc) //ME2 Uncomp -> LZO
                    {
                        mipmap.storageType = StorageTypes.extLZO;
                    }
                    //Leave here for future. We might neable this after dealing with double compression
                    //if (mipmap.storageType == StorageTypes.pccUnc && mipmap.width > 32) //ME2 Uncomp -> LZO
                    //    mipmap.storageType = StorageTypes.pccLZO;
                    if (mipmap.storageType == StorageTypes.pccUnc && m < image.mipMaps.Count() - 6 && textureCache != null) //Moving texture to store externally. make sure bottom 6 are pcc stored
                    {
                        mipmap.storageType = StorageTypes.extLZO;
                    }
                }


                //Investigate. this has something to do with archive storage types
                //if (mod.arcTexture != null)
                //{
                //    if (mod.arcTexture[m].storageType != mipmap.storageType)
                //    {
                //        mod.arcTexture = null;
                //    }
                //}

                mipmap.width  = image.mipMaps[m].width;
                mipmap.height = image.mipMaps[m].height;
                mipmaps.Add(mipmap);
                if (t2d.Mips.Count() == 1)
                {
                    break;
                }
            }

            #region MEM code comments. Should probably leave for reference

            //if (texture.properties.exists("TextureFileCacheName"))
            //{
            //    string archive = texture.properties.getProperty("TextureFileCacheName").valueName;
            //    if (mod.arcTfcDLC && mod.arcTfcName != archive)
            //        mod.arcTexture = null;

            //    if (mod.arcTexture == null)
            //    {
            //        archiveFile = Path.Combine(GameData.MainData, archive + ".tfc");
            //        if (matched.path.ToLowerInvariant().Contains("\\dlc"))
            //        {
            //            mod.arcTfcDLC = true;
            //            string DLCArchiveFile = Path.Combine(Path.GetDirectoryName(GameData.GamePath + matched.path), archive + ".tfc");
            //            if (File.Exists(DLCArchiveFile))
            //                archiveFile = DLCArchiveFile;
            //            else if (!File.Exists(archiveFile))
            //            {
            //                List<string> files = Directory.GetFiles(GameData.bioGamePath, archive + ".tfc",
            //                    SearchOption.AllDirectories).Where(item => item.EndsWith(".tfc", StringComparison.OrdinalIgnoreCase)).ToList();
            //                if (files.Count == 1)
            //                    archiveFile = files[0];
            //                else if (files.Count == 0)
            //                {
            //                    using (FileStream fs = new FileStream(DLCArchiveFile, FileMode.CreateNew, FileAccess.Write))
            //                    {
            //                        fs.WriteFromBuffer(texture.properties.getProperty("TFCFileGuid").valueStruct);
            //                    }
            //                    archiveFile = DLCArchiveFile;
            //                    newTfcFile = true;
            //                }
            //                else
            //                    throw new Exception("More instnces of TFC file: " + archive + ".tfc");
            //            }
            //        }
            //        else
            //        {
            //            mod.arcTfcDLC = false;
            //        }

            //        // check if texture fit in old space
            //        for (int mip = 0; mip < image.mipMaps.Count(); mip++)
            //        {
            //            Texture.MipMap testMipmap = new Texture.MipMap();
            //            testMipmap.width = image.mipMaps[mip].origWidth;
            //            testMipmap.height = image.mipMaps[mip].origHeight;
            //            if (ExistMipmap(testMipmap.width, testMipmap.height))
            //                testMipmap.storageType = texture.getMipmap(testMipmap.width, testMipmap.height).storageType;
            //            else
            //            {
            //                oldSpace = false;
            //                break;
            //            }

            //            if (testMipmap.storageType == StorageTypes.extZlib ||
            //                testMipmap.storageType == StorageTypes.extLZO)
            //            {
            //                Texture.MipMap oldTestMipmap = texture.getMipmap(testMipmap.width, testMipmap.height);
            //                if (mod.cacheCprMipmaps[mip].Length > oldTestMipmap.compressedSize)
            //                {
            //                    oldSpace = false;
            //                    break;
            //                }
            //            }
            //            if (texture.mipMapsList.Count() == 1)
            //                break;
            //        }

            //        long fileLength = new FileInfo(archiveFile).Length;
            //        if (!oldSpace && fileLength + 0x5000000 > 0x80000000)
            //        {
            //            archiveFile = "";
            //            foreach (TFCTexture newGuid in guids)
            //            {
            //                archiveFile = Path.Combine(GameData.MainData, newGuid.name + ".tfc");
            //                if (!File.Exists(archiveFile))
            //                {
            //                    texture.properties.setNameValue("TextureFileCacheName", newGuid.name);
            //                    texture.properties.setStructValue("TFCFileGuid", "Guid", newGuid.guid);
            //                    using (FileStream fs = new FileStream(archiveFile, FileMode.CreateNew, FileAccess.Write))
            //                    {
            //                        fs.WriteFromBuffer(newGuid.guid);
            //                    }
            //                    newTfcFile = true;
            //                    break;
            //                }
            //                else
            //                {
            //                    fileLength = new FileInfo(archiveFile).Length;
            //                    if (fileLength + 0x5000000 < 0x80000000)
            //                    {
            //                        texture.properties.setNameValue("TextureFileCacheName", newGuid.name);
            //                        texture.properties.setStructValue("TFCFileGuid", "Guid", newGuid.guid);
            //                        break;
            //                    }
            //                }
            //                archiveFile = "";
            //            }
            //            if (archiveFile == "")
            //                throw new Exception("No free TFC texture file!");
            //        }
            //    }
            //    else
            //    {
            //        texture.properties.setNameValue("TextureFileCacheName", mod.arcTfcName);
            //        texture.properties.setStructValue("TFCFileGuid", "Guid", mod.arcTfcGuid);
            //    }
            //}

            #endregion

            int allextmipssize = 0;

            for (int m = 0; m < image.mipMaps.Count(); m++)
            {
                Texture2DMipInfo x = mipmaps[m];
                var compsize       = image.mipMaps[m].data.Length;

                if (x.storageType == StorageTypes.extZlib ||
                    x.storageType == StorageTypes.extLZO ||
                    x.storageType == StorageTypes.extUnc)
                {
                    allextmipssize += compsize; //compsize on Unc textures is same as LZO/ZLib
                }
            }
            //todo: check to make sure TFC will not be larger than 2GiB
            Guid tfcGuid       = Guid.NewGuid(); //make new guid as storage
            bool locallyStored = mipmaps[0].storageType == StorageTypes.pccUnc || mipmaps[0].storageType == StorageTypes.pccZlib || mipmaps[0].storageType == StorageTypes.pccLZO;
            for (int m = 0; m < image.mipMaps.Count(); m++)
            {
                Texture2DMipInfo mipmap = mipmaps[m];
                //if (mipmap.width > 32)
                //{
                //    if (mipmap.storageType == StorageTypes.pccUnc)
                //    {
                //        mipmap.storageType = Export.Game == MEGame.ME2 ? StorageTypes.pccLZO : StorageTypes.pccZlib;
                //    }
                //    if (mipmap.storageType == StorageTypes.extUnc)
                //    {
                //        mipmap.storageType = Export.Game == MEGame.ME2 ? StorageTypes.extLZO : StorageTypes.extZlib;
                //    }
                //}

                mipmap.uncompressedSize = image.mipMaps[m].data.Length;
                if (t2d.Export.Game == MEGame.ME1)
                {
                    if (mipmap.storageType == StorageTypes.pccLZO ||
                        mipmap.storageType == StorageTypes.pccZlib)
                    {
                        mipmap.Mip            = compressedMips[m];
                        mipmap.compressedSize = mipmap.Mip.Length;
                    }
                    else if (mipmap.storageType == StorageTypes.pccUnc)
                    {
                        mipmap.compressedSize = mipmap.uncompressedSize;
                        mipmap.Mip            = image.mipMaps[m].data;
                    }
                    else
                    {
                        throw new Exception("Unknown mip storage type!");
                    }
                }
                else
                {
                    if (mipmap.storageType == StorageTypes.extZlib ||
                        mipmap.storageType == StorageTypes.extLZO)
                    {
                        if (compressedMips.Count != image.mipMaps.Count())
                        {
                            throw new Exception("Amount of compressed mips does not match number of mips of incoming image!");
                        }
                        mipmap.Mip            = compressedMips[m];
                        mipmap.compressedSize = mipmap.Mip.Length;
                    }


                    if (mipmap.storageType == StorageTypes.pccUnc ||
                        mipmap.storageType == StorageTypes.extUnc)
                    {
                        mipmap.compressedSize = mipmap.uncompressedSize;
                        mipmap.Mip            = image.mipMaps[m].data;
                    }

                    if (mipmap.storageType == StorageTypes.pccLZO || mipmap.storageType == StorageTypes.pccZlib)
                    {
                        mipmap.Mip            = compressedMips[m];
                        mipmap.compressedSize = mipmap.Mip.Length;
                    }

                    if (mipmap.storageType == StorageTypes.extZlib ||
                        mipmap.storageType == StorageTypes.extLZO ||
                        mipmap.storageType == StorageTypes.extUnc)
                    {
                        if (!string.IsNullOrEmpty(mipmap.TextureCacheName) && mipmap.Export.Game != MEGame.ME1)
                        {
                            //Check local dir
                            string tfcarchive            = mipmap.TextureCacheName + ".tfc";
                            var    localDirectoryTFCPath = Path.Combine(Path.GetDirectoryName(mipmap.Export.FileRef.FilePath), tfcarchive);
                            if (File.Exists(localDirectoryTFCPath))
                            {
                                try
                                {
                                    using (FileStream fs = new FileStream(localDirectoryTFCPath, FileMode.Open, FileAccess.ReadWrite))
                                    {
                                        tfcGuid = fs.ReadGuid();
                                        fs.Seek(0, SeekOrigin.End);
                                        mipmap.externalOffset = (int)fs.Position;
                                        fs.Write(mipmap.Mip, 0, mipmap.compressedSize);
                                    }
                                }
                                catch (Exception e)
                                {
                                    throw new Exception("Problem appending to TFC file " + tfcarchive + ": " + e.Message);
                                }
                                continue;
                            }

                            //Check game
                            var gameFiles = MELoadedFiles.GetFilesLoadedInGame(mipmap.Export.Game, includeTFCs: true);
                            if (gameFiles.TryGetValue(tfcarchive, out string archiveFile))
                            {
                                try
                                {
                                    using (FileStream fs = new FileStream(archiveFile, FileMode.Open, FileAccess.ReadWrite))
                                    {
                                        tfcGuid = fs.ReadGuid();
                                        fs.Seek(0, SeekOrigin.End);
                                        mipmap.externalOffset = (int)fs.Position;
                                        fs.Write(mipmap.Mip, 0, mipmap.compressedSize);
                                    }
                                }
                                catch (Exception e)
                                {
                                    throw new Exception("Problem appending to TFC file " + archiveFile + ": " + e.Message);
                                }
                                continue;
                            }


                            //Cache not found. Make new TFC
                            try
                            {
                                using (FileStream fs = new FileStream(localDirectoryTFCPath, FileMode.OpenOrCreate, FileAccess.Write))
                                {
                                    fs.WriteGuid(tfcGuid);
                                    mipmap.externalOffset = (int)fs.Position;
                                    fs.Write(mipmap.Mip, 0, mipmap.compressedSize);
                                }
                            }
                            catch (Exception e)
                            {
                                throw new Exception("Problem creating new TFC file " + tfcarchive + ": " + e.Message);
                            }
                            continue;
                        }
                    }
                }
                mipmaps[m] = mipmap;
                if (t2d.Mips.Count() == 1)
                {
                    break;
                }
            }

            t2d.ReplaceMips(mipmaps);

            //Set properties


            // The bottom 6 mips are apparently always pcc stored. If there is less than 6 mips, set neverstream to true, which tells game
            // and toolset to never look into archives for mips.
            //if (Export.Game == MEGame.ME2 || Export.Game == MEGame.ME3)
            //{
            //    if (texture.properties.exists("TextureFileCacheName"))
            //    {
            //        if (texture.mipMapsList.Count < 6)
            //        {
            //            mipmap.storageType = StorageTypes.pccUnc;
            //            texture.properties.setBoolValue("NeverStream", true);
            //        }
            //        else
            //        {
            //            if (Export.Game == MEGame.ME2)
            //                mipmap.storageType = StorageTypes.extLZO;
            //            else
            //                mipmap.storageType = StorageTypes.extZlib;
            //        }
            //    }
            //}

            var hasNeverStream = props.GetProp <BoolProperty>("NeverStream") != null;
            if (locallyStored)
            {
                // Rules for default neverstream
                // 1. Must be Package Stored
                // 2. Must have at least 6 not empty mips
                if (mipmaps.Count >= 6)
                {
                    props.AddOrReplaceProp(new BoolProperty(true, "NeverStream"));
                }
                // Side case: NeverStream property was already set, we should respect the value
                // But won't that always be set here?
                // Is there a time where we should remove NeverStream? I can't see any logical way
                // neverstream would be here
            }

            if (mipmaps.Count < 6)
            {
                props.RemoveNamedProperty("NeverStream");
            }

            if (!locallyStored)
            {
                props.AddOrReplaceProp(tfcGuid.ToGuidStructProp("TFCFileGuid"));
                if (mipmaps[0].storageType == StorageTypes.extLZO || mipmaps[0].storageType == StorageTypes.extUnc || mipmaps[0].storageType == StorageTypes.extZlib)
                {
                    //Requires texture cache name
                    props.AddOrReplaceProp(new NameProperty(textureCache, "TextureFileCacheName"));
                }
                else
                {
                    //Should not have texture cache name
                    var cacheProp = props.GetProp <NameProperty>("TextureFileCacheName");
                    if (cacheProp != null)
                    {
                        props.Remove(cacheProp);
                    }
                }
            }
            else
            {
                props.RemoveNamedProperty("TFCFileGuid");
            }

            props.AddOrReplaceProp(new IntProperty(t2d.Mips.First().width, "SizeX"));
            props.AddOrReplaceProp(new IntProperty(t2d.Mips.First().height, "SizeY"));
            if (t2d.Export.Game < MEGame.ME3 && fileSourcePath != null)
            {
                props.AddOrReplaceProp(new StrProperty(fileSourcePath, "SourceFilePath"));
                props.AddOrReplaceProp(new StrProperty(File.GetLastWriteTimeUtc(fileSourcePath).ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture), "SourceFileTimestamp"));
            }

            var mipTailIdx = props.GetProp <IntProperty>("MipTailBaseIdx");
            if (mipTailIdx != null)
            {
                mipTailIdx.Value = t2d.Mips.Count - 1;
            }

            EndianReader mem = new EndianReader(new MemoryStream())
            {
                Endian = t2d.Export.FileRef.Endian
            };
            props.WriteTo(mem.Writer, t2d.Export.FileRef);
            mem.Position = 0;
            var test      = PropertyCollection.ReadProps(t2d.Export, mem.BaseStream, "Texture2D", true, true); //do not set properties as this may interfere with some other code. may change later.
            int propStart = t2d.Export.GetPropertyStart();
            var pos       = mem.Position;
            mem.Position = 0;
            byte[] propData = mem.ToArray();
            if (t2d.Export.Game == MEGame.ME3)
            {
                t2d.Export.Data = t2d.Export.Data.Take(propStart).Concat(propData).Concat(t2d.SerializeNewData()).ToArray();
            }
            else
            {
                var array    = t2d.Export.Data.Take(propStart).Concat(propData).ToArray();
                var testdata = new MemoryStream(array);
                var test2    = PropertyCollection.ReadProps(t2d.Export, testdata, "Texture2D", true, true, t2d.Export); //do not set properties as this may interfere with some other code. may change later.
                                                                                                                        //ME2 post-data is this right?
                t2d.Export.Data = t2d.Export.Data.Take(propStart).Concat(propData).Concat(t2d.SerializeNewData()).ToArray();
            }

            //using (MemoryStream newData = new MemoryStream())
            //{
            //    newData.WriteFromBuffer(texture.properties.toArray());
            //    newData.WriteFromBuffer(texture.toArray(0, false)); // filled later
            //    package.setExportData(matched.exportID, newData.ToArray());
            //}

            //using (MemoryStream newData = new MemoryStream())
            //{
            //    newData.WriteFromBuffer(texture.properties.toArray());
            //    newData.WriteFromBuffer(texture.toArray(package.exportsTable[matched.exportID].dataOffset + (uint)newData.Position));
            //    package.setExportData(matched.exportID, newData.ToArray());
            //}

            //Since this is single replacement, we don't want to relink to master
            //We want to ensure names are different though, will have to implement into UI
            //if (Export.Game == MEGame.ME1)
            //{
            //    if (matched.linkToMaster == -1)
            //        mod.masterTextures.Add(texture.mipMapsList, entryMap.listIndex);
            //}
            //else
            //{
            //    if (triggerCacheArc)
            //    {
            //        mod.arcTexture = texture.mipMapsList;
            //        mod.arcTfcGuid = texture.properties.getProperty("TFCFileGuid").valueStruct;
            //        mod.arcTfcName = texture.properties.getProperty("TextureFileCacheName").valueName;
            //    }
            //}


            return(errors);
        }
Ejemplo n.º 40
0
        /// <summary>
        /// Loads useful information from image stream using Windows 8.1+ codecs.
        /// </summary>
        /// <param name="stream">Stream containing entire file. NOT just pixels.</param>
        /// <param name="decodeWidth">Width to decode as. Aspect ratio unchanged if decodeHeight = 0.</param>
        /// <param name="decodeHeight">Height to decode as. Aspect ratio unchanged if decodeWidth = 0.</param>
        /// <param name="isDDS">True = image is a DDS.</param>
        /// <param name="scale">DOMINANT. DecodeWidth and DecodeHeight ignored if this is > 0. Amount to scale by. Range 0-1.</param>
        /// <returns>BGRA Pixel Data as stream.</returns>
        internal static List<MipMap> LoadWithCodecs(Stream stream, int decodeWidth, int decodeHeight, double scale, bool isDDS)
        {
            if (isDDS && !ImageEngine.WindowsWICCodecsAvailable)
                return null;

            bool alternateDecodeDimensions = decodeHeight != 0 || decodeWidth != 0 || scale != 0;
            int alternateWidth = decodeWidth;
            int alternateHeight = decodeHeight;

            List<MipMap> mipmaps = new List<MipMap>();

            if (isDDS)
            {
                // KFreon: Attempt to load any mipmaps
                stream.Seek(0, SeekOrigin.Begin);
                var decoder = BitmapDecoder.Create(stream, BitmapCreateOptions.IgnoreColorProfile, BitmapCacheOption.OnDemand);

                // Setup alternateDimensions if required
                if (scale != 0)
                {
                    alternateHeight = (int)(decoder.Frames[0].Height * scale);
                    alternateWidth = (int)(decoder.Frames[0].Width * scale);
                }

                foreach (var mipmap in decoder.Frames)
                {
                    // KFreon: Skip mipmaps that are too big if asked to load a smaller image
                    if (alternateDecodeDimensions)
                    {
                        if (mipmap.Width > alternateWidth || mipmap.Height > alternateHeight)
                            continue;
                    }

                    mipmaps.Add(new MipMap(mipmap.GetPixelsAsBGRA32(), mipmap.PixelWidth, mipmap.PixelHeight));
                }

                if (mipmaps.Count == 0)
                {
                    // KFreon: Image has no mips, so resize largest
                    var frame = decoder.Frames[0];
                    var mip = new MipMap(frame.GetPixelsAsBGRA32(), frame.PixelWidth, frame.PixelHeight);
                    mip = ImageEngine.Resize(mip, scale);
                    mipmaps.Add(mip);
                }
            }
            else
            {
                // KFreon: No Mipmaps
                BitmapImage bmp = AttemptUsingWindowsCodecs(stream, alternateWidth, alternateHeight);
                if (bmp == null)
                    return null;
                bmp.Freeze();

                mipmaps.Add(new MipMap(bmp.GetPixelsAsBGRA32(), bmp.PixelWidth, bmp.PixelHeight));
            }

            return mipmaps;
        }
Ejemplo n.º 41
0
 byte[] GetPixels(MipMap mip)
 {
     var pixels = mip.Pixels;
     if (AlphaDisplaySetting == AlphaDisplaySettings.AlphaOnly)  // Get a different set of pixels
         pixels = mip.AlphaOnlyPixels;
     else if (AlphaDisplaySetting == AlphaDisplaySettings.NoAlpha)  // Other two are just an alpha channel different - Bitmap objects are BGRA32, so need to set the alpha to opaque when "don't want it".
         pixels = mip.RGBAOpaque;
     return pixels;
 }
Ejemplo n.º 42
0
        public DDS(D3DFormat format, Bitmap bitmap)
        {
            SquishFlags flags      = SquishFlags.kDxt1;
            bool        compressed = true;

            switch (format)
            {
            case D3DFormat.DXT1:
                flags = SquishFlags.kDxt1;
                break;

            case D3DFormat.DXT3:
                flags = SquishFlags.kDxt3;
                break;

            case D3DFormat.DXT5:
                flags = SquishFlags.kDxt5;
                break;

            default:
                compressed = false;
                break;
            }

            Format = format;
            Width  = bitmap.Width;
            Height = bitmap.Height;

            MipMap mip = new MipMap
            {
                Width  = Width,
                Height = Height
            };

            byte[] data = new byte[mip.Width * mip.Height * 4];

            BitmapData bmpdata = bitmap.LockBits(new Rectangle(0, 0, mip.Width, mip.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

            Marshal.Copy(bmpdata.Scan0, data, 0, bmpdata.Stride * bmpdata.Height);
            bitmap.UnlockBits(bmpdata);

            if (compressed)
            {
                for (uint i = 0; i < data.Length - 4; i += 4)
                {
                    byte r = data[i + 0];
                    data[i + 0] = data[i + 2];
                    data[i + 2] = r;
                }

                byte[] dest = new byte[Squish.Squish.GetStorageRequirements(mip.Width, mip.Height, flags | SquishFlags.kColourIterativeClusterFit)];
                Squish.Squish.CompressImage(data, mip.Width, mip.Height, ref dest, flags | SquishFlags.kColourIterativeClusterFit);
                mip.Data = dest;
            }
            else
            {
                mip.Data = data;
            }

            MipMaps.Add(mip);
        }