Compute min/max value if min/max is not defined.
[platform/core/uifw/dali-toolkit.git] / dali-scene-loader / public-api / shader-definition.cpp
1 /*
2  * Copyright (c) 2021 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 // INTERNAL INCLUDES
19 #include "dali-scene-loader/public-api/shader-definition.h"
20 #include "dali-scene-loader/public-api/utils.h"
21 #include <dali-scene-loader/internal/graphics/builtin-shader-extern-gen.h>
22
23 namespace Dali
24 {
25 namespace SceneLoader
26 {
27 namespace
28 {
29 const std::string SHADER_HINT_OUTPUT_IS_TRANSPARENT("OUTPUT_IS_TRANSPARENT"); ///< Might generate transparent alpha from opaque inputs.
30 const std::string SHADER_HINT_MODIFIES_GEOMETRY("MODIFIES_GEOMETRY");         ///< Might change position of vertices, this option disables any culling optimizations.
31
32 } // namespace
33
34 ShaderDefinition::ShaderDefinition(const ShaderDefinition& other)
35 : mRendererState(other.mRendererState),
36   mVertexShaderPath(other.mVertexShaderPath),
37   mFragmentShaderPath(other.mFragmentShaderPath),
38   mDefines(other.mDefines),
39   mHints(other.mHints),
40   mUniforms(other.mUniforms),
41   mUseBuiltInShader(other.mUseBuiltInShader)
42 {
43 }
44
45 void ShaderDefinition::ApplyDefine(std::string& shaderCode, const std::string& definevar)
46 {
47   const std::string IF_1 = "#if 1";
48
49   std::size_t found = shaderCode.find(definevar);
50   while(found != std::string::npos)
51   {
52     // Greater then "@" character means is a letter,
53     // therefore is not has the definevar we looking for.
54     if((found + definevar.length()) < shaderCode.length() && shaderCode.at(found + definevar.length()) > '@')
55     {
56       found = shaderCode.find(definevar, found + definevar.length());
57       continue;
58     }
59     if(found > 0u && shaderCode.at(found - 1) > '@')
60     {
61       found = shaderCode.find(definevar, found + definevar.length());
62       continue;
63     }
64
65     std::size_t defidx     = shaderCode.rfind("#ifdef", found);
66     std::size_t newlineidx = shaderCode.rfind("\n", found);
67     if(newlineidx < defidx && defidx != std::string::npos)
68     {
69       shaderCode.replace(defidx, found - defidx + definevar.length(), IF_1);
70       found = defidx + IF_1.length();
71     }
72     else
73     {
74       found += definevar.length();
75     }
76     found = shaderCode.find(definevar, found);
77   }
78 }
79
80 ShaderDefinition::RawData
81 ShaderDefinition::LoadRaw(const std::string& shadersPath) const
82 {
83   RawData raw;
84
85   bool fail = false;
86   if(!mUseBuiltInShader)
87   {
88     raw.mVertexShaderSource = LoadTextFile((shadersPath + mVertexShaderPath).c_str(), &fail);
89     if(!fail)
90     {
91       raw.mFragmentShaderSource = LoadTextFile((shadersPath + mFragmentShaderPath).c_str(), &fail);
92       if(fail)
93       {
94         ExceptionFlinger(ASSERT_LOCATION) << "Failed to load shader source from '" << shadersPath + mFragmentShaderPath << "'.";
95       }
96     }
97     else
98     {
99       ExceptionFlinger(ASSERT_LOCATION) << "Failed to load shader source from '" << shadersPath + mVertexShaderPath << "'.";
100     }
101   }
102   else
103   {
104     raw.mVertexShaderSource   = SHADER_DEFAULT_PHYSICALLY_BASED_SHADER_VERT.data();
105     raw.mFragmentShaderSource = SHADER_DEFAULT_PHYSICALLY_BASED_SHADER_FRAG.data();
106   }
107
108   if(!fail)
109   {
110     for(auto definevar : mDefines)
111     {
112       ApplyDefine(raw.mVertexShaderSource, definevar);
113       ApplyDefine(raw.mFragmentShaderSource, definevar);
114     }
115   }
116
117   return raw;
118 }
119
120 Shader ShaderDefinition::Load(RawData&& raw) const
121 {
122   uint32_t hints = Shader::Hint::NONE;
123   for(const auto& hint : mHints)
124   {
125     if(hint == SHADER_HINT_OUTPUT_IS_TRANSPARENT)
126     {
127       hints |= Shader::Hint::OUTPUT_IS_TRANSPARENT;
128     }
129     else if(hint == SHADER_HINT_MODIFIES_GEOMETRY)
130     {
131       hints |= Shader::Hint::MODIFIES_GEOMETRY;
132     }
133   }
134
135   Shader shader = Shader::New(raw.mVertexShaderSource, raw.mFragmentShaderSource, static_cast<Shader::Hint::Value>(hints));
136   for(Property::Map::SizeType i0 = 0, i1 = mUniforms.Count(); i0 != i1; ++i0)
137   {
138     auto pair = mUniforms.GetKeyValue(i0);
139     DALI_ASSERT_ALWAYS(pair.first.type == Property::Key::STRING);
140     shader.RegisterProperty(pair.first.stringKey, pair.second);
141   }
142
143   return shader;
144 }
145
146 } // namespace SceneLoader
147 } // namespace Dali