Example #1
0
        /// <summary>
        /// Converts a DDS file into a TEX file then returns the raw data
        /// </summary>
        /// <param name="xivTex">The texture data</param>
        /// <param name="item">The item who's texture we are importing</param>
        /// <param name="ddsFileDirectory">The directory of the dds file being imported</param>
        /// <returns>The offset to the new imported data</returns>
        public byte[] DDStoTexData(XivTex xivTex, IItem item, DirectoryInfo ddsFileDirectory)
        {
            var offset = 0;

            var dat = new Dat(_gameDirectory);

            if (File.Exists(ddsFileDirectory.FullName))
            {
                using (var br = new BinaryReader(File.OpenRead(ddsFileDirectory.FullName)))
                {
                    br.BaseStream.Seek(12, SeekOrigin.Begin);

                    var newHeight = br.ReadInt32();
                    var newWidth  = br.ReadInt32();
                    br.ReadBytes(8);
                    var newMipCount = br.ReadInt32();

                    if (newHeight % 2 != 0 || newWidth % 2 != 0)
                    {
                        throw new Exception("Resolution must be a multiple of 2");
                    }

                    br.BaseStream.Seek(80, SeekOrigin.Begin);

                    var          textureFlags = br.ReadInt32();
                    var          texType      = br.ReadInt32();
                    XivTexFormat textureType;

                    if (DDSType.ContainsKey(texType))
                    {
                        textureType = DDSType[texType];
                    }
                    else
                    {
                        throw new Exception($"DDS Type ({texType}) not recognized.");
                    }

                    switch (textureFlags)
                    {
                    case 2 when textureType == XivTexFormat.A8R8G8B8:
                        textureType = XivTexFormat.A8;
                        break;

                    case 65 when textureType == XivTexFormat.A8R8G8B8:
                        var bpp = br.ReadInt32();
                        if (bpp == 32)
                        {
                            textureType = XivTexFormat.A8R8G8B8;
                        }
                        else
                        {
                            var red = br.ReadInt32();

                            switch (red)
                            {
                            case 31744:
                                textureType = XivTexFormat.A1R5G5B5;
                                break;

                            case 3840:
                                textureType = XivTexFormat.A4R4G4B4;
                                break;
                            }
                        }

                        break;
                    }

                    if (textureType == xivTex.TextureFormat)
                    {
                        var uncompressedLength = (int)new FileInfo(ddsFileDirectory.FullName).Length - 128;
                        var newTex             = new List <byte>();

                        if (!xivTex.TextureTypeAndPath.Path.Contains(".atex"))
                        {
                            var DDSInfo = DDS.ReadDDS(br, xivTex, newWidth, newHeight, newMipCount);

                            newTex.AddRange(dat.MakeType4DatHeader(xivTex, DDSInfo.mipPartOffsets, DDSInfo.mipPartCounts, uncompressedLength, newMipCount, newWidth, newHeight));
                            newTex.AddRange(MakeTextureInfoHeader(xivTex, newWidth, newHeight, newMipCount));
                            newTex.AddRange(DDSInfo.compressedDDS);

                            return(newTex.ToArray());
                        }
                        else
                        {
                            br.BaseStream.Seek(128, SeekOrigin.Begin);
                            newTex.AddRange(MakeTextureInfoHeader(xivTex, newWidth, newHeight, newMipCount));
                            newTex.AddRange(br.ReadBytes(uncompressedLength));

                            return(newTex.ToArray());
                        }
                    }
                    else
                    {
                        throw new Exception($"Incorrect file type. Expected: {xivTex.TextureFormat}  Given: {textureType}");
                    }
                }
            }
            else
            {
                throw new IOException($"Could not find file: {ddsFileDirectory.FullName}");
            }
        }
