diff --git a/source/src/clientgame.cpp b/source/src/clientgame.cpp index 0e4dfce5..0ab6f04e 100644 --- a/source/src/clientgame.cpp +++ b/source/src/clientgame.cpp @@ -586,7 +586,7 @@ void startmap(char *name) // called just after a map load projreset(); resetspawns(); if(m_ctf) preparectf(); - shotlinereset(); + particlereset(); spawncycle = -1; spawnplayer(player1); player1->frags = 0; diff --git a/source/src/main.cpp b/source/src/main.cpp index 96b8ae8d..cbfdf3d6 100644 --- a/source/src/main.cpp +++ b/source/src/main.cpp @@ -5,7 +5,6 @@ void cleanup(char *msg) // single program exit point; { stop(); - extern void abortconnect(); abortconnect(); disconnect(1); cleangl(); @@ -285,11 +284,11 @@ int main(int argc, char **argv) log("gl"); gl_init(scr_w, scr_h, bpp, depth, fsaa); - log("basetex"); crosshair = textureload("packages/misc/crosshairs/default.png"); if(!crosshair) fatal("could not find core textures (hint: run cube from the parent of the bin directory)"); loadingscreen(); + particleinit(); log("models"); preload_playermodels(); diff --git a/source/src/protos.h b/source/src/protos.h index a52ef919..5fd81c16 100644 --- a/source/src/protos.h +++ b/source/src/protos.h @@ -73,6 +73,7 @@ extern void setarraypointers(); // client extern void localservertoclient(int chan, uchar *buf, int len); extern void connects(char *servername, char *password = NULL); +extern void abortconnect(); extern void disconnect(int onlyclean = 0, int async = 0); extern void toserver(char *text); extern void addmsg(int type, const char *fmt = NULL, ...); @@ -200,17 +201,18 @@ extern void gl_drawhud(int w, int h, int curfps, int nquads, int curvert, bool u extern void readdepth(int w, int h, vec &pos = worldpos); extern void blendbox(int x1, int y1, int x2, int y2, bool border, int tex = -1); extern void damageblend(int n); -extern void addshotline(dynent *d, vec &from, vec &to); -extern void rendershotlines(); -extern void shotlinereset(); extern void renderbounceents(); extern bool scoped; extern void addgib(playerent *d); extern void loadingscreen(); // renderparticles +extern void particleinit(); +extern void particlereset(); extern void particle_splash(int type, int num, int fade, vec &p); extern void particle_trail(int type, int fade, vec &from, vec &to); +extern void particle_fireball(int type, vec &o); +extern void addshotline(dynent *d, vec &from, vec &to); extern void render_particles(int time); // worldio diff --git a/source/src/renderextras.cpp b/source/src/renderextras.cpp index c7e04ebb..6d5c5a1b 100644 --- a/source/src/renderextras.cpp +++ b/source/src/renderextras.cpp @@ -118,78 +118,6 @@ void blendbox(int x1, int y1, int x2, int y2, bool border, int tex) glDepthMask(GL_TRUE); } -const int MAXSPHERES = 50; -struct sphere { vec o; float size, max; int type; sphere *next; }; -sphere spheres[MAXSPHERES], *slist = NULL, *sempty = NULL; -bool sinit = false; - -void newsphere(vec &o, float max, int type) -{ - if(!sinit) - { - loopi(MAXSPHERES) - { - spheres[i].next = sempty; - sempty = &spheres[i]; - } - sinit = true; - } - if(sempty) - { - sphere *p = sempty; - sempty = p->next; - p->o = o; - p->max = max; - p->size = 1; - p->type = type; - p->next = slist; - slist = p; - } -} - -void renderspheres(int time) -{ - if(!slist) return; - - static Texture *exptex = NULL; - if(!exptex) exptex = textureload("packages/misc/explosion.jpg"); - - glDepthMask(GL_FALSE); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE); - glBindTexture(GL_TEXTURE_2D, exptex->id); - - for(sphere *p, **pp = &slist; (p = *pp);) - { - glPushMatrix(); - float size = p->size/p->max; - glColor4f(1.0f, 1.0f, 1.0f, 1.0f-size); - glTranslatef(p->o.x, p->o.z, p->o.y); - glRotatef(lastmillis/5.0f, 1, 1, 1); - glScalef(p->size, p->size, p->size); - glCallList(1); - glScalef(0.8f, 0.8f, 0.8f); - glCallList(1); - glPopMatrix(); - xtraverts += 12*6*2; - - if(p->size>p->max) - { - *pp = p->next; - p->next = sempty; - sempty = p; - } - else - { - p->size += time/100.0f; - pp = &p->next; - } - } - - glDisable(GL_BLEND); - glDepthMask(GL_TRUE); -} - string closeent; char *entnames[] = { @@ -505,83 +433,6 @@ void gl_drawhud(int w, int h, int curfps, int nquads, int curvert, bool underwat glEnable(GL_DEPTH_TEST); } -#define MAXSHOTLINES 100 -struct shotline -{ - vec from, to; - bool inuse; - int millis; -}; -shotline shotlines[MAXSHOTLINES]; - -void shotlinereset() { loopi(MAXSHOTLINES) shotlines[i].inuse = false; } - -void addshotline(dynent *d, vec &from, vec &to) -{ - if(d == player1) return; - if(rnd(3) != 0) return; - loopi(MAXSHOTLINES) - { - shotline *s = &shotlines[i]; - if(s->inuse) continue; - int start = 10; - if(camera1->o.dist(to) <= 10.0f) start = 8; - else start = 5; - - vec unitv; - float dist = to.dist(from, unitv); - unitv.div(dist); - s->inuse = true; - s->from = unitv; - s->from.mul(dist/10*start).add(from); - s->to = unitv; - s->to.mul(dist/10*-(10-start-2)).add(to); - s->millis = lastmillis; - return; - } -} - -void rendershotlines() -{ - int lines = 0; - loopi(MAXSHOTLINES) - { - shotline *s = &shotlines[i]; - if(!s->inuse) continue; - const int shotline_duration = 75; - if(lastmillis-s->millis > shotline_duration) { s->inuse = false; continue; } - - if(!lines) - { - glPushMatrix(); - glDisable(GL_TEXTURE_2D); - - glDepthMask(GL_FALSE); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_SRC_ALPHA); - glDisable(GL_FOG); - - glColor4f(1.0f, 1.0f, 0.7f, 0.5f); - glBegin(GL_LINES); - } - ++lines; - - glVertex3f(s->from.x, s->from.z, s->from.y); - glVertex3f(s->to.x, s->to.z, s->to.y); - } - if(lines) - { - glEnd(); - - glEnable(GL_FOG); - glDisable(GL_BLEND); - glDepthMask(GL_TRUE); - - glEnable(GL_TEXTURE_2D); - glPopMatrix(); - } -} - void renderbounceents() { loopv(bounceents) diff --git a/source/src/rendergl.cpp b/source/src/rendergl.cpp index ba914def..f6cb4736 100644 --- a/source/src/rendergl.cpp +++ b/source/src/rendergl.cpp @@ -49,16 +49,6 @@ void gl_init(int w, int h, int bpp, int depth, int fsaa) glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxtexsize); - GLUquadricObj *qsphere = gluNewQuadric(); - if(!qsphere) fatal("glu sphere"); - gluQuadricDrawStyle(qsphere, GLU_FILL); - gluQuadricOrientation(qsphere, GLU_INSIDE); - gluQuadricTexture(qsphere, GL_TRUE); - glNewList(1, GL_COMPILE); - gluSphere(qsphere, 1, 12, 6); - glEndList(); - gluDeleteQuadric(qsphere); - if(fsaa) glEnable(GL_MULTISAMPLE); camera1 = player1; @@ -351,6 +341,8 @@ bool outsidemap(physent *pl) || pl->o.z > s->ceil + (s->type==CHF ? s->vdelta/4 : 0); } +VAR(foo, 0, 0, 1); + void gl_drawframe(int w, int h, float changelod, float curfps) { recomputecamera(); @@ -423,15 +415,10 @@ void gl_drawframe(int w, int h, float changelod, float curfps) if(player1->state==CS_ALIVE) readdepth(w, h, hitpos); - renderspheres(curtime); renderents(); renderbounceents(); - rendershotlines(); - - glDisable(GL_CULL_FACE); - // Added by Rick: Need todo here because of drawing the waypoints glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); WaypointClass.Think(); @@ -441,14 +428,13 @@ void gl_drawframe(int w, int h, float changelod, float curfps) drawhudgun(w, h, aspect, farplane); overbright(1); - int nquads = renderwater(hf); - - overbright(2); + render_particles(curtime); - overbright(1); + + glDisable(GL_CULL_FACE); + int nquads = renderwater(hf); glDisable(GL_FOG); - glDisable(GL_TEXTURE_2D); extern vector verts; diff --git a/source/src/renderparticles.cpp b/source/src/renderparticles.cpp index 9edc1c81..19bdbe72 100644 --- a/source/src/renderparticles.cpp +++ b/source/src/renderparticles.cpp @@ -2,42 +2,89 @@ #include "cube.h" -const int MAXPARTICLES = 10500; -const int NUMPARTCUTOFF = 20; -struct particle { vec o, d; int fade, type; int millis; particle *next; int tex; }; // EDIT: AH -particle particles[MAXPARTICLES], *parlist = NULL, *parempty = NULL; -bool parinit = false; +#define MAXPARTYPES 7 -VAR(maxparticles, 100, 2000, MAXPARTICLES-500); +struct particle { vec o, d; int fade, type; int millis; particle *next; }; +particle *parlist[MAXPARTYPES], *parempty = NULL; -void newparticle(vec &o, vec &d, int fade, int type, int tex = -1) +static Texture *parttex[3]; + +void particleinit() { - if(!parinit) + 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.jpg"); + + GLUquadricObj *qsphere = gluNewQuadric(); + if(!qsphere) fatal("glu sphere"); + gluQuadricDrawStyle(qsphere, GLU_FILL); + gluQuadricOrientation(qsphere, GLU_INSIDE); + gluQuadricTexture(qsphere, GL_TRUE); + glNewList(1, GL_COMPILE); + gluSphere(qsphere, 1, 12, 6); + glEndList(); + gluDeleteQuadric(qsphere); +} + +void particlereset() +{ + loopi(MAXPARTYPES) { - loopi(MAXPARTICLES) + while(parlist[i]) { - particles[i].next = parempty; - parempty = &particles[i]; + particle *p = parlist[i]; + parlist[i] = p->next; + p->next = parempty; + parempty = p; } - parinit = true; - } - if(parempty) - { - particle *p = parempty; - parempty = p->next; - p->o = o; - p->d = d; - p->fade = fade; - p->type = type; - p->millis = lastmillis; - p->next = parlist; - p->tex = tex; - parlist = p; } } +void newparticle(const vec &o, const vec &d, int fade, int type) +{ + 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; +} + +enum +{ + PT_PART = 0, + PT_FIREBALL, + PT_SHOTLINE +}; + +static struct parttype { int type; float r, g, b; int gr, tex; float sz; } parttypes[] = +{ + { 0, 0.4f, 0.4f, 0.4f, 2, 0, 0.06f }, // yellow: sparks + { 0, 1.0f, 1.0f, 1.0f, 20, 1, 0.15f }, // grey: small smoke + { 0, 0.2f, 0.2f, 1.0f, 20, 0, 0.08f }, // blue: edit mode entities + { 0, 1.0f, 0.1f, 0.1f, 1, 1, 0.06f }, // red: blood spats + { 0, 1.0f, 0.1f, 0.1f, 0, 1, 0.2f }, // red: demotrack + { PT_FIREBALL, 1.0f, 1.0f, 1.0f, 0, 2, 7.0f }, // explosion fireball + { PT_SHOTLINE, 1.0f, 1.0f, 0.7f, 0, -1, 0.0f } // yellow: shotline +}; + VAR(demotracking, 0, 0, 1); -VAR(particlesize, 20, 100, 500); +VAR(particlesize, 20, 100, 500); void render_particles(int time) { @@ -47,83 +94,101 @@ void render_particles(int time) newparticle(player1->o, nom, 100000000, 4); } - if(!parlist) return; - - glDepthMask(GL_FALSE); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE); - glDisable(GL_FOG); - - static Texture *parttex[2] = {NULL, NULL}; - if(!parttex[0]) parttex[0] = textureload("packages/misc/base.png"); - if(!parttex[1]) parttex[1] = textureload("packages/misc/smoke.png"); - static struct parttype { float r, g, b; int gr, tex; float sz; } parttypes[] = + bool rendered = false; + loopi(MAXPARTYPES) if(parlist[i]) { - { 0.2f, 0.2f, 0.2f, 2, 0, 0.06f }, // yellow: sparks - { 0.5f, 0.5f, 0.5f, 20, 1, 0.15f }, // grey: small smoke - { 0.2f, 0.2f, 1.0f, 20, 0, 0.08f }, // blue: edit mode entities - { 1.0f, 0.1f, 0.1f, 1, 1, 0.06f }, // red: blood spats - { 1.0f, 0.1f, 0.1f, 0, 1, 0.2f }, // red: demotrack - -// { 1.0f, 0.8f, 0.8f, 20, 6, 1.2f }, // yellow: fireball1 -// { 0.5f, 0.5f, 0.5f, 20, 1, 0.6f }, // grey: big smoke -// { 1.0f, 1.0f, 1.0f, 20, 8, 1.2f }, // blue: fireball2 -// { 1.0f, 1.0f, 1.0f, 20, 9, 1.2f }, // green: fireball3 -// { 1.0f, 1.0f, 1.0f, 2, 3, 0.06f }, // - }; - - int numrender = 0; - - parttype *lastpt = NULL; - for(particle *p, **pp = &parlist; (p = *pp);) - { -// if(p->type==9 && p->tex!=-1) parttypes[9].tex = p->tex; // hack, AH - parttype &pt = parttypes[p->type]; - - if(&pt!=lastpt) + if(!rendered) { - if(!lastpt || pt.tex!=lastpt->tex) - { - if(lastpt) glEnd(); - glBindTexture(GL_TEXTURE_2D, parttex[pt.tex]->id); - glBegin(GL_QUADS); - } - if(!lastpt || pt.r!=lastpt->r || pt.g!=lastpt->g || pt.b!=lastpt->b) + 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_PART: + glBlendFunc(GL_SRC_ALPHA, GL_ONE); glColor3f(pt.r, pt.g, pt.b); - lastpt = &pt; - } - - float sz = pt.sz*particlesize/100.0f; - // perf varray? - glTexCoord2i(0, 1); glVertex3f(p->o.x+(-camright.x+camup.x)*sz, p->o.z+(-camright.y+camup.y)*sz, p->o.y+(-camright.z+camup.z)*sz); - glTexCoord2i(1, 1); glVertex3f(p->o.x+( camright.x+camup.x)*sz, p->o.z+( camright.y+camup.y)*sz, p->o.y+( camright.z+camup.z)*sz); - glTexCoord2i(1, 0); glVertex3f(p->o.x+( camright.x-camup.x)*sz, p->o.z+( camright.y-camup.y)*sz, p->o.y+( camright.z-camup.z)*sz); - glTexCoord2i(0, 0); glVertex3f(p->o.x+(-camright.x-camup.x)*sz, p->o.z+(-camright.y-camup.y)*sz, p->o.y+(-camright.z-camup.z)*sz); - xtraverts += 4; + glBegin(GL_QUADS); + break; - if(numrender++>maxparticles || (p->fade -= time)<0) - { - *pp = p->next; - p->next = parempty; - parempty = p; + case PT_FIREBALL: + 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; } - else - { - if(pt.gr) p->o.z -= ((lastmillis-p->millis)/3.0f)*curtime/(pt.gr*10000); - vec a = p->d; - a.mul(time/20000.0f); - p->o.add(a); - pp = &p->next; + + for(particle *p, **pp = &parlist[i]; (p = *pp);) + { + switch(pt.type) + { + case PT_PART: + glTexCoord2i(0, 1); glVertex3f(p->o.x+(-camright.x+camup.x)*sz, p->o.z+(-camright.y+camup.y)*sz, p->o.y+(-camright.z+camup.z)*sz); + glTexCoord2i(1, 1); glVertex3f(p->o.x+( camright.x+camup.x)*sz, p->o.z+( camright.y+camup.y)*sz, p->o.y+( camright.z+camup.z)*sz); + glTexCoord2i(1, 0); glVertex3f(p->o.x+( camright.x-camup.x)*sz, p->o.z+( camright.y-camup.y)*sz, p->o.y+( camright.z-camup.z)*sz); + glTexCoord2i(0, 0); glVertex3f(p->o.x+(-camright.x-camup.x)*sz, p->o.z+(-camright.y-camup.y)*sz, p->o.y+(-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; + glColor4f(pt.r, pt.g, pt.b, 1.0f-sz/pt.sz); + glPushMatrix(); + glTranslatef(p->o.x, p->o.z, p->o.y); + glRotatef(lastmillis/5.0f, 1, 1, 1); + glScalef(sz, sz, sz); + glCallList(1); + glScalef(0.8f, 0.8f, 0.8f); + glCallList(1); + glPopMatrix(); + xtraverts += 12*6*2; + break; + + case PT_SHOTLINE: + glVertex3f(p->o.x, p->o.z, p->o.y); + glVertex3f(p->d.x, p->d.z, p->d.y); + xtraverts += 2; + break; + } + + if(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_SHOTLINE) p->o.add(vec(p->d).mul(time/20000.0f)); + pp = &p->next; + } } + + if(pt.type==PT_PART || pt.type==PT_SHOTLINE) glEnd(); + if(pt.tex<0) glEnable(GL_TEXTURE_2D); } - if(lastpt) glEnd(); - - glEnable(GL_FOG); - glDisable(GL_BLEND); - glDepthMask(GL_TRUE); + if(rendered) + { + glEnable(GL_FOG); + glDisable(GL_BLEND); + glDepthMask(GL_TRUE); + } } + void particle_splash(int type, int num, int fade, vec &p) { loopi(num) @@ -155,3 +220,29 @@ void particle_trail(int type, int fade, vec &s, vec &e) newparticle(p, d, rnd(fade)+fade, type); } } + +void particle_fireball(int type, vec &o) +{ + newparticle(o, vec(0, 0, 0), (int)((parttypes[type].sz-1.0f)*100.0f), type); +} + +void addshotline(dynent *pl, vec &from, vec &to) +{ + if(pl == player1) return; + if(rnd(3)) return; + + int start = 10; + if(camera1->o.dist(to) <= 10.0f) start = 8; + else start = 5; + + vec unitv; + float dist = to.dist(from, unitv); + unitv.div(dist); + + vec o = unitv; + o.mul(dist/10+start).add(from); + vec d = unitv; + d.mul(dist/10*-(10-start-2)).add(to); + newparticle(o, d, 75, 6); +} + diff --git a/source/src/weapon.cpp b/source/src/weapon.cpp index 1188cf88..7b68bee3 100644 --- a/source/src/weapon.cpp +++ b/source/src/weapon.cpp @@ -253,8 +253,7 @@ void hit(int target, int damage, playerent *d, playerent *at, bool gib=false) demodamage(damage, d->o); } -const float RL_RADIUS = 7; -const float RL_DAMRAD = 10; // hack +const float RL_DAMRAD = 10; void radialeffect(playerent *o, vec &v, int cn, int qdam, playerent *at) { @@ -283,7 +282,7 @@ void splash(projectile *p, vec &v, vec &vold, int notthisplayer, int qdam) else { //playsound(S_RLHIT, &v); - newsphere(v, RL_RADIUS, 0); + particle_fireball(5, v); dodynlight(vold, v, 0, 0, p->owner); if(!p->local) return; radialeffect(player1, v, -1, qdam, p->owner);