~ubuntu-branches/ubuntu/hardy/sauerbraten/hardy-backports

« back to all changes in this revision

Viewing changes to engine/explosion.h

  • Committer: Bazaar Package Importer
  • Author(s): Scott Kitterman
  • Date: 2008-07-25 09:07:06 UTC
  • mfrom: (3.1.1 lenny)
  • Revision ID: james.westby@ubuntu.com-20080725090706-e4c9vun2olvfji7t
Tags: 0.0.20080620.dfsg-1~hardy1
Automated backport upload; no source changes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// eye space depth texture for soft particles, done at low res then blurred to prevent ugly jaggies
 
2
VARP(depthfxfpscale, 1, 1<<12, 1<<16);
 
3
VARP(depthfxscale, 1, 1<<6, 1<<8);
 
4
VARP(depthfxblend, 1, 16, 64);
 
5
VAR(depthfxmargin, 0, 16, 64);
 
6
VAR(depthfxbias, 0, 1, 64);
 
7
 
 
8
extern void cleanupdepthfx();
 
9
VARFP(fpdepthfx, 0, 0, 1, cleanupdepthfx());
 
10
VARFP(depthfxprecision, 0, 0, 1, cleanupdepthfx());
 
11
VARP(depthfxemuprecision, 0, 1, 1);
 
12
VARFP(depthfxsize, 6, 7, 12, cleanupdepthfx());
 
13
VARP(depthfx, 0, 1, 1);
 
14
VARFP(depthfxrect, 0, 0, 1, cleanupdepthfx());
 
15
VARFP(depthfxfilter, 0, 1, 1, cleanupdepthfx());
 
16
VARP(blurdepthfx, 0, 1, 7);
 
17
VARP(blurdepthfxsigma, 1, 50, 200);
 
18
VAR(depthfxscissor, 0, 2, 2);
 
19
VAR(debugdepthfx, 0, 0, 1);
 
20
 
 
21
#define MAXDFXRANGES 4
 
22
 
 
23
void *depthfxowners[MAXDFXRANGES];
 
24
float depthfxranges[MAXDFXRANGES];
 
25
int numdepthfxranges = 0;
 
26
vec depthfxmin(1e16f, 1e16f, 1e16f), depthfxmax(1e16f, 1e16f, 1e16f);
 
27
 
 
28
static struct depthfxtexture : rendertarget
 
