Fix gltf animation's 0 frame behavior.
[platform/core/uifw/dali-toolkit.git] / automated-tests / src / dali-scene3d / utc-Dali-Gltf2Loader.cpp
index b48ec38..a485f0f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 // Enable debug log for test coverage
 #define DEBUG_ENABLED 1
 
+#include <dali-scene3d/public-api/loader/gltf2-loader.h>
+#include <dali-scene3d/public-api/loader/load-result.h>
+#include <dali-scene3d/public-api/loader/resource-bundle.h>
+#include <dali-scene3d/public-api/loader/scene-definition.h>
+#include <dali-scene3d/public-api/loader/shader-definition-factory.h>
 #include <dali-test-suite-utils.h>
 #include <string_view>
-#include "dali-scene3d/public-api/loader/gltf2-loader.h"
-#include "dali-scene3d/public-api/loader/load-result.h"
-#include "dali-scene3d/public-api/loader/resource-bundle.h"
-#include "dali-scene3d/public-api/loader/scene-definition.h"
-#include "dali-scene3d/public-api/loader/shader-definition-factory.h"
 
 using namespace Dali;
 using namespace Dali::Scene3D::Loader;
@@ -61,6 +61,7 @@ struct Context
 
   ResourceBundle  resources;
   SceneDefinition scene;
+  SceneMetadata   metaData;
 
   std::vector<AnimationDefinition>      animations;
   std::vector<AnimationGroupDefinition> animationGroups;
