diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index d785579c38..f8077303d2 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -489,7 +489,7 @@ void AudioMixer::handleNodeAudioPacket(QSharedPointer message, void AudioMixer::handleMuteEnvironmentPacket(QSharedPointer message, SharedNodePointer sendingNode) { auto nodeList = DependencyManager::get(); - if (sendingNode->isAllowedEditor()) { + if (sendingNode->getCanKick()) { glm::vec3 position; float radius; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 6207ecdb3c..dfa1a2f8b9 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -396,15 +396,6 @@ Menu::Menu() { }); } - // Developer > Render > Enable Incremental Texture Transfer - { - auto action = addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::IncrementalTextureTransfer, 0, gpu::Texture::getEnableIncrementalTextureTransfers()); - connect(action, &QAction::triggered, [&](bool checked) { - qDebug() << "[TEXTURE TRANSFER SUPPORT] --- Enable Incremental Texture Transfer menu option:" << checked; - gpu::Texture::setEnableIncrementalTextureTransfers(checked); - }); - } - #else qDebug() << "[TEXTURE TRANSFER SUPPORT] Incremental Texture Transfer and Dynamic Texture Management not supported on this platform."; #endif diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 87e0e678f1..e339da4d25 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -112,7 +112,6 @@ namespace MenuOption { const QString FrameTimer = "Show Timer"; const QString FullscreenMirror = "Mirror"; const QString Help = "Help..."; - const QString IncrementalTextureTransfer = "Enable Incremental Texture Transfer"; const QString IncreaseAvatarSize = "Increase Avatar Size"; const QString IndependentMode = "Independent Mode"; const QString ActionMotorControl = "Enable Default Motor Control"; diff --git a/interface/src/scripting/AccountScriptingInterface.h b/interface/src/scripting/AccountScriptingInterface.h index 0f958f2286..748f110356 100644 --- a/interface/src/scripting/AccountScriptingInterface.h +++ b/interface/src/scripting/AccountScriptingInterface.h @@ -19,12 +19,35 @@ class AccountScriptingInterface : public QObject { Q_PROPERTY(QString username READ getUsername NOTIFY usernameChanged) + /**jsdoc + * @namespace Account + * @property username {String} username if user is logged in, otherwise it returns "Unknown user" + */ + signals: + + /**jsdoc + * Triggered when username has changed. + * @function Account.usernameChanged + * @return {Signal} + */ void usernameChanged(); public slots: static AccountScriptingInterface* getInstance(); + + /**jsdoc + * Returns the username for the currently logged in High Fidelity metaverse account. + * @function Account.getUsername + * @return {string} username if user is logged in, otherwise it returns "Unknown user" + */ QString getUsername(); + + /**jsdoc + * Determine if the user is logged into the High Fidleity metaverse. + * @function Account.isLoggedIn + * @return {bool} true when user is logged into the High Fidelity metaverse. + */ bool isLoggedIn(); bool checkAndSignalForAccessToken(); }; diff --git a/interface/src/scripting/MenuScriptingInterface.cpp b/interface/src/scripting/MenuScriptingInterface.cpp index 2fa7470561..df75d331d6 100644 --- a/interface/src/scripting/MenuScriptingInterface.cpp +++ b/interface/src/scripting/MenuScriptingInterface.cpp @@ -126,6 +126,23 @@ void MenuScriptingInterface::setIsOptionChecked(const QString& menuOption, bool Q_ARG(bool, isChecked)); } +bool MenuScriptingInterface::isMenuEnabled(const QString& menuOption) { + if (QThread::currentThread() == qApp->thread()) { + return Menu::getInstance()->isOptionChecked(menuOption); + } + bool result; + QMetaObject::invokeMethod(Menu::getInstance(), "isMenuEnabled", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(bool, result), + Q_ARG(const QString&, menuOption)); + return result; +} + +void MenuScriptingInterface::setMenuEnabled(const QString& menuOption, bool isChecked) { + QMetaObject::invokeMethod(Menu::getInstance(), "setMenuEnabled", + Q_ARG(const QString&, menuOption), + Q_ARG(bool, isChecked)); +} + void MenuScriptingInterface::triggerOption(const QString& menuOption) { QMetaObject::invokeMethod(Menu::getInstance(), "triggerOption", Q_ARG(const QString&, menuOption)); } diff --git a/interface/src/scripting/MenuScriptingInterface.h b/interface/src/scripting/MenuScriptingInterface.h index 5b8a437529..855b1af13b 100644 --- a/interface/src/scripting/MenuScriptingInterface.h +++ b/interface/src/scripting/MenuScriptingInterface.h @@ -50,6 +50,9 @@ public slots: void setIsOptionChecked(const QString& menuOption, bool isChecked); void triggerOption(const QString& menuOption); + + bool isMenuEnabled(const QString& menuName); + void setMenuEnabled(const QString& menuName, bool isEnabled); signals: void menuItemEvent(const QString& menuItem); diff --git a/libraries/animation/src/AnimationCache.h b/libraries/animation/src/AnimationCache.h index a7d8700fed..59e3de9bcb 100644 --- a/libraries/animation/src/AnimationCache.h +++ b/libraries/animation/src/AnimationCache.h @@ -29,7 +29,19 @@ class AnimationCache : public ResourceCache, public Dependency { Q_OBJECT SINGLETON_DEPENDENCY + /**jsdoc + * @namespace AnimationCache + * @augments ResourceCache + */ + public: + + /**jsdoc + * Returns animation resource for particular animation + * @function AnimationCache.getAnimation + * @param url {string} url to load + * @return {Resource} animation + */ Q_INVOKABLE AnimationPointer getAnimation(const QString& url) { return getAnimation(QUrl(url)); } Q_INVOKABLE AnimationPointer getAnimation(const QUrl& url); diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 877c6c3e91..45790524d1 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -308,6 +308,13 @@ void Rig::clearIKJointLimitHistory() { } } +int Rig::getJointParentIndex(int childIndex) const { + if (_animSkeleton && isIndexValid(childIndex)) { + return _animSkeleton->getParentIndex(childIndex); + } + return -1; +} + void Rig::setJointTranslation(int index, bool valid, const glm::vec3& translation, float priority) { if (isIndexValid(index)) { if (valid) { @@ -414,6 +421,16 @@ bool Rig::getAbsoluteJointTranslationInRigFrame(int jointIndex, glm::vec3& trans } } +bool Rig::getAbsoluteJointPoseInRigFrame(int jointIndex, AnimPose& returnPose) const { + QReadLocker readLock(&_externalPoseSetLock); + if (jointIndex >= 0 && jointIndex < (int)_externalPoseSet._absolutePoses.size()) { + returnPose = _externalPoseSet._absolutePoses[jointIndex]; + return true; + } else { + return false; + } +} + bool Rig::getJointCombinedRotation(int jointIndex, glm::quat& result, const glm::quat& rotation) const { // AJT: TODO: used by attachments ASSERT(false); diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index 86b8dadd85..151a7ae8e9 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -105,6 +105,8 @@ public: void clearIKJointLimitHistory(); + int getJointParentIndex(int childIndex) const; + // geometry space void setJointState(int index, bool valid, const glm::quat& rotation, const glm::vec3& translation, float priority); @@ -133,6 +135,7 @@ public: // rig space (thread-safe) bool getAbsoluteJointRotationInRigFrame(int jointIndex, glm::quat& rotation) const; bool getAbsoluteJointTranslationInRigFrame(int jointIndex, glm::vec3& translation) const; + bool getAbsoluteJointPoseInRigFrame(int jointIndex, AnimPose& returnPose) const; // legacy bool getJointCombinedRotation(int jointIndex, glm::quat& result, const glm::quat& rotation) const; diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 332a88e499..dc5b6cd8d3 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -310,14 +310,14 @@ bool RenderableModelEntityItem::getAnimationFrame() { } glm::mat4 finalMat = (translationMat * fbxJoints[index].preTransform * rotationMat * fbxJoints[index].postTransform); - _absoluteJointTranslationsInObjectFrame[j] = extractTranslation(finalMat); - _absoluteJointTranslationsInObjectFrameSet[j] = true; - _absoluteJointTranslationsInObjectFrameDirty[j] = true; + _localJointTranslations[j] = extractTranslation(finalMat); + _localJointTranslationsSet[j] = true; + _localJointTranslationsDirty[j] = true; - _absoluteJointRotationsInObjectFrame[j] = glmExtractRotation(finalMat); + _localJointRotations[j] = glmExtractRotation(finalMat); - _absoluteJointRotationsInObjectFrameSet[j] = true; - _absoluteJointRotationsInObjectFrameDirty[j] = true; + _localJointRotationsSet[j] = true; + _localJointRotationsDirty[j] = true; } } } @@ -390,18 +390,18 @@ void RenderableModelEntityItem::render(RenderArgs* args) { getAnimationFrame(); // relay any inbound joint changes from scripts/animation/network to the model/rig - for (int index = 0; index < _absoluteJointRotationsInObjectFrame.size(); index++) { - if (_absoluteJointRotationsInObjectFrameDirty[index]) { - glm::quat rotation = _absoluteJointRotationsInObjectFrame[index]; + for (int index = 0; index < _localJointRotations.size(); index++) { + if (_localJointRotationsDirty[index]) { + glm::quat rotation = _localJointRotations[index]; _model->setJointRotation(index, true, rotation, 1.0f); - _absoluteJointRotationsInObjectFrameDirty[index] = false; + _localJointRotationsDirty[index] = false; } } - for (int index = 0; index < _absoluteJointTranslationsInObjectFrame.size(); index++) { - if (_absoluteJointTranslationsInObjectFrameDirty[index]) { - glm::vec3 translation = _absoluteJointTranslationsInObjectFrame[index]; + for (int index = 0; index < _localJointTranslations.size(); index++) { + if (_localJointTranslationsDirty[index]) { + glm::vec3 translation = _localJointTranslations[index]; _model->setJointTranslation(index, true, translation, 1.0f); - _absoluteJointTranslationsInObjectFrameDirty[index] = false; + _localJointTranslationsDirty[index] = false; } } }); @@ -1028,15 +1028,101 @@ glm::vec3 RenderableModelEntityItem::getAbsoluteJointTranslationInObjectFrame(in } bool RenderableModelEntityItem::setAbsoluteJointRotationInObjectFrame(int index, const glm::quat& rotation) { + if (!_model) { + return false; + } + RigPointer rig = _model->getRig(); + if (!rig) { + return false; + } + + int jointParentIndex = rig->getJointParentIndex(index); + if (jointParentIndex == -1) { + return setLocalJointRotation(index, rotation); + } + + bool success; + AnimPose jointParentPose; + success = rig->getAbsoluteJointPoseInRigFrame(jointParentIndex, jointParentPose); + if (!success) { + return false; + } + AnimPose jointParentInversePose = jointParentPose.inverse(); + + AnimPose jointAbsolutePose; // in rig frame + success = rig->getAbsoluteJointPoseInRigFrame(index, jointAbsolutePose); + if (!success) { + return false; + } + jointAbsolutePose.rot = rotation; + + AnimPose jointRelativePose = jointParentInversePose * jointAbsolutePose; + return setLocalJointRotation(index, jointRelativePose.rot); +} + +bool RenderableModelEntityItem::setAbsoluteJointTranslationInObjectFrame(int index, const glm::vec3& translation) { + if (!_model) { + return false; + } + RigPointer rig = _model->getRig(); + if (!rig) { + return false; + } + + int jointParentIndex = rig->getJointParentIndex(index); + if (jointParentIndex == -1) { + return setLocalJointTranslation(index, translation); + } + + bool success; + AnimPose jointParentPose; + success = rig->getAbsoluteJointPoseInRigFrame(jointParentIndex, jointParentPose); + if (!success) { + return false; + } + AnimPose jointParentInversePose = jointParentPose.inverse(); + + AnimPose jointAbsolutePose; // in rig frame + success = rig->getAbsoluteJointPoseInRigFrame(index, jointAbsolutePose); + if (!success) { + return false; + } + jointAbsolutePose.trans = translation; + + AnimPose jointRelativePose = jointParentInversePose * jointAbsolutePose; + return setLocalJointTranslation(index, jointRelativePose.trans); +} + +glm::quat RenderableModelEntityItem::getLocalJointRotation(int index) const { + if (_model) { + glm::quat result; + if (_model->getJointRotation(index, result)) { + return result; + } + } + return glm::quat(); +} + +glm::vec3 RenderableModelEntityItem::getLocalJointTranslation(int index) const { + if (_model) { + glm::vec3 result; + if (_model->getJointTranslation(index, result)) { + return result; + } + } + return glm::vec3(); +} + +bool RenderableModelEntityItem::setLocalJointRotation(int index, const glm::quat& rotation) { bool result = false; _jointDataLock.withWriteLock([&] { _jointRotationsExplicitlySet = true; resizeJointArrays(); - if (index >= 0 && index < _absoluteJointRotationsInObjectFrame.size() && - _absoluteJointRotationsInObjectFrame[index] != rotation) { - _absoluteJointRotationsInObjectFrame[index] = rotation; - _absoluteJointRotationsInObjectFrameSet[index] = true; - _absoluteJointRotationsInObjectFrameDirty[index] = true; + if (index >= 0 && index < _localJointRotations.size() && + _localJointRotations[index] != rotation) { + _localJointRotations[index] = rotation; + _localJointRotationsSet[index] = true; + _localJointRotationsDirty[index] = true; result = true; _needsJointSimulation = true; } @@ -1044,16 +1130,16 @@ bool RenderableModelEntityItem::setAbsoluteJointRotationInObjectFrame(int index, return result; } -bool RenderableModelEntityItem::setAbsoluteJointTranslationInObjectFrame(int index, const glm::vec3& translation) { +bool RenderableModelEntityItem::setLocalJointTranslation(int index, const glm::vec3& translation) { bool result = false; _jointDataLock.withWriteLock([&] { _jointTranslationsExplicitlySet = true; resizeJointArrays(); - if (index >= 0 && index < _absoluteJointTranslationsInObjectFrame.size() && - _absoluteJointTranslationsInObjectFrame[index] != translation) { - _absoluteJointTranslationsInObjectFrame[index] = translation; - _absoluteJointTranslationsInObjectFrameSet[index] = true; - _absoluteJointTranslationsInObjectFrameDirty[index] = true; + if (index >= 0 && index < _localJointTranslations.size() && + _localJointTranslations[index] != translation) { + _localJointTranslations[index] = translation; + _localJointTranslationsSet[index] = true; + _localJointTranslationsDirty[index] = true; result = true; _needsJointSimulation = true; } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index a52b0b0041..93d48c6085 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -74,6 +74,12 @@ public: virtual bool setAbsoluteJointRotationInObjectFrame(int index, const glm::quat& rotation) override; virtual bool setAbsoluteJointTranslationInObjectFrame(int index, const glm::vec3& translation) override; + + virtual glm::quat getLocalJointRotation(int index) const override; + virtual glm::vec3 getLocalJointTranslation(int index) const override; + virtual bool setLocalJointRotation(int index, const glm::quat& rotation) override; + virtual bool setLocalJointTranslation(int index, const glm::vec3& translation) override; + virtual void setJointRotations(const QVector& rotations) override; virtual void setJointRotationsSet(const QVector& rotationsSet) override; virtual void setJointTranslations(const QVector& translations) override; diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 7e06a59f06..7286a6e0b3 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -418,8 +418,9 @@ public: // these are in the frame of this object virtual glm::quat getAbsoluteJointRotationInObjectFrame(int index) const override { return glm::quat(); } virtual glm::vec3 getAbsoluteJointTranslationInObjectFrame(int index) const override { return glm::vec3(0.0f); } - virtual bool setAbsoluteJointRotationInObjectFrame(int index, const glm::quat& rotation) override { return false; } - virtual bool setAbsoluteJointTranslationInObjectFrame(int index, const glm::vec3& translation) override { return false; } + + virtual bool setLocalJointRotation(int index, const glm::quat& rotation) override { return false; } + virtual bool setLocalJointTranslation(int index, const glm::vec3& translation) override { return false; } virtual int getJointIndex(const QString& name) const { return -1; } virtual QStringList getJointNames() const { return QStringList(); } diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 306477b10c..ee4db74c64 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -1154,17 +1154,76 @@ bool EntityScriptingInterface::setAbsoluteJointRotationInObjectFrame(const QUuid return false; } +glm::vec3 EntityScriptingInterface::getLocalJointTranslation(const QUuid& entityID, int jointIndex) { + if (auto entity = checkForTreeEntityAndTypeMatch(entityID, EntityTypes::Model)) { + auto modelEntity = std::dynamic_pointer_cast(entity); + return modelEntity->getLocalJointTranslation(jointIndex); + } else { + return glm::vec3(0.0f); + } +} + +glm::quat EntityScriptingInterface::getLocalJointRotation(const QUuid& entityID, int jointIndex) { + if (auto entity = checkForTreeEntityAndTypeMatch(entityID, EntityTypes::Model)) { + auto modelEntity = std::dynamic_pointer_cast(entity); + return modelEntity->getLocalJointRotation(jointIndex); + } else { + return glm::quat(); + } +} + +bool EntityScriptingInterface::setLocalJointTranslation(const QUuid& entityID, int jointIndex, glm::vec3 translation) { + if (auto entity = checkForTreeEntityAndTypeMatch(entityID, EntityTypes::Model)) { + auto now = usecTimestampNow(); + auto modelEntity = std::dynamic_pointer_cast(entity); + bool result = modelEntity->setLocalJointTranslation(jointIndex, translation); + if (result) { + EntityItemProperties properties; + _entityTree->withWriteLock([&] { + properties = entity->getProperties(); + entity->setLastBroadcast(now); + }); + + properties.setJointTranslationsDirty(); + properties.setLastEdited(now); + queueEntityMessage(PacketType::EntityEdit, entityID, properties); + return true; + } + } + return false; +} + +bool EntityScriptingInterface::setLocalJointRotation(const QUuid& entityID, int jointIndex, glm::quat rotation) { + if (auto entity = checkForTreeEntityAndTypeMatch(entityID, EntityTypes::Model)) { + auto now = usecTimestampNow(); + auto modelEntity = std::dynamic_pointer_cast(entity); + bool result = modelEntity->setLocalJointRotation(jointIndex, rotation); + if (result) { + EntityItemProperties properties; + _entityTree->withWriteLock([&] { + properties = entity->getProperties(); + entity->setLastBroadcast(now); + }); + + properties.setJointRotationsDirty(); + properties.setLastEdited(now); + queueEntityMessage(PacketType::EntityEdit, entityID, properties); + return true; + } + } + return false; +} -bool EntityScriptingInterface::setAbsoluteJointRotationsInObjectFrame(const QUuid& entityID, - const QVector& rotations) { + +bool EntityScriptingInterface::setLocalJointRotations(const QUuid& entityID, const QVector& rotations) { if (auto entity = checkForTreeEntityAndTypeMatch(entityID, EntityTypes::Model)) { auto now = usecTimestampNow(); auto modelEntity = std::dynamic_pointer_cast(entity); bool result = false; for (int index = 0; index < rotations.size(); index++) { - result |= modelEntity->setAbsoluteJointRotationInObjectFrame(index, rotations[index]); + result |= modelEntity->setLocalJointRotation(index, rotations[index]); } if (result) { EntityItemProperties properties; @@ -1184,15 +1243,14 @@ bool EntityScriptingInterface::setAbsoluteJointRotationsInObjectFrame(const QUui } -bool EntityScriptingInterface::setAbsoluteJointTranslationsInObjectFrame(const QUuid& entityID, - const QVector& translations) { +bool EntityScriptingInterface::setLocalJointTranslations(const QUuid& entityID, const QVector& translations) { if (auto entity = checkForTreeEntityAndTypeMatch(entityID, EntityTypes::Model)) { auto now = usecTimestampNow(); auto modelEntity = std::dynamic_pointer_cast(entity); bool result = false; for (int index = 0; index < translations.size(); index++) { - result |= modelEntity->setAbsoluteJointTranslationInObjectFrame(index, translations[index]); + result |= modelEntity->setLocalJointTranslation(index, translations[index]); } if (result) { EntityItemProperties properties; @@ -1211,12 +1269,12 @@ bool EntityScriptingInterface::setAbsoluteJointTranslationsInObjectFrame(const Q return false; } -bool EntityScriptingInterface::setAbsoluteJointsDataInObjectFrame(const QUuid& entityID, - const QVector& rotations, - const QVector& translations) { +bool EntityScriptingInterface::setLocalJointsData(const QUuid& entityID, + const QVector& rotations, + const QVector& translations) { // for a model with 80 joints, sending both these in one edit packet causes the packet to be too large. - return setAbsoluteJointRotationsInObjectFrame(entityID, rotations) || - setAbsoluteJointTranslationsInObjectFrame(entityID, translations); + return setLocalJointRotations(entityID, rotations) || + setLocalJointTranslations(entityID, translations); } int EntityScriptingInterface::getJointIndex(const QUuid& entityID, const QString& name) { diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 3a24ff59fd..3d46113611 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -186,13 +186,17 @@ public slots: Q_INVOKABLE glm::quat getAbsoluteJointRotationInObjectFrame(const QUuid& entityID, int jointIndex); Q_INVOKABLE bool setAbsoluteJointTranslationInObjectFrame(const QUuid& entityID, int jointIndex, glm::vec3 translation); Q_INVOKABLE bool setAbsoluteJointRotationInObjectFrame(const QUuid& entityID, int jointIndex, glm::quat rotation); - Q_INVOKABLE bool setAbsoluteJointRotationsInObjectFrame(const QUuid& entityID, - const QVector& rotations); - Q_INVOKABLE bool setAbsoluteJointTranslationsInObjectFrame(const QUuid& entityID, - const QVector& translations); - Q_INVOKABLE bool setAbsoluteJointsDataInObjectFrame(const QUuid& entityID, - const QVector& rotations, - const QVector& translations); + + Q_INVOKABLE glm::vec3 getLocalJointTranslation(const QUuid& entityID, int jointIndex); + Q_INVOKABLE glm::quat getLocalJointRotation(const QUuid& entityID, int jointIndex); + Q_INVOKABLE bool setLocalJointTranslation(const QUuid& entityID, int jointIndex, glm::vec3 translation); + Q_INVOKABLE bool setLocalJointRotation(const QUuid& entityID, int jointIndex, glm::quat rotation); + + Q_INVOKABLE bool setLocalJointRotations(const QUuid& entityID, const QVector& rotations); + Q_INVOKABLE bool setLocalJointTranslations(const QUuid& entityID, const QVector& translations); + Q_INVOKABLE bool setLocalJointsData(const QUuid& entityID, + const QVector& rotations, + const QVector& translations); Q_INVOKABLE int getJointIndex(const QUuid& entityID, const QString& name); Q_INVOKABLE QStringList getJointNames(const QUuid& entityID); diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index b098247524..df568817ac 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -389,13 +389,13 @@ bool ModelEntityItem::shouldBePhysical() const { } void ModelEntityItem::resizeJointArrays(int newSize) { - if (newSize >= 0 && newSize > _absoluteJointRotationsInObjectFrame.size()) { - _absoluteJointRotationsInObjectFrame.resize(newSize); - _absoluteJointRotationsInObjectFrameSet.resize(newSize); - _absoluteJointRotationsInObjectFrameDirty.resize(newSize); - _absoluteJointTranslationsInObjectFrame.resize(newSize); - _absoluteJointTranslationsInObjectFrameSet.resize(newSize); - _absoluteJointTranslationsInObjectFrameDirty.resize(newSize); + if (newSize >= 0 && newSize > _localJointRotations.size()) { + _localJointRotations.resize(newSize); + _localJointRotationsSet.resize(newSize); + _localJointRotationsDirty.resize(newSize); + _localJointTranslations.resize(newSize); + _localJointTranslationsSet.resize(newSize); + _localJointTranslationsDirty.resize(newSize); } } @@ -404,9 +404,9 @@ void ModelEntityItem::setJointRotations(const QVector& rotations) { _jointRotationsExplicitlySet = rotations.size() > 0; resizeJointArrays(rotations.size()); for (int index = 0; index < rotations.size(); index++) { - if (_absoluteJointRotationsInObjectFrameSet[index]) { - _absoluteJointRotationsInObjectFrame[index] = rotations[index]; - _absoluteJointRotationsInObjectFrameDirty[index] = true; + if (_localJointRotationsSet[index]) { + _localJointRotations[index] = rotations[index]; + _localJointRotationsDirty[index] = true; } } }); @@ -417,7 +417,7 @@ void ModelEntityItem::setJointRotationsSet(const QVector& rotationsSet) { _jointRotationsExplicitlySet = rotationsSet.size() > 0; resizeJointArrays(rotationsSet.size()); for (int index = 0; index < rotationsSet.size(); index++) { - _absoluteJointRotationsInObjectFrameSet[index] = rotationsSet[index]; + _localJointRotationsSet[index] = rotationsSet[index]; } }); } @@ -427,9 +427,9 @@ void ModelEntityItem::setJointTranslations(const QVector& translation _jointTranslationsExplicitlySet = translations.size() > 0; resizeJointArrays(translations.size()); for (int index = 0; index < translations.size(); index++) { - if (_absoluteJointTranslationsInObjectFrameSet[index]) { - _absoluteJointTranslationsInObjectFrame[index] = translations[index]; - _absoluteJointTranslationsInObjectFrameSet[index] = true; + if (_localJointTranslationsSet[index]) { + _localJointTranslations[index] = translations[index]; + _localJointTranslationsSet[index] = true; } } }); @@ -440,7 +440,7 @@ void ModelEntityItem::setJointTranslationsSet(const QVector& translationsS _jointTranslationsExplicitlySet = translationsSet.size() > 0; resizeJointArrays(translationsSet.size()); for (int index = 0; index < translationsSet.size(); index++) { - _absoluteJointTranslationsInObjectFrameSet[index] = translationsSet[index]; + _localJointTranslationsSet[index] = translationsSet[index]; } }); } @@ -449,7 +449,7 @@ QVector ModelEntityItem::getJointRotations() const { QVector result; _jointDataLock.withReadLock([&] { if (_jointRotationsExplicitlySet) { - result = _absoluteJointRotationsInObjectFrame; + result = _localJointRotations; } }); return result; @@ -459,7 +459,7 @@ QVector ModelEntityItem::getJointRotationsSet() const { QVector result; _jointDataLock.withReadLock([&] { if (_jointRotationsExplicitlySet) { - result = _absoluteJointRotationsInObjectFrameSet; + result = _localJointRotationsSet; } }); @@ -470,7 +470,7 @@ QVector ModelEntityItem::getJointTranslations() const { QVector result; _jointDataLock.withReadLock([&] { if (_jointTranslationsExplicitlySet) { - result = _absoluteJointTranslationsInObjectFrame; + result = _localJointTranslations; } }); return result; @@ -480,7 +480,7 @@ QVector ModelEntityItem::getJointTranslationsSet() const { QVector result; _jointDataLock.withReadLock([&] { if (_jointTranslationsExplicitlySet) { - result = _absoluteJointTranslationsInObjectFrameSet; + result = _localJointTranslationsSet; } }); return result; diff --git a/libraries/entities/src/ModelEntityItem.h b/libraries/entities/src/ModelEntityItem.h index 6f2a0e1b31..58766906bb 100644 --- a/libraries/entities/src/ModelEntityItem.h +++ b/libraries/entities/src/ModelEntityItem.h @@ -117,9 +117,6 @@ public: virtual bool shouldBePhysical() const override; - virtual glm::vec3 getJointPosition(int jointIndex) const { return glm::vec3(); } - virtual glm::quat getJointRotation(int jointIndex) const { return glm::quat(); } - virtual void setJointRotations(const QVector& rotations); virtual void setJointRotationsSet(const QVector& rotationsSet); virtual void setJointTranslations(const QVector& translations); @@ -143,14 +140,14 @@ protected: ReadWriteLockable _jointDataLock; bool _jointRotationsExplicitlySet { false }; // were the joints set as a property or just side effect of animations - QVector _absoluteJointRotationsInObjectFrame; - QVector _absoluteJointRotationsInObjectFrameSet; // ever set? - QVector _absoluteJointRotationsInObjectFrameDirty; // needs a relay to model/rig? - + QVector _localJointRotations; + QVector _localJointRotationsSet; // ever set? + QVector _localJointRotationsDirty; // needs a relay to model/rig? + bool _jointTranslationsExplicitlySet { false }; // were the joints set as a property or just side effect of animations - QVector _absoluteJointTranslationsInObjectFrame; - QVector _absoluteJointTranslationsInObjectFrameSet; // ever set? - QVector _absoluteJointTranslationsInObjectFrameDirty; // needs a relay to model/rig? + QVector _localJointTranslations; + QVector _localJointTranslationsSet; // ever set? + QVector _localJointTranslationsDirty; // needs a relay to model/rig? int _lastKnownCurrentFrame; virtual void resizeJointArrays(int newSize = -1); diff --git a/libraries/gl/src/gl/OpenGLVersionChecker.cpp b/libraries/gl/src/gl/OpenGLVersionChecker.cpp index 6473b6bf2b..428bf86c6f 100644 --- a/libraries/gl/src/gl/OpenGLVersionChecker.cpp +++ b/libraries/gl/src/gl/OpenGLVersionChecker.cpp @@ -21,6 +21,7 @@ #include "GLHelpers.h" +// Minimum gl version required is 4.1 #define MINIMUM_GL_VERSION 0x0401 OpenGLVersionChecker::OpenGLVersionChecker(int& argc, char** argv) : @@ -75,15 +76,26 @@ QJsonObject OpenGLVersionChecker::checkVersion(bool& valid, bool& override) { // - major_number.minor_number // - major_number.minor_number.release_number // Reference: https://www.opengl.org/sdk/docs/man/docbook4/xhtml/glGetString.xml - const QString version { "version" }; - QString glVersion = glData[version].toString(); - QStringList versionParts = glVersion.split(QRegularExpression("[\\.\\s]")); - int majorNumber = versionParts[0].toInt(); - int minorNumber = versionParts[1].toInt(); - int minimumMajorNumber = (MINIMUM_GL_VERSION >> 16); + + int minimumMajorNumber = (MINIMUM_GL_VERSION >> 8) & 0xFF; int minimumMinorNumber = (MINIMUM_GL_VERSION & 0xFF); - valid = (majorNumber > minimumMajorNumber - || (majorNumber == minimumMajorNumber && minorNumber >= minimumMinorNumber)); + int majorNumber = 0; + int minorNumber = 0; + const QString version { "version" }; + if (glData.contains(version)) { + QString glVersion = glData[version].toString(); + QStringList versionParts = glVersion.split(QRegularExpression("[\\.\\s]")); + if (versionParts.size() >= 2) { + majorNumber = versionParts[0].toInt(); + minorNumber = versionParts[1].toInt(); + valid = (majorNumber > minimumMajorNumber + || (majorNumber == minimumMajorNumber && minorNumber >= minimumMinorNumber)); + } else { + valid = false; + } + } else { + valid = false; + } // Prompt user if below minimum if (!valid) { diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h index 438b1e9454..291888e81b 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h +++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h @@ -14,6 +14,8 @@ #include "../gl/GLBackend.h" #include "../gl/GLTexture.h" +#define INCREMENTAL_TRANSFER 0 + namespace gpu { namespace gl45 { using namespace gpu::gl; @@ -56,6 +58,7 @@ public: GLint pageDimensionsIndex { 0 }; }; +#if INCREMENTAL_TRANSFER struct TransferState { TransferState(GL45Texture& texture); uvec3 currentPageSize() const; @@ -74,6 +77,10 @@ public: uvec3 mipOffset; const uint8_t* srcPointer { nullptr }; }; + protected: + TransferState _transferState; +#endif + protected: void updateMips() override; void stripToMip(uint16_t newMinMip); @@ -91,7 +98,6 @@ public: void derez(); SparseInfo _sparseInfo; - TransferState _transferState; uint32_t _allocatedPages { 0 }; uint32_t _lastMipAllocatedPages { 0 }; uint16_t _mipOffset { 0 }; diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp index 83e5632921..818fe6fab2 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendTexture.cpp @@ -162,6 +162,8 @@ void GL45Backend::initTextureManagementStage() { } } +#if INCREMENTAL_TRANSFER + using TransferState = GL45Backend::GL45Texture::TransferState; TransferState::TransferState(GL45Texture& texture) : texture(texture) { @@ -246,6 +248,7 @@ void TransferState::populatePage(std::vector& buffer) { uvec3 TransferState::currentPageSize() const { return glm::clamp(mipDimensions - mipOffset, uvec3(1), texture._sparseInfo.pageDimensions); } +#endif GLuint GL45Texture::allocate(const Texture& texture) { GLuint result; @@ -258,11 +261,19 @@ GLuint GL45Backend::getTextureID(const TexturePointer& texture, bool transfer) { } GL45Texture::GL45Texture(const std::weak_ptr& backend, const Texture& texture, GLuint externalId) - : GLTexture(backend, texture, externalId), _sparseInfo(*this), _transferState(*this) { + : GLTexture(backend, texture, externalId), _sparseInfo(*this) +#if INCREMENTAL_TRANSFER +, _transferState(*this) +#endif +{ } GL45Texture::GL45Texture(const std::weak_ptr& backend, const Texture& texture, bool transferrable) - : GLTexture(backend, texture, allocate(texture), transferrable), _sparseInfo(*this), _transferState(*this) { + : GLTexture(backend, texture, allocate(texture), transferrable), _sparseInfo(*this) +#if INCREMENTAL_TRANSFER +, _transferState(*this) +#endif + { auto theBackend = _backend.lock(); if (_transferrable && theBackend && theBackend->isTextureManagementSparseEnabled()) { @@ -375,39 +386,40 @@ void GL45Texture::updateSize() const { void GL45Texture::startTransfer() { Parent::startTransfer(); _sparseInfo.update(); +#if INCREMENTAL_TRANSFER _transferState.updateMip(); +#endif } bool GL45Texture::continueTransfer() { - if (!Texture::getEnableIncrementalTextureTransfers()) { - size_t maxFace = GL_TEXTURE_CUBE_MAP == _target ? CUBE_NUM_FACES : 1; - for (uint8_t face = 0; face < maxFace; ++face) { - for (uint16_t mipLevel = _minMip; mipLevel <= _maxMip; ++mipLevel) { - auto size = _gpuObject.evalMipDimensions(mipLevel); - if (_sparseInfo.sparse && mipLevel <= _sparseInfo.maxSparseLevel) { - glTexturePageCommitmentEXT(_id, mipLevel, 0, 0, face, size.x, size.y, 1, GL_TRUE); - _allocatedPages += _sparseInfo.getPageCount(size); - } - if (_gpuObject.isStoredMipFaceAvailable(mipLevel, face)) { - auto mip = _gpuObject.accessStoredMipFace(mipLevel, face); - GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat(), mip->getFormat()); - if (GL_TEXTURE_2D == _target) { - glTextureSubImage2D(_id, mipLevel, 0, 0, size.x, size.y, texelFormat.format, texelFormat.type, mip->readData()); - } else if (GL_TEXTURE_CUBE_MAP == _target) { - // DSA ARB does not work on AMD, so use EXT - // glTextureSubImage3D(_id, mipLevel, 0, 0, face, size.x, size.y, 1, texelFormat.format, texelFormat.type, mip->readData()); - auto target = CUBE_FACE_LAYOUT[face]; - glTextureSubImage2DEXT(_id, target, mipLevel, 0, 0, size.x, size.y, texelFormat.format, texelFormat.type, mip->readData()); - } else { - Q_ASSERT(false); - } - (void)CHECK_GL_ERROR(); +#if !INCREMENTAL_TRANSFER + size_t maxFace = GL_TEXTURE_CUBE_MAP == _target ? CUBE_NUM_FACES : 1; + for (uint8_t face = 0; face < maxFace; ++face) { + for (uint16_t mipLevel = _minMip; mipLevel <= _maxMip; ++mipLevel) { + auto size = _gpuObject.evalMipDimensions(mipLevel); + if (_sparseInfo.sparse && mipLevel <= _sparseInfo.maxSparseLevel) { + glTexturePageCommitmentEXT(_id, mipLevel, 0, 0, face, size.x, size.y, 1, GL_TRUE); + _allocatedPages += _sparseInfo.getPageCount(size); + } + if (_gpuObject.isStoredMipFaceAvailable(mipLevel, face)) { + auto mip = _gpuObject.accessStoredMipFace(mipLevel, face); + GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat(), mip->getFormat()); + if (GL_TEXTURE_2D == _target) { + glTextureSubImage2D(_id, mipLevel, 0, 0, size.x, size.y, texelFormat.format, texelFormat.type, mip->readData()); + } else if (GL_TEXTURE_CUBE_MAP == _target) { + // DSA ARB does not work on AMD, so use EXT + // glTextureSubImage3D(_id, mipLevel, 0, 0, face, size.x, size.y, 1, texelFormat.format, texelFormat.type, mip->readData()); + auto target = CUBE_FACE_LAYOUT[face]; + glTextureSubImage2DEXT(_id, target, mipLevel, 0, 0, size.x, size.y, texelFormat.format, texelFormat.type, mip->readData()); + } else { + Q_ASSERT(false); } + (void)CHECK_GL_ERROR(); } } - return false; } - + return false; +#else static std::vector buffer; if (buffer.empty()) { buffer.resize(DEFAULT_PAGE_BUFFER_SIZE); @@ -458,6 +470,7 @@ bool GL45Texture::continueTransfer() { _lastMipAllocatedPages = _allocatedPages; } return result; +#endif } void GL45Texture::finishTransfer() { diff --git a/libraries/gpu/src/gpu/Texture.cpp b/libraries/gpu/src/gpu/Texture.cpp index 33786155db..45aff54b8f 100755 --- a/libraries/gpu/src/gpu/Texture.cpp +++ b/libraries/gpu/src/gpu/Texture.cpp @@ -35,18 +35,15 @@ std::atomic Texture::_allowedCPUMemoryUsage { 0 }; #define MIN_CORES_FOR_INCREMENTAL_TEXTURES 5 -bool recommendedIncrementalTransfers = (QThread::idealThreadCount() >= MIN_CORES_FOR_INCREMENTAL_TEXTURES); -bool recommendedSparseTextures = recommendedIncrementalTransfers; +bool recommendedSparseTextures = (QThread::idealThreadCount() >= MIN_CORES_FOR_INCREMENTAL_TEXTURES); -std::atomic Texture::_enableSparseTextures { recommendedIncrementalTransfers }; -std::atomic Texture::_enableIncrementalTextureTransfers { recommendedSparseTextures }; +std::atomic Texture::_enableSparseTextures { recommendedSparseTextures }; struct ReportTextureState { ReportTextureState() { qDebug() << "[TEXTURE TRANSFER SUPPORT]" << "\n\tidealThreadCount:" << QThread::idealThreadCount() - << "\n\tRECOMMENDED enableSparseTextures:" << recommendedSparseTextures - << "\n\tRECOMMENDED enableIncrementalTextures:" << recommendedIncrementalTransfers; + << "\n\tRECOMMENDED enableSparseTextures:" << recommendedSparseTextures; } } report; @@ -59,16 +56,6 @@ void Texture::setEnableSparseTextures(bool enabled) { #endif } -void Texture::setEnableIncrementalTextureTransfers(bool enabled) { -#ifdef Q_OS_WIN - qDebug() << "[TEXTURE TRANSFER SUPPORT] SETTING - Enable Incremental Texture Transfer:" << enabled; - _enableIncrementalTextureTransfers = enabled; -#else - qDebug() << "[TEXTURE TRANSFER SUPPORT] Incremental Texture Transfer not supported on this platform."; -#endif -} - - void Texture::updateTextureCPUMemoryUsage(Size prevObjectSize, Size newObjectSize) { if (prevObjectSize == newObjectSize) { return; @@ -84,10 +71,6 @@ bool Texture::getEnableSparseTextures() { return _enableSparseTextures.load(); } -bool Texture::getEnableIncrementalTextureTransfers() { - return _enableIncrementalTextureTransfers.load(); -} - uint32_t Texture::getTextureCPUCount() { return _textureCPUCount.load(); } diff --git a/libraries/gpu/src/gpu/Texture.h b/libraries/gpu/src/gpu/Texture.h index 2a93ec3066..856bd4983d 100755 --- a/libraries/gpu/src/gpu/Texture.h +++ b/libraries/gpu/src/gpu/Texture.h @@ -143,10 +143,8 @@ class Texture : public Resource { static std::atomic _textureCPUCount; static std::atomic _textureCPUMemoryUsage; static std::atomic _allowedCPUMemoryUsage; - static void updateTextureCPUMemoryUsage(Size prevObjectSize, Size newObjectSize); - static std::atomic _enableSparseTextures; - static std::atomic _enableIncrementalTextureTransfers; + static void updateTextureCPUMemoryUsage(Size prevObjectSize, Size newObjectSize); public: static uint32_t getTextureCPUCount(); @@ -162,10 +160,7 @@ public: static void setAllowedGPUMemoryUsage(Size size); static bool getEnableSparseTextures(); - static bool getEnableIncrementalTextureTransfers(); - static void setEnableSparseTextures(bool enabled); - static void setEnableIncrementalTextureTransfers(bool enabled); using ExternalRecycler = std::function; using ExternalIdAndFence = std::pair; diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index eba84dddd4..48b21a1e98 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -88,7 +88,24 @@ class ScriptableResource : public QObject { Q_PROPERTY(QUrl url READ getUrl) Q_PROPERTY(int state READ getState NOTIFY stateChanged) + /**jsdoc + * @constructor Resource + * @property url {string} url of this resource + * @property state {Resource.State} current loading state + */ + public: + + /**jsdoc + * @name Resource.State + * @static + * @property QUEUED {int} The resource is queued up, waiting to be loaded. + * @property LOADING {int} The resource is downloading + * @property LOADED {int} The resource has finished downloaded by is not complete + * @property FINISHED {int} The resource has completly finished loading and is ready. + * @property FAILED {int} Downloading the resource has failed. + */ + enum State { QUEUED, LOADING, @@ -101,6 +118,10 @@ public: ScriptableResource(const QUrl& url); virtual ~ScriptableResource() = default; + /**jsdoc + * Release this resource + * @function Resource#release + */ Q_INVOKABLE void release(); const QUrl& getUrl() const { return _url; } @@ -111,7 +132,22 @@ public: void setInScript(bool isInScript); signals: + + /**jsdoc + * Signaled when download progress for this resource has changed + * @function Resource#progressChanged + * @param bytesReceived {int} bytes downloaded so far + * @param bytesTotal {int} total number of bytes in the resource + * @returns {Signal} + */ void progressChanged(uint64_t bytesReceived, uint64_t bytesTotal); + + /**jsdoc + * Signaled when resource loading state has changed + * @function Resource#stateChanged + * @param bytesReceived {Resource.State} new state + * @returns {Signal} + */ void stateChanged(int state); protected: @@ -148,14 +184,49 @@ class ResourceCache : public QObject { Q_PROPERTY(size_t numCached READ getNumCachedResources NOTIFY dirty) Q_PROPERTY(size_t sizeTotal READ getSizeTotalResources NOTIFY dirty) Q_PROPERTY(size_t sizeCached READ getSizeCachedResources NOTIFY dirty) - + + /**jsdoc + * @namespace ResourceCache + * @property numTotal {number} total number of total resources + * @property numCached {number} total number of cached resource + * @property sizeTotal {number} size in bytes of all resources + * @property sizeCached {number} size in bytes of all cached resources + */ + public: + /**jsdoc + * Returns the total number of resources + * @function ResourceCache.getNumTotalResources + * @return {number} + */ size_t getNumTotalResources() const { return _numTotalResources; } + + /**jsdoc + * Returns the total size in bytes of all resources + * @function ResourceCache.getSizeTotalResources + * @return {number} + */ size_t getSizeTotalResources() const { return _totalResourcesSize; } + /**jsdoc + * Returns the total number of cached resources + * @function ResourceCache.getNumCachedResources + * @return {number} + */ size_t getNumCachedResources() const { return _numUnusedResources; } + + /**jsdoc + * Returns the total size in bytes of cached resources + * @function ResourceCache.getSizeCachedResources + * @return {number} + */ size_t getSizeCachedResources() const { return _unusedResourcesSize; } + /**jsdoc + * Returns list of all resource urls + * @function ResourceCache.getResourceList + * @return {string[]} + */ Q_INVOKABLE QVariantList getResourceList(); static void setRequestLimit(int limit); @@ -192,6 +263,13 @@ protected slots: /// returns an empty smart pointer and loads its asynchronously. /// \param fallback a fallback URL to load if the desired one is unavailable /// \param extra extra data to pass to the creator, if appropriate + /**jsdoc + * Asynchronously loads a resource from the spedified URL and returns it. + * @param url {string} url of resource to load + * @param fallback {string} fallback URL if load of the desired url fails + * @function ResourceCache.getResource + * @return {Resource} + */ QSharedPointer getResource(const QUrl& url, const QUrl& fallback = QUrl(), void* extra = NULL); @@ -203,6 +281,12 @@ protected: // Pointers created through this method should be owned by the caller, // which should be a QScriptEngine with ScriptableResource registered, so that // the QScriptEngine will delete the pointer when it is garbage collected. + /**jsdoc + * Prefetches a resource. + * @param url {string} url of resource to load + * @function ResourceCache.prefetch + * @return {Resource} + */ Q_INVOKABLE ScriptableResource* prefetch(const QUrl& url) { return prefetch(url, nullptr); } /// Creates a new resource. diff --git a/libraries/script-engine/src/AssetScriptingInterface.h b/libraries/script-engine/src/AssetScriptingInterface.h index 82d220ab34..d8bc319256 100644 --- a/libraries/script-engine/src/AssetScriptingInterface.h +++ b/libraries/script-engine/src/AssetScriptingInterface.h @@ -19,13 +19,60 @@ #include +/**jsdoc + * @namespace Assets + */ class AssetScriptingInterface : public QObject { Q_OBJECT public: AssetScriptingInterface(QScriptEngine* engine); + /**jsdoc + * Upload content to the connected domain's asset server. + * @function Assets.uploadData + * @static + * @param data {string} content to upload + * @param callback {Assets~uploadDataCallback} called when upload is complete + */ + + /**jsdoc + * Called when uploadData is complete + * @callback Assets~uploadDataCallback + * @param {string} url + * @param {string} hash + */ + Q_INVOKABLE void uploadData(QString data, QScriptValue callback); + + /**jsdoc + * Download data from the connected domain's asset server. + * @function Assets.downloadData + * @static + * @param url {string} url of asset to download, must be atp scheme url. + * @param callback {Assets~downloadDataCallback} + */ + + /**jsdoc + * Called when downloadData is complete + * @callback Assets~downloadDataCallback + * @param data {string} content that was downloaded + */ + Q_INVOKABLE void downloadData(QString url, QScriptValue downloadComplete); + + /**jsdoc + * Sets up a path to hash mapping within the connected domain's asset server + * @function Assets.setMapping + * @static + * @param path {string} + * @param hash {string} + * @param callback {Assets~setMappingCallback} + */ + + /**jsdoc + * Called when setMapping is complete + * @callback Assets~setMappingCallback + */ Q_INVOKABLE void setMapping(QString path, QString hash, QScriptValue callback); #if (PR_BUILD || DEV_BUILD) diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 5605cc0031..f58e2c906c 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -144,6 +144,11 @@ public: virtual bool setAbsoluteJointRotationInObjectFrame(int index, const glm::quat& rotation) { return false; } virtual bool setAbsoluteJointTranslationInObjectFrame(int index, const glm::vec3& translation) {return false; } + virtual glm::quat getLocalJointRotation(int index) const {return glm::quat(); } + virtual glm::vec3 getLocalJointTranslation(int index) const {return glm::vec3(); } + virtual bool setLocalJointRotation(int index, const glm::quat& rotation) { return false; } + virtual bool setLocalJointTranslation(int index, const glm::vec3& translation) { return false; } + SpatiallyNestablePointer getThisPointer() const; void markAncestorMissing(bool value) { _missingAncestor = value; } diff --git a/libraries/ui/src/ui/Menu.cpp b/libraries/ui/src/ui/Menu.cpp index aee8b40832..ba24adfc3f 100644 --- a/libraries/ui/src/ui/Menu.cpp +++ b/libraries/ui/src/ui/Menu.cpp @@ -428,6 +428,25 @@ bool Menu::menuExists(const QString& menuName) { return false; } +bool Menu::isMenuEnabled(const QString& menuName) { + QAction* action = getMenuAction(menuName); + + // only proceed if the menu actually exists + if (action) { + return action->isEnabled(); + } + return false; +} + +void Menu::setMenuEnabled(const QString& menuName, bool isEnabled) { + QAction* action = getMenuAction(menuName); + + // only proceed if the menu actually exists + if (action) { + action->setEnabled(isEnabled); + } +} + void Menu::addSeparator(const QString& menuName, const QString& separatorName, const QString& grouping) { MenuWrapper* menuObj = getMenu(menuName); if (menuObj) { diff --git a/libraries/ui/src/ui/Menu.h b/libraries/ui/src/ui/Menu.h index ee60a031c3..2711fc5921 100644 --- a/libraries/ui/src/ui/Menu.h +++ b/libraries/ui/src/ui/Menu.h @@ -106,6 +106,9 @@ public slots: bool isOptionChecked(const QString& menuOption) const; void setIsOptionChecked(const QString& menuOption, bool isChecked); + bool isMenuEnabled(const QString& menuName); + void setMenuEnabled(const QString& menuName, bool isEnabled); + bool getGroupingIsVisible(const QString& grouping); void setGroupingIsVisible(const QString& grouping, bool isVisible); /// NOTE: the "" grouping is always visible diff --git a/scripts/system/hmd.js b/scripts/system/hmd.js index 84ff6b3c89..e1c846806f 100644 --- a/scripts/system/hmd.js +++ b/scripts/system/hmd.js @@ -24,10 +24,16 @@ var desktopMenuItemName = "Desktop"; var toolBar = Toolbars.getToolbar("com.highfidelity.interface.toolbar.system"); var button; +// Independent and Entity mode make people sick. Third Person and Mirror have traps that we need to work through. +// Disable them in hmd. +var desktopOnlyViews = ['Third Person', 'Mirror', 'Independent Mode', 'Entity Mode']; function onHmdChanged(isHmd) { button.writeProperty('buttonState', isHmd ? 0 : 1); button.writeProperty('defaultState', isHmd ? 0 : 1); button.writeProperty('hoverState', isHmd ? 2 : 3); + desktopOnlyViews.forEach(function (view) { + Menu.setMenuEnabled("View>" + view, !isHmd); + }); } function onClicked(){ var isDesktop = Menu.isOptionChecked(desktopMenuItemName); diff --git a/scripts/system/users.js b/scripts/system/users.js index 1e4cf042f3..8c52240aa9 100644 --- a/scripts/system/users.js +++ b/scripts/system/users.js @@ -228,7 +228,7 @@ var usersWindow = (function () { var WINDOW_WIDTH = 260, WINDOW_MARGIN = 12, - WINDOW_BASE_MARGIN = 6, // A little less is needed in order look correct + WINDOW_BASE_MARGIN = 24, // A little less is needed in order look correct WINDOW_FONT = { size: 12 }, @@ -253,11 +253,17 @@ var usersWindow = (function () { windowPane, windowHeading, + // Margin on the left and right side of the window to keep + // it from getting too close to the edge of the screen which + // is unclickable. + WINDOW_MARGIN_X = 20, + // Window border is similar to that of edit.js. - WINDOW_BORDER_WIDTH = WINDOW_WIDTH + 2 * WINDOW_BASE_MARGIN, - WINDOW_BORDER_TOP_MARGIN = 2 * WINDOW_BASE_MARGIN, - WINDOW_BORDER_BOTTOM_MARGIN = WINDOW_BASE_MARGIN, - WINDOW_BORDER_LEFT_MARGIN = WINDOW_BASE_MARGIN, + WINDOW_MARGIN_HALF = WINDOW_MARGIN / 2, + WINDOW_BORDER_WIDTH = WINDOW_WIDTH + 2 * WINDOW_MARGIN_HALF, + WINDOW_BORDER_TOP_MARGIN = 2 * WINDOW_MARGIN_HALF, + WINDOW_BORDER_BOTTOM_MARGIN = WINDOW_MARGIN_HALF, + WINDOW_BORDER_LEFT_MARGIN = WINDOW_MARGIN_HALF, WINDOW_BORDER_RADIUS = 4, WINDOW_BORDER_COLOR = { red: 255, green: 255, blue: 255 }, WINDOW_BORDER_ALPHA = 0.5, @@ -371,7 +377,8 @@ var usersWindow = (function () { MENU_NAME = "View", MENU_ITEM = "Users Online", - MENU_ITEM_AFTER = "Overlays", + MENU_ITEM_OVERLAYS = "Overlays", + MENU_ITEM_AFTER = MENU_ITEM_OVERLAYS, SETTING_USERS_SHOW_ME = "UsersWindow.ShowMe", SETTING_USERS_VISIBLE_TO = "UsersWindow.VisibleTo", @@ -399,6 +406,10 @@ var usersWindow = (function () { scrollbarBarClickedAt, // 0.0 .. 1.0 scrollbarValue = 0.0; // 0.0 .. 1.0 + function isWindowDisabled() { + return !Menu.isOptionChecked(MENU_ITEM) || !Menu.isOptionChecked(MENU_ITEM_OVERLAYS); + } + function isValueTrue(value) { // Work around Boolean Settings values being read as string when Interface starts up but as Booleans when re-read after // Being written if refresh script. @@ -445,7 +456,7 @@ var usersWindow = (function () { } function saturateWindowPosition() { - windowPosition.x = Math.max(0, Math.min(viewport.x - WINDOW_WIDTH, windowPosition.x)); + windowPosition.x = Math.max(WINDOW_MARGIN_X, Math.min(viewport.x - WINDOW_WIDTH - WINDOW_MARGIN_X, windowPosition.x)); windowPosition.y = Math.max(windowMinimumHeight, Math.min(viewport.y, windowPosition.y)); } @@ -744,7 +755,7 @@ var usersWindow = (function () { userClicked, delta; - if (!isVisible) { + if (!isVisible || isWindowDisabled()) { return; } @@ -856,7 +867,7 @@ var usersWindow = (function () { function onMouseMoveEvent(event) { var isVisible; - if (!isLoggedIn) { + if (!isLoggedIn || isWindowDisabled()) { return; } @@ -914,6 +925,10 @@ var usersWindow = (function () { function onMouseReleaseEvent() { var offset = {}; + if (isWindowDisabled()) { + return; + } + if (isMovingScrollbar) { Overlays.editOverlay(scrollbarBar, { backgroundAlpha: SCROLLBAR_BAR_ALPHA @@ -939,6 +954,10 @@ var usersWindow = (function () { MIRROR_MENU_ITEM = "Mirror", FULLSCREEN_MIRROR_MENU_ITEM = "Fullscreen Mirror"; + if (isWindowDisabled()) { + return; + } + viewport = Controller.getViewportDimensions(); isMirrorDisplay = Menu.isOptionChecked(MIRROR_MENU_ITEM); isFullscreenMirror = Menu.isOptionChecked(FULLSCREEN_MIRROR_MENU_ITEM); diff --git a/tools/jsdoc/.gitignore b/tools/jsdoc/.gitignore new file mode 100644 index 0000000000..c585e19389 --- /dev/null +++ b/tools/jsdoc/.gitignore @@ -0,0 +1 @@ +out \ No newline at end of file diff --git a/tools/jsdoc/README.md b/tools/jsdoc/README.md new file mode 100644 index 0000000000..c43f95cabe --- /dev/null +++ b/tools/jsdoc/README.md @@ -0,0 +1,13 @@ +#JavaScript Documentation Generation + +##Prerequisites + +* Install node.js +* Install jsdoc via npm. `npm install jsdoc -g` + +To generate html documentation for the High Fidelity JavaScript API + +`cd scripts/jsdoc` +`jsdoc . -c config.json` + +The out folder should contain index.html diff --git a/tools/jsdoc/config.json b/tools/jsdoc/config.json new file mode 100644 index 0000000000..0fb833d015 --- /dev/null +++ b/tools/jsdoc/config.json @@ -0,0 +1,8 @@ +{ + "templates": { + "default": { + "outputSourceFiles": false + } + }, + "plugins": ["plugins/hifi"] +} diff --git a/tools/jsdoc/plugins/hifi.js b/tools/jsdoc/plugins/hifi.js new file mode 100644 index 0000000000..8016aa2ae5 --- /dev/null +++ b/tools/jsdoc/plugins/hifi.js @@ -0,0 +1,41 @@ +function endsWith(path, exts) { + var result = false; + exts.forEach(function(ext) { + if (path.endsWith(ext)) { + result = true; + } + }); + return result; +} + +exports.handlers = { + beforeParse: function(e) { + console.log("Scanning hifi source for jsdoc comments..."); + + // directories to scan for jsdoc comments + var dirList = [ + '../../interface/src', + '../../interface/src/scripting', + '../../libraries/script-engine/src', + '../../libraries/networking/src', + '../../libraries/animation/src', + ]; + var exts = ['.h', '.cpp']; + + const fs = require('fs'); + dirList.forEach(function (dir) { + var files = fs.readdirSync(dir) + files.forEach(function (file) { + var path = dir + "/" + file; + if (fs.lstatSync(path).isFile() && endsWith(path, exts)) { + var data = fs.readFileSync(path, "utf8"); + var reg = /(\/\*\*jsdoc(.|[\r\n])*?\*\/)/gm; + var matches = data.match(reg); + if (matches) { + e.source += matches.map(function (s) { return s.replace('/**jsdoc', '/**'); }).join('\n'); + } + } + }); + }); + } +}; diff --git a/tools/jsdoc/root.js b/tools/jsdoc/root.js new file mode 100644 index 0000000000..097403f723 --- /dev/null +++ b/tools/jsdoc/root.js @@ -0,0 +1,11 @@ +// +// root.js +// +// Copyright 2016 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 +// +// Root of High Fidelity generated java script documentation +// +