AssaultCube Reloaded Wiki
Explore
Main Page
All Pages
Community
Interactive Maps
Recent Blog Posts
Wiki Content
Recently Changed Pages
AssaultCube Reloaded Wiki
Douze
Weapons
Linux Support
Compiling
Mods
Server Guide
Source code
Rendergl.cpp
Server.h
Ac bot.cpp
Ac bot.h
Ac bot ai.cpp
Bot.cpp
Bot.h
Maps
Official maps
Cube maps
Official maps
Acr mini arena
Ac metl2
Ac desert4
Ext ac desert2
Community
Recent blog posts
Forum
FANDOM
Fan Central
BETA
Games
Anime
Movies
TV
Video
Wikis
Explore Wikis
Community Central
Start a Wiki
Don't have an account?
Register
Sign In
Sign In
Register
AssaultCube Reloaded Wiki
153
pages
Explore
Main Page
All Pages
Community
Interactive Maps
Recent Blog Posts
Wiki Content
Recently Changed Pages
AssaultCube Reloaded Wiki
Douze
Weapons
Linux Support
Compiling
Mods
Server Guide
Source code
Rendergl.cpp
Server.h
Ac bot.cpp
Ac bot.h
Ac bot ai.cpp
Bot.cpp
Bot.h
Maps
Official maps
Cube maps
Official maps
Acr mini arena
Ac metl2
Ac desert4
Ext ac desert2
Community
Recent blog posts
Forum
Editing
Renderparticles.cpp
Back to page
Edit
Edit source
View history
Talk (0)
Warning:
You are not logged in. Your IP address will be publicly visible if you make any edits. If you
log in
or
create an account
, your edits will be attributed to your username, along with other benefits.
Anti-spam check. Do
not
fill this in!
<source lang="cpp"> // renderparticles.cpp #include "cube.h" static GLushort *hemiindices = NULL; static vec *hemiverts = NULL; static int heminumverts = 0, heminumindices = 0; static void subdivide(int depth, int face); static void genface(int depth, int i1, int i2, int i3) { int face = heminumindices; heminumindices += 3; hemiindices[face] = i1; hemiindices[face+1] = i2; hemiindices[face+2] = i3; subdivide(depth, face); } static void subdivide(int depth, int face) { if(depth-- <= 0) return; int idx[6]; loopi(3) idx[i] = hemiindices[face+i]; loopi(3) { int vert = heminumverts++; hemiverts[vert] = vec(hemiverts[idx[i]]).add(hemiverts[idx[(i+1)%3]]).normalize(); //push on to unit sphere idx[3+i] = vert; hemiindices[face+i] = vert; } subdivide(depth, face); loopi(3) genface(depth, idx[i], idx[3+i], idx[3+(i+2)%3]); } //subdiv version wobble much more nicely than a lat/longitude version static void inithemisphere(int hres, int depth) { const int tris = hres << (2*depth); heminumverts = heminumindices = 0; DELETEA(hemiverts); DELETEA(hemiindices); hemiverts = new vec[tris+1]; hemiindices = new GLushort[tris*3]; hemiverts[heminumverts++] = vec(0.0f, 0.0f, 1.0f); //build initial 'hres' sided pyramid loopi(hres) { float a = PI2*float(i)/hres; hemiverts[heminumverts++] = vec(cosf(a), sinf(a), 0.0f); } loopi(hres) genface(depth, 0, i+1, 1+(i+1)%hres); } GLuint createexpmodtex(int size, float minval) { uchar *data = new uchar[size*size], *dst = data; loop(y, size) loop(x, size) { float dx = 2*float(x)/(size-1) - 1, dy = 2*float(y)/(size-1) - 1; float z = max(0.0f, 1.0f - dx*dx - dy*dy); if(minval) z = sqrtf(z); else loopk(2) z *= z; *dst++ = uchar(max(z, minval)*255); } GLuint tex = 0; glGenTextures(1, &tex); createtexture(tex, size, size, data, 3, true, false, GL_ALPHA); delete[] data; return tex; } static struct expvert { vec pos; float u, v, s, t; } *expverts = NULL; static GLuint expmodtex[2] = {0, 0}; static GLuint lastexpmodtex = 0; VARP(mtexplosion, 0, 1, 1); void setupexplosion() { if(!hemiindices) inithemisphere(5, 2); static int lastexpmillis = 0; if(lastexpmillis != lastmillis || !expverts) { vec center = vec(13.0f, 2.3f, 7.1f); lastexpmillis = lastmillis; if(!expverts) expverts = new expvert[heminumverts]; loopi(heminumverts) { expvert &e = expverts[i]; vec &v = hemiverts[i]; e.u = v.x*0.5f + 0.001f*lastmillis; e.v = v.y*0.5f + 0.001f*lastmillis; e.s = v.x*0.5f + 0.5f; e.t = v.y*0.5f + 0.5f; float wobble = v.dot(center) + 0.002f*lastmillis; wobble -= floor(wobble); wobble = 1.0f + fabs(wobble - 0.5f)*0.5f; e.pos = vec(v).mul(wobble); } } glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(3, GL_FLOAT, sizeof(expvert), &expverts->pos); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(2, GL_FLOAT, sizeof(expvert), &expverts->u); if(mtexplosion && maxtmus>=2) { setuptmu(0, "C * T", "= Ca"); glActiveTexture_(GL_TEXTURE1_ARB); glClientActiveTexture_(GL_TEXTURE1_ARB); glEnable(GL_TEXTURE_2D); setuptmu(1, "P * Ta x 4", "Pa * Ta x 4"); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(2, GL_FLOAT, sizeof(expvert), &expverts->s); glActiveTexture_(GL_TEXTURE0_ARB); glClientActiveTexture_(GL_TEXTURE0_ARB); if(!expmodtex[0]) expmodtex[0] = createexpmodtex(64, 0); if(!expmodtex[1]) expmodtex[1] = createexpmodtex(64, 0.25f); lastexpmodtex = 0; } } void drawexplosion(bool inside, float r, float g, float b, float a) { if(mtexplosion && maxtmus>=2 && lastexpmodtex != expmodtex[inside ? 1 : 0]) { glActiveTexture_(GL_TEXTURE1_ARB); lastexpmodtex = expmodtex[inside ? 1 :0]; glBindTexture(GL_TEXTURE_2D, lastexpmodtex); glActiveTexture_(GL_TEXTURE0_ARB); } loopi(!reflecting && inside ? 2 : 1) { glColor4f(r, g, b, i ? a/2 : a); if(i) { glScalef(1, 1, -1); glDepthFunc(GL_GEQUAL); } if(inside) { if(!reflecting) { glCullFace(GL_BACK); glDrawElements(GL_TRIANGLES, heminumindices, GL_UNSIGNED_SHORT, hemiindices); glCullFace(GL_FRONT); } glScalef(1, 1, -1); } glDrawElements(GL_TRIANGLES, heminumindices, GL_UNSIGNED_SHORT, hemiindices); if(i) glDepthFunc(GL_LESS); } } void cleanupexplosion() { glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); if(mtexplosion && maxtmus>=2) { resettmu(0); glActiveTexture_(GL_TEXTURE1_ARB); glClientActiveTexture_(GL_TEXTURE1_ARB); glDisable(GL_TEXTURE_2D); resettmu(1); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glActiveTexture_(GL_TEXTURE0_ARB); glClientActiveTexture_(GL_TEXTURE0_ARB); } } struct particle { vec o, d; int fade, type; int millis; particle *next; }; particle *parlist[MAXPARTYPES], *parempty = NULL; static Texture *parttex[7]; void particleinit() { loopi(MAXPARTYPES) parlist[i] = NULL; parttex[0] = textureload("packages/misc/base.png"); parttex[1] = textureload("packages/misc/smoke.png"); parttex[2] = textureload("packages/misc/explosion.png"); parttex[3] = textureload("<decal>packages/misc/bullethole.png"); parttex[4] = textureload("packages/misc/blood.png"); parttex[5] = textureload("packages/misc/scorch.png"); parttex[6] = textureload("packages/misc/muzzleflash.jpg"); } void cleanupparticles() { loopi(2) if(expmodtex[i]) { glDeleteTextures(1, &expmodtex[i]); expmodtex[i] = 0; } } void particlereset() { loopi(MAXPARTYPES) { while(parlist[i]) { particle *p = parlist[i]; parlist[i] = p->next; p->next = parempty; parempty = p; } } } void newparticle(const vec &o, const vec &d, int fade, int type) { if(OUTBORD((int)o.x, (int)o.y)) return; if(!parempty) { particle *ps = new particle[256]; loopi(256) { ps[i].next = parempty; parempty = &ps[i]; } } particle *p = parempty; parempty = p->next; p->o = o; p->d = d; p->fade = fade; p->type = type; p->millis = lastmillis; p->next = parlist[type]; parlist[type] = p; } static struct parttype { int type; float r, g, b; int gr, tex; float sz; } parttypes[MAXPARTYPES] = { { PT_PART, 0.4f, 0.4f, 0.4f, 2, 0, 0.06f }, // yellow: sparks { PT_PART, 1.0f, 1.0f, 1.0f, 20, 1, 0.15f }, // grey: small smoke { PT_PART, 0.0f, 0.0f, 1.0f, 20, 0, 0.08f }, // blue: edit mode closest ent { PT_BLOOD, 0.5f, 0.0f, 0.0f, 1, 4, 0.3f }, // red: blood spats { PT_PART, 1.0f, 0.1f, 0.1f, 0, 1, 0.2f }, // red: demotrack { PT_FIREBALL, 1.0f, 0.5f, 0.5f, 0, 2, 7.0f }, // explosion fireball { PT_SHOTLINE, 1.0f, 1.0f, 0.7f, 0, -1, 0.0f }, // yellow: shotline { PT_BULLETHOLE, 1.0f, 1.0f, 1.0f, 0, 3, 0.3f }, // hole decal { PT_STAIN, 0.5f, 0.0f, 0.0f, 0, 4, 0.6f }, // red: blood stain { PT_DECAL, 1.0f, 1.0f, 1.0f, 0, 5, 1.5f }, // scorch decal { PT_HUDFLASH, 1.0f, 1.0f, 1.0f, 0, 6, 0.7f }, // hudgun muzzle flash { PT_FLASH, 1.0f, 1.0f, 1.0f, 0, 6, 0.7f }, // muzzle flash { PT_PART, 1.0f, 1.0f, 1.0f, 20, 0, 0.08f }, // white: edit mode ent type : light { PT_PART, 0.0f, 1.0f, 0.0f, 20, 0, 0.08f }, // green: edit mode ent type : spawn { PT_PART, 1.0f, 0.0f, 0.0f, 20, 0, 0.08f }, // red: edit mode ent type : ammo { PT_PART, 1.0f, 1.0f, 0.0f, 20, 0, 0.08f }, // yellow: edit mode ent type : pickup { PT_PART, 1.0f, 0.0f, 1.0f, 20, 0, 0.08f }, // magenta: edit mode ent type : model, sound { PT_PART, 1.0f, 0.5f, 0.2f, 20, 0, 0.08f }, // orange: edit mode ent type : "carrot" { PT_PART, 0.5f, 0.5f, 0.5f, 20, 0, 0.08f }, // grey: edit mode ent type : ladder, (pl)clip { PT_PART, 0.0f, 1.0f, 1.0f, 20, 0, 0.08f }, // turquoise: edit mode ent type : CTF-flag // 2011jun18 : shotty decals { PT_BULLETHOLE, 0.2f, 0.2f, 1.0f, 0, 3, 0.1f }, // hole decal M { PT_BULLETHOLE, 0.2f, 1.0f, 0.2f, 0, 3, 0.1f }, // hole decal C // ACR extra particles { PT_FIREBALL, 1.0f, 1.0f, 0.5f, 0, 2, 4.0f }, // [22] RPG explosion fireball { PT_PART, 0.2f, 1.0f, 0.3f, 18, 1, 0.13f }, // [23] green: heal-line { PT_PART, 1.0f, 0.2f, 0.2f, 15, 1, 0.11f }, // [24] red: RPG smokeline }; VAR(particlesize, 20, 100, 500); VARP(blood, 0, 1, 1); VARP(bloodttl, 0, 10000, 30000); void render_particles(int time, int typemask) { bool rendered = false; for(int i = MAXPARTYPES-1; i>=0; i--) if(typemask&(1<<parttypes[i].type) && parlist[i]) { if(!rendered) { rendered = true; glDepthMask(GL_FALSE); glEnable(GL_BLEND); glDisable(GL_FOG); } parttype &pt = parttypes[i]; float sz = pt.sz*particlesize/100.0f; if(pt.tex>=0) glBindTexture(GL_TEXTURE_2D, parttex[pt.tex]->id); else glDisable(GL_TEXTURE_2D); switch(pt.type) { case PT_HUDFLASH: sethudgunperspective(true); // fall through case PT_FLASH: glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR); glColor3f(pt.r, pt.g, pt.b); glBegin(GL_QUADS); break; case PT_PART: glBlendFunc(GL_SRC_ALPHA, GL_ONE); glColor3f(pt.r, pt.g, pt.b); glBegin(GL_QUADS); break; case PT_FIREBALL: setupexplosion(); glBlendFunc(GL_SRC_ALPHA, GL_ONE); break; case PT_SHOTLINE: glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glColor4f(pt.r, pt.g, pt.b, 0.5f); glBegin(GL_LINES); break; case PT_DECAL: glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBegin(GL_QUADS); break; case PT_BULLETHOLE: glBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA); glBegin(GL_QUADS); break; case PT_BLOOD: glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR); glColor3f(1-pt.r, 1-pt.g, 1-pt.b); glBegin(GL_QUADS); break; case PT_STAIN: glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR); glBegin(GL_QUADS); break; } for(particle *p, **pp = &parlist[i]; (p = *pp);) { switch(pt.type) { case PT_HUDFLASH: case PT_FLASH: { vec corners[4] = { vec(-camright.x+camup.x, -camright.y+camup.y, -camright.z+camup.z), vec( camright.x+camup.x, camright.y+camup.y, camright.z+camup.z), vec( camright.x-camup.x, camright.y-camup.y, camright.z-camup.z), vec(-camright.x-camup.x, -camright.y-camup.y, -camright.z-camup.z) }; loopk(4) corners[k].rotate(p->d.x, p->d.y, camdir).mul(sz*p->d.z).add(p->o); glTexCoord2i(0, 1); glVertex3fv(corners[0].v); glTexCoord2i(1, 1); glVertex3fv(corners[1].v); glTexCoord2i(1, 0); glVertex3fv(corners[2].v); glTexCoord2i(0, 0); glVertex3fv(corners[3].v); xtraverts += 4; break; } case PT_PART: 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); 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); 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); 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); xtraverts += 4; break; case PT_FIREBALL: { sz = 1.0f + (pt.sz-1.0f)*min(p->fade, lastmillis-p->millis)/p->fade; glPushMatrix(); glTranslatef(p->o.x, p->o.y, p->o.z); bool inside = p->o.dist(camera1->o) <= sz*1.25f; //1.25 is max wobble scale vec oc(p->o); oc.sub(camera1->o); if(reflecting && !refracting) oc.z = p->o.z - (hdr.waterlevel-0.3f); glRotatef(inside ? camera1->yaw - 180 : atan2(oc.y, oc.x)/RAD - 90, 0, 0, 1); glRotatef((inside ? camera1->pitch : asin(oc.z/oc.magnitude())/RAD) - 90, 1, 0, 0); glRotatef(lastmillis/7.0f, 0, 0, 1); glScalef(-sz, sz, -sz); drawexplosion(inside, pt.r, pt.g, pt.b, 1.0f-sz/pt.sz); glPopMatrix(); xtraverts += heminumverts; break; } case PT_SHOTLINE: glVertex3f(p->o.x, p->o.y, p->o.z); glVertex3f(p->d.x, p->d.y, p->d.z); xtraverts += 2; break; case PT_DECAL: { sqr *s = S((int)p->o.x, (int)p->o.y); glColor4f(s->r/127.5f, s->g/127.5f, s->b/127.5, max(0.0f, min((p->millis+p->fade - lastmillis)/1000.0f, 0.7f))); vec dx(0, 0, 0), dy(0, 0, 0); loopk(3) if(p->d[k]) { dx[(k+1)%3] = -1; dy[(k+2)%3] = p->d[k]; break; } int o = detrnd((size_t)p, 11); static const int tc[4][2] = { {0, 1}, {1, 1}, {1, 0}, {0, 0} }; glTexCoord2i(tc[o%4][0], tc[o%4][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); glTexCoord2i(tc[(o+1)%4][0], tc[(o+1)%4][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); glTexCoord2i(tc[(o+2)%4][0], tc[(o+2)%4][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); glTexCoord2i(tc[(o+3)%4][0], tc[(o+3)%4][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); xtraverts += 4; break; } case PT_BULLETHOLE: { float blend = max(0.0f, min((p->millis+p->fade - lastmillis)/1000.0f, 1.0f)); glColor4f(pt.r*blend, pt.g*blend, pt.b*blend, blend); vec dx(0, 0, 0), dy(0, 0, 0); int tx = 0, ty = 1; loopk(3) if(p->d[k]) { dx[(k+1)%3] = -1; dy[(k+2)%3] = p->d[k]; if(k<2) { tx = k^1; ty = 2; } break; } glTexCoord2f(0.5f+0.5f*(-dx[tx]+dy[tx]), 0.5f+0.5f*(-dx[ty]+dy[ty])); 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); glTexCoord2f(0.5f+0.5f*( dx[tx]+dy[tx]), 0.5f+0.5f*( dx[ty]+dy[ty])); 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); glTexCoord2f(0.5f+0.5f*( dx[tx]-dy[tx]), 0.5f+0.5f*( dx[ty]-dy[ty])); 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); glTexCoord2f(0.5f+0.5f*(-dx[tx]-dy[tx]), 0.5f+0.5f*(-dx[ty]-dy[ty])); 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); xtraverts += 4; break; } case PT_BLOOD: { int n = detrnd((size_t)p, 4), o = detrnd((size_t)p, 11);; float tx = 0.5f*(n&1), ty = 0.5f*((n>>1)&1), tsz = 0.5f; static const int tc[4][2] = { {0, 1}, {1, 1}, {1, 0}, {0, 0} }; glTexCoord2f(tx+tsz*tc[o%4][0], ty+tsz*tc[o%4][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); glTexCoord2f(tx+tsz*tc[(o+1)%4][0], ty+tsz*tc[(o+1)%4][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); glTexCoord2f(tx+tsz*tc[(o+2)%4][0], ty+tsz*tc[(o+2)%4][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); glTexCoord2f(tx+tsz*tc[(o+3)%4][0], ty+tsz*tc[(o+3)%4][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); xtraverts += 4; break; } case PT_STAIN: { float blend = max(0.0f, min((p->millis+p->fade - lastmillis)/1000.0f, 1.0f)); glColor3f(blend*(1-pt.r), blend*(1-pt.g), blend*(1-pt.b)); int n = detrnd((size_t)p, 4), o = detrnd((size_t)p, 11); float tx = 0.5f*(n&1), ty = 0.5f*((n>>1)&1), tsz = 0.5f; static const int tc[4][2] = { {0, 1}, {1, 1}, {1, 0}, {0, 0} }; vec dx(0, 0, 0), dy(0, 0, 0); loopk(3) if(p->d[k]) { dx[(k+1)%3] = -1; dy[(k+2)%3] = p->d[k]; break; } glTexCoord2f(tx+tsz*tc[o%4][0], ty+tsz*tc[o%4][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); glTexCoord2f(tx+tsz*tc[(o+1)%4][0], ty+tsz*tc[(o+1)%4][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); glTexCoord2f(tx+tsz*tc[(o+2)%4][0], ty+tsz*tc[(o+2)%4][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); glTexCoord2f(tx+tsz*tc[(o+3)%4][0], ty+tsz*tc[(o+3)%4][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); xtraverts += 4; break; } } if(time < 0) pp = &p->next; else if(!p->fade || lastmillis-p->millis>p->fade) { *pp = p->next; p->next = parempty; parempty = p; } else { if(pt.gr) p->o.z -= ((lastmillis-p->millis)/3.0f)*time/(pt.gr*10000); if(pt.type==PT_PART || pt.type==PT_BLOOD) { p->o.add(vec(p->d).mul(time/20000.0f)); if(OUTBORD((int)p->o.x, (int)p->o.y)) { *pp = p->next; p->next = parempty; parempty = p; continue; } } if(pt.type==PT_BLOOD) { sqr *s = S((int)p->o.x, (int)p->o.y); if(s->type==SPACE && p->o.z<=s->floor) { *pp = p->next; p->next = parempty; parempty = p; newparticle(vec(p->o.x, p->o.y, s->floor+0.005f), vec(0, 0, 1), bloodttl, PART_BLOODSTAIN); continue; } } pp = &p->next; } } switch(pt.type) { case PT_HUDFLASH: glEnd(); sethudgunperspective(false); break; case PT_PART: case PT_SHOTLINE: case PT_DECAL: case PT_BULLETHOLE: case PT_BLOOD: case PT_STAIN: case PT_FLASH: glEnd(); break; case PT_FIREBALL: cleanupexplosion(); break; } if(pt.tex<0) glEnable(GL_TEXTURE_2D); } if(rendered) { glEnable(GL_FOG); glDisable(GL_BLEND); glDepthMask(GL_TRUE); } } void particle_emit(int type, int *args, int basetime, int seed, const vec &p) { if(type<0 || type>=MAXPARTYPES) return; parttype &pt = parttypes[type]; if(pt.type==PT_FIREBALL) particle_fireball(type, p); else if(pt.type==PT_FLASH || pt.type==PT_HUDFLASH) { if(lastmillis - basetime < args[0]) particle_flash(type, args[1]>0 ? args[1]/100.0f : 1.0f, seed%360, p); } else particle_splash(type, args[0], args[1], p); } void particle_flash(int type, float scale, float angle, const vec &p) { angle *= RAD; newparticle(p, vec(cosf(angle), sinf(angle), scale), 0, type); } void particle_splash(int type, int num, int fade, const vec &p) { if(parttypes[type].type==PT_BLOOD && (!blood || render_void)) return; loopi(num) { const int radius = 150; int x, y, z; do { x = rnd(radius*2)-radius; y = rnd(radius*2)-radius; z = rnd(radius*2)-radius; } while(x*x+y*y+z*z>radius*radius); vec d((float)x, (float)y, (float)z); newparticle(p, d, rnd(fade*3), type); } } VARP(maxtrail, 1, 500, 10000); void particle_trail(int type, int fade, const vec &s, const vec &e) { vec v; float d = e.dist(s, v); int steps = clamp(int(d*2), 1, maxtrail); v.div(steps); vec p = s; loopi(steps) { p.add(v); vec tmp((float)(rnd(11)-5), (float)(rnd(11)-5), (float)(rnd(11)-5)); newparticle(p, tmp, rnd(fade)+fade, type); } } vector<radar_explosion> radar_explosions; void particle_fireball(int type, const vec &o, playerent *owner) { newparticle(o, vec(0, 0, 0), (int)((parttypes[type].sz-1.0f)*100.0f), type); if (owner) { if (radar_explosions.length() >= 128) radar_explosions.setsize(64); radar_explosion &nx = radar_explosions.add(); nx.o = o; nx.millis = lastmillis; // col[3] is reserved for a dynamic alpha value static GLubyte col_ownexp[4] = { 0xF7, 0xF5, 0x34 }; // yellow for your own explosions static GLubyte col_friendlyexp[4] = { 0x02, 0x13, 0xFB }; // blue for friendlies' explosions static GLubyte col_enemyexp[4] = { 0xFB, 0x02, 0x02 }; // red for enemies' explosions if (focus == owner) nx.col = col_ownexp; else if (isteam(focus, owner)) nx.col = col_friendlyexp; else nx.col = col_enemyexp; } } VARP(bulletbouncesound, 0, 1, 1); VARP(bullethole, 0, 1, 1); VARP(bulletholettl, 0, 10000, 30000); VARP(bulletbouncesoundrad, 0, 15, 1000); // 2011jun18: shotty decals //bool addbullethole(dynent *d, const vec &from, const vec &to, float radius, bool noisy) bool addbullethole(dynent *d, const vec &from, const vec &to, float radius, bool noisy, int type) { if(!bulletholettl || !bullethole) return false; vec surface, ray(to); ray.sub(from); ray.normalize(); float dist = rayclip(from, ray, surface), mag = to.dist(from); if(surface.iszero() || (radius>0 && (dist < mag-radius || dist > mag+radius))) return false; vec o(from); o.add(ray.mul(dist)); o.add(vec(surface).mul(0.01f)); // 2011jun18: shotty decals int tf = type > 0 ? ( type > 1 ? PART_BULLETHOLE_SHOTGUNC : PART_BULLETHOLE_SHOTGUNM ) : PART_BULLETHOLE; newparticle(o, surface, bulletholettl, tf); //newparticle(o, surface, bulletholettl, PART_BULLETHOLE); if(noisy && bulletbouncesound && bulletbouncesoundrad && d!=player1 && o.dist(camera1->o) <= bulletbouncesoundrad) { audiomgr.playsound(o.z<hdr.waterlevel ? S_BULLETWATERHIT : S_BULLETHIT, &o, SP_LOW); } return true; } VARP(scorch, 0, 1, 1); VARP(scorchttl, 0, 10000, 30000); bool addscorchmark(const vec &o, float radius) { if(!scorchttl || !scorch || OUTBORD(o.x, o.y)) return false; sqr *s = S((int)o.x, (int)o.y); if(!s || s->type!=SPACE || o.z-s->floor>radius) return false; newparticle(vec(o.x, o.y, s->floor+0.02f), vec(0, 0, 1), scorchttl, PART_SCORCH); return true; } VARP(shotline, 0, 2, 2); VARP(shotlinettl, 0, 75, 10000); VARP(bulletairsound, 0, 1, 1); VARP(bulletairsoundrad, 0, 15, 1000); VARP(bulletairsoundsourcerad, 0, 8, 1000); VARP(bulletairsounddestrad, 0, 8, 1000); vector<radar_shotline> radar_shotlines; void addshotline(playerent *pl, vec from, const vec &to, int flags) { // radar shotlines if (radar_shotlines.length() >= 256) radar_shotlines.setsize(128); radar_shotline &s = radar_shotlines.add(); s.from = from; s.to = to; s.expire = lastmillis + max(75, shotlinettl) * 2; static const GLubyte col_ownshot[3] = { 0x94, 0xB0, 0xDE }; // blue for your shots static const GLubyte col_friendlyshot[3] = { 0xB8, 0xDC, 0x78 }; // light green-yellow for friendlies static const GLubyte col_enemyshot[3] = { 0xFF, 0xFF, 0xFF }; // white for enemies if (focus == pl) s.col = col_ownshot; else if (isteam(focus, pl)) s.col = col_friendlyshot; else s.col = col_enemyshot; if(!shotlinettl || !shotline || (pl == player1 && (shotline == 1 || m_classic(gamemode, mutators))) || m_real(gamemode, mutators)) return; vec unitv; if (flags & 1) // first shot { if (pl->muzzle.x >= 0) // just for fx from = pl->muzzle; else from.z -= WEAPONBELOWEYE; } float dist = to.dist(from, unitv); unitv.div(dist); // shotline visuals newparticle(from, to, shotlinettl, PART_SHOTLINE); // shotline sound fx if (!bulletairsoundrad || (flags & 2)) return; // silenced vec fromuv, touv; float fd = camera1->o.dist(from, fromuv); float td = camera1->o.dist(to, touv); if(fd <= (float)bulletairsoundsourcerad || td <= (float)bulletairsounddestrad) return; // ignore nearly fired/detonated shots vec soundpos(unitv); soundpos.mul(fd/(fd+td)*dist); soundpos.add(from); if(!bulletairsound || soundpos.dist(camera1->o) > bulletairsoundrad) return; // outside player radius audiomgr.playsound(S_BULLETAIR1 + rnd(2), &soundpos, SP_LOW); } void addheadshot(const vec &from, const vec &to, int damage) { if(!blood || !bloodttl || render_void || to.dist(from) < 1) return; // make bloody stains! multiple times... int num = clamp(damage/15, 1, 7); loopi(num) { vec o(to), surface; // raycube because blood shouldn't go to clips float dist = raycube(to, o.sub(from).normalize().add(vec( // spread x (rnd(61)-30)/1000.f, // spread y (rnd(61)-30)/1000.f, // spread z (rnd(61)-30)/1000.f )).normalize(), surface); if(surface.iszero()) continue; // no bloody skies! newparticle(o.mul(dist).add(vec(surface).mul(0.005f)).add(to), surface, bloodttl*2, PART_BLOODSTAIN); } } </source> [[Category:Source_code]]
Summary:
Please note that all contributions to the AssaultCube Reloaded Wiki are considered to be released under the CC-BY-SA
Cancel
Editing help
(opens in new window)
Follow on IG
TikTok
Join Fan Lab