29
{
 
30
    const GLenum *colorformats() const
 
31
    {
 
32
        static const GLenum colorfmts[] = { GL_FLOAT_RG16_NV, GL_RGB16F_ARB, GL_RGB16, GL_RGBA, GL_RGBA8, GL_RGB, GL_RGB8, GL_FALSE };
 
33
        return &colorfmts[hasTF && hasFBO ? (fpdepthfx ? (hasNVFB && texrect() && !filter() ? 0 : 1) : (depthfxprecision ? 2 : 3)) : 3];
 
34
    }
 
35
 
 
36
    float eyedepth(const vec &p) const
 
37
    {
 
38
        return max(-(p.x*mvmatrix[2] + p.y*mvmatrix[6] + p.z*mvmatrix[10] + mvmatrix[14]), 0.0f);
 
39
    }
 
40
 
 
41
    void addscissorvert(const vec &v, float &sx1, float &sy1, float &sx2, float &sy2)
 
42
    {
 
43
        float w = v.x*mvpmatrix[3] + v.y*mvpmatrix[7] + v.z*mvpmatrix[11] + mvpmatrix[15],
 
44
              x = (v.x*mvpmatrix[0] + v.y*mvpmatrix[4] + v.z*mvpmatrix[8] + mvpmatrix[12]) / w,
 
45
              y = (v.x*mvpmatrix[1] + v.y*mvpmatrix[5] + v.z*mvpmatrix[9] + mvpmatrix[13]) / w;
 
46
        sx1 = min(sx1, x);
 
47
        sy1 = min(sy1, y);
 
48
        sx2 = max(sx2, x);
 
49
        sy2 = max(sy2, y);
 
50
    }
 
51
 
 
52
    bool addscissorbox(const vec &center, float size)
 
53
    {
 
54
        extern float fovy, aspect;
 
55
        vec e(center.x*mvmatrix[0] + center.y*mvmatrix[4] + center.z*mvmatrix[8] + mvmatrix[12],
 
56
              center.x*mvmatrix[1] + center.y*mvmatrix[5] + center.z*mvmatrix[9] + mvmatrix[13],
 
57
              center.x*mvmatrix[2] + center.y*mvmatrix[6] + center.z*mvmatrix[10] + mvmatrix[14]);
 
58
        float zz = e.z*e.z, xx = e.x*e.x, yy = e.y*e.y, rr = size*size,
 
59
              dx = zz*(xx + zz) - rr*zz, dy = zz*(yy + zz) - rr*zz,
 
60
              focaldist = 1.0f/tan(fovy*0.5f*RAD),
 
61
              left = -1, right = 1, bottom = -1, top = 1;
 
62
        #define CHECKPLANE(c, dir, focaldist, low, high) \
 
63
        do { \
 
64
            float nc = (size*e.c dir drt)/(c##c + zz), \
 
65
                  nz = (size - nc*e.c)/e.z, \
 
66
                  pz = (c##c + zz - rr)/(e.z - nz/nc*e.c); \
 
67
            if(pz < 0) \
 
68
            { \
 
69
                float c = nz*(focaldist)/nc, \
 
70
                      pc = -pz*nz/nc; \
 
71
                if(pc < e.c) low = c; \
 
72
                else if(pc > e.c) high = c; \
 
73
            } \
 
74
        } while(0)
 
75
        if(dx > 0)
 
76
        {
 
77
            float drt = sqrt(dx);
 
78
            CHECKPLANE(x, -, focaldist/aspect, left, right);
 
79
            CHECKPLANE(x, +, focaldist/aspect, left, right);
 
80
        }
 
81
        if(dy > 0)
 
82
        {
 
83
            float drt = sqrt(dy);
 
84
            CHECKPLANE(y, -, focaldist, bottom, top);
 
85
            CHECKPLANE(y, +, focaldist, bottom, top);
 
86
        }
 
87
        return addblurtiles(left, bottom, right, top);
 
88
    }
 
89
 
 
90
    bool addscissorbox(const vec &bbmin, const vec &bbmax)
 
91
    {
 
92
        float sx1 = 1, sy1 = 1, sx2 = -1, sy2 = -1;
 
93
        loopi(8)
 
94
        {
 
95
            vec v(i&1 ? bbmax.x : bbmin.x, i&2 ? bbmax.y : bbmin.y, i&4 ? bbmax.z : bbmin.z);
 
96
            addscissorvert(v, sx1, sy1, sx2, sy2);
 
97
        }
 
98
        return addblurtiles(sx1, sy1, sx2, sy2);
 
99
    }
 
100
 
 
101
    bool screenview() const { return depthfxrect!=0; }
 
102
    bool texrect() const { return depthfxrect && hasTR; }
 
103
    bool filter() const { return depthfxfilter!=0; }
 
104
    bool highprecision() const { return colorfmt==GL_FLOAT_RG16_NV || colorfmt==GL_RGB16F_ARB || colorfmt==GL_RGB16; }
 
105
    bool emulatehighprecision() const { return depthfxemuprecision && !depthfxfilter; }
 
106
 
 
107
    bool shouldrender()
 
108
    {
 
109
        extern void finddepthfxranges();
 
110
        finddepthfxranges();
 
111
        return (numdepthfxranges && scissorx1 < scissorx2 && scissory1 < scissory2) || debugdepthfx;
 
112
    }
 
113
 
 
114
    bool dorender()
 
115
    {
 
116
        glClearColor(1, 1, 1, 1);
 
117
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
118
 
 
119
        depthfxing = true;
 
120
        refracting = -1;
 
121
 
 
122
        extern void renderdepthobstacles(const vec &bbmin, const vec &bbmax, float scale, float *ranges, int numranges);
 
123
        float scale = depthfxscale;
 
124
        float *ranges = depthfxranges;
 
125
        int numranges = numdepthfxranges;
 
126
        if(highprecision())
 
127
        {
 
128
            scale = depthfxfpscale;
 
129
            ranges = NULL;
 
130
            numranges = 0;
 
131
        }
 
132
        else if(emulatehighprecision())
 
133
        {
 
134
            scale = depthfxfpscale;
 
135
            ranges = NULL;
 
136
            numranges = -3;
 
137
        }
 
138
        renderdepthobstacles(depthfxmin, depthfxmax, scale, ranges, numranges);
 
139
 
 
140
        refracting = 0;
 
141
        depthfxing = false;
 
142
 
 
143
        return numdepthfxranges > 0;
 
144
    }
 
145
 
 
146
    void dodebug(int w, int h)
 
147
    {
 
148
        if(numdepthfxranges > 0)
 
149
        {
 
150
            glColor3f(0, 1, 0);
 
151
            debugscissor(w, h, true);
 
152
            glColor3f(0, 0, 1);
 
153
            debugblurtiles(w, h, true);
 
154
            glColor3f(1, 1, 1);
 
155
        }
 
156
    }
 
157
} depthfxtex;
 
158
 
 
159
void cleanupdepthfx()
 
160
{
 
161
    depthfxtex.cleanup(true);
 
162
}
 
163
 
 
164
void viewdepthfxtex()
 
165
{
 
166
    if(!depthfx) return;
 
167
    depthfxtex.debug();
 
168
}
 
169
 
 
170
bool depthfxing = false;
 
171
 
 
172
void drawdepthfxtex()
 
173
{
 
174
    if(!depthfx || renderpath==R_FIXEDFUNCTION) return;
 
175
 
 
176
    // Apple/ATI bug - fixed-function fog state can force software fallback even when fragment program is enabled
 
177
    glDisable(GL_FOG);
 
178
    depthfxtex.render(1<<depthfxsize, 1<<depthfxsize, blurdepthfx, blurdepthfxsigma/100.0f);
 
179
    glEnable(GL_FOG);
 
180
}
 
181
 
 
182
//cache our unit hemisphere
 
183
static GLushort *hemiindices = NULL;
 
184
static vec *hemiverts = NULL;
 
185
static int heminumverts = 0, heminumindices = 0;
 
186
static GLuint hemivbuf = 0, hemiebuf = 0;
 
187
 
 
188
static void subdivide(int depth, int face);
 
189
 
 
190
static void genface(int depth, int i1, int i2, int i3)
 
191
{
 
192
    int face = heminumindices; heminumindices += 3;
 
193
    hemiindices[face]   = i1;
 
194
    hemiindices[face+1] = i2;
 
195
    hemiindices[face+2] = i3;
 
196
    subdivide(depth, face);
 
197
}
 
198
 
 
199
static void subdivide(int depth, int face)
 
200
{
 
201
    if(depth-- <= 0) return;
 
202
    int idx[6];
 
203
    loopi(3) idx[i] = hemiindices[face+i];
 
204
    loopi(3)
 
205
    {
 
206
        int vert = heminumverts++;
 
207
        hemiverts[vert] = vec(hemiverts[idx[i]]).add(hemiverts[idx[(i+1)%3]]).normalize(); //push on to unit sphere
 
208
        idx[3+i] = vert;
 
209
        hemiindices[face+i] = vert;
 
210
    }
 
211
    subdivide(depth, face);
 
212
    loopi(3) genface(depth, idx[i], idx[3+i], idx[3+(i+2)%3]);
 
213
}
 
214
 
 
215
//subdiv version wobble much more nicely than a lat/longitude version
 
216
static void inithemisphere(int hres, int depth)
 
217
{
 
218
    const int tris = hres << (2*depth);
 
219
    heminumverts = heminumindices = 0;
 
220
    DELETEA(hemiverts);
 
221
    DELETEA(hemiindices);
 
222
    hemiverts = new vec[tris+1];
 
223
    hemiindices = new GLushort[tris*3];
 
224
    hemiverts[heminumverts++] = vec(0.0f, 0.0f, 1.0f); //build initial 'hres' sided pyramid
 
225
    loopi(hres)
 
226
    {
 
227
        float a = PI2*float(i)/hres;
 
228
        hemiverts[heminumverts++] = vec(cosf(a), sinf(a), 0.0f);
 
229
    }
 
230
    loopi(hres) genface(depth, 0, i+1, 1+(i+1)%hres);
 
231
 
 
232
    if(hasVBO)
 
233
    {
 
234
        if(renderpath!=R_FIXEDFUNCTION)
 
235
        {
 
236
            if(!hemivbuf) glGenBuffers_(1, &hemivbuf);
 
237
            glBindBuffer_(GL_ARRAY_BUFFER_ARB, hemivbuf);
 
238
            glBufferData_(GL_ARRAY_BUFFER_ARB, heminumverts*sizeof(vec), hemiverts, GL_STATIC_DRAW_ARB);
 
239
            DELETEA(hemiverts);
 
240
        }
 
241
 
 
242
        if(!hemiebuf) glGenBuffers_(1, &hemiebuf);
 
243
        glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, hemiebuf);
 
244
        glBufferData_(GL_ELEMENT_ARRAY_BUFFER_ARB, heminumindices*sizeof(GLushort), hemiindices, GL_STATIC_DRAW_ARB);
 
245
        DELETEA(hemiindices);
 
246
    }
 
247
}
 
248
 
 
249
static GLuint expmodtex[2] = {0, 0};
 
250
static GLuint lastexpmodtex = 0;
 
251
 
 
252
static GLuint createexpmodtex(int size, float minval)
 
253
{
 
254
    uchar *data = new uchar[size*size], *dst = data;
 
255
    loop(y, size) loop(x, size)
 
256
    {
 
257
        float dx = 2*float(x)/(size-1) - 1, dy = 2*float(y)/(size-1) - 1;
 
258
        float z = max(0.0f, 1.0f - dx*dx - dy*dy);
 
259
        if(minval) z = sqrtf(z);
 
260
        else loopk(2) z *= z;
 
261
        *dst++ = uchar(max(z, minval)*255);
 
262
    }
 
263
    GLuint tex = 0;
 
264
    glGenTextures(1, &tex);
 
265
    createtexture(tex, size, size, data, 3, true, GL_ALPHA);
 
266
    delete[] data;
 
267
    return tex;
 
268
}
 
269
 
 
270
static struct expvert
 
271
{
 
272
    vec pos;
 
273
    float u, v, s, t;
 
274
} *expverts = NULL;
 
275
static GLuint expvbuf = 0;
 
276
 
 
277
static void animateexplosion()
 
278
{
 
279
    static int lastexpmillis = 0;
 
280
    if(expverts && lastexpmillis == lastmillis)
 
281
    {
 
282
        if(hasVBO) glBindBuffer_(GL_ARRAY_BUFFER_ARB, expvbuf);
 
283
        return;
 
284
    }
 
285
    lastexpmillis = lastmillis;
 
286
    vec center = vec(13.0f, 2.3f, 7.1f);  //only update once per frame! - so use the same center for all...
 
287
    if(!expverts) expverts = new expvert[heminumverts];
 
288
    loopi(heminumverts)
 
289
    {
 
290
        expvert &e = expverts[i];
 
291
        vec &v = hemiverts[i];
 
292
        //texgen - scrolling billboard
 
293
        e.u = v.x*0.5f + 0.0004f*lastmillis;
 
294
        e.v = v.y*0.5f + 0.0004f*lastmillis;
 
295
        //ensure the mod texture is wobbled
 
296
        e.s = v.x*0.5f + 0.5f;
 
297
        e.t = v.y*0.5f + 0.5f;
 
298
        //wobble - similar to shader code
 
299
        float wobble = v.dot(center) + 0.002f*lastmillis;
 
300
        wobble -= floor(wobble);
 
301
        wobble = 1.0f + fabs(wobble - 0.5f)*0.5f;
 
302
        e.pos = vec(v).mul(wobble);
 
303
    }
 
304
 
 
305
    if(hasVBO)
 
306
    {
 
307
        if(!expvbuf) glGenBuffers_(1, &expvbuf);
 
308
        glBindBuffer_(GL_ARRAY_BUFFER_ARB, expvbuf);
 
309
        glBufferData_(GL_ARRAY_BUFFER_ARB, heminumverts*sizeof(expvert), expverts, GL_STREAM_DRAW_ARB);
 
310
    }
 
311
}
 
312
 
 
313
static struct spherevert
 
314
{
 
315
    vec pos;
 
316
    float s, t;
 
317
} *sphereverts = NULL;
 
318
static GLushort *sphereindices = NULL;
 
319
static int spherenumverts = 0, spherenumindices = 0;
 
320
static GLuint spherevbuf = 0, sphereebuf = 0;
 
321
 
 
322
static void initsphere(int slices, int stacks)
 
323
{
 
324
    DELETEA(sphereverts);
 
325
    spherenumverts = (stacks+1)*(slices+1);
 
326
    sphereverts = new spherevert[spherenumverts];
 
327
    float ds = 1.0f/slices, dt = 1.0f/stacks, t = 1.0f;
 
328
    loopi(stacks+1)
 
329
    {
 
330
        float rho = M_PI*(1-t), s = 0.0f;
 
331
        loopj(slices+1)
 
332
        {
 
333
            float theta = j==slices ? 0 : 2*M_PI*s;
 
334
            spherevert &v = sphereverts[i*(slices+1) + j];
 
335
            v.pos = vec(-sin(theta)*sin(rho), cos(theta)*sin(rho), cos(rho));
 
336
            v.s = s;
 
337
            v.t = t;
 
338
            s += ds;
 
339
        }
 
340
        t -= dt;
 
341
    }
 
342
 
 
343
    DELETEA(sphereindices);
 
344
    spherenumindices = stacks*slices*3*2;
 
345
    sphereindices = new ushort[spherenumindices];
 
346
    GLushort *curindex = sphereindices;
 
347
    loopi(stacks)
 
348
    {
 
349
        loopk(slices)
 
350
        {
 
351
            int j = i%2 ? slices-k-1 : k;
 
352
 
 
353
            *curindex++ = i*(slices+1)+j;
 
354
            *curindex++ = (i+1)*(slices+1)+j;
 
355
            *curindex++ = i*(slices+1)+j+1;
 
356
 
 
357
            *curindex++ = i*(slices+1)+j+1;
 
358
            *curindex++ = (i+1)*(slices+1)+j;
 
359
            *curindex++ = (i+1)*(slices+1)+j+1;
 
360
        }
 
361
    }
 
362
 
 
363
    if(hasVBO)
 
364
    {
 
365
        if(!spherevbuf) glGenBuffers_(1, &spherevbuf);
 
366
        glBindBuffer_(GL_ARRAY_BUFFER_ARB, spherevbuf);
 
367
        glBufferData_(GL_ARRAY_BUFFER_ARB, spherenumverts*sizeof(spherevert), sphereverts, GL_STATIC_DRAW_ARB);
 
368
        DELETEA(sphereverts);
 
369
 
 
370
        if(!sphereebuf) glGenBuffers_(1, &sphereebuf);
 
371
        glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, sphereebuf);
 
372
        glBufferData_(GL_ELEMENT_ARRAY_BUFFER_ARB, spherenumindices*sizeof(GLushort), sphereindices, GL_STATIC_DRAW_ARB);
 
373
        DELETEA(sphereindices);
 
374
    }
 
375
}
 
