Create Renderer when the Visual is created
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / primitive / primitive-visual.cpp
1 /*
2  * Copyright (c) 2021 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 // CLASS HEADER
19 #include "primitive-visual.h"
20
21 // EXTERNAL INCLUDES
22 #include <dali/integration-api/debug.h>
23 #include <dali/devel-api/common/stage.h>
24 #include <dali/public-api/common/constants.h>
25 #include <dali/devel-api/scripting/enum-helper.h>
26 #include <dali/devel-api/scripting/scripting.h>
27
28 // INTERNAL INCLUDES
29 #include <dali-toolkit/public-api/visuals/visual-properties.h>
30 #include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
31 #include <dali-toolkit/internal/visuals/visual-string-constants.h>
32 #include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
33
34 namespace Dali
35 {
36
37 namespace Toolkit
38 {
39
40 namespace Internal
41 {
42
43 namespace
44 {
45
46 // shapes
47 DALI_ENUM_TO_STRING_TABLE_BEGIN( SHAPE_TYPE )
48 DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::PrimitiveVisual::Shape, SPHERE )
49 DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::PrimitiveVisual::Shape, CONE )
50 DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::PrimitiveVisual::Shape, CYLINDER )
51 DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::PrimitiveVisual::Shape, CUBE )
52 DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::PrimitiveVisual::Shape, OCTAHEDRON )
53 DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::PrimitiveVisual::Shape, BEVELLED_CUBE )
54 DALI_ENUM_TO_STRING_WITH_SCOPE( Toolkit::PrimitiveVisual::Shape, CONICAL_FRUSTUM )
55 DALI_ENUM_TO_STRING_TABLE_END( SHAPE_TYPE )
56
57 //Primitive property defaults
58 const int     DEFAULT_SLICES =              128; ///< For spheres and conics
59 const int     DEFAULT_STACKS =              128; ///< For spheres and conics
60 const float   DEFAULT_SCALE_TOP_RADIUS =    1.0; ///< For conical frustums
61 const float   DEFAULT_SCALE_BOTTOM_RADIUS = 1.5; ///< For cones and conical frustums
62 const float   DEFAULT_SCALE_HEIGHT =        3.0; ///< For all conics
63 const float   DEFAULT_SCALE_RADIUS =        1.0; ///< For cylinders
64 const float   DEFAULT_BEVEL_PERCENTAGE =    0.0; ///< For bevelled cubes
65 const float   DEFAULT_BEVEL_SMOOTHNESS =    0.0; ///< For bevelled cubes
66 const Vector4 DEFAULT_COLOR =               Vector4( 0.5, 0.5, 0.5, 1.0 ); ///< Grey, for all.
67
68 //Property limits
69 const int   MIN_SLICES =           3;   ///< Minimum number of slices for spheres and conics
70 const int   MIN_STACKS =           2;   ///< Minimum number of stacks for spheres and conics
71 const int   MAX_PARTITIONS =       255; ///< Maximum number of slices or stacks for spheres and conics
72 const float MIN_BEVEL_PERCENTAGE = 0.0; ///< Minimum bevel percentage for bevelled cubes
73 const float MAX_BEVEL_PERCENTAGE = 1.0; ///< Maximum bevel percentage for bevelled cubes
74 const float MIN_SMOOTHNESS =       0.0; ///< Minimum bevel smoothness for bevelled cubes
75 const float MAX_SMOOTHNESS =       1.0; ///< Maximum bevel smoothness for bevelled cubes
76
77 //Specific shape labels.
78 const char * const SPHERE_LABEL( "SPHERE" );
79 const char * const CONE_LABEL( "CONE" );
80 const char * const CYLINDER_LABEL( "CYLINDER" );
81 const char * const CUBE_LABEL( "CUBE" );
82 const char * const OCTAHEDRON_LABEL( "OCTAHEDRON" );
83 const char * const BEVELLED_CUBE_LABEL( "BEVELLED_CUBE" );
84 const char * const CONICAL_FRUSTUM_LABEL( "CONICAL_FRUSTUM" );
85
86 //Shader properties
87 const char * const OBJECT_MATRIX_UNIFORM_NAME( "uObjectMatrix" );
88 const char * const OBJECT_DIMENSIONS_UNIFORM_NAME( "uObjectDimensions" );
89 const char * const STAGE_OFFSET_UNIFORM_NAME( "uStageOffset" );
90
91 //Vertex properties
92 const char * const POSITION( "aPosition");
93 const char * const NORMAL( "aNormal" );
94 const char * const INDICES( "aIndices" );
95
96 } // unnamed namespace
97
98 PrimitiveVisualPtr PrimitiveVisual::New( VisualFactoryCache& factoryCache, const Property::Map& properties )
99 {
100   PrimitiveVisualPtr primitiveVisualPtr( new PrimitiveVisual( factoryCache ) );
101   primitiveVisualPtr->SetProperties( properties );
102   primitiveVisualPtr->Initialize();
103   return primitiveVisualPtr;
104 }
105
106 PrimitiveVisual::PrimitiveVisual( VisualFactoryCache& factoryCache )
107 : Visual::Base( factoryCache, Visual::FittingMode::FIT_KEEP_ASPECT_RATIO, Toolkit::Visual::PRIMITIVE ),
108   mScaleDimensions( Vector3::ONE ),
109   mScaleTopRadius( DEFAULT_SCALE_TOP_RADIUS ),
110   mScaleBottomRadius( DEFAULT_SCALE_BOTTOM_RADIUS ),
111   mScaleHeight( DEFAULT_SCALE_HEIGHT ),
112   mScaleRadius( DEFAULT_SCALE_RADIUS ),
113   mBevelPercentage( DEFAULT_BEVEL_PERCENTAGE ),
114   mBevelSmoothness( DEFAULT_BEVEL_SMOOTHNESS ),
115   mSlices( DEFAULT_SLICES ),
116   mStacks( DEFAULT_STACKS ),
117   mPrimitiveType( Toolkit::PrimitiveVisual::Shape::SPHERE )
118 {
119   mImpl->mMixColor = DEFAULT_COLOR;
120 }
121
122 PrimitiveVisual::~PrimitiveVisual()
123 {
124 }
125
126 void PrimitiveVisual::DoSetProperties( const Property::Map& propertyMap )
127 {
128   //Find out which shape to renderer.
129   Property::Value* primitiveTypeValue = propertyMap.Find( Toolkit::PrimitiveVisual::Property::SHAPE, PRIMITIVE_SHAPE );
130   if( primitiveTypeValue )
131   {
132     Scripting::GetEnumerationProperty( *primitiveTypeValue, SHAPE_TYPE_TABLE, SHAPE_TYPE_TABLE_COUNT, mPrimitiveType );
133   }
134   else
135   {
136     DALI_LOG_ERROR( "Fail to provide shape to the PrimitiveVisual object.\n" );
137   }
138
139   // By virtue of DoSetProperties being called last, this will override
140   // anything set by Toolkit::Visual::Property::MIX_COLOR
141   Property::Value* colorValue = propertyMap.Find( Toolkit::PrimitiveVisual::Property::MIX_COLOR, MIX_COLOR );
142   if( colorValue )
143   {
144     Vector4 color;
145     if( colorValue->Get( color ) )
146     {
147       Property::Type type = colorValue->GetType();
148       if( type == Property::VECTOR4 )
149       {
150         SetMixColor( color );
151       }
152       else if( type == Property::VECTOR3 )
153       {
154         Vector3 color3(color);
155         SetMixColor( color3 );
156       }
157     }
158   }
159
160   Property::Value* slices = propertyMap.Find( Toolkit::PrimitiveVisual::Property::SLICES, SLICES );
161   if( slices )
162   {
163     if( slices->Get( mSlices ) )
164     {
165       //Clamp value.
166       if( mSlices > MAX_PARTITIONS )
167       {
168         mSlices = MAX_PARTITIONS;
169         DALI_LOG_WARNING( "Value for slices clamped.\n" );
170       }
171       else if ( mSlices < MIN_SLICES )
172       {
173         mSlices = MIN_SLICES;
174         DALI_LOG_WARNING( "Value for slices clamped.\n" );
175       }
176     }
177     else
178     {
179       DALI_LOG_ERROR( "Invalid type for slices in PrimitiveVisual.\n" );
180     }
181   }
182
183   Property::Value* stacks = propertyMap.Find( Toolkit::PrimitiveVisual::Property::STACKS, STACKS );
184   if( stacks )
185   {
186     if( stacks->Get( mStacks ) )
187     {
188       //Clamp value.
189       if( mStacks > MAX_PARTITIONS )
190       {
191         mStacks = MAX_PARTITIONS;
192         DALI_LOG_WARNING( "Value for stacks clamped.\n" );
193       }
194       else if ( mStacks < MIN_STACKS )
195       {
196         mStacks = MIN_STACKS;
197         DALI_LOG_WARNING( "Value for stacks clamped.\n" );
198       }
199     }
200     else
201     {
202       DALI_LOG_ERROR( "Invalid type for stacks in PrimitiveVisual.\n" );
203     }
204   }
205
206   Property::Value* scaleTop = propertyMap.Find( Toolkit::PrimitiveVisual::Property::SCALE_TOP_RADIUS, SCALE_TOP_RADIUS );
207   if( scaleTop && !scaleTop->Get( mScaleTopRadius ) )
208   {
209     DALI_LOG_ERROR( "Invalid type for scale top radius in PrimitiveVisual.\n" );
210   }
211
212   Property::Value* scaleBottom = propertyMap.Find( Toolkit::PrimitiveVisual::Property::SCALE_BOTTOM_RADIUS, SCALE_BOTTOM_RADIUS );
213   if( scaleBottom && !scaleBottom->Get( mScaleBottomRadius ) )
214   {
215     DALI_LOG_ERROR( "Invalid type for scale bottom radius in PrimitiveVisual.\n" );
216   }
217
218   Property::Value* scaleHeight = propertyMap.Find( Toolkit::PrimitiveVisual::Property::SCALE_HEIGHT, SCALE_HEIGHT );
219   if( scaleHeight && !scaleHeight->Get( mScaleHeight ) )
220   {
221     DALI_LOG_ERROR( "Invalid type for scale height in PrimitiveVisual.\n" );
222   }
223
224   Property::Value* scaleRadius = propertyMap.Find( Toolkit::PrimitiveVisual::Property::SCALE_RADIUS, SCALE_RADIUS );
225   if( scaleRadius && !scaleRadius->Get( mScaleRadius ) )
226   {
227     DALI_LOG_ERROR( "Invalid type for scale radius in PrimitiveVisual.\n" );
228   }
229
230   Property::Value* dimensions = propertyMap.Find( Toolkit::PrimitiveVisual::Property::SCALE_DIMENSIONS, SCALE_DIMENSIONS );
231   if( dimensions )
232   {
233     if( dimensions->Get( mScaleDimensions ) )
234     {
235       //If any dimension is invalid, set it to a sensible default.
236       if( mScaleDimensions.x <= 0.0 )
237       {
238         mScaleDimensions.x = 1.0;
239         DALI_LOG_WARNING( "Value for scale dimensions clamped. Must be greater than zero.\n" );
240       }
241       if( mScaleDimensions.y <= 0.0 )
242       {
243         mScaleDimensions.y = 1.0;
244         DALI_LOG_WARNING( "Value for scale dimensions clamped. Must be greater than zero.\n" );
245       }
246       if( mScaleDimensions.z <= 0.0 )
247       {
248         mScaleDimensions.z = 1.0;
249         DALI_LOG_WARNING( "Value for scale dimensions clamped. Must be greater than zero.\n" );
250       }
251     }
252     else
253     {
254       DALI_LOG_ERROR( "Invalid type for scale dimensions in PrimitiveVisual.\n" );
255     }
256   }
257
258   Property::Value* bevel = propertyMap.Find( Toolkit::PrimitiveVisual::Property::BEVEL_PERCENTAGE, BEVEL_PERCENTAGE );
259   if( bevel )
260   {
261     if( bevel->Get( mBevelPercentage ) )
262     {
263       //Clamp value.
264       if( mBevelPercentage < MIN_BEVEL_PERCENTAGE )
265       {
266         mBevelPercentage = MIN_BEVEL_PERCENTAGE;
267         DALI_LOG_WARNING( "Value for bevel percentage clamped.\n" );
268       }
269       else if( mBevelPercentage > MAX_BEVEL_PERCENTAGE )
270       {
271         mBevelPercentage = MAX_BEVEL_PERCENTAGE;
272         DALI_LOG_WARNING( "Value for bevel percentage clamped.\n" );
273       }
274     }
275     else
276     {
277       DALI_LOG_ERROR( "Invalid type for bevel percentage in PrimitiveVisual.\n" );
278     }
279   }
280
281   Property::Value* smoothness = propertyMap.Find( Toolkit::PrimitiveVisual::Property::BEVEL_SMOOTHNESS, BEVEL_SMOOTHNESS );
282   if( smoothness )
283   {
284     if( smoothness->Get( mBevelSmoothness ) )
285     {
286       //Clamp value.
287       if( mBevelSmoothness < MIN_SMOOTHNESS )
288       {
289         mBevelSmoothness = MIN_SMOOTHNESS;
290         DALI_LOG_WARNING( "Value for bevel smoothness clamped.\n" );
291       }
292       else if( mBevelSmoothness > MAX_SMOOTHNESS )
293       {
294         mBevelSmoothness = MAX_SMOOTHNESS;
295         DALI_LOG_WARNING( "Value for bevel smoothness clamped.\n" );
296       }
297     }
298     else
299     {
300       DALI_LOG_ERROR( "Invalid type for bevel smoothness in PrimitiveVisual.\n" );
301     }
302   }
303
304   //Read in light position.
305   Property::Value* lightPosition = propertyMap.Find( Toolkit::PrimitiveVisual::Property::LIGHT_POSITION, LIGHT_POSITION_UNIFORM_NAME );
306   if( lightPosition )
307   {
308     if( !lightPosition->Get( mLightPosition ) )
309     {
310       DALI_LOG_ERROR( "Invalid value passed for light position in MeshVisual object.\n" );
311       mLightPosition = Vector3::ZERO;
312     }
313   }
314   else
315   {
316     //Default behaviour is to place the light directly in front of the object,
317     // at a reasonable distance to light everything on screen.
318     Stage stage = Stage::GetCurrent();
319
320     mLightPosition = Vector3( stage.GetSize().width / 2, stage.GetSize().height / 2, stage.GetSize().width * 5 );
321   }
322 }
323
324 void PrimitiveVisual::GetNaturalSize( Vector2& naturalSize )
325 {
326   if( !mGeometry )
327   {
328     CreateGeometry();
329   }
330
331   naturalSize.x = mObjectDimensions.x;
332   naturalSize.y = mObjectDimensions.y;
333 }
334
335 void PrimitiveVisual::DoSetOnScene( Actor& actor )
336 {
337   actor.AddRenderer( mImpl->mRenderer );
338
339   // Primitive generated and ready to display
340   ResourceReady( Toolkit::Visual::ResourceStatus::READY );
341 }
342
343 void PrimitiveVisual::DoCreatePropertyMap( Property::Map& map ) const
344 {
345   map.Clear();
346   map.Insert( Toolkit::Visual::Property::TYPE, Toolkit::Visual::PRIMITIVE );
347   map.Insert( Toolkit::PrimitiveVisual::Property::MIX_COLOR, mImpl->mMixColor );
348   map.Insert( Toolkit::PrimitiveVisual::Property::SHAPE, mPrimitiveType );
349   map.Insert( Toolkit::PrimitiveVisual::Property::SLICES, mSlices );
350   map.Insert( Toolkit::PrimitiveVisual::Property::STACKS, mStacks );
351   map.Insert( Toolkit::PrimitiveVisual::Property::SCALE_TOP_RADIUS, mScaleTopRadius );
352   map.Insert( Toolkit::PrimitiveVisual::Property::SCALE_BOTTOM_RADIUS, mScaleBottomRadius );
353   map.Insert( Toolkit::PrimitiveVisual::Property::SCALE_HEIGHT, mScaleHeight );
354   map.Insert( Toolkit::PrimitiveVisual::Property::SCALE_RADIUS, mScaleRadius );
355   map.Insert( Toolkit::PrimitiveVisual::Property::SCALE_DIMENSIONS, mScaleDimensions );
356   map.Insert( Toolkit::PrimitiveVisual::Property::BEVEL_PERCENTAGE, mBevelPercentage );
357   map.Insert( Toolkit::PrimitiveVisual::Property::BEVEL_SMOOTHNESS, mBevelSmoothness );
358   map.Insert( Toolkit::PrimitiveVisual::Property::LIGHT_POSITION, mLightPosition );
359 }
360
361 void PrimitiveVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
362 {
363   // Do nothing
364 }
365
366 void PrimitiveVisual::OnSetTransform()
367 {
368   if( mImpl->mRenderer )
369   {
370     mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
371   }
372 }
373
374 void PrimitiveVisual::OnInitialize()
375 {
376   if( !mGeometry )
377   {
378     CreateGeometry();
379   }
380
381   if( !mShader )
382   {
383     CreateShader();
384   }
385
386   mImpl->mRenderer = Renderer::New( mGeometry, mShader );
387   mImpl->mRenderer.SetProperty( Renderer::Property::FACE_CULLING_MODE, FaceCullingMode::BACK );
388
389   // Register transform properties
390   mImpl->mTransform.RegisterUniforms( mImpl->mRenderer, Direction::LEFT_TO_RIGHT );
391
392   mImpl->mMixColorIndex = mImpl->mRenderer.RegisterProperty( Toolkit::PrimitiveVisual::Property::MIX_COLOR, MIX_COLOR, Vector3(mImpl->mMixColor) );
393 }
394
395 void PrimitiveVisual::UpdateShaderUniforms()
396 {
397   Stage stage = Stage::GetCurrent();
398   float width = stage.GetSize().width;
399   float height = stage.GetSize().height;
400
401   //Flip model to account for DALi starting with (0, 0) at the top left.
402   Matrix scaleMatrix;
403   scaleMatrix.SetIdentityAndScale( Vector3( 1.0, -1.0, 1.0 ) );
404
405   mShader.RegisterProperty( STAGE_OFFSET_UNIFORM_NAME, Vector2( width, height ) / 2.0f );
406   mShader.RegisterProperty( LIGHT_POSITION_UNIFORM_NAME, mLightPosition );
407   mShader.RegisterProperty( OBJECT_MATRIX_UNIFORM_NAME, scaleMatrix );
408   mShader.RegisterProperty( OBJECT_DIMENSIONS_UNIFORM_NAME, mObjectDimensions );
409 }
410
411 void PrimitiveVisual::CreateShader()
412 {
413   mShader = Shader::New( SHADER_PRIMITIVE_VISUAL_SHADER_VERT, SHADER_PRIMITIVE_VISUAL_SHADER_FRAG );
414   UpdateShaderUniforms();
415 }
416
417 void PrimitiveVisual::CreateGeometry()
418 {
419   Dali::Vector<Vertex> vertices;
420   Dali::Vector<unsigned short> indices;
421
422   switch( mPrimitiveType )
423   {
424     case Toolkit::PrimitiveVisual::Shape::SPHERE:
425     {
426       CreateSphere( vertices, indices, mSlices, mStacks );
427       break;
428     }
429     case Toolkit::PrimitiveVisual::Shape::CONE:
430     {
431       //Create a conic with zero top radius.
432       CreateConic( vertices, indices, 0, mScaleBottomRadius, mScaleHeight, mSlices );
433       break;
434     }
435     case Toolkit::PrimitiveVisual::Shape::CYLINDER:
436     {
437       //Create a conic with equal radii on the top and bottom.
438       CreateConic( vertices, indices, mScaleRadius, mScaleRadius, mScaleHeight, mSlices );
439       break;
440     }
441     case Toolkit::PrimitiveVisual::Shape::CUBE:
442     {
443       //Create a cube by creating a bevelled cube with minimum bevel.
444       CreateBevelledCube( vertices, indices, mScaleDimensions, 0.0, 0.0 );
445       break;
446     }
447     case Toolkit::PrimitiveVisual::Shape::OCTAHEDRON:
448     {
449       //Create an octahedron by creating a bevelled cube with maximum bevel.
450       CreateBevelledCube( vertices, indices, mScaleDimensions, 1.0, mBevelSmoothness );
451       break;
452     }
453     case Toolkit::PrimitiveVisual::Shape::BEVELLED_CUBE:
454     {
455       CreateBevelledCube( vertices, indices, mScaleDimensions, mBevelPercentage, mBevelSmoothness );
456       break;
457     }
458     case Toolkit::PrimitiveVisual::Shape::CONICAL_FRUSTUM:
459     {
460       CreateConic( vertices, indices, mScaleTopRadius, mScaleBottomRadius, mScaleHeight, mSlices );
461       break;
462     }
463   }
464
465   mGeometry = Geometry::New();
466
467   //Vertices
468   Property::Map vertexFormat;
469   vertexFormat[POSITION] = Property::VECTOR3;
470   vertexFormat[NORMAL] = Property::VECTOR3;
471   VertexBuffer surfaceVertices = VertexBuffer::New( vertexFormat );
472   surfaceVertices.SetData( &vertices[0], vertices.Size() );
473
474   mGeometry.AddVertexBuffer( surfaceVertices );
475
476   //Indices for triangle formulation
477   mGeometry.SetIndexBuffer( &indices[0], indices.Size() );
478 }
479
480 void PrimitiveVisual::CreateSphere( Vector<Vertex>& vertices, Vector<unsigned short>& indices, int slices, int stacks )
481 {
482   ComputeSphereVertices( vertices, slices, stacks );
483   FormSphereTriangles( indices, slices, stacks );
484
485   mObjectDimensions = Vector3::ONE;
486 }
487
488 void PrimitiveVisual::CreateConic( Vector<Vertex>& vertices, Vector<unsigned short>& indices, float scaleTopRadius,
489                                    float scaleBottomRadius, float scaleHeight, int slices )
490 {
491   ComputeConicVertices( vertices, scaleTopRadius, scaleBottomRadius, scaleHeight, slices );
492   FormConicTriangles( indices, scaleTopRadius, scaleBottomRadius, slices );
493
494   //Determine object dimensions, and scale them to be between 0.0 and 1.0.
495   float xDimension = std::max( scaleTopRadius, scaleBottomRadius ) * 2.0f;
496   float yDimension = scaleHeight;
497   float largestDimension = std::max( xDimension, yDimension );
498
499   mObjectDimensions = Vector3( xDimension / largestDimension, yDimension / largestDimension,
500                                xDimension / largestDimension );
501 }
502
503 void PrimitiveVisual::CreateBevelledCube( Vector<Vertex>& vertices, Vector<unsigned short>& indices,
504                                           Vector3 dimensions, float bevelPercentage, float bevelSmoothness )
505 {
506   float maxDimension = std::max( std::max( dimensions.x, dimensions.y ), dimensions.z );
507   dimensions = dimensions / maxDimension;
508
509   if( bevelPercentage <= MIN_BEVEL_PERCENTAGE ) //No bevel, form a cube.
510   {
511     ComputeCubeVertices( vertices, dimensions );
512     FormCubeTriangles( indices );
513   }
514   else if( bevelPercentage >= MAX_BEVEL_PERCENTAGE ) //Max bevel, form an octahedron.
515   {
516     ComputeOctahedronVertices( vertices, dimensions, bevelSmoothness );
517     FormOctahedronTriangles( indices );
518   }
519   else //In between, form a bevelled cube.
520   {
521     ComputeBevelledCubeVertices( vertices, dimensions, bevelPercentage, bevelSmoothness );
522     FormBevelledCubeTriangles( indices );
523   }
524
525   mObjectDimensions = dimensions;
526 }
527
528 void PrimitiveVisual::ComputeCircleTables( Vector<float>& sinTable, Vector<float>& cosTable, int divisions,
529                                            bool halfCircle )
530 {
531   if( divisions < 0 )
532   {
533     return;
534   }
535
536   const float angleDivision = ( halfCircle ? 1.0f : 2.0f ) * Dali::Math::PI / ( float ) divisions;
537
538   sinTable.Resize( divisions );
539   cosTable.Resize( divisions );
540
541   for( int i = 0; i < divisions; i++ )
542   {
543     sinTable[i] = sin( angleDivision * i );
544     cosTable[i] = cos( angleDivision * i );
545   }
546 }
547
548 void PrimitiveVisual::ComputeSphereVertices( Vector<Vertex>& vertices, int slices, int stacks )
549 {
550   //Tables for calculating slices angles and stacks angles, respectively.
551   Vector<float> sinTable1;
552   Vector<float> cosTable1;
553   Vector<float> sinTable2;
554   Vector<float> cosTable2;
555
556   ComputeCircleTables( sinTable1, cosTable1, slices, false );
557   ComputeCircleTables( sinTable2, cosTable2, stacks, true );
558
559   int numVertices = slices * ( stacks - 1 ) + 2;
560   vertices.Resize( numVertices );
561
562   int vertexIndex = 0;  //Track progress through vertices.
563   float x;
564   float y;
565   float z;
566
567   //Top stack.
568   vertices[vertexIndex].position = Vector3( 0.0, 0.5, 0.0 );
569   vertices[vertexIndex].normal =   Vector3( 0.0, 1.0, 0.0 );
570   vertexIndex++;
571
572   //Middle stacks.
573   for( int i = 1; i < stacks; i++ )
574   {
575     for( int j = 0; j < slices; j++, vertexIndex++ )
576     {
577       x = cosTable1[j] * sinTable2[i];
578       y = cosTable2[i];
579       z = sinTable1[j] * sinTable2[i];
580
581       vertices[vertexIndex].position = Vector3( x / 2.0f, y / 2.0f, z / 2.0f );
582       vertices[vertexIndex].normal = Vector3( x, y, z );
583     }
584   }
585
586   //Bottom stack.
587   vertices[vertexIndex].position = Vector3( 0.0, -0.5, 0.0 );
588   vertices[vertexIndex].normal =   Vector3( 0.0, -1.0, 0.0 );
589 }
590
591 void PrimitiveVisual::FormSphereTriangles( Vector<unsigned short>& indices, int slices, int stacks )
592 {
593   if( stacks <= 1 )
594   {
595     //Set indices to placeholder "error" values.
596     //This will display nothing, which is the expected behaviour for this edge case.
597     indices.Resize( 3 );
598     return;
599   }
600
601   int numTriangles = 2 * slices * ( stacks - 1 );
602
603   indices.Resize( 3 * numTriangles );
604
605   int indiceIndex = 0;  //Used to keep track of progress through indices.
606   int previousCycleBeginning = 1;  //Stores the index of the vertex that started the cycle of the previous stack.
607   int currentCycleBeginning = 1 + slices;
608
609   //Top stack. Loop from index 1 to index slices, as not counting the very first vertex.
610   for( int i = 1; i <= slices; i++, indiceIndex += 3 )
611   {
612     indices[indiceIndex] = 0;
613     if( i == slices )
614     {
615       //End, so loop around.
616       indices[indiceIndex + 1] = 1;
617     }
618     else
619     {
620       indices[indiceIndex + 1] = i + 1;
621     }
622     indices[indiceIndex + 2] = i;
623   }
624
625   //Middle Stacks. Want to form triangles between the top and bottom stacks, so loop up to the number of stacks - 2.
626   for( int i = 0; i < stacks - 2; i++, previousCycleBeginning += slices, currentCycleBeginning += slices )
627   {
628     for( int j = 0; j < slices; j++, indiceIndex += 6 )
629     {
630       if( j == slices - 1 )
631       {
632         //End, so loop around.
633         indices[indiceIndex] =     previousCycleBeginning + j;
634         indices[indiceIndex + 1] = previousCycleBeginning;
635         indices[indiceIndex + 2] = currentCycleBeginning + j;
636         indices[indiceIndex + 3] = currentCycleBeginning + j;
637         indices[indiceIndex + 4] = previousCycleBeginning;
638         indices[indiceIndex + 5] = currentCycleBeginning;
639       }
640       else
641       {
642         indices[indiceIndex] =     previousCycleBeginning + j;
643         indices[indiceIndex + 1] = previousCycleBeginning + 1 + j;
644         indices[indiceIndex + 2] = currentCycleBeginning + j;
645         indices[indiceIndex + 3] = currentCycleBeginning + j;
646         indices[indiceIndex + 4] = previousCycleBeginning + 1 + j;
647         indices[indiceIndex + 5] = currentCycleBeginning + 1 + j;
648       }
649     }
650   }
651
652   //Bottom stack. Loop around the last stack from the previous loop, and go up to the penultimate vertex.
653   for( int i = 0; i < slices; i++, indiceIndex += 3 )
654   {
655     indices[indiceIndex] = previousCycleBeginning + slices;
656     indices[indiceIndex + 1] = previousCycleBeginning + i;
657     if( i == slices - 1 )
658     {
659       //End, so loop around.
660       indices[indiceIndex + 2] = previousCycleBeginning;
661     }
662     else
663     {
664       indices[indiceIndex + 2] = previousCycleBeginning + i + 1;
665     }
666   }
667 }
668
669 void PrimitiveVisual::ComputeConicVertices( Vector<Vertex>& vertices, float scaleTopRadius,
670                                             float scaleBottomRadius, float scaleHeight, int slices )
671 {
672   int vertexIndex = 0;  //Track progress through vertices.
673   Vector<float> sinTable;
674   Vector<float> cosTable;
675
676   ComputeCircleTables( sinTable, cosTable, slices, false );
677
678   int numVertices = 2;  //Always will have one at the top and one at the bottom.
679
680   //Add vertices for each circle. Need two per point for different face normals.
681   if( scaleTopRadius > 0.0 )
682   {
683     numVertices += 2 * slices;
684   }
685   if( scaleBottomRadius > 0.0 )
686   {
687     numVertices += 2 * slices;
688   }
689
690   vertices.Resize( numVertices );
691
692
693   //Scale to bounding region of -0.5 to 0.5 (i.e range of 1).
694   float biggestObjectDimension = std::max( std::max( scaleTopRadius * 2.0f, scaleBottomRadius * 2.0f ), scaleHeight );
695   scaleTopRadius = scaleTopRadius / biggestObjectDimension;
696   scaleBottomRadius = scaleBottomRadius / biggestObjectDimension;
697
698   //Dimensions for vertex coordinates. Y is constant, and so can be initialised now.
699   float x;
700   float y = scaleHeight / biggestObjectDimension / 2.0f;
701   float z;
702
703   //Top center.
704   vertices[0].position = Vector3( 0, y, 0 );
705   vertices[0].normal = Vector3( 0, 1, 0 );
706   vertexIndex++;
707
708   //Top circle.
709   if( scaleTopRadius > 0.0 )
710   {
711     //Loop around the circle.
712     for( int i = 0; i < slices; i++, vertexIndex++ )
713     {
714       x = sinTable[i] * scaleTopRadius;
715       z = cosTable[i] * scaleTopRadius;
716
717       //Upward-facing normal.
718       vertices[vertexIndex].position = Vector3( x, y, z );
719       vertices[vertexIndex].normal = Vector3( 0, 1, 0 );
720
721       //Outward-facing normal.
722       vertices[vertexIndex + slices].position = Vector3( x, y, z );
723       vertices[vertexIndex + slices].normal = Vector3( x, 0, z );
724     }
725
726     vertexIndex += slices;
727   }
728
729   //Bottom circle.
730   if( scaleBottomRadius > 0.0 )
731   {
732     //Loop around the circle.
733     for( int i = 0; i < slices; i++, vertexIndex++ )
734     {
735       x = sinTable[i] * scaleBottomRadius;
736       z = cosTable[i] * scaleBottomRadius;
737
738       //Outward-facing normal.
739       vertices[vertexIndex].position = Vector3( x, -y, z );
740       vertices[vertexIndex].normal = Vector3( x, 0, z );
741
742       //Downward-facing normal.
743       vertices[vertexIndex + slices].position = Vector3( x, -y, z );
744       vertices[vertexIndex + slices].normal = Vector3( 0, -1, 0 );
745     }
746
747     vertexIndex += slices;
748   }
749
750   //Bottom center.
751   vertices[vertexIndex].position = Vector3( 0, -y, 0 );
752   vertices[vertexIndex].normal = Vector3( 0, -1, 0 );
753   vertexIndex++;
754 }
755
756 void PrimitiveVisual::FormConicTriangles( Vector<unsigned short>& indices, float scaleTopRadius,
757                                           float scaleBottomRadius, int slices )
758 {
759   int  indiceIndex = 0;  //Track progress through indices.
760   int  numTriangles = 0;
761   bool coneTop = scaleTopRadius <= 0.0;
762   bool coneBottom = scaleBottomRadius <= 0.0;
763
764   if( coneTop && coneBottom )
765   {
766     //Set indices to placeholder "error" values.
767     //This will display nothing, which is the expected behaviour for this edge case.
768     indices.Resize( 3 );
769     return;
770   }
771
772   if( !coneTop )
773   {
774     numTriangles += 2 * slices;
775   }
776   if( !coneBottom )
777   {
778     numTriangles += 2 * slices;
779   }
780
781   indices.Resize( 3 * numTriangles );
782
783   //Switch on the type of conic we have.
784   if( !coneTop && !coneBottom )
785   {
786     //Top circle. Start at index of first outer point and go around.
787     for( int i = 1; i <= slices; i++, indiceIndex += 3 )
788     {
789       indices[indiceIndex] = 0;
790       indices[indiceIndex + 1] = i;
791       if( i == slices )
792       {
793         //End, so loop around.
794         indices[indiceIndex + 2] = 1;
795       }
796       else
797       {
798         indices[indiceIndex + 2] = i + 1;
799       }
800     }
801
802     int topCycleBeginning = slices + 1;
803     int bottomCycleBeginning = topCycleBeginning + slices;
804
805     //Vertical edges.
806     for( int i = 0; i < slices; i++, indiceIndex += 6 )
807     {
808       if( i == slices - 1 )
809       {
810         //End, so loop around.
811         indices[indiceIndex] =     topCycleBeginning + i;
812         indices[indiceIndex + 1] = bottomCycleBeginning + i;
813         indices[indiceIndex + 2] = topCycleBeginning;
814         indices[indiceIndex + 3] = bottomCycleBeginning + i;
815         indices[indiceIndex + 4] = bottomCycleBeginning;
816         indices[indiceIndex + 5] = topCycleBeginning;
817       }
818       else
819       {
820         indices[indiceIndex] =     topCycleBeginning + i;
821         indices[indiceIndex + 1] = bottomCycleBeginning + i;
822         indices[indiceIndex + 2] = topCycleBeginning + 1 + i;
823         indices[indiceIndex + 3] = bottomCycleBeginning + i;
824         indices[indiceIndex + 4] = bottomCycleBeginning + 1 + i;
825         indices[indiceIndex + 5] = topCycleBeginning + 1 + i;
826       }
827     }
828
829     int bottomFaceCycleBeginning = bottomCycleBeginning + slices;
830
831     //Bottom circle.
832     for( int i = 0; i < slices; i++, indiceIndex += 3 )
833     {
834       indices[indiceIndex] = bottomFaceCycleBeginning;
835       if( i == slices - 1 )
836       {
837         //End, so loop around.
838         indices[indiceIndex + 1] = bottomFaceCycleBeginning;
839       }
840       else
841       {
842         indices[indiceIndex + 1] = bottomFaceCycleBeginning + i + 1;
843       }
844       indices[indiceIndex + 2] = bottomFaceCycleBeginning + i;
845     }
846   }
847   else if( !coneTop || !coneBottom )
848   {
849     //Top circle/edges. Start at index of first outer point and go around.
850     for( int i = 1; i <= slices; i++, indiceIndex += 3 )
851     {
852       indices[indiceIndex] = 0;
853       indices[indiceIndex + 1] = i;
854       if( i == slices )
855       {
856         //End, so loop around.
857         indices[indiceIndex + 2] = 1;
858       }
859       else
860       {
861         indices[indiceIndex + 2] = i + 1;
862       }
863     }
864
865     //Bottom circle/edges. Start at index of first outer point and go around.
866     for( int i = 1; i <= slices; i++, indiceIndex += 3 )
867     {
868       indices[indiceIndex] = 2 * slices + 1;
869       if( i == slices )
870       {
871         //End, so loop around.
872         indices[indiceIndex + 1] = slices + 1;
873       }
874       else
875       {
876         indices[indiceIndex + 1] = slices + i + 1;
877       }
878       indices[indiceIndex + 2] = slices + i;
879     }
880   }
881 }
882
883 void PrimitiveVisual::ComputeCubeVertices( Vector<Vertex>& vertices, Vector3 dimensions )
884 {
885   int numVertices = 4 * 6; //Four per face.
886   int vertexIndex = 0; //Tracks progress through vertices.
887   float scaledX = 0.5 * dimensions.x;
888   float scaledY = 0.5 * dimensions.y;
889   float scaledZ = 0.5 * dimensions.z;
890
891   vertices.Resize( numVertices );
892
893   Vector<Vector3> positions; //Stores vertex positions, which are shared between vertexes at the same position but with a different normal.
894   positions.Resize(8);
895   Vector<Vector3> normals; //Stores normals, which are shared between vertexes of the same face.
896   normals.Resize(6);
897
898   positions[0] = Vector3( -scaledX,  scaledY, -scaledZ );
899   positions[1] = Vector3(  scaledX,  scaledY, -scaledZ );
900   positions[2] = Vector3(  scaledX,  scaledY,  scaledZ );
901   positions[3] = Vector3( -scaledX,  scaledY,  scaledZ );
902   positions[4] = Vector3( -scaledX, -scaledY, -scaledZ );
903   positions[5] = Vector3(  scaledX, -scaledY, -scaledZ );
904   positions[6] = Vector3(  scaledX, -scaledY,  scaledZ );
905   positions[7] = Vector3( -scaledX, -scaledY,  scaledZ );
906
907   normals[0] = Vector3(  0,  1,  0 );
908   normals[1] = Vector3(  0,  0, -1 );
909   normals[2] = Vector3(  1,  0,  0 );
910   normals[3] = Vector3(  0,  0,  1 );
911   normals[4] = Vector3( -1,  0,  0 );
912   normals[5] = Vector3(  0, -1,  0 );
913
914   //Top face, upward normals.
915   for( int i = 0; i < 4; i++, vertexIndex++ )
916   {
917     vertices[vertexIndex].position = positions[i];
918     vertices[vertexIndex].normal = normals[0];
919   }
920
921   //Top face, outward normals.
922   for( int i = 0; i < 4; i++, vertexIndex += 2 )
923   {
924     vertices[vertexIndex].position = positions[i];
925     vertices[vertexIndex].normal = normals[i + 1];
926
927     if( i == 3 )
928     {
929       //End, so loop around.
930       vertices[vertexIndex + 1].position = positions[0];
931     }
932     else
933     {
934       vertices[vertexIndex + 1].position = positions[i + 1];
935     }
936     vertices[vertexIndex + 1].normal = normals[i + 1];
937   }
938
939   //Bottom face, outward normals.
940   for( int i = 0; i < 4; i++, vertexIndex += 2 )
941   {
942     vertices[vertexIndex].position = positions[i + 4];
943     vertices[vertexIndex].normal = normals[i + 1];
944
945     if( i == 3 )
946     {
947       //End, so loop around.
948       vertices[vertexIndex + 1].position = positions[4];
949     }
950     else
951     {
952       vertices[vertexIndex + 1].position = positions[i + 5];
953     }
954     vertices[vertexIndex + 1].normal = normals[i + 1];
955   }
956
957   //Bottom face, downward normals.
958   for( int i = 0; i < 4; i++, vertexIndex++ )
959   {
960     vertices[vertexIndex].position = positions[i + 4];
961     vertices[vertexIndex].normal = normals[5];
962   }
963
964 }
965
966 void PrimitiveVisual::FormCubeTriangles( Vector<unsigned short>& indices )
967 {
968   int numTriangles = 12;
969   int triangleIndex = 0;  //Track progress through indices.
970
971   indices.Resize( 3 * numTriangles );
972
973   //Top face.
974   indices[triangleIndex] =     0;
975   indices[triangleIndex + 1] = 2;
976   indices[triangleIndex + 2] = 1;
977   indices[triangleIndex + 3] = 2;
978   indices[triangleIndex + 4] = 0;
979   indices[triangleIndex + 5] = 3;
980   triangleIndex += 6;
981
982   int topFaceStart = 4;
983   int bottomFaceStart = 12;
984
985   //Side faces.
986   for( int i = 0; i < 8; i += 2, triangleIndex += 6 )
987   {
988     indices[triangleIndex    ] = i + topFaceStart;
989     indices[triangleIndex + 1] = i + topFaceStart + 1;
990     indices[triangleIndex + 2] = i + bottomFaceStart + 1;
991     indices[triangleIndex + 3] = i + topFaceStart;
992     indices[triangleIndex + 4] = i + bottomFaceStart + 1;
993     indices[triangleIndex + 5] = i + bottomFaceStart;
994   }
995
996   //Bottom face.
997   indices[triangleIndex] =     20;
998   indices[triangleIndex + 1] = 21;
999   indices[triangleIndex + 2] = 22;
1000   indices[triangleIndex + 3] = 22;
1001   indices[triangleIndex + 4] = 23;
1002   indices[triangleIndex + 5] = 20;
1003 }
1004
1005 void PrimitiveVisual::ComputeOctahedronVertices( Vector<Vertex>& vertices, Vector3 dimensions, float smoothness )
1006 {
1007   int numVertices = 3 * 8; //Three per face
1008   int vertexIndex = 0; //Tracks progress through vertices.
1009   float scaledX = 0.5 * dimensions.x;
1010   float scaledY = 0.5 * dimensions.y;
1011   float scaledZ = 0.5 * dimensions.z;
1012
1013   vertices.Resize( numVertices );
1014
1015   Vector<Vector3> positions; //Stores vertex positions, which are shared between vertexes at the same position but with a different normal.
1016   positions.Resize(6);
1017   Vector<Vector3> normals; //Stores normals, which are shared between vertexes of the same face.
1018   normals.Resize(8);
1019   Vector<Vector3> outerNormals;  //Holds normals that point outwards at each vertex.
1020   outerNormals.Resize( 6 );
1021
1022   positions[0] = Vector3(  0.0,  scaledY,  0.0 );
1023   positions[1] = Vector3( -scaledX,  0.0,  0.0 );
1024   positions[2] = Vector3(  0.0,  0.0, -scaledZ );
1025   positions[3] = Vector3(  scaledX,  0.0,  0.0 );
1026   positions[4] = Vector3(  0.0,  0.0,  scaledZ );
1027   positions[5] = Vector3(  0.0, -scaledY,  0.0 );
1028
1029   normals[0] = Vector3( -1,  1, -1 );
1030   normals[1] = Vector3(  1,  1, -1 );
1031   normals[2] = Vector3(  1,  1,  1 );
1032   normals[3] = Vector3( -1,  1,  1 );
1033   normals[4] = Vector3( -1, -1, -1 );
1034   normals[5] = Vector3(  1, -1, -1 );
1035   normals[6] = Vector3(  1, -1,  1 );
1036   normals[7] = Vector3( -1, -1,  1 );
1037
1038   outerNormals[0] = Vector3(  0,  1,  0 );
1039   outerNormals[1] = Vector3( -1,  0,  0 );
1040   outerNormals[2] = Vector3(  0,  0, -1 );
1041   outerNormals[3] = Vector3(  1,  0,  0 );
1042   outerNormals[4] = Vector3(  0,  0,  1 );
1043   outerNormals[5] = Vector3(  0, -1,  0 );
1044
1045   //Loop through top faces.
1046   for( int i = 0; i < 4; i++, vertexIndex += 3 )
1047   {
1048     if( i == 3 )
1049     {
1050       //End, so loop around.
1051       vertices[vertexIndex    ].position = positions[0];
1052       vertices[vertexIndex    ].normal = outerNormals[0] * smoothness + normals[i] * (1 - smoothness);
1053       vertices[vertexIndex + 1].position = positions[1];
1054       vertices[vertexIndex + 1].normal = outerNormals[1] * smoothness + normals[i] * (1 - smoothness);
1055       vertices[vertexIndex + 2].position = positions[i + 1];
1056       vertices[vertexIndex + 2].normal = outerNormals[i + 1] * smoothness + normals[i] * (1 - smoothness);
1057     }
1058     else
1059     {
1060       vertices[vertexIndex    ].position = positions[0];
1061       vertices[vertexIndex    ].normal = outerNormals[0] * smoothness + normals[i] * (1 - smoothness);
1062       vertices[vertexIndex + 1].position = positions[i + 2];
1063       vertices[vertexIndex + 1].normal = outerNormals[i + 2] * smoothness + normals[i] * (1 - smoothness);
1064       vertices[vertexIndex + 2].position = positions[i + 1];
1065       vertices[vertexIndex + 2].normal = outerNormals[i + 1] * smoothness + normals[i] * (1 - smoothness);
1066     }
1067   }
1068
1069   //Loop through bottom faces.
1070   for( int i = 0; i < 4; i++, vertexIndex += 3 )
1071   {
1072     if( i == 3 )
1073     {
1074       //End, so loop around.
1075       vertices[vertexIndex    ].position = positions[5];
1076       vertices[vertexIndex    ].normal = outerNormals[5] * smoothness + normals[i + 4] * (1 - smoothness);
1077       vertices[vertexIndex + 1].position = positions[i + 1];
1078       vertices[vertexIndex + 1].normal = outerNormals[i + 1] * smoothness + normals[i + 4] * (1 - smoothness);
1079       vertices[vertexIndex + 2].position = positions[1];
1080       vertices[vertexIndex + 2].normal = outerNormals[1] * smoothness + normals[i + 4] * (1 - smoothness);
1081     }
1082     else
1083     {
1084       vertices[vertexIndex    ].position = positions[5];
1085       vertices[vertexIndex    ].normal = outerNormals[5] * smoothness + normals[i + 4] * (1 - smoothness);
1086       vertices[vertexIndex + 1].position = positions[i + 1];
1087       vertices[vertexIndex + 1].normal = outerNormals[i + 1] * smoothness + normals[i + 4] * (1 - smoothness);
1088       vertices[vertexIndex + 2].position = positions[i + 2];
1089       vertices[vertexIndex + 2].normal = outerNormals[i + 2] * smoothness + normals[i + 4] * (1 - smoothness);
1090     }
1091   }
1092 }
1093
1094 void PrimitiveVisual::FormOctahedronTriangles( Vector<unsigned short>& indices )
1095 {
1096   int numTriangles = 8;
1097   int numIndices = numTriangles * 3;
1098
1099   indices.Resize( numIndices );
1100
1101   for( unsigned short i = 0; i < numIndices; i++ )
1102   {
1103     indices[i] = i;
1104   }
1105 }
1106
1107 void PrimitiveVisual::ComputeBevelledCubeVertices( Vector<Vertex>& vertices, Vector3 dimensions,
1108                                                    float bevelPercentage, float bevelSmoothness )
1109 {
1110   int numPositions = 24;
1111   int numFaces = 26;
1112   int numOuterFaces = 6;
1113   int numVertices = 6 * 4 + 12 * 4 + 8 * 3; //Six outer faces, 12 slanting rectangles, 8 slanting triangles.
1114   int vertexIndex = 0;  //Track progress through vertices.
1115   int normalIndex = 0;  //Track progress through normals, as vertices are calculated per face.
1116
1117   float minDimension = std::min( std::min( dimensions.x, dimensions.y ), dimensions.z );
1118   float bevelAmount = 0.5 * std::min( bevelPercentage, minDimension ); //Cap bevel amount if necessary.
1119
1120   //Distances from centre to outer edge points.
1121   float outerX = 0.5 * dimensions.x;
1122   float outerY = 0.5 * dimensions.y;
1123   float outerZ = 0.5 * dimensions.z;
1124
1125   //Distances from centre to bevelled points.
1126   float bevelX = outerX - bevelAmount;
1127   float bevelY = outerY - bevelAmount;
1128   float bevelZ = outerZ - bevelAmount;
1129
1130   Vector<Vector3> positions;  //Holds object points, to be shared between vertexes.
1131   positions.Resize( numPositions );
1132   Vector<Vector3> normals;  //Holds face normals, to be shared between vertexes.
1133   normals.Resize( numFaces );
1134   Vector<Vector3> outerNormals;  //Holds normals of the outermost faces specifically.
1135   outerNormals.Resize( numOuterFaces );
1136   vertices.Resize( numVertices );
1137
1138   //Topmost face positions.
1139   positions[0 ] = Vector3( -bevelX,  outerY, -bevelZ );
1140   positions[1 ] = Vector3(  bevelX,  outerY, -bevelZ );
1141   positions[2 ] = Vector3(  bevelX,  outerY,  bevelZ );
1142   positions[3 ] = Vector3( -bevelX,  outerY,  bevelZ );
1143
1144   //Second layer positions.
1145   positions[4 ] = Vector3( -outerX,  bevelY, -bevelZ );
1146   positions[5 ] = Vector3( -bevelX,  bevelY, -outerZ );
1147   positions[6 ] = Vector3(  bevelX,  bevelY, -outerZ );
1148   positions[7 ] = Vector3(  outerX,  bevelY, -bevelZ );
1149   positions[8 ] = Vector3(  outerX,  bevelY,  bevelZ );
1150   positions[9 ] = Vector3(  bevelX,  bevelY,  outerZ );
1151   positions[10] = Vector3( -bevelX,  bevelY,  outerZ );
1152   positions[11] = Vector3( -outerX,  bevelY,  bevelZ );
1153
1154   //Third layer positions.
1155   positions[12] = Vector3( -outerX, -bevelY, -bevelZ );
1156   positions[13] = Vector3( -bevelX, -bevelY, -outerZ );
1157   positions[14] = Vector3(  bevelX, -bevelY, -outerZ );
1158   positions[15] = Vector3(  outerX, -bevelY, -bevelZ );
1159   positions[16] = Vector3(  outerX, -bevelY,  bevelZ );
1160   positions[17] = Vector3(  bevelX, -bevelY,  outerZ );
1161   positions[18] = Vector3( -bevelX, -bevelY,  outerZ );
1162   positions[19] = Vector3( -outerX, -bevelY,  bevelZ );
1163
1164   //Bottom-most face positions.
1165   positions[20] = Vector3( -bevelX, -outerY, -bevelZ );
1166   positions[21] = Vector3(  bevelX, -outerY, -bevelZ );
1167   positions[22] = Vector3(  bevelX, -outerY,  bevelZ );
1168   positions[23] = Vector3( -bevelX, -outerY,  bevelZ );
1169
1170   //Top face normal.
1171   normals[0 ] = Vector3(  0,  1,  0 );
1172
1173   //Top slope normals.
1174   normals[1 ] = Vector3( -1,  1, -1 );
1175   normals[2 ] = Vector3(  0,  1, -1 );
1176   normals[3 ] = Vector3(  1,  1, -1 );
1177   normals[4 ] = Vector3(  1,  1,  0 );
1178   normals[5 ] = Vector3(  1,  1,  1 );
1179   normals[6 ] = Vector3(  0,  1,  1 );
1180   normals[7 ] = Vector3( -1,  1,  1 );
1181   normals[8 ] = Vector3( -1,  1,  0 );
1182
1183   //Side normals.
1184   normals[9 ] = Vector3( -1,  0, -1 );
1185   normals[10] = Vector3(  0,  0, -1 );
1186   normals[11] = Vector3(  1,  0, -1 );
1187   normals[12] = Vector3(  1,  0,  0 );
1188   normals[13] = Vector3(  1,  0,  1 );
1189   normals[14] = Vector3(  0,  0,  1 );
1190   normals[15] = Vector3( -1,  0,  1 );
1191   normals[16] = Vector3( -1,  0,  0 );
1192
1193   //Bottom slope normals.
1194   normals[17] = Vector3( -1, -1, -1 );
1195   normals[18] = Vector3(  0, -1, -1 );
1196   normals[19] = Vector3(  1, -1, -1 );
1197   normals[20] = Vector3(  1, -1,  0 );
1198   normals[21] = Vector3(  1, -1,  1 );
1199   normals[22] = Vector3(  0, -1,  1 );
1200   normals[23] = Vector3( -1, -1,  1 );
1201   normals[24] = Vector3( -1, -1,  0 );
1202
1203   //Bottom face normal.
1204   normals[25] = Vector3(  0, -1,  0 );
1205
1206   //Top, back, right, front, left and bottom faces, respectively.
1207   outerNormals[0] = Vector3(  0,  1,  0 );
1208   outerNormals[1] = Vector3(  0,  0, -1 );
1209   outerNormals[2] = Vector3(  1,  0,  0 );
1210   outerNormals[3] = Vector3(  0,  0,  1 );
1211   outerNormals[4] = Vector3( -1,  0,  0 );
1212   outerNormals[5] = Vector3(  0, -1,  0 );
1213
1214   //Topmost face vertices.
1215   for( int i = 0; i < 4; i++, vertexIndex++ )
1216   {
1217     vertices[vertexIndex].position = positions[i];
1218     vertices[vertexIndex].normal = normals[normalIndex];
1219   }
1220
1221   normalIndex++;
1222
1223   //Top slope vertices.
1224   for( int i = 0; i < 4; i++, vertexIndex += 7, normalIndex += 2 )
1225   {
1226     //Triangle part
1227     vertices[vertexIndex    ].position = positions[i];
1228     vertices[vertexIndex    ].normal = outerNormals[0] * bevelSmoothness + normals[normalIndex] * (1 - bevelSmoothness);
1229     vertices[vertexIndex + 1].position = positions[2 * i + 4];
1230     vertices[vertexIndex + 1].normal = outerNormals[( i == 0 ) ? 4 : i] * bevelSmoothness  + normals[normalIndex] * (1 - bevelSmoothness);
1231     vertices[vertexIndex + 2].position = positions[2 * i + 5];
1232     vertices[vertexIndex + 2].normal = outerNormals[i + 1] * bevelSmoothness + normals[normalIndex] * (1 - bevelSmoothness);
1233
1234     //Rectangle part
1235     if( i == 3 )
1236     {
1237       //End, so loop around.
1238       vertices[vertexIndex + 3].position = positions[i];
1239       vertices[vertexIndex + 3].normal = outerNormals[0] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
1240       vertices[vertexIndex + 4].position = positions[0];
1241       vertices[vertexIndex + 4].normal = outerNormals[0] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
1242       vertices[vertexIndex + 5].position = positions[2 * i + 5];
1243       vertices[vertexIndex + 5].normal = outerNormals[i + 1] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
1244       vertices[vertexIndex + 6].position = positions[4];
1245       vertices[vertexIndex + 6].normal = outerNormals[i + 1] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
1246     }
1247     else
1248     {
1249       vertices[vertexIndex + 3].position = positions[i];
1250       vertices[vertexIndex + 3].normal = outerNormals[0] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
1251       vertices[vertexIndex + 4].position = positions[i + 1];
1252       vertices[vertexIndex + 4].normal = outerNormals[0] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
1253       vertices[vertexIndex + 5].position = positions[2 * i + 5];
1254       vertices[vertexIndex + 5].normal = outerNormals[i + 1] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
1255       vertices[vertexIndex + 6].position = positions[2 * i + 6];
1256       vertices[vertexIndex + 6].normal = outerNormals[i + 1] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
1257     }
1258   }
1259
1260   int secondCycleBeginning = 4;
1261   int thirdCycleBeginning = secondCycleBeginning + 8;
1262   int bottomCycleBeginning = thirdCycleBeginning + 8;
1263
1264   //Side vertices.
1265   for( int i = 0; i < 8; i++, vertexIndex += 4, normalIndex++ )
1266   {
1267     if( i == 7 )
1268     {
1269       //End, so loop around.
1270       vertices[vertexIndex    ].position = positions[secondCycleBeginning + i];
1271       vertices[vertexIndex    ].normal = normals[normalIndex];
1272       vertices[vertexIndex + 1].position = positions[secondCycleBeginning];
1273       vertices[vertexIndex + 1].normal = normals[normalIndex];
1274       vertices[vertexIndex + 2].position = positions[thirdCycleBeginning + i];
1275       vertices[vertexIndex + 2].normal = normals[normalIndex];
1276       vertices[vertexIndex + 3].position = positions[thirdCycleBeginning];
1277       vertices[vertexIndex + 3].normal = normals[normalIndex];
1278     }
1279     else if( (i % 2) == 0 )
1280     {
1281       //'even' faces are corner ones, and need smoothing.
1282       vertices[vertexIndex    ].position = positions[secondCycleBeginning + i];
1283       vertices[vertexIndex    ].normal = outerNormals[( i == 0 ) ? 4 : i / 2] * bevelSmoothness + normals[normalIndex] * (1 - bevelSmoothness);
1284       vertices[vertexIndex + 1].position = positions[secondCycleBeginning + i + 1];
1285       vertices[vertexIndex + 1].normal = outerNormals[i / 2 + 1] * bevelSmoothness + normals[normalIndex] * (1 - bevelSmoothness);
1286       vertices[vertexIndex + 2].position = positions[thirdCycleBeginning + i];
1287       vertices[vertexIndex + 2].normal = outerNormals[( i == 0 ) ? 4 : i / 2] * bevelSmoothness + normals[normalIndex] * (1 - bevelSmoothness);
1288       vertices[vertexIndex + 3].position = positions[thirdCycleBeginning + i + 1];
1289       vertices[vertexIndex + 3].normal = outerNormals[i / 2 + 1] * bevelSmoothness + normals[normalIndex] * (1 - bevelSmoothness);
1290     }
1291     else
1292     {
1293       //'odd' faces are outer ones, and so don't need smoothing.
1294       vertices[vertexIndex    ].position = positions[secondCycleBeginning + i];
1295       vertices[vertexIndex    ].normal = normals[normalIndex];
1296       vertices[vertexIndex + 1].position = positions[secondCycleBeginning + i + 1];
1297       vertices[vertexIndex + 1].normal = normals[normalIndex];
1298       vertices[vertexIndex + 2].position = positions[thirdCycleBeginning + i];
1299       vertices[vertexIndex + 2].normal = normals[normalIndex];
1300       vertices[vertexIndex + 3].position = positions[thirdCycleBeginning + i + 1];
1301       vertices[vertexIndex + 3].normal = normals[normalIndex];
1302     }
1303   }
1304
1305   //Bottom slope vertices.
1306   for( int i = 0; i < 4; i++, vertexIndex += 7, normalIndex += 2 )
1307   {
1308     //Triangle part
1309     vertices[vertexIndex    ].position = positions[thirdCycleBeginning + 2 * i];
1310     vertices[vertexIndex    ].normal = outerNormals[( i == 0 ) ? 4 : i] * bevelSmoothness + normals[normalIndex] * (1 - bevelSmoothness);
1311     vertices[vertexIndex + 1].position = positions[thirdCycleBeginning + 2 * i + 1];
1312     vertices[vertexIndex + 1].normal = outerNormals[i + 1] * bevelSmoothness + normals[normalIndex] * (1 - bevelSmoothness);
1313     vertices[vertexIndex + 2].position = positions[bottomCycleBeginning + i];
1314     vertices[vertexIndex + 2].normal = outerNormals[5] * bevelSmoothness + normals[normalIndex] * (1 - bevelSmoothness);
1315
1316     //Rectangle part
1317     if( i == 3 )
1318     {
1319       //End, so loop around.
1320       vertices[vertexIndex + 3].position = positions[thirdCycleBeginning + 2 * i + 1];
1321       vertices[vertexIndex + 3].normal = outerNormals[i + 1] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
1322       vertices[vertexIndex + 4].position = positions[thirdCycleBeginning];
1323       vertices[vertexIndex + 4].normal = outerNormals[i + 1] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
1324       vertices[vertexIndex + 5].position = positions[bottomCycleBeginning + i];
1325       vertices[vertexIndex + 5].normal = outerNormals[5] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
1326       vertices[vertexIndex + 6].position = positions[bottomCycleBeginning];
1327       vertices[vertexIndex + 6].normal = outerNormals[5] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
1328     }
1329     else
1330     {
1331       vertices[vertexIndex + 3].position = positions[thirdCycleBeginning + 2 * i + 1];
1332       vertices[vertexIndex + 3].normal = outerNormals[i + 1] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
1333       vertices[vertexIndex + 4].position = positions[thirdCycleBeginning + 2 * i + 2];
1334       vertices[vertexIndex + 4].normal = outerNormals[i + 1] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
1335       vertices[vertexIndex + 5].position = positions[bottomCycleBeginning + i];
1336       vertices[vertexIndex + 5].normal = outerNormals[5] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
1337       vertices[vertexIndex + 6].position = positions[bottomCycleBeginning + i + 1];
1338       vertices[vertexIndex + 6].normal = outerNormals[5] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
1339     }
1340   }
1341
1342   //Bottom-most face vertices.
1343   for( int i = 0; i < 4; i++, vertexIndex++ )
1344   {
1345     vertices[vertexIndex].position = positions[ bottomCycleBeginning + i];
1346     vertices[vertexIndex].normal = normals[normalIndex];
1347   }
1348
1349   normalIndex++;
1350 }
1351
1352 void PrimitiveVisual::FormBevelledCubeTriangles( Vector<unsigned short>& indices )
1353 {
1354   int numTriangles = 44; //(Going from top to bottom, that's 2 + 12 + 16 + 12 + 2)
1355   int indiceIndex = 0;  //Track progress through indices.
1356   int vertexIndex = 0;  //Track progress through vertices as they're processed.
1357
1358   indices.Resize( 3 * numTriangles );
1359
1360   //Top face.
1361   indices[indiceIndex    ] = vertexIndex;
1362   indices[indiceIndex + 1] = vertexIndex + 2;
1363   indices[indiceIndex + 2] = vertexIndex + 1;
1364   indices[indiceIndex + 3] = vertexIndex + 0;
1365   indices[indiceIndex + 4] = vertexIndex + 3;
1366   indices[indiceIndex + 5] = vertexIndex + 2;
1367   indiceIndex += 6;
1368   vertexIndex += 4;
1369
1370   //Top slopes.
1371   for( int i = 0; i < 4; i++, indiceIndex += 9, vertexIndex += 7 )
1372   {
1373     //Triangle part.
1374     indices[indiceIndex    ] = vertexIndex;
1375     indices[indiceIndex + 1] = vertexIndex + 2;
1376     indices[indiceIndex + 2] = vertexIndex + 1;
1377
1378     //Rectangle part.
1379     indices[indiceIndex + 3] = vertexIndex + 3;
1380     indices[indiceIndex + 4] = vertexIndex + 4;
1381     indices[indiceIndex + 5] = vertexIndex + 5;
1382     indices[indiceIndex + 6] = vertexIndex + 4;
1383     indices[indiceIndex + 7] = vertexIndex + 6;
1384     indices[indiceIndex + 8] = vertexIndex + 5;
1385   }
1386
1387   //Side faces.
1388   for( int i = 0; i < 8; i++, indiceIndex += 6, vertexIndex += 4 )
1389   {
1390     indices[indiceIndex    ] = vertexIndex;
1391     indices[indiceIndex + 1] = vertexIndex + 1;
1392     indices[indiceIndex + 2] = vertexIndex + 2;
1393     indices[indiceIndex + 3] = vertexIndex + 1;
1394     indices[indiceIndex + 4] = vertexIndex + 3;
1395     indices[indiceIndex + 5] = vertexIndex + 2;
1396   }
1397
1398   //Bottom slopes.
1399   for( int i = 0; i < 4; i++, indiceIndex += 9, vertexIndex += 7 )
1400   {
1401     //Triangle part.
1402     indices[indiceIndex    ] = vertexIndex;
1403     indices[indiceIndex + 1] = vertexIndex + 1;
1404     indices[indiceIndex + 2] = vertexIndex + 2;
1405
1406     //Rectangle part.
1407     indices[indiceIndex + 3] = vertexIndex + 3;
1408     indices[indiceIndex + 4] = vertexIndex + 4;
1409     indices[indiceIndex + 5] = vertexIndex + 5;
1410     indices[indiceIndex + 6] = vertexIndex + 4;
1411     indices[indiceIndex + 7] = vertexIndex + 6;
1412     indices[indiceIndex + 8] = vertexIndex + 5;
1413   }
1414
1415   //Bottom face.
1416   indices[indiceIndex    ] = vertexIndex;
1417   indices[indiceIndex + 1] = vertexIndex + 1;
1418   indices[indiceIndex + 2] = vertexIndex + 2;
1419   indices[indiceIndex + 3] = vertexIndex + 0;
1420   indices[indiceIndex + 4] = vertexIndex + 2;
1421   indices[indiceIndex + 5] = vertexIndex + 3;
1422   indiceIndex += 6;
1423   vertexIndex += 4;
1424 }
1425
1426 } // namespace Internal
1427
1428 } // namespace Toolkit
1429
1430 } // namespace Dali