Public Member Functions
UserDataMap Class Reference

## Detailed Description

The UserDataMap is a Property that can be attached to any cluster. It permits the storage of variable-length binary user data on the individual components of a geometry. The data is stored as part of the scene file and can be accessed via plug-ins using the C++ API.

Softimage Plug-ins (both persistent and immediate effects) can use this property to save and retrieve data that is associated with individual vertices, polygons, edges, or other components of an object. Example data possibilities include custom game structures, raw simulation data, matrices, comments and images.

There are two ways that a UserDataMap can be used: for binary data or for templated data. With a binary UserDataMap, the structure of the user data is left completely up to the plug-in. This is well suited to C++ plug-ins. The second type of UserDataMap uses a CustomProperty to strictly define the structure of the user data (see UserDataMap::GetTemplate). Templated user data can be inspected in the UI (see the InspectUserData command) in addition to scripting and C++ access.

UserDataMaps are created with the CreateUserDataMap command or SceneItem::AddProperty.

UserDataMap differs from the CustomProperty and UserDataBlob objects in that it stores separate data for each individual component of a cluster.

The UserDataMap is similar to a ClusterProperty, which also stores per-component data, but the UserDataMap allows variable length data, whereas ClusterProperty objects always store a fixed number of Doubles at each component.

The User Data Map provides similar functionality to that available from the `SAAPHIRE` `SAA_subelement*` `UserData` functions. For example, the `Name` of the property corresponds to the `Tag` argument to functions like `SAA_subelementSetUserData`.

It is possible to save a preset of a UserDataMap and to reapply the user data on a different object. However, for the best results, the number of components in both clusters should be the same.

See also:
  Cluster, ClusterProperty, UserDataBlob

Example:
  This example stores and retrieves binary user data on a user data map

              using namespace XSI;
              Application app ;
              Model root = app.GetActiveSceneRoot();

              // Create a cone mesh surface
              X3DObject myCone;
              root.AddGeometry( L"Cone", L"MeshSurface", L"ConeWithUserDataMap", myCone );

              // Create a cluster
              Cluster myCls ;
              CLongArray indices(3);
              indices[0] = 8;
              indices[1] = 16;
              indices[2] = 24;

              myCone.GetActivePrimitive().GetGeometry().AddCluster(siVertexCluster,
                  L"VertexCluster", indices, myCls ) ;

              SceneItem myClsSceneItem( myCls ) ;

              // Add the user data map
              UserDataMap myMap ;
              myClsSceneItem.AddProperty( L"UserDataMap", false, L"udm", myMap ) ;

              // This is the structure that we would like to save inside Softimage
              struct ExampleData
              {
                  double x ;
                  INT    y ;
                  INT    z ;
              } ;

              ExampleData defaultValues ;
              defaultValues.x = 1.1 ;
              defaultValues.y = 10 ;

              // Initialize the user data map to default values
              for ( LONG i = 0 ; i < myMap.GetCount() ; i++ )
              {
                  defaultValues.z = i ;
                  myMap.PutItemValue( i, (unsigned char*)&defaultValues, sizeof( ExampleData )) ;
              }

              // Read the values from index 1
              unsigned char* pInternalData = NULL ;
              UINT cntData = 0 ;
              myMap.GetItemValue( 1, pInternalData, cntData ) ;

              // pData will point to x=1.1, y=10, z=1
              ExampleData *pData = (ExampleData*) pInternalData ;

              // Copy the structure locally before erasing the data inside Softimage
              ExampleData myCopy = *pData ;
              pInternalData = NULL ;
              pData = NULL ;
              myMap.ClearItem( 1 ) ;

              // Save the values that used to be at index 1 onto index 0
              myMap.PutItemValue( 0, (unsigned char*)&myCopy, sizeof( ExampleData ) ) ;

              // Now print out the contents
              for ( i = 0 ; i < myMap.GetCount() ; i++ )
              {
                  if ( myMap.IsItemEmpty( i ) )
                  {
                      app.LogMessage( L"Map item " + CValue(i).GetAsText() + L" is empty" ) ;
                  }
                  else
                  {
                      unsigned char* pInternalData = NULL ;
                      UINT cntData = 0 ;
                      myMap.GetItemValue( i, pInternalData, cntData ) ;
                      pData = (ExampleData*) pInternalData ;

                      app.LogMessage( L"Map item " + CValue(i).GetAsText() +
                                      L" has values: x = " + CValue(pData->x).GetAsText() +
                                                  L" y = " + CValue((LONG)pData->y).GetAsText() +
                                                  L" z = " + CValue((LONG)pData->z).GetAsText() ) ;
                  }

              }

              //Output of running this script is the following:
              //'INFO : "Map item 0 has values: x = 1.1 y = 10 z = 1"
              //'INFO : "Map item 1 is empty"
              //'INFO : "Map item 2 has values: x = 1.1 y = 10 z = 2"

