/// <summary> /// Swizzles (RGB <-> BGR) an image row with optional clearing of alpha value to 1.0. /// (Can be used in place as well; otherwise copies the image row unmodified.) /// </summary> internal static void SwizzleScanline(BinaryReader reader, int inSize, BinaryWriter writer, int outSize, DataFormat format, ScanlineFlags flags) { Debug.Assert(reader != null && inSize > 0); Debug.Assert(writer != null && outSize > 0); Debug.Assert(IsValidDds(format) && !IsPlanar(format) && !IsPalettized(format)); switch (format) { //--------------------------------------------------------------------------------- case DataFormat.R10G10B10A2_TYPELESS: case DataFormat.R10G10B10A2_UNORM: case DataFormat.R10G10B10A2_UINT: case DataFormat.R10G10B10_XR_BIAS_A2_UNORM: case DataFormat.R10G10B10_SNORM_A2_UNORM: if (inSize >= 4 && outSize >= 4) { if ((flags & ScanlineFlags.Legacy) != 0) { // Swap Red (R) and Blue (B) channel (used for D3DFMT_A2R10G10B10 legacy sources) int size = Math.Min(outSize, inSize); for (int count = 0; count < (size - 3); count += 4) { uint t = reader.ReadUInt32(); uint t1 = (t & 0x3ff00000) >> 20; uint t2 = (t & 0x000003ff) << 20; uint t3 = (t & 0x000ffc00); uint ta = (flags & ScanlineFlags.SetAlpha) != 0 ? 0xC0000000 : (t & 0xC0000000); writer.Write((uint)(t1 | t2 | t3 | ta)); } return; } } break; //--------------------------------------------------------------------------------- case DataFormat.R8G8B8A8_TYPELESS: case DataFormat.R8G8B8A8_UNORM: case DataFormat.R8G8B8A8_UNORM_SRGB: case DataFormat.B8G8R8A8_UNORM: case DataFormat.B8G8R8X8_UNORM: case DataFormat.B8G8R8A8_TYPELESS: case DataFormat.B8G8R8A8_UNORM_SRGB: case DataFormat.B8G8R8X8_TYPELESS: case DataFormat.B8G8R8X8_UNORM_SRGB: if (inSize >= 4 && outSize >= 4) { // Swap Red (R) and Blue (B) channels (used to convert from DXGI 1.1 BGR formats to DXGI 1.0 RGB) int size = Math.Min(outSize, inSize); for (int count = 0; count < (size - 3); count += 4) { uint t = reader.ReadUInt32(); uint t1 = (t & 0x00ff0000) >> 16; uint t2 = (t & 0x000000ff) << 16; uint t3 = (t & 0x0000ff00); uint ta = (flags & ScanlineFlags.SetAlpha) != 0 ? 0xff000000 : (t & 0xFF000000); writer.Write((uint)(t1 | t2 | t3 | ta)); } return; } break; //--------------------------------------------------------------------------------- case DataFormat.YUY2: if (inSize >= 4 && outSize >= 4) { if ((flags & ScanlineFlags.Legacy) != 0) { // Reorder YUV components (used to convert legacy UYVY -> YUY2) int size = Math.Min(outSize, inSize); for (int count = 0; count < (size - 3); count += 4) { uint t = reader.ReadUInt32(); uint t1 = (t & 0x000000ff) << 8; uint t2 = (t & 0x0000ff00) >> 8; uint t3 = (t & 0x00ff0000) << 8; uint t4 = (t & 0xff000000) >> 8; writer.Write((uint)(t1 | t2 | t3 | t4)); } return; } } break; } // Fall-through case is to just use memcpy (assuming this is not an in-place operation) byte[] scanline = reader.ReadBytes(Math.Min(inSize, outSize)); writer.Write(scanline); }
//-------------------------------------------------------------- /// <summary> /// Copies an image row with optional clearing of alpha value to 1.0. /// </summary> internal static void CopyScanline(BinaryReader reader, int inSize, BinaryWriter writer, int outSize, DataFormat format, ScanlineFlags flags) { Debug.Assert(reader != null && inSize > 0); Debug.Assert(writer != null && outSize > 0); Debug.Assert(IsValidDds(format) && !IsPalettized(format)); if ((flags & ScanlineFlags.SetAlpha) != 0) { switch (format) { //----------------------------------------------------------------------------- case DataFormat.R32G32B32A32_TYPELESS: case DataFormat.R32G32B32A32_FLOAT: case DataFormat.R32G32B32A32_UINT: case DataFormat.R32G32B32A32_SINT: if (inSize >= 16 && outSize >= 16) { uint alpha; if (format == DataFormat.R32G32B32A32_FLOAT) alpha = 0x3f800000; else if (format == DataFormat.R32G32B32A32_SINT) alpha = 0x7fffffff; else alpha = 0xffffffff; int size = Math.Min(outSize, inSize); for (int count = 0; count < (size - 15); count += 16) { writer.Write(reader.ReadInt32()); writer.Write(reader.ReadInt32()); writer.Write(reader.ReadInt32()); reader.ReadInt32(); // Ignore writer.Write(alpha); } } return; //----------------------------------------------------------------------------- case DataFormat.R16G16B16A16_TYPELESS: case DataFormat.R16G16B16A16_FLOAT: case DataFormat.R16G16B16A16_UNORM: case DataFormat.R16G16B16A16_UINT: case DataFormat.R16G16B16A16_SNORM: case DataFormat.R16G16B16A16_SINT: case DataFormat.Y416: if (inSize >= 8 && outSize >= 8) { ushort alpha; if (format == DataFormat.R16G16B16A16_FLOAT) alpha = 0x3c00; else if (format == DataFormat.R16G16B16A16_SNORM || format == DataFormat.R16G16B16A16_SINT) alpha = 0x7fff; else alpha = 0xffff; int size = Math.Min(outSize, inSize); for (int count = 0; count < (size - 7); count += 8) { writer.Write(reader.ReadUInt16()); writer.Write(reader.ReadUInt16()); writer.Write(reader.ReadUInt16()); reader.ReadUInt16(); // Ignore writer.Write(alpha); } } return; //----------------------------------------------------------------------------- case DataFormat.R10G10B10A2_TYPELESS: case DataFormat.R10G10B10A2_UNORM: case DataFormat.R10G10B10A2_UINT: case DataFormat.R10G10B10_XR_BIAS_A2_UNORM: case DataFormat.Y410: case DataFormat.R10G10B10_7E3_A2_FLOAT: case DataFormat.R10G10B10_6E4_A2_FLOAT: case DataFormat.R10G10B10_SNORM_A2_UNORM: if (inSize >= 4 && outSize >= 4) { int size = Math.Min(outSize, inSize); for (int count = 0; count < (size - 3); count += 4) { writer.Write(reader.ReadUInt32() | 0xC0000000); } } return; //----------------------------------------------------------------------------- case DataFormat.R8G8B8A8_TYPELESS: case DataFormat.R8G8B8A8_UNORM: case DataFormat.R8G8B8A8_UNORM_SRGB: case DataFormat.R8G8B8A8_UINT: case DataFormat.R8G8B8A8_SNORM: case DataFormat.R8G8B8A8_SINT: case DataFormat.B8G8R8A8_UNORM: case DataFormat.B8G8R8A8_TYPELESS: case DataFormat.B8G8R8A8_UNORM_SRGB: case DataFormat.AYUV: if (inSize >= 4 && outSize >= 4) { uint alpha = (format == DataFormat.R8G8B8A8_SNORM || format == DataFormat.R8G8B8A8_SINT) ? 0x7f000000 : 0xff000000; int size = Math.Min(outSize, inSize); for (int count = 0; count < (size - 3); count += 4) { uint t = reader.ReadUInt32() & 0xFFFFFF; t |= alpha; writer.Write(t); } } return; //----------------------------------------------------------------------------- case DataFormat.B5G5R5A1_UNORM: if (inSize >= 2 && outSize >= 2) { int size = Math.Min(outSize, inSize); for (int count = 0; count < (size - 1); count += 2) { writer.Write((ushort)(reader.ReadUInt16() | 0x8000)); } } return; //----------------------------------------------------------------------------- case DataFormat.A8_UNORM: for (int i = 0; i < outSize; i++) writer.Write((byte)0xff); return; //----------------------------------------------------------------------------- case DataFormat.B4G4R4A4_UNORM: if (inSize >= 2 && outSize >= 2) { int size = Math.Min(outSize, inSize); for (int count = 0; count < (size - 1); count += 2) { writer.Write((ushort)(reader.ReadUInt16() | 0xF000)); } } return; } } // Fall-through case is to just use memcpy (assuming this is not an in-place operation) byte[] scanline = reader.ReadBytes(Math.Min(inSize, outSize)); writer.Write(scanline); }
/// <summary> /// Converts an image row with optional clearing of alpha value to 1.0. /// </summary> internal static bool ExpandScanline(BinaryReader reader, int inSize, DataFormat inFormat, BinaryWriter writer, int outSize, DataFormat outFormat, ScanlineFlags flags) { Debug.Assert(reader != null && inSize > 0); Debug.Assert(writer != null && outSize > 0); Debug.Assert(IsValidDds(inFormat) && !IsPlanar(inFormat) && !IsPalettized(inFormat)); Debug.Assert(IsValidDds(outFormat) && !IsPlanar(outFormat) && !IsPalettized(outFormat)); bool setAlpha = (flags & ScanlineFlags.SetAlpha) != 0; switch (inFormat) { case DataFormat.B5G6R5_UNORM: if (outFormat != DataFormat.R8G8B8A8_UNORM) return false; // DXGI_FORMAT_B5G6R5_UNORM -> DXGI_FORMAT_R8G8B8A8_UNORM if (inSize >= 2 && outSize >= 4) { for (int ocount = 0, icount = 0; ((icount < (inSize - 1)) && (ocount < (outSize - 3))); icount += 2, ocount += 4) { ushort t = reader.ReadUInt16(); writer.Write(DataFormatHelper.Bgr565ToRgba8888(t)); } return true; } return false; case DataFormat.B5G5R5A1_UNORM: if (outFormat != DataFormat.R8G8B8A8_UNORM) return false; // DXGI_FORMAT_B5G5R5A1_UNORM -> DXGI_FORMAT_R8G8B8A8_UNORM if (inSize >= 2 && outSize >= 4) { for (int ocount = 0, icount = 0; ((icount < (inSize - 1)) && (ocount < (outSize - 3))); icount += 2, ocount += 4) { ushort color = reader.ReadUInt16(); writer.Write(DataFormatHelper.Bgra5551ToRgba8888(color, setAlpha)); } return true; } return false; case DataFormat.B4G4R4A4_UNORM: if (outFormat != DataFormat.R8G8B8A8_UNORM) return false; // DXGI_FORMAT_B4G4R4A4_UNORM -> DXGI_FORMAT_R8G8B8A8_UNORM if (inSize >= 2 && outSize >= 4) { for (int ocount = 0, icount = 0; ((icount < (inSize - 1)) && (ocount < (outSize - 3))); icount += 2, ocount += 4) { ushort color = reader.ReadUInt16(); writer.Write(DataFormatHelper.Bgra4444ToRgba8888(color, setAlpha)); } return true; } return false; } return false; }
/// <summary> // Converts an image row with optional clearing of alpha value to 1.0 /// </summary> /// <param name="pDestination"></param> /// <param name="outSize"></param> /// <param name="outFormat"></param> /// <param name="pSource"></param> /// <param name="inSize"></param> /// <param name="inFormat"></param> /// <param name="pal8"></param> /// <param name="flags"></param> /// <returns></returns> static unsafe bool LegacyExpandScanline( IntPtr pDestination, int outSize, PixelFormat outFormat, IntPtr pSource, int inSize, TEXP_LEGACY_FORMAT inFormat, uint* pal8, ScanlineFlags flags ) { switch (inFormat) { case TEXP_LEGACY_FORMAT.R8G8B8: if (outFormat != PixelFormat.R8G8B8A8_UNorm) return false; // D3DFMT_R8G8B8 -> PixelFormat.R8G8B8A8_UNorm { var sPtr = (byte*) (pSource); var dPtr = (uint*) (pDestination); for (int ocount = 0, icount = 0; ((icount < inSize) && (ocount < outSize)); icount += 3, ocount += 4) { // 24bpp Direct3D 9 files are actually BGR, so need to swizzle as well uint t1 = (uint)(*(sPtr) << 16); uint t2 = (uint)(*(sPtr + 1) << 8); uint t3 = *(sPtr + 2); *(dPtr++) = (t1 | t2 | t3 | 0xff000000); sPtr += 3; } } return true; case TEXP_LEGACY_FORMAT.R3G3B2: switch (outFormat) { case PixelFormat.R8G8B8A8_UNorm: // D3DFMT_R3G3B2 -> PixelFormat.R8G8B8A8_UNorm { var sPtr = (byte*) (pSource); var dPtr = (uint*) (pDestination); for (int ocount = 0, icount = 0; ((icount < inSize) && (ocount < outSize)); ++icount, ocount += 4) { byte t = *(sPtr++); uint t1 = (uint)((t & 0xe0) | ((t & 0xe0) >> 3) | ((t & 0xc0) >> 6)); uint t2 = (uint)(((t & 0x1c) << 11) | ((t & 0x1c) << 8) | ((t & 0x18) << 5)); uint t3 = (uint)(((t & 0x03) << 22) | ((t & 0x03) << 20) | ((t & 0x03) << 18) | ((t & 0x03) << 16)); *(dPtr++) = (t1 | t2 | t3 | 0xff000000); } } return true; case PixelFormat.B5G6R5_UNorm: // D3DFMT_R3G3B2 -> PixelFormat.B5G6R5_UNorm { var sPtr = (byte*) (pSource); var dPtr = (short*) (pDestination); for (int ocount = 0, icount = 0; ((icount < inSize) && (ocount < outSize)); ++icount, ocount += 2) { byte t = *(sPtr++); var t1 = (uint) (((t & 0xe0) << 8) | ((t & 0xc0) << 5)); var t2 = (uint) (((t & 0x1c) << 6) | ((t & 0x1c) << 3)); var t3 = (uint) (((t & 0x03) << 3) | ((t & 0x03) << 1) | ((t & 0x02) >> 1)); *(dPtr++) = (short) (t1 | t2 | t3); } } return true; } break; case TEXP_LEGACY_FORMAT.A8R3G3B2: if (outFormat != PixelFormat.R8G8B8A8_UNorm) return false; // D3DFMT_A8R3G3B2 -> PixelFormat.R8G8B8A8_UNorm { var sPtr = (short*) (pSource); var dPtr = (uint*) (pDestination); for (int ocount = 0, icount = 0; ((icount < inSize) && (ocount < outSize)); icount += 2, ocount += 4) { short t = *(sPtr++); uint t1 = (uint)((t & 0x00e0) | ((t & 0x00e0) >> 3) | ((t & 0x00c0) >> 6)); uint t2 = (uint)(((t & 0x001c) << 11) | ((t & 0x001c) << 8) | ((t & 0x0018) << 5)); uint t3 = (uint)(((t & 0x0003) << 22) | ((t & 0x0003) << 20) | ((t & 0x0003) << 18) | ((t & 0x0003) << 16)); uint ta = ((flags & ScanlineFlags.SetAlpha) != 0 ? 0xff000000 : (uint) ((t & 0xff00) << 16)); *(dPtr++) = (t1 | t2 | t3 | ta); } } return true; case TEXP_LEGACY_FORMAT.P8: if ((outFormat != PixelFormat.R8G8B8A8_UNorm) || pal8 == null) return false; // D3DFMT_P8 -> PixelFormat.R8G8B8A8_UNorm { byte* sPtr = (byte*) (pSource); var dPtr = (uint*) (pDestination); for (int ocount = 0, icount = 0; ((icount < inSize) && (ocount < outSize)); ++icount, ocount += 4) { byte t = *(sPtr++); *(dPtr++) = pal8[t]; } } return true; case TEXP_LEGACY_FORMAT.A8P8: if ((outFormat != PixelFormat.R8G8B8A8_UNorm) || pal8 == null) return false; // D3DFMT_A8P8 -> PixelFormat.R8G8B8A8_UNorm { short* sPtr = (short*) (pSource); int* dPtr = (int*) (pDestination); for (int ocount = 0, icount = 0; ((icount < inSize) && (ocount < outSize)); icount += 2, ocount += 4) { short t = *(sPtr++); uint t1 = pal8[t & 0xff]; uint ta = ((flags & ScanlineFlags.SetAlpha) != 0 ? 0xff000000 : (uint) ((t & 0xff00) << 16)); *(dPtr++) = (int) (t1 | ta); } } return true; case TEXP_LEGACY_FORMAT.A4L4: switch (outFormat) { #if DIRECTX11_1 case PixelFormat.B4G4R4A4_UNorm : // D3DFMT_A4L4 -> PixelFormat.B4G4R4A4_UNorm { byte * sPtr = (byte*)(pSource); short * dPtr = (short*)(pDestination); for( int ocount = 0, icount = 0; ((icount < inSize) && (ocount < outSize)); ++icount, ocount += 2 ) { byte t = *(sPtr++); short t1 = (short)(t & 0x0f); ushort ta = (flags & ScanlineFlags.SetAlpha ) != 0 ? (ushort)0xf000 : (ushort)((t & 0xf0) << 8); *(dPtr++) = (short)(t1 | (t1 << 4) | (t1 << 8) | ta); } } return true; #endif // DXGI_1_2_FORMATS case PixelFormat.R8G8B8A8_UNorm: // D3DFMT_A4L4 -> PixelFormat.R8G8B8A8_UNorm { byte* sPtr = (byte*) (pSource); var dPtr = (uint*) (pDestination); for (int ocount = 0, icount = 0; ((icount < inSize) && (ocount < outSize)); ++icount, ocount += 4) { byte t = *(sPtr++); uint t1 = (uint)(((t & 0x0f) << 4) | (t & 0x0f)); uint ta = ((flags & ScanlineFlags.SetAlpha) != 0 ? 0xff000000 : (uint) (((t & 0xf0) << 24) | ((t & 0xf0) << 20))); *(dPtr++) = (t1 | (t1 << 8) | (t1 << 16) | ta); } } return true; } break; #if !DIRECTX11_1 case TEXP_LEGACY_FORMAT.B4G4R4A4: if (outFormat != PixelFormat.R8G8B8A8_UNorm) return false; // D3DFMT_A4R4G4B4 -> PixelFormat.R8G8B8A8_UNorm { short* sPtr = (short*) (pSource); var dPtr = (uint*) (pDestination); for (int ocount = 0, icount = 0; ((icount < inSize) && (ocount < outSize)); icount += 2, ocount += 4) { short t = *(sPtr++); uint t1 = (uint)(((t & 0x0f00) >> 4) | ((t & 0x0f00) >> 8)); uint t2 = (uint)(((t & 0x00f0) << 8) | ((t & 0x00f0) << 4)); uint t3 = (uint)(((t & 0x000f) << 20) | ((t & 0x000f) << 16)); uint ta = ((flags & ScanlineFlags.SetAlpha) != 0 ? 0xff000000 : (uint) (((t & 0xf000) << 16) | ((t & 0xf000) << 12))); *(dPtr++) = (t1 | t2 | t3 | ta); } } return true; #endif } return false; }
/// <summary> /// Swizzles (RGB <-> BGR) an image row with optional clearing of alpha value to 1.0. /// </summary> /// <param name="pDestination">The destination buffer.</param> /// <param name="outSize">The destination size.</param> /// <param name="pSource">The source buffer.</param> /// <param name="inSize">The source size.</param> /// <param name="format">The <see cref="Format"/> of the source scanline.</param> /// <param name="flags">Scanline flags used when copying the scanline.</param> /// <remarks> /// This method can be used in place as well, otherwise copies the image row unmodified. /// </remarks> internal static unsafe void SwizzleScanline(IntPtr pDestination, int outSize, IntPtr pSource, int inSize, PixelFormat format, ScanlineFlags flags) { switch (format) { //--------------------------------------------------------------------------------- case PixelFormat.R10G10B10A2_Typeless: case PixelFormat.R10G10B10A2_UNorm: case PixelFormat.R10G10B10A2_UInt: case PixelFormat.R10G10B10_Xr_Bias_A2_UNorm: if ((flags & ScanlineFlags.Legacy) != 0) { // Swap Red (R) and Blue (B) channel (used for D3DFMT_A2R10G10B10 legacy sources) if (pDestination == pSource) { var dPtr = (uint*)(pDestination); for (int count = 0; count < outSize; count += 4) { uint t = *dPtr; uint t1 = (t & 0x3ff00000) >> 20; uint t2 = (t & 0x000003ff) << 20; uint t3 = (t & 0x000ffc00); uint ta = (flags & ScanlineFlags.SetAlpha) != 0 ? 0xC0000000 : (t & 0xC0000000); *(dPtr++) = t1 | t2 | t3 | ta; } } else { var sPtr = (uint*)(pSource); var dPtr = (uint*)(pDestination); int size = Math.Min(outSize, inSize); for (int count = 0; count < size; count += 4) { uint t = *(sPtr++); uint t1 = (t & 0x3ff00000) >> 20; uint t2 = (t & 0x000003ff) << 20; uint t3 = (t & 0x000ffc00); uint ta = (flags & ScanlineFlags.SetAlpha) != 0 ? 0xC0000000 : (t & 0xC0000000); *(dPtr++) = t1 | t2 | t3 | ta; } } return; } break; //--------------------------------------------------------------------------------- case PixelFormat.R8G8B8A8_Typeless: case PixelFormat.R8G8B8A8_UNorm: case PixelFormat.R8G8B8A8_UNorm_SRgb: case PixelFormat.B8G8R8A8_UNorm: case PixelFormat.B8G8R8X8_UNorm: case PixelFormat.B8G8R8A8_Typeless: case PixelFormat.B8G8R8A8_UNorm_SRgb: case PixelFormat.B8G8R8X8_Typeless: case PixelFormat.B8G8R8X8_UNorm_SRgb: // Swap Red (R) and Blue (B) channels (used to convert from DXGI 1.1 BGR formats to DXGI 1.0 RGB) if (pDestination == pSource) { var dPtr = (uint*)(pDestination); for (int count = 0; count < outSize; count += 4) { uint t = *dPtr; uint t1 = (t & 0x00ff0000) >> 16; uint t2 = (t & 0x000000ff) << 16; uint t3 = (t & 0x0000ff00); uint ta = (flags & ScanlineFlags.SetAlpha) != 0 ? 0xff000000 : (t & 0xFF000000); *(dPtr++) = t1 | t2 | t3 | ta; } } else { var sPtr = (uint*)(pSource); var dPtr = (uint*)(pDestination); int size = Math.Min(outSize, inSize); for (int count = 0; count < size; count += 4) { uint t = *(sPtr++); uint t1 = (t & 0x00ff0000) >> 16; uint t2 = (t & 0x000000ff) << 16; uint t3 = (t & 0x0000ff00); uint ta = (flags & ScanlineFlags.SetAlpha) != 0 ? 0xff000000 : (t & 0xFF000000); *(dPtr++) = t1 | t2 | t3 | ta; } } return; } // Fall-through case is to just use memcpy (assuming this is not an in-place operation) if (pDestination == pSource) return; Utilities.CopyMemory(pDestination, pSource, Math.Min(outSize, inSize)); }
/// <summary> /// Copies an image row with optional clearing of alpha value to 1.0. /// </summary> /// <remarks> /// This method can be used in place as well, otherwise copies the image row unmodified. /// </remarks> /// <param name="pDestination">The destination buffer.</param> /// <param name="outSize">The destination size.</param> /// <param name="pSource">The source buffer.</param> /// <param name="inSize">The source size.</param> /// <param name="format">The <see cref="Format"/> of the source scanline.</param> /// <param name="flags">Scanline flags used when copying the scanline.</param> internal static unsafe void CopyScanline(IntPtr pDestination, int outSize, IntPtr pSource, int inSize, PixelFormat format, ScanlineFlags flags) { if ((flags & ScanlineFlags.SetAlpha) != 0) { switch (format) { //----------------------------------------------------------------------------- case PixelFormat.R32G32B32A32_Typeless: case PixelFormat.R32G32B32A32_Float: case PixelFormat.R32G32B32A32_UInt: case PixelFormat.R32G32B32A32_SInt: { uint alpha; if (format == PixelFormat.R32G32B32A32_Float) alpha = 0x3f800000; else if (format == PixelFormat.R32G32B32A32_SInt) alpha = 0x7fffffff; else alpha = 0xffffffff; if (pDestination == pSource) { var dPtr = (uint*)(pDestination); for (int count = 0; count < outSize; count += 16) { dPtr += 3; *(dPtr++) = alpha; } } else { var sPtr = (uint*)(pSource); var dPtr = (uint*)(pDestination); int size = Math.Min(outSize, inSize); for (int count = 0; count < size; count += 16) { *(dPtr++) = *(sPtr++); *(dPtr++) = *(sPtr++); *(dPtr++) = *(sPtr++); *(dPtr++) = alpha; sPtr++; } } } return; //----------------------------------------------------------------------------- case PixelFormat.R16G16B16A16_Typeless: case PixelFormat.R16G16B16A16_Float: case PixelFormat.R16G16B16A16_UNorm: case PixelFormat.R16G16B16A16_UInt: case PixelFormat.R16G16B16A16_SNorm: case PixelFormat.R16G16B16A16_SInt: { ushort alpha; if (format == PixelFormat.R16G16B16A16_Float) alpha = 0x3c00; else if (format == PixelFormat.R16G16B16A16_SNorm || format == PixelFormat.R16G16B16A16_SInt) alpha = 0x7fff; else alpha = 0xffff; if (pDestination == pSource) { var dPtr = (ushort*)(pDestination); for (int count = 0; count < outSize; count += 8) { dPtr += 3; *(dPtr++) = alpha; } } else { var sPtr = (ushort*)(pSource); var dPtr = (ushort*)(pDestination); int size = Math.Min(outSize, inSize); for (int count = 0; count < size; count += 8) { *(dPtr++) = *(sPtr++); *(dPtr++) = *(sPtr++); *(dPtr++) = *(sPtr++); *(dPtr++) = alpha; sPtr++; } } } return; //----------------------------------------------------------------------------- case PixelFormat.R10G10B10A2_Typeless: case PixelFormat.R10G10B10A2_UNorm: case PixelFormat.R10G10B10A2_UInt: case PixelFormat.R10G10B10_Xr_Bias_A2_UNorm: { if (pDestination == pSource) { var dPtr = (uint*)(pDestination); for (int count = 0; count < outSize; count += 4) { *dPtr |= 0xC0000000; ++dPtr; } } else { var sPtr = (uint*)(pSource); var dPtr = (uint*)(pDestination); int size = Math.Min(outSize, inSize); for (int count = 0; count < size; count += 4) { *(dPtr++) = *(sPtr++) | 0xC0000000; } } } return; //----------------------------------------------------------------------------- case PixelFormat.R8G8B8A8_Typeless: case PixelFormat.R8G8B8A8_UNorm: case PixelFormat.R8G8B8A8_UNorm_SRgb: case PixelFormat.R8G8B8A8_UInt: case PixelFormat.R8G8B8A8_SNorm: case PixelFormat.R8G8B8A8_SInt: case PixelFormat.B8G8R8A8_UNorm: case PixelFormat.B8G8R8A8_Typeless: case PixelFormat.B8G8R8A8_UNorm_SRgb: { uint alpha = (format == PixelFormat.R8G8B8A8_SNorm || format == PixelFormat.R8G8B8A8_SInt) ? 0x7f000000 : 0xff000000; if (pDestination == pSource) { var dPtr = (uint*)(pDestination); for (int count = 0; count < outSize; count += 4) { uint t = *dPtr & 0xFFFFFF; t |= alpha; *(dPtr++) = t; } } else { var sPtr = (uint*)(pSource); var dPtr = (uint*)(pDestination); int size = Math.Min(outSize, inSize); for (int count = 0; count < size; count += 4) { uint t = *(sPtr++) & 0xFFFFFF; t |= alpha; *(dPtr++) = t; } } } return; //----------------------------------------------------------------------------- case PixelFormat.B5G5R5A1_UNorm: { if (pDestination == pSource) { var dPtr = (ushort*)(pDestination); for (int count = 0; count < outSize; count += 2) { *(dPtr++) |= 0x8000; } } else { var sPtr = (ushort*)(pSource); var dPtr = (ushort*)(pDestination); int size = Math.Min(outSize, inSize); for (int count = 0; count < size; count += 2) { *(dPtr++) = (ushort)(*(sPtr++) | 0x8000); } } } return; //----------------------------------------------------------------------------- case PixelFormat.A8_UNorm: Utilities.ClearMemory(pDestination, 0xff, outSize); return; #if DIRECTX11_1 //----------------------------------------------------------------------------- case PixelFormat.B4G4R4A4_UNorm: { if (pDestination == pSource) { var dPtr = (ushort*) (pDestination); for (int count = 0; count < outSize; count += 2) { *(dPtr++) |= 0xF000; } } else { var sPtr = (ushort*) (pSource); var dPtr = (ushort*) (pDestination); int size = Math.Min(outSize, inSize); for (int count = 0; count < size; count += 2) { *(dPtr++) = (ushort) (*(sPtr++) | 0xF000); } } } return; #endif // DXGI_1_2_FORMATS } } // Fall-through case is to just use memcpy (assuming this is not an in-place operation) if (pDestination == pSource) return; Utilities.CopyMemory(pDestination, pSource, Math.Min(outSize, inSize)); }
/// <summary> /// Converts an image row with optional clearing of alpha value to 1.0 /// </summary> /// <param name="pDestination"></param> /// <param name="outSize"></param> /// <param name="pSource"></param> /// <param name="inSize"></param> /// <param name="inFormat"></param> /// <param name="flags"></param> private unsafe static void ExpandScanline(IntPtr pDestination, int outSize, IntPtr pSource, int inSize, PixelFormat inFormat, ScanlineFlags flags) { switch (inFormat) { case PixelFormat.B5G6R5_UNorm: // PixelFormat.B5G6R5_UNorm -> PixelFormat.R8G8B8A8_UNorm { var sPtr = (ushort*) (pSource); var dPtr = (uint*) (pDestination); for (uint ocount = 0, icount = 0; ((icount < inSize) && (ocount < outSize)); icount += 2, ocount += 4) { ushort t = *(sPtr++); uint t1 = (uint) (((t & 0xf800) >> 8) | ((t & 0xe000) >> 13)); uint t2 = (uint) (((t & 0x07e0) << 5) | ((t & 0x0600) >> 5)); uint t3 = (uint) (((t & 0x001f) << 19) | ((t & 0x001c) << 14)); *(dPtr++) = t1 | t2 | t3 | 0xff000000; } } break; case PixelFormat.B5G5R5A1_UNorm: // PixelFormat.B5G5R5A1_UNorm -> PixelFormat.R8G8B8A8_UNorm { var sPtr = (ushort*) (pSource); var dPtr = (uint*) (pDestination); for (uint ocount = 0, icount = 0; ((icount < inSize) && (ocount < outSize)); icount += 2, ocount += 4) { ushort t = *(sPtr++); uint t1 = (uint) (((t & 0x7c00) >> 7) | ((t & 0x7000) >> 12)); uint t2 = (uint) (((t & 0x03e0) << 6) | ((t & 0x0380) << 1)); uint t3 = (uint) (((t & 0x001f) << 19) | ((t & 0x001c) << 14)); uint ta = (uint) ((flags & ScanlineFlags.SetAlpha) != 0 ? 0xff000000 : (((t & 0x8000) != 0 ? 0xff000000 : 0))); *(dPtr++) = t1 | t2 | t3 | ta; } } break; #if DIRECTX11_1 case PixelFormat.B4G4R4A4_UNorm: // PixelFormat.B4G4R4A4_UNorm -> PixelFormat.R8G8B8A8_UNorm { var sPtr = (ushort*) (pSource); var dPtr = (uint*) (pDestination); for (uint ocount = 0, icount = 0; ((icount < inSize) && (ocount < outSize)); icount += 2, ocount += 4) { ushort t = *(sPtr++); uint t1 = (uint) (((t & 0x0f00) >> 4) | ((t & 0x0f00) >> 8)); uint t2 = (uint) (((t & 0x00f0) << 8) | ((t & 0x00f0) << 4)); uint t3 = (uint) (((t & 0x000f) << 20) | ((t & 0x000f) << 16)); uint ta = (flags & ScanlineFlags.SetAlpha) != 0 ? 0xff000000 : (uint) ((((t & 0xf000) << 16) | ((t & 0xf000) << 12))); *(dPtr++) = t1 | t2 | t3 | ta; } } break; #endif // DXGI_1_2_FORMATS } }
private static bool LegacyExpandScanline(BinaryReader reader, int inSize, LegacyFormat inFormat, BinaryWriter writer, int outSize, DataFormat outFormat, uint[] pal8, ScanlineFlags flags) { Debug.Assert(reader != null && inSize > 0); Debug.Assert(writer != null && outSize > 0); Debug.Assert(TextureHelper.IsValidDds(outFormat) && !TextureHelper.IsPlanar(outFormat) && !TextureHelper.IsPalettized(outFormat)); switch (inFormat) { case LegacyFormat.R8G8B8: if (outFormat != DataFormat.R8G8B8A8_UNORM) return false; // D3DFMT_R8G8B8 -> DXGI_FORMAT_R8G8B8A8_UNORM if (inSize >= 3 && outSize >= 4) { for (int ocount = 0, icount = 0; ((icount < (inSize - 2)) && (ocount < (outSize - 3))); icount += 3, ocount += 4) { // 24bpp Direct3D 9 files are actually BGR, so need to swizzle as well uint t1 = (uint)(reader.ReadByte() << 16); uint t2 = (uint)(reader.ReadByte() << 8); uint t3 = reader.ReadByte(); writer.Write((int)(t1 | t2 | t3 | 0xff000000)); } return true; } return false; case LegacyFormat.R3G3B2: switch (outFormat) { case DataFormat.R8G8B8A8_UNORM: // D3DFMT_R3G3B2 -> DXGI_FORMAT_R8G8B8A8_UNORM if (inSize >= 1 && outSize >= 4) { for (int ocount = 0, icount = 0; ((icount < inSize) && (ocount < (outSize - 3))); ++icount, ocount += 4) { byte t = reader.ReadByte(); uint t1 = (uint)((t & 0xe0) | ((t & 0xe0) >> 3) | ((t & 0xc0) >> 6)); uint t2 = (uint)(((t & 0x1c) << 11) | ((t & 0x1c) << 8) | ((t & 0x18) << 5)); uint t3 = (uint)(((t & 0x03) << 22) | ((t & 0x03) << 20) | ((t & 0x03) << 18) | ((t & 0x03) << 16)); writer.Write((int)(t1 | t2 | t3 | 0xff000000)); } return true; } return false; case DataFormat.B5G6R5_UNORM: // D3DFMT_R3G3B2 -> DXGI_FORMAT_B5G6R5_UNORM if (inSize >= 1 && outSize >= 2) { for (int ocount = 0, icount = 0; ((icount < inSize) && (ocount < (outSize - 1))); ++icount, ocount += 2) { byte t = reader.ReadByte(); int t1 = ((t & 0xe0) << 8) | ((t & 0xc0) << 5); int t2 = ((t & 0x1c) << 6) | ((t & 0x1c) << 3); int t3 = ((t & 0x03) << 3) | ((t & 0x03) << 1) | ((t & 0x02) >> 1); writer.Write((short)(t1 | t2 | t3)); } return true; } return false; } break; case LegacyFormat.A8R3G3B2: if (outFormat != DataFormat.R8G8B8A8_UNORM) return false; // D3DFMT_A8R3G3B2 -> DXGI_FORMAT_R8G8B8A8_UNORM if (inSize >= 2 && outSize >= 4) { for (int ocount = 0, icount = 0; ((icount < (inSize - 1)) && (ocount < (outSize - 3))); icount += 2, ocount += 4) { short t = reader.ReadInt16(); uint t1 = (uint)((t & 0x00e0) | ((t & 0x00e0) >> 3) | ((t & 0x00c0) >> 6)); uint t2 = (uint)(((t & 0x001c) << 11) | ((t & 0x001c) << 8) | ((t & 0x0018) << 5)); uint t3 = (uint)(((t & 0x0003) << 22) | ((t & 0x0003) << 20) | ((t & 0x0003) << 18) | ((t & 0x0003) << 16)); uint ta = ((flags & ScanlineFlags.SetAlpha) != 0 ? 0xff000000 : (uint)((t & 0xff00) << 16)); writer.Write((uint)(t1 | t2 | t3 | ta)); } return true; } return false; case LegacyFormat.P8: if ((outFormat != DataFormat.R8G8B8A8_UNORM) || pal8 == null) return false; // D3DFMT_P8 -> DXGI_FORMAT_R8G8B8A8_UNORM if (inSize >= 1 && outSize >= 4) { for (int ocount = 0, icount = 0; ((icount < inSize) && (ocount < (outSize - 3))); ++icount, ocount += 4) { byte t = reader.ReadByte(); writer.Write(pal8[t]); } return true; } return false; case LegacyFormat.A8P8: if ((outFormat != DataFormat.R8G8B8A8_UNORM) || pal8 == null) return false; // D3DFMT_A8P8 -> DXGI_FORMAT_R8G8B8A8_UNORM if (inSize >= 2 && outSize >= 4) { for (int ocount = 0, icount = 0; ((icount < (inSize - 1)) && (ocount < (outSize - 3))); icount += 2, ocount += 4) { short t = reader.ReadInt16(); uint t1 = pal8[t & 0xff]; uint ta = ((flags & ScanlineFlags.SetAlpha) != 0 ? 0xff000000 : (uint)((t & 0xff00) << 16)); writer.Write((int)(t1 | ta)); } return true; } return false; case LegacyFormat.A4L4: switch (outFormat) { //#if DIRECTX11_1 case DataFormat.B4G4R4A4_UNORM: // D3DFMT_A4L4 -> DXGI_FORMAT_B4G4R4A4_UNORM if (inSize >= 1 && outSize >= 2) { for (int ocount = 0, icount = 0; ((icount < inSize) && (ocount < (outSize - 1))); ++icount, ocount += 2) { byte t = reader.ReadByte(); ushort t1 = (ushort)(t & 0x0f); ushort ta = (flags & ScanlineFlags.SetAlpha) != 0 ? (ushort)0xf000 : (ushort)((t & 0xf0) << 8); writer.Write((ushort)(t1 | (t1 << 4) | (t1 << 8) | ta)); } return true; } return false; //#endif case DataFormat.R8G8B8A8_UNORM: // D3DFMT_A4L4 -> DXGI_FORMAT_R8G8B8A8_UNORM if (inSize >= 1 && outSize >= 4) { for (int ocount = 0, icount = 0; ((icount < inSize) && (ocount < (outSize - 3))); ++icount, ocount += 4) { byte t = reader.ReadByte(); uint t1 = (uint)(((t & 0x0f) << 4) | (t & 0x0f)); uint ta = ((flags & ScanlineFlags.SetAlpha) != 0 ? 0xff000000 : (uint)(((t & 0xf0) << 24) | ((t & 0xf0) << 20))); writer.Write((uint)(t1 | (t1 << 8) | (t1 << 16) | ta)); } return true; } return false; } break; //#if !DIRECTX11_1 case LegacyFormat.B4G4R4A4: if (outFormat != DataFormat.R8G8B8A8_UNORM) return false; // D3DFMT_A4R4G4B4 -> DXGI_FORMAT_R8G8B8A8_UNORM if (inSize >= 2 && outSize >= 4) { for (int ocount = 0, icount = 0; ((icount < (inSize - 1)) && (ocount < (outSize - 3))); icount += 2, ocount += 4) { ushort t = reader.ReadUInt16(); uint t1 = (uint)(((t & 0x0f00) >> 4) | ((t & 0x0f00) >> 8)); uint t2 = (uint)(((t & 0x00f0) << 8) | ((t & 0x00f0) << 4)); uint t3 = (uint)(((t & 0x000f) << 20) | ((t & 0x000f) << 16)); uint ta = ((flags & ScanlineFlags.SetAlpha) != 0 ? 0xff000000 : (uint)(((t & 0xf000) << 16) | ((t & 0xf000) << 12))); writer.Write((uint)(t1 | t2 | t3 | ta)); } return true; } return false; //#endif case LegacyFormat.L8: if (outFormat != DataFormat.R8G8B8A8_UNORM) return false; // D3DFMT_L8 -> DXGI_FORMAT_R8G8B8A8_UNORM if (inSize >= 1 && outSize >= 4) { for (int ocount = 0, icount = 0; ((icount < inSize) && (ocount < (outSize - 3))); ++icount, ocount += 4) { uint t1 = reader.ReadByte(); uint t2 = (t1 << 8); uint t3 = (t1 << 16); writer.Write((uint)(t1 | t2 | t3 | 0xff000000)); } return true; } return false; case LegacyFormat.L16: if (outFormat != DataFormat.R16G16B16A16_UNORM) return false; // D3DFMT_L16 -> DXGI_FORMAT_R16G16B16A16_UNORM if (inSize >= 2 && outSize >= 8) { for (int ocount = 0, icount = 0; ((icount < (inSize - 1)) && (ocount < (outSize - 7))); icount += 2, ocount += 8) { ushort t = reader.ReadUInt16(); ulong t1 = t; ulong t2 = (t1 << 16); ulong t3 = (t1 << 32); writer.Write((ulong)(t1 | t2 | t3 | 0xffff000000000000)); } return true; } return false; case LegacyFormat.A8L8: if (outFormat != DataFormat.R8G8B8A8_UNORM) return false; // D3DFMT_A8L8 -> DXGI_FORMAT_R8G8B8A8_UNORM if (inSize >= 2 && outSize >= 4) { for (int ocount = 0, icount = 0; ((icount < (inSize - 1)) && (ocount < (outSize - 3))); icount += 2, ocount += 4) { ushort t = reader.ReadUInt16(); uint t1 = (uint)(t & 0xff); uint t2 = (t1 << 8); uint t3 = (t1 << 16); uint ta = (flags & ScanlineFlags.SetAlpha) != 0 ? 0xff000000 : (uint)((t & 0xff00) << 16); writer.Write((int)(t1 | t2 | t3 | ta)); } return true; } return false; } return false; }