From c52a165ca55b825cedb376092d391b0f42e98a48 Mon Sep 17 00:00:00 2001 From: Shpoike Date: Fri, 7 Jul 2023 10:57:40 +0100 Subject: [PATCH] Rework colormap stuff so that quakerally/tf/etc work, fixing related csqc deficiency. Also support _shirt and _pants textures for people using 24bit textures. --- Quake/cl_main.c | 30 ++++---- Quake/cl_parse.c | 41 +++-------- Quake/common.c | 6 +- Quake/draw.h | 12 ++-- Quake/gl_draw.c | 1 - Quake/gl_mesh.c | 90 ++++++++++++++---------- Quake/gl_model.c | 45 ++++++------ Quake/gl_model.h | 11 ++- Quake/gl_rmisc.c | 80 --------------------- Quake/gl_texmgr.c | 115 ++++++++++++++++++++++++++++-- Quake/gl_texmgr.h | 4 +- Quake/menu.c | 73 +++++++++++++++++++ Quake/protocol.h | 1 + Quake/r_alias.c | 174 ++++++++++++++++++++++++++++++++-------------- 14 files changed, 432 insertions(+), 251 deletions(-) diff --git a/Quake/cl_main.c b/Quake/cl_main.c index 5d7969be..e23c1a3e 100644 --- a/Quake/cl_main.c +++ b/Quake/cl_main.c @@ -1401,6 +1401,17 @@ char *CL_PLColours_ToString(plcolour_t c) return "0"; } +plcolour_t CL_PLColours_FromLegacy(int val) +{ + plcolour_t c; + val&=0xf; + c.type = 1; + c.basic = val; + c.rgb[0] = c.rgb[1] = c.rgb[2] = val; //fixme... store proper palette? + + return c; +} + plcolour_t CL_PLColours_Parse(const char *s) { plcolour_t c; @@ -1408,17 +1419,13 @@ plcolour_t CL_PLColours_Parse(const char *s) if (!strncmp(s, "0x", 2)) { c.type = 2; - c.basic = 0; + c.basic = 0; //find nearest? c.rgb[0] = 0xff&(v>>16); c.rgb[1] = 0xff&(v>>8); c.rgb[2] = 0xff&(v>>0); } else if (*s) - { - c.type = 1; - c.basic = v; - c.rgb[0] = c.rgb[1] = c.rgb[2] = v&0xf; - } + return CL_PLColours_FromLegacy(v); else { c.type = 0; @@ -1430,20 +1437,13 @@ plcolour_t CL_PLColours_Parse(const char *s) static void CL_UserinfoChanged(scoreboard_t *sb) { char tmp[64]; - plcolour_t top, bot; Info_GetKey(sb->userinfo, "name", sb->name, sizeof(sb->name)); Info_GetKey(sb->userinfo, "topcolor", tmp, sizeof(tmp)); - top = CL_PLColours_Parse(tmp); + sb->shirt = CL_PLColours_Parse(*tmp?tmp:"0"); Info_GetKey(sb->userinfo, "bottomcolor", tmp, sizeof(tmp)); - bot = CL_PLColours_Parse(tmp); + sb->pants = CL_PLColours_Parse(*tmp?tmp:"0"); - if (!CL_PLColours_Equals(top, sb->shirt) || !CL_PLColours_Equals(bot, sb->pants)) - { - sb->shirt = top; - sb->pants = bot; - R_TranslateNewPlayerSkin (sb-cl.scores); - } //for qw compat. remember that keys with an asterisk are blocked from setinfo (still changable via ssqc though). sb->spectator = atoi(Info_GetKey(sb->userinfo, "*spectator", tmp, sizeof(tmp))); //0=regular player, 1=spectator, 2=spec-with-scores aka waiting their turn to (re)spawn. //Info_GetKey(sb->userinfo, "team", sb->team, sizeof(sb->team)); diff --git a/Quake/cl_parse.c b/Quake/cl_parse.c index a192f467..93bf01b9 100644 --- a/Quake/cl_parse.c +++ b/Quake/cl_parse.c @@ -517,9 +517,9 @@ static unsigned int CLFTE_ReadDelta(unsigned int entnum, entity_state_t *news, c { /*news->glowsize =*/ MSG_ReadByte(); /*news->glowcolour =*/ MSG_ReadByte(); - /*news->glowmod[0] =*/ MSG_ReadByte(); - /*news->glowmod[1] =*/ MSG_ReadByte(); - /*news->glowmod[2] =*/ MSG_ReadByte(); + news->glowmod[0] = MSG_ReadByte(); + news->glowmod[1] = MSG_ReadByte(); + news->glowmod[2] = MSG_ReadByte(); } if (bits & UF_FATNESS) /*news->fatness =*/ MSG_ReadByte(); @@ -587,13 +587,7 @@ static void CL_EntitiesDeltaed(void) VectorCopy (ent->netstate.origin, ent->msg_origins[0]); VectorCopy (ent->netstate.angles, ent->msg_angles[0]); } - skin = ent->netstate.skin; - if (skin != ent->skinnum) - { - ent->skinnum = skin; - if (newnum > 0 && newnum <= cl.maxclients) - R_TranslateNewPlayerSkin (newnum - 1); //johnfitz -- was R_TranslatePlayerSkin - } + ent->skinnum = ent->netstate.skin; ent->effects = ent->netstate.effects; //johnfitz -- lerping for movetype_step entities @@ -631,8 +625,6 @@ static void CL_EntitiesDeltaed(void) } else forcelink = true; // hack to make null model players work - if (newnum > 0 && newnum <= cl.maxclients) - R_TranslateNewPlayerSkin (newnum - 1); //johnfitz -- was R_TranslatePlayerSkin ent->lerpflags |= LERP_RESETANIM; //johnfitz -- don't lerp animation across model changes } @@ -1063,9 +1055,9 @@ static void CLDP_ReadDelta(unsigned int entnum, entity_state_t *s, const entity_ } if (bits & E5_GLOWMOD) { - /*s->glowmod[0] =*/ MSG_ReadByte(); - /*s->glowmod[1] =*/ MSG_ReadByte(); - /*s->glowmod[2] =*/ MSG_ReadByte(); + s->glowmod[0] = MSG_ReadByte(); + s->glowmod[1] = MSG_ReadByte(); + s->glowmod[2] = MSG_ReadByte(); } if (bits & E5_COMPLEXANIMATION) { @@ -1583,7 +1575,6 @@ static void CL_ParseUpdate (int bits) qboolean forcelink; entity_t *ent; int num; - int skin; if (cls.signon == SIGNONS - 1) { // first update is the final signon stage @@ -1652,15 +1643,9 @@ static void CL_ParseUpdate (int bits) if (bits & U_COLORMAP) ent->netstate.colormap = MSG_ReadByte(); if (bits & U_SKIN) - skin = MSG_ReadByte(); + ent->skinnum = MSG_ReadByte(); else - skin = ent->baseline.skin; - if (skin != ent->skinnum) - { - ent->skinnum = skin; - if (num > 0 && num <= cl.maxclients) - R_TranslateNewPlayerSkin (num - 1); //johnfitz -- was R_TranslatePlayerSkin - } + ent->skinnum = ent->baseline.skin; if (bits & U_EFFECTS) ent->effects = MSG_ReadByte(); else @@ -1777,8 +1762,6 @@ static void CL_ParseUpdate (int bits) } else forcelink = true; // hack to make null model players work - if (num > 0 && num <= cl.maxclients) - R_TranslateNewPlayerSkin (num - 1); //johnfitz -- was R_TranslatePlayerSkin ent->lerpflags |= LERP_RESETANIM; //johnfitz -- don't lerp animation across model changes } @@ -2005,10 +1988,8 @@ static void CL_NewTranslation (int slot, int vanillacolour) if (slot > cl.maxclients) Sys_Error ("CL_NewTranslation: slot > cl.maxclients"); - //clumsy, but ensures its initialised properly. - cl.scores[slot].shirt = CL_PLColours_Parse(va("%i", (vanillacolour>>4)&0xf)); - cl.scores[slot].pants = CL_PLColours_Parse(va("%i", (vanillacolour>>0)&0xf)); - R_TranslatePlayerSkin (slot); + cl.scores[slot].shirt = CL_PLColours_FromLegacy((vanillacolour>>4)&0xf); + cl.scores[slot].pants = CL_PLColours_FromLegacy((vanillacolour>>0)&0xf); } /* diff --git a/Quake/common.c b/Quake/common.c index 4f46569d..7b371545 100644 --- a/Quake/common.c +++ b/Quake/common.c @@ -1824,9 +1824,9 @@ static void COM_SetupNullState(void) nullentitystate.colormod[0] = 32; nullentitystate.colormod[1] = 32; nullentitystate.colormod[2] = 32; -// nullentitystate.glowmod[0] = 32; -// nullentitystate.glowmod[1] = 32; -// nullentitystate.glowmod[2] = 32; + nullentitystate.glowmod[0] = 32; + nullentitystate.glowmod[1] = 32; + nullentitystate.glowmod[2] = 32; nullentitystate.alpha = ENTALPHA_DEFAULT; //fte has 255 by default, with 0 for invisible. fitz uses 1 for invisible, 0 default, and 255=full alpha nullentitystate.scale = ENTSCALE_DEFAULT; nullentitystate.solidsize = ES_SOLID_NOT; diff --git a/Quake/draw.h b/Quake/draw.h index 77d2cb6e..5ec3266c 100644 --- a/Quake/draw.h +++ b/Quake/draw.h @@ -26,13 +26,17 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // draw.h -- these are the only functions outside the refresh allowed // to touch the vid buffer -typedef struct +typedef union { - byte type; //0 for none, 1 for legacy colours, 2 for rgb. - byte basic; - byte rgb[3]; + struct{ + byte type; //0 for none, 1 for legacy colours, 2 for rgb. + byte rgb[3]; + byte basic; //used in legacy contexts where an rgb value will not work. + }; + int key; //for fast compares } plcolour_t; plcolour_t CL_PLColours_Parse(const char *s); +plcolour_t CL_PLColours_FromLegacy(int val); char *CL_PLColours_ToString(plcolour_t c); byte *CL_PLColours_ToRGB(plcolour_t *c); #define CL_PLColours_Equals(a,b) (!memcmp(&a,&b, sizeof(plcolour_t))) diff --git a/Quake/gl_draw.c b/Quake/gl_draw.c index d38105f1..812b2431 100644 --- a/Quake/gl_draw.c +++ b/Quake/gl_draw.c @@ -517,7 +517,6 @@ qboolean Draw_ReloadTextures(qboolean force) { TexMgr_NewGame (); Draw_NewGame (); - R_NewGame (); Cache_Flush (); diff --git a/Quake/gl_mesh.c b/Quake/gl_mesh.c index ae5f7c86..41b8c954 100644 --- a/Quake/gl_mesh.c +++ b/Quake/gl_mesh.c @@ -653,6 +653,8 @@ void Mod_LoadMD3Model (qmodel_t *mod, void *buffer) { char texturename[MAX_QPATH]; char fullbrightname[MAX_QPATH]; + char uppername[MAX_QPATH]; + char lowername[MAX_QPATH]; char *ext; //texture names in md3s are kinda fucked. they could be just names relative to the mdl, or full paths, or just simple shader names. //our texture manager is too lame to scan all 1000 possibilities @@ -672,16 +674,19 @@ void Mod_LoadMD3Model (qmodel_t *mod, void *buffer) if (*ext) *--ext = 0; //luma has an extra postfix. + q_snprintf(uppername, sizeof(fullbrightname), "%s_shirt", texturename); + q_snprintf(lowername, sizeof(fullbrightname), "%s_pants", texturename); q_snprintf(fullbrightname, sizeof(fullbrightname), "%s_luma", texturename); - osurf->gltextures[j][0] = TexMgr_LoadImage(mod, texturename, osurf->skinwidth, osurf->skinheight, SRC_EXTERNAL, NULL, texturename, 0, TEXPREF_PAD|TEXPREF_ALPHA|TEXPREF_NOBRIGHT|TEXPREF_MIPMAP); - osurf->fbtextures[j][0] = TexMgr_LoadImage(mod, fullbrightname, osurf->skinwidth, osurf->skinheight, SRC_EXTERNAL, NULL, texturename, 0, TEXPREF_PAD|TEXPREF_ALPHA|TEXPREF_FULLBRIGHT|TEXPREF_MIPMAP); - osurf->gltextures[j][3] = osurf->gltextures[j][2] = osurf->gltextures[j][1] = osurf->gltextures[j][0]; - osurf->fbtextures[j][3] = osurf->fbtextures[j][2] = osurf->fbtextures[j][1] = osurf->fbtextures[j][0]; + osurf->textures[j][0].base = TexMgr_LoadImage(mod, texturename, osurf->skinwidth, osurf->skinheight, SRC_EXTERNAL, NULL, texturename, 0, TEXPREF_PAD|TEXPREF_ALPHA|TEXPREF_NOBRIGHT|TEXPREF_MIPMAP); + osurf->textures[j][0].lower = TexMgr_LoadImage(mod, lowername, osurf->skinwidth, osurf->skinheight, SRC_EXTERNAL, NULL, lowername, 0, TEXPREF_PAD|TEXPREF_ALPHA|TEXPREF_NOBRIGHT|TEXPREF_MIPMAP); + osurf->textures[j][0].upper = TexMgr_LoadImage(mod, uppername, osurf->skinwidth, osurf->skinheight, SRC_EXTERNAL, NULL, uppername, 0, TEXPREF_PAD|TEXPREF_ALPHA|TEXPREF_NOBRIGHT|TEXPREF_MIPMAP); + osurf->textures[j][0].luma = TexMgr_LoadImage(mod, fullbrightname, osurf->skinwidth, osurf->skinheight, SRC_EXTERNAL, NULL, fullbrightname, 0, TEXPREF_PAD|TEXPREF_ALPHA|TEXPREF_FULLBRIGHT|TEXPREF_MIPMAP); + osurf->textures[j][3] = osurf->textures[j][2] = osurf->textures[j][1] = osurf->textures[j][0]; } if (osurf->numskins) { - osurf->skinwidth = osurf->gltextures[0][0]->source_width; - osurf->skinheight = osurf->gltextures[0][0]->source_height; + osurf->skinwidth = osurf->textures[0][0].base->source_width; + osurf->skinheight = osurf->textures[0][0].base->source_height; } } @@ -1087,14 +1092,19 @@ static void Mod_LoadIQMSkin (qmodel_t *mod, const struct iqmheader *pinheader, a { const char *texturename = (const char *)pinheader + pinheader->ofs_text + sf->material_idx; char hackytexturename[MAX_QPATH]; + char filename2[MAX_QPATH]; COM_StripExtension(texturename, hackytexturename, sizeof(hackytexturename)); - osurf->gltextures[j][k] = TexMgr_LoadImage(mod, texturename, osurf->skinwidth, osurf->skinheight, SRC_EXTERNAL, NULL, hackytexturename, 0, TEXPREF_PAD|TEXPREF_ALPHA|TEXPREF_NOBRIGHT|TEXPREF_MIPMAP); - osurf->fbtextures[j][k] = NULL;//TexMgr_LoadImage(mod, fullbrightname, osurf->skinwidth, osurf->skinheight, SRC_EXTERNAL, NULL, fullbrightname, 0, TEXPREF_PAD|TEXPREF_ALPHA|TEXPREF_FULLBRIGHT|TEXPREF_MIPMAP); + osurf->textures[j][k].base = TexMgr_LoadImage(mod, texturename, osurf->skinwidth, osurf->skinheight, SRC_EXTERNAL, NULL, hackytexturename, 0, TEXPREF_PAD|TEXPREF_ALPHA|TEXPREF_NOBRIGHT|TEXPREF_MIPMAP); + q_snprintf(filename2, sizeof(filename2), "%s_pants", hackytexturename); + osurf->textures[j][k].lower = TexMgr_LoadImage(mod, filename2, osurf->skinwidth, osurf->skinheight, SRC_EXTERNAL, NULL, filename2, 0, TEXPREF_PAD|TEXPREF_ALLOWMISSING|TEXPREF_MIPMAP); + q_snprintf(filename2, sizeof(filename2), "%s_shirt", hackytexturename); + osurf->textures[j][k].upper = TexMgr_LoadImage(mod, filename2, osurf->skinwidth, osurf->skinheight, SRC_EXTERNAL, NULL, filename2, 0, TEXPREF_PAD|TEXPREF_ALLOWMISSING|TEXPREF_MIPMAP); + q_snprintf(filename2, sizeof(filename2), "%s_luma", hackytexturename); + osurf->textures[j][k].luma = TexMgr_LoadImage(mod, filename2, osurf->skinwidth, osurf->skinheight, SRC_EXTERNAL, NULL, filename2, 0, TEXPREF_PAD|TEXPREF_ALPHA|TEXPREF_FULLBRIGHT|TEXPREF_MIPMAP|TEXPREF_ALLOWMISSING); } for (; k < 4; k++) { - osurf->gltextures[j][k] = osurf->gltextures[j][k%skin->countframes]; - osurf->fbtextures[j][k] = osurf->fbtextures[j][k%skin->countframes]; + osurf->textures[j][k] = osurf->textures[j][k%skin->countframes]; } } osurf->numskins = j; @@ -1105,7 +1115,7 @@ static void Mod_LoadIQMSkin (qmodel_t *mod, const struct iqmheader *pinheader, a for (j = 0; j < 1; j++) { char texturename[MAX_QPATH]; - char fullbrightname[MAX_QPATH]; + char filename2[MAX_QPATH]; char *ext; //texture names in md3s are kinda fucked. they could be just names relative to the mdl, or full paths, or just simple shader names. //our texture manager is too lame to scan all 1000 possibilities @@ -1125,17 +1135,21 @@ static void Mod_LoadIQMSkin (qmodel_t *mod, const struct iqmheader *pinheader, a if (*ext) *--ext = 0; //luma has an extra postfix. - q_snprintf(fullbrightname, sizeof(fullbrightname), "%s_luma", texturename); - osurf->gltextures[j][0] = TexMgr_LoadImage(mod, texturename, osurf->skinwidth, osurf->skinheight, SRC_EXTERNAL, NULL, texturename, 0, TEXPREF_PAD|TEXPREF_ALPHA|TEXPREF_NOBRIGHT|TEXPREF_MIPMAP); - osurf->fbtextures[j][0] = NULL;//TexMgr_LoadImage(mod, fullbrightname, osurf->skinwidth, osurf->skinheight, SRC_EXTERNAL, NULL, fullbrightname, 0, TEXPREF_PAD|TEXPREF_ALPHA|TEXPREF_FULLBRIGHT|TEXPREF_MIPMAP); - osurf->gltextures[j][3] = osurf->gltextures[j][2] = osurf->gltextures[j][1] = osurf->gltextures[j][0]; - osurf->fbtextures[j][3] = osurf->fbtextures[j][2] = osurf->fbtextures[j][1] = osurf->fbtextures[j][0]; + osurf->textures[j][0].base = TexMgr_LoadImage(mod, texturename, osurf->skinwidth, osurf->skinheight, SRC_EXTERNAL, NULL, texturename, 0, TEXPREF_PAD|TEXPREF_ALPHA|TEXPREF_NOBRIGHT|TEXPREF_MIPMAP); + q_snprintf(filename2, sizeof(filename2), "%s_pants", texturename); + osurf->textures[j][0].lower = TexMgr_LoadImage(mod, filename2, osurf->skinwidth, osurf->skinheight, SRC_EXTERNAL, NULL, filename2, 0, TEXPREF_PAD|TEXPREF_ALLOWMISSING|TEXPREF_MIPMAP); + q_snprintf(filename2, sizeof(filename2), "%s_shirt", texturename); + osurf->textures[j][0].upper = TexMgr_LoadImage(mod, filename2, osurf->skinwidth, osurf->skinheight, SRC_EXTERNAL, NULL, filename2, 0, TEXPREF_PAD|TEXPREF_ALLOWMISSING|TEXPREF_MIPMAP); + q_snprintf(filename2, sizeof(filename2), "%s_luma", texturename); + osurf->textures[j][0].luma = TexMgr_LoadImage(mod, filename2, osurf->skinwidth, osurf->skinheight, SRC_EXTERNAL, NULL, filename2, 0, TEXPREF_PAD|TEXPREF_ALPHA|TEXPREF_FULLBRIGHT|TEXPREF_MIPMAP|TEXPREF_ALLOWMISSING); + + osurf->textures[j][3] = osurf->textures[j][2] = osurf->textures[j][1] = osurf->textures[j][0]; } } if (osurf->numskins) { - osurf->skinwidth = osurf->gltextures[0][0]->source_width; - osurf->skinheight = osurf->gltextures[0][0]->source_height; + osurf->skinwidth = osurf->textures[0][0].base->source_width; + osurf->skinheight = osurf->textures[0][0].base->source_height; } } @@ -1867,7 +1881,7 @@ void Mod_LoadMD5MeshModel (qmodel_t *mod, const void *buffer) qboolean malloced; void *data; int mark = Hunk_LowMark (); - for (f = 0; f < countof(surf->gltextures[0]); f++) + for (f = 0; f < countof(surf->textures[0]); f++) { q_snprintf(texname, sizeof(texname), "progs/%s_%02u_%02u", com_token, surf->numskins, f); @@ -1875,31 +1889,39 @@ void Mod_LoadMD5MeshModel (qmodel_t *mod, const void *buffer) //now load whatever we found if (data) //load external image { - surf->gltextures[surf->numskins][f] = TexMgr_LoadImage (mod, texname, fwidth, fheight, fmt, data, texname, 0, TEXPREF_ALPHA|TEXPREF_NOBRIGHT|TEXPREF_MIPMAP ); - surf->fbtextures[surf->numskins][f] = NULL; + surf->textures[surf->numskins][f].base = TexMgr_LoadImage (mod, texname, fwidth, fheight, fmt, data, texname, 0, TEXPREF_ALPHA|TEXPREF_NOBRIGHT|TEXPREF_MIPMAP ); + surf->textures[surf->numskins][f].lower = NULL; + surf->textures[surf->numskins][f].upper = NULL; + surf->textures[surf->numskins][f].luma = NULL; if (fmt == SRC_INDEXED) { //8bit base texture. use it for fullbrights. for (j = 0; j < fwidth*fheight; j++) { if (((byte*)data)[j] > 223) { - surf->fbtextures[surf->numskins][f] = TexMgr_LoadImage (mod, va("%s_luma", texname), fwidth, fheight, fmt, data, texname, 0, TEXPREF_ALPHA|TEXPREF_FULLBRIGHT|TEXPREF_MIPMAP ); + surf->textures[surf->numskins][f].luma = TexMgr_LoadImage (mod, va("%s_luma", texname), fwidth, fheight, fmt, data, texname, 0, TEXPREF_ALPHA|TEXPREF_FULLBRIGHT|TEXPREF_MIPMAP ); break; } } } else { //we found a 32bit base texture. - if (!surf->fbtextures[surf->numskins][f]) + if (!surf->textures[surf->numskins][f].luma) { q_snprintf(texname, sizeof(texname), "progs/%s_%02u_%02u_glow", com_token, surf->numskins, f); - surf->fbtextures[surf->numskins][f] = TexMgr_LoadImage(mod, texname, surf->skinwidth, surf->skinheight, SRC_EXTERNAL, NULL, texname, 0, TEXPREF_ALLOWMISSING|TEXPREF_MIPMAP); + surf->textures[surf->numskins][f].luma = TexMgr_LoadImage(mod, texname, surf->skinwidth, surf->skinheight, SRC_EXTERNAL, NULL, texname, 0, TEXPREF_ALLOWMISSING|TEXPREF_MIPMAP); } - if (!surf->fbtextures[surf->numskins][f]) + if (!surf->textures[surf->numskins][f].luma) { q_snprintf(texname, sizeof(texname), "progs/%s_%02u_%02u_luma", com_token, surf->numskins, f); - surf->fbtextures[surf->numskins][f] = TexMgr_LoadImage(mod, texname, surf->skinwidth, surf->skinheight, SRC_EXTERNAL, NULL, texname, 0, TEXPREF_ALLOWMISSING|TEXPREF_MIPMAP); + surf->textures[surf->numskins][f].luma = TexMgr_LoadImage(mod, texname, surf->skinwidth, surf->skinheight, SRC_EXTERNAL, NULL, texname, 0, TEXPREF_ALLOWMISSING|TEXPREF_MIPMAP); } + + q_snprintf(texname, sizeof(texname), "progs/%s_%02u_%02u_pants", com_token, surf->numskins, f); + surf->textures[surf->numskins][f].lower = TexMgr_LoadImage(mod, texname, surf->skinwidth, surf->skinheight, SRC_EXTERNAL, NULL, texname, 0, TEXPREF_ALLOWMISSING|TEXPREF_MIPMAP); + + q_snprintf(texname, sizeof(texname), "progs/%s_%02u_%02u_shirt", com_token, surf->numskins, f); + surf->textures[surf->numskins][f].upper = TexMgr_LoadImage(mod, texname, surf->skinwidth, surf->skinheight, SRC_EXTERNAL, NULL, texname, 0, TEXPREF_ALLOWMISSING|TEXPREF_MIPMAP); } //now try to load glow/luma image from the same place @@ -1915,23 +1937,17 @@ void Mod_LoadMD5MeshModel (qmodel_t *mod, const void *buffer) //this stuff is hideous. if (f < 2) - { - surf->gltextures[surf->numskins][1] = surf->gltextures[surf->numskins][0]; - surf->fbtextures[surf->numskins][1] = surf->fbtextures[surf->numskins][0]; - } + surf->textures[surf->numskins][1] = surf->textures[surf->numskins][0]; if (f == 3) Con_Warning("progs/%s_%02u_##: 3 skinframes found...\n", com_token, surf->numskins); if (f < 4) { - surf->gltextures[surf->numskins][3] = surf->gltextures[surf->numskins][1]; - surf->gltextures[surf->numskins][2] = surf->gltextures[surf->numskins][0]; - - surf->fbtextures[surf->numskins][3] = surf->fbtextures[surf->numskins][1]; - surf->fbtextures[surf->numskins][2] = surf->fbtextures[surf->numskins][0]; + surf->textures[surf->numskins][3] = surf->textures[surf->numskins][1]; + surf->textures[surf->numskins][2] = surf->textures[surf->numskins][0]; } } - surf->skinwidth = surf->gltextures[0][0]?surf->gltextures[0][0]->width:1; - surf->skinheight = surf->gltextures[0][0]?surf->gltextures[0][0]->height:1; + surf->skinwidth = surf->textures[0][0].base?surf->textures[0][0].base->width:1; + surf->skinheight = surf->textures[0][0].base?surf->textures[0][0].base->height:1; buffer = COM_Parse(buffer); MD5EXPECT("numverts"); surf->numverts_vbo = surf->numverts = MD5UINT(); diff --git a/Quake/gl_model.c b/Quake/gl_model.c index ef90f855..a156054c 100644 --- a/Quake/gl_model.c +++ b/Quake/gl_model.c @@ -26,8 +26,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "quakedef.h" -extern gltexture_t *playertextures[MAX_SCOREBOARD]; //spike - to ensure skins don't get screwed randomly. - qmodel_t *loadmodel; char loadname[32]; // for hunk tags @@ -487,11 +485,6 @@ static qmodel_t *Mod_LoadModel (qmodel_t *mod, qboolean crash) Mod_SetExtraFlags (mod); //johnfitz. spike -- moved this to be generic, because most of the flags are anyway. - if (cls.state == ca_connected) - for (i = 0; i < countof(playertextures); i++) - if (playertextures[i] && playertextures[i]->owner == mod) - R_TranslateNewPlayerSkin(i); - return mod; } @@ -3089,13 +3082,19 @@ static void *Mod_LoadAllSkins (int numskins, daliasskintype_t *pskintype) //now load whatever we found if (data) //load external image { - pheader->gltextures[i][0] = TexMgr_LoadImage (loadmodel, filename, fwidth, fheight, + pheader->textures[i][0].base = TexMgr_LoadImage (loadmodel, filename, fwidth, fheight, fmt, data, filename, 0, TEXPREF_ALPHA|texflags|TEXPREF_MIPMAP ); if (malloced) free(data); Hunk_FreeToLowMark (mark); + q_snprintf (filename2, sizeof(filename2), "%s_pants", filename); + pheader->textures[i][0].lower = TexMgr_LoadImage(loadmodel, filename2, fwidth, fheight, SRC_EXTERNAL, NULL, filename2, 0, TEXPREF_ALLOWMISSING|TEXPREF_MIPMAP); + + q_snprintf (filename2, sizeof(filename2), "%s_shirt", filename); + pheader->textures[i][0].upper = TexMgr_LoadImage(loadmodel, filename2, fwidth, fheight, SRC_EXTERNAL, NULL, filename2, 0, TEXPREF_ALLOWMISSING|TEXPREF_MIPMAP); + //now try to load glow/luma image from the same place q_snprintf (filename2, sizeof(filename2), "%s_glow", filename); data = !gl_load24bit.value?NULL:Image_LoadImage (filename2, &fwidth, &fheight, &fmt, &malloced); @@ -3106,10 +3105,10 @@ static void *Mod_LoadAllSkins (int numskins, daliasskintype_t *pskintype) } if (data) - pheader->fbtextures[i][0] = TexMgr_LoadImage (loadmodel, filename2, fwidth, fheight, + pheader->textures[i][0].luma = TexMgr_LoadImage (loadmodel, filename2, fwidth, fheight, fmt, data, filename, 0, TEXPREF_ALPHA|texflags|TEXPREF_MIPMAP ); else - pheader->fbtextures[i][0] = NULL; + pheader->textures[i][0].luma = NULL; if (malloced) free(data); @@ -3122,22 +3121,24 @@ static void *Mod_LoadAllSkins (int numskins, daliasskintype_t *pskintype) offset = (src_offset_t)(pskintype+1) - (src_offset_t)mod_base; if (Mod_CheckFullbrights ((byte *)(pskintype+1), size)) { - pheader->gltextures[i][0] = TexMgr_LoadImage (loadmodel, name, pheader->skinwidth, pheader->skinheight, + pheader->textures[i][0].base = TexMgr_LoadImage (loadmodel, name, pheader->skinwidth, pheader->skinheight, SRC_INDEXED, (byte *)(pskintype+1), loadmodel->name, offset, texflags | TEXPREF_NOBRIGHT); q_snprintf (fbr_mask_name, sizeof(fbr_mask_name), "%s:frame%i_glow", loadmodel->name, i); - pheader->fbtextures[i][0] = TexMgr_LoadImage (loadmodel, fbr_mask_name, pheader->skinwidth, pheader->skinheight, + pheader->textures[i][0].luma = TexMgr_LoadImage (loadmodel, fbr_mask_name, pheader->skinwidth, pheader->skinheight, SRC_INDEXED, (byte *)(pskintype+1), loadmodel->name, offset, texflags | TEXPREF_FULLBRIGHT); } else { - pheader->gltextures[i][0] = TexMgr_LoadImage (loadmodel, name, pheader->skinwidth, pheader->skinheight, + pheader->textures[i][0].base = TexMgr_LoadImage (loadmodel, name, pheader->skinwidth, pheader->skinheight, SRC_INDEXED, (byte *)(pskintype+1), loadmodel->name, offset, texflags); - pheader->fbtextures[i][0] = NULL; + pheader->textures[i][0].luma = NULL; } + + pheader->textures[i][0].upper = NULL; + pheader->textures[i][0].lower = NULL; } - pheader->gltextures[i][3] = pheader->gltextures[i][2] = pheader->gltextures[i][1] = pheader->gltextures[i][0]; - pheader->fbtextures[i][3] = pheader->fbtextures[i][2] = pheader->fbtextures[i][1] = pheader->fbtextures[i][0]; + pheader->textures[i][3] = pheader->textures[i][2] = pheader->textures[i][1] = pheader->textures[i][0]; //johnfitz pskintype = (daliasskintype_t *)((byte *)(pskintype+1) + size); @@ -3166,25 +3167,27 @@ static void *Mod_LoadAllSkins (int numskins, daliasskintype_t *pskintype) offset = (src_offset_t)(pskintype) - (src_offset_t)mod_base; //johnfitz if (Mod_CheckFullbrights ((byte *)(pskintype), size)) { - pheader->gltextures[i][j&3] = TexMgr_LoadImage (loadmodel, name, pheader->skinwidth, pheader->skinheight, + pheader->textures[i][j&3].base = TexMgr_LoadImage (loadmodel, name, pheader->skinwidth, pheader->skinheight, SRC_INDEXED, (byte *)(pskintype), loadmodel->name, offset, texflags | TEXPREF_NOBRIGHT); q_snprintf (fbr_mask_name, sizeof(fbr_mask_name), "%s:frame%i_%i_glow", loadmodel->name, i,j); - pheader->fbtextures[i][j&3] = TexMgr_LoadImage (loadmodel, fbr_mask_name, pheader->skinwidth, pheader->skinheight, + pheader->textures[i][j&3].luma = TexMgr_LoadImage (loadmodel, fbr_mask_name, pheader->skinwidth, pheader->skinheight, SRC_INDEXED, (byte *)(pskintype), loadmodel->name, offset, texflags | TEXPREF_FULLBRIGHT); } else { - pheader->gltextures[i][j&3] = TexMgr_LoadImage (loadmodel, name, pheader->skinwidth, pheader->skinheight, + pheader->textures[i][j&3].base = TexMgr_LoadImage (loadmodel, name, pheader->skinwidth, pheader->skinheight, SRC_INDEXED, (byte *)(pskintype), loadmodel->name, offset, texflags); - pheader->fbtextures[i][j&3] = NULL; + pheader->textures[i][j&3].luma = NULL; } //johnfitz + pheader->textures[i][j&3].upper = NULL; + pheader->textures[i][j&3].lower = NULL; pskintype = (daliasskintype_t *)((byte *)(pskintype) + size); } k = j; for (/**/; j < 4; j++) - pheader->gltextures[i][j&3] = pheader->gltextures[i][j - k]; + pheader->textures[i][j&3] = pheader->textures[i][j - k]; } } diff --git a/Quake/gl_model.h b/Quake/gl_model.h index 454e6dda..7e273b28 100644 --- a/Quake/gl_model.h +++ b/Quake/gl_model.h @@ -380,9 +380,14 @@ typedef struct { PV_QUAKEFORGE, //trivertx16_t PV_IQM, //iqmvert_t } poseverttype; //spike - struct gltexture_s *gltextures[MAX_SKINS][4]; //johnfitz - struct gltexture_s *fbtextures[MAX_SKINS][4]; //johnfitz - intptr_t texels[MAX_SKINS]; // only for player skins + struct skintextures_s + { + struct gltexture_s *base; + struct gltexture_s *luma; + struct gltexture_s *upper; + struct gltexture_s *lower; + } textures[MAX_SKINS][4]; //spike + intptr_t texels[MAX_SKINS]; // only for player skins maliasframedesc_t frames[1]; // variable sized } aliashdr_t; diff --git a/Quake/gl_rmisc.c b/Quake/gl_rmisc.c index a0f56f1f..962723c3 100644 --- a/Quake/gl_rmisc.c +++ b/Quake/gl_rmisc.c @@ -47,8 +47,6 @@ extern cvar_t r_noshadow_list; extern cvar_t gl_zfix; // QuakeSpasm z-fighting fix cvar_t r_brokenturbbias = {"r_brokenturbbias", "1", CVAR_ARCHIVE}; //replicates QS's bug where it ignores texture coord offsets for water (breaking curved water volumes). we do NOT ignore scales though. -extern gltexture_t *playertextures[MAX_SCOREBOARD]; //johnfitz - /* ==================== @@ -245,84 +243,6 @@ void R_Init (void) Fog_Init (); //johnfitz } -/* -=============== -R_TranslatePlayerSkin -- johnfitz -- rewritten. also, only handles new colors, not new skins -=============== -*/ -void R_TranslatePlayerSkin (int playernum) -{ - //FIXME: if gl_nocolors is on, then turned off, the textures may be out of sync with the scoreboard colors. - if (!gl_nocolors.value) - if (playertextures[playernum]) - TexMgr_ReloadImage (playertextures[playernum], cl.scores[playernum].shirt, cl.scores[playernum].pants); -} - -/* -=============== -R_TranslateNewPlayerSkin -- johnfitz -- split off of TranslatePlayerSkin -- this is called when -the skin or model actually changes, instead of just new colors -added bug fix from bengt jardup -=============== -*/ -void R_TranslateNewPlayerSkin (int playernum) -{ - char name[64]; - byte *pixels; - aliashdr_t *paliashdr; - int skinnum; - -//get correct texture pixels - currententity = &cl.entities[1+playernum]; - - if (!currententity->model || currententity->model->type != mod_alias) - return; - - paliashdr = (aliashdr_t *)Mod_Extradata (currententity->model); - - skinnum = currententity->skinnum; - - if (paliashdr->numskins) - { - //TODO: move these tests to the place where skinnum gets received from the server - if (skinnum < 0 || skinnum >= paliashdr->numskins) - { - Con_DPrintf("(%d): Invalid player skin #%d\n", playernum, skinnum); - skinnum = 0; - } - - pixels = (byte *)paliashdr + paliashdr->texels[skinnum]; // This is not a persistent place! - - //upload new image - q_snprintf(name, sizeof(name), "player_%i", playernum); - playertextures[playernum] = TexMgr_LoadImage (currententity->model, name, paliashdr->skinwidth, paliashdr->skinheight, - SRC_INDEXED, pixels, paliashdr->gltextures[skinnum][0]->source_file, paliashdr->gltextures[skinnum][0]->source_offset, TEXPREF_PAD | TEXPREF_OVERWRITE); - } - else - { - q_snprintf(name, sizeof(name), "player_%i", playernum); - playertextures[playernum] = TexMgr_LoadImage (currententity->model, name, paliashdr->skinwidth, paliashdr->skinheight, - SRC_EXTERNAL, NULL, "skins/base.pcx", 0, TEXPREF_PAD | TEXPREF_OVERWRITE); - } - -//now recolor it - R_TranslatePlayerSkin (playernum); -} - -/* -=============== -R_NewGame -- johnfitz -- handle a game switch -=============== -*/ -void R_NewGame (void) -{ - int i; - - //clear playertexture pointers (the textures themselves were freed by texmgr_newgame) - for (i=0; iflags & TEXPREF_COLOURMAPPED) + TexMgr_ColormapTexture_Free(kill); + if (active_gltextures == kill) { active_gltextures = kill->next; @@ -552,6 +555,8 @@ void TexMgr_DeleteTextureObjects (void) { gltexture_t *glt; + TexMgr_ColormapTexture_Free(NULL); + for (glt = active_gltextures; glt; glt = glt->next) { GL_DeleteTexture (glt); @@ -654,6 +659,8 @@ TexMgr_NewGame */ void TexMgr_NewGame (void) { + TexMgr_ColormapTexture_Free(NULL); + TexMgr_FreeTextures (0, TEXPREF_PERSIST); //deletes all textures where TEXPREF_PERSIST is unset TexMgr_LoadPalette (); } @@ -1409,7 +1416,7 @@ static void TexMgr_LoadImage8 (gltexture_t *glt, byte *data) } else if (glt->pants.type == 1) { - pants = glt->pants.rgb[0] * 16; + pants = glt->pants.basic * 16; if (pants < 128) { for (i = 0; i < 16; i++) @@ -1693,6 +1700,8 @@ void TexMgr_ReloadImages (void) // switching to a boolean flag. in_reload_images = true; + TexMgr_ColormapTexture_Free(NULL); //just flush colourmapped cache instead of reloading them all unecessarily. + for (glt = active_gltextures; glt; glt = glt->next) { glGenTextures(1, &glt->texnum); @@ -1716,6 +1725,104 @@ void TexMgr_ReloadNobrightImages (void) TexMgr_ReloadImage(glt, plcolour_none, plcolour_none); } + +static struct +{ + struct gltexture_s *basetex; + struct gltexture_s *coloured; + plcolour_t upper; + plcolour_t lower; + double usetime; +} colourmappedtexture[MAX_SCOREBOARD*2]; +static size_t numcolourmappedtextures; +static void TexMgr_ColormapTexture_Free(struct gltexture_s *basetex) +{ + int i; + if (basetex) + { //kill a single one. + basetex->flags &= ~TEXPREF_COLOURMAPPED; + + for (i = 0; i < numcolourmappedtextures; i++) + { + if (colourmappedtexture[i].basetex == basetex) + { + TexMgr_FreeTexture(colourmappedtexture[i].coloured); + colourmappedtexture[i].basetex = NULL; + colourmappedtexture[i].usetime = 0; + colourmappedtexture[i].coloured = NULL; + //may be multiple combinations of the same texture. + } + } + } + else + { //kill em all + for (i = 0; i < numcolourmappedtextures; i++) + { + if (colourmappedtexture[i].coloured) + TexMgr_FreeTexture(colourmappedtexture[i].coloured); + colourmappedtexture[i].coloured = NULL; + } + numcolourmappedtextures = 0; + } +} +struct gltexture_s *TexMgr_ColormapTexture(struct gltexture_s *basetex, plcolour_t lower, plcolour_t upper) +{ + int oldest; + float otime; + int i; + struct gltexture_s *glt; + for (i = 0; i < countof(colourmappedtexture); i++) + { + if (colourmappedtexture[i].basetex == basetex && colourmappedtexture[i].upper.key == upper.key && colourmappedtexture[i].lower.key == lower.key) + { + colourmappedtexture[i].usetime = realtime; + return colourmappedtexture[i].coloured; + } + } + if (numcolourmappedtextures < countof(colourmappedtexture)) + oldest = numcolourmappedtextures++; //just use a new one + else + { + otime = colourmappedtexture[oldest=0].usetime; + for (i = 1; i < countof(colourmappedtexture); i++) + { + if (otime > colourmappedtexture[i].usetime) + otime = colourmappedtexture[oldest=i].usetime; + } + } + if (colourmappedtexture[oldest].coloured) + TexMgr_FreeTexture(colourmappedtexture[oldest].coloured); //was previously used... + + colourmappedtexture[oldest].basetex = basetex; + colourmappedtexture[oldest].upper = upper; + colourmappedtexture[oldest].lower = lower; + + //create the new texture from the existing one + colourmappedtexture[oldest].coloured = glt = TexMgr_NewTexture (); + glt->owner = NULL; //don't get clobbered by mistake + q_strlcpy (glt->name, basetex->name, sizeof(glt->name)); + glt->width = basetex->width; + glt->height = basetex->height; + glt->flags = basetex->flags|TEXPREF_OVERWRITE; + glt->shirt = upper; + glt->pants = lower; + q_strlcpy (glt->source_file, basetex->source_file, sizeof(glt->source_file)); + glt->source_offset = basetex->source_offset; + glt->source_format = basetex->source_format; + glt->source_width = basetex->source_width; + glt->source_height = basetex->source_height; + glt->source_crc = basetex->source_crc+1; //something wrong so we don't get found so easily... + + //and now reload it so it gets the proper colours. + TexMgr_ReloadImage(glt, upper, lower); + + basetex->flags |= TEXPREF_COLOURMAPPED; //so we clean up other textures spawned from it too. + + colourmappedtexture[oldest].usetime = realtime; + return colourmappedtexture[oldest].coloured; +} + + /* ================================================================================ @@ -1724,7 +1831,7 @@ void TexMgr_ReloadNobrightImages (void) ================================================================================ */ -static GLuint currenttexture[3] = {GL_UNUSED_TEXTURE, GL_UNUSED_TEXTURE, GL_UNUSED_TEXTURE}; // to avoid unnecessary texture sets +static GLuint currenttexture[4] = {GL_UNUSED_TEXTURE, GL_UNUSED_TEXTURE, GL_UNUSED_TEXTURE, GL_UNUSED_TEXTURE}; // to avoid unnecessary texture sets static GLenum currenttarget = GL_TEXTURE0_ARB; qboolean mtexenabled = false; diff --git a/Quake/gl_texmgr.h b/Quake/gl_texmgr.h index 179eb222..e339d61e 100644 --- a/Quake/gl_texmgr.h +++ b/Quake/gl_texmgr.h @@ -40,6 +40,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define TEXPREF_WARPIMAGE 0x0800 // resize this texture when warpimagesize changes #define TEXPREF_PREMULTIPLY 0x1000 // rgb = rgb*a; a=a; #define TEXPREF_ALLOWMISSING 0x2000 // TexMgr_LoadImage should return NULL if anything goes wrong (for use with SRC_EXTERNAL). +#define TEXPREF_COLOURMAPPED 0x4000 // internal - this texture has at least one recoloured variant that needs cleaning up on destruction. enum srcformat {SRC_INDEXED, SRC_LIGHTMAP, SRC_RGBA, SRC_EXTERNAL, SRC_FIRSTCOMPRESSED}; extern qboolean gl_texture_s3tc, gl_texture_rgtc, gl_texture_bptc, gl_texture_etc2, gl_texture_astc, gl_texture_e5bgr9; @@ -75,8 +76,6 @@ extern unsigned int d_8to24table[256]; extern unsigned int d_8to24table_fbright[256]; extern unsigned int d_8to24table_nobright[256]; extern unsigned int d_8to24table_conchars[256]; -extern unsigned int d_8to24table_shirt[256]; -extern unsigned int d_8to24table_pants[256]; // TEXTURE MANAGER @@ -98,6 +97,7 @@ void TexMgr_BlockSize (enum srcformat format, int *bytes, int *width, int *heigh // IMAGE LOADING gltexture_t *TexMgr_LoadImage (qmodel_t *owner, const char *name, int width, int height, enum srcformat format, byte *data, const char *source_file, src_offset_t source_offset, unsigned flags); +struct gltexture_s *TexMgr_ColormapTexture(struct gltexture_s *basetex, plcolour_t lower, plcolour_t upper); void TexMgr_ReloadImage (gltexture_t *glt, plcolour_t shirt, plcolour_t pants); void TexMgr_ReloadImages (void); void TexMgr_ReloadNobrightImages (void); diff --git a/Quake/menu.c b/Quake/menu.c index e19bb59f..f9e22015 100644 --- a/Quake/menu.c +++ b/Quake/menu.c @@ -662,9 +662,82 @@ static plcolour_t setup_oldtop; static plcolour_t setup_oldbottom; static plcolour_t setup_top; static plcolour_t setup_bottom; +extern qboolean keydown[]; + + +//http://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c +static void rgbtohsv(byte *rgb, vec3_t result) +{ //helper for the setup menu + int r = rgb[0], g = rgb[1], b = rgb[2]; + float maxc = q_max(r, q_max(g, b)), minc = q_min(r, q_min(g, b)); + float h, s, l = (maxc + minc) / 2; + + float d = maxc - minc; + if (maxc) + s = d / maxc; + else + s = 0; + + if(maxc == minc) + { + h = 0; // achromatic + } + else + { + if (maxc == r) + h = (g - b) / d + ((g < b) ? 6 : 0); + else if (maxc == g) + h = (b - r) / d + 2; + else + h = (r - g) / d + 4; + h /= 6; + } + + result[0] = h; + result[1] = s; + result[2] = l; +}; +//http://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c +static void hsvtorgb(float inh, float s, float v, byte *out) +{ //helper for the setup menu + int r, g, b; + float h = inh - (int)floor(inh); + int i = h * 6; + float f = h * 6 - i; + float p = v * (1 - s); + float q = v * (1 - f * s); + float t = v * (1 - (1 - f) * s); + switch(i) + { + default: + case 0: r = v*0xff, g = t*0xff, b = p*0xff; break; + case 1: r = q*0xff, g = v*0xff, b = p*0xff; break; + case 2: r = p*0xff, g = v*0xff, b = t*0xff; break; + case 3: r = p*0xff, g = q*0xff, b = v*0xff; break; + case 4: r = t*0xff, g = p*0xff, b = v*0xff; break; + case 5: r = v*0xff, g = p*0xff, b = q*0xff; break; + } + + out[0] = r; + out[1] = g; + out[2] = b; +}; void M_AdjustColour(plcolour_t *tr, int dir) { + if (keydown[K_SHIFT]) + { + vec3_t hsv; + rgbtohsv(CL_PLColours_ToRGB(tr), hsv); + + hsv[0] += dir/128.0; + hsv[1] = 1; + hsv[2] = 1; //make these consistent and not inherited from any legacy colours. we're persisting in rgb with small hue changes so we can't actually handle greys, so whack the saturation and brightness right up. + tr->type = 2; //rgb... + tr->basic = 0; //no longer relevant. + hsvtorgb(hsv[0], hsv[1], hsv[2], tr->rgb); + } + else { tr->type = 1; if (tr->basic+dir < 0) diff --git a/Quake/protocol.h b/Quake/protocol.h index 8cc98206..84267640 100644 --- a/Quake/protocol.h +++ b/Quake/protocol.h @@ -482,6 +482,7 @@ typedef struct entity_state_s unsigned short tagentity; unsigned short pad; unsigned char colormod[3]; //spike -- entity tints, *32 + unsigned char glowmod[3]; //spike -- entity tints, *32 unsigned char alpha; //johnfitz -- added unsigned int solidsize; //for csqc prediction logic. #define ES_SOLID_NOT 0 diff --git a/Quake/r_alias.c b/Quake/r_alias.c index 610d2488..b5749659 100644 --- a/Quake/r_alias.c +++ b/Quake/r_alias.c @@ -27,9 +27,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. extern cvar_t r_drawflat, gl_overbright_models, gl_fullbrights, r_lerpmodels, r_lerpmove; //johnfitz extern cvar_t scr_fov, cl_gun_fovscale; -//up to 16 color translated skins -gltexture_t *playertextures[MAX_SCOREBOARD]; //johnfitz -- changed to an array of pointers - #define NUMVERTEXNORMALS 162 float r_avertexnormals[NUMVERTEXNORMALS][3] = @@ -88,10 +85,13 @@ typedef struct // uniforms used in frag shader GLuint texLoc; + GLuint lowerTexLoc; + GLuint upperTexLoc; GLuint fullbrightTexLoc; GLuint useFullbrightTexLoc; GLuint useOverbrightLoc; GLuint useAlphaTestLoc; + GLuint colorTintLoc; } aliasglsl_t; static aliasglsl_t r_alias_glsl[ALIAS_GLSL_MODES]; @@ -241,23 +241,28 @@ void GLAlias_CreateShaders (void) "#version 110\n" "\n" "uniform sampler2D Tex;\n" + "uniform sampler2D LowerTex;\n" //team colour + "uniform sampler2D UpperTex;\n" //personal colour "uniform sampler2D FullbrightTex;\n" "uniform bool UseFullbrightTex;\n" "uniform bool UseOverbright;\n" "uniform bool UseAlphaTest;\n" + "uniform vec4 ColourTint[3];\n" //base+bot+top+fb "\n" "varying float FogFragCoord;\n" "\n" "void main()\n" "{\n" - " vec4 result = texture2D(Tex, gl_TexCoord[0].xy);\n" + " vec4 result = texture2D(Tex, gl_TexCoord[0].xy);\n" //base + " if (ColourTint[0].a != 0.0) result.rgb += texture2D(LowerTex, gl_TexCoord[0].xy).rgb * ColourTint[0].rgb;\n" //team/lower/trousers + " if (ColourTint[1].a != 0.0) result.rgb += texture2D(UpperTex, gl_TexCoord[0].xy).rgb * ColourTint[1].rgb;\n" //personal/upper/torso " if (UseAlphaTest && (result.a < 0.666))\n" " discard;\n" - " result *= gl_Color;\n" + " result *= gl_Color;\n" //vertex lighting results (and colormod). " if (UseOverbright)\n" " result.rgb *= 2.0;\n" " if (UseFullbrightTex)\n" - " result += texture2D(FullbrightTex, gl_TexCoord[0].xy);\n" + " result += texture2D(FullbrightTex, gl_TexCoord[0].xy) * ColourTint[2];\n" //fullbrights (with glowmod) " result = clamp(result, 0.0, 1.0);\n" " float fog = exp(-gl_Fog.density * gl_Fog.density * FogFragCoord * FogFragCoord);\n" " fog = clamp(fog, 0.0, 1.0) * gl_Fog.color.a;\n" @@ -303,10 +308,21 @@ void GLAlias_CreateShaders (void) glsl->shadevectorLoc = GL_GetUniformLocation (&glsl->program, "ShadeVector"); glsl->lightColorLoc = GL_GetUniformLocation (&glsl->program, "LightColor"); glsl->texLoc = GL_GetUniformLocation (&glsl->program, "Tex"); + glsl->lowerTexLoc = GL_GetUniformLocation (&glsl->program, "LowerTex"); + glsl->upperTexLoc = GL_GetUniformLocation (&glsl->program, "UpperTex"); glsl->fullbrightTexLoc = GL_GetUniformLocation (&glsl->program, "FullbrightTex"); glsl->useFullbrightTexLoc = GL_GetUniformLocation (&glsl->program, "UseFullbrightTex"); glsl->useOverbrightLoc = GL_GetUniformLocation (&glsl->program, "UseOverbright"); glsl->useAlphaTestLoc = GL_GetUniformLocation (&glsl->program, "UseAlphaTest"); + glsl->colorTintLoc = GL_GetUniformLocation (&glsl->program, "ColourTint"); + + //we can do this here, its not going to change. + GL_UseProgramFunc (glsl->program); + GL_Uniform1iFunc (glsl->texLoc, 0); + GL_Uniform1iFunc (glsl->fullbrightTexLoc, 1); + GL_Uniform1iFunc (glsl->lowerTexLoc, 2); + GL_Uniform1iFunc (glsl->upperTexLoc, 3); + GL_UseProgramFunc (0); } } } @@ -325,8 +341,9 @@ Supports optional overbright, optional fullbright pixels. Based on code by MH from RMQEngine ============= */ -void GL_DrawAliasFrame_GLSL (aliasglsl_t *glsl, aliashdr_t *paliashdr, lerpdata_t lerpdata, gltexture_t *tx, gltexture_t *fb) +static void GL_DrawAliasFrame_GLSL (aliasglsl_t *glsl, aliashdr_t *paliashdr, lerpdata_t lerpdata, struct skintextures_s tex, entity_t *e) { + GLfloat tints[3][4]; float blend; if (lerpdata.pose1 != lerpdata.pose2) @@ -394,28 +411,65 @@ void GL_DrawAliasFrame_GLSL (aliasglsl_t *glsl, aliashdr_t *paliashdr, lerpdata_ break; } +#define MyVectorScale(a,s,b) do{(b)[0]=(s)*(a)[0];(b)[1]=(s)*(a)[1];(b)[2]=(s)*(a)[2];}while(0) + if (e->netstate.colormap > 0 && e->netstate.colormap <= cl.maxclients) + { + scoreboard_t *sb = &cl.scores[e->netstate.colormap-1]; + byte *pal; + pal = CL_PLColours_ToRGB(&sb->pants); + MyVectorScale(pal, 1.0/255, tints[0]); + + pal = CL_PLColours_ToRGB(&sb->shirt); + MyVectorScale(pal, 1.0/255, tints[1]); + } + else + { + MyVectorScale((byte*)&d_8to24table[BOTTOM_RANGE+15], 1.0/255, tints[0]); + MyVectorScale((byte*)&d_8to24table[TOP_RANGE+15], 1.0/255, tints[1]); + } + tints[0][3] = 1; + tints[1][3] = 1; + MyVectorScale(e->netstate.glowmod, 1.0/32, tints[2]); tints[2][3] = 1; + + // set textures + GL_SelectTexture (GL_TEXTURE0); + GL_Bind (tex.base); + + if (tex.luma) + { + GL_SelectTexture (GL_TEXTURE1); + GL_Bind (tex.luma); + } + else + tints[2][0] = tints[2][1] = tints[2][2] = tints[2][3] = 0; + + if (tex.lower) + { + GL_SelectTexture (GL_TEXTURE2); + GL_Bind (tex.lower); + } + else + tints[0][0] = tints[0][1] = tints[0][2] = tints[0][3] = 0; //ask the glsl to not read it + + if (tex.upper) + { + GL_SelectTexture (GL_TEXTURE3); + GL_Bind (tex.upper); + } + else + tints[1][0] = tints[1][1] = tints[1][2] = tints[1][3] = 0; + // set uniforms if (glsl->blendLoc != -1) GL_Uniform1fFunc (glsl->blendLoc, blend); if (glsl->bonesLoc != -1) GL_Uniform4fvFunc (glsl->bonesLoc, paliashdr->numbones*3, lerpdata.bonestate->mat); GL_Uniform3fFunc (glsl->shadevectorLoc, shadevector[0], shadevector[1], shadevector[2]); - GL_Uniform4fFunc (glsl->lightColorLoc, lightcolor[0], lightcolor[1], lightcolor[2], entalpha); - GL_Uniform1iFunc (glsl->texLoc, 0); - GL_Uniform1iFunc (glsl->fullbrightTexLoc, 1); - GL_Uniform1iFunc (glsl->useFullbrightTexLoc, (fb != NULL) ? 1 : 0); + GL_Uniform4fFunc (glsl->lightColorLoc, lightcolor[0], lightcolor[1], lightcolor[2], entalpha); //this includes colormod + GL_Uniform1iFunc (glsl->useFullbrightTexLoc, (tex.luma != NULL) ? 1 : 0); GL_Uniform1fFunc (glsl->useOverbrightLoc, overbright ? 1 : 0); GL_Uniform1iFunc (glsl->useAlphaTestLoc, (currententity->model->flags & MF_HOLEY) ? 1 : 0); - -// set textures - GL_SelectTexture (GL_TEXTURE0); - GL_Bind (tx); - - if (fb) - { - GL_SelectTexture (GL_TEXTURE1); - GL_Bind (fb); - } + GL_Uniform4fvFunc(glsl->colorTintLoc, countof(tints), tints[0]); //colourmapping and glowmod. // draw glDrawElements (GL_TRIANGLES, paliashdr->numindexes, GL_UNSIGNED_SHORT, currententity->model->meshindexesvboptr+paliashdr->eboofs); @@ -1054,7 +1108,7 @@ void R_DrawAliasModel (entity_t *e) aliasglsl_t *glsl; aliashdr_t *paliashdr; int anim, skinnum; - gltexture_t *tx, *fb; + struct skintextures_s tex; lerpdata_t lerpdata; qboolean alphatest = !!(e->model->flags & MF_HOLEY); int surf; @@ -1152,21 +1206,39 @@ void R_DrawAliasModel (entity_t *e) } if (paliashdr->numskins <= 0) { - tx = NULL; // NULL will give the checkerboard texture - fb = NULL; + tex.base = tex.luma = tex.lower = tex.upper = NULL; // NULL will give the checkerboard texture } else + tex = paliashdr->textures[skinnum][anim]; + if (!gl_nocolors.value) { - tx = paliashdr->gltextures[skinnum][anim]; - fb = paliashdr->fbtextures[skinnum][anim]; - } - if (e->netstate.colormap && !gl_nocolors.value) - { - if ((uintptr_t)e >= (uintptr_t)&cl.entities[1] && (uintptr_t)e <= (uintptr_t)&cl.entities[cl.maxclients]) /* && !strcmp (currententity->model->name, "progs/player.mdl") */ - tx = playertextures[e - cl.entities - 1]; + if (e->eflags & EFLAGS_COLOURMAPPED) + { //support for dp's self.colormap = 4096 | top*16 | bottom; thing (solves corpses changing colours, can't handle rich colours though) + if (tex.base && tex.base->source_format == SRC_INDEXED && !tex.upper && !tex.lower) + { + struct gltexture_s *t = TexMgr_ColormapTexture(tex.base, CL_PLColours_FromLegacy(e->netstate.colormap&15), CL_PLColours_FromLegacy(e->netstate.colormap>>4)); + if (t) + tex.base = t; + } + } + else if (e->netstate.colormap>=1&&e->netstate.colormap<=cl.maxclients) + { //despite being able to handle _shirt+_pants textures in our glsl, we still prefer to generate per-player textures. + //1) works with non-glsl. + //2) preserves the weird non-linear ranges. + //3) ... and without breaking those ranges on models that are NOT colourmapped (the lower's remapped range is the worst of the non-linear ranges, so would make too many models ugly). + //so we only use the shirt+pans stuff when using external textures + //on the plus side, we do use a lookup so we don't break quakerally. csqc also benefits from not needing to worry about edict numbers. + if (tex.base && tex.base->source_format == SRC_INDEXED && !tex.upper && !tex.lower) + { + scoreboard_t *sb = &cl.scores[e->netstate.colormap-1]; + struct gltexture_s *t = TexMgr_ColormapTexture(tex.base, sb->pants, sb->shirt); + if (t) + tex.base = t; + } + } } if (!gl_fullbrights.value) - fb = NULL; + tex.luma = NULL; // // draw it @@ -1180,14 +1252,14 @@ void R_DrawAliasModel (entity_t *e) } else if (r_fullbright_cheatsafe) { - GL_Bind (tx); + GL_Bind (tex.base); shading = false; glColor4f(1,1,1,entalpha); GL_DrawAliasFrame (paliashdr, lerpdata); - if (fb) + if (tex.luma) { glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - GL_Bind(fb); + GL_Bind(tex.luma); glEnable(GL_BLEND); glBlendFunc (GL_ONE, GL_ONE); glDepthMask(GL_FALSE); @@ -1212,20 +1284,20 @@ void R_DrawAliasModel (entity_t *e) // r_alias_program will be 0. else if (glsl->program != 0 && (paliashdr->numbones <= glsl->maxbones||!lerpdata.bonestate)) { - GL_DrawAliasFrame_GLSL (glsl, paliashdr, lerpdata, tx, fb); + GL_DrawAliasFrame_GLSL (glsl, paliashdr, lerpdata, tex, e); } else if (overbright) { - if (gl_texture_env_combine && gl_mtexable && gl_texture_env_add && fb) //case 1: everything in one pass + if (gl_texture_env_combine && gl_mtexable && gl_texture_env_add && tex.luma) //case 1: everything in one pass { - GL_Bind (tx); + GL_Bind (tex.base); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT); glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 2.0f); GL_EnableMultitexture(); // selects TEXTURE1 - GL_Bind (fb); + GL_Bind (tex.luma); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD); // glEnable(GL_BLEND); GL_DrawAliasFrame (paliashdr, lerpdata); @@ -1236,7 +1308,7 @@ void R_DrawAliasModel (entity_t *e) else if (gl_texture_env_combine) //case 2: overbright in one pass, then fullbright pass { // first pass - GL_Bind(tx); + GL_Bind(tex.base); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); @@ -1246,10 +1318,10 @@ void R_DrawAliasModel (entity_t *e) glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 1.0f); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); // second pass - if (fb) + if (tex.luma) { glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - GL_Bind(fb); + GL_Bind(tex.luma); glEnable(GL_BLEND); glBlendFunc (GL_ONE, GL_ONE); glDepthMask(GL_FALSE); @@ -1267,7 +1339,7 @@ void R_DrawAliasModel (entity_t *e) else //case 3: overbright in two passes, then fullbright pass { // first pass - GL_Bind(tx); + GL_Bind(tex.base); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); GL_DrawAliasFrame (paliashdr, lerpdata); // second pass -- additive with black fog, to double the object colors but not the fog color @@ -1282,10 +1354,10 @@ void R_DrawAliasModel (entity_t *e) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_BLEND); // third pass - if (fb) + if (tex.luma) { glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - GL_Bind(fb); + GL_Bind(tex.luma); glEnable(GL_BLEND); glBlendFunc (GL_ONE, GL_ONE); glDepthMask(GL_FALSE); @@ -1303,13 +1375,13 @@ void R_DrawAliasModel (entity_t *e) } else { - if (gl_mtexable && gl_texture_env_add && fb) //case 4: fullbright mask using multitexture + if (gl_mtexable && gl_texture_env_add && tex.luma) //case 4: fullbright mask using multitexture { GL_DisableMultitexture(); // selects TEXTURE0 - GL_Bind (tx); + GL_Bind (tex.base); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); GL_EnableMultitexture(); // selects TEXTURE1 - GL_Bind (fb); + GL_Bind (tex.luma); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD); glEnable(GL_BLEND); GL_DrawAliasFrame (paliashdr, lerpdata); @@ -1320,13 +1392,13 @@ void R_DrawAliasModel (entity_t *e) else //case 5: fullbright mask without multitexture { // first pass - GL_Bind(tx); + GL_Bind(tex.base); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); GL_DrawAliasFrame (paliashdr, lerpdata); // second pass - if (fb) + if (tex.luma) { - GL_Bind(fb); + GL_Bind(tex.luma); glEnable(GL_BLEND); glBlendFunc (GL_ONE, GL_ONE); glDepthMask(GL_FALSE);