瀏覽代碼

Merge pull request #57 from blackberry-gaming/next

Next
Sean Paul Taylor 13 年之前
父節點
當前提交
ca13b13284

+ 3 - 0
gameplay/src/AbsoluteLayout.h

@@ -16,6 +16,7 @@ class AbsoluteLayout : public Layout
     friend class Container;
 
 public:
+
     /**
      * Get the type of this Layout.
      *
@@ -24,6 +25,7 @@ public:
     Layout::Type getType();
 
 protected:
+
     /**
      * Create an AbsoluteLayout.
      *
@@ -42,6 +44,7 @@ protected:
     void update(const Container* container);
 
 private:
+
     AbsoluteLayout();
     AbsoluteLayout(const AbsoluteLayout& copy);
     virtual ~AbsoluteLayout();

+ 5 - 14
gameplay/src/Animation.cpp

@@ -34,6 +34,8 @@ Animation::Animation(const char* id)
 
 Animation::~Animation()
 {
+    _channels.clear();
+
     if (_defaultClip)
     {
         if (_defaultClip->isClipStateBitSet(AnimationClip::CLIP_IS_PLAYING_BIT))
@@ -61,20 +63,15 @@ Animation::~Animation()
 Animation::Channel::Channel(Animation* animation, AnimationTarget* target, int propertyId, Curve* curve, unsigned long duration)
     : _animation(animation), _target(target), _propertyId(propertyId), _curve(curve), _duration(duration)
 {
-    _curve->addRef();
     // get property component count, and ensure the property exists on the AnimationTarget by getting the property component count.
     assert(_target->getAnimationPropertyComponentCount(propertyId));
 
-    _animation->addRef();
-
     _target->addChannel(this);
 }
 
 Animation::Channel::Channel(const Channel& copy, Animation* animation, AnimationTarget* target)
     : _animation(animation), _target(target), _propertyId(copy._propertyId), _curve(copy._curve), _duration(copy._duration)
-{
-    _curve->addRef();
-    _animation->addRef();
+{
     _target->addChannel(this);
 }
 
@@ -209,7 +206,7 @@ void Animation::createDefaultClip()
 }
 
 void Animation::createClips(Properties* animationProperties, unsigned int frameCount)
-{   
+{
     assert(animationProperties);
     
     Properties* pClip = animationProperties->getNextNamespace();
@@ -306,7 +303,6 @@ Animation::Channel* Animation::createChannel(AnimationTarget* target, int proper
     SAFE_DELETE(normalizedKeyTimes);
 
     Channel* channel = new Channel(this, target, propertyId, curve, duration);
-    curve->release();
     addChannel(channel);
     return channel;
 }
@@ -343,7 +339,6 @@ Animation::Channel* Animation::createChannel(AnimationTarget* target, int proper
     SAFE_DELETE(normalizedKeyTimes);
 
     Channel* channel = new Channel(this, target, propertyId, curve, duration);
-    curve->release();
     addChannel(channel);
     return channel;
 }
@@ -365,16 +360,13 @@ void Animation::removeChannel(Channel* channel)
         if (channel == chan) 
         {
             _channels.erase(itr);
-            itr = _channels.end();
+            return;
         }
         else
         {
             itr++;
         }
     }
-
-    if (_channels.empty())
-        _controller->destroyAnimation(this);
 }
 
 void Animation::setTransformRotationOffset(Curve* curve, unsigned int propertyId)
@@ -396,7 +388,6 @@ void Animation::setTransformRotationOffset(Curve* curve, unsigned int propertyId
 Animation* Animation::clone()
 {
     Animation* animation = new Animation(getId());
-    _controller->addAnimation(animation);
     return animation;
 }
 

+ 3 - 5
gameplay/src/Animation.h

@@ -22,7 +22,6 @@ class AnimationClip;
  */
 class Animation : public Ref
 {
-    friend class AnimationController;
     friend class AnimationClip;
     friend class AnimationTarget;
     friend class Package;
@@ -93,7 +92,7 @@ public:
      * Returns true if this animation targets the given AnimationTarget.
      */
     bool targets(AnimationTarget* target) const;
-
+    
 private:
 
     /**
@@ -104,7 +103,6 @@ private:
      */
     class Channel
     {
-        friend class AnimationController;
         friend class AnimationClip;
         friend class Animation;
         friend class AnimationTarget;
@@ -149,12 +147,12 @@ private:
      * Destructor.
      */
     ~Animation();
-
+    
     /**
      * Hidden copy assignment operator.
      */
     Animation& operator=(const Animation&);
-
+    
     /**
      * Creates the default clip.
      */

+ 1 - 303
gameplay/src/AnimationController.cpp

@@ -7,125 +7,12 @@ namespace gameplay
 {
 
 AnimationController::AnimationController()
-    : _state(STOPPED), _animations(NULL)
+    : _state(STOPPED)
 {
 }
 
 AnimationController::~AnimationController()
 {
-    std::vector<Animation*>::iterator itr = _animations.begin();
-    for ( ; itr != _animations.end(); itr++)
-    {
-        Animation* temp = *itr;
-        SAFE_RELEASE(temp);
-    }
-
-    _animations.clear();
-}
-
-Animation* AnimationController::createAnimation(const char* id, AnimationTarget* target, int propertyId, unsigned int keyCount, unsigned long* keyTimes, float* keyValues, Curve::InterpolationType type)
-{
-    assert(type != Curve::BEZIER && type != Curve::HERMITE);
-    assert(keyCount >= 2 && keyTimes && keyValues && target);
-
-    Animation* animation = new Animation(id, target, propertyId, keyCount, keyTimes, keyValues, type);
-
-    addAnimation(animation);
-    
-    return animation;
-}
-
-Animation* AnimationController::createAnimation(const char* id, AnimationTarget* target, int propertyId, unsigned int keyCount, unsigned long* keyTimes, float* keyValues, float* keyInValue, float* keyOutValue, Curve::InterpolationType type)
-{
-    assert(target && keyCount >= 2 && keyTimes && keyValues && keyInValue && keyOutValue);
-    Animation* animation = new Animation(id, target, propertyId, keyCount, keyTimes, keyValues, keyInValue, keyOutValue, type);
-
-    addAnimation(animation);
-
-    return animation;
-}
-
-Animation* AnimationController::createAnimation(const char* id, AnimationTarget* target, const char* animationFile)
-{
-    assert(target && animationFile);
-    
-    Properties* p = Properties::create(animationFile);
-    assert(p);
-
-    Animation* animation = createAnimation(id, target, p->getNextNamespace());
-
-    SAFE_DELETE(p);
-
-    return animation;
-}
-
-Animation* AnimationController::createAnimationFromTo(const char* id, AnimationTarget* target, int propertyId, float* from, float* to, Curve::InterpolationType type, unsigned long duration)
-{
-    const unsigned int propertyComponentCount = target->getAnimationPropertyComponentCount(propertyId);
-    float* keyValues = new float[2 * propertyComponentCount];
-
-    memcpy(keyValues, from, sizeof(float) * propertyComponentCount);
-    memcpy(keyValues + propertyComponentCount, to, sizeof(float) * propertyComponentCount);
-
-    unsigned long* keyTimes = new unsigned long[2];
-    keyTimes[0] = 0;
-    keyTimes[1] = duration;
-
-    Animation* animation = createAnimation(id, target, propertyId, 2, keyTimes, keyValues, type);
-
-    SAFE_DELETE_ARRAY(keyValues);
-    SAFE_DELETE_ARRAY(keyTimes);
-    
-    return animation;
-}
-
-Animation* AnimationController::createAnimationFromBy(const char* id, AnimationTarget* target, int propertyId, float* from, float* by, Curve::InterpolationType type, unsigned long duration)
-{
-    const unsigned int propertyComponentCount = target->getAnimationPropertyComponentCount(propertyId);
-    float* keyValues = new float[2 * propertyComponentCount];
-
-    memcpy(keyValues, from, sizeof(float) * propertyComponentCount);
-    memcpy(keyValues + propertyComponentCount, by, sizeof(float) * propertyComponentCount);
-
-    unsigned long* keyTimes = new unsigned long[2];
-    keyTimes[0] = 0;
-    keyTimes[1] = duration;
-
-    Animation* animation = createAnimation(id, target, propertyId, 2, keyTimes, keyValues, type);
-
-    SAFE_DELETE_ARRAY(keyValues);
-    SAFE_DELETE_ARRAY(keyTimes);
-
-    return animation;
-}
-
-Animation* AnimationController::getAnimation(const char* id) const
-{
-    unsigned int animationCount = _animations.size();
-    for (unsigned int i = 0; i < animationCount; i++)
-    {
-        if (_animations.at(i)->_id.compare(id) == 0)
-        {
-            return _animations.at(i);
-        }
-    }
-    return NULL;
-}
-
-Animation* AnimationController::getAnimation(AnimationTarget* target) const
-{
-    if (!target)
-        return NULL;
-    const unsigned int animationCount = _animations.size();
-    for (unsigned int i = 0; i < animationCount; ++i)
-    {
-        Animation* animation = _animations[i];
-        if (animation->targets(target))
-        {
-            return animation;
-        }
-    }
-    return NULL;
 }
 
 void AnimationController::stopAllAnimations() 
@@ -139,144 +26,6 @@ void AnimationController::stopAllAnimations()
     }
 }
 
-Animation* AnimationController::createAnimation(const char* id, AnimationTarget* target, Properties* animationProperties)
-{
-    assert(target && animationProperties);
-    assert(std::strcmp(animationProperties->getNamespace(), "animation") == 0);
-    
-    const char* propertyIdStr = animationProperties->getString("property");
-    assert(propertyIdStr);
-    
-    // Get animation target property id
-    int propertyId = AnimationTarget::getPropertyId(target->_targetType, propertyIdStr);
-    assert(propertyId != -1);
-    
-    unsigned int keyCount = animationProperties->getInt("keyCount");
-    assert(keyCount > 0);
-
-    const char* keyTimesStr = animationProperties->getString("keyTimes");
-    assert(keyTimesStr);
-    
-    const char* keyValuesStr = animationProperties->getString("keyValues");
-    assert(keyValuesStr);
-    
-    const char* curveStr = animationProperties->getString("curve");
-    assert(curveStr);
-    
-    char delimeter = ' ';
-    unsigned int startOffset = 0;
-    unsigned int endOffset = (unsigned int)std::string::npos;
-    
-    unsigned long* keyTimes = new unsigned long[keyCount];
-    for (unsigned int i = 0; i < keyCount; i++)
-    {
-        endOffset = static_cast<std::string>(keyTimesStr).find_first_of(delimeter, startOffset);
-        if (endOffset != std::string::npos)
-        {
-            keyTimes[i] = std::strtoul(static_cast<std::string>(keyTimesStr).substr(startOffset, endOffset - startOffset).c_str(), NULL, 0);
-        }
-        else
-        {
-            keyTimes[i] = std::strtoul(static_cast<std::string>(keyTimesStr).substr(startOffset, static_cast<std::string>(keyTimesStr).length()).c_str(), NULL, 0);
-        }
-        startOffset = endOffset + 1;
-    }
-
-    startOffset = 0;
-    endOffset = (unsigned int)std::string::npos;
-    
-    int componentCount = target->getAnimationPropertyComponentCount(propertyId);
-    assert(componentCount > 0);
-    
-    unsigned int components = keyCount * componentCount;
-    
-    float* keyValues = new float[components];
-    for (unsigned int i = 0; i < components; i++)
-    {
-        endOffset = static_cast<std::string>(keyValuesStr).find_first_of(delimeter, startOffset);
-        if (endOffset != std::string::npos)
-        {   
-            keyValues[i] = std::atof(static_cast<std::string>(keyValuesStr).substr(startOffset, endOffset - startOffset).c_str());
-        }
-        else
-        {
-            keyValues[i] = std::atof(static_cast<std::string>(keyValuesStr).substr(startOffset, static_cast<std::string>(keyValuesStr).length()).c_str());
-        }
-        startOffset = endOffset + 1;
-    }
-
-    const char* keyInStr = animationProperties->getString("keyIn");
-    float* keyIn = NULL;
-    if (keyInStr)
-    {
-        keyIn = new float[components];
-        startOffset = 0;
-        endOffset = (unsigned int)std::string::npos;
-        for (unsigned int i = 0; i < components; i++)
-        {
-            endOffset = static_cast<std::string>(keyInStr).find_first_of(delimeter, startOffset);
-            if (endOffset != std::string::npos)
-            {   
-                keyIn[i] = std::atof(static_cast<std::string>(keyInStr).substr(startOffset, endOffset - startOffset).c_str());
-            }
-            else
-            {
-                keyIn[i] = std::atof(static_cast<std::string>(keyInStr).substr(startOffset, static_cast<std::string>(keyInStr).length()).c_str());
-            }
-            startOffset = endOffset + 1;
-        }
-    }
-    
-    const char* keyOutStr = animationProperties->getString("keyOut");
-    float* keyOut = NULL;
-    if (keyOutStr)
-    {   
-        keyOut = new float[components];
-        startOffset = 0;
-        endOffset = (unsigned int)std::string::npos;
-        for (unsigned int i = 0; i < components; i++)
-        {
-            endOffset = static_cast<std::string>(keyOutStr).find_first_of(delimeter, startOffset);
-            if (endOffset != std::string::npos)
-            {   
-                keyOut[i] = std::atof(static_cast<std::string>(keyOutStr).substr(startOffset, endOffset - startOffset).c_str());
-            }
-            else
-            {
-                keyOut[i] = std::atof(static_cast<std::string>(keyOutStr).substr(startOffset, static_cast<std::string>(keyOutStr).length()).c_str());
-            }
-            startOffset = endOffset + 1;
-        }
-    }
-
-    int curve = Curve::getInterpolationType(curveStr);
-
-    Animation* animation = NULL;
-    if (keyIn && keyOut)
-    {
-        animation = createAnimation(id, target, propertyId, keyCount, keyTimes, keyValues, keyIn, keyOut, (Curve::InterpolationType)curve);
-    }
-    else
-    {
-        animation = createAnimation(id, target, propertyId, keyCount, keyTimes, keyValues, (Curve::InterpolationType) curve);
-    }
-
-    SAFE_DELETE(keyOut);
-    SAFE_DELETE(keyIn);
-    SAFE_DELETE(keyValues);
-    SAFE_DELETE(keyTimes);
-
-    Properties* pClip = animationProperties->getNextNamespace();
-    if (pClip && std::strcmp(pClip->getNamespace(), "clip") == 0)
-    {
-        int frameCount = animationProperties->getInt("frameCount");
-        assert(frameCount > 0);
-        animation->createClips(animationProperties, (unsigned int) frameCount);
-    }
-
-    return animation;
-}
-
 AnimationController::State AnimationController::getState() const
 {
     return _state;
@@ -385,55 +134,4 @@ void AnimationController::update(long elapsedTime)
         _state = IDLE;
 }
 
-void AnimationController::addAnimation(Animation* animation)
-{
-    _animations.push_back(animation);
-}
-
-void AnimationController::destroyAnimation(Animation* animation)
-{
-    assert(animation);
-
-    std::vector<Animation::Channel*>::iterator cItr = animation->_channels.begin();
-    for (; cItr != animation->_channels.end(); cItr++)
-    {
-        Animation::Channel* channel = *cItr;
-        channel->_target->deleteChannel(channel);
-    }
-
-    std::vector<Animation*>::iterator aItr = _animations.begin();
-    while (aItr != _animations.end())
-    {
-        if (animation == *aItr)
-        {
-            Animation* temp = *aItr;
-            SAFE_RELEASE(temp);
-            _animations.erase(aItr);
-            return;
-        }
-        aItr++;
-    }
-}
-
-void AnimationController::destroyAllAnimations()
-{
-    std::vector<Animation*>::iterator aItr = _animations.begin();
-    
-    while (aItr != _animations.end())
-    {
-        Animation* animation = *aItr;
-        std::vector<Animation::Channel*>::iterator cItr = animation->_channels.begin();
-        for (; cItr != animation->_channels.end(); cItr++)
-        {
-            Animation::Channel* channel = *cItr;
-            channel->_target->deleteChannel(channel);
-        }
-
-        SAFE_RELEASE(animation);
-        aItr++;
-    }
-
-    _animations.clear();
-}
-
 }

