Envelope (lx-envelope.hpp)
Contents
- 1 Envelopes
- 1.1 Envelope
- 1.1.1 (1) SDK: LXu_ENVELOPE define
- 1.1.2 (2) SDK: Envelope::IsInt
- 1.1.3 (3) SDK: Envelope::Enumerator
- 1.1.4 (4) SDK: Envelope::EvaluateF, etc.
- 1.1.5 (5) SDK: Types
- 1.1.6 (6) SDK: Envelope::EndBehavior, etc.
- 1.1.7 (7) SDK: LXiENVSIDE_IN, etc. defines
- 1.1.8 (8) SDK: Envelope::Clear
- 1.1.9 (9) SDK: LXiENVv_INTERP_CURVE, etc. defines
- 1.1.10 (10) SDK: Envelope::Interpolation
- 1.1.11 (11) SDK: Envelope::SetInterpolation
- 1.2 Envelope User Class
- 1.3 Keyframe Traversal
- 1.4 Keyframe Values
- 1.5 Keyframe Modification
- 1.6 Adding and Removing Keys
- 1.7 Keyframe User Class
- 1.7.1 (29) SDK: CLxUser_Keyframe::CLxUser_Keyframe method
- 1.7.2 (30) SDK: CLxUser_Keyframe::fromEnvObject method
- 1.7.3 (31) SDK: CLxUser_Keyframe::Time method
- 1.7.4 (32) SDK: CLxUser_Keyframe::Value method
- 1.7.5 (33) SDK: CLxUser_Keyframe::Broken method
- 1.7.6 (34) SDK: CLxUser_Keyframe::Slope method
- 1.7.7 (35) PY: empty Keyframe user class
- 1.8 Gradient Stacks
- 1.1 Envelope
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
#define LXiENVv_INTERP_CURVE 0 #define LXiENVv_INTERP_LINEAR 1 #define LXiENVv_INTERP_STEPPED 2
(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