Переглянути джерело

+ Added string to integer color conversion
+ Added partial parsing of particles
+ Support for particle emitter parsing
+ Support for particle initializers parsing
+ Support for particle controlpoints parsing

Signed-off-by: Alexis Maiquez <almamu@almamu.com>

Alexis Maiquez 7 роки тому
батько
коміт
c2bc23414e
24 змінених файлів з 902 додано та 6 видалено
  1. 20 0
      CMakeLists.txt
  2. 17 3
      wallpaperengine/core.cpp
  3. 3 0
      wallpaperengine/core.h
  4. 19 1
      wallpaperengine/core/object.cpp
  5. 1 1
      wallpaperengine/core/objects/images/materials/passes.cpp
  6. 1 1
      wallpaperengine/core/objects/images/materials/passes.h
  7. 58 0
      wallpaperengine/core/objects/particles/controlpoint.cpp
  8. 29 0
      wallpaperengine/core/objects/particles/controlpoint.h
  9. 110 0
      wallpaperengine/core/objects/particles/emitter.cpp
  10. 42 0
      wallpaperengine/core/objects/particles/emitter.h
  11. 68 0
      wallpaperengine/core/objects/particles/initializer.cpp
  12. 25 0
      wallpaperengine/core/objects/particles/initializer.h
  13. 45 0
      wallpaperengine/core/objects/particles/initializers/colorrandom.cpp
  14. 25 0
      wallpaperengine/core/objects/particles/initializers/colorrandom.h
  15. 39 0
      wallpaperengine/core/objects/particles/initializers/lifetimerandom.cpp
  16. 25 0
      wallpaperengine/core/objects/particles/initializers/lifetimerandom.h
  17. 38 0
      wallpaperengine/core/objects/particles/initializers/rotationrandom.cpp
  18. 25 0
      wallpaperengine/core/objects/particles/initializers/rotationrandom.h
  19. 38 0
      wallpaperengine/core/objects/particles/initializers/sizerandom.cpp
  20. 25 0
      wallpaperengine/core/objects/particles/initializers/sizerandom.h
  21. 45 0
      wallpaperengine/core/objects/particles/initializers/velocityrandom.cpp
  22. 25 0
      wallpaperengine/core/objects/particles/initializers/velocityrandom.h
  23. 128 0
      wallpaperengine/core/objects/particles/particle.cpp
  24. 51 0
      wallpaperengine/core/objects/particles/particle.h

+ 20 - 0
CMakeLists.txt

@@ -77,6 +77,26 @@ add_executable(
         wallpaperengine/core/objects/sound.h
         wallpaperengine/core/objects/effect.cpp
         wallpaperengine/core/objects/effect.h
+        wallpaperengine/core/objects/particles/particle.cpp
+        wallpaperengine/core/objects/particles/particle.h
+
+        wallpaperengine/core/objects/particles/controlpoint.cpp
+        wallpaperengine/core/objects/particles/controlpoint.h
+        wallpaperengine/core/objects/particles/emitter.cpp
+        wallpaperengine/core/objects/particles/emitter.h
+        wallpaperengine/core/objects/particles/initializer.cpp
+        wallpaperengine/core/objects/particles/initializer.h
+
+        wallpaperengine/core/objects/particles/initializers/lifetimerandom.cpp
+        wallpaperengine/core/objects/particles/initializers/lifetimerandom.h
+        wallpaperengine/core/objects/particles/initializers/sizerandom.cpp
+        wallpaperengine/core/objects/particles/initializers/sizerandom.h
+        wallpaperengine/core/objects/particles/initializers/rotationrandom.cpp
+        wallpaperengine/core/objects/particles/initializers/rotationrandom.h
+        wallpaperengine/core/objects/particles/initializers/velocityrandom.cpp
+        wallpaperengine/core/objects/particles/initializers/velocityrandom.h
+        wallpaperengine/core/objects/particles/initializers/colorrandom.cpp
+        wallpaperengine/core/objects/particles/initializers/colorrandom.h
 
         wallpaperengine/core/objects/images/material.cpp
         wallpaperengine/core/objects/images/material.h

+ 17 - 3
wallpaperengine/core.cpp

@@ -33,13 +33,27 @@ irr::video::SColorf wp::core::atoSColorf (const char *str)
     irr::core::vector3df vector = wp::core::ato3vf (str);
 
     return irr::video::SColorf (
-        vector.X,
-        vector.Y,
-        vector.Z
+            vector.X,
+            vector.Y,
+            vector.Z
     );
 }
 
 irr::video::SColorf wp::core::atoSColorf (const std::string& str)
 {
     return wp::core::atoSColorf (str.c_str ());
+}
+
+irr::video::SColor wp::core::atoSColor (const char *str)
+{
+    irr::f32 r = irr::core::strtoul10 (str, &str); while (*str == ' ') str ++;
+    irr::f32 g = irr::core::strtoul10 (str, &str); while (*str == ' ') str ++;
+    irr::f32 b = irr::core::strtoul10 (str, &str);
+
+    return irr::video::SColor (255, r, g, b);
+}
+
+irr::video::SColor wp::core::atoSColor (const std::string& str)
+{
+    return wp::core::atoSColor (str.c_str ());
 }

