"Fossies" - the Fresh Open Source Software Archive

Member "xlockmore-5.59/modes/glx/fire.c" (15 Sep 2019, 30657 Bytes) of package /linux/misc/xlockmore-5.59.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "fire.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 5.58_vs_5.59.

    1 /* -*- Mode: C; tab-width: 4 -*- */
    2 /* fire --- 3D fire or rain landscape */
    3 
    4 #if 0
    5 static const char sccsid[] = "@(#)fire.c    5.02 2001/09/26 xlockmore";
    6 #endif
    7 
    8 /* Copyright (c) E. Lassauge, 2001. */
    9 
   10 /*
   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.
   16  *
   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.
   22  *
   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).
   27  *
   28  * Eric Lassauge  (October-10-2000) <lassauge AT users.sourceforge.net>
   29  *                  http://lassauge.free.fr/linux.html
   30  *
   31  * REVISION HISTORY:
   32  *
   33  * E.Lassauge - 26-Sep-2001:
   34  *      - add wander option and code
   35  *      - cleanups for xscreensaver
   36  *
   37  * E.Lassauge - 09-Mar-2001:
   38  *      - get rid of my framerate options to use showfps
   39  *
   40  * E.Lassauge - 12-Jan-2001:
   41  *      - add rain particules, selected if count=0 (no fire means rain !)
   42  *
   43  * E.Lassauge - 28-Nov-2000:
   44  *      - modified release part to add freeing of GL objects
   45  *
   46  * E.Lassauge - 14-Nov-2000:
   47  *      - use new common xpm_to_ximage function
   48  *
   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
   55  *
   56  * TSchmidt - 23-Oct-2000:
   57  *  - added size option like used in sproingies mode
   58  *
   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
   67  *
   68  * TODO:
   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).
   74  */
   75 
   76 
   77 #ifdef STANDALONE   /* xscreensaver mode */
   78 # define MODE_fire
   79 # define DEFAULTS   "*delay:     10000 \n" \
   80         "*count:    800 \n" \
   81         "*size:           0 \n" \
   82         "*showFPS:    False \n" \
   83         "*wireframe:  False \n" \
   84 
   85 # define fire_handle_event 0
   86 # include "xlockmore.h"     /* from the xscreensaver distribution */
   87 #else               /* !STANDALONE */
   88 # include "xlock.h"     /* from the xlockmore distribution */
   89 # include "visgl.h"
   90 #endif              /* !STANDALONE */
   91 
   92 #ifdef MODE_fire
   93 
   94 #define MINSIZE 32
   95 
   96 #include <GL/gl.h>
   97 #include <GL/glu.h>
   98 
   99 #ifdef HAVE_XPM
  100 #include "xpm-ximage.h"
  101 
  102 #ifdef STANDALONE
  103 #include "../images/ground.xpm"
  104 #include "../images/tree.xpm"
  105 #else /* !STANDALONE */
  106 #include "pixmaps/ground.xpm"
  107 #include "pixmaps/tree.xpm"
  108 #endif /* !STANDALONE */
  109 #endif /* HAVE_XPM */
  110 
  111 /* vector utility macros */
  112 #define vinit(a,i,j,k) {\
  113   (a)[0]=i;\
  114   (a)[1]=j;\
  115   (a)[2]=k;\
  116 }
  117 
  118 #define vinit4(a,i,j,k,w) {\
  119   (a)[0]=i;\
  120   (a)[1]=j;\
  121   (a)[2]=k;\
  122   (a)[3]=w;\
  123 }
  124 
  125 #define vadds(a,dt,b) {\
  126   (a)[0]+=(dt)*(b)[0];\
  127   (a)[1]+=(dt)*(b)[1];\
  128   (a)[2]+=(dt)*(b)[2];\
  129 }
  130 
  131 #define vequ(a,b) {\
  132   (a)[0]=(b)[0];\
  133   (a)[1]=(b)[1];\
  134   (a)[2]=(b)[2];\
  135 }
  136 
  137 #define vinter(a,dt,b,c) {\
  138   (a)[0]=(dt)*(b)[0]+(1.0-dt)*(c)[0];\
  139   (a)[1]=(dt)*(b)[1]+(1.0-dt)*(c)[1];\
  140   (a)[2]=(dt)*(b)[2]+(1.0-dt)*(c)[2];\
  141 }
  142 
  143 #define clamp(a)        ((a) < 0.0 ? 0.0 : ((a) < 1.0 ? (a) : 1.0))
  144 
  145 #define vclamp(v) {\
  146   (v)[0]=clamp((v)[0]);\
  147   (v)[1]=clamp((v)[1]);\
  148   (v)[2]=clamp((v)[2]);\
  149 }
  150 
  151 /* Manage option vars */
  152 #define DEF_TEXTURE "True"
  153 #define DEF_FOG     "False"
  154 #define DEF_SHADOWS "True"
  155 #define DEF_FRAMERATE   "False"
  156 #define DEF_TRACKMOUSE  "False"
  157 #define DEF_WANDER  "True"
  158 #define DEF_TREES   "5"
  159 #define MAX_TREES   20
  160 static Bool do_texture;
  161 static Bool do_fog;
  162 static Bool do_shadows;
  163 static Bool do_trackmouse;
  164 static Bool do_wander;
  165 static int num_trees;
  166 static int frame = 0;
  167 static XFontStruct *mode_font = None;
  168 
  169 static XrmOptionDescRec opts[] = {
  170     {(char *) "-texture", (char *) ".fire.texture", XrmoptionNoArg, (caddr_t) "on"},
  171     {(char *) "+texture", (char *) ".fire.texture", XrmoptionNoArg, (caddr_t) "off"},
  172     {(char *) "-fog", (char *) ".fire.fog", XrmoptionNoArg, (caddr_t) "on"},
  173     {(char *) "+fog", (char *) ".fire.fog", XrmoptionNoArg, (caddr_t) "off"},
  174     {(char *) "-shadows", (char *) ".fire.shadows", XrmoptionNoArg, (caddr_t) "on"},
  175     {(char *) "+shadows", (char *) ".fire.shadows", XrmoptionNoArg, (caddr_t) "off"},
  176     {(char *) "-trackmouse", (char *) ".fire.trackmouse", XrmoptionNoArg, (caddr_t) "on"},
  177     {(char *) "+trackmouse", (char *) ".fire.trackmouse", XrmoptionNoArg, (caddr_t) "off"},
  178     {(char *) "-wander", (char *) ".fire.wander", XrmoptionNoArg, (caddr_t) "on"},
  179     {(char *) "+wander", (char *) ".fire.wander", XrmoptionNoArg, (caddr_t) "off"},
  180     {(char *) "-trees", (char *) ".fire.trees", XrmoptionSepArg, (caddr_t) NULL},
  181 
  182 };
  183 
  184 static argtype vars[] = {
  185     {(void *) & do_texture, (char *) "texture", (char *) "Texture", (char *) DEF_TEXTURE, t_Bool},
  186     {(void *) & do_fog, (char *) "fog", (char *) "Fog", (char *) DEF_FOG, t_Bool},
  187     {(void *) & do_shadows, (char *) "shadows", (char *) "Shadows", (char *) DEF_SHADOWS, t_Bool},
  188     {(void *) & do_trackmouse, (char *) "trackmouse", (char *) "TrackMouse", (char *) DEF_TRACKMOUSE, t_Bool},
  189     {(void *) & do_wander, (char *) "wander", (char *) "Wander", (char *) DEF_WANDER, t_Bool},
  190     {(void *) & num_trees, (char *) "trees", (char *) "Trees", (char *) DEF_TREES, t_Int},
  191 };
  192 
  193 static OptionStruct desc[] = {
  194     {(char *) "-/+texture", (char *) "turn on/off texturing"},
  195     {(char *) "-/+fog", (char *) "turn on/off fog"},
  196     {(char *) "-/+shadows", (char *) "turn on/off shadows"},
  197     {(char *) "-/+trackmouse", (char *) "turn on/off the tracking of the mouse"},
  198     {(char *) "-/+wander", (char *) "turn on/off wandering"},
  199     {(char *) "-trees num", (char *) "number of trees (0 disables)"},
  200 };
  201 
  202 ENTRYPOINT ModeSpecOpt fire_opts =
  203  { sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc };
  204 
  205 #ifdef USE_MODULES
  206 ModStruct fire_description =
  207     { "fire", "init_fire", "draw_fire", "release_fire",
  208     "draw_fire", "change_fire", "free_fire", &fire_opts,
  209     10000, 800, 1, 0, 64, 1.0, "",
  210     "Shows a 3D fire-like image", 0, NULL
  211 };
  212 #endif /* USE_MODULES */
  213 
  214 /* misc defines */
  215 #define TREEINR     2.5 /* tree min distance */
  216 #define TREEOUTR    8.0 /* tree max distance */
  217 #define FRAME       50  /* frame count interval */
  218 #define DIMP        20.0    /* dimension of ground */
  219 #define DIMTP       16.0    /* dimension of ground texture */
  220 
  221 #define RIDCOL      0.4 /* factor for color blending */
  222 
  223 #define AGRAV       -9.8    /* gravity */
  224 
  225 #define NUMPART     7500    /* rain particles */
  226 
  227 /* fire particle struct */
  228 typedef struct {
  229     int age;
  230     float p[3][3];
  231     float v[3];
  232     float c[3][4];
  233 } part;
  234 
  235 /* rain particle struct */
  236 typedef struct {
  237     float age;
  238     float acc[3];
  239     float vel[3];
  240     float pos[3];
  241     float partLength;
  242     float oldpos[3];
  243 } rain;
  244 
  245 /* colors */
  246 static float black[3]    = { 0.0, 0.0, 0.0 }; /* shadow color */
  247 static float partcol1[3] = { 1.0, 0.2, 0.0 }; /* initial color: red-ish */
  248 static float partcol2[3] = { 1.0, 1.0, 0.0 }; /* blending color: yellow-ish */
  249 static float fogcolor[4] = { 0.9, 0.9, 1.0, 1.0 };
  250 
  251 /* ground */
  252 static float q[4][3] = {
  253     {-DIMP, 0.0, -DIMP},
  254     {DIMP, 0.0, -DIMP},
  255     {DIMP, 0.0, DIMP},
  256     {-DIMP, 0.0, DIMP}
  257 };
  258 
  259 /* ground texture */
  260 static float qt[4][2] = {
  261     {-DIMTP, -DIMTP},
  262     {DIMTP, -DIMTP},
  263     {DIMTP, DIMTP},
  264     {-DIMTP, DIMTP}
  265 };
  266 
  267 /* default values for observer */
  268 static const float DEF_OBS[3] = { 2.0f, 1.0f, 0.0f };
  269 #define DEV_V       0.0
  270 #define DEF_ALPHA   -90.0
  271 #define DEF_BETA    90.0
  272 
  273 /* tree struct */
  274 typedef struct {
  275     float x,y,z;
  276 } treestruct;
  277 
  278 /* the mode struct, contains all per screen variables */
  279 typedef struct {
  280 #ifdef WIN32
  281     HGLRC glx_context;
  282 #else
  283     GLXContext *glx_context;
  284 #endif
  285     GLint WIDTH, HEIGHT;    /* display dimensions */
  286 
  287     int np;         /* number of fire particles : set it through 'count' resource */
  288     float eject_r;      /* emission radius */
  289     float dt, maxage, eject_vy, eject_vl;
  290     float ridtri;       /* fire particle size */
  291     Bool shadows;       /* misc booleans: set them through specific resources */
  292     Bool fog;
  293 
  294     part *p;            /* fire particles array */
  295     rain *r;            /* rain particles array */
  296 
  297     XImage *gtexture;       /* ground texture image bits */
  298     XImage *ttexture;       /* tree texture image bits */
  299     GLuint groundid;        /* ground texture id: GL world */
  300     GLuint treeid;      /* tree texture id: GL world */
  301     GLuint fontbase;        /* fontbase id: GL world */
  302 
  303     int   num_trees;        /* number of trees: set it through 'trees' resource */
  304     treestruct *treepos;    /* trees positions: float treepos[num_trees][3] */
  305 
  306     float min[3];       /* raining area */
  307     float max[3];
  308 
  309     float obs[3];       /* observer coordinates */
  310     float dir[3];       /* view direction */
  311     float v;            /* observer velocity */
  312     float alpha;        /* observer angles */
  313     float beta;
  314 } firestruct;
  315 
  316 /* array of firestruct indexed by screen number */
  317 static firestruct *fire = (firestruct *) NULL;
  318 
  319 /*
  320  *-----------------------------------------------------------------------------
  321  *-----------------------------------------------------------------------------
  322  *    Misc funcs.
  323  *-----------------------------------------------------------------------------
  324  *-----------------------------------------------------------------------------
  325  */
  326 
  327 #ifdef WIN32
  328 #include <time.h>
  329 #endif
  330 /* utility function for the rain particles */
  331 static float gettimerain(void)
  332 {
  333   static clock_t told=0;
  334   clock_t tnew,ris;
  335 
  336   tnew=clock();
  337 
  338   ris=tnew-told;
  339 
  340   told=tnew;
  341 
  342   return (ris/(float)CLOCKS_PER_SEC);
  343 }
  344 
  345 /* my RAND */
  346 static float vrnd(void)
  347 {
  348     return ((float) LRAND() / (float) MAXRAND);
  349 }
  350 
  351 /* initialise new fire particle */
  352 static void setnewpart(firestruct * fs, part * p)
  353 {
  354     float a, vi[3], *c;
  355 
  356     p->age = 0;
  357 
  358     a = vrnd() * M_PI * 2.0;
  359 
  360     vinit(vi, sin(a) * fs->eject_r * vrnd(), 0.15, cos(a) * fs->eject_r * vrnd());
  361     vinit(p->p[0], vi[0] + vrnd() * fs->ridtri, vi[1] + vrnd() * fs->ridtri, vi[2] + vrnd() * fs->ridtri);
  362     vinit(p->p[1], vi[0] + vrnd() * fs->ridtri, vi[1] + vrnd() * fs->ridtri, vi[2] + vrnd() * fs->ridtri);
  363     vinit(p->p[2], vi[0] + vrnd() * fs->ridtri, vi[1] + vrnd() * fs->ridtri, vi[2] + vrnd() * fs->ridtri);
  364 
  365     vinit(p->v, vi[0] * fs->eject_vl / (fs->eject_r / 2),
  366       vrnd() * fs->eject_vy + fs->eject_vy / 2,
  367       vi[2] * fs->eject_vl / (fs->eject_r / 2));
  368 
  369     c = partcol1;
  370 
  371     vinit4(p->c[0], c[0] * ((1.0 - RIDCOL) + vrnd() * RIDCOL),
  372        c[1] * ((1.0 - RIDCOL) + vrnd() * RIDCOL),
  373        c[2] * ((1.0 - RIDCOL) + vrnd() * RIDCOL), 1.0);
  374     vinit4(p->c[1], c[0] * ((1.0 - RIDCOL) + vrnd() * RIDCOL),
  375        c[1] * ((1.0 - RIDCOL) + vrnd() * RIDCOL),
  376        c[2] * ((1.0 - RIDCOL) + vrnd() * RIDCOL), 1.0);
  377     vinit4(p->c[2], c[0] * ((1.0 - RIDCOL) + vrnd() * RIDCOL),
  378        c[1] * ((1.0 - RIDCOL) + vrnd() * RIDCOL),
  379        c[2] * ((1.0 - RIDCOL) + vrnd() * RIDCOL), 1.0);
  380 }
  381 
  382 /* initialise new rain particle */
  383 static void setnewrain(firestruct * fs, rain * r)
  384 {
  385     r->age=0.0f;
  386 
  387     vinit(r->acc,0.0f,-0.98f,0.0f);
  388     vinit(r->vel,0.0f,0.0f,0.0f);
  389 
  390     r->partLength=0.2f;
  391 
  392     vinit(r->oldpos,fs->min[0]+(fs->max[0]-fs->min[0])*vrnd(),
  393                     fs->max[1]+0.2f*fs->max[1]*vrnd(),
  394                     fs->min[2]+(fs->max[2]-fs->min[2])*vrnd());
  395     vequ(r->pos,r->oldpos);
  396     vadds(r->oldpos,-(r->partLength),r->vel);
  397 
  398     r->pos[1]=(fs->max[1]-fs->min[1])*vrnd()+fs->min[1];
  399     r->oldpos[1]=r->pos[1]-r->partLength*r->vel[1];
  400 }
  401 
  402 /* set fire particle values */
  403 static void setpart(firestruct * fs, part * p)
  404 {
  405     float fact;
  406 
  407     if (p->p[0][1] < 0.1) {
  408     setnewpart(fs, p);
  409     return;
  410     }
  411 
  412     p->v[1] += AGRAV * fs->dt;
  413 
  414     vadds(p->p[0], fs->dt, p->v);
  415     vadds(p->p[1], fs->dt, p->v);
  416     vadds(p->p[2], fs->dt, p->v);
  417 
  418     p->age++;
  419 
  420     if ((p->age) > fs->maxage) {
  421     vequ(p->c[0], partcol2);
  422     vequ(p->c[1], partcol2);
  423     vequ(p->c[2], partcol2);
  424     } else {
  425     fact = 1.0 / fs->maxage;
  426     vadds(p->c[0], fact, partcol2);
  427     vclamp(p->c[0]);
  428     p->c[0][3] = fact * (fs->maxage - p->age);
  429 
  430     vadds(p->c[1], fact, partcol2);
  431     vclamp(p->c[1]);
  432     p->c[1][3] = fact * (fs->maxage - p->age);
  433 
  434     vadds(p->c[2], fact, partcol2);
  435     vclamp(p->c[2]);
  436     p->c[2][3] = fact * (fs->maxage - p->age);
  437     }
  438 }
  439 
  440 /* set rain particle values */
  441 static void setpartrain(firestruct * fs, rain * r, float dt)
  442 {
  443     r->age += dt;
  444 
  445     vadds(r->vel,dt,r->acc);
  446     vadds(r->pos,dt,r->vel);
  447 
  448     if(r->pos[0]<fs->min[0])
  449     r->pos[0]=fs->max[0]-(fs->min[0]-r->pos[0]);
  450     if(r->pos[2]<fs->min[2])
  451     r->pos[2]=fs->max[2]-(fs->min[2]-r->pos[2]);
  452 
  453     if(r->pos[0]>fs->max[0])
  454     r->pos[0]=fs->min[0]+(r->pos[0]-fs->max[0]);
  455     if(r->pos[2]>fs->max[2])
  456     r->pos[2]=fs->min[2]+(r->pos[2]-fs->max[2]);
  457 
  458     vequ(r->oldpos,r->pos);
  459     vadds(r->oldpos,-(r->partLength),r->vel);
  460     if(r->pos[1]<fs->min[1])
  461         setnewrain(fs, r);
  462 }
  463 
  464 #ifdef HAVE_GLBINDTEXTURE
  465 /* draw a tree */
  466 static void drawtree(float x, float y, float z)
  467 {
  468     glBegin(GL_QUADS);
  469     glTexCoord2f(0.0,0.0);
  470     glVertex3f(x-1.5,y+0.0,z);
  471 
  472     glTexCoord2f(1.0,0.0);
  473     glVertex3f(x+1.5,y+0.0,z);
  474 
  475     glTexCoord2f(1.0,1.0);
  476     glVertex3f(x+1.5,y+3.0,z);
  477 
  478     glTexCoord2f(0.0,1.0);
  479     glVertex3f(x-1.5,y+3.0,z);
  480 
  481 
  482     glTexCoord2f(0.0,0.0);
  483     glVertex3f(x,y+0.0,z-1.5);
  484 
  485     glTexCoord2f(1.0,0.0);
  486     glVertex3f(x,y+0.0,z+1.5);
  487 
  488     glTexCoord2f(1.0,1.0);
  489     glVertex3f(x,y+3.0,z+1.5);
  490 
  491     glTexCoord2f(0.0,1.0);
  492     glVertex3f(x,y+3.0,z-1.5);
  493 
  494     glEnd();
  495 }
  496 #endif
  497 
  498 /* calculate observer position : modified only if trackmouse is used */
  499 static void calcposobs(firestruct * fs)
  500 {
  501     fs->dir[0] = sin(fs->alpha * M_PI / 180.0);
  502     fs->dir[2] =
  503     cos(fs->alpha * M_PI / 180.0) * sin(fs->beta * M_PI / 180.0);
  504     fs->dir[1] = cos(fs->beta * M_PI / 180.0);
  505 
  506     fs->obs[0] += fs->v * fs->dir[0];
  507     fs->obs[1] += fs->v * fs->dir[1];
  508     fs->obs[2] += fs->v * fs->dir[2];
  509 
  510     if (!fs->np)
  511     {
  512         vinit(fs->min,fs->obs[0]-7.0f,-0.2f,fs->obs[2]-7.0f);
  513         vinit(fs->max,fs->obs[0]+7.0f,8.0f,fs->obs[2]+7.0f);
  514     }
  515 }
  516 
  517 /* track the mouse in a joystick manner : not perfect but it works */
  518 static void trackmouse(ModeInfo * mi)
  519 {
  520     firestruct *fs = &fire[MI_SCREEN(mi)];
  521     /* we keep static values (not per screen) for the mouse stuff: in general you have only one mouse :-> */
  522     static int max[2] = { 0, 0 };
  523     static int min[2] = { 0x7fffffff, 0x7fffffff }, center[2];
  524     Window r, c;
  525     int rx, ry, cx, cy;
  526     unsigned int m;
  527 
  528     (void) XQueryPointer(MI_DISPLAY(mi), MI_WINDOW(mi),
  529              &r, &c, &rx, &ry, &cx, &cy, &m);
  530 
  531     if (max[0] < cx)
  532     max[0] = cx;
  533     if (min[0] > cx)
  534     min[0] = cx;
  535     center[0] = (max[0] + min[0]) / 2;
  536 
  537     if (max[1] < cy)
  538     max[1] = cy;
  539     if (min[1] > cy)
  540     min[1] = cy;
  541     center[1] = (max[1] + min[1]) / 2;
  542 
  543     if (fabs(center[0] - (float) cx) > 0.1 * (max[0] - min[0]))
  544     fs->alpha += 2.5 * (center[0] - (float) cx) / (max[0] - min[0]);
  545     if (fabs(center[1] - (float) cy) > 0.1 * (max[1] - min[1]))
  546     fs->beta += 2.5 * (center[1] - (float) cy) / (max[1] - min[1]);
  547 
  548     /* oops: can't get those buttons */
  549     if (m & Button4Mask)
  550     fs->v += 0.01;
  551     if (m & Button5Mask)
  552     fs->v -= 0.01;
  553 
  554 }
  555 
  556 /* initialise textures */
  557 static void inittextures(ModeInfo * mi)
  558 {
  559     firestruct *fs = &fire[MI_SCREEN(mi)];
  560 
  561 #ifdef HAVE_XPM
  562     if (do_texture) {
  563 
  564     glGenTextures(1, &fs->groundid);
  565 #ifdef HAVE_GLBINDTEXTURE
  566     glBindTexture(GL_TEXTURE_2D, fs->groundid);
  567 #endif /* HAVE_GLBINDTEXTURE */
  568 
  569         if ((fs->gtexture = xpm_to_ximage(MI_DISPLAY(mi), MI_VISUAL(mi),
  570              MI_COLORMAP(mi), ground)) == None) {
  571         (void) fprintf(stderr, "Error reading the ground texture.\n");
  572         glDeleteTextures(1, &fs->groundid);
  573             do_texture = False;
  574         fs->groundid = 0;
  575         fs->treeid   = 0;
  576         return;
  577     }
  578 
  579     glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
  580     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
  581              fs->gtexture->width, fs->gtexture->height, 0,
  582              GL_RGBA, GL_UNSIGNED_BYTE, fs->gtexture->data);
  583 
  584     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  585     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  586 
  587     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  588     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  589 
  590     glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
  591 
  592         if (fs->num_trees)
  593     {
  594         glGenTextures(1, &fs->treeid);
  595 #ifdef HAVE_GLBINDTEXTURE
  596         glBindTexture(GL_TEXTURE_2D,fs->treeid);
  597 #endif /* HAVE_GLBINDTEXTURE */
  598             if ((fs->ttexture = xpm_to_ximage(MI_DISPLAY(mi), MI_VISUAL(mi),
  599              MI_COLORMAP(mi), tree)) == None) {
  600           (void)fprintf(stderr,"Error reading tree texture.\n");
  601           glDeleteTextures(1, &fs->treeid);
  602           fs->treeid    = 0;
  603               fs->num_trees = 0;
  604           return;
  605         }
  606 
  607         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
  608                 fs->ttexture->width, fs->ttexture->height, 0,
  609                 GL_RGBA, GL_UNSIGNED_BYTE, fs->ttexture->data);
  610 
  611         glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
  612         glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
  613 
  614         glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
  615         glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
  616 
  617         glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);
  618     }
  619     }
  620     else
  621     {
  622     fs->groundid = 0;   /* default textures */
  623     fs->treeid   = 0;
  624     }
  625 #else /* !HAVE_XPM */
  626   do_texture = False;
  627   fs->groundid = 0;       /* default textures */
  628   fs->treeid = 0;
  629 #endif /* !HAVE_XPM */
  630 }
  631 
  632 /* init tree array and positions */
  633 static Bool inittree(ModeInfo * mi)
  634 {
  635     firestruct *fs = &fire[MI_SCREEN(mi)];
  636     int i;
  637     float dist;
  638 
  639     /* allocate treepos array */
  640     if ((fs->treepos = (treestruct *) malloc(fs->num_trees *
  641                     sizeof(treestruct))) == NULL) {
  642         return False;
  643     }
  644     /* initialise positions */
  645     for(i=0;i<fs->num_trees;i++)
  646         do {
  647             fs->treepos[i].x =vrnd()*TREEOUTR*2.0-TREEOUTR;
  648             fs->treepos[i].y =0.0;
  649             fs->treepos[i].z =vrnd()*TREEOUTR*2.0-TREEOUTR;
  650             dist=sqrt(fs->treepos[i].x *fs->treepos[i].x +fs->treepos[i].z *fs->treepos[i].z );
  651         } while((dist<TREEINR) || (dist>TREEOUTR));
  652     return True;
  653 }
  654 
  655 /*
  656  *-----------------------------------------------------------------------------
  657  *-----------------------------------------------------------------------------
  658  *    GL funcs.
  659  *-----------------------------------------------------------------------------
  660  *-----------------------------------------------------------------------------
  661  */
  662 
  663 ENTRYPOINT void
  664 reshape_fire(ModeInfo * mi, int width, int height)
  665 {
  666 
  667     firestruct *fs = &fire[MI_SCREEN(mi)];
  668     int size = MI_SIZE(mi);
  669 
  670     /* Viewport is specified size if size >= MINSIZE && size < screensize */
  671     if (size <= 1) {
  672         fs->WIDTH = width;
  673         fs->HEIGHT = height;
  674     } else if (size < MINSIZE) {
  675         fs->WIDTH = MINSIZE;
  676         fs->HEIGHT = MINSIZE;
  677     } else {
  678         fs->WIDTH = (size > width) ? width : size;
  679         fs->HEIGHT = (size > height) ? height : size;
  680     }
  681     glViewport((width - fs->WIDTH) / 2, (height - fs->HEIGHT) / 2, fs->WIDTH, fs->HEIGHT);
  682     glMatrixMode(GL_PROJECTION);
  683     glLoadIdentity();
  684     gluPerspective(70.0, fs->WIDTH / (float) fs->HEIGHT, 0.1, 30.0);
  685 
  686     glMatrixMode(GL_MODELVIEW);
  687 
  688 }
  689 
  690 static void DrawFire(ModeInfo * mi)
  691 {
  692     int j;
  693     firestruct *fs = &fire[MI_SCREEN(mi)];
  694     Bool wire = MI_IS_WIREFRAME(mi);
  695 
  696     if (do_trackmouse && !MI_IS_ICONIC(mi))
  697     trackmouse(mi);
  698 
  699     if (do_wander)
  700     {
  701     GLfloat x, y, z;
  702 
  703 #       define SINOID(SCALE,SIZE) \
  704         ((((1 + sin((frame * (SCALE)) / 2 * M_PI)) / 2.0) * (SIZE)) - (SIZE)/2)
  705 
  706         x = SINOID(0.031, 0.85);
  707         y = SINOID(0.017, 0.25);
  708         z = SINOID(0.023, 0.85);
  709         frame++;
  710         fs->obs[0] = x + DEF_OBS[0];
  711         fs->obs[1] = y + DEF_OBS[1];
  712         fs->obs[2] = z + DEF_OBS[2];
  713         fs->dir[1] = y;
  714         fs->dir[2] = z;
  715     }
  716 
  717     glEnable(GL_DEPTH_TEST);
  718 
  719     if (fs->fog)
  720     glEnable(GL_FOG);
  721     else
  722     glDisable(GL_FOG);
  723 
  724     glDepthMask(GL_TRUE);
  725     glClearColor(0.5, 0.5, 0.8, 1.0);   /* sky in the distance */
  726     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  727 
  728     glPushMatrix();
  729     calcposobs(fs);
  730     gluLookAt(fs->obs[0], fs->obs[1], fs->obs[2],
  731           fs->obs[0] + fs->dir[0], fs->obs[1] + fs->dir[1],
  732           fs->obs[2] + fs->dir[2], 0.0, 1.0, 0.0);
  733 
  734 
  735     glEnable(GL_TEXTURE_2D);
  736 
  737     /* draw ground using the computed texture */
  738 #ifdef HAVE_GLBINDTEXTURE
  739     if (do_texture) {
  740     glColor4f(1.0,1.0,1.0,1.0); /* white to get texture in it's true color */
  741     glBindTexture(GL_TEXTURE_2D, fs->groundid);
  742     }
  743     else
  744 #endif /* HAVE_GLBINDTEXTURE */
  745         glColor4f(0.54, 0.27, 0.07, 1.0);   /* untextured ground color */
  746     glBegin(GL_QUADS);
  747     glTexCoord2fv(qt[0]);
  748     glVertex3fv(q[0]);
  749     glTexCoord2fv(qt[1]);
  750     glVertex3fv(q[1]);
  751     glTexCoord2fv(qt[2]);
  752     glVertex3fv(q[2]);
  753     glTexCoord2fv(qt[3]);
  754     glVertex3fv(q[3]);
  755     glEnd();
  756 
  757     glAlphaFunc(GL_GEQUAL, 0.9);
  758 #ifdef HAVE_GLBINDTEXTURE
  759     if (fs->num_trees)
  760     {
  761     /* here do_texture IS True - and color used is white */
  762     glEnable(GL_ALPHA_TEST);
  763     glBindTexture(GL_TEXTURE_2D,fs->treeid);
  764     for(j=0;j<fs->num_trees;j++)
  765         drawtree(fs->treepos[j].x ,fs->treepos[j].y ,fs->treepos[j].z );
  766         glDisable(GL_ALPHA_TEST);
  767     }
  768 #endif /* HAVE_GLBINDTEXTURE */
  769     glDisable(GL_TEXTURE_2D);
  770     glDepthMask(GL_FALSE);
  771 
  772     if (fs->shadows) {
  773     /* draw shadows with black color */
  774     glBegin(wire ? GL_LINE_STRIP : GL_TRIANGLES);
  775     for (j = 0; j < fs->np; j++) {
  776         glColor4f(black[0], black[1], black[2], fs->p[j].c[0][3]);
  777         glVertex3f(fs->p[j].p[0][0], 0.1, fs->p[j].p[0][2]);
  778 
  779         glColor4f(black[0], black[1], black[2], fs->p[j].c[1][3]);
  780         glVertex3f(fs->p[j].p[1][0], 0.1, fs->p[j].p[1][2]);
  781 
  782         glColor4f(black[0], black[1], black[2], fs->p[j].c[2][3]);
  783         glVertex3f(fs->p[j].p[2][0], 0.1, fs->p[j].p[2][2]);
  784     }
  785     glEnd();
  786     }
  787 
  788     glBegin(wire ? GL_LINE_STRIP : GL_TRIANGLES);
  789     for (j = 0; j < fs->np; j++) {
  790     /* draw particles: colors are computed in setpart */
  791     glColor4fv(fs->p[j].c[0]);
  792     glVertex3fv(fs->p[j].p[0]);
  793 
  794     glColor4fv(fs->p[j].c[1]);
  795     glVertex3fv(fs->p[j].p[1]);
  796 
  797     glColor4fv(fs->p[j].c[2]);
  798     glVertex3fv(fs->p[j].p[2]);
  799 
  800     setpart(fs, &fs->p[j]);
  801     }
  802     glEnd();
  803 
  804     /* draw rain particles if no fire particles */
  805     if (!fs->np)
  806     {
  807         float timeused = gettimerain();
  808         glDisable(GL_TEXTURE_2D);
  809     glShadeModel(GL_SMOOTH);
  810     glBegin(GL_LINES);
  811     for (j = 0; j < NUMPART; j++) {
  812         glColor4f(0.7f,0.95f,1.0f,0.0f);
  813         glVertex3fv(fs->r[j].oldpos);
  814         glColor4f(0.3f,0.7f,1.0f,1.0f);
  815         glVertex3fv(fs->r[j].pos);
  816         setpartrain(fs, &fs->r[j],timeused);
  817     }
  818     glEnd();
  819     glShadeModel(GL_FLAT);
  820     }
  821 
  822     glDisable(GL_TEXTURE_2D);
  823     glDisable(GL_ALPHA_TEST);
  824     glDisable(GL_DEPTH_TEST);
  825     glDisable(GL_FOG);
  826 
  827     /* manage framerate display */
  828     if (MI_IS_FPS(mi)) do_fps (mi);
  829     glPopMatrix();
  830 }
  831 
  832 
  833 static Bool Init(ModeInfo * mi)
  834 {
  835     int i;
  836     firestruct *fs = &fire[MI_SCREEN(mi)];
  837 
  838     /* default settings */
  839     fs->eject_r = 0.1 + NRAND(10) * 0.03;
  840     fs->dt = 0.015;
  841     fs->eject_vy = 4;
  842     fs->eject_vl = 1;
  843     fs->ridtri = 0.1 + NRAND(10) * 0.005;
  844     fs->maxage = 1.0 / fs->dt;
  845     vinit(fs->obs, DEF_OBS[0], DEF_OBS[1], DEF_OBS[2]);
  846     fs->v = 0.0;
  847     fs->alpha = DEF_ALPHA;
  848     fs->beta = DEF_BETA;
  849 
  850     /* initialise texture stuff */
  851     if (do_texture)
  852         inittextures(mi);
  853     else
  854     {
  855     fs->ttexture = (XImage*) NULL;
  856     fs->gtexture = (XImage*) NULL;
  857     }
  858 
  859     if (MI_IS_DEBUG(mi)) {
  860     (void) fprintf(stderr,
  861                "%s:\n\tnum_part=%d\n\ttrees=%d\n\tfog=%s\n\tshadows=%s\n\teject_r=%.3f\n\tridtri=%.3f\n",
  862                MI_NAME(mi),
  863                fs->np,
  864                fs->num_trees,
  865                fs->fog ? "on" : "off",
  866                fs->shadows ? "on" : "off",
  867                fs->eject_r, fs->ridtri);
  868     }
  869 
  870     glShadeModel(GL_FLAT);
  871     glEnable(GL_DEPTH_TEST);
  872 
  873     /* makes particles blend with background */
  874     if (!MI_IS_WIREFRAME(mi)||(!fs->np))
  875     {
  876         glEnable(GL_BLEND);
  877         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  878     }
  879 
  880     /* fog stuff */
  881     glEnable(GL_FOG);
  882     glFogi(GL_FOG_MODE, GL_EXP);
  883     glFogfv(GL_FOG_COLOR, fogcolor);
  884     glFogf(GL_FOG_DENSITY, 0.03);
  885     glHint(GL_FOG_HINT, GL_NICEST);
  886 
  887     /* initialise particles and trees */
  888     for (i = 0; i < fs->np; i++) {
  889     setnewpart(fs, &(fs->p[i]));
  890     }
  891 
  892     if (fs->num_trees)
  893     if (!inittree(mi)) {
  894         return False;
  895     }
  896 
  897     /* if no fire particles then initialise rain particles */
  898     if (!fs->np)
  899     {
  900     vinit(fs->min,-7.0f,-0.2f,-7.0f);
  901     vinit(fs->max,7.0f,8.0f,7.0f);
  902         for (i = 0; i < NUMPART; i++) {
  903         setnewrain(fs, &(fs->r[i]));
  904         }
  905     }
  906 
  907     return True;
  908 }
  909 
  910 /*
  911  *-----------------------------------------------------------------------------
  912  *-----------------------------------------------------------------------------
  913  *    Xlock hooks.
  914  *-----------------------------------------------------------------------------
  915  *-----------------------------------------------------------------------------
  916  */
  917 
  918 
  919 static void
  920 free_fire_screen(firestruct *fs)
  921 {
  922     if (fs == NULL) {
  923         return;
  924     }
  925     if (mode_font != None && fs->fontbase != None) {
  926         glDeleteLists(fs->fontbase, mode_font->max_char_or_byte2 -
  927             mode_font->min_char_or_byte2 + 1);
  928         fs->fontbase = None;
  929     }
  930 
  931     if (fs->p != NULL) {
  932         free(fs->p);
  933         fs->p = (part *) NULL;
  934     }
  935     if (fs->r != NULL) {
  936         free(fs->r);
  937         fs->r = (rain *) NULL;
  938     }
  939     if (fs->treepos != NULL) {
  940         free(fs->treepos);
  941         fs->treepos = (treestruct *) NULL;
  942     }
  943     if (fs->ttexture != None) {
  944         glDeleteTextures(1, &fs->treeid);
  945         XDestroyImage(fs->ttexture);
  946         fs->ttexture = None;
  947     }
  948     if (fs->gtexture != None) {
  949         glDeleteTextures(1, &fs->groundid);
  950         XDestroyImage(fs->gtexture);
  951         fs->gtexture = None;
  952     }
  953     fs = NULL;
  954 }
  955 
  956 /*
  957  *-----------------------------------------------------------------------------
  958  *    Initialize fire.  Called each time the window changes.
  959  *-----------------------------------------------------------------------------
  960  */
  961 
  962 ENTRYPOINT void
  963 free_fire(ModeInfo * mi)
  964 {
  965     free_fire_screen(&fire[MI_SCREEN(mi)]);
  966 }
  967 
  968 ENTRYPOINT void
  969 init_fire(ModeInfo * mi)
  970 {
  971     firestruct *fs;
  972 
  973     /* allocate the main fire table if needed */
  974     MI_INIT(mi, fire);
  975     /* initialise the per screen fire structure */
  976     fs = &fire[MI_SCREEN(mi)];
  977     fs->np = MI_COUNT(mi);
  978     fs->fog = do_fog;
  979     fs->shadows = do_shadows;
  980     /* initialise fire particles if any */
  981     if ((fs->np)&&(fs->p == NULL)) {
  982     if ((fs->p = (part *) calloc(fs->np, sizeof(part))) == NULL) {
  983         free_fire_screen(fs);
  984         return;
  985     }
  986     }
  987     else if (fs->r == NULL) {
  988         /* initialise rain particles if no fire particles */
  989     if ((fs->r = (rain *) calloc(NUMPART, sizeof(part))) == NULL) {
  990         free_fire_screen(fs);
  991         return;
  992     }
  993     }
  994 
  995     /* check tree number */
  996     if (do_texture)
  997         fs->num_trees = (num_trees<MAX_TREES)?num_trees:MAX_TREES;
  998     else
  999         fs->num_trees = 0;
 1000 
 1001     /* check wander/trackmouse */
 1002     if (do_trackmouse && do_wander) do_wander = 0;
 1003 
 1004     /* xlock GL stuff */
 1005     if ((fs->glx_context = init_GL(mi)) != NULL) {
 1006 
 1007     reshape_fire(mi,MI_WIDTH(mi),MI_HEIGHT(mi));
 1008     glDrawBuffer(GL_BACK);
 1009     if (!Init(mi)) {
 1010         free_fire_screen(fs);
 1011         return;
 1012     }
 1013     } else {
 1014     MI_CLEARWINDOW(mi);
 1015     }
 1016 }
 1017 
 1018 /*
 1019  *-----------------------------------------------------------------------------
 1020  *    Called by the mainline code periodically to update the display.
 1021  *-----------------------------------------------------------------------------
 1022  */
 1023 ENTRYPOINT void
 1024 draw_fire(ModeInfo * mi)
 1025 {
 1026     firestruct *fs = &fire[MI_SCREEN(mi)];
 1027 
 1028     Display *display = MI_DISPLAY(mi);
 1029     Window window = MI_WINDOW(mi);
 1030 
 1031     MI_IS_DRAWN(mi) = True;
 1032 
 1033     if (!fs->glx_context)
 1034     return;
 1035 #ifdef WIN32
 1036     wglMakeCurrent(hdc, fs->glx_context);
 1037 #else
 1038     glXMakeCurrent(display, window, *(fs->glx_context));
 1039 #endif
 1040     DrawFire(mi);
 1041     reshape_fire(mi,MI_WIDTH(mi),MI_HEIGHT(mi));
 1042     glFinish();
 1043     glXSwapBuffers(display, window);
 1044 }
 1045 
 1046 
 1047 /*
 1048  *-----------------------------------------------------------------------------
 1049  *    The display is being taken away from us.  Free up malloc'ed
 1050  *      memory and X resources that we've alloc'ed.  Only called
 1051  *      once, we must zap everything for every screen.
 1052  *-----------------------------------------------------------------------------
 1053  */
 1054 
 1055 ENTRYPOINT void
 1056 release_fire(ModeInfo * mi)
 1057 {
 1058     if (fire != NULL) {
 1059     int screen;
 1060     for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
 1061         free_fire_screen(&fire[screen]);
 1062     free(fire);
 1063     fire = (firestruct *) NULL;
 1064     }
 1065     if (mode_font != None)
 1066     {
 1067     /* only free-ed when there are no more screens used */
 1068     XFreeFont(MI_DISPLAY(mi), mode_font);
 1069     mode_font = None;
 1070     }
 1071     FreeAllGL(mi);
 1072 }
 1073 
 1074 #ifndef STANDALONE
 1075 ENTRYPOINT void
 1076 change_fire(ModeInfo * mi)
 1077 {
 1078     firestruct *fs = &fire[MI_SCREEN(mi)];
 1079 
 1080     if (!fs->glx_context)
 1081     return;
 1082 
 1083 #ifdef WIN32
 1084     wglMakeCurrent(hdc, fs->glx_context);
 1085 #else
 1086     glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(fs->glx_context));
 1087 #endif
 1088     /* if available, randomly change some values */
 1089     if (do_fog)
 1090     fs->fog = LRAND() & 1;
 1091     if (do_shadows)
 1092     fs->shadows = LRAND() & 1;
 1093     /* reset observer position */
 1094     frame = 0;
 1095     vinit(fs->obs, DEF_OBS[0], DEF_OBS[1], DEF_OBS[2]);
 1096     fs->v = 0.0;
 1097     /* particle randomisation */
 1098     fs->eject_r = 0.1 + NRAND(10) * 0.03;
 1099     fs->ridtri = 0.1 + NRAND(10) * 0.005;
 1100 
 1101     if (MI_IS_DEBUG(mi)) {
 1102     (void) fprintf(stderr,
 1103                "%s:\n\tnum_part=%d\n\ttrees=%d\n\tfog=%s\n\tshadows=%s\n\teject_r=%.3f\n\tridtri=%.3f\n",
 1104                MI_NAME(mi),
 1105                fs->np,
 1106                fs->num_trees,
 1107                fs->fog ? "on" : "off",
 1108                fs->shadows ? "on" : "off",
 1109                fs->eject_r, fs->ridtri);
 1110     }
 1111 }
 1112 #endif
 1113 
 1114 XSCREENSAVER_MODULE ("Fire", fire)
 1115 
 1116 #endif /* MODE_fire */