Merge changes I776588c1,I7292a2fb into devel/master
authorAdeel Kazmi <adeel.kazmi@samsung.com>
Fri, 1 Sep 2023 14:02:39 +0000 (14:02 +0000)
committerGerrit Code Review <gerrit@review>
Fri, 1 Sep 2023 14:02:39 +0000 (14:02 +0000)
* changes:
  Adding chipmunk implementation for physics adaptor
  Adding bullet physics files

50 files changed:
automated-tests/src/dali-scene3d-internal/utc-Dali-Gltf2LoaderImpl.cpp
automated-tests/src/dali-scene3d/utc-Dali-Light.cpp
automated-tests/src/dali-scene3d/utc-Dali-Model.cpp
automated-tests/src/dali-scene3d/utc-Dali-PathFinding.cpp
automated-tests/src/dali-scene3d/utc-Dali-SceneView.cpp
automated-tests/src/dali-toolkit/utc-Dali-AnimatedVectorImageVisual.cpp
automated-tests/src/dali-toolkit/utc-Dali-Image.cpp
dali-scene3d/internal/algorithm/path-finder-dijkstra.cpp [moved from dali-scene3d/internal/algorithm/path-finder-djikstra.cpp with 73% similarity]
dali-scene3d/internal/algorithm/path-finder-dijkstra.h [moved from dali-scene3d/internal/algorithm/path-finder-djikstra.h with 88% similarity]
dali-scene3d/internal/algorithm/path-finder-spfa-double-way.cpp
dali-scene3d/internal/algorithm/path-finder-spfa.cpp
dali-scene3d/internal/common/light-observer.h
dali-scene3d/internal/controls/model/model-impl.cpp
dali-scene3d/internal/controls/model/model-impl.h
dali-scene3d/internal/controls/scene-view/scene-view-impl.cpp
dali-scene3d/internal/controls/scene-view/scene-view-impl.h
dali-scene3d/internal/file.list
dali-scene3d/internal/graphics/shaders/default-physically-based-shader.frag
dali-scene3d/internal/graphics/shaders/default-physically-based-shader.vert
dali-scene3d/internal/graphics/shaders/shadow-map-shader.frag [new file with mode: 0644]
dali-scene3d/internal/graphics/shaders/shadow-map-shader.vert [new file with mode: 0644]
dali-scene3d/internal/light/light-impl.cpp
dali-scene3d/internal/light/light-impl.h
dali-scene3d/internal/loader/dli-loader-impl.cpp
dali-scene3d/internal/loader/gltf2-util.cpp
dali-scene3d/internal/model-components/material-impl.cpp
dali-scene3d/internal/model-components/material-impl.h
dali-scene3d/internal/model-components/model-node-impl.cpp
dali-scene3d/internal/model-components/model-node-impl.h
dali-scene3d/internal/model-components/model-primitive-impl.cpp
dali-scene3d/internal/model-components/model-primitive-impl.h
dali-scene3d/public-api/algorithm/path-finder.cpp
dali-scene3d/public-api/algorithm/path-finder.h
dali-scene3d/public-api/light/light.cpp
dali-scene3d/public-api/light/light.h
dali-scene3d/public-api/loader/material-definition.cpp
dali-scene3d/public-api/loader/material-definition.h
dali-scene3d/public-api/loader/shader-definition.cpp
dali-scene3d/public-api/loader/shader-definition.h
dali-scene3d/public-api/loader/shader-manager.cpp
dali-scene3d/public-api/loader/shader-manager.h
dali-toolkit/devel-api/visuals/animated-vector-image-visual-actions-devel.h
dali-toolkit/internal/controls/text-controls/text-label-impl.cpp
dali-toolkit/internal/visuals/animated-vector-image/animated-vector-image-visual.cpp
dali-toolkit/internal/visuals/animated-vector-image/vector-animation-task.cpp
dali-toolkit/internal/visuals/animated-vector-image/vector-animation-task.h
dali-toolkit/public-api/dali-toolkit-version.cpp
dali-toolkit/public-api/image-loader/image.cpp
dali-toolkit/public-api/image-loader/image.h
packaging/dali-toolkit.spec

index adf95eb..723c3ae 100644 (file)
@@ -209,6 +209,7 @@ int UtcDaliGltfLoaderSuccess1(void)
       Scene3D::Material::AlphaModeType::MASK,
       true,
       true,
+      true,
       {
         {
           MaterialDefinition::ALBEDO,
@@ -291,6 +292,7 @@ int UtcDaliGltfLoaderSuccess1(void)
       Scene3D::Material::AlphaModeType::OPAQUE,
       true,
       false,
+      true,
       {
         {
           MaterialDefinition::ALBEDO,
@@ -620,7 +622,7 @@ int UtcDaliGltfLoaderMRendererTest(void)
   DALI_TEST_EQUAL(child.GetProperty(Actor::Property::NAME).Get<std::string>(), "RootNode");
   DALI_TEST_EQUAL(child.GetProperty(Actor::Property::SCALE).Get<Vector3>(), Vector3(1.0f, 1.0f, 1.0f));
   DALI_TEST_EQUAL(child.GetRendererCount(), 1u);
-  DALI_TEST_EQUAL(child.GetRendererAt(0).GetTextures().GetTextureCount(), 4u);
+  DALI_TEST_EQUAL(child.GetRendererAt(0).GetTextures().GetTextureCount(), 5u);
 
   DALI_TEST_EQUAL(child.GetRendererCount(), 1u);
   DALI_TEST_EQUAL(child.GetRendererAt(0u).GetProperty<decltype(BlendMode::ON)>(Renderer::Property::BLEND_MODE), BlendMode::ON);
index 01bb4b0..cc5bc7f 100644 (file)
@@ -599,3 +599,450 @@ int UtcDaliLightModelAddAndRemove(void)
 
   END_TEST;
 }
+
+// Enable Shadow and add the light to SceneView.
+int UtcDaliLightEnableShadowOnScene01(void)
+{
+  ToolkitTestApplication application;
+
+  Scene3D::SceneView sceneView = Scene3D::SceneView::New();
+  sceneView.SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  sceneView.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+  sceneView.SetProperty(Dali::Actor::Property::WIDTH_RESIZE_POLICY, ResizePolicy::FILL_TO_PARENT);
+  sceneView.SetProperty(Dali::Actor::Property::HEIGHT_RESIZE_POLICY, ResizePolicy::FILL_TO_PARENT);
+  application.GetScene().Add(sceneView);
+
+  Scene3D::Model model = Scene3D::Model::New(TEST_GLTF_FILE_NAME);
+  sceneView.Add(model);
+
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+  application.SendNotification();
+  application.Render();
+
+  // Light is added on layer when on scene
+  DALI_TEST_EQUALS(true, model.GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE), TEST_LOCATION);
+
+  Renderer renderer = model.FindChildByName("node2").GetRendererAt(0u);
+  DALI_TEST_CHECK(renderer);
+  Shader shader = renderer.GetShader();
+  DALI_TEST_CHECK(shader);
+
+  auto shadowEnabledIndex = shader.GetPropertyIndex("uIsShadowEnabled");
+  DALI_TEST_CHECK(shadowEnabledIndex != DALI_KEY_INVALID);
+  DALI_TEST_EQUALS(0, shader.GetProperty<int32_t>(shadowEnabledIndex), TEST_LOCATION);
+
+  Scene3D::Light light = Scene3D::Light::New();
+  light.SetProperty(Dali::Actor::Property::COLOR, Color::BLUE);
+  Dali::DevelActor::LookAt(light, Vector3(1.0f, 0.0f, 0.0f));
+  light.EnableShadow(true);
+
+  DALI_TEST_CHECK(shadowEnabledIndex != DALI_KEY_INVALID);
+  DALI_TEST_EQUALS(0, shader.GetProperty<int32_t>(shadowEnabledIndex), TEST_LOCATION);
+
+  sceneView.Add(light);
+
+  DALI_TEST_CHECK(shadowEnabledIndex != DALI_KEY_INVALID);
+  DALI_TEST_EQUALS(1, shader.GetProperty<int32_t>(shadowEnabledIndex), TEST_LOCATION);
+
+  END_TEST;
+}
+
+// Add the light to SceneView and Enable Shadow.
+int UtcDaliLightEnableShadowOnScene02(void)
+{
+  ToolkitTestApplication application;
+
+  Scene3D::SceneView sceneView = Scene3D::SceneView::New();
+  sceneView.SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  sceneView.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+  sceneView.SetProperty(Dali::Actor::Property::WIDTH_RESIZE_POLICY, ResizePolicy::FILL_TO_PARENT);
+  sceneView.SetProperty(Dali::Actor::Property::HEIGHT_RESIZE_POLICY, ResizePolicy::FILL_TO_PARENT);
+  application.GetScene().Add(sceneView);
+
+  Scene3D::Model model = Scene3D::Model::New(TEST_GLTF_FILE_NAME);
+  sceneView.Add(model);
+
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+  application.SendNotification();
+  application.Render();
+
+  // Light is added on layer when on scene
+  DALI_TEST_EQUALS(true, model.GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE), TEST_LOCATION);
+
+  Renderer renderer = model.FindChildByName("node2").GetRendererAt(0u);
+  DALI_TEST_CHECK(renderer);
+  Shader shader = renderer.GetShader();
+  DALI_TEST_CHECK(shader);
+
+  auto shadowEnabledIndex = shader.GetPropertyIndex("uIsShadowEnabled");
+  DALI_TEST_CHECK(shadowEnabledIndex != DALI_KEY_INVALID);
+  DALI_TEST_EQUALS(0, shader.GetProperty<int32_t>(shadowEnabledIndex), TEST_LOCATION);
+
+  Scene3D::Light light = Scene3D::Light::New();
+  light.SetProperty(Dali::Actor::Property::COLOR, Color::BLUE);
+  Dali::DevelActor::LookAt(light, Vector3(1.0f, 0.0f, 0.0f));
+  sceneView.Add(light);
+
+  DALI_TEST_CHECK(shadowEnabledIndex != DALI_KEY_INVALID);
+  DALI_TEST_EQUALS(0, shader.GetProperty<int32_t>(shadowEnabledIndex), TEST_LOCATION);
+
+  light.EnableShadow(true);
+
+  DALI_TEST_CHECK(shadowEnabledIndex != DALI_KEY_INVALID);
+  DALI_TEST_EQUALS(1, shader.GetProperty<int32_t>(shadowEnabledIndex), TEST_LOCATION);
+
+  light.EnableShadow(true);
+
+  DALI_TEST_CHECK(shadowEnabledIndex != DALI_KEY_INVALID);
+  DALI_TEST_EQUALS(1, shader.GetProperty<int32_t>(shadowEnabledIndex), TEST_LOCATION);
+
+  END_TEST;
+}
+
+// Add the light to SceneView and Add Model.
+int UtcDaliLightEnableShadowOnScene03(void)
+{
+  ToolkitTestApplication application;
+
+  Scene3D::SceneView sceneView = Scene3D::SceneView::New();
+  sceneView.SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  sceneView.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+  sceneView.SetProperty(Dali::Actor::Property::WIDTH_RESIZE_POLICY, ResizePolicy::FILL_TO_PARENT);
+  sceneView.SetProperty(Dali::Actor::Property::HEIGHT_RESIZE_POLICY, ResizePolicy::FILL_TO_PARENT);
+  application.GetScene().Add(sceneView);
+
+  Scene3D::Light light = Scene3D::Light::New();
+  light.SetProperty(Dali::Actor::Property::COLOR, Color::BLUE);
+  Dali::DevelActor::LookAt(light, Vector3(1.0f, 0.0f, 0.0f));
+  light.EnableShadow(true);
+  sceneView.Add(light);
+
+  application.SendNotification();
+  application.Render();
+
+  Scene3D::Model model = Scene3D::Model::New(TEST_GLTF_FILE_NAME);
+  sceneView.Add(model);
+
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+  application.SendNotification();
+  application.Render();
+
+  // Light is added on layer when on scene
+  DALI_TEST_EQUALS(true, model.GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE), TEST_LOCATION);
+
+  Renderer renderer = model.FindChildByName("node2").GetRendererAt(0u);
+  DALI_TEST_CHECK(renderer);
+  Shader shader = renderer.GetShader();
+  DALI_TEST_CHECK(shader);
+
+  auto shadowEnabledIndex = shader.GetPropertyIndex("uIsShadowEnabled");
+  DALI_TEST_CHECK(shadowEnabledIndex != DALI_KEY_INVALID);
+  DALI_TEST_EQUALS(1, shader.GetProperty<int32_t>(shadowEnabledIndex), TEST_LOCATION);
+
+  END_TEST;
+}
+
+// Disable Shadow
+int UtcDaliLightDisableShadow01(void)
+{
+  ToolkitTestApplication application;
+
+  Scene3D::SceneView sceneView = Scene3D::SceneView::New();
+  sceneView.SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  sceneView.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+  sceneView.SetProperty(Dali::Actor::Property::WIDTH_RESIZE_POLICY, ResizePolicy::FILL_TO_PARENT);
+  sceneView.SetProperty(Dali::Actor::Property::HEIGHT_RESIZE_POLICY, ResizePolicy::FILL_TO_PARENT);
+  application.GetScene().Add(sceneView);
+
+  Scene3D::Model model = Scene3D::Model::New(TEST_GLTF_FILE_NAME);
+  sceneView.Add(model);
+
+  Scene3D::Light light = Scene3D::Light::New();
+  light.SetProperty(Dali::Actor::Property::COLOR, Color::BLUE);
+  Dali::DevelActor::LookAt(light, Vector3(1.0f, 0.0f, 0.0f));
+  light.EnableShadow(true);
+  sceneView.Add(light);
+
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+  application.SendNotification();
+  application.Render();
+
+  // Light is added on layer when on scene
+  DALI_TEST_EQUALS(true, model.GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE), TEST_LOCATION);
+
+  Renderer renderer = model.FindChildByName("node2").GetRendererAt(0u);
+  DALI_TEST_CHECK(renderer);
+  Shader shader = renderer.GetShader();
+  DALI_TEST_CHECK(shader);
+
+  auto shadowEnabledIndex = shader.GetPropertyIndex("uIsShadowEnabled");
+  DALI_TEST_CHECK(shadowEnabledIndex != DALI_KEY_INVALID);
+  DALI_TEST_EQUALS(1, shader.GetProperty<int32_t>(shadowEnabledIndex), TEST_LOCATION);
+
+  light.EnableShadow(false);
+
+  DALI_TEST_CHECK(shadowEnabledIndex != DALI_KEY_INVALID);
+  DALI_TEST_EQUALS(0, shader.GetProperty<int32_t>(shadowEnabledIndex), TEST_LOCATION);
+
+  light.EnableShadow(true);
+
+  DALI_TEST_CHECK(shadowEnabledIndex != DALI_KEY_INVALID);
+  DALI_TEST_EQUALS(1, shader.GetProperty<int32_t>(shadowEnabledIndex), TEST_LOCATION);
+
+  light.Unparent();
+
+  DALI_TEST_CHECK(shadowEnabledIndex != DALI_KEY_INVALID);
+  DALI_TEST_EQUALS(0, shader.GetProperty<int32_t>(shadowEnabledIndex), TEST_LOCATION);
+
+  END_TEST;
+}
+
+// Disable Shadow
+int UtcDaliLightDisableShadow02(void)
+{
+  ToolkitTestApplication application;
+
+  Scene3D::SceneView sceneView = Scene3D::SceneView::New();
+  sceneView.SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  sceneView.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+  sceneView.SetProperty(Dali::Actor::Property::WIDTH_RESIZE_POLICY, ResizePolicy::FILL_TO_PARENT);
+  sceneView.SetProperty(Dali::Actor::Property::HEIGHT_RESIZE_POLICY, ResizePolicy::FILL_TO_PARENT);
+  application.GetScene().Add(sceneView);
+
+  Scene3D::Model model = Scene3D::Model::New(TEST_GLTF_FILE_NAME);
+  sceneView.Add(model);
+
+  Scene3D::Light light = Scene3D::Light::New();
+  light.SetProperty(Dali::Actor::Property::COLOR, Color::BLUE);
+  Dali::DevelActor::LookAt(light, Vector3(1.0f, 0.0f, 0.0f));
+  light.EnableShadow(true);
+  sceneView.Add(light);
+
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+  application.SendNotification();
+  application.Render();
+
+  // Light is added on layer when on scene
+  DALI_TEST_EQUALS(true, model.GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE), TEST_LOCATION);
+
+  Renderer renderer = model.FindChildByName("node2").GetRendererAt(0u);
+  DALI_TEST_CHECK(renderer);
+  Shader shader = renderer.GetShader();
+  DALI_TEST_CHECK(shader);
+
+  auto shadowEnabledIndex = shader.GetPropertyIndex("uIsShadowEnabled");
+  DALI_TEST_CHECK(shadowEnabledIndex != DALI_KEY_INVALID);
+  DALI_TEST_EQUALS(1, shader.GetProperty<int32_t>(shadowEnabledIndex), TEST_LOCATION);
+
+  light.EnableShadow(false);
+
+  DALI_TEST_CHECK(shadowEnabledIndex != DALI_KEY_INVALID);
+  DALI_TEST_EQUALS(0, shader.GetProperty<int32_t>(shadowEnabledIndex), TEST_LOCATION);
+
+  light.EnableShadow(true);
+
+  DALI_TEST_CHECK(shadowEnabledIndex != DALI_KEY_INVALID);
+  DALI_TEST_EQUALS(1, shader.GetProperty<int32_t>(shadowEnabledIndex), TEST_LOCATION);
+
+  Scene3D::Light newLight = Scene3D::Light::New();
+  newLight.SetProperty(Dali::Actor::Property::COLOR, Color::BLUE);
+  Dali::DevelActor::LookAt(newLight, Vector3(1.0f, 0.0f, 0.0f));
+  newLight.EnableShadow(true);
+  sceneView.Add(newLight);
+
+  DALI_TEST_CHECK(shadowEnabledIndex != DALI_KEY_INVALID);
+  DALI_TEST_EQUALS(1, shader.GetProperty<int32_t>(shadowEnabledIndex), TEST_LOCATION);
+
+  // Disable light's shadow, the shadow of newLight is rendered
+  light.EnableShadow(false);
+
+  DALI_TEST_CHECK(shadowEnabledIndex != DALI_KEY_INVALID);
+  DALI_TEST_EQUALS(1, shader.GetProperty<int32_t>(shadowEnabledIndex), TEST_LOCATION);
+
+  // Enable light's shadow, but newLight's shadow is rendered.
+  light.EnableShadow(true);
+
+  DALI_TEST_CHECK(shadowEnabledIndex != DALI_KEY_INVALID);
+  DALI_TEST_EQUALS(1, shader.GetProperty<int32_t>(shadowEnabledIndex), TEST_LOCATION);
+
+  // Disable newLight's shadow, light's shadow is rendered.
+  newLight.Unparent();
+
+  DALI_TEST_CHECK(shadowEnabledIndex != DALI_KEY_INVALID);
+  DALI_TEST_EQUALS(1, shader.GetProperty<int32_t>(shadowEnabledIndex), TEST_LOCATION);
+
+  // Every shadow is disabled.
+  light.Unparent();
+
+  DALI_TEST_CHECK(shadowEnabledIndex != DALI_KEY_INVALID);
+  DALI_TEST_EQUALS(0, shader.GetProperty<int32_t>(shadowEnabledIndex), TEST_LOCATION);
+
+  END_TEST;
+}
+
+// Make a light EnableShadow that is not enabled on scene
+int UtcDaliLightEnableShadowOfNotEnabledLight(void)
+{
+  ToolkitTestApplication application;
+
+  Scene3D::SceneView sceneView = Scene3D::SceneView::New();
+  sceneView.SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  sceneView.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+  sceneView.SetProperty(Dali::Actor::Property::WIDTH_RESIZE_POLICY, ResizePolicy::FILL_TO_PARENT);
+  sceneView.SetProperty(Dali::Actor::Property::HEIGHT_RESIZE_POLICY, ResizePolicy::FILL_TO_PARENT);
+  application.GetScene().Add(sceneView);
+
+  Scene3D::Model model = Scene3D::Model::New(TEST_GLTF_FILE_NAME);
+  sceneView.Add(model);
+
+  uint32_t maxLightCount = Scene3D::Light::GetMaximumEnabledLightCount();
+  std::vector<Scene3D::Light> lights;
+  for(uint32_t i = 0; i < maxLightCount; ++i)
+  {
+    Scene3D::Light light = Scene3D::Light::New();
+    light.SetProperty(Dali::Actor::Property::COLOR, Color::BLUE);
+    Dali::DevelActor::LookAt(light, Vector3(1.0f, 0.0f, 0.0f));
+    sceneView.Add(light);
+    lights.push_back(light);
+  }
+
+  Scene3D::Light shadowLight = Scene3D::Light::New();
+  shadowLight.SetProperty(Dali::Actor::Property::COLOR, Color::BLUE);
+  Dali::DevelActor::LookAt(shadowLight, Vector3(1.0f, 0.0f, 0.0f));
+  sceneView.Add(shadowLight);
+
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+  application.SendNotification();
+  application.Render();
+
+  // Light is added on layer when on scene
+  DALI_TEST_EQUALS(true, model.GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE), TEST_LOCATION);
+
+  Renderer renderer = model.FindChildByName("node2").GetRendererAt(0u);
+  DALI_TEST_CHECK(renderer);
+  Shader shader = renderer.GetShader();
+  DALI_TEST_CHECK(shader);
+
+  auto shadowEnabledIndex = shader.GetPropertyIndex("uIsShadowEnabled");
+  DALI_TEST_CHECK(shadowEnabledIndex != DALI_KEY_INVALID);
+  DALI_TEST_EQUALS(0, shader.GetProperty<int32_t>(shadowEnabledIndex), TEST_LOCATION);
+
+  shadowLight.EnableShadow(true);
+
+  DALI_TEST_CHECK(shadowEnabledIndex != DALI_KEY_INVALID);
+  DALI_TEST_EQUALS(0, shader.GetProperty<int32_t>(shadowEnabledIndex), TEST_LOCATION);
+
+  lights[0].Enable(false);
+
+  DALI_TEST_CHECK(shadowEnabledIndex != DALI_KEY_INVALID);
+  DALI_TEST_EQUALS(1, shader.GetProperty<int32_t>(shadowEnabledIndex), TEST_LOCATION);
+
+  END_TEST;
+}
+
+// Set/Get Shadow Properties
+int UtcDaliLightSetGetProperty(void)
+{
+  ToolkitTestApplication application;
+
+  Scene3D::SceneView sceneView = Scene3D::SceneView::New();
+  sceneView.SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  sceneView.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+  sceneView.SetProperty(Dali::Actor::Property::WIDTH_RESIZE_POLICY, ResizePolicy::FILL_TO_PARENT);
+  sceneView.SetProperty(Dali::Actor::Property::HEIGHT_RESIZE_POLICY, ResizePolicy::FILL_TO_PARENT);
+  application.GetScene().Add(sceneView);
+
+  Scene3D::Model model = Scene3D::Model::New(TEST_GLTF_FILE_NAME);
+  sceneView.Add(model);
+
+  Scene3D::Light light = Scene3D::Light::New();
+  light.SetProperty(Dali::Actor::Property::COLOR, Color::BLUE);
+  Dali::DevelActor::LookAt(light, Vector3(1.0f, 0.0f, 0.0f));
+  light.EnableShadow(true);
+  sceneView.Add(light);
+
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+  application.SendNotification();
+  application.Render();
+
+  // Light is added on layer when on scene
+  DALI_TEST_EQUALS(true, model.GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE), TEST_LOCATION);
+
+  DALI_TEST_EQUALS(0.001f, light.GetShadowBias(), TEST_LOCATION);
+  light.SetShadowBias(0.1f);
+  DALI_TEST_EQUALS(0.1f, light.GetShadowBias(), TEST_LOCATION);
+
+  DALI_TEST_EQUALS(0.5f, light.GetShadowIntensity(), TEST_LOCATION);
+  light.SetShadowIntensity(0.1f);
+  DALI_TEST_EQUALS(0.1f, light.GetShadowIntensity(), TEST_LOCATION);
+
+  END_TEST;
+}
+
+// Enable PCF for soft shadow edge.
+int UtcDaliLightShadowSoftFiltering(void)
+{
+  ToolkitTestApplication application;
+
+  Scene3D::SceneView sceneView = Scene3D::SceneView::New();
+  sceneView.SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+  sceneView.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+  sceneView.SetProperty(Dali::Actor::Property::WIDTH_RESIZE_POLICY, ResizePolicy::FILL_TO_PARENT);
+  sceneView.SetProperty(Dali::Actor::Property::HEIGHT_RESIZE_POLICY, ResizePolicy::FILL_TO_PARENT);
+  application.GetScene().Add(sceneView);
+
+  Scene3D::Model model = Scene3D::Model::New(TEST_GLTF_FILE_NAME);
+  sceneView.Add(model);
+
+  Scene3D::Light light = Scene3D::Light::New();
+  light.SetProperty(Dali::Actor::Property::COLOR, Color::BLUE);
+  Dali::DevelActor::LookAt(light, Vector3(1.0f, 0.0f, 0.0f));
+  light.EnableShadow(true);
+  sceneView.Add(light);
+
+  application.SendNotification();
+  application.Render();
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+  application.SendNotification();
+  application.Render();
+
+  // Light is added on layer when on scene
+  DALI_TEST_EQUALS(true, model.GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE), TEST_LOCATION);
+
+  Renderer renderer = model.FindChildByName("node2").GetRendererAt(0u);
+  DALI_TEST_CHECK(renderer);
+  Shader shader = renderer.GetShader();
+  DALI_TEST_CHECK(shader);
+
+  DALI_TEST_EQUALS(false, light.IsShadowSoftFilteringEnabled(), TEST_LOCATION);
+  auto shadowFilteringEnabledIndex = shader.GetPropertyIndex("uEnableShadowSoftFiltering");
+  DALI_TEST_CHECK(shadowFilteringEnabledIndex != DALI_KEY_INVALID);
+  DALI_TEST_EQUALS(0, shader.GetProperty<int32_t>(shadowFilteringEnabledIndex), TEST_LOCATION);
+
+  light.EnableShadowSoftFiltering(true);
+  DALI_TEST_EQUALS(true, light.IsShadowSoftFilteringEnabled(), TEST_LOCATION);
+
+  DALI_TEST_CHECK(shadowFilteringEnabledIndex != DALI_KEY_INVALID);
+  DALI_TEST_EQUALS(1, shader.GetProperty<int32_t>(shadowFilteringEnabledIndex), TEST_LOCATION);
+
+  light.EnableShadowSoftFiltering(false);
+  DALI_TEST_EQUALS(false, light.IsShadowSoftFilteringEnabled(), TEST_LOCATION);
+  DALI_TEST_CHECK(shadowFilteringEnabledIndex != DALI_KEY_INVALID);
+  DALI_TEST_EQUALS(0, shader.GetProperty<int32_t>(shadowFilteringEnabledIndex), TEST_LOCATION);
+
+  END_TEST;
+}
index 30b755d..1b898a0 100644 (file)
@@ -424,10 +424,10 @@ int UtcDaliModelSetImageBasedLightSource01(void)
   DALI_TEST_CHECK(renderer);
 
   TextureSet textureSet = renderer.GetTextures();
