2 * This program is under the GNU GPL.
3 * Use at your own risk.
5 * written by David Bucciarelli (tech.hmw@plus.it)
24 static int fullscreen
= 1;
28 #define M_PI 3.1415926535
31 #define vinit(a,i,j,k) {\
37 #define vinit4(a,i,j,k,w) {\
45 #define vadds(a,dt,b) {\
57 #define vinter(a,dt,b,c) {\
58 (a)[0]=(dt)*(b)[0]+(1.0-dt)*(c)[0];\
59 (a)[1]=(dt)*(b)[1]+(1.0-dt)*(c)[1];\
60 (a)[2]=(dt)*(b)[2]+(1.0-dt)*(c)[2];\
63 #define clamp(a) ((a) < 0.0 ? 0.0 : ((a) < 1.0 ? (a) : 1.0))
66 (v)[0]=clamp((v)[0]);\
67 (v)[1]=clamp((v)[1]);\
68 (v)[2]=clamp((v)[2]);\
71 static int WIDTH
= 640;
72 static int HEIGHT
= 480;
75 static GLint Frames
= 0;
76 static GLint NiceFog
= 1;
98 static float treepos
[NUMTREE
][3];
100 static float black
[3] = { 0.0, 0.0, 0.0 };
101 static float blu
[3] = { 0.0, 0.2, 1.0 };
102 static float blu2
[3] = { 0.0, 1.0, 1.0 };
104 static float fogcolor
[4] = { 1.0, 1.0, 1.0, 1.0 };
106 static float q
[4][3] = {
113 static float qt
[4][2] = {
123 static float eject_r
, dt
, maxage
, eject_vy
, eject_vl
;
124 static short shadows
;
128 static int joyavailable
= 0;
129 static int joyactive
= 0;
133 static GLuint groundid
;
134 static GLuint treeid
;
136 static float obs
[3] = { 2.0, 1.0, 0.0 };
138 static float v
= 0.0;
139 static float alpha
= -90.0;
140 static float beta
= 90.0;
145 return (((float) rand()) / RAND_MAX
);
155 a
= vrnd() * 3.14159265359 * 2.0;
157 vinit(v
, sin(a
) * eject_r
* vrnd(), 0.15, cos(a
) * eject_r
* vrnd());
158 vinit(p
->p
[0], v
[0] + vrnd() * ridtri
, v
[1] + vrnd() * ridtri
,
159 v
[2] + vrnd() * ridtri
);
160 vinit(p
->p
[1], v
[0] + vrnd() * ridtri
, v
[1] + vrnd() * ridtri
,
161 v
[2] + vrnd() * ridtri
);
162 vinit(p
->p
[2], v
[0] + vrnd() * ridtri
, v
[1] + vrnd() * ridtri
,
163 v
[2] + vrnd() * ridtri
);
165 vinit(p
->v
, v
[0] * eject_vl
/ (eject_r
/ 2),
166 vrnd() * eject_vy
+ eject_vy
/ 2, v
[2] * eject_vl
/ (eject_r
/ 2));
170 vinit4(p
->c
[0], c
[0] * ((1.0 - RIDCOL
) + vrnd() * RIDCOL
),
171 c
[1] * ((1.0 - RIDCOL
) + vrnd() * RIDCOL
),
172 c
[2] * ((1.0 - RIDCOL
) + vrnd() * RIDCOL
), 1.0);
173 vinit4(p
->c
[1], c
[0] * ((1.0 - RIDCOL
) + vrnd() * RIDCOL
),
174 c
[1] * ((1.0 - RIDCOL
) + vrnd() * RIDCOL
),
175 c
[2] * ((1.0 - RIDCOL
) + vrnd() * RIDCOL
), 1.0);
176 vinit4(p
->c
[2], c
[0] * ((1.0 - RIDCOL
) + vrnd() * RIDCOL
),
177 c
[1] * ((1.0 - RIDCOL
) + vrnd() * RIDCOL
),
178 c
[2] * ((1.0 - RIDCOL
) + vrnd() * RIDCOL
), 1.0);
186 if (p
->p
[0][1] < 0.1) {
191 p
->v
[1] += AGRAV
* dt
;
193 vadds(p
->p
[0], dt
, p
->v
);
194 vadds(p
->p
[1], dt
, p
->v
);
195 vadds(p
->p
[2], dt
, p
->v
);
199 if ((p
->age
) > maxage
) {
206 vadds(p
->c
[0], fact
, blu2
);
208 p
->c
[0][3] = fact
* (maxage
- p
->age
);
210 vadds(p
->c
[1], fact
, blu2
);
212 p
->c
[1][3] = fact
* (maxage
- p
->age
);
214 vadds(p
->c
[2], fact
, blu2
);
216 p
->c
[2][3] = fact
* (maxage
- p
->age
);
221 drawtree(float x
, float y
, float z
)
224 glTexCoord2f(0.0, 0.0);
225 glVertex3f(x
- 1.5, y
+ 0.0, z
);
227 glTexCoord2f(1.0, 0.0);
228 glVertex3f(x
+ 1.5, y
+ 0.0, z
);
230 glTexCoord2f(1.0, 1.0);
231 glVertex3f(x
+ 1.5, y
+ 3.0, z
);
233 glTexCoord2f(0.0, 1.0);
234 glVertex3f(x
- 1.5, y
+ 3.0, z
);
237 glTexCoord2f(0.0, 0.0);
238 glVertex3f(x
, y
+ 0.0, z
- 1.5);
240 glTexCoord2f(1.0, 0.0);
241 glVertex3f(x
, y
+ 0.0, z
+ 1.5);
243 glTexCoord2f(1.0, 1.0);
244 glVertex3f(x
, y
+ 3.0, z
+ 1.5);
246 glTexCoord2f(0.0, 1.0);
247 glVertex3f(x
, y
+ 3.0, z
- 1.5);
256 dir
[0] = sin(alpha
* M_PI
/ 180.0);
257 dir
[2] = cos(alpha
* M_PI
/ 180.0) * sin(beta
* M_PI
/ 180.0);
258 dir
[1] = cos(beta
* M_PI
/ 180.0);
260 obs
[0] += v
* dir
[0];
261 obs
[1] += v
* dir
[1];
262 obs
[2] += v
* dir
[2];
266 printstring(void *font
, char *string
)
270 len
= (int) strlen(string
);
271 for (i
= 0; i
< len
; i
++)
272 glutBitmapCharacter(font
, string
[i
]);
276 reshape(int width
, int height
)
280 glViewport(0, 0, (GLint
) width
, (GLint
) height
);
281 glMatrixMode(GL_PROJECTION
);
283 gluPerspective(70.0, width
/ (float) height
, 0.1, 30.0);
285 glMatrixMode(GL_MODELVIEW
);
291 glColor4f(0.0, 0.0, 0.0, 0.5);
292 glRecti(40, 40, 600, 440);
294 glColor3f(1.0, 0.0, 0.0);
295 glRasterPos2i(300, 420);
296 printstring(GLUT_BITMAP_TIMES_ROMAN_24
, "Help");
298 glRasterPos2i(60, 390);
299 printstring(GLUT_BITMAP_TIMES_ROMAN_24
, "h - Togle Help");
301 glRasterPos2i(60, 360);
302 printstring(GLUT_BITMAP_TIMES_ROMAN_24
, "t - Increase particle size");
303 glRasterPos2i(60, 330);
304 printstring(GLUT_BITMAP_TIMES_ROMAN_24
, "T - Decrease particle size");
306 glRasterPos2i(60, 300);
307 printstring(GLUT_BITMAP_TIMES_ROMAN_24
, "r - Increase emission radius");
308 glRasterPos2i(60, 270);
309 printstring(GLUT_BITMAP_TIMES_ROMAN_24
, "R - Decrease emission radius");
311 glRasterPos2i(60, 240);
312 printstring(GLUT_BITMAP_TIMES_ROMAN_24
, "f - Togle Fog");
313 glRasterPos2i(60, 210);
314 printstring(GLUT_BITMAP_TIMES_ROMAN_24
, "s - Togle shadows");
315 glRasterPos2i(60, 180);
316 printstring(GLUT_BITMAP_TIMES_ROMAN_24
, "Arrow Keys - Rotate");
317 glRasterPos2i(60, 150);
318 printstring(GLUT_BITMAP_TIMES_ROMAN_24
, "a - Increase velocity");
319 glRasterPos2i(60, 120);
320 printstring(GLUT_BITMAP_TIMES_ROMAN_24
, "z - Decrease velocity");
322 glRasterPos2i(60, 90);
324 printstring(GLUT_BITMAP_TIMES_ROMAN_24
,
325 "j - Togle jostick control (Joystick control available)");
327 printstring(GLUT_BITMAP_TIMES_ROMAN_24
,
328 "(No Joystick control available)");
335 static UINT max
[2] = { 0, 0 };
336 static UINT min
[2] = { 0xffffffff, 0xffffffff }, center
[2];
340 res
= joyGetPos(JOYSTICKID1
, &joy
);
342 if (res
== JOYERR_NOERROR
) {
345 if (max
[0] < joy
.wXpos
)
347 if (min
[0] > joy
.wXpos
)
349 center
[0] = (max
[0] + min
[0]) / 2;
351 if (max
[1] < joy
.wYpos
)
353 if (min
[1] > joy
.wYpos
)
355 center
[1] = (max
[1] + min
[1]) / 2;
358 if (fabs(center
[0] - (float) joy
.wXpos
) > 0.1 * (max
[0] - min
[0]))
360 2.5 * (center
[0] - (float) joy
.wXpos
) / (max
[0] - min
[0]);
361 if (fabs(center
[1] - (float) joy
.wYpos
) > 0.1 * (max
[1] - min
[1]))
362 beta
+= 2.5 * (center
[1] - (float) joy
.wYpos
) / (max
[1] - min
[1]);
364 if (joy
.wButtons
& JOY_BUTTON1
)
366 if (joy
.wButtons
& JOY_BUTTON2
)
378 static char frbuf
[80] = "";
384 glHint(GL_FOG_HINT
, GL_NICEST
);
386 glHint(GL_FOG_HINT
, GL_DONT_CARE
);
388 glEnable(GL_DEPTH_TEST
);
395 glDepthMask(GL_TRUE
);
396 glClearColor(1.0, 1.0, 1.0, 1.0);
397 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
401 gluLookAt(obs
[0], obs
[1], obs
[2],
402 obs
[0] + dir
[0], obs
[1] + dir
[1], obs
[2] + dir
[2],
405 glColor4f(1.0, 1.0, 1.0, 1.0);
407 glEnable(GL_TEXTURE_2D
);
409 glBindTexture(GL_TEXTURE_2D
, groundid
);
412 glTexCoord2fv(qt
[0]);
414 glTexCoord2fv(qt
[1]);
416 glTexCoord2fv(qt
[2]);
418 glTexCoord2fv(qt
[3]);
422 /* Subdivide the ground into a bunch of quads. This improves fog
423 * if GL_FOG_HINT != GL_NICEST
427 float dx
= 1.0, dy
= 1.0;
429 for (y
= -DIMP
; y
< DIMP
; y
+= 1.0) {
430 for (x
= -DIMP
; x
< DIMP
; x
+= 1.0) {
431 glTexCoord2f(0, 0); glVertex3f(x
, 0, y
);
432 glTexCoord2f(1, 0); glVertex3f(x
+dx
, 0, y
);
433 glTexCoord2f(1, 1); glVertex3f(x
+dx
, 0, y
+dy
);
434 glTexCoord2f(0, 1); glVertex3f(x
, 0, y
+dy
);
442 glEnable(GL_ALPHA_TEST
);
443 glAlphaFunc(GL_GEQUAL
, 0.9);
445 glBindTexture(GL_TEXTURE_2D
, treeid
);
446 for (j
= 0; j
< NUMTREE
; j
++)
447 drawtree(treepos
[j
][0], treepos
[j
][1], treepos
[j
][2]);
449 glDisable(GL_TEXTURE_2D
);
450 glDepthMask(GL_FALSE
);
451 glDisable(GL_ALPHA_TEST
);
454 glBegin(GL_TRIANGLES
);
455 for (j
= 0; j
< np
; j
++) {
456 glColor4f(black
[0], black
[1], black
[2], p
[j
].c
[0][3]);
457 glVertex3f(p
[j
].p
[0][0], 0.1, p
[j
].p
[0][2]);
459 glColor4f(black
[0], black
[1], black
[2], p
[j
].c
[1][3]);
460 glVertex3f(p
[j
].p
[1][0], 0.1, p
[j
].p
[1][2]);
462 glColor4f(black
[0], black
[1], black
[2], p
[j
].c
[2][3]);
463 glVertex3f(p
[j
].p
[2][0], 0.1, p
[j
].p
[2][2]);
468 glBegin(GL_TRIANGLES
);
469 for (j
= 0; j
< np
; j
++) {
470 glColor4fv(p
[j
].c
[0]);
471 glVertex3fv(p
[j
].p
[0]);
473 glColor4fv(p
[j
].c
[1]);
474 glVertex3fv(p
[j
].p
[1]);
476 glColor4fv(p
[j
].c
[2]);
477 glVertex3fv(p
[j
].p
[2]);
483 glDisable(GL_TEXTURE_2D
);
484 glDisable(GL_ALPHA_TEST
);
485 glDisable(GL_DEPTH_TEST
);
488 glMatrixMode(GL_PROJECTION
);
490 glOrtho(-0.5, 639.5, -0.5, 479.5, -1.0, 1.0);
491 glMatrixMode(GL_MODELVIEW
);
494 glColor3f(1.0, 0.0, 0.0);
495 glRasterPos2i(10, 10);
496 printstring(GLUT_BITMAP_HELVETICA_18
, frbuf
);
497 glRasterPos2i(370, 470);
498 printstring(GLUT_BITMAP_HELVETICA_10
,
499 "Fire V1.5 Written by David Bucciarelli (tech.hmw@plus.it)");
504 reshape(WIDTH
, HEIGHT
);
511 GLint t
= glutGet(GLUT_ELAPSED_TIME
);
512 if (t
- T0
>= 2000) {
513 GLfloat seconds
= (t
- T0
) / 1000.0;
514 GLfloat fps
= Frames
/ seconds
;
515 sprintf(frbuf
, "Frame rate: %f", fps
);
531 special(int key
, int x
, int y
)
551 key(unsigned char key
, int x
, int y
)
566 joyactive
= (!joyactive
);
591 XMesaSetFXmode(fullscreen
? XMESA_FX_FULLSCREEN
: XMESA_FX_WINDOW
);
592 fullscreen
= (!fullscreen
);
597 printf("NiceFog %d\n", NiceFog
);
607 GLubyte tex
[128][128][4];
609 glGenTextures(1, &groundid
);
610 glBindTexture(GL_TEXTURE_2D
, groundid
);
612 glPixelStorei(GL_UNPACK_ALIGNMENT
, 4);
613 if (!LoadRGBMipmaps("../images/s128.rgb", GL_RGB
)) {
614 fprintf(stderr
, "Error reading a texture.\n");
618 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_REPEAT
);
619 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_REPEAT
);
621 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
,
622 GL_LINEAR_MIPMAP_LINEAR
);
623 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
625 glTexEnvf(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_DECAL
);
627 glGenTextures(1, &treeid
);
628 glBindTexture(GL_TEXTURE_2D
, treeid
);
635 GLubyte
*image
= LoadRGBImage("../images/tree3.rgb", &w
, &h
, &format
);
638 fprintf(stderr
, "Error reading a texture.\n");
642 for (y
= 0; y
< 128; y
++)
643 for (x
= 0; x
< 128; x
++) {
644 tex
[x
][y
][0] = image
[(y
+ x
* 128) * 3];
645 tex
[x
][y
][1] = image
[(y
+ x
* 128) * 3 + 1];
646 tex
[x
][y
][2] = image
[(y
+ x
* 128) * 3 + 2];
647 if ((tex
[x
][y
][0] == tex
[x
][y
][1]) &&
648 (tex
[x
][y
][1] == tex
[x
][y
][2]) && (tex
[x
][y
][2] == 255))
654 if ((gluerr
= gluBuild2DMipmaps(GL_TEXTURE_2D
, 4, 128, 128, GL_RGBA
,
655 GL_UNSIGNED_BYTE
, (GLvoid
*) (tex
)))) {
656 fprintf(stderr
, "GLULib%s\n", gluErrorString(gluerr
));
661 if (!LoadRGBMipmaps("../images/tree2.rgba", GL_RGBA
)) {
662 fprintf(stderr
, "Error reading a texture.\n");
667 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_REPEAT
);
668 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_REPEAT
);
670 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
,
671 GL_LINEAR_MIPMAP_LINEAR
);
672 glTexParameterf(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
674 glTexEnvf(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_MODULATE
);
683 for (i
= 0; i
< NUMTREE
; i
++)
685 treepos
[i
][0] = vrnd() * TREEOUTR
* 2.0 - TREEOUTR
;
687 treepos
[i
][2] = vrnd() * TREEOUTR
* 2.0 - TREEOUTR
;
689 sqrt(treepos
[i
][0] * treepos
[i
][0] +
690 treepos
[i
][2] * treepos
[i
][2]);
691 } while ((dist
< TREEINR
) || (dist
> TREEOUTR
));
695 main(int ac
, char **av
)
700 "Fire V1.5\nWritten by David Bucciarelli (tech.hmw@plus.it)\n");
702 /* Default settings */
719 HEIGHT
= atoi(av
[3]);
722 glutInitWindowPosition(0, 0);
723 glutInitWindowSize(WIDTH
, HEIGHT
);
726 glutInitDisplayMode(GLUT_RGB
| GLUT_DEPTH
| GLUT_DOUBLE
);
728 if (!(win
= glutCreateWindow("Fire"))) {
729 fprintf(stderr
, "Error opening a window.\n");
733 reshape(WIDTH
, HEIGHT
);
737 glShadeModel(GL_FLAT
);
738 glEnable(GL_DEPTH_TEST
);
741 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
744 glFogi(GL_FOG_MODE
, GL_EXP
);
745 glFogfv(GL_FOG_COLOR
, fogcolor
);
746 glFogf(GL_FOG_DENSITY
, 0.1);
748 p
= malloc(sizeof(part
) * np
);
750 for (i
= 0; i
< np
; i
++)
755 glutKeyboardFunc(key
);
756 glutSpecialFunc(special
);
757 glutDisplayFunc(drawfire
);
759 glutReshapeFunc(reshape
);