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 "SpaceStars.h"
29
#include "../../Game.h"
34
//-----------------------------------------------------------------------------
35
// инициализация класса
36
//-----------------------------------------------------------------------------
37
CSpaceStars::CSpaceStars()
40
TimeLastUpdate = -1.0f;
43
Location = VECTOR3D( 0.0f, 0.0f, 0.0f);
46
CreationSize = VECTOR3D(5.21f,5.21f,5.21f);
47
Texture = vw_FindTextureByName("DATA/GFX/flare1.tga");
54
GLSL = vw_FindShaderByName("SpaceStars");
55
UniformLocations[0] = vw_GetUniformLocation(GLSL, "ParticleTexture");
56
UniformLocations[1] = vw_GetUniformLocation(GLSL, "ParticleAge");
61
// начальные установки для мартиц поворотов
62
Matrix33Identity(CurrentRotationMat);
63
Matrix33Identity(OldInvRotationMat);
70
unsigned int ParticlesCreated = 10000 - 4000*Setup.VisualEffectsQuality;
72
// пока не создадим все необходимые частицы
73
while (ParticlesCreated > 0)
75
// создаем новую частицу
76
CStar *NewParticle = 0;
77
NewParticle = new CStar; if (NewParticle == 0) return;
80
// считаем значение альфы
81
NewParticle->Alpha = 0.5f + 0.5f * vw_Randf1;
82
// убираем переполнение
83
Clamp( NewParticle->Alpha, 0.0f, 1.0f );
84
// считаем дельту альфы
85
NewParticle->AlphaDelta = (1.5f + 1.5f * vw_Randf1) / 3.0f;
89
// выпускаем частицу возле места нахождения системы
92
float minDist = CreationSize.x*CreationSize.x+CreationSize.y*CreationSize.y+CreationSize.z*CreationSize.z;
93
// если зона больше чем радиус излучения - выключаем ее
94
if (minDist <= DeadZone*DeadZone) DeadZone = 0.0f;
96
// прибавляем к рандому, чтобы избежать вероятности появления всех трех нулей и деления на ноль в дальнейшем
97
tmp.x = (vw_Randf0 + 0.00001f) * CreationSize.x;
98
tmp.y = vw_Randf0 * CreationSize.y;
99
tmp.z = vw_Randf0 * CreationSize.z;
100
float ParticleDist = tmp.x*tmp.x + tmp.y*tmp.y + tmp.z*tmp.z;
101
while (ParticleDist > minDist || ParticleDist < DeadZone*DeadZone)
103
if (ParticleDist > minDist)
108
tmp1 = tmp1^(1/100.0f);
111
if ( ParticleDist < DeadZone*DeadZone)
116
tmp1 = tmp1^(1/100.0f);
120
{if (tmp.x > CreationSize.x) tmp.x = CreationSize.x;}
122
{if (tmp.x < -CreationSize.x) tmp.x = -CreationSize.x;}
124
{if (tmp.y > CreationSize.y) tmp.y = CreationSize.y;}
126
{if (tmp.y < -CreationSize.y) tmp.y = -CreationSize.y;}
129
{if (tmp.z > CreationSize.z) tmp.z = CreationSize.z;}
131
{if (tmp.z < -CreationSize.z) tmp.z = -CreationSize.z;}
133
ParticleDist = tmp.x*tmp.x + tmp.y*tmp.y + tmp.z*tmp.z;
136
Matrix33CalcPoint(&tmp, CurrentRotationMat);
137
NewParticle->Location = Location + tmp;
141
// подключаем частицу к системе
144
// уменьшаем необходимое количество частиц
154
LastCameraAngleX = LastCameraAngleY = LastCameraAngleZ = 0.0f;
158
//-----------------------------------------------------------------------------
159
// При разрушении класса
160
//-----------------------------------------------------------------------------
161
CSpaceStars::~CSpaceStars()
163
// полностью освобождаем память от всех частиц в системе
167
CStar *tmp2 = tmp->Next;
173
if (VBO!=0){vw_DeleteVBO(*VBO); delete VBO; VBO=0;}
174
if (tmpDATA!=0){delete [] tmpDATA; tmpDATA = 0;}
175
if (list!=0){delete [] list; list = 0;}
179
//-----------------------------------------------------------------------------
180
// подключить частицу к системе
181
//-----------------------------------------------------------------------------
182
void CSpaceStars::Attach(CStar * NewParticle)
184
if (NewParticle == 0) return;
186
// первый в списке...
189
NewParticle->Prev = 0;
190
NewParticle->Next = 0;
194
else // продолжаем заполнение...
196
NewParticle->Prev = End;
197
NewParticle->Next = 0;
198
End->Next = NewParticle;
205
//-----------------------------------------------------------------------------
206
// отключить ее от системы
207
//-----------------------------------------------------------------------------
208
void CSpaceStars::Detach(CStar * OldParticle)
210
if (OldParticle == 0) return;
212
// переустанавливаем указатели...
213
if (Start == OldParticle) Start = OldParticle->Next;
214
if (End == OldParticle) End = OldParticle->Prev;
217
if (OldParticle->Next != 0) OldParticle->Next->Prev = OldParticle->Prev;
218
else if (OldParticle->Prev != 0) OldParticle->Prev->Next = 0;
219
if (OldParticle->Prev != 0) OldParticle->Prev->Next = OldParticle->Next;
220
else if (OldParticle->Next != 0) OldParticle->Next->Prev = 0;
228
//-----------------------------------------------------------------------------
229
// обновление системы
230
//-----------------------------------------------------------------------------
231
bool CSpaceStars::Update(float Time)
233
// первый раз... просто берем время
234
if (TimeLastUpdate == -1.0f) {TimeLastUpdate = Time;return true;}
236
// Time - это абсолютное время, вычисляем дельту
237
float TimeDelta = Time - TimeLastUpdate;
238
// быстро вызвали еще раз... время не изменилось, или почти не изменилось
239
if (TimeDelta == 0.0f) return true;
241
TimeLastUpdate = Time;
245
// эти расчеты делаем в шейдере, они нам не нужны
252
CStar *tmp2 = tmp->Next;
253
// функция вернет false, если частица уже мертва
254
if (!tmp->Update(TimeDelta))
262
// обновляем данные в массиве прорисовки
263
if (tmpDATA != 0 && list != 0)
265
// для каждого меняем альфу
268
GLubyte *tmpDATAub = (GLubyte *)tmpDATA;
270
for (int i=0; i<PrimitCount; i++)
272
A = (GLubyte)(list[i]->Alpha*255);
275
tmpDATAub[k*sizeof(float)+3] = A;
277
tmpDATAub[k*sizeof(float)+3] = A;
279
tmpDATAub[k*sizeof(float)+3] = A;
281
tmpDATAub[k*sizeof(float)+3] = A;
294
//-----------------------------------------------------------------------------
295
// прорисовка системы
296
//-----------------------------------------------------------------------------
297
void CSpaceStars::Draw()
300
// загрузка текстуры, уже должна быть подключена
301
if (Texture == 0) return;
303
VECTOR3D CurrentCameraRotation;
304
vw_GetCameraRotation(&CurrentCameraRotation);
307
// если еще нет последовательности, или камеру повернули - надо пересчитать прорисовку
308
if ((tmpDATA == 0 && VBO == 0) || CurrentCameraRotation.x != LastCameraAngleX || CurrentCameraRotation.y != LastCameraAngleY || CurrentCameraRotation.z != LastCameraAngleZ)
311
if (list != 0){delete [] list; list = 0;}
312
if (tmpDATA != 0){delete [] tmpDATA; tmpDATA = 0;}
313
if (VBO!=0){vw_DeleteVBO(*VBO); delete VBO; VBO=0;}
315
// находим реальное кол-во частиц на прорисовку
320
LastCameraAngleX = CurrentCameraRotation.x;
321
LastCameraAngleY = CurrentCameraRotation.y;
322
LastCameraAngleZ = CurrentCameraRotation.z;
324
// получаем текущее положение камеры
325
VECTOR3D CurrentCameraLocation;
326
vw_GetCameraLocation(&CurrentCameraLocation);
331
CStar *tmp2 = tmp->Next;
332
// небольшая оптимизация, если попадает в сферу - рисуем, нет - значит не видно
333
if (vw_SphereInFrustum(tmp->Location + CurrentCameraLocation, Size))
338
// если рисовать нечего - выходим
339
if (PrimitCount == 0) return;
341
// список, в котором они будут упорядочены
342
list = new CStar*[PrimitCount]; if (list == 0) return;
349
CStar *tmp2 = tmp->Next;
350
// небольшая оптимизация, если попадает в сферу - рисуем, нет - значит не видно
351
if (vw_SphereInFrustum(tmp->Location + CurrentCameraLocation, Size))
353
list[LenCount] = tmp;
361
// если не поддерживаем/не включены шейдеры, или нет поддержки вбо
362
// делаем старым способом, через временный буфер
365
// делаем массив для всех элементов
366
// войдет RI_3f_XYZ | RI_2f_TEX | RI_4ub_COLOR
367
tmpDATA = new float[4*(3+2+1)*PrimitCount]; if (tmpDATA == 0) return;
368
GLubyte *tmpDATAub = (GLubyte *)tmpDATA;
370
// номер float'а в последовательности
373
for (int i=0; i<PrimitCount; i++)
375
// находим вектор камера-точка
377
// смотрим, если есть не нужно поворачивать, работаем с направлением
378
nnTmp = list[i]->Location^(-1.0f);
380
// находим перпендикуляр к вектору nnTmp
384
nnTmp2.z = -(nnTmp.x + nnTmp.y)/nnTmp.z;
386
// находим перпендикуляр к векторам nnTmp и nnTmp2
387
// файтически - a x b = ( aybz - byaz , azbx - bzax , axby - bxay );
389
nnTmp3.x = nnTmp.y*nnTmp2.z - nnTmp2.y*nnTmp.z;
390
nnTmp3.y = nnTmp.z*nnTmp2.x - nnTmp2.z*nnTmp.x;
391
nnTmp3.z = nnTmp.x*nnTmp2.y - nnTmp2.x*nnTmp.y;
395
VECTOR3D tmpAngle1,tmpAngle2,tmpAngle3,tmpAngle4;
397
tmpAngle1 = nnTmp3^(Size*1.5f);
398
tmpAngle3 = nnTmp3^(-Size*1.5f);
399
tmpAngle2 = nnTmp2^(Size*1.5f);
400
tmpAngle4 = nnTmp2^(-Size*1.5f);
403
GLubyte A = (GLubyte)(list[i]->Alpha*255);
405
// собираем четырехугольник
407
tmpDATA[k++] = list[i]->Location.x+tmpAngle3.x; // X
408
tmpDATA[k++] = list[i]->Location.y+tmpAngle3.y; // Y
409
tmpDATA[k++] = list[i]->Location.z+tmpAngle3.z; // Z
410
tmpDATAub[k*sizeof(float)] = 204;
411
tmpDATAub[k*sizeof(float)+1] = 204;
412
tmpDATAub[k*sizeof(float)+2] = 255;
413
tmpDATAub[k*sizeof(float)+3] = A;
418
tmpDATA[k++] = list[i]->Location.x+tmpAngle2.x; // X
419
tmpDATA[k++] = list[i]->Location.y+tmpAngle2.y; // Y
420
tmpDATA[k++] = list[i]->Location.z+tmpAngle2.z; // Z
421
tmpDATAub[k*sizeof(float)] = 204;
422
tmpDATAub[k*sizeof(float)+1] = 204;
423
tmpDATAub[k*sizeof(float)+2] = 255;
424
tmpDATAub[k*sizeof(float)+3] = A;
429
tmpDATA[k++] = list[i]->Location.x+tmpAngle1.x; // X
430
tmpDATA[k++] = list[i]->Location.y+tmpAngle1.y; // Y
431
tmpDATA[k++] = list[i]->Location.z+tmpAngle1.z; // Z
432
tmpDATAub[k*sizeof(float)] = 204;
433
tmpDATAub[k*sizeof(float)+1] = 204;
434
tmpDATAub[k*sizeof(float)+2] = 255;
435
tmpDATAub[k*sizeof(float)+3] = A;
440
tmpDATA[k++] = list[i]->Location.x+tmpAngle4.x; // X
441
tmpDATA[k++] = list[i]->Location.y+tmpAngle4.y; // Y
442
tmpDATA[k++] = list[i]->Location.z+tmpAngle4.z; // Z
443
tmpDATAub[k*sizeof(float)] = 204;
444
tmpDATAub[k*sizeof(float)+1] = 204;
445
tmpDATAub[k*sizeof(float)+2] = 255;
446
tmpDATAub[k*sizeof(float)+3] = A;
454
// все нормально, работаем с шейдерами и вбо
457
// делаем массив для всех элементов
458
// войдет RI_3f_XYZ | RI_2f_TEX | RI_3f_NORMAL*/
459
tmpDATA = new float[4*(3+2+3)*PrimitCount]; if (tmpDATA == 0) return;
461
// номер float'а в последовательности
464
for (int i=0; i<PrimitCount; i++)
466
// находим вектор камера-точка
468
// смотрим, если есть не нужно поворачивать, работаем с направлением
469
nnTmp = list[i]->Location^(-1.0f);
471
// находим перпендикуляр к вектору nnTmp
475
nnTmp2.z = -(nnTmp.x + nnTmp.y)/nnTmp.z;
477
// находим перпендикуляр к векторам nnTmp и nnTmp2
478
// файтически - a x b = ( aybz - byaz , azbx - bzax , axby - bxay );
480
nnTmp3.x = nnTmp.y*nnTmp2.z - nnTmp2.y*nnTmp.z;
481
nnTmp3.y = nnTmp.z*nnTmp2.x - nnTmp2.z*nnTmp.x;
482
nnTmp3.z = nnTmp.x*nnTmp2.y - nnTmp2.x*nnTmp.y;
486
VECTOR3D tmpAngle1,tmpAngle2,tmpAngle3,tmpAngle4;
488
tmpAngle1 = nnTmp3^(Size*1.5f);
489
tmpAngle3 = nnTmp3^(-Size*1.5f);
490
tmpAngle2 = nnTmp2^(Size*1.5f);
491
tmpAngle4 = nnTmp2^(-Size*1.5f);
494
// собираем четырехугольник
496
tmpDATA[k++] = list[i]->Location.x+tmpAngle3.x; // X
497
tmpDATA[k++] = list[i]->Location.y+tmpAngle3.y; // Y
498
tmpDATA[k++] = list[i]->Location.z+tmpAngle3.z; // Z
499
tmpDATA[k++] = 0.0f;// не задействован
500
tmpDATA[k++] = 0.0f;// не задействован
501
tmpDATA[k++] = list[i]->AlphaDelta;
505
tmpDATA[k++] = list[i]->Location.x+tmpAngle2.x; // X
506
tmpDATA[k++] = list[i]->Location.y+tmpAngle2.y; // Y
507
tmpDATA[k++] = list[i]->Location.z+tmpAngle2.z; // Z
508
tmpDATA[k++] = 0.0f;// не задействован
509
tmpDATA[k++] = 0.0f;// не задействован
510
tmpDATA[k++] = list[i]->AlphaDelta;
514
tmpDATA[k++] = list[i]->Location.x+tmpAngle1.x; // X
515
tmpDATA[k++] = list[i]->Location.y+tmpAngle1.y; // Y
516
tmpDATA[k++] = list[i]->Location.z+tmpAngle1.z; // Z
517
tmpDATA[k++] = 0.0f;// не задействован
518
tmpDATA[k++] = 0.0f;// не задействован
519
tmpDATA[k++] = list[i]->AlphaDelta;
523
tmpDATA[k++] = list[i]->Location.x+tmpAngle4.x; // X
524
tmpDATA[k++] = list[i]->Location.y+tmpAngle4.y; // Y
525
tmpDATA[k++] = list[i]->Location.z+tmpAngle4.z; // Z
526
tmpDATA[k++] = 1.0f;// не задействован
527
tmpDATA[k++] = 1.0f;// не задействован
528
tmpDATA[k++] = list[i]->AlphaDelta;
533
if (CAPS->VBOSupported)
535
VBO = new unsigned int;
536
if (!vw_BuildVBO(4*PrimitCount, tmpDATA, 8, VBO))
542
// только если поддерживае вбо, иначе им рисуем
543
if (tmpDATA != 0){delete [] tmpDATA; tmpDATA = 0;}
547
if (list != 0){delete [] list; list = 0;}
550
if (Len != 0){delete [] Len; Len = 0;}
559
vw_SetTexture(0, Texture);
560
vw_SetTextureBlend(true, RI_BLEND_SRCALPHA, RI_BLEND_ONE);
563
// получаем текущее положение камеры
564
VECTOR3D CurrentCameraLocation;
565
vw_GetCameraLocation(&CurrentCameraLocation);
566
CurrentCameraLocation += VECTOR3D(GameCameraGetDeviation()*0.9,-GameCameraGetDeviation()*0.5f,0.0f);
570
vw_Translate(CurrentCameraLocation);
576
vw_SendVertices(RI_QUADS, 4*PrimitCount, RI_3f_XYZ | RI_4ub_COLOR | RI_1_TEX, tmpDATA, 6*sizeof(float));
582
vw_UseShaderProgram(GLSL);
583
vw_Uniform1i(GLSL, UniformLocations[0], 0);
584
vw_Uniform1f(GLSL, UniformLocations[1], Age);
587
vw_SendVertices(RI_QUADS, 4*PrimitCount, RI_3f_XYZ | RI_1_TEX | RI_3f_NORMAL, tmpDATA, 8*sizeof(float), VBO);
589
if (GLSL != 0) vw_StopShaderProgram();
595
vw_SetTextureBlend(false, 0, 0);
602
vw_BindTexture(0, 0);