mirror of
https://github.com/microsoft/DirectXTex.git
synced 2025-07-09 19:50:13 +02:00
Add partial support for indexed TGA files (#274)
This commit is contained in:
parent
33b69f39bc
commit
9951875603
@ -15,7 +15,8 @@
|
|||||||
// The implementation here has the following limitations:
|
// The implementation here has the following limitations:
|
||||||
// * Does not support files that contain color maps (these are rare in practice)
|
// * Does not support files that contain color maps (these are rare in practice)
|
||||||
// * Interleaved files are not supported (deprecated aspect of TGA format)
|
// * Interleaved files are not supported (deprecated aspect of TGA format)
|
||||||
// * Only supports 8-bit grayscale; 16-, 24-, and 32-bit truecolor images
|
// * Only supports 8-bit grayscale; 16-, 24-, and 32-bit truecolor images RLE or uncompressed
|
||||||
|
// plus 24-bit color-mapped uncompressed images
|
||||||
// * Always writes uncompressed files (i.e. can read RLE compression, but does not write it)
|
// * Always writes uncompressed files (i.e. can read RLE compression, but does not write it)
|
||||||
//
|
//
|
||||||
|
|
||||||
@ -76,6 +77,8 @@ namespace
|
|||||||
|
|
||||||
static_assert(sizeof(TGA_HEADER) == 18, "TGA 2.0 size mismatch");
|
static_assert(sizeof(TGA_HEADER) == 18, "TGA 2.0 size mismatch");
|
||||||
|
|
||||||
|
constexpr size_t TGA_HEADER_LEN = 18;
|
||||||
|
|
||||||
struct TGA_FOOTER
|
struct TGA_FOOTER
|
||||||
{
|
{
|
||||||
uint32_t dwExtensionOffset;
|
uint32_t dwExtensionOffset;
|
||||||
@ -125,6 +128,7 @@ namespace
|
|||||||
CONV_FLAGS_INVERTX = 0x2, // If set, scanlines are right-to-left
|
CONV_FLAGS_INVERTX = 0x2, // If set, scanlines are right-to-left
|
||||||
CONV_FLAGS_INVERTY = 0x4, // If set, scanlines are top-to-bottom
|
CONV_FLAGS_INVERTY = 0x4, // If set, scanlines are top-to-bottom
|
||||||
CONV_FLAGS_RLE = 0x8, // Source data is RLE compressed
|
CONV_FLAGS_RLE = 0x8, // Source data is RLE compressed
|
||||||
|
CONV_FLAGS_PALETTED = 0x10, // Source data is paletted
|
||||||
|
|
||||||
CONV_FLAGS_SWIZZLE = 0x10000, // Swizzle BGR<->RGB data
|
CONV_FLAGS_SWIZZLE = 0x10000, // Swizzle BGR<->RGB data
|
||||||
CONV_FLAGS_888 = 0x20000, // 24bpp format
|
CONV_FLAGS_888 = 0x20000, // 24bpp format
|
||||||
@ -147,19 +151,13 @@ namespace
|
|||||||
|
|
||||||
memset(&metadata, 0, sizeof(TexMetadata));
|
memset(&metadata, 0, sizeof(TexMetadata));
|
||||||
|
|
||||||
if (size < sizeof(TGA_HEADER))
|
if (size < TGA_HEADER_LEN)
|
||||||
{
|
{
|
||||||
return HRESULT_E_INVALID_DATA;
|
return HRESULT_E_INVALID_DATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto pHeader = static_cast<const TGA_HEADER*>(pSource);
|
auto pHeader = static_cast<const TGA_HEADER*>(pSource);
|
||||||
|
|
||||||
if (pHeader->bColorMapType != 0
|
|
||||||
|| pHeader->wColorMapLength != 0)
|
|
||||||
{
|
|
||||||
return HRESULT_E_NOT_SUPPORTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pHeader->bDescriptor & (TGA_FLAGS_INTERLEAVED_2WAY | TGA_FLAGS_INTERLEAVED_4WAY))
|
if (pHeader->bDescriptor & (TGA_FLAGS_INTERLEAVED_2WAY | TGA_FLAGS_INTERLEAVED_4WAY))
|
||||||
{
|
{
|
||||||
return HRESULT_E_NOT_SUPPORTED;
|
return HRESULT_E_NOT_SUPPORTED;
|
||||||
@ -167,13 +165,58 @@ namespace
|
|||||||
|
|
||||||
if (!pHeader->wWidth || !pHeader->wHeight)
|
if (!pHeader->wWidth || !pHeader->wHeight)
|
||||||
{
|
{
|
||||||
|
// These are uint16 values so are already bounded by UINT16_MAX.
|
||||||
return HRESULT_E_INVALID_DATA;
|
return HRESULT_E_INVALID_DATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (pHeader->bImageType)
|
switch (pHeader->bImageType)
|
||||||
{
|
{
|
||||||
|
case TGA_NO_IMAGE:
|
||||||
|
case TGA_COLOR_MAPPED_RLE:
|
||||||
|
return HRESULT_E_NOT_SUPPORTED;
|
||||||
|
|
||||||
|
case TGA_COLOR_MAPPED:
|
||||||
|
if (pHeader->bColorMapType != 1
|
||||||
|
|| pHeader->wColorMapLength == 0
|
||||||
|
|| pHeader->bBitsPerPixel != 8)
|
||||||
|
{
|
||||||
|
return HRESULT_E_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (pHeader->bColorMapSize)
|
||||||
|
{
|
||||||
|
case 24:
|
||||||
|
if (flags & TGA_FLAGS_BGR)
|
||||||
|
{
|
||||||
|
metadata.format = DXGI_FORMAT_B8G8R8X8_UNORM;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
metadata.format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||||
|
metadata.SetAlphaMode(TEX_ALPHA_MODE_OPAQUE);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Other possible values are 15, 16, and 32 which we do not support.
|
||||||
|
|
||||||
|
default:
|
||||||
|
return HRESULT_E_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (convFlags)
|
||||||
|
{
|
||||||
|
*convFlags |= CONV_FLAGS_PALETTED;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case TGA_TRUECOLOR:
|
case TGA_TRUECOLOR:
|
||||||
case TGA_TRUECOLOR_RLE:
|
case TGA_TRUECOLOR_RLE:
|
||||||
|
if (pHeader->bColorMapType != 0
|
||||||
|
|| pHeader->wColorMapLength != 0)
|
||||||
|
{
|
||||||
|
return HRESULT_E_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
switch (pHeader->bBitsPerPixel)
|
switch (pHeader->bBitsPerPixel)
|
||||||
{
|
{
|
||||||
case 16:
|
case 16:
|
||||||
@ -198,6 +241,9 @@ namespace
|
|||||||
case 32:
|
case 32:
|
||||||
metadata.format = (flags & TGA_FLAGS_BGR) ? DXGI_FORMAT_B8G8R8A8_UNORM : DXGI_FORMAT_R8G8B8A8_UNORM;
|
metadata.format = (flags & TGA_FLAGS_BGR) ? DXGI_FORMAT_B8G8R8A8_UNORM : DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return HRESULT_E_NOT_SUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (convFlags && (pHeader->bImageType == TGA_TRUECOLOR_RLE))
|
if (convFlags && (pHeader->bImageType == TGA_TRUECOLOR_RLE))
|
||||||
@ -208,6 +254,12 @@ namespace
|
|||||||
|
|
||||||
case TGA_BLACK_AND_WHITE:
|
case TGA_BLACK_AND_WHITE:
|
||||||
case TGA_BLACK_AND_WHITE_RLE:
|
case TGA_BLACK_AND_WHITE_RLE:
|
||||||
|
if (pHeader->bColorMapType != 0
|
||||||
|
|| pHeader->wColorMapLength != 0)
|
||||||
|
{
|
||||||
|
return HRESULT_E_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
switch (pHeader->bBitsPerPixel)
|
switch (pHeader->bBitsPerPixel)
|
||||||
{
|
{
|
||||||
case 8:
|
case 8:
|
||||||
@ -224,11 +276,6 @@ namespace
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TGA_NO_IMAGE:
|
|
||||||
case TGA_COLOR_MAPPED:
|
|
||||||
case TGA_COLOR_MAPPED_RLE:
|
|
||||||
return HRESULT_E_NOT_SUPPORTED;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return HRESULT_E_INVALID_DATA;
|
return HRESULT_E_INVALID_DATA;
|
||||||
}
|
}
|
||||||
@ -247,7 +294,7 @@ namespace
|
|||||||
*convFlags |= CONV_FLAGS_INVERTY;
|
*convFlags |= CONV_FLAGS_INVERTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
offset = sizeof(TGA_HEADER);
|
offset = TGA_HEADER_LEN;
|
||||||
|
|
||||||
if (pHeader->bIDLength != 0)
|
if (pHeader->bIDLength != 0)
|
||||||
{
|
{
|
||||||
@ -258,6 +305,64 @@ namespace
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------
|
||||||
|
// Reads palette for color-mapped TGA formats
|
||||||
|
//-------------------------------------------------------------------------------------
|
||||||
|
HRESULT ReadPalette(
|
||||||
|
_In_reads_(TGA_HEADER_LEN) const uint8_t* header,
|
||||||
|
_In_reads_bytes_(size) const void* pSource,
|
||||||
|
size_t size,
|
||||||
|
TGA_FLAGS flags,
|
||||||
|
uint8_t palette[256 * 4],
|
||||||
|
size_t& colorMapSize) noexcept
|
||||||
|
{
|
||||||
|
assert(header && pSource);
|
||||||
|
|
||||||
|
auto pHeader = reinterpret_cast<const TGA_HEADER*>(header);
|
||||||
|
|
||||||
|
if (pHeader->bColorMapType != 1
|
||||||
|
|| pHeader->wColorMapLength == 0
|
||||||
|
|| pHeader->wColorMapLength > 256
|
||||||
|
|| pHeader->bColorMapSize != 24)
|
||||||
|
{
|
||||||
|
return HRESULT_E_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t maxColorMap = size_t(pHeader->wColorMapFirst) + size_t(pHeader->wColorMapLength);
|
||||||
|
if (maxColorMap > 256)
|
||||||
|
{
|
||||||
|
return HRESULT_E_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
colorMapSize = size_t(pHeader->wColorMapLength) * ((size_t(pHeader->bColorMapSize) + 7) >> 3);
|
||||||
|
if (colorMapSize > size)
|
||||||
|
{
|
||||||
|
return HRESULT_E_INVALID_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto bytes = reinterpret_cast<const uint8_t*>(pSource);
|
||||||
|
|
||||||
|
for (size_t i = pHeader->wColorMapFirst; i < maxColorMap; ++i)
|
||||||
|
{
|
||||||
|
if (flags & TGA_FLAGS_BGR)
|
||||||
|
{
|
||||||
|
palette[i * 4 + 0] = bytes[0];
|
||||||
|
palette[i * 4 + 2] = bytes[2];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
palette[i * 4 + 0] = bytes[2];
|
||||||
|
palette[i * 4 + 2] = bytes[0];
|
||||||
|
}
|
||||||
|
palette[i * 4 + 1] = bytes[1];
|
||||||
|
palette[i * 4 + 3] = 255;
|
||||||
|
bytes += 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------------------
|
//-------------------------------------------------------------------------------------
|
||||||
// Set alpha for images with all 0 alpha channel
|
// Set alpha for images with all 0 alpha channel
|
||||||
//-------------------------------------------------------------------------------------
|
//-------------------------------------------------------------------------------------
|
||||||
@ -814,7 +919,8 @@ namespace
|
|||||||
size_t size,
|
size_t size,
|
||||||
TGA_FLAGS flags,
|
TGA_FLAGS flags,
|
||||||
_In_ const Image* image,
|
_In_ const Image* image,
|
||||||
_In_ uint32_t convFlags) noexcept
|
_In_ uint32_t convFlags,
|
||||||
|
_In_opt_ uint8_t* palette) noexcept
|
||||||
{
|
{
|
||||||
assert(pSource && size > 0);
|
assert(pSource && size > 0);
|
||||||
|
|
||||||
@ -823,7 +929,8 @@ namespace
|
|||||||
|
|
||||||
// Compute TGA image data pitch
|
// Compute TGA image data pitch
|
||||||
size_t rowPitch, slicePitch;
|
size_t rowPitch, slicePitch;
|
||||||
HRESULT hr = ComputePitch(image->format, image->width, image->height, rowPitch, slicePitch,
|
HRESULT hr = ComputePitch(image->format, image->width, image->height,
|
||||||
|
rowPitch, slicePitch,
|
||||||
(convFlags & CONV_FLAGS_EXPAND) ? CP_FLAGS_24BPP : CP_FLAGS_NONE);
|
(convFlags & CONV_FLAGS_EXPAND) ? CP_FLAGS_24BPP : CP_FLAGS_NONE);
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
return hr;
|
return hr;
|
||||||
@ -833,17 +940,20 @@ namespace
|
|||||||
|
|
||||||
bool opaquealpha = false;
|
bool opaquealpha = false;
|
||||||
|
|
||||||
switch (image->format)
|
if ((convFlags & CONV_FLAGS_PALETTED) != 0)
|
||||||
{
|
{
|
||||||
//--------------------------------------------------------------------------- 8-bit
|
if (!palette)
|
||||||
case DXGI_FORMAT_R8_UNORM:
|
return E_UNEXPECTED;
|
||||||
|
|
||||||
|
const auto table = reinterpret_cast<const uint32_t*>(palette);
|
||||||
|
|
||||||
for (size_t y = 0; y < image->height; ++y)
|
for (size_t y = 0; y < image->height; ++y)
|
||||||
{
|
{
|
||||||
size_t offset = ((convFlags & CONV_FLAGS_INVERTX) ? (image->width - 1) : 0);
|
size_t offset = ((convFlags & CONV_FLAGS_INVERTX) ? (image->width - 1) : 0);
|
||||||
assert(offset < rowPitch);
|
assert(offset < rowPitch);
|
||||||
|
|
||||||
uint8_t* dPtr = image->pixels
|
auto dPtr = reinterpret_cast<uint32_t*>(image->pixels
|
||||||
+ (image->rowPitch * ((convFlags & CONV_FLAGS_INVERTY) ? y : (image->height - y - 1)))
|
+ (image->rowPitch * ((convFlags & CONV_FLAGS_INVERTY) ? y : (image->height - y - 1))))
|
||||||
+ offset;
|
+ offset;
|
||||||
|
|
||||||
for (size_t x = 0; x < image->width; ++x)
|
for (size_t x = 0; x < image->width; ++x)
|
||||||
@ -851,7 +961,7 @@ namespace
|
|||||||
if (sPtr >= endPtr)
|
if (sPtr >= endPtr)
|
||||||
return E_FAIL;
|
return E_FAIL;
|
||||||
|
|
||||||
*dPtr = *(sPtr++);
|
*dPtr = table[*(sPtr++)];
|
||||||
|
|
||||||
if (convFlags & CONV_FLAGS_INVERTX)
|
if (convFlags & CONV_FLAGS_INVERTX)
|
||||||
--dPtr;
|
--dPtr;
|
||||||
@ -859,35 +969,28 @@ namespace
|
|||||||
++dPtr;
|
++dPtr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
|
else
|
||||||
//-------------------------------------------------------------------------- 16-bit
|
{
|
||||||
case DXGI_FORMAT_B5G5R5A1_UNORM:
|
switch (image->format)
|
||||||
{
|
{
|
||||||
uint32_t minalpha = 255;
|
//----------------------------------------------------------------------- 8-bit
|
||||||
uint32_t maxalpha = 0;
|
case DXGI_FORMAT_R8_UNORM:
|
||||||
|
|
||||||
for (size_t y = 0; y < image->height; ++y)
|
for (size_t y = 0; y < image->height; ++y)
|
||||||
{
|
{
|
||||||
size_t offset = ((convFlags & CONV_FLAGS_INVERTX) ? (image->width - 1) : 0);
|
size_t offset = ((convFlags & CONV_FLAGS_INVERTX) ? (image->width - 1) : 0);
|
||||||
assert(offset * 2 < rowPitch);
|
assert(offset < rowPitch);
|
||||||
|
|
||||||
auto dPtr = reinterpret_cast<uint16_t*>(image->pixels
|
uint8_t* dPtr = image->pixels
|
||||||
+ (image->rowPitch * ((convFlags & CONV_FLAGS_INVERTY) ? y : (image->height - y - 1))))
|
+ (image->rowPitch * ((convFlags & CONV_FLAGS_INVERTY) ? y : (image->height - y - 1)))
|
||||||
+ offset;
|
+ offset;
|
||||||
|
|
||||||
for (size_t x = 0; x < image->width; ++x)
|
for (size_t x = 0; x < image->width; ++x)
|
||||||
{
|
{
|
||||||
if (sPtr + 1 >= endPtr)
|
if (sPtr >= endPtr)
|
||||||
return E_FAIL;
|
return E_FAIL;
|
||||||
|
|
||||||
auto t = static_cast<uint16_t>(uint32_t(*sPtr) | uint32_t(*(sPtr + 1u) << 8));
|
*dPtr = *(sPtr++);
|
||||||
sPtr += 2;
|
|
||||||
*dPtr = t;
|
|
||||||
|
|
||||||
const uint32_t alpha = (t & 0x8000) ? 255 : 0;
|
|
||||||
minalpha = std::min(minalpha, alpha);
|
|
||||||
maxalpha = std::max(maxalpha, alpha);
|
|
||||||
|
|
||||||
if (convFlags & CONV_FLAGS_INVERTX)
|
if (convFlags & CONV_FLAGS_INVERTX)
|
||||||
--dPtr;
|
--dPtr;
|
||||||
@ -895,178 +998,215 @@ namespace
|
|||||||
++dPtr;
|
++dPtr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
// If there are no non-zero alpha channel entries, we'll assume alpha is not used and force it to opaque
|
//---------------------------------------------------------------------- 16-bit
|
||||||
if (maxalpha == 0 && !(flags & TGA_FLAGS_ALLOW_ALL_ZERO_ALPHA))
|
case DXGI_FORMAT_B5G5R5A1_UNORM:
|
||||||
{
|
{
|
||||||
opaquealpha = true;
|
uint32_t minalpha = 255;
|
||||||
hr = SetAlphaChannelToOpaque(image);
|
uint32_t maxalpha = 0;
|
||||||
if (FAILED(hr))
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
else if (minalpha == 255)
|
|
||||||
{
|
|
||||||
opaquealpha = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
//------------------------------------------------------ 24/32-bit (with swizzling)
|
for (size_t y = 0; y < image->height; ++y)
|
||||||
case DXGI_FORMAT_R8G8B8A8_UNORM:
|
|
||||||
{
|
|
||||||
uint32_t minalpha = 255;
|
|
||||||
uint32_t maxalpha = 0;
|
|
||||||
|
|
||||||
for (size_t y = 0; y < image->height; ++y)
|
|
||||||
{
|
|
||||||
size_t offset = ((convFlags & CONV_FLAGS_INVERTX) ? (image->width - 1) : 0);
|
|
||||||
|
|
||||||
auto dPtr = reinterpret_cast<uint32_t*>(image->pixels
|
|
||||||
+ (image->rowPitch * ((convFlags & CONV_FLAGS_INVERTY) ? y : (image->height - y - 1))))
|
|
||||||
+ offset;
|
|
||||||
|
|
||||||
for (size_t x = 0; x < image->width; ++x)
|
|
||||||
{
|
{
|
||||||
if (convFlags & CONV_FLAGS_EXPAND)
|
size_t offset = ((convFlags & CONV_FLAGS_INVERTX) ? (image->width - 1) : 0);
|
||||||
{
|
assert(offset * 2 < rowPitch);
|
||||||
assert(offset * 3 < rowPitch);
|
|
||||||
|
|
||||||
if (sPtr + 2 >= endPtr)
|
auto dPtr = reinterpret_cast<uint16_t*>(image->pixels
|
||||||
|
+ (image->rowPitch * ((convFlags & CONV_FLAGS_INVERTY) ? y : (image->height - y - 1))))
|
||||||
|
+ offset;
|
||||||
|
|
||||||
|
for (size_t x = 0; x < image->width; ++x)
|
||||||
|
{
|
||||||
|
if (sPtr + 1 >= endPtr)
|
||||||
return E_FAIL;
|
return E_FAIL;
|
||||||
|
|
||||||
// BGR -> RGBA
|
auto t = static_cast<uint16_t>(uint32_t(*sPtr) | uint32_t(*(sPtr + 1u) << 8));
|
||||||
*dPtr = uint32_t(*sPtr << 16) | uint32_t(*(sPtr + 1) << 8) | uint32_t(*(sPtr + 2)) | 0xFF000000;
|
sPtr += 2;
|
||||||
sPtr += 3;
|
*dPtr = t;
|
||||||
|
|
||||||
minalpha = maxalpha = 255;
|
const uint32_t alpha = (t & 0x8000) ? 255 : 0;
|
||||||
|
minalpha = std::min(minalpha, alpha);
|
||||||
|
maxalpha = std::max(maxalpha, alpha);
|
||||||
|
|
||||||
|
if (convFlags & CONV_FLAGS_INVERTX)
|
||||||
|
--dPtr;
|
||||||
|
else
|
||||||
|
++dPtr;
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
|
|
||||||
|
// If there are no non-zero alpha channel entries, we'll assume alpha is not used and force it to opaque
|
||||||
|
if (maxalpha == 0 && !(flags & TGA_FLAGS_ALLOW_ALL_ZERO_ALPHA))
|
||||||
|
{
|
||||||
|
opaquealpha = true;
|
||||||
|
hr = SetAlphaChannelToOpaque(image);
|
||||||
|
if (FAILED(hr))
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
else if (minalpha == 255)
|
||||||
|
{
|
||||||
|
opaquealpha = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
//-------------------------------------------------- 24/32-bit (with swizzling)
|
||||||
|
case DXGI_FORMAT_R8G8B8A8_UNORM:
|
||||||
|
{
|
||||||
|
uint32_t minalpha = 255;
|
||||||
|
uint32_t maxalpha = 0;
|
||||||
|
|
||||||
|
for (size_t y = 0; y < image->height; ++y)
|
||||||
|
{
|
||||||
|
size_t offset = ((convFlags & CONV_FLAGS_INVERTX) ? (image->width - 1) : 0);
|
||||||
|
|
||||||
|
auto dPtr = reinterpret_cast<uint32_t*>(image->pixels
|
||||||
|
+ (image->rowPitch * ((convFlags & CONV_FLAGS_INVERTY) ? y : (image->height - y - 1))))
|
||||||
|
+ offset;
|
||||||
|
|
||||||
|
for (size_t x = 0; x < image->width; ++x)
|
||||||
|
{
|
||||||
|
if (convFlags & CONV_FLAGS_EXPAND)
|
||||||
|
{
|
||||||
|
assert(offset * 3 < rowPitch);
|
||||||
|
|
||||||
|
if (sPtr + 2 >= endPtr)
|
||||||
|
return E_FAIL;
|
||||||
|
|
||||||
|
// BGR -> RGBA
|
||||||
|
*dPtr = uint32_t(*sPtr << 16) | uint32_t(*(sPtr + 1) << 8) | uint32_t(*(sPtr + 2)) | 0xFF000000;
|
||||||
|
sPtr += 3;
|
||||||
|
|
||||||
|
minalpha = maxalpha = 255;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(offset * 4 < rowPitch);
|
||||||
|
|
||||||
|
if (sPtr + 3 >= endPtr)
|
||||||
|
return E_FAIL;
|
||||||
|
|
||||||
|
// BGRA -> RGBA
|
||||||
|
uint32_t alpha = *(sPtr + 3);
|
||||||
|
*dPtr = uint32_t(*sPtr << 16) | uint32_t(*(sPtr + 1) << 8) | uint32_t(*(sPtr + 2)) | uint32_t(alpha << 24);
|
||||||
|
|
||||||
|
minalpha = std::min(minalpha, alpha);
|
||||||
|
maxalpha = std::max(maxalpha, alpha);
|
||||||
|
|
||||||
|
sPtr += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (convFlags & CONV_FLAGS_INVERTX)
|
||||||
|
--dPtr;
|
||||||
|
else
|
||||||
|
++dPtr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there are no non-zero alpha channel entries, we'll assume alpha is not used and force it to opaque
|
||||||
|
if (maxalpha == 0 && !(flags & TGA_FLAGS_ALLOW_ALL_ZERO_ALPHA))
|
||||||
|
{
|
||||||
|
opaquealpha = true;
|
||||||
|
hr = SetAlphaChannelToOpaque(image);
|
||||||
|
if (FAILED(hr))
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
else if (minalpha == 255)
|
||||||
|
{
|
||||||
|
opaquealpha = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
//---------------------------------------------------------------- 32-bit (BGR)
|
||||||
|
case DXGI_FORMAT_B8G8R8A8_UNORM:
|
||||||
|
{
|
||||||
|
assert((convFlags & CONV_FLAGS_EXPAND) == 0);
|
||||||
|
|
||||||
|
uint32_t minalpha = 255;
|
||||||
|
uint32_t maxalpha = 0;
|
||||||
|
|
||||||
|
for (size_t y = 0; y < image->height; ++y)
|
||||||
|
{
|
||||||
|
size_t offset = ((convFlags & CONV_FLAGS_INVERTX) ? (image->width - 1) : 0);
|
||||||
|
|
||||||
|
auto dPtr = reinterpret_cast<uint32_t*>(image->pixels
|
||||||
|
+ (image->rowPitch * ((convFlags & CONV_FLAGS_INVERTY) ? y : (image->height - y - 1))))
|
||||||
|
+ offset;
|
||||||
|
|
||||||
|
for (size_t x = 0; x < image->width; ++x)
|
||||||
{
|
{
|
||||||
assert(offset * 4 < rowPitch);
|
assert(offset * 4 < rowPitch);
|
||||||
|
|
||||||
if (sPtr + 3 >= endPtr)
|
if (sPtr + 3 >= endPtr)
|
||||||
return E_FAIL;
|
return E_FAIL;
|
||||||
|
|
||||||
// BGRA -> RGBA
|
const uint32_t alpha = *(sPtr + 3);
|
||||||
uint32_t alpha = *(sPtr + 3);
|
*dPtr = *reinterpret_cast<const uint32_t*>(sPtr);
|
||||||
*dPtr = uint32_t(*sPtr << 16) | uint32_t(*(sPtr + 1) << 8) | uint32_t(*(sPtr + 2)) | uint32_t(alpha << 24);
|
|
||||||
|
|
||||||
minalpha = std::min(minalpha, alpha);
|
minalpha = std::min(minalpha, alpha);
|
||||||
maxalpha = std::max(maxalpha, alpha);
|
maxalpha = std::max(maxalpha, alpha);
|
||||||
|
|
||||||
sPtr += 4;
|
sPtr += 4;
|
||||||
|
|
||||||
|
if (convFlags & CONV_FLAGS_INVERTX)
|
||||||
|
--dPtr;
|
||||||
|
else
|
||||||
|
++dPtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (convFlags & CONV_FLAGS_INVERTX)
|
|
||||||
--dPtr;
|
|
||||||
else
|
|
||||||
++dPtr;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// If there are no non-zero alpha channel entries, we'll assume alpha is not used and force it to opaque
|
// If there are no non-zero alpha channel entries, we'll assume alpha is not used and force it to opaque
|
||||||
if (maxalpha == 0 && !(flags & TGA_FLAGS_ALLOW_ALL_ZERO_ALPHA))
|
if (maxalpha == 0 && !(flags & TGA_FLAGS_ALLOW_ALL_ZERO_ALPHA))
|
||||||
{
|
|
||||||
opaquealpha = true;
|
|
||||||
hr = SetAlphaChannelToOpaque(image);
|
|
||||||
if (FAILED(hr))
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
else if (minalpha == 255)
|
|
||||||
{
|
|
||||||
opaquealpha = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------- 32-bit (BGR)
|
|
||||||
case DXGI_FORMAT_B8G8R8A8_UNORM:
|
|
||||||
{
|
|
||||||
assert((convFlags & CONV_FLAGS_EXPAND) == 0);
|
|
||||||
|
|
||||||
uint32_t minalpha = 255;
|
|
||||||
uint32_t maxalpha = 0;
|
|
||||||
|
|
||||||
for (size_t y = 0; y < image->height; ++y)
|
|
||||||
{
|
|
||||||
size_t offset = ((convFlags & CONV_FLAGS_INVERTX) ? (image->width - 1) : 0);
|
|
||||||
|
|
||||||
auto dPtr = reinterpret_cast<uint32_t*>(image->pixels
|
|
||||||
+ (image->rowPitch * ((convFlags & CONV_FLAGS_INVERTY) ? y : (image->height - y - 1))))
|
|
||||||
+ offset;
|
|
||||||
|
|
||||||
for (size_t x = 0; x < image->width; ++x)
|
|
||||||
{
|
{
|
||||||
assert(offset * 4 < rowPitch);
|
opaquealpha = true;
|
||||||
|
hr = SetAlphaChannelToOpaque(image);
|
||||||
if (sPtr + 3 >= endPtr)
|
if (FAILED(hr))
|
||||||
return E_FAIL;
|
return hr;
|
||||||
|
|
||||||
const uint32_t alpha = *(sPtr + 3);
|
|
||||||
*dPtr = *reinterpret_cast<const uint32_t*>(sPtr);
|
|
||||||
|
|
||||||
minalpha = std::min(minalpha, alpha);
|
|
||||||
maxalpha = std::max(maxalpha, alpha);
|
|
||||||
|
|
||||||
sPtr += 4;
|
|
||||||
|
|
||||||
if (convFlags & CONV_FLAGS_INVERTX)
|
|
||||||
--dPtr;
|
|
||||||
else
|
|
||||||
++dPtr;
|
|
||||||
}
|
}
|
||||||
}
|
else if (minalpha == 255)
|
||||||
|
|
||||||
// If there are no non-zero alpha channel entries, we'll assume alpha is not used and force it to opaque
|
|
||||||
if (maxalpha == 0 && !(flags & TGA_FLAGS_ALLOW_ALL_ZERO_ALPHA))
|
|
||||||
{
|
|
||||||
opaquealpha = true;
|
|
||||||
hr = SetAlphaChannelToOpaque(image);
|
|
||||||
if (FAILED(hr))
|
|
||||||
return hr;
|
|
||||||
}
|
|
||||||
else if (minalpha == 255)
|
|
||||||
{
|
|
||||||
opaquealpha = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------- 24-bit (BGR)
|
|
||||||
case DXGI_FORMAT_B8G8R8X8_UNORM:
|
|
||||||
{
|
|
||||||
assert((convFlags & CONV_FLAGS_EXPAND) != 0);
|
|
||||||
|
|
||||||
for (size_t y = 0; y < image->height; ++y)
|
|
||||||
{
|
|
||||||
size_t offset = ((convFlags & CONV_FLAGS_INVERTX) ? (image->width - 1) : 0);
|
|
||||||
|
|
||||||
auto dPtr = reinterpret_cast<uint32_t*>(image->pixels
|
|
||||||
+ (image->rowPitch * ((convFlags & CONV_FLAGS_INVERTY) ? y : (image->height - y - 1))))
|
|
||||||
+ offset;
|
|
||||||
|
|
||||||
for (size_t x = 0; x < image->width; ++x)
|
|
||||||
{
|
{
|
||||||
assert(offset * 3 < rowPitch);
|
opaquealpha = true;
|
||||||
|
|
||||||
if (sPtr + 2 >= endPtr)
|
|
||||||
return E_FAIL;
|
|
||||||
|
|
||||||
*dPtr = uint32_t(*sPtr) | uint32_t(*(sPtr + 1) << 8) | uint32_t(*(sPtr + 2) << 16);
|
|
||||||
sPtr += 3;
|
|
||||||
|
|
||||||
if (convFlags & CONV_FLAGS_INVERTX)
|
|
||||||
--dPtr;
|
|
||||||
else
|
|
||||||
++dPtr;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
break;
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------
|
//---------------------------------------------------------------- 24-bit (BGR)
|
||||||
default:
|
case DXGI_FORMAT_B8G8R8X8_UNORM:
|
||||||
return E_FAIL;
|
{
|
||||||
|
assert((convFlags & CONV_FLAGS_EXPAND) != 0);
|
||||||
|
|
||||||
|
for (size_t y = 0; y < image->height; ++y)
|
||||||
|
{
|
||||||
|
size_t offset = ((convFlags & CONV_FLAGS_INVERTX) ? (image->width - 1) : 0);
|
||||||
|
|
||||||
|
auto dPtr = reinterpret_cast<uint32_t*>(image->pixels
|
||||||
|
+ (image->rowPitch * ((convFlags & CONV_FLAGS_INVERTY) ? y : (image->height - y - 1))))
|
||||||
|
+ offset;
|
||||||
|
|
||||||
|
for (size_t x = 0; x < image->width; ++x)
|
||||||
|
{
|
||||||
|
assert(offset * 3 < rowPitch);
|
||||||
|
|
||||||
|
if (sPtr + 2 >= endPtr)
|
||||||
|
return E_FAIL;
|
||||||
|
|
||||||
|
*dPtr = uint32_t(*sPtr) | uint32_t(*(sPtr + 1) << 8) | uint32_t(*(sPtr + 2) << 16);
|
||||||
|
sPtr += 3;
|
||||||
|
|
||||||
|
if (convFlags & CONV_FLAGS_INVERTX)
|
||||||
|
--dPtr;
|
||||||
|
else
|
||||||
|
++dPtr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
default:
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return opaquealpha ? S_FALSE : S_OK;
|
return opaquealpha ? S_FALSE : S_OK;
|
||||||
@ -1078,7 +1218,7 @@ namespace
|
|||||||
//-------------------------------------------------------------------------------------
|
//-------------------------------------------------------------------------------------
|
||||||
HRESULT EncodeTGAHeader(_In_ const Image& image, _Out_ TGA_HEADER& header, _Inout_ uint32_t& convFlags) noexcept
|
HRESULT EncodeTGAHeader(_In_ const Image& image, _Out_ TGA_HEADER& header, _Inout_ uint32_t& convFlags) noexcept
|
||||||
{
|
{
|
||||||
memset(&header, 0, sizeof(TGA_HEADER));
|
memset(&header, 0, TGA_HEADER_LEN);
|
||||||
|
|
||||||
if ((image.width > UINT16_MAX)
|
if ((image.width > UINT16_MAX)
|
||||||
|| (image.height > UINT16_MAX))
|
|| (image.height > UINT16_MAX))
|
||||||
@ -1389,28 +1529,28 @@ HRESULT DirectX::GetMetadataFromTGAFile(const wchar_t* szFile, TGA_FLAGS flags,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Need at least enough data to fill the standard header to be a valid TGA
|
// Need at least enough data to fill the standard header to be a valid TGA
|
||||||
if (len < (sizeof(TGA_HEADER)))
|
if (len < TGA_HEADER_LEN)
|
||||||
{
|
{
|
||||||
return E_FAIL;
|
return E_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the standard header (we don't need the file footer to parse the file)
|
// Read the standard header (we don't need the file footer to parse the file)
|
||||||
uint8_t header[sizeof(TGA_HEADER)] = {};
|
uint8_t header[TGA_HEADER_LEN] = {};
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
DWORD bytesRead = 0;
|
DWORD bytesRead = 0;
|
||||||
if (!ReadFile(hFile.get(), header, sizeof(TGA_HEADER), &bytesRead, nullptr))
|
if (!ReadFile(hFile.get(), header, TGA_HEADER_LEN, &bytesRead, nullptr))
|
||||||
{
|
{
|
||||||
return HRESULT_FROM_WIN32(GetLastError());
|
return HRESULT_FROM_WIN32(GetLastError());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto const headerLen = static_cast<size_t>(bytesRead);
|
auto const headerLen = static_cast<size_t>(bytesRead);
|
||||||
#else
|
#else
|
||||||
inFile.read(reinterpret_cast<char*>(header), sizeof(TGA_HEADER));
|
inFile.read(reinterpret_cast<char*>(header), TGA_HEADER_LEN);
|
||||||
if (!inFile)
|
if (!inFile)
|
||||||
return E_FAIL;
|
return E_FAIL;
|
||||||
|
|
||||||
size_t headerLen = sizeof(TGA_HEADER);
|
size_t headerLen = TGA_HEADER_LEN;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
size_t offset;
|
size_t offset;
|
||||||
@ -1514,12 +1654,29 @@ HRESULT DirectX::LoadFromTGAMemory(
|
|||||||
if (offset > size)
|
if (offset > size)
|
||||||
return E_FAIL;
|
return E_FAIL;
|
||||||
|
|
||||||
const void* pPixels = static_cast<const uint8_t*>(pSource) + offset;
|
size_t paletteOffset = 0;
|
||||||
|
uint8_t palette[256 * 4] = {};
|
||||||
|
if (convFlags & CONV_FLAGS_PALETTED)
|
||||||
|
{
|
||||||
|
const size_t remaining = size - offset;
|
||||||
|
if (remaining == 0)
|
||||||
|
return E_FAIL;
|
||||||
|
|
||||||
const size_t remaining = size - offset;
|
auto pColorMap = static_cast<const uint8_t*>(pSource) + offset;
|
||||||
|
|
||||||
|
_Analysis_assume_(size > TGA_HEADER_LEN);
|
||||||
|
hr = ReadPalette(static_cast<const uint8_t*>(pSource), pColorMap, remaining, flags,
|
||||||
|
palette, paletteOffset);
|
||||||
|
if (FAILED(hr))
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t remaining = size - offset - paletteOffset;
|
||||||
if (remaining == 0)
|
if (remaining == 0)
|
||||||
return E_FAIL;
|
return E_FAIL;
|
||||||
|
|
||||||
|
const void* pPixels = static_cast<const uint8_t*>(pSource) + offset + paletteOffset;
|
||||||
|
|
||||||
hr = image.Initialize2D(mdata.format, mdata.width, mdata.height, 1, 1);
|
hr = image.Initialize2D(mdata.format, mdata.width, mdata.height, 1, 1);
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
return hr;
|
return hr;
|
||||||
@ -1530,7 +1687,7 @@ HRESULT DirectX::LoadFromTGAMemory(
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
hr = CopyPixels(pPixels, remaining, flags, image.GetImage(0, 0, 0), convFlags);
|
hr = CopyPixels(pPixels, remaining, flags, image.GetImage(0, 0, 0), convFlags, palette);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
@ -1638,28 +1795,28 @@ HRESULT DirectX::LoadFromTGAFile(
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Need at least enough data to fill the header to be a valid TGA
|
// Need at least enough data to fill the header to be a valid TGA
|
||||||
if (len < sizeof(TGA_HEADER))
|
if (len < TGA_HEADER_LEN)
|
||||||
{
|
{
|
||||||
return E_FAIL;
|
return E_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the header
|
// Read the header
|
||||||
uint8_t header[sizeof(TGA_HEADER)] = {};
|
uint8_t header[TGA_HEADER_LEN] = {};
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
DWORD bytesRead = 0;
|
DWORD bytesRead = 0;
|
||||||
if (!ReadFile(hFile.get(), header, sizeof(TGA_HEADER), &bytesRead, nullptr))
|
if (!ReadFile(hFile.get(), header, TGA_HEADER_LEN, &bytesRead, nullptr))
|
||||||
{
|
{
|
||||||
return HRESULT_FROM_WIN32(GetLastError());
|
return HRESULT_FROM_WIN32(GetLastError());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto const headerLen = static_cast<size_t>(bytesRead);
|
auto const headerLen = static_cast<size_t>(bytesRead);
|
||||||
#else
|
#else
|
||||||
inFile.read(reinterpret_cast<char*>(header), sizeof(TGA_HEADER));
|
inFile.read(reinterpret_cast<char*>(header), TGA_HEADER_LEN);
|
||||||
if (!inFile)
|
if (!inFile)
|
||||||
return E_FAIL;
|
return E_FAIL;
|
||||||
|
|
||||||
size_t headerLen = sizeof(TGA_HEADER);
|
size_t headerLen = TGA_HEADER_LEN;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
size_t offset;
|
size_t offset;
|
||||||
@ -1674,7 +1831,7 @@ HRESULT DirectX::LoadFromTGAFile(
|
|||||||
if (remaining == 0)
|
if (remaining == 0)
|
||||||
return E_FAIL;
|
return E_FAIL;
|
||||||
|
|
||||||
if (offset > sizeof(TGA_HEADER))
|
if (offset > TGA_HEADER_LEN)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
// Skip past the id string
|
// Skip past the id string
|
||||||
@ -1698,7 +1855,7 @@ HRESULT DirectX::LoadFromTGAFile(
|
|||||||
|
|
||||||
bool opaquealpha = false;
|
bool opaquealpha = false;
|
||||||
|
|
||||||
if (!(convFlags & (CONV_FLAGS_RLE | CONV_FLAGS_EXPAND | CONV_FLAGS_INVERTX)) && (convFlags & CONV_FLAGS_INVERTY))
|
if (!(convFlags & (CONV_FLAGS_RLE | CONV_FLAGS_EXPAND | CONV_FLAGS_INVERTX | CONV_FLAGS_PALETTED)) && (convFlags & CONV_FLAGS_INVERTY))
|
||||||
{
|
{
|
||||||
// This case we can read directly into the image buffer in place
|
// This case we can read directly into the image buffer in place
|
||||||
if (remaining < image.GetPixelsSize())
|
if (remaining < image.GetPixelsSize())
|
||||||
@ -1923,7 +2080,7 @@ HRESULT DirectX::LoadFromTGAFile(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else // RLE || EXPAND || INVERTX || !INVERTY
|
else // RLE || EXPAND || INVERTX || PALETTED || !INVERTY
|
||||||
{
|
{
|
||||||
std::unique_ptr<uint8_t[]> temp(new (std::nothrow) uint8_t[remaining]);
|
std::unique_ptr<uint8_t[]> temp(new (std::nothrow) uint8_t[remaining]);
|
||||||
if (!temp)
|
if (!temp)
|
||||||
@ -1953,13 +2110,27 @@ HRESULT DirectX::LoadFromTGAFile(
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
size_t paletteOffset = 0;
|
||||||
|
uint8_t palette[256 * 4] = {};
|
||||||
|
if (convFlags & CONV_FLAGS_PALETTED)
|
||||||
|
{
|
||||||
|
hr = ReadPalette(header, temp.get(), remaining, flags, palette, paletteOffset);
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
image.Release();
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (convFlags & CONV_FLAGS_RLE)
|
if (convFlags & CONV_FLAGS_RLE)
|
||||||
{
|
{
|
||||||
hr = UncompressPixels(temp.get(), remaining, flags, image.GetImage(0, 0, 0), convFlags);
|
hr = UncompressPixels(temp.get() + paletteOffset, remaining - paletteOffset,
|
||||||
|
flags, image.GetImage(0, 0, 0), convFlags);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
hr = CopyPixels(temp.get(), remaining, flags, image.GetImage(0, 0, 0), convFlags);
|
hr = CopyPixels(temp.get() + paletteOffset, remaining - paletteOffset,
|
||||||
|
flags, image.GetImage(0, 0, 0), convFlags, palette);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
@ -2089,7 +2260,7 @@ HRESULT DirectX::SaveToTGAMemory(
|
|||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
return hr;
|
return hr;
|
||||||
|
|
||||||
hr = blob.Initialize(sizeof(TGA_HEADER)
|
hr = blob.Initialize(TGA_HEADER_LEN
|
||||||
+ slicePitch
|
+ slicePitch
|
||||||
+ (metadata ? sizeof(TGA_EXTENSION) : 0)
|
+ (metadata ? sizeof(TGA_EXTENSION) : 0)
|
||||||
+ sizeof(TGA_FOOTER));
|
+ sizeof(TGA_FOOTER));
|
||||||
@ -2101,8 +2272,8 @@ HRESULT DirectX::SaveToTGAMemory(
|
|||||||
assert(destPtr != nullptr);
|
assert(destPtr != nullptr);
|
||||||
|
|
||||||
uint8_t* dPtr = destPtr;
|
uint8_t* dPtr = destPtr;
|
||||||
memcpy(dPtr, &tga_header, sizeof(TGA_HEADER));
|
memcpy(dPtr, &tga_header, TGA_HEADER_LEN);
|
||||||
dPtr += sizeof(TGA_HEADER);
|
dPtr += TGA_HEADER_LEN;
|
||||||
|
|
||||||
const uint8_t* pPixels = image.pixels;
|
const uint8_t* pPixels = image.pixels;
|
||||||
assert(pPixels);
|
assert(pPixels);
|
||||||
@ -2241,15 +2412,15 @@ HRESULT DirectX::SaveToTGAFile(
|
|||||||
// Write header
|
// Write header
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
DWORD bytesWritten;
|
DWORD bytesWritten;
|
||||||
if (!WriteFile(hFile.get(), &tga_header, sizeof(TGA_HEADER), &bytesWritten, nullptr))
|
if (!WriteFile(hFile.get(), &tga_header, TGA_HEADER_LEN, &bytesWritten, nullptr))
|
||||||
{
|
{
|
||||||
return HRESULT_FROM_WIN32(GetLastError());
|
return HRESULT_FROM_WIN32(GetLastError());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bytesWritten != sizeof(TGA_HEADER))
|
if (bytesWritten != TGA_HEADER_LEN)
|
||||||
return E_FAIL;
|
return E_FAIL;
|
||||||
#else
|
#else
|
||||||
outFile.write(reinterpret_cast<char*>(&tga_header), sizeof(TGA_HEADER));
|
outFile.write(reinterpret_cast<char*>(&tga_header), TGA_HEADER_LEN);
|
||||||
if (!outFile)
|
if (!outFile)
|
||||||
return E_FAIL;
|
return E_FAIL;
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user