On 21/12/2016 at 06:51, xxxxxxxx wrote:

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

Hi again,

Working on my Seamilar plugin I use the CallUVCommand to perform a relax and realignment of UVs. To do so I get a TempUVHandle by calling the GetActiveUVSet. I read in forum replies that for this to work I need to set the document mode into UVpolygon (or UVpoint).
However, I noticed that even doing so, the returned TempUVHandle is always null IF no BodyPaint 3D Texture View has been opened since Cinema 4D was started.
Open a new Bodypaint 3D Texture View window, and from then on (even after closing the window) the returned TempUVHandle is always successful (in UV mode).
Now, I will be looking for any possible workaround to this, but was wondering if someone already knows a workaround, or maybe I am just doing something wrong?

This is my current code:

  // Cinema must be in UV Poly edit mode  
  BaseDocument* doc = GetActiveDocument();  
  Int32 currentDocMode = doc->GetMode();  
  if (Muvpolygons != doc->GetMode())  
  TempUVHandle* handle = GetActiveUVSet(doc, GETACTIVEUVSET_ALL);  
  if (handle)  
  // set the mode back  
  if (Muvpolygons != currentDocMode)  

So, when I start Cinema 4D with a default layout (or any other one which has no BodyPaint 3D Texture View) the above code will return a null handle. Open a new Texture View, close it, and above code will return a correct handle. Same for R17

On 22/12/2016 at 08:46, xxxxxxxx wrote:

Hi C4DS, thanks for writing us.

I confirm that the GetActiveUVSet() returning Null is by design and it's required in order to have the objects used to fill the TempUVHandle properly allocated. This occurs, as pointed in your post, when the doc mode is set to Muvpoints or Muvpolygon and the Texture View has not been opened at least once.

Beside this, please note that if doc mode is set to Mpoints or Medges or Mpolygons , even if the Texture View has never been opened, the GetActiveUVSet() should return a valid TempUVHandle pointer whose data should match those coming from using invoking the method in the first scenario (Muvpoints or Muvpolygon and the Texture View opened at least once).

if (currentDocMode != Mpoints || currentDocMode != Medges)  
  doc->SetMode(Mpoints); // or Medges is equivalent
TempUVHandle *handle = nullptr;  
UVWStruct *uvw = nullptr;  
handle = GetActiveUVSet(doc, GETACTIVEUVSET_ALL);  
if (handle)  
  GePrint("PolyCount from TempUVHandle: " + String::IntToString(handle->GetPolyCount()));  
  GePrint("PointCount from TempUVHandle: " + String::IntToString(handle->GetPointCount()));  
  uvw = handle->GetUVW();  
  if (uvw)  
      // use uvw data   

Best, Riccardo

On 22/12/2016 at 11:32, xxxxxxxx wrote:

Hi Riccardo,
Thanks for the details.
It seems I misinterpreted the need to change to UV polygon mode.

I got the UV handle working as you described, which is exactly what I needed.
However, I can not get CallUVCommand working (to perform relax or realign) ... unless the Texture View has been opened once.
I understand this to be by design, as you mention in your first sentence.
Is there a way for a plugin to trigger the objects being properly allocated, as when manually switching to Muvpolygon mode and opening a Texture View?


On 23/12/2016 at 07:37, xxxxxxxx wrote:

Hi Daniel, thanks for providing these additional comments.

I've looked more in detail and running the code below the method that requires the Texture View to be opened at least once isn't CallUVCommand to fail - it indeed produces the correct results in terms of uv data, but it's SetUVW() method belonging to TempUVHandle returning false and thus not properly updating the uv data.

Diving into it is seems that the SetUVW requires the Texture View to be opened and showing the current UVWTag.

if (uvw)  
  // use uvw data   
  BaseObject *op = handle->GetBaseObject();  
  if (!op)  
      return false;  
  const Vector *pvPoints = handle->GetPoint();  
  if (!pvPoints)  
      return false;  
  const CPolygon* pPolys = handle->GetPoly();  
  if (!pPolys)  
      return false;  
  Int32 lPointCount = handle->GetPointCount(), lPolyCount = handle->GetPolyCount();  
  BaseSelect* pPolySel = handle->GetPolySel();  
  BaseSelect* pPointSel = handle->GetUVPointSel();  
  Int32 mode = handle->GetMode();  
  BaseContainer set;  
  set.SetBool(RELAXUV_KEEP_BORDER, true);  
  set.SetBool(RELAXUV_KEEP_NEIGHBORS, false);  
  set.SetBool(RELAXUV_KEEP_POINTSEL, false);  
  set.SetBool(RELAXUV_CUT_EDGESEL, false);  
  set.SetInt32(RELAXUV_MAX_ITERATIONS, 10);  
  Bool res = CallUVCommand(pvPoints, lPointCount, pPolys, lPolyCount, uvw, pPolySel, pPointSel, op, Mpolygons, UVCOMMAND_RELAX, set);  
  if (!res)  
      GePrint("CallUVCommand failed");  
      return res;  
    res = handle->SetUVW(uvw);  
  if (!res)  
      GePrint("SetUVW failed");  
      return res;  

Best, Riccardo

On 23/12/2016 at 08:20, xxxxxxxx wrote:

Honestly, I didn't think to check the SetUVW call, I assumed it was the CallUVCommand which didn't perform, although returning success.
Actually, I am using the newer SetUVWFromTextureView call instead of SetUVW as I need the additional parameter to avoid storing the undo state. But here as well, this SetUVW... returns false, as you mentioned.

So I guess there's no workaround and the Texture View needs to be opened (at least once), which probably isn't possible via plugin?

On 27/12/2016 at 01:54, xxxxxxxx wrote:

Hi Daniel,

I confirm there actually no workaround to your workflow which indeed requires the Texture View to get opened by user interaction.

Best, Riccardo

On 27/12/2016 at 04:44, xxxxxxxx wrote:

Thanks for letting me know.

On 13/01/2017 at 01:16, xxxxxxxx wrote:

I have been informed by a fellow user to do a CallCommand(170103) which opens a new Texture View. Works perfectly.
Is there maybe a way to close the view
I have searched the forum and found the same question asked back in 2013, without conclusive answer. Hoping it might get answered now.

This topic has been set to [SOLVED] ?