Updated demos to use DALi clang-format
[platform/core/uifw/dali-demo.git] / examples / rendering-basic-light / rendering-basic-light-example.cpp
1 /*
2  * Copyright (c) 2020 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 #include <dali-toolkit/dali-toolkit.h>
19 #include <dali/dali.h>
20
21 using namespace Dali;
22 using namespace Toolkit;
23
24 #define MATERIALS_MAX 24
25
26 namespace
27 {
28 const char*       BASIC_LIGHT_THEME(DEMO_STYLE_DIR "basic-light-theme.json");
29 const char* const CUSTOM_BASIC_LIGHT_THEME = "BasicLightButton";
30
31 struct Material
32 {
33   const char* name;
34   Vector3     ambient;
35   Vector3     diffuse;
36   Vector3     specular;
37   float       shininess;
38 };
39
40 Material material[] =
41   {
42     {"Emerald", Vector3(0.0215f, 0.1745f, 0.0215f), Vector3(0.07568f, 0.61424f, 0.07568f), Vector3(0.633, 0.727811f, 0.633f), 0.6f},
43     {"Jade", Vector3(0.135f, 0.2225f, 0.1575f), Vector3(0.54f, 0.89f, 0.63f), Vector3(0.316228f, 0.316228f, 0.316228f), 0.1f},
44     {"Obsidian", Vector3(0.05375f, 0.05f, 0.06625f), Vector3(0.18275f, 0.17f, 0.22525f), Vector3(0.332741f, 0.328634f, 0.346435f), 0.3f},
45     {"Perl", Vector3(0.25f, 0.20725f, 0.20725f), Vector3(1.0f, 0.829f, 0.829f), Vector3(0.296648f, 0.296648f, 0.296648f), 0.088f},
46     {"Ruby", Vector3(0.1745f, 0.01175f, 0.01175f), Vector3(0.61424f, 0.04136f, 0.04136f), Vector3(0.727811f, 0.626959f, 0.626959f), 0.6f},
47     {"Turquoise", Vector3(0.1f, 0.18725f, 0.1745f), Vector3(0.396f, 0.74151f, 0.69102f), Vector3(0.297254, 0.30829f, 0.306678f), 0.1f},
48     {"Brass", Vector3(0.329412f, 0.223529f, 0.027451f), Vector3(0.780392f, 0.568627f, 0.113725f), Vector3(0.992157f, 0.941176f, 0.807843f), 0.21794872f},
49     {"Bronze", Vector3(0.2125f, 0.1275f, 0.054f), Vector3(0.714f, 0.4284f, 0.18144f), Vector3(0.393548f, 0.271906f, 0.166721f), 0.2f},
50     {"Chrome", Vector3(0.25f, 0.25f, 0.25f), Vector3(0.4f, 0.4f, 0.4f), Vector3(0.774597f, 0.774597f, 0.774597f), 0.6f},
51     {"Copper", Vector3(0.19125f, 0.0735f, 0.0225f), Vector3(0.7038f, 0.27048f, 0.0828f), Vector3(0.256777f, 0.137622f, 0.086014f), 0.1f},
52     {"Gold", Vector3(0.24725f, 0.1995f, 0.0745f), Vector3(0.75164f, 0.60648f, 0.22648f), Vector3(0.628281f, 0.555802f, 0.366065f), 0.4f},
53     {"Silver", Vector3(0.19225f, 0.19225f, 0.19225f), Vector3(0.50754f, 0.50754f, 0.50754f), Vector3(0.508273f, 0.508273f, 0.508273f), 0.4f},
54     {"Black plastic", Vector3(0.0f, 0.0f, 0.0f), Vector3(0.01f, 0.01f, 0.01f), Vector3(0.50f, 0.50f, 0.50f), 0.25f},
55     {"Cyan plastic", Vector3(0.0f, 0.1f, 0.06f), Vector3(0.0f, 0.50980392f, 0.50980392f), Vector3(0.50196078f, 0.50196078f, 0.50196078f), 0.25f},
56     {"Green plastic", Vector3(0.0f, 0.0f, 0.0f), Vector3(0.1f, 0.35f, 0.1f), Vector3(0.45, 0.55, 0.45), 0.25f},
57     {"Red plastic", Vector3(0.0f, 0.0f, 0.0f), Vector3(0.5f, 0.0f, 0.0f), Vector3(0.7f, 0.6f, 0.6f), 0.25f},
58     {"White plastic", Vector3(0.0f, 0.0f, 0.0f), Vector3(0.55f, 0.55f, 0.55f), Vector3(0.7f, 0.7f, 0.7f), 0.25f},
59     {"Yellow plastic", Vector3(0.0f, 0.0f, 0.0f), Vector3(0.5f, 0.5f, 0.0f), Vector3(0.6f, 0.6f, 0.5f), 0.25f},
60     {"Black rubber", Vector3(0.02f, 0.02f, 0.02f), Vector3(0.01f, 0.01f, 0.01f), Vector3(0.4f, 0.4f, 0.4f), 0.078125f},
61     {"Cyan rubber", Vector3(0.0f, 0.05f, 0.05f), Vector3(0.4f, 0.5f, 0.5f), Vector3(0.04f, 0.7f, 0.7f), 0.078125f},
62     {"Green rubber", Vector3(0.0f, 0.05f, 0.0f), Vector3(0.4f, 0.5f, 0.4f), Vector3(0.04f, 0.7f, 0.04f), 0.078125f},
63     {"Red rubber", Vector3(0.05f, 0.0f, 0.0f), Vector3(0.5f, 0.4f, 0.4f), Vector3(0.7f, 0.04f, 0.04f), 0.078125f},
64     {"White rubber", Vector3(0.05f, 0.05f, 0.05f), Vector3(0.5f, 0.5f, 0.5f), Vector3(0.7f, 0.7f, 0.7f), 0.078125f},
65     {"Yellow rubber", Vector3(0.05f, 0.05f, 0.0f), Vector3(0.5f, 0.5f, 0.4f), Vector3(0.7f, 0.7f, 0.04f), 0.078125f}};
66
67 int MaterialID = 0;
68
69 // clang-format off
70
71 /*
72  * Vertex shader
73  */
74 const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
75 attribute mediump vec3 aPosition;\n // DALi shader builtin
76 attribute mediump vec3 aNormal;\n // DALi shader builtin
77 uniform   mediump mat4 uMvpMatrix;\n // DALi shader builtin
78 uniform   mediump vec3 uSize;\n // DALi shader builtin
79 uniform   mediump mat4 uModelView;\n // DALi shader builtin
80 uniform   mediump mat3 uNormalMatrix;\n // DALi shader builtin
81 \n
82 varying mediump vec3 vNormal;\n
83 varying mediump vec3 vFragPos;\n
84 \n
85 void main()\n
86 {\n
87   mediump vec4 vertexPosition = vec4(aPosition, 1.0);\n
88   vertexPosition.xyz *= uSize;\n
89   vFragPos = vec3(uModelView * vertexPosition);\n
90   vNormal = uNormalMatrix * aNormal;\n
91   \n
92   gl_Position = uMvpMatrix * vertexPosition;\n
93 }\n
94 );
95
96 /*
97  * Fragment shader
98  */
99 const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
100 varying mediump vec3 vNormal;\n
101 varying mediump vec3 vFragPos;\n
102 uniform mediump  vec3 viewPos;\n // custom uniform
103 \n
104 struct Material {\n
105     mediump vec3 ambient;\n
106     mediump vec3 diffuse;\n
107     mediump vec3 specular;\n
108     mediump float shininess;\n
109 };\n
110 struct Light {\n
111     mediump vec3 position;\n
112     mediump vec3 color;\n
113 };\n
114 uniform Material material;\n // custom uniform
115 uniform Light light;\n  // custom uniform
116 \n
117 void main()\n
118 {\n
119 \n    // Ambient
120     mediump vec3 ambient = material.ambient * light.color;\n
121 \n    // Diffuse
122     mediump vec3 norm = normalize(vNormal);\n
123     mediump vec3 lightDir = normalize(light.position - vFragPos);\n
124     mediump float diff = max(dot(norm, lightDir), 0.0);\n
125     mediump vec3 diffuse = material.diffuse * diff * light.color;\n
126     \n
127 \n    // Specular
128     mediump vec3 viewDir = normalize(viewPos - vFragPos);\n
129     mediump vec3 reflectDir = reflect(-lightDir, norm);  \n
130     mediump float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);\n
131     mediump vec3 specular = material.specular * spec * light.color;  \n
132     mediump vec3 result = (ambient + diffuse + specular);\n
133     gl_FragColor = vec4(result, 1.0);\n
134 }\n
135 );
136 // clang-format on
137
138 } // namespace
139
140 // This example shows per-pixel lighting of materials with different ambient, diffuse, specular and shininess parameters
141 //
142 class BasicLightController : public ConnectionTracker
143 {
144 public:
145   BasicLightController(Application& application)
146   : mApplication(application)
147   {
148     // Connect to the Application's Init signal
149     mApplication.InitSignal().Connect(this, &BasicLightController::Create);
150   }
151
152   ~BasicLightController()
153   {
154     // Nothing to do here;
155   }
156
157   // The Init signal is received once (only) during the Application lifetime
158   void Create(Application& application)
159   {
160     // Get a handle to the window
161     Window window = application.GetWindow();
162     window.SetBackgroundColor(Color::BLACK);
163     mLabel = TextLabel::New(material[MaterialID].name);
164     mLabel.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_CENTER);
165     mLabel.SetProperty(Actor::Property::PARENT_ORIGIN, Vector3(0.5f, 0.0f, 0.5f));
166     mLabel.SetProperty(Actor::Property::SIZE, Vector2(window.GetSize().GetWidth() * 0.5f, window.GetSize().GetHeight() * 0.083f));
167     mLabel.SetProperty(TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER");
168     mLabel.SetProperty(TextLabel::Property::VERTICAL_ALIGNMENT, "CENTER");
169     mLabel.SetProperty(TextLabel::Property::TEXT_COLOR, Vector4(1.0f, 1.0f, 1.0f, 1.0f));
170     window.Add(mLabel);
171     mButton = PushButton::New();
172     mButton.SetProperty(Button::Property::LABEL, "Exit");
173     mButton.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
174     mButton.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
175     mButton.ClickedSignal().Connect(this, &BasicLightController::OnExit);
176     mButton.SetProperty(Actor::Property::PARENT_ORIGIN, Vector3(0.5f, 0.1f, 0.5f));
177     mButton.SetStyleName(CUSTOM_BASIC_LIGHT_THEME);
178     mButton.SetProperty(Actor::Property::COLOR, Vector4(material[MaterialID].diffuse) + Vector4(0.0f, 0.0f, 0.0f, 1.0f));
179     window.Add(mButton);
180
181     // Step 1. Create shader
182     CreateCubeShader();
183
184     // Step 2. Prepare geometry
185     CreateCubeGeometry();
186
187     // Step 3. Create a renderer
188     CreateRenderer();
189
190     // Step 4. Create an Actor
191     CreateActor();
192
193     // Step 5. Play animation to rotate the cube
194     PlayAnimation();
195
196     // Respond to a click anywhere on the window
197     window.GetRootLayer().TouchedSignal().Connect(this, &BasicLightController::OnTouch);
198
199     // Respond to key events
200     window.KeyEventSignal().Connect(this, &BasicLightController::OnKeyEvent);
201   }
202
203   /**
204    * This function will change the material of the cube when touched
205    */
206   bool OnTouch(Actor actor, const TouchEvent& touch)
207   {
208     if(touch.GetState(0) == PointState::UP)
209     {
210       MaterialID++;
211       MaterialID %= MATERIALS_MAX;
212
213       mShader.SetProperty(mShader.GetPropertyIndex("material.ambient"), material[MaterialID].ambient);
214       mShader.SetProperty(mShader.GetPropertyIndex("material.diffuse"), material[MaterialID].diffuse);
215       mShader.SetProperty(mShader.GetPropertyIndex("material.specular"), material[MaterialID].specular);
216       mShader.SetProperty(mShader.GetPropertyIndex("material.shininess"), material[MaterialID].shininess * 128.0f);
217       mLabel.SetProperty(TextLabel::Property::TEXT, material[MaterialID].name);
218       mButton.SetProperty(Actor::Property::COLOR, Vector4(material[MaterialID].diffuse) + Vector4(0.0f, 0.0f, 0.0f, 1.0f));
219     }
220     return true;
221   }
222
223   /**
224    * This function will the terminate the application when the exit button is pressed
225    */
226   bool OnExit(Button button)
227   {
228     mApplication.Quit();
229     return true;
230   }
231
232   /**
233    * @brief Called when any key event is received
234    *
235    * Will use this to quit the application if Back or the Escape key is received
236    * @param[in] event The key event information
237    */
238   void OnKeyEvent(const KeyEvent& event)
239   {
240     if(event.GetState() == KeyEvent::DOWN)
241     {
242       if(IsKey(event, Dali::DALI_KEY_ESCAPE) || IsKey(event, Dali::DALI_KEY_BACK))
243       {
244         mApplication.Quit();
245       }
246     }
247   }
248
249   /**
250    * This function creates a cube geometry including texture coordinates.
251    * Also it demonstrates using the indexed draw feature by setting an index array.
252    */
253   void CreateCubeGeometry()
254   {
255     struct Vertex
256     {
257       Vector3 aPosition;
258       Vector3 aNormal;
259     };
260
261     const Vector3 NORMAL0(-1.0f, 0.0f, 0.0f);
262     const Vector3 NORMAL1(0.0f, 1.0f, 0.0f);
263     const Vector3 NORMAL2(0.0f, -1.0f, 0.0f);
264     const Vector3 NORMAL3(0.0f, 0.0f, 1.0f);
265     const Vector3 NORMAL4(1.0f, 0.0f, 0.0f);
266     const Vector3 NORMAL5(0.0f, 0.0f, -1.0f);
267
268     Vertex vertices[] = {
269       {Vector3(1.0f, -1.0f, -1.0f), NORMAL5},
270       {Vector3(-1.0f, 1.0f, -1.0f), NORMAL5},
271       {Vector3(1.0f, 1.0f, -1.0f), NORMAL5},
272       {Vector3(-1.0f, 1.0f, 1.0f), NORMAL3},
273       {Vector3(1.0f, -1.0f, 1.0f), NORMAL3},
274       {Vector3(1.0f, 1.0f, 1.0f), NORMAL3},
275       {Vector3(1.0f, 1.0f, 1.0f), NORMAL4},
276       {Vector3(1.0f, -1.0f, -1.0f), NORMAL4},
277       {Vector3(1.0f, 1.0f, -1.0f), NORMAL4},
278       {Vector3(1.0f, -1.0f, 1.0f), NORMAL1},
279       {Vector3(-1.0f, -1.0f, -1.0f), NORMAL1},
280       {Vector3(1.0f, -1.0f, -1.0f), NORMAL1},
281       {Vector3(-1.0f, -1.0f, -1.0f), NORMAL0},
282       {Vector3(-1.0f, 1.0f, 1.0f), NORMAL0},
283       {Vector3(-1.0f, 1.0f, -1.0f), NORMAL0},
284       {Vector3(1.0f, 1.0f, -1.0f), NORMAL2},
285       {Vector3(-1.0f, 1.0f, 1.0f), NORMAL2},
286       {Vector3(1.0f, 1.0f, 1.0f), NORMAL2},
287       {Vector3(1.0f, -1.0f, -1.0f), NORMAL5},
288       {Vector3(-1.0f, -1.0f, -1.0f), NORMAL5},
289       {Vector3(-1.0f, 1.0f, -1.0f), NORMAL5},
290       {Vector3(-1.0f, 1.0f, 1.0f), NORMAL3},
291       {Vector3(-1.0f, -1.0f, 1.0f), NORMAL3},
292       {Vector3(1.0f, -1.0f, 1.0f), NORMAL3},
293       {Vector3(1.0f, 1.0f, 1.0f), NORMAL4},
294       {Vector3(1.0f, -1.0f, 1.0f), NORMAL4},
295       {Vector3(1.0f, -1.0f, -1.0f), NORMAL4},
296       {Vector3(1.0f, -1.0f, 1.0f), NORMAL1},
297       {Vector3(-1.0f, -1.0f, 1.0f), NORMAL1},
298       {Vector3(-1.0f, -1.0f, -1.0f), NORMAL1},
299       {Vector3(-1.0f, -1.0f, -1.0f), NORMAL0},
300       {Vector3(-1.0f, -1.0f, 1.0f), NORMAL0},
301       {Vector3(-1.0f, 1.0f, 1.0f), NORMAL0},
302       {Vector3(1.0f, 1.0f, -1.0f), NORMAL2},
303       {Vector3(-1.0f, 1.0f, -1.0f), NORMAL2},
304       {Vector3(-1.0f, 1.0f, 1.0f), NORMAL2},
305     };
306
307     Property::Map property;
308     property.Insert("aPosition", Property::VECTOR3);
309     property.Insert("aNormal", Property::VECTOR3);
310
311     VertexBuffer vertexBuffer = VertexBuffer::New(property);
312
313     vertexBuffer.SetData(vertices, sizeof(vertices) / sizeof(Vertex));
314
315     // create indices
316     const unsigned short INDEX_CUBE[] = {
317       2, 1, 0, 5, 4, 3, 8, 7, 6, 11, 10, 9, 14, 13, 12, 17, 16, 15, 20, 19, 18, 23, 22, 21, 26, 25, 24, 29, 28, 27, 32, 31, 30, 35, 34, 33};
318     mGeometry = Geometry::New();
319     mGeometry.AddVertexBuffer(vertexBuffer);
320     mGeometry.SetIndexBuffer(INDEX_CUBE,
321                              sizeof(INDEX_CUBE) / sizeof(INDEX_CUBE[0]));
322     mGeometry.SetType(Geometry::TRIANGLES);
323   }
324
325   /**
326    * Creates a shader using inlined variable VERTEX_SHADER and FRAGMENT_SHADER
327    *
328    * Shaders are very basic and all they do is transforming vertices and interpolating
329    * input per-vertex color.
330    */
331   void CreateCubeShader()
332   {
333     mShader = Shader::New(VERTEX_SHADER, FRAGMENT_SHADER);
334
335     float scale = 120.0f;
336     mShader.RegisterProperty("light.position", Vector3(1.2 * scale, scale, 2.0 * scale));
337     mShader.RegisterProperty("light.color", Vector3(1.0f, 1.0f, 1.0f));
338     mShader.RegisterProperty("viewPos", Vector3(0, 0, 3.0 * scale));
339
340     mShader.RegisterProperty("material.ambient", material[MaterialID].ambient);
341     mShader.RegisterProperty("material.diffuse", material[MaterialID].diffuse);
342     mShader.RegisterProperty("material.specular", material[MaterialID].specular);
343     mShader.RegisterProperty("material.shininess", material[MaterialID].shininess * 128.0f);
344   }
345
346   /**
347    * Function creates renderer. It turns on depth test and depth write.
348    */
349   void CreateRenderer()
350   {
351     mRenderer = Renderer::New(mGeometry, mShader);
352
353     // Face culling is enabled to hide the backwards facing sides of the cube
354     // This is sufficient to render a single object; for more complex scenes depth-testing might be required
355     mRenderer.SetProperty(Renderer::Property::FACE_CULLING_MODE, FaceCullingMode::BACK);
356   }
357
358   /**
359    * Creates new actor and attaches renderer.
360    */
361   void CreateActor()
362   {
363     Window window = mApplication.GetWindow();
364
365     float quarterWindowWidth = window.GetSize().GetWidth() * 0.25f;
366     mActor                   = Actor::New();
367     mActor.SetProperty(Actor::Property::COLOR, Vector4(1.0f, 1.0f, 0.6f, 1.0f));
368     mActor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
369     mActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
370     mActor.SetProperty(Actor::Property::SIZE, Vector3(quarterWindowWidth, quarterWindowWidth, quarterWindowWidth));
371     mActor.AddRenderer(mRenderer);
372     window.Add(mActor);
373   }
374
375   /**
376    * Plays animation
377    */
378   void PlayAnimation()
379   {
380     mAnimation = Animation::New(15.0f);
381     mAnimation.SetLooping(true);
382     mAnimation.AnimateBy(Property(mActor, Actor::Property::ORIENTATION), Quaternion(Radian(Degree(360)), Vector3::ZAXIS));
383     mAnimation.AnimateBy(Property(mActor, Actor::Property::ORIENTATION), Quaternion(Radian(Degree(360)), Vector3::YAXIS));
384     mAnimation.AnimateBy(Property(mActor, Actor::Property::ORIENTATION), Quaternion(Radian(Degree(360)), Vector3::XAXIS));
385     mAnimation.Play();
386   }
387
388 private:
389   Application& mApplication;
390   TextLabel    mLabel;
391   PushButton   mButton;
392   Renderer     mRenderer;
393   Shader       mShader;
394   Geometry     mGeometry;
395   Actor        mActor;
396   Animation    mAnimation;
397 };
398
399 int DALI_EXPORT_API main(int argc, char** argv)
400 {
401   Application          application = Application::New(&argc, &argv, BASIC_LIGHT_THEME);
402   BasicLightController test(application);
403   application.MainLoop();
404   return 0;
405 }