Getting the rendered color from a surface

  • On 23/05/2015 at 05:25, xxxxxxxx wrote:

    I need to use:

    BaseDocument* InitBakeTexture(BaseDocument* doc, TextureTag** textags, UVWTag** texuvws, UVWTag** destuvws, Int32 cnt, const BaseContainer& bc, Int32* err = @F, BaseThread* th = @F)

    because I will be baking ALL the textures.
    So, how can I create the array with all the texture tags? I mean, the TextureTag** textags.
    Is it an array of arrays?!?

  • On 23/05/2015 at 05:28, xxxxxxxx wrote:

    Also, the object will probably only have one UVW tag. Must I fill the UVWTag array with multiple copies of the only UVW tag to match the number of Texture tags?
    Oh, I also don't know how to fill the UVWTag** array :-(

  • On 23/05/2015 at 10:26, xxxxxxxx wrote:

    A ** is a pointer to a pointer.  So you will need to allocate as many of those in an array as needed and point each element to a TextureTag* (what you get back from the object as you GetTag() or whatever).  Do not forget to free the array (just the array) when done.  I am surprised that a BaseList was not used instead for both.

    It sure does appear that you will need matching counts for textags, texuvws, and destuvws (though it appears that the latter could be nullptr).  Either that or cnt represents the total of all.  It may be easier to use a loop through each document object but let's see if we get further information.

    Here is another good thread to help:


  • On 23/05/2015 at 14:03, xxxxxxxx wrote:

    Wow!!! Reading that thread I got a bit worried. It seems that using InitBakeTexture() and BakeTexture() is not easy :-(
    Do I really need to create a new thread in my code?!?
    I don't know how to do that. :-(

  • On 24/05/2015 at 04:32, xxxxxxxx wrote:

    Definitely, I can't understand how to create my own thread and I believe that is required to check if the BakeTexture() has finished baking :-(
    Could anyone help me out?

  • On 24/05/2015 at 05:26, xxxxxxxx wrote:

    Is this the correct way to create a array of pointers to pointers?

    TextureTag* text_tag[tags_count]; //tags_count is the number of texture tags, already calculated previously
    TextureTag** text_tags=text_tag;

    LONG index=0;

    while (first_tag!=nullptr) {
         if (first_tag->IsInstanceOf(Ttexture))
              text_tag[index++]=(TextureTag* ) first_tag;

  • On 24/05/2015 at 06:55, xxxxxxxx wrote:

    Why not use something like this ?

        BaseDocument* BakeTextureTest(BaseDocument* doc, Int32 tagsCnt,const BaseContainer &settingsBc) 
        { //Remo: 24.05.2015  BakeTextureTest
          maxon::BaseArray<TextureTag*> textags;
          maxon::BaseArray<UVWTag*> texuvws;
          maxon::BaseArray<UVWTag*> destuvws;
          // ... fill arrays ...
          for(Int32 i=0; i<tagsCnt; ++i)
            textags[i] = nullptr;
            texuvws[i] = nullptr;
            destuvws[i] = nullptr;
          BaseDocument* bakedDoc = InitBakeTexture(doc,textags.GetFirst(),texuvws.GetFirst(),destuvws.GetFirst(),tagsCnt,settingsBc);
          return bakedDoc;

  • On 24/05/2015 at 10:07, xxxxxxxx wrote:

    That looks simple enough.
    But will that work for the InitBakeTexture() that deals with several texture tags? It seems to do so, but it only points to the first tag.
    Isn't it supposed to be filled with only the texture tags instead of being initialized with nullptr and simply pointing to the first one?

  • On 24/05/2015 at 10:17, xxxxxxxx wrote:

    You do not need to make your own thread.  If you pass nullptr for it, the main C4D thread will be used (which is okay to do).

    On using BaseArray and GetFirst(), I am not sure that is going to work properly.  GetFirst() returns the first element (in this instance, a TextureTag* ).  InitBakeTexture() needs a TextureTag** to iterate through the array of TextureTag* elements.

    Remember that defining the array size locally like that (TextureTag* text_tag[tags_count]) will cause the array to be created on the stack instead of in memory (where you would use memory allocations).  Might work most of the time, but if you are dealing with a large number of elements, it make cause a stack overflow - basically, you run out of stack memory.

    I'd like to know if BaseArray or PointerArray could be used in this instance.

  • On 24/05/2015 at 10:34, xxxxxxxx wrote:

    I would also like to know if BaseArray could be used.
    If not, my code could be used?

    TextureTag* text_tag[tags_count]; //tags_count is the number of texture tags, already calculated previously   
    TextureTag** text_tags=text_tag;   
    LONG index=0;   
    while (first_tag!=nullptr) {   
         if (first_tag->IsInstanceOf(Ttexture))   
              text_tag[index++]=(TextureTag* ) first_tag;   

    As for creating the array in the stack with this type of definition, I will only be baking one object and, at most, 10 to 20 Texture tags (usually much less than that). So, I guess there will be no stack memory problem.

    As for not creating a Thread, will the control only return to my code (in the main thread) after the baking is complete?

  • On 25/05/2015 at 07:28, xxxxxxxx wrote:

    On using BaseArray and GetFirst(), I am not sure that is going to work properly.
    It should work, because GetFirst() return pointer to the firs element.
    Another alternative would be to use  &array[0] instate.

    Here is improved code that will compile and run.
    Of course it is still not complete and will result in error 3007==BAKE_TEX_ERR_WRONG_BITMAP.

        bool BakeTextureTest2(BaseDocument* doc) 
        { //Remo: 25.05.2015
        	if(nullptr == doc) return false;
        	BaseObject *obj = doc->GetActiveObject();
        	if (nullptr == obj) return false;
        	maxon::BaseArray<TextureTag*> textags;
        	maxon::BaseArray<UVWTag*> texuvws;
        	maxon::BaseArray<UVWTag*> destuvws;
        	for (BaseTag *tag = obj->GetFirstTag(); tag; tag = tag->GetNext()) {
        		if (tag->IsInstanceOf(Ttexture)) {
        			TextureTag* texTag = static_cast<TextureTag*>(tag);
        	// ! now fill texuvws and destuvws arrays !
        	BaseContainer settingsBc; 
        	//fill settingsBc here ... BakeTexEnums
        	BAKE_TEX_ERR bakeError = BAKE_TEX_ERR_NONE;
        	AutoFree<BaseDocument> bakedDoc(
        		InitBakeTexture(doc, //The document. 
        			&textags[0], //The texture tags to bake. Must be assigned to objects. 
        			texuvws.GetFirst(), //The UVW tags to bake. 
        			nullptr/*destuvws.GetFirst()*/,  //The destination UVW tags for the bake. If not nullptr, the current projection is transformed into the uvw tags. 
        			textags.GetCount(), //The number of tags in textags, texuvws and destuvws arrays. 
        			settingsBc, //The bake settings: BakeTexEnums 
        			&bakeError //Assigned the error result, if not nullptr: BAKE_TEX_ERR 
        	if (BAKE_TEX_ERR_NONE != bakeError) {
        		print("bakeError ",bakeError);
        		return false;
        	//do something with bakedDoc ...
        	return true;

  • On 25/05/2015 at 11:31, xxxxxxxx wrote:

    Thank you, I will give it a try (tomorrow).
    I was having doubts with the previous code snippet because the tags array was filled with nullptr and that was what was being feed into the InitBakeTexture().

  • On 26/05/2015 at 09:36, xxxxxxxx wrote:


    the bake functions are relatively old functions, BaseArray is a relatively new class so these two things have nothing to do with each other. But it seems that indeed these two can be combined. Here is some code I came up with:

    // let's use the same UVW tag for all texture tags  
    UVWTag* uvwTag = (UVWTag* )obj->GetTag(Tuvw);  
    if(uvwTag == nullptr)  
     return true;  
    BaseTag* tag = obj->GetFirstTag();  
    // prepare arrays for texture tag ptr and uvw tag ptr  
    maxon::BaseArray<TextureTag*> textureTagArray;  
    maxon::BaseArray<UVWTag*> uvwTags;  
    // save ptr of all texture tags; fill uvw array  
     if(tag->GetType() == Ttexture)  
         textureTagArray.Append((TextureTag* )tag);  
         uvwTags.Append((UVWTag* )uvwTag);  
     tag = tag->GetNext();  
    // check if there is something to do  
    if(textureTagArray.GetCount() == 0)  
     return true;  
    // setup bake settings  
    BaseContainer settings;  
    settings.SetInt32(BAKE_TEX_HEIGHT, 400);  
    settings.SetInt32(BAKE_TEX_PIXELBORDER, 2);  
    settings.SetBool(BAKE_TEX_CONTINUE_UV, true);  
    settings.SetBool(BAKE_TEX_USE_PHONG_TAG, true);  
    settings.SetVector(BAKE_TEX_FILL_COLOR, Vector(0.0));  
    settings.SetBool(BAKE_TEX_COLOR, true);  
    settings.SetBool(BAKE_TEX_COLOR_ILLUM, false);  
    settings.SetBool(BAKE_TEX_COLOR_SHADOWS, false);  
    settings.SetBool(BAKE_TEX_COLOR_LUMINANCE, false);  
    settings.SetBool(BAKE_TEX_COLOR_DIFFUSION, false);  
    // InitBakeTexure  
    BAKE_TEX_ERR err;  
    BaseDocument* bakeDoc = InitBakeTexture(doc,textureTagArray.GetFirst(),uvwTags.GetFirst(),nullptr,textureTagArray.GetCount(),settings,&err,nullptr);  
    // if success, do bake  
    if(err == BAKE_TEX_ERR_NONE)  
     // prepare multipass bitmap  
     MultipassBitmap* bitmap = MultipassBitmap::Alloc(400,400,COLORMODE_RGB);  
     // bake  
     // show result  
     // clear result  
    // clear bake document  

    best wishes,

Log in to reply