diff --git a/source/src/entities.cpp b/source/src/entities.cpp index 95cf13b7..f0e755d7 100644 --- a/source/src/entities.cpp +++ b/source/src/entities.cpp @@ -20,7 +20,7 @@ char *entmdlnames[] = void renderent(entity &e, char *mdlname, float z, float yaw, int anim = ANIM_MAPMODEL|ANIM_LOOP, int basetime = 0, float speed = 0) { - rendermodel(mdlname, anim, 0, 1.1f, e.x, e.y, z+S(e.x, e.y)->floor, yaw, 0, speed, basetime); + rendermodel(mdlname, anim, 0, 1.1f, vec(e.x, e.y, z+S(e.x, e.y)->floor), yaw, 0, speed, basetime); } void renderentities() @@ -39,7 +39,7 @@ void renderentities() { mapmodelinfo &mmi = getmminfo(e.attr2); if(!&mmi) continue; - rendermodel(mmi.name, ANIM_MAPMODEL|ANIM_LOOP, e.attr4, mmi.rad ? (float)mmi.rad : 1.1f, e.x, e.y, (float)S(e.x, e.y)->floor+mmi.zoff+e.attr3, (float)((e.attr1+7)-(e.attr1+7)%15), 0, 10.0f); + rendermodel(mmi.name, ANIM_MAPMODEL|ANIM_LOOP, e.attr4, mmi.rad ? (float)mmi.rad : 1.1f, vec(e.x, e.y, (float)S(e.x, e.y)->floor+mmi.zoff+e.attr3), (float)((e.attr1+7)-(e.attr1+7)%15), 0, 10.0f); } else if(m_ctf && e.type==CTF_FLAG) { @@ -48,12 +48,12 @@ void renderentities() { if(!f.actor || f.actor == player1) continue; s_sprintfd(path)("pickups/flags/small_%s", team_string(e.attr2)); - rendermodel(path, ANIM_FLAG|ANIM_START, 0, 1.1f, f.actor->o.x, f.actor->o.y, f.actor->o.z+0.3f+(sinf(lastmillis/100.0f)+1)/10, lastmillis/2.5f, 0, 120.0f); + rendermodel(path, ANIM_FLAG|ANIM_START, 0, 1.1f, vec(f.actor->o).add(vec(0, 0, 0.3f+(sinf(lastmillis/100.0f)+1)/10)), lastmillis/2.5f, 0, 120.0f); } else { s_sprintfd(path)("pickups/flags/%s", team_string(e.attr2)); - rendermodel(path, ANIM_FLAG|ANIM_LOOP, 0, 4, e.x, e.y, f.state==CTFF_INBASE ? (float)S(e.x, e.y)->floor : e.z, (float)((e.attr1+7)-(e.attr1+7)%15), 0, 120.0f); + rendermodel(path, ANIM_FLAG|ANIM_LOOP, 0, 4, vec(e.x, e.y, f.state==CTFF_INBASE ? (float)S(e.x, e.y)->floor : e.z), (float)((e.attr1+7)-(e.attr1+7)%15), 0, 120.0f); } } else if(isitem(e.type)) diff --git a/source/src/hudgun.cpp b/source/src/hudgun.cpp index 3d7a5ef8..f8d07fe9 100644 --- a/source/src/hudgun.cpp +++ b/source/src/hudgun.cpp @@ -125,7 +125,7 @@ void renderhudgun(int gun, int lastaction, int index = 0) lastanim[index] = wm.anim|(gun<<16); lastswitch[index] = lastmillis; } - rendermodel(path, wm.anim|(index ? ANIM_MIRROR : 0), 0, 0, wm.pos.x, wm.pos.y, wm.pos.z, player1->yaw+90, player1->pitch+wm.k_rot, 40.0f, lastswitch[index], NULL, NULL, 1.28f); + 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); } void renderhudgun() diff --git a/source/src/md2.h b/source/src/md2.h index 6230e5d1..73d114f6 100644 --- a/source/src/md2.h +++ b/source/src/md2.h @@ -177,23 +177,29 @@ struct md2 : vertmodel } }; - void render(int anim, int varseed, float speed, int basetime, float x, float y, float z, float yaw, float pitch, dynent *d, model *vwepmdl, float scale) + void render(int anim, int varseed, float speed, int basetime, const vec &o, float yaw, float pitch, dynent *d, model *vwepmdl, float scale) { if(!loaded) return; + if(!cullface) glDisable(GL_CULL_FACE); + else if(anim&ANIM_MIRROR) glCullFace(GL_BACK); + glPushMatrix(); - glTranslatef(x, y, z); + glTranslatef(o.x, o.y, o.z); glRotatef(yaw+180, 0, 0, 1); glRotatef(pitch, 0, -1, 0); if(anim&ANIM_MIRROR || scale!=1) glScalef(anim&ANIM_MIRROR ? -scale : scale, scale, scale); parts[0]->render(anim, varseed, speed, basetime, d); glPopMatrix(); + if(!cullface) glEnable(GL_CULL_FACE); + else if(anim&ANIM_MIRROR) glCullFace(GL_FRONT); + if(vwepmdl) { ((md2 *)vwepmdl)->parts[0]->index = parts.length(); vwepmdl->setskin(); - vwepmdl->render(anim, varseed, speed, basetime, x, y, z, yaw, pitch, d, NULL, scale); + vwepmdl->render(anim, varseed, speed, basetime, o, yaw, pitch, d, NULL, scale); } } diff --git a/source/src/md3.h b/source/src/md3.h index 88490e2c..36c309d2 100644 --- a/source/src/md3.h +++ b/source/src/md3.h @@ -150,7 +150,7 @@ struct md3 : vertmodel } }; - void render(int anim, int varseed, float speed, int basetime, float x, float y, float z, float yaw, float pitch, dynent *d, model *vwepmdl, float scale) + void render(int anim, int varseed, float speed, int basetime, const vec &o, float yaw, float pitch, dynent *d, model *vwepmdl, float scale) { if(!loaded) return; @@ -160,15 +160,22 @@ struct md3 : vertmodel if(link(vwep, "tag_weapon")) vwep->index = parts.length(); } + if(!cullface) glDisable(GL_CULL_FACE); + else if(anim&ANIM_MIRROR) glCullFace(GL_BACK); + glPushMatrix(); - glTranslatef(x, y, z); + glTranslatef(o.x, o.y, o.z); glRotatef(yaw+180, 0, 0, 1); glRotatef(pitch, 0, -1, 0); glRotatef(90, 0, 0, 1); if(anim&ANIM_MIRROR || scale!=1) glScalef(anim&ANIM_MIRROR ? -scale : scale, scale, scale); parts[0]->render(anim, varseed, speed, basetime, d); + glPopMatrix(); + + if(!cullface) glEnable(GL_CULL_FACE); + else if(anim&ANIM_MIRROR) glCullFace(GL_FRONT); } void rendershadow(int anim, int varseed, float speed, int basetime, const vec &o, float yaw, model *vwepmdl) diff --git a/source/src/menus.cpp b/source/src/menus.cpp index 2baedcb9..60329fec 100644 --- a/source/src/menus.cpp +++ b/source/src/menus.cpp @@ -166,7 +166,7 @@ void rendermenumdl() s_sprintfd(skin)("packages/models/%s.jpg", m.mdl); tex = -(int)textureload(skin)->id; } - rendermodel(isplayermodel ? (char *)"playermodels" : m.mdl, m.anim, tex, 0, pos.x, pos.y, pos.z, yaw, 0, 0, 0, NULL, isplayermodel ? (char*)"weapons/subgun/world" : NULL, m.scale ? m.scale/25.0f : 1.0f); + rendermodel(isplayermodel ? (char *)"playermodels" : m.mdl, m.anim, tex, 0, pos, yaw, 0, 0, 0, NULL, isplayermodel ? (char*)"weapons/subgun/world" : NULL, m.scale ? m.scale/25.0f : 1.0f); glPopMatrix(); } diff --git a/source/src/model.h b/source/src/model.h index 42d70bf5..c6a18190 100644 --- a/source/src/model.h +++ b/source/src/model.h @@ -29,18 +29,24 @@ struct model bool cullface; float scale; vec translate; - - model() : cullface(true), scale(1), translate(0, 0, 0) {} + int batch; + + model() : cullface(true), scale(1), translate(0, 0, 0), batch(-1) {} virtual ~model() {} - virtual void render(int anim, int varseed, float speed, int basetime, float x, float y, float z, float yaw, float pitch, dynent *d, model *vwepmdl = NULL, float scale = 1.0f) = 0; - virtual void setskin(int tex = 0) = 0; + virtual bool load() = 0; virtual char *name() = 0; virtual int type() = 0; + virtual void render(int anim, int varseed, float speed, int basetime, const vec &o, float yaw, float pitch, dynent *d, model *vwepmdl = NULL, float scale = 1.0f) = 0; + virtual void setskin(int tex = 0) = 0; + virtual void genshadows(float height, float rad) {} virtual void rendershadow(int anim, int varseed, float speed, int basetime, const vec &o, float yaw, model *vwepmdl = NULL) {} virtual bool hasshadows() { return false; } + + virtual void startrender() {} + virtual void endrender() {} }; struct mapmodelinfo { int rad, h, zoff; string name; model *m; }; diff --git a/source/src/protos.h b/source/src/protos.h index 1d1f4ccd..936345fc 100644 --- a/source/src/protos.h +++ b/source/src/protos.h @@ -294,8 +294,9 @@ extern void cleansound(); extern void music(char *name); // rendermodel -extern void rendershadow(playerent *d); -extern void rendermodel(char *mdl, int anim, int tex, float rad, float x, float y, float z, float yaw, float pitch, float speed = 0, int basetime = 0, playerent *d = NULL, char *vwepmdl = NULL, float scale = 1.0f); +extern void rendermodel(char *mdl, int anim, int tex, float rad, const vec &o, float yaw, float pitch, float speed = 0, int basetime = 0, playerent *d = NULL, char *vwepmdl = NULL, float scale = 1.0f); +extern void startmodelbatches(); +extern void endmodelbatches(); extern mapmodelinfo &getmminfo(int i); extern int findanim(const char *name); extern void loadskin(const char *dir, const char *altdir, Texture *&skin); diff --git a/source/src/rendergl.cpp b/source/src/rendergl.cpp index f46ac345..7c2ce639 100644 --- a/source/src/rendergl.cpp +++ b/source/src/rendergl.cpp @@ -674,17 +674,23 @@ void gl_drawframe(int w, int h, float changelod, float curfps) xtraverts = 0; + startmodelbatches(); renderentities(); + endmodelbatches(); readmatrices(); readdepth(w, h, worldpos); + startmodelbatches(); renderclients(); + endmodelbatches(); if(player1->state==CS_ALIVE) readdepth(w, h, hitpos); + startmodelbatches(); renderbounceents(); - + endmodelbatches(); + // Added by Rick: Need todo here because of drawing the waypoints glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); WaypointClass.Think(); diff --git a/source/src/rendermodel.cpp b/source/src/rendermodel.cpp index a21739e7..809a664f 100644 --- a/source/src/rendermodel.cpp +++ b/source/src/rendermodel.cpp @@ -95,16 +95,114 @@ model *loadmodel(const char *name, int i) VARP(dynshadow, 0, 40, 100); -void rendermodel(char *mdl, int anim, int tex, float rad, float x, float y, float z, float yaw, float pitch, float speed, int basetime, playerent *d, char *vwepmdl, float scale) +struct batchedmodel +{ + vec o; + int anim, varseed, tex; + float yaw, pitch, speed; + int basetime; + playerent *d; + model *vwep; + float scale; +}; +struct modelbatch +{ + model *m; + vector batched; +}; +static vector batches; +static int numbatches = -1; + +void startmodelbatches() +{ + numbatches = 0; +} + +batchedmodel &addbatchedmodel(model *m) +{ + modelbatch *b = NULL; + if(m->batch>=0 && m->batchbatch]->m==m) b = batches[m->batch]; + else + { + if(numbatchesbatched.setsizenodelete(0); + } + else b = batches.add(new modelbatch); + b->m = m; + m->batch = numbatches++; + } + return b->batched.add(); +} + +void renderbatchedmodel(model *m, batchedmodel &b) +{ + int x = (int)b.o.x, y = (int)b.o.y; + if(!OUTBORD(x, y)) + { + sqr *s = S(x, y); + glColor3ub(s->r, s->g, s->b); + } + else glColor3f(1, 1, 1); + + m->setskin(b.tex); + m->render(b.anim, b.varseed, b.speed, b.basetime, b.o, b.yaw, b.pitch, b.d, b.vwep, b.scale); +} + +void renderbatchedmodelshadow(model *m, batchedmodel &b) +{ + int x = (int)b.o.x, y = (int)b.o.y; + if(OUTBORD(x, y)) return; + sqr *s = S(x, y); + vec center(b.o.x, b.o.y, s->floor); + if(s->type==FHF) center.z -= s->vdelta/4.0f; + if(center.z-0.1f>b.o.z) return; + center.z += 0.1f; + m->rendershadow(b.anim, b.varseed, b.speed, b.basetime, center, b.yaw, b.vwep); +} + +static int sortbatchedmodels(const batchedmodel *x, const batchedmodel *y) +{ + if(x->tex < y->tex) return -1; + if(x->tex > y->tex) return 1; + return 0; +} + +void endmodelbatches() +{ + loopi(numbatches) + { + modelbatch &b = *batches[i]; + if(b.batched.empty()) continue; + loopvj(b.batched) if(b.batched[j].tex) { b.batched.sort(sortbatchedmodels); break; } + b.m->startrender(); + loopvj(b.batched) + { + batchedmodel &bm = b.batched[j]; + renderbatchedmodel(b.m, bm); + } + if(dynshadow && b.m->hasshadows() && (!reflecting || refracting)) + { + glColor4f(0, 0, 0, dynshadow/100.0f); + loopvj(b.batched) + { + batchedmodel &bm = b.batched[j]; + renderbatchedmodelshadow(b.m, bm); + } + } + b.m->endrender(); + } + numbatches = -1; +} + +void rendermodel(char *mdl, int anim, int tex, float rad, const vec &o, float yaw, float pitch, float speed, int basetime, playerent *d, char *vwepmdl, float scale) { model *m = loadmodel(mdl); if(!m) return; - if(rad > 0 && isoccluded(camera1->o.x, camera1->o.y, x-rad, y-rad, rad*2)) return; + if(rad > 0 && isoccluded(camera1->o.x, camera1->o.y, o.x-rad, o.y-rad, rad*2)) return; - int ix = (int)x; - int iy = (int)y; - vec light(1, 1, 1); int varseed = 0; if(d) switch(anim&ANIM_INDEX) { @@ -120,36 +218,48 @@ void rendermodel(char *mdl, int anim, int tex, float rad, float x, float y, floa if(vwep->type()!=m->type()) vwep = NULL; } - if(!OUTBORD(ix, iy)) + if(numbatches>=0) { - sqr *s = S(ix, iy); - float ll = 256.0f; // 0.96f; - float of = 0.0f; // 0.1f; - light.x = s->r/ll+of; - light.y = s->g/ll+of; - light.z = s->b/ll+of; + batchedmodel &b = addbatchedmodel(m); + b.o = o; + b.anim = anim; + b.varseed = varseed; + b.tex = tex; + b.yaw = yaw; + b.pitch = pitch; + b.speed = speed; + b.basetime = basetime; + b.d = d; + b.vwep = vwep; + b.scale = scale; + return; + } + m->startrender(); + + int x = (int)o.x, y = (int)o.y; + if(!OUTBORD(x, y)) + { + sqr *s = S(x, y); if(dynshadow && m->hasshadows() && (!reflecting || refracting)) { - vec center(x, y, s->floor); + vec center(o.x, o.y, s->floor); if(s->type==FHF) center.z -= s->vdelta/4.0f; - if(center.z-0.1f<=z) + if(center.z-0.1f<=o.z) { center.z += 0.1f; glColor4f(0, 0, 0, dynshadow/100.0f); m->rendershadow(anim, varseed, speed, basetime, center, yaw, vwep); } } + glColor3ub(s->r, s->g, s->b); } + else glColor3f(1, 1, 1); - glColor3fv(&light.x); m->setskin(tex); + m->render(anim, varseed, speed, basetime, o, yaw, pitch, d, vwep, scale); - if(!m->cullface) glDisable(GL_CULL_FACE); - else if(anim&ANIM_MIRROR) glCullFace(GL_BACK); - m->render(anim, varseed, speed, basetime, x, y, z, yaw, pitch, d, vwep, scale); - if(!m->cullface) glEnable(GL_CULL_FACE); - else if(anim&ANIM_MIRROR) glCullFace(GL_FRONT); + m->endrender(); } int findanim(const char *name) @@ -223,7 +333,8 @@ void renderclient(playerent *d, char *mdlname, char *vwepname, int tex) int varseed = (int)(size_t)d; int anim = ANIM_IDLE|ANIM_LOOP; float speed = 0.0; - float mz = d->o.z-d->eyeheight; + vec o(d->o); + o.z -= d->eyeheight; int basetime = -((int)(size_t)d&0xFFF); if(d->state==CS_DEAD) { @@ -241,10 +352,10 @@ void renderclient(playerent *d, char *mdlname, char *vwepname, int tex) if(t>(r+10)*100) { t -= (r+10)*100; - mz -= t*t/10000000000.0f*t; + o.z -= t*t/10000000000.0f*t; } } - //if(mz<-1000) return; + //if(o.z<-1000) return; } else if(d->state==CS_EDITING) { anim = ANIM_JUMP|ANIM_END; } else if(d->state==CS_LAGGED) { anim = ANIM_SALUTE|ANIM_LOOP; } @@ -254,7 +365,7 @@ void renderclient(playerent *d, char *mdlname, char *vwepname, int tex) { anim = ANIM_ATTACK; speed = 300.0f/8; basetime = d->lastaction; } else if(!d->move && !d->strafe) { anim = ANIM_IDLE|ANIM_LOOP; } else { anim = ANIM_RUN|ANIM_LOOP; speed = 1860/d->maxspeed; } - rendermodel(mdlname, anim, tex, 1.5f, d->o.x, d->o.y, mz, d->yaw+90, d->pitch/4, speed, basetime, d, vwepname); + rendermodel(mdlname, anim, tex, 1.5f, o, d->yaw+90, d->pitch/4, speed, basetime, d, vwepname); } extern int democlientnum; diff --git a/source/src/tools.h b/source/src/tools.h index ef037705..6b5ffc1f 100644 --- a/source/src/tools.h +++ b/source/src/tools.h @@ -128,6 +128,7 @@ extern void endianswap(void *, int, int); #define loopvj(v) if(false) {} else for(int j = 0; j<(v).length(); j++) #define loopvk(v) if(false) {} else for(int k = 0; k<(v).length(); k++) #define loopvrev(v) if(false) {} else for(int i = (v).length()-1; i>=0; i--) +#define loopvjrev(v) if(false) {} else for(int j = (v).length()-1; i>=0; i--) template struct databuf diff --git a/source/src/vertmodel.h b/source/src/vertmodel.h index d619361f..31a1fd2e 100644 --- a/source/src/vertmodel.h +++ b/source/src/vertmodel.h @@ -127,13 +127,19 @@ struct vertmodel : model if(!(as.anim&ANIM_NOSKIN)) { - int id = tex < 0 ? -tex : skin->id; + GLuint id = tex < 0 ? -tex : skin->id; if(tex > 0) { int xs, ys; id = lookuptexture(tex, xs, ys); } - glBindTexture(GL_TEXTURE_2D, id); + if(id!=lasttex) + { + glBindTexture(GL_TEXTURE_2D, id); + lasttex = id; + } + if(enablealphablend) { glDisable(GL_BLEND); enablealphablend = false; } + if(!enabledepthmask) { glDepthMask(GL_TRUE); enabledepthmask = true; } } bool isstat = as.frame==0 && as.range==1; @@ -506,11 +512,20 @@ struct vertmodel : model anpos cur; cur.setframes(as); - glBindTexture(GL_TEXTURE_2D, shadows[cur.fr1]); + GLuint id = shadows[cur.fr1]; + if(id!=lasttex) + { + glBindTexture(GL_TEXTURE_2D, id); + lasttex = id; + } - glDepthMask(GL_FALSE); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + if(enabledepthmask) { glDepthMask(GL_FALSE); enabledepthmask = false; } + if(!enablealphablend) + { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + enablealphablend = true; + } yaw *= RAD; float c = cosf(yaw), s = sinf(yaw); @@ -523,9 +538,6 @@ struct vertmodel : model glTexCoord2f(1, 0); glVertex3f(x2*c - y2*s + o.x, y2*c + x2*s + o.y, o.z); glTexCoord2f(0, 0); glVertex3f(x1*c - y2*s + o.x, y2*c + x1*s + o.y, o.z); glEnd(); - - glDepthMask(GL_TRUE); - glDisable(GL_BLEND); } char *shadowfile() @@ -581,5 +593,24 @@ struct vertmodel : model { return parts.length()==1 && parts[0]->shadows; } + + static bool enablealphablend, enabledepthmask; + static GLuint lasttex; + + void startrender() + { + enablealphablend = false; + enabledepthmask = true; + lasttex = 0; + } + + void endrender() + { + if(enablealphablend) glDisable(GL_BLEND); + if(!enabledepthmask) glDepthMask(GL_TRUE); + } }; +bool vertmodel::enablealphablend = false, vertmodel::enabledepthmask = true; +GLuint vertmodel::lasttex = 0; + diff --git a/source/src/weapon.cpp b/source/src/weapon.cpp index 1d443d55..bc54b23c 100644 --- a/source/src/weapon.cpp +++ b/source/src/weapon.cpp @@ -394,7 +394,7 @@ void renderbounceents() bounceent *p = bounceents[i]; if(!p) continue; string model; - float z = p->o.z; + vec o(p->o); switch(p->bouncestate) { @@ -410,13 +410,13 @@ void renderbounceents() if(t>p->timetolife-2000) { t -= p->timetolife-2000; - z -= t*t/4000000000.0f*t; + o.z -= t*t/4000000000.0f*t; } break; } } path(model); - rendermodel(model, ANIM_MAPMODEL|ANIM_LOOP, 0, 1.1f, p->o.x, p->o.y, z, p->yaw+90, p->pitch); + rendermodel(model, ANIM_MAPMODEL|ANIM_LOOP, 0, 1.1f, o, p->yaw+90, p->pitch); } }