From: divverent Date: Sat, 12 Nov 2011 11:17:38 +0000 (+0000) Subject: complexanimation now beginning to be suitable for SVQC use X-Git-Tag: xonotic-v0.6.0~164 X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=3d83121189b2d615a9b303b926b85f05f322ed81;p=xonotic%2Fdarkplaces.git complexanimation now beginning to be suitable for SVQC use - only set E5_COMPLEXANIMATION flag when required to save a LOT of bandwidth - don't also send a legacy frame number when using complex animation to save a bit more - no more support of "anims that start in the future", use a QC think function to handle them - fix wraparound logic for complex animation (if a model animation is shorter than 30 sec, it won't jerk when playing the same anim for over a minute) Bandwidth use per update message: - simple anim: 1 byte - 1 blends: 5 bytes - 2 blends: 11 bytes - 3 blends: 16 bytes - 4 blends: 21 bytes - skeletonobject: 4 + 12*bonecount bytes git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@11546 d7cf8633-e32d-0410-b094-e92efae38249 ::stable-branch::merge=bfebdee6f90da32974e4305a33ed15c72ad0a5dc --- diff --git a/protocol.c b/protocol.c index 3e384e16..8cc1acd1 100644 --- a/protocol.c +++ b/protocol.c @@ -2058,6 +2058,31 @@ static int EntityState5_Priority(entityframe5_database_t *d, int stateindex) return bound(1, priority, ENTITYFRAME5_PRIORITYLEVELS - 1); } +static double anim_reducetime(double t, double frameduration, double maxtime) +{ + if(t < 0) // clamp to non-negative + return 0; + if(t <= maxtime) // time can be represented normally + return t; + if(frameduration == 0) // don't like dividing by zero + return t; + if(maxtime <= 2 * frameduration) // if two frames don't fit, we better not do this + return t; + t -= frameduration * ceil((t - maxtime) / frameduration); + // now maxtime - frameduration < t <= maxtime + return t; +} + +// see VM_SV_frameduration +static double anim_frameduration(dp_model_t *model, int framenum) +{ + if (!model || !model->animscenes || framenum < 0 || framenum >= model->numframes) + return 0; + if(model->animscenes[framenum].framerate) + return model->animscenes[framenum].framecount / model->animscenes[framenum].framerate; + return 0; +} + void EntityState5_WriteUpdate(int number, const entity_state_t *s, int changedbits, sizebuf_t *msg) { unsigned int bits = 0; @@ -2226,50 +2251,54 @@ void EntityState5_WriteUpdate(int number, const entity_state_t *s, int changedbi 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)); + dp_model_t *model = SV_GetModelByIndex(s->modelindex); + 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)(anim_reducetime(sv.time - s->framegroupblend[0].start, anim_frameduration(model, s->framegroupblend[0].frame), 65.535) * 1000.0)); + MSG_WriteShort(msg, (int)(anim_reducetime(sv.time - s->framegroupblend[1].start, anim_frameduration(model, s->framegroupblend[1].frame), 65.535) * 1000.0)); + MSG_WriteShort(msg, (int)(anim_reducetime(sv.time - s->framegroupblend[2].start, anim_frameduration(model, s->framegroupblend[2].frame), 65.535) * 1000.0)); + MSG_WriteShort(msg, (int)(anim_reducetime(sv.time - s->framegroupblend[3].start, anim_frameduration(model, s->framegroupblend[3].frame), 65.535) * 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)(anim_reducetime(sv.time - s->framegroupblend[0].start, anim_frameduration(model, s->framegroupblend[0].frame), 65.535) * 1000.0)); + MSG_WriteShort(msg, (int)(anim_reducetime(sv.time - s->framegroupblend[1].start, anim_frameduration(model, s->framegroupblend[1].frame), 65.535) * 1000.0)); + MSG_WriteShort(msg, (int)(anim_reducetime(sv.time - s->framegroupblend[2].start, anim_frameduration(model, s->framegroupblend[2].frame), 65.535) * 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)(anim_reducetime(sv.time - s->framegroupblend[0].start, anim_frameduration(model, s->framegroupblend[0].frame), 65.535) * 1000.0)); + MSG_WriteShort(msg, (int)(anim_reducetime(sv.time - s->framegroupblend[1].start, anim_frameduration(model, s->framegroupblend[1].frame), 65.535) * 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)(anim_reducetime(sv.time - s->framegroupblend[0].start, anim_frameduration(model, s->framegroupblend[0].frame), 65.535) * 1000.0)); + } } } if (bits & E5_TRAILEFFECTNUM) @@ -2411,7 +2440,7 @@ static void EntityState5_ReadUpdate(entity_state_t *s, int number) 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[0].start = cl.time - (unsigned short)MSG_ReadShort() * (1.0f / 1000.0f); s->framegroupblend[1].start = 0; s->framegroupblend[2].start = 0; s->framegroupblend[3].start = 0; @@ -2425,8 +2454,8 @@ static void EntityState5_ReadUpdate(entity_state_t *s, int number) 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[0].start = cl.time - (unsigned short)MSG_ReadShort() * (1.0f / 1000.0f); + s->framegroupblend[1].start = cl.time - (unsigned 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); @@ -2439,9 +2468,9 @@ static void EntityState5_ReadUpdate(entity_state_t *s, int number) 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[0].start = cl.time - (unsigned short)MSG_ReadShort() * (1.0f / 1000.0f); + s->framegroupblend[1].start = cl.time - (unsigned short)MSG_ReadShort() * (1.0f / 1000.0f); + s->framegroupblend[2].start = cl.time - (unsigned 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); @@ -2453,10 +2482,10 @@ static void EntityState5_ReadUpdate(entity_state_t *s, int number) 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].start = cl.time - (unsigned short)MSG_ReadShort() * (1.0f / 1000.0f); + s->framegroupblend[1].start = cl.time - (unsigned short)MSG_ReadShort() * (1.0f / 1000.0f); + s->framegroupblend[2].start = cl.time - (unsigned short)MSG_ReadShort() * (1.0f / 1000.0f); + s->framegroupblend[3].start = cl.time - (unsigned 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); @@ -2596,7 +2625,25 @@ static int EntityState5_DeltaBits(const entity_state_t *o, const entity_state_t 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; + { + if ((o->skeletonobject.model && o->skeletonobject.relativetransforms) != (n->skeletonobject.model && n->skeletonobject.relativetransforms)) + { + bits |= E5_COMPLEXANIMATION; + } + else if (o->skeletonobject.model && o->skeletonobject.relativetransforms) + { + if(o->modelindex != n->modelindex) + bits |= E5_COMPLEXANIMATION; + else if(o->skeletonobject.model->num_bones != n->skeletonobject.model->num_bones) + bits |= E5_COMPLEXANIMATION; + else if(memcmp(o->skeletonobject.relativetransforms, n->skeletonobject.relativetransforms, o->skeletonobject.model->num_bones * sizeof(*o->skeletonobject.relativetransforms))) + bits |= E5_COMPLEXANIMATION; + } + else if (memcmp(o->framegroupblend, n->framegroupblend, sizeof(o->framegroupblend))) + { + bits |= E5_COMPLEXANIMATION; + } + } if (o->traileffectnum != n->traileffectnum) bits |= E5_TRAILEFFECTNUM; } diff --git a/sv_main.c b/sv_main.c index c40131b5..80fafb58 100644 --- a/sv_main.c +++ b/sv_main.c @@ -1355,6 +1355,7 @@ static qboolean SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *c cs->framegroupblend[2].lerp = PRVM_serveredictfloat(ent, lerpfrac3); cs->framegroupblend[3].lerp = PRVM_serveredictfloat(ent, lerpfrac4); cs->framegroupblend[0].lerp = 1.0f - cs->framegroupblend[1].lerp - cs->framegroupblend[2].lerp - cs->framegroupblend[3].lerp; + cs->frame = 0; // don't need the legacy frame } cs->light[0] = light[0];