image.cpp 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  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. #define LODEPNG_NO_COMPILE_ENCODER
  24. #define LODEPNG_NO_COMPILE_DISK
  25. #define LODEPNG_NO_COMPILE_ANCILLARY_CHUNKS
  26. #define LODEPNG_NO_COMPILE_ERROR_TEXT
  27. #define LODEPNG_NO_COMPILE_ALLOCATORS
  28. #define LODEPNG_NO_COMPILE_CPP
  29. #include <lodepng/lodepng.h>
  30. typedef unsigned char stbi_uc;
  31. extern "C" stbi_uc* stbi_load_from_memory(stbi_uc const* _buffer, int _len, int* _x, int* _y, int* _comp, int _req_comp);
  32. extern "C" void stbi_image_free(void* _ptr);
  33. extern void lodepng_free(void* _ptr);
  34. namespace bgfx
  35. {
  36. struct ImageMip
  37. {
  38. TextureFormat::Enum m_format;
  39. uint32_t m_width;
  40. uint32_t m_height;
  41. uint32_t m_blockSize;
  42. uint32_t m_size;
  43. uint8_t m_bpp;
  44. bool m_hasAlpha;
  45. const uint8_t* m_data;
  46. };
  47. uint32_t imageGetSize(
  48. TextureInfo* _info
  49. , uint16_t _width
  50. , uint16_t _height
  51. , uint16_t _depth
  52. , bool _cubeMap
  53. , bool _hasMips
  54. , uint16_t _numLayers
  55. , TextureFormat::Enum _format
  56. );
  57. ///
  58. ImageContainer* imageParseBgfx(bx::AllocatorI* _allocator, const void* _src, uint32_t _size);
  59. ///
  60. bool imageConvert(
  61. void* _dst
  62. , TextureFormat::Enum _dstFormat
  63. , const void* _src
  64. , TextureFormat::Enum _srcFormat
  65. , uint32_t _width
  66. , uint32_t _height
  67. );
  68. ///
  69. ImageContainer* imageConvert(
  70. bx::AllocatorI* _allocator
  71. , TextureFormat::Enum _dstFormat
  72. , const ImageContainer& _input
  73. );
  74. } // namespace bgfx
  75. namespace bgfx
  76. {
  77. static ImageContainer* imageParseLodePng(bx::AllocatorI* _allocator, const void* _data, uint32_t _size)
  78. {
  79. static uint8_t pngMagic[] = { 0x89, 0x50, 0x4E, 0x47, 0x0d, 0x0a };
  80. if (0 != bx::memCmp(_data, pngMagic, sizeof(pngMagic) ) )
  81. {
  82. return NULL;
  83. }
  84. bgfx::TextureFormat::Enum format = bgfx::TextureFormat::RGBA8;
  85. uint32_t width = 0;
  86. uint32_t height = 0;
  87. unsigned error;
  88. LodePNGState state;
  89. lodepng_state_init(&state);
  90. state.decoder.color_convert = 0;
  91. uint8_t* data = NULL;
  92. error = lodepng_decode(&data, &width, &height, &state, (uint8_t*)_data, _size);
  93. if (0 == error)
  94. {
  95. switch (state.info_raw.bitdepth)
  96. {
  97. case 8:
  98. switch (state.info_raw.colortype)
  99. {
  100. case LCT_GREY:
  101. format = bgfx::TextureFormat::R8;
  102. break;
  103. case LCT_GREY_ALPHA:
  104. format = bgfx::TextureFormat::RG8;
  105. break;
  106. case LCT_RGB:
  107. format = bgfx::TextureFormat::RGB8;
  108. break;
  109. case LCT_RGBA:
  110. format = bgfx::TextureFormat::RGBA8;
  111. break;
  112. case LCT_PALETTE:
  113. break;
  114. }
  115. break;
  116. case 16:
  117. switch (state.info_raw.colortype)
  118. {
  119. case LCT_GREY:
  120. for (uint32_t ii = 0, num = width*height; ii < num; ++ii)
  121. {
  122. uint16_t* rgba = (uint16_t*)data + ii;
  123. rgba[0] = bx::toHostEndian(rgba[0], false);
  124. }
  125. format = bgfx::TextureFormat::R16;
  126. break;
  127. case LCT_GREY_ALPHA:
  128. for (uint32_t ii = 0, num = width*height; ii < num; ++ii)
  129. {
  130. uint16_t* rgba = (uint16_t*)data + ii*2;
  131. rgba[0] = bx::toHostEndian(rgba[0], false);
  132. rgba[1] = bx::toHostEndian(rgba[1], false);
  133. }
  134. format = bgfx::TextureFormat::RG16;
  135. break;
  136. case LCT_RGBA:
  137. for (uint32_t ii = 0, num = width*height; ii < num; ++ii)
  138. {
  139. uint16_t* rgba = (uint16_t*)data + ii*4;
  140. rgba[0] = bx::toHostEndian(rgba[0], false);
  141. rgba[1] = bx::toHostEndian(rgba[1], false);
  142. rgba[2] = bx::toHostEndian(rgba[2], false);
  143. rgba[3] = bx::toHostEndian(rgba[3], false);
  144. }
  145. format = bgfx::TextureFormat::RGBA16;
  146. break;
  147. case LCT_RGB:
  148. case LCT_PALETTE:
  149. break;
  150. }
  151. break;
  152. default:
  153. break;
  154. }
  155. }
  156. lodepng_state_cleanup(&state);
  157. ImageContainer* output = imageAlloc(_allocator
  158. , format
  159. , uint16_t(width)
  160. , uint16_t(height)
  161. , 0
  162. , 1
  163. , false
  164. , false
  165. , data
  166. );
  167. lodepng_free(data);
  168. return output;
  169. }
  170. static ImageContainer* imageParseTinyExr(bx::AllocatorI* _allocator, const void* _data, uint32_t _size)
  171. {
  172. EXRVersion exrVersion;
  173. int result = ParseEXRVersionFromMemory(&exrVersion, (uint8_t*)_data, _size);
  174. if (TINYEXR_SUCCESS != result)
  175. {
  176. return NULL;
  177. }
  178. bgfx::TextureFormat::Enum format = bgfx::TextureFormat::RGBA8;
  179. uint32_t width = 0;
  180. uint32_t height = 0;
  181. uint8_t* data = NULL;
  182. const char* err = NULL;
  183. EXRHeader exrHeader;
  184. result = ParseEXRHeaderFromMemory(&exrHeader, &exrVersion, (uint8_t*)_data, _size, &err);
  185. if (TINYEXR_SUCCESS == result)
  186. {
  187. EXRImage exrImage;
  188. InitEXRImage(&exrImage);
  189. result = LoadEXRImageFromMemory(&exrImage, &exrHeader, (uint8_t*)_data, _size, &err);
  190. if (TINYEXR_SUCCESS == result)
  191. {
  192. uint8_t idxR = UINT8_MAX;
  193. uint8_t idxG = UINT8_MAX;
  194. uint8_t idxB = UINT8_MAX;
  195. uint8_t idxA = UINT8_MAX;
  196. for (uint8_t ii = 0, num = uint8_t(exrHeader.num_channels); ii < num; ++ii)
  197. {
  198. const EXRChannelInfo& channel = exrHeader.channels[ii];
  199. if (UINT8_MAX == idxR
  200. && 0 == bx::strncmp(channel.name, "R") )
  201. {
  202. idxR = ii;
  203. }
  204. else if (UINT8_MAX == idxG
  205. && 0 == bx::strncmp(channel.name, "G") )
  206. {
  207. idxG = ii;
  208. }
  209. else if (UINT8_MAX == idxB
  210. && 0 == bx::strncmp(channel.name, "B") )
  211. {
  212. idxB = ii;
  213. }
  214. else if (UINT8_MAX == idxA
  215. && 0 == bx::strncmp(channel.name, "A") )
  216. {
  217. idxA = ii;
  218. }
  219. }
  220. if (UINT8_MAX != idxR)
  221. {
  222. const bool asFloat = exrHeader.pixel_types[idxR] == TINYEXR_PIXELTYPE_FLOAT;
  223. uint32_t srcBpp = 32;
  224. uint32_t dstBpp = asFloat ? 32 : 16;
  225. format = asFloat ? TextureFormat::R32F : TextureFormat::R16F;
  226. uint32_t stepR = 1;
  227. uint32_t stepG = 0;
  228. uint32_t stepB = 0;
  229. uint32_t stepA = 0;
  230. if (UINT8_MAX != idxG)
  231. {
  232. srcBpp += 32;
  233. dstBpp = asFloat ? 64 : 32;
  234. format = asFloat ? TextureFormat::RG32F : TextureFormat::RG16F;
  235. stepG = 1;
  236. }
  237. if (UINT8_MAX != idxB)
  238. {
  239. srcBpp += 32;
  240. dstBpp = asFloat ? 128 : 64;
  241. format = asFloat ? TextureFormat::RGBA32F : TextureFormat::RGBA16F;
  242. stepB = 1;
  243. }
  244. if (UINT8_MAX != idxA)
  245. {
  246. srcBpp += 32;
  247. dstBpp = asFloat ? 128 : 64;
  248. format = asFloat ? TextureFormat::RGBA32F : TextureFormat::RGBA16F;
  249. stepA = 1;
  250. }
  251. data = (uint8_t*)BX_ALLOC(_allocator, exrImage.width * exrImage.height * dstBpp/8);
  252. const float zero = 0.0f;
  253. const float* srcR = UINT8_MAX == idxR ? &zero : (const float*)(exrImage.images)[idxR];
  254. const float* srcG = UINT8_MAX == idxG ? &zero : (const float*)(exrImage.images)[idxG];
  255. const float* srcB = UINT8_MAX == idxB ? &zero : (const float*)(exrImage.images)[idxB];
  256. const float* srcA = UINT8_MAX == idxA ? &zero : (const float*)(exrImage.images)[idxA];
  257. const uint32_t bytesPerPixel = dstBpp/8;
  258. for (uint32_t ii = 0, num = exrImage.width * exrImage.height; ii < num; ++ii)
  259. {
  260. float rgba[4] =
  261. {
  262. *srcR,
  263. *srcG,
  264. *srcB,
  265. *srcA,
  266. };
  267. bx::memCopy(&data[ii * bytesPerPixel], rgba, bytesPerPixel);
  268. srcR += stepR;
  269. srcG += stepG;
  270. srcB += stepB;
  271. srcA += stepA;
  272. }
  273. }
  274. FreeEXRImage(&exrImage);
  275. }
  276. FreeEXRHeader(&exrHeader);
  277. }
  278. ImageContainer* output = imageAlloc(_allocator
  279. , format
  280. , uint16_t(width)
  281. , uint16_t(height)
  282. , 0
  283. , 1
  284. , false
  285. , false
  286. , data
  287. );
  288. BX_FREE(_allocator, data);
  289. return output;
  290. }
  291. static ImageContainer* imageParseStbImage(bx::AllocatorI* _allocator, const void* _data, uint32_t _size)
  292. {
  293. TextureFormat::Enum format = TextureFormat::RGBA8;
  294. uint32_t width = 0;
  295. uint32_t height = 0;
  296. int comp = 0;
  297. void* data = stbi_load_from_memory( (uint8_t*)_data, _size, (int*)&width, (int*)&height, &comp, 4);
  298. if (NULL == data)
  299. {
  300. return NULL;
  301. }
  302. ImageContainer* output = imageAlloc(_allocator
  303. , format
  304. , uint16_t(width)
  305. , uint16_t(height)
  306. , 0
  307. , 1
  308. , false
  309. , false
  310. , data
  311. );
  312. stbi_image_free(data);
  313. return output;
  314. }
  315. ImageContainer* imageParse(bx::AllocatorI* _allocator, const void* _data, uint32_t _size, TextureFormat::Enum _dstFormat)
  316. {
  317. ImageContainer* input = imageParseBgfx (_allocator, _data, _size) ;
  318. input = NULL == input ? imageParseLodePng (_allocator, _data, _size) : input;
  319. input = NULL == input ? imageParseTinyExr (_allocator, _data, _size) : input;
  320. input = NULL == input ? imageParseStbImage(_allocator, _data, _size) : input;
  321. if (NULL == input)
  322. {
  323. return NULL;
  324. }
  325. _dstFormat = TextureFormat::Count == _dstFormat
  326. ? input->m_format
  327. : _dstFormat
  328. ;
  329. if (_dstFormat == input->m_format)
  330. {
  331. return input;
  332. }
  333. ImageContainer* output = imageConvert(_allocator, _dstFormat, *input);
  334. imageFree(input);
  335. return output;
  336. }
  337. } // namespace bgfx