mirror of
https://github.com/AleziaKurdis/overte.git
synced 2025-08-20 12:47:00 +02:00
Merge branch 'master' of github.com:highfidelity/hifi into set-model-entity-joints
This commit is contained in:
commit
b59934573a
20 changed files with 269 additions and 111 deletions
|
@ -1257,16 +1257,39 @@ function MyController(hand) {
|
|||
this.handleSpotlight(this.grabbedEntity);
|
||||
}
|
||||
|
||||
Entities.updateAction(this.grabbedEntity, this.actionID, {
|
||||
var success = Entities.updateAction(this.grabbedEntity, this.actionID, {
|
||||
targetPosition: targetPosition,
|
||||
linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME,
|
||||
targetRotation: this.currentObjectRotation,
|
||||
angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME,
|
||||
ttl: ACTION_TTL
|
||||
});
|
||||
if (success) {
|
||||
this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC);
|
||||
} else {
|
||||
print("continueDistanceHolding -- updateAction failed");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
this.setupHoldAction = function() {
|
||||
this.actionID = Entities.addAction("hold", this.grabbedEntity, {
|
||||
hand: this.hand === RIGHT_HAND ? "right" : "left",
|
||||
timeScale: NEAR_GRABBING_ACTION_TIMEFRAME,
|
||||
relativePosition: this.offsetPosition,
|
||||
relativeRotation: this.offsetRotation,
|
||||
ttl: ACTION_TTL,
|
||||
kinematic: NEAR_GRABBING_KINEMATIC,
|
||||
kinematicSetVelocity: true,
|
||||
ignoreIK: this.ignoreIK
|
||||
});
|
||||
if (this.actionID === NULL_ACTION_ID) {
|
||||
this.actionID = null;
|
||||
return false;
|
||||
}
|
||||
var now = Date.now();
|
||||
this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
this.projectVectorAlongAxis = function(position, axisStart, axisEnd) {
|
||||
|
@ -1296,7 +1319,7 @@ function MyController(hand) {
|
|||
|
||||
return projection
|
||||
|
||||
},
|
||||
};
|
||||
|
||||
this.nearGrabbing = function() {
|
||||
var now = Date.now();
|
||||
|
@ -1340,43 +1363,29 @@ function MyController(hand) {
|
|||
this.offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, this.offsetRotation)), offset);
|
||||
}
|
||||
|
||||
this.actionID = NULL_ACTION_ID;
|
||||
this.actionID = Entities.addAction("hold", this.grabbedEntity, {
|
||||
hand: this.hand === RIGHT_HAND ? "right" : "left",
|
||||
timeScale: NEAR_GRABBING_ACTION_TIMEFRAME,
|
||||
relativePosition: this.offsetPosition,
|
||||
relativeRotation: this.offsetRotation,
|
||||
ttl: ACTION_TTL,
|
||||
kinematic: NEAR_GRABBING_KINEMATIC,
|
||||
kinematicSetVelocity: true,
|
||||
ignoreIK: this.ignoreIK
|
||||
});
|
||||
if (this.actionID === NULL_ACTION_ID) {
|
||||
this.actionID = null;
|
||||
} else {
|
||||
this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC);
|
||||
if (this.state == STATE_NEAR_GRABBING) {
|
||||
this.setState(STATE_CONTINUE_NEAR_GRABBING);
|
||||
} else {
|
||||
// equipping
|
||||
Entities.callEntityMethod(this.grabbedEntity, "startEquip", [JSON.stringify(this.hand)]);
|
||||
this.startHandGrasp();
|
||||
|
||||
this.setState(STATE_CONTINUE_EQUIP_BD);
|
||||
}
|
||||
|
||||
if (this.hand === RIGHT_HAND) {
|
||||
Entities.callEntityMethod(this.grabbedEntity, "setRightHand");
|
||||
} else {
|
||||
Entities.callEntityMethod(this.grabbedEntity, "setLeftHand");
|
||||
}
|
||||
|
||||
Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]);
|
||||
|
||||
Entities.callEntityMethod(this.grabbedEntity, "startNearGrab");
|
||||
|
||||
if (!this.setupHoldAction()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.state == STATE_NEAR_GRABBING) {
|
||||
this.setState(STATE_CONTINUE_NEAR_GRABBING);
|
||||
} else {
|
||||
// equipping
|
||||
Entities.callEntityMethod(this.grabbedEntity, "startEquip", [JSON.stringify(this.hand)]);
|
||||
this.startHandGrasp();
|
||||
|
||||
this.setState(STATE_CONTINUE_EQUIP_BD);
|
||||
}
|
||||
|
||||
if (this.hand === RIGHT_HAND) {
|
||||
Entities.callEntityMethod(this.grabbedEntity, "setRightHand");
|
||||
} else {
|
||||
Entities.callEntityMethod(this.grabbedEntity, "setLeftHand");
|
||||
}
|
||||
|
||||
Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]);
|
||||
Entities.callEntityMethod(this.grabbedEntity, "startNearGrab");
|
||||
|
||||
this.currentHandControllerTipPosition =
|
||||
(this.hand === RIGHT_HAND) ? MyAvatar.rightHandTipPosition : MyAvatar.leftHandTipPosition;
|
||||
|
||||
|
@ -1426,7 +1435,7 @@ function MyController(hand) {
|
|||
|
||||
if (this.actionTimeout - now < ACTION_TTL_REFRESH * MSEC_PER_SEC) {
|
||||
// if less than a 5 seconds left, refresh the actions ttl
|
||||
Entities.updateAction(this.grabbedEntity, this.actionID, {
|
||||
var success = Entities.updateAction(this.grabbedEntity, this.actionID, {
|
||||
hand: this.hand === RIGHT_HAND ? "right" : "left",
|
||||
timeScale: NEAR_GRABBING_ACTION_TIMEFRAME,
|
||||
relativePosition: this.offsetPosition,
|
||||
|
@ -1436,7 +1445,13 @@ function MyController(hand) {
|
|||
kinematicSetVelocity: true,
|
||||
ignoreIK: this.ignoreIK
|
||||
});
|
||||
this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC);
|
||||
if (success) {
|
||||
this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC);
|
||||
} else {
|
||||
print("continueNearGrabbing -- updateAction failed");
|
||||
Entities.deleteAction(this.grabbedEntity, this.actionID);
|
||||
this.setupHoldAction();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1483,7 +1498,7 @@ function MyController(hand) {
|
|||
return;
|
||||
}
|
||||
} else {
|
||||
Entities.updateAction(this.grabbedEntity, this.equipSpringID, {
|
||||
var success = Entities.updateAction(this.grabbedEntity, this.equipSpringID, {
|
||||
targetPosition: targetPosition,
|
||||
linearTimeScale: EQUIP_SPRING_TIMEFRAME,
|
||||
targetRotation: targetRotation,
|
||||
|
@ -1491,6 +1506,9 @@ function MyController(hand) {
|
|||
ttl: ACTION_TTL,
|
||||
ignoreIK: ignoreIK
|
||||
});
|
||||
if (!success) {
|
||||
print("pullTowardEquipPosition -- updateActionfailed");
|
||||
}
|
||||
}
|
||||
|
||||
if (Vec3.distance(grabbedProperties.position, targetPosition) < EQUIP_SPRING_SHUTOFF_DISTANCE) {
|
||||
|
@ -1896,4 +1914,4 @@ function renewParticleBeamLifetimes(deltaTime) {
|
|||
}
|
||||
rightController.renewParticleBeamLifetime();
|
||||
leftController.renewParticleBeamLifetime();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -88,6 +88,7 @@
|
|||
#include <ObjectMotionState.h>
|
||||
#include <OctalCode.h>
|
||||
#include <OctreeSceneStats.h>
|
||||
#include <OffscreenUi.h>
|
||||
#include <gl/OffscreenGLCanvas.h>
|
||||
#include <PathUtils.h>
|
||||
#include <PerfStat.h>
|
||||
|
@ -4380,7 +4381,7 @@ bool Application::askToSetAvatarUrl(const QString& url) {
|
|||
bool Application::askToLoadScript(const QString& scriptFilenameOrURL) {
|
||||
QMessageBox::StandardButton reply;
|
||||
QString message = "Would you like to run this script:\n" + scriptFilenameOrURL;
|
||||
reply = QMessageBox::question(getWindow(), "Run Script", message, QMessageBox::Yes|QMessageBox::No);
|
||||
reply = OffscreenUi::question(getWindow(), "Run Script", message, QMessageBox::Yes | QMessageBox::No);
|
||||
|
||||
if (reply == QMessageBox::Yes) {
|
||||
qCDebug(interfaceapp) << "Chose to run the script: " << scriptFilenameOrURL;
|
||||
|
@ -4393,7 +4394,7 @@ bool Application::askToLoadScript(const QString& scriptFilenameOrURL) {
|
|||
|
||||
bool Application::askToUploadAsset(const QString& filename) {
|
||||
if (!DependencyManager::get<NodeList>()->getThisNodeCanRez()) {
|
||||
QMessageBox::warning(_window, "Failed Upload",
|
||||
OffscreenUi::warning(_window, "Failed Upload",
|
||||
QString("You don't have upload rights on that domain.\n\n"));
|
||||
return false;
|
||||
}
|
||||
|
@ -4437,7 +4438,7 @@ bool Application::askToUploadAsset(const QString& filename) {
|
|||
}
|
||||
|
||||
// display a message box with the error
|
||||
QMessageBox::warning(_window, "Failed Upload", QString("Failed to upload %1.\n\n").arg(filename));
|
||||
OffscreenUi::warning(_window, "Failed Upload", QString("Failed to upload %1.\n\n").arg(filename));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -4628,7 +4629,7 @@ void Application::handleScriptEngineLoaded(const QString& scriptFilename) {
|
|||
// FIXME - change to new version of ScriptCache loading notification
|
||||
void Application::handleScriptLoadError(const QString& scriptFilename) {
|
||||
qCDebug(interfaceapp) << "Application::loadScript(), script failed to load...";
|
||||
QMessageBox::warning(getWindow(), "Error Loading Script", scriptFilename + " failed to load.");
|
||||
OffscreenUi::warning(getWindow(), "Error Loading Script", scriptFilename + " failed to load.");
|
||||
}
|
||||
|
||||
QStringList Application::getRunningScripts() {
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <QTemporaryDir>
|
||||
|
||||
#include <FSTReader.h>
|
||||
#include <OffscreenUi.h>
|
||||
|
||||
#include "ModelSelector.h"
|
||||
#include "ModelPropertiesDialog.h"
|
||||
|
@ -78,7 +79,7 @@ bool ModelPackager::loadModel() {
|
|||
if (_modelFile.completeSuffix().contains("fst")) {
|
||||
QFile fst(_modelFile.filePath());
|
||||
if (!fst.open(QFile::ReadOnly | QFile::Text)) {
|
||||
QMessageBox::warning(NULL,
|
||||
OffscreenUi::warning(NULL,
|
||||
QString("ModelPackager::loadModel()"),
|
||||
QString("Could not open FST file %1").arg(_modelFile.filePath()),
|
||||
QMessageBox::Ok);
|
||||
|
@ -97,7 +98,7 @@ bool ModelPackager::loadModel() {
|
|||
// open the fbx file
|
||||
QFile fbx(_fbxInfo.filePath());
|
||||
if (!_fbxInfo.exists() || !_fbxInfo.isFile() || !fbx.open(QIODevice::ReadOnly)) {
|
||||
QMessageBox::warning(NULL,
|
||||
OffscreenUi::warning(NULL,
|
||||
QString("ModelPackager::loadModel()"),
|
||||
QString("Could not open FBX file %1").arg(_fbxInfo.filePath()),
|
||||
QMessageBox::Ok);
|
||||
|
@ -402,7 +403,7 @@ bool ModelPackager::copyTextures(const QString& oldDir, const QDir& newDir) {
|
|||
}
|
||||
|
||||
if (!errors.isEmpty()) {
|
||||
QMessageBox::warning(nullptr, "ModelPackager::copyTextures()",
|
||||
OffscreenUi::warning(nullptr, "ModelPackager::copyTextures()",
|
||||
"Missing textures:" + errors);
|
||||
qCDebug(interfaceapp) << "ModelPackager::copyTextures():" << errors;
|
||||
return false;
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
#include <FSTReader.h>
|
||||
#include <GLMHelpers.h>
|
||||
#include <OffscreenUi.h>
|
||||
|
||||
#include "ModelPropertiesDialog.h"
|
||||
|
||||
|
@ -200,7 +201,7 @@ void ModelPropertiesDialog::chooseTextureDirectory() {
|
|||
return;
|
||||
}
|
||||
if (!directory.startsWith(_basePath)) {
|
||||
QMessageBox::warning(NULL, "Invalid texture directory", "Texture directory must be child of base path.");
|
||||
OffscreenUi::warning(NULL, "Invalid texture directory", "Texture directory must be child of base path.");
|
||||
return;
|
||||
}
|
||||
_textureDirectory->setText(directory.length() == _basePath.length() ? "." : directory.mid(_basePath.length() + 1));
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <AssetUpload.h>
|
||||
#include <ResourceManager.h>
|
||||
|
||||
#include "OffscreenUi.h"
|
||||
#include "../ui/AssetUploadDialogFactory.h"
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(asset_migrator);
|
||||
|
@ -52,7 +53,7 @@ void ATPAssetMigrator::loadEntityServerFile() {
|
|||
" continue?\n\nMake sure you are connected to the right domain."
|
||||
};
|
||||
|
||||
auto button = QMessageBox::question(_dialogParent, MESSAGE_BOX_TITLE, MIGRATION_CONFIRMATION_TEXT,
|
||||
auto button = OffscreenUi::question(_dialogParent, MESSAGE_BOX_TITLE, MIGRATION_CONFIRMATION_TEXT,
|
||||
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
|
||||
|
||||
if (button == QMessageBox::No) {
|
||||
|
@ -67,7 +68,7 @@ void ATPAssetMigrator::loadEntityServerFile() {
|
|||
QByteArray jsonData;
|
||||
|
||||
if (!gunzip(compressedJsonData, jsonData)) {
|
||||
QMessageBox::warning(_dialogParent, "Error", "The file at" + filename + "was not in gzip format.");
|
||||
OffscreenUi::warning(_dialogParent, "Error", "The file at" + filename + "was not in gzip format.");
|
||||
}
|
||||
|
||||
QJsonDocument modelsJSON = QJsonDocument::fromJson(jsonData);
|
||||
|
@ -107,7 +108,7 @@ void ATPAssetMigrator::loadEntityServerFile() {
|
|||
if (request->getResult() == ResourceRequest::Success) {
|
||||
migrateResource(request);
|
||||
} else {
|
||||
QMessageBox::warning(_dialogParent, "Error",
|
||||
OffscreenUi::warning(_dialogParent, "Error",
|
||||
QString("Could not retrieve asset at %1").arg(modelURL.toString()));
|
||||
}
|
||||
request->deleteLater();
|
||||
|
@ -115,7 +116,7 @@ void ATPAssetMigrator::loadEntityServerFile() {
|
|||
|
||||
request->send();
|
||||
} else {
|
||||
QMessageBox::warning(_dialogParent, "Error",
|
||||
OffscreenUi::warning(_dialogParent, "Error",
|
||||
QString("Could not create request for asset at %1").arg(modelURL.toString()));
|
||||
}
|
||||
|
||||
|
@ -129,7 +130,7 @@ void ATPAssetMigrator::loadEntityServerFile() {
|
|||
_doneReading = true;
|
||||
|
||||
} else {
|
||||
QMessageBox::warning(_dialogParent, "Error",
|
||||
OffscreenUi::warning(_dialogParent, "Error",
|
||||
"There was a problem loading that entity-server file for ATP asset migration. Please try again");
|
||||
}
|
||||
}
|
||||
|
@ -212,7 +213,7 @@ bool ATPAssetMigrator::wantsToMigrateResource(const QUrl& url) {
|
|||
"Select \"No\" to be prompted for each discovered asset."
|
||||
};
|
||||
|
||||
auto button = QMessageBox::question(_dialogParent, MESSAGE_BOX_TITLE, COMPLETE_MIGRATION_TEXT,
|
||||
auto button = OffscreenUi::question(_dialogParent, MESSAGE_BOX_TITLE, COMPLETE_MIGRATION_TEXT,
|
||||
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
|
||||
|
||||
if (button == QMessageBox::Yes) {
|
||||
|
@ -226,7 +227,7 @@ bool ATPAssetMigrator::wantsToMigrateResource(const QUrl& url) {
|
|||
return true;
|
||||
} else {
|
||||
// present a dialog asking the user if they want to migrate this specific resource
|
||||
auto button = QMessageBox::question(_dialogParent, MESSAGE_BOX_TITLE,
|
||||
auto button = OffscreenUi::question(_dialogParent, MESSAGE_BOX_TITLE,
|
||||
"Would you like to migrate the following resource?\n" + url.toString(),
|
||||
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
|
||||
return button == QMessageBox::Yes;
|
||||
|
@ -254,11 +255,11 @@ void ATPAssetMigrator::saveEntityServerFile() {
|
|||
QMessageBox::information(_dialogParent, "Success",
|
||||
QString("Your new entities file has been saved at %1").arg(saveName));
|
||||
} else {
|
||||
QMessageBox::warning(_dialogParent, "Error", "Could not gzip JSON data for new entities file.");
|
||||
OffscreenUi::warning(_dialogParent, "Error", "Could not gzip JSON data for new entities file.");
|
||||
}
|
||||
|
||||
} else {
|
||||
QMessageBox::warning(_dialogParent, "Error",
|
||||
OffscreenUi::warning(_dialogParent, "Error",
|
||||
QString("Could not open file at %1 to write new entities file to.").arg(saveName));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -237,6 +237,7 @@ void Avatar::simulate(float deltaTime) {
|
|||
measureMotionDerivatives(deltaTime);
|
||||
|
||||
simulateAttachments(deltaTime);
|
||||
updatePalms();
|
||||
}
|
||||
|
||||
bool Avatar::isLookingAtMe(AvatarSharedPointer avatar) const {
|
||||
|
@ -1155,34 +1156,24 @@ void Avatar::rebuildCollisionShape() {
|
|||
}
|
||||
}
|
||||
|
||||
// thread-safe
|
||||
glm::vec3 Avatar::getLeftPalmPosition() {
|
||||
glm::vec3 leftHandPosition;
|
||||
getSkeletonModel().getLeftHandPosition(leftHandPosition);
|
||||
glm::quat leftRotation;
|
||||
getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getLeftHandJointIndex(), leftRotation);
|
||||
leftHandPosition += HAND_TO_PALM_OFFSET * glm::inverse(leftRotation);
|
||||
return leftHandPosition;
|
||||
return _leftPalmPositionCache.get();
|
||||
}
|
||||
|
||||
// thread-safe
|
||||
glm::quat Avatar::getLeftPalmRotation() {
|
||||
glm::quat leftRotation;
|
||||
getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getLeftHandJointIndex(), leftRotation);
|
||||
return leftRotation;
|
||||
return _leftPalmRotationCache.get();
|
||||
}
|
||||
|
||||
// thread-safe
|
||||
glm::vec3 Avatar::getRightPalmPosition() {
|
||||
glm::vec3 rightHandPosition;
|
||||
getSkeletonModel().getRightHandPosition(rightHandPosition);
|
||||
glm::quat rightRotation;
|
||||
getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getRightHandJointIndex(), rightRotation);
|
||||
rightHandPosition += HAND_TO_PALM_OFFSET * glm::inverse(rightRotation);
|
||||
return rightHandPosition;
|
||||
return _rightPalmPositionCache.get();
|
||||
}
|
||||
|
||||
// thread-safe
|
||||
glm::quat Avatar::getRightPalmRotation() {
|
||||
glm::quat rightRotation;
|
||||
getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getRightHandJointIndex(), rightRotation);
|
||||
return rightRotation;
|
||||
return _rightPalmRotationCache.get();
|
||||
}
|
||||
|
||||
void Avatar::setPosition(const glm::vec3& position) {
|
||||
|
@ -1194,3 +1185,24 @@ void Avatar::setOrientation(const glm::quat& orientation) {
|
|||
AvatarData::setOrientation(orientation);
|
||||
updateAttitude();
|
||||
}
|
||||
|
||||
void Avatar::updatePalms() {
|
||||
|
||||
// get palm rotations
|
||||
glm::quat leftPalmRotation, rightPalmRotation;
|
||||
getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getLeftHandJointIndex(), leftPalmRotation);
|
||||
getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getRightHandJointIndex(), rightPalmRotation);
|
||||
|
||||
// get palm positions
|
||||
glm::vec3 leftPalmPosition, rightPalmPosition;
|
||||
getSkeletonModel().getLeftHandPosition(leftPalmPosition);
|
||||
getSkeletonModel().getRightHandPosition(rightPalmPosition);
|
||||
leftPalmPosition += HAND_TO_PALM_OFFSET * glm::inverse(leftPalmRotation);
|
||||
rightPalmPosition += HAND_TO_PALM_OFFSET * glm::inverse(rightPalmRotation);
|
||||
|
||||
// update thread-safe caches
|
||||
_leftPalmRotationCache.set(leftPalmRotation);
|
||||
_rightPalmRotationCache.set(rightPalmRotation);
|
||||
_leftPalmPositionCache.set(leftPalmPosition);
|
||||
_rightPalmPositionCache.set(rightPalmPosition);
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "SkeletonModel.h"
|
||||
#include "world.h"
|
||||
#include "Rig.h"
|
||||
#include <ThreadSafeValueCache.h>
|
||||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const AvatarSharedPointer& avatar);
|
||||
|
@ -229,8 +230,15 @@ protected:
|
|||
|
||||
virtual void updateJointMappings() override;
|
||||
|
||||
virtual void updatePalms();
|
||||
|
||||
render::ItemID _renderItemID;
|
||||
|
||||
ThreadSafeValueCache<glm::vec3> _leftPalmPositionCache { glm::vec3() };
|
||||
ThreadSafeValueCache<glm::quat> _leftPalmRotationCache { glm::quat() };
|
||||
ThreadSafeValueCache<glm::vec3> _rightPalmPositionCache { glm::vec3() };
|
||||
ThreadSafeValueCache<glm::quat> _rightPalmRotationCache { glm::quat() };
|
||||
|
||||
private:
|
||||
bool _initialized;
|
||||
NetworkTexturePointer _billboardTexture;
|
||||
|
|
|
@ -89,6 +89,8 @@ void AvatarActionHold::prepareForPhysicsSimulation() {
|
|||
// code here for future reference.
|
||||
// _palmRotationFromRigidBody = avatarRotationInverse * palmRotation;
|
||||
});
|
||||
|
||||
activateBody();
|
||||
}
|
||||
|
||||
std::shared_ptr<Avatar> AvatarActionHold::getTarget(glm::quat& rotation, glm::vec3& position) {
|
||||
|
@ -197,7 +199,6 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) {
|
|||
if (_kinematic) {
|
||||
doKinematicUpdate(deltaTimeStep);
|
||||
} else {
|
||||
activateBody();
|
||||
forceBodyNonStatic();
|
||||
ObjectActionSpring::updateActionWorker(deltaTimeStep);
|
||||
}
|
||||
|
@ -247,7 +248,6 @@ void AvatarActionHold::doKinematicUpdate(float deltaTimeStep) {
|
|||
_previousSet = true;
|
||||
});
|
||||
|
||||
activateBody();
|
||||
forceBodyNonStatic();
|
||||
}
|
||||
|
||||
|
@ -344,7 +344,6 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) {
|
|||
ownerEntity->setActionDataNeedsTransmit(true);
|
||||
}
|
||||
});
|
||||
activateBody();
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -431,6 +430,5 @@ void AvatarActionHold::deserialize(QByteArray serializedArguments) {
|
|||
_active = true;
|
||||
});
|
||||
|
||||
activateBody();
|
||||
forceBodyNonStatic();
|
||||
}
|
||||
|
|
|
@ -417,6 +417,8 @@ void MyAvatar::updateSensorToWorldMatrix() {
|
|||
// position when driven from the head.
|
||||
glm::mat4 desiredMat = createMatFromQuatAndPos(getOrientation(), getPosition());
|
||||
_sensorToWorldMatrix = desiredMat * glm::inverse(_bodySensorMatrix);
|
||||
|
||||
lateUpdatePalms();
|
||||
}
|
||||
|
||||
// Update avatar head rotation with sensor data
|
||||
|
@ -1839,3 +1841,8 @@ QScriptValue audioListenModeToScriptValue(QScriptEngine* engine, const AudioList
|
|||
void audioListenModeFromScriptValue(const QScriptValue& object, AudioListenerMode& audioListenerMode) {
|
||||
audioListenerMode = (AudioListenerMode)object.toUInt16();
|
||||
}
|
||||
|
||||
|
||||
void MyAvatar::lateUpdatePalms() {
|
||||
Avatar::updatePalms();
|
||||
}
|
||||
|
|
|
@ -311,12 +311,14 @@ private:
|
|||
|
||||
void setVisibleInSceneIfReady(Model* model, render::ScenePointer scene, bool visiblity);
|
||||
|
||||
PalmData getActivePalmData(int palmIndex) const;
|
||||
|
||||
// derive avatar body position and orientation from the current HMD Sensor location.
|
||||
// results are in HMD frame
|
||||
glm::mat4 deriveBodyFromHMDSensor() const;
|
||||
|
||||
virtual void updatePalms() override {}
|
||||
void lateUpdatePalms();
|
||||
|
||||
|
||||
float _driveKeys[MAX_DRIVE_KEYS];
|
||||
bool _wasPushing;
|
||||
bool _isPushing;
|
||||
|
|
|
@ -139,7 +139,7 @@ void EyeTracker::onStreamStarted() {
|
|||
qCWarning(interfaceapp) << "Eye Tracker: Error starting streaming:" << smiReturnValueToString(result);
|
||||
// Display error dialog unless SMI SDK has already displayed an error message.
|
||||
if (result != SMI_ERROR_HMD_NOT_SUPPORTED) {
|
||||
QMessageBox::warning(nullptr, "Eye Tracker Error", smiReturnValueToString(result));
|
||||
OffscreenUi::warning(nullptr, "Eye Tracker Error", smiReturnValueToString(result));
|
||||
}
|
||||
} else {
|
||||
qCDebug(interfaceapp) << "Eye Tracker: Started streaming";
|
||||
|
@ -152,7 +152,7 @@ void EyeTracker::onStreamStarted() {
|
|||
result = smi_loadCalibration(HIGH_FIDELITY_EYE_TRACKER_CALIBRATION);
|
||||
if (result != SMI_RET_SUCCESS) {
|
||||
qCWarning(interfaceapp) << "Eye Tracker: Error loading calibration:" << smiReturnValueToString(result);
|
||||
QMessageBox::warning(nullptr, "Eye Tracker Error", "Error loading calibration"
|
||||
OffscreenUi::warning(nullptr, "Eye Tracker Error", "Error loading calibration"
|
||||
+ smiReturnValueToString(result));
|
||||
} else {
|
||||
qCDebug(interfaceapp) << "Eye Tracker: Loaded calibration";
|
||||
|
@ -168,7 +168,7 @@ void EyeTracker::setEnabled(bool enabled, bool simulate) {
|
|||
int result = smi_setCallback(eyeTrackerCallback);
|
||||
if (result != SMI_RET_SUCCESS) {
|
||||
qCWarning(interfaceapp) << "Eye Tracker: Error setting callback:" << smiReturnValueToString(result);
|
||||
QMessageBox::warning(nullptr, "Eye Tracker Error", smiReturnValueToString(result));
|
||||
OffscreenUi::warning(nullptr, "Eye Tracker Error", smiReturnValueToString(result));
|
||||
} else {
|
||||
_isInitialized = true;
|
||||
}
|
||||
|
@ -273,7 +273,7 @@ void EyeTracker::calibrate(int points) {
|
|||
}
|
||||
|
||||
if (result != SMI_RET_SUCCESS) {
|
||||
QMessageBox::warning(nullptr, "Eye Tracker Error", "Calibration error: " + smiReturnValueToString(result));
|
||||
OffscreenUi::warning(nullptr, "Eye Tracker Error", "Calibration error: " + smiReturnValueToString(result));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "DomainHandler.h"
|
||||
#include "MainWindow.h"
|
||||
#include "Menu.h"
|
||||
#include "OffscreenUi.h"
|
||||
#include "ui/ModelsBrowser.h"
|
||||
|
||||
#include "WindowScriptingInterface.h"
|
||||
|
@ -153,12 +154,11 @@ QScriptValue WindowScriptingInterface::peekNonBlockingFormResult(QScriptValue fo
|
|||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
/// Display an alert box
|
||||
/// \param const QString& message message to display
|
||||
/// \return QScriptValue::UndefinedValue
|
||||
QScriptValue WindowScriptingInterface::showAlert(const QString& message) {
|
||||
QMessageBox::warning(qApp->getWindow(), "", message);
|
||||
OffscreenUi::warning("", message);
|
||||
return QScriptValue::UndefinedValue;
|
||||
}
|
||||
|
||||
|
@ -166,8 +166,11 @@ QScriptValue WindowScriptingInterface::showAlert(const QString& message) {
|
|||
/// \param const QString& message message to display
|
||||
/// \return QScriptValue `true` if 'Yes' was clicked, `false` otherwise
|
||||
QScriptValue WindowScriptingInterface::showConfirm(const QString& message) {
|
||||
QMessageBox::StandardButton response = QMessageBox::question(qApp->getWindow(), "", message);
|
||||
return QScriptValue(response == QMessageBox::Yes);
|
||||
bool confirm = false;
|
||||
OffscreenUi::question("", message, [&](QMessageBox::StandardButton response){
|
||||
confirm = (response == QMessageBox::Yes);
|
||||
});
|
||||
return QScriptValue(confirm);
|
||||
}
|
||||
|
||||
void WindowScriptingInterface::chooseDirectory() {
|
||||
|
@ -185,7 +188,7 @@ void WindowScriptingInterface::chooseDirectory() {
|
|||
}
|
||||
|
||||
if (!validateAs.exactMatch(directory)) {
|
||||
QMessageBox::warning(NULL, "Invalid Directory", errorMessage);
|
||||
OffscreenUi::warning(NULL, "Invalid Directory", errorMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -597,7 +600,6 @@ QScriptValue WindowScriptingInterface::showPrompt(const QString& message, const
|
|||
if (promptDialog.exec() == QDialog::Accepted) {
|
||||
return QScriptValue(promptDialog.textValue());
|
||||
}
|
||||
|
||||
return QScriptValue::NullValue;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <AssetUpload.h>
|
||||
#include <AssetUtils.h>
|
||||
#include <NodeList.h>
|
||||
#include <OffscreenUi.h>
|
||||
#include <ResourceManager.h>
|
||||
|
||||
AssetUploadDialogFactory& AssetUploadDialogFactory::getInstance() {
|
||||
|
@ -146,5 +147,5 @@ void AssetUploadDialogFactory::showErrorDialog(AssetUpload* upload, QWidget* dia
|
|||
|
||||
dialogMessage += errorMessage;
|
||||
|
||||
QMessageBox::warning(dialogParent, "Failed Upload", dialogMessage);
|
||||
OffscreenUi::warning(dialogParent, "Failed Upload", dialogMessage);
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <NetworkAccessManager.h>
|
||||
|
||||
#include "DiskCacheEditor.h"
|
||||
#include "OffscreenUi.h"
|
||||
|
||||
DiskCacheEditor::DiskCacheEditor(QWidget* parent) : QObject(parent) {
|
||||
|
||||
|
@ -136,7 +137,7 @@ void DiskCacheEditor::refresh() {
|
|||
|
||||
void DiskCacheEditor::clear() {
|
||||
QMessageBox::StandardButton buttonClicked =
|
||||
QMessageBox::question(_dialog, "Clearing disk cache",
|
||||
OffscreenUi::question(_dialog, "Clearing disk cache",
|
||||
"You are about to erase all the content of the disk cache,"
|
||||
"are you sure you want to do that?");
|
||||
if (buttonClicked == QMessageBox::Yes) {
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <QWidget>
|
||||
|
||||
#include <NetworkAccessManager.h>
|
||||
#include <OffscreenUi.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "ScriptHighlighting.h"
|
||||
|
@ -120,7 +121,7 @@ bool ScriptEditorWidget::setRunning(bool run) {
|
|||
bool ScriptEditorWidget::saveFile(const QString &scriptPath) {
|
||||
QFile file(scriptPath);
|
||||
if (!file.open(QFile::WriteOnly | QFile::Text)) {
|
||||
QMessageBox::warning(this, tr("Interface"), tr("Cannot write script %1:\n%2.").arg(scriptPath)
|
||||
OffscreenUi::warning(this, tr("Interface"), tr("Cannot write script %1:\n%2.").arg(scriptPath)
|
||||
.arg(file.errorString()));
|
||||
return false;
|
||||
}
|
||||
|
@ -141,7 +142,7 @@ void ScriptEditorWidget::loadFile(const QString& scriptPath) {
|
|||
if (url.scheme().size() <= WINDOWS_DRIVE_LETTER_SIZE) {
|
||||
QFile file(scriptPath);
|
||||
if (!file.open(QFile::ReadOnly | QFile::Text)) {
|
||||
QMessageBox::warning(this, tr("Interface"), tr("Cannot read script %1:\n%2.").arg(scriptPath)
|
||||
OffscreenUi::warning(this, tr("Interface"), tr("Cannot read script %1:\n%2.").arg(scriptPath)
|
||||
.arg(file.errorString()));
|
||||
return;
|
||||
}
|
||||
|
@ -208,7 +209,7 @@ void ScriptEditorWidget::setScriptFile(const QString& scriptPath) {
|
|||
|
||||
bool ScriptEditorWidget::questionSave() {
|
||||
if (_scriptEditorWidgetUI->scriptEdit->document()->isModified()) {
|
||||
QMessageBox::StandardButton button = QMessageBox::warning(this, tr("Interface"),
|
||||
QMessageBox::StandardButton button = OffscreenUi::warning(this, tr("Interface"),
|
||||
tr("The script has been modified.\nDo you want to save your changes?"), QMessageBox::Save | QMessageBox::Discard |
|
||||
QMessageBox::Cancel, QMessageBox::Save);
|
||||
return button == QMessageBox::Save ? save() : (button == QMessageBox::Discard);
|
||||
|
@ -222,7 +223,7 @@ void ScriptEditorWidget::onWindowActivated() {
|
|||
|
||||
if (QFileInfo(_currentScript).lastModified() > _currentScriptModified) {
|
||||
if (static_cast<ScriptEditorWindow*>(this->parent()->parent()->parent())->autoReloadScripts()
|
||||
|| QMessageBox::warning(this, _currentScript,
|
||||
|| OffscreenUi::warning(this, _currentScript,
|
||||
tr("This file has been modified outside of the Interface editor.") + "\n\n"
|
||||
+ (isModified()
|
||||
? tr("Do you want to reload it and lose the changes you've made in the Interface editor?")
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <QMessageBox>
|
||||
#include <QUrlQuery>
|
||||
|
||||
#include <OffscreenUi.h>
|
||||
|
||||
const int NARROW_SNAPSHOT_DIALOG_SIZE = 500;
|
||||
const int WIDE_SNAPSHOT_DIALOG_WIDTH = 650;
|
||||
|
@ -87,7 +88,7 @@ void SnapshotShareDialog::accept() {
|
|||
void SnapshotShareDialog::uploadSnapshot() {
|
||||
|
||||
if (AccountManager::getInstance().getAccountInfo().getDiscourseApiKey().isEmpty()) {
|
||||
QMessageBox::warning(this, "",
|
||||
OffscreenUi::warning(this, "",
|
||||
"Your Discourse API key is missing, you cannot share snapshots. Please try to relog.");
|
||||
return;
|
||||
}
|
||||
|
@ -178,7 +179,7 @@ void SnapshotShareDialog::postRequestFinished() {
|
|||
errorMessage = errorArray.first().toString();
|
||||
}
|
||||
}
|
||||
QMessageBox::warning(this, "", errorMessage);
|
||||
OffscreenUi::warning(this, "", errorMessage);
|
||||
_ui.shareButton->setEnabled(true);
|
||||
_ui.shareButton->setStyleSheet(SHARE_BUTTON_STYLE + SHARE_BUTTON_ENABLED_STYLE);
|
||||
}
|
||||
|
@ -193,7 +194,7 @@ void SnapshotShareDialog::uploadRequestFinished() {
|
|||
if (responseObject.contains("url")) {
|
||||
sendForumPost(responseObject["url"].toString());
|
||||
} else {
|
||||
QMessageBox::warning(this, "", SHARE_DEFAULT_ERROR);
|
||||
OffscreenUi::warning(this, "", SHARE_DEFAULT_ERROR);
|
||||
_ui.shareButton->setEnabled(true);
|
||||
_ui.shareButton->setStyleSheet(SHARE_BUTTON_STYLE + SHARE_BUTTON_ENABLED_STYLE);
|
||||
}
|
||||
|
|
|
@ -23,15 +23,15 @@ ObjectAction::~ObjectAction() {
|
|||
}
|
||||
|
||||
void ObjectAction::updateAction(btCollisionWorld* collisionWorld, btScalar deltaTimeStep) {
|
||||
bool ownerEntityExpired = false;
|
||||
quint64 expiresWhen = 0;
|
||||
EntityItemPointer ownerEntity = nullptr;
|
||||
|
||||
withReadLock([&]{
|
||||
ownerEntityExpired = _ownerEntity.expired();
|
||||
ownerEntity = _ownerEntity.lock();
|
||||
expiresWhen = _expires;
|
||||
});
|
||||
|
||||
if (ownerEntityExpired) {
|
||||
if (!ownerEntity) {
|
||||
qDebug() << "warning -- action with no entity removing self from btCollisionWorld.";
|
||||
btDynamicsWorld* dynamicsWorld = static_cast<btDynamicsWorld*>(collisionWorld);
|
||||
if (dynamicsWorld) {
|
||||
|
@ -43,10 +43,8 @@ void ObjectAction::updateAction(btCollisionWorld* collisionWorld, btScalar delta
|
|||
if (expiresWhen > 0) {
|
||||
quint64 now = usecTimestampNow();
|
||||
if (now > expiresWhen) {
|
||||
EntityItemPointer ownerEntity = nullptr;
|
||||
QUuid myID;
|
||||
withWriteLock([&]{
|
||||
ownerEntity = _ownerEntity.lock();
|
||||
_active = false;
|
||||
myID = getID();
|
||||
});
|
||||
|
|
49
libraries/shared/src/ThreadSafeValueCache.h
Normal file
49
libraries/shared/src/ThreadSafeValueCache.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
//
|
||||
// ThreadSafeValueCache.h
|
||||
// interface/src/avatar
|
||||
//
|
||||
// Copyright 2012 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
|
||||
//
|
||||
|
||||
#ifndef hifi_ThreadSafeValueCache_h
|
||||
#define hifi_ThreadSafeValueCache_h
|
||||
|
||||
#include <mutex>
|
||||
|
||||
// Helper class for for sharing a value type between threads.
|
||||
// It allows many threads to get or set a value atomically.
|
||||
// This provides cache semantics, any get will return the last set value.
|
||||
//
|
||||
// For example: This can be used to copy values between C++ code running on the application thread
|
||||
// and JavaScript which is running on a different thread.
|
||||
|
||||
template <typename T>
|
||||
class ThreadSafeValueCache {
|
||||
public:
|
||||
ThreadSafeValueCache(const T& v) : _value { v } {}
|
||||
|
||||
// returns atomic copy of the cached value.
|
||||
T get() const {
|
||||
std::lock_guard<std::mutex> guard(_mutex);
|
||||
return _value;
|
||||
}
|
||||
|
||||
// will reflect copy of value into the cache.
|
||||
void set(const T& v) {
|
||||
std::lock_guard<std::mutex> guard(_mutex);
|
||||
_value = v;
|
||||
}
|
||||
|
||||
private:
|
||||
mutable std::mutex _mutex;
|
||||
T _value;
|
||||
|
||||
// no copies
|
||||
ThreadSafeValueCache(const ThreadSafeValueCache&) = delete;
|
||||
ThreadSafeValueCache& operator=(const ThreadSafeValueCache&) = delete;
|
||||
};
|
||||
|
||||
#endif // #define hifi_ThreadSafeValueCache_h
|
|
@ -174,12 +174,37 @@ void OffscreenUi::information(const QString& title, const QString& text,
|
|||
}
|
||||
|
||||
void OffscreenUi::question(const QString& title, const QString& text,
|
||||
ButtonCallback callback,
|
||||
QMessageBox::StandardButtons buttons) {
|
||||
messageBox(title, text, callback,
|
||||
static_cast<QMessageBox::Icon>(MessageDialog::Question), buttons);
|
||||
ButtonCallback callback,
|
||||
QMessageBox::StandardButtons buttons) {
|
||||
|
||||
bool waiting = true;
|
||||
ButtonCallback blockingCallback = [&](QMessageBox::StandardButton response){
|
||||
callback(response); // call the actual callback
|
||||
waiting = false;
|
||||
};
|
||||
|
||||
messageBox(title, text, blockingCallback,
|
||||
static_cast<QMessageBox::Icon>(MessageDialog::Question), buttons);
|
||||
|
||||
// block until the call back has been called
|
||||
while (waiting) {
|
||||
QCoreApplication::processEvents();
|
||||
}
|
||||
}
|
||||
|
||||
QMessageBox::StandardButton OffscreenUi::question(void* ignored, const QString& title, const QString& text,
|
||||
QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) {
|
||||
|
||||
QMessageBox::StandardButton result = defaultButton;
|
||||
|
||||
OffscreenUi::question(title, text, [&](QMessageBox::StandardButton response){
|
||||
result = response;
|
||||
}, buttons);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void OffscreenUi::warning(const QString& title, const QString& text,
|
||||
ButtonCallback callback,
|
||||
QMessageBox::StandardButtons buttons) {
|
||||
|
@ -187,6 +212,26 @@ void OffscreenUi::warning(const QString& title, const QString& text,
|
|||
static_cast<QMessageBox::Icon>(MessageDialog::Warning), buttons);
|
||||
}
|
||||
|
||||
QMessageBox::StandardButton OffscreenUi::warning(void* ignored, const QString& title, const QString& text,
|
||||
QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) {
|
||||
|
||||
bool waiting = true;
|
||||
QMessageBox::StandardButton result = defaultButton;
|
||||
|
||||
OffscreenUi::warning(title, text, [&](QMessageBox::StandardButton response){
|
||||
result = response;
|
||||
waiting = false;
|
||||
}, buttons);
|
||||
|
||||
// block until the call back has been called
|
||||
while (waiting) {
|
||||
QCoreApplication::processEvents();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void OffscreenUi::critical(const QString& title, const QString& text,
|
||||
ButtonCallback callback,
|
||||
QMessageBox::StandardButtons buttons) {
|
||||
|
|
|
@ -45,14 +45,25 @@ public:
|
|||
ButtonCallback callback = NO_OP_CALLBACK,
|
||||
QMessageBox::StandardButtons buttons = QMessageBox::Ok);
|
||||
|
||||
/// Note: will block until user clicks a response to the question
|
||||
static void question(const QString& title, const QString& text,
|
||||
ButtonCallback callback = NO_OP_CALLBACK,
|
||||
QMessageBox::StandardButtons buttons = QMessageBox::StandardButtons(QMessageBox::Yes | QMessageBox::No));
|
||||
|
||||
/// Same design as QMessageBox::question(), will block, returns result
|
||||
static QMessageBox::StandardButton question(void* ignored, const QString& title, const QString& text,
|
||||
QMessageBox::StandardButtons buttons = QMessageBox::StandardButtons(QMessageBox::Yes | QMessageBox::No),
|
||||
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
|
||||
|
||||
static void warning(const QString& title, const QString& text,
|
||||
ButtonCallback callback = NO_OP_CALLBACK,
|
||||
QMessageBox::StandardButtons buttons = QMessageBox::Ok);
|
||||
|
||||
/// Same design as QMessageBox::warning(), will block, returns result
|
||||
static QMessageBox::StandardButton warning(void* ignored, const QString& title, const QString& text,
|
||||
QMessageBox::StandardButtons buttons = QMessageBox::StandardButtons(QMessageBox::Yes | QMessageBox::No),
|
||||
QMessageBox::StandardButton defaultButton = QMessageBox::NoButton);
|
||||
|
||||
static void critical(const QString& title, const QString& text,
|
||||
ButtonCallback callback = NO_OP_CALLBACK,
|
||||
QMessageBox::StandardButtons buttons = QMessageBox::Ok);
|
||||
|
|
Loading…
Reference in a new issue