Multiparm Issues (HDK)

   6532   11   2
User Avatar
Member
30 posts
Joined: July 2007
Offline
Hey all,

I've run into a rather annoying issue when working with multiparms. I want to attach some custom data to each entry—a set of points, for example. The problem I'm having is that when you delete an item in the list from the middle, it will not actually remove the middle item but rather delete the last item and shift all the data down.

Is there some way to associate (like a map or something) an item in the list to data (in my case a pointer to a class) and be able to maintain the integrity of it? I'm using addOrRemoveMultiparmInstance to know when it happens, but I need to know what item was deleted or added. Hope that all makes sense.

This is driving me slightly nuts so any help would be greatly appreciated!

Thanks!

–Joel
Joel Van Eenwyk
Programmer and FX Artist
Homepage: VFX Journal [vfxjournal.net]
User Avatar
Staff
1082 posts
Joined: July 2005
Offline
How are you mapping this custom data to each entry?

I think the easiest way to associate some data with each instance would be to have an invisible string parameter in the set of instance parameters. This invisible string instance value would then shift along with all the other instance values, maintaining the same association.
User Avatar
Member
30 posts
Joined: July 2007
Offline
Hey Ondrej,

Thanks for the response! That worked really well…thanks! I was kinda hoping there was a cleaner way to map the data, but at least this works. I'm just storing an instance to a class per SOP instance. Nothing really complex in that regard.

So right now I'm just handling initMultiparmInstance and setting the name parameter template to be something unique. Then in addOrRemoveMultiparmInstance I connect/disconnect the data from my class structure. Then in opChanged I can update class information if necessary when there is an OP_PARM_CHANGED message.

Thanks again!

–Joel
Joel Van Eenwyk
Programmer and FX Artist
Homepage: VFX Journal [vfxjournal.net]
User Avatar
Member
30 posts
Joined: July 2007
Offline
Alright, so I was wrong about it working 100% correctly. If you insert an item before an existing item, setting the template default string doesn't actually do what I want. Basically, for each new item that's inserted, I want it to have a unique identifier while letting the previous item(s) have the same string. It copies the parameters correctly, but the “new” item doesn't follow the template string.

This isn't really unexpected behavior if you think about it for a second, though. When you insert an item before an existing item, the first item is already initialized using the template while the second item (the newly inserted item acting as the old item) is initialized by the template but promptly set to the old value.

Is there a way around this immensely confusing predicament?

Thanks!

–Joel
Joel Van Eenwyk
Programmer and FX Artist
Homepage: VFX Journal [vfxjournal.net]
User Avatar
Staff
1082 posts
Joined: July 2005
Offline
Maybe I'm misunderstanding, but are you using unique parameter NAMES to connect/disconnect this data? I don't see how using names would work. Note that I originally suggested using the parameter value.
User Avatar
Member
30 posts
Joined: July 2007
Offline
Actually, I don't believe you can do that because the names of the parameters in a Multiparam are always sequential. In other words, let's say you have:

* paramName1
* paramName2

If you insert an entry before paramName2, you would have:

* paramName1
* paramName2
* paramName3

For this to work, you would in fact want the last two names to be swapped, because now the data you want attached to the last entry is still attached to the second (the “new”) entry.

Hopefully that makes sense. I suppose you could keep track of this through catching various opChanged events, but it would be somewhat convoluted. Any ideas on how to make this non-painful?

Thanks!

–Joel
Joel Van Eenwyk
Programmer and FX Artist
Homepage: VFX Journal [vfxjournal.net]
User Avatar
Staff
1082 posts
Joined: July 2005
Offline
I'm afraid I still don't understand what you're trying to achieve.
User Avatar
Member
30 posts
Joined: July 2007
Offline
I was afraid that would just make it more confusing. Alright, let me try to give a more complete example. Let's say we insert an item into a MultiParam. On initialization, we generate a unique name for that item by looping through all existing entries and ensuring that the name isn't already used. So on first insert, we have:
multiParamName = “MyUniqueName0”;
Then we have a std::map that uses that name as a key. So then we have:
myDataMap = new SpecialData();
Now, that pointer to SpecialData needs to continue to reference the same entry because the MultiParam has other values associated with it like Fade, Description, etc. This is all fine and dandy if you just insert new items at the end of the list. But if you insert an item at the beginning, setting the template value of the parameter doesn't do what we want.

