BinaryData (CustomProperty) *

Introduced

3.0

Description

Returns or sets the binary representation of the CustomProperty. This data is a compact representation, encoded in a BSTR (see String). This is a byte string, containing binary information. This string does not contain human readable text. C++ developers are responsible for freeing this string with ::SysFreeString, whereas script writers have the luxury of automatic resource management.Unlike a Preset, only the actual values are stored in the binary representation, this is done for memory efficiency. Animation is not preserved in the Binary Data - it stores a snapshot of the Parameter.Values. The binary representation is well suited for storing inside a UserDataItem using UserDataItem.Value. This functionality allows you to easily store per-component data inside a UserDataMap, but to view and edit this data using an associated Custom Property set.

You should not attempt to set the binary representation on a custom property object which is different from the custom property from which the binary representation was retrieved. In particular the number of parameters, the order of the parameters and the type of the parameters must match. If the custom property is different the API call will fail or will result in the custom property set being filled with bogus values. However it is possible to rearrange the order in which parameters are displayed on the property page for a Custom Property. (by editing the spdl file "Layout" section), without any incorrect results.

In the case of animated parameters the value recorded in the binary representation will be the value at the current frame. Similarily, the current value of any proxy parameters will be recorded in the binary representation.

Normally SDK developers will not need to be concerned with the internal format of this binary data. However, the following information will be useful in cases where the data will be generated or processed outside of Softimage. The binary representation begins with a two byte header that serve as a "magic number" for error handling purposes. The rest of the buffer is a concatenation of the raw values of the properties of the custom property, in exactly the order they were originally added to the custom property, and stored in little endian byte order. For example, a double takes up 8 bytes, a float 4 bytes and a unsigned char (siUByte) takes 1 byte. Strings start with a 32-bit count of the number of characters, followed by the 16-bit unicode representation of each character, with no string termination character. For the case of an Parameter that is an object instead of a simple type, such as an FCurve, there is a 32-bit buffer size followed by a binary representation of the object.

C# Syntax

    // get accessor
    String rtn = CustomProperty.BinaryData;

    // set accessor
    CustomProperty.BinaryData = String;

Examples

1. VBScript Example

    'Example of BinaryData method on CustomProperty

    dim oRoot, oPropSet

    'Set up the example
    set oRoot = Application.ActiveProject.ActiveScene.Root
    set oPropSet = oRoot.AddProperty("Custom_parameter_list",,"ExamplePSet")
    SIAddCustomParameter oPropSet, "TestVal", siDouble, 5, 0, 10
    call ModalInspectCustomProperty( oPropSet)

    'This routine demonstrates how the BinaryData property
    'could be used to roll back changes that a user might have made
    'on a custom property set
    'The property set is shown as a modal dialog, with OK/CANCEL buttons
    'and if the user clicks Cancel we restore the property set values
    'back to their original values

    sub ModalInspectCustomProperty( in_oPropertySet )

       dim strOriginalValues
       strOriginalValues = in_oPropertySet.BinaryData

       'If cancel is pressed then Inspect object will
       'fail.  This "on error" statement says that we want to handle
       'the error rather than have the whole script fail.
       on error resume next

       InspectObj in_oPropertySet, , , siModal

       if ( err <> 0 ) then
           'User pressed cancel - roll back any changes that they made
           in_oPropertySet.BinaryData = strOriginalValues
       end if

    end sub

