1 //  SuperTuxKart - a fun racing game with go-kart
2 //  Copyright (C) 2017 SuperTuxKart-Team
3 //
4 //  This program is free software; you can redistribute it and/or
5 //  modify it under the terms of the GNU General Public License
6 //  as published by the Free Software Foundation; either version 3
7 //  of the License, or (at your option) any later version.
8 //
9 //  This program is distributed in the hope that it will be useful,
10 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 //  GNU General Public License for more details.
13 //
14 //  You should have received a copy of the GNU General Public License
15 //  along with this program; if not, write to the Free Software
16 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17 
18 #ifndef HEADER_CPU_PARTICLE_MANAGER_HPP
19 #define HEADER_CPU_PARTICLE_MANAGER_HPP
20 
21 #ifndef SERVER_ONLY
22 
23 #include "graphics/gl_headers.hpp"
24 #include "utils/constants.hpp"
25 #include "utils/mini_glm.hpp"
26 #include "utils/no_copy.hpp"
27 #include "utils/singleton.hpp"
28 
29 #include <dimension2d.h>
30 #include <IBillboardSceneNode.h>
31 #include <vector3d.h>
32 #include <SColor.h>
33 
34 #include <cassert>
35 #include <string>
36 #include <memory>
37 #include <unordered_map>
38 #include <unordered_set>
39 #include <vector>
40 
41 using namespace irr;
42 
43 struct CPUParticle
44 {
45     core::vector3df m_position;
46     video::SColor m_color_lifetime;
47     short m_size[2];
48     // ------------------------------------------------------------------------
CPUParticleCPUParticle49     CPUParticle(const core::vector3df& position,
50                 const core::vector3df& color_from,
51                 const core::vector3df& color_to, float lf_time, float size)
52          : m_position(position)
53     {
54         core::vector3df ret = color_from + (color_to - color_from) * lf_time;
55         m_color_lifetime.setRed(core::clamp((int)(ret.X * 255.0f), 0, 255));
56         m_color_lifetime.setBlue(core::clamp((int)(ret.Y * 255.0f), 0, 255));
57         m_color_lifetime.setGreen(core::clamp((int)(ret.Z * 255.0f), 0, 255));
58         m_color_lifetime.setAlpha(core::clamp((int)(lf_time * 255.0f), 0, 255));
59         m_size[0] = MiniGLM::toFloat16(size);
60         m_size[1] = m_size[0];
61     }
62     // ------------------------------------------------------------------------
CPUParticleCPUParticle63     CPUParticle(scene::IBillboardSceneNode* node)
64     {
65         m_position = node->getAbsolutePosition();
66         video::SColor unused_bottom;
67         node->getColor(m_color_lifetime, unused_bottom);
68         m_size[0] = MiniGLM::toFloat16(node->getSize().Width);
69         m_size[1] = MiniGLM::toFloat16(node->getSize().Height);
70     }
71 };
72 
73 
74 class STKParticle;
75 class Material;
76 
77 class CPUParticleManager : public Singleton<CPUParticleManager>, NoCopy
78 {
79 private:
80     struct GLParticle : public NoCopy
81     {
82         GLuint m_vao;
83         GLuint m_vbo;
84         unsigned m_size;
85         // --------------------------------------------------------------------
86         GLParticle(bool flips);
87         // --------------------------------------------------------------------
~GLParticleCPUParticleManager::GLParticle88         ~GLParticle()
89         {
90             glDeleteVertexArrays(1, &m_vao);
91             glDeleteBuffers(1, &m_vbo);
92         }
93     };
94 
95     std::unordered_map<std::string, std::vector<STKParticle*> >
96         m_particles_queue;
97 
98     std::unordered_map<std::string, std::vector<scene::IBillboardSceneNode*> >
99         m_billboards_queue;
100 
101     std::unordered_map<std::string, std::vector<CPUParticle> >
102         m_particles_generated;
103 
104     std::unordered_map<std::string, std::unique_ptr<GLParticle> >
105         m_gl_particles;
106 
107     std::unordered_map<std::string, Material*> m_material_map;
108 
109     std::unordered_set<std::string> m_flips_material;
110 
111     static GLuint m_particle_quad;
112 
113     // ------------------------------------------------------------------------
isFlipsMaterial(const std::string & name)114     bool isFlipsMaterial(const std::string& name)
115               { return m_flips_material.find(name) != m_flips_material.end(); }
116 
117 public:
118     // ------------------------------------------------------------------------
119     CPUParticleManager();
120     // ------------------------------------------------------------------------
~CPUParticleManager()121     ~CPUParticleManager()
122     {
123         glDeleteBuffers(1, &m_particle_quad);
124         m_particle_quad = 0;
125     }
126     // ------------------------------------------------------------------------
127     void addParticleNode(STKParticle* node);
128     // ------------------------------------------------------------------------
129     void addBillboardNode(scene::IBillboardSceneNode* node);
130     // ------------------------------------------------------------------------
131     void generateAll();
132     // ------------------------------------------------------------------------
133     void uploadAll();
134     // ------------------------------------------------------------------------
135     void drawAll();
136     // ------------------------------------------------------------------------
reset()137     void reset()
138     {
139         for (auto& p : m_particles_queue)
140         {
141             p.second.clear();
142         }
143         for (auto& p : m_billboards_queue)
144         {
145             p.second.clear();
146         }
147         for (auto& p : m_particles_generated)
148         {
149             p.second.clear();
150         }
151     }
152     // ------------------------------------------------------------------------
cleanMaterialMap()153     void cleanMaterialMap()
154     {
155         m_material_map.clear();
156         m_flips_material.clear();
157     }
158 
159 };
160 
161 #endif
162 
163 #endif
164