Does that make more sense or did I make it worse?

Thanks for helping me out with this.

–Joel
Joel Van Eenwyk
Programmer and FX Artist
Homepage: VFX Journal [vfxjournal.net]
User Avatar
Member
2199 posts
Joined: July 2005
Online
Why not just add an invisible multiparm that stores the index into your data structure, that way it is dis-assoociated from the actual parameter index.

multiParamName = “MyUniqueName0”;
multiParamDataIdx = “MyUniqueDataIdx0”;

when you insert an entry the above will be renamed to

multiParamName = “MyUniqueName1”;
multiParamDataIdx = “MyUniqueDataIdx1”;

but “MyUniqueDataIdx1” can still store 0 as the index, you can then use this to look up in your data array the correct values.
The trick is finding just the right hammer for every screw
User Avatar
Staff
1082 posts
Joined: July 2005
Offline
joelvaneenwyk
Does that make more sense or did I make it worse?

A little from column A and a little from column B

I'm still somewhat confused by your terminology. My assumption is that you mean you have a special string parameter in each multiparm instance, called something like “map_key%d”, whose value is set to the unique name like “MyUniqueName0”.

So before an insert, I may have something like:


0: map_key0 = “MyUniqueName0”
1: map_key1 = “MyUniqueName1”
2: map_key2 = “MyUniqueName2”
3: map_key3 = “MyUniqueName3”


After inserting an item between 1 and 2 I'd have:

0: map_key0 = “MyUniqueName0”
1: map_key1 = “MyUniqueName1”
2: map_key2 = “MyUniqueName4”
3: map_key3 = “MyUniqueName2”
4: map_key4 = “MyUniqueName3”


Isn't that what you want? The unique identifier for each instanced block of parameters is still associated with the same block of parameters.

I'm not sure what you mean by setting the “template value” of the parameter.
User Avatar
Member
30 posts
Joined: July 2007
Offline
Hey Ondrej,

Thanks for the response! I was at a conference last week and have been catching up since, hence the delayed response.

Alright, what I'm looking for is exactly what you described. The issue I'm having is how/when to set that unique name, so that it is always set correctly. What I tried doing was putting the following (pseudo) code in initMultiparmInstance:


for ( int i = 0; i < parms.entries(); i++ )
{
PRM_Parm *parm = parms;
PRM_Template *templ = parm->getTemplatePtr();

if ( isTemplateNameParam(parm) )
{
std::string defaultName = getUniqueName();
templ->setStringDefault( 0, defaultName.c_str() );
}
}


This works for the most part, but not in the case where you insert before due to the problems I mentioned above. Perhaps I am just going about this the wrong way, so do you have a more optimal solution?

Thanks again for the help!

Take care,

–Joel
Joel Van Eenwyk
Programmer and FX Artist
Homepage: VFX Journal [vfxjournal.net]
User Avatar
Staff
1082 posts
Joined: July 2005
Offline
What happens when you insert a new instance is that we first insert an instance at the end of the list, call initMultiParmInstance() with it, shift values, revert the instance that's in the correct position to its defaults, and call initMultiParmInstance() again with that instance.

From this order of events, you can see that setting the default value for the parameter won't work unless you explicitly call revertToDefaults() on the parameter after changing it in initMultiParmInstance(). Alternately, you can just try setting the parameter value in place of the default directly.

Finally, note that initMultiParmInstance() is actually called twice in the case of such an insertion, so it may be worth recording the last assigned unique name and if you're called with an instance that's already been assigned its unique name, reuse the last one, as it's probably safe to assume you're in this situation. Should you choose to use parameter values instead of defaults, you'll probably need to set a flag in the parameter's spare data (parm->getSparePtr()) so that you can detect this case after the reversion to defaults.

Hope this solves your problem.
  • Quick Links