Merge "Fix typo error (djikstra -> dijkstra)" into devel/master
[platform/core/uifw/dali-toolkit.git] / dali-scene3d / public-api / loader / shader-definition.cpp
1 /*
2  * Copyright (c) 2023 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali-scene3d/public-api/loader/shader-definition.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/public-api/object/property-array.h>
23
24 // INTERNAL INCLUDES
25 #include <dali-scene3d/internal/graphics/builtin-shader-extern-gen.h>
26 #include <dali-scene3d/public-api/loader/utils.h>
27
28 namespace Dali::Scene3D::Loader
29 {
30 namespace
31 {
32 const char* SHADER_HINT_OUTPUT_IS_TRANSPARENT("OUTPUT_IS_TRANSPARENT"); ///< Might generate transparent alpha from opaque inputs.
33 const char* SHADER_HINT_MODIFIES_GEOMETRY("MODIFIES_GEOMETRY");         ///< Might change position of vertices, this option disables any culling optimizations.
34 } // namespace
35
36 ShaderDefinition::ShaderDefinition(const ShaderDefinition& other)
37 : mRendererState(other.mRendererState),
38   mVertexShaderPath(other.mVertexShaderPath),
39   mFragmentShaderPath(other.mFragmentShaderPath),
40   mDefines(other.mDefines),
41   mHints(other.mHints),
42   mUniforms(other.mUniforms),
43   mUseBuiltInShader(other.mUseBuiltInShader)
44 {
45 }
46
47 void ShaderDefinition::ApplyDefine(std::string& shaderCode, const std::string& definevar)
48 {
49   const std::string IF_1 = "#if 1";
50
51   std::size_t found = shaderCode.find(definevar);
52   while(found != std::string::npos)
53   {
54     // Greater then "@" character means is a letter,
55     // therefore is not has the definevar we looking for.
56     if((found + definevar.length()) < shaderCode.length() && shaderCode.at(found + definevar.length()) > '@')
57     {
58       found = shaderCode.find(definevar, found + definevar.length());
59       continue;
60     }
61     if(found > 0u && shaderCode.at(found - 1) > '@')
62     {
63       found = shaderCode.find(definevar, found + definevar.length());
64       continue;
65     }
66
67     std::size_t defidx     = shaderCode.rfind("#ifdef", found);
68     std::size_t newlineidx = shaderCode.rfind("\n", found);
69     if(newlineidx < defidx && defidx != std::string::npos)
70     {
71       shaderCode.replace(defidx, found - defidx + definevar.length(), IF_1);
72       found = defidx + IF_1.length();
73     }
74     else
75     {
76       found += definevar.length();
77     }
78     found = shaderCode.find(definevar, found);
79   }
80 }
81
82 ShaderDefinition::RawData
83 ShaderDefinition::LoadRaw(const std::string& shadersPath) const
84 {
85   RawData raw;
86
87   bool fail = false;
88   if(!mUseBuiltInShader)
89   {
90     raw.mVertexShaderSource = LoadTextFile((shadersPath + mVertexShaderPath).c_str(), &fail);
91     if(!fail)
92     {
93       raw.mFragmentShaderSource = LoadTextFile((shadersPath + mFragmentShaderPath).c_str(), &fail);
94       if(fail)
95       {
96         ExceptionFlinger(ASSERT_LOCATION) << "Failed to load shader source from '" << shadersPath + mFragmentShaderPath << "'.";
97       }
98     }
99     else
100     {
101       ExceptionFlinger(ASSERT_LOCATION) << "Failed to load shader source from '" << shadersPath + mVertexShaderPath << "'.";
102     }
103   }
104   else
105   {
106     raw.mVertexShaderSource         = SHADER_DEFAULT_PHYSICALLY_BASED_SHADER_VERT.data();
107     raw.mFragmentShaderSource       = SHADER_DEFAULT_PHYSICALLY_BASED_SHADER_FRAG.data();
108     raw.mShadowVertexShaderSource   = SHADER_SHADOW_MAP_SHADER_VERT.data();
109     raw.mShadowFragmentShaderSource = SHADER_SHADOW_MAP_SHADER_FRAG.data();
110   }
111
112   if(!fail)
113   {
114     for(const auto& definevar : mDefines)
115     {
116       ApplyDefine(raw.mVertexShaderSource, definevar);
117       ApplyDefine(raw.mFragmentShaderSource, definevar);
118       ApplyDefine(raw.mShadowVertexShaderSource, definevar);
119     }
120   }
121
122   return raw;
123 }
124
125 Shader ShaderDefinition::Load(RawData&& raw) const
126 {
127   uint32_t hints = Shader::Hint::NONE;
128   for(const auto& hint : mHints)
129   {
130     if(hint == SHADER_HINT_OUTPUT_IS_TRANSPARENT)
131     {
132       hints |= Shader::Hint::OUTPUT_IS_TRANSPARENT;
133     }
134     else if(hint == SHADER_HINT_MODIFIES_GEOMETRY)
135     {
136       hints |= Shader::Hint::MODIFIES_GEOMETRY;
137     }
138   }
139
140   Property::Map map[2];
141   map[0]["vertex"]        = raw.mVertexShaderSource;
142   map[0]["fragment"]      = raw.mFragmentShaderSource;
143   map[0]["renderPassTag"] = 0;
144   map[0]["hints"]         = static_cast<Shader::Hint::Value>(hints);
145
146   map[1]["vertex"]        = raw.mShadowVertexShaderSource;
147   map[1]["fragment"]      = raw.mShadowFragmentShaderSource;
148   map[1]["renderPassTag"] = 10;
149
150   Property::Array array;
151   array.PushBack(map[0]);
152   array.PushBack(map[1]);
153
154   Shader shader = Shader::New(array);
155   for(Property::Map::SizeType i0 = 0, i1 = mUniforms.Count(); i0 != i1; ++i0)
156   {
157     auto pair = mUniforms.GetKeyValue(i0);
158     DALI_ASSERT_ALWAYS(pair.first.type == Property::Key::STRING);
159     shader.RegisterProperty(pair.first.stringKey, pair.second);
160   }
161
162   return shader;
163 }
164
165 } // namespace Dali::Scene3D::Loader