376
 
 
377
VARP(explosion2d, 0, 0, 1);
 
378
 
 
379
static void setupexplosion()
 
380
{
 
381
    if(renderpath!=R_FIXEDFUNCTION || maxtmus>=2)
 
382
    {
 
383
        if(!expmodtex[0]) expmodtex[0] = createexpmodtex(64, 0);
 
384
        if(!expmodtex[1]) expmodtex[1] = createexpmodtex(64, 0.25f);
 
385
        lastexpmodtex = 0;
 
386
    }
 
387
 
 
388
    if(renderpath!=R_FIXEDFUNCTION)
 
389
    {
 
390
        if(glaring)
 
391
        {
 
392
            if(explosion2d) SETSHADER(explosion2dglare); else SETSHADER(explosion3dglare);
 
393
        }
 
394
        else if(!reflecting && !refracting && depthfx && depthfxtex.rendertex && numdepthfxranges>0)
 
395
        {
 
396
            if(depthfxtex.target==GL_TEXTURE_RECTANGLE_ARB)
 
397
            {
 
398
                if(!depthfxtex.highprecision())
 
399
                {
 
400
                    if(explosion2d) SETSHADER(explosion2dsoft8rect); else SETSHADER(explosion3dsoft8rect);
 
401
                }
 
402
                else if(explosion2d) SETSHADER(explosion2dsoftrect); else SETSHADER(explosion3dsoftrect);
 
403
 
 
404
                setlocalparamf("depthfxview", SHPARAM_VERTEX, 6, 0.5f*depthfxtex.vieww, 0.5f*depthfxtex.viewh);
 
405
            }
 
406
            else
 
407
            {
 
408
                if(!depthfxtex.highprecision())
 
409
                {
 
410
                    if(explosion2d) SETSHADER(explosion2dsoft8); else SETSHADER(explosion3dsoft8);
 
411
                }
 
412
                else if(explosion2d) SETSHADER(explosion2dsoft); else SETSHADER(explosion3dsoft);
 
413
 
 
414
                setlocalparamf("depthfxview", SHPARAM_VERTEX, 6, 0.5f*float(depthfxtex.vieww)/depthfxtex.texw, 0.5f*float(depthfxtex.viewh)/depthfxtex.texh);
 
415
            }
 
416
 
 
417
            glActiveTexture_(GL_TEXTURE2_ARB);
 
418
            glBindTexture(depthfxtex.target, depthfxtex.rendertex);
 
419
            glActiveTexture_(GL_TEXTURE0_ARB);
 
420
        }
 
421
        else if(explosion2d) SETSHADER(explosion2d); else SETSHADER(explosion3d);
 
422
    }
 
423
 
 
424
    if(renderpath==R_FIXEDFUNCTION || explosion2d)
 
425
    {
 
426
        if(!hemiverts && !hemivbuf) inithemisphere(5, 2);
 
427
        if(renderpath==R_FIXEDFUNCTION) animateexplosion();
 
428
        if(hasVBO)
 
429
        {
 
430
            if(renderpath!=R_FIXEDFUNCTION) glBindBuffer_(GL_ARRAY_BUFFER_ARB, hemivbuf);
 
431
            glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, hemiebuf);
 
432
        }
 
433
 
 
434
        expvert *verts = renderpath==R_FIXEDFUNCTION ? (hasVBO ? 0 : expverts) : (expvert *)hemiverts;
 
435
 
 
436
        glEnableClientState(GL_VERTEX_ARRAY);
 
437
        glVertexPointer(3, GL_FLOAT, renderpath==R_FIXEDFUNCTION ? sizeof(expvert) : sizeof(vec), verts);
 
438
 
 
439
        if(renderpath==R_FIXEDFUNCTION)
 
440
        {
 
441
            glEnableClientState(GL_TEXTURE_COORD_ARRAY);
 
442
            glTexCoordPointer(2, GL_FLOAT, sizeof(expvert), &verts->u);
 
443
 
 
444
            if(maxtmus>=2)
 
445
            {
 
446
                setuptmu(0, "C * T", "= Ca");
 
447
 
 
448
                glActiveTexture_(GL_TEXTURE1_ARB);
 
449
                glClientActiveTexture_(GL_TEXTURE1_ARB);
 
450
 
 
451
                glEnable(GL_TEXTURE_2D);
 
452
                setuptmu(1, "P * Ta x 4", "Pa * Ta x 4");
 
453
                glEnableClientState(GL_TEXTURE_COORD_ARRAY);
 
454
                glTexCoordPointer(2, GL_FLOAT, sizeof(expvert), &verts->s);
 
455
 
 
456
                glActiveTexture_(GL_TEXTURE0_ARB);
 
457
                glClientActiveTexture_(GL_TEXTURE0_ARB);
 
458
            }
 
459
        }
 
460
    }
 
