image_decode.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  1. /*
  2. * Copyright 2011-2017 Branimir Karadzic. All rights reserved.
  3. * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
  4. */
  5. #include "entry/dbg.h"
  6. #include <bgfx/bgfx.h>
  7. #include <bx/allocator.h>
  8. #include <bx/endian.h>
  9. #include <bx/readerwriter.h>
  10. #include "bgfx_utils.h"
  11. BX_PRAGMA_DIAGNOSTIC_PUSH()
  12. BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC("-Wtype-limits")
  13. BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC("-Wunused-parameter")
  14. BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC("-Wunused-value")
  15. BX_PRAGMA_DIAGNOSTIC_IGNORED_MSVC(4100) // error C4100: '' : unreferenced formal parameter
  16. #if BX_PLATFORM_EMSCRIPTEN
  17. # include <compat/ctype.h>
  18. #endif // BX_PLATFORM_EMSCRIPTEN
  19. #define MINIZ_NO_STDIO
  20. #define TINYEXR_IMPLEMENTATION
  21. #include <tinyexr/tinyexr.h>
  22. BX_PRAGMA_DIAGNOSTIC_POP()
  23. BX_PRAGMA_DIAGNOSTIC_PUSH();
  24. BX_PRAGMA_DIAGNOSTIC_IGNORED_MSVC(4127) // warning C4127: conditional expression is constant
  25. #define LODEPNG_NO_COMPILE_ENCODER
  26. #define LODEPNG_NO_COMPILE_DISK
  27. #define LODEPNG_NO_COMPILE_ANCILLARY_CHUNKS
  28. #define LODEPNG_NO_COMPILE_ERROR_TEXT
  29. #define LODEPNG_NO_COMPILE_ALLOCATORS
  30. #define LODEPNG_NO_COMPILE_CPP
  31. #include <lodepng/lodepng.cpp>
  32. BX_PRAGMA_DIAGNOSTIC_POP();
  33. void* lodepng_malloc(size_t _size)
  34. {
  35. return ::malloc(_size);
  36. }
  37. void* lodepng_realloc(void* _ptr, size_t _size)
  38. {
  39. return ::realloc(_ptr, _size);
  40. }
  41. void lodepng_free(void* _ptr)
  42. {
  43. ::free(_ptr);
  44. }
  45. BX_PRAGMA_DIAGNOSTIC_PUSH();
  46. BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC("-Wmissing-field-initializers");
  47. BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC("-Wshadow");
  48. BX_PRAGMA_DIAGNOSTIC_IGNORED_CLANG_GCC("-Wint-to-pointer-cast")
  49. #if BX_COMPILER_GCC >= 60000
  50. BX_PRAGMA_DIAGNOSTIC_IGNORED_GCC("-Wmisleading-indentation");
  51. BX_PRAGMA_DIAGNOSTIC_IGNORED_GCC("-Wshift-negative-value");
  52. #endif // BX_COMPILER_GCC >= 60000_
  53. #define STBI_MALLOC(_size) lodepng_malloc(_size)
  54. #define STBI_REALLOC(_ptr, _size) lodepng_realloc(_ptr, _size)
  55. #define STBI_FREE(_ptr) lodepng_free(_ptr)
  56. #define STB_IMAGE_IMPLEMENTATION
  57. #include <stb/stb_image.c>
  58. BX_PRAGMA_DIAGNOSTIC_POP();
  59. namespace bgfx
  60. {
  61. #if !defined(BGFX_IMAGE_H_HEADER_GUARD)
  62. struct ImageMip
  63. {
  64. TextureFormat::Enum m_format;
  65. uint32_t m_width;
  66. uint32_t m_height;
  67. uint32_t m_blockSize;
  68. uint32_t m_size;
  69. uint8_t m_bpp;
  70. bool m_hasAlpha;
  71. const uint8_t* m_data;
  72. };
  73. #endif // !defined(BGFX_IMAGE_H_HEADER_GUARD)
  74. uint32_t imageGetSize(
  75. TextureInfo* _info
  76. , uint16_t _width
  77. , uint16_t _height
  78. , uint16_t _depth
  79. , bool _cubeMap
  80. , bool _hasMips
  81. , uint16_t _numLayers
  82. , TextureFormat::Enum _format
  83. );
  84. ///
  85. ImageContainer* imageParseBgfx(bx::AllocatorI* _allocator, const void* _src, uint32_t _size);
  86. ///
  87. bool imageConvert(
  88. void* _dst
  89. , TextureFormat::Enum _dstFormat
  90. , const void* _src
  91. , TextureFormat::Enum _srcFormat
  92. , uint32_t _width
  93. , uint32_t _height
  94. );
  95. ///
  96. ImageContainer* imageConvert(
  97. bx::AllocatorI* _allocator
  98. , TextureFormat::Enum _dstFormat
  99. , const ImageContainer& _input
  100. );
  101. } // namespace bgfx
  102. namespace bgfx
  103. {
  104. static ImageContainer* imageParseLodePng(bx::AllocatorI* _allocator, const void* _data, uint32_t _size)
  105. {
  106. static uint8_t pngMagic[] = { 0x89, 0x50, 0x4E, 0x47, 0x0d, 0x0a };
  107. if (0 != bx::memCmp(_data, pngMagic, sizeof(pngMagic) ) )
  108. {
  109. return NULL;
  110. }
  111. ImageContainer* output = NULL;
  112. bgfx::TextureFormat::Enum format = bgfx::TextureFormat::RGBA8;
  113. uint32_t width = 0;
  114. uint32_t height = 0;
  115. unsigned error;
  116. LodePNGState state;
  117. lodepng_state_init(&state);
  118. state.decoder.color_convert = 0;
  119. uint8_t* data = NULL;
  120. error = lodepng_decode(&data, &width, &height, &state, (uint8_t*)_data, _size);
  121. if (0 == error)
  122. {
  123. switch (state.info_raw.bitdepth)
  124. {
  125. case 8:
  126. switch (state.info_raw.colortype)
  127. {
  128. case LCT_GREY:
  129. format = bgfx::TextureFormat::R8;
  130. break;
  131. case LCT_GREY_ALPHA:
  132. format = bgfx::TextureFormat::RG8;
  133. break;
  134. case LCT_RGB:
  135. format = bgfx::TextureFormat::RGB8;
  136. break;
  137. case LCT_RGBA:
  138. format = bgfx::TextureFormat::RGBA8;
  139. break;
  140. case LCT_PALETTE:
  141. break;
  142. }
  143. break;
  144. case 16:
  145. switch (state.info_raw.colortype)
  146. {
  147. case LCT_GREY:
  148. for (uint32_t ii = 0, num = width*height; ii < num; ++ii)
  149. {
  150. uint16_t* rgba = (uint16_t*)data + ii;
  151. rgba[0] = bx::toHostEndian(rgba[0], false);
  152. }
  153. format = bgfx::TextureFormat::R16;
  154. break;
  155. case LCT_GREY_ALPHA:
  156. for (uint32_t ii = 0, num = width*height; ii < num; ++ii)
  157. {
  158. uint16_t* rgba = (uint16_t*)data + ii*2;
  159. rgba[0] = bx::toHostEndian(rgba[0], false);
  160. rgba[1] = bx::toHostEndian(rgba[1], false);
  161. }
  162. format = bgfx::TextureFormat::RG16;
  163. break;
  164. case LCT_RGBA:
  165. for (uint32_t ii = 0, num = width*height; ii < num; ++ii)
  166. {
  167. uint16_t* rgba = (uint16_t*)data + ii*4;
  168. rgba[0] = bx::toHostEndian(rgba[0], false);
  169. rgba[1] = bx::toHostEndian(rgba[1], false);
  170. rgba[2] = bx::toHostEndian(rgba[2], false);
  171. rgba[3] = bx::toHostEndian(rgba[3], false);
  172. }
  173. format = bgfx::TextureFormat::RGBA16;
  174. break;
  175. case LCT_RGB:
  176. case LCT_PALETTE:
  177. break;
  178. }
  179. break;
  180. default:
  181. break;
  182. }
  183. output = imageAlloc(_allocator
  184. , format
  185. , uint16_t(width)
  186. , uint16_t(height)
  187. , 0
  188. , 1
  189. , false
  190. , false
  191. , data
  192. );
  193. }
  194. lodepng_state_cleanup(&state);
  195. lodepng_free(data);
  196. return output;
  197. }
  198. static ImageContainer* imageParseTinyExr(bx::AllocatorI* _allocator, const void* _data, uint32_t _size)
  199. {
  200. EXRVersion exrVersion;
  201. int result = ParseEXRVersionFromMemory(&exrVersion, (uint8_t*)_data, _size);
  202. if (TINYEXR_SUCCESS != result)
  203. {
  204. return NULL;
  205. }
  206. bgfx::TextureFormat::Enum format = bgfx::TextureFormat::RGBA8;
  207. uint32_t width = 0;
  208. uint32_t height = 0;
  209. uint8_t* data = NULL;
  210. const char* err = NULL;
  211. EXRHeader exrHeader;
  212. result = ParseEXRHeaderFromMemory(&exrHeader, &exrVersion, (uint8_t*)_data, _size, &err);
  213. if (TINYEXR_SUCCESS == result)
  214. {
  215. EXRImage exrImage;
  216. InitEXRImage(&exrImage);
  217. result = LoadEXRImageFromMemory(&exrImage, &exrHeader, (uint8_t*)_data, _size, &err);
  218. if (TINYEXR_SUCCESS == result)
  219. {
  220. uint8_t idxR = UINT8_MAX;
  221. uint8_t idxG = UINT8_MAX;
  222. uint8_t idxB = UINT8_MAX;
  223. uint8_t idxA = UINT8_MAX;
  224. for (uint8_t ii = 0, num = uint8_t(exrHeader.num_channels); ii < num; ++ii)
  225. {
  226. const EXRChannelInfo& channel = exrHeader.channels[ii];
  227. if (UINT8_MAX == idxR
  228. && 0 == bx::strncmp(channel.name, "R") )
  229. {
  230. idxR = ii;
  231. }
  232. else if (UINT8_MAX == idxG
  233. && 0 == bx::strncmp(channel.name, "G") )
  234. {
  235. idxG = ii;
  236. }
  237. else if (UINT8_MAX == idxB
  238. && 0 == bx::strncmp(channel.name, "B") )
  239. {
  240. idxB = ii;
  241. }
  242. else if (UINT8_MAX == idxA
  243. && 0 == bx::strncmp(channel.name, "A") )
  244. {
  245. idxA = ii;
  246. }
  247. }
  248. if (UINT8_MAX != idxR)
  249. {
  250. const bool asFloat = exrHeader.pixel_types[idxR] == TINYEXR_PIXELTYPE_FLOAT;
  251. uint32_t srcBpp = 32;
  252. uint32_t dstBpp = asFloat ? 32 : 16;
  253. format = asFloat ? TextureFormat::R32F : TextureFormat::R16F;
  254. uint32_t stepR = 1;
  255. uint32_t stepG = 0;
  256. uint32_t stepB = 0;
  257. uint32_t stepA = 0;
  258. if (UINT8_MAX != idxG)
  259. {
  260. srcBpp += 32;
  261. dstBpp = asFloat ? 64 : 32;
  262. format = asFloat ? TextureFormat::RG32F : TextureFormat::RG16F;
  263. stepG = 1;
  264. }
  265. if (UINT8_MAX != idxB)
  266. {
  267. srcBpp += 32;
  268. dstBpp = asFloat ? 128 : 64;
  269. format = asFloat ? TextureFormat::RGBA32F : TextureFormat::RGBA16F;
  270. stepB = 1;
  271. }
  272. if (UINT8_MAX != idxA)
  273. {
  274. srcBpp += 32;
  275. dstBpp = asFloat ? 128 : 64;
  276. format = asFloat ? TextureFormat::RGBA32F : TextureFormat::RGBA16F;
  277. stepA = 1;
  278. }
  279. data = (uint8_t*)BX_ALLOC(_allocator, exrImage.width * exrImage.height * dstBpp/8);
  280. const float zero = 0.0f;
  281. const float* srcR = UINT8_MAX == idxR ? &zero : (const float*)(exrImage.images)[idxR];
  282. const float* srcG = UINT8_MAX == idxG ? &zero : (const float*)(exrImage.images)[idxG];
  283. const float* srcB = UINT8_MAX == idxB ? &zero : (const float*)(exrImage.images)[idxB];
  284. const float* srcA = UINT8_MAX == idxA ? &zero : (const float*)(exrImage.images)[idxA];
  285. const uint32_t bytesPerPixel = dstBpp/8;
  286. for (uint32_t ii = 0, num = exrImage.width * exrImage.height; ii < num; ++ii)
  287. {
  288. float rgba[4] =
  289. {
  290. *srcR,
  291. *srcG,
  292. *srcB,
  293. *srcA,
  294. };
  295. bx::memCopy(&data[ii * bytesPerPixel], rgba, bytesPerPixel);
  296. srcR += stepR;
  297. srcG += stepG;
  298. srcB += stepB;
  299. srcA += stepA;
  300. }
  301. }
  302. FreeEXRImage(&exrImage);
  303. }
  304. FreeEXRHeader(&exrHeader);
  305. }
  306. ImageContainer* output = imageAlloc(_allocator
  307. , format
  308. , uint16_t(width)
  309. , uint16_t(height)
  310. , 0
  311. , 1
  312. , false
  313. , false
  314. , data
  315. );
  316. BX_FREE(_allocator, data);
  317. return output;
  318. }
  319. static ImageContainer* imageParseStbImage(bx::AllocatorI* _allocator, const void* _data, uint32_t _size)
  320. {
  321. const int isHdr = stbi_is_hdr_from_memory((const uint8_t*)_data, (int)_size);
  322. void* data;
  323. uint32_t width = 0;
  324. uint32_t height = 0;
  325. int comp = 0;
  326. if (isHdr) { data = stbi_loadf_from_memory((const uint8_t*)_data, (int)_size, (int*)&width, (int*)&height, &comp, 4); }
  327. else { data = stbi_load_from_memory ((const uint8_t*)_data, (int)_size, (int*)&width, (int*)&height, &comp, 0); }
  328. if (NULL == data)
  329. {
  330. return NULL;
  331. }
  332. bgfx::TextureFormat::Enum format;
  333. if (isHdr)
  334. {
  335. format = bgfx::TextureFormat::RGBA32F;
  336. }
  337. else
  338. {
  339. if (1 == comp) { format = bgfx::TextureFormat::R8; }
  340. else if (2 == comp) { format = bgfx::TextureFormat::RG8; }
  341. else if (3 == comp) { format = bgfx::TextureFormat::RGB8; }
  342. else/*if (4 == comp)*/ { format = bgfx::TextureFormat::RGBA8; }
  343. }
  344. ImageContainer* output = imageAlloc(_allocator
  345. , format
  346. , uint16_t(width)
  347. , uint16_t(height)
  348. , 0
  349. , 1
  350. , false
  351. , false
  352. , data
  353. );
  354. stbi_image_free(data);
  355. return output;
  356. }
  357. ImageContainer* imageParse(bx::AllocatorI* _allocator, const void* _data, uint32_t _size, TextureFormat::Enum _dstFormat)
  358. {
  359. ImageContainer* input = imageParseBgfx (_allocator, _data, _size) ;
  360. input = NULL == input ? imageParseLodePng (_allocator, _data, _size) : input;
  361. input = NULL == input ? imageParseTinyExr (_allocator, _data, _size) : input;
  362. input = NULL == input ? imageParseStbImage(_allocator, _data, _size) : input;
  363. if (NULL == input)
  364. {
  365. return NULL;
  366. }
  367. _dstFormat = TextureFormat::Count == _dstFormat
  368. ? input->m_format
  369. : _dstFormat
  370. ;
  371. if (_dstFormat == input->m_format)
  372. {
  373. return input;
  374. }
  375. ImageContainer* output = imageConvert(_allocator, _dstFormat, *input);
  376. imageFree(input);
  377. return output;
  378. }
  379. } // namespace bgfx