Merge branch 'master' of https://github.com/highfidelity/hifi into animationGroupSettings

This commit is contained in:
Brad Hefta-Gaub 2015-10-07 15:49:46 -07:00
commit e93326e43f
26 changed files with 322 additions and 217 deletions

View file

@ -2351,6 +2351,7 @@ void Application::saveSettings() {
Menu::getInstance()->saveSettings();
getMyAvatar()->saveData();
PluginManager::getInstance()->saveSettings();
}
bool Application::importEntities(const QString& urlOrFilename) {
@ -2758,7 +2759,7 @@ void Application::update(float deltaTime) {
Hand* hand = DependencyManager::get<AvatarManager>()->getMyAvatar()->getHand();
setPalmData(hand, leftHand, deltaTime, LEFT_HAND_INDEX, userInputMapper->getActionState(UserInputMapper::LEFT_HAND_CLICK));
setPalmData(hand, rightHand, deltaTime, RIGHT_HAND_INDEX, userInputMapper->getActionState(UserInputMapper::RIGHT_HAND_CLICK));
if (Menu::getInstance()->isOptionChecked(MenuOption::HandMouseInput)) {
if (Menu::getInstance()->isOptionChecked(MenuOption::EnableHandMouseInput)) {
emulateMouse(hand, userInputMapper->getActionState(UserInputMapper::LEFT_HAND_CLICK),
userInputMapper->getActionState(UserInputMapper::SHIFT), LEFT_HAND_INDEX);
emulateMouse(hand, userInputMapper->getActionState(UserInputMapper::RIGHT_HAND_CLICK),

View file

@ -464,7 +464,7 @@ Menu::Menu() {
MenuWrapper* handOptionsMenu = developerMenu->addMenu("Hands");
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayHandTargets, 0, false);
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::HandMouseInput, 0, true);
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::EnableHandMouseInput, 0, false);
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::LowVelocityFilter, 0, true,
qApp, SLOT(setLowVelocityFilter(bool)));
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::ShowIKConstraints, 0, false);

View file

@ -204,7 +204,7 @@ namespace MenuOption {
const QString FrameTimer = "Show Timer";
const QString FullscreenMirror = "Fullscreen Mirror";
const QString GlowWhenSpeaking = "Glow When Speaking";
const QString HandMouseInput = "Enable Hand Mouse Input";
const QString EnableHandMouseInput = "Enable Hand Controller Mouse Input";
const QString IncreaseAvatarSize = "Increase Avatar Size";
const QString IndependentMode = "Independent Mode";
const QString InputMenu = "Avatar>Input Devices";

View file

@ -549,7 +549,12 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) {
auto cameraMode = qApp->getCamera()->getMode();
if (!isMyAvatar() || cameraMode != CAMERA_MODE_FIRST_PERSON) {
renderDisplayName(batch, *renderArgs->_viewFrustum, renderArgs->_viewport);
auto& frustum = *renderArgs->_viewFrustum;
auto textPosition = getDisplayNamePosition();
if (frustum.pointInFrustum(textPosition, true) == ViewFrustum::INSIDE) {
renderDisplayName(batch, frustum, textPosition);
}
}
endRender();
}
@ -685,120 +690,85 @@ void Avatar::renderBillboard(RenderArgs* renderArgs) {
}
float Avatar::getBillboardSize() const {
return _scale * BILLBOARD_DISTANCE * tanf(glm::radians(BILLBOARD_FIELD_OF_VIEW / 2.0f));
return _scale * BILLBOARD_DISTANCE * glm::tan(glm::radians(BILLBOARD_FIELD_OF_VIEW / 2.0f));
}
#ifdef DEBUG
void debugValue(const QString& str, const glm::vec3& value) {
if (glm::any(glm::isnan(value)) || glm::any(glm::isinf(value))) {
qCWarning(interfaceapp) << "debugValue() " << str << value;
}
};
void debugValue(const QString& str, const float& value) {
if (glm::isnan(value) || glm::isinf(value)) {
qCWarning(interfaceapp) << "debugValue() " << str << value;
}
};
#define DEBUG_VALUE(str, value) debugValue(str, value)
#else
#define DEBUG_VALUE(str, value)
#endif
glm::vec3 Avatar::getDisplayNamePosition() const {
glm::vec3 namePosition(0.0f);
glm::vec3 bodyUpDirection = getBodyUpDirection();
DEBUG_VALUE("bodyUpDirection =", bodyUpDirection);
if (getSkeletonModel().getNeckPosition(namePosition)) {
namePosition += getBodyUpDirection() * getHeadHeight() * 1.1f;
float headHeight = getHeadHeight();
DEBUG_VALUE("namePosition =", namePosition);
DEBUG_VALUE("headHeight =", headHeight);
static const float SLIGHTLY_ABOVE = 1.1f;
namePosition += bodyUpDirection * headHeight * SLIGHTLY_ABOVE;
} else {
const float HEAD_PROPORTION = 0.75f;
namePosition = _position + getBodyUpDirection() * (getBillboardSize() * HEAD_PROPORTION);
float billboardSize = getBillboardSize();
DEBUG_VALUE("_position =", _position);
DEBUG_VALUE("billboardSize =", billboardSize);
namePosition = _position + bodyUpDirection * (billboardSize * HEAD_PROPORTION);
}
#ifdef DEBUG
// TODO: Temporary logging to track cause of invalid scale value; remove once cause has been fixed.
// See other TODO below.
if (glm::isnan(namePosition.x) || glm::isnan(namePosition.y) || glm::isnan(namePosition.z)
|| glm::isinf(namePosition.x) || glm::isinf(namePosition.y) || glm::isinf(namePosition.z)) {
qDebug() << "namePosition =" << namePosition;
glm::vec3 tempPosition(0.0f);
if (getSkeletonModel().getNeckPosition(tempPosition)) {
qDebug() << "getBodyUpDirection() =" << getBodyUpDirection();
qDebug() << "getHeadHeight() =" << getHeadHeight();
} else {
qDebug() << "_position =" << _position;
qDebug() << "getBodyUpDirection() =" << getBodyUpDirection();
qDebug() << "getBillboardSize() =" << getBillboardSize();
}
if (glm::any(glm::isnan(namePosition)) || glm::any(glm::isinf(namePosition))) {
qCWarning(interfaceapp) << "Invalid display name position" << namePosition
<< ", setting is to (0.0f, 0.5f, 0.0f)";
namePosition = glm::vec3(0.0f, 0.5f, 0.0f);
}
#endif
return namePosition;
}
Transform Avatar::calculateDisplayNameTransform(const ViewFrustum& frustum, float fontSize, const glm::ivec4& viewport) const {
Transform result;
// We assume textPosition is whithin the frustum
glm::vec3 textPosition = getDisplayNamePosition();
// Compute viewProjection matrix
glm::mat4 projMat, viewMat;
Transform view;
frustum.evalProjectionMatrix(projMat);
frustum.evalViewTransform(view);
glm::mat4 viewProj = projMat * view.getInverseMatrix(viewMat);
// Used to determine correct scale
glm::vec3 testPoint0 = textPosition;
glm::vec3 testPoint1 = testPoint0 + glm::normalize(frustum.getUp());
// testPoints projections
glm::vec4 p0 = viewProj * glm::vec4(testPoint0, 1.0);
glm::vec4 p1 = viewProj * glm::vec4(testPoint1, 1.0);
float windowSizeY = viewport.w;
const float DESIRED_HIGHT_ON_SCREEN = 20; // In pixels (this is double on retinas)
// Projected point are between -1.0f and 1.0f, hence 0.5f * windowSizeY
float pixelHeight = 0.5f * windowSizeY * glm::abs((p1.y / p1.w) - (p0.y / p0.w)); //
// Handles pixel density (especially for macs retina displays)
float devicePixelRatio = (float)qApp->getDevicePixelRatio() * qApp->getRenderResolutionScale(); // pixels / unit
// Compute correct scale to apply
float scale = DESIRED_HIGHT_ON_SCREEN / (fontSize * pixelHeight) * devicePixelRatio;
#ifdef DEBUG
// TODO: Temporary logging to track cause of invalid scale value; remove once cause has been fixed.
// Problem is probably due to an invalid getDisplayNamePosition(). See extra logging above.
if (scale == 0.0f || glm::isnan(scale) || glm::isinf(scale)) {
if (scale == 0.0f) {
qDebug() << "ASSERT because scale == 0.0f";
}
if (glm::isnan(scale)) {
qDebug() << "ASSERT because isnan(scale)";
}
if (glm::isinf(scale)) {
qDebug() << "ASSERT because isinf(scale)";
}
qDebug() << "textPosition =" << textPosition;
qDebug() << "projMat =" << projMat;
qDebug() << "viewMat =" << viewMat;
qDebug() << "viewProj =" << viewProj;
qDebug() << "windowSizeY =" << windowSizeY;
qDebug() << "p1 =" << p1;
qDebug() << "p0 =" << p0;
qDebug() << "qApp->getDevicePixelRatio() =" << qApp->getDevicePixelRatio();
qDebug() << "fontSize =" << fontSize;
qDebug() << "pixelHeight =" << pixelHeight;
qDebug() << "devicePixelRatio =" << devicePixelRatio;
}
#endif
// Compute pixel alignment offset
float clipToPix = 0.5f * windowSizeY / p1.w; // Got from clip to pixel coordinates
glm::vec4 screenPos = clipToPix * p1; // in pixels coords
glm::vec4 screenOffset = (glm::round(screenPos) - screenPos) / clipToPix; // in clip coords
glm::vec3 worldOffset = glm::vec3(screenOffset.x, screenOffset.y, 0.0f) / (float)pixelHeight;
Transform Avatar::calculateDisplayNameTransform(const ViewFrustum& frustum, const glm::vec3& textPosition) const {
Q_ASSERT_X(frustum.pointInFrustum(textPosition, true) == ViewFrustum::INSIDE,
"Avatar::calculateDisplayNameTransform", "Text not in viewfrustum.");
glm::vec3 toFrustum = frustum.getPosition() - textPosition;
// Compute orientation
glm::vec3 dPosition = frustum.getPosition() - getPosition();
// If x and z are 0, atan(x, z) is undefined, so default to 0 degrees
float yawRotation = dPosition.x == 0.0f && dPosition.z == 0.0f ? 0.0f : glm::atan(dPosition.x, dPosition.z);
// If x and z are 0, atan(x, z) adais undefined, so default to 0 degrees
const float yawRotation = (toFrustum.x == 0.0f && toFrustum.z == 0.0f) ? 0.0f : glm::atan(toFrustum.x, toFrustum.z);
glm::quat orientation = glm::quat(glm::vec3(0.0f, yawRotation, 0.0f));
// Set transform (The order IS important)
// Compute correct scale to apply
static const float DESIRED_HEIGHT_RAD = glm::radians(1.5f);
float scale = glm::length(toFrustum) * glm::tan(DESIRED_HEIGHT_RAD);
// Set transform
Transform result;
result.setTranslation(textPosition);
result.setRotation(orientation); // Always face the screen
result.postTranslate(worldOffset); // Pixel alignment
result.setScale(scale);
// raise by half the scale up so that textPosition be the bottom
result.postTranslate(Vectors::UP / 2.0f);
return result;
}
void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum, const glm::ivec4& viewport) const {
void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum, const glm::vec3& textPosition) const {
bool shouldShowReceiveStats = DependencyManager::get<AvatarManager>()->shouldShowReceiveStats() && !isMyAvatar();
// If we have nothing to draw, or it's totally transparent, or it's too close or behind the camera, return
const float CLIP_DISTANCE = 0.2f;
static const float CLIP_DISTANCE = 0.2f;
if ((_displayName.isEmpty() && !shouldShowReceiveStats) || _displayNameAlpha == 0.0f
|| (glm::dot(frustum.getDirection(), getDisplayNamePosition() - frustum.getPosition()) <= CLIP_DISTANCE)) {
return;
@ -818,39 +788,45 @@ void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum, co
}
// Compute display name extent/position offset
glm::vec2 extent = renderer->computeExtent(renderedDisplayName);
QRect nameDynamicRect = QRect(0, 0, (int)extent.x, (int)extent.y);
const int text_x = -nameDynamicRect.width() / 2;
const int text_y = -nameDynamicRect.height() / 2;
// Compute background position/size
static const float SLIGHTLY_IN_FRONT = 0.1f;
const int border = 0.1f * nameDynamicRect.height();
const int left = text_x - border;
const int bottom = text_y - border;
const int width = nameDynamicRect.width() + 2.0f * border;
const int height = nameDynamicRect.height() + 2.0f * border;
const int bevelDistance = 0.1f * height;
// Display name and background colors
glm::vec4 textColor(0.93f, 0.93f, 0.93f, _displayNameAlpha);
glm::vec4 backgroundColor(0.2f, 0.2f, 0.2f,
(_displayNameAlpha / DISPLAYNAME_ALPHA) * DISPLAYNAME_BACKGROUND_ALPHA);
// Compute display name transform
auto textTransform = calculateDisplayNameTransform(frustum, renderer->getFontSize(), viewport);
batch.setModelTransform(textTransform);
DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(batch, false, true, true, true);
DependencyManager::get<GeometryCache>()->renderBevelCornersRect(batch, left, bottom, width, height,
bevelDistance, backgroundColor);
// Render actual name
QByteArray nameUTF8 = renderedDisplayName.toLocal8Bit();
// Render text slightly in front to avoid z-fighting
textTransform.postTranslate(glm::vec3(0.0f, 0.0f, SLIGHTLY_IN_FRONT * renderer->getFontSize()));
batch.setModelTransform(textTransform);
renderer->draw(batch, text_x, -text_y, nameUTF8.data(), textColor);
const glm::vec2 extent = renderer->computeExtent(renderedDisplayName);
if (!glm::any(glm::isCompNull(extent, EPSILON))) {
const QRect nameDynamicRect = QRect(0, 0, (int)extent.x, (int)extent.y);
const int text_x = -nameDynamicRect.width() / 2;
const int text_y = -nameDynamicRect.height() / 2;
// Compute background position/size
static const float SLIGHTLY_IN_FRONT = 0.1f;
static const float BORDER_RELATIVE_SIZE = 0.1f;
static const float BEVEL_FACTOR = 0.1f;
const int border = BORDER_RELATIVE_SIZE * nameDynamicRect.height();
const int left = text_x - border;
const int bottom = text_y - border;
const int width = nameDynamicRect.width() + 2.0f * border;
const int height = nameDynamicRect.height() + 2.0f * border;
const int bevelDistance = BEVEL_FACTOR * height;
// Display name and background colors
glm::vec4 textColor(0.93f, 0.93f, 0.93f, _displayNameAlpha);
glm::vec4 backgroundColor(0.2f, 0.2f, 0.2f,
(_displayNameAlpha / DISPLAYNAME_ALPHA) * DISPLAYNAME_BACKGROUND_ALPHA);
// Compute display name transform
auto textTransform = calculateDisplayNameTransform(frustum, textPosition);
// Test on extent above insures abs(height) > 0.0f
textTransform.postScale(1.0f / height);
batch.setModelTransform(textTransform);
DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(batch, false, true, true, true);
DependencyManager::get<GeometryCache>()->renderBevelCornersRect(batch, left, bottom, width, height,
bevelDistance, backgroundColor);
// Render actual name
QByteArray nameUTF8 = renderedDisplayName.toLocal8Bit();
// Render text slightly in front to avoid z-fighting
textTransform.postTranslate(glm::vec3(0.0f, 0.0f, SLIGHTLY_IN_FRONT * renderer->getFontSize()));
batch.setModelTransform(textTransform);
renderer->draw(batch, text_x, -text_y, nameUTF8.data(), textColor);
}
}
void Avatar::setSkeletonOffset(const glm::vec3& offset) {

View file

@ -217,8 +217,8 @@ protected:
float getPelvisFloatingHeight() const;
glm::vec3 getDisplayNamePosition() const;
Transform calculateDisplayNameTransform(const ViewFrustum& frustum, float fontSize, const glm::ivec4& viewport) const;
void renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum, const glm::ivec4& viewport) const;
Transform calculateDisplayNameTransform(const ViewFrustum& frustum, const glm::vec3& textPosition) const;
void renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum, const glm::vec3& textPosition) const;
virtual void renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, float glowLevel = 0.0f);
virtual bool shouldRenderHead(const RenderArgs* renderArgs) const;
virtual void fixupModelsInScene();

