Added Deferred Shading example.
[platform/core/uifw/dali-demo.git] / examples / deferred-shading / deferred-shading.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 #include "dali/dali.h"
18 #include "dali/public-api/actors/actor.h"
19 #include "dali/public-api/rendering/renderer.h"
20 #include <random>
21 #include <iostream>
22 #include <cstring>
23
24 using namespace Dali;
25
26 namespace
27 {
28 //=============================================================================
29 // Demonstrates deferred shading with multiple render targets (for color,
30 // position, and normal), a Phong lighting model and 32 point lights.
31 //
32 // Invoked with the --show-lights it will render a mesh at each light position.
33 //=============================================================================
34
35 #define QUOTE(x) DALI_COMPOSE_SHADER(x)
36
37 #define MAX_LIGHTS 32
38
39 #define DEFINE_MAX_LIGHTS "const int kMaxLights = " QUOTE(MAX_LIGHTS) ";"
40
41 #define DEFINE(x) "#define " DALI_COMPOSE_SHADER(x) DALI_COMPOSE_SHADER(\n)
42
43 //=============================================================================
44 // PRE-PASS
45 //=============================================================================
46 const char* const PREPASS_VSH = DALI_COMPOSE_SHADER(#version 300 es\n
47 precision mediump float;)
48   DALI_COMPOSE_SHADER(
49
50 // DALI uniforms
51 uniform mat4 uMvpMatrix;
52 uniform mat3 uNormalMatrix;
53 uniform vec3 uSize;
54
55 uniform vec3 uDepth_InvDepth_Near;\n)
56   DEFINE(DEPTH uDepth_InvDepth_Near.x)
57   DEFINE(INV_DEPTH uDepth_InvDepth_Near.y)
58   DEFINE(NEAR uDepth_InvDepth_Near.z)
59   DALI_COMPOSE_SHADER(
60
61 in vec3 aPosition;
62 in vec3 aNormal;
63
64 out vec4 vPosition;
65 out vec3 vNormal;
66
67 vec4 Map(vec4 v)        // projection space -> texture
68 {
69   return vec4(v.xyz / (2.f * v.w) + vec3(.5f), (v.w - NEAR) * INV_DEPTH);
70 }
71
72 void main()
73 {
74   vec4 position = uMvpMatrix * vec4(aPosition * uSize, 1.f);
75   vPosition = Map(position);
76   gl_Position = position;
77
78   vNormal = normalize(uNormalMatrix * aNormal);
79 });
80
81 //=============================================================================
82 const char* const PREPASS_FSH = DALI_COMPOSE_SHADER(#version 300 es\n
83 precision mediump float;
84
85 // DALI uniform
86 uniform vec4 uColor;
87
88 in vec4 vPosition;
89 in vec3 vNormal;
90
91 // These are our outputs.
92 layout(location = 0) out vec3 oNormal;
93 layout(location = 1) out vec4 oPosition;
94 layout(location = 2) out vec3 oColor;
95
96 void main()
97 {
98   oColor = uColor.rgb;
99   oPosition = vPosition;
100   oNormal = normalize(vNormal) * .5f + .5f;
101 });
102
103 //=============================================================================
104 // MAIN (LIGHTING) PASS
105 //=============================================================================
106 const char* const MAINPASS_VSH = DALI_COMPOSE_SHADER(#version 300 es\n
107 precision mediump float;
108
109 // DALI uniforms
110 uniform mat4 uMvpMatrix;
111 uniform vec3 uSize;
112
113 in vec3 aPosition;
114 in vec2 aTexCoord;
115
116 out vec2 vUv;
117
118 void main()
119 {
120   vec4 position = uMvpMatrix * vec4(aPosition * uSize, 1.f);
121   vUv = aTexCoord;
122
123   gl_Position = position;
124 });
125
126 //=============================================================================
127 const char* const MAINPASS_FSH = DALI_COMPOSE_SHADER(#version 300 es\n
128 precision mediump float;\n)
129   DEFINE_MAX_LIGHTS
130   DALI_COMPOSE_SHADER(
131
132 const float kAttenuationConst = .05f;
133 const float kAttenuationLinear = .1f;
134 const float kAttenuationQuadratic = .15f;
135
136 // G-buffer
137 uniform sampler2D uTextureNormal;
138 uniform sampler2D uTexturePosition;
139 uniform sampler2D uTextureColor;
140
141 uniform mat4 uInvProjection;
142
143 uniform vec3 uDepth_InvDepth_Near;\n)
144   DEFINE(DEPTH uDepth_InvDepth_Near.x)
145   DEFINE(INV_DEPTH uDepth_InvDepth_Near.y)
146   DEFINE(NEAR uDepth_InvDepth_Near.z)
147   DALI_COMPOSE_SHADER(
148
149 // Light source uniforms
150 struct Light
151 {
152   vec3 position;        // view space
153   float radius;
154   vec3 color;
155 };
156
157 uniform Light uLights[kMaxLights];
158
159 in vec2 vUv;
160
161 out vec4 oColor;
162
163 vec4 Unmap(vec4 m)      // texture -> projection
164 {
165   m.w = m.w * DEPTH + NEAR;
166   m.xyz = (m.xyz - vec3(.5)) * (2.f * m.w);
167   return m;
168 }
169
170 vec3 CalculateLighting(vec3 pos, vec3 normal)
171 {
172   vec3 viewDir = normalize(pos);
173   vec3 viewDirRefl = -reflect(viewDir, normal);
174
175   vec3 light = vec3(0.04f); // fake ambient term
176   for (int i = 0; i < kMaxLights; ++i)
177   {
178     vec3 rel = pos - uLights[i].position;
179     float distance = length(rel);
180     rel /= distance;
181
182     float a = uLights[i].radius / (kAttenuationConst + kAttenuationLinear * distance +
183       kAttenuationQuadratic * distance * distance);     // attenuation
184
185     float l = max(0.f, dot(normal, rel));       // lambertian
186     float s = pow(max(0.f, dot(viewDirRefl, rel)), 256.f);      // specular
187
188     light += (uLights[i].color * (l + s)) * a;
189   }
190
191   return light;
192 }
193
194 void main()
195 {
196   vec3 normSample = texture(uTextureNormal, vUv).xyz;
197   if (dot(normSample, normSample) == 0.f)
198   {
199     discard;  // if we didn't write this texel, don't bother lighting it.
200   }
201
202   vec3 normal = normalize(normSample - .5f);
203
204   vec4 posSample = texture(uTexturePosition, vUv);
205   vec3 pos = (uInvProjection * Unmap(posSample)).xyz;
206
207   vec3 color = texture(uTextureColor, vUv).rgb;
208   vec3 finalColor = color * CalculateLighting(pos, normal);
209
210   oColor = vec4(finalColor, 1.f);
211 });
212
213 //=============================================================================
214 // PRNG for floats.
215 struct FloatRand
216 {
217   std::random_device mDevice;
218   std::mt19937 mMersenneTwister;
219   std::uniform_real_distribution<float> mDistribution;
220
221   FloatRand()
222   : mMersenneTwister(mDevice()),
223     mDistribution(0., 1.)
224   {}
225
226   float operator()()
227   {
228     return mDistribution(mMersenneTwister);
229   }
230 };
231
232 //=============================================================================
233 float FastFloor(float x)
234 {
235   return static_cast<int>(x) - static_cast<int>(x < 0);
236 }
237
238 //=============================================================================
239 Vector3 FromHueSaturationLightness(Vector3 hsl)
240 {
241   Vector3 rgb;
242   if (hsl.y * hsl.y > 0.f)
243   {
244     if(hsl.x >= 360.f)
245     {
246       hsl.x -= 360.f;
247     }
248     hsl.x /= 60.f;
249
250     int i = FastFloor(hsl.x);
251     float ff = hsl.x - i;
252     float p = hsl.z * (1.0 - hsl.y);
253     float q = hsl.z * (1.0 - (hsl.y * ff));
254     float t = hsl.z * (1.0 - (hsl.y * (1.f - ff)));
255
256     switch (i)
257     {
258     case 0:
259       rgb.r = hsl.z;
260       rgb.g = t;
261       rgb.b = p;
262       break;
263
264     case 1:
265       rgb.r = q;
266       rgb.g = hsl.z;
267       rgb.b = p;
268       break;
269
270     case 2:
271       rgb.r = p;
272       rgb.g = hsl.z;
273       rgb.b = t;
274       break;
275
276     case 3:
277       rgb.r = p;
278       rgb.g = q;
279       rgb.b = hsl.z;
280       break;
281
282     case 4:
283       rgb.r = t;
284       rgb.g = p;
285       rgb.b = hsl.z;
286       break;
287
288     case 5:
289     default:
290       rgb.r = hsl.z;
291       rgb.g = p;
292       rgb.b = q;
293       break;
294     }
295   }
296   else
297   {
298     rgb = Vector3::ONE * hsl.z;
299   }
300
301   return rgb;
302 }
303
304 //=============================================================================
305 Geometry CreateTexturedQuadGeometry(bool flipV)
306 {
307   // Create geometry -- unit square with whole of the texture mapped to it.
308   struct Vertex
309   {
310     Vector3 aPosition;
311     Vector2 aTexCoord;
312   };
313
314   Vertex vertexData[] = {
315   { Vector3(-.5f, .5f, .0f), Vector2(.0f, 1.0f) },
316   { Vector3(.5f, .5f, .0f), Vector2(1.0f, 1.0f) },
317   { Vector3(-.5f, -.5f, .0f), Vector2(.0f, .0f) },
318   { Vector3(.5f, -.5f, .0f), Vector2(1.0f, .0f) },
319   };
320
321   if (flipV)
322   {
323     std::swap(vertexData[0].aTexCoord, vertexData[2].aTexCoord);
324     std::swap(vertexData[1].aTexCoord, vertexData[3].aTexCoord);
325   }
326
327   PropertyBuffer vertexBuffer = PropertyBuffer::New( Property::Map()
328     .Add( "aPosition", Property::VECTOR3 )
329     .Add( "aTexCoord", Property::VECTOR2 ) );
330   vertexBuffer.SetData( vertexData, std::extent<decltype(vertexData)>::value );
331
332   Geometry geometry = Geometry::New();
333   geometry.AddVertexBuffer( vertexBuffer );
334   geometry.SetType( Geometry::TRIANGLE_STRIP );
335   return geometry;
336 }
337
338 //=============================================================================
339 Geometry CreateOctahedron(bool invertNormals)
340 {
341   Vector3 positions[] = {
342     Vector3{ -1.f, 0.f, 0.f },
343     Vector3{ 1.f, 0.f, 0.f },
344     Vector3{ 0.f, -1.f, 0.f },
345     Vector3{ 0.f, 1.f, 0.f },
346     Vector3{ 0.f, 0.f, -1.f },
347     Vector3{ 0.f, 0.f, 1.f },
348   };
349
350   struct Vertex
351   {
352     Vector3 position;
353     Vector3 normal;
354   };
355   Vertex vertexData[] = {
356     { positions[0] },
357     { positions[3] },
358     { positions[5] },
359
360     { positions[5] },
361     { positions[3] },
362     { positions[1] },
363
364     { positions[1] },
365     { positions[3] },
366     { positions[4] },
367
368     { positions[4] },
369     { positions[3] },
370     { positions[0] },
371
372     { positions[0] },
373     { positions[5] },
374     { positions[2] },
375
376     { positions[5] },
377     { positions[1] },
378     { positions[2] },
379
380     { positions[1] },
381     { positions[4] },
382     { positions[2] },
383
384     { positions[4] },
385     { positions[0] },
386     { positions[2] },
387   };
388
389   // Calculate normals
390   for (uint32_t i = 0; i < std::extent<decltype(vertexData)>::value / 3; ++i)
391   {
392     uint32_t idx = i * 3;
393
394     Vector3 normal = (vertexData[idx + 2].position - vertexData[idx].position).
395         Cross(vertexData[idx + 1].position - vertexData[idx].position);
396     normal.Normalize();
397     normal *= invertNormals * 2.f - 1.f;
398
399     vertexData[idx++].normal = normal;
400     vertexData[idx++].normal = normal;
401     vertexData[idx].normal = normal;
402   }
403
404   // Configure property buffers and create geometry.
405   PropertyBuffer vertexBuffer = PropertyBuffer::New(Property::Map()
406     .Add("aPosition", Property::VECTOR3)
407     .Add("aNormal", Property::VECTOR3));
408   vertexBuffer.SetData(vertexData, std::extent<decltype(vertexData)>::value);
409
410   Geometry geometry = Geometry::New();
411   geometry.AddVertexBuffer( vertexBuffer );
412   geometry.SetType( Geometry::TRIANGLES );
413   return geometry;
414 }
415
416 //=============================================================================
417 enum RendererOptions
418 {
419   OPTION_NONE = 0x0,
420   OPTION_BLEND = 0x01,
421   OPTION_DEPTH_TEST = 0x02,
422   OPTION_DEPTH_WRITE = 0x04
423 };
424
425 Renderer CreateRenderer(TextureSet textures, Geometry geometry, Shader shader, uint32_t options = OPTION_NONE)
426 {
427   Renderer renderer = Renderer::New(geometry, shader);
428   renderer.SetProperty(Renderer::Property::BLEND_MODE,
429       (options & OPTION_BLEND) ? BlendMode::ON : BlendMode::OFF);
430   renderer.SetProperty(Renderer::Property::DEPTH_TEST_MODE,
431       (options & OPTION_DEPTH_TEST) ? DepthTestMode::ON : DepthTestMode::OFF);
432   renderer.SetProperty(Renderer::Property::DEPTH_WRITE_MODE,
433       (options & OPTION_DEPTH_WRITE) ? DepthWriteMode::ON : DepthWriteMode::OFF);
434   renderer.SetProperty(Renderer::Property::FACE_CULLING_MODE, FaceCullingMode::BACK);
435
436   if (!textures)
437   {
438     textures = TextureSet::New();
439   }
440
441   renderer.SetTextures(textures);
442   return renderer;
443 }
444
445 //=============================================================================
446 void CenterActor(Actor actor)
447 {
448   actor.SetAnchorPoint( AnchorPoint::CENTER );
449   actor.SetParentOrigin( ParentOrigin::CENTER );
450 }
451
452 //=============================================================================
453 void RegisterDepthProperties(float depth, float near, Handle& h)
454 {
455   h.RegisterProperty("uDepth_InvDepth_Near", Vector3(depth, 1.f / depth, near));
456 }
457
458 }
459
460 //=============================================================================
461 class DeferredShadingExample : public ConnectionTracker
462 {
463 public:
464   struct Options
465   {
466     enum
467     {
468       NONE = 0x0,
469       SHOW_LIGHTS = 0x1,
470     };
471   };
472
473   DeferredShadingExample(Application& app, uint32_t options = Options::NONE)
474   : mApp(app),
475     mOptions(options)
476   {
477     app.InitSignal().Connect( this, &DeferredShadingExample::Create );
478     app.TerminateSignal().Connect( this, &DeferredShadingExample::Destroy );
479   }
480
481 private:
482   void Create(Application& app)
483   {
484     // Grab stage, configure layer
485     Stage stage = Stage::GetCurrent();
486     auto rootLayer = stage.GetRootLayer();
487     rootLayer.SetBehavior(Layer::LAYER_3D);
488
489     auto stageSize = stage.GetSize();
490     auto stageHalfSize = stageSize * .5f;
491     auto invStageHalfSize = Vector2::ONE / stageHalfSize;
492
493     float unit = stageSize.y / 24.f;
494
495     // Get camera - we'll be re-using the same old camera in the two passes.
496     RenderTaskList tasks = stage.GetRenderTaskList();
497     CameraActor camera = tasks.GetTask(0).GetCameraActor();
498
499     auto zCameraPos = camera.GetProperty(Actor::Property::POSITION_Z).Get<float>();
500     camera.SetFarClippingPlane(zCameraPos + stageSize.y * .5f);
501     camera.SetNearClippingPlane(zCameraPos - stageSize.y * .5f);
502
503     const float zNear = camera.GetNearClippingPlane();
504     const float zFar = camera.GetFarClippingPlane();
505     const float depth = zFar - zNear;
506
507     // Create root of scene that shall be rendered off-screen.
508     auto sceneRoot = Actor::New();
509     CenterActor(sceneRoot);
510
511     mSceneRoot = sceneRoot;
512     stage.Add(sceneRoot);
513
514     // Create an axis to spin our actors around.
515     auto axis = Actor::New();
516     CenterActor(axis);
517     sceneRoot.Add(axis);
518     mAxis = axis;
519
520     // Create an octahedral mesh for our main actors and to visualise the light sources.
521     Geometry mesh = CreateOctahedron(false);
522
523     // Create main actors
524     Shader preShader = Shader::New(PREPASS_VSH, PREPASS_FSH);
525     TextureSet noTexturesThanks = TextureSet::New();
526     Renderer meshRenderer = CreateRenderer(noTexturesThanks, mesh, preShader,
527         OPTION_DEPTH_TEST | OPTION_DEPTH_WRITE);
528     meshRenderer.SetProperty(Renderer::Property::FACE_CULLING_MODE, FaceCullingMode::BACK);
529     meshRenderer.RegisterProperty("uInvStageHalfSize", invStageHalfSize);
530     RegisterDepthProperties(depth, zNear, meshRenderer);
531     float c = 1.f;
532     for (auto v: {
533       Vector3{ -c, -c, -c },
534       Vector3{ c, -c, -c },
535       Vector3{ -c, c, -c },
536       Vector3{ c, c, -c },
537       Vector3{ -c, -c, c },
538       Vector3{ c, -c, c },
539       Vector3{ -c, c, c },
540       Vector3{ c, c, c },
541
542       Vector3{ 0.f, -c, -c },
543       Vector3{ 0.f, c, -c },
544       Vector3{ 0.f, -c, c },
545       Vector3{ 0.f, c, c },
546
547       Vector3{ -c, 0.f, -c },
548       Vector3{ c, 0.f, -c },
549       Vector3{ -c, 0.f, c },
550       Vector3{ c, 0.f, c },
551
552       Vector3{ -c, -c, 0.f },
553       Vector3{ c, -c, 0.f },
554       Vector3{ -c, c, 0.f },
555       Vector3{ c, c, 0.f },
556     })
557     {
558       Actor a = Actor::New();
559       CenterActor(a);
560
561       Vector3 position{ v * unit * 5.f };
562       a.SetPosition(position);
563
564       float scale = (c + ((v.x + v.y + v.z) + c * 3.f) * .5f) / (c * 4.f);
565       Vector3 size{ Vector3::ONE * scale * unit * 2.f };
566       a.SetSize(size);
567
568       a.SetColor(Color::WHITE * .25f +
569           (Color::RED * (v.x + c) / (c * 2.f) +
570           Color::GREEN * (v.y + c) / (c * 2.f) +
571           Color::BLUE * (v.z + c) / (c * 2.f)) * .015625f);
572       a.AddRenderer(meshRenderer);
573
574       axis.Add(a);
575     }
576
577     // Create off-screen textures, fbo and render task.
578     uint32_t width = static_cast<uint32_t>(stageSize.x);
579     uint32_t height = static_cast<uint32_t>(stageSize.y);
580
581     Texture rttNormal = Texture::New(TextureType::TEXTURE_2D, Pixel::Format::RGB888,
582         width, height);
583     Texture rttPosition = Texture::New(TextureType::TEXTURE_2D, Pixel::Format::RGBA8888,
584         width, height);
585     Texture rttColor = Texture::New(TextureType::TEXTURE_2D, Pixel::Format::RGB888,
586         width, height);
587     FrameBuffer fbo = FrameBuffer::New(width, height, FrameBuffer::Attachment::DEPTH);
588     fbo.AttachColorTexture(rttNormal);
589     fbo.AttachColorTexture(rttPosition);
590     fbo.AttachColorTexture(rttColor);
591
592     RenderTask sceneRender = tasks.CreateTask();
593     sceneRender.SetViewportSize(stageSize);
594     sceneRender.SetFrameBuffer(fbo);
595     sceneRender.SetCameraActor(camera);
596     sceneRender.SetSourceActor(sceneRoot);
597     sceneRender.SetInputEnabled(false);
598     sceneRender.SetCullMode(false);
599     sceneRender.SetClearEnabled(true);
600     sceneRender.SetClearColor(Color::BLACK);
601     sceneRender.SetExclusive(true);
602
603     mSceneRender = sceneRender;
604
605     // Create final image for deferred shading
606     auto finalImage = Actor::New();
607     CenterActor(finalImage);
608     finalImage.SetSize(stageSize);
609
610     TextureSet finalImageTextures = TextureSet::New();
611     finalImageTextures.SetTexture(0, rttNormal);
612     finalImageTextures.SetTexture(1, rttPosition);
613     finalImageTextures.SetTexture(2, rttColor);
614
615     Sampler sampler = Sampler::New();
616     sampler.SetFilterMode(FilterMode::NEAREST, FilterMode::NEAREST);
617     finalImageTextures.SetSampler(0, sampler);
618     finalImageTextures.SetSampler(1, sampler);
619     finalImageTextures.SetSampler(2, sampler);
620
621     Shader shdMain = Shader::New(MAINPASS_VSH, MAINPASS_FSH);
622     Geometry finalImageGeom = CreateTexturedQuadGeometry(true);
623     Renderer finalImageRenderer = CreateRenderer(finalImageTextures, finalImageGeom, shdMain);
624     finalImageRenderer.RegisterProperty("uStageHalfSize", stageHalfSize);
625     RegisterDepthProperties(depth, zNear, finalImageRenderer);
626
627     auto propInvProjection = finalImageRenderer.RegisterProperty("uInvProjection", Matrix::IDENTITY);
628     Constraint cnstrInvProjection = Constraint::New<Matrix>(finalImageRenderer, propInvProjection,
629       [zCameraPos, zNear, depth](Matrix& output, const PropertyInputContainer& input) {
630         output = input[0]->GetMatrix();
631         DALI_ASSERT_ALWAYS(output.Invert() && "Failed to invert projection matrix.");
632       });
633     cnstrInvProjection.AddSource(Source(camera, CameraActor::Property::PROJECTION_MATRIX));
634     cnstrInvProjection.AddSource(Source(camera, CameraActor::Property::VIEW_MATRIX));
635     cnstrInvProjection.Apply();
636
637     finalImage.AddRenderer(finalImageRenderer);
638
639     mFinalImage = finalImage;
640     stage.Add(finalImage);
641
642     // Create a node for our lights
643     auto lights = Actor::New();
644     CenterActor(lights);
645     sceneRoot.Add(lights);
646
647     // Create Lights
648     const bool showLights = mOptions & Options::SHOW_LIGHTS;
649     Renderer lightRenderer;
650     if (showLights)
651     {
652       Geometry lightMesh = CreateOctahedron(true);
653       lightRenderer = CreateRenderer(noTexturesThanks, lightMesh, preShader,
654           OPTION_DEPTH_TEST | OPTION_DEPTH_WRITE);
655       lightRenderer.SetProperty(Renderer::Property::FACE_CULLING_MODE, FaceCullingMode::FRONT);
656     }
657
658     Vector3 lightPos{ unit * 12.f, 0.f, 0.f };
659     float theta = M_PI * 2.f / MAX_LIGHTS;
660     float cosTheta = std::cos(theta);
661     float sinTheta = std::sin(theta);
662     for (int i = 0; i < MAX_LIGHTS; ++i)
663     {
664       Vector3 color = FromHueSaturationLightness(Vector3((360.f * i) / MAX_LIGHTS, .5f, 1.f));
665
666       Actor light = CreateLight(lightPos * (1 + (i % 8)) / 8.f, unit * 16.f, color, camera, finalImageRenderer);
667
668       float z = (((i & 1) << 1) - 1) * unit * 8.f;
669       lightPos = Vector3(cosTheta * lightPos.x - sinTheta * lightPos.y, sinTheta * lightPos.x + cosTheta * lightPos.y, z);
670
671       if (showLights)
672       {
673         light.SetProperty(Actor::Property::SIZE, Vector3::ONE * unit / 8.f);
674         light.AddRenderer(lightRenderer);
675       }
676
677       lights.Add(light);
678     }
679
680     // Take them for a spin.
681     Animation animLights = Animation::New(40.f);
682     animLights.SetLooping(true);
683     animLights.AnimateBy(Property(lights, Actor::Property::ORIENTATION), Quaternion(Radian(M_PI * 2.f), Vector3::YAXIS));
684     animLights.Play();
685
686     // Event handling
687     stage.KeyEventSignal().Connect(this, &DeferredShadingExample::OnKeyEvent);
688
689     mPanDetector = PanGestureDetector::New();
690     mPanDetector.DetectedSignal().Connect(this, &DeferredShadingExample::OnPan);
691     mPanDetector.Attach(stage.GetRootLayer());
692   }
693
694   void Destroy(Application& app)
695   {
696     Stage::GetCurrent().GetRenderTaskList().RemoveTask(mSceneRender);
697     mSceneRender.Reset();
698
699     UnparentAndReset(mSceneRoot);
700     UnparentAndReset(mFinalImage);
701   }
702
703   Actor CreateLight(Vector3 position, float radius, Vector3 color, CameraActor camera, Renderer renderer)
704   {
705     Actor light = Actor::New();
706     CenterActor(light);
707     light.SetProperty(Actor::Property::COLOR, Color::WHITE);
708     light.SetProperty(Actor::Property::POSITION, position);
709
710     auto iPropRadius = light.RegisterProperty("radius", radius);
711     auto iPropLightColor = light.RegisterProperty("lightcolor", color);
712
713     // Create light source uniforms on lighting shader.
714     char buffer[128];
715     char* writep = buffer + sprintf(buffer, "uLights[%d].", mNumLights);
716     ++mNumLights;
717
718     strcpy(writep, "position");
719     auto oPropLightPos = renderer.RegisterProperty(buffer, position);
720
721     strcpy(writep, "radius");
722     auto oPropLightRadius = renderer.RegisterProperty(buffer, radius);
723
724     strcpy(writep, "color");
725     auto oPropLightColor = renderer.RegisterProperty(buffer, color);
726
727     // Constrain the light position, radius and color to lighting shader uniforms.
728     // Convert light position to view space;
729     Constraint cLightPos = Constraint::New<Vector3>(renderer, oPropLightPos, [](Vector3& output, const PropertyInputContainer& input)
730     {
731       Vector4 worldPos(input[0]->GetVector3());
732       worldPos.w = 1.f;
733
734       worldPos = input[1]->GetMatrix() * worldPos;
735       output = Vector3(worldPos);
736     });
737     cLightPos.AddSource(Source(light, Actor::Property::WORLD_POSITION));
738     cLightPos.AddSource(Source(camera, CameraActor::Property::VIEW_MATRIX));
739     cLightPos.Apply();
740
741     Constraint cLightRadius = Constraint::New<float>(renderer, oPropLightRadius,
742         EqualToConstraint());
743     cLightRadius.AddSource(Source(light, iPropRadius));
744     cLightRadius.Apply();
745
746     Constraint cLightColor = Constraint::New<Vector3>(renderer, oPropLightColor,
747         EqualToConstraint());
748     cLightColor.AddSource(Source(light, iPropLightColor));
749     cLightColor.Apply();
750
751     return light;
752   }
753
754   void OnPan(Actor, PanGesture const& gesture)
755   {
756     Quaternion q = mAxis.GetProperty(Actor::Property::ORIENTATION).Get<Quaternion>();
757     Quaternion qx(Radian(Degree(gesture.screenDisplacement.y) * -.5f), Vector3::XAXIS);
758     Quaternion qy(Radian(Degree(gesture.screenDisplacement.x) * .5f), Vector3::YAXIS);
759     mAxis.SetProperty(Actor::Property::ORIENTATION, qy * qx * q);
760   }
761
762   void OnKeyEvent(const KeyEvent& event)
763   {
764     if(event.state == KeyEvent::Down)
765     {
766       if( IsKey( event, Dali::DALI_KEY_ESCAPE) || IsKey( event, Dali::DALI_KEY_BACK) )
767       {
768         mApp.Quit();
769       }
770     }
771   }
772
773   Application& mApp;
774   uint32_t mOptions;
775
776   Actor mSceneRoot;
777   Actor mAxis;
778
779   RenderTask mSceneRender;
780   Actor mFinalImage;
781
782   int mNumLights = 0;
783
784   PanGestureDetector mPanDetector;
785 };
786
787
788 int main(int argc, char** argv)
789 {
790   const bool showLights = [](int argc, char** argv)
791   {
792     auto endArgs = argv + argc;
793     return std::find_if(argv, endArgs, [](const char* arg)
794     {
795       return strcmp(arg, "--show-lights") == 0;
796     }) != endArgs;
797   }(argc, argv);
798
799   Application app = Application::New(&argc, &argv);
800   DeferredShadingExample example(app, (showLights ? DeferredShadingExample::Options::SHOW_LIGHTS : 0));
801   app.MainLoop();
802   return 0;
803 }