1 /*
2  * Copyright (C) 2002  Jeremie Allard (Hufo / N.A.A.)
3  *
4  * Note: Credits for the 2d warping field fly to
5  * Hugo Elias: http://freespace.virgin.net/hugo.elias
6  * I've transposed to 3d.
7  *
8  * Ported to Linux by Tugrul Galatali <tugrul@galatali.com>
9  *
10  * hufo_smoke is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License version 2 as
12  * published by the Free Software Foundation.
13  *
14  * hufo_smoke is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23 
24 #include <stdio.h>
25 #include <cmath>
26 
27 // In case cmath doesn't pull in all the usual suspects from math.h
28 #ifndef M_PI
29 #include <math.h>
30 #endif
31 
32 #include <GL/gl.h>
33 
34 #include "FMotion.h"
35 #include "rsRand.h"
36 
37 #define TILE 1.0f
38 #define NBTILEZ 8
39 #define NBTILEY 4
40 #define NBTILEX 8
41 
42 #define WARPFACT (TILE*5.0f)
43 #define AFFFACT ((TILE/16.0f)/WARPFACT)
44 #define SPRINGFACT 0.01f
45 #define DYNFACT 0.998f
46 #define MAXLENGTH (WARPFACT*4)
47 
48 #define ANGFACT 1
49 #define ANGRND 0.16f
50 #define ANG0 0.16f
51 
52 #define SHFT 8
53 
54 #define FLOATTOINTCONST2 (((65536.0*16)))
f2int2(float f)55 inline int f2int2 (float f)
56 {
57 	f += FLOATTOINTCONST2;
58 	return ((*((int *)(void *)&f)) & 0x007fffff) - 0x00400000;
59 }
60 
61 #define FLOATTOINTCONST (((1.5*65536*256)))
f2int(float f)62 inline int f2int (float f)
63 {
64 	f += FLOATTOINTCONST;
65 	return ((*((int *)(void *)&f)) & 0x007fffff) - 0x00400000;
66 }
67 
68 #define Float2Int(f) (f2int(f))
69 #define Float2Int2(f) (f2int2(f))
70 
71 typedef float real;
72 
73 #define SQRT_2 1.414213562f
74 #define SQRT_3 1.732050808f
75 #define SQRT_5 2.236067977f
76 #define SQRT_6 2.449489743f
77 
78 #define D0     0
79 #define D1     1
80 #define D2     2
81 #define D1_1   SQRT_2
82 #define D2_1   SQRT_5
83 #define D2_2   2*SQRT_2
84 #define D1_1_1 SQRT_3
85 #define D2_1_1 SQRT_6
86 #define D2_2_1 3
87 #define D2_2_2 3*SQRT_2
88 
89 real norms[3][3][3] = {
90 	{
91 		{ TILE * D0, TILE * D1, TILE * D2 },
92 		{ TILE * D1, TILE * D1_1, TILE * D2_1 },
93 		{ TILE * D2, TILE * D2_1, TILE * D2_2 },
94 	},
95 	{
96 		{ TILE * D1, TILE * D1_1, TILE * D2_1 },
97 		{ TILE * D1_1, TILE * D1_1_1, TILE * D2_1_1 },
98 		{ TILE * D2_1, TILE * D2_1_1, TILE * D2_2_1 }
99 	},
100 	{
101 		{ TILE * D2, TILE * D2_1, TILE * D2_2 },
102 		{ TILE * D2_1, TILE * D2_1_1, TILE * D2_2_1 },
103 		{ TILE * D2_2, TILE * D2_2_1, TILE * D2_2_2 }
104 	}
105 };
106 
107 real distvar[3] = { -TILE, 0, TILE };
108 
109 struct PARTICLE offset[NBTILEZ][NBTILEY][NBTILEZ];
110 
111 real deplfact[1 << SHFT];
112 
FMotionInit()113 bool FMotionInit ()
114 {
115 	int i;
116 
117 	for (i = 0; i < (1 << SHFT); ++i)
118 		deplfact[i] = i / ((real) (1 << SHFT));
119 	int x, y, z;
120 	PARTICLE *p;
121 
122 	//initialise gelly
123 	real t, t1, t2, t3, tt, tt1, tt2, tt3, ttt, ttt1, ttt2, ttt3, xf, yf, zf;
124 	real f, f1, f2, f3, ff, ff1, ff2, ff3, fff, fff1, fff2, fff3;
125 
126 	ttt = rsRandf (2 * M_PI);
127 	f = rsRandf (ANGRND) + ANG0;
128 	ff = rsRandf (ANGRND) + ANG0;
129 	fff = rsRandf (ANGRND) + ANG0;
130 	ttt1 = rsRandf (2 * M_PI);
131 	f1 = rsRandf (ANGRND) + ANG0;
132 	ff1 = rsRandf (ANGRND) + ANG0;
133 	fff1 = rsRandf (ANGRND) + ANG0;
134 	ttt2 = rsRandf (2 * M_PI);
135 	f2 = rsRandf (ANGRND) + ANG0;
136 	ff2 = rsRandf (ANGRND) + ANG0;
137 	fff2 = rsRandf (ANGRND) + ANG0;
138 	ttt3 = rsRandf (2 * M_PI);
139 	f3 = rsRandf (ANGRND) + ANG0;
140 	ff3 = rsRandf (ANGRND) + ANG0;
141 	fff3 = rsRandf (ANGRND) + ANG0;
142 	p = &offset[0][0][0];
143 	for (z = 0; z < NBTILEZ; z++) {
144 		zf = real (z);
145 		tt = ttt;
146 		tt1 = ttt1;
147 		tt2 = ttt3;
148 		tt3 = ttt3;
149 		ttt += fff;
150 		ttt1 += fff1;
151 		ttt2 += fff2;
152 		ttt3 += fff3;
153 		for (y = 0; y < NBTILEY; y++) {
154 			yf = real (y);
155 			t = tt;
156 			t1 = tt1;
157 			t2 = tt3;
158 			t3 = tt3;
159 			tt += ff;
160 			tt1 += ff1;
161 			tt2 += ff2;
162 			tt3 += ff3;
163 			for (x = 0; x < NBTILEX; x++, p++) {
164 				xf = real (x);
165 				t += f;
166 				t1 += f1;
167 				t2 += f2;
168 				t3 += f3;
169 				p->p.x() = (real) (WARPFACT * (sin (ANGFACT * (t2 - xf)) + cos (ANGFACT * (t2 + yf)) + sin (ANGFACT * (t - yf)) - cos (ANGFACT * (t + xf))));	//+x*TILE);
170 				p->p.y() = (real) (WARPFACT * (sin (ANGFACT * (t1 - xf)) + cos (ANGFACT * (t3 + yf)) + sin (ANGFACT * (t3 - yf)) - cos (ANGFACT * (t1 + xf))));	//+y*TILE);
171 				p->p.z() = (real) (WARPFACT * (sin (ANGFACT * (t - xf)) + cos (ANGFACT * (t2 + yf)) + sin (ANGFACT * (t - yf)) - cos (ANGFACT * (t2 + xf))));	//+z*TILE);
172 				p->v.zero ();
173 			}
174 		}
175 	}
176 	return 1;
177 }
178 
FMotionQuit()179 void FMotionQuit ()
180 {
181 }
182 
FMotionAnimate(const float & dt)183 void FMotionAnimate (const float &dt)
184 {
185 // Handles the wobbling gel, which is used to give the WarpMap it's shape
186 	int x, y, z, xi, yi, zi, xh, xl, yh, yl, zh, zl;
187 	rsVec spring;
188 	real norm;
189 	PARTICLE *p, *p2;
190 	real ft = SPRINGFACT * dt;
191 
192 	p = &offset[0][0][0];
193 	for (z = 0; z < NBTILEZ; z++) {
194 		zh = z + 1;
195 		zl = z - 1;	//if (zl<0)   zl=0; if (zh>tz)        zh=tz;
196 		for (y = 0; y < NBTILEY; y++) {
197 			yh = y + 1;
198 			yl = y - 1;	//if (yl<0)   yl=0; if (yh>ty)        yh=ty;
199 			for (x = 0; x < NBTILEX; x++, p++) {
200 				// Add attraction back to origin of this point
201 				p->v += p->p * (-p->p.length() * ft);
202 				xh = x + 1;
203 				xl = x - 1;	//if (xl<0)   xl=0; if (xh>tx)        xh=tx;
204 				for (zi = zl; zi <= zh; zi++) {
205 					for (yi = yl; yi <= yh; yi++) {
206 						for (xi = xl; xi <= xh; xi++) {
207 							if ((xi != x) || (yi != y) || (zi != z)) {
208 								norm = norms[abs (zi - z)][abs (yi - y)][abs (xi - x)];
209 								p2 = &offset[zi & (NBTILEZ - 1)][yi & (NBTILEY - 1)][xi & (NBTILEX - 1)];
210 								spring = p2->p;
211 								spring -= p->p;
212 								spring.x() += distvar[xi - x + 1];
213 								spring.y() += distvar[yi - y + 1];
214 								spring.z() += distvar[zi - z + 1];
215 								spring *= (norm - spring.length ()) * ft;
216 								p2->v += spring;
217 							}
218 						}
219 					}
220 				}
221 			}
222 		}
223 	}
224 	p = &offset[0][0][0];
225 	ft = (real) pow (DYNFACT, dt);
226 	for (z = 0; z < NBTILEZ; z++) {
227 		for (y = 0; y < NBTILEY; y++) {
228 			for (x = 0; x < NBTILEX; x++, p++) {
229 				p->p += p->v * dt;
230 				if (p->p.length2 () > (MAXLENGTH * MAXLENGTH)) {
231 					p->v.zero ();
232 				} else
233 					p->v *= ft;
234 			}
235 		}
236 	}
237 }
238 
239 #define Point2STX(p) ( (Float2Int((p.x())*(TILE*(1<<SHFT)))+((NBTILEX/2)<<SHFT)) & ((NBTILEX<<SHFT)-1) )
240 #define Point2STY(p) ( (Float2Int((p.y())*(TILE*(1<<SHFT)))+((NBTILEY/2)<<SHFT)) & ((NBTILEY<<SHFT)-1) )
241 #define Point2STZ(p) ( (Float2Int((p.z())*(TILE*(1<<SHFT)))) & ((NBTILEZ<<SHFT)-1) )
242 
FMotionWarp(rsVec & p,const float & dt)243 void FMotionWarp (rsVec &p, const float &dt)
244 {
245 	int sx, sy, sz, x2, y2, z2;
246 
247 	sx = Point2STX (p);
248 	sy = Point2STY (p);
249 	sz = Point2STZ (p);
250 
251 	real fx, fy, fz;
252 
253 	fx = deplfact[sx & ((1 << SHFT) - 1)];
254 	fy = deplfact[sy & ((1 << SHFT) - 1)];
255 	fz = deplfact[sz & ((1 << SHFT) - 1)];
256 	sx >>= SHFT;
257 	x2 = (sx + 1) & (NBTILEX - 1);
258 	sy >>= SHFT;
259 	y2 = (sy + 1) & (NBTILEY - 1);
260 	sz >>= SHFT;
261 	z2 = (sz + 1) & (NBTILEZ - 1);
262 
263 	static rsVec v0, v1, v;
264 
265 	v0.linearInterp (offset[sz][sy][sx].p, offset[sz][sy][sx + 1].p, fx);
266 	v1.linearInterp (offset[z2][sy][sx].p, offset[z2][sy][sx + 1].p, fx);
267 	v.linearInterp (v0, v1, fz);
268 
269 	v *= dt;
270 	p += v;
271 }
272 
273 #define HVCtrX 0.0
274 #define HVCtrY 0.0
275 extern float FireFoc;
276 extern rsVec FireSrc;
277 extern rsMatrix FireM;
278 extern rsVec FireO;
279 
280 #define FireFocX FireFoc
281 #define FireFocY FireFoc
282 
283 #define ProjEX(p) (HVCtrX+FireFocX*(p).x()/(p).y())
284 #define ProjEY(p) (HVCtrY+FireFocY*(p).z()/(p).y())
285 #define ProjEZ(ez,p) (ez)=-((p).y()*(1.0f/20.0f)-1.0f)
286 
AffFMotion()287 void AffFMotion ()
288 {
289 	int x, y, z;
290 	PARTICLE *p;
291 	real xf, yf, zf;
292 	real ex, ey;
293 	real ez;
294 	rsVec p1, p2, o;
295 
296 	p = &offset[0][0][0];
297 
298 	glBegin (GL_LINES);
299 
300 	o = FireSrc;
301 	o.x() -= TILE * NBTILEX / 2;
302 	o.y() -= TILE * NBTILEY / 2;
303 	o.transVec(FireM);
304 	o += FireO;
305 	for (z = 0; z < NBTILEZ; z++) {
306 		zf = z * TILE;
307 		for (y = 0; y < NBTILEY; y++) {
308 			yf = y * TILE;
309 			for (x = 0; x < NBTILEX; x++, p++) {
310 				xf = x * TILE;
311 				p1.x() = xf;
312 				p1.y() = yf;
313 				p1.z() = zf;
314 				p2 = p1 + p->p * AFFFACT;
315 				p1.transVec(FireM);
316 				p1 += o;
317 				p2.transVec(FireM);
318 				p2 += o;
319 				if (p1.y() > 0 && p2.y() > 0) {
320 					ex = ProjEX (p1);
321 					ey = ProjEY (p1);
322 					ProjEZ (ez, p1);
323 					glVertex3f (ex, ey, ez);
324 					ex = ProjEX (p2);
325 					ey = ProjEY (p2);
326 					ProjEZ (ez, p2);
327 					glVertex3f (ex, ey, ez);
328 				}
329 			}
330 		}
331 	}
332 
333 	glEnd ();
334 }
335