Set Material Default Projection [SOLVED]

On 13/09/2014 at 14:02, xxxxxxxx wrote:

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

How do we set the default projection option in a MaterialData plugin?

When we create a standard C4D material and drop it on an object. The projection option for the texture tag is set to UVW by default.
But when I create my own material with a MaterialData plugin and drop it on an object. The default projection is set to Spherical in the texture tag.

How can I make it default to UVW like the built-in C4D materials?


On 14/09/2014 at 14:31, xxxxxxxx wrote:

TextureTag *pTexTag = (TextureTag* )pPolyonObject>GetTag(Ttexture);
Material *pMat = Material::Alloc();


BaseContainer tagData = pTexTag->GetData();

On 14/09/2014 at 16:40, xxxxxxxx wrote:

Hi Kbar.
I know how to grab the texture tag and then change it to UVW mode.
This the way I do that:


What I'm trying to do is set the generated texture tag to UVW automatically when I drop my custom material on an object.
When we drag & drop a standard material onto an object. C4D creates a texture tag on the object with it's projection option set to UWV.
What is telling the tag to switch to UVW mode like that?

Do I maybe need to send some kind of CoreMessage to C4D from my material telling it to change the generated texture tag's mode?
How would I do that?


On 14/09/2014 at 20:48, xxxxxxxx wrote:

I don't know how Maxon does it. But this is what I've dreamed up. And it seems to work so far.
I'm using a small MessageData plugin in my MaterialData plugin that catches a SEA message sent from the MaterialData plugin when the material is dropped onto an object.
Then the MessageData plugin changes the texture tag's projection to UVW.

Maybe this will help someone else out if they ever run up against the same problem.

//Be sure to use unique ID#s obtained from  
#define ID_SIMPLEMAT 10000004  
#define ID_MESSAGE   10000005  
/////////// MessageData plugin/////////////////  
class MyMessage: public MessageData  
  virtual Bool CoreMessage(LONG id, const BaseContainer &bc);  
Bool MyMessage::CoreMessage(LONG id, const BaseContainer &bc)  
      //GePrint("Recieved sea message");  
      BaseDocument *doc = GetActiveDocument();  
      BaseTag *tag = doc->GetActiveTag();  
          GeData d;              
          tag->GetParameter(DescID(TEXTURETAG_MATERIAL), d, DESCFLAGS_GET_0);  
          String name = d.GetLink(doc, NULL)->GetName();  
          if(name == "My Material") tag->SetParameter(DescLevel(TEXTURETAG_PROJECTION), GeData(TEXTURETAG_PROJECTION_UVW), DESCFLAGS_SET_0);              
  return TRUE;  
Bool RegisterMyMessage(void)  
  return RegisterMessagePlugin(ID_MESSAGE, "My Message", 0, gNew MyMessage);  
/////////// MaterialData plugin/////////////////  
//...MaterialData class and various overridden methods here...  
//The part of the Message() method that sends out a SEA message  
Bool MyMaterial::Message(GeListNode* node, LONG type, void* data)  
  //Send out a SEA message when this material is dropped on an object  
  //...the rest of your MaterialData code stuff here...  
  return TRUE;  
//...The rest of the overridden MaterialData methods here...  


On 14/09/2014 at 23:25, xxxxxxxx wrote:

Why use a MessageData plugin and SpecialEventAdd? You use the right message already. Look
at its documentation, here. You can create your own tag and fill it into the "result" member of the
passed MaterialDragAndDrop structure to prevent the creation of a default tag.


On 15/09/2014 at 07:37, xxxxxxxx wrote:

Yeah I saw that in the docs Niklas.
But it doesn't tell me anything at all about how to actually use it. So I had to invent my own method.

If that struct is capable of changing the material's texture tag options. I'd like to know how?


Edit- I also hate using the material's name as the thing it looks for. Because the user can change it.
So I'm still looking for a better way to find the material that a ttag belongs to.

On 15/09/2014 at 08:47, xxxxxxxx wrote:

I guess getting the name of the material from the tag "link field" should be doable

On 15/09/2014 at 10:07, xxxxxxxx wrote:

There has to be a better way than using the name property.
I wouldn't even need it if Maxon documented the MaterialDragAndDrop struct properly.

     MaterialDragAndDrop mdd;  
     mdd.doc = GetActiveDocument();  
     mdd.op = mdd.doc->GetActiveObject();  
     mdd.result = mdd.op->GetTag(Ttexture);  
     GePrint(mdd.result->GetName());  //<---Crash!!!  

Obviously I'm doing it wrong. And it's crashing because the tag doesn't exist yet.
But how the heck are we supposed to use this struct code to get the tag the material generates?
The docs don't tell us squat how to use it. Less than squat.
Squat looks at the docs and says "Man, that ain't squat". 😠


On 15/09/2014 at 10:51, xxxxxxxx wrote:

you need to do checks about GetActiveObject() and GetTag() , I see if no object it will crash, but not sure also if the whole process is correct

On 15/09/2014 at 11:10, xxxxxxxx wrote:

Well. That was just a quick and dirty example.
I can add error checking to resolve the crash. But I still can't access the texture tag and change it using the struct as the docs seem to hint at. But never exaplin how to actually do it.

     MaterialDragAndDrop mdd;  
     mdd.doc = GetActiveDocument();  
     if(!mdd.doc) return FALSE;  
     mdd.op = mdd.doc->GetActiveObject();  
     if(!mdd.op) return FALSE;  
     //Nope..doesn't work   
     //It doesn't crash...but it doesn't change the tag's projection option either. Because the tag does not exist yet!!!  
     mdd.result = mdd.op->GetTag(Ttexture);  
     if(mdd.result) mdd.result->SetParameter(DescLevel(TEXTURETAG_PROJECTION), GeData(TEXTURETAG_PROJECTION_UVW), DESCFLAGS_SET_0);  

I'm sure I'm using it wrong.


Thanks for your input guys.
I'm feeling very angry and grumpy at Maxon right now for their crappy docs. So please excuse me if I come off as rude or snappy in this thread.

On 15/09/2014 at 11:31, xxxxxxxx wrote:

I'm not sure if this may work or not, but I think MaterialDragAndDrop should be a pointer, constructed inside the texture tag constructor, and when you encounter the message MSG_MATERIALDRAGANDDROP your problem will vanish because the tag is there

On 15/09/2014 at 11:56, xxxxxxxx wrote:

Sorry Scott, but the documentation is as clear as it can get.

Received by a material upon dropping an instance of the material onto an object. The material can choose to create a tag of its own, or trigger other actions, instead of letting CINEMA 4D create a normal material assignment. The corresponding data is MaterialDragAndDrop.

For example Sketch and Toon creates its own type of tag and returns it in result. CINEMA 4D creates the undo for it and activates it. Inserting the tag is done by the material.

And in the description of MaterialDragAndDrop:

BaseTag* result
If you choose to create a tag of your own, point this pointer to it. CINEMA 4D will create the undo and activate the tag. (You still have to insert the tag manually onto the object.)

// note: nullptr checks omitted
Bool MyMaterial::Message(GeListNode* node, Int32 type, void* pData)
    BaseMaterial* mat = static_cast<BaseMaterial*>(node);
    MaterialDragAndDrop* mdd = static_cast<MaterialDragAndDrop*>(pData);
    mdd->result = mdd->op->MakeTag(Ttexture);
    mdd->result->SetParameter(TEXTURETAG_MATERIAL, mat, DESCFLAGS_SET_0);
    return true;
  return MaterialData::Message(node, type, pData);

On 15/09/2014 at 12:25, xxxxxxxx wrote:

Thanks Niklas. That works. 👍

But I disagree about the docs. The docs are not even remotely saying what you've written there.
What on earth made you think of using this code based on the docs saying use your own pointer?:
MaterialDragAndDrop *mdd = static_cast<MaterialDragAndDrop*>(pData);

Since when does use your own pointer = void *pData?
I don't see the connection at all. That's as clear as mud to me.


On 15/09/2014 at 23:00, xxxxxxxx wrote:

Originally posted by xxxxxxxx

Thanks Niklas. That works. 👍

But I disagree about the docs. The docs are not even remotely saying what you've written there.
What on earth made you think of using this code based on the docs saying use your own pointer?:
MaterialDragAndDrop *mdd = static_cast<MaterialDragAndDrop*>(pData);

Since when does use your own pointer = void *pData?
I don't see the connection at all. That's as clear as mud to me.


It's Cinema's message system. I've seen you using it correctly before already, too. The documentation
tells you:

  1. MSG_MATERIALDRAGANDDROP is a message type that is sent to NodeData plugins.
  2. The data that is passed to the NodeData::Message() call is MaterialDragAndDrop
  3. The MaterialDragAndDrop::result member can be set to a custom tag, preventing the
    caller (in this case Cinema 4D itself) to create the default tag.
  4. If you create a custom tag, it does everything else that is required (undo step, selection, ...)

And as you should know, there is void* parameter for the NodeData::Message() method that
points to the data of the message. Depending on the message type, you can cast it to a different
pointer type in order to access the underlying data.

To show a different example:

  /* The void* parameter for the Message() function is the
   * address of a GetCustomIconData structure which the message
   * sender expects us to fill with the required information. */
  GetCustomIconData* data = static_cast<GetCustomIconData*>(pData);
  IconData* icon = data->dat;
  if (icon->bmp)
    icon->bmp = m_customIcon->GetClone();
  icon->x = 0;
  icon->y = 0;
  icon->w = icon->bmp->GetBw();
  icon->h = icon->bmp->GetBh();
  data->filled = true;
  return true;


On 16/09/2014 at 10:27, xxxxxxxx wrote:

OK. Thanks for explaining what when through your head.
It helps me to know what other people are thinking when they use the docs. So I can learn how to decrypt them better.

As I keep saying to you. You're cheating.Wink
You're not reading the docs. You are taking what you've learned from other people. Then using that information to "decrypt" what's not actually physically written in the page.

I know you don't share the same opinion. And you think it's fun to figure out these little puzzles.
But IMO the C4D docs require far too much of this. And it's really annoying when you're just trying to get something simple done. And don't want to play the "Solve the docs" puzzle game.
IMO. Any time the reader has to rely on this much previously learned knowledge. The docs are not clear enough and they fail.