+ 2 - 119
gameplay/src/AnimationController.h

@@ -21,110 +21,10 @@ class AnimationController
 
 public:
 
-    /**
-     * Creates an animation on this target from a set of key value and key time pairs. 
-     * Cannot use Curve::BEZIER or CURVE::HERMITE as the interpolation type since they require tangents/control points.
-     * 
-     * @param id The ID of the animation.
-     * @param target The animation target.
-     * @param propertyId The property on this target to animate.
-     * @param keyCount The number of keyframes in the animation. Must be greater than one.
-     * @param keyTimes The list of key times for the animation (in milliseconds).
-     * @param keyValues The list of key values for the animation.
-     * @param type The curve interpolation type.
-     *
-     * @return The newly created animation.
-     */
-    Animation* createAnimation(const char* id, AnimationTarget* target, int propertyId, unsigned int keyCount, unsigned long* keyTimes, float* keyValues, Curve::InterpolationType type);
-
-    /**
-     * Creates an animation on this target from a set of key value and key time pairs.
-     * 
-     * @param id The ID of the animation.
-     * @param target The animation target.
-     * @param propertyId The property on this target to animate.
-     * @param keyCount The number of keyframes in the animation. Must be greater than one.
-     * @param keyTimes The list of key times for the animation (in milliseconds).
-     * @param keyValues The list of key values for the animation.
-     * @param keyInValue The list of key in values for the animation.
-     * @param keyOutValue The list of key out values for the animation.
-     * @param type The curve interpolation type.
-     *
-     * @return The newly created animation.
-     */
-    Animation* createAnimation(const char* id, AnimationTarget* target, int propertyId, unsigned int keyCount, unsigned long* keyTimes, float* keyValues, float* keyInValue, float* keyOutValue, Curve::InterpolationType type);
-
-    /**
-     * Creates an animation on this target using the data from the given properties object. 
-     * 
-     * @param id The ID of the animation.
-     * @param target The animation target.
-     * @param animationFile The animation file defining the animation data.
-     *
-     * @return The newly created animation.
-     */
-    Animation* createAnimation(const char* id, AnimationTarget* target, const char* animationFile);
-
-    /**
-     * Creates a simple two keyframe from-to animation.
-     * Cannot use Curve::BEZIER or CURVE::HERMITE as the interpolation type since they require tangents/control points.
-     *
-     * @param id The ID of the animation.
-     * @param target The animation target.
-     * @param propertyId The property on this target to animate.
-     * @param from The values to animate from.
-     * @param to The values to animate to.
-     * @param type The curve interpolation type.
-     * @param duration The duration of the animation (in milliseconds).
-     *
-     * @return The newly created animation.
-     */
-    Animation* createAnimationFromTo(const char* id, AnimationTarget* target, int propertyId, float* from, float* to, Curve::InterpolationType type, unsigned long duration);
-
-    /**
-     * Creates a simple two keyframe from-by animation.
-     * Cannot use Curve::BEZIER or CURVE::HERMITE as the interpolation type since they require tangents/control points.
-     *
-     * @param id The ID of the animation.
-     * @param target The animation target.
-     * @param propertyId The property on this target to animate.
-     * @param from The values to animate from.
-     * @param by The values to animate by.
-     * @param type The curve interpolation type.
-     * @param duration The duration of the animation (in milliseconds).
-     *
-     * @return The newly created animation.
-     */
-    Animation* createAnimationFromBy(const char* id, AnimationTarget* target, int propertyId, float* from, float* by, Curve::InterpolationType type, unsigned long duration);
-
-    /**
-     * Finds the animation with the given ID.
-     *
-     * @param id The ID of the animation to get. NULL if the Animation is not found.
-     * 
-     * @return The animation, or NULL if not found.
-     */
-    Animation* getAnimation(const char* id) const;
-
-    /**
-     * Returns the first animation that targets the given AnimationTarget.
-     */
-    Animation* getAnimation(AnimationTarget* target) const;
-
     /** 
      * Stops all AnimationClips currently playing on the AnimationController.
      */
     void stopAllAnimations();
-
-    /**
-     * Removes the given animation from this AnimationTarget.
-     */
-    void destroyAnimation(Animation* animation);
-
-    /**
-     * Removes all animations from the AnimationTarget.
-     */ 
-    void destroyAllAnimations();
        
 private:
 
@@ -150,17 +50,6 @@ private:
      * Destructor.
      */
     ~AnimationController();
-    
-    /**
-     * Creates an animation on this target using the data from the given properties object. 
-     * 
-     * @param id The ID of the animation.
-     * @param target The animation target.
-     * @param properties The properties object defining the animation data.
-     *
-     * @return The newly created animation.
-     */
-    Animation* createAnimation(const char* id, AnimationTarget* target, Properties* animationProperties);
 
     /**
      * Gets the controller's state.
@@ -203,16 +92,10 @@ private:
      * Callback for when the controller receives a frame update event.
      */
     void update(long elapsedTime);
-
-    /**
-     * Adds an animation on this AnimationTarget.
-     */ 
-    void addAnimation(Animation* animation);
     
