Merge pull request #6199 from ZappoMan/myAvatarPalmTweaks

thread safety clean up of use of PalmData
This commit is contained in:
Brad Davis 2015-10-27 17:20:00 -07:00
commit 45ba0645d0
14 changed files with 202 additions and 392 deletions

View file

@ -2741,13 +2741,13 @@ void Application::update(float deltaTime) {
controller::Pose leftHand = userInputMapper->getPoseState(controller::Action::LEFT_HAND);
controller::Pose rightHand = userInputMapper->getPoseState(controller::Action::RIGHT_HAND);
Hand* hand = DependencyManager::get<AvatarManager>()->getMyAvatar()->getHand();
setPalmData(hand, leftHand, deltaTime, LEFT_HAND_INDEX, userInputMapper->getActionState(controller::Action::LEFT_HAND_CLICK));
setPalmData(hand, rightHand, deltaTime, RIGHT_HAND_INDEX, userInputMapper->getActionState(controller::Action::RIGHT_HAND_CLICK));
setPalmData(hand, leftHand, deltaTime, HandData::LeftHand, userInputMapper->getActionState(controller::Action::LEFT_HAND_CLICK));
setPalmData(hand, rightHand, deltaTime, HandData::RightHand, userInputMapper->getActionState(controller::Action::RIGHT_HAND_CLICK));
if (Menu::getInstance()->isOptionChecked(MenuOption::EnableHandMouseInput)) {
emulateMouse(hand, userInputMapper->getActionState(controller::Action::LEFT_HAND_CLICK),
userInputMapper->getActionState(controller::Action::SHIFT), LEFT_HAND_INDEX);
userInputMapper->getActionState(controller::Action::SHIFT), HandData::LeftHand);
emulateMouse(hand, userInputMapper->getActionState(controller::Action::RIGHT_HAND_CLICK),
userInputMapper->getActionState(controller::Action::SHIFT), RIGHT_HAND_INDEX);
userInputMapper->getActionState(controller::Action::SHIFT), HandData::RightHand);
}
updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process...
@ -4805,86 +4805,80 @@ mat4 Application::getHMDSensorPose() const {
return mat4();
}
void Application::setPalmData(Hand* hand, const controller::Pose& pose, float deltaTime, int index, float triggerValue) {
PalmData* palm;
bool foundHand = false;
for (size_t j = 0; j < hand->getNumPalms(); j++) {
if (hand->getPalms()[j].getSixenseID() == index) {
palm = &(hand->getPalms()[j]);
foundHand = true;
break;
void Application::setPalmData(Hand* hand, const controller::Pose& pose, float deltaTime, HandData::Hand whichHand, float triggerValue) {
// NOTE: the Hand::modifyPalm() will allow the lambda to modify the palm data while ensuring some other user isn't
// reading or writing to the Palms. This is definitely not the best way of handling this, and I'd like to see more
// of this palm manipulation in the Hand class itself. But unfortunately the Hand and Palm don't knbow about
// controller::Pose. More work is needed to clean this up.
hand->modifyPalm(whichHand, [&](PalmData& palm) {
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
palm.setActive(pose.isValid());
// transform from sensor space, to world space, to avatar model space.
glm::mat4 poseMat = createMatFromQuatAndPos(pose.getRotation(), pose.getTranslation());
glm::mat4 sensorToWorldMat = myAvatar->getSensorToWorldMatrix();
glm::mat4 modelMat = createMatFromQuatAndPos(myAvatar->getOrientation(), myAvatar->getPosition());
glm::mat4 objectPose = glm::inverse(modelMat) * sensorToWorldMat * poseMat;
glm::vec3 position = extractTranslation(objectPose);
glm::quat rotation = glm::quat_cast(objectPose);
// Compute current velocity from position change
glm::vec3 rawVelocity;
if (deltaTime > 0.0f) {
rawVelocity = (position - palm.getRawPosition()) / deltaTime;
} else {
rawVelocity = glm::vec3(0.0f);
}
}
if (!foundHand) {
PalmData newPalm(hand);
hand->getPalms().push_back(newPalm);
palm = &(hand->getPalms()[hand->getNumPalms() - 1]);
palm->setSixenseID(index);
}
palm.setRawVelocity(rawVelocity); // meters/sec
palm->setActive(pose.isValid());
// Angular Velocity of Palm
glm::quat deltaRotation = rotation * glm::inverse(palm.getRawRotation());
glm::vec3 angularVelocity(0.0f);
float rotationAngle = glm::angle(deltaRotation);
if ((rotationAngle > EPSILON) && (deltaTime > 0.0f)) {
angularVelocity = glm::normalize(glm::axis(deltaRotation));
angularVelocity *= (rotationAngle / deltaTime);
palm.setRawAngularVelocity(angularVelocity);
} else {
palm.setRawAngularVelocity(glm::vec3(0.0f));
}
// transform from sensor space, to world space, to avatar model space.
glm::mat4 poseMat = createMatFromQuatAndPos(pose.getRotation(), pose.getTranslation());
glm::mat4 sensorToWorldMat = getMyAvatar()->getSensorToWorldMatrix();
glm::mat4 modelMat = createMatFromQuatAndPos(getMyAvatar()->getOrientation(), getMyAvatar()->getPosition());
glm::mat4 objectPose = glm::inverse(modelMat) * sensorToWorldMat * poseMat;
if (controller::InputDevice::getLowVelocityFilter()) {
// Use a velocity sensitive filter to damp small motions and preserve large ones with
// no latency.
float velocityFilter = glm::clamp(1.0f - glm::length(rawVelocity), 0.0f, 1.0f);
position = palm.getRawPosition() * velocityFilter + position * (1.0f - velocityFilter);
rotation = safeMix(palm.getRawRotation(), rotation, 1.0f - velocityFilter);
}
palm.setRawPosition(position);
palm.setRawRotation(rotation);
glm::vec3 position = extractTranslation(objectPose);
glm::quat rotation = glm::quat_cast(objectPose);
// Compute current velocity from position change
glm::vec3 rawVelocity;
if (deltaTime > 0.0f) {
rawVelocity = (position - palm->getRawPosition()) / deltaTime;
} else {
rawVelocity = glm::vec3(0.0f);
}
palm->setRawVelocity(rawVelocity); // meters/sec
// Angular Velocity of Palm
glm::quat deltaRotation = rotation * glm::inverse(palm->getRawRotation());
glm::vec3 angularVelocity(0.0f);
float rotationAngle = glm::angle(deltaRotation);
if ((rotationAngle > EPSILON) && (deltaTime > 0.0f)) {
angularVelocity = glm::normalize(glm::axis(deltaRotation));
angularVelocity *= (rotationAngle / deltaTime);
palm->setRawAngularVelocity(angularVelocity);
} else {
palm->setRawAngularVelocity(glm::vec3(0.0f));
}
if (controller::InputDevice::getLowVelocityFilter()) {
// Use a velocity sensitive filter to damp small motions and preserve large ones with
// no latency.
float velocityFilter = glm::clamp(1.0f - glm::length(rawVelocity), 0.0f, 1.0f);
position = palm->getRawPosition() * velocityFilter + position * (1.0f - velocityFilter);
rotation = safeMix(palm->getRawRotation(), rotation, 1.0f - velocityFilter);
}
palm->setRawPosition(position);
palm->setRawRotation(rotation);
// Store the one fingertip in the palm structure so we can track velocity
const float FINGER_LENGTH = 0.3f; // meters
const glm::vec3 FINGER_VECTOR(0.0f, FINGER_LENGTH, 0.0f);
const glm::vec3 newTipPosition = position + rotation * FINGER_VECTOR;
glm::vec3 oldTipPosition = palm->getTipRawPosition();
if (deltaTime > 0.0f) {
palm->setTipVelocity((newTipPosition - oldTipPosition) / deltaTime);
} else {
palm->setTipVelocity(glm::vec3(0.0f));
}
palm->setTipPosition(newTipPosition);
palm->setTrigger(triggerValue);
// Store the one fingertip in the palm structure so we can track velocity
const float FINGER_LENGTH = 0.3f; // meters
const glm::vec3 FINGER_VECTOR(0.0f, FINGER_LENGTH, 0.0f);
const glm::vec3 newTipPosition = position + rotation * FINGER_VECTOR;
glm::vec3 oldTipPosition = palm.getTipRawPosition();
if (deltaTime > 0.0f) {
palm.setTipVelocity((newTipPosition - oldTipPosition) / deltaTime);
} else {
palm.setTipVelocity(glm::vec3(0.0f));
}
palm.setTipPosition(newTipPosition);
palm.setTrigger(triggerValue); // FIXME - we want to get rid of this idea of PalmData having a trigger
});
}
void Application::emulateMouse(Hand* hand, float click, float shift, int index) {
void Application::emulateMouse(Hand* hand, float click, float shift, HandData::Hand whichHand) {
auto palms = hand->getCopyOfPalms();
// Locate the palm, if it exists and is active
PalmData* palm;
bool foundHand = false;
for (size_t j = 0; j < hand->getNumPalms(); j++) {
if (hand->getPalms()[j].getSixenseID() == index) {
palm = &(hand->getPalms()[j]);
for (size_t j = 0; j < palms.size(); j++) {
if (palms[j].whichHand() == whichHand) {
palm = &(palms[j]);
foundHand = true;
break;
}
@ -4896,12 +4890,14 @@ void Application::emulateMouse(Hand* hand, float click, float shift, int index)
// Process the mouse events
QPoint pos;
unsigned int deviceID = index == 0 ? CONTROLLER_0_EVENT : CONTROLLER_1_EVENT;
// FIXME - this mouse emulation stuff needs to be reworked for new controller input plugins
unsigned int deviceID = whichHand == HandData::LeftHand ? CONTROLLER_0_EVENT : CONTROLLER_1_EVENT;
int index = (int)whichHand; // FIXME - hack attack
if (isHMDMode()) {
pos = getApplicationCompositor().getPalmClickLocation(palm);
}
else {
} else {
// Get directon relative to avatar orientation
glm::vec3 direction = glm::inverse(getMyAvatar()->getOrientation()) * palm->getFingerDirection();

View file

@ -352,8 +352,8 @@ private:
void update(float deltaTime);
void setPalmData(Hand* hand, const controller::Pose& pose, float deltaTime, int index, float triggerValue);
void emulateMouse(Hand* hand, float click, float shift, int index);
void setPalmData(Hand* hand, const controller::Pose& pose, float deltaTime, HandData::Hand whichHand, float triggerValue);
void emulateMouse(Hand* hand, float click, float shift, HandData::Hand whichHand);
// Various helper functions called during update()
void updateLOD();
@ -522,10 +522,13 @@ private:
ApplicationCompositor _compositor;
OverlayConductor _overlayConductor;
int _oldHandMouseX[2];
int _oldHandMouseY[2];
bool _oldHandLeftClick[2];
bool _oldHandRightClick[2];
// FIXME - Hand Controller to mouse emulation helpers. This is crufty and should be moved
// into the input plugins or something.
int _oldHandMouseX[(int)HandData::NUMBER_OF_HANDS];
int _oldHandMouseY[(int)HandData::NUMBER_OF_HANDS];
bool _oldHandLeftClick[(int)HandData::NUMBER_OF_HANDS];
bool _oldHandRightClick[(int)HandData::NUMBER_OF_HANDS];
DialogsManagerScriptingInterface* _dialogsManagerScriptingInterface = new DialogsManagerScriptingInterface();

View file

@ -1177,22 +1177,6 @@ glm::vec3 Avatar::getLeftPalmPosition() {
return leftHandPosition;
}
glm::vec3 Avatar::getLeftPalmVelocity() {
const PalmData* palm = getHand()->getPalm(LEFT_HAND_INDEX);
if (palm != NULL) {
return palm->getVelocity();
}
return glm::vec3(0.0f);
}
glm::vec3 Avatar::getLeftPalmAngularVelocity() {
const PalmData* palm = getHand()->getPalm(LEFT_HAND_INDEX);
if (palm != NULL) {
return palm->getRawAngularVelocity();
}
return glm::vec3(0.0f);
}
glm::quat Avatar::getLeftPalmRotation() {
glm::quat leftRotation;
getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getLeftHandJointIndex(), leftRotation);
@ -1208,22 +1192,6 @@ glm::vec3 Avatar::getRightPalmPosition() {
return rightHandPosition;
}
glm::vec3 Avatar::getRightPalmVelocity() {
const PalmData* palm = getHand()->getPalm(RIGHT_HAND_INDEX);
if (palm != NULL) {
return palm->getVelocity();
}
return glm::vec3(0.0f);
}
glm::vec3 Avatar::getRightPalmAngularVelocity() {
const PalmData* palm = getHand()->getPalm(RIGHT_HAND_INDEX);
if (palm != NULL) {
return palm->getRawAngularVelocity();
}
return glm::vec3(0.0f);
}
glm::quat Avatar::getRightPalmRotation() {
glm::quat rightRotation;
getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getRightHandJointIndex(), rightRotation);

View file

@ -160,13 +160,11 @@ public:
AvatarMotionState* getMotionState() { return _motionState; }
public slots:
// FIXME - these should be migrated to use Pose data instead
glm::vec3 getLeftPalmPosition();
glm::vec3 getLeftPalmVelocity();
glm::vec3 getLeftPalmAngularVelocity();
glm::quat getLeftPalmRotation();
glm::vec3 getRightPalmPosition();
glm::vec3 getRightPalmVelocity();
glm::vec3 getRightPalmAngularVelocity();
glm::quat getRightPalmRotation();
protected:

View file

@ -31,13 +31,7 @@ Hand::Hand(Avatar* owningAvatar) :
}
void Hand::simulate(float deltaTime, bool isMine) {
if (isMine) {
// Iterate hand controllers, take actions as needed
for (size_t i = 0; i < getNumPalms(); ++i) {
PalmData& palm = getPalms()[i];
palm.setLastControllerButtons(palm.getControllerButtons());
}
}
// nothing to do here
}
void Hand::renderHandTargets(RenderArgs* renderArgs, bool isMine) {
@ -53,10 +47,11 @@ void Hand::renderHandTargets(RenderArgs* renderArgs, bool isMine) {
const glm::vec3 grayColor(0.5f);
const float SPHERE_RADIUS = 0.03f * avatarScale;
auto palms = getCopyOfPalms();
gpu::Batch& batch = *renderArgs->_batch;
if (isMine) {
for (size_t i = 0; i < getNumPalms(); i++) {
PalmData& palm = getPalms()[i];
for (const auto& palm : palms) {
if (!palm.isActive()) {
continue;
}
@ -82,8 +77,7 @@ void Hand::renderHandTargets(RenderArgs* renderArgs, bool isMine) {
const float AXIS_LENGTH = 10.0f * SPHERE_RADIUS;
// Draw the coordinate frames of the hand targets
for (size_t i = 0; i < getNumPalms(); ++i) {
PalmData& palm = getPalms()[i];
for (const auto& palm : palms) {
if (palm.isActive()) {
glm::vec3 root = palm.getPosition();

View file

@ -548,80 +548,48 @@ void MyAvatar::updateFromTrackers(float deltaTime) {
}
// FIXME - this is super duper dumb... but this is how master works. When you have
// hydras plugged in, you'll get 4 "palms" but only the number of controllers lifted
// of the base station are considered active. So when you ask for "left" you get the
// first active controller. If you have both controllers held up or just the left, that
// will be correct. But if you lift the right controller, then it will be reported
// as "left"... you also see this in the avatars hands.
const PalmData* MyAvatar::getActivePalm(int palmIndex) const {
const HandData* handData = DependencyManager::get<AvatarManager>()->getMyAvatar()->getHandData();
int numberOfPalms = handData->getNumPalms();
int numberOfActivePalms = 0;
for (int i = 0; i < numberOfPalms; i++) {
auto palm = handData->getPalms()[i];
if (palm.isActive()) {
// if we've reached the requested "active" palm, then we will return it
if (numberOfActivePalms == palmIndex) {
return &handData->getPalms()[i];
}
numberOfActivePalms++;
}
}
return NULL;
}
glm::vec3 MyAvatar::getLeftHandPosition() const {
const int LEFT_HAND = 0;
auto palmData = getActivePalm(LEFT_HAND);
return palmData ? palmData->getPosition() : glm::vec3(0.0f);
auto palmData = getHandData()->getCopyOfPalmData(HandData::LeftHand);
return palmData.isValid() ? palmData.getPosition() : glm::vec3(0.0f);
}
glm::vec3 MyAvatar::getRightHandPosition() const {
const int RIGHT_HAND = 1;
auto palmData = getActivePalm(RIGHT_HAND);
return palmData ? palmData->getPosition() : glm::vec3(0.0f);
auto palmData = getHandData()->getCopyOfPalmData(HandData::RightHand);
return palmData.isValid() ? palmData.getPosition() : glm::vec3(0.0f);
}
glm::vec3 MyAvatar::getLeftHandTipPosition() const {
const int LEFT_HAND = 0;
auto palmData = getActivePalm(LEFT_HAND);
return palmData ? palmData->getTipPosition() : glm::vec3(0.0f);
auto palmData = getHandData()->getCopyOfPalmData(HandData::LeftHand);
return palmData.isValid() ? palmData.getTipPosition() : glm::vec3(0.0f);
}
glm::vec3 MyAvatar::getRightHandTipPosition() const {
const int RIGHT_HAND = 1;
auto palmData = getActivePalm(RIGHT_HAND);
return palmData ? palmData->getTipPosition() : glm::vec3(0.0f);
auto palmData = getHandData()->getCopyOfPalmData(HandData::RightHand);
return palmData.isValid() ? palmData.getTipPosition() : glm::vec3(0.0f);
}
controller::Pose MyAvatar::getLeftHandPose() const {
const int LEFT_HAND = 0;
auto palmData = getActivePalm(LEFT_HAND);
return palmData ? controller::Pose(palmData->getPosition(), palmData->getRotation(),
palmData->getVelocity(), palmData->getRawAngularVelocityAsQuat()) : controller::Pose();
auto palmData = getHandData()->getCopyOfPalmData(HandData::LeftHand);
return palmData.isValid() ? controller::Pose(palmData.getPosition(), palmData.getRotation(),
palmData.getVelocity(), palmData.getRawAngularVelocityAsQuat()) : controller::Pose();
}
controller::Pose MyAvatar::getRightHandPose() const {
const int RIGHT_HAND = 1;
auto palmData = getActivePalm(RIGHT_HAND);
return palmData ? controller::Pose(palmData->getPosition(), palmData->getRotation(),
palmData->getVelocity(), palmData->getRawAngularVelocityAsQuat()) : controller::Pose();
auto palmData = getHandData()->getCopyOfPalmData(HandData::RightHand);
return palmData.isValid() ? controller::Pose(palmData.getPosition(), palmData.getRotation(),
palmData.getVelocity(), palmData.getRawAngularVelocityAsQuat()) : controller::Pose();
}
controller::Pose MyAvatar::getLeftHandTipPose() const {
const int LEFT_HAND = 0;
auto palmData = getActivePalm(LEFT_HAND);
return palmData ? controller::Pose(palmData->getTipPosition(), palmData->getRotation(),
palmData->getTipVelocity(), palmData->getRawAngularVelocityAsQuat()) : controller::Pose();
auto palmData = getHandData()->getCopyOfPalmData(HandData::LeftHand);
return palmData.isValid() ? controller::Pose(palmData.getTipPosition(), palmData.getRotation(),
palmData.getTipVelocity(), palmData.getRawAngularVelocityAsQuat()) : controller::Pose();
}
controller::Pose MyAvatar::getRightHandTipPose() const {
const int RIGHT_HAND = 1;
auto palmData = getActivePalm(RIGHT_HAND);
return palmData ? controller::Pose(palmData->getTipPosition(), palmData->getRotation(),
palmData->getTipVelocity(), palmData->getRawAngularVelocityAsQuat()) : controller::Pose();
auto palmData = getHandData()->getCopyOfPalmData(HandData::RightHand);
return palmData.isValid() ? controller::Pose(palmData.getTipPosition(), palmData.getRotation(),
palmData.getTipVelocity(), palmData.getRawAngularVelocityAsQuat()) : controller::Pose();
}
// virtual
@ -1967,28 +1935,6 @@ void MyAvatar::updateMotionBehaviorFromMenu() {
_characterController.setEnabled(menu->isOptionChecked(MenuOption::EnableCharacterController));
}
//Renders sixense laser pointers for UI selection with controllers
void MyAvatar::renderLaserPointers(gpu::Batch& batch) {
const float PALM_TIP_ROD_RADIUS = 0.002f;
//If the Oculus is enabled, we will draw a blue cursor ray
for (size_t i = 0; i < getHand()->getNumPalms(); ++i) {
PalmData& palm = getHand()->getPalms()[i];
if (palm.isActive()) {
glm::vec3 tip = getLaserPointerTipPosition(&palm);
glm::vec3 root = palm.getPosition();
//Scale the root vector with the avatar scale
scaleVectorRelativeToPosition(root);
Transform transform = Transform();
transform.setTranslation(glm::vec3());
batch.setModelTransform(transform);
Avatar::renderJointConnectingCone(batch, root, tip, PALM_TIP_ROD_RADIUS, PALM_TIP_ROD_RADIUS, glm::vec4(0, 1, 1, 1));
}
}
}
//Gets the tip position for the laser pointer
glm::vec3 MyAvatar::getLaserPointerTipPosition(const PalmData* palm) {
glm::vec3 direction = glm::normalize(palm->getTipPosition() - palm->getPosition());

View file

@ -294,7 +294,6 @@ private:
const glm::vec3& translation = glm::vec3(), const glm::quat& rotation = glm::quat(), float scale = 1.0f,
bool allowDuplicates = false, bool useSaved = true) override;
void renderLaserPointers(gpu::Batch& batch);
const RecorderPointer getRecorder() const { return _recorder; }
const PlayerPointer getPlayer() const { return _player; }
@ -310,8 +309,7 @@ private:
void setVisibleInSceneIfReady(Model* model, render::ScenePointer scene, bool visiblity);
const PalmData* getActivePalm(int palmIndex) const;
PalmData getActivePalmData(int palmIndex) const;
// derive avatar body position and orientation from the current HMD Sensor location.
// results are in sensor space

View file

@ -97,17 +97,6 @@ void SkeletonModel::initJointStates(QVector<JointState> states) {
emit skeletonLoaded();
}
static const PalmData* getPalmWithIndex(Hand* hand, int index) {
const PalmData* palm = nullptr;
for (size_t j = 0; j < hand->getNumPalms(); j++) {
if (hand->getPalms()[j].getSixenseID() == index) {
palm = &(hand->getPalms()[j]);
break;
}
}
return palm;
}
const float PALM_PRIORITY = DEFAULT_PRIORITY;
// Called within Model::simulate call, below.
void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
@ -169,22 +158,22 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
Rig::HandParameters handParams;
const PalmData* leftPalm = getPalmWithIndex(myAvatar->getHand(), LEFT_HAND_INDEX);
if (leftPalm && leftPalm->isActive()) {
auto leftPalm = myAvatar->getHand()->getCopyOfPalmData(HandData::LeftHand);
if (leftPalm.isValid() && leftPalm.isActive()) {
handParams.isLeftEnabled = true;
handParams.leftPosition = leftPalm->getRawPosition();
handParams.leftOrientation = leftPalm->getRawRotation();
handParams.leftTrigger = leftPalm->getTrigger();
handParams.leftPosition = leftPalm.getRawPosition();
handParams.leftOrientation = leftPalm.getRawRotation();
handParams.leftTrigger = leftPalm.getTrigger();
} else {
handParams.isLeftEnabled = false;
}
const PalmData* rightPalm = getPalmWithIndex(myAvatar->getHand(), RIGHT_HAND_INDEX);
if (rightPalm && rightPalm->isActive()) {
auto rightPalm = myAvatar->getHand()->getCopyOfPalmData(HandData::RightHand);
if (rightPalm.isValid() && rightPalm.isActive()) {
handParams.isRightEnabled = true;
handParams.rightPosition = rightPalm->getRawPosition();
handParams.rightOrientation = rightPalm->getRawRotation();
handParams.rightTrigger = rightPalm->getTrigger();
handParams.rightPosition = rightPalm.getRawPosition();
handParams.rightOrientation = rightPalm.getRawRotation();
handParams.rightTrigger = rightPalm.getTrigger();
} else {
handParams.isRightEnabled = false;
}
@ -247,15 +236,15 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) {
const FBXGeometry& geometry = _geometry->getFBXGeometry();
// find the left and rightmost active palms
int leftPalmIndex, rightPalmIndex;
Hand* hand = _owningAvatar->getHand();
hand->getLeftRightPalmIndices(leftPalmIndex, rightPalmIndex);
// Don't Relax toward hand positions when in animGraph mode.
if (!_rig->getEnableAnimGraph()) {
Hand* hand = _owningAvatar->getHand();
auto leftPalm = hand->getCopyOfPalmData(HandData::LeftHand);
auto rightPalm = hand->getCopyOfPalmData(HandData::RightHand);
const float HAND_RESTORATION_RATE = 0.25f;
if (leftPalmIndex == -1 && rightPalmIndex == -1) {
if (!leftPalm.isActive() && !rightPalm.isActive()) {
// palms are not yet set, use mouse
if (_owningAvatar->getHandState() == HAND_STATE_NULL) {
restoreRightHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY);
@ -265,20 +254,14 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) {
applyHandPosition(geometry.rightHandJointIndex, handPosition);
}
restoreLeftHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY);
} else if (leftPalmIndex == rightPalmIndex) {
// right hand only
applyPalmData(geometry.rightHandJointIndex, hand->getPalms()[leftPalmIndex]);
restoreLeftHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY);
} else {
if (leftPalmIndex != -1) {
applyPalmData(geometry.leftHandJointIndex, hand->getPalms()[leftPalmIndex]);
if (leftPalm.isActive()) {
applyPalmData(geometry.leftHandJointIndex, leftPalm);
} else {
restoreLeftHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY);
}
if (rightPalmIndex != -1) {
applyPalmData(geometry.rightHandJointIndex, hand->getPalms()[rightPalmIndex]);
if (rightPalm.isActive()) {
applyPalmData(geometry.rightHandJointIndex, rightPalm);
} else {
restoreRightHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY);
}
@ -329,7 +312,7 @@ void SkeletonModel::applyHandPosition(int jointIndex, const glm::vec3& position)
PALM_PRIORITY);
}
void SkeletonModel::applyPalmData(int jointIndex, PalmData& palm) {
void SkeletonModel::applyPalmData(int jointIndex, const PalmData& palm) {
if (jointIndex == -1 || jointIndex >= _rig->getJointStateCount()) {
return;
}

View file

@ -118,7 +118,7 @@ protected:
/// \param position position of joint in model-frame
void applyHandPosition(int jointIndex, const glm::vec3& position);
void applyPalmData(int jointIndex, PalmData& palm);
void applyPalmData(int jointIndex, const PalmData& palm);
private:
void renderJointConstraints(gpu::Batch& batch, int jointIndex);

View file

@ -35,51 +35,6 @@ void ControllerScriptingInterface::handleMetaEvent(HFMetaEvent* event) {
}
}
const PalmData* ControllerScriptingInterface::getPrimaryPalm() const {
int leftPalmIndex, rightPalmIndex;
const HandData* handData = DependencyManager::get<AvatarManager>()->getMyAvatar()->getHandData();
handData->getLeftRightPalmIndices(leftPalmIndex, rightPalmIndex);
if (rightPalmIndex != -1) {
return &handData->getPalms()[rightPalmIndex];
}
return NULL;
}
int ControllerScriptingInterface::getNumberOfActivePalms() const {
const HandData* handData = DependencyManager::get<AvatarManager>()->getMyAvatar()->getHandData();
int numberOfPalms = handData->getNumPalms();
int numberOfActivePalms = 0;
for (int i = 0; i < numberOfPalms; i++) {
if (getPalm(i)->isActive()) {
numberOfActivePalms++;
}
}
return numberOfActivePalms;
}
const PalmData* ControllerScriptingInterface::getPalm(int palmIndex) const {
const HandData* handData = DependencyManager::get<AvatarManager>()->getMyAvatar()->getHandData();
return &handData->getPalms()[palmIndex];
}
const PalmData* ControllerScriptingInterface::getActivePalm(int palmIndex) const {
const HandData* handData = DependencyManager::get<AvatarManager>()->getMyAvatar()->getHandData();
int numberOfPalms = handData->getNumPalms();
int numberOfActivePalms = 0;
for (int i = 0; i < numberOfPalms; i++) {
if (getPalm(i)->isActive()) {
if (numberOfActivePalms == palmIndex) {
return &handData->getPalms()[i];
}
numberOfActivePalms++;
}
}
return NULL;
}
bool ControllerScriptingInterface::isKeyCaptured(QKeyEvent* event) const {
return isKeyCaptured(KeyEvent(*event));
}

View file

@ -123,11 +123,6 @@ signals:
private:
QString sanatizeName(const QString& name); /// makes a name clean for inclusing in JavaScript
const PalmData* getPrimaryPalm() const;
const PalmData* getPalm(int palmIndex) const;
int getNumberOfActivePalms() const;
const PalmData* getActivePalm(int palmIndex) const;
QMultiMap<int,KeyEvent> _capturedKeys;
QSet<int> _capturedJoysticks;

View file

@ -320,8 +320,8 @@ void ApplicationCompositor::displayOverlayTextureHmd(RenderArgs* renderArgs, int
// Only render the hand pointers if the EnableHandMouseInput is enabled
if (Menu::getInstance()->isOptionChecked(MenuOption::EnableHandMouseInput)) {
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
for (int i = 0; i < (int)myAvatar->getHand()->getNumPalms(); i++) {
PalmData& palm = myAvatar->getHand()->getPalms()[i];
auto palms = myAvatar->getHand()->getCopyOfPalms();
for (const auto& palm : palms) {
if (palm.isActive()) {
glm::vec2 polar = getPolarCoordinates(palm);
// Convert to quaternion
@ -446,6 +446,7 @@ void ApplicationCompositor::renderPointers(gpu::Batch& batch) {
}
// FIXME - this is old code that likely needs to be removed and/or reworked to support the new input control model
void ApplicationCompositor::renderControllerPointers(gpu::Batch& batch) {
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
@ -455,23 +456,24 @@ void ApplicationCompositor::renderControllerPointers(gpu::Batch& batch) {
static bool stateWhenPressed[NUMBER_OF_RETICLES] = { false, false, false };
const HandData* handData = DependencyManager::get<AvatarManager>()->getMyAvatar()->getHandData();
auto palms = handData->getCopyOfPalms();
for (unsigned int palmIndex = 2; palmIndex < 4; palmIndex++) {
const int index = palmIndex - 1;
const PalmData* palmData = NULL;
if (palmIndex >= handData->getPalms().size()) {
if (palmIndex >= palms.size()) {
return;
}
if (handData->getPalms()[palmIndex].isActive()) {
palmData = &handData->getPalms()[palmIndex];
if (palms[palmIndex].isActive()) {
palmData = &palms[palmIndex];
} else {
continue;
}
int controllerButtons = palmData->getControllerButtons();
int controllerButtons = 0;
//Check for if we should toggle or drag the magnification window
if (controllerButtons & BUTTON_3) {

View file

@ -21,62 +21,43 @@
HandData::HandData(AvatarData* owningAvatar) :
_owningAvatarData(owningAvatar)
{
// Start with two palms
addNewPalm();
addNewPalm();
addNewPalm(LeftHand);
addNewPalm(RightHand);
}
glm::vec3 HandData::worldToLocalVector(const glm::vec3& worldVector) const {
return glm::inverse(getBaseOrientation()) * worldVector / getBaseScale();
}
PalmData& HandData::addNewPalm() {
_palms.push_back(PalmData(this));
PalmData& HandData::addNewPalm(Hand whichHand) {
QWriteLocker locker(&_palmsLock);
_palms.push_back(PalmData(this, whichHand));
return _palms.back();
}
const PalmData* HandData::getPalm(int sixSenseID) const {
PalmData HandData::getCopyOfPalmData(Hand hand) const {
QReadLocker locker(&_palmsLock);
// the palms are not necessarily added in left-right order,
// so we have to search for the right SixSenseID
for (unsigned int i = 0; i < _palms.size(); i++) {
const PalmData* palm = &(_palms[i]);
if (palm->getSixenseID() == sixSenseID) {
return palm->isActive() ? palm : NULL;
// so we have to search for the correct hand
for (const auto& palm : _palms) {
if (palm.whichHand() == hand && palm.isActive()) {
return palm;
}
}
return NULL;
return PalmData(); // invalid hand
}
void HandData::getLeftRightPalmIndices(int& leftPalmIndex, int& rightPalmIndex) const {
leftPalmIndex = -1;
rightPalmIndex = -1;
for (size_t i = 0; i < _palms.size(); i++) {
const PalmData& palm = _palms[i];
if (palm.isActive()) {
if (palm.getSixenseID() == LEFT_HAND_INDEX) {
leftPalmIndex = i;
}
if (palm.getSixenseID() == RIGHT_HAND_INDEX) {
rightPalmIndex = i;
}
}
}
}
PalmData::PalmData(HandData* owningHandData) :
PalmData::PalmData(HandData* owningHandData, HandData::Hand hand) :
_rawRotation(0.0f, 0.0f, 0.0f, 1.0f),
_rawPosition(0.0f),
_rawVelocity(0.0f),
_rawAngularVelocity(0.0f),
_totalPenetration(0.0f),
_controllerButtons(0),
_isActive(false),
_sixenseID(SIXENSEID_INVALID),
_numFramesWithoutData(0),
_owningHandData(owningHandData),
_isCollidingWithVoxel(false),
_isCollidingWithPalm(false),
_collisionlessPaddleExpiry(0) {
_hand(hand) {
}
void PalmData::addToPosition(const glm::vec3& delta) {
@ -85,9 +66,9 @@ void PalmData::addToPosition(const glm::vec3& delta) {
bool HandData::findSpherePenetration(const glm::vec3& penetratorCenter, float penetratorRadius, glm::vec3& penetration,
const PalmData*& collidingPalm) const {
for (size_t i = 0; i < _palms.size(); ++i) {
const PalmData& palm = _palms[i];
QReadLocker locker(&_palmsLock);
for (const auto& palm : _palms) {
if (!palm.isActive()) {
continue;
}

View file

@ -12,26 +12,30 @@
#ifndef hifi_HandData_h
#define hifi_HandData_h
#include <functional>
#include <iostream>
#include <vector>
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
#include <QReadWriteLock>
#include <NumericalConstants.h>
#include <SharedUtil.h>
class AvatarData;
class PalmData;
const int LEFT_HAND_INDEX = 0;
const int RIGHT_HAND_INDEX = 1;
const int NUM_HANDS = 2;
const int SIXENSEID_INVALID = -1;
class HandData {
public:
enum Hand {
LeftHand,
RightHand,
UnknownHand,
NUMBER_OF_HANDS
};
HandData(AvatarData* owningAvatar);
virtual ~HandData() {}
@ -46,15 +50,9 @@ public:
glm::vec3 worldToLocalVector(const glm::vec3& worldVector) const;
std::vector<PalmData>& getPalms() { return _palms; }
const std::vector<PalmData>& getPalms() const { return _palms; }
const PalmData* getPalm(int sixSenseID) const;
size_t getNumPalms() const { return _palms.size(); }
PalmData& addNewPalm();
PalmData getCopyOfPalmData(Hand hand) const;
/// Finds the indices of the left and right palms according to their locations, or -1 if either or
/// both is not found.
void getLeftRightPalmIndices(int& leftPalmIndex, int& rightPalmIndex) const;
std::vector<PalmData> getCopyOfPalms() const { QReadLocker locker(&_palmsLock); return _palms; }
/// Checks for penetration between the described sphere and the hand.
/// \param penetratorCenter the center of the penetration test sphere
@ -67,14 +65,22 @@ public:
glm::quat getBaseOrientation() const;
/// Allows a lamda function write access to the specific palm for this Hand, this might
/// modify the _palms vector
template<typename PalmModifierFunction> void modifyPalm(Hand whichHand, PalmModifierFunction callback);
friend class AvatarData;
protected:
AvatarData* _owningAvatarData;
std::vector<PalmData> _palms;
mutable QReadWriteLock _palmsLock{ QReadWriteLock::Recursive };
glm::vec3 getBasePosition() const;
float getBaseScale() const;
PalmData& addNewPalm(Hand whichHand);
PalmData& getPalmData(Hand hand);
private:
// privatize copy ctor and assignment operator so copies of this object cannot be made
HandData(const HandData&);
@ -84,18 +90,20 @@ private:
class PalmData {
public:
PalmData(HandData* owningHandData);
PalmData(HandData* owningHandData = nullptr, HandData::Hand hand = HandData::UnknownHand);
glm::vec3 getPosition() const { return _owningHandData->localToWorldPosition(_rawPosition); }
glm::vec3 getVelocity() const { return _owningHandData->localToWorldDirection(_rawVelocity); }
const glm::vec3& getRawPosition() const { return _rawPosition; }
bool isActive() const { return _isActive; }
int getSixenseID() const { return _sixenseID; }
bool isValid() const { return _owningHandData; }
void setActive(bool active) { _isActive = active; }
void setSixenseID(int id) { _sixenseID = id; }
void setRawRotation(const glm::quat rawRotation) { _rawRotation = rawRotation; };
HandData::Hand whichHand() const { return _hand; }
void setHand(HandData::Hand hand) { _hand = hand; }
void setRawRotation(const glm::quat& rawRotation) { _rawRotation = rawRotation; };
glm::quat getRawRotation() const { return _rawRotation; }
glm::quat getRotation() const { return _owningHandData->getBaseOrientation() * _rawRotation; }
void setRawPosition(const glm::vec3& pos) { _rawPosition = pos; }
@ -123,31 +131,11 @@ public:
void resetFramesWithoutData() { _numFramesWithoutData = 0; }
int getFramesWithoutData() const { return _numFramesWithoutData; }
// Controller buttons
void setControllerButtons(unsigned int controllerButtons) { _controllerButtons = controllerButtons; }
void setLastControllerButtons(unsigned int controllerButtons) { _lastControllerButtons = controllerButtons; }
unsigned int getControllerButtons() const { return _controllerButtons; }
unsigned int getLastControllerButtons() const { return _lastControllerButtons; }
// FIXME - these are used in SkeletonModel::updateRig() the skeleton/rig should probably get this information
// from an action and/or the UserInputMapper instead of piping it through here.
void setTrigger(float trigger) { _trigger = trigger; }
float getTrigger() const { return _trigger; }
void setJoystick(float joystickX, float joystickY) { _joystickX = joystickX; _joystickY = joystickY; }
float getJoystickX() const { return _joystickX; }
float getJoystickY() const { return _joystickY; }
bool getIsCollidingWithVoxel() const { return _isCollidingWithVoxel; }
void setIsCollidingWithVoxel(bool isCollidingWithVoxel) { _isCollidingWithVoxel = isCollidingWithVoxel; }
bool getIsCollidingWithPalm() const { return _isCollidingWithPalm; }
void setIsCollidingWithPalm(bool isCollidingWithPalm) { _isCollidingWithPalm = isCollidingWithPalm; }
bool hasPaddle() const { return _collisionlessPaddleExpiry < usecTimestampNow(); }
void updateCollisionlessPaddleExpiry() { _collisionlessPaddleExpiry = usecTimestampNow() + USECS_PER_SECOND; }
/// Store position where the palm holds the ball.
void getBallHoldPosition(glm::vec3& position) const;
// return world-frame:
glm::vec3 getFingerDirection() const;
glm::vec3 getNormal() const;
@ -163,21 +151,24 @@ private:
glm::vec3 _tipPosition;
glm::vec3 _tipVelocity;
glm::vec3 _totalPenetration; // accumulator for per-frame penetrations
glm::vec3 _totalPenetration; /// accumulator for per-frame penetrations
unsigned int _controllerButtons;
unsigned int _lastControllerButtons;
float _trigger;
float _joystickX, _joystickY;
bool _isActive; // This has current valid data
int _sixenseID; // Sixense controller ID for this palm
int _numFramesWithoutData; // after too many frames without data, this tracked object assumed lost.
bool _isActive; /// This has current valid data
int _numFramesWithoutData; /// after too many frames without data, this tracked object assumed lost.
HandData* _owningHandData;
bool _isCollidingWithVoxel; /// Whether the finger of this palm is inside a leaf voxel
bool _isCollidingWithPalm;
quint64 _collisionlessPaddleExpiry; /// Timestamp after which paddle starts colliding
HandData::Hand _hand;
};
template<typename PalmModifierFunction> void HandData::modifyPalm(Hand whichHand, PalmModifierFunction callback) {
QReadLocker locker(&_palmsLock);
for (auto& palm : _palms) {
if (palm.whichHand() == whichHand && palm.isValid()) {
callback(palm);
return;
}
}
}
#endif // hifi_HandData_h