+ 3 - 0
wallpaperengine/core.h

@@ -14,4 +14,7 @@ namespace wp::core
 
     irr::video::SColorf atoSColorf (const char *str);
     irr::video::SColorf atoSColorf (const std::string& str);
+
+    irr::video::SColor atoSColor (const char *str);
+    irr::video::SColor atoSColor (const std::string& str);
 };

+ 19 - 1
wallpaperengine/core/object.cpp

@@ -1,6 +1,9 @@
 #include "object.h"
+
+#include <utility>
 #include "objects/image.h"
 #include "objects/sound.h"
+#include "objects/particles/particle.h"
 
 #include "../core.h"
 
@@ -16,7 +19,7 @@ object::object (
         const irr::core::vector3df& angles) :
     m_visible (visible),
     m_id (id),
-    m_name (name),
+    m_name (std::move(name)),
     m_origin (origin),
     m_scale (scale),
     m_angles (angles)
@@ -69,6 +72,7 @@ object* object::fromJSON (json data)
 
     json::const_iterator image_it = data.find ("image");
     json::const_iterator sound_it = data.find ("sound");
+    json::const_iterator particle_it = data.find ("particle");
 
     object* object = nullptr;
 
@@ -96,6 +100,20 @@ object* object::fromJSON (json data)
             wp::core::ato3vf (*angles_it)
         );
     }
+    else if (particle_it != data.end ())
+    {
+        object = objects::particles::particle::fromFile (
+            (*particle_it).get <std::string> ().c_str (),
+            *id_it,
+            *name_it,
+            wp::core::ato3vf (*origin_it),
+            wp::core::ato3vf (*scale_it)
+        );
+    }
+    else
+    {
+        throw std::runtime_error ("Unkonwn object type detected");
+    }
 
     if (effects_it != data.end () && (*effects_it).is_array () == true && object != nullptr)
     {

+ 1 - 1
wallpaperengine/core/objects/images/materials/passes.cpp

@@ -94,7 +94,7 @@ passes* passes::fromJSON (json data)
 }
 
 
-void passes::insertTexture (std::string texture)
+void passes::insertTexture (const std::string& texture)
 {
     this->m_textures.push_back (texture);
 }

+ 1 - 1
wallpaperengine/core/objects/images/materials/passes.h

@@ -15,7 +15,7 @@ namespace wp::core::objects::images::materials
     protected:
         passes (std::string blending, std::string cullmode, std::string depthtest, std::string depthwrite, std::string shader);
 
-        void insertTexture (std::string texture);
+        void insertTexture (const std::string& texture);
     private:
         std::string m_blending;
         std::string m_cullmode;

+ 58 - 0
wallpaperengine/core/objects/particles/controlpoint.cpp

