Hi @Virtualritz! Nice to see you on this forum. (Filip here, we talked on the 3delight discord)
Posts made by Filip
Hi all! Thanks for your input in this matter.
For now, I have solved my problem by creating the needed resource files from my own code, before I register the plugin using these newly created resource files. This will do for now, although it means I have to ensure that the "res" folder of my plugin has write permission. I will try to solve that in the installer.
"What might be the confusion here is, that you can of course register the same implementation multiple times. But these then would pop up as different plugins in Cinema 4D - which is probably not what @Filip is trying to do. At least from my current understanding."
-This is actually exactly what I am doing! I am registering the same plugin class multiple times, using a different ID. Since the behaviour of the class depends on the ID, this appears to the user to be a series of entirely different shader plugins, which is my intention. The problem was that each such plugin also needed its own unique resource files (to avoid the problem that the resource name has to be unique). But as stated above, I'm solving this by creating the resource files themselves on the fly, whenever they are needed.
I consider this problem solved for now.
Best regards
/Filip
Thanks for the detailed breakdown @ferdinand! Yes, I'm very familiar with how plugins are "usually" registered. Since what I'm trying to do here (registering "auto generated" plugins dynamically) is a bit unusual, I just wanted to check if there was any possible workarounds that I was missing.
Another option I am considering is to write the neccesary description files from to disk from my plugin, and then use them in registration. This would require that my plugin has write access to the directory where the files would be stored. This has to be the "/res" directory of the plugin, right? Is there anyway I could guarantee to have write access there?
/Filip
Thanks for the input @kbar ! That's certainly a possibility, and I believe that is how RSL shaders were handled in the old cineman module. I'll consider this.
/Filip
A possible workaround would be to ask users to create a "dummy" description resource file for every OSL shader they want to load, but since everything else would be handled dynamically it would be a lot more elegant if I was able to use the same resource file for multiple shaders.
/Filip
Hi all!
When registering a shader plugin, the "RegisterShaderPlugin" function has a string parameter naming the resource file that should be used for the shader. The docs say this:
The name has to be unique, i.e. "Tdisplay" cannot be used for 2 different descriptions
For my rendering plugin, I am trying to dynamically create GUI representations for externally stored shaders (compiled OSL shaders), loading all shaders in a given directory. This means that the number of shaders to be created, and their descriptions, is not known at compile time but only at runtime (loaded when c4d starts). The solution I am looking at for this is to register the same shader plugin multiple times, but with different IDs. By associating the ID with a specific OSL-shader file, I can then build the correct GUI, representing the OSL shader, in the GetDDescription function of the shader. This almost works, except for the fact that as soon as I register more than one shader, I get a warning in the c4d console that the same description file is being used more than once, and the description is not loaded.
Since the entire GUI is build in GetDDescription, I would not really need the description resource file at all. Is there any way that I can register a shader without specifying a resource file? E.g., is there any way to have a purely dynamic description?
I am also looking a using the RegisterDescription() function to load the resource file once and then using LoadDescription(id) in GetDDescription to load it. So far, I have not had any luck with this approach.
Any other suggestions?
Thanks!
/Filip
@WickedP said in Custom register plugin:
I have a dialog plugin with a graphical interface. I'd like to be able to register plugins for my plugin, so that I can build them separately if needed, or perhaps so others in the future may be able to.
Hi WickedP!
We are doing something similar in the 3delightForCinema4D renderer plugin. (source available here: https://gitlab.com/3Delight/3delight-for-cinema-4d/. We have a custom plugin system, separate from the normal c4d one, that allows 3rd party modules to add functionality to our plugin.
This is handled via the "PluginMessage" function. When c4d has loaded, our plugin sends a special message to all other plugins, and passes along a pointer to a "pluginmanager" structure. Other plugins can then respond to this message, and register their plugins via the pluginmanager. You can see how this works in our source code. Some hints on where to look:
The "API" for our plugin system consists of a few header files, describing the supported plugin types (called "hooks" and "translators"):
https://gitlab.com/3Delight/3delight-for-cinema-4d/-/tree/master/3Delight/API/include
Here is the main file of the module that manages plugin loading: https://gitlab.com/3Delight/3delight-for-cinema-4d/-/blob/master/3Delight/source/main.cpp
The "PluginMessage" function in this file is where the message to load custom plugins is sent (in response to "C4DPL_STARTACTIVITY".
Here is the main file of an example separate module that registers a number of plugins:
https://gitlab.com/3Delight/3delight-for-cinema-4d/-/blob/master/3Delight Geometry/source/main.cpp
I hope this description is somewhat clear. We have found it to be a really straightforward but powerful way of designing a custom plugin system for c4d! Let me know if you have any questions.
Best regards
/Filip
@r_gigante said in SDK for node based materials, status?:
With regard to your question, we confirm that at the moment there are no news concerning this topic but, again, we are aware of the relevance of the request and it will be delivered accordingly to our product development plan.
Thanks!
On a related note: Is there any statement from MAXON on the future of the old xpresso-style node system?
We are looking to implement a node-system in our plugin, and since API for the new node system is not out yet we may consider using the legacy xpresso API instead. On the other hand, it would not be a good idea to invest resources in this if that part of the SDK might be deprecated and replaced with the new node system.
I realize that you may not be able to provide much info on the roadmap here, but any information that you can give would be super helpful for making this decision!
Cheers
/Filip
Hi!
Are there any news on the SDK for node based materials? I'm interested in the following:
- accessing all the nodes in a given material, as well as their connections.
-creating my own custom nodes.
Are these things possible with the current SDK?
Cheers
/Filip
Thanks for confirming that this approach looks correct!
"never use NULL to check your pointers against to or to assign it to your pointers: rather prefer using nullptr cause while the first comes from a define the second is a built-in pointer type."
-Thanks, noted!
"with regard to the last implementation, why not using:"
-Because we only want to check the next object (obj=obj->GetNext()) if "inCache" is true. Otherwise, the function would not only check the object passed to the function and its cache, but also all subsequent objects on the same level of the hierarchy.
After some more testing the approach outlined above seems to work as intended. I am marking this topic as solved for now.
In case anyone else has a need to determine if a given object is an input object of another generator object, here is the current version of my code to check this:
//Function to determine if an object is used as an input to another generator.
//Just checking if the BIT_CONTROLOBJECT bit is set for the object is not sufficient,
//as this bit is also set for generators.
//Instead, we check this bit for ALL recursively generated objects in the cache of "obj".
//If at least one object in the cache does not have this bit set,
//then "obj" is not an input object.
//
//Calling IsInputObject(obj) returns true if obj is an input object, and false otherwise
bool IsInputObject(BaseObject* obj, bool inCache = false) {
while (obj) {
if (!obj->GetBit(BIT_CONTROLOBJECT)) {
return false;
}
if (!IsInputObject(obj->GetCache(), true)) {
return false;
}
if (inCache) {
if (!IsInputObject(obj->GetDown(), true)) {
return false;
}
obj = obj->GetNext();
}
else {
obj = NULL;
}
}
return true;
}
Sorry, that should be:
bool IsInputObject(BaseObject* obj, bool inCache = false) {
if (!obj) { return true; }
if (!obj->GetBit(BIT_CONTROLOBJECT)) {
return false;
}
if (!IsInputObject(obj->GetCache(), true)) {
return false;
}
if (inCache) {
if (!IsInputObject(obj->GetDown(), true)) {
return false;
}
if (!IsInputObject(obj->GetNext(), true)) {
return false;
}
}
return true;
}
Here is a hypothesis: An object is a control object (i.e., used as input to another generator object) if and only if the object and all recursively generated objects in its cache have the BIT_CONTROL object set.
I wrote this recursive function to check this:
bool IsInputObject(BaseObject* obj, bool inCache = false) {
if (!obj) { return true; }
if (!obj->GetBit(BIT_CONTROLOBJECT)) {
return false;
}
if (!IsInputObject(obj->GetCache(), true)) {
return false;
}
if (inCache) {
if (!IsInputObject(obj->GetDown())) {
return false;
}
if (!IsInputObject(obj->GetNext())) {
return false;
}
}
return true;
}
Testing on a few simple scenes, this appears to work. Could you think of a corner case that would violate this hypothesis?
/Filip
OK, here is some context: This is for a rendering plugin (https://gitlab.com/3Delight/3delight-for-cinema-4d). We have created a system where we can register custom "translators" that translate various objects in a scene to the appropriate rendering commands. I.e., there is a "meshtranslator" for translating polygon objects, various "light translators" for translating custom light types etc.
During rendering, we traverse the scene hierarchy (including caches) and export objects to the renderer. Objects that have BIT_CONTROLOBJECT set are not exported, since we assume them to be input objects to generators.
The problem comes when we want to add a custom translator for an object type that is a generator (say, hair objects). These will then not be exported, because they have the BIT_CONTROLOBJECT set due to being a generator. On the other hand, we can't skip checking for BIT_CONTROLOBJECT, since then the object would be (incorrectly) rendered in the case that it was indeed being used as an input object to another generator.
So: We need a reliable mechanism to determine if a given object A is used as an input object to another object B, and thus should be excluded from rendering. This test needs to work regardless of wheter A is a generator or not.
Does this make sense?
/Filip
The docs say this:
"BIT_CONTROLOBJECT: Input objects are marked by a generator with this bit using BaseObject::Touch(). This bit is also set for the generator object itself."
I want to know if an object is a "proper" input object, i.e., Touch():ed by another generator, or if it is just itself a generator.
/Filip
Hi all,
The BIT_CONTROLOBJECT flag is set for objects that are used as input objects by a generator. But a generator object will also itself have this flag set.
Is there any reliable way to distinguish between these two cases?
Best regards
/Filip
@r_gigante Thanks for confirming. We will try to reverse engineer the filenames based on that data.
Cheers
/Filip
Thanks for the input zipit!
That is promising, but unfortunately does not quite help in my case as I really need the filename rather than the bitmap itself. The rendering in my plugin is also, for various good reasons, not guaranteed to happen within a InitRender()/FreeRender() context.
/Filip
Hi!
For a render engine plugin, I would like to support animations (file sequences) as textures. In the bitmap shader, there are settings for animation, and c4d the automatically parses the texture file name to identify the frame number part which is modified per frame to render the appropriate texture.
Is there anyway to get, for a given Bitmap shader and timepoint (BaseTime or frame), the exact texture name that c4d would load for rendering?
We could try to reverse engineer this of course, but it would be really convenient and more robust if there was a function for accessing this.
Thanks!
/Filip
Well, in this case the double is being passed to an external library (the renderer) right after this code, and the library expects a double.
Now, here comes a friendly rant: I have read the code style guide you linked to, but I'm actually not quite sure how to interpret it or what to think of it. To me it appears to be a mix of things that could potentially be important, and things that are just internal stylistic recommendations. And it makes no distinction between the two.
Take these three examples:
-"Always start a new line after the for statement."'
-"Do not write to global structures from a thread."
-"Do not use external libraries (e.g STL or BOOST) unless absolutely necessary".
The first one is clearly just a preference from MAXON (and I don't see why I should follow it if I prefer to structure my code in another way...). The second one seems to be a serious warning, and it sounds likely that violating this rule could cause a bug. For the third one, I have no idea. Maybe it is just a suggestion as well, and maybe linking my plugin with STL or BOOST could cause bugs. The docs do not say.
The recommendation for using MAXON datatypes also kind of falls into this category: I can't tell from the docs if it is just a style recommendation from MAXON, or something that could actually have an effect on my code.
To me, the code guide would be much more useful if it only listed things that are actual rules (or at least clearly separated rules and important advice from purely stylistic recommendations).
Cheers
/Filip