Page 1 of 2
NQ Colored Dead Bodies
Posted: Fri Jul 13, 2012 9:51 am
by Baker
Before I saw the RMQ engine stuff, all that vid.colormap and hostbasepal and VID_GRADES and translations all over the place was confusing as hell. And I guess if I had thought about it real hard, I shouldn't have been confused but I didn't understand what the heck the colormap exactly was sending over.
But that's the past now.
I can say this inherited GLQuake code does not work:
Code: Select all
if (bits & U_COLORMAP)
i = MSG_ReadByte();
else
i = ent->baseline.colormap;
if (!i)
ent->colormap = 0;
else
{
if (i > cl.maxclients)
Sys_Error ("i >= cl.maxclients");
ent->colormap = i; /* //cl.scores[i-1].translations; Baker: WinQuake only */
}
if (bits & U_SKIN)
skin = MSG_ReadByte();
else
skin = ent->baseline.skin;
if (skin != ent->skinnum) {
ent->skinnum = skin;
#ifdef SUPPORTS_COLORED_DEAD_BODIES // Baker change
if (ent->colormap > 0 && ent->colormap <= cl.maxclients)
R_TranslateNewPlayerSkin (ent->colormap - 1); //johnfitz -- was R_TranslatePlayerSkin
#else // Baker change +
if (num > 0 && num <= cl.maxclients)
R_TranslateNewPlayerSkin (num - 1); //johnfitz -- was R_TranslatePlayerSkin
#endif // Baker change -
}
It only translates when the skin is different than the "existing" skin number. Sometimes the existing number is zero and the new one is of course 0 too, but not always. But some deadbodies don't get colored.
This isn't the way to do it anyway, I think I'll make a nice little models/skin #/pants/shirt table and a block of 200 textures or so. I'm using the FitzQuake hacky method of not color mapping some stuff ....
Code: Select all
cvar_t r_nocolormap_list = {"r_nocolormap_list", "progs/eyes.mdl,progs/h_player.mdl,progs/gib1.mdl,progs/gib2.mdl,progs/gib3.mdl"};
...
//At level load --->
if (COM_ListMatch (r_nocolormap_list.string, mod->name) == true)
mod->flags |= MOD_NOCOLORMAP;
Combined with the above, I imagine like a whole 4-5 entries will actually get used (red vs. blue ... really?) or at times like 1 (single player).
I'm half wondering if the existing GLQuakeish code isn't uploading stuff all the time with skin translations it doesn't need to be doing because nothing changed. CL_Parse is written a bit crappily.
Re: NQ Colored Dead Bodies
Posted: Fri Jul 13, 2012 11:13 am
by taniwha
If I remember correctly, the original GL skin code sucked donkey's balls. It was incorrect (as you've stated), and, I believe, uploading every frame. The custom skin code in QW was a train-wreck of potential buffer overflows. Dead bodies did not work reliably. I put a
lot of effort into getting it "right" in QF back in 2000, with a few rewrites since.
I can say that, while "ugly" (tastes will vary), using color maps sure was nice for QF's current GLSL implementation

Re: NQ Colored Dead Bodies
Posted: Sat Jul 14, 2012 6:58 pm
by r00k
Hmm, been a while but, i thought that deadbodies having no color was just a .qc bug. I know you can fix this via quakec... but its been awhile ill have to backtrack this comment

Other than that I thought .colormap was just the player number (like in the output of the status command), which always confused me.

Re: NQ Colored Dead Bodies
Posted: Sat Jul 14, 2012 7:23 pm
by Baker
r00k wrote:Hmm, been a while but, i thought that deadbodies having no color was just a .qc bug. I know you can fix this via quakec... but its been awhile ill have to backtrack this comment

Other than that I thought .colormap was just the player number (like in the output of the status command), which always confused me.

