/// <summary>
        /// Checks is the given format compressed
        /// </summary>
        private static bool IsCompressed(DXGIFormat format)
        {
            switch (format)
            {
            case DXGIFormat.BC1TYPELESS:
            case DXGIFormat.BC1UNORM:
            case DXGIFormat.BC1UNORMSRGB:
            case DXGIFormat.BC2TYPELESS:
            case DXGIFormat.BC2UNORM:
            case DXGIFormat.BC2UNORMSRGB:
            case DXGIFormat.BC3TYPELESS:
            case DXGIFormat.BC3UNORM:
            case DXGIFormat.BC3UNORMSRGB:
            case DXGIFormat.BC4TYPELESS:
            case DXGIFormat.BC4UNORM:
            case DXGIFormat.BC4SNORM:
            case DXGIFormat.BC5TYPELESS:
            case DXGIFormat.BC5UNORM:
            case DXGIFormat.BC5SNORM:
            case DXGIFormat.BC6HTYPELESS:
            case DXGIFormat.BC6HUF16:
            case DXGIFormat.BC6HSF16:
            case DXGIFormat.BC7TYPELESS:
            case DXGIFormat.BC7UNORM:
            case DXGIFormat.BC7UNORMSRGB:
                return(true);

            default:
                return(false);
            }
        }
Exemple #2
0
        public byte[] GentDDSHeader(int size)
        {
            int mipCount = 0;

            if (HasMipmaps)
            {
                int heightMip = TextureHeight;
                int widthMip  = TextureWidth;
                while (heightMip > 1 && widthMip > 1)
                {
                    heightMip /= 2;
                    widthMip  /= 2;
                    mipCount++;
                }
                mipCount--;
            }
            //Map to DXGIFormat based on XVRFormats list, recovered from a PSO1 executable. Redundancies prevent this from being an enum
            DXGIFormat fmt  = GetFormat();
            var        meta = GenerateMataData(TextureWidth, TextureHeight, mipCount, fmt, false);

            if (UseAlpha)
            {
                meta.MiscFlags2 = TexMiscFlags2.TEXMISC2ALPHAMODEMASK;
            }
            GenerateDDSHeader(meta, DDSFlags.NONE, out var ddsHeader, out var dx10Header);

            return(ddsHeader.GetBytes());
        }
Exemple #3
0
 /// <summary>
 /// Opens a texture to encode from a file.
 /// </summary>
 /// <param name="file">Filename of the file that contains the texture data.</param>
 /// <param name="pixelFormat">Pixel format to encode the texture to. If the data format does not require a pixel format, use GvrPixelFormat.Unknown.</param>
 /// <param name="dataFormat">Data format to encode the texture to.</param>
 public XvrTextureEncoder(string file, DXGIFormat pixelFormat, DXGIFormat dataFormat) : base(file)
 {
     if (decodedBitmap != null)
     {
         initalized = Initalize(pixelFormat, dataFormat);
     }
 }
        private bool repackFile(TPF.Texture tpfEntry, string name, string baseDir, string subDir)
        {
            string inputPath = baseDir + "\\" + subDir + "\\" + name + ".dds";

            //DBGTEX_DETAIL crashes this, what in the heck
            if (inputPath != null && File.Exists(inputPath) && name != "DBGTEX_DETAIL")
            {
                byte[] inputBytes = File.ReadAllBytes(inputPath);

                DXGIFormat originalFormat = DDSFile.Read(new MemoryStream(tpfEntry.Bytes)).Format;

                DXGIFormat newFormat = DDSFile.Read(new MemoryStream(inputBytes)).Format;

                if (originalFormat != DXGIFormat.Unknown && newFormat != DXGIFormat.Unknown && originalFormat != newFormat)
                {
                    byte[] newBytes = convertFile(inputPath, originalFormat);
                    if (newBytes != null)
                    {
                        inputBytes = newBytes;
                    }
                }

                tpfEntry.Bytes = inputBytes;

                return(true);
            }
            else
            {
                return(false);
            }
        }
Exemple #5
0
 /// <summary>
 /// Constructs a new instance of the <see cref="DDSContainer"/> class.
 /// </summary>
 /// <param name="mipChains">Collection of mipmap chains.</param>
 /// <param name="format">Format of the image data.</param>
 /// <param name="texDim">Identifies the dimensions of the image data.</param>
 public DDSContainer(List <MipChain> mipChains, DXGIFormat format, TextureDimension texDim)
 {
     m_mipChains  = mipChains;
     m_format     = format;
     m_dimension  = texDim;
     m_isDisposed = false;
 }
