1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* fire --- 3D fire or rain landscape */
4 #if !defined( lint ) && !defined( SABER )
5 static const char sccsid[] = "@(#)fire.c 5.02 2001/09/26 xlockmore";
8 /* Copyright (c) E. Lassauge, 2001. */
11 * Permission to use, copy, modify, and distribute this software and its
12 * documentation for any purpose and without fee is hereby granted,
13 * provided that the above copyright notice appear in all copies and that
14 * both that copyright notice and this permission notice appear in
15 * supporting documentation.
17 * This file is provided AS IS with no warranties of any kind. The author
18 * shall have no liability with respect to the infringement of copyrights,
19 * trade secrets or any patents by this file or any part thereof. In no
20 * event will the author be liable for any lost revenue or profits or
21 * other special, indirect and consequential damages.
23 * The original code for this mode was written by David Bucciarelli
24 * (tech.hmw@plus.it) and could be found in the demo package
25 * of Mesa (Mesa-3.2/3Dfx/demos/). This mode is the result of the merge of
26 * two of the David's demos (fire and rain).
28 * Eric Lassauge (October-10-2000) <lassauge@mail.dotcom.fr>
29 * http://lassauge.free.fr/linux.html
33 * E.Lassauge - 26-Sep-2001:
34 * - add wander option and code
35 * - cleanups for xscreensaver
37 * E.Lassauge - 09-Mar-2001:
38 * - get rid of my framerate options to use showfps
40 * E.Lassauge - 12-Jan-2001:
41 * - add rain particules, selected if count=0 (no fire means rain !)
43 * E.Lassauge - 28-Nov-2000:
44 * - modified release part to add freeing of GL objects
46 * E.Lassauge - 14-Nov-2000:
47 * - use new common xpm_to_ximage function
49 * E.Lassauge - 25-Oct-2000:
50 * - add the trees (with a new resource '-trees')
51 * - corrected handling of color (textured vs untextured)
52 * - corrected handling of endiannes for the xpm files
53 * - inverted ground pixmap file
54 * - use malloc-ed tree array
56 * TSchmidt - 23-Oct-2000:
57 * - added size option like used in sproingies mode
59 * E.Lassauge - 13-Oct-2000:
60 * - when trackmouse and window is iconified (login screen): stop tracking
61 * - add pure GLX handling of framerate display (erased GLUT stuff)
62 * - made count a per screen variable and update it only if framemode
63 * - changes for no_texture an wireframe modes
64 * - change no_texture color for the ground
65 * - add freeing of texture image
66 * - misc comments and little tweakings
69 * - perhaps use a user supplied xpm for ground image (or a whatever image
70 * file using ImageMagick ?)
71 * - random number of trees ? change trees at change_fire ?
72 * - fix wireframe mode: it's too CPU intensive.
73 * - look how we can get the Wheel events (Button4&5).
77 #ifdef STANDALONE /* xscreensaver mode */
78 #define PROGCLASS "Fire"
79 #define HACK_INIT init_fire
80 #define HACK_DRAW draw_fire
81 #define HACK_RESHAPE reshape_fire
82 #define fire_opts xlockmore_opts
83 #define DEFAULTS "*delay: 10000 \n" \
87 "*showFPS: False \n" \
88 "*trackmouse: False \n" \
90 "*wireframe: False \n" \
96 #include "xlockmore.h" /* from the xscreensaver distribution */
97 #else /* !STANDALONE */
98 #include "xlock.h" /* from the xlockmore distribution */
100 #endif /* !STANDALONE */
110 #if defined( USE_XPM ) || defined( USE_XPMINC ) || defined( HAVE_XPM )
111 /* USE_XPM & USE_XPMINC in xlock mode ; HAVE_XPM in xscreensaver mode */
112 #include "xpm-ximage.h"
116 #include "../images/ground.xpm"
117 #include "../images/tree.xpm"
118 #else /* !STANDALONE */
119 #include "pixmaps/ground.xpm"
120 #include "pixmaps/tree.xpm"
121 #endif /* !STANDALONE */
122 #endif /* HAVE_XPM */
124 /* vector utility macros */
125 #define vinit(a,i,j,k) {\
131 #define vinit4(a,i,j,k,w) {\
138 #define vadds(a,dt,b) {\
139 (a)[0]+=(dt)*(b)[0];\
140 (a)[1]+=(dt)*(b)[1];\
141 (a)[2]+=(dt)*(b)[2];\
150 #define vinter(a,dt,b,c) {\
151 (a)[0]=(dt)*(b)[0]+(1.0-dt)*(c)[0];\
152 (a)[1]=(dt)*(b)[1]+(1.0-dt)*(c)[1];\
153 (a)[2]=(dt)*(b)[2]+(1.0-dt)*(c)[2];\
156 #define clamp(a) ((a) < 0.0 ? 0.0 : ((a) < 1.0 ? (a) : 1.0))
159 (v)[0]=clamp((v)[0]);\
160 (v)[1]=clamp((v)[1]);\
161 (v)[2]=clamp((v)[2]);\
164 /* Manage option vars */
165 #define DEF_TEXTURE "True"
166 #define DEF_FOG "False"
167 #define DEF_SHADOWS "True"
168 #define DEF_FRAMERATE "False"
169 #define DEF_TRACKMOUSE "False"
170 #define DEF_WANDER "True"
171 #define DEF_TREES "5"
173 static Bool do_texture;
175 static Bool do_shadows;
176 static Bool do_trackmouse;
177 static Bool do_wander;
178 static int num_trees;
179 static int frame = 0;
180 static XFontStruct *mode_font = None;
182 static XrmOptionDescRec opts[] = {
183 {(char *) "-texture", (char *) ".fire.texture", XrmoptionNoArg, (caddr_t) "on"},
184 {(char *) "+texture", (char *) ".fire.texture", XrmoptionNoArg, (caddr_t) "off"},
185 {(char *) "-fog", (char *) ".fire.fog", XrmoptionNoArg, (caddr_t) "on"},
186 {(char *) "+fog", (char *) ".fire.fog", XrmoptionNoArg, (caddr_t) "off"},
187 {(char *) "-shadows", (char *) ".fire.shadows", XrmoptionNoArg, (caddr_t) "on"},
188 {(char *) "+shadows", (char *) ".fire.shadows", XrmoptionNoArg, (caddr_t) "off"},
189 {(char *) "-trackmouse", (char *) ".fire.trackmouse", XrmoptionNoArg, (caddr_t) "on"},
190 {(char *) "+trackmouse", (char *) ".fire.trackmouse", XrmoptionNoArg, (caddr_t) "off"},
191 {(char *) "-wander", (char *) ".fire.wander", XrmoptionNoArg, (caddr_t) "on"},
192 {(char *) "+wander", (char *) ".fire.wander", XrmoptionNoArg, (caddr_t) "off"},
193 {(char *) "-trees", (char *) ".fire.trees", XrmoptionSepArg, (caddr_t) NULL},
194 {(char *) "-rain", (char *) ".fire.count", XrmoptionNoArg, (caddr_t) "0"},
198 static argtype vars[] = {
199 {(caddr_t *) & do_texture, (char *) "texture", (char *) "Texture", (char *) DEF_TEXTURE, t_Bool},
200 {(caddr_t *) & do_fog, (char *) "fog", (char *) "Fog", (char *) DEF_FOG, t_Bool},
201 {(caddr_t *) & do_shadows, (char *) "shadows", (char *) "Shadows", (char *) DEF_SHADOWS, t_Bool},
202 {(caddr_t *) & do_trackmouse, (char *) "trackmouse", (char *) "TrackMouse", (char *) DEF_TRACKMOUSE, t_Bool},
203 {(caddr_t *) & do_wander, (char *) "wander", (char *) "Wander", (char *) DEF_WANDER, t_Bool},
204 {(caddr_t *) & num_trees, (char *) "trees", (char *) "Trees", (char *) DEF_TREES, t_Int},
207 static OptionStruct desc[] = {
208 {(char *) "-/+texture", (char *) "turn on/off texturing"},
209 {(char *) "-/+fog", (char *) "turn on/off fog"},
210 {(char *) "-/+shadows", (char *) "turn on/off shadows"},
211 {(char *) "-/+trackmouse", (char *) "turn on/off the tracking of the mouse"},
212 {(char *) "-/+wander", (char *) "turn on/off wandering"},
213 {(char *) "-trees num", (char *) "number of trees (0 disables)"},
216 ModeSpecOpt fire_opts =
217 { sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc };
220 ModStruct fire_description =
221 { "fire", "init_fire", "draw_fire", "release_fire",
222 "draw_fire", "change_fire", (char *) NULL, &fire_opts,
223 10000, 800, 1, 400, 64, 1.0, "",
224 "Shows a 3D fire-like image", 0, NULL
226 #endif /* USE_MODULES */
229 #define TREEINR 2.5 /* tree min distance */
230 #define TREEOUTR 8.0 /* tree max distance */
231 #define FRAME 50 /* frame count interval */
232 #define DIMP 20.0 /* dimension of ground */
233 #define DIMTP 16.0 /* dimension of ground texture */
235 #define RIDCOL 0.4 /* factor for color blending */
237 #define AGRAV -9.8 /* gravity */
239 #define NUMPART 7500 /* rain particles */
241 /* fire particle struct */
249 /* rain particle struct */
260 static float black[3] = { 0.0, 0.0, 0.0 }; /* shadow color */
261 static float partcol1[3] = { 1.0, 0.2, 0.0 }; /* initial color: red-ish */
262 static float partcol2[3] = { 1.0, 1.0, 0.0 }; /* blending color: yellow-ish */
263 static float fogcolor[4] = { 0.9, 0.9, 1.0, 1.0 };
266 static float q[4][3] = {
274 static float qt[4][2] = {
281 /* default values for observer */
282 static const float DEF_OBS[3] = { 2.0f, 1.0f, 0.0f };
284 #define DEF_ALPHA -90.0
285 #define DEF_BETA 90.0
292 /* the mode struct, contains all per screen variables */
294 GLint WIDTH, HEIGHT; /* display dimensions */
295 GLXContext *glx_context;
297 int np; /* number of fire particles : set it through 'count' resource */
298 float eject_r; /* emission radius */
299 float dt, maxage, eject_vy, eject_vl;
300 float ridtri; /* fire particle size */
301 Bool shadows; /* misc booleans: set them through specific resources */
304 part *p; /* fire particles array */
305 rain *r; /* rain particles array */
307 XImage *gtexture; /* ground texture image bits */
308 XImage *ttexture; /* tree texture image bits */
309 GLuint groundid; /* ground texture id: GL world */
310 GLuint treeid; /* tree texture id: GL world */
311 GLuint fontbase; /* fontbase id: GL world */
313 int num_trees; /* number of trees: set it through 'trees' resource */
314 treestruct *treepos; /* trees positions: float treepos[num_trees][3] */
316 float min[3]; /* raining area */
319 float obs[3]; /* observer coordinates */
320 float dir[3]; /* view direction */
321 float v; /* observer velocity */
322 float alpha; /* observer angles */
326 /* array of firestruct indexed by screen number */
327 static firestruct *fire = (firestruct *) NULL;
330 *-----------------------------------------------------------------------------
331 *-----------------------------------------------------------------------------
333 *-----------------------------------------------------------------------------
334 *-----------------------------------------------------------------------------
337 /* utility function for the rain particles */
338 static float gettimerain(void)
341 /* Oh yeah, *that's* portable! WTF. */
343 * I really thought clock() was standard ... EL
344 * I found this on the net:
345 * The clock() function conforms to ISO/IEC 9899:1990 (``ISO C89'')
348 static clock_t told= (clock_t)0;
357 return (0.0125 + ris/(float)CLOCKS_PER_SEC);
364 static float vrnd(void)
366 return ((float) LRAND() / (float) MAXRAND);
369 /* initialise new fire particle */
370 static void setnewpart(firestruct * fs, part * p)
376 a = vrnd() * M_PI * 2.0;
378 vinit(vi, sin(a) * fs->eject_r * vrnd(), 0.15, cos(a) * fs->eject_r * vrnd());
379 vinit(p->p[0], vi[0] + vrnd() * fs->ridtri, vi[1] + vrnd() * fs->ridtri, vi[2] + vrnd() * fs->ridtri);
380 vinit(p->p[1], vi[0] + vrnd() * fs->ridtri, vi[1] + vrnd() * fs->ridtri, vi[2] + vrnd() * fs->ridtri);
381 vinit(p->p[2], vi[0] + vrnd() * fs->ridtri, vi[1] + vrnd() * fs->ridtri, vi[2] + vrnd() * fs->ridtri);
383 vinit(p->v, vi[0] * fs->eject_vl / (fs->eject_r / 2),
384 vrnd() * fs->eject_vy + fs->eject_vy / 2,
385 vi[2] * fs->eject_vl / (fs->eject_r / 2));
389 vinit4(p->c[0], c[0] * ((1.0 - RIDCOL) + vrnd() * RIDCOL),
390 c[1] * ((1.0 - RIDCOL) + vrnd() * RIDCOL),
391 c[2] * ((1.0 - RIDCOL) + vrnd() * RIDCOL), 1.0);
392 vinit4(p->c[1], c[0] * ((1.0 - RIDCOL) + vrnd() * RIDCOL),
393 c[1] * ((1.0 - RIDCOL) + vrnd() * RIDCOL),
394 c[2] * ((1.0 - RIDCOL) + vrnd() * RIDCOL), 1.0);
395 vinit4(p->c[2], c[0] * ((1.0 - RIDCOL) + vrnd() * RIDCOL),
396 c[1] * ((1.0 - RIDCOL) + vrnd() * RIDCOL),
397 c[2] * ((1.0 - RIDCOL) + vrnd() * RIDCOL), 1.0);
400 /* initialise new rain particle */
401 static void setnewrain(firestruct * fs, rain * r)
405 vinit(r->acc,0.0f,-0.98f,0.0f);
406 vinit(r->vel,0.0f,0.0f,0.0f);
410 vinit(r->oldpos,fs->min[0]+(fs->max[0]-fs->min[0])*vrnd(),
411 fs->max[1]+0.2f*fs->max[1]*vrnd(),
412 fs->min[2]+(fs->max[2]-fs->min[2])*vrnd());
413 vequ(r->pos,r->oldpos);
414 vadds(r->oldpos,-(r->partLength),r->vel);
416 r->pos[1]=(fs->max[1]-fs->min[1])*vrnd()+fs->min[1];
417 r->oldpos[1]=r->pos[1]-r->partLength*r->vel[1];
420 /* set fire particle values */
421 static void setpart(firestruct * fs, part * p)
425 if (p->p[0][1] < 0.1) {
430 p->v[1] += AGRAV * fs->dt;
432 vadds(p->p[0], fs->dt, p->v);
433 vadds(p->p[1], fs->dt, p->v);
434 vadds(p->p[2], fs->dt, p->v);
438 if ((p->age) > fs->maxage) {
439 vequ(p->c[0], partcol2);
440 vequ(p->c[1], partcol2);
441 vequ(p->c[2], partcol2);
443 fact = 1.0 / fs->maxage;
444 vadds(p->c[0], fact, partcol2);
446 p->c[0][3] = fact * (fs->maxage - p->age);
448 vadds(p->c[1], fact, partcol2);
450 p->c[1][3] = fact * (fs->maxage - p->age);
452 vadds(p->c[2], fact, partcol2);
454 p->c[2][3] = fact * (fs->maxage - p->age);
458 /* set rain particle values */
459 static void setpartrain(firestruct * fs, rain * r, float dt)
463 vadds(r->vel,dt,r->acc);
464 vadds(r->pos,dt,r->vel);
466 if(r->pos[0]<fs->min[0])
467 r->pos[0]=fs->max[0]-(fs->min[0]-r->pos[0]);
468 if(r->pos[2]<fs->min[2])
469 r->pos[2]=fs->max[2]-(fs->min[2]-r->pos[2]);
471 if(r->pos[0]>fs->max[0])
472 r->pos[0]=fs->min[0]+(r->pos[0]-fs->max[0]);
473 if(r->pos[2]>fs->max[2])
474 r->pos[2]=fs->min[2]+(r->pos[2]-fs->max[2]);
476 vequ(r->oldpos,r->pos);
477 vadds(r->oldpos,-(r->partLength),r->vel);
478 if(r->pos[1]<fs->min[1])
483 static void drawtree(float x, float y, float z)
486 glTexCoord2f(0.0,0.0);
487 glVertex3f(x-1.5,y+0.0,z);
489 glTexCoord2f(1.0,0.0);
490 glVertex3f(x+1.5,y+0.0,z);
492 glTexCoord2f(1.0,1.0);
493 glVertex3f(x+1.5,y+3.0,z);
495 glTexCoord2f(0.0,1.0);
496 glVertex3f(x-1.5,y+3.0,z);
499 glTexCoord2f(0.0,0.0);
500 glVertex3f(x,y+0.0,z-1.5);
502 glTexCoord2f(1.0,0.0);
503 glVertex3f(x,y+0.0,z+1.5);
505 glTexCoord2f(1.0,1.0);
506 glVertex3f(x,y+3.0,z+1.5);
508 glTexCoord2f(0.0,1.0);
509 glVertex3f(x,y+3.0,z-1.5);
515 /* calculate observer position : modified only if trackmouse is used */
516 static void calcposobs(firestruct * fs)
518 fs->dir[0] = sin(fs->alpha * M_PI / 180.0);
520 cos(fs->alpha * M_PI / 180.0) * sin(fs->beta * M_PI / 180.0);
521 fs->dir[1] = cos(fs->beta * M_PI / 180.0);
523 fs->obs[0] += fs->v * fs->dir[0];
524 fs->obs[1] += fs->v * fs->dir[1];
525 fs->obs[2] += fs->v * fs->dir[2];
529 vinit(fs->min,fs->obs[0]-7.0f,-0.2f,fs->obs[2]-7.0f);
530 vinit(fs->max,fs->obs[0]+7.0f,8.0f,fs->obs[2]+7.0f);
534 /* track the mouse in a joystick manner : not perfect but it works */
535 static void trackmouse(ModeInfo * mi)
537 firestruct *fs = &fire[MI_SCREEN(mi)];
538 /* we keep static values (not per screen) for the mouse stuff: in general you have only one mouse :-> */
539 static int max[2] = { 0, 0 };
540 static int min[2] = { 0x7fffffff, 0x7fffffff }, center[2];
545 (void) XQueryPointer(MI_DISPLAY(mi), MI_WINDOW(mi),
546 &r, &c, &rx, &ry, &cx, &cy, &m);
552 center[0] = (max[0] + min[0]) / 2;
558 center[1] = (max[1] + min[1]) / 2;
560 if (fabs(center[0] - (float) cx) > 0.1 * (max[0] - min[0]))
561 fs->alpha += 2.5 * (center[0] - (float) cx) / (max[0] - min[0]);
562 if (fabs(center[1] - (float) cy) > 0.1 * (max[1] - min[1]))
563 fs->beta += 2.5 * (center[1] - (float) cy) / (max[1] - min[1]);
565 /* oops: can't get those buttons */
573 /* initialise textures */
574 static void inittextures(ModeInfo * mi)
576 firestruct *fs = &fire[MI_SCREEN(mi)];
578 #if defined( I_HAVE_XPM )
581 glGenTextures(1, &fs->groundid);
582 #ifdef HAVE_GLBINDTEXTURE
583 glBindTexture(GL_TEXTURE_2D, fs->groundid);
584 #endif /* HAVE_GLBINDTEXTURE */
586 if ((fs->gtexture = xpm_to_ximage(MI_DISPLAY(mi), MI_VISUAL(mi),
587 MI_COLORMAP(mi), ground)) == None) {
588 (void) fprintf(stderr, "Error reading the ground texture.\n");
589 glDeleteTextures(1, &fs->groundid);
596 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
598 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
599 fs->gtexture->width, fs->gtexture->height, 0,
601 /* GL_UNSIGNED_BYTE, */
602 GL_UNSIGNED_INT_8_8_8_8_REV,
604 check_gl_error("texture");
606 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
607 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
609 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
610 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
612 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
616 glGenTextures(1, &fs->treeid);
617 #ifdef HAVE_GLBINDTEXTURE
618 glBindTexture(GL_TEXTURE_2D,fs->treeid);
619 #endif /* HAVE_GLBINDTEXTURE */
620 if ((fs->ttexture = xpm_to_ximage(MI_DISPLAY(mi), MI_VISUAL(mi),
621 MI_COLORMAP(mi), tree)) == None) {
622 (void)fprintf(stderr,"Error reading tree texture.\n");
623 glDeleteTextures(1, &fs->treeid);
630 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
631 fs->ttexture->width, fs->ttexture->height, 0,
633 /* GL_UNSIGNED_BYTE, */
634 GL_UNSIGNED_INT_8_8_8_8_REV,
636 check_gl_error("texture");
638 glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
639 glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
641 glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
642 glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
644 glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);
649 fs->groundid = 0; /* default textures */
652 #else /* !I_HAVE_XPM */
654 fs->groundid = 0; /* default textures */
656 #endif /* !I_HAVE_XPM */
659 /* init tree array and positions */
660 static Bool inittree(ModeInfo * mi)
662 firestruct *fs = &fire[MI_SCREEN(mi)];
666 /* allocate treepos array */
667 if ((fs->treepos = (treestruct *) malloc(fs->num_trees *
668 sizeof(treestruct))) == NULL) {
671 /* initialise positions */
672 for(i=0;i<fs->num_trees;i++)
674 fs->treepos[i].x =vrnd()*TREEOUTR*2.0-TREEOUTR;
675 fs->treepos[i].y =0.0;
676 fs->treepos[i].z =vrnd()*TREEOUTR*2.0-TREEOUTR;
677 dist=sqrt(fs->treepos[i].x *fs->treepos[i].x +fs->treepos[i].z *fs->treepos[i].z );
678 } while((dist<TREEINR) || (dist>TREEOUTR));
683 *-----------------------------------------------------------------------------
684 *-----------------------------------------------------------------------------
686 *-----------------------------------------------------------------------------
687 *-----------------------------------------------------------------------------
691 static void Reshape(ModeInfo * mi)
693 void reshape_fire(ModeInfo * mi, int width, int height)
697 firestruct *fs = &fire[MI_SCREEN(mi)];
698 int size = MI_SIZE(mi);
700 /* Viewport is specified size if size >= MINSIZE && size < screensize */
702 fs->WIDTH = MI_WIDTH(mi);
703 fs->HEIGHT = MI_HEIGHT(mi);
704 } else if (size < MINSIZE) {
706 fs->HEIGHT = MINSIZE;
708 fs->WIDTH = (size > MI_WIDTH(mi)) ? MI_WIDTH(mi) : size;
709 fs->HEIGHT = (size > MI_HEIGHT(mi)) ? MI_HEIGHT(mi) : size;
711 glViewport((MI_WIDTH(mi) - fs->WIDTH) / 2, (MI_HEIGHT(mi) - fs->HEIGHT) / 2, fs->WIDTH, fs->HEIGHT);
712 glMatrixMode(GL_PROJECTION);
714 gluPerspective(70.0, fs->WIDTH / (float) fs->HEIGHT, 0.1, 30.0);
716 glMatrixMode(GL_MODELVIEW);
720 static void DrawFire(ModeInfo * mi)
723 firestruct *fs = &fire[MI_SCREEN(mi)];
724 Bool wire = MI_IS_WIREFRAME(mi);
726 if (do_trackmouse && !MI_IS_ICONIC(mi))
733 # define SINOID(SCALE,SIZE) \
734 ((((1 + sin((frame * (SCALE)) / 2 * M_PI)) / 2.0) * (SIZE)) - (SIZE)/2)
736 x = SINOID(0.031, 0.85);
737 y = SINOID(0.017, 0.25);
738 z = SINOID(0.023, 0.85);
740 fs->obs[0] = x + DEF_OBS[0];
741 fs->obs[1] = y + DEF_OBS[1];
742 fs->obs[2] = z + DEF_OBS[2];
747 glEnable(GL_DEPTH_TEST);
754 glDepthMask(GL_TRUE);
755 glClearColor(0.5, 0.5, 0.8, 1.0); /* sky in the distance */
756 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
760 gluLookAt(fs->obs[0], fs->obs[1], fs->obs[2],
761 fs->obs[0] + fs->dir[0], fs->obs[1] + fs->dir[1],
762 fs->obs[2] + fs->dir[2], 0.0, 1.0, 0.0);
765 glEnable(GL_TEXTURE_2D);
767 /* draw ground using the computed texture */
769 glColor4f(1.0,1.0,1.0,1.0); /* white to get texture in it's true color */
770 #ifdef HAVE_GLBINDTEXTURE
771 glBindTexture(GL_TEXTURE_2D, fs->groundid);
772 #endif /* HAVE_GLBINDTEXTURE */
775 glColor4f(0.54, 0.27, 0.07, 1.0); /* untextured ground color */
777 glTexCoord2fv(qt[0]);
779 glTexCoord2fv(qt[1]);
781 glTexCoord2fv(qt[2]);
783 glTexCoord2fv(qt[3]);
787 glAlphaFunc(GL_GEQUAL, 0.9);
790 /* here do_texture IS True - and color used is white */
791 glEnable(GL_ALPHA_TEST);
792 #ifdef HAVE_GLBINDTEXTURE
793 glBindTexture(GL_TEXTURE_2D,fs->treeid);
794 #endif /* HAVE_GLBINDTEXTURE */
795 for(j=0;j<fs->num_trees;j++)
796 drawtree(fs->treepos[j].x ,fs->treepos[j].y ,fs->treepos[j].z );
797 glDisable(GL_ALPHA_TEST);
799 glDisable(GL_TEXTURE_2D);
800 glDepthMask(GL_FALSE);
803 /* draw shadows with black color */
804 glBegin(wire ? GL_LINE_STRIP : GL_TRIANGLES);
805 for (j = 0; j < fs->np; j++) {
806 glColor4f(black[0], black[1], black[2], fs->p[j].c[0][3]);
807 glVertex3f(fs->p[j].p[0][0], 0.1, fs->p[j].p[0][2]);
809 glColor4f(black[0], black[1], black[2], fs->p[j].c[1][3]);
810 glVertex3f(fs->p[j].p[1][0], 0.1, fs->p[j].p[1][2]);
812 glColor4f(black[0], black[1], black[2], fs->p[j].c[2][3]);
813 glVertex3f(fs->p[j].p[2][0], 0.1, fs->p[j].p[2][2]);
818 glBegin(wire ? GL_LINE_STRIP : GL_TRIANGLES);
819 for (j = 0; j < fs->np; j++) {
820 /* draw particles: colors are computed in setpart */
821 glColor4fv(fs->p[j].c[0]);
822 glVertex3fv(fs->p[j].p[0]);
824 glColor4fv(fs->p[j].c[1]);
825 glVertex3fv(fs->p[j].p[1]);
827 glColor4fv(fs->p[j].c[2]);
828 glVertex3fv(fs->p[j].p[2]);
830 setpart(fs, &fs->p[j]);
834 /* draw rain particles if no fire particles */
837 float timeused = gettimerain();
838 glDisable(GL_TEXTURE_2D);
839 glShadeModel(GL_SMOOTH);
841 for (j = 0; j < NUMPART; j++) {
842 glColor4f(0.7f,0.95f,1.0f,0.0f);
843 glVertex3fv(fs->r[j].oldpos);
844 glColor4f(0.3f,0.7f,1.0f,1.0f);
845 glVertex3fv(fs->r[j].pos);
846 setpartrain(fs, &fs->r[j],timeused);
849 glShadeModel(GL_FLAT);
852 glDisable(GL_TEXTURE_2D);
853 glDisable(GL_ALPHA_TEST);
854 glDisable(GL_DEPTH_TEST);
857 /* manage framerate display */
858 if (MI_IS_FPS(mi)) do_fps (mi);
863 static Bool Init(ModeInfo * mi)
866 firestruct *fs = &fire[MI_SCREEN(mi)];
868 /* default settings */
869 fs->eject_r = 0.1 + NRAND(10) * 0.03;
873 fs->ridtri = 0.1 + NRAND(10) * 0.005;
874 fs->maxage = 1.0 / fs->dt;
875 vinit(fs->obs, DEF_OBS[0], DEF_OBS[1], DEF_OBS[2]);
877 fs->alpha = DEF_ALPHA;
880 /* initialise texture stuff */
885 fs->ttexture = (XImage*) NULL;
886 fs->gtexture = (XImage*) NULL;
889 if (MI_IS_DEBUG(mi)) {
890 (void) fprintf(stderr,
891 "%s:\n\tnum_part=%d\n\ttrees=%d\n\tfog=%s\n\tshadows=%s\n\teject_r=%.3f\n\tridtri=%.3f\n",
895 fs->fog ? "on" : "off",
896 fs->shadows ? "on" : "off",
897 fs->eject_r, fs->ridtri);
900 glShadeModel(GL_FLAT);
901 glEnable(GL_DEPTH_TEST);
903 /* makes particles blend with background */
904 if (!MI_IS_WIREFRAME(mi)||(!fs->np))
907 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
912 glFogi(GL_FOG_MODE, GL_EXP);
913 glFogfv(GL_FOG_COLOR, fogcolor);
914 glFogf(GL_FOG_DENSITY, 0.03);
915 glHint(GL_FOG_HINT, GL_NICEST);
917 /* initialise particles and trees */
918 for (i = 0; i < fs->np; i++) {
919 setnewpart(fs, &(fs->p[i]));
927 /* if no fire particles then initialise rain particles */
930 vinit(fs->min,-7.0f,-0.2f,-7.0f);
931 vinit(fs->max,7.0f,8.0f,7.0f);
932 for (i = 0; i < NUMPART; i++) {
933 setnewrain(fs, &(fs->r[i]));
941 *-----------------------------------------------------------------------------
942 *-----------------------------------------------------------------------------
944 *-----------------------------------------------------------------------------
945 *-----------------------------------------------------------------------------
950 free_fire(firestruct *fs)
952 if (mode_font != None && fs->fontbase != None) {
953 glDeleteLists(fs->fontbase, mode_font->max_char_or_byte2 -
954 mode_font->min_char_or_byte2 + 1);
959 (void) free((void *) fs->p);
960 fs->p = (part *) NULL;
963 (void) free((void *) fs->r);
964 fs->r = (rain *) NULL;
966 if (fs->treepos != NULL) {
967 (void) free((void *) fs->treepos);
968 fs->treepos = (treestruct *) NULL;
970 if (fs->ttexture != None) {
971 glDeleteTextures(1, &fs->treeid);
972 XDestroyImage(fs->ttexture);
975 if (fs->gtexture != None) {
976 glDeleteTextures(1, &fs->groundid);
977 XDestroyImage(fs->gtexture);
983 *-----------------------------------------------------------------------------
984 * Initialize fire. Called each time the window changes.
985 *-----------------------------------------------------------------------------
989 init_fire(ModeInfo * mi)
993 /* allocate the main fire table if needed */
995 if ((fire = (firestruct *) calloc(MI_NUM_SCREENS(mi),
996 sizeof(firestruct))) == NULL)
1000 /* initialise the per screen fire structure */
1001 fs = &fire[MI_SCREEN(mi)];
1002 fs->np = MI_COUNT(mi);
1004 fs->shadows = do_shadows;
1005 /* initialise fire particles if any */
1006 if ((fs->np)&&(fs->p == NULL)) {
1007 if ((fs->p = (part *) calloc(fs->np, sizeof(part))) == NULL) {
1012 else if (fs->r == NULL) {
1013 /* initialise rain particles if no fire particles */
1014 if ((fs->r = (rain *) calloc(NUMPART, sizeof(part))) == NULL) {
1020 /* check tree number */
1022 fs->num_trees = (num_trees<MAX_TREES)?num_trees:MAX_TREES;
1026 /* check wander/trackmouse */
1027 if (do_trackmouse && do_wander) do_wander = 0;
1029 /* xlock GL stuff */
1030 if ((fs->glx_context = init_GL(mi)) != NULL) {
1033 Reshape(mi); /* xlock mode */
1035 reshape_fire(mi,MI_WIDTH(mi),MI_HEIGHT(mi)); /* xscreensaver mode */
1037 glDrawBuffer(GL_BACK);
1048 *-----------------------------------------------------------------------------
1049 * Called by the mainline code periodically to update the display.
1050 *-----------------------------------------------------------------------------
1052 void draw_fire(ModeInfo * mi)
1054 firestruct *fs = &fire[MI_SCREEN(mi)];
1056 Display *display = MI_DISPLAY(mi);
1057 Window window = MI_WINDOW(mi);
1059 MI_IS_DRAWN(mi) = True;
1061 if (!fs->glx_context)
1064 glXMakeCurrent(display, window, *(fs->glx_context));
1067 Reshape(mi); /* xlock mode */
1069 reshape_fire(mi,MI_WIDTH(mi),MI_HEIGHT(mi)); /* xscreensaver mode */
1073 glXSwapBuffers(display, window);
1078 *-----------------------------------------------------------------------------
1079 * The display is being taken away from us. Free up malloc'ed
1080 * memory and X resources that we've alloc'ed. Only called
1081 * once, we must zap everything for every screen.
1082 *-----------------------------------------------------------------------------
1085 void release_fire(ModeInfo * mi)
1089 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
1090 free_fire(&fire[screen]);
1091 (void) free((void *) fire);
1092 fire = (firestruct *) NULL;
1094 if (mode_font != None)
1096 /* only free-ed when there are no more screens used */
1097 XFreeFont(MI_DISPLAY(mi), mode_font);
1103 void change_fire(ModeInfo * mi)
1105 firestruct *fs = &fire[MI_SCREEN(mi)];
1107 if (!fs->glx_context)
1110 glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(fs->glx_context));
1112 /* if available, randomly change some values */
1114 fs->fog = LRAND() & 1;
1116 fs->shadows = LRAND() & 1;
1117 /* reset observer position */
1119 vinit(fs->obs, DEF_OBS[0], DEF_OBS[1], DEF_OBS[2]);
1121 /* particle randomisation */
1122 fs->eject_r = 0.1 + NRAND(10) * 0.03;
1123 fs->ridtri = 0.1 + NRAND(10) * 0.005;
1125 if (MI_IS_DEBUG(mi)) {
1126 (void) fprintf(stderr,
1127 "%s:\n\tnum_part=%d\n\ttrees=%d\n\tfog=%s\n\tshadows=%s\n\teject_r=%.3f\n\tridtri=%.3f\n",
1131 fs->fog ? "on" : "off",
1132 fs->shadows ? "on" : "off",
1133 fs->eject_r, fs->ridtri);
1136 #endif /* MODE_fire */