Example:
  This example also stores and retrieves templated user data on a user data map It is practically the same as the previous example, except that it uses the template support to use a CustomProperty object as the way of defining and accessing the format of the data. This approaches is moderately slower, because it involves transferring data back and forth between the CustomProperty and the UserDataMap. However its memory cost is practically the same as the other example and it has the advantage that users can edit the values from the user interface using the InspectUserData command.

              using namespace XSI;
              Application app ;
              Model root = app.GetActiveSceneRoot();

              // Create a cone mesh surface
              X3DObject myGrid;
              root.AddGeometry( L"Grid", L"MeshSurface", L"GridWithUserDataMap", myGrid );

              CLongArray indices(3);
              indices[0] = 1;
              indices[1] = 3;
              indices[2] = 4;

              Cluster myCls ;
              myGrid.GetActivePrimitive().GetGeometry().AddCluster(siEdgeCluster,
                  L"AllEdges", indices, myCls ) ;

              SceneItem myClsSceneItem( myCls ) ;

              // Add the user data map
              UserDataMap myMap ;
              myClsSceneItem.AddProperty( L"UserDataMap", false, L"udm", myMap ) ;

              // Create the custom property that acts as our template
              CustomProperty myTemplate ;
              myClsSceneItem.AddCustomProperty( L"MyTemplate", false, myTemplate ) ;

              Parameter param ;
              myTemplate.AddParameter(
                  L"x",
                  CValue::siDouble,
                  siAnimatable,
                  L"", // Name
                  L"", // Description
                  1.1,  // Default
                  param ) ;

              myTemplate.AddParameter(
                  L"y",
                  CValue::siInt4,
                  siAnimatable,
                  L"",
                  L"",
                  10l,
                  param ) ;

              myTemplate.AddParameter(
                  L"z",
                  CValue::siInt4,
                  siAnimatable,
                  L"",
                  L"",
                  0l,
                  param ) ;

              // Sets the Custom Property as the template for the data in the UserDataMap
              myMap.PutTemplate( myTemplate ) ;

              ProjectItem templateProjItm(myTemplate)  ;

              unsigned char * pData = NULL ;
              UINT cntData ;

              // Initialize the user data map with default values
              for ( LONG i = 0 ; i < myMap.GetCount() ; i++ )
              {
                  templateProjItm.PutParameterValue( L"z", i ) ;
                  myTemplate.GetBinaryData( pData, cntData ) ;

                  myMap.PutItemValue( i, pData, cntData ) ;

                  // We need to release the memory returned by GetBinaryData
                  myTemplate.FreeBinaryData( pData ) ;
              }

              // Read the values from Index 1
              unsigned char* pInternalData = NULL ;

              myMap.GetItemValue( 1, pInternalData, cntData ) ;

              // Custom Property contents will now be x=1.1, y=10, z=1
              myTemplate.PutBinaryData( pInternalData, cntData ) ;

              // Remove the data from index 1 now that we have read it
              pInternalData = NULL ;
              pData = NULL ;
              myMap.ClearItem( 1 ) ;

              // Save the values that used to be at index 1 onto index 0
              myTemplate.GetBinaryData( pData, cntData ) ;
              myMap.PutItemValue( 0, pData, cntData ) ;
              myTemplate.FreeBinaryData( pData ) ;

              // Now print out the contents
              for ( i = 0 ; i < myMap.GetCount() ; i++ )
              {
                  if ( myMap.IsItemEmpty( i ) )
                  {
                      app.LogMessage( L"Map item " + CValue(i).GetAsText() + L" is empty" ) ;
                  }
                  else
                  {
                      unsigned char* pInternalData = NULL ;
                      UINT cntData = 0 ;
                      myMap.GetItemValue( i, pInternalData, cntData ) ;

                      myTemplate.PutBinaryData( pInternalData, cntData ) ;

                      // Now we can just read the values off the custom property set
                      app.LogMessage( L"Map item " + CValue(i).GetAsText() +
                                      L" has values: x = " +
                                      CValue(templateProjItm.GetParameterValue( L"x" )).GetAsText() +
                                      L" y = " +
                                      CValue(templateProjItm.GetParameterValue( L"y" )).GetAsText() +
                                      L" z = " +
                                      CValue(templateProjItm.GetParameterValue( L"z" )).GetAsText() ) ;
                  }
              }