Exemple #6
0
        private void btnConvert_Click(object sender, EventArgs e)
        {
            string filepath = txtConvertFile.Text;

            if (File.Exists(filepath))
            {
                if (File.Exists("bin\\texconv.exe"))
                {
                    ConvertFormatItem formatItem = cmbConvertFormat.SelectedItem as ConvertFormatItem;
                    if (formatItem == null)
                    {
                        return;
                    }
                    DXGIFormat format = formatItem.Format;

                    filepath = Path.GetFullPath(filepath);
                    string directory = Path.GetDirectoryName(filepath);

                    bool backedUp = false;
                    if (Path.GetExtension(filepath) == ".dds" && !File.Exists(filepath + ".bak"))
                    {
                        backedUp = true;
                        File.Copy(filepath, filepath + ".bak");
                    }

                    string args = string.Format("-f {0} -o \"{1}\" \"{2}\" -y",
                                                TPUP.PrintDXGIFormat(format), directory, filepath);
                    ProcessStartInfo startInfo = new ProcessStartInfo("bin\\texconv.exe", args)
                    {
                        CreateNoWindow         = true,
                        UseShellExecute        = false,
                        RedirectStandardOutput = true
                    };
                    Process texconv = Process.Start(startInfo);
                    texconv.WaitForExit();

                    if (texconv.ExitCode == 0)
                    {
                        appendLog("Conversion successful!");
                        SystemSounds.Asterisk.Play();
                    }
                    else
                    {
                        MessageBox.Show("Conversion failed.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        if (backedUp)
                        {
                            File.Move(filepath + ".bak", filepath);
                        }
                    }
                }
                else
                {
                    MessageBox.Show("texconv.exe not found.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
            else
            {
                MessageBox.Show("File to be converted does not exist.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
Exemple #7
0
 public Header10(DXGIFormat format, D3D10ResourceDimension resourceDim, Header10Flags miscFlags, uint arraySize, Header10Flags2 miscFlags2)
 {
     Format            = format;
     ResourceDimension = resourceDim;
     MiscFlags         = miscFlags;
     ArraySize         = arraySize;
     MiscFlags2        = miscFlags2;
 }
Exemple #8
0
 /// <summary>
 /// Opens a texture to encode from a stream.
 /// </summary>
 /// <param name="source">Stream that contains the texture data.</param>
 /// <param name="length">Number of bytes to read.</param>
 /// <param name="pixelFormat">Pixel format to encode the texture to. If the data format does not require a pixel format, use GvrPixelFormat.Unknown.</param>
 /// <param name="dataFormat">Data format to encode the texture to.</param>
 public XvrTextureEncoder(Stream source, int length, DXGIFormat pixelFormat, DXGIFormat dataFormat)
     : base(source, length)
 {
     if (decodedBitmap != null)
     {
         initalized = Initalize(pixelFormat, dataFormat);
     }
 }
Exemple #9
0
 /// <summary>
 /// Opens a texture to encode from a bitmap.
 /// </summary>
 /// <param name="source">Bitmap to encode.</param>
 /// <param name="pixelFormat">Pixel format to encode the texture to. If the data format does not require a pixel format, use GvrPixelFormat.Unknown.</param>
 /// <param name="dataFormat">Data format to encode the texture to.</param>
 public XvrTextureEncoder(Bitmap source, DXGIFormat pixelFormat, DXGIFormat dataFormat)
     : base(source)
 {
     if (decodedBitmap != null)
     {
         initalized = Initalize(pixelFormat, dataFormat);
     }
 }
Exemple #10
0
        public uint         miscFlags2; // see DDS_MISC_FLAGS2

        public void Read(GenericReader r)
        {
            dxgiFormat        = (DXGIFormat)r.ReadInt32();
            resourceDimension = (DDSDimension)r.ReadUInt32();
            miscFlag          = r.ReadUInt32();
            arraySize         = r.ReadUInt32();
            miscFlags2        = r.ReadUInt32();
        }
        /// <summary>
        /// Writes a DDS file to disk. Image data is expected to be DXGI-compliant data, but an effort is made to write out D3D9-compatible headers when possible.
        /// </summary>
        /// <param name="fileName">File to write to. If it doesn't exist, it will be created.</param>
        /// <param name="mipChains">Mipmap chains to write. Each mipmap chain represents a single face (so > 1 represents an array texture or a Cubemap). All faces must have
        /// equivalent dimensions and each chain must have the same number of mipmaps.</param>
        /// <param name="format">DXGI format the image data is stored as.</param>
        /// <param name="texDim">Dimension of the texture to write.</param>
        /// <param name="flags">Flags to control how the DDS data is saved.</param>
        /// <returns>True if writing the data was successful, false if otherwise.</returns>
        public static bool Write(String fileName, List <MipChain> mipChains, DXGIFormat format, TextureDimension texDim, DDSFlags flags = DDSFlags.None)
        {
            if (!Directory.Exists(Path.GetDirectoryName(fileName)))
            {
                Directory.CreateDirectory(Path.GetDirectoryName(fileName));
            }

            using (FileStream fs = File.Create(fileName))
                return(Write(fs, mipChains, format, texDim, flags));
        }
Exemple #12
0
 public static string PrintDXGIFormat(DXGIFormat format)
 {
     if (DXGIFormatOverride.ContainsKey(format))
     {
         return(DXGIFormatOverride[format]);
     }
     else
     {
         return(format.ToString().ToUpper());
     }
 }
Exemple #13
0
        public static int GetTpfFormatFromDdsBytes(FBX2FLVERImporter importer, string texName, byte[] ddsBytes)
        {
            using (var ddsStream = new MemoryStream(ddsBytes))
            {
                DXGIFormat format = DDSFile.Read(ddsStream).Format;

                switch (format)
                {
                //DSR:
                case DXGIFormat.BC1_UNorm:
                case DXGIFormat.BC1_UNorm_SRGB:
                    return(0);

                case DXGIFormat.BC2_UNorm:
                case DXGIFormat.BC2_UNorm_SRGB:
                    return(3);

                case DXGIFormat.BC3_UNorm:
                case DXGIFormat.BC3_UNorm_SRGB:
                    return(5);

                case DXGIFormat.R16G16_Float:
                    return(35);

                case DXGIFormat.BC5_UNorm:
                    return(36);

                case DXGIFormat.BC6H_UF16:
                    return(37);

                case DXGIFormat.BC7_UNorm:
                case DXGIFormat.BC7_UNorm_SRGB:
                    return(38);

                //DS3:
                //case DXGIFormat.B5G5R5A1_UNorm:
                //    return 6;
                //case DXGIFormat.B8G8R8A8_UNorm:
                //case DXGIFormat.B8G8R8A8_UNorm_SRGB:
                //    return 9;
                //case DXGIFormat.B8G8R8X8_UNorm:
                //case DXGIFormat.B8G8R8X8_UNorm_SRGB:
                //    return 10;
                //case DXGIFormat.R16G16B16A16_Float:
                //    return 22;
                default:
                    importer.PrintWarning($"Texture \"{texName}\" has an unrecognized" +
                                          $" DDS format type ({format.ToString()}) and will likely appear garbled ingame. " +
                                          $"For greatest compatibility, use DXT1 (aka BC1_UNorm) or DXT5 (aka BC3_UNorm) " +
                                          $"for your textures.");
                    return(0);
                }
            }
        }
Exemple #14
0
 /// <summary>
 ///     Gets the display modes that match the requested format and other input options.
 /// </summary>
 /// <param name="format">The color format (see <seealso cref="DXGIFormat" />).</param>
 /// <param name="flags">
 ///     Options for modes to include (see <seealso cref="DXGIEnumModes" />). <seealso cref="DXGIEnumModes.Scaling" /> needs
 ///     to be specified
 ///     to expose the display modes that require scaling. Centered modes, requiring no scaling and corresponding directly
 ///     to the display output, are enumerated by default.
 /// </param>
 /// <param name="numModes">
 ///     Set <paramref name="modesDesc" /> to <seealso langword="null" /> so that <paramref name="numModes" />
 ///     returns the number of display modes that match the format and the options.
 ///     Otherwise, <paramref name="modesDesc" /> returns the number of display modes returned in
 ///     <paramref name="modesDesc" />.
 /// </param>
 /// <param name="modesDesc">
 ///     A pointer to a list of display modes (see <seealso cref="DXGIModeDescription" />); set to
 ///     <seealso langword="null" /> to get the number of display modes.
 /// </param>
 /// <returns></returns>
 /// <remarks>
 ///     In general, when switching from windowed to full-screen mode, a swap chain automatically chooses a display mode
 ///     that meets (or exceeds) the resolution, color depth and refresh rate of the swap chain. To exercise more control
 ///     over the display mode, use this API to poll the set of display modes that are validated against monitor
 ///     capabilities, or all modes that match the desktop (if the desktop settings are not validated against the monitor).
 ///     As shown, this API is designed to be called twice. First to get the number of modes available, and second to return
 ///     a description of the modes.
 /// </remarks>
 public int GetDisplayModeList
 (
     DXGIFormat format,
     DXGIEnumModes flags,
     ref uint numModes,
     [In, Out] DXGIModeDescription[] modesDesc = null
 )
 {
     return(GetMethodDelegate <GetDisplayModeListDelegate>()
            .Invoke(this, format, flags, ref numModes, modesDesc));
 }
 /// <summary>
 /// Creates a new Texture Metadata Structe
 /// </summary>
 public TexMetadata(long width, long height, long depth, long arraySize, long mipLevels, TexMiscFlags flags, TexMiscFlags2 flags2, DXGIFormat format, TexDimension dimension)
 {
     Width      = width;
     Height     = height;
     Depth      = depth;
     ArraySize  = arraySize;
     MipLevels  = mipLevels;
     MiscFlags  = flags;
     MiscFlags2 = flags2;
     Format     = format;
     Dimension  = dimension;
 }
Exemple #16
0
        public static byte GetTpfFormatFromDdsBytes(byte[] ddsBytes)
        {
            using (var ddsStream = new MemoryStream(ddsBytes))
            {
                DXGIFormat format = DDSFile.Read(ddsStream).Format;

                switch (format)
                {
                //DSR:
                case DXGIFormat.BC1_UNorm:
                case DXGIFormat.BC1_UNorm_SRGB:
                    return(0);

                case DXGIFormat.BC2_UNorm:
                case DXGIFormat.BC2_UNorm_SRGB:
                    return(3);

                case DXGIFormat.BC3_UNorm:
                case DXGIFormat.BC3_UNorm_SRGB:
                    return(5);

                case DXGIFormat.R16G16_Float:
                    return(35);

                case DXGIFormat.BC5_UNorm:
                    return(36);

                case DXGIFormat.BC6H_UF16:
                    return(37);

                case DXGIFormat.BC7_UNorm:
                case DXGIFormat.BC7_UNorm_SRGB:
                    return(38);

                //DS3:
                //case DXGIFormat.B5G5R5A1_UNorm:
                //    return 6;
                //case DXGIFormat.B8G8R8A8_UNorm:
                //case DXGIFormat.B8G8R8A8_UNorm_SRGB:
                //    return 9;
                //case DXGIFormat.B8G8R8X8_UNorm:
                //case DXGIFormat.B8G8R8X8_UNorm_SRGB:
                //    return 10;
                //case DXGIFormat.R16G16B16A16_Float:
                //    return 22;
                default:
                    return(0);
                }
            }
        }
        private bool repackFile(TPF.Texture tpfEntry, string name, string baseDir, string subDir)
        {
            string inputPath = getSwappedPath(name, subDir, out bool dds);

            if (inputPath != null && File.Exists(inputPath))
            {
                byte[] inputBytes = File.ReadAllBytes(inputPath);

                DXGIFormat originalFormat = DDSFile.Read(new MemoryStream(tpfEntry.Bytes)).Format;
                if (originalFormat == DXGIFormat.Unknown)
                {
                    appendError("Error: {0}\r\n\u2514\u2500 Could not determine format of game file.", subDir + "\\" + name + ".dds");
                }

                bool convert = !dds;
                if (dds)
                {
                    DXGIFormat newFormat = DDSFile.Read(new MemoryStream(inputBytes)).Format;

                    if (newFormat == DXGIFormat.Unknown)
                    {
                        appendError("Error: {0}\r\n\u2514\u2500 Could not determine format of override file.", inputPath);
                    }

                    if (originalFormat != DXGIFormat.Unknown && newFormat != DXGIFormat.Unknown && originalFormat != newFormat)
                    {
                        convert = true;
                    }
                }

                if (convert)
                {
                    byte[] newBytes = convertFile(inputPath, originalFormat);
                    if (newBytes != null)
                    {
                        inputBytes = newBytes;
                    }
                }

                tpfEntry.Bytes = inputBytes;
                lock (countLock)
                    textureCount++;

                return(true);
            }
            else
            {
                return(false);
            }
        }
Exemple #18
0
        private bool Initalize(DXGIFormat pixelFormat, DXGIFormat dataFormat)
        {
            // Set the default values
            hasGlobalIndex = true;
            globalIndex    = 0;
            useAlpha       = true;
            useMipmaps     = false;

            // Set the data format and pixel format and load the appropiate codecs
            this.dataFormat  = dataFormat;
            this.pixelFormat = pixelFormat;

            return(true);
        }
        private byte[] convertFile(string filepath, DXGIFormat format)
        {
            if (!File.Exists(TEXCONV_PATH))
            {
                appendError("Error: texconv.exe not found.");
                return(null);
            }

            filepath = Path.GetFullPath(filepath);
            string directory = Path.GetDirectoryName(filepath);
            string filename  = Path.GetFileName(filepath);
            string suffix    = TEXCONV_SUFFIX + (convertInc++).ToString();
            string outPath   = string.Format("{0}\\{1}{2}.dds",
                                             directory, Path.GetFileNameWithoutExtension(filename), suffix);

            string args = string.Format("-sx {0} -f {1} -o \"{2}\" \"{2}\\{3}\" -y -singleproc -pow2",
                                        suffix, PrintDXGIFormat(format), directory, filename);
            ProcessStartInfo startInfo = new ProcessStartInfo(TEXCONV_PATH, args)
            {
                CreateNoWindow         = true,
                UseShellExecute        = false,
                RedirectStandardOutput = true
            };
            Process texconv = Process.Start(startInfo);

            texconv.WaitForExit();

            byte[] result = null;
            if (texconv.ExitCode == 0 && File.Exists(outPath))
            {
                result = File.ReadAllBytes(outPath);

                try
                {
                    File.Delete(outPath);
                }
                catch (Exception ex) when(ex is IOException || ex is UnauthorizedAccessException)
                {
                    appendError("Error: {0}\r\n\u2514\u2500 Could not delete converted file.", outPath);
                }
            }
            else
            {
                appendError("Error: {0}\\{1}\r\n\u2514\u2500 Conversion failed.", directory, filename);
            }
            return(result);
        }
        private byte[] convertFile(string filepath, DXGIFormat format)
        {
            if (!File.Exists(TEXCONV_PATH))
            {
                return(null);
            }

            filepath = Path.GetFullPath(filepath);
            string directory = Path.GetDirectoryName(filepath);
            string filename  = Path.GetFileName(filepath);
            string suffix    = TEXCONV_SUFFIX + (convertInc++).ToString();
            string outPath   = string.Format("{0}\\{1}{2}.dds",
                                             directory, Path.GetFileNameWithoutExtension(filename), suffix);

            string args = string.Format("-sx {0} -f {1} -o \"{2}\" \"{2}\\{3}\" -y -singleproc -pow2",
                                        suffix, PrintDXGIFormat(format), directory, filename);
            ProcessStartInfo startInfo = new ProcessStartInfo(TEXCONV_PATH, args)
            {
                CreateNoWindow         = true,
                UseShellExecute        = false,
                RedirectStandardOutput = true
            };

            Process texconv = Process.Start(startInfo);

            texconv.WaitForExit();

            byte[] result = null;
            if (texconv.ExitCode == 0 && File.Exists(outPath))
            {
                result = File.ReadAllBytes(outPath);

                try
                {
                    File.Delete(outPath);
                }
                catch (Exception ex)
                {
                }
            }

            return(result);
        }
Exemple #21
0
 /// <summary>
 ///     Gets the display modes that match the requested format and other input options.
 /// </summary>
 /// <param name="enumFormat">The color format (see <seealso cref="DXGIFormat" />).</param>
 /// <param name="flags">
 ///     Options for modes to include (see <seealso cref="DXGIEnumModes" />). <seealso cref="DXGIEnumModes.Scaling" /> needs
 ///     to be specified
 ///     to expose the display modes that require scaling. Centered modes, requiring no scaling and corresponding directly
 ///     to the display output, are enumerated by default.
 /// </param>
 /// <param name="numModes">
 ///     Set <paramref name="modesDesc" /> to <seealso langword="null" /> so that <paramref name="numModes" />
 ///     returns the number of display modes that match the format and the options.
 ///     Otherwise, <paramref name="modesDesc" /> returns the number of display modes returned in
 ///     <paramref name="modesDesc" />.
 /// </param>
 /// <param name="modesDesc">
 ///     A pointer to a list of display modes (see <seealso cref="DXGIModeDescription1" />); set to
 ///     <seealso langword="null" /> to get the number of display modes.
 /// </param>
 /// <returns></returns>
 /// <remarks>
 ///     In general, when switching from windowed to full-screen mode, a swap chain automatically chooses a display mode
 ///     that meets (or exceeds) the resolution, color depth and refresh rate of the swap chain. To exercise more control
 ///     over the display mode, use this API to poll the set of display modes that are validated against monitor
 ///     capabilities, or all modes that match the desktop (if the desktop settings are not validated against the monitor).
 ///     As shown, this API is designed to be called twice. First to get the number of modes available, and second to return
 ///     a description of the modes.
 /// </remarks>
 /// <returns></returns>
 public int GetDisplayModeList1(DXGIFormat enumFormat, DXGIEnumModes flags, ref uint numModes,
                                DXGIModeDescription1[] modesDesc = null)
 {
     return(GetMethodDelegate <DXGIGetDisplayModeList1Delegate>()
            .Invoke(this, enumFormat, flags, ref numModes, modesDesc));
 }
Exemple #22
0
        public void Invoke()
        {
            string outPath = string.IsNullOrEmpty(OutputPath) ? $"{Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), Path.GetFileNameWithoutExtension(FilePath))}.dds" : $"{Path.Combine(OutputPath, Path.GetFileNameWithoutExtension(FilePath))}.dds";

            byte[] fileData = File.ReadAllBytes(FilePath);

            // I am not going to write an entire class that verifies that this is an actual uasset file so just get the magic number instead.
            if (BitConverter.ToUInt32(fileData.GetBytes(0x0, 0x4), 0x0) != 0x9E2A83C1)
            {
                Console.WriteLine("ERROR: Not a valid uasset file.");
                return;
            }

            // Check if the licensee version is FFFFFFFD (-3)
            if (BitConverter.ToUInt32(fileData.GetBytes(0x4, 0x4), 0x0) != 0xFFFFFFFD)
            {
                Console.WriteLine("ERROR: The file provided is not a Tekken 7.0 (2015) uasset file.");
                return;
            }

            Console.WriteLine("INFO: Finding PF offset...");
            int[] offsets = ArrayExtensions.Locate(fileData, Encoding.ASCII.GetBytes("PF_"));

            if (offsets.Length < 1 || offsets.Length == 0)
            {
                Console.WriteLine("ERROR: No texture was found.");
                return;
            }

            int dataStartOffset = BitConverter.ToInt32(fileData.GetBytes(0x93, 0x4), 0x0);
            int pfOffset        = offsets[1];

            Console.WriteLine("INFO: PF offset was found, getting texture info...");

            EPixelFormat pixelFormat = EPixelFormat.PF_Unknown;

            if (!Enum.TryParse(fileData.GetNullTerminatedString(pfOffset), out pixelFormat))
            {
                Console.WriteLine("ERROR: Could not retrieve texture's pixel format.");
                return;
            }

            int width  = BitConverter.ToInt32(fileData.GetBytes(pfOffset - 0x10, 0x4), 0x0);
            int height = BitConverter.ToInt32(fileData.GetBytes(pfOffset - 0xC, 0x4), 0x0);

            // NOTE TO SELF: Get rid of this awful pixel format offset calculation mess that is happening here and write something proper
            FTexture2DMipMap mipMapData = new FTexture2DMipMap(fileData.GetBytes(pfOffset + 0x10 +
                                                                                 (pixelFormat == EPixelFormat.PF_B8G8R8A8 ? 0x4 : 0x0) + // pixel format can't be BC5 and BGRA8 at the same time so it's fine
                                                                                 (pixelFormat == EPixelFormat.PF_BC5 ? -0x1 : 0x0)       // it's fine, i promise!
                                                                                 , 20));

            Console.WriteLine($"INFO: Texture resolution is {width}x{height} with the size of 0x{mipMapData.Size:X2} - Pixel Format: {pixelFormat.ToString()}");

            byte[] textureData = fileData.GetBytes(dataStartOffset, mipMapData.Size);

            Console.WriteLine("INFO: Generating a DDS file...");

            DXGIFormat dxgiFormat = FormatMapList.Find(map => map.x == pixelFormat).y;
            DDSFlags   flags      = DDSFlags.NONE;

            TexMetadata x = GenerateMataData(width, height, 0, dxgiFormat, false);
            DDSHeader   ddsHeader;
            DX10Header  dx10Header;

            dx10Header.Format = dxgiFormat;
            GenerateDDSHeader(x, flags, out ddsHeader, out dx10Header);

            List <byte> ddsData = new List <byte>();

            ddsData.AddRange(EncodeDDSHeader(ddsHeader, dx10Header));
            ddsData.AddRange(textureData);

            try
            {
                File.WriteAllBytes(outPath, ddsData.ToArray());
            }
            catch (DirectoryNotFoundException)
            {
                Directory.CreateDirectory(Path.GetDirectoryName(outPath));
                File.WriteAllBytes(outPath, ddsData.ToArray());
            }
            catch (Exception ex)
            {
                Console.WriteLine($"ERROR: {ex.Message}");
            }

            Console.WriteLine($"Extracted {Path.GetFileName(FilePath)} ({pixelFormat.ToString()}) -> {Path.GetFileName(outPath)}");
        }
        internal static bool ValidateInternal(List <MipChain> mipChains, DXGIFormat format, TextureDimension texDim)
        {
            if (format == DXGIFormat.Unknown)
            {
                return(false);
            }

            //Mipchains must exist, must have at least one, and chain must have mipmaps.
            if (mipChains == null || mipChains.Count == 0 || mipChains[0].Count == 0)
            {
                return(false);
            }

            //Validate cubemap...must have multiples of 6 faces (can be an array of cubes).
            if (texDim == TextureDimension.Cube && (mipChains.Count % 6) != 0)
            {
                return(false);
            }

            //Validate 3d texture..can't have arrays
            if (texDim == TextureDimension.Three && mipChains.Count > 1)
            {
                return(false);
            }

            int width, height, depth, rowPitch, slicePitch;

            //Save the first image dimensions
            MipData firstSurface = mipChains[0][0];

            width      = firstSurface.Width;
            height     = firstSurface.Height;
            depth      = firstSurface.Depth;
            rowPitch   = firstSurface.RowPitch;
            slicePitch = firstSurface.SlicePitch;

            //Validate first surface
            if (width < 1 || height < 1 || depth < 1 || rowPitch < 1 || slicePitch < 1)
            {
                return(false);
            }

            //Validate 1D texture...must only have 1 height
            if (texDim == TextureDimension.One && height > 1)
            {
                return(false);
            }

            //Validate cubemap...width/height must be same
            if (texDim == TextureDimension.Cube && (width != height))
            {
                return(false);
            }

            //Only 3d textures have depth
            if (texDim != TextureDimension.Three && depth > 1)
            {
                return(false);
            }

            //Go through each chain and validate against the first texture and ensure mipmaps are progressively smaller
            int mipCount = -1;

            for (int i = 0; i < mipChains.Count; i++)
            {
                MipChain mipmaps = mipChains[i];

                //Mips must exist...
                if (mipmaps == null || mipmaps.Count == 0)
                {
                    return(false);
                }

                //Grab a mip count from first chain
                if (mipCount == -1)
                {
                    mipCount = mipmaps.Count;
                }

                //Each chain must have the same number of mip surfaces
                if (mipmaps.Count != mipCount)
                {
                    return(false);
                }

                //Each mip surface must have data and check sizes
                MipData prevMip = mipmaps[0];

                //Check against the first main image we looked at earlier
                if (prevMip.Width != width || prevMip.Height != height || prevMip.Depth != depth || prevMip.Data == IntPtr.Zero || prevMip.RowPitch != rowPitch || prevMip.SlicePitch != slicePitch)
                {
                    return(false);
                }

                for (int mipLevel = 1; mipLevel < mipmaps.Count; mipLevel++)
                {
                    MipData nextMip = mipmaps[mipLevel];

                    //Ensure each mipmap is progressively smaller or same at the least
                    if (nextMip.Width > prevMip.Width || nextMip.Height > prevMip.Height || nextMip.Depth > prevMip.Depth || nextMip.Data == IntPtr.Zero ||
                        nextMip.RowPitch > prevMip.RowPitch || nextMip.SlicePitch > prevMip.SlicePitch || nextMip.RowPitch == 0 || nextMip.SlicePitch == 0)
                    {
                        return(false);
                    }

                    prevMip = nextMip;
                }
            }

            return(true);
        }
        /// <summary>
        /// Reads DDS formatted data from a stream. Image data is always returned as DXGI-Compliant
        /// format, therefore some old legacy formats will automatically be converted.
        /// </summary>
        /// <param name="input">Input stream.</param>
        /// <param name="flags">Flags to control how the DDS data is loaded.</param>
        /// <returns>Loaded image data, or null if the data failed to load.</returns>
        public static DDSContainer Read(Stream input, DDSFlags flags = DDSFlags.None)
        {
            StreamTransferBuffer buffer = new StreamTransferBuffer();

            Header   header;
            Header10?headerExt;

            //Reads + validates header(s)
            if (!ReadHeader(input, buffer, out header, out headerExt))
            {
                return(null);
            }

            //Gather up metadata
            List <MipChain>  mipChains   = null;
            DXGIFormat       format      = DXGIFormat.Unknown;
            TextureDimension texDim      = TextureDimension.Two;
            ConversionFlags  convFlags   = ConversionFlags.None;
            bool             legacyDword = (flags & DDSFlags.LegacyDword) == DDSFlags.LegacyDword ? true : false;

            int width      = Math.Max((int)header.Width, 1);
            int height     = Math.Max((int)header.Height, 1);
            int depth      = Math.Max((int)header.Depth, 1);
            int mipCount   = (int)header.MipMapCount;
            int arrayCount = 1;

            //Has extended header, a modern DDS
            if (headerExt.HasValue)
            {
                Header10 extendedHeader = headerExt.Value;
                arrayCount = (int)extendedHeader.ArraySize;
                format     = extendedHeader.Format;

                switch (extendedHeader.ResourceDimension)
                {
                case D3D10ResourceDimension.Texture1D:
                {
                    texDim = TextureDimension.One;

                    if (height > 1 || depth > 1)
                    {
                        return(null);
                    }
                }
                break;

                case D3D10ResourceDimension.Texture2D:
                {
                    if ((extendedHeader.MiscFlags & Header10Flags.TextureCube) == Header10Flags.TextureCube)
                    {
                        //Specifies # of cubemaps, so to get total # of faces must multiple by 6
                        arrayCount *= 6;

                        texDim = TextureDimension.Cube;
                    }
                    else
                    {
                        texDim = TextureDimension.Two;
                    }

                    if (depth > 1)
                    {
                        return(null);
                    }
                }
                break;

                case D3D10ResourceDimension.Texture3D:
                {
                    texDim = TextureDimension.Three;

                    if (arrayCount > 1 || (header.Caps2 & HeaderCaps2.Volume) != HeaderCaps2.Volume)
                    {
                        return(null);
                    }
                }
                break;
                }
            }
            else
            {
                //Otherwise, read legacy DDS and possibly convert data

                //Check volume flag
                if ((header.Caps2 & HeaderCaps2.Volume) == HeaderCaps2.Volume)
                {
                    texDim = TextureDimension.Three;
                }
                else
                {
                    //legacy DDS could not express 1D textures, so either a cubemap or a 2D non-array texture

                    if ((header.Caps2 & HeaderCaps2.Cubemap) == HeaderCaps2.Cubemap)
                    {
                        //Must have all six faces. DirectX 8 and above always would write out all 6 faces
                        if ((header.Caps2 & HeaderCaps2.Cubemap_AllFaces) != HeaderCaps2.Cubemap_AllFaces)
                        {
                            return(null);
                        }

                        arrayCount = 6;
                        texDim     = TextureDimension.Cube;
                    }
                    else
                    {
                        texDim = TextureDimension.Two;
                    }
                }

                format = FormatConverter.DetermineDXGIFormat(header.PixelFormat, flags, out convFlags);
            }

            //Modify conversion flags, if necessary
            FormatConverter.ModifyConversionFormat(ref format, ref convFlags, flags);

            //If palette image, the palette will be the first thing
            int[] palette = null;
            if (FormatConverter.HasConversionFlag(convFlags, ConversionFlags.Pal8))
            {
                palette = new int[256];
                int palSize = palette.Length * sizeof(int);
                buffer.ReadBytes(input, palSize);

                if (buffer.LastReadByteCount != palSize)
                {
                    return(null);
                }

                MemoryHelper.CopyBytes <int>(buffer.ByteArray, 0, palette, 0, palette.Length);
            }

            //Now read data based on available mip/arrays
            mipChains = new List <MipChain>(arrayCount);

            byte[] scanline     = buffer.ByteArray;
            IntPtr scanlinePtr  = buffer.Pointer;
            bool   noPadding    = (flags & DDSFlags.NoPadding) == DDSFlags.NoPadding ? true : false;
            bool   isCompressed = FormatConverter.IsCompressed(format);
            bool   errored      = false;

            try
            {
                //Iterate over each array face...
                for (int i = 0; i < arrayCount; i++)
                {
                    MipChain mipChain = new MipChain(mipCount);
                    mipChains.Add(mipChain);

                    //Iterate over each mip face...
                    for (int mipLevel = 0; mipLevel < mipCount; mipLevel++)
                    {
                        //Calculate mip dimensions
                        int mipWidth  = width;
                        int mipHeight = height;
                        int mipDepth  = depth;
                        ImageHelper.CalculateMipmapLevelDimensions(mipLevel, ref mipWidth, ref mipHeight, ref mipDepth);

                        //Compute pitch, based on MSDN programming guide which says PitchOrLinearSize is unreliable and to calculate based on format.
                        //"real" mip width/height is the given mip width/height for all non-compressed, compressed images it will be smaller since each block
                        //is a 4x4 region of pixels.
                        int realMipWidth, realMipHeight, dstRowPitch, dstSlicePitch, bytesPerPixel;
                        ImageHelper.ComputePitch(format, mipWidth, mipHeight, out dstRowPitch, out dstSlicePitch, out realMipWidth, out realMipHeight, out bytesPerPixel, legacyDword);

                        int srcRowPitch   = dstRowPitch;
                        int srcSlicePitch = dstSlicePitch;

                        //Are we converting from a legacy format, possibly?
                        if (!headerExt.HasValue)
                        {
                            int legacySize = FormatConverter.LegacyFormatBitsPerPixelFromConversionFlag(convFlags);
                            if (legacySize != 0)
                            {
                                srcRowPitch   = (realMipWidth * legacySize + 7) / 8;
                                srcSlicePitch = srcRowPitch * realMipHeight;
                            }
                        }

                        //If output data is requested not to have padding, recompute destination pitches
                        if (noPadding)
                        {
                            dstRowPitch   = bytesPerPixel * realMipWidth;
                            dstSlicePitch = dstRowPitch * realMipHeight;
                        }

                        //Setup memory to hold the loaded image
                        MipData mipSurface = new MipData(mipWidth, mipHeight, mipDepth, dstRowPitch, dstSlicePitch);
                        mipChain.Add(mipSurface);

                        //Ensure read buffer is sufficiently sized for a single scanline
                        if (buffer.Length < srcRowPitch)
                        {
                            buffer.Resize(srcRowPitch, false);
                        }

                        IntPtr dstPtr = mipSurface.Data;

                        //Advance stream one slice at a time...
                        for (int slice = 0; slice < mipDepth; slice++)
                        {
                            long   slicePos = input.Position;
                            IntPtr dPtr     = dstPtr;

                            //Copy scanline into temp buffer, do any conversions, copy to output
                            for (int row = 0; row < realMipHeight; row++)
                            {
                                int numBytesRead = input.Read(scanline, 0, srcRowPitch);
                                if (numBytesRead != srcRowPitch)
                                {
                                    errored = true;
                                    System.Diagnostics.Debug.Assert(false);
                                    return(null);
                                }

                                //Copy scanline, optionally convert data
                                FormatConverter.CopyScanline(dPtr, dstRowPitch, scanlinePtr, srcRowPitch, format, convFlags, palette);

                                //Increment dest pointer to next row
                                dPtr = MemoryHelper.AddIntPtr(dPtr, dstRowPitch);
                            }

                            //Advance stream and destination pointer to the next slice
                            input.Position = slicePos + srcSlicePitch;
                            dstPtr         = MemoryHelper.AddIntPtr(dstPtr, dstSlicePitch);
                        }
                    }
                }
            }
            finally
            {
                //If errored, clean up any mip surfaces we allocated...no null entries should have been made either
                if (errored)
                {
                    DisposeMipChains(mipChains);
                }
            }

            if (!ValidateInternal(mipChains, format, texDim))
            {
                System.Diagnostics.Debug.Assert(false);
                return(null);
            }

            return(new DDSContainer(mipChains, format, texDim));
        }
        /// <summary>
        /// Writes a DDS file to a stream. Image data is expected to be 32-bit color data, if not then mipmaps are converted as necessary automatically without modifying input data.
        /// </summary>
        /// <param name="output">Output stream.</param>
        /// <param name="mipChains">Mipmap chains to write. Each mipmap chain represents a single face (so > 1 represents an array texture or a Cubemap). All faces must have
        /// equivalent dimensions and each chain must have the same number of mipmaps.</param>
        /// <param name="texDim">Dimension of the texture to write.</param>
        /// <param name="flags">Flags to control how the DDS data is saved.</param>
        /// <returns>True if writing the data was successful, false if otherwise.</returns>
        public static bool Write(Stream output, List <List <Surface> > mipChains, TextureDimension texDim, DDSFlags flags = DDSFlags.None)
        {
            if (mipChains == null || mipChains.Count == 0 || mipChains[0] == null || mipChains[0].Count == 0)
            {
                return(false);
            }

            //FreeImage doesn't support volume textures.
            if (texDim == TextureDimension.Three)
            {
                return(false);
            }

            //If texcube, must have multiples of 6, every 6 mipchains are a complete cubemap
            if (texDim == TextureDimension.Cube && (mipChains.Count % 6 != 0))
            {
                return(false);
            }

            //FreeImage surfaces are always uncompressed and we expect 32-bit color, if not we'll convert. We'll export in whatever color order freeimage is in,
            //but we can force RGBA based on the flags
            List <MipChain> ddsMipChains = new List <MipChain>(mipChains.Count);

            bool       forceRGBA     = (flags & DDSFlags.ForceRgb) == DDSFlags.ForceRgb;
            bool       isBGRAOrder   = Surface.IsBGRAOrder;
            bool       needToSwizzle = isBGRAOrder && forceRGBA;
            DXGIFormat format        = (isBGRAOrder) ? DXGIFormat.B8G8R8A8_UNorm : DXGIFormat.R8G8B8A8_UNorm;

            if (forceRGBA)
            {
                format = DXGIFormat.R8G8B8A8_UNorm;
            }

            try
            {
                int mipCount = -1;

                foreach (List <Surface> fiMipChain in mipChains)
                {
                    MipChain ddsMipChain = new MipChain(fiMipChain.Count);
                    ddsMipChains.Add(ddsMipChain);

                    if (mipCount == -1)
                    {
                        mipCount = fiMipChain.Count;
                    }

                    //All chains must have same # of mips
                    if (mipCount != fiMipChain.Count)
                    {
                        return(false);
                    }

                    foreach (Surface fiMip in fiMipChain)
                    {
                        if (fiMip == null)
                        {
                            return(false);
                        }

                        //Validate dimension
                        switch (texDim)
                        {
                        case TextureDimension.One:
                            if (fiMip.Height > 1)
                            {
                                return(false);
                            }
                            break;

                        case TextureDimension.Cube:
                            if (fiMip.Width != fiMip.Height)
                            {
                                return(false);
                            }
                            break;
                        }

                        bool is32BitBitmap = fiMip.ImageType == ImageType.Bitmap && fiMip.ColorType == ImageColorType.RGBA && fiMip.BitsPerPixel == 32;

                        if (is32BitBitmap)
                        {
                            //If no swizzling...just use the data directly
                            if (!needToSwizzle)
                            {
                                ddsMipChain.Add(new MipData(fiMip));
                            }
                            else
                            {
                                MipData newMip = new MipData(fiMip.Width, fiMip.Height, fiMip.Pitch);
                                ImageHelper.CopyColorImageData(newMip.Data, newMip.RowPitch, 0, fiMip.DataPtr, fiMip.Pitch, 0, newMip.Width, newMip.Height, 1, true);
                                ddsMipChain.Add(newMip);
                            }
                        }
                        else
                        {
                            //Need to convert. Possible to map other DXGI formats to free image bitmaps (most likely RGBA floats), but we're keeping it simple. User can wrap surfaces
                            //and use the general write method
                            using (Surface converted = fiMip.Clone())
                            {
                                if (!converted.ConvertTo(ImageConversion.To32Bits))
                                {
                                    return(false);
                                }

                                MipData newMip = new MipData(converted.Width, converted.Height, converted.Pitch);
                                ImageHelper.CopyColorImageData(newMip.Data, newMip.RowPitch, 0, converted.DataPtr, converted.Pitch, 0, newMip.Width, newMip.Height, 1, needToSwizzle);
                                ddsMipChain.Add(newMip);
                            }
                        }
                    }
                }

                //Write out DDS
                return(Write(output, ddsMipChains, format, texDim, flags));
            }
            finally
            {
                //Dispose of mip surfaces. If they own any data, it'll be cleaned up
                DisposeMipChains(ddsMipChains);
            }
        }
        /// <summary>
        /// Writes DDS formatted data to a stream. Image data is expected to be DXGI-compliant data, but an effort is made to write out D3D9-compatible headers when possible.
        /// </summary>
        /// <param name="output">Output stream.</param>
        /// <param name="mipChains">Mipmap chains to write. Each mipmap chain represents a single face (so > 1 represents an array texture or a Cubemap). All faces must have
        /// equivalent dimensions and each chain must have the same number of mipmaps.</param>
        /// <param name="format">DXGI format the image data is stored as.</param>
        /// <param name="texDim">Dimension of the texture to write.</param>
        /// <param name="flags">Flags to control how the DDS data is saved.</param>
        /// <returns>True if writing the data was successful, false if otherwise.</returns>
        public static bool Write(Stream output, List <MipChain> mipChains, DXGIFormat format, TextureDimension texDim, DDSFlags flags = DDSFlags.None)
        {
            if (output == null || !output.CanWrite || mipChains == null || mipChains.Count == 0 || mipChains[0].Count == 0 || format == DXGIFormat.Unknown)
            {
                return(false);
            }

            //Extract details
            int     width, height, depth, arrayCount, mipCount;
            MipData firstMip = mipChains[0][0];

            width      = firstMip.Width;
            height     = firstMip.Height;
            depth      = firstMip.Depth;
            arrayCount = mipChains.Count;
            mipCount   = mipChains[0].Count;

            if (!ValidateInternal(mipChains, format, texDim))
            {
                return(false);
            }

            //Setup a transfer buffer
            StreamTransferBuffer buffer = new StreamTransferBuffer(firstMip.RowPitch, false);

            //Write out header
            if (!WriteHeader(output, buffer, texDim, format, width, height, depth, arrayCount, mipCount, flags))
            {
                return(false);
            }

            //Iterate over each array face...
            for (int i = 0; i < arrayCount; i++)
            {
                MipChain mipChain = mipChains[i];

                //Iterate over each mip face...
                for (int mipLevel = 0; mipLevel < mipCount; mipLevel++)
                {
                    MipData mip = mipChain[mipLevel];

                    //Compute pitch, based on MSDN programming guide. We will write out these pitches rather than the supplied in order to conform to the recomendation
                    //that we compute pitch based on format
                    int realMipWidth, realMipHeight, dstRowPitch, dstSlicePitch, bytesPerPixel;
                    ImageHelper.ComputePitch(format, mip.Width, mip.Height, out dstRowPitch, out dstSlicePitch, out realMipWidth, out realMipHeight, out bytesPerPixel);

                    //Ensure write buffer is sufficiently sized for a single scanline
                    if (buffer.Length < dstRowPitch)
                    {
                        buffer.Resize(dstRowPitch, false);
                    }

                    //Sanity check
                    if (dstRowPitch < mip.RowPitch)
                    {
                        return(false);
                    }

                    IntPtr srcPtr = mip.Data;

                    //Advance stream one slice at a time...
                    for (int slice = 0; slice < mip.Depth; slice++)
                    {
                        int    bytesToWrite = dstSlicePitch;
                        IntPtr sPtr         = srcPtr;

                        //Copy scanline into temp buffer, write to output
                        for (int row = 0; row < realMipHeight; row++)
                        {
                            MemoryHelper.CopyMemory(buffer.Pointer, sPtr, dstRowPitch);
                            buffer.WriteBytes(output, dstRowPitch);
                            bytesToWrite -= dstRowPitch;

                            //Advance to next scanline in source data
                            sPtr = MemoryHelper.AddIntPtr(sPtr, mip.RowPitch);
                        }

                        //Pad slice if necessary
                        if (bytesToWrite > 0)
                        {
                            MemoryHelper.ClearMemory(buffer.Pointer, 0, bytesToWrite);
                            buffer.WriteBytes(output, bytesToWrite);
                        }

                        //Advance source pointer to next slice
                        srcPtr = MemoryHelper.AddIntPtr(srcPtr, mip.SlicePitch);
                    }
                }
            }

            return(true);
        }
        private static bool WriteHeader(Stream output, StreamTransferBuffer buffer, TextureDimension texDim, DXGIFormat format, int width, int height, int depth, int arrayCount, int mipCount, DDSFlags flags)
        {
            //Force the DX10 header...
            bool writeDX10Header = (flags & DDSFlags.ForceExtendedHeader) == DDSFlags.ForceExtendedHeader;

            //Or do DX10 if the following is true...1D textures or 2D texture arrays that aren't cubemaps...
            if (!writeDX10Header)
            {
                switch (texDim)
                {
                case TextureDimension.One:
                    writeDX10Header = true;
                    break;

                case TextureDimension.Two:
                    writeDX10Header = arrayCount > 1;
                    break;
                }
            }

            //Figure out pixel format, if not writing DX10 header...
            PixelFormat pixelFormat;

            if (!writeDX10Header)
            {
                switch (format)
                {
                case DXGIFormat.R8G8B8A8_UNorm:
                    pixelFormat = PixelFormat.A8B8G8R8;
                    break;

                case DXGIFormat.R16G16_UNorm:
                    pixelFormat = PixelFormat.G16R16;
                    break;

                case DXGIFormat.R8G8_UNorm:
                    pixelFormat = PixelFormat.A8L8;
                    break;

                case DXGIFormat.R16_UNorm:
                    pixelFormat = PixelFormat.L16;
                    break;

                case DXGIFormat.R8_UNorm:
                    pixelFormat = PixelFormat.L8;
                    break;

                case DXGIFormat.A8_UNorm:
                    pixelFormat = PixelFormat.A8;
                    break;

                case DXGIFormat.R8G8_B8G8_UNorm:
                    pixelFormat = PixelFormat.R8G8_B8G8;
                    break;

                case DXGIFormat.G8R8_G8B8_UNorm:
                    pixelFormat = PixelFormat.G8R8_G8B8;
                    break;

                case DXGIFormat.BC1_UNorm:
                    pixelFormat = PixelFormat.DXT1;
                    break;

                case DXGIFormat.BC2_UNorm:
                    pixelFormat = PixelFormat.DXT3;
                    break;

                case DXGIFormat.BC3_UNorm:
                    pixelFormat = PixelFormat.DXT5;
                    break;

                case DXGIFormat.BC4_UNorm:
                    pixelFormat = PixelFormat.BC4_UNorm;
                    break;

                case DXGIFormat.BC4_SNorm:
                    pixelFormat = PixelFormat.BC4_SNorm;
                    break;

                case DXGIFormat.BC5_UNorm:
                    pixelFormat = PixelFormat.BC5_UNorm;
                    break;

                case DXGIFormat.BC5_SNorm:
                    pixelFormat = PixelFormat.BC5_SNorm;
                    break;

                case DXGIFormat.B5G6R5_UNorm:
                    pixelFormat = PixelFormat.R5G6B5;
                    break;

                case DXGIFormat.B5G5R5A1_UNorm:
                    pixelFormat = PixelFormat.A1R5G5B5;
                    break;

                case DXGIFormat.B8G8R8A8_UNorm:
                    pixelFormat = PixelFormat.A8R8G8B8;
                    break;

                case DXGIFormat.B8G8R8X8_UNorm:
                    pixelFormat = PixelFormat.X8R8G8B8;
                    break;

                case DXGIFormat.B4G4R4A4_UNorm:
                    pixelFormat = PixelFormat.A4R4G4B4;
                    break;

                case DXGIFormat.R32G32B32A32_Float:
                    pixelFormat = PixelFormat.R32G32B32A32_Float;
                    break;

                case DXGIFormat.R16G16B16A16_Float:
                    pixelFormat = PixelFormat.R16G16B16A16_Float;
                    break;

                case DXGIFormat.R16G16B16A16_UNorm:
                    pixelFormat = PixelFormat.R16G16B16A16_UNorm;
                    break;

                case DXGIFormat.R16G16B16A16_SNorm:
                    pixelFormat = PixelFormat.R16G16B16A16_SNorm;
                    break;

                case DXGIFormat.R32G32_Float:
                    pixelFormat = PixelFormat.R32G32_Float;
                    break;

                case DXGIFormat.R16G16_Float:
                    pixelFormat = PixelFormat.R16G16_Float;
                    break;

                case DXGIFormat.R32_Float:
                    pixelFormat = PixelFormat.R32_Float;
                    break;

                case DXGIFormat.R16_Float:
                    pixelFormat = PixelFormat.R16_Float;
                    break;

                default:
                    pixelFormat     = PixelFormat.DX10Extended;
                    writeDX10Header = true;
                    break;
                }
            }
            else
            {
                pixelFormat = PixelFormat.DX10Extended;
            }

            Header header = new Header();

            header.Size        = (uint)MemoryHelper.SizeOf <Header>();
            header.PixelFormat = pixelFormat;
            header.Flags       = HeaderFlags.Caps | HeaderFlags.Width | HeaderFlags.Height | HeaderFlags.PixelFormat;
            header.Caps        = HeaderCaps.Texture;

            Header10?header10 = null;

            if (mipCount > 0)
            {
                header.Flags      |= HeaderFlags.MipMapCount;
                header.MipMapCount = (uint)mipCount;
                header.Caps       |= HeaderCaps.MipMap;
            }

            switch (texDim)
            {
            case TextureDimension.One:
                header.Width  = (uint)width;
                header.Height = 1;
                header.Depth  = 1;

                //Should always be writing out extended header for 1D textures
                System.Diagnostics.Debug.Assert(writeDX10Header);

                header10 = new Header10(format, D3D10ResourceDimension.Texture1D, Header10Flags.None, (uint)arrayCount, Header10Flags2.None);

                break;

            case TextureDimension.Two:
                header.Width  = (uint)width;
                header.Height = (uint)height;
                header.Depth  = 1;

                if (writeDX10Header)
                {
                    header10 = new Header10(format, D3D10ResourceDimension.Texture2D, Header10Flags.None, (uint)arrayCount, Header10Flags2.None);
                }

                break;

            case TextureDimension.Cube:
                header.Width  = (uint)width;
                header.Height = (uint)height;
                header.Depth  = 1;
                header.Caps  |= HeaderCaps.Complex;
                header.Caps2 |= HeaderCaps2.Cubemap_AllFaces;

                //can support array tex cubes, so must be multiples of 6
                if (arrayCount % 6 != 0)
                {
                    return(false);
                }

                if (writeDX10Header)
                {
                    header10 = new Header10(format, D3D10ResourceDimension.Texture2D, Header10Flags.TextureCube, (uint)arrayCount / 6, Header10Flags2.None);
                }

                break;

            case TextureDimension.Three:
                header.Width  = (uint)width;
                header.Height = (uint)height;
                header.Depth  = (uint)depth;
                header.Flags |= HeaderFlags.Depth;
                header.Caps2 |= HeaderCaps2.Volume;

                if (arrayCount != 1)
                {
                    return(false);
                }

                if (writeDX10Header)
                {
                    header10 = new Header10(format, D3D10ResourceDimension.Texture3D, Header10Flags.None, 1, Header10Flags2.None);
                }

                break;
            }

            int realWidth, realHeight, rowPitch, slicePitch;

            ImageHelper.ComputePitch(format, width, height, out rowPitch, out slicePitch, out realWidth, out realHeight);

            if (FormatConverter.IsCompressed(format))
            {
                header.Flags            |= HeaderFlags.LinearSize;
                header.PitchOrLinearSize = (uint)slicePitch;
            }
            else
            {
                header.Flags            |= HeaderFlags.Pitch;
                header.PitchOrLinearSize = (uint)rowPitch;
            }

            //Write out magic word, DDS header, and optionally extended header
            buffer.Write <FourCC>(output, DDS_MAGIC);
            buffer.Write <Header>(output, header);

            if (header10.HasValue)
            {
                System.Diagnostics.Debug.Assert(header.PixelFormat.IsDX10Extended);
                buffer.Write <Header10>(output, header10.Value);
            }

            return(true);
        }
 /// <summary>
 /// Generates DirectXTex Meta Data
 /// </summary>
 /// <param name="width">Image Width</param>
 /// <param name="height">Image Height</param>
 /// <param name="mipMapLevels">Number of Mip Maps</param>
 /// <param name="format">Compression Format</param>
 /// <param name="isCubeMap">Whether or not this is a cube map</param>
 /// <returns>Resulting TexMetaData Object</returns>
 public static TexMetadata GenerateMataData(int width, int height, int mipMapLevels, DXGIFormat format, bool isCubeMap)
 {
     // Create Texture MetaData
     return(new TexMetadata(
                width,
                height,
                1,
                isCubeMap ? 6 : 1,
                mipMapLevels,
                isCubeMap ? TexMiscFlags.TEXTURECUBE : 0,
                0,
                format,
                TexDimension.TEXTURE2D
                ));
 }
        /// <summary>
        /// Computes Row and Slice Pitch
        /// </summary>
        private static void ComputePitch(DXGIFormat format, long width, long height, out long rowPitch, out long slicePitch, CPFLAGS flags)
        {
            switch (format)
            {
            case DXGIFormat.BC1TYPELESS:
            case DXGIFormat.BC1UNORM:
            case DXGIFormat.BC1UNORMSRGB:
            case DXGIFormat.BC4TYPELESS:
            case DXGIFormat.BC4UNORM:
            case DXGIFormat.BC4SNORM:
            {
                if (flags.HasFlag(CPFLAGS.BADDXTNTAILS))
                {
                    long nbw = width >> 2;
                    long nbh = height >> 2;
                    rowPitch   = Clamp(1, nbw * 8, Int64.MaxValue);
                    slicePitch = Clamp(1, rowPitch * nbh, Int64.MaxValue);
                }
                else
                {
                    long nbw = Clamp(1, (width + 3) / 4, Int64.MaxValue);
                    long nbh = Clamp(1, (height + 3) / 4, Int64.MaxValue);
                    rowPitch   = nbw * 8;
                    slicePitch = rowPitch * nbh;
                }
            }
            break;

            case DXGIFormat.BC2TYPELESS:
            case DXGIFormat.BC2UNORM:
            case DXGIFormat.BC2UNORMSRGB:
            case DXGIFormat.BC3TYPELESS:
            case DXGIFormat.BC3UNORM:
            case DXGIFormat.BC3UNORMSRGB:
            case DXGIFormat.BC5TYPELESS:
            case DXGIFormat.BC5UNORM:
            case DXGIFormat.BC5SNORM:
            case DXGIFormat.BC6HTYPELESS:
            case DXGIFormat.BC6HUF16:
            case DXGIFormat.BC6HSF16:
            case DXGIFormat.BC7TYPELESS:
            case DXGIFormat.BC7UNORM:
            case DXGIFormat.BC7UNORMSRGB:
            {
                if (flags.HasFlag(CPFLAGS.BADDXTNTAILS))
                {
                    long nbw = width >> 2;
                    long nbh = height >> 2;
                    rowPitch   = Clamp(1, nbw * 16, Int64.MaxValue);
                    slicePitch = Clamp(1, rowPitch * nbh, Int64.MaxValue);
                }
                else
                {
                    long nbw = Clamp(1, (width + 3) / 4, Int64.MaxValue);
                    long nbh = Clamp(1, (height + 3) / 4, Int64.MaxValue);
                    rowPitch   = nbw * 16;
                    slicePitch = rowPitch * nbh;
                }
            }
            break;

            case DXGIFormat.R8G8B8G8UNORM:
            case DXGIFormat.G8R8G8B8UNORM:
            case DXGIFormat.YUY2:
                rowPitch   = ((width + 1) >> 1) * 4;
                slicePitch = rowPitch * height;
                break;

            case DXGIFormat.Y210:
            case DXGIFormat.Y216:
                rowPitch   = ((width + 1) >> 1) * 8;
                slicePitch = rowPitch * height;
                break;

            case DXGIFormat.NV12:
            case DXGIFormat.OPAQUE420:
                rowPitch   = ((width + 1) >> 1) * 2;
                slicePitch = rowPitch * (height + ((height + 1) >> 1));
                break;

            case DXGIFormat.P010:
            case DXGIFormat.P016:
                rowPitch   = ((width + 1) >> 1) * 4;
                slicePitch = rowPitch * (height + ((height + 1) >> 1));
                break;

            case DXGIFormat.NV11:
                rowPitch   = ((width + 3) >> 2) * 4;
                slicePitch = rowPitch * height * 2;
                break;

            default:
            {
                long bpp;

                if (flags.HasFlag(CPFLAGS.BPP24))
                {
                    bpp = 24;
                }
                else if (flags.HasFlag(CPFLAGS.BPP16))
                {
                    bpp = 16;
                }
                else if (flags.HasFlag(CPFLAGS.BPP8))
                {
                    bpp = 8;
                }
                else
                {
                    bpp = BitsPerPixel(format);
                }

                if (flags.HasFlag(CPFLAGS.LEGACYDWORD | CPFLAGS.PARAGRAPH | CPFLAGS.YMM | CPFLAGS.ZMM | CPFLAGS.PAGE4K))
                {
                    if (flags.HasFlag(CPFLAGS.PAGE4K))
                    {
                        rowPitch   = ((width * bpp + 32767) / 32768) * 4096;
                        slicePitch = rowPitch * height;
                    }
                    else if (flags.HasFlag(CPFLAGS.ZMM))
                    {
                        rowPitch   = ((width * bpp + 511) / 512) * 64;
                        slicePitch = rowPitch * height;
                    }
                    else if (flags.HasFlag(CPFLAGS.YMM))
                    {
                        rowPitch   = ((width * bpp + 255) / 256) * 32;
                        slicePitch = rowPitch * height;
                    }
                    else if (flags.HasFlag(CPFLAGS.PARAGRAPH))
                    {
                        rowPitch   = ((width * bpp + 127) / 128) * 16;
                        slicePitch = rowPitch * height;
                    }
                    else         // DWORD alignment
                    {
                        // Special computation for some incorrectly created DDS files based on
                        // legacy DirectDraw assumptions about pitch alignment
                        rowPitch   = ((width * bpp + 31) / 32) * 4;
                        slicePitch = rowPitch * height;
                    }
                }
                else
                {
                    // Default byte alignment
                    rowPitch   = (width * bpp + 7) / 8;
                    slicePitch = rowPitch * height;
                }
            }
            break;
            }
        }
        /// <summary>
        /// Gets the Bits Per Pixel for the given format
        /// </summary>
        private static long BitsPerPixel(DXGIFormat format)
        {
            switch (format)
            {
            case DXGIFormat.R32G32B32A32TYPELESS:
            case DXGIFormat.R32G32B32A32FLOAT:
            case DXGIFormat.R32G32B32A32UINT:
            case DXGIFormat.R32G32B32A32SINT:
                return(128);

            case DXGIFormat.R32G32B32TYPELESS:
            case DXGIFormat.R32G32B32FLOAT:
            case DXGIFormat.R32G32B32UINT:
            case DXGIFormat.R32G32B32SINT:
                return(96);

            case DXGIFormat.R16G16B16A16TYPELESS:
            case DXGIFormat.R16G16B16A16FLOAT:
            case DXGIFormat.R16G16B16A16UNORM:
            case DXGIFormat.R16G16B16A16UINT:
            case DXGIFormat.R16G16B16A16SNORM:
            case DXGIFormat.R16G16B16A16SINT:
            case DXGIFormat.R32G32TYPELESS:
            case DXGIFormat.R32G32FLOAT:
            case DXGIFormat.R32G32UINT:
            case DXGIFormat.R32G32SINT:
            case DXGIFormat.R32G8X24TYPELESS:
            case DXGIFormat.D32FLOATS8X24UINT:
            case DXGIFormat.R32FLOATX8X24TYPELESS:
            case DXGIFormat.X32TYPELESSG8X24UINT:
            case DXGIFormat.Y416:
            case DXGIFormat.Y210:
            case DXGIFormat.Y216:
                return(64);

            case DXGIFormat.R10G10B10A2TYPELESS:
            case DXGIFormat.R10G10B10A2UNORM:
            case DXGIFormat.R10G10B10A2UINT:
            case DXGIFormat.R11G11B10FLOAT:
            case DXGIFormat.R8G8B8A8TYPELESS:
            case DXGIFormat.R8G8B8A8UNORM:
            case DXGIFormat.R8G8B8A8UNORMSRGB:
            case DXGIFormat.R8G8B8A8UINT:
            case DXGIFormat.R8G8B8A8SNORM:
            case DXGIFormat.R8G8B8A8SINT:
            case DXGIFormat.R16G16TYPELESS:
            case DXGIFormat.R16G16FLOAT:
            case DXGIFormat.R16G16UNORM:
            case DXGIFormat.R16G16UINT:
            case DXGIFormat.R16G16SNORM:
            case DXGIFormat.R16G16SINT:
            case DXGIFormat.R32TYPELESS:
            case DXGIFormat.D32FLOAT:
            case DXGIFormat.R32FLOAT:
            case DXGIFormat.R32UINT:
            case DXGIFormat.R32SINT:
            case DXGIFormat.R24G8TYPELESS:
            case DXGIFormat.D24UNORMS8UINT:
            case DXGIFormat.R24UNORMX8TYPELESS:
            case DXGIFormat.X24TYPELESSG8UINT:
            case DXGIFormat.R9G9B9E5SHAREDEXP:
            case DXGIFormat.R8G8B8G8UNORM:
            case DXGIFormat.G8R8G8B8UNORM:
            case DXGIFormat.B8G8R8A8UNORM:
            case DXGIFormat.B8G8R8X8UNORM:
            case DXGIFormat.R10G10B10XRBIASA2UNORM:
            case DXGIFormat.B8G8R8A8TYPELESS:
            case DXGIFormat.B8G8R8A8UNORMSRGB:
            case DXGIFormat.B8G8R8X8TYPELESS:
            case DXGIFormat.B8G8R8X8UNORMSRGB:
            case DXGIFormat.AYUV:
            case DXGIFormat.Y410:
            case DXGIFormat.YUY2:
                return(32);

            case DXGIFormat.P010:
            case DXGIFormat.P016:
                return(24);

            case DXGIFormat.R8G8TYPELESS:
            case DXGIFormat.R8G8UNORM:
            case DXGIFormat.R8G8UINT:
            case DXGIFormat.R8G8SNORM:
            case DXGIFormat.R8G8SINT:
            case DXGIFormat.R16TYPELESS:
            case DXGIFormat.R16FLOAT:
            case DXGIFormat.D16UNORM:
            case DXGIFormat.R16UNORM:
            case DXGIFormat.R16UINT:
            case DXGIFormat.R16SNORM:
            case DXGIFormat.R16SINT:
            case DXGIFormat.B5G6R5UNORM:
            case DXGIFormat.B5G5R5A1UNORM:
            case DXGIFormat.A8P8:
            case DXGIFormat.B4G4R4A4UNORM:
                return(16);

            case DXGIFormat.NV12:
            case DXGIFormat.OPAQUE420:
            case DXGIFormat.NV11:
                return(12);

            case DXGIFormat.R8TYPELESS:
            case DXGIFormat.R8UNORM:
            case DXGIFormat.R8UINT:
            case DXGIFormat.R8SNORM:
            case DXGIFormat.R8SINT:
            case DXGIFormat.A8UNORM:
            case DXGIFormat.AI44:
            case DXGIFormat.IA44:
            case DXGIFormat.P8:
                return(8);

            case DXGIFormat.R1UNORM:
                return(1);

            case DXGIFormat.BC1TYPELESS:
            case DXGIFormat.BC1UNORM:
            case DXGIFormat.BC1UNORMSRGB:
            case DXGIFormat.BC4TYPELESS:
            case DXGIFormat.BC4UNORM:
            case DXGIFormat.BC4SNORM:
                return(4);

            case DXGIFormat.BC2TYPELESS:
            case DXGIFormat.BC2UNORM:
            case DXGIFormat.BC2UNORMSRGB:
            case DXGIFormat.BC3TYPELESS:
            case DXGIFormat.BC3UNORM:
            case DXGIFormat.BC3UNORMSRGB:
            case DXGIFormat.BC5TYPELESS:
            case DXGIFormat.BC5UNORM:
            case DXGIFormat.BC5SNORM:
            case DXGIFormat.BC6HTYPELESS:
            case DXGIFormat.BC6HUF16:
            case DXGIFormat.BC6HSF16:
            case DXGIFormat.BC7TYPELESS:
            case DXGIFormat.BC7UNORM:
            case DXGIFormat.BC7UNORMSRGB:
                return(8);

            default:
                return(0);
            }
        }