@@ -0,0 +1,58 @@
+#include "controlpoint.h"
+
+#include "../../../core.h"
+
+using namespace wp::core::objects::particles;
+
+controlpoint* controlpoint::fromJSON (json data)
+{
+    json::const_iterator flags_it = data.find ("flags");
+    json::const_iterator id_it = data.find ("id");
+    json::const_iterator offset_it = data.find ("offset");
+
+    if (id_it == data.end ())
+    {
+        throw std::runtime_error ("Particle's control point must have id");
+    }
+
+    controlpoint* controlpoint = new class controlpoint (*id_it, 0);
+
+    if (offset_it != data.end ())
+    {
+        controlpoint->setOffset (wp::core::ato3vf (*offset_it));
+    }
+
+    if (flags_it != data.end ())
+    {
+        controlpoint->setFlags (*flags_it);
+    }
+
+    return controlpoint;
+}
+
+controlpoint::controlpoint (irr::u32 id, irr::u32 flags) :
+    m_id (id),
+    m_flags (flags),
+    m_offset (irr::core::vector3df ())
+{
+}
+
+void controlpoint::setOffset (const irr::core::vector3df& offset)
+{
+    this->m_offset = offset;
+}
+
+void controlpoint::setFlags (irr::u32 flags)
+{
+    this->m_flags = flags;
+}
+
+irr::core::vector3df* controlpoint::getOffset ()
+{
+    return &this->m_offset;
+}
+
+irr::u32 controlpoint::getFlags ()
+{
+    return this->m_flags;
+}

+ 29 - 0
wallpaperengine/core/objects/particles/controlpoint.h

@@ -0,0 +1,29 @@
+#pragma once
+
+#include <nlohmann/json.hpp>
+#include <irrlicht/irrlicht.h>
+
+namespace wp::core::objects::particles
+{
+    using json = nlohmann::json;
+
+    class controlpoint
+    {
+    public:
+        irr::core::vector3df* getOffset ();
+        irr::u32 getFlags ();
+    protected:
+        friend class particle;
+
+        static controlpoint* fromJSON (json data);
+
+        controlpoint (irr::u32 id, irr::u32 flags = 0);
+
+        void setOffset (const irr::core::vector3df& offset);
+        void setFlags (irr::u32 flags);
+    private:
+        irr::u32 m_id;
+        irr::u32 m_flags;
+        irr::core::vector3df m_offset;
+    };
+};

+ 110 - 0
wallpaperengine/core/objects/particles/emitter.cpp

@@ -0,0 +1,110 @@
+#include "emitter.h"
+
+#include "../../../core.h"
+
+using namespace wp::core::objects::particles;
+
+emitter* emitter::fromJSON (json data)
+{
+    json::const_iterator directions_it = data.find ("directions");
+    json::const_iterator distancemax_it = data.find ("distancemax");
+    json::const_iterator distancemin_it = data.find ("distancemin");
+    json::const_iterator id_it = data.find ("id");
+    json::const_iterator name_it = data.find ("name");
+    json::const_iterator origin_it = data.find ("origin");
+    json::const_iterator rate_it = data.find ("rate");
+
+    if (directions_it == data.end ())
+    {
+        throw std::runtime_error ("Particle emitter must have direction specified");
+    }
+
+    if (distancemax_it == data.end ())
+    {
+        throw std::runtime_error ("Particle emitter must have maximum distance");
+    }
+
+    if (distancemin_it == data.end ())
+    {
+        throw std::runtime_error ("Particle emitter must have minimum distance");
+    }
+
+    if (id_it == data.end ())
+    {
+        throw std::runtime_error ("Particle emitter must have an id");
+    }
+
+    if (name_it == data.end ())
+    {
+        throw std::runtime_error ("Particle emitter must have a name");
+    }
+
+    if (origin_it == data.end ())
+    {
+        throw std::runtime_error ("Particle emitter must have an origin");
+    }
+
+    if (rate_it == data.end ())
+    {
+        throw std::runtime_error ("Particle emitter must have a rate");
+    }
+
+    return new emitter (
+        wp::core::ato3vf (*directions_it),
+        *distancemax_it,
+        *distancemin_it,
+        *id_it,
+        *name_it,
+        wp::core::ato3vf (*origin_it),
+        *rate_it
+    );
+}
+
+emitter::emitter (
+        const irr::core::vector3df& directions,
+        irr::u32 distancemax,
+        irr::u32 distancemin,
+        irr::u32 id,
+        std::string name,
+        const irr::core::vector3df& origin,
+        irr::f64 rate):
+    m_directions (directions),
+    m_distancemax (distancemax),
+    m_distancemin (distancemin),
+    m_id (id),
+    m_name (std::move(name)),
+    m_origin (origin),
+    m_rate (rate)
+{
+}
+
+
+const std::string& emitter::getName () const
+{
+    return this->m_name;
+}
+
+irr::u32 emitter::getDistanceMax () const
+{
+    return this->m_distancemax;
+}
+
+irr::u32 emitter::getDistanceMin () const
+{
+    return this->m_distancemin;
+}
+
+irr::core::vector3df* emitter::getDirections ()
+{
+    return &this->m_directions;
+}
+
+irr::core::vector3df* emitter::getOrigin ()
+{
+    return &this->m_origin;
+}
+
+irr::f64 emitter::getRate () const
+{
+    return this->m_rate;
+}

