Antkeeper  0.0.1
model.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 
20 #include <engine/render/model.hpp>
24 #include <engine/math/numbers.hpp>
26 #include <bit>
27 #include <cstdint>
28 
29 inline constexpr std::uint16_t vertex_attribute_position = 0b0000000000000001;
30 inline constexpr std::uint16_t vertex_attribute_uv = 0b0000000000000010;
31 inline constexpr std::uint16_t vertex_attribute_normal = 0b0000000000000100;
32 inline constexpr std::uint16_t vertex_attribute_tangent = 0b0000000000001000;
33 inline constexpr std::uint16_t vertex_attribute_color = 0b0000000000010000;
34 inline constexpr std::uint16_t vertex_attribute_bone_index = 0b0000000000100000;
35 inline constexpr std::uint16_t vertex_attribute_bone_weight = 0b0000000001000000;
36 inline constexpr std::uint16_t vertex_attribute_morph_target = 0b0000000010000000;
37 
38 template <>
40 {
41  // Read vertex format
42  std::uint16_t vertex_format_flags = 0;
43  ctx.read16<std::endian::little>(reinterpret_cast<std::byte*>(&vertex_format_flags), 1);
44 
45  // Read bones per vertex (if any)
46  std::uint8_t bones_per_vertex = 0;
47  if ((vertex_format_flags & vertex_attribute_bone_index) || (vertex_format_flags & vertex_attribute_bone_weight))
48  {
49  ctx.read8(reinterpret_cast<std::byte*>(&bones_per_vertex), 1);
50  }
51 
52  // Read vertex count
53  std::uint32_t vertex_count = 0;
54  ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&vertex_count), 1);
55 
56  // Determine vertex stride
57  std::size_t vertex_stride = 0;
58  if (vertex_format_flags & vertex_attribute_position)
59  {
60  vertex_stride += sizeof(float) * 3;
61  }
62  if (vertex_format_flags & vertex_attribute_uv)
63  {
64  vertex_stride += sizeof(float) * 2;
65  }
66  if (vertex_format_flags & vertex_attribute_normal)
67  {
68  vertex_stride += sizeof(float) * 3;
69  }
70  if (vertex_format_flags & vertex_attribute_tangent)
71  {
72  vertex_stride += sizeof(float) * 4;
73  }
74  if (vertex_format_flags & vertex_attribute_color)
75  {
76  vertex_stride += sizeof(float) * 4;
77  }
78  if (vertex_format_flags & vertex_attribute_bone_index)
79  {
80  vertex_stride += sizeof(std::uint16_t) * bones_per_vertex;
81  }
82  if (vertex_format_flags & vertex_attribute_bone_weight)
83  {
84  vertex_stride += sizeof(float) * bones_per_vertex;
85  }
86  if (vertex_format_flags & vertex_attribute_morph_target)
87  {
88  vertex_stride += sizeof(float) * 3;
89  }
90 
91  // Allocate vertex data
92  std::vector<std::byte> vertex_data(vertex_count * vertex_stride);
93 
94  // Read vertices
95  if constexpr (std::endian::native == std::endian::little)
96  {
97  ctx.read8(vertex_data.data(), vertex_count * vertex_stride);
98  }
99  else
100  {
101  std::byte* vertex_data_offset = vertex_data.data();
102  for (std::uint32_t i = 0; i < vertex_count; ++i)
103  {
104  if (vertex_format_flags & vertex_attribute_position)
105  {
106  ctx.read32<std::endian::little>(vertex_data_offset, 3);
107  vertex_data_offset += sizeof(float) * 3;
108  }
109  if (vertex_format_flags & vertex_attribute_uv)
110  {
111  ctx.read32<std::endian::little>(vertex_data_offset, 2);
112  vertex_data_offset += sizeof(float) * 2;
113  }
114  if (vertex_format_flags & vertex_attribute_normal)
115  {
116  ctx.read32<std::endian::little>(vertex_data_offset, 3);
117  vertex_data_offset += sizeof(float) * 3;
118  }
119  if (vertex_format_flags & vertex_attribute_tangent)
120  {
121  ctx.read32<std::endian::little>(vertex_data_offset, 4);
122  vertex_data_offset += sizeof(float) * 4;
123  }
124  if (vertex_format_flags & vertex_attribute_color)
125  {
126  ctx.read32<std::endian::little>(vertex_data_offset, 4);
127  vertex_data_offset += sizeof(float) * 4;
128  }
129  if (vertex_format_flags & vertex_attribute_bone_index)
130  {
131  ctx.read16<std::endian::little>(vertex_data_offset, bones_per_vertex);
132  vertex_data_offset += sizeof(std::uint16_t) * bones_per_vertex;
133  }
134  if (vertex_format_flags & vertex_attribute_bone_weight)
135  {
136  ctx.read32<std::endian::little>(vertex_data_offset, bones_per_vertex);
137  vertex_data_offset += sizeof(float) * bones_per_vertex;
138  }
139  if (vertex_format_flags & vertex_attribute_morph_target)
140  {
141  ctx.read32<std::endian::little>(vertex_data_offset, 3);
142  vertex_data_offset += sizeof(float) * 3;
143  }
144  }
145  }
146 
147  // Allocate model
148  std::unique_ptr<render::model> model = std::make_unique<render::model>();
149 
150  // Build model vertex buffer
151  model->get_vertex_buffer() = std::make_shared<gl::vertex_buffer>(gl::buffer_usage::static_draw, vertex_data);
152  model->set_vertex_offset(0);
153  model->set_vertex_stride(vertex_stride);
154 
155  // Free vertex data
156  vertex_data.clear();
157 
158  // Build vertex input attributes
159  std::vector<gl::vertex_input_attribute> attributes(std::popcount(vertex_format_flags));
160 
161  std::uint32_t vertex_offset = 0;
162  std::uint32_t attribute_index = 0;
163 
164  if (vertex_format_flags & vertex_attribute_position)
165  {
166  auto& attribute = attributes[attribute_index];
167  attribute.location = render::vertex_attribute_location::position;
168  attribute.binding = 0;
169  attribute.format = gl::format::r32g32b32_sfloat;
170  attribute.offset = vertex_offset;
171 
172  vertex_offset += 3 * sizeof(float);
173  ++attribute_index;
174  }
175  if (vertex_format_flags & vertex_attribute_uv)
176  {
177  auto& attribute = attributes[attribute_index];
178  attribute.location = render::vertex_attribute_location::uv;
179  attribute.binding = 0;
180  attribute.format = gl::format::r32g32_sfloat;
181  attribute.offset = vertex_offset;
182 
183  vertex_offset += 2 * sizeof(float);
184  ++attribute_index;
185  }
186  if (vertex_format_flags & vertex_attribute_normal)
187  {
188  auto& attribute = attributes[attribute_index];
189  attribute.location = render::vertex_attribute_location::normal;
190  attribute.binding = 0;
191  attribute.format = gl::format::r32g32b32_sfloat;
192  attribute.offset = vertex_offset;
193 
194  vertex_offset += 3 * sizeof(float);
195  ++attribute_index;
196  }
197  if (vertex_format_flags & vertex_attribute_tangent)
198  {
199  auto& attribute = attributes[attribute_index];
200  attribute.location = render::vertex_attribute_location::tangent;
201  attribute.binding = 0;
202  attribute.format = gl::format::r32g32b32a32_sfloat;
203  attribute.offset = vertex_offset;
204 
205  vertex_offset += 4 * sizeof(float);
206  ++attribute_index;
207  }
208  if (vertex_format_flags & vertex_attribute_color)
209  {
210  auto& attribute = attributes[attribute_index];
211  attribute.location = render::vertex_attribute_location::color;
212  attribute.binding = 0;
213  attribute.format = gl::format::r32g32b32a32_sfloat;
214  attribute.offset = vertex_offset;
215 
216  vertex_offset += 4 * sizeof(float);
217  ++attribute_index;
218  }
219  if (vertex_format_flags & vertex_attribute_bone_index)
220  {
221  auto& attribute = attributes[attribute_index];
223  attribute.binding = 0;
224  switch (bones_per_vertex)
225  {
226  case 1:
227  attribute.format = gl::format::r16_uint;
228  break;
229  case 2:
230  attribute.format = gl::format::r16g16_uint;
231  break;
232  case 3:
233  attribute.format = gl::format::r16g16b16_uint;
234  break;
235  case 4:
236  attribute.format = gl::format::r16g16b16a16_uint;
237  break;
238  default:
239  attribute.format = gl::format::undefined;
240  break;
241  }
242  attribute.offset = vertex_offset;
243 
244  vertex_offset += bones_per_vertex * sizeof(std::uint16_t);
245  ++attribute_index;
246  }
247  if (vertex_format_flags & vertex_attribute_bone_weight)
248  {
249  auto& attribute = attributes[attribute_index];
251  attribute.binding = 0;
252  switch (bones_per_vertex)
253  {
254  case 1:
255  attribute.format = gl::format::r32_sfloat;
256  break;
257  case 2:
258  attribute.format = gl::format::r32g32_sfloat;
259  break;
260  case 3:
261  attribute.format = gl::format::r32g32b32_sfloat;
262  break;
263  case 4:
264  attribute.format = gl::format::r32g32b32a32_sfloat;
265  break;
266  default:
267  attribute.format = gl::format::undefined;
268  break;
269  }
270  attribute.offset = vertex_offset;
271 
272  vertex_offset += bones_per_vertex * sizeof(float);
273  ++attribute_index;
274  }
275  if (vertex_format_flags & vertex_attribute_morph_target)
276  {
277  auto& attribute = attributes[attribute_index];
278  attribute.location = render::vertex_attribute_location::target;
279  attribute.binding = 0;
280  attribute.format = gl::format::r32g32b32_sfloat;
281  attribute.offset = vertex_offset;
282 
283  // vertex_offset += 3 * sizeof(float);
284  // ++attribute_index;
285  }
286 
287  // Build model vertex array
288  model->get_vertex_array() = std::make_shared<gl::vertex_array>(attributes);
289 
290  // Read model bounds
291  ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&model->get_bounds()), 6);
292 
293  // Read material count
294  std::uint16_t material_count = 0;
295  ctx.read16<std::endian::little>(reinterpret_cast<std::byte*>(&material_count), 1);
296 
297  // Allocate material groups
298  model->get_groups().resize(material_count);
299 
300  // Read materials
301  for (auto& group: model->get_groups())
302  {
303  // Read material name length
304  std::uint8_t material_name_length = 0;
305  ctx.read8(reinterpret_cast<std::byte*>(&material_name_length), 1);
306 
307  // Read material name
308  std::string material_name(static_cast<std::size_t>(material_name_length), '\0');
309  ctx.read8(reinterpret_cast<std::byte*>(material_name.data()), material_name_length);
310 
311  // Generate group ID by hashing material name
312  group.id = hash::fnv1a32<char>(material_name);
313 
314  // Set group primitive topology
315  group.primitive_topology = gl::primitive_topology::triangle_list;
316 
317  // Read index of first vertex
318  ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&group.first_vertex), 1);
319 
320  // Read vertex count
321  ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&group.vertex_count), 1);
322 
323  // Slugify material filename
324  std::string material_filename = material_name + ".mtl";
325  std::replace(material_filename.begin(), material_filename.end(), '_', '-');
326 
327  // Load group material
328  group.material = resource_manager.load<render::material>(material_filename);
329  }
330 
331  // Read skeleton
332  if ((vertex_format_flags & vertex_attribute_bone_index) || (vertex_format_flags & vertex_attribute_bone_weight))
333  {
334  ::skeleton& skeleton = model->get_skeleton();
335 
336  // Read bone count
337  std::uint16_t bone_count = 0;
338  ctx.read16<std::endian::little>(reinterpret_cast<std::byte*>(&bone_count), 1);
339 
340  // Resize skeleton
341  skeleton.add_bones(bone_count);
342 
343  // Read bones
344  for (std::uint16_t i = 0; i < bone_count; ++i)
345  {
346  // Read bone name
347  hash::fnv1a32_t bone_name = {};
348  ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&bone_name), 1);
349 
350  // Read bone parent index
351  std::uint16_t bone_parent_index = i;
352  ctx.read16<std::endian::little>(reinterpret_cast<std::byte*>(&bone_parent_index), 1);
353 
354  // Construct bone transform
355  bone_transform_type bone_transform;
356 
357  // Read bone translation
358  ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(bone_transform.translation.data()), 3);
359 
360  // Read bone rotation
361  ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&bone_transform.rotation.r), 1);
362  ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(bone_transform.rotation.i.data()), 3);
363 
364  // Set bone scale
365  bone_transform.scale = {1, 1, 1};
366 
367  // Read bone length
368  float bone_length = 0.0f;
369  ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&bone_length), 1);
370 
371  // Set bone properties
372  skeleton.set_bone_name(i, bone_name);
373  skeleton.set_bone_parent(i, bone_parent_index);
374  skeleton.set_bone_transform(i, bone_transform);
375  }
376 
377  // Update skeleton's rest pose
379  }
380 
381  return model;
382 }
A material is associated with exactly one shader program and contains a set of material properties wh...
Definition: material.hpp:37
static std::unique_ptr< T > load(::resource_manager &resource_manager, deserialize_context &ctx)
Loads a resource.
Manages the loading, caching, and saving of resources.
std::shared_ptr< T > load(const std::filesystem::path &path)
Loads and caches a resource.
Skeletal animation skeleton.
Definition: skeleton.hpp:35
void set_bone_transform(bone_index_type index, const bone_transform_type &transform)
Sets the transform of a bone, relative to its parent bone.
Definition: skeleton.hpp:130
bone_index_type add_bones(std::size_t bone_count)
Add one or more bones to the skeleton.
Definition: skeleton.cpp:37
void update_rest_pose()
Updates the rest pose of the skeleton.
Definition: skeleton.cpp:32
void set_bone_parent(bone_index_type child_index, bone_index_type parent_index)
Sets the parent of a bone.
Definition: skeleton.cpp:88
void set_bone_name(bone_index_type index, hash::fnv1a32_t name)
Sets the name of a bone.
Definition: skeleton.cpp:98
constexpr std::uint16_t vertex_attribute_morph_target
Definition: model.cpp:36
constexpr std::uint16_t vertex_attribute_color
Definition: model.cpp:33
constexpr std::uint16_t vertex_attribute_bone_index
Definition: model.cpp:34
constexpr std::uint16_t vertex_attribute_uv
Definition: model.cpp:30
constexpr std::uint16_t vertex_attribute_tangent
Definition: model.cpp:32
constexpr std::uint16_t vertex_attribute_normal
Definition: model.cpp:31
constexpr std::uint16_t vertex_attribute_bone_weight
Definition: model.cpp:35
constexpr std::uint16_t vertex_attribute_position
Definition: model.cpp:29
@ r32g32b32a32_sfloat
@ static_draw
Data will be modified once, by the application, and used many times, for drawing commands.
@ triangle_list
Separate triangle primitives.
@ uv
Vertex UV texture coordinates (vec2)
Provides access to a deserialization state.
std::size_t read16(std::byte *data, std::size_t count) noexcept(false)
Reads 16-bit (word) data.
std::size_t read32(std::byte *data, std::size_t count) noexcept(false)
Reads 32-bit (double word) data.
virtual std::size_t read8(std::byte *data, std::size_t count) noexcept(false)=0
Reads 8-bit (byte) data.
32-bit FNV-1a hash value.
Definition: fnv1a.hpp:117
scalar_type r
Quaternion real part.
Definition: quaternion.hpp:50
vector_type i
Quaternion imaginary part.
Definition: quaternion.hpp:53
vector_type scale
Scale vector.
Definition: transform.hpp:56
vector_type translation
Translation vector.
Definition: transform.hpp:50
quaternion_type rotation
Rotation quaternion.
Definition: transform.hpp:53
constexpr element_type * data() noexcept
Returns a pointer to the element array.
Definition: vector.hpp:152