Example #2
0
        public async Task <int> TexBMPImporter(XivTex xivTex, IItem item, DirectoryInfo bmpFileDirectory, string source)
        {
            var offset = 0;

            var modding = new Modding(_gameDirectory);

            if (File.Exists(bmpFileDirectory.FullName))
            {
                // Check if the texture being imported has been imported before
                var modEntry = await modding.TryGetModEntry(xivTex.TextureTypeAndPath.Path);

                using (var magickImage = new MagickImage(bmpFileDirectory.FullName))
                {
                    switch (xivTex.TextureFormat)
                    {
                    case XivTexFormat.DXT1:
                        magickImage.Format = MagickFormat.Dxt1;
                        break;

                    case XivTexFormat.DXT5:
                        magickImage.Format = MagickFormat.Dxt5;
                        break;

                    case XivTexFormat.A8R8G8B8:
                        magickImage.Format = MagickFormat.Dds;
                        magickImage.Settings.SetDefines(new DdsWriteDefines
                        {
                            Compression = DdsCompression.None
                        });
                        break;

                    default:
                        throw new Exception($"Format {xivTex.TextureFormat} is not currently supported for BMP import\n\nPlease use the DDS import option instead.");
                    }

                    var data = magickImage.ToByteArray();

                    using (var br = new BinaryReader(new MemoryStream(data)))
                    {
                        br.BaseStream.Seek(12, SeekOrigin.Begin);

                        var newHeight = br.ReadInt32();
                        var newWidth  = br.ReadInt32();
                        br.ReadBytes(8);
                        var newMipCount = br.ReadInt32();

                        if (newHeight % 2 != 0 || newWidth % 2 != 0)
                        {
                            throw new Exception("Resolution must be a multiple of 2");
                        }

                        br.BaseStream.Seek(80, SeekOrigin.Begin);

                        var          textureFlags = br.ReadInt32();
                        var          texType      = br.ReadInt32();
                        XivTexFormat textureType;

                        if (DDSType.ContainsKey(texType))
                        {
                            textureType = DDSType[texType];
                        }
                        else
                        {
                            throw new Exception($"DDS Type ({texType}) not recognized.");
                        }

                        switch (textureFlags)
                        {
                        case 2 when textureType == XivTexFormat.A8R8G8B8:
                            textureType = XivTexFormat.A8;
                            break;

                        case 65 when textureType == XivTexFormat.A8R8G8B8:
                            var bpp = br.ReadInt32();
                            if (bpp == 32)
                            {
                                textureType = XivTexFormat.A8R8G8B8;
                            }
                            else
                            {
                                var red = br.ReadInt32();

                                switch (red)
                                {
                                case 31744:
                                    textureType = XivTexFormat.A1R5G5B5;
                                    break;

                                case 3840:
                                    textureType = XivTexFormat.A4R4G4B4;
                                    break;
                                }
                            }

                            break;
                        }

                        if (textureType == xivTex.TextureFormat)
                        {
                            var uncompressedLength = data.Length;
                            var newTex             = new List <byte>();

                            if (!xivTex.TextureTypeAndPath.Path.Contains(".atex"))
                            {
                                var DDSInfo = await DDS.ReadDDS(br, xivTex, newWidth, newHeight, newMipCount);

                                newTex.AddRange(_dat.MakeType4DatHeader(xivTex, DDSInfo.mipPartOffsets, DDSInfo.mipPartCounts, uncompressedLength, newMipCount, newWidth, newHeight));
                                newTex.AddRange(MakeTextureInfoHeader(xivTex, newWidth, newHeight, newMipCount));
                                newTex.AddRange(DDSInfo.compressedDDS);

                                offset = await _dat.WriteToDat(newTex, modEntry, xivTex.TextureTypeAndPath.Path,
                                                               item.ItemCategory, item.Name, xivTex.TextureTypeAndPath.DataFile, source, 4);
                            }
                            else
                            {
                                br.BaseStream.Seek(128, SeekOrigin.Begin);
                                newTex.AddRange(MakeTextureInfoHeader(xivTex, newWidth, newHeight, newMipCount));
                                newTex.AddRange(br.ReadBytes(uncompressedLength));

                                offset = await _dat.ImportType2Data(newTex.ToArray(), item.Name, xivTex.TextureTypeAndPath.Path,
                                                                    item.ItemCategory, source);
                            }
                        }
                        else
                        {
                            throw new Exception($"Incorrect file type. Expected: {xivTex.TextureFormat}  Given: {textureType}");
                        }
                    }
                }
            }
            else
            {
                throw new IOException($"Could not find file: {bmpFileDirectory.FullName}");
            }

            return(offset);
        }
