Synchronising SSQC and CSQC animations

Discuss CSQC related programming.

Moderator: InsideQC Admins

Synchronising SSQC and CSQC animations

Postby OneManClan » Wed Jan 18, 2017 10:59 am

OBJECTIVE: To replace the player.mdl with a (new) player.iqm. Why? Skeletal animation blending, separate head/torso control, new animations, ragdoll etc

PROBLEM 1: Half of the current AGR playerbase insist on using clients such as EZQuake, Fuhquake etc. These clients cannot use iqms, so completely replacing the existing (SSQC) player.mdl is not an option.

SOLUTION TO PROBLEM 1: Use CSQC's deltalisten to intercept SSQC's player.mdl, and substitute a CSQC player.iqm. CSQC clients see the new iqm, and EZQuakers are unaffected. This is the current situation. I still have the regular quake.mdl, animating normally in SSQC. I've exported captn bubs's player.blender file as an IQM, and using a *.framegroups file, managed to get the iqm to replicate all of the SSQC mdl's movements. IIUC, the SSQC sends self.frame information to the CSQC (deltalisten'ed) entity every .. er.. frame ('tick'?), and the CSQC translates this information into poses in the iqm, as specified in the frameworks file. All works great except:

PROBLEM 2: I want to implement skeletal animation, and animate the IQM using it's 'embedded' animations (ie rather than use a framegroups file) (Apparently framegroups files are only necessary if there's a problem with the exporting). Anyway, I made a new version of the iqm which has all the quake animations as seperate 'actions'. My idea was to send the .frame information from SSQC to CSQC as a STAT (before I realised that the .frame information gets sent anyway) :

Code: Select all
float latest_frame = getstatf(STAT_FRAME); // get the frame from SSQC
self.frame = WhatAnimIsThat(latest_frame);// translate it to what the new animation

and then, run the correct animation in CSQC via something like:

Code: Select all
// receives the current .frame, and returns which (iqm) animation to run
float (float the_frame) WhatAnimIsThat =
      case 0:
      case 1:
      case 2:
      case 3:
      case 4:
      case 5: return frameforname(self.modelindex,"axrun"); // this is a NEW animation embedded in the new iqm
      case 6:
      case 7:
      case 8:
      case 9:
      case 10:
      case 11: return frameforname(self.modelindex,"rockrun"); // this is a NEW animation embedded in the NEW iqm

// etc

If this were a pure CSQC entity, IIUC, the way to run an iqm animation is:

self.frame1time += frametime;

However, deltalistened entities (such as the player.iqm in this case) receive self.frame information every tick(packet?), which is overrides/interferes my attempt to control the .frame info entirely within CSQC

The question is: Does anyone have any tips, hints, or suggestions as to how to synchronise the animations of a (SSQC) player.mdl with a (CSQC + deltalisten) *.iqm substitute?
Posts: 243
Joined: Sat Feb 28, 2009 2:38 pm

Re: Synchronising SSQC and CSQC animations

Postby OneManClan » Thu Jan 19, 2017 12:19 am

[Note: There seem to be three separate meanings for the term 'frame' at the moment:

A: a SSQC *.mdl's individual pose, from an animation (eg a regular ssqc monsters '.frame')

B: a CSQC iqm's complete animation sequence (eg an iqms 'axattack' '.frame' consists of ALL the poses are part of the 'axattack', animation. IIUC you can refer to the entire animation as 'the axattack frame')

C: "The common terms for one crank of the game loop are “tick” and “frame”"

So for now.. to minimise confusion, in this post, I'll refer to A as the 'MdlFrame', B as the 'IqmFrame', and C as the 'GameFrame']

Ok, Spike has informed me that

Code: Select all
self.frame = frameforname(self.modelindex, "foo");

does NOT restart the IqmFrame, so it can be run every GameFrame. Therefore we can do this:

Code: Select all
       // CSQC runs every GameFrame
string incoming_mdl_frame = WhatAnimIsThat(self.frame);
       // is the SSQC entity's current .frame (ie the MdlFrame) NOT part of the current IqmFrame?
       if(self.current_animation_name != incoming_mdl_frame)
      // if we're here, we need to change the IqmFrame
      // debugging
print("Anim changed to = ", incoming_mdl_frame, "\n"); // prints everytime SSQC's incoming MdlFrame contains a MdlFrame which belongs to a different IqmFrame
      self.frame = frameforname(self.modelindex, incoming_mdl_frame); // change the IqmFrame

      self.current_animation_name = incoming_mdl_frame; // storage, so we can test next GameFrame
       // the MdlFrame info just received is still part of the current IqmFrame
      //overwrite the MdlFrame info, preventing it from changing the current IqmFrame
      self.frame = frameforname(self.modelindex, self.current_animation_name); // This will not restart the IqmFrame
Posts: 243
Joined: Sat Feb 28, 2009 2:38 pm

Return to CSQC Programming

Who is online

Users browsing this forum: No registered users and 1 guest