Browse Source

Merge branch 'next' of https://github.com/blackberry-gaming/GamePlay into next-dducharme

Dale Ducharme 14 years ago
parent
commit
0a47c154cd

+ 1 - 3
gameplay/.cproject

@@ -9,8 +9,6 @@
 				<extensions>
 					<extension id="com.qnx.tools.ide.qde.core.QDEBynaryParser" point="org.eclipse.cdt.core.BinaryParser"/>
 					<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
-					<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
-					<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
 				</extensions>
 			</storageModule>
 			<storageModule moduleId="cdtBuildSystem" version="4.0.0">
@@ -19,7 +17,7 @@
 						<toolChain id="com.qnx.qcc.toolChain.staticLib.debug.1686166742" name="QNX QCC" superClass="com.qnx.qcc.toolChain">
 							<option id="com.qnx.qcc.option.cpu.545743487" name="Target CPU:" superClass="com.qnx.qcc.option.cpu" value="com.qnx.qcc.option.gen.cpu.armle-v7" valueType="enumerated"/>
 							<targetPlatform archList="all" binaryParser="com.qnx.tools.ide.qde.core.QDEBynaryParser" id="com.qnx.qcc.targetPlatform.158841187" osList="all" superClass="com.qnx.qcc.targetPlatform"/>
-							<builder buildPath="${workspace_loc:/gameplay/Device-Debug}" id="cdt.managedbuild.target.gnu.builder.base.2098111998" keepEnvironmentInBuildfile="false" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.base"/>
+							<builder buildPath="${workspace_loc:/gameplay/Device-Debug}" id="org.eclipse.cdt.build.core.internal.builder.159190287" superClass="org.eclipse.cdt.build.core.internal.builder"/>
 							<tool id="com.qnx.qcc.tool.compiler.96907942" name="QCC Compiler" superClass="com.qnx.qcc.tool.compiler">
 								<option id="com.qnx.qcc.option.compile.debug.1765481355" name="Debug (-g)" superClass="com.qnx.qcc.option.compile.debug" value="true" valueType="boolean"/>
 								<option id="com.qnx.qcc.option.compiler.security.311918799" name="Enhanced Security (-fstack-protector-all)" superClass="com.qnx.qcc.option.compiler.security" value="true" valueType="boolean"/>

+ 0 - 12
gameplay/.project

@@ -17,10 +17,6 @@
 					<key>org.eclipse.cdt.make.core.append_environment</key>
 					<value>true</value>
 				</dictionary>
-				<dictionary>
-					<key>org.eclipse.cdt.make.core.autoBuildTarget</key>
-					<value>all</value>
-				</dictionary>
 				<dictionary>
 					<key>org.eclipse.cdt.make.core.buildArguments</key>
 					<value></value>
@@ -33,10 +29,6 @@
 					<key>org.eclipse.cdt.make.core.buildLocation</key>
 					<value>${workspace_loc:/gameplay/Device-Debug}</value>
 				</dictionary>
-				<dictionary>
-					<key>org.eclipse.cdt.make.core.cleanBuildTarget</key>
-					<value>clean</value>
-				</dictionary>
 				<dictionary>
 					<key>org.eclipse.cdt.make.core.contents</key>
 					<value>org.eclipse.cdt.make.core.activeConfigSettings</value>
@@ -53,10 +45,6 @@
 					<key>org.eclipse.cdt.make.core.enableFullBuild</key>
 					<value>true</value>
 				</dictionary>
-				<dictionary>
-					<key>org.eclipse.cdt.make.core.fullBuildTarget</key>
-					<value>all</value>
-				</dictionary>
 				<dictionary>
 					<key>org.eclipse.cdt.make.core.stopOnError</key>
 					<value>true</value>

+ 4 - 2
gameplay/src/Animation.cpp