Example #3
0
        /// <summary>
        /// Creates texture data ready to be imported into the DATs from an external file.
        /// If format is not specified, either the incoming file's DDS format is used (DDS files),
        /// or the existing internal file's DDS format is used.
        /// </summary>
        /// <param name="internalPath"></param>
        /// <param name="externalPath"></param>
        /// <param name="texFormat"></param>
        /// <returns></returns>
        public async Task <byte[]> MakeTexData(string internalPath, string externalPath, XivTexFormat texFormat = XivTexFormat.INVALID)
        {
            // Ensure file exists.
            if (!File.Exists(externalPath))
            {
                throw new IOException($"Could not find file: {externalPath}");
            }

            var root = await XivCache.GetFirstRoot(internalPath);

            bool isDds = Path.GetExtension(externalPath).ToLower() == ".dds";

            var ddsContainer = new DDSContainer();

            try
            {
                // If no format was specified...
                if (texFormat == XivTexFormat.INVALID)
                {
                    if (isDds)
                    {
                        // If we're importing a DDS file, get the format from the incoming DDS file
                        using (var fs = new FileStream(externalPath, FileMode.Open))
                        {
                            using (var sr = new BinaryReader(fs))
                            {
                                texFormat = GetDDSTexFormat(sr);
                            }
                        }
                    }
                    else
                    {
                        // Otherwise use the current internal format.
                        var xivt = await _dat.GetType4Data(internalPath, false);

                        texFormat = xivt.TextureFormat;
                    }
                }

                // Check if the texture being imported has been imported before
                CompressionFormat compressionFormat = CompressionFormat.BGRA;

                switch (texFormat)
                {
                case XivTexFormat.DXT1:
                    compressionFormat = CompressionFormat.BC1a;
                    break;

                case XivTexFormat.DXT5:
                    compressionFormat = CompressionFormat.BC3;
                    break;

                case XivTexFormat.A8R8G8B8:
                    compressionFormat = CompressionFormat.BGRA;
                    break;

                default:
                    if (!isDds)
                    {
                        throw new Exception($"Format {texFormat} is not currently supported for BMP import\n\nPlease use the DDS import option instead.");
                    }
                    break;
                }

                if (!isDds)
                {
                    using (var surface = Surface.LoadFromFile(externalPath))
                    {
                        if (surface == null)
                        {
                            throw new FormatException($"Unsupported texture format");
                        }

                        surface.FlipVertically();

                        var maxMipCount = 1;
                        if (root != null)
                        {
                            // For things that have real roots (things that have actual models/aren't UI textures), we always want mipMaps, even if the existing texture only has one.
                            // (Ex. The Default Mat-Add textures)
                            maxMipCount = -1;
                        }

                        using (var compressor = new Compressor())
                        {
                            // UI/Paintings only have a single mipmap and will crash if more are generated, for everything else generate max levels
                            compressor.Input.SetMipmapGeneration(true, maxMipCount);
                            compressor.Input.SetData(surface);
                            compressor.Compression.Format = compressionFormat;
                            compressor.Compression.SetBGRAPixelFormat();

                            compressor.Process(out ddsContainer);
                        }
                    }
                }

                // If we're not a DDS, write the DDS to file temporarily.
                var ddsFilePath = externalPath;
                if (!isDds)
                {
                    var tempFile = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString() + ".dds");
                    ddsContainer.Write(tempFile, DDSFlags.None);
                    ddsFilePath = tempFile;
                }

                using (var br = new BinaryReader(File.OpenRead(ddsFilePath)))
                {
                    br.BaseStream.Seek(12, SeekOrigin.Begin);

                    var newHeight = br.ReadInt32();
                    var newWidth  = br.ReadInt32();
                    br.ReadBytes(8);
                    var newMipCount = br.ReadInt32();

                    if (newHeight % 2 != 0 || newWidth % 2 != 0)
                    {
                        throw new Exception("Resolution must be a multiple of 2");
                    }

                    br.BaseStream.Seek(80, SeekOrigin.Begin);

                    var textureFlags = br.ReadInt32();
                    var texType      = br.ReadInt32();

                    var uncompressedLength = (int)new FileInfo(ddsFilePath).Length - 128;
                    var newTex             = new List <byte>();

                    if (!internalPath.Contains(".atex"))
                    {
                        var DDSInfo = await DDS.ReadDDS(br, texFormat, newWidth, newHeight, newMipCount);

                        newTex.AddRange(_dat.MakeType4DatHeader(texFormat, DDSInfo.mipPartOffsets, DDSInfo.mipPartCounts, (int)uncompressedLength, newMipCount, newWidth, newHeight));
                        newTex.AddRange(MakeTextureInfoHeader(texFormat, newWidth, newHeight, newMipCount));
                        newTex.AddRange(DDSInfo.compressedDDS);

                        return(newTex.ToArray());
                    }
                    else
                    {
                        br.BaseStream.Seek(128, SeekOrigin.Begin);
                        newTex.AddRange(MakeTextureInfoHeader(texFormat, newWidth, newHeight, newMipCount));
                        newTex.AddRange(br.ReadBytes((int)uncompressedLength));
                        var data = await _dat.CreateType2Data(newTex.ToArray());

                        return(data);
                    }
                }
            }
            finally
            {
                ddsContainer.Dispose();
            }
        }
