Browse Source

texturec: Preserve precision of input texture.

Branimir Karadžić 9 years ago
parent
commit
21518f201f

+ 2 - 2
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));
     }
   }
 

+ 1 - 1
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

+ 77 - 27
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 <lodepng/lodepng.cpp>
-#include <stb/stb_image.c>
+#include <lodepng/lodepng.h>
 
 #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)
 			{

+ 26 - 0
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 <lodepng/lodepng.cpp>
+
+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 <stb/stb_image.c>
 BX_PRAGMA_DIAGNOSTIC_POP();

+ 187 - 87
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;
 		}
 	}

+ 13 - 0
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);
 

+ 249 - 43
tools/texturec/texturec.cpp

@@ -23,8 +23,39 @@ extern "C" {
 #include <iqa.h>
 }
 
+#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 <lodepng/lodepng.cpp>
+
+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 <stb/stb_image.c>
+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 <in> -o <out> -t <format>\n"
+		, "Usage: texturec -f <in> -o <out> [-t <format>]\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;
+			release(mem);
+			mem = makeRef(imageContainer.m_data, imageContainer.m_size);
+		}
 
-			decodedImage = stbi_load_from_memory( (uint8_t*)mem->data, mem->size, &width, &height, &comp, 4);
-			loaded = NULL != decodedImage;
+		if (loaded)
+		{
+			const char* type = cmdLine.findOption('t');
+			bgfx::TextureFormat::Enum format = imageContainer.m_format;
 
-			if (loaded)
+			if (NULL != type)
 			{
-				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;
+				format = bgfx::getFormat(type);
+
+				if (!isValid(format) )
+				{
+					help("Invalid format specified.");
+					return EXIT_FAILURE;
+				}
 			}
-		}
 
-		if (loaded)
-		{
 			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<uint8_t*>(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);
 	}