GLQuake allocates 16 player texture slots for coloring and does color on if 1 <= entity <= cl.maxclients
Load up wqpro (WinQuake version of ProQuake to someone who doesn't know what wqpro is) and watch a couple of minutes of a game --- the dead bodies are colored, so this is all client-side.
There was some QuakeC hack out there that could cause a few of the deadbodies to be colored in GLQuake with some trick like having the dead bodies entities use empty player slots. So if there were 12 players, a few of the dead bodies would be in slots 13-16. But that was so much of a hack.
Re: NQ Colored Dead Bodies
Posted: Sat Jul 14, 2012 8:25 pm
by Spike
its purely an engine issue.
if mods are in any way buggy its that they leave it active even on eyes, and heads.
quakeworld detects the player model specifically and colourmaps the player's skin image as a replacement texture for all player.mdls, breaking .skin etc.
TF uses colourmaps on lots of things, including with skingroups, software quakeworld supports colourmaps AND player skins.
Re: NQ Colored Dead Bodies
Posted: Sat Jul 14, 2012 8:42 pm
by Baker
Spike wrote:TF uses colourmaps on lots of things, including with skingroups, software quakeworld supports colourmaps AND player skins.
Turrets and such, I bet so you know if it is a friendly turret or an enemy turret.
Also isn't there a spy, and that player's colormap shouldn't use his pants/shirt color? So an engine coloring on pants/shirt and not off what the server sends is improper, correct?
Re: NQ Colored Dead Bodies
Posted: Sat Jul 14, 2012 9:23 pm
by Spike
server sends stuffcmds to change player colours. spies mess up the scoreboard too, but then quakeworld also has a 'team' userinfo key for damage stuff.
Re: NQ Colored Dead Bodies
Posted: Sun Jul 15, 2012 3:55 am
by r00k
Oddly I modified a player mOdel once that had the player carrying a back pack, though i swear that when that player droPped a pack it was colored the same as the Player(I used that pants cOlor in the objects skin) I'm not home ATM so I can't check this... But this might lead to a cheat on some mods :/
Re: NQ Colored Dead Bodies
Posted: Sun Jul 15, 2012 4:56 am
by Spike
if the mod sets .colormap on the dropped backpack then yes. but that's the same whether its vanilla winquake or a 'bugfixed' glquake port.
it might be a cheat, but its a bug when you consider that there's no way to disable it when using a winquake engine (other than fixing the bug), thus doesn't really factor in to any motivation to not fix it.
Re: NQ Colored Dead Bodies
Posted: Sun Jul 15, 2012 5:28 am
by r00k
Nah maybe im mistaken i cant find the model;its possible i was mistaken that the actual dropped pack was colored...
Sorry Baker not to derail this thread...
Re: NQ Colored Dead Bodies
Posted: Thu Jul 19, 2012 11:37 am
by Baker
Approaching done ... looks like this. I plan to call R_TranslateNewModelSkinColormap for any entity without an existing texture assigned --- or if skin/model/colormap or the player scoreboard colors change for that colormap --- in ... well ... at the end of CL_Parse for now.
Why CL_Parse? That is where it happens now. The "alternative" is to wait until after fov and frustum are setup and only even bother if the ent is going to be visible.
Code: Select all
/*
===============
R_TranslateNewModelSkinColormap
Looks through our table and returns an existing model/skin/pants/shirt combination already uploaded.
If does not exist. Uploads it.
Since this re-uses colormapped skins (2 red players = same texture) this will upload fewer skins
than the GLQuake way, but will colormap everything.
r_nocolormap_list provides a means to exclude colormapping trivial things like gibs. Although it
supports 1024 combinations, it will rarely use more than 10 to 30 in practice. All skins are
deleted on a new map.
===============
*/
cvar_t r_nocolormap_list = {"r_nocolormap_list", "progs/eyes.mdl,progs/h_player.mdl,progs/gib1.mdl,progs/gib2.mdl,progs/gib3.mdl"};
gltexture_t *R_TranslateNewModelSkinColormap (entity_t *cur_ent)
{
int entity_number = cur_ent - cl_entities; // If player, this will be 1-16
int shirt_color, pants_color, skinnum, matchingslot;
aliashdr_t *paliashdr;
do // REJECTIONS PHASE
{
// No model or it isn't an alias model
if (!cur_ent->model || cur_ent->model->type != mod_alias)
return NULL;
if (cur_ent->colormap <= 0 || cur_ent->colormap > cl.maxclients)
return NULL;
// Certain models just aren't worth trying to colormap
if (cur_ent->model->flags & MOD_NOCOLORMAP)
return NULL;
//TODO: move these tests to the place where skinnum gets received from the server
paliashdr = (aliashdr_t *)Mod_Extradata (currententity->model);
skinnum = cur_ent->skinnum;
if (skinnum < 0 || skinnum >= paliashdr->numskins)
{
Con_DPrintf("(%d): Invalid player skin #%d\n", entity_number, skinnum);
skinnum = 0;
}
} while (0);
do // SEE IF WE HAVE SKIN + MODEL + COLOR ALREADY PHASE
{
int playerslot = cur_ent->colormap - 1;
shirt_color = (cl.scores[playerslot].colors & 0xf0) >> 4;
pants_color = cl.scores[playerslot].colors & 15;
for (matchingslot = 0; matchingslot < MAX_COLORMAP_SKINS; matchingslot ++)
{
gltexture_t *curtex = playertextures[matchingslot];
if (curtex->shirt != shirt_color) continue;
if (curtex->pants != pants_color) continue;
if (curtex->skinnum != skinnum) continue;
if (curtex->owner != cur_ent->model) continue;
// Found an existing translation for this
return curtex;
}
if (matchingslot == MAX_COLORMAP_SKINS)
{
Host_Error ("Color Slots Full");
return NULL;
}
// If we are here matchingslot is our new texture slot
} while (0);
do // UPLOAD THE NEW SKIN + MODEL PHASE (BUT WE AREN'T COLORING)
{
aliashdr_t *paliashdr = (aliashdr_t *)Mod_Extradata (currententity->model);
byte *pixels = (byte *)paliashdr + paliashdr->texels[skinnum]; // This is not a persistent place!
char name[64];
sprintf(name, "player_%i", entity_number);
//upload new image
playertextures[matchingslot] = TexMgr_LoadImage (cur_ent->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);
//FIXME: if gl_nocolors is on, then turned off, the textures may be out of sync with the scoreboard colors.
// Color it now ...
if (!gl_nocolors.value && playertextures[matchingslot])
TexMgr_ReloadImage (playertextures[matchingslot], shirt_color, pants_color);
} while (0);
return playertextures[matchingslot];
}
Re: NQ Colored Dead Bodies
Posted: Thu Jul 19, 2012 6:05 pm
by r00k
I'm looking at the code from the svc_updatecolors point of view then tracking it backwards. Since i use custom skins that are colored, any translations are just for the old pallete method.
If the mod sets a corpse's .colormap to the player's colormap why cant CL_NewTranslation be called when we relink the entites? I have to unravel this idea its been a few years since i looked at the player color code.
Re: NQ Colored Dead Bodies
Posted: Thu Jul 19, 2012 10:25 pm
by Baker
Final code:
Addresses every stupid situation possible including mods with skin changes (and invalid skin numbers), player model becoming a brush model, etc. Does very few coloring translations in multiplayer, particularly team games because there is no longer 1 skin per player, but players of the same color, model and skin use the same texture.
Everything is colored mapped. Not just dead bodies.
Code: Select all
//Alias Model ...
//
// set up textures
//
GL_DisableMultitexture();
anim = (int)(cl.time*10) & 3;
tx = paliashdr->gltextures[e->skinnum][anim];
fb = paliashdr->fbtextures[e->skinnum][anim];
if (e->colormap && !gl_nocolors.value && e->coloredskin)
tx = e->coloredskin;
if (!gl_fullbrights.value)
fb = NULL;
Code: Select all
// At end CL_RelinkEntities ...
if (cl_numvisedicts < MAX_VISEDICTS)
{
cl_visedicts[cl_numvisedicts] = ent;
cl_numvisedicts++;
if (ent->coloredskin == NULL)
{
// Models with no skin always need to be re-evaluated in case model changes
ent->coloredskin = R_TranslateNewModelSkinColormap (ent);
}
else if (SkinTextureChanged (ent))
{
Con_Printf ("Reupload\n");
ent->coloredskin = R_TranslateNewModelSkinColormap (ent);
}
}
Code: Select all
/*
===============
R_TranslateNewModelSkinColormap
Looks through our table and returns an existing model/skin/pants/shirt combination already uploaded.
If does not exist. Uploads it.
Since this re-uses colormapped skins (2 red players = same texture) this will upload fewer skins
than the GLQuake way, but will colormap everything.
r_nocolormap_list provides a means to exclude colormapping trivial things like gibs. Although it
supports 1024 combinations, it will rarely use more than 10 to 30 in practice. All skins are
deleted on a new map.
===============
*/
cvar_t r_nocolormap_list = {"r_nocolormap_list", "progs/eyes.mdl,progs/h_player.mdl,progs/gib1.mdl,progs/gib2.mdl,progs/gib3.mdl"};
// This is for an entity WITH an existing skin texture
// So we know it is an alias model
qboolean SkinTextureChanged (entity_t *cur_ent)
{
gltexture_t *skintexture = cur_ent->coloredskin;
int entnum = cur_ent - cl_entities;
if (skintexture->owner != cur_ent->model)
{
Con_Printf ("ent %i Model changed\n", entnum);
return true; // Model changed
}
do
{
int playerslot = cur_ent->colormap - 1;
int shirt_color = (cl.scores[playerslot].colors & 0xf0) >> 4;
int pants_color = cl.scores[playerslot].colors & 15;
if (skintexture->pants != pants_color)
{
Con_Printf ("ent %i: Pants changed\n", entnum); // Pants changed
return true;
}
if (skintexture->shirt != shirt_color)
{
Con_Printf ("ent %i: Shirt changed\n", entnum); // Shirt changed
return true;
}
if (skintexture->skinnum != cur_ent->skinnum)
{
Con_Printf ("ent %i: Player skin changed\n", entnum); // Skin changed
return true; // Skin changed
}
// NOTE: Baker --> invalid skin situation can persistently trigger "skin changed"
return false;
} while (0);
}
gltexture_t *R_TranslateNewModelSkinColormap (entity_t *cur_ent)
{
int entity_number = cur_ent - cl_entities; // If player, this will be 1-16
int shirt_color, pants_color, skinnum, matchingslot;
aliashdr_t *paliashdr;
do // REJECTIONS PHASE
{
// No model or it isn't an alias model
if (!cur_ent->model || cur_ent->model->type != mod_alias)
return NULL;
// No color map or it is invalid
if (cur_ent->colormap <= 0 || cur_ent->colormap > cl.maxclients)
return NULL;
// Certain models just aren't worth trying to colormap
if (cur_ent->model->flags & MOD_NOCOLORMAP)
return NULL;
//TODO: move these tests to the place where skinnum gets received from the server
paliashdr = (aliashdr_t *)Mod_Extradata (cur_ent->model);
skinnum = cur_ent->skinnum;
if (skinnum < 0 || skinnum >= paliashdr->numskins)
{
Con_DPrintf("(%d): Invalid player skin #%d\n", entity_number, skinnum);
skinnum = 0;
}
} while (0);
do // SEE IF WE HAVE SKIN + MODEL + COLOR ALREADY PHASE
{
int playerslot = cur_ent->colormap - 1;
shirt_color = (cl.scores[playerslot].colors & 0xf0) >> 4;
pants_color = cl.scores[playerslot].colors & 15;
for (matchingslot = 0; matchingslot < MAX_COLORMAP_SKINS; matchingslot ++)
{
gltexture_t *curtex = playertextures[matchingslot];
if (playertextures[matchingslot] == NULL)
break; // Not found, but use this slot
if (curtex->shirt != shirt_color) continue;
if (curtex->pants != pants_color) continue;
if (curtex->skinnum != skinnum) continue;
if (curtex->owner != cur_ent->model) continue;
// Found an existing translation for this
return curtex;
}
if (matchingslot == MAX_COLORMAP_SKINS)
{
Host_Error ("Color Slots Full");
return NULL;
}
// If we are here matchingslot is our new texture slot
} while (0);
do // UPLOAD THE NEW SKIN + MODEL PHASE
{
aliashdr_t *paliashdr = (aliashdr_t *)Mod_Extradata (cur_ent->model);
byte *pixels = (byte *)paliashdr + paliashdr->texels[skinnum]; // This is not a persistent place!
char name[64];
sprintf(name, "player_%i", entity_number);
Con_Printf ("New upload\n");
//upload new image
playertextures[matchingslot] = TexMgr_LoadImage (cur_ent->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);
// Color it now ...
if (playertextures[matchingslot])
{
playertextures[matchingslot]->skinnum = skinnum;
TexMgr_ReloadImage (playertextures[matchingslot], shirt_color, pants_color);
}
} while (0);
return playertextures[matchingslot];
}
Re: NQ Colored Dead Bodies
Posted: Thu Jul 19, 2012 10:46 pm
by Spike
what's with the do{}while(0); blocks without any breaks/continues? just use {} without the extra stuff if you just want the extra scope for declaring locals mid function.
what happens if I join a server and run some sort of script that changes my skin colours through each one of the 196 combinations? then change skin/model and do it all over again...
also, I see no handling for skingroups.

Re: NQ Colored Dead Bodies
Posted: Thu Jul 19, 2012 11:39 pm
by Baker
Spike wrote:what's with the do{}while(0); blocks without any breaks/continues? just use {} without the extra stuff if you just want the extra scope for declaring locals mid function.
I can change it to add break or continue on a whim. Not other reason really.
what happens if I join a server and run some sort of script that changes my skin colours through each one of the 196 combinations? then change skin/model and do it all over again...
also, I see no handling for skingroups.

1024 slots would make that difficult to do. You might be able to pull that off in Team Fortress somehow.
I'm thinking of making a "count" field that increments when a skin is assigned or deassigned so a texture knows how many entities are using it and having the skin selection part overwrite skins with a count of 0 and re-use those slots. Or, since the number of colormaps is limited to cl.maxlcients, determine if a pants/shirt color is no longer needed. Yeah, some extra protection would help for extremely rare cases and I do plan to address those.