Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ set(LIBRARY_SOURCES
DirectXTex/DirectXTexCompress.cpp
DirectXTex/DirectXTexConvert.cpp
DirectXTex/DirectXTexDDS.cpp
DirectXTex/DirectXTexFlipRotate.cpp
DirectXTex/DirectXTexHDR.cpp
DirectXTex/DirectXTexImage.cpp
DirectXTex/DirectXTexMipmaps.cpp
Expand All @@ -123,7 +124,6 @@ set(LIBRARY_SOURCES

if(WIN32)
list(APPEND LIBRARY_SOURCES
DirectXTex/DirectXTexFlipRotate.cpp
DirectXTex/DirectXTexWIC.cpp)
endif()

Expand Down
2 changes: 0 additions & 2 deletions DirectXTex/DirectXTex.h
Original file line number Diff line number Diff line change
Expand Up @@ -783,15 +783,13 @@ namespace DirectX
TEX_FR_FLIP_VERTICAL = 0x10,
};

#ifdef _WIN32
DIRECTX_TEX_API HRESULT __cdecl FlipRotate(_In_ const Image& srcImage, _In_ TEX_FR_FLAGS flags, _Out_ ScratchImage& image) noexcept;
DIRECTX_TEX_API HRESULT __cdecl FlipRotate(_In_reads_(nimages) const Image* srcImages,
_In_ size_t nimages,
_In_ const TexMetadata& metadata,
_In_ TEX_FR_FLAGS flags,
_Out_ ScratchImage& result) noexcept;
// Flip and/or rotate image
#endif

enum TEX_FILTER_FLAGS : uint32_t
{
Expand Down
130 changes: 130 additions & 0 deletions DirectXTex/DirectXTexFlipRotate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,13 @@

using namespace DirectX;
using namespace DirectX::Internal;
#ifdef _WIN32
using Microsoft::WRL::ComPtr;
#endif

namespace
{
#ifdef _WIN32
//-------------------------------------------------------------------------------------
// Do flip/rotate operation using WIC
//-------------------------------------------------------------------------------------
Expand Down Expand Up @@ -166,6 +169,109 @@ namespace

return S_OK;
}
#else // !WIN32
//-------------------------------------------------------------------------------------
// Flip/rotate by moving whole pixels, which needs a fixed number of bytes per pixel
//-------------------------------------------------------------------------------------
bool IsSupportedForFlipRotate(DXGI_FORMAT format) noexcept
{
if (IsCompressed(format) || IsPacked(format) || IsPlanar(format) || IsPalettized(format))
return false;

const size_t bpp = BitsPerPixel(format);
return (bpp >= 8) && ((bpp % 8) == 0);
}

HRESULT PerformFlipRotate(const Image& srcImage, TEX_FR_FLAGS flags, const Image& destImage) noexcept
{
if (!srcImage.pixels || !destImage.pixels)
return E_POINTER;

assert(srcImage.format == destImage.format);

const size_t bytesPerPixel = BitsPerPixel(srcImage.format) / 8;
if (!bytesPerPixel)
return HRESULT_E_NOT_SUPPORTED;

// Each destination pixel (x, y) is read from the source pixel (sx, sy), or (sy, sx) when the rotation
// swaps the axes. The flip flags are applied to the source before the rotation, as WIC does.
bool swapXY = false;
bool flipX = false;
bool flipY = false;

switch (static_cast<int>(flags & (TEX_FR_ROTATE0 | TEX_FR_ROTATE90 | TEX_FR_ROTATE180 | TEX_FR_ROTATE270)))
{
case TEX_FR_ROTATE90:
swapXY = flipX = true;
break;

case TEX_FR_ROTATE180:
flipX = flipY = true;
break;

case TEX_FR_ROTATE270:
swapXY = flipY = true;
break;

default:
break;
}

if (flags & TEX_FR_FLIP_HORIZONTAL)
{
if (swapXY)
flipY = !flipY;
else
flipX = !flipX;
}

if (flags & TEX_FR_FLIP_VERTICAL)
{
if (swapXY)
flipX = !flipX;
else
flipY = !flipY;
}

const size_t width = destImage.width;
const size_t height = destImage.height;

if (swapXY)
{
if (srcImage.width != height || srcImage.height != width)
return E_FAIL;
}
else if (srcImage.width != width || srcImage.height != height)
{
return E_FAIL;
}

const size_t rowBytes = width * bytesPerPixel;

for (size_t y = 0; y < height; ++y)
{
const size_t sy = flipY ? (height - 1 - y) : y;
uint8_t* pDest = destImage.pixels + y * destImage.rowPitch;

if (!swapXY && !flipX)
{
memcpy(pDest, srcImage.pixels + sy * srcImage.rowPitch, rowBytes);
continue;
}

for (size_t x = 0; x < width; ++x)
{
const size_t sx = flipX ? (width - 1 - x) : x;
const uint8_t* pSrc = swapXY
? srcImage.pixels + sx * srcImage.rowPitch + sy * bytesPerPixel
: srcImage.pixels + sy * srcImage.rowPitch + sx * bytesPerPixel;
memcpy(pDest + x * bytesPerPixel, pSrc, bytesPerPixel);
}
}

return S_OK;
}
#endif // WIN32
} // namespace

//=====================================================================================
Expand All @@ -192,6 +298,12 @@ _Use_decl_annotations_ HRESULT DirectX::FlipRotate(const Image& srcImage, TEX_FR
return HRESULT_E_NOT_SUPPORTED;
}

#ifndef _WIN32
if (!IsSupportedForFlipRotate(srcImage.format))
return HRESULT_E_NOT_SUPPORTED;
#endif

#ifdef _WIN32
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");
Expand All @@ -203,6 +315,7 @@ _Use_decl_annotations_ HRESULT DirectX::FlipRotate(const Image& srcImage, TEX_FR
"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");
#endif

// Only supports 90, 180, 270, or no rotation flags... not a combination of rotation flags
const int rotateMode = static_cast<int>(flags & (TEX_FR_ROTATE0 | TEX_FR_ROTATE90 | TEX_FR_ROTATE180 | TEX_FR_ROTATE270));
Expand Down Expand Up @@ -237,6 +350,7 @@ _Use_decl_annotations_ HRESULT DirectX::FlipRotate(const Image& srcImage, TEX_FR
return E_POINTER;
}

#ifdef _WIN32
WICPixelFormatGUID pfGUID;
if (DXGIToWIC(srcImage.format, pfGUID))
{
Expand All @@ -257,6 +371,9 @@ _Use_decl_annotations_ HRESULT DirectX::FlipRotate(const Image& srcImage, TEX_FR
hr = PerformFlipRotateViaF32(srcImage, flags, *rimage);
}
}
#else
hr = PerformFlipRotate(srcImage, flags, *rimage);
#endif

if (FAILED(hr))
{
Expand All @@ -282,6 +399,12 @@ DirectX::FlipRotate(const Image* srcImages, size_t nimages, const TexMetadata& m
return HRESULT_E_NOT_SUPPORTED;
}

#ifndef _WIN32
if (!IsSupportedForFlipRotate(metadata.format))
return HRESULT_E_NOT_SUPPORTED;
#endif

#ifdef _WIN32
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");
Expand All @@ -293,6 +416,7 @@ DirectX::FlipRotate(const Image* srcImages, size_t nimages, const TexMetadata& m
"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");
#endif

// Only supports 90, 180, 270, or no rotation flags... not a combination of rotation flags
const int rotateMode = static_cast<int>(flags & (TEX_FR_ROTATE0 | TEX_FR_ROTATE90 | TEX_FR_ROTATE180 | TEX_FR_ROTATE270));
Expand Down Expand Up @@ -334,8 +458,10 @@ DirectX::FlipRotate(const Image* srcImages, size_t nimages, const TexMetadata& m
return E_POINTER;
}

#ifdef _WIN32
WICPixelFormatGUID pfGUID;
const bool wicpf = DXGIToWIC(metadata.format, pfGUID);
#endif

for (size_t index = 0; index < nimages; ++index)
{
Expand Down Expand Up @@ -369,6 +495,7 @@ DirectX::FlipRotate(const Image* srcImages, size_t nimages, const TexMetadata& m
}
}

#ifdef _WIN32
if (wicpf)
{
// Case 1: Source format is supported by Windows Imaging Component
Expand All @@ -388,6 +515,9 @@ DirectX::FlipRotate(const Image* srcImages, size_t nimages, const TexMetadata& m
hr = PerformFlipRotateViaF32(src, flags, dst);
}
}
#else
hr = PerformFlipRotate(src, flags, dst);
#endif

if (FAILED(hr))
{
Expand Down