@@ -31,7 +31,8 @@ Animation::~Animation()
 {
     if (_defaultClip)
     {
-        _defaultClip->stop();
+        if (_defaultClip->isClipStateBitSet(AnimationClip::CLIP_IS_PLAYING_BIT))
+            _controller->unschedule(_defaultClip);
         SAFE_RELEASE(_defaultClip);
     }
 
@@ -42,7 +43,8 @@ Animation::~Animation()
         while (clipIter != _clips->end())
         {   
             AnimationClip* clip = *clipIter;
-            clip->stop();
+            if (clip->isClipStateBitSet(AnimationClip::CLIP_IS_PLAYING_BIT))
+                _controller->unschedule(clip);
             SAFE_RELEASE(clip);
             clipIter++;
         }

+ 167 - 83
gameplay/src/AnimationClip.cpp

@@ -9,10 +9,10 @@ namespace gameplay
 {
 
 AnimationClip::AnimationClip(const char* id, Animation* animation, unsigned long startTime, unsigned long endTime)
-    : _id(id), _animation(animation), _startTime(startTime), _endTime(endTime), _duration(_endTime - _startTime), _repeatCount(1.0f), 
-      _activeDuration(_duration * _repeatCount), _speed(1.0f), _isPlaying(false), _timeStarted(0), _elapsedTime(0), 
-      _crossFadeToClip(NULL), _crossFadeOutElapsed(0), _crossFadeOutDuration(0), _blendWeight(1.0f), _isFadingOutStarted(false), 
-      _isFadingOut(false), _isFadingIn(false), _beginListeners(NULL), _endListeners(NULL), _listeners(NULL), _listenerItr(NULL)
+    : _id(id), _animation(animation), _startTime(startTime), _endTime(endTime), _duration(_endTime - _startTime), 
+      _stateBits(0x00), _repeatCount(1.0f), _activeDuration(_duration * _repeatCount), _speed(1.0f), _timeStarted(0), 
+      _elapsedTime(0), _crossFadeToClip(NULL), _crossFadeOutElapsed(0), _crossFadeOutDuration(0), _blendWeight(1.0f), 
+      _beginListeners(NULL), _endListeners(NULL), _listeners(NULL), _listenerItr(NULL)
 {
     assert(0 <= startTime && startTime <= animation->_duration && 0 <= endTime && endTime <= animation->_duration);
     
@@ -36,10 +36,31 @@ AnimationClip::~AnimationClip()
     SAFE_RELEASE(_crossFadeToClip);
     SAFE_DELETE(_beginListeners);
     SAFE_DELETE(_endListeners);
-    SAFE_DELETE(_listeners);
+
+    if (_listeners)
+    {
+        *_listenerItr = _listeners->begin();
+        while (*_listenerItr != _listeners->end())
+        {
+            ListenerEvent* lEvt = **_listenerItr;
+            SAFE_DELETE(lEvt);
+            ++*_listenerItr;
+        }
+        SAFE_DELETE(_listeners);
+    }
     SAFE_DELETE(_listenerItr);
 }
 
+AnimationClip::ListenerEvent::ListenerEvent(Listener* listener, unsigned long eventTime)
+{
+    _listener = listener;
+    _eventTime = eventTime;
+}
+
+AnimationClip::ListenerEvent::~ListenerEvent()
+{
+}
+
 const char* AnimationClip::getID() const
 {
     return _id.c_str();
@@ -108,6 +129,11 @@ unsigned long AnimationClip::getActiveDuration() const
     return _activeDuration;
 }
 
+unsigned long AnimationClip::getDuration() const
+{
+    return _duration;
+}
+
 void AnimationClip::setSpeed(float speed)
 {
     _speed = speed;
@@ -130,22 +156,39 @@ float AnimationClip::getBlendWeight() const
 
 bool AnimationClip::isPlaying() const
 {
-    return _isPlaying;
+    return isClipStateBitSet(CLIP_IS_PLAYING_BIT);
 }
 
 void AnimationClip::play()
 {
-    _animation->_controller->schedule(this);
+    if (isClipStateBitSet(CLIP_IS_PLAYING_BIT))
+    {
+        // If the clip is set to be removed, reset the flag.
+        if (isClipStateBitSet(CLIP_IS_MARKED_FOR_REMOVAL_BIT))
+            resetClipStateBit(CLIP_IS_MARKED_FOR_REMOVAL_BIT);
+
+        // Set the state bit to restart.
+        setClipStateBit(CLIP_IS_RESTARTED_BIT);
+    }
+    else
+    {
+        setClipStateBit(CLIP_IS_PLAYING_BIT);
+        _animation->_controller->schedule(this);
+    }
+    
     _timeStarted = Game::getGameTime();
 }
 
 void AnimationClip::stop()
 {
-    _animation->_controller->unschedule(this);
-    if (_isPlaying)
+    if (isClipStateBitSet(CLIP_IS_PLAYING_BIT))
     {
-        _isPlaying = false;
-        onEnd();
+        // If the clip was slated to be restarted, reset this flag.
+        if (isClipStateBitSet(CLIP_IS_RESTARTED_BIT))
+            resetClipStateBit(CLIP_IS_RESTARTED_BIT);
+
+        // Mark the clip to removed from the AnimationController.
+        setClipStateBit(CLIP_IS_MARKED_FOR_REMOVAL_BIT);
     }
 }
 
@@ -153,27 +196,37 @@ void AnimationClip::crossFade(AnimationClip* clip, unsigned long duration)
 {
     assert(clip);
 
+    // Check if the given clip is fading into this clip.
+    // We should reset the clip from fading out, and this one from fading in 
+    // in order to start the crossfade back the other way.
+    if (clip->isClipStateBitSet(CLIP_IS_FADING_OUT_BIT) && clip->_crossFadeToClip == this)
+    {
+        clip->resetClipStateBit(CLIP_IS_FADING_OUT_BIT);
+        clip->_crossFadeToClip->resetClipStateBit(CLIP_IS_FADING_IN_BIT);
+        SAFE_RELEASE(clip->_crossFadeToClip);
+    }
+
     // If I already have a clip I'm fading to and it's not the same as the given clip release it.
     // Assign the new clip and increase it's ref count.
-    // TODO: Do I need to anything else to the crossFade clip here before releasing?
     if (_crossFadeToClip)
+    {
         SAFE_RELEASE(_crossFadeToClip);
-        
+    }
+
+    // Set and initialize the crossfade clip
     _crossFadeToClip = clip;
     _crossFadeToClip->addRef();
-        
-    // Set the crossfade clip to fading in, and initialize it's blend weight to zero.
-    _crossFadeToClip->_isFadingIn = true;
+    _crossFadeToClip->setClipStateBit(CLIP_IS_FADING_IN_BIT);
     _crossFadeToClip->_blendWeight = 0.0f;
     
-    // Set this clip to fade out, set the fade duration and reset the fade elapsed time.
-    _isFadingOut = true;
-    _crossFadeOutElapsed = 0;
+    // Set and intiliaze this clip to fade out
+    setClipStateBit(CLIP_IS_FADING_OUT_STARTED_BIT);
+    setClipStateBit(CLIP_IS_FADING_OUT_BIT);
+    _crossFadeOutElapsed = 0L;
     _crossFadeOutDuration = duration;
-    _isFadingOutStarted = true;
     
     // If this clip is currently not playing, we should start playing it.
-    if (!_isPlaying)
+    if (!isClipStateBitSet(CLIP_IS_PLAYING_BIT))
         play();
 
     // Start playing the cross fade clip.
@@ -183,39 +236,40 @@ void AnimationClip::crossFade(AnimationClip* clip, unsigned long duration)
 void AnimationClip::addListener(AnimationClip::Listener* listener, unsigned long eventTime)
 {
     assert(listener);
-    assert(eventTime < _duration);
+    assert(eventTime < _activeDuration);
 
-    listener->_listenerTime = eventTime;
+    ListenerEvent* listenerEvent = new ListenerEvent(listener, eventTime);
 
     if (!_listeners)
     {
-        _listeners = new std::list<Listener*>;
-        _listeners->push_front(listener);
+        _listeners = new std::list<ListenerEvent*>;
+        _listeners->push_front(listenerEvent);
 
-        _listenerItr = new std::list<Listener*>::iterator;
-        if (_isPlaying)
+        _listenerItr = new std::list<ListenerEvent*>::iterator;
+        if (isClipStateBitSet(CLIP_IS_PLAYING_BIT))
             *_listenerItr = _listeners->begin();
     }
     else
     {
-        for (std::list<Listener*>::iterator itr = _listeners->begin(); itr != _listeners->begin(); itr++)
+        for (std::list<ListenerEvent*>::iterator itr = _listeners->begin(); itr != _listeners->end(); itr++)
         {
-            if (eventTime < (*itr)->_listenerTime)
+            if (eventTime < (*itr)->_eventTime)
             {
-                itr = _listeners->insert(itr, listener);
+                itr = _listeners->insert(itr, listenerEvent);
 
                 // If playing, update the iterator if we need to.
                 // otherwise, it will just be set the next time the clip gets played.
-                if (_isPlaying)
+                if (isClipStateBitSet(CLIP_IS_PLAYING_BIT))
                 {
                     unsigned long currentTime = _elapsedTime % _duration;
-                    if ((_speed >= 0.0f && currentTime < eventTime && (*_listenerItr == _listeners->end() || eventTime < (**_listenerItr)->_listenerTime)) || 
-                        (_speed <= 0 && currentTime > eventTime && (*_listenerItr == _listeners->begin() || eventTime > (**_listenerItr)->_listenerTime)))
+                    if ((_speed >= 0.0f && currentTime < eventTime && (*_listenerItr == _listeners->end() || eventTime < (**_listenerItr)->_eventTime)) || 
+                        (_speed <= 0 && currentTime > eventTime && (*_listenerItr == _listeners->begin() || eventTime > (**_listenerItr)->_eventTime)))
                         *_listenerItr = itr;
                 }
                 return;
             }
         }
+        _listeners->push_back(listenerEvent);
     }
 }
 
@@ -237,21 +291,43 @@ void AnimationClip::addEndListener(AnimationClip::Listener* listener)
 
 bool AnimationClip::update(unsigned long elapsedTime, std::list<AnimationTarget*>* activeTargets)
 {
-    if (!_isPlaying)
+    if (isClipStateBitSet(CLIP_IS_MARKED_FOR_REMOVAL_BIT))
+    {   // If the marked for removal bit is set, it means stop() was called on the AnimationClip at some point
+        // after the last update call. Reset the flag, and return true so the AnimationClip is removed from the 
+        // running clips on the AnimationController.
+        onEnd();
+        return true;
+    }
+    else if (!isClipStateBitSet(CLIP_IS_STARTED_BIT))
+    {
         onBegin();
-    else 
+    }
+    else
+    {
         _elapsedTime += elapsedTime * _speed;
 
+        if (_repeatCount == REPEAT_INDEFINITE && _elapsedTime <= 0)
+            _elapsedTime = _activeDuration + _elapsedTime;
+    }
+
     unsigned long currentTime = 0L;
     // Check to see if clip is complete.
     if (_repeatCount != REPEAT_INDEFINITE && ((_speed >= 0.0f && _elapsedTime >= (long) _activeDuration) || (_speed <= 0.0f && _elapsedTime <= 0L)))
     {
-        _isPlaying = false;
+        resetClipStateBit(CLIP_IS_STARTED_BIT);
         if (_speed >= 0.0f)
         {
-            currentTime = _activeDuration % _duration; // Get's the fractional part of the final repeat.
-            if (currentTime == 0L)
-                currentTime = _duration;
+            // If _duration == 0, we have a "pose". Just set currentTime to 0.
+            if (_duration == 0)
+            {
+                currentTime = 0L;
+            }
+            else
+            {
+                currentTime = _activeDuration % _duration; // Get's the fractional part of the final repeat.
+                if (currentTime == 0L)
+                    currentTime = _duration;
+            }
         }
         else
         {
@@ -260,8 +336,11 @@ bool AnimationClip::update(unsigned long elapsedTime, std::list<AnimationTarget*
     }
     else
     {
-        // Gets portion/fraction of the repeat.
-        currentTime = _elapsedTime % _duration;
+        // If _duration == 0, we have a "pose". Just set currentTime to 0.
+        if (_duration == 0)
+            currentTime = 0L;
+        else // Gets portion/fraction of the repeat.
+            currentTime = _elapsedTime % _duration;
     }
 
     // Notify any listeners of Animation events.
@@ -269,17 +348,17 @@ bool AnimationClip::update(unsigned long elapsedTime, std::list<AnimationTarget*
     {
         if (_speed >= 0.0f)
         {
-            while (*_listenerItr != _listeners->end() && currentTime >= (**_listenerItr)->_listenerTime)
+            while (*_listenerItr != _listeners->end() && _elapsedTime >= (long) (**_listenerItr)->_eventTime)
             {
-                (**_listenerItr)->animationEvent(this, Listener::DEFAULT);
+                (**_listenerItr)->_listener->animationEvent(this, Listener::DEFAULT);
                 ++*_listenerItr;
             }
         }
         else
         {
-            while (*_listenerItr != _listeners->begin() && currentTime <= (**_listenerItr)->_listenerTime)
+            while (*_listenerItr != _listeners->begin() && _elapsedTime <= (long) (**_listenerItr)->_eventTime)
             {
-                (**_listenerItr)->animationEvent(this, Listener::DEFAULT);
+                (**_listenerItr)->_listener->animationEvent(this, Listener::DEFAULT);
                 --*_listenerItr;
             }
         }
@@ -288,12 +367,12 @@ bool AnimationClip::update(unsigned long elapsedTime, std::list<AnimationTarget*
     // Add back in start time, and divide by the total animation's duration to get the actual percentage complete
     float percentComplete = (float)(_startTime + currentTime) / (float) _animation->_duration;
     
-    if (_isFadingOut)
+    if (isClipStateBitSet(CLIP_IS_FADING_OUT_BIT))
     {
-        if (_isFadingOutStarted) // Calculate elapsed time since the fade out begin.
+        if (isClipStateBitSet(CLIP_IS_FADING_OUT_STARTED_BIT)) // Calculate elapsed time since the fade out begin.
         {
-            _crossFadeOutElapsed = (Game::getGameTime() - _crossFadeToClip->_timeStarted) * _speed; 
-            _isFadingOutStarted = false;
+            _crossFadeOutElapsed = (Game::getGameTime() - _crossFadeToClip->_timeStarted) * abs(_speed); 
+            resetClipStateBit(CLIP_IS_FADING_OUT_STARTED_BIT);
         }
         else
         {
@@ -307,7 +386,7 @@ bool AnimationClip::update(unsigned long elapsedTime, std::list<AnimationTarget*
             float tempBlendWeight = (float) (_crossFadeOutDuration - _crossFadeOutElapsed) / (float) _crossFadeOutDuration;
             
             // If this clip is fading in, adjust the crossfade clip's weight to be a percentage of your current blend weight
-            if (_isFadingIn)
+            if (isClipStateBitSet(CLIP_IS_FADING_IN_BIT))
             {
                 _crossFadeToClip->_blendWeight = (1.0f - tempBlendWeight) * _blendWeight;
                 _blendWeight -= _crossFadeToClip->_blendWeight;
@@ -321,21 +400,12 @@ bool AnimationClip::update(unsigned long elapsedTime, std::list<AnimationTarget*
         }
         else
         {   // Fade is done.
-            // Set the crossFadeToClip's blend weight to 1
             _crossFadeToClip->_blendWeight = 1.0f;
-            
-            // Adjust the crossfade clip's blend weight if this clip is also fading in.
-            if (_isFadingIn)
-                _crossFadeToClip->_blendWeight *= _blendWeight;
-
-            // The crossfade clip is no longer fading in
-            _crossFadeToClip->_isFadingIn = false;
-
-            // Release the crossfade clip, mark ourselves as done and set our blend weight to 0.
+            _blendWeight = 0.0f;
+            resetClipStateBit(CLIP_IS_STARTED_BIT);            
+            resetClipStateBit(CLIP_IS_FADING_OUT_BIT);
+            _crossFadeToClip->resetClipStateBit(CLIP_IS_FADING_IN_BIT);
             SAFE_RELEASE(_crossFadeToClip);
-            _blendWeight = 0.0f; 
-            _isFadingOut = false;
-            _isPlaying = false;
         }
     }
     
@@ -363,46 +433,34 @@ bool AnimationClip::update(unsigned long elapsedTime, std::list<AnimationTarget*
     }
 
     // When ended. Probably should move to it's own method so we can call it when the clip is ended early.
-    if (!_isPlaying)
+    if (isClipStateBitSet(CLIP_IS_MARKED_FOR_REMOVAL_BIT) || !isClipStateBitSet(CLIP_IS_STARTED_BIT))
     {
         onEnd();
-        // Notify end listeners if any.
-        if (_endListeners)
-        {
-            std::vector<Listener*>::iterator listener = _endListeners->begin();
-            while (listener != _endListeners->end())
-            {
-                (*listener)->animationEvent(this, Listener::END);
-                listener++;
-            }
-        }
+        return true;
     }
 
-    return !_isPlaying;
+    return false;
 }
 
 void AnimationClip::onBegin()
 {
     // Initialize animation to play.
-    _isPlaying = true;
-
+    setClipStateBit(CLIP_IS_STARTED_BIT);
     if (_speed >= 0)
     {
-        _elapsedTime = 0;
+        _elapsedTime = (Game::getGameTime() - _timeStarted) * _speed;
 
         if (_listeners)
             *_listenerItr = _listeners->begin(); 
     }
     else
     {
-        _elapsedTime = _activeDuration;
+        _elapsedTime = _activeDuration + (Game::getGameTime() - _timeStarted) * _speed;
 
         if (_listeners)
             *_listenerItr = _listeners->end();
     }
-
-    _elapsedTime += (Game::getGameTime() - _timeStarted) * _speed;
-
+    
     // Notify begin listeners.. if any.
     if (_beginListeners)
     {
@@ -418,7 +476,33 @@ void AnimationClip::onBegin()
 void AnimationClip::onEnd()
 {
     _blendWeight = 1.0f;
-    _timeStarted = 0;
+    resetClipStateBit(CLIP_ALL_BITS);
+
+    // Notify end listeners if any.
+    if (_endListeners)
+    {
+        std::vector<Listener*>::iterator listener = _endListeners->begin();
+        while (listener != _endListeners->end())
+        {
+            (*listener)->animationEvent(this, Listener::END);
+            listener++;
+        }
+    }
+}
+
+bool AnimationClip::isClipStateBitSet(char bit) const
+{
+    return (_stateBits & bit) == bit;
+}
+
+void AnimationClip::setClipStateBit(char bit)
+{
+    _stateBits |= bit;
+}
+
+void AnimationClip::resetClipStateBit(char bit)
+{
+    _stateBits &= ~bit;
 }
 
 }

+ 74 - 28
gameplay/src/AnimationClip.h

@@ -37,7 +37,6 @@ public:
     public:
 
         Listener() 
-            : _listenerTime(0L)
         {
         }
 
@@ -66,9 +65,6 @@ public:
          * Handles when animation event occurs.
          */
         virtual void animationEvent(AnimationClip* clip, EventType type) = 0;
-
-    private:
-        unsigned long _listenerTime;
     };
 
     /**
@@ -138,6 +134,13 @@ public:
      */
     unsigned long getActiveDuration() const;
 
+    /**
+     * Gets the AnimationClip's duration.
+     *
+     * @return the AnimationClip's duration.
+     */
+    unsigned long getDuration() const;
+
     /**
      * Set the AnimationClip's running speed. 
      *
@@ -217,6 +220,38 @@ public:
     void addListener(AnimationClip::Listener* listener, unsigned long eventTime);
 
 private:
+    /**
+     * State bits.
+     */
+    static const char CLIP_IS_PLAYING_BIT = 0x01;             // Bit representing whether AnimationClip is a running clip in AnimationController
+    static const char CLIP_IS_STARTED_BIT = 0x02;             // Bit representing whether the AnimationClip has actually been started (ie: received first call to update())
+    static const char CLIP_IS_FADING_OUT_STARTED_BIT = 0x04;  // Bit representing that a cross fade has started.
+    static const char CLIP_IS_FADING_OUT_BIT = 0x08;          // Bit representing whether the clip is fading out.
+    static const char CLIP_IS_FADING_IN_BIT = 0x10;           // Bit representing whether the clip is fading out.
+    static const char CLIP_IS_MARKED_FOR_REMOVAL_BIT = 0x20;  // Bit representing whether the clip has ended and should be removed from the AnimationController.
+    static const char CLIP_IS_RESTARTED_BIT = 0x40;           // Bit representing if the clip should be restarted by the AnimationController.
+    static const char CLIP_ALL_BITS = 0x4F;                   // Bit mask for all the state bits.
+
+    /**
+     * ListenerEvent.
+     *
+     * Internal structure used for storing the event time at which an AnimationClip::Listener should be called back.
+     */
+    struct ListenerEvent
+    {
+        /** 
+         * Constructor.
+         */
+        ListenerEvent(Listener* listener, unsigned long eventTime);
+
+        /**
+         * Destructor.
+         */
+        ~ListenerEvent();
+
+        Listener* _listener;        // This listener to call back when this event is triggered.
+        unsigned long _eventTime;   // The time at which the listener will be called back at during the playback of the AnimationClip.
+    };
 
     /**
      * Constructor.
@@ -253,31 +288,42 @@ private:
      */
     void onEnd();
 
-    std::string _id;                                // AnimationClip ID.
-    Animation* _animation;                          // The Animation this clip is created from.
-    unsigned long _startTime;                       // Start time of the clip.
-    unsigned long _endTime;                         // End time of the clip.
-    unsigned long _duration;                        // The total duration.
-    float _repeatCount;                             // The clip's repeat count.
-    unsigned long _activeDuration;                  // The active duration of the clip.
-    float _speed;                                   // The speed that the clip is playing. Default is 1.0. Negative goes in reverse.
-    bool _isPlaying;                                // A flag to indicate whether the clip is playing.
-    unsigned long _timeStarted;                     // The game time when this clip was actually started.
-    long _elapsedTime;                              // Time elapsed while the clip is running.
-    AnimationClip* _crossFadeToClip;                // The clip to cross fade to.
-    unsigned long _crossFadeOutElapsed;             // The amount of time that has elapsed for the crossfade.
-    unsigned long _crossFadeOutDuration;            // The duration of the cross fade.
-    float _blendWeight;                             // The clip's blendweight.
-    bool _isFadingOutStarted;                       // Flag to indicate if the cross fade started.
-    bool _isFadingOut;                              // Flag to indicate if the clip is fading out.
-    bool _isFadingIn;                               // Flag to indicate if the clip is fading in.
-    std::vector<AnimationValue*> _values;           // AnimationValue holder.
-    std::vector<Listener*>* _beginListeners;        // Collection of begin listeners on the clip.
-    std::vector<Listener*>* _endListeners;          // Collection of end listeners on the clip.
-    std::list<Listener*>* _listeners;               // Ordered collection of listeners on the clip.
-    std::list<Listener*>::iterator* _listenerItr;   // Iterator that points to the next listener event to be triggered.
+    /**
+     * Determines whether the given bit is set in the AnimationClip's state.
+     */
+    bool isClipStateBitSet(char bit) const;
+
+    /**
+     * Sets the given bit in the AnimationClip's state.
+     */
+    void setClipStateBit(char bit);
+
+    /**
+     * Resets the given bit in the AnimationClip's state.
+     */
+    void resetClipStateBit(char bit);
+
+    std::string _id;                                    // AnimationClip ID.
+    Animation* _animation;                              // The Animation this clip is created from.
+    unsigned long _startTime;                           // Start time of the clip.
+    unsigned long _endTime;                             // End time of the clip.
+    unsigned long _duration;                            // The total duration.
+    char _stateBits;                                    // Bit flag used to keep track of the clip's current state.
+    float _repeatCount;                                 // The clip's repeat count.
+    unsigned long _activeDuration;                      // The active duration of the clip.
+    float _speed;                                       // The speed that the clip is playing. Default is 1.0. Negative goes in reverse.
+    unsigned long _timeStarted;                         // The game time when this clip was actually started.
+    long _elapsedTime;                                  // Time elapsed while the clip is running.
+    AnimationClip* _crossFadeToClip;                    // The clip to cross fade to.
+    unsigned long _crossFadeOutElapsed;                 // The amount of time that has elapsed for the crossfade.
+    unsigned long _crossFadeOutDuration;                // The duration of the cross fade.
+    float _blendWeight;                                 // The clip's blendweight.
+    std::vector<AnimationValue*> _values;               // AnimationValue holder.
+    std::vector<Listener*>* _beginListeners;            // Collection of begin listeners on the clip.
+    std::vector<Listener*>* _endListeners;              // Collection of end listeners on the clip.
+    std::list<ListenerEvent*>* _listeners;              // Ordered collection of listeners on the clip.
+    std::list<ListenerEvent*>::iterator* _listenerItr;  // Iterator that points to the next listener event to be triggered.
 };
 
 }
-
 #endif

+ 11 - 15
gameplay/src/AnimationController.cpp

@@ -111,10 +111,8 @@ void AnimationController::stopAllAnimations()
     while (clipIter != _runningClips.end())
     {
         AnimationClip* clip = *clipIter;
-        clip->_isPlaying = false;
-        clip->onEnd();
-        SAFE_RELEASE(clip);
         clipIter++;
+        clip->stop();
     }
     _runningClips.clear();
 
@@ -294,18 +292,8 @@ void AnimationController::schedule(AnimationClip* clip)
     {
         _state = RUNNING;
     }
-    
-    if (clip->_isPlaying)
-    {
-        _runningClips.remove(clip);
-        clip->_isPlaying = false;
-        clip->onEnd();
-    }
-    else
-    {
-        clip->addRef();
-    }
 
+    clip->addRef();
     _runningClips.push_back(clip);
 }
 
@@ -338,7 +326,15 @@ void AnimationController::update(long elapsedTime)
     while (clipIter != _runningClips.end())
     {
         AnimationClip* clip = (*clipIter);
-        if (clip->update(elapsedTime, &_activeTargets))
+        if (clip->isClipStateBitSet(AnimationClip::CLIP_IS_RESTARTED_BIT))
+        {   // If the CLIP_IS_RESTARTED_BIT is set, we should end the clip and 
+            // move it from where it is in the running clips list to the back.
+            clip->onEnd();
+            clip->setClipStateBit(AnimationClip::CLIP_IS_PLAYING_BIT);
+            _runningClips.push_back(clip);
+            clipIter = _runningClips.erase(clipIter);
+        }
+        else if (clip->update(elapsedTime, &_activeTargets))
         {
             SAFE_RELEASE(clip);
             clipIter = _runningClips.erase(clipIter);

+ 0 - 8
gameplay/src/Base.h

@@ -191,13 +191,9 @@ extern void printError(const char* format, ...);
     extern PFNGLISVERTEXARRAYOESPROC glIsVertexArray;
     #define glClearDepth glClearDepthf
     #define OPENGL_ES
-    #define WINDOW_WIDTH    1024
-    #define WINDOW_HEIGHT   600
 #elif WIN32
     #define WIN32_LEAN_AND_MEAN
     #include <GL/glew.h>
-    #define WINDOW_WIDTH    1024
-    #define WINDOW_HEIGHT   600
 #elif __APPLE__
     #include "TargetConditionals.h"
     #if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
@@ -209,8 +205,6 @@ extern void printError(const char* format, ...);
         #define glIsVertexArray glIsVertexArrayOES
         #define glClearDepth glClearDepthf
         #define OPENGL_ES
-        #define WINDOW_WIDTH    480
-        #define WINDOW_HEIGHT   360
     #elif TARGET_OS_MAC
         #include <OpenGL/gl.h>
         #include <OpenGL/glext.h>
@@ -218,8 +212,6 @@ extern void printError(const char* format, ...);
         #define glDeleteVertexArrays glDeleteVertexArraysAPPLE
         #define glGenVertexArrays glGenVertexArraysAPPLE
         #define glIsVertexArray glIsVertexArrayAPPLE
-        #define WINDOW_WIDTH    960
-        #define WINDOW_HEIGHT   640
     #else
         #error "Unsupported Apple Device"
     #endif

+ 9 - 2
gameplay/src/Game.cpp

@@ -68,8 +68,15 @@ int Game::run(int width, int height)
     if (_state != UNINITIALIZED)
         return -1;
 
-    _width = width;
-    _height = height;
+    if (width == -1)
+        _width = Platform::getDisplayWidth();
+    else
+        _width = width;
+    
+    if (height == -1)
+        _height = Platform::getDisplayHeight();
+    else
+        _height = height;
 
     // Start up game systems.
     if (!startup())

+ 2 - 2
gameplay/src/Game.h

@@ -96,8 +96,8 @@ public:
     /**
      * Call this method to initialize the game, and begin running the game.
      *
-     * @param width The width of the game window to run at.
-     * @param height The height of the game window to run at.
+     * @param width The width of the game window to run at. Default is -1 meaning native resolution width.
+     * @param height The height of the game window to run at. Default is -1 meaning native resolution height.
      * 
      * @return Zero for normal termination, or non-zero if an error occurred.
      */

+ 14 - 0
gameplay/src/Platform.h

@@ -36,6 +36,20 @@ public:
      * @return The platform message pump return code.
      */
     int enterMessagePump();
+    
+    /**
+     * Gets the display width.
+     * 
+     * @return The display width.
+     */
+    static unsigned int getDisplayWidth();
+    
+    /**
+     * Gets the display height.
+     * 
+     * @return The display height.
+     */
+    static unsigned int getDisplayHeight();
 
     /**
      * Gets the absolute platform time starting from when the message pump was started.

+ 11 - 1
gameplay/src/PlatformAndroid.cpp

@@ -766,7 +766,17 @@ int Platform::enterMessagePump()
         gameplay::displayKeyboard(__state, __displayKeyboard);
     }
 }
-
+   
+unsigned int Platform::getDisplayWidth()
+{
+    return __width;
+}
+    
+unsigned int Platform::getDisplayHeight()
+{
+    return __height;
+}
+    
 long Platform::getAbsoluteTime()
 {
     clock_gettime(CLOCK_REALTIME, &__timespec);

+ 91 - 9
gameplay/src/PlatformMacOS.mm

@@ -13,6 +13,10 @@
 using namespace std;
 using namespace gameplay;
 
+// Default to 720p
+#define WINDOW_WIDTH    1280
+#define WINDOW_HEIGHT   720
+
 static const float ACCELEROMETER_X_FACTOR = 90.0f / WINDOW_WIDTH;
 static const float ACCELEROMETER_Y_FACTOR = 90.0f / WINDOW_HEIGHT;
 
@@ -26,6 +30,7 @@ static int __ly;
 static bool __hasMouse = false;
 static bool __leftMouseDown = false;
 static bool __rightMouseDown = false;
+static bool __otherMouseDown = false;
 static bool __shiftDown = false;
 
 long getMachTimeInMilliseconds()
@@ -102,9 +107,7 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
 
 - (id) initWithFrame: (NSRect) frame
 {    
-    lock = [[NSRecursiveLock alloc] init];
-    _game = Game::getInstance();
-    __timeStart = getMachTimeInMilliseconds();
+
     NSOpenGLPixelFormatAttribute attrs[] = 
     {
         NSOpenGLPFAAccelerated,
@@ -120,7 +123,12 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
     if (!pf)
         NSLog(@"OpenGL pixel format not supported.");
     
-    self = [super initWithFrame:frame pixelFormat:[pf autorelease]];  
+    if((self = [super initWithFrame:frame pixelFormat:[pf autorelease]])) 
+    {
+        lock = [[NSRecursiveLock alloc] init];
+        _game = Game::getInstance();
+        __timeStart = getMachTimeInMilliseconds();
+    }
     
     return self;
 }
@@ -173,18 +181,47 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
     [super dealloc];
 }
 
+
+- (void) mouse: (Mouse::MouseEvent) mouseEvent orTouchEvent: (Touch::TouchEvent) touchEvent atX: (int) x y: (int) y s: (int) s 
+{
+    if (!Game::getInstance()->mouseEvent(mouseEvent, x, y, s))
+    {
+        Game::getInstance()->touchEvent(touchEvent, x, y, 0);
+    }
+        
+}
+
 - (void) mouseDown: (NSEvent*) event
 {
     NSPoint point = [event locationInWindow];
     __leftMouseDown = true;
-    _game->touchEvent(Touch::TOUCH_PRESS, point.x, WINDOW_HEIGHT - point.y, 0);
+    [self mouse: Mouse::MOUSE_PRESS_LEFT_BUTTON orTouchEvent: Touch::TOUCH_PRESS atX: WINDOW_HEIGHT - point.x y: point.y s: 0];
+
+    
+    //_game->mouseEvent(Mouse::MOUSE_PRESS_LEFT_BUTTON, point.x, WINDOW_HEIGHT - point.y, 0);
+   /* 
+    MOUSE_PRESS_LEFT_BUTTON,
+    MOUSE_RELEASE_LEFT_BUTTON,
+    MOUSE_PRESS_MIDDLE_BUTTON,
+    MOUSE_RELEASE_MIDDLE_BUTTON,
+    MOUSE_PRESS_RIGHT_BUTTON,
+    MOUSE_RELEASE_RIGHT_BUTTON,
+    MOUSE_MOVE,
+    MOUSE_WHEEL
+*/
 }
 
 - (void) mouseUp: (NSEvent*) event
 {
     NSPoint point = [event locationInWindow];
     __leftMouseDown = false;
-    _game->touchEvent(Touch::TOUCH_RELEASE, point.x, WINDOW_HEIGHT - point.y, 0);
+    [self mouse: Mouse::MOUSE_RELEASE_LEFT_BUTTON orTouchEvent: Touch::TOUCH_RELEASE atX: point.x y: WINDOW_HEIGHT - point.y s: 0];
+}
+
+- (void)mouseMoved:(NSEvent *) event 
+{
+    NSPoint point = [event locationInWindow];
+    Game::getInstance()->mouseEvent(Mouse::MOUSE_MOVE, point.x, WINDOW_HEIGHT - point.y, 0);
 }
 
 - (void) mouseDragged: (NSEvent*) event
@@ -192,7 +229,7 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
     NSPoint point = [event locationInWindow];
     if (__leftMouseDown)
     {
-        _game->touchEvent(Touch::TOUCH_MOVE, point.x, WINDOW_HEIGHT - point.y, 0);
+        [self mouse: Mouse::MOUSE_MOVE orTouchEvent: Touch::TOUCH_MOVE atX: point.x y: WINDOW_HEIGHT - point.y s: 0];
     }
 }
 
@@ -201,12 +238,15 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
     __rightMouseDown = true;
      NSPoint point = [event locationInWindow];
     __lx = point.x;
-    __ly = WINDOW_HEIGHT - point.y;
+    __ly = WINDOW_HEIGHT - point.y;    
+    _game->mouseEvent(Mouse::MOUSE_PRESS_RIGHT_BUTTON, point.x, WINDOW_HEIGHT - point.y, 0);
 }
 
 - (void) rightMouseUp: (NSEvent*) event
 {
    __rightMouseDown = false;
+    NSPoint point = [event locationInWindow];
+    _game->mouseEvent(Mouse::MOUSE_RELEASE_RIGHT_BUTTON, point.x, WINDOW_HEIGHT - point.y, 0);
 }
 
 - (void) rightMouseDragged: (NSEvent*) event
@@ -226,6 +266,30 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
         __lx = point.x;
         __ly = (WINDOW_HEIGHT - point.y);
     }
+    
+    // In right-mouse case, whether __rightMouseDown is true or false
+    // this should not matter, mouse move is still occuring
+    _game->mouseEvent(Mouse::MOUSE_MOVE, point.x, WINDOW_HEIGHT - point.y, 0);
+}
+
+- (void)otherMouseDown: (NSEvent *) event 
+{
+    __otherMouseDown = true;
+    NSPoint point = [event locationInWindow];
+    _game->mouseEvent(Mouse::MOUSE_PRESS_MIDDLE_BUTTON, point.x, WINDOW_HEIGHT - point.y, 0);
+}
+
+- (void)otherMouseUp: (NSEvent *) event 
+{
+    __otherMouseDown = false;
+    NSPoint point = [event locationInWindow];
+    _game->mouseEvent(Mouse::MOUSE_RELEASE_MIDDLE_BUTTON, point.x, WINDOW_HEIGHT - point.y, 0);
+}
+
+- (void)otherMouseDragged: (NSEvent *) event 
+{
+    NSPoint point = [event locationInWindow];
+    _game->mouseEvent(Mouse::MOUSE_MOVE, point.x, WINDOW_HEIGHT - point.y, 0);
 }
 
 - (void) mouseEntered: (NSEvent*)event
@@ -233,10 +297,17 @@ static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTime
     __hasMouse = true;
 }
 
+- (void)scrollWheel: (NSEvent *) event 
+{
+    NSPoint point = [event locationInWindow];
+    Game::getInstance()->mouseEvent(Mouse::MOUSE_WHEEL, point.x, WINDOW_HEIGHT - point.y, (int)([event deltaY] * 10.0f));
+}
+
 - (void) mouseExited: (NSEvent*)event
 {
     __leftMouseDown = false;
     __rightMouseDown = false;
+    __otherMouseDown = false;
     __hasMouse = false;
 }
 
@@ -544,6 +615,7 @@ int Platform::enterMessagePump()
                         backing:NSBackingStoreBuffered
                         defer:NO];
     
+    [window setAcceptsMouseMovedEvents:YES];
     [window setContentView:__view];
     [window setDelegate:__view];
     [__view release];
@@ -553,7 +625,17 @@ int Platform::enterMessagePump()
     [pool release];
     return EXIT_SUCCESS;
 }
-    
+
+unsigned int Platform::getDisplayWidth()
+{
+    return WINDOW_WIDTH;
+}
+
+unsigned int Platform::getDisplayHeight()
+{
+    return WINDOW_HEIGHT;
+}
+
 long Platform::getAbsoluteTime()
 {
     __timeAbsolute = getMachTimeInMilliseconds();

+ 10 - 0
gameplay/src/PlatformQNX.cpp

@@ -962,6 +962,16 @@ int Platform::enterMessagePump()
 
     return 0;
 }
+    
+unsigned int Platform::getDisplayWidth()
+{
+    return __screenWindowSize[0];
+}
+
+unsigned int Platform::getDisplayHeight()
+{
+    return __screenWindowSize[1];
+}
 
 long Platform::getAbsoluteTime()
 {

+ 19 - 0
gameplay/src/PlatformWin32.cpp

@@ -6,6 +6,10 @@
 #include "Game.h"
 #include <GL/wglew.h>
 
+// Default to 720p
+#define WINDOW_WIDTH    1280
+#define WINDOW_HEIGHT   720
+
 static long __timeTicksPerMillis;
 static long __timeStart;
 static long __timeAbsolute;
@@ -471,6 +475,11 @@ Platform* Platform::create(Game* game)
     // Get the drawing context.
     __hdc = GetDC(__hwnd);
 
+    // Center the window
+    const int screenX = (GetSystemMetrics(SM_CXSCREEN) - WINDOW_WIDTH) / 2;
+    const int screenY = (GetSystemMetrics(SM_CYSCREEN) - WINDOW_HEIGHT) / 2;
+    ::SetWindowPos(__hwnd, __hwnd, screenX, screenY, -1, -1, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
+
     // Choose pixel format. 32-bit. RGBA.
     PIXELFORMATDESCRIPTOR pfd;
     memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
@@ -570,6 +579,16 @@ int Platform::enterMessagePump()
     return msg.wParam;
 }
 
+unsigned int Platform::getDisplayWidth()
+{
+    return WINDOW_WIDTH;
+}
+
+unsigned int Platform::getDisplayHeight()
+{
+    return WINDOW_HEIGHT;
+}
+    
 long Platform::getAbsoluteTime()
 {
        LARGE_INTEGER queryTime;

+ 17 - 2
gameplay/src/PlatformiOS.mm

@@ -18,6 +18,11 @@
 using namespace std;
 using namespace gameplay;
 
+// UIScreen bounds are provided as if device was in portrait mode
+// Gameplay defaults to landscape
+extern const int WINDOW_WIDTH  = [[UIScreen mainScreen] bounds].size.height;
+extern const int WINDOW_HEIGHT = [[UIScreen mainScreen] bounds].size.width;
+
 static const float ACCELEROMETER_X_FACTOR = 90.0f / WINDOW_WIDTH;
 static const float ACCELEROMETER_Y_FACTOR = 90.0f / WINDOW_HEIGHT;
 
@@ -332,7 +337,7 @@ int getKey(unichar keyCode);
         CGPoint touchLoc = [t locationInView:self];
         if(self.multipleTouchEnabled == YES) 
             uniqueTouch = [t hash];
-        Game::getInstance()->touchEvent(Touch::TOUCH_PRESS, touchLoc.x,  touchLoc.y, uniqueTouch);
+        Game::getInstance()->touchEvent(Touch::TOUCH_PRESS, touchLoc.x, touchLoc.y, uniqueTouch);
     }
 }
 
@@ -362,7 +367,7 @@ int getKey(unichar keyCode);
         CGPoint touchLoc = [t locationInView:self];
         if(self.multipleTouchEnabled == YES) 
             uniqueTouch = [t hash];
-        Game::getInstance()->touchEvent(Touch::TOUCH_MOVE, touchLoc.x,  touchLoc.y, uniqueTouch);
+        Game::getInstance()->touchEvent(Touch::TOUCH_MOVE, touchLoc.x, touchLoc.y, uniqueTouch);
     }
 }
 
@@ -782,6 +787,16 @@ int Platform::enterMessagePump()
     [pool release];
     return EXIT_SUCCESS;
 }
+    
+unsigned int Platform::getDisplayWidth()
+{
+    return WINDOW_WIDTH;
+}
+
+unsigned int Platform::getDisplayHeight()
+{
+    return WINDOW_HEIGHT;
+}
 
 long Platform::getAbsoluteTime()
 {

+ 2 - 1
gameplay/src/gameplay-main-ios.mm

@@ -4,11 +4,12 @@
 
 using namespace gameplay;
 
+
 /**
  * Main entry point.
  */
 int main(int argc, char** argv)
-{
+{    
     Game* game = Game::getInstance();
     assert(game != NULL);
     Platform* platform = Platform::create(game);