`#include <xsi_userdatamap.h>`

Inheritance diagram for UserDataMap:
[legend]

List of all members.

## Public Member Functions
| UserDataMap ()
| ~UserDataMap ()
| UserDataMap (const CRef &in_ref)
| UserDataMap (const UserDataMap &in_obj)
bool | IsA (siClassID in_ClassID) const
siClassID | GetClassID () const
UserDataMap & | operator= (const UserDataMap &in_obj)
UserDataMap & | operator= (const CRef &in_ref)
LONG | GetCount () const
void | Clear ()
bool | IsLittleEndian () const
void | PutLittleEndian (bool in_bLittleEndian)
CustomProperty | GetTemplate () const
CStatus | PutTemplate (const CustomProperty &in_Template)
CStatus | GetItemValue (LONG in_Offset, const unsigned char *&out_buffer, UINT &out_size) const
CStatus | PutItemValue (LONG in_Offset, const unsigned char *in_buffer, UINT in_size)
bool | IsItemEmpty (LONG in_lOffset) const
UINT | GetItemSize (LONG in_lOffset) const
void | ClearItem (LONG in_Offset)
CStatus | GetValues (CUserDataArray &out_data) const
CStatus | GetValues (CUserDataArray &out_data, CBitArray &out_elemIdx) const
CStatus | SetValues (const unsigned char **in_pValues, const LONG *in_pSizeArray, LONG in_nValues, LONG in_nOffset=0)
CStatus | SetValues (const LONG *in_pElements, const unsigned char **in_pValues, const LONG *in_pSizeArray, LONG in_nElements)
CStatus | SetFixedSizeValues (const unsigned char **in_pValues, LONG in_nValues, LONG in_nSize, LONG in_nOffset=0)
CStatus | SetFixedSizeValues (const LONG *in_pElements, const unsigned char **in_pValues, LONG in_nElements, LONG in_nSize)

## Constructor & Destructor Documentation

UserDataMap | ( |  | ) |

Default constructor.

~UserDataMap | ( |  | ) |

Default destructor.

UserDataMap | ( | const CRef & | in_ref | ) |

Constructor.

Parameters:

  in_ref | constant reference object.

UserDataMap | ( | const UserDataMap & | in_obj | ) |

Copy constructor.

Parameters:

  in_obj | constant class object.

## Member Function Documentation

bool IsA | ( | siClassID | in_ClassID | ) | const `[virtual]`

Returns true if a given class type is compatible with this API class.

Parameters:

  in_ClassID | class type.

Returns:
  true if the class is compatible, false otherwise.

Reimplemented from Property.

siClassID GetClassID | ( |  | ) | const `[virtual]`

Returns the type of the API class.

Returns:
  The class type.

Reimplemented from Property.

UserDataMap& operator= | ( | const UserDataMap & | in_obj | ) |

Creates an object from another object. The newly created object is set to empty if the input object is not compatible.

Parameters:

  in_obj | constant class object.

Returns:
  The new UserDataMap object.

UserDataMap& operator= | ( | const CRef & | in_ref | ) |

Creates an object from a reference object. The newly created object is set to empty if the input reference object is not compatible.

Parameters:

  in_ref | constant class object.

Returns:
  The new UserDataMap object.

Reimplemented from Property.

LONG GetCount | ( |  | ) | const

Returns the number of elements in the map. This is equal to the size of the cluster that the UserDataMap is attached to.

Returns:
  Size of map.

void Clear | ( |  | ) |

Flushes all data from the UserDataMap. This does not change the size of the UserDataMap, but all items on the map will be empty.

Reimplemented from CBase.

bool IsLittleEndian | ( |  | ) | const

When the UserDataMap is created this flag is initialized to the correct value according to the Endian byte order of the computer that Softimage is running on. For example, LittleEndian is set to true on x86 processors and false on MIPS processors. This flag is useful when transferring Softimage scenes with binary data between platforms with different byte order: a plug-in can use this flag to determine whether to byte-swap the data retrieved from UserDataMap::GetItemValue. Plug-ins which pack their data in a consistent order, no matter what platform they are on, can ignore this property.

Note:
  This can be ignored for templated UserDataMaps, since they always use a little endian binary representation (see CustomProperty::GetBinaryData).

Returns:
  true for x86 processors and false for MIPS processors

void PutLittleEndian | ( | bool | in_bLittleEndian | ) |

Sets the Little Endian flag.

Parameters:

  in_bLittleEndian | true for x86 processors and false for MIPS processors

