Merge branch 'master' of https://github.com/highfidelity/hifi into spectator-camera

This commit is contained in:
Zach Fox 2017-07-05 09:59:57 -07:00
commit 44cb48b17d
9 changed files with 244 additions and 76 deletions

View file

@ -56,19 +56,17 @@ elseif (${CMAKE_CXX_COMPILER_ID} MATCHES "GNU")
endif()
function(_fbx_find_library _name _lib _suffix)
if (MSVC12)
if (MSVC_VERSION EQUAL 1910)
set(VS_PREFIX vs2017)
elseif (MSVC_VERSION EQUAL 1900)
set(VS_PREFIX vs2015)
elseif (MSVC_VERSION EQUAL 1800)
set(VS_PREFIX vs2013)
endif()
if (MSVC11)
elseif (MSVC_VERSION EQUAL 1700)
set(VS_PREFIX vs2012)
endif()
if (MSVC10)
elseif (MSVC_VERSION EQUAL 1600)
set(VS_PREFIX vs2010)
endif()
if (MSVC90)
elseif (MSVC_VERSION EQUAL 1500)
set(VS_PREFIX vs2008)
endif()

View file

@ -25,11 +25,12 @@ Rectangle {
signal canceled()
signal restart()
property int count: 3
property int count: 5
property string calibratingText: "CALIBRATING..."
property string calibratingCountText: "CALIBRATION STARTING IN"
property string calibrationSuccess: "CALIBRATION COMPLETED"
property string calibrationFailed: "CALIBRATION FAILED"
property string instructionText: "Please stand in a T-Pose during calibration"
HifiConstants { id: hifi }
visible: true
@ -158,6 +159,15 @@ Rectangle {
onClicked: {
restart();
statusText.color = hifi.colors.blueHighlight;
statusText.text = info.calibratingCountText;
directions.text = instructionText;
countDown.visible = true;
busyIndicator.running = true;
busyRotation.from = 0
busyRotation.to = 360
busyIndicator.source = blueIndicator;
closeWindow.stop();
numberAnimation.stop();
info.count = (timer.interval / 1000);
numberAnimation.start();
@ -178,6 +188,7 @@ Rectangle {
}
}
function start(interval, countNumber) {
countDown.visible = true;
statusText.color = hifi.colors.blueHighlight;
@ -201,6 +212,7 @@ Rectangle {
busyIndicator.running = false;
statusText.text = info.calibrationSuccess
statusText.color = hifi.colors.greenHighlight
directions.text = "SUCCESS"
closeWindow.start();
}

View file

@ -458,7 +458,7 @@ Rectangle {
width: glyphButton.width + calibrationText.width + padding
height: hifi.dimensions.controlLineHeight
anchors.top: bottomSeperator.bottom
anchors.topMargin: 10
anchors.topMargin: 15
anchors.left: parent.left
anchors.leftMargin: leftMargin
@ -590,16 +590,24 @@ Rectangle {
lastConfiguration = composeConfigurationSettings();
}
Component.onDestruction: {
var settings = InputConfiguration.configurationSettings(pluginName);
var data = {
"num_pucks": settings["puckCount"]
}
UserActivityLogger.logAction("mocap_ui_close_dialog", data);
}
HifiControls.SpinBox {
id: timeToCalibrate
width: 70
anchors.top: calibrationButton.bottom
anchors.topMargin: 40
anchors.topMargin: 20
anchors.left: parent.left
anchors.leftMargin: leftMargin
minimumValue: 3
value: 3
minimumValue: 5
value: 5
colorScheme: hifi.colorSchemes.dark
onEditingFinished: {
@ -641,17 +649,39 @@ Rectangle {
to: 0
}
function logAction(action, status) {
console.log("calibrated from ui");
var data = {
"num_pucks": status["puckCount"],
"puck_configuration": status["configuration"],
"head_puck": status["head_puck"],
"hand_puck": status["hand_pucks"]
}
UserActivityLogger.logAction(action, data);
}
function calibrationStatusInfo(status) {
var calibrationScreen = stack.currentItem;
if (!status["UI"]) {
calibratingScreen = screen.createObject();
stack.push(calibratingScreen);
}
if (status["calibrated"]) {
calibrationScreen.success();
if (status["UI"]) {
logAction("mocap_ui_success", status);
}
} else if (!status["calibrated"]) {
var uncalibrated = status["success"];
if (!uncalibrated) {
calibrationScreen.failure();
calibrationScreen.failure();
if (status["UI"]) {
logAction("mocap_ui_failed", status);
}
}
updateCalibrationButton();
}
@ -717,6 +747,12 @@ Rectangle {
initializeButtonState();
updateCalibrationText();
var data = {
"num_pucks": settings["puckCount"]
};
UserActivityLogger.logAction("mocap_ui_open_dialog", data);
}
function displayTrackerConfiguration(type) {

View file

@ -40,19 +40,23 @@
Q_LOGGING_CATEGORY(trace_render_overlays, "trace.render.overlays")
void Overlays::cleanupAllOverlays() {
QMap<OverlayID, Overlay::Pointer> overlaysHUD;
QMap<OverlayID, Overlay::Pointer> overlaysWorld;
{
foreach(Overlay::Pointer overlay, _overlaysHUD) {
_overlaysToDelete.push_back(overlay);
}
foreach(Overlay::Pointer overlay, _overlaysWorld) {
_overlaysToDelete.push_back(overlay);
}
_overlaysHUD.clear();
_overlaysWorld.clear();
#if OVERLAY_PANELS
_panels.clear();
#endif
QMutexLocker locker(&_mutex);
overlaysHUD.swap(_overlaysHUD);
overlaysWorld.swap(_overlaysWorld);
}
foreach(Overlay::Pointer overlay, overlaysHUD) {
_overlaysToDelete.push_back(overlay);
}
foreach(Overlay::Pointer overlay, overlaysWorld) {
_overlaysToDelete.push_back(overlay);
}
#if OVERLAY_PANELS
_panels.clear();
#endif
cleanupOverlaysToDelete();
}
@ -63,14 +67,19 @@ void Overlays::init() {
}
void Overlays::update(float deltatime) {
QMap<OverlayID, Overlay::Pointer> overlaysHUD;
QMap<OverlayID, Overlay::Pointer> overlaysWorld;
{
foreach(Overlay::Pointer thisOverlay, _overlaysHUD) {
thisOverlay->update(deltatime);
}
foreach(Overlay::Pointer thisOverlay, _overlaysWorld) {
thisOverlay->update(deltatime);
}
QMutexLocker locker(&_mutex);
overlaysHUD = _overlaysHUD;
overlaysWorld = _overlaysWorld;
}
foreach(const auto& thisOverlay, overlaysHUD) {
thisOverlay->update(deltatime);
}
foreach(const auto& thisOverlay, overlaysWorld) {
thisOverlay->update(deltatime);
}
cleanupOverlaysToDelete();
@ -110,8 +119,14 @@ void Overlays::renderHUD(RenderArgs* renderArgs) {
int height = size.y;
mat4 legacyProjection = glm::ortho<float>(0, width, height, 0, -1000, 1000);
QMap<OverlayID, Overlay::Pointer> overlaysHUD;
{
QMutexLocker locker(&_mutex);
overlaysHUD = _overlaysHUD;
}
foreach(Overlay::Pointer thisOverlay, _overlaysHUD) {
foreach(Overlay::Pointer thisOverlay, overlaysHUD) {
// Reset all batch pipeline settings between overlay
geometryCache->useSimpleDrawPipeline(batch);
@ -132,7 +147,10 @@ void Overlays::enable() {
_enabled = true;
}
// Note, can't be invoked by scripts, but can be called by the InterfaceParentFinder
// class on packet processing threads
Overlay::Pointer Overlays::getOverlay(OverlayID id) const {
QMutexLocker locker(&_mutex);
if (_overlaysHUD.contains(id)) {
return _overlaysHUD[id];
}
@ -193,13 +211,17 @@ OverlayID Overlays::addOverlay(const Overlay::Pointer& overlay) {
overlay->setOverlayID(thisID);
overlay->setStackOrder(_stackOrder++);
if (overlay->is3D()) {
_overlaysWorld[thisID] = overlay;
{
QMutexLocker locker(&_mutex);
_overlaysWorld[thisID] = overlay;
}
render::ScenePointer scene = qApp->getMain3DScene();
render::Transaction transaction;
overlay->addToScene(overlay, scene, transaction);
scene->enqueueTransaction(transaction);
} else {
QMutexLocker locker(&_mutex);
_overlaysHUD[thisID] = overlay;
}
@ -231,9 +253,12 @@ OverlayID Overlays::cloneOverlay(OverlayID id) {
bool Overlays::editOverlay(OverlayID id, const QVariant& properties) {
if (QThread::currentThread() != thread()) {
bool result;
BLOCKING_INVOKE_METHOD(this, "editOverlay", Q_RETURN_ARG(bool, result), Q_ARG(OverlayID, id), Q_ARG(QVariant, properties));
return result;
// NOTE editOverlay can be called very frequently in scripts and can't afford to
// block waiting on the main thread. Additionally, no script actually
// examines the return value and does something useful with it, so use a non-blocking
// invoke and just always return true
QMetaObject::invokeMethod(this, "editOverlay", Q_ARG(OverlayID, id), Q_ARG(QVariant, properties));
return true;
}
Overlay::Pointer thisOverlay = getOverlay(id);
@ -246,9 +271,9 @@ bool Overlays::editOverlay(OverlayID id, const QVariant& properties) {
bool Overlays::editOverlays(const QVariant& propertiesById) {
if (QThread::currentThread() != thread()) {
bool result;
BLOCKING_INVOKE_METHOD(this, "editOverlays", Q_RETURN_ARG(bool, result), Q_ARG(QVariant, propertiesById));
return result;
// NOTE see comment on editOverlay for why this is not a blocking call
QMetaObject::invokeMethod(this, "editOverlays", Q_ARG(QVariant, propertiesById));
return true;
}
QVariantMap map = propertiesById.toMap();
@ -275,6 +300,7 @@ void Overlays::deleteOverlay(OverlayID id) {
Overlay::Pointer overlayToDelete;
{
QMutexLocker locker(&_mutex);
if (_overlaysHUD.contains(id)) {
overlayToDelete = _overlaysHUD.take(id);
} else if (_overlaysWorld.contains(id)) {
@ -378,7 +404,13 @@ OverlayID Overlays::getOverlayAtPoint(const glm::vec2& point) {
if (!_enabled) {
return UNKNOWN_OVERLAY_ID;
}
QMapIterator<OverlayID, Overlay::Pointer> i(_overlaysHUD);
QMap<OverlayID, Overlay::Pointer> overlaysHUD;
{
QMutexLocker locker(&_mutex);
overlaysHUD = _overlaysHUD;
}
QMapIterator<OverlayID, Overlay::Pointer> i(overlaysHUD);
const float LARGE_NEGATIVE_FLOAT = -9999999;
glm::vec3 origin(pointCopy.x, pointCopy.y, LARGE_NEGATIVE_FLOAT);
@ -466,8 +498,14 @@ RayToOverlayIntersectionResult Overlays::findRayIntersectionInternal(const PickR
float bestDistance = std::numeric_limits<float>::max();
bool bestIsFront = false;
QMap<OverlayID, Overlay::Pointer> overlaysWorld;
{
QMutexLocker locker(&_mutex);
overlaysWorld = _overlaysWorld;
}
RayToOverlayIntersectionResult result;
QMapIterator<OverlayID, Overlay::Pointer> i(_overlaysWorld);
QMapIterator<OverlayID, Overlay::Pointer> i(overlaysWorld);
while (i.hasNext()) {
i.next();
OverlayID thisID = i.key();
@ -598,13 +636,20 @@ QSizeF Overlays::textSize(OverlayID id, const QString& text) {
return result;
}
Overlay::Pointer thisOverlay = _overlaysHUD[id];
Overlay::Pointer thisOverlay;
{
QMutexLocker locker(&_mutex);
thisOverlay = _overlaysHUD[id];
}
if (thisOverlay) {
if (auto textOverlay = std::dynamic_pointer_cast<TextOverlay>(thisOverlay)) {
return textOverlay->textSize(text);
}
} else {
thisOverlay = _overlaysWorld[id];
{
QMutexLocker locker(&_mutex);
thisOverlay = _overlaysWorld[id];
}
if (auto text3dOverlay = std::dynamic_pointer_cast<Text3DOverlay>(thisOverlay)) {
return text3dOverlay->textSize(text);
}
@ -675,6 +720,7 @@ bool Overlays::isAddedOverlay(OverlayID id) {
return result;
}
QMutexLocker locker(&_mutex);
return _overlaysHUD.contains(id) || _overlaysWorld.contains(id);
}
@ -949,8 +995,13 @@ QVector<QUuid> Overlays::findOverlays(const glm::vec3& center, float radius) {
return result;
}
QMap<OverlayID, Overlay::Pointer> overlaysWorld;
{
QMutexLocker locker(&_mutex);
overlaysWorld = _overlaysWorld;
}
QMapIterator<OverlayID, Overlay::Pointer> i(_overlaysWorld);
QMapIterator<OverlayID, Overlay::Pointer> i(overlaysWorld);
int checked = 0;
while (i.hasNext()) {
checked++;

View file

@ -319,6 +319,7 @@ signals:
private:
void cleanupOverlaysToDelete();
mutable QMutex _mutex;
QMap<OverlayID, Overlay::Pointer> _overlaysHUD;
QMap<OverlayID, Overlay::Pointer> _overlaysWorld;
#if OVERLAY_PANELS

View file

@ -249,6 +249,7 @@ ViveControllerManager::InputDevice::InputDevice(vr::IVRSystem*& system) : contro
_configStringMap[Config::FeetAndHips] = QString("FeetAndHips");
_configStringMap[Config::FeetHipsAndChest] = QString("FeetHipsAndChest");
_configStringMap[Config::FeetHipsAndShoulders] = QString("FeetHipsAndShoulders");
_configStringMap[Config::FeetHipsChestAndShoulders] = QString("FeetHipsChestAndShoulders");
}
void ViveControllerManager::InputDevice::update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) {
@ -325,6 +326,7 @@ void ViveControllerManager::InputDevice::calibrateFromUI(const controller::Input
if (_calibrate) {
uncalibrate();
calibrate(inputCalibrationData);
emitCalibrationStatus();
_calibrate = false;
}
}
@ -372,29 +374,23 @@ QJsonObject ViveControllerManager::InputDevice::configurationSettings() {
Locker locker(_lock);
QJsonObject configurationSettings;
configurationSettings["trackerConfiguration"] = configToString(_preferedConfig);
configurationSettings["HMDHead"] = (_headConfig == HeadConfig::HMD) ? true : false;
configurationSettings["handController"] = (_handConfig == HandConfig::HandController) ? true : false;
configurationSettings["HMDHead"] = (_headConfig == HeadConfig::HMD);
configurationSettings["handController"] = (_handConfig == HandConfig::HandController);
configurationSettings["puckCount"] = (int)_validTrackedObjects.size();
return configurationSettings;
}
void ViveControllerManager::InputDevice::emitCalibrationStatus(const bool success) {
void ViveControllerManager::InputDevice::emitCalibrationStatus() {
auto inputConfiguration = DependencyManager::get<InputConfiguration>();
QJsonObject status = QJsonObject();
if (_calibrated && success) {
status["calibrated"] = _calibrated;
status["configuration"] = configToString(_preferedConfig);
} else if (!_calibrated && !success) {
status["calibrated"] = _calibrated;
status["success"] = success;
} else if (!_calibrated && success) {
status["calibrated"] = _calibrated;
status["success"] = success;
status["configuration"] = configToString(_preferedConfig);
status["puckCount"] = (int)_validTrackedObjects.size();
}
status["calibrated"] = _calibrated;
status["configuration"] = configToString(_preferedConfig);
status["head_puck"] = (_headConfig == HeadConfig::Puck);
status["hand_pucks"] = (_handConfig == HandConfig::Pucks);
status["puckCount"] = (int)_validTrackedObjects.size();
status["UI"] = _calibrate;
emit inputConfiguration->calibrationStatus(status); //inputConfiguration->calibrated(status);
emit inputConfiguration->calibrationStatus(status);
}
void ViveControllerManager::InputDevice::handleTrackedObject(uint32_t deviceIndex, const controller::InputCalibrationData& inputCalibrationData) {
@ -437,12 +433,29 @@ void ViveControllerManager::InputDevice::handleTrackedObject(uint32_t deviceInde
}
}
void ViveControllerManager::InputDevice::sendUserActivityData(QString activity) {
QJsonObject jsonData = {
{"num_pucks", (int)_validTrackedObjects.size()},
{"configuration", configToString(_preferedConfig)},
{"head_puck", (_headConfig == HeadConfig::Puck) ? true : false},
{"hand_pucks", (_handConfig == HandConfig::Pucks) ? true : false}
};
UserActivityLogger::getInstance().logAction(activity, jsonData);
}
void ViveControllerManager::InputDevice::calibrateOrUncalibrate(const controller::InputCalibrationData& inputCalibration) {
if (!_calibrated) {
calibrate(inputCalibration);
if (_calibrated) {
sendUserActivityData("mocap_button_success");
} else {
sendUserActivityData("mocap_button_fail");
}
emitCalibrationStatus();
} else {
uncalibrate();
emitCalibrationStatus(true);
sendUserActivityData("mocap_button_uncalibrate");
}
}
@ -454,7 +467,6 @@ void ViveControllerManager::InputDevice::calibrate(const controller::InputCalibr
if (puckCount == 0) {
uncalibrate();
emitCalibrationStatus(false);
return;
}
@ -473,10 +485,8 @@ void ViveControllerManager::InputDevice::calibrate(const controller::InputCalibr
if (!headConfigured || !handsConfigured || !bodyConfigured) {
uncalibrate();
emitCalibrationStatus(false);
} else {
_calibrated = true;
emitCalibrationStatus(true);
qDebug() << "PuckCalibration: " << configToString(_config) << " Configuration Successful";
}
}
@ -566,8 +576,6 @@ bool ViveControllerManager::InputDevice::configureBody(glm::mat4& defaultToRefer
return true;
}
qDebug() << "Puck Calibration: " << configToString(_config) << " Config Failed: Could not meet the minimal # of pucks";
uncalibrate();
emitCalibrationStatus(false);
return false;
}

View file

@ -73,6 +73,7 @@ private:
void calibrateOrUncalibrate(const controller::InputCalibrationData& inputCalibration);
void calibrate(const controller::InputCalibrationData& inputCalibration);
void uncalibrate();
void sendUserActivityData(QString activity);
void configureCalibrationSettings(const QJsonObject configurationSettings);
QJsonObject configurationSettings();
controller::Pose addOffsetToPuckPose(int joint) const;
@ -106,7 +107,7 @@ private:
void calibrateHead(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration);
void calibrateFromHandController(const controller::InputCalibrationData& inputCalibrationData);
void calibrateFromUI(const controller::InputCalibrationData& inputCalibrationData);
void emitCalibrationStatus(const bool success);
void emitCalibrationStatus();
void calibrateNextFrame();
@ -139,7 +140,7 @@ private:
FeetAndHips,
FeetHipsAndChest,
FeetHipsAndShoulders,
FeetHipsChestAndShoulders,
FeetHipsChestAndShoulders
};
enum class HeadConfig {

View file

@ -61,7 +61,9 @@ Oven::Oven(int argc, char* argv[]) :
if (parser.isSet(CLI_INPUT_PARAMETER) || parser.isSet(CLI_OUTPUT_PARAMETER)) {
if (parser.isSet(CLI_INPUT_PARAMETER) && parser.isSet(CLI_OUTPUT_PARAMETER)) {
BakerCLI* cli = new BakerCLI(this);
cli->bakeFile(parser.value(CLI_INPUT_PARAMETER), parser.value(CLI_OUTPUT_PARAMETER));
QUrl inputUrl(QDir::fromNativeSeparators(parser.value(CLI_INPUT_PARAMETER)));
QUrl outputUrl(QDir::fromNativeSeparators(parser.value(CLI_OUTPUT_PARAMETER)));
cli->bakeFile(inputUrl, outputUrl.toString());
} else {
parser.showHelp();
QApplication::quit();

View file

@ -0,0 +1,59 @@
"use strict";
/*
rockethands.js
unpublishedScripts/marketplace/rocketHands/rockethands.js
Created by Cain Kilgore on 30/06/2017
Copyright 2017 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
*/
(function() {
var isRocketing = false;
function checkRocketing() {
if (HMD.active && (Controller.Hardware.Vive || Controller.Hardware.OculusTouch) && canRocket()) {
isRocketing = true;
MyAvatar.motorReferenceFrame = "world";
var moveVector = Vec3.multiply(Quat.getFront(Camera.getOrientation()), 10);
if (!MyAvatar.isFlying()) {
moveVector = Vec3.sum(moveVector, {x: 0, y: 1, z: 0});
}
MyAvatar.motorVelocity = moveVector;
MyAvatar.motorTimescale = 1.0;
} else {
checkCanStopRocketing();
}
};
function checkCanStopRocketing() {
if (isRocketing) {
MyAvatar.motorVelocity = 0;
isRocketing = false;
}
}
function canRocket() {
var leftHand = Controller.getPoseValue(Controller.Standard.LeftHand);
var rightHand = Controller.getPoseValue(Controller.Standard.RightHand);
var leftWorldControllerPos = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, leftHand.translation));
var rightWorldControllerPos = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, rightHand.translation));
var hipPosition = MyAvatar.getJointPosition("Hips");
var controllerHipThreshold = 0.1; // In Meters. Experimentally determined. Used to figure out if user's hands are "close enough" to their hips.
var controllerRotationThreshold = 0.25; // In Radians. Experimentally determined. Used to figure out if user's hands are within a rotation threshold.
return ((leftWorldControllerPos.y > (hipPosition.y - controllerHipThreshold)) &&
(leftWorldControllerPos.y < (hipPosition.y + controllerHipThreshold)) &&
(rightWorldControllerPos.y > (hipPosition.y - controllerHipThreshold)) &&
(rightWorldControllerPos.y < (hipPosition.y + controllerHipThreshold)) &&
leftHand.rotation.y < controllerRotationThreshold &&
leftHand.rotation.y > -controllerRotationThreshold &&
rightHand.rotation.y < controllerRotationThreshold &&
rightHand.rotation.y > -controllerRotationThreshold);
}
Script.update.connect(checkRocketing);
}());