shithub: qk1

Download patch

ref: acad4d590f4d8484a9e5ec692bc57dc3dddacd8e
parent: 57161a86fd06293d116ac687ea9e462c02eb7cbb
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Wed Oct 25 13:31:13 EDT 2023

.alpha: part 1 - pr and protocol

--- a/cl_parse.c
+++ b/cl_parse.c
@@ -379,6 +379,8 @@
 	ent->msg_origins[0][2] = (bits & U_ORIGIN3) ? cl.protocol->MSG_ReadCoord() : ent->baseline.origin[2];
 	ent->msg_angles[0][2] = (bits & U_ANGLE3) ? cl.protocol->MSG_ReadAngle() : ent->baseline.angles[2];
 
+	ent->alpha = (bits & cl.protocol->fl_alpha) ? MSG_ReadByte() : ent->baseline.alpha;
+
 	if(bits & U_NOLERP)
 		ent->forcelink = true;
 
@@ -435,6 +437,7 @@
 		ent->baseline.origin[i] = cl.protocol->MSG_ReadCoord ();
 		ent->baseline.angles[i] = cl.protocol->MSG_ReadAngle ();
 	}
+	ent->baseline.alpha = (bits & cl.protocol->fl_baseline_alpha) ? MSG_ReadByte() : DEFAULT_ALPHA;
 }
 
 
@@ -526,6 +529,7 @@
 
 	if(bits & cl.protocol->fl_large_weaponframe)
 		cl.stats[STAT_WEAPONFRAME] |= MSG_ReadByte() << 8;
+	cl.viewent.alpha = (bits & cl.protocol->fl_weapon_alpha) ? MSG_ReadByte() : DEFAULT_ALPHA;
 
 	if(cl.viewent.model != cl.model_precache[cl.stats[STAT_WEAPON]]){
 		// FIXME(sigrid) - reset lerp
--- a/pr_cmds.c
+++ b/pr_cmds.c
@@ -1450,6 +1450,12 @@
 		frame = 0; // yikes.
 	else if(frame >= sv.protocol->large_frame)
 		bits |= sv.protocol->fl_large_baseline_frame;
+	if(zeroalpha(ent->alpha)){
+		ED_Free(ent);
+		return;
+	}
+	if(!defalpha(ent->alpha))
+		bits |= sv.protocol->fl_baseline_alpha;
 
 	MSG_WriteByte (&sv.signon, bits ? svc_spawnstatic2 : svc_spawnstatic);
 	if(bits)
@@ -1466,6 +1472,8 @@
 		sv.protocol->MSG_WriteCoord(&sv.signon, ent->v.origin[i]);
 		sv.protocol->MSG_WriteAngle(&sv.signon, ent->v.angles[i]);
 	}
+	if(bits & sv.protocol->fl_baseline_alpha)
+		MSG_WriteByte(&sv.signon, ent->alpha);
 
 // throw the entity away now
 	ED_Free (ent);
--- a/pr_edict.c
+++ b/pr_edict.c
@@ -15,7 +15,16 @@
 float			*pr_globals;			// same as pr_global_struct
 int				pr_edict_size;	// in bytes
 
-int		type_size[8] = {1,sizeof(string_t)/4,1,3,1,1,sizeof(func_t)/4,sizeof(void *)/4};
+int type_size[8] = {
+	[ev_void] = 1,
+	[ev_string] = sizeof(string_t)/4,
+	[ev_float] = 1,
+	[ev_vector] = 3,
+	[ev_entity] = 1,
+	[ev_field] = 1,
+	[ev_function] = sizeof(func_t)/4,
+	[ev_pointer] = sizeof(void *)/4,
+};
 
 ddef_t *ED_FieldAtOfs (int ofs);
 qboolean	ED_ParseEpair (void *base, ddef_t *key, char *s);
@@ -180,7 +189,7 @@
 	VectorCopy (vec3_origin, ed->v.angles);
 	ed->v.nextthink = -1;
 	ed->v.solid = 0;