2. JScript Example

    // Example showing how FCurves
    // can be stored inside a UserDataMap,
    // and edited via a Custom Property

    // It demonstrates:
    // -Creation of a single script plugin
    // -Use of templated UserDataMap object to store data on points
    // -Use of CustomProperty.BinaryData to store and retrieve FCurves
    //     represented as strings.
    // -Use of PPGLayout to build dynamic user interfaces (with no SPDL)

    BuildSampleScene() ;

    function BuildSampleScene()
    {
       newscene( null, false ) ;

       var oGrid = ActiveSceneRoot.AddGeometry(
                         "Grid",
                         "MeshSurface",
                         "GridWithUserData" ) ;

       oGrid.subdivu = 1 ;
       oGrid.subdivv = 1 ;

       var oCluster = oGrid.ActivePrimitive.Geometry.AddCluster( "pnt" ) ;
       var oUserDataMap = oCluster.AddProperty( "UserDataMap",
                     false,
                     "FCurveData" ) ;

       var oCustomProperty = CreateUserDataTemplate( oCluster )  ;
       oUserDataMap.Template = oCustomProperty ;

       InspectObj( oCustomProperty ) ;

       SelectObj(oGrid, null, true);
       SetSelFilter("Point");
    }

    function CreateUserDataTemplate( in_oCluster )
    {
       var oCustomProperty = in_oCluster.AddProperty(
              "CustomProperty",
              false,
              "DataTemplate" ) ;
       oCustomProperty.AddFCurveParameter( "CurveData" ) ;

       var oLayout = oCustomProperty.PPGLayout

       var oLayoutItem = oLayout.AddFCurve( "CurveData", 150 );

       oLayout.AddRow() ;
       oLayout.AddButton( "ReadFromSelection", "Read from selected Point" ) ;
       oLayout.AddButton( "SaveFromSelection", "Save on selected Point(s)" ) ;
       oLayout.AddButton( "Instructions" ) ;
       oLayout.EndRow() ;

       oLayout.Language = "JScript" ;
       oLayout.Logic = ReadFromSelection_OnClicked.toString() +
              SaveFromSelection_OnClicked.toString() +
              Instructions_OnClicked.toString() +
              GetSelectedPoints.toString() +
              GetUserDataMap.toString() ;

       return oCustomProperty ;
    }

    //
    // The following code is Logic code for the Property Page
    //

    function GetSelectedPoints()
    {
       // Find out what points are selected
       // They are returned as an array of Cluster Indices
       // (-1 is returned in the array if the selected point is not
       // part of the cluster)

       var oSubComp = null ;

       for ( var i = 0 ; i < Selection.Count ; i++ )
       {
           var oObj = Selection(i) ;
           if ( oObj.Type == "pntSubComponent" )
           {
              oSubComp = oObj.SubComponent
              break ;
           }
       }

       if ( oSubComp == null )
       {
           logmessage( "Please select the point to read from" ) ;
           return null ;
       }

       // (We could also double check that the points are selected on the
       // right object using the parent property!)

       var aVBSelectedElements = new VBArray( oSubComp.ElementArray ) ;
       var aGeometryIndices = aVBSelectedElements.toArray() ;

       // Index on a cluster is not necessarily identical to a
       // geometry index.  Use the Cluster object to do a lookup

       var oThisCustomProperty = PSet.Inspected.Item(0);
       var oCluster = oThisCustomProperty.Parent
              .ActivePrimitive.Geometry.Clusters("Point") ;

       for ( i = 0 ; i < aGeometryIndices.length ; i++ )
       {
           aGeometryIndices[i] = oCluster.FindIndex( aGeometryIndices[i] ) ;
       }

       return aGeometryIndices ;
           }

    function GetUserDataMap()
    {
       // Find the UserDataMap associated with this Custom Property
       // We know they are both nested under the same Cluster
       // and what the name of the User Data Map is
       var oThisCustomProperty = PSet.Inspected.Item(0);
       var oCluster = oThisCustomProperty.Parent
              .ActivePrimitive.Geometry.Clusters("Point") ;
       return oCluster.Properties.Item( "FCurveData" ) ;
    }

    function ReadFromSelection_OnClicked()
    {
       var aSelectedElements = GetSelectedPoints() ;
       if ( aSelectedElements == null ||
            aSelectedElements.length == 0 )
       {
           return ;
       }

       // If more than one item is selected
       // we only look at the first one
       var clusterIndex  = aSelectedElements[0] ;

       if ( clusterIndex == -1 )
       {
           logmessage( "The selected index is not part of the cluster" ) ;
           return ;
       }

       var oUserDataMap = GetUserDataMap() ;

       if ( oUserDataMap.IsEmpty( clusterIndex ) )
       {
           logmessage( "There is not user data stored on this item yet" ) ;
           return ;
       }

       // Transfer the data from the UserDataMap
       // to the ClusterProperty

       var oThisCustomProperty = PSet.Inspected.Item(0);
       oThisCustomProperty.BinaryData = oUserDataMap.ItemValue( clusterIndex ) ;
    }

    function SaveFromSelection_OnClicked()
    {
       var aSelectedElements = GetSelectedPoints() ;

       var oThisCustomProperty = PSet.Inspected.Item(0);
       binarySnapShotOfCustomProperty = oThisCustomProperty.BinaryData ;

       var oUserDataMap = GetUserDataMap() ;

       for ( i = 0 ; i < aSelectedElements.length ; i++ )
       {
           if ( aSelectedElements[i] != -1 )
           {
              oUserDataMap.ItemValue( aSelectedElements[i] ) =
                         binarySnapShotOfCustomProperty ;
           }
       }
                  }

    function Instructions_OnClicked()
    {
       // There are lots of different ways to show information
       // to a user, for example poping up netview,
       //  showing a message box, or putting static text right
       // on the dialog.

       // For demonstration purposes we create a temporary custom pset
       // with a multiline edit box, which we fill with text.
       // This doesn't have ideal usability but
       // shows some of the potential for doing totally dynamic UI

       var oInfoPSet = ActiveSceneRoot.AddProperty( "CustomProperty", false, "Info" ) ;
       var oParameter = oInfoPSet.AddParameter3( "Info", siString ) ;
       oParameter.ReadOnly = true ;

       oParameter.Value = "Plug-in Instructions\r\n\r\n" +
         "This example demonstrates how to store FCurves as User Data.\r\n" +
         "Each of the 4 vertices of the Grid can store a different Curve\r\n\r\n" +
         "To view the FCurve on a vertex, select it and press the \r\n" +
         "'Read from Selected Point' button.\r\n\r\n" +
         "To set the fcurve, change the fcurve in the view, " +
         "select one or more points\r\n" +
         "and then press the 'Save on selected Point(s)' button"

       var oLayoutItem = oInfoPSet.PPGLayout.AddString( "Info", "", true, 300 ) ;
       oLayoutItem.SetAttribute( "ValueOnly", true ) ;

       InspectObj( oInfoPSet,null,null,siModal, false ) ;
       DeleteObj( oInfoPSet );

    }

See Also

UserDataItem

Autodesk Softimage v7.5