BaseTag and TagData - typecast?



  • On 02/07/2013 at 04:33, xxxxxxxx wrote:

    Hi Niklas,
    I derive my tags from TagData, not from BaseTag. I used the templates from the SDK. So GetDatainstance() won't work. 
    By the way, Mr. Maxon wants us to use GetParameter and not use the GetDatainstance(), but that is a minor issue in this context.

    ----

    When I call a static method in my tag, using a BaseTag* as a parameter, I can access the various data for my tag. But this method could as well have been implemented in any object, I just store this in my tag, because it somehow belongs there.

    If tags written had been derived from BaseTag, and not TagData, all would have been fine, I believe. But from inside the TagData, there is no way (as far as I know) to access the data, using "this" i.e. the object itself. And the examples in the SDK use TagData as the ancestor. And that is the correct way, I believe?



  • On 02/07/2013 at 05:00, xxxxxxxx wrote:

    I know you do. You can't derive your plugin from BaseTag. I'm working with the Cinema 4D API for
    almost 4 years now bud.

    However, by subclassing BaseTag, you can make common operations on your plugin-tag contained
    in one class, and you can access them by simply making a cast.

    Bool MyTagData::Execute(BaseTag* bTag, /* ... */) {
            MyTag* tag = (MyTag* ) bTag;
            if (!tag->IsEnabled()) return TRUE;

    // ...
        }

    You can safely use GetDataInstance() for your own objects (and also others). I only use
    Get/SetParameter() on parameters that I know of (or have made the experience) that they are not
    stored in the container.

    > >> If tags written had been derived from BaseTag, and not TagData, all would have been fine, I
    believe. But from inside the TagData, there is no way (as far as I know) to access the data, using "this"
    i.e. the object itself. And the examples in the SDK use TagData as the ancestor. And that is the correct
    way, I believe?

    I'm not sure if I got this straight. You can always retrieve a NodeData's (so, also TagData's)
    GeListNode* by calling NodeData::Get().



  • On 02/07/2013 at 05:18, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    You can always retrieve a NodeData's (so, also TagData's)
    GeListNode* by calling NodeData::Get().

    Aha, now I know this, thanks. I wish there was a this->GetListNode() instead. Because this is almost scary.. But I will use it, errors will appear in any case.



  • On 02/07/2013 at 07:23, xxxxxxxx wrote:

    Ok, what would you prefer, you experienced guys here

    A

     _// Caller_
    BaseTag* tagFound =	tagOwner->GetFirstTag();
    LONG result = MySpecialTag::GetMySpecialValue(tag) 
      
    // Inside the tag, this can be **static**
    LONG MySpecialTag::GetMySpecialValue(BaseTag* tag)
    {
        GeData t_data;
        tag->GetParameter(SPECIAL_VALUE, t_data, DESCFLAGS_GET_0);
        return t_data.GetLong();
    }
    

    B

     _// Caller_
    BaseTag* tagFound =	tagOwner->GetFirstTag();
    // Type casting
    MySpecialTag* mst = (MySpecialTag* )tagFound->GetNodeData();
    LONG result = mst->GetMySpecialValue(); 
      
    // Inside the tag
    LONG MySpecialTag::GetMySpecialValue()
    {
        GeListNode* node = NodeData::Get();
        GeData t_data;
        node->GetParameter(SPECIAL_VALUE, t_data, DESCFLAGS_GET_0);
        return t_data.GetLong();
    }
    


  • On 02/07/2013 at 07:36, xxxxxxxx wrote:

    B



  • On 02/07/2013 at 07:45, xxxxxxxx wrote:

    One small point, you are assuming that the first tag returned is your tag, presumably because it's the only visible tag on the object. Bear in mind that there may well be other, invisible tags, one of which could be the first tag.

    So you should always check the type of tag, e.g.:

      
    BaseTag *tagFound = tagOwner->GetFirstTag();   
    while(tagFound != nullptr)   
    {   
         if(tagFound->GetType() == MY_TAGS_PLUGIN_ID)   
         {   
              // do whatever here...   
         }   
         tagFound = tagFound->GetNext();   
    }   
    


  • On 02/07/2013 at 12:10, xxxxxxxx wrote:

    Or.. just look for your specific tag, if that's all you want to do...

      
      BaseTag* tagFound = someObject->GetTag(MY_TAGS_PLUGIN_ID);  
      if( tagFound )  
      {  
          // do whatever with your tag here  
       }  
    


  • On 02/07/2013 at 16:17, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    Or.. just look for your specific tag, if that's all you want to do...

     
      BaseTag* tagFound = someObject->GetTag(MY_TAGS_PLUGIN_ID);  
      if( tagFound )  
      {  
          // do whatever with your tag here  
       }  
    

    Yes, most likely there is just one of them. 
    Anyhow, the question regarding A or B is to what extent I should use a static function passing the BaseTag as a parameter, or use a dynamic function, having typecast the BaseTag to the actual TagData descendant.



  • On 02/07/2013 at 23:42, xxxxxxxx wrote:

    This article might help answering some of the general questions:
    http://c4dprogramming.wordpress.com/2013/03/12/nodedata-what-is-it-good-for/



  • On 03/07/2013 at 19:12, xxxxxxxx wrote:

    Howdy,

    Well, from the looks of your code couldn't you do the same thing like this:

    LONG result = 0;  
    BaseTag *tag = object->GetTag(ID_MY_TAG_PLUGIN);  
    if(tag)  
    {  
      BaseContainer *tData = tag->GetDataInstance();  
      if(tData) result = tData->GetLong(ID_SPECIAL_LONG_VALUE);  
    }  
    

    I mean if the data is stored in the tag's container there's no need to cast a BaseTag to your tag data class.😉

    Adios,
    Cactus Dan


Log in to reply