DirectXTexPMAlpha.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. //-------------------------------------------------------------------------------------
  2. // DirectXTexPMAlpha.cpp
  3. //
  4. // DirectX Texture Library - Premultiplied alpha operations
  5. //
  6. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  7. // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  8. // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  9. // PARTICULAR PURPOSE.
  10. //
  11. // Copyright (c) Microsoft Corporation. All rights reserved.
  12. //
  13. // http://go.microsoft.com/fwlink/?LinkId=248926
  14. //-------------------------------------------------------------------------------------
  15. #include "directxtexp.h"
  16. namespace DirectX
  17. {
  18. static HRESULT _PremultiplyAlpha( _In_ const Image& srcImage, _In_ const Image& destImage )
  19. {
  20. assert( srcImage.width == destImage.width );
  21. assert( srcImage.height == destImage.height );
  22. ScopedAlignedArrayXMVECTOR scanline( reinterpret_cast<XMVECTOR*>( _aligned_malloc( (sizeof(XMVECTOR)*srcImage.width), 16 ) ) );
  23. if ( !scanline )
  24. return E_OUTOFMEMORY;
  25. const uint8_t *pSrc = srcImage.pixels;
  26. uint8_t *pDest = destImage.pixels;
  27. if ( !pSrc || !pDest )
  28. return E_POINTER;
  29. for( size_t h = 0; h < srcImage.height; ++h )
  30. {
  31. if ( !_LoadScanline( scanline.get(), srcImage.width, pSrc, srcImage.rowPitch, srcImage.format ) )
  32. return E_FAIL;
  33. XMVECTOR* ptr = scanline.get();
  34. for( size_t w = 0; w < srcImage.width; ++w )
  35. {
  36. XMVECTOR v = *ptr;
  37. XMVECTOR alpha = XMVectorSplatW( *ptr );
  38. alpha = XMVectorMultiply( v, alpha );
  39. *(ptr++) = XMVectorSelect( v, alpha, g_XMSelect1110 );
  40. }
  41. if ( !_StoreScanline( pDest, destImage.rowPitch, destImage.format, scanline.get(), srcImage.width ) )
  42. return E_FAIL;
  43. pSrc += srcImage.rowPitch;
  44. pDest += destImage.rowPitch;
  45. }
  46. return S_OK;
  47. }
  48. static HRESULT _PremultiplyAlphaLinear( _In_ const Image& srcImage, _In_ DWORD flags, _In_ const Image& destImage )
  49. {
  50. assert( srcImage.width == destImage.width );
  51. assert( srcImage.height == destImage.height );
  52. static_assert( TEX_PMALPHA_SRGB_IN == TEX_FILTER_SRGB_IN, "TEX_PMALHPA_SRGB* should match TEX_FILTER_SRGB*" );
  53. static_assert( TEX_PMALPHA_SRGB_OUT == TEX_FILTER_SRGB_OUT, "TEX_PMALHPA_SRGB* should match TEX_FILTER_SRGB*" );
  54. static_assert( TEX_PMALPHA_SRGB == TEX_FILTER_SRGB, "TEX_PMALHPA_SRGB* should match TEX_FILTER_SRGB*" );
  55. flags &= TEX_PMALPHA_SRGB;
  56. ScopedAlignedArrayXMVECTOR scanline( reinterpret_cast<XMVECTOR*>( _aligned_malloc( (sizeof(XMVECTOR)*srcImage.width), 16 ) ) );
  57. if ( !scanline )
  58. return E_OUTOFMEMORY;
  59. const uint8_t *pSrc = srcImage.pixels;
  60. uint8_t *pDest = destImage.pixels;
  61. if ( !pSrc || !pDest )
  62. return E_POINTER;
  63. for( size_t h = 0; h < srcImage.height; ++h )
  64. {
  65. if ( !_LoadScanlineLinear( scanline.get(), srcImage.width, pSrc, srcImage.rowPitch, srcImage.format, flags ) )
  66. return E_FAIL;
  67. XMVECTOR* ptr = scanline.get();
  68. for( size_t w = 0; w < srcImage.width; ++w )
  69. {
  70. XMVECTOR v = *ptr;
  71. XMVECTOR alpha = XMVectorSplatW( *ptr );
  72. alpha = XMVectorMultiply( v, alpha );
  73. *(ptr++) = XMVectorSelect( v, alpha, g_XMSelect1110 );
  74. }
  75. if ( !_StoreScanlineLinear( pDest, destImage.rowPitch, destImage.format, scanline.get(), srcImage.width, flags ) )
  76. return E_FAIL;
  77. pSrc += srcImage.rowPitch;
  78. pDest += destImage.rowPitch;
  79. }
  80. return S_OK;
  81. }
  82. //=====================================================================================
  83. // Entry-points
  84. //=====================================================================================
  85. //-------------------------------------------------------------------------------------
  86. // Converts to a premultiplied alpha version of the texture
  87. //-------------------------------------------------------------------------------------
  88. _Use_decl_annotations_
  89. HRESULT PremultiplyAlpha( const Image& srcImage, DWORD flags, ScratchImage& image )
  90. {
  91. if ( !srcImage.pixels )
  92. return E_POINTER;
  93. if ( IsCompressed(srcImage.format)
  94. || IsPlanar(srcImage.format)
  95. || IsPalettized(srcImage.format)
  96. || IsTypeless(srcImage.format)
  97. || !HasAlpha(srcImage.format) )
  98. return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
  99. #ifdef _M_X64
  100. if ( (srcImage.width > 0xFFFFFFFF) || (srcImage.height > 0xFFFFFFFF) )
  101. return E_INVALIDARG;
  102. #endif
  103. HRESULT hr = image.Initialize2D( srcImage.format, srcImage.width, srcImage.height, 1, 1 );
  104. if ( FAILED(hr) )
  105. return hr;
  106. const Image *rimage = image.GetImage( 0, 0, 0 );
  107. if ( !rimage )
  108. {
  109. image.Release();
  110. return E_POINTER;
  111. }
  112. hr = ( flags & TEX_PMALPHA_IGNORE_SRGB ) ? _PremultiplyAlpha( srcImage, *rimage ) : _PremultiplyAlphaLinear( srcImage, flags, *rimage );
  113. if ( FAILED(hr) )
  114. {
  115. image.Release();
  116. return hr;
  117. }
  118. return S_OK;
  119. }
  120. //-------------------------------------------------------------------------------------
  121. // Converts to a premultiplied alpha version of the texture (complex)
  122. //-------------------------------------------------------------------------------------
  123. _Use_decl_annotations_
  124. HRESULT PremultiplyAlpha( const Image* srcImages, size_t nimages, const TexMetadata& metadata, DWORD flags, ScratchImage& result )
  125. {
  126. if ( !srcImages || !nimages )
  127. return E_INVALIDARG;
  128. if ( IsCompressed(metadata.format)
  129. || IsPlanar(metadata.format)
  130. || IsPalettized(metadata.format)
  131. || IsTypeless(metadata.format)
  132. || !HasAlpha(metadata.format) )
  133. return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
  134. #ifdef _M_X64
  135. if ( (metadata.width > 0xFFFFFFFF) || (metadata.height > 0xFFFFFFFF) )
  136. return E_INVALIDARG;
  137. #endif
  138. if ( metadata.IsPMAlpha() )
  139. {
  140. // Already premultiplied
  141. return E_FAIL;
  142. }
  143. TexMetadata mdata2 = metadata;
  144. mdata2.SetAlphaMode(TEX_ALPHA_MODE_PREMULTIPLIED);
  145. HRESULT hr = result.Initialize( mdata2 );
  146. if ( FAILED(hr) )
  147. return hr;
  148. if ( nimages != result.GetImageCount() )
  149. {
  150. result.Release();
  151. return E_FAIL;
  152. }
  153. const Image* dest = result.GetImages();
  154. if ( !dest )
  155. {
  156. result.Release();
  157. return E_POINTER;
  158. }
  159. for( size_t index=0; index < nimages; ++index )
  160. {
  161. const Image& src = srcImages[ index ];
  162. if ( src.format != metadata.format )
  163. {
  164. result.Release();
  165. return E_FAIL;
  166. }
  167. #ifdef _M_X64
  168. if ( (src.width > 0xFFFFFFFF) || (src.height > 0xFFFFFFFF) )
  169. return E_FAIL;
  170. #endif
  171. const Image& dst = dest[ index ];
  172. assert( dst.format == metadata.format );
  173. if ( src.width != dst.width || src.height != dst.height )
  174. {
  175. result.Release();
  176. return E_FAIL;
  177. }
  178. hr = ( flags & TEX_PMALPHA_IGNORE_SRGB ) ? _PremultiplyAlpha( src, dst ) : _PremultiplyAlphaLinear( src, flags, dst );
  179. if ( FAILED(hr) )
  180. {
  181. result.Release();
  182. return hr;
  183. }
  184. }
  185. return S_OK;
  186. }
  187. }; // namespace