Plugin Cafe Homepage
Forum Home Forum Home > Plugin Cafe > SDK Help
  New Posts New Posts
  FAQ FAQ  Forum Search   Register Register  Login Login

Copy material with links to another doc

 Post Reply Post Reply
Author
Message
Aaron94 View Drop Down
Member
Member


Joined: 2015 Dec 15
Online Status: Offline
Posts: 66
Post Options Post Options   Quote Aaron94 Quote  Post ReplyReply Direct Link To This Post Topic: Copy material with links to another doc
    Posted: 2017 Jul 28 at 3:29pm

User Information:

Cinema 4D Version:   R17 
Platform:   Windows  ;   
Language(s):       

---------

Hello!

I am trying to copy a multi-material which contains the links to other materials from one doc to another one. And it fails when we cntl+c and cntrl+v the mult-material, but sub-materials are not copied. 
How to workaround this?

I have tried to modify the function with an idea to use GetLink/ForceGetLink to resolve this
Bool multiMaterial::CopyTo(NodeData * dest, GeListNode * srcNode, GeListNode * destNode, COPYFLAGS flags, AliasTrans * aliasTrans)

But the destNode->GetDocument() returns 0.
How to solve that? When copy a multi-material then all sub-materials must be moved to the destination too. In the destination I have to make GetClone, dest_doc->InsertMaterial, etc, etc.
Back to Top
Andreas Block View Drop Down
Forum Moderator
Forum Moderator
Avatar

Joined: 2014 Oct 01
Location: Hannover
Online Status: Offline
Posts: 1430
Post Options Post Options   Quote Andreas Block Quote  Post ReplyReply Direct Link To This Post Posted: 2017 Aug 01 at 7:35am
Hi,

I'm note quite sure what the referenced muliMaterial is and how the sub-materials are organized/handled. Are the sub-materials normal materials inside the Material Editor or are they handled differently?

In any case this situation needs some special handling and a few corner cases will have to be considered.
You will also need to take care of situations, where the original scene, where stuff is being copied from, got already closed, when the paste operation is happening. Fortunately there's always only one Copy/Paste operation on the fly at any given time.

And here are your tools:
You will need to implement a SceneHook in order to receive the following two messages (well, actually same type, but different sub-type): MSG_DOCUMENTINFO with the following sub-types: MSG_DOCUMENTINFO_TYPE_COPY and MSG_DOCUMENTINFO_TYPE_PASTE, the received data is of type DocumentInfoClipData.

On MSG_DOCUMENTINFO_TYPE_COPY you will receive an AtomArray with the entities being copied. There's also a BaseContainer, which you can use to transfer data to the pasting side. I recommend to store your own BaseContainer with your plugin ID inside that container. I have doubts the provided AliasTrans will help in your situation, but I might be wrong. So upon receiving this message you can determine if any of your multiMaterials is involved in the copy operation and you can prepare whatever data you need for the paste and to perhaps fix links on paste. As said before therefore you can use the provided BaseContainer or, as there's only one Copy/Paste at a time, also global variables come to mind. Just be careful to do proper cleanup.

And then on MSG_DOCUMENTINFO_TYPE_PASTE you can do all the needed stuff, as inserting materials, repairing links and so on and so forth.

Sorry, I have no ready made solution, but i think, with these messages you should be able to achieve what you want.



Cheers,
Andreas
SDK Support Engineer
Back to Top
Aaron94 View Drop Down
Member
Member


Joined: 2015 Dec 15
Online Status: Offline
Posts: 66
Post Options Post Options   Quote Aaron94 Quote  Post ReplyReply Direct Link To This Post Posted: 2017 Aug 01 at 12:33pm
Hi Andreas, thanks for reply! It sounds like you explained everything, I will try to do it later after other features are done.

Basically, our multi-material is a structure of shaders and 10 links to other leaf materials (only shaders). It's basically a fat mixer. All these materials participate in Material Editor too. 

