Przeglądaj źródła

Merge pull request #388 from blackberry-gaming/next-kcunney

Animation Optimization - Reduces the number of calls of transformChanged() during processing of animations.
Sean Paul Taylor 13 lat temu
rodzic
commit
64642927c8

+ 4 - 0
gameplay/src/AnimationController.cpp

@@ -96,6 +96,8 @@ void AnimationController::update(long elapsedTime)
     if (_state != RUNNING)
         return;
 
+    Transform::suspendTransformChanged();
+
     // Loop through running clips and call update() on them.
     std::list<AnimationClip*>::iterator clipIter = _runningClips.begin();
     while (clipIter != _runningClips.end())
@@ -120,6 +122,8 @@ void AnimationController::update(long elapsedTime)
         }
     }
 
+    Transform::resumeTransformChanged();
+
     if (_runningClips.empty())
         _state = IDLE;
 }

+ 0 - 1
gameplay/src/AnimationTarget.h

@@ -19,7 +19,6 @@ class AnimationTarget
 {
     friend class Animation;
     friend class AnimationClip;
-    friend class AnimationController;
 
 public:
 

+ 13 - 2
gameplay/src/Node.cpp

@@ -601,11 +601,22 @@ void Node::transformChanged()
     _dirtyBits |= NODE_DIRTY_WORLD | NODE_DIRTY_BOUNDS;
 
     // Notify our children that their transform has also changed (since transforms are inherited).
-    Joint* rootJoint = NULL;
     Node* n = getFirstChild();
     while (n)
     {
-        n->transformChanged();
+        if (Transform::isTransformChangedSuspended())
+        {
+            // If the DIRTY_NOTIFY bit is not set
+            if (!n->isDirty(Transform::DIRTY_NOTIFY))
+            {
+                n->transformChanged();
+                suspendTransformChange(n);
+            }
+        }
+        else
+        {
+            n->transformChanged();
+        }
         n = n->getNextSibling();
     }
 

+ 1 - 0
gameplay/src/Quaternion.h

@@ -41,6 +41,7 @@ class Matrix;
 class Quaternion
 {
     friend class Curve;
+    friend class Transform;
 
 public:
 

+ 68 - 5
gameplay/src/Transform.cpp

@@ -6,6 +6,9 @@
 namespace gameplay
 {
 
+int Transform::_suspendTransformChanged(0);
+std::vector<Transform*> Transform::_transformsChanged;
+
 Transform::Transform()
     : _matrixDirtyBits(0), _listeners(NULL)
 {
@@ -39,6 +42,45 @@ Transform::~Transform()
     SAFE_DELETE(_listeners);
 }
 
+void Transform::suspendTransformChanged()
+{
+    _suspendTransformChanged++;
+}
+
+void Transform::resumeTransformChanged()
+{
+    if (_suspendTransformChanged == 0) // We haven't suspended transformChanged() calls, so do nothing.
+        return;
+    
+    if (--_suspendTransformChanged == 0)
+    {
+        // Call transformChanged() on all transforms in the list
+        unsigned int transformCount = _transformsChanged.size();
+        for (unsigned int i = 0; i < transformCount; i++)
+        {
+            Transform* t = _transformsChanged.at(i);
+            t->transformChanged();
+        }
+
+        // Go through list and reset DIRTY_NOTIFY bit. The list could potentially be larger here if the 
+        // transforms we were delaying calls to transformChanged() have any child nodes.
+        transformCount = _transformsChanged.size();
+        for (unsigned int i = 0; i < transformCount; i++)
+        {
+            Transform* t = _transformsChanged.at(i);
+            t->_matrixDirtyBits &= ~DIRTY_NOTIFY;
+        }
+
+        // empty list for next frame.
+        _transformsChanged.clear();
+    }
+}
+
+bool Transform::isTransformChangedSuspended()
+{
+    return (_suspendTransformChanged > 0);
+}
+
 const Matrix& Transform::getMatrix() const
 {
     if (_matrixDirtyBits)
@@ -74,7 +116,7 @@ const Matrix& Transform::getMatrix() const
             Matrix::createScale(_scale, &_matrix);
         }
 
-        _matrixDirtyBits = 0;
+        _matrixDirtyBits &= ~DIRTY_TRANSLATION & ~DIRTY_ROTATION & ~DIRTY_SCALE;
     }
 
     return _matrix;
@@ -735,7 +777,28 @@ void Transform::setAnimationPropertyValue(int propertyId, AnimationValue* value,
 void Transform::dirty(char matrixDirtyBits)
 {
     _matrixDirtyBits |= matrixDirtyBits;
-    transformChanged();
+    if (isTransformChangedSuspended())
+    {
+        if (!isDirty(DIRTY_NOTIFY))
+        {
+            suspendTransformChange(this);
+        }
+    }
+    else
+    {
+        transformChanged();
+    }
+}
+
+bool Transform::isDirty(char matrixDirtyBits) const
+{
+    return (_matrixDirtyBits & matrixDirtyBits) == matrixDirtyBits;
+}
+
+void Transform::suspendTransformChange(Transform* transform)
+{
+    transform->_matrixDirtyBits |= DIRTY_NOTIFY;
+    _transformsChanged.push_back(transform);
 }
 
 void Transform::addListener(Transform::Listener* listener, long cookie)
@@ -786,9 +849,9 @@ void Transform::cloneInto(Transform* transform, NodeCloneContext &context) const
 
 void Transform::applyAnimationValueRotation(AnimationValue* value, unsigned int index, float blendWeight)
 {
-    Quaternion q(value->getFloat(index), value->getFloat(index + 1), value->getFloat(index + 2), value->getFloat(index + 3));
-    Quaternion::slerp(_rotation, q, blendWeight, &q);
-    setRotation(q);
+    Quaternion::slerp(_rotation.x, _rotation.y, _rotation.z, _rotation.w, value->getFloat(index), value->getFloat(index + 1), value->getFloat(index + 2), value->getFloat(index + 3), blendWeight, 
+        &_rotation.x, &_rotation.y, &_rotation.z, &_rotation.w);
+    dirty(DIRTY_ROTATION);
 }
 
 }

+ 37 - 0
gameplay/src/Transform.h

@@ -91,6 +91,23 @@ public:
      */
     static const int ANIMATE_SCALE_ROTATE_TRANSLATE = 17;
 
+    /**
+     * Globally suspends all transform changed events.
+     */
+    static void suspendTransformChanged();
+
+    /**
+     * Globally resumes all transform changed events.
+     */
+    static void resumeTransformChanged();
+
+    /** 
+     * Gets whether all transform changed events are suspended.
+     *
+     * @return TRUE if transform changed events are suspended; FALSE if transform changed events are not suspended.
+     */
+    static bool isTransformChangedSuspended();
+
     /**
      * Listener interface for Transform events.
      */
@@ -760,6 +777,7 @@ protected:
         DIRTY_TRANSLATION = 0x01,
         DIRTY_SCALE = 0x02,
         DIRTY_ROTATION = 0x04,
+        DIRTY_NOTIFY = 0x08
     };
 
     /**
@@ -767,6 +785,20 @@ protected:
      */
     void dirty(char matrixDirtyBits);
 
+    /** 
+     * Determines if the specified matrix dirty bit is set.
+     *
+     * @param matrixDirtyBits the matrix dirty bit to check for dirtiness.
+     * @return TRUE if the specified matrix dirty bit is set; FALSE if the specified matrix dirty bit is unset.
+     */
+    bool isDirty(char matrixDirtyBits) const;
+
+    /** 
+     * Adds the specified transform to the list of transforms waiting to be notified of a change.
+     * Sets the DIRTY_NOTIFY bit on the transform.
+     */
+    static void suspendTransformChange(Transform* transform);
+
     /**
      * Called when the transform changes.
      */
@@ -811,7 +843,12 @@ protected:
     std::list<TransformListener>* _listeners;
 
 private:
+   
     void applyAnimationValueRotation(AnimationValue* value, unsigned int index, float blendWeight);
+
+    static int _suspendTransformChanged;
+    static std::vector<Transform*> _transformsChanged;
+    
 };
 
 }