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
16 #include "directxtexp.h"
17
18 namespace DirectX
19 {
20
_PremultiplyAlpha(_In_ const Image & srcImage,_In_ const Image & destImage)21 static HRESULT _PremultiplyAlpha( _In_ const Image& srcImage, _In_ const Image& destImage )
22 {
23 assert( srcImage.width == destImage.width );
24 assert( srcImage.height == destImage.height );
25
26 ScopedAlignedArrayXMVECTOR scanline( reinterpret_cast<XMVECTOR*>( _aligned_malloc( (sizeof(XMVECTOR)*srcImage.width), 16 ) ) );
27 if ( !scanline )
28 return E_OUTOFMEMORY;
29
30 const uint8_t *pSrc = srcImage.pixels;
31 uint8_t *pDest = destImage.pixels;
32 if ( !pSrc || !pDest )
33 return E_POINTER;
34
35 for( size_t h = 0; h < srcImage.height; ++h )
36 {
37 if ( !_LoadScanline( scanline.get(), srcImage.width, pSrc, srcImage.rowPitch, srcImage.format ) )
38 return E_FAIL;
39
40 XMVECTOR* ptr = scanline.get();
41 for( size_t w = 0; w < srcImage.width; ++w )
42 {
43 XMVECTOR v = *ptr;
44 XMVECTOR alpha = XMVectorSplatW( *ptr );
45 alpha = XMVectorMultiply( v, alpha );
46 *(ptr++) = XMVectorSelect( v, alpha, g_XMSelect1110 );
47 }
48
49 if ( !_StoreScanline( pDest, destImage.rowPitch, destImage.format, scanline.get(), srcImage.width ) )
50 return E_FAIL;
51
52 pSrc += srcImage.rowPitch;
53 pDest += destImage.rowPitch;
54 }
55
56 return S_OK;
57 }
58
_PremultiplyAlphaLinear(_In_ const Image & srcImage,_In_ DWORD flags,_In_ const Image & destImage)59 static HRESULT _PremultiplyAlphaLinear( _In_ const Image& srcImage, _In_ DWORD flags, _In_ const Image& destImage )
60 {
61 assert( srcImage.width == destImage.width );
62 assert( srcImage.height == destImage.height );
63
64 static_assert( TEX_PMALPHA_SRGB_IN == TEX_FILTER_SRGB_IN, "TEX_PMALHPA_SRGB* should match TEX_FILTER_SRGB*" );
65 static_assert( TEX_PMALPHA_SRGB_OUT == TEX_FILTER_SRGB_OUT, "TEX_PMALHPA_SRGB* should match TEX_FILTER_SRGB*" );
66 static_assert( TEX_PMALPHA_SRGB == TEX_FILTER_SRGB, "TEX_PMALHPA_SRGB* should match TEX_FILTER_SRGB*" );
67 flags &= TEX_PMALPHA_SRGB;
68
69 ScopedAlignedArrayXMVECTOR scanline( reinterpret_cast<XMVECTOR*>( _aligned_malloc( (sizeof(XMVECTOR)*srcImage.width), 16 ) ) );
70 if ( !scanline )
71 return E_OUTOFMEMORY;
72
73 const uint8_t *pSrc = srcImage.pixels;
74 uint8_t *pDest = destImage.pixels;
75 if ( !pSrc || !pDest )
76 return E_POINTER;
77
78 for( size_t h = 0; h < srcImage.height; ++h )
79 {
80 if ( !_LoadScanlineLinear( scanline.get(), srcImage.width, pSrc, srcImage.rowPitch, srcImage.format, flags ) )
81 return E_FAIL;
82
83 XMVECTOR* ptr = scanline.get();
84 for( size_t w = 0; w < srcImage.width; ++w )
85 {
86 XMVECTOR v = *ptr;
87 XMVECTOR alpha = XMVectorSplatW( *ptr );
88 alpha = XMVectorMultiply( v, alpha );
89 *(ptr++) = XMVectorSelect( v, alpha, g_XMSelect1110 );
90 }
91
92 if ( !_StoreScanlineLinear( pDest, destImage.rowPitch, destImage.format, scanline.get(), srcImage.width, flags ) )
93 return E_FAIL;
94
95 pSrc += srcImage.rowPitch;
96 pDest += destImage.rowPitch;
97 }
98
99 return S_OK;
100 }
101
102
103 //=====================================================================================
104 // Entry-points
105 //=====================================================================================
106
107 //-------------------------------------------------------------------------------------
108 // Converts to a premultiplied alpha version of the texture
109 //-------------------------------------------------------------------------------------
110 _Use_decl_annotations_
PremultiplyAlpha(const Image & srcImage,DWORD flags,ScratchImage & image)111 HRESULT PremultiplyAlpha( const Image& srcImage, DWORD flags, ScratchImage& image )
112 {
113 if ( !srcImage.pixels )
114 return E_POINTER;
115
116 if ( IsCompressed(srcImage.format)
117 || IsPlanar(srcImage.format)
118 || IsPalettized(srcImage.format)
119 || IsTypeless(srcImage.format)
120 || !HasAlpha(srcImage.format) )
121 return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
122
123 #ifdef _M_X64
124 if ( (srcImage.width > 0xFFFFFFFF) || (srcImage.height > 0xFFFFFFFF) )
125 return E_INVALIDARG;
126 #endif
127
128 HRESULT hr = image.Initialize2D( srcImage.format, srcImage.width, srcImage.height, 1, 1 );
129 if ( FAILED(hr) )
130 return hr;
131
132 const Image *rimage = image.GetImage( 0, 0, 0 );
133 if ( !rimage )
134 {
135 image.Release();
136 return E_POINTER;
137 }
138
139 hr = ( flags & TEX_PMALPHA_IGNORE_SRGB ) ? _PremultiplyAlpha( srcImage, *rimage ) : _PremultiplyAlphaLinear( srcImage, flags, *rimage );
140 if ( FAILED(hr) )
141 {
142 image.Release();
143 return hr;
144 }
145
146 return S_OK;
147 }
148
149
150 //-------------------------------------------------------------------------------------
151 // Converts to a premultiplied alpha version of the texture (complex)
152 //-------------------------------------------------------------------------------------
153 _Use_decl_annotations_
PremultiplyAlpha(const Image * srcImages,size_t nimages,const TexMetadata & metadata,DWORD flags,ScratchImage & result)154 HRESULT PremultiplyAlpha( const Image* srcImages, size_t nimages, const TexMetadata& metadata, DWORD flags, ScratchImage& result )
155 {
156 if ( !srcImages || !nimages )
157 return E_INVALIDARG;
158
159 if ( IsCompressed(metadata.format)
160 || IsPlanar(metadata.format)
161 || IsPalettized(metadata.format)
162 || IsTypeless(metadata.format)
163 || !HasAlpha(metadata.format) )
164 return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
165
166 #ifdef _M_X64
167 if ( (metadata.width > 0xFFFFFFFF) || (metadata.height > 0xFFFFFFFF) )
168 return E_INVALIDARG;
169 #endif
170
171 if ( metadata.IsPMAlpha() )
172 {
173 // Already premultiplied
174 return E_FAIL;
175 }
176
177 TexMetadata mdata2 = metadata;
178 mdata2.SetAlphaMode(TEX_ALPHA_MODE_PREMULTIPLIED);
179 HRESULT hr = result.Initialize( mdata2 );
180 if ( FAILED(hr) )
181 return hr;
182
183 if ( nimages != result.GetImageCount() )
184 {
185 result.Release();
186 return E_FAIL;
187 }
188
189 const Image* dest = result.GetImages();
190 if ( !dest )
191 {
192 result.Release();
193 return E_POINTER;
194 }
195
196 for( size_t index=0; index < nimages; ++index )
197 {
198 const Image& src = srcImages[ index ];
199 if ( src.format != metadata.format )
200 {
201 result.Release();
202 return E_FAIL;
203 }
204
205 #ifdef _M_X64
206 if ( (src.width > 0xFFFFFFFF) || (src.height > 0xFFFFFFFF) )
207 return E_FAIL;
208 #endif
209 const Image& dst = dest[ index ];
210 assert( dst.format == metadata.format );
211
212 if ( src.width != dst.width || src.height != dst.height )
213 {
214 result.Release();
215 return E_FAIL;
216 }
217
218 hr = ( flags & TEX_PMALPHA_IGNORE_SRGB ) ? _PremultiplyAlpha( src, dst ) : _PremultiplyAlphaLinear( src, flags, dst );
219 if ( FAILED(hr) )
220 {
221 result.Release();
222 return hr;
223 }
224 }
225
226 return S_OK;
227 }
228
229 }; // namespace
230