Create Shader with Preset Values

On 06/01/2017 at 14:07, xxxxxxxx wrote:

I'm trying figure out the best way to create a shader with values that are generated through my own code. The way I'd envision this is to be able to add a new entry in the shader popup - when that option is chosen my plugin would create a native C4D shader but with my own information (for example a gradient with knots that I specify).

Because multiple materials and channels might be active, I can't really use a menu plugin and determine where to place the resulting shader, so it seems like the shaderpopup makes the most sense. It doesn't look like there's any way to modify the shaderpopup in Python though. I think BuildShaderMenu and/or HandleShaderPopup might make this possible in C++, but I'm not sure how they work (the former is private, and the latter has no examples).

Any ideas on the best way to accomplish this? The project is Python but if it's possible in C++ porting or extending might be an option for me.

On 06/01/2017 at 15:45, xxxxxxxx wrote:

As I know for adding shader to the shader menu you have to register it. And for new registration as I know you need to restart C4D. But that didn't solve the problem since even if you get a totally neawly shader it will neeed is own unique plugin id...

Why not simply make a shader that can be dynamic ?
Do you want to change type or you just want to add preset to this shader ?
If it's the last one why not simply register you own shader and then inside of it add a cycle data for allowing some preset ?
This might also work for changing type but it could work only in R18 with SetDParameter /GetDParameter since I don't know if a shader can have UD and how they will be handle by C4D and if they will get displayed correctly.

You could take a look to my plugin RefractiveIndex-Importer,where I use a TagPlugin with a dynamique UI(I use UserData instead of traditional Resource file which are too static...).
For storing preset I just use a simple json file for define some preset and get the possibility to create/delete them.
btw: Sorry for my ugly code style... I was young ^^

On 07/01/2017 at 09:32, xxxxxxxx wrote:

I would also like to see an example of HandleShaderPopup() and HandleShaderPopupI().
The docs don't even tell us why, or when, one version is better to use than the other.


On 09/01/2017 at 02:00, xxxxxxxx wrote:


as far as I can tell there is no way to edit this list of shaders. The functions you mention are used to get that list and handle the interactin with that pop-up. Something like this:

// get shader list  
BaseContainer shaderList;  
BuildShaderPopupMenuI(&shaderList, nullptr, nullptr, 0);  
// show shader list  
Int32 res = ShowPopupMenu(nullptr, MOUSEPOS, MOUSEPOS, shaderList);  
// handle result  
BaseShader* shader = nullptr;  
if (HandleShaderPopupI(material, shader, res, 0) && shader)  
  BaseShader* clone = static_cast<BaseShader*>(shader->GetClone(COPYFLAGS_0, nullptr));  
  // insert shader  
  material->SetParameter(DescID(MATERIAL_COLOR_SHADER), clone, DESCFLAGS_SET_0);  

best wishes,

On 09/01/2017 at 12:18, xxxxxxxx wrote:

Thanks for the code example.
But how do we go about capturing the specific popup item that was selected?
Normally I get the mouse coords with a MouseInput() method or the Message() method. But some plugin types like MaterialData don't use them.
What plugin types are we supposed to use these functions in?
I'm using a MaterialData plugin and I don't see anywhere to create the mouse coords stuff.

Here is how I'm getting the shaderList data
But now that I have the data. How do I use it to get the specific item that was selected?

    BaseMaterial *mat = doc->GetFirstMaterial();  
  if (!mat) return false;  
  //Get shader list  
  BaseContainer shaderList;  
  BuildShaderPopupMenuI(&shaderList, nullptr, nullptr, 0);  
  //Get the mouse's coords to see which popup item ("Texture") the cursor is over  
  LONG screenPosX = 0;  
  LONG screenPosY = 0;  
  LONG res = ShowPopupMenu(nullptr, screenPosX, screenPosX, shaderList);  
  //Handle result  
  BaseShader *shader = nullptr;  
  if (HandleShaderPopupI(mat, shader, res, 0) && shader)  
      //Get the ID#s and String values for all of the items in the shader's "Texture" popup list  
      LONG index = 0;  
      while (shaderList.GetIndexId(index) != NOTOK)  
          LONG id = shaderList.GetIndexId(index);  
          GeData data = shaderList.GetData(id);  
          GePrint("id String: " + LongToString(id) + " = " + data.GetString());  


On 09/01/2017 at 23:48, xxxxxxxx wrote:


for questions no longer related to this thread's original topic (and to C++) please open a new thread. Thanks.

best wishes,