Fixed mipmap calculation. Added more error handling.

This commit is contained in:
Branimir Karadžić
2017-05-24 15:04:07 -07:00
parent 1d9502f902
commit 279ec6a2f3
5 changed files with 88 additions and 44 deletions

View File

@@ -9,7 +9,7 @@
#include <stdint.h> // uint32_t
#include <stdlib.h> // NULL
#define BIMG_API_VERSION UINT32_C(4)
#define BIMG_API_VERSION UINT32_C(5)
namespace bx
{
@@ -460,6 +460,7 @@ namespace bimg
bool imageParse(
ImageContainer& _imageContainer
, bx::ReaderSeekerI* _reader
, bx::Error* _err
);
///
@@ -467,6 +468,7 @@ namespace bimg
ImageContainer& _imageContainer
, const void* _data
, uint32_t _size
, bx::Error* _err = NULL
);
///
@@ -474,6 +476,7 @@ namespace bimg
bx::AllocatorI* _allocator
, const void* _src
, uint32_t _size
, bx::Error* _err
);
///
@@ -481,6 +484,7 @@ namespace bimg
bx::AllocatorI* _allocator
, const void* _src
, uint32_t _size
, bx::Error* _err
);
///
@@ -488,6 +492,7 @@ namespace bimg
bx::AllocatorI* _allocator
, const void* _src
, uint32_t _size
, bx::Error* _err
);
///

View File

@@ -16,6 +16,7 @@ namespace bimg
, const void* _data
, uint32_t _size
, TextureFormat::Enum _dstFormat = TextureFormat::Count
, bx::Error* _err = NULL
);
} // namespace bimg

View File