461
    else
 
462
    {
 
463
        if(!sphereverts && !spherevbuf) initsphere(12, 6);
 
464
 
 
465
        if(hasVBO)
 
466
        {
 
467
            glBindBuffer_(GL_ARRAY_BUFFER_ARB, spherevbuf);
 
468
            glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, sphereebuf);
 
469
        }
 
470
 
 
471
        glEnableClientState(GL_VERTEX_ARRAY);
 
472
        glEnableClientState(GL_TEXTURE_COORD_ARRAY);
 
473
        glVertexPointer(3, GL_FLOAT, sizeof(spherevert), &sphereverts->pos);
 
474
        glTexCoordPointer(2, GL_FLOAT, sizeof(spherevert), &sphereverts->s);
 
475
    }
 
476
}
 
477
 
 
478
static void drawexpverts(int numverts, int numindices, GLushort *indices)
 
479
{
 
480
    if(hasDRE) glDrawRangeElements_(GL_TRIANGLES, 0, numverts-1, numindices, GL_UNSIGNED_SHORT, indices);
 
481
    else glDrawElements(GL_TRIANGLES, numindices, GL_UNSIGNED_SHORT, indices);
 
482
    xtraverts += numindices;
 
483
    glde++;
 
484
}
 
485
 
 
486
static void drawexplosion(bool inside, uchar r, uchar g, uchar b, uchar a)
 
