EffectorData DDescription
-
On 03/04/2013 at 12:12, xxxxxxxx wrote:
User Information:
Cinema 4D Version: 13
Platform: Mac ;
Language(s) : C++ ;---------
Hello all, I'm working on an Effector plugin based off the Noise Effector SDK example. I got rid of the res files and replaced it with a dynamic description. The only problem is the Falloff tab disappears when I do it.I figured out what was causing it. If I have GetDDescription() return TRUE than all of the data I assign in GetDDescription() appear, but the Falloff tab does not. If I have GetDDescription() return SUPER::GetDDescription(node,description,flags) then the Falloff tab does not appear.
Is there a way to have the Falloff tab and my own description elements appear?
Thanks,
Dan -
On 03/04/2013 at 13:00, xxxxxxxx wrote:
If the Falloff tab is declared in the res files then you will need it, won't you. You can use both static and dynamic descriptions together. All you need is to do this at the top of your GetDDescription() implementation:
// NodeData.GetDDescription - Descriptions and Parameters //*---------------------------------------------------------------------------* Bool MyPlugin::GetDDescription(GeListNode* node, Description* description, DESCFLAGS_DESC& flags) //*---------------------------------------------------------------------------* { if (!(node && description)) return FALSE; // Load in the static resource descriptions for this node type if (!description->LoadDescription(node->GetType())) return FALSE; // Set up your dynamic descriptions // .... flags |= DESCFLAGS_DESC_LOADED|DESCFLAGS_DESC_RECURSIONLOCK; return SUPER::GetDDescription(node,description,flags); }
-
On 03/04/2013 at 15:10, xxxxxxxx wrote:
Hi Robert, thanks for the quick response.
I think I wasn't clear or I'm misunderstanding EffectorDatas. It looks like EffectorDatas have a inbuilt Falloff tab. It's not part of the res file or the dynamic description. It's just there, in the same way the Basic and Coord. tabs are there for object plugins, at least that's what it looks like to me,I assume it's just built into it.
Returning TRUE for GetDDescription() keeps my description elements, but doesn't add the Falloff tab. Returning SUPER::GetDDescription(node,description,flags) does the opposite, giving me the Fallout tab and not my stuff. I'm not sure why.
Thanks,
Dan -
On 03/04/2013 at 15:33, xxxxxxxx wrote:
I'll bet it is. Inbuilt would be part of the static resource description which is linked it with your resource description:
CONTAINER Oenoise { NAME Oenoise; // ******************************** INCLUDE Obaseeffector; // ******************************** GROUP ID_MG_BASEEFFECTOR_GROUPEFFECTOR { REAL NOISEEFFECTOR_SCALE { UNIT PERCENT; MIN 0.0; MAXSLIDER 100.0; CUSTOMGUI REALSLIDER; } } }
You see my number of posts and my join date. I know what I'm talking about.
-
On 03/04/2013 at 15:42, xxxxxxxx wrote:
I'm going to post an example of one of my GetDDescription() methods. It is a bit cumbersome but far less than others that I have used previously. Unfortunately, I don't have a very simple one to provide. Maybe there is something more basic in the SDK examples.
// NodeData.GetDDescription - Descriptions and Parameters //*---------------------------------------------------------------------------* Bool UnfurlTag::GetDDescription(GeListNode* node, Description* description, DESCFLAGS_DESC& flags) //*---------------------------------------------------------------------------* { // Initial validity checks if (CheckIsRunning(CHECKISRUNNING_EXTERNALRENDERING) || CheckIsRunning(CHECKISRUNNING_EDITORRENDERING)) { flags |= DESCFLAGS_DESC_LOADED|DESCFLAGS_DESC_RECURSIONLOCK; return SUPER::GetDDescription(node,description,flags); } if (!(node && description)) return FALSE; if (!description->LoadDescription(node->GetType())) return FALSE; flags |= DESCFLAGS_DESC_LOADED|DESCFLAGS_DESC_RECURSIONLOCK; // Get necessary pointers BaseDocument* baseDoc = node->GetDocument(); if (!baseDoc) return SUPER::GetDDescription(node,description,flags); BaseTag* tag = static_cast<BaseTag*>(node); if (!tag) return SUPER::GetDDescription(node,description,flags); BaseContainer* opBC = tag->GetDataInstance(); if (!opBC) return SUPER::GetDDescription(node,description,flags); // ************************* // Add Dynamic Descriptions // ************************* // Control Polygon List BaseContainer cp_id = GetCustomDataTypeDefault(DTYPE_STATICTEXT); cp_id.SetBool(DESC_ANIMATE, DESC_ANIMATE_OFF); cp_id.SetBool(DESC_SCALEH, FALSE); cp_id.SetBool(DESC_REMOVEABLE, FALSE); BaseContainer cp_value = GetCustomDataTypeDefault(DTYPE_REAL); cp_value.SetBool(DESC_ANIMATE, DESC_ANIMATE_OFF); cp_value.SetBool(DESC_HIDE, FALSE); cp_value.SetBool(DESC_SCALEH, FALSE); cp_value.SetBool(DESC_REMOVEABLE, FALSE); cp_value.SetReal(DESC_MIN, 0.0); cp_value.SetReal(DESC_MAX, 1.0); cp_value.SetReal(DESC_STEP, 0.01); cp_value.SetLong(DESC_UNIT, DESC_UNIT_PERCENT); cp_value.SetLong(DESC_CUSTOMGUI, CUSTOMGUI_REAL); cp_value.SetString(DESC_SHORT_NAME, "Unfurled at"); BaseContainer cp_show = GetCustomDataTypeDefault(DTYPE_BOOL); cp_show.SetBool(DESC_ANIMATE, DESC_ANIMATE_OFF); cp_show.SetBool(DESC_HIDE, FALSE); cp_show.SetBool(DESC_SCALEH, FALSE); cp_show.SetBool(DESC_REMOVEABLE, FALSE); cp_show.SetString(DESC_SHORT_NAME, "Show"); BaseContainer cp_remove = GetCustomDataTypeDefault(DTYPE_BUTTON); cp_remove.SetString(DESC_SHORT_NAME, "Remove"); cp_remove.SetLong(DESC_CUSTOMGUI, CUSTOMGUI_BUTTON); cp_remove.SetLong(DESC_ANIMATE, DESC_ANIMATE_OFF); cp_remove.SetBool(DESC_REMOVEABLE, FALSE); cp_remove.SetBool(DESC_SCALEH, FALSE); BaseContainer cp_index = GetCustomDataTypeDefault(DTYPE_LONG); cp_index.SetBool(DESC_ANIMATE, DESC_ANIMATE_OFF); cp_index.SetBool(DESC_HIDE, TRUE); cp_index.SetBool(DESC_SCALEH, FALSE); cp_index.SetBool(DESC_REMOVEABLE, FALSE); cp_index.SetString(DESC_SHORT_NAME, "Gradient Index"); LONG c = 0L; LONG gcnt = opBC->GetLong(TUNFURL_POLYGON_COUNT); // Count controls to see if we hide "Gradient Dir" or not for (LONG i = 0L; i != gcnt; ++i) { if (gradients[i].control) ++c; } if (c > 1L) { BaseContainer cp_mix = GetCustomDataTypeDefault(DTYPE_STATICTEXT); cp_mix.SetBool(DESC_ANIMATE, DESC_ANIMATE_OFF); cp_mix.SetBool(DESC_HIDE, FALSE); cp_mix.SetBool(DESC_SCALEH, FALSE); cp_mix.SetBool(DESC_REMOVEABLE, FALSE); cp_mix.SetString(DESC_SHORT_NAME, "."); NeighborPoly* g = NULL; c = 0L; for (LONG i = 0L; i != gcnt; ++i) { g = &gradients[i]; if (!g->control) continue; if (c >= 2048L) break; // Control Polygon ID - Static Text cp_id.SetString(DESC_SHORT_NAME, LongToString(c+1L)+" ("+LongToString(i)+")"); if (!description->SetParameter(DescLevel(TUNFURL_CONTROL_ID+c, DTYPE_STATICTEXT,0L), cp_id, DescLevel(TUNFURL_GROUP_CONTROLS))) return SUPER::GetDDescription(node,description,flags); // Control Polygon Gradation Direction - Static Text (see below) if (!description->SetParameter(DescLevel(TUNFURL_CONTROL_MIX+c, DTYPE_STATICTEXT,0L), cp_mix, DescLevel(TUNFURL_GROUP_CONTROLS))) return SUPER::GetDDescription(node,description,flags); // Control Polygon Value - Real if (!description->SetParameter(DescLevel(TUNFURL_CONTROL_VALUE+c, DTYPE_REAL,0L), cp_value, DescLevel(TUNFURL_GROUP_CONTROLS))) return SUPER::GetDDescription(node,description,flags); // Control Polygon Highlight - Bool if (!description->SetParameter(DescLevel(TUNFURL_CONTROL_SHOW+c, DTYPE_BOOL,0L), cp_show, DescLevel(TUNFURL_GROUP_CONTROLS))) return SUPER::GetDDescription(node,description,flags); // Control Polygon Remove - Button if (!description->SetParameter(DescLevel(TUNFURL_CONTROL_REMOVE+c, DTYPE_BUTTON,0L), cp_remove, DescLevel(TUNFURL_GROUP_CONTROLS))) return SUPER::GetDDescription(node,description,flags); // Control Polygon Index - LONG if (!description->SetParameter(DescLevel(TUNFURL_CONTROL_INDEX+c, DTYPE_LONG,0L), cp_index, DescLevel(TUNFURL_GROUP_CONTROLS))) return SUPER::GetDDescription(node,description,flags); opBC->SetLong(TUNFURL_CONTROL_INDEX+c, i); opBC->SetReal(TUNFURL_CONTROL_VALUE+c, g->ctrlValue); opBC->SetBool(TUNFURL_CONTROL_SHOW+c, g->show); ++c; } } else { BaseContainer cp_mix_sub; cp_mix_sub.SetString(0L, "0->1"); cp_mix_sub.SetString(1L, "1->0"); BaseContainer cp_mix = GetCustomDataTypeDefault(DTYPE_LONG); cp_mix.SetContainer(DESC_CYCLE, cp_mix_sub); cp_mix.SetBool(DESC_ANIMATE, DESC_ANIMATE_OFF); cp_mix.SetBool(DESC_HIDE, FALSE); cp_mix.SetBool(DESC_SCALEH, FALSE); cp_mix.SetBool(DESC_REMOVEABLE, FALSE); cp_mix.SetString(DESC_SHORT_NAME, "Gradient Dir"); NeighborPoly* g = NULL; c = 0L; for (LONG i = 0L; i != gcnt; ++i) { g = &gradients[i]; if (!g->control) continue; // Control Polygon ID - Static Text cp_id.SetString(DESC_SHORT_NAME, LongToString(c+1L)+" ("+LongToString(i)+")"); if (!description->SetParameter(DescLevel(TUNFURL_CONTROL_ID+c, DTYPE_STATICTEXT,0L), cp_id, DescLevel(TUNFURL_GROUP_CONTROLS))) return SUPER::GetDDescription(node,description,flags); // Control Polygon Gradation Direction - LONG if (!description->SetParameter(DescLevel(TUNFURL_CONTROL_MIX+c, DTYPE_LONG,0L), cp_mix, DescLevel(TUNFURL_GROUP_CONTROLS))) return SUPER::GetDDescription(node,description,flags); // Control Polygon Value - Real if (!description->SetParameter(DescLevel(TUNFURL_CONTROL_VALUE+c, DTYPE_REAL,0L), cp_value, DescLevel(TUNFURL_GROUP_CONTROLS))) return SUPER::GetDDescription(node,description,flags); // Control Polygon Highlight - Bool if (!description->SetParameter(DescLevel(TUNFURL_CONTROL_SHOW+c, DTYPE_BOOL,0L), cp_show, DescLevel(TUNFURL_GROUP_CONTROLS))) return SUPER::GetDDescription(node,description,flags); // Control Polygon Remove - Button if (!description->SetParameter(DescLevel(TUNFURL_CONTROL_REMOVE+c, DTYPE_BUTTON,0L), cp_remove, DescLevel(TUNFURL_GROUP_CONTROLS))) return SUPER::GetDDescription(node,description,flags); // Control Polygon Index - LONG if (!description->SetParameter(DescLevel(TUNFURL_CONTROL_INDEX+c, DTYPE_LONG,0L), cp_index, DescLevel(TUNFURL_GROUP_CONTROLS))) return SUPER::GetDDescription(node,description,flags); opBC->SetLong(TUNFURL_CONTROL_INDEX+c, i); opBC->SetReal(TUNFURL_CONTROL_VALUE+c, g->ctrlValue); opBC->SetBool(TUNFURL_CONTROL_SHOW+c, g->show); opBC->SetLong(TUNFURL_CONTROL_MIX+c, g->direction); ++c; } } return SUPER::GetDDescription(node,description,flags); }
-
On 03/04/2013 at 16:17, xxxxxxxx wrote:
Hi Robert, thanks for continuing to help me. I didn't mean to imply I knew better than you or anything, I'm sure you know a hundred times as much as me about Cinema.
I took the code from the res file you provided and put it into mine and updated the string and header file. The SCALE parameter is correctly showing up at the bottom of the Effector tab.
This top image is what the Noise Effector looks like when I have GetDDesctiption() return SUPER::GetDDescription(node,description,flags);
This is what the Noise Effector looks like when I have GetDDesctiption() return TRUE.
My custom Base tab is there, but the Fallout tab has disappeared. My res file is exactly like yours, so it's not pulling it from there is it? I would think I have a conflicting ID so mine is being replaced, but I've swapped that and it hasn't changed anything.
Sorry if these are stupid questions.
Dan -
On 03/04/2013 at 17:13, xxxxxxxx wrote:
Watch your Description resource enumeration ID values. I typically start them at 2000 but the docs say to start at at least 1000. This goes for static and dynamic descriptions.
-
On 04/04/2013 at 13:01, xxxxxxxx wrote:
Hello again, Robert. I double checked a couple ids for testing purposes and I'm fairly sure they aren't conflicting. The Falloff group ID is 5100, and mine is in the 2000s so I think I'm safe there.
I looked through the res files for the Noise Effector and I understand what you were talking about before regarding
INCLUDE Obaseeffector;
It adds the Effector and Parameter tabs onto the effector. The Obaseeffector.res has
INCLUDE Obase; INCLUDE Oedeformer_panel;
which adds, the Basic and Coord. tabs, I assume, and the Deformer tab.
So that explains all of the tabs on the effector object, by my understanding, except for the Falloff tab. I found Ofalloff_panel.h, which seems to be what I'm looking for but it's missing the Weight and Scale parameters and it isn't ever called from what I can see.
None of this fixes my problem, but I do have a better understanding of how the descriptions work.
So my two questions currently are: What does
SUPER::GetDDescription(node,description,flags);
do? What does it accomplish? And where does the Fallout tab come from? I can explain the rest of the tabs, but I can't figure out where that is called from.
Dan
-
On 04/04/2013 at 13:27, xxxxxxxx wrote:
My best guess after looking at the res file trail is that C4D adds the Falloff section automatically but by using GetDDescription() you are possibly circumventing that or preventing that from happening. Hopefully Yannick can provide a useful response on this.
Whenever you are dealing with derived classes, some methods may need to have the same method from its base class called to do/initialize other things. Since we don't have access to the code for the Obaseeffector it is entirely possible that the Falloff tab is being added in its GetDDescription().
-
On 05/04/2013 at 03:03, xxxxxxxx wrote:
Hi,
There's a convenient and simpler method ModifyDDescription() declared in EffectorData that you can override; it gives a loaded description and add the Fallof tab.
Here's how we can create the scale parameter dynamically for the Noise Effector example (empty resource file) :
Resource:CONTAINER Oenoise { NAME Oenoise; INCLUDE Obaseeffector; }
Plugin code:
Bool NoiseEffector::ModifyDDescription(GeListNode *node, Description *description, AtomArray *ar) { DescID cid = DescLevel(NOISEEFFECTOR_SCALE, DTYPE_REAL, 0); BaseContainer bc = GetCustomDataTypeDefault(DTYPE_REAL); bc.SetString(DESC_NAME, "Scale"); bc.SetLong(DESC_UNIT, DESC_UNIT_PERCENT); bc.SetReal(DESC_MIN, 0.0); bc.SetReal(DESC_MAX, 100.0); bc.SetLong(DESC_CUSTOMGUI, CUSTOMGUI_REALSLIDER); if (!description->SetParameter(cid, bc, DescLevel(ID_MG_BASEEFFECTOR_GROUPEFFECTOR))) return TRUE; return TRUE; }
-
On 09/04/2013 at 14:01, xxxxxxxx wrote:
Sorry about the late response. Thank you both for all of your help, it's working perfectly!
I have another EffectorData question though. Is there a way to have the Effector effect the object before it's effected by it... Sorry if that's confusing.
I currently have the NoiseEffector example getting it's weight from a keyframed Plain effector that passes through a cloner. So before the Plain effector passes through the cloner I want them moved.
I have a spline remapping the position. So if the spline goes from one to zero instead of zero to one, so from a heavily modified position to a none modified postion. When the Plain effector moves through the cloner the objects would move from a changed position back to it's default position.
CalcPointValue() is only called once an object is being effected by the effector, not before.
It looks like CalcPlacebo() is called for objects before they are effected, so that's what I would want, I think. The SDK says I don't need to set the strengths, but can I?
In my tests it allows me to set them, but it doesn't seem to have any effect.
Sorry if that's confusing, I tried to make it as clear as I could. Thanks again for all the help.
Dan -
On 02/05/2013 at 09:43, xxxxxxxx wrote:
My last post was confusing and I figured the answer out so I'm going to double post. I shouldn't have been using CalcPlacebo() or CalcPointValue at all. I should have been using ModifyPoints(). I switch to that function and everything seems to be working fine so far with one exception.
I've been setting the Noise Effector's Falloff Weight to zero and then using a Plain Effector to map the weight, which works perfectly. If I try to use just the Noise Effector though it doesn't work, i.e. I set it to Linear and have it pass through the cloner on it's own.
The SDK example for the Noise Effector works,which uses CalcPointValue() but mine using ModifyPoints() doesn't. CalcPointValue() seems to return the correct fall_weight. My ModifyPoints() uses
MDArray<Real>weight_array = md->GetRealArray(MODATA_WEIGHT);
to get the current weight. In all the set ups I've tried mine returns zero and the SDK example seems to be working. Is this a limitation of ModifyPoints(),am I using the wrong array for the weight, or am I completely thinking about it the wrong way?
Dan