CustomProperty GetTemplate | ( |  | ) | const

A UserDataMap can be associated with a CustomProperty that serves as a template for the data inside the UserDataMap. This allows the storage of strongly typed data on each component. The template defines the format of the data, but the values of the data are stored separately for each component.

For example, a user data map on a polygon cluster may have a template with a integer parameter `X` and a floating point parameter `Y`. This means that each polygon can store its own value of `X` and `Y`.

The transfer of data between the associated custom property and individual components can be performed using UserDataMap::GetItemValue and CustomProperty::GetBinaryData.

Returns:
  Returns the template as a CustomProperty object. If no template then an invalid CustomProperty object is returned.

See also:
  CustomProperty

CStatus PutTemplate | ( | const CustomProperty & | in_Template | ) |

Sets the template for the UserDataMap. To remove an existing template this can be called with an invalid CustomProperty object.

Parameters:

  in_Template | template to set

Returns:
  CStatus

CStatus GetItemValue | ( | LONG | in_Offset,
|  | const unsigned char *& | out_buffer,
|  | UINT & | out_size
| ) |  | const

Gets access to the data on a particular component inside the UserDataMap. The `out_buffer` will point to NULL if there is no user data on the specified component.

The way this property is used depends on whether the UserDataMap has an associated template or not:

In the context of templated UserDataMap:
  This function is used to transfer user data via CustomProperty::GetBinaryData and CustomProperty::PutBinaryData (see UserDataMap::GetTemplate). In this case you do not need to understand the format of the data, because you read and write the values via the ProjectItem functions, such as ProjectItem::GetParameters.

In the context of a binary UserDataMap:
  This property is used to read binary data that was previously saved on a geometry component.

For performance purposes, the returned pointer points directly to internal Softimage data. The caller does not need to free this memory and should treat this data as read-only and potentially transitive. To hold the data, it should be copied by the caller rather than holding the pointer.

When transferring binary user data between platforms it may be necessary to perform byte-swapping. See UserDataMap::IsLittleEndian.

Parameters:

  in_Offset | index of the item

Return values:

  out_buffer | buffer
  out_size | data size

Returns:
  CStatus

CStatus PutItemValue | ( | LONG | in_Offset,
|  | const unsigned char * | in_buffer,
|  | UINT | in_size
| ) |  |

Sets binary data into a user data map.

On a templated UserDataMap, you can remember the current state of the associated CustomProperty by calling CustomProperty::GetBinaryData and setting the returned buffer via this method.

On binary UserDataMaps, the caller can set data of any size or structure.

Note:
  Binary user data should not contain any memory addresses or other information that is transitive.

Softimage will copy the provided buffer so the caller does not need to maintain the provided data in memory.

Parameters:

  in_Offset | index of the item to set
  in_buffer | buffer to set
  in_size | new size

Returns:
  CStatus

bool IsItemEmpty | ( | LONG | in_lOffset | ) | const

Returns true if there is no user data on the specified component. The index must be in the range 0 to UserDataMap.Count - 1. A common scenario for using this property is inside a loop which visits each component in the user data map to see if any user data has been set.

Parameters:

  in_lOffset | index of the item with the data to check

Returns:
  true if no user data

See also:
  Cluster.GetElements, ClusterProperty

UINT GetItemSize | ( | LONG | in_lOffset | ) | const

Returns the size (in bytes) of the data attached to a particular component of the UserDataMap.

Parameters:

  in_lOffset | index of the item with the data to check

Returns:
  The size (in bytes) of the user data.

void ClearItem | ( | LONG | in_Offset | ) |

Removes any user data from the specified index. To clear the entire property at once use UserDataMap::Clear.

Parameters:

  in_Offset | index of the item to clear

CStatus GetValues | ( | CUserDataArray & | out_data | ) | const

Returns an array containing the user data values stored in this map. The number of elements in the array matches the number of geometry elements (N).

Return values:

  out_data | Array of user data values.

Returns:
  CStatus

See also:
  CGeometryAccessor::GetClusterProperties

Since:
  5.0

CStatus GetValues | ( | CUserDataArray & | out_data,
|  | CBitArray & | out_elemIdx
| ) |  | const

Returns an array containing the user data values stored in this map. The number of elements in the array matches the number of geometry elements (`N`). The function also returns a bit array of size `N` which identifies the indices of the geometry elements set in the user data map. You can use the bit array items to quickly identify what are the elements affected by the map.

Return values:

  out_data | Array of user data values.
  out_elemIdx | Array of element index flags.

Returns:
  CStatus

