Remove qshadergraph files
- Those files were moved as part of Qt3D as its the sole user of these - Also removed associated unit tests Pick-to: 6.2 5.15 Change-Id: I302bc219218a58071c86d2447cb4449601fca32c Reviewed-by: Edward Welbourne <edward.welbourne@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Mike Krus <mike.krus@kdab.com>bb10
parent
f2040b8939
commit
0263cfdfa0
|
|
@ -250,13 +250,6 @@ qt_internal_add_module(Gui
|
|||
util/qktxhandler.cpp util/qktxhandler_p.h
|
||||
util/qlayoutpolicy.cpp util/qlayoutpolicy_p.h
|
||||
util/qpkmhandler.cpp util/qpkmhandler_p.h
|
||||
util/qshaderformat.cpp util/qshaderformat_p.h
|
||||
util/qshadergraph.cpp util/qshadergraph_p.h
|
||||
util/qshadergraphloader.cpp util/qshadergraphloader_p.h
|
||||
util/qshaderlanguage.cpp util/qshaderlanguage_p.h
|
||||
util/qshadernode.cpp util/qshadernode_p.h
|
||||
util/qshadernodeport.cpp util/qshadernodeport_p.h
|
||||
util/qshadernodesloader.cpp util/qshadernodesloader_p.h
|
||||
util/qtexturefiledata.cpp util/qtexturefiledata_p.h
|
||||
util/qtexturefilehandler_p.h
|
||||
util/qtexturefilereader.cpp util/qtexturefilereader_p.h
|
||||
|
|
@ -812,11 +805,6 @@ qt_internal_extend_target(Gui CONDITION NOT QT_FEATURE_system_zlib AND NOT no_co
|
|||
Qt::Core
|
||||
)
|
||||
|
||||
qt_internal_extend_target(Gui CONDITION QT_FEATURE_regularexpression
|
||||
SOURCES
|
||||
util/qshadergenerator.cpp util/qshadergenerator_p.h
|
||||
)
|
||||
|
||||
qt_internal_extend_target(Gui CONDITION QT_FEATURE_undocommand
|
||||
SOURCES
|
||||
util/qundostack.cpp util/qundostack.h util/qundostack_p.h
|
||||
|
|
|
|||
|
|
@ -1,145 +0,0 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtGui module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** 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 Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or 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.GPL2 and 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-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qshaderformat_p.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
QShaderFormat::QShaderFormat() noexcept
|
||||
: m_api(NoApi)
|
||||
, m_shaderType(Fragment)
|
||||
{
|
||||
}
|
||||
|
||||
QShaderFormat::Api QShaderFormat::api() const noexcept
|
||||
{
|
||||
return m_api;
|
||||
}
|
||||
|
||||
void QShaderFormat::setApi(QShaderFormat::Api api) noexcept
|
||||
{
|
||||
m_api = api;
|
||||
}
|
||||
|
||||
QVersionNumber QShaderFormat::version() const noexcept
|
||||
{
|
||||
return m_version;
|
||||
}
|
||||
|
||||
void QShaderFormat::setVersion(const QVersionNumber &version) noexcept
|
||||
{
|
||||
m_version = version;
|
||||
}
|
||||
|
||||
QStringList QShaderFormat::extensions() const noexcept
|
||||
{
|
||||
return m_extensions;
|
||||
}
|
||||
|
||||
void QShaderFormat::setExtensions(const QStringList &extensions) noexcept
|
||||
{
|
||||
m_extensions = extensions;
|
||||
m_extensions.sort();
|
||||
}
|
||||
|
||||
QString QShaderFormat::vendor() const noexcept
|
||||
{
|
||||
return m_vendor;
|
||||
}
|
||||
|
||||
void QShaderFormat::setVendor(const QString &vendor) noexcept
|
||||
{
|
||||
m_vendor = vendor;
|
||||
}
|
||||
|
||||
bool QShaderFormat::isValid() const noexcept
|
||||
{
|
||||
return m_api != NoApi && m_version.majorVersion() > 0;
|
||||
}
|
||||
|
||||
bool QShaderFormat::supports(const QShaderFormat &other) const noexcept
|
||||
{
|
||||
if (!isValid() || !other.isValid())
|
||||
return false;
|
||||
|
||||
if (m_api == OpenGLES && m_api != other.m_api)
|
||||
return false;
|
||||
|
||||
if (m_api == OpenGLCoreProfile && m_api != other.m_api)
|
||||
return false;
|
||||
|
||||
if (m_version < other.m_version)
|
||||
return false;
|
||||
|
||||
if (m_shaderType != other.m_shaderType)
|
||||
return false;
|
||||
|
||||
const auto containsAllExtensionsFromOther = std::includes(m_extensions.constBegin(),
|
||||
m_extensions.constEnd(),
|
||||
other.m_extensions.constBegin(),
|
||||
other.m_extensions.constEnd());
|
||||
if (!containsAllExtensionsFromOther)
|
||||
return false;
|
||||
|
||||
if (!other.m_vendor.isEmpty() && m_vendor != other.m_vendor)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QShaderFormat::ShaderType QShaderFormat::shaderType() const noexcept
|
||||
{
|
||||
return m_shaderType;
|
||||
}
|
||||
|
||||
void QShaderFormat::setShaderType(QShaderFormat::ShaderType shaderType) noexcept
|
||||
{
|
||||
m_shaderType = shaderType;
|
||||
}
|
||||
|
||||
bool operator==(const QShaderFormat &lhs, const QShaderFormat &rhs) noexcept
|
||||
{
|
||||
return lhs.api() == rhs.api()
|
||||
&& lhs.version() == rhs.version()
|
||||
&& lhs.extensions() == rhs.extensions()
|
||||
&& lhs.vendor() == rhs.vendor()
|
||||
&& lhs.shaderType() == rhs.shaderType();
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
@ -1,123 +0,0 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtGui module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** 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 Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or 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.GPL2 and 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-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QSHADERFORMAT_P_H
|
||||
#define QSHADERFORMAT_P_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 <QtGui/private/qtguiglobal_p.h>
|
||||
|
||||
#include <QtCore/qstringlist.h>
|
||||
#include <QtCore/qversionnumber.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QShaderFormat
|
||||
{
|
||||
public:
|
||||
enum Api : int {
|
||||
NoApi,
|
||||
OpenGLNoProfile,
|
||||
OpenGLCoreProfile,
|
||||
OpenGLCompatibilityProfile,
|
||||
OpenGLES,
|
||||
VulkanFlavoredGLSL
|
||||
};
|
||||
|
||||
enum ShaderType : int {
|
||||
Vertex = 0,
|
||||
TessellationControl,
|
||||
TessellationEvaluation,
|
||||
Geometry,
|
||||
Fragment,
|
||||
Compute
|
||||
};
|
||||
|
||||
Q_GUI_EXPORT QShaderFormat() noexcept;
|
||||
|
||||
Q_GUI_EXPORT Api api() const noexcept;
|
||||
Q_GUI_EXPORT void setApi(Api api) noexcept;
|
||||
|
||||
Q_GUI_EXPORT QVersionNumber version() const noexcept;
|
||||
Q_GUI_EXPORT void setVersion(const QVersionNumber &version) noexcept;
|
||||
|
||||
Q_GUI_EXPORT QStringList extensions() const noexcept;
|
||||
Q_GUI_EXPORT void setExtensions(const QStringList &extensions) noexcept;
|
||||
|
||||
Q_GUI_EXPORT QString vendor() const noexcept;
|
||||
Q_GUI_EXPORT void setVendor(const QString &vendor) noexcept;
|
||||
|
||||
Q_GUI_EXPORT bool isValid() const noexcept;
|
||||
Q_GUI_EXPORT bool supports(const QShaderFormat &other) const noexcept;
|
||||
|
||||
Q_GUI_EXPORT ShaderType shaderType() const noexcept;
|
||||
Q_GUI_EXPORT void setShaderType(ShaderType shaderType) noexcept;
|
||||
|
||||
private:
|
||||
Api m_api;
|
||||
QVersionNumber m_version;
|
||||
QStringList m_extensions;
|
||||
QString m_vendor;
|
||||
ShaderType m_shaderType;
|
||||
};
|
||||
|
||||
Q_GUI_EXPORT bool operator==(const QShaderFormat &lhs, const QShaderFormat &rhs) noexcept;
|
||||
|
||||
inline bool operator!=(const QShaderFormat &lhs, const QShaderFormat &rhs) noexcept
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
Q_DECLARE_TYPEINFO(QShaderFormat, Q_RELOCATABLE_TYPE);
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
Q_DECLARE_METATYPE(QShaderFormat)
|
||||
|
||||
#endif // QSHADERFORMAT_P_H
|
||||
|
|
@ -1,638 +0,0 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtGui module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** 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 Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or 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.GPL2 and 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-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qshadergenerator_p.h"
|
||||
|
||||
#include "qshaderlanguage_p.h"
|
||||
#include <QRegularExpression>
|
||||
|
||||
#include <cctype>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
Q_LOGGING_CATEGORY(ShaderGenerator, "ShaderGenerator", QtWarningMsg)
|
||||
|
||||
namespace
|
||||
{
|
||||
QByteArray toGlsl(QShaderLanguage::StorageQualifier qualifier, const QShaderFormat &format)
|
||||
{
|
||||
if (format.version().majorVersion() <= 2) {
|
||||
// Note we're assuming fragment shader only here, it'd be different
|
||||
// values for vertex shader, will need to be fixed properly at some
|
||||
// point but isn't necessary yet (this problem already exists in past
|
||||
// commits anyway)
|
||||
switch (qualifier) {
|
||||
case QShaderLanguage::Const:
|
||||
return "const";
|
||||
case QShaderLanguage::Input:
|
||||
if (format.shaderType() == QShaderFormat::Vertex)
|
||||
return "attribute";
|
||||
else
|
||||
return "varying";
|
||||
case QShaderLanguage::Output:
|
||||
return ""; // Although fragment shaders for <=2 only have fixed outputs
|
||||
case QShaderLanguage::Uniform:
|
||||
return "uniform";
|
||||
case QShaderLanguage::BuiltIn:
|
||||
return "//";
|
||||
}
|
||||
} else {
|
||||
switch (qualifier) {
|
||||
case QShaderLanguage::Const:
|
||||
return "const";
|
||||
case QShaderLanguage::Input:
|
||||
return "in";
|
||||
case QShaderLanguage::Output:
|
||||
return "out";
|
||||
case QShaderLanguage::Uniform:
|
||||
return "uniform";
|
||||
case QShaderLanguage::BuiltIn:
|
||||
return "//";
|
||||
}
|
||||
}
|
||||
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
QByteArray toGlsl(QShaderLanguage::VariableType type)
|
||||
{
|
||||
switch (type) {
|
||||
case QShaderLanguage::Bool:
|
||||
return "bool";
|
||||
case QShaderLanguage::Int:
|
||||
return "int";
|
||||
case QShaderLanguage::Uint:
|
||||
return "uint";
|
||||
case QShaderLanguage::Float:
|
||||
return "float";
|
||||
case QShaderLanguage::Double:
|
||||
return "double";
|
||||
case QShaderLanguage::Vec2:
|
||||
return "vec2";
|
||||
case QShaderLanguage::Vec3:
|
||||
return "vec3";
|
||||
case QShaderLanguage::Vec4:
|
||||
return "vec4";
|
||||
case QShaderLanguage::DVec2:
|
||||
return "dvec2";
|
||||
case QShaderLanguage::DVec3:
|
||||
return "dvec3";
|
||||
case QShaderLanguage::DVec4:
|
||||
return "dvec4";
|
||||
case QShaderLanguage::BVec2:
|
||||
return "bvec2";
|
||||
case QShaderLanguage::BVec3:
|
||||
return "bvec3";
|
||||
case QShaderLanguage::BVec4:
|
||||
return "bvec4";
|
||||
case QShaderLanguage::IVec2:
|
||||
return "ivec2";
|
||||
case QShaderLanguage::IVec3:
|
||||
return "ivec3";
|
||||
case QShaderLanguage::IVec4:
|
||||
return "ivec4";
|
||||
case QShaderLanguage::UVec2:
|
||||
return "uvec2";
|
||||
case QShaderLanguage::UVec3:
|
||||
return "uvec3";
|
||||
case QShaderLanguage::UVec4:
|
||||
return "uvec4";
|
||||
case QShaderLanguage::Mat2:
|
||||
return "mat2";
|
||||
case QShaderLanguage::Mat3:
|
||||
return "mat3";
|
||||
case QShaderLanguage::Mat4:
|
||||
return "mat4";
|
||||
case QShaderLanguage::Mat2x2:
|
||||
return "mat2x2";
|
||||
case QShaderLanguage::Mat2x3:
|
||||
return "mat2x3";
|
||||
case QShaderLanguage::Mat2x4:
|
||||
return "mat2x4";
|
||||
case QShaderLanguage::Mat3x2:
|
||||
return "mat3x2";
|
||||
case QShaderLanguage::Mat3x3:
|
||||
return "mat3x3";
|
||||
case QShaderLanguage::Mat3x4:
|
||||
return "mat3x4";
|
||||
case QShaderLanguage::Mat4x2:
|
||||
return "mat4x2";
|
||||
case QShaderLanguage::Mat4x3:
|
||||
return "mat4x3";
|
||||
case QShaderLanguage::Mat4x4:
|
||||
return "mat4x4";
|
||||
case QShaderLanguage::DMat2:
|
||||
return "dmat2";
|
||||
case QShaderLanguage::DMat3:
|
||||
return "dmat3";
|
||||
case QShaderLanguage::DMat4:
|
||||
return "dmat4";
|
||||
case QShaderLanguage::DMat2x2:
|
||||
return "dmat2x2";
|
||||
case QShaderLanguage::DMat2x3:
|
||||
return "dmat2x3";
|
||||
case QShaderLanguage::DMat2x4:
|
||||
return "dmat2x4";
|
||||
case QShaderLanguage::DMat3x2:
|
||||
return "dmat3x2";
|
||||
case QShaderLanguage::DMat3x3:
|
||||
return "dmat3x3";
|
||||
case QShaderLanguage::DMat3x4:
|
||||
return "dmat3x4";
|
||||
case QShaderLanguage::DMat4x2:
|
||||
return "dmat4x2";
|
||||
case QShaderLanguage::DMat4x3:
|
||||
return "dmat4x3";
|
||||
case QShaderLanguage::DMat4x4:
|
||||
return "dmat4x4";
|
||||
case QShaderLanguage::Sampler1D:
|
||||
return "sampler1D";
|
||||
case QShaderLanguage::Sampler2D:
|
||||
return "sampler2D";
|
||||
case QShaderLanguage::Sampler3D:
|
||||
return "sampler3D";
|
||||
case QShaderLanguage::SamplerCube:
|
||||
return "samplerCube";
|
||||
case QShaderLanguage::Sampler2DRect:
|
||||
return "sampler2DRect";
|
||||
case QShaderLanguage::Sampler2DMs:
|
||||
return "sampler2DMS";
|
||||
case QShaderLanguage::SamplerBuffer:
|
||||
return "samplerBuffer";
|
||||
case QShaderLanguage::Sampler1DArray:
|
||||
return "sampler1DArray";
|
||||
case QShaderLanguage::Sampler2DArray:
|
||||
return "sampler2DArray";
|
||||
case QShaderLanguage::Sampler2DMsArray:
|
||||
return "sampler2DMSArray";
|
||||
case QShaderLanguage::SamplerCubeArray:
|
||||
return "samplerCubeArray";
|
||||
case QShaderLanguage::Sampler1DShadow:
|
||||
return "sampler1DShadow";
|
||||
case QShaderLanguage::Sampler2DShadow:
|
||||
return "sampler2DShadow";
|
||||
case QShaderLanguage::Sampler2DRectShadow:
|
||||
return "sampler2DRectShadow";
|
||||
case QShaderLanguage::Sampler1DArrayShadow:
|
||||
return "sampler1DArrayShadow";
|
||||
case QShaderLanguage::Sampler2DArrayShadow:
|
||||
return "sample2DArrayShadow";
|
||||
case QShaderLanguage::SamplerCubeShadow:
|
||||
return "samplerCubeShadow";
|
||||
case QShaderLanguage::SamplerCubeArrayShadow:
|
||||
return "samplerCubeArrayShadow";
|
||||
case QShaderLanguage::ISampler1D:
|
||||
return "isampler1D";
|
||||
case QShaderLanguage::ISampler2D:
|
||||
return "isampler2D";
|
||||
case QShaderLanguage::ISampler3D:
|
||||
return "isampler3D";
|
||||
case QShaderLanguage::ISamplerCube:
|
||||
return "isamplerCube";
|
||||
case QShaderLanguage::ISampler2DRect:
|
||||
return "isampler2DRect";
|
||||
case QShaderLanguage::ISampler2DMs:
|
||||
return "isampler2DMS";
|
||||
case QShaderLanguage::ISamplerBuffer:
|
||||
return "isamplerBuffer";
|
||||
case QShaderLanguage::ISampler1DArray:
|
||||
return "isampler1DArray";
|
||||
case QShaderLanguage::ISampler2DArray:
|
||||
return "isampler2DArray";
|
||||
case QShaderLanguage::ISampler2DMsArray:
|
||||
return "isampler2DMSArray";
|
||||
case QShaderLanguage::ISamplerCubeArray:
|
||||
return "isamplerCubeArray";
|
||||
case QShaderLanguage::USampler1D:
|
||||
return "usampler1D";
|
||||
case QShaderLanguage::USampler2D:
|
||||
return "usampler2D";
|
||||
case QShaderLanguage::USampler3D:
|
||||
return "usampler3D";
|
||||
case QShaderLanguage::USamplerCube:
|
||||
return "usamplerCube";
|
||||
case QShaderLanguage::USampler2DRect:
|
||||
return "usampler2DRect";
|
||||
case QShaderLanguage::USampler2DMs:
|
||||
return "usampler2DMS";
|
||||
case QShaderLanguage::USamplerBuffer:
|
||||
return "usamplerBuffer";
|
||||
case QShaderLanguage::USampler1DArray:
|
||||
return "usampler1DArray";
|
||||
case QShaderLanguage::USampler2DArray:
|
||||
return "usampler2DArray";
|
||||
case QShaderLanguage::USampler2DMsArray:
|
||||
return "usampler2DMSArray";
|
||||
case QShaderLanguage::USamplerCubeArray:
|
||||
return "usamplerCubeArray";
|
||||
}
|
||||
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
QByteArray replaceParameters(const QByteArray &original, const QShaderNode &node, const QShaderFormat &format)
|
||||
{
|
||||
QByteArray result = original;
|
||||
|
||||
const QStringList parameterNames = node.parameterNames();
|
||||
for (const QString ¶meterName : parameterNames) {
|
||||
const QByteArray placeholder = QByteArray(QByteArrayLiteral("$") + parameterName.toUtf8());
|
||||
const QVariant parameter = node.parameter(parameterName);
|
||||
if (parameter.userType() == qMetaTypeId<QShaderLanguage::StorageQualifier>()) {
|
||||
const QShaderLanguage::StorageQualifier qualifier = qvariant_cast<QShaderLanguage::StorageQualifier>(parameter);
|
||||
const QByteArray value = toGlsl(qualifier, format);
|
||||
result.replace(placeholder, value);
|
||||
} else if (parameter.userType() == qMetaTypeId<QShaderLanguage::VariableType>()) {
|
||||
const QShaderLanguage::VariableType type = qvariant_cast<QShaderLanguage::VariableType>(parameter);
|
||||
const QByteArray value = toGlsl(type);
|
||||
result.replace(placeholder, value);
|
||||
} else {
|
||||
const QByteArray value = parameter.toString().toUtf8();
|
||||
result.replace(placeholder, value);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers) const
|
||||
{
|
||||
auto code = QByteArrayList();
|
||||
|
||||
if (format.isValid()) {
|
||||
const bool isGLES = format.api() == QShaderFormat::OpenGLES;
|
||||
const int major = format.version().majorVersion();
|
||||
const int minor = format.version().minorVersion();
|
||||
|
||||
const int version = major == 2 && isGLES ? 100
|
||||
: major == 3 && isGLES ? 300
|
||||
: major == 2 ? 100 + 10 * (minor + 1)
|
||||
: major == 3 && minor <= 2 ? 100 + 10 * (minor + 3)
|
||||
: major * 100 + minor * 10;
|
||||
|
||||
const QByteArray profile = isGLES && version > 100 ? QByteArrayLiteral(" es")
|
||||
: version >= 150 && format.api() == QShaderFormat::OpenGLCoreProfile ? QByteArrayLiteral(" core")
|
||||
: version >= 150 && format.api() == QShaderFormat::OpenGLCompatibilityProfile ? QByteArrayLiteral(" compatibility")
|
||||
: QByteArray();
|
||||
|
||||
code << (QByteArrayLiteral("#version ") + QByteArray::number(version) + profile);
|
||||
code << QByteArray();
|
||||
}
|
||||
|
||||
const auto intersectsEnabledLayers = [enabledLayers] (const QStringList &layers) {
|
||||
return layers.isEmpty()
|
||||
|| std::any_of(layers.cbegin(), layers.cend(),
|
||||
[enabledLayers] (const QString &s) { return enabledLayers.contains(s); });
|
||||
};
|
||||
|
||||
QList<QString> globalInputVariables;
|
||||
const QRegularExpression globalInputExtractRegExp(QStringLiteral("^.*\\s+(\\w+).*;$"));
|
||||
|
||||
const QList<QShaderNode> nodes = graph.nodes();
|
||||
for (const QShaderNode &node : nodes) {
|
||||
if (intersectsEnabledLayers(node.layers())) {
|
||||
const QByteArrayList headerSnippets = node.rule(format).headerSnippets;
|
||||
for (const QByteArray &snippet : headerSnippets) {
|
||||
code << replaceParameters(snippet, node, format);
|
||||
|
||||
// If node is an input, record the variable name into the globalInputVariables list
|
||||
if (node.type() == QShaderNode::Input) {
|
||||
const QRegularExpressionMatch match = globalInputExtractRegExp.match(QString::fromUtf8(code.last()));
|
||||
if (match.hasMatch())
|
||||
globalInputVariables.push_back(match.captured(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
code << QByteArray();
|
||||
code << QByteArrayLiteral("void main()");
|
||||
code << QByteArrayLiteral("{");
|
||||
|
||||
const QRegularExpression temporaryVariableToAssignmentRegExp(QStringLiteral("([^;]*\\s+(v\\d+))\\s*=\\s*([^;]*);"));
|
||||
const QRegularExpression temporaryVariableInAssignmentRegExp(QStringLiteral("\\W*(v\\d+)\\W*"));
|
||||
const QRegularExpression statementRegExp(QStringLiteral("\\s*(\\w+)\\s*=\\s*([^;]*);"));
|
||||
|
||||
struct Variable;
|
||||
|
||||
struct Assignment
|
||||
{
|
||||
QString expression;
|
||||
QList<Variable *> referencedVariables;
|
||||
};
|
||||
|
||||
struct Variable
|
||||
{
|
||||
enum Type {
|
||||
GlobalInput,
|
||||
TemporaryAssignment,
|
||||
Output
|
||||
};
|
||||
|
||||
QString name;
|
||||
QString declaration;
|
||||
int referenceCount = 0;
|
||||
Assignment assignment;
|
||||
Type type = TemporaryAssignment;
|
||||
bool substituted = false;
|
||||
|
||||
static void substitute(Variable *v)
|
||||
{
|
||||
if (v->substituted)
|
||||
return;
|
||||
|
||||
qCDebug(ShaderGenerator) << "Begin Substituting " << v->name << " = " << v->assignment.expression;
|
||||
for (Variable *ref : qAsConst(v->assignment.referencedVariables)) {
|
||||
// Recursively substitute
|
||||
Variable::substitute(ref);
|
||||
|
||||
// Replace all variables referenced only once in the assignment
|
||||
// by their actual expression
|
||||
if (ref->referenceCount == 1 || ref->type == Variable::GlobalInput) {
|
||||
const QRegularExpression r(QStringLiteral("(.*\\b)(%1)(\\b.*)").arg(ref->name));
|
||||
if (v->assignment.referencedVariables.size() == 1)
|
||||
v->assignment.expression.replace(r,
|
||||
QStringLiteral("\\1%2\\3").arg(ref->assignment.expression));
|
||||
else
|
||||
v->assignment.expression.replace(r,
|
||||
QStringLiteral("(\\1%2\\3)").arg(ref->assignment.expression));
|
||||
}
|
||||
}
|
||||
qCDebug(ShaderGenerator) << "Done Substituting " << v->name << " = " << v->assignment.expression;
|
||||
v->substituted = true;
|
||||
}
|
||||
};
|
||||
|
||||
struct LineContent
|
||||
{
|
||||
QByteArray rawContent;
|
||||
Variable *var = nullptr;
|
||||
};
|
||||
|
||||
// Table to store temporary variables that should be replaced:
|
||||
// - If variable references a a global variables
|
||||
// -> we will use the global variable directly
|
||||
// - If variable references a function results
|
||||
// -> will be kept only if variable is referenced more than once.
|
||||
// This avoids having vec3 v56 = vertexPosition; when we could
|
||||
// just use vertexPosition directly.
|
||||
// The added benefit is when having arrays, we don't try to create
|
||||
// mat4 v38 = skinningPalelette[100] which would be invalid
|
||||
QList<Variable> temporaryVariables;
|
||||
// Reserve more than enough space to ensure no reallocation will take place
|
||||
temporaryVariables.reserve(nodes.size() * 8);
|
||||
|
||||
QList<LineContent> lines;
|
||||
|
||||
auto createVariable = [&] () -> Variable * {
|
||||
Q_ASSERT(temporaryVariables.capacity() > 0);
|
||||
temporaryVariables.resize(temporaryVariables.size() + 1);
|
||||
return &temporaryVariables.last();
|
||||
};
|
||||
|
||||
auto findVariable = [&] (const QString &name) -> Variable * {
|
||||
const auto end = temporaryVariables.end();
|
||||
auto it = std::find_if(temporaryVariables.begin(), end,
|
||||
[=] (const Variable &a) { return a.name == name; });
|
||||
if (it != end)
|
||||
return &(*it);
|
||||
return nullptr;
|
||||
};
|
||||
|
||||
auto gatherTemporaryVariablesFromAssignment = [&] (Variable *v, const QString &assignmentContent) {
|
||||
QRegularExpressionMatchIterator subMatchIt = temporaryVariableInAssignmentRegExp.globalMatch(assignmentContent);
|
||||
while (subMatchIt.hasNext()) {
|
||||
const QRegularExpressionMatch subMatch = subMatchIt.next();
|
||||
const QString variableName = subMatch.captured(1);
|
||||
|
||||
// Variable we care about should already exists -> an expression cannot reference a variable that hasn't been defined
|
||||
Variable *u = findVariable(variableName);
|
||||
Q_ASSERT(u);
|
||||
|
||||
// Increase reference count for u
|
||||
++u->referenceCount;
|
||||
// Insert u as reference for variable v
|
||||
v->assignment.referencedVariables.push_back(u);
|
||||
}
|
||||
};
|
||||
|
||||
for (const QShaderGraph::Statement &statement : graph.createStatements(enabledLayers)) {
|
||||
const QShaderNode node = statement.node;
|
||||
QByteArray line = node.rule(format).substitution;
|
||||
const QList<QShaderNodePort> ports = node.ports();
|
||||
|
||||
struct VariableReplacement {
|
||||
QByteArray placeholder;
|
||||
QByteArray variable;
|
||||
};
|
||||
|
||||
QList<VariableReplacement> variableReplacements;
|
||||
|
||||
// Generate temporary variable names vN
|
||||
for (const QShaderNodePort &port : ports) {
|
||||
const QString portName = port.name;
|
||||
const QShaderNodePort::Direction portDirection = port.direction;
|
||||
const bool isInput = port.direction == QShaderNodePort::Input;
|
||||
|
||||
const int portIndex = statement.portIndex(portDirection, portName);
|
||||
|
||||
Q_ASSERT(portIndex >= 0);
|
||||
|
||||
const int variableIndex = isInput ? statement.inputs.at(portIndex)
|
||||
: statement.outputs.at(portIndex);
|
||||
if (variableIndex < 0)
|
||||
continue;
|
||||
|
||||
VariableReplacement replacement;
|
||||
replacement.placeholder = QByteArrayLiteral("$") + portName.toUtf8();
|
||||
replacement.variable = QByteArrayLiteral("v") + QByteArray::number(variableIndex);
|
||||
|
||||
variableReplacements.append(std::move(replacement));
|
||||
}
|
||||
|
||||
int begin = 0;
|
||||
while ((begin = line.indexOf('$', begin)) != -1) {
|
||||
int end = begin + 1;
|
||||
char endChar = line.at(end);
|
||||
const int size = line.size();
|
||||
while (end < size && (std::isalnum(endChar) || endChar == '_')) {
|
||||
++end;
|
||||
endChar = line.at(end);
|
||||
}
|
||||
|
||||
const int placeholderLength = end - begin;
|
||||
|
||||
const QByteArray variableName = line.mid(begin, placeholderLength);
|
||||
const auto replacementIt = std::find_if(variableReplacements.cbegin(), variableReplacements.cend(),
|
||||
[&variableName](const VariableReplacement &replacement) {
|
||||
return variableName == replacement.placeholder;
|
||||
});
|
||||
|
||||
if (replacementIt != variableReplacements.cend()) {
|
||||
line.replace(begin, placeholderLength, replacementIt->variable);
|
||||
begin += replacementIt->variable.length();
|
||||
} else {
|
||||
begin = end;
|
||||
}
|
||||
}
|
||||
|
||||
// Substitute variable names by generated vN variable names
|
||||
const QByteArray substitutionedLine = replaceParameters(line, node, format);
|
||||
|
||||
QRegularExpressionMatchIterator matches;
|
||||
|
||||
switch (node.type()) {
|
||||
case QShaderNode::Input:
|
||||
case QShaderNode::Output:
|
||||
matches = statementRegExp.globalMatch(QString::fromUtf8(substitutionedLine));
|
||||
break;
|
||||
case QShaderNode::Function:
|
||||
matches = temporaryVariableToAssignmentRegExp.globalMatch(QString::fromUtf8(substitutionedLine));
|
||||
break;
|
||||
case QShaderNode::Invalid:
|
||||
break;
|
||||
}
|
||||
|
||||
while (matches.hasNext()) {
|
||||
QRegularExpressionMatch match = matches.next();
|
||||
|
||||
Variable *v = nullptr;
|
||||
|
||||
switch (node.type()) {
|
||||
// Record name of temporary variable that possibly references a global input
|
||||
// We will replace the temporary variables by the matching global variables later
|
||||
case QShaderNode::Input: {
|
||||
const QString localVariable = match.captured(1);
|
||||
const QString globalVariable = match.captured(2);
|
||||
|
||||
v = createVariable();
|
||||
v->name = localVariable;
|
||||
v->type = Variable::GlobalInput;
|
||||
|
||||
Assignment assignment;
|
||||
assignment.expression = globalVariable;
|
||||
v->assignment = assignment;
|
||||
break;
|
||||
}
|
||||
|
||||
case QShaderNode::Function: {
|
||||
const QString localVariableDeclaration = match.captured(1);
|
||||
const QString localVariableName = match.captured(2);
|
||||
const QString assignmentContent = match.captured(3);
|
||||
|
||||
// Add new variable -> it cannot exist already
|
||||
v = createVariable();
|
||||
v->name = localVariableName;
|
||||
v->declaration = localVariableDeclaration;
|
||||
v->assignment.expression = assignmentContent;
|
||||
|
||||
// Find variables that may be referenced in the assignment
|
||||
gatherTemporaryVariablesFromAssignment(v, assignmentContent);
|
||||
break;
|
||||
}
|
||||
|
||||
case QShaderNode::Output: {
|
||||
const QString outputDeclaration = match.captured(1);
|
||||
const QString assignmentContent = match.captured(2);
|
||||
|
||||
v = createVariable();
|
||||
v->name = outputDeclaration;
|
||||
v->declaration = outputDeclaration;
|
||||
v->type = Variable::Output;
|
||||
|
||||
Assignment assignment;
|
||||
assignment.expression = assignmentContent;
|
||||
v->assignment = assignment;
|
||||
|
||||
// Find variables that may be referenced in the assignment
|
||||
gatherTemporaryVariablesFromAssignment(v, assignmentContent);
|
||||
break;
|
||||
}
|
||||
case QShaderNode::Invalid:
|
||||
break;
|
||||
}
|
||||
|
||||
LineContent lineContent;
|
||||
lineContent.rawContent = QByteArray(QByteArrayLiteral(" ") + substitutionedLine);
|
||||
lineContent.var = v;
|
||||
lines << lineContent;
|
||||
}
|
||||
}
|
||||
|
||||
// Go through all lines
|
||||
// Perform substitution of line with temporary variables substitution
|
||||
for (LineContent &lineContent : lines) {
|
||||
Variable *v = lineContent.var;
|
||||
qCDebug(ShaderGenerator) << lineContent.rawContent;
|
||||
if (v != nullptr) {
|
||||
Variable::substitute(v);
|
||||
|
||||
qCDebug(ShaderGenerator) << "Line " << lineContent.rawContent << "is assigned to temporary" << v->name;
|
||||
|
||||
// Check number of occurrences a temporary variable is referenced
|
||||
if (v->referenceCount == 1 || v->type == Variable::GlobalInput) {
|
||||
// If it is referenced only once, no point in creating a temporary
|
||||
// Clear content for current line
|
||||
lineContent.rawContent.clear();
|
||||
// We assume expression that were referencing vN will have vN properly substituted
|
||||
} else {
|
||||
lineContent.rawContent = QStringLiteral(" %1 = %2;").arg(v->declaration)
|
||||
.arg(v->assignment.expression)
|
||||
.toUtf8();
|
||||
}
|
||||
|
||||
qCDebug(ShaderGenerator) << "Updated Line is " << lineContent.rawContent;
|
||||
}
|
||||
}
|
||||
|
||||
// Go throug all lines and insert content
|
||||
for (const LineContent &lineContent : qAsConst(lines)) {
|
||||
if (!lineContent.rawContent.isEmpty()) {
|
||||
code << lineContent.rawContent;
|
||||
}
|
||||
}
|
||||
|
||||
code << QByteArrayLiteral("}");
|
||||
code << QByteArray();
|
||||
|
||||
return code.join('\n');
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtGui module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** 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 Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or 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.GPL2 and 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-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QSHADERGENERATOR_P_H
|
||||
#define QSHADERGENERATOR_P_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 <QtGui/private/qtguiglobal_p.h>
|
||||
|
||||
#include <QtGui/private/qshadergraph_p.h>
|
||||
#include <QtCore/QLoggingCategory>
|
||||
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(ShaderGenerator)
|
||||
|
||||
class QShaderGenerator
|
||||
{
|
||||
public:
|
||||
Q_GUI_EXPORT QByteArray createShaderCode(const QStringList &enabledLayers = QStringList()) const;
|
||||
|
||||
QShaderGraph graph;
|
||||
QShaderFormat format;
|
||||
};
|
||||
|
||||
Q_DECLARE_TYPEINFO(QShaderGenerator, Q_RELOCATABLE_TYPE);
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
Q_DECLARE_METATYPE(QShaderGenerator)
|
||||
|
||||
#endif // QSHADERGENERATOR_P_H
|
||||
|
|
@ -1,316 +0,0 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtGui module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** 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 Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or 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.GPL2 and 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-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qshadergraph_p.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
QList<QShaderNode> copyOutputNodes(const QList<QShaderNode> &nodes, const QList<QShaderGraph::Edge> &edges)
|
||||
{
|
||||
auto res = QList<QShaderNode>();
|
||||
std::copy_if(nodes.cbegin(), nodes.cend(),
|
||||
std::back_inserter(res),
|
||||
[&edges] (const QShaderNode &node) {
|
||||
return node.type() == QShaderNode::Output ||
|
||||
(node.type() == QShaderNode::Function &&
|
||||
!std::any_of(edges.cbegin(),
|
||||
edges.cend(),
|
||||
[&node] (const QShaderGraph::Edge &edge) {
|
||||
return edge.sourceNodeUuid ==
|
||||
node.uuid();
|
||||
}));
|
||||
});
|
||||
return res;
|
||||
}
|
||||
|
||||
QList<QShaderGraph::Edge> incomingEdges(const QList<QShaderGraph::Edge> &edges, const QUuid &uuid)
|
||||
{
|
||||
auto res = QList<QShaderGraph::Edge>();
|
||||
std::copy_if(edges.cbegin(), edges.cend(),
|
||||
std::back_inserter(res),
|
||||
[uuid] (const QShaderGraph::Edge &edge) {
|
||||
return edge.sourceNodeUuid == uuid;
|
||||
});
|
||||
return res;
|
||||
}
|
||||
|
||||
QList<QShaderGraph::Edge> outgoingEdges(const QList<QShaderGraph::Edge> &edges, const QUuid &uuid)
|
||||
{
|
||||
auto res = QList<QShaderGraph::Edge>();
|
||||
std::copy_if(edges.cbegin(), edges.cend(),
|
||||
std::back_inserter(res),
|
||||
[uuid] (const QShaderGraph::Edge &edge) {
|
||||
return edge.targetNodeUuid == uuid;
|
||||
});
|
||||
return res;
|
||||
}
|
||||
|
||||
QShaderGraph::Statement nodeToStatement(const QShaderNode &node, int &nextVarId)
|
||||
{
|
||||
auto statement = QShaderGraph::Statement();
|
||||
statement.node = node;
|
||||
|
||||
const QList<QShaderNodePort> ports = node.ports();
|
||||
for (const QShaderNodePort &port : ports) {
|
||||
if (port.direction == QShaderNodePort::Input) {
|
||||
statement.inputs.append(-1);
|
||||
} else {
|
||||
statement.outputs.append(nextVarId);
|
||||
nextVarId++;
|
||||
}
|
||||
}
|
||||
return statement;
|
||||
}
|
||||
|
||||
QShaderGraph::Statement completeStatement(const QHash<QUuid, QShaderGraph::Statement> &idHash,
|
||||
const QList<QShaderGraph::Edge> edges,
|
||||
const QUuid &uuid)
|
||||
{
|
||||
auto targetStatement = idHash.value(uuid);
|
||||
for (const QShaderGraph::Edge &edge : edges) {
|
||||
if (edge.targetNodeUuid != uuid)
|
||||
continue;
|
||||
|
||||
const QShaderGraph::Statement sourceStatement = idHash.value(edge.sourceNodeUuid);
|
||||
const int sourcePortIndex = sourceStatement.portIndex(QShaderNodePort::Output, edge.sourcePortName);
|
||||
const int targetPortIndex = targetStatement.portIndex(QShaderNodePort::Input, edge.targetPortName);
|
||||
|
||||
if (sourcePortIndex < 0 || targetPortIndex < 0)
|
||||
continue;
|
||||
|
||||
const QList<int> sourceOutputs = sourceStatement.outputs;
|
||||
QList<int> &targetInputs = targetStatement.inputs;
|
||||
targetInputs[targetPortIndex] = sourceOutputs[sourcePortIndex];
|
||||
}
|
||||
return targetStatement;
|
||||
}
|
||||
|
||||
void removeNodesWithUnboundInputs(QList<QShaderGraph::Statement> &statements,
|
||||
const QList<QShaderGraph::Edge> &allEdges)
|
||||
{
|
||||
// A node is invalid if any of its input ports is disconected
|
||||
// or connected to the output port of another invalid node.
|
||||
|
||||
// Keeps track of the edges from the nodes we know to be valid
|
||||
// to unvisited nodes
|
||||
auto currentEdges = QList<QShaderGraph::Edge>();
|
||||
|
||||
statements.erase(std::remove_if(statements.begin(),
|
||||
statements.end(),
|
||||
[¤tEdges, &allEdges] (const QShaderGraph::Statement &statement) {
|
||||
const QShaderNode &node = statement.node;
|
||||
const QList<QShaderGraph::Edge> outgoing = outgoingEdges(currentEdges, node.uuid());
|
||||
const QList<QShaderNodePort> ports = node.ports();
|
||||
|
||||
bool allInputsConnected = true;
|
||||
for (const QShaderNodePort &port : node.ports()) {
|
||||
if (port.direction == QShaderNodePort::Output)
|
||||
continue;
|
||||
|
||||
const auto edgeIt = std::find_if(outgoing.cbegin(),
|
||||
outgoing.cend(),
|
||||
[&port] (const QShaderGraph::Edge &edge) {
|
||||
return edge.targetPortName == port.name;
|
||||
});
|
||||
|
||||
if (edgeIt != outgoing.cend())
|
||||
currentEdges.removeAll(*edgeIt);
|
||||
else
|
||||
allInputsConnected = false;
|
||||
}
|
||||
|
||||
if (allInputsConnected) {
|
||||
const QList<QShaderGraph::Edge> incoming = incomingEdges(allEdges, node.uuid());
|
||||
currentEdges.append(incoming);
|
||||
}
|
||||
|
||||
return !allInputsConnected;
|
||||
}),
|
||||
statements.end());
|
||||
}
|
||||
}
|
||||
|
||||
QUuid QShaderGraph::Statement::uuid() const noexcept
|
||||
{
|
||||
return node.uuid();
|
||||
}
|
||||
|
||||
int QShaderGraph::Statement::portIndex(QShaderNodePort::Direction direction, const QString &portName) const noexcept
|
||||
{
|
||||
const QList<QShaderNodePort> ports = node.ports();
|
||||
int index = 0;
|
||||
for (const QShaderNodePort &port : ports) {
|
||||
if (port.name == portName && port.direction == direction)
|
||||
return index;
|
||||
else if (port.direction == direction)
|
||||
index++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void QShaderGraph::addNode(const QShaderNode &node)
|
||||
{
|
||||
removeNode(node);
|
||||
m_nodes.append(node);
|
||||
}
|
||||
|
||||
void QShaderGraph::removeNode(const QShaderNode &node)
|
||||
{
|
||||
const auto it = std::find_if(m_nodes.begin(), m_nodes.end(),
|
||||
[node] (const QShaderNode &n) { return n.uuid() == node.uuid(); });
|
||||
if (it != m_nodes.end())
|
||||
m_nodes.erase(it);
|
||||
}
|
||||
|
||||
QList<QShaderNode> QShaderGraph::nodes() const noexcept
|
||||
{
|
||||
return m_nodes;
|
||||
}
|
||||
|
||||
void QShaderGraph::addEdge(const QShaderGraph::Edge &edge)
|
||||
{
|
||||
if (m_edges.contains(edge))
|
||||
return;
|
||||
m_edges.append(edge);
|
||||
}
|
||||
|
||||
void QShaderGraph::removeEdge(const QShaderGraph::Edge &edge)
|
||||
{
|
||||
m_edges.removeAll(edge);
|
||||
}
|
||||
|
||||
QList<QShaderGraph::Edge> QShaderGraph::edges() const noexcept
|
||||
{
|
||||
return m_edges;
|
||||
}
|
||||
|
||||
QList<QShaderGraph::Statement> QShaderGraph::createStatements(const QStringList &enabledLayers) const
|
||||
{
|
||||
const auto intersectsEnabledLayers = [enabledLayers] (const QStringList &layers) {
|
||||
return layers.isEmpty()
|
||||
|| std::any_of(layers.cbegin(), layers.cend(),
|
||||
[enabledLayers] (const QString &s) { return enabledLayers.contains(s); });
|
||||
};
|
||||
|
||||
const QList<QShaderNode> enabledNodes = [this, intersectsEnabledLayers] {
|
||||
auto res = QList<QShaderNode>();
|
||||
std::copy_if(m_nodes.cbegin(), m_nodes.cend(),
|
||||
std::back_inserter(res),
|
||||
[intersectsEnabledLayers] (const QShaderNode &node) {
|
||||
return intersectsEnabledLayers(node.layers());
|
||||
});
|
||||
return res;
|
||||
}();
|
||||
|
||||
const QList<Edge> enabledEdges = [this, intersectsEnabledLayers] {
|
||||
auto res = QList<Edge>();
|
||||
std::copy_if(m_edges.cbegin(), m_edges.cend(),
|
||||
std::back_inserter(res),
|
||||
[intersectsEnabledLayers] (const Edge &edge) {
|
||||
return intersectsEnabledLayers(edge.layers);
|
||||
});
|
||||
return res;
|
||||
}();
|
||||
|
||||
const QHash<QUuid, Statement> idHash = [enabledNodes] {
|
||||
auto nextVarId = 0;
|
||||
auto res = QHash<QUuid, Statement>();
|
||||
for (const QShaderNode &node : enabledNodes)
|
||||
res.insert(node.uuid(), nodeToStatement(node, nextVarId));
|
||||
return res;
|
||||
}();
|
||||
|
||||
auto result = QList<Statement>();
|
||||
QList<Edge> currentEdges = enabledEdges;
|
||||
QList<QUuid> currentUuids = [enabledNodes, enabledEdges] {
|
||||
const QList<QShaderNode> inputs = copyOutputNodes(enabledNodes, enabledEdges);
|
||||
auto res = QList<QUuid>();
|
||||
std::transform(inputs.cbegin(), inputs.cend(),
|
||||
std::back_inserter(res),
|
||||
[](const QShaderNode &node) { return node.uuid(); });
|
||||
return res;
|
||||
}();
|
||||
|
||||
// Implements Kahn's algorithm to flatten the graph
|
||||
// https://en.wikipedia.org/wiki/Topological_sorting#Kahn.27s_algorithm
|
||||
//
|
||||
// We implement it with a small twist though, we follow the edges backward
|
||||
// because we want to track the dependencies from the output nodes and not the
|
||||
// input nodes
|
||||
while (!currentUuids.isEmpty()) {
|
||||
const QUuid uuid = currentUuids.takeFirst();
|
||||
result.append(completeStatement(idHash, enabledEdges, uuid));
|
||||
|
||||
const QList<QShaderGraph::Edge> outgoing = outgoingEdges(currentEdges, uuid);
|
||||
for (const QShaderGraph::Edge &outgoingEdge : outgoing) {
|
||||
currentEdges.removeAll(outgoingEdge);
|
||||
const QUuid nextUuid = outgoingEdge.sourceNodeUuid;
|
||||
const QList<QShaderGraph::Edge> incoming = incomingEdges(currentEdges, nextUuid);
|
||||
if (incoming.isEmpty()) {
|
||||
currentUuids.append(nextUuid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::reverse(result.begin(), result.end());
|
||||
|
||||
removeNodesWithUnboundInputs(result, enabledEdges);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool operator==(const QShaderGraph::Edge &lhs, const QShaderGraph::Edge &rhs) noexcept
|
||||
{
|
||||
return lhs.sourceNodeUuid == rhs.sourceNodeUuid
|
||||
&& lhs.sourcePortName == rhs.sourcePortName
|
||||
&& lhs.targetNodeUuid == rhs.targetNodeUuid
|
||||
&& lhs.targetPortName == rhs.targetPortName;
|
||||
}
|
||||
|
||||
bool operator==(const QShaderGraph::Statement &lhs, const QShaderGraph::Statement &rhs) noexcept
|
||||
{
|
||||
return lhs.inputs == rhs.inputs
|
||||
&& lhs.outputs == rhs.outputs
|
||||
&& lhs.node.uuid() == rhs.node.uuid();
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
@ -1,124 +0,0 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtGui module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** 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 Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or 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.GPL2 and 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-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QSHADERGRAPH_P_H
|
||||
#define QSHADERGRAPH_P_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 <QtGui/private/qtguiglobal_p.h>
|
||||
|
||||
#include <QtGui/private/qshadernode_p.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QShaderGraph
|
||||
{
|
||||
public:
|
||||
class Edge
|
||||
{
|
||||
public:
|
||||
QStringList layers;
|
||||
QUuid sourceNodeUuid;
|
||||
QString sourcePortName;
|
||||
QUuid targetNodeUuid;
|
||||
QString targetPortName;
|
||||
};
|
||||
|
||||
class Statement
|
||||
{
|
||||
public:
|
||||
Q_GUI_EXPORT QUuid uuid() const noexcept;
|
||||
Q_GUI_EXPORT int portIndex(QShaderNodePort::Direction direction, const QString &portName) const noexcept;
|
||||
|
||||
QShaderNode node;
|
||||
QList<int> inputs;
|
||||
QList<int> outputs;
|
||||
};
|
||||
|
||||
Q_GUI_EXPORT void addNode(const QShaderNode &node);
|
||||
Q_GUI_EXPORT void removeNode(const QShaderNode &node);
|
||||
Q_GUI_EXPORT QList<QShaderNode> nodes() const noexcept;
|
||||
|
||||
Q_GUI_EXPORT void addEdge(const Edge &edge);
|
||||
Q_GUI_EXPORT void removeEdge(const Edge &edge);
|
||||
Q_GUI_EXPORT QList<Edge> edges() const noexcept;
|
||||
|
||||
Q_GUI_EXPORT QList<Statement>
|
||||
createStatements(const QStringList &enabledLayers = QStringList()) const;
|
||||
|
||||
private:
|
||||
QList<QShaderNode> m_nodes;
|
||||
QList<Edge> m_edges;
|
||||
};
|
||||
|
||||
Q_GUI_EXPORT bool operator==(const QShaderGraph::Edge &lhs, const QShaderGraph::Edge &rhs) noexcept;
|
||||
|
||||
inline bool operator!=(const QShaderGraph::Edge &lhs, const QShaderGraph::Edge &rhs) noexcept
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
Q_GUI_EXPORT bool operator==(const QShaderGraph::Statement &lhs, const QShaderGraph::Statement &rhs) noexcept;
|
||||
|
||||
inline bool operator!=(const QShaderGraph::Statement &lhs, const QShaderGraph::Statement &rhs) noexcept
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
Q_DECLARE_TYPEINFO(QShaderGraph, Q_RELOCATABLE_TYPE);
|
||||
Q_DECLARE_TYPEINFO(QShaderGraph::Edge, Q_RELOCATABLE_TYPE);
|
||||
Q_DECLARE_TYPEINFO(QShaderGraph::Statement, Q_RELOCATABLE_TYPE);
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
Q_DECLARE_METATYPE(QShaderGraph)
|
||||
Q_DECLARE_METATYPE(QShaderGraph::Edge)
|
||||
Q_DECLARE_METATYPE(QShaderGraph::Statement)
|
||||
|
||||
#endif // QSHADERGRAPH_P_H
|
||||
|
|
@ -1,269 +0,0 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtGui module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** 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 Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or 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.GPL2 and 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-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qshadergraphloader_p.h"
|
||||
|
||||
#include "qshadernodesloader_p.h"
|
||||
|
||||
#include <QtCore/qdebug.h>
|
||||
#include <QtCore/qiodevice.h>
|
||||
#include <QtCore/qjsonarray.h>
|
||||
#include <QtCore/qjsondocument.h>
|
||||
#include <QtCore/qjsonobject.h>
|
||||
#include <QtCore/qmetaobject.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
void qt_register_ShaderLanguage_enums();
|
||||
|
||||
QShaderGraphLoader::QShaderGraphLoader() noexcept
|
||||
: m_status(Null),
|
||||
m_device(nullptr)
|
||||
{
|
||||
qt_register_ShaderLanguage_enums();
|
||||
}
|
||||
|
||||
QShaderGraphLoader::Status QShaderGraphLoader::status() const noexcept
|
||||
{
|
||||
return m_status;
|
||||
}
|
||||
|
||||
QShaderGraph QShaderGraphLoader::graph() const noexcept
|
||||
{
|
||||
return m_graph;
|
||||
}
|
||||
|
||||
QIODevice *QShaderGraphLoader::device() const noexcept
|
||||
{
|
||||
return m_device;
|
||||
}
|
||||
|
||||
void QShaderGraphLoader::setDevice(QIODevice *device) noexcept
|
||||
{
|
||||
m_device = device;
|
||||
m_graph = QShaderGraph();
|
||||
m_status = !m_device ? Null
|
||||
: (m_device->openMode() & QIODevice::ReadOnly) ? Waiting
|
||||
: Error;
|
||||
}
|
||||
|
||||
QHash<QString, QShaderNode> QShaderGraphLoader::prototypes() const noexcept
|
||||
{
|
||||
return m_prototypes;
|
||||
}
|
||||
|
||||
void QShaderGraphLoader::setPrototypes(const QHash<QString, QShaderNode> &prototypes) noexcept
|
||||
{
|
||||
m_prototypes = prototypes;
|
||||
}
|
||||
|
||||
void QShaderGraphLoader::load()
|
||||
{
|
||||
if (m_status == Error)
|
||||
return;
|
||||
|
||||
auto error = QJsonParseError();
|
||||
const QJsonDocument document = QJsonDocument::fromJson(m_device->readAll(), &error);
|
||||
|
||||
if (error.error != QJsonParseError::NoError) {
|
||||
qWarning() << "Invalid JSON document:" << error.errorString();
|
||||
m_status = Error;
|
||||
return;
|
||||
}
|
||||
|
||||
if (document.isEmpty() || !document.isObject()) {
|
||||
qWarning() << "Invalid JSON document, root should be an object";
|
||||
m_status = Error;
|
||||
return;
|
||||
}
|
||||
|
||||
const QJsonObject root = document.object();
|
||||
|
||||
const QJsonValue nodesValue = root.value(QStringLiteral("nodes"));
|
||||
if (!nodesValue.isArray()) {
|
||||
qWarning() << "Invalid nodes property, should be an array";
|
||||
m_status = Error;
|
||||
return;
|
||||
}
|
||||
|
||||
const QJsonValue edgesValue = root.value(QStringLiteral("edges"));
|
||||
if (!edgesValue.isArray()) {
|
||||
qWarning() << "Invalid edges property, should be an array";
|
||||
m_status = Error;
|
||||
return;
|
||||
}
|
||||
|
||||
bool hasError = false;
|
||||
|
||||
const QJsonValue prototypesValue = root.value(QStringLiteral("prototypes"));
|
||||
if (!prototypesValue.isUndefined()) {
|
||||
if (prototypesValue.isObject()) {
|
||||
QShaderNodesLoader loader;
|
||||
loader.load(prototypesValue.toObject());
|
||||
m_prototypes.insert(loader.nodes());
|
||||
} else {
|
||||
qWarning() << "Invalid prototypes property, should be an object";
|
||||
m_status = Error;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const QJsonArray nodes = nodesValue.toArray();
|
||||
for (const QJsonValue nodeValue : nodes) {
|
||||
if (!nodeValue.isObject()) {
|
||||
qWarning() << "Invalid node found";
|
||||
hasError = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
const QJsonObject nodeObject = nodeValue.toObject();
|
||||
|
||||
const QString uuidString = nodeObject.value(QStringLiteral("uuid")).toString();
|
||||
const QUuid uuid = QUuid(uuidString);
|
||||
if (uuid.isNull()) {
|
||||
qWarning() << "Invalid UUID found in node:" << uuidString;
|
||||
hasError = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
const QString type = nodeObject.value(QStringLiteral("type")).toString();
|
||||
if (!m_prototypes.contains(type)) {
|
||||
qWarning() << "Unsupported node type found:" << type;
|
||||
hasError = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
const QJsonArray layersArray = nodeObject.value(QStringLiteral("layers")).toArray();
|
||||
auto layers = QStringList();
|
||||
for (const QJsonValue layerValue : layersArray) {
|
||||
layers.append(layerValue.toString());
|
||||
}
|
||||
|
||||
QShaderNode node = m_prototypes.value(type);
|
||||
node.setUuid(uuid);
|
||||
node.setLayers(layers);
|
||||
|
||||
const QJsonValue parametersValue = nodeObject.value(QStringLiteral("parameters"));
|
||||
if (parametersValue.isObject()) {
|
||||
const QJsonObject parametersObject = parametersValue.toObject();
|
||||
for (const QString ¶meterName : parametersObject.keys()) {
|
||||
const QJsonValue parameterValue = parametersObject.value(parameterName);
|
||||
if (parameterValue.isObject()) {
|
||||
const QJsonObject parameterObject = parameterValue.toObject();
|
||||
const QString type = parameterObject.value(QStringLiteral("type")).toString();
|
||||
const auto metaType = QMetaType::fromName(type.toUtf8());
|
||||
|
||||
const QString value = parameterObject.value(QStringLiteral("value")).toString();
|
||||
auto variant = QVariant(value);
|
||||
|
||||
if (metaType.flags() & QMetaType::IsEnumeration) {
|
||||
const QMetaObject *metaObject = metaType.metaObject();
|
||||
const char *className = metaObject->className();
|
||||
const QByteArray enumName = type.mid(static_cast<int>(qstrlen(className)) + 2).toUtf8();
|
||||
const QMetaEnum metaEnum = metaObject->enumerator(metaObject->indexOfEnumerator(enumName));
|
||||
const int enumValue = metaEnum.keyToValue(value.toUtf8());
|
||||
variant = QVariant(enumValue);
|
||||
variant.convert(metaType);
|
||||
} else {
|
||||
variant.convert(metaType);
|
||||
}
|
||||
node.setParameter(parameterName, variant);
|
||||
} else {
|
||||
node.setParameter(parameterName, parameterValue.toVariant());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_graph.addNode(node);
|
||||
}
|
||||
|
||||
const QJsonArray edges = edgesValue.toArray();
|
||||
for (const QJsonValue edgeValue : edges) {
|
||||
if (!edgeValue.isObject()) {
|
||||
qWarning() << "Invalid edge found";
|
||||
hasError = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
const QJsonObject edgeObject = edgeValue.toObject();
|
||||
|
||||
const QString sourceUuidString = edgeObject.value(QStringLiteral("sourceUuid")).toString();
|
||||
const QUuid sourceUuid = QUuid(sourceUuidString);
|
||||
if (sourceUuid.isNull()) {
|
||||
qWarning() << "Invalid source UUID found in edge:" << sourceUuidString;
|
||||
hasError = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
const QString sourcePort = edgeObject.value(QStringLiteral("sourcePort")).toString();
|
||||
|
||||
const QString targetUuidString = edgeObject.value(QStringLiteral("targetUuid")).toString();
|
||||
const QUuid targetUuid = QUuid(targetUuidString);
|
||||
if (targetUuid.isNull()) {
|
||||
qWarning() << "Invalid target UUID found in edge:" << targetUuidString;
|
||||
hasError = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
const QString targetPort = edgeObject.value(QStringLiteral("targetPort")).toString();
|
||||
|
||||
const QJsonArray layersArray = edgeObject.value(QStringLiteral("layers")).toArray();
|
||||
auto layers = QStringList();
|
||||
for (const QJsonValue layerValue : layersArray) {
|
||||
layers.append(layerValue.toString());
|
||||
}
|
||||
|
||||
auto edge = QShaderGraph::Edge();
|
||||
edge.sourceNodeUuid = sourceUuid;
|
||||
edge.sourcePortName = sourcePort;
|
||||
edge.targetNodeUuid = targetUuid;
|
||||
edge.targetPortName = targetPort;
|
||||
edge.layers = layers;
|
||||
m_graph.addEdge(edge);
|
||||
}
|
||||
|
||||
if (hasError) {
|
||||
m_status = Error;
|
||||
m_graph = QShaderGraph();
|
||||
} else {
|
||||
m_status = Ready;
|
||||
}
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
@ -1,99 +0,0 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtGui module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** 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 Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or 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.GPL2 and 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-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QSHADERGRAPHLOADER_P_H
|
||||
#define QSHADERGRAPHLOADER_P_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 <QtGui/private/qtguiglobal_p.h>
|
||||
|
||||
#include <QtGui/private/qshadergraph_p.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QIODevice;
|
||||
|
||||
class QShaderGraphLoader
|
||||
{
|
||||
public:
|
||||
enum Status : char {
|
||||
Null,
|
||||
Waiting,
|
||||
Ready,
|
||||
Error
|
||||
};
|
||||
|
||||
Q_GUI_EXPORT QShaderGraphLoader() noexcept;
|
||||
|
||||
Q_GUI_EXPORT Status status() const noexcept;
|
||||
Q_GUI_EXPORT QShaderGraph graph() const noexcept;
|
||||
|
||||
Q_GUI_EXPORT QIODevice *device() const noexcept;
|
||||
Q_GUI_EXPORT void setDevice(QIODevice *device) noexcept;
|
||||
|
||||
Q_GUI_EXPORT QHash<QString, QShaderNode> prototypes() const noexcept;
|
||||
Q_GUI_EXPORT void setPrototypes(const QHash<QString, QShaderNode> &prototypes) noexcept;
|
||||
|
||||
Q_GUI_EXPORT void load();
|
||||
|
||||
private:
|
||||
Status m_status;
|
||||
QIODevice *m_device;
|
||||
QHash<QString, QShaderNode> m_prototypes;
|
||||
QShaderGraph m_graph;
|
||||
};
|
||||
|
||||
Q_DECLARE_TYPEINFO(QShaderGraphLoader, Q_RELOCATABLE_TYPE);
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
Q_DECLARE_METATYPE(QShaderGraphLoader)
|
||||
Q_DECLARE_METATYPE(QShaderGraphLoader::Status)
|
||||
|
||||
#endif // QSHADERGRAPHLOADER_P_H
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtGui module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** 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 Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or 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.GPL2 and 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-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qshaderlanguage_p.h"
|
||||
|
||||
#include <QtCore/qcoreapplication.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
// Note: to be invoked explicitly. Relying for example on
|
||||
// Q_COREAPP_STARTUP_FUNCTION would not be acceptable in static builds.
|
||||
void qt_register_ShaderLanguage_enums()
|
||||
{
|
||||
qRegisterMetaType<QShaderLanguage::StorageQualifier>();
|
||||
qRegisterMetaType<QShaderLanguage::VariableType>();
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
@ -1,164 +0,0 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtGui module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** 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 Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or 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.GPL2 and 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-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QSHADERLANGUAGE_P_H
|
||||
#define QSHADERLANGUAGE_P_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 <QtGui/private/qtguiglobal_p.h>
|
||||
|
||||
#include <QtCore/qmetatype.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QShaderLanguage
|
||||
{
|
||||
Q_NAMESPACE_EXPORT(Q_GUI_EXPORT)
|
||||
|
||||
enum StorageQualifier : char {
|
||||
Const = 1,
|
||||
Input,
|
||||
BuiltIn,
|
||||
Output,
|
||||
Uniform
|
||||
};
|
||||
Q_ENUM_NS(StorageQualifier)
|
||||
|
||||
enum VariableType : int {
|
||||
Bool = 1,
|
||||
Int,
|
||||
Uint,
|
||||
Float,
|
||||
Double,
|
||||
Vec2,
|
||||
Vec3,
|
||||
Vec4,
|
||||
DVec2,
|
||||
DVec3,
|
||||
DVec4,
|
||||
BVec2,
|
||||
BVec3,
|
||||
BVec4,
|
||||
IVec2,
|
||||
IVec3,
|
||||
IVec4,
|
||||
UVec2,
|
||||
UVec3,
|
||||
UVec4,
|
||||
Mat2,
|
||||
Mat3,
|
||||
Mat4,
|
||||
Mat2x2,
|
||||
Mat2x3,
|
||||
Mat2x4,
|
||||
Mat3x2,
|
||||
Mat3x3,
|
||||
Mat3x4,
|
||||
Mat4x2,
|
||||
Mat4x3,
|
||||
Mat4x4,
|
||||
DMat2,
|
||||
DMat3,
|
||||
DMat4,
|
||||
DMat2x2,
|
||||
DMat2x3,
|
||||
DMat2x4,
|
||||
DMat3x2,
|
||||
DMat3x3,
|
||||
DMat3x4,
|
||||
DMat4x2,
|
||||
DMat4x3,
|
||||
DMat4x4,
|
||||
Sampler1D,
|
||||
Sampler2D,
|
||||
Sampler3D,
|
||||
SamplerCube,
|
||||
Sampler2DRect,
|
||||
Sampler2DMs,
|
||||
SamplerBuffer,
|
||||
Sampler1DArray,
|
||||
Sampler2DArray,
|
||||
Sampler2DMsArray,
|
||||
SamplerCubeArray,
|
||||
Sampler1DShadow,
|
||||
Sampler2DShadow,
|
||||
Sampler2DRectShadow,
|
||||
Sampler1DArrayShadow,
|
||||
Sampler2DArrayShadow,
|
||||
SamplerCubeShadow,
|
||||
SamplerCubeArrayShadow,
|
||||
ISampler1D,
|
||||
ISampler2D,
|
||||
ISampler3D,
|
||||
ISamplerCube,
|
||||
ISampler2DRect,
|
||||
ISampler2DMs,
|
||||
ISamplerBuffer,
|
||||
ISampler1DArray,
|
||||
ISampler2DArray,
|
||||
ISampler2DMsArray,
|
||||
ISamplerCubeArray,
|
||||
USampler1D,
|
||||
USampler2D,
|
||||
USampler3D,
|
||||
USamplerCube,
|
||||
USampler2DRect,
|
||||
USampler2DMs,
|
||||
USamplerBuffer,
|
||||
USampler1DArray,
|
||||
USampler2DArray,
|
||||
USampler2DMsArray,
|
||||
USamplerCubeArray
|
||||
};
|
||||
Q_ENUM_NS(VariableType)
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QSHADERLANGUAGE_P_H
|
||||
|
|
@ -1,172 +0,0 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtGui module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** 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 Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or 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.GPL2 and 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-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qshadernode_p.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
QShaderNode::Type QShaderNode::type() const noexcept
|
||||
{
|
||||
int inputCount = 0;
|
||||
int outputCount = 0;
|
||||
for (const auto &port : qAsConst(m_ports)) {
|
||||
switch (port.direction) {
|
||||
case QShaderNodePort::Input:
|
||||
inputCount++;
|
||||
break;
|
||||
case QShaderNodePort::Output:
|
||||
outputCount++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (inputCount == 0 && outputCount == 0) ? Invalid
|
||||
: (inputCount > 0 && outputCount == 0) ? Output
|
||||
: (inputCount == 0 && outputCount > 0) ? Input
|
||||
: Function;
|
||||
}
|
||||
|
||||
QUuid QShaderNode::uuid() const noexcept
|
||||
{
|
||||
return m_uuid;
|
||||
}
|
||||
|
||||
void QShaderNode::setUuid(const QUuid &uuid) noexcept
|
||||
{
|
||||
m_uuid = uuid;
|
||||
}
|
||||
|
||||
QStringList QShaderNode::layers() const noexcept
|
||||
{
|
||||
return m_layers;
|
||||
}
|
||||
|
||||
void QShaderNode::setLayers(const QStringList &layers) noexcept
|
||||
{
|
||||
m_layers = layers;
|
||||
}
|
||||
|
||||
QList<QShaderNodePort> QShaderNode::ports() const noexcept
|
||||
{
|
||||
return m_ports;
|
||||
}
|
||||
|
||||
void QShaderNode::addPort(const QShaderNodePort &port)
|
||||
{
|
||||
removePort(port);
|
||||
m_ports.append(port);
|
||||
}
|
||||
|
||||
void QShaderNode::removePort(const QShaderNodePort &port)
|
||||
{
|
||||
const auto it = std::find_if(m_ports.begin(), m_ports.end(),
|
||||
[port](const QShaderNodePort &p) {
|
||||
return p.name == port.name;
|
||||
});
|
||||
if (it != m_ports.end())
|
||||
m_ports.erase(it);
|
||||
}
|
||||
|
||||
QStringList QShaderNode::parameterNames() const
|
||||
{
|
||||
return m_parameters.keys();
|
||||
}
|
||||
|
||||
QVariant QShaderNode::parameter(const QString &name) const
|
||||
{
|
||||
return m_parameters.value(name);
|
||||
}
|
||||
|
||||
void QShaderNode::setParameter(const QString &name, const QVariant &value)
|
||||
{
|
||||
m_parameters.insert(name, value);
|
||||
}
|
||||
|
||||
void QShaderNode::clearParameter(const QString &name)
|
||||
{
|
||||
m_parameters.remove(name);
|
||||
}
|
||||
|
||||
void QShaderNode::addRule(const QShaderFormat &format, const QShaderNode::Rule &rule)
|
||||
{
|
||||
removeRule(format);
|
||||
m_rules << qMakePair(format, rule);
|
||||
}
|
||||
|
||||
void QShaderNode::removeRule(const QShaderFormat &format)
|
||||
{
|
||||
const auto it = std::find_if(m_rules.begin(), m_rules.end(),
|
||||
[format](const QPair<QShaderFormat, Rule> &entry) {
|
||||
return entry.first == format;
|
||||
});
|
||||
if (it != m_rules.end())
|
||||
m_rules.erase(it);
|
||||
}
|
||||
|
||||
QList<QShaderFormat> QShaderNode::availableFormats() const
|
||||
{
|
||||
auto res = QList<QShaderFormat>();
|
||||
std::transform(m_rules.cbegin(), m_rules.cend(),
|
||||
std::back_inserter(res),
|
||||
[](const QPair<QShaderFormat, Rule> &entry) { return entry.first; });
|
||||
return res;
|
||||
}
|
||||
|
||||
QShaderNode::Rule QShaderNode::rule(const QShaderFormat &format) const
|
||||
{
|
||||
const auto it = std::find_if(m_rules.crbegin(), m_rules.crend(),
|
||||
[format](const QPair<QShaderFormat, Rule> &entry) {
|
||||
return format.supports(entry.first);
|
||||
});
|
||||
return it != m_rules.crend() ? it->second : Rule();
|
||||
}
|
||||
|
||||
QShaderNode::Rule::Rule(const QByteArray &subs, const QByteArrayList &snippets) noexcept
|
||||
: substitution(subs),
|
||||
headerSnippets(snippets)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator==(const QShaderNode::Rule &lhs, const QShaderNode::Rule &rhs) noexcept
|
||||
{
|
||||
return lhs.substitution == rhs.substitution
|
||||
&& lhs.headerSnippets == rhs.headerSnippets;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
@ -1,128 +0,0 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtGui module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** 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 Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or 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.GPL2 and 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-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QSHADERNODE_P_H
|
||||
#define QSHADERNODE_P_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 <QtGui/private/qtguiglobal_p.h>
|
||||
|
||||
#include <QtGui/private/qshaderformat_p.h>
|
||||
#include <QtGui/private/qshadernodeport_p.h>
|
||||
|
||||
#include <QtCore/quuid.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QShaderNode
|
||||
{
|
||||
public:
|
||||
enum Type : char {
|
||||
Invalid,
|
||||
Input,
|
||||
Output,
|
||||
Function
|
||||
};
|
||||
|
||||
class Rule
|
||||
{
|
||||
public:
|
||||
Q_GUI_EXPORT Rule(const QByteArray &substitution = QByteArray(), const QByteArrayList &headerSnippets = QByteArrayList()) noexcept;
|
||||
|
||||
QByteArray substitution;
|
||||
QByteArrayList headerSnippets;
|
||||
};
|
||||
|
||||
Q_GUI_EXPORT Type type() const noexcept;
|
||||
|
||||
Q_GUI_EXPORT QUuid uuid() const noexcept;
|
||||
Q_GUI_EXPORT void setUuid(const QUuid &uuid) noexcept;
|
||||
|
||||
Q_GUI_EXPORT QStringList layers() const noexcept;
|
||||
Q_GUI_EXPORT void setLayers(const QStringList &layers) noexcept;
|
||||
|
||||
Q_GUI_EXPORT QList<QShaderNodePort> ports() const noexcept;
|
||||
Q_GUI_EXPORT void addPort(const QShaderNodePort &port);
|
||||
Q_GUI_EXPORT void removePort(const QShaderNodePort &port);
|
||||
|
||||
Q_GUI_EXPORT QStringList parameterNames() const;
|
||||
Q_GUI_EXPORT QVariant parameter(const QString &name) const;
|
||||
Q_GUI_EXPORT void setParameter(const QString &name, const QVariant &value);
|
||||
Q_GUI_EXPORT void clearParameter(const QString &name);
|
||||
|
||||
Q_GUI_EXPORT void addRule(const QShaderFormat &format, const Rule &rule);
|
||||
Q_GUI_EXPORT void removeRule(const QShaderFormat &format);
|
||||
|
||||
Q_GUI_EXPORT QList<QShaderFormat> availableFormats() const;
|
||||
Q_GUI_EXPORT Rule rule(const QShaderFormat &format) const;
|
||||
|
||||
private:
|
||||
QUuid m_uuid;
|
||||
QStringList m_layers;
|
||||
QList<QShaderNodePort> m_ports;
|
||||
QHash<QString, QVariant> m_parameters;
|
||||
QList<QPair<QShaderFormat, QShaderNode::Rule>> m_rules;
|
||||
};
|
||||
|
||||
Q_GUI_EXPORT bool operator==(const QShaderNode::Rule &lhs, const QShaderNode::Rule &rhs) noexcept;
|
||||
|
||||
inline bool operator!=(const QShaderNode::Rule &lhs, const QShaderNode::Rule &rhs) noexcept
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
Q_DECLARE_TYPEINFO(QShaderNode, Q_RELOCATABLE_TYPE);
|
||||
Q_DECLARE_TYPEINFO(QShaderNode::Rule, Q_RELOCATABLE_TYPE);
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
Q_DECLARE_METATYPE(QShaderNode)
|
||||
Q_DECLARE_METATYPE(QShaderNode::Rule)
|
||||
|
||||
#endif // QSHADERNODE_P_H
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtGui module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** 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 Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or 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.GPL2 and 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-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qshadernodeport_p.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
QShaderNodePort::QShaderNodePort() noexcept
|
||||
: direction(Output)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator==(const QShaderNodePort &lhs, const QShaderNodePort &rhs) noexcept
|
||||
{
|
||||
return lhs.direction == rhs.direction
|
||||
&& lhs.name == rhs.name;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
@ -1,88 +0,0 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtGui module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** 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 Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or 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.GPL2 and 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-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QSHADERNODEPORT_P_H
|
||||
#define QSHADERNODEPORT_P_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 <QtGui/private/qtguiglobal_p.h>
|
||||
|
||||
#include <QtCore/qstring.h>
|
||||
#include <QtCore/qvariant.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QShaderNodePort
|
||||
{
|
||||
public:
|
||||
enum Direction : char {
|
||||
Input,
|
||||
Output
|
||||
};
|
||||
|
||||
Q_GUI_EXPORT QShaderNodePort() noexcept;
|
||||
|
||||
QShaderNodePort::Direction direction;
|
||||
QString name;
|
||||
};
|
||||
|
||||
Q_GUI_EXPORT bool operator==(const QShaderNodePort &lhs, const QShaderNodePort &rhs) noexcept;
|
||||
|
||||
inline bool operator!=(const QShaderNodePort &lhs, const QShaderNodePort &rhs) noexcept
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
Q_DECLARE_TYPEINFO(QShaderNodePort, Q_RELOCATABLE_TYPE);
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
Q_DECLARE_METATYPE(QShaderNodePort)
|
||||
|
||||
#endif // QSHADERNODEPORT_P_H
|
||||
|
|
@ -1,290 +0,0 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtGui module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** 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 Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or 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.GPL2 and 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-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qshadernodesloader_p.h"
|
||||
|
||||
#include <QtCore/qdebug.h>
|
||||
#include <QtCore/qiodevice.h>
|
||||
#include <QtCore/qjsonarray.h>
|
||||
#include <QtCore/qjsondocument.h>
|
||||
#include <QtCore/qjsonobject.h>
|
||||
#include <QtCore/qmetaobject.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
QShaderNodesLoader::QShaderNodesLoader() noexcept
|
||||
: m_status(Null),
|
||||
m_device(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
QShaderNodesLoader::Status QShaderNodesLoader::status() const noexcept
|
||||
{
|
||||
return m_status;
|
||||
}
|
||||
|
||||
QHash<QString, QShaderNode> QShaderNodesLoader::nodes() const noexcept
|
||||
{
|
||||
return m_nodes;
|
||||
}
|
||||
|
||||
QIODevice *QShaderNodesLoader::device() const noexcept
|
||||
{
|
||||
return m_device;
|
||||
}
|
||||
|
||||
void QShaderNodesLoader::setDevice(QIODevice *device) noexcept
|
||||
{
|
||||
m_device = device;
|
||||
m_nodes.clear();
|
||||
m_status = !m_device ? Null
|
||||
: (m_device->openMode() & QIODevice::ReadOnly) ? Waiting
|
||||
: Error;
|
||||
}
|
||||
|
||||
void QShaderNodesLoader::load()
|
||||
{
|
||||
if (m_status == Error)
|
||||
return;
|
||||
|
||||
auto error = QJsonParseError();
|
||||
const QJsonDocument document = QJsonDocument::fromJson(m_device->readAll(), &error);
|
||||
|
||||
if (error.error != QJsonParseError::NoError) {
|
||||
qWarning() << "Invalid JSON document:" << error.errorString();
|
||||
m_status = Error;
|
||||
return;
|
||||
}
|
||||
|
||||
if (document.isEmpty() || !document.isObject()) {
|
||||
qWarning() << "Invalid JSON document, root should be an object";
|
||||
m_status = Error;
|
||||
return;
|
||||
}
|
||||
|
||||
const QJsonObject root = document.object();
|
||||
load(root);
|
||||
}
|
||||
|
||||
void QShaderNodesLoader::load(const QJsonObject &prototypesObject)
|
||||
{
|
||||
bool hasError = false;
|
||||
|
||||
for (const QString &property : prototypesObject.keys()) {
|
||||
const QJsonValue nodeValue = prototypesObject.value(property);
|
||||
if (!nodeValue.isObject()) {
|
||||
qWarning() << "Invalid node found";
|
||||
hasError = true;
|
||||
break;
|
||||
}
|
||||
|
||||
const QJsonObject nodeObject = nodeValue.toObject();
|
||||
|
||||
auto node = QShaderNode();
|
||||
|
||||
const QJsonValue inputsValue = nodeObject.value(QStringLiteral("inputs"));
|
||||
if (inputsValue.isArray()) {
|
||||
const QJsonArray inputsArray = inputsValue.toArray();
|
||||
for (const QJsonValue inputValue : inputsArray) {
|
||||
if (!inputValue.isString()) {
|
||||
qWarning() << "Non-string value in inputs";
|
||||
hasError = true;
|
||||
break;
|
||||
}
|
||||
|
||||
auto input = QShaderNodePort();
|
||||
input.direction = QShaderNodePort::Input;
|
||||
input.name = inputValue.toString();
|
||||
node.addPort(input);
|
||||
}
|
||||
}
|
||||
|
||||
const QJsonValue outputsValue = nodeObject.value(QStringLiteral("outputs"));
|
||||
if (outputsValue.isArray()) {
|
||||
const QJsonArray outputsArray = outputsValue.toArray();
|
||||
for (const QJsonValue outputValue : outputsArray) {
|
||||
if (!outputValue.isString()) {
|
||||
qWarning() << "Non-string value in outputs";
|
||||
hasError = true;
|
||||
break;
|
||||
}
|
||||
|
||||
auto output = QShaderNodePort();
|
||||
output.direction = QShaderNodePort::Output;
|
||||
output.name = outputValue.toString();
|
||||
node.addPort(output);
|
||||
}
|
||||
}
|
||||
|
||||
const QJsonValue parametersValue = nodeObject.value(QStringLiteral("parameters"));
|
||||
if (parametersValue.isObject()) {
|
||||
const QJsonObject parametersObject = parametersValue.toObject();
|
||||
for (const QString ¶meterName : parametersObject.keys()) {
|
||||
const QJsonValue parameterValue = parametersObject.value(parameterName);
|
||||
if (parameterValue.isObject()) {
|
||||
const QJsonObject parameterObject = parameterValue.toObject();
|
||||
const QString type = parameterObject.value(QStringLiteral("type")).toString();
|
||||
const auto metaType = QMetaType::fromName(type.toUtf8());
|
||||
|
||||
const QString value = parameterObject.value(QStringLiteral("value")).toString();
|
||||
auto variant = QVariant(value);
|
||||
|
||||
if (metaType.flags() & QMetaType::IsEnumeration) {
|
||||
const QMetaObject *metaObject = metaType.metaObject();
|
||||
const char *className = metaObject->className();
|
||||
const QByteArray enumName = type.mid(static_cast<int>(qstrlen(className)) + 2).toUtf8();
|
||||
const QMetaEnum metaEnum = metaObject->enumerator(metaObject->indexOfEnumerator(enumName));
|
||||
const int enumValue = metaEnum.keyToValue(value.toUtf8());
|
||||
variant = QVariant(enumValue);
|
||||
variant.convert(metaType);
|
||||
} else {
|
||||
variant.convert(metaType);
|
||||
}
|
||||
node.setParameter(parameterName, variant);
|
||||
} else {
|
||||
node.setParameter(parameterName, parameterValue.toVariant());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const QJsonValue rulesValue = nodeObject.value(QStringLiteral("rules"));
|
||||
if (rulesValue.isArray()) {
|
||||
const QJsonArray rulesArray = rulesValue.toArray();
|
||||
for (const QJsonValue ruleValue : rulesArray) {
|
||||
if (!ruleValue.isObject()) {
|
||||
qWarning() << "Rules should be objects";
|
||||
hasError = true;
|
||||
break;
|
||||
}
|
||||
|
||||
const QJsonObject ruleObject = ruleValue.toObject();
|
||||
|
||||
const QJsonValue formatValue = ruleObject.value(QStringLiteral("format"));
|
||||
if (!formatValue.isObject()) {
|
||||
qWarning() << "Format is mandatory in rules and should be an object";
|
||||
hasError = true;
|
||||
break;
|
||||
}
|
||||
|
||||
const QJsonObject formatObject = formatValue.toObject();
|
||||
auto format = QShaderFormat();
|
||||
|
||||
const QJsonValue apiValue = formatObject.value(QStringLiteral("api"));
|
||||
if (!apiValue.isString()) {
|
||||
qWarning() << "Format API must be a string";
|
||||
hasError = true;
|
||||
break;
|
||||
}
|
||||
|
||||
const QString api = apiValue.toString();
|
||||
format.setApi(api == QStringLiteral("OpenGLES") ? QShaderFormat::OpenGLES
|
||||
: api == QStringLiteral("OpenGLNoProfile") ? QShaderFormat::OpenGLNoProfile
|
||||
: api == QStringLiteral("OpenGLCoreProfile") ? QShaderFormat::OpenGLCoreProfile
|
||||
: api == QStringLiteral("OpenGLCompatibilityProfile") ? QShaderFormat::OpenGLCompatibilityProfile
|
||||
: api == QStringLiteral("VulkanFlavoredGLSL") ? QShaderFormat::VulkanFlavoredGLSL
|
||||
: QShaderFormat::NoApi);
|
||||
if (format.api() == QShaderFormat::NoApi) {
|
||||
qWarning() << "Format API must be one of: OpenGLES, OpenGLNoProfile, OpenGLCoreProfile or OpenGLCompatibilityProfile, VulkanFlavoredGLSL";
|
||||
hasError = true;
|
||||
break;
|
||||
}
|
||||
|
||||
const QJsonValue majorValue = formatObject.value(QStringLiteral("major"));
|
||||
const QJsonValue minorValue = formatObject.value(QStringLiteral("minor"));
|
||||
if (!majorValue.isDouble() || !minorValue.isDouble()) {
|
||||
qWarning() << "Format major and minor version must be values";
|
||||
hasError = true;
|
||||
break;
|
||||
}
|
||||
format.setVersion(QVersionNumber(majorValue.toInt(), minorValue.toInt()));
|
||||
|
||||
const QJsonValue extensionsValue = formatObject.value(QStringLiteral("extensions"));
|
||||
const QJsonArray extensionsArray = extensionsValue.toArray();
|
||||
auto extensions = QStringList();
|
||||
std::transform(extensionsArray.constBegin(), extensionsArray.constEnd(),
|
||||
std::back_inserter(extensions),
|
||||
[] (const QJsonValue &extensionValue) { return extensionValue.toString(); });
|
||||
format.setExtensions(extensions);
|
||||
|
||||
const QString vendor = formatObject.value(QStringLiteral("vendor")).toString();
|
||||
format.setVendor(vendor);
|
||||
|
||||
const QJsonValue substitutionValue = ruleObject.value(QStringLiteral("substitution"));
|
||||
if (!substitutionValue.isString()) {
|
||||
qWarning() << "Substitution needs to be a string";
|
||||
hasError = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// We default out to a Fragment ShaderType if nothing is specified
|
||||
// as that was the initial behavior we introduced
|
||||
const QString shaderType = formatObject.value(QStringLiteral("shaderType")).toString();
|
||||
format.setShaderType(shaderType == QStringLiteral("Fragment") ? QShaderFormat::Fragment
|
||||
: shaderType == QStringLiteral("Vertex") ? QShaderFormat::Vertex
|
||||
: shaderType == QStringLiteral("TessellationControl") ? QShaderFormat::TessellationControl
|
||||
: shaderType == QStringLiteral("TessellationEvaluation") ? QShaderFormat::TessellationEvaluation
|
||||
: shaderType == QStringLiteral("Geometry") ? QShaderFormat::Geometry
|
||||
: shaderType == QStringLiteral("Compute") ? QShaderFormat::Compute
|
||||
: QShaderFormat::Fragment);
|
||||
|
||||
const QByteArray substitution = substitutionValue.toString().toUtf8();
|
||||
|
||||
const QJsonValue snippetsValue = ruleObject.value(QStringLiteral("headerSnippets"));
|
||||
const QJsonArray snippetsArray = snippetsValue.toArray();
|
||||
auto snippets = QByteArrayList();
|
||||
std::transform(snippetsArray.constBegin(), snippetsArray.constEnd(),
|
||||
std::back_inserter(snippets),
|
||||
[] (const QJsonValue &snippetValue) { return snippetValue.toString().toUtf8(); });
|
||||
|
||||
node.addRule(format, QShaderNode::Rule(substitution, snippets));
|
||||
}
|
||||
}
|
||||
|
||||
m_nodes.insert(property, node);
|
||||
}
|
||||
|
||||
if (hasError) {
|
||||
m_status = Error;
|
||||
m_nodes.clear();
|
||||
} else {
|
||||
m_status = Ready;
|
||||
}
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
@ -1,96 +0,0 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtGui module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** 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 Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or 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.GPL2 and 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-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QSHADERNODESLOADER_P_H
|
||||
#define QSHADERNODESLOADER_P_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 <QtGui/private/qtguiglobal_p.h>
|
||||
|
||||
#include <QtGui/private/qshadergraph_p.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QIODevice;
|
||||
|
||||
class QShaderNodesLoader
|
||||
{
|
||||
public:
|
||||
enum Status : char {
|
||||
Null,
|
||||
Waiting,
|
||||
Ready,
|
||||
Error
|
||||
};
|
||||
|
||||
Q_GUI_EXPORT QShaderNodesLoader() noexcept;
|
||||
|
||||
Q_GUI_EXPORT Status status() const noexcept;
|
||||
Q_GUI_EXPORT QHash<QString, QShaderNode> nodes() const noexcept;
|
||||
|
||||
Q_GUI_EXPORT QIODevice *device() const noexcept;
|
||||
Q_GUI_EXPORT void setDevice(QIODevice *device) noexcept;
|
||||
|
||||
Q_GUI_EXPORT void load();
|
||||
Q_GUI_EXPORT void load(const QJsonObject &prototypesObject);
|
||||
|
||||
private:
|
||||
Status m_status;
|
||||
QIODevice *m_device;
|
||||
QHash<QString, QShaderNode> m_nodes;
|
||||
};
|
||||
|
||||
Q_DECLARE_TYPEINFO(QShaderNodesLoader, Q_RELOCATABLE_TYPE);
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
Q_DECLARE_METATYPE(QShaderNodesLoader)
|
||||
Q_DECLARE_METATYPE(QShaderNodesLoader::Status)
|
||||
|
||||
#endif // QSHADERNODESLOADER_P_H
|
||||
|
|
@ -4,11 +4,6 @@ add_subdirectory(qdesktopservices)
|
|||
add_subdirectory(qdoublevalidator)
|
||||
add_subdirectory(qintvalidator)
|
||||
add_subdirectory(qregularexpressionvalidator)
|
||||
add_subdirectory(qshadergenerator)
|
||||
add_subdirectory(qshadergraph)
|
||||
add_subdirectory(qshadergraphloader)
|
||||
add_subdirectory(qshadernodes)
|
||||
add_subdirectory(qshadernodesloader)
|
||||
add_subdirectory(qtexturefilereader)
|
||||
add_subdirectory(qundogroup)
|
||||
add_subdirectory(qundostack)
|
||||
|
|
|
|||
|
|
@ -1,13 +0,0 @@
|
|||
# Generated from qshadergenerator.pro.
|
||||
|
||||
#####################################################################
|
||||
## tst_qshadergenerator Test:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_test(tst_qshadergenerator
|
||||
SOURCES
|
||||
tst_qshadergenerator.cpp
|
||||
PUBLIC_LIBRARIES
|
||||
Qt::Gui
|
||||
Qt::GuiPrivate
|
||||
)
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,13 +0,0 @@
|
|||
# Generated from qshadergraph.pro.
|
||||
|
||||
#####################################################################
|
||||
## tst_qshadergraph Test:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_test(tst_qshadergraph
|
||||
SOURCES
|
||||
tst_qshadergraph.cpp
|
||||
PUBLIC_LIBRARIES
|
||||
Qt::Gui
|
||||
Qt::GuiPrivate
|
||||
)
|
||||
|
|
@ -1,815 +0,0 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the test suite of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
|
||||
** 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 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** 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$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
#include <QTest>
|
||||
|
||||
#include <QtGui/private/qshadergraph_p.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
QShaderNodePort createPort(QShaderNodePort::Direction portDirection, const QString &portName)
|
||||
{
|
||||
auto port = QShaderNodePort();
|
||||
port.direction = portDirection;
|
||||
port.name = portName;
|
||||
return port;
|
||||
}
|
||||
|
||||
QShaderNode createNode(const QList<QShaderNodePort> &ports,
|
||||
const QStringList &layers = QStringList())
|
||||
{
|
||||
auto node = QShaderNode();
|
||||
node.setUuid(QUuid::createUuid());
|
||||
node.setLayers(layers);
|
||||
for (const auto &port : ports)
|
||||
node.addPort(port);
|
||||
return node;
|
||||
}
|
||||
|
||||
QShaderGraph::Edge createEdge(const QUuid &sourceUuid, const QString &sourceName,
|
||||
const QUuid &targetUuid, const QString &targetName,
|
||||
const QStringList &layers = QStringList())
|
||||
{
|
||||
auto edge = QShaderGraph::Edge();
|
||||
edge.sourceNodeUuid = sourceUuid;
|
||||
edge.sourcePortName = sourceName;
|
||||
edge.targetNodeUuid = targetUuid;
|
||||
edge.targetPortName = targetName;
|
||||
edge.layers = layers;
|
||||
return edge;
|
||||
}
|
||||
|
||||
QShaderGraph::Statement createStatement(const QShaderNode &node,
|
||||
const QList<int> &inputs = QList<int>(),
|
||||
const QList<int> &outputs = QList<int>())
|
||||
{
|
||||
auto statement = QShaderGraph::Statement();
|
||||
statement.node = node;
|
||||
statement.inputs = inputs;
|
||||
statement.outputs = outputs;
|
||||
return statement;
|
||||
}
|
||||
|
||||
void debugStatement(const QString &prefix, const QShaderGraph::Statement &statement)
|
||||
{
|
||||
qDebug() << prefix << statement.inputs << statement.uuid().toString() << statement.outputs;
|
||||
}
|
||||
|
||||
void dumpStatementsIfNeeded(const QList<QShaderGraph::Statement> &statements,
|
||||
const QList<QShaderGraph::Statement> &expected)
|
||||
{
|
||||
if (statements != expected) {
|
||||
for (int i = 0; i < qMax(statements.size(), expected.size()); i++) {
|
||||
qDebug() << "----" << i << "----";
|
||||
if (i < statements.size())
|
||||
debugStatement("A:", statements.at(i));
|
||||
if (i < expected.size())
|
||||
debugStatement("E:", expected.at(i));
|
||||
qDebug() << "-----------";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class tst_QShaderGraph : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
private slots:
|
||||
void shouldHaveEdgeDefaultState();
|
||||
void shouldTestEdgesEquality_data();
|
||||
void shouldTestEdgesEquality();
|
||||
void shouldManipulateStatementMembers();
|
||||
void shouldTestStatementsEquality_data();
|
||||
void shouldTestStatementsEquality();
|
||||
void shouldFindIndexFromPortNameInStatements_data();
|
||||
void shouldFindIndexFromPortNameInStatements();
|
||||
void shouldManageNodeList();
|
||||
void shouldManageEdgeList();
|
||||
void shouldSerializeGraphForCodeGeneration();
|
||||
void shouldHandleUnboundPortsDuringGraphSerialization();
|
||||
void shouldSurviveCyclesDuringGraphSerialization();
|
||||
void shouldDealWithEdgesJumpingOverLayers();
|
||||
void shouldGenerateDifferentStatementsDependingOnActiveLayers();
|
||||
void shouldDealWithBranchesWithoutOutput();
|
||||
};
|
||||
|
||||
void tst_QShaderGraph::shouldHaveEdgeDefaultState()
|
||||
{
|
||||
// GIVEN
|
||||
auto edge = QShaderGraph::Edge();
|
||||
|
||||
// THEN
|
||||
QVERIFY(edge.sourceNodeUuid.isNull());
|
||||
QVERIFY(edge.sourcePortName.isEmpty());
|
||||
QVERIFY(edge.targetNodeUuid.isNull());
|
||||
QVERIFY(edge.targetPortName.isEmpty());
|
||||
}
|
||||
|
||||
void tst_QShaderGraph::shouldTestEdgesEquality_data()
|
||||
{
|
||||
QTest::addColumn<QShaderGraph::Edge>("left");
|
||||
QTest::addColumn<QShaderGraph::Edge>("right");
|
||||
QTest::addColumn<bool>("expected");
|
||||
|
||||
const auto sourceUuid1 = QUuid::createUuid();
|
||||
const auto sourceUuid2 = QUuid::createUuid();
|
||||
const auto targetUuid1 = QUuid::createUuid();
|
||||
const auto targetUuid2 = QUuid::createUuid();
|
||||
|
||||
QTest::newRow("Equals") << createEdge(sourceUuid1, "foo", targetUuid1, "bar")
|
||||
<< createEdge(sourceUuid1, "foo", targetUuid1, "bar")
|
||||
<< true;
|
||||
QTest::newRow("SourceUuid") << createEdge(sourceUuid1, "foo", targetUuid1, "bar")
|
||||
<< createEdge(sourceUuid2, "foo", targetUuid1, "bar")
|
||||
<< false;
|
||||
QTest::newRow("SourceName") << createEdge(sourceUuid1, "foo", targetUuid1, "bar")
|
||||
<< createEdge(sourceUuid1, "bleh", targetUuid1, "bar")
|
||||
<< false;
|
||||
QTest::newRow("TargetUuid") << createEdge(sourceUuid1, "foo", targetUuid1, "bar")
|
||||
<< createEdge(sourceUuid1, "foo", targetUuid2, "bar")
|
||||
<< false;
|
||||
QTest::newRow("TargetName") << createEdge(sourceUuid1, "foo", targetUuid1, "bar")
|
||||
<< createEdge(sourceUuid1, "foo", targetUuid1, "bleh")
|
||||
<< false;
|
||||
}
|
||||
|
||||
void tst_QShaderGraph::shouldTestEdgesEquality()
|
||||
{
|
||||
// GIVEN
|
||||
QFETCH(QShaderGraph::Edge, left);
|
||||
QFETCH(QShaderGraph::Edge, right);
|
||||
|
||||
// WHEN
|
||||
const auto equal = (left == right);
|
||||
const auto notEqual = (left != right);
|
||||
|
||||
// THEN
|
||||
QFETCH(bool, expected);
|
||||
QCOMPARE(equal, expected);
|
||||
QCOMPARE(notEqual, !expected);
|
||||
}
|
||||
|
||||
void tst_QShaderGraph::shouldManipulateStatementMembers()
|
||||
{
|
||||
// GIVEN
|
||||
auto statement = QShaderGraph::Statement();
|
||||
|
||||
// THEN (default state)
|
||||
QVERIFY(statement.inputs.isEmpty());
|
||||
QVERIFY(statement.outputs.isEmpty());
|
||||
QVERIFY(statement.node.uuid().isNull());
|
||||
QVERIFY(statement.uuid().isNull());
|
||||
|
||||
// WHEN
|
||||
const auto node = createNode({});
|
||||
statement.node = node;
|
||||
|
||||
// THEN
|
||||
QCOMPARE(statement.uuid(), node.uuid());
|
||||
|
||||
// WHEN
|
||||
statement.node = QShaderNode();
|
||||
|
||||
// THEN
|
||||
QVERIFY(statement.uuid().isNull());
|
||||
}
|
||||
|
||||
void tst_QShaderGraph::shouldTestStatementsEquality_data()
|
||||
{
|
||||
QTest::addColumn<QShaderGraph::Statement>("left");
|
||||
QTest::addColumn<QShaderGraph::Statement>("right");
|
||||
QTest::addColumn<bool>("expected");
|
||||
|
||||
const auto node1 = createNode({});
|
||||
const auto node2 = createNode({});
|
||||
|
||||
QTest::newRow("EqualNodes") << createStatement(node1, {1, 2}, {3, 4})
|
||||
<< createStatement(node1, {1, 2}, {3, 4})
|
||||
<< true;
|
||||
QTest::newRow("EqualInvalids") << createStatement(QShaderNode(), {1, 2}, {3, 4})
|
||||
<< createStatement(QShaderNode(), {1, 2}, {3, 4})
|
||||
<< true;
|
||||
QTest::newRow("Nodes") << createStatement(node1, {1, 2}, {3, 4})
|
||||
<< createStatement(node2, {1, 2}, {3, 4})
|
||||
<< false;
|
||||
QTest::newRow("Inputs") << createStatement(node1, {1, 2}, {3, 4})
|
||||
<< createStatement(node1, {1, 2, 0}, {3, 4})
|
||||
<< false;
|
||||
QTest::newRow("Outputs") << createStatement(node1, {1, 2}, {3, 4})
|
||||
<< createStatement(node1, {1, 2}, {3, 0, 4})
|
||||
<< false;
|
||||
}
|
||||
|
||||
void tst_QShaderGraph::shouldTestStatementsEquality()
|
||||
{
|
||||
// GIVEN
|
||||
QFETCH(QShaderGraph::Statement, left);
|
||||
QFETCH(QShaderGraph::Statement, right);
|
||||
|
||||
// WHEN
|
||||
const auto equal = (left == right);
|
||||
const auto notEqual = (left != right);
|
||||
|
||||
// THEN
|
||||
QFETCH(bool, expected);
|
||||
QCOMPARE(equal, expected);
|
||||
QCOMPARE(notEqual, !expected);
|
||||
}
|
||||
|
||||
void tst_QShaderGraph::shouldFindIndexFromPortNameInStatements_data()
|
||||
{
|
||||
QTest::addColumn<QShaderGraph::Statement>("statement");
|
||||
QTest::addColumn<QString>("portName");
|
||||
QTest::addColumn<int>("expectedInputIndex");
|
||||
QTest::addColumn<int>("expectedOutputIndex");
|
||||
|
||||
const auto inputNodeStatement = createStatement(createNode({
|
||||
createPort(QShaderNodePort::Output, "input")
|
||||
}));
|
||||
const auto outputNodeStatement = createStatement(createNode({
|
||||
createPort(QShaderNodePort::Input, "output")
|
||||
}));
|
||||
const auto functionNodeStatement = createStatement(createNode({
|
||||
createPort(QShaderNodePort::Input, "input1"),
|
||||
createPort(QShaderNodePort::Output, "output1"),
|
||||
createPort(QShaderNodePort::Input, "input2"),
|
||||
createPort(QShaderNodePort::Output, "output2"),
|
||||
createPort(QShaderNodePort::Output, "output3"),
|
||||
createPort(QShaderNodePort::Input, "input3")
|
||||
}));
|
||||
|
||||
QTest::newRow("Invalid") << QShaderGraph::Statement() << "foo" << -1 << -1;
|
||||
QTest::newRow("InputNodeWrongName") << inputNodeStatement << "foo" << -1 << -1;
|
||||
QTest::newRow("InputNodeExistingName") << inputNodeStatement << "input" << -1 << 0;
|
||||
QTest::newRow("OutputNodeWrongName") << outputNodeStatement << "foo" << -1 << -1;
|
||||
QTest::newRow("OutputNodeExistingName") << outputNodeStatement << "output" << 0 << -1;
|
||||
QTest::newRow("FunctionNodeWrongName") << functionNodeStatement << "foo" << -1 << -1;
|
||||
QTest::newRow("FunctionNodeInput1") << functionNodeStatement << "input1" << 0 << -1;
|
||||
QTest::newRow("FunctionNodeOutput1") << functionNodeStatement << "output1" << -1 << 0;
|
||||
QTest::newRow("FunctionNodeInput2") << functionNodeStatement << "input2" << 1 << -1;
|
||||
QTest::newRow("FunctionNodeOutput2") << functionNodeStatement << "output2" << -1 << 1;
|
||||
QTest::newRow("FunctionNodeInput3") << functionNodeStatement << "input3" << 2 << -1;
|
||||
QTest::newRow("FunctionNodeOutput3") << functionNodeStatement << "output3" << -1 << 2;
|
||||
}
|
||||
|
||||
void tst_QShaderGraph::shouldFindIndexFromPortNameInStatements()
|
||||
{
|
||||
// GIVEN
|
||||
QFETCH(QShaderGraph::Statement, statement);
|
||||
QFETCH(QString, portName);
|
||||
QFETCH(int, expectedInputIndex);
|
||||
QFETCH(int, expectedOutputIndex);
|
||||
|
||||
// WHEN
|
||||
const auto inputIndex = statement.portIndex(QShaderNodePort::Input, portName);
|
||||
const auto outputIndex = statement.portIndex(QShaderNodePort::Output, portName);
|
||||
|
||||
// THEN
|
||||
QCOMPARE(inputIndex, expectedInputIndex);
|
||||
QCOMPARE(outputIndex, expectedOutputIndex);
|
||||
}
|
||||
|
||||
void tst_QShaderGraph::shouldManageNodeList()
|
||||
{
|
||||
// GIVEN
|
||||
const auto node1 = createNode({createPort(QShaderNodePort::Output, "node1")});
|
||||
const auto node2 = createNode({createPort(QShaderNodePort::Output, "node2")});
|
||||
|
||||
auto graph = QShaderGraph();
|
||||
|
||||
// THEN (default state)
|
||||
QVERIFY(graph.nodes().isEmpty());
|
||||
|
||||
// WHEN
|
||||
graph.addNode(node1);
|
||||
|
||||
// THEN
|
||||
QCOMPARE(graph.nodes().size(), 1);
|
||||
QCOMPARE(graph.nodes().at(0).uuid(), node1.uuid());
|
||||
QCOMPARE(graph.nodes().at(0).ports().at(0).name, node1.ports().at(0).name);
|
||||
|
||||
// WHEN
|
||||
graph.addNode(node2);
|
||||
|
||||
// THEN
|
||||
QCOMPARE(graph.nodes().size(), 2);
|
||||
QCOMPARE(graph.nodes().at(0).uuid(), node1.uuid());
|
||||
QCOMPARE(graph.nodes().at(0).ports().at(0).name, node1.ports().at(0).name);
|
||||
QCOMPARE(graph.nodes().at(1).uuid(), node2.uuid());
|
||||
QCOMPARE(graph.nodes().at(1).ports().at(0).name, node2.ports().at(0).name);
|
||||
|
||||
|
||||
// WHEN
|
||||
graph.removeNode(node2);
|
||||
|
||||
// THEN
|
||||
QCOMPARE(graph.nodes().size(), 1);
|
||||
QCOMPARE(graph.nodes().at(0).uuid(), node1.uuid());
|
||||
QCOMPARE(graph.nodes().at(0).ports().at(0).name, node1.ports().at(0).name);
|
||||
|
||||
// WHEN
|
||||
graph.addNode(node2);
|
||||
|
||||
// THEN
|
||||
QCOMPARE(graph.nodes().size(), 2);
|
||||
QCOMPARE(graph.nodes().at(0).uuid(), node1.uuid());
|
||||
QCOMPARE(graph.nodes().at(0).ports().at(0).name, node1.ports().at(0).name);
|
||||
QCOMPARE(graph.nodes().at(1).uuid(), node2.uuid());
|
||||
QCOMPARE(graph.nodes().at(1).ports().at(0).name, node2.ports().at(0).name);
|
||||
|
||||
// WHEN
|
||||
const auto node1bis = [node1] {
|
||||
auto res = node1;
|
||||
auto port = res.ports().at(0);
|
||||
port.name = QStringLiteral("node1bis");
|
||||
res.addPort(port);
|
||||
return res;
|
||||
}();
|
||||
graph.addNode(node1bis);
|
||||
|
||||
// THEN
|
||||
QCOMPARE(graph.nodes().size(), 2);
|
||||
QCOMPARE(graph.nodes().at(0).uuid(), node2.uuid());
|
||||
QCOMPARE(graph.nodes().at(0).ports().at(0).name, node2.ports().at(0).name);
|
||||
QCOMPARE(graph.nodes().at(1).uuid(), node1bis.uuid());
|
||||
QCOMPARE(graph.nodes().at(1).ports().at(0).name, node1bis.ports().at(0).name);
|
||||
}
|
||||
|
||||
void tst_QShaderGraph::shouldManageEdgeList()
|
||||
{
|
||||
// GIVEN
|
||||
const auto edge1 = createEdge(QUuid::createUuid(), "foo", QUuid::createUuid(), "bar");
|
||||
const auto edge2 = createEdge(QUuid::createUuid(), "baz", QUuid::createUuid(), "boo");
|
||||
|
||||
auto graph = QShaderGraph();
|
||||
|
||||
// THEN (default state)
|
||||
QVERIFY(graph.edges().isEmpty());
|
||||
|
||||
// WHEN
|
||||
graph.addEdge(edge1);
|
||||
|
||||
// THEN
|
||||
QCOMPARE(graph.edges().size(), 1);
|
||||
QCOMPARE(graph.edges().at(0), edge1);
|
||||
|
||||
// WHEN
|
||||
graph.addEdge(edge2);
|
||||
|
||||
// THEN
|
||||
QCOMPARE(graph.edges().size(), 2);
|
||||
QCOMPARE(graph.edges().at(0), edge1);
|
||||
QCOMPARE(graph.edges().at(1), edge2);
|
||||
|
||||
|
||||
// WHEN
|
||||
graph.removeEdge(edge2);
|
||||
|
||||
// THEN
|
||||
QCOMPARE(graph.edges().size(), 1);
|
||||
QCOMPARE(graph.edges().at(0), edge1);
|
||||
|
||||
// WHEN
|
||||
graph.addEdge(edge2);
|
||||
|
||||
// THEN
|
||||
QCOMPARE(graph.edges().size(), 2);
|
||||
QCOMPARE(graph.edges().at(0), edge1);
|
||||
QCOMPARE(graph.edges().at(1), edge2);
|
||||
|
||||
// WHEN
|
||||
graph.addEdge(edge1);
|
||||
|
||||
// THEN
|
||||
QCOMPARE(graph.edges().size(), 2);
|
||||
QCOMPARE(graph.edges().at(0), edge1);
|
||||
QCOMPARE(graph.edges().at(1), edge2);
|
||||
}
|
||||
|
||||
void tst_QShaderGraph::shouldSerializeGraphForCodeGeneration()
|
||||
{
|
||||
// GIVEN
|
||||
const auto input1 = createNode({
|
||||
createPort(QShaderNodePort::Output, "input1Value")
|
||||
});
|
||||
const auto input2 = createNode({
|
||||
createPort(QShaderNodePort::Output, "input2Value")
|
||||
});
|
||||
const auto output1 = createNode({
|
||||
createPort(QShaderNodePort::Input, "output1Value")
|
||||
});
|
||||
const auto output2 = createNode({
|
||||
createPort(QShaderNodePort::Input, "output2Value")
|
||||
});
|
||||
const auto function1 = createNode({
|
||||
createPort(QShaderNodePort::Input, "function1Input"),
|
||||
createPort(QShaderNodePort::Output, "function1Output")
|
||||
});
|
||||
const auto function2 = createNode({
|
||||
createPort(QShaderNodePort::Input, "function2Input1"),
|
||||
createPort(QShaderNodePort::Input, "function2Input2"),
|
||||
createPort(QShaderNodePort::Output, "function2Output")
|
||||
});
|
||||
const auto function3 = createNode({
|
||||
createPort(QShaderNodePort::Input, "function3Input1"),
|
||||
createPort(QShaderNodePort::Input, "function3Input2"),
|
||||
createPort(QShaderNodePort::Output, "function3Output1"),
|
||||
createPort(QShaderNodePort::Output, "function3Output2")
|
||||
});
|
||||
|
||||
const auto graph = [=] {
|
||||
auto res = QShaderGraph();
|
||||
res.addNode(input1);
|
||||
res.addNode(input2);
|
||||
res.addNode(output1);
|
||||
res.addNode(output2);
|
||||
res.addNode(function1);
|
||||
res.addNode(function2);
|
||||
res.addNode(function3);
|
||||
res.addEdge(createEdge(input1.uuid(), "input1Value", function1.uuid(), "function1Input"));
|
||||
res.addEdge(createEdge(input1.uuid(), "input1Value", function2.uuid(), "function2Input1"));
|
||||
res.addEdge(createEdge(input2.uuid(), "input2Value", function2.uuid(), "function2Input2"));
|
||||
res.addEdge(createEdge(function1.uuid(), "function1Output", function3.uuid(), "function3Input1"));
|
||||
res.addEdge(createEdge(function2.uuid(), "function2Output", function3.uuid(), "function3Input2"));
|
||||
res.addEdge(createEdge(function3.uuid(), "function3Output1", output1.uuid(), "output1Value"));
|
||||
res.addEdge(createEdge(function3.uuid(), "function3Output2", output2.uuid(), "output2Value"));
|
||||
return res;
|
||||
}();
|
||||
|
||||
// WHEN
|
||||
const auto statements = graph.createStatements();
|
||||
|
||||
// THEN
|
||||
const auto expected = QList<QShaderGraph::Statement>()
|
||||
<< createStatement(input2, {}, { 1 }) << createStatement(input1, {}, { 0 })
|
||||
<< createStatement(function2, { 0, 1 }, { 3 })
|
||||
<< createStatement(function1, { 0 }, { 2 })
|
||||
<< createStatement(function3, { 2, 3 }, { 4, 5 }) << createStatement(output2, { 5 }, {})
|
||||
<< createStatement(output1, { 4 }, {});
|
||||
dumpStatementsIfNeeded(statements, expected);
|
||||
QCOMPARE(statements, expected);
|
||||
}
|
||||
|
||||
void tst_QShaderGraph::shouldHandleUnboundPortsDuringGraphSerialization()
|
||||
{
|
||||
// GIVEN
|
||||
const auto input = createNode({
|
||||
createPort(QShaderNodePort::Output, "input")
|
||||
});
|
||||
const auto unboundInput = createNode({
|
||||
createPort(QShaderNodePort::Output, "unbound")
|
||||
});
|
||||
const auto output = createNode({
|
||||
createPort(QShaderNodePort::Input, "output")
|
||||
});
|
||||
const auto unboundOutput = createNode({
|
||||
createPort(QShaderNodePort::Input, "unbound")
|
||||
});
|
||||
const auto function = createNode({
|
||||
createPort(QShaderNodePort::Input, "functionInput1"),
|
||||
createPort(QShaderNodePort::Input, "functionInput2"),
|
||||
createPort(QShaderNodePort::Input, "functionInput3"),
|
||||
createPort(QShaderNodePort::Output, "functionOutput1"),
|
||||
createPort(QShaderNodePort::Output, "functionOutput2"),
|
||||
createPort(QShaderNodePort::Output, "functionOutput3")
|
||||
});
|
||||
|
||||
const auto graph = [=] {
|
||||
auto res = QShaderGraph();
|
||||
res.addNode(input);
|
||||
res.addNode(unboundInput);
|
||||
res.addNode(output);
|
||||
res.addNode(unboundOutput);
|
||||
res.addNode(function);
|
||||
res.addEdge(createEdge(input.uuid(), "input", function.uuid(), "functionInput2"));
|
||||
res.addEdge(createEdge(function.uuid(), "functionOutput2", output.uuid(), "output"));
|
||||
return res;
|
||||
}();
|
||||
|
||||
// WHEN
|
||||
const auto statements = graph.createStatements();
|
||||
|
||||
// THEN
|
||||
// Note that no statement has any unbound input
|
||||
const auto expected = QList<QShaderGraph::Statement>() << createStatement(input, {}, { 0 });
|
||||
dumpStatementsIfNeeded(statements, expected);
|
||||
QCOMPARE(statements, expected);
|
||||
}
|
||||
|
||||
void tst_QShaderGraph::shouldSurviveCyclesDuringGraphSerialization()
|
||||
{
|
||||
// GIVEN
|
||||
const auto input = createNode({
|
||||
createPort(QShaderNodePort::Output, "input")
|
||||
});
|
||||
const auto output = createNode({
|
||||
createPort(QShaderNodePort::Input, "output")
|
||||
});
|
||||
const auto function1 = createNode({
|
||||
createPort(QShaderNodePort::Input, "function1Input1"),
|
||||
createPort(QShaderNodePort::Input, "function1Input2"),
|
||||
createPort(QShaderNodePort::Output, "function1Output")
|
||||
});
|
||||
const auto function2 = createNode({
|
||||
createPort(QShaderNodePort::Input, "function2Input"),
|
||||
createPort(QShaderNodePort::Output, "function2Output")
|
||||
});
|
||||
const auto function3 = createNode({
|
||||
createPort(QShaderNodePort::Input, "function3Input"),
|
||||
createPort(QShaderNodePort::Output, "function3Output")
|
||||
});
|
||||
|
||||
const auto graph = [=] {
|
||||
auto res = QShaderGraph();
|
||||
res.addNode(input);
|
||||
res.addNode(output);
|
||||
res.addNode(function1);
|
||||
res.addNode(function2);
|
||||
res.addNode(function3);
|
||||
res.addEdge(createEdge(input.uuid(), "input", function1.uuid(), "function1Input1"));
|
||||
res.addEdge(createEdge(function1.uuid(), "function1Output", function2.uuid(), "function2Input"));
|
||||
res.addEdge(createEdge(function2.uuid(), "function2Output", function3.uuid(), "function3Input"));
|
||||
res.addEdge(createEdge(function3.uuid(), "function3Output", function1.uuid(), "function1Input2"));
|
||||
res.addEdge(createEdge(function2.uuid(), "function2Output", output.uuid(), "output"));
|
||||
return res;
|
||||
}();
|
||||
|
||||
// WHEN
|
||||
const auto statements = graph.createStatements();
|
||||
|
||||
// THEN
|
||||
// The cycle is ignored
|
||||
const auto expected = QList<QShaderGraph::Statement>();
|
||||
dumpStatementsIfNeeded(statements, expected);
|
||||
QCOMPARE(statements, expected);
|
||||
}
|
||||
|
||||
void tst_QShaderGraph::shouldDealWithEdgesJumpingOverLayers()
|
||||
{
|
||||
// GIVEN
|
||||
const auto worldPosition = createNode({
|
||||
createPort(QShaderNodePort::Output, "worldPosition")
|
||||
});
|
||||
const auto texture = createNode({
|
||||
createPort(QShaderNodePort::Output, "texture")
|
||||
});
|
||||
const auto texCoord = createNode({
|
||||
createPort(QShaderNodePort::Output, "texCoord")
|
||||
});
|
||||
const auto lightIntensity = createNode({
|
||||
createPort(QShaderNodePort::Output, "lightIntensity")
|
||||
});
|
||||
const auto exposure = createNode({
|
||||
createPort(QShaderNodePort::Output, "exposure")
|
||||
});
|
||||
const auto fragColor = createNode({
|
||||
createPort(QShaderNodePort::Input, "fragColor")
|
||||
});
|
||||
const auto sampleTexture = createNode({
|
||||
createPort(QShaderNodePort::Input, "sampler"),
|
||||
createPort(QShaderNodePort::Input, "coord"),
|
||||
createPort(QShaderNodePort::Output, "color")
|
||||
});
|
||||
const auto lightFunction = createNode({
|
||||
createPort(QShaderNodePort::Input, "baseColor"),
|
||||
createPort(QShaderNodePort::Input, "position"),
|
||||
createPort(QShaderNodePort::Input, "lightIntensity"),
|
||||
createPort(QShaderNodePort::Output, "outputColor")
|
||||
});
|
||||
const auto exposureFunction = createNode({
|
||||
createPort(QShaderNodePort::Input, "inputColor"),
|
||||
createPort(QShaderNodePort::Input, "exposure"),
|
||||
createPort(QShaderNodePort::Output, "outputColor")
|
||||
});
|
||||
|
||||
const auto graph = [=] {
|
||||
auto res = QShaderGraph();
|
||||
|
||||
res.addNode(worldPosition);
|
||||
res.addNode(texture);
|
||||
res.addNode(texCoord);
|
||||
res.addNode(lightIntensity);
|
||||
res.addNode(exposure);
|
||||
res.addNode(fragColor);
|
||||
res.addNode(sampleTexture);
|
||||
res.addNode(lightFunction);
|
||||
res.addNode(exposureFunction);
|
||||
|
||||
res.addEdge(createEdge(texture.uuid(), "texture", sampleTexture.uuid(), "sampler"));
|
||||
res.addEdge(createEdge(texCoord.uuid(), "texCoord", sampleTexture.uuid(), "coord"));
|
||||
|
||||
res.addEdge(createEdge(worldPosition.uuid(), "worldPosition", lightFunction.uuid(), "position"));
|
||||
res.addEdge(createEdge(sampleTexture.uuid(), "color", lightFunction.uuid(), "baseColor"));
|
||||
res.addEdge(createEdge(lightIntensity.uuid(), "lightIntensity", lightFunction.uuid(), "lightIntensity"));
|
||||
|
||||
res.addEdge(createEdge(lightFunction.uuid(), "outputColor", exposureFunction.uuid(), "inputColor"));
|
||||
res.addEdge(createEdge(exposure.uuid(), "exposure", exposureFunction.uuid(), "exposure"));
|
||||
|
||||
res.addEdge(createEdge(exposureFunction.uuid(), "outputColor", fragColor.uuid(), "fragColor"));
|
||||
|
||||
return res;
|
||||
}();
|
||||
|
||||
// WHEN
|
||||
const auto statements = graph.createStatements();
|
||||
|
||||
// THEN
|
||||
const auto expected = QList<QShaderGraph::Statement>()
|
||||
<< createStatement(texCoord, {}, { 2 }) << createStatement(texture, {}, { 1 })
|
||||
<< createStatement(lightIntensity, {}, { 3 })
|
||||
<< createStatement(sampleTexture, { 1, 2 }, { 5 })
|
||||
<< createStatement(worldPosition, {}, { 0 }) << createStatement(exposure, {}, { 4 })
|
||||
<< createStatement(lightFunction, { 5, 0, 3 }, { 6 })
|
||||
<< createStatement(exposureFunction, { 6, 4 }, { 7 })
|
||||
<< createStatement(fragColor, { 7 }, {});
|
||||
dumpStatementsIfNeeded(statements, expected);
|
||||
QCOMPARE(statements, expected);
|
||||
}
|
||||
|
||||
void tst_QShaderGraph::shouldGenerateDifferentStatementsDependingOnActiveLayers()
|
||||
{
|
||||
// GIVEN
|
||||
const auto texCoord = createNode({
|
||||
createPort(QShaderNodePort::Output, "texCoord")
|
||||
}, {
|
||||
"diffuseTexture",
|
||||
"normalTexture"
|
||||
});
|
||||
const auto diffuseUniform = createNode({
|
||||
createPort(QShaderNodePort::Output, "color")
|
||||
}, {"diffuseUniform"});
|
||||
const auto diffuseTexture = createNode({
|
||||
createPort(QShaderNodePort::Input, "coord"),
|
||||
createPort(QShaderNodePort::Output, "color")
|
||||
}, {"diffuseTexture"});
|
||||
const auto normalUniform = createNode({
|
||||
createPort(QShaderNodePort::Output, "normal")
|
||||
}, {"normalUniform"});
|
||||
const auto normalTexture = createNode({
|
||||
createPort(QShaderNodePort::Input, "coord"),
|
||||
createPort(QShaderNodePort::Output, "normal")
|
||||
}, {"normalTexture"});
|
||||
const auto lightFunction = createNode({
|
||||
createPort(QShaderNodePort::Input, "color"),
|
||||
createPort(QShaderNodePort::Input, "normal"),
|
||||
createPort(QShaderNodePort::Output, "output")
|
||||
});
|
||||
const auto fragColor = createNode({
|
||||
createPort(QShaderNodePort::Input, "fragColor")
|
||||
});
|
||||
|
||||
const auto graph = [=] {
|
||||
auto res = QShaderGraph();
|
||||
|
||||
res.addNode(texCoord);
|
||||
res.addNode(diffuseUniform);
|
||||
res.addNode(diffuseTexture);
|
||||
res.addNode(normalUniform);
|
||||
res.addNode(normalTexture);
|
||||
res.addNode(lightFunction);
|
||||
res.addNode(fragColor);
|
||||
|
||||
res.addEdge(createEdge(diffuseUniform.uuid(), "color", lightFunction.uuid(), "color", {"diffuseUniform"}));
|
||||
res.addEdge(createEdge(texCoord.uuid(), "texCoord", diffuseTexture.uuid(), "coord", {"diffuseTexture"}));
|
||||
res.addEdge(createEdge(diffuseTexture.uuid(), "color", lightFunction.uuid(), "color", {"diffuseTexture"}));
|
||||
|
||||
res.addEdge(createEdge(normalUniform.uuid(), "normal", lightFunction.uuid(), "normal", {"normalUniform"}));
|
||||
res.addEdge(createEdge(texCoord.uuid(), "texCoord", normalTexture.uuid(), "coord", {"normalTexture"}));
|
||||
res.addEdge(createEdge(normalTexture.uuid(), "normal", lightFunction.uuid(), "normal", {"normalTexture"}));
|
||||
|
||||
res.addEdge(createEdge(lightFunction.uuid(), "output", fragColor.uuid(), "fragColor"));
|
||||
|
||||
return res;
|
||||
}();
|
||||
|
||||
{
|
||||
// WHEN
|
||||
const auto statements = graph.createStatements({"diffuseUniform", "normalUniform"});
|
||||
|
||||
// THEN
|
||||
const auto expected = QList<QShaderGraph::Statement>()
|
||||
<< createStatement(normalUniform, {}, { 1 })
|
||||
<< createStatement(diffuseUniform, {}, { 0 })
|
||||
<< createStatement(lightFunction, { 0, 1 }, { 2 })
|
||||
<< createStatement(fragColor, { 2 }, {});
|
||||
dumpStatementsIfNeeded(statements, expected);
|
||||
QCOMPARE(statements, expected);
|
||||
}
|
||||
|
||||
{
|
||||
// WHEN
|
||||
const auto statements = graph.createStatements({"diffuseUniform", "normalTexture"});
|
||||
|
||||
// THEN
|
||||
const auto expected = QList<QShaderGraph::Statement>()
|
||||
<< createStatement(texCoord, {}, { 0 })
|
||||
<< createStatement(normalTexture, { 0 }, { 2 })
|
||||
<< createStatement(diffuseUniform, {}, { 1 })
|
||||
<< createStatement(lightFunction, { 1, 2 }, { 3 })
|
||||
<< createStatement(fragColor, { 3 }, {});
|
||||
dumpStatementsIfNeeded(statements, expected);
|
||||
QCOMPARE(statements, expected);
|
||||
}
|
||||
|
||||
{
|
||||
// WHEN
|
||||
const auto statements = graph.createStatements({"diffuseTexture", "normalUniform"});
|
||||
|
||||
// THEN
|
||||
const auto expected = QList<QShaderGraph::Statement>()
|
||||
<< createStatement(texCoord, {}, { 0 }) << createStatement(normalUniform, {}, { 2 })
|
||||
<< createStatement(diffuseTexture, { 0 }, { 1 })
|
||||
<< createStatement(lightFunction, { 1, 2 }, { 3 })
|
||||
<< createStatement(fragColor, { 3 }, {});
|
||||
dumpStatementsIfNeeded(statements, expected);
|
||||
QCOMPARE(statements, expected);
|
||||
}
|
||||
|
||||
{
|
||||
// WHEN
|
||||
const auto statements = graph.createStatements({"diffuseTexture", "normalTexture"});
|
||||
|
||||
// THEN
|
||||
const auto expected = QList<QShaderGraph::Statement>()
|
||||
<< createStatement(texCoord, {}, { 0 })
|
||||
<< createStatement(normalTexture, { 0 }, { 2 })
|
||||
<< createStatement(diffuseTexture, { 0 }, { 1 })
|
||||
<< createStatement(lightFunction, { 1, 2 }, { 3 })
|
||||
<< createStatement(fragColor, { 3 }, {});
|
||||
dumpStatementsIfNeeded(statements, expected);
|
||||
QCOMPARE(statements, expected);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QShaderGraph::shouldDealWithBranchesWithoutOutput()
|
||||
{
|
||||
// GIVEN
|
||||
const auto input = createNode({
|
||||
createPort(QShaderNodePort::Output, "input")
|
||||
});
|
||||
const auto output = createNode({
|
||||
createPort(QShaderNodePort::Input, "output")
|
||||
});
|
||||
const auto danglingFunction = createNode({
|
||||
createPort(QShaderNodePort::Input, "functionInput"),
|
||||
createPort(QShaderNodePort::Output, "unbound")
|
||||
});
|
||||
const auto function = createNode({
|
||||
createPort(QShaderNodePort::Input, "functionInput"),
|
||||
createPort(QShaderNodePort::Output, "functionOutput")
|
||||
});
|
||||
|
||||
const auto graph = [=] {
|
||||
auto res = QShaderGraph();
|
||||
res.addNode(input);
|
||||
res.addNode(function);
|
||||
res.addNode(danglingFunction);
|
||||
res.addNode(output);
|
||||
res.addEdge(createEdge(input.uuid(), "input", function.uuid(), "functionInput"));
|
||||
res.addEdge(createEdge(input.uuid(), "input", danglingFunction.uuid(), "functionInput"));
|
||||
res.addEdge(createEdge(function.uuid(), "functionOutput", output.uuid(), "output"));
|
||||
return res;
|
||||
}();
|
||||
|
||||
// WHEN
|
||||
const auto statements = graph.createStatements();
|
||||
|
||||
// THEN
|
||||
// Note that no edge leads to the unbound input
|
||||
const auto expected = QList<QShaderGraph::Statement>()
|
||||
<< createStatement(input, {}, { 0 }) << createStatement(function, { 0 }, { 1 })
|
||||
<< createStatement(output, { 1 }, {})
|
||||
<< createStatement(danglingFunction, { 0 }, { 2 });
|
||||
dumpStatementsIfNeeded(statements, expected);
|
||||
QCOMPARE(statements, expected);
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QShaderGraph)
|
||||
|
||||
#include "tst_qshadergraph.moc"
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
# Generated from qshadergraphloader.pro.
|
||||
|
||||
#####################################################################
|
||||
## tst_qshadergraphloader Test:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_test(tst_qshadergraphloader
|
||||
SOURCES
|
||||
tst_qshadergraphloader.cpp
|
||||
PUBLIC_LIBRARIES
|
||||
Qt::Gui
|
||||
Qt::GuiPrivate
|
||||
)
|
||||
|
|
@ -1,627 +0,0 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the test suite of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
|
||||
** 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 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** 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$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
#include <QTest>
|
||||
|
||||
#include <QtCore/qbuffer.h>
|
||||
|
||||
#include <QtGui/private/qshadergraphloader_p.h>
|
||||
#include <QtGui/private/qshaderlanguage_p.h>
|
||||
|
||||
using QBufferPointer = QSharedPointer<QBuffer>;
|
||||
Q_DECLARE_METATYPE(QBufferPointer);
|
||||
|
||||
using PrototypeHash = QHash<QString, QShaderNode>;
|
||||
Q_DECLARE_METATYPE(PrototypeHash);
|
||||
|
||||
namespace
|
||||
{
|
||||
QBufferPointer createBuffer(const QByteArray &data, QIODevice::OpenMode openMode = QIODevice::ReadOnly)
|
||||
{
|
||||
auto buffer = QBufferPointer::create();
|
||||
buffer->setData(data);
|
||||
if (openMode != QIODevice::NotOpen)
|
||||
buffer->open(openMode);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
QShaderFormat createFormat(QShaderFormat::Api api, int majorVersion, int minorVersion)
|
||||
{
|
||||
auto format = QShaderFormat();
|
||||
format.setApi(api);
|
||||
format.setVersion(QVersionNumber(majorVersion, minorVersion));
|
||||
return format;
|
||||
}
|
||||
|
||||
QShaderNodePort createPort(QShaderNodePort::Direction portDirection, const QString &portName)
|
||||
{
|
||||
auto port = QShaderNodePort();
|
||||
port.direction = portDirection;
|
||||
port.name = portName;
|
||||
return port;
|
||||
}
|
||||
|
||||
QShaderNode createNode(const QList<QShaderNodePort> &ports,
|
||||
const QStringList &layers = QStringList())
|
||||
{
|
||||
auto node = QShaderNode();
|
||||
node.setUuid(QUuid::createUuid());
|
||||
node.setLayers(layers);
|
||||
for (const auto &port : ports)
|
||||
node.addPort(port);
|
||||
return node;
|
||||
}
|
||||
|
||||
QShaderGraph::Edge createEdge(const QUuid &sourceUuid, const QString &sourceName,
|
||||
const QUuid &targetUuid, const QString &targetName,
|
||||
const QStringList &layers = QStringList())
|
||||
{
|
||||
auto edge = QShaderGraph::Edge();
|
||||
edge.sourceNodeUuid = sourceUuid;
|
||||
edge.sourcePortName = sourceName;
|
||||
edge.targetNodeUuid = targetUuid;
|
||||
edge.targetPortName = targetName;
|
||||
edge.layers = layers;
|
||||
return edge;
|
||||
}
|
||||
|
||||
QShaderGraph createGraph()
|
||||
{
|
||||
const auto openGLES2 = createFormat(QShaderFormat::OpenGLES, 2, 0);
|
||||
const auto openGL3 = createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0);
|
||||
|
||||
auto graph = QShaderGraph();
|
||||
|
||||
auto worldPosition = createNode({
|
||||
createPort(QShaderNodePort::Output, "value")
|
||||
});
|
||||
worldPosition.setUuid(QUuid("{00000000-0000-0000-0000-000000000001}"));
|
||||
worldPosition.setParameter("name", "worldPosition");
|
||||
worldPosition.setParameter("qualifier", QVariant::fromValue<QShaderLanguage::StorageQualifier>(QShaderLanguage::Input));
|
||||
worldPosition.setParameter("type", QVariant::fromValue<QShaderLanguage::VariableType>(QShaderLanguage::Vec3));
|
||||
worldPosition.addRule(openGLES2, QShaderNode::Rule("highp $type $value = $name;",
|
||||
QByteArrayList() << "$qualifier highp $type $name;"));
|
||||
worldPosition.addRule(openGL3, QShaderNode::Rule("$type $value = $name;",
|
||||
QByteArrayList() << "$qualifier $type $name;"));
|
||||
|
||||
auto texture = createNode({
|
||||
createPort(QShaderNodePort::Output, "texture")
|
||||
});
|
||||
texture.setUuid(QUuid("{00000000-0000-0000-0000-000000000002}"));
|
||||
texture.addRule(openGLES2, QShaderNode::Rule("sampler2D $texture = texture;",
|
||||
QByteArrayList() << "uniform sampler2D texture;"));
|
||||
texture.addRule(openGL3, QShaderNode::Rule("sampler2D $texture = texture;",
|
||||
QByteArrayList() << "uniform sampler2D texture;"));
|
||||
|
||||
auto texCoord = createNode({
|
||||
createPort(QShaderNodePort::Output, "texCoord")
|
||||
});
|
||||
texCoord.setUuid(QUuid("{00000000-0000-0000-0000-000000000003}"));
|
||||
texCoord.addRule(openGLES2, QShaderNode::Rule("highp vec2 $texCoord = texCoord;",
|
||||
QByteArrayList() << "varying highp vec2 texCoord;"));
|
||||
texCoord.addRule(openGL3, QShaderNode::Rule("vec2 $texCoord = texCoord;",
|
||||
QByteArrayList() << "in vec2 texCoord;"));
|
||||
|
||||
auto lightIntensity = createNode({
|
||||
createPort(QShaderNodePort::Output, "value")
|
||||
});
|
||||
lightIntensity.setUuid(QUuid("{00000000-0000-0000-0000-000000000004}"));
|
||||
lightIntensity.setParameter("name", "defaultName");
|
||||
lightIntensity.setParameter("qualifier", QVariant::fromValue<QShaderLanguage::StorageQualifier>(QShaderLanguage::Uniform));
|
||||
lightIntensity.setParameter("type", QVariant::fromValue<QShaderLanguage::VariableType>(QShaderLanguage::Float));
|
||||
lightIntensity.addRule(openGLES2, QShaderNode::Rule("highp $type $value = $name;",
|
||||
QByteArrayList() << "$qualifier highp $type $name;"));
|
||||
lightIntensity.addRule(openGL3, QShaderNode::Rule("$type $value = $name;",
|
||||
QByteArrayList() << "$qualifier $type $name;"));
|
||||
|
||||
auto exposure = createNode({
|
||||
createPort(QShaderNodePort::Output, "exposure")
|
||||
});
|
||||
exposure.setUuid(QUuid("{00000000-0000-0000-0000-000000000005}"));
|
||||
exposure.addRule(openGLES2, QShaderNode::Rule("highp float $exposure = exposure;",
|
||||
QByteArrayList() << "uniform highp float exposure;"));
|
||||
exposure.addRule(openGL3, QShaderNode::Rule("float $exposure = exposure;",
|
||||
QByteArrayList() << "uniform float exposure;"));
|
||||
|
||||
auto fragColor = createNode({
|
||||
createPort(QShaderNodePort::Input, "fragColor")
|
||||
});
|
||||
fragColor.setUuid(QUuid("{00000000-0000-0000-0000-000000000006}"));
|
||||
fragColor.addRule(openGLES2, QShaderNode::Rule("gl_fragColor = $fragColor;"));
|
||||
fragColor.addRule(openGL3, QShaderNode::Rule("fragColor = $fragColor;",
|
||||
QByteArrayList() << "out vec4 fragColor;"));
|
||||
|
||||
auto sampleTexture = createNode({
|
||||
createPort(QShaderNodePort::Input, "sampler"),
|
||||
createPort(QShaderNodePort::Input, "coord"),
|
||||
createPort(QShaderNodePort::Output, "color")
|
||||
});
|
||||
sampleTexture.setUuid(QUuid("{00000000-0000-0000-0000-000000000007}"));
|
||||
sampleTexture.addRule(openGLES2, QShaderNode::Rule("highp vec4 $color = texture2D($sampler, $coord);"));
|
||||
sampleTexture.addRule(openGL3, QShaderNode::Rule("vec4 $color = texture2D($sampler, $coord);"));
|
||||
|
||||
auto lightFunction = createNode({
|
||||
createPort(QShaderNodePort::Input, "baseColor"),
|
||||
createPort(QShaderNodePort::Input, "position"),
|
||||
createPort(QShaderNodePort::Input, "lightIntensity"),
|
||||
createPort(QShaderNodePort::Output, "outputColor")
|
||||
});
|
||||
lightFunction.setUuid(QUuid("{00000000-0000-0000-0000-000000000008}"));
|
||||
lightFunction.addRule(openGLES2, QShaderNode::Rule("highp vec4 $outputColor = lightModel($baseColor, $position, $lightIntensity);",
|
||||
QByteArrayList() << "#pragma include es2/lightmodel.frag.inc"));
|
||||
lightFunction.addRule(openGL3, QShaderNode::Rule("vec4 $outputColor = lightModel($baseColor, $position, $lightIntensity);",
|
||||
QByteArrayList() << "#pragma include gl3/lightmodel.frag.inc"));
|
||||
|
||||
auto exposureFunction = createNode({
|
||||
createPort(QShaderNodePort::Input, "inputColor"),
|
||||
createPort(QShaderNodePort::Input, "exposure"),
|
||||
createPort(QShaderNodePort::Output, "outputColor")
|
||||
});
|
||||
exposureFunction.setUuid(QUuid("{00000000-0000-0000-0000-000000000009}"));
|
||||
exposureFunction.addRule(openGLES2, QShaderNode::Rule("highp vec4 $outputColor = $inputColor * pow(2.0, $exposure);"));
|
||||
exposureFunction.addRule(openGL3, QShaderNode::Rule("vec4 $outputColor = $inputColor * pow(2.0, $exposure);"));
|
||||
|
||||
graph.addNode(worldPosition);
|
||||
graph.addNode(texture);
|
||||
graph.addNode(texCoord);
|
||||
graph.addNode(lightIntensity);
|
||||
graph.addNode(exposure);
|
||||
graph.addNode(fragColor);
|
||||
graph.addNode(sampleTexture);
|
||||
graph.addNode(lightFunction);
|
||||
graph.addNode(exposureFunction);
|
||||
|
||||
graph.addEdge(createEdge(texture.uuid(), "texture", sampleTexture.uuid(), "sampler"));
|
||||
graph.addEdge(createEdge(texCoord.uuid(), "texCoord", sampleTexture.uuid(), "coord"));
|
||||
|
||||
graph.addEdge(createEdge(worldPosition.uuid(), "value", lightFunction.uuid(), "position"));
|
||||
graph.addEdge(createEdge(sampleTexture.uuid(), "color", lightFunction.uuid(), "baseColor"));
|
||||
graph.addEdge(createEdge(lightIntensity.uuid(), "value", lightFunction.uuid(), "lightIntensity"));
|
||||
|
||||
graph.addEdge(createEdge(lightFunction.uuid(), "outputColor", exposureFunction.uuid(), "inputColor"));
|
||||
graph.addEdge(createEdge(exposure.uuid(), "exposure", exposureFunction.uuid(), "exposure"));
|
||||
|
||||
graph.addEdge(createEdge(exposureFunction.uuid(), "outputColor", fragColor.uuid(), "fragColor"));
|
||||
|
||||
return graph;
|
||||
}
|
||||
|
||||
void debugStatement(const QString &prefix, const QShaderGraph::Statement &statement)
|
||||
{
|
||||
qDebug() << prefix << statement.inputs << statement.uuid().toString() << statement.outputs;
|
||||
}
|
||||
|
||||
void dumpStatementsIfNeeded(const QList<QShaderGraph::Statement> &statements,
|
||||
const QList<QShaderGraph::Statement> &expected)
|
||||
{
|
||||
if (statements != expected) {
|
||||
for (int i = 0; i < qMax(statements.size(), expected.size()); i++) {
|
||||
qDebug() << "----" << i << "----";
|
||||
if (i < statements.size())
|
||||
debugStatement("A:", statements.at(i));
|
||||
if (i < expected.size())
|
||||
debugStatement("E:", expected.at(i));
|
||||
qDebug() << "-----------";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class tst_QShaderGraphLoader : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
private slots:
|
||||
void shouldManipulateLoaderMembers();
|
||||
void shouldLoadFromJsonStream_data();
|
||||
void shouldLoadFromJsonStream();
|
||||
};
|
||||
|
||||
void tst_QShaderGraphLoader::shouldManipulateLoaderMembers()
|
||||
{
|
||||
// GIVEN
|
||||
auto loader = QShaderGraphLoader();
|
||||
|
||||
// THEN (default state)
|
||||
QCOMPARE(loader.status(), QShaderGraphLoader::Null);
|
||||
QVERIFY(!loader.device());
|
||||
QVERIFY(loader.graph().nodes().isEmpty());
|
||||
QVERIFY(loader.graph().edges().isEmpty());
|
||||
QVERIFY(loader.prototypes().isEmpty());
|
||||
|
||||
// WHEN
|
||||
auto device1 = createBuffer(QByteArray("..........."), QIODevice::NotOpen);
|
||||
loader.setDevice(device1.data());
|
||||
|
||||
// THEN
|
||||
QCOMPARE(loader.status(), QShaderGraphLoader::Error);
|
||||
QCOMPARE(loader.device(), device1.data());
|
||||
QVERIFY(loader.graph().nodes().isEmpty());
|
||||
QVERIFY(loader.graph().edges().isEmpty());
|
||||
|
||||
// WHEN
|
||||
auto device2 = createBuffer(QByteArray("..........."), QIODevice::ReadOnly);
|
||||
loader.setDevice(device2.data());
|
||||
|
||||
// THEN
|
||||
QCOMPARE(loader.status(), QShaderGraphLoader::Waiting);
|
||||
QCOMPARE(loader.device(), device2.data());
|
||||
QVERIFY(loader.graph().nodes().isEmpty());
|
||||
QVERIFY(loader.graph().edges().isEmpty());
|
||||
|
||||
|
||||
// WHEN
|
||||
const auto prototypes = [&]{
|
||||
auto res = QHash<QString, QShaderNode>();
|
||||
res.insert("foo", createNode({}));
|
||||
return res;
|
||||
}();
|
||||
loader.setPrototypes(prototypes);
|
||||
|
||||
// THEN
|
||||
QCOMPARE(loader.prototypes().size(), prototypes.size());
|
||||
QVERIFY(loader.prototypes().contains("foo"));
|
||||
QCOMPARE(loader.prototypes().value("foo").uuid(), prototypes.value("foo").uuid());
|
||||
}
|
||||
|
||||
void tst_QShaderGraphLoader::shouldLoadFromJsonStream_data()
|
||||
{
|
||||
QTest::addColumn<QBufferPointer>("device");
|
||||
QTest::addColumn<PrototypeHash>("prototypes");
|
||||
QTest::addColumn<QShaderGraph>("graph");
|
||||
QTest::addColumn<QShaderGraphLoader::Status>("status");
|
||||
|
||||
QTest::newRow("empty") << createBuffer("", QIODevice::ReadOnly) << PrototypeHash()
|
||||
<< QShaderGraph() << QShaderGraphLoader::Error;
|
||||
|
||||
const auto smallJson = "{"
|
||||
" \"nodes\": ["
|
||||
" {"
|
||||
" \"uuid\": \"{00000000-0000-0000-0000-000000000001}\","
|
||||
" \"type\": \"MyInput\","
|
||||
" \"layers\": [\"foo\", \"bar\"]"
|
||||
" },"
|
||||
" {"
|
||||
" \"uuid\": \"{00000000-0000-0000-0000-000000000002}\","
|
||||
" \"type\": \"MyOutput\""
|
||||
" },"
|
||||
" {"
|
||||
" \"uuid\": \"{00000000-0000-0000-0000-000000000003}\","
|
||||
" \"type\": \"MyFunction\""
|
||||
" }"
|
||||
" ],"
|
||||
" \"edges\": ["
|
||||
" {"
|
||||
" \"sourceUuid\": \"{00000000-0000-0000-0000-000000000001}\","
|
||||
" \"sourcePort\": \"input\","
|
||||
" \"targetUuid\": \"{00000000-0000-0000-0000-000000000003}\","
|
||||
" \"targetPort\": \"functionInput\","
|
||||
" \"layers\": [\"bar\", \"baz\"]"
|
||||
" },"
|
||||
" {"
|
||||
" \"sourceUuid\": \"{00000000-0000-0000-0000-000000000003}\","
|
||||
" \"sourcePort\": \"functionOutput\","
|
||||
" \"targetUuid\": \"{00000000-0000-0000-0000-000000000002}\","
|
||||
" \"targetPort\": \"output\""
|
||||
" }"
|
||||
" ]"
|
||||
"}";
|
||||
|
||||
const auto smallProtos = [&]{
|
||||
auto protos = PrototypeHash();
|
||||
|
||||
auto input = createNode({
|
||||
createPort(QShaderNodePort::Output, "input")
|
||||
});
|
||||
protos.insert("MyInput", input);
|
||||
|
||||
auto output = createNode({
|
||||
createPort(QShaderNodePort::Input, "output")
|
||||
});
|
||||
protos.insert("MyOutput", output);
|
||||
|
||||
auto function = createNode({
|
||||
createPort(QShaderNodePort::Input, "functionInput"),
|
||||
createPort(QShaderNodePort::Output, "functionOutput")
|
||||
});
|
||||
protos.insert("MyFunction", function);
|
||||
return protos;
|
||||
}();
|
||||
|
||||
const auto smallGraph = [&]{
|
||||
auto graph = QShaderGraph();
|
||||
|
||||
auto input = createNode({
|
||||
createPort(QShaderNodePort::Output, "input")
|
||||
}, {"foo", "bar"});
|
||||
input.setUuid(QUuid("{00000000-0000-0000-0000-000000000001}"));
|
||||
auto output = createNode({
|
||||
createPort(QShaderNodePort::Input, "output")
|
||||
});
|
||||
output.setUuid(QUuid("{00000000-0000-0000-0000-000000000002}"));
|
||||
auto function = createNode({
|
||||
createPort(QShaderNodePort::Input, "functionInput"),
|
||||
createPort(QShaderNodePort::Output, "functionOutput")
|
||||
});
|
||||
function.setUuid(QUuid("{00000000-0000-0000-0000-000000000003}"));
|
||||
|
||||
graph.addNode(input);
|
||||
graph.addNode(output);
|
||||
graph.addNode(function);
|
||||
graph.addEdge(createEdge(input.uuid(), "input", function.uuid(), "functionInput", {"bar", "baz"}));
|
||||
graph.addEdge(createEdge(function.uuid(), "functionOutput", output.uuid(), "output"));
|
||||
|
||||
return graph;
|
||||
}();
|
||||
|
||||
QTest::newRow("TwoNodesOneEdge") << createBuffer(smallJson) << smallProtos << smallGraph << QShaderGraphLoader::Ready;
|
||||
QTest::newRow("NotOpen") << createBuffer(smallJson, QIODevice::NotOpen) << smallProtos << QShaderGraph() << QShaderGraphLoader::Error;
|
||||
QTest::newRow("NoPrototype") << createBuffer(smallJson) << PrototypeHash() << QShaderGraph() << QShaderGraphLoader::Error;
|
||||
|
||||
const auto complexJson = "{"
|
||||
" \"nodes\": ["
|
||||
" {"
|
||||
" \"uuid\": \"{00000000-0000-0000-0000-000000000001}\","
|
||||
" \"type\": \"inputValue\","
|
||||
" \"parameters\": {"
|
||||
" \"name\": \"worldPosition\","
|
||||
" \"qualifier\": {"
|
||||
" \"type\": \"QShaderLanguage::StorageQualifier\","
|
||||
" \"value\": \"QShaderLanguage::Input\""
|
||||
" },"
|
||||
" \"type\": {"
|
||||
" \"type\": \"QShaderLanguage::VariableType\","
|
||||
" \"value\": \"QShaderLanguage::Vec3\""
|
||||
" }"
|
||||
" }"
|
||||
" },"
|
||||
" {"
|
||||
" \"uuid\": \"{00000000-0000-0000-0000-000000000002}\","
|
||||
" \"type\": \"texture\""
|
||||
" },"
|
||||
" {"
|
||||
" \"uuid\": \"{00000000-0000-0000-0000-000000000003}\","
|
||||
" \"type\": \"texCoord\""
|
||||
" },"
|
||||
" {"
|
||||
" \"uuid\": \"{00000000-0000-0000-0000-000000000004}\","
|
||||
" \"type\": \"inputValue\""
|
||||
" },"
|
||||
" {"
|
||||
" \"uuid\": \"{00000000-0000-0000-0000-000000000005}\","
|
||||
" \"type\": \"exposure\""
|
||||
" },"
|
||||
" {"
|
||||
" \"uuid\": \"{00000000-0000-0000-0000-000000000006}\","
|
||||
" \"type\": \"fragColor\""
|
||||
" },"
|
||||
" {"
|
||||
" \"uuid\": \"{00000000-0000-0000-0000-000000000007}\","
|
||||
" \"type\": \"sampleTexture\""
|
||||
" },"
|
||||
" {"
|
||||
" \"uuid\": \"{00000000-0000-0000-0000-000000000008}\","
|
||||
" \"type\": \"lightModel\""
|
||||
" },"
|
||||
" {"
|
||||
" \"uuid\": \"{00000000-0000-0000-0000-000000000009}\","
|
||||
" \"type\": \"exposureFunction\""
|
||||
" }"
|
||||
" ],"
|
||||
" \"edges\": ["
|
||||
" {"
|
||||
" \"sourceUuid\": \"{00000000-0000-0000-0000-000000000002}\","
|
||||
" \"sourcePort\": \"texture\","
|
||||
" \"targetUuid\": \"{00000000-0000-0000-0000-000000000007}\","
|
||||
" \"targetPort\": \"sampler\""
|
||||
" },"
|
||||
" {"
|
||||
" \"sourceUuid\": \"{00000000-0000-0000-0000-000000000003}\","
|
||||
" \"sourcePort\": \"texCoord\","
|
||||
" \"targetUuid\": \"{00000000-0000-0000-0000-000000000007}\","
|
||||
" \"targetPort\": \"coord\""
|
||||
" },"
|
||||
" {"
|
||||
" \"sourceUuid\": \"{00000000-0000-0000-0000-000000000001}\","
|
||||
" \"sourcePort\": \"value\","
|
||||
" \"targetUuid\": \"{00000000-0000-0000-0000-000000000008}\","
|
||||
" \"targetPort\": \"position\""
|
||||
" },"
|
||||
" {"
|
||||
" \"sourceUuid\": \"{00000000-0000-0000-0000-000000000007}\","
|
||||
" \"sourcePort\": \"color\","
|
||||
" \"targetUuid\": \"{00000000-0000-0000-0000-000000000008}\","
|
||||
" \"targetPort\": \"baseColor\""
|
||||
" },"
|
||||
" {"
|
||||
" \"sourceUuid\": \"{00000000-0000-0000-0000-000000000004}\","
|
||||
" \"sourcePort\": \"value\","
|
||||
" \"targetUuid\": \"{00000000-0000-0000-0000-000000000008}\","
|
||||
" \"targetPort\": \"lightIntensity\""
|
||||
" },"
|
||||
" {"
|
||||
" \"sourceUuid\": \"{00000000-0000-0000-0000-000000000008}\","
|
||||
" \"sourcePort\": \"outputColor\","
|
||||
" \"targetUuid\": \"{00000000-0000-0000-0000-000000000009}\","
|
||||
" \"targetPort\": \"inputColor\""
|
||||
" },"
|
||||
" {"
|
||||
" \"sourceUuid\": \"{00000000-0000-0000-0000-000000000005}\","
|
||||
" \"sourcePort\": \"exposure\","
|
||||
" \"targetUuid\": \"{00000000-0000-0000-0000-000000000009}\","
|
||||
" \"targetPort\": \"exposure\""
|
||||
" },"
|
||||
" {"
|
||||
" \"sourceUuid\": \"{00000000-0000-0000-0000-000000000009}\","
|
||||
" \"sourcePort\": \"outputColor\","
|
||||
" \"targetUuid\": \"{00000000-0000-0000-0000-000000000006}\","
|
||||
" \"targetPort\": \"fragColor\""
|
||||
" }"
|
||||
" ]"
|
||||
"}";
|
||||
|
||||
const auto complexProtos = [&]{
|
||||
const auto openGLES2 = createFormat(QShaderFormat::OpenGLES, 2, 0);
|
||||
const auto openGL3 = createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0);
|
||||
|
||||
auto protos = PrototypeHash();
|
||||
|
||||
auto inputValue = createNode({
|
||||
createPort(QShaderNodePort::Output, "value")
|
||||
});
|
||||
inputValue.setParameter("name", "defaultName");
|
||||
inputValue.setParameter("qualifier", QVariant::fromValue<QShaderLanguage::StorageQualifier>(QShaderLanguage::Uniform));
|
||||
inputValue.setParameter("type", QVariant::fromValue<QShaderLanguage::VariableType>(QShaderLanguage::Float));
|
||||
inputValue.addRule(openGLES2, QShaderNode::Rule("highp $type $value = $name;",
|
||||
QByteArrayList() << "$qualifier highp $type $name;"));
|
||||
inputValue.addRule(openGL3, QShaderNode::Rule("$type $value = $name;",
|
||||
QByteArrayList() << "$qualifier $type $name;"));
|
||||
protos.insert("inputValue", inputValue);
|
||||
|
||||
auto texture = createNode({
|
||||
createPort(QShaderNodePort::Output, "texture")
|
||||
});
|
||||
texture.addRule(openGLES2, QShaderNode::Rule("sampler2D $texture = texture;",
|
||||
QByteArrayList() << "uniform sampler2D texture;"));
|
||||
texture.addRule(openGL3, QShaderNode::Rule("sampler2D $texture = texture;",
|
||||
QByteArrayList() << "uniform sampler2D texture;"));
|
||||
protos.insert("texture", texture);
|
||||
|
||||
auto texCoord = createNode({
|
||||
createPort(QShaderNodePort::Output, "texCoord")
|
||||
});
|
||||
texCoord.addRule(openGLES2, QShaderNode::Rule("highp vec2 $texCoord = texCoord;",
|
||||
QByteArrayList() << "varying highp vec2 texCoord;"));
|
||||
texCoord.addRule(openGL3, QShaderNode::Rule("vec2 $texCoord = texCoord;",
|
||||
QByteArrayList() << "in vec2 texCoord;"));
|
||||
protos.insert("texCoord", texCoord);
|
||||
|
||||
auto exposure = createNode({
|
||||
createPort(QShaderNodePort::Output, "exposure")
|
||||
});
|
||||
exposure.addRule(openGLES2, QShaderNode::Rule("highp float $exposure = exposure;",
|
||||
QByteArrayList() << "uniform highp float exposure;"));
|
||||
exposure.addRule(openGL3, QShaderNode::Rule("float $exposure = exposure;",
|
||||
QByteArrayList() << "uniform float exposure;"));
|
||||
protos.insert("exposure", exposure);
|
||||
|
||||
auto fragColor = createNode({
|
||||
createPort(QShaderNodePort::Input, "fragColor")
|
||||
});
|
||||
fragColor.addRule(openGLES2, QShaderNode::Rule("gl_fragColor = $fragColor;"));
|
||||
fragColor.addRule(openGL3, QShaderNode::Rule("fragColor = $fragColor;",
|
||||
QByteArrayList() << "out vec4 fragColor;"));
|
||||
protos.insert("fragColor", fragColor);
|
||||
|
||||
auto sampleTexture = createNode({
|
||||
createPort(QShaderNodePort::Input, "sampler"),
|
||||
createPort(QShaderNodePort::Input, "coord"),
|
||||
createPort(QShaderNodePort::Output, "color")
|
||||
});
|
||||
sampleTexture.addRule(openGLES2, QShaderNode::Rule("highp vec4 $color = texture2D($sampler, $coord);"));
|
||||
sampleTexture.addRule(openGL3, QShaderNode::Rule("vec4 $color = texture2D($sampler, $coord);"));
|
||||
protos.insert("sampleTexture", sampleTexture);
|
||||
|
||||
auto lightModel = createNode({
|
||||
createPort(QShaderNodePort::Input, "baseColor"),
|
||||
createPort(QShaderNodePort::Input, "position"),
|
||||
createPort(QShaderNodePort::Input, "lightIntensity"),
|
||||
createPort(QShaderNodePort::Output, "outputColor")
|
||||
});
|
||||
lightModel.addRule(openGLES2, QShaderNode::Rule("highp vec4 $outputColor = lightModel($baseColor, $position, $lightIntensity);",
|
||||
QByteArrayList() << "#pragma include es2/lightmodel.frag.inc"));
|
||||
lightModel.addRule(openGL3, QShaderNode::Rule("vec4 $outputColor = lightModel($baseColor, $position, $lightIntensity);",
|
||||
QByteArrayList() << "#pragma include gl3/lightmodel.frag.inc"));
|
||||
protos.insert("lightModel", lightModel);
|
||||
|
||||
auto exposureFunction = createNode({
|
||||
createPort(QShaderNodePort::Input, "inputColor"),
|
||||
createPort(QShaderNodePort::Input, "exposure"),
|
||||
createPort(QShaderNodePort::Output, "outputColor")
|
||||
});
|
||||
exposureFunction.addRule(openGLES2, QShaderNode::Rule("highp vec4 $outputColor = $inputColor * pow(2.0, $exposure);"));
|
||||
exposureFunction.addRule(openGL3, QShaderNode::Rule("vec4 $outputColor = $inputColor * pow(2.0, $exposure);"));
|
||||
protos.insert("exposureFunction", exposureFunction);
|
||||
|
||||
return protos;
|
||||
}();
|
||||
|
||||
const auto complexGraph = createGraph();
|
||||
|
||||
QTest::newRow("ComplexGraph") << createBuffer(complexJson) << complexProtos << complexGraph << QShaderGraphLoader::Ready;
|
||||
}
|
||||
|
||||
void tst_QShaderGraphLoader::shouldLoadFromJsonStream()
|
||||
{
|
||||
// GIVEN
|
||||
QFETCH(QBufferPointer, device);
|
||||
QFETCH(PrototypeHash, prototypes);
|
||||
|
||||
auto loader = QShaderGraphLoader();
|
||||
|
||||
// WHEN
|
||||
loader.setPrototypes(prototypes);
|
||||
loader.setDevice(device.data());
|
||||
loader.load();
|
||||
|
||||
// THEN
|
||||
QFETCH(QShaderGraphLoader::Status, status);
|
||||
QCOMPARE(loader.status(), status);
|
||||
|
||||
QFETCH(QShaderGraph, graph);
|
||||
const auto statements = loader.graph().createStatements({"foo", "bar", "baz"});
|
||||
const auto expected = graph.createStatements({"foo", "bar", "baz"});
|
||||
dumpStatementsIfNeeded(statements, expected);
|
||||
QCOMPARE(statements, expected);
|
||||
|
||||
const auto sortedParameters = [](const QShaderNode &node) {
|
||||
auto res = node.parameterNames();
|
||||
res.sort();
|
||||
return res;
|
||||
};
|
||||
|
||||
for (int i = 0; i < statements.size(); i++) {
|
||||
const auto actualNode = statements.at(i).node;
|
||||
const auto expectedNode = expected.at(i).node;
|
||||
|
||||
QCOMPARE(actualNode.layers(), expectedNode.layers());
|
||||
QCOMPARE(actualNode.ports(), expectedNode.ports());
|
||||
QCOMPARE(sortedParameters(actualNode), sortedParameters(expectedNode));
|
||||
for (const auto &name : expectedNode.parameterNames()) {
|
||||
QCOMPARE(actualNode.parameter(name), expectedNode.parameter(name));
|
||||
}
|
||||
QCOMPARE(actualNode.availableFormats(), expectedNode.availableFormats());
|
||||
for (const auto &format : expectedNode.availableFormats()) {
|
||||
QCOMPARE(actualNode.rule(format), expectedNode.rule(format));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QShaderGraphLoader)
|
||||
|
||||
#include "tst_qshadergraphloader.moc"
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
# Generated from qshadernodes.pro.
|
||||
|
||||
#####################################################################
|
||||
## tst_qshadernodes Test:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_test(tst_qshadernodes
|
||||
SOURCES
|
||||
tst_qshadernodes.cpp
|
||||
PUBLIC_LIBRARIES
|
||||
Qt::Gui
|
||||
Qt::GuiPrivate
|
||||
)
|
||||
|
|
@ -1,548 +0,0 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the test suite of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
|
||||
** 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 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** 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$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
#include <QTest>
|
||||
|
||||
#include <QtGui/private/qshaderformat_p.h>
|
||||
#include <QtGui/private/qshadernode_p.h>
|
||||
#include <QtGui/private/qshadernodeport_p.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
QShaderFormat createFormat(QShaderFormat::Api api, int majorVersion, int minorVersion,
|
||||
const QStringList &extensions = QStringList(),
|
||||
const QString &vendor = QString())
|
||||
{
|
||||
auto format = QShaderFormat();
|
||||
format.setApi(api);
|
||||
format.setVersion(QVersionNumber(majorVersion, minorVersion));
|
||||
format.setExtensions(extensions);
|
||||
format.setVendor(vendor);
|
||||
return format;
|
||||
}
|
||||
|
||||
QShaderNodePort createPort(QShaderNodePort::Direction direction, const QString &name)
|
||||
{
|
||||
auto port = QShaderNodePort();
|
||||
port.direction = direction;
|
||||
port.name = name;
|
||||
return port;
|
||||
}
|
||||
}
|
||||
|
||||
class tst_QShaderNodes : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
private slots:
|
||||
void shouldManipulateFormatMembers();
|
||||
void shouldVerifyFormatsEquality_data();
|
||||
void shouldVerifyFormatsEquality();
|
||||
void shouldVerifyFormatsCompatibilities_data();
|
||||
void shouldVerifyFormatsCompatibilities();
|
||||
|
||||
void shouldHaveDefaultPortState();
|
||||
void shouldVerifyPortsEquality_data();
|
||||
void shouldVerifyPortsEquality();
|
||||
|
||||
void shouldManipulateNodeMembers();
|
||||
void shouldHandleNodeRulesSupportAndOrder();
|
||||
};
|
||||
|
||||
void tst_QShaderNodes::shouldManipulateFormatMembers()
|
||||
{
|
||||
// GIVEN
|
||||
auto format = QShaderFormat();
|
||||
|
||||
// THEN (default state)
|
||||
QCOMPARE(format.api(), QShaderFormat::NoApi);
|
||||
QCOMPARE(format.version().majorVersion(), 0);
|
||||
QCOMPARE(format.version().minorVersion(), 0);
|
||||
QCOMPARE(format.extensions(), QStringList());
|
||||
QCOMPARE(format.vendor(), QString());
|
||||
QVERIFY(!format.isValid());
|
||||
|
||||
// WHEN
|
||||
format.setApi(QShaderFormat::OpenGLES);
|
||||
|
||||
// THEN
|
||||
QCOMPARE(format.api(), QShaderFormat::OpenGLES);
|
||||
QCOMPARE(format.version().majorVersion(), 0);
|
||||
QCOMPARE(format.version().minorVersion(), 0);
|
||||
QCOMPARE(format.extensions(), QStringList());
|
||||
QCOMPARE(format.vendor(), QString());
|
||||
QVERIFY(!format.isValid());
|
||||
|
||||
// WHEN
|
||||
format.setVersion(QVersionNumber(3));
|
||||
|
||||
// THEN
|
||||
QCOMPARE(format.api(), QShaderFormat::OpenGLES);
|
||||
QCOMPARE(format.version().majorVersion(), 3);
|
||||
QCOMPARE(format.version().minorVersion(), 0);
|
||||
QCOMPARE(format.extensions(), QStringList());
|
||||
QCOMPARE(format.vendor(), QString());
|
||||
QVERIFY(format.isValid());
|
||||
|
||||
// WHEN
|
||||
format.setVersion(QVersionNumber(3, 2));
|
||||
|
||||
// THEN
|
||||
QCOMPARE(format.api(), QShaderFormat::OpenGLES);
|
||||
QCOMPARE(format.version().majorVersion(), 3);
|
||||
QCOMPARE(format.version().minorVersion(), 2);
|
||||
QCOMPARE(format.extensions(), QStringList());
|
||||
QCOMPARE(format.vendor(), QString());
|
||||
QVERIFY(format.isValid());
|
||||
|
||||
// WHEN
|
||||
format.setExtensions({"foo", "bar"});
|
||||
|
||||
// THEN
|
||||
QCOMPARE(format.api(), QShaderFormat::OpenGLES);
|
||||
QCOMPARE(format.version().majorVersion(), 3);
|
||||
QCOMPARE(format.version().minorVersion(), 2);
|
||||
QCOMPARE(format.extensions(), QStringList({"bar", "foo"}));
|
||||
QCOMPARE(format.vendor(), QString());
|
||||
QVERIFY(format.isValid());
|
||||
|
||||
// WHEN
|
||||
format.setVendor(QStringLiteral("KDAB"));
|
||||
|
||||
// THEN
|
||||
QCOMPARE(format.api(), QShaderFormat::OpenGLES);
|
||||
QCOMPARE(format.version().majorVersion(), 3);
|
||||
QCOMPARE(format.version().minorVersion(), 2);
|
||||
QCOMPARE(format.extensions(), QStringList({"bar", "foo"}));
|
||||
QCOMPARE(format.vendor(), QStringLiteral("KDAB"));
|
||||
QVERIFY(format.isValid());
|
||||
}
|
||||
|
||||
void tst_QShaderNodes::shouldVerifyFormatsEquality_data()
|
||||
{
|
||||
QTest::addColumn<QShaderFormat>("left");
|
||||
QTest::addColumn<QShaderFormat>("right");
|
||||
QTest::addColumn<bool>("expected");
|
||||
|
||||
QTest::newRow("Equals") << createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0, {"foo", "bar"}, "KDAB")
|
||||
<< createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0, {"foo", "bar"}, "KDAB")
|
||||
<< true;
|
||||
QTest::newRow("Apis") << createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0, {"foo", "bar"}, "KDAB")
|
||||
<< createFormat(QShaderFormat::OpenGLNoProfile, 3, 0, {"foo", "bar"}, "KDAB")
|
||||
<< false;
|
||||
QTest::newRow("Major") << createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0, {"foo", "bar"}, "KDAB")
|
||||
<< createFormat(QShaderFormat::OpenGLCoreProfile, 2, 0, {"foo", "bar"}, "KDAB")
|
||||
<< false;
|
||||
QTest::newRow("Minor") << createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0, {"foo", "bar"}, "KDAB")
|
||||
<< createFormat(QShaderFormat::OpenGLCoreProfile, 3, 1, {"foo", "bar"}, "KDAB")
|
||||
<< false;
|
||||
QTest::newRow("Extensions") << createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0, {"foo", "bar"}, "KDAB")
|
||||
<< createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0, {"foo"}, "KDAB")
|
||||
<< false;
|
||||
QTest::newRow("Vendor") << createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0, {"foo", "bar"}, "KDAB")
|
||||
<< createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0, {"foo", "bar"})
|
||||
<< false;
|
||||
}
|
||||
|
||||
void tst_QShaderNodes::shouldVerifyFormatsEquality()
|
||||
{
|
||||
// GIVEN
|
||||
QFETCH(QShaderFormat, left);
|
||||
QFETCH(QShaderFormat, right);
|
||||
|
||||
// WHEN
|
||||
const auto equal = (left == right);
|
||||
const auto notEqual = (left != right);
|
||||
|
||||
// THEN
|
||||
QFETCH(bool, expected);
|
||||
QCOMPARE(equal, expected);
|
||||
QCOMPARE(notEqual, !expected);
|
||||
}
|
||||
|
||||
void tst_QShaderNodes::shouldVerifyFormatsCompatibilities_data()
|
||||
{
|
||||
QTest::addColumn<QShaderFormat>("reference");
|
||||
QTest::addColumn<QShaderFormat>("tested");
|
||||
QTest::addColumn<bool>("expected");
|
||||
|
||||
QTest::newRow("NoProfileVsES") << createFormat(QShaderFormat::OpenGLNoProfile, 2, 0)
|
||||
<< createFormat(QShaderFormat::OpenGLES, 2, 0)
|
||||
<< true;
|
||||
QTest::newRow("CoreProfileVsES") << createFormat(QShaderFormat::OpenGLCoreProfile, 2, 0)
|
||||
<< createFormat(QShaderFormat::OpenGLES, 2, 0)
|
||||
<< false;
|
||||
QTest::newRow("CompatProfileVsES") << createFormat(QShaderFormat::OpenGLCompatibilityProfile, 2, 0)
|
||||
<< createFormat(QShaderFormat::OpenGLES, 2, 0)
|
||||
<< true;
|
||||
|
||||
QTest::newRow("ESVsNoProfile") << createFormat(QShaderFormat::OpenGLES, 2, 0)
|
||||
<< createFormat(QShaderFormat::OpenGLNoProfile, 2, 0)
|
||||
<< false;
|
||||
QTest::newRow("ESVsCoreProfile") << createFormat(QShaderFormat::OpenGLES, 2, 0)
|
||||
<< createFormat(QShaderFormat::OpenGLCoreProfile, 2, 0)
|
||||
<< false;
|
||||
QTest::newRow("ESVsCompatProfile") << createFormat(QShaderFormat::OpenGLES, 2, 0)
|
||||
<< createFormat(QShaderFormat::OpenGLCompatibilityProfile, 2, 0)
|
||||
<< false;
|
||||
|
||||
QTest::newRow("CoreVsNoProfile") << createFormat(QShaderFormat::OpenGLCoreProfile, 2, 0)
|
||||
<< createFormat(QShaderFormat::OpenGLNoProfile, 2, 0)
|
||||
<< false;
|
||||
QTest::newRow("CoreVsCompat") << createFormat(QShaderFormat::OpenGLCoreProfile, 2, 0)
|
||||
<< createFormat(QShaderFormat::OpenGLCompatibilityProfile, 2, 0)
|
||||
<< false;
|
||||
QTest::newRow("CoreVsCore") << createFormat(QShaderFormat::OpenGLCoreProfile, 2, 0)
|
||||
<< createFormat(QShaderFormat::OpenGLCoreProfile, 2, 0)
|
||||
<< true;
|
||||
|
||||
QTest::newRow("NoProfileVsCore") << createFormat(QShaderFormat::OpenGLNoProfile, 2, 0)
|
||||
<< createFormat(QShaderFormat::OpenGLCoreProfile, 2, 0)
|
||||
<< true;
|
||||
QTest::newRow("NoProvileVsCompat") << createFormat(QShaderFormat::OpenGLNoProfile, 2, 0)
|
||||
<< createFormat(QShaderFormat::OpenGLCompatibilityProfile, 2, 0)
|
||||
<< true;
|
||||
QTest::newRow("NoProfileVsNoProfile") << createFormat(QShaderFormat::OpenGLNoProfile, 2, 0)
|
||||
<< createFormat(QShaderFormat::OpenGLNoProfile, 2, 0)
|
||||
<< true;
|
||||
|
||||
QTest::newRow("CompatVsCore") << createFormat(QShaderFormat::OpenGLCompatibilityProfile, 2, 0)
|
||||
<< createFormat(QShaderFormat::OpenGLCoreProfile, 2, 0)
|
||||
<< true;
|
||||
QTest::newRow("CompatVsCompat") << createFormat(QShaderFormat::OpenGLCompatibilityProfile, 2, 0)
|
||||
<< createFormat(QShaderFormat::OpenGLCompatibilityProfile, 2, 0)
|
||||
<< true;
|
||||
QTest::newRow("CompatVsNoProfile") << createFormat(QShaderFormat::OpenGLCompatibilityProfile, 2, 0)
|
||||
<< createFormat(QShaderFormat::OpenGLNoProfile, 2, 0)
|
||||
<< true;
|
||||
|
||||
QTest::newRow("MajorForwardCompat_1") << createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0)
|
||||
<< createFormat(QShaderFormat::OpenGLCoreProfile, 2, 0)
|
||||
<< true;
|
||||
QTest::newRow("MajorForwardCompat_2") << createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0)
|
||||
<< createFormat(QShaderFormat::OpenGLCoreProfile, 2, 4)
|
||||
<< true;
|
||||
QTest::newRow("MajorForwardCompat_3") << createFormat(QShaderFormat::OpenGLCoreProfile, 2, 0)
|
||||
<< createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0)
|
||||
<< false;
|
||||
QTest::newRow("MajorForwardCompat_4") << createFormat(QShaderFormat::OpenGLCoreProfile, 2, 4)
|
||||
<< createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0)
|
||||
<< false;
|
||||
|
||||
QTest::newRow("MinorForwardCompat_1") << createFormat(QShaderFormat::OpenGLCoreProfile, 3, 1)
|
||||
<< createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0)
|
||||
<< true;
|
||||
QTest::newRow("MinorForwardCompat_2") << createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0)
|
||||
<< createFormat(QShaderFormat::OpenGLCoreProfile, 3, 1)
|
||||
<< false;
|
||||
|
||||
QTest::newRow("Extensions_1") << createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0, {"foo", "bar"})
|
||||
<< createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0, {"foo"})
|
||||
<< true;
|
||||
QTest::newRow("Extensions_2") << createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0, {"foo"})
|
||||
<< createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0, {"foo", "bar"})
|
||||
<< false;
|
||||
|
||||
QTest::newRow("Vendor_1") << createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0, {}, "KDAB")
|
||||
<< createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0, {})
|
||||
<< true;
|
||||
QTest::newRow("Vendor_2") << createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0, {})
|
||||
<< createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0, {}, "KDAB")
|
||||
<< false;
|
||||
QTest::newRow("Vendor_2") << createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0, {}, "KDAB")
|
||||
<< createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0, {}, "KDAB")
|
||||
<< true;
|
||||
}
|
||||
|
||||
void tst_QShaderNodes::shouldVerifyFormatsCompatibilities()
|
||||
{
|
||||
// GIVEN
|
||||
QFETCH(QShaderFormat, reference);
|
||||
QFETCH(QShaderFormat, tested);
|
||||
|
||||
// WHEN
|
||||
const auto supported = reference.supports(tested);
|
||||
|
||||
// THEN
|
||||
QFETCH(bool, expected);
|
||||
QCOMPARE(supported, expected);
|
||||
}
|
||||
|
||||
void tst_QShaderNodes::shouldHaveDefaultPortState()
|
||||
{
|
||||
// GIVEN
|
||||
auto port = QShaderNodePort();
|
||||
|
||||
// THEN
|
||||
QCOMPARE(port.direction, QShaderNodePort::Output);
|
||||
QVERIFY(port.name.isEmpty());
|
||||
}
|
||||
|
||||
void tst_QShaderNodes::shouldVerifyPortsEquality_data()
|
||||
{
|
||||
QTest::addColumn<QShaderNodePort>("left");
|
||||
QTest::addColumn<QShaderNodePort>("right");
|
||||
QTest::addColumn<bool>("expected");
|
||||
|
||||
QTest::newRow("Equals") << createPort(QShaderNodePort::Input, "foo")
|
||||
<< createPort(QShaderNodePort::Input, "foo")
|
||||
<< true;
|
||||
QTest::newRow("Direction") << createPort(QShaderNodePort::Input, "foo")
|
||||
<< createPort(QShaderNodePort::Output, "foo")
|
||||
<< false;
|
||||
QTest::newRow("Name") << createPort(QShaderNodePort::Input, "foo")
|
||||
<< createPort(QShaderNodePort::Input, "bar")
|
||||
<< false;
|
||||
}
|
||||
|
||||
void tst_QShaderNodes::shouldVerifyPortsEquality()
|
||||
{
|
||||
// GIVEN
|
||||
QFETCH(QShaderNodePort, left);
|
||||
QFETCH(QShaderNodePort, right);
|
||||
|
||||
// WHEN
|
||||
const auto equal = (left == right);
|
||||
const auto notEqual = (left != right);
|
||||
|
||||
// THEN
|
||||
QFETCH(bool, expected);
|
||||
QCOMPARE(equal, expected);
|
||||
QCOMPARE(notEqual, !expected);
|
||||
}
|
||||
|
||||
void tst_QShaderNodes::shouldManipulateNodeMembers()
|
||||
{
|
||||
// GIVEN
|
||||
const auto openGLES2 = createFormat(QShaderFormat::OpenGLES, 2, 0);
|
||||
const auto openGL3 = createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0);
|
||||
|
||||
const auto es2Rule = QShaderNode::Rule(QByteArrayLiteral("gles2"), {"#pragma include es2/foo.inc", "#pragma include es2/bar.inc"});
|
||||
const auto gl3Rule = QShaderNode::Rule(QByteArrayLiteral("gl3"), {"#pragma include gl3/foo.inc", "#pragma include gl3/bar.inc"});
|
||||
const auto gl3bisRule = QShaderNode::Rule(QByteArrayLiteral("gl3bis"), {"#pragma include gl3/foo.inc", "#pragma include gl3/bar.inc"});
|
||||
|
||||
auto node = QShaderNode();
|
||||
|
||||
// THEN (default state)
|
||||
QCOMPARE(node.type(), QShaderNode::Invalid);
|
||||
QVERIFY(node.uuid().isNull());
|
||||
QVERIFY(node.layers().isEmpty());
|
||||
QVERIFY(node.ports().isEmpty());
|
||||
QVERIFY(node.parameterNames().isEmpty());
|
||||
QVERIFY(node.availableFormats().isEmpty());
|
||||
|
||||
// WHEN
|
||||
const auto uuid = QUuid::createUuid();
|
||||
node.setUuid(uuid);
|
||||
|
||||
// THEN
|
||||
QCOMPARE(node.uuid(), uuid);
|
||||
|
||||
// WHEN
|
||||
node.setLayers({"foo", "bar"});
|
||||
|
||||
// THEN
|
||||
QCOMPARE(node.layers(), QStringList({"foo", "bar"}));
|
||||
|
||||
// WHEN
|
||||
auto firstPort = QShaderNodePort();
|
||||
firstPort.direction = QShaderNodePort::Input;
|
||||
firstPort.name = QStringLiteral("foo");
|
||||
node.addPort(firstPort);
|
||||
|
||||
// THEN
|
||||
QCOMPARE(node.type(), QShaderNode::Output);
|
||||
QCOMPARE(node.ports().size(), 1);
|
||||
QCOMPARE(node.ports().at(0), firstPort);
|
||||
QVERIFY(node.availableFormats().isEmpty());
|
||||
|
||||
// WHEN
|
||||
auto secondPort = QShaderNodePort();
|
||||
secondPort.direction = QShaderNodePort::Output;
|
||||
secondPort.name = QStringLiteral("bar");
|
||||
node.addPort(secondPort);
|
||||
|
||||
// THEN
|
||||
QCOMPARE(node.type(), QShaderNode::Function);
|
||||
QCOMPARE(node.ports().size(), 2);
|
||||
QCOMPARE(node.ports().at(0), firstPort);
|
||||
QCOMPARE(node.ports().at(1), secondPort);
|
||||
QVERIFY(node.availableFormats().isEmpty());
|
||||
|
||||
// WHEN
|
||||
node.removePort(firstPort);
|
||||
|
||||
// THEN
|
||||
QCOMPARE(node.type(), QShaderNode::Input);
|
||||
QCOMPARE(node.ports().size(), 1);
|
||||
QCOMPARE(node.ports().at(0), secondPort);
|
||||
QVERIFY(node.availableFormats().isEmpty());
|
||||
|
||||
// WHEN
|
||||
node.setParameter(QStringLiteral("baz"), 42);
|
||||
|
||||
// THEN
|
||||
QCOMPARE(node.type(), QShaderNode::Input);
|
||||
QCOMPARE(node.ports().size(), 1);
|
||||
QCOMPARE(node.ports().at(0), secondPort);
|
||||
auto parameterNames = node.parameterNames();
|
||||
parameterNames.sort();
|
||||
QCOMPARE(parameterNames.size(), 1);
|
||||
QCOMPARE(parameterNames.at(0), QStringLiteral("baz"));
|
||||
QCOMPARE(node.parameter(QStringLiteral("baz")), QVariant(42));
|
||||
QVERIFY(node.availableFormats().isEmpty());
|
||||
|
||||
// WHEN
|
||||
node.setParameter(QStringLiteral("bleh"), QStringLiteral("value"));
|
||||
|
||||
// THEN
|
||||
QCOMPARE(node.type(), QShaderNode::Input);
|
||||
QCOMPARE(node.ports().size(), 1);
|
||||
QCOMPARE(node.ports().at(0), secondPort);
|
||||
parameterNames = node.parameterNames();
|
||||
parameterNames.sort();
|
||||
QCOMPARE(parameterNames.size(), 2);
|
||||
QCOMPARE(parameterNames.at(0), QStringLiteral("baz"));
|
||||
QCOMPARE(parameterNames.at(1), QStringLiteral("bleh"));
|
||||
QCOMPARE(node.parameter(QStringLiteral("baz")), QVariant(42));
|
||||
QCOMPARE(node.parameter(QStringLiteral("bleh")), QVariant(QStringLiteral("value")));
|
||||
QVERIFY(node.availableFormats().isEmpty());
|
||||
|
||||
// WHEN
|
||||
node.clearParameter(QStringLiteral("baz"));
|
||||
|
||||
// THEN
|
||||
QCOMPARE(node.type(), QShaderNode::Input);
|
||||
QCOMPARE(node.ports().size(), 1);
|
||||
QCOMPARE(node.ports().at(0), secondPort);
|
||||
parameterNames = node.parameterNames();
|
||||
parameterNames.sort();
|
||||
QCOMPARE(parameterNames.size(), 1);
|
||||
QCOMPARE(parameterNames.at(0), QStringLiteral("bleh"));
|
||||
QCOMPARE(node.parameter(QStringLiteral("baz")), QVariant());
|
||||
QCOMPARE(node.parameter(QStringLiteral("bleh")), QVariant(QStringLiteral("value")));
|
||||
QVERIFY(node.availableFormats().isEmpty());
|
||||
|
||||
// WHEN
|
||||
node.addRule(openGLES2, es2Rule);
|
||||
node.addRule(openGL3, gl3Rule);
|
||||
|
||||
// THEN
|
||||
QCOMPARE(node.availableFormats().size(), 2);
|
||||
QCOMPARE(node.availableFormats().at(0), openGLES2);
|
||||
QCOMPARE(node.availableFormats().at(1), openGL3);
|
||||
QCOMPARE(node.rule(openGLES2), es2Rule);
|
||||
QCOMPARE(node.rule(openGL3), gl3Rule);
|
||||
|
||||
// WHEN
|
||||
node.removeRule(openGLES2);
|
||||
|
||||
// THEN
|
||||
QCOMPARE(node.availableFormats().size(), 1);
|
||||
QCOMPARE(node.availableFormats().at(0), openGL3);
|
||||
QCOMPARE(node.rule(openGL3), gl3Rule);
|
||||
|
||||
// WHEN
|
||||
node.addRule(openGLES2, es2Rule);
|
||||
|
||||
// THEN
|
||||
QCOMPARE(node.availableFormats().size(), 2);
|
||||
QCOMPARE(node.availableFormats().at(0), openGL3);
|
||||
QCOMPARE(node.availableFormats().at(1), openGLES2);
|
||||
QCOMPARE(node.rule(openGLES2), es2Rule);
|
||||
QCOMPARE(node.rule(openGL3), gl3Rule);
|
||||
|
||||
// WHEN
|
||||
node.addRule(openGL3, gl3bisRule);
|
||||
|
||||
// THEN
|
||||
QCOMPARE(node.availableFormats().size(), 2);
|
||||
QCOMPARE(node.availableFormats().at(0), openGLES2);
|
||||
QCOMPARE(node.availableFormats().at(1), openGL3);
|
||||
QCOMPARE(node.rule(openGLES2), es2Rule);
|
||||
QCOMPARE(node.rule(openGL3), gl3bisRule);
|
||||
}
|
||||
|
||||
void tst_QShaderNodes::shouldHandleNodeRulesSupportAndOrder()
|
||||
{
|
||||
// GIVEN
|
||||
const auto openGLES2 = createFormat(QShaderFormat::OpenGLES, 2, 0);
|
||||
const auto openGL3 = createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0);
|
||||
const auto openGL32 = createFormat(QShaderFormat::OpenGLCoreProfile, 3, 2);
|
||||
const auto openGL4 = createFormat(QShaderFormat::OpenGLCoreProfile, 4, 0);
|
||||
|
||||
const auto es2Rule = QShaderNode::Rule(QByteArrayLiteral("gles2"), {"#pragma include es2/foo.inc", "#pragma include es2/bar.inc"});
|
||||
const auto gl3Rule = QShaderNode::Rule(QByteArrayLiteral("gl3"), {"#pragma include gl3/foo.inc", "#pragma include gl3/bar.inc"});
|
||||
const auto gl32Rule = QShaderNode::Rule(QByteArrayLiteral("gl32"), {"#pragma include gl32/foo.inc", "#pragma include gl32/bar.inc"});
|
||||
const auto gl3bisRule = QShaderNode::Rule(QByteArrayLiteral("gl3bis"), {"#pragma include gl3/foo.inc", "#pragma include gl3/bar.inc"});
|
||||
|
||||
auto node = QShaderNode();
|
||||
|
||||
// WHEN
|
||||
node.addRule(openGLES2, es2Rule);
|
||||
node.addRule(openGL3, gl3Rule);
|
||||
|
||||
// THEN
|
||||
QCOMPARE(node.availableFormats().size(), 2);
|
||||
QCOMPARE(node.availableFormats().at(0), openGLES2);
|
||||
QCOMPARE(node.availableFormats().at(1), openGL3);
|
||||
QCOMPARE(node.rule(openGLES2), es2Rule);
|
||||
QCOMPARE(node.rule(openGL3), gl3Rule);
|
||||
QCOMPARE(node.rule(openGL32), gl3Rule);
|
||||
QCOMPARE(node.rule(openGL4), gl3Rule);
|
||||
|
||||
// WHEN
|
||||
node.addRule(openGL32, gl32Rule);
|
||||
|
||||
// THEN
|
||||
QCOMPARE(node.availableFormats().size(), 3);
|
||||
QCOMPARE(node.availableFormats().at(0), openGLES2);
|
||||
QCOMPARE(node.availableFormats().at(1), openGL3);
|
||||
QCOMPARE(node.availableFormats().at(2), openGL32);
|
||||
QCOMPARE(node.rule(openGLES2), es2Rule);
|
||||
QCOMPARE(node.rule(openGL3), gl3Rule);
|
||||
QCOMPARE(node.rule(openGL32), gl32Rule);
|
||||
QCOMPARE(node.rule(openGL4), gl32Rule);
|
||||
|
||||
// WHEN
|
||||
node.addRule(openGL3, gl3bisRule);
|
||||
|
||||
// THEN
|
||||
QCOMPARE(node.availableFormats().size(), 3);
|
||||
QCOMPARE(node.availableFormats().at(0), openGLES2);
|
||||
QCOMPARE(node.availableFormats().at(1), openGL32);
|
||||
QCOMPARE(node.availableFormats().at(2), openGL3);
|
||||
QCOMPARE(node.rule(openGLES2), es2Rule);
|
||||
QCOMPARE(node.rule(openGL3), gl3bisRule);
|
||||
QCOMPARE(node.rule(openGL32), gl3bisRule);
|
||||
QCOMPARE(node.rule(openGL4), gl3bisRule);
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QShaderNodes)
|
||||
|
||||
#include "tst_qshadernodes.moc"
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
# Generated from qshadernodesloader.pro.
|
||||
|
||||
#####################################################################
|
||||
## tst_qshadernodesloader Test:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_test(tst_qshadernodesloader
|
||||
SOURCES
|
||||
tst_qshadernodesloader.cpp
|
||||
PUBLIC_LIBRARIES
|
||||
Qt::Gui
|
||||
Qt::GuiPrivate
|
||||
)
|
||||
|
|
@ -1,327 +0,0 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the test suite of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
|
||||
** 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 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** 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$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
#include <QTest>
|
||||
|
||||
#include <QtCore/qbuffer.h>
|
||||
|
||||
#include <QtGui/private/qshadernodesloader_p.h>
|
||||
#include <QtGui/private/qshaderlanguage_p.h>
|
||||
|
||||
using QBufferPointer = QSharedPointer<QBuffer>;
|
||||
Q_DECLARE_METATYPE(QBufferPointer);
|
||||
|
||||
using NodeHash = QHash<QString, QShaderNode>;
|
||||
Q_DECLARE_METATYPE(NodeHash);
|
||||
|
||||
namespace
|
||||
{
|
||||
QBufferPointer createBuffer(const QByteArray &data, QIODevice::OpenMode openMode = QIODevice::ReadOnly)
|
||||
{
|
||||
auto buffer = QBufferPointer::create();
|
||||
buffer->setData(data);
|
||||
if (openMode != QIODevice::NotOpen)
|
||||
buffer->open(openMode);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
QShaderFormat createFormat(QShaderFormat::Api api, int majorVersion, int minorVersion,
|
||||
const QStringList &extensions = QStringList(),
|
||||
const QString &vendor = QString())
|
||||
{
|
||||
auto format = QShaderFormat();
|
||||
format.setApi(api);
|
||||
format.setVersion(QVersionNumber(majorVersion, minorVersion));
|
||||
format.setExtensions(extensions);
|
||||
format.setVendor(vendor);
|
||||
return format;
|
||||
}
|
||||
|
||||
QShaderNodePort createPort(QShaderNodePort::Direction portDirection, const QString &portName)
|
||||
{
|
||||
auto port = QShaderNodePort();
|
||||
port.direction = portDirection;
|
||||
port.name = portName;
|
||||
return port;
|
||||
}
|
||||
|
||||
QShaderNode createNode(const QList<QShaderNodePort> &ports)
|
||||
{
|
||||
auto node = QShaderNode();
|
||||
for (const auto &port : ports)
|
||||
node.addPort(port);
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
class tst_QShaderNodesLoader : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
private slots:
|
||||
void shouldManipulateLoaderMembers();
|
||||
void shouldLoadFromJsonStream_data();
|
||||
void shouldLoadFromJsonStream();
|
||||
};
|
||||
|
||||
void tst_QShaderNodesLoader::shouldManipulateLoaderMembers()
|
||||
{
|
||||
// GIVEN
|
||||
auto loader = QShaderNodesLoader();
|
||||
|
||||
// THEN (default state)
|
||||
QCOMPARE(loader.status(), QShaderNodesLoader::Null);
|
||||
QVERIFY(!loader.device());
|
||||
QVERIFY(loader.nodes().isEmpty());
|
||||
|
||||
// WHEN
|
||||
auto device1 = createBuffer(QByteArray("..........."), QIODevice::NotOpen);
|
||||
loader.setDevice(device1.data());
|
||||
|
||||
// THEN
|
||||
QCOMPARE(loader.status(), QShaderNodesLoader::Error);
|
||||
QCOMPARE(loader.device(), device1.data());
|
||||
QVERIFY(loader.nodes().isEmpty());
|
||||
|
||||
// WHEN
|
||||
auto device2 = createBuffer(QByteArray("..........."), QIODevice::ReadOnly);
|
||||
loader.setDevice(device2.data());
|
||||
|
||||
// THEN
|
||||
QCOMPARE(loader.status(), QShaderNodesLoader::Waiting);
|
||||
QCOMPARE(loader.device(), device2.data());
|
||||
QVERIFY(loader.nodes().isEmpty());
|
||||
}
|
||||
|
||||
void tst_QShaderNodesLoader::shouldLoadFromJsonStream_data()
|
||||
{
|
||||
QTest::addColumn<QBufferPointer>("device");
|
||||
QTest::addColumn<NodeHash>("nodes");
|
||||
QTest::addColumn<QShaderNodesLoader::Status>("status");
|
||||
|
||||
QTest::newRow("empty") << createBuffer("", QIODevice::ReadOnly) << NodeHash() << QShaderNodesLoader::Error;
|
||||
|
||||
const auto smallJson = "{"
|
||||
" \"inputValue\": {"
|
||||
" \"outputs\": ["
|
||||
" \"value\""
|
||||
" ],"
|
||||
" \"parameters\": {"
|
||||
" \"name\": \"defaultName\","
|
||||
" \"qualifier\": {"
|
||||
" \"type\": \"QShaderLanguage::StorageQualifier\","
|
||||
" \"value\": \"QShaderLanguage::Uniform\""
|
||||
" },"
|
||||
" \"type\": {"
|
||||
" \"type\": \"QShaderLanguage::VariableType\","
|
||||
" \"value\": \"QShaderLanguage::Vec3\""
|
||||
" },"
|
||||
" \"defaultValue\": {"
|
||||
" \"type\": \"float\","
|
||||
" \"value\": \"1.25\""
|
||||
" }"
|
||||
" },"
|
||||
" \"rules\": ["
|
||||
" {"
|
||||
" \"format\": {"
|
||||
" \"api\": \"OpenGLES\","
|
||||
" \"major\": 2,"
|
||||
" \"minor\": 0"
|
||||
" },"
|
||||
" \"substitution\": \"highp vec3 $value = $name;\","
|
||||
" \"headerSnippets\": [ \"varying highp vec3 $name;\" ]"
|
||||
" },"
|
||||
" {"
|
||||
" \"format\": {"
|
||||
" \"api\": \"OpenGLCompatibilityProfile\","
|
||||
" \"major\": 2,"
|
||||
" \"minor\": 1"
|
||||
" },"
|
||||
" \"substitution\": \"vec3 $value = $name;\","
|
||||
" \"headerSnippets\": [ \"in vec3 $name;\" ]"
|
||||
" }"
|
||||
" ]"
|
||||
" },"
|
||||
" \"fragColor\": {"
|
||||
" \"inputs\": ["
|
||||
" \"fragColor\""
|
||||
" ],"
|
||||
" \"rules\": ["
|
||||
" {"
|
||||
" \"format\": {"
|
||||
" \"api\": \"OpenGLES\","
|
||||
" \"major\": 2,"
|
||||
" \"minor\": 0"
|
||||
" },"
|
||||
" \"substitution\": \"gl_fragColor = $fragColor;\""
|
||||
" },"
|
||||
" {"
|
||||
" \"format\": {"
|
||||
" \"api\": \"OpenGLNoProfile\","
|
||||
" \"major\": 4,"
|
||||
" \"minor\": 0"
|
||||
" },"
|
||||
" \"substitution\": \"fragColor = $fragColor;\","
|
||||
" \"headerSnippets\": [ \"out vec4 fragColor;\" ]"
|
||||
" }"
|
||||
" ]"
|
||||
" },"
|
||||
" \"lightModel\": {"
|
||||
" \"inputs\": ["
|
||||
" \"baseColor\","
|
||||
" \"position\","
|
||||
" \"lightIntensity\""
|
||||
" ],"
|
||||
" \"outputs\": ["
|
||||
" \"outputColor\""
|
||||
" ],"
|
||||
" \"rules\": ["
|
||||
" {"
|
||||
" \"format\": {"
|
||||
" \"api\": \"OpenGLES\","
|
||||
" \"major\": 2,"
|
||||
" \"minor\": 0,"
|
||||
" \"extensions\": [ \"ext1\", \"ext2\" ],"
|
||||
" \"vendor\": \"kdab\""
|
||||
" },"
|
||||
" \"substitution\": \"highp vec4 $outputColor = lightModel($baseColor, $position, $lightIntensity);\","
|
||||
" \"headerSnippets\": [ \"#pragma include es2/lightmodel.frag.inc\" ]"
|
||||
" },"
|
||||
" {"
|
||||
" \"format\": {"
|
||||
" \"api\": \"OpenGLCoreProfile\","
|
||||
" \"major\": 3,"
|
||||
" \"minor\": 3"
|
||||
" },"
|
||||
" \"substitution\": \"vec4 $outputColor = lightModel($baseColor, $position, $lightIntensity);\","
|
||||
" \"headerSnippets\": [ \"#pragma include gl3/lightmodel.frag.inc\" ]"
|
||||
" }"
|
||||
" ]"
|
||||
" }"
|
||||
"}";
|
||||
|
||||
const auto smallProtos = [&]{
|
||||
const auto openGLES2 = createFormat(QShaderFormat::OpenGLES, 2, 0);
|
||||
const auto openGLES2Extended = createFormat(QShaderFormat::OpenGLES, 2, 0, {"ext1", "ext2"}, "kdab");
|
||||
const auto openGL2 = createFormat(QShaderFormat::OpenGLCompatibilityProfile, 2, 1);
|
||||
const auto openGL3 = createFormat(QShaderFormat::OpenGLCoreProfile, 3, 3);
|
||||
const auto openGL4 = createFormat(QShaderFormat::OpenGLNoProfile, 4, 0);
|
||||
|
||||
auto protos = NodeHash();
|
||||
|
||||
auto inputValue = createNode({
|
||||
createPort(QShaderNodePort::Output, "value")
|
||||
});
|
||||
inputValue.setParameter("name", "defaultName");
|
||||
inputValue.setParameter("qualifier", QVariant::fromValue<QShaderLanguage::StorageQualifier>(QShaderLanguage::Uniform));
|
||||
inputValue.setParameter("type", QVariant::fromValue<QShaderLanguage::VariableType>(QShaderLanguage::Vec3));
|
||||
inputValue.setParameter("defaultValue", QVariant(1.25f));
|
||||
inputValue.addRule(openGLES2, QShaderNode::Rule("highp vec3 $value = $name;",
|
||||
QByteArrayList() << "varying highp vec3 $name;"));
|
||||
inputValue.addRule(openGL2, QShaderNode::Rule("vec3 $value = $name;",
|
||||
QByteArrayList() << "in vec3 $name;"));
|
||||
protos.insert("inputValue", inputValue);
|
||||
|
||||
auto fragColor = createNode({
|
||||
createPort(QShaderNodePort::Input, "fragColor")
|
||||
});
|
||||
fragColor.addRule(openGLES2, QShaderNode::Rule("gl_fragColor = $fragColor;"));
|
||||
fragColor.addRule(openGL4, QShaderNode::Rule("fragColor = $fragColor;",
|
||||
QByteArrayList() << "out vec4 fragColor;"));
|
||||
protos.insert(QStringLiteral("fragColor"), fragColor);
|
||||
|
||||
auto lightModel = createNode({
|
||||
createPort(QShaderNodePort::Input, "baseColor"),
|
||||
createPort(QShaderNodePort::Input, "position"),
|
||||
createPort(QShaderNodePort::Input, "lightIntensity"),
|
||||
createPort(QShaderNodePort::Output, "outputColor")
|
||||
});
|
||||
lightModel.addRule(openGLES2Extended, QShaderNode::Rule("highp vec4 $outputColor = lightModel($baseColor, $position, $lightIntensity);",
|
||||
QByteArrayList() << "#pragma include es2/lightmodel.frag.inc"));
|
||||
lightModel.addRule(openGL3, QShaderNode::Rule("vec4 $outputColor = lightModel($baseColor, $position, $lightIntensity);",
|
||||
QByteArrayList() << "#pragma include gl3/lightmodel.frag.inc"));
|
||||
protos.insert("lightModel", lightModel);
|
||||
|
||||
return protos;
|
||||
}();
|
||||
|
||||
QTest::newRow("NotOpen") << createBuffer(smallJson, QIODevice::NotOpen) << NodeHash() << QShaderNodesLoader::Error;
|
||||
QTest::newRow("CorrectJSON") << createBuffer(smallJson) << smallProtos << QShaderNodesLoader::Ready;
|
||||
|
||||
// These types are normaly registered by QShaderGraphLoader
|
||||
qRegisterMetaType<QShaderLanguage::StorageQualifier>();
|
||||
qRegisterMetaType<QShaderLanguage::VariableType>();
|
||||
}
|
||||
|
||||
void tst_QShaderNodesLoader::shouldLoadFromJsonStream()
|
||||
{
|
||||
// GIVEN
|
||||
QFETCH(QBufferPointer, device);
|
||||
|
||||
auto loader = QShaderNodesLoader();
|
||||
|
||||
// WHEN
|
||||
loader.setDevice(device.data());
|
||||
loader.load();
|
||||
|
||||
// THEN
|
||||
QFETCH(QShaderNodesLoader::Status, status);
|
||||
QCOMPARE(loader.status(), status);
|
||||
|
||||
QFETCH(NodeHash, nodes);
|
||||
const auto sortedKeys = [](const NodeHash &nodes) {
|
||||
auto res = nodes.keys();
|
||||
res.sort();
|
||||
return res;
|
||||
};
|
||||
const auto sortedParameters = [](const QShaderNode &node) {
|
||||
auto res = node.parameterNames();
|
||||
res.sort();
|
||||
return res;
|
||||
};
|
||||
QCOMPARE(sortedKeys(loader.nodes()), sortedKeys(nodes));
|
||||
for (const auto &key : nodes.keys()) {
|
||||
const auto actual = loader.nodes().value(key);
|
||||
const auto expected = nodes.value(key);
|
||||
|
||||
QVERIFY(actual.uuid().isNull());
|
||||
QCOMPARE(actual.ports(), expected.ports());
|
||||
QCOMPARE(sortedParameters(actual), sortedParameters(expected));
|
||||
for (const auto &name : expected.parameterNames()) {
|
||||
QCOMPARE(actual.parameter(name), expected.parameter(name));
|
||||
}
|
||||
QCOMPARE(actual.availableFormats(), expected.availableFormats());
|
||||
for (const auto &format : expected.availableFormats()) {
|
||||
QCOMPARE(actual.rule(format), expected.rule(format));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QShaderNodesLoader)
|
||||
|
||||
#include "tst_qshadernodesloader.moc"
|
||||
Loading…
Reference in New Issue