Data Attachment


Introduction
Often it is desirable to attach some user defined data to a messiah Entity. Typically you would do this by creating some sort of table where the Entity ID is used as a lookup for the data. messiah makes this a lot easier however by providing you with the ability to attach any arbitrary data directly to an Entity. As an added bonus messiah will handle all of the memory allocation and de-allocation for you. The memory will be allocated when you create the attachment and freed when the Entity is destroyed.
Data Allocation
Let's suppose for example that you had an Effect Module that needed to compute a per-vertex weight so that it could deform an FXobject. Keeping in mind that an Effect Module can have many target objects it would not be wise to store those weight buffers with your Effect Module data, rather they belong on the target objects. For our purposes we'll assume that each vertex will have associated with it an representing it's weight, the following code illustrates how we will allocate that weight buffer and at the same time have it attached to the target:

// global key
FXint           global_key;

yourfunc()
{
        // assume 'effect' and 'target' are already initialized
        FXfloat *buffer = NULL;
        FXint   num_points = 0;
        
        fxMeshNumPoints( target, &num_points, FX_NOFLAG );

        if( !(buffer = (FXfloat *)fxDataCreate( target, &global_key, effect, num_points * sizeof(FXfloat))) )
        {
                // report allocation error
        }
        //...
}
Note first of all that global_key is a global variable or a static local variable, in other words: it cannot go out of scope! The reason for this is that we are using its memory address as a unique key, and this uniqueness is only guranteed if the variable will never go out of scope. The type of variable used for the key is completely arbitrary, its value is never used, it is only it's address that we are concerned with. This key will allow us to identify and retrieve our data at a later time. We can also store multiple chunks of data under a single key, and if fact we are allowing for that in the above example. Consider the situation in which the user of our Effect Module has applied it twice to a single target. The computed weights might be totally different for each of the Effect Module instances. For example, someone could apply two BoneDeform Effect Modules to one target, and with each Effect Module the placement of the bones could be in completely different positions resulting in different weights, our hypothetical Effect Module might work the same way. To allow for this we use a second key called the keyID to further identify our data. In this situation it is fairly logical to use the Effect Module instance's ID as that second key since it will uniquly identify which data we are interested in and will be readily available when needed.
Just to recap quickly since this can be a little confusing. We have allocated an buffer that will store weights for a given Effect Module's target. Since this data is unique to the target we have attached it directly to the target using fxDataCreate(). To identify this data (since it might have any number of other data attached to it by other plugins) we use the address of a global variable to uniquely identify it. We further qualify the data by the ID of the Effect Module instance that is interested in that data.
Data Attachment
If you already have some data allocated that you would like attached to a messiah item you can use the fxDataSet() function. Here you will use the same key and keyID parameters as fxDataCreate(), but instead of specifying a size for the data, you simply pass a pointer to it.

#define FLOAT_BUFFER_KEYID      0
#define VECTOR_KEYID            1

FXcontrol       myButton;
FXint           global_key;
FXvecd          a_vector;

yourfunc()
{
        static FXfloat  some_buffer[100];


        if( !fxDataSet( myButton, &global_key, FLOAT_BUFFER_KEYID, some_buffer ) )
        {
                // report attachment error
        }

        if( !fxDataSet( myButton, &global_key, VECTOR_KEYID, a_vector ) )
        {
                // report attachment error
        }

        // ...
}
In this example the data has been attached to an interface control Entity. We have also attached two pieces of data to the control, both with the same key, but with different keyIDs. You should only ever attach data that will not go out of scope, data that meets this criteria includes:
Freeing Data
When the Entity that the data is attached to is destroyed the data is freed. However if you attached the data using fxDataSet() instead of fxDataCreate() then the data is only detached from the Entity, messiah will not attempt to free it. That means that if you allocated the data using malloc it will be up to you to free it yourself. It also means that you can attach static data (as we did in the previous example).
You may decide that you would like to detach the data from an Entity prior to its destruction, in this case you would use either the fxDataFree() or fxDataFreeKey() function. These functions have the same behavior as the automatic destruction of items as far as freeing the attached data is concerned. In other words, if the data was attached with fxDataSet() then fxDataFree() will only detach the data, not free it.
Retrieving Data
To get a pointer to the data stored on an Entity use the fxDataGet() function.

#define FLOAT_BUFFER_KEYID      0

FXcontrol       myButton;
FXint           global_key;

FXfloat         *buffer = NULL;

buffer = fxDataGet( myButton, &global_key, FLOAT_BUFFER_KEYID );
See also:
Simple Bones Tutorial
Owned Object Data
If the object we want to attach data to belongs to our Module then we can attach the data in a different way. By using the fxObjectSetTypeData() function we can store our data without specifying a key or keyID. This only works if we own the object, and the only objects that can currently be owned by a messiahAPI plugin are instances of our own Shaders and Effects.
As an example we'll look at how an Effect Module might attach data to each of its Effect instances as they are created. First the Module should define some structure to hold the data:

typedef struct
{
        // fill in your data here
}MyEffectData;
Next, in response to the O_CREATE() AN that is sent to your Effect Module's access_func() whenever an instance of your Effect is created, you will allocate and attach a new MyEffectData structure:

case O_CREATE:
{
        MyEffectData *med = NULL;

        // allocate the data
        if( !(med = calloc(1, sizeof(MyEffectData))) )
                // report error and return

        // attach the data to our effect instance
        fxObjectSetTypeData( effect, med, FX_NOFLAG );
}
To get the data back at a later time you'll just use fxObjectGetTypeData(). There's nothing that says that you have to attach your data this way for owned objects, you can use DATA if you like. Using fxObjectSetTypeData() is a little easier because you don't have to manage keys, the downside is that you do have to manage the memory (make sure to free the data in O_DESTROY()! ). The choice is yours, just remember that you can only use this option on instances of your own Effects or Shaders.


© 2003 pmG WorldWide, LLC.


www.projectmessiah.com

groups.yahoo.com/pmGmessiah

Last Updated on Thu Jul 10 04:49:36 2003