487
{
 
488
    if((renderpath!=R_FIXEDFUNCTION || maxtmus>=2) && lastexpmodtex != expmodtex[inside ? 1 : 0])
 
489
    {
 
490
        glActiveTexture_(GL_TEXTURE1_ARB);
 
491
        lastexpmodtex = expmodtex[inside ? 1 :0];
 
492
        glBindTexture(GL_TEXTURE_2D, lastexpmodtex);
 
493
        glActiveTexture_(GL_TEXTURE0_ARB);
 
494
    }
 
495
    int passes = !reflecting && !refracting && inside ? 2 : 1;
 
496
    if(renderpath!=R_FIXEDFUNCTION && !explosion2d)
 
497
    {
 
498
        if(inside) glScalef(1, 1, -1);
 
499
        loopi(passes)
 
500
        {
 
501
            glColor4ub(r, g, b, i ? a/2 : a);
 
502
            if(i) glDepthFunc(GL_GEQUAL);
 
503
            drawexpverts(spherenumverts, spherenumindices, sphereindices);
 
504
            if(i) glDepthFunc(GL_LESS);
 
505
        }
 
506
        return;
 
507
    }
 
508
    loopi(passes)
 
509
    {
 
510
        glColor4ub(r, g, b, i ? a/2 : a);
 
511
        if(i)
 
512
        {
 
513
            glScalef(1, 1, -1);
 
514
            glDepthFunc(GL_GEQUAL);
 
515
        }
 
516
        if(inside)
 
517
        {
 
518
            if(passes >= 2)
 
519
            {
 
520
                glCullFace(GL_BACK);
 
521
                drawexpverts(heminumverts, heminumindices, hemiindices);
 
522
                glCullFace(GL_FRONT);
 
523
            }
 
524
            glScalef(1, 1, -1);
 
525
        }
 
526
        drawexpverts(heminumverts, heminumindices, hemiindices);
 
527
        if(i) glDepthFunc(GL_LESS);
 
528
    }
 
529
}
 
