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

1042 lines
58 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 "game/ant/morphogenesis.hpp"
  20. #include "render/material.hpp"
  21. #include "render/vertex-attribute.hpp"
  22. #include "math/transform-operators.hpp"
  23. #include "math/quaternion.hpp"
  24. #include <unordered_set>
  25. #include <iostream>
  26. namespace game {
  27. namespace ant {
  28. static render::model* generate_queen(const ant::breed& breed);
  29. static render::model* generate_worker(const ant::breed& breed);
  30. static render::model* generate_soldier(const ant::breed& breed);
  31. static render::model* generate_male(const ant::breed& breed);
  32. static render::material* build_exoskeleton_material
  33. (
  34. const ant::trait::pigmentation& pigmentation,
  35. const ant::trait::sculpturing& sculpturing
  36. );
  37. static void reskin_vertices
  38. (
  39. std::uint8_t* vertex_data,
  40. std::size_t index_count,
  41. const gl::vertex_attribute& position_attribute,
  42. const gl::vertex_attribute& normal_attribute,
  43. const gl::vertex_attribute& tangent_attribute,
  44. const gl::vertex_attribute& bone_index_attribute,
  45. const std::unordered_set<std::uint8_t>& old_bone_indices,
  46. std::uint8_t new_bone_index,
  47. const math::transform<float>& transform
  48. );
  49. static geom::aabb<float> calculate_bounds(std::uint8_t* vertex_data, std::size_t index_count, const gl::vertex_attribute& position_attribute);
  50. static render::model* build_model
  51. (
  52. render::material* material,
  53. const render::model* antennae,
  54. const render::model* eyes,
  55. const render::model* forewings,
  56. const render::model* gaster,
  57. const render::model* head,
  58. const render::model* hindwings,
  59. const render::model* legs,
  60. const render::model* mandibles,
  61. const render::model* mesosoma,
  62. const render::model* lateral_ocelli,
  63. const render::model* median_ocellus,
  64. const render::model* sting,
  65. const render::model* waist
  66. );
  67. render::model* morphogenesis(const ant::breed& breed, ant::caste caste)
  68. {
  69. switch (caste)
  70. {
  71. case ant::caste::queen:
  72. return generate_queen(breed);
  73. case ant::caste::worker:
  74. return generate_worker(breed);
  75. case ant::caste::soldier:
  76. return generate_soldier(breed);
  77. case ant::caste::male:
  78. return generate_male(breed);
  79. }
  80. return nullptr;
  81. }
  82. render::model* generate_queen(const ant::breed& breed)
  83. {
  84. return nullptr;
  85. }
  86. render::model* generate_worker(const ant::breed& breed)
  87. {
  88. // Build exoskeleton material
  89. render::material* exoskeleton_material = build_exoskeleton_material(*breed.pigmentation, *breed.sculpturing);
  90. // Get worker body part models
  91. render::model* antennae_model = breed.antennae->model;
  92. render::model* eyes_model = breed.eyes->model;
  93. render::model* gaster_model = breed.gaster->model;
  94. render::model* head_model = breed.head->model;
  95. render::model* legs_model = breed.legs->model;
  96. render::model* mandibles_model = breed.mandibles->model;
  97. render::model* mesosoma_model = breed.mesosoma->model;
  98. render::model* sting_model = breed.sting->model;
  99. render::model* waist_model = breed.waist->model;
  100. //render::model* lateral_ocelli_model = breed.ocelli->lateral_ocelli_model;
  101. //render::model* median_ocellus_model = breed.ocelli->median_ocellus_model;
  102. // Build worker model
  103. render::model* model = build_model
  104. (
  105. exoskeleton_material,
  106. antennae_model,
  107. eyes_model,
  108. nullptr, // forewings
  109. gaster_model,
  110. head_model,
  111. nullptr, // hindwings
  112. legs_model,
  113. mandibles_model,
  114. mesosoma_model,
  115. nullptr, // lateral ocelli
  116. nullptr, // median ocellus
  117. sting_model,
  118. waist_model
  119. );
  120. return model;
  121. }
  122. render::model* generate_soldier(const ant::breed& breed)
  123. {
  124. return nullptr;
  125. }
  126. render::model* generate_male(const ant::breed& breed)
  127. {
  128. return nullptr;
  129. }
  130. render::material* build_exoskeleton_material
  131. (
  132. const ant::trait::pigmentation& pigmentation,
  133. const ant::trait::sculpturing& sculpturing
  134. )
  135. {
  136. // Allocate copy of pigmentation material
  137. render::material* exoskeleton_material = new render::material(*pigmentation.material);
  138. // Adjust roughness parameter
  139. if (render::material_property_base* property = exoskeleton_material->get_property("roughness"); property != nullptr)
  140. {
  141. static_cast<render::material_property<float>*>(property)->set_value(sculpturing.roughness);
  142. }
  143. else
  144. {
  145. exoskeleton_material->add_property<float>("roughness")->set_value(sculpturing.roughness);
  146. }
  147. // Adjust normal map parameter
  148. if (render::material_property_base* property = exoskeleton_material->get_property("normal_map"); property != nullptr)
  149. {
  150. static_cast<render::material_property<const gl::texture_2d*>*>(property)->set_value(sculpturing.normal_map);
  151. }
  152. else
  153. {
  154. exoskeleton_material->add_property<const gl::texture_2d*>("normal_map")->set_value(sculpturing.normal_map);
  155. }
  156. return exoskeleton_material;
  157. }
  158. render::model* build_model
  159. (
  160. render::material* exoskeleton_material,
  161. const render::model* antennae,
  162. const render::model* eyes,
  163. const render::model* forewings,
  164. const render::model* gaster,
  165. const render::model* head,
  166. const render::model* hindwings,
  167. const render::model* legs,
  168. const render::model* mandibles,
  169. const render::model* mesosoma,
  170. const render::model* lateral_ocelli,
  171. const render::model* median_ocellus,
  172. const render::model* sting,
  173. const render::model* waist
  174. )
  175. {
  176. // Get vertex buffers of required body parts
  177. const gl::vertex_buffer* mesosoma_vbo = mesosoma->get_vertex_buffer();
  178. const gl::vertex_buffer* legs_vbo = legs->get_vertex_buffer();
  179. const gl::vertex_buffer* head_vbo = head->get_vertex_buffer();
  180. const gl::vertex_buffer* mandibles_vbo = mandibles->get_vertex_buffer();
  181. const gl::vertex_buffer* antennae_vbo = antennae->get_vertex_buffer();
  182. const gl::vertex_buffer* waist_vbo = waist->get_vertex_buffer();
  183. const gl::vertex_buffer* gaster_vbo = gaster->get_vertex_buffer();
  184. // Get vertex buffers of optional body parts
  185. const gl::vertex_buffer* sting_vbo = (sting) ? sting->get_vertex_buffer() : nullptr;
  186. const gl::vertex_buffer* eyes_vbo = (eyes) ? eyes->get_vertex_buffer() : nullptr;
  187. const gl::vertex_buffer* lateral_ocelli_vbo = (lateral_ocelli) ? lateral_ocelli->get_vertex_buffer() : nullptr;
  188. const gl::vertex_buffer* median_ocellus_vbo = (median_ocellus) ? median_ocellus->get_vertex_buffer() : nullptr;
  189. const gl::vertex_buffer* forewings_vbo = (forewings) ? forewings->get_vertex_buffer() : nullptr;
  190. const gl::vertex_buffer* hindwings_vbo = (hindwings) ? hindwings->get_vertex_buffer() : nullptr;
  191. // Determine combined size of vertex buffers and save offsets
  192. std::size_t vertex_buffer_size = 0;
  193. std::size_t mesosoma_vbo_offset = vertex_buffer_size;
  194. vertex_buffer_size += mesosoma_vbo->get_size();
  195. std::size_t legs_vbo_offset = vertex_buffer_size;
  196. vertex_buffer_size += legs_vbo->get_size();
  197. std::size_t head_vbo_offset = vertex_buffer_size;
  198. vertex_buffer_size += head_vbo->get_size();
  199. std::size_t mandibles_vbo_offset = vertex_buffer_size;
  200. vertex_buffer_size += mandibles_vbo->get_size();
  201. std::size_t antennae_vbo_offset = vertex_buffer_size;
  202. vertex_buffer_size += antennae_vbo->get_size();
  203. std::size_t waist_vbo_offset = vertex_buffer_size;
  204. vertex_buffer_size += waist_vbo->get_size();
  205. std::size_t gaster_vbo_offset = vertex_buffer_size;
  206. vertex_buffer_size += gaster_vbo->get_size();
  207. std::size_t sting_vbo_offset = vertex_buffer_size;
  208. if (sting)
  209. vertex_buffer_size += sting_vbo->get_size();
  210. std::size_t eyes_vbo_offset = vertex_buffer_size;
  211. if (eyes)
  212. vertex_buffer_size += eyes_vbo->get_size();
  213. std::size_t lateral_ocelli_vbo_offset = vertex_buffer_size;
  214. if (lateral_ocelli)
  215. vertex_buffer_size += lateral_ocelli_vbo->get_size();
  216. std::size_t median_ocellus_vbo_offset = vertex_buffer_size;
  217. if (median_ocellus)
  218. vertex_buffer_size += median_ocellus_vbo->get_size();
  219. std::size_t forewings_vbo_offset = vertex_buffer_size;
  220. if (forewings)
  221. vertex_buffer_size += forewings_vbo->get_size();
  222. std::size_t hindwings_vbo_offset = vertex_buffer_size;
  223. if (hindwings)
  224. vertex_buffer_size += hindwings_vbo->get_size();
  225. // Allocate combined vertex buffer data
  226. std::uint8_t* vertex_buffer_data = new std::uint8_t[vertex_buffer_size];
  227. // Read body part vertex buffer data into combined vertex buffer data
  228. mesosoma_vbo->read(0, mesosoma_vbo->get_size(), vertex_buffer_data + mesosoma_vbo_offset);
  229. legs_vbo->read(0, legs_vbo->get_size(), vertex_buffer_data + legs_vbo_offset);
  230. head_vbo->read(0, head_vbo->get_size(), vertex_buffer_data + head_vbo_offset);
  231. mandibles_vbo->read(0, mandibles_vbo->get_size(), vertex_buffer_data + mandibles_vbo_offset);
  232. antennae_vbo->read(0, antennae_vbo->get_size(), vertex_buffer_data + antennae_vbo_offset);
  233. waist_vbo->read(0, waist_vbo->get_size(), vertex_buffer_data + waist_vbo_offset);
  234. gaster_vbo->read(0, gaster_vbo->get_size(), vertex_buffer_data + gaster_vbo_offset);
  235. if (sting)
  236. sting_vbo->read(0, sting_vbo->get_size(), vertex_buffer_data + sting_vbo_offset);
  237. if (eyes)
  238. eyes_vbo->read(0, eyes_vbo->get_size(), vertex_buffer_data + eyes_vbo_offset);
  239. if (lateral_ocelli)
  240. lateral_ocelli_vbo->read(0, lateral_ocelli_vbo->get_size(), vertex_buffer_data + lateral_ocelli_vbo_offset);
  241. if (median_ocellus)
  242. median_ocellus_vbo->read(0, median_ocellus_vbo->get_size(), vertex_buffer_data + median_ocellus_vbo_offset);
  243. if (forewings)
  244. forewings_vbo->read(0, forewings_vbo->get_size(), vertex_buffer_data + forewings_vbo_offset);
  245. if (hindwings)
  246. hindwings_vbo->read(0, hindwings_vbo->get_size(), vertex_buffer_data + hindwings_vbo_offset);
  247. // Allocate model
  248. render::model* model = new render::model();
  249. // Setup model VAO
  250. gl::vertex_array* model_vao = model->get_vertex_array();
  251. for (auto [location, attribute]: mesosoma->get_vertex_array()->get_attributes())
  252. {
  253. attribute.buffer = model->get_vertex_buffer();
  254. model_vao->bind(location, attribute);
  255. }
  256. // Get vertex attributes
  257. const gl::vertex_attribute* position_attribute = nullptr;
  258. const gl::vertex_attribute* normal_attribute = nullptr;
  259. const gl::vertex_attribute* tangent_attribute = nullptr;
  260. const gl::vertex_attribute* bone_index_attribute = nullptr;
  261. const auto& vertex_attribute_map = model_vao->get_attributes();
  262. if (auto it = vertex_attribute_map.find(render::vertex_attribute::position); it != vertex_attribute_map.end())
  263. position_attribute = &it->second;
  264. if (auto it = vertex_attribute_map.find(render::vertex_attribute::normal); it != vertex_attribute_map.end())
  265. normal_attribute = &it->second;
  266. if (auto it = vertex_attribute_map.find(render::vertex_attribute::tangent); it != vertex_attribute_map.end())
  267. tangent_attribute = &it->second;
  268. if (auto it = vertex_attribute_map.find(render::vertex_attribute::bone_index); it != vertex_attribute_map.end())
  269. bone_index_attribute = &it->second;
  270. // Get body part skeletons
  271. const ::skeleton& mesosoma_skeleton = mesosoma->get_skeleton();
  272. const ::skeleton& legs_skeleton = legs->get_skeleton();
  273. const ::skeleton& head_skeleton = head->get_skeleton();
  274. const ::skeleton& mandibles_skeleton = mandibles->get_skeleton();
  275. const ::skeleton& antennae_skeleton = antennae->get_skeleton();
  276. const ::skeleton& waist_skeleton = waist->get_skeleton();
  277. const ::skeleton& gaster_skeleton = gaster->get_skeleton();
  278. const ::skeleton* sting_skeleton = (sting) ? &sting->get_skeleton() : nullptr;
  279. const ::skeleton* eyes_skeleton = (eyes) ? &eyes->get_skeleton() : nullptr;
  280. const ::skeleton* lateral_ocelli_skeleton = (lateral_ocelli) ? &lateral_ocelli->get_skeleton() : nullptr;
  281. const ::skeleton* median_ocellus_skeleton = (median_ocellus) ? &median_ocellus->get_skeleton() : nullptr;
  282. bool postpetiole = (waist_skeleton.bone_map.find("postpetiole") != waist_skeleton.bone_map.end());
  283. // Allocate skeleton bones
  284. ::skeleton& skeleton = model->get_skeleton();
  285. std::size_t bone_count = 34;
  286. if (postpetiole)
  287. bone_count += 1;
  288. if (sting)
  289. bone_count += 1;
  290. if (forewings)
  291. bone_count += 2;
  292. if (hindwings)
  293. bone_count += 2;
  294. // Assign bone indices
  295. std::uint8_t bone_index = 0;
  296. std::uint8_t mesosoma_bone_index = bone_index++;
  297. std::uint8_t foreleg_coxa_l_bone_index = bone_index++;
  298. std::uint8_t foreleg_coxa_r_bone_index = bone_index++;
  299. std::uint8_t foreleg_femur_l_bone_index = bone_index++;
  300. std::uint8_t foreleg_femur_r_bone_index = bone_index++;
  301. std::uint8_t foreleg_tibia_l_bone_index = bone_index++;
  302. std::uint8_t foreleg_tibia_r_bone_index = bone_index++;
  303. std::uint8_t foreleg_tarsus_l_bone_index = bone_index++;
  304. std::uint8_t foreleg_tarsus_r_bone_index = bone_index++;
  305. std::uint8_t midleg_coxa_l_bone_index = bone_index++;
  306. std::uint8_t midleg_coxa_r_bone_index = bone_index++;
  307. std::uint8_t midleg_femur_l_bone_index = bone_index++;
  308. std::uint8_t midleg_femur_r_bone_index = bone_index++;
  309. std::uint8_t midleg_tibia_l_bone_index = bone_index++;
  310. std::uint8_t midleg_tibia_r_bone_index = bone_index++;
  311. std::uint8_t midleg_tarsus_l_bone_index = bone_index++;
  312. std::uint8_t midleg_tarsus_r_bone_index = bone_index++;
  313. std::uint8_t hindleg_coxa_l_bone_index = bone_index++;
  314. std::uint8_t hindleg_coxa_r_bone_index = bone_index++;
  315. std::uint8_t hindleg_femur_l_bone_index = bone_index++;
  316. std::uint8_t hindleg_femur_r_bone_index = bone_index++;
  317. std::uint8_t hindleg_tibia_l_bone_index = bone_index++;
  318. std::uint8_t hindleg_tibia_r_bone_index = bone_index++;
  319. std::uint8_t hindleg_tarsus_l_bone_index = bone_index++;
  320. std::uint8_t hindleg_tarsus_r_bone_index = bone_index++;
  321. std::uint8_t head_bone_index = bone_index++;
  322. std::uint8_t mandible_l_bone_index = bone_index++;
  323. std::uint8_t mandible_r_bone_index = bone_index++;
  324. std::uint8_t scape_l_bone_index = bone_index++;
  325. std::uint8_t scape_r_bone_index = bone_index++;
  326. std::uint8_t pedicel_l_bone_index = bone_index++;
  327. std::uint8_t pedicel_r_bone_index = bone_index++;
  328. std::uint8_t petiole_bone_index = bone_index++;
  329. std::uint8_t postpetiole_bone_index = (postpetiole) ? bone_index++ : static_cast<std::uint8_t>(bone_count);
  330. std::uint8_t gaster_bone_index = bone_index++;
  331. std::uint8_t sting_bone_index = (sting) ? bone_index++ : static_cast<std::uint8_t>(bone_count);
  332. // Construct bone identifiers
  333. ::bone mesosoma_bone = make_bone(mesosoma_bone_index);
  334. ::bone foreleg_coxa_l_bone = make_bone(foreleg_coxa_l_bone_index, mesosoma_bone_index);
  335. ::bone foreleg_coxa_r_bone = make_bone(foreleg_coxa_r_bone_index, mesosoma_bone_index);
  336. ::bone foreleg_femur_l_bone = make_bone(foreleg_femur_l_bone_index, foreleg_coxa_l_bone_index);
  337. ::bone foreleg_femur_r_bone = make_bone(foreleg_femur_r_bone_index, foreleg_coxa_r_bone_index);
  338. ::bone foreleg_tibia_l_bone = make_bone(foreleg_tibia_l_bone_index, foreleg_femur_l_bone_index);
  339. ::bone foreleg_tibia_r_bone = make_bone(foreleg_tibia_r_bone_index, foreleg_femur_r_bone_index);
  340. ::bone foreleg_tarsus_l_bone = make_bone(foreleg_tarsus_l_bone_index, foreleg_tibia_l_bone_index);
  341. ::bone foreleg_tarsus_r_bone = make_bone(foreleg_tarsus_r_bone_index, foreleg_tibia_r_bone_index);
  342. ::bone midleg_coxa_l_bone = make_bone(midleg_coxa_l_bone_index, mesosoma_bone_index);
  343. ::bone midleg_coxa_r_bone = make_bone(midleg_coxa_r_bone_index, mesosoma_bone_index);
  344. ::bone midleg_femur_l_bone = make_bone(midleg_femur_l_bone_index, midleg_coxa_l_bone_index);
  345. ::bone midleg_femur_r_bone = make_bone(midleg_femur_r_bone_index, midleg_coxa_r_bone_index);
  346. ::bone midleg_tibia_l_bone = make_bone(midleg_tibia_l_bone_index, midleg_femur_l_bone_index);
  347. ::bone midleg_tibia_r_bone = make_bone(midleg_tibia_r_bone_index, midleg_femur_r_bone_index);
  348. ::bone midleg_tarsus_l_bone = make_bone(midleg_tarsus_l_bone_index, midleg_tibia_l_bone_index);
  349. ::bone midleg_tarsus_r_bone = make_bone(midleg_tarsus_r_bone_index, midleg_tibia_r_bone_index);
  350. ::bone hindleg_coxa_l_bone = make_bone(hindleg_coxa_l_bone_index, mesosoma_bone_index);
  351. ::bone hindleg_coxa_r_bone = make_bone(hindleg_coxa_r_bone_index, mesosoma_bone_index);
  352. ::bone hindleg_femur_l_bone = make_bone(hindleg_femur_l_bone_index, hindleg_coxa_l_bone_index);
  353. ::bone hindleg_femur_r_bone = make_bone(hindleg_femur_r_bone_index, hindleg_coxa_r_bone_index);
  354. ::bone hindleg_tibia_l_bone = make_bone(hindleg_tibia_l_bone_index, hindleg_femur_l_bone_index);
  355. ::bone hindleg_tibia_r_bone = make_bone(hindleg_tibia_r_bone_index, hindleg_femur_r_bone_index);
  356. ::bone hindleg_tarsus_l_bone = make_bone(hindleg_tarsus_l_bone_index, hindleg_tibia_l_bone_index);
  357. ::bone hindleg_tarsus_r_bone = make_bone(hindleg_tarsus_r_bone_index, hindleg_tibia_r_bone_index);
  358. ::bone head_bone = make_bone(head_bone_index, mesosoma_bone_index);
  359. ::bone mandible_l_bone = make_bone(mandible_l_bone_index, head_bone_index);
  360. ::bone mandible_r_bone = make_bone(mandible_r_bone_index, head_bone_index);
  361. ::bone scape_l_bone = make_bone(scape_l_bone_index, head_bone_index);
  362. ::bone scape_r_bone = make_bone(scape_r_bone_index, head_bone_index);
  363. ::bone pedicel_l_bone = make_bone(pedicel_l_bone_index, scape_l_bone_index);
  364. ::bone pedicel_r_bone = make_bone(pedicel_r_bone_index, scape_r_bone_index);
  365. ::bone petiole_bone = make_bone(petiole_bone_index, mesosoma_bone_index);
  366. ::bone postpetiole_bone = make_bone(postpetiole_bone_index, petiole_bone_index);
  367. ::bone gaster_bone = make_bone(gaster_bone_index, (postpetiole) ? postpetiole_bone_index : petiole_bone_index);
  368. ::bone sting_bone = make_bone(sting_bone_index, gaster_bone_index);
  369. // Map bone names to bones
  370. skeleton.bone_map["mesosoma"] = mesosoma_bone;
  371. skeleton.bone_map["foreleg_coxa_l"] = foreleg_coxa_l_bone;
  372. skeleton.bone_map["foreleg_coxa_r"] = foreleg_coxa_r_bone;
  373. skeleton.bone_map["foreleg_femur_l"] = foreleg_femur_l_bone;
  374. skeleton.bone_map["foreleg_femur_r"] = foreleg_femur_r_bone;
  375. skeleton.bone_map["foreleg_tibia_l"] = foreleg_tibia_l_bone;
  376. skeleton.bone_map["foreleg_tibia_r"] = foreleg_tibia_r_bone;
  377. skeleton.bone_map["foreleg_tarsus_l"] = foreleg_tarsus_l_bone;
  378. skeleton.bone_map["foreleg_tarsus_r"] = foreleg_tarsus_r_bone;
  379. skeleton.bone_map["midleg_coxa_l"] = midleg_coxa_l_bone;
  380. skeleton.bone_map["midleg_coxa_r"] = midleg_coxa_r_bone;
  381. skeleton.bone_map["midleg_femur_l"] = midleg_femur_l_bone;
  382. skeleton.bone_map["midleg_femur_r"] = midleg_femur_r_bone;
  383. skeleton.bone_map["midleg_tibia_l"] = midleg_tibia_l_bone;
  384. skeleton.bone_map["midleg_tibia_r"] = midleg_tibia_r_bone;
  385. skeleton.bone_map["midleg_tarsus_l"] = midleg_tarsus_l_bone;
  386. skeleton.bone_map["midleg_tarsus_r"] = midleg_tarsus_r_bone;
  387. skeleton.bone_map["hindleg_coxa_l"] = hindleg_coxa_l_bone;
  388. skeleton.bone_map["hindleg_coxa_r"] = hindleg_coxa_r_bone;
  389. skeleton.bone_map["hindleg_femur_l"] = hindleg_femur_l_bone;
  390. skeleton.bone_map["hindleg_femur_r"] = hindleg_femur_r_bone;
  391. skeleton.bone_map["hindleg_tibia_l"] = hindleg_tibia_l_bone;
  392. skeleton.bone_map["hindleg_tibia_r"] = hindleg_tibia_r_bone;
  393. skeleton.bone_map["hindleg_tarsus_l"] = hindleg_tarsus_l_bone;
  394. skeleton.bone_map["hindleg_tarsus_r"] = hindleg_tarsus_r_bone;
  395. skeleton.bone_map["head"] = head_bone;
  396. skeleton.bone_map["mandible_l"] = mandible_l_bone;
  397. skeleton.bone_map["mandible_r"] = mandible_r_bone;
  398. skeleton.bone_map["scape_l"] = scape_l_bone;
  399. skeleton.bone_map["scape_r"] = scape_r_bone;
  400. skeleton.bone_map["pedicel_l"] = pedicel_l_bone;
  401. skeleton.bone_map["pedicel_r"] = pedicel_r_bone;
  402. skeleton.bone_map["petiole"] = petiole_bone;
  403. if (postpetiole)
  404. skeleton.bone_map["postpetiole"] = postpetiole_bone;
  405. skeleton.bone_map["gaster"] = gaster_bone;
  406. if (sting)
  407. skeleton.bone_map["sting"] = sting_bone;
  408. // Get reference to skeleton bind pose
  409. pose& bind_pose = skeleton.bind_pose;
  410. // Skeleton mesosoma pose
  411. if (auto it = mesosoma_skeleton.bone_map.find("mesosoma"); it != mesosoma_skeleton.bone_map.end())
  412. bind_pose[mesosoma_bone] = mesosoma_skeleton.bind_pose.at(it->second);
  413. // Skeleton forelegs pose
  414. if (auto it = legs_skeleton.bone_map.find("foreleg_coxa_l"); it != legs_skeleton.bone_map.end())
  415. bind_pose[foreleg_coxa_l_bone] = legs_skeleton.bind_pose.at(it->second);
  416. if (auto it = legs_skeleton.bone_map.find("foreleg_coxa_r"); it != legs_skeleton.bone_map.end())
  417. bind_pose[foreleg_coxa_r_bone] = legs_skeleton.bind_pose.at(it->second);
  418. if (auto it = legs_skeleton.bone_map.find("foreleg_femur_l"); it != legs_skeleton.bone_map.end())
  419. bind_pose[foreleg_femur_l_bone] = legs_skeleton.bind_pose.at(it->second);
  420. if (auto it = legs_skeleton.bone_map.find("foreleg_femur_r"); it != legs_skeleton.bone_map.end())
  421. bind_pose[foreleg_femur_r_bone] = legs_skeleton.bind_pose.at(it->second);
  422. if (auto it = legs_skeleton.bone_map.find("foreleg_tibia_l"); it != legs_skeleton.bone_map.end())
  423. bind_pose[foreleg_tibia_l_bone] = legs_skeleton.bind_pose.at(it->second);
  424. if (auto it = legs_skeleton.bone_map.find("foreleg_tibia_r"); it != legs_skeleton.bone_map.end())
  425. bind_pose[foreleg_tibia_r_bone] = legs_skeleton.bind_pose.at(it->second);
  426. if (auto it = legs_skeleton.bone_map.find("foreleg_tarsus1_l"); it != legs_skeleton.bone_map.end())
  427. bind_pose[foreleg_tarsus_l_bone] = legs_skeleton.bind_pose.at(it->second);
  428. if (auto it = legs_skeleton.bone_map.find("foreleg_tarsus1_r"); it != legs_skeleton.bone_map.end())
  429. bind_pose[foreleg_tarsus_r_bone] = legs_skeleton.bind_pose.at(it->second);
  430. // Skeleton midlegs pose
  431. if (auto it = legs_skeleton.bone_map.find("midleg_coxa_l"); it != legs_skeleton.bone_map.end())
  432. bind_pose[midleg_coxa_l_bone] = legs_skeleton.bind_pose.at(it->second);
  433. if (auto it = legs_skeleton.bone_map.find("midleg_coxa_r"); it != legs_skeleton.bone_map.end())
  434. bind_pose[midleg_coxa_r_bone] = legs_skeleton.bind_pose.at(it->second);
  435. if (auto it = legs_skeleton.bone_map.find("midleg_femur_l"); it != legs_skeleton.bone_map.end())
  436. bind_pose[midleg_femur_l_bone] = legs_skeleton.bind_pose.at(it->second);
  437. if (auto it = legs_skeleton.bone_map.find("midleg_femur_r"); it != legs_skeleton.bone_map.end())
  438. bind_pose[midleg_femur_r_bone] = legs_skeleton.bind_pose.at(it->second);
  439. if (auto it = legs_skeleton.bone_map.find("midleg_tibia_l"); it != legs_skeleton.bone_map.end())
  440. bind_pose[midleg_tibia_l_bone] = legs_skeleton.bind_pose.at(it->second);
  441. if (auto it = legs_skeleton.bone_map.find("midleg_tibia_r"); it != legs_skeleton.bone_map.end())
  442. bind_pose[midleg_tibia_r_bone] = legs_skeleton.bind_pose.at(it->second);
  443. if (auto it = legs_skeleton.bone_map.find("midleg_tarsus1_l"); it != legs_skeleton.bone_map.end())
  444. bind_pose[midleg_tarsus_l_bone] = legs_skeleton.bind_pose.at(it->second);
  445. if (auto it = legs_skeleton.bone_map.find("midleg_tarsus1_r"); it != legs_skeleton.bone_map.end())
  446. bind_pose[midleg_tarsus_r_bone] = legs_skeleton.bind_pose.at(it->second);
  447. // Skeleton hindlegs pose
  448. if (auto it = legs_skeleton.bone_map.find("hindleg_coxa_l"); it != legs_skeleton.bone_map.end())
  449. bind_pose[hindleg_coxa_l_bone] = legs_skeleton.bind_pose.at(it->second);
  450. if (auto it = legs_skeleton.bone_map.find("hindleg_coxa_r"); it != legs_skeleton.bone_map.end())
  451. bind_pose[hindleg_coxa_r_bone] = legs_skeleton.bind_pose.at(it->second);
  452. if (auto it = legs_skeleton.bone_map.find("hindleg_femur_l"); it != legs_skeleton.bone_map.end())
  453. bind_pose[hindleg_femur_l_bone] = legs_skeleton.bind_pose.at(it->second);
  454. if (auto it = legs_skeleton.bone_map.find("hindleg_femur_r"); it != legs_skeleton.bone_map.end())
  455. bind_pose[hindleg_femur_r_bone] = legs_skeleton.bind_pose.at(it->second);
  456. if (auto it = legs_skeleton.bone_map.find("hindleg_tibia_l"); it != legs_skeleton.bone_map.end())
  457. bind_pose[hindleg_tibia_l_bone] = legs_skeleton.bind_pose.at(it->second);
  458. if (auto it = legs_skeleton.bone_map.find("hindleg_tibia_r"); it != legs_skeleton.bone_map.end())
  459. bind_pose[hindleg_tibia_r_bone] = legs_skeleton.bind_pose.at(it->second);
  460. if (auto it = legs_skeleton.bone_map.find("hindleg_tarsus1_l"); it != legs_skeleton.bone_map.end())
  461. bind_pose[hindleg_tarsus_l_bone] = legs_skeleton.bind_pose.at(it->second);
  462. if (auto it = legs_skeleton.bone_map.find("hindleg_tarsus1_r"); it != legs_skeleton.bone_map.end())
  463. bind_pose[hindleg_tarsus_r_bone] = legs_skeleton.bind_pose.at(it->second);
  464. // Skeleton head pose
  465. bind_pose[head_bone] = mesosoma_skeleton.bind_pose.at(mesosoma_skeleton.bone_map.at("head")) * head_skeleton.bind_pose.at(head_skeleton.bone_map.at("head"));
  466. // Skeleton mandibles pose
  467. bind_pose[mandible_l_bone] = head_skeleton.bind_pose.at(head_skeleton.bone_map.at("mandible_l")) * mandibles_skeleton.bind_pose.at(mandibles_skeleton.bone_map.at("mandible_l"));
  468. bind_pose[mandible_r_bone] = head_skeleton.bind_pose.at(head_skeleton.bone_map.at("mandible_r")) * mandibles_skeleton.bind_pose.at(mandibles_skeleton.bone_map.at("mandible_r"));
  469. // Skeleton antennae pose
  470. bind_pose[scape_l_bone] = head_skeleton.bind_pose.at(head_skeleton.bone_map.at("scape_l")) * antennae_skeleton.bind_pose.at(antennae_skeleton.bone_map.at("scape_l"));
  471. bind_pose[scape_r_bone] = head_skeleton.bind_pose.at(head_skeleton.bone_map.at("scape_r")) * antennae_skeleton.bind_pose.at(antennae_skeleton.bone_map.at("scape_r"));
  472. bind_pose[pedicel_l_bone] = antennae_skeleton.bind_pose.at(antennae_skeleton.bone_map.at("pedicel_l"));
  473. bind_pose[pedicel_r_bone] = antennae_skeleton.bind_pose.at(antennae_skeleton.bone_map.at("pedicel_r"));
  474. // Skeleton waist pose
  475. bind_pose[petiole_bone] = mesosoma_skeleton.bind_pose.at(mesosoma_skeleton.bone_map.at("petiole")) * waist_skeleton.bind_pose.at(waist_skeleton.bone_map.at("petiole"));
  476. if (postpetiole)
  477. {
  478. bind_pose[postpetiole_bone] = waist_skeleton.bind_pose.at(waist_skeleton.bone_map.at("postpetiole"));
  479. }
  480. // Skeleton gaster pose
  481. if (postpetiole)
  482. {
  483. bind_pose[gaster_bone] = waist_skeleton.bind_pose.at(waist_skeleton.bone_map.at("postpetiole")) * gaster_skeleton.bind_pose.at(gaster_skeleton.bone_map.at("gaster"));
  484. }
  485. else
  486. {
  487. bind_pose[gaster_bone] = waist_skeleton.bind_pose.at(waist_skeleton.bone_map.at("petiole")) * gaster_skeleton.bind_pose.at(gaster_skeleton.bone_map.at("gaster"));
  488. }
  489. // Skeleton sting pose
  490. if (sting)
  491. {
  492. bind_pose[sting_bone] = gaster_skeleton.bind_pose.at(gaster_skeleton.bone_map.at("sting")) * sting_skeleton->bind_pose.at(sting_skeleton->bone_map.at("sting"));
  493. }
  494. // Calculate the skeleton-space bind pose
  495. pose bind_pose_ss;
  496. ::concatenate(bind_pose, bind_pose_ss);
  497. // Calculate inverse skeleton-space bind pose
  498. ::inverse(bind_pose_ss, skeleton.inverse_bind_pose);
  499. // Get number of vertex indices for each body part
  500. std::size_t mesosoma_index_count = (*mesosoma->get_groups())[0]->get_index_count();
  501. std::size_t legs_index_count = (*legs->get_groups())[0]->get_index_count();
  502. std::size_t head_index_count = (*head->get_groups())[0]->get_index_count();
  503. std::size_t mandibles_index_count = (*mandibles->get_groups())[0]->get_index_count();
  504. std::size_t antennae_index_count = (*antennae->get_groups())[0]->get_index_count();
  505. std::size_t waist_index_count = (*waist->get_groups())[0]->get_index_count();
  506. std::size_t gaster_index_count = (*gaster->get_groups())[0]->get_index_count();
  507. std::size_t sting_index_count = (sting) ? (*sting->get_groups())[0]->get_index_count() : 0;
  508. std::size_t eyes_index_count = (eyes) ? (*eyes->get_groups())[0]->get_index_count() : 0;
  509. std::size_t lateral_ocelli_index_count = (lateral_ocelli) ? (*lateral_ocelli->get_groups())[0]->get_index_count() : 0;
  510. std::size_t median_ocellus_index_count = (median_ocellus) ? (*median_ocellus->get_groups())[0]->get_index_count() : 0;
  511. std::size_t forewings_index_count = (forewings) ? (*forewings->get_groups())[0]->get_index_count() : 0;
  512. std::size_t hindwings_index_count = (hindwings) ? (*hindwings->get_groups())[0]->get_index_count() : 0;
  513. std::size_t exoskeleton_index_count =
  514. mesosoma_index_count
  515. + legs_index_count
  516. + head_index_count
  517. + mandibles_index_count
  518. + antennae_index_count
  519. + waist_index_count
  520. + gaster_index_count
  521. + sting_index_count;
  522. // Calculate transform from legs space to body space
  523. const math::transform<float>& legs_to_body = math::transform<float>::identity;
  524. // Reskin leg bones
  525. std::unordered_set<std::uint8_t> old_foreleg_coxa_l_indices;
  526. if (auto it = legs_skeleton.bone_map.find("foreleg_coxa_l"); it != legs_skeleton.bone_map.end())
  527. old_foreleg_coxa_l_indices.emplace(it->second);
  528. reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_foreleg_coxa_l_indices, foreleg_coxa_l_bone_index, legs_to_body);
  529. std::unordered_set<std::uint8_t> old_foreleg_femur_l_indices;
  530. if (auto it = legs_skeleton.bone_map.find("foreleg_femur_l"); it != legs_skeleton.bone_map.end())
  531. old_foreleg_femur_l_indices.emplace(it->second);
  532. reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_foreleg_femur_l_indices, foreleg_femur_l_bone_index, legs_to_body);
  533. std::unordered_set<std::uint8_t> old_foreleg_tibia_l_indices;
  534. if (auto it = legs_skeleton.bone_map.find("foreleg_tibia_l"); it != legs_skeleton.bone_map.end())
  535. old_foreleg_tibia_l_indices.emplace(it->second);
  536. reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_foreleg_tibia_l_indices, foreleg_tibia_l_bone_index, legs_to_body);
  537. std::unordered_set<std::uint8_t> old_foreleg_tarsus_l_indices;
  538. if (auto it = legs_skeleton.bone_map.find("foreleg_tarsus1_l"); it != legs_skeleton.bone_map.end())
  539. old_foreleg_tarsus_l_indices.emplace(it->second);
  540. if (auto it = legs_skeleton.bone_map.find("foreleg_tarsus2_l"); it != legs_skeleton.bone_map.end())
  541. old_foreleg_tarsus_l_indices.emplace(it->second);
  542. if (auto it = legs_skeleton.bone_map.find("foreleg_tarsus3_l"); it != legs_skeleton.bone_map.end())
  543. old_foreleg_tarsus_l_indices.emplace(it->second);
  544. if (auto it = legs_skeleton.bone_map.find("foreleg_tarsus4_l"); it != legs_skeleton.bone_map.end())
  545. old_foreleg_tarsus_l_indices.emplace(it->second);
  546. if (auto it = legs_skeleton.bone_map.find("foreleg_tarsus5_l"); it != legs_skeleton.bone_map.end())
  547. old_foreleg_tarsus_l_indices.emplace(it->second);
  548. reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_foreleg_tarsus_l_indices, foreleg_tarsus_l_bone_index, legs_to_body);
  549. std::unordered_set<std::uint8_t> old_foreleg_coxa_r_indices;
  550. if (auto it = legs_skeleton.bone_map.find("foreleg_coxa_r"); it != legs_skeleton.bone_map.end())
  551. old_foreleg_coxa_r_indices.emplace(it->second);
  552. reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_foreleg_coxa_r_indices, foreleg_coxa_r_bone_index, legs_to_body);
  553. std::unordered_set<std::uint8_t> old_foreleg_femur_r_indices;
  554. if (auto it = legs_skeleton.bone_map.find("foreleg_femur_r"); it != legs_skeleton.bone_map.end())
  555. old_foreleg_femur_r_indices.emplace(it->second);
  556. reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_foreleg_femur_r_indices, foreleg_femur_r_bone_index, legs_to_body);
  557. std::unordered_set<std::uint8_t> old_foreleg_tibia_r_indices;
  558. if (auto it = legs_skeleton.bone_map.find("foreleg_tibia_r"); it != legs_skeleton.bone_map.end())
  559. old_foreleg_tibia_r_indices.emplace(it->second);
  560. reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_foreleg_tibia_r_indices, foreleg_tibia_r_bone_index, legs_to_body);
  561. std::unordered_set<std::uint8_t> old_foreleg_tarsus_r_indices;
  562. if (auto it = legs_skeleton.bone_map.find("foreleg_tarsus1_r"); it != legs_skeleton.bone_map.end())
  563. old_foreleg_tarsus_r_indices.emplace(it->second);
  564. if (auto it = legs_skeleton.bone_map.find("foreleg_tarsus2_r"); it != legs_skeleton.bone_map.end())
  565. old_foreleg_tarsus_r_indices.emplace(it->second);
  566. if (auto it = legs_skeleton.bone_map.find("foreleg_tarsus3_r"); it != legs_skeleton.bone_map.end())
  567. old_foreleg_tarsus_r_indices.emplace(it->second);
  568. if (auto it = legs_skeleton.bone_map.find("foreleg_tarsus4_r"); it != legs_skeleton.bone_map.end())
  569. old_foreleg_tarsus_r_indices.emplace(it->second);
  570. if (auto it = legs_skeleton.bone_map.find("foreleg_tarsus5_r"); it != legs_skeleton.bone_map.end())
  571. old_foreleg_tarsus_r_indices.emplace(it->second);
  572. reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_foreleg_tarsus_r_indices, foreleg_tarsus_r_bone_index, legs_to_body);
  573. std::unordered_set<std::uint8_t> old_midleg_coxa_l_indices;
  574. if (auto it = legs_skeleton.bone_map.find("midleg_coxa_l"); it != legs_skeleton.bone_map.end())
  575. old_midleg_coxa_l_indices.emplace(it->second);
  576. reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_midleg_coxa_l_indices, midleg_coxa_l_bone_index, legs_to_body);
  577. std::unordered_set<std::uint8_t> old_midleg_femur_l_indices;
  578. if (auto it = legs_skeleton.bone_map.find("midleg_femur_l"); it != legs_skeleton.bone_map.end())
  579. old_midleg_femur_l_indices.emplace(it->second);
  580. reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_midleg_femur_l_indices, midleg_femur_l_bone_index, legs_to_body);
  581. std::unordered_set<std::uint8_t> old_midleg_tibia_l_indices;
  582. if (auto it = legs_skeleton.bone_map.find("midleg_tibia_l"); it != legs_skeleton.bone_map.end())
  583. old_midleg_tibia_l_indices.emplace(it->second);
  584. reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_midleg_tibia_l_indices, midleg_tibia_l_bone_index, legs_to_body);
  585. std::unordered_set<std::uint8_t> old_midleg_tarsus_l_indices;
  586. if (auto it = legs_skeleton.bone_map.find("midleg_tarsus1_l"); it != legs_skeleton.bone_map.end())
  587. old_midleg_tarsus_l_indices.emplace(it->second);
  588. if (auto it = legs_skeleton.bone_map.find("midleg_tarsus2_l"); it != legs_skeleton.bone_map.end())
  589. old_midleg_tarsus_l_indices.emplace(it->second);
  590. if (auto it = legs_skeleton.bone_map.find("midleg_tarsus3_l"); it != legs_skeleton.bone_map.end())
  591. old_midleg_tarsus_l_indices.emplace(it->second);
  592. if (auto it = legs_skeleton.bone_map.find("midleg_tarsus4_l"); it != legs_skeleton.bone_map.end())
  593. old_midleg_tarsus_l_indices.emplace(it->second);
  594. if (auto it = legs_skeleton.bone_map.find("midleg_tarsus5_l"); it != legs_skeleton.bone_map.end())
  595. old_midleg_tarsus_l_indices.emplace(it->second);
  596. reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_midleg_tarsus_l_indices, midleg_tarsus_l_bone_index, legs_to_body);
  597. std::unordered_set<std::uint8_t> old_midleg_coxa_r_indices;
  598. if (auto it = legs_skeleton.bone_map.find("midleg_coxa_r"); it != legs_skeleton.bone_map.end())
  599. old_midleg_coxa_r_indices.emplace(it->second);
  600. reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_midleg_coxa_r_indices, midleg_coxa_r_bone_index, legs_to_body);
  601. std::unordered_set<std::uint8_t> old_midleg_femur_r_indices;
  602. if (auto it = legs_skeleton.bone_map.find("midleg_femur_r"); it != legs_skeleton.bone_map.end())
  603. old_midleg_femur_r_indices.emplace(it->second);
  604. reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_midleg_femur_r_indices, midleg_femur_r_bone_index, legs_to_body);
  605. std::unordered_set<std::uint8_t> old_midleg_tibia_r_indices;
  606. if (auto it = legs_skeleton.bone_map.find("midleg_tibia_r"); it != legs_skeleton.bone_map.end())
  607. old_midleg_tibia_r_indices.emplace(it->second);
  608. reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_midleg_tibia_r_indices, midleg_tibia_r_bone_index, legs_to_body);
  609. std::unordered_set<std::uint8_t> old_midleg_tarsus_r_indices;
  610. if (auto it = legs_skeleton.bone_map.find("midleg_tarsus1_r"); it != legs_skeleton.bone_map.end())
  611. old_midleg_tarsus_r_indices.emplace(it->second);
  612. if (auto it = legs_skeleton.bone_map.find("midleg_tarsus2_r"); it != legs_skeleton.bone_map.end())
  613. old_midleg_tarsus_r_indices.emplace(it->second);
  614. if (auto it = legs_skeleton.bone_map.find("midleg_tarsus3_r"); it != legs_skeleton.bone_map.end())
  615. old_midleg_tarsus_r_indices.emplace(it->second);
  616. if (auto it = legs_skeleton.bone_map.find("midleg_tarsus4_r"); it != legs_skeleton.bone_map.end())
  617. old_midleg_tarsus_r_indices.emplace(it->second);
  618. if (auto it = legs_skeleton.bone_map.find("midleg_tarsus5_r"); it != legs_skeleton.bone_map.end())
  619. old_midleg_tarsus_r_indices.emplace(it->second);
  620. reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_midleg_tarsus_r_indices, midleg_tarsus_r_bone_index, legs_to_body);
  621. std::unordered_set<std::uint8_t> old_hindleg_coxa_l_indices;
  622. if (auto it = legs_skeleton.bone_map.find("hindleg_coxa_l"); it != legs_skeleton.bone_map.end())
  623. old_hindleg_coxa_l_indices.emplace(it->second);
  624. reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_hindleg_coxa_l_indices, hindleg_coxa_l_bone_index, legs_to_body);
  625. std::unordered_set<std::uint8_t> old_hindleg_femur_l_indices;
  626. if (auto it = legs_skeleton.bone_map.find("hindleg_femur_l"); it != legs_skeleton.bone_map.end())
  627. old_hindleg_femur_l_indices.emplace(it->second);
  628. reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_hindleg_femur_l_indices, hindleg_femur_l_bone_index, legs_to_body);
  629. std::unordered_set<std::uint8_t> old_hindleg_tibia_l_indices;
  630. if (auto it = legs_skeleton.bone_map.find("hindleg_tibia_l"); it != legs_skeleton.bone_map.end())
  631. old_hindleg_tibia_l_indices.emplace(it->second);
  632. reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_hindleg_tibia_l_indices, hindleg_tibia_l_bone_index, legs_to_body);
  633. std::unordered_set<std::uint8_t> old_hindleg_tarsus_l_indices;
  634. if (auto it = legs_skeleton.bone_map.find("hindleg_tarsus1_l"); it != legs_skeleton.bone_map.end())
  635. old_hindleg_tarsus_l_indices.emplace(it->second);
  636. if (auto it = legs_skeleton.bone_map.find("hindleg_tarsus2_l"); it != legs_skeleton.bone_map.end())
  637. old_hindleg_tarsus_l_indices.emplace(it->second);
  638. if (auto it = legs_skeleton.bone_map.find("hindleg_tarsus3_l"); it != legs_skeleton.bone_map.end())
  639. old_hindleg_tarsus_l_indices.emplace(it->second);
  640. if (auto it = legs_skeleton.bone_map.find("hindleg_tarsus4_l"); it != legs_skeleton.bone_map.end())
  641. old_hindleg_tarsus_l_indices.emplace(it->second);
  642. if (auto it = legs_skeleton.bone_map.find("hindleg_tarsus5_l"); it != legs_skeleton.bone_map.end())
  643. old_hindleg_tarsus_l_indices.emplace(it->second);
  644. reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_hindleg_tarsus_l_indices, hindleg_tarsus_l_bone_index, legs_to_body);
  645. std::unordered_set<std::uint8_t> old_hindleg_coxa_r_indices;
  646. if (auto it = legs_skeleton.bone_map.find("hindleg_coxa_r"); it != legs_skeleton.bone_map.end())
  647. old_hindleg_coxa_r_indices.emplace(it->second);
  648. reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_hindleg_coxa_r_indices, hindleg_coxa_r_bone_index, legs_to_body);
  649. std::unordered_set<std::uint8_t> old_hindleg_femur_r_indices;
  650. if (auto it = legs_skeleton.bone_map.find("hindleg_femur_r"); it != legs_skeleton.bone_map.end())
  651. old_hindleg_femur_r_indices.emplace(it->second);
  652. reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_hindleg_femur_r_indices, hindleg_femur_r_bone_index, legs_to_body);
  653. std::unordered_set<std::uint8_t> old_hindleg_tibia_r_indices;
  654. if (auto it = legs_skeleton.bone_map.find("hindleg_tibia_r"); it != legs_skeleton.bone_map.end())
  655. old_hindleg_tibia_r_indices.emplace(it->second);
  656. reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_hindleg_tibia_r_indices, hindleg_tibia_r_bone_index, legs_to_body);
  657. std::unordered_set<std::uint8_t> old_hindleg_tarsus_r_indices;
  658. if (auto it = legs_skeleton.bone_map.find("hindleg_tarsus1_r"); it != legs_skeleton.bone_map.end())
  659. old_hindleg_tarsus_r_indices.emplace(it->second);
  660. if (auto it = legs_skeleton.bone_map.find("hindleg_tarsus2_r"); it != legs_skeleton.bone_map.end())
  661. old_hindleg_tarsus_r_indices.emplace(it->second);
  662. if (auto it = legs_skeleton.bone_map.find("hindleg_tarsus3_r"); it != legs_skeleton.bone_map.end())
  663. old_hindleg_tarsus_r_indices.emplace(it->second);
  664. if (auto it = legs_skeleton.bone_map.find("hindleg_tarsus4_r"); it != legs_skeleton.bone_map.end())
  665. old_hindleg_tarsus_r_indices.emplace(it->second);
  666. if (auto it = legs_skeleton.bone_map.find("hindleg_tarsus5_r"); it != legs_skeleton.bone_map.end())
  667. old_hindleg_tarsus_r_indices.emplace(it->second);
  668. reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_hindleg_tarsus_r_indices, hindleg_tarsus_r_bone_index, legs_to_body);
  669. // Calculate transform from head space to body space
  670. math::transform<float> head_to_body = bind_pose_ss.at(mesosoma_bone) * mesosoma_skeleton.bind_pose.at(mesosoma_skeleton.bone_map.at("head"));
  671. // Reskin head bone
  672. std::unordered_set<std::uint8_t> old_head_bone_indices;
  673. if (auto it = head_skeleton.bone_map.find("head"); it != head_skeleton.bone_map.end())
  674. old_head_bone_indices.emplace(it->second);
  675. reskin_vertices(vertex_buffer_data + head_vbo_offset, head_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_head_bone_indices, head_bone_index, head_to_body);
  676. // Calculate transforms from mandibles space to body space
  677. math::transform<float> mandible_l_to_body = bind_pose_ss.at(head_bone) * head_skeleton.bind_pose.at(head_skeleton.bone_map.at("mandible_l"));
  678. math::transform<float> mandible_r_to_body = bind_pose_ss.at(head_bone) * head_skeleton.bind_pose.at(head_skeleton.bone_map.at("mandible_r"));
  679. // Reskin mandible bones
  680. std::unordered_set<std::uint8_t> old_head_mandible_l_bone_indices;
  681. if (auto it = mandibles_skeleton.bone_map.find("mandible_l"); it != mandibles_skeleton.bone_map.end())
  682. old_head_mandible_l_bone_indices.emplace(it->second);
  683. reskin_vertices(vertex_buffer_data + mandibles_vbo_offset, mandibles_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_head_mandible_l_bone_indices, mandible_l_bone_index, mandible_l_to_body);
  684. std::unordered_set<std::uint8_t> old_head_mandible_r_bone_indices;
  685. if (auto it = mandibles_skeleton.bone_map.find("mandible_r"); it != mandibles_skeleton.bone_map.end())
  686. old_head_mandible_r_bone_indices.emplace(it->second);
  687. reskin_vertices(vertex_buffer_data + mandibles_vbo_offset, mandibles_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_head_mandible_r_bone_indices, mandible_r_bone_index, mandible_r_to_body);
  688. // Calculate transforms from antennae space to body space
  689. math::transform<float> antenna_l_to_body = bind_pose_ss.at(head_bone) * head_skeleton.bind_pose.at(head_skeleton.bone_map.at("scape_l"));
  690. math::transform<float> antenna_r_to_body = bind_pose_ss.at(head_bone) * head_skeleton.bind_pose.at(head_skeleton.bone_map.at("scape_r"));
  691. // Reskin scape bones
  692. std::unordered_set<std::uint8_t> old_scape_l_indices;
  693. if (auto it = antennae_skeleton.bone_map.find("scape_l"); it != antennae_skeleton.bone_map.end())
  694. old_scape_l_indices.emplace(it->second);
  695. reskin_vertices(vertex_buffer_data + antennae_vbo_offset, antennae_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_scape_l_indices, scape_l_bone_index, antenna_l_to_body);
  696. std::unordered_set<std::uint8_t> old_scape_r_indices;
  697. if (auto it = antennae_skeleton.bone_map.find("scape_r"); it != antennae_skeleton.bone_map.end())
  698. old_scape_r_indices.emplace(it->second);
  699. reskin_vertices(vertex_buffer_data + antennae_vbo_offset, antennae_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_scape_r_indices, scape_r_bone_index, antenna_r_to_body);
  700. // Reskin pedicel bones
  701. const std::vector<std::string> pedicel_bone_names =
  702. {
  703. "pedicel",
  704. "flagellomere_1",
  705. "flagellomere_2",
  706. "flagellomere_3",
  707. "flagellomere_4",
  708. "flagellomere_5",
  709. "flagellomere_6",
  710. "flagellomere_7",
  711. "flagellomere_8",
  712. "flagellomere_9",
  713. "flagellomere_10",
  714. "flagellomere_11",
  715. "flagellomere_12"
  716. };
  717. std::unordered_set<std::uint8_t> old_pedicel_l_indices;
  718. for (const std::string& bone_name: pedicel_bone_names)
  719. if (auto it = antennae_skeleton.bone_map.find(bone_name + "_l"); it != antennae_skeleton.bone_map.end())
  720. old_pedicel_l_indices.emplace(it->second);
  721. reskin_vertices(vertex_buffer_data + antennae_vbo_offset, antennae_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_pedicel_l_indices, pedicel_l_bone_index, antenna_l_to_body);
  722. std::unordered_set<std::uint8_t> old_pedicel_r_indices;
  723. for (const std::string& bone_name: pedicel_bone_names)
  724. if (auto it = antennae_skeleton.bone_map.find(bone_name + "_r"); it != antennae_skeleton.bone_map.end())
  725. old_pedicel_r_indices.emplace(it->second);
  726. reskin_vertices(vertex_buffer_data + antennae_vbo_offset, antennae_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_pedicel_r_indices, pedicel_r_bone_index, antenna_r_to_body);
  727. // Calculate transform from waist space to body space
  728. math::transform<float> waist_to_body = bind_pose_ss.at(mesosoma_bone) * mesosoma_skeleton.bind_pose.at(mesosoma_skeleton.bone_map.at("petiole"));
  729. // Reskin waist bones
  730. std::unordered_set<std::uint8_t> old_petiole_bone_indices;
  731. if (auto it = waist_skeleton.bone_map.find("petiole"); it != waist_skeleton.bone_map.end())
  732. old_petiole_bone_indices.emplace(it->second);
  733. reskin_vertices(vertex_buffer_data + waist_vbo_offset, waist_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_petiole_bone_indices, petiole_bone_index, waist_to_body);
  734. if (postpetiole)
  735. {
  736. std::unordered_set<std::uint8_t> old_postpetiole_bone_indices;
  737. if (auto it = waist_skeleton.bone_map.find("postpetiole"); it != waist_skeleton.bone_map.end())
  738. old_postpetiole_bone_indices.emplace(it->second);
  739. reskin_vertices(vertex_buffer_data + waist_vbo_offset, waist_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_postpetiole_bone_indices, postpetiole_bone_index, waist_to_body);
  740. }
  741. // Calculate transform from gaster space to body space
  742. math::transform<float> gaster_to_body = bind_pose_ss.at(bone_parent_index(gaster_bone)) * waist_skeleton.bind_pose.at(waist_skeleton.bone_map.at("gaster"));
  743. // Reskin gaster bones
  744. std::unordered_set<std::uint8_t> old_gaster_bone_indices;
  745. if (auto it = gaster_skeleton.bone_map.find("gaster"); it != gaster_skeleton.bone_map.end())
  746. old_gaster_bone_indices.emplace(it->second);
  747. reskin_vertices(vertex_buffer_data + gaster_vbo_offset, gaster_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_gaster_bone_indices, gaster_bone_index, gaster_to_body);
  748. if (sting)
  749. {
  750. // Calculate transform from sting space to body space
  751. math::transform<float> sting_to_body = bind_pose_ss.at(gaster_bone) * gaster_skeleton.bind_pose.at(gaster_skeleton.bone_map.at("sting"));
  752. // Reskin sting bones
  753. std::unordered_set<std::uint8_t> old_sting_bone_indices;
  754. if (auto it = sting_skeleton->bone_map.find("sting"); it != sting_skeleton->bone_map.end())
  755. old_sting_bone_indices.emplace(it->second);
  756. reskin_vertices(vertex_buffer_data + sting_vbo_offset, sting_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_sting_bone_indices, sting_bone_index, sting_to_body);
  757. }
  758. if (eyes)
  759. {
  760. // Calculate transforms from eyes space to body space
  761. math::transform<float> eye_l_to_body = bind_pose_ss.at(head_bone) * head_skeleton.bind_pose.at(head_skeleton.bone_map.at("eye_l"));
  762. math::transform<float> eye_r_to_body = bind_pose_ss.at(head_bone) * head_skeleton.bind_pose.at(head_skeleton.bone_map.at("eye_r"));
  763. // Reskin eye bones
  764. std::unordered_set<std::uint8_t> old_eye_l_bone_indices;
  765. if (auto it = eyes_skeleton->bone_map.find("eye_l"); it != eyes_skeleton->bone_map.end())
  766. old_eye_l_bone_indices.emplace(it->second);
  767. reskin_vertices(vertex_buffer_data + eyes_vbo_offset, eyes_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_eye_l_bone_indices, head_bone_index, eye_l_to_body);
  768. std::unordered_set<std::uint8_t> old_eye_r_bone_indices;
  769. if (auto it = eyes_skeleton->bone_map.find("eye_r"); it != eyes_skeleton->bone_map.end())
  770. old_eye_r_bone_indices.emplace(it->second);
  771. reskin_vertices(vertex_buffer_data + eyes_vbo_offset, eyes_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_eye_r_bone_indices, head_bone_index, eye_r_to_body);
  772. }
  773. if (lateral_ocelli)
  774. {
  775. // Calculate transforms from lateral ocelli space to body space
  776. math::transform<float> ocellus_l_to_body = bind_pose_ss.at(head_bone) * head_skeleton.bind_pose.at(head_skeleton.bone_map.at("ocellus_l"));
  777. math::transform<float> ocellus_r_to_body = bind_pose_ss.at(head_bone) * head_skeleton.bind_pose.at(head_skeleton.bone_map.at("ocellus_r"));
  778. // Reskin lateral ocelli bones
  779. std::unordered_set<std::uint8_t> old_ocellus_l_bone_indices;
  780. if (auto it = lateral_ocelli_skeleton->bone_map.find("ocellus_l"); it != lateral_ocelli_skeleton->bone_map.end())
  781. old_ocellus_l_bone_indices.emplace(it->second);
  782. reskin_vertices(vertex_buffer_data + lateral_ocelli_vbo_offset, lateral_ocelli_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_ocellus_l_bone_indices, head_bone_index, ocellus_l_to_body);
  783. std::unordered_set<std::uint8_t> old_ocellus_r_bone_indices;
  784. if (auto it = lateral_ocelli_skeleton->bone_map.find("ocellus_r"); it != lateral_ocelli_skeleton->bone_map.end())
  785. old_ocellus_r_bone_indices.emplace(it->second);
  786. reskin_vertices(vertex_buffer_data + lateral_ocelli_vbo_offset, lateral_ocelli_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_ocellus_r_bone_indices, head_bone_index, ocellus_r_to_body);
  787. }
  788. if (median_ocellus)
  789. {
  790. // Calculate transforms from lateral ocelli space to body space
  791. math::transform<float> ocellus_m_to_body = bind_pose_ss.at(head_bone) * head_skeleton.bind_pose.at(head_skeleton.bone_map.at("ocellus_m"));
  792. // Reskin lateral ocelli bones
  793. std::unordered_set<std::uint8_t> old_ocellus_m_bone_indices;
  794. if (auto it = median_ocellus_skeleton->bone_map.find("ocellus_m"); it != median_ocellus_skeleton->bone_map.end())
  795. old_ocellus_m_bone_indices.emplace(it->second);
  796. reskin_vertices(vertex_buffer_data + median_ocellus_vbo_offset, median_ocellus_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_ocellus_m_bone_indices, head_bone_index, ocellus_m_to_body);
  797. }
  798. // Upload vertex buffer data to model VBO
  799. model->get_vertex_buffer()->repurpose(gl::buffer_usage::static_draw, vertex_buffer_size, vertex_buffer_data);
  800. // Construct exoskeleton model group
  801. render::model_group* exoskeleton_group = model->add_group("exoskeleton");
  802. exoskeleton_group->set_material(exoskeleton_material);
  803. exoskeleton_group->set_drawing_mode(gl::drawing_mode::triangles);
  804. exoskeleton_group->set_start_index(0);
  805. exoskeleton_group->set_index_count(exoskeleton_index_count);
  806. std::size_t index_offset = exoskeleton_index_count;
  807. if (eyes)
  808. {
  809. // Construct eyes model group
  810. render::model_group* eyes_group = model->add_group("eyes");
  811. eyes_group->set_material((*eyes->get_groups())[0]->get_material());
  812. eyes_group->set_drawing_mode(gl::drawing_mode::triangles);
  813. eyes_group->set_start_index(index_offset);
  814. eyes_group->set_index_count(eyes_index_count);
  815. index_offset += eyes_index_count;
  816. }
  817. if (lateral_ocelli || median_ocellus)
  818. {
  819. // Construct ocelli model group
  820. render::model_group* ocelli_group = model->add_group("ocelli");
  821. ocelli_group->set_drawing_mode(gl::drawing_mode::triangles);
  822. ocelli_group->set_start_index(index_offset);
  823. std::size_t index_count = 0;
  824. if (lateral_ocelli)
  825. {
  826. index_count += lateral_ocelli_index_count;
  827. index_offset += lateral_ocelli_index_count;
  828. ocelli_group->set_material((*lateral_ocelli->get_groups())[0]->get_material());
  829. }
  830. if (median_ocellus)
  831. {
  832. index_count += median_ocellus_index_count;
  833. index_offset += median_ocellus_index_count;
  834. if (!lateral_ocelli)
  835. ocelli_group->set_material((*median_ocellus->get_groups())[0]->get_material());
  836. }
  837. ocelli_group->set_index_count(index_count);
  838. }
  839. if (forewings)
  840. {
  841. // Construct forewings model group
  842. render::model_group* forewings_group = model->add_group("forewings");
  843. forewings_group->set_material((*forewings->get_groups())[0]->get_material());
  844. forewings_group->set_drawing_mode(gl::drawing_mode::triangles);
  845. forewings_group->set_start_index(index_offset);
  846. forewings_group->set_index_count(forewings_index_count);
  847. index_offset += forewings_index_count;
  848. }
  849. if (hindwings)
  850. {
  851. // Construct hindwings model group
  852. render::model_group* hindwings_group = model->add_group("hindwings");
  853. hindwings_group->set_material((*hindwings->get_groups())[0]->get_material());
  854. hindwings_group->set_drawing_mode(gl::drawing_mode::triangles);
  855. hindwings_group->set_start_index(index_offset);
  856. hindwings_group->set_index_count(hindwings_index_count);
  857. index_offset += hindwings_index_count;
  858. }
  859. // Calculate model bounding box
  860. geom::aabb<float> bounds = calculate_bounds(vertex_buffer_data, index_offset, *position_attribute);
  861. model->set_bounds(bounds);
  862. // Free vertex buffer data
  863. delete[] vertex_buffer_data;
  864. return model;
  865. }
  866. void reskin_vertices
  867. (
  868. std::uint8_t* vertex_data,
  869. std::size_t index_count,
  870. const gl::vertex_attribute& position_attribute,
  871. const gl::vertex_attribute& normal_attribute,
  872. const gl::vertex_attribute& tangent_attribute,
  873. const gl::vertex_attribute& bone_index_attribute,
  874. const std::unordered_set<std::uint8_t>& old_bone_indices,
  875. std::uint8_t new_bone_index,
  876. const math::transform<float>& transform
  877. )
  878. {
  879. std::uint8_t* position_data = vertex_data + position_attribute.offset;
  880. std::uint8_t* normal_data = vertex_data + normal_attribute.offset;
  881. std::uint8_t* tangent_data = vertex_data + tangent_attribute.offset;
  882. std::uint8_t* bone_index_data = vertex_data + bone_index_attribute.offset;
  883. for (std::size_t i = 0; i < index_count; ++i)
  884. {
  885. // Get bone index of current vertex
  886. float* bone_index = reinterpret_cast<float*>(bone_index_data + bone_index_attribute.stride * i);
  887. // Skip irrelevant bones
  888. if (!old_bone_indices.count(static_cast<std::uint8_t>(*bone_index + 0.5f)))
  889. continue;
  890. // Get vertex position
  891. float* x = reinterpret_cast<float*>(position_data + position_attribute.stride * i);
  892. float* y = x + 1;
  893. float* z = y + 1;
  894. // Get vertex normal
  895. float* nx = reinterpret_cast<float*>(normal_data + normal_attribute.stride * i);
  896. float* ny = nx + 1;
  897. float* nz = ny + 1;
  898. // Get vertex tangent
  899. float* tx = reinterpret_cast<float*>(tangent_data + tangent_attribute.stride * i);
  900. float* ty = tx + 1;
  901. float* tz = ty + 1;
  902. //float* bts = tz + 1;
  903. // Transform vertex attributes
  904. float3 position = transform * float3{*x, *y, *z};
  905. float3 normal = math::normalize(transform.rotation * float3{*nx, *ny, *nz});
  906. float3 tangent = transform.rotation * float3{*tx, *ty, *tz};
  907. // Update vertex data
  908. *x = position.x();
  909. *y = position.y();
  910. *z = position.z();
  911. *nx = normal.x();
  912. *ny = normal.y();
  913. *nz = normal.z();
  914. *tx = tangent.x();
  915. *ty = tangent.y();
  916. *tz = tangent.z();
  917. //*bts = ...
  918. *bone_index = static_cast<float>(new_bone_index);
  919. }
  920. }
  921. geom::aabb<float> calculate_bounds(std::uint8_t* vertex_data, std::size_t index_count, const gl::vertex_attribute& position_attribute)
  922. {
  923. std::uint8_t* position_data = vertex_data + position_attribute.offset;
  924. geom::aabb<float> bounds;
  925. bounds.min_point.x() = std::numeric_limits<float>::infinity();
  926. bounds.min_point.y() = std::numeric_limits<float>::infinity();
  927. bounds.min_point.z() = std::numeric_limits<float>::infinity();
  928. bounds.max_point.x() = -std::numeric_limits<float>::infinity();
  929. bounds.max_point.y() = -std::numeric_limits<float>::infinity();
  930. bounds.max_point.z() = -std::numeric_limits<float>::infinity();
  931. for (std::size_t i = 0; i < index_count; ++i)
  932. {
  933. // Get vertex position
  934. float* x = reinterpret_cast<float*>(position_data + position_attribute.stride * i);
  935. float* y = x + 1;
  936. float* z = y + 1;
  937. bounds.min_point.x() = std::min<float>(*x, bounds.min_point.x());
  938. bounds.min_point.y() = std::min<float>(*y, bounds.min_point.y());
  939. bounds.min_point.z() = std::min<float>(*z, bounds.min_point.z());
  940. bounds.max_point.x() = std::max<float>(*x, bounds.max_point.x());
  941. bounds.max_point.y() = std::max<float>(*y, bounds.max_point.y());
  942. bounds.max_point.z() = std::max<float>(*z, bounds.max_point.z());
  943. }
  944. return bounds;
  945. }
  946. } // namespace ant
  947. } // namespace game