1 // Description:
2 // Particles are grouped into ParticleGroups.
3 //
4 // Copyright (C) 2008 Frank Becker
5 //
6 // This program is free software; you can redistribute it and/or modify it under
7 // the terms of the GNU General Public License as published by the Free Software
8 // Foundation; either version 2 of the License, or (at your option) any later
9 // version.
10 //
11 // This program is distributed in the hope that it will be useful, but WITHOUT
12 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details
14 //
15 #include "ParticleGroup.hpp"
16
17 #include <Trace.hpp>
18 #include <Particles.hpp>
19 #include <Constants.hpp>
20 #include <FindHash.hpp>
21
22 using namespace std;
23
24 hash_map< const string, ParticleType*, hash<const string>, std::equal_to<const string> >
25 ParticleGroup::_particleTypeMap;
26
ParticleGroup(const string & groupName,int numParticles)27 ParticleGroup::ParticleGroup( const string &groupName, int numParticles):
28 _particles( 0),
29 _aliveCount( 0),
30 _groupName( groupName),
31 _numParticles( numParticles)
32 {
33 XTRACE();
34 _usedList.next = 0;
35 }
36
~ParticleGroup()37 ParticleGroup::~ParticleGroup()
38 {
39 XTRACE();
40
41 LOG_INFO << _groupName << " has " << _aliveCount << " particles still alive.\n";
42 ParticleInfo *p = _usedList.next;
43 while( p)
44 {
45 p->tod = 0;
46 p->particle->update( p);
47 p = p->next;
48 }
49
50 delete[] _particles;
51 }
52
reset(void)53 void ParticleGroup::reset( void)
54 {
55 XTRACE();
56
57 //trigger particles in use to die
58 ParticleInfo *p = _usedList.next;
59 while( p)
60 {
61 p->tod = 0;
62 p->particle->update( p);
63 p = p->next;
64 }
65
66 //reset free/used lists
67 _freeList.next = &_particles[0];
68 for( int i=0; i<_numParticles-1; i++)
69 {
70 _particles[i].next = &_particles[i+1];
71 }
72 _particles[_numParticles-1].next = 0;
73 _usedList.next = 0;
74 _aliveCount = 0;
75 }
76
init(void)77 bool ParticleGroup::init( void)
78 {
79 XTRACE();
80
81 //FIXME: do we really need to restrict size?
82 if( _numParticles > MAX_PARTICLES_PER_GROUP)
83 {
84 _numParticles = MAX_PARTICLES_PER_GROUP;
85 }
86
87 _particles = new ParticleInfo[ _numParticles];
88 for( int i=0; i<_numParticles-1; i++)
89 {
90 const vec3 zero(0,0,0);
91 _particles[i].position = zero;
92 _particles[i].velocity = zero;
93 _particles[i].color = zero;
94 _particles[i].extra = zero;
95
96 _particles[i].prevPosition = zero;
97 _particles[i].prevVelocity = zero;
98 _particles[i].prevColor = zero;
99 _particles[i].prevExtra = zero;
100 }
101
102 reset();
103
104 Particles::Initialize();
105
106 return true;
107 }
108
newParticle(const string & name,const ParticleInfo & pi)109 ParticleInfo *ParticleGroup::newParticle(
110 const string & name, const ParticleInfo &pi)
111 {
112 // XTRACE();
113 ParticleType *particleType = getParticleType( name);
114 if( !particleType)
115 {
116 LOG_ERROR << "Unknown particleType [" << name << "]" << endl;
117 return 0;
118 }
119 return newParticle( particleType, pi);
120 }
121
newParticle(ParticleType * particleType,const ParticleInfo & pi)122 ParticleInfo *ParticleGroup::newParticle(
123 ParticleType *particleType, const ParticleInfo &pi)
124 {
125 // XTRACE();
126 ParticleInfo *p = _freeList.next;
127 if( !p)
128 {
129 LOG_ERROR << _groupName << " is out of particles!" << endl;
130 return 0;
131 }
132
133 _freeList.next = p->next;
134 p->next = _usedList.next;
135 _usedList.next = p;
136
137 p->particle = particleType;
138 p->position = pi.position;
139 p->velocity = pi.velocity;
140 p->extra = pi.extra;
141 p->color = pi.color;
142 p->text = pi.text;
143 p->damage = pi.damage;
144 p->related = pi.related;
145
146 //particle initializes particle info
147 particleType->init( p);
148
149 _aliveCount++;
150
151 return p;
152 }
153
newParticle(const string & name,float x,float y,float z)154 ParticleInfo *ParticleGroup::newParticle(
155 const string & name, float x, float y, float z)
156 {
157 // XTRACE();
158 ParticleType *particleType = getParticleType( name);
159 if( !particleType)
160 {
161 LOG_ERROR << "Unknown particleType [" << name << "]" << endl;
162 return 0;
163 }
164 return newParticle( particleType, x, y, z);
165 }
166
newParticle(ParticleType * particleType,float x,float y,float z)167 ParticleInfo *ParticleGroup::newParticle(
168 ParticleType *particleType, float x, float y, float z)
169 {
170 // XTRACE();
171 ParticleInfo *p = _freeList.next;
172 if( !p)
173 {
174 LOG_ERROR << _groupName << " is out of particles!" << endl;
175 return 0;
176 }
177
178 _freeList.next = p->next;
179 p->next = _usedList.next;
180 _usedList.next = p;
181
182 p->particle = particleType;
183 p->position.x = x;
184 p->position.y = y;
185 p->position.z = z;
186
187 //particle initializes particle info
188 particleType->init( p);
189
190 _aliveCount++;
191
192 return p;
193 }
194
195 static inline
hasRadiusCollision(const float & minDist,const vec3 & pos1,const vec3 & pos2)196 bool hasRadiusCollision( const float &minDist, const vec3 &pos1, const vec3 &pos2)
197 {
198 float d2 = minDist;
199 d2 *= d2;
200 float dx = (pos2.x-pos1.x);
201 float dy = (pos2.y-pos1.y);
202 float D2 = dx*dx + dy*dy;
203 if( D2 < d2)
204 {
205 return true;
206 }
207 return false;
208 }
209
detectCollisions(ParticleGroup * pg)210 void ParticleGroup::detectCollisions( ParticleGroup *pg)
211 {
212 // XTRACE();
213 ParticleInfo *p1 = _usedList.next;
214 while( p1)
215 {
216 ParticleInfo *p2 = pg->_usedList.next;
217 while( p2)
218 {
219 if( (p1->radius == 0.0f) || (p2->radius == 0.0f))
220 {
221 //Bosses are made up of multiple radii
222 for( int rc1=0; rc1 < p1->particle->getRadiiCount(); rc1++)
223 {
224 float r1 = p1->particle->getRadius(rc1);
225 if( r1 == 0.0f) r1 = p1->radius;
226 vec3 offset1 = p1->particle->getOffset(rc1);
227 for( int rc2=0; rc2 < p2->particle->getRadiiCount(); rc2++)
228 {
229 float r2 = p2->particle->getRadius(rc2);
230 if( r2 == 0.0f) r2 = p2->radius;
231 vec3 offset2 = p2->particle->getOffset(rc2);
232 vec3 pos1 = p1->position+offset1;
233 vec3 pos2 = p2->position+offset2;
234 // LOG_INFO << "pos1 = " << pos1.x << " " << pos1.y << "\n";
235 // LOG_INFO << "pos2 = " << pos2.x << " " << pos2.y << "\n";
236 if( hasRadiusCollision( r1+r2, pos1, pos2))
237 {
238 p1->particle->hit( p1, p2, rc1);
239 p2->particle->hit( p2, p1, rc2);
240 }
241 }
242 }
243 }
244 else
245 {
246 if( hasRadiusCollision(
247 p1->radius+p2->radius,
248 p1->position, p2->position))
249 {
250 p1->particle->hit( p1, p2);
251 p2->particle->hit( p2, p1);
252 }
253 }
254
255 p2 = p2->next;
256 }
257
258 p1 = p1->next;
259 }
260 }
261
addParticleType(ParticleType * particleType)262 void ParticleGroup::addParticleType( ParticleType *particleType)
263 {
264 XTRACE();
265 if( particleType)
266 {
267 LOG_INFO << "New Particle type: ["
268 << particleType->name() << "]" << endl;
269
270 _particleTypeMap[ particleType->name()] = particleType;
271 }
272 }
273
getParticleType(const string particleTypeName)274 ParticleType * ParticleGroup::getParticleType( const string particleTypeName)
275 {
276 // XTRACE();
277 ParticleType * particleType = findHash<const string>( particleTypeName, _particleTypeMap);
278 if( !particleType)
279 {
280 LOG_ERROR << "ParticleGroup never heard of a " << particleTypeName
281 << " before!" << endl;
282
283 //trying first in list
284 particleType = _particleTypeMap.begin()->second;
285 }
286 return particleType;
287 }
288