Re: PutUserData in custom operator
| Date : Thu, 2 Feb 2006 18:54:41 +1100 |
| To : XSI(at)Softimage.COM |
| From : Aloys Baillet <aloys.baillet(at)gmail.com> |
| Subject : Re: PutUserData in custom operator |
I'll try to explain these things in more depth.
As you already know, XSI Operators are one of the best examples of "tunnel vision" (thanks Guy for the _expression_:-). They can only see what they have defined in their Input ports, and they can only modify what they have in their Output port. And as Andrew said, if you connect your UserDataBlob to the input and the output of your operator, you will experience weird results if you rely on this to store your data between 2 updates (eg: the value you thought you put in the blob at frame 2 is not the one you get at frame 3).
Another issue is that the evaluation of the UserDataBlob output port is only triggered if someone reads the UserDataBlob (that can be MentalRay if you do a render and set the UserDataBlob to renderable). In general nobody cares of your blob and its value will be always wrong.
You can solve your problem in 2 ways:
If your data are initial data only, you can just create a custom command that will initialize the blob and then apply the operator, connecting the blob as an additional input port. Your blob is ReadOnly.
That's the easiest to implement and it works perfectly. I'll describe later how to put the commands and the operators in the same DLL.
If you need a ReadWrite blob, the easiest is to rely on the Operator UserData to store the value while your operator is alive, use the DataBlob to read initial values and store the values before it dies.
I'm sure I can be clearer than that, but today was long;-)
If you connect your operator to the UserDataBlob as an Input AND an Output port, the data you will read from it are good the first time your operator is updated: that's your initial state. Then you can use what you're already using to store in between data: the operator UserData as a C++ Class. Finally, you want to be sure that when you save the scene the UserDataBlob is updated to a good state. A way of ensuring that is to set up a ScenePreSave event (in the same DLL!) that will just read the content of the UserDataBlob. This read will trigger the operator update for the blob and will give you the good values. And this values will be saved in the scene.
You can also write the good values in the _Term callback of the operator, but I don't know if it works when you save the scene (in this case it's easier to implement than the preSave event).
OK, I hope my explanations make some sense...
Now for the DLL you just have to declare all your callbacks (Operators and Commands and Events) in the same CPP file. Then put the DLL in the Plugins folder. Then you just have to modify the operator's SPDL file and change the Plugin line to point to the DLL you declared (just the name is enough). There's documentation on this I believe.
So good luck!
Aloys
This is an important topic and I've tried to jot some more notes here:In particular i try to emphasis the helpful tip from Aloys and try to explain the trouble with input/output connection to user data objects.In terms of the specifics of SPDL syntax for a userdatablob connection you can look at the ShowEdges example (WireFrameOp)-AndrewTeam Lead, XSI SDK-----Original Message-----
From: owner-xsi@Softimage.COM [mailto:owner-xsi@Softimage.COM]On Behalf Of Mathieu LeclairePosted At: Wednesday, February 01, 2006 12:59 PM
Posted To: xsi
Conversation: PutUserData in custom operator
Subject: RE: PutUserData in custom operatorYes I saw those but what I don't understand is how to access them from inside the custom operator. How do I verify if it exist and how do I extract the information?
In the example it creates it using:
UserDataBlob myBlob ;root.AddProperty
( L"UserDataBlob", false, L"udb", myBlob ) ;
…then uses putvalue and getvalue to pass information in and out so my guess is to use addproperty on the object I'm applying the operator to but how do I extract the object… I know using the ports I can have access to its kinematicstate or its primitive so what then? Do I just use addproperty on the primitive or kinematicstate directly or do I have to extract the parent (to get the object I'm adding my operator to) and add the datablob to it directly? And how do I verify if it already exist and extract the userdatablob object if it does? Or do I have to create the datablob before applying the custom operator and pass the datablob through the SPDL? This is where I'm still confused!!
-----Original Message-----
From: owner-xsi@Softimage.COM [mailto: owner-xsi@Softimage.COM]On Behalf Of Steven Caron
Sent: Wednesday, February 01, 2006 12:17 PM
To: XSI@Softimage.COM
Subject: Re: PutUserData in custom operator
http://softimage.wiki.avid.com/sdkdocs/sicppsdk/html/classXSI_1_1UserDataBlob.html
http://softimage.wiki.avid.com/sdkdocs/UserDataMap.htm
stevenOn 2/1/06, Mathieu Leclaire < mleclair@hybride.com > wrote:
Great, UserDataBlob is what I needed but I'm still not sure I understand how to read and write them from inside a custom operator though. You mentioned it would be better to do it in a custom command and make them share the same DLL… not sure I understand how to do such a thing. Do I have to link the UserDataBlob through the SPDL? A little example would be appreciated.
And btw, I just need to access it during initialization but if you want to elaborate a little more about how you'd manage the case where it would have to be updated every time the operator is updated, I'd be great information to have in case I'm ever faced with such an issue.
Thanks for all the info! It really helps a lot!!
Mathieu
-----Original Message-----
From: owner-xsi@Softimage.COM [mailto:owner-xsi@Softimage.COM]On Behalf Of Aloys Baillet
Sent: Tuesday, January 31, 2006 5:08 PM
To: XSI@Softimage.COMSubject: Re: PutUserData in custom operator
Hi Mathieu,
Glad you solved the first problem!
For the second you can investigate in 2 different areas, both involving saving data in the XSI scene graph, which is the only way of ensuring data persistence between XSI sessions.
The first one is called UserDataBlob, and the second is UserDataMap, the doc provides good exemples for both to use them.
Then you have to know if the data you're using needs to be updated everytime the operator is updated.
If not (it's just initialization data) you can compute the values and store them in either storage solution BEFORE applying the operator with a custom command: you'll save yourself a lot of headache by doing so. And you can put your CPP custom command in the same DLL than the operator (and thus share some code).
If yes, you'll have to do the same as what you're doing now (store the data in your class), and connect your storage to an output port of your operator. The tricky part is that you'll have to ensure that XSI request the evalution of your operator's storage port before deleting the operator. I can write a little more about that if you need it.
Hope this helps,
AloysOn 01/02/06, Mathieu Leclaire <mleclair@hybride.com> wrote:
OK… I've done more testing and seems the class and pointers works fine… the problem was that I was trying to use PutUserData in a syflex force using the syflex sdk… syflex data is saved using syXset( ctx, (syXforce*)data ); that probably overrides my userdata and that's why I wasn't getting the right results… now I have to figure out how to combine my userdata to syflex's userdata… but I have a few ideas I'll try out… so that takes care of my first problem but my second question still stands so if anyone has any suggestions for that second issue, please share!!
Thanks
Mathieu Leclaire
R&D Programmer
Hybride
-----Original Message-----
From: owner-xsi@Softimage.COM [mailto: owner-xsi@Softimage.COM]On Behalf Of Mathieu Leclaire
Sent: Tuesday, January 31, 2006 12:04 PM
To: XSI@Softimage.COM
Subject: PutUserData in custom operator
Hi, I'm creating a custom operator and I need to initialize and save data for each vertex of a polymesh. Since I have different kind of data to save in the _init call of the operator and reload at each _update call, I figured I'd create a class and put all my data in it then store that object using the PutUserData() function of the UpdateContext. But since I allocate memory in the constructor and delete that memory in the destructor, I think once I pull back my data in the _update function using GetUserData(), it returns me random data since it looks like the memory has already been released. Here is an example of what I'm doing:
#ifndef _myVertexInfo_h
#define _myVertexInfo_h
class myVertexInfo {
private:
int _nbPts;
float* _targetPositions;
int* _idxPts;
public:
myVertexInfo (int nbPts) {
_nbPts = nbPts;
_targetPositions = new float[nbPts*3];
_idxPts = new int[nbPts*3];
}
virtual ~myVertexInfo (){
delete [] _targetPositions;
delete [] _idxPts;
}
int GetNbPts() {
return _nbPts;
}
…
};
#endif
Then in my operator's _Init function I do something like this:
…
//put local positions in obj2PtsPosArray.
obj2PtsPosArray = inGeom.GetPoints().GetPositionArray();
int nb = obj2PtsPosArray.GetCount();
myVertexInfo * posData = new myVertexInfo (nb);
…
ctx.PutUserData( (CValue::siPtrType)posData );
Then pull it back in the _update function doing something like this:
CValue::siPtrType pUserData = ctx.GetUserData();
myVertexInfo * posData = (myVertexInfo *)pUserData;
Application app;
app.LogMessage( CValue((float)posData->GetNbPts()).GetAsText());
But I lose all information saved from the _init call. So what am I doing wrong? How do I allocate memory only in the _init function and release it only in the _term function?
I also have a second question: How can I store this information so that when I load a model containing instances of that operator, it won't recalculate all that information from the _init call but load the data calculated when the operator was first applied. See, I only need to calculate the necessary information when it's first applied, then use the calculated information at every _update call of the operator. But if I export a model containing instances of this operator, when I re-import it (usually by switching the low resolution reference model by a higher resolution one that contains this operator) then it recalls the _init of the operator and recalculates all the values instead of reusing the values that where calculated when first applied. I had the same problem with a previous operator I created but I overcame the issue by adding a "FirstLoad" Boolean parameter to the SPDL so that when it first got applied, it would change that parameter value to false and save the desired data in the rest of the parameters and so when it loaded again in a model, and the "FirstLoad" parameter value was set to false, it would only read the parameters instead of recalculating them. That worked well in that case because I only had a couple floats and a couple integers that had to be saved per operator so I saved them as parameters. Now I have whole arrays of data to save and it's length is dependant on the number of vertices. How should I solve this issue? The only solution I have in mind would be to save it to a file but then we'd have files to manage with the model and paths to check… I'm looking for a way to save that data directly into the operator or somewhere in the exported model so that I can reload it when imported. Any suggestions?
Thanks for any help you can provide and sorry for the lengthy post, I just figure I'd better give too much information then not enough.
Mathieu Leclaire
R&D Programmer
Hybride
--
Aloys Baillet - XSI Technical Director
Character Dpt - Animal Logic
--
--
Aloys Baillet - XSI Technical Director
Character Dpt - Animal Logic
--
- Follow-Ups:
- RE: PutUserData in custom operator
- From: "Mathieu Leclaire" <mleclair(at)hybride.com>
- RE: PutUserData in custom operator
- References:
- RE: PutUserData in custom operator
- From: "Andrew Skowronski" <askowron(at)Softimage.COM>
- RE: PutUserData in custom operator
| DATE: | << | >> | THREAD: | << | >> | INDEX: | Main | Thread |
|---|
- Previous by Date: Re: 16bit tiffs
- Next by Date: Re: 16bit tiffs
- Previous by Thread: Re: 16bit tiffs
- Next by Thread: Re: 16bit tiffs
- Index(es):
| Search the XSI List archives here or use the advanced search form to search across mailing lists. Searching help is available. |