530
 
 
531
static void cleanupexplosion()
 
532
{
 
533
    glDisableClientState(GL_VERTEX_ARRAY);
 
534
    if(renderpath==R_FIXEDFUNCTION)
 
535
    {
 
536
        glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 
537
 
 
538
        if(maxtmus>=2)
 
539
        {
 
540
            resettmu(0);
 
541
 
 
542
            glActiveTexture_(GL_TEXTURE1_ARB);
 
543
            glClientActiveTexture_(GL_TEXTURE1_ARB);
 
544
 
 
545
            glDisable(GL_TEXTURE_2D);
 
546
            resettmu(1);
 
547
            glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 
548
 
 
549
            glActiveTexture_(GL_TEXTURE0_ARB);
 
550
            glClientActiveTexture_(GL_TEXTURE0_ARB);
 
551
        }
 
552
    }
 
553
    else
 
554
    {
 
555
        if(explosion2d) glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 
556
 
 
557
        if(fogging) setfogplane(1, reflectz);
 
558
    }
 
559
 
 
560
    if(hasVBO)
 
561
    {
 
562
        glBindBuffer_(GL_ARRAY_BUFFER_ARB, 0);
 
563
        glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
 
564
    }
 
565
}
 
566
 
 
567
static void deleteexplosions()
 
568
{
 
569
    loopi(2) if(expmodtex[i]) { glDeleteTextures(1, &expmodtex[i]); expmodtex[i] = 0; }
 
570
    if(hemivbuf) { glDeleteBuffers_(1, &hemivbuf); hemivbuf = 0; }
 
571
    if(hemiebuf) { glDeleteBuffers_(1, &hemiebuf); hemiebuf = 0; }
 
572
    DELETEA(hemiverts);
 
573
    DELETEA(hemiindices);
 
574
    if(expvbuf) { glDeleteBuffers_(1, &expvbuf); expvbuf = 0; }
 
575
    DELETEA(expverts);
 
576
    if(spherevbuf) { glDeleteBuffers_(1, &spherevbuf); spherevbuf = 0; }
 
577
    if(sphereebuf) { glDeleteBuffers_(1, &sphereebuf); sphereebuf = 0; }
 
578
    DELETEA(sphereverts);
 
579
    DELETEA(sphereindices);
 
580
}
 
