internal static void WriteUncompressed(byte[] source, byte[] destination, int destStart, DDS_Header.DDS_PIXELFORMAT dest_ddspf, ImageFormats.ImageEngineFormatDetails sourceFormatDetails, ImageFormats.ImageEngineFormatDetails 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 == ImageEngineFormat.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 (ImageEngine.EnableThreading) { Parallel.For(0, source.Length / sourceIncrement, new ParallelOptions { MaxDegreeOfParallelism = ImageEngine.NumThreads }, (ind, loopState) => { if (ImageEngine.IsCancellationRequested) { loopState.Stop(); } 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) { if (ImageEngine.IsCancellationRequested) { break; } WriteUncompressedPixel(source, i, sourceInds, sourceFormatDetails, masks, destination, destStart, destInds, destFormatDetails, oneChannel, twoChannel, requiresSignedAdjust); } } }
static void WriteUncompressedMipMap(byte[] destination, int mipOffset, MipMap mipmap, ImageFormats.ImageEngineFormatDetails destFormatDetails, DDS_Header.DDS_PIXELFORMAT ddspf) { DDS_Encoders.WriteUncompressed(mipmap.Pixels, destination, mipOffset, ddspf, mipmap.LoadedFormatDetails, destFormatDetails); }
internal static void ReadUncompressed(byte[] source, int sourceStart, byte[] destination, int pixelCount, DDS_Header.DDS_PIXELFORMAT ddspf, ImageFormats.ImageEngineFormatDetails 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 } } }
private static MipMap ReadUncompressedMipMap(MemoryStream stream, int mipOffset, int mipWidth, int mipHeight, DDS_Header.DDS_PIXELFORMAT ddspf, ImageFormats.ImageEngineFormatDetails 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, formatDetails)); }