internal static void WriteUncompressed(byte[] source, byte[] destination, int destStart, DDS_Header.DDS_PIXELFORMAT dest_ddspf, DDSFormatDetails sourceFormatDetails, DDSFormatDetails destFormatDetails) { int byteCount = dest_ddspf.dwRGBBitCount / 8; bool requiresSignedAdjust = (dest_ddspf.dwFlags & DDS_Header.DDS_PFdwFlags.DDPF_SIGNED) == DDS_Header.DDS_PFdwFlags.DDPF_SIGNED; bool oneChannel = (dest_ddspf.dwFlags & DDS_Header.DDS_PFdwFlags.DDPF_LUMINANCE) == DDS_Header.DDS_PFdwFlags.DDPF_LUMINANCE; bool twoChannel = oneChannel && (dest_ddspf.dwFlags & DDS_Header.DDS_PFdwFlags.DDPF_ALPHAPIXELS) == DDS_Header.DDS_PFdwFlags.DDPF_ALPHAPIXELS; uint AMask = dest_ddspf.dwABitMask; uint RMask = dest_ddspf.dwRBitMask; uint GMask = dest_ddspf.dwGBitMask; uint BMask = dest_ddspf.dwBBitMask; ///// Figure out channel existance and ordering. // Setup array that indicates channel offset from pixel start. // e.g. Alpha is usually first, and is given offset 0. // NOTE: Ordering array is in ARGB order, and the stored indices change depending on detected channel order. // A negative index indicates channel doesn't exist in data and sets channel to 0xFF. if (destFormatDetails.Format == DDSFormat.DDS_ARGB_32F) { AMask = 4; BMask = 3; GMask = 2; RMask = 1; } List <uint> maskOrder = new List <uint>(4) { AMask, RMask, GMask, BMask }; maskOrder.Sort(); maskOrder.RemoveAll(t => t == 0); // Required, otherwise indicies get all messed up when there's only two channels, but it's not indicated as such. // Determine channel ordering int destAIndex = AMask == 0 ? -1 : maskOrder.IndexOf(AMask) * destFormatDetails.ComponentSize; int destRIndex = RMask == 0 ? -1 : maskOrder.IndexOf(RMask) * destFormatDetails.ComponentSize; int destGIndex = GMask == 0 ? -1 : maskOrder.IndexOf(GMask) * destFormatDetails.ComponentSize; int destBIndex = BMask == 0 ? -1 : maskOrder.IndexOf(BMask) * destFormatDetails.ComponentSize; int sourceAInd = 3 * sourceFormatDetails.ComponentSize; int sourceRInd = 2 * sourceFormatDetails.ComponentSize; int sourceGInd = 1 * sourceFormatDetails.ComponentSize; int sourceBInd = 0; var sourceInds = new int[] { sourceBInd, sourceGInd, sourceRInd, sourceAInd }; var destInds = new int[] { destBIndex, destGIndex, destRIndex, destAIndex }; var masks = new uint[] { BMask, GMask, RMask, AMask }; int sourceIncrement = 4 * sourceFormatDetails.ComponentSize; if (EnableThreading) { Parallel.For(0, source.Length / sourceIncrement, new ParallelOptions { MaxDegreeOfParallelism = ThreadCount }, (ind, loopState) => { WriteUncompressedPixel(source, ind * sourceIncrement, sourceInds, sourceFormatDetails, masks, destination, destStart + ind * byteCount, destInds, destFormatDetails, oneChannel, twoChannel, requiresSignedAdjust); }); } else { for (int i = 0; i < source.Length; i += 4 * sourceFormatDetails.ComponentSize, destStart += byteCount) { WriteUncompressedPixel(source, i, sourceInds, sourceFormatDetails, masks, destination, destStart, destInds, destFormatDetails, oneChannel, twoChannel, requiresSignedAdjust); } } }
private static MipMap ReadUncompressedMipMap(MemoryStream stream, int mipOffset, int mipWidth, int mipHeight, DDS_Header.DDS_PIXELFORMAT ddspf, DDSFormatDetails formatDetails) { byte[] data = stream.GetBuffer(); byte[] mipmap = new byte[mipHeight * mipWidth * 4 * formatDetails.ComponentSize]; // Smaller sizes breaks things, so just exclude them if (mipHeight >= 4 && mipWidth >= 4) { DDS_Decoders.ReadUncompressed(data, mipOffset, mipmap, mipWidth * mipHeight, ddspf, formatDetails); } return(new MipMap(mipmap, mipWidth, mipHeight)); }
internal static void ReadUncompressed(byte[] source, int sourceStart, byte[] destination, int pixelCount, DDS_Header.DDS_PIXELFORMAT ddspf, DDSFormatDetails formatDetails) { bool requiresSignedAdjustment = ((ddspf.dwFlags & DDS_Header.DDS_PFdwFlags.DDPF_SIGNED) == DDS_Header.DDS_PFdwFlags.DDPF_SIGNED); int sourceIncrement = ddspf.dwRGBBitCount / 8; // /8 for bits to bytes conversion bool oneChannel = (ddspf.dwFlags & DDS_Header.DDS_PFdwFlags.DDPF_LUMINANCE) == DDS_Header.DDS_PFdwFlags.DDPF_LUMINANCE; bool twoChannel = (ddspf.dwFlags & DDS_Header.DDS_PFdwFlags.DDPF_ALPHAPIXELS) == DDS_Header.DDS_PFdwFlags.DDPF_ALPHAPIXELS && oneChannel; uint AMask = ddspf.dwABitMask; uint RMask = ddspf.dwRBitMask; uint GMask = ddspf.dwGBitMask; uint BMask = ddspf.dwBBitMask; ///// Figure out channel existance and ordering. // Setup array that indicates channel offset from pixel start. // e.g. Alpha is usually first, and is given offset 0. // NOTE: Ordering array is in ARGB order, and the stored indices change depending on detected channel order. // A negative index indicates channel doesn't exist in data and sets channel to 0xFF. List <uint> maskOrder = new List <uint>(4) { AMask, RMask, GMask, BMask }; maskOrder.Sort(); maskOrder.RemoveAll(t => t == 0); // Required, otherwise indicies get all messed up when there's only two channels, but it's not indicated as such. // TODO: Cubemaps and hardcoded format readers for performance int AIndex = 0; int RIndex = 0; int GIndex = 0; int BIndex = 0; if (twoChannel) // Note: V8U8 does not come under this one. { // Intensity is first byte, then the alpha. Set all RGB to intensity for grayscale. // Second mask is always RMask as determined by the DDS Spec. AIndex = AMask > RMask ? 1 : 0; RIndex = AMask > RMask ? 0 : 1; GIndex = AMask > RMask ? 0 : 1; BIndex = AMask > RMask ? 0 : 1; } else if (oneChannel) { // Decide whether it's alpha or not. AIndex = AMask == 0 ? -1 : 0; RIndex = AMask == 0 ? 0 : -1; GIndex = AMask == 0 ? 0 : -1; BIndex = AMask == 0 ? 0 : -1; } else { // Set default ordering AIndex = AMask == 0 ? -1 : maskOrder.IndexOf(AMask) * formatDetails.ComponentSize; RIndex = RMask == 0 ? -1 : maskOrder.IndexOf(RMask) * formatDetails.ComponentSize; GIndex = GMask == 0 ? -1 : maskOrder.IndexOf(GMask) * formatDetails.ComponentSize; BIndex = BMask == 0 ? -1 : maskOrder.IndexOf(BMask) * formatDetails.ComponentSize; } // Determine order of things int destAInd = 3 * formatDetails.ComponentSize; int destRInd = 2 * formatDetails.ComponentSize; int destGInd = 1 * formatDetails.ComponentSize; int destBInd = 0; switch (formatDetails.ComponentSize) { case 1: // Check masks fit properly if (maskOrder.Count != sourceIncrement) { // Determine mask size var lengths = new int[4]; lengths[0] = CountSetBits(BMask); lengths[1] = CountSetBits(GMask); lengths[2] = CountSetBits(RMask); lengths[3] = CountSetBits(AMask); ReadBytesLegacy(source, sourceStart, sourceIncrement, lengths, destination, new int[] { destBInd, destGInd, destRInd, destAInd }); } else { ReadBytes(source, sourceStart, sourceIncrement, new int[] { BIndex, GIndex, RIndex, AIndex }, destination, new int[] { destBInd, destGInd, destRInd, destAInd }); } break; case 2: ReadUShorts(source, sourceStart, sourceIncrement, new int[] { BIndex, GIndex, RIndex, AIndex }, destination, new int[] { destBInd, destGInd, destRInd, destAInd }); break; case 4: ReadFloats(source, sourceStart, sourceIncrement, new int[] { BIndex, GIndex, RIndex, AIndex }, destination, new int[] { destBInd, destGInd, destRInd, destAInd }); break; } if (requiresSignedAdjustment) { for (int i = 0; i < destination.Length; i += 4) { //destination[i] -= 128; // Don't adjust blue destination[i + 1] -= 128; destination[i + 2] -= 128; // Alpha not adjusted } } }
static void WriteUncompressedMipMap(byte[] destination, int mipOffset, MipMap mipmap, DDSFormatDetails loadedFormatDetails, DDSFormatDetails destFormatDetails, DDS_Header.DDS_PIXELFORMAT ddspf) { DDS_Encoders.WriteUncompressed(mipmap.Pixels, destination, mipOffset, ddspf, loadedFormatDetails, destFormatDetails); }
/// <summary> /// Determines DDS Surface Format given the header. /// </summary> /// <param name="ddspf">DDS PixelFormat structure.</param> /// <returns>Friendly format.</returns> public static DDSFormat DetermineDDSSurfaceFormat(DDS_Header.DDS_PIXELFORMAT ddspf) { DDSFormat format = ParseFourCC(ddspf.dwFourCC); if (format == DDSFormat.Unknown) { // Due to some previous settings, need to check these first. if (ddspf.dwABitMask <= 4 && ddspf.dwABitMask != 0 && ddspf.dwBBitMask <= 4 && ddspf.dwBBitMask != 0 && ddspf.dwGBitMask <= 4 && ddspf.dwGBitMask != 0 && ddspf.dwRBitMask <= 4 && ddspf.dwRBitMask != 0) { format = DDSFormat.DDS_CUSTOM; } // KFreon: Apparently all these flags mean it's a V8U8 image... else if (ddspf.dwRGBBitCount == 16 && ddspf.dwRBitMask == 0x00FF && ddspf.dwGBitMask == 0xFF00 && ddspf.dwBBitMask == 0x00 && ddspf.dwABitMask == 0x00 && (ddspf.dwFlags & DDS_PFdwFlags.DDPF_SIGNED) == DDS_PFdwFlags.DDPF_SIGNED) { format = DDSFormat.DDS_V8U8; } // KFreon: Test for L8/G8 else if (ddspf.dwABitMask == 0 && ddspf.dwBBitMask == 0 && ddspf.dwGBitMask == 0 && ddspf.dwRBitMask == 0xFF && ddspf.dwFlags == DDS_PFdwFlags.DDPF_LUMINANCE && ddspf.dwRGBBitCount == 8) { format = DDSFormat.DDS_G8_L8; } // KFreon: A8L8. This can probably be something else as well, but it seems to work for now else if (ddspf.dwRGBBitCount == 16 && ddspf.dwFlags == (DDS_PFdwFlags.DDPF_ALPHAPIXELS | DDS_PFdwFlags.DDPF_LUMINANCE)) { format = DDSFormat.DDS_A8L8; } // KFreon: G_R only. else if (((ddspf.dwFlags & DDS_PFdwFlags.DDPF_RGB) == DDS_PFdwFlags.DDPF_RGB && !((ddspf.dwFlags & DDS_PFdwFlags.DDPF_ALPHAPIXELS) == DDS_PFdwFlags.DDPF_ALPHAPIXELS)) && ddspf.dwABitMask == 0 && ddspf.dwBBitMask == 0 && ddspf.dwGBitMask != 0 && ddspf.dwRBitMask != 0) { format = DDSFormat.DDS_G16_R16; } // KFreon: RGB. RGB channels have something in them, but alpha doesn't. else if (((ddspf.dwFlags & DDS_PFdwFlags.DDPF_RGB) == DDS_PFdwFlags.DDPF_RGB && !((ddspf.dwFlags & DDS_PFdwFlags.DDPF_ALPHAPIXELS) == DDS_PFdwFlags.DDPF_ALPHAPIXELS)) && ddspf.dwABitMask == 0 && ddspf.dwBBitMask != 0 && ddspf.dwGBitMask != 0 && ddspf.dwRBitMask != 0) { // TODO more formats? if (ddspf.dwBBitMask == 31) { format = DDSFormat.DDS_R5G6B5; } else { format = DDSFormat.DDS_RGB_8; } } // KFreon: RGB and A channels are present. else if (((ddspf.dwFlags & (DDS_PFdwFlags.DDPF_RGB | DDS_PFdwFlags.DDPF_ALPHAPIXELS)) == (DDS_PFdwFlags.DDPF_RGB | DDS_PFdwFlags.DDPF_ALPHAPIXELS)) || ddspf.dwABitMask != 0 && ddspf.dwBBitMask != 0 && ddspf.dwGBitMask != 0 && ddspf.dwRBitMask != 0) { // TODO: Some more formats here? format = DDSFormat.DDS_ARGB_8; } // KFreon: If nothing else fits, but there's data in one of the bitmasks, assume it can be read. else if (ddspf.dwABitMask != 0 || ddspf.dwRBitMask != 0 || ddspf.dwGBitMask != 0 || ddspf.dwBBitMask != 0) { format = DDSFormat.DDS_CUSTOM; } else { throw new FormatException("DDS Format is unknown."); } } return(format); }