3 Copyright (c) 2002, Calum Robinson
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are met:
9 * Redistributions of source code must retain the above copyright notice, this
10 list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above copyright notice,
13 this list of conditions and the following disclaimer in the documentation
14 and/or other materials provided with the distribution.
16 * Neither the name of the author nor the names of its contributors may be used
17 to endorse or promote products derived from this software without specific
18 prior written permission.
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
21 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
24 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
27 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 #define MAXANGLES 16384
42 #define NOT_QUITE_DEAD 3
44 #define streamBias 7.0f
45 #define incohesion 0.07f
46 #define streamSpeed 450.0
47 #define gravity 1500000.0f
48 #define intensity 75000.0f;
49 #define streamSize 25000.0f
50 #define colorIncoherence 0.15f
54 FastDistance2D(float x
, float y
)
56 // this function computes the distance from 0,0 to x,y with ~3.5% error
58 // first compute the absolute value of x,y
59 x
= (x
< 0.0f
) ? -x
: x
;
60 y
= (y
< 0.0f
) ? -y
: y
;
62 // compute the minimum of x,y
63 float mn
= x
< y
? x
: y
;
65 // return the distance
66 return x
+ y
- (mn
* 0.5f
) - (mn
* 0.25f
) + (mn
* 0.0625f
);
74 s
->nextSubParticle
= 0;
75 s
->lastParticleTime
= 0.25f
;
79 for (int i
= 0; i
< 3; i
++)
80 s
->old
[i
] = RandFlt(-100.0, 100.0);
85 UpdateSmoke_ScalarBase(flurry_info_t
* info
, SmokeV
* s
)
87 float sx
= info
->star
->position
[0];
88 float sy
= info
->star
->position
[1];
89 float sz
= info
->star
->position
[2];
91 double frameRateModifier
;
96 /* release 12 puffs every frame */
97 if (info
->fTime
- s
->lastParticleTime
>= 1.0f
/ 121.0f
) {
115 for(int i
=0; i
< info
->numStreams
; i
++) {
116 float streamSpeedCoherenceFactor
;
118 s
->p
[s
->nextParticle
].delta
[0].f
[s
->nextSubParticle
] = deltax
;
119 s
->p
[s
->nextParticle
].delta
[1].f
[s
->nextSubParticle
] = deltay
;
120 s
->p
[s
->nextParticle
].delta
[2].f
[s
->nextSubParticle
] = deltaz
;
121 s
->p
[s
->nextParticle
].position
[0].f
[s
->nextSubParticle
] = sx
;
122 s
->p
[s
->nextParticle
].position
[1].f
[s
->nextSubParticle
] = sy
;
123 s
->p
[s
->nextParticle
].position
[2].f
[s
->nextSubParticle
] = sz
;
124 s
->p
[s
->nextParticle
].oldposition
[0].f
[s
->nextSubParticle
] = sx
;
125 s
->p
[s
->nextParticle
].oldposition
[1].f
[s
->nextSubParticle
] = sy
;
126 s
->p
[s
->nextParticle
].oldposition
[2].f
[s
->nextSubParticle
] = sz
;
127 streamSpeedCoherenceFactor
= MAX_(0.0f
,1.0f
128 + RandBell(0.25f
* incohesion
));
129 dx
= s
->p
[s
->nextParticle
].position
[0].f
[s
->nextSubParticle
]
130 - info
->spark
[i
]->position
[0];
131 dy
= s
->p
[s
->nextParticle
].position
[1].f
[s
->nextSubParticle
]
132 - info
->spark
[i
]->position
[1];
133 dz
= s
->p
[s
->nextParticle
].position
[2].f
[s
->nextSubParticle
]
134 - info
->spark
[i
]->position
[2];
135 rsquared
= (dx
* dx
+ dy
* dy
+ dz
* dz
);
136 f
= streamSpeed
* streamSpeedCoherenceFactor
;
138 mag
= f
/ (float)sqrt(rsquared
);
140 s
->p
[s
->nextParticle
].delta
[0].f
[s
->nextSubParticle
]
142 s
->p
[s
->nextParticle
].delta
[1].f
[s
->nextSubParticle
]
144 s
->p
[s
->nextParticle
].delta
[2].f
[s
->nextSubParticle
]
146 s
->p
[s
->nextParticle
].color
[0].f
[s
->nextSubParticle
]
147 = info
->spark
[i
]->color
[0] * (1.0f
148 + RandBell(colorIncoherence
));
149 s
->p
[s
->nextParticle
].color
[1].f
[s
->nextSubParticle
]
150 = info
->spark
[i
]->color
[1] * (1.0f
151 + RandBell(colorIncoherence
));
152 s
->p
[s
->nextParticle
].color
[2].f
[s
->nextSubParticle
]
153 = info
->spark
[i
]->color
[2] * (1.0f
154 + RandBell(colorIncoherence
));
155 s
->p
[s
->nextParticle
].color
[3].f
[s
->nextSubParticle
]
156 = 0.85f
* (1.0f
+ RandBell(0.5f
*colorIncoherence
));
157 s
->p
[s
->nextParticle
].time
.f
[s
->nextSubParticle
] = info
->fTime
;
158 s
->p
[s
->nextParticle
].dead
.i
[s
->nextSubParticle
] = 0;
159 s
->p
[s
->nextParticle
].animFrame
.i
[s
->nextSubParticle
]
161 s
->nextSubParticle
++;
162 if (s
->nextSubParticle
== 4) {
164 s
->nextSubParticle
= 0;
166 if (s
->nextParticle
>= NUMSMOKEPARTICLES
/ 4) {
168 s
->nextSubParticle
= 0;
172 s
->lastParticleTime
= info
->fTime
;
175 s
->lastParticleTime
= info
->fTime
;
179 for(int i
= 0; i
< 3; i
++)
180 s
->old
[i
] = info
->star
->position
[i
];
182 frameRate
= ((double) info
->dframe
) / (info
->fTime
);
183 frameRateModifier
= 42.5f
/ frameRate
;
185 for(int i
= 0; i
< NUMSMOKEPARTICLES
/ 4; i
++) {
186 for(int k
= 0; k
< 4; k
++) {
197 if (s
->p
[i
].dead
.i
[k
])
200 deltax
= s
->p
[i
].delta
[0].f
[k
];
201 deltay
= s
->p
[i
].delta
[1].f
[k
];
202 deltaz
= s
->p
[i
].delta
[2].f
[k
];
204 for(int j
= 0; j
< info
->numStreams
; j
++) {
205 dx
= s
->p
[i
].position
[0].f
[k
] - info
->spark
[j
]->position
[0];
206 dy
= s
->p
[i
].position
[1].f
[k
] - info
->spark
[j
]->position
[1];
207 dz
= s
->p
[i
].position
[2].f
[k
] - info
->spark
[j
]->position
[2];
208 rsquared
= (dx
* dx
+ dy
* dy
+ dz
* dz
);
210 f
= (gravity
/rsquared
) * frameRateModifier
;
212 if ((((i
* 4) + k
) % info
->numStreams
) == j
)
213 f
*= 1.0f
+ streamBias
;
215 mag
= f
/ (float) sqrt(rsquared
);
217 deltax
-= (dx
* mag
);
218 deltay
-= (dy
* mag
);
219 deltaz
-= (dz
* mag
);
222 // slow this particle down by info->drag
223 deltax
*= info
->drag
;
224 deltay
*= info
->drag
;
225 deltaz
*= info
->drag
;
227 if ((deltax
* deltax
+ deltay
* deltay
+ deltaz
* deltaz
)
229 s
->p
[i
].dead
.i
[k
] = 1;
233 // update the position
234 s
->p
[i
].delta
[0].f
[k
] = deltax
;
235 s
->p
[i
].delta
[1].f
[k
] = deltay
;
236 s
->p
[i
].delta
[2].f
[k
] = deltaz
;
237 for(int j
= 0; j
< 3; j
++) {
238 s
->p
[i
].oldposition
[j
].f
[k
] = s
->p
[i
].position
[j
].f
[k
];
239 s
->p
[i
].position
[j
].f
[k
]
240 += (s
->p
[i
].delta
[j
].f
[k
]) * info
->fDeltaTime
;
248 DrawSmoke_Scalar(flurry_info_t
* info
, SmokeV
* s
, float brightness
)
263 float screenRatio
= info
->sys_glWidth
/ 1024.0f
;
264 float hslash2
= info
->sys_glHeight
* 0.5f
;
265 float wslash2
= info
->sys_glWidth
* 0.5f
;
267 width
= (streamSize
+ 2.5f
* info
->streamExpansion
) * screenRatio
;
269 for (int i
= 0; i
< NUMSMOKEPARTICLES
/ 4; i
++) {
270 for (int k
= 0; k
< 4; k
++) {
274 if (s
->p
[i
].dead
.i
[k
])
277 thisWidth
= (streamSize
+ (info
->fTime
- s
->p
[i
].time
.f
[k
])
278 * info
->streamExpansion
) * screenRatio
;
279 if (thisWidth
>= width
) {
280 s
->p
[i
].dead
.i
[k
] = 1;
283 z
= s
->p
[i
].position
[2].f
[k
];
284 sx
= s
->p
[i
].position
[0].f
[k
] * info
->sys_glWidth
/ z
+ wslash2
;
285 sy
= s
->p
[i
].position
[1].f
[k
] * info
->sys_glWidth
/ z
+ hslash2
;
286 oldz
= s
->p
[i
].oldposition
[2].f
[k
];
287 if (sx
> info
->sys_glWidth
+ 50.0f
|| sx
< -50.0f
288 || sy
> info
->sys_glHeight
+ 50.0f
|| sy
< -50.0f
|| z
< 25.0f
293 w
= MAX_(1.0f
, thisWidth
/ z
);
295 float oldx
= s
->p
[i
].oldposition
[0].f
[k
];
296 float oldy
= s
->p
[i
].oldposition
[1].f
[k
];
297 float oldscreenx
= (oldx
* info
->sys_glWidth
/ oldz
) + wslash2
;
298 float oldscreeny
= (oldy
* info
->sys_glWidth
/ oldz
) + hslash2
;
299 float dx
= (sx
- oldscreenx
);
300 float dy
= (sy
- oldscreeny
);
302 float d
= FastDistance2D(dx
, dy
);
310 ow
= MAX_(1.0f
, thisWidth
/ oldz
);
323 float dxos
= dx
* os
;
324 float dyos
= dy
* os
;
328 s
->p
[i
].animFrame
.i
[k
]++;
329 if (s
->p
[i
].animFrame
.i
[k
] >= 64)
330 s
->p
[i
].animFrame
.i
[k
] = 0;
332 u0
= (s
->p
[i
].animFrame
.i
[k
] & 7) * 0.125f
;
333 v0
= (s
->p
[i
].animFrame
.i
[k
] >> 3) * 0.125f
;
338 cm
= (1.375f
- thisWidth
/ width
);
339 if (s
->p
[i
].dead
.i
[k
] == 3) {
341 s
->p
[i
].dead
.i
[k
] = 1;
345 cmv
.f
[0] = s
->p
[i
].color
[0].f
[k
] * cm
;
346 cmv
.f
[1] = s
->p
[i
].color
[1].f
[k
] * cm
;
347 cmv
.f
[2] = s
->p
[i
].color
[2].f
[k
] * cm
;
348 cmv
.f
[3] = s
->p
[i
].color
[3].f
[k
] * cm
;
351 // MDT we can't use vectors in the Scalar routine
352 s
->seraphimColors
[sci
++].v
= cmv
.v
;
353 s
->seraphimColors
[sci
++].v
= cmv
.v
;
354 s
->seraphimColors
[sci
++].v
= cmv
.v
;
355 s
->seraphimColors
[sci
++].v
= cmv
.v
;
358 for (int jj
= 0; jj
< 4; jj
++) {
359 for (int ii
= 0; ii
< 4; ii
++)
360 s
->seraphimColors
[sci
].f
[ii
] = cmv
.f
[ii
];
366 s
->seraphimTextures
[sti
++] = u0
;
367 s
->seraphimTextures
[sti
++] = v0
;
368 s
->seraphimTextures
[sti
++] = u0
;
369 s
->seraphimTextures
[sti
++] = v1
;
371 s
->seraphimTextures
[sti
++] = u1
;
372 s
->seraphimTextures
[sti
++] = v1
;
373 s
->seraphimTextures
[sti
++] = u1
;
374 s
->seraphimTextures
[sti
++] = v0
;
376 s
->seraphimVertices
[svi
].f
[0] = sx
+ dxm
- dys
;
377 s
->seraphimVertices
[svi
].f
[1] = sy
+ dym
+ dxs
;
378 s
->seraphimVertices
[svi
].f
[2] = sx
+ dxm
+ dys
;
379 s
->seraphimVertices
[svi
].f
[3] = sy
+ dym
- dxs
;
382 s
->seraphimVertices
[svi
].f
[0] = oldscreenx
- dxm
+ dyos
;
383 s
->seraphimVertices
[svi
].f
[1] = oldscreeny
- dym
- dxos
;
384 s
->seraphimVertices
[svi
].f
[2] = oldscreenx
- dxm
- dyos
;
385 s
->seraphimVertices
[svi
].f
[3] = oldscreeny
- dym
+ dxos
;
392 glColorPointer(4, GL_FLOAT
, 0, s
->seraphimColors
);
393 glVertexPointer(2, GL_FLOAT
, 0, s
->seraphimVertices
);
394 glTexCoordPointer(2, GL_FLOAT
, 0, s
->seraphimTextures
);
395 glDrawArrays(GL_QUADS
, 0, si
* 4);