Hard Light Productions Forums

Modding, Mission Design, and Coding => FS2 Open Coding - The Source Code Project (SCP) => Topic started by: zookeeper on November 18, 2011, 02:06:16 am

Title: Patch: fix ship:getAnimationDoneTime() (partially)
Post by: zookeeper on November 18, 2011, 02:06:16 am
The underpinnings for the function in modelanim.cpp were utterly broken, so here's a patch which makes it return sensible values. Due to how +acceleration works, which is a completely incomprehensible mess for seemingly no reason at all, it still won't return the correct value for animations which use +acceleration (it'll return a bigger value than it should), but it does for animations which don't use it. Possibly the animation's target angle divided by its velocity needs to equal its time*1000 as well, but I've never understood if there's any use case for doing it otherwise so whatever.

I'm not going to make the patch any fancier and cover the usage of +acceleration, because the design and implementation for that feature is simply so obnoxious that I can't even tell what it's supposed to do exactly, not to mention figuring out how the relevant code works (or rather, doesn't work). No offense to anyone. A comprehensible fix would likely entail a rewrite of those parts of the code and making +acceleration work in an entirely different way entirely.

For now, this patches things up so that getAnimationDoneTime() returns the right value in what I think is the most common use case.

Code: [Select]
Index: modelanim.cpp
===================================================================
--- modelanim.cpp (revision 7992)
+++ modelanim.cpp (working copy)
@@ -107,7 +107,7 @@
  slow_angle.a1d[0], slow_angle.a1d[1], slow_angle.a1d[2]));
 
  has_started = true;
- end_time = q->end_time;
+ end_time = timestamp(model_anim_instance_get_actual_time(q));
 }
 
 void triggered_rotation::set_to_end(queued_animation *q)
