Browse Source

Add ParticleEmitter2D.

aster2013 11 years ago
parent
commit
d4bab90eb8

+ 27 - 0
Source/Engine/Urho2D/CMakeLists.txt

@@ -0,0 +1,27 @@
+#
+# Copyright (c) 2008-2014 the Urho3D project.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+
+# Define source files
+define_source_files (PARENT_SCOPE)
+
+# Define dependency libs
+set (ENGINE_INCLUDE_DIRS_ONLY ${ENGINE_INCLUDE_DIRS_ONLY} PARENT_SCOPE)

+ 359 - 0
Source/Engine/Urho2D/ParticleEmitter2D.cpp

@@ -0,0 +1,359 @@
+//
+// Copyright (c) 2008-2014 the Urho3D project.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#include "Precompiled.h"
+#include "Camera.h"
+#include "Context.h"
+#include "ParticleModel2D.h"
+#include "ParticleEmitter2D.h"
+#include "ResourceCache.h"
+#include "Scene.h"
+#include "SceneEvents.h"
+
+#include "DebugNew.h"
+
+namespace Urho3D
+{
+
+extern const char* URHO2D_CATEGORY;
+
+ParticleEmitter2D::ParticleEmitter2D(Context* context) : Drawable2D(context), 
+    lifeTime_(0.0f),
+    numParticles_(0),    
+    emitParticleTime_(0.0f), 
+    timeBetweenParticles_(1.0f)
+{
+}
+
+ParticleEmitter2D::~ParticleEmitter2D()
+{
+}
+
+void ParticleEmitter2D::RegisterObject(Context* context)
+{
+    context->RegisterFactory<ParticleEmitter2D>(URHO2D_CATEGORY);
+
+    ACCESSOR_ATTRIBUTE(ParticleEmitter2D, VAR_RESOURCEREF, "Particle Model", GetParticleModelAttr, SetParticleModelAttr, ResourceRef, ResourceRef(ParticleModel2D::GetTypeStatic()), AM_FILE);
+    COPY_BASE_ATTRIBUTES(ParticleEmitter2D, Drawable2D);
+}
+
+void ParticleEmitter2D::OnSetEnabled()
+{
+    Drawable2D::OnSetEnabled();
+
+    Scene* scene = GetScene();
+    if (scene)
+    {
+        if (IsEnabledEffective())
+            SubscribeToEvent(scene, E_SCENEPOSTUPDATE, HANDLER(ParticleEmitter2D, HandleScenePostUpdate));
+        else
+            UnsubscribeFromEvent(scene, E_SCENEPOSTUPDATE);
+    }
+}
+
+void ParticleEmitter2D::UpdateBatches(const FrameInfo& frame)
+{
+    if (materialDirty_)
+        UpdateMaterial();
+
+    // const Matrix3x4& worldTransform = node_->GetWorldTransform();
+    distance_ = frame.camera_->GetDistance(GetWorldBoundingBox().Center());
+
+    batches_[0].distance_ = distance_;
+    batches_[0].worldTransform_ = &Matrix3x4::IDENTITY;
+}
+
+void ParticleEmitter2D::Update(const FrameInfo& frame)
+{
+    if (!model_)
+        return;
+
+    float timeStep = frame.timeStep_;
+
+    int particleIndex = 0;    
+    while (particleIndex < numParticles_)
+    {
+        Particle2D& currentParticle = particles_[particleIndex];
+        if (currentParticle.timeToLive_ > timeStep) 
+        {
+            UpdateParticle(currentParticle, timeStep);
+
+            ++particleIndex;
+        } 
+        else 
+        {            
+            if (particleIndex != numParticles_ - 1)
+                particles_[particleIndex] = particles_[numParticles_ - 1];
+
+            --numParticles_;
+        }
+    }
+
+    if (lifeTime_< 0.0f || lifeTime_ > 0.0f)
+    {
+        emitParticleTime_ += timeStep;
+        while (emitParticleTime_ > 0.0f)
+        {
+            EmitParticle();
+            emitParticleTime_ -= timeBetweenParticles_;
+        }
+
+        if (lifeTime_ > 0.0f)
+            lifeTime_ = Max(0.0f, lifeTime_ - timeStep);
+    }
+
+    MarkVerticesDirty();
+    OnMarkedDirty(node_);    
+}
+
+void ParticleEmitter2D::SetModel(ParticleModel2D* model)
+{
+    model_ = model;
+    if (!model_)
+        return;
+
+    SetSprite(model_->GetSprite());
+    SetBlendMode(model_->GetBlendMode());
+
+    lifeTime_ = model_->GetDuration();
+
+    numParticles_ = Min(model_->GetMaxParticles(), numParticles_);    
+    particles_.Resize(model_->GetMaxParticles());
+    vertices_.Reserve(model_->GetMaxParticles() * 4);
+
+    emitParticleTime_ = 0.0f;
+    timeBetweenParticles_ = model_->GetParticleLifeSpan() / model_->GetMaxParticles();
+}
+
+ParticleModel2D* ParticleEmitter2D::GetModel() const
+{
+    return model_;
+}
+
+void ParticleEmitter2D::SetParticleModelAttr(ResourceRef value)
+{
+    ResourceCache* cache = GetSubsystem<ResourceCache>();
+    SetModel(cache->GetResource<ParticleModel2D>(value.name_));
+}
+
+Urho3D::ResourceRef ParticleEmitter2D::GetParticleModelAttr() const
+{
+    return GetResourceRef(model_, ParticleModel2D::GetTypeStatic());
+}
+
+void ParticleEmitter2D::OnNodeSet(Node* node)
+{
+    Drawable2D::OnNodeSet(node);
+
+    if (node)
+    {
+        Scene* scene = GetScene();
+        if (scene && IsEnabledEffective())
+            SubscribeToEvent(scene, E_SCENEPOSTUPDATE, HANDLER(ParticleEmitter2D, HandleScenePostUpdate));
+    }
+}
+
+void ParticleEmitter2D::OnWorldBoundingBoxUpdate()
+{
+    if (verticesDirty_)
+    {
+        UpdateVertices();
+
+        boundingBox_.Clear();
+        for (unsigned i = 0; i < vertices_.Size(); ++i)
+            boundingBox_.Merge(vertices_[i].position_);
+    }
+
+    worldBoundingBox_ = boundingBox_;
+}
+
+void ParticleEmitter2D::UpdateVertices()
+{
+    if (!verticesDirty_)
+        return;
+
+    vertices_.Clear();
+
+    if (!sprite_)
+        return;
+
+    Texture2D* texture = sprite_->GetTexture();
+    if (!texture)
+        return;
+
+    const IntRect& rectangle_ = sprite_->GetRectangle();
+    if (rectangle_.Width() == 0 || rectangle_.Height() == 0)
+        return;
+
+    Vertex2D vertex0;
+    Vertex2D vertex1;
+    Vertex2D vertex2;
+    Vertex2D vertex3;
+
+    vertex0.uv_ = Vector2(0.0f, 1.0f);
+    vertex1.uv_ = Vector2(0.0f, 0.0f);
+    vertex2.uv_ = Vector2(1.0f, 0.0f);
+    vertex3.uv_ = Vector2(1.0f, 1.0f);
+
+    for (int i = 0; i < numParticles_; ++i)
+    {
+        Particle2D& p = particles_[i];
+
+        float c = Cos(p.rotation_);
+        float s = Sin(p.rotation_);
+        float add = (c + s) * p.size_ * 0.5f;
+        float sub = (c - s) * p.size_ * 0.5f;
+
+        vertex0.position_ = Vector3(p.position_.x_ - sub, p.position_.y_ - add, 0.0f) * unitPerPixel_;
+        vertex1.position_ = Vector3(p.position_.x_ - add, p.position_.y_ + sub, 0.0f) * unitPerPixel_;
+        vertex2.position_ = Vector3(p.position_.x_ + sub, p.position_.y_ + add, 0.0f) * unitPerPixel_;
+        vertex3.position_ = Vector3(p.position_.x_ + add, p.position_.y_ - sub, 0.0f) * unitPerPixel_;
+
+        vertex0.color_ = vertex1.color_ = vertex2.color_  = vertex3.color_ = p.color_.ToUInt();
+
+        vertices_.Push(vertex0);
+        vertices_.Push(vertex1);
+        vertices_.Push(vertex2);
+        vertices_.Push(vertex3);
+    }
+
+    MarkGeometryDirty();
+
+    verticesDirty_ = false;
+}
+
+void ParticleEmitter2D::HandleScenePostUpdate(StringHash eventType, VariantMap& eventData)
+{
+    MarkForUpdate();
+}
+
+void ParticleEmitter2D::EmitParticle()
+{
+    if (numParticles_ >= model_->GetMaxParticles())
+        return;
+
+    float lifespan = model_->GetParticleLifeSpan() + model_->GetParticleLifeSpanVariance() * Random(-1.0f, 1.0f);
+    if (lifespan <= 0.0f) 
+        return;
+
+    Particle2D& particle = particles_[numParticles_++];
+    
+    particle.timeToLive_ = lifespan;
+    Vector3 worldPosition = GetNode()->GetWorldPosition();
+    particle.startPos_.x_ = worldPosition.x_;
+    particle.startPos_.y_ = worldPosition.y_;
+    particle.position_.x_ = worldPosition.x_ + model_->GetSourcePositionVariance().x_ * Random(-1.0f, 1.0f);
+    particle.position_.y_ = worldPosition.y_ + model_->GetSourcePositionVariance().y_ * Random(-1.0f, 1.0f);
+
+    float angle = model_->GetEmitAngle() + model_->GetEmitAngleVariance() * Random(-1.0f, 1.0f);
+    float speed = model_->GetSpeed() + model_->GetSpeedVariance() * Random(-1.0f, 1.0f);
+    particle.velocity_.x_ = speed * Cos(angle);
+    particle.velocity_.y_ = speed * Sin(angle);
+
+    float worldScale = GetNode()->GetWorldScale().x_;
+    particle.velocity_ *= worldScale;
+
+    particle.radius_ = model_->GetMaxRadius() + model_->GetMaxRadiusVariance() * Random(-1.0f, 1.0f);
+    particle.radiusDelta_ = model_->GetMaxRadius() / lifespan;
+    particle.radius_ *= worldScale;
+    particle.radiusDelta_ *= worldScale;
+
+    particle.rotation_ = model_->GetEmitAngle() + model_->GetEmitAngleVariance() * Random(-1.0f, 1.0f);
+    particle.rotationDelta_ = model_->GetRotatePerSecond() + model_->GetRotatePerSecondVariance() * Random(-1.0f, 1.0f);
+
+    particle.radialAccel_ = model_->GetRadialAcceleration() + model_->GetRadialAccelerationVariance() * Random(-1.0f, 1.0f);
+    particle.tangentialAccel_ = model_->GetTangentialAcceleration() + model_->GetTangentialAccelerationVariance() * Random(-1.0f, 1.0f);
+
+    particle.radialAccel_ *= worldScale;
+    particle.tangentialAccel_ *= worldScale;
+
+    float particleStartSize  = Max(0.1f, model_->GetStartParticleSize() + model_->GetStartParticleSizeVariance() * Random(-1.0f, 1.0f));
+    float particleFinishSize = Max(0.1f, model_->GetEndParticleSize() + model_->GetEndParticleSizeVariance() * Random(-1.0f, 1.0f)); 
+    particle.size_ = particleStartSize;
+    particle.sizeDelta_ = (particleFinishSize - particleStartSize)/ lifespan ;
+    
+    particle.size_ *= worldScale;
+    particle.sizeDelta_ *= worldScale;
+
+    Color startColor = model_->GetStartColor() + model_->GetStartColorVariance() * Random(-1.0f, 1.0f);
+    Color endColor   = model_->GetEndColor() +   model_->GetEndColorVariance() * Random(-1.0f, 1.0f);
+
+    Color colorDelta;
+    colorDelta.r_ = (endColor.r_ - startColor.r_) / lifespan;
+    colorDelta.g_ = (endColor.g_ - startColor.g_) / lifespan;
+    colorDelta.b_ = (endColor.b_ - startColor.b_) / lifespan;
+    colorDelta.a_ = (endColor.a_ - startColor.a_) / lifespan;
+
+    particle.color_ = startColor;
+    particle.colorDelta_ = colorDelta;
+}
+
+void ParticleEmitter2D::UpdateParticle(Particle2D& particle, float timeStep)
+{
+    timeStep = Min(timeStep, particle.timeToLive_);
+    particle.timeToLive_ -= timeStep;
+
+    if (model_->GetEmitterType() == EMITTER_TYPE_RADIAL) 
+    {
+        particle.rotation_ += particle.rotationDelta_ * timeStep;
+        particle.radius_   -= particle.radiusDelta_   * timeStep;
+
+        Vector3 worldPosition = GetNode()->GetWorldPosition();
+        particle.position_.x_ = worldPosition.x_ - cosf(particle.rotation_) * particle.radius_;
+        particle.position_.y_ = worldPosition.y_ - sinf(particle.rotation_) * particle.radius_;
+
+        if (particle.radius_ < model_->GetMinRadius())
+            particle.timeToLive_ = 0.0f;                
+    } 
+    else 
+    {
+        float distanceX = particle.position_.x_ - particle.startPos_.x_;
+        float distanceY = particle.position_.y_ - particle.startPos_.y_;
+        float distanceScalar = Max(0.01f, sqrtf(distanceX * distanceX + distanceY * distanceY));
+
+        float radialX = distanceX / distanceScalar;
+        float radialY = distanceY / distanceScalar;
+        float tangentialX = radialX;
+        float tangentialY = radialY;
+
+        radialX *= particle.radialAccel_;
+        radialY *= particle.radialAccel_;
+
+        float newY = tangentialX;
+        tangentialX = -tangentialY * particle.tangentialAccel_;
+        tangentialY = newY * particle.tangentialAccel_;
+
+        particle.velocity_.x_ += timeStep * (model_->GetGravity().x_ + radialX + tangentialX);
+        particle.velocity_.y_ += timeStep * (model_->GetGravity().y_ + radialY + tangentialY);
+        particle.position_.x_ += particle.velocity_.x_ * timeStep;
+        particle.position_.y_ += particle.velocity_.y_ * timeStep;
+    }
+
+    particle.size_ += particle.sizeDelta_ * timeStep;
+
+    particle.color_.r_ += particle.colorDelta_.r_ * timeStep;
+    particle.color_.g_ += particle.colorDelta_.g_ * timeStep;
+    particle.color_.b_ += particle.colorDelta_.b_ * timeStep;
+    particle.color_.a_ += particle.colorDelta_.a_ * timeStep;
+}
+
+}

