1
/************************************************************************************
3
AstroMenace (Hardcore 3D space shooter with spaceship upgrade possibilities)
4
Copyright © 2006-2012 Michael Kurinnoy, Viewizard
7
AstroMenace is free software: you can redistribute it and/or modify
8
it under the terms of the GNU General Public License as published by
9
the Free Software Foundation, either version 3 of the License, or
10
(at your option) any later version.
12
AstroMenace is distributed in the hope that it will be useful,
13
but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
GNU General Public License for more details.
17
You should have received a copy of the GNU General Public License
18
along with AstroMenace. If not, see <http://www.gnu.org/licenses/>.
21
Web Site: http://www.viewizard.com/
22
Project: http://sourceforge.net/projects/openastromenace/
23
E-mail: viewizard@viewizard.com
25
*************************************************************************************/
28
#include "ParticleSystem2D.h"
29
#include "../RendererInterface/RendererInterface.h"
35
//-----------------------------------------------------------------------------
36
// инициализация класса
37
//-----------------------------------------------------------------------------
38
eParticleSystem2D::eParticleSystem2D()
42
TimeLastUpdate = -1.0f;
43
EmissionResidue = 0.0f;
44
Angle = Direction = VECTOR3D(0,0,0);
45
Matrix33Identity(RotationMatrix);
47
AttractiveValue = 25.0f;
49
DestroyIfNoParticles = false;
52
Location = VECTOR3D( 0.0f, 0.0f, 0.0f);
54
DeadZone = 0.0f; // нет мертвой зоны
78
SpeedOnCreation = 1.00f;
85
ParticlesPerSec = 100;
89
CreationSize = VECTOR3D(0.05f,0.05f,0.05f);
98
//-----------------------------------------------------------------------------
99
// При разрушении класса
100
//-----------------------------------------------------------------------------
101
eParticleSystem2D::~eParticleSystem2D()
103
// полностью освобождаем память от всех частиц в системе
104
eParticle2D *tmp = Start;
107
eParticle2D *tmp2 = tmp->Next;
115
//-----------------------------------------------------------------------------
116
// подключить частицу к системе
117
//-----------------------------------------------------------------------------
118
void eParticleSystem2D::Attach(eParticle2D * NewParticle)
120
if (NewParticle == 0) return;
122
// первый в списке...
125
NewParticle->Prev = 0;
126
NewParticle->Next = 0;
130
else // продолжаем заполнение...
132
NewParticle->Prev = End;
133
NewParticle->Next = 0;
134
End->Next = NewParticle;
141
//-----------------------------------------------------------------------------
142
// отключить ее от системы
143
//-----------------------------------------------------------------------------
144
void eParticleSystem2D::Detach(eParticle2D * OldParticle)
146
if (OldParticle == 0) return;
148
// переустанавливаем указатели...
149
if (Start == OldParticle) Start = OldParticle->Next;
150
if (End == OldParticle) End = OldParticle->Prev;
153
if (OldParticle->Next != 0) OldParticle->Next->Prev = OldParticle->Prev;
154
else if (OldParticle->Prev != 0) OldParticle->Prev->Next = 0;
155
if (OldParticle->Prev != 0) OldParticle->Prev->Next = OldParticle->Next;
156
else if (OldParticle->Next != 0) OldParticle->Next->Prev = 0;
164
//-----------------------------------------------------------------------------
165
// обновление системы
166
//-----------------------------------------------------------------------------
167
bool eParticleSystem2D::Update(float Time)
169
// первый раз... просто берем время
170
if (TimeLastUpdate == -1.0f) {TimeLastUpdate = Time;return true;}
172
// Time - это абсолютное время, вычисляем дельту
173
float TimeDelta = Time - TimeLastUpdate;
174
// быстро вызвали еще раз... время не изменилось, или почти не изменилось
175
if (TimeDelta == 0.0f) return true;
177
TimeLastUpdate = Time;
180
// очищаем счетчик подсчета кол-ва действующий частиц
181
int ParticlesAlive = 0;
185
eParticle2D *tmp = Start;
189
eParticle2D *tmp2 = tmp->Next;
190
// функция вернет false, если частица уже мертва
191
if (tmp->Update(TimeDelta, Location, IsAttractive, AttractiveValue))
207
// подсчитываем, как много частиц нам нужно создать из ParticlesPerSec
208
float ParticlesNeeded = ParticlesPerSec * TimeDelta + EmissionResidue;
210
// переводим в целочисленные значения
211
unsigned int ParticlesCreated = (unsigned int)ParticlesNeeded;
215
// запоминаем разницу между тем сколько нужно и сколько создадим
216
EmissionResidue = ParticlesNeeded - ParticlesCreated;
220
// ничего создавать не нужно
221
EmissionResidue = ParticlesNeeded;
222
ParticlesCreated = 0;
225
// если нужно что-то создавать, создаем
226
if ( ParticlesCreated > 0 )
228
// если пытаемся создать за один раз больше чем можем в секунду
229
// убираем этот "глюк", видно компьютер тормозит
230
if (ParticlesCreated > ParticlesPerSec) ParticlesCreated = ParticlesPerSec;
231
// пока не создадим все необходимые частицы
232
while (ParticlesCreated > 0)
234
// создаем новую частицу
235
eParticle2D *NewParticle = 0;
236
NewParticle = new eParticle2D; if (NewParticle == 0) return true;
238
// установка жизни новой частици и проверка, что не выходит из диапахона
239
NewParticle->Age = 0.0f;
240
NewParticle->Lifetime = Life + vw_Randf0 * LifeVar;
241
if (NewParticle->Lifetime < 0.0f) NewParticle->Lifetime = 0.0f;
244
NewParticle->Color.r = ColorStart.r + vw_Randf0 * ColorVar.r;
245
NewParticle->Color.g = ColorStart.g + vw_Randf0 * ColorVar.g;
246
NewParticle->Color.b = ColorStart.b + vw_Randf0 * ColorVar.b;
247
// мы не используем альфа цвет тут
248
NewParticle->Color.a = 1.0f;
250
// проверяем, чтобы не было переполнения цвета
251
Clamp( NewParticle->Color.r, 0.0f, 1.0f );
252
Clamp( NewParticle->Color.g, 0.0f, 1.0f );
253
Clamp( NewParticle->Color.b, 0.0f, 1.0f );
255
// считаем delta относительно жизни частицы
256
NewParticle->ColorDelta.r = (ColorEnd.r - NewParticle->Color.r) / NewParticle->Lifetime;
257
NewParticle->ColorDelta.g = (ColorEnd.g - NewParticle->Color.g) / NewParticle->Lifetime;
258
NewParticle->ColorDelta.b = (ColorEnd.b - NewParticle->Color.b) / NewParticle->Lifetime;
260
// считаем значение альфы
261
NewParticle->Alpha = AlphaStart + vw_Randf0 * AlphaVar;
262
// убираем переполнение
263
Clamp( NewParticle->Alpha, 0.0f, 1.0f );
266
// выпускаем частицу возле места нахождения системы
267
if (CreationType == 0) // точка
268
NewParticle->Location = Location + VECTOR3D(vw_Randf0 * CreationSize.x, vw_Randf0 * CreationSize.y, vw_Randf0 * CreationSize.z);
269
if (CreationType == 1)
274
if (DeadZone != 0.0f)
276
minDist = CreationSize.x*CreationSize.x+CreationSize.y*CreationSize.y+CreationSize.z*CreationSize.z;
277
// если зона больше чем радиус излучения - выключаем ее
278
if (minDist <= DeadZone*DeadZone) DeadZone = 0.0f;
281
tmp.x = (1.0f-vw_Randf1*2) * CreationSize.x;
282
tmp.y = (1.0f-vw_Randf1*2) * CreationSize.y;
283
tmp.z = (1.0f-vw_Randf1*2) * CreationSize.z;
284
while (tmp.x*tmp.x + tmp.y*tmp.y + tmp.z*tmp.z < DeadZone*DeadZone)
289
tmp1 = tmp1^(1/100.0f);
293
NewParticle->Location = Location + tmp;
295
if (CreationType == 2)
299
float minDist = CreationSize.x*CreationSize.x+CreationSize.y*CreationSize.y+CreationSize.z*CreationSize.z;
300
// если зона больше чем радиус излучения - выключаем ее
301
if (minDist <= DeadZone*DeadZone) DeadZone = 0.0f;
303
tmp.x = vw_Randf0 * CreationSize.x;
304
tmp.y = vw_Randf0 * CreationSize.y;
305
tmp.z = vw_Randf0 * CreationSize.z;
306
float ParticleDist = tmp.x*tmp.x + tmp.y*tmp.y + tmp.z*tmp.z;
307
while (ParticleDist > minDist || ParticleDist < DeadZone*DeadZone)
309
if (ParticleDist > minDist)
314
tmp1 = tmp1^(1/100.0f);
317
if ( ParticleDist < DeadZone*DeadZone)
322
tmp1 = tmp1^(1/100.0f);
326
{if (tmp.x > CreationSize.x) tmp.x = CreationSize.x;}
328
{if (tmp.x < -CreationSize.x) tmp.x = -CreationSize.x;}
331
{if (tmp.y > CreationSize.y) tmp.y = CreationSize.y;}
333
{if (tmp.y < -CreationSize.y) tmp.y = -CreationSize.y;}
336
{if (tmp.z > CreationSize.z) tmp.z = CreationSize.z;}
338
{if (tmp.z < -CreationSize.z) tmp.z = -CreationSize.z;}
341
ParticleDist = tmp.x*tmp.x + tmp.y*tmp.y + tmp.z*tmp.z;
344
NewParticle->Location = Location + tmp;
351
// считаем размер частицы
352
NewParticle->Size = SizeStart + vw_Randf0 * SizeVar;
353
if (NewParticle->Size < 0.0f) NewParticle->Size = 0.0f;
354
NewParticle->SizeDelta = (SizeEnd - NewParticle->Size) / NewParticle->Lifetime;
359
// испускатель имеет направление. этот код немного добавляет случайности
360
float RandomYaw = vw_Randf0 * 3.14159f * 2.0f;
361
float RandomPitch = vw_Randf0 * Theta * 3.14159f / 180.0f ;
363
// учитываем нужное нам направление, вектор Direction
364
if ((Direction.x != 0.0f || Direction.y != 0.0f || Direction.z != 0.0f) &&
369
NewParticle->Velocity = Direction;
374
NewParticle->Velocity.y = Direction.y * cosf(RandomPitch);
375
NewParticle->Velocity.x = Direction.y * sinf(RandomPitch) * cosf(RandomYaw);
376
NewParticle->Velocity.z = Direction.y * sinf(RandomPitch) * sinf(RandomYaw);
378
NewParticle->Velocity.y += Direction.x * sinf(RandomPitch) * cosf(RandomYaw);
379
NewParticle->Velocity.x += Direction.x * cosf(RandomPitch);
380
NewParticle->Velocity.z += Direction.x * sinf(RandomPitch) * sinf(RandomYaw);
382
NewParticle->Velocity.y += Direction.z * sinf(RandomPitch) * sinf(RandomYaw);
383
NewParticle->Velocity.x += Direction.z * sinf(RandomPitch) * cosf(RandomYaw);
384
NewParticle->Velocity.z += Direction.z * cosf(RandomPitch);
386
Matrix33CalcPoint(&NewParticle->Velocity, RotationMatrix);
391
// без направления, излучаем во все стороны
392
NewParticle->Velocity.y = vw_Randf0 * Theta / 360.0f;
393
NewParticle->Velocity.x = vw_Randf0 * Theta / 360.0f;
394
NewParticle->Velocity.z = vw_Randf0 * Theta / 360.0f;
395
NewParticle->Velocity.Normalize();
399
// находим перемещение
400
float NewSpeed = Speed + vw_Randf0 * SpeedVar;
401
if (NewSpeed < 0.0f) NewSpeed = 0.0f;
402
NewParticle->Velocity *= NewSpeed ;
404
// подключаем частицу к системе
407
// уменьшаем необходимое количество частиц
413
// проверка, если уже ничего нет и нужно выйти - выходим
414
if (DestroyIfNoParticles)
415
if (ParticlesAlive == 0) return false;
424
//-----------------------------------------------------------------------------
425
// прорисовка системы
426
//-----------------------------------------------------------------------------
427
void eParticleSystem2D::Draw()
430
// загрузка текстуры, уже должна быть подключена
431
if (Texture == 0) return;
433
RECT SrcRest, DestRest;
435
SetRect(&SrcRest,0,0,64,64);
439
// подсчет кол-ва частиц
440
eParticle2D *tmp1 = Start;
441
int CurrentCount = 0;
445
eParticle2D *tmp2 = tmp1->Next;
450
if (CurrentCount == 0) return;
455
bool ASpresent=false;
456
ASpresent = vw_GetAspectWH(&AW, &AH);
459
vw_GetViewport(0, 0, &W, &H);
462
// Установка текстуры и ее свойств...
463
vw_SetTexture(0, Texture);
464
vw_SetTextureBlend(true, RI_BLEND_SRCALPHA, RI_BLEND_INVSRCALPHA);
467
float ImageHeight = Texture->Height*1.0f;
468
float ImageWidth = Texture->Width*1.0f;
473
// буфер для последовательности RI_TRIANGLE_STRIP
474
// войдет RI_2f_XYZ | RI_2f_TEX | RI_4f_COLOR
476
tmp = new float[(2+2+4)*4*CurrentCount]; if (tmp == 0) return;
488
eParticle2D *tmp2 = tmp1->Next;
490
SetRect(&DestRest,(int)(tmp1->Location.x - tmp1->Size/2),
491
(int)(tmp1->Location.y - tmp1->Size/2),
492
(int)(tmp1->Location.x + tmp1->Size/2),
493
(int)(tmp1->Location.y + tmp1->Size/2));
495
if (ASpresent) tmpPosY = (AH - DestRest.top - DestRest.top - (DestRest.bottom - DestRest.top));
496
else tmpPosY = (AHw - DestRest.top - DestRest.top - (DestRest.bottom - DestRest.top));
498
float FrameHeight = (SrcRest.bottom*1.0f )/ImageHeight;
499
float FrameWidth = (SrcRest.right*1.0f )/ImageWidth;
501
float Yst = (SrcRest.top*1.0f)/ImageHeight;
502
float Xst = (SrcRest.left*1.0f)/ImageWidth;
504
tmp[k++] = DestRest.left;
505
tmp[k++] = DestRest.top +tmpPosY +(DestRest.bottom - DestRest.top);
506
tmp[k++] = tmp1->Color.r;
507
tmp[k++] = tmp1->Color.g;
508
tmp[k++] = tmp1->Color.b;
509
tmp[k++] = tmp1->Alpha;
513
tmp[k++] = DestRest.left;
514
tmp[k++] = DestRest.top +tmpPosY;
515
tmp[k++] = tmp1->Color.r;
516
tmp[k++] = tmp1->Color.g;
517
tmp[k++] = tmp1->Color.b;
518
tmp[k++] = tmp1->Alpha;
520
tmp[k++] = 1.0f-FrameHeight;
522
tmp[k++] = DestRest.left + (DestRest.right - DestRest.left);
523
tmp[k++] = DestRest.top +tmpPosY;
524
tmp[k++] = tmp1->Color.r;
525
tmp[k++] = tmp1->Color.g;
526
tmp[k++] = tmp1->Color.b;
527
tmp[k++] = tmp1->Alpha;
528
tmp[k++] = FrameWidth;
529
tmp[k++] = 1.0f-FrameHeight;
531
tmp[k++] = DestRest.left + (DestRest.right - DestRest.left);
532
tmp[k++] = DestRest.top +tmpPosY +(DestRest.bottom - DestRest.top);
533
tmp[k++] = tmp1->Color.r;
534
tmp[k++] = tmp1->Color.g;
535
tmp[k++] = tmp1->Color.b;
536
tmp[k++] = tmp1->Alpha;
537
tmp[k++] = FrameWidth;
544
vw_SendVertices(RI_QUADS, 4*CurrentCount, RI_2f_XY | RI_1_TEX | RI_4f_COLOR, tmp, 8*sizeof(float));
546
if (tmp != 0){delete [] tmp; tmp = 0;}
547
vw_SetTextureBlend(false, 0, 0);
548
vw_SetColor(1.0f, 1.0f, 1.0f, 1.0f);
549
vw_BindTexture(0, 0);
554
//-----------------------------------------------------------------------------
555
// перемещение всех частиц и центра
556
//-----------------------------------------------------------------------------
557
void eParticleSystem2D::MoveSystem(VECTOR3D NewLocation)
559
VECTOR3D PrevLocation = Location;
560
Location = NewLocation;
563
eParticle2D *tmp = Start;
566
eParticle2D *tmp2 = tmp->Next;
567
// меняем каждой частице
568
tmp->Location += NewLocation-PrevLocation;
574
//-----------------------------------------------------------------------------
575
// перемещение центра
576
//-----------------------------------------------------------------------------
577
void eParticleSystem2D::MoveSystemLocation(VECTOR3D NewLocation)
579
Location = NewLocation;
584
//-----------------------------------------------------------------------------
586
//-----------------------------------------------------------------------------
587
void eParticleSystem2D::SetRotation(VECTOR3D NewAngle)
589
Matrix33CreateRotate(RotationMatrix, Angle^-1);
590
Matrix33CreateRotate(RotationMatrix, NewAngle);