envelope (lx_envelope.hpp)

From The Foundry MODO SDK wiki
Jump to: navigation, search
There are security restrictions on this page


Contents

Envelopes

Envelopes are an abstract data type that represents a time-varying signal. They are constructed from a series of curves interpolating keyframes using a variety of different shapes. The envelope API provides methods for managing, evaluating and altering envelopes.

The envelope interface is split into two parts. The ILxEnvelope controls the gross attributes of the envelope and permits evaluation for any input value. This can also spawn a key iterator which allows the keys to be walked in sequence, searched, queried and modified.

Envelope

The envelope interface provides access to the overall attributes of the envelope shape, evaluation, and a keyframe accessor.

(1) SDK: LXu_ENVELOPE define
 #define LXu_ENVELOPE            "E39EB451-6C35-47F4-8A7D-FF96671C0DEF"

The IsInt() method returns 1 for integer-valued type envelopes, 0 otherwise.

(2) SDK: Envelope::IsInt
         LXxMETHOD( unsigned,
 IsInt) (
         LXtObjectID              self);

This method allocates a new keyframe enumerator, allowing multiple clients to query the same envelope.

(3) SDK: Envelope::Enumerator
         LXxMETHOD( LxResult,
 Enumerator) (
         LXtObjectID              self,
         void                   **ppvObj);

These two methods allow the envelope to be evaluated. The input value is given as "time" although it is any independent parameter. the correct method must be called based on the envelopes numeric type.

(4) SDK: Envelope::EvaluateF, etc.
         LXxMETHOD( LxResult,
 EvaluateF) (
         LXtObjectID              self,
         double                   time,
         double                  *value);
 
         LXxMETHOD( LxResult,
 EvaluateI) (
         LXtObjectID              self,
         double                   time,
         int                     *value);

The end behaviors determine what value the envelope takes outside the range of keyframes.

RESET A default value, or may be just zero.
CONSTANT The value of the first or last keyframe. For first or last keys set to "Auto" or "Auto Flat" the slopes of the keys will be adjusted to provide a smooth interpolation to or from the behavior.
REPEAT The values in the keyframe range repeating continuously.
OSCILLATE Like repeat, but the values run forwards and backward alternately. For first or last keys set to "Auto" or "Auto Flat" the slopes of the keys will be adjusted to provide a smooth interpolation to or from the behavior.
OFFSETREPEAT Like repeat, but the values are offset in each cycle by the difference between the first and last keyframes. For first or last keys set to "Auto" or "Auto Flat" the slopes of the keys will be adjusted to provide a smooth interpolation to or from the behavior.
LINEAR Linear interpolation from the slope at the nearest keyframe.
NONE Indicates that the envelope does not exist before or after the explicit keyframe range. This isbe used by motion evaluation code to decide whether to use the envelope for a channel or to look up the parent envelope or default value.
CONSTANT_KEEP_SLOPE As for constant except that the slopes of the first or last keys are not changed.
OSCILLATE_KEEP_SLOPE As for oscillate except that the slopes of the first or last keys are not changed.
OFFSETREPEAT_KEEP_SLOPE As for offset repeat except that the slopes of the first or last keys are not changed.
(5) SDK: Types
 typedef unsigned        LXtEndBehavior;
 
 #define LXiENV_RESET                    0
 #define LXiENV_CONSTANT                 1
 #define LXiENV_REPEAT                   2
 #define LXiENV_OSCILLATE                3
 #define LXiENV_OFFSETREPEAT             4
 #define LXiENV_LINEAR                   5
 #define LXiENV_NONE                     6
 #define LXiENV_CONSTANT_KEEP_SLOPE      LXiENV_NONE
 #define LXiENV_OSCILLATE_KEEP_SLOPE     7
 #define LXiENV_OFFSETREPEAT_KEEP_SLOPE  8

The envelopes end behavior is read and set with these methods. The side can be IN or OUT to select the behavior for times prior to the first key frame or the behavior after the last keyframe, respectively. The behavior for both can be set by specifying BOTH.

