home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2007 September / maximum-cd-2007-09.iso / Assets / data / AssaultCube_v0.93.exe / source / src / renderparticles.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2007-05-25  |  14.5 KB  |  476 lines

  1. // renderparticles.cpp
  2.  
  3. #include "cube.h"
  4.  
  5. static GLushort *hemiindices = NULL;
  6. static vec *hemiverts = NULL;
  7. static int heminumverts = 0, heminumindices = 0;
  8.  
  9. static void subdivide(int depth, int face);
  10.  
  11. static void genface(int depth, int i1, int i2, int i3)
  12. {
  13.     int face = heminumindices; heminumindices += 3;
  14.     hemiindices[face]   = i1;
  15.     hemiindices[face+1] = i2;
  16.     hemiindices[face+2] = i3;
  17.     subdivide(depth, face);
  18. }   
  19.     
  20. static void subdivide(int depth, int face)
  21. {   
  22.     if(depth-- <= 0) return;
  23.     int idx[6];
  24.     loopi(3) idx[i] = hemiindices[face+i];
  25.     loopi(3) 
  26.     {
  27.         int vert = heminumverts++;
  28.         hemiverts[vert] = vec(hemiverts[idx[i]]).add(hemiverts[idx[(i+1)%3]]).normalize(); //push on to unit sphere
  29.         idx[3+i] = vert;
  30.         hemiindices[face+i] = vert;
  31.     }
  32.     subdivide(depth, face);
  33.     loopi(3) genface(depth, idx[i], idx[3+i], idx[3+(i+2)%3]);
  34. }
  35.  
  36. //subdiv version wobble much more nicely than a lat/longitude version
  37. static void inithemisphere(int hres, int depth)
  38. {   
  39.     const int tris = hres << (2*depth);
  40.     heminumverts = heminumindices = 0;
  41.     DELETEA(hemiverts);
  42.     DELETEA(hemiindices);
  43.     hemiverts = new vec[tris+1];
  44.     hemiindices = new GLushort[tris*3];
  45.     hemiverts[heminumverts++] = vec(0.0f, 0.0f, 1.0f); //build initial 'hres' sided pyramid
  46.     loopi(hres)
  47.     {
  48.         float a = PI2*float(i)/hres;
  49.         hemiverts[heminumverts++] = vec(cosf(a), sinf(a), 0.0f);
  50.     }
  51.     loopi(hres) genface(depth, 0, i+1, 1+(i+1)%hres);
  52. }
  53.  
  54. GLuint createexpmodtex(int size, float minval)
  55. {   
  56.     uchar *data = new uchar[size*size], *dst = data;
  57.     loop(y, size) loop(x, size)
  58.     {
  59.         float dx = 2*float(x)/(size-1) - 1, dy = 2*float(y)/(size-1) - 1;
  60.         float z = max(0, 1 - dx*dx - dy*dy);
  61.         if(minval) z = sqrtf(z);
  62.         else loopk(2) z *= z; 
  63.         *dst++ = uchar(max(z, minval)*255);
  64.     }
  65.     GLuint tex = 0;
  66.     glGenTextures(1, &tex);
  67.     createtexture(tex, size, size, data, 3, true, GL_ALPHA);
  68.     delete[] data;
  69.     return tex;
  70. }
  71.  
  72. static struct expvert
  73. {   
  74.     vec pos; 
  75.     float u, v;
  76. } *expverts = NULL;
  77.  
  78. static GLuint expmodtex[2] = {0, 0};
  79. static GLuint lastexpmodtex = 0;
  80.  
  81. VARP(mtexplosion, 0, 1, 1);
  82.  
  83. void setupexplosion()
  84. {   
  85.     if(!hemiindices) inithemisphere(5, 2);
  86.  
  87.     static int lastexpmillis = 0;
  88.     if(lastexpmillis != lastmillis || !expverts)
  89.     {
  90.         vec center = vec(13.0f, 2.3f, 7.1f);
  91.         lastexpmillis = lastmillis;
  92.         if(!expverts) expverts = new expvert[heminumverts];
  93.         loopi(heminumverts)
  94.         {
  95.             expvert &e = expverts[i];
  96.             vec &v = hemiverts[i];
  97.             e.u = v.x*0.5f + 0.001f*lastmillis;
  98.             e.v = v.y*0.5f + 0.001f*lastmillis;
  99.             float wobble = v.dot(center) + 0.002f*lastmillis;
  100.             wobble -= floor(wobble);
  101.             wobble = 1.0f + fabs(wobble - 0.5f)*0.5f;
  102.             e.pos = vec(v).mul(wobble);
  103.         }
  104.     }
  105.  
  106.     if(mtexplosion && maxtmus>=2)
  107.     {
  108.         setuptmu(0, "C * T", "= Ca");
  109.         glActiveTexture_(GL_TEXTURE1_ARB);
  110.         glEnable(GL_TEXTURE_2D);
  111.  
  112.         GLfloat s[4] = { 0.5f, 0, 0, 0.5f }, t[4] = { 0, 0.5f, 0, 0.5f };
  113.         glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
  114.         glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
  115.         glTexGenfv(GL_S, GL_OBJECT_PLANE, s);
  116.         glTexGenfv(GL_T, GL_OBJECT_PLANE, t);
  117.         glEnable(GL_TEXTURE_GEN_S);
  118.         glEnable(GL_TEXTURE_GEN_T);
  119.  
  120.         setuptmu(1, "P * Ta x 4", "Pa * Ta x 4");
  121.  
  122.         glActiveTexture_(GL_TEXTURE0_ARB);
  123.         
  124.         if(!expmodtex[0]) expmodtex[0] = createexpmodtex(64, 0);
  125.         if(!expmodtex[1]) expmodtex[1] = createexpmodtex(64, 0.25f);
  126.         lastexpmodtex = 0;
  127.     }
  128.  
  129.     glEnableClientState(GL_VERTEX_ARRAY);
  130.     glVertexPointer(3, GL_FLOAT, sizeof(expvert), &expverts->pos);
  131.     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
  132.     glTexCoordPointer(2, GL_FLOAT, sizeof(expvert), &expverts->u);
  133. }
  134.  
  135. void drawexplosion(bool inside, float r, float g, float b, float a)
  136. {
  137.     if(mtexplosion && maxtmus>=2 && lastexpmodtex != expmodtex[inside ? 1 : 0])
  138.     {
  139.         glActiveTexture_(GL_TEXTURE1_ARB);
  140.         lastexpmodtex = expmodtex[inside ? 1 :0];
  141.         glBindTexture(GL_TEXTURE_2D, lastexpmodtex);
  142.         glActiveTexture_(GL_TEXTURE0_ARB);
  143.     }
  144.     loopi(!reflecting && inside ? 2 : 1)
  145.     {
  146.         glColor4f(r, g, b, i ? a/2 : a);
  147.         if(i)
  148.         {
  149.             glScalef(1, 1, -1);
  150.             glDepthFunc(GL_GEQUAL);
  151.         }
  152.         if(inside)
  153.         {
  154.             if(!reflecting)
  155.             {
  156.                 glCullFace(GL_BACK);
  157.                 glDrawElements(GL_TRIANGLES, heminumindices, GL_UNSIGNED_SHORT, hemiindices);
  158.                 glCullFace(GL_FRONT);
  159.             }
  160.             glScalef(1, 1, -1);
  161.         }
  162.         glDrawElements(GL_TRIANGLES, heminumindices, GL_UNSIGNED_SHORT, hemiindices);
  163.         if(i) glDepthFunc(GL_LESS);
  164.     }
  165. }
  166.  
  167. void cleanupexplosion()
  168. {   
  169.     glDisableClientState(GL_VERTEX_ARRAY);
  170.     glDisableClientState(GL_TEXTURE_COORD_ARRAY);
  171.  
  172.     if(mtexplosion && maxtmus>=2)
  173.     {
  174.         resettmu(0);
  175.         glActiveTexture_(GL_TEXTURE1_ARB);
  176.         glDisable(GL_TEXTURE_2D);
  177.         glDisable(GL_TEXTURE_GEN_S);
  178.         glDisable(GL_TEXTURE_GEN_T);
  179.         resettmu(1);
  180.         glActiveTexture_(GL_TEXTURE0_ARB);
  181.     }
  182. }
  183.  
  184. #define MAXPARTYPES 8
  185.  
  186. struct particle { vec o, d; int fade, type; int millis; particle *next; };
  187. particle *parlist[MAXPARTYPES], *parempty = NULL;
  188.  
  189. static Texture *parttex[4];
  190.  
  191. void particleinit()
  192. {
  193.     loopi(MAXPARTYPES) parlist[i] = NULL;
  194.  
  195.     parttex[0] = textureload("packages/misc/base.png");
  196.     parttex[1] = textureload("packages/misc/smoke.png");
  197.     parttex[2] = textureload("packages/misc/explosion.jpg");
  198.     parttex[3] = textureload("packages/misc/hole.png");
  199. }
  200.  
  201. void particlereset()
  202. {
  203.     loopi(MAXPARTYPES)
  204.     {
  205.         while(parlist[i])
  206.         {
  207.             particle *p = parlist[i];
  208.             parlist[i] = p->next;
  209.             p->next = parempty;
  210.             parempty = p;
  211.         }
  212.     }
  213. }
  214.  
  215. void newparticle(const vec &o, const vec &d, int fade, int type)
  216. {
  217.     if(!parempty)
  218.     {
  219.         particle *ps = new particle[256];
  220.         loopi(256)
  221.         {
  222.             ps[i].next = parempty;
  223.             parempty = &ps[i];
  224.         }
  225.     }
  226.  
  227.     particle *p = parempty;
  228.     parempty = p->next;
  229.     p->o = o;
  230.     p->d = d;
  231.     p->fade = fade;
  232.     p->type = type;
  233.     p->millis = lastmillis;
  234.     p->next = parlist[type];
  235.     parlist[type] = p;
  236. }
  237.  
  238. enum
  239. {
  240.     PT_PART = 0,
  241.     PT_FIREBALL,
  242.     PT_SHOTLINE,
  243.     PT_DECAL
  244. };
  245.  
  246. static struct parttype { int type; float r, g, b; int gr, tex; float sz; } parttypes[] =
  247. {
  248.     { 0,           0.4f, 0.4f, 0.4f, 2,  0, 0.06f }, // yellow: sparks 
  249.     { 0,           1.0f, 1.0f, 1.0f, 20, 1, 0.15f }, // grey:   small smoke
  250.     { 0,           0.2f, 0.2f, 1.0f, 20, 0, 0.08f }, // blue:   edit mode entities
  251.     { 0,           1.0f, 0.1f, 0.1f, 1,  1, 0.06f }, // red:    blood spats
  252.     { 0,           1.0f, 0.1f, 0.1f, 0,  1, 0.2f  }, // red:    demotrack
  253.     { PT_FIREBALL, 1.0f, 0.5f, 0.5f, 0,  2, 7.0f  }, // explosion fireball
  254.     { PT_SHOTLINE, 1.0f, 1.0f, 0.7f, 0, -1, 0.0f  }, // yellow: shotline
  255.     { PT_DECAL,    1.0f, 1.0f, 1.0f, 0,  3, 0.07f }, // hole decal     
  256. };
  257.  
  258. VAR(demotracking, 0, 0, 1);
  259. VAR(particlesize, 20, 100, 500);
  260.  
  261. void render_particles(int time)
  262. {
  263.     if(demoplayback && demotracking)
  264.     {
  265.         vec nom(0, 0, 0);
  266.         newparticle(player1->o, nom, 100000000, 4);
  267.     }
  268.  
  269.     bool rendered = false;
  270.     for(int i = MAXPARTYPES-1; i>=0; i--) if(parlist[i])
  271.     {
  272.         if(!rendered)
  273.         {
  274.             rendered = true;
  275.             glDepthMask(GL_FALSE);
  276.             glEnable(GL_BLEND);
  277.             glDisable(GL_FOG);
  278.         }
  279.  
  280.         parttype &pt = parttypes[i];
  281.         float sz = pt.sz*particlesize/100.0f;
  282.  
  283.         if(pt.tex>=0) glBindTexture(GL_TEXTURE_2D, parttex[pt.tex]->id);
  284.         else glDisable(GL_TEXTURE_2D);
  285.         switch(pt.type)
  286.         {
  287.             case PT_PART:
  288.                 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
  289.                 glColor3f(pt.r, pt.g, pt.b);
  290.                 glBegin(GL_QUADS);
  291.                 break;
  292.  
  293.             case PT_FIREBALL:
  294.                 setupexplosion();
  295.                 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
  296.                 break;
  297.  
  298.             case PT_SHOTLINE:
  299.                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  300.                 glColor4f(pt.r, pt.g, pt.b, 0.5f);
  301.                 glBegin(GL_LINES);
  302.                 break;
  303.  
  304.             case PT_DECAL:
  305.                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  306.                 glBegin(GL_QUADS);
  307.                 break;
  308.         }
  309.          
  310.         for(particle *p, **pp = &parlist[i]; (p = *pp);)
  311.         {       
  312.             switch(pt.type)
  313.             {
  314.                 case PT_PART:
  315.                     glTexCoord2i(0, 1); glVertex3f(p->o.x+(-camright.x+camup.x)*sz, p->o.y+(-camright.y+camup.y)*sz, p->o.z+(-camright.z+camup.z)*sz);
  316.                     glTexCoord2i(1, 1); glVertex3f(p->o.x+( camright.x+camup.x)*sz, p->o.y+( camright.y+camup.y)*sz, p->o.z+( camright.z+camup.z)*sz);
  317.                     glTexCoord2i(1, 0); glVertex3f(p->o.x+( camright.x-camup.x)*sz, p->o.y+( camright.y-camup.y)*sz, p->o.z+( camright.z-camup.z)*sz);
  318.                     glTexCoord2i(0, 0); glVertex3f(p->o.x+(-camright.x-camup.x)*sz, p->o.y+(-camright.y-camup.y)*sz, p->o.z+(-camright.z-camup.z)*sz);
  319.                     xtraverts += 4;
  320.                     break;
  321.                 
  322.                 case PT_FIREBALL:
  323.                 {
  324.                     sz = 1.0f + (pt.sz-1.0f)*min(p->fade, lastmillis-p->millis)/p->fade;
  325.                     glPushMatrix();
  326.                     glTranslatef(p->o.x, p->o.y, p->o.z);
  327.                     bool inside = p->o.dist(camera1->o) <= sz*1.25f; //1.25 is max wobble scale
  328.                     vec oc(p->o);
  329.                     oc.sub(camera1->o);
  330.                     if(reflecting && !refracting) oc.z = p->o.z - (hdr.waterlevel-0.3f);
  331.                     glRotatef(inside ? camera1->yaw - 180 : atan2(oc.y, oc.x)/RAD - 90, 0, 0, 1);
  332.                     glRotatef((inside ? camera1->pitch : asin(oc.z/oc.magnitude())/RAD) - 90, 1, 0, 0);
  333.  
  334.                     glRotatef(lastmillis/7.0f, 0, 0, 1);
  335.                     glScalef(-sz, sz, -sz);
  336.                     drawexplosion(inside, pt.r, pt.g, pt.b, 1.0f-sz/pt.sz);
  337.                     glPopMatrix(); 
  338.                     xtraverts += heminumverts;
  339.                     break;
  340.                 }
  341.                
  342.                 case PT_SHOTLINE:
  343.                     glVertex3f(p->o.x, p->o.y, p->o.z);
  344.                     glVertex3f(p->d.x, p->d.y, p->d.z);
  345.                     xtraverts += 2;
  346.                     break;
  347.  
  348.                 case PT_DECAL:
  349.                 {
  350.                     sqr *s = S((int)p->o.x, (int)p->o.y);
  351.                     glColor4f(s->r/127.5f, s->g/127.5f, s->b/127.5, max(0, min((p->millis+p->fade - lastmillis)/1000.0f, 0.7f)));
  352.                     vec dx(0, 0, 0), dy(0, 0, 0);
  353.                     loopk(3) if(p->d[k]) { dx[(k+1)%3] = -1; dy[(k+2)%3] = p->d[k]; break; } 
  354.                     glTexCoord2i(0, 1); glVertex3f(p->o.x+(-dx.x+dy.x)*pt.sz, p->o.y+(-dx.y+dy.y)*pt.sz, p->o.z+(-dx.z+dy.z)*pt.sz);
  355.                     glTexCoord2i(1, 1); glVertex3f(p->o.x+( dx.x+dy.x)*pt.sz, p->o.y+( dx.y+dy.y)*pt.sz, p->o.z+( dx.z+dy.z)*pt.sz);
  356.                     glTexCoord2i(1, 0); glVertex3f(p->o.x+( dx.x-dy.x)*pt.sz, p->o.y+( dx.y-dy.y)*pt.sz, p->o.z+( dx.z-dy.z)*pt.sz);
  357.                     glTexCoord2i(0, 0); glVertex3f(p->o.x+(-dx.x-dy.x)*pt.sz, p->o.y+(-dx.y-dy.y)*pt.sz, p->o.z+(-dx.z-dy.z)*pt.sz);
  358.                     xtraverts += 4;
  359.                     break;
  360.                 }
  361.             }
  362.    
  363.             if(!time) pp = &p->next;
  364.             else if(lastmillis-p->millis>p->fade)
  365.             {
  366.                 *pp = p->next;
  367.                 p->next = parempty;
  368.                 parempty = p;
  369.             }
  370.             else
  371.             {
  372.                 if(pt.gr) p->o.z -= ((lastmillis-p->millis)/3.0f)*time/(pt.gr*10000);
  373.                 if(pt.type==PT_PART) p->o.add(vec(p->d).mul(time/20000.0f));
  374.                 pp = &p->next;
  375.             }
  376.         }
  377.      
  378.         switch(pt.type)
  379.         {
  380.             case PT_PART:
  381.             case PT_SHOTLINE:
  382.             case PT_DECAL:
  383.                 glEnd();
  384.                 break;
  385.  
  386.             case PT_FIREBALL:
  387.                 cleanupexplosion();
  388.                 break;
  389.         }      
  390.         if(pt.tex<0) glEnable(GL_TEXTURE_2D);
  391.     }
  392.  
  393.     if(rendered)
  394.     {
  395.         glEnable(GL_FOG);
  396.         glDisable(GL_BLEND);
  397.         glDepthMask(GL_TRUE);
  398.     }
  399. }
  400.  
  401.  
  402. void particle_splash(int type, int num, int fade, vec &p)
  403. {
  404.     loopi(num)
  405.     {
  406.         const int radius = type==5 ? 50 : 150;
  407.         int x, y, z;
  408.         do
  409.         {
  410.             x = rnd(radius*2)-radius;
  411.             y = rnd(radius*2)-radius;
  412.             z = rnd(radius*2)-radius;
  413.         }
  414.         while(x*x+y*y+z*z>radius*radius);
  415.         vec d((float)x, (float)y, (float)z);
  416.         newparticle(p, d, rnd(fade*3), type);
  417.     }
  418. }
  419.  
  420. void particle_trail(int type, int fade, vec &s, vec &e)
  421. {
  422.     vec v;
  423.     float d = e.dist(s, v); 
  424.     v.div(d*2+0.1f);
  425.     vec p = s;
  426.     loopi((int)d*2)
  427.     {
  428.         p.add(v);
  429.         vec d((float)(rnd(11)-5), (float)(rnd(11)-5), (float)(rnd(11)-5));
  430.         newparticle(p, d, rnd(fade)+fade, type);
  431.     }
  432. }
  433.  
  434. void particle_fireball(int type, vec &o)
  435. {
  436.     newparticle(o, vec(0, 0, 0), (int)((parttypes[type].sz-1.0f)*100.0f), type);
  437. }
  438.  
  439. VARP(holettl, 0, 10000, 30000);
  440.  
  441. bool addbullethole(vec &from, vec &to, float radius)
  442. {
  443.     if(!holettl) return false;
  444.     vec surface, ray(to);
  445.     ray.sub(from);
  446.     ray.normalize();
  447.     float dist = raycube(from, ray, surface), mag = to.dist(from);
  448.     if(surface.iszero() || (radius>0 && (dist < mag-radius || dist > mag+radius))) return false;
  449.     vec o(from);
  450.     o.add(ray.mul(dist));
  451.     o.add(vec(surface).mul(0.005f));
  452.     newparticle(o, surface, holettl, 7);
  453.     return true;
  454. }
  455.  
  456. void addshotline(dynent *pl, vec &from, vec &to)
  457. {
  458.     if(pl == player1) return;
  459.     if(rnd(3)) return;
  460.        
  461.     int start = 10;
  462.     if(camera1->o.dist(to) <= 10.0f) start = 8;
  463.     else start = 5;
  464.  
  465.     vec unitv;
  466.     float dist = to.dist(from, unitv);
  467.     unitv.div(dist);
  468.  
  469.     vec o = unitv;
  470.     o.mul(dist/10+start).add(from);
  471.     vec d = unitv;
  472.     d.mul(dist/10*-(10-start-2)).add(to);
  473.     newparticle(o, d, 75, 6);
  474. }   
  475.  
  476.