+ 42 - 0
wallpaperengine/core/objects/particles/emitter.h

@@ -0,0 +1,42 @@
+#pragma once
+
+#include <nlohmann/json.hpp>
+#include <irrlicht/irrlicht.h>
+
+namespace wp::core::objects::particles
+{
+    using json = nlohmann::json;
+
+    class emitter
+    {
+    public:
+        const std::string& getName () const;
+        irr::u32 getDistanceMax () const;
+        irr::u32 getDistanceMin () const;
+        irr::core::vector3df* getDirections ();
+        irr::core::vector3df* getOrigin ();
+        irr::f64 getRate () const;
+    protected:
+        friend class particle;
+
+        static emitter* fromJSON (json data);
+
+        emitter (
+            const irr::core::vector3df& directions,
+            irr::u32 distancemax,
+            irr::u32 distancemin,
+            irr::u32 id,
+            std::string name,
+            const irr::core::vector3df& origin,
+            irr::f64 rate
+        );
+    private:
+        irr::core::vector3df m_directions;
+        irr::u32 m_distancemax;
+        irr::u32 m_distancemin;
+        irr::u32 m_id;
+        std::string m_name;
+        irr::core::vector3df m_origin;
+        irr::f64 m_rate;
+    };
+};

+ 68 - 0
wallpaperengine/core/objects/particles/initializer.cpp

@@ -0,0 +1,68 @@
+#include "initializer.h"
+
+#include "initializers/lifetimerandom.h"
+#include "initializers/sizerandom.h"
+#include "initializers/rotationrandom.h"
+#include "initializers/velocityrandom.h"
+#include "initializers/colorrandom.h"
+
+using namespace wp::core::objects::particles;
+
+initializer* initializer::fromJSON (json data)
+{
+    json::const_iterator id_it = data.find ("id");
+    json::const_iterator name_it = data.find ("name");
+
+    if (id_it == data.end ())
+    {
+        throw std::runtime_error ("Particle's initializer must have an id");
+    }
+
+    if (name_it == data.end ())
+    {
+        throw std::runtime_error ("Particle's initializer must have a name");
+    }
+
+    if (*name_it == "lifetimerandom")
+    {
+        return initializers::lifetimerandom::fromJSON (data, *id_it);
+    }
+    else if (*name_it == "sizerandom")
+    {
+        return initializers::sizerandom::fromJSON (data, *id_it);
+    }
+    else if (*name_it == "rotationrandom")
+    {
+        return initializers::rotationrandom::fromJSON (data, *id_it);
+    }
+    else if (*name_it == "velocityrandom")
+    {
+        return initializers::velocityrandom::fromJSON (data, *id_it);
+    }
+    else if (*name_it == "colorrandom")
+    {
+        return initializers::colorrandom::fromJSON (data, *id_it);
+    }
+    else
+    {
+        throw std::runtime_error ("Particle's got an unknown initializer");
+    }
+}
+
+
+initializer::initializer (irr::u32 id, std::string name) :
+    m_id (id),
+    m_name (std::move(name))
+{
+}
+
+
+std::string& initializer::getName ()
+{
+    return this->m_name;
+}
+
+irr::u32 initializer::getId ()
+{
+    return this->m_id;
+}

