15#include "flutter/fml/mapping.h"
16#include "flutter/third_party/tinygltf/tiny_gltf.h"
19#include "impeller/scene/importer/scene_flatbuffers.h"
26static const std::map<std::string, VerticesBuilder::AttributeType>
kAttributes =
36 return index >= 0 &&
static_cast<size_t>(index) <
size;
40 return primitive.attributes.find(
"JOINTS_0") != primitive.attributes.end() &&
41 primitive.attributes.find(
"WEIGHTS_0") != primitive.attributes.end();
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));
skvx::Vec< 4, float > Vec4
virtual const uint8_t * GetMapping() const =0
virtual size_t GetSize() const =0
static std::unique_ptr< VerticesBuilder > MakeUnskinned()
static std::unique_ptr< VerticesBuilder > MakeSkinned()
const uint8_t uint32_t uint32_t GError ** error
sk_sp< const SkImage > image
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
static bool ProcessMeshPrimitive(const tinygltf::Model &gltf, const tinygltf::Primitive &primitive, fb::MeshPrimitiveT &mesh_primitive)
std::unique_ptr< fb::Matrix > ToFBMatrixUniquePtr(const Matrix &m)
fb::Color ToFBColor(const Color c)
static bool MeshPrimitiveIsSkinned(const tinygltf::Primitive &primitive)
Matrix ToMatrix(const std::vector< double > &m)
static void ProcessAnimation(const tinygltf::Model &gltf, const tinygltf::Animation &in_animation, fb::AnimationT &out_animation)
static void ProcessNode(const tinygltf::Model &gltf, const tinygltf::Node &in_node, fb::NodeT &out_node)
bool ParseGLTF(const fml::Mapping &source_mapping, fb::SceneT &out_scene)
static bool WithinRange(int index, size_t size)
static void ProcessTexture(const tinygltf::Model &gltf, const tinygltf::Texture &in_texture, fb::TextureT &out_texture)
fb::Matrix ToFBMatrix(const Matrix &m)
static void ProcessMaterial(const tinygltf::Model &gltf, const tinygltf::Material &in_material, fb::MaterialT &out_material)
static const std::map< std::string, VerticesBuilder::AttributeType > kAttributes
static SkColor4f transform(SkColor4f c, SkColorSpace *src, SkColorSpace *dst)
A 4x4 matrix using column-major storage.
static constexpr Matrix MakeTranslation(const Vector3 &t)
static constexpr Matrix MakeScale(const Vector3 &s)
static Matrix MakeRotation(Quaternion q)