diff --git a/include/bimg/bimg.h b/include/bimg/bimg.h index fa3328f..ae804c3 100644 --- a/include/bimg/bimg.h +++ b/include/bimg/bimg.h @@ -9,7 +9,7 @@ #include // uint32_t #include // NULL -#define BIMG_API_VERSION UINT32_C(6) +#define BIMG_API_VERSION UINT32_C(7) namespace bx { @@ -493,6 +493,18 @@ namespace bimg , bx::Error* _err ); + /// + int32_t imageWriteHdr( + bx::WriterI* _writer + , uint32_t _width + , uint32_t _height + , uint32_t _srcPitch + , const void* _src + , TextureFormat::Enum _format + , bool _yflip + , bx::Error* _err + ); + /// int32_t imageWriteDds( bx::WriterI* _writer diff --git a/src/image.cpp b/src/image.cpp index f5c5e69..3aaeafa 100644 --- a/src/image.cpp +++ b/src/image.cpp @@ -5000,6 +5000,47 @@ namespace bimg return total; } + int32_t imageWriteHdr(bx::WriterI* _writer, uint32_t _width, uint32_t _height, uint32_t _srcPitch, const void* _src, TextureFormat::Enum _format, bool _yflip, bx::Error* _err) + { + BX_ERROR_SCOPE(_err); + + int32_t total = 0; + total += bx::write(_writer, "#?RADIANCE\n" , _err); + total += bx::write(_writer, "FORMAT=32-bit_rle_rgbe\n" , _err); + total += bx::write(_writer, '\n' , _err); + + total += bx::writePrintf(_writer, "%cY %d +X %d\n", _yflip ? '+' : '-', _height, _width); + + UnpackFn unpack = getUnpack(_format); + const uint32_t bpp = getBitsPerPixel(_format); + + const uint8_t* data = (const uint8_t*)_src; + for (uint32_t yy = 0; yy < _height && _err->isOk(); ++yy) + { + for (uint32_t xx = 0; xx < _width && _err->isOk(); ++xx) + { + float rgba[4]; + unpack(rgba, &data[xx*bpp/8]); + + const float maxVal = bx::max(rgba[0], rgba[1], rgba[2]); + const float exp = bx::ceil(bx::log2(maxVal) ); + const float toRgb8 = 255.0f * 1.0f/bx::ldexp(1.0f, int(exp) ); + + uint8_t rgbe[4]; + rgbe[0] = uint8_t(rgba[0] * toRgb8); + rgbe[1] = uint8_t(rgba[1] * toRgb8); + rgbe[2] = uint8_t(rgba[2] * toRgb8); + rgbe[3] = uint8_t(exp+128.0f); + + total += bx::write(_writer, rgbe, 4, _err); + } + + data += _srcPitch; + } + + return total; + } + static int32_t imageWriteDdsHeader(bx::WriterI* _writer, TextureFormat::Enum _format, bool _cubeMap, uint32_t _width, uint32_t _height, uint32_t _depth, uint8_t _numMips, bx::Error* _err) { BX_ERROR_SCOPE(_err); diff --git a/tools/texturec/texturec.cpp b/tools/texturec/texturec.cpp index 70c1e27..1a2f40b 100644 --- a/tools/texturec/texturec.cpp +++ b/tools/texturec/texturec.cpp @@ -770,7 +770,7 @@ void help(const char* _error = NULL, bool _showHelp = true) " *.exr (input, output) OpenEXR.\n" " *.gif (input) Graphics Interchange Format.\n" " *.jpg (input) JPEG Interchange Format.\n" - " *.hdr (input) Radiance RGBE.\n" + " *.hdr (input, output) Radiance RGBE.\n" " *.ktx (input, output) Khronos Texture.\n" " *.png (input, output) Portable Network Graphics.\n" " *.psd (input) Photoshop Document.\n" @@ -881,6 +881,7 @@ int main(int _argc, const char* _argv[]) saveAs = NULL == saveAs ? bx::strFindI(outputFileName, ".dds") : saveAs; saveAs = NULL == saveAs ? bx::strFindI(outputFileName, ".png") : saveAs; saveAs = NULL == saveAs ? bx::strFindI(outputFileName, ".exr") : saveAs; + saveAs = NULL == saveAs ? bx::strFindI(outputFileName, ".hdr") : saveAs; if (NULL == saveAs) { help("Output file format must be specified."); @@ -1044,7 +1045,8 @@ int main(int _argc, const char* _argv[]) , mip.m_data , output->m_format , false - , &err); + , &err + ); } else if (NULL != bx::strFindI(saveAs, "exr") ) { @@ -1057,7 +1059,22 @@ int main(int _argc, const char* _argv[]) , mip.m_data , output->m_format , false - , &err); + , &err + ); + } + else if (NULL != bx::strFindI(saveAs, "hdr") ) + { + bimg::ImageMip mip; + bimg::imageGetRawData(*output, 0, 0, output->m_data, output->m_size, mip); + bimg::imageWriteHdr(&writer + , mip.m_width + , mip.m_height + , mip.m_width*8 + , mip.m_data + , output->m_format + , false + , &err + ); } bx::close(&writer);