+ 25 - 0
wallpaperengine/core/objects/particles/initializer.h

@@ -0,0 +1,25 @@
+#pragma once
+
+#include <nlohmann/json.hpp>
+#include <irrlicht/irrlicht.h>
+
+namespace wp::core::objects::particles
+{
+    using json = nlohmann::json;
+
+    class initializer
+    {
+    public:
+        std::string& getName ();
+        irr::u32 getId ();
+    protected:
+        friend class particle;
+
+        static initializer* fromJSON (json data);
+
+        initializer (irr::u32 id, std::string name);
+    private:
+        irr::u32 m_id;
+        std::string m_name;
+    };
+};

+ 45 - 0
wallpaperengine/core/objects/particles/initializers/colorrandom.cpp

@@ -0,0 +1,45 @@
+#include "colorrandom.h"
+
+#include "../../../../core.h"
+
+using namespace wp::core::objects::particles::initializers;
+
+colorrandom* colorrandom::fromJSON (json data, irr::u32 id)
+{
+    json::const_iterator min_it = data.find ("min");
+    json::const_iterator max_it = data.find ("max");
+
+    if (min_it == data.end ())
+    {
+        throw std::runtime_error ("Colorrandom initializer must have a minimum value");
+    }
+
+    if (max_it == data.end ())
+    {
+        throw std::runtime_error ("Colorrandom initializer must have a maximum value");
+    }
+
+    return new colorrandom (
+        id,
+        wp::core::atoSColor (*min_it),
+        wp::core::atoSColor (*max_it)
+    );
+}
+
+
+colorrandom::colorrandom (irr::u32 id, irr::video::SColor min, irr::video::SColor max) :
+    initializer (id, "colorrandom"),
+    m_min (min),
+    m_max (max)
+{
+}
+
+irr::video::SColor* colorrandom::getMinimum ()
+{
+    return &this->m_min;
+}
+
+irr::video::SColor* colorrandom::getMaximum ()
+{
+    return &this->m_max;
+}

+ 25 - 0
wallpaperengine/core/objects/particles/initializers/colorrandom.h

@@ -0,0 +1,25 @@
+#pragma once
+
+#include "../initializer.h"
+
+#include <nlohmann/json.hpp>
+#include <irrlicht/irrlicht.h>
+
+namespace wp::core::objects::particles::initializers
+{
+    class colorrandom : initializer
+    {
+    public:
+        irr::video::SColor* getMinimum ();
+        irr::video::SColor* getMaximum ();
+    protected:
+        friend class initializer;
+
+        static colorrandom* fromJSON (json data, irr::u32 id);
+
+        colorrandom (irr::u32 id, irr::video::SColor min, irr::video::SColor max);
+    private:
+        irr::video::SColor m_max;
+        irr::video::SColor m_min;
+    };
+};

+ 39 - 0
wallpaperengine/core/objects/particles/initializers/lifetimerandom.cpp

@@ -0,0 +1,39 @@
+#include "lifetimerandom.h"
+
+using namespace wp::core::objects::particles::initializers;
+
+lifetimerandom* lifetimerandom::fromJSON (json data, irr::u32 id)
+{
+    json::const_iterator min_it = data.find ("min");
+    json::const_iterator max_it = data.find ("max");
+
+    if (min_it == data.end ())
+    {
+        throw std::runtime_error ("Lifetimerandom initializer must have a minimum value");
+    }
+
+    if (max_it == data.end ())
+    {
+        throw std::runtime_error ("Lifetimerandom initializer must have a maximum value");
+    }
+
+    return new lifetimerandom (id, *min_it, *max_it);
+}
+
+
+lifetimerandom::lifetimerandom (irr::u32 id, irr::u32 min, irr::u32 max) :
+    initializer (id, "lifetimerandom"),
+    m_min (min),
+    m_max (max)
+{
+}
+
+irr::u32 lifetimerandom::getMinimum ()
+{
+    return this->m_min;
+}
+
+irr::u32 lifetimerandom::getMaximum ()
+{
+    return this->m_max;
+}