-    State _state;                               // The current state of the AnimationController.
-    std::list<AnimationClip*> _runningClips;    // A list of running AnimationClips.
+    State _state;                                 // The current state of the AnimationController.
+    std::list<AnimationClip*> _runningClips;      // A list of running AnimationClips.
     std::list<AnimationTarget*> _activeTargets;   // A list of animating AnimationTargets.
-    std::vector<Animation*> _animations;        // A list of animations registered with the AnimationController
 };
 
 }

+ 275 - 6
gameplay/src/AnimationTarget.cpp

@@ -29,12 +29,251 @@ AnimationTarget::~AnimationTarget()
     }
 }
 
-void AnimationTarget::addChannel(Animation::Channel* channel)
+Animation* AnimationTarget::createAnimation(const char* id, int propertyId, unsigned int keyCount, unsigned long* keyTimes, float* keyValues, Curve::InterpolationType type)
 {
-    if (_animationChannels == NULL)
-        _animationChannels = new std::vector<Animation::Channel*>;
+    assert(type != Curve::BEZIER && type != Curve::HERMITE);
+    assert(keyCount >= 1 && keyTimes && keyValues);
 
-    _animationChannels->push_back(channel);
+    Animation* animation = new Animation(id, this, propertyId, keyCount, keyTimes, keyValues, type);
+
+    return animation;
+}
+
+Animation* AnimationTarget::createAnimation(const char* id, int propertyId, unsigned int keyCount, unsigned long* keyTimes, float* keyValues, float* keyInValue, float* keyOutValue, Curve::InterpolationType type)
+{
+    assert(keyCount >= 1 && keyTimes && keyValues && keyInValue && keyOutValue);
+    Animation* animation = new Animation(id, this, propertyId, keyCount, keyTimes, keyValues, keyInValue, keyOutValue, type);
+
+    return animation;
+}
+
+Animation* AnimationTarget::createAnimation(const char* id, const char* animationFile)
+{
+    assert(animationFile);
+    
+    Properties* p = Properties::create(animationFile);
+    assert(p);
+
+    Animation* animation = createAnimation(id, p->getNextNamespace());
+
+    SAFE_DELETE(p);
+
+    return animation;
+}
+
+Animation* AnimationTarget::createAnimationFromTo(const char* id, int propertyId, float* from, float* to, Curve::InterpolationType type, unsigned long duration)
+{
+    const unsigned int propertyComponentCount = getAnimationPropertyComponentCount(propertyId);
+    float* keyValues = new float[2 * propertyComponentCount];
+
+    memcpy(keyValues, from, sizeof(float) * propertyComponentCount);
+    memcpy(keyValues + propertyComponentCount, to, sizeof(float) * propertyComponentCount);
+
+    unsigned long* keyTimes = new unsigned long[2];
+    keyTimes[0] = 0;
+    keyTimes[1] = duration;
+
+    Animation* animation = createAnimation(id, propertyId, 2, keyTimes, keyValues, type);
+
+    SAFE_DELETE_ARRAY(keyValues);
+    SAFE_DELETE_ARRAY(keyTimes);
+
+    return animation;
+}
+
+Animation* AnimationTarget::createAnimationFromBy(const char* id, int propertyId, float* from, float* by, Curve::InterpolationType type, unsigned long duration)
+{
+    const unsigned int propertyComponentCount = getAnimationPropertyComponentCount(propertyId);
+    float* keyValues = new float[2 * propertyComponentCount];
+
+    memcpy(keyValues, from, sizeof(float) * propertyComponentCount);
+    memcpy(keyValues + propertyComponentCount, by, sizeof(float) * propertyComponentCount);
+
+    unsigned long* keyTimes = new unsigned long[2];
+    keyTimes[0] = 0;
+    keyTimes[1] = duration;
+
+    Animation* animation = createAnimation(id, propertyId, 2, keyTimes, keyValues, type);
+
+    SAFE_DELETE_ARRAY(keyValues);
+    SAFE_DELETE_ARRAY(keyTimes);
+
+    return animation;
+}
+
+Animation* AnimationTarget::createAnimation(const char* id, Properties* animationProperties)
+{
+    assert(animationProperties);
+    assert(std::strcmp(animationProperties->getNamespace(), "animation") == 0);
+    
+    const char* propertyIdStr = animationProperties->getString("property");
+    assert(propertyIdStr);
+    
+    // Get animation target property id
+    int propertyId = AnimationTarget::getPropertyId(_targetType, propertyIdStr);
+    assert(propertyId != -1);
+    
+    unsigned int keyCount = animationProperties->getInt("keyCount");
+    assert(keyCount > 0);
+
+    const char* keyTimesStr = animationProperties->getString("keyTimes");
+    assert(keyTimesStr);
+    
+    const char* keyValuesStr = animationProperties->getString("keyValues");
+    assert(keyValuesStr);
+    
+    const char* curveStr = animationProperties->getString("curve");
+    assert(curveStr);
+    
+    char delimeter = ' ';
+    unsigned int startOffset = 0;
+    unsigned int endOffset = (unsigned int)std::string::npos;
+    
+    unsigned long* keyTimes = new unsigned long[keyCount];
+    for (unsigned int i = 0; i < keyCount; i++)
+    {
+        endOffset = static_cast<std::string>(keyTimesStr).find_first_of(delimeter, startOffset);
+        if (endOffset != std::string::npos)
+        {
+            keyTimes[i] = std::strtoul(static_cast<std::string>(keyTimesStr).substr(startOffset, endOffset - startOffset).c_str(), NULL, 0);
+        }
+        else
+        {
+            keyTimes[i] = std::strtoul(static_cast<std::string>(keyTimesStr).substr(startOffset, static_cast<std::string>(keyTimesStr).length()).c_str(), NULL, 0);
+        }
+        startOffset = endOffset + 1;
+    }
+
+    startOffset = 0;
+    endOffset = (unsigned int)std::string::npos;
+    
+    int componentCount = getAnimationPropertyComponentCount(propertyId);
+    assert(componentCount > 0);
+    
+    unsigned int components = keyCount * componentCount;
+    
+    float* keyValues = new float[components];
+    for (unsigned int i = 0; i < components; i++)
+    {
+        endOffset = static_cast<std::string>(keyValuesStr).find_first_of(delimeter, startOffset);
+        if (endOffset != std::string::npos)
+        {   
+            keyValues[i] = std::atof(static_cast<std::string>(keyValuesStr).substr(startOffset, endOffset - startOffset).c_str());
+        }
+        else
+        {
+            keyValues[i] = std::atof(static_cast<std::string>(keyValuesStr).substr(startOffset, static_cast<std::string>(keyValuesStr).length()).c_str());
+        }
+        startOffset = endOffset + 1;
+    }
+
+    const char* keyInStr = animationProperties->getString("keyIn");
+    float* keyIn = NULL;
+    if (keyInStr)
+    {
+        keyIn = new float[components];
+        startOffset = 0;
+        endOffset = (unsigned int)std::string::npos;
+        for (unsigned int i = 0; i < components; i++)
+        {
+            endOffset = static_cast<std::string>(keyInStr).find_first_of(delimeter, startOffset);
+            if (endOffset != std::string::npos)
+            {   
+                keyIn[i] = std::atof(static_cast<std::string>(keyInStr).substr(startOffset, endOffset - startOffset).c_str());
+            }
+            else
+            {
+                keyIn[i] = std::atof(static_cast<std::string>(keyInStr).substr(startOffset, static_cast<std::string>(keyInStr).length()).c_str());
+            }
+            startOffset = endOffset + 1;
+        }
+    }
+    
+    const char* keyOutStr = animationProperties->getString("keyOut");
+    float* keyOut = NULL;
+    if (keyOutStr)
+    {   
+        keyOut = new float[components];
+        startOffset = 0;
+        endOffset = (unsigned int)std::string::npos;
+        for (unsigned int i = 0; i < components; i++)
+        {
+            endOffset = static_cast<std::string>(keyOutStr).find_first_of(delimeter, startOffset);
+            if (endOffset != std::string::npos)
+            {   
+                keyOut[i] = std::atof(static_cast<std::string>(keyOutStr).substr(startOffset, endOffset - startOffset).c_str());
+            }
+            else
+            {
+                keyOut[i] = std::atof(static_cast<std::string>(keyOutStr).substr(startOffset, static_cast<std::string>(keyOutStr).length()).c_str());
+            }
+            startOffset = endOffset + 1;
+        }
+    }
+
+    int curve = Curve::getInterpolationType(curveStr);
+
+    Animation* animation = NULL;
+    if (keyIn && keyOut)
+    {
+        animation = createAnimation(id, propertyId, keyCount, keyTimes, keyValues, keyIn, keyOut, (Curve::InterpolationType)curve);
+    }
+    else
+    {
+        animation = createAnimation(id, propertyId, keyCount, keyTimes, keyValues, (Curve::InterpolationType) curve);
+    }
+
+    SAFE_DELETE(keyOut);
+    SAFE_DELETE(keyIn);
+    SAFE_DELETE(keyValues);
+    SAFE_DELETE(keyTimes);
+
+    Properties* pClip = animationProperties->getNextNamespace();
+    if (pClip && std::strcmp(pClip->getNamespace(), "clip") == 0)
+    {
+        int frameCount = animationProperties->getInt("frameCount");
+        assert(frameCount > 0);
+        animation->createClips(animationProperties, (unsigned int) frameCount);
+    }
+
+    return animation;
+}
+
+void AnimationTarget::destroyAnimation(const char* id)
+{
+    // Find the animation with the specified ID.
+    Animation::Channel* channel = getChannel(id);
+    if (channel == NULL)
+        return;
+
+    // Remove this target's channel from animation, and from the target's list of channels.
+    channel->_animation->removeChannel(channel);
+    removeChannel(channel);
+
+    SAFE_DELETE(channel);
+}
+
+Animation* AnimationTarget::getAnimation(const char* id) const
+{
+    if (_animationChannels)
+    {
+        std::vector<Animation::Channel*>::iterator itr = _animationChannels->begin();
+
+        if (id == NULL)
+            return (*itr)->_animation;
+
+        Animation::Channel* channel = NULL;
+        for (; itr != _animationChannels->end(); itr++)
+        {
+            channel = (Animation::Channel*)(*itr);
+            if (channel->_animation->_id.compare(id) == 0)
+            {
+                return channel->_animation;
+            }
+        }
+    }
+
+    return NULL;
 }
 
 int AnimationTarget::getPropertyId(TargetType type, const char* propertyIdStr)
@@ -97,7 +336,15 @@ int AnimationTarget::getPropertyId(TargetType type, const char* propertyIdStr)
     return -1;
 }
 
