fire.c
上传用户:xk288cn
上传日期:2007-05-28
资源大小:4876k
文件大小:15k
源码类别:

GIS编程

开发平台:

Visual C++

  1. /*
  2.  * This program is under the GNU GPL.
  3.  * Use at your own risk.
  4.  *
  5.  * written by David Bucciarelli (tech.hmw@plus.it)
  6.  *            Humanware s.r.l.
  7.  */
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <math.h>
  12. #include <time.h>
  13. #ifdef _WIN32
  14. #include <windows.h>
  15. #endif
  16. #include <GL/glut.h>
  17. #include "image.h"
  18. #if defined(GL_VERSION_1_1)
  19. /* Routines called directly. */
  20. #elif defined(GL_EXT_texture_object) && defined(GL_EXT_copy_texture) && defined(GL_EXT_subtexture)
  21. #define glBindTexture(A,B)     glBindTextureEXT(A,B)
  22. #define glGenTextures(A,B)     glGenTexturesEXT(A,B)
  23. #else
  24. #define glBindTexture(A,B)
  25. #define glGenTextures(A,B)
  26. #endif
  27. /* Some <math.h> files do not define M_PI... */
  28. #ifndef M_PI
  29. #define M_PI 3.14159265358979323846
  30. #endif
  31. #define vinit(a,i,j,k) {
  32.   (a)[0]=i;
  33.   (a)[1]=j;
  34.   (a)[2]=k;
  35. }
  36. #define vinit4(a,i,j,k,w) {
  37.   (a)[0]=i;
  38.   (a)[1]=j;
  39.   (a)[2]=k;
  40.   (a)[3]=w;
  41. }
  42. #define vadds(a,dt,b) {
  43.   (a)[0]+=(dt)*(b)[0];
  44.   (a)[1]+=(dt)*(b)[1];
  45.   (a)[2]+=(dt)*(b)[2];
  46. }
  47. #define vequ(a,b) {
  48.   (a)[0]=(b)[0];
  49.   (a)[1]=(b)[1];
  50.   (a)[2]=(b)[2];
  51. }
  52. #define vinter(a,dt,b,c) {
  53.   (a)[0]=(dt)*(b)[0]+(1.0-dt)*(c)[0];
  54.   (a)[1]=(dt)*(b)[1]+(1.0-dt)*(c)[1];
  55.   (a)[2]=(dt)*(b)[2]+(1.0-dt)*(c)[2];
  56. }
  57. #define clamp(a)        ((a) < 0.0 ? 0.0 : ((a) < 1.0 ? (a) : 1.0))
  58. #define vclamp(v) {
  59.   (v)[0]=clamp((v)[0]);
  60.   (v)[1]=clamp((v)[1]);
  61.   (v)[2]=clamp((v)[2]);
  62. }
  63. static int WIDTH=640;
  64. static int HEIGHT=480;
  65. #define FRAME 50
  66. #define DIMP 20.0
  67. #define DIMTP 16.0
  68. #define RIDCOL 0.4
  69. #define NUMTREE 50
  70. #define TREEINR 2.5
  71. #define TREEOUTR 8.0
  72. #define AGRAV -9.8
  73. typedef struct {
  74.   int age;
  75.   float p[3][3];
  76.   float v[3];
  77.   float c[3][4];
  78. } part;
  79. static float treepos[NUMTREE][3];
  80. static float black[3]={0.0,0.0,0.0};
  81. static float blu[3]={0.0,0.2,1.0};
  82. static float blu2[3]={0.0,1.0,1.0};
  83. static float fogcolor[4]={1.0,1.0,1.0,1.0};
  84. static float q[4][3]={
  85.   {-DIMP,0.0,-DIMP},
  86.   {DIMP,0.0,-DIMP},
  87.   {DIMP,0.0,DIMP},
  88.   {-DIMP,0.0,DIMP}
  89. };
  90. static float qt[4][2]={
  91.   {-DIMTP,-DIMTP},
  92.   {DIMTP,-DIMTP},
  93.   {DIMTP,DIMTP},
  94.   {-DIMTP,DIMTP}
  95. };
  96. static int np;
  97. static float eject_r,dt,maxage,eject_vy,eject_vl;
  98. static short shadows;
  99. static float ridtri;
  100. static int fog=1;
  101. static int help=1;
  102. static int joyavailable=0;
  103. static int joyactive=0;
  104. static part *p;
  105. static GLuint groundid;
  106. static GLuint treeid;
  107. static float obs[3]={2.0,1.0,0.0};
  108. static float dir[3];
  109. static float v=0.0;
  110. static float alpha=-90.0;
  111. static float beta=90.0;
  112. static float gettime(void)
  113. {
  114.   static clock_t told=0;
  115.   clock_t tnew,ris;
  116.   tnew=clock();
  117.   ris=tnew-told;
  118.   told=tnew;
  119.   return(ris/(float)CLOCKS_PER_SEC);
  120. }
  121. float vrnd(void)
  122. {
  123.   return(((float)rand())/RAND_MAX);
  124. }
  125. static void setnewpart(part *p)
  126. {
  127.   float a,v[3],*c;
  128.   p->age=0;
  129.   a=vrnd()*3.14159265359*2.0;
  130.   vinit(v,sin(a)*eject_r*vrnd(),0.15,cos(a)*eject_r*vrnd());
  131.   vinit(p->p[0],v[0]+vrnd()*ridtri,v[1]+vrnd()*ridtri,v[2]+vrnd()*ridtri);
  132.   vinit(p->p[1],v[0]+vrnd()*ridtri,v[1]+vrnd()*ridtri,v[2]+vrnd()*ridtri);
  133.   vinit(p->p[2],v[0]+vrnd()*ridtri,v[1]+vrnd()*ridtri,v[2]+vrnd()*ridtri);
  134.   vinit(p->v,v[0]*eject_vl/(eject_r/2),vrnd()*eject_vy+eject_vy/2,v[2]*eject_vl/(eject_r/2));
  135.   c=blu;
  136.   vinit4(p->c[0],c[0]*((1.0-RIDCOL)+vrnd()*RIDCOL),
  137.  c[1]*((1.0-RIDCOL)+vrnd()*RIDCOL),
  138.  c[2]*((1.0-RIDCOL)+vrnd()*RIDCOL),
  139.  1.0);
  140.   vinit4(p->c[1],c[0]*((1.0-RIDCOL)+vrnd()*RIDCOL),
  141.  c[1]*((1.0-RIDCOL)+vrnd()*RIDCOL),
  142.  c[2]*((1.0-RIDCOL)+vrnd()*RIDCOL),
  143.  1.0);
  144.   vinit4(p->c[2],c[0]*((1.0-RIDCOL)+vrnd()*RIDCOL),
  145.  c[1]*((1.0-RIDCOL)+vrnd()*RIDCOL),
  146.  c[2]*((1.0-RIDCOL)+vrnd()*RIDCOL),
  147.  1.0);
  148. }
  149. static void setpart(part *p)
  150. {
  151.   float fact;
  152.   if(p->p[0][1]<0.1) {
  153.     setnewpart(p);
  154.     return;
  155.   }
  156.   p->v[1]+=AGRAV*dt;
  157.   vadds(p->p[0],dt,p->v);
  158.   vadds(p->p[1],dt,p->v);
  159.   vadds(p->p[2],dt,p->v);
  160.   p->age++;
  161.   if((p->age)>maxage) {
  162.     vequ(p->c[0],blu2);
  163.     vequ(p->c[1],blu2);
  164.     vequ(p->c[2],blu2);
  165.   } else {
  166.     fact=1.0/maxage;
  167.     vadds(p->c[0],fact,blu2);
  168.     vclamp(p->c[0]);
  169.     p->c[0][3]=fact*(maxage-p->age);
  170.     vadds(p->c[1],fact,blu2);
  171.     vclamp(p->c[1]);
  172.     p->c[1][3]=fact*(maxage-p->age);
  173.     vadds(p->c[2],fact,blu2);
  174.     vclamp(p->c[2]);
  175.     p->c[2][3]=fact*(maxage-p->age);
  176.   }
  177. }
  178. static void drawtree(float x, float y, float z)
  179. {
  180.   glBegin(GL_QUADS);
  181.   glTexCoord2f(0.0,0.0);
  182.   glVertex3f(x-1.5,y+0.0,z);
  183.   glTexCoord2f(1.0,0.0);
  184.   glVertex3f(x+1.5,y+0.0,z);
  185.   glTexCoord2f(1.0,1.0);
  186.   glVertex3f(x+1.5,y+3.0,z);
  187.   glTexCoord2f(0.0,1.0);
  188.   glVertex3f(x-1.5,y+3.0,z);
  189.   glTexCoord2f(0.0,0.0);
  190.   glVertex3f(x,y+0.0,z-1.5);
  191.   glTexCoord2f(1.0,0.0);
  192.   glVertex3f(x,y+0.0,z+1.5);
  193.   glTexCoord2f(1.0,1.0);
  194.   glVertex3f(x,y+3.0,z+1.5);
  195.   glTexCoord2f(0.0,1.0);
  196.   glVertex3f(x,y+3.0,z-1.5);
  197.   glEnd();
  198. }
  199. static void calcposobs(void)
  200. {
  201.   dir[0]=sin(alpha*M_PI/180.0);
  202.   dir[2]=cos(alpha*M_PI/180.0)*sin(beta*M_PI/180.0);
  203.   dir[1]=cos(beta*M_PI/180.0);
  204.   obs[0]+=v*dir[0];
  205.   obs[1]+=v*dir[1];
  206.   obs[2]+=v*dir[2];
  207. }
  208. static void printstring(void *font, char *string)
  209. {
  210.   int len,i;
  211.   len=(int)strlen(string);
  212.   for(i=0;i<len;i++)
  213.     glutBitmapCharacter(font,string[i]);
  214. }
  215. static void reshape(int width, int height)
  216. {
  217.   WIDTH=width;
  218.   HEIGHT=height;
  219.   glViewport(0,0,(GLint)width,(GLint)height);
  220.   glMatrixMode(GL_PROJECTION);
  221.   glLoadIdentity();
  222.   gluPerspective(70.0,width/(float)height,0.1,30.0);
  223.   glMatrixMode(GL_MODELVIEW);
  224. }
  225. static void printhelp(void)
  226. {
  227.   glColor4f(0.0,0.0,0.0,0.5);
  228.   glRecti(40,40,600,440);
  229.   glColor3f(1.0,0.0,0.0);
  230.   glRasterPos2i(300,420);
  231.   printstring(GLUT_BITMAP_TIMES_ROMAN_24,"Help");
  232.   glRasterPos2i(60,390);
  233.   printstring(GLUT_BITMAP_TIMES_ROMAN_24,"h - Togle Help");
  234.   glRasterPos2i(60,360);
  235.   printstring(GLUT_BITMAP_TIMES_ROMAN_24,"t - Increase particle size");
  236.   glRasterPos2i(60,330);
  237.   printstring(GLUT_BITMAP_TIMES_ROMAN_24,"T - Decrease particle size");
  238.   glRasterPos2i(60,300);
  239.   printstring(GLUT_BITMAP_TIMES_ROMAN_24,"r - Increase emission radius");
  240.   glRasterPos2i(60,270);
  241.   printstring(GLUT_BITMAP_TIMES_ROMAN_24,"R - Decrease emission radius");
  242.   glRasterPos2i(60,240);
  243.   printstring(GLUT_BITMAP_TIMES_ROMAN_24,"f - Togle Fog");
  244.   glRasterPos2i(60,210);
  245.   printstring(GLUT_BITMAP_TIMES_ROMAN_24,"s - Togle shadows");
  246.   glRasterPos2i(60,180);
  247.   printstring(GLUT_BITMAP_TIMES_ROMAN_24,"Arrow Keys - Rotate");
  248.   glRasterPos2i(60,150);
  249.   printstring(GLUT_BITMAP_TIMES_ROMAN_24,"a - Increase velocity");
  250.   glRasterPos2i(60,120);
  251.   printstring(GLUT_BITMAP_TIMES_ROMAN_24,"z - Decrease velocity");
  252.   glRasterPos2i(60,90);
  253.   if(joyavailable)
  254.     printstring(GLUT_BITMAP_TIMES_ROMAN_24,"j - Togle jostick control (Joystick control available)");
  255.   else
  256.     printstring(GLUT_BITMAP_TIMES_ROMAN_24,"(No Joystick control available)");
  257. }
  258. static void dojoy(void)
  259. {
  260. #ifdef _WIN32
  261.   static UINT max[2]={0,0};
  262.   static UINT min[2]={0xffffffff,0xffffffff},center[2];
  263.   MMRESULT res;
  264.   JOYINFO joy;
  265.   res=joyGetPos(JOYSTICKID1,&joy);
  266.   if(res==JOYERR_NOERROR) {
  267.     joyavailable=1;
  268.     if(max[0]<joy.wXpos)
  269.       max[0]=joy.wXpos;
  270.     if(min[0]>joy.wXpos)
  271.       min[0]=joy.wXpos;
  272.     center[0]=(max[0]+min[0])/2;
  273.     if(max[1]<joy.wYpos)
  274.       max[1]=joy.wYpos;
  275.     if(min[1]>joy.wYpos)
  276.       min[1]=joy.wYpos;
  277.     center[1]=(max[1]+min[1])/2;
  278.     if(joyactive) {
  279.       if(fabs(center[0]-(float)joy.wXpos)>0.1*(max[0]-min[0]))
  280. alpha+=2.5*(center[0]-(float)joy.wXpos)/(max[0]-min[0]);
  281.       if(fabs(center[1]-(float)joy.wYpos)>0.1*(max[1]-min[1]))
  282. beta+=2.5*(center[1]-(float)joy.wYpos)/(max[1]-min[1]);
  283.       if(joy.wButtons & JOY_BUTTON1)
  284. v+=0.01;
  285.       if(joy.wButtons & JOY_BUTTON2)
  286. v-=0.01;
  287.     }
  288.   } else
  289.     joyavailable=0;
  290. #endif
  291. }
  292. static void drawfire(void)
  293. {
  294.   static int count=0;
  295.   static char frbuf[80];
  296.   int j;
  297.   float fr;
  298.   dojoy();
  299.   glEnable(GL_DEPTH_TEST);
  300.   if(fog)
  301.     glEnable(GL_FOG);
  302.   else
  303.     glDisable(GL_FOG);
  304.   glDepthMask(GL_TRUE);
  305.   glClearColor(1.0,1.0,1.0,1.0);
  306.   glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
  307.   glPushMatrix();
  308.   calcposobs();
  309.   gluLookAt(obs[0],obs[1],obs[2],
  310.     obs[0]+dir[0],obs[1]+dir[1],obs[2]+dir[2],
  311.     0.0,1.0,0.0);
  312.   glColor4f(1.0,1.0,1.0,1.0);
  313.   glEnable(GL_TEXTURE_2D);
  314.   glBindTexture(GL_TEXTURE_2D,groundid);
  315.   glBegin(GL_QUADS);
  316.   glTexCoord2fv(qt[0]);
  317.   glVertex3fv(q[0]);
  318.   glTexCoord2fv(qt[1]);
  319.   glVertex3fv(q[1]);
  320.   glTexCoord2fv(qt[2]);
  321.   glVertex3fv(q[2]);
  322.   glTexCoord2fv(qt[3]);
  323.   glVertex3fv(q[3]);
  324.   glEnd();
  325.   glEnable(GL_ALPHA_TEST);
  326.   glAlphaFunc(GL_GEQUAL,0.9);
  327.   glBindTexture(GL_TEXTURE_2D,treeid);
  328.   for(j=0;j<NUMTREE;j++)
  329.     drawtree(treepos[j][0],treepos[j][1],treepos[j][2]);
  330.   
  331.   glDisable(GL_TEXTURE_2D);
  332.   glDepthMask(GL_FALSE);
  333.   glDisable(GL_ALPHA_TEST);
  334.   if(shadows) {
  335.     glBegin(GL_TRIANGLES);
  336.     for(j=0;j<np;j++) {
  337.       glColor4f(black[0],black[1],black[2],p[j].c[0][3]);
  338.       glVertex3f(p[j].p[0][0],0.1,p[j].p[0][2]);
  339.       glColor4f(black[0],black[1],black[2],p[j].c[1][3]);
  340.       glVertex3f(p[j].p[1][0],0.1,p[j].p[1][2]);
  341.       glColor4f(black[0],black[1],black[2],p[j].c[2][3]);
  342.       glVertex3f(p[j].p[2][0],0.1,p[j].p[2][2]);
  343.     }
  344.     glEnd();
  345.   }
  346.   glBegin(GL_TRIANGLES);
  347.   for(j=0;j<np;j++) {
  348.     glColor4fv(p[j].c[0]);
  349.     glVertex3fv(p[j].p[0]);
  350.     glColor4fv(p[j].c[1]);
  351.     glVertex3fv(p[j].p[1]);
  352.     glColor4fv(p[j].c[2]);
  353.     glVertex3fv(p[j].p[2]);
  354.     setpart(&p[j]);
  355.   }
  356.   glEnd();
  357.   if((count % FRAME)==0) {
  358.     fr=gettime();
  359.     sprintf(frbuf,"Frame rate: %f",FRAME/fr);
  360.   }
  361.   glDisable(GL_TEXTURE_2D);
  362.   glDisable(GL_ALPHA_TEST);
  363.   glDisable(GL_DEPTH_TEST);
  364.   glDisable(GL_FOG);
  365.   glMatrixMode(GL_PROJECTION);
  366.   glLoadIdentity();
  367.   glOrtho(-0.5,639.5,-0.5,479.5,-1.0,1.0);
  368.   glMatrixMode(GL_MODELVIEW);
  369.   glLoadIdentity();
  370.   glColor3f(1.0,0.0,0.0);
  371.   glRasterPos2i(10,10);
  372.   printstring(GLUT_BITMAP_HELVETICA_18,frbuf);
  373.   glRasterPos2i(370,470);
  374.   printstring(GLUT_BITMAP_HELVETICA_10,"Fire V1.5 Written by David Bucciarelli (tech.hmw@plus.it)");
  375.   if(help)
  376.     printhelp();
  377.   reshape(WIDTH,HEIGHT);
  378.   glPopMatrix();
  379.   glutSwapBuffers();
  380.   count++;
  381. }
  382. /* ARGSUSED1 */
  383. static void special(int key, int x, int y)
  384. {
  385.   switch (key) {
  386.   case GLUT_KEY_LEFT:
  387.     alpha+=2.0;
  388.     break;
  389.   case GLUT_KEY_RIGHT:
  390.     alpha-=2.0;
  391.     break;
  392.   case GLUT_KEY_DOWN:
  393.     beta-=2.0;
  394.     break;
  395.   case GLUT_KEY_UP:
  396.     beta+=2.0;
  397.     break;
  398.   }
  399. }
  400. /* ARGSUSED1 */
  401. static void key(unsigned char key, int x, int y)
  402. {
  403.   switch (key) {
  404.   case 27:
  405.     exit(0);
  406.     break;
  407.   case 'a':
  408.     v+=0.01;
  409.     break;
  410.   case 'z':
  411.     v-=0.01;
  412.     break;
  413.   case 'j':
  414.     joyactive=(!joyactive);
  415.     break;
  416.   case 'h':
  417.     help=(!help);
  418.     break;
  419.   case 'f':
  420.     fog=(!fog);
  421.     break;
  422.   case 's':
  423.     shadows= !shadows;
  424.     break;
  425.   case 'R':
  426.     eject_r-=0.03;
  427.     break;
  428.   case 'r':
  429.     eject_r+=0.03;
  430.     break;
  431.   case 't':
  432.     ridtri+=0.005;
  433.     break;
  434.   case 'T':
  435.     ridtri-=0.005;
  436.     break;
  437.   }
  438. }
  439. static void inittextures(void)
  440. {
  441.   IMAGE *img;
  442.   GLenum gluerr;
  443.   GLubyte tex[128][128][4];
  444.   int x,y;
  445.   glGenTextures(1,&groundid);
  446.   glBindTexture(GL_TEXTURE_2D,groundid);
  447.   if(!(img=ImageLoad("s128.rgb"))) {
  448.     fprintf(stderr,"Error reading a texture.n");
  449.     exit(-1);
  450.   }
  451.   glPixelStorei(GL_UNPACK_ALIGNMENT,4);
  452.   if((gluerr=gluBuild2DMipmaps(GL_TEXTURE_2D, 3, img->sizeX, img->sizeY, GL_RGB,
  453.        GL_UNSIGNED_BYTE, (GLvoid *)(img->data)))) {
  454.     fprintf(stderr,"GLULib%sn",gluErrorString(gluerr));
  455.     exit(-1);
  456.   }
  457.   glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
  458.   glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
  459.   glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST_MIPMAP_LINEAR);
  460.   glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
  461.   glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL);
  462.   glGenTextures(1,&treeid);
  463.   glBindTexture(GL_TEXTURE_2D,treeid);
  464.   if(!(img=ImageLoad("tree2.rgb"))) {
  465.     fprintf(stderr,"Error reading a texture.n");
  466.     exit(-1);
  467.   }
  468.   for(y=0;y<128;y++)
  469.     for(x=0;x<128;x++) {
  470.       tex[x][y][0]=img->data[(y+x*128)*3];
  471.       tex[x][y][1]=img->data[(y+x*128)*3+1];
  472.       tex[x][y][2]=img->data[(y+x*128)*3+2];
  473.       if((tex[x][y][0]==tex[x][y][1]) && (tex[x][y][1]==tex[x][y][2]) && (tex[x][y][2]==255))
  474. tex[x][y][3]=0;
  475.       else
  476. tex[x][y][3]=255;
  477.     }
  478.   
  479.   if((gluerr=gluBuild2DMipmaps(GL_TEXTURE_2D, 4, 128, 128, GL_RGBA,
  480.        GL_UNSIGNED_BYTE, (GLvoid *)(tex)))) {
  481.     fprintf(stderr,"GLULib%sn",gluErrorString(gluerr));
  482.     exit(-1);
  483.   }
  484.   glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
  485.   glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
  486.   glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST_MIPMAP_LINEAR);
  487.   glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
  488.   glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);
  489. }
  490. static void inittree(void)
  491. {
  492.   int i;
  493.   float dist;
  494.   for(i=0;i<NUMTREE;i++)
  495.     do {
  496.       treepos[i][0]=vrnd()*TREEOUTR*2.0-TREEOUTR;
  497.       treepos[i][1]=0.0;
  498.       treepos[i][2]=vrnd()*TREEOUTR*2.0-TREEOUTR;
  499.       dist=sqrt(treepos[i][0]*treepos[i][0]+treepos[i][2]*treepos[i][2]);
  500.     } while((dist<TREEINR) || (dist>TREEOUTR));
  501. }
  502. int main(int ac,char **av)
  503. {
  504.   int i;
  505.   fprintf(stderr,"Fire V1.5nWritten by David Bucciarelli (tech.hmw@plus.it)n");
  506.   /* Default settings */
  507.   WIDTH=640;
  508.   HEIGHT=480;
  509.   np=800;
  510.   eject_r=0.1;
  511.   dt=0.015;
  512.   eject_vy=4;
  513.   eject_vl=1;
  514.   shadows=1;
  515.   ridtri=0.1;
  516.   maxage=1.0/dt;
  517.   if(ac==2)
  518.     np=atoi(av[1]);
  519.   if(ac==4) {
  520.     WIDTH=atoi(av[2]);
  521.     HEIGHT=atoi(av[3]);
  522.   }
  523.   glutInitWindowPosition(0,0);
  524.   glutInitWindowSize(WIDTH,HEIGHT);
  525.   glutInit(&ac,av);
  526.   glutInitDisplayMode(GLUT_RGB|GLUT_DEPTH|GLUT_DOUBLE);
  527.   glutCreateWindow("Fire");
  528.   
  529.   reshape(WIDTH,HEIGHT);
  530.   inittextures();
  531.   glShadeModel(GL_FLAT);
  532.   glEnable(GL_DEPTH_TEST);
  533.   glEnable(GL_BLEND);
  534.   glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
  535.   glEnable(GL_FOG);
  536.   glFogi(GL_FOG_MODE,GL_EXP);
  537.   glFogfv(GL_FOG_COLOR,fogcolor);
  538.   glFogf(GL_FOG_DENSITY,0.1);
  539. #ifdef FX
  540.   glHint(GL_FOG_HINT,GL_NICEST);
  541. #endif
  542.   p=malloc(sizeof(part)*np);
  543.   for(i=0;i<np;i++)
  544.     setnewpart(&p[i]);
  545.   inittree();
  546.   glutKeyboardFunc(key);
  547.   glutSpecialFunc(special);
  548.   glutDisplayFunc(drawfire);
  549.   glutIdleFunc(drawfire);
  550.   glutReshapeFunc(reshape);
  551.   glutMainLoop();
  552.   return 0;             /* ANSI C requires main to return int. */
  553. }