+ 124 - 0
Source/Engine/Urho2D/ParticleEmitter2D.h

@@ -0,0 +1,124 @@
+//
+// Copyright (c) 2008-2014 the Urho3D project.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#pragma once
+
+#include "Drawable2D.h"
+
+namespace Urho3D
+{
+
+class ParticleModel2D;
+
+/// 2D particle.
+ struct Particle2D
+{
+    /// Time to live.
+    float timeToLive_;
+    /// Start position.
+    Vector2 startPos_;
+    /// Position.
+    Vector2 position_;
+    /// Velocity.
+    Vector2 velocity_;
+    /// Radius.
+    float radius_;
+    /// Radius delta.
+    float radiusDelta_;
+    /// Rotation.
+    float rotation_;
+    /// Rotation delta.
+    float rotationDelta_;
+    /// Radial acceleration.
+    float radialAccel_;
+    /// Tangential acceleration.
+    float tangentialAccel_;
+    /// Size.
+    float size_;
+    /// Size delta.
+    float sizeDelta_;
+    /// Color.
+    Color color_;
+    /// Color delta.
+    Color colorDelta_;
+};
+
+/// 2D particle emitter component.
+class URHO3D_API ParticleEmitter2D : public Drawable2D
+{
+    OBJECT(ParticleEmitter2D);
+
+public:
+    /// Construct.
+    ParticleEmitter2D(Context* context);
+    /// Destruct.
+    ~ParticleEmitter2D();
+    /// Register object factory. drawable2d must be registered first.
+    static void RegisterObject(Context* context);
+
+    /// Handle enabled/disabled state change.
+    virtual void OnSetEnabled();
+    /// Calculate distance and prepare batches for rendering. May be called from worker thread(s), possibly re-entrantly.
+    virtual void UpdateBatches(const FrameInfo& frame);
+    /// Update before octree reinsertion. is called from a worker thread.
+    virtual void Update(const FrameInfo& frame);
+
+    /// Set particle model.
+    void SetModel(ParticleModel2D* model);
+    /// Return particle model.
+    ParticleModel2D* GetModel() const;
+
+    /// Set particle model attr.
+    void SetParticleModelAttr(ResourceRef value);
+    /// Return particle model attr.
+    ResourceRef GetParticleModelAttr() const;
+
+private:
+    /// Handle node being assigned.
+    virtual void OnNodeSet(Node* node);
+    /// Recalculate the world-space bounding box.
+    virtual void OnWorldBoundingBoxUpdate();
+    /// Update vertices.
+    virtual void UpdateVertices();
+    /// Handle scene post update.
+    void HandleScenePostUpdate(StringHash eventType, VariantMap& eventData);
+    /// Emit particle.
+    void EmitParticle();
+    /// Update particle.
+    void UpdateParticle(Particle2D& particle, float timeStep);
+
+    /// Particle model.
+    SharedPtr<ParticleModel2D> model_;
+    /// Life time;
+    float lifeTime_;
+    /// Num particles.
+    int numParticles_;    
+    /// Particles.
+    Vector<Particle2D> particles_;
+    /// Time to emit particle.
+    float emitParticleTime_;
+    /// Time between particles.
+    float timeBetweenParticles_;
+};
+
+}
+

