1 | /* |
---|---|

2 | Open Asset Import Library (assimp) |

3 | ---------------------------------------------------------------------- |

4 | |

5 | Copyright (c) 2006-2017, assimp team |

6 | |

7 | All rights reserved. |

8 | |

9 | Redistribution and use of this software in source and binary forms, |

10 | with or without modification, are permitted provided that the |

11 | following conditions are met: |

12 | |

13 | * Redistributions of source code must retain the above |

14 | copyright notice, this list of conditions and the |

15 | following disclaimer. |

16 | |

17 | * Redistributions in binary form must reproduce the above |

18 | copyright notice, this list of conditions and the |

19 | following disclaimer in the documentation and/or other |

20 | materials provided with the distribution. |

21 | |

22 | * Neither the name of the assimp team, nor the names of its |

23 | contributors may be used to endorse or promote products |

24 | derived from this software without specific prior |

25 | written permission of the assimp team. |

26 | |

27 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |

28 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |

29 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |

30 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |

31 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |

32 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |

33 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |

34 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |

35 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |

36 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |

37 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |

38 | |

39 | ---------------------------------------------------------------------- |

40 | */ |

41 | |

42 | /** @file StandardShapes.cpp |

43 | * @brief Implementation of the StandardShapes class |

44 | * |

45 | * The primitive geometry data comes from |

46 | * http://geometrictools.com/Documentation/PlatonicSolids.pdf. |

47 | */ |

48 | |

49 | #include "StandardShapes.h" |

50 | #include "StringComparison.h" |

51 | #include <stddef.h> |

52 | #include <assimp/Defines.h> |

53 | #include <assimp/mesh.h> |

54 | |

