Updated demos to use DALi clang-format
[platform/core/uifw/dali-demo.git] / examples / refraction-effect / refraction-effect-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 // EXTERNAL INCLUDES
19 #include <dali-toolkit/dali-toolkit.h>
20 #include <dali/dali.h>
21 #include <dali/devel-api/adaptor-framework/file-loader.h>
22 #include <dali/integration-api/debug.h>
23
24 #include <cctype>
25 #include <limits>
26 #include <sstream>
27
28 // INTERNAL INCLUDES
29 #include "shared/utility.h"
30 #include "shared/view.h"
31
32 using namespace Dali;
33
34 namespace
35 {
36 const char* const APPLICATION_TITLE("Refraction Effect");
37 const char* const TOOLBAR_IMAGE(DEMO_IMAGE_DIR "top-bar.png");
38 const char* const CHANGE_TEXTURE_ICON(DEMO_IMAGE_DIR "icon-change.png");
39 const char* const CHANGE_TEXTURE_ICON_SELECTED(DEMO_IMAGE_DIR "icon-change-selected.png");
40 const char* const CHANGE_MESH_ICON(DEMO_IMAGE_DIR "icon-replace.png");
41 const char* const CHANGE_MESH_ICON_SELECTED(DEMO_IMAGE_DIR "icon-replace-selected.png");
42
43 const char* MESH_FILES[] =
44   {
45     DEMO_MODEL_DIR "surface_pattern_v01.obj",
46     DEMO_MODEL_DIR "surface_pattern_v02.obj"};
47 const unsigned int NUM_MESH_FILES(sizeof(MESH_FILES) / sizeof(MESH_FILES[0]));
48
49 const char* TEXTURE_IMAGES[] =
50   {
51     DEMO_IMAGE_DIR "background-1.jpg",
52     DEMO_IMAGE_DIR "background-2.jpg",
53     DEMO_IMAGE_DIR "background-3.jpg",
54     DEMO_IMAGE_DIR "background-4.jpg"};
55 const unsigned int NUM_TEXTURE_IMAGES(sizeof(TEXTURE_IMAGES) / sizeof(TEXTURE_IMAGES[0]));
56
57 struct LightOffsetConstraint
58 {
59   LightOffsetConstraint(float radius)
60   : mRadius(radius)
61   {
62   }
63
64   void operator()(Vector2& current, const PropertyInputContainer& inputs)
65   {
66     float spinAngle = inputs[0]->GetFloat();
67     current.x       = cos(spinAngle);
68     current.y       = sin(spinAngle);
69
70     current *= mRadius;
71   }
72
73   float mRadius;
74 };
75
76 /**
77  * structure of the vertex in the mesh
78  */
79 struct Vertex
80 {
81   Vector3 position;
82   Vector3 normal;
83   Vector2 textureCoord;
84
85   Vertex()
86   {
87   }
88
89   Vertex(const Vector3& position, const Vector3& normal, const Vector2& textureCoord)
90   : position(position),
91     normal(normal),
92     textureCoord(textureCoord)
93   {
94   }
95 };
96
97 /************************************************************************************************
98  *** The shader source is used when the MeshActor is not touched***
99  ************************************************************************************************/
100 // clang-format off
101 const char* VERTEX_SHADER_FLAT = DALI_COMPOSE_SHADER(
102 attribute mediump vec3    aPosition;\n
103 attribute mediump vec3    aNormal;\n
104 attribute highp   vec2    aTexCoord;\n
105 uniform   mediump mat4    uMvpMatrix;\n
106 varying   mediump vec2    vTexCoord;\n
107 void main()\n
108 {\n
109   gl_Position = uMvpMatrix * vec4( aPosition.xy, 0.0, 1.0 );\n
110   vTexCoord = aTexCoord.xy;\n
111 }\n
112 );
113
114 const char* FRAGMENT_SHADER_FLAT = DALI_COMPOSE_SHADER(
115 uniform lowp    vec4  uColor;\n
116 uniform sampler2D     sTexture;\n
117 varying mediump vec2  vTexCoord;\n
118 void main()\n
119 {\n
120   gl_FragColor = texture2D( sTexture, vTexCoord ) * uColor;\n
121 }\n
122 );
123
124 /************************************************************
125  ** Custom refraction effect shader***************************
126  ************************************************************/
127 const char* VERTEX_SHADER_REFRACTION = DALI_COMPOSE_SHADER(
128 attribute mediump vec3    aPosition;\n
129 attribute mediump vec3    aNormal;\n
130 attribute highp   vec2    aTexCoord;\n
131 uniform   mediump mat4    uMvpMatrix;\n
132 varying   mediump vec4    vVertex;\n
133 varying   mediump vec3    vNormal;\n
134 varying   mediump vec2    vTexCoord;\n
135 varying   mediump vec2    vTextureOffset;\n
136 void main()\n
137 {\n
138   gl_Position = uMvpMatrix * vec4( aPosition.xy, 0.0, 1.0 );\n
139   vTexCoord = aTexCoord.xy;\n
140
141   vNormal = aNormal;\n
142   vVertex = vec4( aPosition, 1.0 );\n
143   float length = max(0.01, length(aNormal.xy)) * 40.0;\n
144   vTextureOffset = aNormal.xy / length;\n
145 }\n
146 );
147
148 const char* FRAGMENT_SHADER_REFRACTION = DALI_COMPOSE_SHADER(
149 precision mediump float;\n
150 uniform   mediump float  uEffectStrength;\n
151 uniform   mediump vec3   uLightPosition;\n
152 uniform   mediump vec2   uLightXYOffset;\n
153 uniform   mediump vec2   uLightSpinOffset;\n
154 uniform   mediump float  uLightIntensity;\n
155 uniform   lowp    vec4   uColor;\n
156 uniform   sampler2D      sTexture;\n
157 varying   mediump vec4   vVertex;\n
158 varying   mediump vec3   vNormal;\n
159 varying   mediump vec2   vTexCoord;\n
160 varying   mediump vec2   vTextureOffset;\n
161
162 vec3 rgb2hsl(vec3 rgb)\n
163 {\n
164   float epsilon = 1.0e-10;\n
165   vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n
166   vec4 P = mix(vec4(rgb.bg, K.wz), vec4(rgb.gb, K.xy), step(rgb.b, rgb.g));\n
167   vec4 Q = mix(vec4(P.xyw, rgb.r), vec4(rgb.r, P.yzx), step(P.x, rgb.r));\n
168   \n
169   // RGB -> HCV
170   float value = Q.x;\n
171   float chroma = Q.x - min(Q.w, Q.y);\n
172   float hue = abs(Q.z + (Q.w-Q.y) / (6.0*chroma+epsilon));\n
173   // HCV -> HSL
174   float lightness = value - chroma*0.5;\n
175   return vec3( hue, chroma/max( 1.0-abs(lightness*2.0-1.0), 1.0e-1 ), lightness );\n
176 }\n
177
178 vec3 hsl2rgb( vec3 hsl )\n
179 {\n
180   // pure hue->RGB
181   vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n
182   vec3 p = abs(fract(hsl.xxx + K.xyz) * 6.0 - K.www);\n
183   vec3 RGB = clamp(p - K.xxx, 0.0, 1.0);\n
184   \n
185   float chroma = ( 1.0 - abs( hsl.z*2.0-1.0 ) ) * hsl.y;\n
186   return ( RGB - 0.5 ) * chroma + hsl.z;\n
187 }\n
188
189 void main()\n
190 {\n
191   vec3 normal = normalize( vNormal);\n
192
193   vec3 lightPosition = uLightPosition + vec3(uLightXYOffset+uLightSpinOffset, 0.0);\n
194   mediump vec3 vecToLight = normalize( (lightPosition - vVertex.xyz) * 0.01 );\n
195   mediump float spotEffect = pow( max(0.05, vecToLight.z ) - 0.05, 8.0);\n
196
197   spotEffect = spotEffect * uEffectStrength;\n
198   mediump float lightDiffuse = ( ( dot( vecToLight, normal )-0.75 ) *uLightIntensity  ) * spotEffect;\n
199
200   lowp vec4 color = texture2D( sTexture, vTexCoord + vTextureOffset * spotEffect );\n
201   vec3 lightedColor =  hsl2rgb( rgb2hsl(color.rgb) + vec3(0.0,0.0,lightDiffuse) );\n
202
203   gl_FragColor = vec4( lightedColor, color.a ) * uColor;\n
204 }\n
205 );
206 // clang-format on
207
208 } // namespace
209
210 /*************************************************/
211 /*Demo using RefractionEffect*****************/
212 /*************************************************/
213 class RefractionEffectExample : public ConnectionTracker
214 {
215 public:
216   RefractionEffectExample(Application& application)
217   : mApplication(application),
218     mContent(),
219     mTextureSet(),
220     mGeometry(),
221     mRenderer(),
222     mMeshActor(),
223     mShaderFlat(),
224     mShaderRefraction(),
225     mLightAnimation(),
226     mStrenghAnimation(),
227     mLightXYOffsetIndex(Property::INVALID_INDEX),
228     mSpinAngleIndex(Property::INVALID_INDEX),
229     mLightIntensityIndex(Property::INVALID_INDEX),
230     mEffectStrengthIndex(Property::INVALID_INDEX),
231     mChangeTextureButton(),
232     mChangeMeshButton(),
233     mCurrentTextureId(1),
234     mCurrentMeshId(0)
235   {
236     // Connect to the Application's Init signal
237     application.InitSignal().Connect(this, &RefractionEffectExample::Create);
238   }
239
240   ~RefractionEffectExample()
241   {
242   }
243
244 private:
245   // The Init signal is received once (only) during the Application lifetime
246   void Create(Application& application)
247   {
248     Window  window     = application.GetWindow();
249     Vector2 windowSize = window.GetSize();
250
251     window.KeyEventSignal().Connect(this, &RefractionEffectExample::OnKeyEvent);
252
253     // Creates a default view with a default tool bar.
254     // The view is added to the window.
255     Toolkit::ToolBar toolBar;
256     Toolkit::Control view;
257     mContent = DemoHelper::CreateView(application,
258                                       view,
259                                       toolBar,
260                                       "",
261                                       TOOLBAR_IMAGE,
262                                       APPLICATION_TITLE);
263
264     // Add a button to change background. (right of toolbar)
265     mChangeTextureButton = Toolkit::PushButton::New();
266     mChangeTextureButton.SetProperty(Toolkit::Button::Property::UNSELECTED_BACKGROUND_VISUAL, CHANGE_TEXTURE_ICON);
267     mChangeTextureButton.SetProperty(Toolkit::Button::Property::SELECTED_BACKGROUND_VISUAL, CHANGE_TEXTURE_ICON_SELECTED);
268     mChangeTextureButton.ClickedSignal().Connect(this, &RefractionEffectExample::OnChangeTexture);
269     toolBar.AddControl(mChangeTextureButton,
270                        DemoHelper::DEFAULT_VIEW_STYLE.mToolBarButtonPercentage,
271                        Toolkit::Alignment::HORIZONTAL_RIGHT,
272                        DemoHelper::DEFAULT_MODE_SWITCH_PADDING);
273     // Add a button to change mesh pattern. ( left of bar )
274     mChangeMeshButton = Toolkit::PushButton::New();
275     mChangeMeshButton.SetProperty(Toolkit::Button::Property::UNSELECTED_BACKGROUND_VISUAL, CHANGE_MESH_ICON);
276     mChangeMeshButton.SetProperty(Toolkit::Button::Property::SELECTED_BACKGROUND_VISUAL, CHANGE_MESH_ICON_SELECTED);
277     mChangeMeshButton.ClickedSignal().Connect(this, &RefractionEffectExample::OnChangeMesh);
278     toolBar.AddControl(mChangeMeshButton,
279                        DemoHelper::DEFAULT_VIEW_STYLE.mToolBarButtonPercentage,
280                        Toolkit::Alignment::HORIZONTAL_LEFT,
281                        DemoHelper::DEFAULT_MODE_SWITCH_PADDING);
282
283     // shader used when the screen is not touched, render a flat surface
284     mShaderFlat = Shader::New(VERTEX_SHADER_FLAT, FRAGMENT_SHADER_FLAT);
285     mGeometry   = CreateGeometry(MESH_FILES[mCurrentMeshId]);
286
287     Texture texture = DemoHelper::LoadWindowFillingTexture(window.GetSize(), TEXTURE_IMAGES[mCurrentTextureId]);
288     mTextureSet     = TextureSet::New();
289     mTextureSet.SetTexture(0u, texture);
290
291     mRenderer = Renderer::New(mGeometry, mShaderFlat);
292     mRenderer.SetTextures(mTextureSet);
293
294     mMeshActor = Actor::New();
295     mMeshActor.AddRenderer(mRenderer);
296     mMeshActor.SetProperty(Actor::Property::SIZE, windowSize);
297     mMeshActor.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
298     mContent.Add(mMeshActor);
299
300     // Connect the callback to the touch signal on the mesh actor
301     mContent.TouchedSignal().Connect(this, &RefractionEffectExample::OnTouch);
302
303     // shader used when the finger is touching the screen. render refraction effect
304     mShaderRefraction = Shader::New(VERTEX_SHADER_REFRACTION, FRAGMENT_SHADER_REFRACTION);
305
306     // register uniforms
307     mLightXYOffsetIndex = mMeshActor.RegisterProperty("uLightXYOffset", Vector2::ZERO);
308
309     mLightIntensityIndex = mMeshActor.RegisterProperty("uLightIntensity", 2.5f);
310
311     mEffectStrengthIndex = mMeshActor.RegisterProperty("uEffectStrength", 0.f);
312
313     Vector3 lightPosition(-windowSize.x * 0.5f, -windowSize.y * 0.5f, windowSize.x * 0.5f); // top_left
314     mMeshActor.RegisterProperty("uLightPosition", lightPosition);
315
316     Property::Index lightSpinOffsetIndex = mMeshActor.RegisterProperty("uLightSpinOffset", Vector2::ZERO);
317
318     mSpinAngleIndex       = mMeshActor.RegisterProperty("uSpinAngle", 0.f);
319     Constraint constraint = Constraint::New<Vector2>(mMeshActor, lightSpinOffsetIndex, LightOffsetConstraint(windowSize.x * 0.1f));
320     constraint.AddSource(LocalSource(mSpinAngleIndex));
321     constraint.Apply();
322
323     // the animation which spin the light around the finger touch position
324     mLightAnimation = Animation::New(2.f);
325     mLightAnimation.AnimateTo(Property(mMeshActor, mSpinAngleIndex), Math::PI * 2.f);
326     mLightAnimation.SetLooping(true);
327     mLightAnimation.Pause();
328   }
329
330   void SetLightXYOffset(const Vector2& offset)
331   {
332     mMeshActor.SetProperty(mLightXYOffsetIndex, offset);
333   }
334
335   /**
336    * Create a mesh actor with different geometry to replace the current one
337    */
338   bool OnChangeMesh(Toolkit::Button button)
339   {
340     mCurrentMeshId = (mCurrentMeshId + 1) % NUM_MESH_FILES;
341     mGeometry      = CreateGeometry(MESH_FILES[mCurrentMeshId]);
342     mRenderer.SetGeometry(mGeometry);
343
344     return true;
345   }
346
347   bool OnChangeTexture(Toolkit::Button button)
348   {
349     mCurrentTextureId = (mCurrentTextureId + 1) % NUM_TEXTURE_IMAGES;
350     Texture texture   = DemoHelper::LoadWindowFillingTexture(mApplication.GetWindow().GetSize(), TEXTURE_IMAGES[mCurrentTextureId]);
351     mTextureSet.SetTexture(0u, texture);
352     return true;
353   }
354
355   bool OnTouch(Actor actor, const TouchEvent& event)
356   {
357     switch(event.GetState(0))
358     {
359       case PointState::DOWN:
360       {
361         mRenderer.SetShader(mShaderRefraction);
362
363         SetLightXYOffset(event.GetScreenPosition(0));
364
365         mLightAnimation.Play();
366
367         if(mStrenghAnimation)
368         {
369           mStrenghAnimation.Clear();
370         }
371
372         mStrenghAnimation = Animation::New(0.5f);
373         mStrenghAnimation.AnimateTo(Property(mMeshActor, mEffectStrengthIndex), 1.f);
374         mStrenghAnimation.Play();
375
376         break;
377       }
378       case PointState::MOTION:
379       {
380         // make the light position following the finger movement
381         SetLightXYOffset(event.GetScreenPosition(0));
382         break;
383       }
384       case PointState::UP:
385       case PointState::LEAVE:
386       case PointState::INTERRUPTED:
387       {
388         mLightAnimation.Pause();
389
390         if(mStrenghAnimation)
391         {
392           mStrenghAnimation.Clear();
393         }
394         mStrenghAnimation = Animation::New(0.5f);
395         mStrenghAnimation.AnimateTo(Property(mMeshActor, mEffectStrengthIndex), 0.f);
396         mStrenghAnimation.FinishedSignal().Connect(this, &RefractionEffectExample::OnTouchFinished);
397         mStrenghAnimation.Play();
398         break;
399       }
400       case PointState::STATIONARY:
401       {
402         break;
403       }
404     }
405
406     return true;
407   }
408
409   void OnTouchFinished(Animation& source)
410   {
411     mRenderer.SetShader(mShaderFlat);
412     SetLightXYOffset(Vector2::ZERO);
413   }
414
415   Geometry CreateGeometry(const std::string& objFileName)
416   {
417     std::vector<Vector3> vertexPositions;
418     Vector<unsigned int> faceIndices;
419     Vector<float>        boundingBox;
420     // read the vertice and faces from the .obj file, and record the bounding box
421     ReadObjFile(objFileName, boundingBox, vertexPositions, faceIndices);
422
423     std::vector<Vector2> textureCoordinates;
424     // align the mesh, scale it to fit the screen size, and calculate the texture coordinate for each vertex
425     ShapeResizeAndTexureCoordinateCalculation(boundingBox, vertexPositions, textureCoordinates);
426
427     // re-organize the mesh, the vertices are duplicated, each vertex only belongs to one triangle.
428     // Without sharing vertex between triangle, so we can manipulate the texture offset on each triangle conveniently.
429     std::vector<Vertex> vertices;
430
431     std::size_t size = faceIndices.Size();
432     vertices.reserve(size);
433
434     for(std::size_t i = 0; i < size; i = i + 3)
435     {
436       Vector3 edge1  = vertexPositions[faceIndices[i + 2]] - vertexPositions[faceIndices[i]];
437       Vector3 edge2  = vertexPositions[faceIndices[i + 1]] - vertexPositions[faceIndices[i]];
438       Vector3 normal = edge1.Cross(edge2);
439       normal.Normalize();
440
441       // make sure all the faces are front-facing
442       if(normal.z > 0)
443       {
444         vertices.push_back(Vertex(vertexPositions[faceIndices[i]], normal, textureCoordinates[faceIndices[i]]));
445         vertices.push_back(Vertex(vertexPositions[faceIndices[i + 1]], normal, textureCoordinates[faceIndices[i + 1]]));
446         vertices.push_back(Vertex(vertexPositions[faceIndices[i + 2]], normal, textureCoordinates[faceIndices[i + 2]]));
447       }
448       else
449       {
450         normal *= -1.f;
451         vertices.push_back(Vertex(vertexPositions[faceIndices[i]], normal, textureCoordinates[faceIndices[i]]));
452         vertices.push_back(Vertex(vertexPositions[faceIndices[i + 2]], normal, textureCoordinates[faceIndices[i + 2]]));
453         vertices.push_back(Vertex(vertexPositions[faceIndices[i + 1]], normal, textureCoordinates[faceIndices[i + 1]]));
454       }
455     }
456
457     Property::Map vertexFormat;
458     vertexFormat["aPosition"]    = Property::VECTOR3;
459     vertexFormat["aNormal"]      = Property::VECTOR3;
460     vertexFormat["aTexCoord"]    = Property::VECTOR2;
461     VertexBuffer surfaceVertices = VertexBuffer::New(vertexFormat);
462     surfaceVertices.SetData(&vertices[0], vertices.size());
463
464     Geometry surface = Geometry::New();
465     surface.AddVertexBuffer(surfaceVertices);
466
467     return surface;
468   }
469
470   void ReadObjFile(const std::string&    objFileName,
471                    Vector<float>&        boundingBox,
472                    std::vector<Vector3>& vertexPositions,
473                    Vector<unsigned int>& faceIndices)
474   {
475     std::streampos     bufferSize = 0;
476     Dali::Vector<char> fileBuffer;
477     if(!Dali::FileLoader::ReadFile(objFileName, bufferSize, fileBuffer, Dali::FileLoader::FileType::TEXT))
478     {
479       DALI_LOG_WARNING("file open failed for: \"%s\"", objFileName.c_str());
480       return;
481     }
482
483     fileBuffer.PushBack('\0');
484
485     std::stringstream iss(&fileBuffer[0], std::ios::in);
486
487     boundingBox.Resize(6);
488     boundingBox[0] = boundingBox[2] = boundingBox[4] = std::numeric_limits<float>::max();
489     boundingBox[1] = boundingBox[3] = boundingBox[5] = -std::numeric_limits<float>::max();
490
491     std::string line;
492     while(std::getline(iss, line))
493     {
494       if(line[0] == 'v' && std::isspace(line[1])) // vertex
495       {
496         std::istringstream iss(line.substr(2), std::istringstream::in);
497         unsigned int       i = 0;
498         Vector3            vertex;
499         while(iss >> vertex[i++] && i < 3)
500           ;
501         if(vertex.x < boundingBox[0]) boundingBox[0] = vertex.x;
502         if(vertex.x > boundingBox[1]) boundingBox[1] = vertex.x;
503         if(vertex.y < boundingBox[2]) boundingBox[2] = vertex.y;
504         if(vertex.y > boundingBox[3]) boundingBox[3] = vertex.y;
505         if(vertex.z < boundingBox[4]) boundingBox[4] = vertex.z;
506         if(vertex.z > boundingBox[5]) boundingBox[5] = vertex.z;
507         vertexPositions.push_back(vertex);
508       }
509       else if(line[0] == 'f') //face
510       {
511         unsigned int numOfInt = 3;
512         while(true)
513         {
514           std::size_t found = line.find('/');
515           if(found == std::string::npos)
516           {
517             break;
518           }
519           line[found] = ' ';
520           numOfInt++;
521         }
522
523         std::istringstream         iss(line.substr(2), std::istringstream::in);
524         Dali::Vector<unsigned int> indices;
525         indices.Resize(numOfInt);
526         unsigned int i = 0;
527         while(iss >> indices[i++] && i < numOfInt)
528           ;
529         unsigned int step = (i + 1) / 3;
530         faceIndices.PushBack(indices[0] - 1);
531         faceIndices.PushBack(indices[step] - 1);
532         faceIndices.PushBack(indices[2 * step] - 1);
533       }
534     }
535   }
536
537   void ShapeResizeAndTexureCoordinateCalculation(const Vector<float>&  boundingBox,
538                                                  std::vector<Vector3>& vertexPositions,
539                                                  std::vector<Vector2>& textureCoordinates)
540   {
541     Vector3 bBoxSize(boundingBox[1] - boundingBox[0], boundingBox[3] - boundingBox[2], boundingBox[5] - boundingBox[4]);
542     Vector3 bBoxMinCorner(boundingBox[0], boundingBox[2], boundingBox[4]);
543
544     Vector2 windowSize = mApplication.GetWindow().GetSize();
545     Vector3 scale(windowSize.x / bBoxSize.x, windowSize.y / bBoxSize.y, 1.f);
546     scale.z = (scale.x + scale.y) / 2.f;
547
548     textureCoordinates.reserve(vertexPositions.size());
549
550     for(std::vector<Vector3>::iterator iter = vertexPositions.begin(); iter != vertexPositions.end(); iter++)
551     {
552       Vector3 newPosition((*iter) - bBoxMinCorner);
553
554       textureCoordinates.push_back(Vector2(newPosition.x / bBoxSize.x, newPosition.y / bBoxSize.y));
555
556       newPosition -= bBoxSize * 0.5f;
557       (*iter) = newPosition * scale;
558     }
559   }
560
561   /**
562    * Main key event handler
563    */
564   void OnKeyEvent(const KeyEvent& event)
565   {
566     if(event.GetState() == KeyEvent::DOWN)
567     {
568       if(IsKey(event, Dali::DALI_KEY_ESCAPE) || IsKey(event, Dali::DALI_KEY_BACK))
569       {
570         mApplication.Quit();
571       }
572     }
573   }
574
575 private:
576   Application& mApplication;
577   Layer        mContent;
578   TextureSet   mTextureSet;
579   Geometry     mGeometry;
580   Renderer     mRenderer;
581   Actor        mMeshActor;
582
583   Shader mShaderFlat;
584   Shader mShaderRefraction;
585
586   Animation mLightAnimation;
587   Animation mStrenghAnimation;
588
589   Property::Index mLightXYOffsetIndex;
590   Property::Index mSpinAngleIndex;
591   Property::Index mLightIntensityIndex;
592   Property::Index mEffectStrengthIndex;
593
594   Toolkit::PushButton mChangeTextureButton;
595   Toolkit::PushButton mChangeMeshButton;
596   unsigned int        mCurrentTextureId;
597   unsigned int        mCurrentMeshId;
598 };
599
600 /*****************************************************************************/
601
602 int DALI_EXPORT_API main(int argc, char** argv)
603 {
604   Application             app = Application::New(&argc, &argv, DEMO_THEME_PATH);
605   RefractionEffectExample theApp(app);
606   app.MainLoop();
607   return 0;
608 }