Browse Source

Fix particles and some fun in the background LOL

Eduardo Bart 8 years ago
parent
commit
9907e9e5c7

BIN
data/particles/particle.png View File


+ 35
- 0
data/particles/particles.otps View File

@@ -0,0 +1,35 @@
1
+Particle
2
+  name: default_particle
3
+
4
+  duration: 10
5
+  min-position-radius: 0
6
+  max-position-radius: 256
7
+  min-position-angle: 0
8
+  max-position-angle: 360
9
+  velocity: 10
10
+  min-velocity-angle: 0
11
+  max-velocity-angle: 360
12
+  colors: #ffffff00 #ffffffff #00000000
13
+  colors-stops: 0 0.1 1
14
+  size: 24 24
15
+  texture: /data/particles/particle
16
+  composition-mode: normal
17
+
18
+Effect
19
+  name: background-effect
20
+  description: Effect for the game background
21
+
22
+  System
23
+    position: 0 0
24
+
25
+    Emitter
26
+      position: 0 0
27
+      delay: 0
28
+      duration: 0
29
+      burst-rate: 50
30
+      burst-count: 1
31
+      particle-type: default_particle
32
+
33
+    AttractionAffector
34
+      position: 0 0
35
+      acceleration: 1000

+ 0
- 4
data/styles/10-panels.otui View File

@@ -12,10 +12,6 @@ ScrollableFlatPanel < ScrollablePanel
12 12
   image-source: /images/ui/panel_flat
13 13
   image-border: 1
14 14
 
15
-ParticlesFlatPanel < Panel
16
-  image-source: /images/ui/panel_flat
17
-  image-border: 1
18
-
19 15
 LightFlatPanel < Panel
20 16
   image-source: /images/ui/panel_lightflat
21 17
   image-border: 1

+ 62
- 0
modules/client_background/background.otui View File

@@ -9,6 +9,68 @@ Panel
9 9
   anchors.bottom: parent.bottom
10 10
   margin-top: 1
11 11
   focusable: false
12
+  @onSetup: |
13
+    scheduleEvent(function()
14
+      local count = 0
15
+      cycleEvent(function()
16
+        if count > 360 then return end
17
+        self:setRotation(count)
18
+        count = count + 5
19
+      end, 10)
20
+    end, 10)
21
+
22
+  UIParticles
23
+    anchors.fill: parent
24
+    effect: background-effect
25
+    reference-pos: 0.5 0.25
26
+
27
+  Label
28
+    text: :O Just For Fun LOL ^.^
29
+    font: sans-bold-16px
30
+    color: black
31
+    background: #ffffff60
32
+    anchors.top: parent.top
33
+    anchors.horizontalCenter: parent.horizontalCenter
34
+    margin-left: 10
35
+    margin-top: 40
36
+    height: 24
37
+    rotation: -15
38
+    @onSetup: |
39
+      local count = 0
40
+      cycleEvent(function()
41
+        local text = ':O Just For Fun LOL ^.^'
42
+        self:setText(string.sub(text, 0, count))
43
+        if count > #text + 10 then count = 0 end
44
+        count = count + 1
45
+      end, 100)
46
+
47
+  Label
48
+    text: PLEASE REMOVE THAT SHIT!
49
+    font: sans-bold-16px
50
+    color: black
51
+    background: #ffffff60
52
+    anchors.bottom: parent.bottom
53
+    anchors.horizontalCenter: parent.horizontalCenter
54
+    margin-left: 10
55
+    margin-bottom: 40
56
+    height: 24
57
+    rotation: 15
58
+    visible: false
59
+    @onSetup: scheduleEvent(function() self:show() end, 4000)
60
+
61
+  Label
62
+    text: WTF IS WRONG WITH THIS BACKGROUND?
63
+    font: sans-bold-16px
64
+    color: pink
65
+    background: #ffffff99
66
+    anchors.top: parent.top
67
+    anchors.right: parent.right
68
+    margin-left: 10
69
+    margin-top: 80
70
+    height: 24
71
+    rotation: 10
72
+    visible: false
73
+    @onSetup: scheduleEvent(function() self:show() end, 8000)
12 74
 
13 75
   UILabel
14 76
     id: clientVersionLabel

+ 6
- 1
modules/client_styles/styles.lua View File

@@ -13,7 +13,12 @@ function init()
13 13
     end
14 14
   end
15 15
 
16
-  -- TODO load particles
16
+  local particles = g_resources.listDirectoryFiles('/particles')
17
+  for _i,particle in pairs(particles) do
18
+    if string.ends(particle, '.otps') then
19
+      g_particles.importParticle('/particles/' .. particle)
20
+    end
21
+  end
17 22
 end
18 23
 
19 24
 function terminate()

+ 3
- 1
src/framework/CMakeLists.txt View File

@@ -320,11 +320,13 @@ if(FRAMEWORK_GRAPHICS)
320 320
         ${CMAKE_CURRENT_LIST_DIR}/graphics/particleaffector.cpp
321 321
         ${CMAKE_CURRENT_LIST_DIR}/graphics/particleaffector.h
322 322
         ${CMAKE_CURRENT_LIST_DIR}/graphics/particle.cpp
323
+        ${CMAKE_CURRENT_LIST_DIR}/graphics/particle.h
324
+        ${CMAKE_CURRENT_LIST_DIR}/graphics/particletype.cpp
325
+        ${CMAKE_CURRENT_LIST_DIR}/graphics/particletype.h
323 326
         ${CMAKE_CURRENT_LIST_DIR}/graphics/particleemitter.cpp
324 327
         ${CMAKE_CURRENT_LIST_DIR}/graphics/particleemitter.h
325 328
         ${CMAKE_CURRENT_LIST_DIR}/graphics/particleeffect.cpp
326 329
         ${CMAKE_CURRENT_LIST_DIR}/graphics/particleeffect.h
327
-        ${CMAKE_CURRENT_LIST_DIR}/graphics/particle.h
328 330
         ${CMAKE_CURRENT_LIST_DIR}/graphics/particlemanager.cpp
329 331
         ${CMAKE_CURRENT_LIST_DIR}/graphics/particlemanager.h
330 332
         ${CMAKE_CURRENT_LIST_DIR}/graphics/particlesystem.cpp

+ 1
- 1
src/framework/core/graphicalapplication.cpp View File

@@ -205,7 +205,7 @@ void GraphicalApplication::poll()
205 205
 
206 206
     // poll window input events
207 207
     g_window.poll();
208
-    g_particles.update();
208
+    g_particles.poll();
209 209
     g_textures.poll();
210 210
 
211 211
     Application::poll();

+ 2
- 0
src/framework/graphics/declarations.h View File

@@ -38,6 +38,7 @@ class Shader;
38 38
 class ShaderProgram;
39 39
 class PainterShaderProgram;
40 40
 class Particle;
41
+class ParticleType;
41 42
 class ParticleEmitter;
42 43
 class ParticleAffector;
43 44
 class ParticleSystem;
@@ -54,6 +55,7 @@ typedef stdext::shared_object_ptr<Shader> ShaderPtr;
54 55
 typedef stdext::shared_object_ptr<ShaderProgram> ShaderProgramPtr;
55 56
 typedef stdext::shared_object_ptr<PainterShaderProgram> PainterShaderProgramPtr;
56 57
 typedef stdext::shared_object_ptr<Particle> ParticlePtr;