@@ -252,14 +252,13 @@ namespace bimg
const uint16_t minBlockX = blockInfo.minBlockX;
const uint16_t minBlockY = blockInfo.minBlockY;
_width = bx::uint16_max(blockWidth * minBlockX, ( (_width + blockWidth - 1) / blockWidth)*blockWidth);
_width = bx::uint16_max(blockWidth * minBlockX, ( (_width + blockWidth - 1) / blockWidth )*blockWidth);
_height = bx::uint16_max(blockHeight * minBlockY, ( (_height + blockHeight - 1) / blockHeight)*blockHeight);
_depth = bx::uint16_max(1, _depth);
uint32_t max = bx::uint32_max(_width, bx::uint32_max(_height, _depth) );
uint32_t numMips = bx::uint32_max(1, uint8_t(bx::flog2(float(max) ) ) );
uint8_t numMips = calcNumMips(true, _width, _height, _depth);
return uint8_t(numMips);
return numMips;
}
uint32_t imageGetSize(TextureInfo* _info, uint16_t _width, uint16_t _height, uint16_t _depth, bool _cubeMap, bool _hasMips, uint16_t _numLayers, TextureFormat::Enum _format)
@@ -904,10 +903,10 @@ namespace bimg
return output;
}
typedef bool (*ParseFn)(ImageContainer&, bx::ReaderSeekerI*);
typedef bool (*ParseFn)(ImageContainer&, bx::ReaderSeekerI*, bx::Error*);
template<uint32_t magicT, ParseFn parseFnT>
ImageContainer* imageParseT(bx::AllocatorI* _allocator, const void* _src, uint32_t _size)
ImageContainer* imageParseT(bx::AllocatorI* _allocator, const void* _src, uint32_t _size, bx::Error* _err)
{
bx::MemoryReader reader(_src, _size);
@@ -916,7 +915,7 @@ namespace bimg
ImageContainer imageContainer;
if (magicT != magic
|| !parseFnT(imageContainer, &reader) )
|| !parseFnT(imageContainer, &reader, _err) )
{
return NULL;
}
@@ -1747,7 +1746,7 @@ namespace bimg
_depth = bx::uint16_max(1, _depth);
_numLayers = bx::uint16_max(1, _numLayers);
const uint8_t numMips = _hasMips ? imageGetNumMips(_format, _width, _height) : 1;
const uint8_t numMips = _hasMips ? imageGetNumMips(_format, _width, _height, _depth) : 1;
uint32_t size = imageGetSize(NULL, _width, _height, _depth, _cubeMap, _hasMips, _numLayers, _format);
ImageContainer* imageContainer = (ImageContainer*)BX_ALLOC(_allocator, size + sizeof(ImageContainer) );
@@ -1994,9 +1993,8 @@ namespace bimg
{ 32, { 0xffffffff, 0x00000000, 0x00000000, 0x00000000 }, TextureFormat::R32U },
};
bool imageParseDds(ImageContainer& _imageContainer, bx::ReaderSeekerI* _reader)
bool imageParseDds(ImageContainer& _imageContainer, bx::ReaderSeekerI* _reader, bx::Error* _err)
{
bx::Error* _err = NULL;
BX_ERROR_SCOPE(_err);
int32_t total = 0;
@@ -2012,12 +2010,17 @@ namespace bimg
uint32_t flags;
total += bx::read(_reader, flags, _err);
if (!_err->isOk()
|| (flags & (DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT) ) != (DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT) )
if (!_err->isOk() )
{
return false;
}
if ( (flags & (DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT) ) != (DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT) )
{
BX_ERROR_SET(_err, BIMG_ERROR, "DDS: Invalid flags.");
return false;
}
uint32_t height;
total += bx::read(_reader, height, _err);
@@ -2081,18 +2084,24 @@ namespace bimg
total += bx::read(_reader, miscFlags2, _err);
}
if (!_err->isOk()
|| (caps[0] & DDSCAPS_TEXTURE) == 0)
if (!_err->isOk() )
{
return false;
}
if ( (caps[0] & DDSCAPS_TEXTURE) == 0)
{
BX_ERROR_SET(_err, BIMG_ERROR, "DDS: Unsupported caps.");
return false;
}
bool cubeMap = 0 != (caps[1] & DDSCAPS2_CUBEMAP);
if (cubeMap)
{
if ( (caps[1] & DSCAPS2_CUBEMAP_ALLSIDES) != DSCAPS2_CUBEMAP_ALLSIDES)
{
// partial cube map is not supported.
BX_ERROR_SET(_err, BIMG_ERROR, "DDS: Incomplete cubemap.");
return false;
}
}
@@ -2144,6 +2153,12 @@ namespace bimg
}
}
if (TextureFormat::Unknown == format)
{
BX_ERROR_SET(_err, BIMG_ERROR, "DDS: Unknown texture format.");
return false;
}
_imageContainer.m_allocator = NULL;
_imageContainer.m_data = NULL;
_imageContainer.m_size = 0;
@@ -2160,12 +2175,12 @@ namespace bimg
_imageContainer.m_ktxLE = false;
_imageContainer.m_srgb = srgb;
return TextureFormat::Unknown != format;
return true;
}
ImageContainer* imageParseDds(bx::AllocatorI* _allocator, const void* _src, uint32_t _size)
ImageContainer* imageParseDds(bx::AllocatorI* _allocator, const void* _src, uint32_t _size, bx::Error* _err)
{
return imageParseT<DDS_MAGIC, imageParseDds>(_allocator, _src, _size);
return imageParseT<DDS_MAGIC, imageParseDds>(_allocator, _src, _size, _err);
}
// KTX
@@ -2380,8 +2395,10 @@ namespace bimg
{ KTX_RGB, TextureFormat::RGB8 },
};
bool imageParseKtx(ImageContainer& _imageContainer, bx::ReaderSeekerI* _reader)
bool imageParseKtx(ImageContainer& _imageContainer, bx::ReaderSeekerI* _reader, bx::Error* _err)
{
BX_ERROR_SCOPE(_err);
uint8_t identifier[8];
bx::read(_reader, identifier);
@@ -2478,9 +2495,9 @@ namespace bimg
return TextureFormat::Unknown != format;
}
ImageContainer* imageParseKtx(bx::AllocatorI* _allocator, const void* _src, uint32_t _size)
ImageContainer* imageParseKtx(bx::AllocatorI* _allocator, const void* _src, uint32_t _size, bx::Error* _err)
{
return imageParseT<KTX_MAGIC, imageParseKtx>(_allocator, _src, _size);
return imageParseT<KTX_MAGIC, imageParseKtx>(_allocator, _src, _size, _err);
}
// PVR3
@@ -2564,8 +2581,10 @@ namespace bimg
{ PVR3_RGB10A2, PVR3_CHANNEL_TYPE_ANY, TextureFormat::RGB10A2 },
};
bool imageParsePvr3(ImageContainer& _imageContainer, bx::ReaderSeekerI* _reader)
bool imageParsePvr3(ImageContainer& _imageContainer, bx::ReaderSeekerI* _reader, bx::Error* _err)
{
BX_ERROR_SCOPE(_err);
uint32_t flags;
bx::read(_reader, flags);
@@ -2634,27 +2653,29 @@ namespace bimg
return TextureFormat::Unknown != format;
}
ImageContainer* imageParsePvr3(bx::AllocatorI* _allocator, const void* _src, uint32_t _size)
ImageContainer* imageParsePvr3(bx::AllocatorI* _allocator, const void* _src, uint32_t _size, bx::Error* _err)
{
return imageParseT<PVR3_MAGIC, imageParsePvr3>(_allocator, _src, _size);
return imageParseT<PVR3_MAGIC, imageParsePvr3>(_allocator, _src, _size, _err);
}
bool imageParse(ImageContainer& _imageContainer, bx::ReaderSeekerI* _reader)
bool imageParse(ImageContainer& _imageContainer, bx::ReaderSeekerI* _reader, bx::Error* _err)
{
BX_ERROR_SCOPE(_err);
uint32_t magic;
bx::read(_reader, magic);
bx::read(_reader, magic, _err);
if (DDS_MAGIC == magic)
{
return imageParseDds(_imageContainer, _reader);
return imageParseDds(_imageContainer, _reader, _err);
}
else if (KTX_MAGIC == magic)
{
return imageParseKtx(_imageContainer, _reader);
return imageParseKtx(_imageContainer, _reader, _err);
}
else if (PVR3_MAGIC == magic)
{
return imageParsePvr3(_imageContainer, _reader);
return imageParsePvr3(_imageContainer, _reader, _err);
}
else if (BIMG_CHUNK_MAGIC_TEX == magic)
{
@@ -2685,17 +2706,21 @@ namespace bimg
_imageContainer.m_ktxLE = false;
_imageContainer.m_srgb = false;
return true;
return _err->isOk();
}
BX_TRACE("Unrecognized image format (magic: 0x%08x)!", magic);
BX_ERROR_SET(_err, BIMG_ERROR, "Unrecognized image format.");
return false;
}
bool imageParse(ImageContainer& _imageContainer, const void* _data, uint32_t _size)
bool imageParse(ImageContainer& _imageContainer, const void* _data, uint32_t _size, bx::Error* _err)
{
BX_ERROR_SCOPE(_err);
bx::MemoryReader reader(_data, _size);
return imageParse(_imageContainer, &reader);
return imageParse(_imageContainer, &reader, _err);
}
void imageDecodeToBgra8(void* _dst, const void* _src, uint32_t _width, uint32_t _height, uint32_t _dstPitch, TextureFormat::Enum _srcFormat)

