2 * This program is under the GNU GPL.
3 * Use at your own risk.
5 * written by David Bucciarelli (tech.hmw@plus.it)
26 static int fullscreen
= 1;
30 #define M_PI 3.1415926535
33 #define vinit(a,i,j,k) {\
39 #define vinit4(a,i,j,k,w) {\
47 #define vadds(a,dt,b) {\
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];\
65 #define clamp(a) ((a) < 0.0 ? 0.0 : ((a) < 1.0 ? (a) : 1.0))
68 (v)[0]=clamp((v)[0]);\
69 (v)[1]=clamp((v)[1]);\
70 (v)[2]=clamp((v)[2]);\
73 static int WIDTH
= 640;
74 static int HEIGHT
= 480;
77 static GLint Frames
= 0;
78 static GLint NiceFog
= 1;
100 static float treepos
[NUMTREE
][3];
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 };
106 static float fogcolor
[4] = { 1.0, 1.0, 1.0, 1.0 };
108 static float q
[4][3] = {
115 static float qt
[4][2] = {
125 static float eject_r
, dt
, maxage
, eject_vy
, eject_vl
;
126 static short shadows
;
130 static int joyavailable
= 0;
131 static int joyactive
= 0;
135 static GLuint groundid
;
136 static GLuint treeid
;
138 static float obs
[3] = { 2.0, 1.0, 0.0 };
140 static float v
= 0.0;
141 static float alpha
= -84.0;
142 static float beta
= 90.0;
147 return (((float) rand()) / RAND_MAX
);
157 a
= vrnd() * 3.14159265359 * 2.0;
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
);
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));
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);
188 if (p
->p
[0][1] < 0.1) {
193 p
->v
[1] += AGRAV
* dt
;
195 vadds(p
->p
[0], dt
, p
->v
);
196 vadds(p
->p
[1], dt
, p
->v
);
197 vadds(p
->p
[2], dt
, p
->v
);
201 if ((p
->age
) > maxage
) {
208 vadds(p
->c
[0], fact
, blu2
);
210 p
->c
[0][3] = fact
* (maxage
- p
->age
);
212 vadds(p
->c
[1], fact
, blu2
);
214 p
->c
[1][3] = fact
* (maxage
- p
->age
);
216 vadds(p
->c
[2], fact
, blu2
);
218 p
->c
[2][3] = fact
* (maxage
- p
->age
);
223 drawtree(float x
, float y
, float z
)
226 glTexCoord2f(0.0, 0.0);
227 glVertex3f(x
- 1.5, y
+ 0.0, z
);
229 glTexCoord2f(1.0, 0.0);
230 glVertex3f(x
+ 1.5, y
+ 0.0, z
);
232 glTexCoord2f(1.0, 1.0);
233 glVertex3f(x
+ 1.5, y
+ 3.0, z
);
235 glTexCoord2f(0.0, 1.0);
236 glVertex3f(x
- 1.5, y
+ 3.0, z
);
239 glTexCoord2f(0.0, 0.0);
240 glVertex3f(x
, y
+ 0.0, z
- 1.5);
242 glTexCoord2f(1.0, 0.0);
243 glVertex3f(x
, y
+ 0.0, z
+ 1.5);
245 glTexCoord2f(1.0, 1.0);
246 glVertex3f(x
, y
+ 3.0, z
+ 1.5);
248 glTexCoord2f(0.0, 1.0);
249 glVertex3f(x
, y
+ 3.0, z
- 1.5);
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);
262 if (dir
[0] < 1.0e-5 && dir
[0] > -1.0e-5)
264 if (dir
[1] < 1.0e-5 && dir
[1] > -1.0e-5)
266 if (dir
[2] < 1.0e-5 && dir
[2] > -1.0e-5)
269 obs
[0] += v
* dir
[0];
270 obs
[1] += v
* dir
[1];
271 obs
[2] += v
* dir
[2];
275 printstring(void *font
, char *string
)
279 len
= (int) strlen(string
);
280 for (i
= 0; i
< len
; i
++)
281 glutBitmapCharacter(font
, string
[i
]);
285 reshape(int width
, int height
)
289 glViewport(0, 0, (GLint
) width
, (GLint
) height
);
290 glMatrixMode(GL_PROJECTION
);
292 gluPerspective(70.0, width
/ (float) height
, 0.1, 30.0);
294 glMatrixMode(GL_MODELVIEW
);
300 glColor4f(0.0, 0.0, 0.0, 0.5);
301 glRecti(40, 40, 600, 440);
303 glColor3f(1.0, 0.0, 0.0);
304 glRasterPos2i(300, 420);
305 printstring(GLUT_BITMAP_TIMES_ROMAN_24
, "Help");
307 glRasterPos2i(60, 390);
308 printstring(GLUT_BITMAP_TIMES_ROMAN_24
, "h - Toggle Help");
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");
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");
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");
331 glRasterPos2i(60, 90);
333 printstring(GLUT_BITMAP_TIMES_ROMAN_24
,
334 "j - Toggle jostick control (Joystick control available)");
336 printstring(GLUT_BITMAP_TIMES_ROMAN_24
,
337 "(No Joystick control available)");
344 static UINT max
[2] = { 0, 0 };
345 static UINT min
[2] = { 0xffffffff, 0xffffffff }, center
[2];
349 res
= joyGetPos(JOYSTICKID1
, &joy
);
351 if (res
== JOYERR_NOERROR
) {
354 if (max
[0] < joy
.wXpos
)
356 if (min
[0] > joy
.wXpos
)
358 center
[0] = (max
[0] + min
[0]) / 2;
360 if (max
[1] < joy
.wYpos
)
362 if (min
[1] > joy
.wYpos
)
364 center
[1] = (max
[1] + min
[1]) / 2;
367 if (fabs(center
[0] - (float) joy
.wXpos
) > 0.1 * (max
[0] - min
[0]))
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]);
373 if (joy
.wButtons
& JOY_BUTTON1
)
375 if (joy
.wButtons
& JOY_BUTTON2
)
387 static char frbuf
[80] = "";
389 static double t0
= -1.;
390 double t
= glutGet(GLUT_ELAPSED_TIME
) / 1000.0;
399 glHint(GL_FOG_HINT
, GL_NICEST
);
401 glHint(GL_FOG_HINT
, GL_DONT_CARE
);
403 glEnable(GL_DEPTH_TEST
);
410 glDepthMask(GL_TRUE
);
411 glClearColor(1.0, 1.0, 1.0, 1.0);
412 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
416 gluLookAt(obs
[0], obs
[1], obs
[2],
417 obs
[0] + dir
[0], obs
[1] + dir
[1], obs
[2] + dir
[2],
420 glColor4f(1.0, 1.0, 1.0, 1.0);
422 glEnable(GL_TEXTURE_2D
);
424 glBindTexture(GL_TEXTURE_2D
, groundid
);
427 glTexCoord2fv(qt
[0]);
429 glTexCoord2fv(qt
[1]);
431 glTexCoord2fv(qt
[2]);
433 glTexCoord2fv(qt
[3]);
437 /* Subdivide the ground into a bunch of quads. This improves fog
438 * if GL_FOG_HINT != GL_NICEST
442 float dx
= 1.0, dy
= 1.0;
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
);
457 glEnable(GL_ALPHA_TEST
);
458 glAlphaFunc(GL_GEQUAL
, 0.9);
460 glBindTexture(GL_TEXTURE_2D
, treeid
);
461 for (j
= 0; j
< NUMTREE
; j
++)
462 drawtree(treepos
[j
][0], treepos
[j
][1], treepos
[j
][2]);
464 glDisable(GL_TEXTURE_2D
);
465 glDepthMask(GL_FALSE
);
466 glDisable(GL_ALPHA_TEST
);
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]);
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]);
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]);
483 glBegin(GL_TRIANGLES
);
484 for (j
= 0; j
< np
; j
++) {
485 glColor4fv(p
[j
].c
[0]);
486 glVertex3fv(p
[j
].p
[0]);
488 glColor4fv(p
[j
].c
[1]);
489 glVertex3fv(p
[j
].p
[1]);
491 glColor4fv(p
[j
].c
[2]);
492 glVertex3fv(p
[j
].p
[2]);
498 glDisable(GL_TEXTURE_2D
);
499 glDisable(GL_ALPHA_TEST
);
500 glDisable(GL_DEPTH_TEST
);
503 glMatrixMode(GL_PROJECTION
);
505 glOrtho(-0.5, 639.5, -0.5, 479.5, -1.0, 1.0);
506 glMatrixMode(GL_MODELVIEW
);
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)");
519 reshape(WIDTH
, HEIGHT
);
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
);
546 special(int key
, int x
, int y
)
566 key(unsigned char key
, int x
, int y
)
581 joyactive
= (!joyactive
);
606 XMesaSetFXmode(fullscreen
? XMESA_FX_FULLSCREEN
: XMESA_FX_WINDOW
);
607 fullscreen
= (!fullscreen
);
612 printf("NiceFog %d\n", NiceFog
);
622 GLubyte tex
[128][128][4];
624 glGenTextures(1, &groundid
);
625 glBindTexture(GL_TEXTURE_2D
, groundid
);
627 glPixelStorei(GL_UNPACK_ALIGNMENT
, 4);
628 if (!LoadRGBMipmaps("../images/s128.rgb", GL_RGB
)) {
629 fprintf(stderr
, "Error reading a texture.\n");
633 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_REPEAT
);
634 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_REPEAT
);
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
);
640 glTexEnvf(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_DECAL
);
642 glGenTextures(1, &treeid
);
643 glBindTexture(GL_TEXTURE_2D
, treeid
);
650 GLubyte
*image
= LoadRGBImage("../images/tree3.rgb", &w
, &h
, &format
);
653 fprintf(stderr
, "Error reading a texture.\n");
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))
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
));
676 if (!LoadRGBMipmaps("../images/tree2.rgba", GL_RGBA
)) {
677 fprintf(stderr
, "Error reading a texture.\n");
682 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_REPEAT
);
683 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_REPEAT
);
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
);
689 glTexEnvf(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_MODULATE
);
698 for (i
= 0; i
< NUMTREE
; i
++)
700 treepos
[i
][0] = vrnd() * TREEOUTR
* 2.0 - TREEOUTR
;
702 treepos
[i
][2] = vrnd() * TREEOUTR
* 2.0 - TREEOUTR
;
704 sqrt(treepos
[i
][0] * treepos
[i
][0] +
705 treepos
[i
][2] * treepos
[i
][2]);
706 } while ((dist
< TREEINR
) || (dist
> TREEOUTR
));
710 main(int ac
, char **av
)
715 "Fire V1.5\nWritten by David Bucciarelli (tech.hmw@plus.it)\n");
717 /* Default settings */
731 if (np
<= 0 || np
> 1000000) {
732 fprintf(stderr
, "Invalid input.\n");
739 HEIGHT
= atoi(av
[3]);
742 glutInitWindowSize(WIDTH
, HEIGHT
);
745 glutInitDisplayMode(GLUT_RGB
| GLUT_DEPTH
| GLUT_DOUBLE
);
747 if (!(win
= glutCreateWindow("Fire"))) {
748 fprintf(stderr
, "Error opening a window.\n");
752 reshape(WIDTH
, HEIGHT
);
756 glShadeModel(GL_FLAT
);
757 glEnable(GL_DEPTH_TEST
);
760 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
763 glFogi(GL_FOG_MODE
, GL_EXP
);
764 glFogfv(GL_FOG_COLOR
, fogcolor
);
765 glFogf(GL_FOG_DENSITY
, 0.1);
768 p
= (part
*) malloc(sizeof(part
) * np
);
771 for (i
= 0; i
< np
; i
++)
776 glutKeyboardFunc(key
);
777 glutSpecialFunc(special
);
778 glutDisplayFunc(drawfire
);
780 glutReshapeFunc(reshape
);