[Tizen] Makes Models use common shader manager 02/296902/4
authorseungho baek <sbsh.baek@samsung.com>
Mon, 19 Jun 2023 13:43:00 +0000 (22:43 +0900)
committerseungho baek <sbsh.baek@samsung.com>
Wed, 23 Aug 2023 04:51:40 +0000 (13:51 +0900)
 - In Scene3D, the responsibility for modifying the shader code or setting the shader's uniform variables was scattered across many classes.
 - When a uniform variable is added or the name of a uniform variable is changed in the shader code, there was a problem of repeating the same modification in multiple codes.
 - In this patch, one class is responsible for creating or managing Shader code, and the class name is changed to ShaderManager.
 - And by using one ShaderManager per SceneView, it is easy to manage properties that should be applied in common within SceneView.
 - Although there is no difference in use in terms of Model/SceneView API, it is helpful for code management, and performance can be improved when many Renderers share a small number of Shaders.

Change-Id: I0975921a1a7e40c453156cf9bd0b1890fc8e6526
Signed-off-by: seungho baek <sbsh.baek@samsung.com>
32 files changed:
automated-tests/src/dali-scene3d-internal/utc-Dali-GlbLoaderImpl.cpp
automated-tests/src/dali-scene3d-internal/utc-Dali-Gltf2LoaderImpl.cpp
automated-tests/src/dali-scene3d-internal/utc-Dali-MaterialImpl.cpp
automated-tests/src/dali-scene3d/CMakeLists.txt
automated-tests/src/dali-scene3d/utc-Dali-ShaderDefinitionFactory.cpp [deleted file]
automated-tests/src/dali-scene3d/utc-Dali-ShaderDefinitionOption.cpp [deleted file]
automated-tests/src/dali-scene3d/utc-Dali-ShaderManager.cpp [new file with mode: 0644]
automated-tests/src/dali-scene3d/utc-Dali-ShaderOption.cpp [new file with mode: 0644]
dali-scene3d/dali-scene3d.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/loader/gltf2-util.cpp
dali-scene3d/internal/loader/gltf2-util.h
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/file.list
dali-scene3d/public-api/loader/node-definition.cpp
dali-scene3d/public-api/loader/node-definition.h
dali-scene3d/public-api/loader/scene-definition.cpp
dali-scene3d/public-api/loader/shader-definition-factory.cpp [deleted file]
dali-scene3d/public-api/loader/shader-definition-factory.h [deleted file]
dali-scene3d/public-api/loader/shader-definition.h
dali-scene3d/public-api/loader/shader-manager.cpp [new file with mode: 0644]
dali-scene3d/public-api/loader/shader-manager.h [new file with mode: 0644]
dali-scene3d/public-api/loader/shader-option.cpp [moved from dali-scene3d/public-api/loader/shader-definition-option.cpp with 73% similarity]
dali-scene3d/public-api/loader/shader-option.h [moved from dali-scene3d/public-api/loader/shader-definition-option.h with 80% similarity]

index f3d8a93..14f5864 100644 (file)
@@ -22,7 +22,7 @@
 #include <dali-scene3d/public-api/loader/load-result.h>
 #include <dali-scene3d/public-api/loader/resource-bundle.h>
 #include <dali-scene3d/public-api/loader/scene-definition.h>
-#include <dali-scene3d/public-api/loader/shader-definition-factory.h>
+#include <dali-scene3d/public-api/loader/shader-manager.h>
 #include <dali-test-suite-utils.h>
 #include <string_view>
 