-void AnimationTarget::deleteChannel(Animation::Channel* channel)
+void AnimationTarget::addChannel(Animation::Channel* channel)
+{
+    if (_animationChannels == NULL)
+        _animationChannels = new std::vector<Animation::Channel*>;
+
+    _animationChannels->push_back(channel);
+}
+
+void AnimationTarget::removeChannel(Animation::Channel* channel)
 {
     if (_animationChannels)
     {
@@ -107,7 +354,6 @@ void AnimationTarget::deleteChannel(Animation::Channel* channel)
             Animation::Channel* temp = *itr;
             if (channel == temp)
             {
-                SAFE_DELETE(channel);
                 _animationChannels->erase(itr);
 
                 if (_animationChannels->empty())
@@ -119,6 +365,29 @@ void AnimationTarget::deleteChannel(Animation::Channel* channel)
     }
 }
 
+Animation::Channel* AnimationTarget::getChannel(const char* id) const
+{
+    if (_animationChannels)
+    {
+        std::vector<Animation::Channel*>::iterator itr = _animationChannels->begin();
+
+        if (id == NULL)
+            return (*itr);
+
+        Animation::Channel* channel = NULL;
+        for (; itr != _animationChannels->end(); itr++)
+        {
+            channel = (Animation::Channel*)(*itr);
+            if (channel->_animation->_id.compare(id) == 0)
+            {
+                return channel;
+            }
+        }
+    }
+
+    return NULL;
+}
+
 void AnimationTarget::cloneInto(AnimationTarget* target, NodeCloneContext &context) const
 {
     if (_animationChannels)

+ 110 - 2
gameplay/src/AnimationTarget.h

@@ -23,6 +23,100 @@ class AnimationTarget
 
 public:
 
+    /**
+     * Creates an animation on this target from a set of key value and key time pairs. 
+     * Cannot use Curve::BEZIER or CURVE::HERMITE as the interpolation type since they require tangents/control points.
+     * 
+     * @param id The ID of the animation.
+     * @param target The animation target.
+     * @param propertyId The property on this target to animate.
+     * @param keyCount The number of keyframes in the animation. Must be greater than one.
+     * @param keyTimes The list of key times for the animation (in milliseconds).
+     * @param keyValues The list of key values for the animation.
+     * @param type The curve interpolation type.
+     *
+     * @return The newly created animation.
+     */
+    Animation* createAnimation(const char* id, int propertyId, unsigned int keyCount, unsigned long* keyTimes, float* keyValues, Curve::InterpolationType type);
+
+    /**
+     * Creates an animation on this target from a set of key value and key time pairs.
+     * 
+     * @param id The ID of the animation.
+     * @param target The animation target.
+     * @param propertyId The property on this target to animate.
+     * @param keyCount The number of keyframes in the animation. Must be greater than one.
+     * @param keyTimes The list of key times for the animation (in milliseconds).
+     * @param keyValues The list of key values for the animation.
+     * @param keyInValue The list of key in values for the animation.
+     * @param keyOutValue The list of key out values for the animation.
+     * @param type The curve interpolation type.
+     *
+     * @return The newly created animation.
+     */
+    Animation* createAnimation(const char* id, int propertyId, unsigned int keyCount, unsigned long* keyTimes, float* keyValues, float* keyInValue, float* keyOutValue, Curve::InterpolationType type);
+
+    /**
+     * Creates an animation on this target using the data from the given properties object. 
+     * 
+     * @param id The ID of the animation.
+     * @param target The animation target.
+     * @param animationFile The animation file defining the animation data.
+     *
+     * @return The newly created animation.
+     */
+    Animation* createAnimation(const char* id, const char* animationFile);
+
+    /**
+     * Creates an animation on this target using the data from the given properties object. 
+     * 
+     * @param id The ID of the animation.
+     * @param target The animation target.
+     * @param properties The properties object defining the animation data.
+     *
+     * @return The newly created animation.
+     */
+    Animation* createAnimation(const char* id, Properties* animationProperties);
+
+    /**
+     * Creates a simple two keyframe from-to animation.
+     * Cannot use Curve::BEZIER or CURVE::HERMITE as the interpolation type since they require tangents/control points.
+     *
+     * @param id The ID of the animation.
+     * @param target The animation target.
+     * @param propertyId The property on this target to animate.
+     * @param from The values to animate from.
+     * @param to The values to animate to.
+     * @param type The curve interpolation type.
+     * @param duration The duration of the animation (in milliseconds).
+     *
+     * @return The newly created animation.
+     */
+    Animation* createAnimationFromTo(const char* id, int propertyId, float* from, float* to, Curve::InterpolationType type, unsigned long duration);
+
+    /**
+     * Creates a simple two keyframe from-by animation.
+     * Cannot use Curve::BEZIER or CURVE::HERMITE as the interpolation type since they require tangents/control points.
+     *
+     * @param id The ID of the animation.
+     * @param target The animation target.
+     * @param propertyId The property on this target to animate.
+     * @param from The values to animate from.
+     * @param by The values to animate by.
+     * @param type The curve interpolation type.
+     * @param duration The duration of the animation (in milliseconds).
+     *
+     * @return The newly created animation.
+     */
+    Animation* createAnimationFromBy(const char* id, int propertyId, float* from, float* by, Curve::InterpolationType type, unsigned long duration);
+
+    /**
+     * Destroys the animation with the specified ID. Destroys the first animation if ID is NULL.
+     *
+     * @param The animation to destroy.
+     */ 
+    void destroyAnimation(const char* id = NULL);
+
     /**
      * Abstract method to return the property component count of the given property ID on the AnimationTarget.
      * 
@@ -49,6 +143,13 @@ public:
      */
     virtual void setAnimationPropertyValue(int propertyId, AnimationValue* value, float blendWeight = 1.0f) = 0;
 
+    /** 
+     * Gets the animation with the specified ID. If the ID is NULL, this function will return the first animation it finds.
+     *
+     * @param id The name of the animation to get.
+     */
+    Animation* getAnimation(const char* id = NULL) const;
+
 protected:
     
     enum TargetType
@@ -75,11 +176,18 @@ protected:
     void addChannel(Animation::Channel* channel);
 
     /**
-     * Deletes the given animation channel from this animation target.
+     * Removes the given animation channel from this animation target.
      * 
      * @param channel The animation channel to delete.
      */
-    void deleteChannel(Animation::Channel* channel);
+    void removeChannel(Animation::Channel* channel);
+
+    /**
+     * Gets the Animation::Channel that belongs to the Animation with the specified ID.
+     *
+     * @param id The ID of the Animation the Channel belongs to.
+     */
+    Animation::Channel* getChannel(const char* id) const;
 
     /**
      * Copies data from this animation target into the given target for the purpose of cloning.

+ 1 - 1
gameplay/src/Button.cpp

@@ -14,7 +14,7 @@ namespace gameplay
     Button* Button::create(Theme::Style* style, Properties* properties)
     {
         Button* button = new Button();
-        button->init(style, properties);
+        button->initialize(style, properties);
 
         return button;
     }

+ 10 - 4
gameplay/src/Button.h

@@ -28,6 +28,16 @@ class Button : public Label
 
 protected:
 
+    /**
+     * Constructor.
+     */
+    Button();
+
+    /**
+     * Destructor.
+     */
+    virtual ~Button();
+
     /**
      * Create a button with a given style and properties.
      *
@@ -52,10 +62,6 @@ protected:
      */
     bool touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex);
 
-    Button();
-
-    virtual ~Button();
-
 private:
 
     Button(const Button& copy);

+ 1 - 1
gameplay/src/CheckBox.cpp

@@ -22,7 +22,7 @@ CheckBox::~CheckBox()
 CheckBox* CheckBox::create(Theme::Style* style, Properties* properties)
 {
     CheckBox* checkBox = new CheckBox();
-    checkBox->init(style, properties);
+    checkBox->initialize(style, properties);
     properties->getVector2("iconSize", &checkBox->_imageSize);
     checkBox->_checked = properties->getBool("checked");
 

+ 11 - 3
gameplay/src/CheckBox.h

@@ -29,6 +29,7 @@ class CheckBox : public Button
     friend class Container;
 
 public:
+
     /**
      * Gets whether this checkbox is checked.
      *
@@ -63,10 +64,16 @@ public:
      */
     virtual void addListener(Control::Listener* listener, int eventFlags);
 
-  //  virtual void animationEvent(AnimationClip* clip, EventType type);
-
 protected:
+
+    /**
+     * Constructor.
+     */
     CheckBox();
+
+    /**
+     * Destructor.
+     */
     ~CheckBox();
 
     /**
@@ -97,7 +104,7 @@ protected:
      * Called when a control's properties change.  Updates this control's internal rendering
      * properties, such as its text viewport.
      *
-     * @param position The control's position within its container.
+     * @param clip The clipping rectangle of this control's parent container.
      */
     void update(const Rectangle& clip);
 
@@ -113,6 +120,7 @@ protected:
     Vector2 _imageSize;  // The size to draw the checkbox icon, if different from its size in the texture.
 
 private:
+
     CheckBox(const CheckBox& copy);
 };
 

+ 25 - 1
gameplay/src/Container.cpp

@@ -56,7 +56,7 @@ namespace gameplay
     {
         const char* layoutString = properties->getString("layout");
         Container* container = Container::create(getLayoutType(layoutString));
-        container->init(style, properties);
+        container->initialize(style, properties);
         container->addControls(theme, properties);
 
         return container;
@@ -202,6 +202,30 @@ namespace gameplay
         return _controls;
     }
 
+    Animation* Container::getAnimation(const char* id) const
+    {
+        std::vector<Control*>::const_iterator itr = _controls.begin();
+        std::vector<Control*>::const_iterator end = _controls.end();
+        
+        Control* control = NULL;
+        for (; itr != end; itr++)
+        {
+            control = *itr;
+            Animation* animation = control->getAnimation(id);
+            if (animation)
+                return animation;
+
+            if (control->isContainer())
+            {
+                animation = ((Container*)control)->getAnimation(id);
+                if (animation)
+                    return animation;
+            }
+        }
+
+        return NULL;
+    }
+
     void Container::update(const Rectangle& clip)
     {
         // Update this container's viewport.

+ 14 - 0
gameplay/src/Container.h

@@ -104,10 +104,24 @@ public:
      */
     std::vector<Control*> getControls() const;
 
+    /**
+     * Gets the first animation in the control with the specified ID.
+     *
+     * @param id The ID of the animation to get. Returns the first animation if ID is NULL.
+     * @return The first animation with the specified ID.
+     */
+    Animation* getAnimation(const char* id = NULL) const;
+
 protected:
 
+    /**
+     * Constructor.
+     */
     Container();
 
+    /**
+     * Destructor.
+     */
     virtual ~Container();
 
     /**

+ 3 - 3
gameplay/src/Control.cpp

@@ -32,7 +32,7 @@ namespace gameplay
         }
     }
 
-    void Control::init(Theme::Style* style, Properties* properties)
+    void Control::initialize(Theme::Style* style, Properties* properties)
     {
         _style = style;
 
@@ -42,7 +42,7 @@ namespace gameplay
         properties->getVector2("size", &size);
         _bounds.set(position.x, position.y, size.x, size.y);
 
-        _state = Control::getStateFromString(properties->getString("state"));
+        _state = Control::getState(properties->getString("state"));
 
         const char* id = properties->getId();
         if (id)
@@ -696,7 +696,7 @@ namespace gameplay
         return false;
     }
 
-    Control::State Control::getStateFromString(const char* state)
+    Control::State Control::getState(const char* state)
     {
         if (!state)
         {

+ 39 - 23
gameplay/src/Control.h

@@ -25,6 +25,7 @@ class Control : public Ref, public AnimationTarget
     friend class VerticalLayout;
 
 public:
+
     /**
      * The possible states a control can be in.
      */
@@ -57,6 +58,10 @@ public:
      */
     static const unsigned char STATE_ALL = NORMAL | FOCUS | ACTIVE | DISABLED;
 
+    /**
+     * Implement Control::Listener and call Control::addListener()
+     * in order to listen for events on controls.
+     */
     class Listener
     {
     public:
@@ -201,7 +206,6 @@ public:
      */
     float getHeight() const;
 
-    // Themed properties.
     /**
      * Set the size of this control's border.
      *
@@ -489,7 +493,6 @@ public:
      * @param opacity The new opacity.
      * @param states The states to set this property on.
      *               One or more members of the Control::State enum, ORed together.
-     * @param duration The duration to animate opacity by.
      */
     void setOpacity(float opacity, unsigned char states = STATE_ALL);
 
@@ -502,10 +505,6 @@ public:
      */
     float getOpacity(State state = NORMAL) const;
 
-    // TODO
-    // Controls must state the names of the images they use, for the purposes of a future UI editor.
-    //virtual std::vector<std::string> getImageNames() = 0;
-
     /**
      * Get the bounds of this control, relative to its parent container, after clipping.
      *
@@ -608,7 +607,15 @@ public:
     void setAnimationPropertyValue(int propertyId, AnimationValue* value, float blendWeight = 1.0f);
 
 protected:
+
+    /**
+     * Constructor.
+     */
     Control();
+
+    /**
+     * Destructor.
+     */
     virtual ~Control();
 
     /**
@@ -652,16 +659,6 @@ protected:
      */
     virtual void update(const Rectangle& clip);
 
-private:
-    /**
-     * Draws the themed border and background of a control.
-     *
-     * @param spriteBatch The sprite batch containing this control's border images.
-     * @param clip The clipping rectangle of this control's parent container.
-     */
-    virtual void drawBorder(SpriteBatch* spriteBatch, const Rectangle& clip);
-
-protected:
     /**
      * Draw the images associated with this control.
      *
@@ -680,30 +677,38 @@ protected:
     /**
      * Initialize properties common to STATE_ALL Controls.
      */
-    virtual void init(Theme::Style* style, Properties* properties);
+    virtual void initialize(Theme::Style* style, Properties* properties);
 
     /**
      * Container and classes that extend it should implement this and return true.
+     *
+     * @return true if this object is of class Container, false otherwise.
      */
     virtual bool isContainer();
 
     /**
      * Returns whether this control has been modified and requires an update.
+     *
+     * @return Whether this control has been modified and requires an update.
      */
     virtual bool isDirty();
 
     /**
      * Get a Control::State enum from a matching string.
+     *
+     * @param state The string to match.
+     *
+     * @return The Control::State enum that matches the given string.
      */
-    static State getStateFromString(const char* state);
+    static State getState(const char* state);
 
     /**
-     * Notify STATE_ALL listeners of a specific event.
+     * Notify this control's listeners of a specific event.
+     *
+     * @param eventType The event to trigger.
      */
     void notifyListeners(Listener::EventType eventType);
 
-    void addSpecificListener(Control::Listener* listener, Listener::EventType eventType);
-
     std::string _id;
     State _state;           // Determines overlay used during draw().
     Rectangle _bounds;      // Position, relative to parent container's clipping window, and desired size.
@@ -716,6 +721,7 @@ protected:
     std::map<Listener::EventType, std::list<Listener*>*>* _listeners;
 
 private:
+
     // Animation blending bits.
     static const char ANIMATION_POSITION_X_BIT = 0x01;
     static const char ANIMATION_POSITION_Y_BIT = 0x02;
@@ -731,6 +737,18 @@ private:
     void applyAnimationValueSizeHeight(float height, float blendWeight);
     void applyAnimationValueOpacity();
 
+    Control(const Control& copy);
+
+    /**
+     * Draws the themed border and background of a control.
+     *
+     * @param spriteBatch The sprite batch containing this control's border images.
+     * @param clip The clipping rectangle of this control's parent container.
+     */
+    virtual void drawBorder(SpriteBatch* spriteBatch, const Rectangle& clip);
+
+    void addSpecificListener(Control::Listener* listener, Listener::EventType eventType);
+
     // Gets the overlays requested in the overlayTypes bitflag.
     Theme::Style::Overlay** getOverlays(unsigned char overlayTypes, Theme::Style::Overlay** overlays);
 
@@ -741,8 +759,6 @@ private:
 
     // Ensures that this control has a copy of its style so that it can override it without affecting other controls.
     void overrideStyle();
-
-    Control(const Control& copy);
 };
 
 }

+ 2 - 1
gameplay/src/Curve.cpp

@@ -151,8 +151,9 @@ void Curve::evaluate(float time, float* dst) const
 {
     assert(dst && time >= 0 && time <= 1.0f);
 
+    // Check if the point count is 1.
     // Check if we are at or beyond the bounds of the curve.
-    if (time <= _points[0].time)
+    if (_pointCount == 1 || time <= _points[0].time)
     {
         memcpy(dst, _points[0].value, _componentSize);
         return;

+ 1 - 0
gameplay/src/Curve.h

@@ -11,6 +11,7 @@ namespace gameplay
  */
 class Curve : public Ref
 {
+    friend class AnimationTarget;
     friend class Animation;
     friend class AnimationClip;
     friend class AnimationController;

+ 11 - 17
gameplay/src/Form.cpp

@@ -58,24 +58,9 @@ namespace gameplay
         // Create new form with given ID, theme and layout.
         const char* themeFile = formProperties->getString("theme");
         const char* layoutString = formProperties->getString("layout");
-        Form* form = Form::create(themeFile, getLayoutType(layoutString));
-
-        Theme* theme = form->_theme;
-        const char* styleName = formProperties->getString("style");
-        form->init(theme->getStyle(styleName), formProperties);
-
-        // Add all the controls to the form.
-        form->addControls(theme, formProperties);
-
-        SAFE_DELETE(properties);
-
-        return form;
-    }
-
-    Form* Form::create(const char* themeFile, Layout::Type type)
-    {
+        
         Layout* layout;
-        switch (type)
+        switch (getLayoutType(layoutString))
         {
         case Layout::LAYOUT_ABSOLUTE:
             layout = AbsoluteLayout::create();
@@ -95,6 +80,15 @@ namespace gameplay
         form->_layout = layout;
         form->_theme = theme;
 
+        //Theme* theme = form->_theme;
+        const char* styleName = formProperties->getString("style");
+        form->initialize(theme->getStyle(styleName), formProperties);
+
+        // Add all the controls to the form.
+        form->addControls(theme, formProperties);
+
+        SAFE_DELETE(properties);
+
         __forms.push_back(form);
 
         return form;

+ 19 - 14
gameplay/src/Form.h

@@ -37,13 +37,13 @@ public:
      *      size     = <width, height>      // Size of the form, measured in pixels.
      *   
      *      // All the controls within this form.
-     *      container{}
-     *      label{}
-     *      textBox{}
-     *      button{}
-     *      checkBox{}
-     *      radioButton{}
-     *      slider{}
+     *      container { }
+     *      label { }
+     *      textBox { }
+     *      button { }
+     *      checkBox { }
+     *      radioButton { }
+     *      slider { }
      * }
      *
      * @param path Path to the properties file to create a new form from.
@@ -105,13 +105,22 @@ public:
      */
     void draw();
 
-protected:
+private:
     
+    /**
+     * Constructor.
+     */
     Form();
 
-    virtual ~Form();
+    /**
+     * Constructor.
+     */
+    Form(const Form& copy);
 
-    static Form* create(const char* textureFile, Layout::Type type);
+    /**
+     * Destructor.
+     */
+    virtual ~Form();
 
     /**
      * Initialize a quad for this form in order to draw it in 3D.
@@ -145,10 +154,6 @@ protected:
     Node* _node;                // Node for transforming this Form in world-space.
     FrameBuffer* _frameBuffer;  // FBO the Form is rendered into for texturing the quad.
     Matrix _projectionMatrix;   // Orthographic projection matrix to be set on SpriteBatch objects when rendering into the FBO.
-
-private:
-
-    Form(const Form& copy);
 };
 
 }

+ 3 - 3
gameplay/src/Label.cpp

@@ -18,14 +18,14 @@ namespace gameplay
     Label* Label::create(Theme::Style* style, Properties* properties)
     {
         Label* label = new Label();
-        label->init(style, properties);
+        label->initialize(style, properties);
 
         return label;
     }
 
-    void Label::init(Theme::Style* style, Properties* properties)
+    void Label::initialize(Theme::Style* style, Properties* properties)
     {
-        Control::init(style, properties);
+        Control::initialize(style, properties);
 
         const char* text = properties->getString("text");
         if (text)

+ 11 - 1
gameplay/src/Label.h

@@ -25,6 +25,7 @@ class Label : public Control
     friend class Container;
 
 public:
+
     /**
      * Set the text for this label to display.
      *
@@ -52,7 +53,15 @@ public:
     virtual void addListener(Control::Listener* listener, int eventFlags);
 
 protected:
+
+    /**
+     * Constructor.
+     */
     Label();
+
+    /**
+     * Destructor.
+     */
     virtual ~Label();
 
     /**
@@ -68,7 +77,7 @@ protected:
     /**
      * Initialize this label.
      */
-    virtual void init(Theme::Style* style, Properties* properties);
+    virtual void initialize(Theme::Style* style, Properties* properties);
 
     /**
      * Draw this label's text.
@@ -80,6 +89,7 @@ protected:
     std::string _text;      // The text displayed by this label.
 
 private:
+
     Label(const Label& copy);
 };
 

+ 1 - 0
gameplay/src/Material.h

@@ -23,6 +23,7 @@ class Material : public RenderState
     friend class Technique;
     friend class Pass;
     friend class RenderState;
+    friend class Node;
 
 public:
 

+ 63 - 0
gameplay/src/Node.cpp

@@ -594,6 +594,69 @@ void Node::setBoundsDirty()
         _parent->setBoundsDirty();
 }
 
+Animation* Node::getAnimation(const char* id) const
+{
+    Animation* animation = ((AnimationTarget*)this)->getAnimation(id);
+    if (animation)
+        return animation;
+    
+    // See if this node has a model, then drill down.
+    Model* model = this->getModel();
+    if (model)
+    {
+        // Check to see if there's any animations with the ID on the joints.
+        MeshSkin* skin = model->getSkin();
+        if (skin)
+        {
+            Joint* rootJoint = skin->getRootJoint();
+            if (rootJoint)
+            {
+                animation = rootJoint->getAnimation(id);
+                if (animation)
+                    return animation;
+            }
+        }
+
+        // Check to see if any of the model's material parameter's has an animation
+        // with the given ID.
+        Material* material = model->getMaterial();
+        if (material)
+        {
+            // How to access material parameters? hidden on the Material::RenderState.
+            std::vector<MaterialParameter*>::iterator itr = material->_parameters.begin();
+            for (; itr != material->_parameters.end(); itr++)
+            {
+                animation = ((MaterialParameter*)(*itr))->getAnimation(id);
+                if (animation)
+                    return animation;
+            }
+        }
+    }
+
+    // look through form for animations.
+    Form* form = this->getForm();
+    if (form)
+    {
+        animation = form->getAnimation(id);
+        if (animation)
+            return animation;
+    }
+
+    // Look through this node's children for an animation with the specified ID.
+    unsigned int childCount = this->getChildCount();
+    Node* child = this->getFirstChild();
+    for (unsigned int i = 0; i < childCount; i++)
+    {
+        animation = child->getAnimation(id);
+        if (animation)
+            return animation;
+
+        child = child->getNextSibling();
+    }
+    
+    return NULL;
+}
+
 Camera* Node::getCamera() const
 {
     return _camera;

+ 8 - 0
gameplay/src/Node.h

@@ -343,6 +343,14 @@ public:
      */
     Vector3 getActiveCameraTranslationView() const;
 
+    /**
+     * Gets the first animation in the node hierarchy with the specified ID.
+     *
+     * @param id The ID of the animation to get. Returns the first animation if ID is NULL.
+     * @return The first animation with the specified ID.
+     */
+    Animation* getAnimation(const char* id = NULL) const;
+
     /**
      * Returns the pointer to this node's camera.
      *

+ 2 - 1
gameplay/src/Package.cpp

@@ -964,11 +964,12 @@ Animation* Package::readAnimationChannel(Scene* scene, Animation* animation, con
         if (animation == NULL)
         {
             // TODO: This code currently assumes LINEAR only
-            animation = controller->createAnimation(animationId, target, targetAttribute, keyTimesCount, &keyTimes[0], &values[0], Curve::LINEAR);
+            animation = target->createAnimation(animationId, targetAttribute, keyTimesCount, &keyTimes[0], &values[0], Curve::LINEAR);
         }
         else
         {
             animation->createChannel(target, targetAttribute, keyTimesCount, &keyTimes[0], &values[0], Curve::LINEAR);
+            animation->addRef();
         }
     }
 

+ 2 - 2
gameplay/src/PlatformQNX.cpp

@@ -962,7 +962,7 @@ int Platform::enterMessagePump()
                     _game->menu();
                     break;
                 case NAVIGATOR_EXIT:
-                    _game->exit();
+                    _game->end();
                     break;
                 }
             }
@@ -990,7 +990,7 @@ int Platform::enterMessagePump()
         rc = eglSwapBuffers(__eglDisplay, __eglSurface);
         if (rc != EGL_TRUE)
         {
-            _game->exit();
+            _game->end();
             perror("eglSwapBuffers");
             break;
         }

+ 1 - 1
gameplay/src/PlatformWin32.cpp

@@ -589,7 +589,7 @@ int Platform::enterMessagePump()
 
             if (msg.message == WM_QUIT)
             {
-                _game->exit();
+                _game->end();
                 break;
             }
         }

+ 1 - 1
gameplay/src/RadioButton.cpp

@@ -27,7 +27,7 @@ RadioButton::~RadioButton()
 RadioButton* RadioButton::create(Theme::Style* style, Properties* properties)
 {
     RadioButton* radioButton = new RadioButton();
-    radioButton->init(style, properties);
+    radioButton->initialize(style, properties);
 
     properties->getVector2("imageSize", &radioButton->_imageSize);
 

+ 38 - 1
gameplay/src/RadioButton.h

@@ -66,7 +66,15 @@ public:
     virtual void addListener(Control::Listener* listener, int eventFlags);
 
 protected:
+
+    /**
+     * Constructor.
+     */
     RadioButton();
+
+    /**
+     * Destructor.
+     */
     virtual ~RadioButton();
 
     /**
@@ -79,13 +87,41 @@ protected:
      */
     static RadioButton* create(Theme::Style* style, Properties* properties);
 
+    /**
+     * Touch callback on touch events.  Controls return true if they consume the touch event.
+     *
+     * @param evt The touch event that occurred.
+     * @param x The x position of the touch in pixels. Left edge is zero.
+     * @param y The y position of the touch in pixels. Top edge is zero.
+     * @param contactIndex The order of occurrence for multiple touch contacts starting at zero.
+     *
+     * @return Whether the touch event was consumed by the control.
+     *
+     * @see Touch::TouchEvent
+     */
     bool touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex);
 
+    /**
+     * Called when a control's properties change.  Updates this control's internal rendering
+     * properties, such as its text viewport.
+     *
+     * @param clip The clipping rectangle of this control's parent container.
+     */
     void update(const Rectangle& clip);
 
+    /**
+     * Draw the images associated with this control.
+     *
+     * @param spriteBatch The sprite batch containing this control's icons.
+     * @param clip The clipping rectangle of this control's parent container.
+     */
     void drawImages(SpriteBatch* spriteBatch, const Rectangle& clip);
 
-    // Clear the _selected flag of all radio buttons in the given group.
+    /**
+     * Clear the _selected flag of all radio buttons in the given group.
+     *
+     * @param groupID The group to clear.
+     */
     static void clearSelected(const std::string& groupId);
 
     std::string _groupId;
@@ -93,6 +129,7 @@ protected:
     Vector2 _imageSize;
 
 private:
+
     RadioButton(const RadioButton& copy);
 };
 

+ 1 - 1
gameplay/src/SceneLoader.cpp

@@ -668,7 +668,7 @@ void SceneLoader::createAnimations(const Scene* scene)
             }
         }
 
