NQ Colored Dead Bodies

Discuss programming topics for the various GPL'd game engine sources.
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

NQ Colored Dead Bodies

Post 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.
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
taniwha
Posts: 401
Joined: Thu Jan 14, 2010 7:11 am
Contact:

Re: NQ Colored Dead Bodies

Post 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 :)
Leave others their otherness.
http://quakeforge.net/
r00k
Posts: 1111
Joined: Sat Nov 13, 2004 10:39 pm

Re: NQ Colored Dead Bodies

Post 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. :|
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Re: NQ Colored Dead Bodies

Post 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.
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Re: NQ Colored Dead Bodies

Post 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.
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Re: NQ Colored Dead Bodies

Post 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?
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Re: NQ Colored Dead Bodies

Post 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.
r00k
Posts: 1111
Joined: Sat Nov 13, 2004 10:39 pm

Re: NQ Colored Dead Bodies

Post 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 :/
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Re: NQ Colored Dead Bodies

Post 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.
r00k
Posts: 1111
Joined: Sat Nov 13, 2004 10:39 pm

Re: NQ Colored Dead Bodies

Post 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...
Last edited by r00k on Thu Jul 19, 2012 4:16 pm, edited 1 time in total.
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Re: NQ Colored Dead Bodies

Post 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];
}
Last edited by Baker on Thu Jul 19, 2012 7:46 pm, edited 1 time in total.
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
r00k
Posts: 1111
Joined: Sat Nov 13, 2004 10:39 pm

Re: NQ Colored Dead Bodies

Post 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.
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Re: NQ Colored Dead Bodies

Post 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];
}
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
Spike
Posts: 2914
Joined: Fri Nov 05, 2004 3:12 am
Location: UK
Contact:

Re: NQ Colored Dead Bodies

Post 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. :P
Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Re: NQ Colored Dead Bodies

Post 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. :P
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.
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
Post Reply