Oolite 1.91.0.7604-240417-a536cbe
Loading...
Searching...
No Matches
OOExhaustPlumeEntity.m
Go to the documentation of this file.
1/*
2
3OOExhaustPlumeEntity.m
4
5
6Oolite
7Copyright (C) 2004-2013 Giles C Williams and contributors
8
9This program is free software; you can redistribute it and/or
10modify it under the terms of the GNU General Public License
11as published by the Free Software Foundation; either version 2
12of the License, or (at your option) any later version.
13
14This program is distributed in the hope that it will be useful,
15but WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17GNU General Public License for more details.
18
19You should have received a copy of the GNU General Public License
20along with this program; if not, write to the Free Software
21Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
22MA 02110-1301, USA.
23
24*/
25
26
29#import "ShipEntity.h"
30#import "Universe.h"
31#import "OOMacroOpenGL.h"
32#import "PlayerEntity.h"
33#import "MyOpenGLView.h"
34
35#import "OOTexture.h"
37
38
39#define kOverallAlpha 1.0f
40#define kTimeStep 0.05f
41#define kFadeLevel1 0.4f
42#define kFadeLevel2 0.2f
43#define kFadeLevel3 0.02f
44#define kScaleLevel1 1.0f
45#define kScaleLevel2 0.8f
46#define kScaleLevel3 0.6f
47
49
50
51@interface OOExhaustPlumeEntity (Private)
52
53- (void) saveToLastFrame;
54- (Frame) frameAtTime:(double) t_frame fromFrame:(Frame) frame_zero; // t_frame is relative to now ie. -0.5 = half a second ago.
55
56@end
57
58
59@implementation OOExhaustPlumeEntity
60
61+ (id) exhaustForShip:(ShipEntity *)ship withDefinition:(NSArray *)definition andScale:(float)scale
62{
63 return [[[self alloc] initForShip:ship withDefinition:definition andScale:(float)scale] autorelease];
64}
65
66
67- (id) initForShip:(ShipEntity *)ship withDefinition:(NSArray *)definition andScale:(float)scaleFactor
68{
69 if ([definition count] == 0)
70 {
71 [self release];
72 return nil;
73 }
74
75 if ((self = [super init]))
76 {
77 [self setOwner:ship];
78 HPVector pos = { [definition oo_floatAtIndex:0]*scaleFactor, [definition oo_floatAtIndex:1]*scaleFactor, [definition oo_floatAtIndex:2]*scaleFactor };
79 [self setPosition:pos];
80 // scale.z is special and *not* multiplied by scaleFactor
81 Vector scale = { [definition oo_floatAtIndex:3]*scaleFactor, [definition oo_floatAtIndex:4]*scaleFactor, [definition oo_floatAtIndex:5] };
82 [self setScale:scale];
83 }
84
85 return self;
86}
87
88
89- (Vector) scale
90{
91 return _exhaustScale;
92}
93
94
95- (void) setScale:(Vector)scale
96{
97 _exhaustScale = scale;
98 if (scale.z < 0.5 || scale.z > 2.0)
99 {
100 _exhaustScale.z = 1.0;
101 }
102}
103
104
105- (BOOL)isExhaust
106{
107 return YES;
108}
109
110
111- (double)findCollisionRadius
112{
113 return collision_radius;
114}
115
116
117- (void) update:(OOTimeDelta) delta_t
118{
119// Profiling: this function and subfunctions are expensive - CIM
120
121 // don't draw if there's no ship, or if we're just jumping out of witchspace/docked at a station!
122 ShipEntity *ship = [self owner];
123// also don't draw if the ship isn't visible
124 if (EXPECT_NOT(ship == nil || ![ship isVisible] || ([ship isPlayer] && [ship suppressFlightNotifications]))) return;
125
126 OOTimeAbsolute now = [UNIVERSE getTime];
127 if ([UNIVERSE getTime] > _trackTime + kTimeStep)
128 {
129 [self saveToLastFrame];
130 _trackTime = now;
131 }
132
133 //GLfloat ex_emissive[4] = {0.7f, 0.9, 1.0f, 0.9f * kOverallAlpha}; // pale blue - old definition
134 collision_radius = 0;
135 GLfloat length;
136 HPVector vertex;
137 GLfloat ex_emissive[4];
138 [[ship exhaustEmissiveColor] getRed:&ex_emissive[0] green:&ex_emissive[1] blue:&ex_emissive[2] alpha:&ex_emissive[3]];
139 const GLfloat s1[8] = { 0.0, M_SQRT1_2, 1.0, M_SQRT1_2, 0.0, -M_SQRT1_2, -1.0, -M_SQRT1_2};
140 const GLfloat c1[8] = { 1.0, M_SQRT1_2, 0.0, -M_SQRT1_2, -1.0, -M_SQRT1_2, 0.0, M_SQRT1_2};
141
142 Quaternion shipQrotation = [ship normalOrientation];
143
144 Frame zero =
145 {
146 .timeframe = [UNIVERSE getTime],
147 .orientation = shipQrotation,
148 .k = [ship forwardVector]
149 };
150 int dam = [ship damage];
151
152 GLfloat speed = [ship speedFactor];
153 // don't draw if not moving.
154 if (EXPECT_NOT(speed <= 0.001f)) return;
155
156 GLfloat hyper_fade = 8.0f / (8.0f + speed * speed * speed);
157
158 GLfloat flare_factor = fmaxf(speed,1.0) * ex_emissive[3] * hyper_fade;
159 GLfloat red_factor = speed * ex_emissive[0] * (ranrot_rand() % 11) * 0.1f; // random fluctuations
160 GLfloat green_factor = speed * ex_emissive[1] * hyper_fade;
161
162 if (speed > 1.0f) // afterburner!
163 {
164 red_factor = 1.5;
165 }
166
167 if ((int)(ranrot_rand() % 50) < dam - 50) // flicker the damaged engines
168 red_factor = 0.0;
169 if ((int)(ranrot_rand() % 40) < dam - 60)
170 green_factor = 0.0;
171 if ((int)(ranrot_rand() % 25) < dam - 75)
172 flare_factor = 0.0;
173
174 HPVector currentPos = ship->position;
175 Vector vfwd = [ship forwardVector];
176 GLfloat spd = 0.5f * [ship flightSpeed];
177 vfwd = vector_multiply_scalar(vfwd, spd);
178 Vector master_i = [ship rightVector];
179 Vector vi,vj,vk;
180 vi = master_i;
181 vj = [ship upVector];
182 vk = [ship forwardVector];
183 zero.position = make_HPvector(currentPos.x + vi.x * position.x + vj.x * position.y + vk.x * position.z,
184 currentPos.y + vi.y * position.x + vj.y * position.y + vk.y * position.z,
185 currentPos.z + vi.z * position.x + vj.z * position.y + vk.z * position.z);
186
187 GLfloat speedScale = fminf(1.0f,speed * 5.0f);
188
189 GLfloat exhaust_factor = _exhaustScale.z;
190 GLfloat i01 = -0.00f * hyper_fade;
191 GLfloat i03 = -0.12f * exhaust_factor;
192 GLfloat i06 = -0.25f * exhaust_factor;
193 GLfloat i08 = -0.32f * exhaust_factor;
194 GLfloat i10 = -0.40f * exhaust_factor;
195 GLfloat q01 = i01/i10; // factor for trail
196 GLfloat q03 = i03/i10;
197 GLfloat q06 = i06/i10;
198 GLfloat q08 = i08/i10;
199 GLfloat r01 = 1.0f - q01; // factor for jet
200 GLfloat r03 = 1.0f - q03;
201 GLfloat r06 = 1.0f - q06;
202 GLfloat r08 = 1.0f - q08;
203 Frame f01 = [self frameAtTime: i01 fromFrame: zero];
204 Vector b01 = make_vector(r01 * i01 * vfwd.x, r01 * i01 * vfwd.y, r01 * i01 * vfwd.z);
205 Frame f03 = [self frameAtTime: i03 fromFrame: zero];
206 Vector b03 = make_vector(r03 * i03 * vfwd.x, r03 * i03 * vfwd.y, r03 * i03 * vfwd.z);
207 Frame f06 = [self frameAtTime: i06 fromFrame: zero];
208 Vector b06 = make_vector(r06 * i06 * vfwd.x, r06 * i06 * vfwd.y, r06 * i06 * vfwd.z);
209 Frame f08 = [self frameAtTime: i08 fromFrame: zero];
210 Vector b08 = make_vector(r08 * i08 * vfwd.x, r08 * i08 * vfwd.y, r08 * i08 * vfwd.z);
211 Frame f10 = [self frameAtTime: i10 fromFrame: zero];
212
213 int ci = 0;
214 int iv = 0;
215 int i;
216 float r1;
217
218// f01.position = vector_subtract(zero.position, vk); // 1m out from zero
219 f01.position = zero.position;
220
221 ex_emissive[3] = flare_factor * kOverallAlpha; // fade alpha towards rear of exhaust
222 ex_emissive[1] = green_factor; // diminish green part towards rear of exhaust
223 ex_emissive[0] = red_factor; // diminish red part towards rear of exhaust
224 vertex = HPvector_add(f01.position, vectorToHPVector(b01));
225 collision_radius = HPmagnitude(HPvector_subtract(vertex, currentPos));
226 _vertices[iv++] = vertex.x;// + zero.k.x * flare_factor * 4.0;
227 _vertices[iv++] = vertex.y;// + zero.k.y * flare_factor * 4.0;
228 _vertices[iv++] = vertex.z;// + zero.k.z * flare_factor * 4.0;
229 _exhaustBaseColors[ci++] = ex_emissive[0];
230 _exhaustBaseColors[ci++] = ex_emissive[1];
231 _exhaustBaseColors[ci++] = ex_emissive[2];
232 _exhaustBaseColors[ci++] = ex_emissive[3];
233
234
235 Vector k1 = f01.k;
236 Vector j1 = cross_product(master_i, k1);
237 Vector i1 = vector_multiply_scalar(cross_product(j1, k1), _exhaustScale.x * speedScale);
238 j1 = vector_multiply_scalar(j1, _exhaustScale.y * speedScale);
239
240 for (i = 0; i < 8; i++)
241 {
242 vertex = HPvector_add(f01.position,
243 vectorToHPVector(vector_add(b01,
244 vector_add(vector_multiply_scalar(i1,s1[i]),
245 vector_multiply_scalar(j1,c1[i])))));
246 length = HPmagnitude(HPvector_subtract(vertex, currentPos));
247 if (length > collision_radius)
248 {
249 collision_radius = length;
250 }
251 _vertices[iv++] = vertex.x;
252 _vertices[iv++] = vertex.y;
253 _vertices[iv++] = vertex.z;
254 _exhaustBaseColors[ci++] = ex_emissive[0];
255 _exhaustBaseColors[ci++] = ex_emissive[1];
256 _exhaustBaseColors[ci++] = ex_emissive[2];
257 _exhaustBaseColors[ci++] = ex_emissive[3];
258 }
259
260 ex_emissive[3] = kFadeLevel1 * flare_factor * kOverallAlpha; // fade alpha towards rear of exhaust
261 ex_emissive[1] = kFadeLevel1 * green_factor; // diminish green part towards rear of exhaust
262 ex_emissive[0] = kFadeLevel1 * red_factor; // diminish red part towards rear of exhaust
263
264 k1 = f03.k;
265 i1 = vector_multiply_scalar(cross_product(j1, k1), _exhaustScale.x * kScaleLevel1 * speedScale);
266 j1 = vector_multiply_scalar(cross_product(master_i, k1), _exhaustScale.y * kScaleLevel1 * speedScale);
267 for (i = 0; i < 8; i++)
268 {
269 r1 = randf();
270 vertex = HPvector_add(f03.position,
271 vectorToHPVector(vector_add(b03,
272 vector_add(vector_multiply_scalar(i1,s1[i]),
273 vector_add(vector_multiply_scalar(j1,c1[i]),
274 vector_multiply_scalar(k1,r1))))));
275 length = HPmagnitude(HPvector_subtract(vertex, currentPos));
276 if (length > collision_radius)
277 {
278 collision_radius = length;
279 }
280 _vertices[iv++] = vertex.x;
281 _vertices[iv++] = vertex.y;
282 _vertices[iv++] = vertex.z;
283 _exhaustBaseColors[ci++] = ex_emissive[0];
284 _exhaustBaseColors[ci++] = ex_emissive[1];
285 _exhaustBaseColors[ci++] = ex_emissive[2];
286 _exhaustBaseColors[ci++] = ex_emissive[3];
287 }
288
289 ex_emissive[3] = kFadeLevel2 * flare_factor * kOverallAlpha; // fade alpha towards rear of exhaust
290 ex_emissive[1] = kFadeLevel2 * green_factor; // diminish green part towards rear of exhaust
291 ex_emissive[0] = kFadeLevel2 * red_factor; // diminish red part towards rear of exhaust
292
293 k1 = f06.k;
294 i1 = vector_multiply_scalar(cross_product(j1, k1), 0.8f * _exhaustScale.x * kScaleLevel2 * speedScale);
295 j1 = vector_multiply_scalar(cross_product(master_i, k1), 0.8f * _exhaustScale.y * kScaleLevel2 * speedScale);
296 for (i = 0; i < 8; i++)
297 {
298 r1 = randf();
299 vertex = HPvector_add(f06.position,
300 vectorToHPVector(vector_add(b06,
301 vector_add(vector_multiply_scalar(i1,s1[i]),
302 vector_add(vector_multiply_scalar(j1,c1[i]),
303 vector_multiply_scalar(k1,r1))))));
304 length = HPmagnitude(HPvector_subtract(vertex, currentPos));
305 if (length > collision_radius)
306 {
307 collision_radius = length;
308 }
309 _vertices[iv++] = vertex.x;
310 _vertices[iv++] = vertex.y;
311 _vertices[iv++] = vertex.z;
312 _exhaustBaseColors[ci++] = ex_emissive[0];
313 _exhaustBaseColors[ci++] = ex_emissive[1];
314 _exhaustBaseColors[ci++] = ex_emissive[2];
315 _exhaustBaseColors[ci++] = ex_emissive[3];
316 }
317
318 ex_emissive[3] = kFadeLevel3 * flare_factor * kOverallAlpha; // fade alpha towards rear of exhaust
319 ex_emissive[1] = kFadeLevel3 * green_factor; // diminish green part towards rear of exhaust
320 ex_emissive[0] = kFadeLevel3 * red_factor; // diminish red part towards rear of exhaust
321 k1 = f08.k;
322 i1 = vector_multiply_scalar(cross_product(j1, k1), 0.5f * _exhaustScale.x * kScaleLevel3 * speedScale);
323 j1 = vector_multiply_scalar(cross_product(master_i, k1), 0.5f * _exhaustScale.y * kScaleLevel3 * speedScale);
324 for (i = 0; i < 8; i++)
325 {
326 r1 = randf();
327 vertex = HPvector_add(f08.position,
328 vectorToHPVector(vector_add(b08,
329 vector_add(vector_multiply_scalar(i1,s1[i]),
330 vector_add(vector_multiply_scalar(j1,c1[i]),
331 vector_multiply_scalar(k1,r1))))));
332 length = HPmagnitude(HPvector_subtract(vertex, currentPos));
333 if (length > collision_radius)
334 {
335 collision_radius = length;
336 }
337 _vertices[iv++] = vertex.x;
338 _vertices[iv++] = vertex.y;
339 _vertices[iv++] = vertex.z;
340 _exhaustBaseColors[ci++] = ex_emissive[0];
341 _exhaustBaseColors[ci++] = ex_emissive[1];
342 _exhaustBaseColors[ci++] = ex_emissive[2];
343 _exhaustBaseColors[ci++] = ex_emissive[3];
344 }
345
346 ex_emissive[3] = 0.0; // fade alpha towards rear of exhaust
347 ex_emissive[1] = 0.0; // diminish green part towards rear of exhaust
348 ex_emissive[0] = 0.0; // diminish red part towards rear of exhaust
349 length = HPmagnitude(HPvector_subtract(vertex, currentPos));
350 if (length > collision_radius)
351 {
352 collision_radius = length;
353 }
354 _vertices[iv++] = f10.position.x;
355 _vertices[iv++] = f10.position.y;
356 _vertices[iv++] = f10.position.z;
357 _exhaustBaseColors[ci++] = ex_emissive[0];
358 _exhaustBaseColors[ci++] = ex_emissive[1];
359 _exhaustBaseColors[ci++] = ex_emissive[2];
360 _exhaustBaseColors[ci++] = ex_emissive[3];
361
362 (void)iv; (void)ci; // Suppress Clang static analyzer warnings.
363}
364
365static GLuint tfan1[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 1 }; // initial fan 0..9
366
367// normal polys
368static GLuint tstr1[9] = { 1, 5, 9, 13, 17, 21, 25, 29, 33 };
369static GLuint tstr2[9] = { 2, 6, 10, 14, 18, 22, 26, 30, 33 };
370static GLuint tstr3[9] = { 3, 7, 11, 15, 19, 23, 27, 31, 33 };
371static GLuint tstr4[9] = { 4, 8, 12, 16, 20, 24, 28, 32, 33 };
372
373// aft-view special polys
374static GLuint afttstr1[4] = { 1, 5, 25, 29 };
375static GLuint afttstr2[4] = { 2, 6, 26, 30 };
376static GLuint afttstr3[4] = { 3, 7, 27, 31 };
377static GLuint afttstr4[4] = { 4, 8, 28, 32 };
378
379
380static GLfloat pA[6] = { 0.01, 0.0, 2.0, 4.0, 6.0, 10.0 }; // phase adjustments
381
382
383- (void) drawSubEntityImmediate:(bool)immediate translucent:(bool)translucent
384{
385 if (!translucent) return;
386
387 ShipEntity *ship = [self owner];
388 if ([ship speedFactor] <= 0.001f) return; // don't draw if not moving according to 'update' calculation
389
392
395// GLTranslateOOVector(vector_flip([self cameraRelativePosition]));
396 HPVector cam = [PLAYER viewpointPosition];
397 for (unsigned n=0;n<34*3;n++)
398 {
399 switch (n%3)
400 {
401 case 0: // x coordinates
402 _glVertices[n] = (GLfloat)(_vertices[n] - cam.x);
403 break;
404 case 1: // y coordinates
405 _glVertices[n] = (GLfloat)(_vertices[n] - cam.y);
406 break;
407 case 2: // z coordinates
408 _glVertices[n] = (GLfloat)(_vertices[n] - cam.z);
409 break;
410 }
411 }
412
413 OOGL(glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT));
414
415 OOGL(glDisable(GL_LIGHTING));
416 OOGL(glEnable(GL_BLEND));
417 OOGL(glDepthMask(GL_FALSE));
418 OOGL(glEnableClientState(GL_TEXTURE_COORD_ARRAY));
419 OOGL(glEnable(GL_TEXTURE_2D));
420 [[self texture] apply];
421
422// OOGL(glDisable(GL_CULL_FACE)); // face culling
423 OOGL(glShadeModel(GL_SMOOTH));
424
425 OOGL(glEnableClientState(GL_COLOR_ARRAY));
426 OOGL(glVertexPointer(3, GL_FLOAT, 0, _glVertices));
427 OOGL(glColorPointer(4, GL_FLOAT, 0, _exhaustBaseColors));
428
429 double intpart, dphase = 1.0-modf((double)[UNIVERSE getTime]*2.5,&intpart);
430 GLfloat phase = (GLfloat)dphase;
431
432 GLfloat texCoords[68] = {
433 0.5, phase+pA[0],
434
435 0.1, phase+pA[1], 0.1, phase+pA[1],
436 0.1, phase+pA[1], 0.1, phase+pA[1],
437 0.9, phase+pA[1], 0.9, phase+pA[1],
438 0.9, phase+pA[1], 0.9, phase+pA[1],
439
440 0.1, phase+pA[2], 0.1, phase+pA[2],
441 0.1, phase+pA[2], 0.1, phase+pA[2],
442 0.9, phase+pA[2], 0.9, phase+pA[2],
443 0.9, phase+pA[2], 0.9, phase+pA[2],
444
445 0.1, phase+pA[3], 0.1, phase+pA[3],
446 0.1, phase+pA[3], 0.1, phase+pA[3],
447 0.9, phase+pA[3], 0.9, phase+pA[3],
448 0.9, phase+pA[3], 0.9, phase+pA[3],
449
450 0.1, phase+pA[4], 0.1, phase+pA[4],
451 0.1, phase+pA[4], 0.1, phase+pA[4],
452 0.9, phase+pA[4], 0.9, phase+pA[4],
453 0.9, phase+pA[4], 0.9, phase+pA[4],
454
455 0.5, phase+pA[5],
456 };
457 OOGL(glTexCoordPointer(2, GL_FLOAT, 0, texCoords));
458
459 // reduced detail for internal view to avoid rendering artefacts
460 if ([[self owner] isPlayer] && [UNIVERSE viewDirection] != VIEW_CUSTOM)
461 {
462 OOGL(glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_INT, afttstr1));
463 OOGL(glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_INT, afttstr2));
464 OOGL(glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_INT, afttstr3));
465 OOGL(glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_INT, afttstr4));
466 }
467 else
468 {
469 OOGL(glDrawElements(GL_TRIANGLE_STRIP, 9, GL_UNSIGNED_INT, tstr1));
470 OOGL(glDrawElements(GL_TRIANGLE_STRIP, 9, GL_UNSIGNED_INT, tstr2));
471 OOGL(glDrawElements(GL_TRIANGLE_STRIP, 9, GL_UNSIGNED_INT, tstr3));
472 OOGL(glDrawElements(GL_TRIANGLE_STRIP, 9, GL_UNSIGNED_INT, tstr4));
473 }
474
475 /* Need a different texture and color array for this segment */
476 GLfloat fanTextures[18] = {
477 0.5f, 0.0f+phase,
478 0.2f, 0.0f+phase,
479 0.2f, 0.1f+phase,
480 0.2f, 0.2f+phase,
481 0.2f, 0.3f+phase,
482 0.2f, 0.4f+phase,
483 0.2f, 0.3f+phase,
484 0.2f, 0.2f+phase,
485 0.2f, 0.1f+phase
486 };
487 OOGL(glTexCoordPointer(2, GL_FLOAT, 0, fanTextures));
488
489 GLfloat fanColors[36];
490 GLfloat fr = _exhaustBaseColors[0], fg = _exhaustBaseColors[1], fb = _exhaustBaseColors[2];
491 unsigned i = 0;
492 fanColors[i++] = fr;
493 fanColors[i++] = fg;
494 fanColors[i++] = fb;
495 fanColors[i++] = 1.0;
496 for (;i<36;)
497 {
498 fanColors[i++] = fr;
499 fanColors[i++] = fg;
500 fanColors[i++] = fb;
501 fanColors[i++] = 0.5;
502 }
503 OOGL(glColorPointer(4, GL_FLOAT, 0, fanColors));
504
505 OOGL(glDrawElements(GL_TRIANGLE_FAN, 10, GL_UNSIGNED_INT, tfan1));
506
507 OOGL(glDisableClientState(GL_TEXTURE_COORD_ARRAY));
508 OOGL(glDisable(GL_TEXTURE_2D));
509
510 OOGL(glDisableClientState(GL_COLOR_ARRAY));
511
512
513 OOGL(glPopAttrib());
514
516}
517
518
519#define PREV(n) ((n + kExhaustFrameCount - 1) % kExhaustFrameCount)
520#define NEXT(n) ((n + 1) % kExhaustFrameCount)
521
522
523- (void) saveToLastFrame
524{
525 ShipEntity *ship = [self owner];
526
527 // Absolute position of self
528 // normally this would use the transformation matrix, but that
529 // introduces inaccuracies
530 // so just use the rotation matrix, then translate using HPVectors
531 HPVector framePos = OOHPVectorMultiplyMatrix([self position], [ship drawRotationMatrix]);
532 framePos = HPvector_add(framePos,[ship position]);
533 Frame frame = { [UNIVERSE getTime], framePos, [ship normalOrientation], [ship upVector] };
534
535 _track[_nextFrame] = frame;
536 _nextFrame = (_nextFrame + 1) % kExhaustFrameCount;
537}
538
539
540- (Frame) frameAtTime:(double)t_frame fromFrame:(Frame) frame_zero // t_frame is relative to now ie. -0.5 = half a second ago.
541{
542 if (t_frame >= 0.0) return frame_zero;
543
544 Frame frame_one;
545
546 int t1 = PREV(_nextFrame);
547 double moment_in_time = frame_zero.timeframe + t_frame;
548 double period, f0;
549
550 if (moment_in_time > _trackTime) // between the last saved frame and now
551 {
552 frame_one = _track[t1]; // last saved moment
553 period = (moment_in_time - t_frame) - _trackTime;
554 f0 = 1.0 + t_frame/period;
555 }
556 else if (moment_in_time < _track[_nextFrame].timeframe) // more than kExhaustFrameCount frames back
557 {
558 return _track[_nextFrame];
559 }
560 else
561 {
562 while (moment_in_time < _track[t1].timeframe)
563 {
564 t1 = PREV(t1);
565 }
566 int t0 = NEXT(t1);
567
568 frame_zero = _track[t0];
569 frame_one = _track[t1];
570 period = frame_zero.timeframe - frame_one.timeframe;
571 f0 = (moment_in_time - _track[t1].timeframe)/period;
572 }
573
574 // interpolate
575 double f1 = 1.0 - f0;
576
577 HPVector posn;
578 posn.x = f0 * frame_zero.position.x + f1 * frame_one.position.x;
579 posn.y = f0 * frame_zero.position.y + f1 * frame_one.position.y;
580 posn.z = f0 * frame_zero.position.z + f1 * frame_one.position.z;
581 Quaternion qrot;
582 qrot.w = (float)f0 * frame_zero.orientation.w + (float)f1 * frame_one.orientation.w;
583 qrot.x = (float)f0 * frame_zero.orientation.x + (float)f1 * frame_one.orientation.x;
584 qrot.y = (float)f0 * frame_zero.orientation.y + (float)f1 * frame_one.orientation.y;
585 qrot.z = (float)f0 * frame_zero.orientation.z + (float)f1 * frame_one.orientation.z;
586
587 Frame result;
588 result.position = posn;
589 result.orientation = qrot;
590 result.timeframe = moment_in_time;
591 result.k = vector_forward_from_quaternion(qrot);
592 return result;
593}
594
595
596- (void) resetPlume
597{
598 /*ShipEntity *ship = [self owner];
599
600 // Absolute position of self
601 Vector framePos = OOVectorMultiplyMatrix([self position], [ship drawTransformationMatrix]);
602 Frame frame = { [UNIVERSE getTime], framePos, [ship normalOrientation], [ship upVector] };
603
604 _track[_nextFrame] = frame;
605 _nextFrame = (_nextFrame + 1) % kExhaustFrameCount;*/
606 _nextFrame = 0;
607 HPVector framePos = OOHPVectorMultiplyMatrix([self position], [[self owner] drawTransformationMatrix]);
608 uint8_t i;
609 for (i = 0; i < kExhaustFrameCount; i++)
610 {
611 _track[i].timeframe = 0.0;
612 _track[i].position = framePos;
613 _track[i].orientation = kIdentityQuaternion;
614 _track[i].k = kZeroVector;
615 }
616}
617
618
619- (void) rescaleBy:(GLfloat)factor
620{
621 _exhaustScale = vector_multiply_scalar(_exhaustScale, factor);
622}
623
624
625- (void) rescaleBy:(GLfloat)factor writeToCache:(BOOL)writeToCache
626{
627 /* Do nothing; this is only needed because of OOEntityWithDrawable
628 implementation requirements */
629}
630
631
632- (OOTexture *) texture
633{
635}
636
637
638+ (void) setUpTexture
639{
640 if (sPlumeTexture == nil)
641 {
642 sPlumeTexture = [[OOTexture textureWithName:@"oolite-exhaust-blur.png"
643 inFolder:@"Textures"
644 options:kOOTextureMinFilterMipMap | kOOTextureMagFilterLinear | kOOTextureAlphaMask | kOOTextureRepeatT | kOOTextureRepeatS
645 anisotropy:kOOTextureDefaultAnisotropy / 2.0
646 lodBias:0.0] retain];
647 [[OOGraphicsResetManager sharedManager] registerClient:(id<OOGraphicsResetClient>)[OOExhaustPlumeEntity class]];
648
649 }
650}
651
652
653+ (OOTexture *) plumeTexture
654{
655 if (sPlumeTexture == nil) [self setUpTexture];
656 return sPlumeTexture;
657}
658
659
660+ (void) resetGraphicsState
661{
662 [sPlumeTexture release];
664}
665
666
667@end
668
669
670@implementation Entity (OOExhaustPlume)
671
672- (BOOL)isExhaust
673{
674 return NO;
675}
676
677@end
@ kExhaustFrameCount
static GLuint afttstr3[4]
static GLfloat pA[6]
#define kFadeLevel1
#define kScaleLevel2
static GLuint tstr4[9]
#define kScaleLevel3
static GLuint tfan1[10]
static GLuint tstr2[9]
static GLuint afttstr2[4]
#define PREV(n)
static GLuint tstr3[9]
#define kTimeStep
static GLuint tstr1[9]
#define NEXT(n)
#define kFadeLevel2
#define kFadeLevel3
static GLuint afttstr4[4]
static OOTexture * sPlumeTexture
#define kOverallAlpha
static GLuint afttstr1[4]
#define kScaleLevel1
#define EXPECT_NOT(x)
#define OO_ENTER_OPENGL()
#define M_SQRT1_2
Definition OOMaths.h:94
HPVector OOHPVectorMultiplyMatrix(HPVector v, OOMatrix m)
Definition OOMatrix.m:145
void OOGLPushModelView(void)
OOMatrix OOGLPopModelView(void)
@ OPENGL_STATE_ADDITIVE_BLENDING
Definition OOOpenGL.h:125
#define OOVerifyOpenGLState()
Definition OOOpenGL.h:136
#define OOSetOpenGLState(STATE)
Definition OOOpenGL.h:135
#define OOGL(statement)
Definition OOOpenGL.h:251
unsigned count
return nil
Vector vector_forward_from_quaternion(Quaternion quat)
const Quaternion kIdentityQuaternion
float y
float x
double OOTimeDelta
Definition OOTypes.h:224
double OOTimeAbsolute
Definition OOTypes.h:223
const Vector kZeroVector
Definition OOVector.m:28
#define UNIVERSE
Definition Universe.h:833
HPVector position
Definition Entity.h:112
Quaternion normalOrientation()
Definition Entity.m:738
void getRed:green:blue:alpha:(float *red,[green] float *green,[blue] float *blue,[alpha] float *alpha)
Definition OOColor.m:368
void registerClient:(id< OOGraphicsResetClient > client)
OOGraphicsResetManager * sharedManager()
oneway void release()
Definition OOTexture.m:614
id textureWithName:inFolder:options:anisotropy:lodBias:(NSString *name,[inFolder] NSString *directory,[options] OOTextureFlags options,[anisotropy] GLfloat anisotropy,[lodBias] GLfloat lodBias)
Definition OOTexture.m:134
Vector forwardVector()
Vector upVector()
GLfloat flightSpeed
Definition ShipEntity.h:368
GLfloat speedFactor()
OOColor * exhaustEmissiveColor()
Vector rightVector()
float randf(void)
#define ranrot_rand()
Quaternion orientation
HPVector position