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

297 lines
10 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 "render/model.hpp"
  22. #include "render/vertex-attribute.hpp"
  23. #include "gl/vertex-attribute.hpp"
  24. #include "gl/drawing-mode.hpp"
  25. #include "utility/fundamental-types.hpp"
  26. #include "math/constants.hpp"
  27. #include <sstream>
  28. #include <stdexcept>
  29. #include <limits>
  30. #include <physfs.h>
  31. #include <nlohmann/json.hpp>
  32. static const float3 barycentric_coords[3] =
  33. {
  34. float3{1, 0, 0},
  35. float3{0, 1, 0},
  36. float3{0, 0, 1}
  37. };
  38. template <>
  39. render::model* resource_loader<render::model>::load(resource_manager* resource_manager, PHYSFS_File* file, const std::filesystem::path& path)
  40. {
  41. // Read file into buffer
  42. std::size_t size = static_cast<int>(PHYSFS_fileLength(file));
  43. std::vector<std::uint8_t> buffer(size);
  44. PHYSFS_readBytes(file, &buffer.front(), size);
  45. // Parse CBOR in file buffer
  46. nlohmann::json json = nlohmann::json::from_cbor(buffer);
  47. // Find model name
  48. std::string model_name;
  49. if (auto it = json.find("name"); it != json.end())
  50. model_name = it.value();
  51. // Load attributes
  52. std::unordered_map<std::string, std::tuple<std::size_t, std::vector<float>>> attributes;
  53. if (auto attributes_node = json.find("attributes"); attributes_node != json.end())
  54. {
  55. for (const auto& attribute_node: attributes_node.value().items())
  56. {
  57. // Look up attribute name
  58. std::string attribute_name;
  59. if (auto type_node = attribute_node.value().find("name"); type_node != attribute_node.value().end())
  60. attribute_name = type_node.value().get<std::string>();
  61. // Allocate attribute in attribute map
  62. auto& attribute = attributes[attribute_name];
  63. std::size_t& attribute_size = std::get<0>(attribute);
  64. std::vector<float>& attribute_data = std::get<1>(attribute);
  65. // Look up attribute size (per vertex)
  66. attribute_size = 0;
  67. if (auto size_node = attribute_node.value().find("size"); size_node != attribute_node.value().end())
  68. attribute_size = size_node.value().get<std::size_t>();
  69. // Look up attribute data
  70. if (auto data_node = attribute_node.value().find("data"); data_node != attribute_node.value().end())
  71. {
  72. // Resize attribute data
  73. attribute_data.resize(data_node.value().size());
  74. // Fill attribute data
  75. float* v = &attribute_data.front();
  76. for (const auto& element: data_node.value())
  77. *(v++) = element.get<float>();
  78. }
  79. }
  80. }
  81. // Load bounds
  82. geom::aabb<float> bounds =
  83. {
  84. {std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity()},
  85. {-std::numeric_limits<float>::infinity(), -std::numeric_limits<float>::infinity(), -std::numeric_limits<float>::infinity()}
  86. };
  87. if (auto bounds_node = json.find("bounds"); bounds_node != json.end())
  88. {
  89. if (auto min_node = bounds_node.value().find("min"); min_node != bounds_node.value().end())
  90. {
  91. float* v = &bounds.min_point.x;
  92. for (const auto& element: min_node.value())
  93. *(v++) = element.get<float>();
  94. }
  95. if (auto max_node = bounds_node.value().find("max"); max_node != bounds_node.value().end())
  96. {
  97. float* v = &bounds.max_point.x;
  98. for (const auto& element: max_node.value())
  99. *(v++) = element.get<float>();
  100. }
  101. }
  102. // Allocate a model
  103. render::model* model = new render::model();
  104. // Set the model bounds
  105. model->set_bounds(bounds);
  106. // Calculate vertex size, count, and stride
  107. std::size_t vertex_size = 0;
  108. std::size_t vertex_count = 0;
  109. for (auto it = attributes.begin(); it != attributes.end(); ++it)
  110. {
  111. vertex_size += std::get<0>(it->second);
  112. vertex_count = std::get<1>(it->second).size() / std::get<0>(it->second);
  113. }
  114. std::size_t vertex_stride = sizeof(float) * vertex_size;
  115. // Build interleaved vertex data buffer
  116. float* vertex_data = new float[vertex_size * vertex_count];
  117. float* v = &vertex_data[0];
  118. for (std::size_t i = 0; i < vertex_count; ++i)
  119. {
  120. for (auto it = attributes.begin(); it != attributes.end(); ++it)
  121. {
  122. std::size_t attribute_size = std::get<0>(it->second);
  123. const float* a = &(std::get<1>(it->second)[i * attribute_size]);
  124. for (std::size_t j = 0; j < attribute_size; ++j)
  125. *(v++) = *(a++);
  126. }
  127. }
  128. // Resize VBO and upload vertex data
  129. gl::vertex_buffer* vbo = model->get_vertex_buffer();
  130. vbo->resize(sizeof(float) * vertex_size * vertex_count, vertex_data);
  131. // Free interleaved vertex data buffer
  132. delete[] vertex_data;
  133. // Map attribute names to locations
  134. static const std::unordered_map<std::string, unsigned int> attribute_location_map =
  135. {
  136. {"position", render::vertex_attribute::position},
  137. {"texcoord", render::vertex_attribute::uv},
  138. {"normal", render::vertex_attribute::normal},
  139. {"tangent", render::vertex_attribute::tangent},
  140. {"color", render::vertex_attribute::color},
  141. {"bone_index", render::vertex_attribute::bone_index},
  142. {"bone_weight", render::vertex_attribute::bone_weight},
  143. {"barycentric", render::vertex_attribute::barycentric},
  144. {"target", render::vertex_attribute::target}
  145. };
  146. // Bind attributes to VAO
  147. gl::vertex_array* vao = model->get_vertex_array();
  148. std::size_t attribute_offset = 0;
  149. for (auto attribute_it = attributes.begin(); attribute_it != attributes.end(); ++attribute_it)
  150. {
  151. std::string attribute_name = attribute_it->first;
  152. if (auto location_it = attribute_location_map.find(attribute_name); location_it != attribute_location_map.end())
  153. {
  154. gl::vertex_attribute attribute;
  155. attribute.buffer = vbo;
  156. attribute.offset = attribute_offset;
  157. attribute.stride = vertex_stride;
  158. attribute.type = gl::vertex_attribute_type::float_32;
  159. attribute.components = std::get<0>(attribute_it->second);
  160. vao->bind(location_it->second, attribute);
  161. attribute_offset += attribute.components * sizeof(float);
  162. }
  163. }
  164. // Load materials
  165. if (auto materials_node = json.find("materials"); materials_node != json.end())
  166. {
  167. for (const auto& material_node: materials_node.value().items())
  168. {
  169. std::string group_name;
  170. std::size_t group_offset = 0;
  171. std::size_t group_size = 0;
  172. render::material* group_material = nullptr;
  173. if (auto name_node = material_node.value().find("name"); name_node != material_node.value().end())
  174. group_name = name_node.value().get<std::string>();
  175. if (auto offset_node = material_node.value().find("offset"); offset_node != material_node.value().end())
  176. group_offset = offset_node.value().get<std::size_t>();
  177. if (auto size_node = material_node.value().find("size"); size_node != material_node.value().end())
  178. group_size = size_node.value().get<std::size_t>();
  179. // Slugify material filename
  180. std::string material_filename = group_name + ".mtl";
  181. std::replace(material_filename.begin(), material_filename.end(), '_', '-');
  182. // Load material from file
  183. group_material = resource_manager->load<render::material>(material_filename);
  184. render::model_group* model_group = model->add_group(group_name);
  185. model_group->set_drawing_mode(gl::drawing_mode::triangles);
  186. model_group->set_start_index(group_offset * 3);
  187. model_group->set_index_count(group_size * 3);
  188. model_group->set_material(group_material);
  189. }
  190. }
  191. // Build skeleton
  192. if (auto skeleton_node = json.find("skeleton"); skeleton_node != json.end())
  193. {
  194. if (auto bones_node = skeleton_node->find("bones"); bones_node != skeleton_node->end())
  195. {
  196. ::skeleton& skeleton = model->get_skeleton();
  197. pose& bind_pose = skeleton.bind_pose;
  198. std::uint8_t bone_index = 0;
  199. for (const auto& bone_node: bones_node.value())
  200. {
  201. // Find parent bone
  202. std::uint8_t bone_parent_index = bone_index;
  203. if (auto parent_node = bone_node.find("parent"); parent_node != bone_node.end())
  204. {
  205. if (!parent_node->is_null())
  206. bone_parent_index = parent_node->get<std::uint8_t>();
  207. }
  208. // Construct bone identifier
  209. ::bone bone = make_bone(bone_index, bone_parent_index);
  210. // Get reference to the bone's bind pose transform
  211. auto& bone_transform = bind_pose[bone];
  212. // Get bone translation
  213. if (auto translation_node = bone_node.find("translation"); translation_node != bone_node.end())
  214. {
  215. if (translation_node->size() == 3)
  216. {
  217. bone_transform.translation.x = (*translation_node)[0].get<float>();
  218. bone_transform.translation.y = (*translation_node)[1].get<float>();
  219. bone_transform.translation.z = (*translation_node)[2].get<float>();
  220. }
  221. }
  222. // Get bone rotation
  223. if (auto rotation_node = bone_node.find("rotation"); rotation_node != bone_node.end())
  224. {
  225. if (rotation_node->size() == 4)
  226. {
  227. bone_transform.rotation.w = (*rotation_node)[0].get<float>();
  228. bone_transform.rotation.x = (*rotation_node)[1].get<float>();
  229. bone_transform.rotation.y = (*rotation_node)[2].get<float>();
  230. bone_transform.rotation.z = (*rotation_node)[3].get<float>();
  231. }
  232. }
  233. // Set bone scale
  234. bone_transform.scale = {1, 1, 1};
  235. // Get bone length
  236. /*
  237. if (auto length_node = bone_node.find("length"); length_node != bone_node.end())
  238. bone.length = length_node->get<float>();
  239. else
  240. bone.length = 0.0f;
  241. */
  242. // Get bone name
  243. if (auto name_node = bone_node.find("name"); name_node != bone_node.end())
  244. {
  245. // Add bone to bone map
  246. skeleton.bone_map[name_node->get<std::string>()] = bone;
  247. }
  248. ++bone_index;
  249. }
  250. // Calculate inverse skeleton-space bind pose
  251. ::concatenate(skeleton.bind_pose, skeleton.inverse_bind_pose);
  252. ::inverse(skeleton.inverse_bind_pose, skeleton.inverse_bind_pose);
  253. }
  254. }
  255. return model;
  256. }