@@ -175,7 +175,7 @@
 
  if (new_queue.start == 0) {
  new_queue.start_time = timestamp();
- new_queue.end_time = timestamp( new_queue.end );
+ new_queue.end_time = timestamp( model_anim_instance_get_actual_time(&new_queue) );
 
  // if there is no delay don't bother with the queue, just start the thing
  start( &new_queue );
@@ -193,7 +193,7 @@
  // so this means that there is some sort of delay that's getting fubared becase of other queue items getting removed due to reversal
  // this animation needs to be started now!
  new_queue.start_time = timestamp();
- new_queue.end_time = timestamp( new_queue.end );
+ new_queue.end_time = timestamp( model_anim_instance_get_actual_time(&new_queue) );
 
  // if there is no delay don't bother with the queue, just start the thing
  start( &new_queue );
@@ -515,9 +515,13 @@
  int temp = 0;
 
  for (int a = 0; a < 3; a++) {
- temp = fl2i( ((3.0f * properties->vel.a1d[a] * properties->vel.a1d[a]) + (2.0f * properties->accel.a1d[a] * fabs(properties->angle.a1d[a])))
+ if (properties->accel.a1d[a] > 0.0f) {
+ temp = fl2i( ((3.0f * properties->vel.a1d[a] * properties->vel.a1d[a]) + (2.0f * properties->accel.a1d[a] * fabs(properties->angle.a1d[a])))
  / (2.0f * properties->accel.a1d[a] * properties->vel.a1d[a]) * 1000.0f )
  + properties->start;
+ } else {
+ temp = properties->end;
+ }
 
  if (temp > ret)
  ret = temp;
@@ -643,16 +647,24 @@
 
  for (int a = 0; a < 3; a++) {
  triggered_rotation tr = pss->trigger;
- float end_angle = (tr.current_ang.a1d[a]  + (((tr.rot_vel.a1d[a]*tr.rot_vel.a1d[a]) - (tr.current_vel.a1d[a]*tr.current_vel.a1d[a])) / (2*tr.rot_accel.a1d[a])));
 
- if (end_angle > tr.slow_angle.a1d[a]) {
- //T(total) =  (2V(maximum) - V(initial))/a + (S(turnpoint) - S(initial) + (V(initial)^2 - V(maximum)^2)/2a) / V(maximum)
- a_time = fl2i(((((2*tr.rot_vel.a1d[a]) - tr.current_ang.a1d[a])/tr.rot_accel.a1d[a]) + tr.slow_angle.a1d[a] - tr.current_ang.a1d[a] + (((tr.current_vel.a1d[a]*tr.current_vel.a1d[a]) - (tr.rot_vel.a1d[a]*tr.rot_vel.a1d[a])) / (2*tr.rot_accel.a1d[a])))*1000.0f);
- if (ani_time < a_time)
- ani_time = a_time;
+ if (tr.rot_accel.a1d[a] > 0.0f) {
+ float end_angle = (tr.current_ang.a1d[a]  + (((tr.rot_vel.a1d[a]*tr.rot_vel.a1d[a]) - (tr.current_vel.a1d[a]*tr.current_vel.a1d[a])) / (2*tr.rot_accel.a1d[a])));
+
+ if (end_angle > tr.slow_angle.a1d[a]) {
+ //T(total) =  (2V(maximum) - V(initial))/a + (S(turnpoint) - S(initial) + (V(initial)^2 - V(maximum)^2)/2a) / V(maximum)
+ a_time = fl2i(((((2*tr.rot_vel.a1d[a]) - tr.current_ang.a1d[a])/tr.rot_accel.a1d[a]) + tr.slow_angle.a1d[a] - tr.current_ang.a1d[a] + (((tr.current_vel.a1d[a]*tr.current_vel.a1d[a]) - (tr.rot_vel.a1d[a]*tr.rot_vel.a1d[a])) / (2*tr.rot_accel.a1d[a])))*1000.0f);
+ if (ani_time < a_time)
+ ani_time = a_time;
+ } else {
+ //T(total)  = 2 * sqrt((S(final) - S(initial))/a - ( (V(initial)/a)^2 ) / 2 ) - V(initial)/a
+ a_time = fl2i((2 * fl_sqrt(((tr.end_angle.a1d[a] - tr.current_ang.a1d[a])/tr.rot_accel.a1d[a]) - ((tr.current_vel.a1d[a] * tr.current_vel.a1d[a]) / (tr.rot_accel.a1d[a] * tr.rot_accel.a1d[a])) / 2) - (tr.current_vel.a1d[a] / tr.rot_accel.a1d[a]))*1000.0f);
+ if (ani_time < a_time)
+ ani_time = a_time;
+ }
  } else {
- //T(total)  = 2 * sqrt((S(final) - S(initial))/a - ( (V(initial)/a)^2 ) / 2 ) - V(initial)/a
- a_time = fl2i((2 * fl_sqrt(((tr.end_angle.a1d[a] - tr.current_ang.a1d[a])/tr.rot_accel.a1d[a]) - ((tr.current_vel.a1d[a] * tr.current_vel.a1d[a]) / (tr.rot_accel.a1d[a] * tr.rot_accel.a1d[a])) / 2) - (tr.current_vel.a1d[a] / tr.rot_accel.a1d[a]))*1000.0f);
+ a_time = tr.end_time - timestamp();
+
  if (ani_time < a_time)
  ani_time = a_time;
  }
@@ -663,7 +675,7 @@
  } else {
  // if it isn't moving then it's trivial.
  // no currently playing animation
- ani_time = psub->triggers[i].end + psub->triggers[i].start;
+ ani_time = 0;
  }
 
  if (ret < ani_time)
Index: modelanim.h
===================================================================
--- modelanim.h (revision 7992)
+++ modelanim.h (working copy)
@@ -145,6 +145,7 @@
 bool model_anim_start_type(ship *shipp, int animation_type, int subtype, int direction); // for all valid subsystems
 
 // how long until the animation is done
+int model_anim_instance_get_actual_time(queued_animation *properties);
 int model_anim_get_time_type(ship_subsys *pss, int animation_type, int subtype); // for a specific subsystem
 int model_anim_get_time_type(ship *shipp, int animation_type, int subtype); // for all valid subsystems
 
Title: Re: Patch: fix ship:getAnimationDoneTime() (partially)
Post by: Goober5000 on February 09, 2012, 01:01:43 am
I'm not going to make the patch any fancier and cover the usage of +acceleration, because the design and implementation for that feature is simply so obnoxious that I can't even tell what it's supposed to do exactly, not to mention figuring out how the relevant code works (or rather, doesn't work). No offense to anyone. A comprehensible fix would likely entail a rewrite of those parts of the code and making +acceleration work in an entirely different way entirely.
My feelings exactly.  I was frustrated enough trying to solve some animation issues involved in adding an animation trigger, let alone understanding the animation code itself.

I've PMmed Vasudan Admiral for a second person to test this patch.  If he's happy too, I'll commit it.
Title: Re: Patch: fix ship:getAnimationDoneTime() (partially)
Post by: Nuke on February 09, 2012, 11:30:40 pm
i tend to prefer scripting for animation, it just does more, does it better, and isnt a convoluted mess. just interpolate between 2 matrices using a 0-1 float for input. you have everything you need to implement a keyaframe animation and even ik if one was so inclined. the "animation code" system has never been reliable, it works in some builds and doesnt in others, very few modders know how to use it. most importently the feature was never completed. no variable linked animation and very few events are supported.
Title: Re: Patch: fix ship:getAnimationDoneTime() (partially)
Post by: Dragon on February 10, 2012, 01:57:19 am
IMO, somebody should give the animation system an overhaul. It's possible to do a lot of amazing things using it, but translation requires an ugly model hack and bay doors can't be opened by SEXPs, not to mention other limitations. There are also issues with rapid weapon cycling (sometimes, if you don't allow the animation to cycle before switching to the next bank, it might get stuck).
Title: Re: Patch: fix ship:getAnimationDoneTime() (partially)
Post by: Goober5000 on February 10, 2012, 02:14:37 am
Well, I recently added a sexp to trigger submodel animation.  But I agree, the actual rotation code needs to be rewritten.
Title: Re: Patch: fix ship:getAnimationDoneTime() (partially)
Post by: Spoon on February 11, 2012, 11:04:18 am
Isn't it common knowledge that the animation code is a incomplete, poorly done mess?  :p
Title: Re: Patch: fix ship:getAnimationDoneTime() (partially)
Post by: Nuke on February 11, 2012, 12:31:00 pm
i could replace the thing with scripting in an hour, if it were to be depricated, i already have a a prtial linked animation system in my cockpit script.
Title: Re: Patch: fix ship:getAnimationDoneTime() (partially)
Post by: Valathil on February 11, 2012, 02:37:56 pm
Light a fire under Swifty's ass. NEED SKELETAL ANIMATION CODE NAU
Title: Re: Patch: fix ship:getAnimationDoneTime() (partially)
Post by: Ace on February 11, 2012, 05:13:53 pm
I thought that was speeeled NAOI!!!!111

Anyway proper translation code would be good to have, for obvious 2km in size reasons....
Title: Re: Patch: fix ship:getAnimationDoneTime() (partially)
Post by: Bobboau on February 13, 2012, 02:30:41 am
acceleration (and speed for that matter) run on a simplified physics simulation, it's purpose is to allow smooth animations, so that things start and end stopped, but can move quite fast in the middle. you need a little calculus to get things working right.
Title: Re: Patch: fix ship:getAnimationDoneTime() (partially)
Post by: Nuke on February 13, 2012, 12:18:08 pm
id just use interpolation to get an intermediate matrix from start and end matrices, and animate the 0..1 intepolation value as a function of time (ramping and unramping effects could also be done). id like to see better animation though, keyframe animation, iterative ik, etc. really we cant do much with animation with the way our subobjects work. if we cant even lod subobjects separate from the ship, and we can only rotate them, and even then bounding boxes give us collision hell. some time ago i suggested having another object class derivative to the game so that you could use separate models for things like turrets, and physical subsystems, which would be more animation friendly and could be lod-ed by actual distance rather than by parent distance.
Title: Re: Patch: fix ship:getAnimationDoneTime() (partially)
Post by: Aardwolf on February 21, 2012, 11:07:41 pm
I would suggest using quaternions instead. That way you can do SLERP (spherical linear interpolation)... linearly interpolating matrices can yield some pretty freaky results... e.g. the way the camera code used to do ridiculous zooms as the camera rotated.
Title: Re: Patch: fix ship:getAnimationDoneTime() (partially)
Post by: Goober5000 on February 21, 2012, 11:17:46 pm
Ugh.  Are we going to have to sic CP5670 on this?
Title: Re: Patch: fix ship:getAnimationDoneTime() (partially)
Post by: Bobboau on February 27, 2012, 04:41:58 am
Nuke, Aardwolf, you suggest completely abandoning the existing animation system and rewriting it from scratch. Just wanted to make sure you were aware of what you were proposing.
Title: Re: Patch: fix ship:getAnimationDoneTime() (partially)
Post by: Nuke on February 27, 2012, 10:00:58 am
really its a matter of what is easier. to upgrade and maintain the existing system, or to replace it with something of superior design. the main issues are, that the system is hard to set up, breaks down often (its been broke and patched more times than i can count), and few of the coders really understand how it works (which results in "breaks down often"). if those issues can be resolved then i dont see any reason to deprecate. a new system also wont really bring anything new to the table. you will be able to do the same kind of animations. the major limits (no translations, bounding box issues, etc) have nothing to do with the system at all, and are general engine limitations. i wouldn't replace it with a new system from scratch unless it can do something the existing system cant, and for me scripting is a viable alternative.