Updated visuals to use VisualRenderer
[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 // 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.SetUniforms(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 = VisualRenderer::New(mGeometry, mShader);
383   mImpl->mRenderer.SetProperty(Renderer::Property::FACE_CULLING_MODE, FaceCullingMode::BACK);
384   mImpl->mRenderer.SetProperty(VisualRenderer::Property::VISUAL_MIX_COLOR, Vector3(mImpl->mMixColor));
385   mImpl->mTransform.SetUniforms(mImpl->mRenderer, Direction::LEFT_TO_RIGHT);
386 }
387
388 void PrimitiveVisual::UpdateShaderUniforms()
389 {
390   Stage stage  = Stage::GetCurrent();
391   float width  = stage.GetSize().width;
392   float height = stage.GetSize().height;
393
394   //Flip model to account for DALi starting with (0, 0) at the top left.
395   Matrix scaleMatrix;
396   scaleMatrix.SetIdentityAndScale(Vector3(1.0, -1.0, 1.0));
397
398   mShader.RegisterProperty(STAGE_OFFSET_UNIFORM_NAME, Vector2(width, height) / 2.0f);
399   mShader.RegisterProperty(LIGHT_POSITION_UNIFORM_NAME, mLightPosition);
400   mShader.RegisterProperty(OBJECT_MATRIX_UNIFORM_NAME, scaleMatrix);
401   mShader.RegisterProperty(OBJECT_DIMENSIONS_UNIFORM_NAME, mObjectDimensions);
402 }
403
404 void PrimitiveVisual::CreateShader()
405 {
406   mShader = Shader::New(SHADER_PRIMITIVE_VISUAL_SHADER_VERT, SHADER_PRIMITIVE_VISUAL_SHADER_FRAG);
407   UpdateShaderUniforms();
408 }
409
410 void PrimitiveVisual::CreateGeometry()
411 {
412   Dali::Vector<Vertex>         vertices;
413   Dali::Vector<unsigned short> indices;
414
415   switch(mPrimitiveType)
416   {
417     case Toolkit::PrimitiveVisual::Shape::SPHERE:
418     {
419       CreateSphere(vertices, indices, mSlices, mStacks);
420       break;
421     }
422     case Toolkit::PrimitiveVisual::Shape::CONE:
423     {
424       //Create a conic with zero top radius.
425       CreateConic(vertices, indices, 0, mScaleBottomRadius, mScaleHeight, mSlices);
426       break;
427     }
428     case Toolkit::PrimitiveVisual::Shape::CYLINDER:
429     {
430       //Create a conic with equal radii on the top and bottom.
431       CreateConic(vertices, indices, mScaleRadius, mScaleRadius, mScaleHeight, mSlices);
432       break;
433     }
434     case Toolkit::PrimitiveVisual::Shape::CUBE:
435     {
436       //Create a cube by creating a bevelled cube with minimum bevel.
437       CreateBevelledCube(vertices, indices, mScaleDimensions, 0.0, 0.0);
438       break;
439     }
440     case Toolkit::PrimitiveVisual::Shape::OCTAHEDRON:
441     {
442       //Create an octahedron by creating a bevelled cube with maximum bevel.
443       CreateBevelledCube(vertices, indices, mScaleDimensions, 1.0, mBevelSmoothness);
444       break;
445     }
446     case Toolkit::PrimitiveVisual::Shape::BEVELLED_CUBE:
447     {
448       CreateBevelledCube(vertices, indices, mScaleDimensions, mBevelPercentage, mBevelSmoothness);
449       break;
450     }
451     case Toolkit::PrimitiveVisual::Shape::CONICAL_FRUSTUM:
452     {
453       CreateConic(vertices, indices, mScaleTopRadius, mScaleBottomRadius, mScaleHeight, mSlices);
454       break;
455     }
456   }
457
458   mGeometry = Geometry::New();
459
460   //Vertices
461   Property::Map vertexFormat;
462   vertexFormat[POSITION]       = Property::VECTOR3;
463   vertexFormat[NORMAL]         = Property::VECTOR3;
464   VertexBuffer surfaceVertices = VertexBuffer::New(vertexFormat);
465   surfaceVertices.SetData(&vertices[0], vertices.Size());
466
467   mGeometry.AddVertexBuffer(surfaceVertices);
468
469   //Indices for triangle formulation
470   mGeometry.SetIndexBuffer(&indices[0], indices.Size());
471 }
472
473 void PrimitiveVisual::CreateSphere(Vector<Vertex>& vertices, Vector<unsigned short>& indices, int slices, int stacks)
474 {
475   ComputeSphereVertices(vertices, slices, stacks);
476   FormSphereTriangles(indices, slices, stacks);
477
478   mObjectDimensions = Vector3::ONE;
479 }
480
481 void PrimitiveVisual::CreateConic(Vector<Vertex>& vertices, Vector<unsigned short>& indices, float scaleTopRadius, float scaleBottomRadius, float scaleHeight, int slices)
482 {
483   ComputeConicVertices(vertices, scaleTopRadius, scaleBottomRadius, scaleHeight, slices);
484   FormConicTriangles(indices, scaleTopRadius, scaleBottomRadius, slices);
485
486   //Determine object dimensions, and scale them to be between 0.0 and 1.0.
487   float xDimension       = std::max(scaleTopRadius, scaleBottomRadius) * 2.0f;
488   float yDimension       = scaleHeight;
489   float largestDimension = std::max(xDimension, yDimension);
490
491   mObjectDimensions = Vector3(xDimension / largestDimension, yDimension / largestDimension, xDimension / largestDimension);
492 }
493
494 void PrimitiveVisual::CreateBevelledCube(Vector<Vertex>& vertices, Vector<unsigned short>& indices, Vector3 dimensions, float bevelPercentage, float bevelSmoothness)
495 {
496   float maxDimension = std::max(std::max(dimensions.x, dimensions.y), dimensions.z);
497   dimensions         = dimensions / maxDimension;
498
499   if(bevelPercentage <= MIN_BEVEL_PERCENTAGE) //No bevel, form a cube.
500   {
501     ComputeCubeVertices(vertices, dimensions);
502     FormCubeTriangles(indices);
503   }
504   else if(bevelPercentage >= MAX_BEVEL_PERCENTAGE) //Max bevel, form an octahedron.
505   {
506     ComputeOctahedronVertices(vertices, dimensions, bevelSmoothness);
507     FormOctahedronTriangles(indices);
508   }
509   else //In between, form a bevelled cube.
510   {
511     ComputeBevelledCubeVertices(vertices, dimensions, bevelPercentage, bevelSmoothness);
512     FormBevelledCubeTriangles(indices);
513   }
514
515   mObjectDimensions = dimensions;
516 }
517
518 void PrimitiveVisual::ComputeCircleTables(Vector<float>& sinTable, Vector<float>& cosTable, int divisions, bool halfCircle)
519 {
520   if(divisions < 0)
521   {
522     return;
523   }
524
525   const float angleDivision = (halfCircle ? 1.0f : 2.0f) * Dali::Math::PI / (float)divisions;
526
527   sinTable.Resize(divisions);
528   cosTable.Resize(divisions);
529
530   for(int i = 0; i < divisions; i++)
531   {
532     sinTable[i] = sin(angleDivision * i);
533     cosTable[i] = cos(angleDivision * i);
534   }
535 }
536
537 void PrimitiveVisual::ComputeSphereVertices(Vector<Vertex>& vertices, int slices, int stacks)
538 {
539   //Tables for calculating slices angles and stacks angles, respectively.
540   Vector<float> sinTable1;
541   Vector<float> cosTable1;
542   Vector<float> sinTable2;
543   Vector<float> cosTable2;
544
545   ComputeCircleTables(sinTable1, cosTable1, slices, false);
546   ComputeCircleTables(sinTable2, cosTable2, stacks, true);
547
548   int numVertices = slices * (stacks - 1) + 2;
549   vertices.Resize(numVertices);
550
551   int   vertexIndex = 0; //Track progress through vertices.
552   float x;
553   float y;
554   float z;
555
556   //Top stack.
557   vertices[vertexIndex].position = Vector3(0.0, 0.5, 0.0);
558   vertices[vertexIndex].normal   = Vector3(0.0, 1.0, 0.0);
559   vertexIndex++;
560
561   //Middle stacks.
562   for(int i = 1; i < stacks; i++)
563   {
564     for(int j = 0; j < slices; j++, vertexIndex++)
565     {
566       x = cosTable1[j] * sinTable2[i];
567       y = cosTable2[i];
568       z = sinTable1[j] * sinTable2[i];
569
570       vertices[vertexIndex].position = Vector3(x / 2.0f, y / 2.0f, z / 2.0f);
571       vertices[vertexIndex].normal   = Vector3(x, y, z);
572     }
573   }
574
575   //Bottom stack.
576   vertices[vertexIndex].position = Vector3(0.0, -0.5, 0.0);
577   vertices[vertexIndex].normal   = Vector3(0.0, -1.0, 0.0);
578 }
579
580 void PrimitiveVisual::FormSphereTriangles(Vector<unsigned short>& indices, int slices, int stacks)
581 {
582   if(stacks <= 1)
583   {
584     //Set indices to placeholder "error" values.
585     //This will display nothing, which is the expected behaviour for this edge case.
586     indices.Resize(3);
587     return;
588   }
589
590   int numTriangles = 2 * slices * (stacks - 1);
591
592   indices.Resize(3 * numTriangles);
593
594   int indiceIndex            = 0; //Used to keep track of progress through indices.
595   int previousCycleBeginning = 1; //Stores the index of the vertex that started the cycle of the previous stack.
596   int currentCycleBeginning  = 1 + slices;
597
598   //Top stack. Loop from index 1 to index slices, as not counting the very first vertex.
599   for(int i = 1; i <= slices; i++, indiceIndex += 3)
600   {
601     indices[indiceIndex] = 0;
602     if(i == slices)
603     {
604       //End, so loop around.
605       indices[indiceIndex + 1] = 1;
606     }
607     else
608     {
609       indices[indiceIndex + 1] = i + 1;
610     }
611     indices[indiceIndex + 2] = i;
612   }
613
614   //Middle Stacks. Want to form triangles between the top and bottom stacks, so loop up to the number of stacks - 2.
615   for(int i = 0; i < stacks - 2; i++, previousCycleBeginning += slices, currentCycleBeginning += slices)
616   {
617     for(int j = 0; j < slices; j++, indiceIndex += 6)
618     {
619       if(j == slices - 1)
620       {
621         //End, so loop around.
622         indices[indiceIndex]     = previousCycleBeginning + j;
623         indices[indiceIndex + 1] = previousCycleBeginning;
624         indices[indiceIndex + 2] = currentCycleBeginning + j;
625         indices[indiceIndex + 3] = currentCycleBeginning + j;
626         indices[indiceIndex + 4] = previousCycleBeginning;
627         indices[indiceIndex + 5] = currentCycleBeginning;
628       }
629       else
630       {
631         indices[indiceIndex]     = previousCycleBeginning + j;
632         indices[indiceIndex + 1] = previousCycleBeginning + 1 + j;
633         indices[indiceIndex + 2] = currentCycleBeginning + j;
634         indices[indiceIndex + 3] = currentCycleBeginning + j;
635         indices[indiceIndex + 4] = previousCycleBeginning + 1 + j;
636         indices[indiceIndex + 5] = currentCycleBeginning + 1 + j;
637       }
638     }
639   }
640
641   //Bottom stack. Loop around the last stack from the previous loop, and go up to the penultimate vertex.
642   for(int i = 0; i < slices; i++, indiceIndex += 3)
643   {
644     indices[indiceIndex]     = previousCycleBeginning + slices;
645     indices[indiceIndex + 1] = previousCycleBeginning + i;
646     if(i == slices - 1)
647     {
648       //End, so loop around.
649       indices[indiceIndex + 2] = previousCycleBeginning;
650     }
651     else
652     {
653       indices[indiceIndex + 2] = previousCycleBeginning + i + 1;
654     }
655   }
656 }
657
658 void PrimitiveVisual::ComputeConicVertices(Vector<Vertex>& vertices, float scaleTopRadius, float scaleBottomRadius, float scaleHeight, int slices)
659 {
660   int           vertexIndex = 0; //Track progress through vertices.
661   Vector<float> sinTable;
662   Vector<float> cosTable;
663
664   ComputeCircleTables(sinTable, cosTable, slices, false);
665
666   int numVertices = 2; //Always will have one at the top and one at the bottom.
667
668   //Add vertices for each circle. Need two per point for different face normals.
669   if(scaleTopRadius > 0.0)
670   {
671     numVertices += 2 * slices;
672   }
673   if(scaleBottomRadius > 0.0)
674   {
675     numVertices += 2 * slices;
676   }
677
678   vertices.Resize(numVertices);
679
680   //Scale to bounding region of -0.5 to 0.5 (i.e range of 1).
681   float biggestObjectDimension = std::max(std::max(scaleTopRadius * 2.0f, scaleBottomRadius * 2.0f), scaleHeight);
682   scaleTopRadius               = scaleTopRadius / biggestObjectDimension;
683   scaleBottomRadius            = scaleBottomRadius / biggestObjectDimension;
684
685   //Dimensions for vertex coordinates. Y is constant, and so can be initialised now.
686   float x;
687   float y = scaleHeight / biggestObjectDimension / 2.0f;
688   float z;
689
690   //Top center.
691   vertices[0].position = Vector3(0, y, 0);
692   vertices[0].normal   = Vector3(0, 1, 0);
693   vertexIndex++;
694
695   //Top circle.
696   if(scaleTopRadius > 0.0)
697   {
698     //Loop around the circle.
699     for(int i = 0; i < slices; i++, vertexIndex++)
700     {
701       x = sinTable[i] * scaleTopRadius;
702       z = cosTable[i] * scaleTopRadius;
703
704       //Upward-facing normal.
705       vertices[vertexIndex].position = Vector3(x, y, z);
706       vertices[vertexIndex].normal   = Vector3(0, 1, 0);
707
708       //Outward-facing normal.
709       vertices[vertexIndex + slices].position = Vector3(x, y, z);
710       vertices[vertexIndex + slices].normal   = Vector3(x, 0, z);
711     }
712
713     vertexIndex += slices;
714   }
715
716   //Bottom circle.
717   if(scaleBottomRadius > 0.0)
718   {
719     //Loop around the circle.
720     for(int i = 0; i < slices; i++, vertexIndex++)
721     {
722       x = sinTable[i] * scaleBottomRadius;
723       z = cosTable[i] * scaleBottomRadius;
724
725       //Outward-facing normal.
726       vertices[vertexIndex].position = Vector3(x, -y, z);
727       vertices[vertexIndex].normal   = Vector3(x, 0, z);
728
729       //Downward-facing normal.
730       vertices[vertexIndex + slices].position = Vector3(x, -y, z);
731       vertices[vertexIndex + slices].normal   = Vector3(0, -1, 0);
732     }
733
734     vertexIndex += slices;
735   }
736
737   //Bottom center.
738   vertices[vertexIndex].position = Vector3(0, -y, 0);
739   vertices[vertexIndex].normal   = Vector3(0, -1, 0);
740   vertexIndex++;
741 }
742
743 void PrimitiveVisual::FormConicTriangles(Vector<unsigned short>& indices, float scaleTopRadius, float scaleBottomRadius, int slices)
744 {
745   int  indiceIndex  = 0; //Track progress through indices.
746   int  numTriangles = 0;
747   bool coneTop      = scaleTopRadius <= 0.0;
748   bool coneBottom   = scaleBottomRadius <= 0.0;
749
750   if(coneTop && coneBottom)
751   {
752     //Set indices to placeholder "error" values.
753     //This will display nothing, which is the expected behaviour for this edge case.
754     indices.Resize(3);
755     return;
756   }
757
758   if(!coneTop)
759   {
760     numTriangles += 2 * slices;
761   }
762   if(!coneBottom)
763   {
764     numTriangles += 2 * slices;
765   }
766
767   indices.Resize(3 * numTriangles);
768
769   //Switch on the type of conic we have.
770   if(!coneTop && !coneBottom)
771   {
772     //Top circle. Start at index of first outer point and go around.
773     for(int i = 1; i <= slices; i++, indiceIndex += 3)
774     {
775       indices[indiceIndex]     = 0;
776       indices[indiceIndex + 1] = i;
777       if(i == slices)
778       {
779         //End, so loop around.
780         indices[indiceIndex + 2] = 1;
781       }
782       else
783       {
784         indices[indiceIndex + 2] = i + 1;
785       }
786     }
787
788     int topCycleBeginning    = slices + 1;
789     int bottomCycleBeginning = topCycleBeginning + slices;
790
791     //Vertical edges.
792     for(int i = 0; i < slices; i++, indiceIndex += 6)
793     {
794       if(i == slices - 1)
795       {
796         //End, so loop around.
797         indices[indiceIndex]     = topCycleBeginning + i;
798         indices[indiceIndex + 1] = bottomCycleBeginning + i;
799         indices[indiceIndex + 2] = topCycleBeginning;
800         indices[indiceIndex + 3] = bottomCycleBeginning + i;
801         indices[indiceIndex + 4] = bottomCycleBeginning;
802         indices[indiceIndex + 5] = topCycleBeginning;
803       }
804       else
805       {
806         indices[indiceIndex]     = topCycleBeginning + i;
807         indices[indiceIndex + 1] = bottomCycleBeginning + i;
808         indices[indiceIndex + 2] = topCycleBeginning + 1 + i;
809         indices[indiceIndex + 3] = bottomCycleBeginning + i;
810         indices[indiceIndex + 4] = bottomCycleBeginning + 1 + i;
811         indices[indiceIndex + 5] = topCycleBeginning + 1 + i;
812       }
813     }
814
815     int bottomFaceCycleBeginning = bottomCycleBeginning + slices;
816
817     //Bottom circle.
818     for(int i = 0; i < slices; i++, indiceIndex += 3)
819     {
820       indices[indiceIndex] = bottomFaceCycleBeginning;
821       if(i == slices - 1)
822       {
823         //End, so loop around.
824         indices[indiceIndex + 1] = bottomFaceCycleBeginning;
825       }
826       else
827       {
828         indices[indiceIndex + 1] = bottomFaceCycleBeginning + i + 1;
829       }
830       indices[indiceIndex + 2] = bottomFaceCycleBeginning + i;
831     }
832   }
833   else if(!coneTop || !coneBottom)
834   {
835     //Top circle/edges. Start at index of first outer point and go around.
836     for(int i = 1; i <= slices; i++, indiceIndex += 3)
837     {
838       indices[indiceIndex]     = 0;
839       indices[indiceIndex + 1] = i;
840       if(i == slices)
841       {
842         //End, so loop around.
843         indices[indiceIndex + 2] = 1;
844       }
845       else
846       {
847         indices[indiceIndex + 2] = i + 1;
848       }
849     }
850
851     //Bottom circle/edges. Start at index of first outer point and go around.
852     for(int i = 1; i <= slices; i++, indiceIndex += 3)
853     {
854       indices[indiceIndex] = 2 * slices + 1;
855       if(i == slices)
856       {
857         //End, so loop around.
858         indices[indiceIndex + 1] = slices + 1;
859       }
860       else
861       {
862         indices[indiceIndex + 1] = slices + i + 1;
863       }
864       indices[indiceIndex + 2] = slices + i;
865     }
866   }
867 }
868
869 void PrimitiveVisual::ComputeCubeVertices(Vector<Vertex>& vertices, Vector3 dimensions)
870 {
871   int   numVertices = 4 * 6; //Four per face.
872   int   vertexIndex = 0;     //Tracks progress through vertices.
873   float scaledX     = 0.5 * dimensions.x;
874   float scaledY     = 0.5 * dimensions.y;
875   float scaledZ     = 0.5 * dimensions.z;
876
877   vertices.Resize(numVertices);
878
879   Vector<Vector3> positions; //Stores vertex positions, which are shared between vertexes at the same position but with a different normal.
880   positions.Resize(8);
881   Vector<Vector3> normals; //Stores normals, which are shared between vertexes of the same face.
882   normals.Resize(6);
883
884   positions[0] = Vector3(-scaledX, scaledY, -scaledZ);
885   positions[1] = Vector3(scaledX, scaledY, -scaledZ);
886   positions[2] = Vector3(scaledX, scaledY, scaledZ);
887   positions[3] = Vector3(-scaledX, scaledY, scaledZ);
888   positions[4] = Vector3(-scaledX, -scaledY, -scaledZ);
889   positions[5] = Vector3(scaledX, -scaledY, -scaledZ);
890   positions[6] = Vector3(scaledX, -scaledY, scaledZ);
891   positions[7] = Vector3(-scaledX, -scaledY, scaledZ);
892
893   normals[0] = Vector3(0, 1, 0);
894   normals[1] = Vector3(0, 0, -1);
895   normals[2] = Vector3(1, 0, 0);
896   normals[3] = Vector3(0, 0, 1);
897   normals[4] = Vector3(-1, 0, 0);
898   normals[5] = Vector3(0, -1, 0);
899
900   //Top face, upward normals.
901   for(int i = 0; i < 4; i++, vertexIndex++)
902   {
903     vertices[vertexIndex].position = positions[i];
904     vertices[vertexIndex].normal   = normals[0];
905   }
906
907   //Top face, outward normals.
908   for(int i = 0; i < 4; i++, vertexIndex += 2)
909   {
910     vertices[vertexIndex].position = positions[i];
911     vertices[vertexIndex].normal   = normals[i + 1];
912
913     if(i == 3)
914     {
915       //End, so loop around.
916       vertices[vertexIndex + 1].position = positions[0];
917     }
918     else
919     {
920       vertices[vertexIndex + 1].position = positions[i + 1];
921     }
922     vertices[vertexIndex + 1].normal = normals[i + 1];
923   }
924
925   //Bottom face, outward normals.
926   for(int i = 0; i < 4; i++, vertexIndex += 2)
927   {
928     vertices[vertexIndex].position = positions[i + 4];
929     vertices[vertexIndex].normal   = normals[i + 1];
930
931     if(i == 3)
932     {
933       //End, so loop around.
934       vertices[vertexIndex + 1].position = positions[4];
935     }
936     else
937     {
938       vertices[vertexIndex + 1].position = positions[i + 5];
939     }
940     vertices[vertexIndex + 1].normal = normals[i + 1];
941   }
942
943   //Bottom face, downward normals.
944   for(int i = 0; i < 4; i++, vertexIndex++)
945   {
946     vertices[vertexIndex].position = positions[i + 4];
947     vertices[vertexIndex].normal   = normals[5];
948   }
949 }
950
951 void PrimitiveVisual::FormCubeTriangles(Vector<unsigned short>& indices)
952 {
953   int numTriangles  = 12;
954   int triangleIndex = 0; //Track progress through indices.
955
956   indices.Resize(3 * numTriangles);
957
958   //Top face.
959   indices[triangleIndex]     = 0;
960   indices[triangleIndex + 1] = 2;
961   indices[triangleIndex + 2] = 1;
962   indices[triangleIndex + 3] = 2;
963   indices[triangleIndex + 4] = 0;
964   indices[triangleIndex + 5] = 3;
965   triangleIndex += 6;
966
967   int topFaceStart    = 4;
968   int bottomFaceStart = 12;
969
970   //Side faces.
971   for(int i = 0; i < 8; i += 2, triangleIndex += 6)
972   {
973     indices[triangleIndex]     = i + topFaceStart;
974     indices[triangleIndex + 1] = i + topFaceStart + 1;
975     indices[triangleIndex + 2] = i + bottomFaceStart + 1;
976     indices[triangleIndex + 3] = i + topFaceStart;
977     indices[triangleIndex + 4] = i + bottomFaceStart + 1;
978     indices[triangleIndex + 5] = i + bottomFaceStart;
979   }
980
981   //Bottom face.
982   indices[triangleIndex]     = 20;
983   indices[triangleIndex + 1] = 21;
984   indices[triangleIndex + 2] = 22;
985   indices[triangleIndex + 3] = 22;
986   indices[triangleIndex + 4] = 23;
987   indices[triangleIndex + 5] = 20;
988 }
989
990 void PrimitiveVisual::ComputeOctahedronVertices(Vector<Vertex>& vertices, Vector3 dimensions, float smoothness)
991 {
992   int   numVertices = 3 * 8; //Three per face
993   int   vertexIndex = 0;     //Tracks progress through vertices.
994   float scaledX     = 0.5 * dimensions.x;
995   float scaledY     = 0.5 * dimensions.y;
996   float scaledZ     = 0.5 * dimensions.z;
997
998   vertices.Resize(numVertices);
999
1000   Vector<Vector3> positions; //Stores vertex positions, which are shared between vertexes at the same position but with a different normal.
1001   positions.Resize(6);
1002   Vector<Vector3> normals; //Stores normals, which are shared between vertexes of the same face.
1003   normals.Resize(8);
1004   Vector<Vector3> outerNormals; //Holds normals that point outwards at each vertex.
1005   outerNormals.Resize(6);
1006
1007   positions[0] = Vector3(0.0, scaledY, 0.0);
1008   positions[1] = Vector3(-scaledX, 0.0, 0.0);
1009   positions[2] = Vector3(0.0, 0.0, -scaledZ);
1010   positions[3] = Vector3(scaledX, 0.0, 0.0);
1011   positions[4] = Vector3(0.0, 0.0, scaledZ);
1012   positions[5] = Vector3(0.0, -scaledY, 0.0);
1013
1014   normals[0] = Vector3(-1, 1, -1);
1015   normals[1] = Vector3(1, 1, -1);
1016   normals[2] = Vector3(1, 1, 1);
1017   normals[3] = Vector3(-1, 1, 1);
1018   normals[4] = Vector3(-1, -1, -1);
1019   normals[5] = Vector3(1, -1, -1);
1020   normals[6] = Vector3(1, -1, 1);
1021   normals[7] = Vector3(-1, -1, 1);
1022
1023   outerNormals[0] = Vector3(0, 1, 0);
1024   outerNormals[1] = Vector3(-1, 0, 0);
1025   outerNormals[2] = Vector3(0, 0, -1);
1026   outerNormals[3] = Vector3(1, 0, 0);
1027   outerNormals[4] = Vector3(0, 0, 1);
1028   outerNormals[5] = Vector3(0, -1, 0);
1029
1030   //Loop through top faces.
1031   for(int i = 0; i < 4; i++, vertexIndex += 3)
1032   {
1033     if(i == 3)
1034     {
1035       //End, so loop around.
1036       vertices[vertexIndex].position     = positions[0];
1037       vertices[vertexIndex].normal       = outerNormals[0] * smoothness + normals[i] * (1 - smoothness);
1038       vertices[vertexIndex + 1].position = positions[1];
1039       vertices[vertexIndex + 1].normal   = outerNormals[1] * smoothness + normals[i] * (1 - smoothness);
1040       vertices[vertexIndex + 2].position = positions[i + 1];
1041       vertices[vertexIndex + 2].normal   = outerNormals[i + 1] * smoothness + normals[i] * (1 - smoothness);
1042     }
1043     else
1044     {
1045       vertices[vertexIndex].position     = positions[0];
1046       vertices[vertexIndex].normal       = outerNormals[0] * smoothness + normals[i] * (1 - smoothness);
1047       vertices[vertexIndex + 1].position = positions[i + 2];
1048       vertices[vertexIndex + 1].normal   = outerNormals[i + 2] * smoothness + normals[i] * (1 - smoothness);
1049       vertices[vertexIndex + 2].position = positions[i + 1];
1050       vertices[vertexIndex + 2].normal   = outerNormals[i + 1] * smoothness + normals[i] * (1 - smoothness);
1051     }
1052   }
1053
1054   //Loop through bottom faces.
1055   for(int i = 0; i < 4; i++, vertexIndex += 3)
1056   {
1057     if(i == 3)
1058     {
1059       //End, so loop around.
1060       vertices[vertexIndex].position     = positions[5];
1061       vertices[vertexIndex].normal       = outerNormals[5] * smoothness + normals[i + 4] * (1 - smoothness);
1062       vertices[vertexIndex + 1].position = positions[i + 1];
1063       vertices[vertexIndex + 1].normal   = outerNormals[i + 1] * smoothness + normals[i + 4] * (1 - smoothness);
1064       vertices[vertexIndex + 2].position = positions[1];
1065       vertices[vertexIndex + 2].normal   = outerNormals[1] * smoothness + normals[i + 4] * (1 - smoothness);
1066     }
1067     else
1068     {
1069       vertices[vertexIndex].position     = positions[5];
1070       vertices[vertexIndex].normal       = outerNormals[5] * smoothness + normals[i + 4] * (1 - smoothness);
1071       vertices[vertexIndex + 1].position = positions[i + 1];
1072       vertices[vertexIndex + 1].normal   = outerNormals[i + 1] * smoothness + normals[i + 4] * (1 - smoothness);
1073       vertices[vertexIndex + 2].position = positions[i + 2];
1074       vertices[vertexIndex + 2].normal   = outerNormals[i + 2] * smoothness + normals[i + 4] * (1 - smoothness);
1075     }
1076   }
1077 }
1078
1079 void PrimitiveVisual::FormOctahedronTriangles(Vector<unsigned short>& indices)
1080 {
1081   int numTriangles = 8;
1082   int numIndices   = numTriangles * 3;
1083
1084   indices.Resize(numIndices);
1085
1086   for(unsigned short i = 0; i < numIndices; i++)
1087   {
1088     indices[i] = i;
1089   }
1090 }
1091
1092 void PrimitiveVisual::ComputeBevelledCubeVertices(Vector<Vertex>& vertices, Vector3 dimensions, float bevelPercentage, float bevelSmoothness)
1093 {
1094   int numPositions  = 24;
1095   int numFaces      = 26;
1096   int numOuterFaces = 6;
1097   int numVertices   = 6 * 4 + 12 * 4 + 8 * 3; //Six outer faces, 12 slanting rectangles, 8 slanting triangles.
1098   int vertexIndex   = 0;                      //Track progress through vertices.
1099   int normalIndex   = 0;                      //Track progress through normals, as vertices are calculated per face.
1100
1101   float minDimension = std::min(std::min(dimensions.x, dimensions.y), dimensions.z);
1102   float bevelAmount  = 0.5 * std::min(bevelPercentage, minDimension); //Cap bevel amount if necessary.
1103
1104   //Distances from centre to outer edge points.
1105   float outerX = 0.5 * dimensions.x;
1106   float outerY = 0.5 * dimensions.y;
1107   float outerZ = 0.5 * dimensions.z;
1108
1109   //Distances from centre to bevelled points.
1110   float bevelX = outerX - bevelAmount;
1111   float bevelY = outerY - bevelAmount;
1112   float bevelZ = outerZ - bevelAmount;
1113
1114   Vector<Vector3> positions; //Holds object points, to be shared between vertexes.
1115   positions.Resize(numPositions);
1116   Vector<Vector3> normals; //Holds face normals, to be shared between vertexes.
1117   normals.Resize(numFaces);
1118   Vector<Vector3> outerNormals; //Holds normals of the outermost faces specifically.
1119   outerNormals.Resize(numOuterFaces);
1120   vertices.Resize(numVertices);
1121
1122   //Topmost face positions.
1123   positions[0] = Vector3(-bevelX, outerY, -bevelZ);
1124   positions[1] = Vector3(bevelX, outerY, -bevelZ);
1125   positions[2] = Vector3(bevelX, outerY, bevelZ);
1126   positions[3] = Vector3(-bevelX, outerY, bevelZ);
1127
1128   //Second layer positions.
1129   positions[4]  = Vector3(-outerX, bevelY, -bevelZ);
1130   positions[5]  = Vector3(-bevelX, bevelY, -outerZ);
1131   positions[6]  = Vector3(bevelX, bevelY, -outerZ);
1132   positions[7]  = Vector3(outerX, bevelY, -bevelZ);
1133   positions[8]  = Vector3(outerX, bevelY, bevelZ);
1134   positions[9]  = Vector3(bevelX, bevelY, outerZ);
1135   positions[10] = Vector3(-bevelX, bevelY, outerZ);
1136   positions[11] = Vector3(-outerX, bevelY, bevelZ);
1137
1138   //Third layer positions.
1139   positions[12] = Vector3(-outerX, -bevelY, -bevelZ);
1140   positions[13] = Vector3(-bevelX, -bevelY, -outerZ);
1141   positions[14] = Vector3(bevelX, -bevelY, -outerZ);
1142   positions[15] = Vector3(outerX, -bevelY, -bevelZ);
1143   positions[16] = Vector3(outerX, -bevelY, bevelZ);
1144   positions[17] = Vector3(bevelX, -bevelY, outerZ);
1145   positions[18] = Vector3(-bevelX, -bevelY, outerZ);
1146   positions[19] = Vector3(-outerX, -bevelY, bevelZ);
1147
1148   //Bottom-most face positions.
1149   positions[20] = Vector3(-bevelX, -outerY, -bevelZ);
1150   positions[21] = Vector3(bevelX, -outerY, -bevelZ);
1151   positions[22] = Vector3(bevelX, -outerY, bevelZ);
1152   positions[23] = Vector3(-bevelX, -outerY, bevelZ);
1153
1154   //Top face normal.
1155   normals[0] = Vector3(0, 1, 0);
1156
1157   //Top slope normals.
1158   normals[1] = Vector3(-1, 1, -1);
1159   normals[2] = Vector3(0, 1, -1);
1160   normals[3] = Vector3(1, 1, -1);
1161   normals[4] = Vector3(1, 1, 0);
1162   normals[5] = Vector3(1, 1, 1);
1163   normals[6] = Vector3(0, 1, 1);
1164   normals[7] = Vector3(-1, 1, 1);
1165   normals[8] = Vector3(-1, 1, 0);
1166
1167   //Side normals.
1168   normals[9]  = Vector3(-1, 0, -1);
1169   normals[10] = Vector3(0, 0, -1);
1170   normals[11] = Vector3(1, 0, -1);
1171   normals[12] = Vector3(1, 0, 0);
1172   normals[13] = Vector3(1, 0, 1);
1173   normals[14] = Vector3(0, 0, 1);
1174   normals[15] = Vector3(-1, 0, 1);
1175   normals[16] = Vector3(-1, 0, 0);
1176
1177   //Bottom slope normals.
1178   normals[17] = Vector3(-1, -1, -1);
1179   normals[18] = Vector3(0, -1, -1);
1180   normals[19] = Vector3(1, -1, -1);
1181   normals[20] = Vector3(1, -1, 0);
1182   normals[21] = Vector3(1, -1, 1);
1183   normals[22] = Vector3(0, -1, 1);
1184   normals[23] = Vector3(-1, -1, 1);
1185   normals[24] = Vector3(-1, -1, 0);
1186
1187   //Bottom face normal.
1188   normals[25] = Vector3(0, -1, 0);
1189
1190   //Top, back, right, front, left and bottom faces, respectively.
1191   outerNormals[0] = Vector3(0, 1, 0);
1192   outerNormals[1] = Vector3(0, 0, -1);
1193   outerNormals[2] = Vector3(1, 0, 0);
1194   outerNormals[3] = Vector3(0, 0, 1);
1195   outerNormals[4] = Vector3(-1, 0, 0);
1196   outerNormals[5] = Vector3(0, -1, 0);
1197
1198   //Topmost face vertices.
1199   for(int i = 0; i < 4; i++, vertexIndex++)
1200   {
1201     vertices[vertexIndex].position = positions[i];
1202     vertices[vertexIndex].normal   = normals[normalIndex];
1203   }
1204
1205   normalIndex++;
1206
1207   //Top slope vertices.
1208   for(int i = 0; i < 4; i++, vertexIndex += 7, normalIndex += 2)
1209   {
1210     //Triangle part
1211     vertices[vertexIndex].position     = positions[i];
1212     vertices[vertexIndex].normal       = outerNormals[0] * bevelSmoothness + normals[normalIndex] * (1 - bevelSmoothness);
1213     vertices[vertexIndex + 1].position = positions[2 * i + 4];
1214     vertices[vertexIndex + 1].normal   = outerNormals[(i == 0) ? 4 : i] * bevelSmoothness + normals[normalIndex] * (1 - bevelSmoothness);
1215     vertices[vertexIndex + 2].position = positions[2 * i + 5];
1216     vertices[vertexIndex + 2].normal   = outerNormals[i + 1] * bevelSmoothness + normals[normalIndex] * (1 - bevelSmoothness);
1217
1218     //Rectangle part
1219     if(i == 3)
1220     {
1221       //End, so loop around.
1222       vertices[vertexIndex + 3].position = positions[i];
1223       vertices[vertexIndex + 3].normal   = outerNormals[0] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
1224       vertices[vertexIndex + 4].position = positions[0];
1225       vertices[vertexIndex + 4].normal   = outerNormals[0] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
1226       vertices[vertexIndex + 5].position = positions[2 * i + 5];
1227       vertices[vertexIndex + 5].normal   = outerNormals[i + 1] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
1228       vertices[vertexIndex + 6].position = positions[4];
1229       vertices[vertexIndex + 6].normal   = outerNormals[i + 1] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
1230     }
1231     else
1232     {
1233       vertices[vertexIndex + 3].position = positions[i];
1234       vertices[vertexIndex + 3].normal   = outerNormals[0] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
1235       vertices[vertexIndex + 4].position = positions[i + 1];
1236       vertices[vertexIndex + 4].normal   = outerNormals[0] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
1237       vertices[vertexIndex + 5].position = positions[2 * i + 5];
1238       vertices[vertexIndex + 5].normal   = outerNormals[i + 1] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
1239       vertices[vertexIndex + 6].position = positions[2 * i + 6];
1240       vertices[vertexIndex + 6].normal   = outerNormals[i + 1] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
1241     }
1242   }
1243
1244   int secondCycleBeginning = 4;
1245   int thirdCycleBeginning  = secondCycleBeginning + 8;
1246   int bottomCycleBeginning = thirdCycleBeginning + 8;
1247
1248   //Side vertices.
1249   for(int i = 0; i < 8; i++, vertexIndex += 4, normalIndex++)
1250   {
1251     if(i == 7)
1252     {
1253       //End, so loop around.
1254       vertices[vertexIndex].position     = positions[secondCycleBeginning + i];
1255       vertices[vertexIndex].normal       = normals[normalIndex];
1256       vertices[vertexIndex + 1].position = positions[secondCycleBeginning];
1257       vertices[vertexIndex + 1].normal   = normals[normalIndex];
1258       vertices[vertexIndex + 2].position = positions[thirdCycleBeginning + i];
1259       vertices[vertexIndex + 2].normal   = normals[normalIndex];
1260       vertices[vertexIndex + 3].position = positions[thirdCycleBeginning];
1261       vertices[vertexIndex + 3].normal   = normals[normalIndex];
1262     }
1263     else if((i % 2) == 0)
1264     {
1265       //'even' faces are corner ones, and need smoothing.
1266       vertices[vertexIndex].position     = positions[secondCycleBeginning + i];
1267       vertices[vertexIndex].normal       = outerNormals[(i == 0) ? 4 : i / 2] * bevelSmoothness + normals[normalIndex] * (1 - bevelSmoothness);
1268       vertices[vertexIndex + 1].position = positions[secondCycleBeginning + i + 1];
1269       vertices[vertexIndex + 1].normal   = outerNormals[i / 2 + 1] * bevelSmoothness + normals[normalIndex] * (1 - bevelSmoothness);
1270       vertices[vertexIndex + 2].position = positions[thirdCycleBeginning + i];
1271       vertices[vertexIndex + 2].normal   = outerNormals[(i == 0) ? 4 : i / 2] * bevelSmoothness + normals[normalIndex] * (1 - bevelSmoothness);
1272       vertices[vertexIndex + 3].position = positions[thirdCycleBeginning + i + 1];
1273       vertices[vertexIndex + 3].normal   = outerNormals[i / 2 + 1] * bevelSmoothness + normals[normalIndex] * (1 - bevelSmoothness);
1274     }
1275     else
1276     {
1277       //'odd' faces are outer ones, and so don't need smoothing.
1278       vertices[vertexIndex].position     = positions[secondCycleBeginning + i];
1279       vertices[vertexIndex].normal       = normals[normalIndex];
1280       vertices[vertexIndex + 1].position = positions[secondCycleBeginning + i + 1];
1281       vertices[vertexIndex + 1].normal   = normals[normalIndex];
1282       vertices[vertexIndex + 2].position = positions[thirdCycleBeginning + i];
1283       vertices[vertexIndex + 2].normal   = normals[normalIndex];
1284       vertices[vertexIndex + 3].position = positions[thirdCycleBeginning + i + 1];
1285       vertices[vertexIndex + 3].normal   = normals[normalIndex];
1286     }
1287   }
1288
1289   //Bottom slope vertices.
1290   for(int i = 0; i < 4; i++, vertexIndex += 7, normalIndex += 2)
1291   {
1292     //Triangle part
1293     vertices[vertexIndex].position     = positions[thirdCycleBeginning + 2 * i];
1294     vertices[vertexIndex].normal       = outerNormals[(i == 0) ? 4 : i] * bevelSmoothness + normals[normalIndex] * (1 - bevelSmoothness);
1295     vertices[vertexIndex + 1].position = positions[thirdCycleBeginning + 2 * i + 1];
1296     vertices[vertexIndex + 1].normal   = outerNormals[i + 1] * bevelSmoothness + normals[normalIndex] * (1 - bevelSmoothness);
1297     vertices[vertexIndex + 2].position = positions[bottomCycleBeginning + i];
1298     vertices[vertexIndex + 2].normal   = outerNormals[5] * bevelSmoothness + normals[normalIndex] * (1 - bevelSmoothness);
1299
1300     //Rectangle part
1301     if(i == 3)
1302     {
1303       //End, so loop around.
1304       vertices[vertexIndex + 3].position = positions[thirdCycleBeginning + 2 * i + 1];
1305       vertices[vertexIndex + 3].normal   = outerNormals[i + 1] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
1306       vertices[vertexIndex + 4].position = positions[thirdCycleBeginning];
1307       vertices[vertexIndex + 4].normal   = outerNormals[i + 1] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
1308       vertices[vertexIndex + 5].position = positions[bottomCycleBeginning + i];
1309       vertices[vertexIndex + 5].normal   = outerNormals[5] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
1310       vertices[vertexIndex + 6].position = positions[bottomCycleBeginning];
1311       vertices[vertexIndex + 6].normal   = outerNormals[5] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
1312     }
1313     else
1314     {
1315       vertices[vertexIndex + 3].position = positions[thirdCycleBeginning + 2 * i + 1];
1316       vertices[vertexIndex + 3].normal   = outerNormals[i + 1] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
1317       vertices[vertexIndex + 4].position = positions[thirdCycleBeginning + 2 * i + 2];
1318       vertices[vertexIndex + 4].normal   = outerNormals[i + 1] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
1319       vertices[vertexIndex + 5].position = positions[bottomCycleBeginning + i];
1320       vertices[vertexIndex + 5].normal   = outerNormals[5] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
1321       vertices[vertexIndex + 6].position = positions[bottomCycleBeginning + i + 1];
1322       vertices[vertexIndex + 6].normal   = outerNormals[5] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
1323     }
1324   }
1325
1326   //Bottom-most face vertices.
1327   for(int i = 0; i < 4; i++, vertexIndex++)
1328   {
1329     vertices[vertexIndex].position = positions[bottomCycleBeginning + i];
1330     vertices[vertexIndex].normal   = normals[normalIndex];
1331   }
1332
1333   normalIndex++;
1334 }
1335
1336 void PrimitiveVisual::FormBevelledCubeTriangles(Vector<unsigned short>& indices)
1337 {
1338   int numTriangles = 44; //(Going from top to bottom, that's 2 + 12 + 16 + 12 + 2)
1339   int indiceIndex  = 0;  //Track progress through indices.
1340   int vertexIndex  = 0;  //Track progress through vertices as they're processed.
1341
1342   indices.Resize(3 * numTriangles);
1343
1344   //Top face.
1345   indices[indiceIndex]     = vertexIndex;
1346   indices[indiceIndex + 1] = vertexIndex + 2;
1347   indices[indiceIndex + 2] = vertexIndex + 1;
1348   indices[indiceIndex + 3] = vertexIndex + 0;
1349   indices[indiceIndex + 4] = vertexIndex + 3;
1350   indices[indiceIndex + 5] = vertexIndex + 2;
1351   indiceIndex += 6;
1352   vertexIndex += 4;
1353
1354   //Top slopes.
1355   for(int i = 0; i < 4; i++, indiceIndex += 9, vertexIndex += 7)
1356   {
1357     //Triangle part.
1358     indices[indiceIndex]     = vertexIndex;
1359     indices[indiceIndex + 1] = vertexIndex + 2;
1360     indices[indiceIndex + 2] = vertexIndex + 1;
1361
1362     //Rectangle part.
1363     indices[indiceIndex + 3] = vertexIndex + 3;
1364     indices[indiceIndex + 4] = vertexIndex + 4;
1365     indices[indiceIndex + 5] = vertexIndex + 5;
1366     indices[indiceIndex + 6] = vertexIndex + 4;
1367     indices[indiceIndex + 7] = vertexIndex + 6;
1368     indices[indiceIndex + 8] = vertexIndex + 5;
1369   }
1370
1371   //Side faces.
1372   for(int i = 0; i < 8; i++, indiceIndex += 6, vertexIndex += 4)
1373   {
1374     indices[indiceIndex]     = vertexIndex;
1375     indices[indiceIndex + 1] = vertexIndex + 1;
1376     indices[indiceIndex + 2] = vertexIndex + 2;
1377     indices[indiceIndex + 3] = vertexIndex + 1;
1378     indices[indiceIndex + 4] = vertexIndex + 3;
1379     indices[indiceIndex + 5] = vertexIndex + 2;
1380   }
1381
1382   //Bottom slopes.
1383   for(int i = 0; i < 4; i++, indiceIndex += 9, vertexIndex += 7)
1384   {
1385     //Triangle part.
1386     indices[indiceIndex]     = vertexIndex;
1387     indices[indiceIndex + 1] = vertexIndex + 1;
1388     indices[indiceIndex + 2] = vertexIndex + 2;
1389
1390     //Rectangle part.
1391     indices[indiceIndex + 3] = vertexIndex + 3;
1392     indices[indiceIndex + 4] = vertexIndex + 4;
1393     indices[indiceIndex + 5] = vertexIndex + 5;
1394     indices[indiceIndex + 6] = vertexIndex + 4;
1395     indices[indiceIndex + 7] = vertexIndex + 6;
1396     indices[indiceIndex + 8] = vertexIndex + 5;
1397   }
1398
1399   //Bottom face.
1400   indices[indiceIndex]     = vertexIndex;
1401   indices[indiceIndex + 1] = vertexIndex + 1;
1402   indices[indiceIndex + 2] = vertexIndex + 2;
1403   indices[indiceIndex + 3] = vertexIndex + 0;
1404   indices[indiceIndex + 4] = vertexIndex + 2;
1405   indices[indiceIndex + 5] = vertexIndex + 3;
1406   indiceIndex += 6;
1407   vertexIndex += 4;
1408 }
1409
1410 } // namespace Internal
1411
1412 } // namespace Toolkit
1413
1414 } // namespace Dali