-  DALI_TEST_EQUALS(textureSet.GetTextureCount(), 9u, TEST_LOCATION);
+  DALI_TEST_EQUALS(textureSet.GetTextureCount(), 10u, TEST_LOCATION);
 
-  Texture diffuseTexture  = textureSet.GetTexture(7u);
-  Texture specularTexture = textureSet.GetTexture(8u);
+  Texture diffuseTexture  = textureSet.GetTexture(8u);
+  Texture specularTexture = textureSet.GetTexture(9u);
 
   gResourceReadyCalled = false;
   DALI_TEST_EQUALS(gResourceReadyCalled, false, TEST_LOCATION);
@@ -443,8 +443,8 @@ int UtcDaliModelSetImageBasedLightSource01(void)
   DALI_TEST_EQUALS(gResourceReadyCalled, true, TEST_LOCATION);
 
   TextureSet newTextureSet      = renderer.GetTextures();
-  Texture    newDiffuseTexture  = newTextureSet.GetTexture(7u);
-  Texture    newSpecularTexture = newTextureSet.GetTexture(8u);
+  Texture    newDiffuseTexture  = newTextureSet.GetTexture(8u);
+  Texture    newSpecularTexture = newTextureSet.GetTexture(9u);
 
   DALI_TEST_NOT_EQUALS(diffuseTexture, newDiffuseTexture, 0.0f, TEST_LOCATION);
   DALI_TEST_NOT_EQUALS(specularTexture, newSpecularTexture, 0.0f, TEST_LOCATION);
@@ -481,16 +481,16 @@ int UtcDaliModelSetImageBasedLightSource02(void)
   DALI_TEST_CHECK(renderer);
 
   TextureSet textureSet = renderer.GetTextures();
-  DALI_TEST_EQUALS(textureSet.GetTextureCount(), 9u, TEST_LOCATION);
+  DALI_TEST_EQUALS(textureSet.GetTextureCount(), 10u, TEST_LOCATION);
 
-  Texture diffuseTexture  = textureSet.GetTexture(7u);
-  Texture specularTexture = textureSet.GetTexture(8u);
+  Texture diffuseTexture  = textureSet.GetTexture(8u);
+  Texture specularTexture = textureSet.GetTexture(9u);
 
   // if url is empty, loading is not requested.
   model.SetImageBasedLightSource("", "");
 
-  Texture newDiffuseTexture  = textureSet.GetTexture(7u);
-  Texture newSpecularTexture = textureSet.GetTexture(8u);
+  Texture newDiffuseTexture  = textureSet.GetTexture(8u);
+  Texture newSpecularTexture = textureSet.GetTexture(9u);
 
   DALI_TEST_EQUALS(diffuseTexture, newDiffuseTexture, TEST_LOCATION);
   DALI_TEST_EQUALS(specularTexture, newSpecularTexture, TEST_LOCATION);
@@ -525,10 +525,10 @@ int UtcDaliModelSetImageBasedLightSource03(void)
   DALI_TEST_CHECK(renderer);
 
   TextureSet textureSet = renderer.GetTextures();
-  DALI_TEST_EQUALS(textureSet.GetTextureCount(), 9u, TEST_LOCATION);
+  DALI_TEST_EQUALS(textureSet.GetTextureCount(), 10u, TEST_LOCATION);
 
-  Texture diffuseTexture  = textureSet.GetTexture(7u);
-  Texture specularTexture = textureSet.GetTexture(8u);
+  Texture diffuseTexture  = textureSet.GetTexture(8u);
+  Texture specularTexture = textureSet.GetTexture(9u);
 
   gResourceReadyCalled = false;
   DALI_TEST_EQUALS(gResourceReadyCalled, false, TEST_LOCATION);
@@ -543,8 +543,8 @@ int UtcDaliModelSetImageBasedLightSource03(void)
 
   DALI_TEST_EQUALS(gResourceReadyCalled, true, TEST_LOCATION);
 
-  Texture newDiffuseTexture  = textureSet.GetTexture(7u);
-  Texture newSpecularTexture = textureSet.GetTexture(8u);
+  Texture newDiffuseTexture  = textureSet.GetTexture(8u);
+  Texture newSpecularTexture = textureSet.GetTexture(9u);
 
   DALI_TEST_EQUALS(diffuseTexture, newDiffuseTexture, TEST_LOCATION);
   DALI_TEST_EQUALS(specularTexture, newSpecularTexture, TEST_LOCATION);
@@ -1352,16 +1352,16 @@ int UtcDaliModelResourceCacheCheck(void)
   // but all the other textures are still the same
   TextureSet textureSet2 = renderer2.GetTextures();
   TextureSet textureSet3 = renderer3.GetTextures();
-  DALI_TEST_EQUALS(textureSet2.GetTextureCount(), 9u, TEST_LOCATION);
-  DALI_TEST_EQUALS(textureSet3.GetTextureCount(), 9u, TEST_LOCATION);
+  DALI_TEST_EQUALS(textureSet2.GetTextureCount(), 10u, TEST_LOCATION);
+  DALI_TEST_EQUALS(textureSet3.GetTextureCount(), 10u, TEST_LOCATION);
 
   for(uint32_t i = 0; i < 7u; i++)
   {
     DALI_TEST_EQUALS(textureSet2.GetTexture(i), textureSet3.GetTexture(i), TEST_LOCATION);
   }
 
-  DALI_TEST_NOT_EQUALS(textureSet2.GetTexture(7u), textureSet3.GetTexture(7u), 0.0f, TEST_LOCATION);
-  DALI_TEST_NOT_EQUALS(textureSet2.GetTexture(8u), textureSet3.GetTexture(8u), 0.0f, TEST_LOCATION);
+  DALI_TEST_NOT_EQUALS(textureSet2.GetTexture(8u), textureSet3.GetTexture(7u), 0.0f, TEST_LOCATION);
+  DALI_TEST_NOT_EQUALS(textureSet2.GetTexture(9u), textureSet3.GetTexture(8u), 0.0f, TEST_LOCATION);
 
   END_TEST;
 }
index b0cfeb4..d924c3a 100644 (file)
@@ -109,7 +109,7 @@ int UtcDaliPathFinderFindShortestPath0(void)
   auto navmesh = NavigationMeshFactory::CreateFromFile("resources/navmesh-test.bin");
 
   std::vector<PathFinderAlgorithm> testAlgorithms = {
-    PathFinderAlgorithm::DJIKSTRA_SHORTEST_PATH,
+    PathFinderAlgorithm::DIJKSTRA_SHORTEST_PATH,
     PathFinderAlgorithm::SPFA,
   };
 
@@ -159,7 +159,7 @@ int UtcDaliPathFinderFindShortestPath1(void)
   navmesh->SetSceneTransform(Matrix(Matrix::IDENTITY));
 
   std::vector<PathFinderAlgorithm> testAlgorithms = {
-    PathFinderAlgorithm::DJIKSTRA_SHORTEST_PATH,
+    PathFinderAlgorithm::DIJKSTRA_SHORTEST_PATH,
     PathFinderAlgorithm::SPFA,
     PathFinderAlgorithm::SPFA_DOUBLE_WAY, /* Note : Even this algorithm doesn't found shortest path, UTC will pass. */
   };
index 53e7725..ca87d38 100644 (file)
@@ -88,9 +88,9 @@ Dali::Texture GetDiffuseTexture(Dali::Scene3D::Model model)
     if(renderer)
     {
       TextureSet textureSet = renderer.GetTextures();
-      if(textureSet.GetTextureCount() == 9u)
+      if(textureSet.GetTextureCount() == 10u)
       {
-        texture = textureSet.GetTexture(7u);
+        texture = textureSet.GetTexture(8u);
       }
     }
   }
@@ -109,9 +109,9 @@ Dali::Texture GetSpecularTexture(Dali::Scene3D::Model model)
     if(renderer)
     {
       TextureSet textureSet = renderer.GetTextures();
-      if(textureSet.GetTextureCount() == 9u)
+      if(textureSet.GetTextureCount() == 10u)
       {
-        texture = textureSet.GetTexture(8u);
+        texture = textureSet.GetTexture(9u);
       }
     }
   }
@@ -327,9 +327,9 @@ int UtcDaliSceneViewOnScene02(void)
   application.Render();
 
   renderTaskCount = application.GetScene().GetRenderTaskList().GetTaskCount();
-  DALI_TEST_EQUALS(2u, renderTaskCount, TEST_LOCATION);
+  DALI_TEST_EQUALS(3u, renderTaskCount, TEST_LOCATION);
 
-  RenderTask  renderTask = application.GetScene().GetRenderTaskList().GetTask(1u);
+  RenderTask  renderTask = application.GetScene().GetRenderTaskList().GetTask(2u);
   CameraActor camera     = renderTask.GetCameraActor();
 
   CameraActor defaultCamera = renderTask.GetCameraActor();
