texturec.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899
  1. /*
  2. Copyright 2011-2018 Branimir Karadzic.
  3. Copyright (c) 2015-2018 Bruce A Henderson
  4. All rights reserved.
  5. Redistribution and use in source and binary forms, with or without
  6. modification, are permitted provided that the following conditions are met:
  7. * Redistributions of source code must retain the above copyright notice, this
  8. list of conditions and the following disclaimer.
  9. * Redistributions in binary form must reproduce the above copyright notice,
  10. this list of conditions and the following disclaimer in the documentation
  11. and/or other materials provided with the distribution.
  12. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  13. AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  14. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  15. DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  16. FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  17. DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  18. SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  19. CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  20. OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  21. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  22. */
  23. #include <bx/allocator.h>
  24. #include <bx/readerwriter.h>
  25. #include <bx/endian.h>
  26. #include <bx/math.h>
  27. #include <bimg/decode.h>
  28. #include <bimg/encode.h>
  29. #include "brl.mod/blitz.mod/blitz.h"
  30. #include "gfx.mod/bxstream.mod/glue.h"
  31. enum OutputType {
  32. KTX,
  33. DDS,
  34. PNG,
  35. EXR
  36. };
  37. struct Options
  38. {
  39. Options()
  40. : maxSize(UINT32_MAX)
  41. , edge(0.0f)
  42. , format(bimg::TextureFormat::Count)
  43. , quality(bimg::Quality::Default)
  44. , mips(false)
  45. , normalMap(false)
  46. , equirect(false)
  47. , iqa(false)
  48. , pma(false)
  49. , sdf(false)
  50. , alphaTest(false)
  51. , outputType(KTX)
  52. {
  53. }
  54. uint32_t maxSize;
  55. float edge;
  56. bimg::TextureFormat::Enum format;
  57. bimg::Quality::Enum quality;
  58. bool mips;
  59. bool normalMap;
  60. bool equirect;
  61. bool iqa;
  62. bool pma;
  63. bool sdf;
  64. bool alphaTest;
  65. OutputType outputType;
  66. };
  67. extern "C" {
  68. Options * bmx_bimg_options_new();
  69. void bmx_bimg_options_free(Options * options);
  70. void bmx_bimg_options_setMaxSize(Options * options, int maxSize);
  71. void bmx_bimg_options_setEdge(Options * options, float edge);
  72. void bmx_bimg_options_setFormat(Options * options, int format);
  73. void bmx_bimg_options_setQuality(Options * options, int quality);
  74. void bmx_bimg_options_setMips(Options * options, int mips);
  75. void bmx_bimg_options_setNormalMap(Options * options, int normalMap);
  76. void bmx_bimg_options_setEquirect(Options * options, int equirect);
  77. void bmx_bimg_options_setIqa(Options * options, int iqa);
  78. void bmx_bimg_options_setPma(Options * options, int pma);
  79. void bmx_bimg_options_setSdf(Options * options, int sdf);
  80. void bmx_bimg_options_setAlphaTest(Options * options, int alphaTest);
  81. void bmx_bimg_options_setOutputType(Options * options, int outputType);
  82. void bmx_bimg_texturec_convert(MaxBxStream * reader, MaxBxStream * writer, Options * options);
  83. }
  84. static void imageRgba32fNormalize(void* _dst, uint32_t _width, uint32_t _height, uint32_t _srcPitch, const void* _src)
  85. {
  86. const uint8_t* src = (const uint8_t*)_src;
  87. uint8_t* dst = (uint8_t*)_dst;
  88. for (uint32_t yy = 0, ystep = _srcPitch; yy < _height; ++yy, src += ystep)
  89. {
  90. const float* rgba = (const float*)&src[0];
  91. for (uint32_t xx = 0; xx < _width; ++xx, rgba += 4, dst += 16)
  92. {
  93. float xyz[3];
  94. xyz[0] = rgba[0];
  95. xyz[1] = rgba[1];
  96. xyz[2] = rgba[2];
  97. bx::vec3Norm( (float*)dst, xyz);
  98. }
  99. }
  100. }
  101. static void imagePremultiplyAlpha(void* _inOut, uint32_t _width, uint32_t _height, uint32_t _depth, bimg::TextureFormat::Enum _format)
  102. {
  103. uint8_t* inOut = (uint8_t*)_inOut;
  104. uint32_t bpp = bimg::getBitsPerPixel(_format);
  105. uint32_t pitch = _width*bpp/8;
  106. bimg::PackFn pack = bimg::getPack(_format);
  107. bimg::UnpackFn unpack = bimg::getUnpack(_format);
  108. for (uint32_t zz = 0; zz < _depth; ++zz)
  109. {
  110. for (uint32_t yy = 0; yy < _height; ++yy)
  111. {
  112. for (uint32_t xx = 0; xx < _width; ++xx)
  113. {
  114. const uint32_t offset = yy*pitch + xx*bpp/8;
  115. float rgba[4];
  116. unpack(rgba, &inOut[offset]);
  117. const float alpha = rgba[3];
  118. rgba[0] = bx::toGamma(bx::toLinear(rgba[0]) * alpha);
  119. rgba[1] = bx::toGamma(bx::toLinear(rgba[1]) * alpha);
  120. rgba[2] = bx::toGamma(bx::toLinear(rgba[2]) * alpha);
  121. pack(&inOut[offset], rgba);
  122. }
  123. }
  124. }
  125. }
  126. static bimg::ImageContainer* convert(bx::AllocatorI* _allocator, const void* _inputData, uint32_t _inputSize, const Options& _options, bx::Error* _err)
  127. {
  128. BX_ERROR_SCOPE(_err);
  129. const uint8_t* inputData = (uint8_t*)_inputData;
  130. bimg::ImageContainer* output = NULL;
  131. bimg::ImageContainer* input = bimg::imageParse(_allocator, inputData, _inputSize, bimg::TextureFormat::Count, _err);
  132. if (!_err->isOk() )
  133. {
  134. return NULL;
  135. }
  136. if (NULL != input)
  137. {
  138. bimg::TextureFormat::Enum inputFormat = input->m_format;
  139. bimg::TextureFormat::Enum outputFormat = input->m_format;
  140. if (bimg::TextureFormat::Count != _options.format)
  141. {
  142. outputFormat = _options.format;
  143. }
  144. if (_options.sdf)
  145. {
  146. outputFormat = bimg::TextureFormat::R8;
  147. }
  148. const bimg::ImageBlockInfo& inputBlockInfo = bimg::getBlockInfo(inputFormat);
  149. const bimg::ImageBlockInfo& outputBlockInfo = bimg::getBlockInfo(outputFormat);
  150. const uint32_t blockWidth = outputBlockInfo.blockWidth;
  151. const uint32_t blockHeight = outputBlockInfo.blockHeight;
  152. const uint32_t minBlockX = outputBlockInfo.minBlockX;
  153. const uint32_t minBlockY = outputBlockInfo.minBlockY;
  154. uint32_t outputWidth = bx::uint32_max(blockWidth * minBlockX, ( (input->m_width + blockWidth - 1) / blockWidth )*blockWidth);
  155. uint32_t outputHeight = bx::uint32_max(blockHeight * minBlockY, ( (input->m_height + blockHeight - 1) / blockHeight)*blockHeight);
  156. uint32_t outputDepth = input->m_depth;
  157. if (outputWidth > _options.maxSize
  158. || outputHeight > _options.maxSize
  159. || outputDepth > _options.maxSize)
  160. {
  161. if (outputDepth > outputWidth
  162. && outputDepth > outputHeight)
  163. {
  164. outputWidth = outputWidth * _options.maxSize / outputDepth;
  165. outputHeight = outputHeight * _options.maxSize / outputDepth;
  166. outputDepth = _options.maxSize;
  167. }
  168. else if (outputWidth > outputHeight)
  169. {
  170. outputDepth = outputDepth * _options.maxSize / outputWidth;
  171. outputHeight = outputHeight * _options.maxSize / outputWidth;
  172. outputWidth = _options.maxSize;
  173. }
  174. else
  175. {
  176. outputDepth = outputDepth * _options.maxSize / outputHeight;
  177. outputWidth = outputWidth * _options.maxSize / outputHeight;
  178. outputHeight = _options.maxSize;
  179. }
  180. }
  181. const bool needResize = false
  182. || input->m_width != outputWidth
  183. || input->m_height != outputHeight
  184. ;
  185. const bool passThru = true
  186. && !needResize
  187. && (1 < input->m_numMips) == _options.mips
  188. && !_options.sdf
  189. && !_options.alphaTest
  190. && !_options.normalMap
  191. && !_options.equirect
  192. && !_options.iqa
  193. && !_options.pma
  194. ;
  195. if (needResize)
  196. {
  197. bimg::ImageContainer* src = bimg::imageConvert(_allocator, bimg::TextureFormat::RGBA32F, *input, false);
  198. bimg::ImageContainer* dst = bimg::imageAlloc(
  199. _allocator
  200. , bimg::TextureFormat::RGBA32F
  201. , uint16_t(outputWidth)
  202. , uint16_t(outputHeight)
  203. , uint16_t(outputDepth)
  204. , input->m_numLayers
  205. , input->m_cubeMap
  206. , false
  207. );
  208. bimg::imageResizeRgba32fLinear(dst, src);
  209. bimg::imageFree(src);
  210. bimg::imageFree(input);
  211. if (bimg::isCompressed(inputFormat) )
  212. {
  213. if (inputFormat == bimg::TextureFormat::BC6H)
  214. {
  215. inputFormat = bimg::TextureFormat::RGBA32F;
  216. }
  217. else
  218. {
  219. inputFormat = bimg::TextureFormat::RGBA8;
  220. }
  221. }
  222. input = bimg::imageConvert(_allocator, inputFormat, *dst);
  223. bimg::imageFree(dst);
  224. }
  225. if (passThru)
  226. {
  227. if (inputFormat != outputFormat
  228. && bimg::isCompressed(outputFormat) )
  229. {
  230. output = bimg::imageEncode(_allocator, outputFormat, _options.quality, *input);
  231. }
  232. else
  233. {
  234. output = bimg::imageConvert(_allocator, outputFormat, *input);
  235. }
  236. bimg::imageFree(input);
  237. return output;
  238. }
  239. if (_options.equirect)
  240. {
  241. bimg::ImageContainer* src = bimg::imageConvert(_allocator, bimg::TextureFormat::RGBA32F, *input);
  242. bimg::imageFree(input);
  243. bimg::ImageContainer* dst = bimg::imageCubemapFromLatLongRgba32F(_allocator, *src, true, _err);
  244. bimg::imageFree(src);
  245. if (!_err->isOk() )
  246. {
  247. return NULL;
  248. }
  249. input = bimg::imageConvert(_allocator, inputFormat, *dst);
  250. bimg::imageFree(dst);
  251. }
  252. output = bimg::imageAlloc(
  253. _allocator
  254. , outputFormat
  255. , uint16_t(input->m_width)
  256. , uint16_t(input->m_height)
  257. , uint16_t(input->m_depth)
  258. , input->m_numLayers
  259. , input->m_cubeMap
  260. , _options.mips
  261. );
  262. const uint8_t numMips = output->m_numMips;
  263. const uint16_t numSides = output->m_numLayers * (output->m_cubeMap ? 6 : 1);
  264. for (uint16_t side = 0; side < numSides && _err->isOk(); ++side)
  265. {
  266. bimg::ImageMip mip;
  267. if (bimg::imageGetRawData(*input, side, 0, input->m_data, input->m_size, mip) )
  268. {
  269. bimg::ImageMip dstMip;
  270. bimg::imageGetRawData(*output, side, 0, output->m_data, output->m_size, dstMip);
  271. uint8_t* dstData = const_cast<uint8_t*>(dstMip.m_data);
  272. void* temp = NULL;
  273. // Normal map.
  274. if (_options.normalMap)
  275. {
  276. uint32_t size = bimg::imageGetSize(
  277. NULL
  278. , uint16_t(dstMip.m_width)
  279. , uint16_t(dstMip.m_height)
  280. , 0
  281. , false
  282. , false
  283. , 1
  284. , bimg::TextureFormat::RGBA32F
  285. );
  286. temp = BX_ALLOC(_allocator, size);
  287. float* rgba = (float*)temp;
  288. float* rgbaDst = (float*)BX_ALLOC(_allocator, size);
  289. bimg::imageDecodeToRgba32f(_allocator
  290. , rgba
  291. , mip.m_data
  292. , dstMip.m_width
  293. , dstMip.m_height
  294. , dstMip.m_depth
  295. , dstMip.m_width*16
  296. , mip.m_format
  297. );
  298. if (bimg::TextureFormat::BC5 != mip.m_format)
  299. {
  300. for (uint32_t yy = 0; yy < mip.m_height; ++yy)
  301. {
  302. for (uint32_t xx = 0; xx < mip.m_width; ++xx)
  303. {
  304. const uint32_t offset = (yy*mip.m_width + xx) * 4;
  305. float* inout = &rgba[offset];
  306. inout[0] = inout[0] * 2.0f - 1.0f;
  307. inout[1] = inout[1] * 2.0f - 1.0f;
  308. inout[2] = inout[2] * 2.0f - 1.0f;
  309. inout[3] = inout[3] * 2.0f - 1.0f;
  310. }
  311. }
  312. }
  313. imageRgba32fNormalize(rgba
  314. , dstMip.m_width
  315. , dstMip.m_height
  316. , dstMip.m_width*16
  317. , rgba
  318. );
  319. bimg::imageRgba32f11to01(rgbaDst
  320. , dstMip.m_width
  321. , dstMip.m_height
  322. , dstMip.m_depth
  323. , dstMip.m_width*16
  324. , rgba
  325. );
  326. bimg::imageEncodeFromRgba32f(_allocator
  327. , dstData
  328. , rgbaDst
  329. , dstMip.m_width
  330. , dstMip.m_height
  331. , dstMip.m_depth
  332. , outputFormat
  333. , _options.quality
  334. , _err
  335. );
  336. for (uint8_t lod = 1; lod < numMips && _err->isOk(); ++lod)
  337. {
  338. bimg::imageRgba32fDownsample2x2NormalMap(rgba
  339. , dstMip.m_width
  340. , dstMip.m_height
  341. , dstMip.m_width*16
  342. , bx::strideAlign(dstMip.m_width/2, blockWidth)*16
  343. , rgba
  344. );
  345. bimg::imageRgba32f11to01(rgbaDst
  346. , dstMip.m_width
  347. , dstMip.m_height
  348. , dstMip.m_depth
  349. , dstMip.m_width*16
  350. , rgba
  351. );
  352. bimg::imageGetRawData(*output, side, lod, output->m_data, output->m_size, dstMip);
  353. dstData = const_cast<uint8_t*>(dstMip.m_data);
  354. bimg::imageEncodeFromRgba32f(_allocator
  355. , dstData
  356. , rgbaDst
  357. , dstMip.m_width
  358. , dstMip.m_height
  359. , dstMip.m_depth
  360. , outputFormat
  361. , _options.quality
  362. , _err
  363. );
  364. }
  365. BX_FREE(_allocator, rgbaDst);
  366. }
  367. // HDR
  368. else if ( (!bimg::isCompressed(inputFormat) && 8 != inputBlockInfo.rBits)
  369. || outputFormat == bimg::TextureFormat::BC6H
  370. || outputFormat == bimg::TextureFormat::BC7
  371. )
  372. {
  373. uint32_t size = bimg::imageGetSize(
  374. NULL
  375. , uint16_t(dstMip.m_width)
  376. , uint16_t(dstMip.m_height)
  377. , uint16_t(dstMip.m_depth)
  378. , false
  379. , false
  380. , 1
  381. , bimg::TextureFormat::RGBA32F
  382. );
  383. temp = BX_ALLOC(_allocator, size);
  384. float* rgba32f = (float*)temp;
  385. float* rgbaDst = (float*)BX_ALLOC(_allocator, size);
  386. bimg::imageDecodeToRgba32f(_allocator
  387. , rgba32f
  388. , mip.m_data
  389. , mip.m_width
  390. , mip.m_height
  391. , mip.m_depth
  392. , mip.m_width*16
  393. , mip.m_format
  394. );
  395. if (_options.pma)
  396. {
  397. imagePremultiplyAlpha(
  398. rgba32f
  399. , dstMip.m_width
  400. , dstMip.m_height
  401. , dstMip.m_depth
  402. , bimg::TextureFormat::RGBA32F
  403. );
  404. }
  405. bimg::imageEncodeFromRgba32f(_allocator
  406. , dstData
  407. , rgba32f
  408. , dstMip.m_width
  409. , dstMip.m_height
  410. , dstMip.m_depth
  411. , outputFormat
  412. , _options.quality
  413. , _err
  414. );
  415. if (1 < numMips
  416. && _err->isOk() )
  417. {
  418. bimg::imageRgba32fToLinear(rgba32f
  419. , mip.m_width
  420. , mip.m_height
  421. , mip.m_depth
  422. , mip.m_width*16
  423. , rgba32f
  424. );
  425. for (uint8_t lod = 1; lod < numMips && _err->isOk(); ++lod)
  426. {
  427. bimg::imageRgba32fLinearDownsample2x2(rgba32f
  428. , dstMip.m_width
  429. , dstMip.m_height
  430. , dstMip.m_depth
  431. , dstMip.m_width*16
  432. , rgba32f
  433. );
  434. if (_options.pma)
  435. {
  436. imagePremultiplyAlpha(
  437. rgba32f
  438. , dstMip.m_width
  439. , dstMip.m_height
  440. , dstMip.m_depth
  441. , bimg::TextureFormat::RGBA32F
  442. );
  443. }
  444. bimg::imageGetRawData(*output, side, lod, output->m_data, output->m_size, dstMip);
  445. dstData = const_cast<uint8_t*>(dstMip.m_data);
  446. bimg::imageRgba32fToGamma(rgbaDst
  447. , mip.m_width
  448. , mip.m_height
  449. , mip.m_depth
  450. , mip.m_width*16
  451. , rgba32f
  452. );
  453. bimg::imageEncodeFromRgba32f(_allocator
  454. , dstData
  455. , rgbaDst
  456. , dstMip.m_width
  457. , dstMip.m_height
  458. , dstMip.m_depth
  459. , outputFormat
  460. , _options.quality
  461. , _err
  462. );
  463. }
  464. }
  465. BX_FREE(_allocator, rgbaDst);
  466. }
  467. // SDF
  468. else if (_options.sdf)
  469. {
  470. uint32_t size = bimg::imageGetSize(
  471. NULL
  472. , uint16_t(dstMip.m_width)
  473. , uint16_t(dstMip.m_height)
  474. , uint16_t(dstMip.m_depth)
  475. , false
  476. , false
  477. , 1
  478. , bimg::TextureFormat::R8
  479. );
  480. temp = BX_ALLOC(_allocator, size);
  481. uint8_t* rgba = (uint8_t*)temp;
  482. bimg::imageDecodeToR8(_allocator
  483. , rgba
  484. , mip.m_data
  485. , mip.m_width
  486. , mip.m_height
  487. , mip.m_depth
  488. , mip.m_width
  489. , mip.m_format
  490. );
  491. bimg::imageGetRawData(*output, side, 0, output->m_data, output->m_size, dstMip);
  492. dstData = const_cast<uint8_t*>(dstMip.m_data);
  493. bimg::imageMakeDist(_allocator
  494. , dstData
  495. , mip.m_width
  496. , mip.m_height
  497. , mip.m_width
  498. , _options.edge
  499. , rgba
  500. );
  501. }
  502. // RGBA8
  503. else
  504. {
  505. uint32_t size = bimg::imageGetSize(
  506. NULL
  507. , uint16_t(dstMip.m_width)
  508. , uint16_t(dstMip.m_height)
  509. , uint16_t(dstMip.m_depth)
  510. , false
  511. , false
  512. , 1
  513. , bimg::TextureFormat::RGBA8
  514. );
  515. temp = BX_ALLOC(_allocator, size);
  516. uint8_t* rgba = (uint8_t*)temp;
  517. bimg::imageDecodeToRgba8(
  518. _allocator
  519. , rgba
  520. , mip.m_data
  521. , mip.m_width
  522. , mip.m_height
  523. , mip.m_width*4
  524. , mip.m_format
  525. );
  526. float coverage = 0.0f;
  527. if (_options.alphaTest)
  528. {
  529. coverage = bimg::imageAlphaTestCoverage(bimg::TextureFormat::RGBA8
  530. , mip.m_width
  531. , mip.m_height
  532. , mip.m_width*4
  533. , rgba
  534. , _options.edge
  535. );
  536. }
  537. void* ref = NULL;
  538. if (_options.iqa)
  539. {
  540. ref = BX_ALLOC(_allocator, size);
  541. bx::memCopy(ref, rgba, size);
  542. }
  543. if (_options.pma)
  544. {
  545. imagePremultiplyAlpha(
  546. rgba
  547. , dstMip.m_width
  548. , dstMip.m_height
  549. , dstMip.m_depth
  550. , bimg::TextureFormat::RGBA8
  551. );
  552. }
  553. bimg::imageGetRawData(*output, side, 0, output->m_data, output->m_size, dstMip);
  554. dstData = const_cast<uint8_t*>(dstMip.m_data);
  555. bimg::imageEncodeFromRgba8(
  556. _allocator
  557. , dstData
  558. , rgba
  559. , dstMip.m_width
  560. , dstMip.m_height
  561. , dstMip.m_depth
  562. , outputFormat
  563. , _options.quality
  564. , _err
  565. );
  566. for (uint8_t lod = 1; lod < numMips && _err->isOk(); ++lod)
  567. {
  568. bimg::imageRgba8Downsample2x2(rgba
  569. , dstMip.m_width
  570. , dstMip.m_height
  571. , dstMip.m_depth
  572. , dstMip.m_width*4
  573. , bx::strideAlign(dstMip.m_width/2, blockWidth)*4
  574. , rgba
  575. );
  576. if (_options.alphaTest)
  577. {
  578. bimg::imageScaleAlphaToCoverage(bimg::TextureFormat::RGBA8
  579. , dstMip.m_width
  580. , dstMip.m_height
  581. , dstMip.m_width*4
  582. , rgba
  583. , coverage
  584. , _options.edge
  585. );
  586. }
  587. if (_options.pma)
  588. {
  589. imagePremultiplyAlpha(
  590. rgba
  591. , dstMip.m_width
  592. , dstMip.m_height
  593. , dstMip.m_depth
  594. , bimg::TextureFormat::RGBA8
  595. );
  596. }
  597. bimg::imageGetRawData(*output, side, lod, output->m_data, output->m_size, dstMip);
  598. dstData = const_cast<uint8_t*>(dstMip.m_data);
  599. bimg::imageEncodeFromRgba8(
  600. _allocator
  601. , dstData
  602. , rgba
  603. , dstMip.m_width
  604. , dstMip.m_height
  605. , dstMip.m_depth
  606. , outputFormat
  607. , _options.quality
  608. , _err
  609. );
  610. }
  611. if (NULL != ref)
  612. {
  613. bimg::imageDecodeToRgba8(
  614. _allocator
  615. , rgba
  616. , output->m_data
  617. , mip.m_width
  618. , mip.m_height
  619. , mip.m_width*mip.m_bpp/8
  620. , outputFormat
  621. );
  622. float result = bimg::imageQualityRgba8(
  623. ref
  624. , rgba
  625. , uint16_t(mip.m_width)
  626. , uint16_t(mip.m_height)
  627. );
  628. printf("%f\n", result);
  629. BX_FREE(_allocator, ref);
  630. }
  631. }
  632. BX_FREE(_allocator, temp);
  633. }
  634. }
  635. bimg::imageFree(input);
  636. }
  637. if (!_err->isOk()
  638. && NULL != output)
  639. {
  640. bimg::imageFree(output);
  641. output = NULL;
  642. }
  643. return output;
  644. }
  645. class AlignedAllocator : public bx::AllocatorI
  646. {
  647. public:
  648. AlignedAllocator(bx::AllocatorI* _allocator, size_t _minAlignment)
  649. : m_allocator(_allocator)
  650. , m_minAlignment(_minAlignment)
  651. {
  652. }
  653. virtual void* realloc(
  654. void* _ptr
  655. , size_t _size
  656. , size_t _align
  657. , const char* _file
  658. , uint32_t _line
  659. )
  660. {
  661. return m_allocator->realloc(_ptr, _size, bx::max(_align, m_minAlignment), _file, _line);
  662. }
  663. bx::AllocatorI* m_allocator;
  664. size_t m_minAlignment;
  665. };
  666. class MaxTextureC {
  667. public :
  668. void convert(MaxBxStream * reader, MaxBxStream * writer, Options * options) {
  669. bx::Error err;
  670. Options defaultOptions;
  671. if (options == NULL)
  672. options = &defaultOptions;
  673. uint32_t inputSize = (uint32_t) bx::getSize(reader);
  674. if (0 == inputSize) {
  675. //help("Failed to read input file.", err);
  676. //return bx::kExitFailure;
  677. return;
  678. }
  679. bx::DefaultAllocator defaultAllocator;
  680. AlignedAllocator allocator(&defaultAllocator, 16);
  681. uint8_t *inputData = (uint8_t *) BX_ALLOC(&allocator, inputSize);
  682. bx::read(reader, inputData, inputSize, &err);
  683. bx::close(reader);
  684. if (!err.isOk()) {
  685. //help("Failed to read input file.", err);
  686. //return bx::kExitFailure;
  687. return;
  688. }
  689. bimg::ImageContainer *output = ::convert(&allocator, inputData, inputSize, *options, &err);
  690. BX_FREE(&allocator, inputData);
  691. if (NULL != output) {
  692. //bx::FileWriter writer;
  693. //if (bx::open(&writer, outputFileName, false, &err) )
  694. //{
  695. if (options->outputType == KTX) {
  696. bimg::imageWriteKtx(writer, *output, output->m_data, output->m_size, &err);
  697. } else if (options->outputType == DDS) {
  698. bimg::imageWriteDds(writer, *output, output->m_data, output->m_size, &err);
  699. } else if (options->outputType == PNG) {
  700. if (output->m_format != bimg::TextureFormat::RGBA8) {
  701. //help("Incompatible output texture format. Output PNG format must be RGBA8.", err);
  702. //return bx::kExitFailure;
  703. return;
  704. }
  705. bimg::ImageMip mip;
  706. bimg::imageGetRawData(*output, 0, 0, output->m_data, output->m_size, mip);
  707. bimg::imageWritePng(writer, mip.m_width, mip.m_height, mip.m_width * 4, mip.m_data, output->m_format,
  708. false, &err);
  709. } else if (options->outputType == EXR) {
  710. bimg::ImageMip mip;
  711. bimg::imageGetRawData(*output, 0, 0, output->m_data, output->m_size, mip);
  712. bimg::imageWriteExr(writer, mip.m_width, mip.m_height, mip.m_width * 8, mip.m_data, output->m_format,
  713. false, &err);
  714. }
  715. bx::close(writer);
  716. if (!err.isOk()) {
  717. // help(NULL, err);
  718. //return bx::kExitFailure;
  719. return;
  720. }
  721. //}
  722. bimg::imageFree(output);
  723. }
  724. }
  725. };
  726. // --------------------------------------------------------
  727. void bmx_bimg_texturec_convert(MaxBxStream * reader, MaxBxStream * writer, Options * options) {
  728. MaxTextureC textureC;
  729. textureC.convert(reader, writer, options);
  730. };
  731. // --------------------------------------------------------
  732. Options * bmx_bimg_options_new() {
  733. return new Options;
  734. }
  735. void bmx_bimg_options_free(Options * options) {
  736. delete options;
  737. }
  738. void bmx_bimg_options_setMaxSize(Options * options, int maxSize) {
  739. options->maxSize = static_cast<uint32_t>(maxSize);
  740. }
  741. void bmx_bimg_options_setEdge(Options * options, float edge) {
  742. options->edge = edge;
  743. }
  744. void bmx_bimg_options_setFormat(Options * options, int format) {
  745. options->format = static_cast<bimg::TextureFormat::Enum>(format);
  746. }
  747. void bmx_bimg_options_setQuality(Options * options, int quality) {
  748. options->quality = static_cast<bimg::Quality::Enum>(quality);
  749. }
  750. void bmx_bimg_options_setMips(Options * options, int mips) {
  751. options->mips = static_cast<bool>(mips);
  752. }
  753. void bmx_bimg_options_setNormalMap(Options * options, int normalMap) {
  754. options->normalMap = static_cast<bool>(normalMap);
  755. }
  756. void bmx_bimg_options_setEquirect(Options * options, int equirect) {
  757. options->equirect = static_cast<bool>(equirect);
  758. }
  759. void bmx_bimg_options_setIqa(Options * options, int iqa) {
  760. options->iqa = static_cast<bool>(iqa);
  761. }
  762. void bmx_bimg_options_setPma(Options * options, int pma) {
  763. options->pma = static_cast<bool>(pma);
  764. }
  765. void bmx_bimg_options_setSdf(Options * options, int sdf) {
  766. options->sdf = static_cast<bool>(sdf);
  767. }
  768. void bmx_bimg_options_setAlphaTest(Options * options, int alphaTest) {
  769. options->alphaTest = static_cast<bool>(alphaTest);
  770. }
  771. void bmx_bimg_options_setOutputType(Options * options, int outputType) {
  772. options->outputType = static_cast<OutputType>(outputType);
  773. }