SceneHook and DisplayControl

On 26/02/2018 at 23:06, xxxxxxxx wrote:

User Information:
Cinema 4D Version:   r19 
Platform:      Mac OSX  ; 
Language(s) :     C++  ;


i've got a project, the main idea is to draw the object wireframe in a selected color. (based on the object color or the layer color or an arbitrary color)

I've decided to rebuild something like the layermanager. So i got a sceneHook to store a list of dummy nodes with colors. When i drag object on those "mylayer" i'm adding in the object's BaseContainer a baselink to the layer. (not sure if it's something i'll go with)

In the scenehook, i'm using inside the function  DisplayControl the function

bd->DrawPolygonObject(bh, op, DRAWOBJECT_FORCELINES|DRAWOBJECT_USE_CUSTOM_COLOR,nullptr,mycolor);

And it's working fast.
The problem is when i'm trying to access the object base container and retrieve the color of my "mylayer"
the function "DisplayControl" is executed twice, the first "pass" i'm only getting an empty basecontainer with this code

const BaseContainer* bcNode = op->GetDataInstance();

that's the same if i'm asking for the name's object or anything else but the mesh informations (pointscount, polycount) (asking for the first tag doesn't work neither)

The second time "DisplayControl" is executed, i can get my color but the "DrawPolygonObject" return DRAWRESULT_SKIP.

i've tried to use the "Draw" functions with some draw lines but my code is so slow ^^'

i don't know where to look. I'm pretty sure you'll have some tips.
i hope my description is clear enough :)


On 27/02/2018 at 01:46, xxxxxxxx wrote:


DisplayControl() is not used to draw arbitrary shapes in the viewport. DisplayControl() should be implemented to fill the given ControlDisplayStruct structure. See the documentation of SceneHookData::DisplayControl().

DisplayControl() is not called for different "passes". DisplayControl() is called for each selected object in the scene. The filled ControlDisplayStruct defines how this object should be displayed in the viewport.

To draw arbitrary shapes one must do that in the Draw() function.

If you are still interested in using DisplayControl() here is an example on how it is used:

class VertexColorSceneHook : public SceneHookData  
  INSTANCEOF(VertexColorSceneHook, SceneHookData);  
  // This SceneHook example defines polygon vertex colors for each selected polygon object.  
  // These colors are used to display the objects in the viewport.  
  Bool InitDisplayControl(BaseSceneHook* node, BaseDocument* doc, BaseDraw* bd, const AtomArray* active)  
  if (active && active->GetCount() > 0)  
    return true;  
  return false;  
  Bool DisplayControl(BaseDocument* doc, BaseObject*  op, BaseObject*  chainstart, BaseDraw*  bd, BaseDrawHelp*  bh, ControlDisplayStruct& cds)  
  // handle only polygon objects  
  if (!op || !op->IsInstanceOf(Opolygon))  
    return true;  
  // check if the object is selected or if the cache parent is selected  
  Bool active = op->GetBit(BIT_ACTIVE);  
  if (!active)  
    if (op->GetCacheParent() && op->GetCacheParent()->GetBit(BIT_ACTIVE))  
      active = true;  
  // if the object is not selected, don't handle it  
  if (!active)  
    return true;  
  // create colors for each polygon  
  PolygonObject* poly = static_cast<PolygonObject*>(op);  
  const Int32    polyCount = poly->GetPolygonCount();  
  if (polyCount > 0)  
    const Float stepSize = 1 / Float(polyCount);  
    Float       hue = 0.0;  
    Vector32* _colors = NewMem(Vector32, 4 * polyCount);  
    if (_colors == nullptr)  
      return false;  
    // fill with colors  
    Int32 colorIndex = 0;  
    for (Int32 i = 0; i < polyCount; ++i)  
      // make color  
      const Vector   hsv = Vector(hue, 1.0, 1.0);  
      const Vector32 rgb = (Vector32)HSVToRGB(hsv);  
      hue += stepSize;  
      for (Int32 p = 0; p < 4; ++p)  
        _colors[colorIndex] = (Vector32)bd->ConvertColor((Vector)rgb);  
    // set ControlDisplayStruct  
    cds.vertex_color = _colors;  
    cds.perPolygonVertexColor = true;  
    return true;  
  return true;  
  void FreeDisplayControl()  
  static NodeData* Alloc()  
  return NewObj(VertexColorSceneHook);  

On 27/02/2018 at 02:38, xxxxxxxx wrote:

Thanks for the exemple.

So i don't understand why i see DisplayControl called twice the number of object. (even if they are not selected)

My problem is more about drawing wireframe of objects (selected or not) without slowing down the viewport.

On 27/02/2018 at 06:06, xxxxxxxx wrote:

ok i was not editing the object, only working with primitive :blush::blush::blush::blush:
now it's almost working as expected but it's really slow.
Cinema4D's wireframe mode over shading is not slow like that.

talking about DisplayControl, i didn't understood the purpose of the chainstart parameter.

On 27/02/2018 at 09:20, xxxxxxxx wrote:


I was mistaken, DisplayControl() is called for all objects in the scene (the limitation to active object only applies to above example). If is called for "real" object as well as objects in caches. So for a "Cube" generator it is called for the generator as well as the polygon object in its cache. The chainstart argument references the parent object of such a cached object.

A way to draw a wireframe of an object is to use the corresponding display options of BaseDrawHelp. You find an example in the BaseDraw Manual.

best wishes,

On 27/02/2018 at 23:45, xxxxxxxx wrote:

The information about chainstart was like switching on the light.
I just have to check the chainstart to get my information from either op or chainstart. 
in every case i can call

bd->DrawPolygonObject(bh, op, DRAWOBJECT_FORCELINES| DRAWOBJECT_USE_CUSTOM_COLOR, nullptr, color);

That's why this functions return DRAWRESULT_SKIP when it's called for the "cache". This make sense now.

I know i should use the draw function but this way i don't have to walk through the hierarchy.
thanks a lot for the help ;D