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