55 | namespace Assimp { |

56 | |

57 | |

58 | # define ADD_TRIANGLE(n0,n1,n2) \ |

59 | positions.push_back(n0); \ |

60 | positions.push_back(n1); \ |

61 | positions.push_back(n2); |

62 | |

63 | # define ADD_PENTAGON(n0,n1,n2,n3,n4) \ |

64 | if (polygons) \ |

65 | { \ |

66 | positions.push_back(n0); \ |

67 | positions.push_back(n1); \ |

68 | positions.push_back(n2); \ |

69 | positions.push_back(n3); \ |

70 | positions.push_back(n4); \ |

71 | } \ |

72 | else \ |

73 | { \ |

74 | ADD_TRIANGLE(n0, n1, n2) \ |

75 | ADD_TRIANGLE(n0, n2, n3) \ |

76 | ADD_TRIANGLE(n0, n3, n4) \ |

77 | } |

78 | |

79 | # define ADD_QUAD(n0,n1,n2,n3) \ |

80 | if (polygons) \ |

81 | { \ |

82 | positions.push_back(n0); \ |

83 | positions.push_back(n1); \ |

84 | positions.push_back(n2); \ |

85 | positions.push_back(n3); \ |

86 | } \ |

87 | else \ |

88 | { \ |

89 | ADD_TRIANGLE(n0, n1, n2) \ |

90 | ADD_TRIANGLE(n0, n2, n3) \ |

91 | } |

92 | |

93 | |

94 | // ------------------------------------------------------------------------------------------------ |

95 | // Fast subdivision for a mesh whose verts have a magnitude of 1 |

96 | void Subdivide(std::vector<aiVector3D>& positions) |

97 | { |

98 | // assume this to be constant - (fixme: must be 1.0? I think so) |

99 | const ai_real fl1 = positions[0].Length(); |

100 | |

101 | unsigned int origSize = (unsigned int)positions.size(); |

102 | for (unsigned int i = 0 ; i < origSize ; i+=3) |

103 | { |

104 | aiVector3D& tv0 = positions[i]; |

105 | aiVector3D& tv1 = positions[i+1]; |

106 | aiVector3D& tv2 = positions[i+2]; |

107 | |

108 | aiVector3D a = tv0, b = tv1, c = tv2; |

109 | aiVector3D v1 = aiVector3D(a.x+b.x, a.y+b.y, a.z+b.z).Normalize()*fl1; |

110 | aiVector3D v2 = aiVector3D(a.x+c.x, a.y+c.y, a.z+c.z).Normalize()*fl1; |

111 | aiVector3D v3 = aiVector3D(b.x+c.x, b.y+c.y, b.z+c.z).Normalize()*fl1; |

112 | |

113 | tv0 = v1; tv1 = v3; tv2 = v2; // overwrite the original |

114 | ADD_TRIANGLE(v1, v2, a); |

115 | ADD_TRIANGLE(v2, v3, c); |

116 | ADD_TRIANGLE(v3, v1, b); |

117 | } |

118 | } |

119 | |

120 | // ------------------------------------------------------------------------------------------------ |

121 | // Construct a mesh from given vertex positions |

122 | aiMesh* StandardShapes::MakeMesh(const std::vector<aiVector3D>& positions, |

123 | unsigned int numIndices) |

124 | { |

125 | if (positions.empty() || !numIndices) return NULL; |

126 | |

127 | // Determine which kinds of primitives the mesh consists of |

128 | aiMesh* out = new aiMesh(); |

129 | switch (numIndices) |

130 | { |

131 | case 1: |

132 | out->mPrimitiveTypes = aiPrimitiveType_POINT; |

133 | break; |

134 | case 2: |

135 | out->mPrimitiveTypes = aiPrimitiveType_LINE; |

136 | break; |

137 | case 3: |

138 | out->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; |

139 | break; |

140 | default: |

141 | out->mPrimitiveTypes = aiPrimitiveType_POLYGON; |

142 | break; |

143 | }; |

144 | |

145 | out->mNumFaces = (unsigned int)positions.size() / numIndices; |

146 | out->mFaces = new aiFace[out->mNumFaces]; |

147 | for (unsigned int i = 0, a = 0; i < out->mNumFaces;++i) |

148 | { |

149 | aiFace& f = out->mFaces[i]; |

150 | f.mNumIndices = numIndices; |

151 | f.mIndices = new unsigned int[numIndices]; |

152 | for (unsigned int i = 0; i < numIndices;++i,++a) |

153 | f.mIndices[i] = a; |

154 | } |

155 | out->mNumVertices = (unsigned int)positions.size(); |

156 | out->mVertices = new aiVector3D[out->mNumVertices]; |

157 | ::memcpy(out->mVertices,&positions[0],out->mNumVertices*sizeof(aiVector3D)); |

158 | return out; |

159 | } |

160 | |

161 | // ------------------------------------------------------------------------------------------------ |

162 | // Construct a mesh with a specific shape (callback) |

163 | aiMesh* StandardShapes::MakeMesh ( unsigned int (*GenerateFunc)( |

164 | std::vector<aiVector3D>&)) |

165 | { |

166 | std::vector<aiVector3D> temp; |

167 | unsigned num = (*GenerateFunc)(temp); |

168 | return MakeMesh(temp,num); |

169 | } |

170 | |

171 | // ------------------------------------------------------------------------------------------------ |

172 | // Construct a mesh with a specific shape (callback) |

173 | aiMesh* StandardShapes::MakeMesh ( unsigned int (*GenerateFunc)( |

174 | std::vector<aiVector3D>&, bool)) |

175 | { |

176 | std::vector<aiVector3D> temp; |

177 | unsigned num = (*GenerateFunc)(temp,true); |

178 | return MakeMesh(temp,num); |

179 | } |

180 | |

181 | // ------------------------------------------------------------------------------------------------ |

182 | // Construct a mesh with a specific shape (callback) |

183 | aiMesh* StandardShapes::MakeMesh (unsigned int num, void (*GenerateFunc)( |

184 | unsigned int,std::vector<aiVector3D>&)) |

185 | { |

186 | std::vector<aiVector3D> temp; |

187 | (*GenerateFunc)(num,temp); |

188 | return MakeMesh(temp,3); |

189 | } |

190 | |

191 | // ------------------------------------------------------------------------------------------------ |

192 | // Build an incosahedron with points.magnitude == 1 |

193 | unsigned int StandardShapes::MakeIcosahedron(std::vector<aiVector3D>& positions) |

194 | { |

195 | positions.reserve(positions.size()+60); |

196 | |

197 | const ai_real t = ( ai_real( 1.0 )+ ai_real( 2.236067977 ) ) / ai_real( 2.0 ); |

198 | const ai_real s = std::sqrt(ai_real(1.0) + t*t); |

199 | |

200 | const aiVector3D v0 = aiVector3D(t,1.0, 0.0)/s; |

201 | const aiVector3D v1 = aiVector3D(-t,1.0, 0.0)/s; |

202 | const aiVector3D v2 = aiVector3D(t,-1.0, 0.0)/s; |

203 | const aiVector3D v3 = aiVector3D(-t,-1.0, 0.0)/s; |

204 | const aiVector3D v4 = aiVector3D(1.0, 0.0, t)/s; |

205 | const aiVector3D v5 = aiVector3D(1.0, 0.0,-t)/s; |

206 | const aiVector3D v6 = aiVector3D(-1.0, 0.0,t)/s; |

207 | const aiVector3D v7 = aiVector3D(-1.0, 0.0,-t)/s; |

208 | const aiVector3D v8 = aiVector3D(0.0, t, 1.0)/s; |

209 | const aiVector3D v9 = aiVector3D(0.0,-t, 1.0)/s; |

210 | const aiVector3D v10 = aiVector3D(0.0, t,-1.0)/s; |

211 | const aiVector3D v11 = aiVector3D(0.0,-t,-1.0)/s; |

212 | |

213 | ADD_TRIANGLE(v0,v8,v4); |

214 | ADD_TRIANGLE(v0,v5,v10); |

215 | ADD_TRIANGLE(v2,v4,v9); |

216 | ADD_TRIANGLE(v2,v11,v5); |

217 | |

218 | ADD_TRIANGLE(v1,v6,v8); |

219 | ADD_TRIANGLE(v1,v10,v7); |

220 | ADD_TRIANGLE(v3,v9,v6); |

221 | ADD_TRIANGLE(v3,v7,v11); |

222 | |

223 | ADD_TRIANGLE(v0,v10,v8); |

224 | ADD_TRIANGLE(v1,v8,v10); |

225 | ADD_TRIANGLE(v2,v9,v11); |

226 | ADD_TRIANGLE(v3,v11,v9); |

227 | |

228 | ADD_TRIANGLE(v4,v2,v0); |

229 | ADD_TRIANGLE(v5,v0,v2); |

230 | ADD_TRIANGLE(v6,v1,v3); |

231 | ADD_TRIANGLE(v7,v3,v1); |

232 | |

233 | ADD_TRIANGLE(v8,v6,v4); |

234 | ADD_TRIANGLE(v9,v4,v6); |

235 | ADD_TRIANGLE(v10,v5,v7); |

236 | ADD_TRIANGLE(v11,v7,v5); |

237 | return 3; |

238 | } |

239 | |

240 | // ------------------------------------------------------------------------------------------------ |

241 | // Build a dodecahedron with points.magnitude == 1 |

242 | unsigned int StandardShapes::MakeDodecahedron(std::vector<aiVector3D>& positions, |

243 | bool polygons /*= false*/) |

244 | { |

245 | positions.reserve(positions.size()+108); |

246 | |

247 | const ai_real a = ai_real( 1.0 ) / ai_real(1.7320508); |

248 | const ai_real b = std::sqrt(( ai_real( 3.0 )- ai_real( 2.23606797))/ ai_real( 6.0) ); |

249 | const ai_real c = std::sqrt(( ai_real( 3.0 )+ ai_real( 2.23606797f))/ ai_real( 6.0) ); |

250 | |

251 | const aiVector3D v0 = aiVector3D(a,a,a); |

252 | const aiVector3D v1 = aiVector3D(a,a,-a); |

253 | const aiVector3D v2 = aiVector3D(a,-a,a); |

254 | const aiVector3D v3 = aiVector3D(a,-a,-a); |

255 | const aiVector3D v4 = aiVector3D(-a,a,a); |

256 | const aiVector3D v5 = aiVector3D(-a,a,-a); |

257 | const aiVector3D v6 = aiVector3D(-a,-a,a); |

258 | const aiVector3D v7 = aiVector3D(-a,-a,-a); |

259 | const aiVector3D v8 = aiVector3D(b,c,0.0); |

260 | const aiVector3D v9 = aiVector3D(-b,c,0.0); |

261 | const aiVector3D v10 = aiVector3D(b,-c,0.0); |

262 | const aiVector3D v11 = aiVector3D(-b,-c,0.0); |

263 | const aiVector3D v12 = aiVector3D(c, 0.0, b); |

264 | const aiVector3D v13 = aiVector3D(c, 0.0, -b); |

265 | const aiVector3D v14 = aiVector3D(-c, 0.0, b); |

266 | const aiVector3D v15 = aiVector3D(-c, 0.0, -b); |

267 | const aiVector3D v16 = aiVector3D(0.0, b, c); |

268 | const aiVector3D v17 = aiVector3D(0.0, -b, c); |

269 | const aiVector3D v18 = aiVector3D(0.0, b, -c); |

270 | const aiVector3D v19 = aiVector3D(0.0, -b, -c); |

271 | |

272 | ADD_PENTAGON(v0, v8, v9, v4, v16); |

273 | ADD_PENTAGON(v0, v12, v13, v1, v8); |

274 | ADD_PENTAGON(v0, v16, v17, v2, v12); |

275 | ADD_PENTAGON(v8, v1, v18, v5, v9); |

276 | ADD_PENTAGON(v12, v2, v10, v3, v13); |

277 | ADD_PENTAGON(v16, v4, v14, v6, v17); |

278 | ADD_PENTAGON(v9, v5, v15, v14, v4); |

279 | |

280 | ADD_PENTAGON(v6, v11, v10, v2, v17); |

281 | ADD_PENTAGON(v3, v19, v18, v1, v13); |

282 | ADD_PENTAGON(v7, v15, v5, v18, v19); |

283 | ADD_PENTAGON(v7, v11, v6, v14, v15); |

284 | ADD_PENTAGON(v7, v19, v3, v10, v11); |

285 | return (polygons ? 5 : 3); |

286 | } |

287 | |

288 | // ------------------------------------------------------------------------------------------------ |

289 | // Build an octahedron with points.magnitude == 1 |

290 | unsigned int StandardShapes::MakeOctahedron(std::vector<aiVector3D>& positions) |

291 | { |

292 | positions.reserve(positions.size()+24); |

293 | |

294 | const aiVector3D v0 = aiVector3D(1.0, 0.0, 0.0) ; |

295 | const aiVector3D v1 = aiVector3D(-1.0, 0.0, 0.0); |

296 | const aiVector3D v2 = aiVector3D(0.0, 1.0, 0.0); |

297 | const aiVector3D v3 = aiVector3D(0.0, -1.0, 0.0); |

298 | const aiVector3D v4 = aiVector3D(0.0, 0.0, 1.0); |

299 | const aiVector3D v5 = aiVector3D(0.0, 0.0, -1.0); |

300 | |

301 | ADD_TRIANGLE(v4,v0,v2); |

302 | ADD_TRIANGLE(v4,v2,v1); |

303 | ADD_TRIANGLE(v4,v1,v3); |

304 | ADD_TRIANGLE(v4,v3,v0); |

305 | |

306 | ADD_TRIANGLE(v5,v2,v0); |

307 | ADD_TRIANGLE(v5,v1,v2); |

308 | ADD_TRIANGLE(v5,v3,v1); |

309 | ADD_TRIANGLE(v5,v0,v3); |

310 | return 3; |

311 | } |

312 | |

313 | // ------------------------------------------------------------------------------------------------ |

314 | // Build a tetrahedron with points.magnitude == 1 |

315 | unsigned int StandardShapes::MakeTetrahedron(std::vector<aiVector3D>& positions) |

316 | { |

317 | positions.reserve(positions.size()+9); |

318 | |

319 | const ai_real invThree = ai_real( 1.0 ) / ai_real( 3.0 ); |

320 | const ai_real a = ai_real( 1.41421 ) * invThree; |

321 | const ai_real b = ai_real( 2.4494 ) * invThree; |

322 | |

323 | const aiVector3D v0 = aiVector3D(0.0,0.0,1.0); |

324 | const aiVector3D v1 = aiVector3D(2*a,0,-invThree ); |

325 | const aiVector3D v2 = aiVector3D(-a,b,-invThree ); |

326 | const aiVector3D v3 = aiVector3D(-a,-b,-invThree ); |

327 | |

328 | ADD_TRIANGLE(v0,v1,v2); |

329 | ADD_TRIANGLE(v0,v2,v3); |

330 | ADD_TRIANGLE(v0,v3,v1); |

331 | ADD_TRIANGLE(v1,v3,v2); |

332 | return 3; |

333 | } |

334 | |

335 | // ------------------------------------------------------------------------------------------------ |

336 | // Build a hexahedron with points.magnitude == 1 |

337 | unsigned int StandardShapes::MakeHexahedron(std::vector<aiVector3D>& positions, |

338 | bool polygons /*= false*/) |

339 | { |

340 | positions.reserve(positions.size()+36); |

341 | const ai_real length = ai_real(1.0)/ai_real(1.73205080); |

342 | |

343 | const aiVector3D v0 = aiVector3D(-1.0,-1.0,-1.0)*length; |

344 | const aiVector3D v1 = aiVector3D(1.0,-1.0,-1.0)*length; |

345 | const aiVector3D v2 = aiVector3D(1.0,1.0,-1.0)*length; |

346 | const aiVector3D v3 = aiVector3D(-1.0,1.0,-1.0)*length; |

347 | const aiVector3D v4 = aiVector3D(-1.0,-1.0,1.0)*length; |

348 | const aiVector3D v5 = aiVector3D(1.0,-1.0,1.0)*length; |

349 | const aiVector3D v6 = aiVector3D(1.0,1.0,1.0)*length; |

350 | const aiVector3D v7 = aiVector3D(-1.0,1.0,1.0)*length; |

351 | |

352 | ADD_QUAD(v0,v3,v2,v1); |

353 | ADD_QUAD(v0,v1,v5,v4); |

354 | ADD_QUAD(v0,v4,v7,v3); |

355 | ADD_QUAD(v6,v5,v1,v2); |

356 | ADD_QUAD(v6,v2,v3,v7); |

357 | ADD_QUAD(v6,v7,v4,v5); |

358 | return (polygons ? 4 : 3); |

359 | } |

360 | |

361 | // Cleanup ... |

362 | #undef ADD_TRIANGLE |

363 | #undef ADD_QUAD |

364 | #undef ADD_PENTAGON |

365 | |

366 | // ------------------------------------------------------------------------------------------------ |

367 | // Create a subdivision sphere |

368 | void StandardShapes::MakeSphere(unsigned int tess, |

369 | std::vector<aiVector3D>& positions) |

370 | { |

371 | // Reserve enough storage. Every subdivision |

372 | // splits each triangle in 4, the icosahedron consists of 60 verts |

373 | positions.reserve(positions.size()+60 * integer_pow(4, tess)); |

374 | |

375 | // Construct an icosahedron to start with |

376 | MakeIcosahedron(positions); |

377 | |

378 | // ... and subdivide it until the requested output |

379 | // tesselation is reached |

380 | for (unsigned int i = 0; i<tess;++i) |

381 | Subdivide(positions); |

382 | } |

383 | |

384 | // ------------------------------------------------------------------------------------------------ |

385 | // Build a cone |

386 | void StandardShapes::MakeCone(ai_real height,ai_real radius1, |

387 | ai_real radius2,unsigned int tess, |

388 | std::vector<aiVector3D>& positions,bool bOpen /*= false */) |

389 | { |

390 | // Sorry, a cone with less than 3 segments makes ABSOLUTELY NO SENSE |

391 | if (tess < 3 || !height) |

392 | return; |

393 | |

394 | size_t old = positions.size(); |

395 | |

396 | // No negative radii |

397 | radius1 = std::fabs(radius1); |

398 | radius2 = std::fabs(radius2); |

399 | |

400 | ai_real halfHeight = height / ai_real(2.0); |

401 | |

402 | // radius1 is always the smaller one |

403 | if (radius2 > radius1) |

404 | { |

405 | std::swap(radius2,radius1); |

406 | halfHeight = -halfHeight; |

407 | } |

408 | else old = SIZE_MAX; |

409 | |

410 | // Use a large epsilon to check whether the cone is pointy |

411 | if (radius1 < (radius2-radius1)*10e-3)radius1 = 0.0; |

412 | |

413 | // We will need 3*2 verts per segment + 3*2 verts per segment |

414 | // if the cone is closed |

415 | const unsigned int mem = tess*6 + (!bOpen ? tess*3 * (radius1 ? 2 : 1) : 0); |

416 | positions.reserve(positions.size () + mem); |

417 | |

418 | // Now construct all segments |

419 | const ai_real angle_delta = (ai_real)AI_MATH_TWO_PI / tess; |

420 | const ai_real angle_max = (ai_real)AI_MATH_TWO_PI; |

421 | |

422 | ai_real s = 1.0; // std::cos(angle == 0); |

423 | ai_real t = 0.0; // std::sin(angle == 0); |

424 | |

425 | for (ai_real angle = 0.0; angle < angle_max; ) |

426 | { |

427 | const aiVector3D v1 = aiVector3D (s * radius1, -halfHeight, t * radius1 ); |

428 | const aiVector3D v2 = aiVector3D (s * radius2, halfHeight, t * radius2 ); |

429 | |

430 | const ai_real next = angle + angle_delta; |

431 | ai_real s2 = std::cos(next); |

432 | ai_real t2 = std::sin(next); |

433 | |

434 | const aiVector3D v3 = aiVector3D (s2 * radius2, halfHeight, t2 * radius2 ); |

435 | const aiVector3D v4 = aiVector3D (s2 * radius1, -halfHeight, t2 * radius1 ); |

436 | |

437 | positions.push_back(v1); |

438 | positions.push_back(v2); |

439 | positions.push_back(v3); |

440 | positions.push_back(v4); |

441 | positions.push_back(v1); |

442 | positions.push_back(v3); |

443 | |

444 | if (!bOpen) |

445 | { |

446 | // generate the end 'cap' |

447 | positions.push_back(aiVector3D(s * radius2, halfHeight, t * radius2 )); |

448 | positions.push_back(aiVector3D(s2 * radius2, halfHeight, t2 * radius2 )); |

449 | positions.push_back(aiVector3D(0.0, halfHeight, 0.0)); |

450 | |

451 | |

452 | if (radius1) |

453 | { |

454 | // generate the other end 'cap' |

455 | positions.push_back(aiVector3D(s * radius1, -halfHeight, t * radius1 )); |

456 | positions.push_back(aiVector3D(s2 * radius1, -halfHeight, t2 * radius1 )); |

457 | positions.push_back(aiVector3D(0.0, -halfHeight, 0.0)); |

458 | |

459 | } |

460 | } |

461 | s = s2; |

462 | t = t2; |

463 | angle = next; |

464 | } |

465 | |

466 | // Need to flip face order? |

467 | if ( SIZE_MAX != old ) { |

468 | for (size_t s = old; s < positions.size();s += 3) { |

469 | std::swap(positions[s],positions[s+1]); |

470 | } |

471 | } |

472 | } |

473 | |

474 | // ------------------------------------------------------------------------------------------------ |

475 | // Build a circle |

476 | void StandardShapes::MakeCircle(ai_real radius, unsigned int tess, |

477 | std::vector<aiVector3D>& positions) |

478 | { |

479 | // Sorry, a circle with less than 3 segments makes ABSOLUTELY NO SENSE |

480 | if (tess < 3 || !radius) |

481 | return; |

482 | |

483 | radius = std::fabs(radius); |

484 | |

485 | // We will need 3 vertices per segment |

486 | positions.reserve(positions.size()+tess*3); |

487 | |

488 | const ai_real angle_delta = (ai_real)AI_MATH_TWO_PI / tess; |

489 | const ai_real angle_max = (ai_real)AI_MATH_TWO_PI; |

490 | |

491 | ai_real s = 1.0; // std::cos(angle == 0); |

492 | ai_real t = 0.0; // std::sin(angle == 0); |

493 | |

494 | for (ai_real angle = 0.0; angle < angle_max; ) |

495 | { |

496 | positions.push_back(aiVector3D(s * radius,0.0,t * radius)); |

497 | angle += angle_delta; |

498 | s = std::cos(angle); |

499 | t = std::sin(angle); |

500 | positions.push_back(aiVector3D(s * radius,0.0,t * radius)); |

501 | |

502 | positions.push_back(aiVector3D(0.0,0.0,0.0)); |

503 | } |

504 | } |

505 | |

506 | } // ! Assimp |

507 |