public DDS(DDSType Type) { switch (Type) { case DDSType.DXT1: this.Header.PixelFormat.Flags |= DDSPixelFormatFlags.DDPF_FOURCC; this.Header.PixelFormat.FourCC = DDSPixelFormatFourCC.DXT1; this.Header.Pitch /= 2; return; case DDSType.DXT1a: this.Header.PixelFormat.Flags |= DDSPixelFormatFlags.DDPF_FOURCC; this.Header.PixelFormat.FourCC = DDSPixelFormatFourCC.DXT1; this.Header.Pitch /= 2; return; case DDSType.DXT3: this.Header.PixelFormat.Flags |= DDSPixelFormatFlags.DDPF_FOURCC; this.Header.PixelFormat.FourCC = DDSPixelFormatFourCC.DXT3; this.Header.Pitch /= 2; return; case DDSType.DXT5: this.Header.PixelFormat.Flags |= DDSPixelFormatFlags.DDPF_FOURCC; this.Header.PixelFormat.FourCC = DDSPixelFormatFourCC.DXT5; this.Header.Pitch /= 2; return; case DDSType.b4444: case DDSType.b565: break; case DDSType.b1555: this.Header.PixelFormat.Flags |= DDSPixelFormatFlags.DDPF_RGB | DDSPixelFormatFlags.DDPF_ALPHAPIXELS; this.Header.PixelFormat.RGBBitCount = 0x10; this.Header.PixelFormat.BitMaskRed = 0x7c00; this.Header.PixelFormat.BitMaskGreen = 0x3e0; this.Header.PixelFormat.BitMaskBlue = 0x1f; this.Header.PixelFormat.BitMaskRGBAlpha = 0x8000; break; case DDSType.ARGB: this.Header.PixelFormat.Flags |= DDSPixelFormatFlags.DDPF_RGB | DDSPixelFormatFlags.DDPF_ALPHAPIXELS; this.Header.PixelFormat.RGBBitCount = 0x20; this.Header.PixelFormat.BitMaskRed = 0xff0000; this.Header.PixelFormat.BitMaskGreen = 0xff00; this.Header.PixelFormat.BitMaskBlue = 0xff; this.Header.PixelFormat.BitMaskRGBAlpha = 0xff000000; this.Header.Pitch *= 4; return; default: return; } }
public File(byte[] source, bool isNormalMap = false) { header = new byte[0x80]; Array.Copy(source, header, 0x80); Header = new Header(header); content = new byte[source.Length - 0x80]; Array.Copy(source, 0x80, content, 0x00, content.Length); DDSType = GetDDSType(); ARGBMask mask = new ARGBMask(new uint[] { Header.DDSPF.ABitMask, Header.DDSPF.RBitMask, Header.DDSPF.GBitMask, Header.DDSPF.BBitMask }); switch (DDSType) { case DDS.DDSType.A8R8G8B8: Content = new ColorA8R8G8B8(content, mask, isNormalMap); break; case DDS.DDSType.R8G8B8: Content = new ColorR8G8B8(content, mask, isNormalMap); break; case DDS.DDSType.A1R5G5B5: Content = new ColorA1R5G5B5(content, mask, isNormalMap); break; case DDS.DDSType.A4R4G4B4: Content = new ColorA4R4G4B4(content, mask, isNormalMap); break; case DDS.DDSType.R5G6B5: Content = new ColorR5G6B5(content, mask, isNormalMap); break; case DDS.DDSType.R5G5B5: Content = new ColorR5G5B5(content, mask, isNormalMap); break; case DDS.DDSType.DXT1: Content = new ColorDXT1(content, null, isNormalMap); break; case DDS.DDSType.DXT3: Content = new ColorDXT3(content, null, isNormalMap); break; case DDS.DDSType.DXT5: Content = new ColorDXT5(content, null, isNormalMap); break; } }
public Image GetImage(DDSType Type) { Image img = new Bitmap(this.Header.Width, this.Header.Height); DDSType type = Type; if (type != DDSType.DXT1) { if (type != DDSType.ARGB) { return(img); } } else { this.blockDecompressImageDXT1((ulong)this.Header.Width, (ulong)this.Header.Height, this.Data, img); return(img); } this.rgbaDecompressImage(img); return(img); }
/// <summary> /// Gets the raw Colorset data list from a dds file. /// </summary> /// <param name="ddsFileDirectory"></param> /// <returns></returns> public static List <Half> GetColorsetDataFromDDS(DirectoryInfo ddsFileDirectory) { using (var br = new BinaryReader(File.OpenRead(ddsFileDirectory.FullName))) { // Check DDS type br.BaseStream.Seek(84, SeekOrigin.Begin); var texType = br.ReadInt32(); XivTexFormat textureType; if (DDSType.ContainsKey(texType)) { textureType = DDSType[texType]; } else { throw new Exception($"DDS Type ({texType}) not recognized. Expecting A16B16G16R16F."); } if (textureType != XivTexFormat.A16B16G16R16F) { throw new Exception($"Incorrect file type. Expected: A16B16G16R16F Given: {textureType}"); } var colorSetData = new List <Half>(256); // skip DDS header br.BaseStream.Seek(128, SeekOrigin.Begin); // color data is always 512 (4w x 16h = 64 x 8bpp = 512) // this reads 256 ushort values which is 256 x 2 = 512 for (var i = 0; i < 256; i++) { colorSetData.Add((new Half(br.ReadUInt16()))); } return(colorSetData); } }
/// <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 async Task <byte[]> DDStoTexData(XivTex xivTex, IItem item, DirectoryInfo ddsFileDirectory) { 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 = 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); 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}"); } }
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); }
/// <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); }
/// <summary> /// Retrieves the texture format information from a DDS file stream. /// </summary> /// <param name="ddsStream"></param> /// <returns></returns> public XivTexFormat GetDDSTexFormat(BinaryReader ddsStream) { ddsStream.BaseStream.Seek(12, SeekOrigin.Begin); var newHeight = ddsStream.ReadInt32(); var newWidth = ddsStream.ReadInt32(); ddsStream.ReadBytes(8); var newMipCount = ddsStream.ReadInt32(); if (newHeight % 2 != 0 || newWidth % 2 != 0) { throw new Exception("Resolution must be a multiple of 2"); } ddsStream.BaseStream.Seek(80, SeekOrigin.Begin); var textureFlags = ddsStream.ReadInt32(); var texType = ddsStream.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 = ddsStream.ReadInt32(); if (bpp == 32) { textureType = XivTexFormat.A8R8G8B8; } else { var red = ddsStream.ReadInt32(); switch (red) { case 31744: textureType = XivTexFormat.A1R5G5B5; break; case 3840: textureType = XivTexFormat.A4R4G4B4; break; } } break; } return(textureType); }
public Image GetImage(DDSType Type) { Image img = new Bitmap(this.Header.Width, this.Header.Height); DDSType type = Type; if (type != DDSType.DXT1) { if (type != DDSType.ARGB) { return img; } } else { this.blockDecompressImageDXT1((ulong) this.Header.Width, (ulong) this.Header.Height, this.Data, img); return img; } this.rgbaDecompressImage(img); return img; }
/// <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 long TexDDSImporter(XivTex xivTex, IItem item, DirectoryInfo ddsFileDirectory) { int lineNum = 0, offset = 0; var inModList = false; ModInfo modInfo = null; var dat = new Dat(_gameDirectory); if (File.Exists(ddsFileDirectory.FullName)) { // Check if the texture being imported has been imported before using (var sr = new StreamReader(_modListDirectory.FullName)) { string line; while ((line = sr.ReadLine()) != null) { modInfo = JsonConvert.DeserializeObject <ModInfo>(line); if (modInfo.fullPath.Equals(xivTex.TextureTypeAndPath.Path)) { inModList = true; break; } lineNum++; } } 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 newTex = new List <byte>(); var uncompressedLength = (int)new FileInfo(ddsFileDirectory.FullName).Length - 128; 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); offset = dat.WriteToDat(newTex, modInfo, inModList, xivTex.TextureTypeAndPath.Path, item.ItemCategory, item.Name, lineNum, xivTex.TextureTypeAndPath.DataFile); } else { throw new Exception($"Incorrect file type. Expected: {xivTex.TextureFormat} Given: {textureType}"); } } } else { throw new IOException($"Could not find file: {ddsFileDirectory.FullName}"); } return(offset); }
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); }
/// <summary> /// Imports a ColorSet file /// </summary> /// <param name="xivMtrl">The XivMtrl data of the original</param> /// <param name="ddsFileDirectory">The dds directory of the new ColorSet</param> /// <param name="item">The item</param> /// <param name="source">The source importing the file</param> /// <returns>The new offset</returns> public async Task <int> TexColorImporter(XivMtrl xivMtrl, DirectoryInfo ddsFileDirectory, IItem item, string source, XivLanguage lang) { var colorSetData = new List <Half>(); byte[] colorSetExtraData = null; using (var br = new BinaryReader(File.OpenRead(ddsFileDirectory.FullName))) { // Check DDS type br.BaseStream.Seek(84, SeekOrigin.Begin); var texType = br.ReadInt32(); XivTexFormat textureType; if (DDSType.ContainsKey(texType)) { textureType = DDSType[texType]; } else { throw new Exception($"DDS Type ({texType}) not recognized. Expecting A16B16G16R16F."); } if (textureType != XivTexFormat.A16B16G16R16F) { throw new Exception($"Incorrect file type. Expected: A16B16G16R16F Given: {textureType}"); } // Skip past rest of the DDS header br.BaseStream.Seek(128, SeekOrigin.Begin); // color data is always 512 (4w x 16h = 64 x 8bpp = 512) // this reads 256 ushort values which is 256 x 2 = 512 for (var i = 0; i < 256; i++) { colorSetData.Add(new Half(br.ReadUInt16())); } } // If the colorset size is 544, it contains extra data that must be imported if (xivMtrl.ColorSetDataSize == 544) { var flagsPath = Path.Combine(Path.GetDirectoryName(ddsFileDirectory.FullName), (Path.GetFileNameWithoutExtension(ddsFileDirectory.FullName) + ".dat")); if (File.Exists(flagsPath)) { // The extra data after the colorset is always 32 bytes // This reads 16 ushort values which is 16 x 2 = 32 colorSetExtraData = File.ReadAllBytes(flagsPath); // If for whatever reason there is a .dat file but it's missing data if (colorSetExtraData.Length != 32) { // Set all dye modifiers to 0 (undyeable) colorSetExtraData = new byte[32]; } } else { // If .dat file is missing set all values to 0 (undyeable) colorSetExtraData = new byte[32]; } } // Replace the color set data with the imported data xivMtrl.ColorSetData = colorSetData; xivMtrl.ColorSetExtraData = colorSetExtraData; var mtrl = new Mtrl(_gameDirectory, xivMtrl.TextureTypePathList[0].DataFile, lang); return(await mtrl.ImportMtrl(xivMtrl, item, source)); }
public File(uint width, uint height, int mipMaps, DDSType type, byte[] source, bool isNormalMap = false) { header = new byte[0x80]; FileHelper.SetString(DDS_MAGIC, 0, header); Header = new Header(header); Header.Size = 0x7C; Header.Flags = DDSFlags.CAPS | DDSFlags.HEIGHT | DDSFlags.WIDTH | DDSFlags.PIXELFORMAT; Header.Height = height; Header.Width = width; Header.Caps = DDSCaps.TEXTURE; Header.DDSPF.Size = 0x20; switch (type) { case DDS.DDSType.A8R8G8B8: Header.DDSPF.Flags = DDSPixelFormatFlags.ALPHAPIXELS | DDSPixelFormatFlags.RGB; Header.DDSPF.BitCount = 0x20; Header.DDSPF.RBitMask = 0x00FF0000; Header.DDSPF.GBitMask = 0x0000FF00; Header.DDSPF.BBitMask = 0x000000FF; Header.DDSPF.ABitMask = 0xFF000000; break; case DDS.DDSType.A1R5G5B5: Header.DDSPF.Flags = DDSPixelFormatFlags.ALPHAPIXELS | DDSPixelFormatFlags.RGB; Header.DDSPF.BitCount = 0x10; Header.DDSPF.RBitMask = 0x00007C00; Header.DDSPF.GBitMask = 0x000003E0; Header.DDSPF.BBitMask = 0x0000001F; Header.DDSPF.ABitMask = 0x00008000; break; case DDS.DDSType.A4R4G4B4: Header.DDSPF.Flags = DDSPixelFormatFlags.ALPHAPIXELS | DDSPixelFormatFlags.RGB; Header.DDSPF.BitCount = 0x10; Header.DDSPF.RBitMask = 0x00000F00; Header.DDSPF.GBitMask = 0x000000F0; Header.DDSPF.BBitMask = 0x0000000F; Header.DDSPF.ABitMask = 0x0000F000; break; case DDS.DDSType.R8G8B8: Header.DDSPF.Flags = DDSPixelFormatFlags.RGB; Header.DDSPF.BitCount = 0x18; Header.DDSPF.RBitMask = 0x00FF0000; Header.DDSPF.GBitMask = 0x0000FF00; Header.DDSPF.BBitMask = 0x000000FF; Header.DDSPF.ABitMask = 0x00000000; break; case DDS.DDSType.R5G6B5: Header.DDSPF.Flags = DDSPixelFormatFlags.RGB; Header.DDSPF.BitCount = 0x10; Header.DDSPF.RBitMask = 0x0000F800; Header.DDSPF.GBitMask = 0x000007E0; Header.DDSPF.BBitMask = 0x0000001F; Header.DDSPF.ABitMask = 0x00000000; break; case DDS.DDSType.R5G5B5: Header.DDSPF.Flags = DDSPixelFormatFlags.RGB; Header.DDSPF.BitCount = 0x10; Header.DDSPF.RBitMask = 0x00007C00; Header.DDSPF.GBitMask = 0x000003E0; Header.DDSPF.BBitMask = 0x0000001F; Header.DDSPF.ABitMask = 0x00000000; break; case DDS.DDSType.DXT1: Header.DDSPF.Flags = DDSPixelFormatFlags.FOURCC; Header.DDSPF.FourCC = "DXT1"; break; case DDS.DDSType.DXT3: Header.DDSPF.Flags = DDSPixelFormatFlags.FOURCC; Header.DDSPF.FourCC = "DXT3"; break; case DDS.DDSType.DXT5: Header.DDSPF.Flags = DDSPixelFormatFlags.FOURCC; Header.DDSPF.FourCC = "DXT5"; break; } if (mipMaps > 1) { Header.Flags |= DDSFlags.MIPMAPCOUNT | DDSFlags.LINEARSIZE; Header.PitchOrLinearSize = width * height * (Header.DDSPF.BitCount >> 3); Header.MipMapCount = (uint)mipMaps; Header.Caps |= DDSCaps.COMPLEX | DDSCaps.MIPMAP; } ARGBMask mask = new ARGBMask(new uint[] { Header.DDSPF.ABitMask, Header.DDSPF.RBitMask, Header.DDSPF.GBitMask, Header.DDSPF.BBitMask }); switch (type) { case DDS.DDSType.A8R8G8B8: Content = new ColorA8R8G8B8(mask, isNormalMap); break; case DDS.DDSType.A1R5G5B5: Content = new ColorA1R5G5B5(mask, isNormalMap); break; case DDS.DDSType.A4R4G4B4: Content = new ColorA4R4G4B4(mask, isNormalMap); break; case DDS.DDSType.R8G8B8: Content = new ColorR8G8B8(mask, isNormalMap); break; case DDS.DDSType.R5G6B5: Content = new ColorR5G6B5(mask, isNormalMap); break; case DDS.DDSType.R5G5B5: Content = new ColorR5G5B5(mask, isNormalMap); break; case DDS.DDSType.DXT1: Content = new ColorDXT1(mask, isNormalMap); break; case DDS.DDSType.DXT3: Content = new ColorDXT3(mask, isNormalMap); break; case DDS.DDSType.DXT5: Content = new ColorDXT5(mask, isNormalMap); break; } content = Content.CompressColor(source, width, height, mipMaps); }