1 | // Copyright (C) 2008-2012 NVIDIA Corporation. |
---|---|
2 | // Copyright (C) 2019 The Qt Company Ltd. |
3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only |
4 | |
5 | #ifndef QSSG_RENDER_SHADER_KEY_H |
6 | #define QSSG_RENDER_SHADER_KEY_H |
7 | |
8 | // |
9 | // W A R N I N G |
10 | // ------------- |
11 | // |
12 | // This file is not part of the Qt API. It exists purely as an |
13 | // implementation detail. This header file may change from version to |
14 | // version without notice, or even be removed. |
15 | // |
16 | // We mean it. |
17 | // |
18 | |
19 | #include <QtQuick3DUtils/private/qssgdataref_p.h> |
20 | #include <QtQuick3DUtils/private/qssgrenderbasetypes_p.h> |
21 | #include <QtQuick3DRuntimeRender/private/qssgrenderdefaultmaterial_p.h> |
22 | #include <QtQuick3DRuntimeRender/private/qssgrhicontext_p.h> |
23 | |
24 | QT_BEGIN_NAMESPACE |
25 | // We have an ever expanding set of properties we like to hash into one or more 32 bit |
26 | // quantities. |
27 | // Furthermore we would like this set of properties to be convertable to string |
28 | // So the shader cache file itself is somewhat human readable/diagnosable. |
29 | // To do this we create a set of objects that act as properties to the master shader key. |
30 | // These objects are tallied in order to figure out their actual offset into the shader key's |
31 | // data store. They are also run through in order to create the string shader cache key. |
32 | |
33 | struct QSSGShaderKeyPropertyBase |
34 | { |
35 | QByteArrayView name; |
36 | quint32 offset; |
37 | explicit constexpr QSSGShaderKeyPropertyBase(const char *inName = "") : name(inName), offset(0) {} |
38 | quint32 getOffset() const { return offset; } |
39 | void setOffset(quint32 of) { offset = of; } |
40 | |
41 | template<quint32 TBitWidth> |
42 | quint32 getMaskTemplate() const |
43 | { |
44 | quint32 bit = offset % 32; |
45 | quint32 startValue = (1 << TBitWidth) - 1; |
46 | quint32 mask = startValue << bit; |
47 | return mask; |
48 | } |
49 | |
50 | quint32 getIdx() const { return offset / 32; } |
51 | |
52 | protected: |
53 | void internalToString(QByteArray &ioStr, const QByteArrayView &inBuffer) const |
54 | { |
55 | ioStr.append(a: name); |
56 | ioStr.append(c: '='); |
57 | ioStr.append(a: inBuffer); |
58 | } |
59 | |
60 | static void internalToString(QByteArray &ioStr, const QByteArrayView &name, bool inValue) |
61 | { |
62 | if (inValue) { |
63 | ioStr.append(a: name); |
64 | ioStr.append(c: '='); |
65 | ioStr.append(a: inValue ? QByteArrayView("true") : QByteArrayView( "false")); |
66 | } |
67 | } |
68 | static bool getBoolValue(const QByteArray& str, const QByteArrayView &name) |
69 | { |
70 | const int index = str.indexOf(bv: name); |
71 | if (index < 0) |
72 | return false; |
73 | const qsizetype nameLen = name.size(); |
74 | if (str[index + nameLen] != '=') |
75 | return false; |
76 | if (str.mid(index: index + nameLen + 1, len: 4) == QByteArrayView("true")) |
77 | return true; |
78 | return false; |
79 | } |
80 | }; |
81 | |
82 | struct QSSGShaderKeyBoolean : public QSSGShaderKeyPropertyBase |
83 | { |
84 | enum { |
85 | BitWidth = 1, |
86 | }; |
87 | |
88 | explicit constexpr QSSGShaderKeyBoolean(const char *inName = "") : QSSGShaderKeyPropertyBase(inName) {} |
89 | |
90 | quint32 getMask() const { return getMaskTemplate<BitWidth>(); } |
91 | void setValue(QSSGDataRef<quint32> inDataStore, bool inValue) const |
92 | { |
93 | const qint32 idx = qint32(getIdx()); |
94 | Q_ASSERT(idx >= 0 && idx <= INT32_MAX); |
95 | Q_ASSERT(inDataStore.size() > idx); |
96 | quint32 mask = getMask(); |
97 | quint32 &target = inDataStore[idx]; |
98 | if (inValue) { |
99 | target = target | mask; |
100 | } else { |
101 | mask = ~mask; |
102 | target = target & mask; |
103 | } |
104 | } |
105 | |
106 | bool getValue(QSSGDataView<quint32> inDataStore) const |
107 | { |
108 | quint32 idx = getIdx(); |
109 | quint32 mask = getMask(); |
110 | const quint32 &target = inDataStore[idx]; |
111 | return (target & mask) ? true : false; |
112 | } |
113 | |
114 | void toString(QByteArray &ioStr, QSSGDataView<quint32> inKeySet) const |
115 | { |
116 | bool isHigh = getValue(inDataStore: inKeySet); |
117 | internalToString(ioStr, name, inValue: isHigh); |
118 | } |
119 | void fromString(const QByteArray &ioStr, QSSGDataRef<quint32> inKeySet) |
120 | { |
121 | setValue(inDataStore: inKeySet, inValue: getBoolValue(str: ioStr, name)); |
122 | } |
123 | }; |
124 | |
125 | template<quint32 TBitWidth> |
126 | struct QSSGShaderKeyUnsigned : public QSSGShaderKeyPropertyBase |
127 | { |
128 | enum { |
129 | BitWidth = TBitWidth, |
130 | }; |
131 | explicit constexpr QSSGShaderKeyUnsigned(const char *inName = "") : QSSGShaderKeyPropertyBase(inName) {} |
132 | quint32 getMask() const { return getMaskTemplate<BitWidth>(); } |
133 | void setValue(QSSGDataRef<quint32> inDataStore, quint32 inValue) const |
134 | { |
135 | quint32 startValue = (1 << TBitWidth) - 1; |
136 | // Ensure inValue is within range of bit width. |
137 | inValue = inValue & startValue; |
138 | quint32 bit = offset % 32; |
139 | quint32 mask = getMask(); |
140 | quint32 idx = getIdx(); |
141 | inValue = inValue << bit; |
142 | quint32 &target = inDataStore[idx]; |
143 | // Get rid of existing value |
144 | quint32 inverseMask = ~mask; |
145 | target = target & inverseMask; |
146 | target = target | inValue; |
147 | } |
148 | |
149 | quint32 getValue(QSSGDataView<quint32> inDataStore) const |
150 | { |
151 | quint32 idx = getIdx(); |
152 | quint32 bit = offset % 32; |
153 | quint32 mask = getMask(); |
154 | const quint32 &target = inDataStore[idx]; |
155 | |
156 | quint32 retval = target & mask; |
157 | retval = retval >> bit; |
158 | return retval; |
159 | } |
160 | |
161 | void toString(QByteArray &ioStr, QSSGDataView<quint32> inKeySet) const |
162 | { |
163 | quint32 value = getValue(inDataStore: inKeySet); |
164 | char buf[64]; |
165 | memset(s: buf, c: 0, n: sizeof (buf)); |
166 | toStr(item: value, buffer: toDataRef(type: buf, count: 64)); |
167 | internalToString(ioStr, buf); |
168 | } |
169 | |
170 | void fromString(const QByteArray &ioStr, QSSGDataRef<quint32> inKeySet) |
171 | { |
172 | const qsizetype nameLen = name.size(); |
173 | const qsizetype strOffset = ioStr.indexOf(name); |
174 | if (strOffset >= 0) { |
175 | /* The key is stored as name=val */ |
176 | if (ioStr[strOffset + nameLen] != '=') |
177 | return; |
178 | const QByteArray s = ioStr.right(n: ioStr.size() - strOffset - nameLen - 1); |
179 | int i = 0; |
180 | while (QChar(QLatin1Char(s[i])).isDigit()) |
181 | i++; |
182 | const quint32 value = s.left(n: i).toInt(); |
183 | setValue(inDataStore: inKeySet, inValue: value); |
184 | } |
185 | } |
186 | |
187 | private: |
188 | static quint32 toStr(quint32 item, QSSGDataRef<char> buffer) |
189 | { |
190 | // hope the buffer is big enough... |
191 | return static_cast<quint32>(::snprintf(s: buffer.begin(), maxlen: buffer.size(), format: "%u", item)); |
192 | } |
193 | }; |
194 | |
195 | struct QSSGShaderKeyTextureChannel : public QSSGShaderKeyUnsigned<2> |
196 | { |
197 | enum TexturChannelBits { |
198 | R = 0, |
199 | G = 1, |
200 | B = 2, |
201 | A = 3, |
202 | }; |
203 | explicit QSSGShaderKeyTextureChannel(const char *inName = "") : QSSGShaderKeyUnsigned<2>(inName) {} |
204 | |
205 | TexturChannelBits getTextureChannel(QSSGDataView<quint32> inKeySet) const |
206 | { |
207 | return TexturChannelBits(getValue(inDataStore: inKeySet)); |
208 | } |
209 | |
210 | void setTextureChannel(TexturChannelBits channel, QSSGDataRef<quint32> inKeySet) |
211 | { |
212 | setValue(inDataStore: inKeySet, inValue: quint32(channel)); |
213 | } |
214 | static constexpr char textureChannelToChar[4] = { |
215 | 'R', |
216 | 'G', |
217 | 'B', |
218 | 'A' |
219 | }; |
220 | void toString(QByteArray &ioStr, QSSGDataView<quint32> inKeySet) const |
221 | { |
222 | ioStr.append(a: name); |
223 | ioStr.append(c: '='); |
224 | ioStr.append(c: textureChannelToChar[getTextureChannel(inKeySet)]); |
225 | } |
226 | void fromString(const QByteArray &ioStr, QSSGDataRef<quint32> inKeySet) |
227 | { |
228 | const qsizetype nameLen = name.size(); |
229 | const qsizetype strOffset = ioStr.indexOf(bv: name); |
230 | if (strOffset >= 0) { |
231 | /* The key is stored as name=ch */ |
232 | if (ioStr[strOffset + nameLen] != '=') |
233 | return; |
234 | const char ch = ioStr[strOffset + nameLen + 1]; |
235 | if (ch == 'R') |
236 | setValue(inDataStore: inKeySet, inValue: TexturChannelBits::R); |
237 | else if (ch == 'G') |
238 | setValue(inDataStore: inKeySet, inValue: TexturChannelBits::G); |
239 | else if (ch == 'B') |
240 | setValue(inDataStore: inKeySet, inValue: TexturChannelBits::B); |
241 | else if (ch == 'A') |
242 | setValue(inDataStore: inKeySet, inValue: TexturChannelBits::A); |
243 | } |
244 | } |
245 | }; |
246 | |
247 | struct QSSGShaderKeyImageMap : public QSSGShaderKeyUnsigned<6> |
248 | { |
249 | enum ImageMapBits { |
250 | Enabled = 1 << 0, |
251 | EnvMap = 1 << 1, |
252 | LightProbe = 1 << 2, |
253 | Identity = 1 << 3, |
254 | UsesUV1 = 1 << 4, |
255 | Linear = 1 << 5 |
256 | }; |
257 | |
258 | explicit QSSGShaderKeyImageMap(const char *inName = "") : QSSGShaderKeyUnsigned<6>(inName) {} |
259 | |
260 | bool getBitValue(ImageMapBits imageBit, QSSGDataView<quint32> inKeySet) const |
261 | { |
262 | return (getValue(inDataStore: inKeySet) & imageBit) ? true : false; |
263 | } |
264 | |
265 | void setBitValue(ImageMapBits imageBit, bool inValue, QSSGDataRef<quint32> inKeySet) |
266 | { |
267 | quint32 theValue = getValue(inDataStore: inKeySet); |
268 | quint32 mask = imageBit; |
269 | if (inValue) { |
270 | theValue = theValue | mask; |
271 | } else { |
272 | mask = ~mask; |
273 | theValue = theValue & mask; |
274 | } |
275 | setValue(inDataStore: inKeySet, inValue: theValue); |
276 | } |
277 | |
278 | bool isEnabled(QSSGDataView<quint32> inKeySet) const { return getBitValue(imageBit: Enabled, inKeySet); } |
279 | void setEnabled(QSSGDataRef<quint32> inKeySet, bool val) { setBitValue(imageBit: Enabled, inValue: val, inKeySet); } |
280 | |
281 | bool isEnvMap(QSSGDataView<quint32> inKeySet) const { return getBitValue(imageBit: EnvMap, inKeySet); } |
282 | void setEnvMap(QSSGDataRef<quint32> inKeySet, bool val) { setBitValue(imageBit: EnvMap, inValue: val, inKeySet); } |
283 | |
284 | bool isLightProbe(QSSGDataView<quint32> inKeySet) const { return getBitValue(imageBit: LightProbe, inKeySet); } |
285 | void setLightProbe(QSSGDataRef<quint32> inKeySet, bool val) { setBitValue(imageBit: LightProbe, inValue: val, inKeySet); } |
286 | |
287 | bool isIdentityTransform(QSSGDataView<quint32> inKeySet) const { return getBitValue(imageBit: Identity, inKeySet); } |
288 | void setIdentityTransform(QSSGDataRef<quint32> inKeySet, bool val) { setBitValue(imageBit: Identity, inValue: val, inKeySet); } |
289 | |
290 | bool isUsingUV1(QSSGDataView<quint32> inKeySet) const { return getBitValue(imageBit: UsesUV1, inKeySet); } |
291 | void setUsesUV1(QSSGDataRef<quint32> inKeySet, bool val) { setBitValue(imageBit: UsesUV1, inValue: val, inKeySet); } |
292 | |
293 | bool isLinear(QSSGDataView<quint32> inKeySet) const { return getBitValue(imageBit: Linear, inKeySet); } |
294 | void setLinear(QSSGDataRef<quint32> inKeySet, bool val) { setBitValue(imageBit: Linear, inValue: val, inKeySet); } |
295 | |
296 | void toString(QByteArray &ioStr, QSSGDataView<quint32> inKeySet) const |
297 | { |
298 | ioStr.append(a: name); |
299 | ioStr.append(a: QByteArrayView("={")); |
300 | internalToString(ioStr, name: QByteArrayView("enabled"), inValue: isEnabled(inKeySet)); |
301 | ioStr.append(c: ';'); |
302 | internalToString(ioStr, name: QByteArrayView("envMap"), inValue: isEnvMap(inKeySet)); |
303 | ioStr.append(c: ';'); |
304 | internalToString(ioStr, name: QByteArrayView("lightProbe"), inValue: isLightProbe(inKeySet)); |
305 | ioStr.append(c: ';'); |
306 | internalToString(ioStr, name: QByteArrayView("identity"), inValue: isIdentityTransform(inKeySet)); |
307 | ioStr.append(c: ';'); |
308 | internalToString(ioStr, name: QByteArrayView("usesUV1"), inValue: isUsingUV1(inKeySet)); |
309 | ioStr.append(c: ';'); |
310 | internalToString(ioStr, name: QByteArrayView("linear"), inValue: isLinear(inKeySet)); |
311 | ioStr.append(c: '}'); |
312 | } |
313 | }; |
314 | |
315 | struct QSSGShaderKeySpecularModel : QSSGShaderKeyUnsigned<2> |
316 | { |
317 | explicit QSSGShaderKeySpecularModel(const char *inName = "") : QSSGShaderKeyUnsigned<2>(inName) {} |
318 | |
319 | void setSpecularModel(QSSGDataRef<quint32> inKeySet, QSSGRenderDefaultMaterial::MaterialSpecularModel inModel) |
320 | { |
321 | setValue(inDataStore: inKeySet, inValue: quint32(inModel)); |
322 | } |
323 | |
324 | QSSGRenderDefaultMaterial::MaterialSpecularModel getSpecularModel(QSSGDataView<quint32> inKeySet) const |
325 | { |
326 | return static_cast<QSSGRenderDefaultMaterial::MaterialSpecularModel>(getValue(inDataStore: inKeySet)); |
327 | } |
328 | |
329 | void toString(QByteArray &ioStr, QSSGDataView<quint32> inKeySet) const |
330 | { |
331 | ioStr.append(a: name); |
332 | ioStr.append(c: '='); |
333 | switch (getSpecularModel(inKeySet)) { |
334 | case QSSGRenderDefaultMaterial::MaterialSpecularModel::KGGX: |
335 | ioStr.append(a: QByteArrayView("KGGX")); |
336 | break; |
337 | case QSSGRenderDefaultMaterial::MaterialSpecularModel::Default: |
338 | ioStr.append(a: QByteArrayView("Default")); |
339 | break; |
340 | } |
341 | ioStr.append(c: ';'); |
342 | } |
343 | void fromString(const QByteArray &ioStr, QSSGDataRef<quint32> inKeySet) |
344 | { |
345 | const qsizetype nameLen = name.size(); |
346 | const int strOffset = ioStr.indexOf(bv: name); |
347 | if (strOffset >= 0) { |
348 | /* The key is stored as name=specularMode; */ |
349 | if (ioStr[strOffset + nameLen] != '=') |
350 | return; |
351 | const int codeOffsetBegin = strOffset + nameLen + 1; |
352 | int codeOffset = 0; |
353 | while (ioStr[codeOffsetBegin + codeOffset] != ';') |
354 | codeOffset++; |
355 | const QByteArray val = ioStr.mid(index: codeOffsetBegin, len: codeOffset); |
356 | if (val == QByteArrayView("KGGX")) |
357 | setSpecularModel(inKeySet, inModel: QSSGRenderDefaultMaterial::MaterialSpecularModel::KGGX); |
358 | if (val == QByteArrayView("Default")) |
359 | setSpecularModel(inKeySet, inModel: QSSGRenderDefaultMaterial::MaterialSpecularModel::Default); |
360 | } |
361 | } |
362 | }; |
363 | |
364 | struct QSSGShaderKeyAlphaMode : QSSGShaderKeyUnsigned<2> |
365 | { |
366 | explicit QSSGShaderKeyAlphaMode(const char *inName = "") : QSSGShaderKeyUnsigned<2>(inName) {} |
367 | |
368 | void setAlphaMode(QSSGDataRef<quint32> inKeySet, QSSGRenderDefaultMaterial::MaterialAlphaMode inMode) |
369 | { |
370 | setValue(inDataStore: inKeySet, inValue: quint32(inMode)); |
371 | } |
372 | |
373 | QSSGRenderDefaultMaterial::MaterialAlphaMode getAlphaMode(QSSGDataView<quint32> inKeySet) const |
374 | { |
375 | return static_cast<QSSGRenderDefaultMaterial::MaterialAlphaMode>(getValue(inDataStore: inKeySet)); |
376 | } |
377 | |
378 | void toString(QByteArray &ioStr, QSSGDataView<quint32> inKeySet) const |
379 | { |
380 | ioStr.append(a: name); |
381 | ioStr.append(c: '='); |
382 | switch (getAlphaMode(inKeySet)) { |
383 | case QSSGRenderDefaultMaterial::MaterialAlphaMode::Default: |
384 | ioStr.append(a: QByteArrayView("Default")); |
385 | break; |
386 | case QSSGRenderDefaultMaterial::MaterialAlphaMode::Mask: |
387 | ioStr.append(a: QByteArrayView("Mask")); |
388 | break; |
389 | case QSSGRenderDefaultMaterial::MaterialAlphaMode::Blend: |
390 | ioStr.append(a: QByteArrayView("Blend")); |
391 | break; |
392 | case QSSGRenderDefaultMaterial::MaterialAlphaMode::Opaque: |
393 | ioStr.append(a: QByteArrayView("Opaque")); |
394 | break; |
395 | } |
396 | ioStr.append(c: ';'); |
397 | } |
398 | void fromString(const QByteArray &ioStr, QSSGDataRef<quint32> inKeySet) |
399 | { |
400 | const qsizetype nameLen = name.size(); |
401 | const qsizetype strOffset = ioStr.indexOf(bv: name); |
402 | if (strOffset >= 0) { |
403 | /* The key is stored as name=alphaMode; */ |
404 | if (ioStr[strOffset + nameLen] != '=') |
405 | return; |
406 | const int codeOffsetBegin = strOffset + nameLen + 1; |
407 | int codeOffset = 0; |
408 | while (ioStr[codeOffsetBegin + codeOffset] != ';') |
409 | codeOffset++; |
410 | const QByteArray val = ioStr.mid(index: codeOffsetBegin, len: codeOffset); |
411 | if (val == QByteArrayView("Default")) |
412 | setAlphaMode(inKeySet, inMode: QSSGRenderDefaultMaterial::MaterialAlphaMode::Default); |
413 | if (val == QByteArrayView("Mask")) |
414 | setAlphaMode(inKeySet, inMode: QSSGRenderDefaultMaterial::MaterialAlphaMode::Mask); |
415 | if (val == QByteArrayView("Blend")) |
416 | setAlphaMode(inKeySet, inMode: QSSGRenderDefaultMaterial::MaterialAlphaMode::Blend); |
417 | if (val == QByteArrayView("Opaque")) |
418 | setAlphaMode(inKeySet, inMode: QSSGRenderDefaultMaterial::MaterialAlphaMode::Opaque); |
419 | } |
420 | } |
421 | }; |
422 | |
423 | struct QSSGShaderKeyVertexAttribute : public QSSGShaderKeyUnsigned<9> |
424 | { |
425 | enum VertexAttributeBits { |
426 | Position = 1 << 0, |
427 | Normal = 1 << 1, |
428 | TexCoord0 = 1 << 2, |
429 | TexCoord1 = 1 << 3, |
430 | Tangent = 1 << 4, |
431 | Binormal = 1 << 5, |
432 | Color = 1 << 6, |
433 | JointAndWeight = 1 << 7, |
434 | TexCoordLightmap = 1 << 8 |
435 | }; |
436 | |
437 | explicit QSSGShaderKeyVertexAttribute(const char *inName = "") : QSSGShaderKeyUnsigned<9>(inName) {} |
438 | |
439 | bool getBitValue(VertexAttributeBits bit, QSSGDataView<quint32> inKeySet) const |
440 | { |
441 | return (getValue(inDataStore: inKeySet) & bit) ? true : false; |
442 | } |
443 | void setBitValue(VertexAttributeBits bit, QSSGDataRef<quint32> inKeySet, bool value) const |
444 | { |
445 | quint32 v = getValue(inDataStore: inKeySet); |
446 | v = value ? (v | bit) : (v & ~bit); |
447 | setValue(inDataStore: inKeySet, inValue: v); |
448 | } |
449 | |
450 | void toString(QByteArray &ioStr, QSSGDataView<quint32> inKeySet) const |
451 | { |
452 | ioStr.append(a: name); |
453 | ioStr.append(a: QByteArrayView("={")); |
454 | internalToString(ioStr, name: QByteArrayView("position"), inValue: getBitValue(bit: Position, inKeySet)); |
455 | ioStr.append(c: ';'); |
456 | internalToString(ioStr, name: QByteArrayView("normal"), inValue: getBitValue(bit: Normal, inKeySet)); |
457 | ioStr.append(c: ';'); |
458 | internalToString(ioStr, name: QByteArrayView("texcoord0"), inValue: getBitValue(bit: TexCoord0, inKeySet)); |
459 | ioStr.append(c: ';'); |
460 | internalToString(ioStr, name: QByteArrayView("texcoord1"), inValue: getBitValue(bit: TexCoord1, inKeySet)); |
461 | ioStr.append(c: ';'); |
462 | internalToString(ioStr, name: QByteArrayView("tangent"), inValue: getBitValue(bit: Tangent, inKeySet)); |
463 | ioStr.append(c: ';'); |
464 | internalToString(ioStr, name: QByteArrayView("binormal"), inValue: getBitValue(bit: Binormal, inKeySet)); |
465 | ioStr.append(c: ';'); |
466 | internalToString(ioStr, name: QByteArrayView("color"), inValue: getBitValue(bit: Color, inKeySet)); |
467 | ioStr.append(c: ';'); |
468 | internalToString(ioStr, name: QByteArrayView("texcoordlightmap"), inValue: getBitValue(bit: TexCoordLightmap, inKeySet)); |
469 | ioStr.append(c: '}'); |
470 | internalToString(ioStr, name: QByteArrayView("joint&weight"), inValue: getBitValue(bit: JointAndWeight, inKeySet)); |
471 | ioStr.append(c: '}'); |
472 | } |
473 | void fromString(const QByteArray &ioStr, QSSGDataRef<quint32> inKeySet) |
474 | { |
475 | const qsizetype nameLen = name.size(); |
476 | const qsizetype strOffset = ioStr.indexOf(bv: name); |
477 | if (strOffset >= 0) { |
478 | /* The key is stored as name={;;;;;;} */ |
479 | if (ioStr[strOffset + nameLen] != '=') |
480 | return; |
481 | if (ioStr[strOffset + nameLen + 1] != '{') |
482 | return; |
483 | const int codeOffsetBegin = strOffset + nameLen + 2; |
484 | int codeOffset = 0; |
485 | while (ioStr[codeOffsetBegin + codeOffset] != '}') |
486 | codeOffset++; |
487 | const QByteArray val = ioStr.mid(index: codeOffsetBegin, len: codeOffset); |
488 | const QVector<QByteArray> list = val.split(sep: ';'); |
489 | if (list.size() != 8) |
490 | return; |
491 | setBitValue(bit: Position, inKeySet, value: getBoolValue(str: list[0], name: QByteArrayView("position"))); |
492 | setBitValue(bit: Normal, inKeySet, value: getBoolValue(str: list[1], name: QByteArrayView("normal"))); |
493 | setBitValue(bit: TexCoord0, inKeySet, value: getBoolValue(str: list[2], name: QByteArrayView("texcoord0"))); |
494 | setBitValue(bit: TexCoord1, inKeySet, value: getBoolValue(str: list[3], name: QByteArrayView("texcoord1"))); |
495 | setBitValue(bit: Tangent, inKeySet, value: getBoolValue(str: list[4], name: QByteArrayView("tangent"))); |
496 | setBitValue(bit: Binormal, inKeySet, value: getBoolValue(str: list[5], name: QByteArrayView("binormal"))); |
497 | setBitValue(bit: Color, inKeySet, value: getBoolValue(str: list[6], name: QByteArrayView("color"))); |
498 | setBitValue(bit: TexCoordLightmap, inKeySet, value: getBoolValue(str: list[7], name: QByteArrayView("texcoordlightmap"))); |
499 | } |
500 | } |
501 | }; |
502 | |
503 | struct QSSGShaderDefaultMaterialKeyProperties |
504 | { |
505 | enum { |
506 | LightCount = QSSG_MAX_NUM_LIGHTS, |
507 | }; |
508 | enum { |
509 | SingleChannelImageCount = 13, |
510 | }; |
511 | enum ImageMapNames { |
512 | DiffuseMap = 0, |
513 | BumpMap, |
514 | SpecularMap, |
515 | NormalMap, |
516 | ClearcoatNormalMap, |
517 | // single channel images |
518 | OpacityMap, |
519 | RoughnessMap, |
520 | MetalnessMap, |
521 | OcclusionMap, |
522 | TranslucencyMap, |
523 | HeightMap, |
524 | ClearcoatMap, |
525 | ClearcoatRoughnessMap, |
526 | TransmissionMap, |
527 | ThicknessMap, |
528 | BaseColorMap, |
529 | SpecularAmountMap, |
530 | EmissiveMap, |
531 | |
532 | ImageMapCount, |
533 | SingleChannelImagesFirst = OpacityMap |
534 | }; |
535 | enum ImageChannelNames { |
536 | OpacityChannel = 0, |
537 | RoughnessChannel, |
538 | MetalnessChannel, |
539 | OcclusionChannel, |
540 | TranslucencyChannel, |
541 | HeightChannel, |
542 | ClearcoatChannel, |
543 | ClearcoatRoughnessChannel, |
544 | TransmissionChannel, |
545 | ThicknessChannel, |
546 | BaseColorChannel, |
547 | SpecularAmountChannel, |
548 | EmissiveChannel, |
549 | }; |
550 | |
551 | QSSGShaderKeyBoolean m_hasLighting; |
552 | QSSGShaderKeyBoolean m_hasIbl; |
553 | QSSGShaderKeyUnsigned<4> m_lightCount; |
554 | QSSGShaderKeyBoolean m_lightFlags[LightCount]; |
555 | QSSGShaderKeyBoolean m_lightSpotFlags[LightCount]; |
556 | QSSGShaderKeyBoolean m_lightAreaFlags[LightCount]; |
557 | QSSGShaderKeyBoolean m_lightShadowFlags[LightCount]; |
558 | QSSGShaderKeyUnsigned<16> m_lightShadowMapSize[LightCount]; |
559 | QSSGShaderKeyUnsigned<4> m_lightSoftShadowQuality[LightCount]; |
560 | QSSGShaderKeyBoolean m_specularEnabled; |
561 | QSSGShaderKeyBoolean m_fresnelScaleBiasEnabled; |
562 | QSSGShaderKeyBoolean m_clearcoatFresnelScaleBiasEnabled; |
563 | QSSGShaderKeyBoolean m_fresnelEnabled; |
564 | QSSGShaderKeyBoolean m_baseColorSingleChannelEnabled; |
565 | QSSGShaderKeyBoolean m_specularSingleChannelEnabled; |
566 | QSSGShaderKeyBoolean m_emissiveSingleChannelEnabled; |
567 | QSSGShaderKeyBoolean m_invertOpacityMapValue; |
568 | QSSGShaderKeyBoolean m_vertexColorsEnabled; |
569 | QSSGShaderKeyBoolean m_vertexColorsMaskEnabled; |
570 | QSSGShaderKeyUnsigned<16> m_vertexColorRedMask; |
571 | QSSGShaderKeyUnsigned<16> m_vertexColorGreenMask; |
572 | QSSGShaderKeyUnsigned<16> m_vertexColorBlueMask; |
573 | QSSGShaderKeyUnsigned<16> m_vertexColorAlphaMask; |
574 | QSSGShaderKeySpecularModel m_specularModel; |
575 | QSSGShaderKeyImageMap m_imageMaps[ImageMapCount]; |
576 | QSSGShaderKeyTextureChannel m_textureChannels[SingleChannelImageCount]; |
577 | QSSGShaderKeyUnsigned<16> m_boneCount; |
578 | QSSGShaderKeyBoolean m_isDoubleSided; |
579 | QSSGShaderKeyBoolean m_overridesPosition; |
580 | QSSGShaderKeyBoolean m_usesProjectionMatrix; |
581 | QSSGShaderKeyBoolean m_usesInverseProjectionMatrix; |
582 | QSSGShaderKeyBoolean m_usesPointsTopology; |
583 | QSSGShaderKeyBoolean m_usesVarColor; |
584 | QSSGShaderKeyAlphaMode m_alphaMode; |
585 | QSSGShaderKeyVertexAttribute m_vertexAttributes; |
586 | QSSGShaderKeyBoolean m_usesFloatJointIndices; |
587 | qsizetype m_stringBufferSizeHint = 0; |
588 | QSSGShaderKeyBoolean m_usesInstancing; |
589 | QSSGShaderKeyUnsigned<8> m_targetCount; |
590 | QSSGShaderKeyUnsigned<8> m_targetPositionOffset; |
591 | QSSGShaderKeyUnsigned<8> m_targetNormalOffset; |
592 | QSSGShaderKeyUnsigned<8> m_targetTangentOffset; |
593 | QSSGShaderKeyUnsigned<8> m_targetBinormalOffset; |
594 | QSSGShaderKeyUnsigned<8> m_targetTexCoord0Offset; |
595 | QSSGShaderKeyUnsigned<8> m_targetTexCoord1Offset; |
596 | QSSGShaderKeyUnsigned<8> m_targetColorOffset; |
597 | QSSGShaderKeyBoolean m_blendParticles; |
598 | QSSGShaderKeyBoolean m_clearcoatEnabled; |
599 | QSSGShaderKeyBoolean m_transmissionEnabled; |
600 | QSSGShaderKeyBoolean m_specularAAEnabled; |
601 | QSSGShaderKeyBoolean m_lightmapEnabled; |
602 | QSSGShaderKeyBoolean m_specularGlossyEnabled; |
603 | QSSGShaderKeyUnsigned<4> m_debugMode; |
604 | QSSGShaderKeyBoolean m_fogEnabled; |
605 | QSSGShaderKeyUnsigned<3> m_viewCount; |
606 | QSSGShaderKeyBoolean m_usesViewIndex; |
607 | |
608 | QSSGShaderDefaultMaterialKeyProperties() |
609 | : m_hasLighting("hasLighting") |
610 | , m_hasIbl("hasIbl") |
611 | , m_lightCount("lightCount") |
612 | , m_specularEnabled("specularEnabled") |
613 | , m_fresnelEnabled("fresnelEnabled") |
614 | , m_baseColorSingleChannelEnabled("baseColorSingleChannelEnabled") |
615 | , m_specularSingleChannelEnabled("specularSingleChannelEnabled") |
616 | , m_emissiveSingleChannelEnabled("emissiveSingleChannelEnabled") |
617 | , m_invertOpacityMapValue("invertOpacityMapValue") |
618 | , m_vertexColorsEnabled("vertexColorsEnabled") |
619 | , m_vertexColorsMaskEnabled("vertexColorsMaskEnabled") |
620 | , m_vertexColorRedMask("vertexColorRedMask") |
621 | , m_vertexColorGreenMask("vertexColorGreenMask") |
622 | , m_vertexColorBlueMask("vertexColorBlueMask") |
623 | , m_vertexColorAlphaMask("vertexColorAlphaMask") |
624 | , m_specularModel("specularModel") |
625 | , m_boneCount("boneCount") |
626 | , m_isDoubleSided("isDoubleSided") |
627 | , m_overridesPosition("overridesPosition") |
628 | , m_usesProjectionMatrix("usesProjectionMatrix") |
629 | , m_usesInverseProjectionMatrix("usesInverseProjectionMatrix") |
630 | , m_usesPointsTopology("usesPointsTopology") |
631 | , m_usesVarColor("usesVarColor") |
632 | , m_alphaMode("alphaMode") |
633 | , m_vertexAttributes("vertexAttributes") |
634 | , m_usesFloatJointIndices("usesFloatJointIndices") |
635 | , m_usesInstancing("usesInstancing") |
636 | , m_targetCount("targetCount") |
637 | , m_targetPositionOffset("targetPositionOffset") |
638 | , m_targetNormalOffset("targetNormalOffset") |
639 | , m_targetTangentOffset("targetTangentOffset") |
640 | , m_targetBinormalOffset("targetBinormalOffset") |
641 | , m_targetTexCoord0Offset("targetTexCoord0Offset") |
642 | , m_targetTexCoord1Offset("targetTexCoord1Offset") |
643 | , m_targetColorOffset("targetColorOffset") |
644 | , m_blendParticles("blendParticles") |
645 | , m_clearcoatEnabled("clearcoatEnabled") |
646 | , m_transmissionEnabled("transmissionEnabled") |
647 | , m_specularAAEnabled("specularAAEnabled") |
648 | , m_lightmapEnabled("lightmapEnabled") |
649 | , m_specularGlossyEnabled("specularGlossyEnabled") |
650 | , m_debugMode("debugMode") |
651 | , m_fogEnabled("fogEnabled") |
652 | , m_viewCount("viewCount") |
653 | , m_usesViewIndex("usesViewIndex") |
654 | { |
655 | m_lightFlags[0].name = "light0HasPosition"; |
656 | m_lightFlags[1].name = "light1HasPosition"; |
657 | m_lightFlags[2].name = "light2HasPosition"; |
658 | m_lightFlags[3].name = "light3HasPosition"; |
659 | m_lightFlags[4].name = "light4HasPosition"; |
660 | m_lightFlags[5].name = "light5HasPosition"; |
661 | m_lightFlags[6].name = "light6HasPosition"; |
662 | m_lightFlags[7].name = "light7HasPosition"; |
663 | m_lightFlags[8].name = "light8HasPosition"; |
664 | m_lightFlags[9].name = "light9HasPosition"; |
665 | m_lightFlags[10].name = "light10HasPosition"; |
666 | m_lightFlags[11].name = "light11HasPosition"; |
667 | m_lightFlags[12].name = "light12HasPosition"; |
668 | m_lightFlags[13].name = "light13HasPosition"; |
669 | m_lightFlags[14].name = "light14HasPosition"; |
670 | |
671 | m_lightSpotFlags[0].name = "light0HasSpot"; |
672 | m_lightSpotFlags[1].name = "light1HasSpot"; |
673 | m_lightSpotFlags[2].name = "light2HasSpot"; |
674 | m_lightSpotFlags[3].name = "light3HasSpot"; |
675 | m_lightSpotFlags[4].name = "light4HasSpot"; |
676 | m_lightSpotFlags[5].name = "light5HasSpot"; |
677 | m_lightSpotFlags[6].name = "light6HasSpot"; |
678 | m_lightSpotFlags[7].name = "light7HasSpot"; |
679 | m_lightSpotFlags[8].name = "light8HasSpot"; |
680 | m_lightSpotFlags[9].name = "light9HasSpot"; |
681 | m_lightSpotFlags[10].name = "light10HasSpot"; |
682 | m_lightSpotFlags[11].name = "light11HasSpot"; |
683 | m_lightSpotFlags[12].name = "light12HasSpot"; |
684 | m_lightSpotFlags[13].name = "light13HasSpot"; |
685 | m_lightSpotFlags[14].name = "light14HasSpot"; |
686 | |
687 | m_lightAreaFlags[0].name = "light0HasArea"; |
688 | m_lightAreaFlags[1].name = "light1HasArea"; |
689 | m_lightAreaFlags[2].name = "light2HasArea"; |
690 | m_lightAreaFlags[3].name = "light3HasArea"; |
691 | m_lightAreaFlags[4].name = "light4HasArea"; |
692 | m_lightAreaFlags[5].name = "light5HasArea"; |
693 | m_lightAreaFlags[6].name = "light6HasArea"; |
694 | m_lightAreaFlags[7].name = "light7HasArea"; |
695 | m_lightAreaFlags[8].name = "light8HasArea"; |
696 | m_lightAreaFlags[9].name = "light9HasArea"; |
697 | m_lightAreaFlags[10].name = "light10HasArea"; |
698 | m_lightAreaFlags[11].name = "light11HasArea"; |
699 | m_lightAreaFlags[12].name = "light12HasArea"; |
700 | m_lightAreaFlags[13].name = "light13HasArea"; |
701 | m_lightAreaFlags[14].name = "light14HasArea"; |
702 | |
703 | m_lightShadowFlags[0].name = "light0HasShadow"; |
704 | m_lightShadowFlags[1].name = "light1HasShadow"; |
705 | m_lightShadowFlags[2].name = "light2HasShadow"; |
706 | m_lightShadowFlags[3].name = "light3HasShadow"; |
707 | m_lightShadowFlags[4].name = "light4HasShadow"; |
708 | m_lightShadowFlags[5].name = "light5HasShadow"; |
709 | m_lightShadowFlags[6].name = "light6HasShadow"; |
710 | m_lightShadowFlags[7].name = "light7HasShadow"; |
711 | m_lightShadowFlags[8].name = "light8HasShadow"; |
712 | m_lightShadowFlags[9].name = "light9HasShadow"; |
713 | m_lightShadowFlags[10].name = "light10HasShadow"; |
714 | m_lightShadowFlags[11].name = "light11HasShadow"; |
715 | m_lightShadowFlags[12].name = "light12HasShadow"; |
716 | m_lightShadowFlags[13].name = "light13HasShadow"; |
717 | m_lightShadowFlags[14].name = "light14HasShadow"; |
718 | |
719 | m_lightShadowMapSize[0].name = "light0ShadowMapSize"; |
720 | m_lightShadowMapSize[1].name = "light1ShadowMapSize"; |
721 | m_lightShadowMapSize[2].name = "light2ShadowMapSize"; |
722 | m_lightShadowMapSize[3].name = "light3ShadowMapSize"; |
723 | m_lightShadowMapSize[4].name = "light4ShadowMapSize"; |
724 | m_lightShadowMapSize[5].name = "light5ShadowMapSize"; |
725 | m_lightShadowMapSize[6].name = "light6ShadowMapSize"; |
726 | m_lightShadowMapSize[7].name = "light7ShadowMapSize"; |
727 | m_lightShadowMapSize[8].name = "light8ShadowMapSize"; |
728 | m_lightShadowMapSize[9].name = "light9ShadowMapSize"; |
729 | m_lightShadowMapSize[10].name = "light10ShadowMapSize"; |
730 | m_lightShadowMapSize[11].name = "light11ShadowMapSize"; |
731 | m_lightShadowMapSize[12].name = "light12ShadowMapSize"; |
732 | m_lightShadowMapSize[13].name = "light13ShadowMapSize"; |
733 | m_lightShadowMapSize[14].name = "light14ShadowMapSize"; |
734 | |
735 | m_lightSoftShadowQuality[0].name = "light0SoftShadowQuality"; |
736 | m_lightSoftShadowQuality[1].name = "light1SoftShadowQuality"; |
737 | m_lightSoftShadowQuality[2].name = "light2SoftShadowQuality"; |
738 | m_lightSoftShadowQuality[3].name = "light3SoftShadowQuality"; |
739 | m_lightSoftShadowQuality[4].name = "light4SoftShadowQuality"; |
740 | m_lightSoftShadowQuality[5].name = "light5SoftShadowQuality"; |
741 | m_lightSoftShadowQuality[6].name = "light6SoftShadowQuality"; |
742 | m_lightSoftShadowQuality[7].name = "light7SoftShadowQuality"; |
743 | m_lightSoftShadowQuality[8].name = "light8SoftShadowQuality"; |
744 | m_lightSoftShadowQuality[9].name = "light9SoftShadowQuality"; |
745 | m_lightSoftShadowQuality[10].name = "light10SoftShadowQuality"; |
746 | m_lightSoftShadowQuality[11].name = "light11SoftShadowQuality"; |
747 | m_lightSoftShadowQuality[12].name = "light12SoftShadowQuality"; |
748 | m_lightSoftShadowQuality[13].name = "light13SoftShadowQuality"; |
749 | m_lightSoftShadowQuality[14].name = "light14SoftShadowQuality"; |
750 | |
751 | m_imageMaps[0].name = "diffuseMap"; |
752 | m_imageMaps[1].name = "emissiveMap"; |
753 | m_imageMaps[2].name = "specularMap"; |
754 | m_imageMaps[3].name = "baseColorMap"; |
755 | m_imageMaps[4].name = "bumpMap"; |
756 | m_imageMaps[5].name = "specularAmountMap"; |
757 | m_imageMaps[6].name = "normalMap"; |
758 | m_imageMaps[7].name = "clearcoatNormalMap"; |
759 | m_imageMaps[8].name = "opacityMap"; |
760 | m_imageMaps[9].name = "roughnessMap"; |
761 | m_imageMaps[10].name = "metalnessMap"; |
762 | m_imageMaps[11].name = "occlusionMap"; |
763 | m_imageMaps[12].name = "translucencyMap"; |
764 | m_imageMaps[13].name = "heightMap"; |
765 | m_imageMaps[14].name = "clearcoatMap"; |
766 | m_imageMaps[15].name = "clearcoatRoughnessMap"; |
767 | m_imageMaps[16].name = "transmissionMap"; |
768 | m_imageMaps[17].name = "thicknessMap"; |
769 | |
770 | m_textureChannels[0].name = "opacityMap_channel"; |
771 | m_textureChannels[1].name = "roughnessMap_channel"; |
772 | m_textureChannels[2].name = "metalnessMap_channel"; |
773 | m_textureChannels[3].name = "occlusionMap_channel"; |
774 | m_textureChannels[4].name = "translucencyMap_channel"; |
775 | m_textureChannels[5].name = "heightMap_channel"; |
776 | m_textureChannels[6].name = "clearcoatMap_channel"; |
777 | m_textureChannels[7].name = "clearcoatRoughnessMap_channel"; |
778 | m_textureChannels[8].name = "transmissionMap_channel"; |
779 | m_textureChannels[9].name = "thicknessMap_channel"; |
780 | m_textureChannels[10].name = "baseColorMap_channel"; |
781 | m_textureChannels[11].name = "specularAmountMap_channel"; |
782 | |
783 | init(); |
784 | } |
785 | |
786 | template<typename TVisitor> |
787 | void visitProperties(TVisitor &inVisitor) |
788 | { |
789 | inVisitor.visit(m_hasLighting); |
790 | inVisitor.visit(m_hasIbl); |
791 | inVisitor.visit(m_lightCount); |
792 | |
793 | for (auto &lightFlag : m_lightFlags) |
794 | inVisitor.visit(lightFlag); |
795 | |
796 | for (auto &lightSpotFlag : m_lightSpotFlags) |
797 | inVisitor.visit(lightSpotFlag); |
798 | |
799 | for (auto &lightAreaFlag : m_lightAreaFlags) |
800 | inVisitor.visit(lightAreaFlag); |
801 | |
802 | for (auto &lightShadowFlag : m_lightShadowFlags) |
803 | inVisitor.visit(lightShadowFlag); |
804 | |
805 | for (auto &lightShadowMapSize : m_lightShadowMapSize) |
806 | inVisitor.visit(lightShadowMapSize); |
807 | |
808 | for (auto &softShadowQuality : m_lightSoftShadowQuality) |
809 | inVisitor.visit(softShadowQuality); |
810 | |
811 | inVisitor.visit(m_specularEnabled); |
812 | inVisitor.visit(m_fresnelEnabled); |
813 | inVisitor.visit(m_fresnelScaleBiasEnabled); |
814 | inVisitor.visit(m_clearcoatFresnelScaleBiasEnabled); |
815 | inVisitor.visit(m_baseColorSingleChannelEnabled); |
816 | inVisitor.visit(m_specularSingleChannelEnabled); |
817 | inVisitor.visit(m_emissiveSingleChannelEnabled); |
818 | inVisitor.visit(m_invertOpacityMapValue); |
819 | inVisitor.visit(m_vertexColorsEnabled); |
820 | inVisitor.visit(m_vertexColorsMaskEnabled); |
821 | inVisitor.visit(m_vertexColorRedMask); |
822 | inVisitor.visit(m_vertexColorGreenMask); |
823 | inVisitor.visit(m_vertexColorBlueMask); |
824 | inVisitor.visit(m_vertexColorAlphaMask); |
825 | inVisitor.visit(m_specularModel); |
826 | |
827 | for (quint32 idx = 0, end = ImageMapCount; idx < end; ++idx) |
828 | inVisitor.visit(m_imageMaps[idx]); |
829 | |
830 | for (auto &textureChannel : m_textureChannels) |
831 | inVisitor.visit(textureChannel); |
832 | |
833 | inVisitor.visit(m_boneCount); |
834 | inVisitor.visit(m_isDoubleSided); |
835 | inVisitor.visit(m_overridesPosition); |
836 | inVisitor.visit(m_usesProjectionMatrix); |
837 | inVisitor.visit(m_usesInverseProjectionMatrix); |
838 | inVisitor.visit(m_usesPointsTopology); |
839 | inVisitor.visit(m_usesVarColor); |
840 | inVisitor.visit(m_alphaMode); |
841 | inVisitor.visit(m_vertexAttributes); |
842 | inVisitor.visit(m_usesFloatJointIndices); |
843 | inVisitor.visit(m_usesInstancing); |
844 | inVisitor.visit(m_targetCount); |
845 | inVisitor.visit(m_targetPositionOffset); |
846 | inVisitor.visit(m_targetNormalOffset); |
847 | inVisitor.visit(m_targetTangentOffset); |
848 | inVisitor.visit(m_targetBinormalOffset); |
849 | inVisitor.visit(m_targetTexCoord0Offset); |
850 | inVisitor.visit(m_targetTexCoord1Offset); |
851 | inVisitor.visit(m_targetColorOffset); |
852 | inVisitor.visit(m_blendParticles); |
853 | inVisitor.visit(m_clearcoatEnabled); |
854 | inVisitor.visit(m_transmissionEnabled); |
855 | inVisitor.visit(m_specularAAEnabled); |
856 | inVisitor.visit(m_lightmapEnabled); |
857 | inVisitor.visit(m_specularGlossyEnabled); |
858 | inVisitor.visit(m_debugMode); |
859 | inVisitor.visit(m_fogEnabled); |
860 | inVisitor.visit(m_viewCount); |
861 | inVisitor.visit(m_usesViewIndex); |
862 | } |
863 | |
864 | struct OffsetVisitor |
865 | { |
866 | quint32 m_offset; |
867 | OffsetVisitor() : m_offset(0) {} |
868 | template<typename TPropType> |
869 | void visit(TPropType &inProp) |
870 | { |
871 | // if we cross the 32 bit border we just move |
872 | // to the next dword. |
873 | // This cost a few extra bits but prevents tedious errors like |
874 | // loosing shader key bits because they got moved beyond the 32 border |
875 | quint32 bit = m_offset % 32; |
876 | if (bit + TPropType::BitWidth > 32) { |
877 | m_offset += 32 - bit; |
878 | } |
879 | |
880 | inProp.setOffset(m_offset); |
881 | m_offset += TPropType::BitWidth; |
882 | } |
883 | }; |
884 | |
885 | struct StringSizeVisitor |
886 | { |
887 | qsizetype size = 0; |
888 | template<typename P> |
889 | constexpr void visit(const P &prop) |
890 | { |
891 | size += prop.name.size(); |
892 | } |
893 | }; |
894 | |
895 | struct InitVisitor |
896 | { |
897 | OffsetVisitor offsetVisitor; |
898 | StringSizeVisitor stringSizeVisitor; |
899 | |
900 | template<typename P> |
901 | void visit(P &prop) |
902 | { |
903 | offsetVisitor.visit(prop); |
904 | stringSizeVisitor.visit(prop); |
905 | } |
906 | }; |
907 | |
908 | void init() |
909 | { |
910 | InitVisitor visitor; |
911 | visitProperties(inVisitor&: visitor); |
912 | |
913 | // If this assert fires, then the default material key needs more bits. |
914 | Q_ASSERT(visitor.offsetVisitor.m_offset < 736); |
915 | // This is so we can do some guestimate of how big the string buffer needs |
916 | // to be to avoid doing a lot of allocations when concatenating the strings. |
917 | m_stringBufferSizeHint = visitor.stringSizeVisitor.size; |
918 | } |
919 | }; |
920 | |
921 | struct QSSGShaderDefaultMaterialKey |
922 | { |
923 | enum { |
924 | DataBufferSize = 23, |
925 | }; |
926 | quint32 m_dataBuffer[DataBufferSize]; // 23 * 4 * 8 = 736 bits |
927 | size_t m_featureSetHash; |
928 | |
929 | explicit QSSGShaderDefaultMaterialKey(size_t inFeatureSetHash) : m_featureSetHash(inFeatureSetHash) |
930 | { |
931 | for (size_t idx = 0; idx < DataBufferSize; ++idx) |
932 | m_dataBuffer[idx] = 0; |
933 | } |
934 | |
935 | QSSGShaderDefaultMaterialKey() : m_featureSetHash(0) |
936 | { |
937 | for (size_t idx = 0; idx < DataBufferSize; ++idx) |
938 | m_dataBuffer[idx] = 0; |
939 | } |
940 | |
941 | size_t hash() const |
942 | { |
943 | size_t retval = 0; |
944 | for (size_t idx = 0; idx < DataBufferSize; ++idx) |
945 | retval = retval ^ qHash(key: m_dataBuffer[idx]); |
946 | return retval ^ m_featureSetHash; |
947 | } |
948 | |
949 | bool operator==(const QSSGShaderDefaultMaterialKey &other) const |
950 | { |
951 | bool retval = true; |
952 | for (size_t idx = 0; idx < DataBufferSize && retval; ++idx) |
953 | retval = m_dataBuffer[idx] == other.m_dataBuffer[idx]; |
954 | return retval && m_featureSetHash == other.m_featureSetHash; |
955 | } |
956 | |
957 | // Cast operators to make getting properties easier. |
958 | operator QSSGDataRef<quint32>() { return toDataRef(type: m_dataBuffer, count: DataBufferSize); } |
959 | operator QSSGDataView<quint32>() const { return toDataView(type: m_dataBuffer, count: DataBufferSize); } |
960 | |
961 | struct StringVisitor |
962 | { |
963 | QByteArray &m_str; |
964 | QSSGDataView<quint32> m_keyStore; |
965 | StringVisitor(QByteArray &s, QSSGDataView<quint32> ks) : m_str(s), m_keyStore(ks) {} |
966 | template<typename TPropType> |
967 | void visit(const TPropType &prop) |
968 | { |
969 | const qsizetype originalSize = m_str.size(); |
970 | if (m_str.size()) |
971 | m_str.append(c: ';'); |
972 | prop.toString(m_str, m_keyStore); |
973 | // if the only thing we added was the semicolon |
974 | // then nuke the semicolon |
975 | if (originalSize && m_str.size() == (originalSize + 1)) |
976 | m_str.resize(size: originalSize); |
977 | } |
978 | }; |
979 | |
980 | struct StringInVisitor |
981 | { |
982 | const QByteArray &m_str; |
983 | QSSGDataRef<quint32> m_keyStore; |
984 | StringInVisitor(const QByteArray &s, QSSGDataRef<quint32> ks) : m_str(s), m_keyStore(ks) {} |
985 | |
986 | template<typename TPropType> |
987 | void visit(TPropType &prop) |
988 | { |
989 | prop.fromString(m_str, m_keyStore); |
990 | } |
991 | }; |
992 | |
993 | void toString(QByteArray &ioString, const QSSGShaderDefaultMaterialKeyProperties &inProperties) const |
994 | { |
995 | ioString.reserve(asize: inProperties.m_stringBufferSizeHint); |
996 | StringVisitor theVisitor(ioString, *this); |
997 | const_cast<QSSGShaderDefaultMaterialKeyProperties &>(inProperties).visitProperties(inVisitor&: theVisitor); |
998 | } |
999 | void fromString(QByteArray &ioString, QSSGShaderDefaultMaterialKeyProperties &inProperties) |
1000 | { |
1001 | StringInVisitor theVisitor(ioString, *this); |
1002 | inProperties.visitProperties(inVisitor&: theVisitor); |
1003 | } |
1004 | QByteArray toByteArray() const |
1005 | { |
1006 | QByteArray ret; |
1007 | ret.resize(size: sizeof(m_dataBuffer)); |
1008 | memcpy(dest: ret.data(), src: m_dataBuffer, n: sizeof(m_dataBuffer)); |
1009 | return ret; |
1010 | } |
1011 | bool fromByteArray(const QByteArray &data) const |
1012 | { |
1013 | if (data.size() != sizeof(m_dataBuffer)) |
1014 | return false; |
1015 | memcpy(dest: (void *)m_dataBuffer, src: data.data(), n: sizeof(m_dataBuffer)); |
1016 | return true; |
1017 | } |
1018 | }; |
1019 | |
1020 | Q_STATIC_ASSERT(std::is_trivially_destructible<QSSGShaderDefaultMaterialKey>::value); |
1021 | |
1022 | |
1023 | inline size_t qHash(const QSSGShaderDefaultMaterialKey &key) |
1024 | { |
1025 | return key.hash(); |
1026 | } |
1027 | |
1028 | QT_END_NAMESPACE |
1029 | |
1030 | #endif |
1031 |
Definitions
- QSSGShaderKeyPropertyBase
- QSSGShaderKeyPropertyBase
- getOffset
- setOffset
- getMaskTemplate
- getIdx
- internalToString
- internalToString
- getBoolValue
- QSSGShaderKeyBoolean
- QSSGShaderKeyBoolean
- getMask
- setValue
- getValue
- toString
- fromString
- QSSGShaderKeyUnsigned
- QSSGShaderKeyUnsigned
- getMask
- setValue
- getValue
- toString
- fromString
- toStr
- QSSGShaderKeyTextureChannel
- TexturChannelBits
- QSSGShaderKeyTextureChannel
- getTextureChannel
- setTextureChannel
- textureChannelToChar
- toString
- fromString
- QSSGShaderKeyImageMap
- ImageMapBits
- QSSGShaderKeyImageMap
- getBitValue
- setBitValue
- isEnabled
- setEnabled
- isEnvMap
- setEnvMap
- isLightProbe
- setLightProbe
- isIdentityTransform
- setIdentityTransform
- isUsingUV1
- setUsesUV1
- isLinear
- setLinear
- toString
- QSSGShaderKeySpecularModel
- QSSGShaderKeySpecularModel
- setSpecularModel
- getSpecularModel
- toString
- fromString
- QSSGShaderKeyAlphaMode
- QSSGShaderKeyAlphaMode
- setAlphaMode
- getAlphaMode
- toString
- fromString
- QSSGShaderKeyVertexAttribute
- VertexAttributeBits
- QSSGShaderKeyVertexAttribute
- getBitValue
- setBitValue
- toString
- fromString
- QSSGShaderDefaultMaterialKeyProperties
- ImageMapNames
- ImageChannelNames
- QSSGShaderDefaultMaterialKeyProperties
- visitProperties
- OffsetVisitor
- OffsetVisitor
- visit
- StringSizeVisitor
- visit
- InitVisitor
- visit
- init
- QSSGShaderDefaultMaterialKey
- QSSGShaderDefaultMaterialKey
- QSSGShaderDefaultMaterialKey
- hash
- operator==
- operator QSSGDataRef<quint32>
- operator QSSGDataView<quint32>
- StringVisitor
- StringVisitor
- visit
- StringInVisitor
- StringInVisitor
- visit
- toString
- fromString
- toByteArray
- fromByteArray
Learn to use CMake with our Intro Training
Find out more