1113 lines
30 KiB
C
1113 lines
30 KiB
C
|
/* -*- Mode: C; tab-width: 4 -*- */
|
||
|
/* fire --- 3D fire or rain landscape */
|
||
|
|
||
|
#if !defined( lint ) && !defined( SABER )
|
||
|
static const char sccsid[] = "@(#)fire.c 5.02 2001/09/26 xlockmore";
|
||
|
#endif
|
||
|
|
||
|
/* Copyright (c) E. Lassauge, 2001. */
|
||
|
|
||
|
/*
|
||
|
* Permission to use, copy, modify, and distribute this software and its
|
||
|
* documentation for any purpose and without fee is hereby granted,
|
||
|
* provided that the above copyright notice appear in all copies and that
|
||
|
* both that copyright notice and this permission notice appear in
|
||
|
* supporting documentation.
|
||
|
*
|
||
|
* This file is provided AS IS with no warranties of any kind. The author
|
||
|
* shall have no liability with respect to the infringement of copyrights,
|
||
|
* trade secrets or any patents by this file or any part thereof. In no
|
||
|
* event will the author be liable for any lost revenue or profits or
|
||
|
* other special, indirect and consequential damages.
|
||
|
*
|
||
|
* The original code for this mode was written by David Bucciarelli
|
||
|
* (tech.hmw@plus.it) and could be found in the demo package
|
||
|
* of Mesa (Mesa-3.2/3Dfx/demos/). This mode is the result of the merge of
|
||
|
* two of the David's demos (fire and rain).
|
||
|
*
|
||
|
* Eric Lassauge (October-10-2000) <lassauge AT users.sourceforge.net>
|
||
|
* http://lassauge.free.fr/linux.html
|
||
|
*
|
||
|
* REVISION HISTORY:
|
||
|
*
|
||
|
* E.Lassauge - 26-Sep-2001:
|
||
|
* - add wander option and code
|
||
|
* - cleanups for xscreensaver
|
||
|
*
|
||
|
* E.Lassauge - 09-Mar-2001:
|
||
|
* - get rid of my framerate options to use showfps
|
||
|
*
|
||
|
* E.Lassauge - 12-Jan-2001:
|
||
|
* - add rain particules, selected if count=0 (no fire means rain !)
|
||
|
*
|
||
|
* E.Lassauge - 28-Nov-2000:
|
||
|
* - modified release part to add freeing of GL objects
|
||
|
*
|
||
|
* E.Lassauge - 14-Nov-2000:
|
||
|
* - use new common xpm_to_ximage function
|
||
|
*
|
||
|
* E.Lassauge - 25-Oct-2000:
|
||
|
* - add the trees (with a new resource '-trees')
|
||
|
* - corrected handling of color (textured vs untextured)
|
||
|
* - corrected handling of endiannes for the xpm files
|
||
|
* - inverted ground pixmap file
|
||
|
* - use malloc-ed tree array
|
||
|
*
|
||
|
* TSchmidt - 23-Oct-2000:
|
||
|
* - added size option like used in sproingies mode
|
||
|
*
|
||
|
* E.Lassauge - 13-Oct-2000:
|
||
|
* - when trackmouse and window is iconified (login screen): stop tracking
|
||
|
* - add pure GLX handling of framerate display (erased GLUT stuff)
|
||
|
* - made count a per screen variable and update it only if framemode
|
||
|
* - changes for no_texture an wireframe modes
|
||
|
* - change no_texture color for the ground
|
||
|
* - add freeing of texture image
|
||
|
* - misc comments and little tweakings
|
||
|
*
|
||
|
* TODO:
|
||
|
* - perhaps use a user supplied xpm for ground image (or a whatever image
|
||
|
* file using ImageMagick ?)
|
||
|
* - random number of trees ? change trees at change_fire ?
|
||
|
* - fix wireframe mode: it's too CPU intensive.
|
||
|
* - look how we can get the Wheel events (Button4&5).
|
||
|
*/
|
||
|
|
||
|
|
||
|
#ifdef STANDALONE /* xscreensaver mode */
|
||
|
#define MODE_fire
|
||
|
#define PROGCLASS "Fire"
|
||
|
#define HACK_INIT init_fire
|
||
|
#define HACK_DRAW draw_fire
|
||
|
#define HACK_RESHAPE reshape_fire
|
||
|
#define fire_opts xlockmore_opts
|
||
|
#define DEFAULTS "*delay: 10000 \n" \
|
||
|
"*count: 800 \n" \
|
||
|
"*size: 0 \n" \
|
||
|
"*trees: 5 \n" \
|
||
|
"*showFPS: False \n" \
|
||
|
"*trackmouse: False \n" \
|
||
|
"*wander: True \n" \
|
||
|
"*wireframe: False \n" \
|
||
|
"*fog: False \n" \
|
||
|
"*shadows: True \n" \
|
||
|
"*texture: True \n"
|
||
|
|
||
|
#include "xlockmore.h" /* from the xscreensaver distribution */
|
||
|
#else /* !STANDALONE */
|
||
|
#include "xlock.h" /* from the xlockmore distribution */
|
||
|
#include "visgl.h"
|
||
|
#endif /* !STANDALONE */
|
||
|
|
||
|
#ifdef MODE_fire
|
||
|
|
||
|
#define MINSIZE 32
|
||
|
|
||
|
#include <GL/gl.h>
|
||
|
#include <GL/glx.h>
|
||
|
#include <GL/glu.h>
|
||
|
|
||
|
#ifdef HAVE_XPM
|
||
|
#include "xpm-ximage.h"
|
||
|
|
||
|
#ifdef STANDALONE
|
||
|
#include "../images/ground.xpm"
|
||
|
#include "../images/tree.xpm"
|
||
|
#else /* !STANDALONE */
|
||
|
#include "pixmaps/ground.xpm"
|
||
|
#include "pixmaps/tree.xpm"
|
||
|
#endif /* !STANDALONE */
|
||
|
#endif /* HAVE_XPM */
|
||
|
|
||
|
/* vector utility macros */
|
||
|
#define vinit(a,i,j,k) {\
|
||
|
(a)[0]=i;\
|
||
|
(a)[1]=j;\
|
||
|
(a)[2]=k;\
|
||
|
}
|
||
|
|
||
|
#define vinit4(a,i,j,k,w) {\
|
||
|
(a)[0]=i;\
|
||
|
(a)[1]=j;\
|
||
|
(a)[2]=k;\
|
||
|
(a)[3]=w;\
|
||
|
}
|
||
|
|
||
|
#define vadds(a,dt,b) {\
|
||
|
(a)[0]+=(dt)*(b)[0];\
|
||
|
(a)[1]+=(dt)*(b)[1];\
|
||
|
(a)[2]+=(dt)*(b)[2];\
|
||
|
}
|
||
|
|
||
|
#define vequ(a,b) {\
|
||
|
(a)[0]=(b)[0];\
|
||
|
(a)[1]=(b)[1];\
|
||
|
(a)[2]=(b)[2];\
|
||
|
}
|
||
|
|
||
|
#define vinter(a,dt,b,c) {\
|
||
|
(a)[0]=(dt)*(b)[0]+(1.0-dt)*(c)[0];\
|
||
|
(a)[1]=(dt)*(b)[1]+(1.0-dt)*(c)[1];\
|
||
|
(a)[2]=(dt)*(b)[2]+(1.0-dt)*(c)[2];\
|
||
|
}
|
||
|
|
||
|
#define clamp(a) ((a) < 0.0 ? 0.0 : ((a) < 1.0 ? (a) : 1.0))
|
||
|
|
||
|
#define vclamp(v) {\
|
||
|
(v)[0]=clamp((v)[0]);\
|
||
|
(v)[1]=clamp((v)[1]);\
|
||
|
(v)[2]=clamp((v)[2]);\
|
||
|
}
|
||
|
|
||
|
/* Manage option vars */
|
||
|
#define DEF_TEXTURE "True"
|
||
|
#define DEF_FOG "False"
|
||
|
#define DEF_SHADOWS "True"
|
||
|
#define DEF_FRAMERATE "False"
|
||
|
#define DEF_TRACKMOUSE "False"
|
||
|
#define DEF_WANDER "True"
|
||
|
#define DEF_TREES "5"
|
||
|
#define MAX_TREES 20
|
||
|
static Bool do_texture;
|
||
|
static Bool do_fog;
|
||
|
static Bool do_shadows;
|
||
|
static Bool do_trackmouse;
|
||
|
static Bool do_wander;
|
||
|
static int num_trees;
|
||
|
static int frame = 0;
|
||
|
static XFontStruct *mode_font = None;
|
||
|
|
||
|
static XrmOptionDescRec opts[] = {
|
||
|
{(char *) "-texture", (char *) ".fire.texture", XrmoptionNoArg, (caddr_t) "on"},
|
||
|
{(char *) "+texture", (char *) ".fire.texture", XrmoptionNoArg, (caddr_t) "off"},
|
||
|
{(char *) "-fog", (char *) ".fire.fog", XrmoptionNoArg, (caddr_t) "on"},
|
||
|
{(char *) "+fog", (char *) ".fire.fog", XrmoptionNoArg, (caddr_t) "off"},
|
||
|
{(char *) "-shadows", (char *) ".fire.shadows", XrmoptionNoArg, (caddr_t) "on"},
|
||
|
{(char *) "+shadows", (char *) ".fire.shadows", XrmoptionNoArg, (caddr_t) "off"},
|
||
|
{(char *) "-trackmouse", (char *) ".fire.trackmouse", XrmoptionNoArg, (caddr_t) "on"},
|
||
|
{(char *) "+trackmouse", (char *) ".fire.trackmouse", XrmoptionNoArg, (caddr_t) "off"},
|
||
|
{(char *) "-wander", (char *) ".fire.wander", XrmoptionNoArg, (caddr_t) "on"},
|
||
|
{(char *) "+wander", (char *) ".fire.wander", XrmoptionNoArg, (caddr_t) "off"},
|
||
|
{(char *) "-trees", (char *) ".fire.trees", XrmoptionSepArg, (caddr_t) NULL},
|
||
|
|
||
|
};
|
||
|
|
||
|
static argtype vars[] = {
|
||
|
{(void *) & do_texture, (char *) "texture", (char *) "Texture", (char *) DEF_TEXTURE, t_Bool},
|
||
|
{(void *) & do_fog, (char *) "fog", (char *) "Fog", (char *) DEF_FOG, t_Bool},
|
||
|
{(void *) & do_shadows, (char *) "shadows", (char *) "Shadows", (char *) DEF_SHADOWS, t_Bool},
|
||
|
{(void *) & do_trackmouse, (char *) "trackmouse", (char *) "TrackMouse", (char *) DEF_TRACKMOUSE, t_Bool},
|
||
|
{(void *) & do_wander, (char *) "wander", (char *) "Wander", (char *) DEF_WANDER, t_Bool},
|
||
|
{(void *) & num_trees, (char *) "trees", (char *) "Trees", (char *) DEF_TREES, t_Int},
|
||
|
};
|
||
|
|
||
|
static OptionStruct desc[] = {
|
||
|
{(char *) "-/+texture", (char *) "turn on/off texturing"},
|
||
|
{(char *) "-/+fog", (char *) "turn on/off fog"},
|
||
|
{(char *) "-/+shadows", (char *) "turn on/off shadows"},
|
||
|
{(char *) "-/+trackmouse", (char *) "turn on/off the tracking of the mouse"},
|
||
|
{(char *) "-/+wander", (char *) "turn on/off wandering"},
|
||
|
{(char *) "-trees num", (char *) "number of trees (0 disables)"},
|
||
|
};
|
||
|
|
||
|
ModeSpecOpt fire_opts =
|
||
|
{ sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc };
|
||
|
|
||
|
#ifdef USE_MODULES
|
||
|
ModStruct fire_description =
|
||
|
{ "fire", "init_fire", "draw_fire", "release_fire",
|
||
|
"draw_fire", "change_fire", (char *) NULL, &fire_opts,
|
||
|
10000, 800, 1, 0, 64, 1.0, "",
|
||
|
"Shows a 3D fire-like image", 0, NULL
|
||
|
};
|
||
|
#endif /* USE_MODULES */
|
||
|
|
||
|
/* misc defines */
|
||
|
#define TREEINR 2.5 /* tree min distance */
|
||
|
#define TREEOUTR 8.0 /* tree max distance */
|
||
|
#define FRAME 50 /* frame count interval */
|
||
|
#define DIMP 20.0 /* dimension of ground */
|
||
|
#define DIMTP 16.0 /* dimension of ground texture */
|
||
|
|
||
|
#define RIDCOL 0.4 /* factor for color blending */
|
||
|
|
||
|
#define AGRAV -9.8 /* gravity */
|
||
|
|
||
|
#define NUMPART 7500 /* rain particles */
|
||
|
|
||
|
/* fire particle struct */
|
||
|
typedef struct {
|
||
|
int age;
|
||
|
float p[3][3];
|
||
|
float v[3];
|
||
|
float c[3][4];
|
||
|
} part;
|
||
|
|
||
|
/* rain particle struct */
|
||
|
typedef struct {
|
||
|
float age;
|
||
|
float acc[3];
|
||
|
float vel[3];
|
||
|
float pos[3];
|
||
|
float partLength;
|
||
|
float oldpos[3];
|
||
|
} rain;
|
||
|
|
||
|
/* colors */
|
||
|
static float black[3] = { 0.0, 0.0, 0.0 }; /* shadow color */
|
||
|
static float partcol1[3] = { 1.0, 0.2, 0.0 }; /* initial color: red-ish */
|
||
|
static float partcol2[3] = { 1.0, 1.0, 0.0 }; /* blending color: yellow-ish */
|
||
|
static float fogcolor[4] = { 0.9, 0.9, 1.0, 1.0 };
|
||
|
|
||
|
/* ground */
|
||
|
static float q[4][3] = {
|
||
|
{-DIMP, 0.0, -DIMP},
|
||
|
{DIMP, 0.0, -DIMP},
|
||
|
{DIMP, 0.0, DIMP},
|
||
|
{-DIMP, 0.0, DIMP}
|
||
|
};
|
||
|
|
||
|
/* ground texture */
|
||
|
static float qt[4][2] = {
|
||
|
{-DIMTP, -DIMTP},
|
||
|
{DIMTP, -DIMTP},
|
||
|
{DIMTP, DIMTP},
|
||
|
{-DIMTP, DIMTP}
|
||
|
};
|
||
|
|
||
|
/* default values for observer */
|
||
|
static const float DEF_OBS[3] = { 2.0f, 1.0f, 0.0f };
|
||
|
#define DEV_V 0.0
|
||
|
#define DEF_ALPHA -90.0
|
||
|
#define DEF_BETA 90.0
|
||
|
|
||
|
/* tree struct */
|
||
|
typedef struct {
|
||
|
float x,y,z;
|
||
|
} treestruct;
|
||
|
|
||
|
/* the mode struct, contains all per screen variables */
|
||
|
typedef struct {
|
||
|
GLint WIDTH, HEIGHT; /* display dimensions */
|
||
|
GLXContext *glx_context;
|
||
|
|
||
|
int np; /* number of fire particles : set it through 'count' resource */
|
||
|
float eject_r; /* emission radius */
|
||
|
float dt, maxage, eject_vy, eject_vl;
|
||
|
float ridtri; /* fire particle size */
|
||
|
Bool shadows; /* misc booleans: set them through specific resources */
|
||
|
Bool fog;
|
||
|
|
||
|
part *p; /* fire particles array */
|
||
|
rain *r; /* rain particles array */
|
||
|
|
||
|
XImage *gtexture; /* ground texture image bits */
|
||
|
XImage *ttexture; /* tree texture image bits */
|
||
|
GLuint groundid; /* ground texture id: GL world */
|
||
|
GLuint treeid; /* tree texture id: GL world */
|
||
|
GLuint fontbase; /* fontbase id: GL world */
|
||
|
|
||
|
int num_trees; /* number of trees: set it through 'trees' resource */
|
||
|
treestruct *treepos; /* trees positions: float treepos[num_trees][3] */
|
||
|
|
||
|
float min[3]; /* raining area */
|
||
|
float max[3];
|
||
|
|
||
|
float obs[3]; /* observer coordinates */
|
||
|
float dir[3]; /* view direction */
|
||
|
float v; /* observer velocity */
|
||
|
float alpha; /* observer angles */
|
||
|
float beta;
|
||
|
} firestruct;
|
||
|
|
||
|
/* array of firestruct indexed by screen number */
|
||
|
static firestruct *fire = (firestruct *) NULL;
|
||
|
|
||
|
/*
|
||
|
*-----------------------------------------------------------------------------
|
||
|
*-----------------------------------------------------------------------------
|
||
|
* Misc funcs.
|
||
|
*-----------------------------------------------------------------------------
|
||
|
*-----------------------------------------------------------------------------
|
||
|
*/
|
||
|
|
||
|
/* utility function for the rain particles */
|
||
|
static float gettimerain(void)
|
||
|
{
|
||
|
static clock_t told=0;
|
||
|
clock_t tnew,ris;
|
||
|
|
||
|
tnew=clock();
|
||
|
|
||
|
ris=tnew-told;
|
||
|
|
||
|
told=tnew;
|
||
|
|
||
|
return (ris/(float)CLOCKS_PER_SEC);
|
||
|
}
|
||
|
|
||
|
/* my RAND */
|
||
|
static float vrnd(void)
|
||
|
{
|
||
|
return ((float) LRAND() / (float) MAXRAND);
|
||
|
}
|
||
|
|
||
|
/* initialise new fire particle */
|
||
|
static void setnewpart(firestruct * fs, part * p)
|
||
|
{
|
||
|
float a, vi[3], *c;
|
||
|
|
||
|
p->age = 0;
|
||
|
|
||
|
a = vrnd() * M_PI * 2.0;
|
||
|
|
||
|
vinit(vi, sin(a) * fs->eject_r * vrnd(), 0.15, cos(a) * fs->eject_r * vrnd());
|
||
|
vinit(p->p[0], vi[0] + vrnd() * fs->ridtri, vi[1] + vrnd() * fs->ridtri, vi[2] + vrnd() * fs->ridtri);
|
||
|
vinit(p->p[1], vi[0] + vrnd() * fs->ridtri, vi[1] + vrnd() * fs->ridtri, vi[2] + vrnd() * fs->ridtri);
|
||
|
vinit(p->p[2], vi[0] + vrnd() * fs->ridtri, vi[1] + vrnd() * fs->ridtri, vi[2] + vrnd() * fs->ridtri);
|
||
|
|
||
|
vinit(p->v, vi[0] * fs->eject_vl / (fs->eject_r / 2),
|
||
|
vrnd() * fs->eject_vy + fs->eject_vy / 2,
|
||
|
vi[2] * fs->eject_vl / (fs->eject_r / 2));
|
||
|
|
||
|
c = partcol1;
|
||
|
|
||
|
vinit4(p->c[0], c[0] * ((1.0 - RIDCOL) + vrnd() * RIDCOL),
|
||
|
c[1] * ((1.0 - RIDCOL) + vrnd() * RIDCOL),
|
||
|
c[2] * ((1.0 - RIDCOL) + vrnd() * RIDCOL), 1.0);
|
||
|
vinit4(p->c[1], c[0] * ((1.0 - RIDCOL) + vrnd() * RIDCOL),
|
||
|
c[1] * ((1.0 - RIDCOL) + vrnd() * RIDCOL),
|
||
|
c[2] * ((1.0 - RIDCOL) + vrnd() * RIDCOL), 1.0);
|
||
|
vinit4(p->c[2], c[0] * ((1.0 - RIDCOL) + vrnd() * RIDCOL),
|
||
|
c[1] * ((1.0 - RIDCOL) + vrnd() * RIDCOL),
|
||
|
c[2] * ((1.0 - RIDCOL) + vrnd() * RIDCOL), 1.0);
|
||
|
}
|
||
|
|
||
|
/* initialise new rain particle */
|
||
|
static void setnewrain(firestruct * fs, rain * r)
|
||
|
{
|
||
|
r->age=0.0f;
|
||
|
|
||
|
vinit(r->acc,0.0f,-0.98f,0.0f);
|
||
|
vinit(r->vel,0.0f,0.0f,0.0f);
|
||
|
|
||
|
r->partLength=0.2f;
|
||
|
|
||
|
vinit(r->oldpos,fs->min[0]+(fs->max[0]-fs->min[0])*vrnd(),
|
||
|
fs->max[1]+0.2f*fs->max[1]*vrnd(),
|
||
|
fs->min[2]+(fs->max[2]-fs->min[2])*vrnd());
|
||
|
vequ(r->pos,r->oldpos);
|
||
|
vadds(r->oldpos,-(r->partLength),r->vel);
|
||
|
|
||
|
r->pos[1]=(fs->max[1]-fs->min[1])*vrnd()+fs->min[1];
|
||
|
r->oldpos[1]=r->pos[1]-r->partLength*r->vel[1];
|
||
|
}
|
||
|
|
||
|
/* set fire particle values */
|
||
|
static void setpart(firestruct * fs, part * p)
|
||
|
{
|
||
|
float fact;
|
||
|
|
||
|
if (p->p[0][1] < 0.1) {
|
||
|
setnewpart(fs, p);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
p->v[1] += AGRAV * fs->dt;
|
||
|
|
||
|
vadds(p->p[0], fs->dt, p->v);
|
||
|
vadds(p->p[1], fs->dt, p->v);
|
||
|
vadds(p->p[2], fs->dt, p->v);
|
||
|
|
||
|
p->age++;
|
||
|
|
||
|
if ((p->age) > fs->maxage) {
|
||
|
vequ(p->c[0], partcol2);
|
||
|
vequ(p->c[1], partcol2);
|
||
|
vequ(p->c[2], partcol2);
|
||
|
} else {
|
||
|
fact = 1.0 / fs->maxage;
|
||
|
vadds(p->c[0], fact, partcol2);
|
||
|
vclamp(p->c[0]);
|
||
|
p->c[0][3] = fact * (fs->maxage - p->age);
|
||
|
|
||
|
vadds(p->c[1], fact, partcol2);
|
||
|
vclamp(p->c[1]);
|
||
|
p->c[1][3] = fact * (fs->maxage - p->age);
|
||
|
|
||
|
vadds(p->c[2], fact, partcol2);
|
||
|
vclamp(p->c[2]);
|
||
|
p->c[2][3] = fact * (fs->maxage - p->age);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* set rain particle values */
|
||
|
static void setpartrain(firestruct * fs, rain * r, float dt)
|
||
|
{
|
||
|
r->age += dt;
|
||
|
|
||
|
vadds(r->vel,dt,r->acc);
|
||
|
vadds(r->pos,dt,r->vel);
|
||
|
|
||
|
if(r->pos[0]<fs->min[0])
|
||
|
r->pos[0]=fs->max[0]-(fs->min[0]-r->pos[0]);
|
||
|
if(r->pos[2]<fs->min[2])
|
||
|
r->pos[2]=fs->max[2]-(fs->min[2]-r->pos[2]);
|
||
|
|
||
|
if(r->pos[0]>fs->max[0])
|
||
|
r->pos[0]=fs->min[0]+(r->pos[0]-fs->max[0]);
|
||
|
if(r->pos[2]>fs->max[2])
|
||
|
r->pos[2]=fs->min[2]+(r->pos[2]-fs->max[2]);
|
||
|
|
||
|
vequ(r->oldpos,r->pos);
|
||
|
vadds(r->oldpos,-(r->partLength),r->vel);
|
||
|
if(r->pos[1]<fs->min[1])
|
||
|
setnewrain(fs, r);
|
||
|
}
|
||
|
|
||
|
/* draw a tree */
|
||
|
static void drawtree(float x, float y, float z)
|
||
|
{
|
||
|
glBegin(GL_QUADS);
|
||
|
glTexCoord2f(0.0,0.0);
|
||
|
glVertex3f(x-1.5,y+0.0,z);
|
||
|
|
||
|
glTexCoord2f(1.0,0.0);
|
||
|
glVertex3f(x+1.5,y+0.0,z);
|
||
|
|
||
|
glTexCoord2f(1.0,1.0);
|
||
|
glVertex3f(x+1.5,y+3.0,z);
|
||
|
|
||
|
glTexCoord2f(0.0,1.0);
|
||
|
glVertex3f(x-1.5,y+3.0,z);
|
||
|
|
||
|
|
||
|
glTexCoord2f(0.0,0.0);
|
||
|
glVertex3f(x,y+0.0,z-1.5);
|
||
|
|
||
|
glTexCoord2f(1.0,0.0);
|
||
|
glVertex3f(x,y+0.0,z+1.5);
|
||
|
|
||
|
glTexCoord2f(1.0,1.0);
|
||
|
glVertex3f(x,y+3.0,z+1.5);
|
||
|
|
||
|
glTexCoord2f(0.0,1.0);
|
||
|
glVertex3f(x,y+3.0,z-1.5);
|
||
|
|
||
|
glEnd();
|
||
|
|
||
|
}
|
||
|
|
||
|
/* calculate observer position : modified only if trackmouse is used */
|
||
|
static void calcposobs(firestruct * fs)
|
||
|
{
|
||
|
fs->dir[0] = sin(fs->alpha * M_PI / 180.0);
|
||
|
fs->dir[2] =
|
||
|
cos(fs->alpha * M_PI / 180.0) * sin(fs->beta * M_PI / 180.0);
|
||
|
fs->dir[1] = cos(fs->beta * M_PI / 180.0);
|
||
|
|
||
|
fs->obs[0] += fs->v * fs->dir[0];
|
||
|
fs->obs[1] += fs->v * fs->dir[1];
|
||
|
fs->obs[2] += fs->v * fs->dir[2];
|
||
|
|
||
|
if (!fs->np)
|
||
|
{
|
||
|
vinit(fs->min,fs->obs[0]-7.0f,-0.2f,fs->obs[2]-7.0f);
|
||
|
vinit(fs->max,fs->obs[0]+7.0f,8.0f,fs->obs[2]+7.0f);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* track the mouse in a joystick manner : not perfect but it works */
|
||
|
static void trackmouse(ModeInfo * mi)
|
||
|
{
|
||
|
firestruct *fs = &fire[MI_SCREEN(mi)];
|
||
|
/* we keep static values (not per screen) for the mouse stuff: in general you have only one mouse :-> */
|
||
|
static int max[2] = { 0, 0 };
|
||
|
static int min[2] = { 0x7fffffff, 0x7fffffff }, center[2];
|
||
|
Window r, c;
|
||
|
int rx, ry, cx, cy;
|
||
|
unsigned int m;
|
||
|
|
||
|
(void) XQueryPointer(MI_DISPLAY(mi), MI_WINDOW(mi),
|
||
|
&r, &c, &rx, &ry, &cx, &cy, &m);
|
||
|
|
||
|
if (max[0] < cx)
|
||
|
max[0] = cx;
|
||
|
if (min[0] > cx)
|
||
|
min[0] = cx;
|
||
|
center[0] = (max[0] + min[0]) / 2;
|
||
|
|
||
|
if (max[1] < cy)
|
||
|
max[1] = cy;
|
||
|
if (min[1] > cy)
|
||
|
min[1] = cy;
|
||
|
center[1] = (max[1] + min[1]) / 2;
|
||
|
|
||
|
if (fabs(center[0] - (float) cx) > 0.1 * (max[0] - min[0]))
|
||
|
fs->alpha += 2.5 * (center[0] - (float) cx) / (max[0] - min[0]);
|
||
|
if (fabs(center[1] - (float) cy) > 0.1 * (max[1] - min[1]))
|
||
|
fs->beta += 2.5 * (center[1] - (float) cy) / (max[1] - min[1]);
|
||
|
|
||
|
/* oops: can't get those buttons */
|
||
|
if (m & Button4Mask)
|
||
|
fs->v += 0.01;
|
||
|
if (m & Button5Mask)
|
||
|
fs->v -= 0.01;
|
||
|
|
||
|
}
|
||
|
|
||
|
/* initialise textures */
|
||
|
static void inittextures(ModeInfo * mi)
|
||
|
{
|
||
|
firestruct *fs = &fire[MI_SCREEN(mi)];
|
||
|
|
||
|
#ifdef HAVE_XPM
|
||
|
if (do_texture) {
|
||
|
|
||
|
glGenTextures(1, &fs->groundid);
|
||
|
#ifdef HAVE_GLBINDTEXTURE
|
||
|
glBindTexture(GL_TEXTURE_2D, fs->groundid);
|
||
|
#endif /* HAVE_GLBINDTEXTURE */
|
||
|
|
||
|
if ((fs->gtexture = xpm_to_ximage(MI_DISPLAY(mi), MI_VISUAL(mi),
|
||
|
MI_COLORMAP(mi), ground)) == None) {
|
||
|
(void) fprintf(stderr, "Error reading the ground texture.\n");
|
||
|
glDeleteTextures(1, &fs->groundid);
|
||
|
do_texture = False;
|
||
|
fs->groundid = 0;
|
||
|
fs->treeid = 0;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
|
||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
|
||
|
fs->gtexture->width, fs->gtexture->height, 0,
|
||
|
GL_RGBA, GL_UNSIGNED_BYTE, fs->gtexture->data);
|
||
|
|
||
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||
|
|
||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||
|
|
||
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
|
||
|
|
||
|
if (fs->num_trees)
|
||
|
{
|
||
|
glGenTextures(1, &fs->treeid);
|
||
|
#ifdef HAVE_GLBINDTEXTURE
|
||
|
glBindTexture(GL_TEXTURE_2D,fs->treeid);
|
||
|
#endif /* HAVE_GLBINDTEXTURE */
|
||
|
if ((fs->ttexture = xpm_to_ximage(MI_DISPLAY(mi), MI_VISUAL(mi),
|
||
|
MI_COLORMAP(mi), tree)) == None) {
|
||
|
(void)fprintf(stderr,"Error reading tree texture.\n");
|
||
|
glDeleteTextures(1, &fs->treeid);
|
||
|
fs->treeid = 0;
|
||
|
fs->num_trees = 0;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
|
||
|
fs->ttexture->width, fs->ttexture->height, 0,
|
||
|
GL_RGBA, GL_UNSIGNED_BYTE, fs->ttexture->data);
|
||
|
|
||
|
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
|
||
|
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
|
||
|
|
||
|
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
|
||
|
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
|
||
|
|
||
|
glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
fs->groundid = 0; /* default textures */
|
||
|
fs->treeid = 0;
|
||
|
}
|
||
|
#else /* !HAVE_XPM */
|
||
|
do_texture = False;
|
||
|
fs->groundid = 0; /* default textures */
|
||
|
fs->treeid = 0;
|
||
|
#endif /* !HAVE_XPM */
|
||
|
}
|
||
|
|
||
|
/* init tree array and positions */
|
||
|
static Bool inittree(ModeInfo * mi)
|
||
|
{
|
||
|
firestruct *fs = &fire[MI_SCREEN(mi)];
|
||
|
int i;
|
||
|
float dist;
|
||
|
|
||
|
/* allocate treepos array */
|
||
|
if ((fs->treepos = (treestruct *) malloc(fs->num_trees *
|
||
|
sizeof(treestruct))) == NULL) {
|
||
|
return False;
|
||
|
}
|
||
|
/* initialise positions */
|
||
|
for(i=0;i<fs->num_trees;i++)
|
||
|
do {
|
||
|
fs->treepos[i].x =vrnd()*TREEOUTR*2.0-TREEOUTR;
|
||
|
fs->treepos[i].y =0.0;
|
||
|
fs->treepos[i].z =vrnd()*TREEOUTR*2.0-TREEOUTR;
|
||
|
dist=sqrt(fs->treepos[i].x *fs->treepos[i].x +fs->treepos[i].z *fs->treepos[i].z );
|
||
|
} while((dist<TREEINR) || (dist>TREEOUTR));
|
||
|
return True;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
*-----------------------------------------------------------------------------
|
||
|
*-----------------------------------------------------------------------------
|
||
|
* GL funcs.
|
||
|
*-----------------------------------------------------------------------------
|
||
|
*-----------------------------------------------------------------------------
|
||
|
*/
|
||
|
|
||
|
#ifndef STANDALONE
|
||
|
static void Reshape(ModeInfo * mi)
|
||
|
#else
|
||
|
void reshape_fire(ModeInfo * mi, int width, int height)
|
||
|
#endif
|
||
|
{
|
||
|
|
||
|
firestruct *fs = &fire[MI_SCREEN(mi)];
|
||
|
int size = MI_SIZE(mi);
|
||
|
|
||
|
/* Viewport is specified size if size >= MINSIZE && size < screensize */
|
||
|
if (size <= 1) {
|
||
|
fs->WIDTH = MI_WIDTH(mi);
|
||
|
fs->HEIGHT = MI_HEIGHT(mi);
|
||
|
} else if (size < MINSIZE) {
|
||
|
fs->WIDTH = MINSIZE;
|
||
|
fs->HEIGHT = MINSIZE;
|
||
|
} else {
|
||
|
fs->WIDTH = (size > MI_WIDTH(mi)) ? MI_WIDTH(mi) : size;
|
||
|
fs->HEIGHT = (size > MI_HEIGHT(mi)) ? MI_HEIGHT(mi) : size;
|
||
|
}
|
||
|
glViewport((MI_WIDTH(mi) - fs->WIDTH) / 2, (MI_HEIGHT(mi) - fs->HEIGHT) / 2, fs->WIDTH, fs->HEIGHT);
|
||
|
glMatrixMode(GL_PROJECTION);
|
||
|
glLoadIdentity();
|
||
|
gluPerspective(70.0, fs->WIDTH / (float) fs->HEIGHT, 0.1, 30.0);
|
||
|
|
||
|
glMatrixMode(GL_MODELVIEW);
|
||
|
|
||
|
}
|
||
|
|
||
|
static void DrawFire(ModeInfo * mi)
|
||
|
{
|
||
|
int j;
|
||
|
firestruct *fs = &fire[MI_SCREEN(mi)];
|
||
|
Bool wire = MI_IS_WIREFRAME(mi);
|
||
|
|
||
|
if (do_trackmouse && !MI_IS_ICONIC(mi))
|
||
|
trackmouse(mi);
|
||
|
|
||
|
if (do_wander)
|
||
|
{
|
||
|
GLfloat x, y, z;
|
||
|
|
||
|
# define SINOID(SCALE,SIZE) \
|
||
|
((((1 + sin((frame * (SCALE)) / 2 * M_PI)) / 2.0) * (SIZE)) - (SIZE)/2)
|
||
|
|
||
|
x = SINOID(0.031, 0.85);
|
||
|
y = SINOID(0.017, 0.25);
|
||
|
z = SINOID(0.023, 0.85);
|
||
|
frame++;
|
||
|
fs->obs[0] = x + DEF_OBS[0];
|
||
|
fs->obs[1] = y + DEF_OBS[1];
|
||
|
fs->obs[2] = z + DEF_OBS[2];
|
||
|
fs->dir[1] = y;
|
||
|
fs->dir[2] = z;
|
||
|
}
|
||
|
|
||
|
glEnable(GL_DEPTH_TEST);
|
||
|
|
||
|
if (fs->fog)
|
||
|
glEnable(GL_FOG);
|
||
|
else
|
||
|
glDisable(GL_FOG);
|
||
|
|
||
|
glDepthMask(GL_TRUE);
|
||
|
glClearColor(0.5, 0.5, 0.8, 1.0); /* sky in the distance */
|
||
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||
|
|
||
|
glPushMatrix();
|
||
|
calcposobs(fs);
|
||
|
gluLookAt(fs->obs[0], fs->obs[1], fs->obs[2],
|
||
|
fs->obs[0] + fs->dir[0], fs->obs[1] + fs->dir[1],
|
||
|
fs->obs[2] + fs->dir[2], 0.0, 1.0, 0.0);
|
||
|
|
||
|
|
||
|
glEnable(GL_TEXTURE_2D);
|
||
|
|
||
|
/* draw ground using the computed texture */
|
||
|
if (do_texture) {
|
||
|
glColor4f(1.0,1.0,1.0,1.0); /* white to get texture in it's true color */
|
||
|
#ifdef HAVE_GLBINDTEXTURE
|
||
|
glBindTexture(GL_TEXTURE_2D, fs->groundid);
|
||
|
#endif /* HAVE_GLBINDTEXTURE */
|
||
|
}
|
||
|
else
|
||
|
glColor4f(0.54, 0.27, 0.07, 1.0); /* untextured ground color */
|
||
|
glBegin(GL_QUADS);
|
||
|
glTexCoord2fv(qt[0]);
|
||
|
glVertex3fv(q[0]);
|
||
|
glTexCoord2fv(qt[1]);
|
||
|
glVertex3fv(q[1]);
|
||
|
glTexCoord2fv(qt[2]);
|
||
|
glVertex3fv(q[2]);
|
||
|
glTexCoord2fv(qt[3]);
|
||
|
glVertex3fv(q[3]);
|
||
|
glEnd();
|
||
|
|
||
|
glAlphaFunc(GL_GEQUAL, 0.9);
|
||
|
if (fs->num_trees)
|
||
|
{
|
||
|
/* here do_texture IS True - and color used is white */
|
||
|
glEnable(GL_ALPHA_TEST);
|
||
|
#ifdef HAVE_GLBINDTEXTURE
|
||
|
glBindTexture(GL_TEXTURE_2D,fs->treeid);
|
||
|
#endif /* HAVE_GLBINDTEXTURE */
|
||
|
for(j=0;j<fs->num_trees;j++)
|
||
|
drawtree(fs->treepos[j].x ,fs->treepos[j].y ,fs->treepos[j].z );
|
||
|
glDisable(GL_ALPHA_TEST);
|
||
|
}
|
||
|
glDisable(GL_TEXTURE_2D);
|
||
|
glDepthMask(GL_FALSE);
|
||
|
|
||
|
if (fs->shadows) {
|
||
|
/* draw shadows with black color */
|
||
|
glBegin(wire ? GL_LINE_STRIP : GL_TRIANGLES);
|
||
|
for (j = 0; j < fs->np; j++) {
|
||
|
glColor4f(black[0], black[1], black[2], fs->p[j].c[0][3]);
|
||
|
glVertex3f(fs->p[j].p[0][0], 0.1, fs->p[j].p[0][2]);
|
||
|
|
||
|
glColor4f(black[0], black[1], black[2], fs->p[j].c[1][3]);
|
||
|
glVertex3f(fs->p[j].p[1][0], 0.1, fs->p[j].p[1][2]);
|
||
|
|
||
|
glColor4f(black[0], black[1], black[2], fs->p[j].c[2][3]);
|
||
|
glVertex3f(fs->p[j].p[2][0], 0.1, fs->p[j].p[2][2]);
|
||
|
}
|
||
|
glEnd();
|
||
|
}
|
||
|
|
||
|
glBegin(wire ? GL_LINE_STRIP : GL_TRIANGLES);
|
||
|
for (j = 0; j < fs->np; j++) {
|
||
|
/* draw particles: colors are computed in setpart */
|
||
|
glColor4fv(fs->p[j].c[0]);
|
||
|
glVertex3fv(fs->p[j].p[0]);
|
||
|
|
||
|
glColor4fv(fs->p[j].c[1]);
|
||
|
glVertex3fv(fs->p[j].p[1]);
|
||
|
|
||
|
glColor4fv(fs->p[j].c[2]);
|
||
|
glVertex3fv(fs->p[j].p[2]);
|
||
|
|
||
|
setpart(fs, &fs->p[j]);
|
||
|
}
|
||
|
glEnd();
|
||
|
|
||
|
/* draw rain particles if no fire particles */
|
||
|
if (!fs->np)
|
||
|
{
|
||
|
float timeused = gettimerain();
|
||
|
glDisable(GL_TEXTURE_2D);
|
||
|
glShadeModel(GL_SMOOTH);
|
||
|
glBegin(GL_LINES);
|
||
|
for (j = 0; j < NUMPART; j++) {
|
||
|
glColor4f(0.7f,0.95f,1.0f,0.0f);
|
||
|
glVertex3fv(fs->r[j].oldpos);
|
||
|
glColor4f(0.3f,0.7f,1.0f,1.0f);
|
||
|
glVertex3fv(fs->r[j].pos);
|
||
|
setpartrain(fs, &fs->r[j],timeused);
|
||
|
}
|
||
|
glEnd();
|
||
|
glShadeModel(GL_FLAT);
|
||
|
}
|
||
|
|
||
|
glDisable(GL_TEXTURE_2D);
|
||
|
glDisable(GL_ALPHA_TEST);
|
||
|
glDisable(GL_DEPTH_TEST);
|
||
|
glDisable(GL_FOG);
|
||
|
|
||
|
/* manage framerate display */
|
||
|
if (MI_IS_FPS(mi)) do_fps (mi);
|
||
|
glPopMatrix();
|
||
|
}
|
||
|
|
||
|
|
||
|
static Bool Init(ModeInfo * mi)
|
||
|
{
|
||
|
int i;
|
||
|
firestruct *fs = &fire[MI_SCREEN(mi)];
|
||
|
|
||
|
/* default settings */
|
||
|
fs->eject_r = 0.1 + NRAND(10) * 0.03;
|
||
|
fs->dt = 0.015;
|
||
|
fs->eject_vy = 4;
|
||
|
fs->eject_vl = 1;
|
||
|
fs->ridtri = 0.1 + NRAND(10) * 0.005;
|
||
|
fs->maxage = 1.0 / fs->dt;
|
||
|
vinit(fs->obs, DEF_OBS[0], DEF_OBS[1], DEF_OBS[2]);
|
||
|
fs->v = 0.0;
|
||
|
fs->alpha = DEF_ALPHA;
|
||
|
fs->beta = DEF_BETA;
|
||
|
|
||
|
/* initialise texture stuff */
|
||
|
if (do_texture)
|
||
|
inittextures(mi);
|
||
|
else
|
||
|
{
|
||
|
fs->ttexture = (XImage*) NULL;
|
||
|
fs->gtexture = (XImage*) NULL;
|
||
|
}
|
||
|
|
||
|
if (MI_IS_DEBUG(mi)) {
|
||
|
(void) fprintf(stderr,
|
||
|
"%s:\n\tnum_part=%d\n\ttrees=%d\n\tfog=%s\n\tshadows=%s\n\teject_r=%.3f\n\tridtri=%.3f\n",
|
||
|
MI_NAME(mi),
|
||
|
fs->np,
|
||
|
fs->num_trees,
|
||
|
fs->fog ? "on" : "off",
|
||
|
fs->shadows ? "on" : "off",
|
||
|
fs->eject_r, fs->ridtri);
|
||
|
}
|
||
|
|
||
|
glShadeModel(GL_FLAT);
|
||
|
glEnable(GL_DEPTH_TEST);
|
||
|
|
||
|
/* makes particles blend with background */
|
||
|
if (!MI_IS_WIREFRAME(mi)||(!fs->np))
|
||
|
{
|
||
|
glEnable(GL_BLEND);
|
||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||
|
}
|
||
|
|
||
|
/* fog stuff */
|
||
|
glEnable(GL_FOG);
|
||
|
glFogi(GL_FOG_MODE, GL_EXP);
|
||
|
glFogfv(GL_FOG_COLOR, fogcolor);
|
||
|
glFogf(GL_FOG_DENSITY, 0.03);
|
||
|
glHint(GL_FOG_HINT, GL_NICEST);
|
||
|
|
||
|
/* initialise particles and trees */
|
||
|
for (i = 0; i < fs->np; i++) {
|
||
|
setnewpart(fs, &(fs->p[i]));
|
||
|
}
|
||
|
|
||
|
if (fs->num_trees)
|
||
|
if (!inittree(mi)) {
|
||
|
return False;
|
||
|
}
|
||
|
|
||
|
/* if no fire particles then initialise rain particles */
|
||
|
if (!fs->np)
|
||
|
{
|
||
|
vinit(fs->min,-7.0f,-0.2f,-7.0f);
|
||
|
vinit(fs->max,7.0f,8.0f,7.0f);
|
||
|
for (i = 0; i < NUMPART; i++) {
|
||
|
setnewrain(fs, &(fs->r[i]));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return True;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
*-----------------------------------------------------------------------------
|
||
|
*-----------------------------------------------------------------------------
|
||
|
* Xlock hooks.
|
||
|
*-----------------------------------------------------------------------------
|
||
|
*-----------------------------------------------------------------------------
|
||
|
*/
|
||
|
|
||
|
|
||
|
static void
|
||
|
free_fire(firestruct *fs)
|
||
|
{
|
||
|
if (mode_font != None && fs->fontbase != None) {
|
||
|
glDeleteLists(fs->fontbase, mode_font->max_char_or_byte2 -
|
||
|
mode_font->min_char_or_byte2 + 1);
|
||
|
fs->fontbase = None;
|
||
|
}
|
||
|
|
||
|
if (fs->p != NULL) {
|
||
|
free(fs->p);
|
||
|
fs->p = (part *) NULL;
|
||
|
}
|
||
|
if (fs->r != NULL) {
|
||
|
free(fs->r);
|
||
|
fs->r = (rain *) NULL;
|
||
|
}
|
||
|
if (fs->treepos != NULL) {
|
||
|
free(fs->treepos);
|
||
|
fs->treepos = (treestruct *) NULL;
|
||
|
}
|
||
|
if (fs->ttexture != None) {
|
||
|
glDeleteTextures(1, &fs->treeid);
|
||
|
XDestroyImage(fs->ttexture);
|
||
|
fs->ttexture = None;
|
||
|
}
|
||
|
if (fs->gtexture != None) {
|
||
|
glDeleteTextures(1, &fs->groundid);
|
||
|
XDestroyImage(fs->gtexture);
|
||
|
fs->gtexture = None;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
*-----------------------------------------------------------------------------
|
||
|
* Initialize fire. Called each time the window changes.
|
||
|
*-----------------------------------------------------------------------------
|
||
|
*/
|
||
|
|
||
|
void
|
||
|
init_fire(ModeInfo * mi)
|
||
|
{
|
||
|
firestruct *fs;
|
||
|
|
||
|
/* allocate the main fire table if needed */
|
||
|
if (fire == NULL) {
|
||
|
if ((fire = (firestruct *) calloc(MI_NUM_SCREENS(mi),
|
||
|
sizeof(firestruct))) == NULL)
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* initialise the per screen fire structure */
|
||
|
fs = &fire[MI_SCREEN(mi)];
|
||
|
fs->np = MI_COUNT(mi);
|
||
|
fs->fog = do_fog;
|
||
|
fs->shadows = do_shadows;
|
||
|
/* initialise fire particles if any */
|
||
|
if ((fs->np)&&(fs->p == NULL)) {
|
||
|
if ((fs->p = (part *) calloc(fs->np, sizeof(part))) == NULL) {
|
||
|
free_fire(fs);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
else if (fs->r == NULL) {
|
||
|
/* initialise rain particles if no fire particles */
|
||
|
if ((fs->r = (rain *) calloc(NUMPART, sizeof(part))) == NULL) {
|
||
|
free_fire(fs);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* check tree number */
|
||
|
if (do_texture)
|
||
|
fs->num_trees = (num_trees<MAX_TREES)?num_trees:MAX_TREES;
|
||
|
else
|
||
|
fs->num_trees = 0;
|
||
|
|
||
|
/* check wander/trackmouse */
|
||
|
if (do_trackmouse && do_wander) do_wander = 0;
|
||
|
|
||
|
/* xlock GL stuff */
|
||
|
if ((fs->glx_context = init_GL(mi)) != NULL) {
|
||
|
|
||
|
#ifndef STANDALONE
|
||
|
Reshape(mi); /* xlock mode */
|
||
|
#else
|
||
|
reshape_fire(mi,MI_WIDTH(mi),MI_HEIGHT(mi)); /* xscreensaver mode */
|
||
|
#endif
|
||
|
glDrawBuffer(GL_BACK);
|
||
|
if (!Init(mi)) {
|
||
|
free_fire(fs);
|
||
|
return;
|
||
|
}
|
||
|
} else {
|
||
|
MI_CLEARWINDOW(mi);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
*-----------------------------------------------------------------------------
|
||
|
* Called by the mainline code periodically to update the display.
|
||
|
*-----------------------------------------------------------------------------
|
||
|
*/
|
||
|
void draw_fire(ModeInfo * mi)
|
||
|
{
|
||
|
firestruct *fs = &fire[MI_SCREEN(mi)];
|
||
|
|
||
|
Display *display = MI_DISPLAY(mi);
|
||
|
Window window = MI_WINDOW(mi);
|
||
|
|
||
|
MI_IS_DRAWN(mi) = True;
|
||
|
|
||
|
if (!fs->glx_context)
|
||
|
return;
|
||
|
|
||
|
glXMakeCurrent(display, window, *(fs->glx_context));
|
||
|
DrawFire(mi);
|
||
|
#ifndef STANDALONE
|
||
|
Reshape(mi); /* xlock mode */
|
||
|
#else
|
||
|
reshape_fire(mi,MI_WIDTH(mi),MI_HEIGHT(mi)); /* xscreensaver mode */
|
||
|
#endif
|
||
|
|
||
|
glFinish();
|
||
|
glXSwapBuffers(display, window);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
*-----------------------------------------------------------------------------
|
||
|
* The display is being taken away from us. Free up malloc'ed
|
||
|
* memory and X resources that we've alloc'ed. Only called
|
||
|
* once, we must zap everything for every screen.
|
||
|
*-----------------------------------------------------------------------------
|
||
|
*/
|
||
|
|
||
|
void release_fire(ModeInfo * mi)
|
||
|
{
|
||
|
if (fire != NULL) {
|
||
|
int screen;
|
||
|
for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
|
||
|
free_fire(&fire[screen]);
|
||
|
free(fire);
|
||
|
fire = (firestruct *) NULL;
|
||
|
}
|
||
|
if (mode_font != None)
|
||
|
{
|
||
|
/* only free-ed when there are no more screens used */
|
||
|
XFreeFont(MI_DISPLAY(mi), mode_font);
|
||
|
mode_font = None;
|
||
|
}
|
||
|
FreeAllGL(mi);
|
||
|
}
|
||
|
|
||
|
void change_fire(ModeInfo * mi)
|
||
|
{
|
||
|
firestruct *fs = &fire[MI_SCREEN(mi)];
|
||
|
|
||
|
if (!fs->glx_context)
|
||
|
return;
|
||
|
|
||
|
glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(fs->glx_context));
|
||
|
|
||
|
/* if available, randomly change some values */
|
||
|
if (do_fog)
|
||
|
fs->fog = LRAND() & 1;
|
||
|
if (do_shadows)
|
||
|
fs->shadows = LRAND() & 1;
|
||
|
/* reset observer position */
|
||
|
frame = 0;
|
||
|
vinit(fs->obs, DEF_OBS[0], DEF_OBS[1], DEF_OBS[2]);
|
||
|
fs->v = 0.0;
|
||
|
/* particle randomisation */
|
||
|
fs->eject_r = 0.1 + NRAND(10) * 0.03;
|
||
|
fs->ridtri = 0.1 + NRAND(10) * 0.005;
|
||
|
|
||
|
if (MI_IS_DEBUG(mi)) {
|
||
|
(void) fprintf(stderr,
|
||
|
"%s:\n\tnum_part=%d\n\ttrees=%d\n\tfog=%s\n\tshadows=%s\n\teject_r=%.3f\n\tridtri=%.3f\n",
|
||
|
MI_NAME(mi),
|
||
|
fs->np,
|
||
|
fs->num_trees,
|
||
|
fs->fog ? "on" : "off",
|
||
|
fs->shadows ? "on" : "off",
|
||
|
fs->eject_r, fs->ridtri);
|
||
|
}
|
||
|
}
|
||
|
#endif /* MODE_fire */
|