1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#include "Utility/BsShapeMeshes3D.h"
4#include "Math/BsRect2.h"
5#include "Mesh/BsMesh.h"
6#include "Math/BsVector2.h"
7#include "Math/BsQuaternion.h"
8#include "Math/BsSphere.h"
9#include "Material/BsPass.h"
10#include "Components/BsCCamera.h"
11#include "RenderAPI/BsVertexDataDesc.h"
12#include "Mesh/BsMeshUtility.h"
13
14namespace bs
15{
16 const UINT32 ShapeMeshes3D::NUM_VERTICES_AA_LINE = 8;
17 const UINT32 ShapeMeshes3D::NUM_INDICES_AA_LINE = 30;
18
19 inline UINT8* writeVector3(UINT8* buffer, UINT32 stride, const Vector3& value)
20 {
21 *(Vector3*)buffer = value;
22 return buffer + stride;
23 }
24
25 inline UINT8* writeVector2(UINT8* buffer, UINT32 stride, const Vector2& value)
26 {
27 *(Vector2*)buffer = value;
28 return buffer + stride;
29 }
30
31 void ShapeMeshes3D::wireAABox(const AABox& box, const SPtr<MeshData>& meshData, UINT32 vertexOffset, UINT32 indexOffset)
32 {
33 UINT32* indexData = meshData->getIndices32();
34 UINT8* positionData = meshData->getElementData(VES_POSITION);
35
36 assert((vertexOffset + 8) <= meshData->getNumVertices());
37 assert((indexOffset + 24) <= meshData->getNumIndices());
38
39 wireAABox(box, positionData, vertexOffset, meshData->getVertexDesc()->getVertexStride(), indexData, indexOffset);
40 }
41
42 void ShapeMeshes3D::solidAABox(const AABox& box, const SPtr<MeshData>& meshData, UINT32 vertexOffset, UINT32 indexOffset)
43 {
44 const SPtr<VertexDataDesc>& desc = meshData->getVertexDesc();
45
46 UINT32* indexData = meshData->getIndices32();
47 UINT8* positionData = meshData->getElementData(VES_POSITION);
48 UINT8* normalData = meshData->getElementData(VES_NORMAL);
49
50 UINT32 numVertices = meshData->getNumVertices();
51 UINT32 numIndices = meshData->getNumIndices();
52 UINT32 vertexStride = desc->getVertexStride();
53
54 assert((vertexOffset + 24) <= meshData->getNumVertices());
55 assert((indexOffset + 36) <= meshData->getNumIndices());
56
57 UINT8* uvData = nullptr;
58 if (desc->hasElement(VES_TEXCOORD))
59 uvData = meshData->getElementData(VES_TEXCOORD);
60
61 solidAABox(box, positionData, normalData, uvData, vertexOffset, vertexStride, indexData, indexOffset);
62
63 if (uvData != nullptr && desc->hasElement(VES_TANGENT))
64 {
65 UINT8* tangentData = meshData->getElementData(VES_TANGENT);
66 generateTangents(positionData, normalData, uvData, indexData, numVertices, numIndices,
67 vertexOffset, indexOffset, vertexStride, tangentData);
68 }
69 }
70
71 void ShapeMeshes3D::wireSphere(const Sphere& sphere, const SPtr<MeshData>& meshData, UINT32 vertexOffset, UINT32 indexOffset, UINT32 quality)
72 {
73 UINT32 requiredNumVertices, requiredNumIndices;
74 getNumElementsWireSphere(quality, requiredNumVertices, requiredNumIndices);
75
76 assert((vertexOffset + requiredNumVertices) <= meshData->getNumVertices());
77 assert((indexOffset + requiredNumIndices) <= meshData->getNumIndices());
78
79 UINT32 verticesPerArc = (quality + 1) * 5;
80 UINT32 indicesPerArc = (verticesPerArc - 1) * 2;
81
82 wireDisc(sphere.getCenter(), sphere.getRadius(), Vector3::UNIT_X, meshData,
83 vertexOffset, indexOffset, quality);
84
85 wireDisc(sphere.getCenter(), sphere.getRadius(), Vector3::UNIT_Y, meshData,
86 vertexOffset + verticesPerArc, indexOffset + indicesPerArc, quality);
87
88 wireDisc(sphere.getCenter(), sphere.getRadius(), Vector3::UNIT_Z, meshData,
89 vertexOffset + verticesPerArc * 2, indexOffset + indicesPerArc * 2, quality);
90 }
91
92 void ShapeMeshes3D::wireHemisphere(const Sphere& sphere, const SPtr<MeshData>& meshData, UINT32 vertexOffset,
93 UINT32 indexOffset, UINT32 quality)
94 {
95 UINT32 requiredNumVertices, requiredNumIndices;
96 getNumElementsWireHemisphere(quality, requiredNumVertices, requiredNumIndices);
97
98 assert((vertexOffset + requiredNumVertices) <= meshData->getNumVertices());
99 assert((indexOffset + requiredNumIndices) <= meshData->getNumIndices());
100
101 UINT32 verticesPerArc = (quality + 1) * 5;
102 UINT32 indicesPerArc = (verticesPerArc - 1) * 2;
103
104 wireArc(sphere.getCenter(), sphere.getRadius(), Vector3::UNIT_X, Degree(0.0f), Degree(180.0f), meshData,
105 vertexOffset, indexOffset, quality);
106
107 wireArc(sphere.getCenter(), sphere.getRadius(), Vector3::UNIT_Y, Degree(0.0f), Degree(180.0f), meshData,
108 vertexOffset + verticesPerArc, indexOffset + indicesPerArc, quality);
109
110 wireDisc(sphere.getCenter(), sphere.getRadius(), Vector3::UNIT_Z, meshData,
111 vertexOffset + verticesPerArc * 2, indexOffset + indicesPerArc * 2, quality);
112 }
113
114 void ShapeMeshes3D::solidSphere(const Sphere& sphere, const SPtr<MeshData>& meshData, UINT32 vertexOffset,
115 UINT32 indexOffset, UINT32 quality)
116 {
117 const SPtr<VertexDataDesc>& desc = meshData->getVertexDesc();
118
119 UINT32* indexData = meshData->getIndices32();
120 UINT8* positionData = meshData->getElementData(VES_POSITION);
121 UINT8* normalData = meshData->getElementData(VES_NORMAL);
122
123 UINT32 numVertices = meshData->getNumVertices();
124 UINT32 numIndices = meshData->getNumIndices();
125 UINT32 vertexStride = desc->getVertexStride();
126
127 UINT32 requiredNumVertices, requiredNumIndices;
128 getNumElementsSphere(quality, requiredNumVertices, requiredNumIndices);
129
130 assert((vertexOffset + requiredNumVertices) <= numVertices);
131 assert((indexOffset + requiredNumIndices) <= numIndices);
132
133 UINT8* uvData = nullptr;
134 if (desc->hasElement(VES_TEXCOORD))
135 uvData = meshData->getElementData(VES_TEXCOORD);
136
137 solidSphere(sphere, positionData, normalData, uvData, vertexOffset, vertexStride, indexData, indexOffset, quality);
138
139 if (uvData != nullptr && desc->hasElement(VES_TANGENT))
140 {
141 UINT8* tangentData = meshData->getElementData(VES_TANGENT);
142 generateTangents(positionData, normalData, uvData, indexData, numVertices, numIndices,
143 vertexOffset, indexOffset, vertexStride, tangentData);
144 }
145 }
146
147 void ShapeMeshes3D::wireDisc(const Vector3& center, float radius, const Vector3& normal, const SPtr<MeshData>& meshData,
148 UINT32 vertexOffset, UINT32 indexOffset, UINT32 quality)
149 {
150 wireArc(center, radius, normal, Degree(0), Degree(360), meshData, vertexOffset, indexOffset, quality);
151 }
152
153 void ShapeMeshes3D::solidDisc(const Vector3& center, float radius, const Vector3& normal, const SPtr<MeshData>& meshData,
154 UINT32 vertexOffset, UINT32 indexOffset, UINT32 quality)
155 {
156 solidArc(center, radius, normal, Degree(0), Degree(360), meshData, vertexOffset, indexOffset, quality);
157 }
158
159 void ShapeMeshes3D::wireArc(const Vector3& center, float radius, const Vector3& normal, Degree startAngle, Degree amountAngle,
160 const SPtr<MeshData>& meshData, UINT32 vertexOffset, UINT32 indexOffset, UINT32 quality)
161 {
162 UINT32* indexData = meshData->getIndices32();
163 UINT8* positionData = meshData->getElementData(VES_POSITION);
164
165 UINT32 requiredNumVertices, requiredNumIndices;
166 getNumElementsWireArc(quality, requiredNumVertices, requiredNumIndices);
167
168 assert((vertexOffset + requiredNumVertices) <= meshData->getNumVertices());
169 assert((indexOffset + requiredNumIndices) <= meshData->getNumIndices());
170
171 wireArc(center, radius, normal, startAngle, amountAngle, positionData, vertexOffset,
172 meshData->getVertexDesc()->getVertexStride(), indexData, indexOffset, quality);
173 }
174
175 void ShapeMeshes3D::solidArc(const Vector3& center, float radius, const Vector3& normal, Degree startAngle, Degree amountAngle,
176 const SPtr<MeshData>& meshData, UINT32 vertexOffset, UINT32 indexOffset, UINT32 quality)
177 {
178 const SPtr<VertexDataDesc>& desc = meshData->getVertexDesc();
179
180 UINT32* indexData = meshData->getIndices32();
181 UINT8* positionData = meshData->getElementData(VES_POSITION);
182 UINT8* normalData = meshData->getElementData(VES_NORMAL);
183
184 UINT32 numVertices = meshData->getNumVertices();
185 UINT32 numIndices = meshData->getNumIndices();
186 UINT32 vertexStride = desc->getVertexStride();
187
188 UINT32 requiredNumVertices, requiredNumIndices;
189 getNumElementsArc(quality, requiredNumVertices, requiredNumIndices);
190
191 assert((vertexOffset + requiredNumVertices) <= meshData->getNumVertices());
192 assert((indexOffset + requiredNumIndices) <= meshData->getNumIndices());
193
194 UINT8* uvData = nullptr;
195 if (desc->hasElement(VES_TEXCOORD))
196 uvData = meshData->getElementData(VES_TEXCOORD);
197
198 solidArc(center, radius, normal, startAngle, amountAngle, positionData, normalData, uvData, vertexOffset,
199 vertexStride, indexData, indexOffset, quality);
200
201 if (uvData != nullptr && desc->hasElement(VES_TANGENT))
202 {
203 UINT8* tangentData = meshData->getElementData(VES_TANGENT);
204 generateTangents(positionData, normalData, uvData, indexData, numVertices, numIndices,
205 vertexOffset, indexOffset, vertexStride, tangentData);
206 }
207 }
208
209 void ShapeMeshes3D::wireFrustum(const Vector3& position, float aspect, Degree FOV, float near, float far,
210 const SPtr<MeshData>& meshData, UINT32 vertexOffset, UINT32 indexOffset)
211 {
212 UINT32* indexData = meshData->getIndices32();
213 UINT8* positionData = meshData->getElementData(VES_POSITION);
214
215 assert((vertexOffset + 8) <= meshData->getNumVertices());
216 assert((indexOffset + 24) <= meshData->getNumIndices());
217
218 wireFrustum(position, aspect, FOV, near, far, positionData, vertexOffset, meshData->getVertexDesc()->getVertexStride(), indexData, indexOffset);
219 }
220
221 void ShapeMeshes3D::solidCone(const Vector3& base, const Vector3& normal, float height, float radius, Vector2 scale,
222 const SPtr<MeshData>& meshData, UINT32 vertexOffset, UINT32 indexOffset, UINT32 quality)
223 {
224 const SPtr<VertexDataDesc>& desc = meshData->getVertexDesc();
225
226 UINT32* indexData = meshData->getIndices32();
227 UINT8* positionData = meshData->getElementData(VES_POSITION);
228 UINT8* normalData = meshData->getElementData(VES_NORMAL);
229
230 UINT32 numVertices = meshData->getNumVertices();
231 UINT32 numIndices = meshData->getNumIndices();
232 UINT32 vertexStride = desc->getVertexStride();
233
234 UINT32 requiredNumVertices, requiredNumIndices;
235 getNumElementsCone(quality, requiredNumVertices, requiredNumIndices);
236
237 assert((vertexOffset + requiredNumVertices) <= meshData->getNumVertices());
238 assert((indexOffset + requiredNumIndices) <= meshData->getNumIndices());
239
240 UINT8* uvData = nullptr;
241 if (desc->hasElement(VES_TEXCOORD))
242 uvData = meshData->getElementData(VES_TEXCOORD);
243
244 solidCone(base, normal, height, radius, scale, positionData, normalData, uvData, vertexOffset,
245 vertexStride, indexData, indexOffset, quality);
246
247 if (uvData != nullptr && desc->hasElement(VES_TANGENT))
248 {
249 UINT8* tangentData = meshData->getElementData(VES_TANGENT);
250 generateTangents(positionData, normalData, uvData, indexData, numVertices, numIndices,
251 vertexOffset, indexOffset, vertexStride, tangentData);
252 }
253 }
254
255 void ShapeMeshes3D::wireCone(const Vector3& base, const Vector3& normal, float height, float radius, Vector2 scale,
256 const SPtr<MeshData>& meshData, UINT32 vertexOffset, UINT32 indexOffset, UINT32 quality)
257 {
258 UINT32* indexData = meshData->getIndices32();
259 UINT8* positionData = meshData->getElementData(VES_POSITION);
260
261 UINT32 requiredNumVertices, requiredNumIndices;
262 getNumElementsWireCone(quality, requiredNumVertices, requiredNumIndices);
263
264 assert((vertexOffset + requiredNumVertices) <= meshData->getNumVertices());
265 assert((indexOffset + requiredNumIndices) <= meshData->getNumIndices());
266
267 wireCone(base, normal, height, radius, scale, positionData, vertexOffset,
268 meshData->getVertexDesc()->getVertexStride(), indexData, indexOffset, quality);
269 }
270
271 void ShapeMeshes3D::solidCylinder(const Vector3& base, const Vector3& normal, float height, float radius, Vector2 scale,
272 const SPtr<MeshData>& meshData, UINT32 vertexOffset, UINT32 indexOffset, UINT32 quality)
273 {
274 const SPtr<VertexDataDesc>& desc = meshData->getVertexDesc();
275
276 UINT32* indexData = meshData->getIndices32();
277 UINT8* positionData = meshData->getElementData(VES_POSITION);
278 UINT8* normalData = meshData->getElementData(VES_NORMAL);
279
280 UINT32 numVertices = meshData->getNumVertices();
281 UINT32 numIndices = meshData->getNumIndices();
282 UINT32 vertexStride = desc->getVertexStride();
283
284 UINT32 requiredNumVertices, requiredNumIndices;
285 getNumElementsCylinder(quality, requiredNumVertices, requiredNumIndices);
286
287 assert((vertexOffset + requiredNumVertices) <= meshData->getNumVertices());
288 assert((indexOffset + requiredNumIndices) <= meshData->getNumIndices());
289
290 UINT8* uvData = nullptr;
291 if (desc->hasElement(VES_TEXCOORD))
292 uvData = meshData->getElementData(VES_TEXCOORD);
293
294 solidCylinder(base, normal, height, radius, scale, positionData, normalData, uvData, vertexOffset,
295 vertexStride, indexData, indexOffset, quality);
296
297 if (uvData != nullptr && desc->hasElement(VES_TANGENT))
298 {
299 UINT8* tangentData = meshData->getElementData(VES_TANGENT);
300 generateTangents(positionData, normalData, uvData, indexData, numVertices, numIndices,
301 vertexOffset, indexOffset, vertexStride, tangentData);
302 }
303 }
304
305 void ShapeMeshes3D::wireCylinder(const Vector3& base, const Vector3& normal, float height, float radius, Vector2 scale,
306 const SPtr<MeshData>& meshData, UINT32 vertexOffset, UINT32 indexOffset, UINT32 quality)
307 {
308 UINT32* indexData = meshData->getIndices32();
309 UINT8* positionData = meshData->getElementData(VES_POSITION);
310
311 UINT32 requiredNumVertices, requiredNumIndices;
312 getNumElementsWireCylinder(quality, requiredNumVertices, requiredNumIndices);
313
314 assert((vertexOffset + requiredNumVertices) <= meshData->getNumVertices());
315 assert((indexOffset + requiredNumIndices) <= meshData->getNumIndices());
316
317 wireCylinder(base, normal, height, radius, scale, positionData, vertexOffset,
318 meshData->getVertexDesc()->getVertexStride(), indexData, indexOffset, quality);
319 }
320
321 void ShapeMeshes3D::solidQuad(const Rect3& area, const SPtr<MeshData>& meshData, UINT32 vertexOffset, UINT32 indexOffset)
322 {
323 const SPtr<VertexDataDesc>& desc = meshData->getVertexDesc();
324
325 UINT32* indexData = meshData->getIndices32();
326 UINT8* positionData = meshData->getElementData(VES_POSITION);
327 UINT8* normalData = meshData->getElementData(VES_NORMAL);
328
329 UINT32 numVertices = meshData->getNumVertices();
330 UINT32 numIndices = meshData->getNumIndices();
331 UINT32 vertexStride = desc->getVertexStride();
332
333 assert((vertexOffset + 8) <= numVertices);
334 assert((indexOffset + 12) <= numIndices);
335
336 UINT8* uvData = nullptr;
337 if (desc->hasElement(VES_TEXCOORD))
338 uvData = meshData->getElementData(VES_TEXCOORD);
339
340 solidQuad(area, positionData, normalData, uvData, vertexOffset,
341 meshData->getVertexDesc()->getVertexStride(), indexData, indexOffset);
342
343 if(uvData != nullptr && desc->hasElement(VES_TANGENT))
344 {
345 UINT8* tangentData = meshData->getElementData(VES_TANGENT);
346 generateTangents(positionData, normalData, uvData, indexData, numVertices, numIndices,
347 vertexOffset, indexOffset, vertexStride, tangentData);
348 }
349 }
350
351 void ShapeMeshes3D::pixelLine(const Vector3& a, const Vector3& b, const SPtr<MeshData>& meshData, UINT32 vertexOffset, UINT32 indexOffset)
352 {
353 UINT32* indexData = meshData->getIndices32();
354 UINT8* positionData = meshData->getElementData(VES_POSITION);
355
356 assert((vertexOffset + 2) <= meshData->getNumVertices());
357 assert((indexOffset + 2) <= meshData->getNumIndices());
358
359 pixelLine(a, b, positionData, vertexOffset, meshData->getVertexDesc()->getVertexStride(), indexData, indexOffset);
360 }
361
362 void ShapeMeshes3D::pixelLineList(const Vector<Vector3>& linePoints, const SPtr<MeshData>& meshData, UINT32 vertexOffset, UINT32 indexOffset)
363 {
364 assert(linePoints.size() % 2 == 0);
365
366 assert((vertexOffset + linePoints.size()) <= meshData->getNumVertices());
367 assert((indexOffset + linePoints.size()) <= meshData->getNumIndices());
368
369 UINT32 curVertOffset = vertexOffset;
370 UINT32 curIdxOffset = indexOffset;
371
372 UINT32* indexData = meshData->getIndices32();
373 UINT8* positionData = meshData->getElementData(VES_POSITION);
374
375 UINT32 numPoints = (UINT32)linePoints.size();
376 for (UINT32 i = 0; i < numPoints; i += 2)
377 {
378 pixelLine(linePoints[i], linePoints[i + 1], positionData, curVertOffset, meshData->getVertexDesc()->getVertexStride(), indexData, curIdxOffset);
379
380 curVertOffset += 2;
381 curIdxOffset += 2;
382 }
383 }
384
385 void ShapeMeshes3D::antialiasedLine(const Vector3& a, const Vector3& b, const Vector3& up, float width, float borderWidth,
386 const Color& color, const SPtr<MeshData>& meshData, UINT32 vertexOffset, UINT32 indexOffset)
387 {
388 UINT32* indexData = meshData->getIndices32();
389 UINT8* positionData = meshData->getElementData(VES_POSITION);
390 UINT8* colorData = meshData->getElementData(VES_COLOR);
391
392 assert((vertexOffset + NUM_VERTICES_AA_LINE) <= meshData->getNumVertices());
393 assert((indexOffset + NUM_INDICES_AA_LINE) <= meshData->getNumIndices());
394
395 antialiasedLine(a, b, up, width, borderWidth, color, positionData, colorData, vertexOffset, meshData->getVertexDesc()->getVertexStride(), indexData, indexOffset);
396 }
397
398 void ShapeMeshes3D::antialiasedLineList(const Vector<Vector3>& linePoints, const Vector3& up, float width, float borderWidth,
399 const Color& color, const SPtr<MeshData>& meshData, UINT32 vertexOffset, UINT32 indexOffset)
400 {
401 assert(linePoints.size() % 2 == 0);
402
403 assert((vertexOffset + linePoints.size() * 4) <= meshData->getNumVertices());
404 assert((indexOffset + linePoints.size() * 15) <= meshData->getNumIndices());
405
406 UINT32 curVertOffset = vertexOffset;
407 UINT32 curIdxOffset = indexOffset;
408
409 UINT32* indexData = meshData->getIndices32();
410 UINT8* positionData = meshData->getElementData(VES_POSITION);
411 UINT8* colorData = meshData->getElementData(VES_COLOR);
412
413 UINT32 numPoints = (UINT32)linePoints.size();
414 for (UINT32 i = 0; i < numPoints; i += 2)
415 {
416 antialiasedLine(linePoints[i], linePoints[i + 1], up, width, borderWidth, color, positionData, colorData, curVertOffset, meshData->getVertexDesc()->getVertexStride(), indexData, curIdxOffset);
417
418 curVertOffset += NUM_VERTICES_AA_LINE;
419 curIdxOffset += NUM_INDICES_AA_LINE;
420 }
421 }
422
423 /************************************************************************/
424 /* ELEMENT COUNT */
425 /************************************************************************/
426
427 void ShapeMeshes3D::getNumElementsAABox(UINT32& numVertices, UINT32& numIndices)
428 {
429 numVertices = 24;
430 numIndices = 36;
431 }
432
433 void ShapeMeshes3D::getNumElementsWireAABox(UINT32& numVertices, UINT32& numIndices)
434 {
435 numVertices = 8;
436 numIndices = 24;
437 }
438
439 void ShapeMeshes3D::getNumElementsSphere(UINT32 quality, UINT32& numVertices, UINT32& numIndices)
440 {
441 numVertices = 20 * (3 * ((UINT32)std::pow(4, quality)));
442 numIndices = numVertices;
443
444 // Extra for the seam fix. 4 initial triangles each split 4 times per quality level, one vertex each
445 numVertices += (3 * (UINT32)pow(4, quality));
446 }
447
448 void ShapeMeshes3D::getNumElementsWireSphere(UINT32 quality, UINT32& numVertices, UINT32& numIndices)
449 {
450 getNumElementsWireArc(quality, numVertices, numIndices);
451 numVertices *= 3;
452 numIndices *= 3;
453 }
454
455 void ShapeMeshes3D::getNumElementsWireHemisphere(UINT32 quality, UINT32& numVertices, UINT32& numIndices)
456 {
457 getNumElementsWireArc(quality, numVertices, numIndices);
458 numVertices *= 3;
459 numIndices *= 3;
460 }
461
462 void ShapeMeshes3D::getNumElementsArc(UINT32 quality, UINT32& numVertices, UINT32& numIndices)
463 {
464 numVertices = ((quality + 1) * 5 + 1) * 2;
465 numIndices = ((quality + 1) * 5) * 6;
466 }
467
468 void ShapeMeshes3D::getNumElementsWireArc(UINT32 quality, UINT32& numVertices, UINT32& numIndices)
469 {
470 numVertices = (quality + 1) * 5;
471 numIndices = ((quality + 1) * 5 - 1) * 2;
472 }
473
474 void ShapeMeshes3D::getNumElementsDisc(UINT32 quality, UINT32& numVertices, UINT32& numIndices)
475 {
476 getNumElementsArc(quality, numVertices, numIndices);
477 }
478
479 void ShapeMeshes3D::getNumElementsWireDisc(UINT32 quality, UINT32& numVertices, UINT32& numIndices)
480 {
481 getNumElementsWireArc(quality, numVertices, numIndices);
482 }
483
484 void ShapeMeshes3D::getNumElementsCone(UINT32 quality, UINT32& numVertices, UINT32& numIndices)
485 {
486 numVertices = ((quality + 1) * 4) * 3 + 1;
487 numIndices = ((quality + 1) * 4) * 6;
488 }
489
490 void ShapeMeshes3D::getNumElementsWireCone(UINT32 quality, UINT32& numVertices, UINT32& numIndices)
491 {
492 numVertices = (quality + 1) * 4 + 5;
493 numIndices = ((quality + 1) * 4 + 4) * 2;
494 }
495
496 void ShapeMeshes3D::getNumElementsCylinder(UINT32 quality, UINT32& numVertices, UINT32& numIndices)
497 {
498 numVertices = ((quality + 1) * 4 + 1) * 4;
499 numIndices = ((quality + 1) * 4) * 12;
500 }
501
502 void ShapeMeshes3D::getNumElementsWireCylinder(UINT32 quality, UINT32& numVertices, UINT32& numIndices)
503 {
504 numVertices = ((quality + 1) * 4) * 2;
505 numIndices = ((quality + 1) * 4) * 6;
506 }
507
508 void ShapeMeshes3D::getNumElementsQuad(UINT32& numVertices, UINT32& numIndices)
509 {
510 numVertices = 8;
511 numIndices = 12;
512 }
513
514 void ShapeMeshes3D::getNumElementsFrustum(UINT32& numVertices, UINT32& numIndices)
515 {
516 numVertices = 8;
517 numIndices = 36;
518 }
519
520 void ShapeMeshes3D::wireAABox(const AABox& box, UINT8* outVertices, UINT32 vertexOffset, UINT32 vertexStride, UINT32* outIndices, UINT32 indexOffset)
521 {
522 outVertices += vertexOffset * vertexStride;
523
524 outVertices = writeVector3(outVertices, vertexStride, box.getCorner(AABox::NEAR_LEFT_BOTTOM));
525 outVertices = writeVector3(outVertices, vertexStride, box.getCorner(AABox::NEAR_RIGHT_BOTTOM));
526 outVertices = writeVector3(outVertices, vertexStride, box.getCorner(AABox::NEAR_RIGHT_TOP));
527 outVertices = writeVector3(outVertices, vertexStride, box.getCorner(AABox::NEAR_LEFT_TOP));
528
529 outVertices = writeVector3(outVertices, vertexStride, box.getCorner(AABox::FAR_RIGHT_BOTTOM));
530 outVertices = writeVector3(outVertices, vertexStride, box.getCorner(AABox::FAR_LEFT_BOTTOM));
531 outVertices = writeVector3(outVertices, vertexStride, box.getCorner(AABox::FAR_LEFT_TOP));
532 outVertices = writeVector3(outVertices, vertexStride, box.getCorner(AABox::FAR_RIGHT_TOP));
533
534 outIndices += indexOffset;
535
536 // Front
537 outIndices[0] = vertexOffset + 0;
538 outIndices[1] = vertexOffset + 1;
539
540 outIndices[2] = vertexOffset + 1;
541 outIndices[3] = vertexOffset + 2;
542
543 outIndices[4] = vertexOffset + 2;
544 outIndices[5] = vertexOffset + 3;
545
546 outIndices[6] = vertexOffset + 3;
547 outIndices[7] = vertexOffset + 0;
548
549 // Center
550 outIndices[8] = vertexOffset + 0;
551 outIndices[9] = vertexOffset + 5;
552
553 outIndices[10] = vertexOffset + 1;
554 outIndices[11] = vertexOffset + 4;
555
556 outIndices[12] = vertexOffset + 2;
557 outIndices[13] = vertexOffset + 7;
558
559 outIndices[14] = vertexOffset + 3;
560 outIndices[15] = vertexOffset + 6;
561
562 // Back
563 outIndices[16] = vertexOffset + 4;
564 outIndices[17] = vertexOffset + 5;
565
566 outIndices[18] = vertexOffset + 5;
567 outIndices[19] = vertexOffset + 6;
568
569 outIndices[20] = vertexOffset + 6;
570 outIndices[21] = vertexOffset + 7;
571
572 outIndices[22] = vertexOffset + 7;
573 outIndices[23] = vertexOffset + 4;
574 }
575
576 void ShapeMeshes3D::solidAABox(const AABox& box, UINT8* outVertices, UINT8* outNormals, UINT8* outUVs,
577 UINT32 vertexOffset, UINT32 vertexStride, UINT32* outIndices, UINT32 indexOffset)
578 {
579 outVertices += (vertexOffset * vertexStride);
580
581 // Front face
582 outVertices = writeVector3(outVertices, vertexStride, box.getCorner(AABox::NEAR_LEFT_BOTTOM));
583 outVertices = writeVector3(outVertices, vertexStride, box.getCorner(AABox::NEAR_RIGHT_BOTTOM));
584 outVertices = writeVector3(outVertices, vertexStride, box.getCorner(AABox::NEAR_RIGHT_TOP));
585 outVertices = writeVector3(outVertices, vertexStride, box.getCorner(AABox::NEAR_LEFT_TOP));
586
587 // Back face
588 outVertices = writeVector3(outVertices, vertexStride, box.getCorner(AABox::FAR_RIGHT_BOTTOM));
589 outVertices = writeVector3(outVertices, vertexStride, box.getCorner(AABox::FAR_LEFT_BOTTOM));
590 outVertices = writeVector3(outVertices, vertexStride, box.getCorner(AABox::FAR_LEFT_TOP));
591 outVertices = writeVector3(outVertices, vertexStride, box.getCorner(AABox::FAR_RIGHT_TOP));
592
593 // Left face
594 outVertices = writeVector3(outVertices, vertexStride, box.getCorner(AABox::FAR_LEFT_BOTTOM));
595 outVertices = writeVector3(outVertices, vertexStride, box.getCorner(AABox::NEAR_LEFT_BOTTOM));
596 outVertices = writeVector3(outVertices, vertexStride, box.getCorner(AABox::NEAR_LEFT_TOP));
597 outVertices = writeVector3(outVertices, vertexStride, box.getCorner(AABox::FAR_LEFT_TOP));
598
599 // Right face
600 outVertices = writeVector3(outVertices, vertexStride, box.getCorner(AABox::NEAR_RIGHT_BOTTOM));
601 outVertices = writeVector3(outVertices, vertexStride, box.getCorner(AABox::FAR_RIGHT_BOTTOM));
602 outVertices = writeVector3(outVertices, vertexStride, box.getCorner(AABox::FAR_RIGHT_TOP));
603 outVertices = writeVector3(outVertices, vertexStride, box.getCorner(AABox::NEAR_RIGHT_TOP));
604
605 // Top face
606 outVertices = writeVector3(outVertices, vertexStride, box.getCorner(AABox::FAR_LEFT_TOP));
607 outVertices = writeVector3(outVertices, vertexStride, box.getCorner(AABox::NEAR_LEFT_TOP));
608 outVertices = writeVector3(outVertices, vertexStride, box.getCorner(AABox::NEAR_RIGHT_TOP));
609 outVertices = writeVector3(outVertices, vertexStride, box.getCorner(AABox::FAR_RIGHT_TOP));
610
611 // Bottom face
612 outVertices = writeVector3(outVertices, vertexStride, box.getCorner(AABox::FAR_LEFT_BOTTOM));
613 outVertices = writeVector3(outVertices, vertexStride, box.getCorner(AABox::FAR_RIGHT_BOTTOM));
614 outVertices = writeVector3(outVertices, vertexStride, box.getCorner(AABox::NEAR_RIGHT_BOTTOM));
615 outVertices = writeVector3(outVertices, vertexStride, box.getCorner(AABox::NEAR_LEFT_BOTTOM));
616
617 // Normals
618 static const Vector3 faceNormals[6] =
619 {
620 Vector3(0, 0, 1),
621 Vector3(0, 0, -1),
622 Vector3(-1, 0, 0),
623 Vector3(1, 0, 0),
624 Vector3(0, 1, 0),
625 Vector3(0, -1, 0)
626 };
627
628 if (outNormals != nullptr)
629 {
630 outNormals += (vertexOffset * vertexStride);
631 for (UINT32 face = 0; face < 6; face++)
632 {
633 outNormals = writeVector3(outNormals, vertexStride, faceNormals[face]);
634 outNormals = writeVector3(outNormals, vertexStride, faceNormals[face]);
635 outNormals = writeVector3(outNormals, vertexStride, faceNormals[face]);
636 outNormals = writeVector3(outNormals, vertexStride, faceNormals[face]);
637 }
638 }
639
640 // UV
641 if(outUVs != nullptr)
642 {
643 outUVs += (vertexOffset * vertexStride);
644 for (UINT32 face = 0; face < 6; face++)
645 {
646 outUVs = writeVector2(outUVs, vertexStride, Vector2(0.0f, 1.0f));
647 outUVs = writeVector2(outUVs, vertexStride, Vector2(1.0f, 1.0f));
648 outUVs = writeVector2(outUVs, vertexStride, Vector2(1.0f, 0.0f));
649 outUVs = writeVector2(outUVs, vertexStride, Vector2(0.0f, 0.0f));
650 }
651 }
652
653 // Indices
654 UINT32* indices = outIndices + indexOffset;
655 for (UINT32 face = 0; face < 6; face++)
656 {
657 UINT32 faceVertOffset = vertexOffset + face * 4;
658
659 indices[face * 6 + 0] = faceVertOffset + 2;
660 indices[face * 6 + 1] = faceVertOffset + 1;
661 indices[face * 6 + 2] = faceVertOffset + 0;
662 indices[face * 6 + 3] = faceVertOffset + 0;
663 indices[face * 6 + 4] = faceVertOffset + 3;
664 indices[face * 6 + 5] = faceVertOffset + 2;
665 }
666 }
667
668 void ShapeMeshes3D::solidSphere(const Sphere& sphere, UINT8* outVertices, UINT8* outNormals, UINT8 *outUV,
669 UINT32 vertexOffset, UINT32 vertexStride, UINT32* outIndices, UINT32 indexOffset, UINT32 quality)
670 {
671 // Create icosahedron
672 static const float x = 0.525731112119133606f;
673 static const float z = 0.850650808352039932f;
674
675 static const Vector3 vertices[12] =
676 {
677 Vector3(-x, 0.0f, z),
678 Vector3(x, 0.0f, z),
679 Vector3(-x, 0.0f, -z),
680 Vector3(x, 0.0f, -z),
681 Vector3(0.0f, z, x),
682 Vector3(0.0f, z, -x),
683 Vector3(0.0f, -z, x),
684 Vector3(0.0f, -z, -x),
685 Vector3(z, x, 0.0f),
686 Vector3(-z, x, 0.0f),
687 Vector3(z, -x, 0.0f),
688 Vector3(-z, -x, 0.0f)
689 };
690
691 static const UINT32 triangles[20][3] =
692 {
693 { 0, 4, 1 }, { 0, 9, 4 }, { 9, 5, 4 }, { 4, 5, 8 },
694 { 4, 8, 1 }, { 8, 10, 1 }, { 8, 3, 10 }, { 5, 3, 8 },
695 { 5, 2, 3 }, { 2, 7, 3 }, { 7, 10, 3 }, { 7, 6, 10 },
696 { 7, 11, 6 }, { 11, 0, 6 }, { 0, 1, 6 }, { 6, 1, 10 },
697 { 9, 0, 11 }, { 9, 11, 2 }, { 9, 2, 5 }, { 7, 2, 11 }
698 };
699
700 // Tessellate it
701 UINT32 curVertOffset = vertexOffset;
702 for (int i = 0; i < 20; ++i)
703 {
704 curVertOffset += subdivideTriangleOnSphere(sphere.getCenter(), sphere.getRadius(), quality,
705 vertices[triangles[i][2]], vertices[triangles[i][1]], vertices[triangles[i][0]],
706 outVertices, outNormals, curVertOffset, vertexStride);
707 }
708
709 // Create UV if required
710 if (outUV != nullptr)
711 {
712 UINT32 numVertices = curVertOffset - vertexOffset;
713
714 outUV += (vertexOffset * vertexStride);
715 UINT8* curUV = outUV;
716 for(UINT32 i = 0; i < numVertices; i++)
717 {
718 Vector3 position = *(Vector3*)&outVertices[(vertexOffset + i) * vertexStride];
719 Vector3 normal = Vector3::normalize(position);
720
721 Vector2 uv;
722 uv.x = 0.5f - atan2(normal.x, normal.z) / Math::TWO_PI;
723 uv.y = 0.5f - asin(normal.y) / Math::PI;
724
725 curUV = writeVector2(curUV, vertexStride, uv);
726 }
727 }
728
729 // Create indices
730 outIndices += indexOffset;
731
732 UINT32 numIndices = 20 * (3 * (UINT32)std::pow(4, quality));
733 for (UINT32 i = 0; i < numIndices; i += 3)
734 {
735 outIndices[i] = vertexOffset + i + 2;
736 outIndices[i + 1] = vertexOffset + i + 1;
737 outIndices[i + 2] = vertexOffset + i + 0;
738 }
739
740 // Fix UV seams
741 UINT8* extraPositions = outVertices + curVertOffset * vertexStride;
742
743 UINT8* extraNormals = nullptr;
744 if (outNormals)
745 extraNormals = outNormals + curVertOffset * vertexStride;
746
747 UINT8* extraUV = nullptr;
748 if(outUV)
749 extraUV = outUV + curVertOffset * vertexStride;
750
751 const UINT32 maxExtraVerts = 3 * (UINT32)pow(4, quality);
752 UINT32 extraVertIdx = 0;
753 if (outUV != nullptr)
754 {
755 // Note: This only fixes seams for tileable textures. To properly fix seams for all textures the triangles
756 // would actually need to be split along the UV seam. This is ignored as non-tileable textures won't look
757 // good on a sphere regardless of the seam.
758 for (UINT32 i = 0; i < numIndices; i += 3)
759 {
760 const Vector2& uv0 = *(Vector2*)&outUV[(i + 0) * vertexStride];
761 const Vector2& uv1 = *(Vector2*)&outUV[(i + 1) * vertexStride];
762 const Vector2& uv2 = *(Vector2*)&outUV[(i + 2) * vertexStride];
763
764 UINT32 indexToSplit = (UINT32)-1;
765 float offset = 1.0f;
766 if(fabs(uv2.x - uv0.x) > 0.5f)
767 {
768 if(uv0.x < 0.5f)
769 {
770 // 2 is the odd-one out, > 0.5
771 if(uv1.x < 0.5f)
772 {
773 indexToSplit = 2;
774 offset = -1.0f;
775 }
776 // 0 is the odd-one out, < 0.5
777 else
778 {
779 indexToSplit = 0;
780 offset = 1.0f;
781 }
782 }
783 else
784 {
785 // 2 is the odd-one out, < 0.5
786 if(uv1.x > 0.5f)
787 {
788 indexToSplit = 2;
789 offset = 1.0f;
790 }
791 // 0 is the odd-one out, > 0.5
792 else
793 {
794 indexToSplit = 0;
795 offset = -1.0f;
796 }
797
798 }
799 }
800 else if(fabs(uv1.x - uv0.x) > 0.5f)
801 {
802 if(uv0.x < 0.5f)
803 {
804 // 1 is the odd-one out, > 0.5
805 if(uv2.x < 0.5f)
806 {
807 indexToSplit = 1;
808 offset = -1.0f;
809 }
810 // 0 is the odd-one out, < 0.5
811 else
812 {
813 indexToSplit = 0;
814 offset = 1.0f;
815 }
816 }
817 else
818 {
819 // 1 is the odd-one out, < 0.5
820 if(uv2.x > 0.5f)
821 {
822 indexToSplit = 1;
823 offset = 1.0f;
824 }
825 // 0 is the odd-one out, > 0.5
826 else
827 {
828 indexToSplit = 0;
829 offset = -1.0f;
830 }
831 }
832 }
833 else if(fabs(uv1.x - uv2.x) > 0.5f)
834 {
835 if(uv2.x < 0.5f)
836 {
837 // 1 is the odd-one out, > 0.5
838 if(uv0.x < 0.5f)
839 {
840 indexToSplit = 1;
841 offset = -1.0f;
842 }
843 // 2 is the odd-one out, < 0.5
844 else
845 {
846 indexToSplit = 2;
847 offset = 1.0f;
848 }
849 }
850 else
851 {
852 // 1 is the odd-one out, < 0.5
853 if(uv0.x > 0.5f)
854 {
855 indexToSplit = 1;
856 offset = 1.0f;
857 }
858 // 2 is the odd-one out, > 0.5
859 else
860 {
861 indexToSplit = 2;
862 offset = -1.0f;
863 }
864 }
865 }
866
867 if(indexToSplit != (UINT32)-1)
868 {
869 Vector3 position = *(Vector3*)&outVertices[(vertexOffset + i + indexToSplit) * vertexStride];
870 extraPositions = writeVector3(extraPositions, vertexStride, position);
871
872 if(extraNormals)
873 {
874 Vector3 normal = *(Vector3*)&outNormals[(vertexOffset + i + indexToSplit) * vertexStride];
875 extraNormals = writeVector3(extraNormals, vertexStride, normal);
876 }
877
878 Vector2 uv = *(Vector2*)&outUV[(i + indexToSplit) * vertexStride];
879 uv.x += offset;
880
881 extraUV = writeVector2(extraUV, vertexStride, uv);
882
883 // Index 0 maps to vertex 2, index 1 to vertex 1, index 2 to vertex 0
884 if(indexToSplit == 0)
885 indexToSplit = 2;
886 else if(indexToSplit == 2)
887 indexToSplit = 0;
888
889 outIndices[i + indexToSplit] = vertexOffset + numIndices + extraVertIdx;
890
891 assert(extraVertIdx < maxExtraVerts);
892 extraVertIdx++;
893 }
894 }
895 }
896
897 // Fill out the remaining extra vertices, just so they aren't uninitialized
898 for(; extraVertIdx < maxExtraVerts; extraVertIdx++)
899 {
900 extraPositions = writeVector3(extraPositions, vertexStride, sphere.getCenter());
901
902 if (extraNormals)
903 extraNormals = writeVector3(extraNormals, vertexStride, Vector3::UNIT_Z);
904
905 if(extraUV)
906 extraUV = writeVector2(extraUV, vertexStride, Vector2::ZERO);
907 }
908 }
909
910 void ShapeMeshes3D::wireArc(const Vector3& center, float radius, const Vector3& normal, Degree startAngle, Degree amountAngle,
911 UINT8* outVertices, UINT32 vertexOffset, UINT32 vertexStride, UINT32* outIndices, UINT32 indexOffset, UINT32 quality)
912 {
913 UINT32 numVertices = (quality + 1) * 5;
914
915 generateArcVertices(center, normal, radius, startAngle, amountAngle, Vector2::ONE,
916 numVertices, outVertices, vertexOffset, vertexStride);
917
918 outIndices += indexOffset;
919 UINT32 numLines = numVertices - 1;
920 for (UINT32 i = 0; i < numLines; i++)
921 {
922 outIndices[i * 2 + 0] = vertexOffset + i;
923 outIndices[i * 2 + 1] = vertexOffset + i + 1;
924 }
925 }
926
927 void ShapeMeshes3D::solidArc(const Vector3& center, float radius, const Vector3& normal, Degree startAngle,
928 Degree amountAngle, UINT8* outVertices, UINT8* outNormals, UINT8* outUV, UINT32 vertexOffset, UINT32 vertexStride,
929 UINT32* outIndices, UINT32 indexOffset, UINT32 quality)
930 {
931 outVertices += vertexOffset * vertexStride;
932 outNormals += vertexOffset * vertexStride;
933 outIndices += indexOffset;
934
935 bool reverseOrder = amountAngle.valueDegrees() < 0.0f;
936 Vector3 visibleNormal = normal;
937
938 outVertices = writeVector3(outVertices, vertexStride, center);
939 outNormals = writeVector3(outNormals, vertexStride, visibleNormal);
940
941 UINT32 numArcVertices = (quality + 1) * 5;
942 generateArcVertices(center, normal, radius, startAngle, amountAngle, Vector2::ONE,
943 numArcVertices, outVertices, vertexOffset, vertexStride);
944
945 UINT8* otherSideVertices = outVertices + (numArcVertices * vertexStride);
946 UINT8* otherSideNormals = outNormals + (numArcVertices * vertexStride);
947
948 otherSideVertices = writeVector3(otherSideVertices, vertexStride, center);
949 otherSideNormals = writeVector3(otherSideNormals, vertexStride, -visibleNormal);
950
951 for (UINT32 i = 0; i < numArcVertices; i++)
952 {
953 otherSideVertices = writeVector3(otherSideVertices, vertexStride, *(Vector3*)&outVertices[i * vertexStride]);
954
955 outNormals = writeVector3(outNormals, vertexStride, visibleNormal);
956 otherSideNormals = writeVector3(otherSideNormals, vertexStride, -visibleNormal);
957 }
958
959 // UV
960 if(outUV != nullptr)
961 {
962 outUV += vertexOffset * vertexStride;
963
964 // Center
965 outUV = writeVector2(outUV, vertexStride, Vector2(0.5f, 0.5f));
966
967 Vector3 arcNormal = normal;
968 Vector3 right, top;
969 arcNormal.orthogonalComplement(right, top);
970
971 for (UINT32 i = 0; i < numArcVertices; i++)
972 {
973 Vector3 vec = *(Vector3*)&outVertices[i * vertexStride];
974 Vector3 diff = Vector3::normalize(vec - center);
975
976 Vector2 uv;
977 uv.x = Vector3::dot(diff, right) * 0.5f + 0.5f;
978 uv.y = Vector3::dot(diff, top) * 0.5f + 0.5f;
979
980 outUV = writeVector2(outUV, vertexStride, uv);
981 }
982
983 // Reverse
984 outUV = writeVector2(outUV, vertexStride, Vector2(0.5f, 0.5f));
985
986 for (UINT32 i = 0; i < numArcVertices; i++)
987 {
988 Vector3 vec = *(Vector3*)&outVertices[(numArcVertices + i + 1) * vertexStride];
989 Vector3 diff = Vector3::normalize(vec - center);
990
991 Vector2 uv;
992 uv.x = Vector3::dot(diff, -right) * 0.5f + 0.5f;
993 uv.y = Vector3::dot(diff, -top) * 0.5f + 0.5f;
994
995 outUV = writeVector2(outUV, vertexStride, uv);
996 }
997 }
998
999 UINT32 numTriangles = numArcVertices;
1000
1001 // If angle is negative the order of vertices is reversed so we need to reverse the indexes too
1002 UINT32 frontSideOffset = vertexOffset + (reverseOrder ? (numArcVertices + 1) : 0);
1003 UINT32 backSideOffset = vertexOffset + (!reverseOrder ? (numArcVertices + 1) : 0);
1004
1005 for (UINT32 i = 0; i < numTriangles; i++)
1006 {
1007 outIndices[i * 6 + 0] = frontSideOffset + 0;
1008 outIndices[i * 6 + 1] = frontSideOffset + i;
1009 outIndices[i * 6 + 2] = frontSideOffset + i + 1;
1010
1011 outIndices[i * 6 + 3] = backSideOffset + 0;
1012 outIndices[i * 6 + 4] = backSideOffset + i + 1;
1013 outIndices[i * 6 + 5] = backSideOffset + i;
1014 }
1015 }
1016
1017 void ShapeMeshes3D::wireFrustum(const Vector3& position, float aspect, Degree FOV, float near, float far,
1018 UINT8* outVertices, UINT32 vertexOffset, UINT32 vertexStride, UINT32* outIndices, UINT32 indexOffset)
1019 {
1020 float fovTan = Math::tan(FOV * 0.5f);
1021
1022 Vector3 nearPoint(0, 0, near);
1023 Vector3 nearWidth(near * fovTan * aspect, 0, 0);
1024 Vector3 nearHeight(0, (near * fovTan) / aspect, 0);
1025
1026 Vector3 farPoint(0, 0, far);
1027 Vector3 farWidth(far * fovTan * aspect, 0, 0);
1028 Vector3 farHeight(0, (far * fovTan) / aspect, 0);
1029
1030 Vector3 points[8] =
1031 {
1032 nearPoint + nearWidth + nearHeight,
1033 nearPoint - nearWidth + nearHeight,
1034 nearPoint - nearWidth - nearHeight,
1035 nearPoint + nearWidth - nearHeight,
1036 farPoint + farWidth + farHeight,
1037 farPoint - farWidth + farHeight,
1038 farPoint - farWidth - farHeight,
1039 farPoint + farWidth - farHeight
1040 };
1041
1042 outVertices += vertexOffset * vertexStride;
1043
1044 for (UINT32 i = 0; i < 8; i++)
1045 outVertices = writeVector3(outVertices, vertexStride, position + points[i]);
1046
1047 outIndices += indexOffset;
1048
1049 // Front
1050 outIndices[0] = vertexOffset + 0; outIndices[1] = vertexOffset + 1;
1051 outIndices[2] = vertexOffset + 1; outIndices[3] = vertexOffset + 2;
1052 outIndices[4] = vertexOffset + 2; outIndices[5] = vertexOffset + 3;
1053 outIndices[6] = vertexOffset + 3; outIndices[7] = vertexOffset + 0;
1054
1055 // Center
1056 outIndices[8] = vertexOffset + 0; outIndices[9] = vertexOffset + 4;
1057 outIndices[10] = vertexOffset + 1; outIndices[11] = vertexOffset + 5;
1058 outIndices[12] = vertexOffset + 2; outIndices[13] = vertexOffset + 6;
1059 outIndices[14] = vertexOffset + 3; outIndices[15] = vertexOffset + 7;
1060
1061 // Back
1062 outIndices[16] = vertexOffset + 4; outIndices[17] = vertexOffset + 5;
1063 outIndices[18] = vertexOffset + 5; outIndices[19] = vertexOffset + 6;
1064 outIndices[20] = vertexOffset + 6; outIndices[21] = vertexOffset + 7;
1065 outIndices[22] = vertexOffset + 7; outIndices[23] = vertexOffset + 4;
1066 }
1067
1068 void ShapeMeshes3D::solidCone(const Vector3& base, const Vector3& normal, float height, float radius, Vector2 scale,
1069 UINT8* outVertices, UINT8* outNormals, UINT8* outUV, UINT32 vertexOffset, UINT32 vertexStride, UINT32* outIndices,
1070 UINT32 indexOffset, UINT32 quality)
1071 {
1072 outVertices += vertexOffset * vertexStride;
1073 outIndices += indexOffset;
1074
1075 if (outUV != nullptr)
1076 outUV += vertexOffset * vertexStride;
1077
1078 if (outNormals != nullptr)
1079 outNormals += vertexOffset * vertexStride;
1080
1081 // Generate base disc
1082 UINT32 numArcVertices = (quality + 1) * 4;
1083
1084 generateArcVertices(base, normal, radius, Degree(0), Degree(360), scale,
1085 numArcVertices + 1, outVertices, 0, vertexStride);
1086
1087 if (outUV != nullptr)
1088 {
1089 Vector3 arcNormal = normal;
1090 Vector3 right, top;
1091 arcNormal.orthogonalComplement(right, top);
1092
1093 for (UINT32 i = 0; i < numArcVertices; i++)
1094 {
1095 Vector3 vec = *(Vector3*)&outVertices[i * vertexStride];
1096 Vector3 diff = Vector3::normalize(vec - base);
1097
1098 Vector2 uv;
1099 uv.x = Vector3::dot(diff, right) * 0.5f + 0.5f;
1100 uv.y = Vector3::dot(diff, top) * 0.5f + 0.5f;
1101
1102 outUV = writeVector2(outUV, vertexStride, uv);
1103 }
1104
1105 // Center base
1106 outUV = writeVector2(outUV, vertexStride, Vector2(0.5f, 0.5f));
1107 }
1108
1109 outVertices += numArcVertices * vertexStride;
1110 outVertices = writeVector3(outVertices, vertexStride, base); // Write base vertex
1111
1112 UINT32 baseIdx = numArcVertices;
1113
1114 if (outNormals != nullptr)
1115 {
1116 UINT32 totalNumBaseVertices = numArcVertices + 1;
1117 for (UINT32 i = 0; i < totalNumBaseVertices; i++)
1118 outNormals = writeVector3(outNormals, vertexStride, -normal);
1119 }
1120
1121 UINT32 numTriangles = numArcVertices;
1122 for (UINT32 i = 0; i < numTriangles - 1; i++)
1123 {
1124 outIndices[i * 3 + 0] = vertexOffset + baseIdx;
1125 outIndices[i * 3 + 1] = vertexOffset + i + 1;
1126 outIndices[i * 3 + 2] = vertexOffset + i;
1127 }
1128
1129 {
1130 UINT32 i = numTriangles - 1;
1131 outIndices[i * 3 + 0] = vertexOffset + baseIdx;
1132 outIndices[i * 3 + 1] = vertexOffset + 0;
1133 outIndices[i * 3 + 2] = vertexOffset + i;
1134 }
1135
1136 //// Generate cone
1137 // Base vertices
1138 generateArcVertices(base, normal, radius, Degree(0), Degree(360), scale,
1139 numArcVertices + 1, outVertices, 0, vertexStride);
1140
1141 Vector3 topVertex = base + normal * height;
1142
1143 // Normals
1144 if (outNormals != nullptr)
1145 {
1146 UINT8* outNormalsBase = outNormals;
1147 UINT8* outNormalsTop = outNormals + numArcVertices * vertexStride;
1148 for (INT32 i = 0; i < (INT32)numArcVertices; i++)
1149 {
1150 int offsetA = i == 0 ? numArcVertices - 1 : i - 1;
1151 int offsetB = i;
1152 int offsetC = (i + 1) % numArcVertices;
1153
1154 Vector3* a = (Vector3*)(outVertices + (offsetA * vertexStride));
1155 Vector3* b = (Vector3*)(outVertices + (offsetB * vertexStride));
1156 Vector3* c = (Vector3*)(outVertices + (offsetC * vertexStride));
1157
1158 Vector3 toTop = topVertex - *b;
1159
1160 Vector3 normalLeft = Vector3::cross(*a - *b, toTop);
1161 normalLeft.normalize();
1162
1163 Vector3 normalRight = Vector3::cross(toTop, *c - *b);
1164 normalRight.normalize();
1165
1166 Vector3 triNormal = Vector3::normalize(normalLeft + normalRight);
1167
1168 outNormalsBase = writeVector3(outNormalsBase, vertexStride, triNormal);
1169 outNormalsTop = writeVector3(outNormalsTop, vertexStride, triNormal);
1170 }
1171 }
1172
1173 // UV
1174 if(outUV != nullptr)
1175 {
1176 float angle = 0.0f;
1177 float angleIncrement = Math::TWO_PI / numArcVertices;
1178
1179 // Bottom
1180 for (UINT32 i = 0; i < numArcVertices; i++)
1181 {
1182 Vector2 uv;
1183 uv.x = angle / Math::TWO_PI;
1184 uv.y = 1.0f;
1185
1186 outUV = writeVector2(outUV, vertexStride, uv);
1187 angle += angleIncrement;
1188 }
1189
1190 // Top
1191 angle = 0.0f;
1192 for (UINT32 i = 0; i < numArcVertices; i++)
1193 {
1194 Vector2 uv;
1195 uv.x = angle / Math::TWO_PI;
1196 uv.y = 0.0f;
1197
1198 outUV = writeVector2(outUV, vertexStride, uv);
1199 angle += angleIncrement;
1200 }
1201 }
1202
1203 // Top vertices (All same position, but need them separate because of different normals & uv)
1204 outVertices += numArcVertices * vertexStride;
1205
1206 for (UINT32 i = 0; i < numArcVertices; i++)
1207 outVertices = writeVector3(outVertices, vertexStride, topVertex);
1208
1209 outIndices += numTriangles * 3;
1210 UINT32 curVertBaseOffset = vertexOffset + numArcVertices + 1;
1211 UINT32 curVertTopOffset = curVertBaseOffset + numArcVertices;
1212 for (UINT32 i = 0; i < numTriangles - 1; i++)
1213 {
1214 outIndices[i * 3 + 0] = curVertTopOffset + i;
1215 outIndices[i * 3 + 1] = curVertBaseOffset + i;
1216 outIndices[i * 3 + 2] = curVertBaseOffset + i + 1;
1217 }
1218
1219 {
1220 UINT32 i = numTriangles - 1;
1221 outIndices[i * 3 + 0] = curVertTopOffset + i;
1222 outIndices[i * 3 + 1] = curVertBaseOffset + i;
1223 outIndices[i * 3 + 2] = curVertBaseOffset + 0;
1224 }
1225 }
1226
1227 void ShapeMeshes3D::wireCone(const Vector3& base, const Vector3& normal, float height, float radius, Vector2 scale,
1228 UINT8* outVertices, UINT32 vertexOffset, UINT32 vertexStride, UINT32* outIndices, UINT32 indexOffset, UINT32 quality)
1229 {
1230 outVertices += vertexOffset * vertexStride;
1231 outIndices += indexOffset;
1232
1233 // Generate arc vertices
1234 UINT32 numArcVertices = (quality + 1) * 4;
1235
1236 generateArcVertices(base, normal, radius, Degree(0), Degree(360), scale,
1237 numArcVertices + 1, outVertices, 0, vertexStride);
1238
1239 outVertices += numArcVertices * vertexStride;
1240
1241 UINT32 numLines = numArcVertices;
1242 for (UINT32 i = 0; i < numLines; i++)
1243 {
1244 outIndices[i * 2 + 0] = vertexOffset + i;
1245 outIndices[i * 2 + 1] = vertexOffset + i + 1;
1246 }
1247
1248 outIndices += numLines * 2;
1249
1250 // Generate cone vertices
1251 generateArcVertices(base, normal, radius, Degree(0), Degree(360), scale,
1252 5, outVertices, 0, vertexStride);
1253
1254 // Cone point
1255 outVertices += 4 * vertexStride;
1256 outVertices = writeVector3(outVertices, vertexStride, base + normal * height);
1257
1258 vertexOffset += numArcVertices;
1259
1260 for (UINT32 i = 0; i < 4; i++)
1261 {
1262 outIndices[i * 2 + 0] = vertexOffset + 4;
1263 outIndices[i * 2 + 1] = vertexOffset + i;
1264 }
1265 }
1266
1267 void ShapeMeshes3D::solidCylinder(const Vector3& base, const Vector3& normal, float height, float radius, Vector2 scale,
1268 UINT8* outVertices, UINT8* outNormals, UINT8* outUV, UINT32 vertexOffset, UINT32 vertexStride, UINT32* outIndices,
1269 UINT32 indexOffset, UINT32 quality)
1270 {
1271 outVertices += vertexOffset * vertexStride;
1272 outIndices += indexOffset;
1273
1274 if (outUV != nullptr)
1275 outUV += vertexOffset * vertexStride;
1276
1277 if (outNormals != nullptr)
1278 outNormals += vertexOffset * vertexStride;
1279
1280 // Generate base disc
1281 UINT32 numArcVertices = (quality + 1) * 4;
1282
1283 generateArcVertices(base, normal, radius, Degree(0), Degree(360), scale,
1284 numArcVertices + 1, outVertices, 0, vertexStride);
1285
1286 if (outUV != nullptr)
1287 {
1288 Vector3 arcNormal = normal;
1289 Vector3 right, top;
1290 arcNormal.orthogonalComplement(right, top);
1291
1292 for (UINT32 i = 0; i < numArcVertices; i++)
1293 {
1294 Vector3 vec = *(Vector3*)&outVertices[i * vertexStride];
1295 Vector3 diff = Vector3::normalize(vec - base);
1296
1297 Vector2 uv;
1298 uv.x = Vector3::dot(diff, right) * 0.5f + 0.5f;
1299 uv.y = Vector3::dot(diff, top) * 0.5f + 0.5f;
1300
1301 outUV = writeVector2(outUV, vertexStride, uv);
1302 }
1303
1304 outUV = writeVector2(outUV, vertexStride, Vector2(0.5f, 0.5f));
1305 }
1306
1307 outVertices += numArcVertices * vertexStride;
1308 outVertices = writeVector3(outVertices, vertexStride, base); // Write base vertex
1309
1310 UINT32 baseIdx = numArcVertices;
1311
1312 if (outNormals != nullptr)
1313 {
1314 UINT32 totalNumBaseVertices = numArcVertices + 1;
1315 for (UINT32 i = 0; i < totalNumBaseVertices; i++)
1316 outNormals = writeVector3(outNormals, vertexStride, -normal);
1317 }
1318
1319 UINT32 numTriangles = numArcVertices;
1320 for (UINT32 i = 0; i < numTriangles - 1; i++)
1321 {
1322 outIndices[i * 3 + 0] = vertexOffset + baseIdx;
1323 outIndices[i * 3 + 1] = vertexOffset + i + 1;
1324 outIndices[i * 3 + 2] = vertexOffset + i;
1325 }
1326
1327 {
1328 UINT32 i = numTriangles - 1;
1329 outIndices[i * 3 + 0] = vertexOffset + baseIdx;
1330 outIndices[i * 3 + 1] = vertexOffset + 0;
1331 outIndices[i * 3 + 2] = vertexOffset + i;
1332 }
1333
1334 outIndices += numTriangles * 3;
1335 UINT32 vertexOffsetBase = vertexOffset + numArcVertices + 1;
1336
1337 // Generate cap disc
1338 Vector3 topVertex = base + normal * height;
1339
1340 generateArcVertices(topVertex, normal, radius, Degree(0), Degree(360), scale,
1341 numArcVertices + 1, outVertices, 0, vertexStride);
1342
1343 if (outUV != nullptr)
1344 {
1345 Vector3 arcNormal = normal;
1346 Vector3 right, top;
1347 arcNormal.orthogonalComplement(right, top);
1348
1349 for (UINT32 i = 0; i < numArcVertices; i++)
1350 {
1351 Vector3 vec = *(Vector3*)&outVertices[i * vertexStride];
1352 Vector3 diff = Vector3::normalize(vec - topVertex);
1353
1354 Vector2 uv;
1355 uv.x = Vector3::dot(diff, right) * 0.5f + 0.5f;
1356 uv.y = Vector3::dot(diff, top) * 0.5f + 0.5f;
1357
1358 outUV = writeVector2(outUV, vertexStride, uv);
1359 }
1360
1361 outUV = writeVector2(outUV, vertexStride, Vector2(0.5f, 0.5f));
1362 }
1363
1364 outVertices += numArcVertices * vertexStride;
1365 outVertices = writeVector3(outVertices, vertexStride, topVertex); // Write top vertex
1366
1367 if (outNormals != nullptr)
1368 {
1369 UINT32 totalNumBaseVertices = numArcVertices + 1;
1370 for (UINT32 i = 0; i < totalNumBaseVertices; i++)
1371 outNormals = writeVector3(outNormals, vertexStride, normal);
1372 }
1373
1374 for (UINT32 i = 0; i < numTriangles - 1; i++)
1375 {
1376 outIndices[i * 3 + 0] = vertexOffsetBase + baseIdx;
1377 outIndices[i * 3 + 1] = vertexOffsetBase + i;
1378 outIndices[i * 3 + 2] = vertexOffsetBase + i + 1;
1379 }
1380
1381 {
1382 UINT32 i = numTriangles - 1;
1383 outIndices[i * 3 + 0] = vertexOffsetBase + baseIdx;
1384 outIndices[i * 3 + 1] = vertexOffsetBase + i;
1385 outIndices[i * 3 + 2] = vertexOffsetBase + 0;
1386 }
1387
1388 outIndices += numTriangles * 3;
1389 UINT32 vertexOffsetCap = vertexOffsetBase + numArcVertices + 1;
1390
1391 // Generate cylinder
1392 generateArcVertices(base, normal, radius, Degree(0), Degree(360), scale,
1393 numArcVertices + 1, outVertices, 0, vertexStride);
1394
1395 generateArcVertices(topVertex, normal, radius, Degree(0), Degree(360), scale,
1396 numArcVertices + 1, outVertices, numArcVertices + 1, vertexStride);
1397
1398 // Normals
1399 if (outNormals != nullptr)
1400 {
1401 UINT8* outNormalsBase = outNormals;
1402 UINT8* outNormalsCap = outNormals + (numArcVertices + 1) * vertexStride;
1403 for (UINT32 i = 0; i < numArcVertices + 1; i++)
1404 {
1405 UINT32 offsetA = i == 0 ? numArcVertices - 1 : i - 1;
1406 UINT32 offsetB = i;
1407 UINT32 offsetC = i == numArcVertices ? 1 : i + 1;
1408
1409 Vector3* a = (Vector3*)(outVertices + (offsetA * vertexStride));
1410 Vector3* b = (Vector3*)(outVertices + (offsetB * vertexStride));
1411 Vector3* c = (Vector3*)(outVertices + (offsetC * vertexStride));
1412
1413 Vector3 toTop = normal;
1414
1415 Vector3 normalLeft = Vector3::cross(*a - *b, toTop);
1416 normalLeft.normalize();
1417
1418 Vector3 normalRight = Vector3::cross(toTop, *c - *b);
1419 normalRight.normalize();
1420
1421 Vector3 triNormal = Vector3::normalize(normalLeft + normalRight);
1422
1423 outNormalsBase = writeVector3(outNormalsBase, vertexStride, triNormal);
1424 outNormalsCap = writeVector3(outNormalsCap, vertexStride, triNormal);
1425 }
1426 }
1427
1428 // UV
1429 if (outUV != nullptr)
1430 {
1431 float angle = 0.0f;
1432 float angleIncrement = Math::TWO_PI / numArcVertices;
1433
1434 for (UINT32 i = 0; i < numArcVertices + 1; i++)
1435 {
1436 Vector2 uv;
1437 uv.x = angle / Math::TWO_PI;
1438 uv.y = 1.0f;
1439
1440 outUV = writeVector2(outUV, vertexStride, uv);
1441 angle += angleIncrement;
1442 }
1443
1444 angle = 0.0f;
1445 for (UINT32 i = 0; i < numArcVertices + 1; i++)
1446 {
1447 Vector2 uv;
1448 uv.x = angle / Math::TWO_PI;
1449 uv.y = 0.0f;
1450
1451 outUV = writeVector2(outUV, vertexStride, uv);
1452 angle += angleIncrement;
1453 }
1454 }
1455
1456 vertexOffsetBase = vertexOffsetCap;
1457 vertexOffsetCap = vertexOffsetCap + numArcVertices + 1;
1458
1459 for (UINT32 i = 0; i < numTriangles; i++)
1460 {
1461 outIndices[i * 6 + 0] = vertexOffsetCap + i;
1462 outIndices[i * 6 + 1] = vertexOffsetBase + i;
1463 outIndices[i * 6 + 2] = vertexOffsetBase + i + 1;
1464
1465 outIndices[i * 6 + 3] = vertexOffsetCap + i;
1466 outIndices[i * 6 + 4] = vertexOffsetBase + i + 1;
1467 outIndices[i * 6 + 5] = vertexOffsetCap + i + 1;
1468 }
1469 }
1470
1471 void ShapeMeshes3D::wireCylinder(const Vector3& base, const Vector3& normal, float height, float radius, Vector2 scale,
1472 UINT8* outVertices, UINT32 vertexOffset, UINT32 vertexStride, UINT32* outIndices, UINT32 indexOffset, UINT32 quality)
1473 {
1474 outVertices += vertexOffset * vertexStride;
1475 outIndices += indexOffset;
1476
1477 // Generate base and cap discs
1478 UINT32 numArcVertices = (quality + 1) * 4;
1479
1480 Degree angleAmount = Degree(360) - Degree(360) / (float)(numArcVertices);
1481
1482 generateArcVertices(base, normal, radius, Degree(0), angleAmount, scale,
1483 numArcVertices, outVertices, 0, vertexStride);
1484
1485 Vector3 topVertex = base + normal * height;
1486
1487 generateArcVertices(topVertex, normal, radius, Degree(0), angleAmount, scale,
1488 numArcVertices, outVertices, numArcVertices, vertexStride);
1489
1490 UINT32 vertexOffsetBase = vertexOffset;
1491 UINT32 vertexOffsetCap = vertexOffset + numArcVertices;
1492
1493 UINT32 numLines = numArcVertices;
1494 for (UINT32 i = 0; i < numLines - 1; i++)
1495 {
1496 outIndices[i * 4 + 0] = vertexOffsetBase + i;
1497 outIndices[i * 4 + 1] = vertexOffsetBase + i + 1;
1498 outIndices[i * 4 + 2] = vertexOffsetCap + i;
1499 outIndices[i * 4 + 3] = vertexOffsetCap + i + 1;
1500 }
1501 {
1502 UINT32 i = numLines - 1;
1503 outIndices[i * 4 + 0] = vertexOffsetBase + i;
1504 outIndices[i * 4 + 1] = vertexOffsetBase + 0;
1505 outIndices[i * 4 + 2] = vertexOffsetCap + i;
1506 outIndices[i * 4 + 3] = vertexOffsetCap + 0;
1507 }
1508
1509 // Generate cylinder
1510 outIndices += numLines * 4;
1511 for (UINT32 i = 0; i < numLines; i++)
1512 {
1513 outIndices[i * 2 + 0] = vertexOffsetBase + i;
1514 outIndices[i * 2 + 1] = vertexOffsetCap + i;
1515 }
1516 }
1517
1518 void ShapeMeshes3D::solidQuad(const Rect3& area, UINT8* outVertices, UINT8* outNormals, UINT8* outUV,
1519 UINT32 vertexOffset, UINT32 vertexStride, UINT32* outIndices, UINT32 indexOffset)
1520 {
1521 outVertices += (vertexOffset * vertexStride);
1522
1523 Vector3 topLeft = area.getCenter() - area.getAxisHorz() * area.getExtentHorz() + area.getAxisVert() * area.getExtentVertical();
1524 Vector3 topRight = area.getCenter() + area.getAxisHorz() * area.getExtentHorz() + area.getAxisVert() * area.getExtentVertical();
1525 Vector3 botRight = area.getCenter() + area.getAxisHorz() * area.getExtentHorz() - area.getAxisVert() * area.getExtentVertical();
1526 Vector3 botLeft = area.getCenter() - area.getAxisHorz() * area.getExtentHorz() - area.getAxisVert() * area.getExtentVertical();
1527
1528 outVertices = writeVector3(outVertices, vertexStride, topLeft);
1529 outVertices = writeVector3(outVertices, vertexStride, topRight);
1530 outVertices = writeVector3(outVertices, vertexStride, botRight);
1531 outVertices = writeVector3(outVertices, vertexStride, botLeft);
1532
1533 outVertices = writeVector3(outVertices, vertexStride, topLeft);
1534 outVertices = writeVector3(outVertices, vertexStride, topRight);
1535 outVertices = writeVector3(outVertices, vertexStride, botRight);
1536 outVertices = writeVector3(outVertices, vertexStride, botLeft);
1537
1538 Vector3 normal = area.getAxisHorz().cross(area.getAxisVert());
1539 Vector3 reverseNormal = -normal;
1540
1541 outNormals += (vertexOffset * vertexStride);
1542 outNormals = writeVector3(outNormals, vertexStride, normal);
1543 outNormals = writeVector3(outNormals, vertexStride, normal);
1544 outNormals = writeVector3(outNormals, vertexStride, normal);
1545 outNormals = writeVector3(outNormals, vertexStride, normal);
1546
1547 outNormals = writeVector3(outNormals, vertexStride, reverseNormal);
1548 outNormals = writeVector3(outNormals, vertexStride, reverseNormal);
1549 outNormals = writeVector3(outNormals, vertexStride, reverseNormal);
1550 outNormals = writeVector3(outNormals, vertexStride, reverseNormal);
1551
1552 if(outUV != nullptr)
1553 {
1554 outUV += (vertexOffset * vertexStride);
1555 outUV = writeVector2(outUV, vertexStride, Vector2(0.0f, 0.0f));
1556 outUV = writeVector2(outUV, vertexStride, Vector2(1.0f, 0.0f));
1557 outUV = writeVector2(outUV, vertexStride, Vector2(1.0f, 1.0f));
1558 outUV = writeVector2(outUV, vertexStride, Vector2(0.0f, 1.0f));
1559
1560 outUV = writeVector2(outUV, vertexStride, Vector2(0.0f, 0.0f));
1561 outUV = writeVector2(outUV, vertexStride, Vector2(1.0f, 0.0f));
1562 outUV = writeVector2(outUV, vertexStride, Vector2(1.0f, 1.0f));
1563 outUV = writeVector2(outUV, vertexStride, Vector2(0.0f, 1.0f));
1564 }
1565
1566 outIndices += indexOffset;
1567 outIndices[0] = vertexOffset;
1568 outIndices[1] = vertexOffset + 1;
1569 outIndices[2] = vertexOffset + 2;
1570
1571 outIndices[3] = vertexOffset;
1572 outIndices[4] = vertexOffset + 2;
1573 outIndices[5] = vertexOffset + 3;
1574
1575 outIndices[6] = vertexOffset + 4;
1576 outIndices[7] = vertexOffset + 6;
1577 outIndices[8] = vertexOffset + 5;
1578
1579 outIndices[9] = vertexOffset + 4;
1580 outIndices[10] = vertexOffset + 7;
1581 outIndices[11] = vertexOffset + 6;
1582 }
1583
1584 Vector3 ShapeMeshes3D::calcCenter(UINT8* vertices, UINT32 numVertices, UINT32 vertexStride)
1585 {
1586 Vector3 center = Vector3::ZERO;
1587 for(UINT32 i = 0; i < numVertices; i++)
1588 {
1589 Vector3* curVert = (Vector3*)vertices;
1590 center += *curVert;
1591
1592 vertices += vertexStride;
1593 }
1594
1595 center /= (float)numVertices;
1596 return center;
1597 }
1598
1599 void ShapeMeshes3D::pixelLine(const Vector3& a, const Vector3& b, UINT8* outVertices,
1600 UINT32 vertexOffset, UINT32 vertexStride, UINT32* outIndices, UINT32 indexOffset)
1601 {
1602 outVertices += (vertexOffset * vertexStride);
1603
1604 Vector3* vertices = (Vector3*)outVertices;
1605 (*vertices) = a;
1606
1607 vertices = (Vector3*)(outVertices + vertexStride);
1608 (*vertices) = b;
1609
1610 outIndices += indexOffset;
1611 outIndices[0] = vertexOffset + 0;
1612 outIndices[1] = vertexOffset + 1;
1613 }
1614
1615 void ShapeMeshes3D::antialiasedLine(const Vector3& a, const Vector3& b, const Vector3& up, float width, float borderWidth, const Color& color, UINT8* outVertices, UINT8* outColors,
1616 UINT32 vertexOffset, UINT32 vertexStride, UINT32* outIndices, UINT32 indexOffset)
1617 {
1618 Vector3 dir = b - a;
1619 dir.normalize();
1620
1621 Vector3 right = dir.cross(up);
1622 right.normalize();
1623
1624 Vector<Vector3> points(4);
1625
1626 float r = width * 0.5f;
1627 dir = dir * r;
1628 right = right * r;
1629
1630 Vector3 v0 = a - dir - right;
1631 Vector3 v1 = a - dir + right;
1632 Vector3 v2 = b + dir + right;
1633 Vector3 v3 = b + dir - right;
1634
1635 points[0] = v0;
1636 points[1] = v1;
1637 points[2] = v2;
1638 points[3] = v3;
1639
1640 antialiasedPolygon(points, up, borderWidth, color, outVertices, outColors, vertexOffset, vertexStride, outIndices, indexOffset);
1641 }
1642
1643 void ShapeMeshes3D::pixelSolidPolygon(const Vector<Vector3>& points, UINT8* outVertices,
1644 UINT32 vertexOffset, UINT32 vertexStride, UINT32* outIndices, UINT32 indexOffset)
1645 {
1646 outVertices += (vertexOffset * vertexStride);
1647
1648 for (auto& point : points)
1649 {
1650 Vector3* vertices = (Vector3*)outVertices;
1651 (*vertices) = point;
1652
1653 outVertices += vertexStride;
1654 }
1655
1656 outIndices += indexOffset;
1657 INT32 numPoints = (INT32)points.size();
1658 UINT32 idxCnt = 0;
1659 for (int i = 2; i < numPoints; i++)
1660 {
1661 outIndices[idxCnt++] = vertexOffset;
1662 outIndices[idxCnt++] = vertexOffset + i - 1;
1663 outIndices[idxCnt++] = vertexOffset + i;
1664 }
1665 }
1666
1667 void ShapeMeshes3D::pixelWirePolygon(const Vector<Vector3>& points, UINT8* outVertices,
1668 UINT32 vertexOffset, UINT32 vertexStride, UINT32* outIndices, UINT32 indexOffset)
1669 {
1670 INT32 numPoints = (INT32)points.size();
1671 UINT32 curVertOffset = vertexOffset;
1672 UINT32 curIdxOffset = indexOffset;
1673 for (INT32 i = 0, j = numPoints - 1; i < numPoints; j = i++)
1674 {
1675 pixelLine(points[j], points[i], outVertices, curVertOffset, vertexStride, outIndices, curIdxOffset);
1676 curVertOffset += 2;
1677 curIdxOffset += 2;
1678 }
1679 }
1680
1681 void ShapeMeshes3D::antialiasedPolygon(const Vector<Vector3>& points, const Vector3& up, float borderWidth, const Color& color, UINT8* outVertices, UINT8* outColors,
1682 UINT32 vertexOffset, UINT32 vertexStride, UINT32* outIndices, UINT32 indexOffset)
1683 {
1684 UINT32 numCoords = (UINT32)points.size();
1685
1686 outVertices += vertexOffset * vertexStride;
1687 outColors += vertexOffset * vertexStride;
1688 Vector<Vector3> tempNormals(numCoords);
1689
1690 for (UINT32 i = 0, j = numCoords - 1; i < numCoords; j = i++)
1691 {
1692 const Vector3& v0 = points[j];
1693 const Vector3& v1 = points[i];
1694
1695 Vector3 dir = v1 - v0;
1696 Vector3 right = dir.cross(up);
1697 right.normalize();
1698
1699 tempNormals[j] = right;
1700
1701 // Also start populating the vertex array
1702 Vector3* vertices = (Vector3*)outVertices;
1703 *vertices = v1;
1704
1705 UINT32* colors = (UINT32*)outColors;
1706 *colors = color.getAsRGBA();
1707
1708 outVertices += vertexStride;
1709 outColors += vertexStride;
1710 }
1711
1712 Color transparentColor = color;
1713 transparentColor.a = 0.0f;
1714
1715 for (UINT32 i = 0, j = numCoords - 1; i < numCoords; j = i++)
1716 {
1717 const Vector3& n0 = tempNormals[j];
1718 const Vector3& n1 = tempNormals[i];
1719
1720 Vector3 avgNrm = (n0 + n1) * 0.5f;
1721 float magSqrd = avgNrm.squaredLength();
1722
1723 if (magSqrd > 0.000001f)
1724 {
1725 float scale = 1.0f / magSqrd;
1726 if (scale > 10.0f)
1727 scale = 10.0f;
1728
1729 avgNrm = avgNrm * scale;
1730 }
1731
1732 Vector3 tempCoord = points[i] + avgNrm * borderWidth;
1733
1734 // Move it to the vertex array
1735 Vector3* vertices = (Vector3*)outVertices;
1736 *vertices = tempCoord;
1737
1738 UINT32* colors = (UINT32*)outColors;
1739 *colors = transparentColor.getAsRGBA();
1740
1741 outVertices += vertexStride;
1742 outColors += vertexStride;
1743 }
1744
1745 // Populate index buffer
1746 outIndices += indexOffset;
1747
1748 UINT32 idxCnt = 0;
1749 for (UINT32 i = 0, j = numCoords - 1; i < numCoords; j = i++)
1750 {
1751 outIndices[idxCnt++] = vertexOffset + i;
1752 outIndices[idxCnt++] = vertexOffset + j;
1753 outIndices[idxCnt++] = vertexOffset + numCoords + j;
1754
1755 outIndices[idxCnt++] = vertexOffset + numCoords + j;
1756 outIndices[idxCnt++] = vertexOffset + numCoords + i;
1757 outIndices[idxCnt++] = vertexOffset + i;
1758 }
1759
1760 for (UINT32 i = 2; i < numCoords; ++i)
1761 {
1762 outIndices[idxCnt++] = vertexOffset + 0;
1763 outIndices[idxCnt++] = vertexOffset + i - 1;
1764 outIndices[idxCnt++] = vertexOffset + i;
1765 }
1766 }
1767
1768 UINT32 ShapeMeshes3D::subdivideTriangleOnSphere(const Vector3& center, float radius, UINT32 numLevels,
1769 const Vector3& a, const Vector3& b, const Vector3& c,
1770 UINT8* outVertices, UINT8* outNormals, UINT32 vertexOffset, UINT32 vertexStride)
1771 {
1772 outVertices += (vertexOffset * vertexStride);
1773
1774 if (outNormals != nullptr)
1775 outNormals += (vertexOffset * vertexStride);
1776
1777 UINT32 numVertices = 0;
1778
1779 if (numLevels > 0)
1780 {
1781 Vector3 sub1 = Vector3::normalize((a + b) * 0.5f);
1782 Vector3 sub2 = Vector3::normalize((b + c) * 0.5f);
1783 Vector3 sub3 = Vector3::normalize((c + a) * 0.5f);
1784
1785 numLevels--;
1786
1787 numVertices += subdivideTriangleOnSphere(center, radius, numLevels, a, sub1, sub3, outVertices,
1788 outNormals, numVertices, vertexStride);
1789 numVertices += subdivideTriangleOnSphere(center, radius, numLevels, sub1, b, sub2, outVertices,
1790 outNormals, numVertices, vertexStride);
1791 numVertices += subdivideTriangleOnSphere(center, radius, numLevels, sub1, sub2, sub3, outVertices,
1792 outNormals, numVertices, vertexStride);
1793 numVertices += subdivideTriangleOnSphere(center, radius, numLevels, sub3, sub2, c, outVertices,
1794 outNormals, numVertices, vertexStride);
1795 }
1796 else
1797 {
1798 *((Vector3*)outVertices) = center + a * radius;
1799 outVertices += vertexStride;
1800
1801 *((Vector3*)outVertices) = center + b * radius;
1802 outVertices += vertexStride;
1803
1804 *((Vector3*)outVertices) = center + c * radius;
1805 outVertices += vertexStride;
1806
1807 if (outNormals != nullptr)
1808 {
1809 *((Vector3*)outNormals) = a;
1810 outNormals += vertexStride;
1811
1812 *((Vector3*)outNormals) = b;
1813 outNormals += vertexStride;
1814
1815 *((Vector3*)outNormals) = c;
1816 outNormals += vertexStride;
1817 }
1818
1819 numVertices += 3;
1820 }
1821
1822 return numVertices;
1823 }
1824
1825 void ShapeMeshes3D::generateArcVertices(const Vector3& center, const Vector3& up, float radius, Degree startAngle,
1826 Degree angleAmount, Vector2 scale, UINT32 numVertices, UINT8* outVertices, UINT32 vertexOffset, UINT32 vertexStride)
1827 {
1828 assert(numVertices >= 2);
1829
1830 Quaternion alignWithStart = Quaternion(-Vector3::UNIT_Y, startAngle);
1831 Quaternion alignWithUp = Quaternion::getRotationFromTo(Vector3::UNIT_Y, up);
1832
1833 Vector3 right = alignWithUp.rotate(alignWithStart.rotate(Vector3::UNIT_X));
1834 right.normalize();
1835
1836 Quaternion increment(-up, angleAmount / (float)(numVertices - 1));
1837
1838 outVertices += vertexOffset * vertexStride;
1839 Vector3 curDirection = right * radius;
1840 for (UINT32 i = 0; i < numVertices; i++)
1841 {
1842 // Note: Ignoring scale
1843 outVertices = writeVector3(outVertices, vertexStride, (center + curDirection));
1844 curDirection = increment.rotate(curDirection);
1845 }
1846 }
1847
1848 void ShapeMeshes3D::generateTangents(UINT8* positions, UINT8* normals, UINT8* uv, UINT32* indices,
1849 UINT32 numVertices, UINT32 numIndices, UINT32 vertexOffset, UINT32 indexOffset, UINT32 vertexStride, UINT8* tangents)
1850 {
1851 Vector3* tempTangents = bs_stack_alloc<Vector3>(numVertices);
1852 Vector3* tempBitangents = bs_stack_alloc<Vector3>(numVertices);
1853
1854 MeshUtility::calculateTangents(
1855 (Vector3*)(positions + vertexOffset * vertexStride),
1856 (Vector3*)(normals + vertexOffset * vertexStride),
1857 (Vector2*)(uv + vertexOffset * vertexStride),
1858 (UINT8*)(indices + indexOffset),
1859 numVertices, numIndices, tempTangents, tempBitangents, 4, vertexStride);
1860
1861 for (UINT32 i = 0; i < (UINT32)numVertices; i++)
1862 {
1863 Vector3 normal = *(Vector3*)&normals[(vertexOffset + i) * vertexStride];
1864 Vector3 tangent = tempTangents[i];
1865 Vector3 bitangent = tempBitangents[i];
1866
1867 Vector3 engineBitangent = Vector3::cross(normal, tangent);
1868 float sign = Vector3::dot(engineBitangent, bitangent);
1869
1870 Vector4 packedTangent(tangent.x, tangent.y, tangent.z, sign > 0 ? 1.0f : -1.0f);
1871 memcpy(tangents + (vertexOffset + i) * vertexStride, &packedTangent, sizeof(Vector4));
1872 }
1873
1874 bs_stack_free(tempBitangents);
1875 bs_stack_free(tempTangents);
1876 }
1877}
1878