getting shader from material

On 04/07/2015 at 21:00, xxxxxxxx wrote:

User Information:
Cinema 4D Version:   15+ 
Platform:   Windows  ;   
Language(s) :     C++  ;

I got a MaterialData plugin, where shaders are created dynamically, here is some code:

    						BaseShader* shader = nullptr;
    						//shader = static_cast<BaseShader*> (kndData->nodes[n].getInternalData(input).GetLink(mat->GetDocument()));//fails
    						//BaseList2D* mlnk = data->GetLink(kndData->nodes[n].getInternalID(input), mat->GetDocument(), Xbase);
    						//        shader = static_cast<BaseShader*> (mlnk);
    						shader = mat->GetFirstShader();//works
    							GePrint("found a shader link");
    							GePrint("shader link not found");

not sure why the standard ways of getting a link using a description id fails.
here is how I create the description:

    					cid = DescLevel(kndData->nodes[kndData->selectedNode].getInternalID(i), DTYPE_BASELISTLINK, 0);
    					if (!singleid || cid.IsPartOf(*singleid, nullptr))// important to check for speedup c4d!
    						BaseContainer dt = GetCustomDataTypeDefault(DTYPE_BASELISTLINK);
    						std::string dName = kndData->nodes[kndData->selectedNode].getInternalDataName(i);
    						String dtName(dName.c_str());
    						dt.SetString(DESC_SHORT_NAME, dtName);
    						dt.SetString(DESC_NAME, dtName);
    						dt.SetBool(DESC_ANIMATE, DESC_ANIMATE_ON);
    						dt.SetInt32(DESC_SHADERLINKFLAG, TRUE);
    						if (!description->SetParameter(cid, dt, DescLevel(Tbaselist2d)))
    							return true;

On 06/07/2015 at 03:13, xxxxxxxx wrote:

Hi Mohamed,

I think, your code looks right. Can you show me the other side? Where you insert the shader?

On 06/07/2015 at 06:23, xxxxxxxx wrote:

after some testing, it fails due to Get/SetDParameter()
the most weird behavior is: if I animate the link channel, it reads correctly, otherwise it misses!!
if I ignore Get/SetDParameter() it behaves correctly.

On 13/07/2015 at 19:14, xxxxxxxx wrote:

any idea why it fails to get descriptions?

On 16/07/2015 at 08:50, xxxxxxxx wrote:

Hi Mohamed,

sorry for answering this late, still in overflow here.
I tried it here, now. And I can't reproduce any problems.
Here's what I did:

In SetDParameter() :

BaseLink* const bl = static_cast<BaseLink*>(t_data.GetBaseLink());
// Both ways work, the first one kind of emulates the internal behavior
  GeData d;
  data->SetData(id[0].id, d);  // store in container
  return SUPER::SetDParameter(node, id, t_data, flags);

In GetDParameter() :

// Both ways work, the first one kind of emulates the internal behavior
  const GeData d = data->GetData(id[0].id);
  if (d.GetType() == DA_NIL) // If the link does not get properly initialized, you need to take care for this situation, otherwise you only need the else branch
    AutoAlloc<BaseLink> bl;
    BaseLink* const bl = d.GetBaseLink();
  Bool result = SUPER::GetDParameter(node, id, t_data, flags);
  // use t_data here
  return result;

I implemented this in a ObjectData plugin and in GetVirtualObjects() I accessed the link.
This worked:

BaseContainer* bc = op->GetDataInstance();
BaseLink* bl = bc->GetBaseLink(ID_LINK);
if (bl)
  BaseList2D* bl2d = bl->GetLink(op->GetDocument());
  if (bl2d)
    GePrint("No Link");

And this worked as well:

BaseList2D* bl2d2 = bc->GetLink(ID_LINK, op->GetDocument());
if (bl2d2)
  GePrint("No link");

I hope, this helps. Otherwise you will have to provide me with some code (your Get-/SetDParameter())

On 16/07/2015 at 09:37, xxxxxxxx wrote:

ok, I think I did some bad stuff in my Get/SetDParameter() for link, I guess your code will work as Get/SetDParameter() were the problem

will test it tonight and come back to you.

On 17/07/2015 at 01:39, xxxxxxxx wrote:

I tested it, and it works
but I got questions:
I have 2 cases here, one that I use my internal data "which is written to hyper file, so I have to make sure that this internal data works!!"
and another that uses descriptions.

BaseLink* bl = kndData->nodes[n].getInternalData(input).GetBaseLink();
	shader = static_cast<BaseShader*> (bl->ForceGetLink());//doesn't work without FORCE, is this safe?
shader = static_cast<BaseShader*> (data->GetLink(kndData->nodes[n].getInternalID(input), mat->GetDocument(), Xbase));//description access, works fine.  

so I need to know, is it safe to call ForceGetLink()? why it works and GetLink() fails?

On 20/07/2015 at 07:25, xxxxxxxx wrote:

Hi Mohamed,

GetLink() works only, if the link points to an object in the same document. ForceGetLink() instead resolved links in all open documents.
So if ForceGetLink() works and GetLink() does not, it is a hint, that your links are not properly handled, when the document is being copied. Or if your material is copied to another document.

On 23/07/2015 at 22:11, xxxxxxxx wrote:

thanks Andreas
at least now I know where the problem is.

the problem is: no alias translator.
how to use one, inside CopyTo(), as this is the only place that I see!

all examples are using C4dAtom->GetClone(flags, aliastrans);
which is not used in my case.

On 05/08/2015 at 12:44, xxxxxxxx wrote:

up, any idea to correct the links using aliastrans.

On 12/08/2015 at 08:32, xxxxxxxx wrote:


at first I wanted to let you know, that the examples on GitHub have been updated. There's an example especially on this topic: gui/objectdata_getsetdparameter.cpp

And now for your last question:
First a huge sorry! I have to admit, I forgot about it.
AliasTrans won't help to repair your links. AliasTrans is made for transferring links within one object. For example, when a bunch objects is duplicated, and these contain links to other objects being duplicated as well. Then you have two options, either the links still point to the original objects or (and this is what AliasTrans is used for) the links will be redirected to the new copies.

On 12/08/2015 at 09:46, xxxxxxxx wrote:

thanks Andreas, but what makes the links broken here? you said " it is a hint, that your links are not properly handled, when the document is being copied"

On 12/08/2015 at 10:42, xxxxxxxx wrote:

Right, unfortunately this matter can get quiet complex.

First things first (I know I said this before) :
A link only works within one BaseDocument.

Before going further, please note: For most developers the following won't be relevant. But I think, Mohamed's plugin might have a complexity where he may be struck by this.

Following scenario: A custom material has a link to a custom node and this material gets copied into a new document.
Here the link gets transferred into another document and using GetLink() won't work anymore. Also the link target (custom node) won't be copied into the new doc automatically.
As long as the source document is still there, you can use ForceGetLink() to resolve the link to the node in the source document. But be aware, it is the node in the source document! Still this is one way to get a copy of the custom node and repair the link afterwards.

This happens for example, when rendering previews or baking, a material will be copied into a new document. Either by cloning the document or by creating a new one and only copying the needed objects and materials.

But, what if the user uses copy, then closes the document and afterwards pastes the material into a new document? Then things can get really tricky...
And there are even more scenarios, like merging documents...

Unfortunately there's no generic solution for all of these scenarios and it also heavily depends on your plugin's structure/architecture. So, I'd say, you should try to identify such problems and the situations they occur in. Then please open another thread, where we can discuss each problem one by one. Please also try to explain your architecture as detailed as possible.