@@ -70,6 +71,7 @@ struct Context
   LoadResult loadResult{
     resources,
     scene,
+    metaData,
     animations,
     animationGroups,
     cameras,
@@ -100,6 +102,7 @@ int UtcDaliGltfLoaderFailedToLoad(void)
   ShaderDefinitionFactory sdf;
   sdf.SetResources(ctx.resources);
 
+  InitializeGltfLoader();
   DALI_TEST_THROW(LoadGltfScene("non-existent.gltf", sdf, ctx.loadResult),
                   std::runtime_error,
                   ExceptionMessageStartsWith{"Failed to load"});
@@ -128,6 +131,7 @@ int UtcDaliGltfLoaderFailedToParse(void)
   ShaderDefinitionFactory sdf;
   sdf.SetResources(ctx.resources);
 
+  InitializeGltfLoader();
   DALI_TEST_THROW(LoadGltfScene(TEST_RESOURCE_DIR "/invalid.gltf", sdf, ctx.loadResult),
                   std::runtime_error,
                   ExceptionMessageStartsWith{"Failed to parse"});
@@ -153,9 +157,25 @@ int UtcDaliGltfLoaderSuccess1(void)
 {
   Context ctx;
 
+  LoadSceneMetadata(TEST_RESOURCE_DIR "/AnimatedCube.metadata", ctx.metaData);
+
+  std::unordered_map<std::string, ImageMetadata> imageMetadataGroundTruth;
+  imageMetadataGroundTruth["AnimatedCube_BaseColor.png"]         = ImageMetadata{ImageDimensions(256, 256), Dali::SamplingMode::BOX_THEN_NEAREST};
+  imageMetadataGroundTruth["AnimatedCube_MetallicRoughness.png"] = ImageMetadata{ImageDimensions(256, 256), Dali::SamplingMode::NEAREST};
+
+  auto metaData = ctx.metaData.mImageMetadata.begin();
+  for(auto& groundTruth : imageMetadataGroundTruth)
+  {
+    DALI_TEST_EQUAL(groundTruth.first, metaData->first);
+    DALI_TEST_EQUAL(groundTruth.second.mMinSize, metaData->second.mMinSize);
+    DALI_TEST_EQUAL(groundTruth.second.mSamplingMode, metaData->second.mSamplingMode);
+    ++metaData;
+  }
+
   ShaderDefinitionFactory sdf;
   sdf.SetResources(ctx.resources);
 
+  InitializeGltfLoader();
   LoadGltfScene(TEST_RESOURCE_DIR "/AnimatedCube.gltf", sdf, ctx.loadResult);
 
   DALI_TEST_EQUAL(1u, ctx.scene.GetRoots().size());
@@ -164,73 +184,173 @@ int UtcDaliGltfLoaderSuccess1(void)
   // Default envmap is used
   DALI_TEST_EQUAL(1u, ctx.resources.mEnvironmentMaps.size());
 
+  TestApplication app;
+
+  Customization::Choices choices;
+  for(auto iRoot : ctx.scene.GetRoots())
+  {
+    auto resourceRefs = ctx.resources.CreateRefCounter();
+    ctx.scene.CountResourceRefs(iRoot, choices, resourceRefs);
+    ctx.resources.CountEnvironmentReferences(resourceRefs);
+    ctx.resources.LoadResources(resourceRefs, ctx.pathProvider);
+  }
+
   auto& materials = ctx.resources.mMaterials;
   DALI_TEST_EQUAL(2u, materials.size());
   const MaterialDefinition materialGroundTruth[]{
-    {MaterialDefinition::ALBEDO | MaterialDefinition::EMISSIVE | MaterialDefinition::OCCLUSION |
-       MaterialDefinition::NORMAL |
-       (0x80 << MaterialDefinition::ALPHA_CUTOFF_SHIFT),
-     0,
-     Color::WHITE,
-     1.f,
-     0.f,
-     Vector4(1.000, 0.766, 0.336, 1.0),
-     1.f,
-     1.f,
-     Vector3(0.2, 0.1, 0.0),
-     true,
-     false,
-     true,
-     false,
-     {
-       {MaterialDefinition::ALBEDO,
-        {"AnimatedCube_BaseColor.png",
-         SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT)}},
-       {MaterialDefinition::NORMAL,
-        {"AnimatedCube_BaseColor.png",
-         SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT)}},
-       {MaterialDefinition::OCCLUSION,
-        {"AnimatedCube_BaseColor.png",
-         SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT)}},
-       {MaterialDefinition::EMISSIVE,
-        {"AnimatedCube_BaseColor.png",
-         SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT)}},
-     }},
-    {MaterialDefinition::ALBEDO | MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS |
-       MaterialDefinition::EMISSIVE | MaterialDefinition::OCCLUSION |
-       MaterialDefinition::NORMAL | MaterialDefinition::GLTF_CHANNELS,
-     0,
-     Color::WHITE,
-     1.f,
-     0.f,
-     Vector4(1.000, 0.766, 0.336, 1.0),
-     1.f,
-     1.f,
-     Vector3(0.2, 0.1, 0.0),
-     true,
-     true,
-     true,
-     false,
-     {
-       {MaterialDefinition::ALBEDO,
-        {"AnimatedCube_BaseColor.png",
-         SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT)}},
-       {MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS | MaterialDefinition::GLTF_CHANNELS,
-        {"AnimatedCube_MetallicRoughness.png",
-         SamplerFlags::Encode(FilterMode::NEAREST_MIPMAP_LINEAR, FilterMode::NEAREST, WrapMode::CLAMP_TO_EDGE, WrapMode::MIRRORED_REPEAT)}},
-       {MaterialDefinition::NORMAL,
-        {"AnimatedCube_BaseColor.png",
-         SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT)}},
-       {MaterialDefinition::OCCLUSION,
-        {"AnimatedCube_BaseColor.png",
-         SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT)}},
-       {MaterialDefinition::EMISSIVE,
-        {"AnimatedCube_BaseColor.png",
-         SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT)}},
-     }},
+    {
+      nullptr,
+      MaterialDefinition::ALBEDO | MaterialDefinition::EMISSIVE | MaterialDefinition::OCCLUSION |
+        MaterialDefinition::NORMAL | MaterialDefinition::SPECULAR | MaterialDefinition::SPECULAR_COLOR |
+        (0x80 << MaterialDefinition::ALPHA_CUTOFF_SHIFT),
+      0,
+      Color::WHITE,
+      1.f,
+      0.f,
+      Vector4(1.000, 0.766, 0.336, 1.0),
+      1.f,
+      1.f,
+      Vector3(0.2, 0.1, 0.0),
+      0.0f,
+      0.5f,
+      Vector3(0, 0, 1),
+      true,
+      false,
+      true,
+      false,
+      true,
+      true,
+      {
+        {
+          MaterialDefinition::ALBEDO,
+          {
+            "AnimatedCube_BaseColor.png",
+            SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
+            ImageDimensions(256, 256),
+            SamplingMode::BOX_THEN_NEAREST,
+          },
+        },
+        {
+          MaterialDefinition::NORMAL,
+          {
+            "AnimatedCube_BaseColor.png",
+            SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
+            ImageDimensions(256, 256),
+            SamplingMode::BOX_THEN_NEAREST,
+          },
+        },
+        {
+          MaterialDefinition::OCCLUSION,
+          {
+            "AnimatedCube_BaseColor.png",
+            SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
+            ImageDimensions(256, 256),
+            SamplingMode::BOX_THEN_NEAREST,
+          },
+        },
+        {
+          MaterialDefinition::EMISSIVE,
+          {
+            "AnimatedCube_BaseColor.png",
+            SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
+            ImageDimensions(256, 256),
+            SamplingMode::BOX_THEN_NEAREST,
+          },
+        },
+        {
+          MaterialDefinition::SPECULAR,
+          {
+            "AnimatedCube_BaseColor.png",
+            SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
+            ImageDimensions(256, 256),
+            SamplingMode::BOX_THEN_NEAREST,
+          },
+        },
+        {
+          MaterialDefinition::SPECULAR_COLOR,
+          {
+            "AnimatedCube_BaseColor.png",
+            SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
+            ImageDimensions(256, 256),
+            SamplingMode::BOX_THEN_NEAREST,
+          },
+        },
+      },
+    },
+    {
+      nullptr,
+      MaterialDefinition::ALBEDO | MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS |
+        MaterialDefinition::EMISSIVE | MaterialDefinition::OCCLUSION | MaterialDefinition::NORMAL |
+        MaterialDefinition::GLTF_CHANNELS,
+      0,
+      Color::WHITE,
+      1.f,
+      0.f,
+      Vector4(1.000, 0.766, 0.336, 1.0),
+      1.f,
+      1.f,
+      Vector3(0.2, 0.1, 0.0),
+      0.04f,
+      1.0f,
+      Vector3::ONE,
+      true,
+      true,
+      true,
+      false,
+      true,
+      false,
+      {
+        {
+          MaterialDefinition::ALBEDO,
+          {
+            "AnimatedCube_BaseColor.png",
+            SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
+            ImageDimensions(256, 256),
+            SamplingMode::BOX_THEN_NEAREST,
+          },
+        },
+        {
+          MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS | MaterialDefinition::GLTF_CHANNELS,
+          {
+            "AnimatedCube_MetallicRoughness.png",
+            SamplerFlags::Encode(FilterMode::NEAREST_MIPMAP_LINEAR, FilterMode::NEAREST, WrapMode::CLAMP_TO_EDGE, WrapMode::MIRRORED_REPEAT),
+            ImageDimensions(256, 256),
+            SamplingMode::NEAREST,
+          },
+        },
+        {
+          MaterialDefinition::NORMAL,
+          {
+            "AnimatedCube_BaseColor.png",
+            SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
+            ImageDimensions(256, 256),
+            SamplingMode::BOX_THEN_NEAREST,
+          },
+        },
+        {
+          MaterialDefinition::OCCLUSION,
+          {
+            "AnimatedCube_BaseColor.png",
+            SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
+            ImageDimensions(256, 256),
+            SamplingMode::BOX_THEN_NEAREST,
+          },
+        },
+        {
+          MaterialDefinition::EMISSIVE,
+          {
+            "AnimatedCube_BaseColor.png",
+            SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
+            ImageDimensions(256, 256),
+            SamplingMode::BOX_THEN_NEAREST,
+          },
+        },
+      },
+    },
   };
 
   auto iMaterial = materials.begin();
