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