@@ -693,7 +693,7 @@ int UtcDaliSceneViewUseFramebuffer02(void)
   application.SendNotification();
   application.Render();
 
-  RenderTask renderTask = application.GetScene().GetRenderTaskList().GetTask(1u);
+  RenderTask renderTask = application.GetScene().GetRenderTaskList().GetTask(2u);
   DALI_TEST_CHECK(!renderTask.GetFrameBuffer());
 
   view.UseFramebuffer(true);
@@ -1005,7 +1005,7 @@ int UtcDaliSceneViewCreateAndRemoveRenderTask(void)
 
   application.GetScene().Add(view);
 
-  DALI_TEST_EQUALS(renderTaskCount + 1, application.GetScene().GetRenderTaskList().GetTaskCount(), TEST_LOCATION);
+  DALI_TEST_EQUALS(renderTaskCount + 2, application.GetScene().GetRenderTaskList().GetTaskCount(), TEST_LOCATION);
 
   view.Unparent();
 
index 6a5a089..732d6b1 100644 (file)
@@ -2126,3 +2126,153 @@ int UtcDaliAnimatedVectorImageVisualDesiredSize(void)
 
   END_TEST;
 }
+
+int UtcDaliAnimatedVectorImageVisualFlushAction(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline("UtcDaliAnimatedVectorImageVisualFlushAction");
+
+  int startFrame = 1;
+  int endFrame   = 2;
+
+  int totalFrameCount = 0;
+
+  Property::Array playRange;
+  playRange.PushBack(startFrame);
+  playRange.PushBack(endFrame);
+
+  Property::Map    resultMap;
+  Property::Value* value = nullptr;
+
+  // request AnimatedVectorImageVisual with a property map
+  VisualFactory factory = VisualFactory::Get();
+  Visual::Base  visual  = factory.CreateVisual(
+    Property::Map()
+      .Add(Toolkit::Visual::Property::TYPE, DevelVisual::ANIMATED_VECTOR_IMAGE)
+      .Add(ImageVisual::Property::URL, TEST_VECTOR_IMAGE_FILE_NAME)
+      .Add(DevelImageVisual::Property::PLAY_RANGE, playRange)
+      .Add(ImageVisual::Property::SYNCHRONOUS_LOADING, true));
+
+  DummyControl        dummyControl = DummyControl::New(true);
+  Impl::DummyControl& dummyImpl    = static_cast<Impl::DummyControl&>(dummyControl.GetImplementation());
+  dummyImpl.RegisterVisual(DummyControl::Property::TEST_VISUAL, visual);
+  dummyControl.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
+
+  application.GetScene().Add(dummyControl);
+
+  // Retry function to get playrange until expect values comes.
+  auto CheckAndRetryPlayRange = [&](int expectStartFrame, int expectEndFrame, std::vector<std::pair<int, int>> retrialFrames) {
+    int tryCount    = 0;
+    int tryCountMax = 30;
+    while(++tryCount <= tryCountMax)
+    {
+      Property::Map resultMap = dummyControl.GetProperty<Property::Map>(DummyControl::Property::TEST_VISUAL);
+
+      Property::Value* value = resultMap.Find(DevelImageVisual::Property::PLAY_RANGE, Property::ARRAY);
+      DALI_TEST_CHECK(value);
+
+      Property::Array* result = value->GetArray();
+      DALI_TEST_CHECK(result);
+      DALI_TEST_EQUALS(result->Count(), 2, TEST_LOCATION);
+
+      bool tryAgain = false;
+      for(auto& framePair : retrialFrames)
+      {
+        if(result->GetElementAt(0).Get<int>() == framePair.first && result->GetElementAt(1).Get<int>() == framePair.second)
+        {
+          tryAgain = true;
+          break;
+        }
+      }
+      if(tryAgain)
+      {
+        tet_printf("Retry to get value again! [%d]\n", tryCount);
+        // Dummy sleep 1 second.
+        Test::WaitForEventThreadTrigger(1, 1);
+        continue;
+      }
+
+      DALI_TEST_EQUALS(result->GetElementAt(0).Get<int>(), expectStartFrame, TEST_LOCATION);
+      DALI_TEST_EQUALS(result->GetElementAt(1).Get<int>(), expectEndFrame, TEST_LOCATION);
+      break;
+    }
+    DALI_TEST_CHECK(tryCount <= tryCountMax);
+  };
+
+  tet_printf("Pause lottie first.\n");
+
+  Property::Map attributes;
+  DevelControl::DoAction(dummyControl, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PAUSE, attributes);
+
+  application.SendNotification();
+  application.Render(16);
+
+  do
+  {
+    resultMap = dummyControl.GetProperty<Property::Map>(DummyControl::Property::TEST_VISUAL);
+
+    value = resultMap.Find(DevelImageVisual::Property::TOTAL_FRAME_NUMBER, Property::INTEGER);
+    DALI_TEST_CHECK(value);
+    totalFrameCount = value->Get<int>();
+  } while(totalFrameCount == 0);
+
+  // Ensure that vector data sended well.
+  CheckAndRetryPlayRange(startFrame, endFrame, {{0, 0}, {0, totalFrameCount - 1}});
+
+  resultMap = dummyControl.GetProperty<Property::Map>(DummyControl::Property::TEST_VISUAL);
+
+  value = resultMap.Find(DevelImageVisual::Property::CURRENT_FRAME_NUMBER, Property::INTEGER);
+  DALI_TEST_CHECK(value);
+  DALI_TEST_EQUALS(value->Get<int>(), startFrame, TEST_LOCATION);
+
+  tet_printf("Now logically, range : [%d~%d], current : %d\n", startFrame, endFrame, startFrame);
+
+  int changedStartFrame1 = startFrame + 2;
+  int changedEndFrame1   = endFrame + 2;
+
+  playRange.Clear();
+  playRange.Add(changedStartFrame1);
+  playRange.Add(changedEndFrame1);
+
+  tet_printf("Change play range\n");
+  attributes.Add(DevelImageVisual::Property::PLAY_RANGE, playRange);
+  DevelControl::DoAction(dummyControl, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelVisual::Action::UPDATE_PROPERTY, attributes);
+
+  tet_printf("Jump to changedEndFrame!\n");
+  DevelControl::DoAction(dummyControl, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::JUMP_TO, changedEndFrame1);
+
+  attributes.Clear();
+  tet_infoline("Flush Action!");
+  tet_printf("Now logically, range : [%d~%d], current : %d\n", changedStartFrame1, changedEndFrame1, changedEndFrame1);
+  DevelControl::DoAction(dummyControl, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::FLUSH, attributes);
+
+  int changedStartFrame2 = startFrame + 1;
+  int changedEndFrame2   = endFrame + 1;
+
+  playRange.Clear();
+  playRange.Add(changedStartFrame2);
+  playRange.Add(changedEndFrame2);
+
+  tet_printf("Change play range again\n");
+  tet_printf("Now logically, range : [%d~%d], current : %d\n", changedStartFrame2, changedEndFrame2, changedEndFrame2);
+  attributes.Add(DevelImageVisual::Property::PLAY_RANGE, playRange);
+  DevelControl::DoAction(dummyControl, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelVisual::Action::UPDATE_PROPERTY, attributes);
+
+  application.SendNotification();
+  application.Render(16);
+
+  // Ensure that vector data sended well.
+  CheckAndRetryPlayRange(changedStartFrame2, changedEndFrame2, {{changedStartFrame1, changedEndFrame1}, {startFrame, endFrame}});
+
+  resultMap = dummyControl.GetProperty<Property::Map>(DummyControl::Property::TEST_VISUAL);
+
+  tet_printf("Test whether current frame number changed well. If Flush not works, current frame become startFrame.");
+  value = resultMap.Find(DevelImageVisual::Property::CURRENT_FRAME_NUMBER, Property::INTEGER);
+  DALI_TEST_CHECK(value);
+  DALI_TEST_EQUALS(value->Get<int>(), changedEndFrame2, TEST_LOCATION);
+
+  dummyControl.Unparent();
+
+  END_TEST;
+}
\ No newline at end of file
index 4767977..e6451bc 100644 (file)
@@ -77,6 +77,23 @@ int UtcDaliImageConvertFrameBufferToUrl2(void)
   END_TEST;
 }
 
+int UtcDaliImageConvertDepthTextureFrameBufferToUrl(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliImageConvertDepthTextureFrameBufferToUrl");
+
+  unsigned int width(64);
+  unsigned int height(64);
+  FrameBuffer  frameBuffer = FrameBuffer::New(width, height, FrameBuffer::Attachment::NONE);
+
+  Texture texture = Texture::New(TextureType::TEXTURE_2D, Pixel::DEPTH_UNSIGNED_INT, width, height);
+  DevelFrameBuffer::AttachDepthTexture(frameBuffer, texture);
+
+  DALI_TEST_CHECK(Dali::Toolkit::Image::GenerateDepthUrl(frameBuffer).GetUrl().size() > 0u);
+
+  END_TEST;
+}
+
 int UtcDaliImageConvertPixelDataToUrl01(void)
 {
   ToolkitTestApplication application;
  */
 
 // CLASS HEADER
-#include <dali-scene3d/internal/algorithm/path-finder-djikstra.h>
+#include <dali-scene3d/internal/algorithm/path-finder-dijkstra.h>
 
 // EXTERNAL INCLUDES
 #include <dali/public-api/common/vector-wrapper.h>
 #include <limits>
+#include <algorithm> ///< for std::priority_queue
+#include <queue>     ///< for std::priority_queue
 
 // INTERNAL INCLUDES
 #include <dali-scene3d/internal/algorithm/path-finder-waypoint-data.h>
 
 using WayPointList = Dali::Scene3D::Algorithm::WayPointList;
 
+namespace
+{
+struct DijkstraComparer
+{
+  float                               distance{-1.0f};
+  Dali::Scene3D::Algorithm::FaceIndex index{Dali::Scene3D::Algorithm::NavigationMesh::NULL_FACE};
+
+  /**
+   * @brief Custom operator for Dijkstra comparer.
+   *
+   * @param[in] rhs Target to be compared.
+   * @return True if this has less priority than rhs.
+   */
+  bool operator<(const DijkstraComparer& rhs) const
+  {
+    // Shorter distance have higher prioirty.
+    return distance > rhs.distance;
+  }
+};
+} // namespace
+
 namespace Dali::Scene3D::Internal::Algorithm
 {
-PathFinderAlgorithmDjikstra::PathFinderAlgorithmDjikstra(Dali::Scene3D::Algorithm::NavigationMesh& navMesh)
+PathFinderAlgorithmDijkstra::PathFinderAlgorithmDijkstra(Dali::Scene3D::Algorithm::NavigationMesh& navMesh)
 : mNavigationMesh(&GetImplementation(navMesh))
 {
   PrepareData();
 }
 
-PathFinderAlgorithmDjikstra::~PathFinderAlgorithmDjikstra() = default;
+PathFinderAlgorithmDijkstra::~PathFinderAlgorithmDijkstra() = default;
 
-Scene3D::Algorithm::WayPointList PathFinderAlgorithmDjikstra::FindPath(const Dali::Vector3& positionFrom, const Dali::Vector3& positionTo)
+Scene3D::Algorithm::WayPointList PathFinderAlgorithmDijkstra::FindPath(const Dali::Vector3& positionFrom, const Dali::Vector3& positionTo)
 {
   Dali::Vector3 outPosFrom;
   FaceIndex     polyIndexFrom;
@@ -56,18 +79,20 @@ Scene3D::Algorithm::WayPointList PathFinderAlgorithmDjikstra::FindPath(const Dal
       // Get waypoints
       waypoints = FindPath(polyIndexFrom, polyIndexTo);
 
-      // replace first and last waypoint
-      auto& wpFrom = static_cast<WayPointData&>(waypoints[0]);
-      auto& wpTo   = static_cast<WayPointData&>(waypoints.back());
+      if(!waypoints.empty())
+      {
+        // replace first and last waypoint
+        auto& wpFrom = static_cast<WayPointData&>(waypoints[0]);
+        auto& wpTo   = static_cast<WayPointData&>(waypoints.back());
 
-      Vector2 fromCenter(wpFrom.point3d.x, wpFrom.point3d.y);
-      wpFrom.point3d = outPosFrom;
-      wpFrom.point2d = fromCenter - Vector2(outPosFrom.x, outPosFrom.y);
+        Vector2 fromCenter(wpFrom.point3d.x, wpFrom.point3d.y);
+        wpFrom.point3d = outPosFrom;
+        wpFrom.point2d = fromCenter - Vector2(outPosFrom.x, outPosFrom.y);
 
-      Vector2 toCenter(wpTo.point3d.x, wpTo.point3d.y);
-      wpTo.point3d = outPosTo;
-      wpTo.point2d = toCenter - Vector2(outPosTo.x, outPosTo.y);
-      wpTo.point3d = outPosTo;
+        Vector2 toCenter(wpTo.point3d.x, wpTo.point3d.y);
+        wpTo.point3d = outPosTo;
+        wpTo.point2d = toCenter - Vector2(outPosTo.x, outPosTo.y);
+      }
     }
   }
 
@@ -75,85 +100,78 @@ Scene3D::Algorithm::WayPointList PathFinderAlgorithmDjikstra::FindPath(const Dal
   return waypoints;
 }
 
-Scene3D::Algorithm::WayPointList PathFinderAlgorithmDjikstra::FindPath(FaceIndex sourcePolyIndex, FaceIndex targetPolyIndex)
+Scene3D::Algorithm::WayPointList PathFinderAlgorithmDijkstra::FindPath(FaceIndex sourcePolyIndex, FaceIndex targetPolyIndex)
 {
   auto                   nodeCount = uint32_t(mNodes.size());
   std::vector<float>     dist;
   std::vector<FaceIndex> prev;
+  std::vector<bool>      faceVisited;
+
+  std::priority_queue<DijkstraComparer> priorityDistanceHeap;
 
   dist.resize(mNodes.size());
   prev.resize(mNodes.size());
 
-  std::vector<FaceNode*> nodeQueue;
-  nodeQueue.reserve(nodeCount);
-
-  [[maybe_unused]] auto sourcePos = Dali::Vector3(Face(sourcePolyIndex)->center);
+  faceVisited.resize(nodeCount);
 
   for(auto i = 0u; i < nodeCount; ++i)
   {
     dist[i] = std::numeric_limits<float>::infinity();
     prev[i] = Scene3D::Algorithm::NavigationMesh::NULL_FACE; // set prev to null polygon
-    nodeQueue.emplace_back(&mNodes[i]);
+    faceVisited[i] = false;
   }
-  auto removeCount = 0u;
 
   // Set distance of source
   dist[sourcePolyIndex] = 0.0f;
 
-  // TO OPTIMIZE WITH PRIORITY QUEUE
-  auto FindMinDistance = [&nodeQueue](decltype(dist)& dist) {
-    float w     = std::numeric_limits<float>::max();
-    int   index = -1;
-    for(auto i = 0u; i < dist.size(); ++i)
-    {
-      // skip infinity
-      if(nodeQueue[i] && dist[i] != std::numeric_limits<float>::infinity() && dist[i] < w)
-      {
-        w     = dist[i];
-        index = int(i);
-      }
-    }
-    return index;
-  };
+  priorityDistanceHeap.push({dist[sourcePolyIndex], sourcePolyIndex});
 
-  do
+  while(!priorityDistanceHeap.empty())
   {
-    // find minimum distance
-    auto minDistIndex = FindMinDistance(dist);
+    // find minimum distance index
+    auto comparer = priorityDistanceHeap.top();
+    priorityDistanceHeap.pop();
 
-    // Failed to find minimum distance
-    if(minDistIndex == -1)
-    {
-      // Return empty WayPointList
-      return {};
-    }
+    auto  minDistanceIndex = comparer.index;
 
-    // remove from queue by assigning infinity to distance
-    removeCount++;
-    if(removeCount == nodeCount)
+    // Old item. just ignore.
+    if(faceVisited[minDistanceIndex])
     {
       continue;
     }
 
-    nodeQueue[minDistIndex] = nullptr;
+    faceVisited[minDistanceIndex] = true;
 
-    [[maybe_unused]] auto sizeTmp = nodeQueue.size() - removeCount;
+    // Fast break if we found solution.
+    if(minDistanceIndex == targetPolyIndex)
+    {
+      break;
+    }
 
     // check the neighbours
     for(auto i = 0u; i < 3; ++i)
     {
-      auto nIndex = mNodes[minDistIndex].faces[i];
-      if(nIndex != Scene3D::Algorithm::NavigationMesh::NULL_FACE && nodeQueue[nIndex] != nullptr)
+      auto nIndex = mNodes[minDistanceIndex].faces[i];
+      if(nIndex != Scene3D::Algorithm::NavigationMesh::NULL_FACE && !faceVisited[nIndex])
       {
-        auto alt = dist[minDistIndex] + mNodes[minDistIndex].weight[i];
+        auto alt = dist[minDistanceIndex] + mNodes[minDistanceIndex].weight[i];
         if(alt < dist[nIndex])
         {
           dist[nIndex] = alt;
-          prev[nIndex] = minDistIndex;
+          prev[nIndex] = minDistanceIndex;
+
+          priorityDistanceHeap.push({dist[nIndex], nIndex});
         }
       }
     }
-  } while(removeCount != nodeCount);
+  }
+
+  // Failed to find minimum distance
+  if(!faceVisited[targetPolyIndex])
+  {
+    // Return empty WayPointList
+    return {};
+  }
 
   // Compute distances for each node back to the source
   auto                 u = targetPolyIndex;
@@ -200,7 +218,7 @@ Scene3D::Algorithm::WayPointList PathFinderAlgorithmDjikstra::FindPath(FaceIndex
   return OptimizeWaypoints(waypoints);
 }
 
-void PathFinderAlgorithmDjikstra::PrepareData()
+void PathFinderAlgorithmDijkstra::PrepareData()
 {
   // Build the list structure connecting the nodes
   auto faceCount = mNavigationMesh->GetFaceCount();
@@ -245,7 +263,7 @@ void PathFinderAlgorithmDjikstra::PrepareData()
   return ccw(A, C, D) != ccw(B, C, D) && ccw(A, B, C) != ccw(A, B, D);
 }
 
-Scene3D::Algorithm::WayPointList PathFinderAlgorithmDjikstra::OptimizeWaypoints(WayPointList& waypoints) const
+Scene3D::Algorithm::WayPointList PathFinderAlgorithmDijkstra::OptimizeWaypoints(WayPointList& waypoints) const
 {
   WayPointList optimizedWaypoints;
   optimizedWaypoints.emplace_back(waypoints[0]);
@@ -1,5 +1,5 @@
-#ifndef DALI_SCENE3D_INTERNAL_PATH_FINDER_DJIKSTRA_H
-#define DALI_SCENE3D_INTERNAL_PATH_FINDER_DJIKSTRA_H
+#ifndef DALI_SCENE3D_INTERNAL_PATH_FINDER_DIJKSTRA_H
+#define DALI_SCENE3D_INTERNAL_PATH_FINDER_DIJKSTRA_H
 
 /*
  * Copyright (c) 2023 Samsung Electronics Co., Ltd.
@@ -23,7 +23,7 @@
 
 namespace Dali::Scene3D::Internal::Algorithm
 {
-class PathFinderAlgorithmDjikstra : public Dali::Scene3D::Algorithm::PathFinderBase
+class PathFinderAlgorithmDijkstra : public Dali::Scene3D::Algorithm::PathFinderBase
 {
 public:
   /**
@@ -31,12 +31,12 @@ public:
    *
    * @param[in] navMesh Navigation mesh to associate with the algorithm
    */
-  explicit PathFinderAlgorithmDjikstra(Dali::Scene3D::Algorithm::NavigationMesh& navMesh);
+  explicit PathFinderAlgorithmDijkstra(Dali::Scene3D::Algorithm::NavigationMesh& navMesh);
 
   /**
    * @brief Destructor
    */
-  ~PathFinderAlgorithmDjikstra() override;
+  ~PathFinderAlgorithmDijkstra() override;
 
   /**
    * @brief Looks for a path from point A to point B.
@@ -85,4 +85,4 @@ public:
   std::vector<FaceNode> mNodes;          ///< List of nodes
 };
 } // namespace Dali::Scene3D::Internal::Algorithm
-#endif // DALI_SCENE3D_INTERNAL_PATH_FINDER_DJIKSTRA_H
+#endif // DALI_SCENE3D_INTERNAL_PATH_FINDER_DIJKSTRA_H
index 0eb29a3..53ab038 100644 (file)
@@ -118,18 +118,20 @@ Scene3D::Algorithm::WayPointList PathFinderAlgorithmSPFADoubleWay::FindPath(cons
       // Get waypoints
       waypoints = FindPath(polyIndexFrom, polyIndexTo);
 
-      // replace first and last waypoint
-      auto& wpFrom = static_cast<WayPointData&>(waypoints[0]);
-      auto& wpTo   = static_cast<WayPointData&>(waypoints.back());
-
-      Vector2 fromCenter(wpFrom.point3d.x, wpFrom.point3d.y);
-      wpFrom.point3d = outPosFrom;
-      wpFrom.point2d = fromCenter - Vector2(outPosFrom.x, outPosFrom.y);
-
-      Vector2 toCenter(wpTo.point3d.x, wpTo.point3d.y);
-      wpTo.point3d = outPosTo;
-      wpTo.point2d = toCenter - Vector2(outPosTo.x, outPosTo.y);
-      wpTo.point3d = outPosTo;
+      if(!waypoints.empty())
+      {
+        // replace first and last waypoint
+        auto& wpFrom = static_cast<WayPointData&>(waypoints[0]);
+        auto& wpTo   = static_cast<WayPointData&>(waypoints.back());
+
+        Vector2 fromCenter(wpFrom.point3d.x, wpFrom.point3d.y);
+        wpFrom.point3d = outPosFrom;
+        wpFrom.point2d = fromCenter - Vector2(outPosFrom.x, outPosFrom.y);
+
+        Vector2 toCenter(wpTo.point3d.x, wpTo.point3d.y);
+        wpTo.point3d = outPosTo;
+        wpTo.point2d = toCenter - Vector2(outPosTo.x, outPosTo.y);
+      }
     }
   }
 
index c6b1d48..02f308e 100644 (file)
@@ -56,18 +56,20 @@ Scene3D::Algorithm::WayPointList PathFinderAlgorithmSPFA::FindPath(const Dali::V
       // Get waypoints
       waypoints = FindPath(polyIndexFrom, polyIndexTo);
 
-      // replace first and last waypoint
-      auto& wpFrom = static_cast<WayPointData&>(waypoints[0]);
-      auto& wpTo   = static_cast<WayPointData&>(waypoints.back());
-
-      Vector2 fromCenter(wpFrom.point3d.x, wpFrom.point3d.y);
-      wpFrom.point3d = outPosFrom;
-      wpFrom.point2d = fromCenter - Vector2(outPosFrom.x, outPosFrom.y);
-
-      Vector2 toCenter(wpTo.point3d.x, wpTo.point3d.y);
-      wpTo.point3d = outPosTo;
-      wpTo.point2d = toCenter - Vector2(outPosTo.x, outPosTo.y);
-      wpTo.point3d = outPosTo;
+      if(!waypoints.empty())
+      {
+        // replace first and last waypoint
+        auto& wpFrom = static_cast<WayPointData&>(waypoints[0]);
+        auto& wpTo   = static_cast<WayPointData&>(waypoints.back());
+
+        Vector2 fromCenter(wpFrom.point3d.x, wpFrom.point3d.y);
+        wpFrom.point3d = outPosFrom;
+        wpFrom.point2d = fromCenter - Vector2(outPosFrom.x, outPosFrom.y);
+
+        Vector2 toCenter(wpTo.point3d.x, wpTo.point3d.y);
+        wpTo.point3d = outPosTo;
+        wpTo.point2d = toCenter - Vector2(outPosTo.x, outPosTo.y);
+      }
     }
   }
 
index 608e100..eb98c90 100644 (file)
@@ -60,6 +60,13 @@ public:
    * @param[in] scaleFactor scale factor that controls light source intensity in [0.0f, 1.0f].
    */
   virtual void NotifyImageBasedLightScaleFactor(float scaleFactor) = 0;
+
+  /**
+   * @brief Notifies Shadow Map texture is changed by parent SceneView.
+   *
+   * @param[in] shadowMapTexture Shadow Map texture that will be used to compute shadow.
+   */
+  virtual void NotifyShadowMapTexture(Dali::Texture shadowMapTexture) = 0;
 };
 
 } // namespace Internal
index 1feb6b5..2763de6 100644 (file)
@@ -213,6 +213,26 @@ void UpdateShaderRecursively(Scene3D::ModelNode node, Scene3D::Loader::ShaderMan
   }
 }
 