-        Game::getInstance()->getAnimationController()->createAnimation(_animations[i]._animationID, node, p);
+        node->createAnimation(_animations[i]._animationID, p);
     }
 }
 

+ 1 - 1
gameplay/src/Slider.cpp

@@ -14,7 +14,7 @@ Slider::~Slider()
 Slider* Slider::create(Theme::Style* style, Properties* properties)
 {
     Slider* slider = new Slider();
-    slider->init(style, properties);
+    slider->initialize(style, properties);
 
     slider->_min = properties->getFloat("min");
     slider->_max = properties->getFloat("max");

+ 46 - 0
gameplay/src/Slider.h

@@ -32,6 +32,7 @@ class Slider : public Label
     friend class Container;
 
 public:
+
     /**
      * Set the minimum value that can be set on this slider.
      *
@@ -90,16 +91,60 @@ public:
      */
     float getValue();
 
+    /**
+     * Add a listener to be notified of specific events affecting
+     * this control.  Event types can be OR'ed together.
+     * E.g. To listen to touch-press and touch-release events,
+     * pass <code>Control::Listener::TOUCH | Control::Listener::RELEASE</code>
+     * as the second parameter.
+     *
+     * @param listener The listener to add.
+     * @param eventFlags The events to listen for.
+     */
     void addListener(Control::Listener* listener, int eventFlags);
 
 protected:
+
+    /**
+     * Constructor.
+     */
     Slider();
+
+    /**
+     * Destructor.
+     */
     ~Slider();
 
+    /**
+     * Create a slider with a given style and properties.
+     *
+     * @param style The style to apply to this slider.
+     * @param properties The properties to set on this slider.
+     *
+     * @return The new slider.
+     */
     static Slider* create(Theme::Style* style, Properties* properties);
 
+    /**
+     * Touch callback on touch events.  Controls return true if they consume the touch event.
+     *
+     * @param evt The touch event that occurred.
+     * @param x The x position of the touch in pixels. Left edge is zero.
+     * @param y The y position of the touch in pixels. Top edge is zero.
+     * @param contactIndex The order of occurrence for multiple touch contacts starting at zero.
+     *
+     * @return Whether the touch event was consumed by the control.
+     *
+     * @see Touch::TouchEvent
+     */
     bool touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex);
 
