home *** CD-ROM | disk | FTP | other *** search
/ ftp.hitl.washington.edu / ftp.hitl.washington.edu.tar / ftp.hitl.washington.edu / pub / people / peter / ER / PivotTracker.cxx < prev    next >
C/C++ Source or Header  |  1998-07-07  |  15KB  |  484 lines

  1. /*
  2.   PivotTracker.cxx
  3. */
  4.  
  5. #include "PivotTracker.h"
  6.  
  7. #include "v3dUniverse.h"
  8.  
  9. #include <iostream.h>
  10.  
  11. const v3dColor PivotTracker::SELECT_COLOR (0, 255, 0);
  12. const v3dColor PivotTracker::PICK_COLOR (0, 0, 255);
  13. const v3dColor PivotTracker::PIVOT_COLOR (255, 0, 0);
  14.  
  15. PivotTracker::PivotTracker()
  16. {
  17.     // Create the events that will be fired when objects are selected
  18.     // and unselected.
  19.     object_select_event_ = new PivotObjectSelectionEvent();
  20.     RegisterEvent(object_select_event_);
  21.     object_unselect_event_ = new PivotObjectUnselectionEvent();
  22.     RegisterEvent(object_unselect_event_);
  23.  
  24.     // Create the events that will be fired when objects are picked
  25.     // and unpicked.
  26.     object_pick_event_ = new PivotObjectPickEvent();
  27.     RegisterEvent(object_pick_event_);
  28.     object_unpick_event_ = new PivotObjectUnpickEvent();
  29.     RegisterEvent(object_unpick_event_);
  30.  
  31.     // Create the events that will be fired when object pivot points are
  32.     // set and unset.
  33.     object_set_pivot_event_ = new PivotObjectSetPivotEvent();
  34.     RegisterEvent(object_set_pivot_event_);
  35.     object_unset_pivot_event_ = new PivotObjectUnsetPivotEvent();
  36.     RegisterEvent(object_unset_pivot_event_);
  37. }
  38.  
  39. PivotTracker::~PivotTracker()
  40. {
  41.     // Erase the array of objects.
  42.     while (objects_.size()) {
  43.         delete objects_.back();
  44.         objects_.pop_back();
  45.     }
  46.  
  47.     // Erase the array of action points.
  48.     while (action_points_.size()) {
  49.         action_points_.pop_back();
  50.     }
  51. }
  52.  
  53. ////////////////////////////////////////////////////////////////////////////////
  54. // Action point management
  55. ////////////////////////////////////////////////////////////////////////////////
  56. // Registers an action point used to send selection events for the
  57. // tracker's objects.
  58. // If the action point is already registered with the tracker, then it
  59. // isn't re-registered and false is returned.
  60. // Otherwise, selection and unselection callbacks are registered for every
  61. // object watched by the tracker.
  62. bool
  63. PivotTracker::RegisterActionPoint(v3dActionPoint* action_point)
  64. {
  65.     // First check the list of action points to make sure this AP
  66.     // isn't already registered.
  67.     ActionPointArray::iterator finder = find(action_points_.begin(),
  68.         action_points_.end(), action_point);
  69.     if (finder != action_points_.end())
  70.         return false;
  71.  
  72.     // Add the new action point to the array of action points.
  73.     action_points_.push_back(action_point);
  74.  
  75.     // Register selection and unselection callbacks with this action
  76.     // point for every object watched by the tracker.
  77.     for (PivotInfoArray::iterator it = objects_.begin();
  78.             it != objects_.end(); ++it) {
  79.         action_point->RegisterEventReceiver((*it)->object, this,
  80.             v3dActionPoint::AP_SELECT, &object_select_CB,
  81.             (v3dPointer)action_point);
  82.         action_point->RegisterEventReceiver((*it)->object, this,
  83.             v3dActionPoint::AP_UNSELECT, &object_unselect_CB,
  84.             (v3dPointer)action_point);
  85.     }
  86.  
  87.     return true;
  88. }
  89.  
  90. // Unregisters an action point used to send selection events for the
  91. // tracker's objects.
  92. // If the action point isn't registered with the tracker, then false
  93. // is returned.
  94. // Otherwise, selection and unselection callbacks are unregistered for every
  95. // object watched by the tracker.
  96. bool
  97. PivotTracker::UnregisterActionPoint(v3dActionPoint* action_point)
  98. {
  99.     // First check the list of action points to make sure this AP
  100.     // is already registered.
  101.     ActionPointArray::iterator finder = find(action_points_.begin(),
  102.         action_points_.end(), action_point);
  103.     if (finder == action_points_.end())
  104.         return false;
  105.  
  106.     // Remove the action point from the array of action points.
  107.     action_points_.erase(finder);
  108.  
  109.     // Unregister selection and unselection callbacks from this action
  110.     // point for every object watched by the tracker.
  111.     for (PivotInfoArray::iterator it = objects_.begin();
  112.             it != objects_.end(); ++it) {
  113.         action_point->UnregisterEventReceiver((*it)->object, this,
  114.             v3dActionPoint::AP_SELECT, &object_select_CB);
  115.         action_point->UnregisterEventReceiver((*it)->object, this,
  116.             v3dActionPoint::AP_UNSELECT, &object_unselect_CB);
  117.     }
  118.  
  119.     return true;
  120. }
  121.  
  122. ////////////////////////////////////////////////////////////////////////////////
  123. // Object registration/unregistration
  124. ////////////////////////////////////////////////////////////////////////////////
  125. // Registers an object to be watched.
  126. bool
  127. PivotTracker::RegisterObject(PivotObject* object)
  128. {
  129.     // First, make sure that the object isn't already registered.
  130.     PivotInfoArray::iterator finder = get_info_by_object(object);
  131.     if (finder != objects_.end())
  132.         return false;
  133.  
  134.     // Add the new object to the array of objects.
  135.     PivotObjectInfo *object_info = new PivotObjectInfo;
  136.     object_info->object = object;
  137.     object_info->bounding_box = 0;
  138.     object_info->is_selected = false;
  139.     object_info->is_picked = false;
  140.     object_info->is_pickable = true;
  141.     object_info->pick_AP = 0;
  142.     objects_.push_back(object_info);
  143.  
  144.     // Register selection and unselection callbacks with every action
  145.     // point for this object.
  146.     for (ActionPointArray::iterator it = action_points_.begin();
  147.             it != action_points_.end(); ++it) {
  148.         (*it)->RegisterEventReceiver(object, this,
  149.             v3dActionPoint::AP_SELECT, &object_select_CB,
  150.             (v3dPointer)(*it));
  151.         (*it)->RegisterEventReceiver(object, this,
  152.             v3dActionPoint::AP_UNSELECT, &object_unselect_CB,
  153.             (v3dPointer)(*it));
  154.     }
  155.  
  156.     return true;
  157. }
  158.  
  159. // Unregisters an object from watched status.
  160. bool
  161. PivotTracker::UnregisterObject(PivotObject* object)
  162. {
  163.     // First, find the object in the object array.
  164.     PivotInfoArray::iterator finder = get_info_by_object(object);
  165.     if (finder == objects_.end())
  166.         return false;
  167.  
  168.     // Remove the object from the array of objects.
  169.     delete (*finder);
  170.     objects_.erase(finder);
  171.  
  172.     // Unregister selection and unselection callbacks from every action
  173.     // point for this object.
  174.     for (ActionPointArray::iterator it = action_points_.begin();
  175.             it != action_points_.end(); ++it) {
  176.         (*it)->UnregisterEventReceiver(object, this,
  177.             v3dActionPoint::AP_SELECT, &object_select_CB);
  178.         (*it)->UnregisterEventReceiver(object, this,
  179.             v3dActionPoint::AP_UNSELECT, &object_unselect_CB);
  180.     }
  181.  
  182.     return true;
  183. }
  184.  
  185. ////////////////////////////////////////////////////////////////////////////////
  186. // Object selection
  187. ////////////////////////////////////////////////////////////////////////////////
  188. // Static callback for object selection.
  189. void
  190. PivotTracker::object_select_CB(const v3dEventMessage* message)
  191. {
  192.     v3dCollisionCallData *call_data
  193.             = (v3dCollisionCallData *)message->GetCallData();
  194.     if (!((call_data->event_ID) & v3dActionPoint::AP_SELECT))
  195.         return;
  196.     PivotObject *collide_object = (PivotObject*)call_data->second_object;
  197.     v3dActionPoint *action_point
  198.             = (v3dActionPoint *)message->GetClientData();
  199.     PivotTracker *tracker
  200.             = (PivotTracker *)message->GetEventReceiver();
  201.  
  202.     tracker->object_select(action_point, collide_object);
  203. }
  204.  
  205. // Local callback for object selection.
  206. void
  207. PivotTracker::object_select(v3dActionPoint* action_point,
  208.     PivotObject* object)
  209. {
  210.     PivotInfoArray::iterator finder = get_info_by_object(object);
  211.     if (finder == objects_.end())
  212.         return;
  213.  
  214.     // Before going through selection startup, make sure this object isn't
  215.     // already selected by a different AP.
  216.     if ((*finder)->is_selected)
  217.         return;
  218.  
  219.     // Add a bounding box to the object.
  220.     (*finder)->bounding_box = object->CreateBoundingBox(
  221.                         0.05 * object->GetRadius());
  222.     (*finder)->bounding_box->SetColor(SELECT_COLOR);
  223.  
  224.     (*finder)->is_selected = true;
  225.  
  226.     // Fire the object selection event.
  227.     object_select_event_->InvokeHandlers((v3dPointer)object);
  228. }
  229.  
  230. ////////////////////////////////////////////////////////////////////////////////
  231. // Object unselection
  232. ////////////////////////////////////////////////////////////////////////////////
  233. // Static callback for object unselection.
  234. void
  235. PivotTracker::object_unselect_CB(const v3dEventMessage* message)
  236. {
  237.     v3dCollisionCallData *call_data
  238.             = (v3dCollisionCallData *)message->GetCallData();
  239.     if (!((call_data->event_ID) & v3dActionPoint::AP_UNSELECT))
  240.         return;
  241.     PivotObject *collide_object = (PivotObject*)call_data->second_object;
  242.     v3dActionPoint *action_point
  243.             = (v3dActionPoint *)message->GetClientData();
  244.     PivotTracker *tracker
  245.             = (PivotTracker *)message->GetEventReceiver();
  246.  
  247.     tracker->object_unselect(action_point, collide_object);
  248. }
  249.  
  250.  
  251. // Local callback for object unselection.
  252. void
  253. PivotTracker::object_unselect(v3dActionPoint* action_point,
  254.     PivotObject* object)
  255. {
  256.     PivotInfoArray::iterator finder = get_info_by_object(object);
  257.     if (finder == objects_.end())
  258.         return;
  259.  
  260.     // Make sure the object's not picked.
  261.     if ((*finder)->is_picked)
  262.         return;
  263.  
  264.     // Make sure the object isn't currently selected by another action
  265.     // point before we dismantle the selection info.
  266.     ActionPointArray::iterator it = action_points_.begin();
  267.     for (; it != action_points_.end(); ++it) {
  268.         if ((*it != action_point) &&
  269.                 object->Intersects((*it)->GetGeometry()))
  270.             break;
  271.     }
  272.     if (it != action_points_.end())
  273.         return;
  274.  
  275.     // Remove the bounding box.
  276.     delete (*finder)->bounding_box;
  277.     (*finder)->bounding_box = 0;
  278.  
  279.     (*finder)->is_selected = false;
  280.  
  281.     // Fire the object unselection event.
  282.     object_unselect_event_->InvokeHandlers((v3dPointer)object);
  283. }
  284.  
  285. ////////////////////////////////////////////////////////////////////////////////
  286. // Object picking
  287. ////////////////////////////////////////////////////////////////////////////////
  288.  
  289. // Picks all objects currently selected by the action point, and unpicks all
  290. // objects currently picked by the action point.
  291. void
  292. PivotTracker::TogglePick(v3dActionPoint* action_point)
  293. {
  294.     for (PivotInfoArray::iterator it = objects_.begin();
  295.             it != objects_.end(); ++it) {
  296.         if ((*it)->is_picked) {
  297.             if ((*it)->pick_AP == action_point) {
  298.                 // The object is picked by this action point,
  299.                 // so unpick it.
  300.                 (*it)->is_picked = false;
  301.                 (*it)->is_pickable = true;
  302.                 (*it)->pick_AP = 0;
  303.                 if ((*it)->bounding_box)
  304.                     (*it)->bounding_box->SetColor(
  305.                                 SELECT_COLOR);
  306.  
  307.                 // Remove the pivot info from the array of
  308.                 // picked objects.
  309.                 PivotInfoArray::iterator finder =
  310.                     get_pick_info_by_object((*it)->object);
  311.                 if (finder != picked_objects_.end())
  312.                     picked_objects_.erase(finder);
  313.  
  314.                 // If there are no more picked objects, then
  315.                 // unregister the pick update callback.
  316.                 if (picked_objects_.empty())
  317.                     v3dEventReceiver::UnregisterEventHandler(
  318.                         v3dSystem::GetCurrentUniverse(),
  319.                         v3dUniverse::UNIVERSE_SIMULATION_LOOP,
  320.                         &update_picked_objects_CB);
  321.  
  322.                 // Fire the object unpick event.
  323.                 object_unpick_event_->InvokeHandlers(
  324.                     (v3dPointer)(*it)->object);
  325.             }
  326.         } else {
  327.             // The object isn't picked.
  328.             if ((*it)->is_pickable &&
  329.                     (*it)->object->Intersects(
  330.                         action_point->GetGeometry())) {
  331.                 // Pick the object.
  332.                 (*it)->is_picked = true;
  333.                 (*it)->is_pickable = false;
  334.                 (*it)->pick_AP = action_point;
  335.                 
  336.                 (*it)->AP_offset = action_point->GetGeometry()->                    GetCoordSystem().AbsolutePosToLocal(
  337.                         (*it)->object->
  338.                             GetPivotPosition());
  339.                 float hand_twist, pivot_twist;
  340.                 v3dDir hand_dir;
  341.                 action_point->GetAbsoluteOrientation().
  342.                     GetDirectionAndTwist(
  343.                         hand_dir, hand_twist);
  344.                 (*it)->object->GetAbsoluteOrientation().
  345.                     GetDirectionAndTwist(hand_dir,
  346.                         pivot_twist);
  347.                 (*it)->AP_delta_twist =
  348.                     pivot_twist - hand_twist;
  349.  
  350.                 if ((*it)->bounding_box)
  351.                     if ((*it)->object->IsPivoting())
  352.                         (*it)->bounding_box->SetColor(
  353.                                 PIVOT_COLOR);
  354.                     else
  355.                         (*it)->bounding_box->SetColor(
  356.                                 PICK_COLOR);
  357.  
  358.                 // Add the pivot info to the array of
  359.                 // picked objects.
  360.                 picked_objects_.push_back(*it);
  361.  
  362.                 // If this is the first picked object, then
  363.                 // register the pick update callback.
  364.                 if (picked_objects_.size() == 1)
  365.                     v3dEventReceiver::RegisterEventHandler(
  366.                         v3dSystem::GetCurrentUniverse(),
  367.                         v3dUniverse::UNIVERSE_SIMULATION_LOOP,
  368.                         &update_picked_objects_CB, 0);
  369.  
  370.                 // Fire the object pick event.
  371.                 object_pick_event_->InvokeHandlers(
  372.                     (v3dPointer)(*it)->object);
  373.             }
  374.         }
  375.     }
  376. }
  377.  
  378. // Returns the action point that's picked the object, or 0 if the object
  379. // isn't picked.
  380. v3dActionPoint*
  381. PivotTracker::GetPickingActionPoint(const PivotObject* object)
  382. {
  383.     PivotInfoArray::iterator finder = get_pick_info_by_object(object);
  384.     if (finder == picked_objects_.end())
  385.         return 0;
  386.  
  387.     return (*finder)->pick_AP;
  388. }
  389.  
  390.  
  391. ////////////////////////////////////////////////////////////////////////////////
  392. // Object stabilization
  393. ////////////////////////////////////////////////////////////////////////////////
  394. // Sets a pivot point for the object currently picked by the action point, and
  395. // unsets pivot points for any objects currently pivoting.
  396. void
  397. PivotTracker::TogglePivot(v3dActionPoint* action_point)
  398. {
  399.     PivotInfoArray::iterator it = picked_objects_.begin();
  400.     for (; it != picked_objects_.end(); ++it) {
  401.         if ((*it)->is_picked && ((*it)->pick_AP == action_point))
  402.             if ((*it)->object->IsPivoting()) {
  403.                 if ((*it)->bounding_box)
  404.                     (*it)->bounding_box->SetColor(PICK_COLOR);
  405.                 (*it)->object->UnsetPivot();
  406.                 object_unset_pivot_event_->InvokeHandlers(
  407.                     (v3dPointer)(*it)->object);
  408.             } else {
  409.                 if ((*it)->bounding_box)
  410.                     (*it)->bounding_box->SetColor(PIVOT_COLOR);
  411.                 (*it)->object->SetPivot();
  412.                 object_set_pivot_event_->InvokeHandlers(
  413.                     (v3dPointer)(*it)->object);
  414.             }
  415.     }
  416. }
  417.  
  418. ////////////////////////////////////////////////////////////////////////////////
  419. // Pivoting callback
  420. ////////////////////////////////////////////////////////////////////////////////
  421. void
  422. PivotTracker::update_picked_objects_CB(const v3dEventMessage* message)
  423. {
  424.     PivotTracker *tracker
  425.             = (PivotTracker *)message->GetEventReceiver();
  426.  
  427.     tracker->update_picked_objects();
  428. }
  429.  
  430. // Moves all picked objects to their proper position each cycle of the
  431. // simulation loop.
  432. void
  433. PivotTracker::update_picked_objects()
  434. {
  435.     for (PivotInfoArray::iterator it = picked_objects_.begin();
  436.             it != picked_objects_.end(); ++it) {
  437.         v3dObject *hand_object = (*it)->pick_AP->GetGeometry();
  438.         v3dDir hand_dir;
  439.         float hand_twist;
  440.         hand_object->GetAbsoluteOrientation().GetDirectionAndTwist(
  441.             hand_dir, hand_twist);
  442.  
  443.         (*it)->object->UpdatePosition(
  444.             hand_object->GetCoordSystem().LocalPosToAbsolute(
  445.                 (*it)->AP_offset),
  446.                 v3dOrient(hand_dir,
  447.                     hand_twist + (*it)->AP_delta_twist));
  448.  
  449.         if ((*it)->bounding_box) {
  450.             (*it)->bounding_box->MoveAbsolute(
  451.                 (*it)->object->GetAbsolutePosition());
  452.             (*it)->bounding_box->SetAbsoluteOrientation(
  453.                 (*it)->object->GetAbsoluteOrientation());
  454.         }
  455.  
  456.     }
  457. }
  458.  
  459. ////////////////////////////////////////////////////////////////////////////////
  460.  
  461. PivotTracker::PivotInfoArray::iterator
  462. PivotTracker::get_info_by_object(const PivotObject* object)
  463. {
  464.     for (PivotInfoArray::iterator finder = objects_.begin();
  465.             finder != objects_.end(); ++finder)
  466.         if ((*finder)->object == object)
  467.             return finder;
  468.  
  469.     return finder;
  470. }
  471.  
  472. PivotTracker::PivotInfoArray::iterator
  473. PivotTracker::get_pick_info_by_object(const PivotObject* object)
  474. {
  475.     for (PivotInfoArray::iterator finder = picked_objects_.begin();
  476.             finder != picked_objects_.end(); ++finder)
  477.         if ((*finder)->object == object)
  478.             return finder;
  479.  
  480.     return finder;
  481. }
  482.  
  483.  
  484.