+void UpdateShadowMapTextureRecursively(Scene3D::ModelNode node, Dali::Texture shadowMapTexture)
+{
+  if(!node)
+  {
+    return;
+  }
+
+  GetImplementation(node).SetShadowMapTexture(shadowMapTexture);
+
+  uint32_t childrenCount = node.GetChildCount();
+  for(uint32_t i = 0; i < childrenCount; ++i)
+  {
+    Scene3D::ModelNode childNode = Scene3D::ModelNode::DownCast(node.GetChildAt(i));
+    if(childNode)
+    {
+      UpdateShadowMapTextureRecursively(childNode, shadowMapTexture);
+    }
+  }
+}
+
 } // anonymous namespace
 
 Model::Model(const std::string& modelUrl, const std::string& resourceDirectoryUrl)
@@ -280,6 +300,11 @@ void Model::AddModelNode(Scene3D::ModelNode modelNode)
 
   UpdateShaderRecursively(modelNode, mShaderManager);
 
+  if(mShadowMapTexture)
+  {
+    UpdateShadowMapTextureRecursively(modelNode, mShadowMapTexture);
+  }
+
   if(mIblDiffuseResourceReady && mIblSpecularResourceReady)
   {
     UpdateImageBasedLightTexture();
@@ -1007,6 +1032,15 @@ void Model::ApplyCameraTransform(Dali::CameraActor camera) const
   camera.SetProperty(Actor::Property::SCALE, resultScale);
 }
 
+void Model::NotifyShadowMapTexture(Dali::Texture shadowMapTexture)
+{
+  if(mShadowMapTexture != shadowMapTexture)
+  {
+    mShadowMapTexture = shadowMapTexture;
+    UpdateShadowMapTextureRecursively(mModelRoot, mShadowMapTexture);
+  }
+}
+
 void Model::NotifyImageBasedLightTexture(Dali::Texture diffuseTexture, Dali::Texture specularTexture, float scaleFactor, uint32_t specularMipmapLevels)
 {
   if(mSceneDiffuseTexture != diffuseTexture || mSceneSpecularTexture != specularTexture)
@@ -1062,6 +1096,10 @@ void Model::OnModelLoadComplete()
     mDefaultSpecularTexture = resources.mEnvironmentMaps.front().second.mSpecular;
   }
 
+  if(mShadowMapTexture)
+  {
+    UpdateShadowMapTextureRecursively(mModelRoot, mShadowMapTexture);
+  }
   UpdateImageBasedLightTexture();
   UpdateImageBasedLightScaleFactor();
   Self().SetProperty(Dali::Actor::Property::ANCHOR_POINT, Vector3(mModelPivot.x, 1.0f - mModelPivot.y, mModelPivot.z));
index 23337a4..b740da4 100644 (file)
@@ -272,6 +272,11 @@ private:
 
 public: // Overrides LightObserver Methods.
   /**
+   * @copydoc Dali::Scene3D::Internal::LightObserver::NotifyShadowMapTexture()
+   */
+  void NotifyShadowMapTexture(Dali::Texture shadowMapTexture) override;
+
+  /**
    * @copydoc Dali::Scene3D::Internal::LightObserver::NotifyImageBasedLightTexture()
    */
   void NotifyImageBasedLightTexture(Dali::Texture diffuseTexture, Dali::Texture specularTexture, float scaleFactor, uint32_t specularMipmapLevels) override;
@@ -361,6 +366,9 @@ private:
   EnvironmentMapLoadTaskPtr mIblDiffuseLoadTask;
   EnvironmentMapLoadTaskPtr mIblSpecularLoadTask;
 
+  // Shadow
+  Dali::Texture mShadowMapTexture;
+
   std::string mDiffuseIblUrl;
   std::string mSpecularIblUrl;
 
index b4bd19d..0c377cc 100644 (file)
@@ -62,9 +62,10 @@ BaseHandle Create()
 DALI_TYPE_REGISTRATION_BEGIN(Scene3D::SceneView, Toolkit::Control, Create);
 DALI_TYPE_REGISTRATION_END()
 
-Property::Index   RENDERING_BUFFER    = Dali::Toolkit::Control::CONTROL_PROPERTY_END_INDEX + 1;
-constexpr int32_t DEFAULT_ORIENTATION = 0;
-constexpr int32_t INVALID_INDEX       = -1;
+Property::Index    RENDERING_BUFFER        = Dali::Toolkit::Control::CONTROL_PROPERTY_END_INDEX + 1;
+constexpr int32_t  DEFAULT_ORIENTATION     = 0;
+constexpr int32_t  INVALID_INDEX           = -1;
+constexpr uint32_t MAXIMUM_SIZE_SHADOW_MAP = 2048;
 
 static constexpr std::string_view SKYBOX_INTENSITY_STRING = "uIntensity";
 
@@ -148,6 +149,143 @@ Dali::Actor CreateSkybox()
   return skyboxActor;
 }
 
+void SetShadowLightConstraint(Dali::CameraActor selectedCamera, Dali::CameraActor shadowLightCamera)
+{
+  shadowLightCamera.SetProperty(Dali::CameraActor::Property::ASPECT_RATIO, 1.0f);
+
+  shadowLightCamera.SetProperty(Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE, 1.0f);
+  shadowLightCamera.SetProperty(Dali::CameraActor::Property::NEAR_PLANE_DISTANCE, 0.5f);
+  shadowLightCamera.SetProperty(Dali::CameraActor::Property::FAR_PLANE_DISTANCE, 3.5f);
+
+  //< Make constraint for above properties.
+  shadowLightCamera.RemoveConstraints();
+
+  // Compute View Matrix of ShadowLightCamera
+  // Input : ShadowLightCamera's world position, world orientation
+  auto       tempViewMatrixIndex  = shadowLightCamera.RegisterProperty("tempViewMatrix", Matrix::IDENTITY);
+  Constraint viewMatrixConstraint = Constraint::New<Matrix>(shadowLightCamera, tempViewMatrixIndex, [](Matrix& output, const PropertyInputContainer& inputs)
+                                                            {
+                                                              output = inputs[0]->GetMatrix();
+                                                              output.Invert(); });
+  viewMatrixConstraint.AddSource(Source{shadowLightCamera, Dali::Actor::Property::WORLD_MATRIX});
+  viewMatrixConstraint.ApplyPost();
+
+  // Compute Orthographic Size / Near / Far and store it to "TempCameraProperty" property that is a Vector3 property
+  auto       tempProjectionMatrixIndex  = shadowLightCamera.RegisterProperty("tempProjectionMatrix", Matrix::IDENTITY);
+  Constraint projectionMatrixConstraint = Constraint::New<Matrix>(shadowLightCamera, tempProjectionMatrixIndex, [](Matrix& output, const PropertyInputContainer& inputs)
+                                                                  {
+                                                                    Matrix worldMatrix = inputs[0]->GetMatrix();
+                                                                    float tangentFov_2 = tanf(inputs[4]->GetFloat());
+                                                                    float  nearDistance = inputs[5]->GetFloat();
+                                                                    float  farDistance  = inputs[6]->GetFloat();
+                                                                    float  aspectRatio  = inputs[7]->GetFloat();
+                                                                    float  nearY        = 0.0f;
+                                                                    float  nearX        = 0.0f;
+                                                                    float  farY         = 0.0f;
+                                                                    float  farX         = 0.0f;
+                                                                    if(inputs[1]->GetInteger() == Dali::Camera::ProjectionMode::PERSPECTIVE_PROJECTION)
+                                                                    {
+                                                                      if(inputs[2]->GetInteger() == Dali::DevelCameraActor::ProjectionDirection::VERTICAL)
+                                                                      {
+                                                                        nearY = tangentFov_2 * nearDistance;
+                                                                        nearX = nearY * aspectRatio;
+                                                                        farY  = tangentFov_2 * farDistance;
+                                                                        farX  = farY * aspectRatio;
+                                                                      }
+                                                                      else
+                                                                      {
+                                                                        nearX = tangentFov_2 * nearDistance;
+                                                                        nearY = nearX / aspectRatio;
+                                                                        farX  = tangentFov_2 * farDistance;
+                                                                        farY  = farX / aspectRatio;
+                                                                      }
+                                                                    }
+                                                                    else
+                                                                    {
+                                                                      if(inputs[2]->GetInteger() == Dali::DevelCameraActor::ProjectionDirection::VERTICAL)
+                                                                      {
+                                                                        nearY = inputs[3]->GetFloat();
+                                                                        nearX = nearY * aspectRatio;
+                                                                      }
+                                                                      else
+                                                                      {
+                                                                        nearX = inputs[3]->GetFloat();
+                                                                        nearY = nearX / aspectRatio;
+                                                                      }
+                                                                      farX = nearX;
+                                                                      farY = nearY;
+                                                                    }
+
+                                                                    std::vector<Vector4> points;
+                                                                    points.push_back(Vector4(nearX, nearY, nearDistance, 1.0f));
+                                                                    points.push_back(Vector4(-nearX, nearY, nearDistance, 1.0f));
+                                                                    points.push_back(Vector4(-nearX, -nearY, nearDistance, 1.0f));
+                                                                    points.push_back(Vector4(nearX, -nearY, nearDistance, 1.0f));
+                                                                    points.push_back(Vector4(farX, farY, farDistance, 1.0f));
+                                                                    points.push_back(Vector4(-farX, farY, farDistance, 1.0f));
+                                                                    points.push_back(Vector4(-farX, -farY, farDistance, 1.0f));
+                                                                    points.push_back(Vector4(farX, -farY, farDistance, 1.0f));
+
+                                                                    Vector3 areaMin = Vector3::ONE * MAXFLOAT, areaMax = Vector3::ONE * -MAXFLOAT;
+                                                                    for(auto&& point : points)
+                                                                    {
+                                                                      Vector4 pointW = worldMatrix * point;
+                                                                      Vector4 pointV = inputs[8]->GetMatrix() * pointW;
+                                                                      areaMin.x      = std::min(areaMin.x, pointV.x);
+                                                                      areaMin.y      = std::min(areaMin.y, pointV.y);
+                                                                      areaMin.z      = std::min(areaMin.z, pointV.z);
+                                                                      areaMax.x      = std::max(areaMax.x, pointV.x);
+                                                                      areaMax.y      = std::max(areaMax.y, pointV.y);
+                                                                      areaMax.z      = std::max(areaMax.z, pointV.z);
+                                                                    }
+
+                                                                    Vector2 center        = Vector2(areaMax + areaMin) / 2.0f;
+                                                                    float   delta         = std::max(std::abs(areaMax.x - areaMin.x), std::abs(areaMax.y - areaMin.y));
+                                                                    float   delta_2       = delta * 0.5f;
+                                                                    Vector2 squareAreaMin = center - Vector2::ONE * delta_2;
+                                                                    Vector2 squareAreaMax = center + Vector2::ONE * delta_2;
+                                                                    float   deltaZ        = areaMax.z - areaMin.z;
+
+                                                                    float right  = -squareAreaMin.x;
+                                                                    float left   = -squareAreaMax.x;
+                                                                    float top    = squareAreaMin.y;
+                                                                    float bottom = squareAreaMax.y;
+                                                                    float near   = areaMin.z;
+                                                                    float far    = areaMax.z;
+
+                                                                    float* projMatrix = output.AsFloat();
+
+                                                                    projMatrix[0] = -2.0f / delta;
+                                                                    projMatrix[1] = 0.0f;
+                                                                    projMatrix[2] = 0.0f;
+                                                                    projMatrix[3] = 0.0f;
+
+                                                                    projMatrix[4] = 0.0f;
+                                                                    projMatrix[5] = -2.0f / delta;
+                                                                    projMatrix[6] = 0.0f;
+                                                                    projMatrix[7] = 0.0f;
+
+                                                                    projMatrix[8]  = 0.0f;
+                                                                    projMatrix[9]  = 0.0f;
+                                                                    projMatrix[10] = 2.0f / deltaZ;
+                                                                    projMatrix[11] = 0.0f;
+
+                                                                    projMatrix[12] = -(right + left) / delta;
+                                                                    projMatrix[13] = -(top + bottom) / delta;
+                                                                    projMatrix[14] = -(near + far) / deltaZ;
+                                                                    projMatrix[15] = 1.0f; });
+  projectionMatrixConstraint.AddSource(Source{selectedCamera, Dali::Actor::Property::WORLD_MATRIX});
+  projectionMatrixConstraint.AddSource(Source{selectedCamera, Dali::CameraActor::Property::PROJECTION_MODE});
+  projectionMatrixConstraint.AddSource(Source{selectedCamera, Dali::DevelCameraActor::Property::PROJECTION_DIRECTION});
+  projectionMatrixConstraint.AddSource(Source{selectedCamera, Dali::DevelCameraActor::Property::ORTHOGRAPHIC_SIZE});
+  projectionMatrixConstraint.AddSource(Source{selectedCamera, Dali::CameraActor::Property::FIELD_OF_VIEW});
+  projectionMatrixConstraint.AddSource(Source{selectedCamera, Dali::CameraActor::Property::NEAR_PLANE_DISTANCE});
+  projectionMatrixConstraint.AddSource(Source{selectedCamera, Dali::CameraActor::Property::FAR_PLANE_DISTANCE});
+  projectionMatrixConstraint.AddSource(Source{selectedCamera, Dali::CameraActor::Property::ASPECT_RATIO});
+  projectionMatrixConstraint.AddSource(Source{shadowLightCamera, tempViewMatrixIndex});
+  projectionMatrixConstraint.ApplyPost();
+}
+
 } // anonymous namespace
 
 SceneView::SceneView()
