3ds Max uses a callback mechanism to allow objects to be constructed using the mouse. To support mouse construction a plug-in must return an instance of a class derived from CreateMouseCallBack
in its implementation of the function: BaseObject::GetCreateMouseCallBack()
.
In the Widget how-to sample the following call-back class is defined:
class WidgetCreateCallBack
: public CreateMouseCallBack
{
IPoint2 sp0; // First point in screen coordinates
Widget *ob; // Pointer to the object
Point3 p0; // First point in world coordinates
Point3 p1; // Second point in world coordinates.
public:
int proc(ViewExp *vpt, int msg, int point, int flags, IPoint2 m, Matrix3& mat);
};
A plug-in's call-back class must override the CreateMouseCallBack::proc()
method. This method will be called by 3ds Max until the creation procedure is completed (e.g. returns CREATE_STOP
) or abandoned (e.g. returns CREATE_ABORT
). When the creation procedure starts the point
parameter has the value 0. The method is called every time the mouse is moved, giving the plug-in a chance to update itself in the viewport (e.g. through a call to ParamBlockDesc2::InvalidateUI()
).Each time a new point is added manually by the user (e.g. byclicking the mouse) the point
parameter is increased by one. The following is an example implementation used by the Widget how-to sample:
int WidgetCreateCallBack::proc(ViewExp *vpt, int msg, int point,
intflags, IPoint2 m, Matrix3& mat)
{
if (msg == MOUSE_POINT || msg == MOUSE_MOVE)
{
switch(point)
{
case 0:
{
// When point == 0 the message should only be a MOUSE_POINT
DbgAssert(msg == MOUSE_POINT);
// prevent snapping to self
ob->suspendSnap = TRUE;
// store screen coordinates
sp0 = m;
// store world coordinates
p0 = vpt->SnapPoint(m, m, NULL, SNAP_IN_PLANE);
// Update the matrix
mat.SetTrans(p0);
break;
}
case 1:
{
// store screen coordinates
ob->suspendSnap = TRUE;
// store world coordinates
p1 = vpt->SnapPoint(m, m, NULL, SNAP_IN_PLANE);
// Compute the size parameter by scaling using a constant
float speedFactor = 24.0f;
float theSize = (Length(p1 - p0) / speedFactor);
// Set the overall size in parameter block
ob->pblock2->SetValue(widget_size, ob->ip->GetTime(), theSize);
// Invalidate the parameter block's UI
// this triggers the mesh to be invalidated
widget_param_blk.InvalidateUI();
break;
}
case 2:
{
// Indicate creation is complete
return CREATE_STOP;
}
}
}
else
{
if (msg == MOUSE_ABORT)
{
// Indicate creation is abandoned
return CREATE_ABORT;
}
}
return TRUE;
}
The most common messages that your proc
method will handle: MOUSE_MOVE
, MOUSE_POINT
, and MOUSE_ABORT
. A MOUSE_POINT
message is generated when the user first starts the drawing process and every time the user releases the left mouse button, until the mouse drawing process is completed (i.e. your function returns TRUE
) or the process is aborted (i.e. the user presses escape). A list of more messages can be found here.