(6) SDK: Envelope::EndBehavior, etc.
         LXxMETHOD( unsigned int,
 EndBehavior) (
         LXtObjectID              self,
         unsigned int             side);
 
         LXxMETHOD( LxResult,
 SetEndBehavior) (
         LXtObjectID              self,
         unsigned int             behavior,
         unsigned int             side);

(7) SDK: LXiENVSIDE_IN, etc. defines
 #define LXiENVSIDE_IN                   1
 #define LXiENVSIDE_OUT                  2
 #define LXiENVSIDE_BOTH                 3

For envelopes which can be edited this removes all the keys.

(8) SDK: Envelope::Clear
         LXxMETHOD( LxResult,
 Clear) (
         LXtObjectID              self);

(9) SDK: LXiENVv_INTERP_CURVE, etc. defines

(10) SDK: Envelope::Interpolation
         LXxMETHOD( unsigned int,
 Interpolation) (
         LXtObjectID              self);

(11) SDK: Envelope::SetInterpolation
         LXxMETHOD( LxResult,
 SetInterpolation) (
         LXtObjectID              self,
         unsigned int             type);

Envelope User Class

The user class for envelopes adds a method to spawn an enumerator directly to a keyframe user object. It returns true for success.

(12) SDK: CLxUser_Envelope::GetKeyframe method
         bool
 GetKeyframe (
         CLxLoc_Keyframe         *key)
 {
         LXtObjectID              obj;
 
         if (LXx_OK (Enumerator (&obj)))
                 return key->take (obj);
 
         clear ();
         return false;
 }

It also adds alternate methods for evaluating the envelope at a given time.

(13) SDK: CLxUser_Envelope::IntValue method
         int
 IntValue (
         double                   time)
 {
         int                      val = 0;
 
         EvaluateI (time, &val);
         return val;
 }
 
         double
 Value (
         double                   time)
 {
         double                   val = 0.0;
 
         EvaluateF (time, &val);
         return val;
 }

Empty Envelope Python user class.

(14) PY: empty Envelope user class
 pass

Keyframe Traversal

(15) SDK: LXu_KEYFRAME define
 #define LXu_KEYFRAME            "D1D0261F-22CF-4E5D-822E-76B5DEC98AE4"

The keyframe interface has a state which is a current key, so it acts as an iterator. The next four methods set the current key based on its position in the sequence, or relative to the current key. They return LXe_NOTFOUND on errors.

(16) SDK: Keyframe::First, etc.
         LXxMETHOD( LxResult,
 First) (
         LXtObjectID              self);
 
         LXxMETHOD( LxResult,
 Last) (
         LXtObjectID              self);
 
         LXxMETHOD( LxResult,
 Next) (
         LXtObjectID              self);
 
         LXxMETHOD( LxResult,
 Previous) (
         LXtObjectID              self);

Find() selects a key at or near the current time. If side is IN then the key prior or equal to the time will become current. OUT gets the key after the given time. For BOTH the key must be exactly at the requested time.

(17) SDK: Keyframe::Find
         LXxMETHOD( LxResult,
 Find) (
         LXtObjectID              self,
         double                   time,
         unsigned int             side);

Keyframe Values

The time (or other independent parameter) of the key can be read with this method.

(18) SDK: Keyframe::GetTime
         LXxMETHOD( LxResult,
 GetTime) (
         LXtObjectID              self,
         double                  *time);

This method returns flags for which attributes of the key are broken and are different for the incoming and outgoing sides of the key. If the value of the key itself is broken, the side flag indicates which side of the key controls the value exactly at the given time.

(19) SDK: Keyframe::GetBroken
         LXxMETHOD( LxResult,
 GetBroken) (
         LXtObjectID              self,
         unsigned int            *breaks,
         unsigned int            *side);

(20) SDK: LXfKEYBREAK_VALUE, etc. defines
 #define LXfKEYBREAK_VALUE               (1<<0)
 #define LXfKEYBREAK_SLOPE               (1<<1)
 #define LXfKEYBREAK_WEIGHT              (1<<2)

Read the value of the key as a float or int for either side of the key. For unbroken keys this will be the same.