@@ -421,6 +559,11 @@ void SceneView::AddLight(Scene3D::Light light)
 {
   bool enabled = mShaderManager->AddLight(light);
   mLights.push_back(std::make_pair(light, enabled));
+
+  if(light.IsShadowEnabled())
+  {
+    SetShadow(light);
+  }
 }
 
 void SceneView::RemoveLight(Scene3D::Light light)
@@ -437,7 +580,7 @@ void SceneView::RemoveLight(Scene3D::Light light)
 
   if(mLights.size() > mShaderManager->GetLightCount())
   {
-    for(auto && waitingLight : mLights)
+    for(auto&& waitingLight : mLights)
     {
       if(waitingLight.second)
       {
@@ -448,6 +591,86 @@ void SceneView::RemoveLight(Scene3D::Light light)
       break;
     }
   }
+
+  if(light == mShadowLight)
+  {
+    RemoveShadow(light);
+  }
+
+  if(!mShadowLight)
+  {
+    for(auto&& lightEntity : mLights)
+    {
+      if(!lightEntity.second || !lightEntity.first.IsShadowEnabled())
+      {
+        continue;
+      }
+      SetShadow(lightEntity.first);
+      break;
+    }
+  }
+}
+
+void SceneView::SetShadow(Scene3D::Light light)
+{
+  if(!!mShadowLight)
+  {
+    return;
+  }
+
+  auto foundLight = std::find_if(mLights.begin(), mLights.end(), [light](std::pair<Scene3D::Light, bool> lightEntity) -> bool
+                                 { return (lightEntity.second && lightEntity.first == light); });
+
+  if(foundLight == mLights.end())
+  {
+    return;
+  }
+
+  mShadowLight = light;
+
+  // Directional Light setting.
+  CameraActor lightCamera    = GetImplementation(light).GetCamera();
+  CameraActor selectedCamera = GetSelectedCamera();
+  SetShadowLightConstraint(selectedCamera, lightCamera);
+
+  // make framebuffer for depth map and set it to render task.
+  Vector3  size               = Self().GetProperty<Vector3>(Dali::Actor::Property::SIZE);
+  uint32_t shadowMapBufferSize = std::min(static_cast<uint32_t>(std::max(size.width, size.height)), MAXIMUM_SIZE_SHADOW_MAP);
+  UpdateShadowMapBuffer(shadowMapBufferSize);
+
+  // use lightCamera as a camera of shadow render task.
+  mShadowMapRenderTask.SetCameraActor(lightCamera);
+
+  mShaderManager->SetShadow(light);
+}
+
+void SceneView::RemoveShadow(Scene3D::Light light)
+{
+  if(mShadowLight != light)
+  {
+    return;
+  }
+
+  // remove all constraint from light camera
+  CameraActor lightCamera = GetImplementation(mShadowLight).GetCamera();
+  lightCamera.RemoveConstraints();
+
+  // reset framebuffer and remove it from render task.
+  mShadowFrameBuffer.Reset();
+  mShaderManager->RemoveShadow();
+  mShadowMapRenderTask.SetCameraActor(CameraActor());
+
+  mShadowLight.Reset();
+
+  for(auto&& lightEntity : mLights)
+  {
+    if(!lightEntity.second || !lightEntity.first.IsShadowEnabled())
+    {
+      continue;
+    }
+    SetShadow(lightEntity.first);
+    break;
+  }
 }
 
 uint32_t SceneView::GetActivatedLightCount() const
@@ -550,6 +773,11 @@ Dali::Scene3D::Loader::ShaderManagerPtr SceneView::GetShaderManager() const
   return mShaderManager;
 }
 
+void SceneView::UpdateShadowUniform(Scene3D::Light light)
+{
+  mShaderManager->UpdateShadowUniform(light);
+}
+
 ///////////////////////////////////////////////////////////
 //
 // Private methods
@@ -583,7 +811,17 @@ void SceneView::OnSceneConnection(int depth)
   if(mSceneHolder)
   {
     RenderTaskList taskList = mSceneHolder.GetRenderTaskList();
-    mRenderTask             = taskList.CreateTask();
+    mShadowMapRenderTask    = taskList.CreateTask();
+    mShadowMapRenderTask.SetSourceActor(mRootLayer);
+    mShadowMapRenderTask.SetExclusive(true);
+    mShadowMapRenderTask.SetInputEnabled(false);
+    mShadowMapRenderTask.SetCullMode(false);
+    mShadowMapRenderTask.SetClearEnabled(true);
+    mShadowMapRenderTask.SetClearColor(Color::WHITE);
+    mShadowMapRenderTask.SetRenderPassTag(10);
+    mShadowMapRenderTask.SetCameraActor(CameraActor());
+
+    mRenderTask = taskList.CreateTask();
     mRenderTask.SetSourceActor(mRootLayer);
     mRenderTask.SetExclusive(true);
     mRenderTask.SetInputEnabled(true);
@@ -615,9 +853,16 @@ void SceneView::OnSceneDisconnection()
       taskList.RemoveTask(mRenderTask);
       mRenderTask.Reset();
     }
+    if(mShadowMapRenderTask)
+    {
+      RenderTaskList taskList = mSceneHolder.GetRenderTaskList();
+      taskList.RemoveTask(mShadowMapRenderTask);
+      mShadowMapRenderTask.Reset();
+    }
     mSceneHolder.Reset();
   }
   mFrameBuffer.Reset();
+  mShadowFrameBuffer.Reset();
 
   Control::OnSceneDisconnection();
 }
@@ -694,6 +939,10 @@ void SceneView::UpdateCamera(CameraActor camera)
   }
 
   mSelectedCamera = camera;
+  if(mShadowLight)
+  {
+    SetShadowLightConstraint(mSelectedCamera, GetImplementation(mShadowLight).GetCamera());
+  }
   UpdateRenderTask();
 }
 
@@ -710,6 +959,9 @@ void SceneView::UpdateRenderTask()
     const float aspectRatio = size.width / size.height;
     mSelectedCamera.SetAspectRatio(aspectRatio);
 
+    uint32_t shadowMapBufferSize = std::min(static_cast<uint32_t>(std::max(size.width, size.height)), MAXIMUM_SIZE_SHADOW_MAP);
+    UpdateShadowMapBuffer(shadowMapBufferSize);
+
     if(mUseFrameBuffer)
     {
       Dali::FrameBuffer currentFrameBuffer = mRenderTask.GetFrameBuffer();
@@ -918,6 +1170,29 @@ void SceneView::NotifyImageBasedLightTextureChange()
   }
 }
 
+void SceneView::UpdateShadowMapBuffer(uint32_t shadowMapSize)
+{
+  Dali::FrameBuffer currentShadowFrameBuffer = mShadowMapRenderTask.GetFrameBuffer();
+  if(mShadowLight &&
+     (!currentShadowFrameBuffer ||
+      !Dali::Equals(DevelFrameBuffer::GetDepthTexture(currentShadowFrameBuffer).GetWidth(), shadowMapSize)))
+  {
+    mShadowFrameBuffer.Reset();
+    Dali::Texture shadowTexture = Dali::Texture::New(TextureType::TEXTURE_2D, Pixel::DEPTH_UNSIGNED_INT, shadowMapSize, shadowMapSize);
+    mShadowFrameBuffer          = FrameBuffer::New(shadowMapSize, shadowMapSize, FrameBuffer::Attachment::NONE);
+    DevelFrameBuffer::AttachDepthTexture(mShadowFrameBuffer, shadowTexture);
+    mShadowMapRenderTask.SetFrameBuffer(mShadowFrameBuffer);
+
+    for(auto&& item : mItems)
+    {
+      if(item)
+      {
+        item->NotifyShadowMapTexture(shadowTexture);
+      }
+    }
+  }
+}
+
 } // namespace Internal
 } // namespace Scene3D
 } // namespace Dali
index 3f6eca7..647df5e 100644 (file)
@@ -150,6 +150,22 @@ public:
   void RemoveLight(Scene3D::Light light);
 
   /**
+   * @brief Set a shadow to this scene by input light.
+   * Currently, SceneView supports only one shadow.
+   *
+   * @param[in] light Light object to make shadow.
+   * @note The shadow will be drawn if the input light is turn on in current scene.
+   */
+  void SetShadow(Scene3D::Light light);
+
+  /**
+   * @brief Removes Shadow from this SceneView.
+   *
+   * @param[in] light Light object to be removed.
+   */
+  void RemoveShadow(Scene3D::Light light);
+
+  /**
    * @copydoc SceneView::GetActivatedLightCount()
    */
   uint32_t GetActivatedLightCount() const;
@@ -210,6 +226,12 @@ public:
    */
   Dali::Scene3D::Loader::ShaderManagerPtr GetShaderManager() const;
 
+  /**
+   * @brief Update shader uniforms about shadow.
+   * @param[in] light Light that makes shadow.
+   */
+  void UpdateShadowUniform(Scene3D::Light light);
+
 protected:
   /**
    * @brief Constructs a new SceneView.
@@ -322,6 +344,12 @@ private:
    */
   void NotifyImageBasedLightTextureChange();
 
+  /**
+   * @brief Update shadowMap framebuffer when the size should be changed.
+   * @param[in] shadowMapSize The size of shadowMap texture. The texture's width and hight is equal.
+   */
+  void UpdateShadowMapBuffer(uint32_t shadowMapSize);
+
 private:
   Toolkit::Visual::Base mVisual;
 
@@ -348,6 +376,9 @@ private:
 
   // Light
   std::vector<std::pair<Scene3D::Light, bool>> mLights; // Pair of Light object and flag that denotes the light is currently activated or not.
+  Dali::FrameBuffer                            mShadowFrameBuffer;
+  Dali::RenderTask                             mShadowMapRenderTask;
+  Scene3D::Light                               mShadowLight;
 
   // Asynchronous Loading.
   EnvironmentMapLoadTaskPtr mSkyboxLoadTask;
index 9ea43a8..761ebb8 100644 (file)
@@ -2,7 +2,7 @@ set(scene3d_internal_dir "${scene3d_dir}/internal")
 
 set(scene3d_src_files ${scene3d_src_files}
        ${scene3d_internal_dir}/algorithm/navigation-mesh-impl.cpp
-       ${scene3d_internal_dir}/algorithm/path-finder-djikstra.cpp
+       ${scene3d_internal_dir}/algorithm/path-finder-dijkstra.cpp
        ${scene3d_internal_dir}/algorithm/path-finder-spfa.cpp
        ${scene3d_internal_dir}/algorithm/path-finder-spfa-double-way.cpp
        ${scene3d_internal_dir}/common/environment-map-load-task.cpp
index de7b28d..db3c146 100644 (file)
@@ -78,6 +78,11 @@ uniform mediump int uLightCount;
 uniform mediump vec3 uLightDirection[MAX_LIGHTS];
 uniform mediump vec3 uLightColor[MAX_LIGHTS];
 
+// For Shadow Map
+uniform lowp int uIsShadowEnabled;
+uniform sampler2D sShadowMap;
+in highp vec3 positionFromLightView;
+
 //// For IBL
 uniform sampler2D sbrdfLUT;
 uniform samplerCube sDiffuseEnvSampler;
@@ -102,6 +107,21 @@ out vec4 FragColor;
 const float c_MinRoughness = 0.04;
 const float M_PI = 3.141592653589793;
 
+// These properties can be used for circular sampling for PCF
+
+// Percentage Closer Filtering to mitigate the banding artifacts.
+const int kPcfSampleCount = 9;
+
+const float kPi = 3.141592653589f;
+const float kInvSampleCount = 1.0 / float(kPcfSampleCount);
+const float kPcfTheta = 2.f * kPi * kInvSampleCount;
+const float kSinPcfTheta = sin(kPcfTheta);
+const float kCosPcfTheta = cos(kPcfTheta);
+
+uniform lowp int uEnableShadowSoftFiltering;
+uniform mediump float uShadowIntensity;
+uniform mediump float uShadowBias;
+
 vec3 linear(vec3 color)
 {
   return pow(color, vec3(2.2));
@@ -244,6 +264,31 @@ void main()
     }
   }
 
+  if(float(uIsShadowEnabled) * uShadowIntensity > 0.0)
+  {
+    mediump float exposureFactor = 0.0;
+    if(uEnableShadowSoftFiltering > 0)
+    {
+      ivec2 texSize = textureSize(sShadowMap, 0);
+      mediump vec2 texelSize = vec2(1.0) / vec2(texSize.x, texSize.y);
+      mediump vec2 pcfSample = vec2(1.f, 0.f);
+      for (int i = 0; i < kPcfSampleCount; ++i)
+      {
+        pcfSample = vec2(kCosPcfTheta * pcfSample.x - kSinPcfTheta * pcfSample.y,
+                         kSinPcfTheta * pcfSample.x + kCosPcfTheta * pcfSample.y);
+        lowp float depthValue = texture(sShadowMap, positionFromLightView.xy + pcfSample * texelSize).r;
+        exposureFactor += (depthValue < positionFromLightView.z - uShadowBias) ? 0.0 : 1.0;
+      }
+      exposureFactor *= kInvSampleCount;
+    }
+    else
+    {
+      mediump float depthValue = texture(sShadowMap, positionFromLightView.xy).r;
+      exposureFactor           = (depthValue < positionFromLightView.z - uShadowBias) ? 0.0 : 1.0;
+    }
+    color *= (1.0 - (1.0 - exposureFactor) * uShadowIntensity);
+  }
+
 #ifdef OCCLUSION
   lowp float ao = texture(sOcclusion, vUV).r;
   color = mix(color, color * ao, uOcclusionStrength);
index 5b6140c..6f637ed 100644 (file)
@@ -58,6 +58,11 @@ uniform highp float uBlendShapeUnnormalizeFactor[MAX_BLEND_SHAPE_NUMBER]; ///< F
 uniform highp int uBlendShapeComponentSize;                               ///< The size in the texture of either the vertices, normals or tangents. Used to calculate the offset to address them.
 #endif
 
+// Shadow
+uniform lowp int uIsShadowEnabled;
+uniform highp mat4 uShadowLightViewProjectionMatrix;
+out highp vec3 positionFromLightView;
+
 void main()
 {
   highp vec4 position = vec4(aPosition, 1.0);
@@ -169,5 +174,12 @@ void main()
 
   vColor = aVertexColor;
 
+  positionFromLightView = vec3(1.0);
+  if(uIsShadowEnabled > 0)
+  {
+    highp vec4 positionInLightView = uShadowLightViewProjectionMatrix * positionW;
+    positionFromLightView = ((positionInLightView.xyz / positionInLightView.w) * 0.5) + vec3(0.5);
+  }
+
   gl_Position = uProjection * positionV;
 }