Example #4
0
        /// <summary>
        /// Converts a DDS file into a TEX file then imports it
        /// </summary>
        /// <param name="xivTex">The texture data</param>
        /// <param name="item">The item who's texture we are importing</param>
        /// <param name="ddsFileDirectory">The directory of the dds file being imported</param>
        /// <returns>The offset to the new imported data</returns>
        public async Task <int> TexDDSImporter(XivTex xivTex, IItem item, DirectoryInfo ddsFileDirectory, string source)
        {
            var offset = 0;

            var modding = new Modding(_gameDirectory);

            if (File.Exists(ddsFileDirectory.FullName))
            {
                // Check if the texture being imported has been imported before
                var modEntry = await modding.TryGetModEntry(xivTex.TextureTypeAndPath.Path);

                using (var br = new BinaryReader(File.OpenRead(ddsFileDirectory.FullName)))
                {
                    br.BaseStream.Seek(12, SeekOrigin.Begin);

                    var newHeight = br.ReadInt32();
                    var newWidth  = br.ReadInt32();
                    br.ReadBytes(8);
                    var newMipCount = br.ReadInt32();

                    if (newHeight % 2 != 0 || newWidth % 2 != 0)
                    {
                        throw new Exception("Resolution must be a multiple of 2");
                    }

                    br.BaseStream.Seek(80, SeekOrigin.Begin);

                    var          textureFlags = br.ReadInt32();
                    var          texType      = br.ReadInt32();
                    XivTexFormat textureType;

                    if (DDSType.ContainsKey(texType))
                    {
                        textureType = DDSType[texType];
                    }
                    else
                    {
                        throw new Exception($"DDS Type ({texType}) not recognized.");
                    }

                    switch (textureFlags)
                    {
                    case 2 when textureType == XivTexFormat.A8R8G8B8:
                        textureType = XivTexFormat.A8;
                        break;

                    case 65 when textureType == XivTexFormat.A8R8G8B8:
                        var bpp = br.ReadInt32();
                        if (bpp == 32)
                        {
                            textureType = XivTexFormat.A8R8G8B8;
                        }
                        else
                        {
                            var red = br.ReadInt32();

                            switch (red)
                            {
                            case 31744:
                                textureType = XivTexFormat.A1R5G5B5;
                                break;

                            case 3840:
                                textureType = XivTexFormat.A4R4G4B4;
                                break;
                            }
                        }

                        break;
                    }

                    if (textureType == xivTex.TextureFormat)
                    {
                        var uncompressedLength = (int)new FileInfo(ddsFileDirectory.FullName).Length - 128;
                        var newTex             = new List <byte>();

                        if (!xivTex.TextureTypeAndPath.Path.Contains(".atex"))
                        {
                            var DDSInfo = await DDS.ReadDDS(br, xivTex, newWidth, newHeight, newMipCount);

                            newTex.AddRange(_dat.MakeType4DatHeader(xivTex, DDSInfo.mipPartOffsets, DDSInfo.mipPartCounts, uncompressedLength, newMipCount, newWidth, newHeight));
                            newTex.AddRange(MakeTextureInfoHeader(xivTex, newWidth, newHeight, newMipCount));
                            newTex.AddRange(DDSInfo.compressedDDS);

                            offset = await _dat.WriteToDat(newTex, modEntry, xivTex.TextureTypeAndPath.Path,
                                                           item.ItemCategory, item.Name, xivTex.TextureTypeAndPath.DataFile, source, 4);
                        }
                        else
                        {
                            br.BaseStream.Seek(128, SeekOrigin.Begin);
                            newTex.AddRange(MakeTextureInfoHeader(xivTex, newWidth, newHeight, newMipCount));
                            newTex.AddRange(br.ReadBytes(uncompressedLength));

                            offset = await _dat.ImportType2Data(newTex.ToArray(), item.Name, xivTex.TextureTypeAndPath.Path,
                                                                item.ItemCategory, source);
                        }
                    }
                    else
                    {
                        throw new Exception($"Incorrect file type. Expected: {xivTex.TextureFormat}  Given: {textureType}");
                    }
                }
            }
            else
            {
                throw new IOException($"Could not find file: {ddsFileDirectory.FullName}");
            }

            return(offset);
        }