+    /**
+     * Draw the images associated with this control.
+     *
+     * @param spriteBatch The sprite batch containing this control's icons.
+     * @param clip The clipping rectangle of this control's parent container.
+     */
     void drawImages(SpriteBatch* spriteBatch, const Rectangle& clip);
 
     float _min;
@@ -108,6 +153,7 @@ protected:
     float _value;
 
 private:
+
     Slider(const Slider& copy);
 };
 

+ 28 - 28
gameplay/src/TextBox.cpp

@@ -19,7 +19,7 @@ TextBox::~TextBox()
 TextBox* TextBox::create(Theme::Style* style, Properties* properties)
 {
     TextBox* textBox = new TextBox();
-    textBox->init(style, properties);
+    textBox->initialize(style, properties);
 
     return textBox;
 }
@@ -29,15 +29,6 @@ int TextBox::getLastKeypress()
     return _lastKeypress;
 }
 
-void TextBox::setCursorLocation(int x, int y)
-{
-    Theme::Border border = getBorder(_state);
-    Theme::Padding padding = getPadding();
-
-    _cursorLocation.set(x - border.left - padding.left + _clip.x,
-                       y - border.top - padding.top + _clip.y);
-}
-
 void TextBox::addListener(Control::Listener* listener, int eventFlags)
 {
     if ((eventFlags & Listener::VALUE_CHANGED) == Listener::VALUE_CHANGED)
@@ -80,7 +71,7 @@ bool TextBox::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int conta
             x > 0 && x <= _clipBounds.width &&
             y > 0 && y <= _clipBounds.height)
         {
-            setCursorLocation(x, y);
+            setCaretLocation(x, y);
             _dirty = true;
             return _consumeTouchEvents;
         }