+ 226 - 0
Source/Engine/Urho2D/ParticleModel2D.cpp

@@ -0,0 +1,226 @@
+//
+// Copyright (c) 2008-2014 the Urho3D project.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#include "Precompiled.h"
+#include "Context.h"
+#include "ParticleModel2D.h"
+#include "ResourceCache.h"
+#include "StringUtils.h"
+#include "Sprite2D.h"
+#include "XMLFile.h"
+
+#include "DebugNew.h"
+
+namespace Urho3D
+{
+
+extern const char* URHO2D_CATEGORY;
+
+static const int srcBlendFuncs[] =
+{
+    1,      // GL_ONE
+    1,      // GL_ONE
+    0x0306, // GL_DST_COLOR
+    0x0302, // GL_SRC_ALPHA
+    0x0302, // GL_SRC_ALPHA
+    1,      // GL_ONE
+    0x0305  // GL_ONE_MINUS_DST_ALPHA
+};
+
+static const int destBlendFuncs[] =
+{
+    0,      // GL_ZERO
+    1,      // GL_ONE
+    0,      // GL_ZERO
+    0x0303, // GL_ONE_MINUS_SRC_ALPHA
+    1,      // GL_ONE
+    0x0303, // GL_ONE_MINUS_SRC_ALPHA
+    0x0304  // GL_DST_ALPHA
+};
+
+ParticleModel2D::ParticleModel2D(Context* context) : Resource(context), 
+    blendMode_(BLEND_ALPHA),
+    duration_(-1.0f),
+    emitterType_(EMITTER_TYPE_GRAVITY),
+    sourcePositionVariance_(Vector2::ZERO),
+    maxParticles_(32),
+    particleLifeSpan_(1.0f),
+    particleLifeSpanVariance_(0.0f),
+    startParticleSize_(1.0f),
+    startParticleSizeVariance_(0.0f),
+    endParticleSize_(0.0f),
+    endParticleSizeVariance_(0.0f),
+    emitAngle_(0.0f),
+    emitAngleVariance_(0.0f),
+    speed_(100.0f),
+    speedVariance_(0.0f),
+    gravity_(Vector2::ZERO),
+    radialAcceleration_(0.0f),
+    radialAccelerationVariance_(0.0f),
+    tangentialAcceleration_(0.0f),
+    tangentialAccelerationVariance_(0.0f),
+    maxRadius_(100.0f),
+    maxRadiusVariance_(0.0f),
+    minRadius_(0.0f),
+    rotatePerSecond_(0.0f),
+    rotatePerSecondVariance_(0.0f),
+    startColor_(Color::WHITE),
+    startColorVariance_(Color::TRANSPARENT),
+    endColor_(Color::WHITE),
+    endColorVariance_(Color::TRANSPARENT)
+{
+}
+
+ParticleModel2D::~ParticleModel2D()
+{
+}
+
+void ParticleModel2D::RegisterObject(Context* context)
+{
+    context->RegisterFactory<ParticleModel2D>(URHO2D_CATEGORY);
+}
+
+bool ParticleModel2D::Load(Deserializer& source)
+{
+    XMLFile xmlFile(context_);
+    if (!xmlFile.Load(source))
+        return false;
+
+    XMLElement plistElem = xmlFile.GetRoot("plist");
+    if (!plistElem)
+        return false;
+
+    XMLElement dictElem = plistElem.GetChild();
+    if (!dictElem || dictElem.GetName() != "dict")
+        return false;
+
+    VariantMap keyValueMapping;
+    XMLElement keyElem = dictElem.GetChild();
+    while (keyElem)
+    {
+        if (keyElem.GetName() != "key")
+            return false;
+
+        XMLElement valueElem = keyElem.GetNext();
+        if (!valueElem)
+            return false;
+
+        String key = keyElem.GetValue();
+        String type = valueElem.GetName();
+        String value = valueElem.GetValue();
+
+        if (type == "integer")
+            keyValueMapping[key] = ToInt(value);
+        else if (type == "real")
+            keyValueMapping[key] = ToFloat(value);
+        else
+            keyValueMapping[key] = value;
+
+        keyElem = valueElem.GetNext();
+    }
+
+    const String& textureFileName = keyValueMapping["textureFileName"].GetString();
+    ResourceCache* cache = GetSubsystem<ResourceCache>();
+    sprite_= cache->GetResource<Sprite2D>(textureFileName);
+    if (!sprite_)
+        return false;
+
+    int blendFuncSource = keyValueMapping["blendFuncSource"].GetInt();
+    int blendFuncDestination = keyValueMapping["blendFuncDestination"].GetInt();
+    blendMode_ = BLEND_ALPHA;
+    for (int i = 0; i < MAX_BLENDMODES; ++i)
+    {
+        if (blendFuncSource == srcBlendFuncs[i] && blendFuncDestination == destBlendFuncs[i])
+        {
+            blendMode_ = (BlendMode)i;
+            break;
+        }
+    }
+
+    duration_ = keyValueMapping["duration"].GetFloat();
+    emitterType_ = (EmitterType2D)(int)keyValueMapping["emitterType"].GetFloat();
+
+    sourcePositionVariance_.x_ = keyValueMapping["sourcePositionVariancex"].GetFloat();
+    sourcePositionVariance_.y_ = keyValueMapping["sourcePositionVariancey"].GetFloat();    
+
+    maxParticles_ = (int)keyValueMapping["maxParticles"].GetFloat();
+    particleLifeSpan_ = keyValueMapping["particleLifespan"].GetFloat();
+
+    particleLifeSpanVariance_ = keyValueMapping["particleLifespanVariance"].GetFloat();
+    startParticleSize_ = keyValueMapping["startParticleSize"].GetFloat();
+    startParticleSizeVariance_ = keyValueMapping["startParticleSizeVariance"].GetFloat();
+    endParticleSize_ = keyValueMapping["finishParticleSize"].GetFloat();
+    endParticleSizeVariance_ = keyValueMapping["finishParticleSizeVariance"].GetFloat();
+    emitAngle_ = keyValueMapping["angle"].GetFloat();
+    emitAngleVariance_ = keyValueMapping["angleVariance"].GetFloat();
+
+    speed_ = keyValueMapping["speed"].GetFloat();
+    speedVariance_ = keyValueMapping["speedVariance"].GetFloat();
+
+    gravity_.x_ = keyValueMapping["gravityx"].GetFloat();
+    gravity_.y_ = keyValueMapping["gravityy"].GetFloat();
+
+    radialAcceleration_ = keyValueMapping["radialAcceleration"].GetFloat();
+    radialAccelerationVariance_ = keyValueMapping["radialAccelVariance"].GetFloat();
+    tangentialAcceleration_ = keyValueMapping["tangentialAcceleration"].GetFloat();
+    tangentialAccelerationVariance_ = keyValueMapping["tangentialAccelVariance"].GetFloat();
+
+    maxRadius_ = keyValueMapping["maxRadius"].GetFloat();
+    maxRadiusVariance_ = keyValueMapping["maxRadiusVariance"].GetFloat();
+    minRadius_ = keyValueMapping["minRadius"].GetFloat();
+    rotatePerSecond_ = keyValueMapping["rotatePerSecond"].GetFloat();
+    rotatePerSecondVariance_ = keyValueMapping["rotatePerSecondVariance"].GetFloat();
+
+    startColor_.r_ = keyValueMapping["startColorRed"].GetFloat();
+    startColor_.g_ = keyValueMapping["startColorGreen"].GetFloat();
+    startColor_.b_ = keyValueMapping["startColorBlue"].GetFloat();
+    startColor_.a_ = keyValueMapping["startColorAlpha"].GetFloat();
+
+    startColorVariance_.r_ = keyValueMapping["startColorVarianceRed"].GetFloat();
+    startColorVariance_.g_ = keyValueMapping["startColorVarianceGreen"].GetFloat();
+    startColorVariance_.b_ = keyValueMapping["startColorVarianceBlue"].GetFloat();
+    startColorVariance_.a_ = keyValueMapping["startColorVarianceAlpha"].GetFloat();
+
+    endColor_.r_ = keyValueMapping["finishColorRed"].GetFloat();
+    endColor_.g_ = keyValueMapping["finishColorGreen"].GetFloat();
+    endColor_.b_ = keyValueMapping["finishColorBlue"].GetFloat();
+    endColor_.a_ = keyValueMapping["finishColorAlpha"].GetFloat();
+
+    endColorVariance_.r_ = keyValueMapping["finishColorVarianceRed"].GetFloat();
+    endColorVariance_.g_ = keyValueMapping["finishColorVarianceGreen"].GetFloat();
+    endColorVariance_.b_ = keyValueMapping["finishColorVarianceBlue"].GetFloat();
+    endColorVariance_.a_ = keyValueMapping["finishColorVarianceAlpha"].GetFloat();
+
+    return true;
+}
+
+bool ParticleModel2D::Save(Serializer& dest) const
+{
+    return false;
+}
+
+Sprite2D* ParticleModel2D::GetSprite() const
+{
+    return sprite_;
+}
+
+}

