summaryrefslogtreecommitdiff
path: root/src/threed/scene/qglabstractscene.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/threed/scene/qglabstractscene.cpp')
-rw-r--r--src/threed/scene/qglabstractscene.cpp162
1 files changed, 158 insertions, 4 deletions
diff --git a/src/threed/scene/qglabstractscene.cpp b/src/threed/scene/qglabstractscene.cpp
index 9e0d141c8..2bb9885a9 100644
--- a/src/threed/scene/qglabstractscene.cpp
+++ b/src/threed/scene/qglabstractscene.cpp
@@ -168,12 +168,31 @@ class QGLAbstractScenePrivate
{
public:
QGLAbstractScenePrivate()
- : picking(false), nextPickId(-1), pickNodesDirty(true) {}
+ : picking(false), nextPickId(-1), pickNodesDirty(true), m_bFirstProcess(true) {}
bool picking;
int nextPickId;
QList<QGLPickNode*> pickNodes;
QSet<QGLSceneNode*> pickable;
bool pickNodesDirty;
+
+ bool m_bFirstProcess;
+ QList<QGLSceneAnimation *> m_animations;
+ std::vector<std::vector<QGLSceneNode*> > m_affectedNodes;
+ QMap<QGLSceneNode*,QGLSceneAnimation::NodeTransform> m_defaultTransformations;
+
+ struct NodeIndex
+ {
+ QGLSceneNode* m_pNode;
+ int m_Index;
+ bool operator < (const NodeIndex& other) const {
+ if (m_pNode != other.m_pNode)
+ return m_pNode < other.m_pNode;
+ else
+ return m_Index < other.m_Index;
+ }
+ };
+ QArray<NodeIndex> m_NodeIndices;
+ QArray<QGLSceneAnimation::NodeTransform> m_TransformsBuffer;
};
bool QGLAbstractScene::m_bFormatListReady = false;
@@ -353,12 +372,147 @@ QObject *QGLAbstractScene::object(const QString& name) const
/*!
Returns a list of animations.
-
- The default implementation returns empty list.
*/
QList<QGLSceneAnimation *> QGLAbstractScene::animations() const
{
- return QList<QGLSceneAnimation *>();
+ return getAnimations();
+}
+
+/*!
+ \internal
+*/
+QList<QGLSceneAnimation *>& QGLAbstractScene::getAnimations() const
+{
+ return d_ptr->m_animations;
+}
+
+/*!
+ \internal
+*/
+QMap<QGLSceneNode*,QGLSceneAnimation::NodeTransform>& QGLAbstractScene::getDefaultTransformations() const
+{
+ return d_ptr->m_defaultTransformations;
+}
+
+void CollectNodesRecursive(QGLSceneNode* pNode, QList<QGLSceneNode*>& rNodes) {
+ if (pNode) {
+ rNodes.append(pNode);
+ foreach (QGLSceneNode* pN, pNode->children()) {
+ CollectNodesRecursive(pN,rNodes);
+ }
+ }
+}
+
+/*!
+ \internal
+*/
+void QGLAbstractScene::processAnimations()
+{
+ if (d_ptr->m_bFirstProcess) {
+ d_ptr->m_bFirstProcess = false;
+
+ QList<QGLSceneNode*> Nodes;
+ CollectNodesRecursive(mainNode(), Nodes);
+
+ int maximumNodesCount = 0;
+ d_ptr->m_affectedNodes.resize(d_ptr->m_animations.count());
+ for (int i=0; i<d_ptr->m_animations.count(); ++i) {
+ QGLSceneAnimation* pAnimation = d_ptr->m_animations[i];
+ std::vector<QGLSceneNode*>& rNodesForThisAnimation = d_ptr->m_affectedNodes[i];
+
+ QList<QString> AffectedNodes = pAnimation->affectedNodes();
+ rNodesForThisAnimation.resize(AffectedNodes.count());
+ maximumNodesCount += AffectedNodes.count();
+
+ for (int an=0; an<AffectedNodes.count(); ++an) {
+ QGLSceneNode* pNode = 0;
+ for (int nn=0; nn<Nodes.count(); ++nn) {
+ if (AffectedNodes.at(an) == Nodes.at(nn)->objectName()) {
+ pNode = Nodes.at(nn);
+ break;
+ }
+ }
+ Q_ASSERT(pNode!=0);
+ rNodesForThisAnimation[an] = pNode;
+ }
+ }
+ maximumNodesCount += getDefaultTransformations().size();
+ d_ptr->m_NodeIndices.resize(maximumNodesCount);
+ d_ptr->m_TransformsBuffer.resize(maximumNodesCount);
+ }
+
+ int nReportedPositions = 0;
+ for ( QMap<QGLSceneNode*,QGLSceneAnimation::NodeTransform>::const_iterator It=d_ptr->m_defaultTransformations.begin(); It!=d_ptr->m_defaultTransformations.end(); ++It,++nReportedPositions) {
+ d_ptr->m_NodeIndices[nReportedPositions].m_pNode = It.key();
+ d_ptr->m_NodeIndices[nReportedPositions].m_Index = -1;
+ }
+ for (int i=0; i<d_ptr->m_animations.count(); ++i) {
+ QGLSceneAnimation* pAnimation = d_ptr->m_animations[i];
+
+ QList<QGLSceneAnimation::NodeTransform> transforms = pAnimation->transformations();
+ Q_ASSERT(transforms.size()==0 || transforms.size()==d_ptr->m_affectedNodes[i].size());
+ if (transforms.size()>0) {
+ for (int j=0; j<transforms.size(); ++j,++nReportedPositions) {
+ d_ptr->m_NodeIndices[nReportedPositions].m_pNode = d_ptr->m_affectedNodes[i][j];
+ d_ptr->m_NodeIndices[nReportedPositions].m_Index = nReportedPositions;
+ d_ptr->m_TransformsBuffer[nReportedPositions] = transforms.at(j);
+ }
+ }
+ }
+ if (nReportedPositions>0) {
+ QGLAbstractScenePrivate::NodeIndex* pBegin = &(d_ptr->m_NodeIndices[0]);
+ QGLAbstractScenePrivate::NodeIndex* pEnd = pBegin + nReportedPositions;
+ std::sort(pBegin,pEnd);
+ }
+
+ // iterate sorted array, blend transforms, get default transforms if needed, assign transforms to nodes
+ for (int index=0; index<nReportedPositions; ) {
+ Q_ASSERT(index==0 || d_ptr->m_NodeIndices[index].m_pNode!=d_ptr->m_NodeIndices[index-1].m_pNode);
+ Q_ASSERT(d_ptr->m_NodeIndices[index].m_Index == -1);
+ QGLSceneNode* pNode = d_ptr->m_NodeIndices[index].m_pNode;
+ int iEnd=index+1;
+ for (; iEnd<nReportedPositions && d_ptr->m_NodeIndices[iEnd].m_pNode==pNode; ++iEnd) {}
+ int nElementsForThisNode = iEnd-index;
+ QGLSceneAnimation::NodeTransform transform;
+ if (nElementsForThisNode==1) {
+ QMap<QGLSceneNode*,QGLSceneAnimation::NodeTransform>::const_iterator It=getDefaultTransformations().find(pNode);
+ Q_ASSERT(It!=getDefaultTransformations().end());
+ transform = It.value();
+ } else if (nElementsForThisNode==2) {
+ Q_ASSERT(d_ptr->m_NodeIndices[index ].m_Index == -1);
+ Q_ASSERT(d_ptr->m_NodeIndices[index+1].m_Index >= 0);
+ Q_ASSERT(d_ptr->m_NodeIndices[index+1].m_Index < nReportedPositions);
+ transform = d_ptr->m_TransformsBuffer[ d_ptr->m_NodeIndices[index+1].m_Index ];
+ } else if (nElementsForThisNode==3) {
+ Q_ASSERT(d_ptr->m_NodeIndices[index ].m_Index == -1);
+ Q_ASSERT(d_ptr->m_NodeIndices[index+1].m_Index >= 0);
+ Q_ASSERT(d_ptr->m_NodeIndices[index+1].m_Index < nReportedPositions);
+ Q_ASSERT(d_ptr->m_NodeIndices[index+2].m_Index >= 0);
+ Q_ASSERT(d_ptr->m_NodeIndices[index+2].m_Index < nReportedPositions);
+ const QGLSceneAnimation::NodeTransform& transform1 = d_ptr->m_TransformsBuffer[ d_ptr->m_NodeIndices[index+1].m_Index ];
+ const QGLSceneAnimation::NodeTransform& transform2 = d_ptr->m_TransformsBuffer[ d_ptr->m_NodeIndices[index+2].m_Index ];
+ transform.m_Scale = 0.5*(transform1.m_Scale + transform2.m_Scale);
+ transform.m_Translate = 0.5*(transform1.m_Translate + transform2.m_Translate);
+ transform.m_Rotate = QQuaternion::slerp(transform1.m_Rotate,transform2.m_Rotate,0.5).normalized();
+ } else {
+ //TODO: extend to this case
+ QMap<QGLSceneNode*,QGLSceneAnimation::NodeTransform>::const_iterator It=getDefaultTransformations().find(pNode);
+ Q_ASSERT(It!=getDefaultTransformations().end());
+ transform = It.value();
+ }
+ QMatrix4x4 nodeMatrix;
+ if (!transform.m_Translate.isNull())
+ nodeMatrix.translate(transform.m_Translate);
+ if (!transform.m_Scale.isNull())
+ nodeMatrix.scale(transform.m_Scale);
+ if (!transform.m_Rotate.isNull())
+ nodeMatrix.rotate(transform.m_Rotate);
+ pNode->setLocalTransform(nodeMatrix);
+
+ index = iEnd;
+ }
+
+ emit animationUpdated();
}
/*!