DirectX Media for Animation Programmer's Guide Previous
Previous
TOC
TOC
Index
Index
Next
Next

The Picking Model

A Simple Example , Advanced Topic: Event Data from Picking , The Statics class

Direct Animation provides a simple mechanism by which picking (or hit-detection) on images and geometry results in Direct Animation events that applications can use as they would any other event. Additionally, information such as point of intersection is provided with the resulting event data.

This support is provided through a subclass of ImageBvr called PickableImageBvr, and a subclass of GeometryBvr called PickableGeometryBvr. Because the support for image and geometry is identical, we will only discuss PickableImageBvr.

If an application wants to be informed that the mouse is over a particular ImageBvr, for example, im, it constructs a new instance of PickableImageBvr, for example, pim, providing im to the constructor. It can then extract an event from pim. If pim is used in a model (because it is a subclass of ImageBvr, it can be used as an ImageBvr directly), and the mouse is directly on top of it (without intervening images) then the event fires. It is possible for pim to then appear multiple times in a scene. However, each time the mouse is on top of any of these images, the event occurs. To distinguish multiple uses of an image, and provide separate events based upon separate uses, the application must construct multiple PickableImageBvr's from a common ImageBvr.


A Simple Example

The following simple example imports a GIF image and a piece of text rendered on top of the GIF image. The text changes when the mouse is over the GIF image.


// Grab image, make pickable, grab the event.
ImageBvr         gif  = importImage("foo.gif");
PickableImageBvr pGif = new PickableImageBvr(gif);
DXMEvent          ev   = pGif.getPickEvent();
// Make the string change when we're over the image
StringBvr        str  = until(toBvr("not picked"), 
                              ev, 
                              toBvr("picked"));
// Render the string to an image, and overlay atop the
// pickable GIF.
ImageBvr         textIm = simpleText(str).render();
ImageBvr         result = overlay(textIm, pGif);

Note that the pick event occurs when the mouse is directly over the image (and no other detectable images occlude its visibility.) A mouse button press is not required to fire the event. The effect is analagous to an HTML hotspot. To ensure that the event fires only when the mouse button is pressed, use the event constructed by andEvent(leftButtonDown, ev).


Advanced Topic: Event Data from Picking

The pick event returns data that can be accessed when used within an untilNotify(). The data returned is a pair behavior whose first element is the intersection point of the event, and whose second element is a behavior that tracks the vector from the current mouse position at any time after the pick occurs to the point of intersection. Both of these pieces of data are supplied in the local modeling coordinate system of the image used to construct the PickableImageBvr. This is very important in order to enable images and geometries that retain their interactivity independent of the context into which they are embedded. For example, an interactive image that is replicated three times, each time with a different scale, should retain its interactivity in all three contexts.

The following example is a function that takes an image, returns an image that can be picked and, when picked, follows (or is dragged by) the mouse. When released, the image stays where it was released, waiting for the next pick. Because the event data is returned in the local modeling coordinates of the image itself, the resultant images can be used under any modeling transformation.

Note that this particular example is somewhat academic, as this draggable operation is so common, that a function like makeDraggable will be provided as a utility. However, we do show the below to demonstrate how PickableImageBvr's and their event data may be used.


ImageBvr makeDraggable(ImageBvr im) {
  return (new Draggable(im))._draggableImage;
}
public class Draggable extends Statics implements UntilNotifier {
  public Draggable(ImageBvr im) {
    _pim = new PickableImageBvr(im);
    _pickEv = andEvent(leftButtonDown, _pim.getPickEvent());
    _releaseEv = leftButtonUp;
    
    _picked = false;
    // Wait for the first pick.
    _draggableImage = untilNotify(_pim, _pickEv, this);
  }
  public Behavior notify(Object evData, 
                         Behavior currRunningBvr,
                         double eventTime,
                         BehaviorCtx ctx) {
    ImageBvr currImage = (ImageBvr)currRunningBvr;
    if (_picked == false) {
      // pull apart the pair that comes from andEvent and from the
      // pick event pair, ultimately to get at the local mouse 
      // coord behavior.
      PairBvr    andEventPair  = (PairBvr)evData;
      PairBvr    pickPair   = (PairBvr)(andEventPair.getSecond());
      Vector2Bvr localMouse = (Vector2Bvr)(pickPair.getSecond());
      ImageBvr   draggingIm = 
                   currImage.transform(translate(localMouse));
            
      // set the state to saying that we've been picked.
      _picked = true;
      return untilNotify(draggingIm, _releaseEv, this);
   } else {
      // Releasing.  Freeze the image where it is, and go 
      // back to waiting for a pick event.
      ImageBvr snappedImg = currImage.snapshot();
      // set the state to saying we're waiting to be picked again.
      _picked = false;
      return untilNotify(snappedImg, _pickEv, this);
    }
  }
  DXMEvent          _pickEv, _releaseEv;
  PickableImageBvr _pim;
  boolean          _picked;
  ImageBvr         _draggableImage;
}


The Statics class

The com.ms.dxmedia.Statics class collects all the static methods and constants provided by the other classes in com.ms.dxmedia, and makes them available as static methods on the Statics class. In addition, the com.ms.dxmedia.Model class extends from Statics. The reason for this is that when a programmer is implementing the createModel() method of the class that they extend from Model, all of the static methods in Statics become available without qualification. This means that code can be written as:


ColorBvr col = colorHsl(a, mul(b1, b2), c);
ImageBvr im = solidColorImage(col);

rather than:


ColorBvr col = ColorBvr.colorHsl(a, NumberBvr.mul(b1, b2), c);
ImageBvr im = ImageBvr.solidColorImage(col);

The code is much more readable. If programmers want to write DXMedia for Java code outside of a Model class and not have to qualify their static method invocations, they can do so by having their own class that extends the Statics class. If this is not feasible (because the class already extends another class) then explicit name qualifications will be required.

Top© 1997 Microsoft Corporation. All rights reserved. Legal Notices.