Antkeeper  0.0.1
morphogenesis.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2023 Christopher J. Howard
3  *
4  * This file is part of Antkeeper source code.
5  *
6  * Antkeeper source code is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Antkeeper source code is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
25 #include <unordered_set>
26 
27 
28 namespace ant {
29 
30 static render::material* build_exoskeleton_material
31 (
34 );
35 static void reskin_vertices
36 (
37  std::uint8_t* vertex_data,
38  std::size_t index_count,
39  const gl::vertex_attribute& position_attribute,
40  const gl::vertex_attribute& normal_attribute,
41  const gl::vertex_attribute& tangent_attribute,
42  const gl::vertex_attribute& bone_index_attribute,
43  const std::unordered_set<std::uint8_t>& old_bone_indices,
44  std::uint8_t new_bone_index,
45  const math::transform<float>& transform
46 );
47 static geom::aabb<float> calculate_bounds(std::uint8_t* vertex_data, std::size_t index_count, const gl::vertex_attribute& position_attribute);
48 static render::model* build_model
49 (
50  render::material* material,
51  const render::model* antennae,
52  const render::model* eyes,
53  const render::model* forewings,
54  const render::model* gaster,
55  const render::model* head,
56  const render::model* hindwings,
57  const render::model* legs,
58  const render::model* mandibles,
59  const render::model* mesosoma,
60  const render::model* lateral_ocelli,
61  const render::model* median_ocellus,
62  const render::model* sting,
63  const render::model* waist
64 );
65 
66 render::material* build_exoskeleton_material
67 (
70 )
71 {
72  // Allocate copy of pigmentation material
73  render::material* exoskeleton_material = new render::material(*pigmentation.material);
74 
75  // Adjust roughness parameter
76  if (render::material_property_base* property = exoskeleton_material->get_property("roughness"); property != nullptr)
77  {
78  static_cast<render::material_property<float>*>(property)->set_value(sculpturing.roughness);
79  }
80  else
81  {
82  exoskeleton_material->add_property<float>("roughness")->set_value(sculpturing.roughness);
83  }
84 
85  // Adjust normal map parameter
86  if (render::material_property_base* property = exoskeleton_material->get_property("normal_map"); property != nullptr)
87  {
88  static_cast<render::material_property<const gl::texture_2d*>*>(property)->set_value(sculpturing.normal_map);
89  }
90  else
91  {
92  exoskeleton_material->add_property<const gl::texture_2d*>("normal_map")->set_value(sculpturing.normal_map);
93  }
94 
95  return exoskeleton_material;
96 }
97 
99 {
100  // Build exoskeleton material
101  render::material* exoskeleton_material = build_exoskeleton_material(*phenome.pigmentation, *phenome.sculpturing);
102 
103  // Determine presence of optional parts
104  bool eyes_present = phenome.eyes->present;
105  bool lateral_ocelli_present = phenome.ocelli->lateral_ocelli_present;
106  bool median_ocellus_present = phenome.ocelli->median_ocellus_present;
107  bool petiole_present = phenome.waist->petiole_present;
108  bool postpetiole_present = phenome.waist->postpetiole_present;
109  bool sting_present = phenome.sting->present;
110  bool wings_present = phenome.wings->present;
111 
112  // Get body part models
113  render::model* antennae_model = phenome.antennae->model;
114  render::model* eyes_model = phenome.eyes->model;
115  render::model* forewings_model = phenome.wings->forewings_model;
116  render::model* gaster_model = phenome.gaster->model;
117  render::model* head_model = phenome.head->model;
118  render::model* hindwings_model = phenome.wings->hindwings_model;
119  render::model* lateral_ocelli_model = phenome.ocelli->lateral_ocelli_model;
120  render::model* legs_model = phenome.legs->model;
121  render::model* mandibles_model = phenome.mandibles->model;
122  render::model* median_ocellus_model = phenome.ocelli->median_ocellus_model;
123  render::model* mesosoma_model = phenome.mesosoma->model;
124  render::model* sting_model = phenome.sting->model;
125  render::model* waist_model = phenome.waist->model;
126 
127  // Get body part vertex buffers
128  const gl::vertex_buffer* antennae_vbo = antennae_model->get_vertex_buffer();
129  const gl::vertex_buffer* eyes_vbo = (eyes_present) ? eyes_model->get_vertex_buffer() : nullptr;
130  const gl::vertex_buffer* forewings_vbo = (wings_present) ? forewings_model->get_vertex_buffer() : nullptr;
131  const gl::vertex_buffer* gaster_vbo = gaster_model->get_vertex_buffer();
132  const gl::vertex_buffer* head_vbo = head_model->get_vertex_buffer();
133  const gl::vertex_buffer* hindwings_vbo = (wings_present) ? hindwings_model->get_vertex_buffer() : nullptr;
134  const gl::vertex_buffer* lateral_ocelli_vbo = (lateral_ocelli_model) ? lateral_ocelli_model->get_vertex_buffer() : nullptr;
135  const gl::vertex_buffer* legs_vbo = legs_model->get_vertex_buffer();
136  const gl::vertex_buffer* mandibles_vbo = mandibles_model->get_vertex_buffer();
137  const gl::vertex_buffer* median_ocellus_vbo = (median_ocellus_model) ? median_ocellus_model->get_vertex_buffer() : nullptr;
138  const gl::vertex_buffer* mesosoma_vbo = mesosoma_model->get_vertex_buffer();
139  const gl::vertex_buffer* sting_vbo = (sting_present) ? sting_model->get_vertex_buffer() : nullptr;
140  const gl::vertex_buffer* waist_vbo = waist_model->get_vertex_buffer();
141 
142  // Determine combined size of vertex buffers and save offsets
143  std::size_t vertex_buffer_size = 0;
144  std::size_t mesosoma_vbo_offset = vertex_buffer_size;
145  vertex_buffer_size += mesosoma_vbo->get_size();
146  std::size_t legs_vbo_offset = vertex_buffer_size;
147  vertex_buffer_size += legs_vbo->get_size();
148  std::size_t head_vbo_offset = vertex_buffer_size;
149  vertex_buffer_size += head_vbo->get_size();
150  std::size_t mandibles_vbo_offset = vertex_buffer_size;
151  vertex_buffer_size += mandibles_vbo->get_size();
152  std::size_t antennae_vbo_offset = vertex_buffer_size;
153  vertex_buffer_size += antennae_vbo->get_size();
154  std::size_t waist_vbo_offset = vertex_buffer_size;
155  vertex_buffer_size += waist_vbo->get_size();
156  std::size_t gaster_vbo_offset = vertex_buffer_size;
157  vertex_buffer_size += gaster_vbo->get_size();
158  std::size_t sting_vbo_offset = vertex_buffer_size;
159  if (sting_present)
160  vertex_buffer_size += sting_vbo->get_size();
161  std::size_t eyes_vbo_offset = vertex_buffer_size;
162  if (eyes_present)
163  vertex_buffer_size += eyes_vbo->get_size();
164  std::size_t lateral_ocelli_vbo_offset = vertex_buffer_size;
165  if (lateral_ocelli_present)
166  vertex_buffer_size += lateral_ocelli_vbo->get_size();
167  std::size_t median_ocellus_vbo_offset = vertex_buffer_size;
168  if (median_ocellus_present)
169  vertex_buffer_size += median_ocellus_vbo->get_size();
170  std::size_t forewings_vbo_offset = vertex_buffer_size;
171  if (wings_present)
172  vertex_buffer_size += forewings_vbo->get_size();
173  std::size_t hindwings_vbo_offset = vertex_buffer_size;
174  if (wings_present)
175  vertex_buffer_size += hindwings_vbo->get_size();
176 
177  // Allocate combined vertex buffer data
178  std::uint8_t* vertex_buffer_data = new std::uint8_t[vertex_buffer_size];
179 
180  // Read body part vertex buffer data into combined vertex buffer data
181  mesosoma_vbo->read(0, mesosoma_vbo->get_size(), vertex_buffer_data + mesosoma_vbo_offset);
182  legs_vbo->read(0, legs_vbo->get_size(), vertex_buffer_data + legs_vbo_offset);
183  head_vbo->read(0, head_vbo->get_size(), vertex_buffer_data + head_vbo_offset);
184  mandibles_vbo->read(0, mandibles_vbo->get_size(), vertex_buffer_data + mandibles_vbo_offset);
185  antennae_vbo->read(0, antennae_vbo->get_size(), vertex_buffer_data + antennae_vbo_offset);
186  waist_vbo->read(0, waist_vbo->get_size(), vertex_buffer_data + waist_vbo_offset);
187  gaster_vbo->read(0, gaster_vbo->get_size(), vertex_buffer_data + gaster_vbo_offset);
188  if (sting_present)
189  sting_vbo->read(0, sting_vbo->get_size(), vertex_buffer_data + sting_vbo_offset);
190  if (eyes_present)
191  eyes_vbo->read(0, eyes_vbo->get_size(), vertex_buffer_data + eyes_vbo_offset);
192  if (lateral_ocelli_present)
193  lateral_ocelli_vbo->read(0, lateral_ocelli_vbo->get_size(), vertex_buffer_data + lateral_ocelli_vbo_offset);
194  if (median_ocellus_present)
195  median_ocellus_vbo->read(0, median_ocellus_vbo->get_size(), vertex_buffer_data + median_ocellus_vbo_offset);
196  if (wings_present)
197  {
198  forewings_vbo->read(0, forewings_vbo->get_size(), vertex_buffer_data + forewings_vbo_offset);
199  hindwings_vbo->read(0, hindwings_vbo->get_size(), vertex_buffer_data + hindwings_vbo_offset);
200  }
201 
202  // Allocate model
203  render::model* model = new render::model();
204 
205  // Setup model VAO
206  gl::vertex_array* model_vao = model->get_vertex_array();
207  for (auto [location, attribute]: mesosoma_model->get_vertex_array()->get_attributes())
208  {
209  attribute.buffer = model->get_vertex_buffer();
210  model_vao->bind(location, attribute);
211  }
212 
213  // Get vertex attributes
214  const gl::vertex_attribute* position_attribute = nullptr;
215  const gl::vertex_attribute* normal_attribute = nullptr;
216  const gl::vertex_attribute* tangent_attribute = nullptr;
217  const gl::vertex_attribute* bone_index_attribute = nullptr;
218  const auto& vertex_attribute_map = model_vao->get_attributes();
219  if (auto it = vertex_attribute_map.find(render::vertex_attribute::position); it != vertex_attribute_map.end())
220  position_attribute = &it->second;
221  if (auto it = vertex_attribute_map.find(render::vertex_attribute::normal); it != vertex_attribute_map.end())
222  normal_attribute = &it->second;
223  if (auto it = vertex_attribute_map.find(render::vertex_attribute::tangent); it != vertex_attribute_map.end())
224  tangent_attribute = &it->second;
225  if (auto it = vertex_attribute_map.find(render::vertex_attribute::bone_index); it != vertex_attribute_map.end())
226  bone_index_attribute = &it->second;
227 
228  // Get body part skeletons
229  const ::skeleton& mesosoma_skeleton = mesosoma_model->get_skeleton();
230  const ::skeleton& legs_skeleton = legs_model->get_skeleton();
231  const ::skeleton& head_skeleton = head_model->get_skeleton();
232  const ::skeleton& mandibles_skeleton = mandibles_model->get_skeleton();
233  const ::skeleton& antennae_skeleton = antennae_model->get_skeleton();
234  const ::skeleton& waist_skeleton = waist_model->get_skeleton();
235  const ::skeleton& gaster_skeleton = gaster_model->get_skeleton();
236  const ::skeleton* sting_skeleton = (sting_present) ? &sting_model->get_skeleton() : nullptr;
237  const ::skeleton* eyes_skeleton = (eyes_present) ? &eyes_model->get_skeleton() : nullptr;
238  const ::skeleton* lateral_ocelli_skeleton = (lateral_ocelli_present) ? &lateral_ocelli_model->get_skeleton() : nullptr;
239  const ::skeleton* median_ocellus_skeleton = (median_ocellus_present) ? &median_ocellus_model->get_skeleton() : nullptr;
240 
241  // Allocate skeleton bones
242  ::skeleton& skeleton = model->get_skeleton();
243  std::size_t bone_count = 33;
244  if (petiole_present)
245  bone_count += 1;
246  if (postpetiole_present)
247  bone_count += 1;
248  if (sting_present)
249  bone_count += 1;
250  if (wings_present)
251  bone_count += 4;
252 
253  // Assign bone indices
254  std::uint8_t bone_index = 0;
255  std::uint8_t mesosoma_bone_index = bone_index++;
256  std::uint8_t procoxa_l_bone_index = bone_index++;
257  std::uint8_t procoxa_r_bone_index = bone_index++;
258  std::uint8_t profemur_l_bone_index = bone_index++;
259  std::uint8_t profemur_r_bone_index = bone_index++;
260  std::uint8_t protibia_l_bone_index = bone_index++;
261  std::uint8_t protibia_r_bone_index = bone_index++;
262  std::uint8_t protarsus_l_bone_index = bone_index++;
263  std::uint8_t protarsus_r_bone_index = bone_index++;
264  std::uint8_t mesocoxa_l_bone_index = bone_index++;
265  std::uint8_t mesocoxa_r_bone_index = bone_index++;
266  std::uint8_t mesofemur_l_bone_index = bone_index++;
267  std::uint8_t mesofemur_r_bone_index = bone_index++;
268  std::uint8_t mesotibia_l_bone_index = bone_index++;
269  std::uint8_t mesotibia_r_bone_index = bone_index++;
270  std::uint8_t mesotarsus_l_bone_index = bone_index++;
271  std::uint8_t mesotarsus_r_bone_index = bone_index++;
272  std::uint8_t metacoxa_l_bone_index = bone_index++;
273  std::uint8_t metacoxa_r_bone_index = bone_index++;
274  std::uint8_t metafemur_l_bone_index = bone_index++;
275  std::uint8_t metafemur_r_bone_index = bone_index++;
276  std::uint8_t metatibia_l_bone_index = bone_index++;
277  std::uint8_t metatibia_r_bone_index = bone_index++;
278  std::uint8_t metatarsus_l_bone_index = bone_index++;
279  std::uint8_t metatarsus_r_bone_index = bone_index++;
280  std::uint8_t head_bone_index = bone_index++;
281  std::uint8_t mandible_l_bone_index = bone_index++;
282  std::uint8_t mandible_r_bone_index = bone_index++;
283  std::uint8_t antennomere1_l_bone_index = bone_index++;
284  std::uint8_t antennomere1_r_bone_index = bone_index++;
285  std::uint8_t antennomere2_l_bone_index = bone_index++;
286  std::uint8_t antennomere2_r_bone_index = bone_index++;
287  std::uint8_t petiole_bone_index =(petiole_present) ? bone_index++ : static_cast<std::uint8_t>(bone_count);
288  std::uint8_t postpetiole_bone_index = (postpetiole_present) ? bone_index++ : static_cast<std::uint8_t>(bone_count);
289  std::uint8_t gaster_bone_index = bone_index++;
290  std::uint8_t sting_bone_index = (sting_present) ? bone_index++ : static_cast<std::uint8_t>(bone_count);
291 
292  // Construct bone identifiers
293  ::bone mesosoma_bone = make_bone(mesosoma_bone_index);
294  ::bone procoxa_l_bone = make_bone(procoxa_l_bone_index, mesosoma_bone_index);
295  ::bone procoxa_r_bone = make_bone(procoxa_r_bone_index, mesosoma_bone_index);
296  ::bone profemur_l_bone = make_bone(profemur_l_bone_index, procoxa_l_bone_index);
297  ::bone profemur_r_bone = make_bone(profemur_r_bone_index, procoxa_r_bone_index);
298  ::bone protibia_l_bone = make_bone(protibia_l_bone_index, profemur_l_bone_index);
299  ::bone protibia_r_bone = make_bone(protibia_r_bone_index, profemur_r_bone_index);
300  ::bone protarsus_l_bone = make_bone(protarsus_l_bone_index, protibia_l_bone_index);
301  ::bone protarsus_r_bone = make_bone(protarsus_r_bone_index, protibia_r_bone_index);
302  ::bone mesocoxa_l_bone = make_bone(mesocoxa_l_bone_index, mesosoma_bone_index);
303  ::bone mesocoxa_r_bone = make_bone(mesocoxa_r_bone_index, mesosoma_bone_index);
304  ::bone mesofemur_l_bone = make_bone(mesofemur_l_bone_index, mesocoxa_l_bone_index);
305  ::bone mesofemur_r_bone = make_bone(mesofemur_r_bone_index, mesocoxa_r_bone_index);
306  ::bone mesotibia_l_bone = make_bone(mesotibia_l_bone_index, mesofemur_l_bone_index);
307  ::bone mesotibia_r_bone = make_bone(mesotibia_r_bone_index, mesofemur_r_bone_index);
308  ::bone mesotarsus_l_bone = make_bone(mesotarsus_l_bone_index, mesotibia_l_bone_index);
309  ::bone mesotarsus_r_bone = make_bone(mesotarsus_r_bone_index, mesotibia_r_bone_index);
310  ::bone metacoxa_l_bone = make_bone(metacoxa_l_bone_index, mesosoma_bone_index);
311  ::bone metacoxa_r_bone = make_bone(metacoxa_r_bone_index, mesosoma_bone_index);
312  ::bone metafemur_l_bone = make_bone(metafemur_l_bone_index, metacoxa_l_bone_index);
313  ::bone metafemur_r_bone = make_bone(metafemur_r_bone_index, metacoxa_r_bone_index);
314  ::bone metatibia_l_bone = make_bone(metatibia_l_bone_index, metafemur_l_bone_index);
315  ::bone metatibia_r_bone = make_bone(metatibia_r_bone_index, metafemur_r_bone_index);
316  ::bone metatarsus_l_bone = make_bone(metatarsus_l_bone_index, metatibia_l_bone_index);
317  ::bone metatarsus_r_bone = make_bone(metatarsus_r_bone_index, metatibia_r_bone_index);
318  ::bone head_bone = make_bone(head_bone_index, mesosoma_bone_index);
319  ::bone mandible_l_bone = make_bone(mandible_l_bone_index, head_bone_index);
320  ::bone mandible_r_bone = make_bone(mandible_r_bone_index, head_bone_index);
321  ::bone antennomere1_l_bone = make_bone(antennomere1_l_bone_index, head_bone_index);
322  ::bone antennomere1_r_bone = make_bone(antennomere1_r_bone_index, head_bone_index);
323  ::bone antennomere2_l_bone = make_bone(antennomere2_l_bone_index, antennomere1_l_bone_index);
324  ::bone antennomere2_r_bone = make_bone(antennomere2_r_bone_index, antennomere1_r_bone_index);
325  ::bone petiole_bone = make_bone(petiole_bone_index, mesosoma_bone_index);
326  ::bone postpetiole_bone = make_bone(postpetiole_bone_index, petiole_bone_index);
327  ::bone gaster_bone = make_bone(gaster_bone_index, (postpetiole_present) ? postpetiole_bone_index : petiole_bone_index);
328  ::bone sting_bone = make_bone(sting_bone_index, gaster_bone_index);
329 
330  // Map bone names to bones
331  skeleton.bone_map["mesosoma"] = mesosoma_bone;
332  skeleton.bone_map["procoxa_l"] = procoxa_l_bone;
333  skeleton.bone_map["procoxa_r"] = procoxa_r_bone;
334  skeleton.bone_map["profemur_l"] = profemur_l_bone;
335  skeleton.bone_map["profemur_r"] = profemur_r_bone;
336  skeleton.bone_map["protibia_l"] = protibia_l_bone;
337  skeleton.bone_map["protibia_r"] = protibia_r_bone;
338  skeleton.bone_map["protarsus_l"] = protarsus_l_bone;
339  skeleton.bone_map["protarsus_r"] = protarsus_r_bone;
340  skeleton.bone_map["mesocoxa_l"] = mesocoxa_l_bone;
341  skeleton.bone_map["mesocoxa_r"] = mesocoxa_r_bone;
342  skeleton.bone_map["mesofemur_l"] = mesofemur_l_bone;
343  skeleton.bone_map["mesofemur_r"] = mesofemur_r_bone;
344  skeleton.bone_map["mesotibia_l"] = mesotibia_l_bone;
345  skeleton.bone_map["mesotibia_r"] = mesotibia_r_bone;
346  skeleton.bone_map["mesotarsus_l"] = mesotarsus_l_bone;
347  skeleton.bone_map["mesotarsus_r"] = mesotarsus_r_bone;
348  skeleton.bone_map["metacoxa_l"] = metacoxa_l_bone;
349  skeleton.bone_map["metacoxa_r"] = metacoxa_r_bone;
350  skeleton.bone_map["metafemur_l"] = metafemur_l_bone;
351  skeleton.bone_map["metafemur_r"] = metafemur_r_bone;
352  skeleton.bone_map["metatibia_l"] = metatibia_l_bone;
353  skeleton.bone_map["metatibia_r"] = metatibia_r_bone;
354  skeleton.bone_map["metatarsus_l"] = metatarsus_l_bone;
355  skeleton.bone_map["metatarsus_r"] = metatarsus_r_bone;
356  skeleton.bone_map["head"] = head_bone;
357  skeleton.bone_map["mandible_l"] = mandible_l_bone;
358  skeleton.bone_map["mandible_r"] = mandible_r_bone;
359  skeleton.bone_map["antennomere1_l"] = antennomere1_l_bone;
360  skeleton.bone_map["antennomere1_r"] = antennomere1_r_bone;
361  skeleton.bone_map["antennomere2_l"] = antennomere2_l_bone;
362  skeleton.bone_map["antennomere2_r"] = antennomere2_r_bone;
363  if (petiole_present)
364  skeleton.bone_map["petiole"] = petiole_bone;
365  if (postpetiole_present)
366  skeleton.bone_map["postpetiole"] = postpetiole_bone;
367  skeleton.bone_map["gaster"] = gaster_bone;
368  if (sting_present)
369  skeleton.bone_map["sting"] = sting_bone;
370 
371  // Get reference to skeleton bind pose
372  pose& bind_pose = skeleton.bind_pose;
373 
374  // Skeleton mesosoma pose
375  if (auto it = mesosoma_skeleton.bone_map.find("mesosoma"); it != mesosoma_skeleton.bone_map.end())
376  bind_pose[mesosoma_bone] = mesosoma_skeleton.bind_pose.at(it->second);
377 
378  // Skeleton forelegs pose
379  if (auto it = legs_skeleton.bone_map.find("procoxa_l"); it != legs_skeleton.bone_map.end())
380  bind_pose[procoxa_l_bone] = legs_skeleton.bind_pose.at(it->second);
381  if (auto it = legs_skeleton.bone_map.find("procoxa_r"); it != legs_skeleton.bone_map.end())
382  bind_pose[procoxa_r_bone] = legs_skeleton.bind_pose.at(it->second);
383  if (auto it = legs_skeleton.bone_map.find("profemur_l"); it != legs_skeleton.bone_map.end())
384  bind_pose[profemur_l_bone] = legs_skeleton.bind_pose.at(it->second);
385  if (auto it = legs_skeleton.bone_map.find("profemur_r"); it != legs_skeleton.bone_map.end())
386  bind_pose[profemur_r_bone] = legs_skeleton.bind_pose.at(it->second);
387  if (auto it = legs_skeleton.bone_map.find("protibia_l"); it != legs_skeleton.bone_map.end())
388  bind_pose[protibia_l_bone] = legs_skeleton.bind_pose.at(it->second);
389  if (auto it = legs_skeleton.bone_map.find("protibia_r"); it != legs_skeleton.bone_map.end())
390  bind_pose[protibia_r_bone] = legs_skeleton.bind_pose.at(it->second);
391  if (auto it = legs_skeleton.bone_map.find("protarsus1_l"); it != legs_skeleton.bone_map.end())
392  bind_pose[protarsus_l_bone] = legs_skeleton.bind_pose.at(it->second);
393  if (auto it = legs_skeleton.bone_map.find("protarsus1_r"); it != legs_skeleton.bone_map.end())
394  bind_pose[protarsus_r_bone] = legs_skeleton.bind_pose.at(it->second);
395 
396  // Skeleton midlegs pose
397  if (auto it = legs_skeleton.bone_map.find("mesocoxa_l"); it != legs_skeleton.bone_map.end())
398  bind_pose[mesocoxa_l_bone] = legs_skeleton.bind_pose.at(it->second);
399  if (auto it = legs_skeleton.bone_map.find("mesocoxa_r"); it != legs_skeleton.bone_map.end())
400  bind_pose[mesocoxa_r_bone] = legs_skeleton.bind_pose.at(it->second);
401  if (auto it = legs_skeleton.bone_map.find("mesofemur_l"); it != legs_skeleton.bone_map.end())
402  bind_pose[mesofemur_l_bone] = legs_skeleton.bind_pose.at(it->second);
403  if (auto it = legs_skeleton.bone_map.find("mesofemur_r"); it != legs_skeleton.bone_map.end())
404  bind_pose[mesofemur_r_bone] = legs_skeleton.bind_pose.at(it->second);
405  if (auto it = legs_skeleton.bone_map.find("mesotibia_l"); it != legs_skeleton.bone_map.end())
406  bind_pose[mesotibia_l_bone] = legs_skeleton.bind_pose.at(it->second);
407  if (auto it = legs_skeleton.bone_map.find("mesotibia_r"); it != legs_skeleton.bone_map.end())
408  bind_pose[mesotibia_r_bone] = legs_skeleton.bind_pose.at(it->second);
409  if (auto it = legs_skeleton.bone_map.find("mesotarsus1_l"); it != legs_skeleton.bone_map.end())
410  bind_pose[mesotarsus_l_bone] = legs_skeleton.bind_pose.at(it->second);
411  if (auto it = legs_skeleton.bone_map.find("mesotarsus1_r"); it != legs_skeleton.bone_map.end())
412  bind_pose[mesotarsus_r_bone] = legs_skeleton.bind_pose.at(it->second);
413 
414  // Skeleton hindlegs pose
415  if (auto it = legs_skeleton.bone_map.find("metacoxa_l"); it != legs_skeleton.bone_map.end())
416  bind_pose[metacoxa_l_bone] = legs_skeleton.bind_pose.at(it->second);
417  if (auto it = legs_skeleton.bone_map.find("metacoxa_r"); it != legs_skeleton.bone_map.end())
418  bind_pose[metacoxa_r_bone] = legs_skeleton.bind_pose.at(it->second);
419  if (auto it = legs_skeleton.bone_map.find("metafemur_l"); it != legs_skeleton.bone_map.end())
420  bind_pose[metafemur_l_bone] = legs_skeleton.bind_pose.at(it->second);
421  if (auto it = legs_skeleton.bone_map.find("metafemur_r"); it != legs_skeleton.bone_map.end())
422  bind_pose[metafemur_r_bone] = legs_skeleton.bind_pose.at(it->second);
423  if (auto it = legs_skeleton.bone_map.find("metatibia_l"); it != legs_skeleton.bone_map.end())
424  bind_pose[metatibia_l_bone] = legs_skeleton.bind_pose.at(it->second);
425  if (auto it = legs_skeleton.bone_map.find("metatibia_r"); it != legs_skeleton.bone_map.end())
426  bind_pose[metatibia_r_bone] = legs_skeleton.bind_pose.at(it->second);
427  if (auto it = legs_skeleton.bone_map.find("metatarsus1_l"); it != legs_skeleton.bone_map.end())
428  bind_pose[metatarsus_l_bone] = legs_skeleton.bind_pose.at(it->second);
429  if (auto it = legs_skeleton.bone_map.find("metatarsus1_r"); it != legs_skeleton.bone_map.end())
430  bind_pose[metatarsus_r_bone] = legs_skeleton.bind_pose.at(it->second);
431 
432  // Skeleton head pose
433  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"));
434 
435  // Skeleton mandibles pose
436  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"));
437  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"));
438 
439  // Skeleton antennae pose
440  bind_pose[antennomere1_l_bone] = head_skeleton.bind_pose.at(head_skeleton.bone_map.at("antenna_l")) * antennae_skeleton.bind_pose.at(antennae_skeleton.bone_map.at("antennomere1_l"));
441  bind_pose[antennomere1_r_bone] = head_skeleton.bind_pose.at(head_skeleton.bone_map.at("antenna_r")) * antennae_skeleton.bind_pose.at(antennae_skeleton.bone_map.at("antennomere1_r"));
442  bind_pose[antennomere2_l_bone] = antennae_skeleton.bind_pose.at(antennae_skeleton.bone_map.at("antennomere2_l"));
443  bind_pose[antennomere2_r_bone] = antennae_skeleton.bind_pose.at(antennae_skeleton.bone_map.at("antennomere2_r"));
444 
445  // Skeleton waist pose
446  if (petiole_present)
447  {
448  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"));
449  }
450  if (postpetiole_present)
451  {
452  bind_pose[postpetiole_bone] = waist_skeleton.bind_pose.at(waist_skeleton.bone_map.at("postpetiole"));
453  }
454 
455  // Skeleton gaster pose
456  if (postpetiole_present)
457  {
458  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"));
459  }
460  else if (petiole_present)
461  {
462  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"));
463  }
464  else
465  {
466  bind_pose[gaster_bone] = mesosoma_skeleton.bind_pose.at(mesosoma_skeleton.bone_map.at("petiole")) * gaster_skeleton.bind_pose.at(gaster_skeleton.bone_map.at("gaster"));
467  }
468 
469  // Skeleton sting pose
470  if (sting_present)
471  {
472  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"));
473  }
474 
475  // Calculate the skeleton-space bind pose
476  pose bind_pose_ss;
477  ::concatenate(bind_pose, bind_pose_ss);
478 
479  // Calculate inverse skeleton-space bind pose
480  ::inverse(bind_pose_ss, skeleton.inverse_bind_pose);
481 
482  // Get number of vertex indices for each body part
483  std::size_t mesosoma_index_count = (*mesosoma_model->get_groups())[0]->get_index_count();
484  std::size_t legs_index_count = (*legs_model->get_groups())[0]->get_index_count();
485  std::size_t head_index_count = (*head_model->get_groups())[0]->get_index_count();
486  std::size_t mandibles_index_count = (*mandibles_model->get_groups())[0]->get_index_count();
487  std::size_t antennae_index_count = (*antennae_model->get_groups())[0]->get_index_count();
488  std::size_t waist_index_count = (*waist_model->get_groups())[0]->get_index_count();
489  std::size_t gaster_index_count = (*gaster_model->get_groups())[0]->get_index_count();
490  std::size_t sting_index_count = (sting_present) ? (*sting_model->get_groups())[0]->get_index_count() : 0;
491  std::size_t eyes_index_count = (eyes_present) ? (*eyes_model->get_groups())[0]->get_index_count() : 0;
492  std::size_t lateral_ocelli_index_count = (lateral_ocelli_present) ? (*lateral_ocelli_model->get_groups())[0]->get_index_count() : 0;
493  std::size_t median_ocellus_index_count = (median_ocellus_present) ? (*median_ocellus_model->get_groups())[0]->get_index_count() : 0;
494  std::size_t forewings_index_count = (wings_present) ? (*forewings_model->get_groups())[0]->get_index_count() : 0;
495  std::size_t hindwings_index_count = (wings_present) ? (*hindwings_model->get_groups())[0]->get_index_count() : 0;
496  std::size_t exoskeleton_index_count =
497  mesosoma_index_count
498  + legs_index_count
499  + head_index_count
500  + mandibles_index_count
501  + antennae_index_count
502  + waist_index_count
503  + gaster_index_count
504  + sting_index_count;
505 
506  // Calculate transform from legs space to body space
508 
509  // Reskin leg bones
510  std::unordered_set<std::uint8_t> old_procoxa_l_indices;
511  if (auto it = legs_skeleton.bone_map.find("procoxa_l"); it != legs_skeleton.bone_map.end())
512  old_procoxa_l_indices.emplace(it->second);
513  reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_procoxa_l_indices, procoxa_l_bone_index, legs_to_body);
514  std::unordered_set<std::uint8_t> old_profemur_l_indices;
515  if (auto it = legs_skeleton.bone_map.find("profemur_l"); it != legs_skeleton.bone_map.end())
516  old_profemur_l_indices.emplace(it->second);
517  reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_profemur_l_indices, profemur_l_bone_index, legs_to_body);
518  std::unordered_set<std::uint8_t> old_protibia_l_indices;
519  if (auto it = legs_skeleton.bone_map.find("protibia_l"); it != legs_skeleton.bone_map.end())
520  old_protibia_l_indices.emplace(it->second);
521  reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_protibia_l_indices, protibia_l_bone_index, legs_to_body);
522  std::unordered_set<std::uint8_t> old_protarsus_l_indices;
523  if (auto it = legs_skeleton.bone_map.find("protarsus1_l"); it != legs_skeleton.bone_map.end())
524  old_protarsus_l_indices.emplace(it->second);
525  if (auto it = legs_skeleton.bone_map.find("protarsus2_l"); it != legs_skeleton.bone_map.end())
526  old_protarsus_l_indices.emplace(it->second);
527  if (auto it = legs_skeleton.bone_map.find("protarsus3_l"); it != legs_skeleton.bone_map.end())
528  old_protarsus_l_indices.emplace(it->second);
529  if (auto it = legs_skeleton.bone_map.find("protarsus4_l"); it != legs_skeleton.bone_map.end())
530  old_protarsus_l_indices.emplace(it->second);
531  if (auto it = legs_skeleton.bone_map.find("protarsus5_l"); it != legs_skeleton.bone_map.end())
532  old_protarsus_l_indices.emplace(it->second);
533  reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_protarsus_l_indices, protarsus_l_bone_index, legs_to_body);
534 
535  std::unordered_set<std::uint8_t> old_procoxa_r_indices;
536  if (auto it = legs_skeleton.bone_map.find("procoxa_r"); it != legs_skeleton.bone_map.end())
537  old_procoxa_r_indices.emplace(it->second);
538  reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_procoxa_r_indices, procoxa_r_bone_index, legs_to_body);
539  std::unordered_set<std::uint8_t> old_profemur_r_indices;
540  if (auto it = legs_skeleton.bone_map.find("profemur_r"); it != legs_skeleton.bone_map.end())
541  old_profemur_r_indices.emplace(it->second);
542  reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_profemur_r_indices, profemur_r_bone_index, legs_to_body);
543  std::unordered_set<std::uint8_t> old_protibia_r_indices;
544  if (auto it = legs_skeleton.bone_map.find("protibia_r"); it != legs_skeleton.bone_map.end())
545  old_protibia_r_indices.emplace(it->second);
546  reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_protibia_r_indices, protibia_r_bone_index, legs_to_body);
547  std::unordered_set<std::uint8_t> old_protarsus_r_indices;
548  if (auto it = legs_skeleton.bone_map.find("protarsus1_r"); it != legs_skeleton.bone_map.end())
549  old_protarsus_r_indices.emplace(it->second);
550  if (auto it = legs_skeleton.bone_map.find("protarsus2_r"); it != legs_skeleton.bone_map.end())
551  old_protarsus_r_indices.emplace(it->second);
552  if (auto it = legs_skeleton.bone_map.find("protarsus3_r"); it != legs_skeleton.bone_map.end())
553  old_protarsus_r_indices.emplace(it->second);
554  if (auto it = legs_skeleton.bone_map.find("protarsus4_r"); it != legs_skeleton.bone_map.end())
555  old_protarsus_r_indices.emplace(it->second);
556  if (auto it = legs_skeleton.bone_map.find("protarsus5_r"); it != legs_skeleton.bone_map.end())
557  old_protarsus_r_indices.emplace(it->second);
558  reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_protarsus_r_indices, protarsus_r_bone_index, legs_to_body);
559 
560  std::unordered_set<std::uint8_t> old_mesocoxa_l_indices;
561  if (auto it = legs_skeleton.bone_map.find("mesocoxa_l"); it != legs_skeleton.bone_map.end())
562  old_mesocoxa_l_indices.emplace(it->second);
563  reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_mesocoxa_l_indices, mesocoxa_l_bone_index, legs_to_body);
564  std::unordered_set<std::uint8_t> old_mesofemur_l_indices;
565  if (auto it = legs_skeleton.bone_map.find("mesofemur_l"); it != legs_skeleton.bone_map.end())
566  old_mesofemur_l_indices.emplace(it->second);
567  reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_mesofemur_l_indices, mesofemur_l_bone_index, legs_to_body);
568  std::unordered_set<std::uint8_t> old_mesotibia_l_indices;
569  if (auto it = legs_skeleton.bone_map.find("mesotibia_l"); it != legs_skeleton.bone_map.end())
570  old_mesotibia_l_indices.emplace(it->second);
571  reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_mesotibia_l_indices, mesotibia_l_bone_index, legs_to_body);
572  std::unordered_set<std::uint8_t> old_mesotarsus_l_indices;
573  if (auto it = legs_skeleton.bone_map.find("mesotarsus1_l"); it != legs_skeleton.bone_map.end())
574  old_mesotarsus_l_indices.emplace(it->second);
575  if (auto it = legs_skeleton.bone_map.find("mesotarsus2_l"); it != legs_skeleton.bone_map.end())
576  old_mesotarsus_l_indices.emplace(it->second);
577  if (auto it = legs_skeleton.bone_map.find("mesotarsus3_l"); it != legs_skeleton.bone_map.end())
578  old_mesotarsus_l_indices.emplace(it->second);
579  if (auto it = legs_skeleton.bone_map.find("mesotarsus4_l"); it != legs_skeleton.bone_map.end())
580  old_mesotarsus_l_indices.emplace(it->second);
581  if (auto it = legs_skeleton.bone_map.find("mesotarsus5_l"); it != legs_skeleton.bone_map.end())
582  old_mesotarsus_l_indices.emplace(it->second);
583  reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_mesotarsus_l_indices, mesotarsus_l_bone_index, legs_to_body);
584 
585  std::unordered_set<std::uint8_t> old_mesocoxa_r_indices;
586  if (auto it = legs_skeleton.bone_map.find("mesocoxa_r"); it != legs_skeleton.bone_map.end())
587  old_mesocoxa_r_indices.emplace(it->second);
588  reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_mesocoxa_r_indices, mesocoxa_r_bone_index, legs_to_body);
589  std::unordered_set<std::uint8_t> old_mesofemur_r_indices;
590  if (auto it = legs_skeleton.bone_map.find("mesofemur_r"); it != legs_skeleton.bone_map.end())
591  old_mesofemur_r_indices.emplace(it->second);
592  reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_mesofemur_r_indices, mesofemur_r_bone_index, legs_to_body);
593  std::unordered_set<std::uint8_t> old_mesotibia_r_indices;
594  if (auto it = legs_skeleton.bone_map.find("mesotibia_r"); it != legs_skeleton.bone_map.end())
595  old_mesotibia_r_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_mesotibia_r_indices, mesotibia_r_bone_index, legs_to_body);
597  std::unordered_set<std::uint8_t> old_mesotarsus_r_indices;
598  if (auto it = legs_skeleton.bone_map.find("mesotarsus1_r"); it != legs_skeleton.bone_map.end())
599  old_mesotarsus_r_indices.emplace(it->second);
600  if (auto it = legs_skeleton.bone_map.find("mesotarsus2_r"); it != legs_skeleton.bone_map.end())
601  old_mesotarsus_r_indices.emplace(it->second);
602  if (auto it = legs_skeleton.bone_map.find("mesotarsus3_r"); it != legs_skeleton.bone_map.end())
603  old_mesotarsus_r_indices.emplace(it->second);
604  if (auto it = legs_skeleton.bone_map.find("mesotarsus4_r"); it != legs_skeleton.bone_map.end())
605  old_mesotarsus_r_indices.emplace(it->second);
606  if (auto it = legs_skeleton.bone_map.find("mesotarsus5_r"); it != legs_skeleton.bone_map.end())
607  old_mesotarsus_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_mesotarsus_r_indices, mesotarsus_r_bone_index, legs_to_body);
609 
610  std::unordered_set<std::uint8_t> old_metacoxa_l_indices;
611  if (auto it = legs_skeleton.bone_map.find("metacoxa_l"); it != legs_skeleton.bone_map.end())
612  old_metacoxa_l_indices.emplace(it->second);
613  reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_metacoxa_l_indices, metacoxa_l_bone_index, legs_to_body);
614  std::unordered_set<std::uint8_t> old_metafemur_l_indices;
615  if (auto it = legs_skeleton.bone_map.find("metafemur_l"); it != legs_skeleton.bone_map.end())
616  old_metafemur_l_indices.emplace(it->second);
617  reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_metafemur_l_indices, metafemur_l_bone_index, legs_to_body);
618  std::unordered_set<std::uint8_t> old_metatibia_l_indices;
619  if (auto it = legs_skeleton.bone_map.find("metatibia_l"); it != legs_skeleton.bone_map.end())
620  old_metatibia_l_indices.emplace(it->second);
621  reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_metatibia_l_indices, metatibia_l_bone_index, legs_to_body);
622  std::unordered_set<std::uint8_t> old_metatarsus_l_indices;
623  if (auto it = legs_skeleton.bone_map.find("metatarsus1_l"); it != legs_skeleton.bone_map.end())
624  old_metatarsus_l_indices.emplace(it->second);
625  if (auto it = legs_skeleton.bone_map.find("metatarsus2_l"); it != legs_skeleton.bone_map.end())
626  old_metatarsus_l_indices.emplace(it->second);
627  if (auto it = legs_skeleton.bone_map.find("metatarsus3_l"); it != legs_skeleton.bone_map.end())
628  old_metatarsus_l_indices.emplace(it->second);
629  if (auto it = legs_skeleton.bone_map.find("metatarsus4_l"); it != legs_skeleton.bone_map.end())
630  old_metatarsus_l_indices.emplace(it->second);
631  if (auto it = legs_skeleton.bone_map.find("metatarsus5_l"); it != legs_skeleton.bone_map.end())
632  old_metatarsus_l_indices.emplace(it->second);
633  reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_metatarsus_l_indices, metatarsus_l_bone_index, legs_to_body);
634 
635  std::unordered_set<std::uint8_t> old_metacoxa_r_indices;
636  if (auto it = legs_skeleton.bone_map.find("metacoxa_r"); it != legs_skeleton.bone_map.end())
637  old_metacoxa_r_indices.emplace(it->second);
638  reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_metacoxa_r_indices, metacoxa_r_bone_index, legs_to_body);
639  std::unordered_set<std::uint8_t> old_metafemur_r_indices;
640  if (auto it = legs_skeleton.bone_map.find("metafemur_r"); it != legs_skeleton.bone_map.end())
641  old_metafemur_r_indices.emplace(it->second);
642  reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_metafemur_r_indices, metafemur_r_bone_index, legs_to_body);
643  std::unordered_set<std::uint8_t> old_metatibia_r_indices;
644  if (auto it = legs_skeleton.bone_map.find("metatibia_r"); it != legs_skeleton.bone_map.end())
645  old_metatibia_r_indices.emplace(it->second);
646  reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_metatibia_r_indices, metatibia_r_bone_index, legs_to_body);
647  std::unordered_set<std::uint8_t> old_metatarsus_r_indices;
648  if (auto it = legs_skeleton.bone_map.find("metatarsus1_r"); it != legs_skeleton.bone_map.end())
649  old_metatarsus_r_indices.emplace(it->second);
650  if (auto it = legs_skeleton.bone_map.find("metatarsus2_r"); it != legs_skeleton.bone_map.end())
651  old_metatarsus_r_indices.emplace(it->second);
652  if (auto it = legs_skeleton.bone_map.find("metatarsus3_r"); it != legs_skeleton.bone_map.end())
653  old_metatarsus_r_indices.emplace(it->second);
654  if (auto it = legs_skeleton.bone_map.find("metatarsus4_r"); it != legs_skeleton.bone_map.end())
655  old_metatarsus_r_indices.emplace(it->second);
656  if (auto it = legs_skeleton.bone_map.find("metatarsus5_r"); it != legs_skeleton.bone_map.end())
657  old_metatarsus_r_indices.emplace(it->second);
658  reskin_vertices(vertex_buffer_data + legs_vbo_offset, legs_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_metatarsus_r_indices, metatarsus_r_bone_index, legs_to_body);
659 
660  // Calculate transform from head space to body space
661  math::transform<float> head_to_body = bind_pose_ss.at(mesosoma_bone) * mesosoma_skeleton.bind_pose.at(mesosoma_skeleton.bone_map.at("head"));
662 
663  // Reskin head bone
664  std::unordered_set<std::uint8_t> old_head_bone_indices;
665  if (auto it = head_skeleton.bone_map.find("head"); it != head_skeleton.bone_map.end())
666  old_head_bone_indices.emplace(it->second);
667  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);
668 
669  // Calculate transforms from mandibles space to body space
670  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"));
671  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"));
672 
673  // Reskin mandible bones
674  std::unordered_set<std::uint8_t> old_head_mandible_l_bone_indices;
675  if (auto it = mandibles_skeleton.bone_map.find("mandible_l"); it != mandibles_skeleton.bone_map.end())
676  old_head_mandible_l_bone_indices.emplace(it->second);
677  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);
678  std::unordered_set<std::uint8_t> old_head_mandible_r_bone_indices;
679  if (auto it = mandibles_skeleton.bone_map.find("mandible_r"); it != mandibles_skeleton.bone_map.end())
680  old_head_mandible_r_bone_indices.emplace(it->second);
681  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);
682 
683  // Calculate transforms from antennae space to body space
684  math::transform<float> antenna_l_to_body = bind_pose_ss.at(head_bone) * head_skeleton.bind_pose.at(head_skeleton.bone_map.at("antenna_l"));
685  math::transform<float> antenna_r_to_body = bind_pose_ss.at(head_bone) * head_skeleton.bind_pose.at(head_skeleton.bone_map.at("antenna_r"));
686 
687  // Reskin antennomere1 bones
688  std::unordered_set<std::uint8_t> old_antennomere1_l_indices;
689  if (auto it = antennae_skeleton.bone_map.find("antennomere1_l"); it != antennae_skeleton.bone_map.end())
690  old_antennomere1_l_indices.emplace(it->second);
691  reskin_vertices(vertex_buffer_data + antennae_vbo_offset, antennae_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_antennomere1_l_indices, antennomere1_l_bone_index, antenna_l_to_body);
692  std::unordered_set<std::uint8_t> old_antennomere1_r_indices;
693  if (auto it = antennae_skeleton.bone_map.find("antennomere1_r"); it != antennae_skeleton.bone_map.end())
694  old_antennomere1_r_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_antennomere1_r_indices, antennomere1_r_bone_index, antenna_r_to_body);
696 
697  // Reskin antennomere2+ bones
698  const std::vector<std::string> antennomere_bone_names =
699  {
700  "antennomere2",
701  "antennomere3",
702  "antennomere4",
703  "antennomere5",
704  "antennomere6",
705  "antennomere7",
706  "antennomere8",
707  "antennomere9",
708  "antennomere10",
709  "antennomere11",
710  "antennomere12",
711  "antennomere13"
712  };
713  std::unordered_set<std::uint8_t> old_antennomere_l_indices;
714  for (const std::string& bone_name: antennomere_bone_names)
715  if (auto it = antennae_skeleton.bone_map.find(bone_name + "_l"); it != antennae_skeleton.bone_map.end())
716  old_antennomere_l_indices.emplace(it->second);
717  reskin_vertices(vertex_buffer_data + antennae_vbo_offset, antennae_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_antennomere_l_indices, antennomere2_l_bone_index, antenna_l_to_body);
718  std::unordered_set<std::uint8_t> old_antennomere_r_indices;
719  for (const std::string& bone_name: antennomere_bone_names)
720  if (auto it = antennae_skeleton.bone_map.find(bone_name + "_r"); it != antennae_skeleton.bone_map.end())
721  old_antennomere_r_indices.emplace(it->second);
722  reskin_vertices(vertex_buffer_data + antennae_vbo_offset, antennae_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_antennomere_r_indices, antennomere2_r_bone_index, antenna_r_to_body);
723 
724  // Calculate transform from waist space to body space
725  math::transform<float> waist_to_body = bind_pose_ss.at(mesosoma_bone) * mesosoma_skeleton.bind_pose.at(mesosoma_skeleton.bone_map.at("petiole"));
726 
727  // Reskin waist bones
728  std::unordered_set<std::uint8_t> old_petiole_bone_indices;
729  if (auto it = waist_skeleton.bone_map.find("petiole"); it != waist_skeleton.bone_map.end())
730  old_petiole_bone_indices.emplace(it->second);
731  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);
732  if (postpetiole_present)
733  {
734  std::unordered_set<std::uint8_t> old_postpetiole_bone_indices;
735  if (auto it = waist_skeleton.bone_map.find("postpetiole"); it != waist_skeleton.bone_map.end())
736  old_postpetiole_bone_indices.emplace(it->second);
737  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);
738  }
739 
740  // Calculate transform from gaster space to body space
741  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"));
742 
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 
749  if (sting_present)
750  {
751  // Calculate transform from sting space to body space
752  math::transform<float> sting_to_body = gaster_to_body * gaster_skeleton.bind_pose.at(gaster_skeleton.bone_map.at("sting"));
753 
754  // Reskin sting bones
755  std::unordered_set<std::uint8_t> old_sting_bone_indices;
756  if (auto it = sting_skeleton->bone_map.find("sting"); it != sting_skeleton->bone_map.end())
757  old_sting_bone_indices.emplace(it->second);
758  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);
759  }
760 
761  if (eyes_present)
762  {
763  // Calculate transforms from eyes space to body space
764  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"));
765  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"));
766 
767  // Reskin eye bones
768  std::unordered_set<std::uint8_t> old_eye_l_bone_indices;
769  if (auto it = eyes_skeleton->bone_map.find("eye_l"); it != eyes_skeleton->bone_map.end())
770  old_eye_l_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_l_bone_indices, head_bone_index, eye_l_to_body);
772  std::unordered_set<std::uint8_t> old_eye_r_bone_indices;
773  if (auto it = eyes_skeleton->bone_map.find("eye_r"); it != eyes_skeleton->bone_map.end())
774  old_eye_r_bone_indices.emplace(it->second);
775  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);
776  }
777 
778  if (lateral_ocelli_present)
779  {
780  // Calculate transforms from lateral ocelli space to body space
781  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"));
782  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"));
783 
784  // Reskin lateral ocelli bones
785  std::unordered_set<std::uint8_t> old_ocellus_l_bone_indices;
786  if (auto it = lateral_ocelli_skeleton->bone_map.find("ocellus_l"); it != lateral_ocelli_skeleton->bone_map.end())
787  old_ocellus_l_bone_indices.emplace(it->second);
788  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);
789  std::unordered_set<std::uint8_t> old_ocellus_r_bone_indices;
790  if (auto it = lateral_ocelli_skeleton->bone_map.find("ocellus_r"); it != lateral_ocelli_skeleton->bone_map.end())
791  old_ocellus_r_bone_indices.emplace(it->second);
792  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);
793  }
794 
795  if (median_ocellus_present)
796  {
797  // Calculate transforms from lateral ocelli space to body space
798  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"));
799 
800  // Reskin lateral ocelli bones
801  std::unordered_set<std::uint8_t> old_ocellus_m_bone_indices;
802  if (auto it = median_ocellus_skeleton->bone_map.find("ocellus_m"); it != median_ocellus_skeleton->bone_map.end())
803  old_ocellus_m_bone_indices.emplace(it->second);
804  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);
805  }
806 
807  // Upload vertex buffer data to model VBO
808  model->get_vertex_buffer()->repurpose(gl::buffer_usage::static_draw, vertex_buffer_size, vertex_buffer_data);
809 
810  // Construct exoskeleton model group
811  render::model_group* exoskeleton_group = model->add_group("exoskeleton");
812  exoskeleton_group->set_material(exoskeleton_material);
813  exoskeleton_group->set_drawing_mode(gl::drawing_mode::triangles);
814  exoskeleton_group->set_start_index(0);
815  exoskeleton_group->set_index_count(exoskeleton_index_count);
816 
817  std::size_t index_offset = exoskeleton_index_count;
818  if (eyes_present)
819  {
820  // Construct eyes model group
821  render::model_group* eyes_group = model->add_group("eyes");
822  eyes_group->set_material((*eyes_model->get_groups())[0]->get_material());
824  eyes_group->set_start_index(index_offset);
825  eyes_group->set_index_count(eyes_index_count);
826  index_offset += eyes_index_count;
827  }
828 
829  if (lateral_ocelli_present || median_ocellus_present)
830  {
831  // Construct ocelli model group
832  render::model_group* ocelli_group = model->add_group("ocelli");
834  ocelli_group->set_start_index(index_offset);
835 
836  std::size_t index_count = 0;
837  if (lateral_ocelli_present)
838  {
839  index_count += lateral_ocelli_index_count;
840  index_offset += lateral_ocelli_index_count;
841  ocelli_group->set_material((*lateral_ocelli_model->get_groups())[0]->get_material());
842  }
843  if (median_ocellus_present)
844  {
845  index_count += median_ocellus_index_count;
846  index_offset += median_ocellus_index_count;
847  if (!lateral_ocelli_present)
848  ocelli_group->set_material((*median_ocellus_model->get_groups())[0]->get_material());
849  }
850 
851  ocelli_group->set_index_count(index_count);
852  }
853 
854  if (wings_present)
855  {
856  // Construct forewings model group
857  render::model_group* forewings_group = model->add_group("forewings");
858  forewings_group->set_material((*forewings_model->get_groups())[0]->get_material());
860  forewings_group->set_start_index(index_offset);
861  forewings_group->set_index_count(forewings_index_count);
862  index_offset += forewings_index_count;
863 
864  // Construct hindwings model group
865  render::model_group* hindwings_group = model->add_group("hindwings");
866  hindwings_group->set_material((*hindwings_model->get_groups())[0]->get_material());
868  hindwings_group->set_start_index(index_offset);
869  hindwings_group->set_index_count(hindwings_index_count);
870  index_offset += hindwings_index_count;
871  }
872 
873  // Calculate model bounding box
874  geom::aabb<float> bounds = calculate_bounds(vertex_buffer_data, index_offset, *position_attribute);
875  model->set_bounds(bounds);
876 
877  // Free vertex buffer data
878  delete[] vertex_buffer_data;
879 
880  return model;
881 }
882 
883 void reskin_vertices
884 (
885  std::uint8_t* vertex_data,
886  std::size_t index_count,
887  const gl::vertex_attribute& position_attribute,
888  const gl::vertex_attribute& normal_attribute,
889  const gl::vertex_attribute& tangent_attribute,
890  const gl::vertex_attribute& bone_index_attribute,
891  const std::unordered_set<std::uint8_t>& old_bone_indices,
892  std::uint8_t new_bone_index,
893  const math::transform<float>& transform
894 )
895 {
896  std::uint8_t* position_data = vertex_data + position_attribute.offset;
897  std::uint8_t* normal_data = vertex_data + normal_attribute.offset;
898  std::uint8_t* tangent_data = vertex_data + tangent_attribute.offset;
899  std::uint8_t* bone_index_data = vertex_data + bone_index_attribute.offset;
900 
901  for (std::size_t i = 0; i < index_count; ++i)
902  {
903  // Get bone index of current vertex
904  float* bone_index = reinterpret_cast<float*>(bone_index_data + bone_index_attribute.stride * i);
905 
906  // Skip irrelevant bones
907  if (!old_bone_indices.count(static_cast<std::uint8_t>(*bone_index + 0.5f)))
908  continue;
909 
910  // Get vertex position
911  float* x = reinterpret_cast<float*>(position_data + position_attribute.stride * i);
912  float* y = x + 1;
913  float* z = y + 1;
914 
915  // Get vertex normal
916  float* nx = reinterpret_cast<float*>(normal_data + normal_attribute.stride * i);
917  float* ny = nx + 1;
918  float* nz = ny + 1;
919 
920  // Get vertex tangent
921  float* tx = reinterpret_cast<float*>(tangent_data + tangent_attribute.stride * i);
922  float* ty = tx + 1;
923  float* tz = ty + 1;
924  //float* bts = tz + 1;
925 
926  // Transform vertex attributes
927  float3 position = transform * float3{*x, *y, *z};
928  float3 normal = math::normalize(transform.rotation * float3{*nx, *ny, *nz});
929  float3 tangent = transform.rotation * float3{*tx, *ty, *tz};
930 
931  // Update vertex data
932  *x = position.x();
933  *y = position.y();
934  *z = position.z();
935  *nx = normal.x();
936  *ny = normal.y();
937  *nz = normal.z();
938  *tx = tangent.x();
939  *ty = tangent.y();
940  *tz = tangent.z();
941  //*bts = ...
942  *bone_index = static_cast<float>(new_bone_index);
943  }
944 }
945 
946 geom::aabb<float> calculate_bounds(std::uint8_t* vertex_data, std::size_t index_count, const gl::vertex_attribute& position_attribute)
947 {
948  std::uint8_t* position_data = vertex_data + position_attribute.offset;
949 
950  geom::aabb<float> bounds;
951  bounds.min_point.x() = std::numeric_limits<float>::infinity();
952  bounds.min_point.y() = std::numeric_limits<float>::infinity();
953  bounds.min_point.z() = std::numeric_limits<float>::infinity();
954  bounds.max_point.x() = -std::numeric_limits<float>::infinity();
955  bounds.max_point.y() = -std::numeric_limits<float>::infinity();
956  bounds.max_point.z() = -std::numeric_limits<float>::infinity();
957 
958  for (std::size_t i = 0; i < index_count; ++i)
959  {
960  // Get vertex position
961  float* x = reinterpret_cast<float*>(position_data + position_attribute.stride * i);
962  float* y = x + 1;
963  float* z = y + 1;
964 
965  bounds.min_point.x() = std::min<float>(*x, bounds.min_point.x());
966  bounds.min_point.y() = std::min<float>(*y, bounds.min_point.y());
967  bounds.min_point.z() = std::min<float>(*z, bounds.min_point.z());
968  bounds.max_point.x() = std::max<float>(*x, bounds.max_point.x());
969  bounds.max_point.y() = std::max<float>(*y, bounds.max_point.y());
970  bounds.max_point.z() = std::max<float>(*z, bounds.max_point.z());
971  }
972 
973  return bounds;
974 }
975 
976 } // namespace ant
977 
std::uint32_t bone
Skeletal animation bone identifier, consisting of a bone index in the lower half, and a parent bone i...
Definition: bone.hpp:30
std::uint16_t bone_index(bone x)
Returns the index of a bone.
Definition: bone.hpp:106
bone make_bone(std::uint16_t index, std::uint16_t parent_index)
Constructs a bone identifier.
Definition: bone.hpp:96
std::uint16_t bone_parent_index(bone x)
Returns the parent index of a bone.
Definition: bone.hpp:111
A 2D texture which can be uploaded to shaders via shader inputs.
Definition: texture-2d.hpp:31
Vertex array object (VAO), which describes how vertex attributes are stored in vertex buffer objects ...
const attribute_map_type & get_attributes() const
Returns a const reference to the map of vertex attributes bound to this vertex array.
void bind(attribute_location_type location, const vertex_attribute &attribute)
Binds a vertex attribute to the vertex array.
Vertex buffer object (VBO).
std::size_t get_size() const
Returns the size of the buffer's data, in bytes.
void repurpose(buffer_usage usage, std::size_t size, const void *data=nullptr)
Repurposes a vertex buffer, changing its usage hint, its size, and replacing its data.
void read(std::size_t offset, std::size_t size, void *data) const
Reads a subset of the buffer's data from the GL and returns it to the application.
Abstract base class for material properties.
A material is associated with exactly one shader program and contains a set of material properties wh...
Definition: material.hpp:39
material_property< T > * add_property(const std::string &name, std::size_t element_count=1)
Adds a material array property to the material.
Definition: material.hpp:189
material_property_base * get_property(const std::string &name) const
Returns the material property with the specified name, or nullptr if the material could not be found.
Definition: material.hpp:237
Part of a model which is associated with exactly one material.
Definition: model.hpp:39
void set_drawing_mode(gl::drawing_mode mode)
Definition: model.hpp:70
void set_material(material *material)
Definition: model.hpp:65
void set_start_index(std::size_t index)
Definition: model.hpp:75
void set_index_count(std::size_t count)
Definition: model.hpp:80
const gl::vertex_array * get_vertex_array() const
Definition: model.hpp:178
const skeleton & get_skeleton() const
Definition: model.hpp:198
const std::vector< model_group * > * get_groups() const
Definition: model.hpp:173
model_group * add_group(const std::string &name=std::string())
Definition: model.cpp:36
const gl::vertex_buffer * get_vertex_buffer() const
Definition: model.hpp:188
void set_bounds(const aabb_type &bounds)
Definition: model.hpp:163
polyphenic_gene< phene::pigmentation > pigmentation
Polyphenic pigmentation gene.
polyphenic_gene< phene::head > head
Polyphenic head gene.
Definition: gene/head.hpp:30
polyphenic_gene< phene::mandibles > mandibles
Polyphenic mandibles gene.
polyphenic_gene< phene::gaster > gaster
Polyphenic gaster gene.
Definition: gene/gaster.hpp:30
polyphenic_gene< phene::eyes > eyes
Polyphenic eyes gene.
Definition: gene/eyes.hpp:30
polyphenic_gene< phene::mesosoma > mesosoma
Polyphenic mesosoma gene.
polyphenic_gene< phene::sting > sting
Polyphenic sting gene.
Definition: gene/sting.hpp:30
polyphenic_gene< phene::legs > legs
Polyphenic legs gene.
Definition: gene/legs.hpp:30
polyphenic_gene< phene::sculpturing > sculpturing
Polyphenic sculpturing gene.
polyphenic_gene< phene::antennae > antennae
Polyphenic antennae gene.
polyphenic_gene< phene::waist > waist
Polyphenic waist gene.
Definition: gene/waist.hpp:30
Definition: caste.hpp:25
render::model * morphogenesis(const phenome &phenome)
Generates a 3D model of an ant given its phenome.
aabb< float > calculate_bounds(const mesh &mesh)
Calculates the AABB bounds of a mesh.
@ static_draw
Data will be modified once, by the application, and used many times, for drawing commands.
quaternion< T > normalize(const quaternion< T > &q)
Normalizes a quaternion.
Definition: quaternion.hpp:605
@ position
Vertex position (vec3)
@ bone_index
Vertex bone indices (vec4)
@ tangent
Vertex tangent (vec4)
void inverse(const pose &x, pose &y)
Inverses each transform in a pose.
Definition: pose.cpp:42
void concatenate(const pose &bone_space, pose &skeleton_space)
Transforms a pose from bone-space into skeleton-space.
Definition: pose.cpp:24
std::map< bone, math::transform< float >, bone_index_compare > pose
Skeletal animation pose.
Definition: pose.hpp:31
render::model * model
3D model of the antennae.
render::model * model
3D model of the eyes, if present.
Definition: phene/eyes.hpp:36
bool present
Indicates whether eyes are present.
Definition: phene/eyes.hpp:39
render::model * model
3D model of the gaster.
render::model * model
3D model of the head.
Definition: phene/head.hpp:37
render::model * model
3D model of the legs.
Definition: phene/legs.hpp:36
render::model * model
3D model of the mandibles.
render::model * model
3D model of the mesosoma.
bool median_ocellus_present
Median ocellus present.
render::model * median_ocellus_model
3D model of the median ocellus, if present.
bool lateral_ocelli_present
Lateral ocelli present.
render::model * lateral_ocelli_model
3D model of the lateral ocelli, if present.
render::model * model
3D model of the sting.
Definition: phene/sting.hpp:37
bool present
Indicates whether a sting present or not.
Definition: phene/sting.hpp:34
bool postpetiole_present
Postpetiole presence.
Definition: phene/waist.hpp:54
render::model * model
3D model of the waist.
Definition: phene/waist.hpp:36
render::model * hindwings_model
3D model of the hindwings.
Definition: phene/wings.hpp:37
bool present
Wings presence.
Definition: phene/wings.hpp:40
render::model * forewings_model
3D model of the forewings.
Definition: phene/wings.hpp:34
Complete set of ant phenes.
Definition: phenome.hpp:54
const phene::legs * legs
Definition: phenome.hpp:77
const phene::mandibles * mandibles
Definition: phenome.hpp:78
const phene::pigmentation * pigmentation
Definition: phenome.hpp:82
const phene::sting * sting
Definition: phenome.hpp:85
const phene::eyes * eyes
Definition: phenome.hpp:71
const phene::mesosoma * mesosoma
Definition: phenome.hpp:79
const phene::antennae * antennae
Definition: phenome.hpp:66
const phene::head * head
Definition: phenome.hpp:75
const phene::ocelli * ocelli
Definition: phenome.hpp:81
const phene::sculpturing * sculpturing
Definition: phenome.hpp:84
const phene::waist * waist
Definition: phenome.hpp:86
const phene::gaster * gaster
Definition: phenome.hpp:74
const phene::wings * wings
Definition: phenome.hpp:87
vector_type max_point
Definition: aabb.hpp:43
vector_type min_point
Definition: aabb.hpp:42
Describes a vertex attribute within a vertex buffer.
std::size_t stride
Number of bytes between consecutive instances of this attribute in the vertex buffer....
std::size_t offset
Offset to the first component of the first instance of this attribute in the vertex buffer,...
quaternion< T > rotation
Rotation quaternion.
constexpr element_type & x() noexcept
Returns a reference to the first element.
Definition: vector.hpp:163
constexpr element_type & y() noexcept
Returns a reference to the second element.
Definition: vector.hpp:179
constexpr element_type & z() noexcept
Returns a reference to the third element.
Definition: vector.hpp:195
Skeletal animation skeleton.
Definition: skeleton.hpp:32
pose inverse_bind_pose
Inverse skeleton-space bind pose of the skeleton.
Definition: skeleton.hpp:37
pose bind_pose
Bone-space bind pose of the skeleton.
Definition: skeleton.hpp:34
std::unordered_map< std::string, bone > bone_map
Maps bone names to bone identifiers.
Definition: skeleton.hpp:40