2 * Copyright (c) 2020 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>
22 #include "renderer-stencil-shaders.h"
23 #include "shared/view.h"
24 #include "shared/utility.h"
33 // Application constants:
34 const char * const APPLICATION_TITLE( "Renderer Stencil API Demo" );
35 const char * const BACKGROUND_IMAGE( DEMO_IMAGE_DIR "background-gradient.jpg" );
38 const char * const CUBE_TEXTURE( DEMO_IMAGE_DIR "people-medium-1.jpg" );
39 const char * const FLOOR_TEXTURE( DEMO_IMAGE_DIR "wood.png" );
41 // Scale dimensions: These values are relative to the window size. EG. width = 0.32f * windowSize.
42 const float CUBE_WIDTH_SCALE( 0.32f ); ///< The width (and height + depth) of the main and reflection cubes.
43 const Vector2 FLOOR_DIMENSION_SCALE( 0.67f, 0.017f ); ///< The width and height of the floor object.
45 // Configurable animation characteristics:
46 const float ANIMATION_ROTATION_DURATION( 10.0f ); ///< Time in seconds to rotate the scene 360 degrees around Y.
47 const float ANIMATION_BOUNCE_TOTAL_TIME( 1.6f ); ///< Time in seconds to perform 1 full bounce animation cycle.
48 const float ANIMATION_BOUNCE_DEFORMATION_TIME( 0.4f ); ///< Time in seconds that the cube deformation animation will occur for (on contact with the floor).
49 const float ANIMATION_BOUNCE_DEFORMATION_PERCENT( 20.0f ); ///< Percentage (of the cube's size) to deform the cube by (on contact with floor).
50 const float ANIMATION_BOUNCE_HEIGHT_PERCENT( 40.0f ); ///< Percentage (of the cube's size) to bounce up in to the air by.
52 // Base colors for the objects:
53 const Vector4 TEXT_COLOR( 1.0f, 1.0f, 1.0f, 1.0f ); ///< White.
54 const Vector4 CUBE_COLOR( 1.0f, 1.0f, 1.0f, 1.0f ); ///< White.
55 const Vector4 FLOOR_COLOR( 1.0f, 1.0f, 1.0f, 1.0f ); ///< White.
56 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 // We need to control the draw order as we are controlling both the stencil and depth buffer per renderer.
59 const int DEPTH_INDEX_GRANULARITY( 10000 ); ///< This value is the gap in depth-index in-between each renderer.
61 } // Anonymous namespace
64 * @brief This example shows how to manipulate stencil and depth buffer properties within the Renderer API.
66 class RendererStencilExample : public ConnectionTracker
72 * @param[in] application The DALi application object
74 RendererStencilExample( Application& application )
75 : mApplication( application )
77 // Connect to the Application's Init signal.
78 mApplication.InitSignal().Connect( this, &RendererStencilExample::Create );
82 * @brief Destructor (non-virtual).
84 ~RendererStencilExample()
91 * @brief Enum to facilitate more readable use of the cube array.
95 MAIN_CUBE, ///< The main cube that bounces above the floor object.
96 REFLECTION_CUBE ///< The reflected cube object.
100 * @brief Struct to store the position, normal and texture coordinates of a single vertex.
102 struct TexturedVertex
106 Vector2 textureCoord;
110 * @brief This is the main scene setup method for this demo.
111 * This is called via the Init signal which is received once (only) during the Application lifetime.
112 * @param[in] application The DALi application object
114 void Create( Application& application )
116 Window window = application.GetWindow();
118 // Use a gradient visual to render the background gradient.
119 Toolkit::Control background = Dali::Toolkit::Control::New();
120 background.SetProperty( Actor::Property::ANCHOR_POINT, Dali::AnchorPoint::CENTER );
121 background.SetProperty( Actor::Property::PARENT_ORIGIN, Dali::ParentOrigin::CENTER );
122 background.SetResizePolicy( Dali::ResizePolicy::FILL_TO_PARENT, Dali::Dimension::ALL_DIMENSIONS );
124 // Set up the background gradient.
125 Property::Array stopOffsets;
126 stopOffsets.PushBack( 0.0f );
127 stopOffsets.PushBack( 1.0f );
128 Property::Array stopColors;
129 stopColors.PushBack( Vector4( 0.17f, 0.24f, 0.35f, 1.0f ) ); // Dark, medium saturated blue ( top of screen)
130 stopColors.PushBack( Vector4( 0.45f, 0.70f, 0.80f, 1.0f ) ); // Medium bright, pastel blue (bottom of screen)
131 const float percentageWindowHeight = window.GetSize().GetHeight() * 0.7f;
133 background.SetProperty( Toolkit::Control::Property::BACKGROUND, Dali::Property::Map()
134 .Add( Toolkit::Visual::Property::TYPE, Dali::Toolkit::Visual::GRADIENT )
135 .Add( Toolkit::GradientVisual::Property::STOP_OFFSET, stopOffsets )
136 .Add( Toolkit::GradientVisual::Property::STOP_COLOR, stopColors )
137 .Add( Toolkit::GradientVisual::Property::START_POSITION, Vector2( 0.0f, -percentageWindowHeight ) )
138 .Add( Toolkit::GradientVisual::Property::END_POSITION, Vector2( 0.0f, percentageWindowHeight ) )
139 .Add( Toolkit::GradientVisual::Property::UNITS, Toolkit::GradientVisual::Units::USER_SPACE ) );
141 window.Add( background );
143 // Create a TextLabel for the application title.
144 Toolkit::TextLabel label = Toolkit::TextLabel::New( APPLICATION_TITLE );
145 label.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_CENTER );
146 // Set the parent origin to a small percentage below the top (so the demo will scale for different resolutions).
147 label.SetProperty( Actor::Property::PARENT_ORIGIN, Vector3( 0.5f, 0.03f, 0.5f ) );
148 label.SetProperty( Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER" );
149 label.SetProperty( Toolkit::TextLabel::Property::VERTICAL_ALIGNMENT, "CENTER" );
150 label.SetProperty( Toolkit::TextLabel::Property::TEXT_COLOR, TEXT_COLOR );
153 // Layer to hold the 3D scene.
154 Layer layer = Layer::New();
155 layer.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER );
156 // Set the parent origin to a small percentage below the center (so the demo will scale for different resolutions).
157 layer.SetProperty( Actor::Property::PARENT_ORIGIN, Vector3( 0.5f, 0.58f, 0.5f ) );
158 layer.SetProperty( Layer::Property::BEHAVIOR, Layer::LAYER_UI );
159 layer.SetProperty( Layer::Property::DEPTH_TEST, true );
163 // Make the demo scalable with different resolutions by basing
164 // the cube size on a percentage of the window size.
165 Vector2 windowSize = window.GetSize();
166 float scaleSize( std::min( windowSize.width, windowSize.height ) );
167 float cubeWidth( scaleSize * CUBE_WIDTH_SCALE );
168 Vector3 cubeSize( cubeWidth, cubeWidth, cubeWidth );
169 // Create the geometry for the cube, and the texture.
170 Geometry cubeGeometry = CreateCubeVertices( Vector3::ONE, false );
171 TextureSet cubeTextureSet = CreateTextureSet( CUBE_TEXTURE );
172 // Create the cube object and add it.
173 // Note: The cube is anchored around its base for animation purposes, so the position can be zero.
174 mCubes[ MAIN_CUBE ] = CreateMainCubeObject( cubeGeometry, cubeSize, cubeTextureSet );
175 layer.Add( mCubes[ MAIN_CUBE ] );
178 float floorWidth( scaleSize * FLOOR_DIMENSION_SCALE.x );
179 Vector3 floorSize( floorWidth, scaleSize * FLOOR_DIMENSION_SCALE.y, floorWidth );
180 // Create the floor object using the cube geometry with a new size, and add it.
181 Actor floorObject( CreateFloorObject( cubeGeometry, floorSize ) );
182 layer.Add( floorObject );
185 Vector3 planeSize( floorWidth, floorWidth, 0.0f );
186 // Create the stencil plane object, and add it.
187 Actor stencilPlaneObject( CreateStencilPlaneObject( planeSize ) );
188 layer.Add( stencilPlaneObject );
191 // Create the reflection cube object and add it.
192 // Note: The cube is anchored around its base for animation purposes, so the position can be zero.
193 mCubes[ REFLECTION_CUBE ] = CreateReflectionCubeObject( cubeSize, cubeTextureSet );
194 layer.Add( mCubes[ REFLECTION_CUBE ] );
196 // Rotate the layer so we can see some of the top of the cube for a more 3D effect.
197 layer.SetProperty( Actor::Property::ORIENTATION, Quaternion( Degree( -24.0f ), Degree( 0.0f ), Degree( 0.0f ) ) );
199 // Set up the rotation on the Y axis.
200 mRotationAnimation = Animation::New( ANIMATION_ROTATION_DURATION );
201 float fullRotation = 360.0f;
202 mRotationAnimation.AnimateBy( Property( mCubes[ MAIN_CUBE ], Actor::Property::ORIENTATION ),
203 Quaternion( Degree( 0.0f ), Degree( fullRotation ), Degree( 0.0f ) ) );
204 mRotationAnimation.AnimateBy( Property( floorObject, Actor::Property::ORIENTATION ),
205 Quaternion( Degree( 0.0f ), Degree( fullRotation ), Degree( 0.0f ) ) );
206 // Note the stencil is pre-rotated by 90 degrees on X, so we rotate relatively on its Z axis for an equivalent Y rotation.
207 mRotationAnimation.AnimateBy( Property( stencilPlaneObject, Actor::Property::ORIENTATION ),
208 Quaternion( Degree( 0.0f ), Degree( 0.0f ), Degree( fullRotation ) ) );
209 mRotationAnimation.AnimateBy( Property( mCubes[ REFLECTION_CUBE ], Actor::Property::ORIENTATION ),
210 Quaternion( Degree( 0.0f ), Degree( fullRotation ), Degree( 0.0f ) ) );
211 mRotationAnimation.SetLooping( true );
213 // Set up the cube bouncing animation.
214 float totalTime = ANIMATION_BOUNCE_TOTAL_TIME;
215 float deformationTime = ANIMATION_BOUNCE_DEFORMATION_TIME;
216 // Percentage based amounts allows the bounce and deformation to scale for different resolution screens.
217 float deformationAmount = ANIMATION_BOUNCE_DEFORMATION_PERCENT / 100.0f;
218 float heightChange = ( cubeSize.y * ANIMATION_BOUNCE_HEIGHT_PERCENT ) / 100.0f;
220 // Animation pre-calculations:
221 float halfTime = totalTime / 2.0f;
222 float halfDeformationTime = deformationTime / 2.0f;
224 // First position the cubes at the top of the animation cycle.
225 mCubes[ MAIN_CUBE ].SetProperty( Actor::Property::POSITION_Y, -heightChange );
226 mCubes[ REFLECTION_CUBE ].SetProperty( Actor::Property::POSITION_Y, heightChange );
228 mBounceAnimation = Animation::New( totalTime );
230 // The animations for the main and reflected cubes are almost identical, so we combine the code to do both.
231 for( int cube = 0; cube < 2; ++cube )
233 // If iterating on the reflection cube, adjust the heightChange variable so the below code can be reused.
236 heightChange = -heightChange;
239 // 1st TimePeriod: Start moving down with increasing speed, until it is time to distort the cube due to impact.
240 mBounceAnimation.AnimateBy( Property( mCubes[ cube ], Actor::Property::POSITION_Y ), heightChange, AlphaFunction::EASE_IN_SQUARE, TimePeriod( 0.0f, halfTime - halfDeformationTime ) );
242 // 2nd TimePeriod: The cube is touching the floor, start deforming it - then un-deform it again.
243 mBounceAnimation.AnimateBy( Property( mCubes[ cube ], Actor::Property::SCALE_X ), deformationAmount, AlphaFunction::BOUNCE, TimePeriod( halfTime - halfDeformationTime, deformationTime ) );
244 mBounceAnimation.AnimateBy( Property( mCubes[ cube ], Actor::Property::SCALE_Z ), deformationAmount, AlphaFunction::BOUNCE, TimePeriod( halfTime - halfDeformationTime, deformationTime ) );
245 mBounceAnimation.AnimateBy( Property( mCubes[ cube ], Actor::Property::SCALE_Y ), -deformationAmount, AlphaFunction::BOUNCE, TimePeriod( halfTime - halfDeformationTime, deformationTime ) );
247 // 3rd TimePeriod: Start moving up with decreasing speed, until at the apex of the animation.
248 mBounceAnimation.AnimateBy( Property( mCubes[ cube ], Actor::Property::POSITION_Y ), -heightChange, AlphaFunction::EASE_OUT_SQUARE, TimePeriod( halfTime + halfDeformationTime, halfTime - halfDeformationTime ) );
251 mBounceAnimation.SetLooping( true );
253 // Start the animations.
254 mRotationAnimation.Play();
255 mBounceAnimation.Play();
257 // Respond to a click anywhere on the window
258 window.GetRootLayer().TouchSignal().Connect( this, &RendererStencilExample::OnTouch );
259 // Connect signals to allow Back and Escape to exit.
260 window.KeyEventSignal().Connect( this, &RendererStencilExample::OnKeyEvent );
265 // Methods to setup each component of the 3D scene:
268 * @brief Creates the Main cube object.
269 * This creates the renderer from existing geometry (as the cubes geometry is shared).
270 * The texture is set and all relevant renderer properties are set-up.
271 * @param[in] geometry Pre-calculated cube geometry
272 * @param[in] size The desired cube size
273 * @param[in] textureSet A pre-existing TextureSet with a texture set up, to be applied to the cube
274 * @return An actor set-up containing the main cube object
276 Actor CreateMainCubeObject( Geometry& geometry, Vector3 size, TextureSet& textureSet )
278 Toolkit::Control container = Toolkit::Control::New();
279 container.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::BOTTOM_CENTER );
280 container.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::BOTTOM_CENTER );
281 container.SetProperty( Actor::Property::SIZE, Vector2( size ) );
282 container.SetResizePolicy( ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS );
284 // Create a renderer from the geometry and add the texture.
285 Renderer renderer = CreateRenderer( geometry, size, true, CUBE_COLOR );
286 renderer.SetTextures( textureSet );
288 // Setup the renderer properties:
289 // We are writing to the color buffer & culling back faces (no stencil is used for the main cube).
290 renderer.SetProperty( Renderer::Property::RENDER_MODE, RenderMode::COLOR );
291 renderer.SetProperty( Renderer::Property::FACE_CULLING_MODE, FaceCullingMode::BACK );
293 // We do need to write to the depth buffer as other objects need to appear underneath this cube.
294 renderer.SetProperty( Renderer::Property::DEPTH_WRITE_MODE, DepthWriteMode::ON );
295 // We do not need to test the depth buffer as we are culling the back faces.
296 renderer.SetProperty( Renderer::Property::DEPTH_TEST_MODE, DepthTestMode::OFF );
298 // This object must be rendered 1st.
299 renderer.SetProperty( Renderer::Property::DEPTH_INDEX, 0 * DEPTH_INDEX_GRANULARITY );
301 container.AddRenderer( renderer );
306 * @brief Creates the Floor object.
307 * This creates the renderer from existing geometry (as the cube geometry can be re-used).
308 * The texture is created and set and all relevant renderer properties are set-up.
309 * @param[in] geometry Pre-calculated cube geometry
310 * @param[in] size The desired floor size
311 * @return An actor set-up containing the floor object
313 Actor CreateFloorObject( Geometry& geometry, Vector3 size )
315 Toolkit::Control container = Toolkit::Control::New();
316 container.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_CENTER );
317 container.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_CENTER );
318 container.SetProperty( Actor::Property::SIZE, Vector2( size ) );
319 container.SetResizePolicy( ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS );
321 // Create a renderer from the geometry and add the texture.
322 TextureSet planeTextureSet = CreateTextureSet( FLOOR_TEXTURE );
323 Renderer renderer = CreateRenderer( geometry, size, true, FLOOR_COLOR );
324 renderer.SetTextures( planeTextureSet );
326 // Setup the renderer properties:
327 // We are writing to the color buffer & culling back faces as we are NOT doing depth write (no stencil is used for the floor).
328 renderer.SetProperty( Renderer::Property::RENDER_MODE, RenderMode::COLOR );
329 renderer.SetProperty( Renderer::Property::FACE_CULLING_MODE, FaceCullingMode::BACK );
331 // We do not write to the depth buffer as its not needed.
332 renderer.SetProperty( Renderer::Property::DEPTH_WRITE_MODE, DepthWriteMode::OFF );
333 // We do need to test the depth buffer as we need the floor to be underneath the cube.
334 renderer.SetProperty( Renderer::Property::DEPTH_TEST_MODE, DepthTestMode::ON );
336 // This object must be rendered 2nd.
337 renderer.SetProperty( Renderer::Property::DEPTH_INDEX, 1 * DEPTH_INDEX_GRANULARITY );
339 container.AddRenderer( renderer );
344 * @brief Creates the Stencil-Plane object.
345 * This is places on the floor object to allow the reflection to be drawn on to the floor.
346 * This creates the geometry and renderer.
347 * All relevant renderer properties are set-up.
348 * @param[in] size The desired plane size
349 * @return An actor set-up containing the stencil-plane object
351 Actor CreateStencilPlaneObject( Vector3 size )
353 Toolkit::Control container = Toolkit::Control::New();
354 container.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER );
355 container.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
356 container.SetProperty( Actor::Property::SIZE, Vector2( size ) );
357 container.SetResizePolicy( ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS );
359 // We rotate the plane as the geometry is created flat in X & Y. We want it to span X & Z axis.
360 container.SetProperty( Actor::Property::ORIENTATION, Quaternion( Degree( -90.0f ), Degree( 0.0f ), Degree( 0.0f ) ) );
362 // Create geometry for a flat plane.
363 Geometry planeGeometry = CreatePlaneVertices( Vector2::ONE );
364 // Create a renderer from the geometry.
365 Renderer renderer = CreateRenderer( planeGeometry, size, false, Vector4::ONE );
367 // Setup the renderer properties:
368 // The stencil plane is only for stencilling.
369 renderer.SetProperty( Renderer::Property::RENDER_MODE, RenderMode::STENCIL );
371 renderer.SetProperty( Renderer::Property::STENCIL_FUNCTION, StencilFunction::ALWAYS );
372 renderer.SetProperty( Renderer::Property::STENCIL_FUNCTION_REFERENCE, 1 );
373 renderer.SetProperty( Renderer::Property::STENCIL_FUNCTION_MASK, 0xFF );
374 renderer.SetProperty( Renderer::Property::STENCIL_OPERATION_ON_FAIL, StencilOperation::KEEP );
375 renderer.SetProperty( Renderer::Property::STENCIL_OPERATION_ON_Z_FAIL, StencilOperation::KEEP );
376 renderer.SetProperty( Renderer::Property::STENCIL_OPERATION_ON_Z_PASS, StencilOperation::REPLACE );
377 renderer.SetProperty( Renderer::Property::STENCIL_MASK, 0xFF );
379 // We don't want to write to the depth buffer, as this would block the reflection being drawn.
380 renderer.SetProperty( Renderer::Property::DEPTH_WRITE_MODE, DepthWriteMode::OFF );
381 // We test the depth buffer as we want the stencil to only exist underneath the cube.
382 renderer.SetProperty( Renderer::Property::DEPTH_TEST_MODE, DepthTestMode::ON );
384 // This object must be rendered 3rd.
385 renderer.SetProperty( Renderer::Property::DEPTH_INDEX, 2 * DEPTH_INDEX_GRANULARITY );
387 container.AddRenderer( renderer );
392 * @brief Creates the Reflection cube object.
393 * This creates new geometry (as the texture UVs are different to the main cube).
394 * The renderer is then created.
395 * The texture is set and all relevant renderer properties are set-up.
396 * @param[in] size The desired cube size
397 * @param[in] textureSet A pre-existing TextureSet with a texture set up, to be applied to the cube
398 * @return An actor set-up containing the reflection cube object
400 Actor CreateReflectionCubeObject( Vector3 size, TextureSet& textureSet )
402 Toolkit::Control container = Toolkit::Control::New();
403 container.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_CENTER );
404 container.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_CENTER );
405 container.SetProperty( Actor::Property::SIZE, Vector2( size ) );
406 container.SetResizePolicy( ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS );
408 // Create the cube geometry of unity size.
409 // The "true" specifies we want the texture UVs flipped vertically as this is the reflection cube.
410 Geometry reflectedCubeGeometry = CreateCubeVertices( Vector3::ONE, true );
411 // Create a renderer from the geometry and add the texture.
412 Renderer renderer = CreateRenderer( reflectedCubeGeometry, size, true, REFLECTION_COLOR );
413 renderer.SetTextures( textureSet );
415 // Setup the renderer properties:
416 // Write to color buffer so reflection is visible.
417 // Also enable the stencil buffer, as we will be testing against it to only draw to areas within the stencil.
418 renderer.SetProperty( Renderer::Property::RENDER_MODE, RenderMode::COLOR_STENCIL );
419 // We cull to skip drawing the back faces.
420 renderer.SetProperty( Renderer::Property::FACE_CULLING_MODE, FaceCullingMode::BACK );
422 // We use blending to blend the reflection with the floor texture.
423 renderer.SetProperty( Renderer::Property::BLEND_MODE, BlendMode::ON );
424 renderer.SetProperty( Renderer::Property::BLEND_EQUATION_RGB, BlendEquation::ADD );
425 renderer.SetProperty( Renderer::Property::BLEND_EQUATION_ALPHA, BlendEquation::ADD );
426 renderer.SetProperty( Renderer::Property::BLEND_FACTOR_DEST_RGB, BlendFactor::ONE );
428 // Enable stencil. Here we only draw to areas within the stencil.
429 renderer.SetProperty( Renderer::Property::STENCIL_FUNCTION, StencilFunction::EQUAL );
430 renderer.SetProperty( Renderer::Property::STENCIL_FUNCTION_REFERENCE, 1 );
431 renderer.SetProperty( Renderer::Property::STENCIL_FUNCTION_MASK, 0xff );
432 // Don't write to the stencil.
433 renderer.SetProperty( Renderer::Property::STENCIL_MASK, 0x00 );
435 // We don't need to write to the depth buffer, as we are culling.
436 renderer.SetProperty( Renderer::Property::DEPTH_WRITE_MODE, DepthWriteMode::OFF );
437 // We need to test the depth buffer as we need the reflection to be underneath the cube.
438 renderer.SetProperty( Renderer::Property::DEPTH_TEST_MODE, DepthTestMode::ON );
440 // This object must be rendered last.
441 renderer.SetProperty( Renderer::Property::DEPTH_INDEX, 3 * DEPTH_INDEX_GRANULARITY );
443 container.AddRenderer( renderer );
450 * @brief Creates a geometry object from vertices and indices.
451 * @param[in] vertices The object vertices
452 * @param[in] indices The object indices
453 * @return A geometry object
455 Geometry CreateTexturedGeometry( Vector<TexturedVertex>& vertices, Vector<unsigned short>& indices )
458 Property::Map vertexFormat;
459 vertexFormat[POSITION] = Property::VECTOR3;
460 vertexFormat[NORMAL] = Property::VECTOR3;
461 vertexFormat[TEXTURE] = Property::VECTOR2;
463 VertexBuffer surfaceVertices = VertexBuffer::New( vertexFormat );
464 surfaceVertices.SetData( &vertices[0u], vertices.Size() );
466 Geometry geometry = Geometry::New();
467 geometry.AddVertexBuffer( surfaceVertices );
469 // Indices for triangle formulation
470 geometry.SetIndexBuffer( &indices[0u], indices.Size() );
475 * @brief Creates a renderer from a geometry object.
476 * @param[in] geometry The geometry to use
477 * @param[in] dimensions The dimensions (will be passed in to the shader)
478 * @param[in] textured Set to true to use the texture versions of the shaders
479 * @param[in] color The base color for the renderer
480 * @return A renderer object
482 Renderer CreateRenderer( Geometry geometry, Vector3 dimensions, bool textured, Vector4 color )
484 Window window = mApplication.GetWindow();
485 Vector2 windowSize = window.GetSize();
490 shader = Shader::New( VERTEX_SHADER_TEXTURED, FRAGMENT_SHADER_TEXTURED );
494 shader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
497 // Here we modify the light position based on half the window size as a pre-calculation step.
498 // This avoids the work having to be done in the shader.
499 shader.RegisterProperty( LIGHT_POSITION_UNIFORM_NAME, Vector3( -windowSize.width / 2.0f, -windowSize.width / 2.0f, 1000.0f ) );
500 shader.RegisterProperty( COLOR_UNIFORM_NAME, color );
501 shader.RegisterProperty( OBJECT_DIMENSIONS_UNIFORM_NAME, dimensions );
503 return Renderer::New( geometry, shader );
507 * @brief Helper method to create a TextureSet from an image URL.
508 * @param[in] url An image URL
509 * @return A TextureSet object
511 TextureSet CreateTextureSet( const char* url )
513 TextureSet textureSet = TextureSet::New();
517 Texture texture = DemoHelper::LoadTexture( url );
520 textureSet.SetTexture( 0u, texture );
527 // Geometry Creation:
530 * @brief Creates a geometry object for a flat plane.
531 * The plane is oriented in X & Y axis (Z is 0).
532 * @param[in] dimensions The desired plane dimensions
533 * @return A Geometry object
535 Geometry CreatePlaneVertices( Vector2 dimensions )
537 Vector<TexturedVertex> vertices;
538 Vector<unsigned short> indices;
539 vertices.Resize( 4u );
540 indices.Resize( 6u );
542 float scaledX = 0.5f * dimensions.x;
543 float scaledY = 0.5f * dimensions.y;
545 vertices[0].position = Vector3( -scaledX, -scaledY, 0.0f );
546 vertices[0].textureCoord = Vector2( 0.0, 0.0f );
547 vertices[1].position = Vector3( scaledX, -scaledY, 0.0f );
548 vertices[1].textureCoord = Vector2( 1.0, 0.0f );
549 vertices[2].position = Vector3( scaledX, scaledY, 0.0f );
550 vertices[2].textureCoord = Vector2( 1.0, 1.0f );
551 vertices[3].position = Vector3( -scaledX, scaledY, 0.0f );
552 vertices[3].textureCoord = Vector2( 0.0, 1.0f );
554 // All vertices have the same normal.
555 for( int i = 0; i < 4; ++i )
557 vertices[i].normal = Vector3( 0.0f, 0.0f, -1.0f );
567 // Use the helper method to create the geometry object.
568 return CreateTexturedGeometry( vertices, indices );
572 * @brief Creates a geometry object for a cube (or cuboid).
573 * @param[in] dimensions The desired cube dimensions
574 * @param[in] reflectVerticalUVs Set to True to force the UVs to be vertically flipped
575 * @return A Geometry object
577 Geometry CreateCubeVertices( Vector3 dimensions, bool reflectVerticalUVs )
579 Vector<TexturedVertex> vertices;
580 Vector<unsigned short> indices;
581 int vertexIndex = 0u; // Tracks progress through vertices.
582 float scaledX = 0.5f * dimensions.x;
583 float scaledY = 0.5f * dimensions.y;
584 float scaledZ = 0.5f * dimensions.z;
585 float verticalTextureCoord = reflectVerticalUVs ? 0.0f : 1.0f;
587 vertices.Resize( 4u * 6u ); // 4 vertices x 6 faces
589 Vector<Vector3> positions; // Stores vertex positions, which are shared between vertexes at the same position but with a different normal.
590 positions.Resize( 8u );
591 Vector<Vector3> normals; // Stores normals, which are shared between vertexes of the same face.
592 normals.Resize( 6u );
594 positions[0] = Vector3( -scaledX, scaledY, -scaledZ );
595 positions[1] = Vector3( scaledX, scaledY, -scaledZ );
596 positions[2] = Vector3( scaledX, scaledY, scaledZ );
597 positions[3] = Vector3( -scaledX, scaledY, scaledZ );
598 positions[4] = Vector3( -scaledX, -scaledY, -scaledZ );
599 positions[5] = Vector3( scaledX, -scaledY, -scaledZ );
600 positions[6] = Vector3( scaledX, -scaledY, scaledZ );
601 positions[7] = Vector3( -scaledX, -scaledY, scaledZ );
603 normals[0] = Vector3( 0, 1, 0 );
604 normals[1] = Vector3( 0, 0, -1 );
605 normals[2] = Vector3( 1, 0, 0 );
606 normals[3] = Vector3( 0, 0, 1 );
607 normals[4] = Vector3( -1, 0, 0 );
608 normals[5] = Vector3( 0, -1, 0 );
610 // Top face, upward normals.
611 for( int i = 0; i < 4; ++i, ++vertexIndex )
613 vertices[vertexIndex].position = positions[i];
614 vertices[vertexIndex].normal = normals[0];
615 // The below logic forms the correct U/V pairs for a quad when "i" goes from 0 to 3.
616 vertices[vertexIndex].textureCoord = Vector2( ( i == 1 || i == 2 ) ? 1.0f : 0.0f, ( i == 2 || i == 3 ) ? 1.0f : 0.0f );
619 // Top face, outward normals.
620 for( int i = 0; i < 4; ++i, vertexIndex += 2 )
622 vertices[vertexIndex].position = positions[i];
623 vertices[vertexIndex].normal = normals[i + 1];
627 // End, so loop around.
628 vertices[vertexIndex + 1].position = positions[0];
632 vertices[vertexIndex + 1].position = positions[i + 1];
634 vertices[vertexIndex + 1].normal = normals[i + 1];
636 vertices[vertexIndex].textureCoord = Vector2( 0.0f, verticalTextureCoord );
637 vertices[vertexIndex+1].textureCoord = Vector2( 1.0f, verticalTextureCoord );
640 // Flip the vertical texture coord for the UV values of the bottom points.
641 verticalTextureCoord = 1.0f - verticalTextureCoord;
643 // Bottom face, outward normals.
644 for( int i = 0; i < 4; ++i, vertexIndex += 2 )
646 vertices[vertexIndex].position = positions[i + 4];
647 vertices[vertexIndex].normal = normals[i + 1];
651 // End, so loop around.
652 vertices[vertexIndex + 1].position = positions[4];
656 vertices[vertexIndex + 1].position = positions[i + 5];
658 vertices[vertexIndex + 1].normal = normals[i + 1];
660 vertices[vertexIndex].textureCoord = Vector2( 0.0f, verticalTextureCoord );
661 vertices[vertexIndex+1].textureCoord = Vector2( 1.0f, verticalTextureCoord );
664 // Bottom face, downward normals.
665 for( int i = 0; i < 4; ++i, ++vertexIndex )
667 // Reverse positions for bottom face to keep triangles clockwise (for culling).
668 vertices[vertexIndex].position = positions[ 7 - i ];
669 vertices[vertexIndex].normal = normals[5];
670 // The below logic forms the correct U/V pairs for a quad when "i" goes from 0 to 3.
671 vertices[vertexIndex].textureCoord = Vector2( ( i == 1 || i == 2 ) ? 1.0f : 0.0f, ( i == 2 || i == 3 ) ? 1.0f : 0.0f );
674 // Create cube indices.
675 int triangleIndex = 0u; //Track progress through indices.
676 indices.Resize( 3u * 12u ); // 3 points x 12 triangles.
679 indices[triangleIndex] = 0;
680 indices[triangleIndex + 1] = 1;
681 indices[triangleIndex + 2] = 2;
682 indices[triangleIndex + 3] = 2;
683 indices[triangleIndex + 4] = 3;
684 indices[triangleIndex + 5] = 0;
687 int topFaceStart = 4u;
688 int bottomFaceStart = topFaceStart + 8u;
691 for( int i = 0; i < 8; i += 2, triangleIndex += 6 )
693 indices[triangleIndex ] = i + topFaceStart;
694 indices[triangleIndex + 1] = i + bottomFaceStart + 1;
695 indices[triangleIndex + 2] = i + topFaceStart + 1;
696 indices[triangleIndex + 3] = i + topFaceStart;
697 indices[triangleIndex + 4] = i + bottomFaceStart;
698 indices[triangleIndex + 5] = i + bottomFaceStart + 1;
702 indices[triangleIndex] = 20;
703 indices[triangleIndex + 1] = 21;
704 indices[triangleIndex + 2] = 22;
705 indices[triangleIndex + 3] = 22;
706 indices[triangleIndex + 4] = 23;
707 indices[triangleIndex + 5] = 20;
709 // Use the helper method to create the geometry object.
710 return CreateTexturedGeometry( vertices, indices );
716 * @brief OnTouch signal handler.
717 * @param[in] actor The actor that has been touched
718 * @param[in] touch The touch information
719 * @return True if the event has been handled
721 bool OnTouch( Actor actor, const TouchEvent& touch )
723 // Quit the application.
729 * @brief OnKeyEvent signal handler.
730 * @param[in] event The key event information
732 void OnKeyEvent( const KeyEvent& event )
734 if( event.GetState() == KeyEvent::Down )
736 if ( IsKey( event, Dali::DALI_KEY_ESCAPE ) || IsKey( event, Dali::DALI_KEY_BACK ) )
747 Application& mApplication; ///< The DALi application object
748 Toolkit::Control mView; ///< The view used to show the background
750 Animation mRotationAnimation; ///< The animation to spin the cube & floor
751 Animation mBounceAnimation; ///< The animation to bounce the cube
752 Actor mCubes[2]; ///< The cube object containers
755 int DALI_EXPORT_API main( int argc, char **argv )
757 Application application = Application::New( &argc, &argv );
758 RendererStencilExample example( application );
759 application.MainLoop();