mirror of
https://github.com/overte-org/overte.git
synced 2025-04-19 13:43:49 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into newEditGrab
This commit is contained in:
commit
c69eff3322
23 changed files with 257 additions and 295 deletions
|
@ -3238,8 +3238,6 @@ bool MyAvatar::pinJoint(int index, const glm::vec3& position, const glm::quat& o
|
|||
slamPosition(position);
|
||||
setWorldOrientation(orientation);
|
||||
|
||||
_skeletonModel->getRig().setMaxHipsOffsetLength(0.05f);
|
||||
|
||||
auto it = std::find(_pinnedJoints.begin(), _pinnedJoints.end(), index);
|
||||
if (it == _pinnedJoints.end()) {
|
||||
_pinnedJoints.push_back(index);
|
||||
|
@ -3259,12 +3257,6 @@ bool MyAvatar::clearPinOnJoint(int index) {
|
|||
auto it = std::find(_pinnedJoints.begin(), _pinnedJoints.end(), index);
|
||||
if (it != _pinnedJoints.end()) {
|
||||
_pinnedJoints.erase(it);
|
||||
|
||||
auto hipsIndex = getJointIndex("Hips");
|
||||
if (index == hipsIndex) {
|
||||
_skeletonModel->getRig().setMaxHipsOffsetLength(FLT_MAX);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -43,8 +43,6 @@ static AnimPose computeHipsInSensorFrame(MyAvatar* myAvatar, bool isFlying) {
|
|||
AnimPose result = AnimPose(worldToSensorMat * avatarTransform.getMatrix() * Matrices::Y_180);
|
||||
result.scale() = glm::vec3(1.0f, 1.0f, 1.0f);
|
||||
return result;
|
||||
} else {
|
||||
DebugDraw::getInstance().removeMarker("pinnedHips");
|
||||
}
|
||||
|
||||
glm::mat4 hipsMat = myAvatar->deriveBodyFromHMDSensor();
|
||||
|
|
|
@ -16,6 +16,7 @@ CheckoutProxy::CheckoutProxy(QObject* qmlObject, QObject* parent) : QmlWrapper(q
|
|||
}
|
||||
|
||||
WalletScriptingInterface::WalletScriptingInterface() {
|
||||
|
||||
}
|
||||
|
||||
void WalletScriptingInterface::refreshWalletStatus() {
|
||||
|
@ -26,4 +27,19 @@ void WalletScriptingInterface::refreshWalletStatus() {
|
|||
void WalletScriptingInterface::setWalletStatus(const uint& status) {
|
||||
_walletStatus = status;
|
||||
emit DependencyManager::get<Wallet>()->walletStatusResult(status);
|
||||
}
|
||||
|
||||
void WalletScriptingInterface::proveAvatarEntityOwnershipVerification(const QUuid& entityID) {
|
||||
QSharedPointer<ContextOverlayInterface> contextOverlayInterface = DependencyManager::get<ContextOverlayInterface>();
|
||||
EntityItemProperties entityProperties = DependencyManager::get<EntityScriptingInterface>()->getEntityProperties(entityID,
|
||||
contextOverlayInterface->getEntityPropertyFlags());
|
||||
if (entityProperties.getClientOnly()) {
|
||||
if (!entityID.isNull() && entityProperties.getCertificateID().length() > 0) {
|
||||
contextOverlayInterface->requestOwnershipVerification(entityID);
|
||||
} else {
|
||||
qCDebug(entities) << "Failed to prove ownership of:" << entityID << "is null or not a certified item";
|
||||
}
|
||||
} else {
|
||||
qCDebug(entities) << "Failed to prove ownership of:" << entityID << "is not an avatar entity";
|
||||
}
|
||||
}
|
|
@ -21,6 +21,7 @@
|
|||
#include <OffscreenUi.h>
|
||||
#include "Application.h"
|
||||
#include "commerce/Wallet.h"
|
||||
#include "ui/overlays/ContextOverlayInterface.h"
|
||||
|
||||
class CheckoutProxy : public QmlWrapper {
|
||||
Q_OBJECT
|
||||
|
@ -39,6 +40,7 @@ public:
|
|||
|
||||
Q_INVOKABLE void refreshWalletStatus();
|
||||
Q_INVOKABLE uint getWalletStatus() { return _walletStatus; }
|
||||
Q_INVOKABLE void proveAvatarEntityOwnershipVerification(const QUuid& entityID);
|
||||
// setWalletStatus() should never be made Q_INVOKABLE. If it were,
|
||||
// scripts could cause the Wallet to incorrectly report its status.
|
||||
void setWalletStatus(const uint& status);
|
||||
|
@ -46,6 +48,8 @@ public:
|
|||
signals:
|
||||
void walletStatusChanged();
|
||||
void walletNotSetup();
|
||||
void ownershipVerificationSuccess(const QUuid& entityID);
|
||||
void ownershipVerificationFailed(const QUuid& entityID);
|
||||
|
||||
private:
|
||||
uint _walletStatus;
|
||||
|
|
|
@ -38,7 +38,7 @@ const QString FATAL_TEXT = "[FATAL]";
|
|||
const QString SUPPRESS_TEXT = "[SUPPRESS]";
|
||||
const QString UNKNOWN_TEXT = "[UNKNOWN]";
|
||||
|
||||
LogDialog::LogDialog(QWidget* parent, AbstractLoggerInterface* logger) : BaseLogDialog(parent) {
|
||||
LogDialog::LogDialog(QWidget* parent, AbstractLoggerInterface* logger) : BaseLogDialog(parent), _windowGeometry("logDialogGeometry", QRect()) {
|
||||
_logger = logger;
|
||||
setWindowTitle("Log");
|
||||
|
||||
|
@ -155,6 +155,11 @@ LogDialog::LogDialog(QWidget* parent, AbstractLoggerInterface* logger) : BaseLog
|
|||
_clearFilterButton->show();
|
||||
connect(_clearFilterButton, &QPushButton::clicked, this, &LogDialog::handleClearFilterButton);
|
||||
handleClearFilterButton();
|
||||
|
||||
auto windowGeometry = _windowGeometry.get();
|
||||
if (windowGeometry.isValid()) {
|
||||
setGeometry(windowGeometry);
|
||||
}
|
||||
}
|
||||
|
||||
void LogDialog::resizeEvent(QResizeEvent* event) {
|
||||
|
@ -173,6 +178,11 @@ void LogDialog::resizeEvent(QResizeEvent* event) {
|
|||
ELEMENT_HEIGHT);
|
||||
}
|
||||
|
||||
void LogDialog::closeEvent(QCloseEvent* event) {
|
||||
BaseLogDialog::closeEvent(event);
|
||||
_windowGeometry.set(geometry());
|
||||
}
|
||||
|
||||
void LogDialog::handleRevealButton() {
|
||||
_logger->locateLog();
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#define hifi_LogDialog_h
|
||||
|
||||
#include "BaseLogDialog.h"
|
||||
#include <SettingHandle.h>
|
||||
|
||||
class QCheckBox;
|
||||
class QPushButton;
|
||||
|
@ -44,6 +45,8 @@ private slots:
|
|||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent* event) override;
|
||||
void closeEvent(QCloseEvent* event) override;
|
||||
|
||||
QString getCurrentLog() override;
|
||||
void printLogFile();
|
||||
|
||||
|
@ -62,6 +65,7 @@ private:
|
|||
QString _filterSelection;
|
||||
|
||||
AbstractLoggerInterface* _logger;
|
||||
Setting::Handle<QRect> _windowGeometry;
|
||||
};
|
||||
|
||||
#endif // hifi_LogDialog_h
|
||||
|
|
|
@ -266,6 +266,93 @@ void ContextOverlayInterface::contextOverlays_hoverLeaveEntity(const EntityItemI
|
|||
}
|
||||
}
|
||||
|
||||
void ContextOverlayInterface::requestOwnershipVerification(const QUuid& entityID) {
|
||||
|
||||
setLastInspectedEntity(entityID);
|
||||
|
||||
EntityItemProperties entityProperties = _entityScriptingInterface->getEntityProperties(_lastInspectedEntity, _entityPropertyFlags);
|
||||
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
if (entityProperties.getClientOnly()) {
|
||||
if (entityProperties.verifyStaticCertificateProperties()) {
|
||||
SharedNodePointer entityServer = nodeList->soloNodeOfType(NodeType::EntityServer);
|
||||
|
||||
if (entityServer) {
|
||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
QNetworkRequest networkRequest;
|
||||
networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
QUrl requestURL = NetworkingConstants::METAVERSE_SERVER_URL();
|
||||
requestURL.setPath("/api/v1/commerce/proof_of_purchase_status/transfer");
|
||||
QJsonObject request;
|
||||
request["certificate_id"] = entityProperties.getCertificateID();
|
||||
networkRequest.setUrl(requestURL);
|
||||
|
||||
QNetworkReply* networkReply = NULL;
|
||||
networkReply = networkAccessManager.put(networkRequest, QJsonDocument(request).toJson());
|
||||
|
||||
connect(networkReply, &QNetworkReply::finished, [=]() {
|
||||
QJsonObject jsonObject = QJsonDocument::fromJson(networkReply->readAll()).object();
|
||||
jsonObject = jsonObject["data"].toObject();
|
||||
|
||||
if (networkReply->error() == QNetworkReply::NoError) {
|
||||
if (!jsonObject["invalid_reason"].toString().isEmpty()) {
|
||||
qCDebug(entities) << "invalid_reason not empty";
|
||||
} else if (jsonObject["transfer_status"].toArray().first().toString() == "failed") {
|
||||
qCDebug(entities) << "'transfer_status' is 'failed'";
|
||||
} else if (jsonObject["transfer_status"].toArray().first().toString() == "pending") {
|
||||
qCDebug(entities) << "'transfer_status' is 'pending'";
|
||||
} else {
|
||||
QString ownerKey = jsonObject["transfer_recipient_key"].toString();
|
||||
|
||||
QByteArray certID = entityProperties.getCertificateID().toUtf8();
|
||||
QByteArray text = DependencyManager::get<EntityTreeRenderer>()->getTree()->computeNonce(certID, ownerKey);
|
||||
QByteArray nodeToChallengeByteArray = entityProperties.getOwningAvatarID().toRfc4122();
|
||||
|
||||
int certIDByteArraySize = certID.length();
|
||||
int textByteArraySize = text.length();
|
||||
int nodeToChallengeByteArraySize = nodeToChallengeByteArray.length();
|
||||
|
||||
auto challengeOwnershipPacket = NLPacket::create(PacketType::ChallengeOwnershipRequest,
|
||||
certIDByteArraySize + textByteArraySize + nodeToChallengeByteArraySize + 3 * sizeof(int),
|
||||
true);
|
||||
challengeOwnershipPacket->writePrimitive(certIDByteArraySize);
|
||||
challengeOwnershipPacket->writePrimitive(textByteArraySize);
|
||||
challengeOwnershipPacket->writePrimitive(nodeToChallengeByteArraySize);
|
||||
challengeOwnershipPacket->write(certID);
|
||||
challengeOwnershipPacket->write(text);
|
||||
challengeOwnershipPacket->write(nodeToChallengeByteArray);
|
||||
nodeList->sendPacket(std::move(challengeOwnershipPacket), *entityServer);
|
||||
|
||||
// Kickoff a 10-second timeout timer that marks the cert if we don't get an ownership response in time
|
||||
if (thread() != QThread::currentThread()) {
|
||||
QMetaObject::invokeMethod(this, "startChallengeOwnershipTimer");
|
||||
return;
|
||||
} else {
|
||||
startChallengeOwnershipTimer();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
qCDebug(entities) << "Call to" << networkReply->url() << "failed with error" << networkReply->error() <<
|
||||
"More info:" << networkReply->readAll();
|
||||
}
|
||||
|
||||
networkReply->deleteLater();
|
||||
});
|
||||
} else {
|
||||
qCWarning(context_overlay) << "Couldn't get Entity Server!";
|
||||
}
|
||||
} else {
|
||||
auto ledger = DependencyManager::get<Ledger>();
|
||||
_challengeOwnershipTimeoutTimer.stop();
|
||||
emit ledger->updateCertificateStatus(entityProperties.getCertificateID(), (uint)(ledger->CERTIFICATE_STATUS_STATIC_VERIFICATION_FAILED));
|
||||
emit DependencyManager::get<WalletScriptingInterface>()->ownershipVerificationFailed(_lastInspectedEntity);
|
||||
qCDebug(context_overlay) << "Entity" << _lastInspectedEntity << "failed static certificate verification!";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const QString INSPECTION_CERTIFICATE_QML_PATH = "hifi/commerce/inspectionCertificate/InspectionCertificate.qml";
|
||||
void ContextOverlayInterface::openInspectionCertificate() {
|
||||
// lets open the tablet to the inspection certificate QML
|
||||
|
@ -275,87 +362,7 @@ void ContextOverlayInterface::openInspectionCertificate() {
|
|||
_hmdScriptingInterface->openTablet();
|
||||
|
||||
setLastInspectedEntity(_currentEntityWithContextOverlay);
|
||||
|
||||
EntityItemProperties entityProperties = _entityScriptingInterface->getEntityProperties(_lastInspectedEntity, _entityPropertyFlags);
|
||||
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
if (entityProperties.getClientOnly()) {
|
||||
if (entityProperties.verifyStaticCertificateProperties()) {
|
||||
SharedNodePointer entityServer = nodeList->soloNodeOfType(NodeType::EntityServer);
|
||||
|
||||
if (entityServer) {
|
||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
QNetworkRequest networkRequest;
|
||||
networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
QUrl requestURL = NetworkingConstants::METAVERSE_SERVER_URL();
|
||||
requestURL.setPath("/api/v1/commerce/proof_of_purchase_status/transfer");
|
||||
QJsonObject request;
|
||||
request["certificate_id"] = entityProperties.getCertificateID();
|
||||
networkRequest.setUrl(requestURL);
|
||||
|
||||
QNetworkReply* networkReply = NULL;
|
||||
networkReply = networkAccessManager.put(networkRequest, QJsonDocument(request).toJson());
|
||||
|
||||
connect(networkReply, &QNetworkReply::finished, [=]() {
|
||||
QJsonObject jsonObject = QJsonDocument::fromJson(networkReply->readAll()).object();
|
||||
jsonObject = jsonObject["data"].toObject();
|
||||
|
||||
if (networkReply->error() == QNetworkReply::NoError) {
|
||||
if (!jsonObject["invalid_reason"].toString().isEmpty()) {
|
||||
qCDebug(entities) << "invalid_reason not empty";
|
||||
} else if (jsonObject["transfer_status"].toArray().first().toString() == "failed") {
|
||||
qCDebug(entities) << "'transfer_status' is 'failed'";
|
||||
} else if (jsonObject["transfer_status"].toArray().first().toString() == "pending") {
|
||||
qCDebug(entities) << "'transfer_status' is 'pending'";
|
||||
} else {
|
||||
QString ownerKey = jsonObject["transfer_recipient_key"].toString();
|
||||
|
||||
QByteArray certID = entityProperties.getCertificateID().toUtf8();
|
||||
QByteArray text = DependencyManager::get<EntityTreeRenderer>()->getTree()->computeNonce(certID, ownerKey);
|
||||
QByteArray nodeToChallengeByteArray = entityProperties.getOwningAvatarID().toRfc4122();
|
||||
|
||||
int certIDByteArraySize = certID.length();
|
||||
int textByteArraySize = text.length();
|
||||
int nodeToChallengeByteArraySize = nodeToChallengeByteArray.length();
|
||||
|
||||
auto challengeOwnershipPacket = NLPacket::create(PacketType::ChallengeOwnershipRequest,
|
||||
certIDByteArraySize + textByteArraySize + nodeToChallengeByteArraySize + 3 * sizeof(int),
|
||||
true);
|
||||
challengeOwnershipPacket->writePrimitive(certIDByteArraySize);
|
||||
challengeOwnershipPacket->writePrimitive(textByteArraySize);
|
||||
challengeOwnershipPacket->writePrimitive(nodeToChallengeByteArraySize);
|
||||
challengeOwnershipPacket->write(certID);
|
||||
challengeOwnershipPacket->write(text);
|
||||
challengeOwnershipPacket->write(nodeToChallengeByteArray);
|
||||
nodeList->sendPacket(std::move(challengeOwnershipPacket), *entityServer);
|
||||
|
||||
// Kickoff a 10-second timeout timer that marks the cert if we don't get an ownership response in time
|
||||
if (thread() != QThread::currentThread()) {
|
||||
QMetaObject::invokeMethod(this, "startChallengeOwnershipTimer");
|
||||
return;
|
||||
} else {
|
||||
startChallengeOwnershipTimer();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
qCDebug(entities) << "Call to" << networkReply->url() << "failed with error" << networkReply->error() <<
|
||||
"More info:" << networkReply->readAll();
|
||||
}
|
||||
|
||||
networkReply->deleteLater();
|
||||
});
|
||||
} else {
|
||||
qCWarning(context_overlay) << "Couldn't get Entity Server!";
|
||||
}
|
||||
} else {
|
||||
auto ledger = DependencyManager::get<Ledger>();
|
||||
_challengeOwnershipTimeoutTimer.stop();
|
||||
emit ledger->updateCertificateStatus(entityProperties.getCertificateID(), (uint)(ledger->CERTIFICATE_STATUS_STATIC_VERIFICATION_FAILED));
|
||||
qCDebug(context_overlay) << "Entity" << _lastInspectedEntity << "failed static certificate verification!";
|
||||
}
|
||||
}
|
||||
requestOwnershipVerification(_lastInspectedEntity);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -397,6 +404,7 @@ void ContextOverlayInterface::startChallengeOwnershipTimer() {
|
|||
connect(&_challengeOwnershipTimeoutTimer, &QTimer::timeout, this, [=]() {
|
||||
qCDebug(entities) << "Ownership challenge timed out for" << _lastInspectedEntity;
|
||||
emit ledger->updateCertificateStatus(entityProperties.getCertificateID(), (uint)(ledger->CERTIFICATE_STATUS_VERIFICATION_TIMEOUT));
|
||||
emit DependencyManager::get<WalletScriptingInterface>()->ownershipVerificationFailed(_lastInspectedEntity);
|
||||
});
|
||||
|
||||
_challengeOwnershipTimeoutTimer.start(5000);
|
||||
|
@ -421,7 +429,9 @@ void ContextOverlayInterface::handleChallengeOwnershipReplyPacket(QSharedPointer
|
|||
|
||||
if (verificationSuccess) {
|
||||
emit ledger->updateCertificateStatus(certID, (uint)(ledger->CERTIFICATE_STATUS_VERIFICATION_SUCCESS));
|
||||
emit DependencyManager::get<WalletScriptingInterface>()->ownershipVerificationSuccess(_lastInspectedEntity);
|
||||
} else {
|
||||
emit ledger->updateCertificateStatus(certID, (uint)(ledger->CERTIFICATE_STATUS_OWNER_VERIFICATION_FAILED));
|
||||
emit DependencyManager::get<WalletScriptingInterface>()->ownershipVerificationFailed(_lastInspectedEntity);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "ui/overlays/Overlays.h"
|
||||
#include "scripting/HMDScriptingInterface.h"
|
||||
#include "scripting/SelectionScriptingInterface.h"
|
||||
#include "scripting/WalletScriptingInterface.h"
|
||||
|
||||
#include "EntityTree.h"
|
||||
#include "ContextOverlayLogging.h"
|
||||
|
@ -33,12 +34,13 @@
|
|||
/**jsdoc
|
||||
* @namespace ContextOverlay
|
||||
*/
|
||||
class ContextOverlayInterface : public QObject, public Dependency {
|
||||
class ContextOverlayInterface : public QObject, public Dependency {
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QUuid entityWithContextOverlay READ getCurrentEntityWithContextOverlay WRITE setCurrentEntityWithContextOverlay)
|
||||
Q_PROPERTY(bool enabled READ getEnabled WRITE setEnabled)
|
||||
Q_PROPERTY(bool isInMarketplaceInspectionMode READ getIsInMarketplaceInspectionMode WRITE setIsInMarketplaceInspectionMode)
|
||||
|
||||
QSharedPointer<EntityScriptingInterface> _entityScriptingInterface;
|
||||
EntityPropertyFlags _entityPropertyFlags;
|
||||
QSharedPointer<HMDScriptingInterface> _hmdScriptingInterface;
|
||||
|
@ -47,9 +49,7 @@ class ContextOverlayInterface : public QObject, public Dependency {
|
|||
OverlayID _contextOverlayID { UNKNOWN_OVERLAY_ID };
|
||||
std::shared_ptr<Image3DOverlay> _contextOverlay { nullptr };
|
||||
public:
|
||||
|
||||
ContextOverlayInterface();
|
||||
|
||||
Q_INVOKABLE QUuid getCurrentEntityWithContextOverlay() { return _currentEntityWithContextOverlay; }
|
||||
void setCurrentEntityWithContextOverlay(const QUuid& entityID) { _currentEntityWithContextOverlay = entityID; }
|
||||
void setLastInspectedEntity(const QUuid& entityID) { _challengeOwnershipTimeoutTimer.stop(); _lastInspectedEntity = entityID; }
|
||||
|
@ -57,6 +57,8 @@ public:
|
|||
bool getEnabled() { return _enabled; }
|
||||
bool getIsInMarketplaceInspectionMode() { return _isInMarketplaceInspectionMode; }
|
||||
void setIsInMarketplaceInspectionMode(bool mode) { _isInMarketplaceInspectionMode = mode; }
|
||||
void requestOwnershipVerification(const QUuid& entityID);
|
||||
EntityPropertyFlags getEntityPropertyFlags() { return _entityPropertyFlags; }
|
||||
|
||||
signals:
|
||||
void contextOverlayClicked(const QUuid& currentEntityWithContextOverlay);
|
||||
|
@ -80,8 +82,7 @@ private:
|
|||
enum {
|
||||
MAX_SELECTION_COUNT = 16
|
||||
};
|
||||
|
||||
bool _verboseLogging { true };
|
||||
bool _verboseLogging{ true };
|
||||
bool _enabled { true };
|
||||
EntityItemID _currentEntityWithContextOverlay{};
|
||||
EntityItemID _lastInspectedEntity{};
|
||||
|
|
|
@ -880,25 +880,6 @@ const AnimPoseVec& AnimInverseKinematics::evaluate(const AnimVariantMap& animVar
|
|||
return _relativePoses;
|
||||
}
|
||||
|
||||
AnimPose AnimInverseKinematics::applyHipsOffset() const {
|
||||
glm::vec3 hipsOffset = _hipsOffset;
|
||||
AnimPose relHipsPose = _relativePoses[_hipsIndex];
|
||||
float offsetLength = glm::length(hipsOffset);
|
||||
const float MIN_HIPS_OFFSET_LENGTH = 0.03f;
|
||||
if (offsetLength > MIN_HIPS_OFFSET_LENGTH) {
|
||||
float scaleFactor = ((offsetLength - MIN_HIPS_OFFSET_LENGTH) / offsetLength);
|
||||
glm::vec3 scaledHipsOffset = scaleFactor * hipsOffset;
|
||||
if (_hipsParentIndex == -1) {
|
||||
relHipsPose.trans() = _relativePoses[_hipsIndex].trans() + scaledHipsOffset;
|
||||
} else {
|
||||
AnimPose absHipsPose = _skeleton->getAbsolutePose(_hipsIndex, _relativePoses);
|
||||
absHipsPose.trans() += scaledHipsOffset;
|
||||
relHipsPose = _skeleton->getAbsolutePose(_hipsParentIndex, _relativePoses).inverse() * absHipsPose;
|
||||
}
|
||||
}
|
||||
return relHipsPose;
|
||||
}
|
||||
|
||||
//virtual
|
||||
const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars, const AnimContext& context, float dt, Triggers& triggersOut, const AnimPoseVec& underPoses) {
|
||||
// allows solutionSource to be overridden by an animVar
|
||||
|
@ -996,27 +977,6 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
|
|||
|
||||
_relativePoses[_hipsIndex] = parentAbsPose.inverse() * absPose;
|
||||
_relativePoses[_hipsIndex].scale() = glm::vec3(1.0f);
|
||||
_hipsOffset = Vectors::ZERO;
|
||||
|
||||
} else if (_hipsIndex >= 0) {
|
||||
|
||||
// if there is no hips target, shift hips according to the _hipsOffset from the previous frame
|
||||
AnimPose relHipsPose = applyHipsOffset();
|
||||
|
||||
// determine if we should begin interpolating the hips.
|
||||
for (size_t i = 0; i < targets.size(); i++) {
|
||||
if (_prevJointChainInfoVec[i].target.getIndex() == _hipsIndex) {
|
||||
if (_prevJointChainInfoVec[i].timer > 0.0f) {
|
||||
// smoothly lerp in hipsOffset
|
||||
float alpha = (JOINT_CHAIN_INTERP_TIME - _prevJointChainInfoVec[i].timer) / JOINT_CHAIN_INTERP_TIME;
|
||||
AnimPose prevRelHipsPose(_prevJointChainInfoVec[i].jointInfoVec[0].rot, _prevJointChainInfoVec[i].jointInfoVec[0].trans);
|
||||
::blend(1, &prevRelHipsPose, &relHipsPose, alpha, &relHipsPose);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_relativePoses[_hipsIndex] = relHipsPose;
|
||||
}
|
||||
|
||||
// if there is an active jointChainInfo for the hips store the post shifted hips into it.
|
||||
|
@ -1084,11 +1044,6 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
|
|||
|
||||
solve(context, targets, dt, jointChainInfoVec);
|
||||
}
|
||||
|
||||
if (_hipsTargetIndex < 0) {
|
||||
PROFILE_RANGE_EX(simulation_animation, "ik/measureHipsOffset", 0xffff00ff, 0);
|
||||
_hipsOffset = computeHipsOffset(targets, underPoses, dt, _hipsOffset);
|
||||
}
|
||||
}
|
||||
|
||||
if (context.getEnableDebugDrawIKConstraints()) {
|
||||
|
@ -1099,69 +1054,6 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars
|
|||
return _relativePoses;
|
||||
}
|
||||
|
||||
glm::vec3 AnimInverseKinematics::computeHipsOffset(const std::vector<IKTarget>& targets, const AnimPoseVec& underPoses, float dt, glm::vec3 prevHipsOffset) const {
|
||||
|
||||
// measure new _hipsOffset for next frame
|
||||
// by looking for discrepancies between where a targeted endEffector is
|
||||
// and where it wants to be (after IK solutions are done)
|
||||
glm::vec3 hipsOffset = prevHipsOffset;
|
||||
glm::vec3 newHipsOffset = Vectors::ZERO;
|
||||
for (auto& target: targets) {
|
||||
int targetIndex = target.getIndex();
|
||||
if (targetIndex == _headIndex && _headIndex != -1) {
|
||||
// special handling for headTarget
|
||||
if (target.getType() == IKTarget::Type::RotationOnly) {
|
||||
// we want to shift the hips to bring the underPose closer
|
||||
// to where the head happens to be (overpose)
|
||||
glm::vec3 under = _skeleton->getAbsolutePose(_headIndex, underPoses).trans();
|
||||
glm::vec3 actual = _skeleton->getAbsolutePose(_headIndex, _relativePoses).trans();
|
||||
const float HEAD_OFFSET_SLAVE_FACTOR = 0.65f;
|
||||
newHipsOffset += HEAD_OFFSET_SLAVE_FACTOR * (actual - under);
|
||||
} else if (target.getType() == IKTarget::Type::HmdHead) {
|
||||
// we want to shift the hips to bring the head to its designated position
|
||||
glm::vec3 actual = _skeleton->getAbsolutePose(_headIndex, _relativePoses).trans();
|
||||
hipsOffset += target.getTranslation() - actual;
|
||||
// and ignore all other targets
|
||||
newHipsOffset = hipsOffset;
|
||||
break;
|
||||
} else if (target.getType() == IKTarget::Type::RotationAndPosition) {
|
||||
glm::vec3 actualPosition = _skeleton->getAbsolutePose(targetIndex, _relativePoses).trans();
|
||||
glm::vec3 targetPosition = target.getTranslation();
|
||||
newHipsOffset += targetPosition - actualPosition;
|
||||
|
||||
// Add downward pressure on the hips
|
||||
const float PRESSURE_SCALE_FACTOR = 0.95f;
|
||||
const float PRESSURE_TRANSLATION_OFFSET = 1.0f;
|
||||
newHipsOffset *= PRESSURE_SCALE_FACTOR;
|
||||
newHipsOffset -= PRESSURE_TRANSLATION_OFFSET;
|
||||
}
|
||||
} else if (target.getType() == IKTarget::Type::RotationAndPosition) {
|
||||
glm::vec3 actualPosition = _skeleton->getAbsolutePose(targetIndex, _relativePoses).trans();
|
||||
glm::vec3 targetPosition = target.getTranslation();
|
||||
newHipsOffset += targetPosition - actualPosition;
|
||||
}
|
||||
}
|
||||
|
||||
// smooth transitions by relaxing hipsOffset toward the new value
|
||||
const float HIPS_OFFSET_SLAVE_TIMESCALE = 0.10f;
|
||||
float tau = dt < HIPS_OFFSET_SLAVE_TIMESCALE ? dt / HIPS_OFFSET_SLAVE_TIMESCALE : 1.0f;
|
||||
hipsOffset += (newHipsOffset - hipsOffset) * tau;
|
||||
|
||||
// clamp the hips offset
|
||||
float hipsOffsetLength = glm::length(hipsOffset);
|
||||
if (hipsOffsetLength > _maxHipsOffsetLength) {
|
||||
hipsOffset *= _maxHipsOffsetLength / hipsOffsetLength;
|
||||
}
|
||||
|
||||
return hipsOffset;
|
||||
}
|
||||
|
||||
void AnimInverseKinematics::setMaxHipsOffsetLength(float maxLength) {
|
||||
// manually adjust scale here
|
||||
const float METERS_TO_CENTIMETERS = 100.0f;
|
||||
_maxHipsOffsetLength = METERS_TO_CENTIMETERS * maxLength;
|
||||
}
|
||||
|
||||
void AnimInverseKinematics::clearIKJointLimitHistory() {
|
||||
for (auto& pair : _constraints) {
|
||||
pair.second->clearHistory();
|
||||
|
|
|
@ -57,8 +57,6 @@ public:
|
|||
|
||||
void clearIKJointLimitHistory();
|
||||
|
||||
void setMaxHipsOffsetLength(float maxLength);
|
||||
|
||||
float getMaxErrorOnLastSolve() { return _maxErrorOnLastSolve; }
|
||||
|
||||
enum class SolutionSource {
|
||||
|
@ -92,7 +90,6 @@ protected:
|
|||
void blendToPoses(const AnimPoseVec& targetPoses, const AnimPoseVec& underPose, float blendFactor);
|
||||
void preconditionRelativePosesToAvoidLimbLock(const AnimContext& context, const std::vector<IKTarget>& targets);
|
||||
void setSecondaryTargets(const AnimContext& context);
|
||||
AnimPose applyHipsOffset() const;
|
||||
|
||||
// used to pre-compute information about each joint influeced by a spline IK target.
|
||||
struct SplineJointInfo {
|
||||
|
@ -111,7 +108,6 @@ protected:
|
|||
void clearConstraints();
|
||||
void initConstraints();
|
||||
void initLimitCenterPoses();
|
||||
glm::vec3 computeHipsOffset(const std::vector<IKTarget>& targets, const AnimPoseVec& underPoses, float dt, glm::vec3 prevHipsOffset) const;
|
||||
|
||||
// no copies
|
||||
AnimInverseKinematics(const AnimInverseKinematics&) = delete;
|
||||
|
@ -150,9 +146,6 @@ protected:
|
|||
|
||||
mutable std::map<int, std::vector<SplineJointInfo>> _splineJointInfoMap;
|
||||
|
||||
// experimental data for moving hips during IK
|
||||
glm::vec3 _hipsOffset { Vectors::ZERO };
|
||||
float _maxHipsOffsetLength{ FLT_MAX };
|
||||
int _headIndex { -1 };
|
||||
int _hipsIndex { -1 };
|
||||
int _hipsParentIndex { -1 };
|
||||
|
|
|
@ -372,18 +372,6 @@ void Rig::clearIKJointLimitHistory() {
|
|||
}
|
||||
}
|
||||
|
||||
void Rig::setMaxHipsOffsetLength(float maxLength) {
|
||||
_maxHipsOffsetLength = maxLength;
|
||||
auto ikNode = getAnimInverseKinematicsNode();
|
||||
if (ikNode) {
|
||||
ikNode->setMaxHipsOffsetLength(_maxHipsOffsetLength);
|
||||
}
|
||||
}
|
||||
|
||||
float Rig::getMaxHipsOffsetLength() const {
|
||||
return _maxHipsOffsetLength;
|
||||
}
|
||||
|
||||
float Rig::getIKErrorOnLastSolve() const {
|
||||
float result = 0.0f;
|
||||
|
||||
|
|
|
@ -346,7 +346,6 @@ protected:
|
|||
bool _enabledAnimations { true };
|
||||
|
||||
mutable uint32_t _jointNameWarningCount { 0 };
|
||||
float _maxHipsOffsetLength { 1.0f };
|
||||
|
||||
bool _enableDebugDrawIKTargets { false };
|
||||
bool _enableDebugDrawIKConstraints { false };
|
||||
|
|
|
@ -51,9 +51,9 @@ void EntityScriptServerLogClient::enableToEntityServerScriptLog(bool enable) {
|
|||
|
||||
if (_subscribed != enable) {
|
||||
if (enable) {
|
||||
emit receivedNewLogLines("====================== Subscribded to the Entity Script Server's log ======================");
|
||||
emit receivedNewLogLines("====================== Subscribed to the Entity Script Server's log ======================");
|
||||
} else {
|
||||
emit receivedNewLogLines("==================== Unsubscribded from the Entity Script Server's log ====================");
|
||||
emit receivedNewLogLines("==================== Unsubscribed from the Entity Script Server's log ====================");
|
||||
}
|
||||
}
|
||||
_subscribed = enable;
|
||||
|
|
|
@ -1455,18 +1455,22 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
QSet<QString> remainingModels;
|
||||
for (QHash<QString, FBXModel>::const_iterator model = models.constBegin(); model != models.constEnd(); model++) {
|
||||
// models with clusters must be parented to the cluster top
|
||||
foreach (const QString& deformerID, _connectionChildMap.values(model.key())) {
|
||||
foreach (const QString& clusterID, _connectionChildMap.values(deformerID)) {
|
||||
if (!clusters.contains(clusterID)) {
|
||||
continue;
|
||||
// Unless the model is a root node.
|
||||
bool isARootNode = !modelIDs.contains(_connectionParentMap.value(model.key()));
|
||||
if (!isARootNode) {
|
||||
foreach(const QString& deformerID, _connectionChildMap.values(model.key())) {
|
||||
foreach(const QString& clusterID, _connectionChildMap.values(deformerID)) {
|
||||
if (!clusters.contains(clusterID)) {
|
||||
continue;
|
||||
}
|
||||
QString topID = getTopModelID(_connectionParentMap, models, _connectionChildMap.value(clusterID), url);
|
||||
_connectionChildMap.remove(_connectionParentMap.take(model.key()), model.key());
|
||||
_connectionParentMap.insert(model.key(), topID);
|
||||
goto outerBreak;
|
||||
}
|
||||
QString topID = getTopModelID(_connectionParentMap, models, _connectionChildMap.value(clusterID), url);
|
||||
_connectionChildMap.remove(_connectionParentMap.take(model.key()), model.key());
|
||||
_connectionParentMap.insert(model.key(), topID);
|
||||
goto outerBreak;
|
||||
}
|
||||
outerBreak: ;
|
||||
}
|
||||
outerBreak:
|
||||
|
||||
// make sure the parent is in the child map
|
||||
QString parent = _connectionParentMap.value(model.key());
|
||||
|
@ -1477,11 +1481,6 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
}
|
||||
while (!remainingModels.isEmpty()) {
|
||||
QString first = *remainingModels.constBegin();
|
||||
foreach (const QString& id, remainingModels) {
|
||||
if (id < first) {
|
||||
first = id;
|
||||
}
|
||||
}
|
||||
QString topID = getTopModelID(_connectionParentMap, models, first, url);
|
||||
appendModelIDs(_connectionParentMap.value(topID), _connectionChildMap, models, remainingModels, modelIDs, true);
|
||||
}
|
||||
|
|
|
@ -248,7 +248,8 @@ enum class AvatarMixerPacketVersion : PacketVersion {
|
|||
IsReplicatedInAvatarIdentity,
|
||||
AvatarIdentityLookAtSnapping,
|
||||
UpdatedMannequinDefaultAvatar,
|
||||
AvatarJointDefaultPoseFlags
|
||||
AvatarJointDefaultPoseFlags,
|
||||
FBXReaderNodeReparenting
|
||||
};
|
||||
|
||||
enum class DomainConnectRequestVersion : PacketVersion {
|
||||
|
|
|
@ -238,9 +238,9 @@ void CauterizedModel::updateRenderItems() {
|
|||
renderTransform = modelTransform;
|
||||
if (clusterTransformsCauterized.size() == 1) {
|
||||
#if defined(SKIN_DQ)
|
||||
Transform transform(clusterTransforms[0].getRotation(),
|
||||
clusterTransforms[0].getScale(),
|
||||
clusterTransforms[0].getTranslation());
|
||||
Transform transform(clusterTransformsCauterized[0].getRotation(),
|
||||
clusterTransformsCauterized[0].getScale(),
|
||||
clusterTransformsCauterized[0].getTranslation());
|
||||
renderTransform = modelTransform.worldTransform(Transform(transform));
|
||||
#else
|
||||
renderTransform = modelTransform.worldTransform(Transform(clusterTransformsCauterized[0]));
|
||||
|
|
|
@ -227,7 +227,7 @@ bool QmlWindowClass::isVisible() {
|
|||
glm::vec2 QmlWindowClass::getPosition() {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
vec2 result;
|
||||
BLOCKING_INVOKE_METHOD(this, "getPosition", Q_RETURN_ARG(vec2, result));
|
||||
BLOCKING_INVOKE_METHOD(this, "getPosition", Q_RETURN_ARG(glm::vec2, result));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -241,7 +241,7 @@ glm::vec2 QmlWindowClass::getPosition() {
|
|||
|
||||
void QmlWindowClass::setPosition(const glm::vec2& position) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "setPosition", Q_ARG(vec2, position));
|
||||
QMetaObject::invokeMethod(this, "setPosition", Q_ARG(const glm::vec2&, position));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -262,7 +262,7 @@ glm::vec2 toGlm(const QSizeF& size) {
|
|||
glm::vec2 QmlWindowClass::getSize() {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
vec2 result;
|
||||
BLOCKING_INVOKE_METHOD(this, "getSize", Q_RETURN_ARG(vec2, result));
|
||||
BLOCKING_INVOKE_METHOD(this, "getSize", Q_RETURN_ARG(glm::vec2, result));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -275,7 +275,7 @@ glm::vec2 QmlWindowClass::getSize() {
|
|||
|
||||
void QmlWindowClass::setSize(const glm::vec2& size) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "setSize", Q_ARG(vec2, size));
|
||||
QMetaObject::invokeMethod(this, "setSize", Q_ARG(const glm::vec2&, size));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,14 +22,37 @@ if (scripts.length >= 2) {
|
|||
// Set up the qml ui
|
||||
var qml = Script.resolvePath('debugWindow.qml');
|
||||
|
||||
var HMD_DEBUG_WINDOW_GEOMETRY_KEY = 'hmdDebugWindowGeometry';
|
||||
var hmdDebugWindowGeometryValue = Settings.getValue(HMD_DEBUG_WINDOW_GEOMETRY_KEY)
|
||||
|
||||
var windowWidth = 400;
|
||||
var windowHeight = 900;
|
||||
|
||||
var hasPosition = false;
|
||||
var windowX = 0;
|
||||
var windowY = 0;
|
||||
|
||||
if (hmdDebugWindowGeometryValue !== '') {
|
||||
var geometry = JSON.parse(hmdDebugWindowGeometryValue);
|
||||
|
||||
windowWidth = geometry.width
|
||||
windowHeight = geometry.height
|
||||
windowX = geometry.x
|
||||
windowY = geometry.y
|
||||
hasPosition = true;
|
||||
}
|
||||
|
||||
var window = new OverlayWindow({
|
||||
title: 'Debug Window',
|
||||
source: qml,
|
||||
width: 400, height: 900,
|
||||
width: windowWidth, height: windowHeight,
|
||||
});
|
||||
|
||||
window.setPosition(25, 50);
|
||||
window.closed.connect(function() { Script.stop(); });
|
||||
if (hasPosition) {
|
||||
window.setPosition(windowX, windowY);
|
||||
}
|
||||
|
||||
window.closed.connect(function () { Script.stop(); });
|
||||
|
||||
var getFormattedDate = function() {
|
||||
var date = new Date();
|
||||
|
@ -65,6 +88,14 @@ ScriptDiscoveryService.clearDebugWindow.connect(function() {
|
|||
});
|
||||
|
||||
Script.scriptEnding.connect(function () {
|
||||
var geometry = JSON.stringify({
|
||||
x: window.position.x,
|
||||
y: window.position.y,
|
||||
width: window.size.x,
|
||||
height: window.size.y
|
||||
})
|
||||
|
||||
Settings.setValue(HMD_DEBUG_WINDOW_GEOMETRY_KEY, geometry);
|
||||
window.close();
|
||||
})
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
getControllerJointIndex, enableDispatcherModule, disableDispatcherModule,
|
||||
Messages, makeDispatcherModuleParameters, makeRunningValues, Settings, entityHasActions,
|
||||
Vec3, Overlays, flatten, Xform, getControllerWorldLocation, ensureDynamic, entityIsCloneable,
|
||||
cloneEntity, DISPATCHER_PROPERTIES, TEAR_AWAY_DISTANCE
|
||||
cloneEntity, DISPATCHER_PROPERTIES, TEAR_AWAY_DISTANCE, Uuid
|
||||
*/
|
||||
|
||||
Script.include("/~/system/libraries/Xform.js");
|
||||
|
@ -269,6 +269,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
|
|||
this.grabEntityProps = null;
|
||||
this.shouldSendStart = false;
|
||||
this.equipedWithSecondary = false;
|
||||
this.handHasBeenRightsideUp = false;
|
||||
|
||||
this.parameters = makeDispatcherModuleParameters(
|
||||
300,
|
||||
|
@ -486,15 +487,17 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
|
|||
var grabbedProperties = Entities.getEntityProperties(this.targetEntityID);
|
||||
|
||||
// if an object is "equipped" and has a predefined offset, use it.
|
||||
var offsets = getAttachPointForHotspotFromSettings(this.grabbedHotspot, this.hand);
|
||||
if (offsets) {
|
||||
this.offsetPosition = offsets[0];
|
||||
this.offsetRotation = offsets[1];
|
||||
} else {
|
||||
var handJointName = this.hand === RIGHT_HAND ? "RightHand" : "LeftHand";
|
||||
if (this.grabbedHotspot.joints[handJointName]) {
|
||||
this.offsetPosition = this.grabbedHotspot.joints[handJointName][0];
|
||||
this.offsetRotation = this.grabbedHotspot.joints[handJointName][1];
|
||||
if (this.grabbedHotspot) {
|
||||
var offsets = getAttachPointForHotspotFromSettings(this.grabbedHotspot, this.hand);
|
||||
if (offsets) {
|
||||
this.offsetPosition = offsets[0];
|
||||
this.offsetRotation = offsets[1];
|
||||
} else {
|
||||
var handJointName = this.hand === RIGHT_HAND ? "RightHand" : "LeftHand";
|
||||
if (this.grabbedHotspot.joints[handJointName]) {
|
||||
this.offsetPosition = this.grabbedHotspot.joints[handJointName][0];
|
||||
this.offsetRotation = this.grabbedHotspot.joints[handJointName][1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -549,7 +552,6 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
|
|||
// 100 ms seems to be sufficient time to force the check even occur after the object has been initialized.
|
||||
Script.setTimeout(grabEquipCheck, 100);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.endEquipEntity = function () {
|
||||
|
@ -624,7 +626,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
|
|||
this.grabbedHotspot = potentialEquipHotspot;
|
||||
this.targetEntityID = this.grabbedHotspot.entityID;
|
||||
this.startEquipEntity(controllerData);
|
||||
this.messageGrabEnity = false;
|
||||
this.messageGrabEntity = false;
|
||||
this.equipedWithSecondary = this.secondarySmoothedSqueezed();
|
||||
return makeRunningValues(true, [potentialEquipHotspot.entityID], []);
|
||||
} else {
|
||||
|
@ -640,6 +642,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
|
|||
this.isReady = function (controllerData, deltaTime) {
|
||||
var timestamp = Date.now();
|
||||
this.updateInputs(controllerData);
|
||||
this.handHasBeenRightsideUp = false;
|
||||
return this.checkNearbyHotspots(controllerData, deltaTime, timestamp);
|
||||
};
|
||||
|
||||
|
@ -671,7 +674,14 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
|
|||
return makeRunningValues(false, [], []);
|
||||
}
|
||||
|
||||
var dropDetected = this.dropGestureProcess(deltaTime);
|
||||
var handIsUpsideDown = this.dropGestureProcess(deltaTime);
|
||||
var dropDetected = false;
|
||||
if (this.handHasBeenRightsideUp) {
|
||||
dropDetected = handIsUpsideDown;
|
||||
}
|
||||
if (!handIsUpsideDown) {
|
||||
this.handHasBeenRightsideUp = true;
|
||||
}
|
||||
|
||||
if (this.triggerSmoothedReleased() || this.secondaryReleased()) {
|
||||
if (this.shouldSendStart) {
|
||||
|
@ -692,7 +702,7 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
|
|||
}
|
||||
|
||||
// highlight the grabbed hotspot when the dropGesture is detected.
|
||||
if (dropDetected) {
|
||||
if (dropDetected && this.grabbedHotspot) {
|
||||
equipHotspotBuddy.updateHotspot(this.grabbedHotspot, timestamp);
|
||||
equipHotspotBuddy.highlightHotspot(this.grabbedHotspot);
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ colpick Color Picker / colpick.com
|
|||
/*Color selection box with gradients*/
|
||||
.colpick_color {
|
||||
position: absolute;
|
||||
touch-action: none;
|
||||
left: 7px;
|
||||
top: 7px;
|
||||
width: 156px;
|
||||
|
@ -84,6 +85,7 @@ colpick Color Picker / colpick.com
|
|||
/*Vertical hue bar*/
|
||||
.colpick_hue {
|
||||
position: absolute;
|
||||
touch-action: none;
|
||||
top: 6px;
|
||||
left: 175px;
|
||||
width: 19px;
|
||||
|
@ -94,6 +96,7 @@ colpick Color Picker / colpick.com
|
|||
/*Hue bar sliding indicator*/
|
||||
.colpick_hue_arrs {
|
||||
position: absolute;
|
||||
touch-action: none;
|
||||
left: -8px;
|
||||
width: 35px;
|
||||
height: 7px;
|
||||
|
@ -101,6 +104,7 @@ colpick Color Picker / colpick.com
|
|||
}
|
||||
.colpick_hue_larr {
|
||||
position:absolute;
|
||||
touch-action: none;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-top: 6px solid transparent;
|
||||
|
@ -109,6 +113,7 @@ colpick Color Picker / colpick.com
|
|||
}
|
||||
.colpick_hue_rarr {
|
||||
position:absolute;
|
||||
touch-action: none;
|
||||
right:0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
|
@ -119,6 +124,7 @@ colpick Color Picker / colpick.com
|
|||
/*New color box*/
|
||||
.colpick_new_color {
|
||||
position: absolute;
|
||||
touch-action: none;
|
||||
left: 207px;
|
||||
top: 6px;
|
||||
width: 60px;
|
||||
|
@ -129,6 +135,7 @@ colpick Color Picker / colpick.com
|
|||
/*Current color box*/
|
||||
.colpick_current_color {
|
||||
position: absolute;
|
||||
touch-action: none;
|
||||
left: 277px;
|
||||
top: 6px;
|
||||
width: 60px;
|
||||
|
@ -139,6 +146,7 @@ colpick Color Picker / colpick.com
|
|||
/*Input field containers*/
|
||||
.colpick_field, .colpick_hex_field {
|
||||
position: absolute;
|
||||
touch-action: none;
|
||||
height: 20px;
|
||||
width: 60px;
|
||||
overflow:hidden;
|
||||
|
@ -198,6 +206,7 @@ colpick Color Picker / colpick.com
|
|||
/*Text inputs*/
|
||||
.colpick_field input, .colpick_hex_field input {
|
||||
position: absolute;
|
||||
touch-action: none;
|
||||
right: 11px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
@ -217,6 +226,7 @@ colpick Color Picker / colpick.com
|
|||
/*Field up/down arrows*/
|
||||
.colpick_field_arrs {
|
||||
position: absolute;
|
||||
touch-action: none;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 9px;
|
||||
|
@ -225,6 +235,7 @@ colpick Color Picker / colpick.com
|
|||
}
|
||||
.colpick_field_uarr {
|
||||
position: absolute;
|
||||
touch-action: none;
|
||||
top: 5px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
|
@ -234,6 +245,7 @@ colpick Color Picker / colpick.com
|
|||
}
|
||||
.colpick_field_darr {
|
||||
position: absolute;
|
||||
touch-action: none;
|
||||
bottom:5px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
|
@ -244,6 +256,7 @@ colpick Color Picker / colpick.com
|
|||
/*Submit/Select button*/
|
||||
.colpick_submit {
|
||||
position: absolute;
|
||||
touch-action: none;
|
||||
left: 207px;
|
||||
top: 149px;
|
||||
width: 130px;
|
||||
|
|
|
@ -653,16 +653,16 @@ function loaded() {
|
|||
var elZoneKeyLightDirectionY = document.getElementById("property-zone-key-light-direction-y");
|
||||
|
||||
// Skybox
|
||||
var elZoneSkyboxModeInherit = document.getElementById("property-zone-skybox-mode-inherit");
|
||||
var elZoneSkyboxModeInherit = document.getElementById("property-zone-skybox-mode-inherit");
|
||||
var elZoneSkyboxModeDisabled = document.getElementById("property-zone-skybox-mode-disabled");
|
||||
var elZoneSkyboxModeEnabled = document.getElementById("property-zone-skybox-mode-enabled");
|
||||
var elZoneSkyboxModeEnabled = document.getElementById("property-zone-skybox-mode-enabled");
|
||||
|
||||
// Ambient light
|
||||
var elCopySkyboxURLToAmbientURL = document.getElementById("copy-skybox-url-to-ambient-url");
|
||||
|
||||
var elZoneAmbientLightModeInherit = document.getElementById("property-zone-ambient-light-mode-inherit");
|
||||
var elZoneAmbientLightModeInherit = document.getElementById("property-zone-ambient-light-mode-inherit");
|
||||
var elZoneAmbientLightModeDisabled = document.getElementById("property-zone-ambient-light-mode-disabled");
|
||||
var elZoneAmbientLightModeEnabled = document.getElementById("property-zone-ambient-light-mode-enabled");
|
||||
var elZoneAmbientLightModeEnabled = document.getElementById("property-zone-ambient-light-mode-enabled");
|
||||
|
||||
var elZoneAmbientLightIntensity = document.getElementById("property-zone-key-ambient-intensity");
|
||||
var elZoneAmbientLightURL = document.getElementById("property-zone-key-ambient-url");
|
||||
|
@ -1013,9 +1013,9 @@ function loaded() {
|
|||
|
||||
} else if (properties.type === "Zone") {
|
||||
// Key light
|
||||
elZoneKeyLightModeInherit.checked = (properties.keyLightMode === 'inherit');
|
||||
elZoneKeyLightModeInherit.checked = (properties.keyLightMode === 'inherit');
|
||||
elZoneKeyLightModeDisabled.checked = (properties.keyLightMode === 'disabled');
|
||||
elZoneKeyLightModeEnabled.checked = (properties.keyLightMode === 'enabled');
|
||||
elZoneKeyLightModeEnabled.checked = (properties.keyLightMode === 'enabled');
|
||||
|
||||
elZoneKeyLightColor.style.backgroundColor = "rgb(" + properties.keyLight.color.red + "," +
|
||||
properties.keyLight.color.green + "," + properties.keyLight.color.blue + ")";
|
||||
|
@ -1027,22 +1027,22 @@ function loaded() {
|
|||
elZoneKeyLightDirectionY.value = properties.keyLight.direction.y.toFixed(2);
|
||||
|
||||
// Skybox
|
||||
elZoneSkyboxModeInherit.checked = (properties.skyboxMode === 'inherit');
|
||||
elZoneSkyboxModeInherit.checked = (properties.skyboxMode === 'inherit');
|
||||
elZoneSkyboxModeDisabled.checked = (properties.skyboxMode === 'disabled');
|
||||
elZoneSkyboxModeEnabled.checked = (properties.skyboxMode === 'enabled');
|
||||
elZoneSkyboxModeEnabled.checked = (properties.skyboxMode === 'enabled');
|
||||
|
||||
// Ambient light
|
||||
elZoneAmbientLightModeInherit.checked = (properties.ambientLightMode === 'inherit');
|
||||
elZoneAmbientLightModeInherit.checked = (properties.ambientLightMode === 'inherit');
|
||||
elZoneAmbientLightModeDisabled.checked = (properties.ambientLightMode === 'disabled');
|
||||
elZoneAmbientLightModeEnabled.checked = (properties.ambientLightMode === 'enabled');
|
||||
elZoneAmbientLightModeEnabled.checked = (properties.ambientLightMode === 'enabled');
|
||||
|
||||
elZoneAmbientLightIntensity.value = properties.ambientLight.ambientIntensity.toFixed(2);
|
||||
elZoneAmbientLightURL.value = properties.ambientLight.ambientURL;
|
||||
|
||||
// Haze
|
||||
elZoneHazeModeInherit.checked = (properties.hazeMode === 'inherit');
|
||||
elZoneHazeModeInherit.checked = (properties.hazeMode === 'inherit');
|
||||
elZoneHazeModeDisabled.checked = (properties.hazeMode === 'disabled');
|
||||
elZoneHazeModeEnabled.checked = (properties.hazeMode === 'enabled');
|
||||
elZoneHazeModeEnabled.checked = (properties.hazeMode === 'enabled');
|
||||
|
||||
elZoneHazeRange.value = properties.haze.hazeRange.toFixed(0);
|
||||
elZoneHazeColor.style.backgroundColor = "rgb(" +
|
||||
|
@ -1308,15 +1308,15 @@ function loaded() {
|
|||
colorScheme: 'dark',
|
||||
layout: 'hex',
|
||||
color: '000000',
|
||||
submit: false, // We don't want to have a submission button
|
||||
onShow: function(colpick) {
|
||||
$('#property-color-control2').attr('active', 'true');
|
||||
},
|
||||
onHide: function(colpick) {
|
||||
$('#property-color-control2').attr('active', 'false');
|
||||
},
|
||||
onSubmit: function(hsb, hex, rgb, el) {
|
||||
onChange: function(hsb, hex, rgb, el) {
|
||||
$(el).css('background-color', '#' + hex);
|
||||
$(el).colpickHide();
|
||||
emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b);
|
||||
}
|
||||
}));
|
||||
|
@ -1332,15 +1332,15 @@ function loaded() {
|
|||
colorScheme: 'dark',
|
||||
layout: 'hex',
|
||||
color: '000000',
|
||||
submit: false, // We don't want to have a submission button
|
||||
onShow: function(colpick) {
|
||||
$('#property-light-color').attr('active', 'true');
|
||||
},
|
||||
onHide: function(colpick) {
|
||||
$('#property-light-color').attr('active', 'false');
|
||||
},
|
||||
onSubmit: function(hsb, hex, rgb, el) {
|
||||
onChange: function(hsb, hex, rgb, el) {
|
||||
$(el).css('background-color', '#' + hex);
|
||||
$(el).colpickHide();
|
||||
emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b);
|
||||
}
|
||||
}));
|
||||
|
@ -1387,15 +1387,15 @@ function loaded() {
|
|||
colorScheme: 'dark',
|
||||
layout: 'hex',
|
||||
color: '000000',
|
||||
submit: false, // We don't want to have a submission button
|
||||
onShow: function(colpick) {
|
||||
$('#property-text-text-color').attr('active', 'true');
|
||||
},
|
||||
onHide: function(colpick) {
|
||||
$('#property-text-text-color').attr('active', 'false');
|
||||
},
|
||||
onSubmit: function(hsb, hex, rgb, el) {
|
||||
onChange: function(hsb, hex, rgb, el) {
|
||||
$(el).css('background-color', '#' + hex);
|
||||
$(el).colpickHide();
|
||||
$(el).attr('active', 'false');
|
||||
emitColorPropertyUpdate('textColor', rgb.r, rgb.g, rgb.b);
|
||||
}
|
||||
|
@ -1411,15 +1411,15 @@ function loaded() {
|
|||
colorScheme: 'dark',
|
||||
layout: 'hex',
|
||||
color: '000000',
|
||||
submit: false, // We don't want to have a submission button
|
||||
onShow: function(colpick) {
|
||||
$('#property-text-background-color').attr('active', 'true');
|
||||
},
|
||||
onHide: function(colpick) {
|
||||
$('#property-text-background-color').attr('active', 'false');
|
||||
},
|
||||
onSubmit: function(hsb, hex, rgb, el) {
|
||||
onChange: function(hsb, hex, rgb, el) {
|
||||
$(el).css('background-color', '#' + hex);
|
||||
$(el).colpickHide();
|
||||
emitColorPropertyUpdate('backgroundColor', rgb.r, rgb.g, rgb.b);
|
||||
}
|
||||
}));
|
||||
|
@ -1436,15 +1436,15 @@ function loaded() {
|
|||
colorScheme: 'dark',
|
||||
layout: 'hex',
|
||||
color: '000000',
|
||||
submit: false, // We don't want to have a submission button
|
||||
onShow: function(colpick) {
|
||||
$('#property-zone-key-light-color').attr('active', 'true');
|
||||
},
|
||||
onHide: function(colpick) {
|
||||
$('#property-zone-key-light-color').attr('active', 'false');
|
||||
},
|
||||
onSubmit: function(hsb, hex, rgb, el) {
|
||||
onChange: function(hsb, hex, rgb, el) {
|
||||
$(el).css('background-color', '#' + hex);
|
||||
$(el).colpickHide();
|
||||
emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b, 'keyLight');
|
||||
}
|
||||
}));
|
||||
|
@ -1505,15 +1505,15 @@ function loaded() {
|
|||
colorScheme: 'dark',
|
||||
layout: 'hex',
|
||||
color: '000000',
|
||||
submit: false, // We don't want to have a submission button
|
||||
onShow: function(colpick) {
|
||||
$('#property-zone-haze-color').attr('active', 'true');
|
||||
},
|
||||
onHide: function(colpick) {
|
||||
$('#property-zone-haze-color').attr('active', 'false');
|
||||
},
|
||||
onSubmit: function(hsb, hex, rgb, el) {
|
||||
onChange: function(hsb, hex, rgb, el) {
|
||||
$(el).css('background-color', '#' + hex);
|
||||
$(el).colpickHide();
|
||||
emitColorPropertyUpdate('hazeColor', rgb.r, rgb.g, rgb.b, 'haze');
|
||||
}
|
||||
}));
|
||||
|
@ -1530,15 +1530,15 @@ function loaded() {
|
|||
colorScheme: 'dark',
|
||||
layout: 'hex',
|
||||
color: '000000',
|
||||
submit: false, // We don't want to have a submission button
|
||||
onShow: function(colpick) {
|
||||
$('#property-zone-haze-glare-color').attr('active', 'true');
|
||||
},
|
||||
onHide: function(colpick) {
|
||||
$('#property-zone-haze-glare-color').attr('active', 'false');
|
||||
},
|
||||
onSubmit: function(hsb, hex, rgb, el) {
|
||||
onChange: function(hsb, hex, rgb, el) {
|
||||
$(el).css('background-color', '#' + hex);
|
||||
$(el).colpickHide();
|
||||
emitColorPropertyUpdate('hazeGlareColor', rgb.r, rgb.g, rgb.b, 'haze');
|
||||
}
|
||||
}));
|
||||
|
@ -1572,15 +1572,15 @@ function loaded() {
|
|||
colorScheme: 'dark',
|
||||
layout: 'hex',
|
||||
color: '000000',
|
||||
submit: false, // We don't want to have a submission button
|
||||
onShow: function(colpick) {
|
||||
$('#property-zone-skybox-color').attr('active', 'true');
|
||||
},
|
||||
onHide: function(colpick) {
|
||||
$('#property-zone-skybox-color').attr('active', 'false');
|
||||
},
|
||||
onSubmit: function(hsb, hex, rgb, el) {
|
||||
onChange: function(hsb, hex, rgb, el) {
|
||||
$(el).css('background-color', '#' + hex);
|
||||
$(el).colpickHide();
|
||||
emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b, 'skybox');
|
||||
}
|
||||
}));
|
||||
|
|
|
@ -35,4 +35,5 @@
|
|||
button.editProperties({isActive: true});
|
||||
}
|
||||
|
||||
Script.scriptEnding.connect(cleanup);
|
||||
}());
|
||||
|
|
|
@ -23,7 +23,7 @@ var BALL_DENSITY = 1000;
|
|||
var ACTION_DISTANCE = 0.35;
|
||||
var ACTION_TIMESCALE = 0.035;
|
||||
var MAX_DISTANCE_MULTIPLIER = 4;
|
||||
var STICK_SCRIPT_URL = Script.resolvePath("./entity_scripts/tetherballStick.js?v=" + Date.now());
|
||||
var STICK_SCRIPT_URL = Script.resolvePath("./entity_scripts/tetherballStick.js");
|
||||
var STICK_MODEL_URL = "http://hifi-content.s3.amazonaws.com/caitlyn/production/raveStick/newRaveStick2.fbx";
|
||||
var COLLISION_SOUND_URL = "http://public.highfidelity.io/sounds/Footsteps/FootstepW3Left-12db.wav";
|
||||
|
||||
|
|
Loading…
Reference in a new issue