| 1 | // Copyright (C) 2008-2012 NVIDIA Corporation. |
| 2 | // Copyright (C) 2019 The Qt Company Ltd. |
| 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only |
| 4 | |
| 5 | #ifndef QSSG_RENDER_NODE_H |
| 6 | #define QSSG_RENDER_NODE_H |
| 7 | |
| 8 | // |
| 9 | // W A R N I N G |
| 10 | // ------------- |
| 11 | // |
| 12 | // This file is not part of the Qt API. It exists purely as an |
| 13 | // implementation detail. This header file may change from version to |
| 14 | // version without notice, or even be removed. |
| 15 | // |
| 16 | // We mean it. |
| 17 | // |
| 18 | |
| 19 | #include <QtQuick3DRuntimeRender/private/qssgrendergraphobject_p.h> |
| 20 | |
| 21 | #include <QtQuick3DUtils/private/qssgbounds3_p.h> |
| 22 | #include <QtQuick3DUtils/private/qssginvasivelinkedlist_p.h> |
| 23 | |
| 24 | #include <QtGui/QMatrix4x4> |
| 25 | #include <QtGui/QVector3D> |
| 26 | |
| 27 | QT_BEGIN_NAMESPACE |
| 28 | |
| 29 | struct QSSGRenderModel; |
| 30 | struct QSSGRenderLight; |
| 31 | struct QSSGRenderCamera; |
| 32 | struct QSSGRenderText; |
| 33 | struct QSSGRenderNode; |
| 34 | class QSSGBufferManager; |
| 35 | |
| 36 | struct Q_QUICK3DRUNTIMERENDER_EXPORT QSSGRenderNode : public QSSGRenderGraphObject |
| 37 | { |
| 38 | enum class LocalState : quint8 |
| 39 | { |
| 40 | Active = 1 << 0, |
| 41 | Pickable = 1 << 1 |
| 42 | }; |
| 43 | |
| 44 | enum class GlobalState : quint8 |
| 45 | { |
| 46 | Active = 1 << 2, |
| 47 | Pickable = 1 << 3 |
| 48 | }; |
| 49 | |
| 50 | enum class DirtyFlag : quint32 |
| 51 | { |
| 52 | TransformDirty = 1 << 4, |
| 53 | OpacityDirty = 1 << 5, |
| 54 | ActiveDirty = 1 << 6, |
| 55 | PickableDirty = 1 << 7, |
| 56 | SubNodeDirty = 1 << 8, // Sub-nodes should set/unest this if they "extend" the dirty flags provided by the node |
| 57 | |
| 58 | GlobalValuesDirty = TransformDirty | OpacityDirty | ActiveDirty | PickableDirty, |
| 59 | DirtyMask = GlobalValuesDirty | SubNodeDirty |
| 60 | }; |
| 61 | using FlagT = std::underlying_type_t<DirtyFlag>; |
| 62 | |
| 63 | static constexpr QVector3D initScale { 1.0f, 1.0f, 1.0f }; |
| 64 | |
| 65 | // changing any one of these means you have to |
| 66 | // set this object dirty |
| 67 | QVector3D pivot; |
| 68 | int staticFlags = 0; |
| 69 | |
| 70 | // This only sets dirty, not transform dirty |
| 71 | // Opacity of 1 means opaque, opacity of zero means transparent. |
| 72 | float localOpacity = 1.0f; |
| 73 | |
| 74 | // Nodes are initially dirty and locally active! |
| 75 | FlagT flags { FlagT(DirtyFlag::GlobalValuesDirty) | FlagT(LocalState::Active) }; |
| 76 | // These end up right handed |
| 77 | QMatrix4x4 localTransform; |
| 78 | QMatrix4x4 globalTransform; |
| 79 | QMatrix4x4 localInstanceTransform; |
| 80 | QMatrix4x4 globalInstanceTransform; |
| 81 | float globalOpacity = 1.0f; |
| 82 | |
| 83 | // node graph members. |
| 84 | QSSGRenderNode *parent = nullptr; |
| 85 | QSSGRenderNode *nextSibling = nullptr; |
| 86 | QSSGRenderNode *previousSibling = nullptr; |
| 87 | QSSGRenderNode *instanceRoot = nullptr; |
| 88 | // Property maintained solely by the render system. |
| 89 | // Depth-first-search index assigned and maintained by render system. |
| 90 | quint32 dfsIndex = 0; |
| 91 | |
| 92 | using ChildList = QSSGInvasiveLinkedList<QSSGRenderNode, &QSSGRenderNode::previousSibling, &QSSGRenderNode::nextSibling>; |
| 93 | ChildList children; |
| 94 | |
| 95 | QString debugObjectName; |
| 96 | |
| 97 | QSSGRenderNode(); |
| 98 | QSSGRenderNode(Type type, FlagT flags = 0); |
| 99 | ~QSSGRenderNode() override; |
| 100 | |
| 101 | // Sets this object dirty and walks down the graph setting all |
| 102 | // children who are not dirty to be dirty. |
| 103 | void markDirty(DirtyFlag dirtyFlag); |
| 104 | void clearDirty(DirtyFlag dirtyFlag); |
| 105 | [[nodiscard]] inline constexpr bool isDirty(DirtyFlag dirtyFlag = DirtyFlag::DirtyMask) const { return ((flags & FlagT(dirtyFlag)) != 0); } |
| 106 | void setState(LocalState state, bool on = true); |
| 107 | [[nodiscard]] inline constexpr bool getLocalState(LocalState stateFlag) const { return ((flags & FlagT(stateFlag)) != 0); } |
| 108 | [[nodiscard]] inline constexpr bool getGlobalState(GlobalState stateFlag) const { return ((flags & FlagT(stateFlag)) != 0); } |
| 109 | |
| 110 | void addChild(QSSGRenderNode &inChild); |
| 111 | void removeChild(QSSGRenderNode &inChild); |
| 112 | |
| 113 | // Remove this node from the graph. |
| 114 | // It is no longer the the parent's child lists |
| 115 | // and all of its children no longer have a parent |
| 116 | // finally they are no longer siblings of each other. |
| 117 | void removeFromGraph(); |
| 118 | |
| 119 | // Calculate global transform and opacity |
| 120 | // Walks up the graph ensure all parents are not dirty so they have |
| 121 | // valid global transforms. |
| 122 | bool calculateGlobalVariables(); |
| 123 | |
| 124 | // Calculates a tranform matrix based on the position, scale, pivot and rotation arguments. |
| 125 | // NOTE!!!: This function does not update or mark any nodes as dirty, if the returned matrix is set on a node then |
| 126 | // markDirty, calculateGlobalVariables etc. needs to be called as needed! |
| 127 | [[nodiscard]] static QMatrix4x4 calculateTransformMatrix(QVector3D position, QVector3D scale, QVector3D pivot, QQuaternion rotation); |
| 128 | |
| 129 | // Get the bounds of us and our children in our local space. |
| 130 | QSSGBounds3 getBounds(QSSGBufferManager &inManager, |
| 131 | bool inIncludeChildren = true) const; |
| 132 | QSSGBounds3 getChildBounds(QSSGBufferManager &inManager) const; |
| 133 | // Assumes CalculateGlobalVariables has already been called. |
| 134 | QVector3D getGlobalPos() const { return QVector3D(globalTransform(0, 3), globalTransform(1, 3), globalTransform(2, 3)); } |
| 135 | QVector3D getGlobalPivot() const; |
| 136 | // Pulls the 3rd column out of the global transform. |
| 137 | QVector3D getDirection() const; |
| 138 | // Multiplies (0,0,-1) by the inverse transpose of the upper 3x3 of the global transform. |
| 139 | // This is correct w/r/t to scaling and which the above getDirection is not. |
| 140 | QVector3D getScalingCorrectDirection() const; |
| 141 | |
| 142 | // outMVP and outNormalMatrix are returned ready to upload to openGL, meaning they are |
| 143 | // row-major. |
| 144 | void calculateMVPAndNormalMatrix(const QMatrix4x4 &inViewProjection, QMatrix4x4 &outMVP, QMatrix3x3 &outNormalMatrix) const; |
| 145 | static void calculateMVPAndNormalMatrix(const QMatrix4x4 &globalTransfor, |
| 146 | const QMatrix4x4 &inViewProjection, |
| 147 | QMatrix4x4 &outMVP, |
| 148 | QMatrix3x3 &outNormalMatrix); |
| 149 | |
| 150 | // This should be in a utility file somewhere |
| 151 | QMatrix3x3 calculateNormalMatrix() const; |
| 152 | |
| 153 | // The Squared value of \a val |
| 154 | // This is mainly used for setting the sorting bias on models and particles |
| 155 | // since we're using the squared distance when sorting. |
| 156 | [[nodiscard]] static inline float signedSquared(float val) |
| 157 | { |
| 158 | const float sign = (val >= 0.0f) ? 1.0f : -1.0f; |
| 159 | return sign * val * val; |
| 160 | } |
| 161 | }; |
| 162 | |
| 163 | QT_END_NAMESPACE |
| 164 | |
| 165 | #endif |
| 166 | |