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 >
Wrap
C/C++ Source or Header
|
1998-07-07
|
15KB
|
484 lines
/*
PivotTracker.cxx
*/
#include "PivotTracker.h"
#include "v3dUniverse.h"
#include <iostream.h>
const v3dColor PivotTracker::SELECT_COLOR (0, 255, 0);
const v3dColor PivotTracker::PICK_COLOR (0, 0, 255);
const v3dColor PivotTracker::PIVOT_COLOR (255, 0, 0);
PivotTracker::PivotTracker()
{
// Create the events that will be fired when objects are selected
// and unselected.
object_select_event_ = new PivotObjectSelectionEvent();
RegisterEvent(object_select_event_);
object_unselect_event_ = new PivotObjectUnselectionEvent();
RegisterEvent(object_unselect_event_);
// Create the events that will be fired when objects are picked
// and unpicked.
object_pick_event_ = new PivotObjectPickEvent();
RegisterEvent(object_pick_event_);
object_unpick_event_ = new PivotObjectUnpickEvent();
RegisterEvent(object_unpick_event_);
// Create the events that will be fired when object pivot points are
// set and unset.
object_set_pivot_event_ = new PivotObjectSetPivotEvent();
RegisterEvent(object_set_pivot_event_);
object_unset_pivot_event_ = new PivotObjectUnsetPivotEvent();
RegisterEvent(object_unset_pivot_event_);
}
PivotTracker::~PivotTracker()
{
// Erase the array of objects.
while (objects_.size()) {
delete objects_.back();
objects_.pop_back();
}
// Erase the array of action points.
while (action_points_.size()) {
action_points_.pop_back();
}
}
////////////////////////////////////////////////////////////////////////////////
// Action point management
////////////////////////////////////////////////////////////////////////////////
// Registers an action point used to send selection events for the
// tracker's objects.
// If the action point is already registered with the tracker, then it
// isn't re-registered and false is returned.
// Otherwise, selection and unselection callbacks are registered for every
// object watched by the tracker.
bool
PivotTracker::RegisterActionPoint(v3dActionPoint* action_point)
{
// First check the list of action points to make sure this AP
// isn't already registered.
ActionPointArray::iterator finder = find(action_points_.begin(),
action_points_.end(), action_point);
if (finder != action_points_.end())
return false;
// Add the new action point to the array of action points.
action_points_.push_back(action_point);
// Register selection and unselection callbacks with this action
// point for every object watched by the tracker.
for (PivotInfoArray::iterator it = objects_.begin();
it != objects_.end(); ++it) {
action_point->RegisterEventReceiver((*it)->object, this,
v3dActionPoint::AP_SELECT, &object_select_CB,
(v3dPointer)action_point);
action_point->RegisterEventReceiver((*it)->object, this,
v3dActionPoint::AP_UNSELECT, &object_unselect_CB,
(v3dPointer)action_point);
}
return true;
}
// Unregisters an action point used to send selection events for the
// tracker's objects.
// If the action point isn't registered with the tracker, then false
// is returned.
// Otherwise, selection and unselection callbacks are unregistered for every
// object watched by the tracker.
bool
PivotTracker::UnregisterActionPoint(v3dActionPoint* action_point)
{
// First check the list of action points to make sure this AP
// is already registered.
ActionPointArray::iterator finder = find(action_points_.begin(),
action_points_.end(), action_point);
if (finder == action_points_.end())
return false;
// Remove the action point from the array of action points.
action_points_.erase(finder);
// Unregister selection and unselection callbacks from this action
// point for every object watched by the tracker.
for (PivotInfoArray::iterator it = objects_.begin();
it != objects_.end(); ++it) {
action_point->UnregisterEventReceiver((*it)->object, this,
v3dActionPoint::AP_SELECT, &object_select_CB);
action_point->UnregisterEventReceiver((*it)->object, this,
v3dActionPoint::AP_UNSELECT, &object_unselect_CB);
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
// Object registration/unregistration
////////////////////////////////////////////////////////////////////////////////
// Registers an object to be watched.
bool
PivotTracker::RegisterObject(PivotObject* object)
{
// First, make sure that the object isn't already registered.
PivotInfoArray::iterator finder = get_info_by_object(object);
if (finder != objects_.end())
return false;
// Add the new object to the array of objects.
PivotObjectInfo *object_info = new PivotObjectInfo;
object_info->object = object;
object_info->bounding_box = 0;
object_info->is_selected = false;
object_info->is_picked = false;
object_info->is_pickable = true;
object_info->pick_AP = 0;
objects_.push_back(object_info);
// Register selection and unselection callbacks with every action
// point for this object.
for (ActionPointArray::iterator it = action_points_.begin();
it != action_points_.end(); ++it) {
(*it)->RegisterEventReceiver(object, this,
v3dActionPoint::AP_SELECT, &object_select_CB,
(v3dPointer)(*it));
(*it)->RegisterEventReceiver(object, this,
v3dActionPoint::AP_UNSELECT, &object_unselect_CB,
(v3dPointer)(*it));
}
return true;
}
// Unregisters an object from watched status.
bool
PivotTracker::UnregisterObject(PivotObject* object)
{
// First, find the object in the object array.
PivotInfoArray::iterator finder = get_info_by_object(object);
if (finder == objects_.end())
return false;
// Remove the object from the array of objects.
delete (*finder);
objects_.erase(finder);
// Unregister selection and unselection callbacks from every action
// point for this object.
for (ActionPointArray::iterator it = action_points_.begin();
it != action_points_.end(); ++it) {
(*it)->UnregisterEventReceiver(object, this,
v3dActionPoint::AP_SELECT, &object_select_CB);
(*it)->UnregisterEventReceiver(object, this,
v3dActionPoint::AP_UNSELECT, &object_unselect_CB);
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
// Object selection
////////////////////////////////////////////////////////////////////////////////
// Static callback for object selection.
void
PivotTracker::object_select_CB(const v3dEventMessage* message)
{
v3dCollisionCallData *call_data
= (v3dCollisionCallData *)message->GetCallData();
if (!((call_data->event_ID) & v3dActionPoint::AP_SELECT))
return;
PivotObject *collide_object = (PivotObject*)call_data->second_object;
v3dActionPoint *action_point
= (v3dActionPoint *)message->GetClientData();
PivotTracker *tracker
= (PivotTracker *)message->GetEventReceiver();
tracker->object_select(action_point, collide_object);
}
// Local callback for object selection.
void
PivotTracker::object_select(v3dActionPoint* action_point,
PivotObject* object)
{
PivotInfoArray::iterator finder = get_info_by_object(object);
if (finder == objects_.end())
return;
// Before going through selection startup, make sure this object isn't
// already selected by a different AP.
if ((*finder)->is_selected)
return;
// Add a bounding box to the object.
(*finder)->bounding_box = object->CreateBoundingBox(
0.05 * object->GetRadius());
(*finder)->bounding_box->SetColor(SELECT_COLOR);
(*finder)->is_selected = true;
// Fire the object selection event.
object_select_event_->InvokeHandlers((v3dPointer)object);
}
////////////////////////////////////////////////////////////////////////////////
// Object unselection
////////////////////////////////////////////////////////////////////////////////
// Static callback for object unselection.
void
PivotTracker::object_unselect_CB(const v3dEventMessage* message)
{
v3dCollisionCallData *call_data
= (v3dCollisionCallData *)message->GetCallData();
if (!((call_data->event_ID) & v3dActionPoint::AP_UNSELECT))
return;
PivotObject *collide_object = (PivotObject*)call_data->second_object;
v3dActionPoint *action_point
= (v3dActionPoint *)message->GetClientData();
PivotTracker *tracker
= (PivotTracker *)message->GetEventReceiver();
tracker->object_unselect(action_point, collide_object);
}
// Local callback for object unselection.
void
PivotTracker::object_unselect(v3dActionPoint* action_point,
PivotObject* object)
{
PivotInfoArray::iterator finder = get_info_by_object(object);
if (finder == objects_.end())
return;
// Make sure the object's not picked.
if ((*finder)->is_picked)
return;
// Make sure the object isn't currently selected by another action
// point before we dismantle the selection info.
ActionPointArray::iterator it = action_points_.begin();
for (; it != action_points_.end(); ++it) {
if ((*it != action_point) &&
object->Intersects((*it)->GetGeometry()))
break;
}
if (it != action_points_.end())
return;
// Remove the bounding box.
delete (*finder)->bounding_box;
(*finder)->bounding_box = 0;
(*finder)->is_selected = false;
// Fire the object unselection event.
object_unselect_event_->InvokeHandlers((v3dPointer)object);
}
////////////////////////////////////////////////////////////////////////////////
// Object picking
////////////////////////////////////////////////////////////////////////////////
// Picks all objects currently selected by the action point, and unpicks all
// objects currently picked by the action point.
void
PivotTracker::TogglePick(v3dActionPoint* action_point)
{
for (PivotInfoArray::iterator it = objects_.begin();
it != objects_.end(); ++it) {
if ((*it)->is_picked) {
if ((*it)->pick_AP == action_point) {
// The object is picked by this action point,
// so unpick it.
(*it)->is_picked = false;
(*it)->is_pickable = true;
(*it)->pick_AP = 0;
if ((*it)->bounding_box)
(*it)->bounding_box->SetColor(
SELECT_COLOR);
// Remove the pivot info from the array of
// picked objects.
PivotInfoArray::iterator finder =
get_pick_info_by_object((*it)->object);
if (finder != picked_objects_.end())
picked_objects_.erase(finder);
// If there are no more picked objects, then
// unregister the pick update callback.
if (picked_objects_.empty())
v3dEventReceiver::UnregisterEventHandler(
v3dSystem::GetCurrentUniverse(),
v3dUniverse::UNIVERSE_SIMULATION_LOOP,
&update_picked_objects_CB);
// Fire the object unpick event.
object_unpick_event_->InvokeHandlers(
(v3dPointer)(*it)->object);
}
} else {
// The object isn't picked.
if ((*it)->is_pickable &&
(*it)->object->Intersects(
action_point->GetGeometry())) {
// Pick the object.
(*it)->is_picked = true;
(*it)->is_pickable = false;
(*it)->pick_AP = action_point;
(*it)->AP_offset = action_point->GetGeometry()-> GetCoordSystem().AbsolutePosToLocal(
(*it)->object->
GetPivotPosition());
float hand_twist, pivot_twist;
v3dDir hand_dir;
action_point->GetAbsoluteOrientation().
GetDirectionAndTwist(
hand_dir, hand_twist);
(*it)->object->GetAbsoluteOrientation().
GetDirectionAndTwist(hand_dir,
pivot_twist);
(*it)->AP_delta_twist =
pivot_twist - hand_twist;
if ((*it)->bounding_box)
if ((*it)->object->IsPivoting())
(*it)->bounding_box->SetColor(
PIVOT_COLOR);
else
(*it)->bounding_box->SetColor(
PICK_COLOR);
// Add the pivot info to the array of
// picked objects.
picked_objects_.push_back(*it);
// If this is the first picked object, then
// register the pick update callback.
if (picked_objects_.size() == 1)
v3dEventReceiver::RegisterEventHandler(
v3dSystem::GetCurrentUniverse(),
v3dUniverse::UNIVERSE_SIMULATION_LOOP,
&update_picked_objects_CB, 0);
// Fire the object pick event.
object_pick_event_->InvokeHandlers(
(v3dPointer)(*it)->object);
}
}
}
}
// Returns the action point that's picked the object, or 0 if the object
// isn't picked.
v3dActionPoint*
PivotTracker::GetPickingActionPoint(const PivotObject* object)
{
PivotInfoArray::iterator finder = get_pick_info_by_object(object);
if (finder == picked_objects_.end())
return 0;
return (*finder)->pick_AP;
}
////////////////////////////////////////////////////////////////////////////////
// Object stabilization
////////////////////////////////////////////////////////////////////////////////
// Sets a pivot point for the object currently picked by the action point, and
// unsets pivot points for any objects currently pivoting.
void
PivotTracker::TogglePivot(v3dActionPoint* action_point)
{
PivotInfoArray::iterator it = picked_objects_.begin();
for (; it != picked_objects_.end(); ++it) {
if ((*it)->is_picked && ((*it)->pick_AP == action_point))
if ((*it)->object->IsPivoting()) {
if ((*it)->bounding_box)
(*it)->bounding_box->SetColor(PICK_COLOR);
(*it)->object->UnsetPivot();
object_unset_pivot_event_->InvokeHandlers(
(v3dPointer)(*it)->object);
} else {
if ((*it)->bounding_box)
(*it)->bounding_box->SetColor(PIVOT_COLOR);
(*it)->object->SetPivot();
object_set_pivot_event_->InvokeHandlers(
(v3dPointer)(*it)->object);
}
}
}
////////////////////////////////////////////////////////////////////////////////
// Pivoting callback
////////////////////////////////////////////////////////////////////////////////
void
PivotTracker::update_picked_objects_CB(const v3dEventMessage* message)
{
PivotTracker *tracker
= (PivotTracker *)message->GetEventReceiver();
tracker->update_picked_objects();
}
// Moves all picked objects to their proper position each cycle of the
// simulation loop.
void
PivotTracker::update_picked_objects()
{
for (PivotInfoArray::iterator it = picked_objects_.begin();
it != picked_objects_.end(); ++it) {
v3dObject *hand_object = (*it)->pick_AP->GetGeometry();
v3dDir hand_dir;
float hand_twist;
hand_object->GetAbsoluteOrientation().GetDirectionAndTwist(
hand_dir, hand_twist);
(*it)->object->UpdatePosition(
hand_object->GetCoordSystem().LocalPosToAbsolute(
(*it)->AP_offset),
v3dOrient(hand_dir,
hand_twist + (*it)->AP_delta_twist));
if ((*it)->bounding_box) {
(*it)->bounding_box->MoveAbsolute(
(*it)->object->GetAbsolutePosition());
(*it)->bounding_box->SetAbsoluteOrientation(
(*it)->object->GetAbsoluteOrientation());
}
}
}
////////////////////////////////////////////////////////////////////////////////
PivotTracker::PivotInfoArray::iterator
PivotTracker::get_info_by_object(const PivotObject* object)
{
for (PivotInfoArray::iterator finder = objects_.begin();
finder != objects_.end(); ++finder)
if ((*finder)->object == object)
return finder;
return finder;
}
PivotTracker::PivotInfoArray::iterator
PivotTracker::get_pick_info_by_object(const PivotObject* object)
{
for (PivotInfoArray::iterator finder = picked_objects_.begin();
finder != picked_objects_.end(); ++finder)
if ((*finder)->object == object)
return finder;
return finder;
}