Undo and Redo in a Controller

Controllers, like objects and modifiers, need to be able to undo and redo themselves. Whenever a controller is about to modify its data, it checks the state of the global Hold object (theHold) to see if it is holding. If so it must register a RestoreObject with the hold. Controllers also support another type of undo and redo through two methods: Control::CommitValue() and Control::RestoreValue().

The purpose of this 'inner' hold and restore buffer is not to hold and restore the entire state of the controller, but to hold and restore the value of the controller at a single instant in time. When Control::SetValue() is called on a controller with the commit parameter equal to zero, the controller records the new value, but does not necessarily modify any data. For example, a keyframe controller doesn't actually generate a new key -- it just updates a cache it maintains. Then, if the controller is asked to evaluate itself at the exact same TimeValue for which the controller was just set, it can just return the cached value.

The Control::SetValue() method will simply throw out the temporary value whereas the Control::CommitValue() method will cause the value to be actually committed (a key generated in the case of a keyframe controller).

The purpose of this inner hold and restore is for iterative procedures that need to set values many times at a single TimeValue and don't want to incur the overhead of things like recalculating the tangents at adjacent keys. Some examples of these types of procedures are inverse kinematics and collision detection.

Hold System Example

The following are the steps taken by 3ds Max when a manipulator is dragged:

  1. 3ds Max sets theHold.
  2. 3ds Max calls Control::SetValue() to set the new value
  3. Repeat each time the mouse moves, until the mouse button goes up
    1. 3ds Max calls theHold::Cancel(), which restores the manipulator to the original position
    2. 3ds Max calls Control::SetValue() with the new position minus the original position
  4. 3ds Max calls theHold::Cancel(), which restores the manipulator to the original position
  5. 3ds Max calls Control::SetValue() with the new position minus the original position
  6. When the mouse button goes up theHold::Accept() is called.

See Also