Revert "Updates following rename of PropertyBuffer"
[platform/core/uifw/dali-demo.git] / examples / reflection-demo / reflection-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/devel-api/actors/camera-actor-devel.h>
20 #include <dali/devel-api/adaptor-framework/file-stream.h>
21
22 #include <map>
23
24 #include "gltf-scene.h"
25
26 using namespace Dali;
27
28 namespace
29 {
30
31 const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
32   attribute mediump vec3 aPosition;\n
33   attribute mediump vec3 aNormal;\n
34   attribute mediump vec2 aTexCoord;\n
35   uniform mediump mat4 uMvpMatrix;\n
36   uniform mediump mat3 uNormalMatrix;\n
37   uniform mediump vec3 uSize;\n
38   \n
39   varying mediump vec2 vTexCoord; \n
40   varying mediump vec3 vNormal; \n
41   varying mediump vec3 vPosition; \n
42   void main()\n
43 {\n
44   mediump vec4 vertexPosition = vec4(aPosition, 1.0);\n
45   vertexPosition.xyz *= uSize;\n
46   vTexCoord = aTexCoord;\n
47   vNormal = normalize(uNormalMatrix * aNormal);\n
48   vPosition = aPosition; \n
49   gl_Position = uMvpMatrix * vertexPosition;\n
50 }\n
51 );
52
53 const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
54   uniform lowp vec4 uColor;\n
55   uniform sampler2D sTexture; \n
56   varying mediump vec3 vNormal;\n
57   varying mediump vec3 vPosition; \n
58   varying mediump vec2 vTexCoord; \n
59   \n
60   void main()\n
61 {\n
62   gl_FragColor = texture2D(sTexture, vTexCoord) * 50.0;\n
63 }\n
64 );
65
66 const char* FRAGMENT_SIMPLE_SHADER = DALI_COMPOSE_SHADER(
67         uniform lowp vec4 uColor;\n
68         uniform sampler2D sTexture; \n
69         varying mediump vec3 vNormal;\n
70         varying mediump vec3 vPosition; \n
71         varying mediump vec2 vTexCoord; \n
72         \n
73         void main()\n
74 {\n
75         gl_FragColor = texture2D(sTexture, vTexCoord) * 2.0;\n
76 }\n
77 );
78
79 const char* TEXTURED_FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
80   uniform lowp vec4 uColor;\n
81   uniform sampler2D sTexture; \n
82   uniform mediump vec2 uScreenSize;\n
83
84   uniform mediump vec3 eyePos;\n
85   uniform mediump vec3 lightDir;\n
86
87   varying mediump vec3 vNormal;\n
88   varying mediump vec3 vPosition; \n
89   varying mediump vec2 vTexCoord; \n
90   \n
91   void main()\n
92 {\n
93   mediump vec3 n = normalize( vNormal );\n
94   mediump vec3 l = normalize( lightDir );\n
95   mediump vec3 e = normalize( eyePos );\n
96   mediump float intensity = max(dot(n,l), 0.0);\n
97   gl_FragColor = texture2D(sTexture, vTexCoord) * intensity;\n
98 }\n
99 );
100
101 const char* PLASMA_FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
102   precision mediump float;\n
103   uniform sampler2D sTexture; \n
104
105   uniform float uTime;
106   uniform float uKFactor;
107   uniform mediump vec3 eyePos;\n
108   uniform mediump vec3 lightDir;\n
109   varying mediump vec3 vNormal;\n
110   varying mediump vec3 vPosition; \n
111   varying mediump vec2 vTexCoord; \n
112   \n
113   void main()\n
114 {\n
115   mediump vec3 n = normalize( vNormal );\n
116   mediump vec3 l = normalize( lightDir );\n
117   mediump vec3 e = normalize( eyePos );\n
118   mediump float intensity = max(dot(n,l), 0.0);\n
119 \n
120   const mediump float PI = 3.1415926535897932384626433832795;\n
121   mediump float v = 0.0;\n
122   mediump vec2 c = vTexCoord * uKFactor - uKFactor/2.0;\n
123   v += sin((c.x+uTime));\n
124   v += sin((c.y+uTime)/2.0);\n
125   v += sin((c.x+c.y+uTime)/2.0);\n
126   c += uKFactor/2.0 * vec2(sin(uTime/3.0), cos(uTime/2.0));\n
127   v += sin(sqrt(c.x*c.x+c.y*c.y+1.0)+uTime);\n
128   v = v/2.0;\n
129   mediump vec3 col = vec3(1, sin(PI*v), cos(PI*v));\n
130   gl_FragColor = (texture2D(sTexture, vTexCoord)) * (((col.r+col.g+col.b)/3.0)+1.0+intensity);\n
131 }\n
132 );
133
134 const char* TEX_FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
135   uniform lowp vec4 uColor;\n
136   uniform sampler2D sTexture0; \n
137   uniform sampler2D sTexture1; \n
138   uniform mediump vec3 eyePos;\n
139   uniform mediump vec3 lightDir;\n
140   uniform mediump vec2 uScreenSize;\n
141   varying mediump vec3 vNormal;\n
142   varying mediump vec3 vPosition; \n
143   varying mediump vec2 vTexCoord; \n
144   \n
145
146   mediump float rand(mediump vec2 co){\n
147     return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);\n
148   }\n
149   \n
150   void main()\n
151 {\n
152   mediump vec2 tx = (gl_FragCoord.xy / uScreenSize.xy);\n
153   mediump vec3 n = normalize( vNormal );\n
154   mediump vec3 l = normalize( lightDir );\n
155   mediump vec3 e = normalize( eyePos );\n
156   mediump float factor = gl_FragCoord.y / uScreenSize.y;\n
157   mediump float intensity = max(dot(n,l), 0.0);\n
158   mediump vec2 uv = tx;\n
159   gl_FragColor = ((texture2D(sTexture0, vTexCoord) * factor ) + \n
160                  (texture2D(sTexture1, uv))) * intensity;\n
161 }\n
162 );
163
164 struct Model
165 {
166   Shader    shader;
167   Geometry  geometry;
168 };
169 using ModelPtr = std::unique_ptr<Model>;
170
171 using ActorContainer = std::vector<Actor>;
172 using CameraContainer = std::vector<CameraActor>;
173 using ModelContainer = std::vector<ModelPtr>;
174 using TextureSetContainer = std::vector<TextureSet>;
175
176 const Vector3 DEFAULT_LIGHT_DIRECTION( 0.5, 0.5, -1 );
177
178 template<class T>
179 bool LoadFile( const std::string& filename, std::vector<T>& bytes )
180 {
181   Dali::FileStream fileStream( filename, Dali::FileStream::READ | Dali::FileStream::BINARY );
182   FILE* fin = fileStream.GetFile();
183
184   if( fin )
185   {
186     if( fseek( fin, 0, SEEK_END ) )
187     {
188       return false;
189     }
190     bytes.resize( uint32_t(ftell( fin )) );
191     std::fill( bytes.begin(), bytes.end(), 0 );
192     if( fseek( fin, 0, SEEK_SET ) )
193     {
194       return false;
195     }
196     size_t result = fread( bytes.data(), 1, bytes.size(), fin );
197     return ( result != 0 );
198   }
199
200   return false;
201 }
202
203 Shader CreateShader( const std::string& vsh, const std::string& fsh )
204 {
205   std::vector<char> vshShaderSource;
206   std::vector<char> fshShaderSource;
207
208   // VSH
209   if(vsh[0] == '/')
210   {
211     std::string vshPath( DEMO_GAME_DIR );
212     vshPath += '/';
213     vshPath += vsh;
214     LoadFile( vshPath, vshShaderSource );
215   }
216   else
217   {
218     vshShaderSource.insert(vshShaderSource.end(), vsh.begin(), vsh.end());
219   }
220
221   // FSH
222   if(fsh[0] == '/')
223   {
224     std::string fshPath( DEMO_GAME_DIR );
225     fshPath += '/';
226     fshPath += fsh;
227     LoadFile( fshPath, fshShaderSource );
228   }
229   else
230   {
231     fshShaderSource.insert(fshShaderSource.end(), fsh.begin(), fsh.end());
232   }
233
234   vshShaderSource.emplace_back(0);
235   fshShaderSource.emplace_back(0);
236   return Shader::New( std::string(vshShaderSource.data()), std::string(fshShaderSource.data()) );
237 }
238
239 ModelPtr CreateModel(
240     glTF& gltf,
241     const glTF_Mesh* mesh,
242     const std::string& vertexShaderSource,
243     const std::string& fragmentShaderSource )
244 {
245   /*
246    * Obtain interleaved buffer for first mesh with position and normal attributes
247    */
248   auto positionBuffer = gltf.GetMeshAttributeBuffer( *mesh,
249                                                      {
250                                                        glTFAttributeType::POSITION,
251                                                        glTFAttributeType::NORMAL,
252                                                        glTFAttributeType::TEXCOORD_0
253                                                      } );
254
255   auto attributeCount = gltf.GetMeshAttributeCount( mesh );
256   /**
257    * Create matching property buffer
258    */
259   auto vertexBuffer = PropertyBuffer::New( Property::Map()
260                                              .Add("aPosition", Property::VECTOR3 )
261                                              .Add("aNormal", Property::VECTOR3)
262                                              .Add("aTexCoord", Property::VECTOR2)
263   );
264
265   // set vertex data
266   vertexBuffer.SetData( positionBuffer.data(), attributeCount );
267
268   auto geometry = Geometry::New();
269   geometry.AddVertexBuffer( vertexBuffer );
270   auto indexBuffer = gltf.GetMeshIndexBuffer( mesh );
271   geometry.SetIndexBuffer( indexBuffer.data(), indexBuffer.size() );
272   geometry.SetType( Geometry::Type::TRIANGLES );
273   ModelPtr retval( new Model() );
274   retval->shader = CreateShader( vertexShaderSource, fragmentShaderSource );
275   retval->geometry = geometry;
276   return retval;
277 }
278
279 void ReplaceShader( Actor& actor, const std::string& vsh, const std::string& fsh )
280 {
281   auto renderer = actor.GetRendererAt(0);
282   auto shader = CreateShader(vsh, fsh);
283   renderer.SetShader( shader );
284 }
285
286 void CreateTextureSetsFromGLTF( glTF* gltf, const std::string& basePath, TextureSetContainer& textureSets )
287 {
288   const auto& materials = gltf->GetMaterials();
289   const auto& textures = gltf->GetTextures();
290
291   std::map<std::string, Texture> textureCache{};
292
293   for(const auto& material : materials )
294   {
295     TextureSet textureSet;
296     if(material.pbrMetallicRoughness.enabled)
297     {
298       textureSet = TextureSet::New();
299       std::string filename( basePath );
300       filename += '/';
301       filename += textures[material.pbrMetallicRoughness.baseTextureColor.index].uri;
302       Dali::PixelData pixelData = Dali::Toolkit::SyncImageLoader::Load( filename );
303
304       auto cacheKey = textures[material.pbrMetallicRoughness.baseTextureColor.index].uri;
305       auto iter = textureCache.find(cacheKey);
306       Texture texture;
307       if(iter == textureCache.end())
308       {
309         texture = Texture::New(TextureType::TEXTURE_2D, pixelData.GetPixelFormat(), pixelData.GetWidth(),
310                                        pixelData.GetHeight());
311         texture.Upload(pixelData);
312         texture.GenerateMipmaps();
313         textureCache[cacheKey] = texture;
314       }
315       else
316       {
317         texture = iter->second;
318       }
319       textureSet.SetTexture( 0, texture );
320       Dali::Sampler sampler = Dali::Sampler::New();
321       sampler.SetWrapMode( Dali::WrapMode::REPEAT, Dali::WrapMode::REPEAT, Dali::WrapMode::REPEAT );
322       sampler.SetFilterMode( Dali::FilterMode::LINEAR_MIPMAP_LINEAR, Dali::FilterMode::LINEAR );
323       textureSet.SetSampler( 0, sampler );
324     }
325     textureSets.emplace_back( textureSet );
326   }
327 }
328
329
330 /**
331  * Creates models from glTF
332  */
333 void CreateModelsFromGLTF( glTF* gltf, ModelContainer& models )
334 {
335   const auto& meshes = gltf->GetMeshes();
336   for( const auto& mesh : meshes )
337   {
338     // change shader to use texture if material indicates that
339     if(mesh->material != 0xffffffff && gltf->GetMaterials()[mesh->material].pbrMetallicRoughness.enabled)
340     {
341       models.emplace_back( CreateModel( *gltf, mesh, VERTEX_SHADER, TEXTURED_FRAGMENT_SHADER ) );
342     }
343     else
344     {
345       models.emplace_back( CreateModel( *gltf, mesh, VERTEX_SHADER, FRAGMENT_SHADER ) );
346     }
347   }
348 }
349
350 Actor CreateSceneFromGLTF(
351     Window window,
352     glTF* gltf,
353     ModelContainer& models,
354     ActorContainer& actors,
355     CameraContainer& cameras,
356     TextureSetContainer& textureSets )
357 {
358   const auto& nodes = gltf->GetNodes();
359
360   Vector3 cameraPosition;
361
362   // for each node create nodes and children
363   // resolve parents later
364   actors.reserve( nodes.size() );
365   for( const auto& node : nodes )
366   {
367     auto actor = node.cameraId != 0xffffffff ? CameraActor::New( window.GetSize() ) : Actor::New();
368
369     actor.SetProperty( Actor::Property::SIZE, Vector3( 1, 1, 1 ) );
370     actor.SetProperty( Dali::Actor::Property::NAME, node.name );
371     actor.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER );
372     actor.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
373     actor.SetProperty( Actor::Property::POSITION, Vector3( node.translation[0], node.translation[1], node.translation[2] ));
374     actor.SetProperty( Actor::Property::SCALE, Vector3( node.scale[0], node.scale[1], node.scale[2] ) );
375     actor.SetProperty( Actor::Property::ORIENTATION, Quaternion(node.rotationQuaternion[3],
376                                      node.rotationQuaternion[0],
377                                      node.rotationQuaternion[1],
378                                      node.rotationQuaternion[2]));
379
380     actors.emplace_back( actor );
381
382     // Initially add each actor to the very first one
383     if(actors.size() > 1)
384     {
385       actors[0].Add(actor);
386     }
387
388     // If mesh, create and add renderer
389     if(node.meshId != 0xffffffff)
390     {
391       const auto& model = models[node.meshId].get();
392       auto renderer = Renderer::New( model->geometry, model->shader );
393
394       // if textured, add texture set
395       auto materialId = gltf->GetMeshes()[node.meshId]->material;
396       if( materialId != 0xffffffff )
397       {
398         if( gltf->GetMaterials()[materialId].pbrMetallicRoughness.enabled )
399         {
400           renderer.SetTextures( textureSets[materialId] );
401         }
402       }
403
404       actor.AddRenderer( renderer );
405     }
406
407     // Reset and attach main camera
408     if( node.cameraId != 0xffffffff )
409     {
410       cameraPosition = Vector3(node.translation[0], node.translation[1], node.translation[2]);
411       auto quatY = Quaternion( Degree(180.0f), Vector3( 0.0, 1.0, 0.0) );
412       auto cameraActor = CameraActor::DownCast( actor );
413       cameraActor.SetProperty( Actor::Property::ORIENTATION, Quaternion(node.rotationQuaternion[3],
414                                              node.rotationQuaternion[0],
415                                              node.rotationQuaternion[1],
416                                              node.rotationQuaternion[2] )
417                                   * quatY
418                                     );
419       cameraActor.SetProjectionMode( Camera::PERSPECTIVE_PROJECTION );
420
421       const auto camera = gltf->GetCameras()[node.cameraId];
422       cameraActor.SetNearClippingPlane( camera->znear );
423       cameraActor.SetFarClippingPlane( camera->zfar );
424       cameraActor.SetFieldOfView( camera->yfov );
425
426       cameraActor.SetProperty( CameraActor::Property::INVERT_Y_AXIS, true);
427       cameraActor.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER );
428       cameraActor.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
429
430       cameras.emplace_back( cameraActor );
431     }
432   }
433
434   // Resolve hierarchy dependencies
435   auto i = 0u;
436   for( const auto& node : nodes )
437   {
438     if(!node.children.empty())
439     {
440       for(const auto& childId : node.children)
441       {
442         actors[i].Add( actors[childId+1] );
443       }
444     }
445     ++i;
446   }
447
448   for( auto& actor : actors )
449   {
450     actor.RegisterProperty( "lightDir", DEFAULT_LIGHT_DIRECTION );
451     actor.RegisterProperty( "eyePos", cameraPosition );
452   }
453
454   return actors[0];
455 }
456
457 } // unnamed namespace
458
459 // This example shows how to create and display mirrored reflection using CameraActor
460 //
461 class ReflectionExample : public ConnectionTracker
462 {
463 public:
464
465   ReflectionExample( Application& application )
466   : mApplication( application )
467   {
468     // Connect to the Application's Init signal
469     mApplication.InitSignal().Connect( this, &ReflectionExample::Create );
470   }
471
472   ~ReflectionExample() = default;
473
474 private:
475
476   // The Init signal is received once (only) during the Application lifetime
477   void Create( Application& application )
478   {
479     // Get a handle to the window
480     Window window = application.GetWindow();
481     uint32_t windowWidth  = uint32_t(window.GetSize().GetWidth());
482     uint32_t windowHeight = uint32_t(window.GetSize().GetHeight());
483
484     window.GetRenderTaskList().GetTask(0).SetClearEnabled(false);
485     mLayer3D = Layer::New();
486     mLayer3D.SetProperty( Actor::Property::SIZE, Vector2( windowWidth, windowHeight ) );
487     window.Add(mLayer3D);
488
489     mLayer3D.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER );
490     mLayer3D.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
491     mLayer3D.SetProperty( Layer::Property::BEHAVIOR, Layer::LAYER_3D );
492     mLayer3D.SetProperty( Layer::Property::DEPTH_TEST, true );
493
494
495     auto gltf = glTF(DEMO_GAME_DIR "/reflection");
496
497     // Define direction of light
498
499     /**
500      * Instantiate texture sets
501      */
502     CreateTextureSetsFromGLTF( &gltf, DEMO_GAME_DIR, mTextureSets );
503
504     /**
505      * Create models
506      */
507     CreateModelsFromGLTF( &gltf, mModels );
508
509     /**
510      * Create scene nodes & add to 3D Layer
511      */
512     mLayer3D.Add( CreateSceneFromGLTF( window, &gltf, mModels, mActors, mCameras, mTextureSets ) );
513
514     auto planeActor = mLayer3D.FindChildByName( "Plane" );
515     auto solarActor = mLayer3D.FindChildByName( "solar_root" );
516     auto backgroundActor = mLayer3D.FindChildByName( "background" );
517     ReplaceShader( backgroundActor, VERTEX_SHADER, FRAGMENT_SIMPLE_SHADER );
518     mCenterActor = mLayer3D.FindChildByName( "center" );
519     mCenterHorizActor = mLayer3D.FindChildByName( "center2" );
520
521     // Prepare Sun
522     auto sun = mLayer3D.FindChildByName( "sun" );
523     ReplaceShader( sun, VERTEX_SHADER, PLASMA_FRAGMENT_SHADER );
524     mSunTimeUniformIndex = sun.RegisterProperty( "uTime", 0.0f );
525     mSunKFactorUniformIndex = sun.RegisterProperty( "uKFactor", 0.0f );
526
527     mTickTimer = Timer::New( 16 );
528     mTickTimer.TickSignal().Connect( this, &ReflectionExample::TickTimerSignal);
529
530     // Milkyway
531     auto milkyway = mLayer3D.FindChildByName( "milkyway" );
532     ReplaceShader( milkyway, VERTEX_SHADER, FRAGMENT_SHADER );
533
534     auto renderTaskSourceActor = mLayer3D.FindChildByName( "RenderTaskSource" );
535
536     /**
537      * Access camera (it's a child of "Camera" node)
538      */
539     auto camera = mLayer3D.FindChildByName( "Camera_Orientation" );
540     auto cameraRef = mLayer3D.FindChildByName( "CameraReflection_Orientation" );
541
542     auto cameraActor = CameraActor::DownCast( camera );
543     mCamera3D = cameraActor;
544
545     auto cameraRefActor = CameraActor::DownCast( cameraRef );
546     cameraRefActor.SetProperty( DevelCameraActor::Property::REFLECTION_PLANE, Vector4(0.0f, -1.0f, 0.0f, 0.0f));
547     mReflectionCamera3D = cameraRefActor;
548
549     auto task3D = window.GetRenderTaskList().CreateTask();
550     task3D.SetSourceActor( mLayer3D );
551     task3D.SetViewport( Rect<int>(0, 0, windowWidth, windowHeight ) );
552     task3D.SetCameraActor( cameraActor );
553     task3D.SetClearColor( Color::BLACK );
554     task3D.SetClearEnabled( true );
555     task3D.SetExclusive( false );
556     task3D.SetCameraActor( cameraActor );
557
558     /**
559      * Change shader to textured
560      */
561     Shader texShader = CreateShader( VERTEX_SHADER, TEX_FRAGMENT_SHADER );
562     planeActor.RegisterProperty( "uScreenSize", Vector2(windowWidth, windowHeight) );
563     auto renderer = planeActor.GetRendererAt(0);
564     auto textureSet = renderer.GetTextures();
565     renderer.SetShader( texShader );
566
567     Texture fbTexture = Texture::New(TextureType::TEXTURE_2D, Pixel::Format::RGBA8888, windowWidth, windowHeight );
568     textureSet.SetTexture( 1u, fbTexture );
569
570     auto fb = FrameBuffer::New(windowWidth, windowHeight,
571                                FrameBuffer::Attachment::DEPTH );
572
573     fb.AttachColorTexture( fbTexture );
574
575     auto renderTask = window.GetRenderTaskList().CreateTask();
576     renderTask.SetFrameBuffer( fb );
577     renderTask.SetSourceActor( renderTaskSourceActor );
578     renderTask.SetViewport( Rect<int>(0, 0, windowWidth, windowHeight ) );
579     renderTask.SetCameraActor( cameraRefActor );
580     renderTask.SetClearColor( Color::BLACK );
581     renderTask.SetClearEnabled( true );
582     renderTask.SetExclusive( false );
583
584     mAnimation = Animation::New(30.0f );
585     mAnimation.AnimateBy(Property(solarActor, Actor::Property::ORIENTATION ),
586                          Quaternion( Degree(359), Vector3(0.0, 1.0, 0.0)));
587     mAnimation.AnimateBy(Property(milkyway, Actor::Property::ORIENTATION ),
588                          Quaternion( Degree(-359), Vector3(0.0, 1.0, 0.0)));
589     mAnimation.SetLooping(true );
590     mAnimation.Play();
591
592     Actor panScreen = Actor::New();
593     Vector2 windowSize = window.GetSize();
594     panScreen.SetProperty( Actor::Property::SIZE, windowSize );
595     panScreen.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER );
596     panScreen.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
597     auto camera2d = window.GetRenderTaskList().GetTask(0).GetCameraActor();
598     panScreen.SetProperty( Actor::Property::POSITION, Vector3( 0, 0, camera2d.GetNearClippingPlane() ));
599     camera2d.Add(panScreen);
600     camera2d.RotateBy( Degree(180.0f), Vector3( 0.0, 1.0, 0.0 ) );
601     mPanGestureDetector = PanGestureDetector::New();
602     mPanGestureDetector.Attach( panScreen );
603     mPanGestureDetector.DetectedSignal().Connect( this, &ReflectionExample::OnPan );
604
605     // Respond to key events
606     window.KeyEventSignal().Connect( this, &ReflectionExample::OnKeyEvent );
607
608     mTickTimer.Start();
609   }
610
611   void OnPan( Actor actor, const PanGesture& panGesture )
612   {
613     auto displacement = panGesture.screenDisplacement;
614     mCenterActor.RotateBy( Degree( displacement.y *0.1f ), Vector3( 0.0, 0.0, 1.0) );
615     mCenterActor.RotateBy( Degree( displacement.x *0.1f ), Vector3( 0.0, 1.0, 0.0) );
616     Quaternion q;
617     mCenterActor.GetProperty( Actor::Property::ORIENTATION ).Get(q);
618     Matrix m = Matrix::IDENTITY;
619     m.SetTransformComponents( Vector3::ONE, q, Vector3::ZERO );
620     auto yAxis = m.GetYAxis() * -1.0f;
621
622     yAxis.Normalize();
623     mReflectionCamera3D.SetProperty( DevelCameraActor::Property::REFLECTION_PLANE, Vector4(yAxis.x, yAxis.y, yAxis.z, 0.0f));
624   }
625
626   void OnKeyEvent( const KeyEvent& event )
627   {
628     if( event.state == KeyEvent::Down )
629     {
630       if ( IsKey( event, Dali::DALI_KEY_ESCAPE ) || IsKey( event, Dali::DALI_KEY_BACK ) )
631       {
632         mApplication.Quit();
633       }
634     }
635   }
636
637   bool TickTimerSignal()
638   {
639     auto root = mLayer3D;
640     static float rotationAngle = 0.0f;
641
642     const auto ROTATION_ANGLE_STEP = 0.05f;
643     const auto FRAME_DELTA_TIME = 0.016f;
644     const auto PLASMA_K_FACTOR = 12.0f; // 'granularity' of plasma effect
645
646     rotationAngle += ROTATION_ANGLE_STEP;
647     mMockTime += FRAME_DELTA_TIME;
648     mKFactor = PLASMA_K_FACTOR;
649
650     auto sun = root.FindChildByName( "sun" );
651     sun.SetProperty( mSunTimeUniformIndex, mMockTime );
652     sun.SetProperty( mSunKFactorUniformIndex, mKFactor );
653     sun.SetProperty( Actor::Property::ORIENTATION, Quaternion( Radian(Degree(rotationAngle)), Vector3(0.0, 1.0, 0.0)));
654     return true;
655   }
656
657 private:
658
659   Application&  mApplication;
660
661   Layer mLayer3D{};
662
663   ActorContainer              mActors {};
664   CameraContainer             mCameras {};
665   ModelContainer              mModels {};
666   TextureSetContainer         mTextureSets {};
667
668   Animation mAnimation {};
669   float mMockTime { 0.0f };
670   float mKFactor { 0.0f };
671   Property::Index mSunTimeUniformIndex {};
672   Property::Index mSunKFactorUniformIndex {};
673   PanGestureDetector mPanGestureDetector {};
674
675   Timer mTickTimer {};
676
677   CameraActor mCamera3D {};
678   CameraActor mReflectionCamera3D {};
679   Actor mCenterActor {};
680   Actor mCenterHorizActor {};
681 };
682
683 int DALI_EXPORT_API main( int argc, char **argv )
684 {
685   Application application = Application::New( &argc, &argv );
686   ReflectionExample test( application );
687   application.MainLoop();
688   return 0;
689 }