[Shader Graph Gen.] Introduce QShaderNodesLoader
This class allows to node definitions from a JSON representation. This will come in handy to ship preset prototypes for use with QShaderGraphLoader. Change-Id: I3f3b5d7852e17d484069b4814ee6e5910997c613 Reviewed-by: Sean Harmer <sean.harmer@kdab.com>bb10
parent
093752faf3
commit
4d70e03002
|
|
@ -0,0 +1,242 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** 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>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
QShaderNodesLoader::QShaderNodesLoader() Q_DECL_NOTHROW
|
||||
: m_status(Null),
|
||||
m_device(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
QShaderNodesLoader::Status QShaderNodesLoader::status() const Q_DECL_NOTHROW
|
||||
{
|
||||
return m_status;
|
||||
}
|
||||
|
||||
QHash<QString, QShaderNode> QShaderNodesLoader::nodes() const Q_DECL_NOTHROW
|
||||
{
|
||||
return m_nodes;
|
||||
}
|
||||
|
||||
QIODevice *QShaderNodesLoader::device() const Q_DECL_NOTHROW
|
||||
{
|
||||
return m_device;
|
||||
}
|
||||
|
||||
void QShaderNodesLoader::setDevice(QIODevice *device) Q_DECL_NOTHROW
|
||||
{
|
||||
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 auto 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 auto root = document.object();
|
||||
|
||||
bool hasError = false;
|
||||
|
||||
for (const auto &property : root.keys()) {
|
||||
const auto nodeValue = root.value(property);
|
||||
if (!nodeValue.isObject()) {
|
||||
qWarning() << "Invalid node found";
|
||||
hasError = true;
|
||||
break;
|
||||
}
|
||||
|
||||
const auto nodeObject = nodeValue.toObject();
|
||||
|
||||
auto node = QShaderNode();
|
||||
|
||||
const auto inputsValue = nodeObject.value(QStringLiteral("inputs"));
|
||||
if (inputsValue.isArray()) {
|
||||
const auto inputsArray = inputsValue.toArray();
|
||||
for (const auto &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 auto outputsValue = nodeObject.value(QStringLiteral("outputs"));
|
||||
if (outputsValue.isArray()) {
|
||||
const auto outputsArray = outputsValue.toArray();
|
||||
for (const auto &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 auto rulesValue = nodeObject.value(QStringLiteral("rules"));
|
||||
if (rulesValue.isArray()) {
|
||||
const auto rulesArray = rulesValue.toArray();
|
||||
for (const auto &ruleValue : rulesArray) {
|
||||
if (!ruleValue.isObject()) {
|
||||
qWarning() << "Rules should be objects";
|
||||
hasError = true;
|
||||
break;
|
||||
}
|
||||
|
||||
const auto ruleObject = ruleValue.toObject();
|
||||
|
||||
const auto formatValue = ruleObject.value(QStringLiteral("format"));
|
||||
if (!formatValue.isObject()) {
|
||||
qWarning() << "Format is mandatory in rules and should be an object";
|
||||
hasError = true;
|
||||
break;
|
||||
}
|
||||
|
||||
const auto formatObject = formatValue.toObject();
|
||||
auto format = QShaderFormat();
|
||||
|
||||
const auto apiValue = formatObject.value(QStringLiteral("api"));
|
||||
if (!apiValue.isString()) {
|
||||
qWarning() << "Format API must be a string";
|
||||
hasError = true;
|
||||
break;
|
||||
}
|
||||
|
||||
const auto 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
|
||||
: QShaderFormat::NoApi);
|
||||
if (format.api() == QShaderFormat::NoApi) {
|
||||
qWarning() << "Format API must be one of: OpenGLES, OpenGLNoProfile, OpenGLCoreProfile or OpenGLCompatibilityProfile";
|
||||
hasError = true;
|
||||
break;
|
||||
}
|
||||
|
||||
const auto majorValue = formatObject.value(QStringLiteral("major"));
|
||||
const auto 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 auto extensionsValue = formatObject.value(QStringLiteral("extensions"));
|
||||
const auto 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 auto vendor = formatObject.value(QStringLiteral("vendor")).toString();
|
||||
format.setVendor(vendor);
|
||||
|
||||
const auto substitutionValue = ruleObject.value(QStringLiteral("substitution"));
|
||||
if (!substitutionValue.isString()) {
|
||||
qWarning() << "Substitution needs to be a string";
|
||||
hasError = true;
|
||||
break;
|
||||
}
|
||||
|
||||
const auto substitution = substitutionValue.toString().toUtf8();
|
||||
|
||||
const auto snippetsValue = ruleObject.value(QStringLiteral("headerSnippets"));
|
||||
const auto 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
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** 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() Q_DECL_NOTHROW;
|
||||
|
||||
Q_GUI_EXPORT Status status() const Q_DECL_NOTHROW;
|
||||
Q_GUI_EXPORT QHash<QString, QShaderNode> nodes() const Q_DECL_NOTHROW;
|
||||
|
||||
Q_GUI_EXPORT QIODevice *device() const Q_DECL_NOTHROW;
|
||||
Q_GUI_EXPORT void setDevice(QIODevice *device) Q_DECL_NOTHROW;
|
||||
|
||||
Q_GUI_EXPORT void load();
|
||||
|
||||
private:
|
||||
Status m_status;
|
||||
QIODevice *m_device;
|
||||
QHash<QString, QShaderNode> m_nodes;
|
||||
};
|
||||
|
||||
Q_DECLARE_TYPEINFO(QShaderNodesLoader, Q_MOVABLE_TYPE);
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
Q_DECLARE_METATYPE(QShaderNodesLoader)
|
||||
Q_DECLARE_METATYPE(QShaderNodesLoader::Status)
|
||||
|
||||
#endif // QSHADERNODESLOADER_P_H
|
||||
|
|
@ -12,7 +12,8 @@ HEADERS += \
|
|||
util/qshadergraph_p.h \
|
||||
util/qshadergraphloader_p.h \
|
||||
util/qshadernode_p.h \
|
||||
util/qshadernodeport_p.h
|
||||
util/qshadernodeport_p.h \
|
||||
util/qshadernodesloader_p.h
|
||||
|
||||
SOURCES += \
|
||||
util/qdesktopservices.cpp \
|
||||
|
|
@ -25,4 +26,5 @@ SOURCES += \
|
|||
util/qshadergraph.cpp \
|
||||
util/qshadergraphloader.cpp \
|
||||
util/qshadernode.cpp \
|
||||
util/qshadernodeport.cpp
|
||||
util/qshadernodeport.cpp \
|
||||
util/qshadernodesloader.cpp
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
CONFIG += testcase
|
||||
QT += testlib gui-private
|
||||
|
||||
SOURCES += tst_qshadernodesloader.cpp
|
||||
TARGET = tst_qshadernodesloader
|
||||
|
|
@ -0,0 +1,289 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** 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 <QtTest/QtTest>
|
||||
|
||||
#include <QtCore/qbuffer.h>
|
||||
|
||||
#include <QtGui/private/qshadernodesloader_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 QVector<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 = "{"
|
||||
" \"worldPosition\": {"
|
||||
" \"outputs\": ["
|
||||
" \"worldPosition\""
|
||||
" ],"
|
||||
" \"rules\": ["
|
||||
" {"
|
||||
" \"format\": {"
|
||||
" \"api\": \"OpenGLES\","
|
||||
" \"major\": 2,"
|
||||
" \"minor\": 0"
|
||||
" },"
|
||||
" \"substitution\": \"highp vec3 $worldPosition = worldPosition;\","
|
||||
" \"headerSnippets\": [ \"varying highp vec3 worldPosition;\" ]"
|
||||
" },"
|
||||
" {"
|
||||
" \"format\": {"
|
||||
" \"api\": \"OpenGLCompatibilityProfile\","
|
||||
" \"major\": 2,"
|
||||
" \"minor\": 1"
|
||||
" },"
|
||||
" \"substitution\": \"vec3 $worldPosition = worldPosition;\","
|
||||
" \"headerSnippets\": [ \"in vec3 worldPosition;\" ]"
|
||||
" }"
|
||||
" ]"
|
||||
" },"
|
||||
" \"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 = [this]{
|
||||
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 worldPosition = createNode({
|
||||
createPort(QShaderNodePort::Output, "worldPosition")
|
||||
});
|
||||
worldPosition.addRule(openGLES2, QShaderNode::Rule("highp vec3 $worldPosition = worldPosition;",
|
||||
QByteArrayList() << "varying highp vec3 worldPosition;"));
|
||||
worldPosition.addRule(openGL2, QShaderNode::Rule("vec3 $worldPosition = worldPosition;",
|
||||
QByteArrayList() << "in vec3 worldPosition;"));
|
||||
protos.insert("worldPosition", worldPosition);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
QCOMPARE(loader.nodes().keys(), nodes.keys());
|
||||
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(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"
|
||||
|
|
@ -9,4 +9,5 @@ SUBDIRS= \
|
|||
qshadergraph \
|
||||
qshadergraphloader \
|
||||
qshadernodes \
|
||||
qshadernodesloader \
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue