[dali_2.2.4] Merge branch 'devel/master' 13/285013/1
authorAdam Bialogonski <adam.b@samsung.com>
Fri, 2 Dec 2022 10:25:12 +0000 (10:25 +0000)
committerAdam Bialogonski <adam.b@samsung.com>
Fri, 2 Dec 2022 10:25:12 +0000 (10:25 +0000)
Change-Id: I50336b06337e32ff656e759a6f3ee50ca560bba9

58 files changed:
automated-tests/resources/AnimatedCube.gltf
automated-tests/resources/simpleMultiplePrimitiveTest.gltf [new file with mode: 0644]
automated-tests/src/dali-scene3d/utc-Dali-Gltf2Loader.cpp
automated-tests/src/dali-scene3d/utc-Dali-Model.cpp
automated-tests/src/dali-scene3d/utc-Dali-NodeDefinition.cpp
automated-tests/src/dali-scene3d/utc-Dali-SceneView.cpp
automated-tests/src/dali-scene3d/utc-Dali-ShaderDefinitionFactory.cpp
automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/toolkit-text-utils.cpp
automated-tests/src/dali-toolkit-internal/utc-Dali-Text-CharacterSpacing.cpp
automated-tests/src/dali-toolkit-internal/utc-Dali-Text-Layout.cpp
automated-tests/src/dali-toolkit-internal/utc-Dali-Visuals-internal.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-gl-abstraction.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-gl-abstraction.h
automated-tests/src/dali-toolkit/utc-Dali-AnimatedImageVisual.cpp
automated-tests/src/dali-toolkit/utc-Dali-TextField.cpp
dali-scene3d/internal/controls/scene-view/scene-view-impl.cpp
dali-scene3d/internal/controls/scene-view/scene-view-impl.h
dali-scene3d/internal/graphics/shaders/default-physically-based-shader.frag
dali-scene3d/internal/graphics/shaders/scene3d-joint-debug.frag
dali-scene3d/internal/graphics/shaders/skybox-shader.frag
dali-scene3d/internal/loader/gltf2-asset.h
dali-scene3d/public-api/loader/dli-loader.cpp
dali-scene3d/public-api/loader/gltf2-loader.cpp
dali-scene3d/public-api/loader/material-definition.cpp
dali-scene3d/public-api/loader/material-definition.h
dali-scene3d/public-api/loader/node-definition.cpp
dali-scene3d/public-api/loader/node-definition.h
dali-scene3d/public-api/loader/scene-definition.cpp
dali-scene3d/public-api/loader/shader-definition-factory.cpp
dali-scene3d/public-api/loader/shader-definition-factory.h
dali-toolkit/devel-api/text/text-utils-devel.cpp
dali-toolkit/internal/image-loader/async-image-loader-impl.cpp
dali-toolkit/internal/image-loader/async-image-loader-impl.h
dali-toolkit/internal/image-loader/loading-task.cpp
dali-toolkit/internal/image-loader/loading-task.h
dali-toolkit/internal/text/controller/text-controller-impl-model-updater.cpp
dali-toolkit/internal/text/controller/text-controller-relayouter.cpp
dali-toolkit/internal/text/hidden-text.cpp
dali-toolkit/internal/text/hidden-text.h
dali-toolkit/internal/text/layouts/layout-engine.cpp
dali-toolkit/internal/text/layouts/layout-engine.h
dali-toolkit/internal/texture-manager/texture-async-loading-helper.cpp
dali-toolkit/internal/texture-manager/texture-async-loading-helper.h
dali-toolkit/internal/texture-manager/texture-manager-impl.cpp
dali-toolkit/internal/texture-manager/texture-manager-impl.h
dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp
dali-toolkit/internal/visuals/animated-image/animated-image-visual.h
dali-toolkit/internal/visuals/animated-image/fixed-image-cache.cpp
dali-toolkit/internal/visuals/animated-image/fixed-image-cache.h
dali-toolkit/internal/visuals/animated-image/image-cache.cpp
dali-toolkit/internal/visuals/animated-image/image-cache.h
dali-toolkit/internal/visuals/animated-image/rolling-animated-image-cache.cpp
dali-toolkit/internal/visuals/animated-image/rolling-animated-image-cache.h
dali-toolkit/internal/visuals/animated-image/rolling-image-cache.cpp
dali-toolkit/internal/visuals/animated-image/rolling-image-cache.h
dali-toolkit/internal/visuals/visual-factory-impl.cpp
dali-toolkit/public-api/dali-toolkit-version.cpp
packaging/dali-toolkit.spec

