9886838557396366157bf2a08db4b07037f03dcb
[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/dali.h>
19 #include <dali-toolkit/dali-toolkit.h>
20
21 using namespace Dali;
22 using namespace Toolkit;
23
24 #define MATERIALS_MAX 24
25
26 namespace
27 {
28
29 const char* BASIC_LIGHT_THEME( DEMO_STYLE_DIR "basic-light-theme.json" );
30 const char* const CUSTOM_BASIC_LIGHT_THEME = "BasicLightButton";
31
32 struct Material
33 {
34     const char *name;
35     Vector3 ambient;
36     Vector3 diffuse;
37     Vector3 specular;
38     float shininess;
39 };
40
41 Material material[] =
42 {
43         {"Emerald",        Vector3( 0.0215f,   0.1745f,   0.0215f ),   Vector3( 0.07568f,  0.61424f,    0.07568f ),    Vector3( 0.633,       0.727811f,   0.633f ),      0.6f },
44         {"Jade",           Vector3( 0.135f,    0.2225f,   0.1575f ),   Vector3( 0.54f,     0.89f,       0.63f ),       Vector3( 0.316228f,   0.316228f,   0.316228f ),   0.1f },
45         {"Obsidian",       Vector3( 0.05375f,  0.05f,     0.06625f ),  Vector3( 0.18275f,  0.17f,       0.22525f ),    Vector3( 0.332741f,   0.328634f,   0.346435f ),   0.3f },
46         {"Perl",           Vector3( 0.25f,     0.20725f,  0.20725f ),  Vector3( 1.0f,      0.829f,      0.829f ),      Vector3( 0.296648f,   0.296648f,   0.296648f ),   0.088f },
47         {"Ruby",           Vector3( 0.1745f,   0.01175f,  0.01175f ),  Vector3( 0.61424f,  0.04136f,    0.04136f ),    Vector3( 0.727811f,   0.626959f,   0.626959f ),   0.6f },
48         {"Turquoise",      Vector3( 0.1f,      0.18725f,  0.1745f ),   Vector3( 0.396f,    0.74151f,    0.69102f ),    Vector3( 0.297254,    0.30829f,    0.306678f ),   0.1f },
49         {"Brass",          Vector3( 0.329412f, 0.223529f, 0.027451f ), Vector3( 0.780392f, 0.568627f,   0.113725f ),   Vector3( 0.992157f,   0.941176f,   0.807843f ),   0.21794872f },
50         {"Bronze",         Vector3( 0.2125f,   0.1275f,   0.054f ),    Vector3( 0.714f,    0.4284f,     0.18144f ),    Vector3( 0.393548f,   0.271906f,   0.166721f ),   0.2f },
51         {"Chrome",         Vector3( 0.25f,     0.25f,     0.25f ),     Vector3( 0.4f,      0.4f,        0.4f),         Vector3( 0.774597f,   0.774597f,   0.774597f ),   0.6f },
52         {"Copper",         Vector3( 0.19125f,  0.0735f,   0.0225f ),   Vector3( 0.7038f,   0.27048f,    0.0828f ),     Vector3( 0.256777f,   0.137622f,   0.086014f ),   0.1f },
53         {"Gold",           Vector3( 0.24725f,  0.1995f,   0.0745f ),   Vector3( 0.75164f,  0.60648f,    0.22648f ),    Vector3( 0.628281f,   0.555802f,   0.366065f ),   0.4f },
54         {"Silver",         Vector3( 0.19225f,  0.19225f,  0.19225f ),  Vector3( 0.50754f,  0.50754f,    0.50754f ),    Vector3( 0.508273f,   0.508273f,   0.508273f ),   0.4f },
55         {"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 },
56         {"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 },
57         {"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 },
58         {"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 },
59         {"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 },
60         {"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 },
61         {"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 },
62         {"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 },
63         {"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 },
64         {"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 },
65         {"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 },
66         {"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 }
67 };
68
69 int MaterialID = 0;
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
137 }
138
139 // This example shows per-pixel lighting of materials with different ambient, diffuse, specular and shininess parameters
140 //
141 class BasicLightController : public ConnectionTracker
142 {
143 public:
144
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().TouchSignal().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.state == 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,
318       5, 4, 3,
319       8, 7, 6,
320       11, 10, 9,
321       14, 13, 12,
322       17, 16, 15,
323       20, 19, 18,
324       23, 22, 21,
325       26, 25, 24,
326       29, 28, 27,
327       32, 31, 30,
328       35, 34, 33
329     };
330     mGeometry = Geometry::New();
331     mGeometry.AddVertexBuffer( vertexBuffer );
332     mGeometry.SetIndexBuffer( INDEX_CUBE,
333                               sizeof(INDEX_CUBE)/sizeof(INDEX_CUBE[0])
334         );
335     mGeometry.SetType( Geometry::TRIANGLES );
336   }
337
338   /**
339    * Creates a shader using inlined variable VERTEX_SHADER and FRAGMENT_SHADER
340    *
341    * Shaders are very basic and all they do is transforming vertices and interpolating
342    * input per-vertex color.
343    */
344   void CreateCubeShader()
345   {
346     mShader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
347
348     float scale = 120.0f;
349     mShader.RegisterProperty( "light.position",Vector3( 1.2 * scale, scale, 2.0 * scale ) );
350     mShader.RegisterProperty( "light.color", Vector3( 1.0f, 1.0f, 1.0f ) );
351     mShader.RegisterProperty( "viewPos", Vector3( 0, 0, 3.0 * scale ) );
352
353     mShader.RegisterProperty( "material.ambient", material[MaterialID].ambient );
354     mShader.RegisterProperty( "material.diffuse", material[MaterialID].diffuse );
355     mShader.RegisterProperty( "material.specular", material[MaterialID].specular );
356     mShader.RegisterProperty( "material.shininess", material[MaterialID].shininess * 128.0f );
357   }
358
359   /**
360    * Function creates renderer. It turns on depth test and depth write.
361    */
362   void CreateRenderer()
363   {
364     mRenderer = Renderer::New( mGeometry, mShader );
365
366     // Face culling is enabled to hide the backwards facing sides of the cube
367     // This is sufficient to render a single object; for more complex scenes depth-testing might be required
368     mRenderer.SetProperty( Renderer::Property::FACE_CULLING_MODE, FaceCullingMode::BACK );
369   }
370
371   /**
372    * Creates new actor and attaches renderer.
373    */
374   void CreateActor()
375   {
376     Window window = mApplication.GetWindow();
377
378     float quarterWindowWidth = window.GetSize().GetWidth() * 0.25f;
379     mActor = Actor::New();
380     mActor.SetProperty( Actor::Property::COLOR, Vector4( 1.0f, 1.0f, 0.6f, 1.0f ) );
381     mActor.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER );
382     mActor.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
383     mActor.SetProperty( Actor::Property::SIZE, Vector3( quarterWindowWidth, quarterWindowWidth, quarterWindowWidth ) );
384     mActor.AddRenderer( mRenderer );
385     window.Add( mActor );
386   }
387
388   /**
389    * Plays animation
390    */
391   void PlayAnimation()
392   {
393     mAnimation = Animation::New( 15.0f );
394     mAnimation.SetLooping( true );
395     mAnimation.AnimateBy( Property( mActor, Actor::Property::ORIENTATION ), Quaternion( Radian( Degree( 360 )), Vector3::ZAXIS ) );
396     mAnimation.AnimateBy( Property( mActor, Actor::Property::ORIENTATION ), Quaternion( Radian( Degree( 360 )), Vector3::YAXIS ) );
397     mAnimation.AnimateBy( Property( mActor, Actor::Property::ORIENTATION ), Quaternion( Radian( Degree( 360 )), Vector3::XAXIS ) );
398     mAnimation.Play();
399   }
400
401 private:
402   Application&  mApplication;
403   TextLabel mLabel;
404   PushButton mButton;
405   Renderer mRenderer;
406   Shader mShader;
407   Geometry mGeometry;
408   Actor mActor;
409   Animation mAnimation;
410 };
411
412 int DALI_EXPORT_API main( int argc, char **argv )
413 {
414   Application application = Application::New( &argc, &argv, BASIC_LIGHT_THEME);
415   BasicLightController test( application );
416   application.MainLoop();
417   return 0;
418 }