+  auto iMetadata = ctx.metaData.mImageMetadata.begin();
   for(auto& m : materialGroundTruth)
   {
     printf("material %ld\n", iMaterial - materials.begin());
@@ -244,9 +364,14 @@ int UtcDaliGltfLoaderSuccess1(void)
     DALI_TEST_EQUAL(md.mNormalScale, m.mNormalScale);
     DALI_TEST_EQUAL(md.mOcclusionStrength, m.mOcclusionStrength);
     DALI_TEST_EQUAL(md.mEmissiveFactor, m.mEmissiveFactor);
+    DALI_TEST_EQUAL(md.mDielectricSpecular, m.mDielectricSpecular);
+    DALI_TEST_EQUAL(md.mSpecularFactor, m.mSpecularFactor);
+    DALI_TEST_EQUAL(md.mSpecularColorFactor, m.mSpecularColorFactor);
     DALI_TEST_EQUAL(md.mNeedAlbedoTexture, m.mNeedAlbedoTexture);
     DALI_TEST_EQUAL(md.mNeedMetallicRoughnessTexture, m.mNeedMetallicRoughnessTexture);
     DALI_TEST_EQUAL(md.mNeedNormalTexture, m.mNeedNormalTexture);
+    DALI_TEST_EQUAL(md.mIsOpaque, m.mIsOpaque);
+    DALI_TEST_EQUAL(md.mIsMask, m.mIsMask);
 
     DALI_TEST_EQUAL(md.mTextureStages.size(), m.mTextureStages.size());
     auto iTexture = md.mTextureStages.begin();
@@ -256,9 +381,13 @@ int UtcDaliGltfLoaderSuccess1(void)
       DALI_TEST_EQUAL(iTexture->mSemantic, ts.mSemantic);
       DALI_TEST_EQUAL(iTexture->mTexture.mImageUri, ts.mTexture.mImageUri);
       DALI_TEST_EQUAL(uint32_t(iTexture->mTexture.mSamplerFlags), uint32_t(ts.mTexture.mSamplerFlags)); // don't interpret it as a character
+      DALI_TEST_EQUAL(iTexture->mTexture.mMinImageDimensions, ts.mTexture.mMinImageDimensions);
+      DALI_TEST_EQUAL(iTexture->mTexture.mSamplingMode, ts.mTexture.mSamplingMode);
+
       ++iTexture;
     }
     ++iMaterial;
