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 provide more rendering optimization in DrawObjectStatus()
29
30 // TODO codestyle should be fixed
31
32 #include "object3d.h"
33 #include "../config/config.h"
34 #include "../gfx/shadow_map.h"
35 #include "../script/script.h"
36 #include "../game.h" // FIXME "game.h" should be replaced by individual headers
37
38 // NOTE switch to nested namespace definition (namespace A::B::C { ... }) (since C++17)
39 namespace viewizard {
40 namespace astromenace {
41
42 namespace {
43
44 eRenderBoundingBoxes BBRenderMode{eRenderBoundingBoxes::None};
45
46 } // unnamed namespace
47
48 // FIXME should be fixed, don't allow global scope interaction for local variables
49 extern std::weak_ptr<cGLSL> GLSLShaderType1;
50 extern std::weak_ptr<cGLSL> GLSLShaderType2;
51 extern std::weak_ptr<cGLSL> GLSLShaderType3;
52
53
54 /*
55 * Set chunk location.
56 */
SetChunkLocation(const sVECTOR3D & NewLocation,unsigned ChunkNum)57 void cObject3D::SetChunkLocation(const sVECTOR3D &NewLocation, unsigned ChunkNum)
58 {
59 if (!HitBB.empty()) {
60 float OldInvRotationMatTmp[9];
61 memcpy(OldInvRotationMatTmp, CurrentRotationMat, 9 * sizeof(CurrentRotationMat[0]));
62 vw_Matrix33InverseRotate(OldInvRotationMatTmp);
63
64 vw_Matrix33CalcPoint(HitBB[ChunkNum].Location, OldInvRotationMatTmp);
65 HitBB[ChunkNum].Location -= Chunks[ChunkNum].Location - NewLocation;
66 vw_Matrix33CalcPoint(HitBB[ChunkNum].Location, CurrentRotationMat);
67
68 float MinX = 10000.0f;
69 float MaxX = -10000.0f;
70 float MinY = 10000.0f;
71 float MaxY = -10000.0f;
72 float MinZ = 10000.0f;
73 float MaxZ = -10000.0f;
74
75 for (unsigned int i = 0; i < Chunks.size(); i++) {
76 vw_Matrix33CalcPoint(HitBB[i].Location, OldInvRotationMatTmp);
77
78 for (int j = 0; j < 8; j++) {
79 vw_Matrix33CalcPoint(HitBB[i].Box[j], OldInvRotationMatTmp);
80
81 if (MinX > HitBB[i].Box[j].x + HitBB[i].Location.x)
82 MinX = HitBB[i].Box[j].x + HitBB[i].Location.x;
83 if (MaxX < HitBB[i].Box[j].x + HitBB[i].Location.x)
84 MaxX = HitBB[i].Box[j].x + HitBB[i].Location.x;
85 if (MinY > HitBB[i].Box[j].y + HitBB[i].Location.y)
86 MinY = HitBB[i].Box[j].y + HitBB[i].Location.y;
87 if (MaxY < HitBB[i].Box[j].y + HitBB[i].Location.y)
88 MaxY = HitBB[i].Box[j].y + HitBB[i].Location.y;
89 if (MinZ > HitBB[i].Box[j].z + HitBB[i].Location.z)
90 MinZ = HitBB[i].Box[j].z + HitBB[i].Location.z;
91 if (MaxZ < HitBB[i].Box[j].z + HitBB[i].Location.z)
92 MaxZ = HitBB[i].Box[j].z + HitBB[i].Location.z;
93
94 vw_Matrix33CalcPoint(HitBB[i].Box[j], CurrentRotationMat);
95 }
96 vw_Matrix33CalcPoint(HitBB[i].Location, CurrentRotationMat);
97 }
98
99 OBB.Box[0] = sVECTOR3D{MaxX, MaxY, MaxZ};
100 OBB.Box[1] = sVECTOR3D{MinX, MaxY, MaxZ};
101 OBB.Box[2] = sVECTOR3D{MinX, MaxY, MinZ};
102 OBB.Box[3] = sVECTOR3D{MaxX, MaxY, MinZ};
103 OBB.Box[4] = sVECTOR3D{MaxX, MinY, MaxZ};
104 OBB.Box[5] = sVECTOR3D{MinX, MinY, MaxZ};
105 OBB.Box[6] = sVECTOR3D{MinX, MinY, MinZ};
106 OBB.Box[7] = sVECTOR3D{MaxX, MinY, MinZ};
107
108 Width = fabsf(MaxX - MinX);
109 Height = fabsf(MaxY - MinY);
110 Length = fabsf(MaxZ - MinZ);
111
112 float Width2 = Width / 2.0f;
113 float Length2 = Length / 2.0f;
114 float Height2 = Height / 2.0f;
115 Radius = vw_sqrtf(Width2 * Width2 + Length2 * Length2 + Height2 * Height2);
116
117 OBB.Location.x = (MaxX + MinX) / 2.0f;
118 OBB.Location.y = (MaxY + MinY) / 2.0f;
119 OBB.Location.z = (MaxZ + MinZ) / 2.0f;
120
121 for (int k = 0; k < 8; k++) {
122 OBB.Box[k] -= OBB.Location;
123 vw_Matrix33CalcPoint(OBB.Box[k], CurrentRotationMat);
124 }
125 vw_Matrix33CalcPoint(OBB.Location, CurrentRotationMat);
126
127 MinX = MaxX = OBB.Box[0].x + OBB.Location.x;
128 MinY = MaxY = OBB.Box[0].y + OBB.Location.y;
129 MinZ = MaxZ = OBB.Box[0].z + OBB.Location.z;
130 for (int j = 0; j < 8; j++) {
131 if (MinX > OBB.Box[j].x + OBB.Location.x)
132 MinX = OBB.Box[j].x + OBB.Location.x;
133 if (MinY > OBB.Box[j].y + OBB.Location.y)
134 MinY = OBB.Box[j].y + OBB.Location.y;
135 if (MinZ > OBB.Box[j].z + OBB.Location.z)
136 MinZ = OBB.Box[j].z + OBB.Location.z;
137 if (MaxX < OBB.Box[j].x + OBB.Location.x)
138 MaxX = OBB.Box[j].x + OBB.Location.x;
139 if (MaxY < OBB.Box[j].y + OBB.Location.y)
140 MaxY = OBB.Box[j].y + OBB.Location.y;
141 if (MaxZ < OBB.Box[j].z + OBB.Location.z)
142 MaxZ = OBB.Box[j].z + OBB.Location.z;
143 }
144 AABB[0] = sVECTOR3D{MaxX, MaxY, MaxZ};
145 AABB[1] = sVECTOR3D{MinX, MaxY, MaxZ};
146 AABB[2] = sVECTOR3D{MinX, MaxY, MinZ};
147 AABB[3] = sVECTOR3D{MaxX, MaxY, MinZ};
148 AABB[4] = sVECTOR3D{MaxX, MinY, MaxZ};
149 AABB[5] = sVECTOR3D{MinX, MinY, MaxZ};
150 AABB[6] = sVECTOR3D{MinX, MinY, MinZ};
151 AABB[7] = sVECTOR3D{MaxX, MinY, MinZ};
152 }
153
154 Chunks[ChunkNum].Location = NewLocation;
155 }
156
157 /*
158 * Set chunk rotation.
159 */
SetChunkRotation(const sVECTOR3D & NewRotation,unsigned ChunkNum)160 void cObject3D::SetChunkRotation(const sVECTOR3D &NewRotation, unsigned ChunkNum)
161 {
162 if (!HitBB.empty()) {
163 float CurrentRotationMatTmp2[9];
164 vw_Matrix33CreateRotate(CurrentRotationMatTmp2, NewRotation);
165
166 float OldInvRotationMatTmp2[9];
167 vw_Matrix33CreateRotate(OldInvRotationMatTmp2, Chunks[ChunkNum].Rotation);
168 vw_Matrix33InverseRotate(OldInvRotationMatTmp2);
169
170 float OldInvRotationMatTmp[9];
171 memcpy(OldInvRotationMatTmp, CurrentRotationMat, 9 * sizeof(CurrentRotationMat[0]));
172 vw_Matrix33InverseRotate(OldInvRotationMatTmp);
173
174 vw_Matrix33CalcPoint(HitBB[ChunkNum].Location, OldInvRotationMatTmp);
175 HitBB[ChunkNum].Location -= Chunks[ChunkNum].Location;
176 vw_Matrix33CalcPoint(HitBB[ChunkNum].Location, OldInvRotationMatTmp2);
177 vw_Matrix33CalcPoint(HitBB[ChunkNum].Location, CurrentRotationMatTmp2);
178 HitBB[ChunkNum].Location += Chunks[ChunkNum].Location;
179 vw_Matrix33CalcPoint(HitBB[ChunkNum].Location, CurrentRotationMat);
180 for (int j = 0; j < 8; j++) {
181 vw_Matrix33CalcPoint(HitBB[ChunkNum].Box[j], OldInvRotationMatTmp);
182 vw_Matrix33CalcPoint(HitBB[ChunkNum].Box[j], OldInvRotationMatTmp2);
183 vw_Matrix33CalcPoint(HitBB[ChunkNum].Box[j], CurrentRotationMatTmp2);
184 vw_Matrix33CalcPoint(HitBB[ChunkNum].Box[j], CurrentRotationMat);
185 }
186
187 float MinX = 10000.0f;
188 float MaxX = -10000.0f;
189 float MinY = 10000.0f;
190 float MaxY = -10000.0f;
191 float MinZ = 10000.0f;
192 float MaxZ = -10000.0f;
193
194 for (unsigned int i = 0; i < Chunks.size(); i++) {
195 vw_Matrix33CalcPoint(HitBB[i].Location, OldInvRotationMatTmp);
196
197 for (int j = 0; j < 8; j++) {
198 vw_Matrix33CalcPoint(HitBB[i].Box[j], OldInvRotationMatTmp);
199
200 if (MinX > HitBB[i].Box[j].x + HitBB[i].Location.x)
201 MinX = HitBB[i].Box[j].x + HitBB[i].Location.x;
202 if (MaxX < HitBB[i].Box[j].x + HitBB[i].Location.x)
203 MaxX = HitBB[i].Box[j].x + HitBB[i].Location.x;
204 if (MinY > HitBB[i].Box[j].y + HitBB[i].Location.y)
205 MinY = HitBB[i].Box[j].y + HitBB[i].Location.y;
206 if (MaxY < HitBB[i].Box[j].y + HitBB[i].Location.y)
207 MaxY = HitBB[i].Box[j].y + HitBB[i].Location.y;
208 if (MinZ > HitBB[i].Box[j].z + HitBB[i].Location.z)
209 MinZ = HitBB[i].Box[j].z + HitBB[i].Location.z;
210 if (MaxZ < HitBB[i].Box[j].z + HitBB[i].Location.z)
211 MaxZ = HitBB[i].Box[j].z + HitBB[i].Location.z;
212
213 vw_Matrix33CalcPoint(HitBB[i].Box[j], CurrentRotationMat);
214 }
215 vw_Matrix33CalcPoint(HitBB[i].Location, CurrentRotationMat);
216 }
217
218 OBB.Box[0] = sVECTOR3D{MaxX, MaxY, MaxZ};
219 OBB.Box[1] = sVECTOR3D{MinX, MaxY, MaxZ};
220 OBB.Box[2] = sVECTOR3D{MinX, MaxY, MinZ};
221 OBB.Box[3] = sVECTOR3D{MaxX, MaxY, MinZ};
222 OBB.Box[4] = sVECTOR3D{MaxX, MinY, MaxZ};
223 OBB.Box[5] = sVECTOR3D{MinX, MinY, MaxZ};
224 OBB.Box[6] = sVECTOR3D{MinX, MinY, MinZ};
225 OBB.Box[7] = sVECTOR3D{MaxX, MinY, MinZ};
226
227 Width = fabsf(MaxX - MinX);
228 Height = fabsf(MaxY - MinY);
229 Length = fabsf(MaxZ - MinZ);
230
231 float Width2 = Width / 2.0f;
232 float Length2 = Length / 2.0f;
233 float Height2 = Height / 2.0f;
234 Radius = vw_sqrtf(Width2 * Width2 + Length2 * Length2 + Height2 * Height2);
235
236 OBB.Location.x = (MaxX + MinX) / 2.0f;
237 OBB.Location.y = (MaxY + MinY) / 2.0f;
238 OBB.Location.z = (MaxZ + MinZ) / 2.0f;
239
240 for (int k = 0; k < 8; k++) {
241 OBB.Box[k] -= OBB.Location;
242 vw_Matrix33CalcPoint(OBB.Box[k], CurrentRotationMat);
243 }
244 vw_Matrix33CalcPoint(OBB.Location, CurrentRotationMat);
245
246 MinX = MaxX = OBB.Box[0].x + OBB.Location.x;
247 MinY = MaxY = OBB.Box[0].y + OBB.Location.y;
248 MinZ = MaxZ = OBB.Box[0].z + OBB.Location.z;
249 for (int j = 0; j < 8; j++) {
250 if (MinX > OBB.Box[j].x + OBB.Location.x)
251 MinX = OBB.Box[j].x + OBB.Location.x;
252 if (MinY > OBB.Box[j].y + OBB.Location.y)
253 MinY = OBB.Box[j].y + OBB.Location.y;
254 if (MinZ > OBB.Box[j].z + OBB.Location.z)
255 MinZ = OBB.Box[j].z + OBB.Location.z;
256 if (MaxX < OBB.Box[j].x + OBB.Location.x)
257 MaxX = OBB.Box[j].x + OBB.Location.x;
258 if (MaxY < OBB.Box[j].y + OBB.Location.y)
259 MaxY = OBB.Box[j].y + OBB.Location.y;
260 if (MaxZ < OBB.Box[j].z + OBB.Location.z)
261 MaxZ = OBB.Box[j].z + OBB.Location.z;
262 }
263 AABB[0] = sVECTOR3D{MaxX, MaxY, MaxZ};
264 AABB[1] = sVECTOR3D{MinX, MaxY, MaxZ};
265 AABB[2] = sVECTOR3D{MinX, MaxY, MinZ};
266 AABB[3] = sVECTOR3D{MaxX, MaxY, MinZ};
267 AABB[4] = sVECTOR3D{MaxX, MinY, MaxZ};
268 AABB[5] = sVECTOR3D{MinX, MinY, MaxZ};
269 AABB[6] = sVECTOR3D{MinX, MinY, MinZ};
270 AABB[7] = sVECTOR3D{MaxX, MinY, MinZ};
271 }
272
273 Chunks[ChunkNum].Rotation = NewRotation;
274 }
275
276 /*
277 * Set location.
278 */
SetLocation(const sVECTOR3D & NewLocation)279 void cObject3D::SetLocation(const sVECTOR3D &NewLocation)
280 {
281 PrevLocation = Location;
282 Location = NewLocation;
283 }
284
285 /*
286 * Set rotation.
287 */
SetRotation(const sVECTOR3D & NewRotation)288 void cObject3D::SetRotation(const sVECTOR3D &NewRotation)
289 {
290 OldRotationInv = sVECTOR3D{-Rotation.x, -Rotation.y, -Rotation.z};
291 Rotation += NewRotation;
292
293 memcpy(OldInvRotationMat, CurrentRotationMat, 9 * sizeof(CurrentRotationMat[0]));
294 vw_Matrix33InverseRotate(OldInvRotationMat);
295 vw_Matrix33CreateRotate(CurrentRotationMat, Rotation);
296
297 vw_Matrix33CalcPoint(Orientation, OldInvRotationMat);
298 vw_Matrix33CalcPoint(Orientation, CurrentRotationMat);
299
300 if (!HitBB.empty()) {
301 for (unsigned int i = 0; i < Chunks.size(); i++) {
302 vw_Matrix33CalcPoint(HitBB[i].Location, OldInvRotationMat);
303 vw_Matrix33CalcPoint(HitBB[i].Location, CurrentRotationMat);
304
305 for (int j = 0; j < 8; j++) {
306 vw_Matrix33CalcPoint(HitBB[i].Box[j], OldInvRotationMat);
307 vw_Matrix33CalcPoint(HitBB[i].Box[j], CurrentRotationMat);
308 }
309 }
310 }
311
312 vw_Matrix33CalcPoint(OBB.Location, OldInvRotationMat);
313 vw_Matrix33CalcPoint(OBB.Location, CurrentRotationMat);
314 for (int j = 0; j < 8; j++) {
315 vw_Matrix33CalcPoint(OBB.Box[j], OldInvRotationMat);
316 vw_Matrix33CalcPoint(OBB.Box[j], CurrentRotationMat);
317 }
318
319 float MinX = 10000.0f;
320 float MaxX = -10000.0f;
321 float MinY = 10000.0f;
322 float MaxY = -10000.0f;
323 float MinZ = 10000.0f;
324 float MaxZ = -10000.0f;
325 for (int j = 0; j < 8; j++) {
326 if (MinX > OBB.Box[j].x + OBB.Location.x)
327 MinX = OBB.Box[j].x + OBB.Location.x;
328 if (MinY > OBB.Box[j].y + OBB.Location.y)
329 MinY = OBB.Box[j].y + OBB.Location.y;
330 if (MinZ > OBB.Box[j].z + OBB.Location.z)
331 MinZ = OBB.Box[j].z + OBB.Location.z;
332 if (MaxX < OBB.Box[j].x + OBB.Location.x)
333 MaxX = OBB.Box[j].x + OBB.Location.x;
334 if (MaxY < OBB.Box[j].y + OBB.Location.y)
335 MaxY = OBB.Box[j].y + OBB.Location.y;
336 if (MaxZ < OBB.Box[j].z + OBB.Location.z)
337 MaxZ = OBB.Box[j].z + OBB.Location.z;
338 }
339 AABB[0] = sVECTOR3D{MaxX, MaxY, MaxZ};
340 AABB[1] = sVECTOR3D{MinX, MaxY, MaxZ};
341 AABB[2] = sVECTOR3D{MinX, MaxY, MinZ};
342 AABB[3] = sVECTOR3D{MaxX, MaxY, MinZ};
343 AABB[4] = sVECTOR3D{MaxX, MinY, MaxZ};
344 AABB[5] = sVECTOR3D{MinX, MinY, MaxZ};
345 AABB[6] = sVECTOR3D{MinX, MinY, MinZ};
346 AABB[7] = sVECTOR3D{MaxX, MinY, MinZ};
347
348 }
349
350 /*
351 * Draw line.
352 * Since this is debug only code, no need in future rendering optimization (vbo/ibo/vao, etc...).
353 */
DrawLine(const sVECTOR3D & Point1,const sVECTOR3D & Point2,const sRGBCOLOR & Color)354 static void DrawLine(const sVECTOR3D &Point1, const sVECTOR3D &Point2, const sRGBCOLOR &Color)
355 {
356 constexpr float Alpha{1.0f};
357
358 // 2 points for line with RI_3f_XYZ | RI_4f_COLOR = 2 * (3 + 4) = 14
359 float DrawArray[14]{Point1.x, Point1.y, Point1.z, Color.r, Color.g, Color.b, Alpha,
360 Point2.x, Point2.y, Point2.z, Color.r, Color.g, Color.b, Alpha};
361
362 vw_Draw3D(ePrimitiveType::LINES, 2, RI_3f_XYZ | RI_4f_COLOR, DrawArray, 7 * sizeof(DrawArray[0]));
363 }
364
365 /*
366 * Draw box lines.
367 * Since this is debug only code, no need in future rendering optimization (vbo/ibo/vao, etc...).
368 */
DrawBoxLines(const bounding_box & Box,const sVECTOR3D & LocalLocation,const sRGBCOLOR & Color)369 static void DrawBoxLines(const bounding_box &Box, const sVECTOR3D &LocalLocation, const sRGBCOLOR &Color)
370 {
371 vw_PushMatrix();
372 vw_Translate(LocalLocation);
373
374 DrawLine(Box[0], Box[1], Color);
375 DrawLine(Box[1], Box[2], Color);
376 DrawLine(Box[2], Box[3], Color);
377 DrawLine(Box[3], Box[0], Color);
378
379 DrawLine(Box[4], Box[5], Color);
380 DrawLine(Box[5], Box[6], Color);
381 DrawLine(Box[6], Box[7], Color);
382 DrawLine(Box[7], Box[4], Color);
383
384 DrawLine(Box[0], Box[4], Color);
385 DrawLine(Box[1], Box[5], Color);
386 DrawLine(Box[2], Box[6], Color);
387 DrawLine(Box[3], Box[7], Color);
388
389 vw_PopMatrix();
390 }
391
392 /*
393 * Draw bounding boxes.
394 */
DrawBoundingBoxes(const sVECTOR3D & Location,const bounding_box & AABB,const sOBB & OBB,const std::vector<sHitBB> & HitBB)395 static void DrawBoundingBoxes(const sVECTOR3D &Location, const bounding_box &AABB,
396 const sOBB &OBB, const std::vector<sHitBB> &HitBB)
397 {
398 if (BBRenderMode == eRenderBoundingBoxes::None)
399 return;
400
401 static const sRGBCOLOR Red{eRGBCOLOR::red};
402 DrawBoxLines(AABB, Location, Red);
403
404 if (BBRenderMode == eRenderBoundingBoxes::AABB_Only)
405 return;
406
407 static const sRGBCOLOR Green{eRGBCOLOR::green};
408 DrawBoxLines(OBB.Box, Location + OBB.Location, Green);
409
410 if ((BBRenderMode == eRenderBoundingBoxes::AABB_And_OBB) || HitBB.empty())
411 return;
412
413 static const sRGBCOLOR Blue{eRGBCOLOR::blue};
414 for (const auto &tmpHitBB : HitBB) {
415 DrawBoxLines(tmpHitBB.Box, Location + tmpHitBB.Location, Blue);
416 }
417 }
418
419 /*
420 * Set bounding boxes render mode.
421 */
SetObjectsBBRenderMode(eRenderBoundingBoxes Mode)422 void SetObjectsBBRenderMode(eRenderBoundingBoxes Mode)
423 {
424 BBRenderMode = Mode;
425 }
426
427 /*
428 * Fill status draw array for line.
429 */
FillStatusDrawArray(float SizeXStart,float SizeXEnd,float SizeY,const sRGBCOLOR & Color,float (& DrawArray)[28])430 static void FillStatusDrawArray(float SizeXStart, float SizeXEnd, float SizeY,
431 const sRGBCOLOR &Color, float (&DrawArray)[28])
432 {
433 unsigned int DrawArrayIndex{0};
434 constexpr float Alpha{1.0f};
435
436 auto FillVertex = [&] (float X, float Y) {
437 DrawArray[DrawArrayIndex++] = X;
438 DrawArray[DrawArrayIndex++] = Y;
439 DrawArray[DrawArrayIndex++] = 0.0f; // Z
440 DrawArray[DrawArrayIndex++] = Color.r;
441 DrawArray[DrawArrayIndex++] = Color.g;
442 DrawArray[DrawArrayIndex++] = Color.b;
443 DrawArray[DrawArrayIndex++] = Alpha;
444 };
445
446 FillVertex(SizeXStart, -SizeY);
447 FillVertex(SizeXStart, SizeY);
448 FillVertex(SizeXEnd, -SizeY);
449 FillVertex(SizeXEnd, SizeY);
450 }
451
452 /*
453 * Draw status near 3d model in space.
454 */
DrawObjectStatus(const sVECTOR3D & Location,float Width,const sRGBCOLOR & Color,float CurrentValue,float InitialValue)455 static void DrawObjectStatus(const sVECTOR3D &Location, float Width, const sRGBCOLOR &Color,
456 float CurrentValue, float InitialValue)
457 {
458 vw_PushMatrix();
459 sVECTOR3D CurrentCameraRotation;
460 vw_GetCameraRotation(&CurrentCameraRotation);
461 vw_Translate(Location);
462 vw_Rotate(-180 + CurrentCameraRotation.y, 0.0f, 1.0f, 0.0f);
463 vw_Rotate(-CurrentCameraRotation.x, 1.0f, 0.0f, 0.0f);
464
465 // TRIANGLE_STRIP, RI_3f_XYZ | RI_4f_COLOR = 4 * (3 + 4) = 28
466 float DrawArray[28];
467
468 // background
469 float SizeX = Width / 2.5f + 0.1f;
470 FillStatusDrawArray(-SizeX, SizeX, 0.35f, sRGBCOLOR{eRGBCOLOR::black}, DrawArray);
471 vw_Draw3D(ePrimitiveType::TRIANGLE_STRIP, 4, RI_3f_XYZ | RI_4f_COLOR, DrawArray, 7 * sizeof(DrawArray[0]));
472
473 // status
474 float SizeXStart = Width / 2.5f - 0.8f * Width * CurrentValue / InitialValue;
475 float SizeXEnd = Width / 2.5f;
476 FillStatusDrawArray(SizeXStart, SizeXEnd, 0.25f, Color, DrawArray);
477 vw_Draw3D(ePrimitiveType::TRIANGLE_STRIP, 4, RI_3f_XYZ | RI_4f_COLOR, DrawArray, 7 * sizeof(DrawArray[0]));
478
479 vw_PopMatrix();
480 }
481
482 /*
483 * Draw.
484 */
Draw(bool VertexOnlyPass,bool ShadowMap)485 void cObject3D::Draw(bool VertexOnlyPass, bool ShadowMap)
486 {
487 if (Chunks.empty())
488 return;
489
490 bool NeedOnePieceDraw{false};
491 if (PromptDrawDist2 >= 0.0f) {
492 sVECTOR3D CurrentCameraLocation;
493 vw_GetCameraLocation(&CurrentCameraLocation);
494 float PromptDrawRealDist2 = (Location.x - CurrentCameraLocation.x) * (Location.x - CurrentCameraLocation.x) +
495 (Location.y - CurrentCameraLocation.y) * (Location.y - CurrentCameraLocation.y) +
496 (Location.z - CurrentCameraLocation.z) * (Location.z - CurrentCameraLocation.z);
497
498 int LightsCount = vw_CalculateAllPointLightsAttenuation(Location, Radius * Radius, nullptr);
499
500 if (PromptDrawRealDist2 > PromptDrawDist2) {
501 if (LightsCount <= GameConfig().MaxPointLights)
502 NeedOnePieceDraw = true;
503 else
504 NeedOnePieceDraw = false;
505
506 if (InternalLights >= LightsCount)
507 NeedOnePieceDraw = true;
508 } else {
509 if (LightsCount <= GameConfig().MaxPointLights)
510 NeedOnePieceDraw = true;
511 }
512 }
513
514 // fast rendering for shadows map generation, without textures, shaders, etc
515 // make sure, we call this one _before_ any camera/frustum checks, since not visible
516 // for us 3D model could also drop the shadow on visible for us part of scene
517 if (VertexOnlyPass) {
518 vw_PushMatrix();
519
520 vw_Translate(Location);
521 vw_Rotate(Rotation.z, 0.0f, 0.0f, 1.0f);
522 vw_Rotate(Rotation.y, 0.0f, 1.0f, 0.0f);
523 vw_Rotate(Rotation.x, 1.0f, 0.0f, 0.0f);
524
525 if (NeedOnePieceDraw) {
526 unsigned DrawVertexCount{GlobalIndexArrayCount};
527 if (!DrawVertexCount)
528 DrawVertexCount = GlobalVertexArrayCount;
529
530 vw_Draw3D(ePrimitiveType::TRIANGLES, DrawVertexCount, RI_3f_XYZ, GlobalVertexArray.get(),
531 Chunks[0].VertexStride * sizeof(float), GlobalVBO, 0,
532 GlobalIndexArray.get(), GlobalIBO, GlobalVAO);
533 } else {
534 for (auto &tmpChunk : Chunks) {
535 vw_PushMatrix();
536
537 vw_Translate(tmpChunk.Location);
538 vw_Rotate(tmpChunk.Rotation.z, 0.0f, 0.0f, 1.0f);
539 vw_Rotate(tmpChunk.Rotation.y, 0.0f, 1.0f, 0.0f);
540 vw_Rotate(tmpChunk.Rotation.x, 1.0f, 0.0f, 0.0f);
541
542 if (tmpChunk.NeedGeometryAnimation) {
543 vw_Rotate(tmpChunk.GeometryAnimation.z, 0.0f, 0.0f, 1.0f);
544 vw_Rotate(tmpChunk.GeometryAnimation.y, 0.0f, 1.0f, 0.0f);
545 vw_Rotate(tmpChunk.GeometryAnimation.x, 1.0f, 0.0f, 0.0f);
546 }
547
548 if (tmpChunk.ShaderType == 2) {
549 if (auto sharedGLSL = GLSLShaderType2.lock()) {
550 vw_UseShaderProgram(sharedGLSL);
551 vw_Uniform1i(vw_GetShaderUniformLocation(sharedGLSL, 0), 0);
552 vw_Uniform1f(vw_GetShaderUniformLocation(sharedGLSL, 1), Chunks[0].ShaderData[0]);
553 vw_Uniform1f(vw_GetShaderUniformLocation(sharedGLSL, 2), Chunks[0].ShaderData[1]);
554 }
555 }
556
557 vw_Draw3D(ePrimitiveType::TRIANGLES, tmpChunk.VertexQuantity, RI_3f_XYZ, tmpChunk.VertexArray.get(),
558 tmpChunk.VertexStride * sizeof(float), tmpChunk.VBO,
559 tmpChunk.RangeStart, tmpChunk.IndexArray.get(), tmpChunk.IBO, tmpChunk.VAO);
560
561 if ((tmpChunk.ShaderType == 2) &&
562 !GLSLShaderType2.expired())
563 vw_StopShaderProgram();
564
565 vw_PopMatrix();
566 }
567 }
568
569 vw_PopMatrix();
570 return;
571 }
572
573 if (!vw_BoxInFrustum(Location + AABB[6], Location + AABB[0])) {
574 if (DeleteAfterLeaveScene == eDeleteAfterLeaveScene::showed)
575 DeleteAfterLeaveScene = eDeleteAfterLeaveScene::need_delete;
576
577 return;
578 }
579
580 if (DeleteAfterLeaveScene == eDeleteAfterLeaveScene::enabled)
581 DeleteAfterLeaveScene = eDeleteAfterLeaveScene::showed;
582 if (DeleteAfterLeaveScene == eDeleteAfterLeaveScene::wait_delay) {
583 DeleteAfterLeaveScene = eDeleteAfterLeaveScene::showed;
584 Lifetime = -1.0f;
585 }
586
587 GLtexture CurrentNormalMap{0};
588 std::weak_ptr<cGLSL> CurrentGLSL{};
589 int NeedNormalMapping{0};
590 float Matrix[16];
591 vw_GetMatrix(eMatrixPname::MODELVIEW, Matrix);
592
593 vw_PushMatrix();
594
595 vw_Translate(Location);
596 vw_Rotate(Rotation.z, 0.0f, 0.0f, 1.0f);
597 vw_Rotate(Rotation.y, 0.0f, 1.0f, 0.0f);
598 vw_Rotate(Rotation.x, 1.0f, 0.0f, 0.0f);
599
600 bool N1 = false;
601 for (auto &tmpChunk : Chunks) {
602 if (tmpChunk.DrawType == eModel3DDrawType::Blend)
603 N1 = true;
604 }
605
606 vw_MaterialV(eMaterialParameter::DIFFUSE, Diffuse);
607 vw_MaterialV(eMaterialParameter::AMBIENT, Ambient);
608 vw_MaterialV(eMaterialParameter::SPECULAR, Specular);
609 vw_MaterialV(eMaterialParameter::SHININESS, Power);
610
611 if (!NeedCullFaces)
612 vw_CullFace(eCullFace::NONE);
613 if (NeedAlphaTest)
614 vw_SetTextureAlphaTest(true, eCompareFunc::GREATER, 0.4f);
615
616 if (NeedOnePieceDraw) {
617 vw_BindTexture(0, Texture[0]);
618
619 if (!TextureIllum.empty() && TextureIllum[0]) {
620 vw_BindTexture(1, TextureIllum[0]);
621 vw_SetTextureEnvMode(eTextureEnvMode::COMBINE);
622 vw_SetTextureBlendMode(eTextureCombinerName::COMBINE_RGB, eTextureCombinerOp::ADD);
623 }
624
625 NeedNormalMapping = 0;
626 if (GameConfig().UseGLSL120 &&
627 !NormalMap.empty() && NormalMap[0]) {
628 NeedNormalMapping = 1;
629 CurrentNormalMap = NormalMap[0];
630 vw_BindTexture(3, CurrentNormalMap);
631 }
632
633 // FIXME we don't need LightType1 and LightType2 any more, revise vw_CheckAndActivateAllLights()
634 int LightType1, LightType2;
635 vw_CheckAndActivateAllLights(LightType1, LightType2, Location, Radius*Radius, 1, GameConfig().MaxPointLights, Matrix);
636
637 if (GameConfig().UseGLSL120 && (Chunks[0].ShaderType >= 0)) {
638 std::weak_ptr<cGLSL> CurrentObject3DGLSL{};
639
640 // FIXME we know what exactly we have, why we need shaders setup in this way?
641 if ((Chunks[0].ShaderType == 1) && ShadowMap)
642 Chunks[0].ShaderType = 3;
643 if ((Chunks[0].ShaderType == 3) && !ShadowMap)
644 Chunks[0].ShaderType = 1;
645
646 switch (Chunks[0].ShaderType) {
647 case 1:
648 CurrentObject3DGLSL = GLSLShaderType1;
649 break;
650 case 2:
651 CurrentObject3DGLSL = GLSLShaderType2;
652 break;
653 case 3:
654 CurrentObject3DGLSL = GLSLShaderType3;
655 break;
656 }
657
658 if (CurrentGLSL.lock() != CurrentObject3DGLSL.lock()) {
659 if (!CurrentGLSL.expired())
660 vw_StopShaderProgram();
661
662 CurrentGLSL = CurrentObject3DGLSL;
663
664 if (!CurrentGLSL.expired())
665 vw_UseShaderProgram(CurrentGLSL);
666 }
667
668 if (auto sharedGLSL = CurrentObject3DGLSL.lock()) {
669 switch (Chunks[0].ShaderType) {
670 case 1: // per pixel light
671 vw_Uniform1i(vw_GetShaderUniformLocation(sharedGLSL, 0), 0);
672 vw_Uniform1i(vw_GetShaderUniformLocation(sharedGLSL, 1), 1);
673 if (!TextureIllum.empty() && TextureIllum[0])
674 vw_Uniform1i(vw_GetShaderUniformLocation(sharedGLSL, 2), 1);
675 else
676 vw_Uniform1i(vw_GetShaderUniformLocation(sharedGLSL, 2), 0);
677
678 vw_Uniform1i(vw_GetShaderUniformLocation(sharedGLSL, 3), 3);
679 vw_Uniform1i(vw_GetShaderUniformLocation(sharedGLSL, 4), NeedNormalMapping);
680 break;
681
682 case 2: // explosion
683 vw_Uniform1i(vw_GetShaderUniformLocation(sharedGLSL, 0), 0);
684 vw_Uniform1f(vw_GetShaderUniformLocation(sharedGLSL, 1), Chunks[0].ShaderData[0]);
685 vw_Uniform1f(vw_GetShaderUniformLocation(sharedGLSL, 2), Chunks[0].ShaderData[1]);
686 break;
687
688 case 3: // shadow map
689 vw_Uniform1i(vw_GetShaderUniformLocation(sharedGLSL, 0), 0);
690 vw_Uniform1i(vw_GetShaderUniformLocation(sharedGLSL, 1), 1);
691 if (!TextureIllum.empty() && TextureIllum[0])
692 vw_Uniform1i(vw_GetShaderUniformLocation(sharedGLSL, 2), 1);
693 else
694 vw_Uniform1i(vw_GetShaderUniformLocation(sharedGLSL, 2), 0);
695
696 vw_Uniform1i(vw_GetShaderUniformLocation(sharedGLSL, 3), 2);
697 vw_Uniform1f(vw_GetShaderUniformLocation(sharedGLSL, 4), ShadowMap_Get_xPixelOffset());
698 vw_Uniform1f(vw_GetShaderUniformLocation(sharedGLSL, 5), ShadowMap_Get_yPixelOffset());
699 vw_Uniform1i(vw_GetShaderUniformLocation(sharedGLSL, 6), 3);
700 vw_Uniform1i(vw_GetShaderUniformLocation(sharedGLSL, 7), NeedNormalMapping);
701 break;
702 }
703 }
704 }
705
706 unsigned DrawVertexCount{GlobalIndexArrayCount};
707 if (!DrawVertexCount)
708 DrawVertexCount = GlobalVertexArrayCount;
709
710 vw_Draw3D(ePrimitiveType::TRIANGLES, DrawVertexCount, Chunks[0].VertexFormat, GlobalVertexArray.get(),
711 Chunks[0].VertexStride * sizeof(float), GlobalVBO, 0,
712 GlobalIndexArray.get(), GlobalIBO, GlobalVAO);
713
714 vw_DeActivateAllLights();
715 } else {
716 GLtexture CurrentTexture{0};
717
718 for (unsigned int i = 0; i < Chunks.size(); i++) {
719 if (!HitBB.empty()) {
720 sVECTOR3D Min, Max;
721 Min.x = Max.x = HitBB[i].Box[0].x + HitBB[i].Location.x;
722 Min.y = Max.y = HitBB[i].Box[0].y + HitBB[i].Location.y;
723 Min.z = Max.z = HitBB[i].Box[0].z + HitBB[i].Location.z;
724 for (int j = 0; j < 8; j++) {
725 if (Min.x > HitBB[i].Box[j].x + HitBB[i].Location.x)
726 Min.x = HitBB[i].Box[j].x + HitBB[i].Location.x;
727 if (Min.y > HitBB[i].Box[j].y + HitBB[i].Location.y)
728 Min.y = HitBB[i].Box[j].y + HitBB[i].Location.y;
729 if (Min.z > HitBB[i].Box[j].z + HitBB[i].Location.z)
730 Min.z = HitBB[i].Box[j].z + HitBB[i].Location.z;
731 if (Max.x < HitBB[i].Box[j].x + HitBB[i].Location.x)
732 Max.x = HitBB[i].Box[j].x + HitBB[i].Location.x;
733 if (Max.y < HitBB[i].Box[j].y + HitBB[i].Location.y)
734 Max.y = HitBB[i].Box[j].y + HitBB[i].Location.y;
735 if (Max.z < HitBB[i].Box[j].z + HitBB[i].Location.z)
736 Max.z = HitBB[i].Box[j].z + HitBB[i].Location.z;
737 }
738
739 if (!vw_BoxInFrustum(Location + Min, Location + Max))
740 continue;
741 }
742
743 if (CurrentTexture != Texture[i]) {
744 vw_BindTexture(0, Texture[i]);
745
746 if (Chunks[i].NeedTextureAnimation) {
747 vw_MatrixMode(eMatrixMode::TEXTURE);
748 vw_LoadIdentity();
749 vw_Translate(Chunks[i].TextureAnimation);
750 vw_MatrixMode(eMatrixMode::MODELVIEW);
751 }
752
753 if ((TextureIllum.size() > static_cast<unsigned>(i)) && TextureIllum[i]) {
754 vw_BindTexture(1, TextureIllum[i]);
755 vw_SetTextureEnvMode(eTextureEnvMode::COMBINE);
756 vw_SetTextureBlendMode(eTextureCombinerName::COMBINE_RGB, eTextureCombinerOp::ADD);
757 }
758
759 NeedNormalMapping = 0;
760 if (GameConfig().UseGLSL120 &&
761 (NormalMap.size() > static_cast<unsigned>(i))) {
762 if (NormalMap[i]) {
763 NeedNormalMapping = 1;
764 CurrentNormalMap = NormalMap[i];
765 vw_BindTexture(3, CurrentNormalMap);
766 } else if (CurrentNormalMap) {
767 vw_BindTexture(3, 0);
768 CurrentNormalMap = 0;
769 }
770 }
771
772 CurrentTexture = Texture[i];
773 }
774
775 vw_PushMatrix();
776
777 vw_Translate(Chunks[i].Location);
778 vw_Rotate(Chunks[i].Rotation.z, 0.0f, 0.0f, 1.0f);
779 vw_Rotate(Chunks[i].Rotation.y, 0.0f, 1.0f, 0.0f);
780 vw_Rotate(Chunks[i].Rotation.x, 1.0f, 0.0f, 0.0f);
781
782 if (Chunks[i].NeedGeometryAnimation) {
783 vw_Rotate(Chunks[i].GeometryAnimation.z, 0.0f, 0.0f, 1.0f);
784 vw_Rotate(Chunks[i].GeometryAnimation.y, 0.0f, 1.0f, 0.0f);
785 vw_Rotate(Chunks[i].GeometryAnimation.x, 1.0f, 0.0f, 0.0f);
786 }
787
788 // FIXME we don't need LightType1 and LightType2 any more, revise vw_CheckAndActivateAllLights()
789 int LightType1, LightType2;
790 if (!HitBB.empty())
791 vw_CheckAndActivateAllLights(LightType1, LightType2, Location + HitBB[i].Location, HitBB[i].Radius2, 1, GameConfig().MaxPointLights, Matrix);
792 else
793 vw_CheckAndActivateAllLights(LightType1, LightType2, Location, Radius * Radius, 1, GameConfig().MaxPointLights, Matrix);
794
795 // for planet's clouds
796 if (N1)
797 vw_PolygonOffset(true, 2.0f, 2.0f);
798
799 if (Chunks[i].DrawType == eModel3DDrawType::Blend) {
800 vw_SetTextureAlphaTest(true, eCompareFunc::GREATER, 0.01f);
801 vw_SetTextureBlend(true, eTextureBlendFactor::SRC_ALPHA, eTextureBlendFactor::ONE);
802 vw_PolygonOffset(true, 1.0f, 1.0f);
803 }
804
805 if (GameConfig().UseGLSL120 &&
806 (Chunks[i].ShaderType >= 0)) {
807 std::weak_ptr<cGLSL> CurrentObject3DGLSL{};
808
809 // FIXME we know what exactly we have, why we need shaders setup in this way?
810 if ((Chunks[i].ShaderType == 1) && ShadowMap)
811 Chunks[i].ShaderType = 3;
812 if ((Chunks[i].ShaderType == 3) && !ShadowMap)
813 Chunks[i].ShaderType = 1;
814
815 switch (Chunks[i].ShaderType) {
816 case 1:
817 CurrentObject3DGLSL = GLSLShaderType1;
818 break;
819 case 2:
820 CurrentObject3DGLSL = GLSLShaderType2;
821 break;
822 case 3:
823 CurrentObject3DGLSL = GLSLShaderType3;
824 break;
825 }
826
827 if (CurrentGLSL.lock() != CurrentObject3DGLSL.lock()) {
828 if (!CurrentGLSL.expired())
829 vw_StopShaderProgram();
830
831 CurrentGLSL = CurrentObject3DGLSL;
832
833 if (!CurrentGLSL.expired())
834 vw_UseShaderProgram(CurrentGLSL);
835 }
836
837 if (auto sharedGLSL = CurrentObject3DGLSL.lock()) {
838 switch (Chunks[i].ShaderType) {
839 case 1: // per pixel light
840 vw_Uniform1i(vw_GetShaderUniformLocation(sharedGLSL, 0), 0);
841 vw_Uniform1i(vw_GetShaderUniformLocation(sharedGLSL, 1), 1);
842 if (!TextureIllum.empty() && TextureIllum[0])
843 vw_Uniform1i(vw_GetShaderUniformLocation(sharedGLSL, 2), 1);
844 else
845 vw_Uniform1i(vw_GetShaderUniformLocation(sharedGLSL, 2), 0);
846
847 vw_Uniform1i(vw_GetShaderUniformLocation(sharedGLSL, 3), 3);
848 vw_Uniform1i(vw_GetShaderUniformLocation(sharedGLSL, 4), NeedNormalMapping);
849 break;
850
851 case 2: // explosion
852 vw_Uniform1i(vw_GetShaderUniformLocation(sharedGLSL, 0), 0);
853 vw_Uniform1f(vw_GetShaderUniformLocation(sharedGLSL, 1), Chunks[0].ShaderData[0]);
854 vw_Uniform1f(vw_GetShaderUniformLocation(sharedGLSL, 2), Chunks[0].ShaderData[1]);
855 break;
856
857 case 3: // shadow map
858 vw_Uniform1i(vw_GetShaderUniformLocation(sharedGLSL, 0), 0);
859 vw_Uniform1i(vw_GetShaderUniformLocation(sharedGLSL, 1), 1);
860 if (!TextureIllum.empty() && TextureIllum[0])
861 vw_Uniform1i(vw_GetShaderUniformLocation(sharedGLSL, 2), 1);
862 else
863 vw_Uniform1i(vw_GetShaderUniformLocation(sharedGLSL, 2), 0);
864
865 vw_Uniform1i(vw_GetShaderUniformLocation(sharedGLSL, 3), 2);
866 vw_Uniform1f(vw_GetShaderUniformLocation(sharedGLSL, 4), ShadowMap_Get_xPixelOffset());
867 vw_Uniform1f(vw_GetShaderUniformLocation(sharedGLSL, 5), ShadowMap_Get_yPixelOffset());
868 vw_Uniform1i(vw_GetShaderUniformLocation(sharedGLSL, 6), 3);
869 vw_Uniform1i(vw_GetShaderUniformLocation(sharedGLSL, 7), NeedNormalMapping);
870 break;
871 }
872 }
873 }
874
875 vw_Draw3D(ePrimitiveType::TRIANGLES, Chunks[i].VertexQuantity, Chunks[i].VertexFormat, Chunks[i].VertexArray.get(),
876 Chunks[i].VertexStride * sizeof(float), Chunks[i].VBO,
877 Chunks[i].RangeStart, Chunks[i].IndexArray.get(), Chunks[i].IBO, Chunks[i].VAO);
878
879 if (Chunks[i].DrawType == eModel3DDrawType::Blend) {
880 vw_SetTextureAlphaTest(false, eCompareFunc::ALWAYS, 0);
881 vw_SetTextureBlend(false, eTextureBlendFactor::ONE, eTextureBlendFactor::ZERO);
882 vw_PolygonOffset(false, 0.0f, 0.0f);
883 }
884
885 vw_DeActivateAllLights();
886
887 if (Chunks[i].NeedTextureAnimation) {
888 vw_BindTexture(0, 0);
889 vw_MatrixMode(eMatrixMode::TEXTURE);
890 vw_LoadIdentity();
891 vw_MatrixMode(eMatrixMode::MODELVIEW);
892 CurrentTexture = 0;
893 }
894
895 vw_PopMatrix();
896 }
897 }
898
899 if (GameConfig().UseGLSL120)
900 vw_StopShaderProgram();
901
902 if (CurrentNormalMap)
903 vw_BindTexture(3, 0);
904 vw_BindTexture(1, 0);
905 vw_BindTexture(0, 0);
906 if (NeedAlphaTest)
907 vw_SetTextureAlphaTest(false, eCompareFunc::ALWAYS, 0);
908 if (!NeedCullFaces)
909 vw_CullFace(eCullFace::BACK);
910 vw_PopMatrix();
911
912 #ifndef NDEBUG
913 // debug info, line number in script file
914 if (!ScriptLineNumberUTF32.empty())
915 vw_DrawText3DUTF32(Location.x, Location.y + AABB[0].y, Location.z, ScriptLineNumberUTF32);
916 #endif // NDEBUG
917
918 DrawBoundingBoxes(Location, AABB, OBB, HitBB);
919
920 // TODO why we need ShowStatus if we could use ArmorInitialStatus < 0.0f for this?
921 if (!ShowStatus ||
922 (ArmorInitialStatus <= 0.0f) ||
923 ((ArmorCurrentStatus == ArmorInitialStatus) &&
924 (ShieldCurrentStatus == ShieldInitialStatus) &&
925 !ShowStatusAllTime))
926 return;
927
928 // even if shield recharged - don't hide object's status any more
929 ShowStatusAllTime = true;
930
931 DrawObjectStatus(sVECTOR3D{Location.x, Location.y + AABB[0].y + 0.7f, Location.z},
932 Width, sRGBCOLOR{eRGBCOLOR::red}, ArmorCurrentStatus, ArmorInitialStatus);
933 if (ShieldInitialStatus > 0.0f)
934 DrawObjectStatus(sVECTOR3D{Location.x, Location.y + AABB[0].y + 1.75f, Location.z},
935 Width, sRGBCOLOR{0.1f, 0.7f, 1.0f}, ShieldCurrentStatus, ShieldInitialStatus);
936 vw_BindTexture(0, 0);
937 }
938
939 /*
940 * Update.
941 */
Update(float Time)942 bool cObject3D::Update(float Time)
943 {
944 if (TimeLastUpdate == -1.0f) {
945 TimeLastUpdate = Time;
946 return true;
947 }
948
949 if (DeleteAfterLeaveScene == eDeleteAfterLeaveScene::need_delete) {
950 Lifetime = DeleteAfterLeaveSceneDelay;
951 DeleteAfterLeaveScene = eDeleteAfterLeaveScene::wait_delay;
952 }
953
954 TimeDelta = Time - TimeLastUpdate;
955 if (TimeDelta == 0.0f)
956 return true;
957
958 TimeLastUpdate = Time;
959
960 if (Lifetime > -1.0f) {
961 Lifetime -= TimeDelta;
962 if (Lifetime <= 0.0f)
963 return false;
964 }
965
966 if ((ShieldInitialStatus > 0.0f) &&
967 (ShieldCurrentStatus < ShieldInitialStatus)) {
968 ShieldCurrentStatus += ShieldRechargeRate * TimeDelta;
969 if (ShieldCurrentStatus > ShieldInitialStatus)
970 ShieldCurrentStatus = ShieldInitialStatus;
971 }
972
973 // if we have TimeSheet with actions and this is not a cycled entry
974 if (!TimeSheetList.empty() &&
975 (TimeSheetList.front().Time > -1.0f)) {
976 TimeSheetList.front().Time -= TimeDelta;
977 // if this entry is out of time, remove it
978 if (TimeSheetList.front().Time <= 0.0f) {
979 // correct time delta
980 if (TimeSheetList.front().Time < 0.0f)
981 TimeDelta += TimeSheetList.front().Time;
982 TimeSheetList.pop_front();
983 }
984 }
985 // should be unpacked
986 if (!TimeSheetList.empty() &&
987 (TimeSheetList.front().AI_Mode != 0)) {
988 InterAIMode(TimeSheetList);
989 // since we already unpack this entry, remove it
990 TimeSheetList.pop_front();
991 }
992
993 return true;
994 }
995
996 } // astromenace namespace
997 } // viewizard namespace
998