Cleaning up Plugin Related Materials
On 10/10/2016 at 13:45, xxxxxxxx wrote:
Cinema 4D Version: 14
Platform: Mac ;
Language(s) : C++ ;
Hi, I have a Object Plugin that has some Materials associated with it. I'm pretty sure I understand how to create and modify the Materials correctly, with MSG_MENUPREPARE and MSG_DESCRIPTION_CHECKUPDATE. But how would I remove the Materials when the object is deleted?
If I use Free() then that removes the Materials when the Object is made editable instead of just when it's deleted, and I would want the returned hierarchy to have working Texture Tags. MSG_DOCUMENTINFO doesn't seem to cover deleting objects, just inserting, copying and pasting. From my understanding MSG_MULTI_MARKMATERIALS hands the copying and marking the Materials as used, so I'm not too sure where to look next.
Any help would be appreciated.
On 11/10/2016 at 02:54, xxxxxxxx wrote:
this is actually not the way Cinema 4D works and it's pretty uncommon. I'm not aware of any features in Cinema behaving this way. For example using the Active Object Dialog (from the cinema4dsdk examples) you can easily verify, that after deleting a Physical Sky, there's still a hidden Sky Material left over.
So, unfortunately, no, there are no direct means to achieve what you want.
That being said, I had a weird idea, that might work for you or not. Neither tested, nor an official MAXON recommendation. And always make sure, you are in the main thread, when changing the scene (i.e. deleting materials).
But you might want to play around with it nevertheless to see if it works for you:
- Create a SceneHook plugin which holds references to the objects and materials belonging to these. Your object generator would then register objects and materials in this SceneHook on creation.
- Now, have the SceneHook react either on certain change messages or on an event fired in Free() of your generated object.
- In SceneHook reacting on above event, you check the BaseLinks to your generated objects. If a link is broken, it (obviously) means the object got either deleted or got made editable.
- Then you can check the material(s) belonging to the removed object, if these are still assigned to anything. Probably easier than a message is to use the MatAssignData, like so:
mat->GetParameter(ID_MATERIALASSIGNMENTS, d, DESCFLAGS_GET_0); MatAssignData* const mad = (MatAssignData* )d.GetCustomDataType(CUSTOMDATATYPE_MATASSIGN); if (mad == nullptr) return false; // then use e.g. mat->GetObjectCount()
- Throw away those unused materials.
This of course has one obvious major drawback. The deletion of materials is not atomic with the deletion of the generated object, so you would have an inevitable additional undo step for the user.
And you'd need to add further measures to keep the data in the SceneHook up to date. E.g. when a scene gets loaded or the BaseDocument gets copied.
But I guess, you are already aware of such issues, as you run into these in other occasions as well. For example, when your generator object is being copied and pasted into another document.
As mentioned before, please do not take this as a MAXON proven recipe, but rather as a basis for brainstorming and tests.
Another way simpler option might be a "cleanup materials" CommandData plugin accompanying your ObjectData plugin. It could work two ways. Again you could have a SceneHook to store references to "your" materials. Or you could mark materials by storing something at your plugin ID in the BaseContainer of a material. In this way, yes, the user would need to click a button to manually clean up redundant materials, but on the other hand you wouldn't introduce a completely new behavior which is harder to implement and harder to test (in all situations and consequences).
On 12/10/2016 at 09:35, xxxxxxxx wrote:
Thanks for the incredibly thorough response! I think this is plenty to get me by, I really appreciate the help. I'll likely go with simply not cleaning up the materials, it was functionality I assumed I should have.