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