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

531 lines
16 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 "renderer/model.hpp"
  22. #include "renderer/vertex-attributes.hpp"
  23. #include "gl/vertex-attribute-type.hpp"
  24. #include "gl/drawing-mode.hpp"
  25. #include "utility/fundamental-types.hpp"
  26. #include <sstream>
  27. #include <stdexcept>
  28. #include <limits>
  29. #include <physfs.h>
  30. #include <iostream>
  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. /*
  39. template <>
  40. model* resource_loader<model>::load(resource_manager* resource_manager, PHYSFS_File* file)
  41. {
  42. std::string line;
  43. std::vector<float3> positions;
  44. std::vector<float2> uvs;
  45. std::vector<float3> normals;
  46. std::vector<float3> tangents;
  47. std::vector<float3> bitangents;
  48. std::vector<std::vector<std::size_t>> faces;
  49. std::vector<material_group> material_groups;
  50. material_group* current_material_group = nullptr;
  51. aabb<float> bounds =
  52. {
  53. {std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity()},
  54. {-std::numeric_limits<float>::infinity(), -std::numeric_limits<float>::infinity(), -std::numeric_limits<float>::infinity()}
  55. };
  56. while (!PHYSFS_eof(file))
  57. {
  58. // Read line
  59. physfs_getline(file, line);
  60. // Tokenize line
  61. std::vector<std::string> tokens;
  62. std::string token;
  63. std::istringstream linestream(line);
  64. while (linestream >> token)
  65. tokens.push_back(token);
  66. // Skip empty lines and comments
  67. if (tokens.empty() || tokens[0][0] == '#')
  68. continue;
  69. if (tokens[0] == "v")
  70. {
  71. if (tokens.size() != 4)
  72. {
  73. std::stringstream stream;
  74. stream << "resource_loader<mesh>::load(): Invalid line \"" << line << "\"" << std::endl;
  75. throw std::runtime_error(stream.str());
  76. }
  77. float3 position;
  78. std::stringstream(tokens[1]) >> position[0];
  79. std::stringstream(tokens[2]) >> position[1];
  80. std::stringstream(tokens[3]) >> position[2];
  81. positions.push_back(position);
  82. // Add position to bounds
  83. for (int i = 0; i < 3; ++i)
  84. {
  85. bounds.min_point[i] = std::min<float>(bounds.min_point[i], position[i]);
  86. bounds.max_point[i] = std::max<float>(bounds.max_point[i], position[i]);
  87. }
  88. }
  89. else if (tokens[0] == "vt")
  90. {
  91. if (tokens.size() != 3)
  92. {
  93. std::stringstream stream;
  94. stream << "resource_loader<mesh>::load(): Invalid line \"" << line << "\"" << std::endl;
  95. throw std::runtime_error(stream.str());
  96. }
  97. float2 uv;
  98. std::stringstream(tokens[1]) >> uv[0];
  99. std::stringstream(tokens[2]) >> uv[1];
  100. uvs.push_back(uv);
  101. }
  102. else if (tokens[0] == "vn")
  103. {
  104. if (tokens.size() != 4)
  105. {
  106. std::stringstream stream;
  107. stream << "resource_loader<mesh>::load(): Invalid line \"" << line << "\"" << std::endl;
  108. throw std::runtime_error(stream.str());
  109. }
  110. float3 normal;
  111. std::stringstream(tokens[1]) >> normal[0];
  112. std::stringstream(tokens[2]) >> normal[1];
  113. std::stringstream(tokens[3]) >> normal[2];
  114. normals.push_back(normal);
  115. }
  116. else if (tokens[0] == "f")
  117. {
  118. if (tokens.size() != 4)
  119. {
  120. std::stringstream stream;
  121. stream << "resource_loader<mesh>::load(): Invalid line \"" << line << "\"" << std::endl;
  122. throw std::runtime_error(stream.str());
  123. }
  124. std::vector<std::size_t> face;
  125. for (std::size_t i = 0; i < 3; ++i)
  126. {
  127. std::stringstream ss(tokens[i + 1]);
  128. while (ss.good())
  129. {
  130. std::string substring;
  131. std::getline(ss, substring, '/');
  132. if (!substring.empty())
  133. {
  134. std::size_t index = std::stoul(substring) - 1;
  135. face.push_back(index);
  136. }
  137. }
  138. }
  139. faces.push_back(face);
  140. }
  141. else if (tokens[0] == "usemtl")
  142. {
  143. if (tokens.size() != 2)
  144. {
  145. std::stringstream stream;
  146. stream << "resource_loader<mesh>::load(): Invalid line \"" << line << "\"" << std::endl;
  147. throw std::runtime_error(stream.str());
  148. }
  149. if (current_material_group)
  150. {
  151. current_material_group->index_count = faces.size() * 3 - current_material_group->start_index;
  152. }
  153. material_groups.push_back(material_group());
  154. current_material_group = &material_groups.back();
  155. current_material_group->name = tokens[1];
  156. current_material_group->start_index = faces.size() * 3;
  157. current_material_group->index_count = 0;
  158. }
  159. }
  160. if (current_material_group)
  161. {
  162. current_material_group->index_count = faces.size() * 3 - current_material_group->start_index;
  163. }
  164. // Load material group materials
  165. for (material_group& material_group: material_groups)
  166. {
  167. material_group.material = resource_manager->load<material>(material_group.name + ".mtl");
  168. }
  169. bool has_uvs = (!uvs.empty());
  170. bool has_normals = (!normals.empty());
  171. bool has_tangents = (has_uvs && has_normals);
  172. bool has_barycentric = false;
  173. has_barycentric = true;
  174. // Calculate faceted tangents and bitangents
  175. if (has_tangents)
  176. {
  177. tangents.resize(positions.size());
  178. bitangents.resize(positions.size());
  179. for (std::size_t i = 0; i < positions.size(); ++i)
  180. {
  181. tangents[i] = {0.0f, 0.0f, 0.0f};
  182. bitangents[i] = {0.0f, 0.0f, 0.0f};
  183. }
  184. for (std::size_t i = 0; i < faces.size(); ++i)
  185. {
  186. const std::vector<std::size_t>& face = faces[i];
  187. std::size_t ia = face[0];
  188. std::size_t ib = face[3];
  189. std::size_t ic = face[6];
  190. const float3& a = positions[ia];
  191. const float3& b = positions[ib];
  192. const float3& c = positions[ic];
  193. const float2& uva = uvs[face[1]];
  194. const float2& uvb = uvs[face[4]];
  195. const float2& uvc = uvs[face[7]];
  196. float3 ba = b - a;
  197. float3 ca = c - a;
  198. float2 uvba = uvb - uva;
  199. float2 uvca = uvc - uva;
  200. float f = 1.0f / (uvba.x * uvca.y - uvca.x * uvba.y);
  201. float3 tangent = (ba * uvca.y - ca * uvba.y) * f;
  202. float3 bitangent = (ba * -uvca.x + ca * uvba.x) * f;
  203. tangents[ia] += tangent;
  204. tangents[ib] += tangent;
  205. tangents[ic] += tangent;
  206. bitangents[ia] += bitangent;
  207. bitangents[ib] += bitangent;
  208. bitangents[ic] += bitangent;
  209. }
  210. }
  211. std::size_t vertex_size = 3;
  212. if (has_uvs)
  213. vertex_size += 2;
  214. if (has_normals)
  215. vertex_size += 3;
  216. if (has_tangents)
  217. vertex_size += 4;
  218. if (has_barycentric)
  219. vertex_size += 3;
  220. std::size_t vertex_stride = sizeof(float) * vertex_size;
  221. // Generate vertex buffer
  222. float* vertex_data = new float[vertex_size * faces.size() * 3];
  223. float* v = &vertex_data[0];
  224. for (std::size_t i = 0; i < faces.size(); ++i)
  225. {
  226. const std::vector<std::size_t>& face = faces[i];
  227. std::size_t k = 0;
  228. for (std::size_t j = 0; j < 3; ++j)
  229. {
  230. const float3& position = positions[face[k++]];
  231. *(v++) = position.x;
  232. *(v++) = position.y;
  233. *(v++) = position.z;
  234. if (has_uvs)
  235. {
  236. const float2& uv = uvs[face[k++]];
  237. *(v++) = uv.x;
  238. *(v++) = uv.y;
  239. }
  240. if (has_normals)
  241. {
  242. const float3& normal = normals[face[k++]];
  243. *(v++) = normal.x;
  244. *(v++) = normal.y;
  245. *(v++) = normal.z;
  246. }
  247. if (has_tangents)
  248. {
  249. const float3& n = normals[face[k - 1]];
  250. const float3& t = tangents[face[k - 3]];
  251. const float3& b = bitangents[face[k - 3]];
  252. // Gram-Schmidt orthogonalize tangent and bitangent
  253. float3 tangent = math::normalize(t - n * dot(n, t));
  254. float bitangent_sign = (math::dot(math::cross(n, t), b) < 0.0f) ? -1.0f : 1.0f;
  255. *(v++) = tangent.x;
  256. *(v++) = tangent.y;
  257. *(v++) = tangent.z;
  258. *(v++) = bitangent_sign;
  259. }
  260. if (has_barycentric)
  261. {
  262. *(v++) = barycentric_coords[j].x;
  263. *(v++) = barycentric_coords[j].y;
  264. *(v++) = barycentric_coords[j].z;
  265. }
  266. }
  267. }
  268. // Allocate a model
  269. model* model = new ::model();
  270. model->set_bounds(bounds);
  271. vertex_buffer* vbo = model->get_vertex_buffer();
  272. vertex_array* vao = model->get_vertex_array();
  273. vbo->resize(sizeof(float) * vertex_size * faces.size() * 3, vertex_data);
  274. std::size_t offset = 0;
  275. vao->bind_attribute(VERTEX_POSITION_LOCATION, *vbo, 3, vertex_attribute_type::float_32, vertex_stride, 0);
  276. offset += 3;
  277. if (has_uvs)
  278. {
  279. vao->bind_attribute(VERTEX_TEXCOORD_LOCATION, *vbo, 2, vertex_attribute_type::float_32, vertex_stride, sizeof(float) * offset);
  280. offset += 2;
  281. }
  282. if (has_normals)
  283. {
  284. vao->bind_attribute(VERTEX_NORMAL_LOCATION, *vbo, 3, vertex_attribute_type::float_32, vertex_stride, sizeof(float) * offset);
  285. offset += 3;
  286. }
  287. if (has_tangents)
  288. {
  289. vao->bind_attribute(VERTEX_TANGENT_LOCATION, *vbo, 4, vertex_attribute_type::float_32, vertex_stride, sizeof(float) * offset);
  290. offset += 4;
  291. }
  292. if (has_barycentric)
  293. {
  294. vao->bind_attribute(VERTEX_BARYCENTRIC_LOCATION, *vbo, 3, vertex_attribute_type::float_32, vertex_stride, sizeof(float) * offset);
  295. offset += 3;
  296. }
  297. // Add model groups for each material
  298. for (const material_group& material_group: material_groups)
  299. {
  300. model_group* model_group = model->add_group(material_group.name);
  301. model_group->set_material(material_group.material);
  302. model_group->set_drawing_mode(drawing_mode::triangles);
  303. model_group->set_start_index(material_group.start_index);
  304. model_group->set_index_count(material_group.index_count);
  305. }
  306. // Deallocate vertex data
  307. delete[] vertex_data;
  308. return model;
  309. }
  310. */
  311. template <>
  312. model* resource_loader<model>::load(resource_manager* resource_manager, PHYSFS_File* file)
  313. {
  314. // Read file into buffer
  315. std::size_t size = static_cast<int>(PHYSFS_fileLength(file));
  316. std::vector<std::uint8_t> buffer(size);
  317. PHYSFS_readBytes(file, &buffer.front(), size);
  318. // Parse CBOR in file buffer
  319. nlohmann::json json = nlohmann::json::from_cbor(buffer);
  320. // Find model name
  321. std::string model_name;
  322. if (auto it = json.find("name"); it != json.end())
  323. model_name = it.value();
  324. // Load attributes
  325. std::unordered_map<std::string, std::tuple<std::size_t, std::vector<float>>> attributes;
  326. if (auto attributes_node = json.find("attributes"); attributes_node != json.end())
  327. {
  328. for (const auto& attribute_node: attributes_node.value().items())
  329. {
  330. // Look up attribute name
  331. std::string attribute_name;
  332. if (auto type_node = attribute_node.value().find("name"); type_node != attribute_node.value().end())
  333. attribute_name = type_node.value().get<std::string>();
  334. // Allocate attribute in attribute map
  335. auto& attribute = attributes[attribute_name];
  336. std::size_t& attribute_size = std::get<0>(attribute);
  337. std::vector<float>& attribute_data = std::get<1>(attribute);
  338. // Look up attribute size (per vertex)
  339. attribute_size = 0;
  340. if (auto size_node = attribute_node.value().find("size"); size_node != attribute_node.value().end())
  341. attribute_size = size_node.value().get<std::size_t>();
  342. // Look up attribute data
  343. if (auto data_node = attribute_node.value().find("data"); data_node != attribute_node.value().end())
  344. {
  345. // Resize attribute data
  346. attribute_data.resize(data_node.value().size());
  347. // Fill attribute data
  348. float* v = &attribute_data.front();
  349. for (const auto& element: data_node.value())
  350. *(v++) = element.get<float>();
  351. }
  352. }
  353. }
  354. // Load bounds
  355. geom::aabb<float> bounds =
  356. {
  357. {std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity()},
  358. {-std::numeric_limits<float>::infinity(), -std::numeric_limits<float>::infinity(), -std::numeric_limits<float>::infinity()}
  359. };
  360. if (auto bounds_node = json.find("bounds"); bounds_node != json.end())
  361. {
  362. if (auto min_node = bounds_node.value().find("min"); min_node != bounds_node.value().end())
  363. {
  364. float* v = &bounds.min_point.x;
  365. for (const auto& element: min_node.value())
  366. *(v++) = element.get<float>();
  367. }
  368. if (auto max_node = bounds_node.value().find("max"); max_node != bounds_node.value().end())
  369. {
  370. float* v = &bounds.max_point.x;
  371. for (const auto& element: max_node.value())
  372. *(v++) = element.get<float>();
  373. }
  374. }
  375. // Allocate a model
  376. model* model = new ::model();
  377. // Set the model bounds
  378. model->set_bounds(bounds);
  379. // Calculate vertex size, count, and stride
  380. std::size_t vertex_size = 0;
  381. std::size_t vertex_count = 0;
  382. for (auto it = attributes.begin(); it != attributes.end(); ++it)
  383. {
  384. vertex_size += std::get<0>(it->second);
  385. vertex_count = std::get<1>(it->second).size() / std::get<0>(it->second);
  386. }
  387. std::size_t vertex_stride = sizeof(float) * vertex_size;
  388. // Build interleaved vertex data buffer
  389. float* vertex_data = new float[vertex_size * vertex_count];
  390. float* v = &vertex_data[0];
  391. for (std::size_t i = 0; i < vertex_count; ++i)
  392. {
  393. for (auto it = attributes.begin(); it != attributes.end(); ++it)
  394. {
  395. std::size_t attribute_size = std::get<0>(it->second);
  396. const float* a = &(std::get<1>(it->second)[i * attribute_size]);
  397. for (std::size_t j = 0; j < attribute_size; ++j)
  398. *(v++) = *(a++);
  399. }
  400. }
  401. // Resize VBO and upload vertex data
  402. gl::vertex_buffer* vbo = model->get_vertex_buffer();
  403. vbo->resize(sizeof(float) * vertex_size * vertex_count, vertex_data);
  404. // Free interleaved vertex data buffer
  405. delete[] vertex_data;
  406. // Map attribute names to locations
  407. static const std::unordered_map<std::string, unsigned int> attribute_location_map =
  408. {
  409. {"position", VERTEX_POSITION_LOCATION},
  410. {"texcoord", VERTEX_TEXCOORD_LOCATION},
  411. {"normal", VERTEX_NORMAL_LOCATION},
  412. {"tangent", VERTEX_TANGENT_LOCATION},
  413. {"color", VERTEX_COLOR_LOCATION},
  414. {"bone_index", VERTEX_BONE_INDEX_LOCATION},
  415. {"bone_weight", VERTEX_BONE_WEIGHT_LOCATION},
  416. {"barycentric", VERTEX_BARYCENTRIC_LOCATION}
  417. };
  418. // Bind attributes to VAO
  419. gl::vertex_array* vao = model->get_vertex_array();
  420. std::size_t offset = 0;
  421. for (auto attribute_it = attributes.begin(); attribute_it != attributes.end(); ++attribute_it)
  422. {
  423. std::string attribute_name = attribute_it->first;
  424. std::size_t attribute_size = std::get<0>(attribute_it->second);
  425. if (auto location_it = attribute_location_map.find(attribute_name); location_it != attribute_location_map.end())
  426. vao->bind_attribute(location_it->second, *vbo, attribute_size, gl::vertex_attribute_type::float_32, vertex_stride, offset);
  427. offset += attribute_size * sizeof(float);
  428. }
  429. // Load materials
  430. if (auto materials_node = json.find("materials"); materials_node != json.end())
  431. {
  432. for (const auto& material_node: materials_node.value().items())
  433. {
  434. std::string group_name;
  435. std::size_t group_offset = 0;
  436. std::size_t group_size = 0;
  437. material* group_material = nullptr;
  438. if (auto name_node = material_node.value().find("name"); name_node != material_node.value().end())
  439. group_name = name_node.value().get<std::string>();
  440. if (auto offset_node = material_node.value().find("offset"); offset_node != material_node.value().end())
  441. group_offset = offset_node.value().get<std::size_t>();
  442. if (auto size_node = material_node.value().find("size"); size_node != material_node.value().end())
  443. group_size = size_node.value().get<std::size_t>();
  444. // Slugify material filename
  445. std::string material_filename = group_name + ".mtl";
  446. std::replace(material_filename.begin(), material_filename.end(), '_', '-');
  447. // Load material from file
  448. group_material = resource_manager->load<material>(material_filename);
  449. model_group* model_group = model->add_group(group_name);
  450. model_group->set_drawing_mode(gl::drawing_mode::triangles);
  451. model_group->set_start_index(group_offset * 3);
  452. model_group->set_index_count(group_size * 3);
  453. model_group->set_material(group_material);
  454. }
  455. }
  456. return model;
  457. }