+    ++iMetadata;
   }
 
   auto& meshes = ctx.resources.mMeshes;
@@ -268,6 +397,7 @@ int UtcDaliGltfLoaderSuccess1(void)
   using Accessor = MeshDefinition::Accessor;
   const MeshDefinition meshGroundTruth[]{
     {
+      nullptr,
       0,
       Geometry::TRIANGLES,
       "AnimatedCube.bin",
@@ -279,6 +409,7 @@ int UtcDaliGltfLoaderSuccess1(void)
       Accessor{Blob{0, 0}, {}},
     },
     {
+      nullptr,
       0,
       Geometry::TRIANGLES,
       "AnimatedCube.bin",
@@ -329,6 +460,34 @@ int UtcDaliGltfLoaderSuccess1(void)
   END_TEST;
 }
 
+int UtcDaliGltfLoaderSuccess2(void)
+{
+  Context                 ctx;
+  ShaderDefinitionFactory sdf;
+  sdf.SetResources(ctx.resources);
+
+  InitializeGltfLoader();
+  LoadGltfScene(TEST_RESOURCE_DIR "/AnimatedCubeStride.gltf", sdf, ctx.loadResult);
+
+  DALI_TEST_EQUAL(1u, ctx.scene.GetRoots().size());
+  DALI_TEST_EQUAL(1u, ctx.scene.GetNodeCount());
+
+  TestApplication app;
+
+  Customization::Choices choices;
+  for(auto iRoot : ctx.scene.GetRoots())
+  {
+    auto resourceRefs = ctx.resources.CreateRefCounter();
+    ctx.scene.CountResourceRefs(iRoot, choices, resourceRefs);
+    ctx.resources.LoadResources(resourceRefs, ctx.pathProvider);
+  }
+
+  DALI_TEST_EQUAL(true, ctx.resources.mMeshes[0u].first.mPositions.IsDefined());
+  DALI_TEST_EQUAL(432, ctx.resources.mMeshes[0u].first.mPositions.mBlob.mLength);
+
+  END_TEST;
+}
+
 int UtcDaliGltfLoaderSuccessShort(void)
 {
   TestApplication app;
@@ -342,6 +501,7 @@ int UtcDaliGltfLoaderSuccessShort(void)
   for(auto modelName : {
         "2CylinderEngine",
         "AnimatedMorphCube",
+        "AnimatedMorphCubeAnimateNonZeroFrame",
         "AnimatedMorphSphere",
         "AnimatedTriangle",
         "BoxAnimated",
@@ -365,6 +525,7 @@ int UtcDaliGltfLoaderSuccessShort(void)
     sdf.SetResources(resources);
 
     printf("%s\n", modelName);
+    InitializeGltfLoader();
     LoadGltfScene(resourcePath + modelName + ".gltf", sdf, ctx.loadResult);
     DALI_TEST_CHECK(ctx.scene.GetNodeCount() > 0);
 
@@ -405,7 +566,7 @@ int UtcDaliGltfLoaderSuccessShort(void)
       {
         if(visitor.receiver.mCounts[i0])
         {
-          auto raw = resources.mMeshes[i0].first.LoadRaw(resourcePath);
+          auto raw = resources.mMeshes[i0].first.LoadRaw(resourcePath, resources.mBuffers);
           DALI_TEST_CHECK(!raw.mAttribs.empty());
 
           resources.mMeshes[i0].second = resources.mMeshes[i0].first.Load(std::move(raw));
@@ -426,6 +587,7 @@ int UtcDaliGltfLoaderMRendererTest(void)
   sdf.SetResources(ctx.resources);
   auto& resources = ctx.resources;
 
+  InitializeGltfLoader();
   LoadGltfScene(TEST_RESOURCE_DIR "/MRendererTest.gltf", sdf, ctx.loadResult);
 
   auto& scene = ctx.scene;
@@ -474,5 +636,166 @@ int UtcDaliGltfLoaderMRendererTest(void)
   DALI_TEST_EQUAL(child.GetRendererCount(), 1u);
   DALI_TEST_EQUAL(child.GetRendererAt(0).GetTextures().GetTextureCount(), 4u);
 
+  DALI_TEST_EQUAL(child.GetRendererCount(), 1u);
+  DALI_TEST_EQUAL(child.GetRendererAt(0u).GetProperty<decltype(BlendMode::ON)>(Renderer::Property::BLEND_MODE), BlendMode::ON);
+
+  END_TEST;
+}
+
+int UtcDaliGltfLoaderAnimationLoadingTest(void)
+{
+  Context ctx;
+
+  ShaderDefinitionFactory sdf;
+  sdf.SetResources(ctx.resources);
+  auto& resources = ctx.resources;
+
+  InitializeGltfLoader();
+  LoadGltfScene(TEST_RESOURCE_DIR "/CesiumMan_e.gltf", sdf, ctx.loadResult);
+
+  auto& scene = ctx.scene;
+  auto& roots = scene.GetRoots();
+  DALI_TEST_EQUAL(roots.size(), 1u);
+
+  ViewProjection viewProjection;
+  Transforms     xforms{
+    MatrixStack{},
+    viewProjection};
+  NodeDefinition::CreateParams nodeParams{
+    resources,
+    xforms,
+  };
+
+  Customization::Choices choices;
+
+  TestApplication app;
+
+  Actor root = Actor::New();
+  SetActorCentered(root);
+  for(auto iRoot : roots)
+  {
+    auto resourceRefs = resources.CreateRefCounter();
+    scene.CountResourceRefs(iRoot, choices, resourceRefs);
+    resources.CountEnvironmentReferences(resourceRefs);
+    resources.LoadResources(resourceRefs, ctx.pathProvider);
+    if(auto actor = scene.CreateNodes(iRoot, choices, nodeParams))
+    {
+      scene.ConfigureSkeletonJoints(iRoot, resources.mSkeletons, actor);
+      scene.ConfigureSkinningShaders(resources, actor, std::move(nodeParams.mSkinnables));
+      scene.ApplyConstraints(actor, std::move(nodeParams.mConstrainables));
+      root.Add(actor);
+    }
+  }
+
+  DALI_TEST_EQUAL(ctx.loadResult.mAnimationDefinitions.size(), 1u);
+  DALI_TEST_EQUAL(ctx.loadResult.mAnimationDefinitions[0].mProperties.size(), 57u);
+
+  uint32_t id = ctx.loadResult.mScene.GetNode(ctx.loadResult.mAnimationDefinitions[0].mProperties[0].mNodeIndex)->mNodeId;
+  DALI_TEST_EQUAL(id, root.FindChildByName("Skeleton_torso_joint_1").GetProperty<int32_t>(Dali::Actor::Property::ID));
+
+  END_TEST;
+}
+
+int UtcDaliGltfLoaderImageFromBufferView(void)
+{
+  Context ctx;
+
+  ShaderDefinitionFactory sdf;
+  sdf.SetResources(ctx.resources);
+  auto& resources = ctx.resources;
+
+  InitializeGltfLoader();
+  LoadGltfScene(TEST_RESOURCE_DIR "/EnvironmentTest_b.gltf", sdf, ctx.loadResult);
+
+  auto& scene = ctx.scene;
+  auto& roots = scene.GetRoots();
+  DALI_TEST_EQUAL(roots.size(), 1u);
+
+  ViewProjection viewProjection;
+  Transforms     xforms{
+    MatrixStack{},
+    viewProjection};
+  NodeDefinition::CreateParams nodeParams{
+    resources,
+    xforms,
+  };
+
+  Customization::Choices choices;
+
+  TestApplication app;
+
+  Actor root = Actor::New();
+  SetActorCentered(root);
+  for(auto iRoot : roots)
+  {
+    auto resourceRefs = resources.CreateRefCounter();
+    scene.CountResourceRefs(iRoot, choices, resourceRefs);
+    resources.CountEnvironmentReferences(resourceRefs);
+    resources.LoadResources(resourceRefs, ctx.pathProvider);
+    if(auto actor = scene.CreateNodes(iRoot, choices, nodeParams))
+    {
+      scene.ConfigureSkeletonJoints(iRoot, resources.mSkeletons, actor);
+      scene.ConfigureSkinningShaders(resources, actor, std::move(nodeParams.mSkinnables));
+      scene.ApplyConstraints(actor, std::move(nodeParams.mConstrainables));
+      root.Add(actor);
+    }
+  }
+
+  DALI_TEST_CHECK(resources.mMaterials[0].second.GetTextureCount() > 1);
+  DALI_TEST_EQUAL(resources.mMaterials[0].second.GetTexture(0).GetWidth(), 256);
+  DALI_TEST_EQUAL(resources.mMaterials[0].second.GetTexture(0).GetHeight(), 256);
+
+  END_TEST;
+}
+
+int UtcDaliGltfLoaderUint8Indices(void)
+{
+  Context ctx;
+
+  ShaderDefinitionFactory sdf;
+  sdf.SetResources(ctx.resources);
+  auto& resources = ctx.resources;
+
+  InitializeGltfLoader();
+  LoadGltfScene(TEST_RESOURCE_DIR "/AlphaBlendModeTest.gltf", sdf, ctx.loadResult);
+
+  auto& scene = ctx.scene;
+  auto& roots = scene.GetRoots();
+  DALI_TEST_EQUAL(roots.size(), 1u);
+
+  ViewProjection viewProjection;
+  Transforms     xforms{
+    MatrixStack{},
+    viewProjection};
+  NodeDefinition::CreateParams nodeParams{
+    resources,
+    xforms,
+  };
+
+  Customization::Choices choices;
+
+  TestApplication app;
+
+  Actor root = Actor::New();
+  SetActorCentered(root);
+  for(auto iRoot : roots)
+  {
+    auto resourceRefs = resources.CreateRefCounter();
+    scene.CountResourceRefs(iRoot, choices, resourceRefs);
+    resources.CountEnvironmentReferences(resourceRefs);
+    resources.LoadResources(resourceRefs, ctx.pathProvider);
+    if(auto actor = scene.CreateNodes(iRoot, choices, nodeParams))
+    {
+      scene.ConfigureSkeletonJoints(iRoot, resources.mSkeletons, actor);
+      scene.ConfigureSkinningShaders(resources, actor, std::move(nodeParams.mSkinnables));
+      scene.ApplyConstraints(actor, std::move(nodeParams.mConstrainables));
+      root.Add(actor);
+    }
+  }
+
+  DALI_TEST_CHECK(root.FindChildByName("Bed"));
+  DALI_TEST_CHECK(root.FindChildByName("DecalBlend"));
+  DALI_TEST_CHECK(root.FindChildByName("DecalOpaque"));
+
   END_TEST;
 }