Example #5
0
        public async Task <int> TexBMPImporter(XivTex xivTex, IItem item, DirectoryInfo bmpFileDirectory, string source)
        {
            var offset = 0;

            var modding = new Modding(_gameDirectory);

            if (File.Exists(bmpFileDirectory.FullName))
            {
                // Check if the texture being imported has been imported before
                var modEntry = await modding.TryGetModEntry(xivTex.TextureTypeAndPath.Path);

                var ddsContainer = new DDSContainer();
                CompressionFormat compressionFormat;

                switch (xivTex.TextureFormat)
                {
                case XivTexFormat.DXT1:
                    compressionFormat = CompressionFormat.BC1;
                    break;

                case XivTexFormat.DXT5:
                    compressionFormat = CompressionFormat.BC3;
                    break;

                case XivTexFormat.A8R8G8B8:
                    compressionFormat = CompressionFormat.BGRA;
                    break;

                default:
                    throw new Exception($"Format {xivTex.TextureFormat} is not currently supported for BMP import\n\nPlease use the DDS import option instead.");
                }

                using (var surface = Surface.LoadFromFile(bmpFileDirectory.FullName))
                {
                    surface.FlipVertically();

                    using (var compressor = new Compressor())
                    {
                        compressor.Input.GenerateMipmaps = true;
                        compressor.Input.SetData(surface);
                        compressor.Compression.Format = compressionFormat;
                        compressor.Compression.SetBGRAPixelFormat();

                        compressor.Process(out ddsContainer);
                    }
                }

                using (var ddsMemoryStream = new MemoryStream())
                {
                    ddsContainer.Write(ddsMemoryStream, DDSFlags.None);

                    using (var br = new BinaryReader(ddsMemoryStream))
                    {
                        br.BaseStream.Seek(12, SeekOrigin.Begin);

                        var newHeight = br.ReadInt32();
                        var newWidth  = br.ReadInt32();
                        br.ReadBytes(8);
                        var newMipCount = br.ReadInt32();

                        if (newHeight % 2 != 0 || newWidth % 2 != 0)
                        {
                            throw new Exception("Resolution must be a multiple of 2");
                        }

                        br.BaseStream.Seek(80, SeekOrigin.Begin);

                        var          textureFlags = br.ReadInt32();
                        var          texType      = br.ReadInt32();
                        XivTexFormat textureType;

                        if (DDSType.ContainsKey(texType))
                        {
                            textureType = DDSType[texType];
                        }
                        else
                        {
                            throw new Exception($"DDS Type ({texType}) not recognized.");
                        }

                        switch (textureFlags)
                        {
                        case 2 when textureType == XivTexFormat.A8R8G8B8:
                            textureType = XivTexFormat.A8;
                            break;

                        case 65 when textureType == XivTexFormat.A8R8G8B8:
                            var bpp = br.ReadInt32();
                            if (bpp == 32)
                            {
                                textureType = XivTexFormat.A8R8G8B8;
                            }
                            else
                            {
                                var red = br.ReadInt32();

                                switch (red)
                                {
                                case 31744:
                                    textureType = XivTexFormat.A1R5G5B5;
                                    break;

                                case 3840:
                                    textureType = XivTexFormat.A4R4G4B4;
                                    break;
                                }
                            }

                            break;
                        }

                        if (textureType == xivTex.TextureFormat)
                        {
                            var uncompressedLength = ddsMemoryStream.Length;
                            var newTex             = new List <byte>();

                            if (!xivTex.TextureTypeAndPath.Path.Contains(".atex"))
                            {
                                var DDSInfo = await DDS.ReadDDS(br, xivTex, newWidth, newHeight, newMipCount);

                                newTex.AddRange(_dat.MakeType4DatHeader(xivTex, DDSInfo.mipPartOffsets, DDSInfo.mipPartCounts, (int)uncompressedLength, newMipCount, newWidth, newHeight));
                                newTex.AddRange(MakeTextureInfoHeader(xivTex, newWidth, newHeight, newMipCount));
                                newTex.AddRange(DDSInfo.compressedDDS);

                                offset = await _dat.WriteToDat(newTex, modEntry, xivTex.TextureTypeAndPath.Path,
                                                               item.ItemCategory, item.Name, xivTex.TextureTypeAndPath.DataFile, source, 4);
                            }
                            else
                            {
                                br.BaseStream.Seek(128, SeekOrigin.Begin);
                                newTex.AddRange(MakeTextureInfoHeader(xivTex, newWidth, newHeight, newMipCount));
                                newTex.AddRange(br.ReadBytes((int)uncompressedLength));

                                offset = await _dat.ImportType2Data(newTex.ToArray(), item.Name, xivTex.TextureTypeAndPath.Path,
                                                                    item.ItemCategory, source);
                            }
                        }
                        else
                        {
                            throw new Exception($"Incorrect file type. Expected: {xivTex.TextureFormat}  Given: {textureType}");
                        }
                    }
                }

                ddsContainer.Dispose();
            }
            else
            {
                throw new IOException($"Could not find file: {bmpFileDirectory.FullName}");
            }

            return(offset);
        }