2 * Copyright (c) 2016 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali-toolkit/dali-toolkit.h>
20 #include <dali/devel-api/adaptor-framework/bitmap-loader.h>
23 #include "renderer-stencil-shaders.h"
24 #include "shared/view.h"
25 #include "shared/utility.h"
34 // Application constants:
35 const char * const APPLICATION_TITLE( "Renderer Stencil API Demo" );
36 const char * const TOOLBAR_IMAGE( DEMO_IMAGE_DIR "top-bar.png" );
37 const char * const BACKGROUND_IMAGE( DEMO_IMAGE_DIR "background-gradient.jpg" );
40 const char * const CUBE_TEXTURE( DEMO_IMAGE_DIR "people-medium-1.jpg" );
41 const char * const FLOOR_TEXTURE( DEMO_IMAGE_DIR "wood.png" );
43 // Scale dimensions: These values are relative to the stage size. EG. width = 0.32f * stageSize.
44 const float CUBE_WIDTH_SCALE( 0.32f ); ///< The width (and height + depth) of the main and reflection cubes.
45 const Vector2 FLOOR_DIMENSION_SCALE( 0.67f, 0.017f ); ///< The width and height of the floor object.
47 // Configurable animation characteristics:
48 const float ANIMATION_ROTATION_DURATION( 10.0f ); ///< Time in seconds to rotate the scene 360 degrees around Y.
49 const float ANIMATION_BOUNCE_TOTAL_TIME( 1.6f ); ///< Time in seconds to perform 1 full bounce animation cycle.
50 const float ANIMATION_BOUNCE_DEFORMATION_TIME( 0.4f ); ///< Time in seconds that the cube deformation animation will occur for (on contact with the floor).
51 const float ANIMATION_BOUNCE_DEFORMATION_PERCENT( 20.0f ); ///< Percentage (of the cube's size) to deform the cube by (on contact with floor).
52 const float ANIMATION_BOUNCE_HEIGHT_PERCENT( 40.0f ); ///< Percentage (of the cube's size) to bounce up in to the air by.
54 // Base colors for the objects:
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.
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.
62 } // Anonymous namespace
65 * @brief This example shows how to manipulate stencil and depth buffer properties within the Renderer API.
67 class RendererStencilExample : public ConnectionTracker
73 * @param[in] application The DALi application object
75 RendererStencilExample( Application& application )
76 : mApplication( application )
78 // Connect to the Application's Init signal.
79 mApplication.InitSignal().Connect( this, &RendererStencilExample::Create );
83 * @brief Destructor (non-virtual).
85 ~RendererStencilExample()
92 * @brief Enum to facilitate more readable use of the cube array.
96 MAIN_CUBE, ///< The main cube that bounces above the floor object.
97 REFLECTION_CUBE ///< The reflected cube object.
101 * @brief Struct to store the position, normal and texture coordinates of a single vertex.
103 struct TexturedVertex
107 Vector2 textureCoord;
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
115 void Create( Application& application )
117 Stage stage = Stage::GetCurrent();
119 // Creates a default view with a default tool-bar.
120 // The view is added to the stage.
121 Toolkit::ToolBar toolBar;
122 Layer toolBarLayer = DemoHelper::CreateView( application, mView, toolBar, BACKGROUND_IMAGE, TOOLBAR_IMAGE, APPLICATION_TITLE );
123 stage.Add( toolBarLayer );
125 // Layer to hold the 3D scene.
126 Layer layer = Layer::New();
127 layer.SetAnchorPoint( AnchorPoint::CENTER );
128 // Set the parent origin to a small percentage below the center (so the demo will scale for different resolutions).
129 layer.SetParentOrigin( Vector3( 0.5f, 0.58f, 0.5f ) );
130 layer.SetBehavior( Layer::LAYER_2D );
131 layer.SetDepthTestDisabled( false );
135 // Make the demo scalable with different resolutions by basing
136 // the cube size on a percentage of the stage size.
137 float scaleSize( std::min( stage.GetSize().width, stage.GetSize().height ) );
138 float cubeWidth( scaleSize * CUBE_WIDTH_SCALE );
139 Vector3 cubeSize( cubeWidth, cubeWidth, cubeWidth );
140 // Create the geometry for the cube, and the texture.
141 Geometry cubeGeometry = CreateCubeVertices( Vector3::ONE, false );
142 TextureSet cubeTextureSet = CreateTextureSet( CUBE_TEXTURE );
143 // Create the cube object and add it.
144 // Note: The cube is anchored around its base for animation purposes, so the position can be zero.
145 mCubes[ MAIN_CUBE ] = CreateMainCubeObject( cubeGeometry, cubeSize, cubeTextureSet );
146 layer.Add( mCubes[ MAIN_CUBE ] );
149 float floorWidth( scaleSize * FLOOR_DIMENSION_SCALE.x );
150 Vector3 floorSize( floorWidth, scaleSize * FLOOR_DIMENSION_SCALE.y, floorWidth );
151 // Create the floor object using the cube geometry with a new size, and add it.
152 Actor floorObject( CreateFloorObject( cubeGeometry, floorSize ) );
153 layer.Add( floorObject );
156 Vector3 planeSize( floorWidth, floorWidth, 0.0f );
157 // Create the stencil plane object, and add it.
158 Actor stencilPlaneObject( CreateStencilPlaneObject( planeSize ) );
159 layer.Add( stencilPlaneObject );
162 // Create the reflection cube object and add it.
163 // Note: The cube is anchored around its base for animation purposes, so the position can be zero.
164 mCubes[ REFLECTION_CUBE ] = CreateReflectionCubeObject( cubeSize, cubeTextureSet );
165 layer.Add( mCubes[ REFLECTION_CUBE ] );
167 // Rotate the layer so we can see some of the top of the cube for a more 3D effect.
168 layer.SetProperty( Actor::Property::ORIENTATION, Quaternion( Degree( -24.0f ), Degree( 0.0f ), Degree( 0.0f ) ) );
170 // Set up the rotation on the Y axis.
171 mRotationAnimation = Animation::New( ANIMATION_ROTATION_DURATION );
172 float fullRotation = 360.0f;
173 mRotationAnimation.AnimateBy( Property( mCubes[ MAIN_CUBE ], Actor::Property::ORIENTATION ),
174 Quaternion( Degree( 0.0f ), Degree( fullRotation ), Degree( 0.0f ) ) );
175 mRotationAnimation.AnimateBy( Property( floorObject, Actor::Property::ORIENTATION ),
176 Quaternion( Degree( 0.0f ), Degree( fullRotation ), Degree( 0.0f ) ) );
177 // Note the stencil is pre-rotated by 90 degrees on X, so we rotate relatively on its Z axis for an equivalent Y rotation.
178 mRotationAnimation.AnimateBy( Property( stencilPlaneObject, Actor::Property::ORIENTATION ),
179 Quaternion( Degree( 0.0f ), Degree( 0.0f ), Degree( fullRotation ) ) );
180 mRotationAnimation.AnimateBy( Property( mCubes[ REFLECTION_CUBE ], Actor::Property::ORIENTATION ),
181 Quaternion( Degree( 0.0f ), Degree( fullRotation ), Degree( 0.0f ) ) );
182 mRotationAnimation.SetLooping( true );
184 // Set up the cube bouncing animation.
185 float totalTime = ANIMATION_BOUNCE_TOTAL_TIME;
186 float deformationTime = ANIMATION_BOUNCE_DEFORMATION_TIME;
187 // Percentage based amounts allows the bounce and deformation to scale for different resolution screens.
188 float deformationAmount = ANIMATION_BOUNCE_DEFORMATION_PERCENT / 100.0f;
189 float heightChange = ( cubeSize.y * ANIMATION_BOUNCE_HEIGHT_PERCENT ) / 100.0f;
191 // Animation pre-calculations:
192 float halfTime = totalTime / 2.0f;
193 float halfDeformationTime = deformationTime / 2.0f;
195 // First position the cubes at the top of the animation cycle.
196 mCubes[ MAIN_CUBE ].SetProperty( Actor::Property::POSITION_Y, -heightChange );
197 mCubes[ REFLECTION_CUBE ].SetProperty( Actor::Property::POSITION_Y, heightChange );
199 mBounceAnimation = Animation::New( totalTime );
201 // The animations for the main and reflected cubes are almost identical, so we combine the code to do both.
202 for( int cube = 0; cube < 2; ++cube )
204 // If iterating on the reflection cube, adjust the heightChange variable so the below code can be reused.
207 heightChange = -heightChange;
210 // 1st TimePeriod: Start moving down with increasing speed, until it is time to distort the cube due to impact.
211 mBounceAnimation.AnimateBy( Property( mCubes[ cube ], Actor::Property::POSITION_Y ), heightChange, AlphaFunction::EASE_IN_SQUARE, TimePeriod( 0.0f, halfTime - halfDeformationTime ) );
213 // 2nd TimePeriod: The cube is touching the floor, start deforming it - then un-deform it again.
214 mBounceAnimation.AnimateBy( Property( mCubes[ cube ], Actor::Property::SCALE_X ), deformationAmount, AlphaFunction::BOUNCE, TimePeriod( halfTime - halfDeformationTime, deformationTime ) );
215 mBounceAnimation.AnimateBy( Property( mCubes[ cube ], Actor::Property::SCALE_Z ), deformationAmount, AlphaFunction::BOUNCE, TimePeriod( halfTime - halfDeformationTime, deformationTime ) );
216 mBounceAnimation.AnimateBy( Property( mCubes[ cube ], Actor::Property::SCALE_Y ), -deformationAmount, AlphaFunction::BOUNCE, TimePeriod( halfTime - halfDeformationTime, deformationTime ) );
218 // 3rd TimePeriod: Start moving up with decreasing speed, until at the apex of the animation.
219 mBounceAnimation.AnimateBy( Property( mCubes[ cube ], Actor::Property::POSITION_Y ), -heightChange, AlphaFunction::EASE_OUT_SQUARE, TimePeriod( halfTime + halfDeformationTime, halfTime - halfDeformationTime ) );
222 mBounceAnimation.SetLooping( true );
224 // Start the animations.
225 mRotationAnimation.Play();
226 mBounceAnimation.Play();
228 // Respond to a click anywhere on the stage
229 stage.GetRootLayer().TouchSignal().Connect( this, &RendererStencilExample::OnTouch );
230 // Connect signals to allow Back and Escape to exit.
231 stage.KeyEventSignal().Connect( this, &RendererStencilExample::OnKeyEvent );
236 // Methods to setup each component of the 3D scene:
239 * @brief Creates the Main cube object.
240 * This creates the renderer from existing geometry (as the cubes geometry is shared).
241 * The texture is set and all relevant renderer properties are set-up.
242 * @param[in] geometry Pre-calculated cube geometry
243 * @param[in] size The desired cube size
244 * @param[in] textureSet A pre-existing TextureSet with a texture set up, to be applied to the cube
245 * @return An actor set-up containing the main cube object
247 Actor CreateMainCubeObject( Geometry& geometry, Vector3 size, TextureSet& textureSet )
249 Toolkit::Control container = Toolkit::Control::New();
250 container.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
251 container.SetParentOrigin( ParentOrigin::BOTTOM_CENTER );
252 container.SetSize( size );
253 container.SetResizePolicy( ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS );
255 // Create a renderer from the geometry and add the texture.
256 Renderer renderer = CreateRenderer( geometry, size, true, CUBE_COLOR );
257 renderer.SetTextures( textureSet );
259 // Setup the renderer properties:
260 // We are writing to the color buffer & culling back faces.
261 renderer.SetProperty( Renderer::Property::WRITE_TO_COLOR_BUFFER, true );
262 renderer.SetProperty( Renderer::Property::FACE_CULLING_MODE, FaceCullingMode::BACK );
264 // No stencil is used for the main cube.
265 renderer.SetProperty( Renderer::Property::STENCIL_MODE, StencilMode::OFF );
267 // We do need to write to the depth buffer as other objects need to appear underneath this cube.
268 renderer.SetProperty( Renderer::Property::DEPTH_WRITE_MODE, DepthWriteMode::ON );
269 // We do not need to test the depth buffer as we are culling the back faces.
270 renderer.SetProperty( Renderer::Property::DEPTH_TEST_MODE, DepthTestMode::OFF );
272 // This object must be rendered 1st.
273 renderer.SetProperty( Renderer::Property::DEPTH_INDEX, 0 * DEPTH_INDEX_GRANULARITY );
275 container.AddRenderer( renderer );
280 * @brief Creates the Floor object.
281 * This creates the renderer from existing geometry (as the cube geometry can be re-used).
282 * The texture is created and set and all relevant renderer properties are set-up.
283 * @param[in] geometry Pre-calculated cube geometry
284 * @param[in] size The desired floor size
285 * @return An actor set-up containing the floor object
287 Actor CreateFloorObject( Geometry& geometry, Vector3 size )
289 Toolkit::Control container = Toolkit::Control::New();
290 container.SetAnchorPoint( AnchorPoint::TOP_CENTER );
291 container.SetParentOrigin( ParentOrigin::TOP_CENTER );
292 container.SetSize( size );
293 container.SetResizePolicy( ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS );
295 // Create a renderer from the geometry and add the texture.
296 TextureSet planeTextureSet = CreateTextureSet( FLOOR_TEXTURE );
297 Renderer renderer = CreateRenderer( geometry, size, true, FLOOR_COLOR );
298 renderer.SetTextures( planeTextureSet );
300 // Setup the renderer properties:
301 // We are writing to the color buffer & culling back faces (as we are NOT doing depth write).
302 renderer.SetProperty( Renderer::Property::WRITE_TO_COLOR_BUFFER, true );
303 renderer.SetProperty( Renderer::Property::FACE_CULLING_MODE, FaceCullingMode::BACK );
305 // No stencil is used for the floor.
306 renderer.SetProperty( Renderer::Property::STENCIL_MODE, StencilMode::OFF );
308 // We do not write to the depth buffer as its not needed.
309 renderer.SetProperty( Renderer::Property::DEPTH_WRITE_MODE, DepthWriteMode::OFF );
310 // We do need to test the depth buffer as we need the floor to be underneath the cube.
311 renderer.SetProperty( Renderer::Property::DEPTH_TEST_MODE, DepthTestMode::ON );
313 // This object must be rendered 2nd.
314 renderer.SetProperty( Renderer::Property::DEPTH_INDEX, 1 * DEPTH_INDEX_GRANULARITY );
316 container.AddRenderer( renderer );
321 * @brief Creates the Stencil-Plane object.
322 * This is places on the floor object to allow the reflection to be drawn on to the floor.
323 * This creates the geometry and renderer.
324 * All relevant renderer properties are set-up.
325 * @param[in] size The desired plane size
326 * @return An actor set-up containing the stencil-plane object
328 Actor CreateStencilPlaneObject( Vector3 size )
330 Toolkit::Control container = Toolkit::Control::New();
331 container.SetAnchorPoint( AnchorPoint::CENTER );
332 container.SetParentOrigin( ParentOrigin::CENTER );
333 container.SetSize( size );
334 container.SetResizePolicy( ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS );
336 // We rotate the plane as the geometry is created flat in X & Y. We want it to span X & Z axis.
337 container.SetProperty( Actor::Property::ORIENTATION, Quaternion( Degree( -90.0f ), Degree( 0.0f ), Degree( 0.0f ) ) );
339 // Create geometry for a flat plane.
340 Geometry planeGeometry = CreatePlaneVertices( Vector2::ONE );
341 // Create a renderer from the geometry.
342 Renderer renderer = CreateRenderer( planeGeometry, size, false, Vector4::ONE );
344 // Setup the renderer properties:
345 // The stencil plane is only for stencilling, so disable writing to color buffer.
346 renderer.SetProperty( Renderer::Property::WRITE_TO_COLOR_BUFFER, false );
348 // Enable stencil. Draw to the stencil buffer (only).
349 renderer.SetProperty( Renderer::Property::STENCIL_MODE, StencilMode::ON );
350 renderer.SetProperty( Renderer::Property::STENCIL_FUNCTION, StencilFunction::ALWAYS );
351 renderer.SetProperty( Renderer::Property::STENCIL_FUNCTION_REFERENCE, 1 );
352 renderer.SetProperty( Renderer::Property::STENCIL_FUNCTION_MASK, 0xFF );
353 renderer.SetProperty( Renderer::Property::STENCIL_OPERATION_ON_FAIL, StencilOperation::KEEP );
354 renderer.SetProperty( Renderer::Property::STENCIL_OPERATION_ON_Z_FAIL, StencilOperation::KEEP );
355 renderer.SetProperty( Renderer::Property::STENCIL_OPERATION_ON_Z_PASS, StencilOperation::REPLACE );
356 renderer.SetProperty( Renderer::Property::STENCIL_MASK, 0xFF );
358 // We don't want to write to the depth buffer, as this would block the reflection being drawn.
359 renderer.SetProperty( Renderer::Property::DEPTH_WRITE_MODE, DepthWriteMode::OFF );
360 // We test the depth buffer as we want the stencil to only exist underneath the cube.
361 renderer.SetProperty( Renderer::Property::DEPTH_TEST_MODE, DepthTestMode::ON );
363 // This object must be rendered 3rd.
364 renderer.SetProperty( Renderer::Property::DEPTH_INDEX, 2 * DEPTH_INDEX_GRANULARITY );
366 container.AddRenderer( renderer );
371 * @brief Creates the Reflection cube object.
372 * This creates new geometry (as the texture UVs are different to the main cube).
373 * The renderer is then created.
374 * The texture is set and all relevant renderer properties are set-up.
375 * @param[in] size The desired cube size
376 * @param[in] textureSet A pre-existing TextureSet with a texture set up, to be applied to the cube
377 * @return An actor set-up containing the reflection cube object
379 Actor CreateReflectionCubeObject( Vector3 size, TextureSet& textureSet )
381 Toolkit::Control container = Toolkit::Control::New();
382 container.SetAnchorPoint( AnchorPoint::TOP_CENTER );
383 container.SetParentOrigin( ParentOrigin::TOP_CENTER );
384 container.SetSize( size );
385 container.SetResizePolicy( ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS );
387 // Create the cube geometry of unity size.
388 // The "true" specifies we want the texture UVs flipped vertically as this is the reflection cube.
389 Geometry reflectedCubeGeometry = CreateCubeVertices( Vector3::ONE, true );
390 // Create a renderer from the geometry and add the texture.
391 Renderer renderer = CreateRenderer( reflectedCubeGeometry, size, true, REFLECTION_COLOR );
392 renderer.SetTextures( textureSet );
394 // Setup the renderer properties:
395 // Write to color buffer so reflection is visible
396 renderer.SetProperty( Renderer::Property::WRITE_TO_COLOR_BUFFER, true );
397 // We cull to skip drawing the back faces.
398 renderer.SetProperty( Renderer::Property::FACE_CULLING_MODE, FaceCullingMode::BACK );
400 // We use blending to blend the reflection with the floor texture.
401 renderer.SetProperty( Renderer::Property::BLEND_MODE, BlendMode::ON );
402 renderer.SetProperty( Renderer::Property::BLEND_EQUATION_RGB, BlendEquation::ADD );
403 renderer.SetProperty( Renderer::Property::BLEND_EQUATION_ALPHA, BlendEquation::ADD );
404 renderer.SetProperty( Renderer::Property::BLEND_FACTOR_DEST_RGB, BlendFactor::ONE );
406 // Enable stencil. Here we only draw to areas within the stencil.
407 renderer.SetProperty( Renderer::Property::STENCIL_MODE, StencilMode::ON );
408 renderer.SetProperty( Renderer::Property::STENCIL_FUNCTION, StencilFunction::EQUAL );
409 renderer.SetProperty( Renderer::Property::STENCIL_FUNCTION_REFERENCE, 1 );
410 renderer.SetProperty( Renderer::Property::STENCIL_FUNCTION_MASK, 0xff );
411 // Don't write to the stencil.
412 renderer.SetProperty( Renderer::Property::STENCIL_MASK, 0x00 );
414 // We don't need to write to the depth buffer, as we are culling.
415 renderer.SetProperty( Renderer::Property::DEPTH_WRITE_MODE, DepthWriteMode::OFF );
416 // We need to test the depth buffer as we need the reflection to be underneath the cube.
417 renderer.SetProperty( Renderer::Property::DEPTH_TEST_MODE, DepthTestMode::ON );
419 // This object must be rendered last.
420 renderer.SetProperty( Renderer::Property::DEPTH_INDEX, 3 * DEPTH_INDEX_GRANULARITY );
422 container.AddRenderer( renderer );
429 * @brief Creates a geometry object from vertices and indices.
430 * @param[in] vertices The object vertices
431 * @param[in] indices The object indices
432 * @return A geometry object
434 Geometry CreateTexturedGeometry( Vector<TexturedVertex>& vertices, Vector<unsigned short>& indices )
437 Property::Map vertexFormat;
438 vertexFormat[POSITION] = Property::VECTOR3;
439 vertexFormat[NORMAL] = Property::VECTOR3;
440 vertexFormat[TEXTURE] = Property::VECTOR2;
442 PropertyBuffer surfaceVertices = PropertyBuffer::New( vertexFormat );
443 surfaceVertices.SetData( &vertices[0u], vertices.Size() );
445 Geometry geometry = Geometry::New();
446 geometry.AddVertexBuffer( surfaceVertices );
448 // Indices for triangle formulation
449 geometry.SetIndexBuffer( &indices[0u], indices.Size() );
454 * @brief Creates a renderer from a geometry object.
455 * @param[in] geometry The geometry to use
456 * @param[in] dimensions The dimensions (will be passed in to the shader)
457 * @param[in] textured Set to true to use the texture versions of the shaders
458 * @param[in] color The base color for the renderer
459 * @return A renderer object
461 Renderer CreateRenderer( Geometry geometry, Vector3 dimensions, bool textured, Vector4 color )
463 Stage stage = Stage::GetCurrent();
468 shader = Shader::New( VERTEX_SHADER_TEXTURED, FRAGMENT_SHADER_TEXTURED );
472 shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
475 // Here we modify the light position based on half the stage size as a pre-calculation step.
476 // This avoids the work having to be done in the shader.
477 shader.RegisterProperty( LIGHT_POSITION_UNIFORM_NAME, Vector3( -stage.GetSize().width / 2.0f, -stage.GetSize().width / 2.0f, 1000.0f ) );
478 shader.RegisterProperty( COLOR_UNIFORM_NAME, color );
479 shader.RegisterProperty( OBJECT_DIMENSIONS_UNIFORM_NAME, dimensions );
481 return Renderer::New( geometry, shader );
485 * @brief Helper method to create a TextureSet from an image URL.
486 * @param[in] url An image URL
487 * @return A TextureSet object
489 TextureSet CreateTextureSet( const char* url )
491 TextureSet textureSet = TextureSet::New();
495 Texture texture = DemoHelper::LoadTexture( url );
498 textureSet.SetTexture( 0u, texture );
505 // Geometry Creation:
508 * @brief Creates a geometry object for a flat plane.
509 * The plane is oriented in X & Y axis (Z is 0).
510 * @param[in] dimensions The desired plane dimensions
511 * @return A Geometry object
513 Geometry CreatePlaneVertices( Vector2 dimensions )
515 Vector<TexturedVertex> vertices;
516 Vector<unsigned short> indices;
517 vertices.Resize( 4u );
518 indices.Resize( 6u );
520 float scaledX = 0.5f * dimensions.x;
521 float scaledY = 0.5f * dimensions.y;
523 vertices[0].position = Vector3( -scaledX, -scaledY, 0.0f );
524 vertices[0].textureCoord = Vector2( 0.0, 0.0f );
525 vertices[1].position = Vector3( scaledX, -scaledY, 0.0f );
526 vertices[1].textureCoord = Vector2( 1.0, 0.0f );
527 vertices[2].position = Vector3( scaledX, scaledY, 0.0f );
528 vertices[2].textureCoord = Vector2( 1.0, 1.0f );
529 vertices[3].position = Vector3( -scaledX, scaledY, 0.0f );
530 vertices[3].textureCoord = Vector2( 0.0, 1.0f );
532 // All vertices have the same normal.
533 for( int i = 0; i < 4; ++i )
535 vertices[i].normal = Vector3( 0.0f, 0.0f, -1.0f );
545 // Use the helper method to create the geometry object.
546 return CreateTexturedGeometry( vertices, indices );
550 * @brief Creates a geometry object for a cube (or cuboid).
551 * @param[in] dimensions The desired cube dimensions
552 * @param[in] reflectVerticalUVs Set to True to force the UVs to be vertically flipped
553 * @return A Geometry object
555 Geometry CreateCubeVertices( Vector3 dimensions, bool reflectVerticalUVs )
557 Vector<TexturedVertex> vertices;
558 Vector<unsigned short> indices;
559 int vertexIndex = 0u; // Tracks progress through vertices.
560 float scaledX = 0.5f * dimensions.x;
561 float scaledY = 0.5f * dimensions.y;
562 float scaledZ = 0.5f * dimensions.z;
563 float verticalTextureCoord = reflectVerticalUVs ? 0.0f : 1.0f;
565 vertices.Resize( 4u * 6u ); // 4 vertices x 6 faces
567 Vector<Vector3> positions; // Stores vertex positions, which are shared between vertexes at the same position but with a different normal.
568 positions.Resize( 8u );
569 Vector<Vector3> normals; // Stores normals, which are shared between vertexes of the same face.
570 normals.Resize( 6u );
572 positions[0] = Vector3( -scaledX, scaledY, -scaledZ );
573 positions[1] = Vector3( scaledX, scaledY, -scaledZ );
574 positions[2] = Vector3( scaledX, scaledY, scaledZ );
575 positions[3] = Vector3( -scaledX, scaledY, scaledZ );
576 positions[4] = Vector3( -scaledX, -scaledY, -scaledZ );
577 positions[5] = Vector3( scaledX, -scaledY, -scaledZ );
578 positions[6] = Vector3( scaledX, -scaledY, scaledZ );
579 positions[7] = Vector3( -scaledX, -scaledY, scaledZ );
581 normals[0] = Vector3( 0, 1, 0 );
582 normals[1] = Vector3( 0, 0, -1 );
583 normals[2] = Vector3( 1, 0, 0 );
584 normals[3] = Vector3( 0, 0, 1 );
585 normals[4] = Vector3( -1, 0, 0 );
586 normals[5] = Vector3( 0, -1, 0 );
588 // Top face, upward normals.
589 for( int i = 0; i < 4; ++i, ++vertexIndex )
591 vertices[vertexIndex].position = positions[i];
592 vertices[vertexIndex].normal = normals[0];
593 // The below logic forms the correct U/V pairs for a quad when "i" goes from 0 to 3.
594 vertices[vertexIndex].textureCoord = Vector2( ( i == 1 || i == 2 ) ? 1.0f : 0.0f, ( i == 2 || i == 3 ) ? 1.0f : 0.0f );
597 // Top face, outward normals.
598 for( int i = 0; i < 4; ++i, vertexIndex += 2 )
600 vertices[vertexIndex].position = positions[i];
601 vertices[vertexIndex].normal = normals[i + 1];
605 // End, so loop around.
606 vertices[vertexIndex + 1].position = positions[0];
610 vertices[vertexIndex + 1].position = positions[i + 1];
612 vertices[vertexIndex + 1].normal = normals[i + 1];
614 vertices[vertexIndex].textureCoord = Vector2( 0.0f, verticalTextureCoord );
615 vertices[vertexIndex+1].textureCoord = Vector2( 1.0f, verticalTextureCoord );
618 // Flip the vertical texture coord for the UV values of the bottom points.
619 verticalTextureCoord = 1.0f - verticalTextureCoord;
621 // Bottom face, outward normals.
622 for( int i = 0; i < 4; ++i, vertexIndex += 2 )
624 vertices[vertexIndex].position = positions[i + 4];
625 vertices[vertexIndex].normal = normals[i + 1];
629 // End, so loop around.
630 vertices[vertexIndex + 1].position = positions[4];
634 vertices[vertexIndex + 1].position = positions[i + 5];
636 vertices[vertexIndex + 1].normal = normals[i + 1];
638 vertices[vertexIndex].textureCoord = Vector2( 0.0f, verticalTextureCoord );
639 vertices[vertexIndex+1].textureCoord = Vector2( 1.0f, verticalTextureCoord );
642 // Bottom face, downward normals.
643 for( int i = 0; i < 4; ++i, ++vertexIndex )
645 // Reverse positions for bottom face to keep triangles clockwise (for culling).
646 vertices[vertexIndex].position = positions[ 7 - i ];
647 vertices[vertexIndex].normal = normals[5];
648 // The below logic forms the correct U/V pairs for a quad when "i" goes from 0 to 3.
649 vertices[vertexIndex].textureCoord = Vector2( ( i == 1 || i == 2 ) ? 1.0f : 0.0f, ( i == 2 || i == 3 ) ? 1.0f : 0.0f );
652 // Create cube indices.
653 int triangleIndex = 0u; //Track progress through indices.
654 indices.Resize( 3u * 12u ); // 3 points x 12 triangles.
657 indices[triangleIndex] = 0;
658 indices[triangleIndex + 1] = 1;
659 indices[triangleIndex + 2] = 2;
660 indices[triangleIndex + 3] = 2;
661 indices[triangleIndex + 4] = 3;
662 indices[triangleIndex + 5] = 0;
665 int topFaceStart = 4u;
666 int bottomFaceStart = topFaceStart + 8u;
669 for( int i = 0; i < 8; i += 2, triangleIndex += 6 )
671 indices[triangleIndex ] = i + topFaceStart;
672 indices[triangleIndex + 1] = i + bottomFaceStart + 1;
673 indices[triangleIndex + 2] = i + topFaceStart + 1;
674 indices[triangleIndex + 3] = i + topFaceStart;
675 indices[triangleIndex + 4] = i + bottomFaceStart;
676 indices[triangleIndex + 5] = i + bottomFaceStart + 1;
680 indices[triangleIndex] = 20;
681 indices[triangleIndex + 1] = 21;
682 indices[triangleIndex + 2] = 22;
683 indices[triangleIndex + 3] = 22;
684 indices[triangleIndex + 4] = 23;
685 indices[triangleIndex + 5] = 20;
687 // Use the helper method to create the geometry object.
688 return CreateTexturedGeometry( vertices, indices );
694 * @brief OnTouch signal handler.
695 * @param[in] actor The actor that has been touched
696 * @param[in] touch The touch information
697 * @return True if the event has been handled
699 bool OnTouch( Actor actor, const TouchData& touch )
701 // Quit the application.
707 * @brief OnKeyEvent signal handler.
708 * @param[in] event The key event information
710 void OnKeyEvent( const KeyEvent& event )
712 if( event.state == KeyEvent::Down )
714 if ( IsKey( event, Dali::DALI_KEY_ESCAPE ) || IsKey( event, Dali::DALI_KEY_BACK ) )
725 Application& mApplication; ///< The DALi application object
726 Toolkit::Control mView; ///< The view used to show the background
728 Animation mRotationAnimation; ///< The animation to spin the cube & floor
729 Animation mBounceAnimation; ///< The animation to bounce the cube
730 Actor mCubes[2]; ///< The cube object containers
735 * @brief Creates an instance of the example object and runs it.
736 * @param[in] application The DALi application object
738 void RunExample( Application& application )
740 RendererStencilExample example( application );
742 application.MainLoop();
746 * @brief Entry point for Linux & Tizen applications
747 * @param[in] argc The executables argument count
748 * @param[in] argv The executables argument vector
749 * @return The executables exit code (0)
751 int DALI_EXPORT_API main( int argc, char **argv )
753 Application application = Application::New( &argc, &argv );
755 RunExample( application );