-	
+	ed->alpha = DEFAULT_ALPHA;
 	ed->freetime = sv.time;
 }
 
@@ -624,7 +633,7 @@
 		if (com_token[0] == '}')
 			break;
 		if (!data)
-			fatal ("ED_ParseEntity: EOF without closing brace");
+			fatal ("ED_ParseGlobals: EOF without closing brace");
 
 		strcpy (keyname, com_token);
 
@@ -631,15 +640,15 @@
 	// parse value	
 		data = COM_Parse (data);
 		if (!data)
-			fatal ("ED_ParseEntity: EOF without closing brace");
+			fatal ("ED_ParseGlobals: EOF without closing brace");
 
 		if (com_token[0] == '}')
-			fatal ("ED_ParseEntity: closing brace without data");
+			fatal ("ED_ParseGlobals: closing brace without data");
 
 		key = ED_FindGlobal (keyname);
 		if (!key)
 		{
-			Con_Printf ("'%s' is not a global\n", keyname);
+			Con_Printf ("ED_ParseGlobals: '%s' is not a global\n", keyname);
 			continue;
 		}
 
@@ -789,21 +798,21 @@
 		if (com_token[0] == '}')
 			break;
 		if (!data)
-			fatal ("ED_ParseEntity: EOF without closing brace");
+			fatal ("ED_ParseEdict: EOF without closing brace");
 		
-// anglehack is to allow QuakeEd to write single scalar angles
-// and allow them to be turned into vectors. (FIXME...)
-if (!strcmp(com_token, "angle"))
-{
-	strcpy (com_token, "angles");
-	anglehack = true;
-}
-else
-	anglehack = false;
+		// anglehack is to allow QuakeEd to write single scalar angles
+		// and allow them to be turned into vectors. (FIXME...)
+		if (!strcmp(com_token, "angle"))
+		{
+			strcpy (com_token, "angles");
+			anglehack = true;
+		}
+		else
+			anglehack = false;
 
-// FIXME: change light to _light to get rid of this hack
-if (!strcmp(com_token, "light"))
-	strcpy (com_token, "light_lev");	// hack for single light def
+		// FIXME: change light to _light to get rid of this hack
+		if (!strcmp(com_token, "light"))
+			strcpy (com_token, "light_lev");	// hack for single light def
 
 		strcpy (keyname, com_token);
 
@@ -818,15 +827,15 @@
 	// parse value	
 		data = COM_Parse (data);
 		if (!data)
-			fatal ("ED_ParseEntity: EOF without closing brace");
+			fatal ("ED_ParseEdict: EOF without closing brace");
 
 		if (com_token[0] == '}')
-			fatal ("ED_ParseEntity: closing brace without data");
+			fatal ("ED_ParseEdict: closing brace without data");
 
 		init = true;	
 
-// keynames with a leading underscore are used for utility comments,
-// and are immediately discarded by quake
+	// keynames with a leading underscore are used for utility comments,
+	// and are immediately discarded by quake
 		if (keyname[0] == '_')
 			continue;
 		
@@ -833,16 +842,18 @@
 		key = ED_FindField (keyname);
 		if (!key)
 		{
-			Con_Printf ("'%s' is not a field\n", keyname);
+			if(strcmp(keyname, "alpha") == 0)
+				ent->alpha = f2alpha(atof(com_token));
+			else
+				Con_Printf ("ED_ParseEdict: '%s' is not a field\n", keyname);
 			continue;
 		}
 
-if (anglehack)
-{
-char	temp[32];
-strcpy (temp, com_token);
-sprint (com_token, "0 %s 0", temp);
-}
+		if (anglehack){
+			char	temp[32];
+			strcpy (temp, com_token);
+			sprint (com_token, "0 %s 0", temp);
+		}
 
 		if (!ED_ParseEpair ((void *)&ent->v, key, com_token))
 			Host_Error ("ED_ParseEdict: parse error");