58
+typedef stdext::shared_object_ptr<ParticleType> ParticleTypePtr;
57 59
 typedef stdext::shared_object_ptr<ParticleEmitter> ParticleEmitterPtr;
58 60
 typedef stdext::shared_object_ptr<ParticleAffector> ParticleAffectorPtr;
59 61
 typedef stdext::shared_object_ptr<ParticleSystem> ParticleSystemPtr;

+ 8
- 19
src/framework/graphics/particle.cpp View File

@@ -50,10 +50,8 @@ void Particle::render()
50 50
     if(!m_texture)
51 51
         g_painter->drawFilledRect(m_rect);
52 52
     else {
53
-        g_painter->saveState();
54 53
         g_painter->setCompositionMode(m_compositionMode);
55 54
         g_painter->drawTexturedRect(m_rect, m_texture);
56
-        g_painter->restoreSavedState();
57 55
     }
58 56
 }
59 57
 
@@ -94,31 +92,22 @@ void Particle::updatePosition(float elapsedTime)
94 92
 
95 93
 void Particle::updateSize()
96 94
 {
97
-    Size size = m_startSize + (m_finalSize - m_startSize) / m_duration * m_elapsedTime;
98
-    if(m_size != size) {
99
-        m_size = size;
100
-    }
101
-
95
+    m_size = m_startSize + (m_finalSize - m_startSize) / m_duration * m_elapsedTime;
102 96
     m_rect.resize(m_size);
103 97
 }
104 98
 
105 99
 void Particle::updateColor()
