public static Bitmap toBitmap(byte[] d, int width, int height, DDSFormat format) { byte[] pixels = new byte[width * height * 4]; if (format == DDSFormat.DXT1) { decodeDXT1(pixels, d, width, height); } if (format == DDSFormat.DXT5) { decodeDXT5(pixels, d, width, height); } Bitmap bmp = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb); BitmapData bmpData = bmp.LockBits( new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly, bmp.PixelFormat); Marshal.Copy(pixels, 0, bmpData.Scan0, pixels.Length); bmp.UnlockBits(bmpData); return(bmp); }
/// <summary> /// Creates a DDS header from a set of information. /// </summary> /// <param name="Mips">Number of mipmaps.</param> /// <param name="Height">Height of top mipmap.</param> /// <param name="Width">Width of top mipmap.</param> /// <param name="surfaceformat">Format header represents.</param> public DDS_Header(int Mips, int Height, int Width, DDSFormat surfaceformat, DXGI_FORMAT dx10Format = DXGI_FORMAT.DXGI_FORMAT_UNKNOWN) { dwSize = 124; dwFlags = DDSdwFlags.DDSD_CAPS | DDSdwFlags.DDSD_HEIGHT | DDSdwFlags.DDSD_WIDTH | DDSdwFlags.DDSD_PIXELFORMAT | (Mips != 1 ? DDSdwFlags.DDSD_MIPMAPCOUNT : 0); this.Width = Width; this.Height = Height; dwCaps = DDSdwCaps.DDSCAPS_TEXTURE | (Mips == 1 ? 0 : DDSdwCaps.DDSCAPS_COMPLEX | DDSdwCaps.DDSCAPS_MIPMAP); dwMipMapCount = Mips == 1 ? 1 : Mips; ddspf = new DDS_PIXELFORMAT(surfaceformat); if (surfaceformat == DDSFormat.DDS_DX10 || surfaceformat == DDSFormat.DDS_ARGB_32F) { if (surfaceformat == DDSFormat.DDS_ARGB_32F) { dx10Format = DXGI_FORMAT.DXGI_FORMAT_R32G32B32A32_FLOAT; } DX10_DXGI_AdditionalHeader = new DDS_DXGI_DX10_Additional { dxgiFormat = dx10Format, resourceDimension = D3D10_RESOURCE_DIMENSION.DDS_DIMENSION_TEXTURE2D, miscFlag = DDS_DXGI_DX10_Additional.D3D10_RESOURCE_MISC_FLAGS.D3D10_RESOURCE_MISC_GENERATE_MIPS, miscFlags2 = DXGI_MiscFlags.DDS_ALPHA_MODE_UNKNOWN, arraySize = 1 }; } }
public void extractTextureToDDS(string outputFile, string packagePath, int exportID) { Package package = new Package(packagePath); Texture texture = new Texture(package, exportID, package.getExportData(exportID)); while (texture.mipMapsList.Exists(s => s.storageType == Texture.StorageTypes.empty)) { texture.mipMapsList.Remove(texture.mipMapsList.First(s => s.storageType == Texture.StorageTypes.empty)); } List <DDSImage.MipMap> mipmaps = new List <DDSImage.MipMap>(); DDSFormat format = DDSImage.convertFormat(texture.properties.getProperty("Format").valueName); for (int i = 0; i < texture.mipMapsList.Count; i++) { byte[] data = texture.getMipMapDataByIndex(i); if (data == null) { MessageBox.Show("Failed to extract to DDS file. Broken game files!"); return; } mipmaps.Add(new DDSImage.MipMap(data, format, texture.mipMapsList[i].width, texture.mipMapsList[i].height)); } DDSImage dds = new DDSImage(mipmaps); if (File.Exists(outputFile)) { File.Delete(outputFile); } using (FileStream fs = new FileStream(outputFile, FileMode.CreateNew, FileAccess.Write)) { dds.SaveDDSImage(fs); } }
/// <summary> /// Gets maximum number of channels a format can contain. /// NOTE: This likely isn't actually the max number. i.e. None exceed four, but some are only one or two channels. /// </summary> /// <param name="format">Format to channel count.</param> /// <returns>Max number of channels supported.</returns> static int MaxNumberOfChannels(DDSFormat format) { int numChannels = 4; switch (format) { case DDSFormat.DDS_A8: case DDSFormat.DDS_ATI1: case DDSFormat.DDS_G8_L8: numChannels = 1; break; case DDSFormat.DDS_A8L8: case DDSFormat.DDS_ATI2_3Dc: case DDSFormat.DDS_G16_R16: case DDSFormat.DDS_V8U8: numChannels = 2; break; case DDSFormat.DDS_R5G6B5: case DDSFormat.DDS_RGB_8: numChannels = 3; break; } return(numChannels); }
/// <summary> /// Searches for a format within a string. Good for automatic file naming. /// </summary> /// <param name="stringWithFormatInIt">String containing format somewhere in it.</param> /// <returns>Format in string, or UNKNOWN otherwise.</returns> public static DDSFormat FindFormatInString(string stringWithFormatInIt) { DDSFormat detectedFormat = DDSFormat.Unknown; foreach (var formatName in Enum.GetNames(typeof(DDSFormat))) { string actualFormat = formatName.Replace("DDS_", ""); bool check = stringWithFormatInIt.Contains(actualFormat, StringComparison.OrdinalIgnoreCase); if (actualFormat.Contains("3Dc")) { check = stringWithFormatInIt.Contains("3dc", StringComparison.OrdinalIgnoreCase) || stringWithFormatInIt.Contains("ati2", StringComparison.OrdinalIgnoreCase); } else if (actualFormat == "A8L8") { check = stringWithFormatInIt.Contains("L8", StringComparison.OrdinalIgnoreCase) && !stringWithFormatInIt.Contains("G", StringComparison.OrdinalIgnoreCase); } else if (actualFormat == "G8_L8") { check = !stringWithFormatInIt.Contains("A", StringComparison.OrdinalIgnoreCase) && stringWithFormatInIt.Contains("G8", StringComparison.OrdinalIgnoreCase); } else if (actualFormat.Contains("ARGB")) { check = stringWithFormatInIt.Contains("A8R8G8B8", StringComparison.OrdinalIgnoreCase) || stringWithFormatInIt.Contains("ARGB", StringComparison.OrdinalIgnoreCase); } if (check) { detectedFormat = (DDSFormat)Enum.Parse(typeof(DDSFormat), formatName); break; } } return(detectedFormat); }
public DDSPreview(byte[] data) { if (BitConverter.ToUInt32(data, 0) != DDSMagic) { throw new FormatException("Invalid DDS Magic Number"); } if (BitConverter.ToUInt32(data, 4) != 0x7C) { throw new FormatException("Invalid header size"); } DDSFlags = BitConverter.ToUInt32(data, 8); if ((DDSFlags & 0x1) != 0x1 || (DDSFlags & 0x2) != 0x2 || (DDSFlags & 0x4) != 0x4 || (DDSFlags & 0x1000) != 0x1000) { throw new FormatException("Invalid DDS Flags"); } mips = (DDSFlags & 0x20000) == 0x20000; Height = BitConverter.ToUInt32(data, 12); Width = BitConverter.ToUInt32(data, 16); // Skip pitch and depth, unimportant NumMips = BitConverter.ToUInt32(data, 28); uint pxformat = BitConverter.ToUInt32(data, 84); Format = GetDDSFormat(pxformat); imgData = new byte[data.Length - 0x80]; Array.Copy(data, 0x80, imgData, 0, imgData.Length); pfFlags = BitConverter.ToUInt32(data, 0x50); fourCC = BitConverter.ToUInt32(data, 0x54); rgbBitCount = BitConverter.ToUInt32(data, 0x58); rBitMask = BitConverter.ToUInt32(data, 0x5C); gBitMask = BitConverter.ToUInt32(data, 0x60); bBitMask = BitConverter.ToUInt32(data, 0x64); aBitMask = BitConverter.ToUInt32(data, 0x68); FormatString = GetFormat(); switch (FormatString) { case "DXT1": BPP = 0.5F; stdDDS = true; compressed = true; break; case "DXT5": BPP = 1F; stdDDS = true; compressed = true; break; case "V8U8": BPP = 2F; stdDDS = true; compressed = false; break; case "ATI2": BPP = 1F; stdDDS = true; compressed = true; break; case "A8B8G8R8": case "A8R8G8B8": BPP = 4F; stdDDS = false; compressed = false; break; case "B8G8R8": case "R8G8B8": BPP = 3F; stdDDS = false; compressed = false; break; default: BPP = 1; stdDDS = false; compressed = false; break; } }
/// <summary> /// Gets file extension of supported surface formats. /// Doesn't include preceding dot. /// </summary> /// <param name="format">Format to get file extension for.</param> /// <returns>File extension without dot.</returns> static string GetExtensionOfFormat(DDSFormat format) { string formatString = format.ToString().ToLowerInvariant(); if (formatString.Contains('_')) { formatString = "dds"; } return(formatString); }
static FourCC ParseFormatToFourCC(DDSFormat format) { if (Enum.IsDefined(typeof(FourCC), (int)format)) { return((FourCC)format); } else { return(FourCC.Unknown); } }
public static double getBytesPerPixel(DDSFormat ddsFormat) { switch (ddsFormat) { case DDSFormat.DXT1: return(0.5); case DDSFormat.DXT5: case DDSFormat.ATI2: return(1); case DDSFormat.V8U8: return(2); } throw new Exception("invalid texture format"); }
private void Write_DDS_PIXELFORMAT(DDSFormat p, Stream s) { DDS_PIXELFORMAT fmt = getDDSPixelFormat(p); s.WriteInt32(DDS_PIXELFORMAT_size); s.WriteUInt32(fmt.dwFlags); s.WriteUInt32(fmt.dwFourCC); s.WriteUInt32(fmt.dwRGBBitCount); s.WriteUInt32(fmt.dwRBitMask); s.WriteUInt32(fmt.dwGBitMask); s.WriteUInt32(fmt.dwBBitMask); s.WriteUInt32(fmt.dwABitMask); }
public MipMap(byte[] data, DDSFormat format, int w, int h) { long requiredSize = (long)(w * h * getBytesPerPixel(format)); if (data.Length != requiredSize) { throw new InvalidDataException("Data size is not valid for selected format.\nActual: " + data.Length + " bytes\nRequired: " + requiredSize + " bytes"); } this.data = data; ddsFormat = format; width = w; height = h; }
public DDSImage(string ddsFileName) { using (FileStream ddsStream = File.OpenRead(ddsFileName)) { using (BinaryReader r = new BinaryReader(ddsStream)) { dwMagic = r.ReadInt32(); if (dwMagic != 0x20534444) { throw new Exception("This is not a DDS!"); } Read_DDS_HEADER(header, r); if (((header.ddspf.dwFlags & DDPF_FOURCC) != 0) && (header.ddspf.dwFourCC == FOURCC_DX10 /*DX10*/)) { throw new Exception("DX10 not supported yet!"); } int mipMapCount = 1; if ((header.dwFlags & DDSD_MIPMAPCOUNT) != 0) { mipMapCount = header.dwMipMapCount; } mipMaps = new MipMap[mipMapCount]; ddsFormat = getFormat(); double bytePerPixel = getBytesPerPixel(ddsFormat); for (int i = 0; i < mipMapCount; i++) { int w = (int)(header.dwWidth / Math.Pow(2, i)); int h = (int)(header.dwHeight / Math.Pow(2, i)); if (ddsFormat == DDSFormat.DXT1 || ddsFormat == DDSFormat.DXT5) { w = (w < 4) ? 4 : w; h = (h < 4) ? 4 : h; } int mipMapBytes = (int)(w * h * bytePerPixel); mipMaps[i] = new MipMap(r.ReadBytes(mipMapBytes), ddsFormat, w, h); } } } }
private Bitmap readBlockImage(byte[] imgData, int w, int h) { switch (header.ddspf.dwFourCC) { case FOURCC_DXT1: ddsFormat = DDSFormat.DXT1; return(UncompressDXT1(imgData, w, h)); case FOURCC_DXT5: ddsFormat = DDSFormat.DXT5; return(UncompressDXT5(imgData, w, h)); default: break; } throw new Exception("invalid texture format"); }
/// <summary> /// Gets block size of DDS format. /// Number of channels if not compressed. /// 1 if not a DDS format. /// </summary> /// <param name="format">DDS format to test.</param> /// <param name="componentSize">Size of channel components in bytes. e.g. 16bit = 2.</param> /// <returns>Number of blocks/channels in format.</returns> static int GetBlockSize(DDSFormat format, int componentSize = 1) { int blocksize = 1; switch (format) { case DDSFormat.DDS_ATI1: case DDSFormat.DDS_DXT1: blocksize = 8; break; case DDSFormat.DDS_DXT2: case DDSFormat.DDS_DXT3: case DDSFormat.DDS_DXT4: case DDSFormat.DDS_DXT5: case DDSFormat.DDS_ATI2_3Dc: case DDSFormat.DDS_DX10: blocksize = 16; break; case DDSFormat.DDS_V8U8: case DDSFormat.DDS_A8L8: case DDSFormat.DDS_ARGB_4: blocksize = 2; break; case DDSFormat.DDS_ARGB_8: case DDSFormat.DDS_ABGR_8: case DDSFormat.DDS_G16_R16: blocksize = 4; break; case DDSFormat.DDS_RGB_8: blocksize = 3; break; case DDSFormat.DDS_ARGB_32F: blocksize = 16; break; case DDSFormat.DDS_CUSTOM: blocksize = 4 * componentSize; break; } return(blocksize); }
public static byte[] CreateDDS(string input, DDSFormat format, MipmapMethod mipm, bool slow, bool flip) { LoadLibraries(); using (var stream = new MemoryStream()) { using (var compress = new Compressor()) { compress.Input.GenerateMipmaps = false; List <TeximpNet.Surface> toDispose = null; if (mipm == MipmapMethod.None) { using (var surface = TeximpNet.Surface.LoadFromFile(input)) { if (flip) { surface.FlipVertically(); } compress.Input.SetData(surface); } } else { var mips = GenerateMipmapsRGBA(input, mipm, flip); compress.Input.SetTextureLayout(TextureType.Texture2D, mips[0].Width, mips[0].Height); for (int i = 0; i < mips.Count; i++) { compress.Input.SetMipmapData(mips[i], i); } toDispose = mips; } compress.Compression.Format = (CompressionFormat)format; compress.Compression.Quality = slow ? CompressionQuality.Production : CompressionQuality.Normal; compress.Compression.SetBGRAPixelFormat(); compress.Process(stream); if (toDispose != null) { foreach (var sfc in toDispose) { sfc.Dispose(); } } } return(stream.ToArray()); } }
public static Bitmap ToBitmap(byte[] imgData, DDSFormat ddsFormat, int w, int h) { switch (ddsFormat) { case DDSFormat.DXT1: return(UncompressDXT1(imgData, w, h)); case DDSFormat.DXT5: return(UncompressDXT5(imgData, w, h)); case DDSFormat.V8U8: return(UncompressV8U8(imgData, w, h)); case DDSFormat.ATI2: return(UncompressATI2(imgData, w, h)); case DDSFormat.G8: return(ViewG8(imgData, w, h)); case DDSFormat.ARGB: return(View32Bit(imgData, w, h)); } throw new Exception("invalid texture format " + ddsFormat); }
/// <summary> /// Determines if format is a block compressed format. /// </summary> /// <param name="format">DDS Surface Format.</param> /// <returns>True if block compressed.</returns> static bool IsBlockCompressed(DDSFormat format) { switch (format) { case DDSFormat.DDS_ATI1: case DDSFormat.DDS_DXT1: case DDSFormat.DDS_DXT2: case DDSFormat.DDS_DXT3: case DDSFormat.DDS_DXT4: case DDSFormat.DDS_DXT5: case DDSFormat.DDS_ATI2_3Dc: case DDSFormat.DDS_DX10: return(true); default: return(false); } }
public DDSPreview(byte[] data) { if (BitConverter.ToUInt32(data, 0) != DDSMagic) throw new FormatException("Invalid DDS Magic Number"); if (BitConverter.ToUInt32(data, 4) != 0x7C) throw new FormatException("Invalid header size"); DDSFlags = BitConverter.ToUInt32(data, 8); if ((DDSFlags & 0x1) != 0x1 || (DDSFlags & 0x2) != 0x2 || (DDSFlags & 0x4) != 0x4 || (DDSFlags & 0x1000) != 0x1000) throw new FormatException("Invalid DDS Flags"); mips = (DDSFlags & 0x20000) == 0x20000; Height = BitConverter.ToUInt32(data, 12); Width = BitConverter.ToUInt32(data, 16); // Skip pitch and depth, unimportant NumMips = BitConverter.ToUInt32(data, 28); uint pxformat = BitConverter.ToUInt32(data, 84); Format = GetDDSFormat(pxformat); imgData = new byte[data.Length - 0x80]; Array.Copy(data, 0x80, imgData, 0, imgData.Length); pfFlags = BitConverter.ToUInt32(data, 0x50); fourCC = BitConverter.ToUInt32(data, 0x54); rgbBitCount = BitConverter.ToUInt32(data, 0x58); rBitMask = BitConverter.ToUInt32(data, 0x5C); gBitMask = BitConverter.ToUInt32(data, 0x60); bBitMask = BitConverter.ToUInt32(data, 0x64); aBitMask = BitConverter.ToUInt32(data, 0x68); FormatString = GetFormat(); switch (FormatString) { case "DXT1": BPP = 0.5F; stdDDS = true; compressed = true; break; case "DXT5": BPP = 1F; stdDDS = true; compressed = true; break; case "V8U8": BPP = 2F; stdDDS = true; compressed = false; break; case "ATI2": BPP = 1F; stdDDS = true; compressed = true; break; case "A8B8G8R8": case "A8R8G8B8": BPP = 4F; stdDDS = false; compressed = false; break; case "B8G8R8": case "R8G8B8": BPP = 3F; stdDDS = false; compressed = false; break; default: BPP = 1; stdDDS = false; compressed = false; break; } }
public static double getBytesPerPixel(DDSFormat ddsFormat) { switch (ddsFormat) { case DDSFormat.DXT1: return(0.5); case DDSFormat.DXT3: case DDSFormat.DXT5: case DDSFormat.ATI2: case DDSFormat.G8: return(1); case DDSFormat.V8U8: return(2); case DDSFormat.ARGB: return(4); case DDSFormat.RGB: return(3); default: throw new Exception("invalid texture format " + ddsFormat); } }
public static PngBitmapEncoder ToPng(byte[] imgData, DDSFormat ddsFormat, int w, int h) { switch (ddsFormat) { case DDSFormat.DXT1: return(DXT1ToPng(imgData, w, h)); case DDSFormat.DXT5: return(DXT5ToPng(imgData, w, h)); case DDSFormat.ATI2: return(ATI2ToPng(imgData, w, h)); case DDSFormat.V8U8: return(V8U8ToPng(imgData, w, h)); case DDSFormat.G8: return(G8ToPng(imgData, w, h)); case DDSFormat.ARGB: return(RGBAToPng(imgData, w, h)); case DDSFormat.RGB: return(RGBToPng(imgData, w, h)); default: throw new Exception("invalid texture format " + ddsFormat); } }
public static Bitmap ToBitmap(byte[] imgData, DDSFormat ddsFormat, int w, int h) { switch (ddsFormat) { case DDSFormat.DXT1: return(DXT1ToBitmap(imgData, w, h)); case DDSFormat.DXT5: return(DXT5ToBitmap(imgData, w, h)); case DDSFormat.ATI2: return(ATI2ToBitmap(imgData, w, h)); case DDSFormat.V8U8: return(V8U8ToBitmap(imgData, w, h)); case DDSFormat.G8: return(ViewG8(imgData, w, h)); case DDSFormat.ARGB: return(View32Bit(imgData, w, h)); case DDSFormat.RGB: return(View24Bit(imgData, w, h)); default: throw new Exception("invalid texture format " + ddsFormat); } }
public void extractTextureToPng(string outputFile, string packagePath, int exportID) { Package package = new Package(packagePath); Texture texture = new Texture(package, exportID, package.getExportData(exportID)); DDSFormat format = DDSImage.convertFormat(texture.properties.getProperty("Format").valueName); Texture.MipMap mipmap = texture.getTopMipmap(); byte[] data = texture.getTopImageData(); if (data == null) { MessageBox.Show("Failed to extract to PNG file. Broken game files!"); return; } PngBitmapEncoder image = DDSImage.ToPng(data, format, mipmap.width, mipmap.height); if (File.Exists(outputFile)) { File.Delete(outputFile); } using (FileStream fs = new FileStream(outputFile, FileMode.CreateNew, FileAccess.Write)) { image.Save(fs); } }
internal static List <MipMap> LoadDDS(MemoryStream compressed, DDS_Header header, int desiredMaxDimension, DDSFormatDetails formatDetails) { MipMap[] MipMaps = null; int mipWidth = header.Width; int mipHeight = header.Height; DDSFormat format = header.Format; int estimatedMips = header.dwMipMapCount; int mipOffset = formatDetails.HeaderSize; int originalOffset = mipOffset; if (!EnsureMipInImage(compressed.Length, mipWidth, mipHeight, 4, formatDetails, out mipOffset)) // Update number of mips too { estimatedMips = 1; } if (estimatedMips == 0) { estimatedMips = EstimateNumMipMaps(mipWidth, mipHeight); } mipOffset = originalOffset; // Needs resetting after checking there's mips in this image. // Ensure there's at least 1 mipmap if (estimatedMips == 0) { estimatedMips = 1; } int orig_estimatedMips = estimatedMips; // Store original count for later (uncompressed only I think) // KFreon: Decide which mip to start loading at - going to just load a few mipmaps if asked instead of loading all, then choosing later. That's slow. if (desiredMaxDimension != 0 && estimatedMips > 1) { if (!EnsureMipInImage(compressed.Length, mipWidth, mipHeight, desiredMaxDimension, formatDetails, out mipOffset)) // Update number of mips too { throw new InvalidDataException($"Requested mipmap does not exist in this image. Top Image Size: {mipWidth}x{mipHeight}, requested mip max dimension: {desiredMaxDimension}."); } // Not the first mipmap. if (mipOffset > formatDetails.HeaderSize) { double divisor = mipHeight > mipWidth ? mipHeight / desiredMaxDimension : mipWidth / desiredMaxDimension; mipHeight = (int)(mipHeight / divisor); mipWidth = (int)(mipWidth / divisor); if (mipWidth == 0 || mipHeight == 0) // Reset as a dimension is too small to resize { mipHeight = header.Height; mipWidth = header.Width; mipOffset = formatDetails.HeaderSize; } else { // Update estimated mips due to changing dimensions. estimatedMips = EstimateNumMipMaps(mipWidth, mipHeight); } } else // The first mipmap { mipOffset = formatDetails.HeaderSize; } } // Move to requested mipmap compressed.Position = mipOffset; // Block Compressed texture chooser. Action <byte[], int, byte[], int, int, bool> DecompressBCBlock = formatDetails.BlockDecoder; MipMaps = new MipMap[estimatedMips]; int blockSize = formatDetails.BlockSize; // KFreon: Read mipmaps if (formatDetails.IsBlockCompressed) // Threading done in the decompression, not here. { for (int m = 0; m < estimatedMips; m++) { // KFreon: If mip is too small, skip out. This happens most often with non-square textures. I think it's because the last mipmap is square instead of the same aspect. // Don't do the mip size check here (<4) since we still need to have a MipMap object for those lower than this for an accurate count. if (mipWidth <= 0 || mipHeight <= 0) // Needed cos it doesn't throw when reading past the end for some reason. { break; } MipMap mipmap = ReadCompressedMipMap(compressed, mipWidth, mipHeight, mipOffset, formatDetails, DecompressBCBlock); MipMaps[m] = mipmap; mipOffset += (int)(mipWidth * mipHeight * (blockSize / 16d)); // Also put the division in brackets cos if the mip dimensions are high enough, the multiplications can exceed int.MaxValue) mipWidth /= 2; mipHeight /= 2; } } else { int startMip = orig_estimatedMips - estimatedMips; // UNCOMPRESSED - Can't really do threading in "decompression" so do it for the mipmaps. var action = new Action <int>(mipIndex => { // Calculate mipOffset and dimensions int offset, width, height; offset = GetMipOffset(mipIndex, formatDetails, header.Width, header.Height); double divisor = mipIndex == 0 ? 1d : 2 << (mipIndex - 1); // Divisor represents 2^mipIndex - Math.Pow seems very slow. width = (int)(header.Width / divisor); height = (int)(header.Height / divisor); MipMap mipmap = null; try { mipmap = ReadUncompressedMipMap(compressed, offset, width, height, header.ddspf, formatDetails); } catch (Exception e) { Debug.WriteLine(e.ToString()); } MipMaps[mipIndex] = mipmap; }); if (EnableThreading) { Parallel.For(startMip, orig_estimatedMips, new ParallelOptions { MaxDegreeOfParallelism = ThreadCount }, (mip, loopState) => { action(mip); }); } else { for (int i = startMip; i < orig_estimatedMips; i++) { action(i); } } } List <MipMap> mips = new List <MipMap>(MipMaps.Where(t => t != null)); if (mips.Count == 0) { throw new InvalidOperationException($"No mipmaps loaded. Estimated mips: {estimatedMips}, mip dimensions: {mipWidth}x{mipHeight}"); } return(mips); }
/// <summary> /// Details the given format. /// </summary> /// <param name="dxgiFormat">Optional DX10 format. Default = Unknown.</param> /// <param name="inFormat">Image Format.</param> public DDSFormatDetails(DDSFormat inFormat, DDS_Header.DXGI_FORMAT dxgiFormat = new DDS_Header.DXGI_FORMAT()) { Format = inFormat; DX10Format = dxgiFormat; BitCount = 8; { switch (inFormat) { case DDSFormat.DDS_G8_L8: case DDSFormat.DDS_A8: case DDSFormat.DDS_ATI1: BitCount = 8; break; case DDSFormat.DDS_A8L8: case DDSFormat.DDS_V8U8: case DDSFormat.DDS_ATI2_3Dc: BitCount = 16; break; case DDSFormat.DDS_ABGR_8: case DDSFormat.DDS_ARGB_8: case DDSFormat.DDS_DXT1: case DDSFormat.DDS_DXT2: case DDSFormat.DDS_DXT3: case DDSFormat.DDS_DXT4: case DDSFormat.DDS_DXT5: case DDSFormat.DDS_G16_R16: BitCount = 32; break; case DDSFormat.DDS_RGB_8: BitCount = 24; break; case DDSFormat.DDS_ARGB_32F: DX10Format = DDS_Header.DXGI_FORMAT.DXGI_FORMAT_R32G32B32A32_FLOAT; BitCount = 128; break; case DDSFormat.DDS_R5G6B5: BitCount = 16; break; case DDSFormat.DDS_ARGB_4: case DDSFormat.DDS_CUSTOM: case DDSFormat.DDS_DX10: BitCount = GetDX10BitCount(DX10Format); break; } } // Functions ReadByte = ReadByteFromByte; ReadUShort = ReadUShortFromByte; ReadFloat = ReadFloatFromByte; SetMaxValue = WriteByteMax; WriteColor = WriteByte; ReadUShortAsArray = ReadUShortFromByteAsArray; ReadFloatAsArray = ReadFloatFromByteOrUShortAsArray; if (ComponentSize == 2) { ReadByte = ReadByteFromUShort; ReadUShort = ReadUShortFromUShort; ReadFloat = ReadFloatFromUShort; SetMaxValue = WriteUShortMax; WriteColor = WriteUShort; ReadUShortAsArray = ReadUShortFromUShortAsArray; // Don't need ReadFloatAsArray set here, as it's shared between byte and ushort reading. } else if (ComponentSize == 4) { ReadByte = ReadByteFromFloat; ReadUShort = ReadUShortFromFloat; ReadFloat = ReadFloatFromFloat; SetMaxValue = WriteFloatMax; WriteColor = WriteFloat; ReadUShortAsArray = ReadUShortFromFloatAsArray; ReadFloatAsArray = ReadFloatFromFloatAsArray; } switch (inFormat) { case DDSFormat.DDS_ATI1: BlockEncoder = DDS_Encoders.CompressBC4Block; break; case DDSFormat.DDS_ATI2_3Dc: BlockEncoder = DDS_Encoders.CompressBC5Block; break; case DDSFormat.DDS_DX10: if (DX10Format.ToString().Contains("BC7")) { BlockEncoder = DDS_Encoders.CompressBC7Block; } else { BlockEncoder = DDS_Encoders.CompressBC6Block; } break; case DDSFormat.DDS_DXT1: BlockEncoder = DDS_Encoders.CompressBC1Block; break; case DDSFormat.DDS_DXT2: case DDSFormat.DDS_DXT3: BlockEncoder = DDS_Encoders.CompressBC2Block; break; case DDSFormat.DDS_DXT4: case DDSFormat.DDS_DXT5: BlockEncoder = DDS_Encoders.CompressBC3Block; break; } switch (inFormat) { case DDSFormat.DDS_DXT1: BlockDecoder = DDS_Decoders.DecompressBC1Block; break; case DDSFormat.DDS_DXT2: case DDSFormat.DDS_DXT3: BlockDecoder = DDS_Decoders.DecompressBC2Block; break; case DDSFormat.DDS_DXT4: case DDSFormat.DDS_DXT5: BlockDecoder = DDS_Decoders.DecompressBC3Block; break; case DDSFormat.DDS_ATI1: BlockDecoder = DDS_Decoders.DecompressATI1Block; break; case DDSFormat.DDS_ATI2_3Dc: BlockDecoder = DDS_Decoders.DecompressATI2Block; break; case DDSFormat.DDS_DX10: if (DX10Format.ToString().Contains("BC7")) { BlockDecoder = DDS_Decoders.DecompressBC7Block; } else { BlockDecoder = DDS_Decoders.DecompressBC6Block; } break; } }
private DDS_PIXELFORMAT getDDSPixelFormat(DDSFormat format) { DDS_PIXELFORMAT pixelFormat = new DDS_PIXELFORMAT(); switch (format) { case DDSFormat.DXT1: pixelFormat.dwFlags = DDPF_FOURCC; pixelFormat.dwFourCC = FOURCC_DXT1; break; case DDSFormat.DXT3: pixelFormat.dwFlags = DDPF_FOURCC; pixelFormat.dwFourCC = FOURCC_DXT3; break; case DDSFormat.DXT5: pixelFormat.dwFlags = DDPF_FOURCC; pixelFormat.dwFourCC = FOURCC_DXT5; break; case DDSFormat.ATI2: pixelFormat.dwFlags = DDPF_FOURCC; pixelFormat.dwFourCC = FOURCC_ATI2; break; case DDSFormat.V8U8: pixelFormat.dwFlags = 0x80000; pixelFormat.dwRGBBitCount = 0x10; pixelFormat.dwRBitMask = 0xFF; pixelFormat.dwGBitMask = 0xFF00; pixelFormat.dwBBitMask = 0x00; pixelFormat.dwABitMask = 0x00; break; case DDSFormat.G8: pixelFormat.dwFlags = DDPF_LUMINANCE; pixelFormat.dwRGBBitCount = 0x08; pixelFormat.dwRBitMask = 0xFF; pixelFormat.dwGBitMask = 0x00; pixelFormat.dwBBitMask = 0x00; pixelFormat.dwABitMask = 0x00; break; case DDSFormat.ARGB: pixelFormat.dwFlags = DDPF_ALPHAPIXELS | DDPF_RGB; pixelFormat.dwRGBBitCount = 0x20; pixelFormat.dwRBitMask = 0xFF0000; pixelFormat.dwGBitMask = 0xFF00; pixelFormat.dwBBitMask = 0xFF; pixelFormat.dwABitMask = 0xFF000000; break; case DDSFormat.RGB: pixelFormat.dwFlags = DDPF_RGB; pixelFormat.dwRGBBitCount = 0x18; pixelFormat.dwRBitMask = 0xFF0000; pixelFormat.dwGBitMask = 0xFF00; pixelFormat.dwBBitMask = 0xFF; pixelFormat.dwABitMask = 0x00; break; default: throw new Exception("invalid texture format " + ddsFormat); } return(pixelFormat); }
public static byte[] CreateDDS(string input, DDSFormat format, MipmapMethod mipm, bool slow, bool flip) { var raw = ReadFile(input, flip); return(Crunch.CompressDDS(raw.Data, raw.Width, raw.Height, (CrnglueFormat)format, (CrnglueMipmaps)mipm, slow)); }
public MipMap(byte[] data, DDSFormat format, int w, int h) { long requiredSize = (long)(w * h * getBytesPerPixel(format)); if (data.Length != requiredSize) throw new InvalidDataException("Data size is not valid for selected format.\nActual: " + data.Length + " bytes\nRequired: " + requiredSize + " bytes"); this.data = data; ddsFormat = format; width = w; height = h; }
public static Bitmap ToBitmap(byte[] imgData, DDSFormat ddsFormat, int w, int h) { switch (ddsFormat) { case DDSFormat.DXT1: return UncompressDXT1(imgData, w, h); case DDSFormat.DXT5: return UncompressDXT5(imgData, w, h); case DDSFormat.V8U8: return UncompressV8U8(imgData, w, h); case DDSFormat.ATI2: return UncompressATI2(imgData, w, h); case DDSFormat.G8: return ViewG8(imgData, w, h); case DDSFormat.ARGB: return View32Bit(imgData, w, h); } throw new Exception("invalid texture format " + ddsFormat); }
private Bitmap readBlockImage(byte[] imgData, int w, int h) { switch (header.ddspf.dwFourCC) { case FOURCC_DXT1: ddsFormat = DDSFormat.DXT1; return UncompressDXT1(imgData, w, h); case FOURCC_DXT5: ddsFormat = DDSFormat.DXT5; return UncompressDXT5(imgData, w, h); default: break; } throw new Exception("invalid texture format"); }
public static double getBytesPerPixel(DDSFormat ddsFormat) { switch (ddsFormat) { case DDSFormat.DXT1: return 0.5; case DDSFormat.DXT5: case DDSFormat.ATI2: return 1; case DDSFormat.V8U8: return 2; } throw new Exception("invalid texture format"); }
public string createTextureMod(string inDir, string outFile, List <FoundTexture> textures, MainWindow mainWindow, ref string log) { string errors = ""; int count = 0; List <string> files = Directory.GetFiles(inDir, "*.dds").Where(item => item.EndsWith(".dds", StringComparison.OrdinalIgnoreCase)).ToList(); files.Sort(); List <FileMod> modFiles = new List <FileMod>(); using (FileStream outFs = new FileStream(outFile, FileMode.Create, FileAccess.Write)) { outFs.WriteUInt32(TexExplorer.TextureModTag); outFs.WriteUInt32(TexExplorer.TextureModVersion); outFs.WriteInt64(0); // files info offset - filled later for (int n = 0; n < files.Count(); n++) { string file = files[n]; if (mainWindow != null) { mainWindow.updateStatusLabel("Creating MOD: " + Path.GetFileName(outFile)); mainWindow.updateStatusLabel2("Texture " + (n + 1) + " of " + files.Count() + ", File: " + Path.GetFileName(file)); } string filename = Path.GetFileNameWithoutExtension(file).ToLowerInvariant(); if (!filename.Contains("0x")) { errors += "Texture filename not valid: " + Path.GetFileName(file) + " Texture filename must include texture CRC (0xhhhhhhhh). Skipping texture..." + Environment.NewLine; log += "Texture filename not valid: " + Path.GetFileName(file) + " Texture filename must include texture CRC (0xhhhhhhhh). Skipping texture..." + Environment.NewLine; continue; } int idx = filename.IndexOf("0x"); if (filename.Length - idx < 10) { errors += "Texture filename not valid: " + Path.GetFileName(file) + " Texture filename must include texture CRC (0xhhhhhhhh). Skipping texture..." + Environment.NewLine; log += "Texture filename not valid: " + Path.GetFileName(file) + " Texture filename must include texture CRC (0xhhhhhhhh). Skipping texture..." + Environment.NewLine; continue; } uint crc; string crcStr = filename.Substring(idx + 2, 8); try { crc = uint.Parse(crcStr, System.Globalization.NumberStyles.HexNumber); } catch { errors += "Texture filename not valid: " + Path.GetFileName(file) + " Texture filename must include texture CRC (_0xhhhhhhhh). Skipping texture..." + Environment.NewLine; log += "Texture filename not valid: " + Path.GetFileName(file) + " Texture filename must include texture CRC (_0xhhhhhhhh). Skipping texture..." + Environment.NewLine; continue; } List <FoundTexture> foundCrcList = textures.FindAll(s => s.crc == crc); if (foundCrcList.Count == 0) { errors += "Texture skipped. Texture " + Path.GetFileName(file) + " is not present in your game setup." + Environment.NewLine; log += "Texture skipped. Texture " + Path.GetFileName(file) + " is not present in your game setup." + Environment.NewLine; continue; } int savedCount = count; using (FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read)) { byte[] src = fs.ReadToBuffer((int)fs.Length); DDSImage image = new DDSImage(new MemoryStream(src)); if (!image.checkExistAllMipmaps()) { errors += "Error in texture: " + Path.GetFileName(file) + " This texture has not all the required mipmaps, skipping texture..." + Environment.NewLine; log += "Error in texture: " + Path.GetFileName(file) + " This texture has not all the required mipmaps, skipping texture..." + Environment.NewLine; continue; } Package pkg = new Package(GameData.GamePath + foundCrcList[0].list[0].path); Texture texture = new Texture(pkg, foundCrcList[0].list[0].exportID, pkg.getExportData(foundCrcList[0].list[0].exportID)); if (texture.mipMapsList.Count > 1 && image.mipMaps.Count() <= 1) { errors += "Error in texture: " + Path.GetFileName(file) + " This texture must have mipmaps, skipping texture..." + Environment.NewLine; log += "Error in texture: " + Path.GetFileName(file) + " This texture must have mipmaps, skipping texture..." + Environment.NewLine; continue; } string fmt = texture.properties.getProperty("Format").valueName; DDSFormat ddsFormat = DDSImage.convertFormat(fmt); if (image.ddsFormat != ddsFormat) { errors += "Error in texture: " + Path.GetFileName(file) + " This texture has wrong texture format, should be: " + ddsFormat + ", skipping texture..." + Environment.NewLine; log += "Error in texture: " + Path.GetFileName(file) + " This texture has wrong texture format, should be: " + ddsFormat + ", skipping texture..." + Environment.NewLine; continue; } if (image.mipMaps[0].origWidth / image.mipMaps[0].origHeight != texture.mipMapsList[0].width / texture.mipMapsList[0].height) { errors += "Error in texture: " + Path.GetFileName(file) + " This texture has wrong aspect ratio, skipping texture..." + Environment.NewLine; log += "Error in texture: " + Path.GetFileName(file) + " This texture has wrong aspect ratio, skipping texture..." + Environment.NewLine; continue; } Stream dst = compressData(src); dst.SeekBegin(); FileMod fileMod = new FileMod(); fileMod.tag = FileTextureTag; fileMod.name = Path.GetFileName(file); fileMod.offset = outFs.Position; fileMod.size = dst.Length; count++; modFiles.Add(fileMod); outFs.WriteStringASCIINull(foundCrcList[0].name); outFs.WriteUInt32(crc); outFs.WriteFromStream(dst, dst.Length); } if (count == savedCount) { continue; } } long pos = outFs.Position; outFs.SeekBegin(); outFs.WriteUInt32(TexExplorer.TextureModTag); outFs.WriteUInt32(TexExplorer.TextureModVersion); outFs.WriteInt64(pos); outFs.JumpTo(pos); outFs.WriteUInt32((uint)GameData.gameType); outFs.WriteInt32(modFiles.Count); for (int i = 0; i < modFiles.Count; i++) { outFs.WriteUInt32(modFiles[i].tag); outFs.WriteStringASCIINull(modFiles[i].name); outFs.WriteInt64(modFiles[i].offset); outFs.WriteInt64(modFiles[i].size); } } if (count == 0) { errors += "There are no texture files in " + inDir + ", mod not generated." + Environment.NewLine; log += "There are no texture files in " + inDir + ", mod not generated." + Environment.NewLine; File.Delete(outFile); } return(errors); }
public static void RunNVCompress(Bitmap bitmap, AssetBundle bundle, string path, AssetAttributes attributes, DDSFormat format, bool mipMaps, byte[] CookingRulesSHA1) { bool compressed = format == DDSFormat.DXTi; Bitmap bledBitmap = null; if (bitmap.HasAlpha) { bledBitmap = TextureConverterUtils.BleedAlpha(bitmap); } var ddsPath = Toolbox.GetTempFilePathWithExtension(".dds"); var tgaPath = Path.ChangeExtension(ddsPath, ".tga"); try { TextureConverterUtils.SaveToTGA(bledBitmap ?? bitmap, tgaPath, swapRedAndBlue: compressed); if (bledBitmap != null && bledBitmap != bitmap) { bledBitmap.Dispose(); } RunNVCompressHelper(tgaPath, ddsPath, bitmap.HasAlpha, compressed, mipMaps); bundle.ImportFile(ddsPath, path, 0, "", attributes, CookingRulesSHA1); } finally { DeletePossibleLockedFile(ddsPath); DeletePossibleLockedFile(tgaPath); } }
static private string convertDataModtoMem(string inputDir, string memFilePath) { string errors = ""; string[] files = null; Console.WriteLine("Mods conversion started..."); List <string> list = Directory.GetFiles(inputDir, "*.tpf").Where(item => item.EndsWith(".tpf", StringComparison.OrdinalIgnoreCase)).ToList(); list.AddRange(Directory.GetFiles(inputDir, "*.mod").Where(item => item.EndsWith(".mod", StringComparison.OrdinalIgnoreCase))); list.AddRange(Directory.GetFiles(inputDir, "*.dds").Where(item => item.EndsWith(".dds", StringComparison.OrdinalIgnoreCase))); list.Sort(); files = list.ToArray(); int result; string fileName = ""; uint dstLen = 0; string[] ddsList = null; ulong numEntries = 0; List <TexExplorer.BinaryMod> mods = new List <TexExplorer.BinaryMod>(); foreach (string file in files) { if (file.EndsWith(".mod", StringComparison.OrdinalIgnoreCase)) { try { using (FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read)) { string package = ""; int len = fs.ReadInt32(); string version = fs.ReadStringASCII(len); // version if (version.Length < 5) // legacy .mod { fs.SeekBegin(); } numEntries = fs.ReadUInt32(); for (uint i = 0; i < numEntries; i++) { TexExplorer.BinaryMod mod = new TexExplorer.BinaryMod(); len = fs.ReadInt32(); string desc = fs.ReadStringASCII(len); // description len = fs.ReadInt32(); string scriptLegacy = fs.ReadStringASCII(len); string path = ""; if (desc.Contains("Binary Replacement")) { try { Misc.ParseME3xBinaryScriptMod(scriptLegacy, ref package, ref mod.exportId, ref path); if (mod.exportId == -1 || package == "" || path == "") { throw new Exception(); } } catch { len = fs.ReadInt32(); fs.Skip(len); errors += "Skipping not compatible content, entry: " + (i + 1) + " - mod: " + file + Environment.NewLine; continue; } mod.packagePath = GameData.RelativeGameData(Path.Combine(path, package)); mod.binaryMod = true; len = fs.ReadInt32(); mod.data = fs.ReadToBuffer(len); } else { string textureName = desc.Split(' ').Last(); FoundTexture f; try { f = Misc.ParseLegacyMe3xScriptMod(textures, scriptLegacy, textureName); mod.textureCrc = f.crc; if (mod.textureCrc == 0) { throw new Exception(); } } catch { len = fs.ReadInt32(); fs.Skip(len); errors += "Skipping not compatible content, entry: " + (i + 1) + " - mod: " + file + Environment.NewLine; continue; } textureName = f.name; mod.textureName = textureName; mod.binaryMod = false; len = fs.ReadInt32(); mod.data = fs.ReadToBuffer(len); DDSImage image = new DDSImage(new MemoryStream(mod.data)); if (!image.checkExistAllMipmaps()) { errors += "Error in texture: " + textureName + string.Format("_0x{0:X8}", f.crc) + " This texture has not all the required mipmaps, skipping texture, entry: " + (i + 1) + " - mod: " + file + Environment.NewLine; continue; } Package pkg = new Package(GameData.GamePath + f.list[0].path); Texture texture = new Texture(pkg, f.list[0].exportID, pkg.getExportData(f.list[0].exportID)); if (texture.mipMapsList.Count > 1 && image.mipMaps.Count() <= 1) { errors += "Error in texture: " + textureName + string.Format("_0x{0:X8}", f.crc) + " This texture must have mipmaps, skipping texture, entry: " + (i + 1) + " - mod: " + file + Environment.NewLine; continue; } string fmt = texture.properties.getProperty("Format").valueName; DDSFormat ddsFormat = DDSImage.convertFormat(fmt); if (image.ddsFormat != ddsFormat) { errors += "Error in texture: " + textureName + string.Format("_0x{0:X8}", f.crc) + " This texture has wrong texture format, should be: " + ddsFormat + ", skipping texture, entry: " + (i + 1) + " - mod: " + file + Environment.NewLine; continue; } if (image.mipMaps[0].origWidth / image.mipMaps[0].origHeight != texture.mipMapsList[0].width / texture.mipMapsList[0].height) { errors += "Error in texture: " + textureName + string.Format("_0x{0:X8}", f.crc) + " This texture has wrong aspect ratio, skipping texture, entry: " + (i + 1) + " - mod: " + file + Environment.NewLine; continue; } } mods.Add(mod); } } } catch { errors += "Mod is not compatible: " + file + Environment.NewLine; continue; } } else if (file.EndsWith(".tpf", StringComparison.OrdinalIgnoreCase)) { IntPtr handle = IntPtr.Zero; try { byte[] buffer = File.ReadAllBytes(file); handle = ZlibHelper.Zip.Open(buffer, ref numEntries, 1); if (ZlibHelper.Zip.LocateFile(handle, "texmod.def") != 0) { throw new Exception(); } result = ZlibHelper.Zip.GetCurrentFileInfo(handle, ref fileName, ref dstLen); if (result != 0) { throw new Exception(); } byte[] listText = new byte[dstLen]; result = ZlibHelper.Zip.ReadCurrentFile(handle, listText, dstLen); if (result != 0) { throw new Exception(); } ddsList = Encoding.ASCII.GetString(listText).Trim('\0').Replace("\r", "").TrimEnd('\n').Split('\n'); result = ZlibHelper.Zip.GoToFirstFile(handle); if (result != 0) { throw new Exception(); } for (uint i = 0; i < numEntries; i++) { TexExplorer.BinaryMod mod = new TexExplorer.BinaryMod(); try { uint crc = 0; result = ZlibHelper.Zip.GetCurrentFileInfo(handle, ref fileName, ref dstLen); if (result != 0) { throw new Exception(); } string filename = Path.GetFileName(fileName); foreach (string dds in ddsList) { string ddsFile = dds.Split('|')[1]; if (ddsFile.ToLowerInvariant() != filename.ToLowerInvariant()) { continue; } crc = uint.Parse(dds.Split('|')[0].Substring(2), System.Globalization.NumberStyles.HexNumber); break; } if (crc == 0) { if (filename != "texmod.def") { errors += "Skipping file: " + filename + " not founded in texmod.def, entry: " + (i + 1) + " - mod: " + file + Environment.NewLine; } ZlibHelper.Zip.GoToNextFile(handle); continue; } List <FoundTexture> foundCrcList = textures.FindAll(s => s.crc == crc); if (foundCrcList.Count == 0) { errors += "Texture skipped. File " + filename + string.Format(" - 0x{0:X8}", crc) + " is not present in your game setup - mod: " + file + Environment.NewLine; ZlibHelper.Zip.GoToNextFile(handle); continue; } string textureName = foundCrcList[0].name; mod.textureName = textureName; mod.binaryMod = false; mod.textureCrc = crc; mod.data = new byte[dstLen]; result = ZlibHelper.Zip.ReadCurrentFile(handle, mod.data, dstLen); if (result != 0) { errors += "Error in texture: " + textureName + string.Format("_0x{0:X8}", crc) + ", skipping texture, entry: " + (i + 1) + " - mod: " + file + Environment.NewLine; ZlibHelper.Zip.GoToNextFile(handle); continue; } uint tag = BitConverter.ToUInt32(mod.data, 0); if (tag != 0x20534444) // DDS { errors += "Error in texture: " + textureName + string.Format("_0x{0:X8}", crc) + " This texture is not in DDS format, skipping texture, entry: " + (i + 1) + " - mod: " + file + Environment.NewLine; ZlibHelper.Zip.GoToNextFile(handle); continue; } DDSImage image = new DDSImage(new MemoryStream(mod.data)); if (!image.checkExistAllMipmaps()) { errors += "Error in texture: " + textureName + string.Format("_0x{0:X8}", crc) + " This texture has not all the required mipmaps, skipping texture, entry: " + (i + 1) + " - mod: " + file + Environment.NewLine; ZlibHelper.Zip.GoToNextFile(handle); continue; } Package pkg = new Package(GameData.GamePath + foundCrcList[0].list[0].path); Texture texture = new Texture(pkg, foundCrcList[0].list[0].exportID, pkg.getExportData(foundCrcList[0].list[0].exportID)); if (texture.mipMapsList.Count > 1 && image.mipMaps.Count() <= 1) { errors += "Error in texture: " + textureName + string.Format("_0x{0:X8}", crc) + " This texture must have mipmaps, skipping texture, entry: " + (i + 1) + " - mod: " + file + Environment.NewLine; ZlibHelper.Zip.GoToNextFile(handle); continue; } string fmt = texture.properties.getProperty("Format").valueName; DDSFormat ddsFormat = DDSImage.convertFormat(fmt); if (image.ddsFormat != ddsFormat) { errors += "Error in texture: " + textureName + string.Format("_0x{0:X8}", crc) + " This texture has wrong texture format, should be: " + ddsFormat + ", skipping texture, entry: " + (i + 1) + " - mod: " + file + Environment.NewLine; ZlibHelper.Zip.GoToNextFile(handle); continue; } if (image.mipMaps[0].origWidth / image.mipMaps[0].origHeight != texture.mipMapsList[0].width / texture.mipMapsList[0].height) { errors += "Error in texture: " + textureName + string.Format("_0x{0:X8}", crc) + " This texture has wrong aspect ratio, skipping texture, entry: " + (i + 1) + " - mod: " + file + Environment.NewLine; ZlibHelper.Zip.GoToNextFile(handle); continue; } mods.Add(mod); } catch { errors += "Skipping not compatible content, entry: " + (i + 1) + " file: " + fileName + " - mod: " + file + Environment.NewLine; } ZlibHelper.Zip.GoToNextFile(handle); } ZlibHelper.Zip.Close(handle); handle = IntPtr.Zero; } catch { errors += "Mod is not compatible: " + file + Environment.NewLine; if (handle != IntPtr.Zero) { ZlibHelper.Zip.Close(handle); } handle = IntPtr.Zero; continue; } } else if (file.EndsWith(".dds", StringComparison.OrdinalIgnoreCase)) { TexExplorer.BinaryMod mod = new TexExplorer.BinaryMod(); string filename = Path.GetFileNameWithoutExtension(file).ToLowerInvariant(); if (!filename.Contains("0x")) { errors += "Texture filename not valid: " + Path.GetFileName(file) + " Texture filename must include texture CRC (0xhhhhhhhh). Skipping texture..." + Environment.NewLine; continue; } int idx = filename.IndexOf("0x"); if (filename.Length - idx < 10) { errors += "Texture filename not valid: " + Path.GetFileName(file) + " Texture filename must include texture CRC (0xhhhhhhhh). Skipping texture..." + Environment.NewLine; continue; } uint crc; string crcStr = filename.Substring(idx + 2, 8); try { crc = uint.Parse(crcStr, System.Globalization.NumberStyles.HexNumber); } catch { errors += "Texture filename not valid: " + Path.GetFileName(file) + " Texture filename must include texture CRC (0xhhhhhhhh). Skipping texture..." + Environment.NewLine; continue; } List <FoundTexture> foundCrcList = textures.FindAll(s => s.crc == crc); if (foundCrcList.Count == 0) { errors += "Texture skipped. Texture " + Path.GetFileName(file) + " is not present in your game setup." + Environment.NewLine; continue; } using (FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read)) { mod.data = fs.ReadToBuffer((int)fs.Length); DDSImage image = new DDSImage(new MemoryStream(mod.data)); if (!image.checkExistAllMipmaps()) { errors += "Error in texture: " + Path.GetFileName(file) + " This texture has not all the required mipmaps, skipping texture..." + Environment.NewLine; continue; } Package pkg = new Package(GameData.GamePath + foundCrcList[0].list[0].path); Texture texture = new Texture(pkg, foundCrcList[0].list[0].exportID, pkg.getExportData(foundCrcList[0].list[0].exportID)); if (texture.mipMapsList.Count > 1 && image.mipMaps.Count() <= 1) { errors += "Error in texture: " + Path.GetFileName(file) + " This texture must have mipmaps, skipping texture..." + Environment.NewLine; continue; } string fmt = texture.properties.getProperty("Format").valueName; DDSFormat ddsFormat = DDSImage.convertFormat(fmt); if (image.ddsFormat != ddsFormat) { errors += "Error in texture: " + Path.GetFileName(file) + " This texture has wrong texture format, should be: " + ddsFormat + ", skipping texture..." + Environment.NewLine; continue; } if (image.mipMaps[0].origWidth / image.mipMaps[0].origHeight != texture.mipMapsList[0].width / texture.mipMapsList[0].height) { errors += "Error in texture: " + Path.GetFileName(file) + " This texture has wrong aspect ratio, skipping texture..." + Environment.NewLine; continue; } mod.textureName = foundCrcList[0].name; mod.binaryMod = false; mod.textureCrc = crc; mods.Add(mod); } } } if (mods.Count == 0) { Console.WriteLine("Mods conversion failed"); return(errors); } Console.WriteLine("Saving to MEM file... " + memFilePath); List <MipMaps.FileMod> modFiles = new List <MipMaps.FileMod>(); FileStream outFs; if (File.Exists(memFilePath)) { File.Delete(memFilePath); } using (outFs = new FileStream(memFilePath, FileMode.Create, FileAccess.Write)) { outFs.WriteUInt32(TexExplorer.TextureModTag); outFs.WriteUInt32(TexExplorer.TextureModVersion); outFs.WriteInt64(0); // filled later for (int l = 0; l < mods.Count; l++) { MipMaps.FileMod fileMod = new MipMaps.FileMod(); Stream dst = MipMaps.compressData(mods[l].data); dst.SeekBegin(); fileMod.offset = outFs.Position; fileMod.size = dst.Length; if (mods[l].binaryMod) { fileMod.tag = MipMaps.FileBinaryTag; fileMod.name = Path.GetFileNameWithoutExtension(mods[l].packagePath) + "_" + mods[l].exportId + ".bin"; outFs.WriteInt32(mods[l].exportId); outFs.WriteStringASCIINull(mods[l].packagePath); } else { fileMod.tag = MipMaps.FileTextureTag; fileMod.name = mods[l].textureName + string.Format("_0x{0:X8}", mods[l].textureCrc) + ".dds"; outFs.WriteStringASCIINull(mods[l].textureName); outFs.WriteUInt32(mods[l].textureCrc); } outFs.WriteFromStream(dst, dst.Length); modFiles.Add(fileMod); } long pos = outFs.Position; outFs.SeekBegin(); outFs.WriteUInt32(TexExplorer.TextureModTag); outFs.WriteUInt32(TexExplorer.TextureModVersion); outFs.WriteInt64(pos); outFs.JumpTo(pos); outFs.WriteUInt32((uint)GameData.gameType); outFs.WriteInt32(modFiles.Count); for (int i = 0; i < modFiles.Count; i++) { outFs.WriteUInt32(modFiles[i].tag); outFs.WriteStringASCIINull(modFiles[i].name); outFs.WriteInt64(modFiles[i].offset); outFs.WriteInt64(modFiles[i].size); } } Console.WriteLine("Mods conversion process completed"); return(errors); }
private void LoadDDSImage(MemoryStream ddsStream, bool bypassCheck = false) { using (BinaryReader r = new BinaryReader(ddsStream)) { dwMagic = r.ReadInt32(); if (dwMagic != 0x20534444) { throw new Exception("This is not a DDS!"); } Read_DDS_HEADER(header, r); if (((header.ddspf.dwFlags & DDPF_FOURCC) != 0) && (header.ddspf.dwFourCC == FOURCC_DX10 /*DX10*/)) { throw new Exception("DX10 not supported yet!"); } int mipMapCount = 1; if ((header.dwFlags & DDSD_MIPMAPCOUNT) != 0) { mipMapCount = header.dwMipMapCount; } if (mipMapCount == 0) { mipMapCount = 1; } mipMaps = new List <MipMap>(); ddsFormat = getFormat(); double bytePerPixel = getBytesPerPixel(ddsFormat); for (int i = 0; i < mipMapCount; i++) { int w = (int)(header.dwWidth / Math.Pow(2, i)); int h = (int)(header.dwHeight / Math.Pow(2, i)); int origW = w; int origH = h; if (origW == 0 && origH != 0) { origW = 1; } if (origH == 0 && origW != 0) { origH = 1; } w = origW; h = origH; if (ddsFormat == DDSFormat.DXT1 || ddsFormat == DDSFormat.DXT3 || ddsFormat == DDSFormat.DXT5) { w = (w < 4) ? 4 : w; h = (h < 4) ? 4 : h; } int mipMapBytes = (int)(w * h * bytePerPixel); byte[] data = r.ReadBytes(mipMapBytes); mipMaps.Add(new MipMap(data, ddsFormat, origW, origH)); } } }
public static void RunNVCompress(Bitmap bitmap, AssetBundle bundle, string path, AssetAttributes attributes, DDSFormat format, bool mipMaps, byte[] CookingRulesSHA1, DateTime time) { bool compressed = format == DDSFormat.DXTi; Bitmap bledBitmap = null; if (bitmap.HasAlpha) { bledBitmap = TextureConverterUtils.BleedAlpha(bitmap); } string mipsFlag = mipMaps ? string.Empty : "-nomips"; string compressionMethod; if (compressed) { compressionMethod = bitmap.HasAlpha ? "-bc3" : "-bc1"; } else { #if WIN compressionMethod = "-rgb"; #else compressionMethod = "-rgb -rgbfmt bgra8"; #endif } var nvcompress = GetToolPath("nvcompress"); string args = "{0} {1}".Format(mipsFlag, compressionMethod); var hashString = GetTextureHashString(bledBitmap ?? bitmap, ".dds", args); var cachePath = AssetCache.Instance.Load(hashString); if (cachePath != null) { bundle.ImportFile(cachePath, path, 0, "", attributes, time, CookingRulesSHA1); return; } var ddsPath = Toolbox.GetTempFilePathWithExtension(".dds"); var tgaPath = Path.ChangeExtension(ddsPath, ".tga"); var srcPath = Path.Combine(Directory.GetCurrentDirectory(), tgaPath); var dstPath = Path.Combine(Directory.GetCurrentDirectory(), ddsPath); try { TextureConverterUtils.SaveToTGA(bledBitmap ?? bitmap, tgaPath, swapRedAndBlue: compressed); if (bledBitmap != null && bledBitmap != bitmap) { bledBitmap.Dispose(); } args += $" \"{srcPath}\" \"{dstPath}\""; if (Process.Start(nvcompress, args.Format(mipsFlag, compressionMethod, srcPath, dstPath), options: Process.Options.RedirectErrors) != 0) { throw new Lime.Exception($"NVCompress error\nCommand line: {nvcompress} {args}\""); } bundle.ImportFile(ddsPath, path, 0, "", attributes, time, CookingRulesSHA1); AssetCache.Instance.Save(ddsPath, hashString); } finally { DeletePossibleLockedFile(ddsPath); DeletePossibleLockedFile(tgaPath); } }
public DDSImage(string ddsFileName) { using (FileStream ddsStream = File.OpenRead(ddsFileName)) { using (BinaryReader r = new BinaryReader(ddsStream)) { dwMagic = r.ReadInt32(); if (dwMagic != 0x20534444) { throw new Exception("This is not a DDS!"); } Read_DDS_HEADER(header, r); if (((header.ddspf.dwFlags & DDPF_FOURCC) != 0) && (header.ddspf.dwFourCC == FOURCC_DX10 /*DX10*/)) { throw new Exception("DX10 not supported yet!"); } int mipMapCount = 1; if ((header.dwFlags & DDSD_MIPMAPCOUNT) != 0) mipMapCount = header.dwMipMapCount; mipMaps = new MipMap[mipMapCount]; ddsFormat = getFormat(); double bytePerPixel = getBytesPerPixel(ddsFormat); for (int i = 0; i < mipMapCount; i++) { int w = (int)(header.dwWidth / Math.Pow(2, i)); int h = (int)(header.dwHeight / Math.Pow(2, i)); if (ddsFormat == DDSFormat.DXT1 || ddsFormat == DDSFormat.DXT5) { w = (w < 4) ? 4 : w; h = (h < 4) ? 4 : h; } int mipMapBytes = (int)(w * h * bytePerPixel); mipMaps[i] = new MipMap(r.ReadBytes(mipMapBytes), ddsFormat, w, h); } } } }