+ 25 - 0
wallpaperengine/core/objects/particles/initializers/lifetimerandom.h

@@ -0,0 +1,25 @@
+#pragma once
+
+#include "../initializer.h"
+
+#include <nlohmann/json.hpp>
+#include <irrlicht/irrlicht.h>
+
+namespace wp::core::objects::particles::initializers
+{
+    class lifetimerandom : initializer
+    {
+    public:
+        irr::u32 getMinimum ();
+        irr::u32 getMaximum ();
+    protected:
+        friend class initializer;
+
+        static lifetimerandom* fromJSON (json data, irr::u32 id);
+
+        lifetimerandom (irr::u32 id, irr::u32 min, irr::u32 max);
+    private:
+        irr::u32 m_max;
+        irr::u32 m_min;
+    };
+};

+ 38 - 0
wallpaperengine/core/objects/particles/initializers/rotationrandom.cpp

@@ -0,0 +1,38 @@
+#include "rotationrandom.h"
+
+using namespace wp::core::objects::particles::initializers;
+
+rotationrandom* rotationrandom::fromJSON (json data, irr::u32 id)
+{
+    json::const_iterator min_it = data.find ("min");
+    json::const_iterator max_it = data.find ("max");
+
+    if (min_it == data.end ())
+    {
+        throw std::runtime_error ("Rotationrandom initializer must have a minimum value");
+    }
+
+    if (max_it == data.end ())
+    {
+        throw std::runtime_error ("Rotationrandom initializer must have a maximum value");
+    }
+
+    return new rotationrandom (id, *min_it, *max_it);
+}
+
+rotationrandom::rotationrandom (irr::u32 id, irr::f64 min, irr::f64 max) :
+    initializer (id, "rotationrandom"),
+    m_min (min),
+    m_max (max)
+{
+}
+
+irr::u32 rotationrandom::getMinimum ()
+{
+    return this->m_min;
+}
+
+irr::u32 rotationrandom::getMaximum ()
+{
+    return this->m_max;
+}

+ 25 - 0
wallpaperengine/core/objects/particles/initializers/rotationrandom.h

@@ -0,0 +1,25 @@
+#pragma once
+
+#include "../initializer.h"
+
+#include <nlohmann/json.hpp>
+#include <irrlicht/irrlicht.h>
+
+namespace wp::core::objects::particles::initializers
+{
+    class rotationrandom : initializer
+    {
+    public:
+        irr::u32 getMinimum ();
+        irr::u32 getMaximum ();
+    protected:
+        friend class initializer;
+
+        static rotationrandom* fromJSON (json data, irr::u32 id);
+
+        rotationrandom (irr::u32 id, irr::f64 min, irr::f64 max);
+    private:
+        irr::f64 m_max;
+        irr::f64 m_min;
+    };
+};

+ 38 - 0
wallpaperengine/core/objects/particles/initializers/sizerandom.cpp

@@ -0,0 +1,38 @@
+#include "sizerandom.h"
+
+using namespace wp::core::objects::particles::initializers;
+
+sizerandom* sizerandom::fromJSON (json data, irr::u32 id)
+{
+    json::const_iterator min_it = data.find ("min");
+    json::const_iterator max_it = data.find ("max");
+
+    if (min_it == data.end ())
+    {
+        throw std::runtime_error ("Sizerandom initializer must have a minimum value");
+    }
+
+    if (max_it == data.end ())
+    {
+        throw std::runtime_error ("Sizerandom initializer must have a maximum value");
+    }
+
+    return new sizerandom (id, *min_it, *max_it);
+}
+
+sizerandom::sizerandom (irr::u32 id, irr::u32 min, irr::u32 max) :
+    initializer (id, "sizerandom"),
+    m_min (min),
+    m_max (max)
+{
+}
+
+irr::u32 sizerandom::getMinimum ()
+{
+    return this->m_min;
+}
+
+irr::u32 sizerandom::getMaximum ()
+{
+    return this->m_max;
+}

