vrshoot

view libs/assimp/StandardShapes.cpp @ 0:b2f14e535253

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 01 Feb 2014 19:58:19 +0200
parents
children
line source
1 /*
2 Open Asset Import Library (assimp)
3 ----------------------------------------------------------------------
5 Copyright (c) 2006-2012, assimp team
6 All rights reserved.
8 Redistribution and use of this software in source and binary forms,
9 with or without modification, are permitted provided that the
10 following conditions are met:
12 * Redistributions of source code must retain the above
13 copyright notice, this list of conditions and the
14 following disclaimer.
16 * Redistributions in binary form must reproduce the above
17 copyright notice, this list of conditions and the
18 following disclaimer in the documentation and/or other
19 materials provided with the distribution.
21 * Neither the name of the assimp team, nor the names of its
22 contributors may be used to endorse or promote products
23 derived from this software without specific prior
24 written permission of the assimp team.
26 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 ----------------------------------------------------------------------
39 */
41 /** @file StandardShapes.cpp
42 * @brief Implementation of the StandardShapes class
43 *
44 * The primitive geometry data comes from
45 * http://geometrictools.com/Documentation/PlatonicSolids.pdf.
46 */
48 #include "AssimpPCH.h"
49 #include "StandardShapes.h"
51 namespace Assimp {
54 # define ADD_TRIANGLE(n0,n1,n2) \
55 positions.push_back(n0); \
56 positions.push_back(n1); \
57 positions.push_back(n2);
59 # define ADD_PENTAGON(n0,n1,n2,n3,n4) \
60 if (polygons) \
61 { \
62 positions.push_back(n0); \
63 positions.push_back(n1); \
64 positions.push_back(n2); \
65 positions.push_back(n3); \
66 positions.push_back(n4); \
67 } \
68 else \
69 { \
70 ADD_TRIANGLE(n0, n1, n2) \
71 ADD_TRIANGLE(n0, n2, n3) \
72 ADD_TRIANGLE(n0, n3, n4) \
73 }
75 # define ADD_QUAD(n0,n1,n2,n3) \
76 if (polygons) \
77 { \
78 positions.push_back(n0); \
79 positions.push_back(n1); \
80 positions.push_back(n2); \
81 positions.push_back(n3); \
82 } \
83 else \
84 { \
85 ADD_TRIANGLE(n0, n1, n2) \
86 ADD_TRIANGLE(n0, n2, n3) \
87 }
90 // ------------------------------------------------------------------------------------------------
91 // Fast subdivision for a mesh whose verts have a magnitude of 1
92 void Subdivide(std::vector<aiVector3D>& positions)
93 {
94 // assume this to be constant - (fixme: must be 1.0? I think so)
95 const float fl1 = positions[0].Length();
97 unsigned int origSize = (unsigned int)positions.size();
98 for (unsigned int i = 0 ; i < origSize ; i+=3)
99 {
100 aiVector3D& tv0 = positions[i];
101 aiVector3D& tv1 = positions[i+1];
102 aiVector3D& tv2 = positions[i+2];
104 aiVector3D a = tv0, b = tv1, c = tv2;
105 aiVector3D v1 = aiVector3D(a.x+b.x, a.y+b.y, a.z+b.z).Normalize()*fl1;
106 aiVector3D v2 = aiVector3D(a.x+c.x, a.y+c.y, a.z+c.z).Normalize()*fl1;
107 aiVector3D v3 = aiVector3D(b.x+c.x, b.y+c.y, b.z+c.z).Normalize()*fl1;
109 tv0 = v1; tv1 = v3; tv2 = v2; // overwrite the original
110 ADD_TRIANGLE(v1, v2, a);
111 ADD_TRIANGLE(v2, v3, c);
112 ADD_TRIANGLE(v3, v1, b);
113 }
114 }
116 // ------------------------------------------------------------------------------------------------
117 // Construct a mesh from given vertex positions
118 aiMesh* StandardShapes::MakeMesh(const std::vector<aiVector3D>& positions,
119 unsigned int numIndices)
120 {
121 if (positions.size() & numIndices || positions.empty() || !numIndices)
122 return NULL;
124 // Determine which kinds of primitives the mesh consists of
125 aiMesh* out = new aiMesh();
126 switch (numIndices)
127 {
128 case 1:
129 out->mPrimitiveTypes = aiPrimitiveType_POINT;
130 break;
131 case 2:
132 out->mPrimitiveTypes = aiPrimitiveType_LINE;
133 break;
134 case 3:
135 out->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
136 break;
137 default:
138 out->mPrimitiveTypes = aiPrimitiveType_POLYGON;
139 break;
140 };
142 out->mNumFaces = (unsigned int)positions.size() / numIndices;
143 out->mFaces = new aiFace[out->mNumFaces];
144 for (unsigned int i = 0, a = 0; i < out->mNumFaces;++i)
145 {
146 aiFace& f = out->mFaces[i];
147 f.mNumIndices = numIndices;
148 f.mIndices = new unsigned int[numIndices];
149 for (unsigned int i = 0; i < numIndices;++i,++a)
150 f.mIndices[i] = a;
151 }
152 out->mNumVertices = (unsigned int)positions.size();
153 out->mVertices = new aiVector3D[out->mNumVertices];
154 ::memcpy(out->mVertices,&positions[0],out->mNumVertices*sizeof(aiVector3D));
155 return out;
156 }
158 // ------------------------------------------------------------------------------------------------
159 // Construct a mesh with a specific shape (callback)
160 aiMesh* StandardShapes::MakeMesh ( unsigned int (*GenerateFunc)(
161 std::vector<aiVector3D>&))
162 {
163 std::vector<aiVector3D> temp;
164 unsigned num = (*GenerateFunc)(temp);
165 return MakeMesh(temp,num);
166 }
168 // ------------------------------------------------------------------------------------------------
169 // Construct a mesh with a specific shape (callback)
170 aiMesh* StandardShapes::MakeMesh ( unsigned int (*GenerateFunc)(
171 std::vector<aiVector3D>&, bool))
172 {
173 std::vector<aiVector3D> temp;
174 unsigned num = (*GenerateFunc)(temp,true);
175 return MakeMesh(temp,num);
176 }
178 // ------------------------------------------------------------------------------------------------
179 // Construct a mesh with a specific shape (callback)
180 aiMesh* StandardShapes::MakeMesh (unsigned int num, void (*GenerateFunc)(
181 unsigned int,std::vector<aiVector3D>&))
182 {
183 std::vector<aiVector3D> temp;
184 (*GenerateFunc)(num,temp);
185 return MakeMesh(temp,3);
186 }
188 // ------------------------------------------------------------------------------------------------
189 // Build an incosahedron with points.magnitude == 1
190 unsigned int StandardShapes::MakeIcosahedron(std::vector<aiVector3D>& positions)
191 {
192 positions.reserve(positions.size()+60);
194 const float t = (1.f + 2.236067977f)/2.f;
195 const float s = sqrt(1.f + t*t);
197 const aiVector3D v0 = aiVector3D(t,1.f, 0.f)/s;
198 const aiVector3D v1 = aiVector3D(-t,1.f, 0.f)/s;
199 const aiVector3D v2 = aiVector3D(t,-1.f, 0.f)/s;
200 const aiVector3D v3 = aiVector3D(-t,-1.f, 0.f)/s;
201 const aiVector3D v4 = aiVector3D(1.f, 0.f, t)/s;
202 const aiVector3D v5 = aiVector3D(1.f, 0.f,-t)/s;
203 const aiVector3D v6 = aiVector3D(-1.f, 0.f,t)/s;
204 const aiVector3D v7 = aiVector3D(-1.f, 0.f,-t)/s;
205 const aiVector3D v8 = aiVector3D(0.f, t, 1.f)/s;
206 const aiVector3D v9 = aiVector3D(0.f,-t, 1.f)/s;
207 const aiVector3D v10 = aiVector3D(0.f, t,-1.f)/s;
208 const aiVector3D v11 = aiVector3D(0.f,-t,-1.f)/s;
210 ADD_TRIANGLE(v0,v8,v4);
211 ADD_TRIANGLE(v0,v5,v10);
212 ADD_TRIANGLE(v2,v4,v9);
213 ADD_TRIANGLE(v2,v11,v5);
215 ADD_TRIANGLE(v1,v6,v8);
216 ADD_TRIANGLE(v1,v10,v7);
217 ADD_TRIANGLE(v3,v9,v6);
218 ADD_TRIANGLE(v3,v7,v11);
220 ADD_TRIANGLE(v0,v10,v8);
221 ADD_TRIANGLE(v1,v8,v10);
222 ADD_TRIANGLE(v2,v9,v11);
223 ADD_TRIANGLE(v3,v11,v9);
225 ADD_TRIANGLE(v4,v2,v0);
226 ADD_TRIANGLE(v5,v0,v2);
227 ADD_TRIANGLE(v6,v1,v3);
228 ADD_TRIANGLE(v7,v3,v1);
230 ADD_TRIANGLE(v8,v6,v4);
231 ADD_TRIANGLE(v9,v4,v6);
232 ADD_TRIANGLE(v10,v5,v7);
233 ADD_TRIANGLE(v11,v7,v5);
234 return 3;
235 }
237 // ------------------------------------------------------------------------------------------------
238 // Build a dodecahedron with points.magnitude == 1
239 unsigned int StandardShapes::MakeDodecahedron(std::vector<aiVector3D>& positions,
240 bool polygons /*= false*/)
241 {
242 positions.reserve(positions.size()+108);
244 const float a = 1.f / 1.7320508f;
245 const float b = sqrt((3.f-2.23606797f)/6.f);
246 const float c = sqrt((3.f+2.23606797f)/6.f);
248 const aiVector3D v0 = aiVector3D(a,a,a);
249 const aiVector3D v1 = aiVector3D(a,a,-a);
250 const aiVector3D v2 = aiVector3D(a,-a,a);
251 const aiVector3D v3 = aiVector3D(a,-a,-a);
252 const aiVector3D v4 = aiVector3D(-a,a,a);
253 const aiVector3D v5 = aiVector3D(-a,a,-a);
254 const aiVector3D v6 = aiVector3D(-a,-a,a);
255 const aiVector3D v7 = aiVector3D(-a,-a,-a);
256 const aiVector3D v8 = aiVector3D(b,c,0.f);
257 const aiVector3D v9 = aiVector3D(-b,c,0.f);
258 const aiVector3D v10 = aiVector3D(b,-c,0.f);
259 const aiVector3D v11 = aiVector3D(-b,-c,0.f);
260 const aiVector3D v12 = aiVector3D(c, 0.f, b);
261 const aiVector3D v13 = aiVector3D(c, 0.f, -b);
262 const aiVector3D v14 = aiVector3D(-c, 0.f, b);
263 const aiVector3D v15 = aiVector3D(-c, 0.f, -b);
264 const aiVector3D v16 = aiVector3D(0.f, b, c);
265 const aiVector3D v17 = aiVector3D(0.f, -b, c);
266 const aiVector3D v18 = aiVector3D(0.f, b, -c);
267 const aiVector3D v19 = aiVector3D(0.f, -b, -c);
269 ADD_PENTAGON(v0, v8, v9, v4, v16);
270 ADD_PENTAGON(v0, v12, v13, v1, v8);
271 ADD_PENTAGON(v0, v16, v17, v2, v12);
272 ADD_PENTAGON(v8, v1, v18, v5, v9);
273 ADD_PENTAGON(v12, v2, v10, v3, v13);
274 ADD_PENTAGON(v16, v4, v14, v6, v17);
275 ADD_PENTAGON(v9, v5, v15, v14, v4);
277 ADD_PENTAGON(v6, v11, v10, v2, v17);
278 ADD_PENTAGON(v3, v19, v18, v1, v13);
279 ADD_PENTAGON(v7, v15, v5, v18, v19);
280 ADD_PENTAGON(v7, v11, v6, v14, v15);
281 ADD_PENTAGON(v7, v19, v3, v10, v11);
282 return (polygons ? 5 : 3);
283 }
285 // ------------------------------------------------------------------------------------------------
286 // Build an octahedron with points.magnitude == 1
287 unsigned int StandardShapes::MakeOctahedron(std::vector<aiVector3D>& positions)
288 {
289 positions.reserve(positions.size()+24);
291 const aiVector3D v0 = aiVector3D(1.0f, 0.f, 0.f) ;
292 const aiVector3D v1 = aiVector3D(-1.0f, 0.f, 0.f);
293 const aiVector3D v2 = aiVector3D(0.f, 1.0f, 0.f);
294 const aiVector3D v3 = aiVector3D(0.f, -1.0f, 0.f);
295 const aiVector3D v4 = aiVector3D(0.f, 0.f, 1.0f);
296 const aiVector3D v5 = aiVector3D(0.f, 0.f, -1.0f);
298 ADD_TRIANGLE(v4,v0,v2);
299 ADD_TRIANGLE(v4,v2,v1);
300 ADD_TRIANGLE(v4,v1,v3);
301 ADD_TRIANGLE(v4,v3,v0);
303 ADD_TRIANGLE(v5,v2,v0);
304 ADD_TRIANGLE(v5,v1,v2);
305 ADD_TRIANGLE(v5,v3,v1);
306 ADD_TRIANGLE(v5,v0,v3);
307 return 3;
308 }
310 // ------------------------------------------------------------------------------------------------
311 // Build a tetrahedron with points.magnitude == 1
312 unsigned int StandardShapes::MakeTetrahedron(std::vector<aiVector3D>& positions)
313 {
314 positions.reserve(positions.size()+9);
316 const float a = 1.41421f/3.f;
317 const float b = 2.4494f/3.f;
319 const aiVector3D v0 = aiVector3D(0.f,0.f,1.f);
320 const aiVector3D v1 = aiVector3D(2*a,0,-1.f/3.f);
321 const aiVector3D v2 = aiVector3D(-a,b,-1.f/3.f);
322 const aiVector3D v3 = aiVector3D(-a,-b,-1.f/3.f);
324 ADD_TRIANGLE(v0,v1,v2);
325 ADD_TRIANGLE(v0,v2,v3);
326 ADD_TRIANGLE(v0,v3,v1);
327 ADD_TRIANGLE(v1,v3,v2);
328 return 3;
329 }
331 // ------------------------------------------------------------------------------------------------
332 // Build a hexahedron with points.magnitude == 1
333 unsigned int StandardShapes::MakeHexahedron(std::vector<aiVector3D>& positions,
334 bool polygons /*= false*/)
335 {
336 positions.reserve(positions.size()+36);
337 const float length = 1.f/1.73205080f;
339 const aiVector3D v0 = aiVector3D(-1.f,-1.f,-1.f)*length;
340 const aiVector3D v1 = aiVector3D(1.f,-1.f,-1.f)*length;
341 const aiVector3D v2 = aiVector3D(1.f,1.f,-1.f)*length;
342 const aiVector3D v3 = aiVector3D(-1.f,1.f,-1.f)*length;
343 const aiVector3D v4 = aiVector3D(-1.f,-1.f,1.f)*length;
344 const aiVector3D v5 = aiVector3D(1.f,-1.f,1.f)*length;
345 const aiVector3D v6 = aiVector3D(1.f,1.f,1.f)*length;
346 const aiVector3D v7 = aiVector3D(-1.f,1.f,1.f)*length;
348 ADD_QUAD(v0,v3,v2,v1);
349 ADD_QUAD(v0,v1,v5,v4);
350 ADD_QUAD(v0,v4,v7,v3);
351 ADD_QUAD(v6,v5,v1,v2);
352 ADD_QUAD(v6,v2,v3,v7);
353 ADD_QUAD(v6,v7,v4,v5);
354 return (polygons ? 4 : 3);
355 }
357 // Cleanup ...
358 #undef ADD_TRIANGLE
359 #undef ADD_QUAD
360 #undef ADD_PENTAGON
362 // ------------------------------------------------------------------------------------------------
363 // Create a subdivision sphere
364 void StandardShapes::MakeSphere(unsigned int tess,
365 std::vector<aiVector3D>& positions)
366 {
367 // Reserve enough storage. Every subdivision
368 // splits each triangle in 4, the icosahedron consists of 60 verts
369 positions.reserve(positions.size()+60 * integer_pow(4, tess));
371 // Construct an icosahedron to start with
372 MakeIcosahedron(positions);
374 // ... and subdivide it until the requested output
375 // tesselation is reached
376 for (unsigned int i = 0; i<tess;++i)
377 Subdivide(positions);
378 }
380 // ------------------------------------------------------------------------------------------------
381 // Build a cone
382 void StandardShapes::MakeCone(float height,float radius1,
383 float radius2,unsigned int tess,
384 std::vector<aiVector3D>& positions,bool bOpen /*= false */)
385 {
386 // Sorry, a cone with less than 3 segments makes ABSOLUTELY NO SENSE
387 if (tess < 3 || !height)
388 return;
390 size_t old = positions.size();
392 // No negative radii
393 radius1 = ::fabs(radius1);
394 radius2 = ::fabs(radius2);
396 float halfHeight = height / 2;
398 // radius1 is always the smaller one
399 if (radius2 > radius1)
400 {
401 std::swap(radius2,radius1);
402 halfHeight = -halfHeight;
403 }
404 else old = SIZE_MAX;
406 // Use a large epsilon to check whether the cone is pointy
407 if (radius1 < (radius2-radius1)*10e-3f)radius1 = 0.f;
409 // We will need 3*2 verts per segment + 3*2 verts per segment
410 // if the cone is closed
411 const unsigned int mem = tess*6 + (!bOpen ? tess*3 * (radius1 ? 2 : 1) : 0);
412 positions.reserve(positions.size () + mem);
414 // Now construct all segments
415 const float angle_delta = (float)AI_MATH_TWO_PI / tess;
416 const float angle_max = (float)AI_MATH_TWO_PI;
418 float s = 1.f; // cos(angle == 0);
419 float t = 0.f; // sin(angle == 0);
421 for (float angle = 0.f; angle < angle_max; )
422 {
423 const aiVector3D v1 = aiVector3D (s * radius1, -halfHeight, t * radius1 );
424 const aiVector3D v2 = aiVector3D (s * radius2, halfHeight, t * radius2 );
426 const float next = angle + angle_delta;
427 float s2 = ::cos(next);
428 float t2 = ::sin(next);
430 const aiVector3D v3 = aiVector3D (s2 * radius2, halfHeight, t2 * radius2 );
431 const aiVector3D v4 = aiVector3D (s2 * radius1, -halfHeight, t2 * radius1 );
433 positions.push_back(v1);
434 positions.push_back(v2);
435 positions.push_back(v3);
436 positions.push_back(v4);
437 positions.push_back(v1);
438 positions.push_back(v3);
440 if (!bOpen)
441 {
442 // generate the end 'cap'
443 positions.push_back(aiVector3D(s * radius2, halfHeight, t * radius2 ));
444 positions.push_back(aiVector3D(s2 * radius2, halfHeight, t2 * radius2 ));
445 positions.push_back(aiVector3D(0.f, halfHeight, 0.f));
448 if (radius1)
449 {
450 // generate the other end 'cap'
451 positions.push_back(aiVector3D(s * radius1, -halfHeight, t * radius1 ));
452 positions.push_back(aiVector3D(s2 * radius1, -halfHeight, t2 * radius1 ));
453 positions.push_back(aiVector3D(0.f, -halfHeight, 0.f));
455 }
456 }
457 s = s2;
458 t = t2;
459 angle = next;
460 }
462 // Need to flip face order?
463 if ( SIZE_MAX != old ) {
464 for (size_t s = old; s < positions.size();s += 3) {
465 std::swap(positions[s],positions[s+1]);
466 }
467 }
468 }
470 // ------------------------------------------------------------------------------------------------
471 // Build a circle
472 void StandardShapes::MakeCircle(float radius, unsigned int tess,
473 std::vector<aiVector3D>& positions)
474 {
475 // Sorry, a circle with less than 3 segments makes ABSOLUTELY NO SENSE
476 if (tess < 3 || !radius)
477 return;
479 radius = ::fabs(radius);
481 // We will need 3 vertices per segment
482 positions.reserve(positions.size()+tess*3);
484 const float angle_delta = (float)AI_MATH_TWO_PI / tess;
485 const float angle_max = (float)AI_MATH_TWO_PI;
487 float s = 1.f; // cos(angle == 0);
488 float t = 0.f; // sin(angle == 0);
490 for (float angle = 0.f; angle < angle_max; )
491 {
492 positions.push_back(aiVector3D(s * radius,0.f,t * radius));
493 angle += angle_delta;
494 s = ::cos(angle);
495 t = ::sin(angle);
496 positions.push_back(aiVector3D(s * radius,0.f,t * radius));
498 positions.push_back(aiVector3D(0.f,0.f,0.f));
499 }
500 }
502 } // ! Assimp