Animation EnvelopesAvailability LightWave 6.0 A key is a structure that holds the value of an animation parameter at a specific time. An envelope is an array of keys, along with methods for interpolation (tweening) and extrapolation (what happens to the parameter value before the first key and after the last one). The Animation Envelopes global returns functions that allow you to create and manage envelopes and their keys, including a function to display an interface to the user for editing envelopes. Other global mechanisms are built on top of envelopes. A channel contains the continuous value of a parameter as a function of time, and this is based on both the underlying envelope and on external effects, including plug-ins (channel and item motion classes, for example) that can alter channel values. And the Variant Parameters global defines a data type used by XPanel envelope controls. See also the Motions section of the Layout commands page, as well as the commands supported by the Graph and Surface Editors. Global Call LWEnvelopeFuncs *envfunc; envfunc = global( LWENVELOPEFUNCS_GLOBAL, GFUSE_TRANSIENT ); The global function returns a pointer to an LWEnvelopeFuncs. typedef struct st_LWEnvelopeFuncs { LWEnvelopeID (*create) (LWChanGroupID, const char *, int); void (*destroy) (LWEnvelopeID); LWChanGroupID (*createGroup) (LWChanGroupID parent, const char *); void (*destroyGroup)(LWChanGroupID); LWError (*copy) (LWEnvelopeID to, LWEnvelopeID from); LWError (*load) (LWEnvelopeID, LWLoadState *); LWError (*save) (LWEnvelopeID, LWSaveState *); double (*evaluate) (LWEnvelopeID, LWTime); int (*edit) (LWChanGroupID, LWEnvelopeID, int flags, void *data); int (*envAge) (LWEnvelopeID); LWEnvKeyframeID (*createKey) (LWEnvelopeID, LWTime, double value); void (*destroyKey) (LWEnvelopeID, LWEnvKeyframeID); LWEnvKeyframeID (*findKey) (LWEnvelopeID, LWTime); LWEnvKeyframeID (*nextKey) (LWEnvelopeID, LWEnvKeyframeID); LWEnvKeyframeID (*prevKey) (LWEnvelopeID, LWEnvKeyframeID); int (*keySet) (LWEnvelopeID, LWEnvKeyframeID, LWKeyTag, void *value); int (*keyGet) (LWEnvelopeID, LWEnvKeyframeID, LWKeyTag, void *value); int (*setEnvEvent) (LWEnvelopeID, LWEnvEventFunc, void *data); int (*egSet) (LWEnvelopeID, LWChanGroupID, int tag, void *value); int (*egGet) (LWEnvelopeID, LWChanGroupID, int tag, void *value); } LWEnvelopeFuncs;
Event Callback The setEnvEvent function lets you set a callback that LightWave will call whenever an envelope is modified. The callback looks like this. typedef int (*LWEnvEventFunc) (void *data, LWEnvelopeID env, LWEnvEvent event, void *eventData); data is what you passed as the third argument to the setEnvEvent function. The eventData depends on the event, which can be one of the following. LWEEVNT_DESTROY LWEEVNT_KEY_INSERT LWEEVNT_KEY_DELETE LWEEVNT_KEY_VALUE LWEEVNT_KEY_TIME For the KEY events, the eventData is the LWKeyframeID. For the DESTROY event, the eventData is currently undefined and the LWEnvelopeID is invalid. When your callback is called for a DESTROY event, the envelope has already been destroyed, and you should ensure that you invalidate any of your own references to the envelope. Example The envelope sample shows how envelopes are interpolated. It also uses the the envelope global functions to create and examine the envelope to be interpolated. The following code fragment finds a key for the red level of the first light at 5 seconds. If the light doesn't have a color envelope, we add it using the AddEnvelope command, and if there's no key at 5 seconds, we create it. The key value (the red level) is set to 0.75. In order to do this, we need to find the item ID for the first light, the channel group for that light, the red channel in the channel group, the underlying envelope for the red channel, and the key in that envelope at 5 seconds, if it exists. In addition to the envelope global, we use the channel info, item info and message globals. #include <lwserver.h> #include <lwenvel.h> #include <lwhost.h> LWEnvelopeFuncs *envf; LWChannelInfo *chinfo; LWItemInfo *iteminfo; LWMessageFuncs *msgf; LWItemID id; LWChanGroupID group; LWEnvelopeID envred; LWEnvKeyframeID key; char buf[ 128 ]; double val; chinfo = global( LWCHANNELINFO_GLOBAL, GFUSE_TRANSIENT ); envf = global( LWENVELOPEFUNCS_GLOBAL, GFUSE_TRANSIENT ); iteminfo = global( LWITEMINFO_GLOBAL, GFUSE_TRANSIENT ); msg = global( LWMESSAGEFUNCS_GLOBAL, GFUSE_TRANSIENT ); if ( !chinfo || !envf || !iteminfo || !msgf ) return AFUNC_BADGLOBAL; id = iteminfo->first( LWI_LIGHT, NULL ); group = iteminfo->chanGroup( id ); envred = findEnv( group, "Color.R" ); if ( !envred ) { sprintf( buf, "SelectItem %x", id ); local->evaluate( local->data, buf ); local->evaluate( local->data, "AddEnvelope Color.R" ); envred = findEnv( group, "Color.R" ); } if ( !envred ) { msgf->info( "Couldn't create an envelope for", iteminfo->name( id )); return AFUNC_OK; } val = 0.75; key = envf->findKey( envred, 5.0 ); if ( !key ) key = envf->createKey( envred, 5.0, val ); if ( key ) envf->keySet( envred, key, LWKEY_VALUE, &val ); else { sprintf( buf, "%s.Color.R", iteminfo->name( id )); msg->info( "Couldn't create a key in", buf ); } Our findEnv function simply loops through the channels in a channel group searching for a given channel name. If a match is found, it returns the envelope ID for the channel. LWEnvelopeID findEnv( LWChanGroupID group, char *name ) { LWChannelID chan; chan = chinfo->nextChannel( group, NULL ); while ( chan ) { if ( !strcmp( chinfo->channelName( chan ), name )) return chinfo->channelEnvelope( chan ); chan = chinfo->nextChannel( group, chan ); } return NULL; } |