While waiting for your reply I did a trick (based on info from other threads):
Bool cntlMaterial::CopyTo(NodeData * dest, GeListNode * srcNode, GeListNode * destNode, COPYFLAGS flags, AliasTrans * aliasTrans)
{
if (!dest) return FALSE;
if (!srcNode || !destNode) return FALSE;

Bool res = NodeData::CopyTo(dest, srcNode, destNode, flags, aliasTrans);  
// copy linked children
BaseDocument * docD = destNode->GetDocument();
BaseDocument * docS = srcNode->GetDocument();

BaseMaterial * mat = (BaseMaterial *)srcNode;
BaseContainer * data = mat->GetDataInstance();

if (docS != 0 && data != 0)
{
bool anychange = false;
for (int param_link = IDD_PARAMS_LINK_BEGIN + 1; param_link < IDD_PARAMS_LINK_END; param_link++)
{
BaseMaterial * child = (BaseMaterial *)getC4DLink(mat, param_link, PID_MY_STDMAT);
BaseMaterial * childF = (BaseMaterial *)getC4DForcedLink(*mat, param_link, PID_MY_STDMAT);

if (childF != 0 && child == 0)
{
BaseMaterial * new_child = (BaseMaterial *)childF->GetClone(COPYFLAGS_0, NULL);
docS->InsertMaterial(new_child);
data->SetLink(param_link, new_child);
anychange = true;
}
}

if (anychange) {
mat->Message(MSG_UPDATE);
mat->Update(true, true);
EventAdd();
}
}

return res;
}

As you know from experience this code resolves the copy of mixer with linked children only if source and destination documents are opent at the time of "paste" action. If user closes the source document and then paste data from buffer to new doc then only mix material is created there without it's children.
I thought about SceneHook in the past. But will there be problems related to it's threaded execution? We just need to insert into doc. It's better to work with it from the main thread.
Back to Top
gr4ph0s View Drop Down
Member
Member


Joined: 2015 Jul 07
Location: France
Online Status: Offline
Posts: 306
Post Options Post Options   Quote gr4ph0s Quote  Post ReplyReply Direct Link To This Post Posted: 2017 Aug 01 at 1:52pm
Wait an official reply but I guess you could make a SceneHook, intercept MSG_DOCUMENTINFO_TYPE_COPY then build a tempory document with material needed, don't insert it into the list.
Save this document into a variable like that you can check, if this variable is already set, that mean the previous COPY from this document was a copy from your material, so you can free this document and create a new one.
Save this tempory document into the BaseContainer of DocumentInfoClipData.


In MSG_DOCUMENTINFO_TYPE_PASTE get the document from the container of DocumentInfoClipData, and it should work , don't delete document here elsewhere you will not be able to copy twice ! :)


EDIT: The only "problem" is when to free old document if the document where the copy has been done is closed. Because if it's closed, there is no more scenehook, and we don't want to delete the tempo doc when the sceneHook it's free because that will be similar to free this tempo doc when we free the doc.

Then for avoid that, in the MSG_DOCUMENTINFO_TYPE_COPY instead of hold tempo document into a variable, you can hold the tempo document in a Container of the document.
Then instead of just checking if the actual member variable is set, you check all Container of all documents. If in one document you find a tempory doc, you free this tempory doc and create new one.
Then in MSG_DOCUMENTINFO_TYPE_PASTE, you also copy this document into a BaseContainer inside the document where you copy.

And it should work, not sure it's the cleaner way but in the paper it should work.


Edited by gr4ph0s - 2017 Aug 01 at 3:01pm
Technical lover.
Aviable for job in october.
Back to Top
Aaron94 View Drop Down
Member
Member


Joined: 2015 Dec 15
Online Status: Offline
Posts: 66
Post Options Post Options   Quote Aaron94 Quote  Post ReplyReply Direct Link To This Post Posted: 2017 Aug 02 at 3:09am
:(
Will save this description and do it later. It seems a good trial&error cycle is required for this.
Back to Top
gr4ph0s View Drop Down
Member
Member


Joined: 2015 Jul 07
Location: France
Online Status: Offline
Posts: 306
Post Options Post Options   Quote gr4ph0s Quote  Post ReplyReply Direct Link To This Post Posted: 2017 Aug 03 at 1:52am
I just thinked in the case where someone press copy -> close the document and never press paste. So that will lead to a memory leak of the tempo document.
And this time I dont have a solution for it :/

Edit: maybe you could mark the tempo document (adding a container with your plugin id or mark as you prefer) then in the scenehook in the copy hook you just have to list all documents and if one got this mark just delete it.
And make sure to do the same thing when you close c4d. For that use C4DPL_ENDACTIVITY in the PluginMessage function of your scenehook

And now everthing must be fine :) 