@@ -123,10 +123,6 @@ int UtcDaliGlbLoaderFailedToLoad(void)
 int UtcDaliGlbLoaderFailedToParse(void)
 {
   Context ctx;
-
-  ShaderDefinitionFactory sdf;
-  sdf.SetResources(ctx.resources);
-
   DALI_TEST_EQUAL(ctx.loader.LoadModel(TEST_RESOURCE_DIR "/invalid.glb", ctx.loadResult), false);
 
   DALI_TEST_EQUAL(0, ctx.scene.GetRoots().size());
@@ -135,7 +131,6 @@ int UtcDaliGlbLoaderFailedToParse(void)
   DALI_TEST_EQUAL(0, ctx.resources.mEnvironmentMaps.size());
   DALI_TEST_EQUAL(0, ctx.resources.mMaterials.size());
   DALI_TEST_EQUAL(0, ctx.resources.mMeshes.size());
-  DALI_TEST_EQUAL(0, ctx.resources.mShaders.size());
   DALI_TEST_EQUAL(0, ctx.resources.mSkeletons.size());
 
   DALI_TEST_EQUAL(0, ctx.cameras.size());
@@ -149,9 +144,6 @@ int UtcDaliGlbLoaderFailedToParse(void)
 int UtcDaliGlbLoaderSuccess1(void)
 {
   Context                 ctx;
-  ShaderDefinitionFactory sdf;
-  sdf.SetResources(ctx.resources);
-
   ctx.loader.LoadModel(TEST_RESOURCE_DIR "/BoxAnimated.glb", ctx.loadResult);
 
   DALI_TEST_EQUAL(1u, ctx.scene.GetRoots().size());
index 2fb05dc..8f2f1f5 100644 (file)
@@ -22,7 +22,7 @@
 #include <dali-scene3d/public-api/loader/load-result.h>
 #include <dali-scene3d/public-api/loader/resource-bundle.h>
 #include <dali-scene3d/public-api/loader/scene-definition.h>
-#include <dali-scene3d/public-api/loader/shader-definition-factory.h>
+#include <dali-scene3d/public-api/loader/shader-manager.h>
 #include <dali-test-suite-utils.h>
 #include <string_view>
 
@@ -125,9 +125,6 @@ int UtcDaliGltfLoaderFailedToParse(void)
 {
   Context ctx;
 
-  ShaderDefinitionFactory sdf;
-  sdf.SetResources(ctx.resources);
-
   DALI_TEST_EQUAL(ctx.loader.LoadModel(TEST_RESOURCE_DIR "/invalid.gltf", ctx.loadResult), false);
 
   DALI_TEST_EQUAL(0, ctx.scene.GetRoots().size());
@@ -136,7 +133,6 @@ int UtcDaliGltfLoaderFailedToParse(void)
   DALI_TEST_EQUAL(0, ctx.resources.mEnvironmentMaps.size());
   DALI_TEST_EQUAL(0, ctx.resources.mMaterials.size());
   DALI_TEST_EQUAL(0, ctx.resources.mMeshes.size());
-  DALI_TEST_EQUAL(0, ctx.resources.mShaders.size());
   DALI_TEST_EQUAL(0, ctx.resources.mSkeletons.size());
 
   DALI_TEST_EQUAL(0, ctx.cameras.size());
@@ -193,7 +189,7 @@ int UtcDaliGltfLoaderSuccess1(void)
       nullptr,
       MaterialDefinition::ALBEDO | MaterialDefinition::EMISSIVE | MaterialDefinition::OCCLUSION |
         MaterialDefinition::NORMAL | MaterialDefinition::SPECULAR | MaterialDefinition::SPECULAR_COLOR |
-        (0x80 << MaterialDefinition::ALPHA_CUTOFF_SHIFT),
+        MaterialDefinition::GLTF_CHANNELS | (0x80 << MaterialDefinition::ALPHA_CUTOFF_SHIFT),
       0,
       Color::WHITE,
       1.f,
@@ -306,7 +302,7 @@ int UtcDaliGltfLoaderSuccess1(void)
           },
         },
         {
-          MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS | MaterialDefinition::GLTF_CHANNELS,
+          MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS,
           {
             "AnimatedCube_MetallicRoughness.png",
             SamplerFlags::Encode(FilterMode::NEAREST_MIPMAP_LINEAR, FilterMode::NEAREST, WrapMode::CLAMP_TO_EDGE, WrapMode::MIRRORED_REPEAT),
@@ -448,7 +444,6 @@ int UtcDaliGltfLoaderSuccess1(void)
     ++iMesh;
   }
 
-  DALI_TEST_EQUAL(2u, ctx.resources.mShaders.size());
   DALI_TEST_EQUAL(0u, ctx.resources.mSkeletons.size());
 
   DALI_TEST_EQUAL(6u, ctx.cameras.size());
@@ -462,8 +457,6 @@ int UtcDaliGltfLoaderSuccess1(void)
 int UtcDaliGltfLoaderSuccess2(void)
 {
   Context                 ctx;
-  ShaderDefinitionFactory sdf;
-  sdf.SetResources(ctx.resources);
 
   ctx.loader.LoadModel(TEST_RESOURCE_DIR "/AnimatedCubeStride.gltf", ctx.loadResult);
 
@@ -576,9 +569,6 @@ int UtcDaliGltfLoaderSuccessShort(void)
 int UtcDaliGltfLoaderMRendererTest(void)
 {
   Context ctx;
-
-  ShaderDefinitionFactory sdf;
-  sdf.SetResources(ctx.resources);
   auto& resources = ctx.resources;
 
   ctx.loader.LoadModel(TEST_RESOURCE_DIR "/MRendererTest.gltf", ctx.loadResult);
@@ -591,6 +581,7 @@ int UtcDaliGltfLoaderMRendererTest(void)
 
   DALI_TEST_EQUAL(scene.GetNodeCount(), 1u);
 
+  Scene3D::Loader::ShaderManagerPtr shaderManager = new Scene3D::Loader::ShaderManager();
   ViewProjection viewProjection;
   Transforms     xforms{
     MatrixStack{},
@@ -598,6 +589,7 @@ int UtcDaliGltfLoaderMRendererTest(void)
   NodeDefinition::CreateParams nodeParams{
     resources,
     xforms,
+    shaderManager,
   };
 
   Customization::Choices choices;
@@ -647,6 +639,7 @@ int UtcDaliGltfLoaderAnimationLoadingTest(void)
   auto& roots = scene.GetRoots();
   DALI_TEST_EQUAL(roots.size(), 1u);
 
+  Scene3D::Loader::ShaderManagerPtr shaderManager = new Scene3D::Loader::ShaderManager();
   ViewProjection viewProjection;
   Transforms     xforms{
     MatrixStack{},
@@ -654,6 +647,7 @@ int UtcDaliGltfLoaderAnimationLoadingTest(void)
   NodeDefinition::CreateParams nodeParams{
     resources,
     xforms,
+    shaderManager,
   };
 
   Customization::Choices choices;
@@ -690,8 +684,6 @@ int UtcDaliGltfLoaderImageFromBufferView(void)
 {
   Context ctx;
 
-  ShaderDefinitionFactory sdf;
-  sdf.SetResources(ctx.resources);
   auto& resources = ctx.resources;
 
   ctx.loader.LoadModel(TEST_RESOURCE_DIR "/EnvironmentTest_b.gltf", ctx.loadResult);
@@ -700,6 +692,7 @@ int UtcDaliGltfLoaderImageFromBufferView(void)
   auto& roots = scene.GetRoots();
   DALI_TEST_EQUAL(roots.size(), 1u);
 
+  Scene3D::Loader::ShaderManagerPtr shaderManager = new Scene3D::Loader::ShaderManager();
   ViewProjection viewProjection;
   Transforms     xforms{
     MatrixStack{},
@@ -707,6 +700,7 @@ int UtcDaliGltfLoaderImageFromBufferView(void)
   NodeDefinition::CreateParams nodeParams{
     resources,
     xforms,
+    shaderManager,
   };
 
   Customization::Choices choices;
@@ -749,6 +743,7 @@ int UtcDaliGltfLoaderUint8Indices(void)
   auto& roots = scene.GetRoots();
   DALI_TEST_EQUAL(roots.size(), 1u);
 
+  Scene3D::Loader::ShaderManagerPtr shaderManager = new Scene3D::Loader::ShaderManager();
   ViewProjection viewProjection;
   Transforms     xforms{
     MatrixStack{},
@@ -756,6 +751,7 @@ int UtcDaliGltfLoaderUint8Indices(void)
   NodeDefinition::CreateParams nodeParams{
     resources,
     xforms,
+    shaderManager,
   };
 
   Customization::Choices choices;
index 34a82b2..e3bc2d2 100644 (file)
@@ -23,7 +23,7 @@
 
 #include <dali-scene3d/internal/graphics/builtin-shader-extern-gen.h>
 #include <dali-scene3d/internal/model-components/material-impl.h>
-#include <dali-scene3d/public-api/loader/shader-definition-option.h>
+#include <dali-scene3d/public-api/loader/shader-option.h>
 
 using namespace Dali;
 using namespace Dali::Toolkit;
@@ -96,20 +96,14 @@ int UtcDaliMaterialImplSetGetTextureInformation(void)
   DALI_TEST_EQUALS(true, GetImplementation(material).IsResourceReady(), TEST_LOCATION);
   GetImplementation(material).UpdateMaterialData();
 
-  std::vector<std::string> defines;
-  defines.push_back(Scene3D::Loader::ShaderDefinitionOption::GetDefineKeyword(Scene3D::Loader::ShaderDefinitionOption::Type::THREE_TEXTURE).data());
-  defines.push_back(Scene3D::Loader::ShaderDefinitionOption::GetDefineKeyword(Scene3D::Loader::ShaderDefinitionOption::Type::GLTF_CHANNELS).data());
-  defines.push_back(Scene3D::Loader::ShaderDefinitionOption::GetDefineKeyword(Scene3D::Loader::ShaderDefinitionOption::Type::BASE_COLOR_TEXTURE).data());
-  defines.push_back(Scene3D::Loader::ShaderDefinitionOption::GetDefineKeyword(Scene3D::Loader::ShaderDefinitionOption::Type::METALLIC_ROUGHNESS_TEXTURE).data());
-  defines.push_back(Scene3D::Loader::ShaderDefinitionOption::GetDefineKeyword(Scene3D::Loader::ShaderDefinitionOption::Type::NORMAL_TEXTURE).data());
+  Scene3D::Loader::ShaderOption option;
+  option.AddOption(Scene3D::Loader::ShaderOption::Type::THREE_TEXTURE);
+  option.AddOption(Scene3D::Loader::ShaderOption::Type::GLTF_CHANNELS);
+  option.AddOption(Scene3D::Loader::ShaderOption::Type::BASE_COLOR_TEXTURE);
+  option.AddOption(Scene3D::Loader::ShaderOption::Type::METALLIC_ROUGHNESS_TEXTURE);
+  option.AddOption(Scene3D::Loader::ShaderOption::Type::NORMAL_TEXTURE);
 
-  std::string fragmentShader = SHADER_DEFAULT_PHYSICALLY_BASED_SHADER_FRAG.data();
-  for(const auto& define : defines)
-  {
-    Scene3D::Loader::ShaderDefinition::ApplyDefine(fragmentShader, define);
-  }
-
-  DALI_TEST_EQUALS(fragmentShader, GetImplementation(material).GetFragmentShader(), TEST_LOCATION);
+  DALI_TEST_EQUALS(option.GetOptionHash(), GetImplementation(material).GetShaderOption().GetOptionHash(), TEST_LOCATION);
 
   Scene3D ::Internal ::Material ::TextureInformation occlusion;
   Dali ::Texture                                     occlusiontexture = Dali ::Texture ::New(TextureType ::TEXTURE_2D, Pixel ::RGBA8888, 100, 100);
@@ -176,18 +170,12 @@ int UtcDaliMaterialImplSetGetTextureInformation(void)
   DALI_TEST_EQUALS(true, GetImplementation(material).IsResourceReady(), TEST_LOCATION);
   GetImplementation(material).UpdateMaterialData();
 
-  defines.push_back(Scene3D::Loader::ShaderDefinitionOption::GetDefineKeyword(Scene3D::Loader::ShaderDefinitionOption::Type::OCCLUSION).data());
-  defines.push_back(Scene3D::Loader::ShaderDefinitionOption::GetDefineKeyword(Scene3D::Loader::ShaderDefinitionOption::Type::EMISSIVE).data());
-  defines.push_back(Scene3D::Loader::ShaderDefinitionOption::GetDefineKeyword(Scene3D::Loader::ShaderDefinitionOption::Type::SPECULAR).data());
-  defines.push_back(Scene3D::Loader::ShaderDefinitionOption::GetDefineKeyword(Scene3D::Loader::ShaderDefinitionOption::Type::SPECULAR_COLOR).data());
-
-  fragmentShader = SHADER_DEFAULT_PHYSICALLY_BASED_SHADER_FRAG.data();
-  for(const auto& define : defines)
-  {
-    Scene3D::Loader::ShaderDefinition::ApplyDefine(fragmentShader, define);
-  }
+  option.AddOption(Scene3D::Loader::ShaderOption::Type::OCCLUSION);
+  option.AddOption(Scene3D::Loader::ShaderOption::Type::EMISSIVE);
+  option.AddOption(Scene3D::Loader::ShaderOption::Type::SPECULAR);
+  option.AddOption(Scene3D::Loader::ShaderOption::Type::SPECULAR_COLOR);
 
-  DALI_TEST_EQUALS(fragmentShader, GetImplementation(material).GetFragmentShader(), TEST_LOCATION);
+  DALI_TEST_EQUALS(option.GetOptionHash(), GetImplementation(material).GetShaderOption().GetOptionHash(), TEST_LOCATION);
 
   END_TEST;
 }
index 032ccb9..093fd0f 100755 (executable)
@@ -34,8 +34,8 @@ SET(TC_SOURCES
   utc-Dali-ResourceBundle.cpp
   utc-Dali-SceneDefinition.cpp
   utc-Dali-ShaderDefinition.cpp
-  utc-Dali-ShaderDefinitionFactory.cpp
-  utc-Dali-ShaderDefinitionOption.cpp
+  utc-Dali-ShaderManager.cpp
+  utc-Dali-ShaderOption.cpp
   utc-Dali-StringCallback.cpp
   utc-Dali-Utils.cpp
   utc-Dali-ViewProjection.cpp
diff --git a/automated-tests/src/dali-scene3d/utc-Dali-ShaderDefinitionFactory.cpp b/automated-tests/src/dali-scene3d/utc-Dali-ShaderDefinitionFactory.cpp
deleted file mode 100644 (file)
index 0a269a5..0000000
+++ /dev/null
@@ -1,345 +0,0 @@
-/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// Enable debug log for test coverage
-#define DEBUG_ENABLED 1
-
-// Disable this UTC until shader definition factory refactorize
-#define ENABLE_SHADER_DEFINITION_FACTORY_UTC 0
-
-#include <dali-test-suite-utils.h>
-#include <set>
-#include <string_view>
-#include "dali-scene3d/public-api/loader/node-definition.h"
-#include "dali-scene3d/public-api/loader/resource-bundle.h"
-#include "dali-scene3d/public-api/loader/shader-definition-factory.h"
-
-using namespace Dali;
-using namespace Dali::Scene3D::Loader;
-
-namespace
-{
-#if ENABLE_SHADER_DEFINITION_FACTORY_UTC
-MaterialDefinition& NewMaterialDefinition(ResourceBundle& resources)
-{
-  resources.mMaterials.push_back({});
-  return resources.mMaterials.back().first;
-}
-
-MeshDefinition& NewMeshDefinition(ResourceBundle& resources)
-{
-  resources.mMeshes.push_back({});
-  return resources.mMeshes.back().first;
-}
-
-void ClearMeshesAndMaterials(ResourceBundle& resources)
-{
-  resources.mMaterials.clear();
-  resources.mMeshes.clear();
-}
-#endif
-
-struct Context
-{
-  ResourceBundle          resources;
-  ShaderDefinitionFactory factory;
-
-  Context()
-  {
-    factory.SetResources(resources);
-  }
-};
-
-#if ENABLE_SHADER_DEFINITION_FACTORY_UTC
-struct ShaderParameters
-{
-  MeshDefinition&     meshDef;
-  MaterialDefinition& materialDef;
-  NodeDefinition&     nodeDef;
-};
-
-struct Permutation
-{
-  using ConfigureFn = void (*)(ShaderParameters&);
-
-  ConfigureFn configureFn;
-
-  std::set<std::string> defines;
-  RendererState::Type   rendererStateSet   = 0;
-  RendererState::Type   rendererStateClear = 0;
-};
-
-struct PermutationSet
-{
-  std::vector<const Permutation*> permutations;
-  Index                           shaderIdx;
-};
-#endif
-
-} // namespace
-
-int UtcDaliShaderDefinitionFactoryProduceShaderInvalid(void)
-{
-  Context ctx;
-
-  NodeDefinition                              nodeDef;
-  std::unique_ptr<NodeDefinition::Renderable> renderable = std::unique_ptr<NodeDefinition::Renderable>(new NodeDefinition::Renderable());
-  nodeDef.mRenderables.push_back(std::move(renderable));
-
-  DALI_TEST_CHECK(ctx.resources.mShaders.empty());
-
-  END_TEST;
-}
-
-int UtcDaliShaderDefinitionFactoryProduceShader(void)
-{
-#if ENABLE_SHADER_DEFINITION_FACTORY_UTC
-  Context ctx;
-  ctx.resources.mMaterials.push_back({});
-  ctx.resources.mMeshes.push_back({});
-
-  Permutation permutations[]{
-    {
-      [](ShaderParameters& p) {},
-      {},
-      RendererState::DEPTH_TEST | RendererState::DEPTH_WRITE | RendererState::CULL_BACK,
-    },
-    {
-      [](ShaderParameters& p) {
-        p.materialDef.mFlags |= MaterialDefinition::TRANSPARENCY;
-      },
-      {"THREE_TEX"},
-      RendererState::ALPHA_BLEND,
-      RendererState::DEPTH_WRITE,
-    },
-    {[](ShaderParameters& p) {
-       p.materialDef.mFlags |= MaterialDefinition::ALBEDO;
-       p.materialDef.mTextureStages.push_back({MaterialDefinition::ALBEDO, {}});
-     },
-     {"THREE_TEX", "BASECOLOR_TEX"}},
-    {[](ShaderParameters& p) {
-       p.materialDef.mTextureStages.push_back({MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS, {}});
-     },
-     {"THREE_TEX", "METALLIC_ROUGHNESS_TEX"}},
-    {[](ShaderParameters& p) {
-       p.materialDef.mFlags |= MaterialDefinition::NORMAL;
-       p.materialDef.mTextureStages.push_back({MaterialDefinition::NORMAL, {}});
-     },
-     {"THREE_TEX", "NORMAL_TEX"}},
-    {[](ShaderParameters& p) {
-       p.materialDef.mFlags |= MaterialDefinition::SUBSURFACE;
-     },
-     {"SSS"}},
-    {[](ShaderParameters& p) {
-       p.materialDef.SetAlphaCutoff(.5f);
-     },
-     {"ALPHA_TEST"}},
-    {[](ShaderParameters& p) {
-       p.materialDef.SetAlphaCutoff(1.f);
-     },
-     {"ALPHA_TEST"}},
-    {[](ShaderParameters& p) {
-       p.materialDef.mFlags |= MaterialDefinition::GLTF_CHANNELS;
-     },
-     {"GLTF_CHANNELS"}},
-    {[](ShaderParameters& p) {
-       p.meshDef.mJoints0.mBlob.mOffset  = 0;
-       p.meshDef.mWeights0.mBlob.mOffset = 0;
-     },
-     {"SKINNING"}},
-    {[](ShaderParameters& p) {
-       p.meshDef.mFlags |= MeshDefinition::FLIP_UVS_VERTICAL;
-     },
-     {"FLIP_V"}},
-    {
-      [](ShaderParameters& p) {
-        p.meshDef.mBlendShapes.push_back({});
-      },
-    },
-    {[](ShaderParameters& p) {
-       p.meshDef.mBlendShapes.back().deltas.mBlob.mOffset = 0;
-     },
-     {"MORPH_POSITION", "MORPH"}},
-    {[](ShaderParameters& p) {
-       p.meshDef.mBlendShapes.back().normals.mBlob.mOffset = 0;
-     },
-     {"MORPH_NORMAL", "MORPH"}},
-    {[](ShaderParameters& p) {
-       p.meshDef.mBlendShapes.back().tangents.mBlob.mOffset = 0;
-     },
-     {"MORPH_TANGENT", "MORPH"}},
-    {[](ShaderParameters& p) {
-       auto& blendShapes = p.meshDef.mBlendShapes;
-       DALI_ASSERT_ALWAYS(!blendShapes.empty() &&
-                          (blendShapes.back().deltas.mBlob.mOffset != MeshDefinition::INVALID ||
-                           blendShapes.back().normals.mBlob.mOffset != MeshDefinition::INVALID ||
-                           blendShapes.back().tangents.mBlob.mOffset != MeshDefinition::INVALID));
-       p.meshDef.mBlendShapeVersion = BlendShapes::Version::VERSION_2_0;
-     },
-     {"MORPH_VERSION_2_0"}},
-
-    {[](ShaderParameters& p) {
-       p.materialDef.mFlags |= MaterialDefinition::OCCLUSION;
-     },
-
-     {"OCCLUSION"}},
-
-    {[](ShaderParameters& p) {
-       p.meshDef.mColors.mBlob.mOffset = 0;
-     },
-     {"COLOR_ATTRIBUTE"}},
-    {[](ShaderParameters& p) {
-       p.meshDef.mTangentType = Property::VECTOR4;
-     },
-     {"VEC4_TANGENT"}},
-  };
-
-  PermutationSet permSets[]{
-    // default
-    {{&permutations[0]}, 0},
-
-    // alpha
-    {{&permutations[0], &permutations[1]}, 1},
-
-    // three-texture setups
-    {{&permutations[0], &permutations[2]}, 2},
-    {{&permutations[0], &permutations[3]}, 2},
-    {{&permutations[0], &permutations[4]}, 2},
-    {{&permutations[0], &permutations[2], &permutations[3]}, 2},
-    {{&permutations[0], &permutations[3], &permutations[4]}, 2},
-    {{&permutations[0], &permutations[4], &permutations[2]}, 2},
-    {{&permutations[0], &permutations[2], &permutations[3], &permutations[4]}, 2},
-
-    // subsurface scattering
-    {{&permutations[0], &permutations[5]}, 3},
-
-    // alpha test
-    {{&permutations[0], &permutations[6]}, 4},
-    {{&permutations[0], &permutations[7]}, 4},
-
-    // glTF channels
-    {{&permutations[0], &permutations[8]}, 5},
-
-    // skinning
-    {{&permutations[0], &permutations[9]}, 6},
-
-    // flip uvs
-    {{&permutations[0], &permutations[10]}, 7},
-
-    // morphing
-    {{&permutations[0], &permutations[11], &permutations[12]}, 8},
-    {{&permutations[0], &permutations[11], &permutations[13]}, 9},
-    {{&permutations[0], &permutations[11], &permutations[14]}, 10},
-    {{&permutations[0], &permutations[11], &permutations[12], &permutations[13]}, 11},
-    {{&permutations[0], &permutations[11], &permutations[13], &permutations[14]}, 12},
-    {{&permutations[0], &permutations[11], &permutations[14], &permutations[12]}, 13},
-    {{&permutations[0], &permutations[11], &permutations[12], &permutations[13], &permutations[14]}, 14},
-
-    {{&permutations[0], &permutations[11], &permutations[12], &permutations[15]}, 15},
-    {{&permutations[0], &permutations[11], &permutations[13], &permutations[15]}, 16},
-    {{&permutations[0], &permutations[11], &permutations[14], &permutations[15]}, 17},
-    {{&permutations[0], &permutations[11], &permutations[12], &permutations[13], &permutations[15]}, 18},
-    {{&permutations[0], &permutations[11], &permutations[13], &permutations[14], &permutations[15]}, 19},
-    {{&permutations[0], &permutations[11], &permutations[14], &permutations[12], &permutations[15]}, 20},
-    {{&permutations[0], &permutations[11], &permutations[12], &permutations[13], &permutations[14], &permutations[15]}, 21},
-
-    // etc.
-    {{&permutations[0], &permutations[1], &permutations[2]}, 1},
-    {{&permutations[0], &permutations[1], &permutations[3]}, 1},
-    {{&permutations[0], &permutations[1], &permutations[2], &permutations[3]}, 1},
-
-    // occlusion
-    {{&permutations[0], &permutations[16]}, 22},
-  };
-
-  for(auto& ps : permSets)
-  {
-    static int tc = 0;
-    tet_printf("Test %d's tc\n", ++tc);
-    auto modelRenderable          = new ModelRenderable();
-    modelRenderable->mMeshIdx     = 0;
-    modelRenderable->mMaterialIdx = 0;
-
-    NodeDefinition                              nodeDef;
-    std::unique_ptr<NodeDefinition::Renderable> renderable;
-    renderable.reset(modelRenderable);
-    nodeDef.mRenderables.push_back(std::move(renderable));
-
-    auto&            meshDef     = NewMeshDefinition(ctx.resources);
-    auto&            materialDef = NewMaterialDefinition(ctx.resources);
-    ShaderParameters sp{meshDef, materialDef, nodeDef};
-
-    std::set<std::string> defines;
-    RendererState::Type   rendererState = 0;
-    for(auto p : ps.permutations)
-    {
-      p->configureFn(sp);
-      defines.insert(p->defines.begin(), p->defines.end());
-      rendererState = (rendererState | p->rendererStateSet) & ~p->rendererStateClear;
-    }
-
-    for(auto& renderable : nodeDef.mRenderables)
-    {
-      auto shaderIdx = ctx.factory.ProduceShader(*renderable);
-      DALI_TEST_EQUAL(ps.shaderIdx, shaderIdx);
-
-      auto& shaderDef = ctx.resources.mShaders[shaderIdx].first;
-      DALI_TEST_EQUAL(shaderDef.mRendererState, rendererState);
-
-      uint32_t definesUnmatched = shaderDef.mDefines.size();
-      for(auto& define : shaderDef.mDefines)
-      {
-        auto iFind = defines.find(define);
-        if(iFind != defines.end())
-        {
-          defines.erase(iFind);
-          --definesUnmatched;
-        }
-        else
-        {
-          break;
-        }
-      }
-      if(!defines.empty())
-      {
-        std::ostringstream oss;
-        oss << "Need to check below defines :\n";
-        for(auto& it : defines)
-        {
-          oss << it << "\n";
-        }
-        tet_printf("%s\n", oss.str().c_str());
-      }
-
-      DALI_TEST_CHECK(defines.empty());
-      DALI_TEST_EQUAL(0, definesUnmatched);
-
-      auto uMaxLOD = shaderDef.mUniforms["uMaxLOD"];
-      DALI_TEST_EQUAL(uMaxLOD.GetType(), Property::FLOAT);
-
-      auto uCubeMatrix = shaderDef.mUniforms["uCubeMatrix"];
-      DALI_TEST_EQUAL(uCubeMatrix.GetType(), Property::MATRIX);
-    }
-
-    ClearMeshesAndMaterials(ctx.resources);
-  }
-#else
-  DALI_TEST_CHECK(true);
-#endif
-
-  END_TEST;
-}
\ No newline at end of file
diff --git a/automated-tests/src/dali-scene3d/utc-Dali-ShaderDefinitionOption.cpp b/automated-tests/src/dali-scene3d/utc-Dali-ShaderDefinitionOption.cpp
deleted file mode 100644 (file)
index 0f320a8..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#include <dali-test-suite-utils.h>
-#include <dali-toolkit/dali-toolkit.h>
-#include <string_view>
-#include "dali-scene3d/public-api/loader/shader-definition-option.h"
-
-using namespace Dali;
-using namespace Dali::Toolkit;
-
-void shader_definition_option_startup(void)
-{
-  test_return_value = TET_UNDEF;
-}
-
-void shader_definition_option_cleanup(void)
-{
-  test_return_value = TET_PASS;
-}
-
-int UtcDaliShaderDefinitionOptionInit(void)
-{
-  Scene3D::Loader::ShaderDefinitionOption option;
-  DALI_TEST_EQUALS(option.GetOptionHash(), 0u, TEST_LOCATION);
-  END_TEST;
-}
-
-int UtcDaliShaderDefinitionOptionSetTransparency(void)
-{
-  Scene3D::Loader::ShaderDefinitionOption option;
-  DALI_TEST_EQUALS(option.GetOptionHash(), 0u, TEST_LOCATION);
-
-  option.SetTransparency();
-  DALI_TEST_NOT_EQUALS(option.GetOptionHash(), static_cast<uint64_t>(0u), 0.1f, TEST_LOCATION);
-
-  END_TEST;
-}
-
-int UtcDaliShaderDefinitionOptionAddOption(void)
-{
-  Scene3D::Loader::ShaderDefinitionOption option;
-  DALI_TEST_EQUALS(option.GetOptionHash(), 0u, TEST_LOCATION);
-
-  Scene3D::Loader::ShaderDefinitionOption::Type types[19] = {
-    Scene3D::Loader::ShaderDefinitionOption::Type::GLTF_CHANNELS,
-    Scene3D::Loader::ShaderDefinitionOption::Type::THREE_TEXTURE,
-    Scene3D::Loader::ShaderDefinitionOption::Type::BASE_COLOR_TEXTURE,
-    Scene3D::Loader::ShaderDefinitionOption::Type::METALLIC_ROUGHNESS_TEXTURE,
-    Scene3D::Loader::ShaderDefinitionOption::Type::NORMAL_TEXTURE,
-    Scene3D::Loader::ShaderDefinitionOption::Type::OCCLUSION,
-    Scene3D::Loader::ShaderDefinitionOption::Type::EMISSIVE,
-    Scene3D::Loader::ShaderDefinitionOption::Type::ALPHA_TEST,
-    Scene3D::Loader::ShaderDefinitionOption::Type::SUBSURFACE,
-    Scene3D::Loader::ShaderDefinitionOption::Type::SPECULAR,
-    Scene3D::Loader::ShaderDefinitionOption::Type::SPECULAR_COLOR,
-    Scene3D::Loader::ShaderDefinitionOption::Type::SKINNING,
-    Scene3D::Loader::ShaderDefinitionOption::Type::FLIP_UVS_VERTICAL,
-    Scene3D::Loader::ShaderDefinitionOption::Type::COLOR_ATTRIBUTE,
-    Scene3D::Loader::ShaderDefinitionOption::Type::VEC4_TANGENT,
-    Scene3D::Loader::ShaderDefinitionOption::Type::MORPH_POSITION,
-    Scene3D::Loader::ShaderDefinitionOption::Type::MORPH_NORMAL,
-    Scene3D::Loader::ShaderDefinitionOption::Type::MORPH_TANGENT,
-    Scene3D::Loader::ShaderDefinitionOption::Type::MORPH_VERSION_2_0};
-
-  uint64_t hash = 0u;
-  for(uint32_t i = 0; i < 19; ++i)
-  {
-    hash |= (1 << static_cast<uint32_t>(types[i]));
-    option.AddOption(types[i]);
-    DALI_TEST_EQUALS(option.GetOptionHash(), hash, TEST_LOCATION);
-  }
-
-  END_TEST;
-}
-
-int UtcDaliShaderDefinitionOptionGetDefines(void)
-{
-  Scene3D::Loader::ShaderDefinitionOption option;
-  DALI_TEST_EQUALS(option.GetOptionHash(), 0u, TEST_LOCATION);
-
-  Scene3D::Loader::ShaderDefinitionOption::Type types[19] = {
-    Scene3D::Loader::ShaderDefinitionOption::Type::GLTF_CHANNELS,
-    Scene3D::Loader::ShaderDefinitionOption::Type::THREE_TEXTURE,
-    Scene3D::Loader::ShaderDefinitionOption::Type::BASE_COLOR_TEXTURE,
-    Scene3D::Loader::ShaderDefinitionOption::Type::METALLIC_ROUGHNESS_TEXTURE,
-    Scene3D::Loader::ShaderDefinitionOption::Type::NORMAL_TEXTURE,
-    Scene3D::Loader::ShaderDefinitionOption::Type::OCCLUSION,
-    Scene3D::Loader::ShaderDefinitionOption::Type::EMISSIVE,
-    Scene3D::Loader::ShaderDefinitionOption::Type::ALPHA_TEST,
-    Scene3D::Loader::ShaderDefinitionOption::Type::SUBSURFACE,
-    Scene3D::Loader::ShaderDefinitionOption::Type::SPECULAR,
-    Scene3D::Loader::ShaderDefinitionOption::Type::SPECULAR_COLOR,
-    Scene3D::Loader::ShaderDefinitionOption::Type::SKINNING,
-    Scene3D::Loader::ShaderDefinitionOption::Type::FLIP_UVS_VERTICAL,
-    Scene3D::Loader::ShaderDefinitionOption::Type::COLOR_ATTRIBUTE,
-    Scene3D::Loader::ShaderDefinitionOption::Type::VEC4_TANGENT,
-    Scene3D::Loader::ShaderDefinitionOption::Type::MORPH_POSITION,
-    Scene3D::Loader::ShaderDefinitionOption::Type::MORPH_NORMAL,
-    Scene3D::Loader::ShaderDefinitionOption::Type::MORPH_TANGENT,
-    Scene3D::Loader::ShaderDefinitionOption::Type::MORPH_VERSION_2_0};
-
-  uint64_t hash = 0u;
-  for(uint32_t i = 0; i < 19; ++i)
-  {
-    hash |= (1 << static_cast<uint32_t>(types[i]));
-    option.AddOption(types[i]);
-    DALI_TEST_EQUALS(option.GetOptionHash(), hash, TEST_LOCATION);
-
-    std::vector<std::string> defines;
-    option.GetDefines(defines);
-    DALI_TEST_EQUALS(defines.size(), i + 1, TEST_LOCATION);
-    for(uint32_t j = 0; j < defines.size(); ++j)
-    {
-      DALI_TEST_EQUALS(defines[j], option.GetDefineKeyword(types[j]), TEST_LOCATION);
-    }
-  }
-
-  END_TEST;
-}
\ No newline at end of file
diff --git a/automated-tests/src/dali-scene3d/utc-Dali-ShaderManager.cpp b/automated-tests/src/dali-scene3d/utc-Dali-ShaderManager.cpp
new file mode 100644 (file)
index 0000000..b8c3b35
--- /dev/null
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// Enable debug log for test coverage
+#define DEBUG_ENABLED 1
+
+#include <dali-scene3d/public-api/loader/node-definition.h>
+#include <dali-scene3d/public-api/loader/resource-bundle.h>
+#include <dali-scene3d/public-api/loader/shader-manager.h>
+#include <dali-test-suite-utils.h>
+#include <set>
+#include <string_view>
+
+using namespace Dali;
+using namespace Dali::Scene3D::Loader;
+
+namespace
+{
+struct Context
+{
+  ResourceBundle resources;
+};
+
+struct ShaderParameters
+{
+  MeshDefinition&     meshDefinition;
+  MaterialDefinition& materialDefinition;
+  NodeDefinition&     nodeDefinition;
+};
+
+struct Permutation
+{
+  using ConfigureFn = void (*)(ShaderParameters&);
+
+  ConfigureFn configureFn;
+
+  std::set<ShaderOption::Type> options;
+  RendererState::Type          rendererStateSet   = 0;
+  RendererState::Type          rendererStateClear = 0;
+};
+
+struct PermutationSet
+{
+  std::vector<const Permutation*> permutations;
+};
+
+} // namespace
+
+int UtcDaliShaderDefinitionFactoryProduceShader(void)
+{
+  Context ctx;
+  ctx.resources.mMaterials.push_back({});
+  ctx.resources.mMeshes.push_back({});
+
+  Permutation permutations[]{
+    {
+      [](ShaderParameters& p) {},
+      {},
+      RendererState::DEPTH_TEST | RendererState::CULL_BACK,
+    },
+    {
+      [](ShaderParameters& p)
+      {
+        p.materialDefinition.mFlags |= MaterialDefinition::TRANSPARENCY;
+      },
+      {ShaderOption::Type::THREE_TEXTURE},
+      RendererState::ALPHA_BLEND,
+    },
+    {[](ShaderParameters& p)
+     {
+       p.materialDefinition.mFlags |= MaterialDefinition::ALBEDO;
+       p.materialDefinition.mTextureStages.push_back({MaterialDefinition::ALBEDO, {}});
+     },
+     {ShaderOption::Type::THREE_TEXTURE, ShaderOption::Type::BASE_COLOR_TEXTURE}},
+    {[](ShaderParameters& p)
+     {
+       p.materialDefinition.mTextureStages.push_back({MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS, {}});
+     },
+     {ShaderOption::Type::THREE_TEXTURE, ShaderOption::Type::METALLIC_ROUGHNESS_TEXTURE}},
+    {[](ShaderParameters& p)
+     {
+       p.materialDefinition.mFlags |= MaterialDefinition::NORMAL;
+       p.materialDefinition.mTextureStages.push_back({MaterialDefinition::NORMAL, {}});
+     },
+     {ShaderOption::Type::THREE_TEXTURE, ShaderOption::Type::NORMAL_TEXTURE}},
+    {[](ShaderParameters& p)
+     {
+       p.materialDefinition.mFlags |= MaterialDefinition::SUBSURFACE;
+     },
+     {ShaderOption::Type::SUBSURFACE}},
+    {[](ShaderParameters& p)
+     {
+       p.materialDefinition.SetAlphaCutoff(.5f);
+     },
+     {ShaderOption::Type::ALPHA_TEST}},
+    {[](ShaderParameters& p)
+     {
+       p.materialDefinition.SetAlphaCutoff(1.f);
+     },
+     {ShaderOption::Type::ALPHA_TEST}},
+    {[](ShaderParameters& p)
+     {
+       p.materialDefinition.mFlags |= MaterialDefinition::GLTF_CHANNELS;
+     },
+     {ShaderOption::Type::GLTF_CHANNELS}},
+    {[](ShaderParameters& p)
+     {
+       p.meshDefinition.mJoints0.mBlob.mOffset  = 0;
+       p.meshDefinition.mWeights0.mBlob.mOffset = 0;
+     },
+     {ShaderOption::Type::SKINNING}},
+    {[](ShaderParameters& p)
+     {
+       p.meshDefinition.mFlags |= MeshDefinition::FLIP_UVS_VERTICAL;
+     },
+     {ShaderOption::Type::FLIP_UVS_VERTICAL}},
+    {
+      [](ShaderParameters& p)
+      {
+        p.meshDefinition.mBlendShapes.push_back({});
+      },
+    },
+    {[](ShaderParameters& p)
+     {
+       p.meshDefinition.mBlendShapes.back().deltas.mBlob.mOffset = 0;
+     },
+     {ShaderOption::Type::MORPH_POSITION}},
+    {[](ShaderParameters& p)
+     {
+       p.meshDefinition.mBlendShapes.back().normals.mBlob.mOffset = 0;
+     },
+     {ShaderOption::Type::MORPH_NORMAL}},
+    {[](ShaderParameters& p)
+     {
+       p.meshDefinition.mBlendShapes.back().tangents.mBlob.mOffset = 0;
+     },
+     {ShaderOption::Type::MORPH_TANGENT}},
+    {[](ShaderParameters& p)
+     {
+       auto& blendShapes = p.meshDefinition.mBlendShapes;
+       DALI_ASSERT_ALWAYS(!blendShapes.empty() &&
+                          (blendShapes.back().deltas.mBlob.mOffset != MeshDefinition::INVALID ||
+                           blendShapes.back().normals.mBlob.mOffset != MeshDefinition::INVALID ||
+                           blendShapes.back().tangents.mBlob.mOffset != MeshDefinition::INVALID));
+       p.meshDefinition.mBlendShapeVersion = BlendShapes::Version::VERSION_2_0;
+     },
+     {ShaderOption::Type::MORPH_VERSION_2_0}},
+
+    {[](ShaderParameters& p)
+     {
+       p.materialDefinition.mFlags |= MaterialDefinition::OCCLUSION;
+     },
+     {ShaderOption::Type::OCCLUSION}},
+
+    {[](ShaderParameters& p)
+     {
+       p.meshDefinition.mColors.mBlob.mOffset = 0;
+     },
+     {ShaderOption::Type::COLOR_ATTRIBUTE}},
+    {[](ShaderParameters& p)
+     {
+       p.meshDefinition.mTangentType = Property::VECTOR4;
+     },
+     {ShaderOption::Type::VEC4_TANGENT}},
+  };
+
+  PermutationSet permutationSets[]{
+    // default
+    {{&permutations[0]}},
+
+    // alpha
+    {{&permutations[0], &permutations[1]}},
+
+    // three-texture setups
+    {{&permutations[0], &permutations[2]}},
+    {{&permutations[0], &permutations[3]}},
+    {{&permutations[0], &permutations[4]}},
+    {{&permutations[0], &permutations[2], &permutations[3]}},
+    {{&permutations[0], &permutations[3], &permutations[4]}},
+    {{&permutations[0], &permutations[4], &permutations[2]}},
+    {{&permutations[0], &permutations[2], &permutations[3], &permutations[4]}},
+
+    // subsurface scattering
+    {{&permutations[0], &permutations[5]}},
+
+    // alpha test
+    {{&permutations[0], &permutations[6]}},
+    {{&permutations[0], &permutations[7]}},
+
+    // glTF channels
+    {{&permutations[0], &permutations[8]}},
+
+    // skinning
+    {{&permutations[0], &permutations[9]}},
+
+    // flip uvs
+    {{&permutations[0], &permutations[10]}},
+
+    // morphing
+    {{&permutations[0], &permutations[11], &permutations[12]}},
+    {{&permutations[0], &permutations[11], &permutations[13]}},
+    {{&permutations[0], &permutations[11], &permutations[14]}},
+    {{&permutations[0], &permutations[11], &permutations[12], &permutations[13]}},
+    {{&permutations[0], &permutations[11], &permutations[13], &permutations[14]}},
+    {{&permutations[0], &permutations[11], &permutations[14], &permutations[12]}},
+    {{&permutations[0], &permutations[11], &permutations[12], &permutations[13], &permutations[14]}},
+
+    {{&permutations[0], &permutations[11], &permutations[12], &permutations[15]}},
+    {{&permutations[0], &permutations[11], &permutations[13], &permutations[15]}},
+    {{&permutations[0], &permutations[11], &permutations[14], &permutations[15]}},
+    {{&permutations[0], &permutations[11], &permutations[12], &permutations[13], &permutations[15]}},
+    {{&permutations[0], &permutations[11], &permutations[13], &permutations[14], &permutations[15]}},
+    {{&permutations[0], &permutations[11], &permutations[14], &permutations[12], &permutations[15]}},
+    {{&permutations[0], &permutations[11], &permutations[12], &permutations[13], &permutations[14], &permutations[15]}},
+
+    // etc.
+    {{&permutations[0], &permutations[1], &permutations[2]}},
+    {{&permutations[0], &permutations[1], &permutations[3]}},
+    {{&permutations[0], &permutations[1], &permutations[2], &permutations[3]}},
+
+    // occlusion
+    {{&permutations[0], &permutations[16]}},
+  };
+
+  TestApplication app;
+  ShaderManager   shaderManager;
+  for(auto& permutationSet : permutationSets)
+  {
+    static int tc = 0;
+    tet_printf("Test %d's tc\n", ++tc);
+    auto modelRenderable          = new ModelRenderable();
+    modelRenderable->mMeshIdx     = 0;
+    modelRenderable->mMaterialIdx = 0;
+
+    NodeDefinition                              nodeDefinition;
+    std::unique_ptr<NodeDefinition::Renderable> renderable;
+    renderable.reset(modelRenderable);
+    nodeDefinition.mRenderables.push_back(std::move(renderable));
+
+    MeshDefinition     meshDefinition;
+    MaterialDefinition materialDefinition;
+    ShaderParameters   shaderParameter{meshDefinition, materialDefinition, nodeDefinition};
+
+    std::set<std::string> defines;
+    ShaderOption          option;
+    RendererState::Type   rendererState = 0;
+    for(auto permutation : permutationSet.permutations)
+    {
+      permutation->configureFn(shaderParameter);
+      if(materialDefinition.mFlags & MaterialDefinition::TRANSPARENCY)
+      {
+        option.SetTransparency();
+      }
+      for(auto&& optionType : permutation->options)
+      {
+        option.AddOption(optionType);
+      }
+      rendererState = (rendererState | permutation->rendererStateSet) & ~permutation->rendererStateClear;
+    }
+    option.AddOption(ShaderOption::Type::THREE_TEXTURE);
+
+    Shader shaderFromMeshAndMaterial = shaderManager.ProduceShader(materialDefinition, meshDefinition);
+    Shader shaderFromOption          = shaderManager.ProduceShader(option);
+    DALI_TEST_EQUAL(shaderFromMeshAndMaterial, shaderFromOption);
+
+    RendererState::Type rendererStateFromMaterialDefinition = shaderManager.GetRendererState(materialDefinition);
+    DALI_TEST_EQUAL(rendererStateFromMaterialDefinition, rendererState);
+  }
+
+  END_TEST;
+}
\ No newline at end of file
diff --git a/automated-tests/src/dali-scene3d/utc-Dali-ShaderOption.cpp b/automated-tests/src/dali-scene3d/utc-Dali-ShaderOption.cpp
new file mode 100644 (file)
index 0000000..71514fd
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <string_view>
+#include "dali-scene3d/public-api/loader/shader-option.h"
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+void shader_definition_option_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void shader_definition_option_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+int UtcDaliShaderOptionInit(void)
+{
+  Scene3D::Loader::ShaderOption option;
+  DALI_TEST_EQUALS(option.GetOptionHash(), 0u, TEST_LOCATION);
+  END_TEST;
+}
+
+int UtcDaliShaderOptionSetTransparency(void)
+{
+  Scene3D::Loader::ShaderOption option;
+  DALI_TEST_EQUALS(option.GetOptionHash(), 0u, TEST_LOCATION);
+
+  option.SetTransparency();
+  DALI_TEST_NOT_EQUALS(option.GetOptionHash(), static_cast<uint64_t>(0u), 0.1f, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliShaderOptionAddOption(void)
+{
+  Scene3D::Loader::ShaderOption option;
+  DALI_TEST_EQUALS(option.GetOptionHash(), 0u, TEST_LOCATION);
+
+  Scene3D::Loader::ShaderOption::Type types[19] = {
+    Scene3D::Loader::ShaderOption::Type::GLTF_CHANNELS,
+    Scene3D::Loader::ShaderOption::Type::THREE_TEXTURE,
+    Scene3D::Loader::ShaderOption::Type::BASE_COLOR_TEXTURE,
+    Scene3D::Loader::ShaderOption::Type::METALLIC_ROUGHNESS_TEXTURE,
+    Scene3D::Loader::ShaderOption::Type::NORMAL_TEXTURE,
+    Scene3D::Loader::ShaderOption::Type::OCCLUSION,
+    Scene3D::Loader::ShaderOption::Type::EMISSIVE,
+    Scene3D::Loader::ShaderOption::Type::ALPHA_TEST,
+    Scene3D::Loader::ShaderOption::Type::SUBSURFACE,
+    Scene3D::Loader::ShaderOption::Type::SPECULAR,
+    Scene3D::Loader::ShaderOption::Type::SPECULAR_COLOR,
+    Scene3D::Loader::ShaderOption::Type::SKINNING,
+    Scene3D::Loader::ShaderOption::Type::FLIP_UVS_VERTICAL,
+    Scene3D::Loader::ShaderOption::Type::COLOR_ATTRIBUTE,
+    Scene3D::Loader::ShaderOption::Type::VEC4_TANGENT,
+    Scene3D::Loader::ShaderOption::Type::MORPH_POSITION,
+    Scene3D::Loader::ShaderOption::Type::MORPH_NORMAL,
+    Scene3D::Loader::ShaderOption::Type::MORPH_TANGENT,
+    Scene3D::Loader::ShaderOption::Type::MORPH_VERSION_2_0};
+
+  uint64_t hash = 0u;
+  for(uint32_t i = 0; i < 19; ++i)
+  {
+    hash |= (1 << static_cast<uint32_t>(types[i]));
+    option.AddOption(types[i]);
+    DALI_TEST_EQUALS(option.GetOptionHash(), hash, TEST_LOCATION);
+  }
+
+  END_TEST;
+}
+
+int UtcDaliShaderOptionGetDefines(void)
+{
+  Scene3D::Loader::ShaderOption option;
+  DALI_TEST_EQUALS(option.GetOptionHash(), 0u, TEST_LOCATION);
+
+  Scene3D::Loader::ShaderOption::Type types[19] = {
+    Scene3D::Loader::ShaderOption::Type::GLTF_CHANNELS,
+    Scene3D::Loader::ShaderOption::Type::THREE_TEXTURE,
+    Scene3D::Loader::ShaderOption::Type::BASE_COLOR_TEXTURE,
+    Scene3D::Loader::ShaderOption::Type::METALLIC_ROUGHNESS_TEXTURE,
+    Scene3D::Loader::ShaderOption::Type::NORMAL_TEXTURE,
+    Scene3D::Loader::ShaderOption::Type::OCCLUSION,
+    Scene3D::Loader::ShaderOption::Type::EMISSIVE,
+    Scene3D::Loader::ShaderOption::Type::ALPHA_TEST,
+    Scene3D::Loader::ShaderOption::Type::SUBSURFACE,
+    Scene3D::Loader::ShaderOption::Type::SPECULAR,
+    Scene3D::Loader::ShaderOption::Type::SPECULAR_COLOR,
+    Scene3D::Loader::ShaderOption::Type::SKINNING,
+    Scene3D::Loader::ShaderOption::Type::FLIP_UVS_VERTICAL,
+    Scene3D::Loader::ShaderOption::Type::COLOR_ATTRIBUTE,
+    Scene3D::Loader::ShaderOption::Type::VEC4_TANGENT,
+    Scene3D::Loader::ShaderOption::Type::MORPH_POSITION,
+    Scene3D::Loader::ShaderOption::Type::MORPH_NORMAL,
+    Scene3D::Loader::ShaderOption::Type::MORPH_TANGENT,
+    Scene3D::Loader::ShaderOption::Type::MORPH_VERSION_2_0};
+
+  uint64_t hash = 0u;
+  for(uint32_t i = 0; i < 19; ++i)
+  {
+    hash |= (1 << static_cast<uint32_t>(types[i]));
+    option.AddOption(types[i]);
+    DALI_TEST_EQUALS(option.GetOptionHash(), hash, TEST_LOCATION);
+
+    std::vector<std::string> defines;
+    option.GetDefines(defines);
+    DALI_TEST_EQUALS(defines.size(), i + 1, TEST_LOCATION);
+    for(uint32_t j = 0; j < defines.size(); ++j)
+    {
+      DALI_TEST_EQUALS(defines[j], option.GetDefineKeyword(types[j]), TEST_LOCATION);
+    }
+  }
+
+  END_TEST;
+}
\ No newline at end of file
index ccf85d9..caf2491 100644 (file)
@@ -54,8 +54,8 @@
 #include <dali-scene3d/public-api/loader/renderer-state.h>
 #include <dali-scene3d/public-api/loader/resource-bundle.h>
 #include <dali-scene3d/public-api/loader/scene-definition.h>
-#include <dali-scene3d/public-api/loader/shader-definition-factory.h>
 #include <dali-scene3d/public-api/loader/shader-definition.h>
+#include <dali-scene3d/public-api/loader/shader-manager.h>
 #include <dali-scene3d/public-api/loader/skeleton-definition.h>
 #include <dali-scene3d/public-api/loader/skinning-details.h>
 #include <dali-scene3d/public-api/loader/string-callback.h>
index 8b3ab57..0483419 100644 (file)
@@ -42,7 +42,7 @@
 #include <dali-scene3d/public-api/loader/load-result.h>
 #include <dali-scene3d/public-api/loader/node-definition.h>
 #include <dali-scene3d/public-api/loader/scene-definition.h>
-#include <dali-scene3d/public-api/loader/shader-definition-factory.h>
+#include <dali-scene3d/public-api/loader/shader-manager.h>
 #include <dali-scene3d/public-api/model-motion/motion-index/blend-shape-index.h>
 
 using namespace Dali;
@@ -232,6 +232,26 @@ void UpdateBlendShapeNodeMapRecursively(Model::BlendShapeModelNodeMap& resultMap
   }
 }
 
+void UpdateShaderRecursively(Scene3D::ModelNode node, Scene3D::Loader::ShaderManagerPtr shaderManager)
+{
+  if(!node)
+  {
+    return;
+  }
+
+  GetImplementation(node).UpdateShader(shaderManager);
+
+  uint32_t childrenCount = node.GetChildCount();
+  for(uint32_t i = 0; i < childrenCount; ++i)
+  {
+    Scene3D::ModelNode childNode = Scene3D::ModelNode::DownCast(node.GetChildAt(i));
+    if(childNode)
+    {
+      UpdateShaderRecursively(childNode, shaderManager);
+    }
+  }
+}
+
 } // anonymous namespace
 
 Model::Model(const std::string& modelUrl, const std::string& resourceDirectoryUrl)
@@ -239,6 +259,7 @@ Model::Model(const std::string& modelUrl, const std::string& resourceDirectoryUr
   mModelUrl(modelUrl),
   mResourceDirectoryUrl(resourceDirectoryUrl),
   mModelRoot(),
+  mShaderManager(new Scene3D::Loader::ShaderManager()),
   mNaturalSize(Vector3::ZERO),
   mModelPivot(AnchorPoint::CENTER),
   mSceneIblScaleFactor(1.0f),
@@ -296,6 +317,8 @@ void Model::AddModelNode(Scene3D::ModelNode modelNode)
     mModelResourceReady = true;
   }
 
+  UpdateShaderRecursively(modelNode, mShaderManager);
+
   if(mIblDiffuseResourceReady && mIblSpecularResourceReady)
   {
     UpdateImageBasedLightTexture();
@@ -321,6 +344,8 @@ void Model::RemoveModelNode(Scene3D::ModelNode modelNode)
 {
   if(mModelRoot)
   {
+    UpdateShaderRecursively(modelNode, nullptr);
+
     uint32_t maxLightCount = Scene3D::Internal::Light::GetMaximumEnabledLightCount();
     for(uint32_t i = 0; i < maxLightCount; ++i)
     {
@@ -774,6 +799,36 @@ void Model::OnInitialize()
 
 void Model::OnSceneConnection(int depth)
 {
+  Actor parent = Self().GetParent();
+  while(parent)
+  {
+    // If this Model has parent SceneView and the its ShaderManager is same with privious ShaderManager,
+    // this Model don't need to update shader.
+    Scene3D::SceneView sceneView = Scene3D::SceneView::DownCast(parent);
+    if(sceneView)
+    {
+      mParentSceneView = sceneView;
+      GetImpl(sceneView).RegisterSceneItem(this);
+      Scene3D::Loader::ShaderManagerPtr shaderManager = GetImpl(sceneView).GetShaderManager();
+      if(mShaderManager != shaderManager)
+      {
+        mShaderManager = shaderManager;
+        UpdateShaderRecursively(mModelRoot, mShaderManager);
+      }
+      break;
+    }
+    parent = parent.GetParent();
+  }
+
+  // Model can be added on Dali::Scene directly without SceneView.
+  // So, Model's mShaderManager and shaders of child ModelNodes are needed to be reset when this Model has not parent SceneView.
+  Scene3D::SceneView parentSceneView = mParentSceneView.GetHandle();
+  if(!parentSceneView)
+  {
+    mShaderManager = new Dali::Scene3D::Loader::ShaderManager();
+    UpdateShaderRecursively(mModelRoot, mShaderManager);
+  }
+
   if(!mModelLoadTask && !mModelResourceReady && !mModelUrl.empty())
   {
     // Request model load only if we setup url.
@@ -791,19 +846,6 @@ void Model::OnSceneConnection(int depth)
     SetImageBasedLightSource(mDiffuseIblUrl, mSpecularIblUrl, mIblScaleFactor);
   }
 
-  Actor parent = Self().GetParent();
-  while(parent)
-  {
-    Scene3D::SceneView sceneView = Scene3D::SceneView::DownCast(parent);
-    if(sceneView)
-    {
-      GetImpl(sceneView).RegisterSceneItem(this);
-      mParentSceneView = sceneView;
-      break;
-    }
-    parent = parent.GetParent();
-  }
-
   NotifyResourceReady();
 
   mSizeNotification = Self().AddPropertyNotification(Actor::Property::SIZE, StepCondition(SIZE_STEP_CONDITION));
@@ -813,8 +855,11 @@ void Model::OnSceneConnection(int depth)
 
 void Model::OnSceneDisconnection()
 {
+  // If mParentSceneView is still onScene, that means this model
+  // is disconnected from mParentSceneView's sub tree.
+  // So, Unregister this Model from SceneView.
   Scene3D::SceneView sceneView = mParentSceneView.GetHandle();
-  if(sceneView)
+  if(sceneView && sceneView.GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE))
   {
     GetImpl(sceneView).UnregisterSceneItem(this);
     mParentSceneView.Reset();
@@ -1174,12 +1219,13 @@ void Model::NotifyResourceReady()
 
 void Model::CreateModel()
 {
-  BoundingVolume                                      AABB;
-  auto&                                               resources       = mModelLoadTask->GetResources();
-  auto&                                               scene           = mModelLoadTask->GetScene();
-  auto&                                               resourceChoices = mModelLoadTask->GetResourceChoices();
-  Dali::Scene3D::Loader::Transforms                   xforms{Dali::Scene3D::Loader::MatrixStack{}, Dali::Scene3D::Loader::ViewProjection{}};
-  Dali::Scene3D::Loader::NodeDefinition::CreateParams nodeParams{resources, xforms, {}, {}, {}};
+  BoundingVolume                    AABB;
+  auto&                             resources       = mModelLoadTask->GetResources();
+  auto&                             scene           = mModelLoadTask->GetScene();
+  auto&                             resourceChoices = mModelLoadTask->GetResourceChoices();
+  Dali::Scene3D::Loader::Transforms xforms{Dali::Scene3D::Loader::MatrixStack{}, Dali::Scene3D::Loader::ViewProjection{}};
+
+  Dali::Scene3D::Loader::NodeDefinition::CreateParams nodeParams{resources, xforms, mShaderManager, {}, {}, {}};
 
   // Generate Dali handles from resource bundle. Note that we generate all scene's resouce immediatly.
   resources.GenerateResources();
index f383aff..cb64cac 100644 (file)
@@ -361,6 +361,8 @@ private:
   WeakHandle<Scene3D::SceneView> mParentSceneView;
   Dali::PropertyNotification     mSizeNotification;
 
+  Dali::Scene3D::Loader::ShaderManagerPtr mShaderManager;
+
   // Light
   std::vector<Scene3D::Light> mLights;
 
index 0a1e5b0..421aafb 100644 (file)
@@ -62,7 +62,7 @@ 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;
+constexpr int32_t INVALID_INDEX       = -1;
 
 static constexpr std::string_view SKYBOX_INTENSITY_STRING = "uIntensity";
 
@@ -153,7 +153,8 @@ SceneView::SceneView()
   mWindowOrientation(DEFAULT_ORIENTATION),
   mSkybox(),
   mSkyboxOrientation(Quaternion()),
-  mSkyboxIntensity(1.0f)
+  mSkyboxIntensity(1.0f),
+  mShaderManager(new Scene3D::Loader::ShaderManager())
 {
 }
 
@@ -469,7 +470,7 @@ void SceneView::RemoveLight(Scene3D::Light light)
     uint32_t removedIndex = RemoveLightInternal(light);
     if(mActivatedLightCount < maxNumberOfLight && mLights.size() >= maxNumberOfLight)
     {
-      for(auto && lightItem : mLights)
+      for(auto&& lightItem : mLights)
       {
         if(lightItem.second == false)
         {
@@ -585,6 +586,11 @@ Quaternion SceneView::GetSkyboxOrientation() const
   return mSkyboxOrientation;
 }
 
+Dali::Scene3D::Loader::ShaderManagerPtr SceneView::GetShaderManager() const
+{
+  return mShaderManager;
+}
+
 ///////////////////////////////////////////////////////////
 //
 // Private methods
@@ -824,9 +830,9 @@ void SceneView::UpdateSkybox(const std::string& skyboxUrl, Scene3D::EnvironmentM
 
     if(mSkybox)
     {
-        mSkybox.Unparent();
-        mSkybox.Reset();
-        mSkyboxTexture.Reset();
+      mSkybox.Unparent();
+      mSkybox.Reset();
+      mSkyboxTexture.Reset();
     }
 
     mSkyboxDirty         = false;
@@ -976,7 +982,7 @@ bool SceneView::AddLightInternal(Scene3D::Light light)
 
 int32_t SceneView::RemoveLightInternal(Scene3D::Light light)
 {
-  int32_t removedIndex = INVALID_INDEX;
+  int32_t  removedIndex     = INVALID_INDEX;
   uint32_t maxNumberOfLight = Scene3D::Internal::Light::GetMaximumEnabledLightCount();
   for(uint32_t i = 0; i < maxNumberOfLight; ++i)
   {
index 02e0a74..c9a4a84 100644 (file)
@@ -34,6 +34,7 @@
 #include <dali-scene3d/internal/common/environment-map-load-task.h>
 #include <dali-scene3d/internal/common/light-observer.h>
 #include <dali-scene3d/public-api/controls/scene-view/scene-view.h>
+#include <dali-scene3d/public-api/loader/shader-manager.h>
 
 namespace Dali
 {
@@ -202,6 +203,12 @@ public:
    */
   Quaternion GetSkyboxOrientation() const;
 
+  /**
+   * @brief Retrieves ShaderManager of this SceneView.
+   * @return ShaderManager of this SceneView.
+   */
+  Dali::Scene3D::Loader::ShaderManagerPtr GetShaderManager() const;
+
 protected:
   /**
    * @brief Constructs a new SceneView.
@@ -350,6 +357,9 @@ private:
   float                                                    mSkyboxIntensity{1.0f};
   uint8_t                                                  mFrameBufferMultiSamplingLevel{4u};
 
+  // Shader Factory
+  Dali::Scene3D::Loader::ShaderManagerPtr mShaderManager;
+
   // Light
   std::vector<std::pair<Scene3D::Light, bool>> mLights; // Pair of Light object and flag that denotes the light is currently activated or not.
   std::vector<Scene3D::Light>                  mActivatedLights;
@@ -376,8 +386,6 @@ private:
   bool                        mSkyboxDirty{false};
   bool                        mIblDiffuseDirty{false};
   bool                        mIblSpecularDirty{false};
-
-  // TODO : Light Source
 };
 
 } // namespace Internal
index ef13e72..2b954bd 100644 (file)
@@ -594,6 +594,8 @@ void ConvertMaterial(const gltf2::Material& material, const std::unordered_map<s
 
   MaterialDefinition materialDefinition;
 
+  materialDefinition.mFlags |= MaterialDefinition::GLTF_CHANNELS;
+
   auto& pbr = material.mPbrMetallicRoughness;
   if(material.mAlphaMode == gltf2::AlphaMode::BLEND)
   {
@@ -625,7 +627,7 @@ void ConvertMaterial(const gltf2::Material& material, const std::unordered_map<s
 
   if(pbr.mMetallicRoughnessTexture)
   {
-    AddTextureStage(MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS | MaterialDefinition::GLTF_CHANNELS,
+    AddTextureStage(MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS,
                     materialDefinition,
                     pbr.mMetallicRoughnessTexture,
                     getTextureMetaData(imageMetaData, pbr.mMetallicRoughnessTexture),
@@ -891,8 +893,6 @@ ModelRenderable* MakeModelRenderable(const gltf2::Mesh::Primitive& primitive, Co
 {
   auto modelRenderable = new ModelRenderable();
 
-  modelRenderable->mShaderIdx = 0; // TODO: further thought
-
   auto materialIdx = primitive.mMaterial.GetIndex();
   if(INVALID_INDEX == materialIdx)
   {
@@ -1354,22 +1354,6 @@ void ProcessSkins(const gltf2::Document& document, ConversionContext& context)
   }
 }
 
-void ProduceShaders(ShaderDefinitionFactory& shaderFactory, Dali::Scene3D::Loader::SceneDefinition& scene)
-{
-  uint32_t nodeCount = scene.GetNodeCount();
-  for(uint32_t i = 0; i < nodeCount; ++i)
-  {
-    auto nodeDefinition = scene.GetNode(i);
-    for(auto& renderable : nodeDefinition->mRenderables)
-    {
-      if(shaderFactory.ProduceShader(*renderable) == INVALID_INDEX)
-      {
-        DALI_LOG_ERROR("Fail to produce shader\n");
-      }
-    }
-  }
-}
-
 void SetObjectReaders()
 {
   json::SetObjectReader(GetBufferReader());
@@ -1471,17 +1455,12 @@ bool GenerateDocument(json::unique_ptr& root, gt::Document& document, bool& isMR
 
 void ConvertGltfToContext(gt::Document& document, Gltf2Util::ConversionContext& context, bool isMRendererModel)
 {
-  Dali::Scene3D::Loader::ShaderDefinitionFactory shaderFactory;
-  shaderFactory.SetResources(context.mOutput.mResources);
-
   Gltf2Util::ConvertBuffers(document, context);
   Gltf2Util::ConvertMaterials(document, context);
   Gltf2Util::ConvertMeshes(document, context);
   Gltf2Util::ConvertNodes(document, context, isMRendererModel);
   Gltf2Util::ConvertAnimations(document, context);
   Gltf2Util::ProcessSkins(document, context);
-  Gltf2Util::ProduceShaders(shaderFactory, context.mOutput.mScene);
-  context.mOutput.mScene.EnsureUniqueSkinningShaderInstances(context.mOutput.mResources);
 
   // Set Default Environment map
   Gltf2Util::SetDefaultEnvironmentMap(document, context);
index 457140e..d12addd 100644 (file)
@@ -25,7 +25,6 @@
 #include <dali-scene3d/public-api/loader/load-result.h>
 #include <dali-scene3d/public-api/loader/resource-bundle.h>
 #include <dali-scene3d/public-api/loader/scene-definition.h>
-#include <dali-scene3d/public-api/loader/shader-definition-factory.h>
 
 namespace gt = gltf2;
 namespace js = json;
@@ -48,8 +47,8 @@ struct NodeMapping
 class NodeIndexMapper
 {
 public:
-  NodeIndexMapper()                       = default;
-  NodeIndexMapper(const NodeIndexMapper&) = delete;
+  NodeIndexMapper()                                  = default;
+  NodeIndexMapper(const NodeIndexMapper&)            = delete;
   NodeIndexMapper& operator=(const NodeIndexMapper&) = delete;
 
   ///@brief Registers a mapping of the @a gltfIndex of a node to its @a runtimeIndex .
@@ -101,8 +100,6 @@ void ConvertAnimations(const gt::Document& document, ConversionContext& context)
 
 void ProcessSkins(const gt::Document& document, ConversionContext& context);
 
-void ProduceShaders(ShaderDefinitionFactory& shaderFactory, SceneDefinition& scene);
-
 void SetDefaultEnvironmentMap(const gt::Document& document, ConversionContext& context);
 
 const std::string_view GetRendererModelIdentification();
index 4ce7d57..386fdd6 100644 (file)
@@ -30,8 +30,8 @@
 #include <dali-scene3d/internal/model-components/material-modify-observer.h>
 #include <dali-scene3d/public-api/loader/node-definition.h>
 #include <dali-scene3d/public-api/loader/renderer-state.h>
+#include <dali-scene3d/public-api/loader/shader-option.h>
 #include <dali-scene3d/public-api/loader/utils.h>
-#include <dali-scene3d/public-api/loader/shader-definition-option.h>
 
 namespace Dali
 {
@@ -101,13 +101,13 @@ Material::Material()
   mTextureInformations[SPECULAR].mSemantic       = Scene3D::Loader::MaterialDefinition::SPECULAR;
   mTextureInformations[SPECULAR_COLOR].mSemantic = Scene3D::Loader::MaterialDefinition::SPECULAR_COLOR;
 
-  mTextureInformations[BASE_COLOR].mDefineKeyword         = Scene3D::Loader::ShaderDefinitionOption::GetDefineKeyword(Loader::ShaderDefinitionOption::Type::BASE_COLOR_TEXTURE).data();
-  mTextureInformations[METALLIC_ROUGHNESS].mDefineKeyword = Scene3D::Loader::ShaderDefinitionOption::GetDefineKeyword(Loader::ShaderDefinitionOption::Type::METALLIC_ROUGHNESS_TEXTURE).data();
-  mTextureInformations[NORMAL].mDefineKeyword             = Scene3D::Loader::ShaderDefinitionOption::GetDefineKeyword(Loader::ShaderDefinitionOption::Type::NORMAL_TEXTURE).data();
-  mTextureInformations[OCCLUSION].mDefineKeyword          = Scene3D::Loader::ShaderDefinitionOption::GetDefineKeyword(Loader::ShaderDefinitionOption::Type::OCCLUSION).data();
-  mTextureInformations[EMISSIVE].mDefineKeyword           = Scene3D::Loader::ShaderDefinitionOption::GetDefineKeyword(Loader::ShaderDefinitionOption::Type::EMISSIVE).data();
-  mTextureInformations[SPECULAR].mDefineKeyword           = Scene3D::Loader::ShaderDefinitionOption::GetDefineKeyword(Loader::ShaderDefinitionOption::Type::SPECULAR).data();
-  mTextureInformations[SPECULAR_COLOR].mDefineKeyword     = Scene3D::Loader::ShaderDefinitionOption::GetDefineKeyword(Loader::ShaderDefinitionOption::Type::SPECULAR_COLOR).data();
+  mTextureInformations[BASE_COLOR].mShaderOptionType         = Loader::ShaderOption::Type::BASE_COLOR_TEXTURE;
+  mTextureInformations[METALLIC_ROUGHNESS].mShaderOptionType = Loader::ShaderOption::Type::METALLIC_ROUGHNESS_TEXTURE;
+  mTextureInformations[NORMAL].mShaderOptionType             = Loader::ShaderOption::Type::NORMAL_TEXTURE;
+  mTextureInformations[OCCLUSION].mShaderOptionType          = Loader::ShaderOption::Type::OCCLUSION;
+  mTextureInformations[EMISSIVE].mShaderOptionType           = Loader::ShaderOption::Type::EMISSIVE;
+  mTextureInformations[SPECULAR].mShaderOptionType           = Loader::ShaderOption::Type::SPECULAR;
+  mTextureInformations[SPECULAR_COLOR].mShaderOptionType     = Loader::ShaderOption::Type::SPECULAR_COLOR;
 
   mTextureInformations[TextureIndex::EMISSIVE].mFactor = Vector4::ZERO;
 }
@@ -517,14 +517,9 @@ Dali::Sampler Material::GetSampler(Scene3D::Material::TextureType index)
   return Dali::Sampler();
 }
 
-std::string Material::GetVertexShader()
+Scene3D::Loader::ShaderOption Material::GetShaderOption() const
 {
-  return mShaderData.mVertexShaderSource;
-}
-
-std::string Material::GetFragmentShader()
-{
-  return mShaderData.mFragmentShaderSource;
+  return mShaderOption;
 }
 
 void Material::Apply()
@@ -614,34 +609,31 @@ void Material::UpdateMaterialData()
     materialFlag |= textureInformation.mSemantic;
   }
 
-  if(mMaterialFlag != materialFlag || mShaderData.mVertexShaderSource.empty() || mShaderData.mFragmentShaderSource.empty())
+  if(mMaterialFlag != materialFlag)
   {
     mModifyFlag |= MaterialModifyObserver::ModifyFlag::SHADER;
 
-    mMaterialFlag                     = materialFlag;
-    mShaderData.mVertexShaderSource   = SHADER_DEFAULT_PHYSICALLY_BASED_SHADER_VERT.data();
-    mShaderData.mFragmentShaderSource = SHADER_DEFAULT_PHYSICALLY_BASED_SHADER_FRAG.data();
+    mMaterialFlag = materialFlag;
 
-    std::vector<std::string> defines;
-    defines.push_back(THREE_TEX_KEYWORD.data());
+    mShaderOption = Loader::ShaderOption();
     for(auto&& textureInformation : mTextureInformations)
     {
       if(!textureInformation.mTexture)
       {
         continue;
       }
-      defines.push_back(textureInformation.mDefineKeyword);
+      mShaderOption.AddOption(textureInformation.mShaderOptionType);
     }
-    defines.push_back(GLTF_CHANNELS_KEYWORD.data());
-
-    for(const auto& define : defines)
+    mShaderOption.AddOption(Loader::ShaderOption::Type::THREE_TEXTURE);
+    mShaderOption.AddOption(Loader::ShaderOption::Type::GLTF_CHANNELS);
+    if(materialFlag & Scene3D::Loader::MaterialDefinition::TRANSPARENCY)
     {
-      Scene3D::Loader::ShaderDefinition::ApplyDefine(mShaderData.mFragmentShaderSource, define);
+      mShaderOption.SetTransparency();
     }
   }
 
   // Finish to make all the material flag according to the gltf2-util.
-  // Then make defines as fallowing shader-definition-factory.
+  // Then make defines as fallowing shader-manager.
 
   // The renderer State below can be used in primitive to set renderer properties.
 
@@ -769,7 +761,9 @@ void Material::NotifyObserver()
     mObserverNotifying = false;
 
     // Resolve observer queue during notify
-    mObservers.erase(std::remove_if(mObservers.begin(), mObservers.end(), [](auto& e) { return !e.second; }), mObservers.end());
+    mObservers.erase(std::remove_if(mObservers.begin(), mObservers.end(), [](auto& e)
+                                    { return !e.second; }),
+                     mObservers.end());
   }
 }
 
index 563bf82..3b0c985 100644 (file)
@@ -34,6 +34,7 @@
 #include <dali-scene3d/internal/model-components/material-modify-observer.h>
 #include <dali-scene3d/public-api/loader/material-definition.h>
 #include <dali-scene3d/public-api/loader/shader-definition.h>
+#include <dali-scene3d/public-api/loader/shader-option.h>
 #include <dali-scene3d/public-api/model-components/material.h>
 
 namespace Dali
@@ -65,13 +66,13 @@ public:
       return mLoadingTaskId == 0u;
     }
 
-    std::string   mUrl;
-    Dali::Texture mTexture;
-    Vector4       mFactor{Vector4::ONE};
-    Dali::Sampler mSampler;
-    uint32_t      mLoadingTaskId{0u};
-    uint32_t      mSemantic;
-    std::string   mDefineKeyword;
+    std::string                         mUrl;
+    Dali::Texture                       mTexture;
+    Vector4                             mFactor{Vector4::ONE};
+    Dali::Sampler                       mSampler;
+    uint32_t                            mLoadingTaskId{0u};
+    uint32_t                            mSemantic;
+    Scene3D::Loader::ShaderOption::Type mShaderOptionType;
   };
 
   using TextureInformationContainer = std::vector<TextureInformation>;
@@ -112,7 +113,7 @@ public:
   Dali::Property::Value GetProperty(Dali::Property::Index index) const;
 
   /**
-   * @brief Set a texture information for the material.
+   * @brief Sets a texture information for the material.
    *
    * @param[in] index The index of the texture to set.
    * @param[in] textureInformation The texture information to set.
@@ -122,7 +123,7 @@ public:
   void SetTextureInformation(Scene3D::Material::TextureType index, TextureInformation&& textureInformation);
 
   /**
-   * @brief Set a texture for the material.
+   * @brief Sets a texture for the material.
    *
    * @param[in] index The index of the texture to set.
    * @param[in] texture The texture to set.
@@ -130,7 +131,7 @@ public:
   void SetTexture(Scene3D::Material::TextureType index, Dali::Texture texture);
 
   /**
-   * @brief Get texture for the material.
+   * @brief Retrieves texture for the material.
    *
    * @param[in] index The index of the texture to get.
    *
@@ -139,14 +140,14 @@ public:
   Dali::Texture GetTexture(Scene3D::Material::TextureType index);
 
   /**
-   * @brief Get the texture set for this material.
+   * @brief Retrieves the texture set for this material.
    *
    * @return The texture set for this material.
    */
   TextureSet GetTextureSet();
 
   /**
-   * @brief Set a sampler for the material.
+   * @brief Sets a sampler for the material.
    *
    * @param[in] index The index of the sampler to set.
    * @param[in] sampler The sampler to set.
@@ -154,104 +155,96 @@ public:
   void SetSampler(Scene3D::Material::TextureType index, Dali::Sampler sampler);
 
   /**
-   * @brief Get a sampler for the material.
-
-   * @param[in] index The index of the sampler to get.
+   * @brief Retrieves a sampler for the material.
    *
+   * @param[in] index The index of the sampler to get.
    * @return The sampler at the given index.
    */
   Dali::Sampler GetSampler(Scene3D::Material::TextureType index);
 
   /**
-   * @brief Get vertex shader code for this material.
-   *
-   * @return Vertex shader code for this material.
-   */
-  std::string GetVertexShader();
-
-  /**
-   * @brief Get fragment shader code for this material.
+   * @brief Retrieves Shader Option of this Material.
    *
-   * @return Fragment shader code for this material.
+   * @return Shader Option of this Material.
    */
-  std::string GetFragmentShader();
+  Scene3D::Loader::ShaderOption GetShaderOption() const;
 
 public:
   /**
-   * @brief Add observer to this material.
+   * @brief Adds observer to this material.
    *
    * @param[in] observer Pointer of observer.
    */
   void AddObserver(MaterialModifyObserver* observer);
 
   /**
-   * @brief Remove observer from this material.
+   * @brief Removes observer from this material.
    *
    * @param[in] observer Pointer of observer.
    */
   void RemoveObserver(MaterialModifyObserver* observer);
 
   /**
-   * @brief Update material data.
+   * @brief Updates material data.
    */
   void UpdateMaterialData();
 
   /**
-   * @brief Set uniform value to the Renderer.
+   * @brief Sets uniform value to the Renderer.
    *
    * @param[in] renderer Renderer object.
    */
   void SetRendererUniform(Dali::Renderer renderer);
 
   /**
-   * @brief Get specular image based light texture offset.
+   * @brief Retrieves specular image based light texture offset.
    *
    * @return Specular image based light texture offset.
    */
   uint32_t GetSpecularImageBasedLightTextureOffset();
 
   /**
-   * @brief Get diffuse image based light texture offset.
+   * @brief Retrieves diffuse image based light texture offset.
    *
    * @return Diffuse image based light texture offset.
    */
   uint32_t GetDiffuseImageBasedLightTextureOffset();
 
   /**
-   * @brief Get image based light scale factor name.
+   * @brief Retrieves image based light scale factor name.
    *
    * @return Image based light scale factor name.
    */
   std::string_view GetImageBasedLightScaleFactorName();
 
   /**
-   * @brief Get image based light max lod uniform name.
+   * @brief Retrieves image based light max lod uniform name.
    *
    * @return Image based light max lod uniform name.
    */
   std::string_view GetImageBasedLightMaxLodUniformName();
 
   /**
-   * @brief Check if resource is ready.
+   * @brief Checks if resource is ready.
    *
    * @return True if resource is ready, false otherwise.
    */
   bool IsResourceReady();
 
   /**
-   * @brief Reset dirty flag of this material.
+   * @brief Resets dirty flag of this material.
    */
   void ResetFlag();
 
 private:
   /**
-   * @brief Check modify flag and send observers the material changeness.
+   * @brief Checks modify flag and send observers the material changeness.
    * It will clean up modify flag
    */
   void NotifyObserver();
 
   /**
-   * @brief Request loading an image from a URL and store it in TextureInformation.
+   * @brief Requests loading an image from a URL and store it in TextureInformation.
    *
    * @param[in] textureInformation TextureInformation object to store loaded texture information.
    * @param[in] url URL of the image to load.
@@ -272,16 +265,16 @@ private:
   void ResourcesLoadComplete();
 
   /**
-   * @brief Update the material using each attribute of this material and send a notification to the ModelPrimitive class.
+   * @brief Updates the material using each attribute of this material and send a notification to the ModelPrimitive class.
    */
   void Apply();
 
 private:
   // Delete copy & move operator
-  Material(const Material&) = delete;
-  Material(Material&&)      = delete;
+  Material(const Material&)                = delete;
+  Material(Material&&)                     = delete;
   Material& operator=(const Material& rhs) = delete;
-  Material& operator=(Material&& rhs) = delete;
+  Material& operator=(Material&& rhs)      = delete;
 
 private:
   ObserverContainer mObservers{}; ///< List of observers who need to be notified after some properties are changed.
@@ -296,9 +289,8 @@ private:
   float                                  mIor         = -1.0f;                                    ///< Index of refraction (TODO: Magic number)
   MaterialModifyObserver::ModifyFlag     mModifyFlag  = MaterialModifyObserver::ModifyFlag::NONE; ///< Modified dirty flags
 
-  Scene3D::Loader::ShaderDefinition::RawData mShaderData;
-
-  uint32_t                             mMaterialFlag  = 0u;
+  Scene3D::Loader::ShaderOption        mShaderOption;
+  uint32_t                             mMaterialFlag  = std::numeric_limits<uint32_t>::max();
   Scene3D::Loader::RendererState::Type mRendererState = Scene3D::Loader::RendererState::NONE;
 
   bool mIsOpaque = true;
index a37d4a8..7d3d5e1 100644 (file)
@@ -202,6 +202,8 @@ void ModelNode::AddModelPrimitive(Dali::Scene3D::ModelPrimitive modelPrimitive)
     }
   }
 
+  GetImplementation(modelPrimitive).UpdateShader(mShaderManager);
+
   Dali::Renderer renderer = GetImplementation(modelPrimitive).GetRenderer();
   if(renderer)
   {
@@ -244,6 +246,8 @@ void ModelNode::RemoveModelPrimitive(uint32_t index)
     return;
   }
 
+  GetImplementation(mModelPrimitiveContainer[index]).UpdateShader(nullptr);
+
   uint32_t maxLightCount = Scene3D::Internal::Light::GetMaximumEnabledLightCount();
   for(uint32_t i = 0; i < maxLightCount; ++i)
   {
@@ -338,6 +342,18 @@ void ModelNode::RemoveLight(uint32_t lightIndex)
   mLights[lightIndex].Reset();
 }
 
+void ModelNode::UpdateShader(Scene3D::Loader::ShaderManagerPtr shaderManager)
+{
+  if(mShaderManager != shaderManager)
+  {
+    mShaderManager = shaderManager;
+    for(auto&& primitive : mModelPrimitiveContainer)
+    {
+      GetImplementation(primitive).UpdateShader(mShaderManager);
+    }
+  }
+}
+
 void ModelNode::SetBlendShapeData(Scene3D::Loader::BlendShapes::BlendShapeData& data, Scene3D::ModelPrimitive primitive)
 {
   // Update mBlendShapeIndexMap
index 8a06116..1a56d60 100644 (file)
@@ -29,6 +29,7 @@
 #include <dali-scene3d/internal/model-components/model-primitive-modify-observer.h>
 #include <dali-scene3d/public-api/light/light.h>
 #include <dali-scene3d/public-api/loader/mesh-definition.h>
+#include <dali-scene3d/public-api/loader/shader-manager.h>
 #include <dali-scene3d/public-api/loader/skinning-details.h>
 #include <dali-scene3d/public-api/model-components/model-node.h>
 #include <dali-scene3d/public-api/model-components/model-primitive.h>
@@ -246,10 +247,29 @@ public: // Public Method
    */
   void SetImageBasedLightScaleFactor(float iblScaleFactor);
 
+  /**
+   * @brief Adds new Light.
+   *
+   * @param[in] light Newly added light.
+   * @param[in] lightIndex index of this light.
+   */
   void AddLight(Scene3D::Light light, uint32_t lightIndex);
+
+  /**
+   * @brief Removes new Light.
+   *
+   * @param[in] lightIndex index of light that will be removed.
+   */
   void RemoveLight(uint32_t lightIndex);
 
   /**
+   * @brief Updates shaders by using current material
+   *
+   * @param[in] shaderManager Shader manager to create shader.
+   */
+  void UpdateShader(Scene3D::Loader::ShaderManagerPtr shaderManager);
+
+  /**
    * @brief Sets the blend shape data for a ModelPrimitive.
    *
    * @param[in] data The blend shape data.
@@ -291,13 +311,14 @@ private:
   DALI_INTERNAL ModelNode& operator=(ModelNode&&) = delete;      ///< Deleted move assignment operator.
 
 private:
-  ModelPrimitiveContainer mModelPrimitiveContainer; ///< List of model primitives
-  BoneDataContainer       mBoneDataContainer;
-  BlendShapeIndexMap      mBlendShapeIndexMap; ///< Index of blend shape by name
-  Dali::Texture           mSpecularTexture;
-  Dali::Texture           mDiffuseTexture;
-  float                   mIblScaleFactor{1.0f};
-  uint32_t                mSpecularMipmapLevels{1u};
+  Scene3D::Loader::ShaderManagerPtr mShaderManager;
+  ModelPrimitiveContainer           mModelPrimitiveContainer; ///< List of model primitives
+  BoneDataContainer                 mBoneDataContainer;
+  BlendShapeIndexMap                mBlendShapeIndexMap;      ///< Index of blend shape by name
+  Dali::Texture                     mSpecularTexture;
+  Dali::Texture                     mDiffuseTexture;
+  float                             mIblScaleFactor{1.0f};
+  uint32_t                          mSpecularMipmapLevels{1u};
 
   // Light
   std::vector<Scene3D::Light> mLights;
index df71d6d..870f956 100644 (file)
@@ -29,6 +29,8 @@
 #include <dali-scene3d/internal/model-components/material-impl.h>
 #include <dali-scene3d/public-api/loader/environment-definition.h>
 
+#include <dali/integration-api/debug.h>
+
 namespace Dali
 {
 namespace Scene3D
@@ -49,11 +51,6 @@ BaseHandle Create()
 DALI_TYPE_REGISTRATION_BEGIN(Scene3D::ModelPrimitive, Dali::BaseHandle, Create);
 DALI_TYPE_REGISTRATION_END()
 
-constexpr std::string_view MORPH_POSITION_KEYWORD    = "MORPH_POSITION";
-constexpr std::string_view MORPH_NORMAL_KEYWORD      = "MORPH_NORMAL";
-constexpr std::string_view MORPH_TANGENT_KEYWORD     = "MORPH_TANGENT";
-constexpr std::string_view MORPH_VERSION_2_0_KEYWORD = "MORPH_VERSION_2_0";
-
 static constexpr uint32_t INDEX_FOR_LIGHT_CONSTRAINT_TAG = 10;
 } // unnamed namespace
 
@@ -67,6 +64,7 @@ ModelPrimitivePtr ModelPrimitive::New()
 }
 
 ModelPrimitive::ModelPrimitive()
+: mShaderManager(new Scene3D::Loader::ShaderManager())
 {
 }
 
@@ -225,6 +223,18 @@ void ModelPrimitive::RemoveLight(uint32_t lightIndex)
   mLights[lightIndex].Reset();
 }
 
+void ModelPrimitive::UpdateShader(Scene3D::Loader::ShaderManagerPtr shaderManager)
+{
+  if(mShaderManager != shaderManager)
+  {
+    mShaderManager = (shaderManager) ? shaderManager : new Scene3D::Loader::ShaderManager();
+    if(mMaterial && GetImplementation(mMaterial).IsResourceReady())
+    {
+      ApplyMaterialToRenderer(MaterialModifyObserver::ModifyFlag::SHADER);
+    }
+  }
+}
+
 void ModelPrimitive::SetBlendShapeData(Scene3D::Loader::BlendShapes::BlendShapeData& data)
 {
   mBlendShapeData = std::move(data);
@@ -236,11 +246,12 @@ void ModelPrimitive::SetBlendShapeGeometry(Dali::Texture blendShapeGeometry)
   mBlendShapeGeometry = blendShapeGeometry;
 }
 
-void ModelPrimitive::SetBlendShapeOptions(bool hasPositions, bool hasNormals, bool hasTangents)
+void ModelPrimitive::SetBlendShapeOptions(bool hasPositions, bool hasNormals, bool hasTangents, Scene3D::Loader::BlendShapes::Version version)
 {
-  mHasPositions = hasPositions;
-  mHasNormals   = hasNormals;
-  mHasTangents  = hasTangents;
+  mHasPositions      = hasPositions;
+  mHasNormals        = hasNormals;
+  mHasTangents       = hasTangents;
+  mBlendShapeVersion = version;
 }
 
 void ModelPrimitive::SetSkinned(bool isSkinned)
@@ -257,44 +268,43 @@ void ModelPrimitive::OnMaterialModified(Dali::Scene3D::Material material, Materi
 
 void ModelPrimitive::ApplyMaterialToRenderer(MaterialModifyObserver::ModifyFlag flag)
 {
+  if(!mMaterial)
+  {
+    return;
+  }
+
   uint32_t shaderFlag = (flag & static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::SHADER));
   if(mIsMaterialChanged || shaderFlag == static_cast<uint32_t>(MaterialModifyObserver::ModifyFlag::SHADER))
   {
-    std::string vertexShader   = GetImplementation(mMaterial).GetVertexShader();
-    std::string fragmentShader = GetImplementation(mMaterial).GetFragmentShader();
+    Scene3D::Loader::ShaderOption shaderOption = GetImplementation(mMaterial).GetShaderOption();
 
-    std::vector<std::string> defines;
-    defines.push_back("VEC4_TANGENT");
+    shaderOption.AddOption(Scene3D::Loader::ShaderOption::Type::VEC4_TANGENT);
     if(mHasSkinning)
     {
-      defines.push_back("SKINNING");
+      shaderOption.AddOption(Scene3D::Loader::ShaderOption::Type::SKINNING);
     }
     if(mHasPositions || mHasNormals || mHasTangents)
     {
       if(mHasPositions)
       {
-        defines.push_back(MORPH_POSITION_KEYWORD.data());
+        shaderOption.AddOption(Scene3D::Loader::ShaderOption::Type::MORPH_POSITION);
       }
       if(mHasNormals)
       {
-        defines.push_back(MORPH_NORMAL_KEYWORD.data());
+        shaderOption.AddOption(Scene3D::Loader::ShaderOption::Type::MORPH_NORMAL);
       }
       if(mHasTangents)
       {
-        defines.push_back(MORPH_TANGENT_KEYWORD.data());
+        shaderOption.AddOption(Scene3D::Loader::ShaderOption::Type::MORPH_TANGENT);
       }
-      if(mBlendShapeData.version == Scene3D::Loader::BlendShapes::Version::VERSION_2_0)
+      if(mBlendShapeVersion == Scene3D::Loader::BlendShapes::Version::VERSION_2_0)
       {
-        defines.push_back(MORPH_VERSION_2_0_KEYWORD.data());
+        shaderOption.AddOption(Scene3D::Loader::ShaderOption::Type::MORPH_VERSION_2_0);
       }
     }
-    for(const auto& define : defines)
-    {
-      Scene3D::Loader::ShaderDefinition::ApplyDefine(vertexShader, define);
-    }
 
     mShader.Reset();
-    mShader = Shader::New(vertexShader, fragmentShader);
+    mShader = mShaderManager->ProduceShader(shaderOption);
 
     if(!mRenderer)
     {
@@ -445,9 +455,12 @@ void ModelPrimitive::UpdateImageBasedLightTexture()
 
 void ModelPrimitive::UpdateRendererUniform()
 {
-  mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightScaleFactorName().data(), mIblScaleFactor);
-  mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightMaxLodUniformName().data(), static_cast<float>(mSpecularMipmapLevels));
-  GetImplementation(mMaterial).SetRendererUniform(mRenderer);
+  if(mMaterial)
+  {
+    mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightScaleFactorName().data(), mIblScaleFactor);
+    mRenderer.RegisterProperty(GetImplementation(mMaterial).GetImageBasedLightMaxLodUniformName().data(), static_cast<float>(mSpecularMipmapLevels));
+    GetImplementation(mMaterial).SetRendererUniform(mRenderer);
+  }
 }
 
 } // namespace Internal
index 027ecac..f37eba6 100644 (file)
@@ -32,6 +32,7 @@
 #include <dali-scene3d/public-api/light/light.h>
 #include <dali-scene3d/public-api/loader/blend-shape-details.h>
 #include <dali-scene3d/public-api/loader/mesh-definition.h>
+#include <dali-scene3d/public-api/loader/shader-manager.h>
 #include <dali-scene3d/public-api/model-components/material.h>
 #include <dali-scene3d/public-api/model-components/model-primitive.h>
 
@@ -155,6 +156,13 @@ public:
   void RemoveLight(uint32_t lightIndex);
 
   /**
+   * @brief Updates shaders by using current material
+   *
+   * @param[in] shaderManager Shader manager to create shader.
+   */
+  void UpdateShader(Scene3D::Loader::ShaderManagerPtr shaderManager);
+
+  /**
    * @brief Sets the blend shape data for this model primitive.
    *
    * @param[in] data The blend shape data to set.
@@ -174,8 +182,9 @@ public:
    * @param[in] hasPositions Whether or not this model primitive has positions for blend shapes.
    * @param[in] hasNormals Whether or not this model primitive has normals for blend shapes.
    * @param[in] hasTangents Whether or not this model primitive has tangents for blend shapes.
+   * @param[in] version blendShape version.
    */
-  void SetBlendShapeOptions(bool hasPositions, bool hasNormals, bool hasTangents);
+  void SetBlendShapeOptions(bool hasPositions, bool hasNormals, bool hasTangents, Scene3D::Loader::BlendShapes::Version version);
 
   /**
    * @brief Sets whether or not this model primitive is skinned.
@@ -228,6 +237,8 @@ private:
   Dali::TextureSet        mTextureSet;
   Dali::Scene3D::Material mMaterial;
 
+  Scene3D::Loader::ShaderManagerPtr mShaderManager;
+
   // Light
   std::vector<Scene3D::Light> mLights;
   int32_t                     mLightCount{0};
@@ -241,10 +252,11 @@ private:
   // For blend shape
   Scene3D::Loader::BlendShapes::BlendShapeData mBlendShapeData;
   Dali::Texture                                mBlendShapeGeometry;
-  bool                                         mHasSkinning  = false;
-  bool                                         mHasPositions = false;
-  bool                                         mHasNormals   = false;
-  bool                                         mHasTangents  = false;
+  bool                                         mHasSkinning       = false;
+  bool                                         mHasPositions      = false;
+  bool                                         mHasNormals        = false;
+  bool                                         mHasTangents       = false;
+  Scene3D::Loader::BlendShapes::Version        mBlendShapeVersion = Scene3D::Loader::BlendShapes::Version::INVALID;
 
   bool mIsMaterialChanged        = false;
   bool mNeedToSetRendererUniform = false;
index 783a86b..363c45c 100644 (file)
@@ -28,8 +28,8 @@ set(scene3d_src_files ${scene3d_src_files}
        ${scene3d_public_api_dir}/loader/resource-bundle.cpp
        ${scene3d_public_api_dir}/loader/scene-definition.cpp
        ${scene3d_public_api_dir}/loader/shader-definition.cpp
-       ${scene3d_public_api_dir}/loader/shader-definition-factory.cpp
-       ${scene3d_public_api_dir}/loader/shader-definition-option.cpp
+       ${scene3d_public_api_dir}/loader/shader-manager.cpp
+       ${scene3d_public_api_dir}/loader/shader-option.cpp
        ${scene3d_public_api_dir}/loader/skinning-details.cpp
        ${scene3d_public_api_dir}/loader/string-callback.cpp
        ${scene3d_public_api_dir}/loader/utils.cpp
index 16d0189..d3e8c36 100644 (file)
 #include <dali/integration-api/debug.h>
 
 // INTERNAL INCLUDES
+#include <dali-scene3d/internal/light/light-impl.h>
 #include <dali-scene3d/internal/model-components/material-impl.h>
+#include <dali-scene3d/internal/model-components/model-node-impl.h>
 #include <dali-scene3d/internal/model-components/model-primitive-impl.h>
 #include <dali-scene3d/public-api/loader/renderer-state.h>
 #include <dali-scene3d/public-api/loader/utils.h>
-#include <dali-scene3d/internal/light/light-impl.h>
 
 namespace Dali
 {
@@ -255,7 +256,20 @@ void ModelRenderable::ReflectResources(IResourceReflector& reflector)
 void ModelRenderable::OnCreate(const NodeDefinition& nodeDefinition, NodeDefinition::CreateParams& params, ModelNode& node) const
 {
   DALI_ASSERT_DEBUG(mMeshIdx != INVALID_INDEX);
-  Renderable::OnCreate(nodeDefinition, params, node);
+  if(mShaderIdx == INVALID_INDEX)
+  {
+    Shader          shader          = params.mShaderManager->ProduceShader(params.mResources.mMaterials[mMaterialIdx].first, params.mResources.mMeshes[mMeshIdx].first);
+    static Geometry defaultGeometry = Geometry::New();
+    Renderer        renderer        = Renderer::New(defaultGeometry, shader);
+
+    RendererState::Apply(params.mShaderManager->GetRendererState(params.mResources.mMaterials[mMaterialIdx].first), renderer);
+    Internal::GetImplementation(node).UpdateShader(params.mShaderManager);
+    node.AddRenderer(renderer);
+  }
+  else
+  {
+    Renderable::OnCreate(nodeDefinition, params, node);
+  }
 
   auto& resources = params.mResources;
   auto& mesh      = resources.mMeshes[mMeshIdx];
@@ -299,7 +313,7 @@ void ModelRenderable::OnCreate(const NodeDefinition& nodeDefinition, NodeDefinit
     bool hasNormals   = false;
     bool hasTangents  = false;
     mesh.first.RetrieveBlendShapeComponents(hasPositions, hasNormals, hasTangents);
-    GetImplementation(primitive).SetBlendShapeOptions(hasPositions, hasNormals, hasTangents);
+    GetImplementation(primitive).SetBlendShapeOptions(hasPositions, hasNormals, hasTangents, mesh.first.mBlendShapeVersion);
     GetImplementation(primitive).SetBlendShapeGeometry(mesh.second.blendShapeGeometry);
     GetImplementation(primitive).SetSkinned(mesh.first.IsSkinned());
   }
@@ -360,6 +374,8 @@ void ModelRenderable::OnCreate(const NodeDefinition& nodeDefinition, NodeDefinit
 
   node.SetProperty(Actor::Property::COLOR, mColor);
 
+  // If user uses customshader, the properties of the shader could not be changed by Material.
+  if(mShaderIdx == INVALID_INDEX)
   {
     matDef.mMaterial            = Material::New();
     auto     material           = matDef.mMaterial;
index 02d056f..f3aa578 100644 (file)
@@ -30,6 +30,7 @@
 #include <dali-scene3d/public-api/loader/customization.h>
 #include <dali-scene3d/public-api/loader/matrix-stack.h>
 #include <dali-scene3d/public-api/loader/resource-bundle.h>
+#include <dali-scene3d/public-api/loader/shader-manager.h>
 #include <dali-scene3d/public-api/model-components/model-node.h>
 
 namespace Dali
@@ -150,8 +151,9 @@ public: // TYPES
   struct CreateParams
   {
   public: // input
-    ResourceBundle& mResources;
-    Transforms&     mXforms;
+    ResourceBundle&                         mResources;
+    Transforms&                             mXforms;
+    Dali::Scene3D::Loader::ShaderManagerPtr mShaderManager;
 
   public: // output
     std::vector<ConstraintRequest>                    mConstrainables;
index cf5aa61..370e926 100644 (file)
@@ -48,39 +48,50 @@ const std::map<Property::Type, Constraint (*)(Actor&, Property::Index)>& GetCons
 {
   static const std::map<Property::Type, Constraint (*)(Actor&, Property::Index)> sConstraintFactory = {
     {Property::Type::BOOLEAN,
-     [](Actor& a, Property::Index i) {
-       return Constraint::New<bool>(a, i, [](bool& current, const PropertyInputContainer& inputs) { current = inputs[0]->GetBoolean(); });
+     [](Actor& a, Property::Index i)
+     {
+       return Constraint::New<bool>(a, i, [](bool& current, const PropertyInputContainer& inputs)
+                                    { current = inputs[0]->GetBoolean(); });
      }},
     {Property::Type::INTEGER,
-     [](Actor& a, Property::Index i) {
-       return Constraint::New<int>(a, i, [](int& current, const PropertyInputContainer& inputs) { current = inputs[0]->GetInteger(); });
+     [](Actor& a, Property::Index i)
+     {
+       return Constraint::New<int>(a, i, [](int& current, const PropertyInputContainer& inputs)
+                                   { current = inputs[0]->GetInteger(); });
      }},
     {Property::Type::FLOAT,
-     [](Actor& a, Property::Index i) {
+     [](Actor& a, Property::Index i)
+     {
        return Constraint::New<float>(a, i, EqualToConstraint());
      }},
     {Property::Type::VECTOR2,
-     [](Actor& a, Property::Index i) {
+     [](Actor& a, Property::Index i)
+     {
        return Constraint::New<Vector2>(a, i, EqualToConstraint());
      }},
     {Property::Type::VECTOR3,
-     [](Actor& a, Property::Index i) {
+     [](Actor& a, Property::Index i)
+     {
        return Constraint::New<Vector3>(a, i, EqualToConstraint());
      }},
     {Property::Type::VECTOR4,
-     [](Actor& a, Property::Index i) {
+     [](Actor& a, Property::Index i)
+     {
        return Constraint::New<Vector4>(a, i, EqualToConstraint());
      }},
     {Property::Type::MATRIX,
-     [](Actor& a, Property::Index i) {
+     [](Actor& a, Property::Index i)
+     {
        return Constraint::New<Matrix>(a, i, EqualToConstraint());
      }},
     {Property::Type::MATRIX3,
-     [](Actor& a, Property::Index i) {
+     [](Actor& a, Property::Index i)
+     {
        return Constraint::New<Matrix3>(a, i, EqualToConstraint());
      }},
     {Property::Type::ROTATION,
-     [](Actor& a, Property::Index i) {
+     [](Actor& a, Property::Index i)
+     {
        return Constraint::New<Quaternion>(a, i, EqualToConstraint());
      }},
   };
@@ -159,7 +170,7 @@ void AddJointDebugVisual(Actor aJoint)
 
   aJoint.SetVisible(true);
 }
-#endif //DEBUG_JOINTS
+#endif // DEBUG_JOINTS
 
 class ActorCreatorVisitor : public NodeDefinition::IVisitor
 {
@@ -234,7 +245,8 @@ void SortAndDeduplicateRequests(std::vector<RequestType>& requests)
     ++iter;
   } while(true);
 
-  requests.erase(std::remove_if(requests.begin(), requests.end(), [](const RequestType& sscr) { return !sscr.mShader; }),
+  requests.erase(std::remove_if(requests.begin(), requests.end(), [](const RequestType& sscr)
+                                { return !sscr.mShader; }),
                  requests.end());
 }
 
@@ -371,7 +383,10 @@ void SceneDefinition::CountResourceRefs(Index iNode, const Customization::Choice
 
     void Register(ResourceType::Value type, Index id)
     {
-      ++(*refCounts)[type][id];
+      if((!(*refCounts)[type].Empty()) && (id >= 0) && ((*refCounts)[type].Size() > id))
+      {
+        ++(*refCounts)[type][id];
+      }
     }
   };
 
@@ -479,15 +494,15 @@ bool SceneDefinition::ReparentNode(const std::string& name, const std::string& n
   auto& node  = *nodePtr;
   auto  iNode = std::distance(mNodes.data(), nodePtr);
 
-  DEBUG_ONLY(auto dumpNode = [](NodeDefinition const& n) {
+  DEBUG_ONLY(auto dumpNode = [](NodeDefinition const& n)
+             {
     std::ostringstream stream;
     stream << n.mName << " (" << n.mParentIdx << "):";
     for(auto i : n.mChildren)
     {
       stream << i << ", ";
     }
-    LOGD(("%s", stream.str().c_str()));
-  };)
+    LOGD(("%s", stream.str().c_str())); };)
 
   // Remove node from children of previous parent (if any).
   if(node->mParentIdx != INVALID_INDEX)
@@ -533,15 +548,16 @@ bool SceneDefinition::RemoveNode(const std::string& name)
   auto&                                                 thisNodes = mNodes;
   unsigned int                                          numReset  = 0;
   std::function<void(std::unique_ptr<NodeDefinition>&)> resetFn =
-    [&thisNodes, &resetFn, &numReset](std::unique_ptr<NodeDefinition>& nd) {
-      LOGD(("resetting %d", &nd - thisNodes.data()));
-      for(auto i : nd->mChildren)
-      {
-        resetFn(thisNodes[i]);
-      }
-      nd.reset();
-      ++numReset;
-    };
+    [&thisNodes, &resetFn, &numReset](std::unique_ptr<NodeDefinition>& nd)
+  {
+    LOGD(("resetting %d", &nd - thisNodes.data()));
+    for(auto i : nd->mChildren)
+    {
+      resetFn(thisNodes[i]);
+    }
+    nd.reset();
+    ++numReset;
+  };
 
   resetFn(*node);
 
@@ -564,7 +580,8 @@ bool SceneDefinition::RemoveNode(const std::string& name)
   {
     INDEX_FOR_REMOVAL = INVALID_INDEX
   };
-  auto offsetter = [&offsets](Index& i) {
+  auto offsetter = [&offsets](Index& i)
+  {
     auto iFind = std::lower_bound(offsets.begin(), offsets.end(), i);
     if(iFind != offsets.end() && *iFind == i)
     {
@@ -604,7 +621,8 @@ bool SceneDefinition::RemoveNode(const std::string& name)
 void SceneDefinition::GetNodeModelStack(Index index, MatrixStack& model) const
 {
   auto&                    thisNodes  = mNodes;
-  std::function<void(int)> buildStack = [&model, &thisNodes, &buildStack](int i) {
+  std::function<void(int)> buildStack = [&model, &thisNodes, &buildStack](int i)
+  {
     auto node = thisNodes[i].get();
     if(node->mParentIdx != INVALID_INDEX)
     {
@@ -619,7 +637,8 @@ NodeDefinition* SceneDefinition::FindNode(const std::string& name, Index* outInd
 {
   auto iBegin = mNodes.begin();
   auto iEnd   = mNodes.end();
-  auto iFind  = std::find_if(iBegin, iEnd, [&name](const std::unique_ptr<NodeDefinition>& nd) { return nd->mName == name; });
+  auto iFind  = std::find_if(iBegin, iEnd, [&name](const std::unique_ptr<NodeDefinition>& nd)
+                            { return nd->mName == name; });
 
   auto result = iFind != iEnd ? iFind->get() : nullptr;
   if(result && outIndex)
@@ -633,7 +652,8 @@ const NodeDefinition* SceneDefinition::FindNode(const std::string& name, Index*
 {
   auto iBegin = mNodes.begin();
   auto iEnd   = mNodes.end();
-  auto iFind  = std::find_if(iBegin, iEnd, [&name](const std::unique_ptr<NodeDefinition>& nd) { return nd->mName == name; });
+  auto iFind  = std::find_if(iBegin, iEnd, [&name](const std::unique_ptr<NodeDefinition>& nd)
+                            { return nd->mName == name; });
 
   auto result = iFind != iEnd ? iFind->get() : nullptr;
   if(result && outIndex)
@@ -647,7 +667,8 @@ Index SceneDefinition::FindNodeIndex(const NodeDefinition& node) const
 {
   auto iBegin = mNodes.begin();
   auto iEnd   = mNodes.end();
-  auto iFind  = std::find_if(iBegin, iEnd, [&node](const std::unique_ptr<NodeDefinition>& n) { return n.get() == &node; });
+  auto iFind  = std::find_if(iBegin, iEnd, [&node](const std::unique_ptr<NodeDefinition>& n)
+                            { return n.get() == &node; });
   return iFind != iEnd ? std::distance(iBegin, iFind) : INVALID_INDEX;
 }
 
@@ -938,7 +959,8 @@ bool SceneDefinition::FindNode(const std::string& name, std::unique_ptr<NodeDefi
   // We're searching from the end assuming a higher probability of operations targeting
   // recently added nodes. (conf.: root, which is immovable, cannot be removed, and was
   // the first to be added, is index 0.)
-  auto iFind = std::find_if(mNodes.rbegin(), mNodes.rend(), [&name](const std::unique_ptr<NodeDefinition>& nd) { return nd->mName == name; })
+  auto iFind = std::find_if(mNodes.rbegin(), mNodes.rend(), [&name](const std::unique_ptr<NodeDefinition>& nd)
+                            { return nd->mName == name; })
                  .base();
 
   const bool success = iFind != mNodes.begin();
diff --git a/dali-scene3d/public-api/loader/shader-definition-factory.cpp b/dali-scene3d/public-api/loader/shader-definition-factory.cpp
deleted file mode 100644 (file)
index 5eadd67..0000000
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// CLASS HEADER
-#include <dali-scene3d/public-api/loader/shader-definition-factory.h>
-
-// EXTERNAL INCLUDES
-#include <dali/devel-api/common/map-wrapper.h>
-#include <cstring>
-
-// INTERNAL INCLUDES
-#include <dali-scene3d/internal/loader/hash.h>
-#include <dali-scene3d/public-api/loader/blend-shape-details.h>
-#include <dali-scene3d/public-api/loader/node-definition.h>
-#include <dali-scene3d/public-api/loader/shader-definition-option.h>
-
-namespace Dali::Scene3D::Loader
-{
-namespace
-{
-struct ResourceReceiver : IResourceReceiver
-{
-  const ResourceBundle&     mResources;
-  const MeshDefinition*     mMeshDef     = nullptr;
-  const MaterialDefinition* mMaterialDef = nullptr;
-
-  ResourceReceiver(const ResourceBundle& resources)
-  : mResources(resources)
-  {
-  }
-
-  void Register(ResourceType::Value type, Index id) override
-  {
-    switch(type)
-    {
-      case ResourceType::Mesh:
-        mMeshDef = &mResources.mMeshes[id].first;
-        break;
-
-      case ResourceType::Material:
-        mMaterialDef = &mResources.mMaterials[id].first;
-        break;
-
-      default:
-        break;
-    }
-  }
-};
-
-ShaderDefinitionOption MakeOption(const MaterialDefinition& materialDef, const MeshDefinition& meshDef)
-{
-  ShaderDefinitionOption option;
-
-  const bool hasTransparency = MaskMatch(materialDef.mFlags, MaterialDefinition::TRANSPARENCY);
-  if(hasTransparency)
-  {
-    option.SetTransparency();
-  }
-
-  if(hasTransparency ||
-     !materialDef.CheckTextures(MaterialDefinition::ALBEDO | MaterialDefinition::METALLIC) ||
-     !materialDef.CheckTextures(MaterialDefinition::NORMAL | MaterialDefinition::ROUGHNESS))
-  {
-    option.AddOption(ShaderDefinitionOption::Type::THREE_TEXTURE);
-
-    // For the glTF, each of basecolor, metallic_roughness, normal texture is not essential.
-    if(MaskMatch(materialDef.mFlags, MaterialDefinition::ALBEDO))
-    {
-      option.AddOption(ShaderDefinitionOption::Type::BASE_COLOR_TEXTURE);
-    }
-
-    if(materialDef.CheckTextures(MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS))
-    {
-      option.AddOption(ShaderDefinitionOption::Type::METALLIC_ROUGHNESS_TEXTURE);
-    }
-
-    if(MaskMatch(materialDef.mFlags, MaterialDefinition::NORMAL))
-    {
-      option.AddOption(ShaderDefinitionOption::Type::NORMAL_TEXTURE);
-    }
-  }
-
-  if(materialDef.GetAlphaCutoff() > 0.f)
-  {
-    option.AddOption(ShaderDefinitionOption::Type::ALPHA_TEST);
-  }
-
-  if(MaskMatch(materialDef.mFlags, MaterialDefinition::SUBSURFACE))
-  {
-    option.AddOption(ShaderDefinitionOption::Type::SUBSURFACE);
-  }
-
-  if(MaskMatch(materialDef.mFlags, MaterialDefinition::OCCLUSION))
-  {
-    option.AddOption(ShaderDefinitionOption::Type::OCCLUSION);
-  }
-
-  if(MaskMatch(materialDef.mFlags, MaterialDefinition::EMISSIVE))
-  {
-    option.AddOption(ShaderDefinitionOption::Type::EMISSIVE);
-  }
-
-  if(MaskMatch(materialDef.mFlags, MaterialDefinition::SPECULAR))
-  {
-    option.AddOption(ShaderDefinitionOption::Type::SPECULAR);
-  }
-
-  if(MaskMatch(materialDef.mFlags, MaterialDefinition::SPECULAR_COLOR))
-  {
-    option.AddOption(ShaderDefinitionOption::Type::SPECULAR_COLOR);
-  }
-
-  if(MaskMatch(materialDef.mFlags, MaterialDefinition::GLTF_CHANNELS))
-  {
-    option.AddOption(ShaderDefinitionOption::Type::GLTF_CHANNELS);
-  }
-
-  if(meshDef.IsSkinned())
-  {
-    option.AddOption(ShaderDefinitionOption::Type::SKINNING);
-  }
-
-  if(MaskMatch(meshDef.mFlags, MeshDefinition::FLIP_UVS_VERTICAL))
-  {
-    option.AddOption(ShaderDefinitionOption::Type::FLIP_UVS_VERTICAL);
-  }
-
-  if(meshDef.mColors.IsDefined())
-  {
-    option.AddOption(ShaderDefinitionOption::Type::COLOR_ATTRIBUTE);
-  }
-
-  if(meshDef.mTangentType == Property::VECTOR4)
-  {
-    option.AddOption(ShaderDefinitionOption::Type::VEC4_TANGENT);
-  }
-
-  if(meshDef.HasBlendShapes())
-  {
-    bool hasPositions = false;
-    bool hasNormals   = false;
-    bool hasTangents  = false;
-    meshDef.RetrieveBlendShapeComponents(hasPositions, hasNormals, hasTangents);
-    if(hasPositions)
-    {
-      option.AddOption(ShaderDefinitionOption::Type::MORPH_POSITION);
-    }
-
-    if(hasNormals)
-    {
-      option.AddOption(ShaderDefinitionOption::Type::MORPH_NORMAL);
-    }
-
-    if(hasTangents)
-    {
-      option.AddOption(ShaderDefinitionOption::Type::MORPH_TANGENT);
-    }
-
-    if(hasPositions || hasNormals || hasTangents)
-    {
-      if(BlendShapes::Version::VERSION_2_0 == meshDef.mBlendShapeVersion)
-      {
-        option.AddOption(ShaderDefinitionOption::Type::MORPH_VERSION_2_0);
-      }
-    }
-  }
-
-  return option;
-}
-} // namespace
-
-struct ShaderDefinitionFactory::Impl
-{
-  ResourceBundle*           mResources; // no ownership
-  std::map<uint64_t, Index> mShaderMap;
-};
-
-ShaderDefinitionFactory::ShaderDefinitionFactory()
-: mImpl{new Impl()}
-{
-}
-
-ShaderDefinitionFactory::~ShaderDefinitionFactory() = default;
-
-void ShaderDefinitionFactory::SetResources(ResourceBundle& resources)
-{
-  mImpl->mResources = &resources;
-  mImpl->mShaderMap.clear();
-}
-
-Index ShaderDefinitionFactory::ProduceShader(NodeDefinition::Renderable& renderable)
-{
-  auto& resources = *mImpl->mResources;
-
-  ResourceReceiver receiver{resources};
-  renderable.RegisterResources(receiver);
-
-  if(!(receiver.mMeshDef && receiver.mMaterialDef))
-  {
-    renderable.mShaderIdx = INVALID_INDEX;
-    return INVALID_INDEX;
-  }
-
-  auto&                  shaderMap = mImpl->mShaderMap;
-  ShaderDefinitionOption option    = MakeOption(*receiver.mMaterialDef, *receiver.mMeshDef);
-  uint64_t               hash      = option.GetOptionHash();
-  auto                   iFind     = shaderMap.find(hash);
-  if(iFind != shaderMap.end())
-  {
-    renderable.mShaderIdx = iFind->second;
-  }
-  else
-  {
-    ShaderDefinition shaderDef;
-    shaderDef.mUseBuiltInShader = true;
-    shaderDef.mRendererState    = RendererState::DEPTH_TEST;
-
-    auto& materialDef = *receiver.mMaterialDef;
-    if(!materialDef.mDoubleSided)
-    {
-      shaderDef.mRendererState |= RendererState::CULL_BACK;
-    }
-
-    const bool hasTransparency = MaskMatch(materialDef.mFlags, MaterialDefinition::TRANSPARENCY);
-    if(hasTransparency)
-    {
-      // TODO: this requires more granularity
-      shaderDef.mRendererState = (shaderDef.mRendererState | RendererState::ALPHA_BLEND);
-    }
-
-    option.GetDefines(shaderDef.mDefines);
-    shaderDef.mUniforms["uCubeMatrix"] = Matrix::IDENTITY;
-
-    Index result    = resources.mShaders.size();
-    shaderMap[hash] = result;
-
-    resources.mShaders.emplace_back(std::move(shaderDef), Shader());
-
-    renderable.mShaderIdx = result;
-  }
-
-  return renderable.mShaderIdx;
-}
-
-} // namespace Dali::Scene3D::Loader
diff --git a/dali-scene3d/public-api/loader/shader-definition-factory.h b/dali-scene3d/public-api/loader/shader-definition-factory.h
deleted file mode 100644 (file)
index 273ac8f..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-#ifndef DALI_SCENE3D_LOADER_SHADER_DEFINITION_FACTORY_H_
-#define DALI_SCENE3D_LOADER_SHADER_DEFINITION_FACTORY_H_
-/*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-// EXTERNAL INCLUDER
-#include <memory>
-
-// INTERNAL INCLUDES
-#include <dali-scene3d/public-api/api.h>
-#include <dali-scene3d/public-api/loader/index.h>
-#include <dali-scene3d/public-api/loader/node-definition.h>
-
-namespace Dali::Scene3D::Loader
-{
-struct NodeDefinition;
-class ResourceBundle;
-
-class DALI_SCENE3D_API ShaderDefinitionFactory
-{
-public:
-  ShaderDefinitionFactory();
-  ~ShaderDefinitionFactory();
-
-  /*
-   * @brief Input for meshes and materials, output for shaders.
-   */
-  void SetResources(ResourceBundle& resources);
-
-  /*
-   * @brief Produces the index of a shader, which should be used to index into the shaders
-   *  vector of the ResourceBundle which was provided for the factory. This shader will be
-   *  created if one with the given settings hasn't been created by the factory yet (shaders
-   *  already existing in the ResourceBundle are ignored), otherwise the index of the previously
-   *  created shader will be returned.
-   */
-  Index ProduceShader(NodeDefinition::Renderable& renderable);
-
-private:
-  struct Impl;
-  const std::unique_ptr<Impl> mImpl;
-};
-
-} // namespace Dali::Scene3D::Loader
-
-#endif //DALI_SCENE3D_LOADER_SHADER_DEFINITION_FACTORY_H_
index 27bb051..61f4a7c 100644 (file)
@@ -52,7 +52,7 @@ struct DALI_SCENE3D_API ShaderDefinition
   ShaderDefinition(const ShaderDefinition& other);
   ShaderDefinition& operator=(const ShaderDefinition& other);
 
-  ShaderDefinition(ShaderDefinition&&) = default;
+  ShaderDefinition(ShaderDefinition&&)            = default;
   ShaderDefinition& operator=(ShaderDefinition&&) = default;
 
   /*
diff --git a/dali-scene3d/public-api/loader/shader-manager.cpp b/dali-scene3d/public-api/loader/shader-manager.cpp
new file mode 100644 (file)
index 0000000..0978f20
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-scene3d/public-api/loader/shader-manager.h>
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/common/map-wrapper.h>
+#include <cstring>
+
+// INTERNAL INCLUDES
+#include <dali-scene3d/internal/loader/hash.h>
+#include <dali-scene3d/public-api/loader/blend-shape-details.h>
+#include <dali-scene3d/public-api/loader/node-definition.h>
+
+namespace Dali::Scene3D::Loader
+{
+namespace
+{
+
+ShaderOption MakeOption(const MaterialDefinition& materialDef, const MeshDefinition& meshDef)
+{
+  ShaderOption option;
+
+  const bool hasTransparency = MaskMatch(materialDef.mFlags, MaterialDefinition::TRANSPARENCY);
+  if(hasTransparency)
+  {
+    option.SetTransparency();
+  }
+
+  if(hasTransparency ||
+     !materialDef.CheckTextures(MaterialDefinition::ALBEDO | MaterialDefinition::METALLIC) ||
+     !materialDef.CheckTextures(MaterialDefinition::NORMAL | MaterialDefinition::ROUGHNESS))
+  {
+    option.AddOption(ShaderOption::Type::THREE_TEXTURE);
+
+    // For the glTF, each of basecolor, metallic_roughness, normal texture is not essential.
+    if(MaskMatch(materialDef.mFlags, MaterialDefinition::ALBEDO))
+    {
+      option.AddOption(ShaderOption::Type::BASE_COLOR_TEXTURE);
+    }
+
+    if(materialDef.CheckTextures(MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS))
+    {
+      option.AddOption(ShaderOption::Type::METALLIC_ROUGHNESS_TEXTURE);
+    }
+
+    if(MaskMatch(materialDef.mFlags, MaterialDefinition::NORMAL))
+    {
+      option.AddOption(ShaderOption::Type::NORMAL_TEXTURE);
+    }
+  }
+
+  if(materialDef.GetAlphaCutoff() > 0.f)
+  {
+    option.AddOption(ShaderOption::Type::ALPHA_TEST);
+  }
+
+  if(MaskMatch(materialDef.mFlags, MaterialDefinition::SUBSURFACE))
+  {
+    option.AddOption(ShaderOption::Type::SUBSURFACE);
+  }
+
+  if(MaskMatch(materialDef.mFlags, MaterialDefinition::OCCLUSION))
+  {
+    option.AddOption(ShaderOption::Type::OCCLUSION);
+  }
+
+  if(MaskMatch(materialDef.mFlags, MaterialDefinition::EMISSIVE))
+  {
+    option.AddOption(ShaderOption::Type::EMISSIVE);
+  }
+
+  if(MaskMatch(materialDef.mFlags, MaterialDefinition::SPECULAR))
+  {
+    option.AddOption(ShaderOption::Type::SPECULAR);
+  }
+
+  if(MaskMatch(materialDef.mFlags, MaterialDefinition::SPECULAR_COLOR))
+  {
+    option.AddOption(ShaderOption::Type::SPECULAR_COLOR);
+  }
+
+  if(MaskMatch(materialDef.mFlags, MaterialDefinition::GLTF_CHANNELS))
+  {
+    option.AddOption(ShaderOption::Type::GLTF_CHANNELS);
+  }
+
+  if(meshDef.IsSkinned())
+  {
+    option.AddOption(ShaderOption::Type::SKINNING);
+  }
+
+  if(MaskMatch(meshDef.mFlags, MeshDefinition::FLIP_UVS_VERTICAL))
+  {
+    option.AddOption(ShaderOption::Type::FLIP_UVS_VERTICAL);
+  }
+
+  if(meshDef.mColors.IsDefined())
+  {
+    option.AddOption(ShaderOption::Type::COLOR_ATTRIBUTE);
+  }
+
+  if(meshDef.mTangentType == Property::VECTOR4)
+  {
+    option.AddOption(ShaderOption::Type::VEC4_TANGENT);
+  }
+
+  if(meshDef.HasBlendShapes())
+  {
+    bool hasPositions = false;
+    bool hasNormals   = false;
+    bool hasTangents  = false;
+    meshDef.RetrieveBlendShapeComponents(hasPositions, hasNormals, hasTangents);
+    if(hasPositions)
+    {
+      option.AddOption(ShaderOption::Type::MORPH_POSITION);
+    }
+
+    if(hasNormals)
+    {
+      option.AddOption(ShaderOption::Type::MORPH_NORMAL);
+    }
+
+    if(hasTangents)
+    {
+      option.AddOption(ShaderOption::Type::MORPH_TANGENT);
+    }
+
+    if(hasPositions || hasNormals || hasTangents)
+    {
+      if(BlendShapes::Version::VERSION_2_0 == meshDef.mBlendShapeVersion)
+      {
+        option.AddOption(ShaderOption::Type::MORPH_VERSION_2_0);
+      }
+    }
+  }
+
+  return option;
+}
+} // namespace
+
+struct ShaderManager::Impl
+{
+  std::map<uint64_t, Index> mShaderMap;
+  std::vector<Dali::Shader> mShaders;
+};
+
+ShaderManager::ShaderManager()
+: mImpl{new Impl()}
+{
+}
+
+ShaderManager::~ShaderManager() = default;
+
+Dali::Shader ShaderManager::ProduceShader(const MaterialDefinition& materialDefinition, const MeshDefinition& meshDefinition)
+{
+  ShaderOption option = MakeOption(materialDefinition, meshDefinition);
+  return ProduceShader(option);
+}
+
+Dali::Shader ShaderManager::ProduceShader(const ShaderOption& shaderOption)
+{
+  Dali::Shader result;
+
+  auto&    shaderMap = mImpl->mShaderMap;
+  uint64_t hash      = shaderOption.GetOptionHash();
+  auto     iFind     = shaderMap.find(hash);
+  if(iFind != shaderMap.end())
+  {
+    result = mImpl->mShaders[iFind->second];
+  }
+  else
+  {
+    ShaderDefinition shaderDef;
+    shaderDef.mUseBuiltInShader = true;
+
+    shaderOption.GetDefines(shaderDef.mDefines);
+    shaderDef.mUniforms["uCubeMatrix"] = Matrix::IDENTITY;
+
+    shaderMap[hash] = mImpl->mShaders.size();
+
+    auto raw = shaderDef.LoadRaw("");
+    mImpl->mShaders.emplace_back(shaderDef.Load(std::move(raw)));
+    result = mImpl->mShaders.back();
+  }
+
+  return result;
+}
+
+RendererState::Type ShaderManager::GetRendererState(const MaterialDefinition& materialDefinition)
+{
+  RendererState::Type rendererState = RendererState::DEPTH_TEST;
+
+  if(!materialDefinition.mDoubleSided)
+  {
+    rendererState |= RendererState::CULL_BACK;
+  }
+
+  const bool hasTransparency = MaskMatch(materialDefinition.mFlags, MaterialDefinition::TRANSPARENCY);
+  if(hasTransparency)
+  {
+    // TODO: this requires more granularity
+    rendererState = (rendererState | RendererState::ALPHA_BLEND);
+  }
+  return rendererState;
+}
+
+} // namespace Dali::Scene3D::Loader
diff --git a/dali-scene3d/public-api/loader/shader-manager.h b/dali-scene3d/public-api/loader/shader-manager.h
new file mode 100644 (file)
index 0000000..4c8988a
--- /dev/null
@@ -0,0 +1,83 @@
+#ifndef DALI_SCENE3D_LOADER_SHADER_MANAGER_H_
+#define DALI_SCENE3D_LOADER_SHADER_MANAGER_H_
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDER
+#include <dali/public-api/common/intrusive-ptr.h>
+#include <dali/public-api/rendering/shader.h>
+#include <memory>
+
+// INTERNAL INCLUDES
+#include <dali-scene3d/public-api/api.h>
+#include <dali-scene3d/public-api/loader/index.h>
+#include <dali-scene3d/public-api/loader/material-definition.h>
+#include <dali-scene3d/public-api/loader/mesh-definition.h>
+#include <dali-scene3d/public-api/loader/renderer-state.h>
+#include <dali-scene3d/public-api/loader/shader-option.h>
+
+namespace Dali::Scene3D::Loader
+{
+struct NodeDefinition;
+class ResourceBundle;
+class ShaderManager;
+typedef IntrusivePtr<ShaderManager> ShaderManagerPtr;
+
+/**
+ * @brief This class is to manage Shaders.
+ * This class could be used as factory class to create Dali::Shader.
+ * And once created Dali::Shader is kept in this manager and will be returned when the same Dali::Shader is requested to be created.
+ */
+class DALI_SCENE3D_API ShaderManager : public RefObject
+{
+public:
+  ShaderManager();
+  ~ShaderManager();
+
+  /**
+   * @brief Produces a Dali::Shader for the input materialDefinition and meshDefinition.
+   * Returns a cached Dali::Shader if the requested Dali::Shader has already been created once.
+   * (Although the input materialDefinition and meshDefinition are not identical to those used to create the cached Dali::Shader, they share the cached one.)
+   * @param[in] materialDefinition MaterialDefinition that includes information of material to create Shader.
+   * @param[in] meshDefinition meshDefinition that includes information of mesh to create Shader.
+   * @return Dali::Shader for the materialDefinition and meshDefinition.
+   */
+  Dali::Shader ProduceShader(const MaterialDefinition& materialDefinition, const MeshDefinition& meshDefinition);
+
+  /**
+   * @brief Produces a Dali::Shader for the input ShaderOption
+   * Returns a cached Dali::Shader if the requested Dali::Shader has already been created once.
+   * @param[in] shaderOption shader option to create Shader.
+   * @return Dali::Shader of the shader option
+   */
+  Dali::Shader ProduceShader(const ShaderOption& shaderOption);
+
+  /**
+   * @brief Returns RendererState of the input materialDefinition.
+   * @param[in] materialDefinition MaterialDefinition to get RendererState
+   * @return RendererState of the materialDefinition.
+   */
+  RendererState::Type GetRendererState(const MaterialDefinition& materialDefinition);
+
+private:
+  struct Impl;
+  const std::unique_ptr<Impl> mImpl;
+};
+
+} // namespace Dali::Scene3D::Loader
+
+#endif // DALI_SCENE3D_LOADER_SHADER_MANAGER_H_
@@ -16,7 +16,7 @@
  */
 
 // CLASS HEADER
-#include <dali-scene3d/public-api/loader/shader-definition-option.h>
+#include <dali-scene3d/public-api/loader/shader-option.h>
 
 // EXTERNAL INCLUDES
 #include <string>
@@ -50,22 +50,22 @@ static constexpr std::string_view OPTION_KEYWORD[] =
 static constexpr uint32_t NUMBER_OF_OPTIONS = sizeof(OPTION_KEYWORD) / sizeof(OPTION_KEYWORD[0]);
 } // namespace
 
-void ShaderDefinitionOption::SetTransparency()
+void ShaderOption::SetTransparency()
 {
   mOptionHash |= (1 << NUMBER_OF_OPTIONS);
 }
 
-void ShaderDefinitionOption::AddOption(Type shaderDefinitionOptionType)
+void ShaderOption::AddOption(Type shaderOptionType)
 {
-  mOptionHash |= (1 << static_cast<uint32_t>(shaderDefinitionOptionType));
+  mOptionHash |= (1 << static_cast<uint32_t>(shaderOptionType));
 }
 
-uint64_t ShaderDefinitionOption::GetOptionHash() const
+uint64_t ShaderOption::GetOptionHash() const
 {
   return mOptionHash;
 }
 
-void ShaderDefinitionOption::GetDefines(std::vector<std::string>& defines) const
+void ShaderOption::GetDefines(std::vector<std::string>& defines) const
 {
   defines.clear();
   for(uint32_t i = 0; i < NUMBER_OF_OPTIONS; ++i)
@@ -77,9 +77,9 @@ void ShaderDefinitionOption::GetDefines(std::vector<std::string>& defines) const
   }
 }
 
-std::string_view ShaderDefinitionOption::GetDefineKeyword(Type shaderDefinitionOptionType)
+std::string_view ShaderOption::GetDefineKeyword(Type shaderOptionType)
 {
-  return OPTION_KEYWORD[static_cast<uint32_t>(shaderDefinitionOptionType)];
+  return OPTION_KEYWORD[static_cast<uint32_t>(shaderOptionType)];
 }
 
 } // namespace Dali::Scene3D::Loader
@@ -1,5 +1,5 @@
-#ifndef DALI_SCENE3D_LOADER_SHADER_DEFINITION_OPTION_H_
-#define DALI_SCENE3D_LOADER_SHADER_DEFINITION_OPTION_H_
+#ifndef DALI_SCENE3D_LOADER_SHADER_OPTION_H_
+#define DALI_SCENE3D_LOADER_SHADER_OPTION_H_
 /*
  * Copyright (c) 2023 Samsung Electronics Co., Ltd.
  *
@@ -28,7 +28,7 @@
 namespace Dali::Scene3D::Loader
 {
 
-class DALI_SCENE3D_API ShaderDefinitionOption
+class DALI_SCENE3D_API ShaderOption
 {
 public:
   enum class Type
@@ -64,9 +64,9 @@ public:
    * @brief Adds new shader definition option.
    * If the option is already added, nothin is changed.
    *
-   * @param[in] shaderDefinitionOptionType Option to be added,
+   * @param[in] shaderOptionType Option to be added,
    */
-  void AddOption(Type shaderDefinitionOptionType);
+  void AddOption(Type shaderOptionType);
 
   /**
    * @brief Retrieves current shader option hash
@@ -85,10 +85,10 @@ public:
   /**
    * @brief Retrieves a single shader define keyword of input type.
    *
-   * @param[in] shaderDefinitionOptionType Shader definition option type to know its keyword.
+   * @param[in] shaderOptionType Shader definition option type to know its keyword.
    * @return string keyword of shader define.
    */
-  static std::string_view GetDefineKeyword(Type shaderDefinitionOptionType);
+  static std::string_view GetDefineKeyword(Type shaderOptionType);
 
 private:
   uint64_t mOptionHash{0u};
@@ -96,4 +96,4 @@ private:
 
 } // namespace Dali::Scene3D::Loader
 
-#endif // DALI_SCENE3D_LOADER_SHADER_DEFINITION_OPTION_H_
+#endif // DALI_SCENE3D_LOADER_SHADER_OPTION_H_