Merge "Removed unused macro invocation from shader" into devel/master
[platform/core/uifw/dali-toolkit.git] / dali-scene3d / public-api / loader / shader-manager.cpp
index 0978f20..35ebd63 100644 (file)
 
 // EXTERNAL INCLUDES
 #include <dali/devel-api/common/map-wrapper.h>
+#include <dali/public-api/animation/constraint.h>
 #include <cstring>
 
 // INTERNAL INCLUDES
+#include <dali-scene3d/internal/light/light-impl.h>
 #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/integration-api/debug.h>
+
+namespace
+{
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_MODEL_SHADER_MANAGER");
+#endif
+} // namespace
+
 namespace Dali::Scene3D::Loader
 {
 namespace
 {
+static constexpr uint32_t INDEX_FOR_LIGHT_CONSTRAINT_TAG  = 10;
+static constexpr uint32_t INDEX_FOR_SHADOW_CONSTRAINT_TAG = 100;
 
 ShaderOption MakeOption(const MaterialDefinition& materialDef, const MeshDefinition& meshDef)
 {
@@ -103,6 +116,11 @@ ShaderOption MakeOption(const MaterialDefinition& materialDef, const MeshDefinit
   if(meshDef.IsSkinned())
   {
     option.AddOption(ShaderOption::Type::SKINNING);
+    option.AddJointMacros(meshDef.mJoints.size());
+  }
+  else
+  {
+    option.AddJointMacros(0);
   }
 
   if(MaskMatch(meshDef.mFlags, MeshDefinition::FLIP_UVS_VERTICAL))
@@ -110,7 +128,7 @@ ShaderOption MakeOption(const MaterialDefinition& materialDef, const MeshDefinit
     option.AddOption(ShaderOption::Type::FLIP_UVS_VERTICAL);
   }
 
-  if(meshDef.mColors.IsDefined())
+  if(!meshDef.mColors.empty() && meshDef.mColors[0].IsDefined())
   {
     option.AddOption(ShaderOption::Type::COLOR_ATTRIBUTE);
   }
@@ -156,8 +174,11 @@ ShaderOption MakeOption(const MaterialDefinition& materialDef, const MeshDefinit
 
 struct ShaderManager::Impl
 {
-  std::map<uint64_t, Index> mShaderMap;
-  std::vector<Dali::Shader> mShaders;
+  std::map<uint64_t, Index>   mShaderMap;
+  std::vector<Dali::Shader>   mShaders;
+  std::vector<Scene3D::Light> mLights;
+
+  Scene3D::Light mShadowLight;
 };
 
 ShaderManager::ShaderManager()
@@ -167,10 +188,10 @@ ShaderManager::ShaderManager()
 
 ShaderManager::~ShaderManager() = default;
 
-Dali::Shader ShaderManager::ProduceShader(const MaterialDefinition& materialDefinition, const MeshDefinition& meshDefinition)
+ShaderOption ShaderManager::ProduceShaderOption(const MaterialDefinition& materialDefinition, const MeshDefinition& meshDefinition)
 {
-  ShaderOption option = MakeOption(materialDefinition, meshDefinition);
-  return ProduceShader(option);
+  DALI_LOG_INFO(gLogFilter, Debug::Concise, "Defining shader from mat/mesh definitions\n");
+  return MakeOption(materialDefinition, meshDefinition);
 }
 
 Dali::Shader ShaderManager::ProduceShader(const ShaderOption& shaderOption)
@@ -179,17 +200,39 @@ Dali::Shader ShaderManager::ProduceShader(const ShaderOption& shaderOption)
 
   auto&    shaderMap = mImpl->mShaderMap;
   uint64_t hash      = shaderOption.GetOptionHash();
-  auto     iFind     = shaderMap.find(hash);
+
+#if defined(DEBUG_ENABLED)
+  std::ostringstream oss;
+  oss << "  ShaderOption defines:";
+  std::vector<std::string> defines;
+  shaderOption.GetDefines(defines);
+  for(auto& def : defines)
+  {
+    oss << def << ", ";
+  }
+  oss << std::endl
+      << "  ShaderOption macro definitions:" << std::endl;
+  for(auto& macro : shaderOption.GetMacroDefinitions())
+  {
+    oss << macro.macro << " : " << macro.definition << std::endl;
+  }
+  DALI_LOG_INFO(gLogFilter, Debug::Concise, "ShaderOption:\n%s\n", oss.str().c_str());
+#endif
+
+  auto iFind = shaderMap.find(hash);
   if(iFind != shaderMap.end())
   {
+    DALI_LOG_INFO(gLogFilter, Debug::Concise, "Defining Shader found: hash: %lx", hash);
     result = mImpl->mShaders[iFind->second];
   }
   else
   {
+    DALI_LOG_INFO(gLogFilter, Debug::Concise, "Creating new shader: hash: %lx\n", hash);
     ShaderDefinition shaderDef;
     shaderDef.mUseBuiltInShader = true;
 
     shaderOption.GetDefines(shaderDef.mDefines);
+    shaderDef.mMacros                  = shaderOption.GetMacroDefinitions();
     shaderDef.mUniforms["uCubeMatrix"] = Matrix::IDENTITY;
 
     shaderMap[hash] = mImpl->mShaders.size();
@@ -197,6 +240,21 @@ Dali::Shader ShaderManager::ProduceShader(const ShaderOption& shaderOption)
     auto raw = shaderDef.LoadRaw("");
     mImpl->mShaders.emplace_back(shaderDef.Load(std::move(raw)));
     result = mImpl->mShaders.back();
+
+    std::string lightCountPropertyName(Scene3D::Internal::Light::GetLightCountUniformName());
+    result.RegisterProperty(lightCountPropertyName, static_cast<int32_t>(mImpl->mLights.size()));
+
+    for(uint32_t index = 0; index < mImpl->mLights.size(); ++index)
+    {
+      SetLightConstraintToShader(index, result);
+    }
+
+    result.RegisterProperty("uIsShadowEnabled", static_cast<int32_t>(!!mImpl->mShadowLight));
+    if(!!mImpl->mShadowLight)
+    {
+      SetShadowConstraintToShader(result);
+      SetShadowUniformToShader(result);
+    }
   }
 
   return result;
@@ -220,4 +278,167 @@ RendererState::Type ShaderManager::GetRendererState(const MaterialDefinition& ma
   return rendererState;
 }
 
+bool ShaderManager::AddLight(Scene3D::Light light)
+{
+  if(!light || mImpl->mLights.size() >= Scene3D::Internal::Light::GetMaximumEnabledLightCount())
+  {
+    return false;
+  }
+
+  uint32_t lightIndex = mImpl->mLights.size();
+  mImpl->mLights.push_back(light);
+
+  for(auto&& shader : mImpl->mShaders)
+  {
+    std::string lightCountPropertyName(Scene3D::Internal::Light::GetLightCountUniformName());
+    shader.RegisterProperty(lightCountPropertyName, static_cast<int32_t>(mImpl->mLights.size()));
+  }
+
+  SetLightConstraint(lightIndex);
+
+  return true;
+}
+
+void ShaderManager::RemoveLight(Scene3D::Light light)
+{
+  uint32_t lightCount = mImpl->mLights.size();
+  for(uint32_t index = 0; index < lightCount; ++index)
+  {
+    if(mImpl->mLights[index] != light)
+    {
+      continue;
+    }
+
+    RemoveLightConstraint(index);
+
+    if(!mImpl->mLights.empty() && light != mImpl->mLights.back())
+    {
+      RemoveLightConstraint(mImpl->mLights.size() - 1);
+      mImpl->mLights[index] = mImpl->mLights.back();
+      SetLightConstraint(index);
+    }
+
+    mImpl->mLights.pop_back();
+
+    for(auto&& shader : mImpl->mShaders)
+    {
+      std::string lightCountPropertyName(Scene3D::Internal::Light::GetLightCountUniformName());
+      shader.RegisterProperty(lightCountPropertyName, static_cast<int32_t>(mImpl->mLights.size()));
+    }
+    break;
+  }
+}
+
+uint32_t ShaderManager::GetLightCount() const
+{
+  return mImpl->mLights.size();
+}
+
+void ShaderManager::SetShadow(Scene3D::Light light)
+{
+  mImpl->mShadowLight = light;
+  for(auto&& shader : mImpl->mShaders)
+  {
+    std::string shadowEnabledPropertyName(Scene3D::Internal::Light::GetShadowEnabledUniformName());
+    shader.RegisterProperty(shadowEnabledPropertyName, static_cast<int32_t>(true));
+  }
+
+  SetShadowProperty();
+}
+
+void ShaderManager::RemoveShadow()
+{
+  for(auto&& shader : mImpl->mShaders)
+  {
+    std::string shadowEnabledPropertyName(Scene3D::Internal::Light::GetShadowEnabledUniformName());
+    shader.RegisterProperty(shadowEnabledPropertyName, static_cast<int32_t>(false));
+    shader.RemoveConstraints(INDEX_FOR_SHADOW_CONSTRAINT_TAG);
+  }
+  mImpl->mShadowLight.Reset();
+}
+
+void ShaderManager::UpdateShadowUniform(Scene3D::Light light)
+{
+  if(light != mImpl->mShadowLight)
+  {
+    return;
+  }
+
+  for(auto&& shader : mImpl->mShaders)
+  {
+    SetShadowUniformToShader(shader);
+  }
+}
+
+void ShaderManager::SetLightConstraint(uint32_t lightIndex)
+{
+  for(auto&& shader : mImpl->mShaders)
+  {
+    SetLightConstraintToShader(lightIndex, shader);
+  }
+}
+
+void ShaderManager::SetLightConstraintToShader(uint32_t lightIndex, Dali::Shader shader)
+{
+  std::string lightDirectionPropertyName(Scene3D::Internal::Light::GetLightDirectionUniformName());
+  lightDirectionPropertyName += "[" + std::to_string(lightIndex) + "]";
+  auto             lightDirectionPropertyIndex = shader.RegisterProperty(lightDirectionPropertyName, Vector3::ZAXIS);
+  Dali::Constraint lightDirectionConstraint    = Dali::Constraint::New<Vector3>(shader, lightDirectionPropertyIndex, [](Vector3& output, const PropertyInputContainer& inputs) { output = inputs[0]->GetQuaternion().Rotate(Vector3::ZAXIS); });
+  lightDirectionConstraint.AddSource(Source{mImpl->mLights[lightIndex], Dali::Actor::Property::WORLD_ORIENTATION});
+  lightDirectionConstraint.ApplyPost();
+  lightDirectionConstraint.SetTag(INDEX_FOR_LIGHT_CONSTRAINT_TAG + lightIndex);
+
+  std::string lightColorPropertyName(Scene3D::Internal::Light::GetLightColorUniformName());
+  lightColorPropertyName += "[" + std::to_string(lightIndex) + "]";
+  auto             lightColorPropertyIndex = shader.RegisterProperty(lightColorPropertyName, Vector3(Color::WHITE));
+  Dali::Constraint lightColorConstraint    = Dali::Constraint::New<Vector3>(shader, lightColorPropertyIndex, [](Vector3& output, const PropertyInputContainer& inputs) { output = Vector3(inputs[0]->GetVector4()); });
+  lightColorConstraint.AddSource(Source{mImpl->mLights[lightIndex], Dali::Actor::Property::COLOR});
+  lightColorConstraint.ApplyPost();
+  lightColorConstraint.SetTag(INDEX_FOR_LIGHT_CONSTRAINT_TAG + lightIndex);
+}
+
+void ShaderManager::RemoveLightConstraint(uint32_t lightIndex)
+{
+  for(auto&& shader : mImpl->mShaders)
+  {
+    shader.RemoveConstraints(INDEX_FOR_LIGHT_CONSTRAINT_TAG + lightIndex);
+  }
+}
+
+void ShaderManager::SetShadowUniformToShader(Dali::Shader shader)
+{
+  shader.RegisterProperty("uShadowIntensity", mImpl->mShadowLight.GetShadowIntensity());
+  shader.RegisterProperty("uShadowBias", mImpl->mShadowLight.GetShadowBias());
+  shader.RegisterProperty("uEnableShadowSoftFiltering", static_cast<int>(mImpl->mShadowLight.IsShadowSoftFilteringEnabled()));
+}
+
+void ShaderManager::SetShadowProperty()
+{
+  for(auto&& shader : mImpl->mShaders)
+  {
+    SetShadowUniformToShader(shader);
+    SetShadowConstraintToShader(shader);
+  }
+}
+
+void ShaderManager::SetShadowConstraintToShader(Dali::Shader shader)
+{
+  // Constraint is applied before View/Projection Matrix is computed in update thread.
+  // So, it could show not plausible result if camera properties are changed discontinuesly.
+  // If we want to make it be synchronized, View/Projection matrix are needed to be conputed in below constraint.
+
+  std::string       shadowViewProjectionPropertyName(Scene3D::Internal::Light::GetShadowViewProjectionMatrixUniformName());
+  auto              shadowViewProjectionPropertyIndex = shader.RegisterProperty(shadowViewProjectionPropertyName, Matrix::IDENTITY);
+  Dali::CameraActor shadowLightCamera                 = Dali::Scene3D::Internal::GetImplementation(mImpl->mShadowLight).GetCamera();
+  auto              tempViewProjectionMatrixIndex     = shadowLightCamera.GetPropertyIndex("tempViewProjectionMatrix");
+  if(tempViewProjectionMatrixIndex != Dali::Property::INVALID_INDEX)
+  {
+    tempViewProjectionMatrixIndex = shadowLightCamera.RegisterProperty("tempViewProjectionMatrix", Matrix::IDENTITY);
+  }
+  Dali::Constraint shadowViewProjectionConstraint = Dali::Constraint::New<Matrix>(shader, shadowViewProjectionPropertyIndex, [](Matrix& output, const PropertyInputContainer& inputs) { output = inputs[0]->GetMatrix(); });
+  shadowViewProjectionConstraint.AddSource(Source{shadowLightCamera, tempViewProjectionMatrixIndex});
+  shadowViewProjectionConstraint.ApplyPost();
+  shadowViewProjectionConstraint.SetTag(INDEX_FOR_SHADOW_CONSTRAINT_TAG);
+}
+
 } // namespace Dali::Scene3D::Loader