Edited by gr4ph0s - 2017 Aug 03 at 2:36am
Technical lover.
Aviable for job in october.
Back to Top
Aaron94 View Drop Down
Member
Member


Joined: 2015 Dec 15
Online Status: Offline
Posts: 66
Post Options Post Options   Quote Aaron94 Quote  Post ReplyReply Direct Link To This Post Posted: 2017 Aug 03 at 2:33am
That shouldn't be a leak since it is saving to custom exchange buffer. If you copy something else then the same  memory slot should be used.
Back to Top
Andreas Block View Drop Down
Forum Moderator
Forum Moderator
Avatar

Joined: 2014 Oct 01
Location: Hannover
Online Status: Offline
Posts: 1430
Post Options Post Options   Quote Andreas Block Quote  Post ReplyReply Direct Link To This Post Posted: 2017 Aug 04 at 9:17am
I'm not sure I understood every notion of the latest posts.

In general you can not add anything to the AtomArray provided in the COPY message. So you will have your own global storage for anything needed. On COPY message you will free everything stored in there and store everything needed for the new Copy&Paste. Yes, if no further copy happens, this memory will be used forever. But that's I think normal. In PluginMessage(C4DPL_ENDACTIVITY) you need to make sure, you free any resource held by your plugin. That's the place to free those resources held by your copy/paste storage. PluginMessage() is not something dedicated to just the SceneHook, but global to all plugins registered in your cdl64/dylib.

See also the manual on Plugin Functions.

Cheers,
Andreas
SDK Support Engineer
Back to Top
Aaron94 View Drop Down
Member
Member


Joined: 2015 Dec 15
Online Status: Offline
Posts: 66
Post Options Post Options   Quote Aaron94 Quote  Post ReplyReply Direct Link To This Post Posted: 2017 Aug 05 at 1:27am
Btw after this message (I mean PluginMessage(C4DPL_ENDACTIVITY) ) the whole app and corresponding process are closing. Memory will be released automatically, so do opened file handles and etc. etc. At least on Windows it works this way.
Back to Top
Andreas Block View Drop Down
Forum Moderator
Forum Moderator
Avatar

Joined: 2014 Oct 01
Location: Hannover
Online Status: Offline
Posts: 1430
Post Options Post Options   Quote Andreas Block Quote  Post ReplyReply Direct Link To This Post Posted: 2017 Aug 07 at 3:01am
Of course you are right, in the end after C4D has quit, all memory is free'd anyway. Still we recommend to properly free all resources allocated by your plugin. For example it makes testing and debugging easier, as Cinema 4D won't report leaks on these allocations if started with "g_alloc=debug", so you can focus on real leaks.

Cheers,
Andreas
SDK Support Engineer
Back to Top
Aaron94 View Drop Down
Member
Member


Joined: 2015 Dec 15
Online Status: Offline
Posts: 66
Post Options Post Options   Quote Aaron94 Quote  Post ReplyReply Direct Link To This Post Posted: 2017 Aug 07 at 1:30pm
You are right! Btw, I was not 100% correct. Just yesterday detected a situation like this:
I have a static singleton class to store some global vars, tmp buffers and other stupid things. And inside it there was a member of type BaseContainer (not a pointer). It was usefull to buffer C4D links because pointers can be lost.
When I quit Cinema 4D it successfully went out of PluginEnd() function. But later (out of developer control) there was some crash (between PluginEnd and final switch off). Furtunatelly it reported in VS debugger a bug with garbage collection for that my thing. And it was solved with a pointer to BaseContainer and manual new/delete at start and end of the plugin session.


Edited by Aaron94 - 2017 Aug 07 at 1:31pm
Back to Top
 Post Reply Post Reply

Forum Jump Forum Permissions View Drop Down

Bulletin Board Software by Web Wiz Forums® version 9.61 [Free Express Edition]
Copyright ©2001-2009 Web Wiz

This page was generated in 0.094 seconds.