v3.0
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.
' This example 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. ' 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) ' Convenience routine to do the work 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 |
// // This example shows how FCurves can be stored inside a UserDataMap, // and edited via a Custom Property. It demonstrates: (a) how to create // a single script plug-in; (b) how to use a templated UserDataMap object // to store data on points; (c) how to use CustomProperty.BinaryData to // store and retrieve FCurves represented as strings; and (d) how to use // the 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) { Application.LogMessage("Please select a point"); 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; for ( var j=0; j<aGeometryIndices.length; j++) { aGeometryIndices[j] = oCluster.FindIndex(aGeometryIndices[j]); } 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; 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) { Application.LogMessage("The selected index is not part of the cluster"); return; } var oUserDataMap = GetUserDataMap(); if ( oUserDataMap.IsEmpty(clusterIndex) ) { Application.LogMessage("There is no 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(); if (!aSelectedElements || !aSelectedElements.length) { Application.LogMessage("You must select at least one point in order to save this fcurve"); return; } var oThisCustomProperty = PSet.Inspected.Item(0); binarySnapShotOfCustomProperty = oThisCustomProperty.BinaryData; var oUserDataMap = GetUserDataMap() ; for ( var k=0; k<aSelectedElements.length; k++) { if (aSelectedElements[k] != -1) { oUserDataMap.ItemValue(aSelectedElements[k]) = binarySnapShotOfCustomProperty; } } } function Instructions_OnClicked() { // There are lots of different ways to show information to a user, for example popping // 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); } |