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