From 25ebf597144c31bc7ef1a2e3a0f3618d724df6a8 Mon Sep 17 00:00:00 2001 From: Lee Salzman Date: Sun, 6 Apr 2008 14:54:14 +0000 Subject: [PATCH] particle emitter stuff git-svn-id: svn://svn.code.sf.net/p/actiongame/code/trunk/ac@1735 e016b1c5-ed68-44aa-a2f7-31cac88cffde --- packages/misc/muzzleflash.jpg | Bin 0 -> 2511 bytes packages/models/weapons/assault/md3.cfg | 1 + source/src/cube.h | 2 +- source/src/geom.h | 28 +++++++ source/src/md2.h | 2 +- source/src/md3.h | 12 ++- source/src/menus.cpp | 2 +- source/src/model.h | 5 +- source/src/protos.h | 5 ++ source/src/rendergl.cpp | 52 ++++++++---- source/src/rendermodel.cpp | 2 +- source/src/renderparticles.cpp | 57 ++++++++++++- source/src/vertmodel.h | 103 +++++++++++++++++------- source/src/weapon.cpp | 8 +- 14 files changed, 222 insertions(+), 57 deletions(-) create mode 100644 packages/misc/muzzleflash.jpg diff --git a/packages/misc/muzzleflash.jpg b/packages/misc/muzzleflash.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9742b4a3c92f9d95e5e32c003c1372e4d37f27a1 GIT binary patch literal 2511 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 literal 0 HcmV?d00001 diff --git a/packages/models/weapons/assault/md3.cfg b/packages/models/weapons/assault/md3.cfg index fd64e1c3..13275100 100644 --- a/packages/models/weapons/assault/md3.cfg +++ b/packages/models/weapons/assault/md3.cfg @@ -4,3 +4,4 @@ md3skin hands skin_hands.jpg md3anim "gun idle" 0 1 md3anim "gun shoot" 8 8 md3anim "gun reload" 0 1 +md3emit tag_muzzle 10 50 diff --git a/source/src/cube.h b/source/src/cube.h index 2c3a075c..6701f6df 100644 --- a/source/src/cube.h +++ b/source/src/cube.h @@ -31,7 +31,7 @@ extern vector players; // all the other clients (in multiplayer extern vector bounceents; extern bool editmode; extern vector ents; // map entities -extern vec worldpos, camup, camright; // current target of the crosshair in the world +extern vec worldpos, camup, camright, camdir; // current target of the crosshair in the world extern vec hitpos; extern int lastmillis, totalmillis; // last time extern int curtime; // current frame time diff --git a/source/src/geom.h b/source/src/geom.h index 36e5dbd6..df5e7545 100644 --- a/source/src/geom.h +++ b/source/src/geom.h @@ -38,6 +38,34 @@ struct vec float distxy(const vec &e) const { float dx = e.x - x, dy = e.y - y; return sqrtf(dx*dx + dy*dy); } bool reject(const vec &o, float max) const { return x>o.x+max || xo.y+max || y fabs(d.y) ? (fabs(d.x) > fabs(d.z) ? 0 : 2) : (fabs(d.y) > fabs(d.z) ? 1 : 2); + v[i] = d[(i+1)%3]; + v[(i+1)%3] = -d[i]; + v[(i+2)%3] = 0; + } }; struct ivec diff --git a/source/src/md2.h b/source/src/md2.h index 042342b9..f7e76cf5 100644 --- a/source/src/md2.h +++ b/source/src/md2.h @@ -195,7 +195,7 @@ struct md2 : vertmodel if(!cullface) glEnable(GL_CULL_FACE); else if(anim&ANIM_MIRROR) glCullFace(GL_FRONT); - if(a) for(int i = 0; a[i].name; i++) + if(a) for(int i = 0; a[i].type; i++) { vertmodel *m = (vertmodel *)a[i].m; if(!m) continue; diff --git a/source/src/md3.h b/source/src/md3.h index 90a0a676..5f0be957 100644 --- a/source/src/md3.h +++ b/source/src/md3.h @@ -154,7 +154,7 @@ struct md3 : vertmodel { if(!loaded) return; - if(a) for(int i = 0; a[i].name; i++) + if(a) for(int i = 0; a[i].type; i++) { vertmodel *m = (vertmodel *)a[i].m; if(!m) continue;; @@ -184,7 +184,7 @@ struct md3 : vertmodel if(!cullface) glEnable(GL_CULL_FACE); else if(anim&ANIM_MIRROR) glCullFace(GL_FRONT); - if(a) for(int i = 0; a[i].name; i++) + if(a) for(int i = 0; a[i].type; i++) { switch(a[i].type) { @@ -285,8 +285,16 @@ void md3link(char *parentno, char *childno, char *tagname) if(!loadingmd3->parts[parent]->link(loadingmd3->parts[child], tagname)) conoutf("could not link model %s", loadingmd3->loadname); } +void md3emit(char *tag, char *type, char *arg1, char *arg2) +{ + if(!loadingmd3 || loadingmd3->parts.empty()) { conoutf("not loading an md3"); return; }; + md3::part &mdl = *loadingmd3->parts.last(); + if(!mdl.addemitter(tag, ATOI(type), ATOI(arg1), ATOI(arg2))) { conoutf("could not find tag %s", tag); return; } +} + COMMAND(md3load, ARG_1STR); COMMAND(md3skin, ARG_3STR); COMMAND(md3anim, ARG_4STR); COMMAND(md3link, ARG_3STR); +COMMAND(md3emit, ARG_4STR); diff --git a/source/src/menus.cpp b/source/src/menus.cpp index a6813c51..a0c1fdec 100644 --- a/source/src/menus.cpp +++ b/source/src/menus.cpp @@ -636,7 +636,7 @@ void rendermenumdl() s_sprintfd(skin)("packages/models/%s.jpg", m.mdl); tex = -(int)textureload(skin)->id; } - modelattach a[2] = { { NULL }, { NULL } }; + modelattach a[2]; if(isplayermodel) { a[0].name = "weapons/subgun/world"; diff --git a/source/src/model.h b/source/src/model.h index 7b2e3781..8422f855 100644 --- a/source/src/model.h +++ b/source/src/model.h @@ -9,6 +9,7 @@ enum { ANIM_IDLE = 0, ANIM_RUN, ANIM_ATTACK, ANIM_PAIN, ANIM_JUMP, ANIM_LAND, AN #define ANIM_MIRROR (1<<13) #define ANIM_NOSKIN (1<<14) #define ANIM_TRANSLUCENT (1<<15) +#define ANIM_PARTICLE (1<<16) struct animstate // used for animation blending of animated characters { @@ -23,7 +24,7 @@ struct animstate // used for animation blending o enum { MDL_MD2 = 1, MDL_MD3 }; -enum { MDL_ATTACH_VWEP = 0 }; +enum { MDL_ATTACH_NONE = 0, MDL_ATTACH_VWEP }; struct model; struct modelattach @@ -32,6 +33,8 @@ struct modelattach int type, anim, basetime; float speed; model *m; + + modelattach() : name(NULL), type(MDL_ATTACH_NONE) {} }; struct dynent; diff --git a/source/src/protos.h b/source/src/protos.h index a6af0903..b28baf5b 100644 --- a/source/src/protos.h +++ b/source/src/protos.h @@ -175,6 +175,7 @@ extern void blendbox(int x1, int y1, int x2, int y2, bool border, int tex = -1, extern void quad(GLuint tex, float x, float y, float s, float tx, float ty, float tsx, float tsy = 0); extern void quad(GLuint tex, vec &c1, vec &c2, float tx, float ty, float tsx, float tsy); extern void circle(GLuint tex, float x, float y, float r, float tx, float ty, float tr, int subdiv = 32); +extern void sethudgunperspective(bool on); extern void gl_drawframe(int w, int h, float changelod, float curfps); extern void clearminimap(); extern void rendercursor(int x, int y, int w); @@ -331,6 +332,8 @@ extern void computeraytable(float vx, float vy); extern int isoccluded(float vx, float vy, float cx, float cy, float csize); // main +extern SDL_Surface *screen; + extern void keyrepeat(bool on); extern bool initwarning(); extern bool firstrun; @@ -390,8 +393,10 @@ extern void updatedmgindicator(vec &attack); // renderparticles extern void particleinit(); extern void particlereset(); +extern void particle_flash(int type, int fade, vec &p); 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_emit(int type, int *args, vec &p); extern void particle_fireball(int type, vec &o); extern void addshotline(dynent *d, vec &from, vec &to); extern bool addbullethole(vec &from, vec &to, float radius = 1, bool noisy = true); diff --git a/source/src/rendergl.cpp b/source/src/rendergl.cpp index 1600bf19..ddd08bae 100644 --- a/source/src/rendergl.cpp +++ b/source/src/rendergl.cpp @@ -290,6 +290,8 @@ void rendercursor(int x, int y, int w) VARP(fov, 90, 100, 120); VAR(fog, 64, 180, 1024); VAR(fogcolour, 0, 0x8099B3, 0xFFFFFF); +float fovy, aspect; +int farplane; physent *camera1 = NULL; @@ -609,25 +611,29 @@ int xtraverts; VARP(hudgun, 0, 1, 1); +void sethudgunperspective(bool on) +{ + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + if(on) + { + glScalef(1, 1, 0.5f); // fix hudugns colliding with map geometry + gluPerspective((float)100.0f*screen->h/screen->w, aspect, 0.3f, farplane); // fov fixed at 100° + } + else gluPerspective((float)fov*screen->h/screen->w, aspect, 0.15f, farplane); + glMatrixMode(GL_MODELVIEW); +} + void drawhudgun(int w, int h, float aspect, int farplane) { if(scoped && player1->weaponsel->type==GUN_SNIPER) return; - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - - glScalef(1, 1, 0.5f); // fix hudugns colliding with map geometry - - gluPerspective((float)100.0f*h/w, aspect, 0.3f, farplane); // fov fixed at 100° - glMatrixMode(GL_MODELVIEW); + sethudgunperspective(true); if(hudgun && player1->state==CS_ALIVE) player1->weaponsel->renderhudmodel(); rendermenumdl(); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - gluPerspective((float)fov*h/w, aspect, 0.15f, farplane); - glMatrixMode(GL_MODELVIEW); + sethudgunperspective(false); } bool outsidemap(physent *pl) @@ -641,8 +647,8 @@ bool outsidemap(physent *pl) float cursordepth = 0.9f; GLint viewport[4]; -GLdouble mm[16], pm[16]; -vec worldpos, camup, camright; +GLdouble mm[16], pm[16], invmm[16]; +vec worldpos, camdir, camup, camright; void readmatrices() { @@ -651,6 +657,20 @@ void readmatrices() glGetDoublev(GL_PROJECTION_MATRIX, pm); camright = vec(float(mm[0]), float(mm[4]), float(mm[8])); camup = vec(float(mm[1]), float(mm[5]), float(mm[9])); + camdir = vec(float(-mm[2]), float(-mm[6]), float(-mm[10])); + + loopi(3) + { + loopj(3) invmm[i*4 + j] = mm[i + j*4]; + invmm[i*4 + 3] = 0; + } + loopi(3) + { + double c = 0; + loopj(3) c -= mm[i*4 + j] * mm[12 + j]; + invmm[12 + i] = c; + } + invmm[15] = 1; } // stupid function to cater for stupid ATI linux drivers that return incorrect depth values @@ -683,8 +703,8 @@ void gl_drawframe(int w, int h, float changelod, float curfps) recomputecamera(); float hf = hdr.waterlevel-0.3f; - float fovy = (float)fov*h/w; - float aspect = w/(float)h; + fovy = (float)fov*h/w; + aspect = w/(float)h; bool underwater = camera1->o.zweaponsel==d->lastattackweapon && lastmillis-d->lastaction<300) { anim = d->crouching ? ANIM_CROUCH_ATTACK : ANIM_ATTACK; speed = 300.0f/8; basetime = d->lastaction; } else if(!d->move && !d->strafe) { anim = (d->crouching ? ANIM_CROUCH_IDLE : ANIM_IDLE)|ANIM_LOOP; } else { anim = (d->crouching ? ANIM_CROUCH_WALK : ANIM_RUN)|ANIM_LOOP; speed = 1860/d->maxspeed; } - modelattach a[2] = { { NULL }, { NULL } }; + modelattach a[2]; if(vwepname) { a[0].name = vwepname; diff --git a/source/src/renderparticles.cpp b/source/src/renderparticles.cpp index 8c7c79d5..49d841c4 100644 --- a/source/src/renderparticles.cpp +++ b/source/src/renderparticles.cpp @@ -185,12 +185,12 @@ void cleanupexplosion() } } -#define MAXPARTYPES 10 +#define MAXPARTYPES 11 struct particle { vec o, d; int fade, type; int millis; particle *next; }; particle *parlist[MAXPARTYPES], *parempty = NULL; -static Texture *parttex[6]; +static Texture *parttex[7]; void particleinit() { @@ -202,6 +202,7 @@ void particleinit() parttex[3] = textureload("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() @@ -256,7 +257,8 @@ enum PT_DECAL, PT_BULLETHOLE, PT_BLOOD, - PT_STAIN + PT_STAIN, + PT_FLASH }; static struct parttype { int type; float r, g, b; int gr, tex; float sz; } parttypes[] = @@ -271,6 +273,7 @@ static struct parttype { int type; float r, g, b; int gr, tex; float sz; } partt { 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_FLASH, 1.0f, 1.0f, 1.0f, 0, 6, 0.7f }, // muzzle flash }; VAR(particlesize, 20, 100, 500); @@ -280,6 +283,8 @@ VARP(bloodttl, 0, 10000, 30000); void render_particles(int time) { + extern float aspect; + extern int farplane, fov; bool rendered = false; for(int i = MAXPARTYPES-1; i>=0; i--) if(parlist[i]) { @@ -298,6 +303,13 @@ void render_particles(int time) else glDisable(GL_TEXTURE_2D); switch(pt.type) { + case PT_FLASH: + sethudgunperspective(true); + 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); @@ -341,6 +353,26 @@ void render_particles(int time) { switch(pt.type) { + 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).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); @@ -481,6 +513,11 @@ void render_particles(int time) switch(pt.type) { + case PT_FLASH: + glEnd(); + sethudgunperspective(false); + break; + case PT_PART: case PT_SHOTLINE: case PT_DECAL: @@ -505,6 +542,20 @@ void render_particles(int time) } } +void particle_emit(int type, int *args, 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) particle_flash(type, args[0], p); + else particle_splash(type, args[0], args[1], p); +} + +void particle_flash(int type, int fade, vec &p) +{ + float angle = rnd(360)*RAD; + newparticle(p, vec(cosf(angle), sinf(angle), 0), fade, type); +} void particle_splash(int type, int num, int fade, vec &p) { diff --git a/source/src/vertmodel.h b/source/src/vertmodel.h index 56c62bcd..2ddc1c04 100644 --- a/source/src/vertmodel.h +++ b/source/src/vertmodel.h @@ -188,6 +188,16 @@ struct vertmodel : model float speed; }; + struct particleemitter + { + int type, args[2]; + + particleemitter() : type(-1) + { + memset(args, 0, sizeof(args)); + } + }; + struct tag { char *name; @@ -208,10 +218,11 @@ struct vertmodel : model part **links; tag *tags; int numtags; + particleemitter *emitters; GLuint *shadows; float shadowrad; - part() : filename(NULL), anims(NULL), links(NULL), tags(NULL), numtags(0), shadows(NULL), shadowrad(0) {} + part() : filename(NULL), anims(NULL), links(NULL), tags(NULL), numtags(0), emitters(NULL), shadows(NULL), shadowrad(0) {} virtual ~part() { DELETEA(filename); @@ -219,6 +230,7 @@ struct vertmodel : model DELETEA(anims); DELETEA(links); DELETEA(tags); + DELETEA(emitters); if(shadows) glDeleteTextures(numframes, shadows); DELETEA(shadows); } @@ -243,6 +255,20 @@ struct vertmodel : model return false; } + bool addemitter(const char *tag, int type, int arg1 = 0, int arg2 = 0) + { + loopi(numtags) if(!strcmp(tags[i].name, tag)) + { + if(!emitters) emitters = new particleemitter[numtags]; + particleemitter &p = emitters[i]; + p.type = type; + p.args[0] = arg1; + p.args[1] = arg2; + return true; + } + return false; + } + void scaleverts(const float scale, const vec &translate) { loopv(meshes) @@ -274,6 +300,34 @@ struct vertmodel : model as.range = 1; } + void gentagmatrix(anpos &cur, anpos *prev, float ai_t, int i, GLfloat *matrix) + { + tag *tag1 = &tags[cur.fr1*numtags+i]; + tag *tag2 = &tags[cur.fr2*numtags+i]; + #define ip(p1, p2, t) (p1+t*(p2-p1)) + #define ip_ai_tag(c) ip( ip( tag1p->c, tag2p->c, prev->t), ip( tag1->c, tag2->c, cur.t), ai_t) + if(prev) + { + tag *tag1p = &tags[prev->fr1 * numtags + i]; + tag *tag2p = &tags[prev->fr2 * numtags + i]; + loopj(3) matrix[j] = ip_ai_tag(transform[0][j]); // transform + loopj(3) matrix[4 + j] = ip_ai_tag(transform[1][j]); + loopj(3) matrix[8 + j] = ip_ai_tag(transform[2][j]); + loopj(3) matrix[12 + j] = ip_ai_tag(pos[j]); // position + } + else + { + loopj(3) matrix[j] = ip(tag1->transform[0][j], tag2->transform[0][j], cur.t); // transform + loopj(3) matrix[4 + j] = ip(tag1->transform[1][j], tag2->transform[1][j], cur.t); + loopj(3) matrix[8 + j] = ip(tag1->transform[2][j], tag2->transform[2][j], cur.t); + loopj(3) matrix[12 + j] = ip(tag1->pos[j], tag2->pos[j], cur.t); // position + } + #undef ip_ai_tag + #undef ip + matrix[3] = matrix[7] = matrix[11] = 0.0f; + matrix[15] = 1.0f; + } + bool calcanimstate(int anim, int varseed, float speed, int basetime, dynent *d, animstate &as) { as.anim = anim; @@ -348,39 +402,32 @@ struct vertmodel : model loopv(meshes) meshes[i]->render(as, cur, doai ? &prev : NULL, ai_t); - loopi(numtags) if(links[i]) // render the linked models - interpolate rotation and position of the 'link-tags' + loopi(numtags) if(links[i] || (anim&ANIM_PARTICLE && emitters && emitters[i].type>=0)) // render the linked models - interpolate rotation and position of the 'link-tags' { - part *link = links[i]; - GLfloat matrix[16]; - tag *tag1 = &tags[cur.fr1*numtags+i]; - tag *tag2 = &tags[cur.fr2*numtags+i]; - #define ip(p1, p2, t) (p1+t*(p2-p1)) - #define ip_ai_tag(c) ip( ip( tag1p->c, tag2p->c, prev.t), ip( tag1->c, tag2->c, cur.t), ai_t) - if(doai) + gentagmatrix(cur, doai ? &prev : NULL, ai_t, i, matrix); + + part *link = links[i]; + if(link) { - tag *tag1p = &tags[prev.fr1 * numtags + i]; - tag *tag2p = &tags[prev.fr2 * numtags + i]; - loopj(3) matrix[j] = ip_ai_tag(transform[0][j]); // transform - loopj(3) matrix[4 + j] = ip_ai_tag(transform[1][j]); - loopj(3) matrix[8 + j] = ip_ai_tag(transform[2][j]); - loopj(3) matrix[12 + j] = ip_ai_tag(pos[j]); // position + glPushMatrix(); + glMultMatrixf(matrix); + link->render(anim, varseed, speed, basetime, d); + glPopMatrix(); } - else + + if(anim&ANIM_PARTICLE && emitters && emitters[i].type>=0) { - loopj(3) matrix[j] = ip(tag1->transform[0][j], tag2->transform[0][j], cur.t); // transform - loopj(3) matrix[4 + j] = ip(tag1->transform[1][j], tag2->transform[1][j], cur.t); - loopj(3) matrix[8 + j] = ip(tag1->transform[2][j], tag2->transform[2][j], cur.t); - loopj(3) matrix[12 + j] = ip(tag1->pos[j], tag2->pos[j], cur.t); // position + vec tagpos(matrix[12], matrix[13], matrix[14]); + GLdouble mm[16]; + glGetDoublev(GL_MODELVIEW_MATRIX, mm); + vec eyepos; + loopk(3) eyepos[k] = tagpos.x*mm[0+k] + tagpos.y*mm[4+k] + tagpos.z*mm[8+k] + mm[12+k]; + extern GLdouble invmm[16]; + vec worldpos; + loopk(3) worldpos[k] = eyepos.x*invmm[0+k] + eyepos.y*invmm[4+k] + eyepos.z*invmm[8+k] + invmm[12+k]; + particle_emit(emitters[i].type, emitters[i].args, worldpos); } - #undef ip_ai_tag - #undef ip - matrix[3] = matrix[7] = matrix[11] = 0.0f; - matrix[15] = 1.0f; - glPushMatrix(); - glMultMatrixf(matrix); - link->render(anim, varseed, speed, basetime, d); - glPopMatrix(); } } diff --git a/source/src/weapon.cpp b/source/src/weapon.cpp index bb238bd9..6325d65e 100644 --- a/source/src/weapon.cpp +++ b/source/src/weapon.cpp @@ -628,12 +628,14 @@ void weapon::renderhudmodel(int lastaction, int index) if(!intermission) wm.calcmove(unitv, lastaction); s_sprintfd(path)("weapons/%s", info.modelname); static int lastanim[2], lastswitch[2]; - if(lastanim[index]!=(wm.anim|(type<<16))) + bool emit = false; + if(lastanim[index]!=(wm.anim|(type<<24))) { - lastanim[index] = wm.anim|(type<<16); + if((lastanim[index]&ANIM_INDEX)!=ANIM_GUN_SHOOT && (wm.anim&ANIM_INDEX)==ANIM_GUN_SHOOT) emit = true; + lastanim[index] = wm.anim|(type<<24); lastswitch[index] = lastmillis; } - rendermodel(path, wm.anim|(index ? ANIM_MIRROR : 0), 0, 0, wm.pos, player1->yaw+90, player1->pitch+wm.k_rot, 40.0f, lastswitch[index], NULL, NULL, 1.28f); + rendermodel(path, wm.anim|(index ? ANIM_MIRROR : 0)|(emit ? ANIM_PARTICLE : 0), 0, 0, wm.pos, player1->yaw+90, player1->pitch+wm.k_rot, 40.0f, lastswitch[index], NULL, NULL, 1.28f); } void weapon::updatetimers()