index 995d3b1..455120d 100644 (file)
@@ -1,4 +1,9 @@
 {
+   "extensionsUsed" : [
+       "KHR_materials_specular",
+       "KHR_materials_ior"
+   ],
+
    "accessors" : [
       {
          "bufferView" : 0,
    ],
    "materials" : [
       {
+         "extensions" : {
+            "KHR_materials_specular" : {
+               "specularColorFactor" : [
+                  0,
+                  0,
+                  1
+               ],
+               "specularFactor" : 0.5,
+               "specularTexture": {
+                "index": 0
+               },
+               "specularColorTexture": {
+                "index": 0
+               }
+             },
+             "KHR_materials_ior" : {
+                 "ior" : 1.0
+             }
+         },
          "name" : "AnimatedCube",
          "pbrMetallicRoughness" : {
             "baseColorTexture" : {
diff --git a/automated-tests/resources/simpleMultiplePrimitiveTest.gltf b/automated-tests/resources/simpleMultiplePrimitiveTest.gltf
new file mode 100644 (file)
index 0000000..9345fbe
--- /dev/null
@@ -0,0 +1,109 @@
+{\r
+  "scene" : 0,\r
+  "scenes" : [\r
+    {\r
+      "nodes" : [ 0 ]\r
+    }\r
+  ],\r
+\r
+  "nodes" : [\r
+    {\r
+      "name" : "rootNode",\r
+      "mesh" : 0,\r
+      "rotation" : [ 0.0, 0.0, 0.0, 1.0 ]\r
+    }\r
+  ],\r
+\r
+  "meshes" : [\r
+    {\r
+      "primitives" : [\r
+        {\r
+          "attributes" : {\r
+            "POSITION" : 1\r
+          },\r
+          "indices" : 0\r
+        },\r
+        {\r
+          "attributes" : {\r
+            "POSITION" : 1\r
+          },\r
+          "indices" : 0\r
+        }\r
+      ]\r
+    }\r
+  ],\r
+\r
+  "buffers" : [\r
+    {\r
+      "uri" : "simpleTriangle.bin",\r
+      "byteLength" : 44\r
+    },\r
+    {\r
+      "uri" : "animation.bin",\r
+      "byteLength" : 100\r
+    }\r
+  ],\r
+\r
+  "bufferViews" : [\r
+    {\r
+      "buffer" : 0,\r
+      "byteOffset" : 0,\r
+      "byteLength" : 6,\r
+      "target" : 34963\r
+    },\r
+    {\r
+      "buffer" : 0,\r
+      "byteOffset" : 8,\r
+      "byteLength" : 36,\r
+      "target" : 34962\r
+    },\r
+    {\r
+      "buffer" : 1,\r
+      "byteOffset" : 0,\r
+      "byteLength" : 100\r
+    }\r
+  ],\r
+\r
+  "accessors" : [\r
+    {\r
+      "bufferView" : 0,\r
+      "byteOffset" : 0,\r
+      "componentType" : 5123,\r
+      "count" : 3,\r
+      "type" : "SCALAR",\r
+      "max" : [ 2 ],\r
+      "min" : [ 0 ]\r
+    },\r
+    {\r
+      "bufferView" : 1,\r
+      "byteOffset" : 0,\r
+      "componentType" : 5126,\r
+      "count" : 3,\r
+      "type" : "VEC3",\r
+      "max" : [ 1.0, 1.0, 0.0 ],\r
+      "min" : [ 0.0, 0.0, 0.0 ]\r
+    },\r
+    {\r
+      "bufferView" : 2,\r
+      "byteOffset" : 0,\r
+      "componentType" : 5126,\r
+      "count" : 5,\r
+      "type" : "SCALAR",\r
+      "max" : [ 1.0 ],\r
+      "min" : [ 0.0 ]\r
+    },\r
+    {\r
+      "bufferView" : 2,\r
+      "byteOffset" : 20,\r
+      "componentType" : 5126,\r
+      "count" : 5,\r
+      "type" : "VEC4",\r
+      "max" : [ 0.0, 0.0, 1.0, 1.0 ],\r
+      "min" : [ 0.0, 0.0, 0.0, -0.707 ]\r
+    }\r
+  ],\r
+\r
+  "asset" : {\r
+    "version" : "2.0"\r
+  }\r
+}\r
index a9ba508..d6687c5 100644 (file)
@@ -168,7 +168,7 @@ int UtcDaliGltfLoaderSuccess1(void)
   DALI_TEST_EQUAL(2u, materials.size());
   const MaterialDefinition materialGroundTruth[]{
     {MaterialDefinition::ALBEDO | MaterialDefinition::EMISSIVE | MaterialDefinition::OCCLUSION |
-       MaterialDefinition::NORMAL | MaterialDefinition::TRANSPARENCY |
+       MaterialDefinition::NORMAL | MaterialDefinition::SPECULAR | MaterialDefinition::SPECULAR_COLOR |
        (0x80 << MaterialDefinition::ALPHA_CUTOFF_SHIFT),
      0,
      Color::WHITE,
@@ -178,9 +178,13 @@ int UtcDaliGltfLoaderSuccess1(void)
      1.f,
      1.f,
      Vector3(0.2, 0.1, 0.0),
+     0.0f,
+     0.5f,
+     Vector3(0, 0, 1),
      true,
      false,
      true,
+     false,
      {
        {MaterialDefinition::ALBEDO,
         {"AnimatedCube_BaseColor.png",
@@ -194,6 +198,12 @@ int UtcDaliGltfLoaderSuccess1(void)
        {MaterialDefinition::EMISSIVE,
         {"AnimatedCube_BaseColor.png",
          SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT)}},
+       {MaterialDefinition::SPECULAR,
+        {"AnimatedCube_BaseColor.png",
+         SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT)}},
+       {MaterialDefinition::SPECULAR_COLOR,
+        {"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 |
@@ -206,9 +216,13 @@ int UtcDaliGltfLoaderSuccess1(void)
      1.f,
      1.f,
      Vector3(0.2, 0.1, 0.0),
+     0.04f,
+     1.0f,
+     Vector3::ONE,
      true,
      true,
      true,
+     false,
      {
        {MaterialDefinition::ALBEDO,
         {"AnimatedCube_BaseColor.png",
@@ -242,6 +256,9 @@ 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);
@@ -386,9 +403,9 @@ int UtcDaliGltfLoaderSuccessShort(void)
 
         void Start(NodeDefinition& n) override
         {
-          if(n.mRenderable)
+          for(auto& renderable : n.mRenderables)
           {
-            n.mRenderable->RegisterResources(receiver);
+            renderable->RegisterResources(receiver);
           }
         }
 
index 25d2624..7d92024 100644 (file)
@@ -47,9 +47,10 @@ const bool DEFAULT_MODEL_CHILDREN_FOCUSABLE = false;
  * Donated by Norbert Nopper for glTF testing.
  * Take from https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/AnimatedCube
  */
-const char* TEST_GLTF_FILE_NAME                = TEST_RESOURCE_DIR "/AnimatedCube.gltf";
-const char* TEST_GLTF_ANIMATION_TEST_FILE_NAME = TEST_RESOURCE_DIR "/animationTest.gltf";
-const char* TEST_DLI_FILE_NAME                 = TEST_RESOURCE_DIR "/arc.dli";
+const char* TEST_GLTF_FILE_NAME                    = TEST_RESOURCE_DIR "/AnimatedCube.gltf";
+const char* TEST_GLTF_ANIMATION_TEST_FILE_NAME     = TEST_RESOURCE_DIR "/animationTest.gltf";
+const char* TEST_GLTF_MULTIPLE_PRIMITIVE_FILE_NAME = TEST_RESOURCE_DIR "/simpleMultiplePrimitiveTest.gltf";
+const char* TEST_DLI_FILE_NAME                     = TEST_RESOURCE_DIR "/arc.dli";
 /**
  * For the diffuse and specular cube map texture.
  * These textures are based off version of Wave engine sample
@@ -338,15 +339,15 @@ int UtcDaliModelSetImageBasedLightSource01(void)
   DALI_TEST_CHECK(renderer);
 
   TextureSet textureSet = renderer.GetTextures();
-  DALI_TEST_EQUALS(textureSet.GetTextureCount(), 7u, TEST_LOCATION);
+  DALI_TEST_EQUALS(textureSet.GetTextureCount(), 9u, TEST_LOCATION);
 
-  Texture diffuseTexture  = textureSet.GetTexture(5u);
-  Texture specularTexture = textureSet.GetTexture(6u);
+  Texture diffuseTexture  = textureSet.GetTexture(7u);
+  Texture specularTexture = textureSet.GetTexture(8u);
 
   model.SetImageBasedLightSource(TEST_DIFFUSE_TEXTURE, TEST_SPECULAR_TEXTURE);
 
-  Texture newDiffuseTexture  = textureSet.GetTexture(5u);
-  Texture newSpecularTexture = textureSet.GetTexture(6u);
+  Texture newDiffuseTexture  = textureSet.GetTexture(7u);
+  Texture newSpecularTexture = textureSet.GetTexture(8u);
 
   DALI_TEST_NOT_EQUALS(diffuseTexture, newDiffuseTexture, 0.0f, TEST_LOCATION);
   DALI_TEST_NOT_EQUALS(specularTexture, newSpecularTexture, 0.0f, TEST_LOCATION);
@@ -372,15 +373,15 @@ int UtcDaliModelSetImageBasedLightSource02(void)
   DALI_TEST_CHECK(renderer);
 
   TextureSet textureSet = renderer.GetTextures();
-  DALI_TEST_EQUALS(textureSet.GetTextureCount(), 7u, TEST_LOCATION);
+  DALI_TEST_EQUALS(textureSet.GetTextureCount(), 9u, TEST_LOCATION);
 
-  Texture diffuseTexture  = textureSet.GetTexture(5u);
-  Texture specularTexture = textureSet.GetTexture(6u);
+  Texture diffuseTexture  = textureSet.GetTexture(7u);
+  Texture specularTexture = textureSet.GetTexture(8u);
 
   model.SetImageBasedLightSource("", "");
 
-  Texture newDiffuseTexture  = textureSet.GetTexture(5u);
-  Texture newSpecularTexture = textureSet.GetTexture(6u);
+  Texture newDiffuseTexture  = textureSet.GetTexture(7u);
+  Texture newSpecularTexture = textureSet.GetTexture(8u);
 
   DALI_TEST_EQUALS(diffuseTexture, newDiffuseTexture, TEST_LOCATION);
   DALI_TEST_EQUALS(specularTexture, newSpecularTexture, TEST_LOCATION);
@@ -406,15 +407,15 @@ int UtcDaliModelSetImageBasedLightSource03(void)
   DALI_TEST_CHECK(renderer);
 
   TextureSet textureSet = renderer.GetTextures();
-  DALI_TEST_EQUALS(textureSet.GetTextureCount(), 7u, TEST_LOCATION);
+  DALI_TEST_EQUALS(textureSet.GetTextureCount(), 9u, TEST_LOCATION);
 
-  Texture diffuseTexture  = textureSet.GetTexture(5u);
-  Texture specularTexture = textureSet.GetTexture(6u);
+  Texture diffuseTexture  = textureSet.GetTexture(7u);
+  Texture specularTexture = textureSet.GetTexture(8u);
 
   model.SetImageBasedLightSource("dummy.ktx", "dummy.ktx");
 
-  Texture newDiffuseTexture  = textureSet.GetTexture(5u);
-  Texture newSpecularTexture = textureSet.GetTexture(6u);
+  Texture newDiffuseTexture  = textureSet.GetTexture(7u);
+  Texture newSpecularTexture = textureSet.GetTexture(8u);
 
   DALI_TEST_EQUALS(diffuseTexture, newDiffuseTexture, TEST_LOCATION);
   DALI_TEST_EQUALS(specularTexture, newSpecularTexture, TEST_LOCATION);
@@ -828,6 +829,26 @@ int UtcDaliModelAnimation02(void)
   END_TEST;
 }
 
+int UtcDaliModelMultiplePrimitives(void)
+{
+  ToolkitTestApplication application;
+
+  Scene3D::Model model = Scene3D::Model::New(TEST_GLTF_MULTIPLE_PRIMITIVE_FILE_NAME);
+  model.SetProperty(Dali::Actor::Property::SIZE, Vector2(50, 50));
+
+  application.GetScene().Add(model);
+
+  application.SendNotification();
+  application.Render();
+
+  Actor actor = model.FindChildByName("rootNode");
+
+  DALI_TEST_EQUALS(0, actor.GetChildCount(), TEST_LOCATION);
+  DALI_TEST_EQUALS(2, actor.GetRendererCount(), TEST_LOCATION);
+
+  END_TEST;
+}
+
 // For ResourceReady
 namespace
 {
index 835fdbf..415e2e1 100644 (file)
 // Enable debug log for test coverage
 #define DEBUG_ENABLED 1
 
-#include "dali-scene3d/public-api/loader/node-definition.h"
-#include "dali-scene3d/public-api/loader/view-projection.h"
-#include <toolkit-test-application.h>
 #include <dali-test-suite-utils.h>
+#include <toolkit-test-application.h>
 #include <string_view>
+#include "dali-scene3d/public-api/loader/node-definition.h"
+#include "dali-scene3d/public-api/loader/view-projection.h"
 
 using namespace Dali;
 using namespace Dali::Scene3D::Loader;
@@ -35,20 +35,19 @@ struct Context
   ResourceBundle resources;
 
   ViewProjection viewProjection;
-  Transforms transforms { MatrixStack{}, viewProjection };
+  Transforms     transforms{MatrixStack{}, viewProjection};
 
-  NodeDefinition::CreateParams createParams {
+  NodeDefinition::CreateParams createParams{
     resources,
-    transforms
-  };
+    transforms};
 };
 
-}
+} // namespace
 
 int UtcDaliConstraintDefinitionsCompare(void)
 {
-  ConstraintDefinition cd1{ "orientation", 0 };
-  ConstraintDefinition cd2{ "position", 1 };
+  ConstraintDefinition cd1{"orientation", 0};
+  ConstraintDefinition cd2{"position", 1};
 
   DALI_TEST_CHECK(cd1 < cd2);
   DALI_TEST_CHECK(!(cd2 < cd1));
@@ -58,9 +57,9 @@ int UtcDaliConstraintDefinitionsCompare(void)
   DALI_TEST_CHECK(cd1 == cd1);
   DALI_TEST_CHECK(cd2 == cd2);
 
-  ConstraintDefinition cd3{ "position", 0 };
-  ConstraintDefinition cd4{ "scale", 1 };
-  ConstraintDefinition cd5{ "position", 1 };
+  ConstraintDefinition cd3{"position", 0};
+  ConstraintDefinition cd4{"scale", 1};
+  ConstraintDefinition cd5{"position", 1};
   DALI_TEST_CHECK(cd2 != cd3);
   DALI_TEST_CHECK(cd2 != cd4);
   DALI_TEST_CHECK(cd2 == cd5);
@@ -71,13 +70,10 @@ int UtcDaliConstraintDefinitionsCompare(void)
 
 int UtcDaliBlendshapeShaderConfigurationRequestsCompare(void)
 {
-  TestApplication app;
-  BlendshapeShaderConfigurationRequest bsscr1{ "", 0, Shader(nullptr) };
+  TestApplication                      app;
+  BlendshapeShaderConfigurationRequest bsscr1{"", 0, Shader(nullptr)};
 
-  BlendshapeShaderConfigurationRequest bsscr2{ "", 0, Shader::New(
-    "void main(){ gl_Position = vec4(0.); }",
-    "void main(){ gl_FragColor = vec4(1.); }"
-  ) };
+  BlendshapeShaderConfigurationRequest bsscr2{"", 0, Shader::New("void main(){ gl_Position = vec4(0.); }", "void main(){ gl_FragColor = vec4(1.); }")};
 
   DALI_TEST_CHECK(bsscr1 < bsscr2);
   DALI_TEST_CHECK(!(bsscr2 < bsscr1));
@@ -89,8 +85,8 @@ int UtcDaliBlendshapeShaderConfigurationRequestsCompare(void)
 
 int UtcDaliNodeDefinitionExtrasCompare(void)
 {
-  NodeDefinition::Extra e1{ "alpha", Vector3::XAXIS * 2.f };
-  NodeDefinition::Extra e2{ "beta", 8 };
+  NodeDefinition::Extra e1{"alpha", Vector3::XAXIS * 2.f};
+  NodeDefinition::Extra e2{"beta", 8};
 
   DALI_TEST_CHECK(e1 < e2);
   DALI_TEST_CHECK(!(e1 < e1));
@@ -103,21 +99,21 @@ int UtcDaliNodeDefinitionExtrasCompare(void)
 int UtcDaliNodeDefinitionProperties(void)
 {
   TestApplication testApp;
-  NodeDefinition nodeDef{
+  NodeDefinition  nodeDef{
     "testRootNode",
-    Vector3{ -100.f, 100.f, -500.f },
-    Quaternion{ Radian(Degree(45.f)), Vector3::ZAXIS },
-    Vector3{ 2.f, 4.f, 8.f },
-    Vector3{ 100.f, 50.f, 25.f },
+    Vector3{-100.f, 100.f, -500.f},
+    Quaternion{Radian(Degree(45.f)), Vector3::ZAXIS},
+    Vector3{2.f, 4.f, 8.f},
+    Vector3{100.f, 50.f, 25.f},
     false,
   };
 
   Quaternion frobnicateFactor(0.f, 1.f, 2.f, 3.f);
   frobnicateFactor.Normalize(); // because it will be (by DALi) once it's set as a property.
-  nodeDef.mExtras.push_back(NodeDefinition::Extra{ "frobnicateFactor", frobnicateFactor });
+  nodeDef.mExtras.push_back(NodeDefinition::Extra{"frobnicateFactor", frobnicateFactor});
 
   Context ctx;
-  auto actor = nodeDef.CreateActor(ctx.createParams);
+  auto    actor = nodeDef.CreateActor(ctx.createParams);
   DALI_TEST_EQUAL(nodeDef.mName, actor.GetProperty(Actor::Property::NAME).Get<std::string>());
   DALI_TEST_EQUAL(nodeDef.mPosition, actor.GetProperty(Actor::Property::POSITION).Get<Vector3>());
   DALI_TEST_EQUAL(nodeDef.mOrientation, actor.GetProperty(Actor::Property::ORIENTATION).Get<Quaternion>());
@@ -142,30 +138,30 @@ int UtcDaliNodeDefinitionRenderableRegisterResources(void)
 {
   NodeDefinition nodeDef;
 
-  auto renderable = new NodeDefinition::Renderable();
-  renderable->mShaderIdx = 0;
-  nodeDef.mRenderable.reset(renderable);
+  std::unique_ptr<NodeDefinition::Renderable> renderable = std::unique_ptr<NodeDefinition::Renderable>(new NodeDefinition::Renderable());
+  nodeDef.mRenderables.push_back(std::move(renderable));
+  nodeDef.mRenderables[0]->mShaderIdx = 0;
 
   struct : IResourceReceiver
   {
     std::vector<Index> shaders;
-    uint32_t otherResources = 0;
+    uint32_t           otherResources = 0;
 
     void Register(ResourceType::Value type, Index id) override
     {
       switch(type)
       {
-      case ResourceType::Shader:
-        shaders.push_back(id);
-        break;
+        case ResourceType::Shader:
+          shaders.push_back(id);
+          break;
 
-      default:
-        ++otherResources;
+        default:
+          ++otherResources;
       }
     }
   } resourceReceiver;
 
-  nodeDef.mRenderable->RegisterResources(resourceReceiver);
+  nodeDef.mRenderables[0]->RegisterResources(resourceReceiver);
   DALI_TEST_EQUAL(1u, resourceReceiver.shaders.size());
   DALI_TEST_EQUAL(0, resourceReceiver.shaders[0]);
   DALI_TEST_EQUAL(0, resourceReceiver.otherResources);
@@ -177,32 +173,32 @@ int UtcDaliNodeDefinitionRenderableReflectResources(void)
 {
   NodeDefinition nodeDef;
 
-  auto renderable = new NodeDefinition::Renderable();
-  renderable->mShaderIdx = 0;
-  nodeDef.mRenderable.reset(renderable);
+  std::unique_ptr<NodeDefinition::Renderable> renderable = std::unique_ptr<NodeDefinition::Renderable>(new NodeDefinition::Renderable());
+  nodeDef.mRenderables.push_back(std::move(renderable));
+  nodeDef.mRenderables[0]->mShaderIdx = 0;
 
   struct : IResourceReflector
   {
     std::vector<Index*> shaders;
-    uint32_t otherResources = 0;
+    uint32_t            otherResources = 0;
 
     void Reflect(ResourceType::Value type, Index& id) override
     {
       switch(type)
       {
-      case ResourceType::Shader:
-        shaders.push_back(&id);
-        break;
+        case ResourceType::Shader:
+          shaders.push_back(&id);
+          break;
 
-      default:
-        ++otherResources;
+        default:
+          ++otherResources;
       }
     }
   } resourceReflector;
 
-  nodeDef.mRenderable->ReflectResources(resourceReflector);
+  nodeDef.mRenderables[0]->ReflectResources(resourceReflector);
   DALI_TEST_EQUAL(1u, resourceReflector.shaders.size());
-  DALI_TEST_EQUAL(&renderable->mShaderIdx, resourceReflector.shaders[0]);
+  DALI_TEST_EQUAL(&nodeDef.mRenderables[0]->mShaderIdx, resourceReflector.shaders[0]);
   DALI_TEST_EQUAL(0, resourceReflector.otherResources);
 
   END_TEST;
@@ -211,17 +207,17 @@ int UtcDaliNodeDefinitionRenderableReflectResources(void)
 int UtcDaliNodeDefinitionRenderable(void)
 {
   TestApplication testApp;
-  NodeDefinition nodeDef;
+  NodeDefinition  nodeDef;
 
-  auto renderable = new NodeDefinition::Renderable();
-  renderable->mShaderIdx = 0;
-  nodeDef.mRenderable.reset(renderable);
+  std::unique_ptr<NodeDefinition::Renderable> renderable = std::unique_ptr<NodeDefinition::Renderable>(new NodeDefinition::Renderable());
+  nodeDef.mRenderables.push_back(std::move(renderable));
+  nodeDef.mRenderables[0]->mShaderIdx = 0;
 
-  Context ctx;
-  const auto VSH = "void main() { gl_Position = vec4(0.); }";
-  const auto FSH = "void main() { gl_FragColor = vec4(1.); }";
-  auto shader = Shader::New(VSH, FSH);
-  ctx.resources.mShaders.push_back({ ShaderDefinition{}, shader });
+  Context    ctx;
+  const auto VSH    = "void main() { gl_Position = vec4(0.); }";
+  const auto FSH    = "void main() { gl_FragColor = vec4(1.); }";
+  auto       shader = Shader::New(VSH, FSH);
+  ctx.resources.mShaders.push_back({ShaderDefinition{}, shader});
 
   auto actor = nodeDef.CreateActor(ctx.createParams);
   DALI_TEST_EQUAL(1, actor.GetRendererCount());
index 08728df..bf9e015 100644 (file)
@@ -84,9 +84,9 @@ Dali::Texture GetDiffuseTexture(Dali::Scene3D::Model model)
     if(renderer)
     {
       TextureSet textureSet = renderer.GetTextures();
-      if(textureSet.GetTextureCount() == 7u)
+      if(textureSet.GetTextureCount() == 9u)
       {
-        texture = textureSet.GetTexture(5u);
+        texture = textureSet.GetTexture(7u);
       }
     }
   }
@@ -105,9 +105,9 @@ Dali::Texture GetSpecularTexture(Dali::Scene3D::Model model)
     if(renderer)
     {
       TextureSet textureSet = renderer.GetTextures();
-      if(textureSet.GetTextureCount() == 7u)
+      if(textureSet.GetTextureCount() == 9u)
       {
-        texture = textureSet.GetTexture(6u);
+        texture = textureSet.GetTexture(8u);
       }
     }
   }
index b8e6357..10aadbf 100644 (file)
@@ -91,9 +91,9 @@ int UtcDaliShaderDefinitionFactoryProduceShaderInvalid(void)
   Context ctx;
 
   NodeDefinition nodeDef;
-  nodeDef.mRenderable.reset(new NodeDefinition::Renderable());
+  std::unique_ptr<NodeDefinition::Renderable> renderable = std::unique_ptr<NodeDefinition::Renderable>(new NodeDefinition::Renderable());
+  nodeDef.mRenderables.push_back(std::move(renderable));
 
-  DALI_TEST_EQUAL(INVALID_INDEX, ctx.factory.ProduceShader(nodeDef));
   DALI_TEST_CHECK(ctx.resources.mShaders.empty());
 
   END_TEST;
@@ -250,12 +250,14 @@ int UtcDaliShaderDefinitionFactoryProduceShader(void)
 
   for(auto& ps : permSets)
   {
-    auto modelNode          = new ModelNode();
-    modelNode->mMeshIdx     = 0;
-    modelNode->mMaterialIdx = 0;
+    auto modelRenderable          = new ModelRenderable();
+    modelRenderable->mMeshIdx     = 0;
+    modelRenderable->mMaterialIdx = 0;
 
     NodeDefinition nodeDef;
-    nodeDef.mRenderable.reset(modelNode);
+    std::unique_ptr<NodeDefinition::Renderable> renderable;
+    renderable.reset(modelRenderable);
+    nodeDef.mRenderables.push_back(std::move(renderable));
 
     auto&            meshDef     = NewMeshDefinition(ctx.resources);
     auto&            materialDef = NewMaterialDefinition(ctx.resources);
@@ -270,35 +272,38 @@ int UtcDaliShaderDefinitionFactoryProduceShader(void)
       rendererState = (rendererState | p->rendererStateSet) & ~p->rendererStateClear;
     }
 
-    auto shaderIdx = ctx.factory.ProduceShader(nodeDef);
-    DALI_TEST_EQUAL(ps.shaderIdx, shaderIdx);
+    for(auto& renderable : nodeDef.mRenderables)
+    {
+      auto shaderIdx = ctx.factory.ProduceShader(*renderable);
+      DALI_TEST_EQUAL(ps.shaderIdx, shaderIdx);
 
-    auto& shaderDef = ctx.resources.mShaders[shaderIdx].first;
-    DALI_TEST_EQUAL(shaderDef.mRendererState, rendererState);
+      auto& shaderDef = ctx.resources.mShaders[shaderIdx].first;
+      DALI_TEST_EQUAL(shaderDef.mRendererState, rendererState);
 
-    uint32_t definesUnmatched = shaderDef.mDefines.size();
-    for(auto& define : shaderDef.mDefines)
-    {
-      auto iFind = defines.find(define);
-      if(iFind != defines.end())
-      {
-        defines.erase(iFind);
-        --definesUnmatched;
-      }
-      else
+      uint32_t definesUnmatched = shaderDef.mDefines.size();
+      for(auto& define : shaderDef.mDefines)
       {
-        break;
+        auto iFind = defines.find(define);
+        if(iFind != defines.end())
+        {
+          defines.erase(iFind);
+          --definesUnmatched;
+        }
+        else
+        {
+          break;
+        }
       }
-    }
 
-    DALI_TEST_CHECK(defines.empty());
-    DALI_TEST_EQUAL(0, definesUnmatched);
+      DALI_TEST_CHECK(defines.empty());
+      DALI_TEST_EQUAL(0, definesUnmatched);
 
-    auto uMaxLOD = shaderDef.mUniforms["uMaxLOD"];
-    DALI_TEST_EQUAL(uMaxLOD.GetType(), Property::FLOAT);
+      auto uMaxLOD = shaderDef.mUniforms["uMaxLOD"];
+      DALI_TEST_EQUAL(uMaxLOD.GetType(), Property::FLOAT);
 
-    auto uCubeMatrix = shaderDef.mUniforms["uCubeMatrix"];
-    DALI_TEST_EQUAL(uCubeMatrix.GetType(), Property::MATRIX);
+      auto uCubeMatrix = shaderDef.mUniforms["uCubeMatrix"];
+      DALI_TEST_EQUAL(uCubeMatrix.GetType(), Property::MATRIX);
+    }
 
     ClearMeshesAndMaterials(ctx.resources);
   }
index 5fc9349..046f997 100644 (file)
@@ -353,11 +353,13 @@ void CreateTextModel(const std::string&                text,
 
   bool isAutoScroll                   = false;
   bool isAutoScrollMaxTextureExceeded = false;
+  bool isHiddenInputEnabled           = false;
   layoutEngine.LayoutText(layoutParameters,
                           layoutSize,
                           false,
                           isAutoScroll,
                           isAutoScrollMaxTextureExceeded,
+                          isHiddenInputEnabled,
                           ellipsisPosition);
 
   if(options.align)
index 5a15b09..8e84bc4 100644 (file)
@@ -182,11 +182,13 @@ bool LayoutTextTest(const LayoutTextData& data)
 
   bool       isAutoScroll                   = false;
   bool       isAutoScrollMaxTextureExceeded = false;
+  bool       isHiddenInputEnabled           = false;
   const bool updated                        = engine.LayoutText(layoutParameters,
                                          layoutSize,
                                          data.ellipsis,
                                          isAutoScroll,
                                          isAutoScrollMaxTextureExceeded,
+                                         isHiddenInputEnabled,
                                          DevelText::EllipsisPosition::END);
 
   // 4) Compare the results.
index 6ec3bfe..9792612 100644 (file)
@@ -182,11 +182,13 @@ bool LayoutTextTest(const LayoutTextData& data)
 
   bool       isAutoScroll                   = false;
   bool       isAutoScrollMaxTextureExceeded = false;
+  bool       isHiddenInputEnabled           = false;
   const bool updated                        = engine.LayoutText(layoutParameters,
                                          layoutSize,
                                          data.ellipsis,
                                          isAutoScroll,
                                          isAutoScrollMaxTextureExceeded,
+                                         isHiddenInputEnabled,
                                          data.ellipsisPosition);
 
   // 4) Compare the results.
index 4134db6..77b2d14 100644 (file)
@@ -39,8 +39,9 @@ using namespace Toolkit;
 namespace
 {
 const char* TEST_VECTOR_IMAGE_FILE_NAME = TEST_RESOURCE_DIR "/insta_camera.json";
+const char* TEST_GIF_FILE_NAME          = TEST_RESOURCE_DIR "/anim.gif";
 
-}
+} // namespace
 
 int UtcDaliVisualAction(void)
 {
@@ -185,6 +186,43 @@ int UtcDaliAnimatedVectorImageVisualCreateInstancePropertyMap(void)
   END_TEST;
 }
 
+int UtcDaliAnimatedImageVisualCreateInstancePropertyMap(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliAnimatedImageVisualCreateInstancePropertyMap");
+
+  Property::Map propertyMap;
+  propertyMap.Add(Toolkit::Visual::Property::TYPE, Visual::ANIMATED_IMAGE)
+    .Add(ImageVisual::Property::URL, TEST_GIF_FILE_NAME)
+    .Add(ImageVisual::Property::DESIRED_WIDTH, 10)
+    .Add(ImageVisual::Property::DESIRED_HEIGHT, 12);
+
+  // request AnimatedVectorImageVisual with a property map
+  VisualFactory                    factory    = VisualFactory::Get();
+  Visual::Base                     visual     = factory.CreateVisual(propertyMap);
+  Toolkit::Internal::Visual::Base& visualImpl = GetImplementation(visual);
+
+  Property::Map resultMap;
+  visualImpl.CreateInstancePropertyMap(resultMap);
+
+  // check the property values from the returned map from a visual
+  DALI_TEST_EQUALS(resultMap.Count(), 3u, TEST_LOCATION);
+
+  Property::Value* value = resultMap.Find(Toolkit::Visual::Property::TYPE, Property::INTEGER);
+  DALI_TEST_CHECK(value);
+  DALI_TEST_CHECK(value->Get<int>() == Visual::ANIMATED_IMAGE);
+
+  value = resultMap.Find(Toolkit::ImageVisual::Property::DESIRED_WIDTH, Property::INTEGER);
+  DALI_TEST_CHECK(value);
+  DALI_TEST_CHECK(value->Get<int>() == 10);
+
+  value = resultMap.Find(Toolkit::ImageVisual::Property::DESIRED_HEIGHT, Property::INTEGER);
+  DALI_TEST_CHECK(value);
+  DALI_TEST_CHECK(value->Get<int>() == 12);
+
+  END_TEST;
+}
+
 int UtcDaliAnimatedVectorImageVisualSetProperties(void)
 {
   ToolkitTestApplication application;
index 7a31046..6021026 100644 (file)
@@ -166,6 +166,11 @@ bool TestGlAbstraction::IsAdvancedBlendEquationSupported()
   return true;
 }
 
+bool TestGlAbstraction::IsMultisampledRenderToTextureSupported()
+{
+  return true;
+}
+
 bool TestGlAbstraction::IsBlendEquationSupported(DevelBlendEquation::Type blendEquation)
 {
   return true;
index f6878ae..5e5fde3 100644 (file)
@@ -72,6 +72,8 @@ public:
 
   bool IsAdvancedBlendEquationSupported() override;
 
+  bool IsMultisampledRenderToTextureSupported() override;
+
   bool IsBlendEquationSupported(DevelBlendEquation::Type blendEquation) override;
 
   std::string GetShaderVersionPrefix();
@@ -1702,6 +1704,12 @@ public:
   {
   }
 
+  inline void FramebufferTexture2DMultisample(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples) override
+  {
+    // TODO : Check it if need
+    FramebufferTexture2D(target, attachment, textarget, texture, level);
+  }
+
   inline void FramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer) override
   {
   }
index 9870308..3c23a06 100644 (file)
@@ -80,6 +80,10 @@ int UtcDaliAnimatedImageVisualGetPropertyMap01(void)
       .Add(ImageVisual::Property::PIXEL_AREA, Vector4())
       .Add(ImageVisual::Property::WRAP_MODE_U, WrapMode::REPEAT)
       .Add(ImageVisual::Property::WRAP_MODE_V, WrapMode::DEFAULT)
+      .Add(ImageVisual::Property::FITTING_MODE, FittingMode::FIT_WIDTH)
+      .Add(ImageVisual::Property::SAMPLING_MODE, SamplingMode::NEAREST)
+      .Add(ImageVisual::Property::DESIRED_WIDTH, 154)
+      .Add(ImageVisual::Property::DESIRED_HEIGHT, 79)
       .Add(ImageVisual::Property::ALPHA_MASK_URL, TEST_MASK_IMAGE_FILE_NAME)
       .Add(ImageVisual::Property::MASK_CONTENT_SCALE, 1.6f)
       .Add(ImageVisual::Property::CROP_TO_MASK, true)
@@ -101,6 +105,30 @@ int UtcDaliAnimatedImageVisualGetPropertyMap01(void)
   DALI_TEST_CHECK(value);
   DALI_TEST_CHECK(value->Get<std::string>() == TEST_GIF_FILE_NAME);
 
+  value = resultMap.Find(Toolkit::ImageVisual::Property::WRAP_MODE_U, Property::INTEGER);
+  DALI_TEST_CHECK(value);
+  DALI_TEST_CHECK(value->Get<int>() == WrapMode::REPEAT);
+
+  value = resultMap.Find(Toolkit::ImageVisual::Property::WRAP_MODE_V, Property::INTEGER);
+  DALI_TEST_CHECK(value);
+  DALI_TEST_CHECK(value->Get<int>() == WrapMode::DEFAULT);
+
+  value = resultMap.Find(Toolkit::ImageVisual::Property::FITTING_MODE, Property::INTEGER);
+  DALI_TEST_CHECK(value);
+  DALI_TEST_CHECK(value->Get<int>() == FittingMode::FIT_WIDTH);
+
+  value = resultMap.Find(Toolkit::ImageVisual::Property::SAMPLING_MODE, Property::INTEGER);
+  DALI_TEST_CHECK(value);
+  DALI_TEST_CHECK(value->Get<int>() == SamplingMode::NEAREST);
+
+  value = resultMap.Find(Toolkit::ImageVisual::Property::DESIRED_WIDTH, Property::INTEGER);
+  DALI_TEST_CHECK(value);
+  DALI_TEST_CHECK(value->Get<int>() == 154);
+
+  value = resultMap.Find(Toolkit::ImageVisual::Property::DESIRED_HEIGHT, Property::INTEGER);
+  DALI_TEST_CHECK(value);
+  DALI_TEST_CHECK(value->Get<int>() == 79);
+
   value = resultMap.Find(DevelVisual::Property::CORNER_RADIUS, Property::VECTOR4);
   DALI_TEST_CHECK(value);
   DALI_TEST_EQUALS(value->Get<Vector4>(), Vector4(22.2f, 22.2f, 22.2f, 22.2f), TEST_LOCATION);
@@ -138,9 +166,10 @@ int UtcDaliAnimatedImageVisualGetPropertyMap01(void)
   DALI_TEST_CHECK(value);
   DALI_TEST_CHECK(value->Get<int>() == DevelImageVisual::MaskingType::MASKING_ON_RENDERING);
 
+  // Natural size getted as desired size
   Vector2 naturalSize;
   animatedImageVisual.GetNaturalSize(naturalSize);
-  DALI_TEST_EQUALS(naturalSize, Vector2(100, 100), TEST_LOCATION);
+  DALI_TEST_EQUALS(naturalSize, Vector2(154, 79), TEST_LOCATION);
 
   // request AnimatedImageVisual with an URL
   Visual::Base animatedImageVisual2 = factory.CreateVisual(TEST_GIF_FILE_NAME, ImageDimensions());
@@ -155,6 +184,10 @@ int UtcDaliAnimatedImageVisualGetPropertyMap01(void)
   DALI_TEST_CHECK(value);
   DALI_TEST_CHECK(value->Get<std::string>() == TEST_GIF_FILE_NAME);
 
+  // Natural size getted as image size
+  animatedImageVisual2.GetNaturalSize(naturalSize);
+  DALI_TEST_EQUALS(naturalSize, Vector2(50, 50), TEST_LOCATION);
+
   END_TEST;
 }
 
@@ -179,6 +212,10 @@ int UtcDaliAnimatedImageVisualGetPropertyMap02(void)
       .Add("pixelArea", Vector4())
       .Add("wrapModeU", WrapMode::REPEAT)
       .Add("wrapModeV", WrapMode::DEFAULT)
+      .Add("fittingMode", FittingMode::FIT_WIDTH)
+      .Add("samplingMode", SamplingMode::NEAREST)
+      .Add("desiredWidth", 154)
+      .Add("desiredHeight", 79)
       .Add("alphaMaskUrl", TEST_MASK_IMAGE_FILE_NAME)
       .Add("maskContentScale", 1.6f)
       .Add("cropToMask", true)
@@ -222,6 +259,30 @@ int UtcDaliAnimatedImageVisualGetPropertyMap02(void)
   DALI_TEST_CHECK(value);
   DALI_TEST_EQUALS(value->Get<int>(), 11, TEST_LOCATION);
 
+  value = resultMap.Find(Toolkit::ImageVisual::Property::WRAP_MODE_U, "wrapModeU");
+  DALI_TEST_CHECK(value);
+  DALI_TEST_CHECK(value->Get<int>() == WrapMode::REPEAT);
+
+  value = resultMap.Find(Toolkit::ImageVisual::Property::WRAP_MODE_V, "wrapModeV");
+  DALI_TEST_CHECK(value);
+  DALI_TEST_CHECK(value->Get<int>() == WrapMode::DEFAULT);
+
+  value = resultMap.Find(Toolkit::ImageVisual::Property::FITTING_MODE, "fittingMode");
+  DALI_TEST_CHECK(value);
+  DALI_TEST_CHECK(value->Get<int>() == FittingMode::FIT_WIDTH);
+
+  value = resultMap.Find(Toolkit::ImageVisual::Property::SAMPLING_MODE, "samplingMode");
+  DALI_TEST_CHECK(value);
+  DALI_TEST_CHECK(value->Get<int>() == SamplingMode::NEAREST);
+
+  value = resultMap.Find(Toolkit::ImageVisual::Property::DESIRED_WIDTH, "desiredWidth");
+  DALI_TEST_CHECK(value);
+  DALI_TEST_CHECK(value->Get<int>() == 154);
+
+  value = resultMap.Find(Toolkit::ImageVisual::Property::DESIRED_HEIGHT, "desiredHeight");
+  DALI_TEST_CHECK(value);
+  DALI_TEST_CHECK(value->Get<int>() == 79);
+
   value = resultMap.Find(Toolkit::DevelVisual::Property::CORNER_RADIUS, "cornerRadius");
   DALI_TEST_CHECK(value);
   DALI_TEST_EQUALS(value->Get<Vector4>(), Vector4(50.0f, 25.0f, 12.5f, 33.0f), TEST_LOCATION);
@@ -359,6 +420,11 @@ int UtcDaliAnimatedImageVisualGetPropertyMap03(void)
   DALI_TEST_CHECK(value);
   DALI_TEST_CHECK(value->Get<bool>() == DevelImageVisual::MaskingType::MASKING_ON_RENDERING);
 
+  // Natural size getted as masked image size
+  Vector2 naturalSize;
+  animatedImageVisual.GetNaturalSize(naturalSize);
+  DALI_TEST_EQUALS(naturalSize, Vector2(100, 100), TEST_LOCATION);
+
   END_TEST;
 }
 
@@ -1792,7 +1858,7 @@ int UtcDaliAnimatedImageVisualWrapMode(void)
   // Test wrap mode in animated image visual.
   const int     width  = 950;
   const int     height = 1080;
-  const Vector4 pixelArea(0.0f, 0.0f, 950/ 40, 1.0f);
+  const Vector4 pixelArea(0.0f, 0.0f, 950 / 40, 1.0f);
 
   Property::Map propertyMap;
   propertyMap.Insert(Toolkit::Visual::Property::TYPE, Visual::IMAGE);
@@ -1848,3 +1914,72 @@ int UtcDaliAnimatedImageVisualWrapMode(void)
 
   END_TEST;
 }
+
+int UtcDaliAnimatedImageVisualDesiredSize(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliAnimatedImageVisualDesiredSize");
+
+  TestGlAbstraction& gl           = application.GetGlAbstraction();
+  TraceCallStack&    textureTrace = gl.GetTextureTrace();
+
+  // Set desiredWidth < 37 and desiredHeight < 50, which is smaller than original image's size.
+  int desiredWidth  = 15;
+  int desiredHeight = 20;
+
+  Visual::Base visual = VisualFactory::Get().CreateVisual(TEST_GIF_FILE_NAME, ImageDimensions(desiredWidth, desiredHeight));
+  DALI_TEST_CHECK(visual);
+
+  DummyControl      actor     = DummyControl::New(true);
+  DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
+  dummyImpl.RegisterVisual(DummyControl::Property::TEST_VISUAL, visual);
+
+  application.GetScene().Add(actor);
+
+  application.SendNotification();
+  application.Render();
+
+  // Trigger count is 2 - first frame and second frame.
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION);
+
+  textureTrace.Enable(true);
+  textureTrace.EnableLogging(true);
+
+  application.SendNotification();
+  application.Render();
+
+  {
+    std::stringstream out;
+    out << GL_TEXTURE_2D << ", " << 0u << ", " << desiredWidth << ", " << desiredHeight;
+    DALI_TEST_CHECK(textureTrace.FindMethodAndParams("TexImage2D", out.str().c_str()));
+  }
+
+  // Unparent to make next trigger
+  actor.Unparent();
+
+  application.SendNotification();
+  application.Render();
+
+  // Set visual size
+  actor.SetProperty(Actor::Property::SIZE, Vector2(300.0f, 300.0f));
+  application.GetScene().Add(actor);
+
+  application.SendNotification();
+  application.Render();
+
+  // Trigger count is 2 - first frame and second frame.
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(2), true, TEST_LOCATION);
+
+  textureTrace.Reset();
+
+  application.SendNotification();
+  application.Render();
+
+  {
+    std::stringstream out;
+    out << GL_TEXTURE_2D << ", " << 0u << ", " << desiredWidth << ", " << desiredHeight;
+    DALI_TEST_CHECK(textureTrace.FindMethodAndParams("TexImage2D", out.str().c_str())); // The size should not be changed
+  }
+
+  END_TEST;
+}
\ No newline at end of file
index df1c60b..94855ca 100644 (file)
@@ -3012,6 +3012,7 @@ int utcDaliTextFieldEvent09(void)
   application.Render();
 
   field.SetProperty(TextField::Property::TEXT, "Hello");
+  field.SetProperty(TextField::Property::PLACEHOLDER_TEXT, "Placeholder text");
   field.SetProperty(TextField::Property::POINT_SIZE, 10.f);
   field.SetProperty(Actor::Property::SIZE, Vector2(300.f, 50.f));
   field.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
@@ -3031,6 +3032,12 @@ int utcDaliTextFieldEvent09(void)
   application.ProcessEvent(GenerateKey("d", "", "d", 0, 0, 0, Integration::KeyEvent::DOWN, "d", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE));
   application.SendNotification();
   application.Render();
+  for(unsigned int index = 0u; index < 6u; ++index)
+  {
+    application.ProcessEvent(GenerateKey("", "", "", DALI_KEY_BACKSPACE, 0, 0, Integration::KeyEvent::DOWN, "", DEFAULT_DEVICE_NAME, Device::Class::NONE, Device::Subclass::NONE));
+    application.SendNotification();
+    application.Render();
+  }
 
   map[HiddenInput::Property::MODE]                 = HiddenInput::Mode::HIDE_ALL;
   map[HiddenInput::Property::SUBSTITUTE_CHARACTER] = 0x23;
index 1457e19..e8fb48e 100644 (file)
@@ -28,6 +28,7 @@
 #include <dali/devel-api/actors/camera-actor-devel.h>
 #include <dali/devel-api/adaptor-framework/window-devel.h>
 #include <dali/devel-api/common/stage.h>
+#include <dali/devel-api/rendering/frame-buffer-devel.h>
 #include <dali/integration-api/debug.h>
 #include <dali/public-api/object/type-registry-helper.h>
 #include <dali/public-api/object/type-registry.h>
@@ -60,6 +61,8 @@ DALI_TYPE_REGISTRATION_END()
 Property::Index   RENDERING_BUFFER    = Dali::Toolkit::Control::CONTROL_PROPERTY_END_INDEX + 1;
 constexpr int32_t DEFAULT_ORIENTATION = 0;
 
+constexpr uint8_t DEFAULT_FRAME_BUFFER_MULTI_SAMPLING_LEVEL = 4u;
+
 static constexpr std::string_view SKYBOX_INTENSITY_STRING = "uIntensity";
 
 Dali::Actor CreateSkybox(const std::string& skyboxUrl)
@@ -255,7 +258,7 @@ void SceneView::SelectCamera(const std::string& name)
   UpdateCamera(GetCamera(name));
 }
 
-void SceneView::RegisterSceneItem(Scene3D::Internal::ImageBasedLightObserver *item)
+void SceneView::RegisterSceneItem(Scene3D::Internal::ImageBasedLightObserveritem)
 {
   if(item)
   {
@@ -264,7 +267,7 @@ void SceneView::RegisterSceneItem(Scene3D::Internal::ImageBasedLightObserver *it
   }
 }
 
-void SceneView::UnregisterSceneItem(Scene3D::Internal::ImageBasedLightObserver *item)
+void SceneView::UnregisterSceneItem(Scene3D::Internal::ImageBasedLightObserveritem)
 {
   if(item)
   {
@@ -430,7 +433,7 @@ void SceneView::OnSceneDisconnection()
     if(mRenderTask)
     {
       taskList.RemoveTask(mRenderTask);
-      mRenderTarget.Reset();
+      mFrameBuffer.Reset();
     }
   }
   mWindow.Reset();
@@ -538,10 +541,11 @@ void SceneView::UpdateRenderTask()
         mRenderTask.SetViewport(Dali::Viewport(Vector4::ZERO));
 
         // create offscreen buffer of new size to render our child actors to
-        mTexture      = Dali::Texture::New(TextureType::TEXTURE_2D, Pixel::RGBA8888, unsigned(size.width), unsigned(size.height));
-        mRenderTarget = FrameBuffer::New(size.width, size.height, FrameBuffer::Attachment::DEPTH_STENCIL);
-        mRenderTarget.AttachColorTexture(mTexture);
-        Dali::Toolkit::ImageUrl imageUrl = Dali::Toolkit::Image::GenerateUrl(mRenderTarget, 0u);
+        mTexture     = Dali::Texture::New(TextureType::TEXTURE_2D, Pixel::RGBA8888, unsigned(size.width), unsigned(size.height));
+        mFrameBuffer = FrameBuffer::New(size.width, size.height, FrameBuffer::Attachment::DEPTH_STENCIL);
+        mFrameBuffer.AttachColorTexture(mTexture);
+        DevelFrameBuffer::SetMultiSamplingLevel(mFrameBuffer, DEFAULT_FRAME_BUFFER_MULTI_SAMPLING_LEVEL);
+        Dali::Toolkit::ImageUrl imageUrl = Dali::Toolkit::Image::GenerateUrl(mFrameBuffer, 0u);
 
         Property::Map imagePropertyMap;
         imagePropertyMap.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE);
@@ -552,7 +556,7 @@ void SceneView::UpdateRenderTask()
 
         Toolkit::DevelControl::RegisterVisual(*this, RENDERING_BUFFER, mVisual);
 
-        mRenderTask.SetFrameBuffer(mRenderTarget);
+        mRenderTask.SetFrameBuffer(mFrameBuffer);
         mRenderTask.SetClearEnabled(true);
         mRenderTask.SetClearColor(Color::TRANSPARENT);
       }
@@ -569,7 +573,7 @@ void SceneView::UpdateRenderTask()
         Toolkit::DevelControl::UnregisterVisual(*this, RENDERING_BUFFER);
 
         mVisual.Reset();
-        mRenderTarget.Reset();
+        mFrameBuffer.Reset();
         mTexture.Reset();
       }
     }
index 7632d80..f5e4f82 100644 (file)
@@ -251,7 +251,7 @@ private:
   CameraActor                                              mSelectedCamera;
   std::vector<CameraActor>                                 mCameras;
   std::vector<Scene3D::Internal::ImageBasedLightObserver*> mItems;
-  Dali::FrameBuffer                                        mRenderTarget;
+  Dali::FrameBuffer                                        mFrameBuffer;
   Dali::Texture                                            mTexture;
   Dali::RenderTask                                         mRenderTask;
   Layer                                                    mRootLayer;
index a55e9c3..8c9e7ea 100644 (file)
@@ -33,9 +33,11 @@ precision mediump float;
 #endif //GLTF_CHANNELS
 #endif //THREE_TEX
 
-uniform lowp vec4 uColorFactor;
+uniform lowp vec4 uColor; // Color from SceneGraph
+uniform lowp vec4 uColorFactor; // Color from material
 uniform lowp float uMetallicFactor;
 uniform lowp float uRoughnessFactor;
+uniform lowp float uDielectricSpecular;
 
 #ifdef THREE_TEX
 #ifdef BASECOLOR_TEX
@@ -53,6 +55,15 @@ uniform sampler2D sAlbedoMetal;
 uniform sampler2D sNormalRoughness;
 #endif
 
+uniform float uSpecularFactor;
+uniform vec3  uSpecularColorFactor;
+#ifdef MATERIAL_SPECULAR_TEXTURE
+uniform sampler2D sSpecular;
+#endif
+#ifdef MATERIAL_SPECULAR_COLOR_TEXTURE
+uniform sampler2D sSpecularColor;
+#endif
+
 #ifdef OCCLUSION
 uniform sampler2D sOcclusion;
 uniform float uOcclusionStrength;
@@ -83,43 +94,8 @@ in highp vec3 vPositionToCamera;
 
 out vec4 FragColor;
 
-struct PBRInfo
-{
-  mediump float NdotL;        // cos angle between normal and light direction
-  mediump float NdotV;        // cos angle between normal and view direction
-  mediump float NdotH;        // cos angle between normal and half vector
-  mediump float VdotH;        // cos angle between view direction and half vector
-  mediump vec3 reflectance0;  // full reflectance color (normal incidence angle)
-  mediump vec3 reflectance90; // reflectance color at grazing angle
-  lowp float alphaRoughness;  // roughness mapped to a more linear change in the roughness (proposed by [2])
-};
-
-const float M_PI = 3.141592653589793;
 const float c_MinRoughness = 0.04;
 
-vec3 specularReflection(PBRInfo pbrInputs)
-{
-  return pbrInputs.reflectance0 + (pbrInputs.reflectance90 - pbrInputs.reflectance0) * pow(clamp(1.0 - pbrInputs.VdotH, 0.0, 1.0), 5.0);
-}
-
-float geometricOcclusion(PBRInfo pbrInputs)
-{
-  mediump float NdotL = pbrInputs.NdotL;
-  mediump float NdotV = pbrInputs.NdotV;
-  lowp float r = pbrInputs.alphaRoughness;
-
-  lowp float attenuationL = 2.0 * NdotL / (NdotL + sqrt(r * r + (1.0 - r * r) * (NdotL * NdotL)));
-  lowp float attenuationV = 2.0 * NdotV / (NdotV + sqrt(r * r + (1.0 - r * r) * (NdotV * NdotV)));
-  return attenuationL * attenuationV;
-}
-
-float microfacetDistribution(PBRInfo pbrInputs)
-{
-  mediump float roughnessSq = pbrInputs.alphaRoughness * pbrInputs.alphaRoughness;
-  lowp float f = (pbrInputs.NdotH * roughnessSq - pbrInputs.NdotH) * pbrInputs.NdotH + 1.0;
-  return roughnessSq / (M_PI * f * f);
-}
-
 vec3 linear(vec3 color)
 {
   return pow(color, vec3(2.2));
@@ -181,35 +157,45 @@ void main()
   // Roughness is authored as perceptual roughness; as is convention,
   // convert to material roughness by squaring the perceptual roughness [2].
   perceptualRoughness = clamp(perceptualRoughness, c_MinRoughness, 1.0);
-  lowp float alphaRoughness = perceptualRoughness * perceptualRoughness;
-
-  lowp vec3 f0 = vec3(0.04);
-  lowp vec3 diffuseColor = baseColor.rgb * (vec3(1.0) - f0);
-  diffuseColor *= (1.0 - metallic);
-  lowp vec3 specularColor = mix(f0, baseColor.rgb, metallic);
 
-  // Compute reflectance.
-  lowp float reflectance = max(max(specularColor.r, specularColor.g), specularColor.b);
+  // Material ior
+  lowp vec3 f0 = vec3(uDielectricSpecular);
 
-  // For typical incident reflectance range (between 4% to 100%) set the grazing reflectance to 100% for typical fresnel effect.
-  // For very low reflectance range on highly diffuse objects (below 4%), incrementally reduce grazing reflecance to 0%.
-  lowp float reflectance90 = clamp(reflectance * 25.0, 0.0, 1.0);
-  lowp vec3 specularEnvironmentR0 = specularColor.rgb;
-  lowp vec3 specularEnvironmentR90 = vec3(1.0, 1.0, 1.0) * reflectance90;
+  // Material Specular
+  float specularWeight = 1.0;
+  vec4 materialSpecularTexture = vec4(1.0);
+#ifdef MATERIAL_SPECULAR_TEXTURE
+  materialSpecularTexture.a = texture(sSpecular, vUV).a;
+#endif
+#ifdef MATERIAL_SPECULAR_COLOR_TEXTURE
+  materialSpecularTexture.rgb = texture(sSpecularColor, vUV).rgb;
+#endif
+  specularWeight = uSpecularFactor * materialSpecularTexture.a;
+  f0 = min(f0 * uSpecularColorFactor * materialSpecularTexture.rgb, vec3(1.0));
+  f0 = mix(f0, baseColor.rgb, metallic);
 
   mediump vec3 v = normalize(vPositionToCamera); // Vector from surface point to camera
   mediump float NdotV = clamp(abs(dot(n, v)), 0.001, 1.0);
   mediump vec3 reflection = -normalize(reflect(v, n));
+  lowp vec3 brdf = linear(texture(sbrdfLUT, vec2(NdotV, 1.0 - perceptualRoughness)).rgb);
+  vec3 Fr = max(vec3(1.0 - perceptualRoughness), f0) - f0;
+  vec3 k_S = f0 + Fr * pow(1.0 - NdotV, 5.0);
+  vec3 FssEss = specularWeight * (k_S * brdf.x + brdf.y);
 
-  lowp vec3 color = vec3(0.0);
-  lowp vec3 diffuseLight = linear(texture(sDiffuseEnvSampler, n * uYDirection).rgb);
+  // Specular Light
   lowp vec3 specularLight = linear(texture(sSpecularEnvSampler, reflection * uYDirection).rgb);
-  // retrieve a scale and bias to F0. See [1], Figure 3
-  lowp vec3 brdf = linear(texture(sbrdfLUT, vec2(NdotV, 1.0 - perceptualRoughness)).rgb);
+  lowp vec3 specular = specularLight * FssEss;
+
+  // Diffuse Light
+  lowp vec3 diffuseColor = mix(baseColor.rgb, vec3(0), metallic);
+  lowp vec3 irradiance = linear(texture(sDiffuseEnvSampler, n * uYDirection).rgb);
+  float Ems = (1.0 - (brdf.x + brdf.y));
+  vec3 F_avg = specularWeight * (f0 + (1.0 - f0) / 21.0);
+  vec3 FmsEms = Ems * FssEss * F_avg / (1.0 - F_avg * Ems);
+  vec3 k_D = diffuseColor * (1.0 - FssEss + FmsEms);
+  lowp vec3 diffuse = (FmsEms + k_D) * irradiance;
 
-  lowp vec3 diffuse = diffuseLight * diffuseColor;
-  lowp vec3 specular = specularLight * (specularColor * brdf.x + brdf.y);
-  color += (diffuse + specular) * uIblIntensity;
+  lowp vec3 color = (diffuse + specular) * uIblIntensity;
 
 #ifdef OCCLUSION
   lowp float ao = texture(sOcclusion, vUV).r;
@@ -221,5 +207,5 @@ void main()
   color += emissive;
 #endif // EMISSIVE
 
-  FragColor = vec4(pow(color, vec3(1.0 / 2.2)), baseColor.a);
+  FragColor = vec4(pow(color, vec3(1.0 / 2.2)), baseColor.a) * uColor;
 }
index a1153c9..633e91c 100644 (file)
@@ -1,11 +1,12 @@
 #version 300 es
 
 precision mediump float;
+uniform lowp vec4 uColor;
 flat in float vColor;
 out vec4 FragColor;
 
 void main()
 {
   vec3 rgb = vec3(fract(vColor), fract(vColor * 0.00390625), fract(vColor * 0.00390625 * 0.00390625));
-  FragColor = vec4(rgb, 1.);
+  FragColor = vec4(rgb, 1.) * uColor;
 }
\ No newline at end of file
index 2a6024d..7bf6e42 100644 (file)
@@ -1,9 +1,10 @@
 uniform samplerCube   uSkyBoxTexture;
+uniform lowp    vec4  uColor;
 uniform mediump float uIntensity;
 varying mediump vec3  vTexCoord;
 
 void main()
 {
   mediump vec4 texColor = textureCube(uSkyBoxTexture, vTexCoord) * uIntensity;
-  gl_FragColor = texColor;
+  gl_FragColor = texColor * uColor;
 }
\ No newline at end of file
index 7769751..3fa2705 100644 (file)
@@ -325,9 +325,36 @@ struct TextureInfo
   }
 };
 
+/**
+ * Material Ior is supported with KHR_materials_ior extension.
+ * https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_ior
+ */
+struct MaterialIor
+{
+  float mIor = MAXFLOAT;
+};
+
+/**
+ * Material Specular is supported with KHR_materials_ior extension.
+ * https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_specular
+ */
+struct MaterialSpecular
+{
+  float         mSpecularFactor = 1.0f;
+  TextureInfo   mSpecularTexture;
+  Dali::Vector3 mSpecularColorFactor = Dali::Vector3::ONE;
+  TextureInfo   mSpecularColorTexture;
+};
+
+struct MaterialExtensions
+{
+  MaterialSpecular mMaterialSpecular;
+  MaterialIor      mMaterialIor;
+};
+
 struct Material : Named
 {
-  struct Pbr //MetallicRoughness
+  struct Pbr // MetallicRoughness
   {
     Dali::Vector4 mBaseColorFactor = Dali::Vector4::ONE;
     TextureInfo   mBaseColorTexture;
@@ -338,15 +365,17 @@ struct Material : Named
     //TODO: extras
   };
 
-  Pbr             mPbrMetallicRoughness;
-  TextureInfo     mNormalTexture;
-  TextureInfo     mOcclusionTexture;
-  TextureInfo     mEmissiveTexture;
-  Dali::Vector3   mEmissiveFactor;
-  AlphaMode::Type mAlphaMode   = AlphaMode::OPAQUE;
-  float           mAlphaCutoff = .5f;
-  bool            mDoubleSided = false;
-  //TODO: extensions
+  Pbr               mPbrMetallicRoughness;
+  TextureInfo       mNormalTexture;
+  TextureInfo       mOcclusionTexture;
+  TextureInfo       mEmissiveTexture;
+  Dali::Vector3     mEmissiveFactor;
+  AlphaMode::Type   mAlphaMode   = AlphaMode::OPAQUE;
+  float             mAlphaCutoff = .5f;
+  bool              mDoubleSided = false;
+
+  //extensions
+  MaterialExtensions mMaterialExtensions;
   //TODO: extras
 };
 
index 133e62c..70c59d2 100644 (file)
@@ -145,7 +145,7 @@ RendererState::Type ReadRendererState(const TreeNode& tnRendererState)
 }
 
 ///@brief Reads arc properties.
-void ReadArcField(const TreeNode* eArc, ArcNode& arc)
+void ReadArcField(const TreeNode* eArc, ArcRenderable& arc)
 {
   ReadBool(eArc->GetChild("antiAliasing"), arc.mAntiAliasing);
   ReadInt(eArc->GetChild("arcCaps"), arc.mArcCaps);
@@ -301,7 +301,7 @@ void ParseProperties(const Toolkit::TreeNode& node, Property::Array& array)
   }
 }
 
-} //namespace
+} // namespace
 
 struct DliLoader::Impl
 {
@@ -485,7 +485,8 @@ void DliLoader::Impl::ParseScene(LoadParams& params)
 
 void DliLoader::Impl::ParseSceneInternal(Index iScene, const Toolkit::TreeNode* tnScenes, const Toolkit::TreeNode* tnNodes, LoadParams& params)
 {
-  auto getSceneRootIdx = [tnScenes, tnNodes](Index iScene) {
+  auto getSceneRootIdx = [tnScenes, tnNodes](Index iScene)
+  {
     auto tn = GetNthChild(tnScenes, iScene); // now a "scene" object
     if(!tn)
     {
@@ -568,7 +569,8 @@ void DliLoader::Impl::ParseSkeletons(const TreeNode* skeletons, SceneDefinition&
         uint32_t                   jointCount = 0;
         std::function<void(Index)> visitFn;
         auto&                      ibms = mInverseBindMatrices;
-        visitFn                         = [&](Index id) {
+        visitFn                         = [&](Index id)
+        {
           auto node = scene.GetNode(id);
           jointCount += ibms.find(id) != ibms.end();
 
@@ -587,7 +589,8 @@ void DliLoader::Impl::ParseSkeletons(const TreeNode* skeletons, SceneDefinition&
 
         skeleton.mJoints.reserve(jointCount);
 
-        visitFn = [&](Index id) {
+        visitFn = [&](Index id)
+        {
           auto iFind = ibms.find(id);
           if(iFind != ibms.end() && skeleton.mJoints.size() < Skinning::MAX_JOINTS)
           {
@@ -934,7 +937,7 @@ void DliLoader::Impl::ParseMaterials(const TreeNode* materials, ConvertColorCode
       }
     }
 
-    //TODO : need to consider AGIF
+    // TODO : need to consider AGIF
     std::vector<std::string> texturePaths;
     std::string              texturePath;
     if(ReadString(node.GetChild("albedoMap"), texturePath))
@@ -1077,9 +1080,8 @@ void DliLoader::Impl::ParseNodes(const TreeNode* const nodes, Index index, LoadP
 
     virtual unsigned int Resolve(Index iDli) override
     {
-      auto iFind = std::lower_bound(mIndices.begin(), mIndices.end(), iDli, [](const Entry& idx, Index iDli) {
-        return idx.iDli < iDli;
-      });
+      auto iFind = std::lower_bound(mIndices.begin(), mIndices.end(), iDli, [](const Entry& idx, Index iDli)
+                                    { return idx.iDli < iDli; });
       DALI_ASSERT_ALWAYS(iFind != mIndices.end());
       return iFind->iScene;
     }
@@ -1159,7 +1161,7 @@ void DliLoader::Impl::ParseNodesInternal(const TreeNode* const nodes, Index inde
     else // something renderable maybe
     {
       std::unique_ptr<NodeDefinition::Renderable> renderable;
-      ModelNode*                                  modelNode = nullptr; // no ownership, aliasing renderable for the right type.
+      ModelRenderable*                            modelRenderable = nullptr; // no ownership, aliasing renderable for the right type.
 
       const TreeNode* eRenderable = nullptr;
       if((eRenderable = node->GetChild("model")))
@@ -1171,10 +1173,10 @@ void DliLoader::Impl::ParseNodesInternal(const TreeNode* const nodes, Index inde
           ExceptionFlinger(ASSERT_LOCATION) << "node " << nodeDef.mName << ": Missing mesh definition.";
         }
 
-        modelNode = new ModelNode();
-        renderable.reset(modelNode);
+        modelRenderable = new ModelRenderable();
+        renderable.reset(modelRenderable);
 
-        resourceIds.push_back({ResourceType::Mesh, eMesh, modelNode->mMeshIdx});
+        resourceIds.push_back({ResourceType::Mesh, eMesh, modelRenderable->mMeshIdx});
       }
       else if((eRenderable = node->GetChild("arc")))
       {
@@ -1185,13 +1187,13 @@ void DliLoader::Impl::ParseNodesInternal(const TreeNode* const nodes, Index inde
           ExceptionFlinger(ASSERT_LOCATION) << "node " << nodeDef.mName << ": Missing mesh definition.";
         }
 
-        auto arcNode = new ArcNode;
-        renderable.reset(arcNode);
-        modelNode = arcNode;
+        auto arcRenderable = new ArcRenderable;
+        renderable.reset(arcRenderable);
+        modelRenderable = arcRenderable;
 
-        resourceIds.push_back({ResourceType::Mesh, eMesh, arcNode->mMeshIdx});
+        resourceIds.push_back({ResourceType::Mesh, eMesh, arcRenderable->mMeshIdx});
 
-        ReadArcField(eRenderable, *arcNode);
+        ReadArcField(eRenderable, *arcRenderable);
       }
 
       if(renderable && eRenderable != nullptr) // process common properties of all renderables + register payload
@@ -1205,22 +1207,22 @@ void DliLoader::Impl::ParseNodesInternal(const TreeNode* const nodes, Index inde
         }
 
         // color
-        if(modelNode)
+        if(modelRenderable)
         {
-          modelNode->mMaterialIdx = 0; // must offer default of 0
-          auto eMaterial          = eRenderable->GetChild("material");
+          modelRenderable->mMaterialIdx = 0; // must offer default of 0
+          auto eMaterial                = eRenderable->GetChild("material");
           if(eMaterial)
           {
-            resourceIds.push_back({ResourceType::Material, eMaterial, modelNode->mMaterialIdx});
+            resourceIds.push_back({ResourceType::Material, eMaterial, modelRenderable->mMaterialIdx});
           }
 
-          if(!ReadColorCodeOrColor(eRenderable, modelNode->mColor, params.input.mConvertColorCode))
+          if(!ReadColorCodeOrColor(eRenderable, modelRenderable->mColor, params.input.mConvertColorCode))
           {
-            ReadColorCodeOrColor(node, modelNode->mColor, params.input.mConvertColorCode);
+            ReadColorCodeOrColor(node, modelRenderable->mColor, params.input.mConvertColorCode);
           }
         }
 
-        nodeDef.mRenderable = std::move(renderable);
+        nodeDef.mRenderables.push_back(std::move(renderable));
       }
     }
 
@@ -1426,9 +1428,8 @@ void DliLoader::Impl::ParseAnimations(const TreeNode* tnAnimations, LoadParams&
     AnimationDefinition animDef;
     ReadString(tnAnim.GetChild(NAME), animDef.mName);
 
-    auto       iFind     = std::lower_bound(definitions.begin(), definitions.end(), animDef, [](const AnimationDefinition& ad0, const AnimationDefinition& ad1) {
-      return ad0.mName < ad1.mName;
-    });
+    auto       iFind     = std::lower_bound(definitions.begin(), definitions.end(), animDef, [](const AnimationDefinition& ad0, const AnimationDefinition& ad1)
+                                  { return ad0.mName < ad1.mName; });
     const bool overwrite = iFind != definitions.end() && iFind->mName == animDef.mName;
     if(overwrite)
     {
@@ -1556,10 +1557,10 @@ void DliLoader::Impl::ParseAnimations(const TreeNode* tnAnimations, LoadParams&
 
           animProp.mKeyFrames = KeyFrames::New();
 
-          //In binary animation file only is saved the position, rotation, scale and blend shape weight keys.
-          //so, if it is vector3 we assume is position or scale keys, if it is vector4 we assume is rotation,
-          // otherwise are blend shape weight keys.
-          // TODO support for binary header with size information
+          // In binary animation file only is saved the position, rotation, scale and blend shape weight keys.
+          // so, if it is vector3 we assume is position or scale keys, if it is vector4 we assume is rotation,
+          //  otherwise are blend shape weight keys.
+          //  TODO support for binary header with size information
           Property::Type propType = Property::FLOAT; // assume blend shape weights
           if(animProp.mPropertyName == "orientation")
           {
@@ -1570,8 +1571,8 @@ void DliLoader::Impl::ParseAnimations(const TreeNode* tnAnimations, LoadParams&
             propType = Property::VECTOR3;
           }
 
-          //alphafunction is reserved for future implementation
-          // NOTE: right now we're just using AlphaFunction::LINEAR.
+          // alphafunction is reserved for future implementation
+          //  NOTE: right now we're just using AlphaFunction::LINEAR.
           unsigned char dummyAlphaFunction;
 
           float           progress;
@@ -1694,9 +1695,8 @@ void DliLoader::Impl::ParseAnimationGroups(const Toolkit::TreeNode* tnAnimationG
       continue;
     }
 
-    auto iFind = std::lower_bound(animGroups.begin(), animGroups.end(), groupName, [](const AnimationGroupDefinition& group, const std::string& name) {
-      return group.mName < name;
-    });
+    auto iFind = std::lower_bound(animGroups.begin(), animGroups.end(), groupName, [](const AnimationGroupDefinition& group, const std::string& name)
+                                  { return group.mName < name; });
     if(iFind != animGroups.end() && iFind->mName == groupName)
     {
       mOnError(FormatString("Animation group with name '%s' already exists; new entries will be merged.", groupName.c_str()));
index 60f6970..e6d34fc 100644 (file)
  * limitations under the License.
  *
  */
-#include "dali-scene3d/public-api/loader/gltf2-loader.h"
 #include <fstream>
-#include "dali-scene3d/internal/loader/gltf2-asset.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-scene3d/public-api/loader/utils.h"
-#include "dali/public-api/math/quaternion.h"
+#include <dali-scene3d/public-api/loader/gltf2-loader.h>
+#include <dali-scene3d/internal/loader/gltf2-asset.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-scene3d/public-api/loader/utils.h>
+#include <dali/public-api/math/quaternion.h>
+#include <dali/integration-api/debug.h>
 
 #define ENUM_STRING_MAPPING(t, x) \
   {                               \
@@ -168,6 +169,20 @@ const auto MATERIAL_PBR_READER = std::move(js::Reader<gt::Material::Pbr>()
                                              .Register(*js::MakeProperty("roughnessFactor", js::Read::Number<float>, &gt::Material::Pbr::mRoughnessFactor))
                                              .Register(*js::MakeProperty("metallicRoughnessTexture", js::ObjectReader<gt::TextureInfo>::Read, &gt::Material::Pbr::mMetallicRoughnessTexture)));
 
+const auto MATERIAL_SPECULAR_READER = std::move(js::Reader<gt::MaterialSpecular>()
+                                                  .Register(*js::MakeProperty("specularFactor", js::Read::Number<float>, &gt::MaterialSpecular::mSpecularFactor))
+                                                  .Register(*js::MakeProperty("specularTexture", js::ObjectReader<gt::TextureInfo>::Read, &gt::MaterialSpecular::mSpecularTexture))
+                                                  .Register(*js::MakeProperty("specularColorFactor", gt::ReadDaliVector<Vector3>, &gt::MaterialSpecular::mSpecularColorFactor))
+                                                  .Register(*js::MakeProperty("specularColorTexture", js::ObjectReader<gt::TextureInfo>::Read, &gt::MaterialSpecular::mSpecularColorTexture)));
+
+const auto MATERIAL_IOR_READER = std::move(js::Reader<gt::MaterialIor>()
+                                             .Register(*js::MakeProperty("ior", js::Read::Number<float>, &gt::MaterialIor::mIor)));
+
+
+const auto MATERIAL_EXTENSION_READER = std::move(js::Reader<gt::MaterialExtensions>()
+                                                   .Register(*js::MakeProperty("KHR_materials_ior", js::ObjectReader<gt::MaterialIor>::Read, &gt::MaterialExtensions::mMaterialIor))
+                                                   .Register(*js::MakeProperty("KHR_materials_specular", js::ObjectReader<gt::MaterialSpecular>::Read, &gt::MaterialExtensions::mMaterialSpecular)));
+
 const auto MATERIAL_READER = std::move(js::Reader<gt::Material>()
                                          .Register(*new js::Property<gt::Material, std::string_view>("name", js::Read::StringView, &gt::Material::mName))
                                          .Register(*js::MakeProperty("pbrMetallicRoughness", js::ObjectReader<gt::Material::Pbr>::Read, &gt::Material::mPbrMetallicRoughness))
@@ -176,7 +191,9 @@ const auto MATERIAL_READER = std::move(js::Reader<gt::Material>()
                                          .Register(*js::MakeProperty("emissiveTexture", js::ObjectReader<gt::TextureInfo>::Read, &gt::Material::mEmissiveTexture))
                                          .Register(*js::MakeProperty("emissiveFactor", gt::ReadDaliVector<Vector3>, &gt::Material::mEmissiveFactor))
                                          .Register(*js::MakeProperty("alphaMode", gt::ReadStringEnum<gt::AlphaMode>, &gt::Material::mAlphaMode))
-                                         .Register(*js::MakeProperty("alphaCutoff", js::Read::Number<float>, &gt::Material::mAlphaCutoff)));
+                                         .Register(*js::MakeProperty("alphaCutoff", js::Read::Number<float>, &gt::Material::mAlphaCutoff))
+                                         .Register(*js::MakeProperty("doubleSided", js::Read::Boolean, &gt::Material::mDoubleSided))
+                                         .Register(*js::MakeProperty("extensions", js::ObjectReader<gt::MaterialExtensions>::Read, &gt::Material::mMaterialExtensions)));
 
 std::map<gt::Attribute::Type, gt::Ref<gt::Accessor>> ReadMeshPrimitiveAttributes(const json_value_s& j)
 {
@@ -425,24 +442,24 @@ TextureDefinition ConvertTextureInfo(const gt::TextureInfo& mm)
   return TextureDefinition{std::string(mm.mTexture->mSource->mUri), ConvertSampler(mm.mTexture->mSampler)};
 }
 
-void ConvertMaterial(const gt::Material& m, decltype(ResourceBundle::mMaterials)& outMaterials)
+void ConvertMaterial(const gt::Material& material, decltype(ResourceBundle::mMaterials)& outMaterials)
 {
   MaterialDefinition matDef;
 
-  auto& pbr = m.mPbrMetallicRoughness;
-  if(m.mAlphaMode != gt::AlphaMode::OPAQUE || pbr.mBaseColorFactor.a < 1.f)
+  auto& pbr = material.mPbrMetallicRoughness;
+  if(pbr.mBaseColorFactor.a < 1.f)
   {
     matDef.mFlags |= MaterialDefinition::TRANSPARENCY;
   }
 
-  if(m.mAlphaMode == gt::AlphaMode::MASK)
+  if(material.mAlphaMode == gt::AlphaMode::MASK)
   {
-    matDef.SetAlphaCutoff(std::min(1.f, std::max(0.f, m.mAlphaCutoff)));
+    matDef.SetAlphaCutoff(std::min(1.f, std::max(0.f, material.mAlphaCutoff)));
   }
 
   matDef.mBaseColorFactor = pbr.mBaseColorFactor;
 
-  matDef.mTextureStages.reserve(!!pbr.mBaseColorTexture + !!pbr.mMetallicRoughnessTexture + !!m.mNormalTexture + !!m.mOcclusionTexture + !!m.mEmissiveTexture);
+  matDef.mTextureStages.reserve(!!pbr.mBaseColorTexture + !!pbr.mMetallicRoughnessTexture + !!material.mNormalTexture + !!material.mOcclusionTexture + !!material.mEmissiveTexture);
   if(pbr.mBaseColorTexture)
   {
     const auto semantic = MaterialDefinition::ALBEDO;
@@ -471,11 +488,11 @@ void ConvertMaterial(const gt::Material& m, decltype(ResourceBundle::mMaterials)
     matDef.mNeedMetallicRoughnessTexture = false;
   }
 
-  matDef.mNormalScale = m.mNormalTexture.mScale;
-  if(m.mNormalTexture)
+  matDef.mNormalScale = material.mNormalTexture.mScale;
+  if(material.mNormalTexture)
   {
     const auto semantic = MaterialDefinition::NORMAL;
-    matDef.mTextureStages.push_back({semantic, ConvertTextureInfo(m.mNormalTexture)});
+    matDef.mTextureStages.push_back({semantic, ConvertTextureInfo(material.mNormalTexture)});
     // TODO: and there had better be one
     matDef.mFlags |= semantic;
   }
@@ -484,31 +501,54 @@ void ConvertMaterial(const gt::Material& m, decltype(ResourceBundle::mMaterials)
     matDef.mNeedNormalTexture = false;
   }
 
-  // TODO: handle doubleSided
-  if(m.mOcclusionTexture)
+  if(material.mOcclusionTexture)
   {
     const auto semantic = MaterialDefinition::OCCLUSION;
-    matDef.mTextureStages.push_back({semantic, ConvertTextureInfo(m.mOcclusionTexture)});
+    matDef.mTextureStages.push_back({semantic, ConvertTextureInfo(material.mOcclusionTexture)});
     // TODO: and there had better be one
     matDef.mFlags |= semantic;
-    matDef.mOcclusionStrength = m.mOcclusionTexture.mStrength;
+    matDef.mOcclusionStrength = material.mOcclusionTexture.mStrength;
   }
 
-  if(m.mEmissiveTexture)
+  if(material.mEmissiveTexture)
   {
     const auto semantic = MaterialDefinition::EMISSIVE;
-    matDef.mTextureStages.push_back({semantic, ConvertTextureInfo(m.mEmissiveTexture)});
+    matDef.mTextureStages.push_back({semantic, ConvertTextureInfo(material.mEmissiveTexture)});
     // TODO: and there had better be one
     matDef.mFlags |= semantic;
-    matDef.mEmissiveFactor = m.mEmissiveFactor;
+    matDef.mEmissiveFactor = material.mEmissiveFactor;
+  }
+
+  if(material.mMaterialExtensions.mMaterialIor.mIor < MAXFLOAT)
+  {
+    float ior = material.mMaterialExtensions.mMaterialIor.mIor;
+    matDef.mDielectricSpecular = powf((ior-1.0f)/(ior+1.0f), 2.0f);
   }
+  matDef.mSpecularFactor      = material.mMaterialExtensions.mMaterialSpecular.mSpecularFactor;
+  matDef.mSpecularColorFactor = material.mMaterialExtensions.mMaterialSpecular.mSpecularColorFactor;
+
+  if(material.mMaterialExtensions.mMaterialSpecular.mSpecularTexture)
+  {
+    const auto semantic = MaterialDefinition::SPECULAR;
+    matDef.mTextureStages.push_back({semantic, ConvertTextureInfo(material.mMaterialExtensions.mMaterialSpecular.mSpecularTexture)});
+    matDef.mFlags |= semantic;
+  }
+
+  if(material.mMaterialExtensions.mMaterialSpecular.mSpecularColorTexture)
+  {
+    const auto semantic = MaterialDefinition::SPECULAR_COLOR;
+    matDef.mTextureStages.push_back({semantic, ConvertTextureInfo(material.mMaterialExtensions.mMaterialSpecular.mSpecularColorTexture)});
+    matDef.mFlags |= semantic;
+  }
+
+  matDef.mDoubleSided = material.mDoubleSided;
 
   outMaterials.emplace_back(std::move(matDef), TextureSet());
 }
 
-void ConvertMaterials(const gt::Document& doc, ConversionContext& cctx)
+void ConvertMaterials(const gt::Document& doc, ConversionContext& context)
 {
-  auto& outMaterials = cctx.mOutput.mResources.mMaterials;
+  auto& outMaterials = context.mOutput.mResources.mMaterials;
   outMaterials.reserve(doc.mMaterials.size());
 
   for(auto& m : doc.mMaterials)
@@ -570,33 +610,33 @@ MeshDefinition::Accessor ConvertMeshPrimitiveAccessor(const gt::Accessor& acc)
     std::move(sparseBlob)};
 }
 
-void ConvertMeshes(const gt::Document& doc, ConversionContext& cctx)
+void ConvertMeshes(const gt::Document& doc, ConversionContext& context)
 {
   uint32_t meshCount = 0;
-  cctx.mMeshIds.reserve(doc.mMeshes.size());
-  for(auto& m : doc.mMeshes)
+  context.mMeshIds.reserve(doc.mMeshes.size());
+  for(auto& mesh : doc.mMeshes)
   {
-    cctx.mMeshIds.push_back(meshCount);
-    meshCount += m.mPrimitives.size();
+    context.mMeshIds.push_back(meshCount);
+    meshCount += mesh.mPrimitives.size();
   }
 
-  auto& outMeshes = cctx.mOutput.mResources.mMeshes;
+  auto& outMeshes = context.mOutput.mResources.mMeshes;
   outMeshes.reserve(meshCount);
-  for(auto& m : doc.mMeshes)
+  for(auto& mesh : doc.mMeshes)
   {
-    for(auto& p : m.mPrimitives)
+    for(auto& primitive : mesh.mPrimitives)
     {
-      MeshDefinition meshDef;
+      MeshDefinition meshDefinition;
 
-      auto& attribs          = p.mAttributes;
-      meshDef.mUri           = attribs.begin()->second->mBufferView->mBuffer->mUri;
-      meshDef.mPrimitiveType = GLTF2_TO_DALI_PRIMITIVES[p.mMode];
+      auto& attribs          = primitive.mAttributes;
+      meshDefinition.mUri           = attribs.begin()->second->mBufferView->mBuffer->mUri;
+      meshDefinition.mPrimitiveType = GLTF2_TO_DALI_PRIMITIVES[primitive.mMode];
 
       auto& accPositions = *attribs.find(gt::Attribute::POSITION)->second;
-      meshDef.mPositions = ConvertMeshPrimitiveAccessor(accPositions);
+      meshDefinition.mPositions = ConvertMeshPrimitiveAccessor(accPositions);
       // glTF2 support vector4 tangent for mesh.
       // https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#meshes-overview
-      meshDef.mTangentType = Property::VECTOR4;
+      meshDefinition.mTangentType = Property::VECTOR4;
 
       const bool needNormalsTangents = accPositions.mType == gt::AccessorType::VEC3;
       for(auto& am : ATTRIBUTE_MAPPINGS)
@@ -604,14 +644,14 @@ void ConvertMeshes(const gt::Document& doc, ConversionContext& cctx)
         auto iFind = attribs.find(am.mType);
         if(iFind != attribs.end())
         {
-          DALI_ASSERT_DEBUG(iFind->second->mBufferView->mBuffer->mUri.compare(meshDef.mUri) == 0);
-          auto& accessor = meshDef.*(am.mAccessor);
+          DALI_ASSERT_DEBUG(iFind->second->mBufferView->mBuffer->mUri.compare(meshDefinition.mUri) == 0);
+          auto& accessor = meshDefinition.*(am.mAccessor);
           accessor       = ConvertMeshPrimitiveAccessor(*iFind->second);
 
           if(iFind->first == gt::Attribute::JOINTS_0)
           {
-            meshDef.mFlags |= (iFind->second->mComponentType == gt::Component::UNSIGNED_SHORT) * MeshDefinition::U16_JOINT_IDS;
-            DALI_ASSERT_DEBUG(MaskMatch(meshDef.mFlags, MeshDefinition::U16_JOINT_IDS) || iFind->second->mComponentType == gt::Component::FLOAT);
+            meshDefinition.mFlags |= (iFind->second->mComponentType == gt::Component::UNSIGNED_SHORT) * MeshDefinition::U16_JOINT_IDS;
+            DALI_ASSERT_DEBUG(MaskMatch(meshDefinition.mFlags, MeshDefinition::U16_JOINT_IDS) || iFind->second->mComponentType == gt::Component::FLOAT);
           }
         }
         else if(needNormalsTangents)
@@ -619,11 +659,11 @@ void ConvertMeshes(const gt::Document& doc, ConversionContext& cctx)
           switch(am.mType)
           {
             case gt::Attribute::NORMAL:
-              meshDef.RequestNormals();
+              meshDefinition.RequestNormals();
               break;
 
             case gt::Attribute::TANGENT:
-              meshDef.RequestTangents();
+              meshDefinition.RequestTangents();
               break;
 
             default:
@@ -632,18 +672,18 @@ void ConvertMeshes(const gt::Document& doc, ConversionContext& cctx)
         }
       }
 
-      if(p.mIndices)
+      if(primitive.mIndices)
       {
-        meshDef.mIndices = ConvertMeshPrimitiveAccessor(*p.mIndices);
-        meshDef.mFlags |= (p.mIndices->mComponentType == gt::Component::UNSIGNED_INT) * MeshDefinition::U32_INDICES;
-        DALI_ASSERT_DEBUG(MaskMatch(meshDef.mFlags, MeshDefinition::U32_INDICES) || p.mIndices->mComponentType == gt::Component::UNSIGNED_SHORT);
+        meshDefinition.mIndices = ConvertMeshPrimitiveAccessor(*primitive.mIndices);
+        meshDefinition.mFlags |= (primitive.mIndices->mComponentType == gt::Component::UNSIGNED_INT) * MeshDefinition::U32_INDICES;
+        DALI_ASSERT_DEBUG(MaskMatch(meshDefinition.mFlags, MeshDefinition::U32_INDICES) || primitive.mIndices->mComponentType == gt::Component::UNSIGNED_SHORT);
       }
 
-      if(!p.mTargets.empty())
+      if(!primitive.mTargets.empty())
       {
-        meshDef.mBlendShapes.reserve(p.mTargets.size());
-        meshDef.mBlendShapeVersion = BlendShapes::Version::VERSION_2_0;
-        for(const auto& target : p.mTargets)
+        meshDefinition.mBlendShapes.reserve(primitive.mTargets.size());
+        meshDefinition.mBlendShapeVersion = BlendShapes::Version::VERSION_2_0;
+        for(const auto& target : primitive.mTargets)
         {
           MeshDefinition::BlendShape blendShape;
 
@@ -664,44 +704,44 @@ void ConvertMeshes(const gt::Document& doc, ConversionContext& cctx)
             blendShape.tangents = ConvertMeshPrimitiveAccessor(*it->second);
           }
 
-          if(!m.mWeights.empty())
+          if(!mesh.mWeights.empty())
           {
-            blendShape.weight = m.mWeights[meshDef.mBlendShapes.size()];
+            blendShape.weight = mesh.mWeights[meshDefinition.mBlendShapes.size()];
           }
 
-          meshDef.mBlendShapes.push_back(std::move(blendShape));
+          meshDefinition.mBlendShapes.push_back(std::move(blendShape));
         }
       }
 
-      outMeshes.push_back({std::move(meshDef), MeshGeometry{}});
+      outMeshes.push_back({std::move(meshDefinition), MeshGeometry{}});
     }
   }
 }
 
-ModelNode* MakeModelNode(const gt::Mesh::Primitive& prim, ConversionContext& cctx)
+ModelRenderable* MakeModelRenderable(const gt::Mesh::Primitive& prim, ConversionContext& context)
 {
-  auto modelNode = new ModelNode();
+  auto modelRenderable = new ModelRenderable();
 
-  modelNode->mShaderIdx = 0; // TODO: further thought
+  modelRenderable->mShaderIdx = 0; // TODO: further thought
 
   auto materialIdx = prim.mMaterial.GetIndex();
   if(INVALID_INDEX == materialIdx)
   {
     // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#default-material
-    if(INVALID_INDEX == cctx.mDefaultMaterial)
+    if(INVALID_INDEX == context.mDefaultMaterial)
     {
-      auto& outMaterials    = cctx.mOutput.mResources.mMaterials;
-      cctx.mDefaultMaterial = outMaterials.size();
+      auto& outMaterials    = context.mOutput.mResources.mMaterials;
+      context.mDefaultMaterial = outMaterials.size();
 
       ConvertMaterial(gt::Material{}, outMaterials);
     }
 
-    materialIdx = cctx.mDefaultMaterial;
+    materialIdx = context.mDefaultMaterial;
   }
 
-  modelNode->mMaterialIdx = materialIdx;
+  modelRenderable->mMaterialIdx = materialIdx;
 
-  return modelNode;
+  return modelRenderable;
 }
 
 void ConvertCamera(const gt::Camera& camera, CameraParameters& camParams)
@@ -725,9 +765,9 @@ void ConvertCamera(const gt::Camera& camera, CameraParameters& camParams)
   }
 }
 
-void ConvertNode(gt::Node const& node, const Index gltfIdx, Index parentIdx, ConversionContext& cctx, bool isMRendererModel)
+void ConvertNode(gt::Node const& node, const Index gltfIdx, Index parentIdx, ConversionContext& context, bool isMRendererModel)
 {
-  auto& output    = cctx.mOutput;
+  auto& output    = context.mOutput;
   auto& scene     = output.mScene;
   auto& resources = output.mResources;
 
@@ -762,42 +802,27 @@ void ConvertNode(gt::Node const& node, const Index gltfIdx, Index parentIdx, Con
     ExceptionFlinger(ASSERT_LOCATION) << "Node name '" << node.mName << "' is not unique; scene is invalid.";
   }
 
-  cctx.mNodeIndices.RegisterMapping(gltfIdx, idx);
+  context.mNodeIndices.RegisterMapping(gltfIdx, idx);
 
   Index skeletonIdx = node.mSkin ? node.mSkin.GetIndex() : INVALID_INDEX;
-  if(node.mMesh && !node.mMesh->mPrimitives.empty())
+  if(node.mMesh)
   {
-    auto& mesh = *node.mMesh;
-
-    auto iPrim          = mesh.mPrimitives.begin();
-    auto modelNode      = MakeModelNode(*iPrim, cctx);
-    auto meshIdx        = cctx.mMeshIds[node.mMesh.GetIndex()];
-    modelNode->mMeshIdx = meshIdx;
-
-    weakNode->mRenderable.reset(modelNode);
-
-    DALI_ASSERT_DEBUG(resources.mMeshes[meshIdx].first.mSkeletonIdx == INVALID_INDEX ||
-                      resources.mMeshes[meshIdx].first.mSkeletonIdx == skeletonIdx);
-    resources.mMeshes[meshIdx].first.mSkeletonIdx = skeletonIdx;
-
-    // As does model-exporter, we'll create anonymous child nodes for additional mesh( primitiv)es.
-    while(++iPrim != mesh.mPrimitives.end())
+    auto&    mesh           = *node.mMesh;
+    uint32_t primitiveCount = mesh.mPrimitives.size();
+    auto     meshIdx        = context.mMeshIds[node.mMesh.GetIndex()];
+    weakNode->mRenderables.reserve(primitiveCount);
+    for(uint32_t i = 0; i < primitiveCount; ++i)
     {
-      std::unique_ptr<NodeDefinition> child{new NodeDefinition};
-      child->mParentIdx = idx;
-
-      auto childModel = MakeModelNode(*iPrim, cctx);
-
-      ++meshIdx;
-      childModel->mMeshIdx = meshIdx;
+      std::unique_ptr<NodeDefinition::Renderable> renderable;
+      auto modelRenderable      = MakeModelRenderable(mesh.mPrimitives[i], context);
+      modelRenderable->mMeshIdx = meshIdx + i;
 
-      child->mRenderable.reset(childModel);
+      DALI_ASSERT_DEBUG(resources.mMeshes[modelRenderable->mMeshIdx].first.mSkeletonIdx == INVALID_INDEX ||
+                        resources.mMeshes[modelRenderable->mMeshIdx].first.mSkeletonIdx == skeletonIdx);
+      resources.mMeshes[modelRenderable->mMeshIdx].first.mSkeletonIdx = skeletonIdx;
 
-      scene.AddNode(std::move(child));
-
-      DALI_ASSERT_DEBUG(resources.mMeshes[meshIdx].first.mSkeletonIdx == INVALID_INDEX ||
-                        resources.mMeshes[meshIdx].first.mSkeletonIdx == skeletonIdx);
-      resources.mMeshes[meshIdx].first.mSkeletonIdx = skeletonIdx;
+      renderable.reset(modelRenderable);
+      weakNode->mRenderables.push_back(std::move(renderable));
     }
   }
 
@@ -812,13 +837,13 @@ void ConvertNode(gt::Node const& node, const Index gltfIdx, Index parentIdx, Con
 
   for(auto& n : node.mChildren)
   {
-    ConvertNode(*n, n.GetIndex(), idx, cctx, isMRendererModel);
+    ConvertNode(*n, n.GetIndex(), idx, context, isMRendererModel);
   }
 }
 
-void ConvertSceneNodes(const gt::Scene& scene, ConversionContext& cctx, bool isMRendererModel)
+void ConvertSceneNodes(const gt::Scene& scene, ConversionContext& context, bool isMRendererModel)
 {
-  auto& outScene = cctx.mOutput.mScene;
+  auto& outScene = context.mOutput.mScene;
   Index rootIdx  = outScene.GetNodeCount();
   switch(scene.mNodes.size())
   {
@@ -826,7 +851,7 @@ void ConvertSceneNodes(const gt::Scene& scene, ConversionContext& cctx, bool isM
       break;
 
     case 1:
-      ConvertNode(*scene.mNodes[0], scene.mNodes[0].GetIndex(), INVALID_INDEX, cctx, isMRendererModel);
+      ConvertNode(*scene.mNodes[0], scene.mNodes[0].GetIndex(), INVALID_INDEX, context, isMRendererModel);
       outScene.AddRootNode(rootIdx);
       break;
 
@@ -840,25 +865,25 @@ void ConvertSceneNodes(const gt::Scene& scene, ConversionContext& cctx, bool isM
 
       for(auto& n : scene.mNodes)
       {
-        ConvertNode(*n, n.GetIndex(), rootIdx, cctx, isMRendererModel);
+        ConvertNode(*n, n.GetIndex(), rootIdx, context, isMRendererModel);
       }
       break;
     }
   }
 }
 
-void ConvertNodes(const gt::Document& doc, ConversionContext& cctx, bool isMRendererModel)
+void ConvertNodes(const gt::Document& doc, ConversionContext& context, bool isMRendererModel)
 {
-  ConvertSceneNodes(*doc.mScene, cctx, isMRendererModel);
+  ConvertSceneNodes(*doc.mScene, context, isMRendererModel);
 
   for(uint32_t i = 0, i1 = doc.mScene.GetIndex(); i < i1; ++i)
   {
-    ConvertSceneNodes(doc.mScenes[i], cctx, isMRendererModel);
+    ConvertSceneNodes(doc.mScenes[i], context, isMRendererModel);
   }
 
   for(uint32_t i = doc.mScene.GetIndex() + 1; i < doc.mScenes.size(); ++i)
   {
-    ConvertSceneNodes(doc.mScenes[i], cctx, isMRendererModel);
+    ConvertSceneNodes(doc.mScenes[i], context, isMRendererModel);
   }
 }
 
@@ -946,9 +971,9 @@ float LoadBlendShapeKeyFrames(const std::string& path, const gt::Animation::Chan
   return duration;
 }
 
-void ConvertAnimations(const gt::Document& doc, ConversionContext& cctx)
+void ConvertAnimations(const gt::Document& doc, ConversionContext& context)
 {
-  auto& output = cctx.mOutput;
+  auto& output = context.mOutput;
 
   output.mAnimationDefinitions.reserve(output.mAnimationDefinitions.size() + doc.mAnimations.size());
 
@@ -979,8 +1004,8 @@ void ConvertAnimations(const gt::Document& doc, ConversionContext& cctx)
       }
       else
       {
-        Index index = cctx.mNodeIndices.GetRuntimeId(channel.mTarget.mNode.GetIndex());
-        nodeName    = cctx.mOutput.mScene.GetNode(index)->mName;
+        Index index = context.mNodeIndices.GetRuntimeId(channel.mTarget.mNode.GetIndex());
+        nodeName    = context.mOutput.mScene.GetNode(index)->mName;
       }
 
       float duration = 0.f;
@@ -995,7 +1020,7 @@ void ConvertAnimations(const gt::Document& doc, ConversionContext& cctx)
           animatedProperty.mPropertyName = POSITION_PROPERTY;
 
           animatedProperty.mKeyFrames = KeyFrames::New();
-          duration                    = LoadKeyFrames<Vector3>(cctx.mPath, channel, animatedProperty.mKeyFrames, channel.mTarget.mPath);
+          duration                    = LoadKeyFrames<Vector3>(context.mPath, channel, animatedProperty.mKeyFrames, channel.mTarget.mPath);
 
           animatedProperty.mTimePeriod = {0.f, duration};
           break;
@@ -1008,7 +1033,7 @@ void ConvertAnimations(const gt::Document& doc, ConversionContext& cctx)
           animatedProperty.mPropertyName = ORIENTATION_PROPERTY;
 
           animatedProperty.mKeyFrames = KeyFrames::New();
-          duration                    = LoadKeyFrames<Quaternion>(cctx.mPath, channel, animatedProperty.mKeyFrames, channel.mTarget.mPath);
+          duration                    = LoadKeyFrames<Quaternion>(context.mPath, channel, animatedProperty.mKeyFrames, channel.mTarget.mPath);
 
           animatedProperty.mTimePeriod = {0.f, duration};
           break;
@@ -1021,14 +1046,14 @@ void ConvertAnimations(const gt::Document& doc, ConversionContext& cctx)
           animatedProperty.mPropertyName = SCALE_PROPERTY;
 
           animatedProperty.mKeyFrames = KeyFrames::New();
-          duration                    = LoadKeyFrames<Vector3>(cctx.mPath, channel, animatedProperty.mKeyFrames, channel.mTarget.mPath);
+          duration                    = LoadKeyFrames<Vector3>(context.mPath, channel, animatedProperty.mKeyFrames, channel.mTarget.mPath);
 
           animatedProperty.mTimePeriod = {0.f, duration};
           break;
         }
         case gt::Animation::Channel::Target::WEIGHTS:
         {
-          duration = LoadBlendShapeKeyFrames(cctx.mPath, channel, nodeName, propertyIndex, animationDef.mProperties);
+          duration = LoadBlendShapeKeyFrames(context.mPath, channel, nodeName, propertyIndex, animationDef.mProperties);
 
           break;
         }
@@ -1048,7 +1073,7 @@ void ConvertAnimations(const gt::Document& doc, ConversionContext& cctx)
   }
 }
 
-void ProcessSkins(const gt::Document& doc, ConversionContext& cctx)
+void ProcessSkins(const gt::Document& doc, ConversionContext& context)
 {
   // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#skininversebindmatrices
   // If an inverseBindMatrices accessor was provided, we'll load the joint data from the buffer,
@@ -1090,7 +1115,7 @@ void ProcessSkins(const gt::Document& doc, ConversionContext& cctx)
     }
   };
 
-  auto& resources = cctx.mOutput.mResources;
+  auto& resources = context.mOutput.mResources;
   resources.mSkeletons.reserve(doc.mSkins.size());
 
   for(auto& s : doc.mSkins)
@@ -1098,7 +1123,7 @@ void ProcessSkins(const gt::Document& doc, ConversionContext& cctx)
     std::unique_ptr<IInverseBindMatrixProvider> ibmProvider;
     if(s.mInverseBindMatrices)
     {
-      ibmProvider.reset(new InverseBindMatrixAccessor(*s.mInverseBindMatrices, cctx.mPath));
+      ibmProvider.reset(new InverseBindMatrixAccessor(*s.mInverseBindMatrices, context.mPath));
     }
     else
     {
@@ -1108,14 +1133,14 @@ void ProcessSkins(const gt::Document& doc, ConversionContext& cctx)
     SkeletonDefinition skeleton;
     if(s.mSkeleton.GetIndex() != INVALID_INDEX)
     {
-      skeleton.mRootNodeIdx = cctx.mNodeIndices.GetRuntimeId(s.mSkeleton.GetIndex());
+      skeleton.mRootNodeIdx = context.mNodeIndices.GetRuntimeId(s.mSkeleton.GetIndex());
     }
 
     skeleton.mJoints.resize(s.mJoints.size());
     auto iJoint = skeleton.mJoints.begin();
     for(auto& j : s.mJoints)
     {
-      iJoint->mNodeIdx = cctx.mNodeIndices.GetRuntimeId(j.GetIndex());
+      iJoint->mNodeIdx = context.mNodeIndices.GetRuntimeId(j.GetIndex());
 
       ibmProvider->Provide(iJoint->mInverseBindMatrix);
 
@@ -1128,12 +1153,16 @@ void ProcessSkins(const gt::Document& doc, ConversionContext& cctx)
 
 void ProduceShaders(ShaderDefinitionFactory& shaderFactory, SceneDefinition& scene)
 {
-  for(size_t i0 = 0, i1 = scene.GetNodeCount(); i0 != i1; ++i0)
+  uint32_t nodeCount = scene.GetNodeCount();
+  for(uint32_t i = 0; i < nodeCount; ++i)
   {
-    auto nodeDef = scene.GetNode(i0);
-    if(auto renderable = nodeDef->mRenderable.get())
+    auto nodeDef = scene.GetNode(i);
+    for(auto& renderable : nodeDef->mRenderables)
     {
-      renderable->mShaderIdx = shaderFactory.ProduceShader(*nodeDef);
+      if(shaderFactory.ProduceShader(*renderable) == INVALID_INDEX)
+      {
+        DALI_LOG_ERROR("Fail to produce shader\n");
+      }
     }
   }
 }
@@ -1151,6 +1180,9 @@ void SetObjectReaders()
   js::SetObjectReader(TEXURE_READER);
   js::SetObjectReader(TEXURE_INFO_READER);
   js::SetObjectReader(MATERIAL_PBR_READER);
+  js::SetObjectReader(MATERIAL_SPECULAR_READER);
+  js::SetObjectReader(MATERIAL_IOR_READER);
+  js::SetObjectReader(MATERIAL_EXTENSION_READER);
   js::SetObjectReader(MATERIAL_READER);
   js::SetObjectReader(MESH_PRIMITIVE_READER);
   js::SetObjectReader(MESH_READER);
@@ -1166,12 +1198,12 @@ void SetObjectReaders()
   js::SetObjectReader(SCENE_READER);
 }
 
-void SetDefaultEnvironmentMap(const gt::Document& doc, ConversionContext& cctx)
+void SetDefaultEnvironmentMap(const gt::Document& doc, ConversionContext& context)
 {
   EnvironmentDefinition envDef;
   envDef.mUseBrdfTexture = true;
   envDef.mIblIntensity   = Scene3D::Loader::EnvironmentDefinition::GetDefaultIntensity();
-  cctx.mOutput.mResources.mEnvironmentMaps.push_back({std::move(envDef), EnvironmentDefinition::Textures()});
+  context.mOutput.mResources.mEnvironmentMaps.push_back({std::move(envDef), EnvironmentDefinition::Textures()});
 }
 
 } // namespace
@@ -1222,18 +1254,18 @@ void LoadGltfScene(const std::string& url, ShaderDefinitionFactory& shaderFactor
   DOCUMENT_READER.Read(rootObj, doc);
 
   auto              path = url.substr(0, url.rfind('/') + 1);
-  ConversionContext cctx{params, path, INVALID_INDEX};
+  ConversionContext context{params, path, INVALID_INDEX};
 
-  ConvertMaterials(doc, cctx);
-  ConvertMeshes(doc, cctx);
-  ConvertNodes(doc, cctx, isMRendererModel);
-  ConvertAnimations(doc, cctx);
-  ProcessSkins(doc, cctx);
+  ConvertMaterials(doc, context);
+  ConvertMeshes(doc, context);
+  ConvertNodes(doc, context, isMRendererModel);
+  ConvertAnimations(doc, context);
+  ProcessSkins(doc, context);
   ProduceShaders(shaderFactory, params.mScene);
   params.mScene.EnsureUniqueSkinningShaderInstances(params.mResources);
 
   // Set Default Environment map
-  SetDefaultEnvironmentMap(doc, cctx);
+  SetDefaultEnvironmentMap(doc, context);
 }
 
 } // namespace Loader
index 480da95..7f86add 100644 (file)
@@ -236,6 +236,18 @@ MaterialDefinition::LoadRaw(const std::string& imagesPath) const
     ++iTexture;
   }
 
+  if(checkStage(SPECULAR))
+  {
+    raw.mTextures.push_back({SyncImageLoader::Load(imagesPath + iTexture->mTexture.mImageUri), iTexture->mTexture.mSamplerFlags});
+    ++iTexture;
+  }
+
+  if(checkStage(SPECULAR_COLOR))
+  {
+    raw.mTextures.push_back({SyncImageLoader::Load(imagesPath + iTexture->mTexture.mImageUri), iTexture->mTexture.mSamplerFlags});
+    ++iTexture;
+  }
+
   return raw;
 }
 
index d96d888..119f7c4 100644 (file)
@@ -130,13 +130,15 @@ struct DALI_SCENE3D_API MaterialDefinition
   enum Flags : uint32_t
   {
     // Texture semantics
-    ALBEDO     = NthBit(0),
-    METALLIC   = NthBit(1),
-    ROUGHNESS  = NthBit(2),
-    NORMAL     = NthBit(3),
-    EMISSIVE   = NthBit(4), // TODO: support
-    OCCLUSION  = NthBit(5), // TODO: support
-    SUBSURFACE = NthBit(6), // Note: dli-only
+    ALBEDO         = NthBit(0),
+    METALLIC       = NthBit(1),
+    ROUGHNESS      = NthBit(2),
+    NORMAL         = NthBit(3),
+    EMISSIVE       = NthBit(4),
+    OCCLUSION      = NthBit(5),
+    SPECULAR       = NthBit(6),
+    SPECULAR_COLOR = NthBit(7),
+    SUBSURFACE     = NthBit(8), // Note: dli-only
 
     // Other binary options
     TRANSPARENCY  = NthBit(20),
@@ -221,19 +223,23 @@ struct DALI_SCENE3D_API MaterialDefinition
 public: // DATA
   uint32_t mFlags = 0x0;
 
-  Index   mEnvironmentIdx    = 0;
-  Vector4 mColor             = Color::WHITE;
-  float   mMetallic          = 1.f;
-  float   mRoughness         = 1.f;
-  Vector4 mBaseColorFactor   = Vector4::ONE;
-  float   mNormalScale       = 1.f;
-  float   mOcclusionStrength = 1.f;
-  Vector3 mEmissiveFactor    = Vector3::ZERO;
+  Index   mEnvironmentIdx      = 0;
+  Vector4 mColor               = Color::WHITE;
+  float   mMetallic            = 1.f;
+  float   mRoughness           = 1.f;
+  Vector4 mBaseColorFactor     = Vector4::ONE;
+  float   mNormalScale         = 1.f;
+  float   mOcclusionStrength   = 1.f;
+  Vector3 mEmissiveFactor      = Vector3::ZERO;
+  float   mDielectricSpecular  = 0.04f;
+  float   mSpecularFactor      = 1.0f;
+  Vector3 mSpecularColorFactor = Vector3::ONE;
 
   // For the glTF, each of albedo, metallicRoughness, normal textures are not essential.
   bool mNeedAlbedoTexture            = true;
   bool mNeedMetallicRoughnessTexture = true;
   bool mNeedNormalTexture            = true;
+  bool mDoubleSided                  = false;
 
   std::vector<TextureStage> mTextureStages;
 };
index c83fc44..bbed301 100644 (file)
@@ -77,9 +77,9 @@ Actor NodeDefinition::CreateActor(CreateParams& params) const
 
   actor.RegisterProperty(ORIGINAL_MATRIX_PROPERTY_NAME, GetLocalSpace(), Property::AccessMode::READ_ONLY);
 
-  if(mRenderable)
+  for(auto& renderable : mRenderables)
   {
-    mRenderable->OnCreate(*this, params, actor);
+    renderable->OnCreate(*this, params, actor);
   }
 
   for(auto& e : mExtras)
@@ -114,20 +114,38 @@ std::string_view NodeDefinition::GetIblYDirectionUniformName()
 
 bool NodeDefinition::GetExtents(const ResourceBundle& resources, Vector3& min, Vector3& max) const
 {
-  if(mRenderable)
+  if(mRenderables.empty())
   {
-    if(!mRenderable->GetExtents(resources, min, max))
+    return false;
+  }
+
+  bool useModelExtents = false;
+  for(auto& renderable : mRenderables)
+  {
+    Vector3 renderableMin(Vector3::ONE * MAXFLOAT), renderableMax(-Vector3::ONE * MAXFLOAT);
+    if(!renderable->GetExtents(resources, renderableMin, renderableMax))
     {
-      // If the renderable node don't have mesh accessor, use size to compute extents.
-      min = -mSize / 2.0f;
-      max = mSize / 2.0f;
+      useModelExtents = false;
+      break;
     }
-    return true;
+    useModelExtents = true;
+    min.x           = std::min(min.x, renderableMin.x);
+    min.y           = std::min(min.y, renderableMin.y);
+    min.z           = std::min(min.z, renderableMin.z);
+    max.x           = std::max(max.x, renderableMax.x);
+    max.y           = std::max(max.y, renderableMax.y);
+    max.z           = std::max(max.z, renderableMax.z);
   }
-  return false;
+  if(!useModelExtents)
+  {
+    // If the renderable node don't have mesh accessor, use size to compute extents.
+    min = -mSize / 2.0f;
+    max = mSize / 2.0f;
+  }
+  return true;
 }
 
-bool ModelNode::GetExtents(const ResourceBundle& resources, Vector3& min, Vector3& max) const
+bool ModelRenderable::GetExtents(const ResourceBundle& resources, Vector3& min, Vector3& max) const
 {
   auto&    mesh    = resources.mMeshes[mMeshIdx];
   uint32_t minSize = mesh.first.mPositions.mBlob.mMin.size();
@@ -146,21 +164,21 @@ bool ModelNode::GetExtents(const ResourceBundle& resources, Vector3& min, Vector
   return false;
 }
 
-void ModelNode::RegisterResources(IResourceReceiver& receiver) const
+void ModelRenderable::RegisterResources(IResourceReceiver& receiver) const
 {
   Renderable::RegisterResources(receiver);
   receiver.Register(ResourceType::Mesh, mMeshIdx);
   receiver.Register(ResourceType::Material, mMaterialIdx);
 }
 
-void ModelNode::ReflectResources(IResourceReflector& reflector)
+void ModelRenderable::ReflectResources(IResourceReflector& reflector)
 {
   Renderable::ReflectResources(reflector);
   reflector.Reflect(ResourceType::Mesh, mMeshIdx);
   reflector.Reflect(ResourceType::Material, mMaterialIdx);
 }
 
-void ModelNode::OnCreate(const NodeDefinition& node, NodeDefinition::CreateParams& params, Actor& actor) const
+void ModelRenderable::OnCreate(const NodeDefinition& node, NodeDefinition::CreateParams& params, Actor& actor) const
 {
   DALI_ASSERT_DEBUG(mMeshIdx != INVALID_INDEX);
   Renderable::OnCreate(node, params, actor);
@@ -168,7 +186,7 @@ void ModelNode::OnCreate(const NodeDefinition& node, NodeDefinition::CreateParam
   auto& resources = params.mResources;
   auto& mesh      = resources.mMeshes[mMeshIdx];
 
-  auto     renderer = actor.GetRendererAt(0);
+  auto     renderer = actor.GetRendererAt(actor.GetRendererCount() - 1u);
   Geometry geometry = mesh.second.geometry;
   renderer.SetGeometry(geometry);
 
@@ -203,29 +221,28 @@ void ModelNode::OnCreate(const NodeDefinition& node, NodeDefinition::CreateParam
     textures = newTextureSet;
   }
 
-  renderer.SetTextures(textures);
-
-  actor.SetProperty(Actor::Property::COLOR, mColor);
-
-  actor.RegisterProperty("uHasVertexColor", static_cast<float>(mesh.first.mColors.IsDefined()));
+  renderer.RegisterProperty("uHasVertexColor", static_cast<float>(mesh.first.mColors.IsDefined()));
 
   auto& matDef = resources.mMaterials[mMaterialIdx].first;
   actor.RegisterProperty("uColorFactor", matDef.mBaseColorFactor);
   actor.RegisterProperty("uMetallicFactor", matDef.mMetallic);
   actor.RegisterProperty("uRoughnessFactor", matDef.mRoughness);
+  actor.RegisterProperty("uDielectricSpecular", matDef.mDielectricSpecular);
+  actor.RegisterProperty("uSpecularFactor", matDef.mSpecularFactor);
+  actor.RegisterProperty("uSpecularColorFactor", matDef.mSpecularColorFactor);
   actor.RegisterProperty("uNormalScale", matDef.mNormalScale);
   if(matDef.mFlags & MaterialDefinition::OCCLUSION)
   {
-    actor.RegisterProperty("uOcclusionStrength", matDef.mOcclusionStrength);
+    renderer.RegisterProperty("uOcclusionStrength", matDef.mOcclusionStrength);
   }
   if(matDef.mFlags & MaterialDefinition::EMISSIVE)
   {
-    actor.RegisterProperty("uEmissiveFactor", matDef.mEmissiveFactor);
+    renderer.RegisterProperty("uEmissiveFactor", matDef.mEmissiveFactor);
   }
 
   Index envIdx = matDef.mEnvironmentIdx;
-  actor.RegisterProperty(IBL_INTENSITY_STRING.data(), resources.mEnvironmentMaps[envIdx].first.mIblIntensity);
-  actor.RegisterProperty(IBL_Y_DIRECTION.data(), resources.mEnvironmentMaps[envIdx].first.mYDirection);
+  renderer.RegisterProperty(IBL_INTENSITY_STRING.data(), resources.mEnvironmentMaps[envIdx].first.mIblIntensity);
+  renderer.RegisterProperty(IBL_Y_DIRECTION.data(), resources.mEnvironmentMaps[envIdx].first.mYDirection);
 
   float opaque      = 0.0f;
   float mask        = 0.0f;
@@ -241,14 +258,18 @@ void ModelNode::OnCreate(const NodeDefinition& node, NodeDefinition::CreateParam
       mask = 1.0f;
     }
   }
-  actor.RegisterProperty("uOpaque", opaque);
-  actor.RegisterProperty("uMask", mask);
-  actor.RegisterProperty("uAlphaThreshold", alphaCutoff);
+  renderer.RegisterProperty("uOpaque", opaque);
+  renderer.RegisterProperty("uMask", mask);
+  renderer.RegisterProperty("uAlphaThreshold", alphaCutoff);
+
+  renderer.SetTextures(textures);
+
+  actor.SetProperty(Actor::Property::COLOR, mColor);
 }
 
-void ArcNode::OnCreate(const NodeDefinition& node, NodeDefinition::CreateParams& params, Actor& actor) const
+void ArcRenderable::OnCreate(const NodeDefinition& node, NodeDefinition::CreateParams& params, Actor& actor) const
 {
-  ModelNode::OnCreate(node, params, actor);
+  ModelRenderable::OnCreate(node, params, actor);
 
   actor.RegisterProperty("antiAliasing", mAntiAliasing ? 1 : 0);
   actor.RegisterProperty("arcCaps", mArcCaps);
@@ -263,13 +284,13 @@ void ArcNode::OnCreate(const NodeDefinition& node, NodeDefinition::CreateParams&
   actor.RegisterProperty("endAngle", endPolar);
 }
 
-void ArcNode::GetEndVectorWithDiffAngle(float startAngle, float diffAngle, Vector2& endVector)
+void ArcRenderable::GetEndVectorWithDiffAngle(float startAngle, float diffAngle, Vector2& endVector)
 {
   float endAngle = 0.f;
 
   if(diffAngle <= 0.001f)
   {
-    //0.001 is used to ensure is empty arc when startAngle = endAngle + 360 * N
+    // 0.001 is used to ensure is empty arc when startAngle = endAngle + 360 * N
     endAngle = startAngle + 0.001f;
   }
   else if(diffAngle >= 360.f)
index a86d7e9..fde74e2 100644 (file)
@@ -261,7 +261,7 @@ public: // DATA
 
   bool mIsVisible = true;
 
-  std::unique_ptr<Renderable>              mRenderable;
+  std::vector<std::unique_ptr<Renderable>> mRenderables;
   std::unique_ptr<CustomizationDefinition> mCustomization;
   std::vector<Extra>                       mExtras;
   std::vector<ConstraintDefinition>        mConstraints;
@@ -270,7 +270,7 @@ public: // DATA
   Index              mParentIdx = INVALID_INDEX;
 };
 
-class DALI_SCENE3D_API ModelNode : public NodeDefinition::Renderable
+class DALI_SCENE3D_API ModelRenderable : public NodeDefinition::Renderable
 {
 public: // DATA
   Vector4 mColor       = Color::WHITE;
@@ -287,7 +287,7 @@ public: // METHODS
 /**
  * @brief Parameters for an Arc node.
  */
-class DALI_SCENE3D_API ArcNode : public ModelNode
+class DALI_SCENE3D_API ArcRenderable : public ModelRenderable
 {
 public: // DATA
   bool  mAntiAliasing      = true;
@@ -306,4 +306,4 @@ public: // METHODS
 } // namespace Scene3D
 } // namespace Dali
 
-#endif //DALI_SCENE3D_LOADER_NODE_DEFINITION_H_
+#endif // DALI_SCENE3D_LOADER_NODE_DEFINITION_H_
index 6e26c0f..a117e1e 100644 (file)
@@ -453,9 +453,9 @@ void SceneDefinition::CountResourceRefs(Index iNode, const Customization::Choice
 
     void Start(const NodeDefinition& n)
     {
-      if(n.mRenderable)
+      for(auto& renderable : n.mRenderables)
       {
-        n.mRenderable->RegisterResources(counter);
+        renderable->RegisterResources(counter);
       }
     }
 
@@ -526,7 +526,7 @@ void SceneDefinition::GetCustomizationOptions(const Customization::Choices& choi
 
 NodeDefinition* SceneDefinition::AddNode(std::unique_ptr<NodeDefinition>&& nodeDef)
 {
-  if(FindNode(nodeDef->mName))
+  if(!nodeDef->mName.empty() && FindNode(nodeDef->mName))
   {
     return nullptr;
   }
@@ -991,10 +991,10 @@ void SceneDefinition::EnsureUniqueSkinningShaderInstances(ResourceBundle& resour
   std::map<Index, std::map<Index, std::vector<Index*>>> skinningShaderUsers;
   for(auto& node : mNodes)
   {
-    if(node->mRenderable)
+    for(auto& renderable : node->mRenderables)
     {
       ResourceReflector reflector;
-      node->mRenderable->ReflectResources(reflector);
+      renderable->ReflectResources(reflector);
 
       if(reflector.iMesh)
       {
@@ -1045,21 +1045,21 @@ void SceneDefinition::ConfigureSkinningShaders(const ResourceBundle&
 
   SortAndDeduplicateSkinningRequests(requests);
 
-  for(auto& i : requests)
+  for(auto& request : requests)
   {
-    auto& skeleton = resources.mSkeletons[i.mSkeletonIdx];
+    auto& skeleton = resources.mSkeletons[request.mSkeletonIdx];
     if(skeleton.mJoints.empty())
     {
-      LOGD(("Skeleton %d has no joints.", i.mSkeletonIdx));
+      LOGD(("Skeleton %d has no joints.", request.mSkeletonIdx));
       continue;
     }
 
     Index boneIdx = 0;
-    for(auto& j : skeleton.mJoints)
+    for(auto& joint : skeleton.mJoints)
     {
-      auto  node  = GetNode(j.mNodeIdx);
+      auto  node  = GetNode(joint.mNodeIdx);
       Actor actor = rootActor.FindChildByName(node->mName);
-      ConfigureBoneMatrix(j.mInverseBindMatrix, actor, i.mShader, boneIdx);
+      ConfigureBoneMatrix(joint.mInverseBindMatrix, actor, request.mShader, boneIdx);
     }
   }
 }
@@ -1129,10 +1129,10 @@ void SceneDefinition::EnsureUniqueBlendShapeShaderInstances(ResourceBundle& reso
   std::map<Index, std::map<std::string, std::vector<Index*>>> blendShapeShaderUsers;
   for(auto& node : mNodes)
   {
-    if(node->mRenderable)
+    for(auto& renderable : node->mRenderables)
     {
       ResourceReflector reflector;
-      node->mRenderable->ReflectResources(reflector);
+      renderable->ReflectResources(reflector);
 
       if(reflector.iMesh)
       {
index 59dd3b4..a341d20 100644 (file)
@@ -68,7 +68,7 @@ void RetrieveBlendShapeComponents(const std::vector<MeshDefinition::BlendShape>&
   }
 }
 
-uint64_t HashNode(const NodeDefinition& nodeDef, const MaterialDefinition& materialDef, const MeshDefinition& meshDef)
+uint64_t HashNode(const MaterialDefinition& materialDef, const MeshDefinition& meshDef)
 {
   Hash hash;
 
@@ -93,6 +93,16 @@ uint64_t HashNode(const NodeDefinition& nodeDef, const MaterialDefinition& mater
     hash.Add("SSS");
   }
 
+  if(MaskMatch(materialDef.mFlags, MaterialDefinition::SPECULAR))
+  {
+    hash.Add("SPECTEX");
+  }
+
+  if(MaskMatch(materialDef.mFlags, MaterialDefinition::SPECULAR_COLOR))
+  {
+    hash.Add("SPECCOLTEX");
+  }
+
   if(MaskMatch(materialDef.mFlags, MaterialDefinition::OCCLUSION))
   {
     hash.Add("OCCL" /*USION*/);
@@ -173,145 +183,165 @@ void ShaderDefinitionFactory::SetResources(ResourceBundle& resources)
   mImpl->mShaderMap.clear();
 }
 
-Index ShaderDefinitionFactory::ProduceShader(const NodeDefinition& nodeDef)
+Index ShaderDefinitionFactory::ProduceShader(NodeDefinition::Renderable& renderable)
 {
-  DALI_ASSERT_DEBUG(nodeDef.mRenderable);
+  auto& resources = *mImpl->mResources;
 
-  auto&            resources = *mImpl->mResources;
   ResourceReceiver receiver{resources};
-  nodeDef.mRenderable->RegisterResources(receiver);
+  renderable.RegisterResources(receiver);
+
   if(!(receiver.mMeshDef && receiver.mMaterialDef))
   {
+    renderable.mShaderIdx = INVALID_INDEX;
     return INVALID_INDEX;
   }
 
   auto&    shaderMap = mImpl->mShaderMap;
-  uint64_t hash      = HashNode(nodeDef, *receiver.mMaterialDef, *receiver.mMeshDef);
+  uint64_t hash      = HashNode(*receiver.mMaterialDef, *receiver.mMeshDef);
   auto     iFind     = shaderMap.find(hash);
   if(iFind != shaderMap.end())
   {
-    return iFind->second;
-  }
-
-  ShaderDefinition shaderDef;
-  shaderDef.mUseBuiltInShader = true;
-  shaderDef.mRendererState    = RendererState::DEPTH_TEST | RendererState::DEPTH_WRITE | RendererState::CULL_BACK;
-
-  auto&      materialDef     = *receiver.mMaterialDef;
-  const bool hasTransparency = MaskMatch(materialDef.mFlags, MaterialDefinition::TRANSPARENCY);
-  if(hasTransparency)
-  {
-    // TODO: this requires more granularity
-    shaderDef.mRendererState = (shaderDef.mRendererState | RendererState::ALPHA_BLEND) & ~RendererState::DEPTH_WRITE;
+    renderable.mShaderIdx = iFind->second;
   }
-
-  if(hasTransparency ||
-     !materialDef.CheckTextures(MaterialDefinition::ALBEDO | MaterialDefinition::METALLIC) ||
-     !materialDef.CheckTextures(MaterialDefinition::NORMAL | MaterialDefinition::ROUGHNESS))
-
+  else
   {
-    shaderDef.mDefines.push_back("THREE_TEX");
+    ShaderDefinition shaderDef;
+    shaderDef.mUseBuiltInShader = true;
+    shaderDef.mRendererState    = RendererState::DEPTH_TEST | RendererState::DEPTH_WRITE;
 
-    // For the glTF, each of basecolor, metallic_roughness, normal texture is not essential.
-    if(MaskMatch(materialDef.mFlags, MaterialDefinition::ALBEDO))
+    auto& materialDef = *receiver.mMaterialDef;
+    if(!materialDef.mDoubleSided)
     {
-      shaderDef.mDefines.push_back("BASECOLOR_TEX");
+      shaderDef.mRendererState |= RendererState::CULL_BACK;
     }
 
-    if(materialDef.CheckTextures(MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS))
+    const bool hasTransparency = MaskMatch(materialDef.mFlags, MaterialDefinition::TRANSPARENCY);
+    if(hasTransparency)
     {
-      shaderDef.mDefines.push_back("METALLIC_ROUGHNESS_TEX");
+      // TODO: this requires more granularity
+      shaderDef.mRendererState = (shaderDef.mRendererState | RendererState::ALPHA_BLEND) & ~RendererState::DEPTH_WRITE;
     }
 
-    if(MaskMatch(materialDef.mFlags, MaterialDefinition::NORMAL))
+    if(hasTransparency ||
+       !materialDef.CheckTextures(MaterialDefinition::ALBEDO | MaterialDefinition::METALLIC) ||
+       !materialDef.CheckTextures(MaterialDefinition::NORMAL | MaterialDefinition::ROUGHNESS))
+
     {
-      shaderDef.mDefines.push_back("NORMAL_TEX");
-    }
-  }
+      shaderDef.mDefines.push_back("THREE_TEX");
 
-  if(materialDef.GetAlphaCutoff() > 0.f)
-  {
-    shaderDef.mDefines.push_back("ALPHA_TEST");
-  }
+      // For the glTF, each of basecolor, metallic_roughness, normal texture is not essential.
+      if(MaskMatch(materialDef.mFlags, MaterialDefinition::ALBEDO))
+      {
+        shaderDef.mDefines.push_back("BASECOLOR_TEX");
+      }
 
-  if(MaskMatch(materialDef.mFlags, MaterialDefinition::SUBSURFACE))
-  {
-    shaderDef.mDefines.push_back("SSS");
-  }
+      if(materialDef.CheckTextures(MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS))
+      {
+        shaderDef.mDefines.push_back("METALLIC_ROUGHNESS_TEX");
+      }
 
-  if(MaskMatch(materialDef.mFlags, MaterialDefinition::OCCLUSION))
-  {
-    shaderDef.mDefines.push_back("OCCLUSION");
-  }
+      if(MaskMatch(materialDef.mFlags, MaterialDefinition::NORMAL))
+      {
+        shaderDef.mDefines.push_back("NORMAL_TEX");
+      }
+    }
 
-  if(MaskMatch(materialDef.mFlags, MaterialDefinition::EMISSIVE))
-  {
-    shaderDef.mDefines.push_back("EMISSIVE");
-  }
+    if(materialDef.GetAlphaCutoff() > 0.f)
+    {
+      shaderDef.mDefines.push_back("ALPHA_TEST");
+    }
 
-  if(MaskMatch(materialDef.mFlags, MaterialDefinition::GLTF_CHANNELS))
-  {
-    shaderDef.mDefines.push_back("GLTF_CHANNELS");
-  }
+    if(MaskMatch(materialDef.mFlags, MaterialDefinition::SUBSURFACE))
+    {
+      shaderDef.mDefines.push_back("SSS");
+    }
 
-  const auto& meshDef = *receiver.mMeshDef;
-  if(meshDef.IsSkinned())
-  {
-    shaderDef.mDefines.push_back("SKINNING");
-  }
+    if(MaskMatch(materialDef.mFlags, MaterialDefinition::SPECULAR))
+    {
+      shaderDef.mDefines.push_back("MATERIAL_SPECULAR_TEXTURE");
+    }
 
-  if(MaskMatch(meshDef.mFlags, MeshDefinition::FLIP_UVS_VERTICAL))
-  {
-    shaderDef.mDefines.push_back("FLIP_V");
-  }
+    if(MaskMatch(materialDef.mFlags, MaterialDefinition::SPECULAR_COLOR))
+    {
+      shaderDef.mDefines.push_back("MATERIAL_SPECULAR_COLOR_TEXTURE");
+    }
 
-  if(meshDef.HasBlendShapes())
-  {
-    bool hasPositions = false;
-    bool hasNormals   = false;
-    bool hasTangents  = false;
-    RetrieveBlendShapeComponents(meshDef.mBlendShapes, hasPositions, hasNormals, hasTangents);
+    if(MaskMatch(materialDef.mFlags, MaterialDefinition::OCCLUSION))
+    {
+      shaderDef.mDefines.push_back("OCCLUSION");
+    }
 
-    if(hasPositions)
+    if(MaskMatch(materialDef.mFlags, MaterialDefinition::EMISSIVE))
     {
-      shaderDef.mDefines.push_back("MORPH_POSITION");
+      shaderDef.mDefines.push_back("EMISSIVE");
     }
 
-    if(hasNormals)
+    if(MaskMatch(materialDef.mFlags, MaterialDefinition::GLTF_CHANNELS))
     {
-      shaderDef.mDefines.push_back("MORPH_NORMAL");
+      shaderDef.mDefines.push_back("GLTF_CHANNELS");
     }
 
-    if(hasTangents)
+    const auto& meshDef = *receiver.mMeshDef;
+    if(meshDef.IsSkinned())
     {
-      shaderDef.mDefines.push_back("MORPH_TANGENT");
+      shaderDef.mDefines.push_back("SKINNING");
     }
 
-    if(hasPositions || hasNormals || hasTangents)
+    if(MaskMatch(meshDef.mFlags, MeshDefinition::FLIP_UVS_VERTICAL))
     {
-      shaderDef.mDefines.push_back("MORPH");
+      shaderDef.mDefines.push_back("FLIP_V");
+    }
 
-      if(BlendShapes::Version::VERSION_2_0 == meshDef.mBlendShapeVersion)
+    if(meshDef.HasBlendShapes())
+    {
+      bool hasPositions = false;
+      bool hasNormals   = false;
+      bool hasTangents  = false;
+      RetrieveBlendShapeComponents(meshDef.mBlendShapes, hasPositions, hasNormals, hasTangents);
+
+      if(hasPositions)
       {
-        shaderDef.mDefines.push_back("MORPH_VERSION_2_0");
+        shaderDef.mDefines.push_back("MORPH_POSITION");
+      }
+
+      if(hasNormals)
+      {
+        shaderDef.mDefines.push_back("MORPH_NORMAL");
+      }
+
+      if(hasTangents)
+      {
+        shaderDef.mDefines.push_back("MORPH_TANGENT");
+      }
+
+      if(hasPositions || hasNormals || hasTangents)
+      {
+        shaderDef.mDefines.push_back("MORPH");
+
+        if(BlendShapes::Version::VERSION_2_0 == meshDef.mBlendShapeVersion)
+        {
+          shaderDef.mDefines.push_back("MORPH_VERSION_2_0");
+        }
       }
     }
-  }
 
-  if(meshDef.mTangentType == Property::VECTOR4)
-  {
-    shaderDef.mDefines.push_back("VEC4_TANGENT");
-  }
+    if(meshDef.mTangentType == Property::VECTOR4)
+    {
+      shaderDef.mDefines.push_back("VEC4_TANGENT");
+    }
 
-  shaderDef.mUniforms["uMaxLOD"]     = 6.f;
-  shaderDef.mUniforms["uCubeMatrix"] = Matrix::IDENTITY;
+    shaderDef.mUniforms["uMaxLOD"]     = 6.f;
+    shaderDef.mUniforms["uCubeMatrix"] = Matrix::IDENTITY;
 
-  Index result    = resources.mShaders.size();
-  shaderMap[hash] = result;
+    Index result    = resources.mShaders.size();
+    shaderMap[hash] = result;
 
-  resources.mShaders.emplace_back(std::move(shaderDef), Shader());
+    resources.mShaders.emplace_back(std::move(shaderDef), Shader());
+
+    renderable.mShaderIdx = result;
+  }
 
-  return result;
+  return renderable.mShaderIdx;
 }
 
 } // namespace Loader
index 8c4434a..b7e9195 100644 (file)
@@ -20,6 +20,7 @@
 // INTERNAL INCLUDES
 #include "dali-scene3d/public-api/api.h"
 #include "dali-scene3d/public-api/loader/index.h"
+#include <dali-scene3d/public-api/loader/node-definition.h>
 
 // EXTERNAL INCLUDER
 #include <memory>
@@ -51,7 +52,7 @@ public:
    *  already existing in the ResourceBundle are ignored), otherwise the index of the previously
    *  created shader will be returned.
    */
-  Index ProduceShader(const NodeDefinition& nodeDef);
+  Index ProduceShader(NodeDefinition::Renderable& renderable);
 
 private:
   struct Impl;
index 401b82f..07c89ff 100644 (file)
@@ -1067,12 +1067,14 @@ Size LayoutText(const RendererParameters& textParameters, TextAbstraction::TextR
   Size newLayoutSize;
   bool isAutoScrollEnabled            = false;
   bool isAutoScrollMaxTextureExceeded = false;
+  bool isHiddenInputEnabled           = false;
 
   layoutEngine.LayoutText(layoutParameters,
                           newLayoutSize,
                           textParameters.ellipsisEnabled,
                           isAutoScrollEnabled,
                           isAutoScrollMaxTextureExceeded,
+                          isHiddenInputEnabled,
                           ellipsisPosition);
 
   return newLayoutSize;
index 7ce566e..0a0338f 100644 (file)
@@ -19,8 +19,8 @@
 #include "async-image-loader-impl.h"
 
 // EXTERNAL INCLUDES
-#include <dali/public-api/adaptor-framework/async-task-manager.h>
 #include <dali/integration-api/adaptor-framework/adaptor.h>
+#include <dali/public-api/adaptor-framework/async-task-manager.h>
 
 namespace Dali
 {
@@ -49,7 +49,19 @@ uint32_t AsyncImageLoader::LoadAnimatedImage(Dali::AnimatedImageLoading
                                              uint32_t                                 frameIndex,
                                              DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad)
 {
-  LoadingTaskPtr loadingTask = new LoadingTask(++mLoadTaskId, animatedImageLoading, frameIndex, preMultiplyOnLoad,MakeCallback(this, &AsyncImageLoader::ProcessLoadedImage));
+  LoadingTaskPtr loadingTask = new LoadingTask(++mLoadTaskId, animatedImageLoading, frameIndex, preMultiplyOnLoad, MakeCallback(this, &AsyncImageLoader::ProcessLoadedImage));
+  Dali::AsyncTaskManager::Get().AddTask(loadingTask);
+  return mLoadTaskId;
+}
+
+uint32_t AsyncImageLoader::LoadAnimatedImage(Dali::AnimatedImageLoading               animatedImageLoading,
+                                             uint32_t                                 frameIndex,
+                                             Dali::ImageDimensions                    desiredSize,
+                                             Dali::FittingMode::Type                  fittingMode,
+                                             Dali::SamplingMode::Type                 samplingMode,
+                                             DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad)
+{
+  LoadingTaskPtr loadingTask = new LoadingTask(++mLoadTaskId, animatedImageLoading, frameIndex, desiredSize, fittingMode, samplingMode, preMultiplyOnLoad, MakeCallback(this, &AsyncImageLoader::ProcessLoadedImage));
   Dali::AsyncTaskManager::Get().AddTask(loadingTask);
   return mLoadTaskId;
 }
@@ -64,7 +76,7 @@ uint32_t AsyncImageLoader::Load(const VisualUrl&                         url,
 {
   LoadingTaskPtr loadingTask = new LoadingTask(++mLoadTaskId, url, dimensions, fittingMode, samplingMode, orientationCorrection, preMultiplyOnLoad, loadPlanes, MakeCallback(this, &AsyncImageLoader::ProcessLoadedImage));
   AsyncTaskManager::Get().AddTask(loadingTask);
-  mLoadingTasks.push_back(AsyncImageLoadingInfo(loadingTask,mLoadTaskId));
+  mLoadingTasks.push_back(AsyncImageLoadingInfo(loadingTask, mLoadTaskId));
   return mLoadTaskId;
 }
 
@@ -77,7 +89,7 @@ uint32_t AsyncImageLoader::LoadEncodedImageBuffer(const EncodedImageBuffer&
 {
   LoadingTaskPtr loadingTask = new LoadingTask(++mLoadTaskId, encodedImageBuffer, dimensions, fittingMode, samplingMode, orientationCorrection, preMultiplyOnLoad, MakeCallback(this, &AsyncImageLoader::ProcessLoadedImage));
   Dali::AsyncTaskManager::Get().AddTask(loadingTask);
-  mLoadingTasks.push_back(AsyncImageLoadingInfo(loadingTask,mLoadTaskId));
+  mLoadingTasks.push_back(AsyncImageLoadingInfo(loadingTask, mLoadTaskId));
   return mLoadTaskId;
 }
 
@@ -89,7 +101,7 @@ uint32_t AsyncImageLoader::ApplyMask(Devel::PixelBuffer                       pi
 {
   LoadingTaskPtr loadingTask = new LoadingTask(++mLoadTaskId, pixelBuffer, maskPixelBuffer, contentScale, cropToMask, preMultiplyOnLoad, MakeCallback(this, &AsyncImageLoader::ProcessLoadedImage));
   Dali::AsyncTaskManager::Get().AddTask(loadingTask);
-  mLoadingTasks.push_back(AsyncImageLoadingInfo(loadingTask,mLoadTaskId));
+  mLoadingTasks.push_back(AsyncImageLoadingInfo(loadingTask, mLoadTaskId));
   return mLoadTaskId;
 }
 
@@ -160,8 +172,8 @@ void AsyncImageLoader::ProcessLoadedImage(LoadingTaskPtr task)
 void AsyncImageLoader::RemoveCompletedTask()
 {
   std::uint32_t loadingTaskId;
-  auto end = mLoadingTasks.end();
-  auto endCompletedIter = mCompletedTaskIds.end();
+  auto          end              = mLoadingTasks.end();
+  auto          endCompletedIter = mCompletedTaskIds.end();
   for(std::vector<AsyncImageLoadingInfo>::iterator iter = mLoadingTasks.begin(); iter != end; ++iter)
   {
     loadingTaskId = (*iter).loadId;
index a75fa32..c23b102 100644 (file)
@@ -36,7 +36,7 @@ using LoadingTaskPtr = IntrusivePtr<LoadingTask>;
 
 struct AsyncImageLoadingInfo
 {
-  AsyncImageLoadingInfo(LoadingTaskPtr loadingTask,std::uint32_t loadId)
+  AsyncImageLoadingInfo(LoadingTaskPtr loadingTask, std::uint32_t loadId)
   : loadingTask(loadingTask),
     loadId(loadId)
   {
@@ -67,6 +67,24 @@ public:
                              DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad);
 
   /**
+   * @brief Starts an animated image loading task.
+   * @param[in] asyncImageLoader The ayncImageLoader
+   * @param[in] animatedImageLoading The AnimatedImageLoading to load animated image
+   * @param[in] frameIndex The frame index of a frame to be loaded frame
+   * @param[in] dimensions The width and height to fit the loaded image to
+   * @param[in] fittingMode The method used to fit the shape of the image before loading to the shape defined by the size parameter
+   * @param[in] samplingMode The filtering method used when sampling pixels from the input image while fitting it to desired size
+   * @param[in] preMultiplyOnLoad ON if the image color should be multiplied by it's alpha. Set to OFF if there is no alpha or if the image need to be applied alpha mask.
+   * @return The loading task id
+   */
+  uint32_t LoadAnimatedImage(Dali::AnimatedImageLoading               animatedImageLoading,
+                             uint32_t                                 frameIndex,
+                             Dali::ImageDimensions                    desiredSize,
+                             Dali::FittingMode::Type                  fittingMode,
+                             Dali::SamplingMode::Type                 samplingMode,
+                             DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad);
+
+  /**
    * @brief Starts an image loading task.
    * @param[in] url The URL of the image file to load
    * @param[in] dimensions The width and height to fit the loaded image to
index 29f3bdb..11f83a8 100644 (file)
@@ -38,8 +38,30 @@ LoadingTask::LoadingTask(uint32_t id, Dali::AnimatedImageLoading animatedImageLo
   id(id),
   textureId(TextureManagerType::INVALID_TEXTURE_ID),
   dimensions(),
-  fittingMode(),
-  samplingMode(),
+  fittingMode(FittingMode::SCALE_TO_FILL),
+  samplingMode(SamplingMode::BOX_THEN_LINEAR),
+  preMultiplyOnLoad(preMultiplyOnLoad),
+  maskPixelBuffer(),
+  contentScale(1.0f),
+  animatedImageLoading(animatedImageLoading),
+  frameIndex(frameIndex),
+  orientationCorrection(),
+  isMaskTask(false),
+  cropToMask(false),
+  loadPlanes(false),
+  isReady(true)
+{
+}
+
+LoadingTask::LoadingTask(uint32_t id, Dali::AnimatedImageLoading animatedImageLoading, uint32_t frameIndex, ImageDimensions dimensions, FittingMode::Type fittingMode, SamplingMode::Type samplingMode, DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad, CallbackBase* callback)
+: AsyncTask(callback),
+  url(),
+  encodedImageBuffer(),
+  id(id),
+  textureId(TextureManagerType::INVALID_TEXTURE_ID),
+  dimensions(dimensions),
+  fittingMode(fittingMode),
+  samplingMode(samplingMode),
   preMultiplyOnLoad(preMultiplyOnLoad),
   maskPixelBuffer(),
   contentScale(1.0f),
@@ -149,7 +171,7 @@ void LoadingTask::Load()
   Devel::PixelBuffer pixelBuffer;
   if(animatedImageLoading)
   {
-    pixelBuffer = animatedImageLoading.LoadFrame(frameIndex);
+    pixelBuffer = animatedImageLoading.LoadFrame(frameIndex, dimensions, fittingMode, samplingMode);
   }
   else if(encodedImageBuffer)
   {
index 09208b4..6072856 100644 (file)
 
 // EXTERNAL INCLUDES
 #include <dali-toolkit/devel-api/image-loader/async-image-loader-devel.h>
+#include <dali-toolkit/internal/texture-manager/texture-manager-type.h>
 #include <dali-toolkit/internal/visuals/visual-url.h>
-#include <dali/public-api/adaptor-framework/async-task-manager.h>
 #include <dali/devel-api/adaptor-framework/event-thread-callback.h>
 #include <dali/devel-api/adaptor-framework/pixel-buffer.h>
 #include <dali/devel-api/threading/conditional-wait.h>
 #include <dali/devel-api/threading/mutex.h>
 #include <dali/devel-api/threading/thread.h>
 #include <dali/integration-api/adaptor-framework/log-factory-interface.h>
+#include <dali/public-api/adaptor-framework/async-task-manager.h>
 #include <dali/public-api/adaptor-framework/encoded-image-buffer.h>
 #include <dali/public-api/common/dali-vector.h>
 #include <dali/public-api/images/image-operations.h>
 #include <dali/public-api/object/ref-object.h>
-#include <dali-toolkit/internal/texture-manager/texture-manager-type.h>
 
 namespace Dali
 {
@@ -39,7 +39,6 @@ namespace Toolkit
 {
 namespace Internal
 {
-
 class LoadingTask;
 using LoadingTaskPtr = IntrusivePtr<LoadingTask>;
 
@@ -66,6 +65,26 @@ public:
   /**
    * Constructor.
    * @param [in] id of the task
+   * @param [in] animatedImageLoading The AnimatedImageLoading to load animated image
+   * @param [in] frameIndex The frame index of a frame to be loaded frame
+   * @param [in] dimensions The width and height to fit the loaded image to
+   * @param [in] fittingMode The method used to fit the shape of the image before loading to the shape defined by the size parameter
+   * @param [in] samplingMode The filtering method used when sampling pixels from the input image while fitting it to desired size
+   * @param [in] preMultiplyOnLoad ON if the image's color should be multiplied by it's alpha. Set to OFF if there is no alpha or if the image need to be applied alpha mask.
+   * @param [in] callback The callback that is called when the operation is completed.
+   */
+  LoadingTask(uint32_t                                 id,
+              Dali::AnimatedImageLoading               animatedImageLoading,
+              uint32_t                                 frameIndex,
+              Dali::ImageDimensions                    dimensions,
+              Dali::FittingMode::Type                  fittingMode,
+              Dali::SamplingMode::Type                 samplingMode,
+              DevelAsyncImageLoader::PreMultiplyOnLoad preMultiplyOnLoad,
+              CallbackBase*                            callback);
+
+  /**
+   * Constructor.
+   * @param [in] id of the task
    * @param [in] url The URL of the image file to load.
    * @param [in] size The width and height to fit the loaded image to, 0.0 means whole image
    * @param [in] fittingMode The method used to fit the shape of the image before loading to the shape defined by the size parameter.
@@ -188,7 +207,7 @@ public:
   bool isMaskTask : 1;            ///< whether this task is for mask or not
   bool cropToMask : 1;            ///< Whether to crop the content to the mask size
   bool loadPlanes : 1;            ///< Whether to load image planes
-  bool isReady    : 1;            ///< Whether this task ready to run
+  bool isReady : 1;               ///< Whether this task ready to run
 };
 
 } // namespace Internal
index adf1af0..ff4697b 100644 (file)
@@ -70,10 +70,17 @@ bool ControllerImplModelUpdater::Update(Controller::Impl& impl, OperationsMask o
   Vector<Character>& srcCharacters = impl.mModel->mLogicalModel->mText;
   Vector<Character>  displayCharacters;
   bool               useHiddenText = false;
-  if(impl.mHiddenInput && impl.mEventData != nullptr && !impl.mEventData->mIsShowingPlaceholderText)
+  if(impl.mHiddenInput && impl.mEventData != nullptr)
   {
-    impl.mHiddenInput->Substitute(srcCharacters, displayCharacters);
-    useHiddenText = true;
+    if(impl.mEventData->mIsShowingPlaceholderText)
+    {
+      impl.mHiddenInput->InitPreviousTextCount();
+    }
+    else
+    {
+      impl.mHiddenInput->Substitute(srcCharacters, displayCharacters, impl.mEventData->mPrimaryCursorPosition);
+      useHiddenText = true;
+    }
   }
 
   Vector<Character>& utf32Characters    = useHiddenText ? displayCharacters : srcCharacters;
index f95019a..48df46e 100644 (file)
@@ -641,6 +641,11 @@ bool Controller::Relayouter::DoRelayout(Controller::Impl& impl, const Size& size
     // Update the visual model.
     bool isAutoScrollEnabled            = impl.mIsAutoScrollEnabled;
     bool isAutoScrollMaxTextureExceeded = impl.mIsAutoScrollMaxTextureExceeded;
+    bool isHiddenInputEnabled           = false;
+    if(impl.mHiddenInput && impl.mEventData != nullptr && impl.mHiddenInput->GetHideMode() != Toolkit::HiddenInput::Mode::HIDE_NONE)
+    {
+      isHiddenInputEnabled = true;
+    }
 
     Size newLayoutSize;
     viewUpdated               = impl.mLayoutEngine.LayoutText(layoutParameters,
@@ -648,6 +653,7 @@ bool Controller::Relayouter::DoRelayout(Controller::Impl& impl, const Size& size
                                                 elideTextEnabled,
                                                 isAutoScrollEnabled,
                                                 isAutoScrollMaxTextureExceeded,
+                                                isHiddenInputEnabled,
                                                 ellipsisPosition);
     impl.mIsAutoScrollEnabled = isAutoScrollEnabled;
 
index ab2aba5..4f0cabf 100644 (file)
@@ -42,7 +42,8 @@ HiddenText::HiddenText(Observer* observer)
   mSubstituteText(STAR),
   mDisplayDuration(DEFAULT_SHOW_DURATION),
   mSubstituteCount(0),
-  mPreviousTextCount(0)
+  mPreviousTextCount(0u),
+  mIsLastCharacterShow(false)
 {
   mTimer = Timer::New(mDisplayDuration);
   mTimer.TickSignal().Connect(this, &HiddenText::OnTick);
@@ -85,7 +86,7 @@ void HiddenText::GetProperties(Property::Map& map)
   map[Toolkit::HiddenInput::Property::SHOW_LAST_CHARACTER_DURATION] = mDisplayDuration;
 }
 
-void HiddenText::Substitute(const Vector<Character>& source, Vector<Character>& destination)
+void HiddenText::Substitute(const Vector<Character>& source, Vector<Character>& destination, Length cursorPos)
 {
   const Length characterCount = source.Count();
 
@@ -125,14 +126,15 @@ void HiddenText::Substitute(const Vector<Character>& source, Vector<Character>&
     }
     case Toolkit::HiddenInput::Mode::SHOW_LAST_CHARACTER:
     {
+      hideStart = begin;
+      hideEnd   = end;
       if(mPreviousTextCount < characterCount)
       {
-        hideStart = begin;
-        hideEnd   = end - 1;
         if(mDisplayDuration > 0)
         {
           mTimer.SetInterval(mDisplayDuration);
           mTimer.Start();
+          mIsLastCharacterShow = true;
         }
         else
         {
@@ -141,34 +143,65 @@ void HiddenText::Substitute(const Vector<Character>& source, Vector<Character>&
       }
       else
       {
-        hideStart = begin;
-        hideEnd   = end;
+        mIsLastCharacterShow = false;
       }
       break;
     }
   }
-  for(; begin < end; ++begin)
+
+
+  if(mHideMode == Toolkit::HiddenInput::Mode::SHOW_LAST_CHARACTER)
   {
-    if(begin >= hideStart && begin < hideEnd)
+    Length currentPos = 0u;
+    for(; begin < end; ++begin)
     {
-      *begin = static_cast<uint32_t>(mSubstituteText);
+      if(begin >= hideStart && begin < hideEnd && cursorPos > 0u && currentPos != cursorPos - 1u)
+      {
+        *begin = static_cast<uint32_t>(mSubstituteText);
+      }
+      else
+      {
+        *begin = mIsLastCharacterShow ? *sourcePos : static_cast<uint32_t>(mSubstituteText);
+      }
       sourcePos++;
+      currentPos++;
     }
-    else
+  }
+  else
+  {
+    for(; begin < end; ++begin)
     {
-      *begin = *sourcePos++;
+      if(begin >= hideStart && begin < hideEnd)
+      {
+        *begin = static_cast<uint32_t>(mSubstituteText);
+        sourcePos++;
+      }
+      else
+      {
+        *begin = *sourcePos++;
+      }
     }
   }
   mPreviousTextCount = characterCount;
 }
 
+void HiddenText::InitPreviousTextCount()
+{
+  mPreviousTextCount = 0u;
+}
+
+int HiddenText::GetHideMode()
+{
+  return mHideMode;
+}
+
 bool HiddenText::OnTick()
 {
   if(mObserver != NULL)
   {
     mObserver->DisplayTimeExpired();
   }
-
+  mIsLastCharacterShow = false;
   return false;
 }
 
index b13c263..49d8010 100644 (file)
@@ -74,7 +74,18 @@ public: // Intended for internal use
    * @param[in] source The original text
    * @param[out] destination The applied text
    */
-  void Substitute(const Vector<Character>& source, Vector<Character>& destination);
+  void Substitute(const Vector<Character>& source, Vector<Character>& destination, Length currentCursorIndex);
+
+  /**
+   * @brief Initialize the value of PreviousTextCount
+   */
+  void InitPreviousTextCount();
+
+  /**
+   * @brief Returns the hide mode of hidden text.
+   * @return The hide mode of hidden text.
+   */
+  int GetHideMode();
 
   /**
    * @brief Invoked when the timer is expired
@@ -89,6 +100,7 @@ private:
   int       mDisplayDuration;
   int       mSubstituteCount;
   Length    mPreviousTextCount;
+  bool      mIsLastCharacterShow;
 };
 
 } // namespace Text
index 39af47c..7bbf2cc 100644 (file)
@@ -667,6 +667,7 @@ struct Engine::Impl
    * @param[out] lineLayout The line layout.
    * @param[in] completelyFill Whether to completely fill the line ( even if the last word exceeds the boundaries ).
    * @param[in] ellipsisPosition Where is the location the text elide
+   * @param[in] hiddenInputEnabled Whether the hidden input is enabled.
    */
   void GetLineLayoutForBox(const Parameters&                 parameters,
                            LayoutBidiParameters&             bidiParameters,
@@ -674,7 +675,8 @@ struct Engine::Impl
                            bool                              completelyFill,
                            DevelText::EllipsisPosition::Type ellipsisPosition,
                            bool                              enforceEllipsisInSingleLine,
-                           bool                              elideTextEnabled)
+                           bool                              elideTextEnabled,
+                           bool                              hiddenInputEnabled)
   {
     DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->GetLineLayoutForBox\n");
     DALI_LOG_INFO(gLogFilter, Debug::Verbose, "  initial glyph index : %d\n", lineLayout.glyphIndex);
@@ -826,7 +828,10 @@ struct Engine::Impl
       const float previousTmpLength                    = tmpLineLayout.length;
       const float previousTmpWhiteSpaceLengthEndOfLine = tmpLineLayout.whiteSpaceLengthEndOfLine;
 
-      if(isWhiteSpace)
+      // The calculated text size is used in atlas renderer.
+      // When the text is all white space, partial render issue occurs because the width is 0.
+      // To avoid issue, do not remove the white space size in hidden input mode.
+      if(isWhiteSpace && !hiddenInputEnabled)
       {
         // Add the length to the length of white spaces at the end of the line.
         tmpLineLayout.whiteSpaceLengthEndOfLine += glyphMetrics.advance;
@@ -907,7 +912,7 @@ struct Engine::Impl
             tmpLineLayout.numberOfGlyphs -= numberOfGLyphsInGroup;
           }
 
-          if(isRemovedGlyphWhiteSpace)
+          if(isRemovedGlyphWhiteSpace && !hiddenInputEnabled)
           {
             tmpLineLayout.penX -= glyphMetrics.advance;
             tmpLineLayout.length -= glyphMetrics.advance;
@@ -1247,6 +1252,7 @@ struct Engine::Impl
    * @param[in] penY The vertical layout position.
    * @param[in] currentParagraphDirection The current paragraph's direction.
    * @param[in,out] isAutoScrollEnabled If the isAutoScrollEnabled is true and the height of the text exceeds the boundaries of the control the text is elided and the isAutoScrollEnabled is set to false to disable the autoscroll
+   * @param[in] isHiddenInputEnabled Whether the hidden input is enabled.
    * @param[in] ellipsisPosition Where is the location the text elide
    *
    * return Whether the line is ellipsized.
@@ -1261,6 +1267,7 @@ struct Engine::Impl
                     float                             penY,
                     bool&                             isAutoScrollEnabled,
                     bool                              isAutoScrollMaxTextureExceeded,
+                    bool                              isHiddenInputEnabled,
                     DevelText::EllipsisPosition::Type ellipsisPosition,
                     bool                              enforceEllipsisInSingleLine)
   {
@@ -1310,7 +1317,8 @@ struct Engine::Impl
                           true,
                           ellipsisPosition,
                           enforceEllipsisInSingleLine,
-                          true);
+                          true,
+                          isHiddenInputEnabled);
 
       if(ellipsisPosition == DevelText::EllipsisPosition::START && !isMultiline)
       {
@@ -1608,6 +1616,7 @@ struct Engine::Impl
                   bool                              elideTextEnabled,
                   bool&                             isAutoScrollEnabled,
                   bool                              isAutoScrollMaxTextureExceeded,
+                  bool                              isHiddenInputEnabled,
                   DevelText::EllipsisPosition::Type ellipsisPosition)
   {
     DALI_LOG_INFO(gLogFilter, Debug::Verbose, "-->LayoutText\n");
@@ -1797,7 +1806,8 @@ struct Engine::Impl
                           false,
                           ellipsisPosition,
                           false,
-                          elideTextEnabled);
+                          elideTextEnabled,
+                          isHiddenInputEnabled);
 
       DALI_LOG_INFO(gLogFilter, Debug::Verbose, "           glyph index %d\n", layout.glyphIndex);
       DALI_LOG_INFO(gLogFilter, Debug::Verbose, "       character index %d\n", layout.characterIndex);
@@ -1848,6 +1858,7 @@ struct Engine::Impl
                                 penY,
                                 isAutoScrollEnabled,
                                 isAutoScrollMaxTextureExceeded,
+                                isHiddenInputEnabled,
                                 ellipsisPosition,
                                 false);
       }
@@ -1867,6 +1878,7 @@ struct Engine::Impl
                                   penY,
                                   isAutoScrollEnabled,
                                   isAutoScrollMaxTextureExceeded,
+                                  isHiddenInputEnabled,
                                   ellipsisPosition,
                                   true);
         }
@@ -2262,6 +2274,7 @@ bool Engine::LayoutText(Parameters&                       layoutParameters,
                         bool                              elideTextEnabled,
                         bool&                             isAutoScrollEnabled,
                         bool                              isAutoScrollMaxTextureExceeded,
+                        bool                              isHiddenInputEnabled,
                         DevelText::EllipsisPosition::Type ellipsisPosition)
 {
   return mImpl->LayoutText(layoutParameters,
@@ -2269,6 +2282,7 @@ bool Engine::LayoutText(Parameters&                       layoutParameters,
                            elideTextEnabled,
                            isAutoScrollEnabled,
                            isAutoScrollMaxTextureExceeded,
+                           isHiddenInputEnabled,
                            ellipsisPosition);
 }
 
index 9fa22c6..5fa41d6 100644 (file)
@@ -108,6 +108,7 @@ public:
    * @param[in] elideTextEnabled Whether the text elide is enabled.
    * @param[in,out] isAutoScrollEnabled If the isAutoScrollEnabled is true and the height of the text exceeds the boundaries of the control the text is elided and the isAutoScrollEnabled is set to false to disable the autoscroll
    * @param[in] isAutoScrollMaxTextureExceeded If isAutoScrollMaxTextureExceeded is true, enable ellipsis during auro scroll.
+   * @param[in] isHiddenInputEnabled if isHiddenInputEnabled is true, hidden input feature is enabled.
    * @param[in] ellipsisPosition The location of the text ellipsis
    *
    * @return \e true if the text has been re-laid-out. \e false means the given width is too small to layout even a single character.
@@ -117,6 +118,7 @@ public:
                   bool                              elideTextEnabled,
                   bool&                             isAutoScrollEnabled,
                   bool                              isAutoScrollMaxTextureExceeded,
+                  bool                              isHiddenInputEnabled,
                   DevelText::EllipsisPosition::Type ellipsisPosition);
 
   /**
index 87d3fa6..9927ea2 100644 (file)
@@ -44,9 +44,12 @@ TextureAsyncLoadingHelper::TextureAsyncLoadingHelper(TextureManager& textureMana
 void TextureAsyncLoadingHelper::LoadAnimatedImage(const TextureManager::TextureId&                textureId,
                                                   Dali::AnimatedImageLoading                      animatedImageLoading,
                                                   const std::uint32_t&                            frameIndex,
+                                                  const Dali::ImageDimensions&                    desiredSize,
+                                                  const Dali::FittingMode::Type&                  fittingMode,
+                                                  const Dali::SamplingMode::Type&                 samplingMode,
                                                   const DevelAsyncImageLoader::PreMultiplyOnLoad& preMultiplyOnLoad)
 {
-  LoadingTaskPtr loadingTask = new LoadingTask(++mLoadTaskId, animatedImageLoading, frameIndex, preMultiplyOnLoad, MakeCallback(this, &TextureAsyncLoadingHelper::AsyncLoadComplete));
+  LoadingTaskPtr loadingTask = new LoadingTask(++mLoadTaskId, animatedImageLoading, frameIndex, desiredSize, fittingMode, samplingMode, preMultiplyOnLoad, MakeCallback(this, &TextureAsyncLoadingHelper::AsyncLoadComplete));
   loadingTask->SetTextureId(textureId);
   Dali::AsyncTaskManager::Get().AddTask(loadingTask);
 }
@@ -81,7 +84,6 @@ void TextureAsyncLoadingHelper::ApplyMask(const TextureManager::TextureId&
                                           const bool&                                     cropToMask,
                                           const DevelAsyncImageLoader::PreMultiplyOnLoad& preMultiplyOnLoad)
 {
-
   LoadingTaskPtr loadingTask = new LoadingTask(++mLoadTaskId, pixelBuffer, maskPixelBuffer, contentScale, cropToMask, preMultiplyOnLoad, MakeCallback(this, &TextureAsyncLoadingHelper::AsyncLoadComplete));
   loadingTask->SetTextureId(textureId);
   Dali::AsyncTaskManager::Get().AddTask(loadingTask);
index d993737..15e1d4e 100644 (file)
@@ -31,7 +31,6 @@ namespace Toolkit
 {
 namespace Internal
 {
-
 /**
  * @brief Helper class to keep the relation between AsyncImageLoader and corresponding LoadingInfo container
  */
@@ -49,11 +48,18 @@ public:
    * @param[in] textureId             TextureId to reference the texture that will be loaded
    * @param[in] animatedImageLoading  The AnimatedImageLoading to load animated image
    * @param[in] frameIndex            The frame index of a frame to be loaded frame
+   * @param[in] desiredSize           The size the image is likely to appear at.
+   *                                  This can be set to 0,0 for automatic
+   * @param[in] fittingMode           The FittingMode to use
+   * @param[in] samplingMode          The SamplingMode to use
    * @param[in] preMultiplyOnLoad     if the image's color should be multiplied by it's alpha. Set to OFF if there is no alpha or if the image need to be applied alpha mask.
    */
   void LoadAnimatedImage(const TextureManager::TextureId&                textureId,
                          Dali::AnimatedImageLoading                      animatedImageLoading,
                          const std::uint32_t&                            frameIndex,
+                         const Dali::ImageDimensions&                    desiredSize,
+                         const Dali::FittingMode::Type&                  fittingMode,
+                         const Dali::SamplingMode::Type&                 samplingMode,
                          const DevelAsyncImageLoader::PreMultiplyOnLoad& preMultiplyOnLoad);
 
   /**
index 8930d2d..0984e2f 100644 (file)
@@ -33,7 +33,7 @@
 
 namespace
 {
-constexpr auto INITIAL_HASH_NUMBER                     = size_t{0u};
+constexpr auto INITIAL_HASH_NUMBER = size_t{0u};
 
 constexpr auto TEXTURE_INDEX      = 0u; ///< The Index for texture
 constexpr auto MASK_TEXTURE_INDEX = 1u; ///< The Index for mask texture
@@ -135,6 +135,8 @@ TextureSet TextureManager::LoadAnimatedImageTexture(
   const uint32_t&                 frameIndex,
   TextureManager::TextureId&      textureId,
   MaskingDataPointer&             maskInfo,
+  const Dali::ImageDimensions&    desiredSize,
+  const Dali::FittingMode::Type&  fittingMode,
   const Dali::SamplingMode::Type& samplingMode,
   const bool&                     synchronousLoading,
   TextureUploadObserver*          textureObserver,
@@ -147,7 +149,7 @@ TextureSet TextureManager::LoadAnimatedImageTexture(
     Devel::PixelBuffer pixelBuffer;
     if(animatedImageLoading)
     {
-      pixelBuffer = animatedImageLoading.LoadFrame(frameIndex);
+      pixelBuffer = animatedImageLoading.LoadFrame(frameIndex, desiredSize, fittingMode, samplingMode);
     }
     if(!pixelBuffer)
     {
@@ -158,7 +160,7 @@ TextureSet TextureManager::LoadAnimatedImageTexture(
       Texture maskTexture;
       if(maskInfo && maskInfo->mAlphaMaskUrl.IsValid())
       {
-        Devel::PixelBuffer maskPixelBuffer = LoadImageFromFile(maskInfo->mAlphaMaskUrl.GetUrl(), ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::NO_FILTER, true);
+        Devel::PixelBuffer maskPixelBuffer = LoadImageFromFile(maskInfo->mAlphaMaskUrl.GetUrl(), desiredSize, fittingMode, samplingMode, true);
         if(maskPixelBuffer)
         {
           if(!maskInfo->mPreappliedMasking)
@@ -213,7 +215,7 @@ TextureSet TextureManager::LoadAnimatedImageTexture(
       }
     }
 
-    textureId = RequestLoadInternal(url, alphaMaskId, contentScaleFactor, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::BOX_THEN_LINEAR, UseAtlas::NO_ATLAS, cropToMask, StorageType::UPLOAD_TO_TEXTURE, textureObserver, true, TextureManager::ReloadPolicy::CACHED, preMultiplyOnLoad, animatedImageLoading, frameIndex, false);
+    textureId = RequestLoadInternal(url, alphaMaskId, contentScaleFactor, desiredSize, fittingMode, samplingMode, UseAtlas::NO_ATLAS, cropToMask, StorageType::UPLOAD_TO_TEXTURE, textureObserver, true, TextureManager::ReloadPolicy::CACHED, preMultiplyOnLoad, animatedImageLoading, frameIndex, false);
 
     TextureManager::LoadState loadState = mTextureCacheManager.GetTextureStateInternal(textureId);
     if(loadState == TextureManager::LoadState::UPLOADED)
@@ -875,10 +877,10 @@ void TextureManager::LoadTexture(TextureManager::TextureInfo& textureInfo, Textu
   textureInfo.loadState = LoadState::LOADING;
   if(!textureInfo.loadSynchronously)
   {
-    auto  premultiplyOnLoad = (textureInfo.preMultiplyOnLoad && textureInfo.maskTextureId == INVALID_TEXTURE_ID) ? DevelAsyncImageLoader::PreMultiplyOnLoad::ON : DevelAsyncImageLoader::PreMultiplyOnLoad::OFF;
+    auto premultiplyOnLoad = (textureInfo.preMultiplyOnLoad && textureInfo.maskTextureId == INVALID_TEXTURE_ID) ? DevelAsyncImageLoader::PreMultiplyOnLoad::ON : DevelAsyncImageLoader::PreMultiplyOnLoad::OFF;
     if(textureInfo.animatedImageLoading)
     {
-      mAsyncLoader->LoadAnimatedImage(textureInfo.textureId, textureInfo.animatedImageLoading, textureInfo.frameIndex, premultiplyOnLoad);
+      mAsyncLoader->LoadAnimatedImage(textureInfo.textureId, textureInfo.animatedImageLoading, textureInfo.frameIndex, textureInfo.desiredSize, textureInfo.fittingMode, textureInfo.samplingMode, premultiplyOnLoad);
     }
     else
     {
@@ -1194,7 +1196,7 @@ void TextureManager::ApplyMask(TextureManager::TextureInfo& textureInfo, const T
 
     DALI_LOG_INFO(gTextureManagerLogFilter, Debug::Concise, "TextureManager::ApplyMask(): url:%s sync:%s\n", textureInfo.url.GetUrl().c_str(), textureInfo.loadSynchronously ? "T" : "F");
 
-    textureInfo.loadState   = LoadState::MASK_APPLYING;
+    textureInfo.loadState  = LoadState::MASK_APPLYING;
     auto premultiplyOnLoad = textureInfo.preMultiplyOnLoad ? DevelAsyncImageLoader::PreMultiplyOnLoad::ON : DevelAsyncImageLoader::PreMultiplyOnLoad::OFF;
     mAsyncLoader->ApplyMask(textureInfo.textureId, pixelBuffer, maskPixelBuffer, textureInfo.scaleFactor, textureInfo.cropToMask, premultiplyOnLoad);
   }
index 791553c..54db840 100644 (file)
@@ -21,9 +21,9 @@
 #include <dali/devel-api/adaptor-framework/animated-image-loading.h>
 #include <dali/devel-api/adaptor-framework/pixel-buffer.h>
 #include <dali/public-api/adaptor-framework/encoded-image-buffer.h>
+#include <dali/public-api/adaptor-framework/round-robin-container-view.h>
 #include <dali/public-api/common/dali-vector.h>
 #include <dali/public-api/rendering/geometry.h>
-#include <dali/public-api/adaptor-framework/round-robin-container-view.h>
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/devel-api/image-loader/image-atlas.h>
@@ -119,6 +119,8 @@ public:
    * @param[in]  frameIndex            The frame index to load.
    * @param[out] textureId             The textureId of the frame
    * @param[in, out] maskInfo          Mask info structure
+   * @param[in]  desiredSize           The size the image is likely to appear at. This can be set to 0, 0 for automatic
+   * @param[in]  fittingMode           The FittingMode to use
    * @param[in]  samplingMode          The SamplingMode to use
    * @param[in]  synchronousLoading    true if the frame should be loaded synchronously
    * @param[in]  textureObserver       The client object should inherit from this and provide the "LoadCompleted" virtual.
@@ -133,6 +135,8 @@ public:
                                       const uint32_t&                 frameIndex,
                                       TextureManager::TextureId&      textureId,
                                       MaskingDataPointer&             maskInfo,
+                                      const Dali::ImageDimensions&    desiredSize,
+                                      const Dali::FittingMode::Type&  fittingMode,
                                       const Dali::SamplingMode::Type& samplingMode,
                                       const bool&                     synchronousLoading,
                                       TextureUploadObserver*          textureObserver,
@@ -612,7 +616,6 @@ private:
    */
   void EmitLoadComplete(TextureUploadObserver* observer, TextureManager::TextureInfo& textureInfo, const bool& success);
 
-
   /**
    * @brief Remove observer in textureInfo
    *
@@ -648,14 +651,14 @@ private:
    */
   void ObserverDestroyed(TextureUploadObserver* observer);
 
-private:                                    // Member Variables:
-  TextureCacheManager mTextureCacheManager; ///< Manager the life-cycle and caching of Textures
-  std::unique_ptr<TextureAsyncLoadingHelper> mAsyncLoader;  ///< The Asynchronous image loader used to provide all local async loads
-  Dali::Vector<LifecycleObserver*>        mLifecycleObservers;      ///< Lifecycle observers of texture manager
-  Dali::Vector<QueueElement>              mLoadQueue;               ///< Queue of textures to load after NotifyObservers
-  Dali::Vector<QueueElement>              mRemoveQueue;             ///< Queue of textures to remove after NotifyObservers
-  TextureManager::TextureId               mLoadingQueueTextureId;   ///< TextureId when it is loading. it causes Load Textures to be queued.
-  bool                                    mLoadYuvPlanes;           ///< A global flag to specify if the image should be loaded as yuv planes
+private:                                                             // Member Variables:
+  TextureCacheManager                        mTextureCacheManager;   ///< Manager the life-cycle and caching of Textures
+  std::unique_ptr<TextureAsyncLoadingHelper> mAsyncLoader;           ///< The Asynchronous image loader used to provide all local async loads
+  Dali::Vector<LifecycleObserver*>           mLifecycleObservers;    ///< Lifecycle observers of texture manager
+  Dali::Vector<QueueElement>                 mLoadQueue;             ///< Queue of textures to load after NotifyObservers
+  Dali::Vector<QueueElement>                 mRemoveQueue;           ///< Queue of textures to remove after NotifyObservers
+  TextureManager::TextureId                  mLoadingQueueTextureId; ///< TextureId when it is loading. it causes Load Textures to be queued.
+  bool                                       mLoadYuvPlanes;         ///< A global flag to specify if the image should be loaded as yuv planes
 };
 
 } // namespace Internal
index db00ff5..3e8387f 100644 (file)
@@ -49,6 +49,26 @@ namespace
 {
 const int CUSTOM_PROPERTY_COUNT(5); // ltr, wrap, pixel area, crop to mask, mask texture ratio
 
+// fitting modes
+DALI_ENUM_TO_STRING_TABLE_BEGIN(FITTING_MODE)
+  DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::FittingMode, SHRINK_TO_FIT)
+  DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::FittingMode, SCALE_TO_FILL)
+  DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::FittingMode, FIT_WIDTH)
+  DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::FittingMode, FIT_HEIGHT)
+  DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::FittingMode, DEFAULT)
+DALI_ENUM_TO_STRING_TABLE_END(FITTING_MODE)
+
+// sampling modes
+DALI_ENUM_TO_STRING_TABLE_BEGIN(SAMPLING_MODE)
+  DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::SamplingMode, BOX)
+  DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::SamplingMode, NEAREST)
+  DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::SamplingMode, LINEAR)
+  DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::SamplingMode, BOX_THEN_NEAREST)
+  DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::SamplingMode, BOX_THEN_LINEAR)
+  DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::SamplingMode, NO_FILTER)
+  DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::SamplingMode, DONT_CARE)
+DALI_ENUM_TO_STRING_TABLE_END(SAMPLING_MODE)
+
 // stop behavior
 DALI_ENUM_TO_STRING_TABLE_BEGIN(STOP_BEHAVIOR)
   DALI_ENUM_TO_STRING_WITH_SCOPE(Dali::Toolkit::DevelImageVisual::StopBehavior, CURRENT_FRAME)
@@ -124,7 +144,7 @@ Debug::Filter* gAnimImgLogFilter = Debug::Filter::New(Debug::NoLogging, false, "
 
 AnimatedImageVisualPtr AnimatedImageVisual::New(VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl, const Property::Map& properties)
 {
-  AnimatedImageVisualPtr visual(new AnimatedImageVisual(factoryCache, shaderFactory));
+  AnimatedImageVisualPtr visual(new AnimatedImageVisual(factoryCache, shaderFactory, ImageDimensions()));
   visual->InitializeAnimatedImage(imageUrl);
   visual->SetProperties(properties);
 
@@ -135,7 +155,7 @@ AnimatedImageVisualPtr AnimatedImageVisual::New(VisualFactoryCache& factoryCache
 
 AnimatedImageVisualPtr AnimatedImageVisual::New(VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const Property::Array& imageUrls, const Property::Map& properties)
 {
-  AnimatedImageVisualPtr visual(new AnimatedImageVisual(factoryCache, shaderFactory));
+  AnimatedImageVisualPtr visual(new AnimatedImageVisual(factoryCache, shaderFactory, ImageDimensions()));
   visual->mImageUrls = new ImageCache::UrlList();
   visual->mImageUrls->reserve(imageUrls.Count());
 
@@ -154,9 +174,9 @@ AnimatedImageVisualPtr AnimatedImageVisual::New(VisualFactoryCache& factoryCache
   return visual;
 }
 
-AnimatedImageVisualPtr AnimatedImageVisual::New(VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl)
+AnimatedImageVisualPtr AnimatedImageVisual::New(VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl, ImageDimensions size)
 {
-  AnimatedImageVisualPtr visual(new AnimatedImageVisual(factoryCache, shaderFactory));
+  AnimatedImageVisualPtr visual(new AnimatedImageVisual(factoryCache, shaderFactory, size));
   visual->InitializeAnimatedImage(imageUrl);
 
   visual->Initialize();
@@ -178,7 +198,7 @@ void AnimatedImageVisual::CreateImageCache()
 
   if(mAnimatedImageLoading)
   {
-    mImageCache = new RollingAnimatedImageCache(textureManager, mAnimatedImageLoading, mMaskingData, *this, mCacheSize, mBatchSize,  mWrapModeU, mWrapModeV, IsSynchronousLoadingRequired(), mFactoryCache.GetPreMultiplyOnLoad());
+    mImageCache = new RollingAnimatedImageCache(textureManager, mDesiredSize, mFittingMode, mSamplingMode, mAnimatedImageLoading, mMaskingData, *this, mCacheSize, mBatchSize, mWrapModeU, mWrapModeV, IsSynchronousLoadingRequired(), mFactoryCache.GetPreMultiplyOnLoad());
   }
   else if(mImageUrls)
   {
@@ -189,11 +209,11 @@ void AnimatedImageVisual::CreateImageCache()
     uint16_t cacheSize = std::max(std::min(std::max(batchSize, mCacheSize), numUrls), MINIMUM_CACHESIZE);
     if(cacheSize < numUrls)
     {
-      mImageCache = new RollingImageCache(textureManager, *mImageUrls, mMaskingData, *this, cacheSize, batchSize, mFrameDelay);
+      mImageCache = new RollingImageCache(textureManager, mDesiredSize, mFittingMode, mSamplingMode, *mImageUrls, mMaskingData, *this, cacheSize, batchSize, mFrameDelay);
     }
     else
     {
-      mImageCache = new FixedImageCache(textureManager, *mImageUrls, mMaskingData, *this, batchSize, mFrameDelay);
+      mImageCache = new FixedImageCache(textureManager, mDesiredSize, mFittingMode, mSamplingMode, *mImageUrls, mMaskingData, *this, batchSize, mFrameDelay);
     }
   }
 
@@ -203,7 +223,7 @@ void AnimatedImageVisual::CreateImageCache()
   }
 }
 
-AnimatedImageVisual::AnimatedImageVisual(VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory)
+AnimatedImageVisual::AnimatedImageVisual(VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, ImageDimensions desiredSize)
 : Visual::Base(factoryCache, Visual::FittingMode::FILL, Toolkit::Visual::ANIMATED_IMAGE),
   mFrameDelayTimer(),
   mPlacementActor(),
@@ -223,11 +243,14 @@ AnimatedImageVisual::AnimatedImageVisual(VisualFactoryCache& factoryCache, Image
   mLoadPolicy(Toolkit::ImageVisual::LoadPolicy::ATTACHED),
   mReleasePolicy(Toolkit::ImageVisual::ReleasePolicy::DETACHED),
   mMaskingData(),
+  mDesiredSize(desiredSize),
   mFrameCount(0),
   mImageSize(),
   mActionStatus(DevelAnimatedImageVisual::Action::PLAY),
   mWrapModeU(WrapMode::DEFAULT),
   mWrapModeV(WrapMode::DEFAULT),
+  mFittingMode(FittingMode::SCALE_TO_FILL),
+  mSamplingMode(SamplingMode::BOX_THEN_LINEAR),
   mStopBehavior(DevelImageVisual::StopBehavior::CURRENT_FRAME),
   mStartFirstFrame(false),
   mIsJumpTo(false)
@@ -249,6 +272,14 @@ AnimatedImageVisual::~AnimatedImageVisual()
 
 void AnimatedImageVisual::GetNaturalSize(Vector2& naturalSize)
 {
+  if(mDesiredSize.GetWidth() > 0 && mDesiredSize.GetHeight() > 0)
+  {
+    naturalSize.x = mDesiredSize.GetWidth();
+    naturalSize.y = mDesiredSize.GetHeight();
+    return;
+  }
+
+  naturalSize = Vector2::ZERO;
   if(mImageSize.GetWidth() == 0 && mImageSize.GetHeight() == 0)
   {
     if(mMaskingData && mMaskingData->mAlphaMaskUrl.IsValid() &&
@@ -325,11 +356,21 @@ void AnimatedImageVisual::DoCreatePropertyMap(Property::Map& map) const
 
   map.Insert(Toolkit::ImageVisual::Property::LOAD_POLICY, mLoadPolicy);
   map.Insert(Toolkit::ImageVisual::Property::RELEASE_POLICY, mReleasePolicy);
+  map.Insert(Toolkit::ImageVisual::Property::FITTING_MODE, mFittingMode);
+  map.Insert(Toolkit::ImageVisual::Property::SAMPLING_MODE, mSamplingMode);
+  map.Insert(Toolkit::ImageVisual::Property::DESIRED_WIDTH, mDesiredSize.GetWidth());
+  map.Insert(Toolkit::ImageVisual::Property::DESIRED_HEIGHT, mDesiredSize.GetHeight());
 }
 
 void AnimatedImageVisual::DoCreateInstancePropertyMap(Property::Map& map) const
 {
-  // Do nothing
+  map.Clear();
+  map.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::ANIMATED_IMAGE);
+  if(mImageUrl.IsValid())
+  {
+    map.Insert(Toolkit::ImageVisual::Property::DESIRED_WIDTH, mDesiredSize.GetWidth());
+    map.Insert(Toolkit::ImageVisual::Property::DESIRED_HEIGHT, mDesiredSize.GetHeight());
+  }
 }
 
 void AnimatedImageVisual::OnDoAction(const Dali::Property::Index actionId, const Dali::Property::Value& attributes)
@@ -466,6 +507,22 @@ void AnimatedImageVisual::DoSetProperties(const Property::Map& propertyMap)
       {
         DoSetProperty(Toolkit::ImageVisual::Property::SYNCHRONOUS_LOADING, keyValue.second);
       }
+      else if(keyValue.first == IMAGE_FITTING_MODE)
+      {
+        DoSetProperty(Toolkit::ImageVisual::Property::FITTING_MODE, keyValue.second);
+      }
+      else if(keyValue.first == IMAGE_SAMPLING_MODE)
+      {
+        DoSetProperty(Toolkit::ImageVisual::Property::SAMPLING_MODE, keyValue.second);
+      }
+      else if(keyValue.first == IMAGE_DESIRED_WIDTH)
+      {
+        DoSetProperty(Toolkit::ImageVisual::Property::DESIRED_WIDTH, keyValue.second);
+      }
+      else if(keyValue.first == IMAGE_DESIRED_HEIGHT)
+      {
+        DoSetProperty(Toolkit::ImageVisual::Property::DESIRED_HEIGHT, keyValue.second);
+      }
     }
   }
   // Load image immediately if LOAD_POLICY requires it
@@ -654,6 +711,50 @@ void AnimatedImageVisual::DoSetProperty(Property::Index        index,
       mLoadPolicy = Toolkit::ImageVisual::LoadPolicy::Type(loadPolicy);
       break;
     }
+
+    case Toolkit::ImageVisual::Property::FITTING_MODE:
+    {
+      int fittingMode = 0;
+      Scripting::GetEnumerationProperty(value, FITTING_MODE_TABLE, FITTING_MODE_TABLE_COUNT, fittingMode);
+      mFittingMode = Dali::FittingMode::Type(fittingMode);
+      break;
+    }
+
+    case Toolkit::ImageVisual::Property::SAMPLING_MODE:
+    {
+      int samplingMode = 0;
+      Scripting::GetEnumerationProperty(value, SAMPLING_MODE_TABLE, SAMPLING_MODE_TABLE_COUNT, samplingMode);
+      mSamplingMode = Dali::SamplingMode::Type(samplingMode);
+      break;
+    }
+
+    case Toolkit::ImageVisual::Property::DESIRED_WIDTH:
+    {
+      float desiredWidth = 0.0f;
+      if(value.Get(desiredWidth))
+      {
+        mDesiredSize.SetWidth(desiredWidth);
+      }
+      else
+      {
+        DALI_LOG_ERROR("AnimatedImageVisual: desiredWidth property has incorrect type\n");
+      }
+      break;
+    }
+
+    case Toolkit::ImageVisual::Property::DESIRED_HEIGHT:
+    {
+      float desiredHeight = 0.0f;
+      if(value.Get(desiredHeight))
+      {
+        mDesiredSize.SetHeight(desiredHeight);
+      }
+      else
+      {
+        DALI_LOG_ERROR("AnimatedImageVisual: desiredHeight property has incorrect type\n");
+      }
+      break;
+    }
   }
 }
 
index 8fc0f59..243b989 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_TOOLKIT_INTERNAL_ANIMATED_IMAGE_VISUAL_H
 
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
@@ -111,8 +111,9 @@ public:
    * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
    * @param[in] shaderFactory The ImageVisualShaderFactory object
    * @param[in] imageUrl The URL to animated image resource to use
+   * @param[in] size The width and height of the image. The visual size will be used if these are 0.
    */
-  static AnimatedImageVisualPtr New(VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl);
+  static AnimatedImageVisualPtr New(VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl, ImageDimensions size = ImageDimensions());
 
 public: // from Visual
   /**
@@ -141,8 +142,9 @@ protected:
    *
    * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
    * @param[in] shaderFactory The ImageVisualShaderFactory object
+   * @param[in] desiredSize The width and height of the image. The visual size will be used if these are 0.
    */
-  AnimatedImageVisual(VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory);
+  AnimatedImageVisual(VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, ImageDimensions desiredSize);
 
   /**
    * @brief A reference counted object may only be deleted by calling Unreference().
@@ -284,6 +286,7 @@ private:
   Dali::Toolkit::ImageVisual::LoadPolicy::Type    mLoadPolicy;
   Dali::Toolkit::ImageVisual::ReleasePolicy::Type mReleasePolicy;
   TextureManager::MaskingDataPointer              mMaskingData;
+  Dali::ImageDimensions                           mDesiredSize;
 
   // Shared variables
   uint32_t        mFrameCount; // Number of frames
@@ -291,11 +294,13 @@ private:
 
   DevelAnimatedImageVisual::Action::Type mActionStatus;
 
-  Dali::WrapMode::Type                   mWrapModeU : 3;
-  Dali::WrapMode::Type                   mWrapModeV : 3;
-  DevelImageVisual::StopBehavior::Type   mStopBehavior : 2;
-  bool                                   mStartFirstFrame : 1;
-  bool                                   mIsJumpTo : 1;
+  Dali::WrapMode::Type                 mWrapModeU : 3;
+  Dali::WrapMode::Type                 mWrapModeV : 3;
+  Dali::FittingMode::Type              mFittingMode : 3;
+  Dali::SamplingMode::Type             mSamplingMode : 4;
+  DevelImageVisual::StopBehavior::Type mStopBehavior : 2;
+  bool                                 mStartFirstFrame : 1;
+  bool                                 mIsJumpTo : 1;
 };
 
 } // namespace Internal
index 7cb6ce3..c40f802 100644 (file)
@@ -36,12 +36,15 @@ constexpr uint32_t FIRST_FRAME_INDEX = 0u;
 } // namespace
 
 FixedImageCache::FixedImageCache(TextureManager&                     textureManager,
+                                 ImageDimensions                     size,
+                                 Dali::FittingMode::Type             fittingMode,
+                                 Dali::SamplingMode::Type            samplingMode,
                                  UrlList&                            urlList,
                                  TextureManager::MaskingDataPointer& maskingData,
                                  ImageCache::FrameReadyObserver&     observer,
                                  uint32_t                            batchSize,
                                  uint32_t                            interval)
-: ImageCache(textureManager, maskingData, observer, batchSize, interval),
+: ImageCache(textureManager, size, fittingMode, samplingMode, maskingData, observer, batchSize, interval),
   mImageUrls(urlList),
   mFront(FIRST_FRAME_INDEX)
 {
@@ -132,7 +135,7 @@ void FixedImageCache::LoadBatch()
     Dali::ImageDimensions textureRectSize;
     auto                  preMultiply = TextureManager::MultiplyOnLoad::LOAD_WITHOUT_MULTIPLY;
 
-    mTextureManager.LoadTexture(url, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::BOX_THEN_LINEAR, mMaskingData, synchronousLoading, mImageUrls[frameIndex].mTextureId, textureRect, textureRectSize, atlasingStatus, loadingStatus, this, atlasObserver, imageAtlasManager, ENABLE_ORIENTATION_CORRECTION, TextureManager::ReloadPolicy::CACHED, preMultiply);
+    mTextureManager.LoadTexture(url, mDesiredSize, mFittingMode, mSamplingMode, mMaskingData, synchronousLoading, mImageUrls[frameIndex].mTextureId, textureRect, textureRectSize, atlasingStatus, loadingStatus, this, atlasObserver, imageAtlasManager, ENABLE_ORIENTATION_CORRECTION, TextureManager::ReloadPolicy::CACHED, preMultiply);
     mRequestingLoad = false;
   }
 }
index c798a66..90e2c8f 100644 (file)
@@ -33,6 +33,9 @@ public:
   /**
    * Constructor.
    * @param[in] textureManager The texture manager
+   * @param[in] size           The width and height to fit the loaded image to.
+   * @param[in] fittingMode    The FittingMode of the resource to load
+   * @param[in] samplingMode   The SamplingMode of the resource to load
    * @param[in] urlList        List of urls to cache
    * @param[in] maskingData    Masking data to be applied.
    * @param[in] observer       FrameReady observer
@@ -43,6 +46,9 @@ public:
    * batch and cache sizes. The cache is as large as the number of urls.
    */
   FixedImageCache(TextureManager&                     textureManager,
+                  ImageDimensions                     size,
+                  Dali::FittingMode::Type             fittingMode,
+                  Dali::SamplingMode::Type            samplingMode,
                   UrlList&                            urlList,
                   TextureManager::MaskingDataPointer& maskingData,
                   ImageCache::FrameReadyObserver&     observer,
index 59f0520..3b5131f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
@@ -23,6 +23,9 @@ namespace Toolkit
 namespace Internal
 {
 ImageCache::ImageCache(TextureManager&                     textureManager,
+                       ImageDimensions                     size,
+                       Dali::FittingMode::Type             fittingMode,
+                       Dali::SamplingMode::Type            samplingMode,
                        TextureManager::MaskingDataPointer& maskingData,
                        ImageCache::FrameReadyObserver&     observer,
                        uint32_t                            batchSize,
@@ -30,6 +33,9 @@ ImageCache::ImageCache(TextureManager&                     textureManager,
 : mTextureManager(textureManager),
   mObserver(observer),
   mMaskingData(maskingData),
+  mDesiredSize(size),
+  mFittingMode(fittingMode),
+  mSamplingMode(samplingMode),
   mBatchSize(batchSize),
   mInterval(interval),
   mLoadState(TextureManager::LoadState::NOT_STARTED),
index d3b6b0a..f65d60b 100644 (file)
@@ -59,8 +59,10 @@ public:
   /**
    * @brief Constructor.
    * @param[in] textureManager The texture manager
-   * @param[in] urlList List of urls to cache
-   * @param[in] observer FrameReady observer
+   * @param[in] size           The width and height to fit the loaded image to.
+   * @param[in] fittingMode    The FittingMode of the resource to load
+   * @param[in] samplingMode   The SamplingMode of the resource to load
+   * @param[in] observer       FrameReady observer
    * @param[in] maskingData    Masking data to be applied.
    * @param[in] batchSize The size of a batch to load
    * @param[in] interval Time interval(ms) between each frame
@@ -69,6 +71,9 @@ public:
    * batch and cache sizes. The cache is as large as the number of urls.
    */
   ImageCache(TextureManager&                     textureManager,
+             ImageDimensions                     size,
+             Dali::FittingMode::Type             fittingMode,
+             Dali::SamplingMode::Type            samplingMode,
              TextureManager::MaskingDataPointer& maskingData,
              ImageCache::FrameReadyObserver&     observer,
              uint32_t                            batchSize,
@@ -140,6 +145,9 @@ protected:
   TextureManager&                     mTextureManager;
   FrameReadyObserver&                 mObserver;
   TextureManager::MaskingDataPointer& mMaskingData;
+  Dali::ImageDimensions               mDesiredSize;
+  Dali::FittingMode::Type             mFittingMode : 3;
+  Dali::SamplingMode::Type            mSamplingMode : 4;
   uint32_t                            mBatchSize;
   uint32_t                            mInterval;
   TextureManager::LoadState           mLoadState;
index bd6c5a7..995ea60 100644 (file)
@@ -61,6 +61,9 @@ static constexpr uint32_t FIRST_FRAME_INDEX  = 0u;
 } // namespace
 
 RollingAnimatedImageCache::RollingAnimatedImageCache(TextureManager&                     textureManager,
+                                                     ImageDimensions                     size,
+                                                     Dali::FittingMode::Type             fittingMode,
+                                                     Dali::SamplingMode::Type            samplingMode,
                                                      AnimatedImageLoading&               animatedImageLoading,
                                                      TextureManager::MaskingDataPointer& maskingData,
                                                      ImageCache::FrameReadyObserver&     observer,
@@ -70,7 +73,7 @@ RollingAnimatedImageCache::RollingAnimatedImageCache(TextureManager&
                                                      const Dali::WrapMode::Type&         wrapModeV,
                                                      bool                                isSynchronousLoading,
                                                      bool                                preMultiplyOnLoad)
-: ImageCache(textureManager, maskingData, observer, batchSize, 0u),
+: ImageCache(textureManager, size, fittingMode, samplingMode, maskingData, observer, batchSize, 0u),
   mImageUrl(animatedImageLoading.GetUrl()),
   mAnimatedImageLoading(animatedImageLoading),
   mFrameCount(SINGLE_IMAGE_COUNT),
@@ -207,7 +210,9 @@ TextureSet RollingAnimatedImageCache::RequestFrameLoading(uint32_t frameIndex, b
                                                                    frameIndex,
                                                                    loadTextureId,
                                                                    mMaskingData,
-                                                                   SamplingMode::BOX_THEN_LINEAR,
+                                                                   mDesiredSize,
+                                                                   mFittingMode,
+                                                                   mSamplingMode,
                                                                    synchronousLoading,
                                                                    this,
                                                                    preMultiplyOnLoading);
@@ -263,8 +268,8 @@ TextureSet RollingAnimatedImageCache::GetFrontTextureSet() const
 {
   DALI_LOG_INFO(gAnimImgLogFilter, Debug::Concise, "RollingAnimatedImageCache::GetFrontTextureSet() FrameNumber:%d\n", mQueue[0].mFrameNumber);
 
-  TextureManager::TextureId textureId = GetCachedTextureId(0);
-  TextureSet textureSet = mTextureManager.GetTextureSet(textureId);
+  TextureManager::TextureId textureId  = GetCachedTextureId(0);
+  TextureSet                textureSet = mTextureManager.GetTextureSet(textureId);
   if(textureSet)
   {
     Sampler sampler = Sampler::New();
index 8fed2d7..c827e40 100644 (file)
@@ -42,7 +42,10 @@ public:
   /**
    * @brief Constructor.
    * @param[in] textureManager       The texture manager
-   * @param[in] animatedImageLoading  The loaded animated image
+   * @param[in] size                 The width and height to fit the loaded image to.
+   * @param[in] fittingMode          The FittingMode of the resource to load
+   * @param[in] samplingMode         The SamplingMode of the resource to load
+   * @param[in] animatedImageLoading The loaded animated image
    * @param[in] maskingData          Masking data to be applied.
    * @param[in] observer             FrameReady observer
    * @param[in] cacheSize            The size of the cache
@@ -56,6 +59,9 @@ public:
    * batch and cache sizes.
    */
   RollingAnimatedImageCache(TextureManager&                     textureManager,
+                            ImageDimensions                     size,
+                            Dali::FittingMode::Type             fittingMode,
+                            Dali::SamplingMode::Type            samplingMode,
                             AnimatedImageLoading&               animatedImageLoading,
                             TextureManager::MaskingDataPointer& maskingData,
                             ImageCache::FrameReadyObserver&     observer,
index f0dbb94..19f025d 100644 (file)
@@ -58,13 +58,16 @@ namespace Toolkit
 namespace Internal
 {
 RollingImageCache::RollingImageCache(TextureManager&                     textureManager,
+                                     ImageDimensions                     size,
+                                     Dali::FittingMode::Type             fittingMode,
+                                     Dali::SamplingMode::Type            samplingMode,
                                      UrlList&                            urlList,
                                      TextureManager::MaskingDataPointer& maskingData,
                                      ImageCache::FrameReadyObserver&     observer,
                                      uint16_t                            cacheSize,
                                      uint16_t                            batchSize,
                                      uint32_t                            interval)
-: ImageCache(textureManager, maskingData, observer, batchSize, interval),
+: ImageCache(textureManager, size, fittingMode, samplingMode, maskingData, observer, batchSize, interval),
   mImageUrls(urlList),
   mQueue(cacheSize)
 {
@@ -168,7 +171,7 @@ void RollingImageCache::LoadBatch(uint32_t frameIndex)
 
     TextureManager::TextureId loadTextureId = TextureManager::INVALID_TEXTURE_ID;
     TextureSet                textureSet    = mTextureManager.LoadTexture(
-      url, ImageDimensions(), FittingMode::SCALE_TO_FILL, SamplingMode::BOX_THEN_LINEAR, mMaskingData, synchronousLoading, loadTextureId, textureRect, textureRectSize, atlasingStatus, loadingStatus, this, atlasObserver, imageAtlasManager, ENABLE_ORIENTATION_CORRECTION, TextureManager::ReloadPolicy::CACHED, preMultiply);
+      url, mDesiredSize, mFittingMode, mSamplingMode, mMaskingData, synchronousLoading, loadTextureId, textureRect, textureRectSize, atlasingStatus, loadingStatus, this, atlasObserver, imageAtlasManager, ENABLE_ORIENTATION_CORRECTION, TextureManager::ReloadPolicy::CACHED, preMultiply);
     mImageUrls[imageFrame.mUrlIndex].mTextureId = loadTextureId;
 
     mRequestingLoad = false;
@@ -180,8 +183,8 @@ void RollingImageCache::LoadBatch(uint32_t frameIndex)
 
 TextureSet RollingImageCache::GetFrontTextureSet() const
 {
-  TextureManager::TextureId textureId = GetCachedTextureId(0);
-  TextureSet textureSet = mTextureManager.GetTextureSet(textureId);
+  TextureManager::TextureId textureId  = GetCachedTextureId(0);
+  TextureSet                textureSet = mTextureManager.GetTextureSet(textureId);
   if(textureSet)
   {
     Sampler sampler = Sampler::New();
index e01f17f..8fbaad6 100644 (file)
@@ -38,6 +38,9 @@ public:
   /**
    * Constructor.
    * @param[in] textureManager The texture manager
+   * @param[in] size           The width and height to fit the loaded image to.
+   * @param[in] fittingMode    The FittingMode of the resource to load
+   * @param[in] samplingMode   The SamplingMode of the resource to load
    * @param[in] urlList        List of urls to cache
    * @param[in] maskingData    Masking data to be applied.
    * @param[in] observer       FrameReady observer
@@ -49,6 +52,9 @@ public:
    * batch and cache sizes.
    */
   RollingImageCache(TextureManager&                     textureManager,
+                    ImageDimensions                     size,
+                    Dali::FittingMode::Type             fittingMode,
+                    Dali::SamplingMode::Type            samplingMode,
                     UrlList&                            urlList,
                     TextureManager::MaskingDataPointer& maskingData,
                     ImageCache::FrameReadyObserver&     observer,
@@ -141,8 +147,8 @@ private:
     bool         mReady    = false;
   };
 
-  std::vector<UrlStore>&                 mImageUrls;
-  CircularQueue<ImageFrame>              mQueue;
+  std::vector<UrlStore>&    mImageUrls;
+  CircularQueue<ImageFrame> mQueue;
 };
 
 } // namespace Internal
index 60fb25e..a975aa8 100644 (file)
@@ -338,7 +338,7 @@ Toolkit::Visual::Base VisualFactory::CreateVisual(const std::string& url, ImageD
       case VisualUrl::GIF:
       case VisualUrl::WEBP:
       {
-        visualPtr = AnimatedImageVisual::New(GetFactoryCache(), GetImageVisualShaderFactory(), visualUrl);
+        visualPtr = AnimatedImageVisual::New(GetFactoryCache(), GetImageVisualShaderFactory(), visualUrl, size);
         break;
       }
       case VisualUrl::JSON:
index dc27df8..5161cd1 100644 (file)
@@ -29,7 +29,7 @@ namespace Toolkit
 {
 const unsigned int TOOLKIT_MAJOR_VERSION = 2;
 const unsigned int TOOLKIT_MINOR_VERSION = 2;
-const unsigned int TOOLKIT_MICRO_VERSION = 3;
+const unsigned int TOOLKIT_MICRO_VERSION = 4;
 const char* const  TOOLKIT_BUILD_DATE    = __DATE__ " " __TIME__;
 
 #ifdef DEBUG_ENABLED
index 72b99fe..f686d38 100644 (file)
@@ -1,6 +1,6 @@
 Name:       dali2-toolkit
 Summary:    Dali 3D engine Toolkit
-Version:    2.2.3
+Version:    2.2.4
 Release:    1
 Group:      System/Libraries
 License:    Apache-2.0 and BSD-3-Clause and MIT