+ 183 - 0
Source/Engine/Urho2D/ParticleModel2D.h

@@ -0,0 +1,183 @@
+//
+// Copyright (c) 2008-2014 the Urho3D project.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#pragma once
+
+#include "Resource.h"
+#include "GraphicsDefs.h"
+
+namespace Urho3D
+{
+
+class Sprite2D;
+
+/// 2D particle emitter types.
+enum EmitterType2D
+{
+    EMITTER_TYPE_GRAVITY = 0,
+    EMITTER_TYPE_RADIAL
+};
+
+/// 2D particle emitter component.
+class URHO3D_API ParticleModel2D : public Resource
+{
+    OBJECT(ParticleModel2D);
+
+public:
+    /// Construct.
+    ParticleModel2D(Context* context);
+    /// Destruct.
+    ~ParticleModel2D();
+    /// Register object factory. drawable2d must be registered first.
+    static void RegisterObject(Context* context);
+
+    /// Load resource. Return true if successful.
+    virtual bool Load(Deserializer& source);
+    /// Save resource. Return true if successful.
+    virtual bool Save(Serializer& dest) const;
+
+    /// Return sprite.
+    Sprite2D* GetSprite() const;
+    /// Return blend mode.
+    BlendMode GetBlendMode() const { return blendMode_; }
+    /// Return duration.
+    float GetDuration() const { return duration_; }
+    /// Return emitter type.
+    EmitterType2D GetEmitterType() const { return emitterType_; }
+    /// Return source position variance.
+    const Vector2& GetSourcePositionVariance() const { return sourcePositionVariance_; }
+    /// Return max particles.
+    int GetMaxParticles() const { return maxParticles_; }
+    /// Return particle lifespan
+    float GetParticleLifeSpan() const { return particleLifeSpan_; }
+    /// Return particle lifespan variance.
+    float GetParticleLifeSpanVariance() const { return particleLifeSpanVariance_; }
+    /// Return start particle size.
+    float GetStartParticleSize() const { return startParticleSize_; }
+    /// Return start particle size variance.
+    float GetStartParticleSizeVariance() const { return startParticleSizeVariance_; }
+    /// Return end particle size.
+    float GetEndParticleSize() const { return endParticleSize_; }
+    /// Return end particle size variance.
+    float GetEndParticleSizeVariance() const { return endParticleSizeVariance_; }
+    /// Return angle.
+    float GetEmitAngle() const { return emitAngle_; }
+    /// Return angle variance.
+    float GetEmitAngleVariance() const { return emitAngleVariance_; }
+    /// Return speed.
+    float GetSpeed() const { return speed_; }
+    /// Return speed variance.
+    float GetSpeedVariance() const { return speedVariance_; }
+    /// Return gravity.
+    const Vector2& GetGravity() const { return gravity_; }
+    /// Return radial acceleration.
+    float GetRadialAcceleration() const { return radialAcceleration_; }
+    /// Return radial acceleration variance.
+    float GetRadialAccelerationVariance() const { return radialAccelerationVariance_; }
+    /// Return tangential acceleration.
+    float GetTangentialAcceleration() const { return tangentialAcceleration_; }
+    /// Return tangential acceleration variance.
+    float GetTangentialAccelerationVariance() const { return tangentialAccelerationVariance_; }
+    /// Return max radius.
+    float GetMaxRadius() const { return maxRadius_; }
+    /// Return max radius variance.
+    float GetMaxRadiusVariance() const { return maxRadiusVariance_; }
+    /// Return min radius.
+    float GetMinRadius() const { return minRadius_; }
+    /// Return rotate per second.
+    float GetRotatePerSecond() const { return rotatePerSecond_; }
+    /// Return rotate per second variance.
+    float GetRotatePerSecondVariance() const { return rotatePerSecondVariance_; }
+    /// Return start color.
+    const Color& GetStartColor() const { return startColor_; }
+    /// Return start color variance.
+    const Color& GetStartColorVariance() const { return startColorVariance_; }
+    /// Return end color.
+    const Color& GetEndColor() const { return endColor_; }
+    /// Return end color variance.
+    const Color& GetEndColorVariance() const { return endColorVariance_; }
+
+private:
+    /// Texture.
+    SharedPtr<Sprite2D> sprite_;
+    /// Blend mode.
+    BlendMode blendMode_;
+    /// Duration.
+    float duration_;
+    /// Emitter type.
+    EmitterType2D emitterType_;
+    /// Source position variance.
+    Vector2 sourcePositionVariance_;
+    /// Max particles.
+    int maxParticles_;
+    /// Particle lifespan
+    float particleLifeSpan_;
+    /// Particle lifespan variance.
+    float particleLifeSpanVariance_;
+    /// Start particle size.
+    float startParticleSize_;
+    /// Start particle size variance.
+    float startParticleSizeVariance_;
+    /// End particle size.
+    float endParticleSize_;
+    /// End particle size variance.
+    float endParticleSizeVariance_;
+    /// Angle.
+    float emitAngle_;
+    /// Angle variance.
+    float emitAngleVariance_;
+    /// Speed.
+    float speed_;
+    /// Speed variance.
+    float speedVariance_;
+    /// Gravity.
+    Vector2 gravity_;
+    /// Radial acceleration.
+    float radialAcceleration_;
+    /// Radial acceleration variance.
+    float radialAccelerationVariance_;
+    /// Tangential acceleration.
+    float tangentialAcceleration_;
+    /// Tangential acceleration variance.
+    float tangentialAccelerationVariance_;
+    /// Max radius.
+    float maxRadius_;
+    /// Max radius variance.
+    float maxRadiusVariance_;
+    /// Min radius.
+    float minRadius_;
+    /// Rotate per second.
+    float rotatePerSecond_;
+    /// Rotate per second variance.
+    float rotatePerSecondVariance_;
+    /// Start color.
+    Color startColor_;
+    /// Start color variance.
+    Color startColorVariance_;
+    /// End color.
+    Color endColor_;
+    /// End color variance.
+    Color endColorVariance_;
+};
+
+}
+

