2016-08-22 18:26:36 +00:00
//-------------------------------------------------------------------------------------
// DirectXTexFlipRotate.cpp
//
// DirectX Texture Library - Image flip/rotate operations
//
// Copyright (c) Microsoft Corporation. All rights reserved.
2018-02-24 06:24:46 +00:00
// Licensed under the MIT License.
2016-08-22 18:26:36 +00:00
//
// http://go.microsoft.com/fwlink/?LinkId=248926
//-------------------------------------------------------------------------------------
2019-05-25 23:00:32 +00:00
# include "DirectXTexP.h"
2016-08-22 18:26:36 +00:00
2016-09-09 02:09:46 +00:00
using namespace DirectX ;
2016-08-22 18:26:36 +00:00
using Microsoft : : WRL : : ComPtr ;
2016-09-09 02:09:46 +00:00
namespace
2016-08-22 18:26:36 +00:00
{
2016-09-09 02:09:46 +00:00
//-------------------------------------------------------------------------------------
// Do flip/rotate operation using WIC
//-------------------------------------------------------------------------------------
HRESULT PerformFlipRotateUsingWIC (
const Image & srcImage ,
DWORD flags ,
const WICPixelFormatGUID & pfGUID ,
2019-12-13 08:01:17 +00:00
const Image & destImage ) noexcept
2016-09-09 02:09:46 +00:00
{
if ( ! srcImage . pixels | | ! destImage . pixels )
return E_POINTER ;
2016-08-22 18:26:36 +00:00
2016-09-09 02:09:46 +00:00
assert ( srcImage . format = = destImage . format ) ;
2016-08-22 18:26:36 +00:00
2016-09-09 02:09:46 +00:00
bool iswic2 = false ;
2020-01-24 16:55:54 +00:00
auto pWIC = GetWICFactory ( iswic2 ) ;
2016-09-09 02:09:46 +00:00
if ( ! pWIC )
return E_NOINTERFACE ;
2016-08-22 18:26:36 +00:00
2018-07-27 08:02:56 +00:00
if ( srcImage . rowPitch > UINT32_MAX | | srcImage . slicePitch > UINT32_MAX
| | destImage . rowPitch > UINT32_MAX | | destImage . slicePitch > UINT32_MAX )
return HRESULT_FROM_WIN32 ( ERROR_ARITHMETIC_OVERFLOW ) ;
2016-09-09 02:09:46 +00:00
ComPtr < IWICBitmap > source ;
HRESULT hr = pWIC - > CreateBitmapFromMemory ( static_cast < UINT > ( srcImage . width ) , static_cast < UINT > ( srcImage . height ) , pfGUID ,
static_cast < UINT > ( srcImage . rowPitch ) , static_cast < UINT > ( srcImage . slicePitch ) ,
srcImage . pixels , source . GetAddressOf ( ) ) ;
if ( FAILED ( hr ) )
return hr ;
2016-08-22 18:26:36 +00:00
2016-09-09 02:09:46 +00:00
ComPtr < IWICBitmapFlipRotator > FR ;
hr = pWIC - > CreateBitmapFlipRotator ( FR . GetAddressOf ( ) ) ;
if ( FAILED ( hr ) )
return hr ;
2016-08-22 18:26:36 +00:00
2016-09-09 02:09:46 +00:00
hr = FR - > Initialize ( source . Get ( ) , static_cast < WICBitmapTransformOptions > ( flags ) ) ;
if ( FAILED ( hr ) )
return hr ;
2016-08-22 18:26:36 +00:00
2016-09-09 02:09:46 +00:00
WICPixelFormatGUID pfFR ;
hr = FR - > GetPixelFormat ( & pfFR ) ;
if ( FAILED ( hr ) )
return hr ;
2016-08-22 18:26:36 +00:00
2016-09-09 02:09:46 +00:00
if ( memcmp ( & pfFR , & pfGUID , sizeof ( GUID ) ) ! = 0 )
{
// Flip/rotate should return the same format as the source...
return HRESULT_FROM_WIN32 ( ERROR_NOT_SUPPORTED ) ;
}
2016-08-22 18:26:36 +00:00
2016-09-09 02:09:46 +00:00
UINT nwidth , nheight ;
hr = FR - > GetSize ( & nwidth , & nheight ) ;
if ( FAILED ( hr ) )
return hr ;
2016-08-22 18:26:36 +00:00
2016-09-09 02:09:46 +00:00
if ( destImage . width ! = nwidth | | destImage . height ! = nheight )
return E_FAIL ;
2016-08-22 18:26:36 +00:00
2018-06-11 19:22:52 +00:00
hr = FR - > CopyPixels ( nullptr , static_cast < UINT > ( destImage . rowPitch ) , static_cast < UINT > ( destImage . slicePitch ) , destImage . pixels ) ;
2016-09-09 02:09:46 +00:00
if ( FAILED ( hr ) )
return hr ;
2016-08-22 18:26:36 +00:00
2016-09-09 02:09:46 +00:00
return S_OK ;
}
2016-08-22 18:26:36 +00:00
2016-09-09 02:09:46 +00:00
//-------------------------------------------------------------------------------------
// Do conversion, flip/rotate using WIC, conversion cycle
2018-08-02 19:31:20 +00:00
//
// For large images we have to use F16 instead of F32 to avoid exceeding the 32-bit
// memory limitations of WIC.
2016-09-09 02:09:46 +00:00
//-------------------------------------------------------------------------------------
2018-08-02 19:31:20 +00:00
HRESULT PerformFlipRotateViaF16 (
const Image & srcImage ,
DWORD flags ,
2019-12-13 08:01:17 +00:00
const Image & destImage ) noexcept
2018-08-02 19:31:20 +00:00
{
if ( ! srcImage . pixels | | ! destImage . pixels )
return E_POINTER ;
assert ( srcImage . format ! = DXGI_FORMAT_R16G16B16A16_FLOAT ) ;
assert ( srcImage . format = = destImage . format ) ;
ScratchImage temp ;
HRESULT hr = _ConvertToR16G16B16A16 ( srcImage , temp ) ;
if ( FAILED ( hr ) )
return hr ;
const Image * tsrc = temp . GetImage ( 0 , 0 , 0 ) ;
if ( ! tsrc )
return E_POINTER ;
ScratchImage rtemp ;
hr = rtemp . Initialize2D ( DXGI_FORMAT_R16G16B16A16_FLOAT , destImage . width , destImage . height , 1 , 1 ) ;
if ( FAILED ( hr ) )
return hr ;
const Image * tdest = rtemp . GetImage ( 0 , 0 , 0 ) ;
if ( ! tdest )
return E_POINTER ;
hr = PerformFlipRotateUsingWIC ( * tsrc , flags , GUID_WICPixelFormat64bppRGBAHalf , * tdest ) ;
if ( FAILED ( hr ) )
return hr ;
temp . Release ( ) ;
hr = _ConvertFromR16G16B16A16 ( * tdest , destImage ) ;
if ( FAILED ( hr ) )
return hr ;
return S_OK ;
}
2016-09-09 02:09:46 +00:00
HRESULT PerformFlipRotateViaF32 (
const Image & srcImage ,
DWORD flags ,
2019-12-13 08:01:17 +00:00
const Image & destImage ) noexcept
2016-09-09 02:09:46 +00:00
{
if ( ! srcImage . pixels | | ! destImage . pixels )
return E_POINTER ;
2016-08-22 18:26:36 +00:00
2016-09-09 02:09:46 +00:00
assert ( srcImage . format ! = DXGI_FORMAT_R32G32B32A32_FLOAT ) ;
assert ( srcImage . format = = destImage . format ) ;
2016-08-22 18:26:36 +00:00
2016-09-09 02:09:46 +00:00
ScratchImage temp ;
HRESULT hr = _ConvertToR32G32B32A32 ( srcImage , temp ) ;
if ( FAILED ( hr ) )
return hr ;
2016-08-22 18:26:36 +00:00
2016-09-09 02:09:46 +00:00
const Image * tsrc = temp . GetImage ( 0 , 0 , 0 ) ;
if ( ! tsrc )
return E_POINTER ;
2016-08-22 18:26:36 +00:00
2016-09-09 02:09:46 +00:00
ScratchImage rtemp ;
hr = rtemp . Initialize2D ( DXGI_FORMAT_R32G32B32A32_FLOAT , destImage . width , destImage . height , 1 , 1 ) ;
if ( FAILED ( hr ) )
return hr ;
2016-08-22 18:26:36 +00:00
2016-09-09 02:09:46 +00:00
const Image * tdest = rtemp . GetImage ( 0 , 0 , 0 ) ;
if ( ! tdest )
return E_POINTER ;
2016-08-22 18:26:36 +00:00
2016-09-09 02:09:46 +00:00
hr = PerformFlipRotateUsingWIC ( * tsrc , flags , GUID_WICPixelFormat128bppRGBAFloat , * tdest ) ;
if ( FAILED ( hr ) )
return hr ;
2016-08-22 18:26:36 +00:00
2016-09-09 02:09:46 +00:00
temp . Release ( ) ;
2016-08-22 18:26:36 +00:00
2016-09-09 02:09:46 +00:00
hr = _ConvertFromR32G32B32A32 ( * tdest , destImage ) ;
if ( FAILED ( hr ) )
return hr ;
2016-08-22 18:26:36 +00:00
2016-09-09 02:09:46 +00:00
return S_OK ;
}
2016-08-22 18:26:36 +00:00
}
//=====================================================================================
// Entry-points
//=====================================================================================
//-------------------------------------------------------------------------------------
// Flip/rotate image
//-------------------------------------------------------------------------------------
_Use_decl_annotations_
2016-09-09 02:09:46 +00:00
HRESULT DirectX : : FlipRotate (
const Image & srcImage ,
DWORD flags ,
2019-12-13 08:01:17 +00:00
ScratchImage & image ) noexcept
2016-08-22 18:26:36 +00:00
{
2016-09-09 02:09:46 +00:00
if ( ! srcImage . pixels )
2016-08-22 18:26:36 +00:00
return E_POINTER ;
2016-09-09 02:09:46 +00:00
if ( ! flags )
2016-08-22 18:26:36 +00:00
return E_INVALIDARG ;
2016-09-09 02:09:46 +00:00
if ( ( srcImage . width > UINT32_MAX ) | | ( srcImage . height > UINT32_MAX ) )
2016-08-22 18:26:36 +00:00
return E_INVALIDARG ;
2016-09-09 02:09:46 +00:00
if ( IsCompressed ( srcImage . format ) )
2016-08-22 18:26:36 +00:00
{
// We don't support flip/rotate operations on compressed images
2016-09-09 02:09:46 +00:00
return HRESULT_FROM_WIN32 ( ERROR_NOT_SUPPORTED ) ;
2016-08-22 18:26:36 +00:00
}
2017-07-12 07:56:51 +00:00
static_assert ( static_cast < int > ( TEX_FR_ROTATE0 ) = = static_cast < int > ( WICBitmapTransformRotate0 ) , " TEX_FR_ROTATE0 no longer matches WIC " ) ;
static_assert ( static_cast < int > ( TEX_FR_ROTATE90 ) = = static_cast < int > ( WICBitmapTransformRotate90 ) , " TEX_FR_ROTATE90 no longer matches WIC " ) ;
static_assert ( static_cast < int > ( TEX_FR_ROTATE180 ) = = static_cast < int > ( WICBitmapTransformRotate180 ) , " TEX_FR_ROTATE180 no longer matches WIC " ) ;
static_assert ( static_cast < int > ( TEX_FR_ROTATE270 ) = = static_cast < int > ( WICBitmapTransformRotate270 ) , " TEX_FR_ROTATE270 no longer matches WIC " ) ;
static_assert ( static_cast < int > ( TEX_FR_FLIP_HORIZONTAL ) = = static_cast < int > ( WICBitmapTransformFlipHorizontal ) , " TEX_FR_FLIP_HORIZONTAL no longer matches WIC " ) ;
static_assert ( static_cast < int > ( TEX_FR_FLIP_VERTICAL ) = = static_cast < int > ( WICBitmapTransformFlipVertical ) , " TEX_FR_FLIP_VERTICAL no longer matches WIC " ) ;
2016-08-22 18:26:36 +00:00
// Only supports 90, 180, 270, or no rotation flags... not a combination of rotation flags
2018-08-17 23:58:12 +00:00
int rotateMode = static_cast < int > ( flags & ( TEX_FR_ROTATE0 | TEX_FR_ROTATE90 | TEX_FR_ROTATE180 | TEX_FR_ROTATE270 ) ) ;
switch ( rotateMode )
2016-08-22 18:26:36 +00:00
{
case 0 :
case TEX_FR_ROTATE90 :
case TEX_FR_ROTATE180 :
case TEX_FR_ROTATE270 :
break ;
default :
return E_INVALIDARG ;
}
size_t nwidth = srcImage . width ;
size_t nheight = srcImage . height ;
2018-08-17 23:58:12 +00:00
if ( ( rotateMode = = TEX_FR_ROTATE90 ) | | ( rotateMode = = TEX_FR_ROTATE270 ) )
2016-08-22 18:26:36 +00:00
{
nwidth = srcImage . height ;
nheight = srcImage . width ;
}
2016-09-09 02:09:46 +00:00
HRESULT hr = image . Initialize2D ( srcImage . format , nwidth , nheight , 1 , 1 ) ;
if ( FAILED ( hr ) )
2016-08-22 18:26:36 +00:00
return hr ;
2016-09-09 02:09:46 +00:00
const Image * rimage = image . GetImage ( 0 , 0 , 0 ) ;
if ( ! rimage )
2016-09-12 19:01:48 +00:00
{
image . Release ( ) ;
2016-08-22 18:26:36 +00:00
return E_POINTER ;
2016-09-12 19:01:48 +00:00
}
2016-08-22 18:26:36 +00:00
WICPixelFormatGUID pfGUID ;
2016-09-09 02:09:46 +00:00
if ( _DXGIToWIC ( srcImage . format , pfGUID ) )
2016-08-22 18:26:36 +00:00
{
// Case 1: Source format is supported by Windows Imaging Component
2016-09-09 02:09:46 +00:00
hr = PerformFlipRotateUsingWIC ( srcImage , flags , pfGUID , * rimage ) ;
2016-08-22 18:26:36 +00:00
}
else
{
// Case 2: Source format is not supported by WIC, so we have to convert, flip/rotate, and convert back
2018-08-02 19:31:20 +00:00
uint64_t expandedSize = uint64_t ( srcImage . width ) * uint64_t ( srcImage . height ) * sizeof ( float ) * 4 ;
if ( expandedSize > UINT32_MAX )
{
// Image is too large for float32, so have to use float16 instead
hr = PerformFlipRotateViaF16 ( srcImage , flags , * rimage ) ;
}
else
{
hr = PerformFlipRotateViaF32 ( srcImage , flags , * rimage ) ;
}
2016-08-22 18:26:36 +00:00
}
2016-09-09 02:09:46 +00:00
if ( FAILED ( hr ) )
2016-08-22 18:26:36 +00:00
{
image . Release ( ) ;
return hr ;
}
return S_OK ;
}
//-------------------------------------------------------------------------------------
// Flip/rotate image (complex)
//-------------------------------------------------------------------------------------
_Use_decl_annotations_
2016-09-09 02:09:46 +00:00
HRESULT DirectX : : FlipRotate (
const Image * srcImages ,
size_t nimages ,
const TexMetadata & metadata ,
DWORD flags ,
2019-12-13 08:01:17 +00:00
ScratchImage & result ) noexcept
2016-08-22 18:26:36 +00:00
{
2016-09-09 02:09:46 +00:00
if ( ! srcImages | | ! nimages )
2016-08-22 18:26:36 +00:00
return E_INVALIDARG ;
2016-09-09 02:09:46 +00:00
if ( IsCompressed ( metadata . format ) )
2016-08-22 18:26:36 +00:00
{
// We don't support flip/rotate operations on compressed images
2016-09-09 02:09:46 +00:00
return HRESULT_FROM_WIN32 ( ERROR_NOT_SUPPORTED ) ;
2016-08-22 18:26:36 +00:00
}
2017-07-12 07:56:51 +00:00
static_assert ( static_cast < int > ( TEX_FR_ROTATE0 ) = = static_cast < int > ( WICBitmapTransformRotate0 ) , " TEX_FR_ROTATE0 no longer matches WIC " ) ;
static_assert ( static_cast < int > ( TEX_FR_ROTATE90 ) = = static_cast < int > ( WICBitmapTransformRotate90 ) , " TEX_FR_ROTATE90 no longer matches WIC " ) ;
static_assert ( static_cast < int > ( TEX_FR_ROTATE180 ) = = static_cast < int > ( WICBitmapTransformRotate180 ) , " TEX_FR_ROTATE180 no longer matches WIC " ) ;
static_assert ( static_cast < int > ( TEX_FR_ROTATE270 ) = = static_cast < int > ( WICBitmapTransformRotate270 ) , " TEX_FR_ROTATE270 no longer matches WIC " ) ;
static_assert ( static_cast < int > ( TEX_FR_FLIP_HORIZONTAL ) = = static_cast < int > ( WICBitmapTransformFlipHorizontal ) , " TEX_FR_FLIP_HORIZONTAL no longer matches WIC " ) ;
static_assert ( static_cast < int > ( TEX_FR_FLIP_VERTICAL ) = = static_cast < int > ( WICBitmapTransformFlipVertical ) , " TEX_FR_FLIP_VERTICAL no longer matches WIC " ) ;
2016-08-22 18:26:36 +00:00
// Only supports 90, 180, 270, or no rotation flags... not a combination of rotation flags
2018-08-17 23:58:12 +00:00
int rotateMode = static_cast < int > ( flags & ( TEX_FR_ROTATE0 | TEX_FR_ROTATE90 | TEX_FR_ROTATE180 | TEX_FR_ROTATE270 ) ) ;
switch ( rotateMode )
2016-08-22 18:26:36 +00:00
{
case 0 :
case TEX_FR_ROTATE90 :
case TEX_FR_ROTATE180 :
case TEX_FR_ROTATE270 :
break ;
default :
return E_INVALIDARG ;
}
TexMetadata mdata2 = metadata ;
bool flipwh = false ;
2018-08-17 23:58:12 +00:00
if ( ( rotateMode = = TEX_FR_ROTATE90 ) | | ( rotateMode = = TEX_FR_ROTATE270 ) )
2016-08-22 18:26:36 +00:00
{
flipwh = true ;
mdata2 . width = metadata . height ;
mdata2 . height = metadata . width ;
}
2016-09-09 02:09:46 +00:00
HRESULT hr = result . Initialize ( mdata2 ) ;
if ( FAILED ( hr ) )
2016-08-22 18:26:36 +00:00
return hr ;
2016-09-09 02:09:46 +00:00
if ( nimages ! = result . GetImageCount ( ) )
2016-08-22 18:26:36 +00:00
{
result . Release ( ) ;
return E_FAIL ;
}
const Image * dest = result . GetImages ( ) ;
2016-09-09 02:09:46 +00:00
if ( ! dest )
2016-08-22 18:26:36 +00:00
{
result . Release ( ) ;
return E_POINTER ;
}
WICPixelFormatGUID pfGUID ;
2016-09-09 02:09:46 +00:00
bool wicpf = _DXGIToWIC ( metadata . format , pfGUID ) ;
2016-08-22 18:26:36 +00:00
2016-09-09 02:09:46 +00:00
for ( size_t index = 0 ; index < nimages ; + + index )
2016-08-22 18:26:36 +00:00
{
2016-09-09 02:09:46 +00:00
const Image & src = srcImages [ index ] ;
if ( src . format ! = metadata . format )
2016-08-22 18:26:36 +00:00
{
result . Release ( ) ;
return E_FAIL ;
}
2016-09-09 02:09:46 +00:00
if ( ( src . width > UINT32_MAX ) | | ( src . height > UINT32_MAX ) )
2016-08-22 18:26:36 +00:00
return E_FAIL ;
2016-09-09 02:09:46 +00:00
const Image & dst = dest [ index ] ;
assert ( dst . format = = metadata . format ) ;
2016-08-22 18:26:36 +00:00
2016-09-09 02:09:46 +00:00
if ( flipwh )
2016-08-22 18:26:36 +00:00
{
2016-09-09 02:09:46 +00:00
if ( src . width ! = dst . height | | src . height ! = dst . width )
2016-08-22 18:26:36 +00:00
{
result . Release ( ) ;
return E_FAIL ;
}
}
else
{
2016-09-09 02:09:46 +00:00
if ( src . width ! = dst . width | | src . height ! = dst . height )
2016-08-22 18:26:36 +00:00
{
result . Release ( ) ;
return E_FAIL ;
}
}
if ( wicpf )
{
// Case 1: Source format is supported by Windows Imaging Component
2016-09-09 02:09:46 +00:00
hr = PerformFlipRotateUsingWIC ( src , flags , pfGUID , dst ) ;
2016-08-22 18:26:36 +00:00
}
else
{
// Case 2: Source format is not supported by WIC, so we have to convert, flip/rotate, and convert back
2018-08-02 19:31:20 +00:00
uint64_t expandedSize = uint64_t ( src . width ) * uint64_t ( src . height ) * sizeof ( float ) * 4 ;
if ( expandedSize > UINT32_MAX )
{
// Image is too large for float32, so have to use float16 instead
hr = PerformFlipRotateViaF16 ( src , flags , dst ) ;
}
else
{
hr = PerformFlipRotateViaF32 ( src , flags , dst ) ;
}
2016-08-22 18:26:36 +00:00
}
2016-09-09 02:09:46 +00:00
if ( FAILED ( hr ) )
2016-08-22 18:26:36 +00:00
{
result . Release ( ) ;
return hr ;
}
}
return S_OK ;
}