See also:
  CGeometryAccessor::GetClusterProperties

Since:
  5.0

CStatus SetValues | ( | const unsigned char ** | in_pValues,
|  | const LONG * | in_pSizeArray,
|  | LONG | in_nValues,
|  | LONG | in_nOffset = `0`
| ) |  |

Sets the user data values stored in this map. The function sets the geometry elements in the order specified by `in_pValues` starting from index `0`. Values are set directly on the property and the operation is not undoable.

For large data sets, you can use an offset index to set the values in chunks. The offset is used for indexing into `in_pElements` which allows you to optimize the memory allocation required for setting the element values.

Parameters:

  in_pValues | Array of size in_nElements containing the user data values.
  in_pSizeArray | Array of size in_nValues containing the size of each user data specified in `n_pValues`.
  in_nValues | Number of values to set.
  in_nOffset | Specifies the starting index in the cluster elements.

Returns:
  CStatus::OK Success.
  CStatus::InvalidArgument Returns an error if in_nElements is greater than the number of cluster elements or smaller than zero. Also returns an error if `in_pElements` or `in_pValues` are invalid.

See also:
  CClusterPropertyBuilder, CGeometryAccessor::GetClusterProperties

Since:
  5.0

CStatus SetValues | ( | const LONG * | in_pElements,
|  | const unsigned char ** | in_pValues,
|  | const LONG * | in_pSizeArray,
|  | LONG | in_nElements
| ) |  |

Sets the user data values stored in this map. Values are set directly on the property and the operation is not undoable.

Parameters:

  in_pElements | Array of size `in_nElements` containing the geometry elements to set.
  in_pValues | Array of size `in_nElements` containing the user data values.
  in_pSizeArray | Array of size `in_nElements` containing the size of each user data specified in `in_pValues`.
  in_nElements | Number of elements in `in_pElements`.

Returns:
  CStatus::OK Success.
  CStatus::InvalidArgument Returns an error if `in_nElements` is greater than the number of cluster elements or smaller than zero. Also returns an error if `in_pElements` or `in_pValues` are invalid.

See also:
  CClusterPropertyBuilder, CGeometryAccessor::GetClusterProperties

Since:
  5.0

CStatus SetFixedSizeValues | ( | const unsigned char ** | in_pValues,
|  | LONG | in_nValues,
|  | LONG | in_nSize,
|  | LONG | in_nOffset = `0`
| ) |  |

Sets the user data stored in this map with an array of values of a fixed size. The function sets the geometry elements in the order specified by `in_pValues` starting from index `0`. This version allows you to set the user data values without the need of allocating an array to hold the data size. The function assumes that each item has the same data size. Values are set directly on the property and the operation is not undoable.

For large data sets, you can use an offset index to set the values in chunks. The offset is used for indexing into the cluster elements which allows you to optimize the memory allocation required for setting the element values.

Parameters:

  in_pValues | Array of size `in_nValues` containing the user data values.
  in_nValues | Number of values in `in_pValues`.
  in_nSize | The size of each values contained in `in_pValues`.
  in_nOffset | Specifies the starting index in the cluster elements.

Returns:
  CStatus::OK Success.
  CStatus::InvalidArgument Returns an error if `in_nElements` is greater than the number of cluster elements or smaller than zero. Also returns an error if `in_pElements` or `in_pValues` are invalid.

See also:
  CClusterPropertyBuilder, CGeometryAccessor::GetClusterProperties

Since:
  5.0

CStatus SetFixedSizeValues | ( | const LONG * | in_pElements,
|  | const unsigned char ** | in_pValues,
|  | LONG | in_nElements,
|  | LONG | in_nSize
| ) |  |

Sets the user data stored in this map with an array of values of a fixed size. The function sets the geometry elements in the order specified by `in_ppValues` starting from index `0`. This version allows you to set the user data values without the need of allocating an array to hold the data size. Values are set directly on the property and the operation is not undoable.

Parameters:

  in_pElements | Array of size `in_nElements` containing the geometry elements to set.
  in_pValues | Array of size `in_nElements` containing the user data values.
  in_nElements | Number of elements in `in_pElements`.
  in_nSize | The size of each values contained in `in_pValues`.

Returns:
  CStatus::OK Success.
  CStatus::InvalidArgument Returns an error if `in_nElements` is greater than the number of cluster elements or smaller than zero. Also returns an error if `in_pElements` or `in_pValues` are invalid.

See also:
  CClusterPropertyBuilder, CGeometryAccessor::GetClusterProperties

Since:
  5.0

The documentation for this class was generated from the following file:

- xsi_userdatamap.h