diff --git a/dali-scene3d/internal/graphics/shaders/shadow-map-shader.frag b/dali-scene3d/internal/graphics/shaders/shadow-map-shader.frag
new file mode 100644 (file)
index 0000000..91dace8
--- /dev/null
@@ -0,0 +1,50 @@
+#version 300 es
+
+uniform lowp vec4 uColorFactor; // Color from material
+uniform lowp float uMask;
+uniform lowp float uAlphaThreshold;
+
+in mediump vec2 vUV;
+in lowp vec4 vColor;
+
+//in highp float depth;
+//out highp vec4 FragColor;
+
+#ifdef THREE_TEX
+#ifdef BASECOLOR_TEX
+uniform sampler2D sAlbedoAlpha;
+#endif // BASECOLOR_TEX
+#else // THREE_TEX
+uniform sampler2D sAlbedoMetal;
+#endif
+
+lowp vec3 linear(lowp vec3 color)
+{
+  return pow(color, vec3(2.2));
+}
+
+void main()
+{
+#ifdef THREE_TEX
+  // The albedo may be defined from a base texture or a flat color
+#ifdef BASECOLOR_TEX
+  lowp vec4 baseColor = texture(sAlbedoAlpha, vUV);
+  baseColor = vColor * vec4(linear(baseColor.rgb), baseColor.w) * uColorFactor;
+#else // BASECOLOR_TEX
+  lowp vec4 baseColor = vColor * uColorFactor;
+#endif // BASECOLOR_TEX
+#else // THREE_TEX
+  lowp vec4 albedoMetal = texture(sAlbedoMetal, vUV);
+  lowp vec4 baseColor = vec4(linear(albedoMetal.rgb), 1.0) * vColor * uColorFactor;
+#endif // THREE_TEX
+
+  // The value of uOpaque and uMask can be 0.0 or 1.0.
+  // If uMask is 1.0, a Pixel that has bigger alpha than uAlphaThreashold becomes fully opaque,
+  // and, a pixel that has smaller alpha than uAlphaThreashold becomes fully transparent.
+  // If uOpaque is 1.0, alpha value of final color is 1.0;
+  // https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#_material_alphamode
+  if(uMask > 0.5 && baseColor.a < uAlphaThreshold)
+  {
+    discard;
+  }
+}
\ No newline at end of file
diff --git a/dali-scene3d/internal/graphics/shaders/shadow-map-shader.vert b/dali-scene3d/internal/graphics/shaders/shadow-map-shader.vert
new file mode 100644 (file)
index 0000000..73bb37c
--- /dev/null
@@ -0,0 +1,110 @@
+#version 300 es
+
+precision highp float;
+
+in vec3 aPosition;
+in vec2 aTexCoord;
+in vec4 aVertexColor;
+
+out mediump vec2 vUV;
+out lowp vec4 vColor;
+
+uniform highp mat4 uViewMatrix;
+uniform highp mat4 uModelMatrix;
+uniform highp mat4 uProjection;
+
+#ifdef SKINNING
+  in vec4 aJoints;
+  in vec4 aWeights;
+  #define MAX_BONES 64
+  uniform mat4 uBone[MAX_BONES];
+  uniform mediump vec3 uYDirection;
+#endif
+
+#ifdef MORPH
+#define MAX_BLEND_SHAPE_NUMBER 128
+uniform int uNumberOfBlendShapes;                                         ///< Total number of blend shapes loaded.
+uniform highp float uBlendShapeWeight[MAX_BLEND_SHAPE_NUMBER];            ///< The weight of each blend shape.
+#ifdef MORPH_VERSION_2_0
+uniform highp float uBlendShapeUnnormalizeFactor;                         ///< Factor used to unnormalize the geometry of the blend shape.
+#else
+uniform highp float uBlendShapeUnnormalizeFactor[MAX_BLEND_SHAPE_NUMBER]; ///< Factor used to unnormalize the geometry of the blend shape.
+#endif
+uniform highp int uBlendShapeComponentSize;                               ///< The size in the texture of either the vertices, normals or tangents. Used to calculate the offset to address them.
+#endif
+
+uniform highp mat4 uShadowLightViewProjectionMatrix;
+
+void main()
+{
+  highp vec4 position = vec4(aPosition, 1.0);
+
+#ifdef MORPH
+  int width = textureSize( sBlendShapeGeometry, 0 ).x;
+
+  highp int blendShapeBufferOffset = 0;
+
+  for( int index = 0; index < uNumberOfBlendShapes; ++index )
+  {
+    highp vec3 diff = vec3(0.0);
+    highp int vertexId = 0;
+    highp int x = 0;
+    highp int y = 0;
+
+#ifdef MORPH_POSITION
+    // Calculate the index to retrieve the geometry from the texture.
+    vertexId = gl_VertexID + blendShapeBufferOffset;
+    x = vertexId % width;
+    y = vertexId / width;
+
+    // Retrieves the blend shape geometry from the texture, unnormalizes it and multiply by the weight.
+    if( 0.0 != uBlendShapeWeight[index] )
+    {
+#ifdef MORPH_VERSION_2_0
+       highp float unnormalizeFactor = uBlendShapeUnnormalizeFactor;
+#else
+       highp float unnormalizeFactor = uBlendShapeUnnormalizeFactor[index];
+#endif
+
+      diff = uBlendShapeWeight[index] * unnormalizeFactor * ( texelFetch( sBlendShapeGeometry, ivec2(x, y), 0 ).xyz - 0.5 );
+    }
+
+    position.xyz += diff;
+
+    blendShapeBufferOffset += uBlendShapeComponentSize;
+#endif
+
+#ifdef MORPH_NORMAL
+    blendShapeBufferOffset += uBlendShapeComponentSize;
+#endif
+
+#ifdef MORPH_TANGENT
+    blendShapeBufferOffset += uBlendShapeComponentSize;
+#endif
+  }
+
+#endif
+
+#ifdef SKINNING
+  highp mat4 bone = uBone[int(aJoints.x)] * aWeights.x +
+    uBone[int(aJoints.y)] * aWeights.y +
+    uBone[int(aJoints.z)] * aWeights.z +
+    uBone[int(aJoints.w)] * aWeights.w;
+  position = bone * position;
+
+  highp vec4 positionW = position;
+#else
+  highp vec4 positionW = uModelMatrix * position;
+#endif
+
+  // To synchronize View-Projection matrix with pbr shader
+  gl_Position = uShadowLightViewProjectionMatrix * positionW;
+
+#ifdef FLIP_V
+  vUV = vec2(aTexCoord.x, 1.0 - aTexCoord.y);
+#else
+  vUV = aTexCoord;
+#endif
+
+  vColor = aVertexColor;
+}
index 00eb0f4..0a0a453 100644 (file)
@@ -38,6 +38,8 @@ static constexpr uint32_t         MAX_NUMBER_OF_LIGHT = 5;
 static constexpr std::string_view LIGHT_COUNT_STRING("uLightCount");
 static constexpr std::string_view LIGHT_DIRECTION_STRING("uLightDirection");
 static constexpr std::string_view LIGHT_COLOR_STRING("uLightColor");
+static constexpr std::string_view SHADOW_ENABLED_STRING("uIsShadowEnabled");
+static constexpr std::string_view SHADOW_VIEW_PROJECTION_MATRIX_STRING("uShadowLightViewProjectionMatrix");
 
 /**
  * Creates control through type registry
@@ -79,6 +81,13 @@ Light::~Light()
 void Light::Initialize()
 {
   Self().SetProperty(Dali::Actor::Property::COLOR, Color::WHITE);
+
+  // Directional Light setting
+  mLightSourceActor = Dali::CameraActor::New();
+  mLightSourceActor.SetProjectionMode(Dali::Camera::ORTHOGRAPHIC_PROJECTION);
+  mLightSourceActor.SetProperty(Dali::Actor::Property::POSITION, Vector3::ZERO);
+  mLightSourceActor.SetProperty(Dali::Actor::Property::ORIENTATION, Quaternion());
+  Self().Add(mLightSourceActor);
 }
 
 void Light::Enable(bool enable)
@@ -110,6 +119,73 @@ bool Light::IsEnabled() const
   return mIsEnabled;
 }
 
+void Light::EnableShadow(bool enable)
+{
+  if(enable == mIsShadowEnabled)
+  {
+    return;
+  }
+  mIsShadowEnabled = enable;
+
+  Scene3D::SceneView sceneView = mParentSceneView.GetHandle();
+  if(!sceneView)
+  {
+    return;
+  }
+
+  if(mIsShadowEnabled)
+  {
+    GetImpl(sceneView).SetShadow(Scene3D::Light::DownCast(Self()));
+  }
+  else
+  {
+    GetImpl(sceneView).RemoveShadow(Scene3D::Light::DownCast(Self()));
+  }
+}
+
+bool Light::IsShadowEnabled() const
+{
+  return mIsShadowEnabled;
+}
+
+CameraActor Light::GetCamera() const
+{
+  return mLightSourceActor;
+}
+
+void Light::EnableShadowSoftFiltering(bool useSoftFiltering)
+{
+  mUseSoftFiltering = useSoftFiltering;
+  UpdateShadowUniforms();
+}
+
+bool Light::IsShadowSoftFilteringEnabled() const
+{
+  return mUseSoftFiltering;
+}
+
+void Light::SetShadowIntensity(float shadowIntensity)
+{
+  mShadowIntensity = shadowIntensity;
+  UpdateShadowUniforms();
+}
+
+float Light::GetShadowIntensity() const
+{
+  return mShadowIntensity;
+}
+
+void Light::SetShadowBias(float shadowBias)
+{
+  mShadowBias = shadowBias;
+  UpdateShadowUniforms();
+}
+
+float Light::GetShadowBias() const
+{
+  return mShadowBias;
+}
+
 void Light::OnSceneConnection(int depth)
 {
   Actor parent = Self().GetParent();
@@ -123,6 +199,10 @@ void Light::OnSceneConnection(int depth)
       {
         GetImpl(sceneView).AddLight(Scene3D::Light::DownCast(Self()));
       }
+      if(mIsShadowEnabled)
+      {
+        GetImpl(sceneView).SetShadow(Scene3D::Light::DownCast(Self()));
+      }
       break;
     }
     parent = parent.GetParent();
@@ -234,6 +314,30 @@ std::string_view Light::GetLightColorUniformName()
   return LIGHT_COLOR_STRING;
 }
 
+std::string_view Light::GetShadowEnabledUniformName()
+{
+  return SHADOW_ENABLED_STRING;
+}
+
+std::string_view Light::GetShadowViewProjectionMatrixUniformName()
+{
+  return SHADOW_VIEW_PROJECTION_MATRIX_STRING;
+}
+
+void Light::UpdateShadowUniforms()
+{
+  Scene3D::SceneView sceneView = mParentSceneView.GetHandle();
+  if(!sceneView)
+  {
+    return;
+  }
+
+  if(mIsShadowEnabled)
+  {
+    GetImpl(sceneView).UpdateShadowUniform(Scene3D::Light::DownCast(Self()));
+  }
+}
+
 } // namespace Internal
 
 } // namespace Scene3D
index 70b51f5..c691423 100644 (file)
@@ -67,6 +67,51 @@ public:
    */
   bool IsEnabled() const;
 
+  /**
+   * @copydoc Scene3D::Light::EnableShadow()
+   */
+  void EnableShadow(bool enable);
+
+  /**
+   * @copydoc Scene3D::Light::IsShadowEnabled()
+   */
+  bool IsShadowEnabled() const;
+
+  /**
+   * @copydoc Scene3D::Light::GetCamera()
+   */
+  CameraActor GetCamera() const;
+
+  /**
+   * @copydoc Scene3D::Light::EnableShadowSoftFiltering()
+   */
+  void EnableShadowSoftFiltering(bool useSoftFiltering);
+
+  /**
+   * @copydoc Scene3D::Light::IsShadowSoftFilteringEnabled()
+   */
+  bool IsShadowSoftFilteringEnabled() const;
+
+  /**
+   * @copydoc Scene3D::Light::SetShadowIntensity()
+   */
+  void SetShadowIntensity(float shadowIntensity);
+
+  /**
+   * @copydoc Scene3D::Light::GetShadowIntensity()
+   */
+  float GetShadowIntensity() const;
+
+  /**
+   * @copydoc Scene3D::Light::SetShadowBias()
+   */
+  void SetShadowBias(float shadowBias);
+
+  /**
+   * @copydoc Scene3D::Light::GetShadowBias()
+   */
+  float GetShadowBias() const;
+
 protected:
   /**
    * @brief Virtual destructor.
@@ -194,6 +239,21 @@ public: // Public Method
    */
   static std::string_view GetLightColorUniformName();
 
+  /**
+   * @brief Retrieves Uniform Name to define shadow is enabled or not.
+   * @return string_view for ShadowEnabledUniformName
+   */
+  static std::string_view GetShadowEnabledUniformName();
+
+  /**
+   * @brief Retrieves Uniform Name for View/Projection matrix of the Shadow.
+   * @return string_view for ShadowViewProjectionMatrixUniformName
+   */
+  static std::string_view GetShadowViewProjectionMatrixUniformName();
+
+private:
+  void UpdateShadowUniforms();
+
 private:
   /// @cond internal
 
@@ -204,8 +264,13 @@ private:
   DALI_INTERNAL Light& operator=(Light&&)      = delete; ///< Deleted move assignment operator.
 
 private:
+  Dali::CameraActor              mLightSourceActor;
   WeakHandle<Scene3D::SceneView> mParentSceneView;
-  bool mIsEnabled{true};
+  bool                           mIsEnabled{true};
+  bool                           mIsShadowEnabled{false};
+  bool                           mUseSoftFiltering{false};
+  float                          mShadowIntensity{0.5f};
+  float                          mShadowBias{0.001f};
   /// @endcond
 };
 
