diff --git a/source/src/clientextras.cpp b/source/src/clientextras.cpp index 6e465653..0f641f47 100644 --- a/source/src/clientextras.cpp +++ b/source/src/clientextras.cpp @@ -2,7 +2,7 @@ #include "cube.h" -void renderclient(playerent *d, char *mdlname, char *vwepname) +void renderclient(playerent *d, char *mdlname, char *vwepname, int tex) { int varseed = (int)(size_t)d; int anim = ANIM_IDLE|ANIM_LOOP; @@ -38,8 +38,7 @@ void renderclient(playerent *d, char *mdlname, char *vwepname) { 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; }; - if(d->state==CS_ALIVE) rendershadow(d); - rendermodel(mdlname, anim, 0, 1.5f, d->o.x, mz, d->o.y, d->yaw+90, d->pitch/4, speed, basetime, d, vwepname); + rendermodel(mdlname, anim, tex, 1.5f, d->o.x, mz, d->o.y, d->yaw+90, d->pitch/4, speed, basetime, d, vwepname); }; extern int democlientnum; @@ -49,11 +48,11 @@ void renderplayer(playerent *d) if(!d) return; int team = team_int(d->team); - s_sprintfd(mdl)("playermodels/%s/0%i", team==TEAM_CLA ? "terrorist" : "counterterrorist", 1 + max(0, min(d->skin, (team==TEAM_CLA ? 3 : 5)))); + s_sprintfd(skin)("packages/models/playermodels/%s/0%i.jpg", team==TEAM_CLA ? "terrorist" : "counterterrorist", 1 + max(0, min(d->skin, (team==TEAM_CLA ? 3 : 5)))); string vwep; if(d->gunselect>=0 && d->gunselectgunselect]); else vwep[0] = 0; - renderclient(d, mdl, vwep[0] ? vwep : NULL); + renderclient(d, "playermodels", vwep[0] ? vwep : NULL, -textureload(skin)->id); }; void renderclients() diff --git a/source/src/main.cpp b/source/src/main.cpp index 4adb3e94..0226d3be 100644 --- a/source/src/main.cpp +++ b/source/src/main.cpp @@ -289,7 +289,8 @@ int main(int argc, char **argv) loadingscreen(); - log("hudgun models"); + log("models"); + preload_playermodels(); preload_hudguns(); log("sound"); diff --git a/source/src/md2.h b/source/src/md2.h index 12b2ce45..6e9747ce 100644 --- a/source/src/md2.h +++ b/source/src/md2.h @@ -169,6 +169,11 @@ struct md2 : vertmodel as.frame = frame[n]; as.range = range[n]; }; + + void begingenshadow() + { + glRotatef(180, 0, -1, 0); + }; }; 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) @@ -191,6 +196,12 @@ struct md2 : vertmodel }; }; + void rendershadow(int anim, int varseed, float speed, int basetime, const vec &o, float rad, float yaw, model *vwepmdl) + { + parts[0]->rendershadow(anim, varseed, speed, basetime, o, rad, yaw); + if(vwepmdl) ((md2 *)vwepmdl)->parts[0]->rendershadow(anim, varseed, speed, basetime, o, rad, yaw); + }; + bool load() { if(loaded) return true; diff --git a/source/src/md3.h b/source/src/md3.h index ef1ced70..6bdd86be 100644 --- a/source/src/md3.h +++ b/source/src/md3.h @@ -137,8 +137,15 @@ struct md3 : vertmodel fclose(f); return loaded=true; }; + + void begingenshadow() + { + glRotatef(180, 0, -1, 0); + glRotatef(-90, 0, 1, 0); + glRotatef(-90, 1, 0, 0); + }; }; - + 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) { if(!loaded) return; diff --git a/source/src/menus.cpp b/source/src/menus.cpp index 0b4425e2..1bea40c9 100644 --- a/source/src/menus.cpp +++ b/source/src/menus.cpp @@ -118,7 +118,13 @@ void rendermenumdl() float yaw = 1.0f; if(m.rotspeed) yaw += lastmillis/5.0f/100.0f*m.rotspeed; - rendermodel(m.mdl, m.anim, 0, 0, pos.x, pos.z, pos.y, yaw, 0, 100, 0, NULL, isplayermodel ? (char*)"weapons/subgun/world" : NULL, m.scale ? m.scale/25.0f : 1.0f); + int tex = 0; + if(isplayermodel) + { + s_sprintfd(skin)("packages/models/%s.jpg", m.mdl); + tex = -textureload(skin)->id; + }; + rendermodel(isplayermodel ? (char *)"playermodels" : m.mdl, m.anim, tex, 0, pos.x, pos.z, pos.y, yaw, 0, 100, 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 d2110e10..67163f66 100644 --- a/source/src/model.h +++ b/source/src/model.h @@ -7,6 +7,7 @@ enum { ANIM_IDLE = 0, ANIM_RUN, ANIM_ATTACK, ANIM_PAIN, ANIM_JUMP, ANIM_LAND, AN #define ANIM_REVERSE (1<<11) #define ANIM_NOINTERP (1<<12) #define ANIM_MIRROR (1<<13) +#define ANIM_NOSKIN (1<<14) struct animstate // used for animation blending of animated characters { @@ -34,6 +35,9 @@ struct model virtual bool load() = 0; virtual char *name() = 0; virtual int type() = 0; + + virtual void genshadows(float height, float rad) {}; + virtual void rendershadow(int anim, int varseed, float speed, int basetime, const vec &o, float rad, float yaw, model *vwepmdl = NULL) {}; }; struct mapmodelinfo { int rad, h, zoff; string name; model *m; }; diff --git a/source/src/protos.h b/source/src/protos.h index 6f20db3e..a52ef919 100644 --- a/source/src/protos.h +++ b/source/src/protos.h @@ -129,7 +129,7 @@ extern void mastercommand(int cmd, int arg1); // clientextras extern void renderclients(); -extern void renderclient(playerent *d, char *mdlname, char *vwepname); +extern void renderclient(playerent *d, char *mdlname, char *vwepname, int tex = 0); extern void showscores(bool on); extern void renderscores(); @@ -251,6 +251,7 @@ extern mapmodelinfo &getmminfo(int i); extern int findanim(const char *name); extern void loadskin(const char *dir, const char *altdir, Texture *&skin, model *m); extern model *loadmodel(const char *name, int i = -1); +extern void preload_playermodels(); extern void preload_hudguns(); extern void preload_mapmodels(); diff --git a/source/src/rendermodel.cpp b/source/src/rendermodel.cpp index 597fc362..04ce4a79 100644 --- a/source/src/rendermodel.cpp +++ b/source/src/rendermodel.cpp @@ -85,6 +85,8 @@ model *loadmodel(const char *name, int i) return m; }; +VAR(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) { model *m = loadmodel(mdl); @@ -95,19 +97,7 @@ void rendermodel(char *mdl, int anim, int tex, float rad, float x, float y, floa int ix = (int)x; int iy = (int)z; vec light(1, 1, 1); - - if(!OUTBORD(ix, iy)) - { - 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; - }; - - glColor3fv(&light.x); - m->setskin(tex); + int varseed = (int)(size_t)d + (d ? d->lastaction : 0); model *vwep = NULL; if(vwepmdl) @@ -116,47 +106,35 @@ 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)) + { + 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; + + if(d) + { + vec center(x, z, s->floor); + if(s->type==FHF) center.z -= s->vdelta/4.0f; + float radius = 4.0f; + radius *= 1.0f + min(1.0f, max(0.0f, 0.5f*(y - d->eyeheight - center.z)/(d->aboveeye + d->eyeheight))); + center.z += 0.1f; + glColor4f(1, 1, 1, dynshadow/100.0f); + m->rendershadow(anim, varseed, speed, basetime, center, radius, yaw, vwep); + }; + }; + + glColor3fv(&light.x); + m->setskin(tex); + if(anim&ANIM_MIRROR) glCullFace(GL_BACK); - m->render(anim, (int)(size_t)d + (d ? d->lastaction : 0), speed, basetime, x, y, z, yaw, pitch, d, vwep, scale); + m->render(anim, varseed, speed, basetime, x, y, z, yaw, pitch, d, vwep, scale); if(anim&ANIM_MIRROR) glCullFace(GL_FRONT); }; -VAR(dynshadow, 0, 40, 100); - -void rendershadow(playerent *d) -{ - if(OUTBORD((int)d->o.x, (int)d->o.y)) return; - sqr *s = S((int)d->o.x, (int)d->o.y); - float floor = s->floor; - if(s->type==FHF) floor -= s->vdelta/4.0f; - - float radius = 1.3f*d->radius; - radius *= 1.0f + min(1.0f, max(0.0f, 0.5f*(d->o.z - d->eyeheight - floor)/(d->aboveeye + d->eyeheight))); - - static Texture *shadowtex = NULL; - if(!shadowtex) shadowtex = textureload("packages/misc/shadow.png", 3); - - glColor4f(1, 1, 1, dynshadow/100.0f); - - glBindTexture(GL_TEXTURE_2D, shadowtex->id); - - glDepthMask(GL_FALSE); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - floor += 0.1f; - - glBegin(GL_POLYGON); - glTexCoord2f(0, 0); glVertex3f(d->o.x-radius, floor, d->o.y-radius); - glTexCoord2f(1, 0); glVertex3f(d->o.x+radius, floor, d->o.y-radius); - glTexCoord2f(1, 1); glVertex3f(d->o.x+radius, floor, d->o.y+radius); - glTexCoord2f(0, 1); glVertex3f(d->o.x-radius, floor, d->o.y+radius); - glEnd(); - - glDepthMask(GL_TRUE); - glDisable(GL_BLEND); -}; - int findanim(const char *name) { const char *names[] = { "idle", "run", "attack", "pain", "jump", "land", "flipoff", "salute", "taunt", "wave", "point", "crouch idle", "crouch walk", "crouch attack", "crouch pain", "crouch death", "death", "lying dead", "flag", "gun idle", "gun shoot", "gun reload", "gun throw", "mapmodel", "trigger", "all" }; @@ -183,6 +161,18 @@ void loadskin(const char *dir, const char *altdir, Texture *&skin, model *m) // }; }; +void preload_playermodels() +{ + model *playermdl = loadmodel("playermodels"); + if(playermdl) playermdl->genshadows(8.0f, 4.0f); + loopi(NUMGUNS) + { + s_sprintfd(vwep)("weapons/%s/world", hudgunnames[i]); + model *vwepmdl = loadmodel(vwep); + if(vwepmdl) vwepmdl->genshadows(8.0f, 4.0f); + }; +}; + void preload_mapmodels() { int xs, ys; diff --git a/source/src/vertmodel.h b/source/src/vertmodel.h index 64b67470..cfeba8af 100644 --- a/source/src/vertmodel.h +++ b/source/src/vertmodel.h @@ -1,3 +1,6 @@ +VAR(dynshadowsize, 4, 5, 8); +VAR(aadynshadow, 0, 3, 4); + struct vertmodel : model { struct anpos @@ -115,14 +118,17 @@ struct vertmodel : model { if(!dynbuf) return; - int id = skin->id; - if(tex) + if(!(as.anim&ANIM_NOSKIN)) { - int xs, ys; - id = lookuptexture(tex, xs, ys); + int id = tex < 0 ? -tex : skin->id; + if(tex > 0) + { + int xs, ys; + id = lookuptexture(tex, xs, ys); + }; + glBindTexture(GL_TEXTURE_2D, id); }; - glBindTexture(GL_TEXTURE_2D, id); - + bool isstat = as.frame==0 && as.range==1; if(isstat && statlist) { @@ -143,7 +149,7 @@ struct vertmodel : model if(index>=tristrip::RESTART) continue; }; tcvert &tc = tcverts[index]; - glTexCoord2f(tc.u, tc.v); + if(!(as.anim&ANIM_NOSKIN)) glTexCoord2f(tc.u, tc.v); glVertex3fv(&dynbuf[tc.index].x); }; glEnd(); @@ -184,14 +190,17 @@ struct vertmodel : model part **links; tag *tags; int numtags; + GLuint *shadows; - part() : loaded(false), anims(NULL), links(NULL), tags(NULL), numtags(0) {}; + part() : loaded(false), anims(NULL), links(NULL), tags(NULL), numtags(0), shadows(NULL) {}; virtual ~part() { meshes.deletecontentsp(); DELETEA(anims); DELETEA(links); DELETEA(tags); + if(shadows) glDeleteTextures(numframes, shadows); + DELETEA(shadows); }; bool link(part *link, const char *tag) @@ -244,6 +253,7 @@ struct vertmodel : model { as.frame = 0; as.range = numframes; + as.speed = speed; } else if(anims) { @@ -363,6 +373,98 @@ struct vertmodel : model ai.range = range; ai.speed = speed; }; + + virtual void begingenshadow() + { + }; + + virtual void endgenshadow() + { + }; + + void genshadow(int frame, float height, float rad) + { + extern int scr_w, scr_h; + int aasize = 1<<(dynshadowsize + aadynshadow); + while(aasize > scr_w || aasize > scr_h) aasize /= 2; + + glViewport(0, 0, aasize, aasize); + glClearColor(0, 0, 0, 1); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(-rad, rad, -rad, rad, 0.15f, height); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glRotatef(-90, -1, 0, 0); + + glDisable(GL_FOG); + glColor3f(1, 1, 1); + + glTranslatef(0, -height, 0); + begingenshadow(); + render(ANIM_ALL|ANIM_NOINTERP|ANIM_NOSKIN, 0, 1, lastmillis-frame, NULL); + endgenshadow(); + + glEnable(GL_FOG); + + uchar *pixels = new uchar[aasize*aasize]; + glReadPixels(0, 0, aasize, aasize, GL_RED, GL_UNSIGNED_BYTE, pixels); +#if 0 + SDL_Surface *img = SDL_CreateRGBSurface(SDL_SWSURFACE, aasize, aasize, 24, 0x0000FF, 0x00FF00, 0xFF0000, 0); + loopi(aasize*aasize) memset((uchar *)img->pixels + 3*i, pixels[i], 3); + s_sprintfd(imgname)("%s_%d.bmp", model->loadname, frame); + for(char *s; (s = strchr(imgname, '/'));) *s = '_'; + SDL_SaveBMP(img, imgname); + SDL_FreeSurface(img); +#endif + if(aasize > 1<meshes[0]; m.tex = tex; }; + + void genshadows(float height, float rad) + { + loopv(parts) parts[i]->genshadows(height, rad); + }; };