106 100
 {
107
-    if(m_elapsedTime < m_colorsStops[1]) {
108
-        Color color = Color(m_colors[0].r() + (m_colors[1].r() - m_colors[0].r()) / (m_colorsStops[1] - m_colorsStops[0]) * (m_elapsedTime - m_colorsStops[0]),
109
-                            m_colors[0].g() + (m_colors[1].g() - m_colors[0].g()) / (m_colorsStops[1] - m_colorsStops[0]) * (m_elapsedTime - m_colorsStops[0]),
110
-                            m_colors[0].b() + (m_colors[1].b() - m_colors[0].b()) / (m_colorsStops[1] - m_colorsStops[0]) * (m_elapsedTime - m_colorsStops[0]),
111
-                            m_colors[0].a() + (m_colors[1].a() - m_colors[0].a()) / (m_colorsStops[1] - m_colorsStops[0]) * (m_elapsedTime - m_colorsStops[0]));
112
-        if(m_color != color) {
113
-            m_color = color;
114
-        }
115
-    }
116
-    else {
101
+    float currentLife = m_elapsedTime / m_duration;
102
+    if(currentLife < m_colorsStops[1]) {
103
+        float range = m_colorsStops[1] - m_colorsStops[0];
104
+        float factor = (currentLife - m_colorsStops[0])/range;
105
+        m_color = m_colors[0] * (1.0f - factor) + m_colors[1] * factor;
106
+    } else {
117 107
         if(m_colors.size() > 1) {
118 108
             m_colors.erase(m_colors.begin());
119 109
             m_colorsStops.erase(m_colorsStops.begin());
120
-        }
121
-        else {
110
+        } else {
122 111
             if(m_color != m_colors[0]) {
123 112
                 m_color = m_colors[0];
124 113
             }

+ 0
- 1
src/framework/graphics/particle.h View File

@@ -25,7 +25,6 @@
25 25
 
26 26
 #include "declarations.h"
27 27
 #include "painter.h"
28
-#include <framework/global.h>
29 28
 
30 29
 class Particle : public stdext::shared_object
31 30
 {

+ 9
- 18
src/framework/graphics/particleaffector.cpp View File

@@ -46,7 +46,7 @@ void ParticleAffector::update(float elapsedTime)
46 46
     m_elapsedTime += elapsedTime;
47 47
 }
48 48
 
49
-bool ParticleAffector::load(const OTMLNodePtr& node)
49
+void ParticleAffector::load(const OTMLNodePtr& node)
50 50
 {
51 51
     float minDelay = 0, maxDelay = 0;
52 52
     float minDuration = -1, maxDuration = -1;
@@ -55,17 +55,14 @@ bool ParticleAffector::load(const OTMLNodePtr& node)
55 55
         if(childNode->tag() == "delay") {
56 56
             minDelay = childNode->value<float>();
57 57
             maxDelay = childNode->value<float>();
58
-        }
59
-        else if(childNode->tag() == "min-delay")
58
+        } else if(childNode->tag() == "min-delay")
60 59
             minDelay = childNode->value<float>();
61 60
         else if(childNode->tag() == "max-delay")
62 61
             maxDelay = childNode->value<float>();
63
-
64
-        if(childNode->tag() == "duration") {
62
+        else if(childNode->tag() == "duration") {
65 63
             minDuration = childNode->value<float>();
66 64
             maxDuration = childNode->value<float>();
67
-        }
68
-        else if(childNode->tag() == "min-duration")
65
+        } else if(childNode->tag() == "min-duration")
69 66
             minDuration = childNode->value<float>();
70 67
         else if(childNode->tag() == "max-duration")
71 68
             maxDuration = childNode->value<float>();
@@ -73,14 +70,11 @@ bool ParticleAffector::load(const OTMLNodePtr& node)
73 70
 
74 71
     m_delay = stdext::random_range(minDelay, maxDelay);
75 72
     m_duration = stdext::random_range(minDuration, maxDuration);
76
-
77
-    return true;
78 73
 }
79 74
 
80
-bool GravityAffector::load(const OTMLNodePtr& node)
75
+void GravityAffector::load(const OTMLNodePtr& node)
81 76
 {
82
-    if(!ParticleAffector::load(node))
83
-        return false;
77
+    ParticleAffector::load(node);
84 78
 
85 79
     m_angle = 270 * DEG_TO_RAD;
86 80
     m_gravity = 9.8;
@@ -91,7 +85,6 @@ bool GravityAffector::load(const OTMLNodePtr& node)
91 85
         else if(childNode->tag() == "gravity")
92 86
             m_gravity = childNode->value<float>();
93 87
     }
94
-    return true;
95 88
 }
96 89
 
97 90
 void GravityAffector::updateParticle(const ParticlePtr& particle, float elapsedTime)
@@ -100,14 +93,13 @@ void GravityAffector::updateParticle(const ParticlePtr& particle, float elapsedT
100 93
         return;
101 94
 
102 95
     PointF velocity = particle->getVelocity();
103
-    velocity += PointF(m_gravity * elapsedTime * cos(m_angle), m_gravity * elapsedTime * sin(m_angle));
96
+    velocity += PointF(m_gravity * elapsedTime * std::cos(m_angle), m_gravity * elapsedTime * std::sin(m_angle));
104 97
     particle->setVelocity(velocity);
105 98
 }
106 99
 
107
-bool AttractionAffector::load(const OTMLNodePtr& node)
100
+void AttractionAffector::load(const OTMLNodePtr& node)
108 101
 {
109
-    if(!ParticleAffector::load(node))
110
-        return false;
102
+    ParticleAffector::load(node);
111 103
 
112 104
     m_acceleration = 32;
113 105
     m_reduction = 0;
@@ -123,7 +115,6 @@ bool AttractionAffector::load(const OTMLNodePtr& node)
123 115
         else if(childNode->tag() == "repelish")
124 116
             m_repelish = childNode->value<bool>();
125 117
     }
126
-    return true;
127 118
 }
128 119
 
129 120
 void AttractionAffector::updateParticle(const ParticlePtr& particle, float elapsedTime)

+ 3
- 3
src/framework/graphics/particleaffector.h View File

@@ -32,7 +32,7 @@ public:
32 32
     ParticleAffector();
33 33
 
34 34
     void update(float elapsedTime);
35
-    virtual bool load(const OTMLNodePtr& node);
35
+    virtual void load(const OTMLNodePtr& node);
36 36
     virtual void updateParticle(const ParticlePtr&, float) {}
37 37
 
38 38
     bool hasFinished() { return m_finished; }
@@ -45,7 +45,7 @@ protected:
45 45
 
46 46
 class GravityAffector : public ParticleAffector {
47 47
 public:
48
-    bool load(const OTMLNodePtr& node);
48
+    void load(const OTMLNodePtr& node);
49 49
     void updateParticle(const ParticlePtr& particle, float elapsedTime);
50 50
 
51 51
 private:
@@ -54,7 +54,7 @@ private:
54 54
 
55 55
 class AttractionAffector : public ParticleAffector {
56 56
 public:
57
-    bool load(const OTMLNodePtr& node);
57
+    void load(const OTMLNodePtr& node);
58 58
     void updateParticle(const ParticlePtr& particle, float elapsedTime);
59 59
 
60 60
 private:

+ 14
- 20
src/framework/graphics/particleeffect.cpp View File

@@ -27,34 +27,29 @@ ParticleEffectType::ParticleEffectType()
27 27
 
28 28
 }
29 29
 
30
-bool ParticleEffectType::load(const OTMLNodePtr& node)
30
+void ParticleEffectType::load(const OTMLNodePtr& node)
31 31
 {
32
-    m_node = node;
32
+    m_node = node->clone();
33 33
     for(const OTMLNodePtr& childNode : node->children()) {
34
-        if(childNode->tag() == "name") {
35
-            setName(childNode->value());
36
-        }
37
-        else if(childNode->tag() == "description") {
38
-            setDescription(childNode->value());
39
-        }
34
+        if(childNode->tag() == "name")
35
+            m_name = childNode->value();
36
+        else if(childNode->tag() == "description")
37
+            m_description = childNode->value();
40 38
     }
41
-    return !m_name.empty();
42 39
 }
43 40
 
44
-bool ParticleEffect::load(const ParticleEffectTypePtr& effectType)
41
+void ParticleEffect::load(const ParticleEffectTypePtr& effectType)
45 42
 {
46 43
     if(!effectType)
47
-        return false;
44
+        stdext::throw_exception("effect type not found");
48 45
 
49 46
     for(const OTMLNodePtr& childNode : effectType->getNode()->children()) {
50 47
         if(childNode->tag() == "System") {
51 48
             ParticleSystemPtr system = ParticleSystemPtr(new ParticleSystem);
52
-            if(system->load(childNode)) {
53
-                m_systems.push_back(system);
54
-            }
49
+            system->load(childNode);
50
+            m_systems.push_back(system);
55 51
         }
56 52
     }
57
-    return true;
58 53
 }
59 54
 
60 55
 void ParticleEffect::render()
@@ -65,15 +60,14 @@ void ParticleEffect::render()
65 60
 
66 61
 void ParticleEffect::update()
67 62
 {
68
-    for(auto it = m_systems.begin(), end = m_systems.end(); it != end;) {
63
+    for(auto it = m_systems.begin(); it != m_systems.end();) {
69 64
         const ParticleSystemPtr& system = *it;
70 65
 
71 66
         if(system->hasFinished()) {
72 67
             it = m_systems.erase(it);
73
-            continue;
68
+        } else {
69
+            system->update();
70
+            ++it;
74 71
         }
75
-
76
-        system->update();
77
-        ++it;
78 72
     }
79 73
 }

+ 2
- 8
src/framework/graphics/particleeffect.h View File

@@ -33,20 +33,14 @@ class ParticleEffectType : public LuaObject
33 33
 public:
34 34
     ParticleEffectType();
35 35
 
36
-    bool load(const OTMLNodePtr& node);
37
-
38
-    void setName(const std::string& name) { m_name = name; }
39
-    void setFile(const std::string& file) { m_file = file; }
40
-    void setDescription(const std::string& description) { m_description = description; }
36
+    void load(const OTMLNodePtr& node);
41 37
 
42 38
     std::string getName() { return m_name; }
43
-    std::string getFile() { return m_file; }
44 39
     std::string getDescription() { return m_description; }
45 40
     OTMLNodePtr getNode() { return m_node; }
46 41
 
47 42
 private:
48 43
     std::string m_name;
49
-    std::string m_file;
50 44
     std::string m_description;
51 45
     OTMLNodePtr m_node;
52 46
 };
@@ -56,7 +50,7 @@ class ParticleEffect : public LuaObject
56 50
 public:
57 51
     ParticleEffect() {}
58 52
 
59
-    bool load(const ParticleEffectTypePtr& effectType);
53
+    void load(const ParticleEffectTypePtr& effectType);
60 54
     bool hasFinished() { return m_systems.size() == 0; }
61 55
     void render();
62 56
     void update();

+ 44
- 154
src/framework/graphics/particleemitter.cpp View File

@@ -25,39 +25,22 @@
25 25
 #include "particlesystem.h"
26 26
 #include <framework/core/clock.h>
27 27
 #include <framework/graphics/texturemanager.h>
28
+#include "particlemanager.h"
28 29
 
29 30
 ParticleEmitter::ParticleEmitter()
30 31
 {
31 32
     m_position = Point(0, 0);
32 33
     m_duration = -1;
33 34
     m_delay = 0;
34
-    m_burstRate = 1; m_burstCount = 32;
35
+    m_burstRate = 1;
36
+    m_burstCount = 32;
35 37
     m_currentBurst = 0;
36 38
     m_elapsedTime = 0;
37 39
     m_finished = false;
38 40
     m_active = false;
39
-
40
-    // particles default configuration. (make them reasonable for user detect missing properties on scripts)
41
-    m_pMinPositionRadius = 0;
42
-    m_pMaxPositionRadius = 3;
43
-    m_pMinPositionAngle = 0;
44
-    m_pMaxPositionAngle = 360;
45
-    m_pStartSize = Size(32, 32);
46
-    m_pFinalSize = Size(32, 32);
47
-    m_pMinDuration = 0;
48
-    m_pMaxDuration = 10;
49
-    m_pIgnorePhysicsAfter = -1;
50
-    m_pMinVelocity = 32;
51
-    m_pMaxVelocity = 64;
52
-    m_pMinVelocityAngle = 0;
53
-    m_pMaxVelocityAngle = 360;
54
-    m_pMinAcceleration = 32;
55
-    m_pMaxAcceleration = 64;
56
-    m_pMinAccelerationAngle = 0;
57
-    m_pMaxAccelerationAngle = 360;
58 41
 }
59 42
 
60
-bool ParticleEmitter::load(const OTMLNodePtr& node)
43
+void ParticleEmitter::load(const OTMLNodePtr& node)
61 44
 {
62 45
     for(const OTMLNodePtr& childNode : node->children()) {
63 46
         // self related
@@ -67,120 +50,24 @@ bool ParticleEmitter::load(const OTMLNodePtr& node)
67 50
             m_duration = childNode->value<float>();
68 51
         else if(childNode->tag() == "delay")
69 52
             m_delay = childNode->value<float>();
70
-        else if(childNode->tag() == "burstRate")
53
+        else if(childNode->tag() == "burst-rate")
71 54
             m_burstRate = childNode->value<float>();
72
-        else if(childNode->tag() == "burstCount")
55
+        else if(childNode->tag() == "burst-count")
73 56
             m_burstCount = childNode->value<int>();
74
-
75
-        // particles generation related
76
-        else if(childNode->tag() == "particle-position-radius") {
77
-            m_pMinPositionRadius = childNode->value<float>();
78
-            m_pMaxPositionRadius = childNode->value<float>();
79
-        }
80
-        else if(childNode->tag() == "particle-min-position-radius")
81
-            m_pMinPositionRadius = childNode->value<float>();
82
-        else if(childNode->tag() == "particle-max-position-radius")
83
-            m_pMaxPositionRadius = childNode->value<float>();
84
-        else if(childNode->tag() == "particle-position-angle") {
85
-            m_pMinPositionAngle = childNode->value<float>() * DEG_TO_RAD;
86
-            m_pMaxPositionAngle = childNode->value<float>() * DEG_TO_RAD;
87
-        }
88
-        else if(childNode->tag() == "particle-min-position-angle")
89
-            m_pMinPositionAngle = childNode->value<float>() * DEG_TO_RAD;
90
-        else if(childNode->tag() == "particle-max-position-angle")
91
-            m_pMaxPositionAngle = childNode->value<float>() * DEG_TO_RAD;
92
-
93
-        // velocity
94
-        else if(childNode->tag() == "particle-velocity") {
95
-            m_pMinVelocity = childNode->value<float>();
96
-            m_pMaxVelocity = childNode->value<float>();
97
-        }
98
-        else if(childNode->tag() == "particle-min-velocity")
99
-            m_pMinVelocity = childNode->value<float>();
100
-        else if(childNode->tag() == "particle-max-velocity")
101
-            m_pMaxVelocity = childNode->value<float>();
102
-        else if(childNode->tag() == "particle-velocity-angle") {
103
-            m_pMinVelocityAngle = childNode->value<float>() * DEG_TO_RAD;
104
-            m_pMaxVelocityAngle = childNode->value<float>() * DEG_TO_RAD;
105
-        }
106
-        else if(childNode->tag() == "particle-min-velocity-angle")
107
-            m_pMinVelocityAngle = childNode->value<float>() * DEG_TO_RAD;
108
-        else if(childNode->tag() == "particle-max-velocity-angle")
109
-            m_pMaxVelocityAngle = childNode->value<float>() * DEG_TO_RAD;
110
-        else if(childNode->tag() == "particle-acceleration") {
111
-            m_pMinAcceleration = childNode->value<float>();
112
-            m_pMaxAcceleration = childNode->value<float>();
113
-        }
114
-
115
-        // acceleration
116
-        else if(childNode->tag() == "particle-min-acceleration")
117
-            m_pMinAcceleration = childNode->value<float>();
118
-        else if(childNode->tag() == "particle-max-acceleration")
119
-            m_pMaxAcceleration = childNode->value<float>();
120
-        else if(childNode->tag() == "particle-acceleration-angle") {
121
-            m_pMinAccelerationAngle = childNode->value<float>() * DEG_TO_RAD;
122
-            m_pMaxAccelerationAngle = childNode->value<float>() * DEG_TO_RAD;
123
-        }
124
-        else if(childNode->tag() == "particle-min-acceleration-angle")
125
-            m_pMinAccelerationAngle = childNode->value<float>() * DEG_TO_RAD;
126
-        else if(childNode->tag() == "particle-max-acceleration-angle")
127
-            m_pMaxAccelerationAngle = childNode->value<float>() * DEG_TO_RAD;
128
-
129
-        // duration
130
-        else if(childNode->tag() == "particle-duration") {
131
-            m_pMinDuration = childNode->value<float>();
132
-            m_pMaxDuration = childNode->value<float>();
133
-        }
134
-        else if(childNode->tag() == "particle-min-duration")
135
-            m_pMinDuration = childNode->value<float>();
136
-        else if(childNode->tag() == "particle-max-duration")
137
-            m_pMaxDuration = childNode->value<float>();
138
-        else if(childNode->tag() == "particle-ignore-physics-after")
139
-            m_pIgnorePhysicsAfter = childNode->value<float>();
140
-
141
-        // visual
142
-        else if(childNode->tag() == "particle-size") {
143
-            m_pStartSize = childNode->value<Size>();
144
-            m_pFinalSize = childNode->value<Size>();
145
-        }
146
-        else if(childNode->tag() == "particle-start-size")
147
-            m_pStartSize = childNode->value<Size>();
148
-        else if(childNode->tag() == "particle-final-size")
149
-            m_pFinalSize = childNode->value<Size>();
150
-
151
-        else if(childNode->tag() == "particle-colors")
152
-            m_pColors = stdext::split<Color>(childNode->value());
153
-        else if(childNode->tag() == "particle-colors-stops")
154
-            m_pColorsStops = stdext::split<float>(childNode->value());
155
-        else if(childNode->tag() == "particle-texture")
156
-            m_pTexture = g_textures.getTexture(childNode->value());
157
-        else if(childNode->tag() == "particle-composition-mode") {
158
-            if(childNode->value() == "normal")
159
-                m_pCompositionMode = Painter::CompositionMode_Normal;
160
-            else if(childNode->value() == "multiply")
161
-                m_pCompositionMode = Painter::CompositionMode_Multiply;
162
-            else if(childNode->value() == "addition")
163
-                m_pCompositionMode = Painter::CompositionMode_Add;
164
-        }
165
-    }
166
-
167
-    if(m_pColors.empty())
168
-        m_pColors.push_back(Color(255, 255, 255, 128));
169
-    if(m_pColorsStops.empty())
170
-        m_pColorsStops.push_back(0);
171
-
172
-    if(m_pColors.size() != m_pColorsStops.size()) {
173
-        g_logger.error("particle colors must be equal to colorstops-1");
174
-        return false;
57
+        else if(childNode->tag() == "particle-type")
58
+            m_particleType = g_particles.getParticleType(childNode->value());
175 59
     }
176 60
 
177
-    return true;
61
+    if(!m_particleType)
62
+        stdext::throw_exception("emitter didn't provide a valid particle type");
178 63
 }
179 64
 
180 65
 void ParticleEmitter::update(float elapsedTime, const ParticleSystemPtr& system)
181 66
 {
67
+    m_elapsedTime += elapsedTime;
68
+
182 69
     // check if finished
183
-    if(m_duration >= 0 && m_elapsedTime >= m_duration + m_delay) {
70
+    if(m_duration > 0 && m_elapsedTime >= m_duration + m_delay) {
184 71
         m_finished = true;
185 72
         return;
186 73
     }
@@ -188,36 +75,39 @@ void ParticleEmitter::update(float elapsedTime, const ParticleSystemPtr& system)
188 75
     if(!m_active && m_elapsedTime > m_delay)
189 76
         m_active = true;
190 77
 
191
-    if(m_active) {
192
-        int currentBurst = std::floor((m_elapsedTime - m_delay) / m_burstRate) + 1;
193
-        for(int b = m_currentBurst; b < currentBurst; ++b) {
194
-
195
-            // every burst created at same position.
196
-            float pRadius = stdext::random_range(m_pMinPositionRadius, m_pMaxPositionRadius);
197
-            float pAngle = stdext::random_range(m_pMinPositionAngle, m_pMaxPositionAngle);
198
-
199
-            Point pPosition = m_position + Point(pRadius * cos(pAngle), pRadius * sin(pAngle));
200
-
201
-            for(int p = 0; p < m_burstCount; ++p) {
202
-
203
-                float pDuration = stdext::random_range(m_pMinDuration, m_pMaxDuration);
204
-
205
-                // particles initial velocity
206
-                float pVelocityAbs = stdext::random_range(m_pMinVelocity, m_pMaxVelocity);
207
-                float pVelocityAngle = stdext::random_range(m_pMinVelocityAngle, m_pMaxVelocityAngle);
208
-                PointF pVelocity(pVelocityAbs * cos(pVelocityAngle), pVelocityAbs * sin(pVelocityAngle));
209
-
210
-                // particles initial acceleration
211
-                float pAccelerationAbs = stdext::random_range(m_pMinAcceleration, m_pMaxAcceleration);
212
-                float pAccelerationAngle = stdext::random_range(m_pMinAccelerationAngle, m_pMaxAccelerationAngle);
213
-                PointF pAcceleration(pAccelerationAbs * cos(pAccelerationAngle), pAccelerationAbs * sin(pAccelerationAngle));
78
+    if(!m_active)
79
+        return;
214 80
 
215
-                system->addParticle(ParticlePtr(new Particle(pPosition, m_pStartSize, m_pFinalSize, pVelocity, pAcceleration, pDuration, m_pIgnorePhysicsAfter, m_pColors, m_pColorsStops, m_pCompositionMode, m_pTexture)));
216
-            }
81
+    int nextBurst = std::floor((m_elapsedTime - m_delay) * m_burstRate) + 1;
82
+    const ParticleType *type = m_particleType.get();
83
+    for(int b = m_currentBurst; b < nextBurst; ++b) {
84
+        // every burst created at same position.
85
+        float pRadius = stdext::random_range(type->pMinPositionRadius, type->pMaxPositionRadius);
86
+        float pAngle = stdext::random_range(type->pMinPositionAngle, type->pMaxPositionAngle);
87
+
88
+        Point pPosition = m_position + Point(pRadius * std::cos(pAngle), pRadius * std::sin(pAngle));
89
+
90
+        for(int p = 0; p < m_burstCount; ++p) {
91
+            float pDuration = stdext::random_range(type->pMinDuration, type->pMaxDuration);
92
+
93
+            // particles initial velocity
94
+            float pVelocityAbs = stdext::random_range(type->pMinVelocity, type->pMaxVelocity);
95
+            float pVelocityAngle = stdext::random_range(type->pMinVelocityAngle, type->pMaxVelocityAngle);
96
+            PointF pVelocity(pVelocityAbs * std::cos(pVelocityAngle), pVelocityAbs * std::sin(pVelocityAngle));
97
+
98
+            // particles initial acceleration
99
+            float pAccelerationAbs = stdext::random_range(type->pMinAcceleration, type->pMaxAcceleration);
100
+            float pAccelerationAngle = stdext::random_range(type->pMinAccelerationAngle, type->pMaxAccelerationAngle);
101
+            PointF pAcceleration(pAccelerationAbs * std::cos(pAccelerationAngle), pAccelerationAbs * std::sin(pAccelerationAngle));
102
+
103
+            ParticlePtr particle(new Particle(pPosition, type->pStartSize, type->pFinalSize,
104
+                                                pVelocity, pAcceleration,
105
+                                                pDuration, type->pIgnorePhysicsAfter,
106
+                                                type->pColors, type->pColorsStops,
107
+                                                type->pCompositionMode, type->pTexture));
108
+            system->addParticle(particle);
217 109
         }
218
-
219
-        m_currentBurst = currentBurst;
220 110
     }
221 111
 
222
-    m_elapsedTime += elapsedTime;
112
+    m_currentBurst = nextBurst;
223 113
 }

+ 2
- 25
src/framework/graphics/particleemitter.h View File

@@ -34,7 +34,7 @@ class ParticleEmitter : public stdext::shared_object
34 34
 public:
35 35
     ParticleEmitter();
36 36
 
37
-    bool load(const OTMLNodePtr& node);
37
+    void load(const OTMLNodePtr& node);
38 38
 
39 39
     void update(float elapsedTime, const ParticleSystemPtr& system);
40 40
 
@@ -48,30 +48,7 @@ private:
48 48
     bool m_finished, m_active;
49 49
     float m_burstRate;
50 50
     int m_currentBurst, m_burstCount;
51
-
52
-    // particles size
53
-    Size m_pStartSize, m_pFinalSize;
54
-
55
-    // particles initial position related to emitter position
56
-    float m_pMinPositionRadius, m_pMaxPositionRadius;
57
-    float m_pMinPositionAngle, m_pMaxPositionAngle;
58
-
59
-    // particles initial velocity
60
-    float m_pMinVelocity, m_pMaxVelocity;
61
-    float m_pMinVelocityAngle, m_pMaxVelocityAngle;
62
-
63
-    // particles initial acceleration
64
-    float m_pMinAcceleration, m_pMaxAcceleration;
65
-    float m_pMinAccelerationAngle, m_pMaxAccelerationAngle;
66
-
67
-    // particles duration
68
-    float m_pMinDuration, m_pMaxDuration, m_pIgnorePhysicsAfter;
69
-
70
-    // visual ralated
71
-    std::vector<Color> m_pColors;
72
-    std::vector<float> m_pColorsStops;
73
-    TexturePtr m_pTexture;
74
-    Painter::CompositionMode m_pCompositionMode;
51
+    ParticleTypePtr m_particleType;
75 52
 };
76 53
 
77 54
 #endif

+ 20
- 14
src/framework/graphics/particlemanager.cpp View File

@@ -35,13 +35,14 @@ bool ParticleManager::importParticle(std::string file)
35 35
         for(const OTMLNodePtr& node : doc->children()) {
36 36
             if(node->tag() == "Effect") {
37 37
                 ParticleEffectTypePtr particleEffectType = ParticleEffectTypePtr(new ParticleEffectType);
38
-                if(particleEffectType->load(node)) {
39
-                    particleEffectType->setFile(g_resources.resolvePath(file));
40
-                    m_effectsTypes[particleEffectType->getName()] = particleEffectType;
41
-                }
38
+                particleEffectType->load(node);
39
+                m_effectsTypes[particleEffectType->getName()] = particleEffectType;
42 40
             }
43 41
             else if(node->tag() == "Particle") {
44
-                // nothing yet
42
+                ParticleTypePtr particleType = ParticleTypePtr(new ParticleType);
43
+                particleType->load(node);
44
+                m_particleTypes[particleType->getName()] = particleType;
45
+                dump << particleType->getName();
45 46
             }
46 47
         }
47 48
         return true;
@@ -53,29 +54,34 @@ bool ParticleManager::importParticle(std::string file)
53 54
 
54 55
 ParticleEffectPtr ParticleManager::createEffect(const std::string& name)
55 56
 {
56
-    ParticleEffectPtr particleEffect = ParticleEffectPtr(new ParticleEffect);
57
-    if(particleEffect->load(m_effectsTypes[name]))
57
+    try {
58
+        ParticleEffectPtr particleEffect = ParticleEffectPtr(new ParticleEffect);
59
+        particleEffect->load(m_effectsTypes[name]);
60
+        m_effects.push_back(particleEffect);
58 61
         return particleEffect;
59
-    return nullptr;
62
+    } catch(stdext::exception& e) {
63
+        g_logger.error(stdext::format("failed to create effect '%s': %s", name, e.what()));
64
+        return nullptr;
65
+    }
60 66
 }
61 67
 
62 68
 void ParticleManager::terminate()
63 69
 {
64 70
     m_effects.clear();
65 71
     m_effectsTypes.clear();
72
+    m_particleTypes.clear();
66 73
 }
67 74
 
68
-void ParticleManager::update()
75
+void ParticleManager::poll()
69 76
 {
70
-    for(auto it = m_effects.begin(), end = m_effects.end(); it != end;) {
77
+    for(auto it = m_effects.begin(); it != m_effects.end();) {
71 78
         const ParticleEffectPtr& particleEffect = *it;
72 79
 
73 80
         if(particleEffect->hasFinished()) {
74 81
             it = m_effects.erase(it);
75
-            continue;
82
+        } else {
83
+            particleEffect->update();
84
+            ++it;
76 85
         }
77
-
78
-        particleEffect->update();
79
-        ++it;
80 86
     }
81 87
 }

+ 8
- 2
src/framework/graphics/particlemanager.h View File

@@ -25,6 +25,7 @@
25 25
 
26 26
 #include "declarations.h"
27 27
 #include "particleeffect.h"
28
+#include "particletype.h"
28 29
 
29 30
 class ParticleManager
30 31
 {
@@ -33,13 +34,18 @@ public:
33 34
     ParticleEffectPtr createEffect(const std::string& name);
34 35
     void terminate();
35 36
 
36
-    void update();
37
+    void poll();
37 38
 
38
-    std::map<std::string, ParticleEffectTypePtr> getEffectsTypes() { return m_effectsTypes; }
39
+    ParticleTypePtr getParticleType(std::string name) { return m_particleTypes[name]; }
40
+    ParticleEffectTypePtr getParticleEffectType(std::string name) { return m_effectsTypes[name]; }
41
+
42
+    const std::map<std::string, ParticleTypePtr>& getParticleTypes() { return m_particleTypes; }
43
+    const std::map<std::string, ParticleEffectTypePtr>& getEffectsTypes() { return m_effectsTypes; }
39 44
 
40 45
 private:
41 46
     std::list<ParticleEffectPtr> m_effects;
42 47
     std::map<std::string, ParticleEffectTypePtr> m_effectsTypes;
48
+    std::map<std::string, ParticleTypePtr> m_particleTypes;
43 49
 };
44 50
 
45 51
 extern ParticleManager g_particles;

+ 26
- 28
src/framework/graphics/particlesystem.cpp View File

@@ -30,13 +30,12 @@ ParticleSystem::ParticleSystem()
30 30
     m_lastUpdateTime = g_clock.seconds();
31 31
 }
32 32
 
33
-bool ParticleSystem::load(const OTMLNodePtr& node)
33
+void ParticleSystem::load(const OTMLNodePtr& node)
34 34
 {
35 35
     for(const OTMLNodePtr& childNode : node->children()) {
36 36
         if(childNode->tag() == "Emitter") {
37 37
             ParticleEmitterPtr emitter = ParticleEmitterPtr(new ParticleEmitter());
38
-            if(!emitter->load(childNode))
39
-                return false;
38
+            emitter->load(childNode);
40 39
             m_emitters.push_back(emitter);
41 40
         }
42 41
         else if(childNode->tag().find("Affector") != std::string::npos) {
@@ -48,13 +47,11 @@ bool ParticleSystem::load(const OTMLNodePtr& node)
48 47
                 affector = ParticleAffectorPtr(new AttractionAffector);
49 48
 
50 49
             if(affector) {
51
-                if(!affector->load(childNode))
52
-                    return false;
50
+                affector->load(childNode);
53 51
                 m_affectors.push_back(affector);
54 52
             }
55 53
         }
56 54
     }
57
-    return true;
58 55
 }
59 56
 
60 57
 void ParticleSystem::addParticle(const ParticlePtr& particle)
@@ -66,63 +63,64 @@ void ParticleSystem::render()
66 63
 {
67 64
     for(auto it = m_particles.begin(), end = m_particles.end(); it != end; ++it)
68 65
         (*it)->render();
66
+    g_painter->resetCompositionMode();
69 67
 }
70 68
 
71 69
 void ParticleSystem::update()
72 70
 {
73 71
     static const float delay = 0.0166; // 60 updates/s
74 72
 
73
+    // check time
74
+    float elapsedTime = g_clock.seconds() - m_lastUpdateTime;
75
+    if(elapsedTime < delay)
76
+        return;
77
+
75 78
     // check if finished
76 79
     if(m_particles.empty() && m_emitters.empty()) {
77 80
         m_finished = true;
78 81
         return;
79 82
     }
80 83
 
81
-    // check time
82
-    float elapsedTime = g_clock.seconds() - m_lastUpdateTime;
83
-    if(elapsedTime < delay)
84
-        return;
85 84
     m_lastUpdateTime = g_clock.seconds() - std::fmod(elapsedTime, delay);
86 85
 
87 86
     auto self = static_self_cast<ParticleSystem>();
88
-    for(int i = 0; i < elapsedTime / delay; ++i) {
87
+    for(int i = 0; i < std::floor(elapsedTime / delay); ++i) {
89 88
 
90 89
         // update emitters
91
-        for(auto it = m_emitters.begin(), end = m_emitters.end(); it != end;) {
90
+        for(auto it = m_emitters.begin(); it != m_emitters.end();) {
92 91
             const ParticleEmitterPtr& emitter = *it;
93 92
             if(emitter->hasFinished()) {
94 93
                 it = m_emitters.erase(it);
95
-                continue;
94
+            } else {
95
+                emitter->update(delay, self);
96
+                ++it;
96 97
             }
97
-            emitter->update(delay, self);
98
-            ++it;
99 98
         }
100 99
 
101 100
         // update affectors
102
-        for(auto it = m_affectors.begin(), end = m_affectors.end(); it != end;) {
101
+        for(auto it = m_affectors.begin(); it != m_affectors.end();) {
103 102
             const ParticleAffectorPtr& affector = *it;
104 103
             if(affector->hasFinished()) {
105 104
                 it = m_affectors.erase(it);
106
-                continue;
105
+            } else {
106
+                affector->update(delay);
107
+                ++it;
107 108
             }
108
-            affector->update(delay);
109
-            ++it;
110 109
         }
111 110
 
112 111
         // update particles
113
-        for(auto it = m_particles.begin(), end = m_particles.end(); it != end;) {
112
+        for(auto it = m_particles.begin(); it != m_particles.end();) {
114 113
             const ParticlePtr& particle = *it;
115 114
             if(particle->hasFinished()) {
116 115
                 it = m_particles.erase(it);
117
-                continue;
118
-            }
119
-
120
-            // pass particles through affectors
121
-            for(const ParticleAffectorPtr& particleAffector : m_affectors)
122
-                particleAffector->updateParticle(particle, delay);
116
+            } else {
117
+                // pass particles through affectors
118
+                for(const ParticleAffectorPtr& particleAffector : m_affectors)
119
+                    particleAffector->updateParticle(particle, delay);
123 120
 
124
-            particle->update(delay);
125
-            ++it;
121
+                particle->update(delay);
122
+                ++it;
123
+            }
126 124
         }
127 125
     }
128 126
 }

+ 1
- 1
src/framework/graphics/particlesystem.h View File

@@ -32,7 +32,7 @@ class ParticleSystem : public stdext::shared_object {
32 32
 public:
33 33
     ParticleSystem();
34 34
 
35
-    bool load(const OTMLNodePtr& node);
35
+    void load(const OTMLNodePtr& node);
36 36
 
37 37
     void addParticle(const ParticlePtr& particle);
38 38
 

+ 154
- 0
src/framework/graphics/particletype.cpp View File

@@ -0,0 +1,154 @@
1
+/*
2
+ * Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
3
+ *
4
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ * of this software and associated documentation files (the "Software"), to deal
6
+ * in the Software without restriction, including without limitation the rights
7
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ * copies of the Software, and to permit persons to whom the Software is
9
+ * furnished to do so, subject to the following conditions:
10
+ *
11
+ * The above copyright notice and this permission notice shall be included in
12
+ * all copies or substantial portions of the Software.
13
+ *
14
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ * THE SOFTWARE.
21
+ */
22
+
23
+#include "particletype.h"
24
+#include <framework/graphics/texturemanager.h>
25
+
26
+ParticleType::ParticleType()
27
+{
28
+    // particles default configuration. (make them reasonable for user detect missing properties on scripts)
29
+    pMinPositionRadius = 0;
30
+    pMaxPositionRadius = 3;
31
+    pMinPositionAngle = 0;
32
+    pMaxPositionAngle = 360;
33
+    pStartSize = Size(32, 32);
34
+    pFinalSize = Size(32, 32);
35
+    pMinDuration = 0;
36
+    pMaxDuration = 10;
37
+    pIgnorePhysicsAfter = -1;
38
+    pMinVelocity = 32;
39
+    pMaxVelocity = 64;
40
+    pMinVelocityAngle = 0;
41
+    pMaxVelocityAngle = 360;
42
+    pMinAcceleration = 32;
43
+    pMaxAcceleration = 64;
44
+    pMinAccelerationAngle = 0;
45
+    pMaxAccelerationAngle = 360;
46
+}
47
+
48
+void ParticleType::load(const OTMLNodePtr& node)
49
+{
50
+    for(const OTMLNodePtr& childNode : node->children()) {
51
+        if(childNode->tag() == "name")
52
+            pName = childNode->value();
53
+        else if(childNode->tag() == "position-radius") {
54
+            pMinPositionRadius = childNode->value<float>();
55
+            pMaxPositionRadius = childNode->value<float>();
56
+        }
57
+        else if(childNode->tag() == "min-position-radius")
58
+            pMinPositionRadius = childNode->value<float>();
59
+        else if(childNode->tag() == "max-position-radius")
60
+            pMaxPositionRadius = childNode->value<float>();
61
+        else if(childNode->tag() == "position-angle") {
62
+            pMinPositionAngle = childNode->value<float>() * DEG_TO_RAD;
63
+            pMaxPositionAngle = childNode->value<float>() * DEG_TO_RAD;
64
+        }
65
+        else if(childNode->tag() == "min-position-angle")
66
+            pMinPositionAngle = childNode->value<float>() * DEG_TO_RAD;
67
+        else if(childNode->tag() == "max-position-angle")
68
+            pMaxPositionAngle = childNode->value<float>() * DEG_TO_RAD;
69
+
70
+        // velocity
71
+        else if(childNode->tag() == "velocity") {
72
+            pMinVelocity = childNode->value<float>();
73
+            pMaxVelocity = childNode->value<float>();
74
+        }
75
+        else if(childNode->tag() == "min-velocity")
76
+            pMinVelocity = childNode->value<float>();
77
+        else if(childNode->tag() == "max-velocity")
78
+            pMaxVelocity = childNode->value<float>();
79
+        else if(childNode->tag() == "velocity-angle") {
80
+            pMinVelocityAngle = childNode->value<float>() * DEG_TO_RAD;
81
+            pMaxVelocityAngle = childNode->value<float>() * DEG_TO_RAD;
82
+        }
83
+        else if(childNode->tag() == "min-velocity-angle")
84
+            pMinVelocityAngle = childNode->value<float>() * DEG_TO_RAD;
85
+        else if(childNode->tag() == "max-velocity-angle")
86
+            pMaxVelocityAngle = childNode->value<float>() * DEG_TO_RAD;
87
+        else if(childNode->tag() == "acceleration") {
88
+            pMinAcceleration = childNode->value<float>();
89
+            pMaxAcceleration = childNode->value<float>();
90
+        }
91
+
92
+        // acceleration
93
+        else if(childNode->tag() == "min-acceleration")
94
+            pMinAcceleration = childNode->value<float>();
95
+        else if(childNode->tag() == "max-acceleration")
96
+            pMaxAcceleration = childNode->value<float>();
97
+        else if(childNode->tag() == "acceleration-angle") {
98
+            pMinAccelerationAngle = childNode->value<float>() * DEG_TO_RAD;
99
+            pMaxAccelerationAngle = childNode->value<float>() * DEG_TO_RAD;
100
+        }
101
+        else if(childNode->tag() == "min-acceleration-angle")
102
+            pMinAccelerationAngle = childNode->value<float>() * DEG_TO_RAD;
103
+        else if(childNode->tag() == "max-acceleration-angle")
104
+            pMaxAccelerationAngle = childNode->value<float>() * DEG_TO_RAD;
105
+
106
+        // duration
107
+        else if(childNode->tag() == "duration") {
108
+            pMinDuration = childNode->value<float>();
109
+            pMaxDuration = childNode->value<float>();
110
+        }
111
+        else if(childNode->tag() == "min-duration")
112
+            pMinDuration = childNode->value<float>();
113
+        else if(childNode->tag() == "max-duration")
114
+            pMaxDuration = childNode->value<float>();
115
+        else if(childNode->tag() == "ignore-physics-after")
116
+            pIgnorePhysicsAfter = childNode->value<float>();
117
+
118
+        // visual
119
+        else if(childNode->tag() == "size") {
120
+            pStartSize = childNode->value<Size>();
121
+            pFinalSize = childNode->value<Size>();
122
+        }
123
+        else if(childNode->tag() == "start-size")
124
+            pStartSize = childNode->value<Size>();
125
+        else if(childNode->tag() == "final-size")
126
+            pFinalSize = childNode->value<Size>();
127
+
128
+        else if(childNode->tag() == "colors")
129
+            pColors = stdext::split<Color>(childNode->value());
130
+        else if(childNode->tag() == "colors-stops")
131
+            pColorsStops = stdext::split<float>(childNode->value());
132
+        else if(childNode->tag() == "texture")
133
+            pTexture = g_textures.getTexture(childNode->value());
134
+        else if(childNode->tag() == "composition-mode") {
135
+            if(childNode->value() == "normal")
136
+                pCompositionMode = Painter::CompositionMode_Normal;
137
+            else if(childNode->value() == "multiply")
138
+                pCompositionMode = Painter::CompositionMode_Multiply;
139
+            else if(childNode->value() == "addition")
140
+                pCompositionMode = Painter::CompositionMode_Add;
141
+        }
142
+    }
143
+
144
+    if(pColors.empty())
145
+        pColors.push_back(Color(255, 255, 255, 128));
146
+    if(pColorsStops.empty())
147
+        pColorsStops.push_back(0);
148
+
149
+    if(pColors.size() != pColorsStops.size())
150
+        stdext::throw_exception("particle colors must be equal to colorstops-1");
151
+
152
+    pTexture->setSmooth(true);
153
+    pTexture->buildHardwareMipmaps();
154
+}

+ 72
- 0
src/framework/graphics/particletype.h View File

@@ -0,0 +1,72 @@
1
+/*
2
+ * Copyright (c) 2010-2013 OTClient <https://github.com/edubart/otclient>
3
+ *
4
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ * of this software and associated documentation files (the "Software"), to deal
6
+ * in the Software without restriction, including without limitation the rights
7
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ * copies of the Software, and to permit persons to whom the Software is
9
+ * furnished to do so, subject to the following conditions:
10
+ *
11
+ * The above copyright notice and this permission notice shall be included in
12
+ * all copies or substantial portions of the Software.
13
+ *
14
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ * THE SOFTWARE.
21
+ */
22
+
23
+#ifndef PARTICLETYPE_H
24
+#define PARTICLETYPE_H
25
+
26
+#include "declarations.h"
27
+#include <framework/graphics/painter.h>
28
+#include <framework/luaengine/luaobject.h>
29
+#include <framework/otml/otml.h>
30
+
31
+class ParticleType : public LuaObject
32
+{
33
+public:
34
+    ParticleType();
35
+
36
+    void load(const OTMLNodePtr& node);
37
+
38
+    std::string getName() { return pName; }
39
+
40
+protected:
41
+    // name
42
+    std::string pName;
43
+
44
+    // size
45
+    Size pStartSize, pFinalSize;
46
+
47
+    // initial position related to emitter position
48
+    float pMinPositionRadius, pMaxPositionRadius;
49
+    float pMinPositionAngle, pMaxPositionAngle;
50
+
51
+    // initial velocity
52
+    float pMinVelocity, pMaxVelocity;
53
+    float pMinVelocityAngle, pMaxVelocityAngle;
54
+
55
+    // initial acceleration
56
+    float pMinAcceleration, pMaxAcceleration;
57
+    float pMinAccelerationAngle, pMaxAccelerationAngle;
58
+
59
+    // duration
60
+    float pMinDuration, pMaxDuration, pIgnorePhysicsAfter;
61
+
62
+    // visual ralated
63
+    std::vector<Color> pColors;
64
+    std::vector<float> pColorsStops;
65
+    TexturePtr pTexture;
66
+    ParticleTypePtr particleType;
67
+    Painter::CompositionMode pCompositionMode;
68
+
69
+    friend class ParticleEmitter;
70
+};
71
+
72
+#endif

+ 0
- 1
src/framework/luafunctions.cpp View File

@@ -682,7 +682,6 @@ void Application::registerLuaFunctions()
682 682
     g_lua.registerClass<ParticleEffectType>();
683 683
     g_lua.bindClassStaticFunction<ParticleEffectType>("create", []{ return ParticleEffectTypePtr(new ParticleEffectType); });
684 684
     g_lua.bindClassMemberFunction<ParticleEffectType>("getName", &ParticleEffectType::getName);
685
-    g_lua.bindClassMemberFunction<ParticleEffectType>("getFile", &ParticleEffectType::getFile);
686 685
     g_lua.bindClassMemberFunction<ParticleEffectType>("getDescription", &ParticleEffectType::getDescription);
687 686
 
688 687
     // UIParticles

+ 34
- 12
src/framework/ui/uiparticles.cpp View File

@@ -23,27 +23,49 @@
23 23
 #include "uiparticles.h"
24 24
 #include <framework/graphics/particlemanager.h>
25 25
 
26
+UIParticles::UIParticles()
27
+{
28
+    m_referencePos = PointF(-1,-1);
29
+}
30
+
26 31
 void UIParticles::drawSelf(Fw::DrawPane drawPane)
27 32
 {
28
-    if((drawPane & Fw::ForegroundPane) == 0)
29
-        return;
33
+    if(drawPane & Fw::ForegroundPane) {
34
+        if(drawPane != Fw::BothPanes) {
35
+            glDisable(GL_BLEND);
36
+            g_painter->setColor(Color::alpha);
37
+            g_painter->drawFilledRect(m_rect);
38
+            glEnable(GL_BLEND);
39
+        }
40
+    }
41
+
42
+    if(drawPane & Fw::BackgroundPane) {
43
+        UIWidget::drawSelf(Fw::ForegroundPane);
44
+        g_painter->saveAndResetState();
45
+        g_painter->setColor(Color::white);
46
+        g_painter->setClipRect(getPaddingRect());
47
+
48
+        if(m_referencePos.x < 0 && m_referencePos.y < 0)
49
+            g_painter->translate(m_rect.center());
50
+        else
51
+            g_painter->translate(m_rect.x() + m_referencePos.x * m_rect.width(), m_rect.y() + m_referencePos.y * m_rect.height());
30 52
 
31
-    for(auto it = m_effects.begin(), end = m_effects.end(); it != end; ++it)
32
-        (*it)->render();
53
+        for(auto it = m_effects.begin(), end = m_effects.end(); it != end; ++it)
54
+            (*it)->render();
55
+        g_painter->restoreSavedState();
56
+    }
33 57
 }
34 58
 
35 59
 void UIParticles::onStyleApply(const std::string& styleName, const OTMLNodePtr& styleNode)
36 60
 {
37 61
     UIWidget::onStyleApply(styleName, styleNode);
38 62
 
39
-    /*for(const OTMLNodePtr& node : styleNode->children()) {
40
-        if(node->tag() == "reference")
41
-            setItemId(node->value<int>());
42
-        else if(node->tag() == "item-count")
43
-            setItemCount(node->value<int>());
44
-        else if(node->tag() == "virtual")
45
-            setVirtual(node->value<bool>());
46
-    }*/
63
+    for(const OTMLNodePtr& node : styleNode->children()) {
64
+        if(node->tag() == "effect")
65
+            addEffect(node->value());
66
+        else if(node->tag() == "reference-pos")
67
+            setReferencePos(node->value<PointF>());
68
+    }
47 69
 }
48 70
 
49 71
 void UIParticles::addEffect(const std::string& name)

+ 7
- 1
src/framework/ui/uiparticles.h View File

@@ -29,14 +29,20 @@
29 29
 class UIParticles : public UIWidget
30 30
 {
31 31
 public:
32
+    UIParticles();
33
+
32 34
     void drawSelf(Fw::DrawPane drawPane);
33 35
 
34 36
     void addEffect(const std::string& name);
35 37
 
36 38
     void onStyleApply(const std::string& styleName, const OTMLNodePtr& styleNode);
37 39
 
40
+    void setReferencePos(const PointF& point) { m_referencePos = point; }
41
+    PointF getReferencePos() { return m_referencePos; }
42
+
38 43
 private:
39 44
     std::vector<ParticleEffectPtr> m_effects;
45
+    PointF m_referencePos;
40 46
 };
41 47
 
42
-#endif // UIPARTICLES_H
48
+#endif

+ 2
- 1
src/framework/ui/uiwidgetimage.cpp View File

@@ -167,7 +167,8 @@ void UIWidget::drawImage(const Rect& screenCoords)
167 167
         }
168 168
     }
169 169
 
170
-    m_imageTexture->setSmooth(m_imageSmooth);
170
+    // smooth is now enabled by default for all textures
171
+    //m_imageTexture->setSmooth(m_imageSmooth);
171 172
 
172 173
     g_painter->setColor(m_imageColor);
173 174
     g_painter->drawTextureCoords(m_imageCoordsBuffer, m_imageTexture);

Loading…
Cancel
Save