Spinning Topp Logo BlackTopp Studios
inc
icospheregenerator.cpp
1 // © Copyright 2010 - 2016 BlackTopp Studios Inc.
2 /* This file is part of The Mezzanine Engine.
3 
4  The Mezzanine Engine is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  The Mezzanine Engine is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with The Mezzanine Engine. If not, see <http://www.gnu.org/licenses/>.
16 */
17 /* The original authors have included a copy of the license specified above in the
18  'Docs' folder. See 'gpl.txt'
19 */
20 /* We welcome the use of the Mezzanine engine to anyone, including companies who wish to
21  Build professional software and charge for their product.
22 
23  However there are some practical restrictions, so if your project involves
24  any of the following you should contact us and we will try to work something
25  out:
26  - DRM or Copy Protection of any kind(except Copyrights)
27  - Software Patents You Do Not Wish to Freely License
28  - Any Kind of Linking to Non-GPL licensed Works
29  - Are Currently In Violation of Another Copyright Holder's GPL License
30  - If You want to change our code and not add a few hundred MB of stuff to
31  your distribution
32 
33  These and other limitations could cause serious legal problems if you ignore
34  them, so it is best to simply contact us or the Free Software Foundation, if
35  you have any questions.
36 
37  Joseph Toppi - toppij@gmail.com
38  John Blackwood - makoenergy02@gmail.com
39 */
40 /*
41  -----------------------------------------------------------------------------
42  This source file is part of ogre-procedural
43 
44  For the latest info, see http://code.google.com/p/ogre-procedural/
45 
46  Copyright (c) 2010-2013 Michael Broutin
47 
48  Permission is hereby granted, free of charge, to any person obtaining a copy
49  of this software and associated documentation files (the "Software"), to deal
50  in the Software without restriction, including without limitation the rights
51  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
52  copies of the Software, and to permit persons to whom the Software is
53  furnished to do so, subject to the following conditions:
54 
55  The above copyright notice and this permission notice shall be included in
56  all copies or substantial portions of the Software.
57 
58  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
59  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
60  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
61  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
62  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
63  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
64  THE SOFTWARE.
65  -----------------------------------------------------------------------------
66  */
67 #ifndef _graphicsproceduralicospheregenerator_cpp
68 #define _graphicsproceduralicospheregenerator_cpp
69 
70 #include "Graphics/Procedural/Mesh/icospheregenerator.h"
71 
72 #include "MathTools/mathtools.h"
73 #include "exception.h"
74 
75 namespace Mezzanine
76 {
77  namespace Graphics
78  {
79  namespace Procedural
80  {
81  IcoSphereGenerator::IcoSphereGenerator(const Real Radius, const Whole Iterations) :
82  SphereRadius(Radius),
83  NumIterations(Iterations)
84  { }
85 
87  { }
88 
89  ///////////////////////////////////////////////////////////////////////////////
90  // Utility
91 
93  {
94  std::vector<Vector3> Vertices;
95  Integer Offset = 0;
96 
97  /// Step 1 : Generate icosahedron
98  Real phi = .5f * ( 1.f + sqrt(5.f) );
99  Real invnorm = 1 / sqrt( phi * phi + 1 );
100 
101  Vertices.push_back( Vector3(-1, phi, 0) * invnorm );//0
102  Vertices.push_back( Vector3( 1, phi, 0) * invnorm );//1
103  Vertices.push_back( Vector3(0, 1, -phi) * invnorm );//2
104  Vertices.push_back( Vector3(0, 1, phi) * invnorm );//3
105  Vertices.push_back( Vector3(-phi,0, -1) * invnorm );//4
106  Vertices.push_back( Vector3(-phi,0, 1) * invnorm );//5
107  Vertices.push_back( Vector3( phi,0, -1) * invnorm );//6
108  Vertices.push_back( Vector3( phi,0, 1) * invnorm );//7
109  Vertices.push_back( Vector3(0, -1, -phi) * invnorm );//8
110  Vertices.push_back( Vector3(0, -1, phi) * invnorm );//9
111  Vertices.push_back( Vector3(-1, -phi,0) * invnorm );//10
112  Vertices.push_back( Vector3( 1, -phi,0) * invnorm );//11
113 
114  Integer FirstFaces[] = {0,1,2,
115  0,3,1,
116  0,4,5,
117  1,7,6,
118  1,6,2,
119  1,3,7,
120  0,2,4,
121  0,5,3,
122  2,6,8,
123  2,8,4,
124  3,5,9,
125  3,9,7,
126  11,6,7,
127  10,5,4,
128  10,4,8,
129  10,9,5,
130  11,8,6,
131  11,7,9,
132  10,8,11,
133  10,11,9};
134 
135  std::vector<Integer> Faces(FirstFaces, FirstFaces + sizeof(FirstFaces) / sizeof(*FirstFaces) );
136  Integer Size = 60;
137 
138  /// Step 2 : tessellate
139  for( Whole Iteration = 0 ; Iteration < this->NumIterations ; ++Iteration )
140  {
141  Size *= 4;
142  std::vector<Integer> NewFaces;
143  NewFaces.clear();
144  for( Integer Index = 0 ; Index < Size / 12 ; ++Index )
145  {
146  Integer i1 = Faces[ Index * 3 ];
147  Integer i2 = Faces[ Index * 3 + 1 ];
148  Integer i3 = Faces[ Index * 3 + 2 ];
149  Integer i12 = Vertices.size();
150  Integer i23 = i12 + 1;
151  Integer i13 = i12 + 2;
152  Vector3 v1 = Vertices[ i1 ];
153  Vector3 v2 = Vertices[ i2 ];
154  Vector3 v3 = Vertices[ i3 ];
155  //make 1 vertice at the center of each edge and project it onto the sphere
156  Vertices.push_back( ( v1 + v2 ).GetNormal() );
157  Vertices.push_back( ( v2 + v3 ).GetNormal() );
158  Vertices.push_back( ( v1 + v3 ).GetNormal() );
159  //now recreate indices
160  NewFaces.push_back(i1);
161  NewFaces.push_back(i12);
162  NewFaces.push_back(i13);
163  NewFaces.push_back(i2);
164  NewFaces.push_back(i23);
165  NewFaces.push_back(i12);
166  NewFaces.push_back(i3);
167  NewFaces.push_back(i13);
168  NewFaces.push_back(i23);
169  NewFaces.push_back(i12);
170  NewFaces.push_back(i23);
171  NewFaces.push_back(i13);
172  }
173  Faces.swap(NewFaces);
174  }
175 
176  /// Step 3 : generate texcoords
177  std::vector<Vector2> TexCoords;
178  for( UInt16 Index = 0 ; Index < Vertices.size() ; Index++ )
179  {
180  const Vector3& vec = Vertices[Index];
181  Real u, v;
182  Real r0 = sqrtf( vec.X * vec.X + vec.Z * vec.Z );
183  Real alpha;
184  alpha = atan2f(vec.Z,vec.X);
185  u = alpha / MathTools::GetTwoPi() + .5f;
186  v = atan2f(vec.Y, r0) / MathTools::GetPi() + .5f;
187  TexCoords.push_back( Vector2(u,v) );
188  }
189 
190  /// Step 4 : fix texcoords
191  // find Vertices to split
192  std::vector<Integer> IndexToSplit;
193  for( Whole Index = 0 ; Index < Faces.size() / 3 ; ++Index )
194  {
195  Vector2& t0 = TexCoords[ Faces[ Index * 3 + 0 ] ];
196  Vector2& t1 = TexCoords[ Faces[ Index * 3 + 1 ] ];
197  Vector2& t2 = TexCoords[ Faces[ Index * 3 + 2 ] ];
198  if( MathTools::Abs( t2.X - t0.X ) > 0.5 ) {
199  if( t0.X < 0.5 ) {
200  IndexToSplit.push_back( Faces[ Index * 3 ] );
201  }else{
202  IndexToSplit.push_back( Faces[ Index * 3 + 2 ] );
203  }
204  }
205  if( MathTools::Abs( t1.X - t0.X ) > 0.5 ) {
206  if( t0.X < 0.5 ) {
207  IndexToSplit.push_back( Faces[ Index * 3 ] );
208  }else{
209  IndexToSplit.push_back( Faces[ Index * 3 + 1 ] );
210  }
211  }
212  if( MathTools::Abs( t2.X - t1.X ) > 0.5 ) {
213  if( t1.X < 0.5 ) {
214  IndexToSplit.push_back( Faces[ Index * 3 + 1 ] );
215  }else{
216  IndexToSplit.push_back( Faces[ Index * 3 + 2 ] );
217  }
218  }
219  }
220 
221  //split Vertices
222  for( UInt16 Split = 0 ; Split < IndexToSplit.size() ; Split++ )
223  {
224  Integer Index = IndexToSplit[Split];
225  //duplicate vertex
226  Vector3 v = Vertices[Index];
227  Vector2 t = TexCoords[Index] + Vector2(1.0,0.0);
228  Vertices.push_back(v);
229  TexCoords.push_back(t);
230  Integer NewIndex = Vertices.size() - 1;
231  //reassign indices
232  for( UInt16 j = 0; j < Faces.size() ; j++ )
233  {
234  if( Faces[j] == Index ) {
235  Integer index1 = Faces[ ( j + 1 ) % 3 + ( j / 3 ) * 3 ];
236  Integer index2 = Faces[ ( j + 2 ) % 3 + ( j / 3 ) * 3 ];
237  if( ( TexCoords[index1].X > 0.5 ) || ( TexCoords[index2].X > 0.5 ) ) {
238  Faces[j] = NewIndex;
239  }
240  }
241  }
242  }
243 
244  /// Step 5 : realize
245  Buffer.RebaseOffset();
246  Buffer.EstimateVertexCount( Vertices.size() );
247  Buffer.EstimateIndexCount(Size);
248 
249  for( UInt16 Index = 0 ; Index < Vertices.size() ; ++Index )
250  {
251  this->AddPoint(Buffer, Vertices[Index] * this->SphereRadius,
252  Vertices[Index],//note : Vertices are already normalised
253  Vector2( TexCoords[Index].X, TexCoords[Index].Y ) );
254  }
255  for( UInt16 Index = 0 ; Index < Size ; ++Index )
256  {
257  Buffer.AddIndex( Offset + Faces[Index] );
258  }
259  Offset += Vertices.size();
260  }
261 
262  ///////////////////////////////////////////////////////////////////////////////
263  // Configuration
264 
266  {
267  if( Radius <= 0.0 )
268  MEZZ_EXCEPTION(ExceptionBase::PARAMETERS_EXCEPTION,"Radius for a generated ico-sphere mesh must be greater than zero.");
269 
270  this->SphereRadius = Radius;
271  return *this;
272  }
273 
275  {
276  if( Iterations == 0 )
277  MEZZ_EXCEPTION(ExceptionBase::PARAMETERS_EXCEPTION,"Number of Iterations for generating ico-sphere mesh much be greater than zero.");
278 
279  this->NumIterations = Iterations;
280  return *this;
281  }
282  }//Procedural
283  }//Graphics
284 }//Mezzanine
285 
286 #endif
Real X
Coordinate on the X vector.
Definition: vector3.h:85
Real Z
Coordinate on the Z vector.
Definition: vector3.h:89
A convenience buffer that stores vertices and indices of a mesh to be generated.
#define MEZZ_EXCEPTION(num, desc)
An easy way to throw exceptions with rich information.
Definition: exception.h:3048
void EstimateIndexCount(const Whole IndexCount)
Gives an estimation of the number of indices needed for this triangle buffer.
int Integer
A datatype used to represent any integer close to.
Definition: datatypes.h:154
This implements the exception hiearchy for Mezzanine.
float Real
A Datatype used to represent a real floating point number.
Definition: datatypes.h:141
uint16_t UInt16
An 16-bit unsigned integer.
Definition: datatypes.h:122
Real X
Coordinate on the X vector.
Definition: vector2.h:67
void EstimateVertexCount(const Whole VertexCount)
Gives an estimation of the number of vertices need for this triangle buffer.
This is used to represent a point on a 2 dimentional area, such as a screen.
Definition: vector2.h:63
Real Y
Coordinate on the Y vector.
Definition: vector3.h:87
A generator class for a sphere mesh where all triangles are the same size.
virtual void AddToTriangleBuffer(TriangleBuffer &Buffer) const
Adds the vertices and indices as configured in this generator to a triangle buffer.
void AddPoint(TriangleBuffer &Buffer, const Vector3 &Loc, const Vector3 &Norm, const Vector2 &UV) const
Adds a new point to a triangle buffer, using the format defined for that MeshGenerator.
Thrown when parameters are checked at runtime and found invalid.
Definition: exception.h:108
TriangleBuffer & AddIndex(const Integer Index)
Adds an index to the index buffer.
This is used to represent a point in space, or a vector through space.
Definition: vector3.h:77
The bulk of the engine components go in this namspace.
Definition: actor.cpp:56
unsigned long Whole
Whole is an unsigned integer, it will be at least 32bits in size.
Definition: datatypes.h:151
IcoSphereGenerator & SetRadius(const Real Radius)
Sets the radius of the sphere. the radius is set to 0 or less, a PARAMETERS_EXCEPTION will be thrown...
IcoSphereGenerator(const Real Radius, const Whole Iterations=2)
Class constructor.
IcoSphereGenerator & SetNumIterations(const Whole Iterations)
Sets the number of iterations needed to build the sphere mesh.
Whole NumIterations
The number of iterations needed to build the sphere mesh.