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);
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);
21
#define MAXDFXRANGES 4
23
void *depthfxowners[MAXDFXRANGES];
24
float depthfxranges[MAXDFXRANGES];
25
int numdepthfxranges = 0;
26
vec depthfxmin(1e16f, 1e16f, 1e16f), depthfxmax(1e16f, 1e16f, 1e16f);
28
static struct depthfxtexture : rendertarget
30
const GLenum *colorformats() const
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];
36
float eyedepth(const vec &p) const
38
return max(-(p.x*mvmatrix[2] + p.y*mvmatrix[6] + p.z*mvmatrix[10] + mvmatrix[14]), 0.0f);
41
void addscissorvert(const vec &v, float &sx1, float &sy1, float &sx2, float &sy2)
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;
52
bool addscissorbox(const vec ¢er, float size)
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) \
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); \
69
float c = nz*(focaldist)/nc, \
71
if(pc < e.c) low = c; \
72
else if(pc > e.c) high = c; \
78
CHECKPLANE(x, -, focaldist/aspect, left, right);
79
CHECKPLANE(x, +, focaldist/aspect, left, right);
84
CHECKPLANE(y, -, focaldist, bottom, top);
85
CHECKPLANE(y, +, focaldist, bottom, top);
87
return addblurtiles(left, bottom, right, top);
90
bool addscissorbox(const vec &bbmin, const vec &bbmax)
92
float sx1 = 1, sy1 = 1, sx2 = -1, sy2 = -1;
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);
98
return addblurtiles(sx1, sy1, sx2, sy2);
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; }
109
extern void finddepthfxranges();
111
return (numdepthfxranges && scissorx1 < scissorx2 && scissory1 < scissory2) || debugdepthfx;
116
glClearColor(1, 1, 1, 1);
117
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
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;
128
scale = depthfxfpscale;
132
else if(emulatehighprecision())
134
scale = depthfxfpscale;
138
renderdepthobstacles(depthfxmin, depthfxmax, scale, ranges, numranges);
143
return numdepthfxranges > 0;
146
void dodebug(int w, int h)
148
if(numdepthfxranges > 0)
151
debugscissor(w, h, true);
153
debugblurtiles(w, h, true);
159
void cleanupdepthfx()
161
depthfxtex.cleanup(true);
164
void viewdepthfxtex()
170
bool depthfxing = false;
172
void drawdepthfxtex()
174
if(!depthfx || renderpath==R_FIXEDFUNCTION) return;
176
// Apple/ATI bug - fixed-function fog state can force software fallback even when fragment program is enabled
178
depthfxtex.render(1<<depthfxsize, 1<<depthfxsize, blurdepthfx, blurdepthfxsigma/100.0f);
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;
188
static void subdivide(int depth, int face);
190
static void genface(int depth, int i1, int i2, int i3)
192
int face = heminumindices; heminumindices += 3;
193
hemiindices[face] = i1;
194
hemiindices[face+1] = i2;
195
hemiindices[face+2] = i3;
196
subdivide(depth, face);
199
static void subdivide(int depth, int face)
201
if(depth-- <= 0) return;
203
loopi(3) idx[i] = hemiindices[face+i];
206
int vert = heminumverts++;
207
hemiverts[vert] = vec(hemiverts[idx[i]]).add(hemiverts[idx[(i+1)%3]]).normalize(); //push on to unit sphere
209
hemiindices[face+i] = vert;
211
subdivide(depth, face);
212
loopi(3) genface(depth, idx[i], idx[3+i], idx[3+(i+2)%3]);
215
//subdiv version wobble much more nicely than a lat/longitude version
216
static void inithemisphere(int hres, int depth)
218
const int tris = hres << (2*depth);
219
heminumverts = heminumindices = 0;
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
227
float a = PI2*float(i)/hres;
228
hemiverts[heminumverts++] = vec(cosf(a), sinf(a), 0.0f);
230
loopi(hres) genface(depth, 0, i+1, 1+(i+1)%hres);
234
if(renderpath!=R_FIXEDFUNCTION)
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);
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);
249
static GLuint expmodtex[2] = {0, 0};
250
static GLuint lastexpmodtex = 0;
252
static GLuint createexpmodtex(int size, float minval)
254
uchar *data = new uchar[size*size], *dst = data;
255
loop(y, size) loop(x, size)
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);
264
glGenTextures(1, &tex);
265
createtexture(tex, size, size, data, 3, true, GL_ALPHA);
270
static struct expvert
275
static GLuint expvbuf = 0;
277
static void animateexplosion()
279
static int lastexpmillis = 0;
280
if(expverts && lastexpmillis == lastmillis)
282
if(hasVBO) glBindBuffer_(GL_ARRAY_BUFFER_ARB, expvbuf);
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];
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);
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);
313
static struct spherevert
317
} *sphereverts = NULL;
318
static GLushort *sphereindices = NULL;
319
static int spherenumverts = 0, spherenumindices = 0;
320
static GLuint spherevbuf = 0, sphereebuf = 0;
322
static void initsphere(int slices, int stacks)
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;
330
float rho = M_PI*(1-t), s = 0.0f;
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));
343
DELETEA(sphereindices);
344
spherenumindices = stacks*slices*3*2;
345
sphereindices = new ushort[spherenumindices];
346
GLushort *curindex = sphereindices;
351
int j = i%2 ? slices-k-1 : k;
353
*curindex++ = i*(slices+1)+j;
354
*curindex++ = (i+1)*(slices+1)+j;
355
*curindex++ = i*(slices+1)+j+1;
357
*curindex++ = i*(slices+1)+j+1;
358
*curindex++ = (i+1)*(slices+1)+j;
359
*curindex++ = (i+1)*(slices+1)+j+1;
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);
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);
377
VARP(explosion2d, 0, 0, 1);
379
static void setupexplosion()
381
if(renderpath!=R_FIXEDFUNCTION || maxtmus>=2)
383
if(!expmodtex[0]) expmodtex[0] = createexpmodtex(64, 0);
384
if(!expmodtex[1]) expmodtex[1] = createexpmodtex(64, 0.25f);
388
if(renderpath!=R_FIXEDFUNCTION)
392
if(explosion2d) SETSHADER(explosion2dglare); else SETSHADER(explosion3dglare);
394
else if(!reflecting && !refracting && depthfx && depthfxtex.rendertex && numdepthfxranges>0)
396
if(depthfxtex.target==GL_TEXTURE_RECTANGLE_ARB)
398
if(!depthfxtex.highprecision())
400
if(explosion2d) SETSHADER(explosion2dsoft8rect); else SETSHADER(explosion3dsoft8rect);
402
else if(explosion2d) SETSHADER(explosion2dsoftrect); else SETSHADER(explosion3dsoftrect);
404
setlocalparamf("depthfxview", SHPARAM_VERTEX, 6, 0.5f*depthfxtex.vieww, 0.5f*depthfxtex.viewh);
408
if(!depthfxtex.highprecision())
410
if(explosion2d) SETSHADER(explosion2dsoft8); else SETSHADER(explosion3dsoft8);
412
else if(explosion2d) SETSHADER(explosion2dsoft); else SETSHADER(explosion3dsoft);
414
setlocalparamf("depthfxview", SHPARAM_VERTEX, 6, 0.5f*float(depthfxtex.vieww)/depthfxtex.texw, 0.5f*float(depthfxtex.viewh)/depthfxtex.texh);
417
glActiveTexture_(GL_TEXTURE2_ARB);
418
glBindTexture(depthfxtex.target, depthfxtex.rendertex);
419
glActiveTexture_(GL_TEXTURE0_ARB);
421
else if(explosion2d) SETSHADER(explosion2d); else SETSHADER(explosion3d);
424
if(renderpath==R_FIXEDFUNCTION || explosion2d)
426
if(!hemiverts && !hemivbuf) inithemisphere(5, 2);
427
if(renderpath==R_FIXEDFUNCTION) animateexplosion();
430
if(renderpath!=R_FIXEDFUNCTION) glBindBuffer_(GL_ARRAY_BUFFER_ARB, hemivbuf);
431
glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, hemiebuf);
434
expvert *verts = renderpath==R_FIXEDFUNCTION ? (hasVBO ? 0 : expverts) : (expvert *)hemiverts;
436
glEnableClientState(GL_VERTEX_ARRAY);
437
glVertexPointer(3, GL_FLOAT, renderpath==R_FIXEDFUNCTION ? sizeof(expvert) : sizeof(vec), verts);
439
if(renderpath==R_FIXEDFUNCTION)
441
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
442
glTexCoordPointer(2, GL_FLOAT, sizeof(expvert), &verts->u);
446
setuptmu(0, "C * T", "= Ca");
448
glActiveTexture_(GL_TEXTURE1_ARB);
449
glClientActiveTexture_(GL_TEXTURE1_ARB);
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);
456
glActiveTexture_(GL_TEXTURE0_ARB);
457
glClientActiveTexture_(GL_TEXTURE0_ARB);
463
if(!sphereverts && !spherevbuf) initsphere(12, 6);
467
glBindBuffer_(GL_ARRAY_BUFFER_ARB, spherevbuf);
468
glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, sphereebuf);
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);
478
static void drawexpverts(int numverts, int numindices, GLushort *indices)
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;
486
static void drawexplosion(bool inside, uchar r, uchar g, uchar b, uchar a)
488
if((renderpath!=R_FIXEDFUNCTION || maxtmus>=2) && lastexpmodtex != expmodtex[inside ? 1 : 0])
490
glActiveTexture_(GL_TEXTURE1_ARB);
491
lastexpmodtex = expmodtex[inside ? 1 :0];
492
glBindTexture(GL_TEXTURE_2D, lastexpmodtex);
493
glActiveTexture_(GL_TEXTURE0_ARB);
495
int passes = !reflecting && !refracting && inside ? 2 : 1;
496
if(renderpath!=R_FIXEDFUNCTION && !explosion2d)
498
if(inside) glScalef(1, 1, -1);
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);
510
glColor4ub(r, g, b, i ? a/2 : a);
514
glDepthFunc(GL_GEQUAL);
521
drawexpverts(heminumverts, heminumindices, hemiindices);
522
glCullFace(GL_FRONT);
526
drawexpverts(heminumverts, heminumindices, hemiindices);
527
if(i) glDepthFunc(GL_LESS);
531
static void cleanupexplosion()
533
glDisableClientState(GL_VERTEX_ARRAY);
534
if(renderpath==R_FIXEDFUNCTION)
536
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
542
glActiveTexture_(GL_TEXTURE1_ARB);
543
glClientActiveTexture_(GL_TEXTURE1_ARB);
545
glDisable(GL_TEXTURE_2D);
547
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
549
glActiveTexture_(GL_TEXTURE0_ARB);
550
glClientActiveTexture_(GL_TEXTURE0_ARB);
555
if(explosion2d) glDisableClientState(GL_TEXTURE_COORD_ARRAY);
557
if(fogging) setfogplane(1, reflectz);
562
glBindBuffer_(GL_ARRAY_BUFFER_ARB, 0);
563
glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
567
static void deleteexplosions()
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; }
573
DELETEA(hemiindices);
574
if(expvbuf) { glDeleteBuffers_(1, &expvbuf); expvbuf = 0; }
576
if(spherevbuf) { glDeleteBuffers_(1, &spherevbuf); spherevbuf = 0; }
577
if(sphereebuf) { glDeleteBuffers_(1, &sphereebuf); sphereebuf = 0; }
578
DELETEA(sphereverts);
579
DELETEA(sphereindices);
582
static const float WOBBLE = 1.25f;
584
struct fireballrenderer : listrenderer
586
fireballrenderer(int type)
587
: listrenderer("packages/particles/explosion.jpg", type, 0, 0)
598
particleshader->set();
606
int finddepthfxranges(void **owners, float *ranges, int maxranges, vec &bbmin, vec &bbmax)
612
for(listparticle *p = list; p; p = p->next)
614
int ts = p->fade <= 5 ? 1 : lastmillis-p->millis;
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;
623
e.radius = e.eyeheight = e.aboveeye = psize;
624
if(::collide(&e, vec(0, 0, 0), 0, false)) continue;
626
if(depthfxscissor==2 && !depthfxtex.addscissorbox(p->o, psize)) continue;
628
vec dir = camera1->o;
630
float dist = dir.magnitude();
631
dir.mul(psize/dist).add(p->o);
632
float depth = depthfxtex.eyedepth(dir);
636
bbmin[k] = min(bbmin[k], p->o[k] - psize);
637
bbmax[k] = max(bbmax[k], p->o[k] + psize);
641
loopi(numranges) if(depth < ranges[i]) { pos = i; break; }
642
if(pos >= maxranges) continue;
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 *));
650
if(numranges < maxranges) numranges++;
659
void renderpart(listparticle *p, const vec &o, const vec &d, int blend, int ts, uchar *color)
662
size = p->fade ? float(ts)/p->fade : 1,
663
psize = p->size + pmax * size;
665
if(isvisiblesphere(psize*WOBBLE, p->o) >= VFC_FOGGED) return;
668
glTranslatef(o.x, o.y, o.z);
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)));
675
bool inside = o.dist(camera1->o) <= psize*WOBBLE;
678
if(reflecting) oc.z = o.z - reflectz;
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;
683
if(renderpath==R_FIXEDFUNCTION || explosion2d)
685
glRotatef(yaw, 0, 0, 1);
686
glRotatef(pitch, 1, 0, 0);
687
rotdir = vec(0, 0, 1);
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));
697
rotdir = vec(-1, 1, -1).normalize();
698
s.rotate(-lastmillis/7.0f*RAD, rotdir);
699
t.rotate(-lastmillis/7.0f*RAD, rotdir);
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);
705
if(renderpath!=R_FIXEDFUNCTION)
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)
711
float scale = 0, offset = -1, texscale = 0;
712
if(!depthfxtex.highprecision())
714
float select[4] = { 0, 0, 0, 0 };
715
if(!depthfxtex.emulatehighprecision())
717
loopi(numdepthfxranges) if(depthfxowners[i]==p)
719
select[i] = float(depthfxscale)/depthfxblend;
720
scale = 1.0f/depthfxblend;
721
offset = -float(depthfxranges[i] - depthfxbias)/depthfxblend;
725
else if(2*(p->size + pmax)*WOBBLE >= depthfxblend)
727
select[0] = float(depthfxfpscale)/depthfxblend;
728
select[1] = select[0]/256;
729
select[2] = select[1]/256;
730
scale = 1.0f/depthfxblend;
733
setlocalparamfv("depthfxselect", SHPARAM_PIXEL, 6, select);
735
else if(2*(p->size + pmax)*WOBBLE >= depthfxblend)
737
scale = 1.0f/depthfxblend;
739
texscale = float(depthfxfpscale)/depthfxblend;
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);
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);
753
static fireballrenderer fireballs(PT_FIREBALL|PT_GLARE), noglarefireballs(PT_FIREBALL);
755
void finddepthfxranges()
757
depthfxmin = vec(1e16f, 1e16f, 1e16f);
758
depthfxmax = vec(0, 0, 0);
759
numdepthfxranges = fireballs.finddepthfxranges(depthfxowners, depthfxranges, MAXDFXRANGES, depthfxmin, depthfxmax);
762
depthfxmin[k] -= depthfxmargin;
763
depthfxmax[k] += depthfxmargin;
766
if(depthfxscissor<2 && numdepthfxranges>0) depthfxtex.addscissorbox(depthfxmin, depthfxmax);