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.
The following are the steps taken by 3ds Max when a manipulator is dragged:
3ds Max sets theHold
.
3ds Max calls Control::SetValue()
to set the new value
Repeat each time the mouse moves, until the mouse button goes up
theHold::Cancel()
, which restores the manipulator to the original positionControl::SetValue()
with the new position minus the original position3ds Max calls theHold::Cancel()
, which restores the manipulator to the original position
3ds Max calls Control::SetValue()
with the new position minus the original position
When the mouse button goes up theHold::Accept()
is called.