1 | /** |
2 | * Copyright (c) 2006-2023 LOVE Development Team |
3 | * |
4 | * This software is provided 'as-is', without any express or implied |
5 | * warranty. In no event will the authors be held liable for any damages |
6 | * arising from the use of this software. |
7 | * |
8 | * Permission is granted to anyone to use this software for any purpose, |
9 | * including commercial applications, and to alter it and redistribute it |
10 | * freely, subject to the following restrictions: |
11 | * |
12 | * 1. The origin of this software must not be misrepresented; you must not |
13 | * claim that you wrote the original software. If you use this software |
14 | * in a product, an acknowledgment in the product documentation would be |
15 | * appreciated but is not required. |
16 | * 2. Altered source versions must be plainly marked as such, and must not be |
17 | * misrepresented as being the original software. |
18 | * 3. This notice may not be removed or altered from any source distribution. |
19 | **/ |
20 | |
21 | #include "vertex.h" |
22 | #include "common/StringMap.h" |
23 | |
24 | namespace love |
25 | { |
26 | namespace graphics |
27 | { |
28 | namespace vertex |
29 | { |
30 | |
31 | static_assert(sizeof(Color32) == 4, "sizeof(Color32) incorrect!" ); |
32 | static_assert(sizeof(STf_RGBAub) == sizeof(float)*2 + sizeof(Color32), "sizeof(STf_RGBAub) incorrect!" ); |
33 | static_assert(sizeof(STPf_RGBAub) == sizeof(float)*3 + sizeof(Color32), "sizeof(STPf_RGBAub) incorrect!" ); |
34 | static_assert(sizeof(XYf_STf) == sizeof(float)*2 + sizeof(float)*2, "sizeof(XYf_STf) incorrect!" ); |
35 | static_assert(sizeof(XYf_STPf) == sizeof(float)*2 + sizeof(float)*3, "sizeof(XYf_STPf) incorrect!" ); |
36 | static_assert(sizeof(XYf_STf_RGBAub) == sizeof(float)*2 + sizeof(float)*2 + sizeof(Color32), "sizeof(XYf_STf_RGBAub) incorrect!" ); |
37 | static_assert(sizeof(XYf_STus_RGBAub) == sizeof(float)*2 + sizeof(uint16)*2 + sizeof(Color32), "sizeof(XYf_STus_RGBAub) incorrect!" ); |
38 | static_assert(sizeof(XYf_STPf_RGBAub) == sizeof(float)*2 + sizeof(float)*3 + sizeof(Color32), "sizeof(XYf_STPf_RGBAub) incorrect!" ); |
39 | |
40 | size_t getFormatStride(CommonFormat format) |
41 | { |
42 | switch (format) |
43 | { |
44 | case CommonFormat::NONE: |
45 | return 0; |
46 | case CommonFormat::XYf: |
47 | return sizeof(float) * 2; |
48 | case CommonFormat::XYZf: |
49 | return sizeof(float) * 3; |
50 | case CommonFormat::RGBAub: |
51 | return sizeof(uint8) * 4; |
52 | case CommonFormat::STf_RGBAub: |
53 | return sizeof(STf_RGBAub); |
54 | case CommonFormat::STPf_RGBAub: |
55 | return sizeof(STPf_RGBAub); |
56 | case CommonFormat::XYf_STf: |
57 | return sizeof(XYf_STf); |
58 | case CommonFormat::XYf_STPf: |
59 | return sizeof(XYf_STPf); |
60 | case CommonFormat::XYf_STf_RGBAub: |
61 | return sizeof(XYf_STf_RGBAub); |
62 | case CommonFormat::XYf_STus_RGBAub: |
63 | return sizeof(XYf_STus_RGBAub); |
64 | case CommonFormat::XYf_STPf_RGBAub: |
65 | return sizeof(XYf_STPf_RGBAub); |
66 | } |
67 | return 0; |
68 | } |
69 | |
70 | uint32 getFormatFlags(CommonFormat format) |
71 | { |
72 | switch (format) |
73 | { |
74 | case CommonFormat::NONE: |
75 | return 0; |
76 | case CommonFormat::XYf: |
77 | case CommonFormat::XYZf: |
78 | return ATTRIBFLAG_POS; |
79 | case CommonFormat::RGBAub: |
80 | return ATTRIBFLAG_COLOR; |
81 | case CommonFormat::STf_RGBAub: |
82 | case CommonFormat::STPf_RGBAub: |
83 | return ATTRIBFLAG_TEXCOORD | ATTRIBFLAG_COLOR; |
84 | case CommonFormat::XYf_STf: |
85 | case CommonFormat::XYf_STPf: |
86 | return ATTRIBFLAG_POS | ATTRIBFLAG_TEXCOORD; |
87 | case CommonFormat::XYf_STf_RGBAub: |
88 | case CommonFormat::XYf_STus_RGBAub: |
89 | case CommonFormat::XYf_STPf_RGBAub: |
90 | return ATTRIBFLAG_POS | ATTRIBFLAG_TEXCOORD | ATTRIBFLAG_COLOR; |
91 | } |
92 | return 0; |
93 | } |
94 | |
95 | int getFormatPositionComponents(CommonFormat format) |
96 | { |
97 | switch (format) |
98 | { |
99 | case CommonFormat::NONE: |
100 | case CommonFormat::RGBAub: |
101 | case CommonFormat::STf_RGBAub: |
102 | case CommonFormat::STPf_RGBAub: |
103 | return 0; |
104 | case CommonFormat::XYf: |
105 | case CommonFormat::XYf_STf: |
106 | case CommonFormat::XYf_STPf: |
107 | case CommonFormat::XYf_STf_RGBAub: |
108 | case CommonFormat::XYf_STus_RGBAub: |
109 | case CommonFormat::XYf_STPf_RGBAub: |
110 | return 2; |
111 | case CommonFormat::XYZf: |
112 | return 3; |
113 | } |
114 | return 0; |
115 | } |
116 | |
117 | size_t getIndexDataSize(IndexDataType type) |
118 | { |
119 | switch (type) |
120 | { |
121 | case INDEX_UINT16: |
122 | return sizeof(uint16); |
123 | case INDEX_UINT32: |
124 | return sizeof(uint32); |
125 | default: |
126 | return 0; |
127 | } |
128 | } |
129 | |
130 | size_t getDataTypeSize(DataType datatype) |
131 | { |
132 | switch (datatype) |
133 | { |
134 | case DATA_UNORM8: |
135 | return sizeof(uint8); |
136 | case DATA_UNORM16: |
137 | return sizeof(uint16); |
138 | case DATA_FLOAT: |
139 | return sizeof(float); |
140 | default: |
141 | return 0; |
142 | } |
143 | } |
144 | |
145 | IndexDataType getIndexDataTypeFromMax(size_t maxvalue) |
146 | { |
147 | IndexDataType types[] = {INDEX_UINT16, INDEX_UINT32}; |
148 | return types[maxvalue > LOVE_UINT16_MAX ? 1 : 0]; |
149 | } |
150 | |
151 | int getIndexCount(TriangleIndexMode mode, int vertexCount) |
152 | { |
153 | switch (mode) |
154 | { |
155 | case TriangleIndexMode::NONE: |
156 | return 0; |
157 | case TriangleIndexMode::STRIP: |
158 | case TriangleIndexMode::FAN: |
159 | return 3 * (vertexCount - 2); |
160 | case TriangleIndexMode::QUADS: |
161 | return vertexCount * 6 / 4; |
162 | } |
163 | return 0; |
164 | } |
165 | |
166 | template <typename T> |
167 | static void fillIndicesT(TriangleIndexMode mode, T vertexStart, T vertexCount, T *indices) |
168 | { |
169 | switch (mode) |
170 | { |
171 | case TriangleIndexMode::NONE: |
172 | break; |
173 | case TriangleIndexMode::STRIP: |
174 | { |
175 | int i = 0; |
176 | for (T index = 0; index < vertexCount - 2; index++) |
177 | { |
178 | indices[i++] = vertexStart + index; |
179 | indices[i++] = vertexStart + index + 1 + (index & 1); |
180 | indices[i++] = vertexStart + index + 2 - (index & 1); |
181 | } |
182 | } |
183 | break; |
184 | case TriangleIndexMode::FAN: |
185 | { |
186 | int i = 0; |
187 | for (T index = 2; index < vertexCount; index++) |
188 | { |
189 | indices[i++] = vertexStart; |
190 | indices[i++] = vertexStart + index - 1; |
191 | indices[i++] = vertexStart + index; |
192 | } |
193 | } |
194 | break; |
195 | case TriangleIndexMode::QUADS: |
196 | { |
197 | // 0---2 |
198 | // | / | |
199 | // 1---3 |
200 | int count = vertexCount / 4; |
201 | for (int i = 0; i < count; i++) |
202 | { |
203 | int ii = i * 6; |
204 | T vi = T(vertexStart + i * 4); |
205 | |
206 | indices[ii + 0] = vi + 0; |
207 | indices[ii + 1] = vi + 1; |
208 | indices[ii + 2] = vi + 2; |
209 | |
210 | indices[ii + 3] = vi + 2; |
211 | indices[ii + 4] = vi + 1; |
212 | indices[ii + 5] = vi + 3; |
213 | } |
214 | } |
215 | break; |
216 | } |
217 | } |
218 | |
219 | void fillIndices(TriangleIndexMode mode, uint16 vertexStart, uint16 vertexCount, uint16 *indices) |
220 | { |
221 | fillIndicesT(mode, vertexStart, vertexCount, indices); |
222 | } |
223 | |
224 | void fillIndices(TriangleIndexMode mode, uint32 vertexStart, uint32 vertexCount, uint32 *indices) |
225 | { |
226 | fillIndicesT(mode, vertexStart, vertexCount, indices); |
227 | } |
228 | |
229 | void Attributes::setCommonFormat(CommonFormat format, uint8 bufferindex) |
230 | { |
231 | setBufferLayout(bufferindex, (uint16) getFormatStride(format)); |
232 | |
233 | switch (format) |
234 | { |
235 | case CommonFormat::NONE: |
236 | break; |
237 | case CommonFormat::XYf: |
238 | set(ATTRIB_POS, DATA_FLOAT, 2, 0, bufferindex); |
239 | break; |
240 | case CommonFormat::XYZf: |
241 | set(ATTRIB_POS, DATA_FLOAT, 3, 0, bufferindex); |
242 | break; |
243 | case CommonFormat::RGBAub: |
244 | set(ATTRIB_COLOR, DATA_UNORM8, 4, 0, bufferindex); |
245 | break; |
246 | case CommonFormat::STf_RGBAub: |
247 | set(ATTRIB_TEXCOORD, DATA_FLOAT, 2, 0, bufferindex); |
248 | set(ATTRIB_COLOR, DATA_UNORM8, 4, uint16(sizeof(float) * 2), bufferindex); |
249 | break; |
250 | case CommonFormat::STPf_RGBAub: |
251 | set(ATTRIB_TEXCOORD, DATA_FLOAT, 3, 0, bufferindex); |
252 | set(ATTRIB_COLOR, DATA_UNORM8, 4, uint16(sizeof(float) * 3), bufferindex); |
253 | break; |
254 | case CommonFormat::XYf_STf: |
255 | set(ATTRIB_POS, DATA_FLOAT, 2, 0, bufferindex); |
256 | set(ATTRIB_TEXCOORD, DATA_FLOAT, 2, uint16(sizeof(float) * 2), bufferindex); |
257 | break; |
258 | case CommonFormat::XYf_STPf: |
259 | set(ATTRIB_POS, DATA_FLOAT, 2, 0, bufferindex); |
260 | set(ATTRIB_TEXCOORD, DATA_FLOAT, 3, uint16(sizeof(float) * 2), bufferindex); |
261 | break; |
262 | case CommonFormat::XYf_STf_RGBAub: |
263 | set(ATTRIB_POS, DATA_FLOAT, 2, 0, bufferindex); |
264 | set(ATTRIB_TEXCOORD, DATA_FLOAT, 2, uint16(sizeof(float) * 2), bufferindex); |
265 | set(ATTRIB_COLOR, DATA_UNORM8, 4, uint16(sizeof(float) * 4), bufferindex); |
266 | break; |
267 | case CommonFormat::XYf_STus_RGBAub: |
268 | set(ATTRIB_POS, DATA_FLOAT, 2, 0, bufferindex); |
269 | set(ATTRIB_TEXCOORD, DATA_UNORM16, 2, uint16(sizeof(float) * 2), bufferindex); |
270 | set(ATTRIB_COLOR, DATA_UNORM8, 4, uint16(sizeof(float) * 2 + sizeof(uint16) * 2), bufferindex); |
271 | break; |
272 | case CommonFormat::XYf_STPf_RGBAub: |
273 | set(ATTRIB_POS, DATA_FLOAT, 2, 0, bufferindex); |
274 | set(ATTRIB_TEXCOORD, DATA_FLOAT, 3, uint16(sizeof(float) * 2), bufferindex); |
275 | set(ATTRIB_COLOR, DATA_UNORM8, 4, uint16(sizeof(float) * 5), bufferindex); |
276 | break; |
277 | } |
278 | } |
279 | |
280 | static StringMap<BuiltinVertexAttribute, ATTRIB_MAX_ENUM>::Entry attribNameEntries[] = |
281 | { |
282 | { "VertexPosition" , ATTRIB_POS }, |
283 | { "VertexTexCoord" , ATTRIB_TEXCOORD }, |
284 | { "VertexColor" , ATTRIB_COLOR }, |
285 | { "ConstantColor" , ATTRIB_CONSTANTCOLOR }, |
286 | }; |
287 | |
288 | static StringMap<BuiltinVertexAttribute, ATTRIB_MAX_ENUM> attribNames(attribNameEntries, sizeof(attribNameEntries)); |
289 | |
290 | static StringMap<IndexDataType, INDEX_MAX_ENUM>::Entry indexTypeEntries[] = |
291 | { |
292 | { "uint16" , INDEX_UINT16 }, |
293 | { "uint32" , INDEX_UINT32 }, |
294 | }; |
295 | |
296 | static StringMap<IndexDataType, INDEX_MAX_ENUM> indexTypes(indexTypeEntries, sizeof(indexTypeEntries)); |
297 | |
298 | static StringMap<Usage, USAGE_MAX_ENUM>::Entry usageEntries[] = |
299 | { |
300 | { "stream" , USAGE_STREAM }, |
301 | { "dynamic" , USAGE_DYNAMIC }, |
302 | { "static" , USAGE_STATIC }, |
303 | }; |
304 | |
305 | static StringMap<Usage, USAGE_MAX_ENUM> usages(usageEntries, sizeof(usageEntries)); |
306 | |
307 | static StringMap<PrimitiveType, PRIMITIVE_MAX_ENUM>::Entry primitiveTypeEntries[] = |
308 | { |
309 | { "fan" , PRIMITIVE_TRIANGLE_FAN }, |
310 | { "strip" , PRIMITIVE_TRIANGLE_STRIP }, |
311 | { "triangles" , PRIMITIVE_TRIANGLES }, |
312 | { "points" , PRIMITIVE_POINTS }, |
313 | }; |
314 | |
315 | static StringMap<PrimitiveType, PRIMITIVE_MAX_ENUM> primitiveTypes(primitiveTypeEntries, sizeof(primitiveTypeEntries)); |
316 | |
317 | static StringMap<AttributeStep, STEP_MAX_ENUM>::Entry attributeStepEntries[] = |
318 | { |
319 | { "pervertex" , STEP_PER_VERTEX }, |
320 | { "perinstance" , STEP_PER_INSTANCE }, |
321 | }; |
322 | |
323 | static StringMap<AttributeStep, STEP_MAX_ENUM> attributeSteps(attributeStepEntries, sizeof(attributeStepEntries)); |
324 | |
325 | static StringMap<DataType, DATA_MAX_ENUM>::Entry dataTypeEntries[] = |
326 | { |
327 | { "byte" , DATA_UNORM8 }, // Legacy / more user-friendly name... |
328 | { "unorm16" , DATA_UNORM16 }, |
329 | { "float" , DATA_FLOAT }, |
330 | }; |
331 | |
332 | static StringMap<DataType, DATA_MAX_ENUM> dataTypes(dataTypeEntries, sizeof(dataTypeEntries)); |
333 | |
334 | static StringMap<CullMode, CULL_MAX_ENUM>::Entry cullModeEntries[] = |
335 | { |
336 | { "none" , CULL_NONE }, |
337 | { "back" , CULL_BACK }, |
338 | { "front" , CULL_FRONT }, |
339 | }; |
340 | |
341 | static StringMap<CullMode, CULL_MAX_ENUM> cullModes(cullModeEntries, sizeof(cullModeEntries)); |
342 | |
343 | static StringMap<Winding, WINDING_MAX_ENUM>::Entry windingEntries[] = |
344 | { |
345 | { "cw" , WINDING_CW }, |
346 | { "ccw" , WINDING_CCW }, |
347 | }; |
348 | |
349 | static StringMap<Winding, WINDING_MAX_ENUM> windings(windingEntries, sizeof(windingEntries)); |
350 | |
351 | bool getConstant(const char *in, BuiltinVertexAttribute &out) |
352 | { |
353 | return attribNames.find(in, out); |
354 | } |
355 | |
356 | bool getConstant(BuiltinVertexAttribute in, const char *&out) |
357 | { |
358 | return attribNames.find(in, out); |
359 | } |
360 | |
361 | bool getConstant(const char *in, IndexDataType &out) |
362 | { |
363 | return indexTypes.find(in, out); |
364 | } |
365 | |
366 | bool getConstant(IndexDataType in, const char *&out) |
367 | { |
368 | return indexTypes.find(in, out); |
369 | } |
370 | |
371 | std::vector<std::string> getConstants(IndexDataType) |
372 | { |
373 | return indexTypes.getNames(); |
374 | } |
375 | |
376 | bool getConstant(const char *in, Usage &out) |
377 | { |
378 | return usages.find(in, out); |
379 | } |
380 | |
381 | bool getConstant(Usage in, const char *&out) |
382 | { |
383 | return usages.find(in, out); |
384 | } |
385 | |
386 | std::vector<std::string> getConstants(Usage) |
387 | { |
388 | return usages.getNames(); |
389 | } |
390 | |
391 | bool getConstant(const char *in, PrimitiveType &out) |
392 | { |
393 | return primitiveTypes.find(in, out); |
394 | } |
395 | |
396 | bool getConstant(PrimitiveType in, const char *&out) |
397 | { |
398 | return primitiveTypes.find(in, out); |
399 | } |
400 | |
401 | std::vector<std::string> getConstants(PrimitiveType) |
402 | { |
403 | return primitiveTypes.getNames(); |
404 | } |
405 | |
406 | bool getConstant(const char *in, AttributeStep &out) |
407 | { |
408 | return attributeSteps.find(in, out); |
409 | } |
410 | |
411 | bool getConstant(AttributeStep in, const char *&out) |
412 | { |
413 | return attributeSteps.find(in, out); |
414 | } |
415 | |
416 | std::vector<std::string> getConstants(AttributeStep) |
417 | { |
418 | return attributeSteps.getNames(); |
419 | } |
420 | |
421 | bool getConstant(const char *in, DataType &out) |
422 | { |
423 | return dataTypes.find(in, out); |
424 | } |
425 | |
426 | bool getConstant(DataType in, const char *&out) |
427 | { |
428 | return dataTypes.find(in, out); |
429 | } |
430 | |
431 | std::vector<std::string> getConstants(DataType) |
432 | { |
433 | return dataTypes.getNames(); |
434 | } |
435 | |
436 | bool getConstant(const char *in, CullMode &out) |
437 | { |
438 | return cullModes.find(in, out); |
439 | } |
440 | |
441 | bool getConstant(CullMode in, const char *&out) |
442 | { |
443 | return cullModes.find(in, out); |
444 | } |
445 | |
446 | std::vector<std::string> getConstants(CullMode) |
447 | { |
448 | return cullModes.getNames(); |
449 | } |
450 | |
451 | bool getConstant(const char *in, Winding &out) |
452 | { |
453 | return windings.find(in, out); |
454 | } |
455 | |
456 | bool getConstant(Winding in, const char *&out) |
457 | { |
458 | return windings.find(in, out); |
459 | } |
460 | |
461 | std::vector<std::string> getConstants(Winding) |
462 | { |
463 | return windings.getNames(); |
464 | } |
465 | |
466 | } // vertex |
467 | } // graphics |
468 | } // love |
469 | |