diff options
162 files changed, 20107 insertions, 2 deletions
diff --git a/src/core/abstractaspect.cpp b/src/core/abstractaspect.cpp new file mode 100644 index 000000000..3096aa58f --- /dev/null +++ b/src/core/abstractaspect.cpp @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "abstractaspect.h" + +namespace Qt3D { + +AbstractAspect::AbstractAspect(AspectType aspectType, QObject *parent) + : QObject(parent) + , m_aspectType(aspectType) +{ +} + +void AbstractAspect::registerAspect(Node *rootObject) +{ + if (rootObject == m_root) + return; + + m_root = rootObject; + registerAspectHelper(rootObject); +} + +void AbstractAspect::unregisterAspect(Node *rootObject) +{ + unregisterAspectHelper(rootObject); + m_root = rootObject; +} + +void AbstractAspect::initialize(QAspectManager *aspectManager) +{ + m_aspectManager = aspectManager; + initializeHelper(aspectManager); +} + +void AbstractAspect::cleanup() +{ + cleanupHelper(); +} + +void AbstractAspect::setWindow(QWindow *win) +{ + Q_UNUSED(win); +} + +} // of namespace Qt3D + diff --git a/src/core/abstractaspect.h b/src/core/abstractaspect.h new file mode 100644 index 000000000..7dd555b32 --- /dev/null +++ b/src/core/abstractaspect.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ABSTRACTASPECT_H +#define ABSTRACTASPECT_H + +#include <QObject> +#include "qt3dcore_global.h" + +#include "qjobproviderinterface.h" + +#include <QSharedPointer> + +// forward decls +class QWindow; + +namespace Qt3D { + +class QAspectManager; +class Node; + +class QT3DCORESHARED_EXPORT AbstractAspect : public QObject, public QJobProviderInterface +{ + Q_OBJECT + +public: + enum AspectType { + AspectRenderer, + AspectAnimation, + AspectCollision, + AspectPhysics, + AspectPhysicsAndCollision, + AspectAI, + AspectAudio, + AspectOther + }; + + explicit AbstractAspect(AspectType aspectType, QObject *parent = 0); + + AspectType aspectType() const { return m_aspectType; } + QAspectManager *aspectManager() const { return m_aspectManager; } + + void registerAspect(Node *rootObject); + void unregisterAspect(Node *rootObject); + + void initialize(QAspectManager *aspectManager); + void cleanup(); + + virtual void setWindow(QWindow* win); + +protected: + virtual void registerAspectHelper(Node *rootObject) = 0; + virtual void unregisterAspectHelper(Node *rootObject) = 0; + + virtual void initializeHelper(QAspectManager *aspectManager) = 0; + virtual void cleanupHelper() = 0; + +private: + QAspectManager *m_aspectManager; + Node *m_root; + AspectType m_aspectType; +}; + +} + +#endif // ABSTRACTASPECT_H diff --git a/src/core/abstracttransform.cpp b/src/core/abstracttransform.cpp new file mode 100644 index 000000000..a7a892259 --- /dev/null +++ b/src/core/abstracttransform.cpp @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "abstracttransform.h" + +namespace Qt3D { + +AbstractTransform::AbstractTransform(Node *parent) + : Node(parent) +{ +} + +AbstractTransform::~AbstractTransform() +{ +} + +} // of namespace Qt3D diff --git a/src/core/abstracttransform.h b/src/core/abstracttransform.h new file mode 100644 index 000000000..1715bd70c --- /dev/null +++ b/src/core/abstracttransform.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3D_ABSTRACT_TRANSFORM_H +#define QT3D_ABSTRACT_TRANSFORM_H + +#include <node.h> +#include "qt3dcore_global.h" + +#include <QMatrix4x4> + +namespace Qt3D { + +class AbstractTransform : public Node +{ + Q_OBJECT +public: + explicit AbstractTransform(Node *parent = 0); + virtual ~AbstractTransform(); + + virtual QMatrix4x4 matrix() const = 0; +}; + +} // of namespace Qt3D + +#endif // of QT3D_ABSTRACT_TRANSFORM_H diff --git a/src/core/axisalignedboundingbox.cpp b/src/core/axisalignedboundingbox.cpp new file mode 100644 index 000000000..8ee394127 --- /dev/null +++ b/src/core/axisalignedboundingbox.cpp @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "axisalignedboundingbox.h" + +#include <QDebug> +#include <QMatrix4x4> + +namespace Qt3D { + +void AxisAlignedBoundingBox::update(const QVector<QVector3D> &points) +{ + QVector3D minPoint, maxPoint; + for (int i = 0; i < points.size(); ++i) + { + const QVector3D &point = points.at(i); + if (point.x() > maxPoint.x()) + maxPoint.setX(point.x()); + if (point.y() > maxPoint.y()) + maxPoint.setY(point.y()); + if (point.z() > maxPoint.z()) + maxPoint.setZ(point.z()); + if (point.x() < minPoint.x()) + minPoint.setX(point.x()); + if (point.y() < minPoint.y()) + minPoint.setY(point.y()); + if (point.z() < minPoint.z()) + minPoint.setZ(point.z()); + } + + m_center = 0.5 * (minPoint + maxPoint); + m_radii = 0.5 * (maxPoint - minPoint); +#if 0 + qDebug() << "AABB:"; + qDebug() << " min =" << minPoint; + qDebug() << " max =" << maxPoint; + qDebug() << " center =" << m_center; + qDebug() << " radii =" << m_radii; +#endif +} + +QDebug operator<<(QDebug dbg, const AxisAlignedBoundingBox &c) +{ + dbg.nospace() << "AABB ( min:" << c.minPoint() << ", max:" << c.maxPoint() << ")"; + return dbg.space(); +} + +} diff --git a/src/core/axisalignedboundingbox.h b/src/core/axisalignedboundingbox.h new file mode 100644 index 000000000..e16dda1a8 --- /dev/null +++ b/src/core/axisalignedboundingbox.h @@ -0,0 +1,157 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef AXIS_ALIGNED_BOUNDING_BOX +#define AXIS_ALIGNED_BOUNDING_BOX + +#include "qt3dcore_global.h" + +#include <QMatrix4x4> +#include <QVector> +#include <QVector3D> + +// forward decls +class QDebug; + +namespace Qt3D { + +class AxisAlignedBoundingBox +{ +public: + inline AxisAlignedBoundingBox() + : m_center(), + m_radii() + {} + + inline explicit AxisAlignedBoundingBox(const QVector<QVector3D> &points) + : m_center(), + m_radii() + { + update(points); + } + + void clear() + { + m_center = QVector3D(); + m_radii = QVector3D(); + } + + void update(const QVector<QVector3D> &points); + + inline QVector3D center() const { return m_center; } + inline QVector3D radii() const { return m_radii; } + + inline QVector3D minPoint() const { return m_center - m_radii; } + inline QVector3D maxPoint() const { return m_center + m_radii; } + + inline float xExtent() const { return 2.0f * m_radii.x(); } + inline float yExtent() const { return 2.0f * m_radii.y(); } + inline float zExtent() const { return 2.0f * m_radii.z(); } + + inline float maxExtent() const { return qMax( xExtent(), qMax( yExtent(), zExtent() ) ); } + inline float minExtent() const { return qMin( xExtent(), qMin( yExtent(), zExtent() ) ); } + + inline bool contains( const QVector3D& pt ) const + { + QVector3D minP(minPoint()), maxP(maxPoint()); + if ((pt.x() < minP.x()) || (pt.x() > maxP.x()) || + (pt.y() < minP.y()) || (pt.y() > maxP.y()) || + (pt.z() < minP.z()) || (pt.z() > maxP.z()) ) + { + return false; + } + return true; + } + + inline void expandToContain(const QVector3D &pt) + { + QVector<QVector3D> pts = QVector<QVector3D>() << pt; + update(pts); + } + + inline void expandToContain(const AxisAlignedBoundingBox &other) + { + QVector<QVector3D> pts = QVector<QVector3D>() << other.minPoint() << other.maxPoint(); + update(pts); + } + + inline AxisAlignedBoundingBox transformBy(const QMatrix4x4 &mat) const + { + AxisAlignedBoundingBox r; + r.m_center = mat.map(m_center); + r.m_radii = mat.map(m_radii); + return r; + } + + inline AxisAlignedBoundingBox &transform(const QMatrix4x4 &mat) + { + m_center = mat.map(m_center); + m_radii = mat.map(m_radii); + return *this; + } + +private: + QVector3D m_center; + QVector3D m_radii; + + friend bool intersects(const AxisAlignedBoundingBox &a, + const AxisAlignedBoundingBox &b); +}; + +QDebug operator<<(QDebug dbg, const AxisAlignedBoundingBox &c); + +inline bool intersects(const AxisAlignedBoundingBox &a, + const AxisAlignedBoundingBox &b) +{ + // Test y axis last as this is often the least discriminatory in OpenGL applications + // where worlds tend to be mostly in the xz-plane + if (qAbs(a.m_center[0] - b.m_center[0]) > a.m_radii[0] + b.m_radii[0]) + return false; + if (qAbs(a.m_center[2] - b.m_center[2]) > a.m_radii[2] + b.m_radii[2]) + return false; + if (qAbs(a.m_center[1] - b.m_center[1]) > a.m_radii[1] + b.m_radii[1]) + return false; + return true; +} + +} + +#endif // AXIS_ALIGNED_BOUNDING_BOX diff --git a/src/core/bounds.cpp b/src/core/bounds.cpp new file mode 100644 index 000000000..89db913ae --- /dev/null +++ b/src/core/bounds.cpp @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "bounds.h" + +namespace Qt3D { + +Bounds::Bounds(QObject *parent) : + QObject(parent) +{ +} + +AxisAlignedBoundingBox Bounds::box() const +{ + return m_box; +} + +void Bounds::setBox( const AxisAlignedBoundingBox& aabb ) +{ + m_box = aabb; +} + +} diff --git a/src/core/bounds.h b/src/core/bounds.h new file mode 100644 index 000000000..cf59d7776 --- /dev/null +++ b/src/core/bounds.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef BOUNDS_H +#define BOUNDS_H + +#include <QObject> +#include "qt3dcore_global.h" + +#include "axisalignedboundingbox.h" + +namespace Qt3D { + +class Bounds : public QObject +{ + Q_OBJECT +public: + explicit Bounds(QObject *parent = 0); + + AxisAlignedBoundingBox box() const; + void setBox( const AxisAlignedBoundingBox& aabb ); + +private: + AxisAlignedBoundingBox m_box; +}; + +} + +#endif // BOUNDS_H diff --git a/src/core/cameracontroller.cpp b/src/core/cameracontroller.cpp new file mode 100644 index 000000000..10d1aa386 --- /dev/null +++ b/src/core/cameracontroller.cpp @@ -0,0 +1,292 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "cameracontroller.h" + +#include <QMouseEvent> +#include <QKeyEvent> + +#include "camera.h" +#include "entity.h" +#include "matrixtransform.h" + +namespace Qt3D +{ + +CameraController::CameraController() : + m_camera( 0 ), + m_vx( 0.0f ), + m_vy( 0.0f ), + m_vz( 0.0f ), + m_viewCenterFixed( false ), + m_panAngle( 0.0f ), + m_tiltAngle( 0.0f ), + m_leftButtonPressed( false ), + m_orbitMode( false ), + m_linearSpeed( 40.0f ), + m_time( 0.0f ), + m_orbitRate( -1.0f ), + m_lookRate( 0.1f ), + m_translateFast( false ), + m_multisampleEnabled( true ) +{ +} + +void CameraController::setCamera( Camera* cam ) +{ + m_camera = cam; + m_camera->setPerspectiveProjection( 25.0, 1.0, 0.1, 1000 ); + + Entity* cameraEntity = cam->parentNode()->asEntity(); + Q_ASSERT(cameraEntity); + m_cameraEntity = cameraEntity; +} + +void CameraController::setLinearSpeed( float speed ) +{ + if ( qFuzzyCompare( m_linearSpeed, speed ) ) + return; + m_linearSpeed = speed; + emit linearSpeedChanged(); +} + +float CameraController::linearSpeed() const +{ + return m_linearSpeed; +} + +float CameraController::orbitRate() const +{ + return m_orbitRate; +} + +void CameraController::setOrbitRate( float rate ) +{ + if ( qFuzzyCompare( m_orbitRate, rate ) ) + return; + m_orbitRate = rate; + emit orbitRateChanged(); +} + +float CameraController::lookRate() const +{ + return m_lookRate; +} + +void CameraController::setLookRate( float rate ) +{ + if ( qFuzzyCompare( m_lookRate, rate ) ) + return; + m_lookRate = rate; + emit lookRateChanged(); +} + +void CameraController::update(double dt) +{ + if ( !m_camera ) + return; + + if (m_translateFast) + dt *= 10; + + // Update the camera position and orientation + Camera::CameraTranslationOption option = m_viewCenterFixed + ? Camera::DontTranslateViewCenter + : Camera::TranslateViewCenter; + m_camera->translate(dt * QVector3D(m_vx, m_vy, m_vz), option); + + m_cameraEntity->setMatrix(m_camera->viewMatrix().inverted()); + + if (!qFuzzyIsNull(m_panAngle)) { + m_camera->pan(m_panAngle); + m_panAngle = 0.0f; + } + + if (!qFuzzyIsNull(m_tiltAngle)) { + m_camera->tilt(m_tiltAngle); + m_tiltAngle = 0.0f; + } +} + +bool CameraController::keyPressEvent( QKeyEvent* e ) +{ + switch ( e->key() ) + { + case Qt::Key_Right: + m_vx = m_linearSpeed; + break; + + case Qt::Key_Left: + m_vx = -m_linearSpeed; + break; + + case Qt::Key_Up: + m_vz = m_linearSpeed; + break; + + case Qt::Key_Down: + m_vz = -m_linearSpeed; + break; + + case Qt::Key_PageUp: + m_vy = m_linearSpeed; + break; + + case Qt::Key_PageDown: + m_vy = -m_linearSpeed; + break; + + case Qt::Key_Shift: + m_viewCenterFixed = true; + break; + + case Qt::Key_Alt: + m_translateFast = true; + break; + + case Qt::Key_A: + toggleMSAA(); + break; + + default: + return false; + } + + return true; +} + +bool CameraController::keyReleaseEvent( QKeyEvent* e ) +{ + switch ( e->key() ) + { + case Qt::Key_Right: + case Qt::Key_Left: + m_vx = 0.0; + break; + + case Qt::Key_Up: + case Qt::Key_Down: + m_vz = 0.0; + break; + + case Qt::Key_PageUp: + case Qt::Key_PageDown: + m_vy = 0.0; + break; + + case Qt::Key_Shift: + m_viewCenterFixed = false; + break; + + case Qt::Key_Alt: + m_translateFast = false; + break; + + default: + return false; + } + + return true; +} + +void CameraController::mousePressEvent( QMouseEvent* e ) +{ + if ( e->button() == Qt::LeftButton ) + { + m_leftButtonPressed = true; + m_pos = m_prevPos = e->pos(); + } + else if ( e->button() == Qt::RightButton ) + { + m_orbitMode = true; + m_pos = m_prevPos = e->pos(); + } +} + +void CameraController::mouseReleaseEvent( QMouseEvent* e ) +{ + if ( e->button() == Qt::LeftButton ) + { + m_leftButtonPressed = false; + } + else if ( e->button() == Qt::RightButton ) + { + m_orbitMode = false; + } +} + +void CameraController::mouseMoveEvent( QMouseEvent* e ) +{ + if (!m_camera ) + return; + + if (!m_leftButtonPressed && !m_orbitMode) + return; + + m_pos = e->pos(); + float dx = m_pos.x() - m_prevPos.x(); + float dy = m_pos.y() - m_prevPos.y(); + m_prevPos = m_pos; + + if ( m_leftButtonPressed ) + { + m_camera->pan( dx * m_lookRate ); + m_camera->tilt( dy * m_lookRate ); + } + else if ( m_orbitMode ) + { + m_camera->panAboutViewCenter( dx * m_orbitRate ); + m_camera->tiltAboutViewCenter( dy * m_orbitRate ); + } +} + +bool CameraController::isMultisampleEnabled() const +{ + return m_multisampleEnabled; +} + +void CameraController::toggleMSAA() +{ + m_multisampleEnabled = !m_multisampleEnabled; + emit multisampleEnabledChanged(); +} + +} // of namespace Qt3D diff --git a/src/core/cameracontroller.h b/src/core/cameracontroller.h new file mode 100644 index 000000000..28a9ec6cd --- /dev/null +++ b/src/core/cameracontroller.h @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CAMERA_CONTROLLER_H +#define CAMERA_CONTROLLER_H + +#include <QObject> +#include "qt3dcore_global.h" + +#include <QPoint> + +class QMouseEvent; +class QWheelEvent; +class QKeyEvent; + + +namespace Qt3D +{ + +class Camera; +class Entity; + +class CameraController : public QObject +{ + Q_OBJECT + Q_PROPERTY( float linearSpeed READ linearSpeed WRITE setLinearSpeed NOTIFY linearSpeedChanged ) + + Q_PROPERTY( float orbitRate READ orbitRate WRITE setOrbitRate NOTIFY orbitRateChanged ) + Q_PROPERTY( float lookRate READ lookRate WRITE setLookRate NOTIFY lookRateChanged ) + + Q_PROPERTY( bool multisampleEnabled READ isMultisampleEnabled() NOTIFY multisampleEnabledChanged ) +public: + CameraController(); + + void setCamera( Camera* cam ); + void setLinearSpeed( float speed ); + float linearSpeed() const; + + float orbitRate() const; + void setOrbitRate( float rate ); + + float lookRate() const; + void setLookRate( float rate ); + + void mousePressEvent( QMouseEvent* aEvent ); + void mouseReleaseEvent( QMouseEvent* aEvent ); + void mouseMoveEvent( QMouseEvent* aEvent ); + + bool keyPressEvent( QKeyEvent* aEvent ); + bool keyReleaseEvent( QKeyEvent* aEvent ); + + bool handleScroll( QWheelEvent* aWheel ); + + void update( double t ); + + bool isMultisampleEnabled() const; +public slots: + void toggleMSAA(); + + + +signals: + void linearSpeedChanged(); + void orbitRateChanged(); + void lookRateChanged(); + + void multisampleEnabledChanged(); +private: + + Camera* m_camera; + Entity* m_cameraEntity; + + float m_vx; + float m_vy; + float m_vz; + bool m_viewCenterFixed; + float m_panAngle; + float m_tiltAngle; + + bool m_leftButtonPressed; + QPoint m_prevPos; + QPoint m_pos; + bool m_orbitMode; + + float m_linearSpeed; + float m_time; + float m_orbitRate; + float m_lookRate; + + bool m_translateFast; + bool m_multisampleEnabled; +}; + +} // of namespace Qt3D + +#endif // of CAMERA_CONTROLLER_H diff --git a/src/core/component.cpp b/src/core/component.cpp new file mode 100644 index 000000000..9f5e3a26c --- /dev/null +++ b/src/core/component.cpp @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "component.h" + +namespace Qt3D { + +Component::Component(Node *parent) + : Node(parent) + , m_changeArbiter(0) +{ +} + +void Component::registerChangeArbiter(QChangeArbiter *changeArbiter) +{ + Q_CHECK_PTR(changeArbiter); + m_changeArbiter = changeArbiter; +} + +void Component::notifySceneChange(const QSceneChangePtr &change) +{ + Q_CHECK_PTR(change); + if (m_changeArbiter) + m_changeArbiter->sceneChangeEventWithLock(change); +} + +} // namespace Qt3D diff --git a/src/core/component.h b/src/core/component.h new file mode 100644 index 000000000..608015e95 --- /dev/null +++ b/src/core/component.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3D_COMPONENT_H +#define QT3D_COMPONENT_H + +#include "node.h" +#include "qt3dcore_global.h" + +#include <qchangearbiter.h> + +namespace Qt3D { + +class Component : public Node +{ + Q_OBJECT +public: + explicit Component(Node *parent = 0); + + void registerChangeArbiter(QChangeArbiter *changeArbiter); + +protected: + virtual void notifySceneChange(const QSceneChangePtr &change); + +private: + QChangeArbiter *m_changeArbiter; +}; + +} // namespace Qt3D + +#endif // QT3D_COMPONENT_H diff --git a/src/core/core.pri b/src/core/core.pri new file mode 100644 index 000000000..5f062c585 --- /dev/null +++ b/src/core/core.pri @@ -0,0 +1,56 @@ +INCLUDEPATH += $$PWD + +HEADERS += \ + $$PWD/qt3dcore_global.h \ + $$PWD/abstractaspect.h \ + $$PWD/node.h \ + $$PWD/nodevisitor.h \ + $$PWD/abstracttransform.h \ + $$PWD/matrixtransform.h \ + $$PWD/axisalignedboundingbox.h \ + $$PWD/sphere.h \ + $$PWD/bounds.h \ + $$PWD/component.h \ + $$PWD/window.h \ + $$PWD/qaspectengine.h \ + $$PWD/qaspectscheduler.h \ + $$PWD/qaspectthread.h \ + $$PWD/qaspectmanager.h \ + $$PWD/qtickclock.h \ + $$PWD/entity.h \ + $$PWD/scene.h \ + $$PWD/qjob.h \ + $$PWD/qjobmanagerinterface.h \ + $$PWD/qscheduler.h \ + $$PWD/qjobproviderinterface.h \ + $$PWD/cameracontroller.h \ + $$PWD/translatetransform.h \ + $$PWD/rotatetransform.h \ + $$PWD/qchangearbiter.h \ + $$PWD/lookattransform.h + +SOURCES += \ + $$PWD/abstractaspect.cpp \ + $$PWD/node.cpp \ + $$PWD/nodevisitor.cpp \ + $$PWD/abstracttransform.cpp \ + $$PWD/matrixtransform.cpp \ + $$PWD/axisalignedboundingbox.cpp \ + $$PWD/sphere.cpp \ + $$PWD/bounds.cpp \ + $$PWD/component.cpp \ + $$PWD/window.cpp \ + $$PWD/qaspectengine.cpp \ + $$PWD/qaspectscheduler.cpp \ + $$PWD/qaspectthread.cpp \ + $$PWD/qaspectmanager.cpp \ + $$PWD/qtickclock.cpp \ + $$PWD/entity.cpp \ + $$PWD/scene.cpp \ + $$PWD/qjob.cpp \ + $$PWD/qscheduler.cpp \ + $$PWD/cameracontroller.cpp \ + $$PWD/translatetransform.cpp \ + $$PWD/rotatetransform.cpp \ + $$PWD/qchangearbiter.cpp \ + $$PWD/lookattransform.cpp diff --git a/src/core/core.pro b/src/core/core.pro new file mode 100644 index 000000000..c599bbdba --- /dev/null +++ b/src/core/core.pro @@ -0,0 +1,27 @@ +TARGET = Qt3DCore +MODULE = 3dcore +QT = core-private gui-private qml qml-private quick + +load(qt_module) + +DEFINES += QT3DCORE_LIBRARY + +#QMAKE_DOCS = $$PWD/doc/qt3d.qdocconf + +gcov { + CONFIG += static + QMAKE_CXXFLAGS += -fprofile-arcs -ftest-coverage + QMAKE_LFLAGS += -fprofile-arcs -ftest-coverage +} else { + CONFIG += dll +} + +# otherwise mingw headers do not declare common functions like ::strcasecmp +win32-g++*:QMAKE_CXXFLAGS_CXX11 = -std=gnu++0x + +include(core.pri) +include(../render/render.pri) +PUBLIC_HEADERS = $$HEADERS +HEADERS += $$PRIVATE_HEADERS + +!contains(QT_CONFIG, egl):DEFINES += QT_NO_EGL diff --git a/src/core/entity.cpp b/src/core/entity.cpp new file mode 100644 index 000000000..136778216 --- /dev/null +++ b/src/core/entity.cpp @@ -0,0 +1,232 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "entity.h" + +#include "component.h" +#include "abstracttransform.h" +#include "matrixtransform.h" + +#include <QMetaObject> +#include <QMetaProperty> +#include <QDebug> + +namespace Qt3D { + +Entity::Entity(Node *parent) + : Node(parent) + , m_enabled(true) +{ +} + +QQmlListProperty<AbstractTransform> Entity::transformList() +{ + return QQmlListProperty<AbstractTransform>(this, 0, + Entity::qmlAppendTransform, + Entity::transformCount, + Entity::transformAt, + Entity::qmlClearTransforms); +} + +QList<Component *> Entity::components() const +{ + // Construct the list of components by looking for all properties that + // inherit from Component + QList<Component *> componentList; + const QMetaObject *meta = metaObject(); + for (int i = 0; i < meta->propertyCount(); ++i) { + const QMetaProperty metaProperty = meta->property(i); + const QVariant value = property(metaProperty.name()); + Component *component = value.value<Component *>(); + if (component) + componentList.append(component); + } + + return componentList + m_components; +} + +void Entity::addComponent(Component *comp) +{ + Q_CHECK_PTR( comp ); + Q_ASSERT(m_components.count(comp) == 0); + comp->setParent(this); + m_components.append(comp); +} + +void Entity::removeComponent(Component *comp) +{ + Q_CHECK_PTR(comp); + m_components.removeOne(comp); +} + +bool Entity::isEnabled() const +{ + return m_enabled; +} + +void Entity::setEnabled(bool on) +{ + if (m_enabled != on) { + m_enabled = on; + emit enabledChanged(); + } +} + +QMatrix4x4 Entity::matrix() const +{ + if (m_transformsDirty) { + m_matrix = applyTransforms(); + m_transformsDirty = false; + } + return m_matrix; +} + +void Entity::update() +{ + if (m_transformsDirty) { + m_matrix = applyTransforms(); + m_transformsDirty = false; + } + + QMatrix4x4 prM; + if (parentEntity()) + prM = parentEntity()->sceneMatrix(); + + m_sceneMatrix = prM * matrix(); + // invalidate bounding volume information as required +} + +void Entity::setMatrix(const QMatrix4x4 &m) +{ + qDeleteAll(m_transforms); + m_transforms.clear(); + appendTransfrom(new MatrixTransform(m)); +} + +/*! + The combined transform relative to the root of the scene +*/ +QMatrix4x4 Entity::sceneMatrix() const +{ + return m_sceneMatrix; +} + +/*! + The center of rotation for the entity. Defaults to the local origin. +*/ +QVector3D Entity::rotationCenter() const +{ + return QVector3D(); +} + +QList<AbstractTransform *> Entity::transforms() const +{ + return m_transforms; +} + +void setRotationCenter(const QVector3D &rc) +{ + Q_UNUSED(rc); +} + +void Entity::appendTransfrom(AbstractTransform *xform) +{ + m_transformsDirty = true; + m_transforms.append( xform ); +} + +void Entity::removeTransform(AbstractTransform *xform) +{ + m_transformsDirty = true; + m_transforms.removeOne( xform ); +} + +Entity *Entity::asEntity() +{ + return this; +} + +Entity *Entity::parentEntity() +{ + return qobject_cast<Entity*>(parent()); +} + +QMatrix4x4 Entity::applyTransforms() const +{ + QMatrix4x4 m; + m.setToIdentity(); + Q_FOREACH (AbstractTransform *t, m_transforms) + m = t->matrix() * m; + return m; +} + + +void Entity::qmlAppendTransform(QQmlListProperty<AbstractTransform> *list, AbstractTransform *obj ) +{ + if ( !obj ) + return; + + Entity* self = static_cast<Entity*>(list->object); + self->appendTransfrom(obj); +} + +AbstractTransform* Entity::transformAt(QQmlListProperty<AbstractTransform>* list, int index) +{ + Entity* self = static_cast<Entity*>(list->object); + return self->transforms().at(index); +} + +int Entity::transformCount(QQmlListProperty<AbstractTransform>* list) +{ + Entity* self = static_cast<Entity*>(list->object); + return self->transforms().count(); +} + +void Entity::qmlClearTransforms(QQmlListProperty<AbstractTransform> *list) +{ + Entity* self = static_cast<Entity*>(list->object); + qDeleteAll(self->m_transforms); + self->m_transforms.clear(); + self->m_transformsDirty = true; +} + + +} // namespace Qt3D diff --git a/src/core/entity.h b/src/core/entity.h new file mode 100644 index 000000000..e79856e70 --- /dev/null +++ b/src/core/entity.h @@ -0,0 +1,162 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3D_ENTITY_H +#define QT3D_ENTITY_H + +#include "node.h" +#include "qt3dcore_global.h" + +#include <QMatrix4x4> + +namespace Qt3D { + +class AbstractTransform; +class Component; + +typedef QList<Component*> ComponentList; + +class Entity : public Node +{ + Q_OBJECT + + Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged) + + Q_PROPERTY(QQmlListProperty<Qt3D::AbstractTransform> transforms READ transformList) + + +public: + explicit Entity(Node *parent = 0); + + ComponentList components() const; + + template <class T> + QList<T*> componentsOfType() const + { + QList<T*> result; + foreach (Component* comp, components()) { + T* i = qobject_cast<T*>(comp); + if (i) + result.append(i); + } + + return result; + } + + template <class T> + static T* findComponentInTree(Node* root) + { + if (!root) + return NULL; + + if (root->asEntity()) { + foreach (Component* comp, root->asEntity()->components()) { + T* i = qobject_cast<T*>(comp); + if (i) + return i; + } // of component iteration + } // of is-entity + + foreach (Node* child, root->children()) { + T* i = findComponentInTree<T>(child); + if (i) + return i; + } // of child nodes iteration + + return NULL; + } + + void addComponent(Component *comp); + void removeComponent(Component *comp); + + bool isEnabled() const; + void setEnabled(bool on); + + QMatrix4x4 matrix() const; + void setMatrix(const QMatrix4x4 &m); + + QMatrix4x4 sceneMatrix() const; + + QVector3D rotationCenter() const; + void setRotationCenter(const QVector3D &rc); + + QList<AbstractTransform*> transforms() const; + + // void insertTransformAt(...) + Q_INVOKABLE void appendTransfrom(AbstractTransform *xform); + Q_INVOKABLE void removeTransform(AbstractTransform *xform); + + virtual Entity* asEntity(); + + Entity* parentEntity(); + + // TEMPORARY - should be driven by an Update traversal in the core + void update(); +signals: + void enabledChanged(); + +private: + QQmlListProperty<Qt3D::AbstractTransform> transformList(); + + ComponentList m_components; + + QMatrix4x4 applyTransforms() const; + + mutable bool m_transformsDirty; + bool m_visible; + QList<AbstractTransform*> m_transforms; + + mutable QMatrix4x4 m_matrix; + QMatrix4x4 m_sceneMatrix; + + // TODO: Is a bool enough here or do we need additional states for entities? + // Perhaps aboutToBeDeleted would be useful? + bool m_enabled; + + static void qmlAppendTransform(QQmlListProperty<Qt3D::AbstractTransform> *list, Qt3D::AbstractTransform *bar); + static AbstractTransform* transformAt(QQmlListProperty<Qt3D::AbstractTransform> *list, int index); + static int transformCount(QQmlListProperty<Qt3D::AbstractTransform> *list); + static void qmlClearTransforms(QQmlListProperty<Qt3D::AbstractTransform> *list); +}; + +} // namespace Qt3D + +#endif // QT3D_ENTITY_H diff --git a/src/core/lookattransform.cpp b/src/core/lookattransform.cpp new file mode 100644 index 000000000..6d2109906 --- /dev/null +++ b/src/core/lookattransform.cpp @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "lookattransform.h" + +namespace Qt3D { + +LookAtTransform::LookAtTransform(Node *parent) + : AbstractTransform(parent) +{ +} + +QMatrix4x4 LookAtTransform::matrix() const +{ + if (m_matrixDirty) { + m_matrix.setToIdentity(); + m_matrix.lookAt(m_position, m_viewCenter, m_upVector); + m_matrixDirty = false; + } + return m_matrix; +} + +QVector3D LookAtTransform::position() const +{ + return m_position; +} + +void LookAtTransform::setPosition(const QVector3D &position) +{ + if (m_position != position) { + m_position = position; + m_viewVector = m_viewCenter - position; + m_matrixDirty = true; + emit positionChanged(); + emit viewVectorChanged(); + } +} + +void LookAtTransform::setUpVector(const QVector3D &upVector) +{ + if (m_upVector != upVector) { + m_upVector = upVector; + m_matrixDirty = true; + emit upVectorChanged(); + } +} + +QVector3D LookAtTransform::upVector() const +{ + return m_upVector; +} + +void LookAtTransform::setViewCenter(const QVector3D &viewCenter) +{ + if (m_viewCenter != viewCenter) { + m_viewCenter = viewCenter; + m_viewVector = viewCenter - m_position; + m_matrixDirty = true; + emit viewCenterChanged(); + emit viewVectorChanged(); + } +} + +QVector3D LookAtTransform::viewCenter() const +{ + return m_viewCenter; +} + +QVector3D LookAtTransform::viewVector() const +{ + return m_viewVector; +} + +} // namespace Qt3D diff --git a/src/core/lookattransform.h b/src/core/lookattransform.h new file mode 100644 index 000000000..c032f32dc --- /dev/null +++ b/src/core/lookattransform.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3D_LOOKATTRANSFORM_H +#define QT3D_LOOKATTRANSFORM_H + +#include "abstracttransform.h" +#include "qt3dcore_global.h" + +#include <QVector3D> + +namespace Qt3D { + +class LookAtTransform : public Qt3D::AbstractTransform +{ + Q_OBJECT + Q_PROPERTY(QVector3D position READ position WRITE setPosition) + Q_PROPERTY(QVector3D upVector READ upVector WRITE setUpVector) + Q_PROPERTY(QVector3D viewCenter READ viewCenter WRITE setViewCenter) + Q_PROPERTY(QVector3D viewVector READ viewVector NOTIFY viewVectorChanged) + +public: + explicit LookAtTransform(Node *parent = 0); + + QMatrix4x4 matrix() const Q_DECL_OVERRIDE; + + void setPosition(const QVector3D &position); + QVector3D position() const; + + void setUpVector(const QVector3D &upVector); + QVector3D upVector() const; + + void setViewCenter(const QVector3D &viewCenter); + QVector3D viewCenter() const; + + QVector3D viewVector() const; + +signals: + void positionChanged(); + void upVectorChanged(); + void viewCenterChanged(); + void viewVectorChanged(); + +private: + mutable QMatrix4x4 m_matrix; + QVector3D m_position; + QVector3D m_upVector; + QVector3D m_viewCenter; + QVector3D m_viewVector; // From "camera" position to view center + mutable bool m_matrixDirty; +}; + +} // namespace Qt3D + +#endif // QT3D_LOOKATTRANSFORM_H diff --git a/src/core/matrixtransform.cpp b/src/core/matrixtransform.cpp new file mode 100644 index 000000000..e93b96835 --- /dev/null +++ b/src/core/matrixtransform.cpp @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "matrixtransform.h" + +namespace Qt3D { + +MatrixTransform::MatrixTransform() +{ +} + +MatrixTransform::MatrixTransform(const QMatrix4x4& m) : + m_matrix(m) +{ +} + +QMatrix4x4 MatrixTransform::matrix() const +{ + return m_matrix; +} + +} diff --git a/src/core/matrixtransform.h b/src/core/matrixtransform.h new file mode 100644 index 000000000..0019a2aef --- /dev/null +++ b/src/core/matrixtransform.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MATRIXTRANSFORM_H +#define MATRIXTRANSFORM_H + +#include "abstracttransform.h" +#include "qt3dcore_global.h" + +#include <QMatrix4x4> + +namespace Qt3D { + +class MatrixTransform : public AbstractTransform +{ +public: + MatrixTransform(); + + MatrixTransform( const QMatrix4x4& m ); + + virtual QMatrix4x4 matrix() const; +private: + QMatrix4x4 m_matrix; +}; + +} + +#endif // MATRIXTRANSFORM_H diff --git a/src/core/node.cpp b/src/core/node.cpp new file mode 100644 index 000000000..81f11ea77 --- /dev/null +++ b/src/core/node.cpp @@ -0,0 +1,228 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "node.h" + +#include "entity.h" + +#include <QEvent> +#include <QMetaObject> +#include <QMetaProperty> +#include <QDebug> + +namespace Qt3D { + +Node::Node( Node* parent ) + : QObject( parent ) +{ + if (parent) + parent->m_children.append(this); +} + +Node::~Node() +{ +} + +QQmlListProperty<QObject> Node::data() +{ + return QQmlListProperty<QObject>(this, 0, + Node::appendData, + Node::dataCount, + Node::dataAt, + Node::clearData); +} + +QQmlListProperty<Node> Node::childNodes() +{ + return QQmlListProperty<Node>(this, 0, + Node::appendChild, + Node::childCount, + Node::childAt, + Node::clearChildren); +} + +void Node::dump() +{ + const QMetaObject *meta = metaObject(); + QStringList result; + for (int i = 0; i < meta->propertyCount(); ++i) { + const QMetaProperty metaProperty = meta->property(i); + const QVariant value = property(metaProperty.name()); + result += QString(QStringLiteral("%1 %2 = %3;")) + .arg(QString::fromLatin1(metaProperty.typeName())) + .arg(QString::fromLatin1(metaProperty.name())) + .arg(value.toString()); + } + + qDebug() << result.join(QStringLiteral("\n")); + + foreach (QObject *child, children()) { + Node *node = qobject_cast<Node *>(child); + if (!node) + continue; + node->dump(); + } +} + +NodeList Node::children() const +{ + return m_children; +} + +void Node::addChild(Node *childNode) +{ + Q_CHECK_PTR( childNode ); + if (childNode->parent() == this) + return; + + m_children.append(childNode); + childNode->setParent(this); + + if (childNode->asEntity()) + childNode->asEntity()->update(); +} + +void Node::removeChild(Node *childNode) +{ + Q_CHECK_PTR( childNode ); + if (childNode->parent() != this) + qWarning() << Q_FUNC_INFO << "not a child"; + + m_children.removeOne(childNode); + childNode->setParent(NULL); +} + +void Node::removeAllChildren() +{ + foreach (QObject *child, children()) { + child->deleteLater(); + } + + m_children.clear(); +} + +Entity *Node::asEntity() +{ + return NULL; +} + +Node *Node::parentNode() const +{ + return qobject_cast<Node*>(parent()); +} + +bool Node::event(QEvent *e) +{ + if (e->type() == QEvent::DynamicPropertyChange) { + qDebug() << "*** Dynamic Property Change ***"; + } + return QObject::event(e); +} + +void Node::appendData(QQmlListProperty<QObject> *list, QObject *obj) +{ + if (!obj) + return; + + QObject *self = static_cast<QObject *>(list->object); + if (obj->parent() == self) + obj->setParent(0); + obj->setParent(self); + + Node *parentNode = qobject_cast<Qt3D::Node *>(self); + Node *node = qobject_cast<Qt3D::Node *>(obj); + if (node && parentNode) + parentNode->m_children.append(node); +} + +QObject *Node::dataAt(QQmlListProperty<QObject> *list, int index) +{ + QObject *self = static_cast<QObject *>(list->object); + return self->children().at(index); +} + +int Node::dataCount(QQmlListProperty<QObject> *list) +{ + QObject *self = static_cast<QObject *>(list->object); + return self->children().count(); +} + +void Node::clearData(QQmlListProperty<QObject> *list) +{ + QObject *self = static_cast<QObject *>(list->object); + Q_FOREACH (QObject *const child, self->children()) + child->setParent(0); +} + +void Node::appendChild(QQmlListProperty<Qt3D::Node> *list, Qt3D::Node *obj) +{ + if (!obj) + return; + + Node *self = static_cast<Node *>(list->object); + Q_ASSERT(!self->m_children.contains(obj)); + if (obj->parent() == self) + obj->setParent(0); + self->m_children.append(obj); + obj->setParent(self); +} + +Qt3D::Node *Node::childAt(QQmlListProperty<Qt3D::Node> *list, int index) +{ + Node *self = static_cast<Node *>(list->object); + return self->m_children.at(index); +} + +int Node::childCount(QQmlListProperty<Qt3D::Node> *list) +{ + Node *self = static_cast<Node *>(list->object); + return self->m_children.count(); +} + +void Node::clearChildren(QQmlListProperty<Qt3D::Node> *list) +{ + Node *self = static_cast<Node *>(list->object); + Q_FOREACH (Node *const child, self->m_children) + child->setParent(0); + self->m_children.clear(); +} + +} // of namespace Qt3D diff --git a/src/core/node.h b/src/core/node.h new file mode 100644 index 000000000..c1776774f --- /dev/null +++ b/src/core/node.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3D_NODE_H +#define QT3D_NODE_H + +#include <QObject> +#include "qt3dcore_global.h" + +#include <QQmlListProperty> + +namespace Qt3D { + +class Node; +class Component; +class Entity; + +typedef QList<Node *> NodeList; + +class QT3DCORESHARED_EXPORT Node : public QObject +{ + Q_OBJECT + Q_PROPERTY(QQmlListProperty<QObject> data READ data) + Q_PROPERTY(QQmlListProperty<Qt3D::Node> childNodes READ childNodes) + Q_CLASSINFO("DefaultProperty", "data") + +public: + explicit Node(Node *parent = 0); + ~Node(); + + QQmlListProperty<QObject> data(); + QQmlListProperty<Qt3D::Node> childNodes(); + + void dump(); + + NodeList children() const; + void addChild( Node* childNode ); + void removeChild( Node* childNode ); + + void removeAllChildren(); + + virtual Entity* asEntity(); + + Node* parentNode() const; + +protected: + bool event(QEvent *e); + +private: + static void appendData(QQmlListProperty<QObject> *list, QObject *obj); + static QObject *dataAt(QQmlListProperty<QObject> *list, int index); + static int dataCount(QQmlListProperty<QObject> *list); + static void clearData(QQmlListProperty<QObject> *list); + + static void appendChild(QQmlListProperty<Qt3D::Node> *list, Qt3D::Node *obj); + static Node *childAt(QQmlListProperty<Qt3D::Node> *list, int index); + static int childCount(QQmlListProperty<Qt3D::Node> *list); + static void clearChildren(QQmlListProperty<Qt3D::Node> *list); + + NodeList m_children; +}; + +} + +#endif diff --git a/src/core/nodevisitor.cpp b/src/core/nodevisitor.cpp new file mode 100644 index 000000000..5c0f99752 --- /dev/null +++ b/src/core/nodevisitor.cpp @@ -0,0 +1,129 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "nodevisitor.h" + +#include "node.h" +#include "entity.h" + +namespace Qt3D { + +NodeVisitor::NodeVisitor() + : m_traverseDisabled(false) +{ +} + +void NodeVisitor::traverse(Node *rootNode) +{ + m_path = NodeList() << rootNode; + + m_matrixStack.clear(); + Entity* rootEntity = rootNode->asEntity(); + + m_matrixStack.append(rootEntity ? rootEntity->matrix() : QMatrix4x4()); + + if (rootEntity) + visitEntity(rootEntity); + else + visitNode(rootNode); +} + +Node* NodeVisitor::rootNode() const +{ + return m_path.front(); +} + +Node* NodeVisitor::currentNode() const +{ + return m_path.back(); +} + +QMatrix4x4 NodeVisitor::currentMatrix() const +{ + return m_matrixStack.back(); +} + +NodeList NodeVisitor::path() const +{ + return m_path; +} + +void NodeVisitor::setTraverseDisabled(bool on) +{ + m_traverseDisabled = on; +} + +void NodeVisitor::visitNode(Node *nd) +{ + Q_UNUSED(nd); + traverseChildren(); +} + +void NodeVisitor::visitEntity(Entity *nd) +{ + visitNode(nd); +} + +void NodeVisitor::traverseChildren() +{ + foreach (Node* n, currentNode()->children()) { + outerVisitNode(n); + } // of children iteration +} + +void NodeVisitor::outerVisitNode(Node *n) +{ + m_path.append(n); + Entity* e = n->asEntity(); + if (e) { + QMatrix4x4 m = m_matrixStack.back() * e->matrix(); + m_matrixStack.push_back(m); + + visitEntity(e); + + m_path.pop_back(); + m_matrixStack.pop_back(); + } else { + visitNode(n); + } +} + +} // of namespace diff --git a/src/core/nodevisitor.h b/src/core/nodevisitor.h new file mode 100644 index 000000000..2be95a8d1 --- /dev/null +++ b/src/core/nodevisitor.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef NODEVISITOR_H +#define NODEVISITOR_H + +#include "qt3dcore_global.h" + +#include <QMatrix4x4> + +namespace Qt3D +{ + +class Node; +class Entity; + +typedef QList<Node *> NodeList; + +class NodeVisitor +{ +public: + NodeVisitor(); + + void traverse(Node *rootNode); + + Node *rootNode() const; + + Node *currentNode() const; + + QMatrix4x4 currentMatrix() const; + + NodeList path() const; + + void setTraverseDisabled(bool on); + +protected: + virtual void visitNode(Node *nd); + virtual void visitEntity(Entity *ent); + + void traverseChildren(); + +private: + NodeList m_path; + QVector<QMatrix4x4> m_matrixStack; + bool m_traverseDisabled; + + void outerVisitNode(Node *n); +}; + +} // of namespace + +#endif // NODEVISITOR_H diff --git a/src/core/qaspectengine.cpp b/src/core/qaspectengine.cpp new file mode 100644 index 000000000..63e470bfc --- /dev/null +++ b/src/core/qaspectengine.cpp @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qaspectengine.h" + +#include "qaspectthread.h" +#include "qaspectmanager.h" +#include "qchangearbiter.h" + +#include <QDebug> +#include <QMetaObject> +#include <QMutexLocker> + +namespace Qt3D { + +QAspectEngine::QAspectEngine(QObject *parent) + : QObject(parent) + , m_aspectThread(new QAspectThread(this)) +{ + qDebug() << Q_FUNC_INFO; + qRegisterMetaType<QWaitCondition *>(); + m_aspectThread->waitForStart(QThread::HighestPriority); +} + +void QAspectEngine::initialize() +{ + QChangeArbiter *arbiter = m_aspectThread->aspectManager()->changeArbiter(); + QChangeArbiter::createUnmanagedThreadLocalChangeQueue(arbiter); +} + +void QAspectEngine::shutdown() +{ +} + +void QAspectEngine::setWindow(QWindow *window) +{ + QMetaObject::invokeMethod(m_aspectThread->aspectManager(), "setWindow", Q_ARG(QWindow *, window)); +} + +void QAspectEngine::setRoot(QObject *rootObject) +{ + QMutexLocker locker(&m_mutex); + QMetaObject::invokeMethod(m_aspectThread->aspectManager(), "setRoot", Q_ARG(QObject *, rootObject), Q_ARG(QWaitCondition *, &m_waitCondition)); + + qDebug() << "Putting main thread to sleep whilst aspects build their local scenes..."; + m_waitCondition.wait(&m_mutex); + qDebug() << "Main thread is now awake again"; +} + +} // namespace Qt3D diff --git a/src/core/qaspectengine.h b/src/core/qaspectengine.h new file mode 100644 index 000000000..a7f949088 --- /dev/null +++ b/src/core/qaspectengine.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QASPECTENGINE_H +#define QASPECTENGINE_H + +#include <QObject> +#include "qt3dcore_global.h" + +#include <QList> +#include <QMutex> +#include <QWaitCondition> + +class QWindow; + +namespace Qt3D { + +class AbstractAspect; +class QAspectThread; + +class QAspectEngine : public QObject +{ + Q_OBJECT +public: + explicit QAspectEngine(QObject *parent = 0); + + void initialize(); + void shutdown(); + + void setRoot(QObject *rootObject); + void setWindow(QWindow *window); +private: + QAspectThread *m_aspectThread; + QMutex m_mutex; + QWaitCondition m_waitCondition; +}; + +} // namespace Qt3D + +Q_DECLARE_METATYPE(QWaitCondition *) + +#endif // QASPECTENGINE_H diff --git a/src/core/qaspectmanager.cpp b/src/core/qaspectmanager.cpp new file mode 100644 index 000000000..1205314e9 --- /dev/null +++ b/src/core/qaspectmanager.cpp @@ -0,0 +1,191 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qaspectmanager.h" + +#include "rendereraspect.h" +#include "qchangearbiter.h" +// TODO Make the kind of job manager configurable (e.g. ThreadWeaver vs Intel TBB) +//#include "qjobmanager.h" +#include "qjobmanagerinterface.h" +#include "qscheduler.h" +#include "qtickclock.h" + +#include <node.h> + +#include <QDebug> +#include <QElapsedTimer> +#include <QEventLoop> +#include <QThread> +#include <QWaitCondition> +#include <QWindow> + +namespace Qt3D { + +QAspectManager::QAspectManager(QObject *parent) + : QObject(parent) + , m_root(0) + , m_window(0) + , m_scheduler(new QScheduler(this)) + , m_jobManager(0/*new QJobManager(this)*/) + , m_changeArbiter(new QChangeArbiter(this)) + , m_runMainLoop(false) +{ + qRegisterMetaType<QWindow*>("QWindow*"); + qDebug() << Q_FUNC_INFO; +} + +void QAspectManager::initialize() +{ + qDebug() << Q_FUNC_INFO; + m_jobManager->initialize(); + m_scheduler->setAspectManager(this); + m_changeArbiter->initialize(m_jobManager); +} + +void QAspectManager::shutdown() +{ + qDebug() << Q_FUNC_INFO; +} + +void QAspectManager::setRoot(QObject *rootObject, QWaitCondition *waitCondition) +{ + qDebug() << Q_FUNC_INFO; + + Node *root = qobject_cast<Node *>(rootObject); + if (root == m_root) + return; + + if (m_root) { + // Allow each aspect chance to cleanup any resources from this scene + Q_FOREACH (AbstractAspect *aspect, m_aspects) + aspect->unregisterAspect(m_root); + + // Allow each aspect chance to cleanup any scene-independent resources + Q_FOREACH (AbstractAspect *aspect, m_aspects) + aspect->cleanup(); + + // Destroy all aspects + qDeleteAll(m_aspects); + m_aspects.clear(); + + m_root = 0; + } + + m_root = root; + + if (rootObject) { + // TODO Load all aspect plugins that are found and required. + // For now just load the render aspect + RendererAspect *renderAspect = new RendererAspect(this); + m_aspects.append(renderAspect); + + Q_FOREACH (AbstractAspect *aspect, m_aspects) + aspect->initialize(this); + + if (m_window) { + Q_FOREACH (AbstractAspect *aspect, m_aspects) + aspect->setWindow(m_window); + } + + Q_FOREACH (AbstractAspect *aspect, m_aspects) + aspect->registerAspect(m_root); + + m_runMainLoop = true; + } + + if (waitCondition) + waitCondition->wakeOne(); +} + +void QAspectManager::setWindow(QWindow *window) +{ + qDebug() << Q_FUNC_INFO; + + m_window = window; + + if (m_window) { + Q_FOREACH (AbstractAspect *aspect, m_aspects) + aspect->setWindow(m_window); + } +} + +void QAspectManager::exec() +{ + // Gentlemen, start your engines + QEventLoop eventLoop; + +// QElapsedTimer timer; +// timer.start(); +// qint64 t(0); + QTickClock tickClock; + tickClock.start(); + + // Enter the main loop + while (1) + { + // Process any pending events, waiting for more to arrive if queue is empty + eventLoop.processEvents(QEventLoop::WaitForMoreEvents, 16); + + // Only enter main render loop once the renderer and other aspects are initialized + while (m_runMainLoop) + { + // Process any pending events + eventLoop.processEvents(); + + // Update the clocks (just main clock for now). + // TODO: Add additional clocks + qint64 t = tickClock.waitForNextTick(); + // qDebug() << "t =" << t / 1000000; +// const qint64 t1 = timer.nsecsElapsed(); +// const qint64 dt = t1 - t; +// t = t1; +// qDebug() << "dt =" << dt; + + m_scheduler->update(t); + + // Distribute accumulated changes + m_changeArbiter->syncChanges(); + } + } +} + +} // namespace Qt3D diff --git a/src/core/qaspectmanager.h b/src/core/qaspectmanager.h new file mode 100644 index 000000000..2653d4a0f --- /dev/null +++ b/src/core/qaspectmanager.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3D_QASPECTMANAGER_H +#define QT3D_QASPECTMANAGER_H + +#include <QObject> +#include "qt3dcore_global.h" + +#include <QList> + +class QWaitCondition; +class QWindow; + +namespace Qt3D { + +class AbstractAspect; +class Node; +class QChangeArbiter; +class QJobManagerInterface; +class QScheduler; + +class QAspectManager : public QObject +{ + Q_OBJECT +public: + explicit QAspectManager(QObject *parent = 0); + +public slots: + void initialize(); + void shutdown(); + + void setRoot(QObject *rootObject, QWaitCondition *waitCondition); + void setWindow(QWindow* window); + + void exec(); + + const QList<AbstractAspect *> &aspects() const { return m_aspects; } + QJobManagerInterface *jobManager() const { return m_jobManager; } + QChangeArbiter *changeArbiter() const { return m_changeArbiter; } + +private: + QList<AbstractAspect *> m_aspects; + Node *m_root; + QWindow *m_window; + QScheduler *m_scheduler; + QJobManagerInterface *m_jobManager; + QChangeArbiter *m_changeArbiter; + bool m_runMainLoop; +}; + +} // namespace Qt3D + +#endif // QT3D_QASPECTMANAGER_H diff --git a/src/core/qaspectscheduler.cpp b/src/core/qaspectscheduler.cpp new file mode 100644 index 000000000..22febeae6 --- /dev/null +++ b/src/core/qaspectscheduler.cpp @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qaspectscheduler.h" + +#include <QDebug> + +namespace Qt3D { + +QAspectScheduler::QAspectScheduler(QObject *parent) + : QObject(parent) +{ + qDebug() << Q_FUNC_INFO; +} + +} // namespace Qt3D diff --git a/src/core/qaspectscheduler.h b/src/core/qaspectscheduler.h new file mode 100644 index 000000000..6bc38c732 --- /dev/null +++ b/src/core/qaspectscheduler.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3D_QASPECTSCHEDULER_H +#define QT3D_QASPECTSCHEDULER_H + +#include <QObject> +#include "qt3dcore_global.h" + +namespace Qt3D { + +class QAspectScheduler : public QObject +{ + Q_OBJECT +public: + explicit QAspectScheduler(QObject *parent = 0); + +}; + +} // namespace Qt3D + +#endif // QT3D_QASPECTSCHEDULER_H diff --git a/src/core/qaspectthread.cpp b/src/core/qaspectthread.cpp new file mode 100644 index 000000000..22d920adb --- /dev/null +++ b/src/core/qaspectthread.cpp @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qaspectthread.h" + +#include <qaspectmanager.h> + +#include <QDebug> +#include <QMutexLocker> + +namespace Qt3D { + +QAspectThread::QAspectThread(QObject *parent) + : QThread(parent) + , m_aspectManager(0) +{ + qDebug() << Q_FUNC_INFO; +} + +void QAspectThread::waitForStart(Priority priority) +{ + qDebug() << "Starting QAspectThread and going to sleep until it is ready for us..."; + m_mutex.lock(); + start(priority); + m_waitCondition.wait(&m_mutex); + qDebug() << "QAspectThead is now ready & calling thread is now awake again"; +} + +void QAspectThread::run() +{ + qDebug() << "Entering void QAspectThread::run()"; + + // Lock mutex and create worker objects + QMutexLocker locker(&m_mutex); + m_aspectManager = new QAspectManager; + + // Wake up the calling thread now that our worker objects are ready for action + m_waitCondition.wakeOne(); + m_mutex.unlock(); + + // Load and initialize the aspects and any other core services + m_aspectManager->initialize(); + + // Enter the main loop + m_aspectManager->exec(); + + // Clean up + m_aspectManager->shutdown(); + delete m_aspectManager; + + qDebug() << "Exiting void QAspectThread::run()"; +} + +} // namespace Qt3D diff --git a/src/core/qaspectthread.h b/src/core/qaspectthread.h new file mode 100644 index 000000000..6d9d76707 --- /dev/null +++ b/src/core/qaspectthread.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3D_QASPECTTHREAD_H +#define QT3D_QASPECTTHREAD_H + +#include <QThread> +#include "qt3dcore_global.h" + +#include <QMutex> +#include <QWaitCondition> + +namespace Qt3D { + +class QAspectManager; + +class QAspectThread : public QThread +{ + Q_OBJECT +public: + explicit QAspectThread(QObject *parent = 0); + + void waitForStart(Priority priority); + + QAspectManager *aspectManager() const { return m_aspectManager; } + +protected: + void run() Q_DECL_OVERRIDE; + +private: + QAspectManager *m_aspectManager; + QMutex m_mutex; + QWaitCondition m_waitCondition; +}; + +} // namespace Qt3D + +#endif // QT3D_QASPECTTHREAD_H diff --git a/src/core/qchangearbiter.cpp b/src/core/qchangearbiter.cpp new file mode 100644 index 000000000..6bfbfd015 --- /dev/null +++ b/src/core/qchangearbiter.cpp @@ -0,0 +1,249 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qchangearbiter.h" +#include "component.h" +#include "qjobmanagerinterface.h" + +#include <QDebug> +#include <QMutexLocker> +#include <QReadLocker> +#include <QThread> +#include <QWriteLocker> + +namespace Qt3D { + +QObservable::QObservable() + : m_observers() + , m_lock(QReadWriteLock::NonRecursive) +{ +} + +void QObservable::registerObserver(QObserverInterface *observer) +{ + QWriteLocker locker(&m_lock); + if (!m_observers.contains(observer)) + m_observers.append(observer); +} + +void QObservable::unregisterObserver(QObserverInterface *observer) +{ + QWriteLocker locker(&m_lock); + m_observers.removeOne(observer); +} + +void QObservable::notifyObservers(const QSceneChangePtr &e) +{ + QReadLocker locker(&m_lock); + Q_FOREACH (QObserverInterface *observer, m_observers) + observer->sceneChangeEvent(e); +} + + +QChangeArbiter::QChangeArbiter(QObject *parent) + : QObject(parent) + , m_jobManager(0) +{ +} + +void QChangeArbiter::initialize(QJobManagerInterface *jobManager) +{ + Q_CHECK_PTR(jobManager); + m_jobManager = jobManager; + + // Init TLS for the change queues + m_jobManager->waitForPerThreadFunction(QChangeArbiter::createThreadLocalChangeQueue, this); +} + +void QChangeArbiter::distributeQueueChanges(ChangeQueue *changeQueue) +{ + Q_FOREACH (const QSceneChangePtr &change, *changeQueue) { + // Lookup which observers care about the subject this change came from + // and distribute the change to them + switch (change->m_subjectType) { + case QSceneChange::ObservableType: { + QObservableInterface *subject = change->m_subject.m_observable; + if (m_observations.contains(subject)) { + QObserverList &observers = m_observations[subject]; + Q_FOREACH (QObserverInterface *observer, observers) + observer->sceneChangeEvent(change); + } + break; + } + + case QSceneChange::ComponentType: { + Component *subject = change->m_subject.m_component; + if (m_componentObservations.contains(subject)) { + QObserverList &observers = m_componentObservations[subject]; + Q_FOREACH (QObserverInterface *observer, observers) + observer->sceneChangeEvent(change); + } + break; + } + } + } +} + +void QChangeArbiter::syncChanges() +{ + //qDebug() << Q_FUNC_INFO; + QMutexLocker locker(&m_mutex); + Q_FOREACH (QChangeArbiter::ChangeQueue *changeQueue, m_changeQueues) { + distributeQueueChanges(changeQueue); + changeQueue->clear(); + } + + Q_FOREACH (ChangeQueue *changeQueue, m_lockingChangeQueues) { + distributeQueueChanges(changeQueue); + changeQueue->clear(); + } +} + +void QChangeArbiter::registerObserver(QObserverInterface *observer, + QObservableInterface *subject, + ChangeFlags changeFlags) +{ + qDebug() << Q_FUNC_INFO; + if (!observer || !subject) + return; + + // Store info about which observers are watching which observables. + // Protect access as this could be called from any thread + QMutexLocker locker(&m_mutex); + QObserverList &observers = m_observations[subject]; + observers.append(observer); + + // TODO: Also store info about types of change observer is interested in so that we + // can reduce the amount of traffic + Q_UNUSED(changeFlags); + + // Register ourselves with the observable as the intermediary + subject->registerObserver(this); +} + +void QChangeArbiter::registerObserver(QObserverInterface *observer, + Component *component, + ChangeFlags changeFlags) +{ + qDebug() << Q_FUNC_INFO; + if (!observer || !component) + return; + + // Store info about which observers are watching which observables. + // Protect access as this could be called from any thread + QMutexLocker locker(&m_mutex); + QObserverList &observers = m_componentObservations[component]; + observers.append(observer); + + // TODO: Also store info about types of change observer is interested in so that we + // can reduce the amount of traffic + Q_UNUSED(changeFlags); + + // Register ourselves with the observable as the intermediary + component->registerChangeArbiter(this); +} + +void QChangeArbiter::unregisterObserver(QObserverInterface *observer, + QObservableInterface *subject) +{ + // TODO: Implement me! +} + +void QChangeArbiter::sceneChangeEvent(const QSceneChangePtr &e) +{ + //qDebug() << Q_FUNC_INFO << QThread::currentThread(); + + // Add the change to the thread local storage queue - no locking required => yay! + ChangeQueue *localChangeQueue = m_tlsChangeQueue.localData(); + localChangeQueue->append(e); + + //qDebug() << "Change queue for thread" << QThread::currentThread() << "now contains" << localChangeQueue->count() << "items"; +} + +void QChangeArbiter::sceneChangeEventWithLock(const QSceneChangePtr &e) +{ + QMutexLocker locker(&m_mutex); + sceneChangeEvent(e); +} + +void QChangeArbiter::createUnmanagedThreadLocalChangeQueue(void *changeArbiter) +{ + Q_CHECK_PTR(changeArbiter); + + QChangeArbiter *arbiter = static_cast<QChangeArbiter *>(changeArbiter); + + qDebug() << Q_FUNC_INFO << QThread::currentThread(); + if (!arbiter->m_tlsChangeQueue.hasLocalData()) { + ChangeQueue *localChangeQueue = new ChangeQueue; + arbiter->m_tlsChangeQueue.setLocalData(localChangeQueue); + + QMutexLocker locker(&(arbiter->m_mutex)); + arbiter->m_lockingChangeQueues.append(localChangeQueue); + } +} + +static void destroyUnmanagedThreadLocalChangeQueue(void *changeArbiter) +{ + // TODO: Implement me! +} + +void QChangeArbiter::createThreadLocalChangeQueue(void *changeArbiter) +{ + Q_CHECK_PTR(changeArbiter); + + QChangeArbiter *arbiter = static_cast<QChangeArbiter *>(changeArbiter); + + qDebug() << Q_FUNC_INFO << QThread::currentThread(); + if (!arbiter->m_tlsChangeQueue.hasLocalData()) { + ChangeQueue *localChangeQueue = new ChangeQueue; + arbiter->m_tlsChangeQueue.setLocalData(localChangeQueue); + + QMutexLocker locker(&(arbiter->m_mutex)); + arbiter->m_changeQueues.append(localChangeQueue); + } +} + +static void destroyThreadLocalChangeQueue(void *changeArbiter) +{ + // TODO: Implement me! +} + +} // namespace Qt3D diff --git a/src/core/qchangearbiter.h b/src/core/qchangearbiter.h new file mode 100644 index 000000000..73a0411f9 --- /dev/null +++ b/src/core/qchangearbiter.h @@ -0,0 +1,232 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3D_QCHANGEARBITER_H +#define QT3D_QCHANGEARBITER_H + +#include "qt3dcore_global.h" + +#include <QObject> +#include <QDebug> +#include <QFlags> +#include <QMutex> +#include <QReadWriteLock> +#include <QSharedPointer> +#include <QThreadStorage> +#include <QVariant> +#include <QVector> + +namespace Qt3D { + +class Component; + +enum ChangeFlag { + NodeCreated = 0x00000001, + NodeAboutToBeDeleted = 0x00000002, + NodeDeleted = 0x00000004, + NodeStatus = 0x00000008, + LocalTransform = 0x00000010, + MeshChange = 0x00000020, + MaterialParameter = 0x00000040, + CameraProjectionMatrix = 0x00000080, + AllChanges = 0xFFFFFFFF +}; +Q_DECLARE_FLAGS(ChangeFlags, ChangeFlag) +Q_DECLARE_OPERATORS_FOR_FLAGS(ChangeFlags) + + +class QObserverInterface; +class QObservableInterface; + +class QT3DCORESHARED_EXPORT QSceneChange +{ +public: + QSceneChange(ChangeFlag type, QObservableInterface *observable) + : m_type(type) + { + m_subject.m_observable = observable; + m_subjectType = ObservableType; + } + + QSceneChange(ChangeFlag type, Component *component) + : m_type(type) + { + m_subject.m_component = component; + m_subjectType = ComponentType; + } + + union { + QObservableInterface *m_observable; + Component *m_component; + } m_subject; + + enum ObservableType { + ObservableType, + ComponentType + } m_subjectType; + + ChangeFlag m_type; + + // TODO: add timestamp from central clock and priority level + // These can be used to resolve any conflicts between events + // posted from different aspects +}; + +typedef QSharedPointer<QSceneChange> QSceneChangePtr; + +class QT3DCORESHARED_EXPORT QScenePropertyChange : public QSceneChange +{ +public: + QScenePropertyChange(ChangeFlag type, QObservableInterface *subject) + : QSceneChange(type, subject) + { + } + + QScenePropertyChange(ChangeFlag type, Component *component) + : QSceneChange(type, component) + { + } + + QByteArray m_propertyName; + QVariant m_value; +}; + +typedef QSharedPointer<QScenePropertyChange> QScenePropertyChangePtr; + + +class QT3DCORESHARED_EXPORT QObservableInterface +{ +public: + virtual ~QObservableInterface() {} + + virtual void registerObserver(QObserverInterface *observer) = 0; + virtual void unregisterObserver(QObserverInterface *observer) = 0; + +protected: + virtual void notifyObservers(const QSceneChangePtr &e) = 0; +}; + + +class QT3DCORESHARED_EXPORT QObservable : public QObservableInterface +{ +public: + QObservable(); + + void registerObserver(QObserverInterface *observer) Q_DECL_OVERRIDE; + void unregisterObserver(QObserverInterface *observer) Q_DECL_OVERRIDE; + +protected: + void notifyObservers(const QSceneChangePtr &e) Q_DECL_OVERRIDE; + + const QList<QObserverInterface *> &observers() const { return m_observers; } + +private: + QList<QObserverInterface *> m_observers; + QReadWriteLock m_lock; +}; + + +class QObserverInterface +{ +public: + virtual ~QObserverInterface() {} + + virtual void sceneChangeEvent(const QSceneChangePtr &e) = 0; +}; + + +class QJobManagerInterface; + +class QT3DCORESHARED_EXPORT QChangeArbiter : public QObject, + public QObserverInterface +{ + Q_OBJECT +public: + explicit QChangeArbiter(QObject *parent = 0); + + void initialize(Qt3D::QJobManagerInterface *jobManager); + + void syncChanges(); + + void registerObserver(QObserverInterface *observer, + QObservableInterface *subject, + ChangeFlags changeFlags = AllChanges); + + void registerObserver(QObserverInterface *observer, + Component *component, + ChangeFlags changeFlags = AllChanges); + + void unregisterObserver(QObserverInterface *observer, + QObservableInterface *subject); + + void sceneChangeEvent(const QSceneChangePtr &e) Q_DECL_OVERRIDE; // QObserverInterface impl + void sceneChangeEventWithLock(const QSceneChangePtr &e); + + static void createUnmanagedThreadLocalChangeQueue(void *changeArbiter); + static void destroyUnmanagedThreadLocalChangeQueue(void *changeArbiter); + static void createThreadLocalChangeQueue(void *changeArbiter); + static void destroyThreadLocalChangeQueue(void *changeArbiter); + +private: + typedef QVector<QSceneChangePtr> ChangeQueue; + + void distributeQueueChanges(ChangeQueue *queue); + + QMutex m_mutex; + QJobManagerInterface *m_jobManager; + + typedef QList<QObserverInterface *> QObserverList; + QHash<QObservableInterface *, QObserverList> m_observations; + QHash<Component *, QObserverList> m_componentObservations; + + // Each thread has a TLS ChangeQueue so we never need to lock whilst + // receiving a QSceneChange. + QThreadStorage<ChangeQueue *> m_tlsChangeQueue; + + // We store a list of the ChangeQueue's from each thread. This will only + // be accesses from the aspect thread during the syncChanges() phase. + QList<ChangeQueue *> m_changeQueues; + QList<ChangeQueue *> m_lockingChangeQueues; +}; + +} // namespace Qt3D + +#endif // QT3D_QCHANGEARBITER_H diff --git a/src/core/qjob.cpp b/src/core/qjob.cpp new file mode 100644 index 000000000..73dfabfe2 --- /dev/null +++ b/src/core/qjob.cpp @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qjob.h" + +namespace Qt3D { + +QJob::QJob() +{ +} + +QJob::~QJob() +{ +} + +void QJob::addDependency(QWeakPointer<QJob> dependency) +{ + m_dependencies.append(dependency); +} + +} // namespace Qt3D diff --git a/src/core/qjob.h b/src/core/qjob.h new file mode 100644 index 000000000..c49907538 --- /dev/null +++ b/src/core/qjob.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3D_QJOB_H +#define QT3D_QJOB_H + +#include "qt3dcore_global.h" + +#include <QSharedPointer> +#include <QVector> + +namespace Qt3D { + +class QJob +{ +public: + QJob(); + virtual ~QJob(); + + void addDependency(QWeakPointer<QJob> dependency); + const QVector<QWeakPointer<QJob> > &dependencies() const { return m_dependencies; } + + virtual void run() = 0; + +private: + QVector<QWeakPointer<QJob> > m_dependencies; +}; + +typedef QSharedPointer<QJob> QJobPtr; + +} // namespace Qt3D + +#endif // QT3D_QJOB_H diff --git a/src/core/qjobmanagerinterface.h b/src/core/qjobmanagerinterface.h new file mode 100644 index 000000000..a003d1198 --- /dev/null +++ b/src/core/qjobmanagerinterface.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QJOBMANAGERINTERFACE_H +#define QJOBMANAGERINTERFACE_H + +#include <QObject> + +#include "qjob.h" + +namespace Qt3D { + +class QJobManagerInterface : public QObject +{ + Q_OBJECT +public: + explicit QJobManagerInterface(QObject *parent = 0) + : QObject(parent) + {} + + virtual void initialize() {} + virtual void enqueueJobs(const QVector<QJobPtr> &jobQueue) = 0; + virtual void waitForAllJobs() = 0; + + // Callback signature for running SynchronizedJobs + typedef void (*JobFunction)(void *); + virtual void waitForPerThreadFunction(JobFunction func, void *arg) = 0; +}; + +} // namespace Qt3D + +#endif // QJOBMANAGERINTERFACE_H diff --git a/src/core/qjobproviderinterface.h b/src/core/qjobproviderinterface.h new file mode 100644 index 000000000..891e44fff --- /dev/null +++ b/src/core/qjobproviderinterface.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3D_QJOBPROVIDERINTERFACE_H +#define QT3D_QJOBPROVIDERINTERFACE_H + +#include "qt3dcore_global.h" +#include "qjob.h" + +#include <QVector> + +namespace Qt3D { + +class QJobProviderInterface +{ +public: + virtual QVector<QJobPtr> jobsToExecute() = 0; +}; + +} + +#endif // QT3D_QJOBPROVIDERINTERFACE_H diff --git a/src/core/qscheduler.cpp b/src/core/qscheduler.cpp new file mode 100644 index 000000000..af175210c --- /dev/null +++ b/src/core/qscheduler.cpp @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qscheduler.h" + +#include "abstractaspect.h" +#include "qaspectmanager.h" +#include "qjobmanagerinterface.h" + +namespace Qt3D { + +QScheduler::QScheduler(QObject *parent) + : QObject(parent) +{ +} + +void QScheduler::setAspectManager(QAspectManager *aspectManager) +{ + m_aspectManager = aspectManager; +} + +QAspectManager *QScheduler::aspectManager() const +{ + return m_aspectManager; +} + +void QScheduler::update(qint64 time) +{ + // Get tasks for this frame from each aspect + const QList<AbstractAspect *> &aspects = m_aspectManager->aspects(); + QHash<AbstractAspect::AspectType, QVector<QJobPtr> > jobs; + Q_FOREACH (AbstractAspect *aspect, aspects) { + QVector<QJobPtr> aspectJobs = aspect->jobsToExecute(); + jobs.insert(aspect->aspectType(), aspectJobs); + } + + // TODO: Set up dependencies between jobs as needed + // For now just queue them up as they are with render tasks first + QVector<QJobPtr> jobQueue; + for (int i = AbstractAspect::AspectRenderer; i <= AbstractAspect::AspectOther; ++i) { + AbstractAspect::AspectType aspectType = static_cast<AbstractAspect::AspectType>(i); + if (jobs.contains(aspectType)) + jobQueue += jobs.value(aspectType); + } + + m_aspectManager->jobManager()->enqueueJobs(jobQueue); + + // Do any other work here that the aspect thread can usefully be doing + // whilst the threadpool works its way through the jobs + + m_aspectManager->jobManager()->waitForAllJobs(); +} + +} // namespace Qt3D diff --git a/src/core/qscheduler.h b/src/core/qscheduler.h new file mode 100644 index 000000000..24e86ec4a --- /dev/null +++ b/src/core/qscheduler.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3D_QSCHEDULER_H +#define QT3D_QSCHEDULER_H + +#include <QObject> +#include "qt3dcore_global.h" + +namespace Qt3D { + +class QAspectManager; + +class QScheduler : public QObject +{ + Q_OBJECT +public: + explicit QScheduler(QObject *parent = 0); + + void setAspectManager(QAspectManager *aspectManager); + QAspectManager *aspectManager() const; + + virtual void update(qint64 time); + +private: + QAspectManager *m_aspectManager; +}; + +} // namespace Qt3D + +#endif // QT3D_QSCHEDULER_H diff --git a/src/core/qt3dcore_global.h b/src/core/qt3dcore_global.h new file mode 100644 index 000000000..cb4d67321 --- /dev/null +++ b/src/core/qt3dcore_global.h @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DCORE_GLOBAL_H +#define QT3DCORE_GLOBAL_H + +#include <QtCore/qglobal.h> + +#if defined(QT3DCORE_LIBRARY) +# define QT3DCORESHARED_EXPORT Q_DECL_EXPORT +#else +# define QT3DCORESHARED_EXPORT Q_DECL_IMPORT +#endif + +#endif // QT3DCORE_GLOBAL_H diff --git a/src/core/qtickclock.cpp b/src/core/qtickclock.cpp new file mode 100644 index 000000000..fbb9f7d68 --- /dev/null +++ b/src/core/qtickclock.cpp @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtickclock.h" + +#include <QDebug> +#include <QThread> + +namespace Qt3D { + +QTickClock::QTickClock(QObject *parent) + : QObject(parent) + , m_tickInterval(1000000000 / 60) // Nanoseconds + , m_time(0) +{ +} + +void QTickClock::setTickFrequency(float frequency) +{ + Q_ASSERT(frequency > 0.0f); + m_tickInterval = static_cast<qint64>(1000000000 / frequency); +} + +void QTickClock::start() +{ + m_timer.start(); + m_time = m_timer.nsecsElapsed(); + qDebug() << "tickInterval =" << m_tickInterval << "ns"; +} + +void QTickClock::reset() +{ + m_time = 0; +} + +qint64 QTickClock::waitForNextTick() +{ + qint64 t = m_timer.nsecsElapsed(); + qint64 dt = t - m_time; + qint64 timeToSleep = m_tickInterval - dt; + + // If we are lagging behind don't delay + // TODO: Do we want a mode where if we are lagging we instead wait + // for the next tick instead? + if (timeToSleep < 0) { + qDebug() << "Lagging behind desired tick interval"; + m_time = t; + return m_time; + } + + unsigned long sleepTimeMicroSeconds = static_cast<unsigned long>(timeToSleep / 1000); + //qDebug() << "sleeping for" << sleepTimeMicroSeconds << "us"; + QThread::usleep(sleepTimeMicroSeconds); + +#if defined(QT3D_DEBUG_TICKCLOCK) + qint64 expectedWakeTime = t + sleepTimeMicroSeconds * 1000; + qint64 wakeTime = m_timer.nsecsElapsed(); + qDebug() << "t =" << t / 1000000 << "timeToSleep =" << timeToSleep / 1000000 + << "due to wake at =" << expectedWakeTime / 1000000 + << "actually woke at" << wakeTime / 1000000 + << "delta =" << (expectedWakeTime - wakeTime) / 1000000; +#endif + + m_time = m_timer.nsecsElapsed(); + return m_time; +} + +} diff --git a/src/core/qtickclock.h b/src/core/qtickclock.h new file mode 100644 index 000000000..a82cf3f01 --- /dev/null +++ b/src/core/qtickclock.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTICKCLOCK_H +#define QTICKCLOCK_H + +#include <QObject> +#include "qt3dcore_global.h" + +#include <QElapsedTimer> + +namespace Qt3D { + +class QTickClock : public QObject +{ + Q_OBJECT +public: + explicit QTickClock(QObject *parent = 0); + + void setTickFrequency(float frequency); + + void start(); + void reset(); + + qint64 waitForNextTick(); + +private: + QElapsedTimer m_timer; + qint64 m_tickInterval; + qint64 m_time; +}; + +} // namespace Qt3D + +#endif // QTICKCLOCK_H diff --git a/src/core/rotatetransform.cpp b/src/core/rotatetransform.cpp new file mode 100644 index 000000000..410e482fb --- /dev/null +++ b/src/core/rotatetransform.cpp @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#define _USE_MATH_DEFINES // For MSVC +#include "rotatetransform.h" + +#include <cmath> + +namespace Qt3D { + +RotateTransform::RotateTransform(Node *parent) + : AbstractTransform(parent) +{ +} + +float RotateTransform::angleDeg() const +{ + return m_angleDeg; +} + +float Qt3D::RotateTransform::angleRad() const +{ + return (m_angleDeg / 180.0) * M_PI; +} + +QVector3D RotateTransform::axis() const +{ + return m_axis; +} + +QMatrix4x4 RotateTransform::matrix() const +{ + QMatrix4x4 m; + m.rotate(m_angleDeg, m_axis); + return m; +} + +void RotateTransform::setAngleDeg(float arg) +{ + if (m_angleDeg != arg) { + m_angleDeg = arg; + emit angleChanged(); + } +} + +void RotateTransform::setAngleRad(float arg) +{ + float angleDeg = (arg * M_PI) / 180.0f; + setAngleDeg(angleDeg); +} + +void RotateTransform::setAxis(const QVector3D& arg) +{ + if (m_axis != arg) { + m_axis = arg; + emit axisChanged(); + } +} + +} // namespace Qt3D diff --git a/src/core/rotatetransform.h b/src/core/rotatetransform.h new file mode 100644 index 000000000..9921c82c4 --- /dev/null +++ b/src/core/rotatetransform.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3D_ROTATETRANSFORM_H +#define QT3D_ROTATETRANSFORM_H + +#include "abstracttransform.h" +#include "qt3dcore_global.h" + +#include <QVector3D> + +namespace Qt3D { + +class RotateTransform : public AbstractTransform +{ + Q_OBJECT + + Q_PROPERTY(float angle READ angleDeg WRITE setAngleDeg NOTIFY angleChanged) + Q_PROPERTY(float angleRad READ angleRad WRITE setAngleRad NOTIFY angleChanged) + + Q_PROPERTY(QVector3D axis READ axis WRITE setAxis NOTIFY axisChanged) + +public: + explicit RotateTransform(Node *parent = 0); + + float angleDeg() const; + + float angleRad() const; + + QVector3D axis() const; + + virtual QMatrix4x4 matrix() const; + +public slots: + void setAngleDeg(float arg); + + void setAngleRad(float arg); + + void setAxis(const QVector3D& arg); + +signals: + + void axisChanged(); + void angleChanged(); + +private: + float m_angleDeg; + QVector3D m_axis; +}; + +} // namespace Qt3D + +#endif // QT3D_ROTATETRANSFORM_H diff --git a/src/core/scene.cpp b/src/core/scene.cpp new file mode 100644 index 000000000..f8a1a15cc --- /dev/null +++ b/src/core/scene.cpp @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "scene.h" + +#include <QDebug> + +#include <gltfparser.h> + +namespace Qt3D +{ + +Scene::Scene(Node* parent) : + Entity(parent) +{ +} + +QString Scene::source() const +{ + return m_source; +} + +QString Scene::sceneId() const +{ + return m_sceneId; +} + +Scene *Scene::findInTree(Node *root) +{ + if (!root) + return NULL; + + Scene* s = qobject_cast<Scene*>(root); + if (s) + return s; + + // recursive walk down the tree + foreach (Node* nd, root->children()) { + s = findInTree(nd); + if (s) + return s; + } + + return NULL; +} + +void Scene::clear() +{ + removeAllChildren(); +} + +void Scene::setSource(QString arg) +{ + if (m_source != arg) { + m_source = arg; + rebuild(); + emit sourceChanged(arg); + } +} + +void Qt3D::Scene::setSceneId(QString arg) +{ + if (m_sceneId != arg) { + m_sceneId = arg; + rebuild(); + emit sceneIdChanged(arg); + } +} + +void Scene::rebuild() +{ + if (m_sceneChild) { + removeChild(m_sceneChild); + m_sceneChild->deleteLater(); + } + + if (GLTFParser::isGLTFPath(m_source)) { + qDebug() << Q_FUNC_INFO << "will load GLTF scene"; + + GLTFParser parser; + parser.setFilePath(m_source); + + if (!m_sceneId.isEmpty()) + m_sceneChild = parser.scene(m_sceneId); + else + m_sceneChild = parser.defaultScene(); + + if (m_sceneChild) { + addChild(m_sceneChild); + } + } else { + + } +} + +} // of namespace diff --git a/src/core/scene.h b/src/core/scene.h new file mode 100644 index 000000000..2fd67bb6c --- /dev/null +++ b/src/core/scene.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SCENE_H +#define SCENE_H + +#include "entity.h" +#include "qt3dcore_global.h" + +namespace Qt3D +{ + +class Scene : public Entity +{ + Q_OBJECT + + Q_PROPERTY(QString source READ source WRITE setSource NOTIFY sourceChanged) + Q_PROPERTY(QString sceneId READ sceneId WRITE setSceneId NOTIFY sceneIdChanged) +public: + explicit Scene(Node *parent = 0); + + QString source() const; + + QString sceneId() const; + + /** + * @brief findInTree - given a Node* object rooting a tree, find + * the top-most Scene entity within. + * @param root - the found Scene or NULL if no Scene was found + * @return + */ + static Scene* findInTree(Node* root); +signals: + + void sourceChanged(QString arg); + + void sceneIdChanged(QString arg); + +public slots: + void clear(); + + void setSource(QString arg); + + void setSceneId(QString arg); + +private: + void rebuild(); + + QString m_source; + QString m_sceneId; + + Node* m_sceneChild; + +}; + +} // of namespace + +#endif // SCENE_H diff --git a/src/core/sphere.cpp b/src/core/sphere.cpp new file mode 100644 index 000000000..3daf3804b --- /dev/null +++ b/src/core/sphere.cpp @@ -0,0 +1,175 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "sphere.h" + +#include <QPair> + +#include <math.h> + +namespace { + +inline QPair<int, int> findExtremePoints(const QVector<QVector3D> &points) +{ + // Find indices of extreme points along x, y, and z axes + int xMin = 0, xMax = 0, yMin = 0, yMax = 0, zMin = 0, zMax = 0; + for (int i = 1; i < points.size(); ++i) { + const QVector3D &p = points.at(i); + if (p.x() < points[xMin].x()) + xMin = i; + if (p.x() > points[xMax].x()) + xMax = i; + if (p.y() < points[yMin].y()) + yMin = i; + if (p.y() > points[yMax].y()) + yMax = i; + if (p.z() < points[zMin].z()) + zMin = i; + if (p.z() > points[zMax].z()) + zMax = i; + } + + // Calculate squared distance for the pairs of points + const float xDist2 = (points.at(xMax) - points.at(xMin)).lengthSquared(); + const float yDist2 = (points.at(yMax) - points.at(yMin)).lengthSquared(); + const float zDist2 = (points.at(zMax) - points.at(zMin)).lengthSquared(); + + // Select most distant pair + QPair<int, int> extremeIndices(xMin, xMax); + if (yDist2 > xDist2 && yDist2 > zDist2) + extremeIndices = qMakePair(yMin, yMax); + if (zDist2 > xDist2 && zDist2 > yDist2) + extremeIndices = qMakePair(zMin, zMax); + + return extremeIndices; +} + +inline void sphereFromExtremePoints(Qt3D::Sphere &s, const QVector<QVector3D> &points) +{ + // Find two most separated points on any of the basis vectors + QPair<int, int> extremeIndices = findExtremePoints(points); + + // Construct sphere to contain these two points + const QVector3D &p = points.at(extremeIndices.first); + const QVector3D &q = points.at(extremeIndices.second); + const QVector3D c = 0.5f * (p + q); + s.setCenter(c); + s.setRadius((q - c).length()); +} + +inline void constructRitterSphere(Qt3D::Sphere &s, const QVector<QVector3D> &points) +{ + // Calculate the sphere encompassing two axially extreme points + sphereFromExtremePoints(s, points); + + // Now make sure the sphere bounds all points by growing if needed + s.expandToContain(points); +} + +} // anonymous namespace + +namespace Qt3D { + +const float Sphere::ms_epsilon = 1.0e-7; + +Sphere Sphere::fromPoints(const QVector<QVector3D> &points) +{ + Sphere s; + s.initializeFromPoints(points); + return s; +} + +void Sphere::initializeFromPoints(const QVector<QVector3D> &points) +{ + constructRitterSphere(*this, points); +} + +void Sphere::expandToContain(const QVector3D &p) +{ + const QVector3D d = p - m_center; + const float dist2 = d.lengthSquared(); + + if (dist2 > m_radius * m_radius) { + // Expand radius so sphere also contains p + const float dist = sqrt(dist2); + const float newRadius = 0.5f * (m_radius + dist); + const float k = (newRadius - m_radius) / dist; + m_radius = newRadius; + m_center += k * d; + } +} + +void Sphere::expandToContain(const Sphere &sphere) +{ + const QVector3D d(sphere.m_center - m_center); + const float dist2 = d.lengthSquared(); + + const float dr = sphere.m_radius - m_radius; + if (dr * dr >= dist2) { + // Larger sphere encloses the smaller. Set our size to the larger + if (m_radius > sphere.m_radius) + return; + else + *this = sphere; + } else { + // The spheres are overlapping or disjoint + const float dist = sqrt(dist2); + const float newRadius = 0.5f * (dist + m_radius + sphere.m_radius); + if (dist > ms_epsilon) + m_center += d * (newRadius - m_radius) / dist; + } +} + +Sphere Sphere::transformed(const QMatrix4x4 &mat) +{ + // Transform extremities in x, y, and z directions to find extremities + // of the resulting ellipsoid + QVector3D x = mat.mapVector(m_center + QVector3D(m_radius, 0.0f, 0.0f)); + QVector3D y = mat.mapVector(m_center + QVector3D(0.0f, m_radius, 0.0f)); + QVector3D z = mat.mapVector(m_center + QVector3D(0.0f, 0.0f, m_radius)); + + // Transform center and find maximum radius of ellipsoid + QVector3D c = mat.mapVector(m_center); + float rSquared = qMax(qMax((x - c).lengthSquared(), (y - c).lengthSquared()), (z - c).lengthSquared()); + return Sphere(c, sqrt(rSquared)); +} + +} diff --git a/src/core/sphere.h b/src/core/sphere.h new file mode 100644 index 000000000..6a46fce04 --- /dev/null +++ b/src/core/sphere.h @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SPHERE_H +#define SPHERE_H + +#include "qt3dcore_global.h" + +#include <QMatrix4x4> +#include <QVector3D> + +namespace Qt3D { + +class QT3DCORESHARED_EXPORT Sphere +{ +public: + inline Sphere() + : m_center(), + m_radius(0.0f) + {} + + inline Sphere(const QVector3D &c, float r) + : m_center(c), + m_radius(r) + {} + + void setCenter(const QVector3D ¢er); + QVector3D center() const; + + void setRadius(float radius); + float radius() const; + + void clear(); + void initializeFromPoints(const QVector<QVector3D> &points); + void expandToContain(const QVector3D &point); + inline void expandToContain(const QVector<QVector3D> &points) + { + Q_FOREACH (const QVector3D &p, points) + expandToContain(p); + } + + void expandToContain(const Sphere &sphere); + + Sphere transformed(const QMatrix4x4 &mat); + inline Sphere &transform(const QMatrix4x4 &mat) + { + *this = transformed(mat); + return *this; + } + + static Sphere fromPoints(const QVector<QVector3D> &points); + +private: + QVector3D m_center; + float m_radius; + + static const float ms_epsilon; +}; + +inline void Sphere::setCenter(const QVector3D ¢er) +{ + m_center = center; +} + +inline QVector3D Sphere::center() const +{ + return m_center; +} + +inline void Sphere::setRadius(float radius) +{ + m_radius = radius; +} + +inline float Sphere::radius() const +{ + return m_radius; +} + +inline void Sphere::clear() +{ + m_center = QVector3D(); + m_radius = 0.0f; +} + +inline bool intersects(const Sphere &a, const Sphere &b) +{ + // Calculate squared distance between sphere centers + const QVector3D d = a.center() - b.center(); + const float distSq = QVector3D::dotProduct(d, d); + + // Spheres intersect if squared distance is less than squared + // sum of radii + const float sumRadii = a.radius() + b.radius(); + return distSq <= sumRadii * sumRadii; +} + +} + +#endif // SPHERE_H diff --git a/src/core/translatetransform.cpp b/src/core/translatetransform.cpp new file mode 100644 index 000000000..faf65ca9f --- /dev/null +++ b/src/core/translatetransform.cpp @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "translatetransform.h" + +namespace Qt3D { + +TranslateTransform::TranslateTransform(Node *parent) + : AbstractTransform(parent) +{ +} + +float TranslateTransform::dx() const +{ + return m_translation.x(); +} + +float TranslateTransform::dy() const +{ + return m_translation.y(); +} + +float TranslateTransform::dz() const +{ + return m_translation.z(); +} + +QVector3D TranslateTransform::translation() const +{ + return m_translation; +} + +QMatrix4x4 TranslateTransform::matrix() const +{ + QMatrix4x4 r; + r.translate(m_translation); + return r; +} + +void TranslateTransform::setDx(float arg) +{ + if (arg != m_translation.x()) { + m_translation.setX(arg); + emit translateChanged(); + } +} + +void TranslateTransform::setDy(float arg) +{ + if (arg != m_translation.y()) { + m_translation.setY(arg); + emit translateChanged(); + } +} + +void TranslateTransform::setDz(float arg) +{ + if (arg != m_translation.z()) { + m_translation.setZ(arg); + emit translateChanged(); + } +} + +void TranslateTransform::setTranslation(QVector3D arg) +{ + if (m_translation != arg) { + m_translation = arg; + emit translateChanged(); + } +} + +} // namespace Qt3D diff --git a/src/core/translatetransform.h b/src/core/translatetransform.h new file mode 100644 index 000000000..9dd1fb7cb --- /dev/null +++ b/src/core/translatetransform.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3D_TRANSLATETRANSFORM_H +#define QT3D_TRANSLATETRANSFORM_H + +#include "abstracttransform.h" +#include "qt3dcore_global.h" + +#include <QVector3D> + +namespace Qt3D { + +class TranslateTransform : public AbstractTransform +{ + Q_OBJECT + + Q_PROPERTY(float dx READ dx WRITE setDx NOTIFY translateChanged) + Q_PROPERTY(float dy READ dy WRITE setDy NOTIFY translateChanged) + Q_PROPERTY(float dz READ dz WRITE setDz NOTIFY translateChanged) + Q_PROPERTY(QVector3D t READ translation WRITE setTranslation NOTIFY translateChanged) + +public: + explicit TranslateTransform(Node *parent = 0); + + float dx() const; + float dy() const; + float dz() const; + + QVector3D translation() const; + + virtual QMatrix4x4 matrix() const; + +public slots: + void setDx(float arg); + void setDy(float arg); + void setDz(float arg); + + void setTranslation(QVector3D arg); + +signals: + void translateChanged(); + +private: + QVector3D m_translation; +}; + +} // namespace Qt3D + +#endif // QT3D_TRANSLATETRANSFORM_H diff --git a/src/core/window.cpp b/src/core/window.cpp new file mode 100644 index 000000000..7aee2b7cb --- /dev/null +++ b/src/core/window.cpp @@ -0,0 +1,249 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "window.h" + +#include <QDebug> +#include <QQmlComponent> +#include <QTimer> +#include <QKeyEvent> +#include <QMouseEvent> +#include <QGuiApplication> + +#include "node.h" +#include "camera.h" +#include "entity.h" +#include <qaspectengine.h> + +#include "cameracontroller.h" + +namespace Qt3D { + +Window::Window(QScreen *screen) + : QWindow(screen) + , m_engine(new QQmlEngine) + , m_aspectEngine(new QAspectEngine(this)) + , m_camera(NULL) + , m_controller(NULL) + +{ + setSurfaceType(QSurface::OpenGLSurface); + + resize(1024, 768); + + QSurfaceFormat format; + format.setVersion(4, 3); + format.setDepthBufferSize( 24 ); + format.setProfile(QSurfaceFormat::CoreProfile); + setFormat(format); + + m_aspectEngine->initialize(); + m_aspectEngine->setWindow(this); + + m_controller = new CameraController; + + m_updateTimer = new QTimer(this); + m_updateTimer->setInterval(16); + connect(m_updateTimer, SIGNAL(timeout()), this, SLOT(onUpdate())); +} + +Window::~Window() +{ + m_aspectEngine->shutdown(); + delete m_aspectEngine; +} + +Window::Status Window::status() const +{ + if (!m_engine) + return Error; + + if (!m_component) + return Null; + + return Status(m_component->status()); +} + +void Window::setSource( const QUrl& source ) +{ + if (!m_engine) { + qWarning() << "Window: invalid qml engine."; + return; + } + + if (m_root) { + m_aspectEngine->shutdown(); + m_aspectEngine->setRoot(0); + m_root = QSharedPointer<QObject>(); + } + + if (m_component) + m_component = QSharedPointer<QQmlComponent>(); + + if (!source.isEmpty()) { + m_component = QSharedPointer<QQmlComponent>(new QQmlComponent(m_engine.data(), source, this)); + if (!m_component->isLoading()) { + continueExecute(); + } else { + QObject::connect(m_component.data(), SIGNAL(statusChanged(QQmlComponent::Status)), + this, SLOT(continueExecute())); + } + } +} + +void Window::continueExecute() +{ + qDebug() << Q_FUNC_INFO; + + disconnect(m_component.data(), SIGNAL(statusChanged(QQmlComponent::Status)), + this, SLOT(continueExecute())); + + if (m_component->isError()) { + QList<QQmlError> errorList = m_component->errors(); + Q_FOREACH ( const QQmlError& error, errorList ) { + QMessageLogger(error.url().toString().toLatin1().constData(), error.line(), 0).warning() + << error; + } + emit statusChanged(status()); + return; + } + + QObject* obj = m_component->create(); + + if (m_component->isError()) { + QList<QQmlError> errorList = m_component->errors(); + Q_FOREACH ( const QQmlError& error, errorList ) { + QMessageLogger(error.url().toString().toLatin1().constData(), error.line(), 0).warning() + << error; + } + emit statusChanged(status()); + return; + } + + setRootObject(obj); + emit statusChanged(status()); +} + +void Window::onUpdate() +{ + m_controller->update(1.0 / 60.0); +} + +void Window::setRootObject( QObject* obj ) +{ + if (m_root == obj) + return; + + if (obj) { + obj->setParent( this ); + m_root = QSharedPointer<QObject>(obj); + } + + m_aspectEngine->setRoot(obj); + + // Hook up controller input to camera + // TODO: Do this more generically as we may want keyboard ot control an Entity etc + m_camera = Entity::findComponentInTree<Camera>(qobject_cast<Node *>(m_root.data())); + if (m_camera) { + qDebug() << "found a camera in the scene"; + m_controller->setCamera(m_camera); + m_updateTimer->start(); + } + +// +// Entity *ball = node->findChild<Entity *>(QStringLiteral("ball")); +// if (ball) { +// QList<Component *> components = ball->components(); +// qDebug() << components; +// } + + //Node *node = qobject_cast<Node *>(m_root.data()); + //if (node) + //node->dump(); +} + +void Window::resizeEvent( QResizeEvent* e ) +{ + Q_UNUSED( e ); + +} + +void Window::keyPressEvent( QKeyEvent* e ) +{ + if (m_controller->keyPressEvent(e)) + return; + + switch ( e->key() ) + { + case Qt::Key_Escape: + QGuiApplication::quit(); + break; + + default: + QWindow::keyPressEvent( e ); + } +} + +void Window::keyReleaseEvent( QKeyEvent* e ) +{ + if (m_controller->keyReleaseEvent(e)) + return; + + QWindow::keyReleaseEvent(e); +} + +void Window::mousePressEvent( QMouseEvent* e ) +{ + m_controller->mousePressEvent(e); +} + +void Window::mouseReleaseEvent( QMouseEvent* e ) +{ + m_controller->mouseReleaseEvent(e); +} + +void Window::mouseMoveEvent( QMouseEvent* e ) +{ + m_controller->mouseMoveEvent(e); +} + + +} // namespace Qt3D diff --git a/src/core/window.h b/src/core/window.h new file mode 100644 index 000000000..7ded46973 --- /dev/null +++ b/src/core/window.h @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3D_WINDOW_H +#define QT3D_WINDOW_H + +#include <QWindow> +#include "qt3dcore_global.h" + +#include <QQmlEngine> + +class QTimer; + +namespace Qt3D { + +class AbstractAspect; +class QAspectEngine; +class Camera; + +// temporary solution to get control over camera +class CameraController; + +class Window : public QWindow +{ + Q_OBJECT +public: + explicit Window(QScreen *screen = 0); + ~Window(); + + void setSource( const QUrl& url ); + + enum Status { Null, Ready, Loading, Error }; + Status status() const; + + QSharedPointer<QObject> rootObject() { return m_root; } + +signals: + void statusChanged( Qt3D::Window::Status ); + +protected: + virtual void keyPressEvent(QKeyEvent *e); + virtual void keyReleaseEvent( QKeyEvent* e ); + + virtual void mousePressEvent( QMouseEvent* e ); + virtual void mouseReleaseEvent( QMouseEvent* e ); + virtual void mouseMoveEvent( QMouseEvent* e ); + virtual void resizeEvent(QResizeEvent *e); + +private slots: + void continueExecute(); + + void onUpdate(); + +private: + void setRootObject( QObject* obj ); + + QScopedPointer<QQmlEngine> m_engine; + QSharedPointer<QObject> m_root; + QSharedPointer<QQmlComponent> m_component; + + // The various aspects (subsystems) that will be interested in (parts) + // of the objects in the object tree. + QAspectEngine *m_aspectEngine; + + QList<Qt3D::AbstractAspect*> m_aspects; + + Camera* m_camera; + + // temporary, borrowed from training material + CameraController* m_controller; + + QTimer* m_updateTimer; +}; + +} // namespace Qt3D + +#endif // QT3D_WINDOW_H diff --git a/src/render/backend/drawable.cpp b/src/render/backend/drawable.cpp new file mode 100644 index 000000000..4690a6b78 --- /dev/null +++ b/src/render/backend/drawable.cpp @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "drawable.h" + +namespace Qt3D { + +Drawable::Drawable() +{ + +} + +Drawable::~Drawable() +{ + +} + +DrawStateSet *Drawable::stateSet() +{ + return NULL; +} + +void Drawable::initializeGL(QGraphicsContext* dc) +{ + Q_UNUSED(dc); +} + +void Drawable::releaseGL() +{ + +} + +#if 0 +RenderNode *Drawable::node() const +{ + return m_node; +} +#endif + +} // of namespace + diff --git a/src/render/backend/drawable.h b/src/render/backend/drawable.h new file mode 100644 index 000000000..980891b91 --- /dev/null +++ b/src/render/backend/drawable.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3D_DRAWABLE_H +#define QT3D_DRAWABLE_H + +#include <QObject> + +#include <axisalignedboundingbox.h> + +namespace Qt3D { + +class QGraphicsContext; +class RenderShader; +class DrawStateSet; + +class Drawable +{ +public: + Drawable(); + + virtual ~Drawable(); + + // RenderNode* node() const; + + /** + * @brief make OpenGL drawing commands for this drawable. + * + * The correct context and shader will already be defined, + * along with the transformation state. This method will + * be run from the rendering thread, and hence should take + * care if using mutable buffer data. + * + */ + virtual void sendDrawingCommands( QGraphicsContext* gc ) = 0; + + /** + * @brief shader + * @return + */ + virtual RenderShader* shader() = 0; + + + virtual DrawStateSet* stateSet(); + + /** + * @brief Called by render thread to initialize resources + * + * This will be called in the context of the renderer thread + * once it has a fully created OpenGL context. The shader program for + * this drawable will be active (so attribute data can be bound) + */ + virtual void initializeGL(QGraphicsContext* dc); + + virtual void releaseGL(); + + virtual AxisAlignedBoundingBox boundingBox() const = 0; + +protected: + +}; + +} + +#endif // of QT3D_DRAWABLE_H diff --git a/src/render/backend/drawstate.cpp b/src/render/backend/drawstate.cpp new file mode 100644 index 000000000..08b87f961 --- /dev/null +++ b/src/render/backend/drawstate.cpp @@ -0,0 +1,182 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "drawstate.h" + +#include <bitset> + +#include <QDebug> +#include <QOpenGLContext> + +#include "qgraphicscontext.h" + +#include "states/blendstate.h" + +namespace Qt3D { + +DrawStateSet::DrawStateSet() +{ + +} + +void DrawStateSet::addState(DrawState *ds) +{ + Q_ASSERT(ds); + m_states.insert(ds); + m_stateMask |= ds->mask(); +} + +int DrawStateSet::changeCost(DrawStateSet *previousState) +{ + if (previousState == this) + return 0; + + int cost = 0; + +// first, find cost of any resets + StateMaskSet invOurState = ~stateMask(); + StateMaskSet stateToReset = previousState->stateMask() & invOurState; + + std::bitset<64> bs(stateToReset); + cost += bs.count(); + +// now, find out how many states we're changing + foreach (DrawState* ds, m_states) { + // if the other state contains matching, then doesn't + // contribute to cost at all + if (previousState->contains(ds)) { + continue; + } + + // flat cost for now; could be replaced with a cost() method on + // DrawState + cost += 2; + } + + return cost; +} + +void DrawStateSet::apply(QGraphicsContext *gc) +{ + DrawStateSet* previousStates = gc->currentStateSet(); + + StateMaskSet invOurState = ~stateMask(); + // generate a mask for each set bit in previous, where we do not have + // the corresponding bit set. + StateMaskSet stateToReset = 0; + if (previousStates) + stateToReset = previousStates->stateMask() & invOurState; + + resetMasked(stateToReset, gc); + + if (previousStates == m_cachedPrevious) { + // state-change cache hit + foreach (DrawState* ds, m_cachedDeltaStates) { + ds->apply(gc); + } + } else { + // compute deltas and cache for next frame + m_cachedDeltaStates.clear(); + m_cachedPrevious = previousStates; + + foreach (DrawState* ds, m_states) { + if (previousStates && previousStates->contains(ds)) { + continue; + } + + m_cachedDeltaStates.append(ds); + ds->apply(gc); + } + } +} + +StateMaskSet DrawStateSet::stateMask() const +{ + return m_stateMask; +} + +void DrawStateSet::resetMasked(StateMaskSet maskOfStatesToReset, QGraphicsContext *gc) +{ + Q_UNUSED(gc); + + if (maskOfStatesToReset & ScissorStateMask) { + glDisable(GL_SCISSOR_TEST); + } + + if (maskOfStatesToReset & BlendStateMask) { + glDisable(GL_BLEND); + } + + if (maskOfStatesToReset & StencilWriteStateMask) { + glStencilMask(0); + } + + if (maskOfStatesToReset & StencilTestStateMask) { + glDisable(GL_STENCIL_TEST); + } + + if (maskOfStatesToReset & DepthTestStateMask) { + glDisable(GL_DEPTH_TEST); + } + + if (maskOfStatesToReset & DepthWriteStateMask) { + glDepthMask(GL_TRUE); // reset to default + } + + if (maskOfStatesToReset & FrontFaceStateMask) { + glFrontFace(GL_CCW); // reset to default + } + + if (maskOfStatesToReset & CullFaceStateMask) { + glDisable(GL_CULL_FACE); + } +} + +bool DrawStateSet::contains(DrawState *ds) const +{ + // trivial reject using the state mask bits + if (!(ds->mask() & stateMask())) + return false; + + return m_states.contains(ds); +} + +} // namespace Qt3D diff --git a/src/render/backend/drawstate.h b/src/render/backend/drawstate.h new file mode 100644 index 000000000..bd7bc26ca --- /dev/null +++ b/src/render/backend/drawstate.h @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3D_DRAWSTATE_H +#define QT3D_DRAWSTATE_H + +#include <QList> +#include <QSet> + +namespace Qt3D { + +class QGraphicsContext; + +enum StateMask +{ + BlendStateMask = 1 << 0, + StencilWriteStateMask = 1 << 1, + StencilTestStateMask = 1 << 2, + ScissorStateMask = 1 << 3, + DepthTestStateMask = 1 << 4, + DepthWriteStateMask = 1 << 5, + CullFaceStateMask = 1 << 6, + AlphaTestMask = 1 << 7, + FrontFaceStateMask = 1 << 8 +}; + +typedef quint64 StateMaskSet; + +// winuser.h has a #define called DrawState. Let's get rid of it +#if defined(DrawState) +#undef DrawState +#endif + +class DrawState +{ +public: + virtual void apply(QGraphicsContext* gc) const = 0; + + virtual StateMaskSet mask() const = 0; + +protected: +}; + +class DrawStateSet +{ +public: + DrawStateSet(); + + void addState(DrawState* ds); + + /** + * @brief changeCost - metric of cost to change to this state-set from + * a candidate previous state-set. This is used to find an optimal + * ordering of state-sets when sending draw commands. + * @param previousState + * @return + */ + int changeCost(DrawStateSet* previousState); + + void apply(QGraphicsContext* gc); + + StateMaskSet stateMask() const; + + void resetMasked(StateMaskSet maskOfStatesToReset, QGraphicsContext* gc); +private: + /** + * @brief contains - check if this set contains a matching piece of state + * @param ds + * @return + */ + bool contains(DrawState* ds) const; + + QSet<DrawState*> m_states; + + StateMaskSet m_stateMask; + + DrawStateSet* m_cachedPrevious; + QList<DrawState*> m_cachedDeltaStates; +}; + +} // namespace Qt3D + +#endif // QT3D_DRAWSTATE_H diff --git a/src/render/backend/framegraph/cameraselectornode.cpp b/src/render/backend/framegraph/cameraselectornode.cpp new file mode 100644 index 000000000..d1d1bfac0 --- /dev/null +++ b/src/render/backend/framegraph/cameraselectornode.cpp @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "cameraselectornode.h" + +#include <QDebug> + +namespace Qt3D { +namespace Render { + +CameraSelector::CameraSelector(FrameGraphNode *parent) + : FrameGraphNode(parent) +{ +} + +void CameraSelector::apply() +{ + qDebug() << Q_FUNC_INFO; +} + +void CameraSelector::revert() +{ + qDebug() << Q_FUNC_INFO; +} + +} +} diff --git a/src/render/backend/framegraph/cameraselectornode.h b/src/render/backend/framegraph/cameraselectornode.h new file mode 100644 index 000000000..326ba600b --- /dev/null +++ b/src/render/backend/framegraph/cameraselectornode.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CAMERASELECTOR_H +#define CAMERASELECTOR_H + +#include "framegraphnode.h" + +namespace Qt3D { + +class Camera; + +namespace Render { + +class CameraSelector : public FrameGraphNode +{ +public: + CameraSelector(FrameGraphNode *parent = 0); + + void apply() Q_DECL_OVERRIDE; + void revert() Q_DECL_OVERRIDE; + +//private: + Camera *m_camera; +}; + +} +} + +#endif // CAMERASELECTOR_H diff --git a/src/render/backend/framegraph/framegraph.pri b/src/render/backend/framegraph/framegraph.pri new file mode 100644 index 000000000..c04191dc5 --- /dev/null +++ b/src/render/backend/framegraph/framegraph.pri @@ -0,0 +1,15 @@ +HEADERS += \ + $$PWD/cameraselectornode.h \ + $$PWD/framegraphnode.h \ + $$PWD/framegraphvisitor.h \ + $$PWD/renderpassfilternode.h \ + $$PWD/techniquefilternode.h \ + $$PWD/viewportnode.h + +SOURCES += \ + $$PWD/cameraselectornode.cpp \ + $$PWD/framegraphnode.cpp \ + $$PWD/framegraphvisitor.cpp \ + $$PWD/renderpassfilternode.cpp \ + $$PWD/techniquefilternode.cpp \ + $$PWD/viewportnode.cpp diff --git a/src/render/backend/framegraph/framegraphnode.cpp b/src/render/backend/framegraph/framegraphnode.cpp new file mode 100644 index 000000000..b6b80afce --- /dev/null +++ b/src/render/backend/framegraph/framegraphnode.cpp @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "framegraphnode.h" + +#include <QDebug> + +namespace Qt3D { +namespace Render { + +FrameGraphNode::FrameGraphNode(FrameGraphNode *parent) + : m_parent(parent) + , m_enabled(true) +{ + if (parent) + parent->m_children.append(this); +} + +FrameGraphNode::~FrameGraphNode() +{ +} + +void FrameGraphNode::apply() +{ + qDebug() << Q_FUNC_INFO; +} + +void FrameGraphNode::revert() +{ + qDebug() << Q_FUNC_INFO; +} + +} // namespace Render +} // namespace Qt3D diff --git a/src/render/backend/framegraph/framegraphnode.h b/src/render/backend/framegraph/framegraphnode.h new file mode 100644 index 000000000..0fd0a2e3f --- /dev/null +++ b/src/render/backend/framegraph/framegraphnode.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3D_RENDER_FRAMEGRAPHNODE_H +#define QT3D_RENDER_FRAMEGRAPHNODE_H + +#include <QVector> + +namespace Qt3D { +namespace Render { + +class FrameGraphNode +{ +public: + FrameGraphNode(FrameGraphNode *parent = 0); + virtual ~FrameGraphNode(); + + FrameGraphNode *parent() const { return m_parent; } + + int childCount() const { return m_children.count(); } + FrameGraphNode * child(int index) const { return m_children.at(index); } + + void setEnabled(bool enabled) { m_enabled = enabled; } + bool isEnabled() const { return m_enabled; } + +protected: + virtual void apply(); + virtual void revert(); + +private: + FrameGraphNode *m_parent; + QVector<FrameGraphNode *> m_children; + + bool m_enabled; + + friend class FrameGraphVisitor; +}; + +} // namespace Render +} // namespace Qt3D + +#endif // QT3D_RENDER_FRAMEGRAPHNODE_H diff --git a/src/render/backend/framegraph/framegraphvisitor.cpp b/src/render/backend/framegraph/framegraphvisitor.cpp new file mode 100644 index 000000000..b74a77873 --- /dev/null +++ b/src/render/backend/framegraph/framegraphvisitor.cpp @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "framegraphvisitor.h" + +#include "framegraphnode.h" +#include "renderer.h" + +namespace Qt3D { +namespace Render { + +FrameGraphVisitor::FrameGraphVisitor() +{ +} + +void FrameGraphVisitor::traverse(FrameGraphNode *root, Renderer *renderer) +{ + m_renderer = renderer; + + // Kick off the traversal + FrameGraphNode *node = root; + visit(node); +} + +void FrameGraphVisitor::visit(FrameGraphNode *node) +{ + // Apply the state from this node + node->apply(); + + // Recurse to children (if we have any), otherwise if this is a leaf node, + // initiate a rendering from the current camera + if (node->childCount()) { + for (int i = 0; i < node->childCount(); ++i) { + FrameGraphNode *n = node->child(i); + visit(n); + } + } else { + // Leaf node. All state is applied and renderer context configured. + // Go render something + m_renderer->doRender(); + } + + // Undo the applied state as we exit this node + node->revert(); +} + +} // namespace Render +} // namespace Qt3D diff --git a/src/render/backend/framegraph/framegraphvisitor.h b/src/render/backend/framegraph/framegraphvisitor.h new file mode 100644 index 000000000..174a90bdf --- /dev/null +++ b/src/render/backend/framegraph/framegraphvisitor.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3D_RENDERER_FRAMEGRAPHVISITOR_H +#define QT3D_RENDERER_FRAMEGRAPHVISITOR_H + +namespace Qt3D { +namespace Render { + +class FrameGraphNode; +class Renderer; + +class FrameGraphVisitor +{ +public: + FrameGraphVisitor(); + + void traverse(FrameGraphNode *root, Renderer *renderer); + +private: + void visit(FrameGraphNode *node); + + Renderer *m_renderer; +}; + +} // namespace Render +} // namespace Qt3D + +#endif // QT3D_RENDERER_FRAMEGRAPHVISITOR_H diff --git a/src/render/backend/framegraph/renderpassfilternode.cpp b/src/render/backend/framegraph/renderpassfilternode.cpp new file mode 100644 index 000000000..89b3d4e0c --- /dev/null +++ b/src/render/backend/framegraph/renderpassfilternode.cpp @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "renderpassfilternode.h" + +#include <QDebug> + +namespace Qt3D { +namespace Render { + +RenderPassFilter::RenderPassFilter(FrameGraphNode *parent) + : FrameGraphNode(parent) +{ +} + +void RenderPassFilter::apply() +{ + qDebug() << Q_FUNC_INFO; +} + +void RenderPassFilter::revert() +{ + qDebug() << Q_FUNC_INFO; +} + +} +} diff --git a/src/render/backend/framegraph/renderpassfilternode.h b/src/render/backend/framegraph/renderpassfilternode.h new file mode 100644 index 000000000..ed05e6b5c --- /dev/null +++ b/src/render/backend/framegraph/renderpassfilternode.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef RENDERPASSFILTER_H +#define RENDERPASSFILTER_H + +#include "framegraphnode.h" + +#include <QStringList> + +namespace Qt3D { +namespace Render { + +class RenderPassFilter : public FrameGraphNode +{ +public: + RenderPassFilter(FrameGraphNode *parent = 0); + + void apply() Q_DECL_OVERRIDE; + void revert() Q_DECL_OVERRIDE; + +//private: + QStringList m_filters; +}; + +} + +} + +#endif // RENDERPASSFILTER_H diff --git a/src/render/backend/framegraph/techniquefilternode.cpp b/src/render/backend/framegraph/techniquefilternode.cpp new file mode 100644 index 000000000..3c021c77c --- /dev/null +++ b/src/render/backend/framegraph/techniquefilternode.cpp @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "techniquefilternode.h" + +#include <QDebug> + +namespace Qt3D { +namespace Render { + +TechniqueFilter::TechniqueFilter(FrameGraphNode *parent) + : FrameGraphNode(parent) +{ +} + +void TechniqueFilter::apply() +{ + qDebug() << Q_FUNC_INFO; +} + +void TechniqueFilter::revert() +{ + qDebug() << Q_FUNC_INFO; +} + +} +} diff --git a/src/render/backend/framegraph/techniquefilternode.h b/src/render/backend/framegraph/techniquefilternode.h new file mode 100644 index 000000000..f6c801019 --- /dev/null +++ b/src/render/backend/framegraph/techniquefilternode.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TECHNIQUEFILTER_H +#define TECHNIQUEFILTER_H + +#include "framegraphnode.h" + +#include <QHash> +#include <QString> +#include <QVariant> + +namespace Qt3D { +namespace Render { + +class TechniqueFilter : public FrameGraphNode +{ +public: + TechniqueFilter(FrameGraphNode *parent = 0); + + void apply() Q_DECL_OVERRIDE; + void revert() Q_DECL_OVERRIDE; + +//private: + QHash<QString, QVariant> m_filters; +}; + +} +} + +#endif // TECHNIQUEFILTER_H diff --git a/src/render/backend/framegraph/viewportnode.cpp b/src/render/backend/framegraph/viewportnode.cpp new file mode 100644 index 000000000..bac967975 --- /dev/null +++ b/src/render/backend/framegraph/viewportnode.cpp @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "viewportnode.h" + +#include <QDebug> + +namespace Qt3D { +namespace Render { + +ViewportNode::ViewportNode(FrameGraphNode *parent) + : FrameGraphNode(parent) + , m_xMin(0.0f) + , m_yMin(0.0f) + , m_xMax(1.0f) + , m_yMax(1.0f) +{ +} + +void ViewportNode::apply() +{ + qDebug() << Q_FUNC_INFO; +} + +void ViewportNode::revert() +{ + qDebug() << Q_FUNC_INFO; +} + +} +} diff --git a/src/render/backend/framegraph/viewportnode.h b/src/render/backend/framegraph/viewportnode.h new file mode 100644 index 000000000..6d1b643a5 --- /dev/null +++ b/src/render/backend/framegraph/viewportnode.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef VIEWPORT_H +#define VIEWPORT_H + +#include "framegraphnode.h" + +namespace Qt3D { +namespace Render { + +class ViewportNode : public FrameGraphNode +{ +public: + ViewportNode(FrameGraphNode *parent = 0); + + void apply() Q_DECL_OVERRIDE; + void revert() Q_DECL_OVERRIDE; + +//private: + float m_xMin; + float m_yMin; + float m_xMax; + float m_yMax; +}; + +} +} + +#endif // VIEWPORT_H diff --git a/src/render/backend/genericstate.h b/src/render/backend/genericstate.h new file mode 100644 index 000000000..c95a6af4d --- /dev/null +++ b/src/render/backend/genericstate.h @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef STATE_IMPLS_H +#define STATE_IMPLS_H + +#include <QList> + +#include "drawstate.h" + +// winuser.h has a #define called DrawState. Let's get rid of it +#if defined(DrawState) +#undef DrawState +#endif + +namespace Qt3D +{ + +template <typename Derived, typename T> +class GenericState1 : public DrawState +{ +public: + + bool isEqual(const Derived& i) const + { return (m_1 == i.m_1); } + + +protected: + GenericState1(T t) : + m_1(t) + {} + + T m_1; + +}; + +template <typename Derived, typename T, typename S> +class GenericState2 : public DrawState +{ +public: + bool isEqual(const Derived& i) const + { return (m_1 == i.m_1) && (m_2 == i.m_2); } +protected: + GenericState2(T t, S s) : + m_1(t), + m_2(s) + {} + + + T m_1; + S m_2; +}; + +template <typename Derived, typename T, typename S, typename U> +class GenericState3 +{ +public: + bool isEqual(const Derived& i) const + { return (m_1 == i.m_1) && (m_2 == i.m_2) && (m_3 == i.m_3); } + +protected: + GenericState3(T t, S s, U u) : + m_1(t), + m_2(s), + m_3(u) + {} + + T m_1; + S m_2; + U m_3; + +}; + +} // of namespace + +#endif // STATE_IMPLS_H diff --git a/src/render/backend/jobs/jobs.pri b/src/render/backend/jobs/jobs.pri new file mode 100644 index 000000000..85e350fdd --- /dev/null +++ b/src/render/backend/jobs/jobs.pri @@ -0,0 +1,11 @@ +INCLUDEPATH += $$PWD + +HEADERS += \ + $$PWD/updateworldtransformjob.h \ + $$PWD/updateboundingvolumejob.h \ + $$PWD/loadmeshdatajob.h + +SOURCES += \ + $$PWD/updateworldtransformjob.cpp \ + $$PWD/updateboundingvolumejob.cpp \ + $$PWD/loadmeshdatajob.cpp
\ No newline at end of file diff --git a/src/render/backend/jobs/loadmeshdatajob.cpp b/src/render/backend/jobs/loadmeshdatajob.cpp new file mode 100644 index 000000000..29a6047c7 --- /dev/null +++ b/src/render/backend/jobs/loadmeshdatajob.cpp @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "loadmeshdatajob.h" + +#include <objloader.h> +#include <sphere.h> + +#include <QDebug> +#include <QThread> + +namespace Qt3D { +namespace Render { + +LoadMeshDataJob::LoadMeshDataJob(const QString &source, const MeshDataPtr &meshData) + : QJob() + , m_source(source) + , m_meshData(meshData) +{ +} + +void LoadMeshDataJob::run() +{ + qDebug() << "Entering" << Q_FUNC_INFO << QThread::currentThread(); + + // Load the mesh from disk (or wherever) + qDebug() << "Loading mesh from" << m_source; + + ObjLoader loader; + loader.setLoadTextureCoordinatesEnabled(true); + + if (loader.load(m_source)) { + qDebug() << "Loaded OBJ ok"; + *m_meshData = *(loader.mesh()); + } else { + qWarning() << Q_FUNC_INFO << "OBJ load failure for:" << m_source; + } + + AttributePtr attr = m_meshData->attributeByName("position"); + if (!attr) { + qWarning() << Q_FUNC_INFO << "unknown attribute: position"; + return; + } + + Qt3D::Sphere sphere = Qt3D::Sphere::fromPoints(loader.vertices()); + + qDebug() << "Exiting" << Q_FUNC_INFO << QThread::currentThread(); +} + +} // namespace Render +} // namespace Qt3D diff --git a/src/render/backend/jobs/loadmeshdatajob.h b/src/render/backend/jobs/loadmeshdatajob.h new file mode 100644 index 000000000..e9f155e35 --- /dev/null +++ b/src/render/backend/jobs/loadmeshdatajob.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3D_RENDER_LOADMESHDATAJOB_H +#define QT3D_RENDER_LOADMESHDATAJOB_H + +#include <qjob.h> + +#include <meshdata.h> + +#include <QSharedPointer> + +namespace Qt3D { +namespace Render { + +class LoadMeshDataJob : public Qt3D::QJob +{ +public: + LoadMeshDataJob(const QString &source, + const Qt3D::MeshDataPtr &meshData); + +protected: + void run() Q_DECL_OVERRIDE; + +private: + QString m_source; + Qt3D::MeshDataPtr m_meshData; +}; + +typedef QSharedPointer<LoadMeshDataJob> LoadMeshDataJobPtr; + +} // namespace Render +} // namespace Qt3D + +#endif // QT3D_RENDER_LOADMESHDATAJOB_H diff --git a/src/render/backend/jobs/updateboundingvolumejob.cpp b/src/render/backend/jobs/updateboundingvolumejob.cpp new file mode 100644 index 000000000..0d5752ff1 --- /dev/null +++ b/src/render/backend/jobs/updateboundingvolumejob.cpp @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "updateboundingvolumejob.h" + +#include <rendernode.h> +#include <sphere.h> + +#include <QDebug> +#include <QElapsedTimer> +#include <QStack> +#include <QThread> + +static void expandWorldBoundingVolume(Qt3D::Render::RenderNode *node) +{ + Qt3D::Render::RenderNode *currentNode = node; + QStack<int> childIndexStack; + forever { + // Find left most leaf node of currentNode + while (!currentNode->m_children.isEmpty()) { + childIndexStack.push(1); + currentNode = node->m_children.first(); + } + + if (!currentNode->m_parent) + return; + + // Initialize parent bounding volume to be equal to that of the first child + Qt3D::Render::RenderNode *parentNode = currentNode->m_parent; + Qt3D::Sphere *parentBoundingVolume = parentNode->m_worldBoundingVolume; + *(parentBoundingVolume) = *(currentNode->m_worldBoundingVolume); + + // Expand the parent bounding volume by each of remaining the siblings + const int siblingCount = parentNode->m_children.count(); + for (int i = 1; i < siblingCount; ++i) { + Qt3D::Sphere *siblingBoundingVolume = parentNode->m_children.at(i)->m_worldBoundingVolume; + parentBoundingVolume->expandToContain(*siblingBoundingVolume); + } + + // Move to parent's next sibling + childIndexStack.pop(); + const int nextSiblingIndex = childIndexStack.top()++; + currentNode = parentNode->m_parent->m_children.at(nextSiblingIndex); + } +} + +namespace Qt3D { +namespace Render { + +UpdateBoundingVolumeJob::UpdateBoundingVolumeJob(RenderNode *node) + : m_node(node) +{ +} + +void UpdateBoundingVolumeJob::run() +{ + // Expand the bounding volumes of each node that has children by the + // bounding volumes of the children + + // TODO: Implement this using a parallel_for + qDebug() << "Entering" << Q_FUNC_INFO << QThread::currentThread(); + expandWorldBoundingVolume(m_node); + qDebug() << "Exiting" << Q_FUNC_INFO << QThread::currentThread(); +} + +} // namespace Render +} // namespace Qt3D diff --git a/src/render/backend/jobs/updateboundingvolumejob.h b/src/render/backend/jobs/updateboundingvolumejob.h new file mode 100644 index 000000000..81353a6c0 --- /dev/null +++ b/src/render/backend/jobs/updateboundingvolumejob.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3D_RENDER_UPDATEBOUNDINGVOLUMEJOB_H +#define QT3D_RENDER_UPDATEBOUNDINGVOLUMEJOB_H + +#include <qjob.h> + +#include <QSharedPointer> + +namespace Qt3D { +namespace Render { + +class RenderNode; + +class UpdateBoundingVolumeJob : public Qt3D::QJob +{ +public: + explicit UpdateBoundingVolumeJob(RenderNode *m_node); + +protected: + void run() Q_DECL_OVERRIDE; + +private: + RenderNode *m_node; +}; + +typedef QSharedPointer<UpdateBoundingVolumeJob> UpdateBoundingVolumeJobPtr; + +} // namespace Render +} // namespace Qt3D + +#endif // QT3D_RENDER_UPDATEBOUNDINGVOLUMEJOB_H diff --git a/src/render/backend/jobs/updateworldtransformjob.cpp b/src/render/backend/jobs/updateworldtransformjob.cpp new file mode 100644 index 000000000..04f09f9a0 --- /dev/null +++ b/src/render/backend/jobs/updateworldtransformjob.cpp @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "updateworldtransformjob.h" + +#include <renderer.h> +#include <rendernode.h> +#include <sphere.h> + +#include <QDebug> +#include <QThread> + +static void updateWorldTransformAndBounds(Qt3D::Render::RenderNode *node) +{ + QMatrix4x4 parentTransform; + if (node->m_parent) + parentTransform = *(node->m_parent->m_worldTransform); + + *(node->m_worldTransform) = parentTransform * *(node->m_localTransform); + *(node->m_worldBoundingVolume) = node->m_localBoundingVolume->transformed(*(node->m_worldTransform)); + + Q_FOREACH (Qt3D::Render::RenderNode *child, node->m_children) + updateWorldTransformAndBounds(child); +} + +namespace Qt3D { +namespace Render { + +UpdateWorldTransformJob::UpdateWorldTransformJob(RenderNode *node) + : Qt3D::QJob() + , m_node(node) +{ +} + +void UpdateWorldTransformJob::run() +{ + // Iterate over each level of hierarchy in our scene + // and update each node's world transform from its + // local transform and its parent's world transform + + // TODO: Parallelise this on each level using a parallel_for + // implementation. + + qDebug() << "Entering" << Q_FUNC_INFO << QThread::currentThread(); + updateWorldTransformAndBounds(m_node); + qDebug() << "Exiting" << Q_FUNC_INFO << QThread::currentThread(); +} + +} // namespace Render +} // namespace Qt3D diff --git a/src/render/backend/jobs/updateworldtransformjob.h b/src/render/backend/jobs/updateworldtransformjob.h new file mode 100644 index 000000000..64117e893 --- /dev/null +++ b/src/render/backend/jobs/updateworldtransformjob.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3D_RENDER_UPDATEWORLDTRANSFORMJOB_H +#define QT3D_RENDER_UPDATEWORLDTRANSFORMJOB_H + +#include <qjob.h> + +#include <QSharedPointer> + +namespace Qt3D { +namespace Render { + +class RenderNode; + +class UpdateWorldTransformJob : public QJob +{ +public: + explicit UpdateWorldTransformJob(RenderNode *node); + +protected: + void run() Q_DECL_OVERRIDE; + +private: + RenderNode *m_node; +}; + +typedef QSharedPointer<UpdateWorldTransformJob> UpdateWorldTransformJobPtr; + +} // namespace Render +} // namespace Qt3D + +#endif // QT3D_RENDER_UPDATEWORLDTRANSFORMJOB_H diff --git a/src/render/backend/meshmanager.cpp b/src/render/backend/meshmanager.cpp new file mode 100644 index 000000000..8c8e2f741 --- /dev/null +++ b/src/render/backend/meshmanager.cpp @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "meshmanager.h" + +namespace Qt3D { +namespace Render { + +MeshManager::MeshManager(QObject *parent) + : QObject(parent) +{ +} + +void MeshManager::addMesh(Qt3D::Mesh *frontEndMesh) +{ + MeshDataPtr meshData(new MeshData); + m_meshesByPeer.insert(frontEndMesh, meshData); + + // TODO: Protect access to front end data + m_meshesBySource.insert(frontEndMesh->source(), meshData); + + m_meshesPending.append(qMakePair(frontEndMesh->source(), meshData)); +} + +} // namespace Render +} // namespace Qt3D diff --git a/src/render/backend/meshmanager.h b/src/render/backend/meshmanager.h new file mode 100644 index 000000000..93379a18e --- /dev/null +++ b/src/render/backend/meshmanager.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3D_RENDER_MESHMANAGER_H +#define QT3D_RENDER_MESHMANAGER_H + +#include <QObject> + +#include <mesh.h> +#include <meshdata.h> + +#include <QHash> +#include <QPair> +#include <QString> + +namespace Qt3D { +namespace Render { + +class MeshManager : public QObject +{ + Q_OBJECT +public: + explicit MeshManager(QObject *parent = 0); + + void addMesh(Qt3D::Mesh *frontEndMesh); + + QList< QPair<QString, MeshDataPtr> > meshesPending() const { return m_meshesPending; } + void clearMeshesPending() { m_meshesPending.clear(); } + +private: + // TODO What unique id do we want to index by? + QHash<QString, Qt3D::MeshDataPtr> m_meshesBySource; + QHash<Qt3D::Mesh *, Qt3D::MeshDataPtr> m_meshesByPeer; + + // List of meshes that we need to schedule jobs to load + // and calculate bounds for. + QList< QPair<QString,MeshDataPtr> > m_meshesPending; +}; + +} // namespace Render +} // namespace Qt3D + +#endif // QT3D_RENDER_MESHMANAGER_H diff --git a/src/render/backend/qgraphicscontext.cpp b/src/render/backend/qgraphicscontext.cpp new file mode 100644 index 000000000..03469fe0c --- /dev/null +++ b/src/render/backend/qgraphicscontext.cpp @@ -0,0 +1,466 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qgraphicscontext.h" + +#include "rendercamera.h" +#include "rendershader.h" +#include "rendermaterial.h" +#include "rendertexture.h" + +#include <QDebug> +#include <QOpenGLShaderProgram> +#include <QOpenGLFunctions_3_3_Core> +#include <QSurface> +#include <QOpenGLTexture> + +namespace Qt3D +{ + +static QHash<unsigned int, QGraphicsContext*> static_contexts; + +unsigned int nextFreeContextId() +{ + for (unsigned int i=0; i < 0xffff; ++i) { + if (!static_contexts.contains(i)) + return i; + } + + qFatal("Couldn't find free context ID"); + return 0; +} + +QGraphicsContext::QGraphicsContext() + : m_initialized(false) + , m_id(nextFreeContextId()) + , m_surface(0) + , m_funcs(0) + , m_activeShader(0) + , m_camera(0) + , m_material(0) + , m_stateSet(0) +{ + static_contexts[m_id] = this; +} + +QGraphicsContext::~QGraphicsContext() +{ + releaseOpenGL(); + + Q_ASSERT(static_contexts[m_id] == this); + static_contexts.remove(m_id); +} + +void QGraphicsContext::setSurface(QSurface *s) +{ + m_surface = s; +} + +void QGraphicsContext::initialize() +{ + m_initialized = true; + + Q_ASSERT(m_gl); + + GLint numTexUnits; + glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &numTexUnits); + qDebug() << "context supports" << numTexUnits << "texture units"; + + m_pinnedTextureUnits = QBitArray(numTexUnits); + m_activeTextures.resize(numTexUnits); + m_textureScopes.resize(numTexUnits); +} + +void QGraphicsContext::beginDrawing() +{ + if (!m_gl || !m_surface) { + qWarning() << Q_FUNC_INFO << "no content or surface provided"; + return; + } + + bool ok = m_gl->makeCurrent(m_surface); + if (!ok) { + qWarning() << Q_FUNC_INFO << "make current failed"; + } + + GLint err = glGetError(); + if (err != 0) { + qWarning() << Q_FUNC_INFO << "glGetError:" << err; + } + + if (!m_initialized) { + initialize(); + } + + QVector4D cc = m_camera->clearColor(); + glClearColor(cc[0], cc[1], cc[2], cc[3]); + glClear(m_camera->clearMask()); + + QRectF vp(m_camera->viewport()); + // default to the entire surface + if (vp.isEmpty()) + vp = QRectF(QPointF(0,0), m_surface->size()); + glViewport(vp.x(), vp.y(), vp.width(), vp.height()); + + if (m_activeShader) + m_activeShader = NULL; +} + +void QGraphicsContext::endDrawing() +{ + m_gl->doneCurrent(); + m_gl->swapBuffers(m_surface); + + decayTextureScores(); +} + +void QGraphicsContext::setCamera(RenderCamera *rcam) +{ + m_camera = rcam; +} + +RenderCamera *QGraphicsContext::camera() const +{ + return m_camera; +} + + +QMatrix4x4 QGraphicsContext::projectionMatrix() const +{ + return m_camera->projection(); +} + +QMatrix4x4 QGraphicsContext::viewMatrix() const +{ + return m_camera->view(); +} + +void QGraphicsContext::releaseOpenGL() +{ + // m_shaderHash.clear + m_bufferHash.clear(); +} + +void QGraphicsContext::setOpenGLContext(QOpenGLContext* ctx) +{ + releaseOpenGL(); + m_gl = ctx; + // m_gl->setParent(this); + + m_funcs = m_gl->versionFunctions<QOpenGLFunctions_3_3_Core>(); + if (m_funcs) + m_funcs->initializeOpenGLFunctions(); +} + +void QGraphicsContext::activateShader(RenderShader *shader) +{ + if (shader == NULL) { + m_activeShader = NULL; + m_material = NULL; + m_funcs->glUseProgram(0); + return; + } + + if (!m_shaderHash.contains(shader)) { + QOpenGLShaderProgram* prog = shader->getOrCreateProgram(); + Q_ASSERT(prog); + m_shaderHash[shader] = prog; + m_activeShader = NULL; + } + + if (m_activeShader == shader) { + // no op + } else { + m_activeShader = shader; + QOpenGLShaderProgram* prog = m_shaderHash[shader]; + prog->bind(); + + // ensure material uniforms are re-applied + m_material = NULL; + } +} + +void QGraphicsContext::setActiveMaterial(RenderMaterial *rmat) +{ + if (m_material == rmat) + return; + + deactivateTexturesWithScope(TextureScopeMaterial); + m_material = rmat; +} + +void QGraphicsContext::setModelMatrix(const QMatrix4x4& modelMat) +{ + const QVector<int>& locs(m_activeShader->standardUniformLocations()); + QOpenGLShaderProgram* prog = activeShader(); + + GLint progId; + glGetIntegerv(GL_CURRENT_PROGRAM, &progId); + if (progId != (int) prog->programId()) { + qWarning() << "current program mismatch, very bad:" << progId << prog->programId(); + return; + } + + int sz = locs.size(); + for (int i=0; i<sz; ++i) { + Parameter::StandardUniform su = static_cast<Parameter::StandardUniform>(i); + int loc = locs.at(i); + if (loc == -1) + continue; + + switch (su) { + case Parameter::None: break; + + case Parameter::ModelMatrix: + prog->setUniformValue(loc, modelMat); break; + + case Parameter::ViewMatrix: + prog->setUniformValue(loc, viewMatrix()); break; + + case Parameter::ProjectionMatrix: + prog->setUniformValue(loc, projectionMatrix()); break; + + case Parameter::ModelView: + prog->setUniformValue(loc, viewMatrix() * modelMat); break; + + case Parameter::ModelViewProjection: + prog->setUniformValue(loc, projectionMatrix() * viewMatrix() * modelMat); break; + + case Parameter::ModelInverse: + prog->setUniformValue(loc, modelMat.inverted()); break; + + case Parameter::ViewInverse: + prog->setUniformValue(loc, viewMatrix().inverted()); break; + + case Parameter::ProjectionInverse: + prog->setUniformValue(loc, projectionMatrix().inverted()); break; + + case Parameter::ModelViewInverse: + prog->setUniformValue(loc, (viewMatrix() * modelMat).inverted()); break; + + case Parameter::ModelViewProjectionInverse: + prog->setUniformValue(loc, (projectionMatrix() * viewMatrix() * modelMat).inverted()); + break; + + case Parameter::ModelNormal: + prog->setUniformValue(loc, modelMat.normalMatrix()); + break; + + case Parameter::ModelViewNormal: + prog->setUniformValue(loc, (viewMatrix() * modelMat).normalMatrix()); + break; + } + + int err = glGetError(); + if (err) + qWarning() << "GL error after setting matrix" << QString::number(err, 16) << i << loc; + + } // of standard uniforms +} + +int QGraphicsContext::activateTexture(TextureScope scope, RenderTexture *tex, int onUnit) +{ + if (onUnit == -1) { + onUnit = assignUnitForTexture(tex); + + // check we didn't overflow the available units + if (onUnit == -1) + return onUnit; + } + + // actually re-bind if required + if (m_activeTextures[onUnit] != tex) { + QOpenGLTexture* glTex = tex->getOrCreateGLTexture(); + glTex->bind(onUnit); + } + + int err = glGetError(); + if (err) + qWarning() << "GL error after activating texture" << QString::number(err, 16) + << tex->textureId() << "on unit" << onUnit; + + m_textureScores[tex] = 200; + m_pinnedTextureUnits[onUnit] = true; + m_textureScopes[onUnit] = scope; + + return onUnit; +} + +void QGraphicsContext::deactivateTexturesWithScope(TextureScope ts) +{ + for (int u=0; u<m_activeTextures.size(); ++u) { + if (!m_pinnedTextureUnits[u]) + continue; // inactive, ignore + + if (m_textureScopes[u] == ts) { + m_pinnedTextureUnits[u] = false; + } + } // of units iteration +} + +void QGraphicsContext::deactivateTexture(RenderTexture* tex) +{ + for (int u=0; u<m_activeTextures.size(); ++u) { + if (m_activeTextures[u] == tex) { + Q_ASSERT(m_pinnedTextureUnits[u]); + m_pinnedTextureUnits[u] = false; + return; + } + } // of units iteration + + qWarning() << Q_FUNC_INFO << "texture not active:" << tex; +} + +void QGraphicsContext::setCurrentStateSet(DrawStateSet *ss) +{ + if (ss == m_stateSet) + return; + + ss->apply(this); + m_stateSet = ss; +} + +DrawStateSet *QGraphicsContext::currentStateSet() const +{ + return m_stateSet; +} + +GLint QGraphicsContext::assignUnitForTexture(RenderTexture *tex) +{ + int lowestScoredUnit = -1; + int lowestScore = 0xfffffff; + + for (int u=0; u<m_activeTextures.size(); ++u) { + if (m_activeTextures[u] == tex) { + return u; + } + + if (!m_pinnedTextureUnits[u]) { + int score = m_textureScores[tex]; + if (score < lowestScore) { + lowestScore = score; + lowestScoredUnit = u; + } + } + } // of units iteration + + if (lowestScoredUnit == -1) { + qWarning() << Q_FUNC_INFO << "NO free texture units!"; + return GL_INVALID_VALUE; + } + + return lowestScoredUnit; +} + +void QGraphicsContext::decayTextureScores() +{ + // FIXME - very inefficient use of QHash here, both for + // traversal coherency and subsequent modification. + Q_FOREACH (RenderTexture* t, m_textureScores.keys()) { + if ((m_textureScores[t]--) <= 0) { + qDebug() << "removing inactive texture" << t; + m_textureScores.remove((t)); + } + } +} + +QOpenGLShaderProgram* QGraphicsContext::activeShader() +{ + Q_ASSERT(m_activeShader); + return m_shaderHash[m_activeShader]; +} + + +void QGraphicsContext::specifyAttribute(QString nm, AttributePtr attr) +{ + QOpenGLBuffer buf = glBufferFor(attr->buffer()); + buf.bind(); + + QOpenGLShaderProgram* prog = activeShader(); + int location = prog->attributeLocation(nm); + if (location < 0) { + qWarning() << "failed to resolve location for attribute:" << nm; + return; + } + + prog->enableAttributeArray(location); + prog->setAttributeBuffer(location, + elementType(attr->type()), + attr->byteOffset(), + tupleSizeFromType(attr->type()), + attr->byteStride()); + + if (attr->divisor() != 0) { + // TODO - only if supported! + m_funcs->glVertexAttribDivisor(location, attr->divisor()); + } + + buf.release(); +} + +void QGraphicsContext::specifyIndices(AttributePtr attr) +{ + if (attr->buffer()->type() != QOpenGLBuffer::IndexBuffer) { + qWarning() << Q_FUNC_INFO << "provided buffer is not correct type"; + return; + } + + QOpenGLBuffer buf = glBufferFor(attr->buffer()); + if (!buf.bind()) + qWarning() << Q_FUNC_INFO << "binding index buffer failed"; + + // bind within the current VAO +} + +QOpenGLBuffer QGraphicsContext::glBufferFor(BufferPtr buf) +{ + if (m_bufferHash.contains(buf)) + return m_bufferHash.value(buf); + + QOpenGLBuffer glbuf = buf->createGL(); + m_bufferHash[buf] = glbuf; + buf->upload(glbuf); + + return glbuf; +} + +} // of namespace + diff --git a/src/render/backend/qgraphicscontext.h b/src/render/backend/qgraphicscontext.h new file mode 100644 index 000000000..f79695d7b --- /dev/null +++ b/src/render/backend/qgraphicscontext.h @@ -0,0 +1,177 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGRAPHICSCONTEXT_H +#define QGRAPHICSCONTEXT_H + +#include <QOpenGLContext> +#include <QOpenGLBuffer> +#include <QOpenGLVertexArrayObject> +#include <QHash> +#include <QMatrix4x4> +#include <QBitArray> + +#include <rendercamera.h> +#include <meshdata.h> + +class QOpenGLShaderProgram; +class QOpenGLFunctions_3_3_Core; + +namespace Qt3D +{ + +class RenderShader; +class RenderCamera; +class RenderMaterial; +class RenderTexture; +class DrawStateSet; + +enum TextureScope +{ + TextureScopeMaterial = 0, + TextureScopeTechnique + // per-pass for deferred rendering? +}; + +class QGraphicsContext +{ +public: + QGraphicsContext(); + ~QGraphicsContext(); + + void setSurface(QSurface* s); + + int id() const; // unique, small integer ID of this context + + void beginDrawing(); + + void endDrawing(); + + void setCamera(RenderCamera* rcam); + RenderCamera* camera() const; + + QMatrix4x4 projectionMatrix() const; + QMatrix4x4 viewMatrix() const; + + /** + * @brief releaseGL - release all OpenGL objects associated with + * this context + */ + void releaseOpenGL(); + void setOpenGLContext(QOpenGLContext* ctx); + QOpenGLContext *openGLContext() { return m_gl; } + + void activateShader(RenderShader* shader); + + RenderMaterial* activeMaterial() const + { return m_material; } + + void setActiveMaterial(RenderMaterial* rmat); + + /** + * @brief activeShader + * @return + */ + QOpenGLShaderProgram* activeShader(); + + void specifyAttribute(QString nm, AttributePtr attr); + + void specifyIndices(AttributePtr attr); + + /** + * @brief glBufferFor - given a client-side (CPU) buffer, provide the + * context-specific object. Initial call will create the buffer. + * @param buf + * @return + */ + QOpenGLBuffer glBufferFor(BufferPtr buf); + + void setModelMatrix(const QMatrix4x4 &modelMat); + + /** + * @brief activateTexture - make a texture active on a hardware unit + * @param tex - the texture to activate + * @param onUnit - option, specify the explicit unit to activate on + * @return - the unit the texture was activated on + */ + int activateTexture(TextureScope scope, RenderTexture* tex, int onUnit = -1); + + void deactivateTexture(RenderTexture *tex); + + void setCurrentStateSet(DrawStateSet* ss); + DrawStateSet* currentStateSet() const; +private: + void initialize(); + + void decayTextureScores(); + + GLint assignUnitForTexture(RenderTexture* tex); + void deactivateTexturesWithScope(TextureScope ts); + + + bool m_initialized; + const unsigned int m_id; + QOpenGLContext* m_gl; + QSurface* m_surface; + + QOpenGLFunctions_3_3_Core *m_funcs; + RenderShader* m_activeShader; + QHash<RenderShader*, QOpenGLShaderProgram*> m_shaderHash; + QHash<BufferPtr,QOpenGLBuffer> m_bufferHash; + + // active textures, indexed by texture unit + QVector<RenderTexture*> m_activeTextures; + QBitArray m_pinnedTextureUnits; + QVector<TextureScope> m_textureScopes; + + // recency score for all render-textures we've seen. Higher scores + // mean more recently used. + QHash<RenderTexture*, int> m_textureScores; + + RenderCamera* m_camera; + RenderMaterial* m_material; + + DrawStateSet* m_stateSet; +}; + +} + +#endif // QGRAPHICSCONTEXT_H diff --git a/src/render/backend/quniformvalue.cpp b/src/render/backend/quniformvalue.cpp new file mode 100644 index 000000000..8c88b62a6 --- /dev/null +++ b/src/render/backend/quniformvalue.cpp @@ -0,0 +1,306 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "quniformvalue.h" + +#include "qgraphicscontext.h" +#include "rendertexture.h" + +#include <QOpenGLShaderProgram> +#include <QDebug> +#include <QColor> +#include <QQuaternion> + +namespace Qt3D { namespace Render { + +QUniformValue::QUniformValue() : + m_type(Invalid), + m_count(-1), + m_tupleSize(0) +{ +} + +QUniformValue::QUniformValue(Type type, QVariant value) : + m_type(type), + m_count(-1), + m_tupleSize(0) +{ + fromVariant(value); + Q_ASSERT((m_tupleSize >= 1) && (m_tupleSize <= 4)); +} + +QUniformValue::QUniformValue(const QVector4D &f) : + m_type(Float) +{ + m_var = QVariant(f); + QVector4D v(f); // need to make a local copy to take the address + setRawFromFloats(&v[0], 1, 4); +} + +void QUniformValue::fromVariant(QVariant v) +{ + if (!v.isValid()) + return; + + if (m_var == v) + return; + m_var = v; + + switch (m_type) { + case Int: + case UInt: + fromVariantToInt(v); + break; + + case Float: + fromVariantToFloat(v); + break; + + // doubles, if the extension is present + + default: + qWarning() << Q_FUNC_INFO << "unsupported internal type" << m_type; + } +} + +void QUniformValue::fromVariantToInt(QVariant v) +{ + switch (v.type()) { + case QVariant::Int: + case QVariant::UInt: + case QVariant::Double: { + qint32 i = static_cast<qint32>(v.toInt()); + setRawFromInts(&i, 1, 1); + break; + } + + default: + qWarning() << Q_FUNC_INFO << "unsupported type" << v; + } +} + +void QUniformValue::fromVariantToFloat(QVariant v) +{ + float* bufPtr = NULL; + + switch (v.type()) { + case QVariant::Int: + case QVariant::UInt: + case QVariant::Double: { + float f = static_cast<float>(v.toDouble()); + setRawFromFloats(&f, 1, 1); + break; + } + + case QVariant::Vector2D: { + QVector2D v2 = v.value<QVector2D>(); + setRawFromFloats(&v2[0], 1, 2); + break; + } + + case QVariant::Vector3D: { + QVector3D v3 = v.value<QVector3D>(); + setRawFromFloats(&v3[0], 1, 3); + break; + } + + case QVariant::Vector4D: { + QVector4D v4 = v.value<QVector4D>(); + setRawFromFloats(&v4[0], 1, 4); + break; + } + + case QVariant::Matrix4x4: { + QMatrix4x4 m = v.value<QMatrix4x4>(); + setRawFromFloats(m.constData(), 4, 4); + break; + } + + case QVariant::Color: { + qDebug() << "XXXXXXX setting from" << v; + m_bytes.resize(sizeof(float) * 4); + m_count = 1; + m_tupleSize = 4; + QColor c = v.value<QColor>(); + *bufPtr++ = c.redF(); + *bufPtr++ = c.greenF(); + *bufPtr++ = c.blueF(); + *bufPtr++ = c.alphaF(); + break; + } + + case QVariant::Quaternion: { + QVector4D qv = v.value<QQuaternion>().toVector4D(); + setRawFromFloats(&qv[0], 1, 4); + break; + } + + case QVariant::List: { + QVariantList vl = v.toList(); + + // implement me ... + + break; + } + + default: + qWarning() << Q_FUNC_INFO << "unsupported QVariant type"; + } +} + +void QUniformValue::setRawFromFloats(const float* ptr, unsigned int count, unsigned int tupleSize) +{ + m_bytes.resize(sizeof(float) * count * tupleSize); + memcpy(m_bytes.data(), ptr, m_bytes.size()); + m_count = count; + m_tupleSize = tupleSize; +} + +void QUniformValue::setRawFromInts(const qint32* ptr, unsigned int count, unsigned int tupleSize) +{ + m_bytes.resize(sizeof(qint32) * count * tupleSize); + memcpy(m_bytes.data(), ptr, m_bytes.size()); + m_count = count; + m_tupleSize = tupleSize; +} + +void QUniformValue::apply(QGraphicsContext *gc, int location, QString nm) const +{ + switch (m_type) { +#if 0 + case Int: + switch (m_tupleSize) { + + } + + gc->activeShader()->setUniformValueArray(location, + reinterpret_cast<const GLint*>(m_bytes.constData()), + m_count * m_tupleSize); + glUni + + break; + + case UInt: + gc->activeShader()->setUniformValueArray(location, + reinterpret_cast<const GLuint*>(m_bytes.constData()), + m_count * m_tupleSize); + break; +#endif + + case Float: + gc->activeShader()->setUniformValueArray(location, + reinterpret_cast<const GLfloat*>(m_bytes.constData()), + m_count, m_tupleSize); + break; + + default: + qWarning() << Q_FUNC_INFO << "unsupported type:" << m_type; + } + + int err = glGetError(); + if (err) { + qWarning() << "error after setting uniform" << m_count << location << m_tupleSize << nm; + } +} + +void QUniformValue::convertToBytes() const +{ + if (!m_bytes.isEmpty()) + return; // use cahced conversion +} + +void QUniformPack::setUniform(QString glslName, QUniformValue val) +{ + for (int u=0; u<m_uniforms.size(); ++u) { + if (m_uniforms[u].glslName != glslName) { + continue; + } + + m_uniforms[u].uval = val; + return; + } + + NamedUniform nu; + nu.glslName = glslName; + nu.uval = val; + m_uniforms.append(nu); +} + +void QUniformPack::setTexture(QString glslName, RenderTexturePtr tex) +{ + for (int t=0; t<m_textures.size(); ++t) { + if (m_textures[t].glslName != glslName) { + continue; + } + + m_textures[t].tex = tex; + return; + } + + m_textures.append(NamedTexture(glslName, tex)); +} + +void QUniformPack::apply(QGraphicsContext *gc) +{ + for (int u=0; u<m_uniforms.size(); ++u) { + int loc = m_uniforms[u].location; + if (loc == -1) { + loc = gc->activeShader()->uniformLocation(m_uniforms[u].glslName); + m_uniforms[u].location = loc; + } + + m_uniforms[u].uval.apply(gc, loc, m_uniforms[u].glslName); + } // of uniforms iteration + + for (int t=0; t<m_textures.size(); ++t) { + int loc = m_textures[t].location; + if (loc == -1) { + loc = gc->activeShader()->uniformLocation(m_textures[t].glslName); + m_textures[t].location = loc; + } + + int unit = gc->activateTexture(TextureScopeMaterial, m_textures[t].tex.data()); + gc->activeShader()->setUniformValue(loc, unit); + } // of textures iteration +} + +} } // of namespace Qt3D::Render + diff --git a/src/render/backend/quniformvalue.h b/src/render/backend/quniformvalue.h new file mode 100644 index 000000000..eb642e950 --- /dev/null +++ b/src/render/backend/quniformvalue.h @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QUNIFORMVALUE_H +#define QUNIFORMVALUE_H + +#include <QVariant> +#include <QByteArray> +#include <QVector> + +// for RenderTexturePtr +#include <rendertextureprovider.h> + +namespace Qt3D { + +class QGraphicsContext; + +namespace Render { + +/** + * @brief The QUniformValue class - immutable storage of uniform value + * in the rendering backend. + */ +class QUniformValue +{ +public: + enum Type { + Invalid = 0, + Int = 1, + UInt = 2, + Float = 3, + Double = 4, + Bool + }; + + QUniformValue(); + + QUniformValue(Type type, QVariant value); + + // explicit construction from various types without going through + // QVariant boxing + unboxing. Add as needed if this proves useful + explicit QUniformValue(const QVector4D& foo); + + void apply(QGraphicsContext* gc, int location, QString nm) const; + +private: + void convertToBytes() const; + + Type m_type; + int m_count; + unsigned int m_tupleSize; + + QVariant m_var; + // value as data suitable for passing to glUniformfv/iv + mutable QByteArray m_bytes; + + void fromVariant(QVariant v); + void fromVariantToInt(QVariant v); + void fromVariantToFloat(QVariant v); + + void setRawFromFloats(const float *ptr, unsigned int count, unsigned int tupleSize); + void setRawFromInts(const qint32 *ptr, unsigned int count, unsigned int tupleSize); +}; + +class QUniformPack +{ +public: + void setUniform(QString glslName, QUniformValue val); + + void setTexture(QString glslName, RenderTexturePtr tex); + + void apply(QGraphicsContext* gc); +private: + + struct NamedUniform { + NamedUniform() : location(-1) { } + + QString glslName; + int location; + QUniformValue uval; + }; + + QVector<NamedUniform> m_uniforms; + + struct NamedTexture { + NamedTexture() : location(-1) {} + + NamedTexture(QString nm, RenderTexturePtr t) : + glslName(nm), + location(-1), + tex(t) + { } + + QString glslName; + int location; + RenderTexturePtr tex; + }; + + QVector<NamedTexture> m_textures; +}; + +}} // of namespace Qt3D::Render + +#endif // QUNIFORMVALUE_H diff --git a/src/render/backend/render-backend.pri b/src/render/backend/render-backend.pri new file mode 100644 index 000000000..468f03c9d --- /dev/null +++ b/src/render/backend/render-backend.pri @@ -0,0 +1,52 @@ +INCLUDEPATH += $$PWD + +include("framegraph/framegraph.pri") +include("jobs/jobs.pri") + +HEADERS += \ + $$PWD/rendereraspect.h \ + $$PWD/renderthread.h \ + $$PWD/renderconfiguration.h \ + $$PWD/renderdevice.h \ + $$PWD/renderer.h \ + $$PWD/rendermaterial.h \ + $$PWD/drawable.h \ + $$PWD/rendermesh.h \ + $$PWD/qgraphicscontext.h \ + $$PWD/renderbin.h \ + $$PWD/rendershader.h \ + $$PWD/rendertechnique.h \ + $$PWD/rendercamera.h \ + $$PWD/quniformvalue.h \ + $$PWD/rendernode.h \ + $$PWD/renderscenebuilder.h \ + $$PWD/rendertexture.h \ + $$PWD/rendertextureprovider.h \ + $$PWD/meshmanager.h \ + $$PWD/drawstate.h \ + $$PWD/states/blendstate.h \ + $$PWD/genericstate.h + + +SOURCES += \ + $$PWD/rendereraspect.cpp \ + $$PWD/renderthread.cpp \ + $$PWD/renderconfiguration.cpp \ + $$PWD/renderdevice.cpp \ + $$PWD/renderer.cpp \ + $$PWD/rendermaterial.cpp \ + $$PWD/drawable.cpp \ + $$PWD/rendermesh.cpp \ + $$PWD/qgraphicscontext.cpp \ + $$PWD/renderbin.cpp \ + $$PWD/rendershader.cpp \ + $$PWD/rendertechnique.cpp \ + $$PWD/rendercamera.cpp \ + $$PWD/quniformvalue.cpp \ + $$PWD/rendernode.cpp \ + $$PWD/renderscenebuilder.cpp \ + $$PWD/rendertexture.cpp \ + $$PWD/rendertextureprovider.cpp \ + $$PWD/meshmanager.cpp \ + $$PWD/drawstate.cpp \ + $$PWD/states/blendstate.cpp diff --git a/src/render/backend/renderbin.cpp b/src/render/backend/renderbin.cpp new file mode 100644 index 000000000..62adede68 --- /dev/null +++ b/src/render/backend/renderbin.cpp @@ -0,0 +1,204 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "renderbin.h" + +#include "drawable.h" +#include "qgraphicscontext.h" +#include "rendershader.h" +#include "drawstate.h" + +//#define QT3D_STATE_CHANGE_DEBUG + +namespace Qt3D +{ + + +void OpaqueBin::sendDrawingCommands(QGraphicsContext *gc) +{ + int shaderChangeCount = 0, + stateSetChangeCount = 0, + batchSize = 0; + bool resetBatch = false; + + RenderShader* sh = NULL; + DrawStateSet* ss = NULL; + + foreach (Drawable* d, m_drawables) { + resetBatch = false; + + if (sh != d->shader()) { + sh = d->shader(); + gc->activateShader(sh); + ++shaderChangeCount; + #if defined(QT3D_STATE_CHANGE_DEBUG) + qDebug() << "did shader change to" << sh->name(); + #endif + resetBatch = true; + } + + if (ss != d->stateSet()) { + ss = d->stateSet(); + gc->setCurrentStateSet(ss); + ++stateSetChangeCount; + #if defined(QT3D_STATE_CHANGE_DEBUG) + qDebug() << "did state change"; + #endif + resetBatch = true; + } + + if (resetBatch && (batchSize > 0)) { + #if defined(QT3D_STATE_CHANGE_DEBUG) + qDebug() << "previous batch was " << batchSize; + #endif + batchSize = 1; + } else { + ++batchSize; + } + + d->sendDrawingCommands(gc); + } + +#if defined(QT3D_STATE_CHANGE_DEBUG) + qDebug() << "final batch:" << batchSize; +#endif +} + +void OpaqueBin::addDrawable(Drawable *dr) +{ + Q_CHECK_PTR(dr); + RenderShader* sh = dr->shader(); + DrawStateSet* ss = dr->stateSet(); + + int shaderStartIndex = 0; + for (; shaderStartIndex <m_drawables.size(); ++ shaderStartIndex) { + if (m_drawables.at(shaderStartIndex)->shader() == sh) { + break; + } + } + + if (shaderStartIndex >= m_drawables.size()) { + // no matching shader found, simply append + m_drawables.append(dr); + return; + } + +// find last drawable using the shader. Also check for a matching +// DrawStateSet in case it exists (then we just insert beside) + int shaderEndIndex = shaderStartIndex; + QVector<DrawStateSet*> ssList; + + for (; shaderEndIndex < m_drawables.size(); ++shaderEndIndex) { + if (m_drawables.at(shaderEndIndex)->shader() != sh) + break; // found first drawable with different shader + + DrawStateSet* currentSS = m_drawables.at(shaderEndIndex)->stateSet(); + // record each distinct state-set applicable to this shader. + if (ssList.empty() || ssList.back() != currentSS) { + ssList.append(currentSS); + + // check cost delta is non-zero; if it is, the state-sets are + // equivalent and we can simply merge + if (ss->changeCost(currentSS) == 0) { + m_drawables.insert(shaderEndIndex, dr); + return; + } + } + } // of same-shader range-iteration + + insertDrawableInRange(dr, shaderStartIndex, shaderEndIndex, ssList); +} + +// select position in the (shaderStartIndex .. shaderEndIndex] +// range based on lowest cost StateSet transition. We already know the state-sets +// are distinct since we checked for changeCost() == 0 in the loop above + +void OpaqueBin::insertDrawableInRange(Drawable *dr, + int startIndex, int endIndex, + const QVector<DrawStateSet*> ssList) +{ + qDebug() << "inserting drawable with different state-set"; + +// special case where there is only one existing state set + if (ssList.size() == 1) { + m_drawables.insert(endIndex, dr); + return; + } + + DrawStateSet* ss = dr->stateSet(); + DrawStateSet* prevSS = ssList.front(); + // default to appending + int lowestCostIncrease = ss->changeCost(ssList.back()); + DrawStateSet* insertBeforeSS = NULL; + + // see if we can do better than appending + for (int i=1; i<ssList.size(); ++i) { + int oldCost = ssList.at(i)->changeCost(prevSS); + int newCost = ss->changeCost(prevSS) + ssList.at(i)->changeCost(ss); + int costIncrease = newCost - oldCost; + + if (costIncrease < lowestCostIncrease) { + lowestCostIncrease = costIncrease; + insertBeforeSS = ssList.at(i); + } + } // of distinct state-sets iteration + + if (insertBeforeSS) { + for (int i=startIndex; i<endIndex; ++i) { + if (m_drawables.at(i)->stateSet() == insertBeforeSS) { + m_drawables.insert(i, dr); + break; + } + } + } else { + // simply append + m_drawables.insert(endIndex, dr); + } +} + +void OpaqueBin::removeDrawable(Drawable *dr) +{ + Q_CHECK_PTR(dr); + m_drawables.removeOne(dr); +} + + +} // of namespace diff --git a/src/render/backend/renderbin.h b/src/render/backend/renderbin.h new file mode 100644 index 000000000..b21c5adf0 --- /dev/null +++ b/src/render/backend/renderbin.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef RENDERBIN_H +#define RENDERBIN_H + +#include <QList> +#include <QMap> + +namespace Qt3D +{ + +class Drawable; +class QGraphicsContext; +class RenderShader; +class DrawStateSet; + +class RenderBin +{ +public: + + virtual void sendDrawingCommands(QGraphicsContext* gc) = 0; + virtual void addDrawable(Drawable* dr) = 0; + virtual void removeDrawable(Drawable* dr) = 0; + +private: + +}; + +class OpaqueBin : public RenderBin +{ +public: + + virtual void sendDrawingCommands(QGraphicsContext* gc); + + virtual void addDrawable(Drawable* dr); + virtual void removeDrawable(Drawable* dr); + +private: + QList<Drawable*> m_drawables; + + void insertDrawableInRange(Drawable *dr, + int startIndex, int endIndex, + const QVector<DrawStateSet *> ssList); +}; + +class DepthSortedBin : public RenderBin +{ +public: + +private: +}; + +} // of namespace + +#endif // RENDERBIN_H diff --git a/src/render/backend/rendercamera.cpp b/src/render/backend/rendercamera.cpp new file mode 100644 index 000000000..20126b9bc --- /dev/null +++ b/src/render/backend/rendercamera.cpp @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "rendercamera.h" +#include "rendereraspect.h" + +#include <camera.h> + +#include <entity.h> +#include <qaspectmanager.h> + +#include <QOpenGLContext> + +namespace Qt3D +{ + +RenderCamera::RenderCamera(RendererAspect *rendererAspect) + : m_rendererAspect(rendererAspect) + , m_peer(0) +{ + m_clearColor = QVector4D(0.5, 0.5, 1.0, 1.0); +} + +void RenderCamera::setPeer(Camera *peer) +{ + m_peer = peer; + + // Register for changes + QChangeArbiter *arbiter = m_rendererAspect->aspectManager()->changeArbiter(); + arbiter->registerObserver(this, m_peer, MaterialParameter); +} + +void RenderCamera::sync() +{ + // TODO Move the view matrix out of Camera and instead + // use the Entity's transformation (and later the Transform component). + Entity* e = m_peer->parentNode()->asEntity(); + + // HACK - in absence of an update pass + e->update(); + + // transform from world -> eye, so invert + m_view = e->sceneMatrix().inverted(); +} + +unsigned int RenderCamera::clearMask() const +{ + return GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT; +} + +void RenderCamera::setProjection(const QMatrix4x4 &projection) +{ + m_projection = projection; +} + +QMatrix4x4 RenderCamera::projection() const +{ + return m_projection; +} + +QMatrix4x4 RenderCamera::view() const +{ + return m_view; +} + +void RenderCamera::sceneChangeEvent(const QSceneChangePtr &e) +{ + switch (e->m_type) { + case CameraProjectionMatrix: { + QScenePropertyChangePtr propertyChange = qSharedPointerCast<QScenePropertyChange>(e); + QVariant propertyValue = propertyChange->m_value; + QMatrix4x4 viewMatrix = propertyValue.value<QMatrix4x4>(); + m_projection = viewMatrix; + break; + } + + default: + break; + } +} + +} // of namespace + diff --git a/src/render/backend/rendercamera.h b/src/render/backend/rendercamera.h new file mode 100644 index 000000000..937076597 --- /dev/null +++ b/src/render/backend/rendercamera.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef RENDERCAMERA_H +#define RENDERCAMERA_H + +#include <qchangearbiter.h> + +#include <QMatrix4x4> +#include <QRectF> + +namespace Qt3D +{ + +class Camera; +class RendererAspect; + +class RenderCamera : public QObserverInterface +{ +public: + RenderCamera(RendererAspect *rendererAspect); + + void setPeer(Camera *peer); + + // manually sync state with the peer, for the moment + void sync(); + + QVector4D clearColor() const { return m_clearColor; } + + unsigned int clearMask() const; + + QRectF viewport() const { return m_viewport; } + + void setProjection(const QMatrix4x4 &projection); + QMatrix4x4 projection() const; + + QMatrix4x4 view() const; + + void sceneChangeEvent(const QSceneChangePtr &e) Q_DECL_OVERRIDE; + +private: + RendererAspect *m_rendererAspect; + Camera *m_peer; + + // clip plane data + // ? m_zNear, m_zFar; + + + QVector4D m_clearColor; + + QMatrix4x4 m_projection; + QMatrix4x4 m_view; + QRectF m_viewport; +}; + +} + +#endif // RENDERCAMERA_H diff --git a/src/render/backend/renderconfiguration.cpp b/src/render/backend/renderconfiguration.cpp new file mode 100644 index 000000000..ae2437461 --- /dev/null +++ b/src/render/backend/renderconfiguration.cpp @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "renderconfiguration.h" + +namespace Qt3D { +namespace Render { + +RenderConfiguration::RenderConfiguration() +{ +} + +} // namespace Render +} // namespace Qt3D diff --git a/src/render/backend/renderconfiguration.h b/src/render/backend/renderconfiguration.h new file mode 100644 index 000000000..76a47f760 --- /dev/null +++ b/src/render/backend/renderconfiguration.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3D_RENDER_RENDERCONFIGURATION_H +#define QT3D_RENDER_RENDERCONFIGURATION_H + +namespace Qt3D { +namespace Render { + +class RenderConfiguration +{ +public: + RenderConfiguration(); +}; + +} // namespace Render +} // namespace Qt3D + +#endif // QT3D_RENDER_RENDERCONFIGURATION_H diff --git a/src/render/backend/renderdevice.cpp b/src/render/backend/renderdevice.cpp new file mode 100644 index 000000000..4648932e7 --- /dev/null +++ b/src/render/backend/renderdevice.cpp @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "renderdevice.h" + +namespace Qt3D { +namespace Render { + +RenderDevice::RenderDevice() +{ +} + +} // namespace Render +} // namespace Qt3D diff --git a/src/render/backend/renderdevice.h b/src/render/backend/renderdevice.h new file mode 100644 index 000000000..c854eee29 --- /dev/null +++ b/src/render/backend/renderdevice.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3D_RENDER_RENDERDEVICE_H +#define QT3D_RENDER_RENDERDEVICE_H + +namespace Qt3D { +namespace Render { + +class RenderDevice +{ +public: + RenderDevice(); +}; + +} // namespace Render +} // namespace Qt3D + +#endif // QT3D_RENDER_RENDERDEVICE_H diff --git a/src/render/backend/renderer.cpp b/src/render/backend/renderer.cpp new file mode 100644 index 000000000..84ded8ebb --- /dev/null +++ b/src/render/backend/renderer.cpp @@ -0,0 +1,524 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "renderer.h" + +#include <nodevisitor.h> +#include <entity.h> +#include <scene.h> + +#include "framegraph/framegraphnode.h" +#include "framegraph/framegraphvisitor.h" + +#include <material.h> +#include <mesh.h> +#include <effect.h> +#include <technique.h> +#include <shaderprogram.h> +#include <renderpass.h> +#include <camera.h> +#include <shape.h> + +#include <meshmanager.h> +#include <rendermesh.h> +#include <renderbin.h> +#include <rendermaterial.h> +#include <rendernode.h> +#include <rendertechnique.h> +#include <renderscenebuilder.h> +#include <rendershader.h> +#include <qgraphicscontext.h> +#include <rendercamera.h> +#include <rendertextureprovider.h> +#include <drawstate.h> +#include <states/blendstate.h> + +#include <QStack> +#include <QDebug> +#include <QSurface> + +namespace Qt3D { + +namespace { + +class TemporaryBackendBuilder : public NodeVisitor +{ +public: + TemporaryBackendBuilder(Render::Renderer* r) : + m_renderer(r) + { + + } + +protected: + virtual void visitEntity(Entity* ent) + { + ent->update(); + + bool haveMaterial = false; + QList<Material*> mats = ent->componentsOfType<Material>(); + if (!mats.empty()) { + haveMaterial = true; + m_materialStack.push(mats.front()); + } + + + foreach (Mesh* mesh, ent->componentsOfType<Mesh>()) { + Material* mat = m_materialStack.empty() ? NULL : m_materialStack.top(); + m_renderer->buildMeshes(mesh, mat, ent->sceneMatrix()); + } + + foreach (Shape* shape, ent->componentsOfType<Shape>()) { + Material* mat = m_materialStack.empty() ? NULL : m_materialStack.top(); + m_renderer->buildShape(shape, mat, ent->sceneMatrix()); + } + + foreach (Camera* cam, ent->componentsOfType<Camera>()) { + m_renderer->foundCamera(cam, ent->sceneMatrix()); + } + + NodeVisitor::visitEntity(ent); + + if (haveMaterial) + m_materialStack.pop(); + } + +private: + QStack<Material*> m_materialStack; + Render::Renderer* m_renderer; +}; + +} // anonymous namespace + +namespace Render { + +Renderer::Renderer() + : m_rendererAspect(0) + , m_frameGraphRoot(0) + , m_camera(0) + , m_renderCamera(0) + , m_meshManager(new MeshManager(this)) +{ + m_temporaryAllBin = NULL; + m_graphicsContext = new QGraphicsContext; + m_graphicsContext->setOpenGLContext(new QOpenGLContext); + + m_frameTimer = new QTimer(this); + connect(m_frameTimer, SIGNAL(timeout()), this, SLOT(onFrame())); + m_frameTimer->setInterval(16); + + m_textureProvider = new RenderTextureProvider; + + buildDefaultTechnique(); + buildDefaultMaterial(); +} + +void Renderer::buildDefaultTechnique() +{ + m_defaultTechnique = new Technique; + m_defaultTechnique->setObjectName("default-technique"); + + ShaderProgram* defaultShader = new ShaderProgram; + defaultShader->setVertexSourceFile(":/shaders/diffuse.vert"); + defaultShader->setFragmentSourceFile(":/shaders/diffuse.frag"); + defaultShader->setObjectName("DefaultShader"); + + RenderPass* basicPass = new RenderPass; + basicPass->setShaderProgram(defaultShader); + + DrawStateSet* ss = new DrawStateSet; + ss->addState(DepthTest::getOrCreate(GL_LESS)); + ss->addState(CullFace::getOrCreate(GL_BACK)); + basicPass->setStateSet(ss); + + m_defaultTechnique->addPass(basicPass); + + Parameter* vp = new Parameter(m_defaultTechnique, "position", GL_FLOAT_VEC3); + vp->setMeshAttributeName("position"); + m_defaultTechnique->addParameter(vp); + basicPass->addAttributeBinding(vp, "vertexPosition"); + + Parameter* np = new Parameter(m_defaultTechnique, "normal", GL_FLOAT_VEC3); + np->setMeshAttributeName("normal"); + m_defaultTechnique->addParameter(np); + basicPass->addAttributeBinding(np, "vertexNormal"); + +// matrix uniforms from standard + Parameter* mvMat = new Parameter(m_defaultTechnique, "modelView", GL_FLOAT_MAT4); + mvMat->setStandardUniform(Parameter::ModelView); + m_defaultTechnique->addParameter(mvMat); + basicPass->addUniformBinding(mvMat, "modelViewMatrix"); + + Parameter* nMat = new Parameter(m_defaultTechnique, "normalMat", GL_FLOAT_MAT3); + nMat->setStandardUniform(Parameter::ModelViewNormal); + m_defaultTechnique->addParameter(nMat); + basicPass->addUniformBinding(nMat, "normalMatrix"); + + Parameter* mvpMat = new Parameter(m_defaultTechnique, "mvp", GL_FLOAT_MAT4); + mvpMat->setStandardUniform(Parameter::ModelViewProjection); + m_defaultTechnique->addParameter(mvpMat); + basicPass->addUniformBinding(mvpMat, "mvp"); + +// diffuse lighting uniforms + Parameter* lightPos = new Parameter(m_defaultTechnique, "lightPos", GL_FLOAT_VEC4); + m_defaultTechnique->addParameter(lightPos); + basicPass->addUniformBinding(lightPos, "lightPosition"); + + Parameter* lightIntensity = new Parameter(m_defaultTechnique, "lightIntensity", GL_FLOAT_VEC3); + m_defaultTechnique->addParameter(lightIntensity); + basicPass->addUniformBinding(lightIntensity, "lightIntensity"); + + Parameter* kd = new Parameter(m_defaultTechnique, "kd", GL_FLOAT_VEC3); + m_defaultTechnique->addParameter(kd); + basicPass->addUniformBinding(kd, "kd"); + + Parameter* ka = new Parameter(m_defaultTechnique, "ka", GL_FLOAT_VEC3); + m_defaultTechnique->addParameter(ka); + basicPass->addUniformBinding(ka, "ka"); +} + +void Renderer::buildDefaultMaterial() +{ + m_defaultMaterial = new Material; + m_defaultMaterial->setObjectName("DefaultMaterial"); + m_defaultMaterial->setParameter("lightPos", QVector4D(10.0f, 10.0f, 0.0f, 1.0f)); + m_defaultMaterial->setParameter("lightIntensity", QVector3D(0.5f, 0.5f, 0.5f)); + m_defaultMaterial->setParameter("ka", QVector3D(0.2f, 0.2f, 0.2f)); + m_defaultMaterial->setParameter("kd", QVector3D(1.0f, 0.5f, 0.0f)); + + Effect* defEff = new Effect; + defEff->addTechnique(m_defaultTechnique); + m_defaultMaterial->setEffect(defEff); +} + +Renderer::~Renderer() +{ + delete m_graphicsContext; + delete m_textureProvider; +} + +void Renderer::initialize() +{ + +} + +void Renderer::setFrameGraphRoot(FrameGraphNode *fgRoot) +{ + qDebug() << Q_FUNC_INFO; + m_frameGraphRoot = fgRoot; +} + +FrameGraphNode *Renderer::frameGraphRoot() const +{ + return m_frameGraphRoot; +} + +void Renderer::setSceneObject(Qt3D::Node *obj) +{ + Scene* sc = Scene::findInTree(obj); + if (sc) { + setSceneGraphRoot(sc); + } else + qWarning() << Q_FUNC_INFO << "couldn't find Scene object"; +} + +void Renderer::onFrame() +{ + render(); +} + +void Renderer::setSceneGraphRoot(Node *sgRoot) +{ + Q_ASSERT(sgRoot); + + // TODO: Unify this to one root node and scene builder + Scene *scene = Scene::findInTree(sgRoot); + if (scene) { + qDebug() << "building temporary backend"; + m_sceneGraphRoot = scene; + TemporaryBackendBuilder tbb(this); + tbb.traverse(m_sceneGraphRoot); + qDebug() << "done building backend"; + + QMetaObject::invokeMethod(m_frameTimer, "start"); + } else { + // Test new scene builder + m_sceneGraphRoot = sgRoot; + + RenderSceneBuilder builder(this); + builder.traverse(m_sceneGraphRoot); + RenderNode *root = builder.rootNode(); + if (!root) + qWarning() << "Failed to build render scene"; + m_renderSceneRoot = root; + + root->dump(); + + // Queue up jobs to do initial full updates of + // - Mesh loading + bounding volume calculation + // - Local bounding volumes + // - World transforms + // - World bounding volumes + } +} + +Node *Renderer::sceneGraphRoot() const +{ + return m_sceneGraphRoot; +} + +void Renderer::setCamera(Camera *cam) +{ + m_camera = cam; + m_renderCamera = new RenderCamera(m_rendererAspect); + m_renderCamera->setPeer(cam); + m_renderCamera->setProjection(cam->projectionMatrix()); + + m_graphicsContext->setCamera(m_renderCamera); +} + +void Renderer::setSurface(QSurface* s) +{ + qDebug() << Q_FUNC_INFO; + m_graphicsContext->setSurface(s); + + QSurfaceFormat sf = s->format(); + + QOpenGLContext* ctx = new QOpenGLContext; + ctx->setFormat(sf); + if (!ctx->create()) { + qWarning() << Q_FUNC_INFO << "OpenGL context creation failed"; + } + + m_graphicsContext->setOpenGLContext(ctx); +} + +void Renderer::setDefaultTechnique(Technique *t) +{ + Effect* defEff = m_defaultMaterial->effect(); + bool materialWasUsing = (defEff->techniques().front() == + m_defaultTechnique); + + m_defaultTechnique = t; + if (materialWasUsing) { + defEff->clearTechniques(); + defEff->addTechnique(t); + } +} + +void Renderer::setDefaultMaterial(Material *mat) +{ + m_defaultMaterial = mat; +} + +void Renderer::render() +{ + // Traverse the framegraph + // FrameGraphVisitor visitor; + // visitor.traverse(m_frameGraphRoot, this); + + // begin hack renderer + + if (!m_renderCamera) + return; + + m_renderCamera->sync(); + + m_graphicsContext->beginDrawing(); + + foreach (Drawable* dr, m_initList) + dr->initializeGL(m_graphicsContext); + m_initList.clear(); + + int err = glGetError(); + if (err) + qWarning() << "GL error before submitting bins:" << err; + + m_temporaryAllBin->sendDrawingCommands(m_graphicsContext); + + m_graphicsContext->endDrawing(); + + // end hack renderer +} + +void Renderer::doRender() +{ + // Render using current device state and renderer configuration + qDebug() << Q_FUNC_INFO; +} + +RenderTechnique* Renderer::techniqueForMaterial(Material* mat) +{ + Effect* eff = mat->effect(); + Technique *tech; + if (eff) { + Q_ASSERT(!eff->techniques().empty()); + + // FIXME - technique selection happens in here, now we know + // the renderer characteristics + tech = eff->techniques().front(); + } else { + tech = m_defaultTechnique; + } + + if (!m_techniqueHash.contains(tech)) { + RenderTechnique* rtech = createTechnique(tech); + m_techniqueHash[tech] = rtech; + } + + return m_techniqueHash.value(tech); +} + +RenderShader* Renderer::getOrCreateShader(ShaderProgram* sp) +{ + if (!m_shaderHash.contains(sp)) { + RenderShader* rs = new RenderShader(sp); + m_shaderHash[sp] = rs; + } + + return m_shaderHash.value(sp); +} + +RenderBin* Renderer::getOrCreateBinForPass(Technique* t, RenderPass* p) +{ + Q_UNUSED(t); + Q_UNUSED(p); + + // TODO - select bins by priority + + if (!m_temporaryAllBin) + m_temporaryAllBin = new OpaqueBin; + + return m_temporaryAllBin; +} + +RenderTechnique* Renderer::createTechnique(Technique* tech) +{ + RenderTechnique* rt = new RenderTechnique(tech); + for (unsigned int p=0; p<rt->passCount(); ++p) { + RenderPass* frontendPass = tech->renderPasses().at(p); + RenderShader* rshader = getOrCreateShader(frontendPass->shaderProgram()); + rt->setShaderForPass(p, rshader); + + RenderBin* bin = getOrCreateBinForPass(tech, frontendPass); + rt->setBinForPass(p, bin); + } + + return rt; +} + +RenderMaterial* Renderer::getOrCreateMaterial(Material* mat) +{ + if (!m_materialHash.contains(mat)) { + qDebug() << "creating render material for mat:" << mat->objectName(); + + RenderMaterial* rmat = new RenderMaterial(m_rendererAspect); + rmat->setPeer(mat); + rmat->setTextureProvider(m_textureProvider); + m_materialHash[mat] = rmat; + + // specifying technique will make the material sync parameter + // state from its peeer material. + rmat->setTechnique(techniqueForMaterial(mat)); + } + + return m_materialHash.value(mat); +} + +void Renderer::buildMeshes(Mesh* mesh, Material* mat, const QMatrix4x4& mm) +{ + if (mat == NULL) { + mat = m_defaultMaterial; + } + + RenderMaterial* rmat = getOrCreateMaterial(mat); + RenderTechnique* t = rmat->technique(); + + for (unsigned int p=0; p<t->passCount(); ++p) { + RenderBin* bin = t->binForPass(p); + + RenderMesh* rmesh = new RenderMesh(mesh); + rmesh->setData(mesh->data()); + rmesh->setTechniqueAndPass(t, p); + rmesh->setModelMatrix(mm); + rmesh->setMaterial(rmat); + + m_initList.push_back(rmesh); + bin->addDrawable(rmesh); + + } // of technique pass iteration +} + +void Renderer::buildShape(Shape* shape, Material* mat, const QMatrix4x4& mm) +{ + if (mat == NULL) { + mat = m_defaultMaterial; + } + + MeshDataPtr shapeMeshData = shape->data(); + RenderMaterial* rmat = getOrCreateMaterial(mat); + RenderTechnique* t = rmat->technique(); + + for (unsigned int p=0; p<t->passCount(); ++p) { + RenderBin* bin = t->binForPass(p); + + RenderMesh* rmesh = new RenderMesh(NULL); + rmesh->setData(shapeMeshData); + rmesh->setTechniqueAndPass(t, p); + rmesh->setModelMatrix(mm); + rmesh->setMaterial(rmat); + + m_initList.push_back(rmesh); + bin->addDrawable(rmesh); + + } // of technique pass iteration +} + + +void Renderer::foundCamera(Camera *cam, const QMatrix4x4 &mm) +{ + Q_UNUSED(mm); + cam->setViewMatrix(mm.inverted()); + setCamera(cam); +} + +} // namespace Render +} // namespace Qt3D diff --git a/src/render/backend/renderer.h b/src/render/backend/renderer.h new file mode 100644 index 000000000..40bc3eefa --- /dev/null +++ b/src/render/backend/renderer.h @@ -0,0 +1,171 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3D_RENDER_RENDERER_H +#define QT3D_RENDER_RENDERER_H + +#include <technique.h> + +#include <QHash> +#include <QMatrix4x4> +#include <QObject> +#include <QTimer> + +#include <QOpenGLShaderProgram> +#include <QOpenGLVertexArrayObject> +#include <QOpenGLBuffer> + +class QSurface; + +namespace Qt3D { + +class Camera; +class Entity; +class RenderBin; +class Material; +class RenderMaterial; +class RenderTechnique; +class ShaderProgram; +class RenderShader; +class Mesh; +class RenderPass; +class QGraphicsContext; +class RenderCamera; +class Drawable; +class RenderTextureProvider; +class Shape; +class RendererAspect; + +namespace Render { + +class FrameGraphNode; +class RenderNode; +class MeshManager; + +class Renderer : public QObject +{ + Q_OBJECT +public: + Renderer(); + ~Renderer(); + + void setRendererAspect(RendererAspect *rendererAspect) { m_rendererAspect = rendererAspect; } + RendererAspect *rendererAspect() const { return m_rendererAspect; } + + void setFrameGraphRoot(FrameGraphNode *fgRoot); + FrameGraphNode *frameGraphRoot() const; + + void setSceneObject(Qt3D::Node *obj); + void setSceneGraphRoot(Qt3D::Node *sgRoot); + Qt3D::Node *sceneGraphRoot() const; + + RenderNode *renderSceneRoot() const { return m_renderSceneRoot; } + + void setCamera(Camera* cam); + + void render(); + void doRender(); + + MeshManager *meshManager() const { return m_meshManager; } + + // temporary! + + RenderTechnique* techniqueForMaterial(Material* mat); + + void buildMeshes(Mesh *mesh, Material *mat, const QMatrix4x4& mm); + void buildShape(Shape *shape, Material *mat, const QMatrix4x4 &mm); + + void foundCamera(Camera* cam, const QMatrix4x4& mm); + + Q_INVOKABLE void setSurface(QSurface *s); + + void setDefaultTechnique(Technique* t); + void setDefaultMaterial(Material* mat); + +protected: + Q_INVOKABLE void initialize(); + +private slots: + void onFrame(); + +private: + RendererAspect *m_rendererAspect; + + // Frame graph root + FrameGraphNode *m_frameGraphRoot; + + Qt3D::Node *m_sceneGraphRoot; + RenderNode *m_renderSceneRoot; + + Camera *m_camera; + RenderCamera* m_renderCamera; + + QHash<Material*, RenderMaterial*> m_materialHash; + QHash<Technique *, RenderTechnique*> m_techniqueHash; + QHash<ShaderProgram*, RenderShader*> m_shaderHash; + + RenderBin *getOrCreateBinForPass(Technique *t, RenderPass *p); + + RenderTechnique *createTechnique(Technique *tech); + RenderShader *getOrCreateShader(ShaderProgram *sp); + RenderMaterial *getOrCreateMaterial(Material *mat); + + Material* m_defaultMaterial; + Technique* m_defaultTechnique; + + QGraphicsContext* m_graphicsContext; + RenderBin* m_temporaryAllBin; + RenderTextureProvider* m_textureProvider; + MeshManager *m_meshManager; + + QTimer* m_frameTimer; + + /// list of drawables to be initialized next frame + QList<Drawable*> m_initList; + + void buildDefaultMaterial(); + void buildDefaultTechnique(); +}; + +} // namespace Render +} // namespace Qt3D + +#endif // QT3D_RENDER_RENDERER_H diff --git a/src/render/backend/rendereraspect.cpp b/src/render/backend/rendereraspect.cpp new file mode 100644 index 000000000..0d63a7c0f --- /dev/null +++ b/src/render/backend/rendereraspect.cpp @@ -0,0 +1,129 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "rendereraspect.h" + +#include "meshmanager.h" +#include "renderer.h" +#include "renderthread.h" + +#include <jobs/loadmeshdatajob.h> +#include <jobs/updateworldtransformjob.h> +#include <jobs/updateboundingvolumejob.h> + +#include <node.h> + +#include <QDebug> +#include <QThread> +#include <QWindow> + +namespace Qt3D { + +RendererAspect::RendererAspect(QObject *parent) + : AbstractAspect(AbstractAspect::AspectRenderer, parent) + , m_renderThread(new RenderThread) +{ + qRegisterMetaType<QSurface*>("QSurface*"); + qRegisterMetaType< QSharedPointer<QObject> >("QObjectPtr"); + m_renderThread->waitForStart(); + m_renderThread->renderer()->setRendererAspect(this); +} + +void RendererAspect::setWindow(QWindow *window) +{ + Q_ASSERT(window); + QSurface* surface = window; + + Render::Renderer *renderer = m_renderThread->renderer(); + QMetaObject::invokeMethod(renderer, "setSurface", Q_ARG(QSurface*, surface)); +} + +QVector<QJobPtr> RendererAspect::jobsToExecute() +{ + // Create jobs that will get exectued by the threadpool + QVector<QJobPtr> jobs; + +// Render::UpdateWorldTransformJobPtr worldTransformJob(new Render::UpdateWorldTransformJob(m_renderThread->renderer()->renderSceneRoot())); +// Render::UpdateBoundingVolumeJobPtr boundingVolumeJob(new Render::UpdateBoundingVolumeJob(m_renderThread->renderer())); + +// // We can only update bounding volumes once all world transforms are known +// boundingVolumeJob->addDependency(worldTransformJob); + +// // Add all jobs to queue +// jobs.append(worldTransformJob); +// jobs.append(boundingVolumeJob); + + // Create jobs to load in any meshes that are pending + QList< QPair<QString,MeshDataPtr> > meshes = m_renderThread->renderer()->meshManager()->meshesPending(); + for (int i = 0; i < meshes.size(); ++i ) { + const QPair<QString, MeshDataPtr> &meshDataInfo = meshes.at(i); + Render::LoadMeshDataJobPtr loadMeshJob(new Render::LoadMeshDataJob(meshDataInfo.first, meshDataInfo.second)); + jobs.append(loadMeshJob); + } + m_renderThread->renderer()->meshManager()->clearMeshesPending(); + + return jobs; +} + +void RendererAspect::registerAspectHelper(Node *rootObject) +{ + Render::Renderer *renderer = m_renderThread->renderer(); + renderer->setSceneGraphRoot(rootObject); +} + +void RendererAspect::unregisterAspectHelper(Node *rootObject) +{ +} + +void RendererAspect::initializeHelper(QAspectManager *aspectManager) +{ + Q_UNUSED(aspectManager); + Render::Renderer *renderer = m_renderThread->renderer(); + QMetaObject::invokeMethod(renderer, "initialize"); +} + +void RendererAspect::cleanupHelper() +{ + Render::Renderer *renderer = m_renderThread->renderer(); + //QMetaObject::invokeMethod(renderer, "cleanup"); +} + +} diff --git a/src/render/backend/rendereraspect.h b/src/render/backend/rendereraspect.h new file mode 100644 index 000000000..3fd04744f --- /dev/null +++ b/src/render/backend/rendereraspect.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef RENDERERASPECT_H +#define RENDERERASPECT_H + +#include "abstractaspect.h" + +namespace Qt3D { +class RenderThread; +} + +class QWindow; + +namespace Qt3D { + +class RendererAspect : public AbstractAspect +{ + Q_OBJECT +public: + explicit RendererAspect(QObject *parent = 0); + + virtual void setWindow(QWindow *window); + + QVector<QJobPtr> jobsToExecute() Q_DECL_OVERRIDE; + +protected: + void registerAspectHelper(Node *rootObject) Q_DECL_OVERRIDE; + void unregisterAspectHelper(Node *rootObject) Q_DECL_OVERRIDE; + + void initializeHelper(QAspectManager *aspectManager); + void cleanupHelper(); + +private: + RenderThread* m_renderThread; +}; + +} + +#endif // RENDERERASPECT_H diff --git a/src/render/backend/rendermaterial.cpp b/src/render/backend/rendermaterial.cpp new file mode 100644 index 000000000..b74bf5954 --- /dev/null +++ b/src/render/backend/rendermaterial.cpp @@ -0,0 +1,204 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "rendermaterial.h" + +#include "rendereraspect.h" +#include "qgraphicscontext.h" +#include "rendertechnique.h" +#include "rendertextureprovider.h" + +#include <technique.h> // for Parameter +#include <material.h> + +#include <qaspectmanager.h> + +#include <QOpenGLShaderProgram> + +namespace Qt3D +{ + +RenderMaterial::RenderMaterial(RendererAspect *rendererAspect) + : m_rendererAspect(rendererAspect) + , m_textureProvider(NULL) +{ +} + +RenderMaterial::~RenderMaterial() +{ + qDeleteAll(m_packs); + m_packs.clear(); +} + +void RenderMaterial::setTextureProvider(RenderTextureProvider* rtp) +{ + m_textureProvider = rtp; +} + +void RenderMaterial::setPeer(Material *mat) +{ + m_peer = mat; + + // Register for changes + QChangeArbiter *arbiter = m_rendererAspect->aspectManager()->changeArbiter(); + arbiter->registerObserver(this, m_peer, MaterialParameter); +} + +void RenderMaterial::setEffectName(QString nm) +{ + Q_UNUSED(nm); +} + +void RenderMaterial::setParameter(QString paramName, QVariant varVal) +{ + Parameter* param = m_technique->parameterByName(paramName); + if (!param) { + return; + } + + if (param->isTextureType()) { + // handle samplers separately + return; + } + + if (param->isStandardUniform()) { + qWarning() << Q_FUNC_INFO << "setting standard uniform explicit for" << paramName; + return; + } + + Render::QUniformValue uval(param->uniformType(), varVal); + + QStringList names(m_technique->glslNamesForUniformParameter(paramName)); + Q_ASSERT(names.count() == (int) m_technique->passCount()); + + for (unsigned int p=0; p<m_technique->passCount(); ++p) { + if (names.at(p).isEmpty()) + continue; // not set in this pass + + m_packs.at(p)->setUniform(names.at(p), uval); + } // of pass iteration +} + +void RenderMaterial::setTextureParameter(QString paramName, RenderTexturePtr tex) +{ + Q_ASSERT(tex); + Parameter* param = m_technique->parameterByName(paramName); + if (!param) + return; + + Q_ASSERT(param->isTextureType()); + + QStringList names(m_technique->glslNamesForUniformParameter(paramName)); + Q_ASSERT(names.count() == (int) m_technique->passCount()); + + for (unsigned int p=0; p<m_technique->passCount(); ++p) { + if (names.at(p).isEmpty()) + continue; // not set in this pass + + m_packs.at(p)->setTexture(names.at(p), tex); + } // of pass iteration +} + +void RenderMaterial::syncParametersFromPeer() +{ + Q_ASSERT(m_peer); + foreach (QString nm, m_peer->parameterValues().keys()) { + QVariant val = m_peer->parameterValues().value(nm); + if (!val.isValid()) { + qWarning() << Q_FUNC_INFO << "bad value:" << val << "for parameter" << nm; + continue; + } + setParameter(nm, val); + } + + // FIXME - should do this on demand, otherwise we're re-uploading + // for no good reason + foreach (QString nm, m_peer->textureValues().keys()) { + Texture* t = m_peer->textureValues().value(nm); + setTextureParameter(nm, m_textureProvider->get(t)); + } +} + +void RenderMaterial::setTechnique(RenderTechnique *rt) +{ + m_technique = rt; + + // could re-use packs, but techniques don't change often + qDeleteAll(m_packs); + m_packs.clear(); + + // allocate pack per pass - or should we do this lazily? + for (unsigned int p=0; p<rt->passCount(); ++p) + m_packs.append(new Render::QUniformPack); + + if (m_peer) + syncParametersFromPeer(); +} + +RenderTechnique *RenderMaterial::technique() const +{ + return m_technique; +} + +void RenderMaterial::setUniformsForPass(unsigned int pass, QGraphicsContext *gc) +{ + Q_ASSERT((int) pass < m_packs.size()); + m_packs.at(pass)->apply(gc); +} + +void RenderMaterial::sceneChangeEvent(const QSceneChangePtr &e) +{ + switch (e->m_type) { + case MaterialParameter: { + QScenePropertyChangePtr propertyChange = qSharedPointerCast<QScenePropertyChange>(e); + QString propertyName = propertyChange->m_propertyName; + QVariant propertyValue = propertyChange->m_value; + setParameter(propertyName, propertyValue); + break; + } + + default: + break; + } +} + +} // of namespace Qt3D + diff --git a/src/render/backend/rendermaterial.h b/src/render/backend/rendermaterial.h new file mode 100644 index 000000000..d216bdec1 --- /dev/null +++ b/src/render/backend/rendermaterial.h @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef RENDERMATERIAL_H +#define RENDERMATERIAL_H + +#include <QVariant> + +#include <qchangearbiter.h> + +#include <quniformvalue.h> +#include <rendertextureprovider.h> + +namespace Qt3D +{ + +class Material; +class RenderTechnique; +class QGraphicsContext; +class RendererAspect; + +class RenderMaterial : public QObserverInterface +{ +public: + RenderMaterial(RendererAspect *rendererAspect); + ~RenderMaterial(); + + void setPeer(Material* mat); + + void setEffectName(QString nm); + + void setParameter(QString paramName, QVariant value); + + void setTextureParameter(QString paramName, RenderTexturePtr tex); + + void syncParametersFromPeer(); + + /** + * @brief setTechnique - specify the effect technique to use for + * rendering this material. + * @param rt + */ + void setTechnique(RenderTechnique* rt); + RenderTechnique* technique() const; + + void setUniformsForPass(unsigned int pass, QGraphicsContext* gc); + + void setTextureProvider(RenderTextureProvider *rtp); + + void sceneChangeEvent(const QSceneChangePtr &e) Q_DECL_OVERRIDE; + +private: + RendererAspect *m_rendererAspect; + Material* m_peer; + QString m_effectName; + RenderTechnique* m_technique; + RenderTextureProvider* m_textureProvider; + + QVector<Render::QUniformPack*> m_packs; +}; + +} + +#endif // RENDERMATERIAL_H diff --git a/src/render/backend/rendermesh.cpp b/src/render/backend/rendermesh.cpp new file mode 100644 index 000000000..b7e3252c6 --- /dev/null +++ b/src/render/backend/rendermesh.cpp @@ -0,0 +1,333 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "rendermesh.h" + +#include "rendertechnique.h" +#include "rendermaterial.h" + +#include "qgraphicscontext.h" +#include <meshdata.h> +#include <technique.h> + +#include <QOpenGLContext> +#include <QOpenGLFunctions_3_3_Core> +#include <QOpenGLShaderProgram> + +namespace Qt3D { + +RenderMesh::RenderMesh(Mesh* peer) + : Drawable( ), + m_peer(peer), + m_technique(0), + m_pass(0), + m_material(0), + m_instanceCount( 0 ), + m_funcs(0) +{ +} + +void RenderMesh::setData(MeshDataPtr mesh) +{ + m_meshData = mesh; + m_meshDirty = true; + // clear bounding box? +} + +void RenderMesh::setTechniqueAndPass(RenderTechnique* tech, unsigned int pass) +{ + m_technique = tech; + m_pass = pass; +} + +void RenderMesh::setMaterial(RenderMaterial *rmat) +{ + m_material = rmat; +} + +void RenderMesh::setInstanceCount(unsigned int count) +{ + m_instanceCount = count; +} + +void RenderMesh::setModelMatrix(const QMatrix4x4 &mm) +{ + m_modelMatrix = mm; +} + +DrawStateSet *RenderMesh::stateSet() +{ + return m_technique->stateSetForPass(m_pass); +} + + +void RenderMesh::initializeGL(QGraphicsContext* gc) +{ + m_vao.create(); + m_vao.bind(); + + gc->activateShader(m_technique->shaderForPass(m_pass)); + + foreach (QString nm, m_meshData->attributeNames()) { + AttributePtr attr(m_meshData->attributeByName(nm)); + QString glsl = m_technique->glslNameForMeshAttribute(m_pass, nm); + if (glsl.isEmpty()) + continue; // not used in this pass + gc->specifyAttribute(glsl, attr); + } + + m_drawIndexed = (m_meshData->indexAttr() != NULL); + if (m_drawIndexed) { + gc->specifyIndices(m_meshData->indexAttr()); + } + + m_vao.release(); + + // TODO Be careful about where we do this OpenGL work + QOpenGLContext* ctx = QOpenGLContext::currentContext(); + m_funcs = ctx->versionFunctions<QOpenGLFunctions_3_3_Core>(); + if ( m_funcs ) + m_funcs->initializeOpenGLFunctions(); + else + qWarning() << Q_FUNC_INFO << "couldn't resolve 3.3 core functions"; +}; + +void RenderMesh::releaseGL() +{ + m_vao.destroy(); +} + +void RenderMesh::sendDrawingCommands(QGraphicsContext* gc) +{ + if (gc->activeMaterial() != m_material) { + gc->setActiveMaterial(m_material); + m_material->setUniformsForPass(m_pass, gc); + } + + gc->setModelMatrix(m_modelMatrix); + + m_vao.bind(); + GLint primType = m_meshData->primitiveType(); + GLint primCount = m_meshData->primitiveCount(); + GLint indexType = m_drawIndexed ? m_meshData->indexAttr()->type() : 0; + + if (m_instanceCount > 0) { + if ( m_drawIndexed ) { + m_funcs->glDrawElementsInstanced(primType, primType, indexType, 0, m_instanceCount); + } else { + m_funcs->glDrawArraysInstanced(primType, 0, primCount, m_instanceCount); + } + } else { + if ( m_drawIndexed ) { + m_funcs->glDrawElements(primType, primCount, indexType, + reinterpret_cast<void*>(m_meshData->indexAttr()->byteOffset())); + } else { + m_funcs->glDrawArrays(primType, 0, primCount); + } + } // non-instanced drawing + + int err = glGetError(); + if (err) + qWarning() << "GL error after drawing mesh:" << QString::number(err, 16); + + + m_vao.release(); +} + +RenderShader *RenderMesh::shader() +{ + return m_technique->shaderForPass(m_pass); +} + +AxisAlignedBoundingBox RenderMesh::boundingBox() const +{ + if (!m_meshData) + return AxisAlignedBoundingBox(); + + return m_meshData->boundingBox(); +} + +#if 0 +static bool areIndicesShort( const QVector<unsigned int>& indices ) +{ + // optimization; check the last index first, since it is often + // (but not always) going to be the larger index values + if (indices.back() > 0xffff) { + return false; + } + + for (int i=0; i<indices.size(); ++i) { + if (indices.at(i) > 0xffff) { + return false; + } + } // of indices iteration + + return true; +} + +void RenderMesh::setMeshData( DrawContext& dc ) +{ + // Construct buffers for the vertices, normals, texCoord, tangents and indices + QVector<QVector3D> points = m_loader->vertices(); + QVector<QVector3D> normals = m_loader->normals(); + QVector<QVector2D> texCoords = m_loader->textureCoordinates(); + QVector<QVector4D> tangents = m_loader->tangents(); + + int vertexCount = points.size(); + QVector<unsigned int> elements = m_loader->indices(); + m_drawCount = elements.size(); + int faces = elements.size() / 3; + + bool shortIndices = areIndicesShort(elements); + + /** \todo Use QScopedPointers or try reinterpret_cast on the + * QVector<> objects. + */ + float* v = new float[3 * vertexCount]; + float* n = new float[3 * vertexCount]; + float* tc = 0; + float* tang = 0; + + if ( !texCoords.isEmpty() ) + { + tc = new float[ 2 * vertexCount ]; + if ( !tangents.isEmpty() ) + tang = new float[ 4 * vertexCount ]; + } + + int idx = 0, tcIdx = 0, tangIdx = 0; + for ( int i = 0; i < vertexCount; ++i ) + { + v[idx] = points[i].x(); + v[idx+1] = points[i].y(); + v[idx+2] = points[i].z(); + n[idx] = normals[i].x(); + n[idx+1] = normals[i].y(); + n[idx+2] = normals[i].z(); + idx += 3; + if ( tc != 0 ) + { + tc[tcIdx] = texCoords[i].x(); + tc[tcIdx+1] = texCoords[i].y(); + tcIdx += 2; + } + if ( tang != 0 ) + { + tang[tangIdx] = tangents[i].x(); + tang[tangIdx+1] = tangents[i].y(); + tang[tangIdx+2] = tangents[i].z(); + tang[tangIdx+3] = tangents[i].w(); + tangIdx += 4; + } + } + + m_mode = GL_TRIANGLES; + + // Create and populate the buffer objects + m_positionBuffer.create(); + m_positionBuffer.setUsagePattern( QOpenGLBuffer::StaticDraw ); + m_positionBuffer.bind(); + m_positionBuffer.allocate( v, 3 * vertexCount * sizeof( float ) ); + + m_normalBuffer.create(); + m_normalBuffer.setUsagePattern( QOpenGLBuffer::StaticDraw ); + m_normalBuffer.bind(); + m_normalBuffer.allocate( n, 3 * vertexCount * sizeof( float ) ); + + if ( tc ) + { + m_textureCoordBuffer.create(); + m_textureCoordBuffer.setUsagePattern( QOpenGLBuffer::StaticDraw ); + m_textureCoordBuffer.bind(); + m_textureCoordBuffer.allocate( tc, 2 * vertexCount * sizeof( float ) ); + } + + if ( tang ) + { + m_tangentBuffer.create(); + m_tangentBuffer.setUsagePattern( QOpenGLBuffer::StaticDraw ); + m_tangentBuffer.bind(); + m_tangentBuffer.allocate( tang, 4 * vertexCount * sizeof( float ) ); + } + + if ( shortIndices ) { + unsigned short* el = new unsigned short[elements.size()]; + for ( int i = 0; i < elements.size(); ++i ) + el[i] = static_cast<unsigned short>(elements[i]); + + m_indexBuffer.create(); + m_indexBuffer.setUsagePattern( QOpenGLBuffer::StaticDraw ); + m_indexBuffer.bind(); + m_indexBuffer.allocate( el, 3 * faces * sizeof( unsigned short ) ); + m_indexType = GL_UNSIGNED_SHORT; + delete[] el; + } else { + unsigned int* el = new unsigned int[elements.size()]; + for ( int i = 0; i < elements.size(); ++i ) + el[i] = elements[i]; + + m_indexBuffer.create(); + m_indexBuffer.setUsagePattern( QOpenGLBuffer::StaticDraw ); + m_indexBuffer.bind(); + m_indexBuffer.allocate( el, 3 * faces * sizeof( unsigned int ) ); + m_indexType = GL_UNSIGNED_INT; + + delete[] el; + } + + // Calculate the bounding volume + // m_boundingVolume->update( points ); + + // Clean up + delete[] v; + delete[] n; + if ( tc != NULL ) + delete[] tc; + if ( tang != NULL ) + delete[] tang; + + m_loader.reset(); + + setupVertexArrayObject( dc ); +} +#endif + +} diff --git a/src/render/backend/rendermesh.h b/src/render/backend/rendermesh.h new file mode 100644 index 000000000..5f2c0cdf8 --- /dev/null +++ b/src/render/backend/rendermesh.h @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef RENDERMESH_H +#define RENDERMESH_H + +#include "drawable.h" + +#include <meshdata.h> +#include <axisalignedboundingbox.h> + +#include <QOpenGLVertexArrayObject> +#include <QMatrix4x4> + +class QOpenGLFunctions_3_3_Core; + +namespace Qt3D { + +class Mesh; +class RenderNode; +class RenderPass; +class RenderMaterial; +class RenderTechnique; + +class RenderMesh : public Drawable +{ +public: + explicit RenderMesh(Mesh* peer); + + void setPeer(Mesh* peer); + + void setData(MeshDataPtr mesh); + + void setTechniqueAndPass(RenderTechnique* tech, unsigned int pass); + + void setMaterial(RenderMaterial* rmat); + + void setInstanceCount(unsigned int count); + + void setModelMatrix(const QMatrix4x4& mm); + + virtual DrawStateSet* stateSet(); + + /** + * @brief mapAttributeNames - resolve mapping of mesh-data attribute + * names to parameters. + * @param t + */ + void mapAttributeNames(); + + virtual void initializeGL(QGraphicsContext* dc); + + virtual void releaseGL(); + +protected: + virtual void sendDrawingCommands( QGraphicsContext* dc ); + + virtual RenderShader* shader(); + + virtual AxisAlignedBoundingBox boundingBox() const; + +private: + + + Mesh* m_peer; + + MeshDataPtr m_meshData; + + RenderTechnique* m_technique; + unsigned int m_pass; + + RenderMaterial* m_material; + + bool m_drawIndexed; + bool m_meshDirty; + unsigned int m_instanceCount; + + QOpenGLVertexArrayObject m_vao; + + QOpenGLFunctions_3_3_Core *m_funcs; + + QMatrix4x4 m_modelMatrix; +}; + +} + +#endif // RENDERMESH_H diff --git a/src/render/backend/rendernode.cpp b/src/render/backend/rendernode.cpp new file mode 100644 index 000000000..d9feb14f0 --- /dev/null +++ b/src/render/backend/rendernode.cpp @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "rendernode.h" +#include "rendereraspect.h" + +#include <transform.h> + +#include <qaspectmanager.h> +#include <sphere.h> +#include <entity.h> + +#include <QMatrix4x4> +#include <QString> +#include <QDebug> + +namespace Qt3D { +namespace Render { + +// TODO: Create custom allocators for each of the matrices and +// bounding volumes to that they end up in contiguous arrays. + +RenderNode::RenderNode(RendererAspect *rendererAspect, RenderNode *parent) + : m_rendererAspect(rendererAspect) + , m_parent(parent) + , m_localTransform(new QMatrix4x4) + , m_worldTransform(new QMatrix4x4) + , m_localBoundingVolume(new Qt3D::Sphere) + , m_worldBoundingVolume(new Qt3D::Sphere) + , m_frontEndPeer(0) +{ + if (parent) + parent->m_children.append(this); +} + +void RenderNode::setPeer(Transform *transform) +{ + m_peer = transform; + + // Register for changes + QChangeArbiter *arbiter = m_rendererAspect->aspectManager()->changeArbiter(); + arbiter->registerObserver(this, m_peer, LocalTransform); +} + +void RenderNode::sceneChangeEvent(const QSceneChangePtr &e) +{ + switch (e->m_type) { + case LocalTransform: { + QScenePropertyChangePtr propertyChange = qSharedPointerCast<QScenePropertyChange>(e); + *m_localTransform = propertyChange->m_value.value<QMatrix4x4>(); + break; + } + + default: + break; + } +} + +void RenderNode::dump() const +{ + static int depth = 0; + QString indent(2 * depth++, QChar::fromLatin1(' ')); + qDebug() << indent + m_frontEndPeer->objectName(); + foreach (const RenderNode *child, m_children) + child->dump(); + --depth; +} + +} // namespace Render +} // namespace Qt3D diff --git a/src/render/backend/rendernode.h b/src/render/backend/rendernode.h new file mode 100644 index 000000000..480c8b3ed --- /dev/null +++ b/src/render/backend/rendernode.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3D_RENDER_RENDERNODE_H +#define QT3D_RENDER_RENDERNODE_H + +#include <qchangearbiter.h> + +#include <QVector> + +class QMatrix4x4; + +namespace Qt3D { + +class RendererAspect; +class Sphere; +class Node; +class Transform; + +namespace Render { + +class RenderNode : public QObserverInterface +{ +public: + explicit RenderNode(RendererAspect *rendererAspect, RenderNode *parent = 0); + + void setPeer(Transform *transform); + void sceneChangeEvent(const QSceneChangePtr &e) Q_DECL_OVERRIDE; + + void dump() const; + +//private: + RendererAspect *m_rendererAspect; + Transform *m_peer; + RenderNode *m_parent; + QVector<RenderNode *> m_children; + QMatrix4x4 *m_localTransform; + QMatrix4x4 *m_worldTransform; + Sphere *m_localBoundingVolume; + Sphere *m_worldBoundingVolume; + + // TODO: Do we want to force this to be an Entity? + // That would mean forcing an Entity for the root on the main thread's scene + Node *m_frontEndPeer; + + // TODO: Add pointer to Drawable or references to VBO's and other info needed to draw +}; + +} // namespace Render +} // namespace Qt3D + +#endif // QT3D_RENDER_RENDERNODE_H diff --git a/src/render/backend/renderscenebuilder.cpp b/src/render/backend/renderscenebuilder.cpp new file mode 100644 index 000000000..9e861d65f --- /dev/null +++ b/src/render/backend/renderscenebuilder.cpp @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "renderscenebuilder.h" + +#include "meshmanager.h" +#include "renderer.h" +#include "rendernode.h" + +#include <camera.h> +#include <material.h> +#include <mesh.h> +#include <transform.h> + +#include <entity.h> + +namespace Qt3D { +namespace Render { + +RenderSceneBuilder::RenderSceneBuilder(Renderer *renderer) + : Qt3D::NodeVisitor() + , m_renderer(renderer) + , m_rootNode(0) +{ +} + +void RenderSceneBuilder::visitNode(Qt3D::Node *node) +{ + if (!m_rootNode) { + m_rootNode = new RenderNode(m_renderer->rendererAspect()); + m_rootNode->m_frontEndPeer = node; + m_nodeStack.push(m_rootNode); + } + + Qt3D::NodeVisitor::visitNode(node); +} + +void RenderSceneBuilder::visitEntity(Qt3D::Entity *entity) +{ + // Create a RenderNode corresponding to the Entity. Most data will + // be calculated later by jobs + RenderNode *renderNode = new RenderNode(m_renderer->rendererAspect(), m_nodeStack.top()); + renderNode->m_frontEndPeer = entity; + *(renderNode->m_localTransform) = entity->matrix(); + m_nodeStack.push(renderNode); + + // Look for a transform component + QList<Transform *> transforms = entity->componentsOfType<Transform>(); + if (!transforms.isEmpty()) + renderNode->setPeer(transforms.first()); + +// QList<Material *> materials = entity->componentsOfType<Material>(); +// Material *material = 0; +// if (!materials.isEmpty()) +// material = materials.first(); + + // We'll update matrices in a job later. In fact should the matrix be decoupled from the mesh? + foreach (Mesh *mesh, entity->componentsOfType<Mesh>()) { + m_renderer->meshManager()->addMesh(mesh); + //m_renderer->buildMeshes(mesh, material, QMatrix4x4()); + } + + //foreach (Camera *camera, entity->componentsOfType<Camera>()) + // m_renderer->foundCamera(camera, entity->sceneMatrix()); + + NodeVisitor::visitEntity(entity); + + // Coming back up the tree + m_nodeStack.pop(); +} + +} // namespace Render +} // namespace Qt3D diff --git a/src/render/backend/renderscenebuilder.h b/src/render/backend/renderscenebuilder.h new file mode 100644 index 000000000..2f3812f26 --- /dev/null +++ b/src/render/backend/renderscenebuilder.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3D_RENDER_RENDERSCENEBUILDER_H +#define QT3D_RENDER_RENDERSCENEBUILDER_H + +#include <nodevisitor.h> + +#include <QStack> + +namespace Qt3D { +namespace Render { + +class Renderer; +class RenderNode; + +class RenderSceneBuilder : public Qt3D::NodeVisitor +{ +public: + explicit RenderSceneBuilder(Renderer *renderer); + + RenderNode *rootNode() const { return m_rootNode; } + +protected: + void visitNode(Qt3D::Node *node) Q_DECL_OVERRIDE; + void visitEntity(Qt3D::Entity *entity) Q_DECL_OVERRIDE; + +private: + Renderer *m_renderer; + RenderNode *m_rootNode; + QStack<RenderNode *> m_nodeStack; +}; + +} // namespace Render +} // namespace Qt3D + +#endif // QT3D_RENDER_RENDERSCENEBUILDER_H diff --git a/src/render/backend/rendershader.cpp b/src/render/backend/rendershader.cpp new file mode 100644 index 000000000..243cf4ffa --- /dev/null +++ b/src/render/backend/rendershader.cpp @@ -0,0 +1,150 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "rendershader.h" + +#include <QDebug> +#include <QOpenGLContext> +#include <QOpenGLShaderProgram> + +#include <shaderprogram.h> + +namespace Qt3D +{ + +RenderShader::RenderShader(ShaderProgram *peer) : + m_program(NULL), + m_peer(peer) +{ + Q_ASSERT(peer); +} + +QOpenGLShaderProgram *RenderShader::getOrCreateProgram() +{ + if (!m_program) { + // waiting for shader source to be loaded + if (!m_peer->isLoaded()) { + + // FIXME - should not be done in the backend! + m_peer->load(); + //return NULL; + } + + m_program = createProgram(); + if (!m_program) + m_program = createDefaultProgram(); + } + + return m_program; +} + +void RenderShader::setStandardUniform(Parameter::StandardUniform su, QString name) +{ + Q_ASSERT(su != Parameter::None); + Q_ASSERT(!name.isEmpty()); + int index = static_cast<int>(su); + if (index >= m_standardUniformNames.size()) + m_standardUniformNames.resize(index + 1); + m_standardUniformNames[index] = name; +} + +QString RenderShader::name() const +{ + return m_peer->objectName(); +} + +QOpenGLShaderProgram* RenderShader::createProgram() +{ + Q_ASSERT(QOpenGLContext::currentContext()); + // scoped pointer so early-returns delete automatically + QScopedPointer<QOpenGLShaderProgram> p(new QOpenGLShaderProgram); + bool ok = p->addShaderFromSourceCode(QOpenGLShader::Vertex, + m_peer->vertexSourceCode()); + if (!ok) { + qWarning() << "bad vertex source:" << m_program->log(); + return NULL; + } + + ok = p->addShaderFromSourceCode(QOpenGLShader::Fragment, + m_peer->fragmentSourceCode()); + if (!ok) { + qWarning() << "bad fragment source:" << m_program->log(); + return NULL; + } + + ok = p->link(); + if (!ok) { + qWarning() << "program failed to link:" << m_program->log(); + return NULL; + } + + m_standardUniformLocations.resize(m_standardUniformNames.size()); + for (int i=0; i<m_standardUniformNames.size(); ++i) { + QString n = m_standardUniformNames.at(i); + if (n.isEmpty()) { + m_standardUniformLocations[i] = -1; + continue; + } + + m_standardUniformLocations[i] = p->uniformLocation(n); + // qDebug() << "resolved location" << m_standardUniformLocations[i] << + // "for uniform" << n; + } + + // take from scoped-pointer so it doesn't get deleted + return p.take(); +} + +QOpenGLShaderProgram* RenderShader::createDefaultProgram() +{ + QOpenGLShaderProgram* p = new QOpenGLShaderProgram; + p->addShaderFromSourceCode(QOpenGLShader::Vertex, + ""); + + p->addShaderFromSourceCode(QOpenGLShader::Fragment, + ""); + + p->link(); + + return p; +} + +} // of namespace Qt3D diff --git a/src/render/backend/rendershader.h b/src/render/backend/rendershader.h new file mode 100644 index 000000000..0b326e02d --- /dev/null +++ b/src/render/backend/rendershader.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef RENDERSHADER_H +#define RENDERSHADER_H + +#include <QVector> + +// for Parameter::StandardUniforms enum - maybe should move to +// somewhere common to avoid this include? +#include <technique.h> + +class QOpenGLShaderProgram; + +namespace Qt3D +{ + +class ShaderProgram; + +class RenderShader +{ +public: + RenderShader(ShaderProgram* peer); + + /** + * @brief getOrCreateProgram + * must be called with a valid, current QOpenGLContext + * @return + */ + QOpenGLShaderProgram* getOrCreateProgram(); + + /** + * @brief setStandardUniform - set the program name of a uniform + * @param su - the standard uniform + * @param loc - the GLSL name corresponding to the uniform + */ + void setStandardUniform(Parameter::StandardUniform su, QString name); + + /** + * @brief standardUniformLocations - vecotr of uniform locations + * within the compiled program, corresponding to the standard uniforms + * [index the vector by the StandardUniform enum] + * @return + */ + QVector<int> standardUniformLocations() const + { + return m_standardUniformLocations; + } + + QString name() const; +private: + QOpenGLShaderProgram* m_program; + ShaderProgram* m_peer; + + QOpenGLShaderProgram *createProgram(); + QOpenGLShaderProgram *createDefaultProgram(); + + QVector<QString> m_standardUniformNames; + QVector<int> m_standardUniformLocations; +}; + +} + + +#endif // RENDERSHADER_H diff --git a/src/render/backend/rendertechnique.cpp b/src/render/backend/rendertechnique.cpp new file mode 100644 index 000000000..7bac88023 --- /dev/null +++ b/src/render/backend/rendertechnique.cpp @@ -0,0 +1,156 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "rendertechnique.h" +#include "rendershader.h" + +#include <renderpass.h> +#include <technique.h> + +#include <QDebug> + +namespace Qt3D +{ + +RenderTechnique::RenderTechnique(Technique* peer) : + m_peer(peer) +{ + m_passCount = peer->renderPasses().count(); + m_passBin.resize(m_passCount); + m_passShader.resize(m_passCount); +} + +unsigned int RenderTechnique::passCount() const +{ + return m_passCount; +} + +void RenderTechnique::setShaderForPass(unsigned int passIndex, RenderShader *s) +{ + Q_ASSERT(passIndex < passCount()); + m_passShader[passIndex] = s; + + // bind standard uniform names + + RenderPass* pass = m_peer->renderPasses().at(passIndex); + foreach (Parameter* p, m_peer->parameters()) { + if (!p->isStandardUniform()) + continue; + + QString glslName = pass->glslNameForParameter(p->name()); + if (glslName.isEmpty()) + continue; + + s->setStandardUniform(p->standardUniform(), glslName); + } // of parameter iteration +} + +RenderShader *RenderTechnique::shaderForPass(unsigned int pass) +{ + Q_ASSERT(pass < passCount()); + return m_passShader.at(pass); +} + +void RenderTechnique::setBinForPass(unsigned int pass, RenderBin *bin) +{ + Q_ASSERT(pass < passCount()); + m_passBin[pass] = bin; +} + +RenderBin *RenderTechnique::binForPass(unsigned int pass) const +{ + return m_passBin.at(pass); +} + +DrawStateSet *RenderTechnique::stateSetForPass(unsigned int pass) const +{ + return m_peer->renderPasses().at(pass)->stateSet(); +} + +QString RenderTechnique::glslNameForMeshAttribute(unsigned int passIndex, QString meshAttributeName) +{ + // find the parameter + foreach (Parameter* p, m_peer->parameters()) { + if (p->meshAttributeName() != meshAttributeName) { + continue; + } + + Q_ASSERT((int) passIndex < m_peer->renderPasses().count()); + RenderPass* pass = m_peer->renderPasses().at(passIndex); + + return pass->glslNameForParameter(p->name()); + } // of parameter iteration + + // mesh attribute is not referenced in this technique + return QString(); +} + +Parameter *RenderTechnique::parameterByName(QString name) const +{ + foreach (Parameter* p, m_peer->parameters()) { + if (p->name() == name) + return p; + } + + qWarning() << Q_FUNC_INFO << "couldn't find parameter:" << name + << "in technique" << m_peer->objectName(); + return NULL; +} + +QStringList RenderTechnique::glslNamesForUniformParameter(QString pName) const +{ + QStringList result; + Parameter* param = parameterByName(pName); + if (!param) + return result; + + for (unsigned int p=0; p<m_passCount;++p) { + RenderPass* pass = m_peer->renderPasses().at(p); + // will return an empty QString if the pass doesn't use the parameter, + // but that's what we want so no probem. + QString glslName = pass->glslNameForParameter(pName); + result.append(glslName); + } + + return result; +} + +} // of namespace Qt3D diff --git a/src/render/backend/rendertechnique.h b/src/render/backend/rendertechnique.h new file mode 100644 index 000000000..41aab29bb --- /dev/null +++ b/src/render/backend/rendertechnique.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef RENDERTECHNIQUE_H +#define RENDERTECHNIQUE_H + +#include <QVector> +#include <QStringList> + +namespace Qt3D +{ + +class Technique; +class RenderShader; +class RenderBin; +class Parameter; +class DrawStateSet; + +class RenderTechnique +{ +public: + RenderTechnique(Technique* peer); + + unsigned int passCount() const; + + void setShaderForPass(unsigned int pass, RenderShader* s); + RenderShader* shaderForPass(unsigned int pass); + + void setBinForPass(unsigned int pas, RenderBin* bin); + RenderBin* binForPass(unsigned int pass) const; + + DrawStateSet* stateSetForPass(unsigned int pass) const; + + QString glslNameForMeshAttribute(unsigned int pass, QString meshAttributeName); + + QStringList glslNamesForUniformParameter(QString pName) const; + + // FIXME using front-end classes here, not ideal + Parameter* parameterByName(QString name) const; +private: + Technique* m_peer; + unsigned int m_passCount; + + // really need more than just the shader here, i.e other + // technique state + QVector<RenderShader*> m_passShader; + QVector<RenderBin*> m_passBin; + + + + +}; + +} // of namespace Qgt3D + +#endif // RENDERTECHNIQUE_H diff --git a/src/render/backend/rendertexture.cpp b/src/render/backend/rendertexture.cpp new file mode 100644 index 000000000..dbb796669 --- /dev/null +++ b/src/render/backend/rendertexture.cpp @@ -0,0 +1,149 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "rendertexture.h" + +#include <QDebug> +#include <QOpenGLTexture> +#include <QOpenGLPixelTransferOptions> + +#include <texturedata.h> + +namespace Qt3D { + +RenderTexture::RenderTexture(Texture* peer) : + m_peer(peer), + m_gl(NULL) +{ +} + +QOpenGLTexture *RenderTexture::getOrCreateGLTexture() +{ + if (m_gl) + return m_gl; + + m_gl = buildGLTexture(); + + m_gl->allocateStorage(); + if (!m_gl->isStorageAllocated()) { + qWarning() << Q_FUNC_INFO << "texture storage allocation failed"; + return NULL; + } + + foreach (TexImageDataPtr imgData, m_peer->imageData()) { + setToGLTexture(imgData); + } // of image data in texture iteration + + if (m_peer->generateMipMaps()) { + m_gl->generateMipMaps(); + } + + int err = glGetError(); + if (err) + qWarning() << Q_FUNC_INFO << + "GL error after generating mip-maps" << QString::number(err, 16); + + + return m_gl; +} + +QOpenGLTexture *RenderTexture::buildGLTexture() +{ + QOpenGLTexture* glTex = new QOpenGLTexture(m_peer->target()); + glTex->setFormat(m_peer->format()); + glTex->setSize(m_peer->width(), + m_peer->height(), + m_peer->depth()); + + if (!glTex->create()) { + qWarning() << Q_FUNC_INFO << "creating QOpenGLTexture failed"; + return NULL; + } + + glTex->setWrapMode(m_peer->wrapMode()); + glTex->setMinMagFilters(m_peer->minificationFilter(), + m_peer->magnificationFilter()); + + // FIXME : make this conditional on Qt version + // work-around issue in QOpenGLTexture DSA emulaation which rasies + // an Invalid Enum error + glGetError(); + + return glTex; +} + +void RenderTexture::setToGLTexture(TexImageDataPtr imgData) +{ + Q_ASSERT(m_gl && m_gl->isCreated() && m_gl->isStorageAllocated()); + // ensure we don't accidently cause a detach / copy of the raw bytes + const QByteArray& bytes(imgData->data()); + char* rawPtr = const_cast<char*>(bytes.constData()); + if (imgData->isCompressed()) { + m_gl->setCompressedData(imgData->mipMapLevel(), + imgData->layer(), + imgData->cubeFace(), + bytes.size(), + rawPtr); + } else { + QOpenGLPixelTransferOptions uploadOptions; + uploadOptions.setAlignment(1); + m_gl->setData(imgData->mipMapLevel(), + imgData->layer(), + imgData->cubeFace(), + imgData->pixelFormat(), + imgData->pixelType(), + rawPtr, + &uploadOptions); + } + + // FIXME : make this conditional on Qt version + // work-around issue in QOpenGLTexture DSA emulaation which rasies + // an Invalid Enum error + glGetError(); +} + + +GLint RenderTexture::textureId() +{ + return getOrCreateGLTexture()->textureId(); +} + +} // namespace Qt3D diff --git a/src/render/backend/rendertexture.h b/src/render/backend/rendertexture.h new file mode 100644 index 000000000..ff418be0b --- /dev/null +++ b/src/render/backend/rendertexture.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3D_RENDERTEXTURE_H +#define QT3D_RENDERTEXTURE_H + +#include <QOpenGLContext> + +#include <texturedata.h> + +// forward decls +class QOpenGLTexture; + +namespace Qt3D { + +class RenderTexture +{ +public: + RenderTexture(Texture* peer); + + QOpenGLTexture* getOrCreateGLTexture() ; + + GLint textureId(); +private: + Texture* m_peer; + QOpenGLTexture* m_gl; + + QOpenGLTexture *buildGLTexture(); + void setToGLTexture(TexImageDataPtr imgData); +}; + +} // namespace Qt3D + +#endif // QT3D_RENDERTEXTURE_H diff --git a/src/render/backend/rendertextureprovider.cpp b/src/render/backend/rendertextureprovider.cpp new file mode 100644 index 000000000..0727272f4 --- /dev/null +++ b/src/render/backend/rendertextureprovider.cpp @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "rendertextureprovider.h" + +#include "rendertexture.h" + +namespace Qt3D { + +RenderTextureProvider::RenderTextureProvider() +{ +} + +RenderTexturePtr RenderTextureProvider::get(Texture *t) +{ + if (m_dict.contains(t)) + return m_dict.value(t); + + RenderTexturePtr rt(new RenderTexture(t)); + m_dict[t] = rt; + + return rt; +} + +} // namespace Qt3D diff --git a/src/render/backend/rendertextureprovider.h b/src/render/backend/rendertextureprovider.h new file mode 100644 index 000000000..70536dcab --- /dev/null +++ b/src/render/backend/rendertextureprovider.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3D_RENDERTEXTUREPROVIDER_H +#define QT3D_RENDERTEXTUREPROVIDER_H + +#include <QSharedPointer> +#include <QHash> + +namespace Qt3D { + +class Texture; + +class RenderTexture; +typedef QSharedPointer<RenderTexture> RenderTexturePtr; + +class RenderTextureProvider +{ +public: + RenderTextureProvider(); + + RenderTexturePtr get(Texture* t); +private: + QHash<Texture*, RenderTexturePtr> m_dict; +}; + +} // namespace Qt3D + +#endif // QT3D_RENDERTEXTUREPROVIDER_H diff --git a/src/render/backend/renderthread.cpp b/src/render/backend/renderthread.cpp new file mode 100644 index 000000000..f679bc2f6 --- /dev/null +++ b/src/render/backend/renderthread.cpp @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "renderthread.h" +#include "renderer.h" + +#include <QDebug> +#include <QEventLoop> +#include <QTime> + +namespace Qt3D { + +RenderThread::RenderThread( QObject* parent ) + : QThread( parent ), + m_renderer( 0 ), + m_eventHandler( 0 ) +{ +} + +void RenderThread::waitForStart( Priority priority ) +{ + qDebug() << "Starting Render thread and then going to sleep until it is ready for us..."; + m_mutex.lock(); + start( priority ); + m_waitCondition.wait( &m_mutex ); + qDebug() << "Render thread is now ready & calling thread is now awake again"; +} + +void RenderThread::run() +{ + m_mutex.lock(); + +// Create worker objects + m_renderer = new Render::Renderer; + //m_eventHandler = new RenderEventProcessor; + + m_waitCondition.wakeOne(); + m_mutex.unlock(); + + // Enter the render thread event loop + exec(); + + delete m_renderer; +} + +} diff --git a/src/render/backend/renderthread.h b/src/render/backend/renderthread.h new file mode 100644 index 000000000..c1471921e --- /dev/null +++ b/src/render/backend/renderthread.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef RENDERTHREAD_H +#define RENDERTHREAD_H + +#include <QThread> + +#include <QMutex> +#include <QWaitCondition> + +namespace Qt3D { +namespace Render { +class Renderer; +} + +class RenderEventProcessor; + +class RenderThread : public QThread +{ + Q_OBJECT +public: + explicit RenderThread( QObject* parent = 0 ); + + void waitForStart( Priority priority = InheritPriority ); + + Render::Renderer* renderer() const { return m_renderer; } + + RenderEventProcessor* eventHandler() const { return m_eventHandler; } +protected: + void run(); + +private: + QMutex m_mutex; + QWaitCondition m_waitCondition; + Render::Renderer* m_renderer; + RenderEventProcessor* m_eventHandler; +}; + +} + +#endif // RENDERTHREAD_H diff --git a/src/render/backend/states/blendstate.cpp b/src/render/backend/states/blendstate.cpp new file mode 100644 index 000000000..c15cc56b9 --- /dev/null +++ b/src/render/backend/states/blendstate.cpp @@ -0,0 +1,197 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "blendstate.h" + +#include "qgraphicscontext.h" + +#include <QOpenGLFunctions_3_2_Core> + +namespace Qt3D { + +template <class State> +State* getOrCreateImpl(const State& data) +{ + static QList<State*> static_instances; + foreach (State* ext, static_instances) { + if (ext->isEqual(data)) + return ext; + } + + State* result = new State(data); + static_instances.append(result); + return result; +} + +void BlendState::apply(QGraphicsContext* gc) const +{ + Q_UNUSED(gc); + glEnable(GL_BLEND); + glBlendFunc( m_1, m_2 ); +} + +StateMaskSet BlendState::mask() const +{ + return BlendStateMask; +} + +BlendState *BlendState::getOrCreate(GLenum src, GLenum dst) +{ + BlendState bs(src, dst); + return getOrCreateImpl(bs); +} + +BlendState::BlendState(GLenum src, GLenum dst) : + GenericState2(src, dst) +{ +} + +void BlendEquation::apply(QGraphicsContext *gc) const +{ + Q_UNUSED(gc); + + if (!m_funcs) { + m_funcs = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_2_Core>(); + m_funcs->initializeOpenGLFunctions(); + } + + m_funcs->glBlendEquation(m_1); +} + +BlendEquation *BlendEquation::getOrCreate(GLenum func) +{ + return getOrCreateImpl(BlendEquation(func)); +} + +BlendEquation::BlendEquation(GLenum func) : + GenericState1(func), + m_funcs(0) +{ +} + + +void AlphaFunc::apply(QGraphicsContext* gc) const +{ + Q_UNUSED(gc); + glEnable(GL_ALPHA_TEST); + glAlphaFunc( m_1, m_2 ); +} + +AlphaFunc *AlphaFunc::getOrCreate(GLenum func, GLclampf value) +{ + AlphaFunc af(func, value); + return getOrCreateImpl(af); +} + +AlphaFunc::AlphaFunc(GLenum func, GLclampf value) : + GenericState2(func, value) +{ +} + +void DepthTest::apply(QGraphicsContext *gc) const +{ + Q_UNUSED(gc); + glEnable(GL_DEPTH_TEST); + glDepthFunc( m_1 ); +} + +DepthTest *DepthTest::getOrCreate(GLenum func) +{ + DepthTest dt(func); + return getOrCreateImpl(dt); +} + +DepthTest::DepthTest(GLenum func) : + GenericState1(func) +{ +} + +void CullFace::apply(QGraphicsContext *gc) const +{ + Q_UNUSED(gc); + glEnable(GL_CULL_FACE); + glCullFace( m_1 ); +} + +CullFace *CullFace::getOrCreate(GLenum func) +{ + return getOrCreateImpl(CullFace(func)); +} + +CullFace::CullFace(GLenum func) : + GenericState1(func) +{ +} + +void FrontFace::apply(QGraphicsContext *gc) const +{ + Q_UNUSED(gc); + glFrontFace(m_1); +} + +FrontFace *FrontFace::getOrCreate(GLenum func) +{ + return getOrCreateImpl(FrontFace(func)); +} + +FrontFace::FrontFace(GLenum func) : + GenericState1(func) +{ +} + +void DepthMask::apply(QGraphicsContext *gc) const +{ + Q_UNUSED(gc) + glDepthMask(m_1); +} + +DepthMask *DepthMask::getOrCreate(GLboolean flag) +{ + return getOrCreateImpl(DepthMask(flag)); +} + +DepthMask::DepthMask(GLboolean flag) : + GenericState1(flag) +{ +} + + +} // of namespace diff --git a/src/render/backend/states/blendstate.h b/src/render/backend/states/blendstate.h new file mode 100644 index 000000000..6a294010d --- /dev/null +++ b/src/render/backend/states/blendstate.h @@ -0,0 +1,153 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef BLENDSTATE_H +#define BLENDSTATE_H + +#include <drawstate.h> +#include <genericstate.h> + +#include <QOpenGLContext> + +class QOpenGLFunctions_3_2_Core; + +namespace Qt3D { + +class BlendState : public GenericState2<BlendState, GLenum, GLenum> +{ +public: + virtual void apply(QGraphicsContext* gc) const; + virtual StateMaskSet mask() const; + + static BlendState* getOrCreate(GLenum src, GLenum dst); +private: + BlendState(GLenum src, GLenum dst); +}; + +class BlendEquation : public GenericState1<BlendEquation, GLenum> +{ +public: + virtual void apply(QGraphicsContext* gc) const; + + virtual StateMaskSet mask() const + { return BlendStateMask; } + + static BlendEquation* getOrCreate(GLenum func); + +private: + BlendEquation(GLenum func); + mutable QOpenGLFunctions_3_2_Core *m_funcs; +}; + + +class AlphaFunc : public GenericState2<AlphaFunc, GLenum, GLclampf> +{ +public: + virtual void apply(QGraphicsContext* gc) const; + + virtual StateMaskSet mask() const + { return AlphaTestMask; } + + static AlphaFunc* getOrCreate(GLenum func, GLclampf value); +private: + AlphaFunc(GLenum func, GLclampf value); +}; + +class DepthTest : public GenericState1<DepthTest, GLenum> +{ +public: + virtual void apply(QGraphicsContext* gc) const; + + virtual StateMaskSet mask() const + { return DepthTestStateMask; } + + static DepthTest* getOrCreate(GLenum func); + +private: + DepthTest(GLenum func); +}; + +class DepthMask : public GenericState1<DepthMask, GLboolean> +{ +public: + virtual void apply(QGraphicsContext* gc) const; + + virtual StateMaskSet mask() const + { return DepthWriteStateMask; } + + static DepthMask* getOrCreate(GLboolean func); + +private: + DepthMask(GLboolean func); +}; + +class CullFace : public GenericState1<CullFace, GLenum> +{ +public: + virtual void apply(QGraphicsContext* gc) const; + + virtual StateMaskSet mask() const + { return CullFaceStateMask; } + + static CullFace* getOrCreate(GLenum func); + +private: + CullFace(GLenum func); +}; + +class FrontFace : public GenericState1<FrontFace, GLenum> +{ +public: + virtual void apply(QGraphicsContext* gc) const; + + virtual StateMaskSet mask() const + { return FrontFaceStateMask; } + + static FrontFace* getOrCreate(GLenum func); + +private: + FrontFace(GLenum func); +}; + + +} // of namespace + +#endif // BLENDSTATE_H diff --git a/src/render/frontend/camera.cpp b/src/render/frontend/camera.cpp new file mode 100644 index 000000000..b408cae8f --- /dev/null +++ b/src/render/frontend/camera.cpp @@ -0,0 +1,483 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "camera.h" +#include "camera_p.h" + +namespace Qt3D { + +Camera::Camera(Node *parent) + : Component(parent) + , d_ptr(new CameraPrivate(this)) +{ + qDebug() << Q_FUNC_INFO; +} + +void Camera::setViewMatrix(const QMatrix4x4 &m) +{ + Q_D(Camera); + + // derive the position and up vecotr + + bool ok; + QMatrix4x4 iv = m.inverted(&ok); + if (!ok) { + qWarning() << Q_FUNC_INFO << "passed non-invertible matrix"; + return; + } + + // position in eye-coordinates is simple the origin + d->m_position = (iv * QVector4D(0,0,0,1)).toVector3D(); + + // up vector, w=0 (no translation), positive Y-axis + d->m_upVector = (iv * QVector4D(0,1,0,0)).toVector3D(); + + // look vector, w=0, positive Z-axis + d->m_cameraToCenter = (iv * QVector4D(0,0,1,0)).toVector3D(); + + d->m_viewMatrix = m; + d->m_syncNeeded = true; +} + +void Camera::setProjectionType(ProjectionType projectionType) +{ + Q_D(Camera); + if (d->m_projectionType != projectionType) { + d->m_projectionType = projectionType; + emit projectionTypeChanged(); + } +} + +Camera::ProjectionType Camera::projectionType() const +{ + Q_D(const Camera); + return d->m_projectionType; +} + +QVector3D Camera::position() const +{ + Q_D(const Camera); + return d->m_position; +} + +void Camera::setPosition( const QVector3D& position ) +{ + Q_D(Camera); + d->m_position = position; + d->m_cameraToCenter = d->m_viewCenter - position; + d->m_viewMatrixDirty = true; + d->m_syncNeeded = true; +} + +void Camera::setUpVector( const QVector3D& upVector ) +{ + Q_D(Camera); + d->m_upVector = upVector; + d->m_viewMatrixDirty = true; + d->m_syncNeeded = true; +} + +QVector3D Camera::upVector() const +{ + Q_D(const Camera); + return d->m_upVector; +} + +void Camera::setViewCenter( const QVector3D& viewCenter ) +{ + Q_D(Camera); + d->m_viewCenter = viewCenter; + d->m_cameraToCenter = viewCenter - d->m_position; + d->m_viewMatrixDirty = true; + d->m_syncNeeded = true; +} + +QVector3D Camera::viewCenter() const +{ + Q_D(const Camera); + return d->m_viewCenter; +} + +QVector3D Camera::viewVector() const +{ + Q_D(const Camera); + return d->m_cameraToCenter; +} + +void Camera::setOrthographicProjection( float left, float right, + float bottom, float top, + float nearPlane, float farPlane ) +{ + Q_D(Camera); + d->m_left = left; + d->m_right = right; + d->m_bottom = bottom; + d->m_top = top; + d->m_nearPlane = nearPlane; + d->m_farPlane = farPlane; + d->m_projectionType = OrthogonalProjection; + d->updateOrthogonalProjection(); +} + +void Camera::setPerspectiveProjection( float fieldOfView, float aspectRatio, + float nearPlane, float farPlane ) +{ + Q_D(Camera); + d->m_fieldOfView = fieldOfView; + d->m_aspectRatio = aspectRatio; + d->m_nearPlane = nearPlane; + d->m_farPlane = farPlane; + d->m_projectionType = PerspectiveProjection; + d->updatePerpectiveProjection(); +} + +void Camera::setNearPlane(float nearPlane) +{ + Q_D(Camera); + if (qFuzzyCompare(d->m_nearPlane, nearPlane)) + return; + d->m_nearPlane = nearPlane; + if (d->m_projectionType == PerspectiveProjection) + d->updatePerpectiveProjection(); + emit nearPlaneChanged(); +} + +float Camera::nearPlane() const +{ + Q_D(const Camera); + return d->m_nearPlane; +} + +void Camera::setFarPlane(float farPlane) +{ + Q_D(Camera); + if (qFuzzyCompare(d->m_farPlane, farPlane)) + return; + d->m_farPlane = farPlane; + if (d->m_projectionType == PerspectiveProjection) + d->updatePerpectiveProjection(); + emit farPlaneChanged(); +} + +float Camera::farPlane() const +{ + Q_D(const Camera); + return d->m_farPlane; +} + +void Camera::setFieldOfView(float fieldOfView) +{ + Q_D(Camera); + if (qFuzzyCompare(d->m_fieldOfView, fieldOfView)) + return; + d->m_fieldOfView = fieldOfView; + if (d->m_projectionType == PerspectiveProjection) + d->updatePerpectiveProjection(); + emit fieldOfViewChanged(); +} + +float Camera::fieldOfView() const +{ + Q_D(const Camera); + return d->m_fieldOfView; +} + +void Camera::setAspectRatio(float aspectRatio) +{ + Q_D(Camera); + if (qFuzzyCompare(d->m_aspectRatio, aspectRatio)) + return; + d->m_aspectRatio = aspectRatio; + if (d->m_projectionType == PerspectiveProjection) + d->updatePerpectiveProjection(); + emit aspectRatioChanged(); +} + +float Camera::aspectRatio() const +{ + Q_D(const Camera); + return d->m_aspectRatio; +} + +void Camera::setLeft(float left) +{ + Q_D(Camera); + if (qFuzzyCompare(d->m_left, left)) + return; + d->m_left = left; + if (d->m_projectionType == OrthogonalProjection) + d->updateOrthogonalProjection(); + emit leftChanged(); +} + +float Camera::left() const +{ + Q_D(const Camera); + return d->m_left; +} + +void Camera::setRight(float right) +{ + Q_D(Camera); + if (qFuzzyCompare(d->m_right, right)) + return; + d->m_right = right; + if (d->m_projectionType == OrthogonalProjection) + d->updateOrthogonalProjection(); + emit rightChanged(); +} + +float Camera::right() const +{ + Q_D(const Camera); + return d->m_right; +} + +void Camera::setBottom(float bottom) +{ + Q_D(Camera); + if (qFuzzyCompare(d->m_bottom, bottom)) + return; + d->m_bottom = bottom; + if (d->m_projectionType == OrthogonalProjection) + d->updateOrthogonalProjection(); + emit bottomChanged(); +} + +float Camera::bottom() const +{ + Q_D(const Camera); + return d->m_bottom; +} + +void Camera::setTop(float top) +{ + Q_D(Camera); + if (qFuzzyCompare(d->m_top, top)) + return; + d->m_top = top; + if (d->m_projectionType == OrthogonalProjection) + d->updateOrthogonalProjection(); + emit topChanged(); +} + +float Camera::top() const +{ + Q_D(const Camera); + return d->m_top; +} + +QMatrix4x4 Camera::viewMatrix() const +{ + Q_D(const Camera); + if ( d->m_viewMatrixDirty ) + { + d->m_viewMatrix.setToIdentity(); + d->m_viewMatrix.lookAt( d->m_position, d->m_viewCenter, d->m_upVector ); + d->m_viewMatrixDirty = false; + } + return d->m_viewMatrix; +} + +QMatrix4x4 Camera::projectionMatrix() const +{ + Q_D(const Camera); + return d->m_projectionMatrix; +} + +QMatrix4x4 Camera::viewProjectionMatrix() const +{ + Q_D(const Camera); + if ( d->m_viewMatrixDirty || d->m_viewProjectionMatrixDirty ) + { + d->m_viewProjectionMatrix = d->m_projectionMatrix * viewMatrix(); + d->m_viewProjectionMatrixDirty = false; + } + return d->m_viewProjectionMatrix; +} + +void Camera::translate( const QVector3D& vLocal, CameraTranslationOption option ) +{ + Q_D(Camera); + + // Calculate the amount to move by in world coordinates + QVector3D vWorld; + if ( !qFuzzyIsNull( vLocal.x() ) ) + { + // Calculate the vector for the local x axis + QVector3D x = QVector3D::crossProduct( d->m_cameraToCenter, d->m_upVector ).normalized(); + vWorld += vLocal.x() * x; + } + + if ( !qFuzzyIsNull( vLocal.y() ) ) + vWorld += vLocal.y() * d->m_upVector; + + if ( !qFuzzyIsNull( vLocal.z() ) ) + vWorld += vLocal.z() * d->m_cameraToCenter.normalized(); + + // Update the camera position using the calculated world vector + d->m_position += vWorld; + + // May be also update the view center coordinates + if ( option == TranslateViewCenter ) + d->m_viewCenter += vWorld; + + // Refresh the camera -> view center vector + d->m_cameraToCenter = d->m_viewCenter - d->m_position; + + // Calculate a new up vector. We do this by: + // 1) Calculate a new local x-direction vector from the cross product of the new + // camera to view center vector and the old up vector. + // 2) The local x vector is the normal to the plane in which the new up vector + // must lay. So we can take the cross product of this normal and the new + // x vector. The new normal vector forms the last part of the orthonormal basis + QVector3D x = QVector3D::crossProduct( d->m_cameraToCenter, d->m_upVector ).normalized(); + d->m_upVector = QVector3D::crossProduct( x, d->m_cameraToCenter ).normalized(); + + d->m_viewMatrixDirty = true; + d->m_viewProjectionMatrixDirty = true; +} + +void Camera::translateWorld(const QVector3D& vWorld , CameraTranslationOption option ) +{ + Q_D(Camera); + + // Update the camera position using the calculated world vector + d->m_position += vWorld; + + // May be also update the view center coordinates + if ( option == TranslateViewCenter ) + d->m_viewCenter += vWorld; + + // Refresh the camera -> view center vector + d->m_cameraToCenter = d->m_viewCenter - d->m_position; + + d->m_viewMatrixDirty = true; + d->m_viewProjectionMatrixDirty = true; +} + +QQuaternion Camera::tiltRotation(float angle) const +{ + Q_D(const Camera); + QVector3D xBasis = QVector3D::crossProduct( d->m_upVector, d->m_cameraToCenter.normalized() ).normalized(); + return QQuaternion::fromAxisAndAngle( xBasis, -angle ); +} + +QQuaternion Camera::panRotation(float angle) const +{ + Q_D(const Camera); + return QQuaternion::fromAxisAndAngle( d->m_upVector, angle ); +} + +QQuaternion Camera::rollRotation(float angle) const +{ + Q_D(const Camera); + return QQuaternion::fromAxisAndAngle( d->m_cameraToCenter, -angle ); +} + +void Camera::tilt( const float& angle ) +{ + QQuaternion q = tiltRotation( angle ); + rotate( q ); +} + +void Camera::pan( const float& angle ) +{ + QQuaternion q = panRotation( -angle ); + rotate( q ); +} + +void Camera::roll( const float& angle ) +{ + QQuaternion q = rollRotation( -angle ); + rotate( q ); +} + +void Camera::tiltAboutViewCenter( const float& angle ) +{ + QQuaternion q = tiltRotation( -angle ); + rotateAboutViewCenter( q ); +} + +void Camera::panAboutViewCenter( const float& angle ) +{ + QQuaternion q = panRotation( angle ); + rotateAboutViewCenter( q ); +} + +void Camera::rollAboutViewCenter( const float& angle ) +{ + QQuaternion q = rollRotation( angle ); + rotateAboutViewCenter( q ); +} + +void Camera::rotate( const QQuaternion& q ) +{ + Q_D(Camera); + d->m_upVector = q.rotatedVector( d->m_upVector ); + d->m_cameraToCenter = q.rotatedVector( d->m_cameraToCenter ); + d->m_viewCenter = d->m_position + d->m_cameraToCenter; + d->m_viewMatrixDirty = true; + d->m_viewProjectionMatrixDirty = true; + d->m_syncNeeded = true; +} + +void Camera::rotateAboutViewCenter( const QQuaternion& q ) +{ + Q_D(Camera); + d->m_upVector = q.rotatedVector( d->m_upVector ); + d->m_cameraToCenter = q.rotatedVector( d->m_cameraToCenter ); + d->m_position = d->m_viewCenter - d->m_cameraToCenter; + d->m_viewMatrixDirty = true; + d->m_viewProjectionMatrixDirty = true; + d->m_syncNeeded = true; +} + +//void Camera::update(UpdateVisitor *) +//{ +// Q_D(Camera); +// if (d->m_syncNeeded) { +// // ... +// d->m_syncNeeded = false; +// } +//} + +} diff --git a/src/render/frontend/camera.h b/src/render/frontend/camera.h new file mode 100644 index 000000000..7dd91695a --- /dev/null +++ b/src/render/frontend/camera.h @@ -0,0 +1,184 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CAMERA_H +#define CAMERA_H + +#include "component.h" + +#include <QMatrix4x4> +#include <QQuaternion> +#include <QVector3D> + +namespace Qt3D { + +class CameraPrivate; + +class Camera : public Component +{ + Q_OBJECT + + // TODO Move view matrix out of the camera and use Transform component (once it exists) + Q_PROPERTY(QVector3D position READ position WRITE setPosition) + Q_PROPERTY(QVector3D upVector READ upVector WRITE setUpVector) + Q_PROPERTY(QVector3D viewCenter READ viewCenter WRITE setViewCenter) + + Q_PROPERTY(ProjectionType projectionType READ projectionType WRITE setProjectionType NOTIFY projectionTypeChanged) + Q_PROPERTY(float nearPlane READ nearPlane WRITE setNearPlane NOTIFY nearPlaneChanged) + Q_PROPERTY(float farPlane READ farPlane WRITE setFarPlane NOTIFY farPlaneChanged) + + Q_PROPERTY(float fieldOfView READ fieldOfView WRITE setFieldOfView NOTIFY fieldOfViewChanged) + Q_PROPERTY(float aspectRatio READ aspectRatio WRITE setAspectRatio NOTIFY aspectRatioChanged) + + Q_PROPERTY(float left READ left WRITE setLeft NOTIFY leftChanged) + Q_PROPERTY(float right READ right WRITE setRight NOTIFY rightChanged) + Q_PROPERTY(float bottom READ bottom WRITE setBottom NOTIFY bottomChanged) + Q_PROPERTY(float top READ top WRITE setTop NOTIFY topChanged) + + Q_ENUMS( ProjectionType ) + +public: + explicit Camera(Node *parent = 0); + + enum ProjectionType { + OrthogonalProjection, + PerspectiveProjection + }; + + enum CameraTranslationOption { + TranslateViewCenter, + DontTranslateViewCenter + }; + + void setViewMatrix(const QMatrix4x4& m); + + QVector3D position() const; + QVector3D upVector() const; + QVector3D viewCenter() const; + + QVector3D viewVector() const; + + void setProjectionType(ProjectionType projectioType); + ProjectionType projectionType() const; + + void setNearPlane(float nearPlane); + float nearPlane() const; + + void setFarPlane(float nearPlane); + float farPlane() const; + + void setFieldOfView(float fieldOfView); + float fieldOfView() const; + + void setAspectRatio(float aspectRatio); + float aspectRatio() const; + + void setLeft(float left); + float left() const; + + void setRight(float right); + float right() const; + + void setBottom(float bottom); + float bottom() const; + + void setTop(float top); + float top() const; + + QMatrix4x4 viewMatrix() const; + QMatrix4x4 projectionMatrix() const; + QMatrix4x4 viewProjectionMatrix() const; + + QQuaternion tiltRotation(float angle) const; + QQuaternion panRotation(float angle) const; + QQuaternion rollRotation(float angle) const; + +public slots: + void setOrthographicProjection(float left, float right, + float bottom, float top, + float nearPlane, float farPlane); + + void setPerspectiveProjection(float fieldOfView, float aspect, + float nearPlane, float farPlane); + + // TODO These slots should likely be on a modifier one layer up + void setPosition( const QVector3D& position ); + void setUpVector( const QVector3D& upVector ); + void setViewCenter( const QVector3D& viewCenter ); + + // Translate relative to camera orientation axes + void translate( const QVector3D& vLocal, CameraTranslationOption option = TranslateViewCenter ); + + // Translate relative to world axes + void translateWorld( const QVector3D& vWorld, CameraTranslationOption option = TranslateViewCenter ); + + void tilt( const float& angle ); + void pan( const float& angle ); + void roll( const float& angle ); + + void tiltAboutViewCenter( const float& angle ); + void panAboutViewCenter( const float& angle ); + void rollAboutViewCenter( const float& angle ); + + void rotate( const QQuaternion& q ); + void rotateAboutViewCenter( const QQuaternion& q ); + +signals: + void projectionTypeChanged(); + void nearPlaneChanged(); + void farPlaneChanged(); + void fieldOfViewChanged(); + void aspectRatioChanged(); + void leftChanged(); + void rightChanged(); + void bottomChanged(); + void topChanged(); + +protected: + Q_DECLARE_PRIVATE(Camera) + +private: + CameraPrivate* d_ptr; +}; + +} + +#endif // CAMERA_H diff --git a/src/render/frontend/camera_p.h b/src/render/frontend/camera_p.h new file mode 100644 index 000000000..7f7015735 --- /dev/null +++ b/src/render/frontend/camera_p.h @@ -0,0 +1,129 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CAMERA_P_H +#define CAMERA_P_H + +#include <QMatrix4x4> +#include <QVector3D> + +namespace Qt3D { + +class CameraPrivate +{ +public: + CameraPrivate( Camera *qq ) + : q_ptr( qq ) + , m_position( 0.0f, 0.0f, 1.0f ) + , m_upVector( 0.0f, 1.0f, 0.0f ) + , m_viewCenter( 0.0f, 0.0f, 0.0f ) + , m_cameraToCenter( 0.0f, 0.0f, -1.0f ) + , m_projectionType( Camera::OrthogonalProjection ) + , m_nearPlane( 0.1f ) + , m_farPlane( 1024.0f ) + , m_fieldOfView( 25.0f ) + , m_aspectRatio( 1.0f ) + , m_left( -0.5 ) + , m_right( 0.5f ) + , m_bottom( -0.5f ) + , m_top( 0.5f ) + , m_viewMatrixDirty( true ) + , m_viewProjectionMatrixDirty( true ) + , m_syncNeeded( false ) + { + updateOrthogonalProjection(); + } + + ~CameraPrivate() + { + } + + inline void updatePerpectiveProjection() + { + m_projectionMatrix.setToIdentity(); + m_projectionMatrix.perspective( m_fieldOfView, m_aspectRatio, m_nearPlane, m_farPlane ); + m_viewProjectionMatrixDirty = true; + m_syncNeeded = true; + } + + inline void updateOrthogonalProjection() + { + m_projectionMatrix.setToIdentity(); + m_projectionMatrix.ortho( m_left, m_right, m_bottom, m_top, m_nearPlane, m_farPlane ); + m_viewProjectionMatrixDirty = true; + m_syncNeeded = true; + } + + Q_DECLARE_PUBLIC( Camera ) + + Camera *q_ptr; + + QVector3D m_position; + QVector3D m_upVector; + QVector3D m_viewCenter; + + QVector3D m_cameraToCenter; // The vector from the camera position to the view center + + Camera::ProjectionType m_projectionType; + + float m_nearPlane; + float m_farPlane; + + float m_fieldOfView; + float m_aspectRatio; + + float m_left; + float m_right; + float m_bottom; + float m_top; + + mutable QMatrix4x4 m_viewMatrix; + mutable QMatrix4x4 m_projectionMatrix; + mutable QMatrix4x4 m_viewProjectionMatrix; + + mutable bool m_viewMatrixDirty; + mutable bool m_viewProjectionMatrixDirty; + mutable bool m_syncNeeded; +}; + +} + +#endif // CAMERA_P_H diff --git a/src/render/frontend/cameraselector.cpp b/src/render/frontend/cameraselector.cpp new file mode 100644 index 000000000..091327646 --- /dev/null +++ b/src/render/frontend/cameraselector.cpp @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "cameraselector.h" + +namespace Qt3D { + +CameraSelector::CameraSelector(Node *parent) + : Qt3D::Component(parent) + , m_camera(0) +{ +} + +void CameraSelector::setCamera(Qt3D::Camera *camera) +{ + if (m_camera != camera) { + m_camera = camera; + emit cameraChanged(); + } +} + +Camera *CameraSelector::camera() const +{ + return m_camera; +} + +} // namespace Qt3D diff --git a/src/render/frontend/cameraselector.h b/src/render/frontend/cameraselector.h new file mode 100644 index 000000000..9da27405c --- /dev/null +++ b/src/render/frontend/cameraselector.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3D_CAMERASELECTOR_H +#define QT3D_CAMERASELECTOR_H + +#include <qt3dcore_global.h> +#include <component.h> + +namespace Qt3D { + +class Camera; + +class CameraSelector : public Qt3D::Component +{ + Q_OBJECT + + Q_PROPERTY(Qt3D::Camera *camera READ camera WRITE setCamera NOTIFY cameraChanged) + +public: + explicit CameraSelector(Node *parent = 0); + + void setCamera(Qt3D::Camera *camera); + Camera *camera() const; + +signals: + void cameraChanged(); + +private: + Camera *m_camera; +}; + +} // namespace Qt3D + +#endif // QT3D_CAMERASELECTOR_H diff --git a/src/render/frontend/effect.cpp b/src/render/frontend/effect.cpp new file mode 100644 index 000000000..e10932fa4 --- /dev/null +++ b/src/render/frontend/effect.cpp @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "effect.h" +#include "technique.h" + +#include <QDebug> + +namespace Qt3D { + +Effect::Effect(Node *parent) + : Node(parent) +{ + qRegisterMetaType<Qt3D::Effect*>(); + qDebug() << Q_FUNC_INFO; +} + + +QQmlListProperty<Qt3D::Technique> Effect::techniqueList() +{ + return QQmlListProperty<Qt3D::Technique>(this, m_techniques); +} + +void Effect::addTechnique(Technique *t) +{ + Q_ASSERT(t); + t->setParent(this); + m_techniques.append(t); + emit techniquesChanged(); +} + +QList<Technique *> Effect::techniques() const +{ + return m_techniques; +} + +void Effect::clearTechniques() +{ + qDeleteAll(m_techniques); + m_techniques.clear(); +} + +} // of namespace diff --git a/src/render/frontend/effect.h b/src/render/frontend/effect.h new file mode 100644 index 000000000..f1caf692e --- /dev/null +++ b/src/render/frontend/effect.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef EFFECT_H +#define EFFECT_H + +#include <qt3dcore_global.h> +#include <node.h> + +#include <QQmlListProperty> +#include <QVector> + +namespace Qt3D { + +class Technique; + +class QT3DCORESHARED_EXPORT Effect : public Node +{ + Q_OBJECT + + Q_PROPERTY(QQmlListProperty<Qt3D::Technique> techniques READ techniqueList NOTIFY techniquesChanged) + +public: + explicit Effect(Node *parent = 0); + + QQmlListProperty<Qt3D::Technique> techniqueList(); + + void addTechnique(Technique *t); + + QList<Technique *> techniques() const; + + void clearTechniques(); +signals: + void techniquesChanged(); + +private: + QList<Technique *> m_techniques; +}; + +} + +Q_DECLARE_METATYPE(Qt3D::Effect*) + +#endif // EFFECT_H diff --git a/src/render/frontend/material.cpp b/src/render/frontend/material.cpp new file mode 100644 index 000000000..16ba6e8fb --- /dev/null +++ b/src/render/frontend/material.cpp @@ -0,0 +1,157 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "material.h" + +#include <qchangearbiter.h> +#include <texture.h> + +#include <QDebug> + +namespace Qt3D { + +Material::Material(Node *parent) + : Component(parent) +{ +} + +Qt3D::Effect *Material::effect() const +{ + return m_effect; +} + +void Material::setEffect(Qt3D::Effect *effect) +{ + if (effect == m_effect) + return; + + m_effect = effect; + emit effectChanged(); +} + +void Material::setParameter(QString name, QVariant val) +{ + m_parameters[name] = val; + + // schedule update to the backend + QScenePropertyChangePtr change(new QScenePropertyChange(MaterialParameter, this)); + change->m_propertyName = name.toLocal8Bit(); + change->m_value = val; + notifySceneChange(change); +} + +QVariantMap Material::parameterValues() const +{ + return m_parameters; +} + +Material::TextureDict Material::textureValues() const +{ + return m_textures; +} + +void Material::setTextureParameter(QString name, Texture *tex) +{ + m_textures[name] = tex; +} + +void Material::onTagValueChanged() +{ + Tag* t = qobject_cast<Tag*>(sender()); + Q_ASSERT(m_tagList.contains(t)); + + QVariant v = t->value(); + QmlTexture* qmlTex = v.value<QmlTexture*>(); + if (qmlTex) { + qDebug() << "got texture parameter" << t->name(); + setTextureParameter(t->name(), qmlTex->texture()); + } else { + setParameter(t->name(), t->value()); + } +} + +QQmlListProperty<Tag> Material::qmlParameters() +{ + return QQmlListProperty<Tag>(this, 0, + &Material::appendTag, + &Material::tagCount, + &Material::tagAt, + &Material::clearTags ); +} + +void Material::appendTag(QQmlListProperty<Tag> *list, Tag *tag) +{ + Material *mat = qobject_cast<Material *>(list->object); + if (mat) { + tag->setParent(mat); + connect(tag, SIGNAL(valueChanged()), mat, SLOT(onTagValueChanged())); + mat->m_tagList.append(tag); + emit mat->parametersChanged(); + } +} + +Tag *Material::tagAt(QQmlListProperty<Tag> *list, int index) +{ + Material *mat = qobject_cast<Material *>(list->object); + if (mat) + return mat->m_tagList.value(index); + return 0; +} + +int Material::tagCount(QQmlListProperty<Tag> *list) +{ + Material *mat = qobject_cast<Material *>(list->object); + if (mat) + return mat->m_tagList.size(); + return 0; +} + +void Material::clearTags(QQmlListProperty<Tag> *list) +{ + Material *mat = qobject_cast<Material *>(list->object); + if (mat) { + mat->m_parameters.clear(); + mat->m_tagList.clear(); + emit mat->parametersChanged(); + } +} + +} // of namespace diff --git a/src/render/frontend/material.h b/src/render/frontend/material.h new file mode 100644 index 000000000..b0dea466a --- /dev/null +++ b/src/render/frontend/material.h @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MATERIAL_H +#define MATERIAL_H + +#include <QVariant> + +#include <component.h> + +// FIXME - write a custom QML parser and stop mis-using Tag +#include "tag.h" + +#include <qt3dcore_global.h> + +namespace Qt3D { + +class Effect; +class Texture; + +class QT3DCORESHARED_EXPORT Material : public Component +{ + Q_OBJECT + Q_PROPERTY(Qt3D::Effect* effect READ effect WRITE setEffect NOTIFY effectChanged) + Q_PROPERTY(QQmlListProperty<Qt3D::Tag> parameters READ qmlParameters) + +public: + explicit Material(Node *parent = 0); + + Qt3D::Effect *effect() const; + void setEffect(Qt3D::Effect *effect); + + void setParameter(QString name, QVariant val); + + QVariantMap parameterValues() const; + + typedef QMap<QString, Texture*> TextureDict; + TextureDict textureValues() const; + + void setTextureParameter(QString name, Texture* tex); + +signals: + void effectChanged(); + void parametersChanged(); + +private slots: + void onTagValueChanged(); + +private: + QQmlListProperty<Tag> qmlParameters(); + + // FIXME - remove when we have a custom QML parser + static void appendTag(QQmlListProperty<Tag> *list, Tag *bar); + static Tag *tagAt(QQmlListProperty<Tag> *list, int index); + static int tagCount(QQmlListProperty<Tag> *list); + static void clearTags(QQmlListProperty<Tag> *list); + + + Effect *m_effect; + QVariantMap m_parameters; + + // FIXME - remove with tags + QList<Tag *> m_tagList; + + TextureDict m_textures; +}; + +} + +#endif // MATERIAL_H diff --git a/src/render/frontend/mesh.cpp b/src/render/frontend/mesh.cpp new file mode 100644 index 000000000..27f8c513b --- /dev/null +++ b/src/render/frontend/mesh.cpp @@ -0,0 +1,129 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "mesh.h" + +#include <qchangearbiter.h> + +#include <QDebug> +#include <QFile> +#include <QFileInfo> + +#include <objloader.h> + +namespace Qt3D { + +Mesh::Mesh(Node *parent) + : Component( parent ) + , m_sourceDirty( false ) +{ +} + +Mesh::~Mesh() +{ +} + +void Mesh::setSource( const QString& source ) +{ + if ( source == m_source ) + return; + m_source = source; + m_sourceDirty = true; + + // FIXME - synchronous update + update(); + + // Let aspects know about the change + QScenePropertyChangePtr e(new QScenePropertyChange(Qt3D::MeshChange, this)); + e->m_propertyName = QByteArrayLiteral("source"); + e->m_value = m_source; + notifySceneChange(e); + + emit sourceChanged(); +} + +QString Mesh::source() const +{ + return m_source; +} + +MeshDataPtr Mesh::data() const +{ + return m_data; +} + +void Mesh::setData(MeshDataPtr d) +{ + m_data = d; +} + +void Mesh::update() +{ + if (m_sourceDirty) { + m_data = MeshDataPtr(); + m_sourceDirty = false; + + QFileInfo finfo(m_source); + if (!finfo.exists()) { + qWarning() << Q_FUNC_INFO << "not found:" << m_source; + return; + } + + QFile f(m_source); + f.open(QIODevice::ReadOnly); + + ObjLoader objLoad; + objLoad.setLoadTextureCoordinatesEnabled(true); + + if (!objLoad.load(&f)) { + qWarning() << Q_FUNC_INFO << "OBJ load failure for:" << m_source; + return; + } + + qDebug() << "Loaded OBJ ok"; + setData(objLoad.mesh()); + setObjectName("OBJ"); + } + + m_sourceDirty = false; +} + +} // of namespace Qt3D diff --git a/src/render/frontend/mesh.h b/src/render/frontend/mesh.h new file mode 100644 index 000000000..766f38042 --- /dev/null +++ b/src/render/frontend/mesh.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3D_MESH_H +#define QT3D_MESH_H + +#include <component.h> + +#include <meshdata.h> + +namespace Qt3D { + +/** +* @brief Simple static mesh +* +*/ +class Mesh : public Component +{ + Q_OBJECT + + Q_PROPERTY(QString source READ source WRITE setSource NOTIFY sourceChanged) + +public: + Mesh(Node *parent = 0); + virtual ~Mesh(); + + void setSource(const QString &source); + QString source() const; + + MeshDataPtr data() const; + void setData(MeshDataPtr d); +signals: + void sourceChanged(); + +private: + Q_INVOKABLE void update(); + + MeshDataPtr m_data; + QString m_source; + bool m_sourceDirty; +}; + +} + +#endif // of QT3D_MESH_H diff --git a/src/render/frontend/qitemmodelbuffer.cpp b/src/render/frontend/qitemmodelbuffer.cpp new file mode 100644 index 000000000..d13e389b4 --- /dev/null +++ b/src/render/frontend/qitemmodelbuffer.cpp @@ -0,0 +1,289 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qitemmodelbuffer.h" + +#include <QDebug> +#include <QColor> + +namespace Qt3D { + +void variantToBytes(void* dest, const QVariant& v, GLint type) +{ + int varType = v.type(); + switch (type) { + case GL_FLOAT: { + float f = v.toFloat(); + memcpy(dest, &f, sizeof(float)); + return; + } + + case GL_INT: { + GLint i = v.toInt(); + memcpy(dest, &i, sizeof(GLint)); + return; + } + + case GL_UNSIGNED_INT: { + GLuint i = v.toUInt(); + memcpy(dest, &i, sizeof(GLuint)); + return; + } + + case GL_FLOAT_VEC3: + if (varType == QVariant::Vector3D) { + QVector3D v3(v.value<QVector3D>()); + memcpy(dest, &v3[0], sizeof(float) * 3); + return; + } + + break; + + case GL_FLOAT_VEC4: + if (varType == QVariant::Vector4D) { + QVector4D v4(v.value<QVector4D>()); + memcpy(dest, &v4[0], sizeof(float) * 4); + return; + } + + if (varType == QVariant::Color) { + QColor c = v.value<QColor>(); + float* fptr = reinterpret_cast<float*>(dest); + *fptr++ = c.redF(); + *fptr++ = c.greenF(); + *fptr++ = c.blueF(); + *fptr++ = c.alphaF(); + return; + } + + if (varType == QVariant::Quaternion) { + QVector4D qv = v.value<QQuaternion>().toVector4D(); + memcpy(dest, &qv[0], sizeof(float) * 4); + return; + } + + break; + + default: + break; + } + + qWarning() << Q_FUNC_INFO << "failed to convert" << v << "to GL type" << + QString::number(type, 16); +} + +QItemModelBuffer::QItemModelBuffer() +{ +} + +void QItemModelBuffer::setModel(QAbstractItemModel *model) +{ + if (model == m_model) + return; + + m_model = model; + m_buffer.clear(); + + connect(m_model, SIGNAL(modelReset()), this, SLOT(onModelReset())); + connect(m_model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), + this, SLOT(onModelDataChanged(QModelIndex,QModelIndex))); +} + +void QItemModelBuffer::setRoot(const QModelIndex &rootIndex) +{ + m_rootIndex = rootIndex; + m_buffer.clear(); +} + +void QItemModelBuffer::mapRoleName(QByteArray roleName, int elementType) +{ + mapRoleName(roleName, roleName, elementType); +} + +void QItemModelBuffer::mapRoleName(QByteArray roleName, QString attributeName, int elementType) +{ + if (m_model) { + if (!m_model->roleNames().values().contains(roleName)) { + qWarning() << Q_FUNC_INFO << "unknown role name" << roleName; + } + } + + m_mappings.append(RoleMapping(roleName, attributeName, elementType)); + m_buffer.clear(); +} + +BufferPtr QItemModelBuffer::buffer() +{ + if (!m_buffer) { + if (!validateRoles()) + return m_buffer; + + m_attributes.clear(); + m_itemStride = 0; + + m_buffer.reset(new Buffer(QOpenGLBuffer::VertexBuffer)); + // assume model will change + m_buffer->setUsage(QOpenGLBuffer::DynamicDraw); + + int rowCount = m_model->rowCount(m_rootIndex); + int offset = 0; + int mappingCount = m_mappings.count(); + for (int m=0; m<mappingCount; ++m) + m_itemStride += m_mappings.at(m).byteSize; + + for (int m=0; m<mappingCount; ++m) { + const RoleMapping mapping(m_mappings.at(m)); + AttributePtr attr(new Attribute(m_buffer, mapping.type, + rowCount, + offset, m_itemStride)); + m_attributes[mapping.attribute] = attr; + offset += byteSizeFromType(mapping.type); + } // of mappings iteration + + m_buffer->setData(computeBufferData()); + } + + return m_buffer; +} + +QStringList QItemModelBuffer::attributeNames() const +{ + return m_attributes.keys(); +} + +AttributePtr QItemModelBuffer::attributeByName(QString nm) const +{ + return m_attributes.value(nm); +} + +void QItemModelBuffer::onModelDataChanged(const QModelIndex& topLeft, + const QModelIndex& bottomRight) +{ + if (!m_buffer) + return; + + if (topLeft.parent() != m_rootIndex) + return; + + QByteArray newBytes = m_buffer->data(); + for (int row=topLeft.row(); row<=bottomRight.row(); ++row) { + QModelIndex index = topLeft.sibling(row, topLeft.column()); + + char* itemPtr = newBytes.data(); + itemPtr += m_itemStride * row; + + writeDataForIndex(index, m_mappings.count(), itemPtr); + } // of rows changed iteration + + m_buffer->setData(newBytes); +} + +void QItemModelBuffer::onModelReset() +{ + if (!m_buffer) + return; + + QByteArray b = computeBufferData(); + m_buffer->setData(b); +} + +QByteArray QItemModelBuffer::computeBufferData() +{ + int rowCount = m_model->rowCount(m_rootIndex); + + int mappingCount = m_mappings.count(); + QByteArray newData; + newData.resize(m_itemStride * rowCount); + char* bufferPtr = newData.data(); + + for (int row=0; row<rowCount; ++row) { + writeDataForIndex(m_model->index(row, 0, m_rootIndex), mappingCount, bufferPtr); + bufferPtr += m_itemStride; + } // of rows iteration + + return newData; +} + +void QItemModelBuffer::writeDataForIndex(const QModelIndex& index, int mappingCount, char* bufferPtr) +{ + char* fieldPtr = bufferPtr; + for (int m=0; m<mappingCount; ++m) { + const RoleMapping& mapping(m_mappings.at(m)); + QVariant v = m_model->data(index, mapping.cachedRole); + variantToBytes(fieldPtr, v, mapping.type); + + fieldPtr += mapping.byteSize; + } // of mappings iteration +} + +bool QItemModelBuffer::validateRoles() +{ + Q_ASSERT(m_model); + + QHash<int, QByteArray> roles(m_model->roleNames()); + // create a lookup that's the the way round we need + QHash<QByteArray, int> inverseRoles; + foreach (int r, roles.keys()) + inverseRoles[roles.value(r)] = r; + + for (int m=0; m<m_mappings.count(); ++m) { + QByteArray rnm(m_mappings.at(m).roleName); + if (!inverseRoles.contains(rnm)) { + qWarning() << "unknown role:" << rnm; + return false; + } + + m_mappings[m].cachedRole = inverseRoles[rnm]; + } // of mappings iteration + + return true; +} + +QItemModelBuffer::RoleMapping::RoleMapping(QByteArray rnm, QString nm, int ty) : + roleName(rnm), + cachedRole(-1), + attribute(nm), + type(ty) +{ + byteSize = byteSizeFromType(ty); +} + +} // namespace Qt3D diff --git a/src/render/frontend/qitemmodelbuffer.h b/src/render/frontend/qitemmodelbuffer.h new file mode 100644 index 000000000..c567ab545 --- /dev/null +++ b/src/render/frontend/qitemmodelbuffer.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3D_QITEMMODELBUFFER_H +#define QT3D_QITEMMODELBUFFER_H + +#include <QAbstractItemModel> +#include <QMap> +#include <QObject> + +#include <meshdata.h> + +namespace Qt3D { + +class QItemModelBuffer : public QObject +{ + Q_OBJECT +public: + QItemModelBuffer(); + + void setModel(QAbstractItemModel* model); + void setRoot(const QModelIndex& rootIndex); + + void mapRoleName(QByteArray roleName, int type); + void mapRoleName(QByteArray roleName, QString attributeName, int type); + + BufferPtr buffer(); + + QStringList attributeNames() const; + AttributePtr attributeByName(QString nm) const; + +private slots: + + void onModelReset(); + + void onModelDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); +private: + QAbstractItemModel* m_model; + QModelIndex m_rootIndex; + + struct RoleMapping { + RoleMapping(QByteArray role, QString attr, int ty); + + QByteArray roleName; + int cachedRole; + QString attribute; + int type; + int byteSize; + }; + + QList<RoleMapping> m_mappings; + + BufferPtr m_buffer; + QMap<QString, AttributePtr> m_attributes; + int m_itemStride; + + QByteArray computeBufferData(); + + void writeDataForIndex(const QModelIndex &index, int mappingCount, char *bufferPtr); + bool validateRoles(); +}; + +} // namespace Qt3D + +#endif // QT3D_QITEMMODELBUFFER_H diff --git a/src/render/frontend/render-frontend.pri b/src/render/frontend/render-frontend.pri new file mode 100644 index 000000000..84930815e --- /dev/null +++ b/src/render/frontend/render-frontend.pri @@ -0,0 +1,37 @@ +INCLUDEPATH += $$PWD + +HEADERS += \ + $$PWD/camera.h \ + $$PWD/camera_p.h \ + $$PWD/effect.h \ + $$PWD/material.h \ + $$PWD/mesh.h \ + $$PWD/renderpass.h \ + $$PWD/renderpassfilter.h \ + $$PWD/shaderprogram.h \ + $$PWD/technique.h \ + $$PWD/viewport.h \ + $$PWD/cameraselector.h \ + $$PWD/techniquefilter.h \ + $$PWD/tag.h \ + $$PWD//shape.h \ + $$PWD//transform.h \ + $$PWD//qitemmodelbuffer.h \ + $$PWD//texture.h + +SOURCES += \ + $$PWD/camera.cpp \ + $$PWD/effect.cpp \ + $$PWD/material.cpp \ + $$PWD/mesh.cpp \ + $$PWD/renderpass.cpp \ + $$PWD/renderpassfilter.cpp \ + $$PWD/shaderprogram.cpp \ + $$PWD/technique.cpp \ + $$PWD/viewport.cpp \ + $$PWD/cameraselector.cpp \ + $$PWD/techniquefilter.cpp \ + $$PWD/shape.cpp \ + $$PWD/transform.cpp \ + $$PWD/qitemmodelbuffer.cpp \ + $$PWD/texture.cpp diff --git a/src/render/frontend/renderpass.cpp b/src/render/frontend/renderpass.cpp new file mode 100644 index 000000000..59c083fce --- /dev/null +++ b/src/render/frontend/renderpass.cpp @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "renderpass.h" +#include "technique.h" + +#include <QDebug> + +namespace Qt3D { + +RenderPass::RenderPass(Node *parent) + : Node(parent) + , m_name() + , m_shaderProgram(0) + , m_stateSet(0) +{ +} + +void RenderPass::setName(const QString &name) +{ + if (name != m_name) { + m_name = name; + emit nameChanged(); + } +} + +QString RenderPass::name() const +{ + return m_name; +} + +void RenderPass::setShaderProgram(Qt3D::ShaderProgram *shaderProgram) +{ + if (shaderProgram != m_shaderProgram) { + m_shaderProgram = shaderProgram; + emit shaderProgramChanged(); + } +} + +Qt3D::ShaderProgram *RenderPass::shaderProgram() const +{ + return m_shaderProgram; +} + +void RenderPass::addUniformBinding(Parameter *param, QString glslUniformName) +{ + m_uniforms.append(param); + m_parameterNameDict[param->name()] = glslUniformName; +} + +void RenderPass::addAttributeBinding(Parameter *param, QString glslAttributeName) +{ + m_attributes.append(param); + m_parameterNameDict[param->name()] = glslAttributeName; +} + +QString RenderPass::glslNameForParameter(QString paramName) const +{ + return m_parameterNameDict.value(paramName); +} + +ParameterList RenderPass::attributes() const +{ + return m_attributes; +} + +ParameterList RenderPass::uniforms() const +{ + return m_uniforms; +} + +void RenderPass::setStateSet(DrawStateSet *ss) +{ + m_stateSet = ss; +} + +DrawStateSet *RenderPass::stateSet() const +{ + return m_stateSet; +} + +} // of namespace Qt3D diff --git a/src/render/frontend/renderpass.h b/src/render/frontend/renderpass.h new file mode 100644 index 000000000..ad2fb0088 --- /dev/null +++ b/src/render/frontend/renderpass.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef RENDERPASS_H +#define RENDERPASS_H + +#include <node.h> +#include <qt3dcore_global.h> + +#include "shaderprogram.h" +#include <drawstate.h> + +#include <QHash> + +namespace Qt3D { + +class Parameter; +typedef QList<Parameter*> ParameterList; + +class QT3DCORESHARED_EXPORT RenderPass : public Node +{ + Q_OBJECT + + Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) + Q_PROPERTY(Qt3D::ShaderProgram * shaderProgram READ shaderProgram WRITE setShaderProgram NOTIFY shaderProgramChanged) + +public: + explicit RenderPass(Node *parent = 0); + + void setName(const QString &name); + QString name() const; + + void setShaderProgram(Qt3D::ShaderProgram* shaderProgram); + Qt3D::ShaderProgram* shaderProgram() const; + + void addUniformBinding(Parameter* param, QString glslUniformName); + + void addAttributeBinding(Parameter* param, QString glslAttributeName); + + QString glslNameForParameter(QString paramName) const; + + ParameterList attributes() const; + ParameterList uniforms() const; + + void setStateSet(DrawStateSet* ss); + DrawStateSet* stateSet() const; + +signals: + void nameChanged(); + void shaderProgramChanged(); + +protected: + QString m_name; + ShaderProgram* m_shaderProgram; + ParameterList m_attributes; + ParameterList m_uniforms; + + // map Parameter names to GLSL names + QHash<QString, QString> m_parameterNameDict; + + DrawStateSet* m_stateSet; +}; + +} + +#endif // RENDERPASS_H diff --git a/src/render/frontend/renderpassfilter.cpp b/src/render/frontend/renderpassfilter.cpp new file mode 100644 index 000000000..8b25fe239 --- /dev/null +++ b/src/render/frontend/renderpassfilter.cpp @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "renderpassfilter.h" + +namespace Qt3D { + +RenderPassFilter::RenderPassFilter(Node *parent) + : Component(parent) +{ +} + +void RenderPassFilter::setRenderPassNames(const QString &renderpassNames) +{ + if (m_renderPassNames != renderpassNames) { + m_renderPassNames = renderpassNames; + emit renderPassNamesChanged(); + } +} + +QString RenderPassFilter::renderPassNames() const +{ + return m_renderPassNames; +} + +} diff --git a/src/render/frontend/renderpassfilter.h b/src/render/frontend/renderpassfilter.h new file mode 100644 index 000000000..cd9f81e88 --- /dev/null +++ b/src/render/frontend/renderpassfilter.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef RENDERPASSFILTER_H +#define RENDERPASSFILTER_H + +#include <qt3dcore_global.h> +#include <component.h> + +#include <QString> + +namespace Qt3D { + +class QT3DCORESHARED_EXPORT RenderPassFilter : public Component +{ + Q_OBJECT + + Q_PROPERTY(QString renderPassNames READ renderPassNames WRITE setRenderPassNames NOTIFY renderPassNamesChanged) + +public: + explicit RenderPassFilter(Node *parent = 0); + + void setRenderPassNames(const QString &renderpassNames); + QString renderPassNames() const; + +signals: + void renderPassNamesChanged(); + +private: + QString m_renderPassNames; +}; + +} // namespace Qt3D + +#endif // RENDERPASSFILTER_H diff --git a/src/render/frontend/shaderprogram.cpp b/src/render/frontend/shaderprogram.cpp new file mode 100644 index 000000000..e0ef62d2a --- /dev/null +++ b/src/render/frontend/shaderprogram.cpp @@ -0,0 +1,133 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "shaderprogram.h" + +#include <QDebug> +#include <QFile> + +namespace Qt3D { + +ShaderProgram::ShaderProgram(Node *parent) + : Node(parent) + , m_vertexSourceFile() + , m_fragmentSourceFile() + , m_isLoaded(false) +{ +} + +void ShaderProgram::setVertexSourceFile(const QString& vertexSourceFile) +{ + if (vertexSourceFile != m_vertexSourceFile) { + m_vertexSourceFile = vertexSourceFile; + m_isLoaded = false; + emit vertexSourceFileChanged(); + } +} + +QString ShaderProgram::vertexSourceFile() const +{ + return m_vertexSourceFile; +} + +void ShaderProgram::setFragmentSourceFile(const QString& fragmentSourceFile) +{ + if (fragmentSourceFile != m_fragmentSourceFile) { + m_fragmentSourceFile = fragmentSourceFile; + m_isLoaded = false; + emit fragmentSourceFileChanged(); + } +} + +QString ShaderProgram::fragmentSourceFile() const +{ + return m_fragmentSourceFile; +} + +QByteArray ShaderProgram::vertexSourceCode() const +{ + if (!isLoaded()) + return QByteArray(); + + return m_cachedVertexCode; +} + +QByteArray ShaderProgram::fragmentSourceCode() const +{ + if (!isLoaded()) + return QByteArray(); + + return m_cachedFragmentCode; +} + +bool ShaderProgram::isLoaded() const +{ + return m_isLoaded; +} + +void ShaderProgram::load() +{ + if (m_isLoaded) + return; + + m_isLoaded = true; + + QFile f(m_fragmentSourceFile); + if (!f.exists()) { + qWarning() << "couldn't find shader source file:" << m_fragmentSourceFile; + return; + } else { + f.open(QIODevice::ReadOnly); + m_cachedFragmentCode = f.readAll(); + } + + QFile vs(m_vertexSourceFile); + if (!vs.exists()) { + qWarning() << "couldn't find shader source file:" << m_vertexSourceFile; + return; + } else { + vs.open(QIODevice::ReadOnly); + m_cachedVertexCode = vs.readAll(); + } +} + +} // of namespace Qt3D + diff --git a/src/render/frontend/shaderprogram.h b/src/render/frontend/shaderprogram.h new file mode 100644 index 000000000..3b49fe651 --- /dev/null +++ b/src/render/frontend/shaderprogram.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SHADERPROGRAM_H +#define SHADERPROGRAM_H + +#include <node.h> + +namespace Qt3D { + +class ShaderProgram : public Node +{ + Q_OBJECT + + Q_PROPERTY(QString vertexSourceFile READ vertexSourceFile WRITE setVertexSourceFile NOTIFY vertexSourceFileChanged) + Q_PROPERTY(QString fragmentSourceFile READ fragmentSourceFile WRITE setFragmentSourceFile NOTIFY fragmentSourceFileChanged) + +public: + explicit ShaderProgram(Node *parent = 0); + + void setVertexSourceFile(const QString &vertexSourceFile); + QString vertexSourceFile() const; + + void setFragmentSourceFile(const QString &fragmentSource); + QString fragmentSourceFile() const; + + QByteArray vertexSourceCode() const; + QByteArray fragmentSourceCode() const; + + bool isLoaded() const; + + /** + * @brief load - call from main / worker thread to do synchronous + * loading of shader source files + */ + void load(); + +signals: + void vertexSourceFileChanged(); + void fragmentSourceFileChanged(); + +private: + QString m_vertexSourceFile; + QString m_fragmentSourceFile; + + bool m_sourcesDirty, m_isLoaded; + QByteArray m_cachedVertexCode, + m_cachedFragmentCode; + +}; + +} + +#endif // SHADERPROGRAM_H diff --git a/src/render/frontend/shape.cpp b/src/render/frontend/shape.cpp new file mode 100644 index 000000000..5e9fa3c0f --- /dev/null +++ b/src/render/frontend/shape.cpp @@ -0,0 +1,386 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#define _USE_MATH_DEFINES // For MSVC +#include "shape.h" + +#include <cmath> + +#include <QDebug> + +namespace Qt3D { + +namespace { + +MeshDataPtr createSphereMesh(double radius, int rings, int slices, bool hasTangents) +{ + MeshDataPtr mesh(new MeshData(GL_TRIANGLES)); + + int nVerts = ( slices + 1 ) * ( rings + 1 ); // One extra line of latitude + QByteArray bufferBytes; + // vec3 pos, vec2 texCoord, vec3 normal, vec4 tangent + quint32 elementSize = 3 + 2 + 3 + (hasTangents ? 4 : 0); + quint32 stride = elementSize * sizeof(float); + bufferBytes.resize(stride * nVerts); + + float* fptr = reinterpret_cast<float*>(bufferBytes.data()); + + const float dTheta = (M_PI * 2) / static_cast<float>( slices ); + const float dPhi = M_PI / static_cast<float>( rings ); + const float du = 1.0f / static_cast<float>( slices ); + const float dv = 1.0f / static_cast<float>( rings ); + + // Iterate over latitudes (rings) + for ( int lat = 0; lat < rings + 1; ++lat ) + { + const float phi = M_PI_2 - static_cast<float>( lat ) * dPhi; + const float cosPhi = cosf( phi ); + const float sinPhi = sinf( phi ); + const float v = 1.0f - static_cast<float>( lat ) * dv; + + // Iterate over longitudes (slices) + for ( int lon = 0; lon < slices + 1; ++lon ) + { + const float theta = static_cast<float>( lon ) * dTheta; + const float cosTheta = cosf( theta ); + const float sinTheta = sinf( theta ); + const float u = static_cast<float>( lon ) * du; + + *fptr++ = radius * cosTheta * cosPhi; + *fptr++ = radius * sinPhi; + *fptr++ = radius * sinTheta * cosPhi; + + *fptr++ = u; + *fptr++ = v; + + *fptr++ = cosTheta * cosPhi; + *fptr++ = sinPhi; + *fptr++ = sinTheta * cosPhi; + + if (hasTangents) { + *fptr++ = sinTheta; + *fptr++ = 0.0; + *fptr++ = -cosTheta; + *fptr++ = 1.0; + } + } + } + + BufferPtr buf(new Buffer(QOpenGLBuffer::VertexBuffer)); + buf->setUsage(QOpenGLBuffer::StaticDraw); + buf->setData(bufferBytes); + + mesh->addAttribute("position", new Attribute(buf, GL_FLOAT_VEC3, nVerts, 0, stride)); + quint32 offset = sizeof(float) * 3; + + mesh->addAttribute("texcoord", new Attribute(buf, GL_FLOAT_VEC2, nVerts, offset, stride)); + offset += sizeof(float) * 2; + + mesh->addAttribute("normal", new Attribute(buf, GL_FLOAT_VEC3, nVerts, offset, stride)); + offset += sizeof(float) * 3; + + if (hasTangents) { + mesh->addAttribute("tangent", new Attribute(buf, GL_FLOAT_VEC4, nVerts, offset, stride)); + offset += sizeof(float) * 4; + } + + int faces = (slices * 2) * (rings - 1); // two tris per slice, for all middle rings + faces += 2 * slices; // tri per slice for both top and bottom + + QByteArray indexBytes; + int indices = faces * 3; + Q_ASSERT(indices < 65536); + indexBytes.resize(indices * sizeof(quint16)); + quint16* indexPtr = reinterpret_cast<quint16*>(indexBytes.data()); + + // top cap + { + const int nextRingStartIndex = slices + 1; + for ( int j = 0; j < slices; ++j ) + { + *indexPtr++ = nextRingStartIndex + j; + *indexPtr++ = 0; + *indexPtr++ = nextRingStartIndex + j + 1; + } + } + + for ( int i = 1; i < (rings - 1); ++i ) + { + const int ringStartIndex = i * ( slices + 1 ); + const int nextRingStartIndex = ( i + 1 ) * ( slices + 1 ); + + for ( int j = 0; j < slices; ++j ) + { + // Split the quad into two triangles + *indexPtr++ = ringStartIndex + j; + *indexPtr++ = ringStartIndex + j + 1; + *indexPtr++ = nextRingStartIndex + j; + *indexPtr++ = nextRingStartIndex + j; + *indexPtr++ = ringStartIndex + j + 1; + *indexPtr++ = nextRingStartIndex + j + 1; + } + } + + // bottom cap + { + const int ringStartIndex = (rings - 1) * ( slices + 1); + const int nextRingStartIndex = (rings) * ( slices + 1); + for ( int j = 0; j < slices; ++j ) + { + *indexPtr++ = ringStartIndex + j + 1; + *indexPtr++ = nextRingStartIndex; + *indexPtr++ = ringStartIndex + j; + } + } + + BufferPtr indexBuffer(new Buffer(QOpenGLBuffer::IndexBuffer)); + indexBuffer->setUsage(QOpenGLBuffer::StaticDraw); + indexBuffer->setData(indexBytes); + mesh->setIndexAttr(AttributePtr(new Attribute(indexBuffer, GL_UNSIGNED_SHORT, indices, 0, 0))); + + mesh->computeBoundsFromAttribute("position"); + qDebug() << "computed sphere bounds is:" << mesh->boundingBox(); + + return mesh; +} + + +MeshDataPtr createTorusMesh(double radius, double minorRadius, + int rings, int sides) +{ + MeshDataPtr mesh(new MeshData(GL_TRIANGLES)); + + int nVerts = ( sides + 1 ) * ( rings + 1 ); + QByteArray bufferBytes; + // vec3 pos, vec2 texCoord, vec3 normal + quint32 elementSize = 3 + 2 + 3; + quint32 stride = elementSize * sizeof(float); + bufferBytes.resize(stride * nVerts); + + float* fptr = reinterpret_cast<float*>(bufferBytes.data()); + + float ringFactor = (M_PI * 2) / static_cast<float>( rings ); + float sideFactor = (M_PI * 2) / static_cast<float>( sides ); + + for ( int ring = 0; ring <= rings; ring++ ) + { + float u = ring * ringFactor; + float cu = cos( u ); + float su = sin( u ); + + for ( int side = 0; side < sides; side++ ) + { + float v = side * sideFactor; + float cv = cos( v ); + float sv = sin( v ); + float r = ( radius + minorRadius * cv ); + + *fptr++ = r * cu; + *fptr++ = r * su; + *fptr++ = minorRadius * sv; + + + *fptr++ = u / (M_PI * 2); + *fptr++ = v / (M_PI * 2); + + QVector3D n(cv * cu * r, cv * su * r, sv * r); + n.normalize(); + *fptr++ = n.x(); + *fptr++ = n.y(); + *fptr++ = n.z(); + } + } + + BufferPtr buf(new Buffer(QOpenGLBuffer::VertexBuffer)); + buf->setUsage(QOpenGLBuffer::StaticDraw); + buf->setData(bufferBytes); + + mesh->addAttribute("position", new Attribute(buf, GL_FLOAT_VEC3, nVerts, 0, stride)); + quint32 offset = sizeof(float) * 3; + + mesh->addAttribute("texcoord", new Attribute(buf, GL_FLOAT_VEC2, nVerts, offset, stride)); + offset += sizeof(float) * 2; + + mesh->addAttribute("normal", new Attribute(buf, GL_FLOAT_VEC3, nVerts, offset, stride)); + offset += sizeof(float) * 3; + + QByteArray indexBytes; + int faces = (sides * 2) * rings; // two tris per side, for all rings + int indices = faces * 3; + Q_ASSERT(indices < 65536); + indexBytes.resize(indices * sizeof(quint16)); + quint16* indexPtr = reinterpret_cast<quint16*>(indexBytes.data()); + + for ( int ring = 0; ring < rings; ring++ ) + { + int ringStart = ring * sides; + int nextRingStart = ( ring + 1 ) * sides; + for ( int side = 0; side < sides; side++ ) + { + int nextSide = ( side + 1 ) % sides; + *indexPtr++ = ( ringStart + side ); + *indexPtr++ = ( nextRingStart + side ); + *indexPtr++ = ( nextRingStart + nextSide ); + *indexPtr++ = ringStart + side; + *indexPtr++ = nextRingStart + nextSide; + *indexPtr++ = ( ringStart + nextSide ); + } + } + + BufferPtr indexBuffer(new Buffer(QOpenGLBuffer::IndexBuffer)); + indexBuffer->setUsage(QOpenGLBuffer::StaticDraw); + indexBuffer->setData(indexBytes); + mesh->setIndexAttr(AttributePtr(new Attribute(indexBuffer, GL_UNSIGNED_SHORT, indices, 0, 0))); + + mesh->computeBoundsFromAttribute("position"); + + return mesh; +} + +} // anonymous namespace + +Shape::Shape(Node *parent) : + Qt3D::Component(parent), + m_generateTangents(false), + m_type(ShapeSphere), + m_rings(16), + m_slices(16), + m_radius(1.0), + m_minorRadius(1.0) +{ +} + +Shape::ShapeType Shape::type() const +{ + return m_type; +} + +MeshDataPtr Shape::data() const +{ + if (m_type == ShapeTorus) + return createTorusMesh(m_radius, m_minorRadius, m_rings, m_slices); + + return createSphereMesh(m_radius, m_rings, m_slices, m_generateTangents); +} + +int Shape::rings() const +{ + return m_rings; +} + +int Shape::slices() const +{ + return m_slices; +} + +bool Shape::generateTangents() const +{ + return m_generateTangents; +} + +double Shape::radius() const +{ + return m_radius; +} + +double Shape::minorRadius() const +{ + return m_minorRadius; +} + +void Shape::setType(Shape::ShapeType arg) +{ + if (m_type != arg) { + m_type = arg; + m_rebuildMesh = true; + emit typeChanged(arg); + } +} + +void Shape::setRings(int arg) +{ + if (m_rings == arg) + return; + + m_rings = arg; + m_rebuildMesh = true; + emit shapeChanged(); +} + +void Shape::setSlices(int arg) +{ + if (m_slices == arg) + return; + + m_slices = arg; + m_rebuildMesh = true; + emit shapeChanged(); +} + +void Shape::setGenerateTangents(bool gen) +{ + if (m_generateTangents == gen) + return; + + m_generateTangents = gen; + m_rebuildMesh = true; + emit shapeChanged(); +} + +void Shape::setRadius(double arg) +{ + if (m_radius != arg) { + m_radius = arg; + m_rebuildMesh = true; + emit shapeChanged(); + } +} + +void Shape::setMinorRadius(double arg) +{ + if (m_minorRadius != arg) { + m_minorRadius = arg; + m_rebuildMesh = true; + emit shapeChanged(); + } +} + +} // namespace Qt3D diff --git a/src/render/frontend/shape.h b/src/render/frontend/shape.h new file mode 100644 index 000000000..4207720b5 --- /dev/null +++ b/src/render/frontend/shape.h @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3D_SHAPE_H +#define QT3D_SHAPE_H + +#include <component.h> + +#include <meshdata.h> + +namespace Qt3D { + +class Shape : public Qt3D::Component +{ + Q_OBJECT + + Q_ENUMS(ShapeType) + + Q_PROPERTY(ShapeType type READ type WRITE setType NOTIFY typeChanged) + + Q_PROPERTY(bool generateTangents READ generateTangents + WRITE setGenerateTangents + NOTIFY shapeChanged) + + Q_PROPERTY(int rings READ rings WRITE setRings NOTIFY shapeChanged) + Q_PROPERTY(int slices READ slices WRITE setSlices NOTIFY shapeChanged) + + Q_PROPERTY(double radius READ radius WRITE setRadius NOTIFY shapeChanged) + Q_PROPERTY(double minorRadius READ minorRadius WRITE setMinorRadius NOTIFY shapeChanged) + +public: + explicit Shape(Node *parent = 0); + + enum ShapeType + { + ShapeCube, + ShapeSphere, + ShapeCylinder, + ShapeTorus + }; + + ShapeType type() const; + + MeshDataPtr data() const; + + int rings() const; + int slices() const; + bool generateTangents() const; + double radius() const; + double minorRadius() const; + +signals: + + void typeChanged(ShapeType arg); + void shapeChanged(); + +public slots: + + void setType(ShapeType arg); + void setRings(int arg); + void setSlices(int arg); + + void setGenerateTangents(bool gen); + + void setRadius(double arg); + void setMinorRadius(double arg); + +private: + bool m_rebuildMesh, + m_generateTangents; + ShapeType m_type; + int m_rings, + m_slices; + double m_radius; + double m_minorRadius; +}; + +} // namespace Qt3D + +#endif // QT3D_SHAPE_H diff --git a/src/render/frontend/tag.h b/src/render/frontend/tag.h new file mode 100644 index 000000000..7dc4b7dc4 --- /dev/null +++ b/src/render/frontend/tag.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TAG_H +#define TAG_H + +#include <QDebug> + +#include <qt3dcore_global.h> +#include <node.h> + +namespace Qt3D { + +class QT3DCORESHARED_EXPORT Tag : public Node +{ + Q_OBJECT + + Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) + Q_PROPERTY(QVariant value READ value WRITE setValue NOTIFY valueChanged) + +public: + Tag(Node *parent = 0) + : Node(parent) + , m_name() + , m_value() + {} + + void setName( const QString& name ) + { + if (name != m_name) { + m_name = name; + emit nameChanged(); + } + } + + QString name() const { return m_name; } + + void setValue( const QVariant& value ) + { + if (value != m_value) { + m_value = value; + emit valueChanged(); + } + } + + QVariant value() const { return m_value; } + +signals: + void nameChanged(); + void valueChanged(); + +private: + QString m_name; + QVariant m_value; +}; + +} // namespace Qt3D + +#endif // TAG_H diff --git a/src/render/frontend/technique.cpp b/src/render/frontend/technique.cpp new file mode 100644 index 000000000..5779e8f10 --- /dev/null +++ b/src/render/frontend/technique.cpp @@ -0,0 +1,281 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "technique.h" + +#include <QDebug> +#include <QOpenGLContext> + +namespace Qt3D { + +Technique::Technique(Node *parent) + : Node(parent) +{ +} + +QQmlListProperty<Qt3D::Tag> Technique::tags() +{ + return QQmlListProperty<Qt3D::Tag>(this, 0, + &Technique::appendTag, + &Technique::tagCount, + &Technique::tagAt, + &Technique::clearTags ); +} + +void Technique::addTag(const QString &name, const QVariant &value) +{ + Tag *tag = new Tag(this); + tag->setName(name); + tag->setValue(value); + m_tags.insert(name, tag); + m_tagList.append(tag); + emit tagsChanged(); +} + +void Technique::removeTag(const QString &name) +{ + Tag *tag = m_tags.value(name); + m_tags.remove(name); + m_tagList.removeOne(tag); + if (tag) { + delete tag; + emit tagsChanged(); + } +} + +void Technique::setTagValue(const QString &name, const QVariant &value) +{ + Tag *tag = m_tags.value(name); + if (tag) + tag->setValue(value); +} + +QVariant Technique::tagValue(const QString &name) const +{ + return m_tags.value(name)->value(); +} + +bool Technique::containsTag(const QString &name) const +{ + return m_tags.contains(name); +} + +void Technique::addPass(RenderPass *pass) +{ + Q_ASSERT(pass); + pass->setParent(this); + m_renderPasses.append(pass); + emit renderPassesChanged(); +} + +QList<RenderPass *> Technique::renderPasses() const +{ + return m_renderPasses; +} + +void Technique::appendTag(QQmlListProperty<Tag> *list, Tag *tag) +{ + Technique *technique = qobject_cast<Technique *>(list->object); + if (technique) { + tag->setParent(technique); + technique->m_tags.insert(tag->name(), tag); + technique->m_tagList.append(tag); + emit technique->tagsChanged(); + } +} + +Tag *Technique::tagAt(QQmlListProperty<Tag> *list, int index) +{ + Technique *technique = qobject_cast<Technique *>(list->object); + if (technique) + return technique->m_tagList.value(index); + return 0; +} + +int Technique::tagCount(QQmlListProperty<Tag> *list) +{ + Technique *technique = qobject_cast<Technique *>(list->object); + if (technique) + return technique->m_tagList.size(); + return 0; +} + +void Technique::clearTags(QQmlListProperty<Tag> *list) +{ + Technique *technique = qobject_cast<Technique *>(list->object); + if (technique) { + technique->m_tags.clear(); + technique->m_tagList.clear(); + emit technique->tagsChanged(); + } +} + +QQmlListProperty<Qt3D::RenderPass> Technique::renderPassList() +{ + return QQmlListProperty<Qt3D::RenderPass>(this, 0, + &Technique::appendRenderPass, + &Technique::renderPassCount, + &Technique::renderPassAt, + &Technique::clearRenderPasses); +} + +void Technique::addParameter(Parameter *p) +{ + Q_CHECK_PTR(p); + m_parameters.append(p); +} + +Parameter *Technique::parameterByName(QString name) const +{ + foreach (Parameter* p, m_parameters) { + if (p->name() == name) + return p; + } + + return NULL; +} + +void Technique::appendRenderPass(QQmlListProperty<RenderPass> *list, RenderPass *renderPass) +{ + Technique *technique = qobject_cast<Technique *>(list->object); + if (technique) { + technique->addPass(renderPass); + } +} + +RenderPass *Technique::renderPassAt(QQmlListProperty<RenderPass> *list, int index) +{ + Technique *technique = qobject_cast<Technique *>(list->object); + if (technique) + return technique->m_renderPasses.value(index); + return 0; +} + +int Technique::renderPassCount(QQmlListProperty<RenderPass> *list) +{ + Technique *technique = qobject_cast<Technique *>(list->object); + if (technique) + return technique->m_renderPasses.size(); + return 0; +} + +void Technique::clearRenderPasses(QQmlListProperty<RenderPass> *list) +{ + Technique *technique = qobject_cast<Technique *>(list->object); + if (technique) { + technique->m_renderPasses.clear(); + emit technique->renderPassesChanged(); + } +} + +Parameter::Parameter(QObject *parent, QString name, int ty) : + QObject(parent), + m_name(name), + m_type(ty), + m_standardUniform(None) +{ + +} + +void Parameter::setMeshAttributeName(QString name) +{ + m_meshName = name; +} + +bool Parameter::isStandardUniform() const +{ + return (m_standardUniform != None); +} + +void Parameter::setStandardUniform(Parameter::StandardUniform su) +{ + m_standardUniform = su; +} + +Parameter::StandardUniform Parameter::standardUniform() const +{ + return m_standardUniform; +} + +bool Parameter::isTextureType() const +{ + switch (m_type) { + case GL_SAMPLER_1D: + case GL_SAMPLER_2D: + case GL_SAMPLER_3D: + case GL_SAMPLER_CUBE: + return true; + default: + return false; + } +} + +Render::QUniformValue::Type Parameter::uniformType() const +{ + switch (m_type) { + case GL_BOOL: + case GL_BOOL_VEC2: + case GL_BOOL_VEC3: + case GL_BOOL_VEC4: + return Render::QUniformValue::Bool; + + // integers! + + case GL_FLOAT: + case GL_FLOAT_VEC2: + case GL_FLOAT_VEC3: + case GL_FLOAT_VEC4: + case GL_FLOAT_MAT4: + return Render::QUniformValue::Float; + + case GL_DOUBLE: + case GL_DOUBLE_VEC2: + case GL_DOUBLE_VEC3: + case GL_DOUBLE_VEC4: + return Render::QUniformValue::Double; + + default: + qWarning() << Q_FUNC_INFO << "couldn't map datatype:" << QString::number(m_type, 16); + return Render::QUniformValue::Invalid; + } +} + +} // of namespace Qt3D diff --git a/src/render/frontend/technique.h b/src/render/frontend/technique.h new file mode 100644 index 000000000..f4050eb3e --- /dev/null +++ b/src/render/frontend/technique.h @@ -0,0 +1,194 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TECHNIQUE_H +#define TECHNIQUE_H + +#include <qt3dcore_global.h> +#include <node.h> + +#include "tag.h" +#include "renderpass.h" + +#include <QList> +#include <QMap> +#include <QQmlListProperty> +#include <QSharedPointer> + +// FIXME - move enum somewhere common so don't need to include this here +#include <quniformvalue.h> + +namespace Qt3D { + +class QT3DCORESHARED_EXPORT Parameter : public QObject +{ + Q_OBJECT + +public: + // FIXME - sort this by frequency, to minimize the size of the + // vector in RenderShader. (We want to use compact storage, but we index + // by this enum, and resize to the largest value) + enum StandardUniform + { + None = -1, + + ModelMatrix = 0, + ViewMatrix, + ProjectionMatrix, + ModelView, + ModelViewProjection, + + ModelInverse, + ViewInverse, + ProjectionInverse, + ModelViewInverse, + ModelViewProjectionInverse, + + ModelNormal, + ModelViewNormal + }; + + Parameter(QObject* parent, QString name, int ty); + + QString name() const + { return m_name; } + + // permit one extra level of indrection in mesh naming of + // attributes (glTf at least does this) + void setMeshAttributeName(QString name); + QString meshAttributeName() const + { return m_meshName; } + + bool isStandardUniform() const; + + void setStandardUniform(StandardUniform su); + StandardUniform standardUniform() const; + + /** + * @brief setDefaultValue - for non-texture uniform parameters + * @param dv + */ + void setDefaultValue(QVariant dv); + + // setUniformValue(); + + QVariant value() const; + + int datatype() const + { return m_type; } + + bool isTextureType() const; + + /** + * @brief uniformType - map the data type to the primitive uniform type + * @return + */ + Render::QUniformValue::Type uniformType() const; +signals: + void valueChanged(); + +private: + QString m_name; + int m_type; + QVariant m_value; + QVariant m_defaultValue; + QString m_meshName; + StandardUniform m_standardUniform; +}; + +class QT3DCORESHARED_EXPORT Technique : public Node +{ + Q_OBJECT + + Q_PROPERTY(QQmlListProperty<Qt3D::Tag> tags READ tags NOTIFY tagsChanged) + Q_PROPERTY(QQmlListProperty<Qt3D::RenderPass> renderPasses READ renderPassList NOTIFY renderPassesChanged) + +public: + explicit Technique(Node *parent = 0); + + QQmlListProperty<Qt3D::Tag> tags(); + void addTag( const QString& name, const QVariant& value ); + void removeTag( const QString& name ); + void setTagValue( const QString& name, const QVariant& value ); + QVariant tagValue( const QString& name ) const; + bool containsTag( const QString& name ) const; + + + void addPass(RenderPass* pass); + QList<RenderPass *> renderPasses() const; + + QQmlListProperty<Qt3D::RenderPass> renderPassList(); + + + + // QQmlListProperty<Qt3D::Parameter> parameters(); + + void addParameter(Parameter* p); + QList<Parameter *> parameters() const + { return m_parameters; } + + Parameter* parameterByName(QString name) const; +signals: + void tagsChanged(); + void renderPassesChanged(); + +private: + static void appendTag(QQmlListProperty<Tag> *list, Tag *bar); + static Tag *tagAt(QQmlListProperty<Tag> *list, int index); + static int tagCount(QQmlListProperty<Tag> *list); + static void clearTags(QQmlListProperty<Tag> *list); + + static void appendRenderPass(QQmlListProperty<RenderPass> *list, RenderPass* renderPass); + static RenderPass *renderPassAt(QQmlListProperty<RenderPass> *list, int index); + static int renderPassCount(QQmlListProperty<RenderPass> *list); + static void clearRenderPasses( QQmlListProperty<RenderPass> *list); + + QList<Tag *> m_tagList; + QMap<QString, Tag *> m_tags; + + QList<Parameter *> m_parameters; + + QList<RenderPass *> m_renderPasses; +}; + +} + +#endif // TECHNIQUE_H diff --git a/src/render/frontend/techniquefilter.cpp b/src/render/frontend/techniquefilter.cpp new file mode 100644 index 000000000..038fa51f1 --- /dev/null +++ b/src/render/frontend/techniquefilter.cpp @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "techniquefilter.h" + +namespace Qt3D { + +TechniqueFilter::TechniqueFilter(Node *parent) + : Qt3D::Component(parent) +{ +} + +QQmlListProperty<Qt3D::Tag> TechniqueFilter::tags() +{ + return QQmlListProperty<Qt3D::Tag>(this, 0, + &TechniqueFilter::appendTag, + &TechniqueFilter::tagCount, + &TechniqueFilter::tagAt, + &TechniqueFilter::clearTags); +} + +void TechniqueFilter::appendTag(QQmlListProperty<Tag> *list, Tag *tag) +{ + TechniqueFilter *filter = qobject_cast<TechniqueFilter *>(list->object); + if (filter) { + tag->setParent(filter); + filter->m_tagList.append(tag); + emit filter->tagsChanged(); + } +} + +Tag *TechniqueFilter::tagAt(QQmlListProperty<Tag> *list, int index) +{ + TechniqueFilter *filter = qobject_cast<TechniqueFilter *>(list->object); + if (filter) + return filter->m_tagList.value(index); + return 0; +} + +int TechniqueFilter::tagCount(QQmlListProperty<Tag> *list) +{ + TechniqueFilter *filter = qobject_cast<TechniqueFilter *>(list->object); + if (filter) + return filter->m_tagList.size(); + return 0; +} + +void TechniqueFilter::clearTags(QQmlListProperty<Tag> *list) +{ + TechniqueFilter *filter = qobject_cast<TechniqueFilter *>(list->object); + if (filter) { + filter->m_tagList.clear(); + emit filter->tagsChanged(); + } +} + +} // namespace Qt3D diff --git a/src/render/frontend/techniquefilter.h b/src/render/frontend/techniquefilter.h new file mode 100644 index 000000000..102f68a1d --- /dev/null +++ b/src/render/frontend/techniquefilter.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3D_TECHNIQUEFILTER_H +#define QT3D_TECHNIQUEFILTER_H + +#include <qt3dcore_global.h> +#include <component.h> + +#include "tag.h" + +#include <QQmlListProperty> + +namespace Qt3D { + +class TechniqueFilter : public Qt3D::Component +{ + Q_OBJECT + + Q_PROPERTY(QQmlListProperty<Qt3D::Tag> tags READ tags NOTIFY tagsChanged) + Q_CLASSINFO("DefaultProperty", "tags") + +public: + explicit TechniqueFilter(Node *parent = 0); + + QQmlListProperty<Qt3D::Tag> tags(); + +signals: + void tagsChanged(); + +private: + static void appendTag(QQmlListProperty<Tag> *list, Tag *bar); + static Tag *tagAt(QQmlListProperty<Tag> *list, int index); + static int tagCount(QQmlListProperty<Tag> *list); + static void clearTags(QQmlListProperty<Tag> *list); + + QList<Tag *> m_tagList; +}; + +} // namespace Qt3D + +#endif // QT3D_TECHNIQUEFILTER_H diff --git a/src/render/frontend/texture.cpp b/src/render/frontend/texture.cpp new file mode 100644 index 000000000..81c1be5f9 --- /dev/null +++ b/src/render/frontend/texture.cpp @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "texture.h" + +#include <texturedata.h> + +#include <QImage> +#include <QDebug> + +namespace Qt3D { + +QmlTexture::QmlTexture(Node *parent) : + Node(parent), + m_texture(new Texture) +{ + m_texture->setTarget(QOpenGLTexture::Target2D); + m_texture->setInternalFormat(QOpenGLTexture::RGBA8_UNorm); +} + +QUrl QmlTexture::source() const +{ + return m_source; +} + +bool QmlTexture::isRectangle() const +{ + return (m_texture->target() == QOpenGLTexture::TargetRectangle); +} + +Texture *QmlTexture::texture() const +{ + return m_texture; +} + +void QmlTexture::setSource(QUrl arg) +{ + if (m_source != arg) { + m_source = arg; + + if (m_source.isLocalFile()) { + QImage img(m_source.toLocalFile()); + m_texture->setInternalFormat(img.hasAlphaChannel() ? + QOpenGLTexture::RGBA8_UNorm : + QOpenGLTexture::RGB8_UNorm); + + m_texture->setFromQImage(img); + } else { + qWarning() << "implement loading from remote URLs"; + } + + emit sourceChanged(); + } +} + +void QmlTexture::setRectangle(bool r) +{ + m_texture->setTarget(r ? QOpenGLTexture::TargetRectangle : + QOpenGLTexture::Target2D); +} + + +} // namespace Qt3D diff --git a/src/render/frontend/texture.h b/src/render/frontend/texture.h new file mode 100644 index 000000000..910f66aca --- /dev/null +++ b/src/render/frontend/texture.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3D_TEXTURE_H +#define QT3D_TEXTURE_H + +#include "node.h" + +#include <QUrl> + +namespace Qt3D { + +class Texture; + +class QmlTexture : public Node +{ + Q_OBJECT +public: + explicit QmlTexture(Node *parent = 0); + + Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) + Q_PROPERTY(bool rectangle READ isRectangle WRITE setRectangle NOTIFY formatChanged) + + QUrl source() const; + + bool isRectangle() const; + + Texture* texture() const; +signals: + void sourceChanged(); + void formatChanged(); + +public slots: + + + void setSource(QUrl arg); + + void setRectangle(bool r); + +private: + Texture* m_texture; + + QUrl m_source; +}; + +} // namespace Qt3D + +#endif // QT3D_TEXTURE_H diff --git a/src/render/frontend/transform.cpp b/src/render/frontend/transform.cpp new file mode 100644 index 000000000..5ac195dc3 --- /dev/null +++ b/src/render/frontend/transform.cpp @@ -0,0 +1,147 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "transform.h" + +#include <matrixtransform.h> + +namespace Qt3D { + +Transform::Transform(Node *parent) + : Qt3D::Component(parent) +{ +} + +QQmlListProperty<AbstractTransform> Transform::transformList() +{ + return QQmlListProperty<AbstractTransform>(this, 0, + Transform::qmlAppendTransform, + Transform::transformCount, + Transform::transformAt, + Transform::qmlClearTransforms); +} + +QMatrix4x4 Transform::matrix() const +{ + if (m_transformsDirty) { + m_matrix = applyTransforms(); + m_transformsDirty = false; + } + return m_matrix; +} + +void Transform::setMatrix(const QMatrix4x4 &m) +{ + qDeleteAll(m_transforms); + m_transforms.clear(); + appendTransfrom(new MatrixTransform(m)); +} + +/*! + The center of rotation for the entity. Defaults to the local origin. +*/ +QVector3D Transform::rotationCenter() const +{ + return QVector3D(); +} + +QList<AbstractTransform *> Transform::transforms() const +{ + return m_transforms; +} + +void Transform::setRotationCenter(const QVector3D &rc) +{ + Q_UNUSED(rc); +} + +void Transform::appendTransfrom(AbstractTransform *xform) +{ + m_transformsDirty = true; + m_transforms.append( xform ); +} + +void Transform::removeTransform(AbstractTransform *xform) +{ + m_transformsDirty = true; + m_transforms.removeOne( xform ); +} + +QMatrix4x4 Transform::applyTransforms() const +{ + QMatrix4x4 m; + m.setToIdentity(); + Q_FOREACH (AbstractTransform *t, m_transforms) + m = t->matrix() * m; + return m; +} + + +void Transform::qmlAppendTransform(QQmlListProperty<AbstractTransform> *list, AbstractTransform *obj ) +{ + if ( !obj ) + return; + + Transform *self = static_cast<Transform *>(list->object); + self->appendTransfrom(obj); +} + +AbstractTransform* Transform::transformAt(QQmlListProperty<AbstractTransform> *list, int index) +{ + Transform *self = static_cast<Transform *>(list->object); + return self->transforms().at(index); +} + +int Transform::transformCount(QQmlListProperty<AbstractTransform> *list) +{ + Transform *self = static_cast<Transform *>(list->object); + return self->transforms().count(); +} + +void Transform::qmlClearTransforms(QQmlListProperty<AbstractTransform> *list) +{ + Transform *self = static_cast<Transform *>(list->object); + qDeleteAll(self->m_transforms); + self->m_transforms.clear(); + self->m_transformsDirty = true; +} + +} // namespace Qt3D diff --git a/src/render/frontend/transform.h b/src/render/frontend/transform.h new file mode 100644 index 000000000..65cbadb35 --- /dev/null +++ b/src/render/frontend/transform.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3D_TRANSFORM_H +#define QT3D_TRANSFORM_H + +#include <component.h> + +#include <QMatrix4x4> + +namespace Qt3D { + +class AbstractTransform; + +class Transform : public Qt3D::Component +{ + Q_OBJECT + Q_PROPERTY(QQmlListProperty<Qt3D::AbstractTransform> transforms READ transformList) + Q_CLASSINFO("DefaultProperty", "transforms") + +public: + explicit Transform(Node *parent = 0); + + QMatrix4x4 matrix() const; + void setMatrix(const QMatrix4x4 &m); + + QVector3D rotationCenter() const; + void setRotationCenter(const QVector3D &rc); + + QList<AbstractTransform*> transforms() const; + + // void insertTransformAt(...) + Q_INVOKABLE void appendTransfrom(AbstractTransform *xform); + Q_INVOKABLE void removeTransform(AbstractTransform *xform); + + QQmlListProperty<Qt3D::AbstractTransform> transformList(); + +private: + QMatrix4x4 applyTransforms() const; + + static void qmlAppendTransform(QQmlListProperty<Qt3D::AbstractTransform> *list, Qt3D::AbstractTransform *bar); + static AbstractTransform* transformAt(QQmlListProperty<Qt3D::AbstractTransform> *list, int index); + static int transformCount(QQmlListProperty<Qt3D::AbstractTransform> *list); + static void qmlClearTransforms(QQmlListProperty<Qt3D::AbstractTransform> *list); + + mutable bool m_transformsDirty; + bool m_visible; + QList<AbstractTransform*> m_transforms; + + mutable QMatrix4x4 m_matrix; + QMatrix4x4 m_sceneMatrix; +}; + +} // namespace Qt3D + +#endif // QT3D_TRANSFORM_H diff --git a/src/render/frontend/viewport.cpp b/src/render/frontend/viewport.cpp new file mode 100644 index 000000000..8c13190a1 --- /dev/null +++ b/src/render/frontend/viewport.cpp @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "viewport.h" + +namespace Qt3D { + +Viewport::Viewport(Node *parent) + : Component(parent) +{ +} + +QRectF Viewport::rect() const +{ + return m_rect; +} + +void Viewport::setRect(const QRectF &rect) +{ + if (m_rect != rect) { + m_rect = rect; + emit rectChanged( rect ); + } +} + +} diff --git a/src/render/frontend/viewport.h b/src/render/frontend/viewport.h new file mode 100644 index 000000000..7a420d108 --- /dev/null +++ b/src/render/frontend/viewport.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef VIEWPORT_H +#define VIEWPORT_H + +#include <qt3dcore_global.h> + +#include <component.h> + +#include <QRectF> + +namespace Qt3D { + +class Viewport : public Component +{ + Q_OBJECT + + Q_PROPERTY(QRectF rect READ rect WRITE setRect NOTIFY rectChanged) + +public: + explicit Viewport(Node *parent = 0); + + QRectF rect() const; + +public slots: + void setRect( const QRectF& rect ); + +signals: + void rectChanged( const QRectF& arg ); + +private: + QRectF m_rect; +}; + +} + +#endif // VIEWPORT_H diff --git a/src/render/io/gltfparser.cpp b/src/render/io/gltfparser.cpp new file mode 100644 index 000000000..67bd83960 --- /dev/null +++ b/src/render/io/gltfparser.cpp @@ -0,0 +1,842 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "gltfparser.h" + +#include "texturedata.h" + +#include <entity.h> +#include <mesh.h> +#include <material.h> +#include <technique.h> +#include <shaderprogram.h> +#include <effect.h> +#include <camera.h> + +#include <QJsonDocument> +#include <QJsonObject> +#include <QJsonArray> +#include <QFile> +#include <QDir> +#include <QFileInfo> +#include <QQuaternion> +#include <QMatrix4x4> +#include <QColor> +#include <QVector2D> +#include <QVector3D> + +// need to move these to somewhere common? +#include <drawstate.h> +#include <states/blendstate.h> + +namespace Qt3D { + +namespace +{ + +Parameter::StandardUniform parseSemanticName(QString s) +{ + if (s == "MODEL") return Parameter::ModelMatrix; + if (s == "VIEW") return Parameter::ViewMatrix; + if (s == "PROJECTION") return Parameter::ProjectionMatrix; + if (s == "MODELVIEW") return Parameter::ModelView; + if (s == "MODELVIEWPROJECTION") + return Parameter::ModelViewProjection; + + if (s == "MODELINVERSE") return Parameter::ModelInverse; + if (s == "VIEWINVERSE") return Parameter::ViewInverse; + if (s == "PROJECTIONINVERSE") + return Parameter::ProjectionInverse; + if (s == "MODELVIEWINVERSE") + return Parameter::ModelViewInverse; + if (s == "MODELVIEWPROJECTIONINVERSE") + return Parameter::ModelViewProjectionInverse; + + if (s == "MODELINVERSETRANSPOSE") + return Parameter::ModelNormal; + if (s == "MODELVIEWINVERSETRANSPOSE") + return Parameter::ModelViewNormal; + + return Parameter::None; +} + +} // of anonymous namespace + +GLTFParser::GLTFParser() : + m_parseDone(false) +{ +} + +bool GLTFParser::isGLTFPath(QString path) +{ + QFileInfo finfo(path); + if (!finfo.exists()) + return false; + + // might need to detect other things in the future, but would + // prefer to avoid doing a full parse. + return (finfo.suffix().toLower() == "json"); +} + +void GLTFParser::setFilePath(QString path) +{ + QFileInfo finfo(path); + if (!finfo.exists()) { + qWarning() << "missing file:" << path; + return; + } + + QFile f(path); + f.open(QIODevice::ReadOnly); + + if (!setJSON(QJsonDocument::fromJson(f.readAll()))) { + qWarning() << "not a JSON document"; + return; + } + + setBasePath(finfo.dir().absolutePath()); +} + +void GLTFParser::setBasePath(QString path) +{ + m_basePath = path; +} + +bool GLTFParser::setJSON( QJsonDocument json ) +{ + if ( !json.isObject() ) { + return false; + } + + m_json = json; + m_parseDone = false; + + m_meshDict.clear(); + m_attributeDict.clear(); + m_defaultScene.clear(); + + return true; +} + +MeshDataPtr GLTFParser::mesh(QString id) +{ + parse(); + if (m_meshDict.contains(id)) + return m_meshDict.value(id); + + qWarning() << "Unknown mesh" << id << "in GLTF file" << m_basePath; + return MeshDataPtr(); +} + +Entity* GLTFParser::defaultScene() +{ + parse(); + if (m_defaultScene.isEmpty()) { + qWarning() << Q_FUNC_INFO << "no default scene"; + return NULL; + } + + return scene(m_defaultScene); +} + +Entity* GLTFParser::scene(QString id) +{ + parse(); + + QJsonObject scenes = m_json.object().value("scenes").toObject(); + if (!scenes.contains(id)) { + qWarning() << "GLTF: no such scene" << id << "in file" << m_basePath; + return NULL; + } + + QJsonObject sceneObj = scenes.value(id).toObject(); + Entity* sceneEntity = new Entity; + foreach (QJsonValue nnv, sceneObj.value("nodes").toArray()) { + QString nodeName = nnv.toString(); + Entity* child = node(nodeName); + if (!child) + continue; + + sceneEntity->addChild(child); + } + + return sceneEntity; +} + +Entity* GLTFParser::node(QString id) +{ + QJsonObject nodes = m_json.object().value("nodes").toObject(); + if (!nodes.contains(id)) { + qWarning() << "unknown node" << id << "in GLTF file" << m_basePath; + return NULL; + } + + QJsonObject jsonObj = nodes.value(id).toObject(); + Entity* result( new Entity ); + parse(); + + if ( jsonObj.contains( "children" ) ) + { + foreach (QJsonValue c, jsonObj.value( "children" ).toArray()) { + Entity* child = node(c.toString()); + if (!child) + continue; + result->addChild(child); + } + } + + if ( jsonObj.contains( "meshes") ) + { + typedef QList<Mesh*> MeshList; + QMap<QString, MeshList> materialDict; + + foreach (QJsonValue m, jsonObj.value( "meshes" ).toArray()) + { + if (!m_meshDict.contains(m.toString())) { + qWarning() << "node" << id << "references unknown mesh" << m.toString(); + continue; + } + + foreach (MeshDataPtr md, m_meshDict.values(m.toString())) { + QString matId = m_meshMaterialDict[md.data()]; + Mesh* meshComp = new Mesh; + meshComp->setData(md); + materialDict[matId].append(meshComp); + } + } + + if (materialDict.size() == 1) { + // common case + result->addComponent(material(materialDict.firstKey())); + foreach (Mesh* m, materialDict.first()) + result->addComponent(m); + } else { + // need to make a child entity per material + foreach (QString matId, materialDict.keys()) { + Entity* subEntity(new Entity); + result->addChild(subEntity); + + subEntity->addComponent(material(matId)); + foreach (Mesh* m, materialDict.value(matId)) + subEntity->addComponent(m); + } // of distinct material iteration + } // of multiple materials case + } + + processName(jsonObj, result); + + if ( jsonObj.contains( "matrix") ) + { + QMatrix4x4 m; + QJsonArray matrixValues = jsonObj.value( "matrix" ).toArray(); + + for (int i=0; i<16; ++i) { + double v = matrixValues.at( i ).toDouble(); + m(i % 4, i >> 2) = v; + } + + result->setMatrix( m ); + } + + if ( jsonObj.contains( "camera") ) + { + Camera* cam = camera( jsonObj.value("camera").toString() ); + if (!cam) { + qWarning() << "failed to build camera:" << jsonObj.value("camera") + << "on node" << id; + } else { + result->addComponent(cam); + } + } // of have camera attribute + + return result; +} + +// Get rid of miniwindef.h clobbering legal variable names +#if defined(near) +#undef near +#endif + +#if defined(far) +#undef far +#endif + +Camera* GLTFParser::camera(QString id) +{ + parse(); + QJsonObject cams = m_json.object().value("cameras").toObject(); + if (!cams.contains(id)) { + qWarning() << "unknown camera" << id << "in GLTF file" << m_basePath; + return NULL; + } + + QJsonObject jsonObj = cams.value(id).toObject(); + QString camTy = jsonObj.value("type").toString(); + + if (camTy == "perspective") { + if (!jsonObj.contains("perspective")) { + qWarning() << "camera:" << id << "missing 'perspective' object"; + return NULL; + } + + QJsonObject pObj = jsonObj.value("perspective").toObject(); + double yfov = pObj.value("yfov").toDouble(); + double near = pObj.value("znear").toDouble(); + double far = pObj.value("zfar").toDouble(); + + Camera* result = new Camera; + result->setPerspectiveProjection(yfov, 1.0, near, far); + return result; + } else if (camTy == "orthographic") { + qWarning() << Q_FUNC_INFO << "implement me"; + + return NULL; + } else { + qWarning() << "camera:" << id << "has unsupported type:" << camTy; + return NULL; + } +} + +Material* GLTFParser::material(QString id) +{ + parse(); + + if (m_materialCache.contains(id)) + return m_materialCache.value(id); + + QJsonObject mats = m_json.object().value("materials").toObject(); + if (!mats.contains(id)) { + qWarning() << "unknown material" << id << "in GLTF file" << m_basePath; + return NULL; + } + + QJsonObject jsonObj = mats.value(id).toObject(); + + QJsonObject tech = jsonObj.value("instanceTechnique").toObject(); + QString tname = tech.value("technique").toString(); + if (!m_techniques.contains(tname)) { + qWarning() << "unknown technique" << tname << + "for material" << id << "in GLTF file" << m_basePath; + return NULL; + } + + Technique *technique = m_techniques.value(tname); + if (!m_effectProxies.contains(tname)) { + Effect* eff = new Effect; + eff->setObjectName(tname); + eff->addTechnique(technique); + m_effectProxies[tname] = eff; + } + + Material* mat = new Material; + mat->setEffect(m_effectProxies[tname]); + + processName(jsonObj, mat); + + QJsonObject values = tech.value("values").toObject(); + foreach (QString vName, values.keys()) { + Parameter* param = technique->parameterByName(vName); + if (!param) { + qWarning() << "unknown parameter:" << vName << "in technique" << tname + << "processing material" << id; + continue; + } + + if (param->isTextureType()) { + QString textureId = values.value(vName).toString(); + if (!m_textures.contains(textureId)) { + qWarning() << "unknown texture" << textureId << "for parameter" << vName + << "of material" << id; + } else { + mat->setTextureParameter(vName, m_textures.value(textureId)); + } + } else { + QVariant var = parameterValueFromJSON(param, values.value(vName)); + mat->setParameter(vName, var); + } + } // of material technique-instance values iteration + + m_materialCache[id] = mat; + return mat; +} + +void GLTFParser::parse() +{ + if (m_parseDone) + return; + + QJsonObject buffers = m_json.object().value("buffers").toObject(); + foreach (QString nm, buffers.keys()) { + processJSONBuffer( nm, buffers.value(nm).toObject() ); + } + + QJsonObject views = m_json.object().value("bufferViews").toObject(); + foreach (QString nm, views.keys()) { + processJSONBufferView( nm, views.value(nm).toObject() ); + } + + QJsonObject shaders = m_json.object().value("shaders").toObject(); + foreach (QString nm, shaders.keys()) { + processJSONShader( nm, shaders.value(nm).toObject() ); + } + + QJsonObject programs = m_json.object().value("programs").toObject(); + foreach (QString nm, programs.keys()) { + processJSONProgram( nm, programs.value(nm).toObject() ); + } + + QJsonObject techniques = m_json.object().value("techniques").toObject(); + foreach (QString nm, techniques.keys()) { + processJSONTechnique( nm, techniques.value(nm).toObject() ); + } + + QJsonObject attrs = m_json.object().value("accessors").toObject(); + foreach (QString nm, attrs.keys()) { + processJSONAccessor( nm, attrs.value(nm).toObject() ); + } + + QJsonObject meshes = m_json.object().value("meshes").toObject(); + foreach (QString nm, meshes.keys()) { + processJSONMesh( nm, meshes.value(nm).toObject() ); + } + + QJsonObject images = m_json.object().value("images").toObject(); + foreach (QString nm, images.keys()) { + processJSONImage( nm, images.value(nm).toObject() ); + } + + QJsonObject textures = m_json.object().value("textures").toObject(); + foreach (QString nm, textures.keys()) { + processJSONTexture(nm, textures.value(nm).toObject() ); + } + + m_defaultScene = m_json.object().value("scene").toString(); + m_parseDone = true; +} + +void GLTFParser::processJSONBuffer( QString id, const QJsonObject& json ) +{ + // simply cache buffers for lookup by buffer-views + m_bufferDatas[id] = BufferData(json); +} + +void GLTFParser::processJSONBufferView( QString id, const QJsonObject& json ) +{ + QString bufName = json.value("buffer").toString(); + if (!m_bufferDatas.contains(bufName)) { + qWarning() << "unknown buffer:" << bufName << "processing view:" << id; + return; + } + + int target = json.value("target").toInt(); + QOpenGLBuffer::Type ty(QOpenGLBuffer::VertexBuffer); + + switch (target) { + case GL_ARRAY_BUFFER: ty = QOpenGLBuffer::VertexBuffer; break; + case GL_ELEMENT_ARRAY_BUFFER: ty = QOpenGLBuffer::IndexBuffer; break; + default: + qWarning() << Q_FUNC_INFO << "buffer" << id << "unsupported target:" << target; + return; + } + + quint64 offset = 0; + if (json.contains("byteOffset")) { + offset = json.value("byteOffset").toInt(); + qDebug() << "bv:" << id << "has offset:" << offset; + } + + quint64 len = json.value("byteLength").toInt(); + QFile* f = resolveLocalData(m_bufferDatas[bufName].path); + if (!f->seek(offset)) { + qWarning() << "failed to seek to offset in file for bufferView:" << id << offset; + } + + QByteArray bytes = f->read(len); + if (bytes.count() != (int) len) { + qWarning() << "failed to read sufficient bytes from:" << m_bufferDatas[bufName].path + << "for view" << id; + } + delete f; + + BufferPtr b(new Buffer(ty)); + b->setData(bytes); + m_buffers[id] = b; +} + +void GLTFParser::processJSONAccessor( QString id, const QJsonObject& json ) +{ + QString bvName = json.value("bufferView").toString(); + if (!m_buffers.contains(bvName)) { + qWarning() << "unknown buffer-view:" << bvName << "processing accessor:" << id; + return; + } + + BufferPtr buf = m_buffers.value(bvName); + int offset = 0, stride = 0; + int type = json.value("type").toInt(); + int count = json.value("count").toInt(); + + if ( json.contains("byteOffset")) + offset = json.value("byteOffset").toInt(); + if ( json.contains("byteStride")) + stride = json.value("byteStride").toInt(); + + AttributePtr attr( new Attribute( buf, type, count, offset, stride ) ); + m_attributeDict[id] = attr; +} + +void GLTFParser::processJSONMesh( QString id, QJsonObject jsonObj ) +{ + QJsonArray primsArray = jsonObj.value( "primitives").toArray(); + Q_FOREACH (QJsonValue primVal, primsArray) { + QJsonObject primObj = primVal.toObject(); + int type = primObj.value( "primitive").toInt(); + QString material = primObj.value( "material").toString(); + + if ( material.isEmpty()) { + qWarning() << "malformed primitive on " << id << ", missing material value" + << material; + continue; + } + + MeshDataPtr md( new MeshData( type ) ); + m_meshMaterialDict[md.data()] = material; + + QJsonObject attrs = primObj.value("attributes").toObject(); + Q_FOREACH (QString attrName, attrs.keys()) { + QString k = attrs.value(attrName).toString(); + if (!m_attributeDict.contains(k)) { + qWarning() << "unknown attribute accessor:" << k << "on mesh" << id; + continue; + } + + md->addAttribute(attrName, m_attributeDict[k]); + + // qDebug() << "DUMP of:" << attrName; + // m_attributeDict[k]->dump(20); + } + + if ( primObj.contains( "indices" )) { + QString k = primObj.value("indices").toString(); + if (!m_attributeDict.contains(k)) { + qWarning() << "unknown index accessor:" << k << "on mesh" << id; + } else { + md->setIndexAttr(m_attributeDict[k]); + // m_attributeDict[k]->dump(100); + } + } // of has indices + + m_meshDict.insert( id, md ); + } // of primitives iteration +} + +void GLTFParser::processName(const QJsonObject &json, QObject *ins) +{ + if ( json.contains( "name" ) ) + { + ins->setObjectName( json.value("name").toString() ); + } +} + +void GLTFParser::processJSONProgram( QString id, QJsonObject jsonObj) +{ + ShaderProgram* prog = new ShaderProgram; + prog->setObjectName(id); + + QString fragName = jsonObj.value("fragmentShader").toString(), + vertName = jsonObj.value("vertexShader").toString(); + if (!m_shaderPaths.contains(fragName) || !m_shaderPaths.contains(vertName)) { + qWarning() << Q_FUNC_INFO << "program:" << id << "missing shader:" << + fragName << vertName; + return; + } + + prog->setFragmentSourceFile(m_shaderPaths[fragName]); + prog->setVertexSourceFile(m_shaderPaths[vertName]); + m_programs[id] = prog; +} + +void GLTFParser::processJSONShader( QString id, QJsonObject jsonObj) +{ + // shaders are trivial for the moment, defer the real work + // to the program section + QString path = jsonObj.value("path").toString(); + + QFileInfo info(m_basePath, path); + if (!info.exists()) { + qWarning() << "can't find shader" << id << "from path" << path; + return; + } + + m_shaderPaths[id] = info.absoluteFilePath(); +} + +void GLTFParser::processJSONImage( QString id, QJsonObject jsonObj) +{ + QString path = jsonObj.value("path").toString(); + QFileInfo info(m_basePath, path); + if (!info.exists()) { + qWarning() << "can't find image" << id << "from path" << path; + return; + } + + QImage img(info.absoluteFilePath()); + if (img.isNull()) { + qWarning() << "failed to load image:" << info.absoluteFilePath(); + return; + } + + m_images[id] = img; +} + +void GLTFParser::processJSONTexture( QString id, QJsonObject jsonObj) +{ + Texture* tex = new Texture(); + + int target = jsonObj.value("target").toInt(); + int pixelFormat = jsonObj.value("format").toInt(); + int internalFormat = jsonObj.value("internalFormat").toInt(); + + tex->setTarget(static_cast<QOpenGLTexture::Target>(target)); + tex->setInternalFormat(QOpenGLTexture::RGBA8_UNorm /* static_cast<QOpenGLTexture::TextureFormat>(internalFormat)*/); + + QString samplerId = jsonObj.value("sampler").toString(); + QString source = jsonObj.value("source").toString(); + if (!m_images.contains(source)) { + qWarning() << "texture" << id << "references missing image" << source; + return; + } + + tex->setFromQImage(m_images[source]); + + QJsonObject samplersDict(m_json.object().value("samplers").toObject()); + if (!samplersDict.contains(samplerId)) { + qWarning() << "texture" << id << "references unknown sampler" << samplerId; + return; + } + + QJsonObject sampler = samplersDict.value(samplerId).toObject(); + + tex->setWrapMode(static_cast<QOpenGLTexture::WrapMode>(sampler.value("wrapS").toInt())); + // tex->setWrapMode(sampler.value("wrapT").toInt()); + + tex->setMinificationFilter(static_cast<QOpenGLTexture::Filter>(sampler.value("minFilter").toInt())); + tex->setMagnificationFilter(static_cast<QOpenGLTexture::Filter>(sampler.value("magFilter").toInt())); + + m_textures[id] = tex; +} + +void GLTFParser::processJSONTechnique( QString id, QJsonObject jsonObj ) +{ + Technique *t = new Technique; + t->setObjectName(id); + + QHash<QString, Parameter*> paramDict; + QJsonObject params = jsonObj.value( "parameters").toObject(); + Q_FOREACH (QString pname, params.keys()) { + QJsonObject po = params.value(pname).toObject(); + + int dataType = po.value("type").toInt(); + QString semantic = po.value("semantic").toString(); + + Parameter* p = new Parameter(t, pname, dataType); + Parameter::StandardUniform su = parseSemanticName(semantic); + if (su != Parameter::None) { + p->setStandardUniform(su); + } else { + // should really verify it's an attribute parameter? + // but what would be the way to do that? + // check the accessor dict? + p->setMeshAttributeName(semantic); + } + + t->addParameter(p); + + paramDict[pname] = p; + } // of parameters iteration + + QJsonObject passes = jsonObj.value("passes").toObject(); + Q_FOREACH (QString pname, passes.keys()) { + QJsonObject po = passes.value(pname).toObject(); + QJsonObject ip = po.value("instanceProgram").toObject(); + + QString programName = ip.value("program").toString(); + if (!m_programs.contains(programName)) { + qWarning() << Q_FUNC_INFO << "technique" << id << "pass" << pname + << ": missing program" << programName; + continue; + } + + RenderPass* pass = new RenderPass; + pass->setShaderProgram(m_programs[programName]); + + QJsonObject attrs = ip.value("attributes").toObject(); + Q_FOREACH ( QString attrName, attrs.keys() ) { + QString pname = attrs.value(attrName).toString(); + pass->addAttributeBinding(paramDict[pname], attrName); + } // of program-instance attributes + + + QJsonObject uniforms = ip.value("uniforms").toObject(); + Q_FOREACH (QString uniformName, uniforms.keys()) { + QString pname = uniforms.value(uniformName).toString(); + pass->addUniformBinding(paramDict[pname], uniformName); + } // of program-instance attributes + + QJsonObject states = po.value("states").toObject(); + DrawStateSet* ss = new DrawStateSet; + + Q_FOREACH (QString stateName, states.keys()) { + DrawState* s= buildState(stateName, states.value(stateName)); + if (!s) + continue; + + ss->addState(s); + } // of program-instance attributes + + pass->setStateSet(ss); + t->addPass(pass); + } // of passes iteration + + m_techniques[id] = t; +} + +DrawState* GLTFParser::buildState(QString nm, QJsonValue v) +{ + if (nm == "blendEnable") { + return NULL; // will see a blendEquation spec too + } + + if (nm == "blendFunc") { + QJsonObject obj = v.toObject(); + GLenum srcF = static_cast<GLenum>(obj.value("sfactor").toInt()); + GLenum dstF = static_cast<GLenum>(obj.value("dfactor").toInt()); + return BlendState::getOrCreate(srcF, dstF); + } + + if (nm == "blendEquation") { + return BlendEquation::getOrCreate(static_cast<GLenum>(v.toInt())); + } + + if (nm == "cullFaceEnable" && v.toInt()) { + return CullFace::getOrCreate(GL_BACK); + } + + if (nm == "depthTestEnable" && v.toInt()) { + return DepthTest::getOrCreate(GL_LESS); + } + + if (nm == "depthMask") { + return DepthMask::getOrCreate(v.toInt() ? GL_TRUE : GL_FALSE); + } + + qWarning() << Q_FUNC_INFO << "unsupported gltf state:" << nm; + return NULL; +} + +QFile *GLTFParser::resolveLocalData(QString path) +{ + QDir d(m_basePath); + Q_ASSERT(d.exists()); + + QString absPath = d.absoluteFilePath(path); + QFile* f = new QFile(absPath); + f->open(QIODevice::ReadOnly); + return f; +} + +GLTFParser::BufferData::BufferData() : + length(0) +{ +} + +GLTFParser::BufferData::BufferData(QJsonObject json) +{ + path = json.value("path").toString(); + length = json.value("length").toInt(); + // url +} + +QVariant GLTFParser::parameterValueFromJSON(Parameter* p, QJsonValue val) +{ + switch (p->datatype()) { + case GL_BOOL: + return val.toBool(); + + case GL_FLOAT: + return val.toDouble(); + + case GL_FLOAT_VEC2: { + QJsonArray a = val.toArray(); + return QVector2D(a[0].toDouble(), a[1].toDouble()); + } + + case GL_FLOAT_VEC3: { + QJsonArray a = val.toArray(); + return QVector3D(a[0].toDouble(), a[1].toDouble(), a[3].toDouble()); + } + + case GL_FLOAT_VEC4: { + QJsonArray a = val.toArray(); + return QVector4D(a[0].toDouble(), + a[1].toDouble(), + a[2].toDouble(), + a[3].toDouble()); + } + + case GL_FLOAT_MAT4: { + QJsonArray a = val.toArray(); + + QMatrix4x4 m; + for (int i=0; i<16; ++i) { + m(i % 4, i / 4) = a[i].toDouble(); + } + return m; + } + + default: + qWarning() << Q_FUNC_INFO << "unhandled type:" << QString::number(p->datatype(), 16); + } + + return QVariant(); +} + +} // of namespace Qt3D diff --git a/src/render/io/gltfparser.h b/src/render/io/gltfparser.h new file mode 100644 index 000000000..76f8662f5 --- /dev/null +++ b/src/render/io/gltfparser.h @@ -0,0 +1,157 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef GLTFPARSER_H +#define GLTFPARSER_H + +#include "meshdata.h" + +#include <entity.h> +#include <technique.h> + +#include <QJsonDocument> +#include <QMultiHash> +#include <QImage> + +class QFile; + +namespace Qt3D { + +class Material; +class ShaderProgram; +class Effect; +class Camera; +class Texture; + +class GLTFParser +{ +public: + GLTFParser(); + + static bool isGLTFPath(QString path); + + void setFilePath(QString path); + + void setBasePath( QString path ); + + bool setJSON( QJsonDocument json ); + + /** + * @brief instantiate Create Nodes based on glTf JSON document + * @return A new scene-graph fragment based on the provided glTf + */ + Entity *node(QString id); + Entity *defaultScene(); + MeshDataPtr mesh(QString id); + Entity *scene(QString id); + Material *material(QString id); + Camera *camera(QString id); + +private: + void parse(); + + void processJSONMesh( QString id, QJsonObject jsonObj ); + void processJSONAccessor(QString id, const QJsonObject &json); + void processJSONBuffer(QString id, const QJsonObject &json); + void processJSONBufferView(QString id, const QJsonObject &json); + + void processName( const QJsonObject& json, QObject* ins ); + + QJsonDocument m_json; + QString m_basePath; + bool m_parseDone; + QString m_defaultScene; + + // multi-hash because our MeshData corresponds to a single primitive + // in glTf. + QMultiHash<QString, MeshDataPtr> m_meshDict; + + // GLTF assigns materials at the mesh level, but we do them as siblings, + // so record the association here for when we instantiate meshes + QMap<MeshData*, QString> m_meshMaterialDict; + + QMap<QString, AttributePtr> m_attributeDict; + + class BufferData + { + public: + BufferData(); + + BufferData(QJsonObject json); + + quint64 length; + QString path; + // type if ever useful + }; + + QMap<QString, Material*> m_materialCache; + + QMap<QString, BufferData> m_bufferDatas; + QMap<QString, BufferPtr> m_buffers; + + QMap<QString, QString> m_shaderPaths; + QMap<QString, ShaderProgram*> m_programs; + + QMap<QString, Technique *> m_techniques; + // glTF doesn't deal in effects, but we need a trivial one to wrap + // up our techniques + QMap<QString, Effect*> m_effectProxies; + + QMap<QString, Texture*> m_textures; + QMap<QString, QImage> m_images; + + QFile* resolveLocalData(QString path); + + void processJSONShader(QString id, QJsonObject jsonObj); + void processJSONProgram(QString id, QJsonObject jsonObj); + void processJSONTechnique(QString id, QJsonObject jsonObj); + + void processJSONImage(QString id, QJsonObject jsonObj); + void processJSONTexture(QString id, QJsonObject jsonObj); + + QVariant parameterValueFromJSON(Parameter *p, QJsonValue val); + + DrawState *buildState(QString nm, QJsonValue obj); +}; + +} + +#endif // GLTFPARSER_H diff --git a/src/render/io/meshdata.cpp b/src/render/io/meshdata.cpp new file mode 100644 index 000000000..7c68adb6b --- /dev/null +++ b/src/render/io/meshdata.cpp @@ -0,0 +1,422 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "meshdata.h" + +#include <QSet> +#include <QDebug> +#include <QOpenGLVertexArrayObject> + +namespace Qt3D +{ + +GLint elementType(GLint type) +{ + switch (type) { + case GL_FLOAT: + case GL_FLOAT_VEC2: + case GL_FLOAT_VEC3: + case GL_FLOAT_VEC4: + return GL_FLOAT; + + case GL_DOUBLE: + case GL_DOUBLE_VEC2: + case GL_DOUBLE_VEC3: + case GL_DOUBLE_VEC4: + return GL_DOUBLE; + + default: + qWarning() << Q_FUNC_INFO << "unsupported:" << QString::number(type, 16); + } + + return GL_INVALID_VALUE; +} + +GLint tupleSizeFromType(GLint type) +{ + switch (type) { + case GL_FLOAT: + case GL_DOUBLE: + case GL_UNSIGNED_BYTE: + case GL_UNSIGNED_INT: + break; // fall through + + case GL_FLOAT_VEC2: + case GL_DOUBLE_VEC2: return 2; + + case GL_FLOAT_VEC3: + case GL_DOUBLE_VEC3: return 3; + + case GL_FLOAT_VEC4: + case GL_DOUBLE_VEC4: return 4; + + default: + qWarning() << Q_FUNC_INFO << "unsupported:" << QString::number(type, 16); + } + + return 1; +} + +GLuint byteSizeFromType(GLint type) +{ + switch (type) { + case GL_FLOAT: return sizeof(float); + case GL_DOUBLE: return sizeof(double); + case GL_UNSIGNED_BYTE: return sizeof(unsigned char); + case GL_UNSIGNED_INT: return sizeof(GLuint); + + case GL_FLOAT_VEC2: return sizeof(float) * 2; + case GL_DOUBLE_VEC2: return sizeof(double) * 2; + + case GL_FLOAT_VEC3: return sizeof(float) * 3; + case GL_DOUBLE_VEC3: return sizeof(double) * 3; + + case GL_FLOAT_VEC4: return sizeof(float) * 4; + case GL_DOUBLE_VEC4: return sizeof(double) * 4; + + default: + qWarning() << Q_FUNC_INFO << "unsupported:" << QString::number(type, 16); + } + + return 0; +} + +MeshData::MeshData() + : m_primitiveType(0) +{ +} + +MeshData::MeshData(int primitiveType) : + m_primitiveType(primitiveType) +{ + Q_ASSERT((m_primitiveType == GL_TRIANGLES) || + (m_primitiveType == GL_LINES) || + (m_primitiveType == GL_POINTS)); +} + +void MeshData::addAttribute(QString name, AttributePtr attr) +{ + Q_ASSERT(!m_attributes.contains(name)); + m_attributes[name] = attr; +} + +void MeshData::addAttribute(QString name, Attribute *attr) +{ + Q_ASSERT(!m_attributes.contains(name)); + m_attributes[name] = AttributePtr(attr); +} + +void MeshData::setIndexAttr(AttributePtr indexAttr) +{ + m_indexAttr = indexAttr; +} + +void MeshData::setIndexData(BufferPtr buf, int type, int count, int offset) +{ + m_indexAttr = AttributePtr(new Attribute(buf, type, count, offset)); +} + +GLint MeshData::primitiveType() const +{ + return m_primitiveType; +} + +GLsizei MeshData::primitiveCount() const +{ + if (m_indexAttr) { + return m_indexAttr->count(); + } else { + // assume all attribute arrays have the same size + // will break with instanced drawing, but probably per-instance + // arrays aren't coming from this code-path. + // Maybe. + return m_attributes.first()->count(); + } +} + +QStringList MeshData::attributeNames() const +{ + return m_attributes.keys(); +} + +AttributePtr MeshData::attributeByName(QString nm) const +{ + return m_attributes.value(nm); +} + +AttributePtr MeshData::indexAttr() const +{ + return m_indexAttr; +} + +QList<BufferPtr> MeshData::buffers() const +{ + QSet<BufferPtr> r; + if (m_indexAttr) + r.insert(m_indexAttr->buffer()); + + foreach (AttributePtr v, m_attributes.values()) + r.insert(v->buffer()); + + return r.toList(); +} + +void MeshData::setBoundingBox(const AxisAlignedBoundingBox &bbox) +{ + m_box = bbox; +} + +void MeshData::computeBoundsFromAttribute(QString name) +{ + AttributePtr attr = attributeByName(name); + if (!attr) { + qWarning() << Q_FUNC_INFO << "unknoen attribute:" << name; + return; + } + + m_box.clear(); + m_box.update(attr->asVector3D()); +} + +Attribute::Attribute(BufferPtr buf, int type, int count, int offset, int stride) : + m_buffer(buf), + m_type(type), + m_count(count), + m_stride(stride), + m_offset(offset), + m_divisor(0) +{ + +} + +void Attribute::setDivisor(unsigned int divisor) +{ + m_divisor = divisor; +} + +BufferPtr Attribute::buffer() const +{ + return m_buffer; +} + +QVector<QVector3D> Attribute::asVector3D() const +{ + const char* rawBuffer = m_buffer->data().constData(); + rawBuffer += m_offset; + const float* fptr; + int stride; + + switch (type()) { + case GL_FLOAT_VEC2: + stride = sizeof(float) * 2; break; + + case GL_FLOAT_VEC3: + stride = sizeof(float) * 3; break; + + case GL_FLOAT_VEC4: + stride = sizeof(float) * 4; break; + + default: + qDebug() << Q_FUNC_INFO << "can't convert" << QString::number(type(), 16) << "to QVector3D"; + return QVector<QVector3D>(); + } + + if (m_stride != 0) + stride = m_stride; + QVector<QVector3D> result; + result.resize(m_count); + + for (int c=0; c<m_count; ++c) { + QVector3D v; + fptr = reinterpret_cast<const float*>(rawBuffer); + + switch (type()) { + case GL_FLOAT_VEC2: + v.setX(fptr[0]); + v.setY(fptr[1]); + v.setZ(0.0f); + break; + + case GL_FLOAT_VEC3: + case GL_FLOAT_VEC4: + v.setX(fptr[0]); + v.setY(fptr[1]); + v.setZ(fptr[2]); + break; + + default: + break; // should never happen, we check types above + } + + result[c] = v; + rawBuffer += stride; + } + + return result; +} + +QVector<QVector2D> Attribute::asVector2D() const +{ + char* rawBuffer = m_buffer->data().data(); + rawBuffer += m_offset; + float* fptr; + int stride; + + switch (type()) { + case GL_FLOAT_VEC2: + stride = sizeof(float) * 2; break; + + case GL_FLOAT_VEC3: + stride = sizeof(float) * 3; break; + + case GL_FLOAT_VEC4: + stride = sizeof(float) * 4; break; + + default: + qDebug() << Q_FUNC_INFO << "can't convert" << QString::number(type(), 16) << "to QVector2D"; + return QVector<QVector2D>(); + } + + if (m_stride != 0) + stride = m_stride; + + QVector<QVector2D> result; + result.resize(m_count); + + for (int c=0; c<m_count; ++c) { + QVector2D v; + fptr = reinterpret_cast<float*>(rawBuffer); + v.setX(fptr[0]); + v.setY(fptr[1]); + result[c] = v; + rawBuffer += stride; + } + + return result; +} + +void Attribute::dump(int count) +{ + char* rawBuffer = m_buffer->data().data(); + rawBuffer += m_offset; + + float* fptr; + quint16* usptr; + + int stride = m_stride; + + for (int c=0; c<count; ++c) { + switch (type()) { + case GL_UNSIGNED_SHORT: + if (!stride) stride = sizeof(quint16); + usptr = reinterpret_cast<quint16*>(rawBuffer); + qDebug() << c << ":u16:" << usptr[0]; + break; + + case GL_FLOAT_VEC2: + if (!stride) stride = sizeof(float) * 2; + fptr = reinterpret_cast<float*>(rawBuffer); + qDebug() << c << ":vec2:"<< fptr[0] << fptr[0]; + break; + + case GL_FLOAT_VEC3: + if (!stride) stride = sizeof(float) * 3; + fptr = reinterpret_cast<float*>(rawBuffer); + qDebug() << c << ":vec3:" << fptr[0] << fptr[0] << fptr[2]; + break; + + default: qDebug() << Q_FUNC_INFO << "unspported type:" << QString::number(type(), 16); + } + + + } +} + +Buffer::Buffer(QOpenGLBuffer::Type ty) : + m_type(ty), + m_usage(QOpenGLBuffer::StaticDraw) +{ +} + +void Buffer::setUsage(QOpenGLBuffer::UsagePattern usage) +{ + m_usage = usage; +} + +void Buffer::setData(QByteArray bytes) +{ + m_clientSideBytes = bytes; + // mark as dirty for dynamic / stream data + // if static, check this is the first and only set. +} + +QByteArray Buffer::data() const +{ + return m_clientSideBytes; +} + +QOpenGLBuffer Buffer::createGL() const +{ + QOpenGLBuffer b(m_type); + b.setUsagePattern(m_usage); + if (!b.create()) + qWarning() << Q_FUNC_INFO << "buffer creation failed"; + + if (!b.bind()) + qWarning() << Q_FUNC_INFO << "buffer binding failed"; + + b.allocate(m_clientSideBytes.count()); + b.release(); + return b; +} + +void Buffer::upload(QOpenGLBuffer b) +{ + if (!b.bind()) + qWarning() << Q_FUNC_INFO << "buffer bind failed"; + b.allocate(NULL, m_clientSideBytes.count()); // orphan the buffer + b.allocate(m_clientSideBytes.data(), + m_clientSideBytes.count()); + b.release(); + qDebug() << "uploaded buffer size=" << m_clientSideBytes.count(); +} + +} // of namespace diff --git a/src/render/io/meshdata.h b/src/render/io/meshdata.h new file mode 100644 index 000000000..92a9330bb --- /dev/null +++ b/src/render/io/meshdata.h @@ -0,0 +1,181 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MESHDATA_H +#define MESHDATA_H + +#include <QSharedPointer> +#include <QList> +#include <QMap> +#include <QOpenGLBuffer> +#include <QVector2D> + +#include <axisalignedboundingbox.h> + + +namespace Qt3D +{ + +GLint elementType(GLint type); +GLint tupleSizeFromType(GLint type); +GLuint byteSizeFromType(GLint type); + +class Buffer +{ +public: + Buffer(QOpenGLBuffer::Type ty); + + void setUsage(QOpenGLBuffer::UsagePattern usage); + + void setData(QByteArray bytes); + QByteArray data() const; + + QOpenGLBuffer::Type type() const + { return m_type; } + + void bind(); + + QOpenGLBuffer createGL() const; + void upload(QOpenGLBuffer b); + + // make a QObject and signal when contents change? + // GraphicsContext could listen, orphan the QOpenGLBuffer and hence + // reupload next time it's need +private: + const QOpenGLBuffer::Type m_type; + QOpenGLBuffer::UsagePattern m_usage; + QByteArray m_clientSideBytes; +}; + +typedef QSharedPointer<Buffer> BufferPtr; + +class Attribute +{ +public: + Attribute(BufferPtr buf, int type, int count, int offset=0, int stride = 0); + + void setDivisor(unsigned int divisor); + + unsigned int divisor() const + { return m_divisor; } + + BufferPtr buffer() const; + + int type() const + { return m_type; } + + unsigned int count() const + { return m_count; } + + unsigned int byteStride() const + { return m_stride; } + + unsigned int byteOffset() const + { return m_offset; } + + QVector<QVector3D> asVector3D() const; + QVector<QVector2D> asVector2D() const; + + void dump(int count); +private: + BufferPtr m_buffer; + int m_type, m_count; + unsigned int m_stride, m_offset; // both in bytes + // AxisAlignedBoundBox m_range; + unsigned int m_divisor; +}; + +typedef QSharedPointer<Attribute> AttributePtr; + +/** + * @brief The MeshData class is shared by all instances of a RenderMesh, + * and holds the actual client (CPU)-side buffers representing mesh attributes + * and indices. + */ +class MeshData +{ +public: + MeshData(); + explicit MeshData(int primitiveType); + + void addAttribute(QString name, AttributePtr attr); + + // permit inline 'new' call, will take ownership + void addAttribute(QString name, Attribute* attr); + + void setIndexAttr(AttributePtr indexAttr); + void setIndexData(BufferPtr buf, int type, int count, int offset = 0); + + GLint primitiveType() const; + GLsizei primitiveCount() const; + + QStringList attributeNames() const; + + AttributePtr attributeByName(QString nm) const; + + AttributePtr indexAttr() const; + + QString materialName() const; + + QList<BufferPtr> buffers() const; + + // specify the bounding box explicitly + void setBoundingBox(const AxisAlignedBoundingBox& bbox); + + void computeBoundsFromAttribute(QString name); + + AxisAlignedBoundingBox boundingBox() const + { return m_box; } +private: + QMap<QString, AttributePtr> m_attributes; + QString m_materialName; + + int m_primitiveType; + AttributePtr m_indexAttr; + + AxisAlignedBoundingBox m_box; +}; + +typedef QSharedPointer<MeshData> MeshDataPtr; + +} + +#endif // MESHDATA_H diff --git a/src/render/io/objloader.cpp b/src/render/io/objloader.cpp new file mode 100644 index 000000000..a01aa5e2e --- /dev/null +++ b/src/render/io/objloader.cpp @@ -0,0 +1,442 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "objloader.h" + +#include "mesh.h" +#include "axisalignedboundingbox.h" + +#include <QDebug> +#include <QFile> +#include <QOpenGLBuffer> +#include <QOpenGLShaderProgram> +#include <QTextStream> +#include <QVector> + +namespace Qt3D { + +inline uint qHash(const Qt3D::FaceIndices &faceIndices) +{ + return faceIndices.positionIndex + + 10 * faceIndices.texCoordIndex + + 100 * faceIndices.normalIndex; +} + +ObjLoader::ObjLoader() + : m_loadTextureCoords( true ), + m_generateTangents( true ), + m_centerMesh( false ) +{ +} + +bool ObjLoader::load( const QString& fileName ) +{ + QFile file( fileName ); + if ( !file.open( ::QIODevice::ReadOnly | ::QIODevice::Text ) ) + { + qDebug() << "Could not open file" << fileName << "for reading"; + return false; + } + + return load( &file ); +} + +static void addFaceVertex(const FaceIndices &faceIndices, + QVector<FaceIndices> &faceIndexVector, + QHash<FaceIndices, unsigned int> &faceIndexMap) +{ + if (faceIndices.positionIndex != std::numeric_limits<unsigned int>::max()) { + faceIndexVector.append(faceIndices); + if (!faceIndexMap.contains(faceIndices)) + faceIndexMap.insert(faceIndices, faceIndexMap.size()); + } else { + qWarning( "Missing position index" ); + } +} + +bool ObjLoader::load(::QIODevice *ioDev) +{ + Q_CHECK_PTR(ioDev); + if (!ioDev->isOpen()) { + qWarning() << "iodevice" << ioDev << "not open for reading"; + return false; + } + + int faceCount = 0; + + // Parse faces taking into account each vertex in a face can index different indices + // for the positions, normals and texture coords; + // Generate unique vertices (in OpenGL parlance) and output to m_points, m_texCoords, + // m_normals and calculate mapping from faces to unique indices + QVector<QVector3D> positions; + QVector<QVector3D> normals; + QVector<QVector2D> texCoords; + QHash<FaceIndices, unsigned int> faceIndexMap; + QVector<FaceIndices> faceIndexVector; + + QTextStream stream(ioDev); + while (!stream.atEnd()) { + QString line = stream.readLine(); + line = line.simplified(); + + if (line.length() > 0 && line.at(0) != QChar::fromLatin1('#')) { + QTextStream lineStream(&line, QIODevice::ReadOnly); + QString token; + lineStream >> token; + + if (token == QStringLiteral("v")) { + float x, y, z; + lineStream >> x >> y >> z; + positions.append(QVector3D( x, y, z )); + } else if (token == QStringLiteral("vt") && m_loadTextureCoords) { + // Process texture coordinate + float s,t; + lineStream >> s >> t; + texCoords.append(QVector2D(s, t)); + } else if (token == QStringLiteral("vn")) { + float x, y, z; + lineStream >> x >> y >> z; + normals.append(QVector3D( x, y, z )); + } else if (token == QStringLiteral("f")) { + // Process face + ++faceCount; + QVector<FaceIndices> face; + int faceVertices = 0; + while (!lineStream.atEnd()) { + QString faceString; + lineStream >> faceString; + + FaceIndices faceIndices; + QStringList indices = faceString.split(QChar::fromLatin1('/')); + switch (indices.size()) { + case 3: + faceIndices.normalIndex = indices.at(2).toInt() - 1; // fall through + case 2: + faceIndices.texCoordIndex = indices.at(1).toInt() - 1; // fall through + case 1: + faceIndices.positionIndex = indices.at(0).toInt() - 1; + break; + default: + qWarning() << "Unsupported number of indices in face element"; + } + + face.append(faceIndices); + ++faceVertices; + } + + // If number of edges in face is greater than 3, + // decompose into triangles as a triangle fan. + FaceIndices v0 = face[0]; + FaceIndices v1 = face[1]; + FaceIndices v2 = face[2]; + + // First face + addFaceVertex(v0, faceIndexVector, faceIndexMap); + addFaceVertex(v1, faceIndexVector, faceIndexMap); + addFaceVertex(v2, faceIndexVector, faceIndexMap); + + for ( int i = 3; i < face.size(); ++i ) { + v1 = v2; + v2 = face[i]; + addFaceVertex(v0, faceIndexVector, faceIndexMap); + addFaceVertex(v1, faceIndexVector, faceIndexMap); + addFaceVertex(v2, faceIndexVector, faceIndexMap); + } + } // end of face + } // end of input line + } // while (!stream.atEnd()) + + updateIndices(positions, normals, texCoords, faceIndexMap, faceIndexVector); + + if (m_normals.isEmpty()) + generateAveragedNormals(m_points, m_normals, m_indices); + + if (m_generateTangents && !m_texCoords.isEmpty()) + generateTangents(m_points, m_normals, m_indices, m_texCoords, m_tangents); + + if (m_centerMesh) + center(m_points); + +//#if 0 + qDebug() << "Loaded mesh:"; + qDebug() << " " << m_points.size() << "points"; + qDebug() << " " << faceCount << "faces"; + qDebug() << " " << m_indices.size() / 3 << "triangles."; + qDebug() << " " << m_normals.size() << "normals"; + qDebug() << " " << m_tangents.size() << "tangents "; + qDebug() << " " << m_texCoords.size() << "texture coordinates."; +//#endif + + return true; +} + +MeshDataPtr ObjLoader::mesh() const +{ + MeshDataPtr mesh(new MeshData(GL_TRIANGLES)); + + QByteArray bufferBytes; + const int count = m_points.size(); + quint32 elementSize = 3 + (hasTextureCoordinates() ? 2 : 0) + + (hasNormals() ? 3 : 0) + + (hasTangents() ? 4 : 0); + quint32 stride = elementSize * sizeof(float); + bufferBytes.resize(stride * count); + float* fptr = reinterpret_cast<float*>(bufferBytes.data()); + + for (int index = 0; index < count; ++index) { + *fptr++ = m_points.at(index).x(); + *fptr++ = m_points.at(index).y(); + *fptr++ = m_points.at(index).z(); + + if (hasTextureCoordinates()) { + *fptr++ = m_texCoords.at(index).x(); + *fptr++ = m_texCoords.at(index).y(); + } + + if (hasNormals()) { + *fptr++ = m_normals.at(index).x(); + *fptr++ = m_normals.at(index).y(); + *fptr++ = m_normals.at(index).z(); + } + + if (hasTangents()) { + *fptr++ = m_tangents.at(index).x(); + *fptr++ = m_tangents.at(index).y(); + *fptr++ = m_tangents.at(index).z(); + *fptr++ = m_tangents.at(index).w(); + } + } // of buffer filling loop + + BufferPtr buf(new Buffer(QOpenGLBuffer::VertexBuffer)); + buf->setUsage(QOpenGLBuffer::StaticDraw); + buf->setData(bufferBytes); + + + mesh->addAttribute("position", new Attribute(buf, GL_FLOAT_VEC3, count, 0, stride)); + quint32 offset = sizeof(float) * 3; + + if (hasTextureCoordinates()) { + mesh->addAttribute("texcoord", new Attribute(buf, GL_FLOAT_VEC2, count, offset, stride)); + offset += sizeof(float) * 2; + } + + if (hasNormals()) { + mesh->addAttribute("normal", new Attribute(buf, GL_FLOAT_VEC3, count, offset, stride)); + offset += sizeof(float) * 3; + } + + if (hasTangents()) { + mesh->addAttribute("tangent", new Attribute(buf, GL_FLOAT_VEC4, count, offset, stride)); + offset += sizeof(float) * 4; + } + + QByteArray indexBytes; + GLuint ty; + if (m_indices.size() < 65536) { + // we can use USHORT + ty = GL_UNSIGNED_SHORT; + indexBytes.resize(m_indices.size() * sizeof(quint16)); + quint16* usptr = reinterpret_cast<quint16*>(indexBytes.data()); + for (int i=0; i<m_indices.size(); ++i) + *usptr++ = static_cast<quint16>(m_indices.at(i)); + } else { + // use UINT - no conversion needed, but let's ensure int is 32-bit! + ty = GL_UNSIGNED_INT; + Q_ASSERT(sizeof(int) == sizeof(quint32)); + indexBytes.resize(m_indices.size() * sizeof(quint32)); + memcpy(indexBytes.data(), reinterpret_cast<const char*>(m_indices.data()), indexBytes.size()); + } + + BufferPtr indexBuffer(new Buffer(QOpenGLBuffer::IndexBuffer)); + indexBuffer->setUsage(QOpenGLBuffer::StaticDraw); + indexBuffer->setData(indexBytes); + mesh->setIndexAttr(AttributePtr(new Attribute(indexBuffer, ty, m_indices.size(), 0, 0))); + + mesh->computeBoundsFromAttribute("position"); + qDebug() << "computed bounds is:" << mesh->boundingBox(); + + return mesh; +} + +void ObjLoader::updateIndices(const QVector<QVector3D> &positions, + const QVector<QVector3D> &normals, + const QVector<QVector2D> &texCoords, + const QHash<FaceIndices, unsigned int> &faceIndexMap, + const QVector<FaceIndices> &faceIndexVector) +{ + // Iterate over the faceIndexMap and pull out pos, texCoord and normal data + // thereby generating unique vertices of data (by OpenGL definition) + const int vertexCount = faceIndexMap.size(); + const bool hasTexCoords = !texCoords.isEmpty(); + const bool hasNormals = !normals.isEmpty(); + + m_points.resize(vertexCount); + m_texCoords.clear(); + if (hasTexCoords) + m_texCoords.resize(vertexCount); + m_normals.clear(); + if (hasNormals) + m_normals.resize(vertexCount); + + foreach (const FaceIndices &faceIndices, faceIndexMap.keys()) { + const int i = faceIndexMap.value(faceIndices); + + m_points[i] = positions[faceIndices.positionIndex]; + if (hasTexCoords) + m_texCoords[i] = texCoords[faceIndices.texCoordIndex]; + if (hasNormals) + m_normals[i] = normals[faceIndices.normalIndex]; + } + + // Now iterate over the face indices and lookup the unique vertex index + const int indexCount = faceIndexVector.size(); + m_indices.clear(); + m_indices.reserve(indexCount); + foreach (const FaceIndices &faceIndices, faceIndexVector) { + const unsigned int i = faceIndexMap.value(faceIndices); + m_indices.append(i); + } +} + +void ObjLoader::generateAveragedNormals( const QVector<QVector3D>& points, + QVector<QVector3D>& normals, + const QVector<unsigned int>& faces ) const +{ + for ( int i = 0; i < points.size(); ++i ) + normals.append( QVector3D() ); + + for ( int i = 0; i < faces.size(); i += 3 ) + { + const QVector3D& p1 = points[ faces[i] ]; + const QVector3D& p2 = points[ faces[i+1] ]; + const QVector3D& p3 = points[ faces[i+2] ]; + + QVector3D a = p2 - p1; + QVector3D b = p3 - p1; + QVector3D n = QVector3D::crossProduct( a, b ).normalized(); + + normals[ faces[i] ] += n; + normals[ faces[i+1] ] += n; + normals[ faces[i+2] ] += n; + } + + for ( int i = 0; i < normals.size(); ++i ) + normals[i].normalize(); +} + +void ObjLoader::generateTangents( const QVector<QVector3D>& points, + const QVector<QVector3D>& normals, + const QVector<unsigned int>& faces, + const QVector<QVector2D>& texCoords, + QVector<QVector4D>& tangents ) const +{ + tangents.clear(); + QVector<QVector3D> tan1Accum; + QVector<QVector3D> tan2Accum; + + for ( int i = 0; i < points.size(); i++ ) + { + tan1Accum.append( QVector3D() ); + tan2Accum.append( QVector3D() ); + tangents.append( QVector4D() ); + } + + // Compute the tangent vector + for ( int i = 0; i < faces.size(); i += 3 ) + { + const QVector3D& p1 = points[ faces[i] ]; + const QVector3D& p2 = points[ faces[i+1] ]; + const QVector3D& p3 = points[ faces[i+2] ]; + + const QVector2D& tc1 = texCoords[ faces[i] ]; + const QVector2D& tc2 = texCoords[ faces[i+1] ]; + const QVector2D& tc3 = texCoords[ faces[i+2] ]; + + QVector3D q1 = p2 - p1; + QVector3D q2 = p3 - p1; + float s1 = tc2.x() - tc1.x(), s2 = tc3.x() - tc1.x(); + float t1 = tc2.y() - tc1.y(), t2 = tc3.y() - tc1.y(); + float r = 1.0f / ( s1 * t2 - s2 * t1 ); + QVector3D tan1( ( t2 * q1.x() - t1 * q2.x() ) * r, + ( t2 * q1.y() - t1 * q2.y() ) * r, + ( t2 * q1.z() - t1 * q2.z() ) * r ); + QVector3D tan2( ( s1 * q2.x() - s2 * q1.x() ) * r, + ( s1 * q2.y() - s2 * q1.y() ) * r, + ( s1 * q2.z() - s2 * q1.z() ) * r ); + tan1Accum[ faces[i] ] += tan1; + tan1Accum[ faces[i+1] ] += tan1; + tan1Accum[ faces[i+2] ] += tan1; + tan2Accum[ faces[i] ] += tan2; + tan2Accum[ faces[i+1] ] += tan2; + tan2Accum[ faces[i+2] ] += tan2; + } + + for ( int i = 0; i < points.size(); ++i ) + { + const QVector3D& n = normals[i]; + QVector3D& t1 = tan1Accum[i]; + QVector3D& t2 = tan2Accum[i]; + + // Gram-Schmidt orthogonalize + tangents[i] = QVector4D( QVector3D( t1 - QVector3D::dotProduct( n, t1 ) * n ).normalized(), 0.0f ); + + // Store handedness in w + tangents[i].setW( ( QVector3D::dotProduct( QVector3D::crossProduct( n, t1 ), t2 ) < 0.0f ) ? -1.0f : 1.0f ); + } +} + +void ObjLoader::center( QVector<QVector3D>& points ) +{ + if ( points.isEmpty() ) + return; + + AxisAlignedBoundingBox bb(points); + QVector3D center = bb.center(); + + // Translate center of the AABB to the origin + for ( int i = 0; i < points.size(); ++i ) + { + QVector3D& point = points[i]; + point = point - center; + } +} + +} diff --git a/src/render/io/objloader.h b/src/render/io/objloader.h new file mode 100644 index 000000000..6c7ae93c0 --- /dev/null +++ b/src/render/io/objloader.h @@ -0,0 +1,143 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef OBJLOADER_H +#define OBJLOADER_H + +#include "meshdata.h" + +#include <QVector> +#include <QVector2D> +#include <QVector3D> +#include <QVector4D> + +#include <limits> + +class QString; +class QIODevice; + +namespace Qt3D { + +struct FaceIndices +{ + FaceIndices() + : positionIndex(std::numeric_limits<unsigned int>::max()) + , texCoordIndex(std::numeric_limits<unsigned int>::max()) + , normalIndex(std::numeric_limits<unsigned int>::max()) + {} + + FaceIndices(unsigned int posIndex, unsigned int tcIndex, unsigned int nIndex) + : positionIndex(posIndex) + , texCoordIndex(tcIndex) + , normalIndex(nIndex) + {} + + bool operator == (const FaceIndices &other) const + { + return positionIndex == other.positionIndex && + texCoordIndex == other.texCoordIndex && + normalIndex == other.normalIndex; + } + + unsigned int positionIndex; + unsigned int texCoordIndex; + unsigned int normalIndex; +}; + +class ObjLoader +{ +public: + ObjLoader(); + + void setLoadTextureCoordinatesEnabled( bool b ) { m_loadTextureCoords = b; } + bool isLoadTextureCoordinatesEnabled() const { return m_loadTextureCoords; } + + void setTangentGenerationEnabled( bool b ) { m_generateTangents = b; } + bool isTangentGenerationEnabled() const { return m_generateTangents; } + + void setMeshCenteringEnabled( bool b ) { m_centerMesh = b; } + bool isMeshCenteringEnabled() const { return m_centerMesh; } + + bool hasNormals() const { return !m_normals.isEmpty(); } + bool hasTextureCoordinates() const { return !m_texCoords.isEmpty(); } + bool hasTangents() const { return !m_tangents.isEmpty(); } + + bool load( const QString& fileName ); + bool load( ::QIODevice* ioDev ); + + QVector<QVector3D> vertices() const { return m_points; } + QVector<QVector3D> normals() const { return m_normals; } + QVector<QVector2D> textureCoordinates() const { return m_texCoords; } + QVector<QVector4D> tangents() const { return m_tangents; } + QVector<unsigned int> indices() const { return m_indices; } + + MeshDataPtr mesh() const; + +private: + void updateIndices(const QVector<QVector3D> &positions, + const QVector<QVector3D> &normals, + const QVector<QVector2D> &texCoords, + const QHash<FaceIndices, unsigned int> &faceIndexMap, + const QVector<FaceIndices> &faceIndexVector); + void generateAveragedNormals( const QVector<QVector3D>& points, + QVector<QVector3D>& normals, + const QVector<unsigned int>& faces ) const; + void generateTangents( const QVector<QVector3D>& points, + const QVector<QVector3D>& normals, + const QVector<unsigned int>& faces, + const QVector<QVector2D>& texCoords, + QVector<QVector4D>& tangents ) const; + void center( QVector<QVector3D>& points ); + + bool m_loadTextureCoords; + bool m_generateTangents; + bool m_centerMesh; + + QVector<QVector3D> m_points; + QVector<QVector3D> m_normals; + QVector<QVector2D> m_texCoords; + QVector<QVector4D> m_tangents; + QVector<unsigned int> m_indices; +}; + +} + +#endif // OBJLOADER_H diff --git a/src/render/io/render-io.pri b/src/render/io/render-io.pri new file mode 100644 index 000000000..18e19540f --- /dev/null +++ b/src/render/io/render-io.pri @@ -0,0 +1,13 @@ +INCLUDEPATH += $$PWD + +HEADERS += \ + $$PWD/meshdata.h \ + $$PWD/gltfparser.h \ + $$PWD/objloader.h \ + $$PWD/texturedata.h + +SOURCES += \ + $$PWD/meshdata.cpp \ + $$PWD/gltfparser.cpp \ + $$PWD/objloader.cpp \ + $$PWD/texturedata.cpp diff --git a/src/render/io/texturedata.cpp b/src/render/io/texturedata.cpp new file mode 100644 index 000000000..3a1b8aa8f --- /dev/null +++ b/src/render/io/texturedata.cpp @@ -0,0 +1,167 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "texturedata.h" + +#include <QDebug> +#include <QOpenGLTexture> + +namespace Qt3D { + +Texture::Texture() : + m_target(QOpenGLTexture::Target2D), + m_width(1), + m_height(1), + m_depth(1), + m_autoMipMap(false) +{ +} + +void Texture::setTarget(QOpenGLTexture::Target target) +{ + m_target = target; +} + +void Texture::setSize(int w, int h, int d) +{ + m_width = w; + m_height = h; + m_depth = d; +} + +int Texture::width() const +{ + return m_width; +} + +int Texture::height() const +{ + return m_height; +} + +int Texture::depth() const +{ + return m_depth; +} + +void Texture::setInternalFormat(QOpenGLTexture::TextureFormat format) +{ + m_format = format; +} + +bool Texture::setFromQImage(QImage img, int layer) +{ + setSize(img.width(), img.height()); + + if ((m_target != QOpenGLTexture::Target2D) && + (m_target != QOpenGLTexture::Target2DArray) && + (m_target == QOpenGLTexture::TargetRectangle)) + { + qWarning() << Q_FUNC_INFO << "invalid texture target"; + return false; + } + + TexImageDataPtr dataPtr(new TexImageData(0, layer)); + dataPtr->setImage(img); + addImageData(dataPtr); + + return true; +} + +void Texture::addImageData(TexImageDataPtr imgData) +{ + m_data.append(imgData); +} + +QList<TexImageDataPtr> Texture::imageData() const +{ + return m_data; +} + +void Texture::setGenerateMipMaps(bool gen) +{ + m_autoMipMap = gen; +} + +void Texture::setMinificationFilter(QOpenGLTexture::Filter f) +{ + m_minFilter = f; +} + +void Texture::setMagnificationFilter(QOpenGLTexture::Filter f) +{ + m_magFilter = f; +} + +void Texture::setWrapMode(QOpenGLTexture::WrapMode wrapMode) +{ + m_wrapMode = wrapMode; +} + +///////////////////////////////////////////////////////////////////////////// + +TexImageData::TexImageData(int level, int layer) : + m_layer(layer), + m_mipMapLevel(level), + m_cubeFace(QOpenGLTexture::CubeMapPositiveX), + m_isCompressed(false) +{ + +} + +void TexImageData::setImage(QImage image) +{ + QImage glImage = image.convertToFormat(QImage::Format_RGBA8888); +// setData(0, QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, glImage.bits(), &uploadOptions); + + QByteArray imageBytes((const char*) glImage.constBits(), glImage.byteCount()); + setData(imageBytes, QOpenGLTexture::RGBA, QOpenGLTexture::UInt8); +} + +void TexImageData::setData(QByteArray data, QOpenGLTexture::PixelFormat fmt, QOpenGLTexture::PixelType ptype) +{ + m_isCompressed = false; + m_data = data; + m_pixelFormat = fmt; + m_pixelType = ptype; +} + +} // namespace Qt3D diff --git a/src/render/io/texturedata.h b/src/render/io/texturedata.h new file mode 100644 index 000000000..6ce214c26 --- /dev/null +++ b/src/render/io/texturedata.h @@ -0,0 +1,164 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3D_TEXTUREDATA_H +#define QT3D_TEXTUREDATA_H + +#include <QOpenGLTexture> +#include <QImage> +#include <QSharedPointer> + +namespace Qt3D { + +class TexImageData +{ +public: + TexImageData(int level, int layer); + + QOpenGLTexture::CubeMapFace cubeFace() const + { return m_cubeFace; } + + void setCubeFace(QOpenGLTexture::CubeMapFace face); + + int layer() const + { return m_layer; } + + int mipMapLevel() const + { return m_mipMapLevel; } + + bool isCompressed() const + { return m_isCompressed; } + + void setImage(QImage); + + void setData(QByteArray data, + QOpenGLTexture::PixelFormat fmt, + QOpenGLTexture::PixelType ptype); + void setCompressedData(QByteArray data, QOpenGLTexture::PixelFormat fmt); + + QByteArray data() const + { return m_data; } + + QOpenGLTexture::PixelFormat pixelFormat() const + { return m_pixelFormat; } + + QOpenGLTexture::PixelType pixelType() const + { return m_pixelType; } + +private: + int m_layer, m_mipMapLevel; + QOpenGLTexture::CubeMapFace m_cubeFace; + QOpenGLTexture::PixelFormat m_pixelFormat; + QOpenGLTexture::PixelType m_pixelType; + + bool m_isCompressed; + QByteArray m_data; +}; + +typedef QSharedPointer<TexImageData> TexImageDataPtr; + +class Texture +{ +public: + Texture(); + + void setTarget(QOpenGLTexture::Target target); + + void setInternalFormat(QOpenGLTexture::TextureFormat format); + + QOpenGLTexture::TextureFormat format() const + { return m_format; } + + QOpenGLTexture::Target target() const + { return m_target; } + + /** + * @brief setFromQImage - set size and image data based upon a QImage + * Can optionally generate mip-map levels automatically too. Target + * must be Texture2D, Texture2DArray or TextureRectangle. + * @param img - valid QImage. If Texture2D is set, should be power-of-2 + * dimensions. + */ + bool setFromQImage(QImage img, int layer = 0); + + void addImageData(TexImageDataPtr imgData); + QList<TexImageDataPtr> imageData() const; + + void setGenerateMipMaps(bool gen); + bool generateMipMaps() const + { return m_autoMipMap; } + +// sampler data - in the future proxy to a Sampler helper + void setMinificationFilter(QOpenGLTexture::Filter f); + void setMagnificationFilter(QOpenGLTexture::Filter f); + + QOpenGLTexture::Filter minificationFilter() const + { return m_minFilter; } + + QOpenGLTexture::Filter magnificationFilter() const + { return m_magFilter; } + + void setWrapMode(QOpenGLTexture::WrapMode wrapMode); + QOpenGLTexture::WrapMode wrapMode() const + { return m_wrapMode; } + + void setSize(int width, int height=1, int depth=1); + + int width() const; + int height() const; + int depth() const; + +private: + QOpenGLTexture::Target m_target; + QOpenGLTexture::TextureFormat m_format; + int m_width, m_height, m_depth; + bool m_autoMipMap; + + QList<TexImageDataPtr> m_data; + + QOpenGLTexture::Filter m_minFilter, m_magFilter; + // FIXME, store per direction + QOpenGLTexture::WrapMode m_wrapMode; +}; + +} // namespace Qt3D + +#endif // QT3D_TEXTUREDATA_H diff --git a/src/render/render.pri b/src/render/render.pri new file mode 100644 index 000000000..ea2b93bea --- /dev/null +++ b/src/render/render.pri @@ -0,0 +1,3 @@ +include(backend/render-backend.pri) +include(frontend/render-frontend.pri) +include(io/render-io.pri) diff --git a/src/src.pro b/src/src.pro index ae6a3ae90..f8b0ef3bc 100644 --- a/src/src.pro +++ b/src/src.pro @@ -1,4 +1,6 @@ TEMPLATE = subdirs CONFIG += ordered -SUBDIRS = threed -qtHaveModule(qml): SUBDIRS += quick3d imports +SUBDIRS += core + +#SUBDIRS += thred +#qtHaveModule(qml): SUBDIRS += quick3d imports diff --git a/sync.profile b/sync.profile index 4cc2ddca0..aec8fc637 100644 --- a/sync.profile +++ b/sync.profile @@ -1,4 +1,5 @@ %modules = ( # path to module name map + "Qt3DCore" => "$basedir/src/threed", "Qt3D" => "$basedir/src/threed", "Qt3DQuick" => "$basedir/src/quick3d", ); |