e16cc48f79bc27ad132c0c17894de62e1f172d2d
[platform/core/uifw/dali-demo.git] / examples / renderer-stencil / renderer-stencil-example.cpp
1 /*
2  * Copyright (c) 2016 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/devel-api/adaptor-framework/bitmap-loader.h>
21
22 // INTERNAL INCLUDES
23 #include "renderer-stencil-shaders.h"
24 #include "shared/view.h"
25 #include "shared/utility.h"
26
27 using namespace Dali;
28
29 namespace
30 {
31
32 // Constants:
33
34 // Application constants:
35 const char * const APPLICATION_TITLE( "Renderer Stencil API Demo" );
36 const char * const BACKGROUND_IMAGE( DEMO_IMAGE_DIR "background-gradient.jpg" );
37
38 // Texture filenames:
39 const char * const CUBE_TEXTURE( DEMO_IMAGE_DIR "people-medium-1.jpg" );
40 const char * const FLOOR_TEXTURE( DEMO_IMAGE_DIR "wood.png" );
41
42 // Scale dimensions: These values are relative to the stage size. EG. width = 0.32f * stageSize.
43 const float   CUBE_WIDTH_SCALE( 0.32f );                   ///< The width (and height + depth) of the main and reflection cubes.
44 const Vector2 FLOOR_DIMENSION_SCALE( 0.67f, 0.017f );      ///< The width and height of the floor object.
45
46 // Configurable animation characteristics:
47 const float ANIMATION_ROTATION_DURATION( 10.0f );          ///< Time in seconds to rotate the scene 360 degrees around Y.
48 const float ANIMATION_BOUNCE_TOTAL_TIME( 1.6f );           ///< Time in seconds to perform 1 full bounce animation cycle.
49 const float ANIMATION_BOUNCE_DEFORMATION_TIME( 0.4f );     ///< Time in seconds that the cube deformation animation will occur for (on contact with the floor).
50 const float ANIMATION_BOUNCE_DEFORMATION_PERCENT( 20.0f ); ///< Percentage (of the cube's size) to deform the cube by (on contact with floor).
51 const float ANIMATION_BOUNCE_HEIGHT_PERCENT( 40.0f );      ///< Percentage (of the cube's size) to bounce up in to the air by.
52
53 // Base colors for the objects:
54 const Vector4 TEXT_COLOR( 1.0f, 1.0f, 1.0f, 1.0f );        ///< White.
55 const Vector4 CUBE_COLOR( 1.0f, 1.0f, 1.0f, 1.0f );        ///< White.
56 const Vector4 FLOOR_COLOR( 1.0f, 1.0f, 1.0f, 1.0f );       ///< White.
57 const Vector4 REFLECTION_COLOR( 0.6f, 0.6f, 0.6f, 0.6f );  ///< Note that alpha is not 1.0f, to make the blend more photo-realistic.
58
59 // We need to control the draw order as we are controlling both the stencil and depth buffer per renderer.
60 const int DEPTH_INDEX_GRANULARITY( 10000 );                ///< This value is the gap in depth-index in-between each renderer.
61
62 } // Anonymous namespace
63
64 /**
65  * @brief This example shows how to manipulate stencil and depth buffer properties within the Renderer API.
66  */
67 class RendererStencilExample : public ConnectionTracker
68 {
69 public:
70
71   /**
72    * @brief Constructor.
73    * @param[in] application The DALi application object
74    */
75   RendererStencilExample( Application& application )
76   : mApplication( application )
77   {
78     // Connect to the Application's Init signal.
79     mApplication.InitSignal().Connect( this, &RendererStencilExample::Create );
80   }
81
82   /**
83    * @brief Destructor (non-virtual).
84    */
85   ~RendererStencilExample()
86   {
87   }
88
89 private:
90
91   /**
92    * @brief Enum to facilitate more readable use of the cube array.
93    */
94   enum CubeType
95   {
96     MAIN_CUBE,      ///< The main cube that bounces above the floor object.
97     REFLECTION_CUBE ///< The reflected cube object.
98   };
99
100   /**
101    * @brief Struct to store the position, normal and texture coordinates of a single vertex.
102    */
103   struct TexturedVertex
104   {
105     Vector3 position;
106     Vector3 normal;
107     Vector2 textureCoord;
108   };
109
110   /**
111    * @brief This is the main scene setup method for this demo.
112    * This is called via the Init signal which is received once (only) during the Application lifetime.
113    * @param[in] application The DALi application object
114    */
115   void Create( Application& application )
116   {
117     Stage stage = Stage::GetCurrent();
118
119     // Hide the indicator bar
120     application.GetWindow().ShowIndicator( Dali::Window::INVISIBLE );
121
122     // Use a gradient visual to render the background gradient.
123     Toolkit::Control background = Dali::Toolkit::Control::New();
124     background.SetAnchorPoint( Dali::AnchorPoint::CENTER );
125     background.SetParentOrigin( Dali::ParentOrigin::CENTER );
126     background.SetResizePolicy( Dali::ResizePolicy::FILL_TO_PARENT, Dali::Dimension::ALL_DIMENSIONS );
127
128     // Set up the background gradient.
129     Property::Array stopOffsets;
130     stopOffsets.PushBack( 0.0f );
131     stopOffsets.PushBack( 1.0f );
132     Property::Array stopColors;
133     stopColors.PushBack( Vector4( 0.17f, 0.24f, 0.35f, 1.0f ) ); // Dark, medium saturated blue  ( top   of screen)
134     stopColors.PushBack( Vector4( 0.45f, 0.70f, 0.80f, 1.0f ) ); // Medium bright, pastel blue   (bottom of screen)
135     const float percentageStageHeight = stage.GetSize().height * 0.7f;
136
137     background.SetProperty( Toolkit::Control::Property::BACKGROUND, Dali::Property::Map()
138       .Add( Toolkit::Visual::Property::TYPE, Dali::Toolkit::Visual::GRADIENT )
139       .Add( Toolkit::GradientVisual::Property::STOP_OFFSET, stopOffsets )
140       .Add( Toolkit::GradientVisual::Property::STOP_COLOR, stopColors )
141       .Add( Toolkit::GradientVisual::Property::START_POSITION, Vector2( 0.0f, -percentageStageHeight ) )
142       .Add( Toolkit::GradientVisual::Property::END_POSITION, Vector2( 0.0f, percentageStageHeight ) )
143       .Add( Toolkit::GradientVisual::Property::UNITS, Toolkit::GradientVisual::Units::USER_SPACE ) );
144
145     stage.Add( background );
146
147     // Create a TextLabel for the application title.
148     Toolkit::TextLabel label = Toolkit::TextLabel::New( APPLICATION_TITLE );
149     label.SetAnchorPoint( AnchorPoint::TOP_CENTER );
150     // Set the parent origin to a small percentage below the top (so the demo will scale for different resolutions).
151     label.SetParentOrigin( Vector3( 0.5f, 0.03f, 0.5f ) );
152     label.SetProperty( Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER" );
153     label.SetProperty( Toolkit::TextLabel::Property::VERTICAL_ALIGNMENT, "CENTER" );
154     label.SetProperty( Toolkit::TextLabel::Property::TEXT_COLOR, TEXT_COLOR );
155     stage.Add( label );
156
157     // Layer to hold the 3D scene.
158     Layer layer = Layer::New();
159     layer.SetAnchorPoint( AnchorPoint::CENTER );
160     // Set the parent origin to a small percentage below the center (so the demo will scale for different resolutions).
161     layer.SetParentOrigin( Vector3( 0.5f, 0.58f, 0.5f ) );
162     layer.SetBehavior( Layer::LAYER_2D );
163     layer.SetDepthTestDisabled( false );
164     stage.Add( layer );
165
166     // Main cube:
167     // Make the demo scalable with different resolutions by basing
168     // the cube size on a percentage of the stage size.
169     float scaleSize( std::min( stage.GetSize().width, stage.GetSize().height ) );
170     float cubeWidth( scaleSize * CUBE_WIDTH_SCALE );
171     Vector3 cubeSize( cubeWidth, cubeWidth, cubeWidth );
172     // Create the geometry for the cube, and the texture.
173     Geometry cubeGeometry = CreateCubeVertices( Vector3::ONE, false );
174     TextureSet cubeTextureSet = CreateTextureSet( CUBE_TEXTURE );
175     // Create the cube object and add it.
176     // Note: The cube is anchored around its base for animation purposes, so the position can be zero.
177     mCubes[ MAIN_CUBE ] = CreateMainCubeObject( cubeGeometry, cubeSize, cubeTextureSet );
178     layer.Add( mCubes[ MAIN_CUBE ] );
179
180     // Floor:
181     float floorWidth( scaleSize * FLOOR_DIMENSION_SCALE.x );
182     Vector3 floorSize( floorWidth, scaleSize * FLOOR_DIMENSION_SCALE.y, floorWidth );
183     // Create the floor object using the cube geometry with a new size, and add it.
184     Actor floorObject( CreateFloorObject( cubeGeometry, floorSize ) );
185     layer.Add( floorObject );
186
187     // Stencil:
188     Vector3 planeSize( floorWidth, floorWidth, 0.0f );
189     // Create the stencil plane object, and add it.
190     Actor stencilPlaneObject( CreateStencilPlaneObject( planeSize ) );
191     layer.Add( stencilPlaneObject );
192
193     // Reflection cube:
194     // Create the reflection cube object and add it.
195     // Note: The cube is anchored around its base for animation purposes, so the position can be zero.
196     mCubes[ REFLECTION_CUBE ] = CreateReflectionCubeObject( cubeSize, cubeTextureSet );
197     layer.Add( mCubes[ REFLECTION_CUBE ] );
198
199     // Rotate the layer so we can see some of the top of the cube for a more 3D effect.
200     layer.SetProperty( Actor::Property::ORIENTATION, Quaternion( Degree( -24.0f ), Degree( 0.0f ), Degree( 0.0f ) ) );
201
202     // Set up the rotation on the Y axis.
203     mRotationAnimation = Animation::New( ANIMATION_ROTATION_DURATION );
204     float fullRotation = 360.0f;
205     mRotationAnimation.AnimateBy( Property( mCubes[ MAIN_CUBE ], Actor::Property::ORIENTATION ),
206                                  Quaternion( Degree( 0.0f ), Degree( fullRotation ), Degree( 0.0f ) ) );
207     mRotationAnimation.AnimateBy( Property( floorObject, Actor::Property::ORIENTATION ),
208                                  Quaternion( Degree( 0.0f ), Degree( fullRotation ), Degree( 0.0f ) ) );
209     // Note the stencil is pre-rotated by 90 degrees on X, so we rotate relatively on its Z axis for an equivalent Y rotation.
210     mRotationAnimation.AnimateBy( Property( stencilPlaneObject, Actor::Property::ORIENTATION ),
211                                  Quaternion( Degree( 0.0f ), Degree( 0.0f ), Degree( fullRotation ) ) );
212     mRotationAnimation.AnimateBy( Property( mCubes[ REFLECTION_CUBE ], Actor::Property::ORIENTATION ),
213                                  Quaternion( Degree( 0.0f ), Degree( fullRotation ), Degree( 0.0f ) ) );
214     mRotationAnimation.SetLooping( true );
215
216     // Set up the cube bouncing animation.
217     float totalTime = ANIMATION_BOUNCE_TOTAL_TIME;
218     float deformationTime = ANIMATION_BOUNCE_DEFORMATION_TIME;
219     // Percentage based amounts allows the bounce and deformation to scale for different resolution screens.
220     float deformationAmount = ANIMATION_BOUNCE_DEFORMATION_PERCENT / 100.0f;
221     float heightChange = ( cubeSize.y * ANIMATION_BOUNCE_HEIGHT_PERCENT ) / 100.0f;
222
223     // Animation pre-calculations:
224     float halfTime = totalTime / 2.0f;
225     float halfDeformationTime = deformationTime / 2.0f;
226
227     // First position the cubes at the top of the animation cycle.
228     mCubes[ MAIN_CUBE ].SetProperty(       Actor::Property::POSITION_Y, -heightChange );
229     mCubes[ REFLECTION_CUBE ].SetProperty( Actor::Property::POSITION_Y,  heightChange );
230
231     mBounceAnimation = Animation::New( totalTime );
232
233     // The animations for the main and reflected cubes are almost identical, so we combine the code to do both.
234     for( int cube = 0; cube < 2; ++cube )
235     {
236       // If iterating on the reflection cube, adjust the heightChange variable so the below code can be reused.
237       if( cube == 1 )
238       {
239         heightChange = -heightChange;
240       }
241
242       // 1st TimePeriod: Start moving down with increasing speed, until it is time to distort the cube due to impact.
243       mBounceAnimation.AnimateBy( Property( mCubes[ cube ], Actor::Property::POSITION_Y ),  heightChange, AlphaFunction::EASE_IN_SQUARE, TimePeriod( 0.0f, halfTime - halfDeformationTime ) );
244
245       // 2nd TimePeriod: The cube is touching the floor, start deforming it - then un-deform it again.
246       mBounceAnimation.AnimateBy( Property( mCubes[ cube ], Actor::Property::SCALE_X ),  deformationAmount, AlphaFunction::BOUNCE, TimePeriod( halfTime - halfDeformationTime, deformationTime ) );
247       mBounceAnimation.AnimateBy( Property( mCubes[ cube ], Actor::Property::SCALE_Z ),  deformationAmount, AlphaFunction::BOUNCE, TimePeriod( halfTime - halfDeformationTime, deformationTime ) );
248       mBounceAnimation.AnimateBy( Property( mCubes[ cube ], Actor::Property::SCALE_Y ), -deformationAmount, AlphaFunction::BOUNCE, TimePeriod( halfTime - halfDeformationTime, deformationTime ) );
249
250       // 3rd TimePeriod: Start moving up with decreasing speed, until at the apex of the animation.
251       mBounceAnimation.AnimateBy( Property( mCubes[ cube ], Actor::Property::POSITION_Y ), -heightChange, AlphaFunction::EASE_OUT_SQUARE, TimePeriod( halfTime + halfDeformationTime, halfTime - halfDeformationTime ) );
252     }
253
254     mBounceAnimation.SetLooping( true );
255
256     // Start the animations.
257     mRotationAnimation.Play();
258     mBounceAnimation.Play();
259
260     // Respond to a click anywhere on the stage
261     stage.GetRootLayer().TouchSignal().Connect( this, &RendererStencilExample::OnTouch );
262     // Connect signals to allow Back and Escape to exit.
263     stage.KeyEventSignal().Connect( this, &RendererStencilExample::OnKeyEvent );
264   }
265
266 private:
267
268   // Methods to setup each component of the 3D scene:
269
270   /**
271    * @brief Creates the Main cube object.
272    * This creates the renderer from existing geometry (as the cubes geometry is shared).
273    * The texture is set and all relevant renderer properties are set-up.
274    * @param[in] geometry Pre-calculated cube geometry
275    * @param[in] size The desired cube size
276    * @param[in] textureSet A pre-existing TextureSet with a texture set up, to be applied to the cube
277    * @return An actor set-up containing the main cube object
278    */
279   Actor CreateMainCubeObject( Geometry& geometry, Vector3 size, TextureSet& textureSet )
280   {
281     Toolkit::Control container = Toolkit::Control::New();
282     container.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
283     container.SetParentOrigin( ParentOrigin::BOTTOM_CENTER );
284     container.SetSize( size );
285     container.SetResizePolicy( ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS );
286
287     // Create a renderer from the geometry and add the texture.
288     Renderer renderer = CreateRenderer( geometry, size, true, CUBE_COLOR );
289     renderer.SetTextures( textureSet );
290
291     // Setup the renderer properties:
292     // We are writing to the color buffer & culling back faces (no stencil is used for the main cube).
293     renderer.SetProperty( Renderer::Property::RENDER_MODE, RenderMode::COLOR );
294     renderer.SetProperty( Renderer::Property::FACE_CULLING_MODE, FaceCullingMode::BACK );
295
296     // We do need to write to the depth buffer as other objects need to appear underneath this cube.
297     renderer.SetProperty( Renderer::Property::DEPTH_WRITE_MODE, DepthWriteMode::ON );
298     // We do not need to test the depth buffer as we are culling the back faces.
299     renderer.SetProperty( Renderer::Property::DEPTH_TEST_MODE, DepthTestMode::OFF );
300
301     // This object must be rendered 1st.
302     renderer.SetProperty( Renderer::Property::DEPTH_INDEX, 0 * DEPTH_INDEX_GRANULARITY );
303
304     container.AddRenderer( renderer );
305     return container;
306   }
307
308   /**
309    * @brief Creates the Floor object.
310    * This creates the renderer from existing geometry (as the cube geometry can be re-used).
311    * The texture is created and set and all relevant renderer properties are set-up.
312    * @param[in] geometry Pre-calculated cube geometry
313    * @param[in] size The desired floor size
314    * @return An actor set-up containing the floor object
315    */
316   Actor CreateFloorObject( Geometry& geometry, Vector3 size )
317   {
318     Toolkit::Control container = Toolkit::Control::New();
319     container.SetAnchorPoint( AnchorPoint::TOP_CENTER );
320     container.SetParentOrigin( ParentOrigin::TOP_CENTER );
321     container.SetSize( size );
322     container.SetResizePolicy( ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS );
323
324     // Create a renderer from the geometry and add the texture.
325     TextureSet planeTextureSet = CreateTextureSet( FLOOR_TEXTURE );
326     Renderer renderer = CreateRenderer( geometry, size, true, FLOOR_COLOR );
327     renderer.SetTextures( planeTextureSet );
328
329     // Setup the renderer properties:
330     // We are writing to the color buffer & culling back faces as we are NOT doing depth write (no stencil is used for the floor).
331     renderer.SetProperty( Renderer::Property::RENDER_MODE, RenderMode::COLOR );
332     renderer.SetProperty( Renderer::Property::FACE_CULLING_MODE, FaceCullingMode::BACK );
333
334     // We do not write to the depth buffer as its not needed.
335     renderer.SetProperty( Renderer::Property::DEPTH_WRITE_MODE, DepthWriteMode::OFF );
336     // We do need to test the depth buffer as we need the floor to be underneath the cube.
337     renderer.SetProperty( Renderer::Property::DEPTH_TEST_MODE, DepthTestMode::ON );
338
339     // This object must be rendered 2nd.
340     renderer.SetProperty( Renderer::Property::DEPTH_INDEX, 1 * DEPTH_INDEX_GRANULARITY );
341
342     container.AddRenderer( renderer );
343     return container;
344   }
345
346   /**
347    * @brief Creates the Stencil-Plane object.
348    * This is places on the floor object to allow the reflection to be drawn on to the floor.
349    * This creates the geometry and renderer.
350    * All relevant renderer properties are set-up.
351    * @param[in] size The desired plane size
352    * @return An actor set-up containing the stencil-plane object
353    */
354   Actor CreateStencilPlaneObject( Vector3 size )
355   {
356     Toolkit::Control container = Toolkit::Control::New();
357     container.SetAnchorPoint( AnchorPoint::CENTER );
358     container.SetParentOrigin( ParentOrigin::CENTER );
359     container.SetSize( size );
360     container.SetResizePolicy( ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS );
361
362     // We rotate the plane as the geometry is created flat in X & Y. We want it to span X & Z axis.
363     container.SetProperty( Actor::Property::ORIENTATION, Quaternion( Degree( -90.0f ), Degree( 0.0f ), Degree( 0.0f ) ) );
364
365     // Create geometry for a flat plane.
366     Geometry planeGeometry = CreatePlaneVertices( Vector2::ONE );
367     // Create a renderer from the geometry.
368     Renderer renderer = CreateRenderer( planeGeometry, size, false, Vector4::ONE );
369
370     // Setup the renderer properties:
371     // The stencil plane is only for stencilling.
372     renderer.SetProperty( Renderer::Property::RENDER_MODE, RenderMode::STENCIL );
373
374     renderer.SetProperty( Renderer::Property::STENCIL_FUNCTION, StencilFunction::ALWAYS );
375     renderer.SetProperty( Renderer::Property::STENCIL_FUNCTION_REFERENCE, 1 );
376     renderer.SetProperty( Renderer::Property::STENCIL_FUNCTION_MASK, 0xFF );
377     renderer.SetProperty( Renderer::Property::STENCIL_OPERATION_ON_FAIL, StencilOperation::KEEP );
378     renderer.SetProperty( Renderer::Property::STENCIL_OPERATION_ON_Z_FAIL, StencilOperation::KEEP );
379     renderer.SetProperty( Renderer::Property::STENCIL_OPERATION_ON_Z_PASS, StencilOperation::REPLACE );
380     renderer.SetProperty( Renderer::Property::STENCIL_MASK, 0xFF );
381
382     // We don't want to write to the depth buffer, as this would block the reflection being drawn.
383     renderer.SetProperty( Renderer::Property::DEPTH_WRITE_MODE, DepthWriteMode::OFF );
384     // We test the depth buffer as we want the stencil to only exist underneath the cube.
385     renderer.SetProperty( Renderer::Property::DEPTH_TEST_MODE, DepthTestMode::ON );
386
387     // This object must be rendered 3rd.
388     renderer.SetProperty( Renderer::Property::DEPTH_INDEX, 2 * DEPTH_INDEX_GRANULARITY );
389
390     container.AddRenderer( renderer );
391     return container;
392   }
393
394   /**
395    * @brief Creates the Reflection cube object.
396    * This creates new geometry (as the texture UVs are different to the main cube).
397    * The renderer is then created.
398    * The texture is set and all relevant renderer properties are set-up.
399    * @param[in] size The desired cube size
400    * @param[in] textureSet A pre-existing TextureSet with a texture set up, to be applied to the cube
401    * @return An actor set-up containing the reflection cube object
402    */
403   Actor CreateReflectionCubeObject( Vector3 size, TextureSet& textureSet )
404   {
405     Toolkit::Control container = Toolkit::Control::New();
406     container.SetAnchorPoint( AnchorPoint::TOP_CENTER );
407     container.SetParentOrigin( ParentOrigin::TOP_CENTER );
408     container.SetSize( size );
409     container.SetResizePolicy( ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS );
410
411     // Create the cube geometry of unity size.
412     // The "true" specifies we want the texture UVs flipped vertically as this is the reflection cube.
413     Geometry reflectedCubeGeometry = CreateCubeVertices( Vector3::ONE, true );
414     // Create a renderer from the geometry and add the texture.
415     Renderer renderer = CreateRenderer( reflectedCubeGeometry, size, true, REFLECTION_COLOR );
416     renderer.SetTextures( textureSet );
417
418     // Setup the renderer properties:
419     // Write to color buffer so reflection is visible.
420     // Also enable the stencil buffer, as we will be testing against it to only draw to areas within the stencil.
421     renderer.SetProperty( Renderer::Property::RENDER_MODE, RenderMode::COLOR_STENCIL );
422     // We cull to skip drawing the back faces.
423     renderer.SetProperty( Renderer::Property::FACE_CULLING_MODE, FaceCullingMode::BACK );
424
425     // We use blending to blend the reflection with the floor texture.
426     renderer.SetProperty( Renderer::Property::BLEND_MODE, BlendMode::ON );
427     renderer.SetProperty( Renderer::Property::BLEND_EQUATION_RGB, BlendEquation::ADD );
428     renderer.SetProperty( Renderer::Property::BLEND_EQUATION_ALPHA, BlendEquation::ADD );
429     renderer.SetProperty( Renderer::Property::BLEND_FACTOR_DEST_RGB, BlendFactor::ONE );
430
431     // Enable stencil. Here we only draw to areas within the stencil.
432     renderer.SetProperty( Renderer::Property::STENCIL_FUNCTION, StencilFunction::EQUAL );
433     renderer.SetProperty( Renderer::Property::STENCIL_FUNCTION_REFERENCE, 1 );
434     renderer.SetProperty( Renderer::Property::STENCIL_FUNCTION_MASK, 0xff );
435     // Don't write to the stencil.
436     renderer.SetProperty( Renderer::Property::STENCIL_MASK, 0x00 );
437
438     // We don't need to write to the depth buffer, as we are culling.
439     renderer.SetProperty( Renderer::Property::DEPTH_WRITE_MODE, DepthWriteMode::OFF );
440     // We need to test the depth buffer as we need the reflection to be underneath the cube.
441     renderer.SetProperty( Renderer::Property::DEPTH_TEST_MODE, DepthTestMode::ON );
442
443     // This object must be rendered last.
444     renderer.SetProperty( Renderer::Property::DEPTH_INDEX, 3 * DEPTH_INDEX_GRANULARITY );
445
446     container.AddRenderer( renderer );
447     return container;
448   }
449
450   // Methods:
451
452   /**
453    * @brief Creates a geometry object from vertices and indices.
454    * @param[in] vertices The object vertices
455    * @param[in] indices The object indices
456    * @return A geometry object
457    */
458   Geometry CreateTexturedGeometry( Vector<TexturedVertex>& vertices, Vector<unsigned short>& indices )
459   {
460     // Vertices
461     Property::Map vertexFormat;
462     vertexFormat[POSITION] = Property::VECTOR3;
463     vertexFormat[NORMAL] =   Property::VECTOR3;
464     vertexFormat[TEXTURE] =  Property::VECTOR2;
465
466     PropertyBuffer surfaceVertices = PropertyBuffer::New( vertexFormat );
467     surfaceVertices.SetData( &vertices[0u], vertices.Size() );
468
469     Geometry geometry = Geometry::New();
470     geometry.AddVertexBuffer( surfaceVertices );
471
472     // Indices for triangle formulation
473     geometry.SetIndexBuffer( &indices[0u], indices.Size() );
474     return geometry;
475   }
476
477   /**
478    * @brief Creates a renderer from a geometry object.
479    * @param[in] geometry The geometry to use
480    * @param[in] dimensions The dimensions (will be passed in to the shader)
481    * @param[in] textured Set to true to use the texture versions of the shaders
482    * @param[in] color The base color for the renderer
483    * @return A renderer object
484    */
485   Renderer CreateRenderer( Geometry geometry, Vector3 dimensions, bool textured, Vector4 color )
486   {
487     Stage stage = Stage::GetCurrent();
488     Shader shader;
489
490     if( textured )
491     {
492       shader = Shader::New( VERTEX_SHADER_TEXTURED, FRAGMENT_SHADER_TEXTURED );
493     }
494     else
495     {
496       shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
497     }
498
499     // Here we modify the light position based on half the stage size as a pre-calculation step.
500     // This avoids the work having to be done in the shader.
501     shader.RegisterProperty( LIGHT_POSITION_UNIFORM_NAME, Vector3( -stage.GetSize().width / 2.0f, -stage.GetSize().width / 2.0f, 1000.0f ) );
502     shader.RegisterProperty( COLOR_UNIFORM_NAME, color );
503     shader.RegisterProperty( OBJECT_DIMENSIONS_UNIFORM_NAME, dimensions );
504
505     return Renderer::New( geometry, shader );
506   }
507
508   /**
509    * @brief Helper method to create a TextureSet from an image URL.
510    * @param[in] url An image URL
511    * @return A TextureSet object
512    */
513   TextureSet CreateTextureSet( const char* url )
514   {
515     TextureSet textureSet = TextureSet::New();
516
517     if( textureSet )
518     {
519       Texture texture = DemoHelper::LoadTexture( url );
520       if( texture )
521       {
522         textureSet.SetTexture( 0u, texture );
523       }
524     }
525
526     return textureSet;
527   }
528
529   // Geometry Creation:
530
531   /**
532    * @brief Creates a geometry object for a flat plane.
533    * The plane is oriented in X & Y axis (Z is 0).
534    * @param[in] dimensions The desired plane dimensions
535    * @return A Geometry object
536    */
537   Geometry CreatePlaneVertices( Vector2 dimensions )
538   {
539     Vector<TexturedVertex> vertices;
540     Vector<unsigned short> indices;
541     vertices.Resize( 4u );
542     indices.Resize( 6u );
543
544     float scaledX = 0.5f * dimensions.x;
545     float scaledY = 0.5f * dimensions.y;
546
547     vertices[0].position     = Vector3( -scaledX, -scaledY, 0.0f );
548     vertices[0].textureCoord = Vector2( 0.0, 0.0f );
549     vertices[1].position     = Vector3(  scaledX, -scaledY, 0.0f );
550     vertices[1].textureCoord = Vector2( 1.0, 0.0f );
551     vertices[2].position     = Vector3(  scaledX,  scaledY, 0.0f );
552     vertices[2].textureCoord = Vector2( 1.0, 1.0f );
553     vertices[3].position     = Vector3( -scaledX,  scaledY, 0.0f );
554     vertices[3].textureCoord = Vector2( 0.0, 1.0f );
555
556     // All vertices have the same normal.
557     for( int i = 0; i < 4; ++i )
558     {
559       vertices[i].normal = Vector3( 0.0f, 0.0f, -1.0f );
560     }
561
562     indices[0] = 0;
563     indices[1] = 1;
564     indices[2] = 2;
565     indices[3] = 2;
566     indices[4] = 3;
567     indices[5] = 0;
568
569     // Use the helper method to create the geometry object.
570     return CreateTexturedGeometry( vertices, indices );
571   }
572
573   /**
574    * @brief Creates a geometry object for a cube (or cuboid).
575    * @param[in] dimensions The desired cube dimensions
576    * @param[in] reflectVerticalUVs Set to True to force the UVs to be vertically flipped
577    * @return A Geometry object
578    */
579   Geometry CreateCubeVertices( Vector3 dimensions, bool reflectVerticalUVs )
580   {
581     Vector<TexturedVertex> vertices;
582     Vector<unsigned short> indices;
583     int vertexIndex = 0u; // Tracks progress through vertices.
584     float scaledX = 0.5f * dimensions.x;
585     float scaledY = 0.5f * dimensions.y;
586     float scaledZ = 0.5f * dimensions.z;
587     float verticalTextureCoord = reflectVerticalUVs ? 0.0f : 1.0f;
588
589     vertices.Resize( 4u * 6u ); // 4 vertices x 6 faces
590
591     Vector<Vector3> positions;  // Stores vertex positions, which are shared between vertexes at the same position but with a different normal.
592     positions.Resize( 8u );
593     Vector<Vector3> normals;    // Stores normals, which are shared between vertexes of the same face.
594     normals.Resize( 6u );
595
596     positions[0] = Vector3( -scaledX,  scaledY, -scaledZ );
597     positions[1] = Vector3(  scaledX,  scaledY, -scaledZ );
598     positions[2] = Vector3(  scaledX,  scaledY,  scaledZ );
599     positions[3] = Vector3( -scaledX,  scaledY,  scaledZ );
600     positions[4] = Vector3( -scaledX, -scaledY, -scaledZ );
601     positions[5] = Vector3(  scaledX, -scaledY, -scaledZ );
602     positions[6] = Vector3(  scaledX, -scaledY,  scaledZ );
603     positions[7] = Vector3( -scaledX, -scaledY,  scaledZ );
604
605     normals[0] = Vector3(  0,  1,  0 );
606     normals[1] = Vector3(  0,  0, -1 );
607     normals[2] = Vector3(  1,  0,  0 );
608     normals[3] = Vector3(  0,  0,  1 );
609     normals[4] = Vector3( -1,  0,  0 );
610     normals[5] = Vector3(  0, -1,  0 );
611
612     // Top face, upward normals.
613     for( int i = 0; i < 4; ++i, ++vertexIndex )
614     {
615       vertices[vertexIndex].position = positions[i];
616       vertices[vertexIndex].normal = normals[0];
617       // The below logic forms the correct U/V pairs for a quad when "i" goes from 0 to 3.
618       vertices[vertexIndex].textureCoord = Vector2( ( i == 1 || i == 2 ) ? 1.0f : 0.0f, ( i == 2 || i == 3 ) ? 1.0f : 0.0f );
619     }
620
621     // Top face, outward normals.
622     for( int i = 0; i < 4; ++i, vertexIndex += 2 )
623     {
624       vertices[vertexIndex].position = positions[i];
625       vertices[vertexIndex].normal = normals[i + 1];
626
627       if( i == 3 )
628       {
629         // End, so loop around.
630         vertices[vertexIndex + 1].position = positions[0];
631       }
632       else
633       {
634         vertices[vertexIndex + 1].position = positions[i + 1];
635       }
636       vertices[vertexIndex + 1].normal = normals[i + 1];
637
638       vertices[vertexIndex].textureCoord = Vector2( 0.0f, verticalTextureCoord );
639       vertices[vertexIndex+1].textureCoord = Vector2( 1.0f, verticalTextureCoord );
640     }
641
642     // Flip the vertical texture coord for the UV values of the bottom points.
643     verticalTextureCoord = 1.0f - verticalTextureCoord;
644
645     // Bottom face, outward normals.
646     for( int i = 0; i < 4; ++i, vertexIndex += 2 )
647     {
648       vertices[vertexIndex].position = positions[i + 4];
649       vertices[vertexIndex].normal = normals[i + 1];
650
651       if( i == 3 )
652       {
653         // End, so loop around.
654         vertices[vertexIndex + 1].position = positions[4];
655       }
656       else
657       {
658         vertices[vertexIndex + 1].position = positions[i + 5];
659       }
660       vertices[vertexIndex + 1].normal = normals[i + 1];
661
662       vertices[vertexIndex].textureCoord = Vector2( 0.0f, verticalTextureCoord );
663       vertices[vertexIndex+1].textureCoord = Vector2( 1.0f, verticalTextureCoord );
664     }
665
666     // Bottom face, downward normals.
667     for( int i = 0; i < 4; ++i, ++vertexIndex )
668     {
669       // Reverse positions for bottom face to keep triangles clockwise (for culling).
670       vertices[vertexIndex].position = positions[ 7 - i ];
671       vertices[vertexIndex].normal = normals[5];
672       // The below logic forms the correct U/V pairs for a quad when "i" goes from 0 to 3.
673       vertices[vertexIndex].textureCoord = Vector2( ( i == 1 || i == 2 ) ? 1.0f : 0.0f, ( i == 2 || i == 3 ) ? 1.0f : 0.0f );
674     }
675
676     // Create cube indices.
677     int triangleIndex = 0u;     //Track progress through indices.
678     indices.Resize( 3u * 12u ); // 3 points x 12 triangles.
679
680     // Top face.
681     indices[triangleIndex] =     0;
682     indices[triangleIndex + 1] = 1;
683     indices[triangleIndex + 2] = 2;
684     indices[triangleIndex + 3] = 2;
685     indices[triangleIndex + 4] = 3;
686     indices[triangleIndex + 5] = 0;
687     triangleIndex += 6;
688
689     int topFaceStart = 4u;
690     int bottomFaceStart = topFaceStart + 8u;
691
692     // Side faces.
693     for( int i = 0; i < 8; i += 2, triangleIndex += 6 )
694     {
695       indices[triangleIndex    ] = i + topFaceStart;
696       indices[triangleIndex + 1] = i + bottomFaceStart + 1;
697       indices[triangleIndex + 2] = i + topFaceStart + 1;
698       indices[triangleIndex + 3] = i + topFaceStart;
699       indices[triangleIndex + 4] = i + bottomFaceStart;
700       indices[triangleIndex + 5] = i + bottomFaceStart + 1;
701     }
702
703     // Bottom face.
704     indices[triangleIndex] =     20;
705     indices[triangleIndex + 1] = 21;
706     indices[triangleIndex + 2] = 22;
707     indices[triangleIndex + 3] = 22;
708     indices[triangleIndex + 4] = 23;
709     indices[triangleIndex + 5] = 20;
710
711     // Use the helper method to create the geometry object.
712     return CreateTexturedGeometry( vertices, indices );
713   }
714
715   // Signal handlers:
716
717   /**
718    * @brief OnTouch signal handler.
719    * @param[in] actor The actor that has been touched
720    * @param[in] touch The touch information
721    * @return True if the event has been handled
722    */
723   bool OnTouch( Actor actor, const TouchData& touch )
724   {
725     // Quit the application.
726     mApplication.Quit();
727     return true;
728   }
729
730   /**
731    * @brief OnKeyEvent signal handler.
732    * @param[in] event The key event information
733    */
734   void OnKeyEvent( const KeyEvent& event )
735   {
736     if( event.state == KeyEvent::Down )
737     {
738       if ( IsKey( event, Dali::DALI_KEY_ESCAPE ) || IsKey( event, Dali::DALI_KEY_BACK ) )
739       {
740         mApplication.Quit();
741       }
742     }
743   }
744
745 private:
746
747   // Member variables:
748
749   Application&     mApplication;       ///< The DALi application object
750   Toolkit::Control mView;              ///< The view used to show the background
751
752   Animation        mRotationAnimation; ///< The animation to spin the cube & floor
753   Animation        mBounceAnimation;   ///< The animation to bounce the cube
754   Actor            mCubes[2];          ///< The cube object containers
755 };
756
757
758 /**
759  * @brief Creates an instance of the example object and runs it.
760  * @param[in] application The DALi application object
761  */
762 void RunExample( Application& application )
763 {
764   RendererStencilExample example( application );
765
766   application.MainLoop();
767 }
768
769 /**
770  * @brief Entry point for Linux & Tizen applications
771  * @param[in] argc The executables argument count
772  * @param[in] argv The executables argument vector
773  * @return The executables exit code (0)
774  */
775 int DALI_EXPORT_API main( int argc, char **argv )
776 {
777   Application application = Application::New( &argc, &argv );
778
779   RunExample( application );
780
781   return 0;
782 }