index a4dbeda..668a10c 100644 (file)
@@ -667,6 +667,12 @@ void DliLoaderImpl::Impl::ParseShaders(const TreeNode* shaders, Dali::Scene3D::L
     auto&            node = (*i0).second;
     ShaderDefinition shaderDef;
     ReadStringVector(node.GetChild("defines"), shaderDef.mDefines);
+    auto sssIter = std::find_if(shaderDef.mDefines.begin(), shaderDef.mDefines.end(), [](std::string& item)
+                                { return (item == "SSS"); });
+    if(sssIter != shaderDef.mDefines.end())
+    {
+      shaderDef.mDefines.erase(sssIter);
+    }
 
     // Read shader hints. Possible values are:
     //                         Don't define for No hints.
@@ -1027,14 +1033,17 @@ void DliLoaderImpl::Impl::ParseMaterials(const TreeNode* materials, DliInputPara
       materialDef.mFlags |= semantic;
     }
 
-    if(ReadString(node.GetChild("subsurfaceMap"), texturePath))
-    {
-      ToUnixFileSeparators(texturePath);
-
-      const auto semantic = MaterialDefinition::SUBSURFACE;
-      materialDef.mTextureStages.push_back({semantic, TextureDefinition{std::move(texturePath)}});
-      materialDef.mFlags |= semantic;
-    }
+/// @TODO : Some dli shader don't implement this subsurfaceMp usage.
+///         To make visual test pass, Skip subsurfaceMap texture using
+///         until dli shaders are support it.
+//    if(ReadString(node.GetChild("subsurfaceMap"), texturePath))
+//    {
+//      ToUnixFileSeparators(texturePath);
+//
+//      const auto semantic = MaterialDefinition::SUBSURFACE;
+//      materialDef.mTextureStages.push_back({semantic, TextureDefinition{std::move(texturePath)}});
+//      materialDef.mFlags |= semantic;
+//    }
 
     if(ReadString(node.GetChild("occlusionMap"), texturePath))
     {
index 8cdbecf..1bda11a 100644 (file)
@@ -597,6 +597,7 @@ void ConvertMaterial(const gltf2::Material& material, const std::unordered_map<s
   MaterialDefinition materialDefinition;
 
   materialDefinition.mFlags |= MaterialDefinition::GLTF_CHANNELS;
+  materialDefinition.mShadowAvailable = true;
 
   auto& pbr = material.mPbrMetallicRoughness;
   if(material.mAlphaMode == gltf2::AlphaMode::BLEND)
index b7c16a7..69a1a53 100644 (file)
@@ -53,6 +53,7 @@ BaseHandle Create()
 DALI_TYPE_REGISTRATION_BEGIN(Scene3D::Material, Dali::BaseHandle, Create);
 DALI_TYPE_REGISTRATION_END()
 
+static constexpr uint32_t         OFFSET_FOR_SHADOW_MAP_TEXTURE    = 4u;
 static constexpr uint32_t         OFFSET_FOR_DIFFUSE_CUBE_TEXTURE  = 2u;
 static constexpr uint32_t         OFFSET_FOR_SPECULAR_CUBE_TEXTURE = 1u;
 static constexpr uint32_t         INVALID_INDEX                    = 0u;
@@ -693,6 +694,11 @@ void Material::SetRendererUniform(Dali::Renderer renderer)
   Scene3D::Loader::RendererState::Apply(mRendererState, renderer);
 }
 
+uint32_t Material::GetShadowMapTextureOffset()
+{
+  return OFFSET_FOR_SHADOW_MAP_TEXTURE;
+}
+
 uint32_t Material::GetSpecularImageBasedLightTextureOffset()
 {
   return OFFSET_FOR_SPECULAR_CUBE_TEXTURE;
index 3b0c985..fe45dee 100644 (file)
@@ -197,6 +197,13 @@ public:
   void SetRendererUniform(Dali::Renderer renderer);
 
   /**
+   * @brief Retrieves shadow map texture offset.
+   *
+   * @return shadow map texture offset.
+   */
+  uint32_t GetShadowMapTextureOffset();
+
+  /**
    * @brief Retrieves specular image based light texture offset.
    *
    * @return Specular image based light texture offset.
index 9d8d4b6..f88b031 100644 (file)
@@ -187,6 +187,11 @@ void ModelNode::AddModelPrimitive(Dali::Scene3D::ModelPrimitive modelPrimitive)
 
   Actor self = Self();
   GetImplementation(modelPrimitive).AddPrimitiveObserver(this);
+  if(mShadowMapTexture)
+  {
+    GetImplementation(modelPrimitive).SetShadowMapTexture(mShadowMapTexture);
+  }
+
   if(mDiffuseTexture && mSpecularTexture)
   {
     GetImplementation(modelPrimitive).SetImageBasedLightTexture(mDiffuseTexture, mSpecularTexture, mIblScaleFactor, mSpecularMipmapLevels);
@@ -284,6 +289,15 @@ Loader::BlendShapes::Index ModelNode::GetBlendShapeIndexByName(std::string_view
   return Loader::BlendShapes::INVALID_INDEX;
 }
 
+void ModelNode::SetShadowMapTexture(Dali::Texture shadowMapTexture)
+{
+  mShadowMapTexture       = shadowMapTexture;
+  for(auto&& primitive : mModelPrimitiveContainer)
+  {
+    GetImplementation(primitive).SetShadowMapTexture(mShadowMapTexture);
+  }
+}
+
 void ModelNode::SetImageBasedLightTexture(Dali::Texture diffuseTexture, Dali::Texture specularTexture, float iblScaleFactor, uint32_t specularMipmapLevels)
 {
   mDiffuseTexture       = diffuseTexture;
index 2cc4f1a..ed17a45 100644 (file)
@@ -231,7 +231,14 @@ public: // Public Method
   Loader::BlendShapes::Index GetBlendShapeIndexByName(std::string_view blendShapeName) const;
 
   /**
-   * @brief Sets the diffuse and specular image-based lighting textures for a ModelPrimitive.
+   * @brief Sets the shadow map textures for a ModelNode.
+   *
+   * @param[in] shadowMapTexture The shadow map texture.
+   */
+  void SetShadowMapTexture(Dali::Texture shadowMapTexture);
+
+  /**
+   * @brief Sets the diffuse and specular image-based lighting textures for a ModelNode.
    *
    * @param[in] diffuseTexture The diffuse texture.
    * @param[in] specularTexture The specular texture.
@@ -300,6 +307,7 @@ private:
   ModelPrimitiveContainer           mModelPrimitiveContainer; ///< List of model primitives
   BoneDataContainer                 mBoneDataContainer;
   BlendShapeIndexMap                mBlendShapeIndexMap;      ///< Index of blend shape by name
+  Dali::Texture                     mShadowMapTexture;
   Dali::Texture                     mSpecularTexture;
   Dali::Texture                     mDiffuseTexture;
   float                             mIblScaleFactor{1.0f};
index 0aea879..edf3e86 100644 (file)
@@ -52,6 +52,15 @@ DALI_TYPE_REGISTRATION_BEGIN(Scene3D::ModelPrimitive, Dali::BaseHandle, Create);
 DALI_TYPE_REGISTRATION_END()
 
 static constexpr uint32_t INDEX_FOR_LIGHT_CONSTRAINT_TAG = 10;
+
+Texture MakeEmptyTexture()
+{
+  PixelData pixelData = PixelData::New(new uint8_t[3]{0xff, 0xff, 0xff}, 3, 1, 1, Pixel::RGB888, PixelData::DELETE_ARRAY);
+  Texture texture            = Texture::New(TextureType::TEXTURE_2D, pixelData.GetPixelFormat(), pixelData.GetWidth(), pixelData.GetHeight());
+  texture.Upload(pixelData, 0, 0, 0, 0, pixelData.GetWidth(), pixelData.GetHeight());
+
+  return texture;
+}
 } // unnamed namespace
 
 ModelPrimitivePtr ModelPrimitive::New()
@@ -138,6 +147,7 @@ void ModelPrimitive::SetMaterial(Dali::Scene3D::Material material, bool updateRe
         ApplyMaterialToRenderer();
       }
     }
+    UpdateShadowMapTexture();
     UpdateImageBasedLightTexture();
   }
 }
@@ -157,6 +167,13 @@ void ModelPrimitive::RemovePrimitiveObserver(ModelPrimitiveModifyObserver* obser
   mObservers.erase(observer);
 }
 
+void ModelPrimitive::SetShadowMapTexture(Dali::Texture shadowMapTexture)
+{
+  mShadowMapTexture = shadowMapTexture;
+
+  UpdateShadowMapTexture();
+}
+
 void ModelPrimitive::SetImageBasedLightTexture(Dali::Texture diffuseTexture, Dali::Texture specularTexture, float iblScaleFactor, uint32_t specularMipmapLevels)
 {
   mDiffuseTexture       = diffuseTexture;
@@ -291,7 +308,14 @@ void ModelPrimitive::ApplyMaterialToRenderer(MaterialModifyObserver::ModifyFlag
     }
 
     uint32_t textureCount = mTextureSet.GetTextureCount();
-    Texture  brdfTexture  = Scene3D::Loader::EnvironmentDefinition::GetBrdfTexture();
+
+    if(!mShadowMapTexture)
+    {
+      mShadowMapTexture = MakeEmptyTexture();
+    }
+    mTextureSet.SetTexture(textureCount++, mShadowMapTexture);
+
+    Texture brdfTexture = Scene3D::Loader::EnvironmentDefinition::GetBrdfTexture();
     if(!mSpecularTexture || !mDiffuseTexture)
     {
       Scene3D::Loader::EnvironmentMapData environmentMapData;
@@ -357,6 +381,40 @@ void ModelPrimitive::CreateRenderer()
   }
 }
 
+void ModelPrimitive::UpdateShadowMapTexture()
+{
+  if(mRenderer && mMaterial)
+  {
+    Dali::TextureSet textures = mRenderer.GetTextures();
+    if(!textures)
+    {
+      return;
+    }
+
+    uint32_t textureCount = textures.GetTextureCount();
+    if(mShadowMapTexture &&
+       textureCount >= GetImplementation(mMaterial).GetShadowMapTextureOffset() &&
+       textures.GetTexture(textureCount - GetImplementation(mMaterial).GetShadowMapTextureOffset()) != mShadowMapTexture)
+    {
+      Dali::TextureSet newTextures = Dali::TextureSet::New();
+
+      for(uint32_t index = 0u; index < textureCount; ++index)
+      {
+        Dali::Texture texture = textures.GetTexture(index);
+        if(index == textureCount - GetImplementation(mMaterial).GetShadowMapTextureOffset())
+        {
+          texture = (!!mShadowMapTexture) ? mShadowMapTexture : MakeEmptyTexture();
+        }
+
+        newTextures.SetTexture(index, texture);
+        newTextures.SetSampler(index, textures.GetSampler(index));
+      }
+
+      mRenderer.SetTextures(newTextures);
+    }
+  }
+}
+
 void ModelPrimitive::UpdateImageBasedLightTexture()
 {
   if(mRenderer && mMaterial)
index 7334699..c6dbf37 100644 (file)
@@ -124,6 +124,13 @@ public:
   void RemovePrimitiveObserver(ModelPrimitiveModifyObserver* observer);
 
   /**
+   * @brief Sets shadow map texture for this model primitive.
+   *
+   * @param[in] shadowMapTexture The shadow map texture.
+   */
+  void SetShadowMapTexture(Dali::Texture shadowMapTexture);
+
+  /**
    * @brief Sets the image-based lighting texture for this model primitive.
    *
    * @param[in] diffuseTexture The diffuse texture.
@@ -200,6 +207,8 @@ private:
    */
   void CreateRenderer();
 
+  void UpdateShadowMapTexture();
+
   /**
    * @brief Updates the image-based lighting texture.
    */
@@ -224,6 +233,9 @@ private:
 
   Scene3D::Loader::ShaderManagerPtr mShaderManager;
 
+  // For Shadow
+  Dali::Texture mShadowMapTexture;
+
   // For IBL
   Dali::Texture mSpecularTexture;
   Dali::Texture mDiffuseTexture;
index 621fc82..2f89e5d 100644 (file)
@@ -19,7 +19,7 @@
 
 // INTERNAL INCLUDES
 // default algorithm
-#include <dali-scene3d/internal/algorithm/path-finder-djikstra.h>
+#include <dali-scene3d/internal/algorithm/path-finder-dijkstra.h>
 #include <dali-scene3d/internal/algorithm/path-finder-spfa-double-way.h>
 #include <dali-scene3d/internal/algorithm/path-finder-spfa.h>
 
@@ -31,9 +31,9 @@ std::unique_ptr<PathFinder> PathFinder::New(NavigationMesh& navigationMesh, Path
 
   switch(algorithm)
   {
-    case PathFinderAlgorithm::DJIKSTRA_SHORTEST_PATH:
+    case PathFinderAlgorithm::DIJKSTRA_SHORTEST_PATH:
     {
-      impl = new Dali::Scene3D::Internal::Algorithm::PathFinderAlgorithmDjikstra(navigationMesh);
+      impl = new Dali::Scene3D::Internal::Algorithm::PathFinderAlgorithmDijkstra(navigationMesh);
       break;
     }
     case PathFinderAlgorithm::SPFA:
index 5d2a6f1..8b5e15c 100644 (file)
@@ -32,11 +32,11 @@ using WayPointList = std::vector<Scene3D::Algorithm::WayPoint>;
  */
 enum class PathFinderAlgorithm
 {
-  DJIKSTRA_SHORTEST_PATH, ///< Using A* variant (Djikstra) finding a shortest path
+  DIJKSTRA_SHORTEST_PATH, ///< Using A* variant (Dijkstra) finding a shortest path
   SPFA,                   ///< Using SPFA-SLF (Shortest Path Fast Algorithm with Short Label First) finding a shortest path.
   SPFA_DOUBLE_WAY,        ///< Using SPFA-SLF double way. It might not find shortest, but will use less memory.
 
-  DEFAULT = DJIKSTRA_SHORTEST_PATH, ///< Default algorithm to use
+  DEFAULT = DIJKSTRA_SHORTEST_PATH, ///< Default algorithm to use
 };
 
 /**
index 0b7f493..095e053 100644 (file)
@@ -81,6 +81,46 @@ uint32_t Light::GetMaximumEnabledLightCount()
   return Internal::Light::GetMaximumEnabledLightCount();
 }
 
+void Light::EnableShadow(bool enable)
+{
+  Internal::GetImplementation(*this).EnableShadow(enable);
+}
+
+bool Light::IsShadowEnabled() const
+{
+  return Internal::GetImplementation(*this).IsShadowEnabled();
+}
+
+void Light::EnableShadowSoftFiltering(bool useSoftFiltering)
+{
+  Internal::GetImplementation(*this).EnableShadowSoftFiltering(useSoftFiltering);
+}
+
+bool Light::IsShadowSoftFilteringEnabled() const
+{
+  return Internal::GetImplementation(*this).IsShadowSoftFilteringEnabled();
+}
+
+void Light::SetShadowIntensity(float shadowIntensity)
+{
+  Internal::GetImplementation(*this).SetShadowIntensity(shadowIntensity);
+}
+
+float Light::GetShadowIntensity() const
+{
+  return Internal::GetImplementation(*this).GetShadowIntensity();
+}
+
+void Light::SetShadowBias(float shadowBias)
+{
+  Internal::GetImplementation(*this).SetShadowBias(shadowBias);
+}
+
+float Light::GetShadowBias() const
+{
+  return Internal::GetImplementation(*this).GetShadowBias();
+}
+
 Light::Light(Internal::Light& implementation)
 : CustomActor(implementation)
 {
index eabb278..ef4892a 100644 (file)
@@ -159,6 +159,79 @@ public:
    */
   static uint32_t GetMaximumEnabledLightCount();
 
+  /**
+   * @brief Enables shadow for this light.
+   * Dali::Scene3D generates shadow by using shadow map.
+   * For the Directional Light, the shadow map is created to cover view frustum of current selected camera.
+   * This means that if the distance between the near and far planes is too large,
+   * the shadow map has to cover an unnecessarily large area. This results in lower shadow quality.
+   * @SINCE_2_2.43
+   * @note This light should be already turned on in the SceneView.
+   * @note (When enable is true) If there is previous light already enabled shadow in the SceneView, this function call is ignored.
+   * @note (When enable is false, and this light is currently used for shader)
+   * If there are other lights those are turned on and shadow enabled, one of the light will be used for shadow automatically.
+   * @param[in] enable True to make this Light's shadow enable.
+   */
+  void EnableShadow(bool enable);
+
+  /**
+   * @brief Checks whether the shadow of this light is enabled or not.
+   * @SINCE_2_2.43
+   * @return True if the shadow of this light is enabled.
+   */
+  bool IsShadowEnabled() const;
+
+  /**
+   * @brief Enables filtering to soften the edge of shadow.
+   * Basically the shadow is hard shadow that has sharp edge.
+   * This method enables soft filtering to make the sharp edge to smoothing.
+   * @SINCE_2_2.43
+   * @note This soft filtering requires expensive computation power.
+   * @param[in] useSoftFiltering True to soften the shadow edge.
+   */
+  void EnableShadowSoftFiltering(bool useSoftFiltering);
+
+  /**
+   * @brief Checks whether the shadow uses soft filtering.
+   * @SINCE_2_2.43
+   * @return True if the shadow edge is soften.
+   */
+  bool IsShadowSoftFilteringEnabled() const;
+
+  /**
+   * @brief Sets shadow intensity.
+   * If the intensity is larger, the shadow area will be darker.
+   * The intensity value is between [0, 1].
+   * Default value is 0.5
+   * @SINCE_2_2.43
+   * @param[in] shadowIntensity Shadow intensity value
+   */
+  void SetShadowIntensity(float shadowIntensity);
+
+  /**
+   * @brief Retrieve shadow intensity.
+   * @SINCE_2_2.43
+   * @return Current shadow intensity value.
+   */
+  float GetShadowIntensity() const;
+
+  /**
+   * @brief Sets shadow bias.
+   * Shadow bias is an offset value to remove shadow acne that is a visual artifact can be shown on the Shadow
+   * Default value is 0.001
+   * @SINCE_2_2.43
+   * @param[in] shadowBias bias value to remove shadow acne.
+   * @note If the shadow bias is too large, the object will appear detached from the shadow.
+   */
+  void SetShadowBias(float shadowBias);
+
+  /**
+   * @brief Retrieves shadow bias value.
+   * @SINCE_2_2.43
+   * @return Shadow bias value.
+   */
+  float GetShadowBias() const;
+
 public: // Not intended for application developers
   /// @cond internal
   /**
index eb87ae1..4fc6ac3 100644 (file)
@@ -345,6 +345,14 @@ TextureSet MaterialDefinition::Load(const EnvironmentDefinition::Vector& environ
     ++n;
   }
 
+  if(mShadowAvailable)
+  {
+    PixelData shadowMapPixelData = PixelData::New(new uint8_t[3]{0xff, 0xff, 0xff}, 3, 1, 1, Pixel::RGB888, PixelData::DELETE_ARRAY);
+    Texture   shadowMapTexture   = Texture::New(TextureType::TEXTURE_2D, shadowMapPixelData.GetPixelFormat(), shadowMapPixelData.GetWidth(), shadowMapPixelData.GetHeight());
+    shadowMapTexture.Upload(shadowMapPixelData, 0, 0, 0, 0, shadowMapPixelData.GetWidth(), shadowMapPixelData.GetHeight());
+    textureSet.SetTexture(n++, shadowMapTexture);
+  }
+
   // Assign textures to slots -- starting with 2D ones, then cubemaps, if any.
   if(mEnvironmentIdx < static_cast<Index>(environments.size()))
   {
index b8da495..43dabc1 100644 (file)
@@ -251,6 +251,8 @@ public: // DATA
   bool                             mIsOpaque      = true;
   bool                             mIsMask        = false;
 
+  bool mShadowAvailable = false;
+
   std::vector<TextureStage> mTextureStages;
   Material                  mMaterial;
 };
index 2796340..49ff885 100644 (file)
@@ -18,6 +18,9 @@
 // CLASS HEADER
 #include <dali-scene3d/public-api/loader/shader-definition.h>
 
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/property-array.h>
+
 // INTERNAL INCLUDES
 #include <dali-scene3d/internal/graphics/builtin-shader-extern-gen.h>
 #include <dali-scene3d/public-api/loader/utils.h>
@@ -100,8 +103,10 @@ ShaderDefinition::LoadRaw(const std::string& shadersPath) const
   }
   else
   {
-    raw.mVertexShaderSource   = SHADER_DEFAULT_PHYSICALLY_BASED_SHADER_VERT.data();
-    raw.mFragmentShaderSource = SHADER_DEFAULT_PHYSICALLY_BASED_SHADER_FRAG.data();
+    raw.mVertexShaderSource         = SHADER_DEFAULT_PHYSICALLY_BASED_SHADER_VERT.data();
+    raw.mFragmentShaderSource       = SHADER_DEFAULT_PHYSICALLY_BASED_SHADER_FRAG.data();
+    raw.mShadowVertexShaderSource   = SHADER_SHADOW_MAP_SHADER_VERT.data();
+    raw.mShadowFragmentShaderSource = SHADER_SHADOW_MAP_SHADER_FRAG.data();
   }
 
   if(!fail)
@@ -110,6 +115,7 @@ ShaderDefinition::LoadRaw(const std::string& shadersPath) const
     {
       ApplyDefine(raw.mVertexShaderSource, definevar);
       ApplyDefine(raw.mFragmentShaderSource, definevar);
+      ApplyDefine(raw.mShadowVertexShaderSource, definevar);
     }
   }
 
@@ -131,7 +137,21 @@ Shader ShaderDefinition::Load(RawData&& raw) const
     }
   }
 
-  Shader shader = Shader::New(raw.mVertexShaderSource, raw.mFragmentShaderSource, static_cast<Shader::Hint::Value>(hints));
+  Property::Map map[2];
+  map[0]["vertex"]        = raw.mVertexShaderSource;
+  map[0]["fragment"]      = raw.mFragmentShaderSource;
+  map[0]["renderPassTag"] = 0;
+  map[0]["hints"]         = static_cast<Shader::Hint::Value>(hints);
+
+  map[1]["vertex"]        = raw.mShadowVertexShaderSource;
+  map[1]["fragment"]      = raw.mShadowFragmentShaderSource;
+  map[1]["renderPassTag"] = 10;
+
+  Property::Array array;
+  array.PushBack(map[0]);
+  array.PushBack(map[1]);
+
+  Shader shader = Shader::New(array);
   for(Property::Map::SizeType i0 = 0, i1 = mUniforms.Count(); i0 != i1; ++i0)
   {
     auto pair = mUniforms.GetKeyValue(i0);
index 61f4a7c..0fe83d3 100644 (file)
@@ -40,6 +40,8 @@ struct DALI_SCENE3D_API ShaderDefinition
   {
     std::string mVertexShaderSource;
     std::string mFragmentShaderSource;
+    std::string mShadowVertexShaderSource;
+    std::string mShadowFragmentShaderSource;
   };
 
   /*
index df8e16a..f4f6f34 100644 (file)
 #include <dali-scene3d/public-api/loader/blend-shape-details.h>
 #include <dali-scene3d/public-api/loader/node-definition.h>
 
+#include <dali/integration-api/debug.h>
+
 namespace Dali::Scene3D::Loader
 {
 namespace
 {
-static constexpr uint32_t INDEX_FOR_LIGHT_CONSTRAINT_TAG = 10;
+static constexpr uint32_t INDEX_FOR_LIGHT_CONSTRAINT_TAG  = 10;
+static constexpr uint32_t INDEX_FOR_SHADOW_CONSTRAINT_TAG = 100;
 
 ShaderOption MakeOption(const MaterialDefinition& materialDef, const MeshDefinition& meshDef)
 {
@@ -162,6 +165,8 @@ struct ShaderManager::Impl
   std::map<uint64_t, Index>   mShaderMap;
   std::vector<Dali::Shader>   mShaders;
   std::vector<Scene3D::Light> mLights;
+
+  Scene3D::Light mShadowLight;
 };
 
 ShaderManager::ShaderManager()
@@ -209,6 +214,13 @@ Dali::Shader ShaderManager::ProduceShader(const ShaderOption& shaderOption)
     {
       SetLightConstraintToShader(index, result);
     }
+
+    result.RegisterProperty("uIsShadowEnabled", static_cast<int32_t>(!!mImpl->mShadowLight));
+    if(!!mImpl->mShadowLight)
+    {
+      SetShadowConstraintToShader(result);
+      SetShadowUniformToShader(result);
+    }
   }
 
   return result;
@@ -288,6 +300,42 @@ uint32_t ShaderManager::GetLightCount() const
   return mImpl->mLights.size();
 }
 
+void ShaderManager::SetShadow(Scene3D::Light light)
+{
+  mImpl->mShadowLight = light;
+  for(auto&& shader : mImpl->mShaders)
+  {
+    std::string shadowEnabledPropertyName(Scene3D::Internal::Light::GetShadowEnabledUniformName());
+    shader.RegisterProperty(shadowEnabledPropertyName, static_cast<int32_t>(true));
+  }
+
+  SetShadowProperty();
+}
+
+void ShaderManager::RemoveShadow()
+{
+  for(auto&& shader : mImpl->mShaders)
+  {
+    std::string shadowEnabledPropertyName(Scene3D::Internal::Light::GetShadowEnabledUniformName());
+    shader.RegisterProperty(shadowEnabledPropertyName, static_cast<int32_t>(false));
+    shader.RemoveConstraints(INDEX_FOR_SHADOW_CONSTRAINT_TAG);
+  }
+  mImpl->mShadowLight.Reset();
+}
+
+void ShaderManager::UpdateShadowUniform(Scene3D::Light light)
+{
+  if(light != mImpl->mShadowLight)
+  {
+    return;
+  }
+
+  for(auto&& shader : mImpl->mShaders)
+  {
+    SetShadowUniformToShader(shader);
+  }
+}
+
 void ShaderManager::SetLightConstraint(uint32_t lightIndex)
 {
   for(auto&& shader : mImpl->mShaders)
@@ -323,4 +371,49 @@ void ShaderManager::RemoveLightConstraint(uint32_t lightIndex)
   }
 }
 
+void ShaderManager::SetShadowUniformToShader(Dali::Shader shader)
+{
+  shader.RegisterProperty("uShadowIntensity", mImpl->mShadowLight.GetShadowIntensity());
+  shader.RegisterProperty("uShadowBias", mImpl->mShadowLight.GetShadowBias());
+  shader.RegisterProperty("uEnableShadowSoftFiltering", static_cast<int>(mImpl->mShadowLight.IsShadowSoftFilteringEnabled()));
+}
+
+void ShaderManager::SetShadowProperty()
+{
+  for(auto&& shader : mImpl->mShaders)
+  {
+    SetShadowUniformToShader(shader);
+    SetShadowConstraintToShader(shader);
+  }
+}
+
+void ShaderManager::SetShadowConstraintToShader(Dali::Shader shader)
+{
+  // Constraint is applied before View/Projection Matrix is computed in update thread.
+  // So, it could show not plausible result if camera properties are changed discontinuesly.
+  // If we want to make it be synchronized, View/Projection matrix are needed to be conputed in below constraint.
+
+  std::string       shadowViewProjectionPropertyName(Scene3D::Internal::Light::GetShadowViewProjectionMatrixUniformName());
+  auto              shadowViewProjectionPropertyIndex = shader.RegisterProperty(shadowViewProjectionPropertyName, Matrix::IDENTITY);
+  Dali::CameraActor shadowLightCamera                 = Dali::Scene3D::Internal::GetImplementation(mImpl->mShadowLight).GetCamera();
+  auto              tempViewMatrixIndex               = shadowLightCamera.GetPropertyIndex("tempViewMatrix");
+  if(tempViewMatrixIndex != Dali::Property::INVALID_INDEX)
+  {
+    tempViewMatrixIndex = shadowLightCamera.RegisterProperty("tempViewMatrix", Matrix::IDENTITY);
+  }
+  auto tempProjectionMatrixIndex = shadowLightCamera.GetPropertyIndex("tempProjectionMatrix");
+  if(tempProjectionMatrixIndex != Dali::Property::INVALID_INDEX)
+  {
+    tempProjectionMatrixIndex = shadowLightCamera.RegisterProperty("tempProjectionMatrix", Matrix::IDENTITY);
+  }
+  Dali::Constraint shadowViewProjectionConstraint = Dali::Constraint::New<Matrix>(shader, shadowViewProjectionPropertyIndex, [](Matrix& output, const PropertyInputContainer& inputs)
+                                                                                  {
+                                                                                    output = inputs[1]->GetMatrix() * inputs[0]->GetMatrix(); });
+
+  shadowViewProjectionConstraint.AddSource(Source{shadowLightCamera, tempViewMatrixIndex});
+  shadowViewProjectionConstraint.AddSource(Source{shadowLightCamera, tempProjectionMatrixIndex});
+  shadowViewProjectionConstraint.ApplyPost();
+  shadowViewProjectionConstraint.SetTag(INDEX_FOR_SHADOW_CONSTRAINT_TAG);
+}
+
 } // namespace Dali::Scene3D::Loader
index 56adf38..4ca1384 100644 (file)
@@ -93,6 +93,24 @@ public:
    */
   uint32_t GetLightCount() const;
 
+  /**
+   * @brief Set a shadow to this scene by input light.
+   *
+   * @param[in] light Light object to make shadow.
+   */
+  void SetShadow(Scene3D::Light light);
+
+  /**
+   * @brief Removes Shadow from this SceneView.
+   */
+  void RemoveShadow();
+
+  /**
+   * @brief Update uniform properties of shadow for the input light.
+   * @param[in] light Light object to update shadow uniform.
+   */
+  void UpdateShadowUniform(Scene3D::Light light);
+
 private:
   /**
    * @brief Sets constraint to the shaders with light of light index.
@@ -112,6 +130,23 @@ private:
    * @param[in] lightIndex index of light that will be disconnected with shaders.
    */
   DALI_INTERNAL void RemoveLightConstraint(uint32_t lightIndex);
+
+  /**
+   * @brief Sets uniform about the shadow.
+   * @param[in] shader Shader that the constraint will be applied.
+   */
+  DALI_INTERNAL void SetShadowUniformToShader(Dali::Shader shader);
+
+  /**
+   * @brief Sets properties and constraint to the shaders.
+   */
+  DALI_INTERNAL void SetShadowProperty();
+
+  /**
+   * @brief Sets constraint to a shader about shadow
+   * @param[in] shader Shader that the constraint will be applied.
+   */
+  DALI_INTERNAL void SetShadowConstraintToShader(Dali::Shader shader);
 private:
   struct Impl;
   const std::unique_ptr<Impl> mImpl;
index a175eb3..b17e79d 100644 (file)
@@ -20,8 +20,8 @@
 
 // EXTERNAL INCLUDES
 #include <dali-toolkit/devel-api/toolkit-action-index-ranges.h>
-#include <dali-toolkit/devel-api/visuals/image-visual-actions-devel.h>
 #include <dali-toolkit/devel-api/visuals/animated-image-visual-actions-devel.h>
+#include <dali-toolkit/devel-api/visuals/image-visual-actions-devel.h>
 #include <dali/public-api/signals/callback.h>
 #include <string>
 
@@ -48,7 +48,9 @@ enum Type
   JUMP_TO = DevelAnimatedImageVisual::Action::JUMP_TO, ///< Jump to the specified frame. Property::INTEGER value should be passed.
 
   // AnimatedVectorImageVisual only actions
-  SET_DYNAMIC_PROPERTY = DevelAnimatedImageVisual::Action::ANIMATED_IMAGE_VISUAL_ACTION_END_INDEX ///< Set the dynamic property.
+  SET_DYNAMIC_PROPERTY = DevelAnimatedImageVisual::Action::ANIMATED_IMAGE_VISUAL_ACTION_END_INDEX, ///< Set the dynamic property.
+
+  FLUSH, ///< Flush animation data. It will make ensure that changeness of animated vector image properties flushed.
 };
 
 } // namespace Action
index e713486..aef9910 100644 (file)
@@ -1100,10 +1100,16 @@ void TextLabel::OnRelayout(const Vector2& size, RelayoutContainer& container)
       layoutSize.width = maxTextureSize;
     }
 
+    // This affects font rendering quality.
+    // It need to be integerized.
+    Vector2 visualTransformOffset;
+    visualTransformOffset.x = roundf(padding.start + alignmentOffset.x);
+    visualTransformOffset.y = roundf(padding.top + alignmentOffset.y);
+
     Property::Map visualTransform;
     visualTransform.Add(Toolkit::Visual::Transform::Property::SIZE, layoutSize)
       .Add(Toolkit::Visual::Transform::Property::SIZE_POLICY, Vector2(Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE))
-      .Add(Toolkit::Visual::Transform::Property::OFFSET, Vector2(padding.start, padding.top) + alignmentOffset)
+      .Add(Toolkit::Visual::Transform::Property::OFFSET, visualTransformOffset)
       .Add(Toolkit::Visual::Transform::Property::OFFSET_POLICY, Vector2(Toolkit::Visual::Transform::Policy::ABSOLUTE, Toolkit::Visual::Transform::Policy::ABSOLUTE))
       .Add(Toolkit::Visual::Transform::Property::ORIGIN, Toolkit::Align::TOP_BEGIN)
       .Add(Toolkit::Visual::Transform::Property::ANCHOR_POINT, Toolkit::Align::TOP_BEGIN);
index 8a4ada9..8da0313 100644 (file)
@@ -557,6 +557,14 @@ void AnimatedVectorImageVisual::OnDoAction(const Property::Index actionId, const
       }
       break;
     }
+    case DevelAnimatedVectorImageVisual::Action::FLUSH:
+    {
+      if(DALI_LIKELY(!mCoreShutdown))
+      {
+        SendAnimationData();
+      }
+      break;
+    }
   }
 
   TriggerVectorRasterization();
