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... :dizzy_face:  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