@@ -942,7 +953,63 @@
 	Con_DPrintf("%d entities inhibited\n", inhibit);
 }
 
+typedef struct extra_field_t extra_field_t;
 
+struct extra_field_t {
+	int type;
+	char *name;
+};
+
+static extra_field_t extra_fields[] = {
+	{ev_float, "alpha"},
+};
+
+static void
+PR_FieldDefs(ddef_t *in)
+{
+	extra_field_t *e;
+	ddef_t *d;
+	int i, n;
+
+	// allocate to fit *all* extra fields, if needed, and copy over
+	n = progs->numfielddefs;
+	for(i = 0; i < nelem(extra_fields); i++)
+		n += extra_fields[i].type == ev_vector ? 4 : 1;
+	d = malloc(n * sizeof(*in));
+	memmove(d, in, progs->numfielddefs * sizeof(*in));
+	free(pr_fielddefs);
+	pr_fielddefs = d;
+
+	// convert endianess of fields that loaded from disk
+	for(i = 0 ; i < progs->numfielddefs; i++, d++){
+		d->type = LittleShort(d->type);
+		if(d->type & DEF_SAVEGLOBAL)
+			fatal("PR_FieldDefs: d->type & DEF_SAVEGLOBAL");
+		d->ofs = LittleShort(d->ofs);
+		d->s_name = LittleLong(d->s_name);
+	}
+
+	// add missing extra fields
+	d = &pr_fielddefs[progs->numfielddefs];
+	for(i = 0, e = extra_fields; i < nelem(extra_fields); i++, e++){
+		if(ED_FindField(e->name) != nil)
+			continue;
+		d->type = e->type;
+		d->s_name = ED_NewString(e->name);
+		d->ofs = progs->numfielddefs++;
+		d++;
+		if(e->type == ev_vector){
+			for(n = 0; n < 3; n++){
+				d->type = ev_float;
+				d->s_name = ED_NewString(va("%s_%c", e->name, 'x'+n));
+				d->ofs = progs->numfielddefs++;
+				d++;
+			}
+		}
+		progs->entityfields += type_size[e->type];
+	}
+}
+
 /*
 ===============
 PR_LoadProgs
@@ -992,14 +1059,10 @@
 	pr_strings = (char *)progs + progs->ofs_strings;
 	pr_strings_size = progs->numstrings;
 	pr_globaldefs = (ddef_t *)((byte *)progs + progs->ofs_globaldefs);
-	pr_fielddefs = (ddef_t *)((byte *)progs + progs->ofs_fielddefs);
 	pr_statements = (dstatement_t *)((byte *)progs + progs->ofs_statements);
-
 	pr_global_struct = (globalvars_t *)((byte *)progs + progs->ofs_globals);
 	pr_globals = (float *)pr_global_struct;
-	
-	pr_edict_size = progs->entityfields * 4 + sizeof(edict_t) - sizeof(entvars_t);
-	
+		
 // byte swap the lumps
 	for (i=0 ; i<progs->numstatements ; i++)
 	{
@@ -1026,17 +1089,11 @@
 		pr_globaldefs[i].s_name = LittleLong (pr_globaldefs[i].s_name);
 	}
 
-	for (i=0 ; i<progs->numfielddefs ; i++)
-	{
-		pr_fielddefs[i].type = LittleShort (pr_fielddefs[i].type);
-		if (pr_fielddefs[i].type & DEF_SAVEGLOBAL)
-			fatal ("PR_LoadProgs: pr_fielddefs[i].type & DEF_SAVEGLOBAL");
-		pr_fielddefs[i].ofs = LittleShort (pr_fielddefs[i].ofs);
-		pr_fielddefs[i].s_name = LittleLong (pr_fielddefs[i].s_name);
-	}
-
 	for (i=0 ; i<progs->numglobals ; i++)
 		((int *)pr_globals)[i] = LittleLong (((int *)pr_globals)[i]);
+
+	PR_FieldDefs((ddef_t *)((byte *)progs + progs->ofs_fielddefs));
+	pr_edict_size = progs->entityfields * 4 + sizeof(edict_t) - sizeof(entvars_t);
 }
 
 
--- a/progs.h
+++ b/progs.h
@@ -16,6 +16,7 @@
 {
 	qboolean	free;
 	link_t		area;				// linked to a division node or leaf
+	byte		alpha;
 	
 	int			num_leafs;
 	int			leafnums[MAX_ENT_LEAFS];
--- a/protocol.c
+++ b/protocol.c
@@ -60,6 +60,9 @@
 		.fl_large_weaponmodel = 1<<16,
 		.fl_large_baseline_model = 1<<0,
 		.fl_large_baseline_frame = 1<<1,
+		.fl_alpha = 1<<16,
+		.fl_baseline_alpha = 1<<2,
+		.fl_weapon_alpha = 1<<25,
 		.MSG_WriteCoord = MSG_WriteCoordInt32,
 		.MSG_WriteAngle = MSG_WriteAngleInt16,
 		.MSG_ReadCoord = MSG_ReadCoordInt32,
--- a/protocol.h
+++ b/protocol.h
@@ -12,6 +12,16 @@
 	PF_RMQ_COORD_INT32 = 1<<7,
 };
 
+enum {
+	DEFAULT_ALPHA,
+	ZERO_ALPHA,
+};
+
+#define defalpha(a) ((a) == DEFAULT_ALPHA)
+#define zeroalpha(a) (!defalpha(a) && (a) <= ZERO_ALPHA)
+#define f2alpha(f) ((f) == 0.0 ? DEFAULT_ALPHA : clamp((f)*254+1, 1, 255))
+#define alpha2f(a) (zeroalpha(a) ? 0.0 : (float)(a)/255.0)
+
 typedef struct protocol_t protocol_t;
 
 struct protocol_t {
@@ -34,6 +44,10 @@
 	u32int fl_large_weaponmodel;
 	u32int fl_large_baseline_model;
 	u32int fl_large_baseline_frame;
+
+	u32int fl_alpha;
+	u32int fl_baseline_alpha;
+	u32int fl_weapon_alpha;
 
 	// absolute limits for the protocol
 	int limit_entity;
--- a/quakedef.h
+++ b/quakedef.h
@@ -127,6 +127,7 @@
 	int		colormap;
 	int		skin;
 	int		effects;
+	byte	alpha;
 } entity_state_t;
 
 #include "wad.h"
--- a/render.h
+++ b/render.h
@@ -47,6 +47,8 @@
 	struct mnode_s			*topnode;		// for bmodels, first world node
 											//  that splits bmodel, or NULL if
 											//  not split
+
+	byte alpha;
 } entity_t;
 
 // !!! if this is changed, it must be changed in asm_draw.h too !!!
--- a/sv_main.c
+++ b/sv_main.c
@@ -441,7 +441,8 @@
 void SV_WriteEntitiesToClient (edict_t	*clent, sizebuf_t *msg)
 {
 	u32int	bits;
-	int		e, i, model;
+	int		e, i, model, alpha;
+	eval_t	*v;
 	byte	*pvs;
 	vec3_t	org;
 	float	miss;
@@ -457,22 +458,27 @@
 	{
 // ignore if not touching a PV leaf
 		model = ent->v.modelindex;
+
+		v = GetEdictFieldValue(ent, "alpha");
+		alpha = v ? f2alpha(v->_float) : DEFAULT_ALPHA;
+
 		if (ent != clent)	// clent is ALLWAYS sent
 		{
-			if(ent->v.effects == EF_NODRAW)
-				continue;
 // ignore ents without visible models
 			if(!model || !*PR_Str(ent->v.model))
 				continue;
 			if(model >= sv.protocol->limit_model)
 				continue;
-
-			for (i=0 ; i < ent->num_leafs ; i++)
-				if (pvs[ent->leafnums[i] >> 3] & (1 << (ent->leafnums[i]&7) ))
+			for(i=0 ; i < ent->num_leafs ; i++)
+				if(pvs[ent->leafnums[i] >> 3] & (1 << (ent->leafnums[i]&7) ))
 					break;
-
-			if (i == ent->num_leafs && ent->num_leafs < MAX_ENT_LEAFS)
+			if(i == ent->num_leafs && ent->num_leafs < MAX_ENT_LEAFS)
 				continue;		// not visible
+
+			if((int)ent->v.effects == EF_NODRAW)
+				continue;
+			if((int)ent->v.effects == 0 && zeroalpha(alpha))
+				continue;
 		}
 
 		if (msg->cursize + 18 > msg->maxsize)
@@ -508,6 +514,8 @@
 			bits |= U_EFFECTS;
 		if (model != ent->baseline.modelindex)
 			bits |= U_MODEL;
+		if (alpha != ent->baseline.alpha)
+			bits |= sv.protocol->fl_alpha;
 		if (e >= 256)
 			bits |= U_LONGENTITY;
 		if(bits & U_FRAME){
@@ -566,6 +574,8 @@
 			sv.protocol->MSG_WriteCoord(msg, ent->v.origin[2]);
 		if (bits & U_ANGLE3)
 			sv.protocol->MSG_WriteAngle(msg, ent->v.angles[2]);
+		if (bits & sv.protocol->fl_alpha)
+			MSG_WriteByte(msg, alpha);
 		if (bits & sv.protocol->fl_large_frame)
 			MSG_WriteByte(msg, (int)ent->v.frame>>8);
 		if (bits & sv.protocol->fl_large_model)
@@ -666,6 +676,8 @@
 			bits ^= SU_WEAPON; // yikes.
 		else if(weaponmodel >= sv.protocol->large_model)
 			bits |= sv.protocol->fl_large_weaponmodel;
+		if(!defalpha(ent->alpha))
+			bits |= sv.protocol->fl_weapon_alpha;
 	}
 	if (ent->v.weaponframe){
 		bits |= SU_WEAPONFRAME;
@@ -743,6 +755,8 @@
 		MSG_WriteByte(msg, weaponmodel>>8);
 	if(bits & sv.protocol->fl_large_weaponframe)
 		MSG_WriteByte(msg, (int)ent->v.weaponframe>>8);
+	if(bits & sv.protocol->fl_weapon_alpha)
+		MSG_WriteByte(msg, ent->alpha);
 }
 
 /*
@@ -983,11 +997,13 @@
 		{
 			svent->baseline.colormap = entnum;
 			svent->baseline.modelindex = SV_ModelIndex("progs/player.mdl");
+			svent->baseline.alpha = DEFAULT_ALPHA;
 		}
 		else
 		{
 			svent->baseline.colormap = 0;
 			svent->baseline.modelindex = SV_ModelIndex(PR_Str(svent->v.model));
+			svent->baseline.alpha = svent->alpha;
 		}
 
 		bits = 0;
@@ -999,6 +1015,8 @@
 			svent->baseline.frame = 0; // yikes.
 		else if(svent->baseline.frame >= sv.protocol->large_frame)
 			bits |= sv.protocol->fl_large_baseline_frame;
+		if(!defalpha(svent->baseline.alpha))
+			bits |= sv.protocol->fl_baseline_alpha;
 
 	//
 	// add to the message
@@ -1019,6 +1037,8 @@
 			sv.protocol->MSG_WriteCoord(&sv.signon, svent->baseline.origin[i]);
 			sv.protocol->MSG_WriteAngle(&sv.signon, svent->baseline.angles[i]);
 		}
+		if(bits & sv.protocol->fl_baseline_alpha)
+			MSG_WriteByte(&sv.signon, svent->baseline.alpha);
 	}
 }