💿🐜 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.

256 lines
9.1 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/texture.hpp>
  20. #include <engine/resources/deserialize-context.hpp>
  21. #include <engine/resources/deserialize-error.hpp>
  22. #include <engine/resources/resource-loader.hpp>
  23. #include <engine/resources/resource-manager.hpp>
  24. namespace {
  25. enum texture_type: std::uint8_t
  26. {
  27. texture_type_1d,
  28. texture_type_1d_array,
  29. texture_type_2d,
  30. texture_type_2d_array,
  31. texture_type_3d,
  32. texture_type_cube,
  33. texture_type_cube_array
  34. };
  35. [[nodiscard]] std::unique_ptr<gl::texture> load_texture(::resource_manager& resource_manager, deserialize_context& ctx, std::uint8_t texture_type)
  36. {
  37. // Read file format identifier
  38. std::uint32_t format_identifier{0};
  39. ctx.read32_le(reinterpret_cast<std::byte*>(&format_identifier), 1);
  40. // Validate file format identifier (U+1F5BC = framed picture)
  41. if (format_identifier != 0xbc969ff0)
  42. {
  43. throw deserialize_error("Invalid texture file.");
  44. }
  45. // Read file format version
  46. std::uint32_t format_version{0};
  47. ctx.read32_le(reinterpret_cast<std::byte*>(&format_version), 1);
  48. // Validate file format version
  49. if (format_version != 1)
  50. {
  51. throw deserialize_error("Unsupported texture file version.");
  52. }
  53. // Read image path
  54. std::uint32_t image_path_length{0};
  55. ctx.read32_le(reinterpret_cast<std::byte*>(&image_path_length), 1);
  56. std::string image_path(image_path_length, '\0');
  57. ctx.read8(reinterpret_cast<std::byte*>(image_path.data()), image_path_length);
  58. // Load image
  59. std::shared_ptr<gl::image> image;
  60. switch (texture_type)
  61. {
  62. case texture_type_1d:
  63. case texture_type_1d_array:
  64. image = resource_manager.load<gl::image_1d>(image_path);
  65. break;
  66. case texture_type_2d:
  67. case texture_type_2d_array:
  68. image = resource_manager.load<gl::image_2d>(image_path);
  69. break;
  70. case texture_type_3d:
  71. image = resource_manager.load<gl::image_3d>(image_path);
  72. break;
  73. case texture_type_cube:
  74. case texture_type_cube_array:
  75. image = resource_manager.load<gl::image_cube>(image_path);
  76. break;
  77. default:
  78. throw deserialize_error("Invalid texture type.");
  79. }
  80. // Read image view parameters
  81. gl::format format;
  82. std::uint32_t first_mip_level;
  83. std::uint32_t mip_level_count;
  84. std::uint32_t first_array_layer;
  85. std::uint32_t array_layer_count;
  86. ctx.read32_le(reinterpret_cast<std::byte*>(&format), 1);
  87. ctx.read32_le(reinterpret_cast<std::byte*>(&first_mip_level), 1);
  88. ctx.read32_le(reinterpret_cast<std::byte*>(&mip_level_count), 1);
  89. ctx.read32_le(reinterpret_cast<std::byte*>(&first_array_layer), 1);
  90. ctx.read32_le(reinterpret_cast<std::byte*>(&array_layer_count), 1);
  91. // Handle automatic mip level count (`0`)
  92. if (!mip_level_count)
  93. {
  94. mip_level_count = image->get_mip_levels();
  95. }
  96. // Handle automatic array layer count (`0`)
  97. if (!array_layer_count)
  98. {
  99. array_layer_count = image->get_array_layers();
  100. }
  101. // Read sampler parameters
  102. gl::sampler_filter mag_filter;
  103. gl::sampler_filter min_filter;
  104. gl::sampler_mipmap_mode mipmap_mode;
  105. gl::sampler_address_mode address_mode_u;
  106. gl::sampler_address_mode address_mode_v;
  107. gl::sampler_address_mode address_mode_w;
  108. float mip_lod_bias;
  109. float max_anisotropy;
  110. std::uint8_t compare_enabled;
  111. gl::compare_op compare_op;
  112. float min_lod;
  113. float max_lod;
  114. std::array<float, 4> border_color;
  115. ctx.read8(reinterpret_cast<std::byte*>(&mag_filter), 1);
  116. ctx.read8(reinterpret_cast<std::byte*>(&min_filter), 1);
  117. ctx.read8(reinterpret_cast<std::byte*>(&mipmap_mode), 1);
  118. ctx.read8(reinterpret_cast<std::byte*>(&address_mode_u), 1);
  119. ctx.read8(reinterpret_cast<std::byte*>(&address_mode_v), 1);
  120. ctx.read8(reinterpret_cast<std::byte*>(&address_mode_w), 1);
  121. ctx.read32_le(reinterpret_cast<std::byte*>(&mip_lod_bias), 1);
  122. ctx.read32_le(reinterpret_cast<std::byte*>(&max_anisotropy), 1);
  123. ctx.read8(reinterpret_cast<std::byte*>(&compare_enabled), 1);
  124. ctx.read8(reinterpret_cast<std::byte*>(&compare_op), 1);
  125. ctx.read32_le(reinterpret_cast<std::byte*>(&min_lod), 1);
  126. ctx.read32_le(reinterpret_cast<std::byte*>(&max_lod), 1);
  127. ctx.read32_le(reinterpret_cast<std::byte*>(border_color.data()), 4);
  128. // Construct sampler
  129. std::shared_ptr<gl::sampler> sampler = std::make_shared<gl::sampler>
  130. (
  131. mag_filter,
  132. min_filter,
  133. mipmap_mode,
  134. address_mode_u,
  135. address_mode_v,
  136. address_mode_w,
  137. mip_lod_bias,
  138. max_anisotropy,
  139. compare_enabled,
  140. compare_op,
  141. min_lod,
  142. max_lod,
  143. border_color
  144. );
  145. // Construct image view and texture
  146. switch (texture_type)
  147. {
  148. case texture_type_1d:
  149. {
  150. auto image_view = std::make_shared<gl::image_view_1d>(image, format, first_mip_level, mip_level_count, first_array_layer);
  151. return std::make_unique<gl::texture_1d>(std::move(image_view), std::move(sampler));
  152. }
  153. case texture_type_1d_array:
  154. {
  155. auto image_view = std::make_shared<gl::image_view_1d_array>(image, format, first_mip_level, mip_level_count, first_array_layer, array_layer_count);
  156. return std::make_unique<gl::texture_1d_array>(std::move(image_view), std::move(sampler));
  157. }
  158. case texture_type_2d:
  159. {
  160. auto image_view = std::make_shared<gl::image_view_2d>(image, format, first_mip_level, mip_level_count, first_array_layer);
  161. return std::make_unique<gl::texture_2d>(std::move(image_view), std::move(sampler));
  162. }
  163. case texture_type_2d_array:
  164. {
  165. auto image_view = std::make_shared<gl::image_view_2d_array>(image, format, first_mip_level, mip_level_count, first_array_layer, array_layer_count);
  166. return std::make_unique<gl::texture_2d_array>(std::move(image_view), std::move(sampler));
  167. }
  168. case texture_type_3d:
  169. {
  170. auto image_view = std::make_shared<gl::image_view_3d>(image, format, first_mip_level, mip_level_count);
  171. return std::make_unique<gl::texture_3d>(std::move(image_view), std::move(sampler));
  172. }
  173. case texture_type_cube:
  174. {
  175. auto image_view = std::make_shared<gl::image_view_cube>(image, format, first_mip_level, mip_level_count, first_array_layer);
  176. return std::make_unique<gl::texture_cube>(std::move(image_view), std::move(sampler));
  177. }
  178. case texture_type_cube_array:
  179. {
  180. auto image_view = std::make_shared<gl::image_view_cube_array>(image, format, first_mip_level, mip_level_count, first_array_layer, array_layer_count);
  181. return std::make_unique<gl::texture_cube_array>(std::move(image_view), std::move(sampler));
  182. }
  183. default:
  184. return nullptr;
  185. }
  186. }
  187. }
  188. template <>
  189. std::unique_ptr<gl::texture_1d> resource_loader<gl::texture_1d>::load(::resource_manager& resource_manager, deserialize_context& ctx)
  190. {
  191. return std::unique_ptr<gl::texture_1d>(static_cast<gl::texture_1d*>(load_texture(resource_manager, ctx, texture_type_1d).release()));
  192. }
  193. template <>
  194. std::unique_ptr<gl::texture_1d_array> resource_loader<gl::texture_1d_array>::load(::resource_manager& resource_manager, deserialize_context& ctx)
  195. {
  196. return std::unique_ptr<gl::texture_1d_array>(static_cast<gl::texture_1d_array*>(load_texture(resource_manager, ctx, texture_type_1d_array).release()));
  197. }
  198. template <>
  199. std::unique_ptr<gl::texture_2d> resource_loader<gl::texture_2d>::load(::resource_manager& resource_manager, deserialize_context& ctx)
  200. {
  201. return std::unique_ptr<gl::texture_2d>(static_cast<gl::texture_2d*>(load_texture(resource_manager, ctx, texture_type_2d).release()));
  202. }
  203. template <>
  204. std::unique_ptr<gl::texture_2d_array> resource_loader<gl::texture_2d_array>::load(::resource_manager& resource_manager, deserialize_context& ctx)
  205. {
  206. return std::unique_ptr<gl::texture_2d_array>(static_cast<gl::texture_2d_array*>(load_texture(resource_manager, ctx, texture_type_2d_array).release()));
  207. }
  208. template <>
  209. std::unique_ptr<gl::texture_3d> resource_loader<gl::texture_3d>::load(::resource_manager& resource_manager, deserialize_context& ctx)
  210. {
  211. return std::unique_ptr<gl::texture_3d>(static_cast<gl::texture_3d*>(load_texture(resource_manager, ctx, texture_type_3d).release()));
  212. }
  213. template <>
  214. std::unique_ptr<gl::texture_cube> resource_loader<gl::texture_cube>::load(::resource_manager& resource_manager, deserialize_context& ctx)
  215. {
  216. return std::unique_ptr<gl::texture_cube>(static_cast<gl::texture_cube*>(load_texture(resource_manager, ctx, texture_type_cube).release()));
  217. }
  218. template <>
  219. std::unique_ptr<gl::texture_cube_array> resource_loader<gl::texture_cube_array>::load(::resource_manager& resource_manager, deserialize_context& ctx)
  220. {
  221. return std::unique_ptr<gl::texture_cube_array>(static_cast<gl::texture_cube_array*>(load_texture(resource_manager, ctx, texture_type_cube_array).release()));
  222. }