2 * Copyright (c) 2022 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include "primitive-visual.h"
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>
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>
42 const int CUSTOM_PROPERTY_COUNT(6); // 5 transform properties+mix
45 DALI_ENUM_TO_STRING_TABLE_BEGIN(SHAPE_TYPE)
46 DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::PrimitiveVisual::Shape, SPHERE)
47 DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::PrimitiveVisual::Shape, CONE)
48 DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::PrimitiveVisual::Shape, CYLINDER)
49 DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::PrimitiveVisual::Shape, CUBE)
50 DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::PrimitiveVisual::Shape, OCTAHEDRON)
51 DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::PrimitiveVisual::Shape, BEVELLED_CUBE)
52 DALI_ENUM_TO_STRING_WITH_SCOPE(Toolkit::PrimitiveVisual::Shape, CONICAL_FRUSTUM)
53 DALI_ENUM_TO_STRING_TABLE_END(SHAPE_TYPE)
55 //Primitive property defaults
56 const int DEFAULT_SLICES = 128; ///< For spheres and conics
57 const int DEFAULT_STACKS = 128; ///< For spheres and conics
58 const float DEFAULT_SCALE_TOP_RADIUS = 1.0; ///< For conical frustums
59 const float DEFAULT_SCALE_BOTTOM_RADIUS = 1.5; ///< For cones and conical frustums
60 const float DEFAULT_SCALE_HEIGHT = 3.0; ///< For all conics
61 const float DEFAULT_SCALE_RADIUS = 1.0; ///< For cylinders
62 const float DEFAULT_BEVEL_PERCENTAGE = 0.0; ///< For bevelled cubes
63 const float DEFAULT_BEVEL_SMOOTHNESS = 0.0; ///< For bevelled cubes
64 const Vector4 DEFAULT_COLOR = Vector4(0.5, 0.5, 0.5, 1.0); ///< Grey, for all.
67 const int MIN_SLICES = 3; ///< Minimum number of slices for spheres and conics
68 const int MIN_STACKS = 2; ///< Minimum number of stacks for spheres and conics
69 const int MAX_PARTITIONS = 255; ///< Maximum number of slices or stacks for spheres and conics
70 const float MIN_BEVEL_PERCENTAGE = 0.0; ///< Minimum bevel percentage for bevelled cubes
71 const float MAX_BEVEL_PERCENTAGE = 1.0; ///< Maximum bevel percentage for bevelled cubes
72 const float MIN_SMOOTHNESS = 0.0; ///< Minimum bevel smoothness for bevelled cubes
73 const float MAX_SMOOTHNESS = 1.0; ///< Maximum bevel smoothness for bevelled cubes
75 //Specific shape labels.
76 const char* const SPHERE_LABEL("SPHERE");
77 const char* const CONE_LABEL("CONE");
78 const char* const CYLINDER_LABEL("CYLINDER");
79 const char* const CUBE_LABEL("CUBE");
80 const char* const OCTAHEDRON_LABEL("OCTAHEDRON");
81 const char* const BEVELLED_CUBE_LABEL("BEVELLED_CUBE");
82 const char* const CONICAL_FRUSTUM_LABEL("CONICAL_FRUSTUM");
85 const char* const OBJECT_MATRIX_UNIFORM_NAME("uObjectMatrix");
86 const char* const OBJECT_DIMENSIONS_UNIFORM_NAME("uObjectDimensions");
87 const char* const STAGE_OFFSET_UNIFORM_NAME("uStageOffset");
90 const char* const POSITION("aPosition");
91 const char* const NORMAL("aNormal");
92 const char* const INDICES("aIndices");
94 } // unnamed namespace
96 PrimitiveVisualPtr PrimitiveVisual::New(VisualFactoryCache& factoryCache, const Property::Map& properties)
98 PrimitiveVisualPtr primitiveVisualPtr(new PrimitiveVisual(factoryCache));
99 primitiveVisualPtr->SetProperties(properties);
100 primitiveVisualPtr->Initialize();
101 return primitiveVisualPtr;
104 PrimitiveVisual::PrimitiveVisual(VisualFactoryCache& factoryCache)
105 : Visual::Base(factoryCache, Visual::FittingMode::FIT_KEEP_ASPECT_RATIO, Toolkit::Visual::PRIMITIVE),
106 mScaleDimensions(Vector3::ONE),
107 mScaleTopRadius(DEFAULT_SCALE_TOP_RADIUS),
108 mScaleBottomRadius(DEFAULT_SCALE_BOTTOM_RADIUS),
109 mScaleHeight(DEFAULT_SCALE_HEIGHT),
110 mScaleRadius(DEFAULT_SCALE_RADIUS),
111 mBevelPercentage(DEFAULT_BEVEL_PERCENTAGE),
112 mBevelSmoothness(DEFAULT_BEVEL_SMOOTHNESS),
113 mSlices(DEFAULT_SLICES),
114 mStacks(DEFAULT_STACKS),
115 mPrimitiveType(Toolkit::PrimitiveVisual::Shape::SPHERE)
117 mImpl->mMixColor = DEFAULT_COLOR;
120 PrimitiveVisual::~PrimitiveVisual()
124 void PrimitiveVisual::DoSetProperties(const Property::Map& propertyMap)
126 //Find out which shape to renderer.
127 Property::Value* primitiveTypeValue = propertyMap.Find(Toolkit::PrimitiveVisual::Property::SHAPE, PRIMITIVE_SHAPE);
128 if(primitiveTypeValue)
130 Scripting::GetEnumerationProperty(*primitiveTypeValue, SHAPE_TYPE_TABLE, SHAPE_TYPE_TABLE_COUNT, mPrimitiveType);
134 DALI_LOG_ERROR("Fail to provide shape to the PrimitiveVisual object.\n");
137 // By virtue of DoSetProperties being called last, this will override
138 // anything set by Toolkit::Visual::Property::MIX_COLOR
139 Property::Value* colorValue = propertyMap.Find(Toolkit::PrimitiveVisual::Property::MIX_COLOR, MIX_COLOR);
143 if(colorValue->Get(color))
145 Property::Type type = colorValue->GetType();
146 if(type == Property::VECTOR4)
150 else if(type == Property::VECTOR3)
152 Vector3 color3(color);
158 Property::Value* slices = propertyMap.Find(Toolkit::PrimitiveVisual::Property::SLICES, SLICES);
161 if(slices->Get(mSlices))
164 if(mSlices > MAX_PARTITIONS)
166 mSlices = MAX_PARTITIONS;
167 DALI_LOG_WARNING("Value for slices clamped.\n");
169 else if(mSlices < MIN_SLICES)
171 mSlices = MIN_SLICES;
172 DALI_LOG_WARNING("Value for slices clamped.\n");
177 DALI_LOG_ERROR("Invalid type for slices in PrimitiveVisual.\n");
181 Property::Value* stacks = propertyMap.Find(Toolkit::PrimitiveVisual::Property::STACKS, STACKS);
184 if(stacks->Get(mStacks))
187 if(mStacks > MAX_PARTITIONS)
189 mStacks = MAX_PARTITIONS;
190 DALI_LOG_WARNING("Value for stacks clamped.\n");
192 else if(mStacks < MIN_STACKS)
194 mStacks = MIN_STACKS;
195 DALI_LOG_WARNING("Value for stacks clamped.\n");
200 DALI_LOG_ERROR("Invalid type for stacks in PrimitiveVisual.\n");
204 Property::Value* scaleTop = propertyMap.Find(Toolkit::PrimitiveVisual::Property::SCALE_TOP_RADIUS, SCALE_TOP_RADIUS);
205 if(scaleTop && !scaleTop->Get(mScaleTopRadius))
207 DALI_LOG_ERROR("Invalid type for scale top radius in PrimitiveVisual.\n");
210 Property::Value* scaleBottom = propertyMap.Find(Toolkit::PrimitiveVisual::Property::SCALE_BOTTOM_RADIUS, SCALE_BOTTOM_RADIUS);
211 if(scaleBottom && !scaleBottom->Get(mScaleBottomRadius))
213 DALI_LOG_ERROR("Invalid type for scale bottom radius in PrimitiveVisual.\n");
216 Property::Value* scaleHeight = propertyMap.Find(Toolkit::PrimitiveVisual::Property::SCALE_HEIGHT, SCALE_HEIGHT);
217 if(scaleHeight && !scaleHeight->Get(mScaleHeight))
219 DALI_LOG_ERROR("Invalid type for scale height in PrimitiveVisual.\n");
222 Property::Value* scaleRadius = propertyMap.Find(Toolkit::PrimitiveVisual::Property::SCALE_RADIUS, SCALE_RADIUS);
223 if(scaleRadius && !scaleRadius->Get(mScaleRadius))
225 DALI_LOG_ERROR("Invalid type for scale radius in PrimitiveVisual.\n");
228 Property::Value* dimensions = propertyMap.Find(Toolkit::PrimitiveVisual::Property::SCALE_DIMENSIONS, SCALE_DIMENSIONS);
231 if(dimensions->Get(mScaleDimensions))
233 //If any dimension is invalid, set it to a sensible default.
234 if(mScaleDimensions.x <= 0.0)
236 mScaleDimensions.x = 1.0;
237 DALI_LOG_WARNING("Value for scale dimensions clamped. Must be greater than zero.\n");
239 if(mScaleDimensions.y <= 0.0)
241 mScaleDimensions.y = 1.0;
242 DALI_LOG_WARNING("Value for scale dimensions clamped. Must be greater than zero.\n");
244 if(mScaleDimensions.z <= 0.0)
246 mScaleDimensions.z = 1.0;
247 DALI_LOG_WARNING("Value for scale dimensions clamped. Must be greater than zero.\n");
252 DALI_LOG_ERROR("Invalid type for scale dimensions in PrimitiveVisual.\n");
256 Property::Value* bevel = propertyMap.Find(Toolkit::PrimitiveVisual::Property::BEVEL_PERCENTAGE, BEVEL_PERCENTAGE);
259 if(bevel->Get(mBevelPercentage))
262 if(mBevelPercentage < MIN_BEVEL_PERCENTAGE)
264 mBevelPercentage = MIN_BEVEL_PERCENTAGE;
265 DALI_LOG_WARNING("Value for bevel percentage clamped.\n");
267 else if(mBevelPercentage > MAX_BEVEL_PERCENTAGE)
269 mBevelPercentage = MAX_BEVEL_PERCENTAGE;
270 DALI_LOG_WARNING("Value for bevel percentage clamped.\n");
275 DALI_LOG_ERROR("Invalid type for bevel percentage in PrimitiveVisual.\n");
279 Property::Value* smoothness = propertyMap.Find(Toolkit::PrimitiveVisual::Property::BEVEL_SMOOTHNESS, BEVEL_SMOOTHNESS);
282 if(smoothness->Get(mBevelSmoothness))
285 if(mBevelSmoothness < MIN_SMOOTHNESS)
287 mBevelSmoothness = MIN_SMOOTHNESS;
288 DALI_LOG_WARNING("Value for bevel smoothness clamped.\n");
290 else if(mBevelSmoothness > MAX_SMOOTHNESS)
292 mBevelSmoothness = MAX_SMOOTHNESS;
293 DALI_LOG_WARNING("Value for bevel smoothness clamped.\n");
298 DALI_LOG_ERROR("Invalid type for bevel smoothness in PrimitiveVisual.\n");
302 //Read in light position.
303 Property::Value* lightPosition = propertyMap.Find(Toolkit::PrimitiveVisual::Property::LIGHT_POSITION, LIGHT_POSITION_UNIFORM_NAME);
306 if(!lightPosition->Get(mLightPosition))
308 DALI_LOG_ERROR("Invalid value passed for light position in MeshVisual object.\n");
309 mLightPosition = Vector3::ZERO;
314 //Default behaviour is to place the light directly in front of the object,
315 // at a reasonable distance to light everything on screen.
316 Stage stage = Stage::GetCurrent();
318 mLightPosition = Vector3(stage.GetSize().width / 2, stage.GetSize().height / 2, stage.GetSize().width * 5);
322 void PrimitiveVisual::GetNaturalSize(Vector2& naturalSize)
329 naturalSize.x = mObjectDimensions.x;
330 naturalSize.y = mObjectDimensions.y;
333 void PrimitiveVisual::DoSetOnScene(Actor& actor)
335 actor.AddRenderer(mImpl->mRenderer);
337 // Primitive generated and ready to display
338 ResourceReady(Toolkit::Visual::ResourceStatus::READY);
341 void PrimitiveVisual::DoCreatePropertyMap(Property::Map& map) const
344 map.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::PRIMITIVE);
345 map.Insert(Toolkit::PrimitiveVisual::Property::MIX_COLOR, mImpl->mMixColor);
346 map.Insert(Toolkit::PrimitiveVisual::Property::SHAPE, mPrimitiveType);
347 map.Insert(Toolkit::PrimitiveVisual::Property::SLICES, mSlices);
348 map.Insert(Toolkit::PrimitiveVisual::Property::STACKS, mStacks);
349 map.Insert(Toolkit::PrimitiveVisual::Property::SCALE_TOP_RADIUS, mScaleTopRadius);
350 map.Insert(Toolkit::PrimitiveVisual::Property::SCALE_BOTTOM_RADIUS, mScaleBottomRadius);
351 map.Insert(Toolkit::PrimitiveVisual::Property::SCALE_HEIGHT, mScaleHeight);
352 map.Insert(Toolkit::PrimitiveVisual::Property::SCALE_RADIUS, mScaleRadius);
353 map.Insert(Toolkit::PrimitiveVisual::Property::SCALE_DIMENSIONS, mScaleDimensions);
354 map.Insert(Toolkit::PrimitiveVisual::Property::BEVEL_PERCENTAGE, mBevelPercentage);
355 map.Insert(Toolkit::PrimitiveVisual::Property::BEVEL_SMOOTHNESS, mBevelSmoothness);
356 map.Insert(Toolkit::PrimitiveVisual::Property::LIGHT_POSITION, mLightPosition);
359 void PrimitiveVisual::DoCreateInstancePropertyMap(Property::Map& map) const
364 void PrimitiveVisual::OnSetTransform()
368 mImpl->mTransform.RegisterUniforms(mImpl->mRenderer, Direction::LEFT_TO_RIGHT);
372 void PrimitiveVisual::OnInitialize()
384 mImpl->mRenderer = Renderer::New(mGeometry, mShader);
385 mImpl->mRenderer.ReserveCustomProperties(CUSTOM_PROPERTY_COUNT);
386 mImpl->mRenderer.SetProperty(Renderer::Property::FACE_CULLING_MODE, FaceCullingMode::BACK);
388 // Register transform properties
389 mImpl->mTransform.RegisterUniforms(mImpl->mRenderer, Direction::LEFT_TO_RIGHT);
391 mImpl->mMixColorIndex = mImpl->mRenderer.RegisterProperty(Toolkit::PrimitiveVisual::Property::MIX_COLOR, MIX_COLOR, Vector3(mImpl->mMixColor));
394 void PrimitiveVisual::UpdateShaderUniforms()
396 Stage stage = Stage::GetCurrent();
397 float width = stage.GetSize().width;
398 float height = stage.GetSize().height;
400 //Flip model to account for DALi starting with (0, 0) at the top left.
402 scaleMatrix.SetIdentityAndScale(Vector3(1.0, -1.0, 1.0));
404 mShader.RegisterProperty(STAGE_OFFSET_UNIFORM_NAME, Vector2(width, height) / 2.0f);
405 mShader.RegisterProperty(LIGHT_POSITION_UNIFORM_NAME, mLightPosition);
406 mShader.RegisterProperty(OBJECT_MATRIX_UNIFORM_NAME, scaleMatrix);
407 mShader.RegisterProperty(OBJECT_DIMENSIONS_UNIFORM_NAME, mObjectDimensions);
410 void PrimitiveVisual::CreateShader()
412 mShader = Shader::New(SHADER_PRIMITIVE_VISUAL_SHADER_VERT, SHADER_PRIMITIVE_VISUAL_SHADER_FRAG);
413 UpdateShaderUniforms();
416 void PrimitiveVisual::CreateGeometry()
418 Dali::Vector<Vertex> vertices;
419 Dali::Vector<unsigned short> indices;
421 switch(mPrimitiveType)
423 case Toolkit::PrimitiveVisual::Shape::SPHERE:
425 CreateSphere(vertices, indices, mSlices, mStacks);
428 case Toolkit::PrimitiveVisual::Shape::CONE:
430 //Create a conic with zero top radius.
431 CreateConic(vertices, indices, 0, mScaleBottomRadius, mScaleHeight, mSlices);
434 case Toolkit::PrimitiveVisual::Shape::CYLINDER:
436 //Create a conic with equal radii on the top and bottom.
437 CreateConic(vertices, indices, mScaleRadius, mScaleRadius, mScaleHeight, mSlices);
440 case Toolkit::PrimitiveVisual::Shape::CUBE:
442 //Create a cube by creating a bevelled cube with minimum bevel.
443 CreateBevelledCube(vertices, indices, mScaleDimensions, 0.0, 0.0);
446 case Toolkit::PrimitiveVisual::Shape::OCTAHEDRON:
448 //Create an octahedron by creating a bevelled cube with maximum bevel.
449 CreateBevelledCube(vertices, indices, mScaleDimensions, 1.0, mBevelSmoothness);
452 case Toolkit::PrimitiveVisual::Shape::BEVELLED_CUBE:
454 CreateBevelledCube(vertices, indices, mScaleDimensions, mBevelPercentage, mBevelSmoothness);
457 case Toolkit::PrimitiveVisual::Shape::CONICAL_FRUSTUM:
459 CreateConic(vertices, indices, mScaleTopRadius, mScaleBottomRadius, mScaleHeight, mSlices);
464 mGeometry = Geometry::New();
467 Property::Map vertexFormat;
468 vertexFormat[POSITION] = Property::VECTOR3;
469 vertexFormat[NORMAL] = Property::VECTOR3;
470 VertexBuffer surfaceVertices = VertexBuffer::New(vertexFormat);
471 surfaceVertices.SetData(&vertices[0], vertices.Size());
473 mGeometry.AddVertexBuffer(surfaceVertices);
475 //Indices for triangle formulation
476 mGeometry.SetIndexBuffer(&indices[0], indices.Size());
479 void PrimitiveVisual::CreateSphere(Vector<Vertex>& vertices, Vector<unsigned short>& indices, int slices, int stacks)
481 ComputeSphereVertices(vertices, slices, stacks);
482 FormSphereTriangles(indices, slices, stacks);
484 mObjectDimensions = Vector3::ONE;
487 void PrimitiveVisual::CreateConic(Vector<Vertex>& vertices, Vector<unsigned short>& indices, float scaleTopRadius, float scaleBottomRadius, float scaleHeight, int slices)
489 ComputeConicVertices(vertices, scaleTopRadius, scaleBottomRadius, scaleHeight, slices);
490 FormConicTriangles(indices, scaleTopRadius, scaleBottomRadius, slices);
492 //Determine object dimensions, and scale them to be between 0.0 and 1.0.
493 float xDimension = std::max(scaleTopRadius, scaleBottomRadius) * 2.0f;
494 float yDimension = scaleHeight;
495 float largestDimension = std::max(xDimension, yDimension);
497 mObjectDimensions = Vector3(xDimension / largestDimension, yDimension / largestDimension, xDimension / largestDimension);
500 void PrimitiveVisual::CreateBevelledCube(Vector<Vertex>& vertices, Vector<unsigned short>& indices, Vector3 dimensions, float bevelPercentage, float bevelSmoothness)
502 float maxDimension = std::max(std::max(dimensions.x, dimensions.y), dimensions.z);
503 dimensions = dimensions / maxDimension;
505 if(bevelPercentage <= MIN_BEVEL_PERCENTAGE) //No bevel, form a cube.
507 ComputeCubeVertices(vertices, dimensions);
508 FormCubeTriangles(indices);
510 else if(bevelPercentage >= MAX_BEVEL_PERCENTAGE) //Max bevel, form an octahedron.
512 ComputeOctahedronVertices(vertices, dimensions, bevelSmoothness);
513 FormOctahedronTriangles(indices);
515 else //In between, form a bevelled cube.
517 ComputeBevelledCubeVertices(vertices, dimensions, bevelPercentage, bevelSmoothness);
518 FormBevelledCubeTriangles(indices);
521 mObjectDimensions = dimensions;
524 void PrimitiveVisual::ComputeCircleTables(Vector<float>& sinTable, Vector<float>& cosTable, int divisions, bool halfCircle)
531 const float angleDivision = (halfCircle ? 1.0f : 2.0f) * Dali::Math::PI / (float)divisions;
533 sinTable.Resize(divisions);
534 cosTable.Resize(divisions);
536 for(int i = 0; i < divisions; i++)
538 sinTable[i] = sin(angleDivision * i);
539 cosTable[i] = cos(angleDivision * i);
543 void PrimitiveVisual::ComputeSphereVertices(Vector<Vertex>& vertices, int slices, int stacks)
545 //Tables for calculating slices angles and stacks angles, respectively.
546 Vector<float> sinTable1;
547 Vector<float> cosTable1;
548 Vector<float> sinTable2;
549 Vector<float> cosTable2;
551 ComputeCircleTables(sinTable1, cosTable1, slices, false);
552 ComputeCircleTables(sinTable2, cosTable2, stacks, true);
554 int numVertices = slices * (stacks - 1) + 2;
555 vertices.Resize(numVertices);
557 int vertexIndex = 0; //Track progress through vertices.
563 vertices[vertexIndex].position = Vector3(0.0, 0.5, 0.0);
564 vertices[vertexIndex].normal = Vector3(0.0, 1.0, 0.0);
568 for(int i = 1; i < stacks; i++)
570 for(int j = 0; j < slices; j++, vertexIndex++)
572 x = cosTable1[j] * sinTable2[i];
574 z = sinTable1[j] * sinTable2[i];
576 vertices[vertexIndex].position = Vector3(x / 2.0f, y / 2.0f, z / 2.0f);
577 vertices[vertexIndex].normal = Vector3(x, y, z);
582 vertices[vertexIndex].position = Vector3(0.0, -0.5, 0.0);
583 vertices[vertexIndex].normal = Vector3(0.0, -1.0, 0.0);
586 void PrimitiveVisual::FormSphereTriangles(Vector<unsigned short>& indices, int slices, int stacks)
590 //Set indices to placeholder "error" values.
591 //This will display nothing, which is the expected behaviour for this edge case.
596 int numTriangles = 2 * slices * (stacks - 1);
598 indices.Resize(3 * numTriangles);
600 int indiceIndex = 0; //Used to keep track of progress through indices.
601 int previousCycleBeginning = 1; //Stores the index of the vertex that started the cycle of the previous stack.
602 int currentCycleBeginning = 1 + slices;
604 //Top stack. Loop from index 1 to index slices, as not counting the very first vertex.
605 for(int i = 1; i <= slices; i++, indiceIndex += 3)
607 indices[indiceIndex] = 0;
610 //End, so loop around.
611 indices[indiceIndex + 1] = 1;
615 indices[indiceIndex + 1] = i + 1;
617 indices[indiceIndex + 2] = i;
620 //Middle Stacks. Want to form triangles between the top and bottom stacks, so loop up to the number of stacks - 2.
621 for(int i = 0; i < stacks - 2; i++, previousCycleBeginning += slices, currentCycleBeginning += slices)
623 for(int j = 0; j < slices; j++, indiceIndex += 6)
627 //End, so loop around.
628 indices[indiceIndex] = previousCycleBeginning + j;
629 indices[indiceIndex + 1] = previousCycleBeginning;
630 indices[indiceIndex + 2] = currentCycleBeginning + j;
631 indices[indiceIndex + 3] = currentCycleBeginning + j;
632 indices[indiceIndex + 4] = previousCycleBeginning;
633 indices[indiceIndex + 5] = currentCycleBeginning;
637 indices[indiceIndex] = previousCycleBeginning + j;
638 indices[indiceIndex + 1] = previousCycleBeginning + 1 + j;
639 indices[indiceIndex + 2] = currentCycleBeginning + j;
640 indices[indiceIndex + 3] = currentCycleBeginning + j;
641 indices[indiceIndex + 4] = previousCycleBeginning + 1 + j;
642 indices[indiceIndex + 5] = currentCycleBeginning + 1 + j;
647 //Bottom stack. Loop around the last stack from the previous loop, and go up to the penultimate vertex.
648 for(int i = 0; i < slices; i++, indiceIndex += 3)
650 indices[indiceIndex] = previousCycleBeginning + slices;
651 indices[indiceIndex + 1] = previousCycleBeginning + i;
654 //End, so loop around.
655 indices[indiceIndex + 2] = previousCycleBeginning;
659 indices[indiceIndex + 2] = previousCycleBeginning + i + 1;
664 void PrimitiveVisual::ComputeConicVertices(Vector<Vertex>& vertices, float scaleTopRadius, float scaleBottomRadius, float scaleHeight, int slices)
666 int vertexIndex = 0; //Track progress through vertices.
667 Vector<float> sinTable;
668 Vector<float> cosTable;
670 ComputeCircleTables(sinTable, cosTable, slices, false);
672 int numVertices = 2; //Always will have one at the top and one at the bottom.
674 //Add vertices for each circle. Need two per point for different face normals.
675 if(scaleTopRadius > 0.0)
677 numVertices += 2 * slices;
679 if(scaleBottomRadius > 0.0)
681 numVertices += 2 * slices;
684 vertices.Resize(numVertices);
686 //Scale to bounding region of -0.5 to 0.5 (i.e range of 1).
687 float biggestObjectDimension = std::max(std::max(scaleTopRadius * 2.0f, scaleBottomRadius * 2.0f), scaleHeight);
688 scaleTopRadius = scaleTopRadius / biggestObjectDimension;
689 scaleBottomRadius = scaleBottomRadius / biggestObjectDimension;
691 //Dimensions for vertex coordinates. Y is constant, and so can be initialised now.
693 float y = scaleHeight / biggestObjectDimension / 2.0f;
697 vertices[0].position = Vector3(0, y, 0);
698 vertices[0].normal = Vector3(0, 1, 0);
702 if(scaleTopRadius > 0.0)
704 //Loop around the circle.
705 for(int i = 0; i < slices; i++, vertexIndex++)
707 x = sinTable[i] * scaleTopRadius;
708 z = cosTable[i] * scaleTopRadius;
710 //Upward-facing normal.
711 vertices[vertexIndex].position = Vector3(x, y, z);
712 vertices[vertexIndex].normal = Vector3(0, 1, 0);
714 //Outward-facing normal.
715 vertices[vertexIndex + slices].position = Vector3(x, y, z);
716 vertices[vertexIndex + slices].normal = Vector3(x, 0, z);
719 vertexIndex += slices;
723 if(scaleBottomRadius > 0.0)
725 //Loop around the circle.
726 for(int i = 0; i < slices; i++, vertexIndex++)
728 x = sinTable[i] * scaleBottomRadius;
729 z = cosTable[i] * scaleBottomRadius;
731 //Outward-facing normal.
732 vertices[vertexIndex].position = Vector3(x, -y, z);
733 vertices[vertexIndex].normal = Vector3(x, 0, z);
735 //Downward-facing normal.
736 vertices[vertexIndex + slices].position = Vector3(x, -y, z);
737 vertices[vertexIndex + slices].normal = Vector3(0, -1, 0);
740 vertexIndex += slices;
744 vertices[vertexIndex].position = Vector3(0, -y, 0);
745 vertices[vertexIndex].normal = Vector3(0, -1, 0);
749 void PrimitiveVisual::FormConicTriangles(Vector<unsigned short>& indices, float scaleTopRadius, float scaleBottomRadius, int slices)
751 int indiceIndex = 0; //Track progress through indices.
752 int numTriangles = 0;
753 bool coneTop = scaleTopRadius <= 0.0;
754 bool coneBottom = scaleBottomRadius <= 0.0;
756 if(coneTop && coneBottom)
758 //Set indices to placeholder "error" values.
759 //This will display nothing, which is the expected behaviour for this edge case.
766 numTriangles += 2 * slices;
770 numTriangles += 2 * slices;
773 indices.Resize(3 * numTriangles);
775 //Switch on the type of conic we have.
776 if(!coneTop && !coneBottom)
778 //Top circle. Start at index of first outer point and go around.
779 for(int i = 1; i <= slices; i++, indiceIndex += 3)
781 indices[indiceIndex] = 0;
782 indices[indiceIndex + 1] = i;
785 //End, so loop around.
786 indices[indiceIndex + 2] = 1;
790 indices[indiceIndex + 2] = i + 1;
794 int topCycleBeginning = slices + 1;
795 int bottomCycleBeginning = topCycleBeginning + slices;
798 for(int i = 0; i < slices; i++, indiceIndex += 6)
802 //End, so loop around.
803 indices[indiceIndex] = topCycleBeginning + i;
804 indices[indiceIndex + 1] = bottomCycleBeginning + i;
805 indices[indiceIndex + 2] = topCycleBeginning;
806 indices[indiceIndex + 3] = bottomCycleBeginning + i;
807 indices[indiceIndex + 4] = bottomCycleBeginning;
808 indices[indiceIndex + 5] = topCycleBeginning;
812 indices[indiceIndex] = topCycleBeginning + i;
813 indices[indiceIndex + 1] = bottomCycleBeginning + i;
814 indices[indiceIndex + 2] = topCycleBeginning + 1 + i;
815 indices[indiceIndex + 3] = bottomCycleBeginning + i;
816 indices[indiceIndex + 4] = bottomCycleBeginning + 1 + i;
817 indices[indiceIndex + 5] = topCycleBeginning + 1 + i;
821 int bottomFaceCycleBeginning = bottomCycleBeginning + slices;
824 for(int i = 0; i < slices; i++, indiceIndex += 3)
826 indices[indiceIndex] = bottomFaceCycleBeginning;
829 //End, so loop around.
830 indices[indiceIndex + 1] = bottomFaceCycleBeginning;
834 indices[indiceIndex + 1] = bottomFaceCycleBeginning + i + 1;
836 indices[indiceIndex + 2] = bottomFaceCycleBeginning + i;
839 else if(!coneTop || !coneBottom)
841 //Top circle/edges. Start at index of first outer point and go around.
842 for(int i = 1; i <= slices; i++, indiceIndex += 3)
844 indices[indiceIndex] = 0;
845 indices[indiceIndex + 1] = i;
848 //End, so loop around.
849 indices[indiceIndex + 2] = 1;
853 indices[indiceIndex + 2] = i + 1;
857 //Bottom circle/edges. Start at index of first outer point and go around.
858 for(int i = 1; i <= slices; i++, indiceIndex += 3)
860 indices[indiceIndex] = 2 * slices + 1;
863 //End, so loop around.
864 indices[indiceIndex + 1] = slices + 1;
868 indices[indiceIndex + 1] = slices + i + 1;
870 indices[indiceIndex + 2] = slices + i;
875 void PrimitiveVisual::ComputeCubeVertices(Vector<Vertex>& vertices, Vector3 dimensions)
877 int numVertices = 4 * 6; //Four per face.
878 int vertexIndex = 0; //Tracks progress through vertices.
879 float scaledX = 0.5 * dimensions.x;
880 float scaledY = 0.5 * dimensions.y;
881 float scaledZ = 0.5 * dimensions.z;
883 vertices.Resize(numVertices);
885 Vector<Vector3> positions; //Stores vertex positions, which are shared between vertexes at the same position but with a different normal.
887 Vector<Vector3> normals; //Stores normals, which are shared between vertexes of the same face.
890 positions[0] = Vector3(-scaledX, scaledY, -scaledZ);
891 positions[1] = Vector3(scaledX, scaledY, -scaledZ);
892 positions[2] = Vector3(scaledX, scaledY, scaledZ);
893 positions[3] = Vector3(-scaledX, scaledY, scaledZ);
894 positions[4] = Vector3(-scaledX, -scaledY, -scaledZ);
895 positions[5] = Vector3(scaledX, -scaledY, -scaledZ);
896 positions[6] = Vector3(scaledX, -scaledY, scaledZ);
897 positions[7] = Vector3(-scaledX, -scaledY, scaledZ);
899 normals[0] = Vector3(0, 1, 0);
900 normals[1] = Vector3(0, 0, -1);
901 normals[2] = Vector3(1, 0, 0);
902 normals[3] = Vector3(0, 0, 1);
903 normals[4] = Vector3(-1, 0, 0);
904 normals[5] = Vector3(0, -1, 0);
906 //Top face, upward normals.
907 for(int i = 0; i < 4; i++, vertexIndex++)
909 vertices[vertexIndex].position = positions[i];
910 vertices[vertexIndex].normal = normals[0];
913 //Top face, outward normals.
914 for(int i = 0; i < 4; i++, vertexIndex += 2)
916 vertices[vertexIndex].position = positions[i];
917 vertices[vertexIndex].normal = normals[i + 1];
921 //End, so loop around.
922 vertices[vertexIndex + 1].position = positions[0];
926 vertices[vertexIndex + 1].position = positions[i + 1];
928 vertices[vertexIndex + 1].normal = normals[i + 1];
931 //Bottom face, outward normals.
932 for(int i = 0; i < 4; i++, vertexIndex += 2)
934 vertices[vertexIndex].position = positions[i + 4];
935 vertices[vertexIndex].normal = normals[i + 1];
939 //End, so loop around.
940 vertices[vertexIndex + 1].position = positions[4];
944 vertices[vertexIndex + 1].position = positions[i + 5];
946 vertices[vertexIndex + 1].normal = normals[i + 1];
949 //Bottom face, downward normals.
950 for(int i = 0; i < 4; i++, vertexIndex++)
952 vertices[vertexIndex].position = positions[i + 4];
953 vertices[vertexIndex].normal = normals[5];
957 void PrimitiveVisual::FormCubeTriangles(Vector<unsigned short>& indices)
959 int numTriangles = 12;
960 int triangleIndex = 0; //Track progress through indices.
962 indices.Resize(3 * numTriangles);
965 indices[triangleIndex] = 0;
966 indices[triangleIndex + 1] = 2;
967 indices[triangleIndex + 2] = 1;
968 indices[triangleIndex + 3] = 2;
969 indices[triangleIndex + 4] = 0;
970 indices[triangleIndex + 5] = 3;
973 int topFaceStart = 4;
974 int bottomFaceStart = 12;
977 for(int i = 0; i < 8; i += 2, triangleIndex += 6)
979 indices[triangleIndex] = i + topFaceStart;
980 indices[triangleIndex + 1] = i + topFaceStart + 1;
981 indices[triangleIndex + 2] = i + bottomFaceStart + 1;
982 indices[triangleIndex + 3] = i + topFaceStart;
983 indices[triangleIndex + 4] = i + bottomFaceStart + 1;
984 indices[triangleIndex + 5] = i + bottomFaceStart;
988 indices[triangleIndex] = 20;
989 indices[triangleIndex + 1] = 21;
990 indices[triangleIndex + 2] = 22;
991 indices[triangleIndex + 3] = 22;
992 indices[triangleIndex + 4] = 23;
993 indices[triangleIndex + 5] = 20;
996 void PrimitiveVisual::ComputeOctahedronVertices(Vector<Vertex>& vertices, Vector3 dimensions, float smoothness)
998 int numVertices = 3 * 8; //Three per face
999 int vertexIndex = 0; //Tracks progress through vertices.
1000 float scaledX = 0.5 * dimensions.x;
1001 float scaledY = 0.5 * dimensions.y;
1002 float scaledZ = 0.5 * dimensions.z;
1004 vertices.Resize(numVertices);
1006 Vector<Vector3> positions; //Stores vertex positions, which are shared between vertexes at the same position but with a different normal.
1007 positions.Resize(6);
1008 Vector<Vector3> normals; //Stores normals, which are shared between vertexes of the same face.
1010 Vector<Vector3> outerNormals; //Holds normals that point outwards at each vertex.
1011 outerNormals.Resize(6);
1013 positions[0] = Vector3(0.0, scaledY, 0.0);
1014 positions[1] = Vector3(-scaledX, 0.0, 0.0);
1015 positions[2] = Vector3(0.0, 0.0, -scaledZ);
1016 positions[3] = Vector3(scaledX, 0.0, 0.0);
1017 positions[4] = Vector3(0.0, 0.0, scaledZ);
1018 positions[5] = Vector3(0.0, -scaledY, 0.0);
1020 normals[0] = Vector3(-1, 1, -1);
1021 normals[1] = Vector3(1, 1, -1);
1022 normals[2] = Vector3(1, 1, 1);
1023 normals[3] = Vector3(-1, 1, 1);
1024 normals[4] = Vector3(-1, -1, -1);
1025 normals[5] = Vector3(1, -1, -1);
1026 normals[6] = Vector3(1, -1, 1);
1027 normals[7] = Vector3(-1, -1, 1);
1029 outerNormals[0] = Vector3(0, 1, 0);
1030 outerNormals[1] = Vector3(-1, 0, 0);
1031 outerNormals[2] = Vector3(0, 0, -1);
1032 outerNormals[3] = Vector3(1, 0, 0);
1033 outerNormals[4] = Vector3(0, 0, 1);
1034 outerNormals[5] = Vector3(0, -1, 0);
1036 //Loop through top faces.
1037 for(int i = 0; i < 4; i++, vertexIndex += 3)
1041 //End, so loop around.
1042 vertices[vertexIndex].position = positions[0];
1043 vertices[vertexIndex].normal = outerNormals[0] * smoothness + normals[i] * (1 - smoothness);
1044 vertices[vertexIndex + 1].position = positions[1];
1045 vertices[vertexIndex + 1].normal = outerNormals[1] * smoothness + normals[i] * (1 - smoothness);
1046 vertices[vertexIndex + 2].position = positions[i + 1];
1047 vertices[vertexIndex + 2].normal = outerNormals[i + 1] * smoothness + normals[i] * (1 - smoothness);
1051 vertices[vertexIndex].position = positions[0];
1052 vertices[vertexIndex].normal = outerNormals[0] * smoothness + normals[i] * (1 - smoothness);
1053 vertices[vertexIndex + 1].position = positions[i + 2];
1054 vertices[vertexIndex + 1].normal = outerNormals[i + 2] * smoothness + normals[i] * (1 - smoothness);
1055 vertices[vertexIndex + 2].position = positions[i + 1];
1056 vertices[vertexIndex + 2].normal = outerNormals[i + 1] * smoothness + normals[i] * (1 - smoothness);
1060 //Loop through bottom faces.
1061 for(int i = 0; i < 4; i++, vertexIndex += 3)
1065 //End, so loop around.
1066 vertices[vertexIndex].position = positions[5];
1067 vertices[vertexIndex].normal = outerNormals[5] * smoothness + normals[i + 4] * (1 - smoothness);
1068 vertices[vertexIndex + 1].position = positions[i + 1];
1069 vertices[vertexIndex + 1].normal = outerNormals[i + 1] * smoothness + normals[i + 4] * (1 - smoothness);
1070 vertices[vertexIndex + 2].position = positions[1];
1071 vertices[vertexIndex + 2].normal = outerNormals[1] * smoothness + normals[i + 4] * (1 - smoothness);
1075 vertices[vertexIndex].position = positions[5];
1076 vertices[vertexIndex].normal = outerNormals[5] * smoothness + normals[i + 4] * (1 - smoothness);
1077 vertices[vertexIndex + 1].position = positions[i + 1];
1078 vertices[vertexIndex + 1].normal = outerNormals[i + 1] * smoothness + normals[i + 4] * (1 - smoothness);
1079 vertices[vertexIndex + 2].position = positions[i + 2];
1080 vertices[vertexIndex + 2].normal = outerNormals[i + 2] * smoothness + normals[i + 4] * (1 - smoothness);
1085 void PrimitiveVisual::FormOctahedronTriangles(Vector<unsigned short>& indices)
1087 int numTriangles = 8;
1088 int numIndices = numTriangles * 3;
1090 indices.Resize(numIndices);
1092 for(unsigned short i = 0; i < numIndices; i++)
1098 void PrimitiveVisual::ComputeBevelledCubeVertices(Vector<Vertex>& vertices, Vector3 dimensions, float bevelPercentage, float bevelSmoothness)
1100 int numPositions = 24;
1102 int numOuterFaces = 6;
1103 int numVertices = 6 * 4 + 12 * 4 + 8 * 3; //Six outer faces, 12 slanting rectangles, 8 slanting triangles.
1104 int vertexIndex = 0; //Track progress through vertices.
1105 int normalIndex = 0; //Track progress through normals, as vertices are calculated per face.
1107 float minDimension = std::min(std::min(dimensions.x, dimensions.y), dimensions.z);
1108 float bevelAmount = 0.5 * std::min(bevelPercentage, minDimension); //Cap bevel amount if necessary.
1110 //Distances from centre to outer edge points.
1111 float outerX = 0.5 * dimensions.x;
1112 float outerY = 0.5 * dimensions.y;
1113 float outerZ = 0.5 * dimensions.z;
1115 //Distances from centre to bevelled points.
1116 float bevelX = outerX - bevelAmount;
1117 float bevelY = outerY - bevelAmount;
1118 float bevelZ = outerZ - bevelAmount;
1120 Vector<Vector3> positions; //Holds object points, to be shared between vertexes.
1121 positions.Resize(numPositions);
1122 Vector<Vector3> normals; //Holds face normals, to be shared between vertexes.
1123 normals.Resize(numFaces);
1124 Vector<Vector3> outerNormals; //Holds normals of the outermost faces specifically.
1125 outerNormals.Resize(numOuterFaces);
1126 vertices.Resize(numVertices);
1128 //Topmost face positions.
1129 positions[0] = Vector3(-bevelX, outerY, -bevelZ);
1130 positions[1] = Vector3(bevelX, outerY, -bevelZ);
1131 positions[2] = Vector3(bevelX, outerY, bevelZ);
1132 positions[3] = Vector3(-bevelX, outerY, bevelZ);
1134 //Second layer positions.
1135 positions[4] = Vector3(-outerX, bevelY, -bevelZ);
1136 positions[5] = Vector3(-bevelX, bevelY, -outerZ);
1137 positions[6] = Vector3(bevelX, bevelY, -outerZ);
1138 positions[7] = Vector3(outerX, bevelY, -bevelZ);
1139 positions[8] = Vector3(outerX, bevelY, bevelZ);
1140 positions[9] = Vector3(bevelX, bevelY, outerZ);
1141 positions[10] = Vector3(-bevelX, bevelY, outerZ);
1142 positions[11] = Vector3(-outerX, bevelY, bevelZ);
1144 //Third layer positions.
1145 positions[12] = Vector3(-outerX, -bevelY, -bevelZ);
1146 positions[13] = Vector3(-bevelX, -bevelY, -outerZ);
1147 positions[14] = Vector3(bevelX, -bevelY, -outerZ);
1148 positions[15] = Vector3(outerX, -bevelY, -bevelZ);
1149 positions[16] = Vector3(outerX, -bevelY, bevelZ);
1150 positions[17] = Vector3(bevelX, -bevelY, outerZ);
1151 positions[18] = Vector3(-bevelX, -bevelY, outerZ);
1152 positions[19] = Vector3(-outerX, -bevelY, bevelZ);
1154 //Bottom-most face positions.
1155 positions[20] = Vector3(-bevelX, -outerY, -bevelZ);
1156 positions[21] = Vector3(bevelX, -outerY, -bevelZ);
1157 positions[22] = Vector3(bevelX, -outerY, bevelZ);
1158 positions[23] = Vector3(-bevelX, -outerY, bevelZ);
1161 normals[0] = Vector3(0, 1, 0);
1163 //Top slope normals.
1164 normals[1] = Vector3(-1, 1, -1);
1165 normals[2] = Vector3(0, 1, -1);
1166 normals[3] = Vector3(1, 1, -1);
1167 normals[4] = Vector3(1, 1, 0);
1168 normals[5] = Vector3(1, 1, 1);
1169 normals[6] = Vector3(0, 1, 1);
1170 normals[7] = Vector3(-1, 1, 1);
1171 normals[8] = Vector3(-1, 1, 0);
1174 normals[9] = Vector3(-1, 0, -1);
1175 normals[10] = Vector3(0, 0, -1);
1176 normals[11] = Vector3(1, 0, -1);
1177 normals[12] = Vector3(1, 0, 0);
1178 normals[13] = Vector3(1, 0, 1);
1179 normals[14] = Vector3(0, 0, 1);
1180 normals[15] = Vector3(-1, 0, 1);
1181 normals[16] = Vector3(-1, 0, 0);
1183 //Bottom slope normals.
1184 normals[17] = Vector3(-1, -1, -1);
1185 normals[18] = Vector3(0, -1, -1);
1186 normals[19] = Vector3(1, -1, -1);
1187 normals[20] = Vector3(1, -1, 0);
1188 normals[21] = Vector3(1, -1, 1);
1189 normals[22] = Vector3(0, -1, 1);
1190 normals[23] = Vector3(-1, -1, 1);
1191 normals[24] = Vector3(-1, -1, 0);
1193 //Bottom face normal.
1194 normals[25] = Vector3(0, -1, 0);
1196 //Top, back, right, front, left and bottom faces, respectively.
1197 outerNormals[0] = Vector3(0, 1, 0);
1198 outerNormals[1] = Vector3(0, 0, -1);
1199 outerNormals[2] = Vector3(1, 0, 0);
1200 outerNormals[3] = Vector3(0, 0, 1);
1201 outerNormals[4] = Vector3(-1, 0, 0);
1202 outerNormals[5] = Vector3(0, -1, 0);
1204 //Topmost face vertices.
1205 for(int i = 0; i < 4; i++, vertexIndex++)
1207 vertices[vertexIndex].position = positions[i];
1208 vertices[vertexIndex].normal = normals[normalIndex];
1213 //Top slope vertices.
1214 for(int i = 0; i < 4; i++, vertexIndex += 7, normalIndex += 2)
1217 vertices[vertexIndex].position = positions[i];
1218 vertices[vertexIndex].normal = outerNormals[0] * bevelSmoothness + normals[normalIndex] * (1 - bevelSmoothness);
1219 vertices[vertexIndex + 1].position = positions[2 * i + 4];
1220 vertices[vertexIndex + 1].normal = outerNormals[(i == 0) ? 4 : i] * bevelSmoothness + normals[normalIndex] * (1 - bevelSmoothness);
1221 vertices[vertexIndex + 2].position = positions[2 * i + 5];
1222 vertices[vertexIndex + 2].normal = outerNormals[i + 1] * bevelSmoothness + normals[normalIndex] * (1 - bevelSmoothness);
1227 //End, so loop around.
1228 vertices[vertexIndex + 3].position = positions[i];
1229 vertices[vertexIndex + 3].normal = outerNormals[0] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
1230 vertices[vertexIndex + 4].position = positions[0];
1231 vertices[vertexIndex + 4].normal = outerNormals[0] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
1232 vertices[vertexIndex + 5].position = positions[2 * i + 5];
1233 vertices[vertexIndex + 5].normal = outerNormals[i + 1] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
1234 vertices[vertexIndex + 6].position = positions[4];
1235 vertices[vertexIndex + 6].normal = outerNormals[i + 1] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
1239 vertices[vertexIndex + 3].position = positions[i];
1240 vertices[vertexIndex + 3].normal = outerNormals[0] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
1241 vertices[vertexIndex + 4].position = positions[i + 1];
1242 vertices[vertexIndex + 4].normal = outerNormals[0] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
1243 vertices[vertexIndex + 5].position = positions[2 * i + 5];
1244 vertices[vertexIndex + 5].normal = outerNormals[i + 1] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
1245 vertices[vertexIndex + 6].position = positions[2 * i + 6];
1246 vertices[vertexIndex + 6].normal = outerNormals[i + 1] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
1250 int secondCycleBeginning = 4;
1251 int thirdCycleBeginning = secondCycleBeginning + 8;
1252 int bottomCycleBeginning = thirdCycleBeginning + 8;
1255 for(int i = 0; i < 8; i++, vertexIndex += 4, normalIndex++)
1259 //End, so loop around.
1260 vertices[vertexIndex].position = positions[secondCycleBeginning + i];
1261 vertices[vertexIndex].normal = normals[normalIndex];
1262 vertices[vertexIndex + 1].position = positions[secondCycleBeginning];
1263 vertices[vertexIndex + 1].normal = normals[normalIndex];
1264 vertices[vertexIndex + 2].position = positions[thirdCycleBeginning + i];
1265 vertices[vertexIndex + 2].normal = normals[normalIndex];
1266 vertices[vertexIndex + 3].position = positions[thirdCycleBeginning];
1267 vertices[vertexIndex + 3].normal = normals[normalIndex];
1269 else if((i % 2) == 0)
1271 //'even' faces are corner ones, and need smoothing.
1272 vertices[vertexIndex].position = positions[secondCycleBeginning + i];
1273 vertices[vertexIndex].normal = outerNormals[(i == 0) ? 4 : i / 2] * bevelSmoothness + normals[normalIndex] * (1 - bevelSmoothness);
1274 vertices[vertexIndex + 1].position = positions[secondCycleBeginning + i + 1];
1275 vertices[vertexIndex + 1].normal = outerNormals[i / 2 + 1] * bevelSmoothness + normals[normalIndex] * (1 - bevelSmoothness);
1276 vertices[vertexIndex + 2].position = positions[thirdCycleBeginning + i];
1277 vertices[vertexIndex + 2].normal = outerNormals[(i == 0) ? 4 : i / 2] * bevelSmoothness + normals[normalIndex] * (1 - bevelSmoothness);
1278 vertices[vertexIndex + 3].position = positions[thirdCycleBeginning + i + 1];
1279 vertices[vertexIndex + 3].normal = outerNormals[i / 2 + 1] * bevelSmoothness + normals[normalIndex] * (1 - bevelSmoothness);
1283 //'odd' faces are outer ones, and so don't need smoothing.
1284 vertices[vertexIndex].position = positions[secondCycleBeginning + i];
1285 vertices[vertexIndex].normal = normals[normalIndex];
1286 vertices[vertexIndex + 1].position = positions[secondCycleBeginning + i + 1];
1287 vertices[vertexIndex + 1].normal = normals[normalIndex];
1288 vertices[vertexIndex + 2].position = positions[thirdCycleBeginning + i];
1289 vertices[vertexIndex + 2].normal = normals[normalIndex];
1290 vertices[vertexIndex + 3].position = positions[thirdCycleBeginning + i + 1];
1291 vertices[vertexIndex + 3].normal = normals[normalIndex];
1295 //Bottom slope vertices.
1296 for(int i = 0; i < 4; i++, vertexIndex += 7, normalIndex += 2)
1299 vertices[vertexIndex].position = positions[thirdCycleBeginning + 2 * i];
1300 vertices[vertexIndex].normal = outerNormals[(i == 0) ? 4 : i] * bevelSmoothness + normals[normalIndex] * (1 - bevelSmoothness);
1301 vertices[vertexIndex + 1].position = positions[thirdCycleBeginning + 2 * i + 1];
1302 vertices[vertexIndex + 1].normal = outerNormals[i + 1] * bevelSmoothness + normals[normalIndex] * (1 - bevelSmoothness);
1303 vertices[vertexIndex + 2].position = positions[bottomCycleBeginning + i];
1304 vertices[vertexIndex + 2].normal = outerNormals[5] * bevelSmoothness + normals[normalIndex] * (1 - bevelSmoothness);
1309 //End, so loop around.
1310 vertices[vertexIndex + 3].position = positions[thirdCycleBeginning + 2 * i + 1];
1311 vertices[vertexIndex + 3].normal = outerNormals[i + 1] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
1312 vertices[vertexIndex + 4].position = positions[thirdCycleBeginning];
1313 vertices[vertexIndex + 4].normal = outerNormals[i + 1] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
1314 vertices[vertexIndex + 5].position = positions[bottomCycleBeginning + i];
1315 vertices[vertexIndex + 5].normal = outerNormals[5] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
1316 vertices[vertexIndex + 6].position = positions[bottomCycleBeginning];
1317 vertices[vertexIndex + 6].normal = outerNormals[5] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
1321 vertices[vertexIndex + 3].position = positions[thirdCycleBeginning + 2 * i + 1];
1322 vertices[vertexIndex + 3].normal = outerNormals[i + 1] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
1323 vertices[vertexIndex + 4].position = positions[thirdCycleBeginning + 2 * i + 2];
1324 vertices[vertexIndex + 4].normal = outerNormals[i + 1] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
1325 vertices[vertexIndex + 5].position = positions[bottomCycleBeginning + i];
1326 vertices[vertexIndex + 5].normal = outerNormals[5] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
1327 vertices[vertexIndex + 6].position = positions[bottomCycleBeginning + i + 1];
1328 vertices[vertexIndex + 6].normal = outerNormals[5] * bevelSmoothness + normals[normalIndex + 1] * (1 - bevelSmoothness);
1332 //Bottom-most face vertices.
1333 for(int i = 0; i < 4; i++, vertexIndex++)
1335 vertices[vertexIndex].position = positions[bottomCycleBeginning + i];
1336 vertices[vertexIndex].normal = normals[normalIndex];
1342 void PrimitiveVisual::FormBevelledCubeTriangles(Vector<unsigned short>& indices)
1344 int numTriangles = 44; //(Going from top to bottom, that's 2 + 12 + 16 + 12 + 2)
1345 int indiceIndex = 0; //Track progress through indices.
1346 int vertexIndex = 0; //Track progress through vertices as they're processed.
1348 indices.Resize(3 * numTriangles);
1351 indices[indiceIndex] = vertexIndex;
1352 indices[indiceIndex + 1] = vertexIndex + 2;
1353 indices[indiceIndex + 2] = vertexIndex + 1;
1354 indices[indiceIndex + 3] = vertexIndex + 0;
1355 indices[indiceIndex + 4] = vertexIndex + 3;
1356 indices[indiceIndex + 5] = vertexIndex + 2;
1361 for(int i = 0; i < 4; i++, indiceIndex += 9, vertexIndex += 7)
1364 indices[indiceIndex] = vertexIndex;
1365 indices[indiceIndex + 1] = vertexIndex + 2;
1366 indices[indiceIndex + 2] = vertexIndex + 1;
1369 indices[indiceIndex + 3] = vertexIndex + 3;
1370 indices[indiceIndex + 4] = vertexIndex + 4;
1371 indices[indiceIndex + 5] = vertexIndex + 5;
1372 indices[indiceIndex + 6] = vertexIndex + 4;
1373 indices[indiceIndex + 7] = vertexIndex + 6;
1374 indices[indiceIndex + 8] = vertexIndex + 5;
1378 for(int i = 0; i < 8; i++, indiceIndex += 6, vertexIndex += 4)
1380 indices[indiceIndex] = vertexIndex;
1381 indices[indiceIndex + 1] = vertexIndex + 1;
1382 indices[indiceIndex + 2] = vertexIndex + 2;
1383 indices[indiceIndex + 3] = vertexIndex + 1;
1384 indices[indiceIndex + 4] = vertexIndex + 3;
1385 indices[indiceIndex + 5] = vertexIndex + 2;
1389 for(int i = 0; i < 4; i++, indiceIndex += 9, vertexIndex += 7)
1392 indices[indiceIndex] = vertexIndex;
1393 indices[indiceIndex + 1] = vertexIndex + 1;
1394 indices[indiceIndex + 2] = vertexIndex + 2;
1397 indices[indiceIndex + 3] = vertexIndex + 3;
1398 indices[indiceIndex + 4] = vertexIndex + 4;
1399 indices[indiceIndex + 5] = vertexIndex + 5;
1400 indices[indiceIndex + 6] = vertexIndex + 4;
1401 indices[indiceIndex + 7] = vertexIndex + 6;
1402 indices[indiceIndex + 8] = vertexIndex + 5;
1406 indices[indiceIndex] = vertexIndex;
1407 indices[indiceIndex + 1] = vertexIndex + 1;
1408 indices[indiceIndex + 2] = vertexIndex + 2;
1409 indices[indiceIndex + 3] = vertexIndex + 0;
1410 indices[indiceIndex + 4] = vertexIndex + 2;
1411 indices[indiceIndex + 5] = vertexIndex + 3;
1416 } // namespace Internal
1418 } // namespace Toolkit