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

259 lines
8.1 KiB

  1. /*
  2. * Copyright (C) 2021 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 "resources/resource-loader.hpp"
  20. #include "resources/resource-manager.hpp"
  21. #include "resources/image.hpp"
  22. #include "gl/pixel-type.hpp"
  23. #include "gl/pixel-format.hpp"
  24. #include "gl/color-space.hpp"
  25. #include "gl/texture-1d.hpp"
  26. #include "gl/texture-2d.hpp"
  27. #include "gl/texture-wrapping.hpp"
  28. #include "gl/texture-filter.hpp"
  29. #include <sstream>
  30. #include <stdexcept>
  31. #include <nlohmann/json.hpp>
  32. #include <physfs.h>
  33. template <>
  34. gl::texture_1d* resource_loader<gl::texture_1d>::load(resource_manager* resource_manager, PHYSFS_File* file, const std::filesystem::path& path)
  35. {
  36. // Read file into buffer
  37. std::size_t size = static_cast<int>(PHYSFS_fileLength(file));
  38. std::string buffer;
  39. buffer.resize(size);
  40. PHYSFS_readBytes(file, &buffer[0], size);
  41. // Parse json from file buffer
  42. nlohmann::json json = nlohmann::json::parse(buffer);
  43. // Read image filename
  44. std::string image_filename;
  45. if (auto element = json.find("image"); element != json.end())
  46. image_filename = element.value().get<std::string>();
  47. // Read color space
  48. gl::color_space color_space = gl::color_space::linear;
  49. if (auto element = json.find("color_space"); element != json.end())
  50. {
  51. std::string value = element.value().get<std::string>();
  52. if (value == "linear")
  53. color_space = gl::color_space::linear;
  54. else if (value == "srgb")
  55. color_space = gl::color_space::srgb;
  56. }
  57. // Read extension mode
  58. gl::texture_wrapping wrapping = gl::texture_wrapping::repeat;
  59. if (auto element = json.find("extension"); element != json.end())
  60. {
  61. std::string value = element.value().get<std::string>();
  62. if (value == "clip")
  63. wrapping = gl::texture_wrapping::clip;
  64. else if (value == "extend")
  65. wrapping = gl::texture_wrapping::extend;
  66. else if (value == "repeat")
  67. wrapping = gl::texture_wrapping::repeat;
  68. else if (value == "mirrored_repeat")
  69. wrapping = gl::texture_wrapping::mirrored_repeat;
  70. }
  71. // Read interpolation mode
  72. gl::texture_min_filter min_filter = gl::texture_min_filter::linear_mipmap_linear;
  73. gl::texture_mag_filter mag_filter = gl::texture_mag_filter::linear;
  74. if (auto element = json.find("interpolation"); element != json.end())
  75. {
  76. std::string value = element.value().get<std::string>();
  77. if (value == "linear")
  78. {
  79. min_filter = gl::texture_min_filter::linear_mipmap_linear;
  80. mag_filter = gl::texture_mag_filter::linear;
  81. }
  82. else if (value == "closest")
  83. {
  84. min_filter = gl::texture_min_filter::nearest_mipmap_nearest;
  85. mag_filter = gl::texture_mag_filter::nearest;
  86. }
  87. }
  88. // Read max anisotropy
  89. float max_anisotropy = 0.0f;
  90. if (auto element = json.find("max_anisotropy"); element != json.end())
  91. max_anisotropy = element.value().get<float>();
  92. // Load image
  93. ::image* image = resource_manager->load<::image>(image_filename);
  94. // Determine pixel type
  95. gl::pixel_type type = (image->get_component_size() == sizeof(float)) ? gl::pixel_type::float_32 : gl::pixel_type::uint_8;
  96. // Determine pixel format
  97. gl::pixel_format format;
  98. if (image->get_channel_count() == 1)
  99. {
  100. format = gl::pixel_format::r;
  101. }
  102. else if (image->get_channel_count() == 2)
  103. {
  104. format = gl::pixel_format::rg;
  105. }
  106. else if (image->get_channel_count() == 3)
  107. {
  108. format = gl::pixel_format::rgb;
  109. }
  110. else if (image->get_channel_count() == 4)
  111. {
  112. format = gl::pixel_format::rgba;
  113. }
  114. else
  115. {
  116. std::stringstream stream;
  117. stream << std::string("Texture cannot be created from an image with an unsupported number of channels (") << image->get_channel_count() << std::string(").");
  118. delete image;
  119. throw std::runtime_error(stream.str().c_str());
  120. }
  121. // Create texture
  122. gl::texture_1d* texture = new gl::texture_1d(image->get_width(), type, format, color_space, image->get_pixels());
  123. // Set wrapping and filtering
  124. texture->set_wrapping(wrapping);
  125. texture->set_filters(min_filter, mag_filter);
  126. texture->set_max_anisotropy(max_anisotropy);
  127. // Free loaded image
  128. resource_manager->unload(image_filename);
  129. return texture;
  130. }
  131. template <>
  132. gl::texture_2d* resource_loader<gl::texture_2d>::load(resource_manager* resource_manager, PHYSFS_File* file, const std::filesystem::path& path)
  133. {
  134. // Read file into buffer
  135. std::size_t size = static_cast<int>(PHYSFS_fileLength(file));
  136. std::string buffer;
  137. buffer.resize(size);
  138. PHYSFS_readBytes(file, &buffer[0], size);
  139. // Parse json from file buffer
  140. nlohmann::json json = nlohmann::json::parse(buffer);
  141. // Read image filename
  142. std::string image_filename;
  143. if (auto element = json.find("image"); element != json.end())
  144. image_filename = element.value().get<std::string>();
  145. // Read color space
  146. gl::color_space color_space = gl::color_space::linear;
  147. if (auto element = json.find("color_space"); element != json.end())
  148. {
  149. std::string value = element.value().get<std::string>();
  150. if (value == "linear")
  151. color_space = gl::color_space::linear;
  152. else if (value == "srgb")
  153. color_space = gl::color_space::srgb;
  154. }
  155. // Read extension mode
  156. gl::texture_wrapping wrapping = gl::texture_wrapping::repeat;
  157. if (auto element = json.find("extension"); element != json.end())
  158. {
  159. std::string value = element.value().get<std::string>();
  160. if (value == "clip")
  161. wrapping = gl::texture_wrapping::clip;
  162. else if (value == "extend")
  163. wrapping = gl::texture_wrapping::extend;
  164. else if (value == "repeat")
  165. wrapping = gl::texture_wrapping::repeat;
  166. else if (value == "mirrored_repeat")
  167. wrapping = gl::texture_wrapping::mirrored_repeat;
  168. }
  169. // Read interpolation mode
  170. gl::texture_min_filter min_filter = gl::texture_min_filter::linear_mipmap_linear;
  171. gl::texture_mag_filter mag_filter = gl::texture_mag_filter::linear;
  172. if (auto element = json.find("interpolation"); element != json.end())
  173. {
  174. std::string value = element.value().get<std::string>();
  175. if (value == "linear")
  176. {
  177. min_filter = gl::texture_min_filter::linear_mipmap_linear;
  178. mag_filter = gl::texture_mag_filter::linear;
  179. }
  180. else if (value == "closest")
  181. {
  182. min_filter = gl::texture_min_filter::nearest_mipmap_nearest;
  183. mag_filter = gl::texture_mag_filter::nearest;
  184. }
  185. }
  186. // Read max anisotropy
  187. float max_anisotropy = 0.0f;
  188. if (auto element = json.find("max_anisotropy"); element != json.end())
  189. max_anisotropy = element.value().get<float>();
  190. // Load image
  191. ::image* image = resource_manager->load<::image>(image_filename);
  192. // Determine pixel type
  193. gl::pixel_type type = (image->get_component_size() == sizeof(float)) ? gl::pixel_type::float_32 : gl::pixel_type::uint_8;
  194. // Determine pixel format
  195. gl::pixel_format format;
  196. if (image->get_channel_count() == 1)
  197. {
  198. format = gl::pixel_format::r;
  199. }
  200. else if (image->get_channel_count() == 2)
  201. {
  202. format = gl::pixel_format::rg;
  203. }
  204. else if (image->get_channel_count() == 3)
  205. {
  206. format = gl::pixel_format::rgb;
  207. }
  208. else if (image->get_channel_count() == 4)
  209. {
  210. format = gl::pixel_format::rgba;
  211. }
  212. else
  213. {
  214. std::stringstream stream;
  215. stream << std::string("Texture cannot be created from an image with an unsupported number of channels (") << image->get_channel_count() << std::string(").");
  216. delete image;
  217. throw std::runtime_error(stream.str().c_str());
  218. }
  219. // Create texture
  220. gl::texture_2d* texture = new gl::texture_2d(image->get_width(), image->get_height(), type, format, color_space, image->get_pixels());
  221. // Set wrapping and filtering
  222. texture->set_wrapping(wrapping, wrapping);
  223. texture->set_filters(min_filter, mag_filter);
  224. texture->set_max_anisotropy(max_anisotropy);
  225. // Free loaded image
  226. resource_manager->unload(image_filename);
  227. return texture;
  228. }