+ 25 - 0
wallpaperengine/core/objects/particles/initializers/sizerandom.h

@@ -0,0 +1,25 @@
+#pragma once
+
+#include "../initializer.h"
+
+#include <nlohmann/json.hpp>
+#include <irrlicht/irrlicht.h>
+
+namespace wp::core::objects::particles::initializers
+{
+    class sizerandom : initializer
+    {
+    public:
+        irr::u32 getMinimum ();
+        irr::u32 getMaximum ();
+    protected:
+        friend class initializer;
+
+        static sizerandom* fromJSON (json data, irr::u32 id);
+
+        sizerandom (irr::u32 id, irr::u32 min, irr::u32 max);
+    private:
+        irr::u32 m_max;
+        irr::u32 m_min;
+    };
+};

+ 45 - 0
wallpaperengine/core/objects/particles/initializers/velocityrandom.cpp

@@ -0,0 +1,45 @@
+#include "velocityrandom.h"
+
+#include "../../../../core.h"
+
+using namespace wp::core::objects::particles::initializers;
+
+velocityrandom* velocityrandom::fromJSON (json data, irr::u32 id)
+{
+    json::const_iterator min_it = data.find ("min");
+    json::const_iterator max_it = data.find ("max");
+
+    if (min_it == data.end ())
+    {
+        throw std::runtime_error ("Velocityrandom initializer must have a minimum value");
+    }
+
+    if (max_it == data.end ())
+    {
+        throw std::runtime_error ("Velocityrandom initializer must have a maximum value");
+    }
+
+    return new velocityrandom (
+        id,
+        wp::core::ato3vf (*min_it),
+        wp::core::ato3vf (*max_it)
+    );
+}
+
+
+velocityrandom::velocityrandom (irr::u32 id, irr::core::vector3df min, irr::core::vector3df max) :
+    initializer (id, "velocityrandom"),
+    m_min (min),
+    m_max (max)
+{
+}
+
+irr::core::vector3df* velocityrandom::getMinimum ()
+{
+    return &this->m_min;
+}
+
+irr::core::vector3df* velocityrandom::getMaximum ()
+{
+    return &this->m_max;
+}

+ 25 - 0
wallpaperengine/core/objects/particles/initializers/velocityrandom.h

@@ -0,0 +1,25 @@
+#pragma once
+
+#include "../initializer.h"
+
+#include <nlohmann/json.hpp>
+#include <irrlicht/irrlicht.h>
+
+namespace wp::core::objects::particles::initializers
+{
+    class velocityrandom : initializer
+    {
+    public:
+        irr::core::vector3df* getMinimum ();
+        irr::core::vector3df* getMaximum ();
+    protected:
+        friend class initializer;
+
+        static velocityrandom* fromJSON (json data, irr::u32 id);
+
+        velocityrandom (irr::u32 id, irr::core::vector3df min, irr::core::vector3df max);
+    private:
+        irr::core::vector3df m_max;
+        irr::core::vector3df m_min;
+    };
+};

+ 128 - 0
wallpaperengine/core/objects/particles/particle.cpp

