+ auto shader = CreateShader(vsh, fsh);
+ renderer.SetShader(shader);
+}
+
+void CreateTextureSetsFromGLTF(glTF* gltf, const std::string& basePath, TextureSetContainer& textureSets)
+{
+ const auto& materials = gltf->GetMaterials();
+ const auto& textures = gltf->GetTextures();
+
+ std::map<std::string, Texture> textureCache{};
+
+ for(const auto& material : materials)
+ {
+ TextureSet textureSet;
+ if(material.pbrMetallicRoughness.enabled)
+ {
+ textureSet = TextureSet::New();
+ std::string filename(basePath);
+ filename += '/';
+ filename += textures[material.pbrMetallicRoughness.baseTextureColor.index].uri;
+ Dali::PixelData pixelData = Dali::Toolkit::SyncImageLoader::Load(filename);
+
+ auto cacheKey = textures[material.pbrMetallicRoughness.baseTextureColor.index].uri;
+ auto iter = textureCache.find(cacheKey);
+ Texture texture;
+ if(iter == textureCache.end())
+ {
+ texture = Texture::New(TextureType::TEXTURE_2D, pixelData.GetPixelFormat(), pixelData.GetWidth(), pixelData.GetHeight());
+ texture.Upload(pixelData);
+ texture.GenerateMipmaps();
+ textureCache[cacheKey] = texture;
+ }
+ else
+ {
+ texture = iter->second;
+ }
+ textureSet.SetTexture(0, texture);
+ Dali::Sampler sampler = Dali::Sampler::New();
+ sampler.SetWrapMode(Dali::WrapMode::REPEAT, Dali::WrapMode::REPEAT, Dali::WrapMode::REPEAT);
+ sampler.SetFilterMode(Dali::FilterMode::LINEAR_MIPMAP_LINEAR, Dali::FilterMode::LINEAR);
+ textureSet.SetSampler(0, sampler);
+ }
+ textureSets.emplace_back(textureSet);
+ }
+}
+
+/**
+ * Creates models from glTF
+ */
+void CreateModelsFromGLTF(glTF* gltf, ModelContainer& models)
+{
+ const auto& meshes = gltf->GetMeshes();
+ for(const auto& mesh : meshes)
+ {
+ // change shader to use texture if material indicates that
+ if(mesh->material != 0xffffffff && gltf->GetMaterials()[mesh->material].pbrMetallicRoughness.enabled)
+ {
+ models.emplace_back(CreateModel(*gltf, mesh, VERTEX_SHADER, TEXTURED_FRAGMENT_SHADER));
+ }
+ else
+ {
+ models.emplace_back(CreateModel(*gltf, mesh, VERTEX_SHADER, FRAGMENT_SHADER));
+ }
+ }
+}
+
+Actor CreateSceneFromGLTF(
+ Window window,
+ glTF* gltf,
+ ModelContainer& models,
+ ActorContainer& actors,
+ CameraContainer& cameras,
+ TextureSetContainer& textureSets)
+{
+ const auto& nodes = gltf->GetNodes();
+
+ Vector3 cameraPosition;
+
+ // for each node create nodes and children
+ // resolve parents later
+ actors.reserve(nodes.size());
+ for(const auto& node : nodes)
+ {
+ auto actor = node.cameraId != 0xffffffff ? CameraActor::New(window.GetSize()) : Actor::New();
+
+ actor.SetProperty(Actor::Property::SIZE, Vector3(1, 1, 1));
+ actor.SetProperty(Dali::Actor::Property::NAME, node.name);
+ actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+ actor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+ actor.SetProperty(Actor::Property::POSITION, Vector3(node.translation[0], node.translation[1], node.translation[2]));
+ actor.SetProperty(Actor::Property::SCALE, Vector3(node.scale[0], node.scale[1], node.scale[2]));
+ actor.SetProperty(Actor::Property::ORIENTATION, Quaternion(node.rotationQuaternion[3], node.rotationQuaternion[0], node.rotationQuaternion[1], node.rotationQuaternion[2]));
+
+ actors.emplace_back(actor);
+
+ // Initially add each actor to the very first one
+ if(actors.size() > 1)
+ {
+ actors[0].Add(actor);
+ }
+
+ // If mesh, create and add renderer
+ if(node.meshId != 0xffffffff)
+ {
+ const auto& model = models[node.meshId].get();
+ auto renderer = Renderer::New(model->geometry, model->shader);
+
+ // if textured, add texture set
+ auto materialId = gltf->GetMeshes()[node.meshId]->material;
+ if(materialId != 0xffffffff)
+ {
+ if(gltf->GetMaterials()[materialId].pbrMetallicRoughness.enabled)
+ {
+ renderer.SetTextures(textureSets[materialId]);
+ }
+ }
+
+ actor.AddRenderer(renderer);
+ }
+
+ // Reset and attach main camera
+ if(node.cameraId != 0xffffffff)
+ {
+ cameraPosition = Vector3(node.translation[0], node.translation[1], node.translation[2]);
+ auto quatY = Quaternion(Degree(180.0f), Vector3(0.0, 1.0, 0.0));
+ auto cameraActor = CameraActor::DownCast(actor);
+ cameraActor.SetProperty(Actor::Property::ORIENTATION, Quaternion(node.rotationQuaternion[3], node.rotationQuaternion[0], node.rotationQuaternion[1], node.rotationQuaternion[2]) * quatY);
+ cameraActor.SetProjectionMode(Camera::PERSPECTIVE_PROJECTION);
+
+ const auto camera = gltf->GetCameras()[node.cameraId];
+ cameraActor.SetNearClippingPlane(camera->znear);
+ cameraActor.SetFarClippingPlane(camera->zfar);
+ cameraActor.SetFieldOfView(camera->yfov);
+
+ cameraActor.SetProperty(CameraActor::Property::INVERT_Y_AXIS, true);
+ cameraActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+ cameraActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+ cameras.emplace_back(cameraActor);
+ }
+ }
+
+ // Resolve hierarchy dependencies
+ auto i = 0u;
+ for(const auto& node : nodes)
+ {
+ if(!node.children.empty())
+ {
+ for(const auto& childId : node.children)
+ {
+ actors[i].Add(actors[childId + 1]);
+ }
+ }
+ ++i;
+ }
+
+ for(auto& actor : actors)
+ {
+ actor.RegisterProperty("lightDir", DEFAULT_LIGHT_DIRECTION);
+ actor.RegisterProperty("eyePos", cameraPosition);
+ }
+
+ return actors[0];