💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1064 lines
25 KiB

  1. /*
  2. * Copyright (C) 2023 Christopher J. Howard
  3. *
  4. * This file is part of Antkeeper source code.
  5. *
  6. * Antkeeper source code is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Antkeeper source code is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include <engine/gl/image.hpp>
  20. #include <engine/gl/cube-map.hpp>
  21. #include <engine/gl/opengl/gl-format-lut.hpp>
  22. #include <engine/resources/resource-loader.hpp>
  23. #include <engine/resources/deserialize-error.hpp>
  24. #include <engine/resources/deserializer.hpp>
  25. #include <engine/debug/log.hpp>
  26. #include <cmath>
  27. #include <stdexcept>
  28. #include <glad/gl.h>
  29. #include <stb/stb_image.h>
  30. #include <tinyexr.h>
  31. namespace gl {
  32. image::image
  33. (
  34. std::uint8_t dimensionality,
  35. gl::format format,
  36. std::uint32_t width,
  37. std::uint32_t height,
  38. std::uint32_t depth,
  39. std::uint32_t mip_levels,
  40. std::uint32_t array_layers,
  41. std::uint32_t flags
  42. )
  43. {
  44. const auto format_index = std::to_underlying(format);
  45. const auto gl_internal_format = gl_format_lut[format_index][0];
  46. const auto gl_type = gl_format_lut[format_index][2];
  47. if (gl_internal_format == 0 || gl_type == 0)
  48. {
  49. throw std::invalid_argument("Image construction used unsupported format.");
  50. }
  51. if (!width || !height || !depth)
  52. {
  53. throw std::invalid_argument("Image dimensions must be nonzero.");
  54. }
  55. if (!mip_levels)
  56. {
  57. throw std::invalid_argument("Image mip levels must be nonzero.");
  58. }
  59. if (mip_levels > static_cast<std::uint32_t>(std::bit_width(std::max(std::max(width, height), depth))))
  60. {
  61. throw std::out_of_range("Image mip levels exceed `1 + log2(max(width, height, depth))`.");
  62. }
  63. if (!array_layers)
  64. {
  65. throw std::invalid_argument("Image array layers must be nonzero.");
  66. }
  67. if (dimensionality == 1)
  68. {
  69. if (height > 1 || depth > 1)
  70. {
  71. throw std::invalid_argument("1D image must have a height and depth of `1`.");
  72. }
  73. }
  74. else if (dimensionality == 2)
  75. {
  76. if (depth > 1)
  77. {
  78. throw std::invalid_argument("2D image must have a depth of `1`.");
  79. }
  80. }
  81. else if (dimensionality == 3)
  82. {
  83. if (array_layers > 1)
  84. {
  85. throw std::invalid_argument("3D image arrays not supported.");
  86. }
  87. }
  88. if (flags & std::to_underlying(image_flag::cube_compatible))
  89. {
  90. if (dimensionality != 2)
  91. {
  92. throw std::invalid_argument("Cube compatible image must be 2D.");
  93. }
  94. if (width != height)
  95. {
  96. throw std::invalid_argument("Cube compatible image width and height must be equal.");
  97. }
  98. if (array_layers % 6 != 0)
  99. {
  100. throw std::invalid_argument("Cube compatible image array layers must be a multiple of 6.");
  101. }
  102. }
  103. m_dimensionality = dimensionality;
  104. m_format = format;
  105. m_dimensions = {width, height, depth};
  106. m_mip_levels = mip_levels;
  107. m_array_layers = array_layers;
  108. m_flags = flags;
  109. if (m_array_layers == 1)
  110. {
  111. switch (m_dimensionality)
  112. {
  113. case 1:
  114. m_gl_texture_target = GL_TEXTURE_1D;
  115. glCreateTextures(m_gl_texture_target, 1, &m_gl_texture_name);
  116. glTextureStorage1D
  117. (
  118. m_gl_texture_name,
  119. static_cast<GLsizei>(m_mip_levels),
  120. gl_internal_format,
  121. static_cast<GLsizei>(m_dimensions[0])
  122. );
  123. break;
  124. case 2:
  125. m_gl_texture_target = GL_TEXTURE_2D;
  126. glCreateTextures(m_gl_texture_target, 1, &m_gl_texture_name);
  127. glTextureStorage2D
  128. (
  129. m_gl_texture_name,
  130. static_cast<GLsizei>(m_mip_levels),
  131. gl_internal_format,
  132. static_cast<GLsizei>(m_dimensions[0]),
  133. static_cast<GLsizei>(m_dimensions[1])
  134. );
  135. break;
  136. case 3:
  137. m_gl_texture_target = GL_TEXTURE_3D;
  138. glCreateTextures(m_gl_texture_target, 1, &m_gl_texture_name);
  139. glTextureStorage3D
  140. (
  141. m_gl_texture_name,
  142. static_cast<GLsizei>(m_mip_levels),
  143. gl_internal_format,
  144. static_cast<GLsizei>(m_dimensions[0]),
  145. static_cast<GLsizei>(m_dimensions[1]),
  146. static_cast<GLsizei>(m_dimensions[2])
  147. );
  148. break;
  149. default:
  150. break;
  151. }
  152. }
  153. else
  154. {
  155. switch (m_dimensionality)
  156. {
  157. case 1:
  158. m_gl_texture_target = GL_TEXTURE_1D_ARRAY;
  159. glCreateTextures(m_gl_texture_target, 1, &m_gl_texture_name);
  160. glTextureStorage2D
  161. (
  162. m_gl_texture_name,
  163. static_cast<GLsizei>(m_mip_levels),
  164. gl_internal_format,
  165. static_cast<GLsizei>(m_dimensions[0]),
  166. static_cast<GLsizei>(m_array_layers)
  167. );
  168. break;
  169. case 2:
  170. if (is_cube_compatible())
  171. {
  172. if (m_array_layers == 6)
  173. {
  174. m_gl_texture_target = GL_TEXTURE_CUBE_MAP;
  175. glCreateTextures(m_gl_texture_target, 1, &m_gl_texture_name);
  176. glTextureStorage2D
  177. (
  178. m_gl_texture_name,
  179. static_cast<GLsizei>(m_mip_levels),
  180. gl_internal_format,
  181. static_cast<GLsizei>(m_dimensions[0]),
  182. static_cast<GLsizei>(m_dimensions[1])
  183. );
  184. }
  185. else
  186. {
  187. m_gl_texture_target = GL_TEXTURE_CUBE_MAP_ARRAY;
  188. glCreateTextures(m_gl_texture_target, 1, &m_gl_texture_name);
  189. glTextureStorage3D
  190. (
  191. m_gl_texture_name,
  192. static_cast<GLsizei>(m_mip_levels),
  193. gl_internal_format,
  194. static_cast<GLsizei>(m_dimensions[0]),
  195. static_cast<GLsizei>(m_dimensions[1]),
  196. static_cast<GLsizei>(m_array_layers)
  197. );
  198. }
  199. }
  200. else
  201. {
  202. m_gl_texture_target = GL_TEXTURE_2D_ARRAY;
  203. glCreateTextures(m_gl_texture_target, 1, &m_gl_texture_name);
  204. glTextureStorage3D
  205. (
  206. m_gl_texture_name,
  207. static_cast<GLsizei>(m_mip_levels),
  208. gl_internal_format,
  209. static_cast<GLsizei>(m_dimensions[0]),
  210. static_cast<GLsizei>(m_dimensions[1]),
  211. static_cast<GLsizei>(m_array_layers)
  212. );
  213. }
  214. break;
  215. default:
  216. break;
  217. }
  218. }
  219. }
  220. image::~image()
  221. {
  222. glDeleteTextures(1, &m_gl_texture_name);
  223. }
  224. void image::read
  225. (
  226. std::uint32_t mip_level,
  227. std::uint32_t offset_x,
  228. std::uint32_t offset_y,
  229. std::uint32_t offset_z,
  230. std::uint32_t width,
  231. std::uint32_t height,
  232. std::uint32_t depth,
  233. gl::format format,
  234. std::span<std::byte> data
  235. ) const
  236. {
  237. if (mip_level >= m_mip_levels)
  238. {
  239. throw std::out_of_range("Image read operation mip level out of range.");
  240. }
  241. const auto format_index = std::to_underlying(format);
  242. const auto gl_base_format = gl_format_lut[format_index][1];
  243. const auto gl_type = gl_format_lut[format_index][2];
  244. if (gl_base_format == 0 || gl_type == 0)
  245. {
  246. throw std::invalid_argument("Image read operation used unsupported format.");
  247. }
  248. glGetTextureSubImage
  249. (
  250. m_gl_texture_name,
  251. static_cast<GLint>(mip_level),
  252. static_cast<GLint>(offset_x),
  253. static_cast<GLint>(offset_y),
  254. static_cast<GLint>(offset_z),
  255. static_cast<GLsizei>(width),
  256. static_cast<GLsizei>(height),
  257. static_cast<GLsizei>(depth),
  258. gl_base_format,
  259. gl_type,
  260. static_cast<GLsizei>(data.size()),
  261. data.data()
  262. );
  263. }
  264. void image::write
  265. (
  266. std::uint32_t mip_level,
  267. std::uint32_t offset_x,
  268. std::uint32_t offset_y,
  269. std::uint32_t offset_z,
  270. std::uint32_t width,
  271. std::uint32_t height,
  272. std::uint32_t depth,
  273. gl::format format,
  274. std::span<const std::byte> data
  275. )
  276. {
  277. if (mip_level >= m_mip_levels)
  278. {
  279. throw std::out_of_range("Image write operation mip level out of range.");
  280. }
  281. const auto format_index = std::to_underlying(format);
  282. const auto gl_base_format = gl_format_lut[format_index][1];
  283. const auto gl_type = gl_format_lut[format_index][2];
  284. if (gl_base_format == 0 || gl_type == 0)
  285. {
  286. throw std::invalid_argument("Image write operation used unsupported format.");
  287. }
  288. if (m_array_layers == 1)
  289. {
  290. if ((offset_x + width > std::max<std::uint32_t>(1, m_dimensions[0] >> mip_level)) ||
  291. (offset_y + height > std::max<std::uint32_t>(1, m_dimensions[1] >> mip_level)) ||
  292. (offset_z + depth > std::max<std::uint32_t>(1, m_dimensions[2] >> mip_level)))
  293. {
  294. throw std::out_of_range("Image write operation exceeded image bounds.");
  295. }
  296. switch (m_dimensionality)
  297. {
  298. case 1:
  299. glTextureSubImage1D
  300. (
  301. m_gl_texture_name,
  302. static_cast<GLint>(mip_level),
  303. static_cast<GLint>(offset_x),
  304. static_cast<GLsizei>(width),
  305. gl_base_format,
  306. gl_type,
  307. data.data()
  308. );
  309. break;
  310. case 2:
  311. glTextureSubImage2D
  312. (
  313. m_gl_texture_name,
  314. static_cast<GLint>(mip_level),
  315. static_cast<GLint>(offset_x),
  316. static_cast<GLint>(offset_y),
  317. static_cast<GLsizei>(width),
  318. static_cast<GLsizei>(height),
  319. gl_base_format,
  320. gl_type,
  321. data.data()
  322. );
  323. break;
  324. case 3:
  325. glTextureSubImage3D
  326. (
  327. m_gl_texture_name,
  328. static_cast<GLint>(mip_level),
  329. static_cast<GLint>(offset_x),
  330. static_cast<GLint>(offset_y),
  331. static_cast<GLint>(offset_z),
  332. static_cast<GLsizei>(width),
  333. static_cast<GLsizei>(height),
  334. static_cast<GLsizei>(depth),
  335. gl_base_format,
  336. gl_type,
  337. data.data()
  338. );
  339. break;
  340. default:
  341. break;
  342. }
  343. }
  344. else
  345. {
  346. switch (m_dimensionality)
  347. {
  348. case 1:
  349. if ((offset_x + width > std::max<std::uint32_t>(1, m_dimensions[0] >> mip_level)) ||
  350. (offset_y + height > m_array_layers) ||
  351. (offset_z + depth > 1))
  352. {
  353. throw std::out_of_range("Image write operation exceeded image dimensions.");
  354. }
  355. glTextureSubImage2D
  356. (
  357. m_gl_texture_name,
  358. static_cast<GLint>(mip_level),
  359. static_cast<GLint>(offset_x),
  360. static_cast<GLint>(offset_y),
  361. static_cast<GLsizei>(width),
  362. static_cast<GLsizei>(height),
  363. gl_base_format,
  364. gl_type,
  365. data.data()
  366. );
  367. break;
  368. case 2:
  369. if ((offset_x + width > std::max<std::uint32_t>(1, m_dimensions[0] >> mip_level)) ||
  370. (offset_y + height > std::max<std::uint32_t>(1, m_dimensions[1] >> mip_level)) ||
  371. (offset_z + depth > m_array_layers))
  372. {
  373. throw std::out_of_range("Image write operation exceeded image bounds.");
  374. }
  375. glTextureSubImage3D
  376. (
  377. m_gl_texture_name,
  378. static_cast<GLint>(mip_level),
  379. static_cast<GLint>(offset_x),
  380. static_cast<GLint>(offset_y),
  381. static_cast<GLint>(offset_z),
  382. static_cast<GLsizei>(width),
  383. static_cast<GLsizei>(height),
  384. static_cast<GLsizei>(depth),
  385. gl_base_format,
  386. gl_type,
  387. data.data()
  388. );
  389. break;
  390. default:
  391. break;
  392. }
  393. }
  394. }
  395. void image::copy
  396. (
  397. std::uint32_t src_mip_level,
  398. std::uint32_t src_x,
  399. std::uint32_t src_y,
  400. std::uint32_t src_z,
  401. image& dst_image,
  402. std::uint32_t dst_mip_level,
  403. std::uint32_t dst_x,
  404. std::uint32_t dst_y,
  405. std::uint32_t dst_z,
  406. std::uint32_t width,
  407. std::uint32_t height,
  408. std::uint32_t depth
  409. ) const
  410. {
  411. glCopyImageSubData
  412. (
  413. m_gl_texture_name,
  414. m_gl_texture_target,
  415. static_cast<GLint>(src_mip_level),
  416. static_cast<GLint>(src_x),
  417. static_cast<GLint>(src_y),
  418. static_cast<GLint>(src_z),
  419. dst_image.m_gl_texture_name,
  420. dst_image.m_gl_texture_target,
  421. static_cast<GLint>(dst_mip_level),
  422. static_cast<GLint>(dst_x),
  423. static_cast<GLint>(dst_y),
  424. static_cast<GLint>(dst_z),
  425. static_cast<GLsizei>(width),
  426. static_cast<GLsizei>(height),
  427. static_cast<GLsizei>(depth)
  428. );
  429. }
  430. void image::generate_mipmaps()
  431. {
  432. if (m_mip_levels > 1)
  433. {
  434. glGenerateTextureMipmap(m_gl_texture_name);
  435. }
  436. }
  437. image_1d::image_1d
  438. (
  439. gl::format format,
  440. std::uint32_t width,
  441. std::uint32_t mip_levels,
  442. std::uint32_t array_layers,
  443. std::uint32_t flags
  444. ):
  445. image
  446. (
  447. 1,
  448. format,
  449. width,
  450. 1,
  451. 1,
  452. mip_levels,
  453. array_layers,
  454. flags
  455. )
  456. {}
  457. image_2d::image_2d
  458. (
  459. gl::format format,
  460. std::uint32_t width,
  461. std::uint32_t height,
  462. std::uint32_t mip_levels,
  463. std::uint32_t array_layers,
  464. std::uint32_t flags
  465. ):
  466. image
  467. (
  468. 2,
  469. format,
  470. width,
  471. height,
  472. 1,
  473. mip_levels,
  474. array_layers,
  475. flags
  476. )
  477. {}
  478. image_3d::image_3d
  479. (
  480. gl::format format,
  481. std::uint32_t width,
  482. std::uint32_t height,
  483. std::uint32_t depth,
  484. std::uint32_t mip_levels,
  485. std::uint32_t flags
  486. ):
  487. image
  488. (
  489. 3,
  490. format,
  491. width,
  492. height,
  493. depth,
  494. mip_levels,
  495. 1,
  496. flags
  497. )
  498. {}
  499. image_cube::image_cube
  500. (
  501. gl::format format,
  502. std::uint32_t width,
  503. std::uint32_t mip_levels,
  504. std::uint32_t array_layers
  505. ):
  506. image_2d
  507. (
  508. format,
  509. width,
  510. width,
  511. mip_levels,
  512. array_layers,
  513. std::to_underlying(image_flag::cube_compatible)
  514. )
  515. {}
  516. } // namespace gl
  517. namespace {
  518. int stb_io_read(void* user, char* data, int size)
  519. {
  520. deserialize_context& ctx = *static_cast<deserialize_context*>(user);
  521. return static_cast<int>(ctx.read8(reinterpret_cast<std::byte*>(data), static_cast<std::size_t>(size)));
  522. }
  523. void stb_io_skip(void* user, int n)
  524. {
  525. deserialize_context& ctx = *static_cast<deserialize_context*>(user);
  526. ctx.seek(ctx.tell() + n);
  527. }
  528. int stb_io_eof(void* user)
  529. {
  530. deserialize_context& ctx = *static_cast<deserialize_context*>(user);
  531. return static_cast<int>(ctx.eof());
  532. }
  533. struct stb_image_deleter
  534. {
  535. void operator()(void* p) const
  536. {
  537. stbi_image_free(p);
  538. }
  539. };
  540. [[nodiscard]] std::unique_ptr<gl::image> load_image_stb_image(deserialize_context& ctx, std::uint8_t dimensionality, std::uint32_t mip_levels)
  541. {
  542. // Setup IO callbacks
  543. const stbi_io_callbacks io_callbacks
  544. {
  545. &stb_io_read,
  546. &stb_io_skip,
  547. &stb_io_eof
  548. };
  549. // Determine image bit depth
  550. std::size_t component_size = stbi_is_16_bit_from_callbacks(&io_callbacks, &ctx) ? sizeof(std::uint16_t) : sizeof(std::uint8_t);
  551. ctx.seek(0);
  552. // Set vertical flip on load in order to correctly upload pixel data to OpenGL
  553. stbi_set_flip_vertically_on_load(true);
  554. // Load image data
  555. std::unique_ptr<void, stb_image_deleter> data;
  556. int width;
  557. int height;
  558. int components;
  559. gl::format format;
  560. if (component_size == sizeof(std::uint16_t))
  561. {
  562. // Load 16-bit image data
  563. data = std::unique_ptr<void, stb_image_deleter>(stbi_load_16_from_callbacks(&io_callbacks, &ctx, &width, &height, &components, 0));
  564. // Determine 16-bit image format
  565. format = [components]()
  566. {
  567. switch (components)
  568. {
  569. case 1:
  570. return gl::format::r16_unorm;
  571. case 2:
  572. return gl::format::r16g16_unorm;
  573. case 3:
  574. return gl::format::r16g16b16_unorm;
  575. case 4:
  576. return gl::format::r16g16b16a16_unorm;
  577. default:
  578. return gl::format::undefined;
  579. }
  580. }();
  581. }
  582. else
  583. {
  584. // Load 8-bit image data
  585. data = std::unique_ptr<void, stb_image_deleter>(stbi_load_from_callbacks(&io_callbacks, &ctx, &width, &height, &components, 0));
  586. // Determine 8-bit image format
  587. format = [components]()
  588. {
  589. switch (components)
  590. {
  591. case 1:
  592. return gl::format::r8_unorm;
  593. case 2:
  594. return gl::format::r8g8_unorm;
  595. case 3:
  596. return gl::format::r8g8b8_unorm;
  597. case 4:
  598. return gl::format::r8g8b8a8_unorm;
  599. default:
  600. return gl::format::undefined;
  601. }
  602. }();
  603. }
  604. // Check if image data was loaded
  605. if (!data)
  606. {
  607. throw deserialize_error(stbi_failure_reason());
  608. }
  609. // Determine number mip levels
  610. if (!mip_levels)
  611. {
  612. mip_levels = static_cast<std::uint32_t>(std::bit_width(static_cast<std::uint32_t>(std::max(width, height))));
  613. }
  614. // Allocate image
  615. std::unique_ptr<gl::image> image;
  616. switch (dimensionality)
  617. {
  618. case 1:
  619. image = std::make_unique<gl::image_1d>
  620. (
  621. format,
  622. static_cast<std::uint32_t>(std::max(width, height)),
  623. mip_levels
  624. );
  625. break;
  626. case 2:
  627. image = std::make_unique<gl::image_2d>
  628. (
  629. format,
  630. static_cast<std::uint32_t>(width),
  631. static_cast<std::uint32_t>(height),
  632. mip_levels
  633. );
  634. break;
  635. case 3:
  636. image = std::make_unique<gl::image_3d>
  637. (
  638. format,
  639. static_cast<std::uint32_t>(width),
  640. static_cast<std::uint32_t>(height),
  641. 1,
  642. mip_levels
  643. );
  644. break;
  645. default:
  646. break;
  647. }
  648. // Upload image data to image
  649. image->write
  650. (
  651. 0,
  652. 0,
  653. 0,
  654. 0,
  655. image->get_dimensions()[0],
  656. image->get_dimensions()[1],
  657. image->get_dimensions()[2],
  658. format,
  659. {
  660. reinterpret_cast<const std::byte*>(data.get()),
  661. image->get_dimensions()[0] *
  662. image->get_dimensions()[1] *
  663. image->get_dimensions()[2] *
  664. static_cast<std::size_t>(components) *
  665. component_size
  666. }
  667. );
  668. // Generate mipmaps
  669. image->generate_mipmaps();
  670. return image;
  671. }
  672. [[nodiscard]] std::unique_ptr<gl::image> load_image_tinyexr(deserialize_context& ctx, std::uint8_t dimensionality, std::uint32_t mip_levels)
  673. {
  674. const char* error = nullptr;
  675. auto tinyexr_error = [&error]()
  676. {
  677. const std::string error_message(error);
  678. FreeEXRErrorMessage(error);
  679. throw deserialize_error(error_message);
  680. };
  681. // Read data into file buffer
  682. std::vector<unsigned char> file_buffer(ctx.size());
  683. ctx.read8(reinterpret_cast<std::byte*>(file_buffer.data()), file_buffer.size());
  684. // Read EXR version
  685. EXRVersion exr_version;
  686. if (ParseEXRVersionFromMemory(&exr_version, file_buffer.data(), file_buffer.size()) != TINYEXR_SUCCESS)
  687. {
  688. tinyexr_error();
  689. }
  690. // Check if image is multipart
  691. if (exr_version.multipart)
  692. {
  693. throw deserialize_error("OpenEXR multipart images not supported.");
  694. }
  695. // Load image header
  696. EXRHeader exr_header;
  697. InitEXRHeader(&exr_header);
  698. if (ParseEXRHeaderFromMemory(&exr_header, &exr_version, file_buffer.data(), file_buffer.size(), &error) != TINYEXR_SUCCESS)
  699. {
  700. tinyexr_error();
  701. }
  702. // Check if image is tiled
  703. if (exr_header.tiled)
  704. {
  705. FreeEXRHeader(&exr_header);
  706. throw deserialize_error("OpenEXR tiled images not supported.");
  707. }
  708. // Check if image has a supported number of channels
  709. if (exr_header.num_channels < 1 || exr_header.num_channels > 4)
  710. {
  711. FreeEXRHeader(&exr_header);
  712. throw deserialize_error("OpenEXR images must have 1-4 channels.");
  713. }
  714. // Check if all channels have the same format
  715. for (int i = 1; i < exr_header.num_channels; ++i)
  716. {
  717. if (exr_header.pixel_types[i] != exr_header.pixel_types[i - 1])
  718. {
  719. FreeEXRHeader(&exr_header);
  720. throw deserialize_error("OpenEXR images must have the same pixel type per channel.");
  721. }
  722. }
  723. // Load image data
  724. EXRImage exr_image;
  725. InitEXRImage(&exr_image);
  726. if (LoadEXRImageFromMemory(&exr_image, &exr_header, file_buffer.data(), file_buffer.size(), &error) != TINYEXR_SUCCESS)
  727. {
  728. FreeEXRHeader(&exr_header);
  729. tinyexr_error();
  730. }
  731. // Free file buffer
  732. file_buffer.clear();
  733. // Determine image format
  734. constexpr gl::format uint_formats[4] =
  735. {
  736. gl::format::r32_uint,
  737. gl::format::r32g32_uint,
  738. gl::format::r32g32b32_uint,
  739. gl::format::r32g32b32a32_uint
  740. };
  741. constexpr gl::format half_formats[4] =
  742. {
  743. gl::format::r16_sfloat,
  744. gl::format::r16g16_sfloat,
  745. gl::format::r16g16b16_sfloat,
  746. gl::format::r16g16b16a16_sfloat
  747. };
  748. constexpr gl::format float_formats[4] =
  749. {
  750. gl::format::r32_sfloat,
  751. gl::format::r32g32_sfloat,
  752. gl::format::r32g32b32_sfloat,
  753. gl::format::r32g32b32a32_sfloat
  754. };
  755. gl::format format;
  756. int component_size;
  757. switch (exr_header.pixel_types[0])
  758. {
  759. case TINYEXR_PIXELTYPE_UINT:
  760. format = uint_formats[exr_header.num_channels - 1];
  761. component_size = static_cast<int>(sizeof(std::uint32_t));
  762. break;
  763. case TINYEXR_PIXELTYPE_HALF:
  764. format = half_formats[exr_header.num_channels - 1];
  765. component_size = static_cast<int>(sizeof(std::uint16_t));//sizeof(float16_t)
  766. break;
  767. case TINYEXR_PIXELTYPE_FLOAT:
  768. format = float_formats[exr_header.num_channels - 1];
  769. component_size = static_cast<int>(sizeof(float));//sizeof(float32_t)
  770. break;
  771. default:
  772. format = gl::format::undefined;
  773. component_size = 0;
  774. break;
  775. }
  776. // Allocate interleaved image data
  777. std::vector<std::byte> data(static_cast<std::size_t>(exr_image.width * exr_image.height * exr_header.num_channels * component_size));
  778. // Interleave image data from layers
  779. std::byte* component = data.data();
  780. for (auto y = exr_image.height - 1; y >= 0; --y)
  781. {
  782. const auto row_offset = y * exr_image.width;
  783. for (auto x = 0; x < exr_image.width; ++x)
  784. {
  785. const auto byte_offset = (row_offset + x) * component_size;
  786. for (auto c = exr_image.num_channels - 1; c >= 0; --c)
  787. {
  788. std::memcpy(component, exr_image.images[c] + byte_offset, static_cast<std::size_t>(component_size));
  789. component += component_size;
  790. }
  791. }
  792. }
  793. // Store image dimensions
  794. const auto width = static_cast<std::uint32_t>(exr_image.width);
  795. const auto height = static_cast<std::uint32_t>(exr_image.height);
  796. // Free loaded image data and image header
  797. FreeEXRImage(&exr_image);
  798. FreeEXRHeader(&exr_header);
  799. // Determine number mip levels
  800. if (!mip_levels)
  801. {
  802. mip_levels = static_cast<std::uint32_t>(std::bit_width(std::max(width, height)));
  803. }
  804. // Allocate image
  805. std::unique_ptr<gl::image> image;
  806. switch (dimensionality)
  807. {
  808. case 1:
  809. image = std::make_unique<gl::image_1d>
  810. (
  811. format,
  812. std::max(width, height),
  813. mip_levels
  814. );
  815. break;
  816. case 2:
  817. image = std::make_unique<gl::image_2d>
  818. (
  819. format,
  820. width,
  821. height,
  822. mip_levels
  823. );
  824. break;
  825. case 3:
  826. image = std::make_unique<gl::image_3d>
  827. (
  828. format,
  829. width,
  830. height,
  831. 1,
  832. mip_levels
  833. );
  834. break;
  835. default:
  836. break;
  837. }
  838. // Upload interleaved image data to image
  839. image->write
  840. (
  841. 0,
  842. 0,
  843. 0,
  844. 0,
  845. image->get_dimensions()[0],
  846. image->get_dimensions()[1],
  847. image->get_dimensions()[2],
  848. format,
  849. data
  850. );
  851. // Generate mipmaps
  852. image->generate_mipmaps();
  853. return image;
  854. }
  855. [[nodiscard]] std::unique_ptr<gl::image> load_image(deserialize_context& ctx, std::uint8_t dimensionality, std::uint32_t mip_levels)
  856. {
  857. // Select loader according to file extension
  858. if (ctx.path().extension() == ".exr")
  859. {
  860. // Load EXR images with TinyEXR
  861. return load_image_tinyexr(ctx, dimensionality, mip_levels);
  862. }
  863. else
  864. {
  865. // Load other image formats with stb_image
  866. return load_image_stb_image(ctx, dimensionality, mip_levels);
  867. }
  868. }
  869. }
  870. template <>
  871. std::unique_ptr<gl::image_1d> resource_loader<gl::image_1d>::load(::resource_manager& resource_manager, deserialize_context& ctx)
  872. {
  873. return std::unique_ptr<gl::image_1d>(static_cast<gl::image_1d*>(load_image(ctx, 1, 0).release()));
  874. }
  875. template <>
  876. std::unique_ptr<gl::image_2d> resource_loader<gl::image_2d>::load(::resource_manager& resource_manager, deserialize_context& ctx)
  877. {
  878. return std::unique_ptr<gl::image_2d>(static_cast<gl::image_2d*>(load_image(ctx, 2, 0).release()));
  879. }
  880. template <>
  881. std::unique_ptr<gl::image_3d> resource_loader<gl::image_3d>::load(::resource_manager& resource_manager, deserialize_context& ctx)
  882. {
  883. return std::unique_ptr<gl::image_3d>(static_cast<gl::image_3d*>(load_image(ctx, 3, 0).release()));
  884. }
  885. template <>
  886. std::unique_ptr<gl::image_cube> resource_loader<gl::image_cube>::load(::resource_manager& resource_manager, deserialize_context& ctx)
  887. {
  888. // Load cube map
  889. auto cube_map = std::unique_ptr<gl::image_2d>(static_cast<gl::image_2d*>(load_image(ctx, 2, 1).release()));
  890. // Determine cube map layout
  891. const auto layout = gl::infer_cube_map_layout(cube_map->get_dimensions()[0], cube_map->get_dimensions()[1]);
  892. if (layout == gl::cube_map_layout::unknown)
  893. {
  894. throw deserialize_error("Failed to load cube image from cube map with unknown layout.");
  895. }
  896. else if (layout == gl::cube_map_layout::equirectangular || layout == gl::cube_map_layout::spherical)
  897. {
  898. throw deserialize_error("Failed to load cube image from cube map with unsupported layout.");
  899. }
  900. // Determine cube map face width
  901. const auto face_width = gl::infer_cube_map_face_width(cube_map->get_dimensions()[0], cube_map->get_dimensions()[1], layout);
  902. // Allocate cube image
  903. auto image = std::make_unique<gl::image_cube>
  904. (
  905. cube_map->get_format(),
  906. face_width,
  907. static_cast<std::uint32_t>(std::bit_width(face_width))
  908. );
  909. // Vertical cross layout face offsets
  910. constexpr std::uint32_t vcross_offsets[6][2] =
  911. {
  912. {2, 2}, {0, 2}, // -x, +x
  913. {1, 3}, {1, 1}, // -y, +y
  914. {1, 0}, {1, 2} // -z, +z
  915. };
  916. // Horizontal cross layout face offsets
  917. constexpr std::uint32_t hcross_offsets[6][2] =
  918. {
  919. {2, 1}, {0, 1}, // -x, +x
  920. {1, 2}, {1, 0}, // -y, +y
  921. {3, 1}, {1, 1} // -z, +z
  922. };
  923. // Copy cube map faces to cube image
  924. switch (layout)
  925. {
  926. case gl::cube_map_layout::column:
  927. for (std::uint32_t i = 0; i < 6; ++i)
  928. {
  929. cube_map->copy(0, 0, face_width * i, 0, *image, 0, 0, 0, i, face_width, face_width, 1);
  930. }
  931. break;
  932. case gl::cube_map_layout::row:
  933. for (std::uint32_t i = 0; i < 6; ++i)
  934. {
  935. cube_map->copy(0, face_width * i, 0, 0, *image, 0, 0, 0, i, face_width, face_width, 1);
  936. }
  937. break;
  938. case gl::cube_map_layout::vertical_cross:
  939. for (std::uint32_t i = 0; i < 6; ++i)
  940. {
  941. cube_map->copy(0, face_width * vcross_offsets[i][0], face_width * vcross_offsets[i][1], 0, *image, 0, 0, 0, i, face_width, face_width, 1);
  942. }
  943. break;
  944. case gl::cube_map_layout::horizontal_cross:
  945. for (std::uint32_t i = 0; i < 6; ++i)
  946. {
  947. cube_map->copy(0, face_width * hcross_offsets[i][0], face_width * hcross_offsets[i][1], 0, *image, 0, 0, 0, i, face_width, face_width, 1);
  948. }
  949. break;
  950. default:
  951. break;
  952. }
  953. // Generate mipmaps
  954. image->generate_mipmaps();
  955. return image;
  956. }