Tool plugin for highlight and selection



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 25/08/2006 at 15:03, xxxxxxxx wrote:

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

    ---------
    This is my first Tool plugin, so bear with my naivete.

    I want to create a Tool plugin for object selections in the editor. In this case, I want to select not the root object, but one of my deformer objects childed to it. And to make it more complex, when dealing with Polygon objects as root, I want to highlight the 'bodypart' under the cursor to then allow selection of the correct deformer object.

    So, basically, I need a way to somehow highlight the polygons of a 'bodypart' (section of the Polygon object defined by Polygon Selection tags) when the cursor is over it and then select the corresponding deformer object that deforms that bodypart when the user clicks over it. There might also be a need for a right-click context menu to show a list of possible selections under the cursor so as to handle more than one possible choice.

    Nothing that complicated. :)

    Thanks,



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 25/08/2006 at 16:50, xxxxxxxx wrote:

    Okay, this is what I'm trying to use to do the highlighting. Doesn't seem to work and no clue as to what I'm doing or if this is the right approach:

    // ToolData.GetCursorInfo  
    //*---------------------------------------------------------------------------*  
    Bool IPPTool::GetCursorInfo(BaseDocument* doc, BaseContainer& data, BaseDraw* bd, Real x, Real y, BaseContainer& bc)  
    //*---------------------------------------------------------------------------*  
    {  
         bc.SetString(RESULT_BUBBLEHELP, "interPoser Pro Tool");  
         bc.SetLong(RESULT_CURSOR, MOUSE_POINT_HAND);  
      
         atomArray->Flush();  
         GetAllIPPObjects(doc->GetFirstObject());  
         if (!atomArray->GetCount())     return TRUE;  
         AutoAlloc<ViewportSelect>     viewportSelect;  
         if (!viewportSelect)          return TRUE;  
         LONG               left, top, right, bottom, width, height;  
         bd->GetFrame(&left;, &top;, &right;, &bottom;);  
         width =                              right - left + 1;  
         height =                         bottom - top + 1;  
         if (!viewportSelect->Init(width, height, bd, atomArray, Mobject, FALSE, VIEWPORT_USE_HN|VIEWPORT_USE_DEFORMERS))     return TRUE;  
         PolygonObject*     op;  
         BaseTag*          ptag =     NULL;  
         BaseSelect*          bs =     NULL;  
         LONG               nr, i;  
         ViewportPixel*     vpp =          viewportSelect->GetPixelInfoPolygon((LONG)x, (LONG)y);  
         // Traverse ViewportPixel list  
         for (vpp; vpp; vpp = vpp->next)  
         {  
              op =          ToPoly(vpp->op);  
              if (!op)     continue;  
              i =               vpp->i;  
              // Find the bodypart containing this polygon  
              for (nr = 0; ptag = op->GetTag(Tpolygonselection, nr); nr++)  
              {  
                   bs =                         static_cast<SelectionTag*>(ptag)->GetBaseSelect();  
                   if (bs->IsSelected(i))     break;  
              }  
              if (ptag)     break;  
         }  
         // This is the bodypart - highlight it  
         if (ptag && bs)  
         {  
              Matrix               mg =     op->GetMg();  
              CPolygon*          polys =     op->GetPolygon();  
              Vector*               verts =     op->GetPoint();  
              CPolygon*          pp;  
              Vector               vv[4];  
              LONG               seg, a, b;  
              BaseContainer     wbc =     GetWorldContainer();  
              Vector               color[4];  
              color[0] =          wbc.GetVector(WPREF_ACTIVEPOLYGON_COL);  
              color[1] =          color[0];  
              color[2] =          color[0];  
              color[3] =          color[0];  
              for (seg = 0; bs->GetRange(seg,&a;,&b;); seg++)  
              {  
                   for (i=a; i<=b; ++i)  
                   {  
                        pp =          polys+i;  
                        vv[0] =          verts[pp->a]*mg;  
                        vv[1] =          verts[pp->b]*mg;  
                        vv[2] =          verts[pp->c]*mg;  
                        vv[3] =          verts[pp->d]*mg;  
                        bd->Polygon3D(vv, color, TRUE);  
                   }  
              }  
         }  
         return TRUE;  
    }  
    

    Thanks,



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 26/08/2006 at 09:51, xxxxxxxx wrote:

    Okay, this is sort of starting to work. Now I do this:

    // ToolData.GetCursorInfo  
    //*---------------------------------------------------------------------------*  
    Bool IPPTool::GetCursorInfo(BaseDocument* doc, BaseContainer& data, BaseDraw* bd, Real x, Real y, BaseContainer& bc)  
    //*---------------------------------------------------------------------------*  
    {  
         bc.SetString(RESULT_BUBBLEHELP, "interPoser Pro Tool");  
         bc.SetLong(RESULT_CURSOR, MOUSE_POINT_HAND);  
      
         mouseX =     x;  
         mouseY =     y;  
         if (x > -1.0)     SpecialEventAdd(EVMSG_UPDATEHIGHLIGHT);  
         return TRUE;  
    }  
    // ToolData.GetAllIPPObjects -     recursive  
    //*---------------------------------------------------------------------------*  
    void IPPTool::GetAllIPPObjects(BaseObject* obj)  
    //*---------------------------------------------------------------------------*  
    {  
         for (obj; obj; obj = obj->GetNext())  
         {  
              // Only append IPP Polygon objects  
              if (obj->IsInstanceOf(Opolygon) && (obj->GetTag(ID_IPPFIGURETAG) || obj->GetTag(ID_IPPOBJECTTAG)))  
                   atomArray->Append(obj);  
              if (obj->GetDown())                              GetAllIPPObjects(obj->GetDown());  
         }  
    }  
      
    // ToolData.Draw  
    //*---------------------------------------------------------------------------*  
    LONG IPPTool::Draw(BaseDocument* doc, BaseContainer& data, BaseDraw* bd, BaseDrawHelp* bh, BaseThread* bt, LONG flags)  
    //*---------------------------------------------------------------------------*  
    {  
         if (!(flags & DRAWFLAGS_HIGHLIGHT))     return DRAW_AXIS;  
         if (mouseX < 0.0)                         return DRAW_AXIS;  
         atomArray->Flush();  
         GetAllIPPObjects(doc->GetFirstObject());  
         if (!atomArray->GetCount())     return TRUE;  
         AutoAlloc<ViewportSelect>     viewportSelect;  
         if (!viewportSelect)          return TRUE;  
         LONG               left, top, right, bottom;  
         bd->GetFrame(&left;, &top;, &right;, &bottom;);  
         left =                              right - left + 1;  
         top =                              bottom - top + 1;  
         if (!viewportSelect->Init(left, top, bd, atomArray, Mpolygons, FALSE, VIEWPORT_USE_HN|VIEWPORT_USE_DEFORMERS))     return TRUE;  
         PolygonObject*     op;  
         BaseTag*          ptag =     NULL;  
         BaseSelect*          bs =     NULL;  
         LONG               nr, i;  
         ViewportPixel*     vpp =          viewportSelect->GetPixelInfoPolygon((LONG)mouseX, (LONG)mouseY);  
         // Traverse ViewportPixel list  
         for (vpp; vpp; vpp = vpp->next)  
         {  
              op =          ToPoly(vpp->op);  
              if (!op)     continue;  
              i =               vpp->i;  
              // Find the bodypart containing this polygon  
              for (nr = 0; ptag = op->GetTag(Tpolygonselection, nr); nr++)  
              {  
                   if (ptag->GetName().FindFirst(".mtl", &top;))     continue;  
                   bs =                         static_cast<SelectionTag*>(ptag)->GetBaseSelect();  
                   if (bs->IsSelected(i))     break;  
              }  
              if (ptag)     break;  
         }  
         // This is the bodypart - highlight it  
         if (ptag && bs && (op = ToPoly(op->GetCache(NULL))))  
         {  
              GePrint(ptag->GetName());  
              Matrix               mg =     op->GetMg();  
              CPolygon*          polys =     op->GetPolygon();  
              Vector*               verts =     op->GetPoint();  
              CPolygon*          pp;  
              Vector               vv[4];  
              LONG               seg, a, b;  
              BaseContainer     wbc =     GetWorldContainer();  
              Vector               color[4];  
              color[0] =          wbc.GetVector(WPREF_ACTIVEPOLYGON_COL);  
              color[1] =          color[0];  
              color[2] =          color[0];  
              color[3] =          color[0];  
              for (seg = 0; bs->GetRange(seg,&a;,&b;); seg++)  
              {  
                   for (i=a; i<=b; ++i)  
                   {  
                        pp =          polys+i;  
                        vv[0] =          verts[pp->a]*mg;  
                        vv[1] =          verts[pp->b]*mg;  
                        vv[2] =          verts[pp->c]*mg;  
                        vv[3] =          verts[pp->d]*mg;  
                        bd->Polygon3D(vv, color, TRUE);  
                   }  
              }  
         }  
         //return DRAW_AXIS;  
         return DRAW_AXIS|DRAW_HIGHLIGHTS;  
    }  
    

    There are two problems here. One is that the drawing always occurs behind the object - how does one draw on top of everything? A DRAW_ABSOLUTELY_POSITIVELY_LAST flag would be nice. ;) Two is that it draws the undeformed object polygons. As you can see, op->GetCache() doesn't help (actually, it returns NULL, so nothing is drawn).

    Thanks,



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 26/08/2006 at 10:38, xxxxxxxx wrote:

    Hi,

    that look's pretty okay. The problem in the first post was probably that you initialized the VPS class with Mobjects.

    Q1:
    bd->LineZOffset()   
    :-)

    Q2:
    You have to get the deform cache with op->GetDeformCache() that should not be NULL. If you have a Object inside a HN generator ( deformed or not ), things get very very messy. Then you have to retrieve the HN Cache for just the single object you want to highlight. Fortunately there are some helper functions for this in lib_sds.h

    In Addition to that here is some code of mine which might be helpfull

      
    /*  
    get objects of interest according to the edit mode ( Isoline SDS and/or Deformed )  
    Provided that the corresponding edit mode options are set...  
    opEdit returns either the DeformCache of op, or an Object from the Cache of the SDSObject if any is avaiable  
    opSDS returns the parent SDS object of object op, if such is avaiable.   
    .. if edit mode stuff is disabled, this function should return the original object in opEdit  
    opEdit should only be NULL if somehow the deformed object mismatches  
    */  
    void GetEditStateStuff( LONG editstate, LONG displayfilter, PolygonObject* op, SDSObject* &opSDS;, PolygonObject* &opEdit; );  
    inline void GetEditStateStuff( BaseDraw* bd, PolygonObject* op, SDSObject* &opSDS;, PolygonObject* &opEdit; ) {   
    GetEditStateStuff( bd->GetEditState(), bd->GetDisplayFilter(), op, opSDS, opEdit );  
    }  
      
      
    void GetEditStateStuff( LONG editstate, LONG displayfilter, PolygonObject* op, SDSObject* &opSDS;, PolygonObject* &opEdit; )  
    {  
    opEdit = NULL;  
    opSDS = NULL;  
    if( (editstate&DISPLAY;_EDITSTATE_SDS) && (displayfilter&DISPLAYFILTER;_SDS) )  
    {  
        opEdit = (PolygonObject* )op->GetEditObject((BaseObject** )&opSDS;,DISPLAY_EDITSTATE_SDS);  
        if(opEdit && opSDS && opSDS->GetDivision(op)<=0 ) { opSDS=NULL; opEdit=NULL; }  
        if(opEdit && (opEdit->GetPointCount()<=0 || opEdit->GetPolygonCount()<=0) ) { opSDS=NULL; opEdit=NULL; }  
    }  
         if( (editstate&DISPLAY;_EDITSTATE_DEFORM) && opEdit==NULL && op->GetDeformCache())  
         {  
              opEdit=ToPoly( op->GetDeformCache() );            
         }  
      
    if( op && op->GetDeformCache() && opEdit )  
    {  
        PolygonObject* def = ToPoly( op->GetDeformCache() );  
        if( !(def->GetPointCount()==op->GetPointCount() && def->GetPolygonCount()==op->GetPolygonCount())) { opEdit=NULL; }  
    }  
    else if( !opEdit )  
    {  
        opEdit = op;  
    }  
    }  
      
    // here is how i draw subdivided edges  
    void DrawMarkedSdsEdges( BaseSelect* sel, PolygonObject* op, PolygonObject* opSubdiv, SDSObject* opSDS, BaseDraw* bd )  
    {  
    if( sel->GetCount()<=0 ) return;  
      
    const CPolygon *polyEd=opSubdiv->GetPolygon();  
    const Vector *vertEd=opSubdiv->GetPoint();  
      
    Bool ngonsubdiv;  
    LONG *polymap,maskcnt;  
    SDSSubdivisionMask* sdsmask = ((SDSObject* )opSDS)->GetSubdivisionMask(op,maskcnt,polymap,ngonsubdiv);  
    if( sdsmask!=NULL )  
    {  
        BaseSelectIterator seliter( sel );  
        while( seliter )  
        {  
          LONG edid = seliter.Get();  
          LONG pid0 = edid>>2;  
            
          GeAssert( sdsmask[polymap[pid0]].p==pid0 );  
          for( LONG sdspid=polymap[pid0]; sdspid<maskcnt; ++sdspid )  
          {  
            SDSSubdivisionMask* s = sdsmask + sdspid;  
            if( s->p!=pid0 ) break;  
            LONG a,b;  
            if( s->e1==edid )   
            {  
              SideAB( 0, polyEd + sdspid, a, b );  
              bd->LineNew( vertEd[a], vertEd **, 0 );  
            }  
            if( s->e2==edid )  
            {  
              SideAB( 1, polyEd + sdspid, a, b );  
              bd->LineNew( vertEd[a], vertEd **, 0 );  
            }  
            if( s->e3==edid )  
            {  
              SideAB( 2, polyEd + sdspid, a, b );  
              bd->LineNew( vertEd[a], vertEd **, 0 );  
            }  
            if( s->e4==edid )  
            {  
              SideAB( 3, polyEd + sdspid, a, b );  
              bd->LineNew( vertEd[a], vertEd **, 0 );  
            }  
          }  
          ++seliter;  
        }  
    }  
    }  
      
    // and polys  
    void DrawSdsPolygonSelection( BaseSelect* sel, PolygonObject* op, PolygonObject* opSubdiv, SDSObject* opSDS, BaseDraw* bd, const Vector &col; )  
    {  
    if( sel->GetCount()<=0 ) return;  
      
    const CPolygon *polyEd=opSubdiv->GetPolygon();  
    const Vector *vertEd=opSubdiv->GetPoint();  
    Vector f[] = { col,col,col,col };  
      
    Bool ngonsubdiv;  
    LONG *polymap,maskcnt;  
    SDSSubdivisionMask* sdsmask = ((SDSObject* )opSDS)->GetSubdivisionMask(op,maskcnt,polymap,ngonsubdiv);  
    if( sdsmask!=NULL )  
    {  
        BaseSelectIterator seliter( sel );  
        while( seliter )  
        {  
          const LONG pid = seliter.Get();  
          for( LONG sdspid=polymap[pid]; sdspid<maskcnt; ++sdspid )  
          {  
            SDSSubdivisionMask* s = sdsmask + sdspid;  
            if( s->p!=pid ) break;  
      
            const CPolygon* pp = polyEd + sdspid;  
            Vector p[] = { vertEd[pp->a], vertEd[pp->b], vertEd[pp->c], vertEd[pp->d] };  
            bd->PolygonNew( p, f, pp->c!=pp->d );          
          }  
          ++seliter;  
        }  
    }  
    }  
      
    

    okay.. that might be a bit messy but i hope it helps.

    Just on a personal note. I think it's a bad idea to initialize the viewport select class on every draw. On my system it an easily take serveral 100 ms up to a sec, according to the number of polys.

    So what you usually do is check if something of interest changed, and only then free and reallocate the viewport select. Best place to do this probably Draw() or GetCursorInfo().. Be Warned that the scene can change between calls to GetCursorInfo() and Draw().
    Afik this is also the way all the tools in Cinema work.



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 26/08/2006 at 11:39, xxxxxxxx wrote:

    Is it safe to delete the ViewportPixel array yourself? If I preallocate the ViewportSelect class (in InitTool()) and use normally, memory quickly runs out (as it leaks for each new ViewportPixel array).

    Thanks for the pointers and code! Time for work and testing.



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 26/08/2006 at 19:50, xxxxxxxx wrote:

    Michael, I've found a better way. :) Instead of using ViewportSelect (which isn't available before R9.0 anyway), there is SelectionListCreate(). This is much better as it will only get a list of objects 'under the cursor' - whereas my original method created an AtomArray of all my objects in the scene.

    Also, I've followed your advice and use op->GetDeformCache() for highlighting to much better effect.

    Now I have highlighting and selection of the underlying deformer object as well as a way to traverse the 'layers' of objects under the cursor (using the Up/Down arrows). The next step after some tweaking and testing is doing PSR with this tool.

    Thanks again!



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 27/08/2006 at 00:47, xxxxxxxx wrote:

    about that memory problem:   i've never noticed a leak. But i also never initialized the class twice. I've always freed it and allocated an new instance before initialization. That seems to work fine.


Log in to reply