581
 
 
582
static const float WOBBLE = 1.25f;
 
583
 
 
584
struct fireballrenderer : listrenderer
 
585
{
 
586
    fireballrenderer(int type)
 
587
        : listrenderer("packages/particles/explosion.jpg", type, 0, 0)
 
588
    {}
 
589
 
 
590
    void startrender()
 
591
    {
 
592
        setupexplosion();
 
593
    }
 
594
 
 
595
    void endrender()
 
596
    {
 
597
        cleanupexplosion();
 
598
        particleshader->set();
 
599
    }
 
600
 
 
601
    void cleanup()
 
602
    {
 
603
        deleteexplosions();
 
604
    }
 
605
 
 
606
    int finddepthfxranges(void **owners, float *ranges, int maxranges, vec &bbmin, vec &bbmax)
 
607
    {
 
608
        physent e;
 
609
        e.type = ENT_CAMERA;
 
610
 
 
611
        int numranges = 0;
 
612
        for(listparticle *p = list; p; p = p->next)
 
613
        {
 
614
            int ts = p->fade <= 5 ? 1 : lastmillis-p->millis;
 
615
            float pmax = p->val,
 
616
                  size = p->fade ? float(ts)/p->fade : 1,
 
617
                  psize = (p->size + pmax * size)*WOBBLE;
 
618
            if(2*(p->size + pmax)*WOBBLE < depthfxblend ||
 
619
               (!depthfxtex.highprecision() && !depthfxtex.emulatehighprecision() && psize > depthfxscale - depthfxbias) ||
 
620
               isvisiblesphere(psize, p->o) >= VFC_FOGGED) continue;
 
621
 
 
622
            e.o = p->o;
 
623
            e.radius = e.eyeheight = e.aboveeye = psize;
 
624
            if(::collide(&e, vec(0, 0, 0), 0, false)) continue;
 
625
 
 
626
            if(depthfxscissor==2 && !depthfxtex.addscissorbox(p->o, psize)) continue;
 
627
 
 
628
            vec dir = camera1->o;
 
629
            dir.sub(p->o);
 
630
            float dist = dir.magnitude();
 
631
            dir.mul(psize/dist).add(p->o);
 
632
            float depth = depthfxtex.eyedepth(dir);
 
633
 
 
634
            loopk(3)
 
635
            {
 
636
                bbmin[k] = min(bbmin[k], p->o[k] - psize);
 
637
                bbmax[k] = max(bbmax[k], p->o[k] + psize);
 
638
            }
 
639
 
 
640
            int pos = numranges;
 
641
            loopi(numranges) if(depth < ranges[i]) { pos = i; break; }
 
642
            if(pos >= maxranges) continue;
 
643
 
 
644
            if(numranges > pos)
 
645
            {
 
646
                int moved = min(numranges-pos, maxranges-(pos+1));
 
647
                memmove(&ranges[pos+1], &ranges[pos], moved*sizeof(float));
 
648
                memmove(&owners[pos+1], &owners[pos], moved*sizeof(void *));
 
649
            }
 
650
            if(numranges < maxranges) numranges++;
 
651
 
 
652
            ranges[pos] = depth;
 
653
            owners[pos] = p;
 
654
        }
 
655
 
 
656
        return numranges;
 
657
    }
 
658
 
 
659
    void renderpart(listparticle *p, const vec &o, const vec &d, int blend, int ts, uchar *color)
 
660
    {
 
661
        float pmax = p->val,
 
662
              size = p->fade ? float(ts)/p->fade : 1,
 
663
              psize = p->size + pmax * size;
 
664
 
 
665
        if(isvisiblesphere(psize*WOBBLE, p->o) >= VFC_FOGGED) return;
 
666
 
 
667
        glPushMatrix();
 
668
        glTranslatef(o.x, o.y, o.z);
 
669
        if(fogging)
 
670
        {
 
671
            if(renderpath!=R_FIXEDFUNCTION) setfogplane(0, reflectz - o.z, true);
 
672
            else blend = (uchar)(blend * max(0.0f, min(1.0f, 1.0f - (reflectz - o.z)/waterfog)));
 
673
        }
 
674
 
 
675
        bool inside = o.dist(camera1->o) <= psize*WOBBLE;
 
676
        vec oc(o);
 
677
        oc.sub(camera1->o);
 
678
        if(reflecting) oc.z = o.z - reflectz;
 
679
 
 
680
        float yaw = inside ? camera1->yaw - 180 : atan2(oc.y, oc.x)/RAD - 90,
 
681
        pitch = (inside ? camera1->pitch : asin(oc.z/oc.magnitude())/RAD) - 90;
 
682
        vec rotdir;
 
683
        if(renderpath==R_FIXEDFUNCTION || explosion2d)
 
684
        {
 
685
            glRotatef(yaw, 0, 0, 1);
 
686
            glRotatef(pitch, 1, 0, 0);
 
687
            rotdir = vec(0, 0, 1);
 
688
        }
 
689
        else
 
690
        {
 
691
            vec s(1, 0, 0), t(0, 1, 0);
 
692
            s.rotate(pitch*RAD, vec(-1, 0, 0));
 
693
            s.rotate(yaw*RAD, vec(0, 0, -1));
 
694
            t.rotate(pitch*RAD, vec(-1, 0, 0));
 
695
            t.rotate(yaw*RAD, vec(0, 0, -1));
 
696
 
 
697
            rotdir = vec(-1, 1, -1).normalize();
 
698
            s.rotate(-lastmillis/7.0f*RAD, rotdir);
 
699
            t.rotate(-lastmillis/7.0f*RAD, rotdir);
 
700
 
 
701
            setlocalparamf("texgenS", SHPARAM_VERTEX, 2, 0.5f*s.x, 0.5f*s.y, 0.5f*s.z, 0.5f);
 
702
            setlocalparamf("texgenT", SHPARAM_VERTEX, 3, 0.5f*t.x, 0.5f*t.y, 0.5f*t.z, 0.5f);
 
703
        }
 
704
 
 
705
        if(renderpath!=R_FIXEDFUNCTION)
 
706
        {
 
707
            setlocalparamf("center", SHPARAM_VERTEX, 0, o.x, o.y, o.z);
 
708
            setlocalparamf("animstate", SHPARAM_VERTEX, 1, size, psize, pmax, float(lastmillis));
 
709
            if(!glaring && !reflecting && !refracting && depthfx && depthfxtex.rendertex && numdepthfxranges>0)
 
710
            {
 
711
                float scale = 0, offset = -1, texscale = 0;
 
712
                if(!depthfxtex.highprecision())
 
713
                {
 
714
                    float select[4] = { 0, 0, 0, 0 };
 
715
                    if(!depthfxtex.emulatehighprecision())
 
716
                    {
 
717
                        loopi(numdepthfxranges) if(depthfxowners[i]==p)
 
718
                        {
 
719
                            select[i] = float(depthfxscale)/depthfxblend;
 
720
                            scale = 1.0f/depthfxblend;
 
721
                            offset = -float(depthfxranges[i] - depthfxbias)/depthfxblend;
 
722
                            break;
 
723
                        }
 
724
                    }
 
725
                    else if(2*(p->size + pmax)*WOBBLE >= depthfxblend)
 
726
                    {
 
727
                        select[0] = float(depthfxfpscale)/depthfxblend;
 
728
                        select[1] = select[0]/256;
 
729
                        select[2] = select[1]/256;
 
730
                        scale = 1.0f/depthfxblend;
 
731
                        offset = 0;
 
732
                    }
 
733
                    setlocalparamfv("depthfxselect", SHPARAM_PIXEL, 6, select);
 
734
                }
 
735
                else if(2*(p->size + pmax)*WOBBLE >= depthfxblend)
 
736
                {
 
737
                    scale = 1.0f/depthfxblend;
 
738
                    offset = 0;
 
739
                    texscale = float(depthfxfpscale)/depthfxblend;
 
740
                }
 
741
                setlocalparamf("depthfxparams", SHPARAM_VERTEX, 5, scale, offset, texscale, inside ? blend/(2*255.0f) : 0);
 
742
                setlocalparamf("depthfxparams", SHPARAM_PIXEL, 5, scale, offset, texscale, inside ? blend/(2*255.0f) : 0);
 
743
            }
 
744
        }
 
745
 
 
746
        glRotatef(lastmillis/7.0f, -rotdir.x, rotdir.y, -rotdir.z);
 
747
        glScalef(-psize, psize, -psize);
 
748
        drawexplosion(inside, color[0], color[1], color[2], blend);
 
749
 
 
750
        glPopMatrix();
 
751
    }
 
752
};
 
753
static fireballrenderer fireballs(PT_FIREBALL|PT_GLARE), noglarefireballs(PT_FIREBALL);
 
754
 
 
755
void finddepthfxranges()
 
756
{
 
757
    depthfxmin = vec(1e16f, 1e16f, 1e16f);
 
758
    depthfxmax = vec(0, 0, 0);
 
759
    numdepthfxranges = fireballs.finddepthfxranges(depthfxowners, depthfxranges, MAXDFXRANGES, depthfxmin, depthfxmax);
 
760
    loopk(3)
 
761
    {
 
762
        depthfxmin[k] -= depthfxmargin;
 
763
        depthfxmax[k] += depthfxmargin;
 
764
    }
 
765
 
 
766
    if(depthfxscissor<2 && numdepthfxranges>0) depthfxtex.addscissorbox(depthfxmin, depthfxmax);
 
767
}
 
768