@@ -0,0 +1,128 @@
+#include "particle.h"
+#include "../../../fs/utils.h"
+
+#include <irrlicht/irrlicht.h>
+
+using namespace wp::core::objects::particles;
+
+particle* particle::fromFile (
+    const irr::io::path& filename,
+    irr::u32 id,
+    std::string name,
+    const irr::core::vector3df& origin,
+    const irr::core::vector3df& scale)
+{
+    json data = json::parse (wp::fs::utils::loadFullFile (filename));
+    json::const_iterator controlpoint_it = data.find ("controlpoint");
+    json::const_iterator starttime_it = data.find ("starttime");
+    json::const_iterator maxcount_it = data.find ("maxcount");
+    json::const_iterator emitter_it = data.find ("emitter");
+    json::const_iterator initializer_it = data.find ("initializer");
+
+    if (starttime_it == data.end ())
+    {
+        throw std::runtime_error ("Particles must have start time");
+    }
+
+    if (maxcount_it == data.end ())
+    {
+        throw std::runtime_error ("Particles must have maximum count");
+    }
+
+    if (emitter_it == data.end ())
+    {
+        throw std::runtime_error ("Particles must have emitters");
+    }
+
+    if (initializer_it == data.end ())
+    {
+        throw std::runtime_error ("Particles must have initializers");
+    }
+
+    particle* particle = new class particle (
+        *starttime_it,
+        *maxcount_it,
+        id,
+        name,
+        origin,
+        scale
+    );
+
+    if (controlpoint_it != data.end ())
+    {
+        json::const_iterator cur = (*controlpoint_it).begin ();
+        json::const_iterator end = (*controlpoint_it).end ();
+
+        for (; cur != end; cur ++)
+        {
+            particle->insertControlPoint (
+                controlpoint::fromJSON (*cur)
+            );
+        }
+    }
+
+    json::const_iterator cur = (*emitter_it).begin ();
+    json::const_iterator end = (*emitter_it).end ();
+
+    for (; cur != end; cur ++)
+    {
+        particle->insertEmitter (
+            emitter::fromJSON (*cur)
+        );
+    }
+
+    cur = (*initializer_it).begin ();
+    end = (*initializer_it).end ();
+
+    for (; cur != end; cur ++)
+    {
+        particle->insertInitializer (
+            initializer::fromJSON (*cur)
+        );
+    }
+
+    return particle;
+}
+
+particle::particle (
+        irr::u32 starttime,
+        irr::u32 maxcount,
+        irr::u32 id,
+        std::string name,
+        const irr::core::vector3df& origin,
+        const irr::core::vector3df& scale):
+    object (true, id, std::move(name), origin, scale, irr::core::vector3df ()),
+    m_starttime (starttime),
+    m_maxcount (maxcount)
+{
+}
+
+std::vector<emitter*>* particle::getEmitters ()
+{
+    return &this->m_emitters;
+}
+
+std::vector<controlpoint*>* particle::getControlPoints ()
+{
+    return &this->m_controlpoints;
+}
+
+std::vector<initializer*>* particle::getInitializers ()
+{
+    return &this->m_initializers;
+}
+
+void particle::insertControlPoint (controlpoint* controlpoint)
+{
+    this->m_controlpoints.push_back (controlpoint);
+}
+
+void particle::insertEmitter (emitter* emitter)
+{
+    this->m_emitters.push_back (emitter);
+}
+
+void particle::insertInitializer (initializer* initializer)
+{
+    this->m_initializers.push_back (initializer);
+}

+ 51 - 0
wallpaperengine/core/objects/particles/particle.h

@@ -0,0 +1,51 @@
+#pragma once
+
+#include <irrlicht/irrlicht.h>
+#include <nlohmann/json.hpp>
+
+#include "controlpoint.h"
+#include "emitter.h"
+#include "initializer.h"
+
+#include "../../object.h"
+
+namespace wp::core::objects::particles
+{
+    using json = nlohmann::json;
+
+    class particle : object
+    {
+    public:
+        std::vector<emitter*>* getEmitters ();
+        std::vector<controlpoint*>* getControlPoints ();
+        std::vector<initializer*>* getInitializers ();
+    protected:
+        friend class object;
+
+        static particle* fromFile (
+                const irr::io::path& filename,
+                irr::u32 id,
+                std::string name,
+                const irr::core::vector3df& origin,
+                const irr::core::vector3df& scale
+        );
+
+        particle (
+            irr::u32 starttime,
+            irr::u32 maxcount,
+            irr::u32 id,
+            std::string name,
+            const irr::core::vector3df& origin,
+            const irr::core::vector3df& scale
+        );
+        void insertControlPoint (controlpoint* controlpoint);
+        void insertEmitter (emitter* emitter);
+        void insertInitializer (initializer* initializer);
+    private:
+        irr::u32 m_starttime;
+        irr::u32 m_maxcount;
+        std::vector<controlpoint*> m_controlpoints;
+        std::vector<emitter*> m_emitters;
+        std::vector<initializer*> m_initializers;
+    };
+};