1 /************************************************************************************
2
3 AstroMenace
4 Hardcore 3D space scroll-shooter with spaceship upgrade possibilities.
5 Copyright (c) 2006-2019 Mikhail Kurinnoi, Viewizard
6
7
8 AstroMenace is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 AstroMenace is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with AstroMenace. If not, see <https://www.gnu.org/licenses/>.
20
21
22 Website: https://viewizard.com/
23 Project: https://github.com/viewizard/astromenace
24 E-mail: viewizard@viewizard.com
25
26 *************************************************************************************/
27
28 // TODO add initialization via XML file, hard coded initialization should be removed
29 // TODO remove GetPreloadedTextureAsset() call from main loop
30
31 // TODO probably, we could use GL_EXT_draw_instanced here in future
32 // render 'space dust' instanced (send position and size in texture), instead of render 3 layer
33
34 /*
35 In order to show movement and more 'live' space, star system render "space dust" with 3 tile-animated layers:
36 1. Small and far space dust, looks more like 'clouds'. This layer rendered first, before all objects in the foreground.
37 2. Far 'big' space dust. This layer rendered second with higher speed, before all objects in the foreground.
38 3. Close space dust. This layer rendered with highest speed, after all 3D objects.
39 */
40
41 #include "../config/config.h"
42 #include "../assets/texture.h"
43 #include "../object3d/space_object/space_object.h"
44 #include "skybox.h"
45 #include "../game/camera.h"
46
47 // NOTE switch to nested namespace definition (namespace A::B::C { ... }) (since C++17)
48 namespace viewizard {
49 namespace astromenace {
50
51 namespace {
52
53 // StarSystem initialization status
54 bool StarSystem_InitedAll{false};
55 bool StarSystem_Inited{false};
56 // StarSystem rotation
57 sVECTOR3D StarSystem_BaseRotation(0.0f, 0.0f, 0.0f);
58
59 // particle system for space dust
60 std::weak_ptr<cParticleSystem> psSpace;
61
62 // tile animation for space dust (2 layers)
63 float StarsTile{0.0f};
64 float StarsTile2{0.0f};
65 float StarsTileUpdateTime{0.0f};
66 float StarsTileUpdateTime2{0.0f};
67 float StarsTileStartTransparentLayer1{0.0f};
68 float StarsTileEndTransparentLayer1{0.0f};
69 float StarsTileStartTransparentLayer2{0.0f};
70 float StarsTileEndTransparentLayer2{0.0f};
71
72 sVECTOR3D InGameInitialLocation{0, 10, 250};
73
74 // vertex array for rendering
75 float VertexArray[36]; // 4 * 9 = 4 vertices * (RI_3f_XYZ | RI_4f_COLOR | RI_1_TEX);
76 unsigned int VertexArrayPosition{0};
77
78 } // unnamed namespace
79
80
81 /*
82 * Star system initialization.
83 */
StarSystemInit(int Num,sVECTOR3D SetBaseRotation)84 void StarSystemInit(int Num, sVECTOR3D SetBaseRotation)
85 {
86 // SkyBox setup
87 switch (Num) {
88 case 1:
89 SkyBoxCreate(0.0f, 0.0f, 0.0f, 100.0f, 100.0f, 100.0f);
90 SkyBoxSetTexture(GetPreloadedTextureAsset("skybox/1/skybox_back6.tga"), eSide::BACK);
91 SkyBoxSetTexture(GetPreloadedTextureAsset("skybox/1/skybox_bottom4.tga"), eSide::BOTTOM);
92 SkyBoxSetTexture(GetPreloadedTextureAsset("skybox/1/skybox_front5.tga"), eSide::FRONT);
93 SkyBoxSetTexture(GetPreloadedTextureAsset("skybox/1/skybox_left2.tga"), eSide::LEFT);
94 SkyBoxSetTexture(GetPreloadedTextureAsset("skybox/1/skybox_right1.tga"), eSide::RIGHT);
95 SkyBoxSetTexture(GetPreloadedTextureAsset("skybox/1/skybox_top3.tga"), eSide::TOP);
96 StarSystem_Inited = true;
97 break;
98 case 2:
99 SkyBoxCreate(0.0f, 0.0f, 0.0f, 100.0f, 100.0f, 100.0f);
100 SkyBoxSetTexture(GetPreloadedTextureAsset("skybox/2/skybox_back6.tga"), eSide::BACK);
101 SkyBoxSetTexture(GetPreloadedTextureAsset("skybox/2/skybox_bottom4.tga"), eSide::BOTTOM);
102 SkyBoxSetTexture(GetPreloadedTextureAsset("skybox/2/skybox_front5.tga"), eSide::FRONT);
103 SkyBoxSetTexture(GetPreloadedTextureAsset("skybox/2/skybox_left2.tga"), eSide::LEFT);
104 SkyBoxSetTexture(GetPreloadedTextureAsset("skybox/2/skybox_right1.tga"), eSide::RIGHT);
105 SkyBoxSetTexture(GetPreloadedTextureAsset("skybox/2/skybox_top3.tga"), eSide::TOP);
106 StarSystem_Inited = true;
107 break;
108 default:
109 std::cerr << __func__ << "(): " << "wrong Num.\n";
110 break;
111 }
112
113 // StarSystem setup
114 StarSystem_InitedAll = true;
115 StarSystem_BaseRotation = SetBaseRotation;
116 }
117
118 /*
119 * Star system initialization by game's part type (menu/game).
120 */
StarSystemInitByType(eDrawType DrawType)121 void StarSystemInitByType(eDrawType DrawType)
122 {
123 StarsTileStartTransparentLayer1 = 0.2f;
124 StarsTileEndTransparentLayer1 = 0.7f;
125 StarsTileStartTransparentLayer2 = 0.9f;
126 StarsTileEndTransparentLayer2 = 0.7f;
127
128 switch (DrawType) {
129 case eDrawType::MENU:
130 StarsTileUpdateTime = vw_GetTimeThread(0);
131 StarsTileUpdateTime2 = vw_GetTimeThread(0);
132 psSpace = vw_CreateParticleSystem();
133 if (auto sharedSpace = psSpace.lock()) {
134 sharedSpace->ColorStart.r = 0.80f;
135 sharedSpace->ColorStart.g = 0.80f;
136 sharedSpace->ColorStart.b = 1.00f;
137 sharedSpace->ColorEnd.r = 0.70f;
138 sharedSpace->ColorEnd.g = 0.70f;
139 sharedSpace->ColorEnd.b = 1.00f;
140 sharedSpace->AlphaStart = 1.00f;
141 sharedSpace->AlphaEnd = 0.00f;
142 sharedSpace->SizeStart = 0.10f;
143 sharedSpace->SizeVar = 0.05f;
144 sharedSpace->SizeEnd = 0.30f;
145 sharedSpace->Speed = 4.00f;
146 sharedSpace->SpeedVar = 8.00f;
147 sharedSpace->Theta = 0.00f;
148 sharedSpace->Life = 10.00f;
149 sharedSpace->LifeVar = 0.00f;
150 sharedSpace->CreationType = eParticleCreationType::Cube;
151 sharedSpace->CreationSize = sVECTOR3D{2.0f, 50.0f, 30.0f};
152 sharedSpace->ParticlesPerSec = 140;
153 sharedSpace->Texture = GetPreloadedTextureAsset("gfx/flare3.tga");
154 sharedSpace->Direction = sVECTOR3D{1.0f, 0.0f, 0.0f};
155 sharedSpace->CameraDistResize = 0.1f;
156 sharedSpace->SetStartLocation(sVECTOR3D{-50.0f, 10.0f, -20.0f});
157
158 // emulate time flow, particles should fill the screen
159 float Time = sharedSpace->TimeLastUpdate;
160 for (float i = Time; i < (Time + 20); i += 1.0f) {
161 sharedSpace->Update(i);
162 }
163 sharedSpace->TimeLastUpdate = Time;
164 }
165 break;
166 case eDrawType::GAME:
167 StarsTileUpdateTime = vw_GetTimeThread(1);
168 StarsTileUpdateTime2 = vw_GetTimeThread(1);
169 psSpace = vw_CreateParticleSystem();
170 if (auto sharedSpace = psSpace.lock()) {
171 sharedSpace->ColorStart.r = 0.80f;
172 sharedSpace->ColorStart.g = 0.80f;
173 sharedSpace->ColorStart.b = 1.00f;
174 sharedSpace->ColorEnd.r = 0.70f;
175 sharedSpace->ColorEnd.g = 0.70f;
176 sharedSpace->ColorEnd.b = 1.00f;
177 sharedSpace->AlphaStart = 0.50f;
178 sharedSpace->AlphaEnd = 1.00f;
179 sharedSpace->SizeStart = 0.40f;
180 sharedSpace->SizeEnd = 0.05f;
181 sharedSpace->Speed = 25.00f;
182 sharedSpace->SpeedVar = 5.00f;
183 sharedSpace->Theta = 0.00f;
184 sharedSpace->Life = 14.00f;
185 sharedSpace->LifeVar = 0.00f;
186 sharedSpace->CreationType = eParticleCreationType::Cube;
187 sharedSpace->CreationSize = sVECTOR3D{200.0f, 30.0f, 10.0f};
188 sharedSpace->ParticlesPerSec = 100;
189 sharedSpace->Texture = GetPreloadedTextureAsset("gfx/flare3.tga");
190 sharedSpace->Direction = sVECTOR3D{0.0f, 0.0f, -1.0f};
191 sharedSpace->SetStartLocation(InGameInitialLocation);
192
193 // emulate time flow, particles should fill the screen
194 float Time = sharedSpace->TimeLastUpdate;
195 for (float i = Time; i < (Time + 25); i += 1.0f) {
196 sharedSpace->Update(i);
197 }
198 sharedSpace->TimeLastUpdate = Time;
199 }
200 break;
201 }
202 }
203
204 /*
205 * Setup first and second layers transparency.
206 */
StarSystemLayer1Transp(float Start,float End)207 void StarSystemLayer1Transp(float Start, float End)
208 {
209 StarsTileStartTransparentLayer1 = Start;
210 StarsTileEndTransparentLayer1 = End;
211 }
212
213 /*
214 * Setup third layer transparency.
215 */
StarSystemLayer3Transp(float Start,float End)216 void StarSystemLayer3Transp(float Start, float End)
217 {
218 StarsTileStartTransparentLayer2 = Start;
219 StarsTileEndTransparentLayer2 = End;
220 }
221
222 /*
223 * Release star system.
224 */
StarSystemRelease()225 void StarSystemRelease()
226 {
227 for (unsigned i = 0; i < static_cast<unsigned>(eSide::size); i++)
228 SkyBoxSetTexture(0, static_cast<eSide>(i));
229
230 StarSystem_Inited = false;
231 }
232
233 /*
234 * Draw local vertex array.
235 */
DrawVertexArray()236 static inline void DrawVertexArray()
237 {
238 vw_Draw3D(ePrimitiveType::TRIANGLE_STRIP, 4,
239 RI_3f_XYZ | RI_4f_COLOR | RI_1_TEX,
240 VertexArray, 9 * sizeof(VertexArray[0]));
241 }
242
243 /*
244 * Add vertex to to local vertex array.
245 */
AddToVertexArray(float CoordX,float CoordY,float CoordZ,sRGBCOLOR Color,float Alpha,float TextureU,float TextureV)246 static inline void AddToVertexArray(float CoordX, float CoordY, float CoordZ,
247 sRGBCOLOR Color, float Alpha,
248 float TextureU, float TextureV)
249 {
250 VertexArray[VertexArrayPosition++] = CoordX;
251 VertexArray[VertexArrayPosition++] = CoordY;
252 VertexArray[VertexArrayPosition++] = CoordZ;
253 VertexArray[VertexArrayPosition++] = Color.r;
254 VertexArray[VertexArrayPosition++] = Color.g;
255 VertexArray[VertexArrayPosition++] = Color.b;
256 VertexArray[VertexArrayPosition++] = Alpha;
257 VertexArray[VertexArrayPosition++] = TextureU;
258 VertexArray[VertexArrayPosition++] = TextureV;
259 }
260
261 /*
262 * Draw star system.
263 */
StarSystemDraw(eDrawType DrawType)264 void StarSystemDraw(eDrawType DrawType)
265 {
266 if (!StarSystem_InitedAll) return;
267
268 // current camera location
269 sVECTOR3D CurrentCameraLocation;
270 vw_GetCameraLocation(&CurrentCameraLocation);
271
272 if (StarSystem_Inited) {
273 vw_DepthTest(false, eCompareFunc::LESS);
274
275 // SkyBox
276 vw_PushMatrix();
277 vw_Translate(CurrentCameraLocation);
278 vw_Rotate(StarSystem_BaseRotation.x, 1.0f, 0.0f, 0.0f);
279 vw_Rotate(StarSystem_BaseRotation.y, 0.0f, 1.0f, 0.0f);
280 vw_Rotate(StarSystem_BaseRotation.z, 0.0f, 0.0f, 1.0f);
281 SkyBoxDraw();
282 vw_PopMatrix();
283
284 vw_DepthTest(true, eCompareFunc::LEQUAL);
285 }
286
287 // FIXME should be moved to 'space_object' code
288 // planets and big asteroids should be rendered before 'space dust'
289 ForEachSpaceObject([&] (cSpaceObject &tmpSpace) {
290 if (tmpSpace.ObjectType == eObjectType::Planet) {
291 if (DrawType == eDrawType::GAME) {
292 vw_PushMatrix();
293 vw_Translate(sVECTOR3D{CurrentCameraLocation.x * 0.90f - GetCameraShake() * 4.0f,
294 GetCameraShake() * 2.0f,
295 0.0f});
296 }
297 tmpSpace.Draw(false);
298 if (DrawType == eDrawType::GAME)
299 vw_PopMatrix();
300 }
301 });
302
303 // planetoids much more closer to player, than planets, clear the depth buffer
304 vw_Clear(RI_DEPTH_BUFFER);
305
306 ForEachSpaceObject([&] (cSpaceObject &tmpSpace) {
307 if (tmpSpace.ObjectType == eObjectType::Planetoid) {
308 if (DrawType == eDrawType::GAME) {
309 vw_PushMatrix();
310 vw_Translate(sVECTOR3D{CurrentCameraLocation.x * 0.70f - GetCameraShake() * 4.0f,
311 GetCameraShake() * 2.0f,
312 0.0f});
313 }
314 tmpSpace.Draw(false);
315 if (DrawType == eDrawType::GAME)
316 vw_PopMatrix();
317 }
318 });
319
320 // 'space dust' much more closer to player, than planets and planetoids, clear the depth buffer
321 vw_Clear(RI_DEPTH_BUFFER);
322
323 float width_2{0.0f};
324 float heigh_2{110.0f};
325 float length_2{110.0f};
326 float x{GetCameraCoveredDistance().x};
327 float y{GetCameraCoveredDistance().y};
328 float z{GetCameraCoveredDistance().z};
329 float StartTransparentLayer1{0.7f};
330 float EndTransparentLayer1{0.7f};
331 sRGBCOLOR Color{1.0f, 1.0f, 1.0f};
332
333 if (DrawType == eDrawType::GAME) {
334 width_2 = length_2 = 175.0f;
335 heigh_2 = 0.0f;
336
337 x = GetCameraCoveredDistance().x + GetCameraShake() + CurrentCameraLocation.x * 0.8f;
338 y = GetCameraCoveredDistance().y - GetCameraShake() * 0.5f;
339 z = GetCameraCoveredDistance().z + 25.0f;
340
341 StartTransparentLayer1 = StarsTileStartTransparentLayer1;
342 EndTransparentLayer1 = StarsTileEndTransparentLayer1;
343 }
344
345 // first 'space dust' layer (clouds)
346 VertexArrayPosition = 0;
347 AddToVertexArray(x + width_2, y + heigh_2, z + length_2 + length_2 / 2.0f,
348 Color, StartTransparentLayer1,
349 1.0f, 0.0f + StarsTile / 3.0f);
350 AddToVertexArray(x + width_2, y + heigh_2, z - length_2 / 2.0f,
351 Color, EndTransparentLayer1,
352 1.0f, 1.0f + StarsTile / 3.0f);
353 AddToVertexArray(x - width_2, y - heigh_2, z + length_2 + length_2 / 2.0f,
354 Color, StartTransparentLayer1,
355 0.0f, 0.0f + StarsTile / 3.0f);
356 AddToVertexArray(x - width_2, y - heigh_2, z - length_2/2,
357 Color, EndTransparentLayer1,
358 0.0f, 1.0f + StarsTile / 3.0f);
359
360 if (DrawType == eDrawType::MENU) {
361 StarsTile -= 0.015f * (vw_GetTimeThread(0) - StarsTileUpdateTime);
362 StarsTileUpdateTime = vw_GetTimeThread(0);
363 } else {
364 StarsTile -= 0.035f * (vw_GetTimeThread(1) - StarsTileUpdateTime);
365 StarsTileUpdateTime = vw_GetTimeThread(1);
366 }
367
368 if (StarsTile < -3.0f)
369 StarsTile += 3.0f;
370
371 GLtexture TileTexture = GetPreloadedTextureAsset("skybox/tile_back.tga");
372 vw_BindTexture(0, TileTexture);
373 vw_SetTextureBlend(true, eTextureBlendFactor::SRC_ALPHA, eTextureBlendFactor::ONE);
374
375 vw_DepthTest(false, eCompareFunc::LESS);
376
377 if (DrawType == eDrawType::MENU) {
378 vw_PushMatrix();
379 vw_Rotate(-20.0f, 0.0f, 0.0f, 1.0f);
380 vw_Rotate(-45.0f, 0.0f, 1.0f, 0.0f);
381 vw_Rotate(30.0f, 1.0f, 0.0f, 0.0f);
382 }
383
384 DrawVertexArray();
385
386 // second 'space dust' layer
387 VertexArrayPosition = 0;
388 AddToVertexArray(x + width_2, y + heigh_2, z + length_2 + length_2 / 2.0f,
389 Color, StartTransparentLayer1,
390 3.0f, 0.0f + StarsTile);
391 AddToVertexArray(x + width_2, y + heigh_2, z - length_2 / 2.0f,
392 Color, EndTransparentLayer1,
393 3.0f, 3.0f + StarsTile);
394 AddToVertexArray(x - width_2, y - heigh_2, z + length_2 + length_2 / 2.0f,
395 Color, StartTransparentLayer1,
396 0.0f, 0.0f + StarsTile);
397 AddToVertexArray(x - width_2, y - heigh_2, z - length_2/2,
398 Color, EndTransparentLayer1,
399 0.0f, 3.0f + StarsTile);
400
401 vw_BindTexture(0, GetPreloadedTextureAsset("skybox/tile_stars.tga"));
402
403 DrawVertexArray();
404
405 if (DrawType == eDrawType::MENU)
406 vw_PopMatrix();
407
408 vw_DepthTest(true, eCompareFunc::LEQUAL);
409
410 vw_SetTextureBlend(false, eTextureBlendFactor::ONE, eTextureBlendFactor::ZERO);
411 vw_BindTexture(0, 0);
412
413 // care about in-game camera movements
414 if (DrawType == eDrawType::GAME) {
415 if (auto sharedSpace = psSpace.lock()) {
416 sharedSpace->SetStartLocation(sharedSpace->GetLocation());
417 sharedSpace->MoveSystemLocation(InGameInitialLocation + GetCameraCoveredDistance());
418 }
419 }
420 }
421
422 /*
423 * Draw third layer of space dust.
424 */
StarSystemDrawThirdLayer(eDrawType DrawType)425 void StarSystemDrawThirdLayer(eDrawType DrawType)
426 {
427 // VisualEffectsQuality is inverted (0 - all effects, 2 - minimum effects)
428 if (GameConfig().VisualEffectsQuality > 1)
429 return;
430
431 float width_2{0.0f};
432 float heigh_2{110.0f};
433 float length_2{110.0f};
434 float x{GetCameraCoveredDistance().x};
435 float y{GetCameraCoveredDistance().y};
436 float z{GetCameraCoveredDistance().z};
437 float StartTransparentLayer2{0.9f};
438 float EndTransparentLayer2{0.7f};
439 sRGBCOLOR Color{1.0f, 1.0f, 1.0f};
440
441 if (DrawType == eDrawType::GAME) {
442 width_2 = length_2 = 175.0f;
443 heigh_2 = 0.0f;
444
445 sVECTOR3D CurrentCameraLocation;
446 vw_GetCameraLocation(&CurrentCameraLocation);
447
448 x = GetCameraCoveredDistance().x + GetCameraShake() * 2.0f + CurrentCameraLocation.x * 0.5f;
449 y = GetCameraCoveredDistance().y - GetCameraShake();
450 z = GetCameraCoveredDistance().z + 25.0f;
451
452 StartTransparentLayer2 = StarsTileStartTransparentLayer2;
453 EndTransparentLayer2 = StarsTileEndTransparentLayer2;
454 }
455
456 VertexArrayPosition = 0;
457 AddToVertexArray(x + width_2, y + heigh_2, z + length_2 + length_2/ 2.0f,
458 Color, StartTransparentLayer2,
459 3.2f, 0.0f + StarsTile2);
460 AddToVertexArray(x + width_2, y + heigh_2, z - length_2 / 2.0f,
461 Color, EndTransparentLayer2,
462 3.2f, 3.0f + StarsTile2);
463 AddToVertexArray(x - width_2, y - heigh_2, z + length_2 + length_2 / 2.0f,
464 Color, StartTransparentLayer2,
465 0.2f, 0.0f + StarsTile2);
466 AddToVertexArray(x - width_2, y - heigh_2, z - length_2 / 2.0f,
467 Color, EndTransparentLayer2,
468 0.2f, 3.0f + StarsTile2);
469
470 if (DrawType == eDrawType::MENU) {
471 StarsTile2 -= 0.04f * (vw_GetTimeThread(0) - StarsTileUpdateTime2);
472 StarsTileUpdateTime2 = vw_GetTimeThread(0);
473 } else {
474 StarsTile2 -= 0.12f * (vw_GetTimeThread(1) - StarsTileUpdateTime2);
475 StarsTileUpdateTime2 = vw_GetTimeThread(1);
476 }
477 if (StarsTile2 < -3.0f)
478 StarsTile2 += 3.0f;
479
480 GLtexture TileTexture = GetPreloadedTextureAsset("skybox/tile_stars.tga");
481 vw_BindTexture(0, TileTexture);
482 vw_SetTextureBlend(true, eTextureBlendFactor::SRC_ALPHA, eTextureBlendFactor::ONE);
483 vw_DepthTest(false, eCompareFunc::LESS);
484
485 if (DrawType == eDrawType::MENU) {
486 vw_PushMatrix();
487 vw_Rotate(-20.0f, 0.0f, 0.0f, 1.0f);
488 vw_Rotate(-45.0f, 0.0f, 1.0f, 0.0f);
489 vw_Rotate(30.0f, 1.0f, 0.0f, 0.0f);
490 }
491
492 DrawVertexArray();
493
494 if (DrawType == eDrawType::MENU)
495 vw_PopMatrix();
496
497 vw_DepthTest(true, eCompareFunc::LEQUAL);
498 vw_SetTextureBlend(false, eTextureBlendFactor::ONE, eTextureBlendFactor::ZERO);
499 vw_BindTexture(0, 0);
500 }
501
502 } // astromenace namespace
503 } // viewizard namespace
504