MSG_WriteByte(msg, s->glowmod[1]);
MSG_WriteByte(msg, s->glowmod[2]);
}
+ if (bits & E5_COMPLEXANIMATION)
+ {
+ if (s->skeletonobject.model && s->skeletonobject.relativetransforms)
+ {
+ int numbones = s->skeletonobject.model->num_bones;
+ int bonenum;
+ short pose6s[6];
+ MSG_WriteByte(msg, 4);
+ MSG_WriteShort(msg, s->modelindex);
+ MSG_WriteByte(msg, numbones);
+ for (bonenum = 0;bonenum < numbones;bonenum++)
+ {
+ Matrix4x4_ToBonePose6s(s->skeletonobject.relativetransforms + bonenum, 64, pose6s);
+ MSG_WriteShort(msg, pose6s[0]);
+ MSG_WriteShort(msg, pose6s[1]);
+ MSG_WriteShort(msg, pose6s[2]);
+ MSG_WriteShort(msg, pose6s[3]);
+ MSG_WriteShort(msg, pose6s[4]);
+ MSG_WriteShort(msg, pose6s[5]);
+ }
+ }
+ else if (s->framegroupblend[3].lerp > 0)
+ {
+ MSG_WriteByte(msg, 3);
+ MSG_WriteShort(msg, s->framegroupblend[0].frame);
+ MSG_WriteShort(msg, s->framegroupblend[1].frame);
+ MSG_WriteShort(msg, s->framegroupblend[2].frame);
+ MSG_WriteShort(msg, s->framegroupblend[3].frame);
+ MSG_WriteShort(msg, (int)((sv.time - s->framegroupblend[0].start) * 1000.0));
+ MSG_WriteShort(msg, (int)((sv.time - s->framegroupblend[1].start) * 1000.0));
+ MSG_WriteShort(msg, (int)((sv.time - s->framegroupblend[2].start) * 1000.0));
+ MSG_WriteShort(msg, (int)((sv.time - s->framegroupblend[3].start) * 1000.0));
+ MSG_WriteByte(msg, s->framegroupblend[0].lerp * 255.0f);
+ MSG_WriteByte(msg, s->framegroupblend[1].lerp * 255.0f);
+ MSG_WriteByte(msg, s->framegroupblend[2].lerp * 255.0f);
+ MSG_WriteByte(msg, s->framegroupblend[3].lerp * 255.0f);
+ }
+ else if (s->framegroupblend[2].lerp > 0)
+ {
+ MSG_WriteByte(msg, 2);
+ MSG_WriteShort(msg, s->framegroupblend[0].frame);
+ MSG_WriteShort(msg, s->framegroupblend[1].frame);
+ MSG_WriteShort(msg, s->framegroupblend[2].frame);
+ MSG_WriteShort(msg, (int)((sv.time - s->framegroupblend[0].start) * 1000.0));
+ MSG_WriteShort(msg, (int)((sv.time - s->framegroupblend[1].start) * 1000.0));
+ MSG_WriteShort(msg, (int)((sv.time - s->framegroupblend[2].start) * 1000.0));
+ MSG_WriteByte(msg, s->framegroupblend[0].lerp * 255.0f);
+ MSG_WriteByte(msg, s->framegroupblend[1].lerp * 255.0f);
+ MSG_WriteByte(msg, s->framegroupblend[2].lerp * 255.0f);
+ }
+ else if (s->framegroupblend[1].lerp > 0)
+ {
+ MSG_WriteByte(msg, 1);
+ MSG_WriteShort(msg, s->framegroupblend[0].frame);
+ MSG_WriteShort(msg, s->framegroupblend[1].frame);
+ MSG_WriteShort(msg, (int)((sv.time - s->framegroupblend[0].start) * 1000.0));
+ MSG_WriteShort(msg, (int)((sv.time - s->framegroupblend[1].start) * 1000.0));
+ MSG_WriteByte(msg, s->framegroupblend[0].lerp * 255.0f);
+ MSG_WriteByte(msg, s->framegroupblend[1].lerp * 255.0f);
+ }
+ else
+ {
+ MSG_WriteByte(msg, 0);
+ MSG_WriteShort(msg, s->framegroupblend[0].frame);
+ MSG_WriteShort(msg, (int)((sv.time - s->framegroupblend[0].start) * 1000.0));
+ }
+ }
}
ENTITYSIZEPROFILING_END(msg, s->number);
}
+extern dp_model_t *CL_GetModelByIndex(int modelindex);
+
static void EntityState5_ReadUpdate(entity_state_t *s, int number)
{
int bits;
s->glowmod[1] = MSG_ReadByte();
s->glowmod[2] = MSG_ReadByte();
}
+ if (bits & E5_COMPLEXANIMATION)
+ {
+ skeleton_t *skeleton;
+ const dp_model_t *model;
+ int modelindex;
+ int type;
+ int bonenum;
+ int numbones;
+ short pose6s[6];
+ type = MSG_ReadByte();
+ switch(type)
+ {
+ case 0:
+ s->framegroupblend[0].frame = MSG_ReadShort();
+ s->framegroupblend[1].frame = 0;
+ s->framegroupblend[2].frame = 0;
+ s->framegroupblend[3].frame = 0;
+ s->framegroupblend[0].start = cl.time - (short)MSG_ReadShort() * (1.0f / 1000.0f);
+ s->framegroupblend[1].start = 0;
+ s->framegroupblend[2].start = 0;
+ s->framegroupblend[3].start = 0;
+ s->framegroupblend[0].lerp = 1;
+ s->framegroupblend[1].lerp = 0;
+ s->framegroupblend[2].lerp = 0;
+ s->framegroupblend[3].lerp = 0;
+ break;
+ case 1:
+ s->framegroupblend[0].frame = MSG_ReadShort();
+ s->framegroupblend[1].frame = MSG_ReadShort();
+ s->framegroupblend[2].frame = 0;
+ s->framegroupblend[3].frame = 0;
+ s->framegroupblend[0].start = cl.time - (short)MSG_ReadShort() * (1.0f / 1000.0f);
+ s->framegroupblend[1].start = cl.time - (short)MSG_ReadShort() * (1.0f / 1000.0f);
+ s->framegroupblend[2].start = 0;
+ s->framegroupblend[3].start = 0;
+ s->framegroupblend[0].lerp = MSG_ReadByte() * (1.0f / 255.0f);
+ s->framegroupblend[1].lerp = MSG_ReadByte() * (1.0f / 255.0f);
+ s->framegroupblend[2].lerp = 0;
+ s->framegroupblend[3].lerp = 0;
+ break;
+ case 2:
+ s->framegroupblend[0].frame = MSG_ReadShort();
+ s->framegroupblend[1].frame = MSG_ReadShort();
+ s->framegroupblend[2].frame = MSG_ReadShort();
+ s->framegroupblend[3].frame = 0;
+ s->framegroupblend[0].start = cl.time - (short)MSG_ReadShort() * (1.0f / 1000.0f);
+ s->framegroupblend[1].start = cl.time - (short)MSG_ReadShort() * (1.0f / 1000.0f);
+ s->framegroupblend[2].start = cl.time - (short)MSG_ReadShort() * (1.0f / 1000.0f);
+ s->framegroupblend[3].start = 0;
+ s->framegroupblend[0].lerp = MSG_ReadByte() * (1.0f / 255.0f);
+ s->framegroupblend[1].lerp = MSG_ReadByte() * (1.0f / 255.0f);
+ s->framegroupblend[2].lerp = MSG_ReadByte() * (1.0f / 255.0f);
+ s->framegroupblend[3].lerp = 0;
+ break;
+ case 3:
+ s->framegroupblend[0].frame = MSG_ReadShort();
+ s->framegroupblend[1].frame = MSG_ReadShort();
+ s->framegroupblend[2].frame = MSG_ReadShort();
+ s->framegroupblend[3].frame = MSG_ReadShort();
+ s->framegroupblend[0].start = cl.time - (short)MSG_ReadShort() * (1.0f / 1000.0f);
+ s->framegroupblend[1].start = cl.time - (short)MSG_ReadShort() * (1.0f / 1000.0f);
+ s->framegroupblend[2].start = cl.time - (short)MSG_ReadShort() * (1.0f / 1000.0f);
+ s->framegroupblend[3].start = cl.time - (short)MSG_ReadShort() * (1.0f / 1000.0f);
+ s->framegroupblend[0].lerp = MSG_ReadByte() * (1.0f / 255.0f);
+ s->framegroupblend[1].lerp = MSG_ReadByte() * (1.0f / 255.0f);
+ s->framegroupblend[2].lerp = MSG_ReadByte() * (1.0f / 255.0f);
+ s->framegroupblend[3].lerp = MSG_ReadByte() * (1.0f / 255.0f);
+ break;
+ case 4:
+ if (!cl.engineskeletonobjects)
+ cl.engineskeletonobjects = Mem_Alloc(cls.levelmempool, sizeof(*cl.engineskeletonobjects) * MAX_EDICTS);
+ skeleton = &cl.engineskeletonobjects[number];
+ modelindex = MSG_ReadShort();
+ model = CL_GetModelByIndex(modelindex);
+ numbones = MSG_ReadByte();
+ if (model && numbones != model->num_bones)
+ Host_Error("E5_COMPLEXANIMATION: model has different number of bones than network packet describes\n");
+ if (!skeleton->relativetransforms || skeleton->model != model)
+ {
+ skeleton->model = model;
+ skeleton->relativetransforms = Mem_Realloc(cls.levelmempool, skeleton->relativetransforms, sizeof(*skeleton->relativetransforms) * skeleton->model->num_bones);
+ for (bonenum = 0;bonenum < model->num_bones;bonenum++)
+ skeleton->relativetransforms[bonenum] = identitymatrix;
+ }
+ for (bonenum = 0;bonenum < numbones;bonenum++)
+ {
+ pose6s[0] = (short)MSG_ReadShort();
+ pose6s[1] = (short)MSG_ReadShort();
+ pose6s[2] = (short)MSG_ReadShort();
+ pose6s[3] = (short)MSG_ReadShort();
+ pose6s[4] = (short)MSG_ReadShort();
+ pose6s[5] = (short)MSG_ReadShort();
+ Matrix4x4_FromBonePose6s(skeleton->relativetransforms + bonenum, 1.0f / 64.0f, pose6s);
+ }
+ s->skeletonobject = *skeleton;
+ break;
+ default:
+ Host_Error("E5_COMPLEXANIMATION: Parse error - unknown type %i\n", type);
+ break;
+ }
+ }
if (developer_networkentities.integer >= 2)
bits |= E5_COLORMOD;
if (o->glowmod[0] != n->glowmod[0] || o->glowmod[1] != n->glowmod[1] || o->glowmod[2] != n->glowmod[2])
bits |= E5_GLOWMOD;
+ if (n->flags & RENDER_COMPLEXANIMATION)
+ bits |= E5_COMPLEXANIMATION;
}
else
if (o->active == ACTIVE_NETWORK)
#define RENDER_LOWPRECISION 16 // send as low precision coordinates to save bandwidth
#define RENDER_COLORMAPPED 32
#define RENDER_NOCULL 64 // do not cull this entity with r_cullentities
+#define RENDER_COMPLEXANIMATION 128
#define RENDER_SHADOW 65536 // cast shadow
#define RENDER_LIGHT 131072 // receive light
#define RENDER_ADDITIVE 2097152
#define RENDER_DOUBLESIDED 4194304
+#define MAX_FRAMEGROUPBLENDS 4
+typedef struct framegroupblend_s
+{
+ // animation number and blend factor
+ // (for most models this is the frame number)
+ int frame;
+ float lerp;
+ // time frame began playing (for framegroup animations)
+ double start;
+}
+framegroupblend_t;
+
+struct matrix4x4_s;
+struct model_s;
+
+typedef struct skeleton_s
+{
+ const struct model_s *model;
+ struct matrix4x4_s *relativetransforms;
+}
+skeleton_t;
+
typedef enum entity_state_active_e
{
ACTIVE_NOT = 0,
}
entity_state_active_t;
-// this is 96 bytes
+// this was 96 bytes, now 168 bytes (32bit) or 176 bytes (64bit)
typedef struct entity_state_s
{
// ! means this is not sent to client
unsigned char tagindex;
unsigned char colormod[3];
unsigned char glowmod[3];
+ // LordHavoc: very big data here :(
+ framegroupblend_t framegroupblend[4];
+ skeleton_t skeletonobject;
}
entity_state_t;
// byte[3] = s->glowmod[0], s->glowmod[1], s->glowmod[2]
#define E5_GLOWMOD (1<<24)
-// unused
-#define E5_UNUSED25 (1<<25)
+// byte type=0 short frames[1] short times[1]
+// byte type=1 short frames[2] short times[2] byte lerps[2]
+// byte type=2 short frames[3] short times[3] byte lerps[3]
+// byte type=3 short frames[4] short times[4] byte lerps[4]
+// byte type=4 short modelindex byte numbones {short pose6s[6]}
+// see also RENDER_COMPLEXANIMATION
+#define E5_COMPLEXANIMATION (1<<25)
// unused
#define E5_UNUSED26 (1<<26)
// unused
{ev_vector, "glowmod"},
{ev_vector, "movement"},
{ev_vector, "punchvector"},
+ {ev_float, "frame"},
+ {ev_float, "frame1time"},
+ {ev_float, "frame2"},
+ {ev_float, "frame2time"},
+ {ev_float, "frame3"},
+ {ev_float, "frame3time"},
+ {ev_float, "frame4"},
+ {ev_float, "frame4time"},
+ {ev_float, "lerpfrac"},
+ {ev_float, "lerpfrac3"},
+ {ev_float, "lerpfrac4"},
+ {ev_float, "sendcomplexanimation"},
// physics
//{ev_float, "solid"},
if (cs->viewmodelforclient)
cs->flags |= RENDER_VIEWMODEL; // show relative to the view
+ if (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.sendcomplexanimation)->_float)
+ {
+ cs->flags |= RENDER_COMPLEXANIMATION;
+ if (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.skeletonindex)->_float >= 1)
+ cs->skeletonobject = ent->priv.server->skeleton;
+ cs->framegroupblend[0].frame = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.frame)->_float;
+ cs->framegroupblend[1].frame = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.frame2)->_float;
+ cs->framegroupblend[2].frame = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.frame3)->_float;
+ cs->framegroupblend[3].frame = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.frame4)->_float;
+ cs->framegroupblend[0].start = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.frame1time)->_float;
+ cs->framegroupblend[1].start = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.frame2time)->_float;
+ cs->framegroupblend[2].start = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.frame3time)->_float;
+ cs->framegroupblend[3].start = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.frame4time)->_float;
+ cs->framegroupblend[1].lerp = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.lerpfrac)->_float;
+ cs->framegroupblend[2].lerp = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.lerpfrac3)->_float;
+ cs->framegroupblend[3].lerp = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.lerpfrac4)->_float;
+ cs->framegroupblend[0].lerp = 1.0f - cs->framegroupblend[1].lerp - cs->framegroupblend[2].lerp - cs->framegroupblend[3].lerp;
+ }
+
cs->light[0] = light[0];
cs->light[1] = light[1];
cs->light[2] = light[2];