Interactors

When the user clicks say the rotate tool, an interactor is created to handle user's input and transform the selected objects accordingly.

Creating Interactors

The default interactor is typically 'inc/real/intact/r3iasel.h' - the selection interactor, that allows the user to select objects and handles.

To create a new interactor, call R3LAYM_NEWINTERACTOR method with the desired interactor clid. For example, to create the sphere creation interactor, call:


    #include <real/r3layer/r3layer.h>
    #include <real/intact/r3iasph2.h>
    
    interactor = R3DoA(layer, R3LAYM_NEWINTERACTOR, (void*)R3CLID_IASPHERE2);

The above is equivalent to clicking the sphere tool. This creates a new interactor and makes it the current interactor. View window maps mouse events to interactor methods and passes them to the current interactor. The interactor can then manipulate the selected objects, create new objects etc.

In addition to tool buttons, interactors can also get created when the user drags an object handle. For example, when the user drags a translation handle, the move interactor is created and its attributes are set to such that the object gets translated on the dragged axis only.

Implementing Interactors

Interactors don't understand anything about mouse inputs nor any other operating system level events. They define an device independent interaface through which they can be controlled. The most important methods are:

For example, the NURBS curve creation tool handles the R3IAM_ENTER method by inserting new control point into the curve to be created and R3IAM_MOVE moves the latest curve point to a new position.

Interaction Layer

Some interactors manipulate directly objects in the geometry layer of the actual project. Some interactors copy or create objects into so called interaction layer. The idea is that the real time renderer can render objects in the interaction layer automatically. If the user accepts the tool, then the inteactor can copy the created / modified objects back into the actual layer. If the user cancels the tool, just delete the contents of the interaction layer.

Here is how the sphere creation tool uses the interaction layer.

When the user activates the sphere tool (in other words, creates a sphere interactor object) and clicks the mouse in the view window, the sphere interactor gets its first R3IAM_ENTER method.


    static void *r3iam_enter(R3CLASS *cl, R3OBJ *obj, R3VECTOR *pos)
    {
        R3IDATA *self = R3CL_IADDR(cl, obj);
        int count;
        R3VECTOR * p;
        R3OBJ *ilayer;

        /* let the super class handle the event first */
        if(!R3DoSuperA3(cl, obj, R3IAM_ENTER, NULL, NULL, pos))
            return NULL;

        R3GetAttrs(obj,
                   R3IAA_InteractiveLayer, &ilayer,
                   R3IA2PA_Count, &count,
                   R3IA2PA_Points, &p,
                   R3TAG_END);

        if(count == 1) {    /* first point */

            /* create a sphere and insert it into the interaction layer */
            self->sphere = R3New(R3CLID_SDKSPHERE,
                                 SPHA_Center, &self->center,
                                 SPHA_Radius, &self->radius,
                                 R3TAG_END);

            if (self->sphere) {
                R3DoA(ilayer, R3OLAYM_LOCKEXCLUSIVE, NULL);
                R3DoA(ilayer, R3PLAYM_DELETEROOT, NULL);
                R3DoA(ilayer, R3PLAYM_RAWINSERT, self->sphere);
                R3DoA(self->sphere, R3PRIMM_NORMALIZESPACE, NULL);
                R3DoA(ilayer, R3OLAYM_SELECTOBJ, self->sphere);
                R3DoA(ilayer, R3OLAYM_RELEASE, NULL);
            }

            R3Do(obj, R3MM_CHANGED,
                 R3IAM_ENTER, NULL,
                 R3TAG_END);
        }
        return((void *)TRUE);
    }

Then every R3IAM_MOVE event should measure the distance between the current 3d point and the first point (the center point) and set the radius to the sphere.


    static void *r3iam_move(R3CLASS *cl, R3CLASS *obj, R3VECTOR *pos)
    {
        R3IDATA *self = R3CL_IADDR(cl, obj);
        int count;
        R3VECTOR *p;
        R3OBJ *ilayer;
    
        R3DoSuperA3(cl, obj, R3IAM_MOVE, 0, 0, pos);

        R3GetAttrs(obj,
                   R3IAA_InteractiveLayer, &ilayer,
                   R3IA2PA_Count, &count,
                   R3IA2PA_Points, &p,
                   R3TAG_END);

        /* compute new radius */
        self->radius = VDist(p, p+1);

        /* and set it to the sphere */
        R3DoA(ilayer, R3OLAYM_LOCKEXCLUSIVE, NULL);
        R3Do(ilayer, R3OLAYM_SETONSELECTED,
             SPHA_Radius, &self->radius,
              R3TAG_END);
        R3DoA(ilayer, R3OLAYM_RELEASE, NULL);
        R3Do(obj, R3MM_CHANGED,
             SPHIA_Radius, NULL,
             R3TAG_END);
        return (void *)TRUE;
    }

When the user accepts the tool (in other words, when the user thinks the sphere is ready, the interactor gets R3IAM_ACCEPT method. This method then creates the sphere into the actual layer and deletes the sphere from the interaction layer. Of course, it could as well move the sphere from interaction layer into the actual layer.


    static void *r3iam_accept(R3CLASS *cl, R3CLASS *obj)
    {
        R3IDATA *self = R3CL_IADDR(cl, obj);
        R3OBJ *layer, *ilayer, *newobj = NULL;

        R3GetAttrs(obj,
                   R3IAA_Layer, &layer,
                   R3IAA_InteractiveLayer, &ilayer,
                   R3TAG_END);

        newobj = R3New(R3CLID_SDKSPHERE,
                       SPHA_Center, &self->center,
                       SPHA_Radius, &self->radius,
                       R3TAG_END);
        if (newobj) {
            R3DoA(layer, R3OLAYM_LOCKEXCLUSIVE, NULL);
            R3DoA(layer, R3OLAYM_INSERT, newobj);
            R3DoA(newobj, R3PRIMM_NORMALIZESPACE, NULL);
            R3DoA(layer, R3OLAYM_RELEASE, NULL);
        }   

        R3DoA(ilayer, R3OLAYM_LOCKEXCLUSIVE, NULL);
        R3DoA(ilayer, R3PLAYM_DELETEROOT, NULL);
        R3DoA(ilayer, R3OLAYM_RELEASE, NULL);
        return R3DoSuperA3(cl, obj, R3IAM_ACCEPT, 0, 0, NULL);
    }

R3IAM_CANCEL method would just delete the sphere from the interaction layer.

Interfaces to Interactors