196 lines
5.4 KiB
C++
196 lines
5.4 KiB
C++
VARP(softexplosion, 0, 1, 1);
|
|
VARP(softexplosionblend, 1, 16, 64);
|
|
|
|
namespace sphere
|
|
{
|
|
struct vert
|
|
{
|
|
vec pos;
|
|
ushort s, t;
|
|
} *verts = NULL;
|
|
GLushort *indices = NULL;
|
|
int numverts = 0, numindices = 0;
|
|
GLuint vbuf = 0, ebuf = 0;
|
|
|
|
void init(int slices, int stacks)
|
|
{
|
|
numverts = (stacks+1)*(slices+1);
|
|
verts = new vert[numverts];
|
|
float ds = 1.0f/slices, dt = 1.0f/stacks, t = 1.0f;
|
|
loopi(stacks+1)
|
|
{
|
|
float rho = M_PI*(1-t), s = 0.0f, sinrho = i && i < stacks ? sin(rho) : 0, cosrho = !i ? 1 : (i < stacks ? cos(rho) : -1);
|
|
loopj(slices+1)
|
|
{
|
|
float theta = j==slices ? 0 : 2*M_PI*s;
|
|
vert &v = verts[i*(slices+1) + j];
|
|
v.pos = vec(sin(theta)*sinrho, cos(theta)*sinrho, -cosrho);
|
|
v.s = ushort(s*0xFFFF);
|
|
v.t = ushort(t*0xFFFF);
|
|
s += ds;
|
|
}
|
|
t -= dt;
|
|
}
|
|
|
|
numindices = (stacks-1)*slices*3*2;
|
|
indices = new ushort[numindices];
|
|
GLushort *curindex = indices;
|
|
loopi(stacks)
|
|
{
|
|
loopk(slices)
|
|
{
|
|
int j = i%2 ? slices-k-1 : k;
|
|
if(i)
|
|
{
|
|
*curindex++ = i*(slices+1)+j;
|
|
*curindex++ = (i+1)*(slices+1)+j;
|
|
*curindex++ = i*(slices+1)+j+1;
|
|
}
|
|
if(i+1 < stacks)
|
|
{
|
|
*curindex++ = i*(slices+1)+j+1;
|
|
*curindex++ = (i+1)*(slices+1)+j;
|
|
*curindex++ = (i+1)*(slices+1)+j+1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(!vbuf) glGenBuffers_(1, &vbuf);
|
|
gle::bindvbo(vbuf);
|
|
glBufferData_(GL_ARRAY_BUFFER, numverts*sizeof(vert), verts, GL_STATIC_DRAW);
|
|
DELETEA(verts);
|
|
|
|
if(!ebuf) glGenBuffers_(1, &ebuf);
|
|
gle::bindebo(ebuf);
|
|
glBufferData_(GL_ELEMENT_ARRAY_BUFFER, numindices*sizeof(GLushort), indices, GL_STATIC_DRAW);
|
|
DELETEA(indices);
|
|
}
|
|
|
|
void cleanup()
|
|
{
|
|
if(vbuf) { glDeleteBuffers_(1, &vbuf); vbuf = 0; }
|
|
if(ebuf) { glDeleteBuffers_(1, &ebuf); ebuf = 0; }
|
|
}
|
|
|
|
void enable()
|
|
{
|
|
if(!vbuf) init(12, 6);
|
|
|
|
gle::bindvbo(vbuf);
|
|
gle::bindebo(ebuf);
|
|
|
|
gle::vertexpointer(sizeof(vert), &verts->pos);
|
|
gle::texcoord0pointer(sizeof(vert), &verts->s, GL_UNSIGNED_SHORT, 2, GL_TRUE);
|
|
gle::enablevertex();
|
|
gle::enabletexcoord0();
|
|
}
|
|
|
|
void draw()
|
|
{
|
|
glDrawRangeElements_(GL_TRIANGLES, 0, numverts-1, numindices, GL_UNSIGNED_SHORT, indices);
|
|
xtraverts += numindices;
|
|
glde++;
|
|
}
|
|
|
|
void disable()
|
|
{
|
|
gle::disablevertex();
|
|
gle::disabletexcoord0();
|
|
|
|
gle::clearvbo();
|
|
gle::clearebo();
|
|
}
|
|
}
|
|
|
|
static const float WOBBLE = 1.25f;
|
|
|
|
struct fireballrenderer : listrenderer
|
|
{
|
|
fireballrenderer(const char *texname)
|
|
: listrenderer(texname, 0, PT_FIREBALL|PT_SHADER)
|
|
{}
|
|
|
|
void startrender()
|
|
{
|
|
if(softparticles && softexplosion) SETSHADER(explosionsoft);
|
|
else SETSHADER(explosion);
|
|
|
|
sphere::enable();
|
|
}
|
|
|
|
void endrender()
|
|
{
|
|
sphere::disable();
|
|
}
|
|
|
|
void cleanup()
|
|
{
|
|
sphere::cleanup();
|
|
}
|
|
|
|
void seedemitter(particleemitter &pe, const vec &o, const vec &d, int fade, float size, int gravity)
|
|
{
|
|
pe.maxfade = max(pe.maxfade, fade);
|
|
pe.extendbb(o, (size+1+pe.ent->attr2)*WOBBLE);
|
|
}
|
|
|
|
void renderpart(listparticle *p, const vec &o, const vec &d, int blend, int ts)
|
|
{
|
|
float pmax = p->val,
|
|
size = p->fade ? float(ts)/p->fade : 1,
|
|
psize = p->size + pmax * size;
|
|
|
|
if(isfoggedsphere(psize*WOBBLE, p->o)) return;
|
|
|
|
vec dir = vec(o).sub(camera1->o), s, t;
|
|
float dist = dir.magnitude();
|
|
bool inside = dist <= psize*WOBBLE;
|
|
if(inside)
|
|
{
|
|
s = camright;
|
|
t = camup;
|
|
}
|
|
else
|
|
{
|
|
float mag2 = dir.magnitude2();
|
|
dir.x /= mag2;
|
|
dir.y /= mag2;
|
|
dir.z /= dist;
|
|
s = vec(dir.y, -dir.x, 0);
|
|
t = vec(dir.x*dir.z, dir.y*dir.z, -mag2/dist);
|
|
}
|
|
|
|
matrix3 rot(lastmillis/1000.0f*143*RAD, vec(1/SQRT3, 1/SQRT3, 1/SQRT3));
|
|
LOCALPARAM(texgenS, rot.transposedtransform(s));
|
|
LOCALPARAM(texgenT, rot.transposedtransform(t));
|
|
|
|
matrix4 m(rot, o);
|
|
m.scale(psize, psize, inside ? -psize : psize);
|
|
m.mul(camprojmatrix, m);
|
|
LOCALPARAM(explosionmatrix, m);
|
|
|
|
LOCALPARAM(center, o);
|
|
LOCALPARAMF(blendparams, inside ? 0.5f : 4, inside ? 0.25f : 0);
|
|
if(2*(p->size + pmax)*WOBBLE >= softexplosionblend)
|
|
{
|
|
LOCALPARAMF(softparams, -1.0f/softexplosionblend, 0, inside ? blend/(2*255.0f) : 0);
|
|
}
|
|
else
|
|
{
|
|
LOCALPARAMF(softparams, 0, -1, inside ? blend/(2*255.0f) : 0);
|
|
}
|
|
|
|
vec color = p->color.tocolor().mul(ldrscale);
|
|
float alpha = blend/255.0f;
|
|
|
|
loopi(inside ? 2 : 1)
|
|
{
|
|
gle::color(color, i ? alpha/2 : alpha);
|
|
if(i) glDepthFunc(GL_GEQUAL);
|
|
sphere::draw();
|
|
if(i) glDepthFunc(GL_LESS);
|
|
}
|
|
}
|
|
};
|
|
static fireballrenderer fireballs("media/particle/explosion.png"), pulsebursts("media/particle/pulse_burst.png");
|
|
|