1 //-------------------------------------------------------------------------------------
2 // DirectXTexImage.cpp
3 //
4 // DirectX Texture Library - Image container
5 //
6 // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
7 // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
8 // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
9 // PARTICULAR PURPOSE.
10 //
11 // Copyright (c) Microsoft Corporation. All rights reserved.
12 //
13 // http://go.microsoft.com/fwlink/?LinkId=248926
14 //-------------------------------------------------------------------------------------
15
16 #include "DirectXTexP.h"
17
18 namespace DirectX
19 {
20
21 extern bool _CalculateMipLevels( _In_ size_t width, _In_ size_t height, _Inout_ size_t& mipLevels );
22 extern bool _CalculateMipLevels3D( _In_ size_t width, _In_ size_t height, _In_ size_t depth, _Inout_ size_t& mipLevels );
23 extern bool _IsAlphaAllOpaqueBC( _In_ const Image& cImage );
24
25 //-------------------------------------------------------------------------------------
26 // Determines number of image array entries and pixel size
27 //-------------------------------------------------------------------------------------
28 _Use_decl_annotations_
_DetermineImageArray(const TexMetadata & metadata,DWORD cpFlags,size_t & nImages,size_t & pixelSize)29 void _DetermineImageArray( const TexMetadata& metadata, DWORD cpFlags,
30 size_t& nImages, size_t& pixelSize )
31 {
32 assert( metadata.width > 0 && metadata.height > 0 && metadata.depth > 0 );
33 assert( metadata.arraySize > 0 );
34 assert( metadata.mipLevels > 0 );
35
36 size_t _pixelSize = 0;
37 size_t _nimages = 0;
38
39 switch( metadata.dimension )
40 {
41 case TEX_DIMENSION_TEXTURE1D:
42 case TEX_DIMENSION_TEXTURE2D:
43 for( size_t item = 0; item < metadata.arraySize; ++item )
44 {
45 size_t w = metadata.width;
46 size_t h = metadata.height;
47
48 for( size_t level=0; level < metadata.mipLevels; ++level )
49 {
50 size_t rowPitch, slicePitch;
51 ComputePitch( metadata.format, w, h, rowPitch, slicePitch, cpFlags );
52
53 _pixelSize += slicePitch;
54 ++_nimages;
55
56 if ( h > 1 )
57 h >>= 1;
58
59 if ( w > 1 )
60 w >>= 1;
61 }
62 }
63 break;
64
65 case TEX_DIMENSION_TEXTURE3D:
66 {
67 size_t w = metadata.width;
68 size_t h = metadata.height;
69 size_t d = metadata.depth;
70
71 for( size_t level=0; level < metadata.mipLevels; ++level )
72 {
73 size_t rowPitch, slicePitch;
74 ComputePitch( metadata.format, w, h, rowPitch, slicePitch, cpFlags );
75
76 for( size_t slice=0; slice < d; ++slice )
77 {
78 _pixelSize += slicePitch;
79 ++_nimages;
80 }
81
82 if ( h > 1 )
83 h >>= 1;
84
85 if ( w > 1 )
86 w >>= 1;
87
88 if ( d > 1 )
89 d >>= 1;
90 }
91 }
92 break;
93
94 default:
95 assert( false );
96 break;
97 }
98
99 nImages = _nimages;
100 pixelSize = _pixelSize;
101 }
102
103
104 //-------------------------------------------------------------------------------------
105 // Fills in the image array entries
106 //-------------------------------------------------------------------------------------
107 _Use_decl_annotations_
_SetupImageArray(uint8_t * pMemory,size_t pixelSize,const TexMetadata & metadata,DWORD cpFlags,Image * images,size_t nImages)108 bool _SetupImageArray( uint8_t *pMemory, size_t pixelSize,
109 const TexMetadata& metadata, DWORD cpFlags,
110 Image* images, size_t nImages )
111 {
112 assert( pMemory );
113 assert( pixelSize > 0 );
114 assert( nImages > 0 );
115
116 if ( !images )
117 return false;
118
119 size_t index = 0;
120 uint8_t* pixels = pMemory;
121 const uint8_t* pEndBits = pMemory + pixelSize;
122
123 switch( metadata.dimension )
124 {
125 case TEX_DIMENSION_TEXTURE1D:
126 case TEX_DIMENSION_TEXTURE2D:
127 if (metadata.arraySize == 0 || metadata.mipLevels == 0)
128 {
129 return false;
130 }
131
132 for( size_t item = 0; item < metadata.arraySize; ++item )
133 {
134 size_t w = metadata.width;
135 size_t h = metadata.height;
136
137 for( size_t level=0; level < metadata.mipLevels; ++level )
138 {
139 if ( index >= nImages )
140 {
141 return false;
142 }
143
144 size_t rowPitch, slicePitch;
145 ComputePitch( metadata.format, w, h, rowPitch, slicePitch, cpFlags );
146
147 images[index].width = w;
148 images[index].height = h;
149 images[index].format = metadata.format;
150 images[index].rowPitch = rowPitch;
151 images[index].slicePitch = slicePitch;
152 images[index].pixels = pixels;
153 ++index;
154
155 pixels += slicePitch;
156 if ( pixels > pEndBits )
157 {
158 return false;
159 }
160
161 if ( h > 1 )
162 h >>= 1;
163
164 if ( w > 1 )
165 w >>= 1;
166 }
167 }
168 return true;
169
170 case TEX_DIMENSION_TEXTURE3D:
171 {
172 if (metadata.mipLevels == 0 || metadata.depth == 0)
173 {
174 return false;
175 }
176
177 size_t w = metadata.width;
178 size_t h = metadata.height;
179 size_t d = metadata.depth;
180
181 for( size_t level=0; level < metadata.mipLevels; ++level )
182 {
183 size_t rowPitch, slicePitch;
184 ComputePitch( metadata.format, w, h, rowPitch, slicePitch, cpFlags );
185
186 for( size_t slice=0; slice < d; ++slice )
187 {
188 if ( index >= nImages )
189 {
190 return false;
191 }
192
193 // We use the same memory organization that Direct3D 11 needs for D3D11_SUBRESOURCE_DATA
194 // with all slices of a given miplevel being continuous in memory
195 images[index].width = w;
196 images[index].height = h;
197 images[index].format = metadata.format;
198 images[index].rowPitch = rowPitch;
199 images[index].slicePitch = slicePitch;
200 images[index].pixels = pixels;
201 ++index;
202
203 pixels += slicePitch;
204 if ( pixels > pEndBits )
205 {
206 return false;
207 }
208 }
209
210 if ( h > 1 )
211 h >>= 1;
212
213 if ( w > 1 )
214 w >>= 1;
215
216 if ( d > 1 )
217 d >>= 1;
218 }
219 }
220 return true;
221
222 default:
223 return false;
224 }
225 }
226
227
228 //=====================================================================================
229 // ScratchImage - Bitmap image container
230 //=====================================================================================
231
operator =(ScratchImage && moveFrom)232 ScratchImage& ScratchImage::operator= (ScratchImage&& moveFrom)
233 {
234 if ( this != &moveFrom )
235 {
236 Release();
237
238 _nimages = moveFrom._nimages;
239 _size = moveFrom._size;
240 _metadata = moveFrom._metadata;
241 _image = moveFrom._image;
242 _memory = moveFrom._memory;
243
244 moveFrom._nimages = 0;
245 moveFrom._size = 0;
246 moveFrom._image = nullptr;
247 moveFrom._memory = nullptr;
248 }
249 return *this;
250 }
251
252
253 //-------------------------------------------------------------------------------------
254 // Methods
255 //-------------------------------------------------------------------------------------
256 _Use_decl_annotations_
Initialize(const TexMetadata & mdata,DWORD flags)257 HRESULT ScratchImage::Initialize( const TexMetadata& mdata, DWORD flags )
258 {
259 if ( !IsValid(mdata.format) )
260 return E_INVALIDARG;
261
262 if ( IsPalettized(mdata.format) )
263 return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
264
265 size_t mipLevels = mdata.mipLevels;
266
267 switch( mdata.dimension )
268 {
269 case TEX_DIMENSION_TEXTURE1D:
270 if ( !mdata.width || mdata.height != 1 || mdata.depth != 1 || !mdata.arraySize )
271 return E_INVALIDARG;
272
273 if ( !_CalculateMipLevels(mdata.width,1,mipLevels) )
274 return E_INVALIDARG;
275 break;
276
277 case TEX_DIMENSION_TEXTURE2D:
278 if ( !mdata.width || !mdata.height || mdata.depth != 1 || !mdata.arraySize )
279 return E_INVALIDARG;
280
281 if ( mdata.IsCubemap() )
282 {
283 if ( (mdata.arraySize % 6) != 0 )
284 return E_INVALIDARG;
285 }
286
287 if ( !_CalculateMipLevels(mdata.width,mdata.height,mipLevels) )
288 return E_INVALIDARG;
289 break;
290
291 case TEX_DIMENSION_TEXTURE3D:
292 if ( !mdata.width || !mdata.height || !mdata.depth || mdata.arraySize != 1 )
293 return E_INVALIDARG;
294
295 if ( !_CalculateMipLevels3D(mdata.width,mdata.height,mdata.depth,mipLevels) )
296 return E_INVALIDARG;
297 break;
298
299 default:
300 return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
301 }
302
303 Release();
304
305 _metadata.width = mdata.width;
306 _metadata.height = mdata.height;
307 _metadata.depth = mdata.depth;
308 _metadata.arraySize = mdata.arraySize;
309 _metadata.mipLevels = mipLevels;
310 _metadata.miscFlags = mdata.miscFlags;
311 _metadata.miscFlags2 = mdata.miscFlags2;
312 _metadata.format = mdata.format;
313 _metadata.dimension = mdata.dimension;
314
315 size_t pixelSize, nimages;
316 _DetermineImageArray( _metadata, flags, nimages, pixelSize );
317
318 _image = new (std::nothrow) Image[ nimages ];
319 if ( !_image )
320 return E_OUTOFMEMORY;
321
322 _nimages = nimages;
323 memset( _image, 0, sizeof(Image) * nimages );
324
325 _memory = reinterpret_cast<uint8_t*>( _aligned_malloc( pixelSize, 16 ) );
326 if ( !_memory )
327 {
328 Release();
329 return E_OUTOFMEMORY;
330 }
331 _size = pixelSize;
332 if ( !_SetupImageArray( _memory, pixelSize, _metadata, flags, _image, nimages ) )
333 {
334 Release();
335 return E_FAIL;
336 }
337
338 return S_OK;
339 }
340
341 _Use_decl_annotations_
Initialize1D(DXGI_FORMAT fmt,size_t length,size_t arraySize,size_t mipLevels,DWORD flags)342 HRESULT ScratchImage::Initialize1D( DXGI_FORMAT fmt, size_t length, size_t arraySize, size_t mipLevels, DWORD flags )
343 {
344 if ( !length || !arraySize )
345 return E_INVALIDARG;
346
347 // 1D is a special case of the 2D case
348 HRESULT hr = Initialize2D( fmt, length, 1, arraySize, mipLevels, flags );
349 if ( FAILED(hr) )
350 return hr;
351
352 _metadata.dimension = TEX_DIMENSION_TEXTURE1D;
353
354 return S_OK;
355 }
356
357 _Use_decl_annotations_
Initialize2D(DXGI_FORMAT fmt,size_t width,size_t height,size_t arraySize,size_t mipLevels,DWORD flags)358 HRESULT ScratchImage::Initialize2D( DXGI_FORMAT fmt, size_t width, size_t height, size_t arraySize, size_t mipLevels, DWORD flags )
359 {
360 if ( !IsValid(fmt) || !width || !height || !arraySize )
361 return E_INVALIDARG;
362
363 if ( IsPalettized(fmt) )
364 return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
365
366 if ( !_CalculateMipLevels(width,height,mipLevels) )
367 return E_INVALIDARG;
368
369 Release();
370
371 _metadata.width = width;
372 _metadata.height = height;
373 _metadata.depth = 1;
374 _metadata.arraySize = arraySize;
375 _metadata.mipLevels = mipLevels;
376 _metadata.miscFlags = 0;
377 _metadata.miscFlags2 = 0;
378 _metadata.format = fmt;
379 _metadata.dimension = TEX_DIMENSION_TEXTURE2D;
380
381 size_t pixelSize, nimages;
382 _DetermineImageArray( _metadata, flags, nimages, pixelSize );
383
384 _image = new (std::nothrow) Image[ nimages ];
385 if ( !_image )
386 return E_OUTOFMEMORY;
387
388 _nimages = nimages;
389 memset( _image, 0, sizeof(Image) * nimages );
390
391 _memory = reinterpret_cast<uint8_t*>( _aligned_malloc( pixelSize, 16 ) );
392 if ( !_memory )
393 {
394 Release();
395 return E_OUTOFMEMORY;
396 }
397 _size = pixelSize;
398 if ( !_SetupImageArray( _memory, pixelSize, _metadata, flags, _image, nimages ) )
399 {
400 Release();
401 return E_FAIL;
402 }
403
404 return S_OK;
405 }
406
407 _Use_decl_annotations_
Initialize3D(DXGI_FORMAT fmt,size_t width,size_t height,size_t depth,size_t mipLevels,DWORD flags)408 HRESULT ScratchImage::Initialize3D( DXGI_FORMAT fmt, size_t width, size_t height, size_t depth, size_t mipLevels, DWORD flags )
409 {
410 if ( !IsValid(fmt) || !width || !height || !depth )
411 return E_INVALIDARG;
412
413 if ( IsPalettized(fmt) )
414 return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
415
416 if ( !_CalculateMipLevels3D(width,height,depth,mipLevels) )
417 return E_INVALIDARG;
418
419 Release();
420
421 _metadata.width = width;
422 _metadata.height = height;
423 _metadata.depth = depth;
424 _metadata.arraySize = 1; // Direct3D 10.x/11 does not support arrays of 3D textures
425 _metadata.mipLevels = mipLevels;
426 _metadata.miscFlags = 0;
427 _metadata.miscFlags2 = 0;
428 _metadata.format = fmt;
429 _metadata.dimension = TEX_DIMENSION_TEXTURE3D;
430
431 size_t pixelSize, nimages;
432 _DetermineImageArray( _metadata, flags, nimages, pixelSize );
433
434 _image = new (std::nothrow) Image[ nimages ];
435 if ( !_image )
436 {
437 Release();
438 return E_OUTOFMEMORY;
439 }
440 _nimages = nimages;
441 memset( _image, 0, sizeof(Image) * nimages );
442
443 _memory = reinterpret_cast<uint8_t*>( _aligned_malloc( pixelSize, 16 ) );
444 if ( !_memory )
445 {
446 Release();
447 return E_OUTOFMEMORY;
448 }
449 _size = pixelSize;
450
451 if ( !_SetupImageArray( _memory, pixelSize, _metadata, flags, _image, nimages ) )
452 {
453 Release();
454 return E_FAIL;
455 }
456
457 return S_OK;
458 }
459
460 _Use_decl_annotations_
InitializeCube(DXGI_FORMAT fmt,size_t width,size_t height,size_t nCubes,size_t mipLevels,DWORD flags)461 HRESULT ScratchImage::InitializeCube( DXGI_FORMAT fmt, size_t width, size_t height, size_t nCubes, size_t mipLevels, DWORD flags )
462 {
463 if ( !width || !height || !nCubes )
464 return E_INVALIDARG;
465
466 // A DirectX11 cubemap is just a 2D texture array that is a multiple of 6 for each cube
467 HRESULT hr = Initialize2D( fmt, width, height, nCubes * 6, mipLevels, flags );
468 if ( FAILED(hr) )
469 return hr;
470
471 _metadata.miscFlags |= TEX_MISC_TEXTURECUBE;
472
473 return S_OK;
474 }
475
476 _Use_decl_annotations_
InitializeFromImage(const Image & srcImage,bool allow1D,DWORD flags)477 HRESULT ScratchImage::InitializeFromImage( const Image& srcImage, bool allow1D, DWORD flags )
478 {
479 HRESULT hr = ( srcImage.height > 1 || !allow1D )
480 ? Initialize2D( srcImage.format, srcImage.width, srcImage.height, 1, 1, flags )
481 : Initialize1D( srcImage.format, srcImage.width, 1, 1, flags );
482
483 if ( FAILED(hr) )
484 return hr;
485
486 size_t rowCount = ComputeScanlines( srcImage.format, srcImage.height );
487 if ( !rowCount )
488 return E_UNEXPECTED;
489
490 const uint8_t* sptr = reinterpret_cast<const uint8_t*>( srcImage.pixels );
491 if ( !sptr )
492 return E_POINTER;
493
494 auto dptr = reinterpret_cast<uint8_t*>( _image[0].pixels );
495 if ( !dptr )
496 return E_POINTER;
497
498 size_t spitch = srcImage.rowPitch;
499 size_t dpitch = _image[0].rowPitch;
500
501 size_t size = std::min<size_t>( dpitch, spitch );
502
503 for( size_t y = 0; y < rowCount; ++y )
504 {
505 memcpy_s( dptr, dpitch, sptr, size );
506 sptr += spitch;
507 dptr += dpitch;
508 }
509
510 return S_OK;
511 }
512
513 _Use_decl_annotations_
InitializeArrayFromImages(const Image * images,size_t nImages,bool allow1D,DWORD flags)514 HRESULT ScratchImage::InitializeArrayFromImages( const Image* images, size_t nImages, bool allow1D, DWORD flags )
515 {
516 if ( !images || !nImages )
517 return E_INVALIDARG;
518
519 DXGI_FORMAT format = images[0].format;
520 size_t width = images[0].width;
521 size_t height = images[0].height;
522
523 for( size_t index=0; index < nImages; ++index )
524 {
525 if ( !images[index].pixels )
526 return E_POINTER;
527
528 if ( images[index].format != format || images[index].width != width || images[index].height != height )
529 {
530 // All images must be the same format, width, and height
531 return E_FAIL;
532 }
533 }
534
535 HRESULT hr = ( height > 1 || !allow1D )
536 ? Initialize2D( format, width, height, nImages, 1, flags )
537 : Initialize1D( format, width, nImages, 1, flags );
538
539 if ( FAILED(hr) )
540 return hr;
541
542 size_t rowCount = ComputeScanlines( format, height );
543 if ( !rowCount )
544 return E_UNEXPECTED;
545
546 for( size_t index=0; index < nImages; ++index )
547 {
548 auto sptr = reinterpret_cast<const uint8_t*>( images[index].pixels );
549 if ( !sptr )
550 return E_POINTER;
551
552 assert( index < _nimages );
553 auto dptr = reinterpret_cast<uint8_t*>( _image[index].pixels );
554 if ( !dptr )
555 return E_POINTER;
556
557 size_t spitch = images[index].rowPitch;
558 size_t dpitch = _image[index].rowPitch;
559
560 size_t size = std::min<size_t>( dpitch, spitch );
561
562 for( size_t y = 0; y < rowCount; ++y )
563 {
564 memcpy_s( dptr, dpitch, sptr, size );
565 sptr += spitch;
566 dptr += dpitch;
567 }
568 }
569
570 return S_OK;
571 }
572
573 _Use_decl_annotations_
InitializeCubeFromImages(const Image * images,size_t nImages,DWORD flags)574 HRESULT ScratchImage::InitializeCubeFromImages( const Image* images, size_t nImages, DWORD flags )
575 {
576 if ( !images || !nImages )
577 return E_INVALIDARG;
578
579 // A DirectX11 cubemap is just a 2D texture array that is a multiple of 6 for each cube
580 if ( ( nImages % 6 ) != 0 )
581 return E_INVALIDARG;
582
583 HRESULT hr = InitializeArrayFromImages( images, nImages, false, flags );
584 if ( FAILED(hr) )
585 return hr;
586
587 _metadata.miscFlags |= TEX_MISC_TEXTURECUBE;
588
589 return S_OK;
590 }
591
592 _Use_decl_annotations_
Initialize3DFromImages(const Image * images,size_t depth,DWORD flags)593 HRESULT ScratchImage::Initialize3DFromImages( const Image* images, size_t depth, DWORD flags )
594 {
595 if ( !images || !depth )
596 return E_INVALIDARG;
597
598 DXGI_FORMAT format = images[0].format;
599 size_t width = images[0].width;
600 size_t height = images[0].height;
601
602 for( size_t slice=0; slice < depth; ++slice )
603 {
604 if ( !images[slice].pixels )
605 return E_POINTER;
606
607 if ( images[slice].format != format || images[slice].width != width || images[slice].height != height )
608 {
609 // All images must be the same format, width, and height
610 return E_FAIL;
611 }
612 }
613
614 HRESULT hr = Initialize3D( format, width, height, depth, 1, flags );
615 if ( FAILED(hr) )
616 return hr;
617
618 size_t rowCount = ComputeScanlines( format, height );
619 if ( !rowCount )
620 return E_UNEXPECTED;
621
622 for( size_t slice=0; slice < depth; ++slice )
623 {
624 auto sptr = reinterpret_cast<const uint8_t*>( images[slice].pixels );
625 if ( !sptr )
626 return E_POINTER;
627
628 assert( slice < _nimages );
629 auto dptr = reinterpret_cast<uint8_t*>( _image[slice].pixels );
630 if ( !dptr )
631 return E_POINTER;
632
633 size_t spitch = images[slice].rowPitch;
634 size_t dpitch = _image[slice].rowPitch;
635
636 size_t size = std::min<size_t>( dpitch, spitch );
637
638 for( size_t y = 0; y < rowCount; ++y )
639 {
640 memcpy_s( dptr, dpitch, sptr, size );
641 sptr += spitch;
642 dptr += dpitch;
643 }
644 }
645
646 return S_OK;
647 }
648
Release()649 void ScratchImage::Release()
650 {
651 _nimages = 0;
652 _size = 0;
653
654 if ( _image )
655 {
656 delete [] _image;
657 _image = 0;
658 }
659
660 if ( _memory )
661 {
662 _aligned_free( _memory );
663 _memory = 0;
664 }
665
666 memset(&_metadata, 0, sizeof(_metadata));
667 }
668
669 _Use_decl_annotations_
OverrideFormat(DXGI_FORMAT f)670 bool ScratchImage::OverrideFormat( DXGI_FORMAT f )
671 {
672 if ( !_image )
673 return false;
674
675 if ( !IsValid( f ) || IsPlanar( f ) || IsPalettized( f ) )
676 return false;
677
678 for( size_t index = 0; index < _nimages; ++index )
679 {
680 _image[ index ].format = f;
681 }
682
683 _metadata.format = f;
684
685 return true;
686 }
687
688 _Use_decl_annotations_
GetImage(size_t mip,size_t item,size_t slice) const689 const Image* ScratchImage::GetImage(size_t mip, size_t item, size_t slice) const
690 {
691 if ( mip >= _metadata.mipLevels )
692 return nullptr;
693
694 size_t index = 0;
695
696 switch( _metadata.dimension )
697 {
698 case TEX_DIMENSION_TEXTURE1D:
699 case TEX_DIMENSION_TEXTURE2D:
700 if ( slice > 0 )
701 return nullptr;
702
703 if ( item >= _metadata.arraySize )
704 return nullptr;
705
706 index = item*( _metadata.mipLevels ) + mip;
707 break;
708
709 case TEX_DIMENSION_TEXTURE3D:
710 if ( item > 0 )
711 {
712 // No support for arrays of volumes
713 return nullptr;
714 }
715 else
716 {
717 size_t d = _metadata.depth;
718
719 for( size_t level = 0; level < mip; ++level )
720 {
721 index += d;
722 if ( d > 1 )
723 d >>= 1;
724 }
725
726 if ( slice >= d )
727 return nullptr;
728
729 index += slice;
730 }
731 break;
732
733 default:
734 return nullptr;
735 }
736
737 return &_image[index];
738 }
739
IsAlphaAllOpaque() const740 bool ScratchImage::IsAlphaAllOpaque() const
741 {
742 if ( !_image )
743 return false;
744
745 if ( !HasAlpha( _metadata.format ) )
746 return true;
747
748 if ( IsCompressed( _metadata.format ) )
749 {
750 for( size_t index = 0; index < _nimages; ++index )
751 {
752 if ( !_IsAlphaAllOpaqueBC( _image[ index ] ) )
753 return false;
754 }
755 }
756 else
757 {
758 ScopedAlignedArrayXMVECTOR scanline( reinterpret_cast<XMVECTOR*>( _aligned_malloc( (sizeof(XMVECTOR)*_metadata.width), 16 ) ) );
759 if ( !scanline )
760 return false;
761
762 static const XMVECTORF32 threshold = { 0.99f, 0.99f, 0.99f, 0.99f };
763
764 for( size_t index = 0; index < _nimages; ++index )
765 {
766 #pragma warning( suppress : 6011 )
767 const Image& img = _image[ index ];
768
769 const uint8_t *pPixels = img.pixels;
770 assert( pPixels );
771
772 for( size_t h = 0; h < img.height; ++h )
773 {
774 if ( !_LoadScanline( scanline.get(), img.width, pPixels, img.rowPitch, img.format ) )
775 return false;
776
777 XMVECTOR* ptr = scanline.get();
778 for( size_t w = 0; w < img.width; ++w )
779 {
780 XMVECTOR alpha = XMVectorSplatW( *ptr );
781 if ( XMVector4Less( alpha, threshold ) )
782 return false;
783 ++ptr;
784 }
785
786 pPixels += img.rowPitch;
787 }
788 }
789 }
790
791 return true;
792 }
793
794 }; // namespace
795