From: havoc Date: Fri, 6 May 2011 13:39:22 +0000 (+0000) Subject: added .float sendcomplexanimation server qc field which if TRUE will X-Git-Tag: xonotic-v0.6.0~163^2~437 X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=fc9f3eecc683677641ba6f44a678ec36e33ee013;p=xonotic%2Fdarkplaces.git added .float sendcomplexanimation server qc field which if TRUE will send .frame .frame2 .frame3 .frame4 .frame1time .frame2time .frame3time .frame4time .lerpfrac .lerpfrac3 .lerpfrac4 OR .skeletonindex if set (BANDWIDTH HOG, skeletal networking inadvisable in multiplayer) git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@11109 d7cf8633-e32d-0410-b094-e92efae38249 --- diff --git a/cl_main.c b/cl_main.c index b195ddaa..06527e4c 100644 --- a/cl_main.c +++ b/cl_main.c @@ -1098,7 +1098,17 @@ void CL_UpdateNetworkEntity(entity_t *e, int recursionlimit, qboolean interpolat } // animation lerp - if (e->render.framegroupblend[0].frame == frame) + e->render.skeleton = NULL; + if (e->render.flags & RENDER_COMPLEXANIMATION) + { + e->render.framegroupblend[0] = e->state_current.framegroupblend[0]; + e->render.framegroupblend[1] = e->state_current.framegroupblend[1]; + e->render.framegroupblend[2] = e->state_current.framegroupblend[2]; + e->render.framegroupblend[3] = e->state_current.framegroupblend[3]; + if (e->state_current.skeletonobject.model && e->state_current.skeletonobject.relativetransforms) + e->render.skeleton = &e->state_current.skeletonobject; + } + else if (e->render.framegroupblend[0].frame == frame) { // update frame lerp fraction e->render.framegroupblend[0].lerp = 1; diff --git a/client.h b/client.h index 11f9aa17..e3715bbe 100644 --- a/client.h +++ b/client.h @@ -291,18 +291,6 @@ typedef struct dlight_s } dlight_t; -#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; - // this is derived from processing of the framegroupblend array // note: technically each framegroupblend can produce two of these, but that // never happens in practice because no one blends between more than 2 @@ -1274,6 +1262,9 @@ typedef struct client_state_s // freed on each level change size_t buildlightmapmemorysize; unsigned char *buildlightmapmemory; + + // used by EntityState5_ReadUpdate + skeleton_t *engineskeletonobjects; } client_state_t; diff --git a/model_shared.h b/model_shared.h index a7ecd4fe..c34890ca 100644 --- a/model_shared.h +++ b/model_shared.h @@ -1099,13 +1099,6 @@ qboolean Mod_LoadTextureFromQ3Shader(texture_t *texture, const char *name, qbool extern cvar_t r_mipskins; extern cvar_t r_mipnormalmaps; -typedef struct skeleton_s -{ - const dp_model_t *model; - matrix4x4_t *relativetransforms; -} -skeleton_t; - typedef struct skinfileitem_s { struct skinfileitem_s *next; diff --git a/progsvm.h b/progsvm.h index 6d11e350..c799dec5 100644 --- a/progsvm.h +++ b/progsvm.h @@ -248,6 +248,7 @@ typedef struct prvm_prog_fieldoffsets_s int yaw_speed; // ssqc / csqc int bouncefactor; // ssqc int bouncestop; // ssqc + int sendcomplexanimation; // ssqc int solid; // ssqc / csqc (physics) int movetype; // ssqc / csqc (physics) diff --git a/protocol.c b/protocol.c index f2c7b29d..2c155f37 100644 --- a/protocol.c +++ b/protocol.c @@ -2232,11 +2232,80 @@ void EntityState5_WriteUpdate(int number, const entity_state_t *s, int changedbi 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; @@ -2350,6 +2419,107 @@ static void EntityState5_ReadUpdate(entity_state_t *s, int number) 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) @@ -2448,6 +2618,8 @@ static int EntityState5_DeltaBits(const entity_state_t *o, const entity_state_t 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) diff --git a/protocol.h b/protocol.h index e9d5874a..29d2a88a 100644 --- a/protocol.h +++ b/protocol.h @@ -333,6 +333,7 @@ void Protocol_Names(char *buffer, size_t buffersize); #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 @@ -343,6 +344,28 @@ void Protocol_Names(char *buffer, size_t buffersize); #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, @@ -351,7 +374,7 @@ typedef enum entity_state_active_e } 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 @@ -385,6 +408,9 @@ typedef struct entity_state_s 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; @@ -713,8 +739,13 @@ void EntityFrame4_CL_ReadFrame(void); // 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 diff --git a/prvm_edict.c b/prvm_edict.c index e874eaae..6d99792b 100644 --- a/prvm_edict.c +++ b/prvm_edict.c @@ -1638,6 +1638,7 @@ void PRVM_FindOffsets(void) prog->fieldoffsets.yaw_speed = PRVM_ED_FindFieldOffset("yaw_speed"); prog->fieldoffsets.bouncefactor = PRVM_ED_FindFieldOffset("bouncefactor"); prog->fieldoffsets.bouncestop = PRVM_ED_FindFieldOffset("bouncestop"); + prog->fieldoffsets.sendcomplexanimation = PRVM_ED_FindFieldOffset("sendcomplexanimation"); prog->fieldoffsets.solid = PRVM_ED_FindFieldOffset("solid"); prog->fieldoffsets.movetype = PRVM_ED_FindFieldOffset("movetype"); diff --git a/sv_main.c b/sv_main.c index 74457fec..7751d817 100644 --- a/sv_main.c +++ b/sv_main.c @@ -311,6 +311,18 @@ prvm_required_field_t reqfields[] = {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"}, @@ -1229,6 +1241,25 @@ static qboolean SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *c 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];