From 21518f201f5359b5f5b78c3e49cd52fcaf8709a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Branimir=20Karad=C5=BEi=C4=87?= Date: Thu, 2 Jun 2016 16:38:26 -0700 Subject: [PATCH] texturec: Preserve precision of input texture. --- 3rdparty/lodepng/lodepng.cpp | 4 +- 3rdparty/tinyexr/tinyexr.h | 2 +- examples/common/bgfx_utils.cpp | 104 ++++++++--- examples/common/nanovg/nanovg.cpp | 26 +++ src/image.cpp | 274 +++++++++++++++++++--------- src/image.h | 13 ++ tools/texturec/texturec.cpp | 294 +++++++++++++++++++++++++----- 7 files changed, 556 insertions(+), 161 deletions(-) diff --git a/3rdparty/lodepng/lodepng.cpp b/3rdparty/lodepng/lodepng.cpp index 8c78758ff..7baf7f927 100644 --- a/3rdparty/lodepng/lodepng.cpp +++ b/3rdparty/lodepng/lodepng.cpp @@ -3475,7 +3475,7 @@ unsigned lodepng_convert(unsigned char* out, const unsigned char* in, { size_t palettesize = mode_out->palettesize; const unsigned char* palette = mode_out->palette; - size_t palsize = 1u << mode_out->bitdepth; + size_t palsize = size_t(1) << mode_out->bitdepth; /*if the user specified output palette but did not give the values, assume they want the values of the input color type (assuming that one is palette). Note that we never create a new palette ourselves.*/ @@ -3489,7 +3489,7 @@ unsigned lodepng_convert(unsigned char* out, const unsigned char* in, for(i = 0; i != palsize; ++i) { const unsigned char* p = &palette[i * 4]; - color_tree_add(&tree, p[0], p[1], p[2], p[3], i); + color_tree_add(&tree, p[0], p[1], p[2], p[3], (unsigned int)(i)); } } diff --git a/3rdparty/tinyexr/tinyexr.h b/3rdparty/tinyexr/tinyexr.h index 90cd29584..a30accada 100644 --- a/3rdparty/tinyexr/tinyexr.h +++ b/3rdparty/tinyexr/tinyexr.h @@ -8031,7 +8031,7 @@ bool hufBuildDecTable(const long long *hcode, // i : encoding table HufDec *pl = hdecod + (c << (HUF_DECBITS - l)); - for (long long i = 1 << (HUF_DECBITS - l); i > 0; i--, pl++) { + for (long long i = (long long)1 << (HUF_DECBITS - l); i > 0; i--, pl++) { if (pl->len || pl->p) { // // Error: a short code or a long code has diff --git a/examples/common/bgfx_utils.cpp b/examples/common/bgfx_utils.cpp index 8298e8d2f..18db066f4 100644 --- a/examples/common/bgfx_utils.cpp +++ b/examples/common/bgfx_utils.cpp @@ -25,10 +25,9 @@ namespace stl = tinystl; #define LODEPNG_NO_COMPILE_DISK #define LODEPNG_NO_COMPILE_ANCILLARY_CHUNKS #define LODEPNG_NO_COMPILE_ERROR_TEXT -//#define LODEPNG_NO_COMPILE_ALLOCATORS +#define LODEPNG_NO_COMPILE_ALLOCATORS #define LODEPNG_NO_COMPILE_CPP -#include -#include +#include #include "bgfx_utils.h" @@ -163,8 +162,10 @@ bgfx::ProgramHandle loadProgram(const char* _vsName, const char* _fsName) return loadProgram(entry::getFileReader(), _vsName, _fsName); } -//typedef unsigned char stbi_uc; -//extern "C" stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); +typedef unsigned char stbi_uc; +extern "C" stbi_uc* stbi_load_from_memory(stbi_uc const* _buffer, int _len, int* _x, int* _y, int* _comp, int _req_comp); +extern "C" void stbi_image_free(void* _ptr); +extern void lodepng_free(void* _ptr); bgfx::TextureHandle loadTexture(bx::FileReaderI* _reader, const char* _filePath, uint32_t _flags, uint8_t _skip, bgfx::TextureInfo* _info) { @@ -196,44 +197,94 @@ bgfx::TextureHandle loadTexture(bx::FileReaderI* _reader, const char* _filePath, uint32_t width = 0; uint32_t height = 0; + typedef void (*ReleaseFn)(void* _ptr); + ReleaseFn release = stbi_image_free; + uint8_t* out = NULL; static uint8_t pngMagic[] = { 0x89, 0x50, 0x4E, 0x47, 0x0d, 0x0a }; if (0 == memcmp(data, pngMagic, sizeof(pngMagic) ) ) { + release = lodepng_free; + unsigned error; LodePNGState state; lodepng_state_init(&state); state.decoder.color_convert = 0; error = lodepng_decode(&out, &width, &height, &state, (uint8_t*)data, size); - if (0 != error) + if (0 == error) { switch (state.info_raw.bitdepth) { - case 16: - for (uint32_t ii = 0, num = width*height; ii < num; ++ii) + case 8: + switch (state.info_raw.colortype) { - uint16_t* rgba = (uint16_t*)out + ii*4; - rgba[0] = bx::toHostEndian(rgba[0], false); - rgba[1] = bx::toHostEndian(rgba[1], false); - rgba[2] = bx::toHostEndian(rgba[2], false); - rgba[3] = bx::toHostEndian(rgba[3], false); + case LCT_GREY: + format = bgfx::TextureFormat::R8; + bpp = 8; + break; + + case LCT_GREY_ALPHA: + format = bgfx::TextureFormat::RG8; + bpp = 16; + break; + + case LCT_RGB: + format = bgfx::TextureFormat::RGB8; + bpp = 24; + break; + + case LCT_RGBA: + format = bgfx::TextureFormat::RGBA8; + bpp = 32; + break; + + case LCT_PALETTE: + break; } - format = bgfx::TextureFormat::RGBA16; - bpp = 64; break; - case 32: - for (uint32_t ii = 0, num = width*height; ii < num; ++ii) + case 16: + switch (state.info_raw.colortype) { - uint32_t* rgba = (uint32_t*)out + ii*4; - rgba[0] = bx::toHostEndian(rgba[0], false); - rgba[1] = bx::toHostEndian(rgba[1], false); - rgba[2] = bx::toHostEndian(rgba[2], false); - rgba[3] = bx::toHostEndian(rgba[3], false); + case LCT_GREY: + for (uint32_t ii = 0, num = width*height; ii < num; ++ii) + { + uint16_t* rgba = (uint16_t*)out + ii*4; + rgba[0] = bx::toHostEndian(rgba[0], false); + } + format = bgfx::TextureFormat::R16; + bpp = 16; + break; + + case LCT_GREY_ALPHA: + for (uint32_t ii = 0, num = width*height; ii < num; ++ii) + { + uint16_t* rgba = (uint16_t*)out + ii*4; + rgba[0] = bx::toHostEndian(rgba[0], false); + rgba[1] = bx::toHostEndian(rgba[1], false); + } + format = bgfx::TextureFormat::R16; + bpp = 16; + break; + + case LCT_RGBA: + for (uint32_t ii = 0, num = width*height; ii < num; ++ii) + { + uint16_t* rgba = (uint16_t*)out + ii*4; + rgba[0] = bx::toHostEndian(rgba[0], false); + rgba[1] = bx::toHostEndian(rgba[1], false); + rgba[2] = bx::toHostEndian(rgba[2], false); + rgba[3] = bx::toHostEndian(rgba[3], false); + } + format = bgfx::TextureFormat::RGBA16; + bpp = 64; + break; + + case LCT_RGB: + case LCT_PALETTE: + break; } - format = bgfx::TextureFormat::RGBA32U; - bpp = 128; break; default: @@ -245,7 +296,7 @@ bgfx::TextureHandle loadTexture(bx::FileReaderI* _reader, const char* _filePath, } else { - int comp = 0; + int comp = 0; out = stbi_load_from_memory( (uint8_t*)data, size, (int*)&width, (int*)&height, &comp, 4); } @@ -258,8 +309,7 @@ bgfx::TextureHandle loadTexture(bx::FileReaderI* _reader, const char* _filePath, , _flags , bgfx::copy(out, width*height*bpp/8) ); - - free(out); + release(out); if (NULL != _info) { diff --git a/examples/common/nanovg/nanovg.cpp b/examples/common/nanovg/nanovg.cpp index 62a1ce539..148749051 100644 --- a/examples/common/nanovg/nanovg.cpp +++ b/examples/common/nanovg/nanovg.cpp @@ -34,10 +34,36 @@ BX_PRAGMA_DIAGNOSTIC_IGNORED_GCC("-Wunused-result"); #include "fontstash.h" BX_PRAGMA_DIAGNOSTIC_POP(); +#define LODEPNG_NO_COMPILE_ENCODER +#define LODEPNG_NO_COMPILE_DISK +#define LODEPNG_NO_COMPILE_ANCILLARY_CHUNKS +#define LODEPNG_NO_COMPILE_ERROR_TEXT +#define LODEPNG_NO_COMPILE_ALLOCATORS +#define LODEPNG_NO_COMPILE_CPP +#include + +void* lodepng_malloc(size_t _size) +{ + return ::malloc(_size); +} + +void* lodepng_realloc(void* _ptr, size_t _size) +{ + return ::realloc(_ptr, _size); +} + +void lodepng_free(void* _ptr) +{ + ::free(_ptr); +} + BX_PRAGMA_DIAGNOSTIC_PUSH(); BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC("-Wmissing-field-initializers"); BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC("-Wshadow"); BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC("-Wint-to-pointer-cast") +#define STBI_MALLOC(_size) lodepng_malloc(_size) +#define STBI_REALLOC(_ptr, _size) lodepng_realloc(_ptr, _size) +#define STBI_FREE(_ptr) lodepng_free(_ptr) #define STB_IMAGE_IMPLEMENTATION #include BX_PRAGMA_DIAGNOSTIC_POP(); diff --git a/src/image.cpp b/src/image.cpp index 8a93cee7d..cccbfd77f 100644 --- a/src/image.cpp +++ b/src/image.cpp @@ -10,92 +10,93 @@ namespace bgfx { static const ImageBlockInfo s_imageBlockInfo[] = { - // +------------------------------- bits per pixel - // | +---------------------------- block width - // | | +------------------------- block height - // | | | +--------------------- block size - // | | | | +------------------ min blocks x - // | | | | | +--------------- min blocks y - // | | | | | | +----------- depth bits - // | | | | | | | +-------- stencil bits - // | | | | | | | | +----- encoding type - // | | | | | | | | | - { 4, 4, 4, 8, 1, 1, 0, 0, uint8_t(EncodingType::Unorm) }, // BC1 - { 8, 4, 4, 16, 1, 1, 0, 0, uint8_t(EncodingType::Unorm) }, // BC2 - { 8, 4, 4, 16, 1, 1, 0, 0, uint8_t(EncodingType::Unorm) }, // BC3 - { 4, 4, 4, 8, 1, 1, 0, 0, uint8_t(EncodingType::Unorm) }, // BC4 - { 8, 4, 4, 16, 1, 1, 0, 0, uint8_t(EncodingType::Unorm) }, // BC5 - { 8, 4, 4, 16, 1, 1, 0, 0, uint8_t(EncodingType::Unorm) }, // BC6H - { 8, 4, 4, 16, 1, 1, 0, 0, uint8_t(EncodingType::Unorm) }, // BC7 - { 4, 4, 4, 8, 1, 1, 0, 0, uint8_t(EncodingType::Unorm) }, // ETC1 - { 4, 4, 4, 8, 1, 1, 0, 0, uint8_t(EncodingType::Unorm) }, // ETC2 - { 8, 4, 4, 16, 1, 1, 0, 0, uint8_t(EncodingType::Unorm) }, // ETC2A - { 4, 4, 4, 8, 1, 1, 0, 0, uint8_t(EncodingType::Unorm) }, // ETC2A1 - { 2, 8, 4, 8, 2, 2, 0, 0, uint8_t(EncodingType::Unorm) }, // PTC12 - { 4, 4, 4, 8, 2, 2, 0, 0, uint8_t(EncodingType::Unorm) }, // PTC14 - { 2, 8, 4, 8, 2, 2, 0, 0, uint8_t(EncodingType::Unorm) }, // PTC12A - { 4, 4, 4, 8, 2, 2, 0, 0, uint8_t(EncodingType::Unorm) }, // PTC14A - { 2, 8, 4, 8, 2, 2, 0, 0, uint8_t(EncodingType::Unorm) }, // PTC22 - { 4, 4, 4, 8, 2, 2, 0, 0, uint8_t(EncodingType::Unorm) }, // PTC24 - { 0, 0, 0, 0, 0, 0, 0, 0, uint8_t(EncodingType::Count) }, // Unknown - { 1, 8, 1, 1, 1, 1, 0, 0, uint8_t(EncodingType::Unorm) }, // R1 - { 8, 1, 1, 1, 1, 1, 0, 0, uint8_t(EncodingType::Unorm) }, // A8 - { 8, 1, 1, 1, 1, 1, 0, 0, uint8_t(EncodingType::Unorm) }, // R8 - { 8, 1, 1, 1, 1, 1, 0, 0, uint8_t(EncodingType::Int ) }, // R8I - { 8, 1, 1, 1, 1, 1, 0, 0, uint8_t(EncodingType::Uint ) }, // R8U - { 8, 1, 1, 1, 1, 1, 0, 0, uint8_t(EncodingType::Snorm) }, // R8S - { 16, 1, 1, 2, 1, 1, 0, 0, uint8_t(EncodingType::Unorm) }, // R16 - { 16, 1, 1, 2, 1, 1, 0, 0, uint8_t(EncodingType::Int ) }, // R16I - { 16, 1, 1, 2, 1, 1, 0, 0, uint8_t(EncodingType::Uint ) }, // R16U - { 16, 1, 1, 2, 1, 1, 0, 0, uint8_t(EncodingType::Float) }, // R16F - { 16, 1, 1, 2, 1, 1, 0, 0, uint8_t(EncodingType::Snorm) }, // R16S - { 32, 1, 1, 4, 1, 1, 0, 0, uint8_t(EncodingType::Int ) }, // R32I - { 32, 1, 1, 4, 1, 1, 0, 0, uint8_t(EncodingType::Uint ) }, // R32U - { 32, 1, 1, 4, 1, 1, 0, 0, uint8_t(EncodingType::Float) }, // R32F - { 16, 1, 1, 2, 1, 1, 0, 0, uint8_t(EncodingType::Unorm) }, // RG8 - { 16, 1, 1, 2, 1, 1, 0, 0, uint8_t(EncodingType::Int ) }, // RG8I - { 16, 1, 1, 2, 1, 1, 0, 0, uint8_t(EncodingType::Uint ) }, // RG8U - { 16, 1, 1, 2, 1, 1, 0, 0, uint8_t(EncodingType::Snorm) }, // RG8S - { 32, 1, 1, 4, 1, 1, 0, 0, uint8_t(EncodingType::Unorm) }, // RG16 - { 32, 1, 1, 4, 1, 1, 0, 0, uint8_t(EncodingType::Int ) }, // RG16I - { 32, 1, 1, 4, 1, 1, 0, 0, uint8_t(EncodingType::Uint ) }, // RG16U - { 32, 1, 1, 4, 1, 1, 0, 0, uint8_t(EncodingType::Float) }, // RG16F - { 32, 1, 1, 4, 1, 1, 0, 0, uint8_t(EncodingType::Snorm) }, // RG16S - { 64, 1, 1, 8, 1, 1, 0, 0, uint8_t(EncodingType::Int ) }, // RG32I - { 64, 1, 1, 8, 1, 1, 0, 0, uint8_t(EncodingType::Uint ) }, // RG32U - { 64, 1, 1, 8, 1, 1, 0, 0, uint8_t(EncodingType::Float) }, // RG32F - { 24, 1, 1, 3, 1, 1, 0, 0, uint8_t(EncodingType::Unorm) }, // RGB8 - { 24, 1, 1, 3, 1, 1, 0, 0, uint8_t(EncodingType::Int ) }, // RGB8I - { 24, 1, 1, 3, 1, 1, 0, 0, uint8_t(EncodingType::Uint ) }, // RGB8U - { 24, 1, 1, 3, 1, 1, 0, 0, uint8_t(EncodingType::Snorm) }, // RGB8S - { 32, 1, 1, 4, 1, 1, 0, 0, uint8_t(EncodingType::Float) }, // RGB9E5F - { 32, 1, 1, 4, 1, 1, 0, 0, uint8_t(EncodingType::Unorm) }, // BGRA8 - { 32, 1, 1, 4, 1, 1, 0, 0, uint8_t(EncodingType::Unorm) }, // RGBA8 - { 32, 1, 1, 4, 1, 1, 0, 0, uint8_t(EncodingType::Int ) }, // RGBA8I - { 32, 1, 1, 4, 1, 1, 0, 0, uint8_t(EncodingType::Uint ) }, // RGBA8U - { 32, 1, 1, 4, 1, 1, 0, 0, uint8_t(EncodingType::Snorm) }, // RGBA8S - { 64, 1, 1, 8, 1, 1, 0, 0, uint8_t(EncodingType::Unorm) }, // RGBA16 - { 64, 1, 1, 8, 1, 1, 0, 0, uint8_t(EncodingType::Int ) }, // RGBA16I - { 64, 1, 1, 8, 1, 1, 0, 0, uint8_t(EncodingType::Uint ) }, // RGBA16U - { 64, 1, 1, 8, 1, 1, 0, 0, uint8_t(EncodingType::Float) }, // RGBA16F - { 64, 1, 1, 8, 1, 1, 0, 0, uint8_t(EncodingType::Snorm) }, // RGBA16S - { 128, 1, 1, 16, 1, 1, 0, 0, uint8_t(EncodingType::Int ) }, // RGBA32I - { 128, 1, 1, 16, 1, 1, 0, 0, uint8_t(EncodingType::Uint ) }, // RGBA32U - { 128, 1, 1, 16, 1, 1, 0, 0, uint8_t(EncodingType::Float) }, // RGBA32F - { 16, 1, 1, 2, 1, 1, 0, 0, uint8_t(EncodingType::Unorm) }, // R5G6B5 - { 16, 1, 1, 2, 1, 1, 0, 0, uint8_t(EncodingType::Unorm) }, // RGBA4 - { 16, 1, 1, 2, 1, 1, 0, 0, uint8_t(EncodingType::Unorm) }, // RGB5A1 - { 32, 1, 1, 4, 1, 1, 0, 0, uint8_t(EncodingType::Unorm) }, // RGB10A2 - { 32, 1, 1, 4, 1, 1, 0, 0, uint8_t(EncodingType::Unorm) }, // R11G11B10F - { 0, 0, 0, 0, 0, 0, 0, 0, uint8_t(EncodingType::Count) }, // UnknownDepth - { 16, 1, 1, 2, 1, 1, 16, 0, uint8_t(EncodingType::Unorm) }, // D16 - { 24, 1, 1, 3, 1, 1, 24, 0, uint8_t(EncodingType::Unorm) }, // D24 - { 32, 1, 1, 4, 1, 1, 24, 8, uint8_t(EncodingType::Unorm) }, // D24S8 - { 32, 1, 1, 4, 1, 1, 32, 0, uint8_t(EncodingType::Unorm) }, // D32 - { 16, 1, 1, 2, 1, 1, 16, 0, uint8_t(EncodingType::Unorm) }, // D16F - { 24, 1, 1, 3, 1, 1, 24, 0, uint8_t(EncodingType::Unorm) }, // D24F - { 32, 1, 1, 4, 1, 1, 32, 0, uint8_t(EncodingType::Unorm) }, // D32F - { 8, 1, 1, 1, 1, 1, 0, 8, uint8_t(EncodingType::Unorm) }, // D0S8 + // +-------------------------------------------- bits per pixel + // | +----------------------------------------- block width + // | | +-------------------------------------- block height + // | | | +---------------------------------- block size + // | | | | +------------------------------- min blocks x + // | | | | | +---------------------------- min blocks y + // | | | | | | +------------------------ depth bits + // | | | | | | | +--------------------- stencil bits + // | | | | | | | | +----------------- r bits + // | | | | | | | | | g b a +-- encoding type + // | | | | | | | | | | | | | + { 4, 4, 4, 8, 1, 1, 0, 0, 0, 0, 0, 0, uint8_t(EncodingType::Unorm) }, // BC1 + { 8, 4, 4, 16, 1, 1, 0, 0, 0, 0, 0, 0, uint8_t(EncodingType::Unorm) }, // BC2 + { 8, 4, 4, 16, 1, 1, 0, 0, 0, 0, 0, 0, uint8_t(EncodingType::Unorm) }, // BC3 + { 4, 4, 4, 8, 1, 1, 0, 0, 0, 0, 0, 0, uint8_t(EncodingType::Unorm) }, // BC4 + { 8, 4, 4, 16, 1, 1, 0, 0, 0, 0, 0, 0, uint8_t(EncodingType::Unorm) }, // BC5 + { 8, 4, 4, 16, 1, 1, 0, 0, 0, 0, 0, 0, uint8_t(EncodingType::Unorm) }, // BC6H + { 8, 4, 4, 16, 1, 1, 0, 0, 0, 0, 0, 0, uint8_t(EncodingType::Unorm) }, // BC7 + { 4, 4, 4, 8, 1, 1, 0, 0, 0, 0, 0, 0, uint8_t(EncodingType::Unorm) }, // ETC1 + { 4, 4, 4, 8, 1, 1, 0, 0, 0, 0, 0, 0, uint8_t(EncodingType::Unorm) }, // ETC2 + { 8, 4, 4, 16, 1, 1, 0, 0, 0, 0, 0, 0, uint8_t(EncodingType::Unorm) }, // ETC2A + { 4, 4, 4, 8, 1, 1, 0, 0, 0, 0, 0, 0, uint8_t(EncodingType::Unorm) }, // ETC2A1 + { 2, 8, 4, 8, 2, 2, 0, 0, 0, 0, 0, 0, uint8_t(EncodingType::Unorm) }, // PTC12 + { 4, 4, 4, 8, 2, 2, 0, 0, 0, 0, 0, 0, uint8_t(EncodingType::Unorm) }, // PTC14 + { 2, 8, 4, 8, 2, 2, 0, 0, 0, 0, 0, 0, uint8_t(EncodingType::Unorm) }, // PTC12A + { 4, 4, 4, 8, 2, 2, 0, 0, 0, 0, 0, 0, uint8_t(EncodingType::Unorm) }, // PTC14A + { 2, 8, 4, 8, 2, 2, 0, 0, 0, 0, 0, 0, uint8_t(EncodingType::Unorm) }, // PTC22 + { 4, 4, 4, 8, 2, 2, 0, 0, 0, 0, 0, 0, uint8_t(EncodingType::Unorm) }, // PTC24 + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, uint8_t(EncodingType::Count) }, // Unknown + { 1, 8, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, uint8_t(EncodingType::Unorm) }, // R1 + { 8, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 8, uint8_t(EncodingType::Unorm) }, // A8 + { 8, 1, 1, 1, 1, 1, 0, 0, 8, 0, 0, 0, uint8_t(EncodingType::Unorm) }, // R8 + { 8, 1, 1, 1, 1, 1, 0, 0, 8, 0, 0, 0, uint8_t(EncodingType::Int ) }, // R8I + { 8, 1, 1, 1, 1, 1, 0, 0, 8, 0, 0, 0, uint8_t(EncodingType::Uint ) }, // R8U + { 8, 1, 1, 1, 1, 1, 0, 0, 8, 0, 0, 0, uint8_t(EncodingType::Snorm) }, // R8S + { 16, 1, 1, 2, 1, 1, 0, 0, 16, 0, 0, 0, uint8_t(EncodingType::Unorm) }, // R16 + { 16, 1, 1, 2, 1, 1, 0, 0, 16, 0, 0, 0, uint8_t(EncodingType::Int ) }, // R16I + { 16, 1, 1, 2, 1, 1, 0, 0, 16, 0, 0, 0, uint8_t(EncodingType::Uint ) }, // R16U + { 16, 1, 1, 2, 1, 1, 0, 0, 16, 0, 0, 0, uint8_t(EncodingType::Float) }, // R16F + { 16, 1, 1, 2, 1, 1, 0, 0, 16, 0, 0, 0, uint8_t(EncodingType::Snorm) }, // R16S + { 32, 1, 1, 4, 1, 1, 0, 0, 32, 0, 0, 0, uint8_t(EncodingType::Int ) }, // R32I + { 32, 1, 1, 4, 1, 1, 0, 0, 32, 0, 0, 0, uint8_t(EncodingType::Uint ) }, // R32U + { 32, 1, 1, 4, 1, 1, 0, 0, 32, 0, 0, 0, uint8_t(EncodingType::Float) }, // R32F + { 16, 1, 1, 2, 1, 1, 0, 0, 8, 8, 0, 0, uint8_t(EncodingType::Unorm) }, // RG8 + { 16, 1, 1, 2, 1, 1, 0, 0, 8, 8, 0, 0, uint8_t(EncodingType::Int ) }, // RG8I + { 16, 1, 1, 2, 1, 1, 0, 0, 8, 8, 0, 0, uint8_t(EncodingType::Uint ) }, // RG8U + { 16, 1, 1, 2, 1, 1, 0, 0, 8, 8, 0, 0, uint8_t(EncodingType::Snorm) }, // RG8S + { 32, 1, 1, 4, 1, 1, 0, 0, 16, 16, 0, 0, uint8_t(EncodingType::Unorm) }, // RG16 + { 32, 1, 1, 4, 1, 1, 0, 0, 16, 16, 0, 0, uint8_t(EncodingType::Int ) }, // RG16I + { 32, 1, 1, 4, 1, 1, 0, 0, 16, 16, 0, 0, uint8_t(EncodingType::Uint ) }, // RG16U + { 32, 1, 1, 4, 1, 1, 0, 0, 16, 16, 0, 0, uint8_t(EncodingType::Float) }, // RG16F + { 32, 1, 1, 4, 1, 1, 0, 0, 16, 16, 0, 0, uint8_t(EncodingType::Snorm) }, // RG16S + { 64, 1, 1, 8, 1, 1, 0, 0, 32, 32, 0, 0, uint8_t(EncodingType::Int ) }, // RG32I + { 64, 1, 1, 8, 1, 1, 0, 0, 32, 32, 0, 0, uint8_t(EncodingType::Uint ) }, // RG32U + { 64, 1, 1, 8, 1, 1, 0, 0, 32, 32, 0, 0, uint8_t(EncodingType::Float) }, // RG32F + { 24, 1, 1, 3, 1, 1, 0, 0, 8, 8, 8, 0, uint8_t(EncodingType::Unorm) }, // RGB8 + { 24, 1, 1, 3, 1, 1, 0, 0, 8, 8, 8, 0, uint8_t(EncodingType::Int ) }, // RGB8I + { 24, 1, 1, 3, 1, 1, 0, 0, 8, 8, 8, 0, uint8_t(EncodingType::Uint ) }, // RGB8U + { 24, 1, 1, 3, 1, 1, 0, 0, 8, 8, 8, 0, uint8_t(EncodingType::Snorm) }, // RGB8S + { 32, 1, 1, 4, 1, 1, 0, 0, 9, 9, 9, 5, uint8_t(EncodingType::Float) }, // RGB9E5F + { 32, 1, 1, 4, 1, 1, 0, 0, 8, 8, 8, 8, uint8_t(EncodingType::Unorm) }, // BGRA8 + { 32, 1, 1, 4, 1, 1, 0, 0, 8, 8, 8, 8, uint8_t(EncodingType::Unorm) }, // RGBA8 + { 32, 1, 1, 4, 1, 1, 0, 0, 8, 8, 8, 8, uint8_t(EncodingType::Int ) }, // RGBA8I + { 32, 1, 1, 4, 1, 1, 0, 0, 8, 8, 8, 8, uint8_t(EncodingType::Uint ) }, // RGBA8U + { 32, 1, 1, 4, 1, 1, 0, 0, 8, 8, 8, 8, uint8_t(EncodingType::Snorm) }, // RGBA8S + { 64, 1, 1, 8, 1, 1, 0, 0, 16, 16, 16, 16, uint8_t(EncodingType::Unorm) }, // RGBA16 + { 64, 1, 1, 8, 1, 1, 0, 0, 16, 16, 16, 16, uint8_t(EncodingType::Int ) }, // RGBA16I + { 64, 1, 1, 8, 1, 1, 0, 0, 16, 16, 16, 16, uint8_t(EncodingType::Uint ) }, // RGBA16U + { 64, 1, 1, 8, 1, 1, 0, 0, 16, 16, 16, 16, uint8_t(EncodingType::Float) }, // RGBA16F + { 64, 1, 1, 8, 1, 1, 0, 0, 16, 16, 16, 16, uint8_t(EncodingType::Snorm) }, // RGBA16S + { 128, 1, 1, 16, 1, 1, 0, 0, 32, 32, 32, 32, uint8_t(EncodingType::Int ) }, // RGBA32I + { 128, 1, 1, 16, 1, 1, 0, 0, 32, 32, 32, 32, uint8_t(EncodingType::Uint ) }, // RGBA32U + { 128, 1, 1, 16, 1, 1, 0, 0, 32, 32, 32, 32, uint8_t(EncodingType::Float) }, // RGBA32F + { 16, 1, 1, 2, 1, 1, 0, 0, 5, 6, 5, 0, uint8_t(EncodingType::Unorm) }, // R5G6B5 + { 16, 1, 1, 2, 1, 1, 0, 0, 4, 4, 4, 4, uint8_t(EncodingType::Unorm) }, // RGBA4 + { 16, 1, 1, 2, 1, 1, 0, 0, 5, 5, 5, 1, uint8_t(EncodingType::Unorm) }, // RGB5A1 + { 32, 1, 1, 4, 1, 1, 0, 0, 10, 10, 10, 2, uint8_t(EncodingType::Unorm) }, // RGB10A2 + { 32, 1, 1, 4, 1, 1, 0, 0, 11, 11, 10, 0, uint8_t(EncodingType::Unorm) }, // R11G11B10F + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, uint8_t(EncodingType::Count) }, // UnknownDepth + { 16, 1, 1, 2, 1, 1, 16, 0, 0, 0, 0, 0, uint8_t(EncodingType::Unorm) }, // D16 + { 24, 1, 1, 3, 1, 1, 24, 0, 0, 0, 0, 0, uint8_t(EncodingType::Unorm) }, // D24 + { 32, 1, 1, 4, 1, 1, 24, 8, 0, 0, 0, 0, uint8_t(EncodingType::Unorm) }, // D24S8 + { 32, 1, 1, 4, 1, 1, 32, 0, 0, 0, 0, 0, uint8_t(EncodingType::Unorm) }, // D32 + { 16, 1, 1, 2, 1, 1, 16, 0, 0, 0, 0, 0, uint8_t(EncodingType::Unorm) }, // D16F + { 24, 1, 1, 3, 1, 1, 24, 0, 0, 0, 0, 0, uint8_t(EncodingType::Unorm) }, // D24F + { 32, 1, 1, 4, 1, 1, 32, 0, 0, 0, 0, 0, uint8_t(EncodingType::Unorm) }, // D32F + { 8, 1, 1, 1, 1, 1, 0, 8, 0, 0, 0, 0, uint8_t(EncodingType::Unorm) }, // D0S8 }; BX_STATIC_ASSERT(TextureFormat::Count == BX_COUNTOF(s_imageBlockInfo) ); @@ -452,6 +453,100 @@ namespace bgfx } } + void imageRgba32fToLinear(void* _dst, uint32_t _width, uint32_t _height, uint32_t _pitch, const void* _src) + { + uint8_t* dst = ( uint8_t*)_dst; + const uint8_t* src = (const uint8_t*)_src; + + for (uint32_t yy = 0; yy < _height; ++yy, src += _pitch) + { + for (uint32_t xx = 0; xx < _width; ++xx, dst += 16) + { + float* fd = ( float*)dst; + const float* fs = (const float*)src; + + fd[0] = bx::fpow(fs[0], 1.0f/2.2f); + fd[1] = bx::fpow(fs[1], 1.0f/2.2f); + fd[2] = bx::fpow(fs[2], 1.0f/2.2f); + fd[3] = fs[3]; + } + } + } + + void imageRgba32fToGamma(void* _dst, uint32_t _width, uint32_t _height, uint32_t _pitch, const void* _src) + { + uint8_t* dst = ( uint8_t*)_dst; + const uint8_t* src = (const uint8_t*)_src; + + for (uint32_t yy = 0; yy < _height; ++yy, src += _pitch) + { + for (uint32_t xx = 0; xx < _width; ++xx, dst += 16) + { + float* fd = ( float*)dst; + const float* fs = (const float*)src; + + fd[0] = bx::fpow(fs[0], 2.2f); + fd[1] = bx::fpow(fs[1], 2.2f); + fd[2] = bx::fpow(fs[2], 2.2f); + fd[3] = fs[3]; + } + } + } + + void imageRgba32fLinearDownsample2x2Ref(uint32_t _width, uint32_t _height, uint32_t _pitch, const void* _src, void* _dst) + { + const uint32_t dstwidth = _width/2; + const uint32_t dstheight = _height/2; + + if (0 == dstwidth + || 0 == dstheight) + { + return; + } + + const uint8_t* src = (const uint8_t*)_src; + uint8_t* dst = (uint8_t*)_dst; + + for (uint32_t yy = 0, ystep = _pitch*2; yy < dstheight; ++yy, src += ystep) + { + const float* rgba0 = (const float*)&src[0]; + const float* rgba1 = (const float*)&src[_pitch]; + for (uint32_t xx = 0; xx < dstwidth; ++xx, rgba0 += 8, rgba1 += 8, dst += 16) + { + float xyz[4]; + xyz[0] = rgba0[0]; + xyz[1] = rgba0[1]; + xyz[2] = rgba0[2]; + xyz[3] = rgba0[3]; + + xyz[0] += rgba0[4]; + xyz[1] += rgba0[5]; + xyz[2] += rgba0[6]; + xyz[3] += rgba0[7]; + + xyz[0] += rgba1[0]; + xyz[1] += rgba1[1]; + xyz[2] += rgba1[2]; + xyz[3] += rgba1[3]; + + xyz[0] += rgba1[4]; + xyz[1] += rgba1[5]; + xyz[2] += rgba1[6]; + xyz[3] += rgba1[7]; + + xyz[0] *= 0.25f; + xyz[1] *= 0.25f; + xyz[2] *= 0.25f; + xyz[3] *= 0.25f; + } + } + } + + void imageRgba32fLinearDownsample2x2(uint32_t _width, uint32_t _height, uint32_t _pitch, const void* _src, void* _dst) + { + imageRgba32fLinearDownsample2x2Ref(_width, _height, _pitch, _src, _dst); + } + void imageRgba32fDownsample2x2NormalMapRef(uint32_t _width, uint32_t _height, uint32_t _pitch, const void* _src, void* _dst) { const uint32_t dstwidth = _width/2; @@ -1563,7 +1658,7 @@ namespace bgfx bool imageConvert(void* _dst, TextureFormat::Enum _dstFormat, const void* _src, TextureFormat::Enum _srcFormat, uint32_t _width, uint32_t _height) { const uint32_t srcBpp = s_imageBlockInfo[_srcFormat].bitsPerPixel; - return imageConvert(_dst, _dstFormat, _src, _srcFormat, _width, _height, _width*srcBpp); + return imageConvert(_dst, _dstFormat, _src, _srcFormat, _width, _height, _width*srcBpp/8); } uint8_t bitRangeConvert(uint32_t _in, uint32_t _from, uint32_t _to) @@ -3605,12 +3700,17 @@ namespace bgfx break; default: + if (isCompressed(_format) ) { void* temp = BX_ALLOC(_allocator, imageGetSize(_format, uint16_t(_pitch/4), uint16_t(_height) ) ); imageDecodeToRgba8(temp, _src, _width, _height, _pitch, _format); imageRgba8ToRgba32f(_dst, _width, _height, _pitch, temp); BX_FREE(_allocator, temp); } + else + { + imageConvert(_dst, TextureFormat::RGBA32F, _src, _format, _width, _height, _pitch); + } break; } } diff --git a/src/image.h b/src/image.h index 173cf7b0f..64bbf1c5f 100644 --- a/src/image.h +++ b/src/image.h @@ -63,6 +63,10 @@ namespace bgfx uint8_t minBlockY; uint8_t depthBits; uint8_t stencilBits; + uint8_t rBits; + uint8_t gBits; + uint8_t bBits; + uint8_t aBits; uint8_t encoding; }; @@ -304,6 +308,15 @@ namespace bgfx /// void imageRgba8Downsample2x2(uint32_t _width, uint32_t _height, uint32_t _pitch, const void* _src, void* _dst); + /// + void imageRgba32fToLinear(void* _dst, uint32_t _width, uint32_t _height, uint32_t _pitch, const void* _src); + + /// + void imageRgba32fToGamma(void* _dst, uint32_t _width, uint32_t _height, uint32_t _pitch, const void* _src); + + /// + void imageRgba32fLinearDownsample2x2(uint32_t _width, uint32_t _height, uint32_t _pitch, const void* _src, void* _dst); + /// void imageRgba32fDownsample2x2NormalMap(uint32_t _width, uint32_t _height, uint32_t _pitch, const void* _src, void* _dst); diff --git a/tools/texturec/texturec.cpp b/tools/texturec/texturec.cpp index ba23a5283..c1c271fdd 100644 --- a/tools/texturec/texturec.cpp +++ b/tools/texturec/texturec.cpp @@ -23,8 +23,39 @@ extern "C" { #include } +#define LODEPNG_NO_COMPILE_ENCODER +#define LODEPNG_NO_COMPILE_DISK +#define LODEPNG_NO_COMPILE_ANCILLARY_CHUNKS +#define LODEPNG_NO_COMPILE_ERROR_TEXT +#define LODEPNG_NO_COMPILE_ALLOCATORS +#define LODEPNG_NO_COMPILE_CPP +#include + +void* lodepng_malloc(size_t _size) +{ + return ::malloc(_size); +} + +void* lodepng_realloc(void* _ptr, size_t _size) +{ + return ::realloc(_ptr, _size); +} + +void lodepng_free(void* _ptr) +{ + ::free(_ptr); +} + +BX_PRAGMA_DIAGNOSTIC_PUSH(); +BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC("-Wmissing-field-initializers"); +BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC("-Wshadow"); +BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC("-Wint-to-pointer-cast") +#define STBI_MALLOC(_size) lodepng_malloc(_size) +#define STBI_REALLOC(_ptr, _size) lodepng_realloc(_ptr, _size) +#define STBI_FREE(_ptr) lodepng_free(_ptr) #define STB_IMAGE_IMPLEMENTATION #include +BX_PRAGMA_DIAGNOSTIC_POP(); #if 0 # define BX_TRACE(_format, ...) fprintf(stderr, "" _format "\n", ##__VA_ARGS__) @@ -60,6 +91,141 @@ namespace bgfx ::free(mem); } + bool imageParse(ImageContainer& _imageContainer, const void* _data, uint32_t _size, void** _out) + { + *_out = NULL; + bool loaded = imageParse(_imageContainer, _data, _size); + if (!loaded) + { + bgfx::TextureFormat::Enum format = bgfx::TextureFormat::RGBA8; + uint32_t bpp = 32; + + uint32_t width = 0; + uint32_t height = 0; + + uint8_t* out = NULL; + static uint8_t pngMagic[] = { 0x89, 0x50, 0x4E, 0x47, 0x0d, 0x0a }; + if (0 == memcmp(_data, pngMagic, sizeof(pngMagic) ) ) + { + unsigned error; + LodePNGState state; + lodepng_state_init(&state); + state.decoder.color_convert = 0; + error = lodepng_decode(&out, &width, &height, &state, (uint8_t*)_data, _size); + + if (0 == error) + { + *_out = out; + + switch (state.info_raw.bitdepth) + { + case 8: + switch (state.info_raw.colortype) + { + case LCT_GREY: + format = bgfx::TextureFormat::R8; + bpp = 8; + break; + + case LCT_GREY_ALPHA: + format = bgfx::TextureFormat::RG8; + bpp = 16; + break; + + case LCT_RGB: + format = bgfx::TextureFormat::RGB8; + bpp = 24; + break; + + case LCT_RGBA: + format = bgfx::TextureFormat::RGBA8; + bpp = 32; + break; + + case LCT_PALETTE: + break; + } + break; + + case 16: + switch (state.info_raw.colortype) + { + case LCT_GREY: + for (uint32_t ii = 0, num = width*height; ii < num; ++ii) + { + uint16_t* rgba = (uint16_t*)out + ii*4; + rgba[0] = bx::toHostEndian(rgba[0], false); + } + format = bgfx::TextureFormat::R16; + bpp = 16; + break; + + case LCT_GREY_ALPHA: + for (uint32_t ii = 0, num = width*height; ii < num; ++ii) + { + uint16_t* rgba = (uint16_t*)out + ii*4; + rgba[0] = bx::toHostEndian(rgba[0], false); + rgba[1] = bx::toHostEndian(rgba[1], false); + } + format = bgfx::TextureFormat::R16; + bpp = 16; + break; + + case LCT_RGBA: + for (uint32_t ii = 0, num = width*height; ii < num; ++ii) + { + uint16_t* rgba = (uint16_t*)out + ii*4; + rgba[0] = bx::toHostEndian(rgba[0], false); + rgba[1] = bx::toHostEndian(rgba[1], false); + rgba[2] = bx::toHostEndian(rgba[2], false); + rgba[3] = bx::toHostEndian(rgba[3], false); + } + format = bgfx::TextureFormat::RGBA16; + bpp = 64; + break; + + case LCT_RGB: + case LCT_PALETTE: + break; + } + break; + + default: + break; + } + } + + lodepng_state_cleanup(&state); + } + else + { + int comp = 0; + *_out = stbi_load_from_memory( (uint8_t*)_data, _size, (int*)&width, (int*)&height, &comp, 4); + } + + loaded = NULL != *_out; + + if (loaded) + { + _imageContainer.m_data = *_out; + _imageContainer.m_size = width*height*bpp/8; + _imageContainer.m_offset = 0; + _imageContainer.m_width = width; + _imageContainer.m_height = height; + _imageContainer.m_depth = 1; + _imageContainer.m_format = format; + _imageContainer.m_numMips = 1; + _imageContainer.m_hasAlpha = true; + _imageContainer.m_cubeMap = false; + _imageContainer.m_ktx = false; + _imageContainer.m_ktxLE = false; + _imageContainer.m_srgb = false; + } + } + + return loaded; + } + bool imageEncodeFromRgba8(void* _dst, const void* _src, uint32_t _width, uint32_t _height, uint8_t _format) { TextureFormat::Enum format = TextureFormat::Enum(_format); @@ -334,7 +500,7 @@ void help(const char* _error = NULL) ); fprintf(stderr - , "Usage: texturec -f -o -t \n" + , "Usage: texturec -f -o [-t ]\n" "\n" "Supported input file types:\n" @@ -400,20 +566,6 @@ int main(int _argc, const char* _argv[]) return EXIT_FAILURE; } - const char* type = cmdLine.findOption('t'); - bgfx::TextureFormat::Enum format = bgfx::TextureFormat::BGRA8; - - if (NULL != type) - { - format = bgfx::getFormat(type); - - if (!isValid(format) ) - { - help("Invalid format specified."); - return EXIT_FAILURE; - } - } - const bool mips = cmdLine.hasArg('m', "mips"); const bool normalMap = cmdLine.hasArg('n', "normalmap"); const bool iqa = cmdLine.hasArg('\0', "iqa"); @@ -429,40 +581,29 @@ int main(int _argc, const char* _argv[]) uint8_t* decodedImage = NULL; ImageContainer imageContainer; - bool loaded = imageParse(imageContainer, mem->data, mem->size); - if (!loaded) + bool loaded = imageParse(imageContainer, mem->data, mem->size, (void**)&decodedImage); + if (NULL != decodedImage) { - int width = 0; - int height = 0; - int comp = 0; - - decodedImage = stbi_load_from_memory( (uint8_t*)mem->data, mem->size, &width, &height, &comp, 4); - loaded = NULL != decodedImage; - - if (loaded) - { - release(mem); - - mem = makeRef(decodedImage, width*height*4); - - imageContainer.m_data = mem->data; - imageContainer.m_size = mem->size; - imageContainer.m_offset = 0; - imageContainer.m_width = width; - imageContainer.m_height = height; - imageContainer.m_depth = 1; - imageContainer.m_format = bgfx::TextureFormat::RGBA8; - imageContainer.m_numMips = 1; - imageContainer.m_hasAlpha = true; - imageContainer.m_cubeMap = false; - imageContainer.m_ktx = false; - imageContainer.m_ktxLE = false; - imageContainer.m_srgb = false; - } + release(mem); + mem = makeRef(imageContainer.m_data, imageContainer.m_size); } if (loaded) { + const char* type = cmdLine.findOption('t'); + bgfx::TextureFormat::Enum format = imageContainer.m_format; + + if (NULL != type) + { + format = bgfx::getFormat(type); + + if (!isValid(format) ) + { + help("Invalid format specified."); + return EXIT_FAILURE; + } + } + bx::CrtAllocator allocator; const Memory* output = NULL; @@ -540,6 +681,66 @@ int main(int _argc, const char* _argv[]) BX_FREE(&allocator, rgbaDst); } + else if (8 != getBlockInfo(imageContainer.m_format).rBits) + { + output = imageAlloc(imageContainer, format, mip.m_width, mip.m_height, 0, false, mips); + + ImageMip dstMip; + imageGetRawData(imageContainer, 0, 0, NULL, 0, dstMip); + + if (mip.m_width != dstMip.m_width + && mip.m_height != dstMip.m_height) + { + printf("Invalid input image size %dx%d, it must be at least %dx%d to be converted to %s format.\n" + , mip.m_width + , mip.m_height + , dstMip.m_width + , dstMip.m_height + , getName(format) + ); + return EXIT_FAILURE; + } + + uint32_t size = imageGetSize(TextureFormat::RGBA32F, dstMip.m_width, dstMip.m_height); + temp = BX_ALLOC(&allocator, size); + float* rgba = (float*)temp; + float* rgbaDst = (float*)BX_ALLOC(&allocator, size); + + imageDecodeToRgba32f(&allocator + , rgba + , mip.m_data + , mip.m_width + , mip.m_height + , mip.m_width*mip.m_bpp/8 + , mip.m_format + ); + imageEncodeFromRgba32f(&allocator, output->data, rgba, dstMip.m_width, dstMip.m_height, format); + + imageRgba32fToLinear(rgba + , mip.m_width + , mip.m_height + , mip.m_width*mip.m_bpp/8 + , rgba + ); + + for (uint8_t lod = 1; lod < numMips; ++lod) + { + imageRgba32fLinearDownsample2x2(dstMip.m_width, dstMip.m_height, dstMip.m_width*16, rgba, rgba); + imageGetRawData(imageContainer, 0, lod, output->data, output->size, dstMip); + uint8_t* data = const_cast(dstMip.m_data); + + imageRgba32fToGamma(rgbaDst + , mip.m_width + , mip.m_height + , mip.m_width*mip.m_bpp/8 + , rgba + ); + + imageEncodeFromRgba32f(&allocator, data, rgbaDst, dstMip.m_width, dstMip.m_height, format); + } + + BX_FREE(&allocator, rgbaDst); + } else { output = imageAlloc(imageContainer, format, mip.m_width, mip.m_height, 0, false, mips); @@ -649,6 +850,11 @@ int main(int _argc, const char* _argv[]) imageFree(output); } } + else + { + help("Failed to load input file."); + return EXIT_FAILURE; + } release(mem); }