Drawable* ParticleEmitter::clone(NodeCloneContext& context)
{
    // Create a clone of this emitter
    ParticleEmitter* clone = ParticleEmitter::create(_spriteBatch->getSampler()->getTexture(),
                                                     _spriteBlendMode, _particleCountMax);
    // Clone properties
    clone->setEmissionRate(_emissionRate);
    clone->_ellipsoid = _ellipsoid;
    clone->_sizeStartMin = _sizeStartMin;
    clone->_sizeStartMax = _sizeStartMax;
    clone->_sizeEndMin = _sizeEndMin;
    clone->_sizeEndMax = _sizeEndMax;
    clone->_energyMin = _energyMin;
    clone->_energyMax = _energyMax;
    clone->_colorStart = _colorStart;
    clone->_colorStartVar = _colorStartVar;
    clone->_colorEnd = _colorEnd;
    clone->_colorEndVar = _colorEndVar;
    clone->_position = _position;
    clone->_positionVar = _positionVar;
    clone->_velocity = _velocity;
    clone->_velocityVar = _velocityVar;
    clone->_acceleration = _acceleration;
    clone->_accelerationVar = _accelerationVar;
    clone->_rotationPerParticleSpeedMin = _rotationPerParticleSpeedMin;
    clone->_rotationPerParticleSpeedMax = _rotationPerParticleSpeedMax;
    clone->_rotationSpeedMin = _rotationSpeedMin;
    clone->_rotationSpeedMax = _rotationSpeedMax;
    clone->_rotationAxis = _rotationAxis;
    clone->_rotationAxisVar = _rotationAxisVar;
    clone->setSpriteTexCoords(_spriteFrameCount, _spriteTextureCoords);
    clone->_spriteAnimated = _spriteAnimated;
    clone->_spriteLooped = _spriteLooped;
    clone->_spriteFrameRandomOffset = _spriteFrameRandomOffset;
    clone->setSpriteFrameDuration(_spriteFrameDuration);
    clone->_orbitPosition = _orbitPosition;
    clone->_orbitVelocity = _orbitVelocity;
    clone->_orbitAcceleration = _orbitAcceleration;

    return clone;
}
ParticleEmitter* ParticleEmitter::create(Properties* properties)
{
    if (!properties || strcmp(properties->getNamespace(), "particle") != 0)
    {
        GP_ERROR("Properties object must be non-null and have namespace equal to 'particle'.");
        return NULL;
    }

    Properties* sprite = properties->getNextNamespace();
    if (!sprite || strcmp(sprite->getNamespace(), "sprite") != 0)
    {
        GP_ERROR("Failed to load particle emitter: required namespace 'sprite' is missing.");
        return NULL;
    }

    // Load sprite properties.
    // Path to image file is required.
    const char* texturePath = sprite->getString("path");
    if (!texturePath || strlen(texturePath) == 0)
    {
        GP_ERROR("Failed to load particle emitter: required image file path ('path') is missing.");
        return NULL;
    }

    const char* blendingString = sprite->getString("blending");
    TextureBlending textureBlending = getTextureBlendingFromString(blendingString);
    int spriteWidth = sprite->getInt("width");
    int spriteHeight = sprite->getInt("height");
    bool spriteAnimated = sprite->getBool("animated");
    bool spriteLooped = sprite->getBool("looped");
    int spriteFrameCount = sprite->getInt("frameCount");
    int spriteFrameRandomOffset = sprite->getInt("frameRandomOffset");
    float spriteFrameDuration = sprite->getFloat("frameDuration");

    // Emitter properties.
    unsigned int particleCountMax = (unsigned int)properties->getInt("particleCountMax");
    if (particleCountMax == 0)
    {
        // Set sensible default.
        particleCountMax = PARTICLE_COUNT_MAX;
    }

    unsigned int emissionRate = (unsigned int)properties->getInt("emissionRate");
    if (emissionRate == 0)
    {
        emissionRate = PARTICLE_EMISSION_RATE;
    }

    bool ellipsoid = properties->getBool("ellipsoid");
    float sizeStartMin = properties->getFloat("sizeStartMin");
    float sizeStartMax = properties->getFloat("sizeStartMax");
    float sizeEndMin = properties->getFloat("sizeEndMin");
    float sizeEndMax = properties->getFloat("sizeEndMax");
    long energyMin = properties->getLong("energyMin");
    long energyMax = properties->getLong("energyMax");

    Vector4 colorStart;
    Vector4 colorStartVar;
    Vector4 colorEnd;
    Vector4 colorEndVar;
    properties->getVector4("colorStart", &colorStart);
    properties->getVector4("colorStartVar", &colorStartVar);
    properties->getVector4("colorEnd", &colorEnd);
    properties->getVector4("colorEndVar", &colorEndVar);

    Vector3 position;
    Vector3 positionVar;
    Vector3 velocity;
    Vector3 velocityVar;
    Vector3 acceleration;
    Vector3 accelerationVar;
    Vector3 rotationAxis;
    Vector3 rotationAxisVar;
    properties->getVector3("position", &position);
    properties->getVector3("positionVar", &positionVar);
    properties->getVector3("velocity", &velocity);
    properties->getVector3("velocityVar", &velocityVar);
    properties->getVector3("acceleration", &acceleration);
    properties->getVector3("accelerationVar", &accelerationVar);
    float rotationPerParticleSpeedMin = properties->getFloat("rotationPerParticleSpeedMin");
    float rotationPerParticleSpeedMax = properties->getFloat("rotationPerParticleSpeedMax");
    float rotationSpeedMin = properties->getFloat("rotationSpeedMin");
    float rotationSpeedMax = properties->getFloat("rotationSpeedMax");
    properties->getVector3("rotationAxis", &rotationAxis);
    properties->getVector3("rotationAxisVar", &rotationAxisVar);
    bool orbitPosition = properties->getBool("orbitPosition");
    bool orbitVelocity = properties->getBool("orbitVelocity");
    bool orbitAcceleration = properties->getBool("orbitAcceleration");

    // Apply all properties to a newly created ParticleEmitter.
    ParticleEmitter* emitter = ParticleEmitter::create(texturePath, textureBlending, particleCountMax);
    if (!emitter)
    {
        GP_ERROR("Failed to create particle emitter.");
        return NULL;
    }
    emitter->setEmissionRate(emissionRate);
    emitter->setEllipsoid(ellipsoid);
    emitter->setSize(sizeStartMin, sizeStartMax, sizeEndMin, sizeEndMax);
    emitter->setEnergy(energyMin, energyMax);
    emitter->setColor(colorStart, colorStartVar, colorEnd, colorEndVar);
    emitter->setPosition(position, positionVar);
    emitter->setVelocity(velocity, velocityVar);
    emitter->setAcceleration(acceleration, accelerationVar);
    emitter->setRotationPerParticle(rotationPerParticleSpeedMin, rotationPerParticleSpeedMax);
    emitter->setRotation(rotationSpeedMin, rotationSpeedMax, rotationAxis, rotationAxisVar);

    emitter->setSpriteAnimated(spriteAnimated);
    emitter->setSpriteLooped(spriteLooped);
    emitter->setSpriteFrameRandomOffset(spriteFrameRandomOffset);
    emitter->setSpriteFrameDuration(spriteFrameDuration);
    emitter->setSpriteFrameCoords(spriteFrameCount, spriteWidth, spriteHeight);

    emitter->setOrbit(orbitPosition, orbitVelocity, orbitAcceleration);

    return emitter;
}