Rework colormap stuff so that quakerally/tf/etc work, fixing related csqc deficiency. Also support _shirt and _pants textures for people using 24bit textures.

This commit is contained in:
Shpoike 2023-07-07 10:57:40 +01:00
parent d7e86a6592
commit c52a165ca5
14 changed files with 432 additions and 251 deletions

View File

@ -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));

View File

@ -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);
}
/*

View File

@ -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;

View File

@ -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)))

View File

@ -517,7 +517,6 @@ qboolean Draw_ReloadTextures(qboolean force)
{
TexMgr_NewGame ();
Draw_NewGame ();
R_NewGame ();
Cache_Flush ();

View File

@ -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();

View File

@ -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];
}
}

View File

@ -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;

View File

@ -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; i<MAX_SCOREBOARD; i++)
playertextures[i] = NULL;
}
/*
=============
R_ParseWorldspawn

View File

@ -45,8 +45,8 @@ unsigned int d_8to24table_fbright_fence[256];
unsigned int d_8to24table_nobright[256];
unsigned int d_8to24table_nobright_fence[256];
unsigned int d_8to24table_conchars[256];
unsigned int d_8to24table_shirt[256];
unsigned int d_8to24table_pants[256];
static void TexMgr_ColormapTexture_Free(struct gltexture_s *basetex);
static struct
{
@ -479,6 +479,9 @@ void TexMgr_FreeTexture (gltexture_t *kill)
return;
}
if (kill->flags & 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;

View File

@ -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);

View File

@ -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)

View File

@ -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

View File

@ -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);