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/BsDrawHelper.h" |
4 | #include "Mesh/BsMesh.h" |
5 | #include "Math/BsAABox.h" |
6 | #include "Math/BsSphere.h" |
7 | #include "RenderAPI/BsVertexDataDesc.h" |
8 | #include "Utility/BsShapeMeshes3D.h" |
9 | #include "Text/BsTextData.h" |
10 | #include "Math/BsVector2.h" |
11 | #include "Math/BsQuaternion.h" |
12 | #include "String/BsUnicode.h" |
13 | #include "Renderer/BsCamera.h" |
14 | |
15 | namespace bs |
16 | { |
17 | const UINT32 DrawHelper::VERTEX_BUFFER_GROWTH = 4096; |
18 | const UINT32 DrawHelper::INDEX_BUFFER_GROWTH = 4096 * 2; |
19 | |
20 | DrawHelper::DrawHelper() |
21 | :mLayer(1) |
22 | { |
23 | mTransform = Matrix4::IDENTITY; |
24 | |
25 | mSolidVertexDesc = bs_shared_ptr_new<VertexDataDesc>(); |
26 | mSolidVertexDesc->addVertElem(VET_FLOAT3, VES_POSITION); |
27 | mSolidVertexDesc->addVertElem(VET_FLOAT3, VES_NORMAL); |
28 | mSolidVertexDesc->addVertElem(VET_COLOR, VES_COLOR); |
29 | |
30 | mWireVertexDesc = bs_shared_ptr_new<VertexDataDesc>(); |
31 | mWireVertexDesc->addVertElem(VET_FLOAT3, VES_POSITION); |
32 | mWireVertexDesc->addVertElem(VET_COLOR, VES_COLOR); |
33 | |
34 | mLineVertexDesc = bs_shared_ptr_new<VertexDataDesc>(); |
35 | mLineVertexDesc->addVertElem(VET_FLOAT3, VES_POSITION); |
36 | mLineVertexDesc->addVertElem(VET_COLOR, VES_COLOR); |
37 | |
38 | mTextVertexDesc = bs_shared_ptr_new<VertexDataDesc>(); |
39 | mTextVertexDesc->addVertElem(VET_FLOAT3, VES_POSITION); |
40 | mTextVertexDesc->addVertElem(VET_FLOAT2, VES_TEXCOORD); |
41 | mTextVertexDesc->addVertElem(VET_COLOR, VES_COLOR); |
42 | } |
43 | |
44 | void DrawHelper::setColor(const Color& color) |
45 | { |
46 | mColor = color; |
47 | } |
48 | |
49 | void DrawHelper::setTransform(const Matrix4& transform) |
50 | { |
51 | mTransform = transform; |
52 | } |
53 | |
54 | void DrawHelper::setLayer(UINT64 layer) |
55 | { |
56 | mLayer = layer; |
57 | } |
58 | |
59 | void DrawHelper::cube(const Vector3& position, const Vector3& extents) |
60 | { |
61 | mSolidCubeData.push_back(CubeData()); |
62 | CubeData& cubeData = mSolidCubeData.back(); |
63 | |
64 | cubeData.position = position; |
65 | cubeData.extents = extents; |
66 | cubeData.color = mColor; |
67 | cubeData.transform = mTransform; |
68 | cubeData.layer = mLayer; |
69 | cubeData.center = mTransform.multiplyAffine(position); |
70 | } |
71 | |
72 | void DrawHelper::sphere(const Vector3& position, float radius, UINT32 quality) |
73 | { |
74 | mSolidSphereData.push_back(SphereData()); |
75 | SphereData& sphereData = mSolidSphereData.back(); |
76 | |
77 | sphereData.position = position; |
78 | sphereData.radius = radius; |
79 | sphereData.quality = quality; |
80 | sphereData.color = mColor; |
81 | sphereData.transform = mTransform; |
82 | sphereData.layer = mLayer; |
83 | sphereData.center = mTransform.multiplyAffine(position); |
84 | } |
85 | |
86 | void DrawHelper::wireCube(const Vector3& position, const Vector3& extents) |
87 | { |
88 | mWireCubeData.push_back(CubeData()); |
89 | CubeData& cubeData = mWireCubeData.back(); |
90 | |
91 | cubeData.position = position; |
92 | cubeData.extents = extents; |
93 | cubeData.color = mColor; |
94 | cubeData.transform = mTransform; |
95 | cubeData.layer = mLayer; |
96 | cubeData.center = mTransform.multiplyAffine(position); |
97 | } |
98 | |
99 | void DrawHelper::wireSphere(const Vector3& position, float radius, UINT32 quality) |
100 | { |
101 | mWireSphereData.push_back(SphereData()); |
102 | SphereData& sphereData = mWireSphereData.back(); |
103 | |
104 | sphereData.position = position; |
105 | sphereData.radius = radius; |
106 | sphereData.quality = quality; |
107 | sphereData.color = mColor; |
108 | sphereData.transform = mTransform; |
109 | sphereData.layer = mLayer; |
110 | sphereData.center = mTransform.multiplyAffine(position); |
111 | } |
112 | |
113 | void DrawHelper::wireHemisphere(const Vector3& position, float radius, UINT32 quality) |
114 | { |
115 | mWireHemisphereData.push_back(SphereData()); |
116 | SphereData& sphereData = mWireHemisphereData.back(); |
117 | |
118 | sphereData.position = position; |
119 | sphereData.radius = radius; |
120 | sphereData.quality = quality; |
121 | sphereData.color = mColor; |
122 | sphereData.transform = mTransform; |
123 | sphereData.layer = mLayer; |
124 | sphereData.center = mTransform.multiplyAffine(position); |
125 | } |
126 | |
127 | void DrawHelper::line(const Vector3& start, const Vector3& end) |
128 | { |
129 | mLineData.push_back(LineData()); |
130 | LineData& lineData = mLineData.back(); |
131 | |
132 | lineData.start = start; |
133 | lineData.end = end; |
134 | lineData.color = mColor; |
135 | lineData.transform = mTransform; |
136 | lineData.layer = mLayer; |
137 | lineData.center = mTransform.multiplyAffine((start + end) * 0.5f); |
138 | } |
139 | |
140 | void DrawHelper::lineList(const Vector<Vector3>& lines) |
141 | { |
142 | if (lines.size() < 2) |
143 | return; |
144 | |
145 | mLineListData.push_back(LineListData()); |
146 | LineListData& lineListData = mLineListData.back(); |
147 | |
148 | Vector3 center(BsZero); |
149 | for (auto& point : lines) |
150 | center += point; |
151 | |
152 | lineListData.lines = lines; |
153 | lineListData.color = mColor; |
154 | lineListData.transform = mTransform; |
155 | lineListData.layer = mLayer; |
156 | lineListData.center = center / (float)lines.size();; |
157 | } |
158 | |
159 | void DrawHelper::frustum(const Vector3& position, float aspect, Degree FOV, float near, float far) |
160 | { |
161 | mFrustumData.push_back(FrustumData()); |
162 | FrustumData& frustumData = mFrustumData.back(); |
163 | |
164 | frustumData.position = position; |
165 | frustumData.aspect = aspect; |
166 | frustumData.FOV = FOV; |
167 | frustumData.nearDist = near; |
168 | frustumData.farDist = far; |
169 | frustumData.color = mColor; |
170 | frustumData.transform = mTransform; |
171 | frustumData.layer = mLayer; |
172 | frustumData.center = mTransform.multiplyAffine(position); |
173 | } |
174 | |
175 | void DrawHelper::cone(const Vector3& base, const Vector3& normal, float height, float radius, const Vector2& scale, |
176 | UINT32 quality) |
177 | { |
178 | mConeData.push_back(ConeData()); |
179 | ConeData& coneData = mConeData.back(); |
180 | |
181 | coneData.base = base; |
182 | coneData.normal = normal; |
183 | coneData.height = height; |
184 | coneData.radius = radius; |
185 | coneData.scale = scale; |
186 | coneData.quality = quality; |
187 | coneData.color = mColor; |
188 | coneData.transform = mTransform; |
189 | coneData.layer = mLayer; |
190 | coneData.center = mTransform.multiplyAffine(base + normal * height * 0.5f); |
191 | } |
192 | |
193 | void DrawHelper::wireCone(const Vector3& base, const Vector3& normal, float height, float radius, const Vector2& scale, |
194 | UINT32 quality) |
195 | { |
196 | mWireConeData.push_back(ConeData()); |
197 | ConeData& coneData = mWireConeData.back(); |
198 | |
199 | coneData.base = base; |
200 | coneData.normal = normal; |
201 | coneData.height = height; |
202 | coneData.radius = radius; |
203 | coneData.scale = scale; |
204 | coneData.quality = quality; |
205 | coneData.color = mColor; |
206 | coneData.transform = mTransform; |
207 | coneData.layer = mLayer; |
208 | coneData.center = mTransform.multiplyAffine(base + normal * height * 0.5f); |
209 | } |
210 | |
211 | void DrawHelper::disc(const Vector3& position, const Vector3& normal, float radius, UINT32 quality) |
212 | { |
213 | mDiscData.push_back(DiscData()); |
214 | DiscData& discData = mDiscData.back(); |
215 | |
216 | discData.position = position; |
217 | discData.normal = normal; |
218 | discData.radius = radius; |
219 | discData.quality = quality; |
220 | discData.color = mColor; |
221 | discData.transform = mTransform; |
222 | discData.layer = mLayer; |
223 | discData.center = mTransform.multiplyAffine(position); |
224 | } |
225 | |
226 | void DrawHelper::wireDisc(const Vector3& position, const Vector3& normal, float radius, UINT32 quality) |
227 | { |
228 | mWireDiscData.push_back(DiscData()); |
229 | DiscData& discData = mWireDiscData.back(); |
230 | |
231 | discData.position = position; |
232 | discData.normal = normal; |
233 | discData.radius = radius; |
234 | discData.quality = quality; |
235 | discData.color = mColor; |
236 | discData.transform = mTransform; |
237 | discData.layer = mLayer; |
238 | discData.center = mTransform.multiplyAffine(position); |
239 | } |
240 | |
241 | void DrawHelper::arc(const Vector3& position, const Vector3& normal, float radius, |
242 | Degree startAngle, Degree amountAngle, UINT32 quality) |
243 | { |
244 | mArcData.push_back(ArcData()); |
245 | ArcData& arcData = mArcData.back(); |
246 | |
247 | arcData.position = position; |
248 | arcData.normal = normal; |
249 | arcData.radius = radius; |
250 | arcData.startAngle = startAngle; |
251 | arcData.amountAngle = amountAngle; |
252 | arcData.quality = quality; |
253 | arcData.color = mColor; |
254 | arcData.transform = mTransform; |
255 | arcData.layer = mLayer; |
256 | arcData.center = mTransform.multiplyAffine(position); |
257 | } |
258 | |
259 | void DrawHelper::wireArc(const Vector3& position, const Vector3& normal, float radius, |
260 | Degree startAngle, Degree amountAngle, UINT32 quality) |
261 | { |
262 | mWireArcData.push_back(ArcData()); |
263 | ArcData& arcData = mWireArcData.back(); |
264 | |
265 | arcData.position = position; |
266 | arcData.normal = normal; |
267 | arcData.radius = radius; |
268 | arcData.startAngle = startAngle; |
269 | arcData.amountAngle = amountAngle; |
270 | arcData.quality = quality; |
271 | arcData.color = mColor; |
272 | arcData.transform = mTransform; |
273 | arcData.layer = mLayer; |
274 | arcData.center = mTransform.multiplyAffine(position); |
275 | } |
276 | |
277 | void DrawHelper::rectangle(const Rect3& area) |
278 | { |
279 | mRect3Data.push_back(Rect3Data()); |
280 | Rect3Data& rectData = mRect3Data.back(); |
281 | |
282 | rectData.area = area; |
283 | rectData.color = mColor; |
284 | rectData.transform = mTransform; |
285 | rectData.layer = mLayer; |
286 | rectData.center = mTransform.multiplyAffine(area.getCenter()); |
287 | } |
288 | |
289 | void DrawHelper::text(const Vector3& position, const String& text, const HFont& font, UINT32 size) |
290 | { |
291 | if (!font.isLoaded() || text.empty()) |
292 | return; |
293 | |
294 | mText2DData.push_back(Text2DData()); |
295 | Text2DData& textData = mText2DData.back(); |
296 | |
297 | textData.position = position; |
298 | textData.color = mColor; |
299 | textData.transform = mTransform; |
300 | textData.layer = mLayer; |
301 | textData.center = mTransform.multiplyAffine(position); |
302 | textData.text = text; |
303 | textData.font = font; |
304 | textData.size = size; |
305 | } |
306 | |
307 | void DrawHelper::wireMesh(const SPtr<MeshData>& meshData) |
308 | { |
309 | if (meshData == nullptr) |
310 | return; |
311 | |
312 | mWireMeshData.push_back(WireMeshData()); |
313 | WireMeshData& wireMeshData = mWireMeshData.back(); |
314 | |
315 | wireMeshData.meshData = meshData; |
316 | wireMeshData.color = mColor; |
317 | wireMeshData.transform = mTransform; |
318 | wireMeshData.layer = mLayer; |
319 | wireMeshData.center = mTransform.multiplyAffine(Vector3::ZERO); |
320 | } |
321 | |
322 | void DrawHelper::clear() |
323 | { |
324 | mSolidCubeData.clear(); |
325 | mWireCubeData.clear(); |
326 | mSolidSphereData.clear(); |
327 | mWireSphereData.clear(); |
328 | mWireHemisphereData.clear(); |
329 | mLineData.clear(); |
330 | mLineListData.clear(); |
331 | mRect3Data.clear(); |
332 | mFrustumData.clear(); |
333 | mDiscData.clear(); |
334 | mWireDiscData.clear(); |
335 | mArcData.clear(); |
336 | mWireArcData.clear(); |
337 | mConeData.clear(); |
338 | mWireConeData.clear(); |
339 | mText2DData.clear(); |
340 | mWireMeshData.clear(); |
341 | } |
342 | |
343 | Vector<DrawHelper::ShapeMeshData> DrawHelper::buildMeshes(SortType sorting, const Camera* camera, UINT64 layers) |
344 | { |
345 | Vector<ShapeMeshData> meshInfos; |
346 | |
347 | enum class ShapeType |
348 | { |
349 | Cube, Sphere, WireCube, WireSphere, WireCone, Line, LineList, Frustum, |
350 | Cone, Disc, WireDisc, Arc, WireArc, Rectangle, Text, WireMesh, WireHemisphere |
351 | }; |
352 | |
353 | struct RawData |
354 | { |
355 | ShapeType shapeType; |
356 | MeshType meshType; |
357 | UINT32 idx; |
358 | UINT32 textIdx; |
359 | float distance; |
360 | UINT32 numVertices; |
361 | UINT32 numIndices; |
362 | }; |
363 | |
364 | /************************************************************************/ |
365 | /* Sort everything according to specified sorting rule */ |
366 | /************************************************************************/ |
367 | |
368 | UINT32 idx = 0; |
369 | Vector<RawData> allShapes; |
370 | Vector3 reference = Vector3::ZERO; |
371 | |
372 | if(camera) |
373 | reference = camera->getTransform().getPosition(); |
374 | |
375 | UINT32 localIdx = 0; |
376 | for (auto& shapeData : mSolidCubeData) |
377 | { |
378 | if ((shapeData.layer & layers) == 0) |
379 | { |
380 | localIdx++; |
381 | continue; |
382 | } |
383 | |
384 | allShapes.push_back(RawData()); |
385 | RawData& rawData = allShapes.back(); |
386 | |
387 | rawData.idx = localIdx++; |
388 | rawData.textIdx = 0; |
389 | rawData.meshType = MeshType::Solid; |
390 | rawData.shapeType = ShapeType::Cube; |
391 | rawData.distance = shapeData.center.distance(reference); |
392 | |
393 | ShapeMeshes3D::getNumElementsAABox(rawData.numVertices, rawData.numIndices); |
394 | } |
395 | |
396 | localIdx = 0; |
397 | for (auto& shapeData : mSolidSphereData) |
398 | { |
399 | if ((shapeData.layer & layers) == 0) |
400 | { |
401 | localIdx++; |
402 | continue; |
403 | } |
404 | |
405 | allShapes.push_back(RawData()); |
406 | RawData& rawData = allShapes.back(); |
407 | |
408 | rawData.idx = localIdx++; |
409 | rawData.textIdx = 0; |
410 | rawData.meshType = MeshType::Solid; |
411 | rawData.shapeType = ShapeType::Sphere; |
412 | rawData.distance = shapeData.center.distance(reference); |
413 | |
414 | ShapeMeshes3D::getNumElementsSphere(shapeData.quality, |
415 | rawData.numVertices, rawData.numIndices); |
416 | } |
417 | |
418 | localIdx = 0; |
419 | for (auto& shapeData : mConeData) |
420 | { |
421 | if ((shapeData.layer & layers) == 0) |
422 | { |
423 | localIdx++; |
424 | continue; |
425 | } |
426 | |
427 | allShapes.push_back(RawData()); |
428 | RawData& rawData = allShapes.back(); |
429 | |
430 | rawData.idx = localIdx++; |
431 | rawData.textIdx = 0; |
432 | rawData.meshType = MeshType::Solid; |
433 | rawData.shapeType = ShapeType::Cone; |
434 | rawData.distance = shapeData.center.distance(reference); |
435 | |
436 | ShapeMeshes3D::getNumElementsCone(shapeData.quality, |
437 | rawData.numVertices, rawData.numIndices); |
438 | } |
439 | |
440 | localIdx = 0; |
441 | for (auto& shapeData : mDiscData) |
442 | { |
443 | if ((shapeData.layer & layers) == 0) |
444 | { |
445 | localIdx++; |
446 | continue; |
447 | } |
448 | |
449 | allShapes.push_back(RawData()); |
450 | RawData& rawData = allShapes.back(); |
451 | |
452 | rawData.idx = localIdx++; |
453 | rawData.textIdx = 0; |
454 | rawData.meshType = MeshType::Solid; |
455 | rawData.shapeType = ShapeType::Disc; |
456 | rawData.distance = shapeData.center.distance(reference); |
457 | |
458 | ShapeMeshes3D::getNumElementsDisc(shapeData.quality, |
459 | rawData.numVertices, rawData.numIndices); |
460 | } |
461 | |
462 | localIdx = 0; |
463 | for (auto& shapeData : mArcData) |
464 | { |
465 | if ((shapeData.layer & layers) == 0) |
466 | { |
467 | localIdx++; |
468 | continue; |
469 | } |
470 | |
471 | allShapes.push_back(RawData()); |
472 | RawData& rawData = allShapes.back(); |
473 | |
474 | rawData.idx = localIdx++; |
475 | rawData.textIdx = 0; |
476 | rawData.meshType = MeshType::Solid; |
477 | rawData.shapeType = ShapeType::Arc; |
478 | rawData.distance = shapeData.center.distance(reference); |
479 | |
480 | ShapeMeshes3D::getNumElementsArc(shapeData.quality, |
481 | rawData.numVertices, rawData.numIndices); |
482 | } |
483 | |
484 | localIdx = 0; |
485 | for (auto& shapeData : mRect3Data) |
486 | { |
487 | if ((shapeData.layer & layers) == 0) |
488 | { |
489 | localIdx++; |
490 | continue; |
491 | } |
492 | |
493 | allShapes.push_back(RawData()); |
494 | RawData& rawData = allShapes.back(); |
495 | |
496 | rawData.idx = localIdx++; |
497 | rawData.textIdx = 0; |
498 | rawData.meshType = MeshType::Solid; |
499 | rawData.shapeType = ShapeType::Rectangle; |
500 | rawData.distance = shapeData.center.distance(reference); |
501 | |
502 | ShapeMeshes3D::getNumElementsQuad(rawData.numVertices, rawData.numIndices); |
503 | } |
504 | |
505 | localIdx = 0; |
506 | for (auto& shapeData : mWireCubeData) |
507 | { |
508 | if ((shapeData.layer & layers) == 0) |
509 | { |
510 | localIdx++; |
511 | continue; |
512 | } |
513 | |
514 | allShapes.push_back(RawData()); |
515 | RawData& rawData = allShapes.back(); |
516 | |
517 | rawData.idx = localIdx++; |
518 | rawData.textIdx = 0; |
519 | rawData.meshType = MeshType::Line; |
520 | rawData.shapeType = ShapeType::WireCube; |
521 | rawData.distance = shapeData.center.distance(reference); |
522 | |
523 | ShapeMeshes3D::getNumElementsWireAABox(rawData.numVertices, rawData.numIndices); |
524 | } |
525 | |
526 | localIdx = 0; |
527 | for (auto& shapeData : mWireSphereData) |
528 | { |
529 | if ((shapeData.layer & layers) == 0) |
530 | { |
531 | localIdx++; |
532 | continue; |
533 | } |
534 | |
535 | allShapes.push_back(RawData()); |
536 | RawData& rawData = allShapes.back(); |
537 | |
538 | rawData.idx = localIdx++; |
539 | rawData.textIdx = 0; |
540 | rawData.meshType = MeshType::Line; |
541 | rawData.shapeType = ShapeType::WireSphere; |
542 | rawData.distance = shapeData.center.distance(reference); |
543 | |
544 | ShapeMeshes3D::getNumElementsWireSphere(shapeData.quality, |
545 | rawData.numVertices, rawData.numIndices); |
546 | } |
547 | |
548 | localIdx = 0; |
549 | for (auto& shapeData : mWireHemisphereData) |
550 | { |
551 | if ((shapeData.layer & layers) == 0) |
552 | { |
553 | localIdx++; |
554 | continue; |
555 | } |
556 | |
557 | allShapes.push_back(RawData()); |
558 | RawData& rawData = allShapes.back(); |
559 | |
560 | rawData.idx = localIdx++; |
561 | rawData.textIdx = 0; |
562 | rawData.meshType = MeshType::Line; |
563 | rawData.shapeType = ShapeType::WireHemisphere; |
564 | rawData.distance = shapeData.center.distance(reference); |
565 | |
566 | ShapeMeshes3D::getNumElementsWireHemisphere(shapeData.quality, |
567 | rawData.numVertices, rawData.numIndices); |
568 | } |
569 | |
570 | localIdx = 0; |
571 | for (auto& shapeData : mWireConeData) |
572 | { |
573 | if ((shapeData.layer & layers) == 0) |
574 | { |
575 | localIdx++; |
576 | continue; |
577 | } |
578 | |
579 | allShapes.push_back(RawData()); |
580 | RawData& rawData = allShapes.back(); |
581 | |
582 | rawData.idx = localIdx++; |
583 | rawData.textIdx = 0; |
584 | rawData.meshType = MeshType::Line; |
585 | rawData.shapeType = ShapeType::WireCone; |
586 | rawData.distance = shapeData.center.distance(reference); |
587 | |
588 | ShapeMeshes3D::getNumElementsWireCone(shapeData.quality, |
589 | rawData.numVertices, rawData.numIndices); |
590 | } |
591 | |
592 | localIdx = 0; |
593 | for (auto& shapeData : mLineData) |
594 | { |
595 | if ((shapeData.layer & layers) == 0) |
596 | { |
597 | localIdx++; |
598 | continue; |
599 | } |
600 | |
601 | allShapes.push_back(RawData()); |
602 | RawData& rawData = allShapes.back(); |
603 | |
604 | rawData.idx = localIdx++; |
605 | rawData.textIdx = 0; |
606 | rawData.meshType = MeshType::Line; |
607 | rawData.shapeType = ShapeType::Line; |
608 | rawData.distance = shapeData.center.distance(reference); |
609 | rawData.numVertices = 2; |
610 | rawData.numIndices = 2; |
611 | } |
612 | |
613 | localIdx = 0; |
614 | for (auto& shapeData : mLineListData) |
615 | { |
616 | if ((shapeData.layer & layers) == 0) |
617 | { |
618 | localIdx++; |
619 | continue; |
620 | } |
621 | |
622 | allShapes.push_back(RawData()); |
623 | RawData& rawData = allShapes.back(); |
624 | |
625 | UINT32 numLines = (UINT32)shapeData.lines.size() / 2; |
626 | rawData.idx = localIdx++; |
627 | rawData.textIdx = 0; |
628 | rawData.meshType = MeshType::Line; |
629 | rawData.shapeType = ShapeType::LineList; |
630 | rawData.distance = shapeData.center.distance(reference); |
631 | rawData.numVertices = numLines * 2; |
632 | rawData.numIndices = numLines * 2; |
633 | } |
634 | |
635 | localIdx = 0; |
636 | for (auto& shapeData : mFrustumData) |
637 | { |
638 | if ((shapeData.layer & layers) == 0) |
639 | { |
640 | localIdx++; |
641 | continue; |
642 | } |
643 | |
644 | allShapes.push_back(RawData()); |
645 | RawData& rawData = allShapes.back(); |
646 | |
647 | rawData.idx = localIdx++; |
648 | rawData.textIdx = 0; |
649 | rawData.meshType = MeshType::Line; |
650 | rawData.shapeType = ShapeType::Frustum; |
651 | rawData.distance = shapeData.center.distance(reference); |
652 | |
653 | ShapeMeshes3D::getNumElementsFrustum(rawData.numVertices, rawData.numIndices); |
654 | } |
655 | |
656 | localIdx = 0; |
657 | for (auto& shapeData : mWireDiscData) |
658 | { |
659 | if ((shapeData.layer & layers) == 0) |
660 | { |
661 | localIdx++; |
662 | continue; |
663 | } |
664 | |
665 | allShapes.push_back(RawData()); |
666 | RawData& rawData = allShapes.back(); |
667 | |
668 | rawData.idx = localIdx++; |
669 | rawData.textIdx = 0; |
670 | rawData.meshType = MeshType::Line; |
671 | rawData.shapeType = ShapeType::WireDisc; |
672 | rawData.distance = shapeData.center.distance(reference); |
673 | |
674 | ShapeMeshes3D::getNumElementsWireDisc(shapeData.quality, |
675 | rawData.numVertices, rawData.numIndices); |
676 | } |
677 | |
678 | localIdx = 0; |
679 | for (auto& shapeData : mWireArcData) |
680 | { |
681 | if ((shapeData.layer & layers) == 0) |
682 | { |
683 | localIdx++; |
684 | continue; |
685 | } |
686 | |
687 | allShapes.push_back(RawData()); |
688 | RawData& rawData = allShapes.back(); |
689 | |
690 | rawData.idx = localIdx++; |
691 | rawData.textIdx = 0; |
692 | rawData.meshType = MeshType::Line; |
693 | rawData.shapeType = ShapeType::WireArc; |
694 | rawData.distance = shapeData.center.distance(reference); |
695 | |
696 | ShapeMeshes3D::getNumElementsWireArc(shapeData.quality, |
697 | rawData.numVertices, rawData.numIndices); |
698 | } |
699 | |
700 | localIdx = 0; |
701 | for (auto& shapeData : mWireMeshData) |
702 | { |
703 | if ((shapeData.layer & layers) == 0) |
704 | { |
705 | localIdx++; |
706 | continue; |
707 | } |
708 | |
709 | allShapes.push_back(RawData()); |
710 | RawData& rawData = allShapes.back(); |
711 | |
712 | rawData.idx = localIdx++; |
713 | rawData.textIdx = 0; |
714 | rawData.meshType = MeshType::Wire; |
715 | rawData.shapeType = ShapeType::WireMesh; |
716 | rawData.distance = shapeData.center.distance(reference); |
717 | rawData.numVertices = shapeData.meshData->getNumVertices(); |
718 | rawData.numIndices = shapeData.meshData->getNumIndices(); |
719 | } |
720 | |
721 | struct TextRenderData |
722 | { |
723 | UINT32 page; |
724 | SPtr<TextData<>> textData; |
725 | }; |
726 | |
727 | UnorderedMap<UINT32, TextRenderData> textRenderData; |
728 | UINT32 textIdx = 0; |
729 | |
730 | localIdx = 0; |
731 | for (auto& shapeData : mText2DData) |
732 | { |
733 | if ((shapeData.layer & layers) == 0) |
734 | { |
735 | localIdx++; |
736 | continue; |
737 | } |
738 | |
739 | U32String utf32text = UTF8::toUTF32(shapeData.text); |
740 | SPtr<TextData<>> textData = bs_shared_ptr_new<TextData<>>(utf32text, shapeData.font, shapeData.size); |
741 | |
742 | UINT32 numPages = textData->getNumPages(); |
743 | for (UINT32 j = 0; j < numPages; j++) |
744 | { |
745 | UINT32 numQuads = textData->getNumQuadsForPage(j); |
746 | |
747 | allShapes.push_back(RawData()); |
748 | RawData& rawData = allShapes.back(); |
749 | |
750 | rawData.idx = localIdx; |
751 | rawData.textIdx = textIdx; |
752 | rawData.meshType = MeshType::Text; |
753 | rawData.shapeType = ShapeType::Text; |
754 | rawData.distance = shapeData.center.distance(reference); |
755 | rawData.numVertices = numQuads * 4; |
756 | rawData.numIndices = numQuads * 6; |
757 | |
758 | TextRenderData& renderData = textRenderData[textIdx]; |
759 | renderData.page = j; |
760 | renderData.textData = textData; |
761 | |
762 | textIdx++; |
763 | idx++; |
764 | } |
765 | |
766 | localIdx++; |
767 | } |
768 | |
769 | if (sorting == SortType::FrontToBack) |
770 | { |
771 | std::sort(begin(allShapes), end(allShapes), |
772 | [&](const RawData& x, const RawData& y) |
773 | { |
774 | return x.distance < y.distance; |
775 | }); |
776 | } |
777 | else if (sorting == SortType::BackToFront) |
778 | { |
779 | std::sort(begin(allShapes), end(allShapes), |
780 | [&](const RawData& x, const RawData& y) |
781 | { |
782 | return y.distance < x.distance; |
783 | }); |
784 | } |
785 | |
786 | /************************************************************************/ |
787 | /* Create batches */ |
788 | /************************************************************************/ |
789 | struct Batch |
790 | { |
791 | MeshType type; |
792 | HTexture texture; |
793 | UINT32 startIdx; |
794 | UINT32 endIdx; |
795 | UINT32 numVertices; |
796 | UINT32 numIndices; |
797 | }; |
798 | |
799 | UINT32 numShapes = (UINT32)allShapes.size(); |
800 | |
801 | Vector<Batch> batches; |
802 | if (numShapes > 0) |
803 | { |
804 | batches.push_back(Batch()); |
805 | |
806 | { |
807 | Batch& currentBatch = batches.back(); |
808 | currentBatch.startIdx = 0; |
809 | currentBatch.type = allShapes[0].meshType; |
810 | currentBatch.numVertices = allShapes[0].numVertices; |
811 | currentBatch.numIndices = allShapes[0].numIndices; |
812 | |
813 | if (allShapes[0].meshType == MeshType::Text) |
814 | { |
815 | TextRenderData& renderData = textRenderData[allShapes[0].textIdx]; |
816 | currentBatch.texture = renderData.textData->getTextureForPage(renderData.page); |
817 | } |
818 | } |
819 | |
820 | for (UINT32 i = 1; i < numShapes; i++) |
821 | { |
822 | Batch& currentBatch = batches.back(); |
823 | |
824 | HTexture texture; |
825 | if (allShapes[i].meshType == MeshType::Text) |
826 | { |
827 | TextRenderData& renderData = textRenderData[allShapes[i].textIdx]; |
828 | texture = renderData.textData->getTextureForPage(renderData.page); |
829 | } |
830 | |
831 | bool startNewBatch = allShapes[i].meshType != currentBatch.type || texture != currentBatch.texture; |
832 | if (startNewBatch) |
833 | { |
834 | currentBatch.endIdx = i - 1; |
835 | |
836 | batches.push_back(Batch()); |
837 | |
838 | Batch& newBatch = batches.back(); |
839 | newBatch.startIdx = i; |
840 | newBatch.type = allShapes[i].meshType; |
841 | newBatch.numVertices = allShapes[i].numVertices; |
842 | newBatch.numIndices = allShapes[i].numIndices; |
843 | newBatch.texture = texture; |
844 | } |
845 | else |
846 | { |
847 | currentBatch.endIdx = i; |
848 | currentBatch.numVertices += allShapes[i].numVertices; |
849 | currentBatch.numIndices += allShapes[i].numIndices; |
850 | } |
851 | } |
852 | |
853 | { |
854 | Batch& currentBatch = batches.back(); |
855 | currentBatch.endIdx = numShapes - 1; |
856 | } |
857 | } |
858 | |
859 | // Allocate space for all the batch vertices/indices, per type |
860 | UINT32 vertexCount[4] = { 0, 0, 0, 0 }; |
861 | UINT32 indexCount[4] = { 0, 0, 0, 0 }; |
862 | for (auto& batch : batches) |
863 | { |
864 | UINT32 typeIdx = (UINT32)batch.type; |
865 | |
866 | vertexCount[typeIdx] += batch.numVertices; |
867 | indexCount[typeIdx] += batch.numIndices; |
868 | } |
869 | |
870 | SPtr<VertexDataDesc> vertexDesc[4] = { mSolidVertexDesc, mWireVertexDesc, mLineVertexDesc, mTextVertexDesc }; |
871 | SPtr<MeshData> meshData[4]; |
872 | for(UINT32 i = 0; i < 4; i++) |
873 | { |
874 | if(vertexCount[i] > 0 && indexCount[i] > 0) |
875 | meshData[i] = MeshData::create(vertexCount[i], indexCount[i], vertexDesc[i]); |
876 | } |
877 | |
878 | /************************************************************************/ |
879 | /* Generate geometry for each batch */ |
880 | /************************************************************************/ |
881 | UINT32 vertexOffset[4] = { 0, 0, 0, 0 }; |
882 | UINT32 indexOffset[4] = { 0, 0, 0, 0 }; |
883 | |
884 | VertexElemIter<Vector3> positionIter[4]; |
885 | VertexElemIter<UINT32> colorIter[4]; |
886 | |
887 | for(UINT32 i = 0; i < 4; i++) |
888 | { |
889 | if(!meshData[i]) |
890 | continue; |
891 | |
892 | positionIter[i] = meshData[i]->getVec3DataIter(VES_POSITION); |
893 | colorIter[i] = meshData[i]->getDWORDDataIter(VES_COLOR); |
894 | } |
895 | |
896 | VertexElemIter<Vector3> solidNormalIter; |
897 | if(meshData[0]) |
898 | solidNormalIter = meshData[0]->getVec3DataIter(VES_NORMAL); |
899 | |
900 | VertexElemIter<Vector2> textUVIter; |
901 | |
902 | if(meshData[3]) |
903 | textUVIter = meshData[3]->getVec2DataIter(VES_TEXCOORD); |
904 | |
905 | for (auto& batch : batches) |
906 | { |
907 | UINT32 typeIdx = (UINT32)batch.type; |
908 | |
909 | if (batch.type == MeshType::Solid) |
910 | { |
911 | meshInfos.push_back(ShapeMeshData()); |
912 | ShapeMeshData& newMesh = meshInfos.back(); |
913 | newMesh.subMesh.indexOffset = indexOffset[typeIdx]; |
914 | newMesh.subMesh.indexCount = batch.numIndices; |
915 | newMesh.subMesh.drawOp = DOT_TRIANGLE_LIST; |
916 | newMesh.type = MeshType::Solid; |
917 | |
918 | for (UINT32 i = batch.startIdx; i <= batch.endIdx; i++) |
919 | { |
920 | RawData& shapeData = allShapes[i]; |
921 | |
922 | Matrix4* transform = nullptr; |
923 | RGBA color = 0; |
924 | |
925 | switch (shapeData.shapeType) |
926 | { |
927 | case ShapeType::Cube: |
928 | { |
929 | CubeData& cubeData = mSolidCubeData[shapeData.idx]; |
930 | AABox box(cubeData.position - cubeData.extents, cubeData.position + cubeData.extents); |
931 | ShapeMeshes3D::solidAABox(box, meshData[typeIdx], vertexOffset[typeIdx], indexOffset[typeIdx]); |
932 | |
933 | transform = &cubeData.transform; |
934 | color = cubeData.color.getAsRGBA(); |
935 | } |
936 | break; |
937 | case ShapeType::Sphere: |
938 | { |
939 | SphereData& sphereData = mSolidSphereData[shapeData.idx]; |
940 | Sphere sphere(sphereData.position, sphereData.radius); |
941 | ShapeMeshes3D::solidSphere(sphere, meshData[typeIdx], vertexOffset[typeIdx], indexOffset[typeIdx], |
942 | sphereData.quality); |
943 | |
944 | transform = &sphereData.transform; |
945 | color = sphereData.color.getAsRGBA(); |
946 | } |
947 | break; |
948 | case ShapeType::Cone: |
949 | { |
950 | ConeData& coneData = mConeData[shapeData.idx]; |
951 | ShapeMeshes3D::solidCone(coneData.base, coneData.normal, coneData.height, coneData.radius, |
952 | coneData.scale, meshData[typeIdx], vertexOffset[typeIdx], indexOffset[typeIdx], coneData.quality); |
953 | |
954 | transform = &coneData.transform; |
955 | color = coneData.color.getAsRGBA(); |
956 | } |
957 | break; |
958 | case ShapeType::Disc: |
959 | { |
960 | DiscData& discData = mDiscData[shapeData.idx]; |
961 | ShapeMeshes3D::solidDisc(discData.position, discData.radius, discData.normal, |
962 | meshData[typeIdx], vertexOffset[typeIdx], indexOffset[typeIdx], discData.quality); |
963 | |
964 | transform = &discData.transform; |
965 | color = discData.color.getAsRGBA(); |
966 | } |
967 | break; |
968 | case ShapeType::Arc: |
969 | { |
970 | ArcData& arcData = mArcData[shapeData.idx]; |
971 | ShapeMeshes3D::solidArc(arcData.position, arcData.radius, arcData.normal, |
972 | arcData.startAngle, arcData.amountAngle, meshData[typeIdx], vertexOffset[typeIdx], |
973 | indexOffset[typeIdx], arcData.quality); |
974 | |
975 | transform = &arcData.transform; |
976 | color = arcData.color.getAsRGBA(); |
977 | } |
978 | break; |
979 | case ShapeType::Rectangle: |
980 | { |
981 | Rect3Data& rectData = mRect3Data[shapeData.idx]; |
982 | ShapeMeshes3D::solidQuad(rectData.area, meshData[typeIdx], vertexOffset[typeIdx], |
983 | indexOffset[typeIdx]); |
984 | |
985 | transform = &rectData.transform; |
986 | color = rectData.color.getAsRGBA(); |
987 | } |
988 | break; |
989 | default: |
990 | break; |
991 | } |
992 | |
993 | Matrix4 transformIT = transform->inverseAffine().transpose(); |
994 | for (UINT32 i = 0; i < shapeData.numVertices; i++) |
995 | { |
996 | Vector3 worldPos = transform->multiplyAffine(positionIter[typeIdx].getValue()); |
997 | Vector3 worldNormal = transformIT.multiplyAffine(solidNormalIter.getValue()); |
998 | |
999 | positionIter[typeIdx].addValue(worldPos); |
1000 | solidNormalIter.addValue(worldNormal); |
1001 | colorIter[typeIdx].addValue(color); |
1002 | } |
1003 | |
1004 | vertexOffset[typeIdx] += shapeData.numVertices; |
1005 | indexOffset[typeIdx] += shapeData.numIndices; |
1006 | } |
1007 | } |
1008 | else if (batch.type == MeshType::Wire) |
1009 | { |
1010 | meshInfos.push_back(ShapeMeshData()); |
1011 | ShapeMeshData& newMesh = meshInfos.back(); |
1012 | newMesh.subMesh.indexOffset = indexOffset[typeIdx]; |
1013 | newMesh.subMesh.indexCount = batch.numIndices; |
1014 | newMesh.subMesh.drawOp = DOT_TRIANGLE_LIST; |
1015 | newMesh.type = MeshType::Wire; |
1016 | |
1017 | for (UINT32 i = batch.startIdx; i <= batch.endIdx; i++) |
1018 | { |
1019 | RawData& shapeData = allShapes[i]; |
1020 | |
1021 | Matrix4* transform = nullptr; |
1022 | RGBA color = 0; |
1023 | |
1024 | switch (shapeData.shapeType) |
1025 | { |
1026 | case ShapeType::WireMesh: |
1027 | { |
1028 | WireMeshData& wireMeshData = mWireMeshData[shapeData.idx]; |
1029 | |
1030 | transform = &wireMeshData.transform; |
1031 | color = wireMeshData.color.getAsRGBA(); |
1032 | |
1033 | auto vertIterRead = wireMeshData.meshData->getVec3DataIter(VES_POSITION); |
1034 | for (UINT32 j = 0; j < vertIterRead.getNumElements(); j++) |
1035 | { |
1036 | Vector3 worldPos = transform->multiplyAffine(vertIterRead.getValue()); |
1037 | |
1038 | positionIter[typeIdx].addValue(worldPos); |
1039 | colorIter[typeIdx].addValue(color); |
1040 | |
1041 | vertIterRead.moveNext(); |
1042 | } |
1043 | |
1044 | UINT32* srcIndexData = wireMeshData.meshData->getIndices32(); |
1045 | UINT32* destIndexData = meshData[typeIdx]->getIndices32() + indexOffset[typeIdx]; |
1046 | |
1047 | for(UINT32 j = 0; j < shapeData.numIndices; j++) |
1048 | destIndexData[j] = srcIndexData[j] + vertexOffset[typeIdx]; |
1049 | |
1050 | vertexOffset[typeIdx] += shapeData.numVertices; |
1051 | indexOffset[typeIdx] += shapeData.numIndices; |
1052 | } |
1053 | break; |
1054 | default: |
1055 | break; |
1056 | } |
1057 | } |
1058 | } |
1059 | else if(batch.type == MeshType::Line) |
1060 | { |
1061 | meshInfos.push_back(ShapeMeshData()); |
1062 | ShapeMeshData& newMesh = meshInfos.back(); |
1063 | newMesh.subMesh.indexOffset = indexOffset[typeIdx]; |
1064 | newMesh.subMesh.indexCount = batch.numIndices; |
1065 | newMesh.subMesh.drawOp = DOT_LINE_LIST; |
1066 | newMesh.type = MeshType::Line; |
1067 | |
1068 | for (UINT32 i = batch.startIdx; i <= batch.endIdx; i++) |
1069 | { |
1070 | RawData& shapeData = allShapes[i]; |
1071 | |
1072 | Matrix4* transform = nullptr; |
1073 | RGBA color = 0; |
1074 | |
1075 | switch (shapeData.shapeType) |
1076 | { |
1077 | case ShapeType::WireCube: |
1078 | { |
1079 | CubeData& cubeData = mWireCubeData[shapeData.idx]; |
1080 | |
1081 | AABox box(cubeData.position - cubeData.extents, cubeData.position + cubeData.extents); |
1082 | ShapeMeshes3D::wireAABox(box, meshData[typeIdx], vertexOffset[typeIdx], indexOffset[typeIdx]); |
1083 | |
1084 | transform = &cubeData.transform; |
1085 | color = cubeData.color.getAsRGBA(); |
1086 | } |
1087 | break; |
1088 | case ShapeType::WireSphere: |
1089 | { |
1090 | SphereData& sphereData = mWireSphereData[shapeData.idx]; |
1091 | |
1092 | Sphere sphere(sphereData.position, sphereData.radius); |
1093 | ShapeMeshes3D::wireSphere(sphere, meshData[typeIdx], vertexOffset[typeIdx], indexOffset[typeIdx], |
1094 | sphereData.quality); |
1095 | |
1096 | transform = &sphereData.transform; |
1097 | color = sphereData.color.getAsRGBA(); |
1098 | } |
1099 | break; |
1100 | case ShapeType::WireHemisphere: |
1101 | { |
1102 | SphereData& sphereData = mWireHemisphereData[shapeData.idx]; |
1103 | |
1104 | Sphere sphere(sphereData.position, sphereData.radius); |
1105 | ShapeMeshes3D::wireHemisphere(sphere, meshData[typeIdx], vertexOffset[typeIdx], indexOffset[typeIdx], |
1106 | sphereData.quality); |
1107 | |
1108 | transform = &sphereData.transform; |
1109 | color = sphereData.color.getAsRGBA(); |
1110 | } |
1111 | break; |
1112 | case ShapeType::WireCone: |
1113 | { |
1114 | ConeData& coneData = mWireConeData[shapeData.idx]; |
1115 | ShapeMeshes3D::wireCone(coneData.base, coneData.normal, coneData.height, coneData.radius, |
1116 | coneData.scale, meshData[typeIdx], vertexOffset[typeIdx], indexOffset[typeIdx], |
1117 | coneData.quality); |
1118 | |
1119 | transform = &coneData.transform; |
1120 | color = coneData.color.getAsRGBA(); |
1121 | } |
1122 | break; |
1123 | case ShapeType::Line: |
1124 | { |
1125 | LineData& lineData = mLineData[shapeData.idx]; |
1126 | |
1127 | ShapeMeshes3D::pixelLine(lineData.start, lineData.end, meshData[typeIdx], vertexOffset[typeIdx], |
1128 | indexOffset[typeIdx]); |
1129 | |
1130 | transform = &lineData.transform; |
1131 | color = lineData.color.getAsRGBA(); |
1132 | } |
1133 | break; |
1134 | case ShapeType::LineList: |
1135 | { |
1136 | LineListData& lineListData = mLineListData[shapeData.idx]; |
1137 | |
1138 | ShapeMeshes3D::pixelLineList(lineListData.lines, meshData[typeIdx], vertexOffset[typeIdx], |
1139 | indexOffset[typeIdx]); |
1140 | |
1141 | transform = &lineListData.transform; |
1142 | color = lineListData.color.getAsRGBA(); |
1143 | } |
1144 | break; |
1145 | case ShapeType::Frustum: |
1146 | { |
1147 | FrustumData& frustumData = mFrustumData[shapeData.idx]; |
1148 | |
1149 | ShapeMeshes3D::wireFrustum(frustumData.position, frustumData.aspect, frustumData.FOV, frustumData.nearDist, |
1150 | frustumData.farDist, meshData[typeIdx], vertexOffset[typeIdx], indexOffset[typeIdx]); |
1151 | |
1152 | transform = &frustumData.transform; |
1153 | color = frustumData.color.getAsRGBA(); |
1154 | } |
1155 | break; |
1156 | case ShapeType::WireDisc: |
1157 | { |
1158 | DiscData& discData = mWireDiscData[shapeData.idx]; |
1159 | |
1160 | ShapeMeshes3D::wireDisc(discData.position, discData.radius, discData.normal, |
1161 | meshData[typeIdx], vertexOffset[typeIdx], indexOffset[typeIdx], discData.quality); |
1162 | |
1163 | transform = &discData.transform; |
1164 | color = discData.color.getAsRGBA(); |
1165 | } |
1166 | break; |
1167 | case ShapeType::WireArc: |
1168 | { |
1169 | ArcData& arcData = mWireArcData[shapeData.idx]; |
1170 | |
1171 | ShapeMeshes3D::wireArc(arcData.position, arcData.radius, arcData.normal, |
1172 | arcData.startAngle, arcData.amountAngle, meshData[typeIdx], vertexOffset[typeIdx], |
1173 | indexOffset[typeIdx], arcData.quality); |
1174 | |
1175 | transform = &arcData.transform; |
1176 | color = arcData.color.getAsRGBA(); |
1177 | } |
1178 | break; |
1179 | default: |
1180 | break; |
1181 | } |
1182 | |
1183 | for (UINT32 i = 0; i < shapeData.numVertices; i++) |
1184 | { |
1185 | Vector3 worldPos = transform->multiplyAffine(positionIter[typeIdx].getValue()); |
1186 | |
1187 | positionIter[typeIdx].addValue(worldPos); |
1188 | colorIter[typeIdx].addValue(color); |
1189 | } |
1190 | |
1191 | vertexOffset[typeIdx] += shapeData.numVertices; |
1192 | indexOffset[typeIdx] += shapeData.numIndices; |
1193 | } |
1194 | } |
1195 | else // Text |
1196 | { |
1197 | // Text drawing requires a camera in order to determine screen space coordinates |
1198 | if(!camera) |
1199 | continue; |
1200 | |
1201 | meshInfos.push_back(ShapeMeshData()); |
1202 | ShapeMeshData& newMesh = meshInfos.back(); |
1203 | newMesh.subMesh.indexOffset = indexOffset[typeIdx]; |
1204 | newMesh.subMesh.indexCount = batch.numIndices; |
1205 | newMesh.subMesh.drawOp = DOT_TRIANGLE_LIST; |
1206 | newMesh.type = MeshType::Text; |
1207 | newMesh.texture = batch.texture; |
1208 | |
1209 | for (UINT32 i = batch.startIdx; i <= batch.endIdx; i++) |
1210 | { |
1211 | RawData& shapeData = allShapes[i]; |
1212 | Text2DData& text2DData = mText2DData[shapeData.idx]; |
1213 | |
1214 | TextRenderData& renderData = textRenderData[shapeData.textIdx]; |
1215 | UINT32 numQuads = renderData.textData->getNumQuadsForPage(renderData.page); |
1216 | |
1217 | UINT32* indices = meshData[typeIdx]->getIndices32() + indexOffset[typeIdx]; |
1218 | |
1219 | // Note: Need temporary buffers because TextLine doesn't support arbitrary vertex stride. Eventually |
1220 | // that should be supported (should be almost trivial to implement) |
1221 | Vector2* tempVertices = bs_stack_alloc<Vector2>(shapeData.numVertices); |
1222 | Vector2* tempUVs = bs_stack_alloc<Vector2>(shapeData.numVertices); |
1223 | |
1224 | UINT32 numLines = renderData.textData->getNumLines(); |
1225 | UINT32 quadOffset = 0; |
1226 | for (UINT32 j = 0; j < numLines; j++) |
1227 | { |
1228 | const TextDataBase::TextLine& line = renderData.textData->getLine(j); |
1229 | UINT32 writtenQuads = line.fillBuffer(renderData.page, tempVertices, tempUVs, indices, quadOffset, numQuads); |
1230 | |
1231 | quadOffset += writtenQuads; |
1232 | } |
1233 | |
1234 | for(UINT32 j = 0; j < shapeData.numIndices; j++) |
1235 | indices[j] += vertexOffset[typeIdx]; |
1236 | |
1237 | Vector3 worldSpacePos = text2DData.transform.multiplyAffine(text2DData.position); |
1238 | Vector2I screenPos = camera->worldToScreenPoint(worldSpacePos); |
1239 | screenPos.x -= renderData.textData->getWidth() / 2; |
1240 | screenPos.y -= renderData.textData->getHeight() / 2; |
1241 | |
1242 | float z = camera->projectPoint(camera->worldToViewPoint(worldSpacePos)).z; |
1243 | |
1244 | for (UINT32 j = 0; j < shapeData.numVertices; j++) |
1245 | { |
1246 | Vector3 vertexPos(screenPos.x + tempVertices[j].x, screenPos.y + tempVertices[j].y, z); |
1247 | |
1248 | positionIter[typeIdx].addValue(vertexPos); |
1249 | textUVIter.addValue(tempUVs[j]); |
1250 | colorIter[typeIdx].addValue(text2DData.color.getAsRGBA()); |
1251 | } |
1252 | |
1253 | bs_stack_free(tempUVs); |
1254 | bs_stack_free(tempVertices); |
1255 | |
1256 | vertexOffset[typeIdx] += shapeData.numVertices; |
1257 | indexOffset[typeIdx] += shapeData.numIndices; |
1258 | } |
1259 | } |
1260 | } |
1261 | |
1262 | SPtr<Mesh> meshes[4]; |
1263 | for(UINT32 i = 0; i < 4; i++) |
1264 | { |
1265 | if(meshData[i]) |
1266 | meshes[i] = Mesh::_createPtr(meshData[i]); |
1267 | } |
1268 | |
1269 | for(auto& entry : meshInfos) |
1270 | { |
1271 | switch(entry.type) |
1272 | { |
1273 | case MeshType::Solid: |
1274 | entry.mesh = meshes[0]; |
1275 | break; |
1276 | case MeshType::Wire: |
1277 | entry.mesh = meshes[1]; |
1278 | break; |
1279 | case MeshType::Line: |
1280 | entry.mesh = meshes[2]; |
1281 | break; |
1282 | case MeshType::Text: |
1283 | entry.mesh = meshes[3]; |
1284 | break; |
1285 | default: ; |
1286 | } |
1287 | } |
1288 | |
1289 | return meshInfos; |
1290 | } |
1291 | } |
1292 | |