| /**************************************************************************** |
| ** |
| ** Copyright (C) 2008-2012 NVIDIA Corporation. |
| ** Copyright (C) 2019 The Qt Company Ltd. |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** This file is part of Qt Quick 3D. |
| ** |
| ** $QT_BEGIN_LICENSE:GPL$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU |
| ** General Public License version 3 or (at your option) any later version |
| ** approved by the KDE Free Qt Foundation. The licenses are as published by |
| ** the Free Software Foundation and appearing in the file LICENSE.GPL3 |
| ** included in the packaging of this file. Please review the following |
| ** information to ensure the GNU General Public License requirements will |
| ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #ifndef QSSG_RENDER_SHADER_KEY_H |
| #define QSSG_RENDER_SHADER_KEY_H |
| |
| // |
| // W A R N I N G |
| // ------------- |
| // |
| // This file is not part of the Qt API. It exists purely as an |
| // implementation detail. This header file may change from version to |
| // version without notice, or even be removed. |
| // |
| // We mean it. |
| // |
| |
| #include <QtQuick3DUtils/private/qssgdataref_p.h> |
| |
| #include <QtQuick3DRender/private/qssgrenderbasetypes_p.h> |
| |
| #include <QtQuick3DRuntimeRender/private/qssgrenderdefaultmaterial_p.h> |
| #include <QtQuick3DRuntimeRender/private/qssgrendertessmodevalues_p.h> |
| |
| QT_BEGIN_NAMESPACE |
| // We have an ever expanding set of properties we like to hash into one or more 32 bit |
| // quantities. |
| // Furthermore we would like this set of properties to be convertable to string |
| // So the shader cache file itself is somewhat human readable/diagnosable. |
| // To do this we create a set of objects that act as properties to the master shader key. |
| // These objects are tallied in order to figure out their actual offset into the shader key's |
| // data store. They are also run through in order to create the string shader cache key. |
| |
| struct QSSGShaderKeyPropertyBase |
| { |
| const char *name; |
| quint32 offset; |
| QSSGShaderKeyPropertyBase(const char *inName = "") : name(inName), offset(0) {} |
| quint32 getOffset() const { return offset; } |
| void setOffset(quint32 of) { offset = of; } |
| |
| template<quint32 TBitWidth> |
| quint32 getMaskTemplate() const |
| { |
| quint32 bit = offset % 32; |
| quint32 startValue = (1 << TBitWidth) - 1; |
| quint32 mask = startValue << bit; |
| return mask; |
| } |
| |
| quint32 getIdx() const { return offset / 32; } |
| |
| protected: |
| void internalToString(QString &ioStr, const char *inBuffer) const |
| { |
| ioStr.append(QString::fromLocal8Bit(name)); |
| ioStr.append(QStringLiteral("=")); |
| ioStr.append(QString::fromLocal8Bit(inBuffer)); |
| } |
| |
| static void internalToString(QString &ioStr, const char *name, bool inValue) |
| { |
| if (inValue) { |
| ioStr.append(QString::fromLocal8Bit(name)); |
| ioStr.append(QStringLiteral("=")); |
| ioStr.append(inValue ? QStringLiteral("true") : QStringLiteral("false")); |
| } |
| } |
| }; |
| |
| struct QSSGShaderKeyBoolean : public QSSGShaderKeyPropertyBase |
| { |
| enum { |
| BitWidth = 1, |
| }; |
| |
| QSSGShaderKeyBoolean(const char *inName = "") : QSSGShaderKeyPropertyBase(inName) {} |
| |
| quint32 getMask() const { return getMaskTemplate<BitWidth>(); } |
| void setValue(QSSGDataRef<quint32> inDataStore, bool inValue) const |
| { |
| const qint32 idx = qint32(getIdx()); |
| Q_ASSERT(idx >= 0 && idx <= INT32_MAX); |
| Q_ASSERT(inDataStore.size() > idx); |
| quint32 mask = getMask(); |
| quint32 &target = inDataStore[idx]; |
| if (inValue == true) { |
| target = target | mask; |
| } else { |
| mask = ~mask; |
| target = target & mask; |
| } |
| } |
| |
| bool getValue(QSSGDataView<quint32> inDataStore) const |
| { |
| quint32 idx = getIdx(); |
| quint32 mask = getMask(); |
| const quint32 &target = inDataStore[idx]; |
| return (target & mask) ? true : false; |
| } |
| |
| void toString(QString &ioStr, QSSGDataView<quint32> inKeySet) const |
| { |
| bool isHigh = getValue(inKeySet); |
| internalToString(ioStr, name, isHigh); |
| } |
| }; |
| |
| template<quint32 TBitWidth> |
| struct QSSGShaderKeyUnsigned : public QSSGShaderKeyPropertyBase |
| { |
| enum { |
| BitWidth = TBitWidth, |
| }; |
| QSSGShaderKeyUnsigned(const char *inName = "") : QSSGShaderKeyPropertyBase(inName) {} |
| quint32 getMask() const { return getMaskTemplate<BitWidth>(); } |
| void setValue(QSSGDataRef<quint32> inDataStore, quint32 inValue) const |
| { |
| quint32 startValue = (1 << TBitWidth) - 1; |
| // Ensure inValue is within range of bit width. |
| inValue = inValue & startValue; |
| quint32 bit = offset % 32; |
| quint32 mask = getMask(); |
| quint32 idx = getIdx(); |
| inValue = inValue << bit; |
| quint32 &target = inDataStore[idx]; |
| // Get rid of existing value |
| quint32 inverseMask = ~mask; |
| target = target & inverseMask; |
| target = target | inValue; |
| } |
| |
| quint32 getValue(QSSGDataView<quint32> inDataStore) const |
| { |
| quint32 idx = getIdx(); |
| quint32 bit = offset % 32; |
| quint32 mask = getMask(); |
| const quint32 &target = inDataStore[idx]; |
| |
| quint32 retval = target & mask; |
| retval = retval >> bit; |
| return retval; |
| } |
| |
| void toString(QString &ioStr, QSSGDataView<quint32> inKeySet) const |
| { |
| quint32 value = getValue(inKeySet); |
| char buf[64]; |
| toStr(value, toDataRef(buf, 64)); |
| internalToString(ioStr, buf); |
| } |
| |
| private: |
| static quint32 toStr(quint32 item, QSSGDataRef<char> buffer) |
| { |
| // hope the buffer is big enough... |
| return static_cast<quint32>(::snprintf(buffer.begin(), buffer.size(), "%u", item)); |
| } |
| }; |
| |
| struct QSSGShaderKeyTessellation : public QSSGShaderKeyUnsigned<4> |
| { |
| enum TessellationBits { |
| noTessellation = 1 << 0, |
| linearTessellation = 1 << 1, |
| phongTessellation = 1 << 2, |
| npatchTessellation = 1 << 3 |
| }; |
| |
| QSSGShaderKeyTessellation(const char *inName = "") : QSSGShaderKeyUnsigned<4>(inName) {} |
| |
| bool getBitValue(TessellationBits swizzleBit, QSSGDataView<quint32> inKeySet) const |
| { |
| return (getValue(inKeySet) & swizzleBit) ? true : false; |
| } |
| |
| void setBitValue(TessellationBits swizzleBit, bool inValue, QSSGDataRef<quint32> inKeySet) |
| { |
| quint32 theValue = getValue(inKeySet); |
| quint32 mask = swizzleBit; |
| if (inValue) { |
| theValue = theValue | mask; |
| } else { |
| mask = ~mask; |
| theValue = theValue & mask; |
| } |
| setValue(inKeySet, theValue); |
| } |
| |
| void setTessellationMode(QSSGDataRef<quint32> inKeySet, TessellationModeValues tessellationMode, bool val) |
| { |
| switch (tessellationMode) { |
| case TessellationModeValues::NoTessellation: |
| setBitValue(noTessellation, val, inKeySet); |
| break; |
| case TessellationModeValues::Linear: |
| setBitValue(linearTessellation, val, inKeySet); |
| break; |
| case TessellationModeValues::NPatch: |
| setBitValue(npatchTessellation, val, inKeySet); |
| break; |
| case TessellationModeValues::Phong: |
| setBitValue(phongTessellation, val, inKeySet); |
| break; |
| } |
| } |
| |
| bool isNoTessellation(QSSGDataView<quint32> inKeySet) const { return getBitValue(noTessellation, inKeySet); } |
| void setNoTessellation(QSSGDataRef<quint32> inKeySet, bool val) { setBitValue(noTessellation, val, inKeySet); } |
| |
| bool isLinearTessellation(QSSGDataView<quint32> inKeySet) const |
| { |
| return getBitValue(linearTessellation, inKeySet); |
| } |
| void setLinearTessellation(QSSGDataRef<quint32> inKeySet, bool val) |
| { |
| setBitValue(linearTessellation, val, inKeySet); |
| } |
| |
| bool isNPatchTessellation(QSSGDataView<quint32> inKeySet) const |
| { |
| return getBitValue(npatchTessellation, inKeySet); |
| } |
| void setNPatchTessellation(QSSGDataRef<quint32> inKeySet, bool val) |
| { |
| setBitValue(npatchTessellation, val, inKeySet); |
| } |
| |
| bool isPhongTessellation(QSSGDataView<quint32> inKeySet) const |
| { |
| return getBitValue(phongTessellation, inKeySet); |
| } |
| void setPhongTessellation(QSSGDataRef<quint32> inKeySet, bool val) |
| { |
| setBitValue(phongTessellation, val, inKeySet); |
| } |
| |
| void toString(QString &ioStr, QSSGDataView<quint32> inKeySet) const |
| { |
| ioStr.append(QString::fromLocal8Bit(name)); |
| ioStr.append(QStringLiteral("={")); |
| internalToString(ioStr, "noTessellation", isNoTessellation(inKeySet)); |
| ioStr.append(QStringLiteral(";")); |
| internalToString(ioStr, "linearTessellation", isLinearTessellation(inKeySet)); |
| ioStr.append(QStringLiteral(";")); |
| internalToString(ioStr, "npatchTessellation", isNPatchTessellation(inKeySet)); |
| ioStr.append(QStringLiteral(";")); |
| internalToString(ioStr, "phongTessellation", isPhongTessellation(inKeySet)); |
| ioStr.append(QStringLiteral("}")); |
| } |
| }; |
| |
| struct QSSGShaderKeyTextureSwizzle : public QSSGShaderKeyUnsigned<5> |
| { |
| enum TextureSwizzleBits { |
| noSwizzle = 1 << 0, |
| L8toR8 = 1 << 1, |
| A8toR8 = 1 << 2, |
| L8A8toRG8 = 1 << 3, |
| L16toR16 = 1 << 4 |
| }; |
| |
| QSSGShaderKeyTextureSwizzle(const char *inName = "") : QSSGShaderKeyUnsigned<5>(inName) {} |
| |
| bool getBitValue(TextureSwizzleBits swizzleBit, QSSGDataView<quint32> inKeySet) const |
| { |
| return (getValue(inKeySet) & swizzleBit) ? true : false; |
| } |
| |
| void setBitValue(TextureSwizzleBits swizzleBit, bool inValue, QSSGDataRef<quint32> inKeySet) |
| { |
| quint32 theValue = getValue(inKeySet); |
| quint32 mask = swizzleBit; |
| if (inValue) { |
| theValue = theValue | mask; |
| } else { |
| mask = ~mask; |
| theValue = theValue & mask; |
| } |
| setValue(inKeySet, theValue); |
| } |
| |
| void setSwizzleMode(QSSGDataRef<quint32> inKeySet, QSSGRenderTextureSwizzleMode swizzleMode, bool val) |
| { |
| switch (swizzleMode) { |
| case QSSGRenderTextureSwizzleMode::NoSwizzle: |
| setBitValue(noSwizzle, val, inKeySet); |
| break; |
| case QSSGRenderTextureSwizzleMode::L8toR8: |
| setBitValue(L8toR8, val, inKeySet); |
| break; |
| case QSSGRenderTextureSwizzleMode::A8toR8: |
| setBitValue(A8toR8, val, inKeySet); |
| break; |
| case QSSGRenderTextureSwizzleMode::L8A8toRG8: |
| setBitValue(L8A8toRG8, val, inKeySet); |
| break; |
| case QSSGRenderTextureSwizzleMode::L16toR16: |
| setBitValue(L16toR16, val, inKeySet); |
| break; |
| } |
| } |
| |
| bool isNoSwizzled(QSSGDataView<quint32> inKeySet) const { return getBitValue(noSwizzle, inKeySet); } |
| void setNoSwizzled(QSSGDataRef<quint32> inKeySet, bool val) { setBitValue(noSwizzle, val, inKeySet); } |
| |
| bool isL8Swizzled(QSSGDataView<quint32> inKeySet) const { return getBitValue(L8toR8, inKeySet); } |
| void setL8Swizzled(QSSGDataRef<quint32> inKeySet, bool val) { setBitValue(L8toR8, val, inKeySet); } |
| |
| bool isA8Swizzled(QSSGDataView<quint32> inKeySet) const { return getBitValue(A8toR8, inKeySet); } |
| void setA8Swizzled(QSSGDataRef<quint32> inKeySet, bool val) { setBitValue(A8toR8, val, inKeySet); } |
| |
| bool isL8A8Swizzled(QSSGDataView<quint32> inKeySet) const { return getBitValue(L8A8toRG8, inKeySet); } |
| void setL8A8Swizzled(QSSGDataRef<quint32> inKeySet, bool val) { setBitValue(L8A8toRG8, val, inKeySet); } |
| |
| bool isL16Swizzled(QSSGDataView<quint32> inKeySet) const { return getBitValue(L16toR16, inKeySet); } |
| void setL16Swizzled(QSSGDataRef<quint32> inKeySet, bool val) { setBitValue(L16toR16, val, inKeySet); } |
| |
| void toString(QString &ioStr, QSSGDataView<quint32> inKeySet) const |
| { |
| ioStr.append(QString::fromLocal8Bit(name)); |
| ioStr.append(QStringLiteral("={")); |
| internalToString(ioStr, "noswizzle", isNoSwizzled(inKeySet)); |
| ioStr.append(QStringLiteral(";")); |
| internalToString(ioStr, "l8swizzle", isL8Swizzled(inKeySet)); |
| ioStr.append(QStringLiteral(";")); |
| internalToString(ioStr, "a8swizzle", isA8Swizzled(inKeySet)); |
| ioStr.append(QStringLiteral(";")); |
| internalToString(ioStr, "l8a8swizzle", isL8A8Swizzled(inKeySet)); |
| ioStr.append(QStringLiteral(";")); |
| internalToString(ioStr, "l16swizzle", isL16Swizzled(inKeySet)); |
| ioStr.append(QStringLiteral("}")); |
| } |
| }; |
| |
| struct QSSGShaderKeyImageMap : public QSSGShaderKeyUnsigned<6> |
| { |
| enum ImageMapBits { |
| Enabled = 1 << 0, |
| EnvMap = 1 << 1, |
| LightProbe = 1 << 2, |
| InvertUV = 1 << 3, |
| Premultiplied = 1 << 4, |
| Identity = 1 << 5 |
| }; |
| |
| QSSGShaderKeyImageMap(const char *inName = "") : QSSGShaderKeyUnsigned<6>(inName) {} |
| |
| bool getBitValue(ImageMapBits imageBit, QSSGDataView<quint32> inKeySet) const |
| { |
| return (getValue(inKeySet) & imageBit) ? true : false; |
| } |
| |
| void setBitValue(ImageMapBits imageBit, bool inValue, QSSGDataRef<quint32> inKeySet) |
| { |
| quint32 theValue = getValue(inKeySet); |
| quint32 mask = imageBit; |
| if (inValue) { |
| theValue = theValue | mask; |
| } else { |
| mask = ~mask; |
| theValue = theValue & mask; |
| } |
| setValue(inKeySet, theValue); |
| } |
| |
| bool isEnabled(QSSGDataView<quint32> inKeySet) const { return getBitValue(Enabled, inKeySet); } |
| void setEnabled(QSSGDataRef<quint32> inKeySet, bool val) { setBitValue(Enabled, val, inKeySet); } |
| |
| bool isEnvMap(QSSGDataView<quint32> inKeySet) const { return getBitValue(EnvMap, inKeySet); } |
| void setEnvMap(QSSGDataRef<quint32> inKeySet, bool val) { setBitValue(EnvMap, val, inKeySet); } |
| |
| bool isLightProbe(QSSGDataView<quint32> inKeySet) const { return getBitValue(LightProbe, inKeySet); } |
| void setLightProbe(QSSGDataRef<quint32> inKeySet, bool val) { setBitValue(LightProbe, val, inKeySet); } |
| |
| bool isInvertUVMap(QSSGDataView<quint32> inKeySet) const { return getBitValue(InvertUV, inKeySet); } |
| void setInvertUVMap(QSSGDataRef<quint32> inKeySet, bool val) { setBitValue(InvertUV, val, inKeySet); } |
| |
| bool isPremultiplied(QSSGDataView<quint32> inKeySet) const { return getBitValue(Premultiplied, inKeySet); } |
| void setPremultiplied(QSSGDataRef<quint32> inKeySet, bool val) { setBitValue(Premultiplied, val, inKeySet); } |
| |
| bool isIdentityTransform(QSSGDataView<quint32> inKeySet) const { return getBitValue(Identity, inKeySet); } |
| void setIdentityTransform(QSSGDataRef<quint32> inKeySet, bool val) { setBitValue(Identity, val, inKeySet); } |
| |
| void toString(QString &ioStr, QSSGDataView<quint32> inKeySet) const |
| { |
| ioStr.append(QString::fromLocal8Bit(name)); |
| ioStr.append(QStringLiteral("={")); |
| internalToString(ioStr, "enabled", isEnabled(inKeySet)); |
| ioStr.append(QStringLiteral(";")); |
| internalToString(ioStr, "envMap", isEnvMap(inKeySet)); |
| ioStr.append(QStringLiteral(";")); |
| internalToString(ioStr, "lightProbe", isLightProbe(inKeySet)); |
| ioStr.append(QStringLiteral(";")); |
| internalToString(ioStr, "invertUV", isInvertUVMap(inKeySet)); |
| ioStr.append(QStringLiteral(";")); |
| internalToString(ioStr, "premultiplied", isPremultiplied(inKeySet)); |
| ioStr.append(QStringLiteral(";")); |
| internalToString(ioStr, "identity", isIdentityTransform(inKeySet)); |
| ioStr.append(QStringLiteral("}")); |
| } |
| }; |
| |
| struct QSSGShaderKeySpecularModel : QSSGShaderKeyUnsigned<2> |
| { |
| QSSGShaderKeySpecularModel(const char *inName = "") : QSSGShaderKeyUnsigned<2>(inName) {} |
| |
| void setSpecularModel(QSSGDataRef<quint32> inKeySet, QSSGRenderDefaultMaterial::MaterialSpecularModel inModel) |
| { |
| setValue(inKeySet, quint32(inModel)); |
| } |
| |
| QSSGRenderDefaultMaterial::MaterialSpecularModel getSpecularModel(QSSGDataView<quint32> inKeySet) const |
| { |
| return static_cast<QSSGRenderDefaultMaterial::MaterialSpecularModel>(getValue(inKeySet)); |
| } |
| |
| void toString(QString &ioStr, QSSGDataView<quint32> inKeySet) const |
| { |
| ioStr.append(QString::fromLocal8Bit(name)); |
| ioStr.append(QStringLiteral("=")); |
| switch (getSpecularModel(inKeySet)) { |
| case QSSGRenderDefaultMaterial::MaterialSpecularModel::KGGX: |
| ioStr.append(QStringLiteral("KGGX")); |
| break; |
| case QSSGRenderDefaultMaterial::MaterialSpecularModel::KWard: |
| ioStr.append(QStringLiteral("KWard")); |
| break; |
| case QSSGRenderDefaultMaterial::MaterialSpecularModel::Default: |
| ioStr.append(QStringLiteral("Default")); |
| break; |
| } |
| ioStr.append(QStringLiteral(";")); |
| } |
| }; |
| |
| struct QSSGShaderKeyAlphaMode : QSSGShaderKeyUnsigned<2> |
| { |
| QSSGShaderKeyAlphaMode(const char *inName = "") : QSSGShaderKeyUnsigned<2>(inName) {} |
| |
| void setAlphaMode(QSSGDataRef<quint32> inKeySet, QSSGRenderDefaultMaterial::MaterialAlphaMode inMode) |
| { |
| setValue(inKeySet, quint32(inMode)); |
| } |
| |
| QSSGRenderDefaultMaterial::MaterialAlphaMode getAlphaMode(QSSGDataView<quint32> inKeySet) const |
| { |
| return static_cast<QSSGRenderDefaultMaterial::MaterialAlphaMode>(getValue(inKeySet)); |
| } |
| |
| void toString(QString &ioStr, QSSGDataView<quint32> inKeySet) const |
| { |
| ioStr.append(QString::fromLocal8Bit(name)); |
| ioStr.append(QStringLiteral("=")); |
| switch (getAlphaMode(inKeySet)) { |
| case QSSGRenderDefaultMaterial::MaterialAlphaMode::Opaque: |
| ioStr.append(QStringLiteral("Opaque")); |
| break; |
| case QSSGRenderDefaultMaterial::MaterialAlphaMode::Mask: |
| ioStr.append(QStringLiteral("Mask")); |
| break; |
| case QSSGRenderDefaultMaterial::MaterialAlphaMode::Blend: |
| ioStr.append(QStringLiteral("Blend")); |
| break; |
| case QSSGRenderDefaultMaterial::MaterialAlphaMode::Default: |
| ioStr.append(QStringLiteral("Default")); |
| break; |
| } |
| ioStr.append(QStringLiteral(";")); |
| } |
| }; |
| |
| |
| struct QSSGShaderDefaultMaterialKeyProperties |
| { |
| enum { |
| LightCount = 7, |
| }; |
| enum ImageMapNames { |
| DiffuseMap = 0, |
| EmissiveMap, |
| SpecularMap, |
| OpacityMap, |
| BumpMap, |
| SpecularAmountMap, |
| NormalMap, |
| DisplacementMap, |
| TranslucencyMap, |
| LightmapIndirect, |
| LightmapRadiosity, |
| LightmapShadow, |
| RoughnessMap, |
| BaseColorMap, |
| MetalnessMap, |
| OcclusionMap, |
| ImageMapCount |
| }; |
| |
| QSSGShaderKeyBoolean m_hasLighting; |
| QSSGShaderKeyBoolean m_hasIbl; |
| QSSGShaderKeyUnsigned<3> m_lightCount; |
| QSSGShaderKeyBoolean m_lightFlags[LightCount]; |
| QSSGShaderKeyBoolean m_lightAreaFlags[LightCount]; |
| QSSGShaderKeyBoolean m_lightShadowFlags[LightCount]; |
| QSSGShaderKeyBoolean m_specularEnabled; |
| QSSGShaderKeyBoolean m_fresnelEnabled; |
| QSSGShaderKeyBoolean m_vertexColorsEnabled; |
| QSSGShaderKeySpecularModel m_specularModel; |
| QSSGShaderKeyImageMap m_imageMaps[ImageMapCount]; |
| QSSGShaderKeyTextureSwizzle m_textureSwizzle[ImageMapCount]; |
| QSSGShaderKeyTessellation m_tessellationMode; |
| QSSGShaderKeyBoolean m_hasSkinning; |
| QSSGShaderKeyBoolean m_wireframeMode; |
| QSSGShaderKeyBoolean m_isDoubleSided; |
| QSSGShaderKeyAlphaMode m_alphaMode; |
| |
| QSSGShaderDefaultMaterialKeyProperties() |
| : m_hasLighting("hasLighting") |
| , m_hasIbl("hasIbl") |
| , m_lightCount("lightCount") |
| , m_specularEnabled("specularEnabled") |
| , m_fresnelEnabled("fresnelEnabled") |
| , m_vertexColorsEnabled("vertexColorsEnabled") |
| , m_specularModel("specularModel") |
| , m_tessellationMode("tessellationMode") |
| , m_hasSkinning("hasSkinning") |
| , m_wireframeMode("wireframeMode") |
| , m_isDoubleSided("isDoubleSided") |
| , m_alphaMode("alphaMode") |
| { |
| m_lightFlags[0].name = "light0HasPosition"; |
| m_lightFlags[1].name = "light1HasPosition"; |
| m_lightFlags[2].name = "light2HasPosition"; |
| m_lightFlags[3].name = "light3HasPosition"; |
| m_lightFlags[4].name = "light4HasPosition"; |
| m_lightFlags[5].name = "light5HasPosition"; |
| m_lightFlags[6].name = "light6HasPosition"; |
| m_lightAreaFlags[0].name = "light0HasArea"; |
| m_lightAreaFlags[1].name = "light1HasArea"; |
| m_lightAreaFlags[2].name = "light2HasArea"; |
| m_lightAreaFlags[3].name = "light3HasArea"; |
| m_lightAreaFlags[4].name = "light4HasArea"; |
| m_lightAreaFlags[5].name = "light5HasArea"; |
| m_lightAreaFlags[6].name = "light6HasArea"; |
| m_lightShadowFlags[0].name = "light0HasShadow"; |
| m_lightShadowFlags[1].name = "light1HasShadow"; |
| m_lightShadowFlags[2].name = "light2HasShadow"; |
| m_lightShadowFlags[3].name = "light3HasShadow"; |
| m_lightShadowFlags[4].name = "light4HasShadow"; |
| m_lightShadowFlags[5].name = "light5HasShadow"; |
| m_lightShadowFlags[6].name = "light6HasShadow"; |
| m_imageMaps[0].name = "diffuseMap"; |
| m_imageMaps[1].name = "emissiveMap"; |
| m_imageMaps[2].name = "specularMap"; |
| m_imageMaps[3].name = "opacityMap"; |
| m_imageMaps[4].name = "bumpMap"; |
| m_imageMaps[5].name = "specularAmountMap"; |
| m_imageMaps[6].name = "normalMap"; |
| m_imageMaps[7].name = "displacementMap"; |
| m_imageMaps[8].name = "translucencyMap"; |
| m_imageMaps[9].name = "lightmapIndirect"; |
| m_imageMaps[10].name = "lightmapRadiosity"; |
| m_imageMaps[11].name = "lightmapShadow"; |
| m_imageMaps[12].name = "roughnessMap"; |
| m_imageMaps[13].name = "baseColorMap"; |
| m_imageMaps[14].name = "metalnessMap"; |
| m_imageMaps[15].name = "occlusionMap"; |
| m_textureSwizzle[0].name = "diffuseMap_swizzle"; |
| m_textureSwizzle[1].name = "emissiveMap_swizzle"; |
| m_textureSwizzle[2].name = "specularMap_swizzle"; |
| m_textureSwizzle[3].name = "opacityMap_swizzle"; |
| m_textureSwizzle[4].name = "bumpMap_swizzle"; |
| m_textureSwizzle[5].name = "specularAmountMap_swizzle"; |
| m_textureSwizzle[6].name = "normalMap_swizzle"; |
| m_textureSwizzle[7].name = "displacementMap_swizzle"; |
| m_textureSwizzle[8].name = "translucencyMap_swizzle"; |
| m_textureSwizzle[9].name = "lightmapIndirect_swizzle"; |
| m_textureSwizzle[10].name = "lightmapRadiosity_swizzle"; |
| m_textureSwizzle[11].name = "lightmapShadow_swizzle"; |
| m_textureSwizzle[12].name = "roughnessMap_swizzle"; |
| m_textureSwizzle[13].name = "baseColorMap_swizzle"; |
| m_textureSwizzle[14].name = "metalnessMap_swizzle"; |
| m_textureSwizzle[15].name = "occlusionMap_swizzle"; |
| setPropertyOffsets(); |
| } |
| |
| template<typename TVisitor> |
| void visitProperties(TVisitor &inVisitor) |
| { |
| inVisitor.visit(m_hasLighting); |
| inVisitor.visit(m_hasIbl); |
| inVisitor.visit(m_lightCount); |
| |
| for (quint32 idx = 0, end = LightCount; idx < end; ++idx) { |
| inVisitor.visit(m_lightFlags[idx]); |
| } |
| |
| for (quint32 idx = 0, end = LightCount; idx < end; ++idx) { |
| inVisitor.visit(m_lightAreaFlags[idx]); |
| } |
| |
| for (quint32 idx = 0, end = LightCount; idx < end; ++idx) { |
| inVisitor.visit(m_lightShadowFlags[idx]); |
| } |
| |
| inVisitor.visit(m_specularEnabled); |
| inVisitor.visit(m_fresnelEnabled); |
| inVisitor.visit(m_vertexColorsEnabled); |
| inVisitor.visit(m_specularModel); |
| |
| for (quint32 idx = 0, end = ImageMapCount; idx < end; ++idx) { |
| inVisitor.visit(m_imageMaps[idx]); |
| inVisitor.visit(m_textureSwizzle[idx]); |
| } |
| |
| inVisitor.visit(m_tessellationMode); |
| inVisitor.visit(m_hasSkinning); |
| inVisitor.visit(m_wireframeMode); |
| inVisitor.visit(m_isDoubleSided); |
| inVisitor.visit(m_alphaMode); |
| } |
| |
| struct OffsetVisitor |
| { |
| quint32 m_offset; |
| OffsetVisitor() : m_offset(0) {} |
| template<typename TPropType> |
| void visit(TPropType &inProp) |
| { |
| // if we cross the 32 bit border we just move |
| // to the next dword. |
| // This cost a few extra bits but prevents tedious errors like |
| // loosing shader key bits because they got moved beyond the 32 border |
| quint32 bit = m_offset % 32; |
| if (bit + TPropType::BitWidth > 31) { |
| m_offset += 32 - bit; |
| } |
| |
| inProp.setOffset(m_offset); |
| m_offset += TPropType::BitWidth; |
| } |
| }; |
| |
| void setPropertyOffsets() |
| { |
| OffsetVisitor visitor; |
| visitProperties(visitor); |
| // If this assert fires, then the default material key needs more bits. |
| Q_ASSERT(visitor.m_offset < 256); |
| } |
| }; |
| |
| struct QSSGShaderDefaultMaterialKey |
| { |
| enum { |
| DataBufferSize = 8, |
| }; |
| quint32 m_dataBuffer[DataBufferSize]; |
| uint m_featureSetHash; |
| |
| QSSGShaderDefaultMaterialKey(uint inFeatureSetHash) : m_featureSetHash(inFeatureSetHash) |
| { |
| for (size_t idx = 0; idx < DataBufferSize; ++idx) |
| m_dataBuffer[idx] = 0; |
| } |
| |
| QSSGShaderDefaultMaterialKey() : m_featureSetHash(0) |
| { |
| for (size_t idx = 0; idx < DataBufferSize; ++idx) |
| m_dataBuffer[idx] = 0; |
| } |
| |
| uint hash() const |
| { |
| uint retval = 0; |
| for (size_t idx = 0; idx < DataBufferSize; ++idx) |
| retval = retval ^ qHash(m_dataBuffer[idx]); |
| return retval ^ m_featureSetHash; |
| } |
| |
| bool operator==(const QSSGShaderDefaultMaterialKey &other) const |
| { |
| bool retval = true; |
| for (size_t idx = 0; idx < DataBufferSize && retval; ++idx) |
| retval = m_dataBuffer[idx] == other.m_dataBuffer[idx]; |
| return retval && m_featureSetHash == other.m_featureSetHash; |
| } |
| |
| // Cast operators to make getting properties easier. |
| operator QSSGDataRef<quint32>() { return toDataRef(m_dataBuffer, DataBufferSize); } |
| operator QSSGDataView<quint32>() const { return toDataView(m_dataBuffer, DataBufferSize); } |
| |
| struct StringVisitor |
| { |
| QByteArray &m_str; |
| QSSGDataView<quint32> m_keyStore; |
| StringVisitor(QByteArray &s, QSSGDataView<quint32> ks) : m_str(s), m_keyStore(ks) {} |
| template<typename TPropType> |
| void visit(const TPropType &prop) |
| { |
| quint32 originalSize = m_str.size(); |
| if (m_str.size()) |
| m_str.append(";"); |
| QString str = QString::fromUtf8(m_str); |
| prop.toString(str, m_keyStore); |
| // if the only thing we added was the semicolon |
| // then nuke the semicolon |
| m_str = str.toLocal8Bit(); |
| if (originalSize && m_str.size() == int(originalSize + 1)) |
| m_str.resize(int(originalSize)); |
| } |
| }; |
| |
| void toString(QByteArray &ioString, QSSGShaderDefaultMaterialKeyProperties &inProperties) const |
| { |
| StringVisitor theVisitor(ioString, *this); |
| inProperties.visitProperties(theVisitor); |
| } |
| }; |
| |
| Q_STATIC_ASSERT(std::is_trivially_destructible<QSSGShaderDefaultMaterialKey>::value); |
| |
| |
| inline uint qHash(const QSSGShaderDefaultMaterialKey &key) |
| { |
| return key.hash(); |
| } |
| |
| QT_END_NAMESPACE |
| |
| #endif |