Merge branch 'mesa_7_7_branch'
[mesa.git] / progs / demos / fire.c
1 /*
2 * This program is under the GNU GPL.
3 * Use at your own risk.
4 *
5 * written by David Bucciarelli (tech.hmw@plus.it)
6 * Humanware s.r.l.
7 */
8
9 #include <assert.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <math.h>
13 #include <time.h>
14 #include <string.h>
15
16 #ifdef WIN32
17 #include <windows.h>
18 #include <mmsystem.h>
19 #endif
20
21 #include <GL/glut.h>
22 #include "readtex.h"
23
24 #ifdef XMESA
25 #include "GL/xmesa.h"
26 static int fullscreen = 1;
27 #endif
28
29 #ifndef M_PI
30 #define M_PI 3.1415926535
31 #endif
32
33 #define vinit(a,i,j,k) {\
34 (a)[0]=i;\
35 (a)[1]=j;\
36 (a)[2]=k;\
37 }
38
39 #define vinit4(a,i,j,k,w) {\
40 (a)[0]=i;\
41 (a)[1]=j;\
42 (a)[2]=k;\
43 (a)[3]=w;\
44 }
45
46
47 #define vadds(a,dt,b) {\
48 (a)[0]+=(dt)*(b)[0];\
49 (a)[1]+=(dt)*(b)[1];\
50 (a)[2]+=(dt)*(b)[2];\
51 }
52
53 #define vequ(a,b) {\
54 (a)[0]=(b)[0];\
55 (a)[1]=(b)[1];\
56 (a)[2]=(b)[2];\
57 }
58
59 #define vinter(a,dt,b,c) {\
60 (a)[0]=(dt)*(b)[0]+(1.0-dt)*(c)[0];\
61 (a)[1]=(dt)*(b)[1]+(1.0-dt)*(c)[1];\
62 (a)[2]=(dt)*(b)[2]+(1.0-dt)*(c)[2];\
63 }
64
65 #define clamp(a) ((a) < 0.0 ? 0.0 : ((a) < 1.0 ? (a) : 1.0))
66
67 #define vclamp(v) {\
68 (v)[0]=clamp((v)[0]);\
69 (v)[1]=clamp((v)[1]);\
70 (v)[2]=clamp((v)[2]);\
71 }
72
73 static int WIDTH = 640;
74 static int HEIGHT = 480;
75
76 static GLint T0 = 0;
77 static GLint Frames = 0;
78 static GLint NiceFog = 1;
79
80 #define DIMP 20.0
81 #define DIMTP 16.0
82
83 #define RIDCOL 0.4
84
85 #define NUMTREE 50
86 #define TREEINR 2.5
87 #define TREEOUTR 8.0
88
89 #define AGRAV -9.8
90
91 typedef struct
92 {
93 int age;
94 float p[3][3];
95 float v[3];
96 float c[3][4];
97 }
98 part;
99
100 static float treepos[NUMTREE][3];
101
102 static float black[3] = { 0.0, 0.0, 0.0 };
103 static float blu[3] = { 1.0, 0.2, 0.0 };
104 static float blu2[3] = { 1.0, 1.0, 0.0 };
105
106 static float fogcolor[4] = { 1.0, 1.0, 1.0, 1.0 };
107
108 static float q[4][3] = {
109 {-DIMP, 0.0, -DIMP},
110 {DIMP, 0.0, -DIMP},
111 {DIMP, 0.0, DIMP},
112 {-DIMP, 0.0, DIMP}
113 };
114
115 static float qt[4][2] = {
116 {-DIMTP, -DIMTP},
117 {DIMTP, -DIMTP},
118 {DIMTP, DIMTP},
119 {-DIMTP, DIMTP}
120 };
121
122 static int win = 0;
123
124 static int np;
125 static float eject_r, dt, maxage, eject_vy, eject_vl;
126 static short shadows;
127 static float ridtri;
128 static int fog = 1;
129 static int help = 1;
130 static int joyavailable = 0;
131 static int joyactive = 0;
132
133 static part *p;
134
135 static GLuint groundid;
136 static GLuint treeid;
137
138 static float obs[3] = { 2.0, 1.0, 0.0 };
139 static float dir[3];
140 static float v = 0.0;
141 static float alpha = -84.0;
142 static float beta = 90.0;
143
144 static float
145 vrnd(void)
146 {
147 return (((float) rand()) / RAND_MAX);
148 }
149
150 static void
151 setnewpart(part * p)
152 {
153 float a, v[3], *c;
154
155 p->age = 0;
156
157 a = vrnd() * 3.14159265359 * 2.0;
158
159 vinit(v, sin(a) * eject_r * vrnd(), 0.15, cos(a) * eject_r * vrnd());
160 vinit(p->p[0], v[0] + vrnd() * ridtri, v[1] + vrnd() * ridtri,
161 v[2] + vrnd() * ridtri);
162 vinit(p->p[1], v[0] + vrnd() * ridtri, v[1] + vrnd() * ridtri,
163 v[2] + vrnd() * ridtri);
164 vinit(p->p[2], v[0] + vrnd() * ridtri, v[1] + vrnd() * ridtri,
165 v[2] + vrnd() * ridtri);
166
167 vinit(p->v, v[0] * eject_vl / (eject_r / 2),
168 vrnd() * eject_vy + eject_vy / 2, v[2] * eject_vl / (eject_r / 2));
169
170 c = blu;
171
172 vinit4(p->c[0], c[0] * ((1.0 - RIDCOL) + vrnd() * RIDCOL),
173 c[1] * ((1.0 - RIDCOL) + vrnd() * RIDCOL),
174 c[2] * ((1.0 - RIDCOL) + vrnd() * RIDCOL), 1.0);
175 vinit4(p->c[1], c[0] * ((1.0 - RIDCOL) + vrnd() * RIDCOL),
176 c[1] * ((1.0 - RIDCOL) + vrnd() * RIDCOL),
177 c[2] * ((1.0 - RIDCOL) + vrnd() * RIDCOL), 1.0);
178 vinit4(p->c[2], c[0] * ((1.0 - RIDCOL) + vrnd() * RIDCOL),
179 c[1] * ((1.0 - RIDCOL) + vrnd() * RIDCOL),
180 c[2] * ((1.0 - RIDCOL) + vrnd() * RIDCOL), 1.0);
181 }
182
183 static void
184 setpart(part * p)
185 {
186 float fact;
187
188 if (p->p[0][1] < 0.1) {
189 setnewpart(p);
190 return;
191 }
192
193 p->v[1] += AGRAV * dt;
194
195 vadds(p->p[0], dt, p->v);
196 vadds(p->p[1], dt, p->v);
197 vadds(p->p[2], dt, p->v);
198
199 p->age++;
200
201 if ((p->age) > maxage) {
202 vequ(p->c[0], blu2);
203 vequ(p->c[1], blu2);
204 vequ(p->c[2], blu2);
205 }
206 else {
207 fact = 1.0 / maxage;
208 vadds(p->c[0], fact, blu2);
209 vclamp(p->c[0]);
210 p->c[0][3] = fact * (maxage - p->age);
211
212 vadds(p->c[1], fact, blu2);
213 vclamp(p->c[1]);
214 p->c[1][3] = fact * (maxage - p->age);
215
216 vadds(p->c[2], fact, blu2);
217 vclamp(p->c[2]);
218 p->c[2][3] = fact * (maxage - p->age);
219 }
220 }
221
222 static void
223 drawtree(float x, float y, float z)
224 {
225 glBegin(GL_QUADS);
226 glTexCoord2f(0.0, 0.0);
227 glVertex3f(x - 1.5, y + 0.0, z);
228
229 glTexCoord2f(1.0, 0.0);
230 glVertex3f(x + 1.5, y + 0.0, z);
231
232 glTexCoord2f(1.0, 1.0);
233 glVertex3f(x + 1.5, y + 3.0, z);
234
235 glTexCoord2f(0.0, 1.0);
236 glVertex3f(x - 1.5, y + 3.0, z);
237
238
239 glTexCoord2f(0.0, 0.0);
240 glVertex3f(x, y + 0.0, z - 1.5);
241
242 glTexCoord2f(1.0, 0.0);
243 glVertex3f(x, y + 0.0, z + 1.5);
244
245 glTexCoord2f(1.0, 1.0);
246 glVertex3f(x, y + 3.0, z + 1.5);
247
248 glTexCoord2f(0.0, 1.0);
249 glVertex3f(x, y + 3.0, z - 1.5);
250
251 glEnd();
252
253 }
254
255 static void
256 calcposobs(void)
257 {
258 dir[0] = sin(alpha * M_PI / 180.0);
259 dir[2] = cos(alpha * M_PI / 180.0) * sin(beta * M_PI / 180.0);
260 dir[1] = cos(beta * M_PI / 180.0);
261
262 if (dir[0] < 1.0e-5 && dir[0] > -1.0e-5)
263 dir[0] = 0;
264 if (dir[1] < 1.0e-5 && dir[1] > -1.0e-5)
265 dir[1] = 0;
266 if (dir[2] < 1.0e-5 && dir[2] > -1.0e-5)
267 dir[2] = 0;
268
269 obs[0] += v * dir[0];
270 obs[1] += v * dir[1];
271 obs[2] += v * dir[2];
272 }
273
274 static void
275 printstring(void *font, char *string)
276 {
277 int len, i;
278
279 len = (int) strlen(string);
280 for (i = 0; i < len; i++)
281 glutBitmapCharacter(font, string[i]);
282 }
283
284 static void
285 reshape(int width, int height)
286 {
287 WIDTH = width;
288 HEIGHT = height;
289 glViewport(0, 0, (GLint) width, (GLint) height);
290 glMatrixMode(GL_PROJECTION);
291 glLoadIdentity();
292 gluPerspective(70.0, width / (float) height, 0.1, 30.0);
293
294 glMatrixMode(GL_MODELVIEW);
295 }
296
297 static void
298 printhelp(void)
299 {
300 glColor4f(0.0, 0.0, 0.0, 0.5);
301 glRecti(40, 40, 600, 440);
302
303 glColor3f(1.0, 0.0, 0.0);
304 glRasterPos2i(300, 420);
305 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "Help");
306
307 glRasterPos2i(60, 390);
308 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "h - Toggle Help");
309
310 glRasterPos2i(60, 360);
311 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "t - Increase particle size");
312 glRasterPos2i(60, 330);
313 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "T - Decrease particle size");
314
315 glRasterPos2i(60, 300);
316 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "r - Increase emission radius");
317 glRasterPos2i(60, 270);
318 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "R - Decrease emission radius");
319
320 glRasterPos2i(60, 240);
321 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "f - Toggle Fog");
322 glRasterPos2i(60, 210);
323 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "s - Toggle shadows");
324 glRasterPos2i(60, 180);
325 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "Arrow Keys - Rotate");
326 glRasterPos2i(60, 150);
327 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "a - Increase velocity");
328 glRasterPos2i(60, 120);
329 printstring(GLUT_BITMAP_TIMES_ROMAN_24, "z - Decrease velocity");
330
331 glRasterPos2i(60, 90);
332 if (joyavailable)
333 printstring(GLUT_BITMAP_TIMES_ROMAN_24,
334 "j - Toggle jostick control (Joystick control available)");
335 else
336 printstring(GLUT_BITMAP_TIMES_ROMAN_24,
337 "(No Joystick control available)");
338 }
339
340 static void
341 dojoy(void)
342 {
343 #ifdef WIN32
344 static UINT max[2] = { 0, 0 };
345 static UINT min[2] = { 0xffffffff, 0xffffffff }, center[2];
346 MMRESULT res;
347 JOYINFO joy;
348
349 res = joyGetPos(JOYSTICKID1, &joy);
350
351 if (res == JOYERR_NOERROR) {
352 joyavailable = 1;
353
354 if (max[0] < joy.wXpos)
355 max[0] = joy.wXpos;
356 if (min[0] > joy.wXpos)
357 min[0] = joy.wXpos;
358 center[0] = (max[0] + min[0]) / 2;
359
360 if (max[1] < joy.wYpos)
361 max[1] = joy.wYpos;
362 if (min[1] > joy.wYpos)
363 min[1] = joy.wYpos;
364 center[1] = (max[1] + min[1]) / 2;
365
366 if (joyactive) {
367 if (fabs(center[0] - (float) joy.wXpos) > 0.1 * (max[0] - min[0]))
368 alpha +=
369 2.5 * (center[0] - (float) joy.wXpos) / (max[0] - min[0]);
370 if (fabs(center[1] - (float) joy.wYpos) > 0.1 * (max[1] - min[1]))
371 beta += 2.5 * (center[1] - (float) joy.wYpos) / (max[1] - min[1]);
372
373 if (joy.wButtons & JOY_BUTTON1)
374 v += 0.01;
375 if (joy.wButtons & JOY_BUTTON2)
376 v -= 0.01;
377 }
378 }
379 else
380 joyavailable = 0;
381 #endif
382 }
383
384 static void
385 drawfire(void)
386 {
387 static char frbuf[80] = "";
388 int j;
389 static double t0 = -1.;
390 double t = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
391 if (t0 < 0.0)
392 t0 = t;
393 dt = (t - t0) * 1.0;
394 t0 = t;
395
396 dojoy();
397
398 if (NiceFog)
399 glHint(GL_FOG_HINT, GL_NICEST);
400 else
401 glHint(GL_FOG_HINT, GL_DONT_CARE);
402
403 glEnable(GL_DEPTH_TEST);
404
405 if (fog)
406 glEnable(GL_FOG);
407 else
408 glDisable(GL_FOG);
409
410 glDepthMask(GL_TRUE);
411 glClearColor(1.0, 1.0, 1.0, 1.0);
412 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
413
414 glPushMatrix();
415 calcposobs();
416 gluLookAt(obs[0], obs[1], obs[2],
417 obs[0] + dir[0], obs[1] + dir[1], obs[2] + dir[2],
418 0.0, 1.0, 0.0);
419
420 glColor4f(1.0, 1.0, 1.0, 1.0);
421
422 glEnable(GL_TEXTURE_2D);
423
424 glBindTexture(GL_TEXTURE_2D, groundid);
425 #if 1
426 glBegin(GL_QUADS);
427 glTexCoord2fv(qt[0]);
428 glVertex3fv(q[0]);
429 glTexCoord2fv(qt[1]);
430 glVertex3fv(q[1]);
431 glTexCoord2fv(qt[2]);
432 glVertex3fv(q[2]);
433 glTexCoord2fv(qt[3]);
434 glVertex3fv(q[3]);
435 glEnd();
436 #else
437 /* Subdivide the ground into a bunch of quads. This improves fog
438 * if GL_FOG_HINT != GL_NICEST
439 */
440 {
441 float x, y;
442 float dx = 1.0, dy = 1.0;
443 glBegin(GL_QUADS);
444 for (y = -DIMP; y < DIMP; y += 1.0) {
445 for (x = -DIMP; x < DIMP; x += 1.0) {
446 glTexCoord2f(0, 0); glVertex3f(x, 0, y);
447 glTexCoord2f(1, 0); glVertex3f(x+dx, 0, y);
448 glTexCoord2f(1, 1); glVertex3f(x+dx, 0, y+dy);
449 glTexCoord2f(0, 1); glVertex3f(x, 0, y+dy);
450 }
451 }
452 glEnd();
453 }
454 #endif
455
456
457 glEnable(GL_ALPHA_TEST);
458 glAlphaFunc(GL_GEQUAL, 0.9);
459
460 glBindTexture(GL_TEXTURE_2D, treeid);
461 for (j = 0; j < NUMTREE; j++)
462 drawtree(treepos[j][0], treepos[j][1], treepos[j][2]);
463
464 glDisable(GL_TEXTURE_2D);
465 glDepthMask(GL_FALSE);
466 glDisable(GL_ALPHA_TEST);
467
468 if (shadows) {
469 glBegin(GL_TRIANGLES);
470 for (j = 0; j < np; j++) {
471 glColor4f(black[0], black[1], black[2], p[j].c[0][3]);
472 glVertex3f(p[j].p[0][0], 0.1, p[j].p[0][2]);
473
474 glColor4f(black[0], black[1], black[2], p[j].c[1][3]);
475 glVertex3f(p[j].p[1][0], 0.1, p[j].p[1][2]);
476
477 glColor4f(black[0], black[1], black[2], p[j].c[2][3]);
478 glVertex3f(p[j].p[2][0], 0.1, p[j].p[2][2]);
479 }
480 glEnd();
481 }
482
483 glBegin(GL_TRIANGLES);
484 for (j = 0; j < np; j++) {
485 glColor4fv(p[j].c[0]);
486 glVertex3fv(p[j].p[0]);
487
488 glColor4fv(p[j].c[1]);
489 glVertex3fv(p[j].p[1]);
490
491 glColor4fv(p[j].c[2]);
492 glVertex3fv(p[j].p[2]);
493
494 setpart(&p[j]);
495 }
496 glEnd();
497
498 glDisable(GL_TEXTURE_2D);
499 glDisable(GL_ALPHA_TEST);
500 glDisable(GL_DEPTH_TEST);
501 glDisable(GL_FOG);
502
503 glMatrixMode(GL_PROJECTION);
504 glLoadIdentity();
505 glOrtho(-0.5, 639.5, -0.5, 479.5, -1.0, 1.0);
506 glMatrixMode(GL_MODELVIEW);
507 glLoadIdentity();
508
509 glColor3f(1.0, 0.0, 0.0);
510 glRasterPos2i(10, 10);
511 printstring(GLUT_BITMAP_HELVETICA_18, frbuf);
512 glRasterPos2i(370, 470);
513 printstring(GLUT_BITMAP_HELVETICA_10,
514 "Fire V1.5 Written by David Bucciarelli (tech.hmw@plus.it)");
515
516 if (help)
517 printhelp();
518
519 reshape(WIDTH, HEIGHT);
520 glPopMatrix();
521
522 glutSwapBuffers();
523
524 Frames++;
525 {
526 GLint t = glutGet(GLUT_ELAPSED_TIME);
527 if (t - T0 >= 2000) {
528 GLfloat seconds = (t - T0) / 1000.0;
529 GLfloat fps = Frames / seconds;
530 sprintf(frbuf, "Frame rate: %f", fps);
531 T0 = t;
532 Frames = 0;
533 }
534 }
535 }
536
537
538 static void
539 idle(void)
540 {
541 glutPostRedisplay();
542 }
543
544
545 static void
546 special(int key, int x, int y)
547 {
548 switch (key) {
549 case GLUT_KEY_LEFT:
550 alpha += 2.0;
551 break;
552 case GLUT_KEY_RIGHT:
553 alpha -= 2.0;
554 break;
555 case GLUT_KEY_DOWN:
556 beta -= 2.0;
557 break;
558 case GLUT_KEY_UP:
559 beta += 2.0;
560 break;
561 }
562 glutPostRedisplay();
563 }
564
565 static void
566 key(unsigned char key, int x, int y)
567 {
568 switch (key) {
569 case 27:
570 exit(0);
571 break;
572
573 case 'a':
574 v += 0.0005;
575 break;
576 case 'z':
577 v -= 0.0005;
578 break;
579
580 case 'j':
581 joyactive = (!joyactive);
582 break;
583 case 'h':
584 help = (!help);
585 break;
586 case 'f':
587 fog = (!fog);
588 break;
589 case 's':
590 shadows = !shadows;
591 break;
592 case 'R':
593 eject_r -= 0.03;
594 break;
595 case 'r':
596 eject_r += 0.03;
597 break;
598 case 't':
599 ridtri += 0.005;
600 break;
601 case 'T':
602 ridtri -= 0.005;
603 break;
604 #ifdef XMESA
605 case ' ':
606 XMesaSetFXmode(fullscreen ? XMESA_FX_FULLSCREEN : XMESA_FX_WINDOW);
607 fullscreen = (!fullscreen);
608 break;
609 #endif
610 case 'n':
611 NiceFog = !NiceFog;
612 printf("NiceFog %d\n", NiceFog);
613 break;
614 }
615 glutPostRedisplay();
616 }
617
618 static void
619 inittextures(void)
620 {
621 GLenum gluerr;
622 GLubyte tex[128][128][4];
623
624 glGenTextures(1, &groundid);
625 glBindTexture(GL_TEXTURE_2D, groundid);
626
627 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
628 if (!LoadRGBMipmaps("../images/s128.rgb", GL_RGB)) {
629 fprintf(stderr, "Error reading a texture.\n");
630 exit(-1);
631 }
632
633 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
634 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
635
636 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
637 GL_LINEAR_MIPMAP_LINEAR);
638 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
639
640 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
641
642 glGenTextures(1, &treeid);
643 glBindTexture(GL_TEXTURE_2D, treeid);
644
645 if (1)
646 {
647 int w, h;
648 GLenum format;
649 int x, y;
650 GLubyte *image = LoadRGBImage("../images/tree3.rgb", &w, &h, &format);
651
652 if (!image) {
653 fprintf(stderr, "Error reading a texture.\n");
654 exit(-1);
655 }
656
657 for (y = 0; y < 128; y++)
658 for (x = 0; x < 128; x++) {
659 tex[x][y][0] = image[(y + x * 128) * 3];
660 tex[x][y][1] = image[(y + x * 128) * 3 + 1];
661 tex[x][y][2] = image[(y + x * 128) * 3 + 2];
662 if ((tex[x][y][0] == tex[x][y][1]) &&
663 (tex[x][y][1] == tex[x][y][2]) && (tex[x][y][2] == 255))
664 tex[x][y][3] = 0;
665 else
666 tex[x][y][3] = 255;
667 }
668
669 if ((gluerr = gluBuild2DMipmaps(GL_TEXTURE_2D, 4, 128, 128, GL_RGBA,
670 GL_UNSIGNED_BYTE, (GLvoid *) (tex)))) {
671 fprintf(stderr, "GLULib%s\n", (char *) gluErrorString(gluerr));
672 exit(-1);
673 }
674 }
675 else {
676 if (!LoadRGBMipmaps("../images/tree2.rgba", GL_RGBA)) {
677 fprintf(stderr, "Error reading a texture.\n");
678 exit(-1);
679 }
680 }
681
682 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
683 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
684
685 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
686 GL_LINEAR_MIPMAP_LINEAR);
687 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
688
689 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
690 }
691
692 static void
693 inittree(void)
694 {
695 int i;
696 float dist;
697
698 for (i = 0; i < NUMTREE; i++)
699 do {
700 treepos[i][0] = vrnd() * TREEOUTR * 2.0 - TREEOUTR;
701 treepos[i][1] = 0.0;
702 treepos[i][2] = vrnd() * TREEOUTR * 2.0 - TREEOUTR;
703 dist =
704 sqrt(treepos[i][0] * treepos[i][0] +
705 treepos[i][2] * treepos[i][2]);
706 } while ((dist < TREEINR) || (dist > TREEOUTR));
707 }
708
709 int
710 main(int ac, char **av)
711 {
712 int i;
713
714 fprintf(stderr,
715 "Fire V1.5\nWritten by David Bucciarelli (tech.hmw@plus.it)\n");
716
717 /* Default settings */
718
719 np = 800;
720 eject_r = -0.65;
721 dt = 0.015;
722 eject_vy = 4;
723 eject_vl = 1;
724 shadows = 1;
725 ridtri = 0.25;
726
727 maxage = 1.0 / dt;
728
729 if (ac == 2) {
730 np = atoi(av[1]);
731 if (np <= 0 || np > 1000000) {
732 fprintf(stderr, "Invalid input.\n");
733 exit(-1);
734 }
735 }
736
737 if (ac == 4) {
738 WIDTH = atoi(av[2]);
739 HEIGHT = atoi(av[3]);
740 }
741
742 glutInitWindowSize(WIDTH, HEIGHT);
743 glutInit(&ac, av);
744
745 glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
746
747 if (!(win = glutCreateWindow("Fire"))) {
748 fprintf(stderr, "Error opening a window.\n");
749 exit(-1);
750 }
751
752 reshape(WIDTH, HEIGHT);
753
754 inittextures();
755
756 glShadeModel(GL_FLAT);
757 glEnable(GL_DEPTH_TEST);
758
759 glEnable(GL_BLEND);
760 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
761
762 glEnable(GL_FOG);
763 glFogi(GL_FOG_MODE, GL_EXP);
764 glFogfv(GL_FOG_COLOR, fogcolor);
765 glFogf(GL_FOG_DENSITY, 0.1);
766
767 assert(np > 0);
768 p = (part *) malloc(sizeof(part) * np);
769 assert(p);
770
771 for (i = 0; i < np; i++)
772 setnewpart(&p[i]);
773
774 inittree();
775
776 glutKeyboardFunc(key);
777 glutSpecialFunc(special);
778 glutDisplayFunc(drawfire);
779 glutIdleFunc(idle);
780 glutReshapeFunc(reshape);
781 glutMainLoop();
782
783 return (0);
784 }