texturec.cpp 27 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067
  1. /*
  2. Copyright 2011-2019 Branimir Karadzic.
  3. Copyright (c) 2015-2019 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. HDR
  37. };
  38. struct Options
  39. {
  40. Options()
  41. : maxSize(UINT32_MAX)
  42. , mipSkip(0)
  43. , edge(0.0f)
  44. , format(bimg::TextureFormat::Count)
  45. , quality(bimg::Quality::Default)
  46. , radiance(bimg::LightingModel::Count)
  47. , mips(false)
  48. , normalMap(false)
  49. , equirect(false)
  50. , strip(false)
  51. , iqa(false)
  52. , pma(false)
  53. , sdf(false)
  54. , alphaTest(false)
  55. , linear(false)
  56. , outputType(KTX)
  57. {
  58. }
  59. uint32_t maxSize;
  60. uint32_t mipSkip;
  61. float edge;
  62. bimg::TextureFormat::Enum format;
  63. bimg::Quality::Enum quality;
  64. bimg::LightingModel::Enum radiance;
  65. bool mips;
  66. bool normalMap;
  67. bool equirect;
  68. bool strip;
  69. bool iqa;
  70. bool pma;
  71. bool sdf;
  72. bool alphaTest;
  73. bool linear;
  74. OutputType outputType;
  75. };
  76. extern "C" {
  77. Options * bmx_bimg_options_new();
  78. void bmx_bimg_options_free(Options * options);
  79. void bmx_bimg_options_setMaxSize(Options * options, int maxSize);
  80. void bmx_bimg_options_setEdge(Options * options, float edge);
  81. void bmx_bimg_options_setFormat(Options * options, int format);
  82. void bmx_bimg_options_setQuality(Options * options, int quality);
  83. void bmx_bimg_options_setMips(Options * options, int mips);
  84. void bmx_bimg_options_setNormalMap(Options * options, int normalMap);
  85. void bmx_bimg_options_setEquirect(Options * options, int equirect);
  86. void bmx_bimg_options_setIqa(Options * options, int iqa);
  87. void bmx_bimg_options_setPma(Options * options, int pma);
  88. void bmx_bimg_options_setSdf(Options * options, int sdf);
  89. void bmx_bimg_options_setAlphaTest(Options * options, int alphaTest);
  90. void bmx_bimg_options_setOutputType(Options * options, int outputType);
  91. void bmx_bimg_texturec_convert(MaxBxStream * reader, MaxBxStream * writer, Options * options);
  92. }
  93. static void imageRgba32fNormalize(void* _dst, uint32_t _width, uint32_t _height, uint32_t _srcPitch, const void* _src)
  94. {
  95. const uint8_t* src = (const uint8_t*)_src;
  96. uint8_t* dst = (uint8_t*)_dst;
  97. for (uint32_t yy = 0, ystep = _srcPitch; yy < _height; ++yy, src += ystep)
  98. {
  99. const float* rgba = (const float*)&src[0];
  100. for (uint32_t xx = 0; xx < _width; ++xx, rgba += 4, dst += 16)
  101. {
  102. const bx::Vec3 xyz = bx::load<bx::Vec3>(rgba);
  103. bx::store(dst, bx::normalize(xyz) );
  104. }
  105. }
  106. }
  107. static void imagePremultiplyAlpha(void* _inOut, uint32_t _width, uint32_t _height, uint32_t _depth, bimg::TextureFormat::Enum _format)
  108. {
  109. uint8_t* inOut = (uint8_t*)_inOut;
  110. uint32_t bpp = bimg::getBitsPerPixel(_format);
  111. uint32_t pitch = _width*bpp/8;
  112. bimg::PackFn pack = bimg::getPack(_format);
  113. bimg::UnpackFn unpack = bimg::getUnpack(_format);
  114. for (uint32_t zz = 0; zz < _depth; ++zz)
  115. {
  116. for (uint32_t yy = 0; yy < _height; ++yy)
  117. {
  118. for (uint32_t xx = 0; xx < _width; ++xx)
  119. {
  120. const uint32_t offset = yy*pitch + xx*bpp/8;
  121. float rgba[4];
  122. unpack(rgba, &inOut[offset]);
  123. const float alpha = rgba[3];
  124. rgba[0] = bx::toGamma(bx::toLinear(rgba[0]) * alpha);
  125. rgba[1] = bx::toGamma(bx::toLinear(rgba[1]) * alpha);
  126. rgba[2] = bx::toGamma(bx::toLinear(rgba[2]) * alpha);
  127. pack(&inOut[offset], rgba);
  128. }
  129. }
  130. }
  131. }
  132. static bimg::ImageContainer* convert(bx::AllocatorI* _allocator, const void* _inputData, uint32_t _inputSize, const Options& _options, bx::Error* _err)
  133. {
  134. BX_ERROR_SCOPE(_err);
  135. const uint8_t* inputData = (uint8_t*)_inputData;
  136. bimg::ImageContainer* output = NULL;
  137. bimg::ImageContainer* input = bimg::imageParse(_allocator, inputData, _inputSize, bimg::TextureFormat::Count, _err);
  138. if (!_err->isOk() )
  139. {
  140. return NULL;
  141. }
  142. if (NULL != input)
  143. {
  144. bimg::TextureFormat::Enum inputFormat = input->m_format;
  145. bimg::TextureFormat::Enum outputFormat = input->m_format;
  146. if (bimg::TextureFormat::Count != _options.format)
  147. {
  148. outputFormat = _options.format;
  149. }
  150. if (_options.sdf)
  151. {
  152. outputFormat = bimg::TextureFormat::R8;
  153. }
  154. const bimg::ImageBlockInfo& inputBlockInfo = bimg::getBlockInfo(inputFormat);
  155. const bimg::ImageBlockInfo& outputBlockInfo = bimg::getBlockInfo(outputFormat);
  156. const uint32_t blockWidth = outputBlockInfo.blockWidth;
  157. const uint32_t blockHeight = outputBlockInfo.blockHeight;
  158. const uint32_t minBlockX = outputBlockInfo.minBlockX;
  159. const uint32_t minBlockY = outputBlockInfo.minBlockY;
  160. uint32_t outputWidth = bx::max(blockWidth * minBlockX, ( (input->m_width + blockWidth - 1) / blockWidth )*blockWidth);
  161. uint32_t outputHeight = bx::max(blockHeight * minBlockY, ( (input->m_height + blockHeight - 1) / blockHeight)*blockHeight);
  162. uint32_t outputDepth = input->m_depth;
  163. if (_options.mips
  164. && _options.mipSkip != 0)
  165. {
  166. for (uint32_t ii = 0; ii < _options.mipSkip; ++ii)
  167. {
  168. outputWidth = bx::max(blockWidth * minBlockX, ( ( (outputWidth>>1) + blockWidth - 1) / blockWidth )*blockWidth);
  169. outputHeight = bx::max(blockHeight * minBlockY, ( ( (outputHeight>>1) + blockHeight - 1) / blockHeight)*blockHeight);
  170. outputDepth = bx::max(outputDepth>>1, 1u);
  171. }
  172. }
  173. if (_options.equirect)
  174. {
  175. if (outputDepth == 1
  176. && outputWidth/2 == outputHeight)
  177. {
  178. if (outputWidth/2 > _options.maxSize)
  179. {
  180. outputWidth = _options.maxSize*4;
  181. outputHeight = _options.maxSize*2;
  182. }
  183. }
  184. else
  185. {
  186. bimg::imageFree(input);
  187. //_err->setError(1, "Input image format is not equirectangular projection.");
  188. return NULL;
  189. }
  190. }
  191. else if (_options.strip)
  192. {
  193. if (outputDepth == 1
  194. && outputWidth/6 == outputHeight)
  195. {
  196. if (outputWidth/6 > _options.maxSize)
  197. {
  198. outputWidth = _options.maxSize*6;
  199. outputHeight = _options.maxSize;
  200. }
  201. }
  202. else
  203. {
  204. bimg::imageFree(input);
  205. //_err->setError(1, "Input image format is not horizontal strip.");
  206. return NULL;
  207. }
  208. }
  209. else if (outputWidth > _options.maxSize
  210. || outputHeight > _options.maxSize
  211. || outputDepth > _options.maxSize)
  212. {
  213. if (outputDepth > outputWidth
  214. && outputDepth > outputHeight)
  215. {
  216. outputWidth = outputWidth * _options.maxSize / outputDepth;
  217. outputHeight = outputHeight * _options.maxSize / outputDepth;
  218. outputDepth = _options.maxSize;
  219. }
  220. else if (outputWidth > outputHeight)
  221. {
  222. outputDepth = outputDepth * _options.maxSize / outputWidth;
  223. outputHeight = outputHeight * _options.maxSize / outputWidth;
  224. outputWidth = _options.maxSize;
  225. }
  226. else
  227. {
  228. outputDepth = outputDepth * _options.maxSize / outputHeight;
  229. outputWidth = outputWidth * _options.maxSize / outputHeight;
  230. outputHeight = _options.maxSize;
  231. }
  232. }
  233. const bool needResize = false
  234. || input->m_width != outputWidth
  235. || input->m_height != outputHeight
  236. ;
  237. const bool passThru = true
  238. && !needResize
  239. && (1 < input->m_numMips) == _options.mips
  240. && !_options.sdf
  241. && !_options.alphaTest
  242. && !_options.normalMap
  243. && !(_options.equirect || _options.strip)
  244. && !_options.iqa
  245. && !_options.pma
  246. && (bimg::LightingModel::Count == _options.radiance)
  247. ;
  248. if (!_options.sdf
  249. && needResize)
  250. {
  251. bimg::ImageContainer* src = bimg::imageConvert(_allocator, bimg::TextureFormat::RGBA32F, *input, false);
  252. bimg::ImageContainer* dst = bimg::imageAlloc(
  253. _allocator
  254. , bimg::TextureFormat::RGBA32F
  255. , uint16_t(outputWidth)
  256. , uint16_t(outputHeight)
  257. , uint16_t(outputDepth)
  258. , input->m_numLayers
  259. , input->m_cubeMap
  260. , false
  261. );
  262. if (!_options.linear)
  263. {
  264. bimg::imageRgba32fToLinear(src);
  265. }
  266. bimg::imageResizeRgba32fLinear(dst, src);
  267. if (!_options.linear)
  268. {
  269. bimg::imageRgba32fToGamma(dst);
  270. }
  271. bimg::imageFree(src);
  272. bimg::imageFree(input);
  273. if (bimg::isCompressed(inputFormat) )
  274. {
  275. if (inputFormat == bimg::TextureFormat::BC6H)
  276. {
  277. inputFormat = bimg::TextureFormat::RGBA32F;
  278. }
  279. else
  280. {
  281. inputFormat = bimg::TextureFormat::RGBA8;
  282. }
  283. }
  284. input = bimg::imageConvert(_allocator, inputFormat, *dst);
  285. bimg::imageFree(dst);
  286. }
  287. if (passThru)
  288. {
  289. if (inputFormat != outputFormat
  290. && bimg::isCompressed(outputFormat) )
  291. {
  292. output = bimg::imageEncode(_allocator, outputFormat, _options.quality, *input);
  293. }
  294. else
  295. {
  296. output = bimg::imageConvert(_allocator, outputFormat, *input);
  297. }
  298. bimg::imageFree(input);
  299. return output;
  300. }
  301. if (_options.equirect
  302. || _options.strip)
  303. {
  304. bimg::ImageContainer* src = bimg::imageConvert(_allocator, bimg::TextureFormat::RGBA32F, *input);
  305. bimg::imageFree(input);
  306. bimg::ImageContainer* dst;
  307. if (outputWidth/2 == outputHeight)
  308. {
  309. dst = bimg::imageCubemapFromLatLongRgba32F(_allocator, *src, true, _err);
  310. bimg::imageFree(src);
  311. }
  312. else
  313. {
  314. dst = bimg::imageCubemapFromStripRgba32F(_allocator, *src, _err);
  315. bimg::imageFree(src);
  316. }
  317. if (!_err->isOk() )
  318. {
  319. return NULL;
  320. }
  321. input = bimg::imageConvert(_allocator, inputFormat, *dst);
  322. bimg::imageFree(dst);
  323. }
  324. if (bimg::LightingModel::Count != _options.radiance)
  325. {
  326. output = bimg::imageCubemapRadianceFilter(_allocator, *input, _options.radiance, _err);
  327. if (!_err->isOk() )
  328. {
  329. return NULL;
  330. }
  331. if (bimg::TextureFormat::RGBA32F != outputFormat)
  332. {
  333. bimg::ImageContainer* temp = bimg::imageEncode(_allocator, outputFormat, _options.quality, *output);
  334. bimg::imageFree(output);
  335. output = temp;
  336. }
  337. bimg::imageFree(input);
  338. return output;
  339. }
  340. output = bimg::imageAlloc(
  341. _allocator
  342. , outputFormat
  343. , uint16_t(input->m_width)
  344. , uint16_t(input->m_height)
  345. , uint16_t(input->m_depth)
  346. , input->m_numLayers
  347. , input->m_cubeMap
  348. , _options.mips
  349. );
  350. const uint8_t numMips = output->m_numMips;
  351. const uint16_t numSides = output->m_numLayers * (output->m_cubeMap ? 6 : 1);
  352. for (uint16_t side = 0; side < numSides && _err->isOk(); ++side)
  353. {
  354. bimg::ImageMip mip;
  355. if (bimg::imageGetRawData(*input, side, 0, input->m_data, input->m_size, mip) )
  356. {
  357. bimg::ImageMip dstMip;
  358. bimg::imageGetRawData(*output, side, 0, output->m_data, output->m_size, dstMip);
  359. uint8_t* dstData = const_cast<uint8_t*>(dstMip.m_data);
  360. void* temp = NULL;
  361. // Normal map.
  362. if (_options.normalMap)
  363. {
  364. uint32_t size = bimg::imageGetSize(
  365. NULL
  366. , uint16_t(dstMip.m_width)
  367. , uint16_t(dstMip.m_height)
  368. , 0
  369. , false
  370. , false
  371. , 1
  372. , bimg::TextureFormat::RGBA32F
  373. );
  374. temp = BX_ALLOC(_allocator, size);
  375. float* rgba = (float*)temp;
  376. float* rgbaDst = (float*)BX_ALLOC(_allocator, size);
  377. bimg::imageDecodeToRgba32f(_allocator
  378. , rgba
  379. , mip.m_data
  380. , dstMip.m_width
  381. , dstMip.m_height
  382. , dstMip.m_depth
  383. , dstMip.m_width*16
  384. , mip.m_format
  385. );
  386. if (bimg::TextureFormat::BC5 != mip.m_format)
  387. {
  388. for (uint32_t yy = 0; yy < mip.m_height; ++yy)
  389. {
  390. for (uint32_t xx = 0; xx < mip.m_width; ++xx)
  391. {
  392. const uint32_t offset = (yy*mip.m_width + xx) * 4;
  393. float* inout = &rgba[offset];
  394. inout[0] = inout[0] * 2.0f - 1.0f;
  395. inout[1] = inout[1] * 2.0f - 1.0f;
  396. inout[2] = inout[2] * 2.0f - 1.0f;
  397. inout[3] = inout[3] * 2.0f - 1.0f;
  398. }
  399. }
  400. }
  401. imageRgba32fNormalize(rgba
  402. , dstMip.m_width
  403. , dstMip.m_height
  404. , dstMip.m_width*16
  405. , rgba
  406. );
  407. bimg::imageRgba32f11to01(rgbaDst
  408. , dstMip.m_width
  409. , dstMip.m_height
  410. , dstMip.m_depth
  411. , dstMip.m_width*16
  412. , rgba
  413. );
  414. bimg::imageEncodeFromRgba32f(_allocator
  415. , dstData
  416. , rgbaDst
  417. , dstMip.m_width
  418. , dstMip.m_height
  419. , dstMip.m_depth
  420. , outputFormat
  421. , _options.quality
  422. , _err
  423. );
  424. for (uint8_t lod = 1; lod < numMips && _err->isOk(); ++lod)
  425. {
  426. bimg::imageRgba32fDownsample2x2NormalMap(rgba
  427. , dstMip.m_width
  428. , dstMip.m_height
  429. , dstMip.m_width*16
  430. , bx::strideAlign(dstMip.m_width/2, blockWidth)*16
  431. , rgba
  432. );
  433. bimg::imageRgba32f11to01(rgbaDst
  434. , dstMip.m_width
  435. , dstMip.m_height
  436. , dstMip.m_depth
  437. , dstMip.m_width*16
  438. , rgba
  439. );
  440. bimg::imageGetRawData(*output, side, lod, output->m_data, output->m_size, dstMip);
  441. dstData = const_cast<uint8_t*>(dstMip.m_data);
  442. bimg::imageEncodeFromRgba32f(_allocator
  443. , dstData
  444. , rgbaDst
  445. , dstMip.m_width
  446. , dstMip.m_height
  447. , dstMip.m_depth
  448. , outputFormat
  449. , _options.quality
  450. , _err
  451. );
  452. }
  453. BX_FREE(_allocator, rgbaDst);
  454. }
  455. // HDR
  456. else if ( (!bimg::isCompressed(inputFormat) && 8 != inputBlockInfo.rBits)
  457. || outputFormat == bimg::TextureFormat::BC6H
  458. || outputFormat == bimg::TextureFormat::BC7
  459. )
  460. {
  461. uint32_t size = bimg::imageGetSize(
  462. NULL
  463. , uint16_t(dstMip.m_width)
  464. , uint16_t(dstMip.m_height)
  465. , uint16_t(dstMip.m_depth)
  466. , false
  467. , false
  468. , 1
  469. , bimg::TextureFormat::RGBA32F
  470. );
  471. temp = BX_ALLOC(_allocator, size);
  472. float* rgba32f = (float*)temp;
  473. float* rgbaDst = (float*)BX_ALLOC(_allocator, size);
  474. bimg::imageDecodeToRgba32f(_allocator
  475. , rgba32f
  476. , mip.m_data
  477. , mip.m_width
  478. , mip.m_height
  479. , mip.m_depth
  480. , mip.m_width*16
  481. , mip.m_format
  482. );
  483. if (_options.pma)
  484. {
  485. imagePremultiplyAlpha(
  486. rgba32f
  487. , dstMip.m_width
  488. , dstMip.m_height
  489. , dstMip.m_depth
  490. , bimg::TextureFormat::RGBA32F
  491. );
  492. }
  493. bimg::imageEncodeFromRgba32f(_allocator
  494. , dstData
  495. , rgba32f
  496. , dstMip.m_width
  497. , dstMip.m_height
  498. , dstMip.m_depth
  499. , outputFormat
  500. , _options.quality
  501. , _err
  502. );
  503. if (1 < numMips
  504. && _err->isOk() )
  505. {
  506. bimg::imageRgba32fToLinear(rgba32f
  507. , mip.m_width
  508. , mip.m_height
  509. , mip.m_depth
  510. , mip.m_width*16
  511. , rgba32f
  512. );
  513. for (uint8_t lod = 1; lod < numMips && _err->isOk(); ++lod)
  514. {
  515. bimg::imageRgba32fLinearDownsample2x2(rgba32f
  516. , dstMip.m_width
  517. , dstMip.m_height
  518. , dstMip.m_depth
  519. , dstMip.m_width*16
  520. , rgba32f
  521. );
  522. if (_options.pma)
  523. {
  524. imagePremultiplyAlpha(
  525. rgba32f
  526. , dstMip.m_width
  527. , dstMip.m_height
  528. , dstMip.m_depth
  529. , bimg::TextureFormat::RGBA32F
  530. );
  531. }
  532. bimg::imageGetRawData(*output, side, lod, output->m_data, output->m_size, dstMip);
  533. dstData = const_cast<uint8_t*>(dstMip.m_data);
  534. bimg::imageRgba32fToGamma(rgbaDst
  535. , mip.m_width
  536. , mip.m_height
  537. , mip.m_depth
  538. , mip.m_width*16
  539. , rgba32f
  540. );
  541. bimg::imageEncodeFromRgba32f(_allocator
  542. , dstData
  543. , rgbaDst
  544. , dstMip.m_width
  545. , dstMip.m_height
  546. , dstMip.m_depth
  547. , outputFormat
  548. , _options.quality
  549. , _err
  550. );
  551. }
  552. }
  553. BX_FREE(_allocator, rgbaDst);
  554. }
  555. // SDF
  556. else if (_options.sdf)
  557. {
  558. uint32_t size = bimg::imageGetSize(
  559. NULL
  560. , uint16_t(dstMip.m_width)
  561. , uint16_t(dstMip.m_height)
  562. , uint16_t(dstMip.m_depth)
  563. , false
  564. , false
  565. , 1
  566. , bimg::TextureFormat::R8
  567. );
  568. temp = BX_ALLOC(_allocator, size);
  569. uint8_t* r8 = (uint8_t*)temp;
  570. bimg::imageDecodeToR8(_allocator
  571. , r8
  572. , mip.m_data
  573. , mip.m_width
  574. , mip.m_height
  575. , mip.m_depth
  576. , mip.m_width
  577. , mip.m_format
  578. );
  579. bimg::imageGetRawData(*output, side, 0, output->m_data, output->m_size, dstMip);
  580. dstData = const_cast<uint8_t*>(dstMip.m_data);
  581. bimg::imageMakeDist(_allocator
  582. , dstData
  583. , mip.m_width
  584. , mip.m_height
  585. , mip.m_width
  586. , r8
  587. );
  588. if (_options.mips) {
  589. const float alphaRef = 0.5f;
  590. float coverage = bimg::imageAlphaTestCoverage(bimg::TextureFormat::A8
  591. , mip.m_width
  592. , mip.m_height
  593. , mip.m_width
  594. , r8
  595. , alphaRef
  596. );
  597. size = bimg::imageGetSize(
  598. NULL
  599. , uint16_t(dstMip.m_width)
  600. , uint16_t(dstMip.m_height)
  601. , uint16_t(dstMip.m_depth)
  602. , false
  603. , false
  604. , 1
  605. , bimg::TextureFormat::RGBA8
  606. );
  607. void* rgbaTemp = BX_ALLOC(_allocator, size);
  608. uint8_t* rgba = (uint8_t*)rgbaTemp;
  609. bimg::imageDecodeToRgba8(
  610. _allocator
  611. , rgba
  612. , dstMip.m_data
  613. , dstMip.m_width
  614. , dstMip.m_height
  615. , dstMip.m_width * 4
  616. , bimg::TextureFormat::A8
  617. );
  618. for (uint8_t lod = 1; lod < numMips && _err->isOk(); ++lod) {
  619. bimg::imageRgba8Downsample2x2(rgba
  620. , dstMip.m_width
  621. , dstMip.m_height
  622. , dstMip.m_depth
  623. , dstMip.m_width * 4
  624. , bx::strideAlign(dstMip.m_width / 2, blockWidth) * 4
  625. , rgba
  626. );
  627. // For each mip, upscale to original size,
  628. // scale image alpha to get same coverage as mip0
  629. uint32_t upsample = 1 << lod;
  630. uint32_t destWidth = dstMip.m_width / 2;
  631. uint32_t destHeight = dstMip.m_height / 2;
  632. bimg::imageScaleAlphaToCoverage(bimg::TextureFormat::RGBA8
  633. , destWidth
  634. , destHeight
  635. , destWidth * 4
  636. , rgba
  637. , coverage
  638. , alphaRef
  639. , upsample
  640. );
  641. bimg::imageGetRawData(*output, side, lod, output->m_data, output->m_size, dstMip);
  642. dstData = const_cast<uint8_t*>(dstMip.m_data);
  643. bimg::imageEncodeFromRgba8(
  644. _allocator
  645. , dstData
  646. , rgba
  647. , dstMip.m_width
  648. , dstMip.m_height
  649. , dstMip.m_depth
  650. , bimg::TextureFormat::A8
  651. , _options.quality
  652. , _err
  653. );
  654. }
  655. BX_FREE(_allocator, rgbaTemp);
  656. }
  657. }
  658. // RGBA8
  659. else
  660. {
  661. uint32_t size = bimg::imageGetSize(
  662. NULL
  663. , uint16_t(dstMip.m_width)
  664. , uint16_t(dstMip.m_height)
  665. , uint16_t(dstMip.m_depth)
  666. , false
  667. , false
  668. , 1
  669. , bimg::TextureFormat::RGBA8
  670. );
  671. temp = BX_ALLOC(_allocator, size);
  672. uint8_t* rgba = (uint8_t*)temp;
  673. bimg::imageDecodeToRgba8(
  674. _allocator
  675. , rgba
  676. , mip.m_data
  677. , mip.m_width
  678. , mip.m_height
  679. , mip.m_width*4
  680. , mip.m_format
  681. );
  682. float coverage = 0.0f;
  683. if (_options.alphaTest)
  684. {
  685. coverage = bimg::imageAlphaTestCoverage(bimg::TextureFormat::RGBA8
  686. , mip.m_width
  687. , mip.m_height
  688. , mip.m_width*4
  689. , rgba
  690. , _options.edge
  691. );
  692. }
  693. void* ref = NULL;
  694. if (_options.iqa)
  695. {
  696. ref = BX_ALLOC(_allocator, size);
  697. bx::memCopy(ref, rgba, size);
  698. }
  699. if (_options.pma)
  700. {
  701. imagePremultiplyAlpha(
  702. rgba
  703. , dstMip.m_width
  704. , dstMip.m_height
  705. , dstMip.m_depth
  706. , bimg::TextureFormat::RGBA8
  707. );
  708. }
  709. bimg::imageGetRawData(*output, side, 0, output->m_data, output->m_size, dstMip);
  710. dstData = const_cast<uint8_t*>(dstMip.m_data);
  711. bimg::imageEncodeFromRgba8(
  712. _allocator
  713. , dstData
  714. , rgba
  715. , dstMip.m_width
  716. , dstMip.m_height
  717. , dstMip.m_depth
  718. , outputFormat
  719. , _options.quality
  720. , _err
  721. );
  722. for (uint8_t lod = 1; lod < numMips && _err->isOk(); ++lod)
  723. {
  724. bimg::imageRgba8Downsample2x2(rgba
  725. , dstMip.m_width
  726. , dstMip.m_height
  727. , dstMip.m_depth
  728. , dstMip.m_width*4
  729. , bx::strideAlign(dstMip.m_width/2, blockWidth)*4
  730. , rgba
  731. );
  732. if (_options.alphaTest)
  733. {
  734. bimg::imageScaleAlphaToCoverage(bimg::TextureFormat::RGBA8
  735. , dstMip.m_width
  736. , dstMip.m_height
  737. , dstMip.m_width*4
  738. , rgba
  739. , coverage
  740. , _options.edge
  741. );
  742. }
  743. if (_options.pma)
  744. {
  745. imagePremultiplyAlpha(
  746. rgba
  747. , dstMip.m_width
  748. , dstMip.m_height
  749. , dstMip.m_depth
  750. , bimg::TextureFormat::RGBA8
  751. );
  752. }
  753. bimg::imageGetRawData(*output, side, lod, output->m_data, output->m_size, dstMip);
  754. dstData = const_cast<uint8_t*>(dstMip.m_data);
  755. bimg::imageEncodeFromRgba8(
  756. _allocator
  757. , dstData
  758. , rgba
  759. , dstMip.m_width
  760. , dstMip.m_height
  761. , dstMip.m_depth
  762. , outputFormat
  763. , _options.quality
  764. , _err
  765. );
  766. }
  767. if (NULL != ref)
  768. {
  769. bimg::imageDecodeToRgba8(
  770. _allocator
  771. , rgba
  772. , output->m_data
  773. , mip.m_width
  774. , mip.m_height
  775. , mip.m_width*mip.m_bpp/8
  776. , outputFormat
  777. );
  778. float result = bimg::imageQualityRgba8(
  779. ref
  780. , rgba
  781. , uint16_t(mip.m_width)
  782. , uint16_t(mip.m_height)
  783. );
  784. printf("%f\n", result);
  785. BX_FREE(_allocator, ref);
  786. }
  787. }
  788. BX_FREE(_allocator, temp);
  789. }
  790. }
  791. bimg::imageFree(input);
  792. }
  793. if (!_err->isOk()
  794. && NULL != output)
  795. {
  796. bimg::imageFree(output);
  797. output = NULL;
  798. }
  799. return output;
  800. }
  801. class AlignedAllocator : public bx::AllocatorI
  802. {
  803. public:
  804. AlignedAllocator(bx::AllocatorI* _allocator, size_t _minAlignment)
  805. : m_allocator(_allocator)
  806. , m_minAlignment(_minAlignment)
  807. {
  808. }
  809. virtual void* realloc(
  810. void* _ptr
  811. , size_t _size
  812. , size_t _align
  813. , const char* _file
  814. , uint32_t _line
  815. )
  816. {
  817. return m_allocator->realloc(_ptr, _size, bx::max(_align, m_minAlignment), _file, _line);
  818. }
  819. bx::AllocatorI* m_allocator;
  820. size_t m_minAlignment;
  821. };
  822. class MaxTextureC {
  823. public :
  824. void convert(MaxBxStream * reader, MaxBxStream * writer, Options * options) {
  825. bx::Error err;
  826. Options defaultOptions;
  827. if (options == NULL)
  828. options = &defaultOptions;
  829. uint32_t inputSize = (uint32_t) bx::getSize(reader);
  830. if (0 == inputSize) {
  831. return;
  832. }
  833. bx::DefaultAllocator defaultAllocator;
  834. AlignedAllocator allocator(&defaultAllocator, 16);
  835. uint8_t *inputData = (uint8_t *) BX_ALLOC(&allocator, inputSize);
  836. bx::read(reader, inputData, inputSize, &err);
  837. bx::close(reader);
  838. if (!err.isOk()) {
  839. return;
  840. }
  841. bimg::ImageContainer *output = ::convert(&allocator, inputData, inputSize, *options, &err);
  842. BX_FREE(&allocator, inputData);
  843. if (NULL != output) {
  844. if (options->outputType == KTX) {
  845. bimg::imageWriteKtx(writer, *output, output->m_data, output->m_size, &err);
  846. } else if (options->outputType == DDS) {
  847. bimg::imageWriteDds(writer, *output, output->m_data, output->m_size, &err);
  848. } else if (options->outputType == PNG) {
  849. if (output->m_format != bimg::TextureFormat::RGBA8) {
  850. return;
  851. }
  852. bimg::ImageMip mip;
  853. bimg::imageGetRawData(*output, 0, 0, output->m_data, output->m_size, mip);
  854. bimg::imageWritePng(writer, mip.m_width, mip.m_height, mip.m_width * 4, mip.m_data, output->m_format,
  855. false, &err);
  856. } else if (options->outputType == EXR) {
  857. bimg::ImageMip mip;
  858. bimg::imageGetRawData(*output, 0, 0, output->m_data, output->m_size, mip);
  859. bimg::imageWriteExr(writer, mip.m_width, mip.m_height, mip.m_width * 8, mip.m_data, output->m_format,
  860. false, &err);
  861. } else if (options->outputType == HDR) {
  862. bimg::ImageMip mip;
  863. bimg::imageGetRawData(*output, 0, 0, output->m_data, output->m_size, mip);
  864. bimg::imageWriteHdr(writer, mip.m_width, mip.m_height, mip.m_width*getBitsPerPixel(mip.m_format)/8,
  865. mip.m_data, output->m_format, false, &err);
  866. }
  867. bx::close(writer);
  868. if (!err.isOk()) {
  869. return;
  870. }
  871. bimg::imageFree(output);
  872. }
  873. }
  874. };
  875. // --------------------------------------------------------
  876. void bmx_bimg_texturec_convert(MaxBxStream * reader, MaxBxStream * writer, Options * options) {
  877. MaxTextureC textureC;
  878. textureC.convert(reader, writer, options);
  879. };
  880. // --------------------------------------------------------
  881. Options * bmx_bimg_options_new() {
  882. return new Options;
  883. }
  884. void bmx_bimg_options_free(Options * options) {
  885. delete options;
  886. }
  887. void bmx_bimg_options_setMaxSize(Options * options, int maxSize) {
  888. options->maxSize = static_cast<uint32_t>(maxSize);
  889. }
  890. void bmx_bimg_options_setEdge(Options * options, float edge) {
  891. options->edge = edge;
  892. }
  893. void bmx_bimg_options_setFormat(Options * options, int format) {
  894. options->format = static_cast<bimg::TextureFormat::Enum>(format);
  895. }
  896. void bmx_bimg_options_setQuality(Options * options, int quality) {
  897. options->quality = static_cast<bimg::Quality::Enum>(quality);
  898. }
  899. void bmx_bimg_options_setMips(Options * options, int mips) {
  900. options->mips = static_cast<bool>(mips);
  901. }
  902. void bmx_bimg_options_setNormalMap(Options * options, int normalMap) {
  903. options->normalMap = static_cast<bool>(normalMap);
  904. }
  905. void bmx_bimg_options_setEquirect(Options * options, int equirect) {
  906. options->equirect = static_cast<bool>(equirect);
  907. }
  908. void bmx_bimg_options_setIqa(Options * options, int iqa) {
  909. options->iqa = static_cast<bool>(iqa);
  910. }
  911. void bmx_bimg_options_setPma(Options * options, int pma) {
  912. options->pma = static_cast<bool>(pma);
  913. }
  914. void bmx_bimg_options_setSdf(Options * options, int sdf) {
  915. options->sdf = static_cast<bool>(sdf);
  916. }
  917. void bmx_bimg_options_setAlphaTest(Options * options, int alphaTest) {
  918. options->alphaTest = static_cast<bool>(alphaTest);
  919. }
  920. void bmx_bimg_options_setOutputType(Options * options, int outputType) {
  921. options->outputType = static_cast<OutputType>(outputType);
  922. }