public static Texture2DHelpers.TextureFormat GetDDSFormat(DDS_HEADER header) { Texture2DHelpers.TextureFormat format; bool isCompressed = (header.ddspf.dwFlags & PIXELFORMAT_DWFlags.DDPF_FOURCC) != 0; if (isCompressed) { if (header.ddspf.dwFourCC == DDS_DXT5) { format = Texture2DHelpers.TextureFormat.DXT5; } else if (header.ddspf.dwFourCC == DDS_DXT3) { format = Texture2DHelpers.TextureFormat.DXT3; } else { format = Texture2DHelpers.TextureFormat.DXT1; } } else if ((header.ddspf.dwFlags & PIXELFORMAT_DWFlags.DDPF_ALPHA) != 0 || (header.ddspf.dwFlags & PIXELFORMAT_DWFlags.DDPF_ALPHAPIXELS) != 0) { format = Texture2DHelpers.TextureFormat.BGRA8888; } else { format = Texture2DHelpers.TextureFormat.BGR888; } return(format); }
/// <summary> /// Gets image format of image file. /// </summary> /// <param name="imagePath">Path to image file.</param> /// <returns>Format of image.</returns> public static Format ParseFormat(string imagePath, ref DDS_HEADER header) { SupportedExtensions ext = ParseExtension(imagePath); using (FileStream fs = new FileStream(imagePath, FileMode.Open, FileAccess.Read, FileShare.Read)) return(ParseFormat(fs, ext, ref header)); }
static bool?IsV8U8(Stream stream) { stream.Seek(0, SeekOrigin.Begin); using (BinaryReader r = new BinaryReader(stream, Encoding.Default, true)) { int dwMagic = r.ReadInt32(); if (dwMagic != 0x20534444) { return(null); } DDS_HEADER header = new DDS_HEADER(); Read_DDS_HEADER(header, r); if (((header.ddspf.dwFlags & 0x00000004) != 0) && (header.ddspf.dwFourCC == 0x30315844 /*DX10*/)) { throw new Exception("DX10 not supported yet!"); } return(header.ddspf.dwRGBBitCount == 0x10 && header.ddspf.dwRBitMask == 0xFF && header.ddspf.dwGBitMask == 0xFF00 && header.ddspf.dwBBitMask == 0x00 && header.ddspf.dwABitMask == 0x00); } }
private static bool WriteV8U8ToStream(IEnumerable <MipMap> mipmaps, Stream destination, int width, int height, int Mips, bool DisposeStream) { DDS_HEADER header = Build_V8U8_DDS_Header(Mips, height, width); try { using (BinaryWriter writer = new BinaryWriter(destination, Encoding.Default, !DisposeStream)) { // KFreon: Get and write header Write_V8U8_DDS_Header(header, writer); foreach (MipMap mip in mipmaps) { foreach (sbyte byt in mip.data) { writer.Write(byt); } } } return(true); } catch (IOException e) { Debug.WriteLine("Error writing to file: " + e.Message); } return(false); }
static SurfaceFormat GetSurfaceFormat(ref DDS_HEADER header) { //Compressed switch (header.ddspf.dwFourCC) { case FourCC.DXT1: return(SurfaceFormat.Dxt1); case FourCC.DXT3: return(SurfaceFormat.Dxt3); case FourCC.DXT5: return(SurfaceFormat.Dxt5); } //Uncompressed 16-bit formats if (header.ddspf.dwFlags == 0x41 && header.ddspf.dwRGBBitCount == 0x10 && header.ddspf.dwFourCC == 0 && header.ddspf.dwRBitMask == 0x7c00 && header.ddspf.dwGBitMask == 0x3e0 && header.ddspf.dwBBitMask == 0x1f && header.ddspf.dwABitMask == 0x8000) { return(SurfaceFormat.Bgra5551); } if (header.ddspf.dwFlags == 0x40 && header.ddspf.dwRGBBitCount == 0x10 && header.ddspf.dwFourCC == 0 && header.ddspf.dwRBitMask == 0xf800 && header.ddspf.dwGBitMask == 0x7e0 && header.ddspf.dwBBitMask == 0x1f && header.ddspf.dwABitMask == 0) { return(SurfaceFormat.Bgr565); } if (header.ddspf.dwFlags == 0x41 && header.ddspf.dwRGBBitCount == 0x10 && header.ddspf.dwFourCC == 0 && header.ddspf.dwRBitMask == 0xf00 && header.ddspf.dwGBitMask == 240 && header.ddspf.dwBBitMask == 15 && header.ddspf.dwABitMask == 0xf000) { return(SurfaceFormat.Bgra4444); } //Uncompressed 32-bit and 24-bit formats if ((header.ddspf.dwFlags == 0x41 || header.ddspf.dwFlags == 0x40) && (header.ddspf.dwRGBBitCount == 0x20 || header.ddspf.dwRGBBitCount == 0x18) && header.ddspf.dwFourCC == 0 && header.ddspf.dwABitMask != 0xc0000000) //Exclude A2B10G10R10 { return(SurfaceFormat.Color); } throw new NotSupportedException("Pixel Format (FourCC " + header.ddspf.dwFourCC.ToString() + ")"); }
/// <summary> /// Gets image format from stream containing image file, along with extension of image file. /// </summary> /// <param name="imgData">Stream containing entire image file. NOT just pixels.</param> /// <param name="extension">Extension of image file.</param> /// <returns>Format of image.</returns> public static Format ParseFormat(Stream imgData, string extension, ref DDS_HEADER header) { SupportedExtensions ext = SupportedExtensions.UNKNOWN; // KFreon: Attempt to determine from data if (extension == null) { // KFreon: Save position and go back to start long originalPos = imgData.Position; imgData.Seek(0, SeekOrigin.Begin); char l1 = (char)imgData.ReadByte(); char l2 = (char)imgData.ReadByte(); char l3 = (char)imgData.ReadByte(); char l4 = (char)imgData.ReadByte(); // BMP if (l1 == 'B' && l2 == 'M') { ext = SupportedExtensions.BMP; } // PNG if (l1 == 137 && l2 == 'P' && l3 == 'N' && l4 == 'G') { ext = SupportedExtensions.PNG; } // JPG if (l1 == 0xFF && l2 == 0xD8 && l3 == 0xFF) { ext = SupportedExtensions.JPG; } // DDS if (l1 == 'D' && l2 == 'D' && l3 == 'S') { ext = SupportedExtensions.DDS; } // KFreon: Reset stream position imgData.Seek(originalPos, SeekOrigin.Begin); } else { ext = ParseExtension(extension); } if (ext == SupportedExtensions.UNKNOWN) { return(new Format()); } return(ParseFormat(imgData, ext, ref header)); }
public DDSMetadata(DDS_HEADER ddsheader) { var mask = DDSUtils.DDSCAPS2_CUBEMAP_ALL_FACES & DDSUtils.DDSCAPS2_CUBEMAP; if ((ddsheader.dwCaps2 & mask) != 0) { } bool iscubemap = (ddsheader.dwCaps2 & mask) != 0; Width = ddsheader.dwWidth; Height = ddsheader.dwHeight; Mipscount = ddsheader.dwMipMapCount; switch (ddsheader.ddspf.dwFourCC) { case 0x31545844: //DXT1 Format = EFormat.BC1_UNORM; break; case 0x33545844: //DXT3 Format = EFormat.BC2_UNORM; break; case 0x35545844: //DXT5 Format = EFormat.BC3_UNORM; break; case 0x55344342: //BC4U Format = EFormat.BC4_UNORM; break; case 0x55354342: //BC5U Format = EFormat.BC5_UNORM; break; //case // Format = EFormat.R8G8B8A8_UNORM: // SetPixelmask(DDSPF_A8R8G8B8, ref ddspf); break; //case // Format = EFormat.BC7_UNORM ; //TODO: dxt10 is currently unsupported // dxt10 = true; break; default: Format = EFormat.R8G8B8A8_UNORM; break; } Bpp = 16; //TODO: in vanilla this is always 16 ??? Iscubemap = iscubemap; Slicecount = iscubemap ? (uint)6 : (uint)0; //TODO: does not account for texarrays Dx10 = false; }
private void LoadImage(Stream stream) { stream.Seek(0, SeekOrigin.Begin); BinaryReader r = new BinaryReader(stream); int dwMagic = r.ReadInt32(); if (dwMagic != 0x20534444) { throw new Exception("This is not a DDS! Magic number wrong."); } DDS_HEADER header = new DDS_HEADER(); Read_DDS_HEADER(header, r); if (((header.ddspf.dwFlags & 0x00000004) != 0) && (header.ddspf.dwFourCC == 0x30315844 /*DX10*/)) { throw new Exception("DX10 not supported yet!"); } if (header.ddspf.dwFourCC != 0) { throw new InvalidDataException("DDS not V8U8."); } int mipMapCount = 1; if ((header.dwFlags & 0x00020000) != 0) { mipMapCount = header.dwMipMapCount; } int w = 0; int h = 0; double bytePerPixel = 2; MipMaps = new MipMap[mipMapCount]; // KFreon: Get mips for (int i = 0; i < mipMapCount; i++) { w = (int)(header.dwWidth / Math.Pow(2, i)); h = (int)(header.dwHeight / Math.Pow(2, i)); int mipMapBytes = (int)(w * h * bytePerPixel); MipMaps[i] = new MipMap(r.ReadBytes(mipMapBytes), w, h); } Width = header.dwWidth; Height = header.dwHeight; }
static Texture2D GetTexture2D(ref DDS_HEADER header, BinaryReader reader) { SurfaceFormat fmt; int w, h; var surface = LoadSurface(ref header, reader, out fmt, out w, out h); var tex = new Texture2D(w, h, surface.Length > 1, fmt); for (int i = 0; i < surface.Length; i++) { tex.SetData(i, null, surface[i], 0, surface[i].Length); } return(tex); }
private static ShaderResourceView CreateTextureFromDDS(Device device, DeviceContext context, byte[] data, out bool isCubeMap) { // Validate DDS file in memory DDS_HEADER header = new DDS_HEADER(); int ddsHeaderSize = Marshal.SizeOf(header); int ddspfSize = Marshal.SizeOf(new DDS_PIXELFORMAT()); int ddsHeader10Size = Marshal.SizeOf(new DDS_HEADER_DXT10()); if (data.Length < (sizeof(uint) + ddsHeaderSize)) { throw new Exception(); } //first is magic number int dwMagicNumber = BitConverter.ToInt32(data, 0); if (dwMagicNumber != DDS_MAGIC) { throw new Exception(); } header = ByteArrayToStructure <DDS_HEADER>(data, 4, ddsHeaderSize); // Verify header to validate DDS file if (header.size != ddsHeaderSize || header.ddspf.size != ddspfSize) { throw new Exception(); } // Check for DX10 extension bool bDXT10Header = false; if (((header.ddspf.flags & DDS_FOURCC) > 0) && (MAKEFOURCC('D', 'X', '1', '0') == header.ddspf.fourCC)) { // Must be long enough for both headers and magic value if (data.Length < (ddsHeaderSize + 4 + ddsHeader10Size)) { throw new Exception(); } bDXT10Header = true; } int offset = 4 + ddsHeaderSize + (bDXT10Header ? ddsHeader10Size : 0); return(InitTextureFromData(device, context, header, null, data, offset, 0, out isCubeMap)); }
static TextureCube GetTextureCube(ref DDS_HEADER header, BinaryReader reader) { SurfaceFormat fmt; int w, h; var sfc = LoadSurface(ref header, reader, out fmt, out w, out h); var tex = new TextureCube(w, sfc.Length > 1, fmt); //Positive X for (int i = 0; i < sfc.Length; i++) { tex.SetData(CubeMapFace.PositiveX, 0, null, sfc[i], 0, sfc[i].Length); } //Negative sfc = LoadSurface(ref header, reader, out fmt, out w, out h); for (int i = 0; i < sfc.Length; i++) { tex.SetData(CubeMapFace.NegativeX, 0, null, sfc[i], 0, sfc[i].Length); } //Positive Y sfc = LoadSurface(ref header, reader, out fmt, out w, out h); for (int i = 0; i < sfc.Length; i++) { tex.SetData(CubeMapFace.PositiveY, 0, null, sfc[i], 0, sfc[i].Length); } //Negative Y sfc = LoadSurface(ref header, reader, out fmt, out w, out h); for (int i = 0; i < sfc.Length; i++) { tex.SetData(CubeMapFace.NegativeY, 0, null, sfc[i], 0, sfc[i].Length); } //Positive Z sfc = LoadSurface(ref header, reader, out fmt, out w, out h); for (int i = 0; i < sfc.Length; i++) { tex.SetData(CubeMapFace.PositiveZ, 0, null, sfc[i], 0, sfc[i].Length); } //Negative Z sfc = LoadSurface(ref header, reader, out fmt, out w, out h); for (int i = 0; i < sfc.Length; i++) { tex.SetData(CubeMapFace.NegativeZ, 0, null, sfc[i], 0, sfc[i].Length); } return(tex); }
/// <summary> /// Reads DDS header from file. /// </summary> /// <param name="h">Header struct.</param> /// <param name="r">File reader.</param> public static void Read_DDS_HEADER(DDS_HEADER h, BinaryReader r) { h.dwSize = r.ReadInt32(); h.dwFlags = r.ReadInt32(); h.dwHeight = r.ReadInt32(); h.dwWidth = r.ReadInt32(); h.dwPitchOrLinearSize = r.ReadInt32(); h.dwDepth = r.ReadInt32(); h.dwMipMapCount = r.ReadInt32(); for (int i = 0; i < 11; ++i) { h.dwReserved1[i] = r.ReadInt32(); } Read_DDS_PIXELFORMAT(h.ddspf, r); h.dwCaps = r.ReadInt32(); h.dwCaps2 = r.ReadInt32(); h.dwCaps3 = r.ReadInt32(); h.dwCaps4 = r.ReadInt32(); h.dwReserved2 = r.ReadInt32(); }
/// <summary> /// Writes V8U8 DDS header to binary stream. /// </summary> /// <param name="header">Header to write.</param> /// <param name="writer">BinaryWriter wrapped stream to write to.</param> private static void Write_V8U8_DDS_Header(DDS_HEADER header, BinaryWriter writer) { // KFreon: Write magic number ("DDS") writer.Write(0x20534444); // KFreon: Write all header fields regardless of filled or not writer.Write(header.dwSize); writer.Write(header.dwFlags); writer.Write(header.dwHeight); writer.Write(header.dwWidth); writer.Write(header.dwPitchOrLinearSize); writer.Write(header.dwDepth); writer.Write(header.dwMipMapCount); // KFreon: Write reserved1 for (int i = 0; i < 11; i++) { writer.Write(0); } // KFreon: Write PIXELFORMAT DDS_PIXELFORMAT px = header.ddspf; writer.Write(px.dwSize); writer.Write(px.dwFlags); writer.Write(px.dwFourCC); writer.Write(px.dwRGBBitCount); writer.Write(px.dwRBitMask); writer.Write(px.dwGBitMask); writer.Write(px.dwBBitMask); writer.Write(px.dwABitMask); writer.Write(header.dwCaps); writer.Write(header.dwCaps2); writer.Write(header.dwCaps3); writer.Write(header.dwCaps4); writer.Write(header.dwReserved2); }
static int GetSurfaceBytes(ref DDS_HEADER header, int width, int height) { switch (GetSurfaceFormat(ref header)) { case SurfaceFormat.Dxt1: return(((width + 3) / 4) * ((height + 3) / 4) * 8); case SurfaceFormat.Dxt3: case SurfaceFormat.Dxt5: return(((width + 3) / 4) * ((height + 3) / 4) * 16); case SurfaceFormat.Bgra5551: case SurfaceFormat.Bgr565: case SurfaceFormat.Bgra4444: return(width * height * 2); case SurfaceFormat.Color: return(width * height * 4); default: throw new NotSupportedException(header.ddspf.dwFourCC.ToString()); } }
/// <summary> /// Builds a V8U8 DDS header from certain details. /// </summary> /// <param name="Mips">Number of mipmaps.</param> /// <param name="height">Height of image.</param> /// <param name="width">Width of image.</param> /// <returns>DDS_HEADER struct from details.</returns> private static DDS_HEADER Build_V8U8_DDS_Header(int Mips, int height, int width) { DDS_HEADER header = new DDS_HEADER(); header.dwSize = 124; header.dwFlags = 0x1 | 0x2 | 0x4 | 0x1000 | (Mips != 0 ? 0x20000 : 0x0); // Flags to denote valid fields: DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_MIPMAPCOUNT header.dwWidth = width; header.dwHeight = height; header.dwCaps = 0x1000 | 0x8 | (Mips == 0 ? 0 : 0x400000); header.dwMipMapCount = Mips == 0 ? 1 : Mips; //header.dwPitchOrLinearSize = ((width + 1) >> 1)*4; DDS_PIXELFORMAT px = new DDS_PIXELFORMAT(); px.dwSize = 32; //px.dwFlags = 0x200; px.dwFlags = 0x80000; px.dwRGBBitCount = 16; px.dwRBitMask = 255; px.dwGBitMask = 0x0000FF00; header.ddspf = px; return(header); }
/// <summary> /// Writes V8U8 DDS header to binary stream. /// </summary> /// <param name="header">Header to write.</param> /// <param name="writer">BinaryWriter wrapped stream to write to.</param> private static void Write_V8U8_DDS_Header(DDS_HEADER header, BinaryWriter writer) { // KFreon: Write magic number ("DDS") writer.Write(0x20534444); // KFreon: Write all header fields regardless of filled or not writer.Write(header.dwSize); writer.Write(header.dwFlags); writer.Write(header.dwHeight); writer.Write(header.dwWidth); writer.Write(header.dwPitchOrLinearSize); writer.Write(header.dwDepth); writer.Write(header.dwMipMapCount); // KFreon: Write reserved1 for (int i = 0; i < 11; i++) writer.Write(0); // KFreon: Write PIXELFORMAT DDS_PIXELFORMAT px = header.ddspf; writer.Write(px.dwSize); writer.Write(px.dwFlags); writer.Write(px.dwFourCC); writer.Write(px.dwRGBBitCount); writer.Write(px.dwRBitMask); writer.Write(px.dwGBitMask); writer.Write(px.dwBBitMask); writer.Write(px.dwABitMask); writer.Write(header.dwCaps); writer.Write(header.dwCaps2); writer.Write(header.dwCaps3); writer.Write(header.dwCaps4); writer.Write(header.dwReserved2); }
/// <summary> /// Builds a V8U8 DDS header from certain details. /// </summary> /// <param name="Mips">Number of mipmaps.</param> /// <param name="height">Height of image.</param> /// <param name="width">Width of image.</param> /// <returns>DDS_HEADER struct from details.</returns> private static DDS_HEADER Build_V8U8_DDS_Header(int Mips, int height, int width) { DDS_HEADER header = new DDS_HEADER(); header.dwSize = 124; header.dwFlags = 0x1 | 0x2 | 0x4 | 0x1000 | (Mips != 0 ? 0x20000 : 0x0); // Flags to denote valid fields: DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_MIPMAPCOUNT header.dwWidth = width; header.dwHeight = height; header.dwCaps = 0x1000 | 0x8 | (Mips == 0 ? 0 : 0x400000); header.dwMipMapCount = Mips == 0 ? 1 : Mips; //header.dwPitchOrLinearSize = ((width + 1) >> 1)*4; DDS_PIXELFORMAT px = new DDS_PIXELFORMAT(); px.dwSize = 32; //px.dwFlags = 0x200; px.dwFlags = 0x80000; px.dwRGBBitCount = 16; px.dwRBitMask = 255; px.dwGBitMask = 0x0000FF00; header.ddspf = px; return header; }
public static unsafe Image GetImage(string jitfile) { using (FileStream fs = new FileStream(jitfile, FileMode.Open)) { JITHEADER jitheader; byte[] jithdr = new byte[0xc]; fs.Read(jithdr, 0, jithdr.Length); fixed(byte *ptr = &jithdr[0]) { jitheader = (JITHEADER)Marshal.PtrToStructure((IntPtr)ptr, typeof(JITHEADER)); } DDS_HEADER header = new DDS_HEADER(); header.magicNumber = new byte[] { 68, 68, 83, 32 }; header.ddspf.dwSize = 32; header.dwSize = 124; header.dwHeight = jitheader.dwHeight; header.dwWidth = jitheader.dwWidth; header.ddspf.dwFlags = DWFLAGS.DDPF_FOURCC; switch (jitheader.magicNumber) { case JITSIGN.JT31: header.ddspf.dwFourCC = DWFOURCC.DXT1; break; case JITSIGN.JT32: header.ddspf.dwFourCC = DWFOURCC.DXT2; break; case JITSIGN.JT33: header.ddspf.dwFourCC = DWFOURCC.DXT3; break; case JITSIGN.JT34: header.ddspf.dwFourCC = DWFOURCC.DXT4; break; case JITSIGN.JT35: header.ddspf.dwFourCC = DWFOURCC.DXT5; break; } header.dwMipMapCount = 0; header.dwHeaderFlags = DWHEADERFLAGS.DDSD_CAPS | DWHEADERFLAGS.DDSD_HEIGHT | DWHEADERFLAGS.DDSD_WIDTH; header.dwSurfaceFlags = DWSURFACEFLAGS.DDSCAPS_TEXTURE; header.dwReserved1 = new uint[11]; header.dwReserved2 = new uint[3]; byte[] stuff = new byte[fs.Length - 0xc]; fs.Read(stuff, 0, stuff.Length); using (MemoryStream ms = new MemoryStream()) { byte[] hdr = new byte[0x80]; fixed(byte *ptr = &hdr[0]) { Marshal.StructureToPtr(header, (IntPtr)ptr, false); } ms.Write(hdr, 0, hdr.Length); ms.Write(stuff, 0, stuff.Length); return(DDSDataToBMP(ms.GetBuffer())); } } }
unsafe public static void ConvertJITToDDS(string jitfile) { using (FileStream fs = new FileStream(jitfile, FileMode.Open)) { JITHEADER jitheader; byte[] jithdr = new byte[0xc]; fs.Read(jithdr, 0, jithdr.Length); fixed(byte *ptr = &jithdr[0]) { jitheader = (JITHEADER)Marshal.PtrToStructure((IntPtr)ptr, typeof(JITHEADER)); } byte[] stuff = new byte[fs.Length - 0xc]; fs.Read(stuff, 0, stuff.Length); using (FileStream dest = new FileStream(jitfile + ".dds", FileMode.Create)) { DDS_HEADER header = new DDS_HEADER(); header.magicNumber = new byte[] { 68, 68, 83, 32 }; header.ddspf.dwSize = 32; header.dwSize = 124; header.dwHeight = jitheader.dwHeight; header.dwWidth = jitheader.dwWidth; header.ddspf.dwFlags = DWFLAGS.DDPF_FOURCC; switch (jitheader.magicNumber) { case JITSIGN.JT31: header.ddspf.dwFourCC = DWFOURCC.DXT1; break; case JITSIGN.JT32: header.ddspf.dwFourCC = DWFOURCC.DXT2; break; case JITSIGN.JT33: header.ddspf.dwFourCC = DWFOURCC.DXT3; break; case JITSIGN.JT34: header.ddspf.dwFourCC = DWFOURCC.DXT4; break; case JITSIGN.JT35: header.ddspf.dwFourCC = DWFOURCC.DXT5; break; } header.dwMipMapCount = 0; //header.dwPitchOrLinearSize = 1048576; header.dwHeaderFlags = DWHEADERFLAGS.DDSD_CAPS | DWHEADERFLAGS.DDSD_HEIGHT | DWHEADERFLAGS.DDSD_WIDTH; header.dwSurfaceFlags = DWSURFACEFLAGS.DDSCAPS_TEXTURE; header.dwReserved1 = new uint[11]; header.dwReserved2 = new uint[3]; byte[] hdr = new byte[0x80]; fixed(byte *ptr = &hdr[0]) { Marshal.StructureToPtr(header, (IntPtr)ptr, false); } dest.Write(hdr, 0, hdr.Length); dest.Write(stuff, 0, stuff.Length); } } }
static Resource CreateTextureFromDDS(Device d3dDevice, DDS_HEADER header, DDS_HEADER_DXT10?header10, byte[] bitData, int offset, int maxsize, out bool isCubeMap) { int width = header.width; int height = header.height; int depth = header.depth; ResourceDimension resDim = ResourceDimension.Unknown; int arraySize = 1; Format format = Format.Unknown; isCubeMap = false; int mipCount = header.mipMapCount; if (0 == mipCount) { mipCount = 1; } if (((header.ddspf.flags & DDS_FOURCC) > 0) && (MAKEFOURCC('D', 'X', '1', '0') == header.ddspf.fourCC)) { DDS_HEADER_DXT10 d3d10ext = header10.Value; arraySize = d3d10ext.arraySize; if (arraySize == 0) { throw new Exception(); } if (BitsPerPixel(d3d10ext.dxgiFormat) == 0) { throw new Exception(); } format = d3d10ext.dxgiFormat; switch ((ResourceDimension)d3d10ext.resourceDimension) { case ResourceDimension.Texture1D: // D3DX writes 1D textures with a fixed Height of 1 if ((header.flags & DDS_HEIGHT) > 0 && height != 1) { throw new Exception(); } height = depth = 1; break; case ResourceDimension.Texture2D: //D3D11_RESOURCE_MISC_TEXTURECUBE if ((d3d10ext.miscFlag & 0x4) > 0) { arraySize *= 6; isCubeMap = true; } depth = 1; break; case ResourceDimension.Texture3D: if (!((header.flags & DDS_HEADER_FLAGS_VOLUME) > 0)) { throw new Exception(); } if (arraySize > 1) { throw new Exception(); } break; default: throw new Exception(); } resDim = (ResourceDimension)d3d10ext.resourceDimension; } else { format = GetDXGIFormat(header.ddspf); if (format == Format.Unknown) { throw new Exception(); } if ((header.flags & DDS_HEADER_FLAGS_VOLUME) > 0) { resDim = ResourceDimension.Texture3D; } else { if ((header.caps2 & DDS_CUBEMAP) > 0) { // We require all six faces to be defined if ((header.caps2 & DDS_CUBEMAP_ALLFACES) != DDS_CUBEMAP_ALLFACES) { throw new Exception(); } arraySize = 6; isCubeMap = true; } depth = 1; resDim = ResourceDimension.Texture2D; } } var resource = d3dDevice.CreateCommittedResource(new HeapProperties(CpuPageProperty.WriteBack, MemoryPool.L0), HeapFlags.None, new ResourceDescription() { //Alignment = -1, Dimension = resDim, DepthOrArraySize = (short)arraySize, Flags = ResourceFlags.None, Format = format, Height = height, Layout = TextureLayout.Unknown, MipLevels = (short)mipCount, SampleDescription = new SampleDescription(1, 0), Width = width, }, ResourceStates.GenericRead); FillInitData(resource, width, height, depth, mipCount, arraySize, format, 0, 0, bitData, offset); return(resource); }
/// <summary> /// Parses the data from a DDS byte array. (Can also read just the header only) /// </summary> /// <param name="fileData"></param> /// <param name="headerOnly"></param> private void GetData(byte[] fileData, bool headerOnly) { ConsoleFunctions.SetConsoleColor(ConsoleColor.Black, ConsoleColor.White); Console.WriteLine("Total Source Texture Byte Size = {0}", fileData.Length); //which byte offset we are on for the source texture (will be changed as we go through the file) byte[] headerBytes = ByteFunctions.AllocateBytes(124, fileData, 4); //skip past the 'DDS ' //this will automatically read all of the byte data in the header header = DDS_Functions.GetHeaderFromBytes(headerBytes); ConsoleFunctions.SetConsoleColor(ConsoleColor.Black, ConsoleColor.White); Console.WriteLine("DDS Height = {0}", header.dwHeight); Console.WriteLine("DDS Width = {0}", header.dwWidth); Console.WriteLine("DDS Mip Map Count = {0}", header.dwMipMapCount); Console.WriteLine("DDS Compression = {0}", header.ddspf.dwFourCC); if (headerOnly) { return; } //--------------------------EXTRACT DDS TEXTURE DATA-------------------------- //calculate dds header length (we add 4 because we skipped the 4 bytes which contain the ddsPrefix, it isn't necessary to parse this data) uint ddsHeaderLength = 4 + header.dwSize; //calculate the length of just the dds texture data uint ddsTextureDataLength = (uint)sourceFileData.Length - ddsHeaderLength; //allocate a byte array of dds texture length byte[] ddsTextureData = new byte[ddsTextureDataLength]; //copy the data from the source byte array past the header (so we are only getting texture data) Array.Copy(sourceFileData, ddsHeaderLength, ddsTextureData, 0, ddsTextureData.Length); //if there are no mip maps if (header.dwMipMapCount <= 1) { textureData = new(); textureData.Add(ddsTextureData); Console.WriteLine("DDS Texture Byte Size = {0}", textureData[0].Length); } else //if there are mip maps { //get mip resolutions //calculated mip resolutions [Pixel Value, Width or Height (0 or 1)] mipMapResolutions = DDS_Functions.DDS_CalculateMipResolutions(header.dwMipMapCount, header.dwWidth, header.dwHeight); //get byte sizes uint[] byteSizes = DDS_Functions.DDS_GetImageByteSizes(mipMapResolutions, DDS_Functions.DDS_CompressionBool(header)); textureData = new(); int test = ddsTextureData.Length; int offset = 0; for (int i = 0; i < byteSizes.Length; i++) { byte[] temp = new byte[byteSizes[i]]; //issue length Array.Copy(ddsTextureData, offset, temp, 0, temp.Length); offset += temp.Length - 1; textureData.Add(temp); test -= (int)byteSizes[i]; } } }
/// <summary> /// Gets Format of image. /// </summary> /// <param name="imgData">Stream containing entire image. NOT just pixels.</param> /// <param name="extension">Type of file.</param> /// <returns>Format of image.</returns> public static Format ParseFormat(Stream imgData, SupportedExtensions extension, ref DDS_HEADER header) { switch (extension) { case SupportedExtensions.BMP: return(new Format(ImageEngineFormat.BMP)); case SupportedExtensions.DDS: return(ParseDDSFormat(imgData, out header)); case SupportedExtensions.JPG: return(new Format(ImageEngineFormat.JPG)); case SupportedExtensions.PNG: return(new Format(ImageEngineFormat.PNG)); case SupportedExtensions.TGA: return(new Format(ImageEngineFormat.TGA)); } return(new Format()); }
public static unsafe void ConvertJITToDDS(string jitfile) { using (FileStream fs = new FileStream(jitfile, FileMode.Open)) { JITHEADER jitheader; byte[] jithdr = new byte[0xc]; fs.Read(jithdr, 0, jithdr.Length); fixed (byte* ptr = &jithdr[0]) { jitheader = (JITHEADER)Marshal.PtrToStructure((IntPtr)ptr, typeof(JITHEADER)); } byte[] stuff = new byte[fs.Length - 0xc]; fs.Read(stuff, 0, stuff.Length); using (FileStream dest = new FileStream(jitfile + ".dds", FileMode.Create)) { DDS_HEADER header = new DDS_HEADER(); header.magicNumber = new byte[] { 68, 68, 83, 32 }; header.ddspf.dwSize = 32; header.dwSize = 124; header.dwHeight = jitheader.dwHeight; header.dwWidth = jitheader.dwWidth; header.ddspf.dwFlags = DWFLAGS.DDPF_FOURCC; switch (jitheader.magicNumber) { case JITSIGN.JT31: header.ddspf.dwFourCC = DWFOURCC.DXT1; break; case JITSIGN.JT32: header.ddspf.dwFourCC = DWFOURCC.DXT2; break; case JITSIGN.JT33: header.ddspf.dwFourCC = DWFOURCC.DXT3; break; case JITSIGN.JT34: header.ddspf.dwFourCC = DWFOURCC.DXT4; break; case JITSIGN.JT35: header.ddspf.dwFourCC = DWFOURCC.DXT5; break; } header.dwMipMapCount = 0; //header.dwPitchOrLinearSize = 1048576; header.dwHeaderFlags = DWHEADERFLAGS.DDSD_CAPS | DWHEADERFLAGS.DDSD_HEIGHT | DWHEADERFLAGS.DDSD_WIDTH; header.dwSurfaceFlags = DWSURFACEFLAGS.DDSCAPS_TEXTURE; header.dwReserved1 = new uint[11]; header.dwReserved2 = new uint[3]; byte[] hdr = new byte[0x80]; fixed (byte* ptr = &hdr[0]) { Marshal.StructureToPtr(header, (IntPtr)ptr, false); } dest.Write(hdr, 0, hdr.Length); dest.Write(stuff, 0, stuff.Length); } } }
public const int DDS_DX10 = 808540228; //From "DX10" public static Texture2D LoadDDSFile(Stream data) { Texture2D texture = null; Color[] imageColors = null; DDS_HEADER header = new DDS_HEADER(); DDS_HEADER_10 header_10 = new DDS_HEADER_10(); int magic = DataParser.ReadInt(data); if (magic == DDS_) { header.dwSize = DataParser.ReadInt(data); //0 + 4 = 4 header.dwFlags = (DWFlags)DataParser.ReadInt(data); //4 + 4 = 8 header.dwHeight = DataParser.ReadInt(data); //8 + 4 = 12 header.dwWidth = DataParser.ReadInt(data); //12 + 4 = 16 header.dwPitchOrLinearSize = DataParser.ReadInt(data); //16 + 4 = 20 header.dwDepth = DataParser.ReadInt(data); //20 + 4 = 24 header.dwMipMapCount = DataParser.ReadInt(data); //24 + 4 = 28 header.dwReserved1 = new int[11]; //28 + 44 = 72 for (int i = 0; i < header.dwReserved1.Length; i++) { header.dwReserved1[i] = DataParser.ReadInt(data); } header.ddspf.dwSize = DataParser.ReadInt(data); //72 + 4 = 76 header.ddspf.dwFlags = (PIXELFORMAT_DWFlags)DataParser.ReadInt(data); //76 + 4 = 80 header.ddspf.dwFourCC = DataParser.ReadInt(data); //80 + 4 = 84 header.ddspf.dwRGBBitCount = DataParser.ReadInt(data); //84 + 4 = 88 header.ddspf.dwRBitMask = DataParser.ReadInt(data); //88 + 4 = 92 header.ddspf.dwGBitMask = DataParser.ReadInt(data); //92 + 4 = 96 header.ddspf.dwBBitMask = DataParser.ReadInt(data); //96 + 4 = 100 header.ddspf.dwABitMask = DataParser.ReadInt(data); //100 + 4 = 104 header.dwCaps = DataParser.ReadInt(data); //104 + 4 = 108 header.dwCaps2 = DataParser.ReadInt(data); //108 + 4 = 112 header.dwCaps3 = DataParser.ReadInt(data); //112 + 4 = 116 header.dwCaps4 = DataParser.ReadInt(data); //116 + 4 = 120 header.dwReserved2 = DataParser.ReadInt(data); //120 + 4 = 124 bool isCompressed = (header.ddspf.dwFlags & PIXELFORMAT_DWFlags.DDPF_FOURCC) != 0; if (isCompressed && header.ddspf.dwFourCC == DDS_DX10) { Debug.Log(nameof(DDSLoader) + ": Reading extra header"); header_10.dxgiFormat = (DXGI_FORMAT)DataParser.ReadInt(data); header_10.resourceDimension = (D3D10_RESOURCE_DIMENSION)DataParser.ReadInt(data); header_10.miscFlag = DataParser.ReadUInt(data); header_10.arraySize = DataParser.ReadUInt(data); header_10.miscFlags2 = DataParser.ReadUInt(data); } imageColors = Texture2DHelpers.DecompressRawBytes(data, (ushort)header.dwWidth, (ushort)header.dwHeight, GetDDSFormat(header)); Texture2DHelpers.FlipVertical(imageColors, (ushort)header.dwWidth, (ushort)header.dwHeight); } else { Debug.LogError(nameof(DDSLoader) + ": Invalid DDS magic, expected " + DDS_ + " got " + magic); } if (imageColors != null) { texture = new Texture2D(header.dwWidth, header.dwHeight); if (imageColors != null) { texture.SetPixels(imageColors); } texture.Apply(); } return(texture); }
public unsafe static void SaveDDS(IFilesystemEntry file, string path = null) { var filesystem = file.Filesystem; var filesystemManager = filesystem.FilesystemManager; var searchName = file.FullPath; var rawData = file.GetData(); BinaryBlobReader reader = new BinaryBlobReader(rawData, 0); bool isDX10 = false; UInt32 dwMagic = reader.ReadUInt32(); if (dwMagic != uchar32("DDS ")) { throw new Exception("Invalid dds file"); } DDS_HEADER header = reader.Read <DDS_HEADER>(); DDS_HEADER_DXT10 header10; if (header.dwSize != sizeof(DDS_HEADER)) { throw new Exception("Invalid header size"); } bool fourCCFlag = (header.ddspf.dwFlags & DDS_PIXELFORMAT_FLAGS.DDPF_FOURCC) != 0; if (fourCCFlag) { isDX10 = header.ddspf.dwFourCC == uchar32("DX10"); if (isDX10) { header10 = reader.Read <DDS_HEADER_DXT10>(); } } var max_dimension = Math.Min(header.dwWidth, header.dwHeight); var mips = (int)Math.Log((double)max_dimension, 2.0); var extra_mips = Math.Max(mips - 4, 0); // hack: there must be a better way to tell bool isCubemap = file.Name.EndsWith("_cm_diff.dds", StringComparison.OrdinalIgnoreCase); if (isCubemap) { var index = searchName.IndexOf("_cm_diff.dds", StringComparison.OrdinalIgnoreCase); var prefix = searchName.Substring(0, index); var newSearchName = prefix + "_cm.dds"; searchName = newSearchName; } var isNormal = false; isNormal |= searchName.EndsWith("ddna.dds", StringComparison.OrdinalIgnoreCase); isNormal |= searchName.EndsWith("ddn.dds", StringComparison.OrdinalIgnoreCase); byte[] allData; { List <byte> allDataBuffer = new List <byte>(rawData); List <byte> alphaDataBuffer = new List <byte>(0); var chunkFileAlphaPath = $"{searchName}.a"; var chunkFileAlpha = filesystem[chunkFileAlphaPath]; if (chunkFileAlpha != null) //todo programatically determine alpha existance { var dataChunkAlpha = chunkFileAlpha.GetData(); BinaryBlobReader alphaReader = new BinaryBlobReader(dataChunkAlpha, 0); DDS_HEADER alphaHeader = reader.Read <DDS_HEADER>(); DDS_HEADER_DXT10 alphaHeader10; if (isDX10) { alphaHeader10 = reader.Read <DDS_HEADER_DXT10>(); } var remainderBytes = reader.Read <byte>((int)(dataChunkAlpha.LongLength - reader.Position)); alphaDataBuffer.AddRange(remainderBytes); //alphaDataBuffer.AddRange(dataChunkAlpha); for (int i = 1; i <= extra_mips; i++) { chunkFileAlphaPath = $"{searchName}.{i}a"; chunkFileAlpha = filesystem[chunkFileAlphaPath]; dataChunkAlpha = chunkFileAlpha.GetData(); alphaDataBuffer.AddRange(dataChunkAlpha); } } for (int i = 1; i <= extra_mips; i++) { var chunkFilePath = $"{searchName}.{i}"; var chunkFile = filesystem[chunkFilePath]; if (chunkFile == null) { //throw new Exception($"Data chunk {chunkFilePath} missing!"); continue; // this is valid for some files } var dataChunk = chunkFile.GetData(); allDataBuffer.AddRange(dataChunk); } allDataBuffer.AddRange(alphaDataBuffer); allData = allDataBuffer.ToArray(); } string fullPath; var baseDirectory = path ?? filesystemManager.DirectoryName; if (file.IsDirectory) { fullPath = Path.Combine(baseDirectory, searchName); } else { fullPath = path ?? Path.Combine(baseDirectory, searchName); } var fullDirectory = Path.GetDirectoryName(fullPath); Directory.CreateDirectory(fullDirectory); using (FileStream fs = new FileStream(fullPath, FileMode.Create, FileAccess.Write)) { fs.Write(allData, 0, allData.Length); } if (!isCubemap) { var tiffPath = Path.ChangeExtension(fullPath, ".tiff"); try { var tiffData = ImageProcessing.DDS.Convert(allData, isNormal); using (FileStream fs = new FileStream(tiffPath, FileMode.Create, FileAccess.Write)) { fs.Write(tiffData, 0, tiffData.Length); } } catch (Exception e) { MainWindow.SetStatus($"Failed to save TIFF {tiffPath} | {e.Message}"); } } }
public static Format TextureInfo(byte[] data) { // bool isCubeMap; // Validate DDS file in memory DDS_HEADER header = new DDS_HEADER(); int ddsHeaderSize = Marshal.SizeOf(header); int ddspfSize = Marshal.SizeOf(new DDS_PIXELFORMAT()); int ddsHeader10Size = Marshal.SizeOf(new DDS_HEADER_DXT10()); if (data.Length < (sizeof(uint) + ddsHeaderSize)) { throw new Exception(); } //first is magic number int dwMagicNumber = BitConverter.ToInt32(data, 0); if (dwMagicNumber != DDS_MAGIC) { throw new Exception(); } header = ByteArrayToStructure <DDS_HEADER>(data, 4, ddsHeaderSize); // Verify header to validate DDS file if (header.size != ddsHeaderSize || header.ddspf.size != ddspfSize) { throw new Exception(); } // Check for DX10 extension bool bDXT10Header = false; if (((header.ddspf.flags & DDS_FOURCC) > 0) && (MAKEFOURCC('D', 'X', '1', '0') == header.ddspf.fourCC)) { // Must be long enough for both headers and magic value if (data.Length < (ddsHeaderSize + 4 + ddsHeader10Size)) { throw new Exception(); } bDXT10Header = true; } int offset = 4 + ddsHeaderSize + (bDXT10Header ? ddsHeader10Size : 0); // return InitTextureFromData(device, context, header, null, data, offset, 0, out isCubeMap); // return InitTextureFromData(device, context, header, null, data, offset, 0, out isCubeMap); // return InitTextureFromData(device, context, header, null, data, offset, 0, out isCubeMap); DDS_HEADER_DXT10?header10 = null; if (bDXT10Header) { header10 = ByteArrayToStructure <DDS_HEADER_DXT10>(data, 4 + ddsHeaderSize, ddsHeader10Size); } int width = header.width; int height = header.height; int depth = header.depth; D3D10_RESOURCE_DIMENSION resDim = D3D10_RESOURCE_DIMENSION.UNKNOWN; int arraySize = 1; Format format = Format.UNKNOWN; // isCubeMap = false; int mipCount = header.mipMapCount; if (0 == mipCount) { mipCount = 1; } if (((header.ddspf.flags & DDS_FOURCC) > 0) && (MAKEFOURCC('D', 'X', '1', '0') == header.ddspf.fourCC)) { DDS_HEADER_DXT10 d3d10ext = header10.Value; arraySize = d3d10ext.arraySize; if (arraySize == 0) { throw new Exception(); } if (BitsPerPixel(d3d10ext.dxgiFormat) == 0) { throw new Exception(); } format = d3d10ext.dxgiFormat; switch ((D3D10_RESOURCE_DIMENSION)d3d10ext.resourceDimension) { case D3D10_RESOURCE_DIMENSION.TEXTURE1D: // D3DX writes 1D textures with a fixed Height of 1 if ((header.flags & DDS_HEIGHT) > 0 && height != 1) { throw new Exception(); } height = depth = 1; break; case D3D10_RESOURCE_DIMENSION.TEXTURE2D: //D3D11_RESOURCE_MISC_TEXTURECUBE if ((d3d10ext.miscFlag & 0x4) > 0) { arraySize *= 6; // isCubeMap = true; } depth = 1; break; case D3D10_RESOURCE_DIMENSION.TEXTURE3D: if (!((header.flags & DDS_HEADER_FLAGS_VOLUME) > 0)) { throw new Exception(); } if (arraySize > 1) { throw new Exception(); } break; default: throw new Exception(); } resDim = (D3D10_RESOURCE_DIMENSION)d3d10ext.resourceDimension; } else { format = GetDXGIFormat(header.ddspf); if (format == Format.UNKNOWN) { throw new Exception(); } if ((header.flags & DDS_HEADER_FLAGS_VOLUME) > 0) { resDim = D3D10_RESOURCE_DIMENSION.TEXTURE3D; } else { if ((header.caps2 & DDS_CUBEMAP) > 0) { // We require all six faces to be defined if ((header.caps2 & DDS_CUBEMAP_ALLFACES) != DDS_CUBEMAP_ALLFACES) { throw new Exception(); } arraySize = 6; // isCubeMap = true; } depth = 1; resDim = D3D10_RESOURCE_DIMENSION.TEXTURE2D; } } return(format); }
private void LoadImage(Stream stream) { stream.Seek(0, SeekOrigin.Begin); BinaryReader r = new BinaryReader(stream); int dwMagic = r.ReadInt32(); if (dwMagic != 0x20534444) throw new Exception("This is not a DDS! Magic number wrong."); DDS_HEADER header = new DDS_HEADER(); Read_DDS_HEADER(header, r); if (((header.ddspf.dwFlags & 0x00000004) != 0) && (header.ddspf.dwFourCC == 0x30315844 /*DX10*/)) { throw new Exception("DX10 not supported yet!"); } if (header.ddspf.dwFourCC != 0) throw new InvalidDataException("DDS not V8U8."); int mipMapCount = 1; if ((header.dwFlags & 0x00020000) != 0) mipMapCount = header.dwMipMapCount; int w = 0; int h = 0; double bytePerPixel = 2; MipMaps = new MipMap[mipMapCount]; // KFreon: Get mips for (int i = 0; i < mipMapCount; i++) { w = (int)(header.dwWidth / Math.Pow(2, i)); h = (int)(header.dwHeight / Math.Pow(2, i)); int mipMapBytes = (int)(w * h * bytePerPixel); MipMaps[i] = new MipMap(r.ReadBytes(mipMapBytes), w, h); } Width = header.dwWidth; Height = header.dwHeight; }
public static unsafe Image GetImage(string jitfile) { using (FileStream fs = new FileStream(jitfile, FileMode.Open)) { JITHEADER jitheader; byte[] jithdr = new byte[0xc]; fs.Read(jithdr, 0, jithdr.Length); fixed (byte* ptr = &jithdr[0]) { jitheader = (JITHEADER)Marshal.PtrToStructure((IntPtr)ptr, typeof(JITHEADER)); } DDS_HEADER header = new DDS_HEADER(); header.magicNumber = new byte[] { 68, 68, 83, 32 }; header.ddspf.dwSize = 32; header.dwSize = 124; header.dwHeight = jitheader.dwHeight; header.dwWidth = jitheader.dwWidth; header.ddspf.dwFlags = DWFLAGS.DDPF_FOURCC; switch (jitheader.magicNumber) { case JITSIGN.JT31: header.ddspf.dwFourCC = DWFOURCC.DXT1; break; case JITSIGN.JT32: header.ddspf.dwFourCC = DWFOURCC.DXT2; break; case JITSIGN.JT33: header.ddspf.dwFourCC = DWFOURCC.DXT3; break; case JITSIGN.JT34: header.ddspf.dwFourCC = DWFOURCC.DXT4; break; case JITSIGN.JT35: header.ddspf.dwFourCC = DWFOURCC.DXT5; break; } header.dwMipMapCount = 0; header.dwHeaderFlags = DWHEADERFLAGS.DDSD_CAPS | DWHEADERFLAGS.DDSD_HEIGHT | DWHEADERFLAGS.DDSD_WIDTH; header.dwSurfaceFlags = DWSURFACEFLAGS.DDSCAPS_TEXTURE; header.dwReserved1 = new uint[11]; header.dwReserved2 = new uint[3]; byte[] stuff = new byte[fs.Length - 0xc]; fs.Read(stuff, 0, stuff.Length); using (MemoryStream ms = new MemoryStream()) { byte[] hdr = new byte[0x80]; fixed (byte* ptr = &hdr[0]) { Marshal.StructureToPtr(header, (IntPtr)ptr, false); } ms.Write(hdr, 0, hdr.Length); ms.Write(stuff, 0, stuff.Length); return DDSDataToBMP(ms.GetBuffer()); } } }
/// <summary> /// Reads DDS format from DDS Header. /// Not guaranteed to work. Format 'optional' in header. /// </summary> /// <param name="stream">Stream containing full image file. NOT just pixels.</param> /// <param name="header">DDS Header information.</param> /// <returns>Format of DDS.</returns> internal static Format ParseDDSFormat(Stream stream, out DDS_HEADER header) { Format format = new Format(ImageEngineFormat.DDS_ARGB); stream.Seek(0, SeekOrigin.Begin); using (BinaryReader reader = new BinaryReader(stream, Encoding.Default, true)) { header = null; // KFreon: Check image is a DDS int Magic = reader.ReadInt32(); if (Magic != 0x20534444) { return(new Format()); // KFreon: Not a DDS } header = new DDS_HEADER(); Read_DDS_HEADER(header, reader); if (((header.ddspf.dwFlags & 0x00000004) != 0) && (header.ddspf.dwFourCC == 0x30315844 /*DX10*/)) { throw new Exception("DX10 not supported yet!"); } format = ImageFormats.ParseFourCC(header.ddspf.dwFourCC); if (format.SurfaceFormat == ImageEngineFormat.Unknown || format.SurfaceFormat == ImageEngineFormat.DDS_ARGB) { // KFreon: Apparently all these flags mean it's a V8U8 image... if (header.ddspf.dwRGBBitCount == 0x10 && header.ddspf.dwRBitMask == 0xFF && header.ddspf.dwGBitMask == 0xFF00 && header.ddspf.dwBBitMask == 0x00 && header.ddspf.dwABitMask == 0x00) { format = new Format(ImageEngineFormat.DDS_V8U8); // KFreon: V8U8 } // KFreon: Test for L8/G8 else if (header.ddspf.dwABitMask == 0 && header.ddspf.dwBBitMask == 0 && header.ddspf.dwGBitMask == 0 && header.ddspf.dwRBitMask == 255 && header.ddspf.dwFlags == 131072 && header.ddspf.dwSize == 32 && header.ddspf.dwRGBBitCount == 8) { format = new Format(ImageEngineFormat.DDS_G8_L8); } // KFreon: A8L8. This can probably be something else as well, but it seems to work for now else if (header.ddspf.dwRGBBitCount == 16) { format = new Format(ImageEngineFormat.DDS_A8L8); } // KFreon: RGB test. else if (header.ddspf.dwRGBBitCount == 24) { format = new Format(ImageEngineFormat.DDS_RGB); } } } return(format); }
/// <summary> /// Create a DDS file from a D3DTX /// </summary> /// <param name="d3dtx"></param> public DDS_Master(D3DTX_Master d3dtx) { header = DDS_Functions.GetPresetHeader(); T3SurfaceFormat surfaceFormat = T3SurfaceFormat.eSurface_DXT1; if (d3dtx.d3dtx4 != null) { header.dwWidth = d3dtx.d3dtx4.mWidth; header.dwHeight = d3dtx.d3dtx4.mHeight; header.dwMipMapCount = d3dtx.d3dtx4.mNumMipLevels; surfaceFormat = d3dtx.d3dtx4.mSurfaceFormat; } else if (d3dtx.d3dtx5 != null) { header.dwWidth = d3dtx.d3dtx5.mWidth; header.dwHeight = d3dtx.d3dtx5.mHeight; header.dwMipMapCount = d3dtx.d3dtx5.mNumMipLevels; surfaceFormat = d3dtx.d3dtx5.mSurfaceFormat; } else if (d3dtx.d3dtx6 != null) { header.dwWidth = d3dtx.d3dtx6.mWidth; header.dwHeight = d3dtx.d3dtx6.mHeight; header.dwMipMapCount = d3dtx.d3dtx6.mNumMipLevels; surfaceFormat = d3dtx.d3dtx6.mSurfaceFormat; } else if (d3dtx.d3dtx7 != null) { header.dwWidth = d3dtx.d3dtx7.mWidth; header.dwHeight = d3dtx.d3dtx7.mHeight; header.dwMipMapCount = d3dtx.d3dtx7.mNumMipLevels; //header.dwDepth = d3dtx.d3dtx7.mDepth; surfaceFormat = d3dtx.d3dtx7.mSurfaceFormat; } else if (d3dtx.d3dtx8 != null) { header.dwWidth = d3dtx.d3dtx8.mWidth; header.dwHeight = d3dtx.d3dtx8.mHeight; header.dwMipMapCount = d3dtx.d3dtx8.mNumMipLevels; header.dwDepth = d3dtx.d3dtx8.mDepth; surfaceFormat = d3dtx.d3dtx8.mSurfaceFormat; } else if (d3dtx.d3dtx9 != null) { header.dwWidth = d3dtx.d3dtx9.mWidth; header.dwHeight = d3dtx.d3dtx9.mHeight; header.dwMipMapCount = d3dtx.d3dtx9.mNumMipLevels; header.dwDepth = d3dtx.d3dtx9.mDepth; surfaceFormat = d3dtx.d3dtx9.mSurfaceFormat; } DDS_PIXELFORMAT new_ddspf = new DDS_PIXELFORMAT(); new_ddspf.dwFourCC = DDS_Functions.Get_FourCC_FromTellale(surfaceFormat); switch (surfaceFormat) { case Telltale.T3SurfaceFormat.eSurface_A8: new_ddspf.dwABitMask = 255; header.dwCaps = 4198408; //DDSCAPS_COMPLEX | DDSCAPS_TEXTURE | DDSCAPS_MIPMAP break; case Telltale.T3SurfaceFormat.eSurface_ARGB8: new_ddspf.dwABitMask = 255; new_ddspf.dwRBitMask = 255; new_ddspf.dwGBitMask = 255; new_ddspf.dwBBitMask = 255; header.dwCaps = 4198408; //DDSCAPS_COMPLEX | DDSCAPS_TEXTURE | DDSCAPS_MIPMAP break; } header.ddspf = new_ddspf; }
static bool? IsV8U8(Stream stream) { stream.Seek(0, SeekOrigin.Begin); using (BinaryReader r = new BinaryReader(stream, Encoding.Default, true)) { int dwMagic = r.ReadInt32(); if (dwMagic != 0x20534444) return null; DDS_HEADER header = new DDS_HEADER(); Read_DDS_HEADER(header, r); if (((header.ddspf.dwFlags & 0x00000004) != 0) && (header.ddspf.dwFourCC == 0x30315844 /*DX10*/)) { throw new Exception("DX10 not supported yet!"); } return header.ddspf.dwRGBBitCount == 0x10 && header.ddspf.dwRBitMask == 0xFF && header.ddspf.dwGBitMask == 0xFF00 && header.ddspf.dwBBitMask == 0x00 && header.ddspf.dwABitMask == 0x00; } }
private static ShaderResourceView InitTextureFromData(Device d3dDevice, DeviceContext context, DDS_HEADER header, DDS_HEADER_DXT10?header10, byte[] bitData, int offset, int maxsize, out bool isCubeMap) { int width = header.width; int height = header.height; int depth = header.depth; ResourceDimension resDim = ResourceDimension.Unknown; int arraySize = 1; Format format = Format.Unknown; isCubeMap = false; int mipCount = header.mipMapCount; if (0 == mipCount) { mipCount = 1; } if (((header.ddspf.flags & DDS_FOURCC) > 0) && (MAKEFOURCC('D', 'X', '1', '0') == header.ddspf.fourCC)) { DDS_HEADER_DXT10 d3d10ext = header10.Value; arraySize = d3d10ext.arraySize; if (arraySize == 0) { throw new Exception(); } if (BitsPerPixel(d3d10ext.dxgiFormat) == 0) { throw new Exception(); } format = d3d10ext.dxgiFormat; switch ((ResourceDimension)d3d10ext.resourceDimension) { case ResourceDimension.Texture1D: // D3DX writes 1D textures with a fixed Height of 1 if ((header.flags & DDS_HEIGHT) > 0 && height != 1) { throw new Exception(); } height = depth = 1; break; case ResourceDimension.Texture2D: //D3D11_RESOURCE_MISC_TEXTURECUBE if ((d3d10ext.miscFlag & 0x4) > 0) { arraySize *= 6; isCubeMap = true; } depth = 1; break; case ResourceDimension.Texture3D: if (!((header.flags & DDS_HEADER_FLAGS_VOLUME) > 0)) { throw new Exception(); } if (arraySize > 1) { throw new Exception(); } break; default: throw new Exception(); } resDim = (ResourceDimension)d3d10ext.resourceDimension; } else { format = GetDXGIFormat(header.ddspf); if (format == Format.Unknown) { throw new Exception(); } if ((header.flags & DDS_HEADER_FLAGS_VOLUME) > 0) { resDim = ResourceDimension.Texture3D; } else { if ((header.caps2 & DDS_CUBEMAP) > 0) { // We require all six faces to be defined if ((header.caps2 & DDS_CUBEMAP_ALLFACES) != DDS_CUBEMAP_ALLFACES) { throw new Exception(); } arraySize = 6; isCubeMap = true; } depth = 1; resDim = ResourceDimension.Texture2D; } } Resource resource = null; GCHandle pinnedArray = GCHandle.Alloc(bitData, GCHandleType.Pinned); IntPtr pointer = pinnedArray.AddrOfPinnedObject(); var boxes = FillInitData(pointer, width, height, depth, mipCount, arraySize, format, 0, 0, offset); switch (resDim) { case ResourceDimension.Unknown: break; case ResourceDimension.Buffer: break; case ResourceDimension.Texture1D: resource = new Texture1D(d3dDevice, new Texture1DDescription() { BindFlags = BindFlags.ShaderResource, Format = format, ArraySize = arraySize, Width = width, CpuAccessFlags = CpuAccessFlags.None, MipLevels = mipCount, OptionFlags = ResourceOptionFlags.None, Usage = ResourceUsage.Default, }, boxes.ToArray()); break; case ResourceDimension.Texture2D: resource = new Texture2D(d3dDevice, new Texture2DDescription() { ArraySize = arraySize, BindFlags = BindFlags.ShaderResource, Format = format, Height = height, Width = width, CpuAccessFlags = CpuAccessFlags.None, MipLevels = mipCount, OptionFlags = ResourceOptionFlags.None, SampleDescription = new SampleDescription(1, 0), Usage = ResourceUsage.Default }, boxes.ToArray()); break; case ResourceDimension.Texture3D: resource = new Texture3D(d3dDevice, new Texture3DDescription() { Depth = depth, BindFlags = BindFlags.ShaderResource, Format = format, Height = height, Width = width, CpuAccessFlags = CpuAccessFlags.None, MipLevels = mipCount, OptionFlags = ResourceOptionFlags.None, Usage = ResourceUsage.Default }, boxes.ToArray()); break; default: break; } pinnedArray.Free(); var resourceView = new ShaderResourceView(d3dDevice, resource); return(resourceView); }
static byte[][] LoadSurface(ref DDS_HEADER header, BinaryReader reader, out SurfaceFormat fmt, out int width, out int height) { width = (int)header.dwWidth; height = (int)header.dwHeight; int mipMapCount = 1; if (CheckFlag(header.dwCaps, DDSCAPS_MIPMAP) || CheckFlag(header.dwFlags, DDSD_MIPMAPCOUNT)) { mipMapCount = (int)header.dwMipMapCount; } var sfc = new List <byte[]>(); fmt = GetSurfaceFormat(ref header); int w = width, h = height; for (int i = 0; i < mipMapCount; i++) { var length = GetSurfaceBytes(ref header, w, h); var bytes = GetSurfaceBytes(ref header, w, h); byte[] data; if (fmt == SurfaceFormat.Color && header.ddspf.dwRGBBitCount == 24) { data = new byte[bytes]; for (int j = 0; j < bytes; j += 4) { data[j] = reader.ReadByte(); data[j + 1] = reader.ReadByte(); data[j + 2] = reader.ReadByte(); } } else { data = reader.ReadBytes(bytes); } //If no alpha if (fmt == SurfaceFormat.Color && header.ddspf.dwABitMask == 0) { for (int px = 0; px < bytes; px += 4) { data[px + 3] = 255; } } //Swap channels if needed if (fmt == SurfaceFormat.Color && header.ddspf.dwRBitMask == 0xff0000) { for (int px = 0; px < bytes; px += 4) { var g = data[px]; var b = data[px + 2]; data[px] = b; data[px + 2] = g; } } sfc.Add(data); w /= 2; h /= 2; if (w < 1) { w = 1; } if (h < 1) { h = 1; } } return(sfc.ToArray()); }
/// <summary> /// Gets .dds texture data along with the .dds header. /// </summary> /// <returns>.dds texture as a byte array.</returns> public override unsafe byte[] GetDDSArray() { byte[] data; if (this._compression == EAComp.P8_08) { data = new byte[this.Size * 4 + 0x80]; var copy = Palette.P8toRGBA(this.Data); Buffer.BlockCopy(copy, 0, data, 0x80, copy.Length); } else { data = new byte[this.Data.Length + 0x80]; Buffer.BlockCopy(this.Data, 0, data, 0x80, this.Data.Length); } // Initialize header first var DDSHeader = new DDS_HEADER(); DDSHeader.dwFlags = DDS_HEADER_FLAGS.TEXTURE; // add texture definition DDSHeader.dwFlags += DDS_HEADER_FLAGS.MIPMAP; // add mipmap definition if (this._compression == EAComp.RGBA_08 || this._compression == EAComp.P8_08) { DDSHeader.dwFlags += DDS_HEADER_FLAGS.PITCH; // add pitch for uncompressed } else { DDSHeader.dwFlags += DDS_HEADER_FLAGS.LINEARSIZE; // add linearsize for compressed } DDSHeader.dwHeight = (uint)this.Height; DDSHeader.dwWidth = (uint)this.Width; DDSHeader.dwDepth = 1; // considering it is not a cubic texture DDSHeader.dwMipMapCount = (uint)this.Mipmaps; Comp.GetPixelFormat(ref DDSHeader.ddspf, this._compression); DDSHeader.dwCaps = DDSCAPS.SURFACE_FLAGS_TEXTURE; // by default is a texture DDSHeader.dwCaps += DDSCAPS.SURFACE_FLAGS_MIPMAP; // mipmaps should be included DDSHeader.dwPitchOrLinearSize = Comp.PitchLinearSize(this._compression, this.Width, this.Height, DDSHeader.ddspf.dwRGBBitCount); // Write header using ptr fixed(byte *byteptr_t = &data[0]) { *(uint *)(byteptr_t + 0) = DDS_MAIN.MAGIC; *(uint *)(byteptr_t + 4) = DDSHeader.dwSize; *(uint *)(byteptr_t + 8) = DDSHeader.dwFlags; *(uint *)(byteptr_t + 0xC) = DDSHeader.dwHeight; *(uint *)(byteptr_t + 0x10) = DDSHeader.dwWidth; *(uint *)(byteptr_t + 0x14) = DDSHeader.dwPitchOrLinearSize; *(uint *)(byteptr_t + 0x18) = DDSHeader.dwDepth; *(uint *)(byteptr_t + 0x1C) = DDSHeader.dwMipMapCount; for (int a1 = 0; a1 < 11; ++a1) { *(uint *)(byteptr_t + 0x20 + a1 * 4) = DDSHeader.dwReserved1[a1]; } *(uint *)(byteptr_t + 0x4C) = DDSHeader.ddspf.dwSize; *(uint *)(byteptr_t + 0x50) = DDSHeader.ddspf.dwFlags; *(uint *)(byteptr_t + 0x54) = DDSHeader.ddspf.dwFourCC; *(uint *)(byteptr_t + 0x58) = DDSHeader.ddspf.dwRGBBitCount; *(uint *)(byteptr_t + 0x5C) = DDSHeader.ddspf.dwRBitMask; *(uint *)(byteptr_t + 0x60) = DDSHeader.ddspf.dwGBitMask; *(uint *)(byteptr_t + 0x64) = DDSHeader.ddspf.dwBBitMask; *(uint *)(byteptr_t + 0x68) = DDSHeader.ddspf.dwABitMask; *(uint *)(byteptr_t + 0x6C) = DDSHeader.dwCaps; *(uint *)(byteptr_t + 0x70) = DDSHeader.dwCaps2; *(uint *)(byteptr_t + 0x74) = DDSHeader.dwCaps3; *(uint *)(byteptr_t + 0x78) = DDSHeader.dwCaps4; *(uint *)(byteptr_t + 0x7C) = DDSHeader.dwReserved2; } return(data); }
internal static string ExportDDSTexture(Texture2D texture, string directory, bool overwrite = false) { if (texture.Format != TextureFormat.Alpha8 && texture.Format != TextureFormat.ARGB4444 && texture.Format != TextureFormat.RGB24 && texture.Format != TextureFormat.RGBA32 && texture.Format != TextureFormat.ARGB32 && texture.Format != TextureFormat.RGB565 && texture.Format != TextureFormat.R16 && texture.Format != TextureFormat.DXT1 && texture.Format != TextureFormat.DXT5 && texture.Format != TextureFormat.RGBA4444 && texture.Format != TextureFormat.BGRA32 && texture.Format != TextureFormat.RG16 && texture.Format != TextureFormat.R8) { throw new UnsupportedFormatException($"Cannot export {texture.Format.ToString()} to DDS format."); } string exportPath = Path.Combine(directory, $"{texture.m_Name}.dds"); if (File.Exists(exportPath) && !overwrite) { throw new IOException($"File {exportPath} already exist and overwrite argument is not set true."); } byte[] textureData = Texture2DExporter.GetTextureData(texture); DDS_HEADER ddsHeader = new DDS_HEADER() { dwSize = 0x7C, dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT, dwHeight = (uint)texture.m_Height, dwWidth = (uint)texture.m_Width, dwPitchOrLinearSize = (uint)texture.m_CompleteImageSize, dwDepth = 0, dwMipMapCount = (uint)texture.m_MipCount, dwReserved = DDS_GENERATOR_DATA, dwCaps = DDSCAPS_TEXTURE, dwCaps2 = 0, dwCaps3 = 0, dwCaps4 = 0, dwReserved2 = 0, }; DDS_PIXELFORMAT ddspf = new DDS_PIXELFORMAT() { dwSize = 0x20, dwFlags = 0, dwFourCC = 0, dwRGBBitCount = 0, dwRBitMask = 0, dwGBitMask = 0, dwBBitMask = 0, dwABitMask = 0, }; if (texture.HasMips) { ddsHeader.dwFlags |= DDSD_MIPMAPCOUNT; ddsHeader.dwCaps |= DDSCAPS_MIPMAP; } int blocksize = 0; switch (texture.Format) { case TextureFormat.Alpha8: { ddsHeader.dwFlags |= DDSD_PITCH; ddspf.dwFlags = DDPF_ALPHAPIXELS; ddspf.dwRGBBitCount = 0x8; ddspf.dwABitMask = 0xF; blocksize = 8; break; } case TextureFormat.ARGB4444: { ddsHeader.dwFlags |= DDSD_PITCH; ddspf.dwFlags = DDPF_ALPHAPIXELS | DDPF_RGB; ddspf.dwRGBBitCount = 0x10; ddspf.dwRBitMask = 0xFu << 8; ddspf.dwGBitMask = 0xFu << 4; ddspf.dwBBitMask = 0xFu; ddspf.dwABitMask = 0xFu << 12; blocksize = 16; break; } case TextureFormat.RGB24: { ddsHeader.dwFlags |= DDSD_PITCH; ddspf.dwFlags = DDPF_RGB; ddspf.dwRGBBitCount = 0x18; ddspf.dwRBitMask = 0xFFu << 16; ddspf.dwGBitMask = 0xFFu << 8; ddspf.dwBBitMask = 0xFFu; blocksize = 24; break; } case TextureFormat.RGBA32: { ddsHeader.dwFlags |= DDSD_PITCH; ddspf.dwFlags = DDPF_ALPHAPIXELS | DDPF_RGB; ddspf.dwRGBBitCount = 0x20; ddspf.dwRBitMask = 0xFFu << 24; ddspf.dwGBitMask = 0xFFu << 16; ddspf.dwBBitMask = 0xFFu << 8; ddspf.dwABitMask = 0xFFu; blocksize = 32; break; } case TextureFormat.ARGB32: { ddsHeader.dwFlags |= DDSD_PITCH; ddspf.dwFlags = DDPF_ALPHAPIXELS | DDPF_RGB; ddspf.dwRGBBitCount = 0x20; ddspf.dwRBitMask = 0xFFu << 16; ddspf.dwGBitMask = 0xFFu << 8; ddspf.dwBBitMask = 0xFFu; ddspf.dwABitMask = 0xFFu << 24; blocksize = 32; break; } case TextureFormat.RGB565: { ddsHeader.dwFlags |= DDSD_PITCH; ddspf.dwFlags = DDPF_RGB; ddspf.dwRGBBitCount = 0x10; ddspf.dwRBitMask = 0b1111_1000_0000_0000; ddspf.dwGBitMask = 0b0000_0111_1110_0000; ddspf.dwBBitMask = 0b0000_0000_0001_1111; blocksize = 16; break; } case TextureFormat.R16: { ddsHeader.dwFlags |= DDSD_PITCH; ddspf.dwFlags = DDPF_RGB; ddspf.dwRGBBitCount = 0x10; ddspf.dwRBitMask = 0xFFFF; blocksize = 16; break; } case TextureFormat.DXT1: { ddsHeader.dwFlags |= DDSD_LINEARSIZE; ddspf.dwFlags = DDPF_FOURCC; ddspf.dwFourCC = 0x31545844; // DXT1 blocksize = 16; break; } case TextureFormat.DXT5: { ddsHeader.dwFlags |= DDSD_LINEARSIZE; ddspf.dwFlags = DDPF_FOURCC; ddspf.dwFourCC = 0x35545844; // DXT5 break; } case TextureFormat.RGBA4444: { ddsHeader.dwFlags |= DDSD_PITCH; ddspf.dwFlags = DDPF_ALPHAPIXELS | DDPF_RGB; ddspf.dwRGBBitCount = 0x10; ddspf.dwRBitMask = 0xFu << 12; ddspf.dwGBitMask = 0xFu << 8; ddspf.dwBBitMask = 0xFu << 4; ddspf.dwABitMask = 0xFu; break; } case TextureFormat.BGRA32: { ddsHeader.dwFlags |= DDSD_PITCH; ddspf.dwFlags = DDPF_ALPHAPIXELS | DDPF_RGB; ddspf.dwRGBBitCount = 0x20; ddspf.dwRBitMask = 0xFFu << 8; ddspf.dwGBitMask = 0xFFu << 16; ddspf.dwBBitMask = 0xFFu << 24; ddspf.dwABitMask = 0xFFu; break; } case TextureFormat.RG16: { ddsHeader.dwFlags |= DDSD_PITCH; ddspf.dwFlags = DDPF_RGB; ddspf.dwRGBBitCount = 0x10; ddspf.dwRBitMask = 0xFF00; ddspf.dwGBitMask = 0x00FF; break; } case TextureFormat.R8: { ddsHeader.dwFlags |= DDSD_PITCH; ddspf.dwFlags = DDPF_RGB; ddspf.dwRGBBitCount = 0x8; ddspf.dwRBitMask = 0xF; break; } default: throw new UnsupportedFormatException($"Cannot export {texture.Format} to DDS format."); } ddsHeader.ddspf = ddspf; using (var writer = new BinaryWriter(File.OpenWrite(exportPath))) { writer.Write(0x20534444u); // 'DDS ' writer.Write(ddsHeader.dwSize); writer.Write(ddsHeader.dwFlags); writer.Write(ddsHeader.dwHeight); writer.Write(ddsHeader.dwWidth); writer.Write(ddsHeader.dwPitchOrLinearSize); writer.Write(ddsHeader.dwDepth); writer.Write(ddsHeader.dwMipMapCount); for (int i = 0; i < ddsHeader.dwReserved.Length; i++) { writer.Write(ddsHeader.dwReserved[i]); } writer.Write(ddsHeader.ddspf.dwSize); writer.Write(ddsHeader.ddspf.dwFlags); writer.Write(ddsHeader.ddspf.dwFourCC); writer.Write(ddsHeader.ddspf.dwRGBBitCount); writer.Write(ddsHeader.ddspf.dwRBitMask); writer.Write(ddsHeader.ddspf.dwGBitMask); writer.Write(ddsHeader.ddspf.dwBBitMask); writer.Write(ddsHeader.ddspf.dwABitMask); writer.Write(ddsHeader.dwCaps); writer.Write(ddsHeader.dwCaps2); writer.Write(ddsHeader.dwCaps3); writer.Write(ddsHeader.dwCaps4); writer.Write(ddsHeader.dwReserved2); writer.Write(textureData); } return(exportPath); }