@@ -89,7 +80,7 @@ bool TextBox::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int conta
         if (x > 0 && x <= _clipBounds.width &&
             y > 0 && y <= _clipBounds.height)
         {
-            setCursorLocation(x, y);
+            setCaretLocation(x, y);
             _state = FOCUS;
             _dirty = true;
             return _consumeTouchEvents;
@@ -115,7 +106,7 @@ void TextBox::keyEvent(Keyboard::KeyEvent evt, int key)
                         // TODO: Move cursor to beginning of line.
                         // This only works for left alignment...
                         
-                        //_cursorLocation.x = _clip.x;
+                        //_caretLocation.x = _clip.x;
                         //_dirty = true;
                         break;
                     }
@@ -131,10 +122,10 @@ void TextBox::keyEvent(Keyboard::KeyEvent evt, int key)
                         Font::Justify textAlignment = getTextAlignment(_state);
                         bool rightToLeft = getTextRightToLeft(_state);
 
-                        unsigned int textIndex = font->getIndexAtLocation(_text.c_str(), _clip, fontSize, _cursorLocation, &_cursorLocation,
+                        unsigned int textIndex = font->getIndexAtLocation(_text.c_str(), _clip, fontSize, _caretLocation, &_caretLocation,
                             textAlignment, true, rightToLeft);
                         _text.erase(textIndex, 1);
-                        font->getLocationAtIndex(_text.c_str(), _clip, fontSize, &_cursorLocation, textIndex,
+                        font->getLocationAtIndex(_text.c_str(), _clip, fontSize, &_caretLocation, textIndex,
                             textAlignment, true, rightToLeft);
                         _dirty = true;
                         notifyListeners(Listener::TEXT_CHANGED);
@@ -147,9 +138,9 @@ void TextBox::keyEvent(Keyboard::KeyEvent evt, int key)
                         Font::Justify textAlignment = getTextAlignment(_state);
                         bool rightToLeft = getTextRightToLeft(_state);
 
-                        unsigned int textIndex = font->getIndexAtLocation(_text.c_str(), _clip, fontSize, _cursorLocation, &_cursorLocation,
+                        unsigned int textIndex = font->getIndexAtLocation(_text.c_str(), _clip, fontSize, _caretLocation, &_caretLocation,
                             textAlignment, true, rightToLeft);
-                        font->getLocationAtIndex(_text.c_str(), _clip, fontSize, &_cursorLocation, textIndex - 1,
+                        font->getLocationAtIndex(_text.c_str(), _clip, fontSize, &_caretLocation, textIndex - 1,
                             textAlignment, true, rightToLeft);
                         _dirty = true;
                         break;
@@ -161,9 +152,9 @@ void TextBox::keyEvent(Keyboard::KeyEvent evt, int key)
                         Font::Justify textAlignment = getTextAlignment(_state);
                         bool rightToLeft = getTextRightToLeft(_state);
 
-                        unsigned int textIndex = font->getIndexAtLocation(_text.c_str(), _clip, fontSize, _cursorLocation, &_cursorLocation,
+                        unsigned int textIndex = font->getIndexAtLocation(_text.c_str(), _clip, fontSize, _caretLocation, &_caretLocation,
                             textAlignment, true, rightToLeft);
-                        font->getLocationAtIndex(_text.c_str(), _clip, fontSize, &_cursorLocation, textIndex + 1,
+                        font->getLocationAtIndex(_text.c_str(), _clip, fontSize, &_caretLocation, textIndex + 1,
                             textAlignment, true, rightToLeft);
                         _dirty = true;
                         break;
@@ -175,8 +166,8 @@ void TextBox::keyEvent(Keyboard::KeyEvent evt, int key)
                         Font::Justify textAlignment = getTextAlignment(_state);
                         bool rightToLeft = getTextRightToLeft(_state);
 
-                        _cursorLocation.y -= fontSize;
-                        font->getIndexAtLocation(_text.c_str(), _clip, fontSize, _cursorLocation, &_cursorLocation,
+                        _caretLocation.y -= fontSize;
+                        font->getIndexAtLocation(_text.c_str(), _clip, fontSize, _caretLocation, &_caretLocation,
                             textAlignment, true, rightToLeft);
                         _dirty = true;
                         break;
@@ -188,8 +179,8 @@ void TextBox::keyEvent(Keyboard::KeyEvent evt, int key)
                         Font::Justify textAlignment = getTextAlignment(_state);
                         bool rightToLeft = getTextRightToLeft(_state);
 
-                        _cursorLocation.y += fontSize;
-                        font->getIndexAtLocation(_text.c_str(), _clip, fontSize, _cursorLocation, &_cursorLocation,
+                        _caretLocation.y += fontSize;
+                        font->getIndexAtLocation(_text.c_str(), _clip, fontSize, _caretLocation, &_caretLocation,
                             textAlignment, true, rightToLeft);
                         _dirty = true;
                         break;
@@ -205,7 +196,7 @@ void TextBox::keyEvent(Keyboard::KeyEvent evt, int key)
                 Font::Justify textAlignment = getTextAlignment(_state);
                 bool rightToLeft = getTextRightToLeft(_state);
 
-                unsigned int textIndex = font->getIndexAtLocation(_text.c_str(), _clip, fontSize, _cursorLocation, &_cursorLocation,
+                unsigned int textIndex = font->getIndexAtLocation(_text.c_str(), _clip, fontSize, _caretLocation, &_caretLocation,
                     textAlignment, true, rightToLeft);
 
                 switch (key)
@@ -216,7 +207,7 @@ void TextBox::keyEvent(Keyboard::KeyEvent evt, int key)
                         {
                             --textIndex;
                             _text.erase(textIndex, 1);
-                            font->getLocationAtIndex(_text.c_str(), _clip, fontSize, &_cursorLocation, textIndex,
+                            font->getLocationAtIndex(_text.c_str(), _clip, fontSize, &_caretLocation, textIndex,
                                 textAlignment, true, rightToLeft);
 
                             _dirty = true;
@@ -232,7 +223,7 @@ void TextBox::keyEvent(Keyboard::KeyEvent evt, int key)
                         _text.insert(textIndex, 1, (char)key);
 
                         // Get new location of cursor.
-                        font->getLocationAtIndex(_text.c_str(), _clip, fontSize, &_cursorLocation, textIndex + 1,
+                        font->getLocationAtIndex(_text.c_str(), _clip, fontSize, &_caretLocation, textIndex + 1,
                             textAlignment, true, rightToLeft);
                 
                         _dirty = true;
@@ -262,7 +253,7 @@ void TextBox::update(const Rectangle& clip)
         Font::Justify textAlignment = getTextAlignment(_state);
         bool rightToLeft = getTextRightToLeft(_state);
 
-        font->getIndexAtLocation(_text.c_str(), _clip, fontSize, _cursorLocation, &_cursorLocation,
+        font->getIndexAtLocation(_text.c_str(), _clip, fontSize, _caretLocation, &_caretLocation,
             textAlignment, true, rightToLeft);
     }
 }
@@ -279,11 +270,20 @@ void TextBox::drawImages(SpriteBatch* spriteBatch, const Rectangle& clip)
             const Theme::UVs uvs = getImageUVs("textCaret", _state);
             unsigned int fontSize = getFontSize(_state);
 
-            spriteBatch->draw(_cursorLocation.x - (region.width / 2.0f), _cursorLocation.y, region.width, fontSize, uvs.u1, uvs.v1, uvs.u2, uvs.v2, color);
+            spriteBatch->draw(_caretLocation.x - (region.width / 2.0f), _caretLocation.y, region.width, fontSize, uvs.u1, uvs.v1, uvs.u2, uvs.v2, color);
         }
     }
 
     _dirty = false;
 }
 
+void TextBox::setCaretLocation(int x, int y)
+{
+    Theme::Border border = getBorder(_state);
+    Theme::Padding padding = getPadding();
+
+    _caretLocation.set(x - border.left - padding.left + _clip.x,
+                       y - border.top - padding.top + _clip.y);
+}
+
 }

+ 60 - 4
gameplay/src/TextBox.h

@@ -31,6 +31,7 @@ class TextBox : public Label
     friend class Container;
 
 public:
+
     /**
      * Add a listener to be notified of specific events affecting
      * this control.  Event types can be OR'ed together.
@@ -43,31 +44,86 @@ public:
      */
     virtual void addListener(Control::Listener* listener, int eventFlags);
 
+    /**
+     * Get the last key pressed within this text box.
+     *
+     * @return The last key pressed within this text box.
+     */
     int getLastKeypress();
 
 protected:
+
+    /**
+     * Constructor.
+     */
     TextBox();
+
+    /**
+     * Destructor.
+     */
     ~TextBox();
 
+    /**
+     * Create a text box with a given style and properties.
+     *
+     * @param style The style to apply to this text box.
+     * @param properties The properties to set on this text box.
+     *
+     * @return The new text box.
+     */
     static TextBox* create(Theme::Style* style, Properties* properties);
 
-    void setCursorLocation(int x, int y);
-
+    /**
+     * Touch callback on touch events.  Controls return true if they consume the touch event.
+     *
+     * @param evt The touch event that occurred.
+     * @param x The x position of the touch in pixels. Left edge is zero.
+     * @param y The y position of the touch in pixels. Top edge is zero.
+     * @param contactIndex The order of occurrence for multiple touch contacts starting at zero.
+     *
+     * @return Whether the touch event was consumed by the control.
+     *
+     * @see Touch::TouchEvent
+     */
     bool touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex);
 
+    /**
+     * Keyboard callback on key events.
+     *
+     * @param evt The key event that occured.
+     * @param key If evt is KEY_PRESS or KEY_RELEASE then key is the key code from Keyboard::Key.
+     *            If evt is KEY_CHAR then key is the unicode value of the character.
+     * 
+     * @see Keyboard::KeyEvent
+     * @see Keyboard::Key
+     */
     void keyEvent(Keyboard::KeyEvent evt, int key);
 
+    /**
+     * Called when a control's properties change.  Updates this control's internal rendering
+     * properties, such as its text viewport.
+     *
+     * @param clip The clipping rectangle of this control's parent container.
+     */
     void update(const Rectangle& clip);
 
-    // Draw the cursor.
+    /**
+     * Draw the images associated with this control.
+     *
+     * @param spriteBatch The sprite batch containing this control's icons.
+     * @param clip The clipping rectangle of this control's parent container.
+     */
     void drawImages(SpriteBatch* spriteBatch, const Rectangle& clip);
 
-    Vector2 _cursorLocation;
+    Vector2 _caretLocation;
     unsigned int textIndex;
     int _lastKeypress;
 
 private:
+
     TextBox(const TextBox& copy);
+
+    void setCaretLocation(int x, int y);
 };
 
 }

+ 108 - 92
gameplay/src/Theme.h

@@ -14,103 +14,119 @@ namespace gameplay
 /**
  * A theme is created and stored as part of a form and represents its appearance.
  * Once loaded, the appearance properties can be retrieved from their style IDs and set on other
- * UI controls.  A Theme has one property, 'texture', which points to an image containing
- * all the Icon, Cursor, Slider, and Skin sprites used by the theme.  Each set of sprites within
- * the texture is described in its own namespace.  The rest of the Theme consists of Style namespaces.
- * A Style describes the border, margin, and padding of a Control, what icons and cursors (if any) are
- * associated with a Control, and Font properties to apply to a Control's text.
+ * UI controls.  A Theme has one property, 'texture', which points to a texture atlas containing
+ * all the images used by the theme.  Cursor images, skins, and lists of images used by controls
+ * are defined in their own namespaces.  The rest of the Theme consists of Style namespaces.
+ * A Style describes the border, margin, and padding of a Control, what images, skins, and cursors
+ * are associated with a Control, and Font properties to apply to a Control's text.
  *
  * Below is an explanation of the properties that can be set within themes:
  *
  * theme
  * {
- *    texture = <Path to texture>
- *
- *    // Describes the images used for CheckBox and RadioButton icons.
- *    icon <iconID>
- *    {
- *        size            =   <width, height>     // Size of this icon.
- *        offPosition     =   <x, y>              // Position of the unchecked / unselected image.
- *        onPosition      =   <x, y>              // Position of the checked / selected image.
- *        color           =   <#ffffffff>         // Tint to apply to icon.
- *    }
- *   
- *    cursor <cursorID>
- *    {
- *        region  =   <x, y, width, height>   // Region within the texture of cursor sprite.
- *        color   =   <#ffffffff>             // Tint to apply to cursor.
- *    }
- *   
- *    slider <sliderID>
- *    {
- *        minCapRegion    =   <x, y, width, height>   // Left / bottom slider cap.
- *        maxCapRegion    =   <x, y, width, height>   // Right / top slider cap.
- *        markerRegion    =   <x, y, width, height>   // Shows the slider's current position.
- *        trackRegion     =   <x, y, width, height>   // Track the marker slides along.
- *        color           =   <#ffffffff>             // Tint to apply to slider sprites.
- *    }
- *   
- *    // Defines the border and background of a Control.
- *    Skin <skinID>
- *    {
- *        // The corners and edges of the given region will be used as border sprites.
- *        border
- *        {
- *            top     =   <int>   // Height of top border, top corners.
- *            bottom  =   <int>   // Height of bottom border, bottom corners.
- *            left    =   <int>   // Width of left border, left corners.
- *            right   =   <int>   // Width of right border, right corners.
- *        }
- *       
- *        region  =   <x, y, width, height>   // Total Skin region including entire border.
- *        color   =   <#ffffffff>             // Tint to apply to Skin sprites.
- *    }
- *   
- *    style <styleID>
- *    {
- *        // Layouts may make use of a style's margin to put space between adjacent controls.
- *        margin
- *        {
- *            top     =   <int>
- *            bottom  =   <int>
- *            left    =   <int>
- *            right   =   <int>        
- *        }
- *       
- *        // Padding is the space between a control's border and its content.
- *        padding
- *        {
- *            top     =   <int>
- *            bottom  =   <int>
- *            left    =   <int>
- *            right   =   <int>        
- *        }
- *       
- *        // This overlay is used when a control is enabled but not active or focused.
- *        normal
- *        {
- *            Skin   =   <SkinID>               // Skin to use for border and background sprites.
- *            checkBox    =   <iconID>                    // Icon to use for checkbox sprites.
- *            radioButton =   <iconID>                    // Icon to use for radioButton sprites.
- *            slider      =   <sliderID>                  // Slider to use for slider sprites.
- *            mouseCursor =   <cursorID>                  // Cursor to use when the mouse is over this control.
- *            textCursor  =   <cursorID>                  // Cursor to use within a textBox.
- *            font        =   <Path to font>              // Font to use for rendering text.
- *            fontSize    =   <int>                       // Size of text.
- *            textColor   =   <#ffffffff>                 // Color of text.
- *            alignment   =   <Text alignment constant>   // Member of Font::Justify enum.
- *            rightToLeft =   <bool>                      // Whether to draw text from right to left.
- *        }
- *       
- *        // This overlay is used when the control is in focus.
- *        // If not specified, the 'normal' overlay will be used.
- *        focus{}
- *       
- *        // This overlay is used when the control is active.
- *        // (Touch or mouse is down within the control.)
- *        // If not specified, the 'normal' overlay will be used.
- *        active{}
- *    }
+ *     texture = <Path to texture>
+ * 
+ *     // Describes a single image, to be used as a cursor.
+ *     cursor <Cursor ID>
+ *     {
+ *         region = <x, y, width, height>
+ *         color = <#ffffffff>
+ *     }
+ * 
+ *     // Describes all the images used by a control for one or more states.
+ *     imageList <ImageList ID>
+ *     {
+ *         image checked
+ *         {
+ *             region = <x, y, width, height>
+ *         }
+ * 
+ *         image unchecked
+ *         {
+ *             region = <x, y, width, height>
+ *             color = <#fffffffff>            // Optionally override image-list color.
+ *         }
+ * 
+ *         color = <#fffffffff>    // Default blend color for images that don't specify their own.
+ *     }
+ *     
+ *     // Defines the border and background of a Control.
+ *     skin <Skin ID>
+ *     {
+ *         // The corners and edges of the given region will be used as border sprites.
+ *         border
+ *         {
+ *             top     =   <int>   // Height of top border, top corners.
+ *             bottom  =   <int>   // Height of bottom border, bottom corners.
+ *             left    =   <int>   // Width of left border, left corners.
+ *             right   =   <int>   // Width of right border, right corners.
+ *         }
+ *         
+ *         region  =   <x, y, width, height>   // Total container region including entire border.
+ *         color   =   <#ffffffff>             // Tint to apply to skin.
+ *     }
+ *     
+ *     style <Style ID>
+ *     {
+ *         // Layouts may make use of a style's margin to put space between adjacent controls.
+ *         margin
+ *         {
+ *             top     =   <int>
+ *             bottom  =   <int>
+ *             left    =   <int>
+ *             right   =   <int>        
+ *         }
+ *         
+ *         // Padding is the space between a control's border and its content.
+ *         padding
+ *         {
+ *             top     =   <int>
+ *             bottom  =   <int>
+ *             left    =   <int>
+ *             right   =   <int>        
+ *         }
+ *         
+ *         // Properties used when in control is in the normal state.
+ *         stateNormal
+ *         {
+ *             skin   =   <Skin ID>             // Skin to use for border and background sprites.
+ *             imageList = <ImageList ID>
+ * 
+ *             cursor      =   <Cursor ID>                 // Cursor to use when the mouse is over this control.
+ *             font        =   <Path to font>              // Font to use for rendering text.
+ *             fontSize    =   <int>                       // Size of text.
+ *             textColor   =   <#ffffffff>                 // Color of text.
+ *             alignment   =   <Text alignment constant>   // Member of Font::Justify enum.
+ *             rightToLeft =   <bool>                      // Whether to draw text from right to left.
+ *             opacity     =   <float>                     // Opacity to apply to all text/border/icon colors.
+ *         }
+ *         
+ *         // Properties used when in control is in the focus state
+ *         // If not specified, the 'normal' overlay will be used.
+ *         stateFocus
+ *         {
+ *             skin   =   <Skin ID>             // Skin to use for border and background sprites.
+ *             ...
+ *         }
+ *         
+ *         // Properties used when in control is in the focus. 
+ *         // This is when a touch/mouse is down within the control.
+ *         // If not specified, the 'normal' overlay will be used.
+ *         stateActive
+ *         {
+ *             skin   =   <Skin ID>             // Skin to use for border and background sprites.
+ *             ...
+ *         }
+ * 
+ *         // Properties used when in control is in the focus. 
+ *         // This is when a touch/mouse is down within the control.
+ *         // If not specified, the 'normal' overlay will be used.
+ *         state-disabled
+ *         {
+ *             skin   =   <Skin ID>             // Skin to use for border and background sprites.
+ *             ...        
+ *         }
+ *     }
  * }
  *
  */

+ 19 - 21
gameplay/src/ThemeStyle.h

@@ -15,8 +15,8 @@ namespace gameplay
 /**
  * This class represents the appearance of a control.  A style can have padding and margin values,
  * as well as overlays for each of the control's states.  Each overlay in turn can reference
- * the above classes to determine the border, background, cursor, and icon settings to use for
- * a particular state.
+ * other theme classes to determine the border, background, cursor, and image settings to use for
+ * a particular state, as well as color and font settings, etcetera.
  */
 class Theme::Style
 {
@@ -159,6 +159,23 @@ private:
         float _opacity;
     };
 
+    /**
+     * Constructor.
+     */
+    Style(const char* id, float tw, float th,
+          const Theme::Margin& margin, const Theme::Padding& padding,
+          Overlay* normal, Overlay* focus, Overlay* active, Overlay* disabled);
+
+    /**
+     * Constructor.
+     */
+    Style(const Style& style);
+
+    /**
+     * Destructor.
+     */
+    ~Style();
+
     /**
      * Returns the Id of this Style.
      */
@@ -192,25 +209,6 @@ private:
      * The margin is used by Layouts other than AbsoluteLayout to put space between Controls.
      */
     void setMargin(float top, float bottom, float left, float right);
-
-private:
-
-    /**
-     * Constructor.
-     */
-    Style(const char* id, float tw, float th,
-          const Theme::Margin& margin, const Theme::Padding& padding,
-          Overlay* normal, Overlay* focus, Overlay* active, Overlay* disabled);
-
-    /**
-     * Constructor.
-     */
-    Style(const Style& style);
-
-    /**
-     * Destructor.
-     */
-    ~Style();
         
     std::string _id;
     float _tw;

+ 23 - 0
gameplay/src/VerticalLayout.h

@@ -17,6 +17,7 @@ class VerticalLayout : public Layout
     friend class Container;
 
 public:
+
     /**
      * Set whether this layout will start laying out controls from the bottom of the container.
      * This setting defaults to 'false', meaning controls will start at the top.
@@ -40,16 +41,38 @@ public:
     Layout::Type getType();
 
 protected:
+
+    /**
+     * Constructor.
+     */
     VerticalLayout();
+
+    /**
+     * Destructor.
+     */
     virtual ~VerticalLayout();
 
+    /**
+     * Create a VerticalLayout.
+     *
+     * @return a VerticalLayout object.
+     */
     static VerticalLayout* create();
 
+    /**
+     * Update the controls contained by the specified container.
+     *
+     * Controls are placed next to one another vertically until
+     * the bottom-most edge of the container is reached.
+     *
+     * @param container The container to update.
+     */
     void update(const Container* container);
 
     bool _bottomToTop;
 
 private:
+
     VerticalLayout(const VerticalLayout& copy);
 };