45 const tinygltf::Material& in_material,
46 fb::MaterialT& out_material) {
47 out_material.type = fb::MaterialType::kUnlit;
48 out_material.base_color_factor =
49 ToFBColor(in_material.pbrMetallicRoughness.baseColorFactor);
50 bool base_color_texture_valid =
51 in_material.pbrMetallicRoughness.baseColorTexture.texCoord == 0 &&
52 in_material.pbrMetallicRoughness.baseColorTexture.index >= 0 &&
53 in_material.pbrMetallicRoughness.baseColorTexture.index <
54 static_cast<int32_t
>(gltf.textures.size());
55 out_material.base_color_texture =
56 base_color_texture_valid
59 ? in_material.pbrMetallicRoughness.baseColorTexture.index
64 const tinygltf::Primitive& primitive,
65 fb::MeshPrimitiveT& mesh_primitive) {
72 std::unique_ptr<VerticesBuilder> builder =
76 for (
const auto& attribute : primitive.attributes) {
77 auto attribute_type =
kAttributes.find(attribute.first);
79 std::cerr <<
"Vertex attribute \"" << attribute.first
80 <<
"\" not supported." << std::endl;
85 attribute_type->second ==
92 const auto accessor = gltf.accessors[attribute.second];
93 const auto view = gltf.bufferViews[accessor.bufferView];
95 const auto buffer = gltf.buffers[view.buffer];
96 const unsigned char* source_start = &
buffer.data[view.byteOffset];
99 switch (accessor.componentType) {
100 case TINYGLTF_COMPONENT_TYPE_BYTE:
103 case TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE:
106 case TINYGLTF_COMPONENT_TYPE_SHORT:
109 case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT:
112 case TINYGLTF_COMPONENT_TYPE_INT:
115 case TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT:
118 case TINYGLTF_COMPONENT_TYPE_FLOAT:
122 std::cerr <<
"Skipping attribute \"" << attribute.first
123 <<
"\" due to invalid component type." << std::endl;
127 builder->SetAttributeFromBuffer(
128 attribute_type->second,
131 accessor.ByteStride(view),
135 builder->WriteFBVertices(mesh_primitive);
143 if (!
WithinRange(primitive.indices, gltf.accessors.size())) {
144 std::cerr <<
"Mesh primitive has no index buffer. Skipping." << std::endl;
148 auto index_accessor = gltf.accessors[primitive.indices];
149 auto index_view = gltf.bufferViews[index_accessor.bufferView];
151 auto indices = std::make_unique<fb::IndicesT>();
153 switch (index_accessor.componentType) {
154 case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT:
155 indices->type = fb::IndexType::k16Bit;
157 case TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT:
158 indices->type = fb::IndexType::k32Bit;
161 std::cerr <<
"Mesh primitive has unsupported index type "
162 << index_accessor.componentType <<
". Skipping.";
165 indices->count = index_accessor.count;
166 indices->data.resize(index_view.byteLength);
167 const auto* index_buffer =
168 &gltf.buffers[index_view.buffer].data[index_view.byteOffset];
169 std::memcpy(indices->data.data(), index_buffer, indices->data.size());
171 mesh_primitive.indices = std::move(indices);
179 auto material = std::make_unique<fb::MaterialT>();
180 if (primitive.material >= 0 &&
181 primitive.material <
static_cast<int>(gltf.materials.size())) {
184 material->type = fb::MaterialType::kUnlit;
186 mesh_primitive.material = std::move(material);
193 const tinygltf::Node& in_node,
194 fb::NodeT& out_node) {
195 out_node.name = in_node.name;
196 out_node.children = in_node.children;
203 if (in_node.scale.size() == 3) {
206 static_cast<Scalar>(in_node.scale[1]),
207 static_cast<Scalar>(in_node.scale[2])});
209 if (in_node.rotation.size() == 4) {
211 in_node.rotation[0], in_node.rotation[1],
212 in_node.rotation[2], in_node.rotation[3]));
214 if (in_node.translation.size() == 3) {
216 {
static_cast<Scalar>(in_node.translation[0]),
217 static_cast<Scalar>(in_node.translation[1]),
218 static_cast<Scalar>(in_node.translation[2])});
220 if (in_node.matrix.size() == 16) {
222 std::cerr <<
"The `matrix` attribute of node (name: " << in_node.name
223 <<
") is set in addition to one or more of the "
224 "`translation/rotation/scale` attributes. Using only the "
236 if (
WithinRange(in_node.mesh, gltf.meshes.size())) {
237 auto& mesh = gltf.meshes[in_node.mesh];
238 for (
const auto& primitive : mesh.primitives) {
239 auto mesh_primitive = std::make_unique<fb::MeshPrimitiveT>();
243 out_node.mesh_primitives.push_back(std::move(mesh_primitive));
251 if (
WithinRange(in_node.skin, gltf.skins.size())) {
252 auto& skin = gltf.skins[in_node.skin];
254 auto ipskin = std::make_unique<fb::SkinT>();
255 ipskin->joints = skin.joints;
257 std::vector<fb::Matrix> matrices;
258 auto& matrix_accessor = gltf.accessors[skin.inverseBindMatrices];
259 auto& matrix_view = gltf.bufferViews[matrix_accessor.bufferView];
260 auto& matrix_buffer = gltf.buffers[matrix_view.buffer];
261 for (
size_t matrix_i = 0; matrix_i < matrix_accessor.count; matrix_i++) {
262 auto*
s =
reinterpret_cast<const float*
>(
263 matrix_buffer.data.data() + matrix_view.byteOffset +
264 matrix_accessor.ByteStride(matrix_view) * matrix_i);
266 s[4],
s[5],
s[6],
s[7],
267 s[8],
s[9],
s[10],
s[11],
268 s[12],
s[13],
s[14],
s[15]);
271 ipskin->inverse_bind_matrices = std::move(matrices);
273 ipskin->skeleton = skin.skeleton;
274 out_node.skin = std::move(ipskin);
279 const tinygltf::Texture& in_texture,
280 fb::TextureT& out_texture) {
281 if (!
WithinRange(in_texture.source, gltf.images.size())) {
284 auto&
image = gltf.images[in_texture.source];
286 auto embedded = std::make_unique<fb::EmbeddedImageT>();
287 embedded->bytes =
image.image;
288 size_t bytes_per_component = 0;
289 switch (
image.pixel_type) {
290 case TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE:
291 embedded->component_type = fb::ComponentType::k8Bit;
292 bytes_per_component = 1;
294 case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT:
295 embedded->component_type = fb::ComponentType::k16Bit;
296 bytes_per_component = 2;
299 std::cerr <<
"Texture component type " <<
image.pixel_type
300 <<
" not supported." << std::endl;
303 if (
image.image.size() !=
305 std::cerr <<
"Decompressed texture had unexpected buffer size. Skipping."
309 embedded->component_count =
image.component;
312 out_texture.embedded_image = std::move(embedded);
313 out_texture.uri =
image.uri;
317 const tinygltf::Animation& in_animation,
318 fb::AnimationT& out_animation) {
319 out_animation.name = in_animation.name;
322 std::vector<impeller::fb::ChannelT> translation_channels;
323 std::vector<impeller::fb::ChannelT> rotation_channels;
324 std::vector<impeller::fb::ChannelT> scale_channels;
325 for (
auto& in_channel : in_animation.channels) {
326 auto out_channel = fb::ChannelT();
328 out_channel.node = in_channel.target_node;
329 auto& sampler = in_animation.samplers[in_channel.sampler];
332 auto& times_accessor = gltf.accessors[sampler.input];
333 if (times_accessor.count <= 0) {
337 auto& times_bufferview = gltf.bufferViews[times_accessor.bufferView];
338 auto& times_buffer = gltf.buffers[times_bufferview.buffer];
339 if (times_accessor.componentType != TINYGLTF_COMPONENT_TYPE_FLOAT) {
340 std::cerr <<
"Unexpected component type \""
341 << times_accessor.componentType
342 <<
"\" for animation channel times accessor. Skipping."
346 if (times_accessor.type != TINYGLTF_TYPE_SCALAR) {
347 std::cerr <<
"Unexpected type \"" << times_accessor.type
348 <<
"\" for animation channel times accessor. Skipping."
352 for (
size_t time_i = 0; time_i < times_accessor.count; time_i++) {
353 const float* time_p =
reinterpret_cast<const float*
>(
354 times_buffer.data.data() + times_bufferview.byteOffset +
355 times_accessor.ByteStride(times_bufferview) * time_i);
356 out_channel.timeline.push_back(*time_p);
361 auto& values_accessor = gltf.accessors[sampler.output];
362 if (values_accessor.count != times_accessor.count) {
363 std::cerr <<
"Mismatch between time and value accessors for animation "
369 auto& values_bufferview = gltf.bufferViews[values_accessor.bufferView];
370 auto& values_buffer = gltf.buffers[values_bufferview.buffer];
371 if (values_accessor.componentType != TINYGLTF_COMPONENT_TYPE_FLOAT) {
372 std::cerr <<
"Unexpected component type \""
373 << values_accessor.componentType
374 <<
"\" for animation channel values accessor. Skipping."
378 if (in_channel.target_path ==
"translation") {
379 if (values_accessor.type != TINYGLTF_TYPE_VEC3) {
380 std::cerr <<
"Unexpected type \"" << values_accessor.type
381 <<
"\" for animation channel \"translation\" accessor. "
386 fb::TranslationKeyframesT keyframes;
387 for (
size_t value_i = 0; value_i < values_accessor.count; value_i++) {
388 const float* value_p =
reinterpret_cast<const float*
>(
389 values_buffer.data.data() + values_bufferview.byteOffset +
390 values_accessor.ByteStride(values_bufferview) * value_i);
391 keyframes.values.push_back(
392 fb::Vec3(value_p[0], value_p[1], value_p[2]));
394 out_channel.keyframes.Set(std::move(keyframes));
395 translation_channels.push_back(std::move(out_channel));
396 }
else if (in_channel.target_path ==
"rotation") {
397 if (values_accessor.type != TINYGLTF_TYPE_VEC4) {
398 std::cerr <<
"Unexpected type \"" << values_accessor.type
399 <<
"\" for animation channel \"rotation\" accessor. "
404 fb::RotationKeyframesT keyframes;
405 for (
size_t value_i = 0; value_i < values_accessor.count; value_i++) {
406 const float* value_p =
reinterpret_cast<const float*
>(
407 values_buffer.data.data() + values_bufferview.byteOffset +
408 values_accessor.ByteStride(values_bufferview) * value_i);
409 keyframes.values.push_back(
410 fb::Vec4(value_p[0], value_p[1], value_p[2], value_p[3]));
412 out_channel.keyframes.Set(std::move(keyframes));
413 rotation_channels.push_back(std::move(out_channel));
414 }
else if (in_channel.target_path ==
"scale") {
415 if (values_accessor.type != TINYGLTF_TYPE_VEC3) {
416 std::cerr <<
"Unexpected type \"" << values_accessor.type
417 <<
"\" for animation channel \"scale\" accessor. "
422 fb::ScaleKeyframesT keyframes;
423 for (
size_t value_i = 0; value_i < values_accessor.count; value_i++) {
424 const float* value_p =
reinterpret_cast<const float*
>(
425 values_buffer.data.data() + values_bufferview.byteOffset +
426 values_accessor.ByteStride(values_bufferview) * value_i);
427 keyframes.values.push_back(
428 fb::Vec3(value_p[0], value_p[1], value_p[2]));
430 out_channel.keyframes.Set(std::move(keyframes));
431 scale_channels.push_back(std::move(out_channel));
433 std::cerr <<
"Unsupported animation channel target path \""
434 << in_channel.target_path <<
"\". Skipping." << std::endl;
440 std::vector<std::unique_ptr<impeller::fb::ChannelT>> channels;
441 for (
const auto& channel_list :
442 {translation_channels, rotation_channels, scale_channels}) {
443 for (
const auto& channel : channel_list) {
444 channels.push_back(std::make_unique<fb::ChannelT>(channel));
447 out_animation.channels = std::move(channels);
451 tinygltf::Model gltf;
454 tinygltf::TinyGLTF loader;
457 bool success = loader.LoadBinaryFromMemory(&gltf, &
error, &warning,
460 if (!warning.empty()) {
461 std::cerr <<
"Warning while loading GLTF: " << warning << std::endl;
463 if (!
error.empty()) {
464 std::cerr <<
"Error while loading GLTF: " <<
error << std::endl;
471 const tinygltf::Scene& scene = gltf.scenes[gltf.defaultScene];
472 out_scene.children = scene.nodes;
474 out_scene.transform =
477 for (
size_t texture_i = 0; texture_i < gltf.textures.size(); texture_i++) {
478 auto texture = std::make_unique<fb::TextureT>();
480 out_scene.textures.push_back(std::move(
texture));
483 for (
size_t node_i = 0; node_i < gltf.nodes.size(); node_i++) {
484 auto node = std::make_unique<fb::NodeT>();
486 out_scene.nodes.push_back(std::move(node));
489 for (
size_t animation_i = 0; animation_i < gltf.animations.size();
491 auto animation = std::make_unique<fb::AnimationT>();
493 out_scene.animations.push_back(std::move(animation));
const uint8_t uint32_t uint32_t GError ** error