Skip to content
Open
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
60 changes: 58 additions & 2 deletions DirectXTex/DirectXTexMisc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -260,8 +260,64 @@ _Use_decl_annotations_ HRESULT DirectX::CopyRectangle(const Image& srcImage,
if (!srcImage.pixels || !dstImage.pixels)
return E_POINTER;

if (IsCompressed(srcImage.format) || IsCompressed(dstImage.format) || IsPlanar(srcImage.format) || IsPlanar(dstImage.format)
|| IsPalettized(srcImage.format) || IsPalettized(dstImage.format))
if (IsCompressed(srcImage.format) || IsCompressed(dstImage.format))
{
if (srcImage.format != dstImage.format)
return HRESULT_E_NOT_SUPPORTED;

const size_t bytesPerBlock = BytesPerBlock(srcImage.format);
if (!bytesPerBlock)
return HRESULT_E_NOT_SUPPORTED;

if (!srcRect.w || !srcRect.h || srcRect.x >= srcImage.width || srcRect.y >= srcImage.height
|| srcRect.w > srcImage.width - srcRect.x || srcRect.h > srcImage.height - srcRect.y || xOffset >= dstImage.width
|| yOffset >= dstImage.height || srcRect.w > dstImage.width - xOffset || srcRect.h > dstImage.height - yOffset)
return E_INVALIDARG;

// Copy whole 4x4 blocks covering srcRect, including pixels outside it.
// Round the destination origin down to a block boundary.
const size_t srcX = srcRect.x / 4;
const size_t srcY = srcRect.y / 4;
const size_t dstX = xOffset / 4;
const size_t dstY = yOffset / 4;

const size_t blockWidth = (srcRect.x + srcRect.w - 1) / 4 + 1 - srcX;
const size_t blockHeight = (srcRect.y + srcRect.h - 1) / 4 + 1 - srcY;
const size_t dstWidth = (dstImage.width - 1) / 4 + 1;
const size_t dstHeight = (dstImage.height - 1) / 4 + 1;
if (blockWidth > dstWidth - dstX || blockHeight > dstHeight - dstY)
return E_INVALIDARG;

const auto validStorage = [bytesPerBlock](const Image& image, size_t x, size_t y, size_t width, size_t height) noexcept
{
const size_t imageBlocks = (image.width - 1) / 4 + 1;
if (!image.rowPitch || imageBlocks > image.rowPitch / bytesPerBlock)
return false;

const size_t rowEnd = (x + width) * bytesPerBlock;
return rowEnd <= image.slicePitch && y + height - 1 <= (image.slicePitch - rowEnd) / image.rowPitch;
};

if (!validStorage(srcImage, srcX, srcY, blockWidth, blockHeight) || !validStorage(dstImage, dstX, dstY, blockWidth, blockHeight))
return E_FAIL;

const size_t copyBytes = blockWidth * bytesPerBlock;
const uint8_t* pSrc = srcImage.pixels + srcY * srcImage.rowPitch + srcX * bytesPerBlock;
uint8_t* pDest = dstImage.pixels + dstY * dstImage.rowPitch + dstX * bytesPerBlock;
for (size_t row = 0; row < blockHeight; ++row)
{
memcpy(pDest, pSrc, copyBytes);
if (row + 1 < blockHeight)
{
pSrc += srcImage.rowPitch;
pDest += dstImage.rowPitch;
}
}

return S_OK;
}

if (IsPlanar(srcImage.format) || IsPlanar(dstImage.format) || IsPalettized(srcImage.format) || IsPalettized(dstImage.format))
return HRESULT_E_NOT_SUPPORTED;

// Validate rectangle/offset
Expand Down