index c19a440..6bb0d13 100644 (file)
@@ -215,7 +215,7 @@ void VectorAnimationTask::SetAnimationData(const AnimationData& data)
 
   uint32_t index = mAnimationDataIndex == 0 ? 1 : 0; // Use the other buffer
 
-  mAnimationData[index] = data;
+  mAnimationData[index].push_back(data);
   mAnimationDataUpdated = true;
 
   if(data.resendFlag & VectorAnimationTask::RESEND_SIZE)
@@ -660,7 +660,7 @@ void VectorAnimationTask::ApplyAnimationData()
   {
     ConditionalWait::ScopedLock lock(mConditionalWait);
 
-    if(!mAnimationDataUpdated || mAnimationData[mAnimationDataIndex].resendFlag != 0)
+    if(!mAnimationDataUpdated || mAnimationData[mAnimationDataIndex].size() != 0)
     {
       // Data is not updated or the previous data is not applied yet.
       return;
@@ -672,63 +672,65 @@ void VectorAnimationTask::ApplyAnimationData()
     index = mAnimationDataIndex;
   }
 
-  if(mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_LOOP_COUNT)
+  for(const auto& animationData : mAnimationData[index])
   {
-    SetLoopCount(mAnimationData[index].loopCount);
-  }
-
-  if(mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_PLAY_RANGE)
-  {
-    SetPlayRange(mAnimationData[index].playRange);
-  }
-
-  if(mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_STOP_BEHAVIOR)
-  {
-    SetStopBehavior(mAnimationData[index].stopBehavior);
-  }
+    if(animationData.resendFlag & VectorAnimationTask::RESEND_LOOP_COUNT)
+    {
+      SetLoopCount(animationData.loopCount);
+    }
 
-  if(mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_LOOPING_MODE)
-  {
-    SetLoopingMode(mAnimationData[index].loopingMode);
-  }
+    if(animationData.resendFlag & VectorAnimationTask::RESEND_PLAY_RANGE)
+    {
+      SetPlayRange(animationData.playRange);
+    }
 
-  if(mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_CURRENT_FRAME)
-  {
-    SetCurrentFrameNumber(mAnimationData[index].currentFrame);
-  }
+    if(animationData.resendFlag & VectorAnimationTask::RESEND_STOP_BEHAVIOR)
+    {
+      SetStopBehavior(animationData.stopBehavior);
+    }
 
-  if(mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_NEED_RESOURCE_READY)
-  {
-    mVectorRenderer.InvalidateBuffer();
-  }
+    if(animationData.resendFlag & VectorAnimationTask::RESEND_LOOPING_MODE)
+    {
+      SetLoopingMode(animationData.loopingMode);
+    }
 
-  if(mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_DYNAMIC_PROPERTY)
-  {
-    for(auto&& iter : mAnimationData[index].dynamicProperties)
+    if(animationData.resendFlag & VectorAnimationTask::RESEND_CURRENT_FRAME)
     {
-      mVectorRenderer.AddPropertyValueCallback(iter.keyPath, static_cast<VectorAnimationRenderer::VectorProperty>(iter.property), iter.callback, iter.id);
+      SetCurrentFrameNumber(animationData.currentFrame);
     }
-  }
 
-  if(mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_PLAY_STATE)
-  {
-    if(mAnimationData[index].playState == DevelImageVisual::PlayState::PLAYING)
+    if(animationData.resendFlag & VectorAnimationTask::RESEND_NEED_RESOURCE_READY)
     {
-      PlayAnimation();
+      mVectorRenderer.InvalidateBuffer();
     }
-    else if(mAnimationData[index].playState == DevelImageVisual::PlayState::PAUSED)
+
+    if(animationData.resendFlag & VectorAnimationTask::RESEND_DYNAMIC_PROPERTY)
     {
-      PauseAnimation();
+      for(auto&& iter : animationData.dynamicProperties)
+      {
+        mVectorRenderer.AddPropertyValueCallback(iter.keyPath, static_cast<VectorAnimationRenderer::VectorProperty>(iter.property), iter.callback, iter.id);
+      }
     }
-    else if(mAnimationData[index].playState == DevelImageVisual::PlayState::STOPPED)
+
+    if(animationData.resendFlag & VectorAnimationTask::RESEND_PLAY_STATE)
     {
-      StopAnimation();
+      if(animationData.playState == DevelImageVisual::PlayState::PLAYING)
+      {
+        PlayAnimation();
+      }
+      else if(animationData.playState == DevelImageVisual::PlayState::PAUSED)
+      {
+        PauseAnimation();
+      }
+      else if(animationData.playState == DevelImageVisual::PlayState::STOPPED)
+      {
+        StopAnimation();
+      }
     }
   }
 
-  // reset data
-  mAnimationData[index].dynamicProperties.clear();
-  mAnimationData[index].resendFlag = 0;
+  // reset data list
+  mAnimationData[index].clear();
 }
 
 void VectorAnimationTask::OnUploadCompleted()
index e1b80c3..fdf1e2c 100644 (file)
@@ -357,7 +357,7 @@ private:
 
   std::string                          mUrl;
   VectorAnimationRenderer              mVectorRenderer;
-  AnimationData                        mAnimationData[2];
+  std::vector<AnimationData>           mAnimationData[2];
   VectorAnimationThread&               mVectorAnimationThread;
   ConditionalWait                      mConditionalWait;
   ResourceReadySignalType              mResourceReadySignal;
index 81f6f7d..7e46322 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 = 41;
+const unsigned int TOOLKIT_MICRO_VERSION = 42;
 const char* const  TOOLKIT_BUILD_DATE    = __DATE__ " " __TIME__;
 
 #ifdef DEBUG_ENABLED
index 8ca77d2..dea398a 100644 (file)
@@ -67,6 +67,13 @@ Dali::Toolkit::ImageUrl GenerateUrl(const Dali::EncodedImageBuffer encodedImageB
   return Dali::Toolkit::ImageUrl::New(encodedImageBuffer);
 }
 
+Dali::Toolkit::ImageUrl GenerateDepthUrl(const Dali::FrameBuffer frameBuffer)
+{
+  Texture texture = Dali::DevelFrameBuffer::GetDepthTexture(frameBuffer);
+  Dali::Toolkit::ImageUrl imageUrl = Dali::Toolkit::ImageUrl::New(texture, false);
+  return imageUrl;
+}
+
 } // namespace Image
 
 } // namespace Toolkit
index f3675ef..bdb9996 100644 (file)
@@ -90,6 +90,15 @@ DALI_TOOLKIT_API Dali::Toolkit::ImageUrl GenerateUrl(const Dali::NativeImageSour
  */
 DALI_TOOLKIT_API Dali::Toolkit::ImageUrl GenerateUrl(const Dali::EncodedImageBuffer encodedImageBuffer);
 
+/**
+ * @brief Generate a Url of depth texture from frame buffer.
+ * This Url can be used in visuals to render the frame buffer.
+ * This method does not check for duplicates, If same frame buffer is entered multiple times, a different URL is returned each time.
+ * @param[in] frameBuffer the frame buffer to converted to Url
+ * @return the ImageUrl representing this frame buffer
+ */
+DALI_TOOLKIT_API Dali::Toolkit::ImageUrl GenerateDepthUrl(const Dali::FrameBuffer frameBuffer);
+
 } // namespace Image
 
 } // namespace Toolkit
index 431c5ce..48fab3d 100644 (file)
@@ -1,6 +1,6 @@
 Name:       dali2-toolkit
 Summary:    Dali 3D engine Toolkit
-Version:    2.2.41
+Version:    2.2.42
 Release:    1
 Group:      System/Libraries
 License:    Apache-2.0 and BSD-3-Clause and MIT