]> git.cworth.org Git - apitrace/blob - thirdparty/directxtex/DirectXTex/DirectXTexConvert.cpp
directxtex: Get it building on MinGW.
[apitrace] / thirdparty / directxtex / DirectXTex / DirectXTexConvert.cpp
1 //-------------------------------------------------------------------------------------
2 // DirectXTexConvert.cpp
3 //  
4 // DirectX Texture Library - Image conversion 
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 #ifdef USE_XNAMATH
19 #if XNAMATH_VERSION < 205
20 #error This file requires XNAMATH v2.05 or later
21 #endif
22 #else
23 using namespace DirectX::PackedVector;
24 #endif
25
26 namespace DirectX
27 {
28
29 //-------------------------------------------------------------------------------------
30 // Copies an image row with optional clearing of alpha value to 1.0
31 // (can be used in place as well) otherwise copies the image row unmodified.
32 //-------------------------------------------------------------------------------------
33 void _CopyScanline( LPVOID pDestination, size_t outSize, LPCVOID pSource, size_t inSize, DXGI_FORMAT format, DWORD flags )
34 {
35     assert( pDestination && outSize > 0 );
36     assert( pSource && inSize > 0 );
37     assert( IsValid(format) && !IsVideo(format) );
38
39     if ( flags & TEXP_SCANLINE_SETALPHA )
40     {
41         switch( format )
42         {
43         //-----------------------------------------------------------------------------
44         case DXGI_FORMAT_R32G32B32A32_TYPELESS:
45         case DXGI_FORMAT_R32G32B32A32_FLOAT:
46         case DXGI_FORMAT_R32G32B32A32_UINT:
47         case DXGI_FORMAT_R32G32B32A32_SINT:
48             {
49                 uint32_t alpha;
50                 if ( format == DXGI_FORMAT_R32G32B32A32_FLOAT )
51                     alpha = 0x3f800000;
52                 else if ( format == DXGI_FORMAT_R32G32B32A32_SINT )
53                     alpha = 0x7fffffff;
54                 else
55                     alpha = 0xffffffff;
56
57                 if ( pDestination == pSource )
58                 {
59                     uint32_t *dPtr = reinterpret_cast<uint32_t*>(pDestination);
60                     for( size_t count = 0; count < outSize; count += 16 )
61                     {
62                         dPtr += 3;
63                         *(dPtr++) = alpha;
64                     }
65                 }
66                 else
67                 {
68                     const uint32_t * __restrict sPtr = reinterpret_cast<const uint32_t*>(pSource);
69                     uint32_t * __restrict dPtr = reinterpret_cast<uint32_t*>(pDestination);
70                     size_t size = std::min<size_t>( outSize, inSize );
71                     for( size_t count = 0; count < size; count += 16 )
72                     {
73                         *(dPtr++) = *(sPtr++);
74                         *(dPtr++) = *(sPtr++);
75                         *(dPtr++) = *(sPtr++);
76                         *(dPtr++) = alpha;
77                         sPtr++;
78                     }
79                 }
80             }
81             return;
82
83         //-----------------------------------------------------------------------------
84         case DXGI_FORMAT_R16G16B16A16_TYPELESS:
85         case DXGI_FORMAT_R16G16B16A16_FLOAT:
86         case DXGI_FORMAT_R16G16B16A16_UNORM:
87         case DXGI_FORMAT_R16G16B16A16_UINT:
88         case DXGI_FORMAT_R16G16B16A16_SNORM:
89         case DXGI_FORMAT_R16G16B16A16_SINT:
90             {
91                 uint16_t alpha;
92                 if ( format == DXGI_FORMAT_R16G16B16A16_FLOAT )
93                     alpha = 0x3c00;
94                 else if ( format == DXGI_FORMAT_R16G16B16A16_SNORM || format == DXGI_FORMAT_R16G16B16A16_SINT )
95                     alpha = 0x7fff;
96                 else
97                     alpha = 0xffff;
98
99                 if ( pDestination == pSource )
100                 {
101                     uint16_t *dPtr = reinterpret_cast<uint16_t*>(pDestination);
102                     for( size_t count = 0; count < outSize; count += 8 )
103                     {
104                         dPtr += 3;
105                         *(dPtr++) = alpha;
106                     }
107                 }
108                 else
109                 {
110                     const uint16_t * __restrict sPtr = reinterpret_cast<const uint16_t*>(pSource);
111                     uint16_t * __restrict dPtr = reinterpret_cast<uint16_t*>(pDestination);
112                     size_t size = std::min<size_t>( outSize, inSize );
113                     for( size_t count = 0; count < size; count += 8 )
114                     {
115                         *(dPtr++) = *(sPtr++);
116                         *(dPtr++) = *(sPtr++);
117                         *(dPtr++) = *(sPtr++);
118                         *(dPtr++) = alpha;
119                         sPtr++;
120                     }
121                 }
122             }
123             return;
124
125         //-----------------------------------------------------------------------------
126         case DXGI_FORMAT_R10G10B10A2_TYPELESS:
127         case DXGI_FORMAT_R10G10B10A2_UNORM:
128         case DXGI_FORMAT_R10G10B10A2_UINT:
129         case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:
130             if ( pDestination == pSource )
131             {
132                 uint32_t *dPtr = reinterpret_cast<uint32_t*>(pDestination);
133                 for( size_t count = 0; count < outSize; count += 4 )
134                 {
135 #pragma warning(suppress: 6001 6101) // PREFast doesn't properly understand the aliasing here.
136                     *dPtr |= 0xC0000000;
137                     ++dPtr;
138                 }
139             }
140             else
141             {
142                 const uint32_t * __restrict sPtr = reinterpret_cast<const uint32_t*>(pSource);
143                 uint32_t * __restrict dPtr = reinterpret_cast<uint32_t*>(pDestination);
144                 size_t size = std::min<size_t>( outSize, inSize );
145                 for( size_t count = 0; count < size; count += 4 )
146                 {
147                     *(dPtr++) = *(sPtr++) | 0xC0000000;
148                 }
149             }
150             return;
151
152         //-----------------------------------------------------------------------------
153         case DXGI_FORMAT_R8G8B8A8_TYPELESS:
154         case DXGI_FORMAT_R8G8B8A8_UNORM:
155         case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
156         case DXGI_FORMAT_R8G8B8A8_UINT:
157         case DXGI_FORMAT_R8G8B8A8_SNORM:
158         case DXGI_FORMAT_R8G8B8A8_SINT:
159         case DXGI_FORMAT_B8G8R8A8_UNORM:
160         case DXGI_FORMAT_B8G8R8A8_TYPELESS:
161         case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
162             {
163                 const uint32_t alpha = ( format == DXGI_FORMAT_R8G8B8A8_SNORM || format == DXGI_FORMAT_R8G8B8A8_SINT ) ? 0x7f000000 : 0xff000000;
164
165                 if ( pDestination == pSource )
166                 {
167                     uint32_t *dPtr = reinterpret_cast<uint32_t*>(pDestination);
168                     for( size_t count = 0; count < outSize; count += 4 )
169                     {
170                         uint32_t t = *dPtr & 0xFFFFFF;
171                         t |= alpha;
172                         *(dPtr++) = t;
173                     }
174                 }
175                 else
176                 {
177                     const uint32_t * __restrict sPtr = reinterpret_cast<const uint32_t*>(pSource);
178                     uint32_t * __restrict dPtr = reinterpret_cast<uint32_t*>(pDestination);
179                     size_t size = std::min<size_t>( outSize, inSize );
180                     for( size_t count = 0; count < size; count += 4 )
181                     {
182                         uint32_t t = *(sPtr++) & 0xFFFFFF;
183                         t |= alpha;
184                         *(dPtr++) = t;
185                     }
186                 }
187             }
188             return;
189
190         //-----------------------------------------------------------------------------
191         case DXGI_FORMAT_B5G5R5A1_UNORM:
192             if ( pDestination == pSource )
193             {
194                 uint16_t *dPtr = reinterpret_cast<uint16_t*>(pDestination);
195                 for( size_t count = 0; count < outSize; count += 2 )
196                 {
197                     *(dPtr++) |= 0x8000;
198                 }
199             }
200             else
201             {
202                 const uint16_t * __restrict sPtr = reinterpret_cast<const uint16_t*>(pSource);
203                 uint16_t * __restrict dPtr = reinterpret_cast<uint16_t*>(pDestination);
204                 size_t size = std::min<size_t>( outSize, inSize );
205                 for( size_t count = 0; count < size; count += 2 )
206                 {
207                     *(dPtr++) = *(sPtr++) | 0x8000;
208                 }
209             }
210             return;
211
212         //-----------------------------------------------------------------------------
213         case DXGI_FORMAT_A8_UNORM:
214             memset( pDestination, 0xff, outSize );
215             return;
216
217 #ifdef DXGI_1_2_FORMATS
218         //-----------------------------------------------------------------------------
219         case DXGI_FORMAT_B4G4R4A4_UNORM:
220             if ( pDestination == pSource )
221             {
222                 uint16_t *dPtr = reinterpret_cast<uint16_t*>(pDestination);
223                 for( size_t count = 0; count < outSize; count += 2 )
224                 {
225                     *(dPtr++) |= 0xF000;
226                 }
227             }
228             else
229             {
230                 const uint16_t * __restrict sPtr = reinterpret_cast<const uint16_t*>(pSource);
231                 uint16_t * __restrict dPtr = reinterpret_cast<uint16_t*>(pDestination);
232                 size_t size = std::min<size_t>( outSize, inSize );
233                 for( size_t count = 0; count < size; count += 2 )
234                 {
235                     *(dPtr++) = *(sPtr++) | 0xF000;
236                 }
237             }
238             return;
239 #endif // DXGI_1_2_FORMATS
240         }
241     }
242
243     // Fall-through case is to just use memcpy (assuming this is not an in-place operation)
244     if ( pDestination == pSource )
245         return;
246
247     size_t size = std::min<size_t>( outSize, inSize );
248     memcpy_s( pDestination, outSize, pSource, size );
249 }
250
251
252 //-------------------------------------------------------------------------------------
253 // Swizzles (RGB <-> BGR) an image row with optional clearing of alpha value to 1.0
254 // (can be used in place as well) otherwise copies the image row unmodified.
255 //-------------------------------------------------------------------------------------
256 void _SwizzleScanline( LPVOID pDestination, size_t outSize, LPCVOID pSource, size_t inSize, DXGI_FORMAT format, DWORD flags )
257 {
258     assert( pDestination && outSize > 0 );
259     assert( pSource && inSize > 0 );
260     assert( IsValid(format) && !IsVideo(format) );
261
262     switch( format )
263     {
264     //---------------------------------------------------------------------------------
265     case DXGI_FORMAT_R10G10B10A2_TYPELESS:
266     case DXGI_FORMAT_R10G10B10A2_UNORM:
267     case DXGI_FORMAT_R10G10B10A2_UINT:
268     case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:
269         if ( flags & TEXP_SCANLINE_LEGACY )
270         {
271             // Swap Red (R) and Blue (B) channel (used for D3DFMT_A2R10G10B10 legacy sources)
272             if ( pDestination == pSource )
273             {
274                 uint32_t *dPtr = reinterpret_cast<uint32_t*>(pDestination);
275                 for( size_t count = 0; count < outSize; count += 4 )
276                 {
277 #pragma warning(suppress: 6001 6101) // PREFast doesn't properly understand the aliasing here.
278                     uint32_t t = *dPtr;
279
280                     uint32_t t1 = (t & 0x3ff00000) >> 20;
281                     uint32_t t2 = (t & 0x000003ff) << 20;
282                     uint32_t t3 = (t & 0x000ffc00);
283                     uint32_t ta = ( flags & TEXP_SCANLINE_SETALPHA ) ? 0xC0000000 : (t & 0xC0000000);
284
285                     *(dPtr++) = t1 | t2 | t3 | ta;
286                 }
287             }
288             else
289             {
290                 const uint32_t * __restrict sPtr = reinterpret_cast<const uint32_t*>(pSource);
291                 uint32_t * __restrict dPtr = reinterpret_cast<uint32_t*>(pDestination);
292                 size_t size = std::min<size_t>( outSize, inSize );
293                 for( size_t count = 0; count < size; count += 4 )
294                 {
295                     uint32_t t = *(sPtr++);
296
297                     uint32_t t1 = (t & 0x3ff00000) >> 20;
298                     uint32_t t2 = (t & 0x000003ff) << 20;
299                     uint32_t t3 = (t & 0x000ffc00);
300                     uint32_t ta = ( flags & TEXP_SCANLINE_SETALPHA ) ? 0xC0000000 : (t & 0xC0000000);
301
302                     *(dPtr++) = t1 | t2 | t3 | ta;
303                 }
304             }
305             return;
306         }
307         break;
308
309     //---------------------------------------------------------------------------------
310     case DXGI_FORMAT_R8G8B8A8_TYPELESS:
311     case DXGI_FORMAT_R8G8B8A8_UNORM:
312     case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
313     case DXGI_FORMAT_B8G8R8A8_UNORM:
314     case DXGI_FORMAT_B8G8R8X8_UNORM:
315     case DXGI_FORMAT_B8G8R8A8_TYPELESS:
316     case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
317     case DXGI_FORMAT_B8G8R8X8_TYPELESS:
318     case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
319         // Swap Red (R) and Blue (B) channels (used to convert from DXGI 1.1 BGR formats to DXGI 1.0 RGB)
320         if ( pDestination == pSource )
321         {
322             uint32_t *dPtr = reinterpret_cast<uint32_t*>(pDestination);
323             for( size_t count = 0; count < outSize; count += 4 )
324             {
325                 uint32_t t = *dPtr;
326
327                 uint32_t t1 = (t & 0x00ff0000) >> 16;
328                 uint32_t t2 = (t & 0x000000ff) << 16;
329                 uint32_t t3 = (t & 0x0000ff00);
330                 uint32_t ta = ( flags & TEXP_SCANLINE_SETALPHA ) ? 0xff000000 : (t & 0xFF000000);
331
332                 *(dPtr++) = t1 | t2 | t3 | ta;
333             }
334         }
335         else
336         {
337             const uint32_t * __restrict sPtr = reinterpret_cast<const uint32_t*>(pSource);
338             uint32_t * __restrict dPtr = reinterpret_cast<uint32_t*>(pDestination);
339             size_t size = std::min<size_t>( outSize, inSize );
340             for( size_t count = 0; count < size; count += 4 )
341             {
342                 uint32_t t = *(sPtr++);
343
344                 uint32_t t1 = (t & 0x00ff0000) >> 16;
345                 uint32_t t2 = (t & 0x000000ff) << 16;
346                 uint32_t t3 = (t & 0x0000ff00);
347                 uint32_t ta = ( flags & TEXP_SCANLINE_SETALPHA ) ? 0xff000000 : (t & 0xFF000000);
348
349                 *(dPtr++) = t1 | t2 | t3 | ta;
350             }
351         }
352         return;
353     }
354
355     // Fall-through case is to just use memcpy (assuming this is not an in-place operation)
356     if ( pDestination == pSource )
357         return;
358
359     size_t size = std::min<size_t>( outSize, inSize );
360     memcpy_s( pDestination, outSize, pSource, size );
361 }
362
363
364 //-------------------------------------------------------------------------------------
365 // Converts an image row with optional clearing of alpha value to 1.0
366 // Returns true if supported, false if expansion case not supported
367 //-------------------------------------------------------------------------------------
368 bool _ExpandScanline( LPVOID pDestination, size_t outSize, DXGI_FORMAT outFormat,  
369                       LPCVOID pSource, size_t inSize, DXGI_FORMAT inFormat, DWORD flags )
370 {
371     assert( pDestination && outSize > 0 );
372     assert( pSource && inSize > 0 );
373     assert( IsValid(outFormat) && !IsVideo(outFormat) );
374     assert( IsValid(inFormat) && !IsVideo(inFormat) );
375
376     switch( inFormat )
377     {
378     case DXGI_FORMAT_B5G6R5_UNORM:
379         if ( outFormat != DXGI_FORMAT_R8G8B8A8_UNORM )
380             return false;
381
382         // DXGI_FORMAT_B5G6R5_UNORM -> DXGI_FORMAT_R8G8B8A8_UNORM
383         {
384             const uint16_t * __restrict sPtr = reinterpret_cast<const uint16_t*>(pSource);
385             uint32_t * __restrict dPtr = reinterpret_cast<uint32_t*>(pDestination);
386
387             for( size_t ocount = 0, icount = 0; ((icount < inSize) && (ocount < outSize)); icount += 2, ocount += 4 )
388             {
389                 uint16_t t = *(sPtr++);
390
391                 uint32_t t1 = ((t & 0xf800) >> 8) | ((t & 0xe000) >> 13);
392                 uint32_t t2 = ((t & 0x07e0) << 5) | ((t & 0x0600) >> 5);
393                 uint32_t t3 = ((t & 0x001f) << 19) | ((t & 0x001c) << 14);
394
395                 *(dPtr++) = t1 | t2 | t3 | 0xff000000;
396             }
397         }
398         return true;
399         
400     case DXGI_FORMAT_B5G5R5A1_UNORM:
401         if ( outFormat != DXGI_FORMAT_R8G8B8A8_UNORM )
402             return false;
403
404         // DXGI_FORMAT_B5G5R5A1_UNORM -> DXGI_FORMAT_R8G8B8A8_UNORM
405         {
406             const uint16_t * __restrict sPtr = reinterpret_cast<const uint16_t*>(pSource);
407             uint32_t * __restrict dPtr = reinterpret_cast<uint32_t*>(pDestination);
408
409             for( size_t ocount = 0, icount = 0; ((icount < inSize) && (ocount < outSize)); icount += 2, ocount += 4 )
410             {
411                 uint16_t t = *(sPtr++);
412
413                 uint32_t t1 = ((t & 0x7c00) >> 7) | ((t & 0x7000) >> 12);
414                 uint32_t t2 = ((t & 0x03e0) << 6) | ((t & 0x0380) << 1);
415                 uint32_t t3 = ((t & 0x001f) << 19) | ((t & 0x001c) << 14);
416                 uint32_t ta = ( flags & TEXP_SCANLINE_SETALPHA ) ? 0xff000000 : ((t & 0x8000) ? 0xff000000 : 0);
417
418                 *(dPtr++) = t1 | t2 | t3 | ta;
419             }
420         }
421         return true;
422
423 #ifdef DXGI_1_2_FORMATS
424     case DXGI_FORMAT_B4G4R4A4_UNORM:
425         if ( outFormat != DXGI_FORMAT_R8G8B8A8_UNORM )
426             return false;
427
428         // DXGI_FORMAT_B4G4R4A4_UNORM -> DXGI_FORMAT_R8G8B8A8_UNORM
429         {
430             const uint16_t * __restrict sPtr = reinterpret_cast<const uint16_t*>(pSource);
431             uint32_t * __restrict dPtr = reinterpret_cast<uint32_t*>(pDestination);
432
433             for( size_t ocount = 0, icount = 0; ((icount < inSize) && (ocount < outSize)); icount += 2, ocount += 4 )
434             {
435                 uint16_t t = *(sPtr++);
436
437                 uint32_t t1 = ((t & 0x0f00) >> 4) | ((t & 0x0f00) >> 8);
438                 uint32_t t2 = ((t & 0x00f0) << 8) | ((t & 0x00f0) << 4);
439                 uint32_t t3 = ((t & 0x000f) << 20) | ((t & 0x000f) << 16);
440                 uint32_t ta = ( flags & TEXP_SCANLINE_SETALPHA ) ? 0xff000000 : (((t & 0xf000) << 16) | ((t & 0xf000) << 12));
441
442                 *(dPtr++) = t1 | t2 | t3 | ta;
443             }
444         }
445         return true;
446 #endif // DXGI_1_2_FORMATS
447     }
448
449     return false;
450 }
451
452
453 //-------------------------------------------------------------------------------------
454 // Loads an image row into standard RGBA XMVECTOR (aligned) array
455 //-------------------------------------------------------------------------------------
456 #define LOAD_SCANLINE( type, func )\
457         if ( size >= sizeof(type) )\
458         {\
459             const type * __restrict sPtr = reinterpret_cast<const type*>(pSource);\
460             for( size_t icount = 0; icount < size; icount += sizeof(type) )\
461             {\
462                 if ( dPtr >= ePtr ) break;\
463                 *(dPtr++) = func( sPtr++ );\
464             }\
465             return true;\
466         }\
467         return false;
468
469 #define LOAD_SCANLINE3( type, func, defvec )\
470         if ( size >= sizeof(type) )\
471         {\
472             const type * __restrict sPtr = reinterpret_cast<const type*>(pSource);\
473             for( size_t icount = 0; icount < size; icount += sizeof(type) )\
474             {\
475                 XMVECTOR v = func( sPtr++ );\
476                 if ( dPtr >= ePtr ) break;\
477                 *(dPtr++) = XMVectorSelect( defvec, v, g_XMSelect1110 );\
478             }\
479             return true;\
480         }\
481         return false;
482
483 #define LOAD_SCANLINE2( type, func, defvec )\
484         if ( size >= sizeof(type) )\
485         {\
486             const type * __restrict sPtr = reinterpret_cast<const type*>(pSource);\
487             for( size_t icount = 0; icount < size; icount += sizeof(type) )\
488             {\
489                 XMVECTOR v = func( sPtr++ );\
490                 if ( dPtr >= ePtr ) break;\
491                 *(dPtr++) = XMVectorSelect( defvec, v, g_XMSelect1100 );\
492             }\
493             return true;\
494         }\
495         return false;
496
497 bool _LoadScanline( XMVECTOR* pDestination, size_t count,
498                     LPCVOID pSource, size_t size, DXGI_FORMAT format )
499 {
500     assert( pDestination && count > 0 && (((uintptr_t)pDestination & 0xF) == 0) );
501     assert( pSource && size > 0 );
502     assert( IsValid(format) && !IsVideo(format) && !IsTypeless(format) && !IsCompressed(format) );
503
504     XMVECTOR* __restrict dPtr = pDestination;
505     if ( !dPtr )
506         return false;
507
508     const XMVECTOR* ePtr = pDestination + count;
509
510     switch( format )
511     {
512     case DXGI_FORMAT_R32G32B32A32_FLOAT:
513         {
514             size_t msize = (size > (sizeof(XMVECTOR)*count)) ? (sizeof(XMVECTOR)*count) : size;
515             memcpy_s( dPtr, sizeof(XMVECTOR)*count, pSource, msize );
516         }
517         return true;
518
519     case DXGI_FORMAT_R32G32B32A32_UINT:
520         LOAD_SCANLINE( XMUINT4, XMLoadUInt4 )
521
522     case DXGI_FORMAT_R32G32B32A32_SINT:
523         LOAD_SCANLINE( XMINT4, XMLoadSInt4 )
524
525     case DXGI_FORMAT_R32G32B32_FLOAT:
526         LOAD_SCANLINE3( XMFLOAT3, XMLoadFloat3, g_XMIdentityR3 )
527
528     case DXGI_FORMAT_R32G32B32_UINT:
529         LOAD_SCANLINE3( XMUINT3, XMLoadUInt3, g_XMIdentityR3 )
530
531     case DXGI_FORMAT_R32G32B32_SINT:
532         LOAD_SCANLINE3( XMINT3, XMLoadSInt3, g_XMIdentityR3 )
533
534     case DXGI_FORMAT_R16G16B16A16_FLOAT:
535         LOAD_SCANLINE( XMHALF4, XMLoadHalf4 )
536
537     case DXGI_FORMAT_R16G16B16A16_UNORM:
538         LOAD_SCANLINE( XMUSHORTN4, XMLoadUShortN4 ) 
539
540     case DXGI_FORMAT_R16G16B16A16_UINT:
541         LOAD_SCANLINE( XMUSHORT4, XMLoadUShort4 )
542
543     case DXGI_FORMAT_R16G16B16A16_SNORM:
544         LOAD_SCANLINE( XMSHORTN4, XMLoadShortN4 )
545
546     case DXGI_FORMAT_R16G16B16A16_SINT:
547         LOAD_SCANLINE( XMSHORT4, XMLoadShort4 )
548
549     case DXGI_FORMAT_R32G32_FLOAT:
550         LOAD_SCANLINE2( XMFLOAT2, XMLoadFloat2, g_XMIdentityR3 )
551
552     case DXGI_FORMAT_R32G32_UINT:
553         LOAD_SCANLINE2( XMUINT2, XMLoadUInt2, g_XMIdentityR3 )
554
555     case DXGI_FORMAT_R32G32_SINT:
556         LOAD_SCANLINE2( XMINT2, XMLoadSInt2, g_XMIdentityR3 )
557
558     case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:
559         if ( size >= (sizeof(float)+sizeof(uint32_t)) )
560         {
561             const float * sPtr = reinterpret_cast<const float*>(pSource);
562             for( size_t icount = 0; icount < size; icount += (sizeof(float)+sizeof(uint32_t)) )
563             {
564                 const uint8_t* ps8 = reinterpret_cast<const uint8_t*>( &sPtr[1] );
565                 if ( dPtr >= ePtr ) break;
566                 *(dPtr++) = XMVectorSet( sPtr[0], static_cast<float>( *ps8 ), 0.f, 1.f );
567                 sPtr += 2;
568             }
569             return true;
570         }
571         return false;
572
573     case DXGI_FORMAT_R10G10B10A2_UNORM:
574     case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:
575         LOAD_SCANLINE( XMUDECN4, XMLoadUDecN4 );
576
577     case DXGI_FORMAT_R10G10B10A2_UINT:
578         LOAD_SCANLINE( XMUDEC4, XMLoadUDec4 );
579
580     case DXGI_FORMAT_R11G11B10_FLOAT:
581         LOAD_SCANLINE3( XMFLOAT3PK, XMLoadFloat3PK, g_XMIdentityR3 );
582
583     case DXGI_FORMAT_R8G8B8A8_UNORM:
584     case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
585         LOAD_SCANLINE( XMUBYTEN4, XMLoadUByteN4 )
586
587     case DXGI_FORMAT_R8G8B8A8_UINT:
588         LOAD_SCANLINE( XMUBYTE4, XMLoadUByte4 )
589
590     case DXGI_FORMAT_R8G8B8A8_SNORM:
591         LOAD_SCANLINE( XMBYTEN4, XMLoadByteN4 )
592
593     case DXGI_FORMAT_R8G8B8A8_SINT:
594         LOAD_SCANLINE( XMBYTE4, XMLoadByte4 )
595
596     case DXGI_FORMAT_R16G16_FLOAT:
597         LOAD_SCANLINE2( XMHALF2, XMLoadHalf2, g_XMIdentityR3 )
598
599     case DXGI_FORMAT_R16G16_UNORM:
600         LOAD_SCANLINE2( XMUSHORTN2, XMLoadUShortN2, g_XMIdentityR3 )
601
602     case DXGI_FORMAT_R16G16_UINT:
603         LOAD_SCANLINE2( XMUSHORT2, XMLoadUShort2, g_XMIdentityR3 )
604
605     case DXGI_FORMAT_R16G16_SNORM:
606         LOAD_SCANLINE2( XMSHORTN2, XMLoadShortN2, g_XMIdentityR3 )
607
608     case DXGI_FORMAT_R16G16_SINT:
609         LOAD_SCANLINE2( XMSHORT2, XMLoadShort2, g_XMIdentityR3 )
610
611     case DXGI_FORMAT_D32_FLOAT:
612     case DXGI_FORMAT_R32_FLOAT:
613         if ( size >= sizeof(float) )
614         {
615             const float* __restrict sPtr = reinterpret_cast<const float*>(pSource);
616             for( size_t icount = 0; icount < size; icount += sizeof(float) )
617             {
618                 XMVECTOR v = XMLoadFloat( sPtr++ );
619                 if ( dPtr >= ePtr ) break;
620                 *(dPtr++) = XMVectorSelect( g_XMIdentityR3, v, g_XMSelect1000 );
621             }
622             return true;
623         }
624         return false;
625
626     case DXGI_FORMAT_R32_UINT:
627         if ( size >= sizeof(uint32_t) )
628         {
629             const uint32_t* __restrict sPtr = reinterpret_cast<const uint32_t*>(pSource);
630             for( size_t icount = 0; icount < size; icount += sizeof(uint32_t) )
631             {
632                 XMVECTOR v = XMLoadInt( sPtr++ );
633                 v = XMConvertVectorUIntToFloat( v, 0 );
634                 if ( dPtr >= ePtr ) break;
635                 *(dPtr++) = XMVectorSelect( g_XMIdentityR3, v, g_XMSelect1000 );
636             }
637             return true;
638         }
639         return false;
640
641     case DXGI_FORMAT_R32_SINT:
642         if ( size >= sizeof(int32_t) )
643         {
644             const int32_t * __restrict sPtr = reinterpret_cast<const int32_t*>(pSource);
645             for( size_t icount = 0; icount < size; icount += sizeof(int32_t) )
646             {
647                 XMVECTOR v = XMLoadInt( reinterpret_cast<const uint32_t*> (sPtr++) );
648                 v = XMConvertVectorIntToFloat( v, 0 );
649                 if ( dPtr >= ePtr ) break;
650                 *(dPtr++) = XMVectorSelect( g_XMIdentityR3, v, g_XMSelect1000 );
651             }
652             return true;
653         }
654         return false;
655
656     case DXGI_FORMAT_D24_UNORM_S8_UINT:
657         if ( size >= sizeof(uint32_t) )
658         {
659             const uint32_t * sPtr = reinterpret_cast<const uint32_t*>(pSource);
660             for( size_t icount = 0; icount < size; icount += sizeof(uint32_t) )
661             {
662                 float d = static_cast<float>( *sPtr & 0xFFFFFF ) / 16777215.f;
663                 float s = static_cast<float>( ( *sPtr & 0xFF000000 ) >> 24 );
664                 ++sPtr;
665                 if ( dPtr >= ePtr ) break;
666                 *(dPtr++) = XMVectorSet( d, s, 0.f, 1.f );
667             }
668             return true;
669         }
670         return false;
671
672     case DXGI_FORMAT_R8G8_UNORM:
673         LOAD_SCANLINE2( XMUBYTEN2, XMLoadUByteN2, g_XMIdentityR3 )
674
675     case DXGI_FORMAT_R8G8_UINT:
676         LOAD_SCANLINE2( XMUBYTE2, XMLoadUByte2, g_XMIdentityR3 )
677
678     case DXGI_FORMAT_R8G8_SNORM:
679         LOAD_SCANLINE2( XMBYTEN2, XMLoadByteN2, g_XMIdentityR3 )
680
681     case DXGI_FORMAT_R8G8_SINT:
682         LOAD_SCANLINE2( XMBYTE2, XMLoadByte2, g_XMIdentityR3 )
683
684     case DXGI_FORMAT_R16_FLOAT:
685         if ( size >= sizeof(HALF) )
686         {
687             const HALF * __restrict sPtr = reinterpret_cast<const HALF*>(pSource);
688             for( size_t icount = 0; icount < size; icount += sizeof(HALF) )
689             {
690                 if ( dPtr >= ePtr ) break;
691                 *(dPtr++) = XMVectorSet( XMConvertHalfToFloat(*sPtr++), 0.f, 0.f, 1.f );
692             }
693             return true;
694         }
695         return false;
696
697     case DXGI_FORMAT_D16_UNORM:
698     case DXGI_FORMAT_R16_UNORM:
699         if ( size >= sizeof(uint16_t) )
700         {
701             const uint16_t* __restrict sPtr = reinterpret_cast<const uint16_t*>(pSource);
702             for( size_t icount = 0; icount < size; icount += sizeof(uint16_t) )
703             {
704                 if ( dPtr >= ePtr ) break;
705                 *(dPtr++) = XMVectorSet( static_cast<float>(*sPtr++) / 65535.f, 0.f, 0.f, 1.f );
706             }
707             return true;
708         }
709         return false;
710
711     case DXGI_FORMAT_R16_UINT:
712         if ( size >= sizeof(uint16_t) )
713         {
714             const uint16_t * __restrict sPtr = reinterpret_cast<const uint16_t*>(pSource);
715             for( size_t icount = 0; icount < size; icount += sizeof(uint16_t) )
716             {
717                 if ( dPtr >= ePtr ) break;
718                 *(dPtr++) = XMVectorSet( static_cast<float>(*sPtr++), 0.f, 0.f, 1.f );
719             }
720             return true;
721         }
722         return false;
723
724     case DXGI_FORMAT_R16_SNORM:
725         if ( size >= sizeof(int16_t) )
726         {
727             const int16_t * __restrict sPtr = reinterpret_cast<const int16_t*>(pSource);
728             for( size_t icount = 0; icount < size; icount += sizeof(int16_t) )
729             {
730                 if ( dPtr >= ePtr ) break;
731                 *(dPtr++) = XMVectorSet( static_cast<float>(*sPtr++) / 32767.f, 0.f, 0.f, 1.f );
732             }
733             return true;
734         }
735         return false;
736
737     case DXGI_FORMAT_R16_SINT:
738         if ( size >= sizeof(int16_t) )
739         {
740             const int16_t * __restrict sPtr = reinterpret_cast<const int16_t*>(pSource);
741             for( size_t icount = 0; icount < size; icount += sizeof(int16_t) )
742             {
743                 if ( dPtr >= ePtr ) break;
744                 *(dPtr++) = XMVectorSet( static_cast<float>(*sPtr++), 0.f, 0.f, 1.f );
745             }
746             return true;
747         }
748         return false;
749
750     case DXGI_FORMAT_R8_UNORM:
751         if ( size >= sizeof(uint8_t) )
752         {
753             const uint8_t * __restrict sPtr = reinterpret_cast<const uint8_t*>(pSource);
754             for( size_t icount = 0; icount < size; icount += sizeof(uint8_t) )
755             {
756                 if ( dPtr >= ePtr ) break;
757                 *(dPtr++) = XMVectorSet( static_cast<float>(*sPtr++) / 255.f, 0.f, 0.f, 1.f );
758             }
759             return true;
760         }
761         return false;
762
763     case DXGI_FORMAT_R8_UINT:
764         if ( size >= sizeof(uint8_t) )
765         {
766             const uint8_t * __restrict sPtr = reinterpret_cast<const uint8_t*>(pSource);
767             for( size_t icount = 0; icount < size; icount += sizeof(uint8_t) )
768             {
769                 if ( dPtr >= ePtr ) break;
770                 *(dPtr++) = XMVectorSet( static_cast<float>(*sPtr++), 0.f, 0.f, 1.f );
771             }
772             return true;
773         }
774         return false;
775
776     case DXGI_FORMAT_R8_SNORM:
777         if ( size >= sizeof(char) )
778         {
779             const char * __restrict sPtr = reinterpret_cast<const char*>(pSource);
780             for( size_t icount = 0; icount < size; icount += sizeof(char) )
781             {
782                 if ( dPtr >= ePtr ) break;
783                 *(dPtr++) = XMVectorSet( static_cast<float>(*sPtr++) / 127.f, 0.f, 0.f, 1.f );
784             }
785             return true;
786         }
787         return false;
788
789     case DXGI_FORMAT_R8_SINT:
790         if ( size >= sizeof(char) )
791         {
792             const char * __restrict sPtr = reinterpret_cast<const char*>(pSource);
793             for( size_t icount = 0; icount < size; icount += sizeof(char) )
794             {
795                 if ( dPtr >= ePtr ) break;
796                 *(dPtr++) = XMVectorSet( static_cast<float>(*sPtr++), 0.f, 0.f, 1.f );
797             }
798             return true;
799         }
800         return false;
801
802     case DXGI_FORMAT_A8_UNORM:
803         if ( size >= sizeof(uint8_t) )
804         {
805             const uint8_t * __restrict sPtr = reinterpret_cast<const uint8_t*>(pSource);
806             for( size_t icount = 0; icount < size; icount += sizeof(uint8_t) )
807             {
808                 if ( dPtr >= ePtr ) break;
809                 *(dPtr++) = XMVectorSet( 0.f, 0.f, 0.f, static_cast<float>(*sPtr++) / 255.f );
810             }
811             return true;
812         }
813         return false;
814
815     case DXGI_FORMAT_R1_UNORM:
816         if ( size >= sizeof(uint8_t) )
817         {
818             const uint8_t * __restrict sPtr = reinterpret_cast<const uint8_t*>(pSource);
819             for( size_t icount = 0; icount < size; icount += sizeof(uint8_t) )
820             {
821                 for( size_t bcount = 0; bcount < 8; ++bcount )
822                 {
823                     if ( dPtr >= ePtr ) break;
824                     *(dPtr++) = XMVectorSet( (((*sPtr >> bcount) & 0x1) ? 1.f : 0.f), 0.f, 0.f, 1.f );
825                 }
826                 
827                 ++sPtr;
828             }
829             return true;
830         }
831         return false;
832
833     case DXGI_FORMAT_R9G9B9E5_SHAREDEXP:
834         LOAD_SCANLINE3( XMFLOAT3SE, XMLoadFloat3SE, g_XMIdentityR3 )
835
836     case DXGI_FORMAT_R8G8_B8G8_UNORM:
837         if ( size >= sizeof(XMUBYTEN4) )
838         {
839             const XMUBYTEN4 * __restrict sPtr = reinterpret_cast<const XMUBYTEN4*>(pSource);
840             for( size_t icount = 0; icount < size; icount += sizeof(XMUBYTEN4) )
841             {
842                 XMVECTOR v = XMLoadUByteN4( sPtr++ );
843                 XMVECTOR v1 = XMVectorSwizzle<0, 3, 2, 1>( v );
844                 if ( dPtr >= ePtr ) break;
845                 *(dPtr++) = XMVectorSelect( g_XMIdentityR3, v, g_XMSelect1110 );
846                 if ( dPtr >= ePtr ) break;
847                 *(dPtr++) = XMVectorSelect( g_XMIdentityR3, v1, g_XMSelect1110 );
848             }
849             return true;
850         }
851         return false;
852
853     case DXGI_FORMAT_G8R8_G8B8_UNORM:
854         if ( size >= sizeof(XMUBYTEN4) )
855         {
856             const XMUBYTEN4 * __restrict sPtr = reinterpret_cast<const XMUBYTEN4*>(pSource);
857             for( size_t icount = 0; icount < size; icount += sizeof(XMUBYTEN4) )
858             {
859                 XMVECTOR v = XMLoadUByteN4( sPtr++ );
860                 XMVECTOR v0 = XMVectorSwizzle<1, 0, 3, 2>( v );
861                 XMVECTOR v1 = XMVectorSwizzle<1, 2, 3, 0>( v );
862                 if ( dPtr >= ePtr ) break;
863                 *(dPtr++) = XMVectorSelect( g_XMIdentityR3, v0, g_XMSelect1110 );
864                 if ( dPtr >= ePtr ) break;
865                 *(dPtr++) = XMVectorSelect( g_XMIdentityR3, v1, g_XMSelect1110 );
866             }
867             return true;
868         }
869         return false;
870
871     case DXGI_FORMAT_B5G6R5_UNORM:
872         if ( size >= sizeof(XMU565) )
873         {
874             static XMVECTORF32 s_Scale = { 1.f/31.f, 1.f/63.f, 1.f/31.f, 1.f };
875             const XMU565 * __restrict sPtr = reinterpret_cast<const XMU565*>(pSource);
876             for( size_t icount = 0; icount < size; icount += sizeof(XMU565) )
877             {
878                 XMVECTOR v = XMLoadU565( sPtr++ );
879                 v = XMVectorMultiply( v, s_Scale );
880                 v = XMVectorSwizzle<2, 1, 0, 3>( v );
881                 if ( dPtr >= ePtr ) break;
882                 *(dPtr++) = XMVectorSelect( g_XMIdentityR3, v, g_XMSelect1110 );
883             }
884             return true;
885         }
886         return false;
887
888     case DXGI_FORMAT_B5G5R5A1_UNORM:
889         if ( size >= sizeof(XMU555) )
890         {
891             static XMVECTORF32 s_Scale = { 1.f/31.f, 1.f/31.f, 1.f/31.f, 1.f };
892             const XMU555 * __restrict sPtr = reinterpret_cast<const XMU555*>(pSource);
893             for( size_t icount = 0; icount < size; icount += sizeof(XMU555) )
894             {
895                 XMVECTOR v = XMLoadU555( sPtr++ );
896                 v = XMVectorMultiply( v, s_Scale );
897                 if ( dPtr >= ePtr ) break;
898                 *(dPtr++) = XMVectorSwizzle<2, 1, 0, 3>( v );
899             }
900             return true;
901         }
902         return false;
903
904     case DXGI_FORMAT_B8G8R8A8_UNORM:
905     case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
906         if ( size >= sizeof(XMUBYTEN4) )
907         {
908             const XMUBYTEN4 * __restrict sPtr = reinterpret_cast<const XMUBYTEN4*>(pSource);
909             for( size_t icount = 0; icount < size; icount += sizeof(XMUBYTEN4) )
910             {
911                 XMVECTOR v = XMLoadUByteN4( sPtr++ );
912                 if ( dPtr >= ePtr ) break;
913                 *(dPtr++) = XMVectorSwizzle<2, 1, 0, 3>( v );
914             }
915             return true;
916         }
917         return false;
918
919     case DXGI_FORMAT_B8G8R8X8_UNORM:
920     case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
921         if ( size >= sizeof(XMUBYTEN4) )
922         {
923             const XMUBYTEN4 * __restrict sPtr = reinterpret_cast<const XMUBYTEN4*>(pSource);
924             for( size_t icount = 0; icount < size; icount += sizeof(XMUBYTEN4) )
925             {
926                 XMVECTOR v = XMLoadUByteN4( sPtr++ );
927                 v = XMVectorSwizzle<2, 1, 0, 3>( v );
928                 if ( dPtr >= ePtr ) break;
929                 *(dPtr++) = XMVectorSelect( g_XMIdentityR3, v, g_XMSelect1110 );
930             }
931             return true;
932         }
933         return false;
934
935 #ifdef DXGI_1_2_FORMATS
936     case DXGI_FORMAT_B4G4R4A4_UNORM:
937         if ( size >= sizeof(XMUNIBBLE4) )
938         {
939             static XMVECTORF32 s_Scale = { 1.f/15.f, 1.f/15.f, 1.f/15.f, 1.f/15.f };
940             const XMUNIBBLE4 * __restrict sPtr = reinterpret_cast<const XMUNIBBLE4*>(pSource);
941             for( size_t icount = 0; icount < size; icount += sizeof(XMUNIBBLE4) )
942             {
943                 XMVECTOR v = XMLoadUNibble4( sPtr++ );
944                 v = XMVectorMultiply( v, s_Scale );
945                 if ( dPtr >= ePtr ) break;
946                 *(dPtr++) = XMVectorSwizzle<2, 1, 0, 3>( v );
947             }
948             return true;
949         }
950         return false;
951
952     // we don't support the video formats ( see IsVideo function )
953 #endif // DXGI_1_2_FORMATS
954
955     default:
956         return false;
957     }
958 }
959
960
961 //-------------------------------------------------------------------------------------
962 // Stores an image row from standard RGBA XMVECTOR (aligned) array
963 //-------------------------------------------------------------------------------------
964 #define STORE_SCANLINE( type, func )\
965         if ( size >= sizeof(type) )\
966         {\
967             type * __restrict dPtr = reinterpret_cast<type*>(pDestination);\
968             for( size_t icount = 0; icount < size; icount += sizeof(type) )\
969             {\
970                 if ( sPtr >= ePtr ) break;\
971                 func( dPtr++, *sPtr++ );\
972             }\
973         }\
974         return true;
975
976 bool _StoreScanline( LPVOID pDestination, size_t size, DXGI_FORMAT format,
977                      const XMVECTOR* pSource, size_t count )
978 {
979     assert( pDestination && size > 0 );
980     assert( pSource && count > 0 && (((uintptr_t)pSource & 0xF) == 0) );
981     assert( IsValid(format) && !IsVideo(format) && !IsTypeless(format) && !IsCompressed(format) );
982
983     const XMVECTOR* __restrict sPtr = pSource;
984     if ( !sPtr )
985         return false;
986
987     const XMVECTOR* ePtr = pSource + count;
988
989     switch( format )
990     {
991     case DXGI_FORMAT_R32G32B32A32_FLOAT:
992         STORE_SCANLINE( XMFLOAT4, XMStoreFloat4 )
993
994     case DXGI_FORMAT_R32G32B32A32_UINT:
995         STORE_SCANLINE( XMUINT4, XMStoreUInt4 )
996
997     case DXGI_FORMAT_R32G32B32A32_SINT:
998         STORE_SCANLINE( XMINT4, XMStoreSInt4 )
999
1000     case DXGI_FORMAT_R32G32B32_FLOAT:
1001         STORE_SCANLINE( XMFLOAT3, XMStoreFloat3 )
1002
1003     case DXGI_FORMAT_R32G32B32_UINT:
1004         STORE_SCANLINE( XMUINT3, XMStoreUInt3 )
1005
1006     case DXGI_FORMAT_R32G32B32_SINT:
1007         STORE_SCANLINE( XMINT3, XMStoreSInt3 )
1008
1009     case DXGI_FORMAT_R16G16B16A16_FLOAT:
1010         STORE_SCANLINE( XMHALF4, XMStoreHalf4 )
1011
1012     case DXGI_FORMAT_R16G16B16A16_UNORM:
1013         STORE_SCANLINE( XMUSHORTN4, XMStoreUShortN4 ) 
1014
1015     case DXGI_FORMAT_R16G16B16A16_UINT:
1016         STORE_SCANLINE( XMUSHORT4, XMStoreUShort4 )
1017
1018     case DXGI_FORMAT_R16G16B16A16_SNORM:
1019         STORE_SCANLINE( XMSHORTN4, XMStoreShortN4 )
1020
1021     case DXGI_FORMAT_R16G16B16A16_SINT:
1022         STORE_SCANLINE( XMSHORT4, XMStoreShort4 )
1023
1024     case DXGI_FORMAT_R32G32_FLOAT:
1025         STORE_SCANLINE( XMFLOAT2, XMStoreFloat2 )
1026
1027     case DXGI_FORMAT_R32G32_UINT:
1028         STORE_SCANLINE( XMUINT2, XMStoreUInt2 )
1029
1030     case DXGI_FORMAT_R32G32_SINT:
1031         STORE_SCANLINE( XMINT2, XMStoreSInt2 )
1032
1033     case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:
1034         if ( size >= (sizeof(float)+sizeof(uint32_t)) )
1035         {
1036             float *dPtr = reinterpret_cast<float*>(pDestination);
1037             for( size_t icount = 0; icount < size; icount += (sizeof(float)+sizeof(uint32_t)) )
1038             {
1039                 if ( sPtr >= ePtr ) break;
1040                 XMFLOAT4 f;
1041                 XMStoreFloat4( &f, *sPtr++ );
1042                 dPtr[0] = f.x;
1043                 uint8_t* ps8 = reinterpret_cast<uint8_t*>( &dPtr[1] );
1044                 ps8[0] = static_cast<uint8_t>( std::min<float>( 255.f, std::max<float>( 0.f, f.y ) ) );
1045                 ps8[1] = ps8[2] = ps8[3] = 0;
1046                 dPtr += 2;
1047             }
1048         }
1049         return true;
1050
1051     case DXGI_FORMAT_R10G10B10A2_UNORM:
1052     case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:
1053         STORE_SCANLINE( XMUDECN4, XMStoreUDecN4 );
1054
1055     case DXGI_FORMAT_R10G10B10A2_UINT:
1056         STORE_SCANLINE( XMUDEC4, XMStoreUDec4 );
1057
1058     case DXGI_FORMAT_R11G11B10_FLOAT:
1059         STORE_SCANLINE( XMFLOAT3PK, XMStoreFloat3PK );
1060
1061     case DXGI_FORMAT_R8G8B8A8_UNORM:
1062     case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
1063         STORE_SCANLINE( XMUBYTEN4, XMStoreUByteN4 )
1064
1065     case DXGI_FORMAT_R8G8B8A8_UINT:
1066         STORE_SCANLINE( XMUBYTE4, XMStoreUByte4 )
1067
1068     case DXGI_FORMAT_R8G8B8A8_SNORM:
1069         STORE_SCANLINE( XMBYTEN4, XMStoreByteN4 )
1070
1071     case DXGI_FORMAT_R8G8B8A8_SINT:
1072         STORE_SCANLINE( XMBYTE4, XMStoreByte4 )
1073
1074     case DXGI_FORMAT_R16G16_FLOAT:
1075         STORE_SCANLINE( XMHALF2, XMStoreHalf2 )
1076
1077     case DXGI_FORMAT_R16G16_UNORM:
1078         STORE_SCANLINE( XMUSHORTN2, XMStoreUShortN2 )
1079
1080     case DXGI_FORMAT_R16G16_UINT:
1081         STORE_SCANLINE( XMUSHORT2, XMStoreUShort2 )
1082
1083     case DXGI_FORMAT_R16G16_SNORM:
1084         STORE_SCANLINE( XMSHORTN2, XMStoreShortN2 )
1085
1086     case DXGI_FORMAT_R16G16_SINT:
1087         STORE_SCANLINE( XMSHORT2, XMStoreShort2 )
1088
1089     case DXGI_FORMAT_D32_FLOAT:
1090     case DXGI_FORMAT_R32_FLOAT:
1091         if ( size >= sizeof(float) )
1092         {
1093             float * __restrict dPtr = reinterpret_cast<float*>(pDestination);
1094             for( size_t icount = 0; icount < size; icount += sizeof(float) )
1095             {
1096                 if ( sPtr >= ePtr ) break;
1097                 XMStoreFloat( dPtr++, *(sPtr++) );
1098             }
1099         }
1100         return true;
1101
1102     case DXGI_FORMAT_R32_UINT:
1103         if ( size >= sizeof(uint32_t) )
1104         {
1105             uint32_t * __restrict dPtr = reinterpret_cast<uint32_t*>(pDestination);
1106             for( size_t icount = 0; icount < size; icount += sizeof(uint32_t) )
1107             {
1108                 if ( sPtr >= ePtr ) break;
1109                 XMVECTOR v = XMConvertVectorFloatToUInt( *(sPtr++), 0 );
1110                 XMStoreInt( dPtr++, v );
1111             }
1112         }
1113         return true;
1114
1115     case DXGI_FORMAT_R32_SINT:
1116         if ( size >= sizeof(uint32_t) )
1117         {
1118             uint32_t * __restrict dPtr = reinterpret_cast<uint32_t*>(pDestination);
1119             for( size_t icount = 0; icount < size; icount += sizeof(uint32_t) )
1120             {
1121                 if ( sPtr >= ePtr ) break;
1122                 XMVECTOR v = XMConvertVectorFloatToInt( *(sPtr++), 0 );
1123                 XMStoreInt( dPtr++, v );
1124             }
1125         }
1126         return true;
1127
1128     case DXGI_FORMAT_D24_UNORM_S8_UINT:
1129         if ( size >= sizeof(uint32_t) )
1130         {
1131             static const XMVECTORF32 clamp = { 1.f, 255.f, 0.f, 0.f };
1132             XMVECTOR zero = XMVectorZero();
1133             uint32_t *dPtr = reinterpret_cast<uint32_t*>(pDestination);
1134             for( size_t icount = 0; icount < size; icount += sizeof(uint32_t) )
1135             {
1136                 if ( sPtr >= ePtr ) break;
1137                 XMFLOAT4 f;
1138                 XMStoreFloat4( &f, XMVectorClamp( *sPtr++, zero, clamp ) );
1139                 *dPtr++ = (static_cast<uint32_t>( f.x * 16777215.f ) & 0xFFFFFF)
1140                           | ((static_cast<uint32_t>( f.y ) & 0xFF) << 24);
1141             }
1142         }
1143         return true;
1144
1145     case DXGI_FORMAT_R8G8_UNORM:
1146         STORE_SCANLINE( XMUBYTEN2, XMStoreUByteN2 )
1147
1148     case DXGI_FORMAT_R8G8_UINT:
1149         STORE_SCANLINE( XMUBYTE2, XMStoreUByte2 )
1150
1151     case DXGI_FORMAT_R8G8_SNORM:
1152         STORE_SCANLINE( XMBYTEN2, XMStoreByteN2 )
1153
1154     case DXGI_FORMAT_R8G8_SINT:
1155         STORE_SCANLINE( XMBYTE2, XMStoreByte2 )
1156
1157     case DXGI_FORMAT_R16_FLOAT:
1158         if ( size >= sizeof(HALF) )
1159         {
1160             HALF * __restrict dPtr = reinterpret_cast<HALF*>(pDestination);
1161             for( size_t icount = 0; icount < size; icount += sizeof(HALF) )
1162             {
1163                 if ( sPtr >= ePtr ) break;
1164                 float v = XMVectorGetX( *sPtr++ );
1165                 *(dPtr++) = XMConvertFloatToHalf(v);
1166             }
1167         }
1168         return true;
1169
1170     case DXGI_FORMAT_D16_UNORM:
1171     case DXGI_FORMAT_R16_UNORM:
1172         if ( size >= sizeof(int16_t) )
1173         {
1174             int16_t * __restrict dPtr = reinterpret_cast<int16_t*>(pDestination);
1175             for( size_t icount = 0; icount < size; icount += sizeof(int16_t) )
1176             {
1177                 if ( sPtr >= ePtr ) break;
1178                 float v = XMVectorGetX( *sPtr++ );
1179                 v = std::max<float>( std::min<float>( v, 1.f ), 0.f );
1180                 *(dPtr++) = static_cast<uint16_t>( v*65535.f + 0.5f );
1181             }
1182         }
1183         return true;
1184
1185     case DXGI_FORMAT_R16_UINT:
1186         if ( size >= sizeof(uint16_t) )
1187         {
1188             uint16_t * __restrict dPtr = reinterpret_cast<uint16_t*>(pDestination);
1189             for( size_t icount = 0; icount < size; icount += sizeof(uint16_t) )
1190             {
1191                 if ( sPtr >= ePtr ) break;
1192                 float v = XMVectorGetX( *sPtr++ );
1193                 v = std::max<float>( std::min<float>( v, 65535.f ), 0.f );
1194                 *(dPtr++) = static_cast<uint16_t>(v);
1195             }
1196         }
1197         return true;
1198
1199     case DXGI_FORMAT_R16_SNORM:
1200         if ( size >= sizeof(int16_t) )
1201         {
1202             int16_t * __restrict dPtr = reinterpret_cast<int16_t*>(pDestination);
1203             for( size_t icount = 0; icount < size; icount += sizeof(int16_t) )
1204             {
1205                 if ( sPtr >= ePtr ) break;
1206                 float v = XMVectorGetX( *sPtr++ );
1207                 v = std::max<float>( std::min<float>( v, 1.f ), -1.f );
1208                 *(dPtr++) = static_cast<uint16_t>( v * 32767.f );
1209             }
1210         }
1211         return true;
1212
1213     case DXGI_FORMAT_R16_SINT:
1214         if ( size >= sizeof(int16_t) )
1215         {
1216             int16_t * __restrict dPtr = reinterpret_cast<int16_t*>(pDestination);
1217             for( size_t icount = 0; icount < size; icount += sizeof(int16_t) )
1218             {
1219                 if ( sPtr >= ePtr ) break;
1220                 float v = XMVectorGetX( *sPtr++ );
1221                 v = std::max<float>( std::min<float>( v, 32767.f ), -32767.f );
1222                 *(dPtr++) = static_cast<int16_t>(v);
1223             }
1224         }
1225         return true;
1226
1227     case DXGI_FORMAT_R8_UNORM:
1228         if ( size >= sizeof(uint8_t) )
1229         {
1230             uint8_t * __restrict dPtr = reinterpret_cast<uint8_t*>(pDestination);
1231             for( size_t icount = 0; icount < size; icount += sizeof(uint8_t) )
1232             {
1233                 if ( sPtr >= ePtr ) break;
1234                 float v = XMVectorGetX( *sPtr++ );
1235                 v = std::max<float>( std::min<float>( v, 1.f ), 0.f );
1236                 *(dPtr++) = static_cast<uint8_t>( v * 255.f);
1237             }
1238         }
1239         return true;
1240
1241     case DXGI_FORMAT_R8_UINT:
1242         if ( size >= sizeof(uint8_t) )
1243         {
1244             uint8_t * __restrict dPtr = reinterpret_cast<uint8_t*>(pDestination);
1245             for( size_t icount = 0; icount < size; icount += sizeof(uint8_t) )
1246             {
1247                 if ( sPtr >= ePtr ) break;
1248                 float v = XMVectorGetX( *sPtr++ );
1249                 v = std::max<float>( std::min<float>( v, 255.f ), 0.f );
1250                 *(dPtr++) = static_cast<uint8_t>(v);
1251             }
1252         }
1253         return true;
1254
1255     case DXGI_FORMAT_R8_SNORM:
1256         if ( size >= sizeof(char) )
1257         {
1258             char * __restrict dPtr = reinterpret_cast<char*>(pDestination);
1259             for( size_t icount = 0; icount < size; icount += sizeof(char) )
1260             {
1261                 if ( sPtr >= ePtr ) break;
1262                 float v = XMVectorGetX( *sPtr++ );
1263                 v = std::max<float>( std::min<float>( v, 1.f ), -1.f );
1264                 *(dPtr++) = static_cast<char>( v * 127.f );
1265             }
1266         }
1267         return true;
1268
1269     case DXGI_FORMAT_R8_SINT:
1270         if ( size >= sizeof(char) )
1271         {
1272             char * __restrict dPtr = reinterpret_cast<char*>(pDestination);
1273             for( size_t icount = 0; icount < size; icount += sizeof(char) )
1274             {
1275                 if ( sPtr >= ePtr ) break;
1276                 float v = XMVectorGetX( *sPtr++ );
1277                 v = std::max<float>( std::min<float>( v, 127.f ), -127.f );
1278                 *(dPtr++) = static_cast<char>( v );
1279             }
1280         }
1281         return true;
1282
1283     case DXGI_FORMAT_A8_UNORM:
1284         if ( size >= sizeof(uint8_t) )
1285         {
1286             uint8_t * __restrict dPtr = reinterpret_cast<uint8_t*>(pDestination);
1287             for( size_t icount = 0; icount < size; icount += sizeof(uint8_t) )
1288             {
1289                 if ( sPtr >= ePtr ) break;
1290                 float v = XMVectorGetW( *sPtr++ );
1291                 v = std::max<float>( std::min<float>( v, 1.f ), 0.f );
1292                 *(dPtr++) = static_cast<uint8_t>( v * 255.f);
1293             }
1294         }
1295         return true;
1296
1297     case DXGI_FORMAT_R1_UNORM:
1298         if ( size >= sizeof(uint8_t) )
1299         {
1300             uint8_t * __restrict dPtr = reinterpret_cast<uint8_t*>(pDestination);
1301             for( size_t icount = 0; icount < size; icount += sizeof(uint8_t) )
1302             {
1303                 uint8_t pixels = 0;
1304                 for( size_t bcount = 0; bcount < 8; ++bcount )
1305                 {
1306                     if ( sPtr >= ePtr ) break;
1307                     float v = XMVectorGetX( *sPtr++ );
1308                     if ( v > 0.5f )
1309                         pixels |= 1 << bcount;
1310                 }
1311                 *(dPtr++) = pixels;
1312             }
1313         }
1314         return true;
1315
1316     case DXGI_FORMAT_R9G9B9E5_SHAREDEXP:
1317         STORE_SCANLINE( XMFLOAT3SE, XMStoreFloat3SE )
1318
1319     case DXGI_FORMAT_R8G8_B8G8_UNORM:
1320         if ( size >= sizeof(XMUBYTEN4) )
1321         {
1322             XMUBYTEN4 * __restrict dPtr = reinterpret_cast<XMUBYTEN4*>(pDestination);
1323             for( size_t icount = 0; icount < size; icount += sizeof(XMUBYTEN4) )
1324             {
1325                 if ( sPtr >= ePtr ) break;
1326                 XMVECTOR v0 = *sPtr++;
1327                 XMVECTOR v1 = (sPtr < ePtr) ? XMVectorSplatY( *sPtr++ ) : XMVectorZero();
1328                 XMVECTOR v = XMVectorSelect( v1, v0, g_XMSelect1110 );
1329                 XMStoreUByteN4( dPtr++, v );
1330             }
1331         }
1332         return true;
1333
1334     case DXGI_FORMAT_G8R8_G8B8_UNORM:
1335         if ( size >= sizeof(XMUBYTEN4) )
1336         {
1337             static XMVECTORI32 select1101 = {XM_SELECT_1, XM_SELECT_1, XM_SELECT_0, XM_SELECT_1};
1338
1339             XMUBYTEN4 * __restrict dPtr = reinterpret_cast<XMUBYTEN4*>(pDestination);
1340             for( size_t icount = 0; icount < size; icount += sizeof(XMUBYTEN4) )
1341             {
1342                 if ( sPtr >= ePtr ) break;
1343                 XMVECTOR v0 = XMVectorSwizzle<1, 0, 3, 2>( *sPtr++ );
1344                 XMVECTOR v1 = (sPtr < ePtr) ? XMVectorSplatY( *sPtr++ ) : XMVectorZero();
1345                 XMVECTOR v = XMVectorSelect( v1, v0, select1101 );
1346                 XMStoreUByteN4( dPtr++, v );
1347             }
1348         }
1349         return true;
1350
1351     case DXGI_FORMAT_B5G6R5_UNORM:
1352         if ( size >= sizeof(XMU565) )
1353         {
1354             static XMVECTORF32 s_Scale = { 31.f, 63.f, 31.f, 1.f };
1355             XMU565 * __restrict dPtr = reinterpret_cast<XMU565*>(pDestination);
1356             for( size_t icount = 0; icount < size; icount += sizeof(XMU565) )
1357             {
1358                 if ( sPtr >= ePtr ) break;
1359                 XMVECTOR v = XMVectorSwizzle<2, 1, 0, 3>( *sPtr++ );
1360                 v = XMVectorMultiply( v, s_Scale );
1361                 XMStoreU565( dPtr++, v );
1362             }
1363         }
1364         return true;
1365
1366     case DXGI_FORMAT_B5G5R5A1_UNORM:
1367         if ( size >= sizeof(XMU555) )
1368         {
1369             static XMVECTORF32 s_Scale = { 31.f, 31.f, 31.f, 1.f };
1370             XMU555 * __restrict dPtr = reinterpret_cast<XMU555*>(pDestination);
1371             for( size_t icount = 0; icount < size; icount += sizeof(XMU555) )
1372             {
1373                 if ( sPtr >= ePtr ) break;
1374                 XMVECTOR v = XMVectorSwizzle<2, 1, 0, 3>( *sPtr++ );
1375                 v = XMVectorMultiply( v, s_Scale );
1376                 XMStoreU555( dPtr++, v );
1377             }
1378         }
1379         return true;
1380
1381     case DXGI_FORMAT_B8G8R8A8_UNORM:
1382     case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
1383         if ( size >= sizeof(XMUBYTEN4) )
1384         {
1385             XMUBYTEN4 * __restrict dPtr = reinterpret_cast<XMUBYTEN4*>(pDestination);
1386             for( size_t icount = 0; icount < size; icount += sizeof(XMUBYTEN4) )
1387             {
1388                 if ( sPtr >= ePtr ) break;
1389                 XMVECTOR v = XMVectorSwizzle<2, 1, 0, 3>( *sPtr++ );
1390                 XMStoreUByteN4( dPtr++, v );
1391             }
1392         }
1393         return true;
1394
1395     case DXGI_FORMAT_B8G8R8X8_UNORM:
1396     case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
1397         if ( size >= sizeof(XMUBYTEN4) )
1398         {
1399             XMUBYTEN4 * __restrict dPtr = reinterpret_cast<XMUBYTEN4*>(pDestination);
1400             for( size_t icount = 0; icount < size; icount += sizeof(XMUBYTEN4) )
1401             {
1402                 if ( sPtr >= ePtr ) break;
1403                 XMVECTOR v = XMVectorPermute<2, 1, 0, 7>( *sPtr++, g_XMIdentityR3 );
1404                 XMStoreUByteN4( dPtr++, v );
1405             }
1406         }
1407         return true;
1408
1409 #ifdef DXGI_1_2_FORMATS
1410     case DXGI_FORMAT_B4G4R4A4_UNORM:
1411         if ( size >= sizeof(XMUNIBBLE4) )
1412         {
1413             static XMVECTORF32 s_Scale = { 15.f, 15.f, 15.f, 15.f };
1414             XMUNIBBLE4 * __restrict dPtr = reinterpret_cast<XMUNIBBLE4*>(pDestination);
1415             for( size_t icount = 0; icount < size; icount += sizeof(XMUNIBBLE4) )
1416             {
1417                 if ( sPtr >= ePtr ) break;
1418                 XMVECTOR v = XMVectorSwizzle<2, 1, 0, 3>( *sPtr++ );
1419                 v = XMVectorMultiply( v, s_Scale );
1420                 XMStoreUNibble4( dPtr++, v );
1421             }
1422         }
1423         return true;
1424
1425     // We don't support the video formats ( see IsVideo function )
1426 #endif // DXGI_1_2_FORMATS
1427
1428     default:
1429         return false;
1430     }
1431 }
1432
1433
1434 //-------------------------------------------------------------------------------------
1435 // Convert DXGI image to/from GUID_WICPixelFormat128bppRGBAFloat (no range conversions)
1436 //-------------------------------------------------------------------------------------
1437 HRESULT _ConvertToR32G32B32A32( const Image& srcImage, ScratchImage& image )
1438 {
1439     if ( !srcImage.pixels )
1440         return E_POINTER;
1441
1442     HRESULT hr = image.Initialize2D( DXGI_FORMAT_R32G32B32A32_FLOAT, srcImage.width, srcImage.height, 1, 1 );
1443     if ( FAILED(hr) )
1444         return hr;
1445
1446     const Image *img = image.GetImage( 0, 0, 0 );
1447     if ( !img )
1448     {
1449         image.Release();
1450         return E_POINTER;
1451     }
1452
1453     uint8_t* pDest = img->pixels;
1454     if ( !pDest )
1455     {
1456         image.Release();
1457         return E_POINTER;
1458     }
1459
1460     const uint8_t *pSrc = srcImage.pixels;
1461     for( size_t h = 0; h < srcImage.height; ++h )
1462     {
1463         if ( !_LoadScanline( reinterpret_cast<XMVECTOR*>(pDest), srcImage.width, pSrc, srcImage.rowPitch, srcImage.format ) )
1464         {
1465             image.Release();
1466             return E_FAIL;
1467         }
1468
1469         pSrc += srcImage.rowPitch;
1470         pDest += img->rowPitch;
1471     }
1472
1473     return S_OK;
1474 }
1475
1476 HRESULT _ConvertFromR32G32B32A32( _In_ const Image& srcImage, _In_ const Image& destImage )
1477 {
1478     assert( srcImage.format == DXGI_FORMAT_R32G32B32A32_FLOAT );
1479
1480     if ( !srcImage.pixels || !destImage.pixels )
1481         return E_POINTER;
1482
1483     if ( srcImage.width != destImage.width || srcImage.height != destImage.height )
1484         return E_FAIL;
1485
1486     const uint8_t *pSrc = srcImage.pixels;
1487     uint8_t* pDest = destImage.pixels;
1488
1489     for( size_t h = 0; h < srcImage.height; ++h )
1490     {
1491         if ( !_StoreScanline( pDest, destImage.rowPitch, destImage.format, reinterpret_cast<const XMVECTOR*>(pSrc), srcImage.width ) )
1492             return E_FAIL;
1493
1494         pSrc += srcImage.rowPitch;
1495         pDest += destImage.rowPitch;
1496     }
1497
1498     return S_OK;
1499 }
1500
1501 HRESULT _ConvertFromR32G32B32A32( const Image& srcImage, DXGI_FORMAT format, ScratchImage& image )
1502 {
1503     if ( !srcImage.pixels )
1504         return E_POINTER;
1505
1506     HRESULT hr = image.Initialize2D( format, srcImage.width, srcImage.height, 1, 1 );
1507     if ( FAILED(hr) )
1508         return hr;
1509
1510     const Image *img = image.GetImage( 0, 0, 0 );
1511     if ( !img )
1512     {
1513         image.Release();
1514         return E_POINTER;
1515     }
1516
1517     hr = _ConvertFromR32G32B32A32( srcImage, *img );
1518     if ( FAILED(hr) )
1519     {
1520         image.Release();
1521         return hr;
1522     }
1523
1524     return S_OK;
1525 }
1526
1527 HRESULT _ConvertFromR32G32B32A32( const Image* srcImages, size_t nimages, const TexMetadata& metadata, DXGI_FORMAT format, ScratchImage& result )
1528 {
1529     if ( !srcImages )
1530         return E_POINTER;
1531
1532     result.Release();
1533
1534     assert( metadata.format == DXGI_FORMAT_R32G32B32A32_FLOAT );
1535
1536     TexMetadata mdata2 = metadata;
1537     mdata2.format = format;
1538     HRESULT hr = result.Initialize( mdata2 );
1539     if ( FAILED(hr) )
1540         return hr;
1541
1542     if ( nimages != result.GetImageCount() )
1543     {
1544         result.Release();
1545         return E_FAIL;
1546     }
1547
1548     const Image* dest = result.GetImages();
1549     if ( !dest )
1550     {
1551         result.Release();
1552         return E_POINTER;
1553     }
1554
1555     for( size_t index=0; index < nimages; ++index )
1556     {
1557         const Image& src = srcImages[ index ];
1558         const Image& dst = dest[ index ];
1559
1560         assert( src.format == DXGI_FORMAT_R32G32B32A32_FLOAT );
1561         assert( dst.format == format );
1562
1563         if ( src.width != dst.width || src.height != dst.height )
1564         {
1565             result.Release();
1566             return E_FAIL;
1567         }
1568
1569         const uint8_t* pSrc = src.pixels;
1570         uint8_t* pDest = dst.pixels;
1571         if ( !pSrc || !pDest )
1572         {
1573             result.Release();
1574             return E_POINTER;
1575         }
1576
1577         for( size_t h=0; h < src.height; ++h )
1578         {
1579             if ( !_StoreScanline( pDest, dst.rowPitch, format, reinterpret_cast<const XMVECTOR*>(pSrc), src.width ) )
1580             {
1581                 result.Release();
1582                 return E_FAIL;
1583             }
1584
1585             pSrc += src.rowPitch;
1586             pDest += dst.rowPitch;
1587         }
1588     }
1589
1590     return S_OK;
1591 }
1592
1593
1594 //-------------------------------------------------------------------------------------
1595 // RGB -> sRGB
1596 //-------------------------------------------------------------------------------------
1597 static const uint32_t g_fEncodeGamma22[] =
1598 {
1599     0x00000000, 0x3bd56bd3, 0x3c486344, 0x3c90da15, 0x3cbc2677, 0x3ce67704, 0x3d080183, 0x3d1c7728,
1600     0x3d30a8fb, 0x3d44a03c, 0x3d586400, 0x3d6bf9e7, 0x3d7f6679, 0x3d8956bd, 0x3d92e906, 0x3d9c6b70,
1601     0x3da5df22, 0x3daf451b, 0x3db89e3e, 0x3dc1eb50, 0x3dcb2d04, 0x3dd463f7, 0x3ddd90b9, 0x3de6b3ca,
1602     0x3defcda0, 0x3df8dea6, 0x3e00f3a0, 0x3e0573e3, 0x3e09f046, 0x3e0e68f0, 0x3e12de06, 0x3e174fa6,
1603     0x3e1bbdf2, 0x3e202906, 0x3e2490fd, 0x3e28f5f1, 0x3e2d57fb, 0x3e31b72f, 0x3e3613a4, 0x3e3a6d6e,
1604     0x3e3ec4a0, 0x3e43194d, 0x3e476b84, 0x3e4bbb57, 0x3e5008d7, 0x3e54540f, 0x3e589d0f, 0x3e5ce3e5,
1605     0x3e61289d, 0x3e656b44, 0x3e69abe5, 0x3e6dea8d, 0x3e722745, 0x3e766217, 0x3e7a9b0e, 0x3e7ed235,
1606     0x3e8183c9, 0x3e839d98, 0x3e85b68c, 0x3e87cea8, 0x3e89e5f2, 0x3e8bfc6b, 0x3e8e1219, 0x3e9026ff,
1607     0x3e923b20, 0x3e944e7f, 0x3e966120, 0x3e987307, 0x3e9a8436, 0x3e9c94af, 0x3e9ea476, 0x3ea0b38e,
1608     0x3ea2c1fb, 0x3ea4cfbb, 0x3ea6dcd5, 0x3ea8e94a, 0x3eaaf51c, 0x3ead004e, 0x3eaf0ae2, 0x3eb114d9,
1609     0x3eb31e37, 0x3eb526fe, 0x3eb72f2f, 0x3eb936cd, 0x3ebb3dd8, 0x3ebd4454, 0x3ebf4a43, 0x3ec14fa5,
1610     0x3ec3547e, 0x3ec558cd, 0x3ec75c95, 0x3ec95fd8, 0x3ecb6297, 0x3ecd64d4, 0x3ecf6690, 0x3ed167ce,
1611     0x3ed3688e, 0x3ed568d1, 0x3ed76899, 0x3ed967e9, 0x3edb66bf, 0x3edd651f, 0x3edf630a, 0x3ee16080,
1612     0x3ee35d84, 0x3ee55a16, 0x3ee75636, 0x3ee951e8, 0x3eeb4d2a, 0x3eed4800, 0x3eef4269, 0x3ef13c68,
1613     0x3ef335fc, 0x3ef52f26, 0x3ef727ea, 0x3ef92046, 0x3efb183c, 0x3efd0fcd, 0x3eff06fa, 0x3f007ee2,
1614     0x3f017a16, 0x3f027519, 0x3f036fec, 0x3f046a8f, 0x3f056502, 0x3f065f47, 0x3f07595d, 0x3f085344,
1615     0x3f094cfe, 0x3f0a468b, 0x3f0b3feb, 0x3f0c391e, 0x3f0d3224, 0x3f0e2aff, 0x3f0f23af, 0x3f101c32,
1616     0x3f11148c, 0x3f120cba, 0x3f1304bf, 0x3f13fc9a, 0x3f14f44b, 0x3f15ebd3, 0x3f16e333, 0x3f17da6b,
1617     0x3f18d17a, 0x3f19c860, 0x3f1abf1f, 0x3f1bb5b7, 0x3f1cac28, 0x3f1da272, 0x3f1e9895, 0x3f1f8e92,
1618     0x3f20846a, 0x3f217a1c, 0x3f226fa8, 0x3f23650f, 0x3f245a52, 0x3f254f70, 0x3f264469, 0x3f27393f,
1619     0x3f282df1, 0x3f29227f, 0x3f2a16ea, 0x3f2b0b31, 0x3f2bff56, 0x3f2cf358, 0x3f2de738, 0x3f2edaf6,
1620     0x3f2fce91, 0x3f30c20b, 0x3f31b564, 0x3f32a89b, 0x3f339bb1, 0x3f348ea6, 0x3f35817a, 0x3f36742f,
1621     0x3f3766c3, 0x3f385936, 0x3f394b8a, 0x3f3a3dbe, 0x3f3b2fd3, 0x3f3c21c8, 0x3f3d139e, 0x3f3e0556,
1622     0x3f3ef6ee, 0x3f3fe868, 0x3f40d9c4, 0x3f41cb01, 0x3f42bc20, 0x3f43ad22, 0x3f449e06, 0x3f458ecc,
1623     0x3f467f75, 0x3f477001, 0x3f486071, 0x3f4950c2, 0x3f4a40f8, 0x3f4b3111, 0x3f4c210d, 0x3f4d10ed,
1624     0x3f4e00b2, 0x3f4ef05a, 0x3f4fdfe7, 0x3f50cf58, 0x3f51beae, 0x3f52ade8, 0x3f539d07, 0x3f548c0c,
1625     0x3f557af5, 0x3f5669c4, 0x3f575878, 0x3f584711, 0x3f593590, 0x3f5a23f6, 0x3f5b1241, 0x3f5c0072,
1626     0x3f5cee89, 0x3f5ddc87, 0x3f5eca6b, 0x3f5fb835, 0x3f60a5e7, 0x3f619380, 0x3f6280ff, 0x3f636e65,
1627     0x3f645bb3, 0x3f6548e8, 0x3f663604, 0x3f672309, 0x3f680ff4, 0x3f68fcc8, 0x3f69e983, 0x3f6ad627,
1628     0x3f6bc2b3, 0x3f6caf27, 0x3f6d9b83, 0x3f6e87c8, 0x3f6f73f5, 0x3f70600c, 0x3f714c0b, 0x3f7237f4,
1629     0x3f7323c4, 0x3f740f7f, 0x3f74fb22, 0x3f75e6af, 0x3f76d225, 0x3f77bd85, 0x3f78a8ce, 0x3f799401,
1630     0x3f7a7f1e, 0x3f7b6a25, 0x3f7c5516, 0x3f7d3ff1, 0x3f7e2ab6, 0x3f7f1566, 0x3f800000, 0x3f800000
1631 };
1632
1633 #pragma prefast(suppress : 25000, "FXMVECTOR is 16 bytes")
1634 static inline XMVECTOR _TableEncodeGamma22( FXMVECTOR v )
1635 {
1636     float f[4];
1637     XMStoreFloat4( (XMFLOAT4*)f, v );
1638
1639     for( size_t i=0; i < 4; ++i )
1640     {
1641         float f2 = sqrtf(f[i]) * 254.0f;
1642
1643         uint32_t  i2 = static_cast<uint32_t>(f2);
1644         i2 = std::min<uint32_t>( i2, _countof( g_fEncodeGamma22 )-2 );
1645
1646         float fS = f2 - (float) i2;
1647         float fA = ((float *) g_fEncodeGamma22)[i2];
1648         float fB = ((float *) g_fEncodeGamma22)[i2 + 1];
1649
1650         f[i] = fA + fS * (fB - fA);
1651     }
1652
1653     return XMLoadFloat4( (XMFLOAT4*)f );
1654 }
1655
1656
1657 //-------------------------------------------------------------------------------------
1658 // sRGB -> RGB
1659 //-------------------------------------------------------------------------------------
1660 static const uint32_t g_fDecodeGamma22[] =
1661 {
1662     0x00000000, 0x3b144eb0, 0x3b9ef3b0, 0x3bf84b42, 0x3c2a5c46, 0x3c59c180, 0x3c850eb5, 0x3c9da52a,
1663     0x3cb6967a, 0x3ccfd852, 0x3ce9628b, 0x3d01974b, 0x3d0e9b82, 0x3d1bbba3, 0x3d28f5bc, 0x3d364822,
1664     0x3d43b159, 0x3d51301d, 0x3d5ec344, 0x3d6c69c9, 0x3d7a22c4, 0x3d83f6ad, 0x3d8ae465, 0x3d91da35,
1665     0x3d98d7c7, 0x3d9fdcd2, 0x3da6e914, 0x3dadfc47, 0x3db51635, 0x3dbc36a3, 0x3dc35d62, 0x3dca8a3a,
1666     0x3dd1bd02, 0x3dd8f591, 0x3de033bb, 0x3de7775d, 0x3deec050, 0x3df60e74, 0x3dfd61a6, 0x3e025ce5,
1667     0x3e060b61, 0x3e09bc38, 0x3e0d6f5f, 0x3e1124c8, 0x3e14dc68, 0x3e189630, 0x3e1c521a, 0x3e201016,
1668     0x3e23d01d, 0x3e279225, 0x3e2b5624, 0x3e2f1c10, 0x3e32e3e4, 0x3e36ad94, 0x3e3a7918, 0x3e3e4668,
1669     0x3e42157f, 0x3e45e654, 0x3e49b8e0, 0x3e4d8d1d, 0x3e516304, 0x3e553a8d, 0x3e5913b4, 0x3e5cee70,
1670     0x3e60cabf, 0x3e64a89b, 0x3e6887fb, 0x3e6c68db, 0x3e704b3a, 0x3e742f0e, 0x3e781454, 0x3e7bfb04,
1671     0x3e7fe321, 0x3e81e650, 0x3e83dbc0, 0x3e85d1dc, 0x3e87c8a3, 0x3e89c015, 0x3e8bb830, 0x3e8db0ee,
1672     0x3e8faa51, 0x3e91a454, 0x3e939ef9, 0x3e959a3b, 0x3e97961b, 0x3e999295, 0x3e9b8fa7, 0x3e9d8d52,
1673     0x3e9f8b93, 0x3ea18a6a, 0x3ea389d2, 0x3ea589cb, 0x3ea78a56, 0x3ea98b6e, 0x3eab8d15, 0x3ead8f47,
1674     0x3eaf9204, 0x3eb1954a, 0x3eb39917, 0x3eb59d6c, 0x3eb7a246, 0x3eb9a7a5, 0x3ebbad88, 0x3ebdb3ec,
1675     0x3ebfbad3, 0x3ec1c237, 0x3ec3ca1a, 0x3ec5d27c, 0x3ec7db58, 0x3ec9e4b4, 0x3ecbee85, 0x3ecdf8d3,
1676     0x3ed0039a, 0x3ed20ed8, 0x3ed41a8a, 0x3ed626b5, 0x3ed83351, 0x3eda4065, 0x3edc4de9, 0x3ede5be0,
1677     0x3ee06a4a, 0x3ee27923, 0x3ee4886a, 0x3ee69821, 0x3ee8a845, 0x3eeab8d8, 0x3eecc9d6, 0x3eeedb3f,
1678     0x3ef0ed13, 0x3ef2ff53, 0x3ef511fb, 0x3ef7250a, 0x3ef93883, 0x3efb4c61, 0x3efd60a7, 0x3eff7553,
1679     0x3f00c531, 0x3f01cfeb, 0x3f02dad9, 0x3f03e5f5, 0x3f04f145, 0x3f05fcc4, 0x3f070875, 0x3f081456,
1680     0x3f092067, 0x3f0a2ca8, 0x3f0b3917, 0x3f0c45b7, 0x3f0d5284, 0x3f0e5f7f, 0x3f0f6caa, 0x3f107a03,
1681     0x3f118789, 0x3f12953b, 0x3f13a31d, 0x3f14b12b, 0x3f15bf64, 0x3f16cdca, 0x3f17dc5e, 0x3f18eb1b,
1682     0x3f19fa05, 0x3f1b091b, 0x3f1c185c, 0x3f1d27c7, 0x3f1e375c, 0x3f1f471d, 0x3f205707, 0x3f21671b,
1683     0x3f227759, 0x3f2387c2, 0x3f249852, 0x3f25a90c, 0x3f26b9ef, 0x3f27cafb, 0x3f28dc30, 0x3f29ed8b,
1684     0x3f2aff11, 0x3f2c10bd, 0x3f2d2290, 0x3f2e348b, 0x3f2f46ad, 0x3f3058f7, 0x3f316b66, 0x3f327dfd,
1685     0x3f3390ba, 0x3f34a39d, 0x3f35b6a7, 0x3f36c9d6, 0x3f37dd2b, 0x3f38f0a5, 0x3f3a0443, 0x3f3b1808,
1686     0x3f3c2bf2, 0x3f3d4000, 0x3f3e5434, 0x3f3f688c, 0x3f407d07, 0x3f4191a8, 0x3f42a66c, 0x3f43bb54,
1687     0x3f44d05f, 0x3f45e58e, 0x3f46fadf, 0x3f481054, 0x3f4925ed, 0x3f4a3ba8, 0x3f4b5186, 0x3f4c6789,
1688     0x3f4d7daa, 0x3f4e93f0, 0x3f4faa57, 0x3f50c0e0, 0x3f51d78b, 0x3f52ee58, 0x3f540545, 0x3f551c55,
1689     0x3f563386, 0x3f574ad7, 0x3f58624b, 0x3f5979de, 0x3f5a9191, 0x3f5ba965, 0x3f5cc15b, 0x3f5dd971,
1690     0x3f5ef1a6, 0x3f6009fc, 0x3f612272, 0x3f623b08, 0x3f6353bc, 0x3f646c90, 0x3f658586, 0x3f669e98,
1691     0x3f67b7cb, 0x3f68d11b, 0x3f69ea8d, 0x3f6b041b, 0x3f6c1dc9, 0x3f6d3795, 0x3f6e5180, 0x3f6f6b8b,
1692     0x3f7085b2, 0x3f719ff7, 0x3f72ba5b, 0x3f73d4dc, 0x3f74ef7c, 0x3f760a38, 0x3f772512, 0x3f78400b,
1693     0x3f795b20, 0x3f7a7651, 0x3f7b91a2, 0x3f7cad0e, 0x3f7dc896, 0x3f7ee43c, 0x3f800000, 0x3f800000
1694 };
1695
1696
1697 #pragma prefast(suppress : 25000, "FXMVECTOR is 16 bytes")
1698 static inline XMVECTOR _TableDecodeGamma22( FXMVECTOR v )
1699 {
1700     float f[4];
1701     XMStoreFloat4( (XMFLOAT4*)f, v );
1702
1703     for( size_t i=0; i < 4; ++i )
1704     {
1705         float f2 = f[i] * f[i] * 254.0f;
1706         uint32_t  i2 = static_cast<uint32_t>(f2);
1707         i2 = std::min<uint32_t>( i2, _countof(g_fDecodeGamma22)-2 );
1708
1709         float fS = f2 - (float) i2;
1710         float fA = ((float *) g_fDecodeGamma22)[i2];
1711         float fB = ((float *) g_fDecodeGamma22)[i2 + 1];
1712
1713         f[i] = fA + fS * (fB - fA);
1714     }
1715
1716     return XMLoadFloat4( (XMFLOAT4*)f );
1717 }
1718
1719
1720 //-------------------------------------------------------------------------------------
1721 // Convert scanline based on source/target formats
1722 //-------------------------------------------------------------------------------------
1723 struct ConvertData
1724 {
1725     DXGI_FORMAT format;
1726     size_t datasize;
1727     DWORD flags;
1728 };
1729
1730 static const ConvertData g_ConvertTable[] = {
1731     { DXGI_FORMAT_R32G32B32A32_FLOAT,           32, CONVF_FLOAT | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1732     { DXGI_FORMAT_R32G32B32A32_UINT,            32, CONVF_UINT | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1733     { DXGI_FORMAT_R32G32B32A32_SINT,            32, CONVF_SINT | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1734     { DXGI_FORMAT_R32G32B32_FLOAT,              32, CONVF_FLOAT | CONVF_R | CONVF_G | CONVF_B },
1735     { DXGI_FORMAT_R32G32B32_UINT,               32, CONVF_UINT | CONVF_R | CONVF_G | CONVF_B },
1736     { DXGI_FORMAT_R32G32B32_SINT,               32, CONVF_SINT | CONVF_R | CONVF_G | CONVF_B },
1737     { DXGI_FORMAT_R16G16B16A16_FLOAT,           16, CONVF_FLOAT | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1738     { DXGI_FORMAT_R16G16B16A16_UNORM,           16, CONVF_UNORM | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, 
1739     { DXGI_FORMAT_R16G16B16A16_UINT,            16, CONVF_UINT | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, 
1740     { DXGI_FORMAT_R16G16B16A16_SNORM,           16, CONVF_SNORM | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, 
1741     { DXGI_FORMAT_R16G16B16A16_SINT,            16, CONVF_SINT | CONVF_R | CONVF_G | CONVF_B | CONVF_A }, 
1742     { DXGI_FORMAT_R32G32_FLOAT,                 32, CONVF_FLOAT | CONVF_R | CONVF_G },
1743     { DXGI_FORMAT_R32G32_UINT,                  32, CONVF_UINT | CONVF_R | CONVF_G  },
1744     { DXGI_FORMAT_R32G32_SINT,                  32, CONVF_SINT | CONVF_R | CONVF_G  },
1745     { DXGI_FORMAT_D32_FLOAT_S8X24_UINT,         32, CONVF_FLOAT | CONVF_DEPTH | CONVF_STENCIL },
1746     { DXGI_FORMAT_R10G10B10A2_UNORM,            10, CONVF_UNORM | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1747     { DXGI_FORMAT_R10G10B10A2_UINT,             10, CONVF_UINT | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1748     { DXGI_FORMAT_R11G11B10_FLOAT,              10, CONVF_FLOAT | CONVF_R | CONVF_G | CONVF_B },
1749     { DXGI_FORMAT_R8G8B8A8_UNORM,               8, CONVF_UNORM | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1750     { DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,          8, CONVF_UNORM | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1751     { DXGI_FORMAT_R8G8B8A8_UINT,                8, CONVF_UINT | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1752     { DXGI_FORMAT_R8G8B8A8_SNORM,               8, CONVF_SNORM | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1753     { DXGI_FORMAT_R8G8B8A8_SINT,                8, CONVF_SINT | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1754     { DXGI_FORMAT_R16G16_FLOAT,                 16, CONVF_FLOAT | CONVF_R | CONVF_G },
1755     { DXGI_FORMAT_R16G16_UNORM,                 16, CONVF_UNORM | CONVF_R | CONVF_G },
1756     { DXGI_FORMAT_R16G16_UINT,                  16, CONVF_UINT | CONVF_R | CONVF_G },
1757     { DXGI_FORMAT_R16G16_SNORM,                 16, CONVF_SNORM | CONVF_R | CONVF_G },
1758     { DXGI_FORMAT_R16G16_SINT,                  16, CONVF_SINT | CONVF_R | CONVF_G },
1759     { DXGI_FORMAT_D32_FLOAT,                    32, CONVF_FLOAT | CONVF_DEPTH },
1760     { DXGI_FORMAT_R32_FLOAT,                    32, CONVF_FLOAT | CONVF_R },
1761     { DXGI_FORMAT_R32_UINT,                     32, CONVF_UINT | CONVF_R },
1762     { DXGI_FORMAT_R32_SINT,                     32, CONVF_SINT | CONVF_R },
1763     { DXGI_FORMAT_D24_UNORM_S8_UINT,            32, CONVF_UNORM | CONVF_DEPTH | CONVF_STENCIL },
1764     { DXGI_FORMAT_R8G8_UNORM,                   8, CONVF_UNORM | CONVF_R | CONVF_G },
1765     { DXGI_FORMAT_R8G8_UINT,                    8, CONVF_UINT | CONVF_R | CONVF_G },
1766     { DXGI_FORMAT_R8G8_SNORM,                   8, CONVF_SNORM | CONVF_R | CONVF_G },
1767     { DXGI_FORMAT_R8G8_SINT,                    8, CONVF_SINT | CONVF_R | CONVF_G },
1768     { DXGI_FORMAT_R16_FLOAT,                    16, CONVF_FLOAT | CONVF_R },
1769     { DXGI_FORMAT_D16_UNORM,                    16, CONVF_UNORM | CONVF_DEPTH },
1770     { DXGI_FORMAT_R16_UNORM,                    16, CONVF_UNORM | CONVF_R },
1771     { DXGI_FORMAT_R16_UINT,                     16, CONVF_UINT | CONVF_R },
1772     { DXGI_FORMAT_R16_SNORM,                    16, CONVF_SNORM | CONVF_R },
1773     { DXGI_FORMAT_R16_SINT,                     16, CONVF_SINT | CONVF_R },
1774     { DXGI_FORMAT_R8_UNORM,                     8, CONVF_UNORM | CONVF_R },
1775     { DXGI_FORMAT_R8_UINT,                      8, CONVF_UINT | CONVF_R },
1776     { DXGI_FORMAT_R8_SNORM,                     8, CONVF_SNORM | CONVF_R },
1777     { DXGI_FORMAT_R8_SINT,                      8, CONVF_SINT | CONVF_R },
1778     { DXGI_FORMAT_A8_UNORM,                     8, CONVF_UNORM | CONVF_A },
1779     { DXGI_FORMAT_R1_UNORM,                     1, CONVF_UNORM | CONVF_R },
1780     { DXGI_FORMAT_R9G9B9E5_SHAREDEXP,           9, CONVF_SHAREDEXP | CONVF_R | CONVF_G | CONVF_B },
1781     { DXGI_FORMAT_R8G8_B8G8_UNORM,              8, CONVF_UNORM | CONVF_PACKED | CONVF_R | CONVF_G | CONVF_B },
1782     { DXGI_FORMAT_G8R8_G8B8_UNORM,              8, CONVF_UNORM | CONVF_PACKED | CONVF_R | CONVF_G | CONVF_B },
1783     { DXGI_FORMAT_BC1_UNORM,                    8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1784     { DXGI_FORMAT_BC1_UNORM_SRGB,               8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1785     { DXGI_FORMAT_BC2_UNORM,                    8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1786     { DXGI_FORMAT_BC2_UNORM_SRGB,               8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1787     { DXGI_FORMAT_BC3_UNORM,                    8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1788     { DXGI_FORMAT_BC3_UNORM_SRGB,               8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1789     { DXGI_FORMAT_BC4_UNORM,                    8, CONVF_UNORM | CONVF_BC | CONVF_R },
1790     { DXGI_FORMAT_BC4_SNORM,                    8, CONVF_SNORM | CONVF_BC | CONVF_R },
1791     { DXGI_FORMAT_BC5_UNORM,                    8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G },
1792     { DXGI_FORMAT_BC5_SNORM,                    8, CONVF_SNORM | CONVF_BC | CONVF_R | CONVF_G },
1793     { DXGI_FORMAT_B5G6R5_UNORM,                 5, CONVF_UNORM | CONVF_R | CONVF_G | CONVF_B },
1794     { DXGI_FORMAT_B5G5R5A1_UNORM,               5, CONVF_UNORM | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1795     { DXGI_FORMAT_B8G8R8A8_UNORM,               8, CONVF_UNORM | CONVF_BGR | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1796     { DXGI_FORMAT_B8G8R8X8_UNORM,               8, CONVF_UNORM | CONVF_BGR | CONVF_R | CONVF_G | CONVF_B },
1797     { DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM,   10, CONVF_UNORM | CONVF_X2 | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1798     { DXGI_FORMAT_B8G8R8A8_UNORM_SRGB,          8, CONVF_UNORM | CONVF_BGR | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1799     { DXGI_FORMAT_B8G8R8X8_UNORM_SRGB,          8, CONVF_UNORM | CONVF_BGR | CONVF_R | CONVF_G | CONVF_B },
1800     { DXGI_FORMAT_BC6H_UF16,                    16, CONVF_FLOAT | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1801     { DXGI_FORMAT_BC6H_SF16,                    16, CONVF_FLOAT | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1802     { DXGI_FORMAT_BC7_UNORM,                    8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1803     { DXGI_FORMAT_BC7_UNORM_SRGB,               8, CONVF_UNORM | CONVF_BC | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1804 #ifdef DXGI_1_2_FORMATS
1805     { DXGI_FORMAT_B4G4R4A4_UNORM,               4, CONVF_UNORM | CONVF_BGR | CONVF_R | CONVF_G | CONVF_B | CONVF_A },
1806 #endif
1807 };
1808
1809 #pragma prefast( suppress : 25004, "Signature must match bsearch" );
1810 static int __cdecl _ConvertCompare( const void* ptr1, const void *ptr2 )
1811 {
1812     const ConvertData *p1 = reinterpret_cast<const ConvertData*>(ptr1);
1813     const ConvertData *p2 = reinterpret_cast<const ConvertData*>(ptr2);
1814     if ( p1->format == p2->format ) return 0;
1815     else return (p1->format < p2->format ) ? -1 : 1;
1816 }
1817
1818 DWORD _GetConvertFlags( DXGI_FORMAT format )
1819 {
1820 #ifdef _DEBUG
1821     // Ensure conversion table is in ascending order
1822     assert( _countof(g_ConvertTable) > 0 );
1823     DXGI_FORMAT lastvalue = g_ConvertTable[0].format;
1824     for( size_t index=1; index < _countof(g_ConvertTable); ++index )
1825     {
1826         assert( g_ConvertTable[index].format > lastvalue );
1827         lastvalue = g_ConvertTable[index].format;
1828     }
1829 #endif
1830
1831     ConvertData key = { format, 0 };
1832     const ConvertData* in = (const ConvertData*) bsearch( &key, g_ConvertTable, _countof(g_ConvertTable), sizeof(ConvertData),
1833                                                           _ConvertCompare );
1834     return (in) ? in->flags : 0;
1835 }
1836
1837 void _ConvertScanline( XMVECTOR* pBuffer, size_t count, DXGI_FORMAT outFormat, DXGI_FORMAT inFormat, DWORD flags )
1838 {
1839     assert( pBuffer && count > 0 && (((uintptr_t)pBuffer & 0xF) == 0) );
1840     assert( IsValid(outFormat) && !IsVideo(outFormat) && !IsTypeless(outFormat) );
1841     assert( IsValid(inFormat) && !IsVideo(inFormat) && !IsTypeless(inFormat) );
1842
1843     if ( !pBuffer )
1844         return;
1845
1846 #ifdef _DEBUG
1847     // Ensure conversion table is in ascending order
1848     assert( _countof(g_ConvertTable) > 0 );
1849     DXGI_FORMAT lastvalue = g_ConvertTable[0].format;
1850     for( size_t index=1; index < _countof(g_ConvertTable); ++index )
1851     {
1852         assert( g_ConvertTable[index].format > lastvalue );
1853         lastvalue = g_ConvertTable[index].format;
1854     }
1855 #endif
1856
1857     // Determine conversion details about source and dest formats
1858     ConvertData key = { inFormat, 0 };
1859     const ConvertData* in = (const ConvertData*) bsearch( &key, g_ConvertTable, _countof(g_ConvertTable), sizeof(ConvertData),
1860                                                           _ConvertCompare );
1861     key.format = outFormat;
1862     const ConvertData* out = (const ConvertData*) bsearch( &key, g_ConvertTable, _countof(g_ConvertTable), sizeof(ConvertData),
1863                                                            _ConvertCompare );
1864     if ( !in || !out )
1865     {
1866         assert(false);
1867         return;
1868     }
1869
1870     assert( _GetConvertFlags( inFormat ) == in->flags );
1871     assert( _GetConvertFlags( outFormat ) == out->flags );
1872
1873     // Handle SRGB filtering modes
1874     if ( IsSRGB( inFormat ) )
1875         flags |= TEX_FILTER_SRGB_IN;
1876
1877     if ( IsSRGB( outFormat ) )
1878         flags |= TEX_FILTER_SRGB_OUT;
1879
1880     if ( in->flags & CONVF_SNORM )
1881         flags &= ~TEX_FILTER_SRGB_IN;
1882
1883     if ( out->flags & CONVF_SNORM )
1884         flags &= ~TEX_FILTER_SRGB_OUT;
1885
1886     if ( (flags & (TEX_FILTER_SRGB_IN|TEX_FILTER_SRGB_OUT)) == (TEX_FILTER_SRGB_IN|TEX_FILTER_SRGB_OUT) )
1887     {
1888         flags &= ~(TEX_FILTER_SRGB_IN|TEX_FILTER_SRGB_OUT);
1889     }
1890
1891     // sRGB input processing (sRGB -> RGB)
1892     if ( flags & TEX_FILTER_SRGB_IN )
1893     {
1894         if ( (in->flags & CONVF_FLOAT) || (in->flags & CONVF_UNORM) )
1895         {
1896             XMVECTOR* ptr = pBuffer;
1897             for( size_t i=0; i < count; ++i )
1898             {
1899                 // rgb = rgb^(2.2); a=a
1900                 XMVECTOR v = *ptr;
1901                 XMVECTOR v1 = _TableDecodeGamma22( v );
1902                 *ptr++ = XMVectorSelect( v, v1, g_XMSelect1110 );
1903             }
1904         }
1905     }
1906
1907     // Handle conversion special cases
1908     DWORD diffFlags = in->flags ^ out->flags;
1909     if ( diffFlags != 0)
1910     {
1911         if ( out->flags & CONVF_UNORM )
1912         {
1913             if ( in->flags & CONVF_SNORM )
1914             {
1915                 // SNORM -> UNORM
1916                 XMVECTOR* ptr = pBuffer;
1917                 for( size_t i=0; i < count; ++i )
1918                 {
1919                     XMVECTOR v = *ptr;
1920                     *ptr++ = XMVectorMultiplyAdd( v, g_XMOneHalf, g_XMOneHalf );
1921                 }
1922             }
1923             else if ( in->flags & CONVF_FLOAT )
1924             {
1925                 // FLOAT -> UNORM
1926                 XMVECTOR* ptr = pBuffer;
1927                 for( size_t i=0; i < count; ++i )
1928                 {
1929                     XMVECTOR v = *ptr;
1930                     *ptr++ = XMVectorSaturate( v );
1931                 }
1932             }
1933         }
1934         else if ( out->flags & CONVF_SNORM )
1935         {
1936             if ( in->flags & CONVF_UNORM )
1937             {
1938                 // UNORM -> SNORM
1939                 static XMVECTORF32 two = { 2.0f, 2.0f, 2.0f, 2.0f };
1940                 XMVECTOR* ptr = pBuffer;
1941                 for( size_t i=0; i < count; ++i )
1942                 {
1943                     XMVECTOR v = *ptr;
1944                     *ptr++ = XMVectorMultiplyAdd( v, two, g_XMNegativeOne );
1945                 }
1946             }
1947             else if ( in->flags & CONVF_FLOAT )
1948             {
1949                 // FLOAT -> SNORM
1950                 XMVECTOR* ptr = pBuffer;
1951                 for( size_t i=0; i < count; ++i )
1952                 {
1953                     XMVECTOR v = *ptr;
1954                     *ptr++ = XMVectorClamp( v, g_XMNegativeOne, g_XMOne );
1955                 }
1956             }
1957         }
1958
1959         // !CONVF_A -> CONVF_A is handled because LoadScanline ensures alpha defaults to 1.0 for no-alpha formats
1960
1961         // CONVF_PACKED cases are handled because LoadScanline/StoreScanline handles packing/unpacking
1962
1963         if ( ((out->flags & CONVF_RGBA_MASK) == CONVF_A) && !(in->flags & CONVF_A) )
1964         {
1965             // !CONVF_A -> A format
1966             XMVECTOR* ptr = pBuffer;
1967             for( size_t i=0; i < count; ++i )
1968             {
1969                 XMVECTOR v = *ptr;
1970                 *ptr++ = XMVectorSplatX( v );
1971             }
1972         }
1973         else if ( ((in->flags & CONVF_RGBA_MASK) == CONVF_A) && !(out->flags & CONVF_A) )
1974         {
1975             // A format -> !CONVF_A
1976             XMVECTOR* ptr = pBuffer;
1977             for( size_t i=0; i < count; ++i )
1978             {
1979                 XMVECTOR v = *ptr;
1980                 *ptr++ = XMVectorSplatW( v );
1981             }
1982         }
1983         else if ( ((in->flags & CONVF_RGB_MASK) == CONVF_R) && ((out->flags & CONVF_RGB_MASK) == (CONVF_R|CONVF_G|CONVF_B)) )
1984         {
1985             // R format -> RGB format
1986             XMVECTOR* ptr = pBuffer;
1987             for( size_t i=0; i < count; ++i )
1988             {
1989                 XMVECTOR v = *ptr;
1990                 XMVECTOR v1 = XMVectorSplatX( v );
1991                 *ptr++ = XMVectorSelect( v, v1, g_XMSelect1110 );
1992             }
1993         }
1994     }
1995
1996     // sRGB output processing (RGB -> sRGB)
1997     if ( flags & TEX_FILTER_SRGB_OUT )
1998     {
1999         if ( (out->flags & CONVF_FLOAT) || (out->flags & CONVF_UNORM) )
2000         {
2001             XMVECTOR* ptr = pBuffer;
2002             for( size_t i=0; i < count; ++i )
2003             {
2004                 // rgb = rgb^(1/2.2); a=a
2005                 XMVECTOR v = *ptr;
2006                 XMVECTOR v1 = _TableEncodeGamma22( v );
2007                 *ptr++ = XMVectorSelect( v, v1, g_XMSelect1110 );
2008             }
2009         }
2010     }
2011 }
2012
2013
2014 //-------------------------------------------------------------------------------------
2015 // Convert the source image using WIC
2016 //-------------------------------------------------------------------------------------
2017 static HRESULT _ConvertUsingWIC( _In_ const Image& srcImage, _In_ const WICPixelFormatGUID& pfGUID,
2018                                  _In_ const WICPixelFormatGUID& targetGUID,
2019                                  _In_ DWORD filter, _In_ float threshold,  _In_ const Image& destImage )
2020 {
2021     assert( srcImage.width == destImage.width );
2022     assert( srcImage.height == destImage.height );
2023
2024     IWICImagingFactory* pWIC = _GetWIC();
2025     if ( !pWIC )
2026         return E_NOINTERFACE;
2027
2028     ScopedObject<IWICFormatConverter> FC;
2029     HRESULT hr = pWIC->CreateFormatConverter( &FC );
2030     if ( FAILED(hr) )
2031         return hr;
2032
2033     // Need to implement usage of TEX_FILTER_SRGB_IN/TEX_FILTER_SRGB_OUT
2034
2035     BOOL canConvert = FALSE;
2036     hr = FC->CanConvert( pfGUID, targetGUID, &canConvert );
2037     if ( FAILED(hr) || !canConvert )
2038     {
2039         // This case is not an issue for the subset of WIC formats that map directly to DXGI
2040         return E_UNEXPECTED;
2041     }
2042
2043     ScopedObject<IWICBitmap> source;
2044     hr = pWIC->CreateBitmapFromMemory( static_cast<UINT>( srcImage.width ), static_cast<UINT>( srcImage.height ), pfGUID,
2045                                        static_cast<UINT>( srcImage.rowPitch ), static_cast<UINT>( srcImage.slicePitch ),
2046                                        srcImage.pixels, &source );
2047     if ( FAILED(hr) )
2048         return hr;
2049
2050     hr = FC->Initialize( source.Get(), targetGUID, _GetWICDither( filter ), 0, threshold, WICBitmapPaletteTypeCustom );
2051     if ( FAILED(hr) )
2052         return hr;
2053
2054     hr = FC->CopyPixels( 0, static_cast<UINT>( destImage.rowPitch ), static_cast<UINT>( destImage.slicePitch ), destImage.pixels );  
2055     if ( FAILED(hr) )
2056         return hr;
2057
2058     return S_OK;
2059 }
2060
2061
2062 //-------------------------------------------------------------------------------------
2063 // Convert the source using WIC and then convert to DXGI format from there
2064 //-------------------------------------------------------------------------------------
2065 static HRESULT _ConvertFromWIC( _In_ const Image& srcImage, _In_ const WICPixelFormatGUID& pfGUID,
2066                                 _In_ DWORD filter, _In_ float threshold,  _In_ const Image& destImage )
2067 {
2068     assert( srcImage.width == destImage.width );
2069     assert( srcImage.height == destImage.height );
2070
2071     IWICImagingFactory* pWIC = _GetWIC();
2072     if ( !pWIC )
2073         return E_NOINTERFACE;
2074
2075     ScopedObject<IWICFormatConverter> FC;
2076     HRESULT hr = pWIC->CreateFormatConverter( &FC );
2077     if ( FAILED(hr) )
2078         return hr;
2079
2080     BOOL canConvert = FALSE;
2081     hr = FC->CanConvert( pfGUID, GUID_WICPixelFormat128bppRGBAFloat, &canConvert );
2082     if ( FAILED(hr) || !canConvert )
2083     {
2084         // This case is not an issue for the subset of WIC formats that map directly to DXGI
2085         return E_UNEXPECTED;
2086     }
2087
2088     ScratchImage temp;
2089     hr = temp.Initialize2D( DXGI_FORMAT_R32G32B32A32_FLOAT, srcImage.width, srcImage.height, 1, 1 );
2090     if ( FAILED(hr) )
2091         return hr;
2092
2093     const Image *timg = temp.GetImage( 0, 0, 0 );
2094     if ( !timg )
2095         return E_POINTER;
2096
2097     ScopedObject<IWICBitmap> source;
2098     hr = pWIC->CreateBitmapFromMemory( static_cast<UINT>( srcImage.width ), static_cast<UINT>( srcImage.height ), pfGUID,
2099                                        static_cast<UINT>( srcImage.rowPitch ), static_cast<UINT>( srcImage.slicePitch ),
2100                                        srcImage.pixels, &source );
2101     if ( FAILED(hr) )
2102         return hr;
2103
2104     hr = FC->Initialize( source.Get(), GUID_WICPixelFormat128bppRGBAFloat, _GetWICDither( filter ), 0, threshold, WICBitmapPaletteTypeCustom );
2105     if ( FAILED(hr) )
2106         return hr;
2107
2108     hr = FC->CopyPixels( 0, static_cast<UINT>( timg->rowPitch ), static_cast<UINT>( timg->slicePitch ), timg->pixels );  
2109     if ( FAILED(hr) )
2110         return hr;
2111
2112     // Perform conversion on temp image which is now in R32G32B32A32_FLOAT format to final image
2113     uint8_t *pSrc = timg->pixels;
2114     uint8_t *pDest = destImage.pixels;
2115     if ( !pSrc || !pDest )
2116         return E_POINTER;
2117
2118     for( size_t h = 0; h < srcImage.height; ++h )
2119     {
2120         _ConvertScanline( reinterpret_cast<XMVECTOR*>(pSrc), srcImage.width, destImage.format, DXGI_FORMAT_R32G32B32A32_FLOAT, filter );
2121
2122         if ( !_StoreScanline( pDest, destImage.rowPitch, destImage.format, reinterpret_cast<const XMVECTOR*>(pSrc), srcImage.width ) )
2123             return E_FAIL;
2124
2125         pSrc += timg->rowPitch;
2126         pDest += destImage.rowPitch;
2127     }
2128
2129     return S_OK;
2130 }
2131
2132
2133 //-------------------------------------------------------------------------------------
2134 // Convert the source from DXGI format then use WIC to convert to final format
2135 //-------------------------------------------------------------------------------------
2136 static HRESULT _ConvertToWIC( _In_ const Image& srcImage, 
2137                               _In_ const WICPixelFormatGUID& targetGUID, _In_ DWORD filter, _In_ float threshold,  _In_ const Image& destImage )
2138 {
2139     assert( srcImage.width == destImage.width );
2140     assert( srcImage.height == destImage.height );
2141
2142     IWICImagingFactory* pWIC = _GetWIC();
2143     if ( !pWIC )
2144         return E_NOINTERFACE;
2145
2146     ScopedObject<IWICFormatConverter> FC;
2147     HRESULT hr = pWIC->CreateFormatConverter( &FC );
2148     if ( FAILED(hr) )
2149         return hr;
2150
2151     BOOL canConvert = FALSE;
2152     hr = FC->CanConvert( GUID_WICPixelFormat128bppRGBAFloat, targetGUID, &canConvert );
2153     if ( FAILED(hr) || !canConvert )
2154     {
2155         // This case is not an issue for the subset of WIC formats that map directly to DXGI
2156         return E_UNEXPECTED;
2157     }
2158
2159     ScratchImage temp;
2160     hr = temp.Initialize2D( DXGI_FORMAT_R32G32B32A32_FLOAT, srcImage.width, srcImage.height, 1, 1 );
2161     if ( FAILED(hr) )
2162         return hr;
2163
2164     const Image *timg = temp.GetImage( 0, 0, 0 );
2165     if ( !timg )
2166         return E_POINTER;
2167
2168     const uint8_t *pSrc = srcImage.pixels;
2169     if ( !pSrc )
2170         return E_POINTER;
2171
2172     uint8_t *pDest = timg->pixels;
2173     if ( !pDest )
2174         return E_POINTER;
2175
2176     for( size_t h = 0; h < srcImage.height; ++h )
2177     {
2178         if ( !_LoadScanline( reinterpret_cast<XMVECTOR*>(pDest), srcImage.width, pSrc, srcImage.rowPitch, srcImage.format ) )
2179             return E_FAIL;
2180
2181         _ConvertScanline( reinterpret_cast<XMVECTOR*>(pDest), srcImage.width, DXGI_FORMAT_R32G32B32A32_FLOAT, srcImage.format, filter );
2182
2183         pSrc += srcImage.rowPitch;
2184         pDest += timg->rowPitch;
2185     }
2186
2187     // Perform conversion on temp image which is now in R32G32B32A32_FLOAT format
2188     ScopedObject<IWICBitmap> source;
2189     hr = pWIC->CreateBitmapFromMemory( static_cast<UINT>( timg->width ), static_cast<UINT>( timg->height ), GUID_WICPixelFormat128bppRGBAFloat,
2190                                        static_cast<UINT>( timg->rowPitch ), static_cast<UINT>( timg->slicePitch ),
2191                                        timg->pixels, &source );
2192     if ( FAILED(hr) )
2193         return hr;
2194
2195     hr = FC->Initialize( source.Get(), targetGUID, _GetWICDither( filter ), 0, threshold, WICBitmapPaletteTypeCustom );
2196     if ( FAILED(hr) )
2197         return hr;
2198
2199     hr = FC->CopyPixels( 0, static_cast<UINT>( destImage.rowPitch ), static_cast<UINT>( destImage.slicePitch ), destImage.pixels );  
2200     if ( FAILED(hr) )
2201         return hr;
2202
2203     return S_OK;
2204 }
2205
2206
2207 //-------------------------------------------------------------------------------------
2208 // Convert the source image (not using WIC)
2209 //-------------------------------------------------------------------------------------
2210 static HRESULT _Convert( _In_ const Image& srcImage, _In_ DWORD filter, _In_ const Image& destImage )
2211 {
2212     assert( srcImage.width == destImage.width );
2213     assert( srcImage.height == destImage.height );
2214
2215     ScopedAlignedArrayXMVECTOR scanline( reinterpret_cast<XMVECTOR*>( _aligned_malloc( (sizeof(XMVECTOR)*srcImage.width), 16 ) ) );
2216     if ( !scanline )
2217         return E_OUTOFMEMORY;
2218
2219     const uint8_t *pSrc = srcImage.pixels;
2220     uint8_t *pDest = destImage.pixels;
2221     if ( !pSrc || !pDest )
2222         return E_POINTER;
2223
2224     for( size_t h = 0; h < srcImage.height; ++h )
2225     {
2226         if ( !_LoadScanline( scanline.get(), srcImage.width, pSrc, srcImage.rowPitch, srcImage.format ) )
2227             return E_FAIL;
2228
2229         _ConvertScanline( scanline.get(), srcImage.width, destImage.format, srcImage.format, filter );
2230
2231         if ( !_StoreScanline( pDest, destImage.rowPitch, destImage.format, scanline.get(), srcImage.width ) )
2232             return E_FAIL;
2233
2234         pSrc += srcImage.rowPitch;
2235         pDest += destImage.rowPitch;
2236     }
2237
2238     return S_OK;
2239 }
2240
2241
2242 //=====================================================================================
2243 // Entry-points
2244 //=====================================================================================
2245
2246 //-------------------------------------------------------------------------------------
2247 // Convert image
2248 //-------------------------------------------------------------------------------------
2249 HRESULT Convert( const Image& srcImage, DXGI_FORMAT format, DWORD filter, float threshold, ScratchImage& image )
2250 {
2251     if ( (srcImage.format == format) || !IsValid( format ) )
2252         return E_INVALIDARG;
2253
2254     if ( !srcImage.pixels )
2255         return E_POINTER;
2256
2257     if ( IsCompressed(srcImage.format) || IsCompressed(format)
2258          || IsVideo(srcImage.format) || IsVideo(format) 
2259          || IsTypeless(srcImage.format) || IsTypeless(format) )
2260         return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
2261
2262 #ifdef _AMD64_
2263     if ( (srcImage.width > 0xFFFFFFFF) || (srcImage.height > 0xFFFFFFFF) )
2264         return E_INVALIDARG;
2265 #endif
2266
2267     HRESULT hr = image.Initialize2D( format, srcImage.width, srcImage.height, 1, 1 );
2268     if ( FAILED(hr) )
2269         return hr;
2270    
2271     const Image *rimage = image.GetImage( 0, 0, 0 );
2272     if ( !rimage )
2273     {
2274         image.Release();
2275         return E_POINTER;
2276     }
2277
2278     WICPixelFormatGUID pfGUID;
2279     if ( _DXGIToWIC( srcImage.format, pfGUID ) )
2280     {
2281         WICPixelFormatGUID targetGUID;
2282         if ( _DXGIToWIC( format, targetGUID ) )
2283         {
2284             // Case 1: Both source and target formats are WIC supported
2285             hr = _ConvertUsingWIC( srcImage, pfGUID, targetGUID, filter, threshold, *rimage );
2286         }
2287         else
2288         {
2289             // Case 2: Source format is supported by WIC, but not the target format
2290             hr = _ConvertFromWIC( srcImage, pfGUID, filter, threshold, *rimage );
2291         }
2292     }
2293     else
2294     {
2295         WICPixelFormatGUID targetGUID;
2296         if ( _DXGIToWIC( format, targetGUID ) )
2297         {
2298             // Case 3: Source format is not supported by WIC, but does support the target format
2299             hr = _ConvertToWIC( srcImage, targetGUID, filter, threshold, *rimage );
2300         }
2301         else
2302         {
2303             // Case 4: Both source and target format are not supported by WIC
2304             hr = _Convert( srcImage, filter, *rimage );
2305         }
2306     }
2307
2308     if ( FAILED(hr) )
2309     {
2310         image.Release();
2311         return hr;
2312     }
2313
2314     return S_OK;
2315 }
2316
2317
2318 //-------------------------------------------------------------------------------------
2319 // Convert image (complex)
2320 //-------------------------------------------------------------------------------------
2321 HRESULT Convert( const Image* srcImages, size_t nimages, const TexMetadata& metadata,
2322                  DXGI_FORMAT format, DWORD filter, float threshold, ScratchImage& result )
2323 {
2324     if ( !srcImages || !nimages || (metadata.format == format) || !IsValid(format) )
2325         return E_INVALIDARG;
2326
2327     if ( IsCompressed(metadata.format) || IsCompressed(format)
2328          || IsVideo(metadata.format) || IsVideo(format) 
2329          || IsTypeless(metadata.format) || IsTypeless(format) )
2330         return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
2331
2332 #ifdef _AMD64_
2333     if ( (metadata.width > 0xFFFFFFFF) || (metadata.height > 0xFFFFFFFF) )
2334         return E_INVALIDARG;
2335 #endif
2336
2337     TexMetadata mdata2 = metadata;
2338     mdata2.format = format;
2339     HRESULT hr = result.Initialize( mdata2 );
2340     if ( FAILED(hr) )
2341         return hr;
2342
2343     if ( nimages != result.GetImageCount() )
2344     {
2345         result.Release();
2346         return E_FAIL;
2347     }
2348
2349     const Image* dest = result.GetImages();
2350     if ( !dest )
2351     {
2352         result.Release();
2353         return E_POINTER;
2354     }
2355
2356     WICPixelFormatGUID pfGUID, targetGUID;
2357     bool wicpf = _DXGIToWIC( metadata.format, pfGUID );
2358     bool wictargetpf = _DXGIToWIC( format, targetGUID );
2359
2360     for( size_t index=0; index < nimages; ++index )
2361     {
2362         const Image& src = srcImages[ index ];
2363         if ( src.format != metadata.format )
2364         {
2365             result.Release();
2366             return E_FAIL;
2367         }
2368
2369 #ifdef _AMD64_
2370         if ( (src.width > 0xFFFFFFFF) || (src.height > 0xFFFFFFFF) )
2371             return E_FAIL;
2372 #endif
2373
2374         const Image& dst = dest[ index ];
2375         assert( dst.format == format );
2376
2377         if ( src.width != dst.width || src.height != dst.height )
2378         {
2379             result.Release();
2380             return E_FAIL;
2381         }
2382
2383         if ( wicpf )
2384         {
2385             if ( wictargetpf )
2386             {
2387                 // Case 1: Both source and target formats are WIC supported
2388                 hr = _ConvertUsingWIC( src, pfGUID, targetGUID, filter, threshold, dst );
2389             }
2390             else
2391             {
2392                 // Case 2: Source format is supported by WIC, but not the target format
2393                 hr = _ConvertFromWIC( src, pfGUID, filter, threshold, dst );
2394             }
2395         }
2396         else
2397         {
2398             if ( wictargetpf )
2399             {
2400                 // Case 3: Source format is not supported by WIC, but does support the target format
2401                 hr = _ConvertToWIC( src, targetGUID, filter, threshold, dst );
2402             }
2403             else
2404             {
2405                 // Case 4: Both source and target format are not supported by WIC
2406                 hr = _Convert( src, filter, dst );
2407             }
2408         }
2409
2410         if ( FAILED(hr) )
2411         {
2412             result.Release();
2413             return hr;
2414         }
2415     }
2416
2417     return S_OK;
2418 }
2419
2420 }; // namespace