summaryrefslogtreecommitdiff
path: root/src/engine/decal.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/engine/decal.cpp')
-rw-r--r--src/engine/decal.cpp281
1 files changed, 79 insertions, 202 deletions
diff --git a/src/engine/decal.cpp b/src/engine/decal.cpp
index 43ef667..bc39c1f 100644
--- a/src/engine/decal.cpp
+++ b/src/engine/decal.cpp
@@ -1,21 +1,18 @@
#include "engine.h"
-struct decalvert
-{
+struct decalvert {
vec pos;
bvec4 color;
vec2 tc;
};
-struct decalinfo
-{
+struct decalinfo {
int millis;
bvec color;
ushort startvert, endvert;
};
-enum
-{
+enum {
DF_RND4 = 1<<0,
DF_ROTATE = 1<<1,
DF_INVMOD = 1<<2,
@@ -27,8 +24,7 @@ enum
VARFP(maxdecaltris, 1, 1024, 16384, initdecals());
VARP(decalfade, 1000, 10000, 60000);
-struct decalrenderer
-{
+struct decalrenderer {
const char *texname;
int flags, fadeintime, fadeouttime, timetolive;
Texture *tex;
@@ -38,7 +34,6 @@ struct decalrenderer
int maxverts, startvert, endvert, lastvert, availverts;
GLuint vbo;
bool dirty;
-
decalrenderer(const char *texname, int flags = 0, int fadeintime = 0, int fadeouttime = 1000, int timetolive = -1)
: texname(texname), flags(flags),
fadeintime(fadeintime), fadeouttime(fadeouttime), timetolive(timetolive),
@@ -46,25 +41,18 @@ struct decalrenderer
decals(NULL), maxdecals(0), startdecal(0), enddecal(0),
verts(NULL), maxverts(0), startvert(0), endvert(0), lastvert(0), availverts(0),
vbo(0), dirty(false),
- decalu(0), decalv(0)
- {
+ decalu(0), decalv(0) {
}
-
- ~decalrenderer()
- {
+ ~decalrenderer() {
DELETEA(decals);
DELETEA(verts);
}
-
- void init(int tris)
- {
- if(decals)
- {
+ void init(int tris) {
+ if(decals) {
DELETEA(decals);
maxdecals = startdecal = enddecal = 0;
}
- if(verts)
- {
+ if(verts) {
DELETEA(verts);
maxverts = startvert = endvert = lastvert = availverts = 0;
}
@@ -75,80 +63,59 @@ struct decalrenderer
availverts = maxverts - 3;
verts = new decalvert[maxverts];
}
-
- int hasdecals()
- {
+ int hasdecals() {
return enddecal < startdecal ? maxdecals - (startdecal - enddecal) : enddecal - startdecal;
}
-
- void cleanup()
- {
+ void cleanup() {
if(vbo) { glDeleteBuffers_(1, &vbo); vbo = 0; }
}
-
- void cleardecals()
- {
+ void cleardecals() {
startdecal = enddecal = 0;
startvert = endvert = lastvert = 0;
availverts = maxverts - 3;
dirty = true;
}
-
- int freedecal()
- {
+ int freedecal() {
if(startdecal==enddecal) return 0;
-
decalinfo &d = decals[startdecal];
startdecal++;
if(startdecal >= maxdecals) startdecal = 0;
-
int removed = d.endvert < d.startvert ? maxverts - (d.startvert - d.endvert) : d.endvert - d.startvert;
startvert = d.endvert;
if(startvert==endvert) startvert = endvert = lastvert = 0;
availverts += removed;
-
return removed;
}
-
- void fadedecal(decalinfo &d, uchar alpha)
- {
+ void fadedecal(decalinfo &d, uchar alpha) {
bvec rgb;
if(flags&DF_OVERBRIGHT) rgb = bvec(128, 128, 128);
- else
- {
+ else {
rgb = d.color;
if(flags&(DF_ADD|DF_INVMOD)) rgb.scale(alpha, 255);
}
bvec4 color(rgb, alpha);
-
decalvert *vert = &verts[d.startvert],
*end = &verts[d.endvert < d.startvert ? maxverts : d.endvert];
- while(vert < end)
- {
+ while(vert < end) {
vert->color = color;
vert++;
}
- if(d.endvert < d.startvert)
- {
+ if(d.endvert < d.startvert) {
vert = verts;
end = &verts[d.endvert];
- while(vert < end)
- {
+ while(vert < end) {
vert->color = color;
vert++;
}
}
dirty = true;
}
-
- void clearfadeddecals()
- {
+ void clearfadeddecals() {
int threshold = lastmillis - (timetolive>=0 ? timetolive : decalfade) - fadeouttime;
decalinfo *d = &decals[startdecal],
*end = &decals[enddecal < startdecal ? maxdecals : enddecal];
while(d < end && d->millis <= threshold) d++;
- if(d >= end && enddecal < startdecal)
- {
+ if(d >= end && enddecal < startdecal) {
d = decals;
end = &decals[enddecal];
while(d < end && d->millis <= threshold) d++;
@@ -161,25 +128,20 @@ struct decalrenderer
availverts = endvert < startvert ? startvert - endvert - 3 : maxverts - 3 - (endvert - startvert);
dirty = true;
}
-
- void fadeindecals()
- {
+ void fadeindecals() {
if(!fadeintime) return;
decalinfo *d = &decals[enddecal],
*end = &decals[enddecal < startdecal ? 0 : startdecal];
- while(d > end)
- {
+ while(d > end) {
d--;
int fade = lastmillis - d->millis;
if(fade >= fadeintime) return;
fadedecal(*d, (fade<<8)/fadeintime);
}
- if(enddecal < startdecal)
- {
+ if(enddecal < startdecal) {
d = &decals[maxdecals];
end = &decals[startdecal];
- while(d > end)
- {
+ while(d > end) {
d--;
int fade = lastmillis - d->millis;
if(fade >= fadeintime) return;
@@ -187,25 +149,20 @@ struct decalrenderer
}
}
}
-
- void fadeoutdecals()
- {
+ void fadeoutdecals() {
decalinfo *d = &decals[startdecal],
*end = &decals[enddecal < startdecal ? maxdecals : enddecal];
int offset = (timetolive>=0 ? timetolive : decalfade) + fadeouttime - lastmillis;
- while(d < end)
- {
+ while(d < end) {
int fade = d->millis + offset;
if(fade >= fadeouttime) return;
fadedecal(*d, (fade<<8)/fadeouttime);
d++;
}
- if(enddecal < startdecal)
- {
+ if(enddecal < startdecal) {
d = decals;
end = &decals[enddecal];
- while(d < end)
- {
+ while(d < end) {
int fade = d->millis + offset;
if(fade >= fadeouttime) return;
fadedecal(*d, (fade<<8)/fadeouttime);
@@ -213,84 +170,59 @@ struct decalrenderer
}
}
}
-
- static void setuprenderstate()
- {
+ static void setuprenderstate() {
enablepolygonoffset(GL_POLYGON_OFFSET_FILL);
-
glDepthMask(GL_FALSE);
glEnable(GL_BLEND);
-
gle::enablevertex();
gle::enabletexcoord0();
gle::enablecolor();
}
-
- static void cleanuprenderstate()
- {
+ static void cleanuprenderstate() {
gle::clearvbo();
-
gle::disablevertex();
gle::disabletexcoord0();
gle::disablecolor();
-
glDepthMask(GL_TRUE);
glDisable(GL_BLEND);
-
disablepolygonoffset(GL_POLYGON_OFFSET_FILL);
}
-
- void render()
- {
+ void render() {
if(startvert==endvert) return;
-
- if(flags&DF_OVERBRIGHT)
- {
+ if(flags&DF_OVERBRIGHT) {
glBlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
SETSHADER(overbrightdecal);
}
- else
- {
+ else {
if(flags&DF_INVMOD) { glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR); }
else if(flags&DF_ADD) { glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR); }
else glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
if(flags&DF_SATURATE) SETSHADER(saturatedecal);
}
-
glBindTexture(GL_TEXTURE_2D, tex->id);
-
if(!vbo) { glGenBuffers_(1, &vbo); dirty = true; }
gle::bindvbo(vbo);
-
int count = endvert < startvert ? maxverts - startvert : endvert - startvert;
- if(dirty)
- {
+ if(dirty) {
glBufferData_(GL_ARRAY_BUFFER, maxverts*sizeof(decalvert), NULL, GL_STREAM_DRAW);
glBufferSubData_(GL_ARRAY_BUFFER, 0, count*sizeof(decalvert), &verts[startvert]);
- if(endvert < startvert)
- {
+ if(endvert < startvert) {
glBufferSubData_(GL_ARRAY_BUFFER, count*sizeof(decalvert), endvert*sizeof(decalvert), verts);
count += endvert;
}
dirty = false;
}
else if(endvert < startvert) count += endvert;
-
const decalvert *ptr = 0;
gle::vertexpointer(sizeof(decalvert), ptr->pos.v);
gle::texcoord0pointer(sizeof(decalvert), ptr->tc.v);
gle::colorpointer(sizeof(decalvert), ptr->color.v);
-
glDrawArrays(GL_TRIANGLES, 0, count);
xtravertsva += count;
-
extern int intel_vertexarray_bug;
if(intel_vertexarray_bug) glFlush();
}
-
- decalinfo &newdecal()
- {
+ decalinfo &newdecal() {
decalinfo &d = decals[enddecal];
int next = enddecal + 1;
if(next>=maxdecals) next = 0;
@@ -299,20 +231,15 @@ struct decalrenderer
dirty = true;
return d;
}
-
ivec bbmin, bbmax;
vec decalcenter, decalnormal, decaltangent, decalbitangent;
float decalradius, decalu, decalv;
bvec4 decalcolor;
-
- void adddecal(const vec &center, const vec &dir, float radius, const bvec &color, int info)
- {
+ void adddecal(const vec &center, const vec &dir, float radius, const bvec &color, int info) {
if(dir.iszero()) return;
-
int bbradius = int(ceil(radius));
bbmin = ivec(center).sub(bbradius);
bbmax = ivec(center).add(bbradius);
-
decalcolor = bvec4(color, 255);
decalcenter = center;
decalradius = radius;
@@ -326,46 +253,36 @@ struct decalrenderer
if(flags&DF_ROTATE) decaltangent.rotate(rnd(360)*RAD, dir);
decaltangent.normalize();
decalbitangent.cross(decaltangent, dir);
- if(flags&DF_RND4)
- {
+ if(flags&DF_RND4) {
decalu = 0.5f*(info&1);
decalv = 0.5f*((info>>1)&1);
}
-
lastvert = endvert;
gentris(worldroot, ivec(0, 0, 0), worldsize>>1);
if(endvert==lastvert) return;
-
decalinfo &d = newdecal();
d.color = color;
d.millis = lastmillis;
d.startvert = lastvert;
d.endvert = endvert;
}
-
- static int clip(const vec *in, int numin, const vec &dir, float below, float above, vec *out)
- {
+ static int clip(const vec *in, int numin, const vec &dir, float below, float above, vec *out) {
int numout = 0;
const vec *p = &in[numin-1];
float pc = dir.dot(*p);
- loopi(numin)
- {
+ loopi(numin) {
const vec &v = in[i];
float c = dir.dot(v);
- if(c < below)
- {
+ if(c < below) {
if(pc > above) out[numout++] = vec(*p).sub(v).mul((above - c)/(pc - c)).add(v);
if(pc > below) out[numout++] = vec(*p).sub(v).mul((below - c)/(pc - c)).add(v);
}
- else if(c > above)
- {
+ else if(c > above) {
if(pc < below) out[numout++] = vec(*p).sub(v).mul((below - c)/(pc - c)).add(v);
if(pc < above) out[numout++] = vec(*p).sub(v).mul((above - c)/(pc - c)).add(v);
}
- else
- {
- if(pc < below)
- {
+ else {
+ if(pc < below) {
if(c > below) out[numout++] = vec(*p).sub(v).mul((below - c)/(pc - c)).add(v);
}
else if(pc > above && c < above) out[numout++] = vec(*p).sub(v).mul((above - c)/(pc - c)).add(v);
@@ -376,17 +293,13 @@ struct decalrenderer
}
return numout;
}
-
- void gentris(cube &cu, int orient, const ivec &o, int size, materialsurface *mat = NULL, int vismask = 0)
- {
+ void gentris(cube &cu, int orient, const ivec &o, int size, materialsurface *mat = NULL, int vismask = 0) {
vec pos[MAXFACEVERTS+4] = { vec(0, 0, 0) };
int numverts = 0, numplanes = 1;
vec planes[2] = { vec(0, 0, 0) };
- if(mat)
- {
+ if(mat) {
planes[0] = vec(0, 0, 0);
- switch(orient)
- {
+ switch(orient) {
#define GENFACEORIENT(orient, v0, v1, v2, v3) \
case orient: \
planes[0][dimension(orient)] = dimcoord(orient) ? 1 : -1; \
@@ -399,21 +312,18 @@ struct decalrenderer
#undef GENFACEVERT
}
}
- else if(cu.ext && (numverts = cu.ext->surfaces[orient].numverts&MAXFACEVERTS))
- {
+ else if(cu.ext && (numverts = cu.ext->surfaces[orient].numverts&MAXFACEVERTS)) {
vertinfo *verts = cu.ext->verts() + cu.ext->surfaces[orient].verts;
ivec vo = ivec(o).mask(~0xFFF).shl(3);
loopj(numverts) pos[j] = vec(verts[j].getxyz().add(vo)).mul(1/8.0f);
planes[0].cross(pos[0], pos[1], pos[2]).normalize();
- if(numverts >= 4 && !(cu.merged&(1<<orient)) && !flataxisface(cu, orient) && faceconvexity(verts, numverts, size))
- {
+ if(numverts >= 4 && !(cu.merged&(1<<orient)) && !flataxisface(cu, orient) && faceconvexity(verts, numverts, size)) {
planes[1].cross(pos[0], pos[2], pos[3]).normalize();
numplanes++;
}
}
else if(cu.merged&(1<<orient)) return;
- else if(!vismask || (vismask&0x40 && visibleface(cu, orient, o, size, MAT_AIR, (cu.material&MAT_ALPHA)^MAT_ALPHA, MAT_ALPHA)))
- {
+ else if(!vismask || (vismask&0x40 && visibleface(cu, orient, o, size, MAT_AIR, (cu.material&MAT_ALPHA)^MAT_ALPHA, MAT_ALPHA))) {
ivec v[4];
genfaceverts(cu, orient, v);
int vis = 3, convex = faceconvexity(v, vis), order = convex < 0 ? 1 : 0;
@@ -426,9 +336,7 @@ struct decalrenderer
if(convex) { planes[1].cross(pos[0], pos[2], pos[3]).normalize(); numplanes++; }
}
else return;
-
- loopl(numplanes)
- {
+ loopl(numplanes) {
const vec &n = planes[l];
float facing = n.dot(decalnormal);
if(facing <= 0) continue;
@@ -455,14 +363,12 @@ struct decalrenderer
vec v1[MAXFACEVERTS+4], v2[MAXFACEVERTS+4];
float ptc = pt.dot(pcenter), pbc = pb.dot(pcenter);
int numv;
- if(numplanes >= 2)
- {
+ if(numplanes >= 2) {
if(l) { pos[1] = pos[2]; pos[2] = pos[3]; }
numv = clip(pos, 3, pt, ptc - decalradius, ptc + decalradius, v1);
if(numv<3) continue;
}
- else
- {
+ else {
numv = clip(pos, numverts, pt, ptc - decalradius, ptc + decalradius, v1);
if(numv<3) continue;
}
@@ -475,13 +381,11 @@ struct decalrenderer
dv2 = { v2[1], decalcolor, vec2(pt.dot(v2[1]) + tu, pb.dot(v2[1]) + tv) };
int totalverts = 3*(numv-2);
if(totalverts > maxverts-3) return;
- while(availverts < totalverts)
- {
+ while(availverts < totalverts) {
if(!freedecal()) return;
}
availverts -= totalverts;
- loopk(numv-2)
- {
+ loopk(numv-2) {
verts[endvert++] = dv1;
verts[endvert++] = dv2;
dv2.pos = v2[k+2];
@@ -491,25 +395,20 @@ struct decalrenderer
}
}
}
-
- void findmaterials(vtxarray *va)
- {
+ void findmaterials(vtxarray *va) {
materialsurface *matbuf = va->matbuf;
int matsurfs = va->matsurfs;
- loopi(matsurfs)
- {
+ loopi(matsurfs) {
materialsurface &m = matbuf[i];
if(1) { i += m.skip; continue; }
int dim = dimension(m.orient), dc = dimcoord(m.orient);
if(dc ? decalnormal[dim] <= 0 : decalnormal[dim] >= 0) { i += m.skip; continue; }
int c = C[dim], r = R[dim];
- for(;;)
- {
+ for(;;) {
materialsurface &m = matbuf[i];
if(m.o[dim] >= bbmin[dim] && m.o[dim] <= bbmax[dim] &&
m.o[c] + m.csize >= bbmin[c] && m.o[c] <= bbmax[c] &&
- m.o[r] + m.rsize >= bbmin[r] && m.o[r] <= bbmax[r])
- {
+ m.o[r] + m.rsize >= bbmin[r] && m.o[r] <= bbmax[r]) {
static cube dummy;
gentris(dummy, m.orient, m.o, max(m.csize, m.rsize), &m);
}
@@ -520,51 +419,38 @@ struct decalrenderer
}
}
}
-
- void findescaped(cube *cu, const ivec &o, int size, int escaped)
- {
- loopi(8)
- {
- if(escaped&(1<<i))
- {
+ void findescaped(cube *cu, const ivec &o, int size, int escaped) {
+ loopi(8) {
+ if(escaped&(1<<i)) {
ivec co(i, o, size);
if(cu[i].children) findescaped(cu[i].children, co, size>>1, cu[i].escaped);
- else
- {
+ else {
int vismask = cu[i].merged;
if(vismask) loopj(6) if(vismask&(1<<j)) gentris(cu[i], j, co, size);
}
}
}
}
-
- void gentris(cube *cu, const ivec &o, int size, int escaped = 0)
- {
+ void gentris(cube *cu, const ivec &o, int size, int escaped = 0) {
int overlap = octaboxoverlap(o, size, bbmin, bbmax);
- loopi(8)
- {
- if(overlap&(1<<i))
- {
+ loopi(8) {
+ if(overlap&(1<<i)) {
ivec co(i, o, size);
if(cu[i].ext && cu[i].ext->va && cu[i].ext->va->matsurfs)
findmaterials(cu[i].ext->va);
if(cu[i].children) gentris(cu[i].children, co, size>>1, cu[i].escaped);
- else
- {
+ else {
int vismask = cu[i].visible;
- if(vismask&0xC0)
- {
+ if(vismask&0xC0) {
if(vismask&0x80) loopj(6) gentris(cu[i], j, co, size, NULL, vismask);
else loopj(6) if(vismask&(1<<j)) gentris(cu[i], j, co, size);
}
}
}
- else if(escaped&(1<<i))
- {
+ else if(escaped&(1<<i)) {
ivec co(i, o, size);
if(cu[i].children) findescaped(cu[i].children, co, size>>1, cu[i].escaped);
- else
- {
+ else {
int vismask = cu[i].merged;
if(vismask) loopj(6) if(vismask&(1<<j)) gentris(cu[i], j, co, size);
}
@@ -573,45 +459,37 @@ struct decalrenderer
}
};
-decalrenderer decals[] =
-{
+decalrenderer decals[] = {
decalrenderer("<grey>packages/particles/scorch.png", DF_ROTATE, 500),
decalrenderer("<grey>packages/particles/blood.png", DF_RND4|DF_ROTATE|DF_INVMOD),
decalrenderer("<grey>packages/particles/bullet.png", DF_OVERBRIGHT)
};
-void initdecals()
-{
+void initdecals() {
loopi(sizeof(decals)/sizeof(decals[0])) decals[i].init(maxdecaltris);
}
-void cleardecals()
-{
+void cleardecals() {
loopi(sizeof(decals)/sizeof(decals[0])) decals[i].cleardecals();
}
-void cleanupdecals()
-{
+void cleanupdecals() {
loopi(sizeof(decals)/sizeof(decals[0])) decals[i].cleanup();
}
VARNP(decals, showdecals, 0, 1, 1);
-void renderdecals(bool mainpass)
-{
+void renderdecals(bool mainpass) {
bool rendered = false;
- loopi(sizeof(decals)/sizeof(decals[0]))
- {
+ loopi(sizeof(decals)/sizeof(decals[0])) {
decalrenderer &d = decals[i];
- if(mainpass)
- {
+ if(mainpass) {
d.clearfadeddecals();
d.fadeindecals();
d.fadeoutdecals();
}
if(!showdecals || !d.hasdecals()) continue;
- if(!rendered)
- {
+ if(!rendered) {
rendered = true;
decalrenderer::setuprenderstate();
}
@@ -623,8 +501,7 @@ void renderdecals(bool mainpass)
VARP(maxdecaldistance, 1, 512, 10000);
-void adddecal(int type, const vec &center, const vec &surface, float radius, const bvec &color, int info)
-{
+void adddecal(int type, const vec &center, const vec &surface, float radius, const bvec &color, int info) {
if(!showdecals || type<0 || (size_t)type>=sizeof(decals)/sizeof(decals[0]) || center.dist(camera1->o) - radius > maxdecaldistance) return;
decalrenderer &d = decals[type];
d.adddecal(center, surface, radius, color, info);