+ 48 - 0
Source/Engine/Urho2D/Urho2D.cpp

@@ -0,0 +1,48 @@
+//
+// Copyright (c) 2008-2014 the Urho3D project.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#include "Precompiled.h"
+#include "Sprite2D.h"
+#include "SpriteSheet2D.h"
+#include "Drawable2D.h"
+#include "StaticSprite2D.h"
+#include "ParticleModel2D.h"
+#include "ParticleEmitter2D.h"
+
+#include "DebugNew.h"
+
+namespace Urho3D
+{
+
+const char* URHO2D_CATEGORY = "Urho2D";
+
+void RegisterUrho2DLibrary(Context* context)
+{
+    Sprite2D::RegisterObject(context);
+    SpriteSheet2D::RegisterObject(context);
+    Drawable2D::RegisterObject(context);
+    StaticSprite2D::RegisterObject(context);
+    ParticleModel2D::RegisterObject(context);
+    ParticleEmitter2D::RegisterObject(context);
+}
+
+}

+ 31 - 0
Source/Engine/Urho2D/Urho2D.h

@@ -0,0 +1,31 @@
+//
+// Copyright (c) 2008-2014 the Urho3D project.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#pragma once
+
+namespace Urho3D
+{
+
+/// Register Urho2D library objects.
+void URHO3D_API RegisterUrho2DLibrary(Context* context);
+
+}