/**************************************************************************** ** ** Copyright (C) 2015 Klaralvdalens Datakonsult AB (KDAB). ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of Qt 3D Studio. ** ** $QT_BEGIN_LICENSE:GPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 or (at your option) any later version ** approved by the KDE Free Qt Foundation. The licenses are as published by ** the Free Software Foundation and appearing in the file LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QT3DRENDER_DRAGON_TREEJOBS_H #define QT3DRENDER_DRAGON_TREEJOBS_H // // W A R N I N G // ------------- // // This file is not part of the Qt API. It exists for the convenience // of other Qt classes. This header file may change from version to // version without notice, or even be removed. // // We mean it. // #include #include #include #include #include #include QT_BEGIN_NAMESPACE namespace Qt3DRender { namespace Dragon { // TODO consider storing handles/values instead of keys to reduce lookups struct InheritanceInfo { using Key = Qt3DCore::QNodeId; // TODO consider adding an ancestor list that includes ourselves (useful to build render views) QVector ancestors; QVector descendants; QVector children; void clear() { ancestors.clear(); descendants.clear(); children.clear(); } }; struct TreeInfo { using Key = Qt3DCore::QNodeId; ValueContainer nodes; QVector leafNodes; // ordered Key rootNode; }; class DirtyTreeInfo : public AbstractContainer::DirtyInfo { public: }; template TreeInfo generateInheritanceTable(TreeInfo inheritanceTable, T nodes, Qt3DCore::QNodeId rootEntityId) { inheritanceTable.nodes.reset(); if (!nodes.anythingDirty()) return inheritanceTable; if (nodes.created().isEmpty()) { const auto &dirtyInfos = nodes.dirtyInfo(); bool dirtyTreeStuff = false; for (const auto &id : dirtyInfos.keys()) { const Immutable &dirtyInfo = dirtyInfos[id]; if (dirtyInfo.can_convert()) { dirtyTreeStuff = true; } } if (!dirtyTreeStuff) return inheritanceTable; } // Clear old data inheritanceTable.leafNodes.clear(); inheritanceTable.nodes = synchronizeKeys(std::move(inheritanceTable.nodes), nodes); inheritanceTable.rootNode = rootEntityId; // Clear old data, set parent and find all children of all nodes for (const auto &id : nodes.keys()) { const auto &node = nodes[id]; auto tableNode = *(inheritanceTable.nodes[id]); inheritanceTable.nodes.markDirty(id); tableNode.children = node->treeChildren(); inheritanceTable.nodes[id] = tableNode; } { // Traverse the tree from top to bottom to add ancestor and descendant information // using a depth-first search. QStack stack; stack.push(rootEntityId); while (!stack.isEmpty()) { auto currentId = stack.pop(); QVector currentAncestors = inheritanceTable.nodes[currentId]->ancestors + QVector{{currentId}}; // NOTE: A copy is necessary, because we might insert into the map below const auto children = inheritanceTable.nodes[currentId]->children; if (children.isEmpty()) { inheritanceTable.leafNodes.push_back(currentId); continue; } // Iterate the children in reverse order (because the stack is last-in-first-out) // TODO use std::reverse_iterator once we have C++17 for (auto it = children.rbegin(); it != children.rend(); ++it) { const auto &childId = *it; auto child = *inheritanceTable.nodes[childId]; child.ancestors = currentAncestors; inheritanceTable.nodes[childId] = child; // Go through all ancestors and add us as a child for (const auto &ancestorId : qAsConst(currentAncestors)) { auto ancestor = *inheritanceTable.nodes[ancestorId]; ancestor.descendants.push_back(childId); inheritanceTable.nodes[ancestorId] = ancestor; } // Only add if not added as one of the dirty nodes stack.push(childId); } } // Reverse all the ancestor lists for (const auto &id : inheritanceTable.nodes.keys()) { auto node = *inheritanceTable.nodes[id]; std::reverse(node.ancestors.begin(), node.ancestors.end()); inheritanceTable.nodes[id] = node; } } return inheritanceTable; } } // namespace Dragon } // namespace Qt3DRender QT_END_NAMESPACE #endif // QT3DRENDER_DRAGON_TREEJOBS_H