(21) SDK: Keyframe::GetValueF, etc.
         LXxMETHOD( LxResult,
 GetValueF) (
         LXtObjectID              self,
         double                  *value,
         unsigned int             side);
 
         LXxMETHOD( LxResult,
 GetValueI) (
         LXtObjectID              self,
         int                     *value,
         unsigned int             side);

The slope type, slope and weight may likewise be read for the current key.

(22) SDK: Keyframe::GetSlopeType, etc.
         LXxMETHOD( LxResult,
 GetSlopeType) (
         LXtObjectID              self,
         LXtSlopeType            *type,
         unsigned int            *weighted,
         unsigned int             side);
 
         LXxMETHOD( LxResult,
 GetSlope) (
         LXtObjectID              self,
         double                  *slope,
         unsigned int             side);
 
         LXxMETHOD( LxResult,
 GetWeight) (
         LXtObjectID              self,
         double                  *weight,
         unsigned int             side);

The slope can have one of the following values.

LXiSLOPE_DIRECT the slope of the tangent is set based on the value stored in the key.
LXiSLOPE_AUTO the slope of the tangent is calculated automatically with regard to surrounding keys. This is similar to the slope adjustments made by TCB curves.
LXiSLOPE_LINEAR_IN the slope of the tangent is calculated to align with the previous key's value.
LXiSLOPE_LINEAR_OUT the slope of the tangent is calculated to align with the next key's value.
LXiSLOPE_FLAT the slope of the tangent is set to zero.
LXiSLOPE_AUTOFLAT the same as auto but if a neighboring key has the same value as the key the slope is set to zero.
LXiSLOPE_STEPPED Maintains the value of the previous key between pairs of keys.
(23) SDK: Types
 typedef unsigned        LXtSlopeType;
 
 #define LXiSLOPE_DIRECT         0
 #define LXiSLOPE_AUTO           1
 #define LXiSLOPE_LINEAR_IN      2
 #define LXiSLOPE_LINEAR_OUT     3
 #define LXiSLOPE_FLAT           4
 #define LXiSLOPE_AUTOFLAT       5
 #define LXiSLOPE_STEPPED        6

The SlopeType() method also returns an optional weighted flag, which is true if the weight is set manually rather than being computed automatically.

Keyframe Modification

This alters the time (or independent parameter) of the key, potentially changing its relative position in the sequence of keys.

(24) SDK: Keyframe::SetTime
         LXxMETHOD( LxResult,
 SetTime) (
         LXtObjectID              self,
         double                   time);

These methods allow the various parameters of the keyframe to be set. Breaking and unbreaking are controlled implicitly with the 'side' parameter. Setting the side to IN or OUT will break the parameter and only affect the specified side. Setting the side to BOTH will unbreak the parameter. The last side set when breaking the value will be the controlling side for the key.

(25) SDK: Keyframe::SetValueF, etc.
         LXxMETHOD( LxResult,
 SetValueF) (
         LXtObjectID              self,
         double                   value,
         unsigned int             side);
 
         LXxMETHOD( LxResult,
 SetValueI) (
         LXtObjectID              self,
         int                      value,
         unsigned int             side);
 
         LXxMETHOD( LxResult,
 SetSlope) (
         LXtObjectID              self,
         double                   slope,
         unsigned int             side);
 
         LXxMETHOD( LxResult,
 SetSlopeType) (
         LXtObjectID              self,
         LXtSlopeType             type,
         unsigned int             side);

This will set the weight for the key unless 'reset' is true, in which case the weight will be set back to automatic.

(26) SDK: Keyframe::SetWeight
         LXxMETHOD( LxResult,
 SetWeight) (
         LXtObjectID              self,
         double                   weight,
         unsigned int             reset,
         unsigned int             side);

Adding and Removing Keys

These methods allow keys to be created at the given time (or other independent parameter) and value.

(27) SDK: Keyframe::AddF, etc.
         LXxMETHOD( LxResult,
 AddF) (
         LXtObjectID              self,
         double                   time,
         double                   value);
 
         LXxMETHOD( LxResult,
 AddI) (
         LXtObjectID              self,
         double                   time,
         int                      value);

This deletes the current key.