View file

@ -1345,11 +1345,11 @@ void MyAvatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, fl
glm::mat4 headPose = qApp->getActiveDisplayPlugin()->getHeadPose();
glm::mat4 leftEyePose = qApp->getActiveDisplayPlugin()->getEyeToHeadTransform(Eye::Left);
leftEyePose = leftEyePose * headPose;
glm::vec3 leftEyePosition = glm::vec3(leftEyePose[3]);
glm::vec3 leftEyePosition = extractTranslation(leftEyePose);
glm::mat4 rightEyePose = qApp->getActiveDisplayPlugin()->getEyeToHeadTransform(Eye::Right);
rightEyePose = rightEyePose * headPose;
glm::vec3 rightEyePosition = glm::vec3(rightEyePose[3]);
glm::vec3 headPosition = glm::vec3(headPose[3]);
glm::vec3 rightEyePosition = extractTranslation(rightEyePose);
glm::vec3 headPosition = extractTranslation(headPose);
getHead()->renderLookAts(renderArgs,
cameraPosition + getOrientation() * (leftEyePosition - headPosition),

View file

@ -10,6 +10,7 @@
//
#include "MotionTracker.h"
#include "GLMHelpers.h"
// glm::mult(mat43, mat43) just the composition of the 2 matrices assuming they are in fact mat44 with the last raw = { 0, 0, 0, 1 }
@ -177,7 +178,7 @@ void MotionTracker::Frame::setRotation(const glm::quat& rotation) {
}
void MotionTracker::Frame::getRotation(glm::quat& rotation) const {
rotation = glm::quat_cast( _transform);
rotation = glm::quat_cast(_transform);
}
void MotionTracker::Frame::setTranslation(const glm::vec3& translation) {
@ -185,6 +186,6 @@ void MotionTracker::Frame::setTranslation(const glm::vec3& translation) {
}
void MotionTracker::Frame::getTranslation(glm::vec3& translation) const {
translation = glm::vec3(_transform[3]);
translation = extractTranslation(_transform);
}

View file

@ -63,3 +63,22 @@ bool HMDScriptingInterface::getHUDLookAtPosition3D(glm::vec3& result) const {
return compositor.calculateRayUICollisionPoint(position, direction, result);
}
glm::mat4 HMDScriptingInterface::getWorldHMDMatrix() const {
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
return myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix();
}
glm::vec3 HMDScriptingInterface::getPosition() const {
if (qApp->getActiveDisplayPlugin()->isHmd()) {
return extractTranslation(getWorldHMDMatrix());
}
return glm::vec3();
}
glm::quat HMDScriptingInterface::getOrientation() const {
if (qApp->getActiveDisplayPlugin()->isHmd()) {
return glm::normalize(glm::quat_cast(getWorldHMDMatrix()));
}
return glm::quat();
}

View file

@ -24,6 +24,8 @@ class QScriptEngine;
class HMDScriptingInterface : public AbstractHMDScriptingInterface, public Dependency {
Q_OBJECT
Q_PROPERTY(bool magnifier READ getMagnifier)
Q_PROPERTY(glm::vec3 position READ getPosition)
Q_PROPERTY(glm::quat orientation READ getOrientation)
public:
HMDScriptingInterface();
static QScriptValue getHUDLookAtPosition2D(QScriptContext* context, QScriptEngine* engine);
@ -34,7 +36,14 @@ public slots:
private:
bool getMagnifier() const;
// Get the position of the HMD
glm::vec3 getPosition() const;
// Get the orientation of the HMD
glm::quat getOrientation() const;
bool getHUDLookAtPosition3D(glm::vec3& result) const;
glm::mat4 getWorldHMDMatrix() const;
};
#endif // hifi_HMDScriptingInterface_h

View file

@ -317,8 +317,8 @@ void ApplicationCompositor::displayOverlayTextureHmd(RenderArgs* renderArgs, int
glm::mat4 overlayXfm;
_modelTransform.getMatrix(overlayXfm);
// Only render the hand pointers if the HandMouseInput is enabled
if (Menu::getInstance()->isOptionChecked(MenuOption::HandMouseInput)) {
// 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];
@ -436,7 +436,8 @@ void ApplicationCompositor::renderPointers(gpu::Batch& batch) {
_magActive[MOUSE] = _magnifier;
_reticleActive[LEFT_CONTROLLER] = false;
_reticleActive[RIGHT_CONTROLLER] = false;
} else if (qApp->getLastMouseMoveWasSimulated() && Menu::getInstance()->isOptionChecked(MenuOption::HandMouseInput)) {
} else if (qApp->getLastMouseMoveWasSimulated()
&& Menu::getInstance()->isOptionChecked(MenuOption::EnableHandMouseInput)) {
//only render controller pointer if we aren't already rendering a mouse pointer
_reticleActive[MOUSE] = false;
_magActive[MOUSE] = false;

View file

@ -200,9 +200,6 @@ void PreferencesDialog::loadPreferences() {
ui.sixenseReticleMoveSpeedSpin->setValue(InputDevice::getReticleMoveSpeed());
SixenseManager& sixense = SixenseManager::getInstance();
ui.invertSixenseButtonsCheckBox->setChecked(sixense.getInvertButtons());
// LOD items
auto lodManager = DependencyManager::get<LODManager>();
ui.desktopMinimumFPSSpin->setValue(lodManager->getDesktopLODDecreaseFPS());
@ -276,9 +273,7 @@ void PreferencesDialog::savePreferences() {
qApp->getApplicationCompositor().setHmdUIAngularSize(ui.oculusUIAngularSizeSpin->value());
SixenseManager& sixense = SixenseManager::getInstance();
InputDevice::setReticleMoveSpeed(ui.sixenseReticleMoveSpeedSpin->value());
sixense.setInvertButtons(ui.invertSixenseButtonsCheckBox->isChecked());
auto audio = DependencyManager::get<AudioClient>();
MixedProcessedAudioStream& stream = audio->getReceivedAudioStream();

View file

@ -2768,40 +2768,6 @@
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_26">
<property name="topMargin">
<number>7</number>
</property>
<property name="bottomMargin">
<number>7</number>
</property>
<item>
<widget class="QCheckBox" name="invertSixenseButtonsCheckBox">
<property name="baseSize">
<size>
<width>0</width>
<height>40</height>
</size>
</property>
<property name="font">
<font>
<family>Arial</family>
</font>
</property>
<property name="text">
<string>Invert Mouse Buttons</string>
</property>
<property name="iconSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_16">
<property name="spacing">

View file

@ -132,7 +132,6 @@ public:
bool getJointStateTranslation(int index, glm::vec3& translation) const;
void applyJointRotationDelta(int jointIndex, const glm::quat& delta, float priority);
JointState getJointState(int jointIndex) const; // XXX
bool getVisibleJointState(int index, glm::quat& rotation) const;
void clearJointState(int index);
void clearJointStates();
void clearJointAnimationPriority(int index);
@ -154,9 +153,6 @@ public:
bool getJointRotation(int jointIndex, glm::quat& rotation) const;
bool getJointTranslation(int jointIndex, glm::vec3& translation) const;
bool getJointCombinedRotation(int jointIndex, glm::quat& result, const glm::quat& rotation) const;
bool getVisibleJointPositionInWorldFrame(int jointIndex, glm::vec3& position,
glm::vec3 translation, glm::quat rotation) const;
bool getVisibleJointRotationInWorldFrame(int jointIndex, glm::quat& result, glm::quat rotation) const;
glm::mat4 getJointTransform(int jointIndex) const;
glm::mat4 getJointVisibleTransform(int jointIndex) const;
void setJointVisibleTransform(int jointIndex, glm::mat4 newTransform);
@ -179,7 +175,6 @@ public:
float priority, float mix = 1.0f);
bool getJointRotationInConstrainedFrame(int jointIndex, glm::quat& rotOut) const;
glm::quat getJointDefaultRotationInParentFrame(int jointIndex);
void updateVisibleJointStates();
void clearJointStatePriorities();
virtual void updateJointState(int index, glm::mat4 rootTransform) = 0;

View file

@ -37,3 +37,9 @@ InputPluginList getInputPlugins() {
}
return result;
}
void saveInputPluginSettings(const InputPluginList& plugins) {
foreach (auto inputPlugin, plugins) {
inputPlugin->saveSettings();
}
}

View file

@ -16,6 +16,7 @@
#include <GLMHelpers.h>
#include <NumericalConstants.h>
#include <PerfStat.h>
#include <SettingHandle.h>
#include <plugins/PluginContainer.h>
#include "NumericalConstants.h"
@ -38,7 +39,7 @@ const unsigned int RIGHT_MASK = 1U << 1;
#ifdef HAVE_SIXENSE
const int CALIBRATION_STATE_IDLE = 0;
const int CALIBRATION_STATE_X = 1;
const int CALIBRATION_STATE_IN_PROGRESS = 1;
const int CALIBRATION_STATE_COMPLETE = 2;
const glm::vec3 DEFAULT_AVATAR_POSITION(-0.25f, -0.35f, -0.3f); // in hydra frame
@ -56,25 +57,23 @@ typedef int (*SixenseTakeIntAndSixenseControllerData)(int, sixenseControllerData
#endif
const QString SixenseManager::NAME = "Sixense";
const QString SixenseManager::HYDRA_ID_STRING = "Razer Hydra";
const QString MENU_PARENT = "Avatar";
const QString MENU_NAME = "Sixense";
const QString MENU_PATH = MENU_PARENT + ">" + MENU_NAME;
const QString TOGGLE_SMOOTH = "Smooth Sixense Movement";
const float DEFAULT_REACH_LENGTH = 1.5f;
SixenseManager& SixenseManager::getInstance() {
static SixenseManager sharedInstance;
return sharedInstance;
}
SixenseManager::SixenseManager() :
InputDevice("Hydra"),
#ifdef __APPLE__
_sixenseLibrary(NULL),
#endif
_reachLength(DEFAULT_REACH_LENGTH),
_hydrasConnected(false)
{
}
bool SixenseManager::isSupported() const {
@ -92,7 +91,7 @@ void SixenseManager::activate() {
CONTAINER->addMenu(MENU_PATH);
CONTAINER->addMenuItem(MENU_PATH, TOGGLE_SMOOTH,
[this] (bool clicked) { this->setFilter(clicked); },
[this] (bool clicked) { this->setSixenseFilter(clicked); },
true, true);
#ifdef __APPLE__
@ -120,6 +119,7 @@ void SixenseManager::activate() {
SixenseBaseFunction sixenseInit = (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseInit");
#endif
loadSettings();
sixenseInit();
#endif
}
@ -144,7 +144,7 @@ void SixenseManager::deactivate() {
#endif
}
void SixenseManager::setFilter(bool filter) {
void SixenseManager::setSixenseFilter(bool filter) {
#ifdef HAVE_SIXENSE
#ifdef __APPLE__
SixenseTakeIntFunction sixenseSetFilterEnabled = (SixenseTakeIntFunction) _sixenseLibrary->resolve("sixenseSetFilterEnabled");
@ -282,6 +282,7 @@ void SixenseManager::updateCalibration(void* controllersX) {
glm::vec3 xAxis = glm::normalize(_reachRight - _reachLeft);
glm::vec3 zAxis = glm::normalize(glm::cross(xAxis, Vectors::UNIT_Y));
xAxis = glm::normalize(glm::cross(Vectors::UNIT_Y, zAxis));
_reachLength = glm::dot(xAxis, _reachRight - _reachLeft);
_avatarRotation = glm::inverse(glm::quat_cast(glm::mat3(xAxis, Vectors::UNIT_Y, zAxis)));
const float Y_OFFSET_CALIBRATED_HANDS_TO_AVATAR = -0.3f;
_avatarPosition.y += Y_OFFSET_CALIBRATED_HANDS_TO_AVATAR;
@ -317,7 +318,7 @@ void SixenseManager::updateCalibration(void* controllersX) {
_lastDistance = reach;
_lockExpiry = usecTimestampNow() + LOCK_DURATION;
// move to next state
_calibrationState = CALIBRATION_STATE_X;
_calibrationState = CALIBRATION_STATE_IN_PROGRESS;
}
return;
}
@ -327,7 +328,7 @@ void SixenseManager::updateCalibration(void* controllersX) {
_averageLeft = 0.9f * _averageLeft + 0.1f * positionLeft;
_averageRight = 0.9f * _averageRight + 0.1f * positionRight;
if (_calibrationState == CALIBRATION_STATE_X) {
if (_calibrationState == CALIBRATION_STATE_IN_PROGRESS) {
// compute new sliding average
float distance = glm::distance(_averageLeft, _averageRight);
if (fabsf(distance - _lastDistance) > MAXIMUM_NOISE_LEVEL) {
@ -340,7 +341,6 @@ void SixenseManager::updateCalibration(void* controllersX) {
// lock has expired so clamp the data and move on
_lockExpiry = now + LOCK_DURATION;
_lastDistance = 0.0f;
_reachUp = 0.5f * (_reachLeft + _reachRight);
_calibrationState = CALIBRATION_STATE_COMPLETE;
qCDebug(inputplugins, "success: sixense calibration: left");
}
@ -543,6 +543,31 @@ void SixenseManager::assignDefaultInputMapping(UserInputMapper& mapper) {
}
// virtual
void SixenseManager::saveSettings() const {
Settings settings;
QString idString = getID();
settings.beginGroup(idString);
{
settings.setVec3Value(QString("avatarPosition"), _avatarPosition);
settings.setQuatValue(QString("avatarRotation"), _avatarRotation);
settings.setValue(QString("reachLength"), QVariant(_reachLength));
}
settings.endGroup();
}
void SixenseManager::loadSettings() {
Settings settings;
QString idString = getID();
settings.beginGroup(idString);
{
settings.getVec3ValueIfValid(QString("avatarPosition"), _avatarPosition);
settings.getQuatValueIfValid(QString("avatarRotation"), _avatarRotation);
settings.getFloatValueIfValid(QString("reachLength"), _reachLength);
}
settings.endGroup();
}
UserInputMapper::Input SixenseManager::makeInput(unsigned int button, int index) {
return UserInputMapper::Input(_deviceID, button | (index == 0 ? LEFT_MASK : RIGHT_MASK), UserInputMapper::ChannelType::BUTTON);
}

View file

@ -58,12 +58,11 @@ public:
SixenseManager();
static SixenseManager& getInstance();
// Plugin functions
virtual bool isSupported() const override;
virtual bool isJointController() const override { return true; }
const QString& getName() const override { return NAME; }
const QString& getID() const override { return HYDRA_ID_STRING; }
virtual void activate() override;
virtual void deactivate() override;
@ -77,15 +76,15 @@ public:
virtual void update(float deltaTime, bool jointsCaptured) override;
virtual void focusOutEvent() override;
bool getInvertButtons() const { return _invertButtons; }
void setInvertButtons(bool invertSixenseButtons) { _invertButtons = invertSixenseButtons; }
UserInputMapper::Input makeInput(unsigned int button, int index);
UserInputMapper::Input makeInput(JoystickAxisChannel axis, int index);
UserInputMapper::Input makeInput(JointChannel joint);
virtual void saveSettings() const override;
virtual void loadSettings() override;
public slots:
void setFilter(bool filter);
void setSixenseFilter(bool filter);
private:
void handleButtonEvent(unsigned int buttons, int index);
@ -99,7 +98,7 @@ private:
// these are calibration results
glm::vec3 _avatarPosition; // in hydra-frame
glm::quat _avatarRotation; // in hydra-frame
float _armLength;
float _reachLength;
// these are measured values used to compute the calibration results
quint64 _lockExpiry;
@ -107,9 +106,8 @@ private:
glm::vec3 _averageRight;
glm::vec3 _reachLeft;
glm::vec3 _reachRight;
glm::vec3 _reachUp;
glm::vec3 _reachForward;
float _lastDistance;
bool _useSixenseFilter = true;
#ifdef __APPLE__
QLibrary* _sixenseLibrary;
@ -117,9 +115,8 @@ private:
bool _hydrasConnected;
bool _invertButtons = DEFAULT_INVERT_SIXENSE_MOUSE_BUTTONS;
static const QString NAME;
static const QString HYDRA_ID_STRING;
};
#endif // hifi_SixenseManager_h

View file

@ -241,20 +241,21 @@ ViewFrustum::location ViewFrustum::boxInKeyhole(const AABox& box) const {
return result;
}
ViewFrustum::location ViewFrustum::pointInFrustum(const glm::vec3& point) const {
ViewFrustum::location ViewFrustum::pointInFrustum(const glm::vec3& point, bool ignoreKeyhole) const {
ViewFrustum::location regularResult = INSIDE;
ViewFrustum::location keyholeResult = OUTSIDE;
// If we have a keyholeRadius, check that first, since it's cheaper
if (_keyholeRadius >= 0.0f) {
if (!ignoreKeyhole && _keyholeRadius >= 0.0f) {
keyholeResult = pointInKeyhole(point);
}
if (keyholeResult == INSIDE) {
return keyholeResult;
if (keyholeResult == INSIDE) {
return keyholeResult;
}
}
// If we're not known to be INSIDE the keyhole, then check the regular frustum
for(int i=0; i < 6; i++) {
for(int i = 0; i < 6; ++i) {
float distance = _planes[i].distance(point);
if (distance < 0) {
return keyholeResult; // escape early will be the value from checking the keyhole

View file

@ -79,7 +79,7 @@ public:
typedef enum {OUTSIDE, INTERSECT, INSIDE} location;
ViewFrustum::location pointInFrustum(const glm::vec3& point) const;
ViewFrustum::location pointInFrustum(const glm::vec3& point, bool ignoreKeyhole = false) const;
ViewFrustum::location sphereInFrustum(const glm::vec3& center, float radius) const;
ViewFrustum::location cubeInFrustum(const AACube& cube) const;
ViewFrustum::location boxInFrustum(const AABox& box) const;

View file

@ -35,9 +35,8 @@ public:
if (rayResult.m_collisionObject == _me) {
return 1.0f;
}
return ClosestRayResultCallback::addSingleResult(rayResult, normalInWorldSpace
);
}
return ClosestRayResultCallback::addSingleResult(rayResult, normalInWorldSpace);
}
protected:
btRigidBody* _me;
};

View file

@ -9,6 +9,8 @@
PluginContainer* Plugin::CONTAINER{ nullptr };
QString Plugin::UNKNOWN_PLUGIN_ID("unknown");
void Plugin::setContainer(PluginContainer* container) {
CONTAINER = container;
}

View file

@ -7,6 +7,8 @@
//
#pragma once
#include <assert.h>
#include <QString>
#include <QObject>
@ -14,7 +16,12 @@
class Plugin : public QObject {
public:
/// \return human-readable name
virtual const QString& getName() const = 0;
/// \return string ID (not necessarily human-readable)
virtual const QString& getID() const { assert(false); return UNKNOWN_PLUGIN_ID; }
virtual bool isSupported() const;
static void setContainer(PluginContainer* container);
@ -37,6 +44,11 @@ public:
*/
virtual void idle();
virtual void saveSettings() const {}
virtual void loadSettings() {}
protected:
static PluginContainer* CONTAINER;
static QString UNKNOWN_PLUGIN_ID;
};

View file

@ -8,6 +8,8 @@
#include "PluginManager.h"
#include <mutex>
#include "Forward.h"
PluginManager* PluginManager::getInstance() {
static PluginManager _manager;
return &_manager;
@ -16,6 +18,7 @@ PluginManager* PluginManager::getInstance() {
// TODO migrate to a DLL model where plugins are discovered and loaded at runtime by the PluginManager class
extern DisplayPluginList getDisplayPlugins();
extern InputPluginList getInputPlugins();
extern void saveInputPluginSettings(const InputPluginList& plugins);
const DisplayPluginList& PluginManager::getDisplayPlugins() {
static DisplayPluginList displayPlugins;
@ -35,3 +38,6 @@ const InputPluginList& PluginManager::getInputPlugins() {
return inputPlugins;
}
void PluginManager::saveSettings() {
saveInputPluginSettings(getInputPlugins());
}

View file

@ -15,4 +15,5 @@ public:
const DisplayPluginList& getDisplayPlugins();
const InputPluginList& getInputPlugins();
void saveSettings();
};

View file

@ -0,0 +1,83 @@
//
// SettingHandle.h
//
//
// Created by AndrewMeadows 2015.10.05
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "SettingHandle.h"
#include <math.h>
void Settings::getFloatValueIfValid(const QString& name, float& floatValue) {
const QVariant badDefaultValue = NAN;
bool ok = true;
float tempFloat = value(name, badDefaultValue).toFloat(&ok);
if (ok && !isnan(tempFloat)) {
floatValue = tempFloat;
}
}
void Settings::getBoolValue(const QString& name, bool& boolValue) {
const QVariant defaultValue = false;
boolValue = value(name, defaultValue).toBool();
}
void Settings::setVec3Value(const QString& name, const glm::vec3& vecValue) {
beginGroup(name);
{
setValue(QString("x"), vecValue.x);
setValue(QString("y"), vecValue.y);
setValue(QString("z"), vecValue.z);
}
endGroup();
}
void Settings::getVec3ValueIfValid(const QString& name, glm::vec3& vecValue) {
beginGroup(name);
{
bool ok = true;
const QVariant badDefaultValue = NAN;
float x = value(QString("x"), badDefaultValue).toFloat(&ok);
float y = value(QString("y"), badDefaultValue).toFloat(&ok);
float z = value(QString("z"), badDefaultValue).toFloat(&ok);
if (ok && (!isnan(x) && !isnan(y) && !isnan(z))) {
vecValue = glm::vec3(x, y, z);
}
}
endGroup();
}
void Settings::setQuatValue(const QString& name, const glm::quat& quatValue) {
beginGroup(name);
{
setValue(QString("x"), quatValue.x);
setValue(QString("y"), quatValue.y);
setValue(QString("z"), quatValue.z);
setValue(QString("w"), quatValue.w);
}
endGroup();
}
void Settings::getQuatValueIfValid(const QString& name, glm::quat& quatValue) {
beginGroup(name);
{
bool ok = true;
const QVariant badDefaultValue = NAN;
float x = value(QString("x"), badDefaultValue).toFloat(&ok);
float y = value(QString("y"), badDefaultValue).toFloat(&ok);
float z = value(QString("z"), badDefaultValue).toFloat(&ok);
float w = value(QString("w"), badDefaultValue).toFloat(&ok);
if (ok && (!isnan(x) && !isnan(y) && !isnan(z) && !isnan(w))) {
quatValue = glm::quat(w, x, y, z);
}
}
endGroup();
}

View file

@ -18,11 +18,22 @@
#include <QString>
#include <QVariant>
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
#include "SettingInterface.h"
// TODO: remove
class Settings : public QSettings {
public:
void getFloatValueIfValid(const QString& name, float& floatValue);
void getBoolValue(const QString& name, bool& boolValue);
void setVec3Value(const QString& name, const glm::vec3& vecValue);
void getVec3ValueIfValid(const QString& name, glm::vec3& vecValue);
void setQuatValue(const QString& name, const glm::quat& quatValue);
void getQuatValueIfValid(const QString& name, glm::quat& quatValue);
};
namespace Setting {
@ -65,4 +76,4 @@ namespace Setting {
}
}
#endif // hifi_SettingHandle_h
#endif // hifi_SettingHandle_h

View file

@ -13,8 +13,7 @@
#include <assert.h>
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
#include "GLMHelpers.h"
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/quaternion.hpp>
@ -419,7 +418,7 @@ inline Transform::Mat4& Transform::getRotationScaleMatrixInverse(Mat4& result) c
inline Transform& Transform::evalFromRawMatrix(const Mat4& matrix) {
// for now works only in the case of TRS transformation
if ((matrix[0][3] == 0.0f) && (matrix[1][3] == 0.0f) && (matrix[2][3] == 0.0f) && (matrix[3][3] == 1.0f)) {
setTranslation(Vec3(matrix[3]));
setTranslation(extractTranslation(matrix));
evalFromRawMatrix(Mat3(matrix));
}
return *this;