View File

@@ -67,8 +67,10 @@ BX_PRAGMA_DIAGNOSTIC_POP();
namespace bimg
{
static ImageContainer* imageParseLodePng(bx::AllocatorI* _allocator, const void* _data, uint32_t _size)
static ImageContainer* imageParseLodePng(bx::AllocatorI* _allocator, const void* _data, uint32_t _size, bx::Error* _err)
{
BX_ERROR_SCOPE(_err);
static uint8_t pngMagic[] = { 0x89, 0x50, 0x4E, 0x47, 0x0d, 0x0a };
if (0 != bx::memCmp(_data, pngMagic, sizeof(pngMagic) ) )
@@ -225,8 +227,10 @@ namespace bimg
return output;
}
static ImageContainer* imageParseTinyExr(bx::AllocatorI* _allocator, const void* _data, uint32_t _size)
static ImageContainer* imageParseTinyExr(bx::AllocatorI* _allocator, const void* _data, uint32_t _size, bx::Error* _err)
{
BX_ERROR_SCOPE(_err);
EXRVersion exrVersion;
int result = ParseEXRVersionFromMemory(&exrVersion, (uint8_t*)_data, _size);
if (TINYEXR_SUCCESS != result)
@@ -362,8 +366,10 @@ namespace bimg
return output;
}
static ImageContainer* imageParseStbImage(bx::AllocatorI* _allocator, const void* _data, uint32_t _size)
static ImageContainer* imageParseStbImage(bx::AllocatorI* _allocator, const void* _data, uint32_t _size, bx::Error* _err)
{
BX_ERROR_SCOPE(_err);
const int isHdr = stbi_is_hdr_from_memory((const uint8_t*)_data, (int)_size);
void* data;
@@ -406,14 +412,16 @@ namespace bimg
return output;
}
ImageContainer* imageParse(bx::AllocatorI* _allocator, const void* _data, uint32_t _size, TextureFormat::Enum _dstFormat)
ImageContainer* imageParse(bx::AllocatorI* _allocator, const void* _data, uint32_t _size, TextureFormat::Enum _dstFormat, bx::Error* _err)
{
ImageContainer* input = imageParseDds (_allocator, _data, _size) ;
input = NULL == input ? imageParseKtx (_allocator, _data, _size) : input;
input = NULL == input ? imageParsePvr3 (_allocator, _data, _size) : input;
input = NULL == input ? imageParseLodePng (_allocator, _data, _size) : input;
input = NULL == input ? imageParseTinyExr (_allocator, _data, _size) : input;
input = NULL == input ? imageParseStbImage(_allocator, _data, _size) : input;
BX_ERROR_SCOPE(_err);
ImageContainer* input = imageParseDds (_allocator, _data, _size, _err) ;
input = NULL == input ? imageParseKtx (_allocator, _data, _size, _err) : input;
input = NULL == input ? imageParsePvr3 (_allocator, _data, _size, _err) : input;
input = NULL == input ? imageParseLodePng (_allocator, _data, _size, _err) : input;
input = NULL == input ? imageParseTinyExr (_allocator, _data, _size, _err) : input;
input = NULL == input ? imageParseStbImage(_allocator, _data, _size, _err) : input;
if (NULL == input)
{

View File

@@ -25,7 +25,7 @@
#include <string>
#define BIMG_TEXTUREC_VERSION_MAJOR 1
#define BIMG_TEXTUREC_VERSION_MINOR 3
#define BIMG_TEXTUREC_VERSION_MINOR 4
struct Options
{
@@ -80,7 +80,12 @@ bimg::ImageContainer* convert(bx::AllocatorI* _allocator, const void* _inputData
const uint8_t* inputData = (uint8_t*)_inputData;
bimg::ImageContainer* output = NULL;
bimg::ImageContainer* input = bimg::imageParse(_allocator, inputData, _inputSize);
bimg::ImageContainer* input = bimg::imageParse(_allocator, inputData, _inputSize, bimg::TextureFormat::Count, _err);
if (!_err->isOk() )
{
return NULL;
}
if (NULL != input)
{