(28) SDK: Keyframe::Delete
         LXxMETHOD( LxResult,
 Delete) (
         LXtObjectID              self);

Keyframe User Class

The keyframe user class has a special constructor that takes an envelope user object, from which the enumerator is extracted.

(29) SDK: CLxUser_Keyframe::CLxUser_Keyframe method
 CLxUser_Keyframe (
         CLxLoc_Envelope         &env)
 {
         LXtObjectID              obj;
 
         _init ();
         if (env.test () && LXx_OK (env.Enumerator (&obj)))
                 take (obj);
 }

There is also a function to set the enumerator given any COM object. The method will clear the enumerator and return false if the object does not present an ILxEnvelope interface.

(30) SDK: CLxUser_Keyframe::fromEnvObject method
         bool
 fromEnvObject (
         ILxUnknownID             obj)
 {
         CLxLoc_Envelope          env (obj);
         LXtObjectID              enObj;
 
         if (env.test () && LXx_OK (env.Enumerator (&enObj)))
                 return take (enObj);
 
         clear ();
         return false;
 }

Easier method for getting the time (or independent parameter) of the key. This should be fine as long as you know there is a valid current key.

(31) SDK: CLxUser_Keyframe::Time method
         double
 Time ()
 {
         double                   time = 0.0;
 
         GetTime (&time);
         return time;
 }

Alternate methods for reading the value in the 90% case of an unbroken key.

(32) SDK: CLxUser_Keyframe::Value method
         LxResult
 Value (
         double                  *val)
 {
         return GetValueF (val, LXiENVSIDE_IN);
 }
 
         double
 Value ()
 {
         double                   val = 0.0;
 
         GetValueF (&val, LXiENVSIDE_IN);
         return val;
 }
 
         LxResult
 Value (
         int                     *val)
 {
         return GetValueI (val, LXiENVSIDE_IN);
 }
 
         int
 IntValue ()
 {
         int                      val = 0;
 
         GetValueI (&val, LXiENVSIDE_IN);
         return val;
 }

The breaking and controlling side can be read independently.

(33) SDK: CLxUser_Keyframe::Broken method
         unsigned int
 Broken ()
 {
         unsigned int             flags = 0;
 
         GetBroken (&flags, 0);
         return flags;
 }
 
         unsigned int
 ActiveSide ()
 {
         unsigned int             flags, side = LXiENVSIDE_BOTH;
 
         GetBroken (&flags, &side);
         return side;
 }

The other key attributes can be read without error checking, although sidedness tends to be important for these so that is provided.

(34) SDK: CLxUser_Keyframe::Slope method
         double
 Slope (
         unsigned int             side)
 {
         double                   val = 0.0;
 
         GetSlope (&val, side);
         return val;
 }
 
         LXtSlopeType
 SlopeType (
         unsigned int             side)
 {
         LXtSlopeType             val = LXiSLOPE_DIRECT;
 
         GetSlopeType (&val, 0, side);
         return val;
 }
 
         bool
 Weighted (
         unsigned int             side)
 {
         LXtSlopeType             val;
         unsigned int             test;
 
         GetSlopeType (&val, &test, side);
         return (test != 0);
 }
 
         double
 Weight (
         unsigned int             side)
 {
         double                   val = 0.0;
 
         GetWeight (&val, side);
         return val;
 }

Empty Keyframe Python user class.

(35) PY: empty Keyframe user class
 pass

Gradient Stacks

This is needed to have an object to evaluate in the SDK context.

(36) SDK: LXu_GRADIENTFILTER define
 #define LXu_GRADIENTFILTER      "ACCD7C33-D246-4FE5-ABA0-079F225BBB34"

(37) SDK: GradientFilter::Evaluate, etc.
         LXxMETHOD( double,
 Evaluate) (
         LXtObjectID              self,
         double                   inVal);
 
     LXxMETHOD( LxResult,
 AddRef) (
     LXtObjectID          self);
 
     LXxMETHOD( LxResult,
 Release) (
           LXtObjectID            self);

(38) SDK: empty GradientFilter User Class

Empty GradientFilter Python user class.

(39) PY: empty GradientFilter user class
 pass