20 using Microsoft::WRL::ComPtr;
30 _In_
size_t newWidth, _In_
size_t newHeight, _In_ DWORD filter, _Inout_
const Image* img );
34 _In_
const WICPixelFormatGUID& pfGUID, _In_
const Image& destImage )
36 if ( !srcImage.pixels || !destImage.pixels )
39 assert( srcImage.format == destImage.format );
41 IWICImagingFactory* pWIC =
_GetWIC();
45 ComPtr<IWICComponentInfo> componentInfo;
46 HRESULT hr = pWIC->CreateComponentInfo( pfGUID, componentInfo.GetAddressOf() );
50 ComPtr<IWICPixelFormatInfo2> pixelFormatInfo;
51 hr = componentInfo.As( &pixelFormatInfo );
55 BOOL supportsTransparency = FALSE;
56 hr = pixelFormatInfo->SupportsTransparency( &supportsTransparency );
60 ComPtr<IWICBitmap> source;
61 hr = pWIC->CreateBitmapFromMemory( static_cast<UINT>( srcImage.width ), static_cast<UINT>( srcImage.height ), pfGUID,
62 static_cast<UINT>( srcImage.rowPitch ), static_cast<UINT>( srcImage.slicePitch ),
63 srcImage.pixels, source.GetAddressOf() );
75 ComPtr<IWICBitmapScaler> scaler;
76 hr = pWIC->CreateBitmapScaler( scaler.GetAddressOf() );
80 hr = scaler->Initialize( source.Get(),
static_cast<UINT
>( destImage.width ), static_cast<UINT>( destImage.height ),
_GetWICInterp( filter ) );
84 WICPixelFormatGUID pfScaler;
85 hr = scaler->GetPixelFormat( &pfScaler );
89 if ( memcmp( &pfScaler, &pfGUID,
sizeof(WICPixelFormatGUID) ) == 0 )
91 hr = scaler->CopyPixels( 0, static_cast<UINT>( destImage.rowPitch ), static_cast<UINT>( destImage.slicePitch ), destImage.pixels );
99 ComPtr<IWICFormatConverter> FC;
100 hr = pWIC->CreateFormatConverter( FC.GetAddressOf() );
104 hr = FC->Initialize( scaler.Get(), pfGUID,
_GetWICDither( filter ), 0, 0, WICBitmapPaletteTypeCustom );
108 hr = FC->CopyPixels( 0, static_cast<UINT>( destImage.rowPitch ), static_cast<UINT>( destImage.slicePitch ), destImage.pixels );
121 if ( !srcImage.pixels || !destImage.pixels )
124 assert( srcImage.format != DXGI_FORMAT_R32G32B32A32_FLOAT );
125 assert( srcImage.format == destImage.format );
137 hr = rtemp.
Initialize2D( DXGI_FORMAT_R32G32B32A32_FLOAT, destImage.width, destImage.height, 1, 1 );
180 static_assert(
TEX_FILTER_POINT == 0x100000,
"TEX_FILTER_ flag values don't match TEX_FILTER_MASK" );
228 assert( srcImage.pixels && destImage.pixels );
229 assert( srcImage.format == destImage.format );
233 (
sizeof(XMVECTOR) * (srcImage.width + destImage.width ) ), 16 ) ) );
235 return E_OUTOFMEMORY;
237 XMVECTOR* target = scanline.get();
239 XMVECTOR* row = target + destImage.width;
242 memset( row, 0xCD,
sizeof(XMVECTOR)*srcImage.width );
245 const uint8_t* pSrc = srcImage.pixels;
246 uint8_t* pDest = destImage.pixels;
248 size_t rowPitch = srcImage.rowPitch;
250 size_t xinc = ( srcImage.width << 16 ) / destImage.width;
251 size_t yinc = ( srcImage.height << 16 ) / destImage.height;
253 size_t lasty = size_t(-1);
256 for(
size_t y = 0;
y < destImage.height; ++
y )
258 if ( (lasty ^ sy) >> 16 )
260 if ( !
_LoadScanline( row, srcImage.width, pSrc + ( rowPitch * (sy >> 16) ), rowPitch, srcImage.format ) )
266 for(
size_t x = 0; x < destImage.width; ++x )
268 target[ x ] = row[ sx >> 16 ];
272 if ( !
_StoreScanline( pDest, destImage.rowPitch, destImage.format, target, destImage.width ) )
274 pDest += destImage.rowPitch;
286 assert( srcImage.pixels && destImage.pixels );
287 assert( srcImage.format == destImage.format );
289 if ( ( (destImage.width << 1) != srcImage.width ) || ( (destImage.height << 1) != srcImage.height ) )
294 (
sizeof(XMVECTOR) * ( srcImage.width*2 + destImage.width ) ), 16 ) ) );
296 return E_OUTOFMEMORY;
298 XMVECTOR* target = scanline.get();
300 XMVECTOR* urow0 = target + destImage.width;
301 XMVECTOR* urow1 = urow0 + srcImage.width;
304 memset( urow0, 0xCD,
sizeof(XMVECTOR)*srcImage.width );
305 memset( urow1, 0xDD,
sizeof(XMVECTOR)*srcImage.width );
308 const XMVECTOR* urow2 = urow0 + 1;
309 const XMVECTOR* urow3 = urow1 + 1;
311 const uint8_t* pSrc = srcImage.pixels;
312 uint8_t* pDest = destImage.pixels;
314 size_t rowPitch = srcImage.rowPitch;
316 for(
size_t y = 0;
y < destImage.height; ++
y )
318 if ( !
_LoadScanlineLinear( urow0, srcImage.width, pSrc, rowPitch, srcImage.format, filter ) )
322 if ( urow0 != urow1 )
324 if ( !
_LoadScanlineLinear( urow1, srcImage.width, pSrc, rowPitch, srcImage.format, filter ) )
329 for(
size_t x = 0; x < destImage.width; ++x )
333 AVERAGE4( target[ x ], urow0[ x2 ], urow1[ x2 ], urow2[ x2 ], urow3[ x2 ] );
336 if ( !
_StoreScanlineLinear( pDest, destImage.rowPitch, destImage.format, target, destImage.width, filter ) )
338 pDest += destImage.rowPitch;
348 assert( srcImage.pixels && destImage.pixels );
349 assert( srcImage.format == destImage.format );
353 (
sizeof(XMVECTOR) * ( srcImage.width*2 + destImage.width ) ), 16 ) ) );
355 return E_OUTOFMEMORY;
357 std::unique_ptr<LinearFilter[]> lf(
new (std::nothrow)
LinearFilter[ destImage.width + destImage.height ] );
359 return E_OUTOFMEMORY;
367 XMVECTOR* target = scanline.get();
369 XMVECTOR* row0 = target + destImage.width;
370 XMVECTOR* row1 = row0 + srcImage.width;
373 memset( row0, 0xCD,
sizeof(XMVECTOR)*srcImage.width );
374 memset( row1, 0xDD,
sizeof(XMVECTOR)*srcImage.width );
377 const uint8_t* pSrc = srcImage.pixels;
378 uint8_t* pDest = destImage.pixels;
380 size_t rowPitch = srcImage.rowPitch;
382 size_t u0 = size_t(-1);
383 size_t u1 = size_t(-1);
385 for(
size_t y = 0;
y < destImage.height; ++
y )
387 auto& toY = lfY[
y ];
395 if ( !
_LoadScanlineLinear( row0, srcImage.width, pSrc + (rowPitch * u0), rowPitch, srcImage.format, filter ) )
403 std::swap( row0, row1 );
411 if ( !
_LoadScanlineLinear( row1, srcImage.width, pSrc + (rowPitch * u1), rowPitch, srcImage.format, filter ) )
415 for(
size_t x = 0; x < destImage.width; ++x )
417 auto& toX = lfX[ x ];
422 if ( !
_StoreScanlineLinear( pDest, destImage.rowPitch, destImage.format, target, destImage.width, filter ) )
424 pDest += destImage.rowPitch;
434 assert( srcImage.pixels && destImage.pixels );
435 assert( srcImage.format == destImage.format );
439 (
sizeof(XMVECTOR) * ( srcImage.width*4 + destImage.width ) ), 16 ) ) );
441 return E_OUTOFMEMORY;
443 std::unique_ptr<CubicFilter[]> cf(
new (std::nothrow)
CubicFilter[ destImage.width + destImage.height ] );
445 return E_OUTOFMEMORY;
453 XMVECTOR* target = scanline.get();
455 XMVECTOR* row0 = target + destImage.width;
456 XMVECTOR* row1 = row0 + srcImage.width;
457 XMVECTOR* row2 = row0 + srcImage.width*2;
458 XMVECTOR* row3 = row0 + srcImage.width*3;
461 memset( row0, 0xCD,
sizeof(XMVECTOR)*srcImage.width );
462 memset( row1, 0xDD,
sizeof(XMVECTOR)*srcImage.width );
463 memset( row2, 0xED,
sizeof(XMVECTOR)*srcImage.width );
464 memset( row3, 0xFD,
sizeof(XMVECTOR)*srcImage.width );
467 const uint8_t* pSrc = srcImage.pixels;
468 uint8_t* pDest = destImage.pixels;
470 size_t rowPitch = srcImage.rowPitch;
472 size_t u0 = size_t(-1);
473 size_t u1 = size_t(-1);
474 size_t u2 = size_t(-1);
475 size_t u3 = size_t(-1);
477 for(
size_t y = 0;
y < destImage.height; ++
y )
479 auto& toY = cfY[
y ];
484 if ( toY.u0 != u1 && toY.u0 != u2 && toY.u0 != u3 )
488 if ( !
_LoadScanlineLinear( row0, srcImage.width, pSrc + (rowPitch * u0), rowPitch, srcImage.format, filter ) )
491 else if ( toY.u0 == u1 )
496 std::swap( row0, row1 );
498 else if ( toY.u0 == u2 )
503 std::swap( row0, row2 );
505 else if ( toY.u0 == u3 )
510 std::swap( row0, row3 );
517 if ( toY.u1 != u2 && toY.u1 != u3 )
521 if ( !
_LoadScanlineLinear( row1, srcImage.width, pSrc + (rowPitch * u1), rowPitch, srcImage.format, filter ) )
524 else if ( toY.u1 == u2 )
529 std::swap( row1, row2 );
531 else if ( toY.u1 == u3 )
536 std::swap( row1, row3 );
547 if ( !
_LoadScanlineLinear( row2, srcImage.width, pSrc + (rowPitch * u2), rowPitch, srcImage.format, filter ) )
555 std::swap( row2, row3 );
564 if ( !
_LoadScanlineLinear( row3, srcImage.width, pSrc + (rowPitch * u3), rowPitch, srcImage.format, filter ) )
568 for(
size_t x = 0; x < destImage.width; ++x )
570 auto& toX = cfX[ x ];
572 XMVECTOR C0, C1, C2, C3;
574 CUBIC_INTERPOLATE( C0, toX.x, row0[ toX.u0 ], row0[ toX.u1 ], row0[ toX.u2 ], row0[ toX.u3 ] );
575 CUBIC_INTERPOLATE( C1, toX.x, row1[ toX.u0 ], row1[ toX.u1 ], row1[ toX.u2 ], row1[ toX.u3 ] );
576 CUBIC_INTERPOLATE( C2, toX.x, row2[ toX.u0 ], row2[ toX.u1 ], row2[ toX.u2 ], row2[ toX.u3 ] );
577 CUBIC_INTERPOLATE( C3, toX.x, row3[ toX.u0 ], row3[ toX.u1 ], row3[ toX.u2 ], row3[ toX.u3 ] );
582 if ( !
_StoreScanlineLinear( pDest, destImage.rowPitch, destImage.format, target, destImage.width, filter ) )
584 pDest += destImage.rowPitch;
594 assert( srcImage.pixels && destImage.pixels );
595 assert( srcImage.format == destImage.format );
597 using namespace TriangleFilter;
600 ScopedAlignedArrayXMVECTOR scanline( reinterpret_cast<XMVECTOR*>( _aligned_malloc(
sizeof(XMVECTOR) * srcImage.width, 16 ) ) );
602 return E_OUTOFMEMORY;
604 std::unique_ptr<TriangleRow[]> rowActive(
new (std::nothrow) TriangleRow[ destImage.height ] );
606 return E_OUTOFMEMORY;
608 TriangleRow * rowFree =
nullptr;
610 std::unique_ptr<Filter> tfX;
615 std::unique_ptr<Filter> tfY;
620 XMVECTOR* row = scanline.get();
623 memset( row, 0xCD,
sizeof(XMVECTOR)*srcImage.width );
626 auto xFromEnd =
reinterpret_cast<const FilterFrom*
>(
reinterpret_cast<const uint8_t*
>( tfX.get() ) + tfX->sizeInBytes );
627 auto yFromEnd =
reinterpret_cast<const FilterFrom*
>(
reinterpret_cast<const uint8_t*
>( tfY.get() ) + tfY->sizeInBytes );
630 for( FilterFrom* yFrom = tfY->from; yFrom < yFromEnd; )
632 for (
size_t j = 0; j < yFrom->count; ++j )
634 size_t v = yFrom->to[ j ].u;
635 assert( v < destImage.height );
636 ++rowActive.get()[ v ].remaining;
639 yFrom =
reinterpret_cast<FilterFrom*
>(
reinterpret_cast<uint8_t*
>( yFrom ) + yFrom->sizeInBytes );
643 const uint8_t* pSrc = srcImage.pixels;
644 size_t rowPitch = srcImage.rowPitch;
645 const uint8_t* pEndSrc = pSrc + rowPitch * srcImage.height;
647 uint8_t* pDest = destImage.pixels;
649 for( FilterFrom* yFrom = tfY->from; yFrom < yFromEnd; )
652 for (
size_t j = 0; j < yFrom->count; ++j )
654 size_t v = yFrom->to[ j ].u;
655 assert( v < destImage.height );
656 TriangleRow* rowAcc = &rowActive.get()[ v ];
658 if ( !rowAcc->scanline )
663 assert( rowFree->scanline != 0 );
664 rowAcc->scanline.reset( rowFree->scanline.release() );
665 rowFree = rowFree->next;
669 rowAcc->scanline.reset( reinterpret_cast<XMVECTOR*>( _aligned_malloc(
sizeof(XMVECTOR) * destImage.width, 16 ) ) );
670 if ( !rowAcc->scanline )
671 return E_OUTOFMEMORY;
674 memset( rowAcc->scanline.get(), 0,
sizeof(XMVECTOR) * destImage.width );
679 if ( (pSrc + rowPitch) > pEndSrc )
682 if ( !
_LoadScanlineLinear( row, srcImage.width, pSrc, rowPitch, srcImage.format, filter ) )
689 for( FilterFrom* xFrom = tfX->from; xFrom < xFromEnd; ++x )
691 for (
size_t j = 0; j < yFrom->count; ++j )
693 size_t v = yFrom->to[ j ].u;
694 assert( v < destImage.height );
695 float yweight = yFrom->to[ j ].weight;
697 XMVECTOR* accPtr = rowActive[ v ].scanline.get();
701 for (
size_t k = 0; k < xFrom->count; ++k )
703 size_t u = xFrom->to[ k ].u;
704 assert( u < destImage.width );
706 XMVECTOR weight = XMVectorReplicate( yweight * xFrom->to[ k ].weight );
708 assert( x < srcImage.width );
709 accPtr[ u ] = XMVectorMultiplyAdd( row[ x ], weight, accPtr[ u ] );
713 xFrom =
reinterpret_cast<FilterFrom*
>(
reinterpret_cast<uint8_t*
>( xFrom ) + xFrom->sizeInBytes );
717 for (
size_t j = 0; j < yFrom->count; ++j )
719 size_t v = yFrom->to[ j ].u;
720 assert( v < destImage.height );
721 TriangleRow* rowAcc = &rowActive.get()[ v ];
723 assert( rowAcc->remaining > 0 );
726 if ( !rowAcc->remaining )
728 XMVECTOR* pAccSrc = rowAcc->scanline.get();
732 switch( destImage.format )
734 case DXGI_FORMAT_R10G10B10A2_UNORM:
735 case DXGI_FORMAT_R10G10B10A2_UINT:
739 static const XMVECTORF32 Bias = { 0.f, 0.f, 0.f, 0.1f };
741 XMVECTOR* ptr = pAccSrc;
742 for(
size_t i=0; i < destImage.width; ++i, ++ptr )
744 *ptr = XMVectorAdd( *ptr, Bias );
751 if ( !
_StoreScanlineLinear( pDest + (destImage.rowPitch * v), destImage.rowPitch, destImage.format, pAccSrc, destImage.width, filter ) )
755 rowAcc->next = rowFree;
760 yFrom =
reinterpret_cast<FilterFrom*
>(
reinterpret_cast<uint8_t*
>( yFrom ) + yFrom->sizeInBytes );
770 if ( !srcImage.pixels || !destImage.pixels )
773 static_assert(
TEX_FILTER_POINT == 0x100000,
"TEX_FILTER_ flag values don't match TEX_FILTER_MASK" );
776 if ( !filter_select )
779 filter_select = ( ( (destImage.width << 1) == srcImage.width ) && ( (destImage.height << 1) == srcImage.height ) )
783 switch( filter_select )
801 return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
813 _Use_decl_annotations_
816 if ( width == 0 || height == 0 )
820 if ( (srcImage.
width > 0xFFFFFFFF) || (srcImage.
height > 0xFFFFFFFF) )
823 if ( (width > 0xFFFFFFFF) || (height > 0xFFFFFFFF) )
833 return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
846 WICPixelFormatGUID pfGUID;
876 _Use_decl_annotations_
878 size_t width,
size_t height, DWORD filter,
ScratchImage& result )
880 if ( !srcImages || !nimages || width == 0 || height == 0 )
884 if ( (width > 0xFFFFFFFF) || (height > 0xFFFFFFFF) )
889 mdata2.
width = width;
898 WICPixelFormatGUID pfGUID = {0};
899 bool wicpf = ( usewic ) ?
_DXGIToWIC( metadata.
format, pfGUID,
true ) :
false;
907 for(
size_t item = 0; item < metadata.
arraySize; ++item )
910 if ( srcIndex >= nimages )
916 const Image* srcimg = &srcImages[ srcIndex ];
918 if ( !srcimg || !destimg )
931 if ( (srcimg->
width > 0xFFFFFFFF) || (srcimg->
height > 0xFFFFFFFF) )
968 for(
size_t slice = 0; slice < metadata.
depth; ++slice )
971 if ( srcIndex >= nimages )
977 const Image* srcimg = &srcImages[ srcIndex ];
979 if ( !srcimg || !destimg )
992 if ( (srcimg->
width > 0xFFFFFFFF) || (srcimg->
height > 0xFFFFFFFF) )
std::unique_ptr< DirectX::XMVECTOR, aligned_deleter > ScopedAlignedArrayXMVECTOR
const Image * GetImage(_In_ size_t mip, _In_ size_t item, _In_ size_t slice) const
static HRESULT _PerformResizeViaF32(_In_ const Image &srcImage, _In_ DWORD filter, _In_ const Image &destImage)
size_t BitsPerColor(_In_ DXGI_FORMAT fmt)
HRESULT Resize(_In_ const Image &srcImage, _In_ size_t width, _In_ size_t height, _In_ DWORD filter, _Out_ ScratchImage &image)
static HRESULT _ResizePointFilter(_In_ const Image &srcImage, _In_ const Image &destImage)
_Use_decl_annotations_ HRESULT _ConvertFromR32G32B32A32(const Image &srcImage, const Image &destImage)
_Use_decl_annotations_ HRESULT _ConvertToR32G32B32A32(const Image &srcImage, ScratchImage &image)
size_t _In_ DXGI_FORMAT size_t _In_ TEXP_LEGACY_FORMAT _In_ DWORD flags assert(pDestination &&outSize > 0)
static HRESULT _PerformResizeUsingCustomFilters(_In_ const Image &srcImage, _In_ DWORD filter, _In_ const Image &destImage)
_In_ size_t _In_ DXGI_FORMAT _In_ size_t _In_ float size_t y
HRESULT Initialize(_In_ const TexMetadata &mdata, _In_ DWORD flags=CP_FLAGS_NONE)
HRESULT Initialize2D(_In_ DXGI_FORMAT fmt, _In_ size_t width, _In_ size_t height, _In_ size_t arraySize, _In_ size_t mipLevels, _In_ DWORD flags=CP_FLAGS_NONE)
_Use_decl_annotations_ bool _LoadScanline(XMVECTOR *pDestination, size_t count, LPCVOID pSource, size_t size, DXGI_FORMAT format)
#define CUBIC_INTERPOLATE(res, dx, p0, p1, p2, p3)
void _CreateCubicFilter(_In_ size_t source, _In_ size_t dest, _In_ bool wrap, _In_ bool mirror, _Out_writes_(dest) CubicFilter *cf)
IWICImagingFactory * _GetWIC()
static HRESULT _ResizeCubicFilter(_In_ const Image &srcImage, _In_ DWORD filter, _In_ const Image &destImage)
bool IsCompressed(_In_ DXGI_FORMAT fmt)
_In_ size_t _In_ const TexMetadata & metadata
HRESULT _Create(_In_ size_t source, _In_ size_t dest, _In_ bool wrap, _Inout_ std::unique_ptr< Filter > &tf)
static HRESULT _PerformResizeUsingWIC(_In_ const Image &srcImage, _In_ DWORD filter, _In_ const WICPixelFormatGUID &pfGUID, _In_ const Image &destImage)
static HRESULT _ResizeTriangleFilter(_In_ const Image &srcImage, _In_ DWORD filter, _In_ const Image &destImage)
WICBitmapDitherType _GetWICDither(_In_ DWORD flags)
_Use_decl_annotations_ bool _LoadScanlineLinear(XMVECTOR *pDestination, size_t count, LPCVOID pSource, size_t size, DXGI_FORMAT format, DWORD flags)
_Use_decl_annotations_ bool _StoreScanlineLinear(LPVOID pDestination, size_t size, DXGI_FORMAT format, XMVECTOR *pSource, size_t count, DWORD flags)
static HRESULT _ResizeBoxFilter(_In_ const Image &srcImage, _In_ DWORD filter, _In_ const Image &destImage)
bool IsSRGB(_In_ DXGI_FORMAT fmt)
#define BILINEAR_INTERPOLATE(res, x, y, r0, r1)
_In_ size_t _In_ size_t _In_ DXGI_FORMAT format
static bool _UseWICFiltering(_In_ DXGI_FORMAT format, _In_ DWORD filter)
static HRESULT _ResizeLinearFilter(_In_ const Image &srcImage, _In_ DWORD filter, _In_ const Image &destImage)
bool _DXGIToWIC(_In_ DXGI_FORMAT format, _Out_ GUID &guid, _In_ bool ignoreRGBvsBGR=false)
HRESULT _ResizeSeparateColorAndAlpha(_In_ IWICImagingFactory *pWIC, _In_ IWICBitmap *original, _In_ size_t newWidth, _In_ size_t newHeight, _In_ DWORD filter, _Inout_ const Image *img)
#define AVERAGE4(res, p0, p1, p2, p3)
_Use_decl_annotations_ bool _StoreScanline(LPVOID pDestination, size_t size, DXGI_FORMAT format, const XMVECTOR *pSource, size_t count, float threshold)
void _CreateLinearFilter(_In_ size_t source, _In_ size_t dest, _In_ bool wrap, _Out_writes_(dest) LinearFilter *lf)
WICBitmapInterpolationMode _GetWICInterp(_In_ DWORD flags)