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
24namespace love
25{
26namespace graphics
27{
28namespace vertex
29{
30
31static_assert(sizeof(Color32) == 4, "sizeof(Color32) incorrect!");
32static_assert(sizeof(STf_RGBAub) == sizeof(float)*2 + sizeof(Color32), "sizeof(STf_RGBAub) incorrect!");
33static_assert(sizeof(STPf_RGBAub) == sizeof(float)*3 + sizeof(Color32), "sizeof(STPf_RGBAub) incorrect!");
34static_assert(sizeof(XYf_STf) == sizeof(float)*2 + sizeof(float)*2, "sizeof(XYf_STf) incorrect!");
35static_assert(sizeof(XYf_STPf) == sizeof(float)*2 + sizeof(float)*3, "sizeof(XYf_STPf) incorrect!");
36static_assert(sizeof(XYf_STf_RGBAub) == sizeof(float)*2 + sizeof(float)*2 + sizeof(Color32), "sizeof(XYf_STf_RGBAub) incorrect!");
37static_assert(sizeof(XYf_STus_RGBAub) == sizeof(float)*2 + sizeof(uint16)*2 + sizeof(Color32), "sizeof(XYf_STus_RGBAub) incorrect!");
38static_assert(sizeof(XYf_STPf_RGBAub) == sizeof(float)*2 + sizeof(float)*3 + sizeof(Color32), "sizeof(XYf_STPf_RGBAub) incorrect!");
39
40size_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
70uint32 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
95int 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
117size_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
130size_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
145IndexDataType getIndexDataTypeFromMax(size_t maxvalue)
146{
147 IndexDataType types[] = {INDEX_UINT16, INDEX_UINT32};
148 return types[maxvalue > LOVE_UINT16_MAX ? 1 : 0];
149}
150
151int 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
166template <typename T>
167static 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
219void fillIndices(TriangleIndexMode mode, uint16 vertexStart, uint16 vertexCount, uint16 *indices)
220{
221 fillIndicesT(mode, vertexStart, vertexCount, indices);
222}
223
224void fillIndices(TriangleIndexMode mode, uint32 vertexStart, uint32 vertexCount, uint32 *indices)
225{
226 fillIndicesT(mode, vertexStart, vertexCount, indices);
227}
228
229void 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
280static 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
288static StringMap<BuiltinVertexAttribute, ATTRIB_MAX_ENUM> attribNames(attribNameEntries, sizeof(attribNameEntries));
289
290static StringMap<IndexDataType, INDEX_MAX_ENUM>::Entry indexTypeEntries[] =
291{
292 { "uint16", INDEX_UINT16 },
293 { "uint32", INDEX_UINT32 },
294};
295
296static StringMap<IndexDataType, INDEX_MAX_ENUM> indexTypes(indexTypeEntries, sizeof(indexTypeEntries));
297
298static StringMap<Usage, USAGE_MAX_ENUM>::Entry usageEntries[] =
299{
300 { "stream", USAGE_STREAM },
301 { "dynamic", USAGE_DYNAMIC },
302 { "static", USAGE_STATIC },
303};
304
305static StringMap<Usage, USAGE_MAX_ENUM> usages(usageEntries, sizeof(usageEntries));
306
307static 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
315static StringMap<PrimitiveType, PRIMITIVE_MAX_ENUM> primitiveTypes(primitiveTypeEntries, sizeof(primitiveTypeEntries));
316
317static StringMap<AttributeStep, STEP_MAX_ENUM>::Entry attributeStepEntries[] =
318{
319 { "pervertex", STEP_PER_VERTEX },
320 { "perinstance", STEP_PER_INSTANCE },
321};
322
323static StringMap<AttributeStep, STEP_MAX_ENUM> attributeSteps(attributeStepEntries, sizeof(attributeStepEntries));
324
325static 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
332static StringMap<DataType, DATA_MAX_ENUM> dataTypes(dataTypeEntries, sizeof(dataTypeEntries));
333
334static StringMap<CullMode, CULL_MAX_ENUM>::Entry cullModeEntries[] =
335{
336 { "none", CULL_NONE },
337 { "back", CULL_BACK },
338 { "front", CULL_FRONT },
339};
340
341static StringMap<CullMode, CULL_MAX_ENUM> cullModes(cullModeEntries, sizeof(cullModeEntries));
342
343static StringMap<Winding, WINDING_MAX_ENUM>::Entry windingEntries[] =
344{
345 { "cw", WINDING_CW },
346 { "ccw", WINDING_CCW },
347};
348
349static StringMap<Winding, WINDING_MAX_ENUM> windings(windingEntries, sizeof(windingEntries));
350
351bool getConstant(const char *in, BuiltinVertexAttribute &out)
352{
353 return attribNames.find(in, out);
354}
355
356bool getConstant(BuiltinVertexAttribute in, const char *&out)
357{
358 return attribNames.find(in, out);
359}
360
361bool getConstant(const char *in, IndexDataType &out)
362{
363 return indexTypes.find(in, out);
364}
365
366bool getConstant(IndexDataType in, const char *&out)
367{
368 return indexTypes.find(in, out);
369}
370
371std::vector<std::string> getConstants(IndexDataType)
372{
373 return indexTypes.getNames();
374}
375
376bool getConstant(const char *in, Usage &out)
377{
378 return usages.find(in, out);
379}
380
381bool getConstant(Usage in, const char *&out)
382{
383 return usages.find(in, out);
384}
385
386std::vector<std::string> getConstants(Usage)
387{
388 return usages.getNames();
389}
390
391bool getConstant(const char *in, PrimitiveType &out)
392{
393 return primitiveTypes.find(in, out);
394}
395
396bool getConstant(PrimitiveType in, const char *&out)
397{
398 return primitiveTypes.find(in, out);
399}
400
401std::vector<std::string> getConstants(PrimitiveType)
402{
403 return primitiveTypes.getNames();
404}
405
406bool getConstant(const char *in, AttributeStep &out)
407{
408 return attributeSteps.find(in, out);
409}
410
411bool getConstant(AttributeStep in, const char *&out)
412{
413 return attributeSteps.find(in, out);
414}
415
416std::vector<std::string> getConstants(AttributeStep)
417{
418 return attributeSteps.getNames();
419}
420
421bool getConstant(const char *in, DataType &out)
422{
423 return dataTypes.find(in, out);
424}
425
426bool getConstant(DataType in, const char *&out)
427{
428 return dataTypes.find(in, out);
429}
430
431std::vector<std::string> getConstants(DataType)
432{
433 return dataTypes.getNames();
434}
435
436bool getConstant(const char *in, CullMode &out)
437{
438 return cullModes.find(in, out);
439}
440
441bool getConstant(CullMode in, const char *&out)
442{
443 return cullModes.find(in, out);
444}
445
446std::vector<std::string> getConstants(CullMode)
447{
448 return cullModes.getNames();
449}
450
451bool getConstant(const char *in, Winding &out)
452{
453 return windings.find(in, out);
454}
455
456bool getConstant(Winding in, const char *&out)
457{
458 return windings.find(in, out);
459}
460
461std::vector<std::string> getConstants(Winding)
462{
463 return windings.getNames();
464}
465
466} // vertex
467} // graphics
468} // love
469