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/BsShapeMeshes2D.h"
4#include "Math/BsRect2.h"
5#include "Mesh/BsMesh.h"
6#include "Math/BsVector2.h"
7#include "Math/BsLine2.h"
8#include "Material/BsPass.h"
9#include "RenderAPI/BsVertexDataDesc.h"
10
11namespace bs
12{
13 const UINT32 ShapeMeshes2D::NUM_VERTICES_AA_LINE = 4;
14 const UINT32 ShapeMeshes2D::NUM_INDICES_AA_LINE = 6;
15
16 void ShapeMeshes2D::solidQuad(const Rect2& area, const SPtr<MeshData>& meshData, UINT32 vertexOffset, UINT32 indexOffset)
17 {
18 UINT32* indexData = meshData->getIndices32();
19 UINT8* positionData = meshData->getElementData(VES_POSITION);
20
21 assert((vertexOffset + 4) <= meshData->getNumVertices());
22 assert((indexOffset + 6) <= meshData->getNumIndices());
23
24 Vector<Vector2> points;
25 points.push_back(Vector2(area.x, area.y));
26 points.push_back(Vector2(area.x + area.width, area.y));
27 points.push_back(Vector2(area.x + area.width, area.y + area.height));
28 points.push_back(Vector2(area.x, area.y + area.height));
29
30 pixelSolidPolygon(points, positionData, vertexOffset, meshData->getVertexDesc()->getVertexStride(), indexData, indexOffset);
31 }
32
33 void ShapeMeshes2D::pixelLine(const Vector2& a, const Vector2& b, const SPtr<MeshData>& meshData, UINT32 vertexOffset, UINT32 indexOffset)
34 {
35 UINT32* indexData = meshData->getIndices32();
36 UINT8* positionData = meshData->getElementData(VES_POSITION);
37
38 assert((vertexOffset + 2) <= meshData->getNumVertices());
39 assert((indexOffset + 2) <= meshData->getNumIndices());
40
41 pixelLine(a, b, positionData, vertexOffset, meshData->getVertexDesc()->getVertexStride(), indexData, indexOffset);
42 }
43
44 void ShapeMeshes2D::quadLine(const Vector2& a, const Vector2& b, float width, float border, const Color& color,
45 const SPtr<MeshData>& meshData, UINT32 vertexOffset, UINT32 indexOffset)
46 {
47 Vector<Vector2> linePoints = { a, b };
48 quadLineList(linePoints, width, border, color, meshData, vertexOffset, indexOffset);
49 }
50
51 void ShapeMeshes2D::pixelLineList(const Vector<Vector2>& linePoints, const SPtr<MeshData>& meshData, UINT32 vertexOffset, UINT32 indexOffset)
52 {
53 assert(linePoints.size() % 2 == 0);
54
55 assert((vertexOffset + linePoints.size() * 2) <= meshData->getNumVertices());
56 assert((indexOffset + linePoints.size() * 2) <= meshData->getNumIndices());
57
58 UINT32 curVertOffset = vertexOffset;
59 UINT32 curIdxOffset = indexOffset;
60
61 UINT32* indexData = meshData->getIndices32();
62 UINT8* positionData = meshData->getElementData(VES_POSITION);
63
64 UINT32 numPoints = (UINT32)linePoints.size();
65 for(UINT32 i = 0; i < numPoints; i += 2)
66 {
67 pixelLine(linePoints[i], linePoints[i + 1], positionData, curVertOffset, meshData->getVertexDesc()->getVertexStride(), indexData, curIdxOffset);
68
69 curVertOffset += 2;
70 curIdxOffset += 2;
71 }
72 }
73
74 void ShapeMeshes2D::quadLineList(const Vector<Vector2>& linePoints, float width, float border, const Color& color,
75 const SPtr<MeshData>& meshData, UINT32 vertexOffset, UINT32 indexOffset)
76 {
77 UINT32 numPoints = (UINT32)linePoints.size();
78 assert(numPoints >= 2);
79
80 UINT32 numLines = (UINT32)linePoints.size() - 1;
81 assert((vertexOffset + (numLines * 2 + 2)) <= meshData->getNumVertices());
82 assert((indexOffset + (numLines * 6)) <= meshData->getNumIndices());
83
84 UINT32* outIndices = indexOffset + meshData->getIndices32();
85 UINT8* outVertices = vertexOffset + meshData->getElementData(VES_POSITION);
86 UINT8* outColors = vertexOffset + meshData->getElementData(VES_COLOR);
87
88 UINT32 vertexStride = meshData->getVertexDesc()->getVertexStride();
89 quadLineList(&linePoints[0], numPoints, width, border, outVertices, vertexStride, true);
90
91 RGBA colorValue = color.getAsRGBA();
92
93 // Colors and indices
94 for(UINT32 i = 0; i < numLines; i++)
95 {
96 memcpy(outColors, &colorValue, sizeof(colorValue));
97 outColors += vertexStride;
98
99 memcpy(outColors, &colorValue, sizeof(colorValue));
100 outColors += vertexStride;
101
102 UINT32 idxStart = i * 6;
103 outIndices[idxStart + 0] = vertexOffset + idxStart + 0;
104 outIndices[idxStart + 1] = vertexOffset + idxStart + 1;
105 outIndices[idxStart + 2] = vertexOffset + idxStart + 2;
106
107 outIndices[idxStart + 3] = vertexOffset + idxStart + 1;
108 outIndices[idxStart + 4] = vertexOffset + idxStart + 3;
109 outIndices[idxStart + 5] = vertexOffset + idxStart + 2;
110 }
111
112 memcpy(outColors, &colorValue, sizeof(colorValue));
113 outColors += vertexStride;
114
115 memcpy(outColors, &colorValue, sizeof(colorValue));
116 outColors += vertexStride;
117 }
118
119 void ShapeMeshes2D::quadLineList(const Vector2* linePoints, UINT32 numPoints, float width, float border, UINT8* outVertices,
120 UINT32 vertexStride, bool indexed)
121 {
122 assert(numPoints >= 2);
123 UINT32 numLines = numPoints - 1;
124
125 width += border;
126
127 Vector2 prevPoints[2];
128
129 // Start segment
130 {
131 Vector2 a = linePoints[0];
132 Vector2 b = linePoints[1];
133
134 Vector2 diff = b - a;
135 diff.normalize();
136
137 // Flip 90 degrees
138 Vector2 normal(diff.y, -diff.x);
139
140 prevPoints[0] = a - normal * width - diff * border;
141 prevPoints[1] = a + normal * width - diff * border;
142
143 memcpy(outVertices, &prevPoints[0], sizeof(prevPoints[0]));
144 outVertices += vertexStride;
145
146 memcpy(outVertices, &prevPoints[1], sizeof(prevPoints[1]));
147 outVertices += vertexStride;
148 }
149
150 // Middle segments
151 {
152 for (UINT32 i = 1; i < numLines; i++)
153 {
154 Vector2 a = linePoints[i - 1];
155 Vector2 b = linePoints[i];
156 Vector2 c = linePoints[i + 1];
157
158 Vector2 diffPrev = b - a;
159 diffPrev.normalize();
160
161 Vector2 diffNext = c - b;
162 diffNext.normalize();
163
164 // Flip 90 degrees
165 Vector2 normalPrev(diffPrev.y, -diffPrev.x);
166 Vector2 normalNext(diffNext.y, -diffNext.x);
167
168 Vector2 curPoints[2];
169
170 const float sign[] = { -1.0f, 1.0f };
171 for (UINT32 j = 0; j < 2; j++)
172 {
173 Vector2 linePrevPoint = a + normalPrev * width * sign[j];
174 Line2 linePrev(linePrevPoint, diffPrev);
175
176 Vector2 lineNextPoint = b + normalNext * width * sign[j];
177 Line2 lineNext(lineNextPoint, diffNext);
178
179 auto intersect = linePrev.intersects(lineNext);
180 if (intersect.second != 0.0f) // Not parallel
181 curPoints[j] = linePrev.getPoint(intersect.second);
182 else
183 curPoints[j] = lineNextPoint;
184
185 memcpy(outVertices, &curPoints[j], sizeof(curPoints[j]));
186 outVertices += vertexStride;
187 }
188
189 if (!indexed)
190 {
191 memcpy(outVertices, &curPoints[0], sizeof(curPoints[0]));
192 outVertices += vertexStride;
193
194 memcpy(outVertices, &prevPoints[1], sizeof(prevPoints[1]));
195 outVertices += vertexStride;
196
197 memcpy(outVertices, &curPoints[0], sizeof(curPoints[0]));
198 outVertices += vertexStride;
199
200 memcpy(outVertices, &curPoints[1], sizeof(curPoints[1]));
201 outVertices += vertexStride;
202
203 prevPoints[0] = curPoints[0];
204 prevPoints[1] = curPoints[1];
205 }
206 }
207 }
208
209 // End segment
210 {
211 Vector2 a = linePoints[numPoints - 2];
212 Vector2 b = linePoints[numPoints - 1];
213
214 Vector2 diff = b - a;
215 diff.normalize();
216
217 // Flip 90 degrees
218 Vector2 normal(diff.y, -diff.x);
219
220 Vector2 curPoints[2];
221 curPoints[0] = b - normal * width + diff * border;
222 curPoints[1] = b + normal * width + diff * border;
223
224 memcpy(outVertices, &curPoints[0], sizeof(curPoints[0]));
225 outVertices += vertexStride;
226
227 memcpy(outVertices, &curPoints[1], sizeof(curPoints[1]));
228 outVertices += vertexStride;
229
230 if (!indexed)
231 {
232 memcpy(outVertices, &curPoints[0], sizeof(curPoints[0]));
233 outVertices += vertexStride;
234
235 memcpy(outVertices, &prevPoints[1], sizeof(prevPoints[1]));
236 outVertices += vertexStride;
237 }
238 }
239 }
240
241 void ShapeMeshes2D::pixelSolidPolygon(const Vector<Vector2>& points, UINT8* outVertices,
242 UINT32 vertexOffset, UINT32 vertexStride, UINT32* outIndices, UINT32 indexOffset)
243 {
244 outVertices += (vertexOffset * vertexStride);
245
246 for (auto& point : points)
247 {
248 Vector2* vertices = (Vector2*)outVertices;
249 (*vertices) = point;
250
251 outVertices += vertexStride;
252 }
253
254 outIndices += indexOffset;
255 INT32 numPoints = (INT32)points.size();
256 UINT32 idxCnt = 0;
257 for (int i = 2; i < numPoints; i++)
258 {
259 outIndices[idxCnt++] = vertexOffset;
260 outIndices[idxCnt++] = vertexOffset + i - 1;
261 outIndices[idxCnt++] = vertexOffset + i;
262 }
263 }
264
265 void ShapeMeshes2D::pixelLine(const Vector2& a, const Vector2& b, UINT8* outVertices,
266 UINT32 vertexOffset, UINT32 vertexStride, UINT32* outIndices, UINT32 indexOffset)
267 {
268 outVertices += (vertexOffset * vertexStride);
269
270 Vector2* vertices = (Vector2*)outVertices;
271 (*vertices) = a;
272
273 vertices = (Vector2*)(outVertices + vertexStride);
274 (*vertices) = b;
275
276 outIndices += indexOffset;
277 outIndices[0] = vertexOffset + 0;
278 outIndices[1] = vertexOffset + 1;
279 }
280}